Line data Source code
1 : #pragma once
2 :
3 : #include <algorithm>
4 : #include <cstdint>
5 : #include <cstring>
6 : #include <iostream>
7 : #include <memory>
8 : #include <string>
9 : #include <type_traits>
10 : #include <vector>
11 :
12 : #include "envoy/common/optref.h"
13 : #include "envoy/common/pure.h"
14 : #include "envoy/common/union_string.h"
15 : #include "envoy/http/header_formatter.h"
16 :
17 : #include "source/common/common/assert.h"
18 : #include "source/common/common/hash.h"
19 : #include "source/common/common/macros.h"
20 :
21 : #include "absl/container/inlined_vector.h"
22 : #include "absl/strings/string_view.h"
23 :
24 : namespace Envoy {
25 : namespace Http {
26 :
27 : // Used by ASSERTs to validate internal consistency. E.g. valid HTTP header keys/values should
28 : // never contain embedded NULLs.
29 3274 : static inline bool validHeaderString(absl::string_view s) {
30 0 : // If you modify this list of illegal embedded characters you will probably
31 0 : // want to change header_map_fuzz_impl_test at the same time.
32 19767 : for (const char c : s) {
33 19767 : switch (c) {
34 0 : case '\0':
35 0 : FALLTHRU;
36 4 : case '\r':
37 4 : FALLTHRU;
38 4 : case '\n':
39 4 : return false;
40 19763 : default:
41 19763 : continue;
42 19767 : }
43 19767 : }
44 3270 : return true;
45 3274 : }
46 :
47 : /**
48 : * Wrapper for a lower case string used in header operations to generally avoid needless case
49 : * insensitive compares.
50 : */
51 : class LowerCaseString {
52 : public:
53 731 : LowerCaseString(LowerCaseString&& rhs) noexcept : string_(std::move(rhs.string_)) {
54 731 : ASSERT(valid());
55 731 : }
56 0 : LowerCaseString& operator=(LowerCaseString&& rhs) noexcept {
57 0 : string_ = std::move(rhs.string_);
58 0 : ASSERT(valid());
59 0 : return *this;
60 0 : }
61 :
62 2983 : LowerCaseString(const LowerCaseString& rhs) : string_(rhs.string_) { ASSERT(valid()); }
63 0 : LowerCaseString& operator=(const LowerCaseString& rhs) {
64 0 : string_ = std::move(rhs.string_);
65 0 : ASSERT(valid());
66 0 : return *this;
67 0 : }
68 :
69 81929 : explicit LowerCaseString(absl::string_view new_string) : string_(new_string) {
70 81929 : ASSERT(valid());
71 81929 : lower();
72 81929 : }
73 :
74 188957 : const std::string& get() const { return string_; }
75 1385 : bool operator==(const LowerCaseString& rhs) const { return string_ == rhs.string_; }
76 18 : bool operator!=(const LowerCaseString& rhs) const { return string_ != rhs.string_; }
77 56157 : bool operator<(const LowerCaseString& rhs) const { return string_.compare(rhs.string_) < 0; }
78 :
79 0 : friend std::ostream& operator<<(std::ostream& os, const LowerCaseString& lower_case_string) {
80 0 : return os << lower_case_string.string_;
81 0 : }
82 :
83 : // Implicit conversion to absl::string_view.
84 12358 : operator absl::string_view() const { return string_; }
85 :
86 : private:
87 81929 : void lower() {
88 81929 : std::transform(string_.begin(), string_.end(), string_.begin(), absl::ascii_tolower);
89 81929 : }
90 0 : bool valid() const { return validHeaderString(string_); }
91 :
92 : std::string string_;
93 : };
94 :
95 : /**
96 : * Convenient type for a vector of lower case string and string pair.
97 : */
98 : using LowerCaseStrPairVector =
99 : std::vector<std::pair<const Http::LowerCaseString, const std::string>>;
100 :
101 : class HeaderStringValidator {
102 : public:
103 0 : bool operator()(absl::string_view view) {
104 0 : return disable_validation_for_tests_ ? true : validHeaderString(view);
105 0 : }
106 :
107 : // This flag allows disabling the check for the NUL, CR and LF characters in the
108 : // header names or values in the DEBUG builds to prevent the `ASSERT(valid())` in the
109 : // HeaderString constructor from failing tests.
110 : static bool disable_validation_for_tests_;
111 : };
112 :
113 : class HeaderString : public UnionStringBase<HeaderStringValidator> {
114 : public:
115 : using UnionStringBase::UnionStringBase;
116 :
117 : /**
118 : * Constructor for a lower case string reference.
119 : * @param ref_value MUST point to data that will live beyond the lifetime of any request/response
120 : * using the string (since a codec may optimize for zero copy).
121 : */
122 : explicit HeaderString(const LowerCaseString& ref_value) noexcept;
123 :
124 : /**
125 : * Constructor for normal UnionString instance.
126 : * @param move_value moveable UnionString. The string value MUST be valid header string.
127 : */
128 : explicit HeaderString(UnionString&& move_value) noexcept;
129 : };
130 :
131 : /**
132 : * Encapsulates an individual header entry (including both key and value).
133 : */
134 : class HeaderEntry {
135 : public:
136 91201 : virtual ~HeaderEntry() = default;
137 :
138 : /**
139 : * @return the header key.
140 : */
141 : virtual const HeaderString& key() const PURE;
142 :
143 : /**
144 : * Set the header value by copying data into it.
145 : */
146 : virtual void value(absl::string_view value) PURE;
147 :
148 : /**
149 : * Set the header value by copying an integer into it.
150 : */
151 : virtual void value(uint64_t value) PURE;
152 :
153 : /**
154 : * Set the header value by copying the value in another header entry.
155 : */
156 : virtual void value(const HeaderEntry& header) PURE;
157 :
158 : /**
159 : * @return the header value.
160 : */
161 : virtual const HeaderString& value() const PURE;
162 :
163 : /**
164 : * @return the header value.
165 : */
166 : virtual HeaderString& value() PURE;
167 :
168 : private:
169 : void value(const char*); // Do not allow auto conversion to std::string
170 : };
171 :
172 : /**
173 : * The following defines all default request headers that Envoy allows direct access to inside of
174 : * the header map. In practice, these are all headers used during normal Envoy request flow
175 : * processing. This allows O(1) access to these headers without even a hash lookup.
176 : *
177 : */
178 : #define INLINE_REQ_STRING_HEADERS(HEADER_FUNC) \
179 33 : HEADER_FUNC(ClientTraceId) \
180 33 : HEADER_FUNC(EnvoyDownstreamServiceCluster) \
181 33 : HEADER_FUNC(EnvoyDownstreamServiceNode) \
182 33 : HEADER_FUNC(EnvoyExternalAddress) \
183 33 : HEADER_FUNC(EnvoyForceTrace) \
184 33 : HEADER_FUNC(EnvoyHedgeOnPerTryTimeout) \
185 33 : HEADER_FUNC(EnvoyInternalRequest) \
186 33 : HEADER_FUNC(EnvoyIpTags) \
187 33 : HEADER_FUNC(EnvoyRetryOn) \
188 33 : HEADER_FUNC(EnvoyRetryGrpcOn) \
189 33 : HEADER_FUNC(EnvoyRetriableStatusCodes) \
190 33 : HEADER_FUNC(EnvoyRetriableHeaderNames) \
191 33 : HEADER_FUNC(EnvoyIsTimeoutRetry) \
192 33 : HEADER_FUNC(EnvoyOriginalPath) \
193 33 : HEADER_FUNC(EnvoyOriginalUrl) \
194 33 : HEADER_FUNC(EnvoyUpstreamAltStatName) \
195 33 : HEADER_FUNC(EnvoyUpstreamRequestTimeoutAltResponse) \
196 33 : HEADER_FUNC(Expect) \
197 33 : HEADER_FUNC(ForwardedClientCert) \
198 33 : HEADER_FUNC(ForwardedFor) \
199 33 : HEADER_FUNC(ForwardedHost) \
200 33 : HEADER_FUNC(ForwardedProto) \
201 33 : HEADER_FUNC(GrpcTimeout) \
202 33 : HEADER_FUNC(Host) \
203 33 : HEADER_FUNC(Method) \
204 33 : HEADER_FUNC(Path) \
205 33 : HEADER_FUNC(Protocol) \
206 33 : HEADER_FUNC(Scheme) \
207 33 : HEADER_FUNC(TE) \
208 33 : HEADER_FUNC(UserAgent)
209 :
210 : #define INLINE_REQ_NUMERIC_HEADERS(HEADER_FUNC) \
211 33 : HEADER_FUNC(EnvoyExpectedRequestTimeoutMs) \
212 33 : HEADER_FUNC(EnvoyMaxRetries) \
213 33 : HEADER_FUNC(EnvoyUpstreamRequestTimeoutMs) \
214 33 : HEADER_FUNC(EnvoyUpstreamRequestPerTryTimeoutMs) \
215 33 : HEADER_FUNC(EnvoyUpstreamStreamDurationMs) \
216 33 : HEADER_FUNC(ForwardedPort)
217 :
218 : #define INLINE_REQ_HEADERS(HEADER_FUNC) \
219 33 : INLINE_REQ_STRING_HEADERS(HEADER_FUNC) \
220 33 : INLINE_REQ_NUMERIC_HEADERS(HEADER_FUNC)
221 :
222 : /**
223 : * Default O(1) response headers.
224 : */
225 : #define INLINE_RESP_STRING_HEADERS(HEADER_FUNC) \
226 26 : HEADER_FUNC(Date) \
227 26 : HEADER_FUNC(EnvoyDegraded) \
228 26 : HEADER_FUNC(EnvoyImmediateHealthCheckFail) \
229 26 : HEADER_FUNC(EnvoyRateLimited) \
230 26 : HEADER_FUNC(EnvoyUpstreamCanary) \
231 26 : HEADER_FUNC(EnvoyUpstreamHealthCheckedCluster) \
232 26 : HEADER_FUNC(Location) \
233 26 : HEADER_FUNC(Server)
234 :
235 : #define INLINE_RESP_NUMERIC_HEADERS(HEADER_FUNC) \
236 26 : HEADER_FUNC(EnvoyUpstreamServiceTime) \
237 26 : HEADER_FUNC(Status)
238 :
239 : #define INLINE_RESP_HEADERS(HEADER_FUNC) \
240 26 : INLINE_RESP_STRING_HEADERS(HEADER_FUNC) \
241 26 : INLINE_RESP_NUMERIC_HEADERS(HEADER_FUNC)
242 :
243 : /**
244 : * Default O(1) request and response headers.
245 : */
246 : #define INLINE_REQ_RESP_STRING_HEADERS(HEADER_FUNC) \
247 59 : HEADER_FUNC(Connection) \
248 59 : HEADER_FUNC(ContentType) \
249 59 : HEADER_FUNC(EnvoyDecoratorOperation) \
250 59 : HEADER_FUNC(KeepAlive) \
251 59 : HEADER_FUNC(ProxyConnection) \
252 59 : HEADER_FUNC(ProxyStatus) \
253 59 : HEADER_FUNC(RequestId) \
254 59 : HEADER_FUNC(TransferEncoding) \
255 59 : HEADER_FUNC(Upgrade) \
256 59 : HEADER_FUNC(Via)
257 :
258 : #define INLINE_REQ_RESP_NUMERIC_HEADERS(HEADER_FUNC) \
259 59 : HEADER_FUNC(ContentLength) \
260 59 : HEADER_FUNC(EnvoyAttemptCount)
261 :
262 : #define INLINE_REQ_RESP_HEADERS(HEADER_FUNC) \
263 59 : INLINE_REQ_RESP_STRING_HEADERS(HEADER_FUNC) \
264 59 : INLINE_REQ_RESP_NUMERIC_HEADERS(HEADER_FUNC)
265 :
266 : /**
267 : * Default O(1) response headers and trailers.
268 : */
269 49 : #define INLINE_RESP_STRING_HEADERS_TRAILERS(HEADER_FUNC) HEADER_FUNC(GrpcMessage)
270 :
271 49 : #define INLINE_RESP_NUMERIC_HEADERS_TRAILERS(HEADER_FUNC) HEADER_FUNC(GrpcStatus)
272 :
273 : #define INLINE_RESP_HEADERS_TRAILERS(HEADER_FUNC) \
274 49 : INLINE_RESP_STRING_HEADERS_TRAILERS(HEADER_FUNC) \
275 49 : INLINE_RESP_NUMERIC_HEADERS_TRAILERS(HEADER_FUNC)
276 :
277 : /**
278 : * The following functions are defined for each inline header above.
279 :
280 : * E.g., for path we have:
281 : * Path() -> returns the header entry if it exists or nullptr.
282 : * removePath() -> removes the header if it exists.
283 : * setPath(path_string) -> sets the header value to the string path_string by copying the data.
284 : *
285 : */
286 : #define DEFINE_INLINE_HEADER(name) \
287 : virtual const HeaderEntry* name() const PURE; \
288 : virtual size_t remove##name() PURE; \
289 : virtual absl::string_view get##name##Value() const PURE; \
290 : virtual void set##name(absl::string_view value) PURE;
291 :
292 : /*
293 : * For inline headers that have string values, there are also:
294 : * appendPath(path, "/") -> appends the string path with delimiter "/" to the header value.
295 : * setReferencePath(PATH) -> sets header value to reference string PATH.
296 : *
297 : */
298 : #define DEFINE_INLINE_STRING_HEADER(name) \
299 : DEFINE_INLINE_HEADER(name) \
300 : virtual void append##name(absl::string_view data, absl::string_view delimiter) PURE; \
301 : virtual void setReference##name(absl::string_view value) PURE;
302 :
303 : /*
304 : * For inline headers that use integers, there is:
305 : * setContentLength(5) -> sets the header value to the integer 5.
306 : */
307 : #define DEFINE_INLINE_NUMERIC_HEADER(name) \
308 : DEFINE_INLINE_HEADER(name) \
309 : virtual void set##name(uint64_t) PURE;
310 :
311 : /**
312 : * Wraps a set of HTTP headers.
313 : */
314 : class HeaderMap {
315 : public:
316 14120 : virtual ~HeaderMap() = default;
317 :
318 : /**
319 : * For testing. This is an exact match comparison (order matters).
320 : */
321 : virtual bool operator==(const HeaderMap& rhs) const PURE;
322 : virtual bool operator!=(const HeaderMap& rhs) const PURE;
323 :
324 : /**
325 : * Add a header via full move. This is the expected high performance paths for codecs populating
326 : * a map when receiving.
327 : * @param key supplies the header key.
328 : * @param value supplies the header value.
329 : */
330 : virtual void addViaMove(HeaderString&& key, HeaderString&& value) PURE;
331 :
332 : /**
333 : * Add a reference header to the map. Both key and value MUST point to data that will live beyond
334 : * the lifetime of any request/response using the string (since a codec may optimize for zero
335 : * copy). The key will not be copied and a best effort will be made not to
336 : * copy the value (but this may happen when comma concatenating, see below).
337 : *
338 : * Calling addReference multiple times for the same header will result in:
339 : * - Comma concatenation for predefined inline headers.
340 : * - Multiple headers being present in the HeaderMap for other headers.
341 : *
342 : * @param key specifies the name of the header to add; it WILL NOT be copied.
343 : * @param value specifies the value of the header to add; it WILL NOT be copied.
344 : */
345 : virtual void addReference(const LowerCaseString& key, absl::string_view value) PURE;
346 :
347 : /**
348 : * Add a header with a reference key to the map. The key MUST point to data that will live beyond
349 : * the lifetime of any request/response using the string (since a codec may optimize for zero
350 : * copy). The value will be copied.
351 : *
352 : * Calling addReference multiple times for the same header will result in:
353 : * - Comma concatenation for predefined inline headers.
354 : * - Multiple headers being present in the HeaderMap for other headers.
355 : *
356 : * @param key specifies the name of the header to add; it WILL NOT be copied.
357 : * @param value specifies the value of the header to add; it WILL be copied.
358 : */
359 : virtual void addReferenceKey(const LowerCaseString& key, uint64_t value) PURE;
360 :
361 : /**
362 : * Add a header with a reference key to the map. The key MUST point to data that will
363 : * live beyond the lifetime of any request/response using the string (since a codec may optimize
364 : * for zero copy). The value will be copied.
365 : *
366 : * Calling addReference multiple times for the same header will result in:
367 : * - Comma concatenation for predefined inline headers.
368 : * - Multiple headers being present in the HeaderMap for other headers.
369 : *
370 : * @param key specifies the name of the header to add; it WILL NOT be copied.
371 : * @param value specifies the value of the header to add; it WILL be copied.
372 : */
373 : virtual void addReferenceKey(const LowerCaseString& key, absl::string_view value) PURE;
374 :
375 : /**
376 : * Add a header by copying both the header key and the value.
377 : *
378 : * Calling addCopy multiple times for the same header will result in:
379 : * - Comma concatenation for predefined inline headers.
380 : * - Multiple headers being present in the HeaderMap for other headers.
381 : *
382 : * @param key specifies the name of the header to add; it WILL be copied.
383 : * @param value specifies the value of the header to add; it WILL be copied.
384 : */
385 : virtual void addCopy(const LowerCaseString& key, uint64_t value) PURE;
386 :
387 : /**
388 : * Add a header by copying both the header key and the value.
389 : *
390 : * Calling addCopy multiple times for the same header will result in:
391 : * - Comma concatenation for predefined inline headers.
392 : * - Multiple headers being present in the HeaderMap for other headers.
393 : *
394 : * @param key specifies the name of the header to add; it WILL be copied.
395 : * @param value specifies the value of the header to add; it WILL be copied.
396 : */
397 : virtual void addCopy(const LowerCaseString& key, absl::string_view value) PURE;
398 :
399 : /**
400 : * Appends data to header. If header already has a value, the string "," is added between the
401 : * existing value and data.
402 : *
403 : * @param key specifies the name of the header to append; it WILL be copied.
404 : * @param value specifies the value of the header to add; it WILL be copied.
405 : *
406 : * Caution: This iterates over the HeaderMap to find the header to append. This will modify only
407 : * the first occurrence of the header.
408 : * TODO(asraa): Investigate whether necessary to append to all headers with the key.
409 : */
410 : virtual void appendCopy(const LowerCaseString& key, absl::string_view value) PURE;
411 :
412 : /**
413 : * Set a reference header in the map. Both key and value MUST point to data that will live beyond
414 : * the lifetime of any request/response using the string (since a codec may optimize for zero
415 : * copy). Nothing will be copied.
416 : *
417 : * Calling setReference multiple times for the same header will result in only the last header
418 : * being present in the HeaderMap.
419 : *
420 : * @param key specifies the name of the header to set; it WILL NOT be copied.
421 : * @param value specifies the value of the header to set; it WILL NOT be copied.
422 : */
423 : virtual void setReference(const LowerCaseString& key, absl::string_view value) PURE;
424 :
425 : /**
426 : * Set a header with a reference key in the map. The key MUST point to point to data that will
427 : * live beyond the lifetime of any request/response using the string (since a codec may optimize
428 : * for zero copy). The value will be copied.
429 : *
430 : * Calling setReferenceKey multiple times for the same header will result in only the last header
431 : * being present in the HeaderMap.
432 : *
433 : * @param key specifies the name of the header to set; it WILL NOT be copied.
434 : * @param value specifies the value of the header to set; it WILL be copied.
435 : */
436 : virtual void setReferenceKey(const LowerCaseString& key, absl::string_view value) PURE;
437 :
438 : /**
439 : * Replaces a header value by copying the value. Copies the key if the key does not exist.
440 : * If there are multiple values for one header, this removes all existing values and add
441 : * the new one.
442 : *
443 : * Calling setCopy multiple times for the same header will result in only the last header
444 : * being present in the HeaderMap.
445 : *
446 : * @param key specifies the name of the header to set; it WILL be copied.
447 : * @param value specifies the value of the header to set; it WILL be copied.
448 : * TODO(asraa): Investigate whether necessary to set all headers with the key.
449 : */
450 : virtual void setCopy(const LowerCaseString& key, absl::string_view value) PURE;
451 :
452 : /**
453 : * @return uint64_t the size of the header map in bytes. This is the sum of the header keys and
454 : * values and does not account for data structure overhead.
455 : */
456 : virtual uint64_t byteSize() const PURE;
457 :
458 : /**
459 : * @return uint32_t the max size of the header map in kilobyte.
460 : */
461 : virtual uint32_t maxHeadersKb() const PURE;
462 :
463 : /**
464 : * @return uint32_t the max count of headers in a header map.
465 : */
466 : virtual uint32_t maxHeadersCount() const PURE;
467 :
468 : /**
469 : * This is a wrapper for the return result from get(). It avoids a copy when translating from
470 : * non-const HeaderEntry to const HeaderEntry and only provides const access to the result.
471 : */
472 : using NonConstGetResult = absl::InlinedVector<HeaderEntry*, 1>;
473 : class GetResult {
474 : public:
475 0 : GetResult() = default;
476 6772 : explicit GetResult(NonConstGetResult&& result) : result_(std::move(result)) {}
477 0 : void operator=(GetResult&& rhs) noexcept { result_ = std::move(rhs.result_); }
478 :
479 10497 : bool empty() const { return result_.empty(); }
480 66461 : size_t size() const { return result_.size(); }
481 68679 : const HeaderEntry* operator[](size_t i) const { return result_[i]; }
482 :
483 : private:
484 : NonConstGetResult result_;
485 : };
486 :
487 : /**
488 : * Get a header by key.
489 : * @param key supplies the header key.
490 : * @return all header entries matching the key.
491 : */
492 : virtual GetResult get(const LowerCaseString& key) const PURE;
493 :
494 : // aliases to make iterate() and iterateReverse() callbacks easier to read
495 : enum class Iterate { Continue, Break };
496 :
497 : /**
498 : * Callback when calling iterate() over a const header map.
499 : * @param header supplies the header entry.
500 : * @return Iterate::Continue to continue iteration, or Iterate::Break to stop;
501 : */
502 : using ConstIterateCb = std::function<Iterate(const HeaderEntry&)>;
503 :
504 : /**
505 : * Iterate over a constant header map.
506 : * @param cb supplies the iteration callback.
507 : */
508 : virtual void iterate(ConstIterateCb cb) const PURE;
509 :
510 : /**
511 : * Iterate over a constant header map in reverse order.
512 : * @param cb supplies the iteration callback.
513 : */
514 : virtual void iterateReverse(ConstIterateCb cb) const PURE;
515 :
516 : /**
517 : * Clears the headers in the map.
518 : */
519 : virtual void clear() PURE;
520 :
521 : /**
522 : * Remove all instances of a header by key.
523 : * @param key supplies the header key to remove.
524 : * @return the number of headers removed.
525 : */
526 : virtual size_t remove(const LowerCaseString& key) PURE;
527 :
528 : /**
529 : * Remove all instances of headers where the header matches the predicate.
530 : * @param predicate supplies the predicate to match headers against.
531 : * @return the number of headers removed.
532 : */
533 : using HeaderMatchPredicate = std::function<bool(const HeaderEntry&)>;
534 : virtual size_t removeIf(const HeaderMatchPredicate& predicate) PURE;
535 :
536 : /**
537 : * Remove all instances of headers where the key begins with the supplied prefix.
538 : * @param prefix supplies the prefix to match header keys against.
539 : * @return the number of headers removed.
540 : */
541 : virtual size_t removePrefix(const LowerCaseString& prefix) PURE;
542 :
543 : /**
544 : * @return the number of headers in the map.
545 : */
546 : virtual size_t size() const PURE;
547 :
548 : /**
549 : * @return true if the map is empty, false otherwise.
550 : */
551 : virtual bool empty() const PURE;
552 :
553 : /**
554 : * Dump the header map to the ostream specified
555 : *
556 : * @param os the stream to dump state to
557 : * @param indent_level the depth, for pretty-printing.
558 : *
559 : * This function is called on Envoy fatal errors so should avoid memory allocation where possible.
560 : */
561 : virtual void dumpState(std::ostream& os, int indent_level = 0) const PURE;
562 :
563 : /**
564 : * Allow easy pretty-printing of the key/value pairs in HeaderMap
565 : * @param os supplies the ostream to print to.
566 : * @param headers the headers to print.
567 : */
568 0 : friend std::ostream& operator<<(std::ostream& os, const HeaderMap& headers) {
569 0 : headers.dumpState(os);
570 0 : return os;
571 0 : }
572 :
573 : /**
574 : * Return the optional stateful formatter attached to this header map.
575 : *
576 : * Filters can use the non-const version to process additional header keys during operation if
577 : * they wish. The sequence of events would be to first add/modify the header map, and then call
578 : * processKey(), similar to what is done when headers are received by the codec.
579 : *
580 : * TODO(mattklein123): The above sequence will not work for headers added via route (headers to
581 : * add, etc.). We can potentially add direct processKey() calls in these places as a follow up.
582 : */
583 : virtual StatefulHeaderKeyFormatterOptConstRef formatter() const PURE;
584 : virtual StatefulHeaderKeyFormatterOptRef formatter() PURE;
585 : };
586 :
587 : using HeaderMapPtr = std::unique_ptr<HeaderMap>;
588 :
589 : /**
590 : * Wraps a set of header modifications.
591 : */
592 : struct HeaderTransforms {
593 : std::vector<std::pair<Http::LowerCaseString, std::string>> headers_to_append_or_add;
594 : std::vector<std::pair<Http::LowerCaseString, std::string>> headers_to_overwrite_or_add;
595 : std::vector<std::pair<Http::LowerCaseString, std::string>> headers_to_add_if_absent;
596 : std::vector<Http::LowerCaseString> headers_to_remove;
597 : };
598 :
599 : /**
600 : * Registry for custom headers. Headers can be registered multiple times in independent
601 : * compilation units and will still point to the same slot. Headers are registered independently
602 : * for each concrete header map type and do not overlap. Handles are strongly typed and do not
603 : * allow mixing.
604 : */
605 : class CustomInlineHeaderRegistry {
606 : public:
607 : enum class Type { RequestHeaders, RequestTrailers, ResponseHeaders, ResponseTrailers };
608 : using RegistrationMap = std::map<LowerCaseString, size_t>;
609 :
610 : // A "phantom" type is used here to force the compiler to verify that handles are not mixed
611 : // between concrete header map types.
612 : template <Type type> struct Handle {
613 4224 : Handle(RegistrationMap::const_iterator it) : it_(it) {}
614 : bool operator==(const Handle& rhs) const { return it_ == rhs.it_; }
615 :
616 : RegistrationMap::const_iterator it_;
617 : };
618 :
619 : /**
620 : * Register an inline header and return a handle for use in inline header calls. Must be called
621 : * prior to finalize().
622 : */
623 : template <Type type>
624 2407 : static Handle<type> registerInlineHeader(const LowerCaseString& header_name) {
625 2407 : static size_t inline_header_index = 0;
626 :
627 2407 : ASSERT(!mutableFinalized<type>());
628 2407 : auto& map = mutableRegistrationMap<type>();
629 2407 : auto entry = map.find(header_name);
630 2407 : if (entry == map.end()) {
631 2358 : map[header_name] = inline_header_index++;
632 2358 : }
633 2407 : return Handle<type>(map.find(header_name));
634 2407 : }
635 :
636 : /**
637 : * Fetch the handle for a registered inline header. May only be called after finalized().
638 : */
639 : template <Type type>
640 1817 : static absl::optional<Handle<type>> getInlineHeader(const LowerCaseString& header_name) {
641 1817 : ASSERT(mutableFinalized<type>());
642 1817 : auto& map = mutableRegistrationMap<type>();
643 1817 : auto entry = map.find(header_name);
644 1817 : if (entry != map.end()) {
645 1817 : return Handle<type>(entry);
646 1817 : }
647 0 : return absl::nullopt;
648 1817 : }
649 :
650 : /**
651 : * Fetch all registered headers. May only be called after finalized().
652 : */
653 637 : template <Type type> static const RegistrationMap& headers() {
654 637 : ASSERT(mutableFinalized<type>());
655 637 : return mutableRegistrationMap<type>();
656 637 : }
657 :
658 : /**
659 : * Finalize the custom header registrations. No further changes are allowed after this point.
660 : * This guaranteed that all header maps created by the process have the same variable size and
661 : * custom registrations.
662 : */
663 101 : template <Type type> static void finalize() {
664 101 : ASSERT(!mutableFinalized<type>());
665 101 : mutableFinalized<type>() = true;
666 101 : }
667 :
668 : private:
669 4861 : template <Type type> static RegistrationMap& mutableRegistrationMap() {
670 4861 : MUTABLE_CONSTRUCT_ON_FIRST_USE(RegistrationMap);
671 4861 : }
672 101 : template <Type type> static bool& mutableFinalized() { MUTABLE_CONSTRUCT_ON_FIRST_USE(bool); }
673 : };
674 :
675 : /**
676 : * Static initializer to register a custom header in a compilation unit. This can be used by
677 : * extensions to register custom headers.
678 : */
679 : template <CustomInlineHeaderRegistry::Type type> class RegisterCustomInlineHeader {
680 : public:
681 : RegisterCustomInlineHeader(const LowerCaseString& header)
682 153 : : handle_(CustomInlineHeaderRegistry::registerInlineHeader<type>(header)) {}
683 :
684 11 : typename CustomInlineHeaderRegistry::Handle<type> handle() { return handle_; }
685 :
686 : private:
687 : const typename CustomInlineHeaderRegistry::Handle<type> handle_;
688 : };
689 :
690 : /**
691 : * The following functions allow O(1) access for custom inline headers.
692 : */
693 : template <CustomInlineHeaderRegistry::Type type> class CustomInlineHeaderBase {
694 : public:
695 14120 : virtual ~CustomInlineHeaderBase() = default;
696 :
697 : static constexpr CustomInlineHeaderRegistry::Type header_map_type = type;
698 : using Handle = CustomInlineHeaderRegistry::Handle<header_map_type>;
699 :
700 : virtual const HeaderEntry* getInline(Handle handle) const PURE;
701 : virtual void appendInline(Handle handle, absl::string_view data,
702 : absl::string_view delimiter) PURE;
703 : virtual void setReferenceInline(Handle, absl::string_view value) PURE;
704 : virtual void setInline(Handle, absl::string_view value) PURE;
705 : virtual void setInline(Handle, uint64_t value) PURE;
706 : virtual size_t removeInline(Handle handle) PURE;
707 16037 : absl::string_view getInlineValue(Handle handle) const {
708 16037 : const auto header = getInline(handle);
709 16037 : if (header != nullptr) {
710 12029 : return header->value().getStringView();
711 12029 : }
712 4008 : return {};
713 16037 : }
714 : };
715 :
716 : /**
717 : * Typed derived classes for all header map types.
718 : */
719 :
720 : // Base class for both request and response headers.
721 : class RequestOrResponseHeaderMap : public HeaderMap {
722 : public:
723 : INLINE_REQ_RESP_STRING_HEADERS(DEFINE_INLINE_STRING_HEADER)
724 : INLINE_REQ_RESP_NUMERIC_HEADERS(DEFINE_INLINE_NUMERIC_HEADER)
725 : };
726 :
727 : // Request headers.
728 : class RequestHeaderMap
729 : : public RequestOrResponseHeaderMap,
730 : public CustomInlineHeaderBase<CustomInlineHeaderRegistry::Type::RequestHeaders> {
731 : public:
732 : INLINE_REQ_STRING_HEADERS(DEFINE_INLINE_STRING_HEADER)
733 : INLINE_REQ_NUMERIC_HEADERS(DEFINE_INLINE_NUMERIC_HEADER)
734 : };
735 : using RequestHeaderMapPtr = std::unique_ptr<RequestHeaderMap>;
736 : using RequestHeaderMapSharedPtr = std::shared_ptr<RequestHeaderMap>;
737 : using RequestHeaderMapConstSharedPtr = std::shared_ptr<const RequestHeaderMap>;
738 : using RequestHeaderMapOptRef = OptRef<RequestHeaderMap>;
739 : using RequestHeaderMapOptConstRef = OptRef<const RequestHeaderMap>;
740 :
741 : // Request trailers.
742 : class RequestTrailerMap
743 : : public HeaderMap,
744 : public CustomInlineHeaderBase<CustomInlineHeaderRegistry::Type::RequestTrailers> {};
745 : using RequestTrailerMapPtr = std::unique_ptr<RequestTrailerMap>;
746 : using RequestTrailerMapOptRef = OptRef<RequestTrailerMap>;
747 : using RequestTrailerMapOptConstRef = OptRef<const RequestTrailerMap>;
748 :
749 : // Base class for both response headers and trailers.
750 : class ResponseHeaderOrTrailerMap {
751 : public:
752 4600 : virtual ~ResponseHeaderOrTrailerMap() = default;
753 :
754 : INLINE_RESP_STRING_HEADERS_TRAILERS(DEFINE_INLINE_STRING_HEADER)
755 : INLINE_RESP_NUMERIC_HEADERS_TRAILERS(DEFINE_INLINE_NUMERIC_HEADER)
756 : };
757 :
758 : // Response headers.
759 : class ResponseHeaderMap
760 : : public RequestOrResponseHeaderMap,
761 : public ResponseHeaderOrTrailerMap,
762 : public CustomInlineHeaderBase<CustomInlineHeaderRegistry::Type::ResponseHeaders> {
763 : public:
764 : INLINE_RESP_STRING_HEADERS(DEFINE_INLINE_STRING_HEADER)
765 : INLINE_RESP_NUMERIC_HEADERS(DEFINE_INLINE_NUMERIC_HEADER)
766 : };
767 : using ResponseHeaderMapPtr = std::unique_ptr<ResponseHeaderMap>;
768 : using ResponseHeaderMapSharedPtr = std::shared_ptr<ResponseHeaderMap>;
769 : using ResponseHeaderMapConstSharedPtr = std::shared_ptr<const ResponseHeaderMap>;
770 : using ResponseHeaderMapOptRef = OptRef<ResponseHeaderMap>;
771 : using ResponseHeaderMapOptConstRef = OptRef<const ResponseHeaderMap>;
772 :
773 : // Response trailers.
774 : class ResponseTrailerMap
775 : : public ResponseHeaderOrTrailerMap,
776 : public HeaderMap,
777 : public CustomInlineHeaderBase<CustomInlineHeaderRegistry::Type::ResponseTrailers> {};
778 : using ResponseTrailerMapPtr = std::unique_ptr<ResponseTrailerMap>;
779 : using ResponseTrailerMapSharedPtr = std::shared_ptr<ResponseTrailerMap>;
780 : using ResponseTrailerMapConstSharedPtr = std::shared_ptr<const ResponseTrailerMap>;
781 : using ResponseTrailerMapOptRef = OptRef<ResponseTrailerMap>;
782 : using ResponseTrailerMapOptConstRef = OptRef<const ResponseTrailerMap>;
783 :
784 : /**
785 : * Convenient container type for storing Http::LowerCaseString and std::string key/value pairs.
786 : */
787 : using HeaderVector = std::vector<std::pair<LowerCaseString, std::string>>;
788 :
789 : /**
790 : * An interface to be implemented by header matchers.
791 : */
792 : class HeaderMatcher {
793 : public:
794 72 : virtual ~HeaderMatcher() = default;
795 :
796 : /**
797 : * Check whether header matcher matches any headers in a given HeaderMap.
798 : */
799 : virtual bool matchesHeaders(const HeaderMap& headers) const PURE;
800 : };
801 :
802 : using HeaderMatcherSharedPtr = std::shared_ptr<HeaderMatcher>;
803 :
804 : } // namespace Http
805 : } // namespace Envoy
806 :
807 : // NOLINT(namespace-envoy)
808 : namespace fmt {
809 : // Allow fmtlib to use operator << defined in HeaderMap and LowerCaseString
810 : template <> struct formatter<::Envoy::Http::LowerCaseString> : ostream_formatter {};
811 :
812 : template <typename HeaderMapType>
813 : struct formatter<
814 : HeaderMapType,
815 : std::enable_if_t<std::is_base_of<::Envoy::Http::HeaderMap, HeaderMapType>::value, char>>
816 : : ostream_formatter {};
817 : } // namespace fmt
|