Line data Source code
1 : #pragma once
2 :
3 : #include <chrono>
4 : #include <cstdint>
5 : #include <memory>
6 : #include <string>
7 :
8 : #include "envoy/common/regex.h"
9 : #include "envoy/config/core/v3/http_uri.pb.h"
10 : #include "envoy/config/core/v3/protocol.pb.h"
11 : #include "envoy/config/route/v3/route_components.pb.h"
12 : #include "envoy/grpc/status.h"
13 : #include "envoy/http/codes.h"
14 : #include "envoy/http/filter.h"
15 : #include "envoy/http/message.h"
16 : #include "envoy/http/metadata_interface.h"
17 : #include "envoy/http/query_params.h"
18 :
19 : #include "source/common/http/exception.h"
20 : #include "source/common/http/status.h"
21 :
22 : #include "absl/strings/string_view.h"
23 : #include "absl/types/optional.h"
24 :
25 : namespace Envoy {
26 : namespace Http {
27 : namespace Utility {
28 :
29 : /**
30 : * Well-known HTTP ALPN values.
31 : */
32 : class AlpnNameValues {
33 : public:
34 : const std::string Http10 = "http/1.0";
35 : const std::string Http11 = "http/1.1";
36 : const std::string Http2 = "h2";
37 : const std::string Http2c = "h2c";
38 : const std::string Http3 = "h3";
39 : };
40 :
41 : using AlpnNames = ConstSingleton<AlpnNameValues>;
42 :
43 : } // namespace Utility
44 : } // namespace Http
45 :
46 : namespace Http2 {
47 : namespace Utility {
48 :
49 : // Limits and defaults for `envoy::config::core::v3::Http2ProtocolOptions` protos.
50 : struct OptionsLimits {
51 : // disable HPACK compression
52 : static const uint32_t MIN_HPACK_TABLE_SIZE = 0;
53 : // initial value from HTTP/2 spec, same as NGHTTP2_DEFAULT_HEADER_TABLE_SIZE from nghttp2
54 : static const uint32_t DEFAULT_HPACK_TABLE_SIZE = (1 << 12);
55 : // no maximum from HTTP/2 spec, use unsigned 32-bit maximum
56 : static const uint32_t MAX_HPACK_TABLE_SIZE = std::numeric_limits<uint32_t>::max();
57 : // TODO(jwfang): make this 0, the HTTP/2 spec minimum
58 : static const uint32_t MIN_MAX_CONCURRENT_STREAMS = 1;
59 : // defaults to maximum, same as nghttp2
60 : static const uint32_t DEFAULT_MAX_CONCURRENT_STREAMS = (1U << 31) - 1;
61 : // no maximum from HTTP/2 spec, total streams is unsigned 32-bit maximum,
62 : // one-side (client/server) is half that, and we need to exclude stream 0.
63 : // same as NGHTTP2_INITIAL_MAX_CONCURRENT_STREAMS from nghttp2
64 : static const uint32_t MAX_MAX_CONCURRENT_STREAMS = (1U << 31) - 1;
65 :
66 : // initial value from HTTP/2 spec, same as NGHTTP2_INITIAL_WINDOW_SIZE from nghttp2
67 : // NOTE: we only support increasing window size now, so this is also the minimum
68 : // TODO(jwfang): make this 0 to support decrease window size
69 : static const uint32_t MIN_INITIAL_STREAM_WINDOW_SIZE = (1 << 16) - 1;
70 : // initial value from HTTP/2 spec is 65535, but we want more (256MiB)
71 : static const uint32_t DEFAULT_INITIAL_STREAM_WINDOW_SIZE = 256 * 1024 * 1024;
72 : // maximum from HTTP/2 spec, same as NGHTTP2_MAX_WINDOW_SIZE from nghttp2
73 : static const uint32_t MAX_INITIAL_STREAM_WINDOW_SIZE = (1U << 31) - 1;
74 :
75 : // CONNECTION_WINDOW_SIZE is similar to STREAM_WINDOW_SIZE, but for connection-level window
76 : // TODO(jwfang): make this 0 to support decrease window size
77 : static const uint32_t MIN_INITIAL_CONNECTION_WINDOW_SIZE = (1 << 16) - 1;
78 : // nghttp2's default connection-level window equals to its stream-level,
79 : // our default connection-level window also equals to our stream-level
80 : static const uint32_t DEFAULT_INITIAL_CONNECTION_WINDOW_SIZE = 256 * 1024 * 1024;
81 : static const uint32_t MAX_INITIAL_CONNECTION_WINDOW_SIZE = (1U << 31) - 1;
82 :
83 : // Default limit on the number of outbound frames of all types.
84 : static const uint32_t DEFAULT_MAX_OUTBOUND_FRAMES = 10000;
85 : // Default limit on the number of outbound frames of types PING, SETTINGS and RST_STREAM.
86 : static const uint32_t DEFAULT_MAX_OUTBOUND_CONTROL_FRAMES = 1000;
87 : // Default limit on the number of consecutive inbound frames with an empty payload
88 : // and no end stream flag.
89 : static const uint32_t DEFAULT_MAX_CONSECUTIVE_INBOUND_FRAMES_WITH_EMPTY_PAYLOAD = 1;
90 : // Default limit on the number of inbound frames of type PRIORITY (per stream).
91 : static const uint32_t DEFAULT_MAX_INBOUND_PRIORITY_FRAMES_PER_STREAM = 100;
92 : // Default limit on the number of inbound frames of type WINDOW_UPDATE (per DATA frame sent).
93 : static const uint32_t DEFAULT_MAX_INBOUND_WINDOW_UPDATE_FRAMES_PER_DATA_FRAME_SENT = 10;
94 : };
95 :
96 : /**
97 : * Validates settings/options already set in |options| and initializes any remaining fields with
98 : * defaults.
99 : */
100 : envoy::config::core::v3::Http2ProtocolOptions
101 : initializeAndValidateOptions(const envoy::config::core::v3::Http2ProtocolOptions& options);
102 :
103 : envoy::config::core::v3::Http2ProtocolOptions
104 : initializeAndValidateOptions(const envoy::config::core::v3::Http2ProtocolOptions& options,
105 : bool hcm_stream_error_set,
106 : const ProtobufWkt::BoolValue& hcm_stream_error);
107 : } // namespace Utility
108 : } // namespace Http2
109 : namespace Http3 {
110 : namespace Utility {
111 :
112 : // Limits and defaults for `envoy::config::core::v3::Http3ProtocolOptions` protos.
113 : struct OptionsLimits {
114 : // The same as kStreamReceiveWindowLimit in QUICHE which is the maximum supported by QUICHE.
115 : static const uint32_t DEFAULT_INITIAL_STREAM_WINDOW_SIZE = 16 * 1024 * 1024;
116 : // The same as kSessionReceiveWindowLimit in QUICHE which is the maximum supported by QUICHE.
117 : static const uint32_t DEFAULT_INITIAL_CONNECTION_WINDOW_SIZE = 24 * 1024 * 1024;
118 : };
119 :
120 : envoy::config::core::v3::Http3ProtocolOptions
121 : initializeAndValidateOptions(const envoy::config::core::v3::Http3ProtocolOptions& options,
122 : bool hcm_stream_error_set,
123 : const ProtobufWkt::BoolValue& hcm_stream_error);
124 :
125 : } // namespace Utility
126 : } // namespace Http3
127 : namespace Http {
128 : namespace Utility {
129 :
130 : enum UrlComponents {
131 : UcSchema = 0,
132 : UcHost = 1,
133 : UcPort = 2,
134 : UcPath = 3,
135 : UcQuery = 4,
136 : UcFragment = 5,
137 : UcUserinfo = 6,
138 : UcMax = 7
139 : };
140 :
141 : /**
142 : * Given a fully qualified URL, splits the string_view provided into scheme,
143 : * host and path with query parameters components.
144 : */
145 :
146 : class Url {
147 : public:
148 : bool initialize(absl::string_view absolute_url, bool is_connect_request);
149 1 : absl::string_view scheme() const { return scheme_; }
150 3 : absl::string_view hostAndPort() const { return host_and_port_; }
151 2 : absl::string_view pathAndQueryParams() const { return path_and_query_params_; }
152 :
153 0 : void setPathAndQueryParams(absl::string_view path_and_query_params) {
154 0 : path_and_query_params_ = path_and_query_params;
155 0 : }
156 :
157 : /** Returns the fully qualified URL as a string. */
158 : std::string toString() const;
159 :
160 : bool containsFragment();
161 : bool containsUserinfo();
162 :
163 : private:
164 : absl::string_view scheme_;
165 : absl::string_view host_and_port_;
166 : absl::string_view path_and_query_params_;
167 : uint8_t component_bitmap_;
168 : };
169 :
170 : class PercentEncoding {
171 : public:
172 : /**
173 : * Encodes string view to its percent encoded representation. Non-visible ASCII is always escaped,
174 : * in addition to a given list of reserved chars.
175 : *
176 : * @param value supplies string to be encoded.
177 : * @param reserved_chars list of reserved chars to escape. By default the escaped chars in
178 : * https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md#responses are used.
179 : * @return std::string percent-encoded string.
180 : */
181 : static std::string encode(absl::string_view value, absl::string_view reserved_chars = "%");
182 :
183 : /**
184 : * Decodes string view from its percent encoded representation.
185 : * @param encoded supplies string to be decoded.
186 : * @return std::string decoded string https://tools.ietf.org/html/rfc3986#section-2.1.
187 : */
188 : static std::string decode(absl::string_view encoded);
189 :
190 : /**
191 : * Encodes string view for storing it as a query parameter according to the
192 : * x-www-form-urlencoded spec:
193 : * https://www.w3.org/TR/html5/forms.html#application/x-www-form-urlencoded-encoding-algorithm
194 : * @param value supplies string to be encoded.
195 : * @return std::string encoded string according to
196 : * https://www.w3.org/TR/html5/forms.html#application/x-www-form-urlencoded-encoding-algorithm
197 : *
198 : * Summary:
199 : * The x-www-form-urlencoded spec mandates that all ASCII codepoints are %-encoded except the
200 : * following: ALPHA | DIGIT | * | - | . | _
201 : *
202 : * NOTE: the space character is encoded as %20, NOT as the + character
203 : */
204 : static std::string urlEncodeQueryParameter(absl::string_view value);
205 :
206 : /**
207 : * Decodes string view that represents URL in x-www-form-urlencoded query parameter.
208 : * @param encoded supplies string to be decoded.
209 : * @return std::string decoded string compliant with https://datatracker.ietf.org/doc/html/rfc3986
210 : *
211 : * This function decodes a query parameter assuming it is a URL. It only decodes characters
212 : * permitted in the URL - the unreserved and reserved character sets.
213 : * unreserved-set := ALPHA | DIGIT | - | . | _ | ~
214 : * reserved-set := sub-delims | gen-delims
215 : * sub-delims := ! | $ | & | ` | ( | ) | * | + | , | ; | =
216 : * gen-delims := : | / | ? | # | [ | ] | @
217 : *
218 : * The following characters are not decoded:
219 : * ASCII controls <= 0x1F, space, DEL (0x7F), extended ASCII > 0x7F
220 : * As well as the following characters without defined meaning in URL
221 : * " | < | > | \ | ^ | { | }
222 : * and the "pipe" `|` character
223 : */
224 : static std::string urlDecodeQueryParameter(absl::string_view encoded);
225 :
226 : private:
227 : // Encodes string view to its percent encoded representation, with start index.
228 : static std::string encode(absl::string_view value, const size_t index,
229 : const absl::flat_hash_set<char>& reserved_char_set);
230 : };
231 :
232 : /**
233 : * Append to x-forwarded-for header.
234 : * @param headers supplies the headers to append to.
235 : * @param remote_address supplies the remote address to append.
236 : */
237 : void appendXff(RequestHeaderMap& headers, const Network::Address::Instance& remote_address);
238 :
239 : /**
240 : * Append to via header.
241 : * @param headers supplies the headers to append to.
242 : * @param via supplies the via header to append.
243 : */
244 : void appendVia(RequestOrResponseHeaderMap& headers, const std::string& via);
245 :
246 : /**
247 : * Update authority with the specified hostname.
248 : * @param headers headers where authority should be updated.
249 : * @param hostname hostname that authority should be updated with.
250 : * @param append_xfh append the original authority to the x-forwarded-host header.
251 : */
252 : void updateAuthority(RequestHeaderMap& headers, absl::string_view hostname, bool append_xfh);
253 :
254 : /**
255 : * Creates an SSL (https) redirect path based on the input host and path headers.
256 : * @param headers supplies the request headers.
257 : * @return std::string the redirect path.
258 : */
259 : std::string createSslRedirectPath(const RequestHeaderMap& headers);
260 :
261 : /**
262 : * Finds the start of the query string in a path
263 : * @param path supplies a HeaderString& to search for the query string
264 : * @return absl::string_view starting at the beginning of the query string,
265 : * or a string_view starting at the end of the path if there was
266 : * no query string.
267 : */
268 : absl::string_view findQueryStringStart(const HeaderString& path);
269 :
270 : /**
271 : * Returns the path without the query string.
272 : * @param path supplies a HeaderString& possibly containing a query string.
273 : * @return std::string the path without query string.
274 : */
275 : std::string stripQueryString(const HeaderString& path);
276 :
277 : /**
278 : * Parse a particular value out of a cookie
279 : * @param headers supplies the headers to get the cookie from.
280 : * @param key the key for the particular cookie value to return
281 : * @return std::string the parsed cookie value, or "" if none exists
282 : **/
283 : std::string parseCookieValue(const HeaderMap& headers, const std::string& key);
284 :
285 : /**
286 : * Parse cookies from header into a map.
287 : * @param headers supplies the headers to get cookies from.
288 : * @param key_filter predicate that returns true for every cookie key to be included.
289 : * @return absl::flat_hash_map cookie map.
290 : **/
291 : absl::flat_hash_map<std::string, std::string>
292 : parseCookies(const RequestHeaderMap& headers,
293 : const std::function<bool(absl::string_view)>& key_filter);
294 :
295 : /**
296 : * Parse cookies from header into a map.
297 : * @param headers supplies the headers to get cookies from.
298 : * @return absl::flat_hash_map cookie map.
299 : **/
300 : absl::flat_hash_map<std::string, std::string> parseCookies(const RequestHeaderMap& headers);
301 :
302 : /**
303 : * Parse a particular value out of a set-cookie
304 : * @param headers supplies the headers to get the set-cookie from.
305 : * @param key the key for the particular set-cookie value to return
306 : * @return std::string the parsed set-cookie value, or "" if none exists
307 : **/
308 : std::string parseSetCookieValue(const HeaderMap& headers, const std::string& key);
309 :
310 : /**
311 : * Produce the value for a Set-Cookie header with the given parameters.
312 : * @param key is the name of the cookie that is being set.
313 : * @param value the value to set the cookie to; this value is trusted.
314 : * @param path the path for the cookie, or the empty string to not set a path.
315 : * @param max_age the length of time for which the cookie is valid, or zero
316 : * @param httponly true if the cookie should have HttpOnly appended.
317 : * to create a session cookie.
318 : * @return std::string a valid Set-Cookie header value string
319 : */
320 : std::string makeSetCookieValue(const std::string& key, const std::string& value,
321 : const std::string& path, const std::chrono::seconds max_age,
322 : bool httponly, const Http::CookieAttributeRefVector attributes);
323 :
324 : /**
325 : * Get the response status from the response headers.
326 : * @param headers supplies the headers to get the status from.
327 : * @return uint64_t the response code or returns 0 if headers are invalid.
328 : */
329 : uint64_t getResponseStatus(const ResponseHeaderMap& headers);
330 :
331 : /**
332 : * Get the response status from the response headers.
333 : * @param headers supplies the headers to get the status from.
334 : * @return absl::optional<uint64_t> the response code or absl::nullopt if the headers are invalid.
335 : */
336 : absl::optional<uint64_t> getResponseStatusOrNullopt(const ResponseHeaderMap& headers);
337 :
338 : /**
339 : * Determine whether these headers are a valid Upgrade request or response.
340 : * This function returns true if the following HTTP headers and values are present:
341 : * - Connection: Upgrade
342 : * - Upgrade: [any value]
343 : */
344 : bool isUpgrade(const RequestOrResponseHeaderMap& headers);
345 :
346 : /**
347 : * @return true if this is a CONNECT request with a :protocol header present, false otherwise.
348 : */
349 : bool isH2UpgradeRequest(const RequestHeaderMap& headers);
350 :
351 : /**
352 : * @return true if this is a CONNECT request with a :protocol header present, false otherwise.
353 : */
354 : bool isH3UpgradeRequest(const RequestHeaderMap& headers);
355 :
356 : /**
357 : * Determine whether this is a WebSocket Upgrade request.
358 : * This function returns true if the following HTTP headers and values are present:
359 : * - Connection: Upgrade
360 : * - Upgrade: websocket
361 : */
362 : bool isWebSocketUpgradeRequest(const RequestHeaderMap& headers);
363 :
364 : struct EncodeFunctions {
365 : // Function to modify locally generated response headers.
366 : std::function<void(ResponseHeaderMap& headers)> modify_headers_;
367 : // Function to rewrite locally generated response.
368 : std::function<void(ResponseHeaderMap& response_headers, Code& code, std::string& body,
369 : absl::string_view& content_type)>
370 : rewrite_;
371 : // Function to encode response headers.
372 : std::function<void(ResponseHeaderMapPtr&& headers, bool end_stream)> encode_headers_;
373 : // Function to encode the response body.
374 : std::function<void(Buffer::Instance& data, bool end_stream)> encode_data_;
375 : };
376 :
377 : struct LocalReplyData {
378 : // Tells if this is a response to a gRPC request.
379 : bool is_grpc_;
380 : // Supplies the HTTP response code.
381 : Code response_code_;
382 : // Supplies the optional body text which is returned.
383 : absl::string_view body_text_;
384 : // gRPC status code to override the httpToGrpcStatus mapping with.
385 : const absl::optional<Grpc::Status::GrpcStatus> grpc_status_;
386 : // Tells if this is a response to a HEAD request.
387 : bool is_head_request_ = false;
388 : };
389 :
390 : // Prepared local reply after modifying headers and rewriting body.
391 : struct PreparedLocalReply {
392 : bool is_grpc_request_ = false;
393 : bool is_head_request_ = false;
394 : ResponseHeaderMapPtr response_headers_;
395 : std::string response_body_;
396 : // Function to encode response headers.
397 : std::function<void(ResponseHeaderMapPtr&& headers, bool end_stream)> encode_headers_;
398 : // Function to encode the response body.
399 : std::function<void(Buffer::Instance& data, bool end_stream)> encode_data_;
400 : };
401 :
402 : using PreparedLocalReplyPtr = std::unique_ptr<PreparedLocalReply>;
403 :
404 : /**
405 : * Create a locally generated response using the provided lambdas.
406 :
407 : * @param is_reset boolean reference that indicates whether a stream has been reset. It is the
408 : * responsibility of the caller to ensure that this is set to false if onDestroy()
409 : * is invoked in the context of sendLocalReply().
410 : * @param encode_functions supplies the functions to encode response body and headers.
411 : * @param local_reply_data struct which keeps data related to generate reply.
412 : */
413 : void sendLocalReply(const bool& is_reset, const EncodeFunctions& encode_functions,
414 : const LocalReplyData& local_reply_data);
415 :
416 : /**
417 : * Prepares a locally generated response.
418 : *
419 : * @param encode_functions supplies the functions to encode response body and headers.
420 : * @param local_reply_data struct which keeps data related to generate reply.
421 : */
422 : PreparedLocalReplyPtr prepareLocalReply(const EncodeFunctions& encode_functions,
423 : const LocalReplyData& local_reply_data);
424 : /**
425 : * Encodes a prepared local reply.
426 : * @param is_reset boolean reference that indicates whether a stream has been reset. It is the
427 : * responsibility of the caller to ensure that this is set to false if onDestroy()
428 : * is invoked in the context of sendLocalReply().
429 : * @param prepared_local_reply supplies the local reply to encode.
430 : */
431 : void encodeLocalReply(const bool& is_reset, PreparedLocalReplyPtr prepared_local_reply);
432 :
433 : struct GetLastAddressFromXffInfo {
434 : // Last valid address pulled from the XFF header.
435 : Network::Address::InstanceConstSharedPtr address_;
436 : // Whether this address can be used to determine if it's an internal request.
437 : bool allow_trusted_address_checks_;
438 : };
439 :
440 : /**
441 : * Retrieves the last IPv4/IPv6 address in the x-forwarded-for header.
442 : * @param request_headers supplies the request headers.
443 : * @param num_to_skip specifies the number of addresses at the end of the XFF header
444 : * to ignore when identifying the "last" address.
445 : * @return GetLastAddressFromXffInfo information about the last address in the XFF header.
446 : * @see GetLastAddressFromXffInfo for more information.
447 : */
448 : GetLastAddressFromXffInfo getLastAddressFromXFF(const Http::RequestHeaderMap& request_headers,
449 : uint32_t num_to_skip = 0);
450 :
451 : /**
452 : * Remove any headers nominated by the Connection header
453 : * Sanitize the TE header if it contains unsupported values
454 : *
455 : * @param headers the client request headers
456 : * @return whether the headers were sanitized successfully
457 : */
458 : bool sanitizeConnectionHeader(Http::RequestHeaderMap& headers);
459 :
460 : /**
461 : * Get the string for the given http protocol.
462 : * @param protocol for which to return the string representation.
463 : * @return string representation of the protocol.
464 : */
465 : const std::string& getProtocolString(const Protocol p);
466 :
467 : /**
468 : * Constructs the original URI sent from the client from
469 : * the request headers.
470 : * @param request headers from the original request
471 : * @param length to truncate the constructed URI's path
472 : */
473 : std::string buildOriginalUri(const Http::RequestHeaderMap& request_headers,
474 : absl::optional<uint32_t> max_path_length);
475 :
476 : /**
477 : * Extract host and path from a URI. The host may contain port.
478 : * This function doesn't validate if the URI is valid. It only parses the URI with following
479 : * format: scheme://host/path.
480 : * @param the input URI string
481 : * @param the output host string.
482 : * @param the output path string.
483 : */
484 : void extractHostPathFromUri(const absl::string_view& uri, absl::string_view& host,
485 : absl::string_view& path);
486 :
487 : /**
488 : * Takes a the path component from a file:/// URI and returns a local path for file access.
489 : * @param file_path if we have file:///foo/bar, the file_path is foo/bar. For file:///c:/foo/bar
490 : * it is c:/foo/bar. This is not prefixed with /.
491 : * @return std::string with absolute path for local access, e.g. /foo/bar, c:/foo/bar.
492 : */
493 : std::string localPathFromFilePath(const absl::string_view& file_path);
494 :
495 : /**
496 : * Prepare headers for a HttpUri.
497 : */
498 : RequestMessagePtr prepareHeaders(const envoy::config::core::v3::HttpUri& http_uri);
499 :
500 : /**
501 : * Returns string representation of StreamResetReason.
502 : */
503 : const std::string resetReasonToString(const Http::StreamResetReason reset_reason);
504 :
505 : /**
506 : * Transforms the supplied headers from an HTTP/1 Upgrade request to an H2 style upgrade.
507 : * Changes the method to connection, moves the Upgrade to a :protocol header,
508 : * @param headers the headers to convert.
509 : */
510 : void transformUpgradeRequestFromH1toH2(RequestHeaderMap& headers);
511 :
512 : /**
513 : * Transforms the supplied headers from an HTTP/1 Upgrade request to an H3 style upgrade,
514 : * which is the same as the H2 upgrade.
515 : * @param headers the headers to convert.
516 : */
517 : void transformUpgradeRequestFromH1toH3(RequestHeaderMap& headers);
518 :
519 : /**
520 : * Transforms the supplied headers from an HTTP/1 Upgrade response to an H2 style upgrade response.
521 : * Changes the 101 upgrade response to a 200 for the CONNECT response.
522 : * @param headers the headers to convert.
523 : */
524 : void transformUpgradeResponseFromH1toH2(ResponseHeaderMap& headers);
525 :
526 : /**
527 : * Transforms the supplied headers from an HTTP/1 Upgrade response to an H3 style upgrade response,
528 : * which is the same as the H2 style upgrade.
529 : * @param headers the headers to convert.
530 : */
531 : void transformUpgradeResponseFromH1toH3(ResponseHeaderMap& headers);
532 :
533 : /**
534 : * Transforms the supplied headers from an H2 "CONNECT"-with-:protocol-header to an HTTP/1 style
535 : * Upgrade response.
536 : * @param headers the headers to convert.
537 : */
538 : void transformUpgradeRequestFromH2toH1(RequestHeaderMap& headers);
539 :
540 : /**
541 : * Transforms the supplied headers from an H3 "CONNECT"-with-:protocol-header to an HTTP/1 style
542 : * Upgrade response. Same as H2 upgrade response transform
543 : * @param headers the headers to convert.
544 : */
545 : void transformUpgradeRequestFromH3toH1(RequestHeaderMap& headers);
546 :
547 : /**
548 : * Transforms the supplied headers from an H2 "CONNECT success" to an HTTP/1 style Upgrade response.
549 : * The caller is responsible for ensuring this only happens on upgraded streams.
550 : * @param headers the headers to convert.
551 : * @param upgrade the HTTP Upgrade token.
552 : */
553 : void transformUpgradeResponseFromH2toH1(ResponseHeaderMap& headers, absl::string_view upgrade);
554 :
555 : /**
556 : * Transforms the supplied headers from an H2 "CONNECT success" to an HTTP/1 style Upgrade response.
557 : * The caller is responsible for ensuring this only happens on upgraded streams.
558 : * Same as H2 Upgrade response transform
559 : * @param headers the headers to convert.
560 : * @param upgrade the HTTP Upgrade token.
561 : */
562 : void transformUpgradeResponseFromH3toH1(ResponseHeaderMap& headers, absl::string_view upgrade);
563 :
564 : /**
565 : * Retrieves the route specific config. Route specific config can be in a few
566 : * places, that are checked in order. The first config found is returned. The
567 : * order is:
568 : * - the routeEntry() (for config that's applied on weighted clusters)
569 : * - the route
570 : * - and finally from the virtual host object (routeEntry()->virtualhost()).
571 : *
572 : * To use, simply:
573 : *
574 : * const auto* config =
575 : * Utility::resolveMostSpecificPerFilterConfig<ConcreteType>(stream_callbacks_);
576 : *
577 : * See notes about config's lifetime below.
578 : *
579 : * @param callbacks The stream filter callbacks to check for route configs.
580 : *
581 : * @return The route config if found. nullptr if not found. The returned
582 : * pointer's lifetime is the same as the matched route.
583 : */
584 : template <class ConfigType>
585 150 : const ConfigType* resolveMostSpecificPerFilterConfig(const Http::StreamFilterCallbacks* callbacks) {
586 150 : static_assert(std::is_base_of<Router::RouteSpecificFilterConfig, ConfigType>::value,
587 150 : "ConfigType must be a subclass of Router::RouteSpecificFilterConfig");
588 150 : ASSERT(callbacks != nullptr);
589 150 : return dynamic_cast<const ConfigType*>(callbacks->mostSpecificPerFilterConfig());
590 150 : }
591 :
592 : /**
593 : * Merge all the available per route filter configs into one. To perform the merge,
594 : * the reduce function will be called on each two configs until a single merged config is left.
595 : *
596 : * @param reduce The first argument for this function will be the config from the previous level
597 : * and the second argument is the config from the current level (the more specific one). The
598 : * function should merge the second argument into the first argument.
599 : *
600 : * @return The merged config.
601 : */
602 : template <class ConfigType>
603 : absl::optional<ConfigType>
604 : getMergedPerFilterConfig(const Http::StreamFilterCallbacks* callbacks,
605 32 : std::function<void(ConfigType&, const ConfigType&)> reduce) {
606 32 : static_assert(std::is_copy_constructible<ConfigType>::value,
607 32 : "ConfigType must be copy constructible");
608 32 : ASSERT(callbacks != nullptr);
609 :
610 32 : absl::optional<ConfigType> merged;
611 :
612 32 : callbacks->traversePerFilterConfig([&reduce,
613 32 : &merged](const Router::RouteSpecificFilterConfig& cfg) {
614 0 : const ConfigType* typed_cfg = dynamic_cast<const ConfigType*>(&cfg);
615 0 : if (typed_cfg == nullptr) {
616 0 : ENVOY_LOG_MISC(debug, "Failed to retrieve the correct type of route specific filter config");
617 0 : return;
618 0 : }
619 0 : if (!merged) {
620 0 : merged.emplace(*typed_cfg);
621 0 : } else {
622 0 : reduce(merged.value(), *typed_cfg);
623 0 : }
624 0 : });
625 :
626 32 : return merged;
627 32 : }
628 :
629 : struct AuthorityAttributes {
630 : // whether parsed authority is pure ip address(IPv4/IPv6), if it is true
631 : // passed that are not FQDN
632 : bool is_ip_address_{};
633 :
634 : // If parsed authority has host, that is stored here.
635 : absl::string_view host_;
636 :
637 : // If parsed authority has port, that is stored here.
638 : absl::optional<uint16_t> port_;
639 : };
640 :
641 : /**
642 : * Parse passed authority, and get that is valid FQDN or IPv4/IPv6 address, hostname and port-name.
643 : * @param host host/authority
644 : * @param default_port If passed authority does not have port, this value is returned
645 : * @return hostname parse result. that includes whether host is IP Address, hostname and port-name
646 : */
647 : AuthorityAttributes parseAuthority(absl::string_view host);
648 :
649 : /**
650 : * It validates RetryPolicy defined in core api. It should be called at the main thread as
651 : * it may throw exception.
652 : * @param retry_policy core retry policy
653 : */
654 : void validateCoreRetryPolicy(const envoy::config::core::v3::RetryPolicy& retry_policy);
655 :
656 : /**
657 : * It returns RetryPolicy defined in core api to route api.
658 : * @param retry_policy core retry policy
659 : * @param retry_on this specifies when retry should be invoked.
660 : * @return route retry policy
661 : */
662 : envoy::config::route::v3::RetryPolicy
663 : convertCoreToRouteRetryPolicy(const envoy::config::core::v3::RetryPolicy& retry_policy,
664 : const std::string& retry_on);
665 :
666 : /**
667 : * @param request_headers the request header to be looked into.
668 : * @return true if the request method is safe as defined in
669 : * https://www.rfc-editor.org/rfc/rfc7231#section-4.2.1
670 : */
671 : bool isSafeRequest(const Http::RequestHeaderMap& request_headers);
672 :
673 : /**
674 : * @param value: the value of the referer header field
675 : * @return true if the given value conforms to RFC specifications
676 : * https://www.rfc-editor.org/rfc/rfc7231#section-5.5.2
677 : */
678 : bool isValidRefererValue(absl::string_view value);
679 :
680 : /**
681 : * Return the GatewayTimeout HTTP code to indicate the request is full received.
682 : */
683 : Http::Code maybeRequestTimeoutCode(bool remote_decode_complete);
684 :
685 : /**
686 : * Container for route config elements that pertain to a redirect.
687 : */
688 : struct RedirectConfig {
689 : const std::string scheme_redirect_;
690 : const std::string host_redirect_;
691 : const std::string port_redirect_;
692 : const std::string path_redirect_;
693 : const std::string prefix_rewrite_redirect_;
694 : const std::string regex_rewrite_redirect_substitution_;
695 : Regex::CompiledMatcherPtr regex_rewrite_redirect_;
696 : // Keep small members (bools and enums) at the end of class, to reduce alignment overhead.
697 : const bool path_redirect_has_query_;
698 : const bool https_redirect_;
699 : const bool strip_query_;
700 : };
701 :
702 : /**
703 : * Validates the provided scheme is valid (either http or https)
704 : * @param scheme the scheme to validate
705 : * @return bool true if the scheme is valid.
706 : */
707 : bool schemeIsValid(const absl::string_view scheme);
708 :
709 : /**
710 : * @param scheme the scheme to validate
711 : * @return bool true if the scheme is http.
712 : */
713 : bool schemeIsHttp(const absl::string_view scheme);
714 :
715 : /**
716 : * @param scheme the scheme to validate
717 : * @return bool true if the scheme is https.
718 : */
719 : bool schemeIsHttps(const absl::string_view scheme);
720 :
721 : /*
722 : * Compute new path based on RedirectConfig.
723 : */
724 : std::string newUri(::Envoy::OptRef<const RedirectConfig> redirect_config,
725 : const Http::RequestHeaderMap& headers);
726 :
727 : } // namespace Utility
728 : } // namespace Http
729 : } // namespace Envoy
|