Line data Source code
1 : #pragma once 2 : 3 : #include <cstdint> 4 : #include <string> 5 : 6 : #include "envoy/common/exception.h" 7 : #include "envoy/common/platform.h" 8 : #include "envoy/grpc/status.h" 9 : #include "envoy/http/filter.h" 10 : #include "envoy/http/header_map.h" 11 : #include "envoy/http/message.h" 12 : 13 : #include "source/common/common/hash.h" 14 : #include "source/common/grpc/status.h" 15 : #include "source/common/protobuf/protobuf.h" 16 : 17 : #include "absl/types/optional.h" 18 : #include "google/rpc/status.pb.h" 19 : 20 : namespace Envoy { 21 : namespace Grpc { 22 : 23 : class Exception : public EnvoyException { 24 : public: 25 : Exception(const absl::optional<uint64_t>& grpc_status, const std::string& message) 26 0 : : EnvoyException(message), grpc_status_(grpc_status) {} 27 : 28 : const absl::optional<uint64_t> grpc_status_; 29 : }; 30 : 31 : class Common { 32 : public: 33 : /** 34 : * @param headers the headers to parse. 35 : * @return bool indicating whether content-type is gRPC. 36 : */ 37 : static bool hasGrpcContentType(const Http::RequestOrResponseHeaderMap& headers); 38 : 39 : /** 40 : * @param headers the headers to parse. 41 : * @return bool indicating whether Connect-Protocol-Version is present. 42 : */ 43 : static bool hasConnectProtocolVersionHeader(const Http::RequestOrResponseHeaderMap& headers); 44 : 45 : /** 46 : * @param headers the headers to parse. 47 : * @return bool indicating whether content-type is connect streaming. 48 : */ 49 : static bool hasConnectStreamingContentType(const Http::RequestOrResponseHeaderMap& headers); 50 : 51 : /** 52 : * @param headers the headers to parse. 53 : * @return bool indicating whether content-type is Protobuf. 54 : */ 55 : static bool hasProtobufContentType(const Http::RequestOrResponseHeaderMap& headers); 56 : 57 : /** 58 : * @param headers the headers to parse. 59 : * @return bool indicating whether the header is a gRPC request header. 60 : * Currently headers are considered gRPC request headers if they have the gRPC 61 : * content type, and have a path header. 62 : */ 63 : static bool isGrpcRequestHeaders(const Http::RequestHeaderMap& headers); 64 : 65 : /** 66 : * @param headers the headers to parse. 67 : * @return bool indicating whether the header is a Connect request header. 68 : * This is determined by checking for the connect protocol version header and a path header. 69 : */ 70 : static bool isConnectRequestHeaders(const Http::RequestHeaderMap& headers); 71 : 72 : /** 73 : * @param headers the headers to parse. 74 : * @return bool indicating whether the header is a Connect streaming request header. 75 : * This is determined by checking for the connect streaming content type and a path header. 76 : */ 77 : static bool isConnectStreamingRequestHeaders(const Http::RequestHeaderMap& headers); 78 : 79 : /** 80 : * @param headers the headers to parse. 81 : * @return bool indicating whether the header is a protobuf request header. 82 : * Currently headers are considered gRPC request headers if they have the protobuf 83 : * content type, and have a path header. 84 : */ 85 : static bool isProtobufRequestHeaders(const Http::RequestHeaderMap& headers); 86 : 87 : /** 88 : * @param headers the headers to parse. 89 : * @param bool indicating whether the header is at end_stream. 90 : * @return bool indicating whether the header is a gRPC response header 91 : */ 92 : static bool isGrpcResponseHeaders(const Http::ResponseHeaderMap& headers, bool end_stream); 93 : 94 : /** 95 : * @param headers the headers to parse. 96 : * @return bool indicating whether the header is a Connect streaming response header. 97 : */ 98 : static bool isConnectStreamingResponseHeaders(const Http::ResponseHeaderMap& headers); 99 : 100 : /** 101 : * Returns the GrpcStatus code from a given set of trailers, if present. 102 : * @param trailers the trailers to parse. 103 : * @param allow_user_status whether allow user defined grpc status. 104 : * if this value is false, custom grpc status is regarded as invalid status 105 : * @return absl::optional<Status::GrpcStatus> the parsed status code or InvalidCode if no valid 106 : * status is found. 107 : */ 108 : static absl::optional<Status::GrpcStatus> 109 : getGrpcStatus(const Http::ResponseHeaderOrTrailerMap& trailers, bool allow_user_defined = false); 110 : 111 : /** 112 : * Returns the GrpcStatus code from the set of trailers, headers, and StreamInfo, if present. 113 : * @param trailers the trailers to parse for a status code 114 : * @param headers the headers to parse if no status code was found in the trailers 115 : * @param info the StreamInfo to check for HTTP response code if no code was found in the trailers 116 : * or headers 117 : * @return absl::optional<Status::GrpcStatus> the parsed status code or absl::nullopt if no status 118 : * is found 119 : */ 120 : static absl::optional<Status::GrpcStatus> getGrpcStatus(const Http::ResponseTrailerMap& trailers, 121 : const Http::ResponseHeaderMap& headers, 122 : const StreamInfo::StreamInfo& info, 123 : bool allow_user_defined = false); 124 : 125 : /** 126 : * Returns the grpc-message from a given set of trailers, if present. 127 : * @param trailers the trailers to parse. 128 : * @return std::string the gRPC status message or empty string if grpc-message is not present in 129 : * trailers. 130 : */ 131 : static std::string getGrpcMessage(const Http::ResponseHeaderOrTrailerMap& trailers); 132 : 133 : /** 134 : * Returns the decoded google.rpc.Status message from a given set of trailers, if present. 135 : * @param trailers the trailers to parse. 136 : * @return std::unique_ptr<google::rpc::Status> the gRPC status message or empty pointer if no 137 : * grpc-status-details-bin trailer found or it was invalid. 138 : */ 139 : static absl::optional<google::rpc::Status> 140 : getGrpcStatusDetailsBin(const Http::HeaderMap& trailers); 141 : 142 : /** 143 : * Parse gRPC header 'grpc-timeout' value to a duration in milliseconds. 144 : * @param request_headers the header map from which to extract the value of 'grpc-timeout' header. 145 : * If this header is missing the timeout corresponds to infinity. The header is encoded in 146 : * maximum of 8 decimal digits and a char for the unit. 147 : * @return absl::optional<std::chrono::milliseconds> the duration in milliseconds. absl::nullopt 148 : * is returned if 'grpc-timeout' is missing or malformed. 149 : */ 150 : static absl::optional<std::chrono::milliseconds> 151 : getGrpcTimeout(const Http::RequestHeaderMap& request_headers); 152 : 153 : /** 154 : * Encode 'timeout' into 'grpc-timeout' format in the grpc-timeout header. 155 : * @param timeout the duration in std::chrono::milliseconds. 156 : * @param headers the HeaderMap in which the grpc-timeout header will be set with the timeout in 157 : * 'grpc-timeout' format, up to 8 decimal digits and a letter indicating the unit. 158 : */ 159 : static void toGrpcTimeout(const std::chrono::milliseconds& timeout, 160 : Http::RequestHeaderMap& headers); 161 : 162 : /** 163 : * Serialize protobuf message with gRPC frame header. 164 : */ 165 : static Buffer::InstancePtr serializeToGrpcFrame(const Protobuf::Message& message); 166 : 167 : /** 168 : * Serialize protobuf message. Without grpc header. 169 : */ 170 : static Buffer::InstancePtr serializeMessage(const Protobuf::Message& message); 171 : 172 : /** 173 : * Prepare headers for protobuf service. 174 : */ 175 : static Http::RequestMessagePtr 176 : prepareHeaders(const std::string& upstream_cluster, const std::string& service_full_name, 177 : const std::string& method_name, 178 : const absl::optional<std::chrono::milliseconds>& timeout); 179 : 180 : /** 181 : * @return const std::string& type URL prefix. 182 : */ 183 : static const std::string& typeUrlPrefix(); 184 : 185 : /** 186 : * Prefix type URL to a qualified name. 187 : * @param qualified_name packagename.messagename. 188 : * @return qualified_name prefixed with typeUrlPrefix + "/". 189 : */ 190 : static std::string typeUrl(const std::string& qualified_name); 191 : 192 : /** 193 : * Prepend a gRPC frame header to a Buffer::Instance containing a single gRPC frame. 194 : * @param buffer containing the frame data which will be modified. 195 : */ 196 : static void prependGrpcFrameHeader(Buffer::Instance& buffer); 197 : 198 : /** 199 : * Parse a Buffer::Instance into a Protobuf::Message. 200 : * @param buffer containing the data to be parsed. 201 : * @param proto the parsed proto. 202 : * @return bool true if the parse was successful. 203 : */ 204 : static bool parseBufferInstance(Buffer::InstancePtr&& buffer, Protobuf::Message& proto); 205 : 206 : struct RequestNames { 207 : absl::string_view service_; 208 : absl::string_view method_; 209 : }; 210 : 211 : /** 212 : * Resolve the gRPC service and method from the HTTP2 :path header. 213 : * @param path supplies the :path header. 214 : * @return if both gRPC serve and method have been resolved successfully returns 215 : * a populated RequestNames, otherwise returns an empty optional. 216 : * @note The return value is only valid as long as `path` is still valid and unmodified. 217 : */ 218 : static absl::optional<RequestNames> resolveServiceAndMethod(const Http::HeaderEntry* path); 219 : 220 : private: 221 : static constexpr size_t MAX_GRPC_TIMEOUT_VALUE = 99999999; 222 : }; 223 : 224 : } // namespace Grpc 225 : } // namespace Envoy