Coverage Report

Created: 2024-09-19 09:45

/proc/self/cwd/source/common/grpc/common.h
Line
Count
Source (jump to first uncovered line)
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