Line data Source code
1 : #pragma once
2 :
3 : #include <array>
4 : #include <cstdint>
5 : #include <list>
6 : #include <memory>
7 : #include <string>
8 : #include <type_traits>
9 :
10 : #include "envoy/common/optref.h"
11 : #include "envoy/http/header_map.h"
12 :
13 : #include "source/common/common/non_copyable.h"
14 : #include "source/common/common/utility.h"
15 : #include "source/common/http/headers.h"
16 : #include "source/common/runtime/runtime_features.h"
17 :
18 : namespace Envoy {
19 : namespace Http {
20 :
21 : /**
22 : * These are definitions of all of the inline header access functions described inside header_map.h
23 : */
24 : #define DEFINE_INLINE_HEADER_FUNCS(name) \
25 : public: \
26 36672 : const HeaderEntry* name() const override { return getInline(HeaderHandles::get().name); } \
27 14060 : size_t remove##name() override { return removeInline(HeaderHandles::get().name); } \
28 16028 : absl::string_view get##name##Value() const override { \
29 16028 : return getInlineValue(HeaderHandles::get().name); \
30 16028 : } \
31 5341 : void set##name(absl::string_view value) override { setInline(HeaderHandles::get().name, value); }
32 :
33 : #define DEFINE_INLINE_HEADER_STRING_FUNCS(name) \
34 : DEFINE_INLINE_HEADER_FUNCS(name) \
35 189 : void append##name(absl::string_view data, absl::string_view delimiter) override { \
36 189 : appendInline(HeaderHandles::get().name, data, delimiter); \
37 189 : } \
38 2565 : void setReference##name(absl::string_view value) override { \
39 2565 : setReferenceInline(HeaderHandles::get().name, value); \
40 2565 : }
41 :
42 : #define DEFINE_INLINE_HEADER_NUMERIC_FUNCS(name) \
43 : DEFINE_INLINE_HEADER_FUNCS(name) \
44 817 : void set##name(uint64_t value) override { setInline(HeaderHandles::get().name, value); }
45 :
46 : /**
47 : * Implementation of Http::HeaderMap. This is heavily optimized for performance. Roughly, when
48 : * headers are added to the map by string, we do a trie lookup to see if it's one of the O(1)
49 : * headers. If it is, we store a reference to it that can be accessed later directly via direct
50 : * method access. Most high performance paths use O(1) direct method access. In general, we try to
51 : * copy as little as possible and allocate as little as possible in any of the paths.
52 : */
53 : class HeaderMapImpl : NonCopyable {
54 : public:
55 : HeaderMapImpl(const uint32_t max_headers_kb = UINT32_MAX,
56 : const uint32_t max_headers_count = UINT32_MAX)
57 10236 : : max_headers_kb_(max_headers_kb), max_headers_count_(max_headers_count) {}
58 10200 : virtual ~HeaderMapImpl() = default;
59 :
60 : // The following "constructors" call virtual functions during construction and must use the
61 : // static factory pattern.
62 : static void copyFrom(HeaderMap& lhs, const HeaderMap& rhs);
63 : // The value_type of iterator must be pair, and the first value of them must be LowerCaseString.
64 : // If not, it won't be compiled successfully.
65 487 : template <class It> static void initFromInitList(HeaderMap& new_header_map, It begin, It end) {
66 1070 : for (auto it = begin; it != end; ++it) {
67 583 : static_assert(std::is_same<decltype(it->first), LowerCaseString>::value,
68 583 : "iterator must be pair and the first value of them must be LowerCaseString");
69 583 : HeaderString key_string;
70 583 : key_string.setCopy(it->first.get().c_str(), it->first.get().size());
71 583 : HeaderString value_string;
72 583 : value_string.setCopy(it->second.c_str(), it->second.size());
73 583 : new_header_map.addViaMove(std::move(key_string), std::move(value_string));
74 583 : }
75 487 : }
76 :
77 : // Performs a manual byte size count for test verification.
78 : void verifyByteSizeInternalForTest() const;
79 :
80 : // Note: This class does not actually implement Http::HeaderMap to avoid virtual inheritance in
81 : // the derived classes. Instead, it is used as a mix-in class for TypedHeaderMapImpl below. This
82 : // both avoid virtual inheritance and allows the concrete final header maps to use a variable
83 : // length member at the end.
84 : bool operator==(const HeaderMap& rhs) const;
85 : bool operator!=(const HeaderMap& rhs) const;
86 : void addViaMove(HeaderString&& key, HeaderString&& value);
87 : void addReference(const LowerCaseString& key, absl::string_view value);
88 : void addReferenceKey(const LowerCaseString& key, uint64_t value);
89 : void addReferenceKey(const LowerCaseString& key, absl::string_view value);
90 : void addCopy(const LowerCaseString& key, uint64_t value);
91 : void addCopy(const LowerCaseString& key, absl::string_view value);
92 : void appendCopy(const LowerCaseString& key, absl::string_view value);
93 : void setReference(const LowerCaseString& key, absl::string_view value);
94 : void setReferenceKey(const LowerCaseString& key, absl::string_view value);
95 : void setCopy(const LowerCaseString& key, absl::string_view value);
96 : uint64_t byteSize() const;
97 11 : uint32_t maxHeadersKb() const { return max_headers_kb_; }
98 22 : uint32_t maxHeadersCount() const { return max_headers_count_; }
99 : HeaderMap::GetResult get(const LowerCaseString& key) const;
100 : void iterate(HeaderMap::ConstIterateCb cb) const;
101 : void iterateReverse(HeaderMap::ConstIterateCb cb) const;
102 : void clear();
103 : size_t remove(const LowerCaseString& key);
104 : size_t removeIf(const HeaderMap::HeaderMatchPredicate& predicate);
105 : size_t removePrefix(const LowerCaseString& key);
106 34902 : size_t size() const { return headers_.size(); }
107 58 : bool empty() const { return headers_.empty(); }
108 : void dumpState(std::ostream& os, int indent_level = 0) const;
109 758 : StatefulHeaderKeyFormatterOptConstRef formatter() const {
110 758 : return StatefulHeaderKeyFormatterOptConstRef(makeOptRefFromPtr(formatter_.get()));
111 758 : }
112 2787 : StatefulHeaderKeyFormatterOptRef formatter() { return makeOptRefFromPtr(formatter_.get()); }
113 :
114 : protected:
115 : struct HeaderEntryImpl : public HeaderEntry, NonCopyable {
116 : HeaderEntryImpl(const LowerCaseString& key);
117 : HeaderEntryImpl(const LowerCaseString& key, HeaderString&& value);
118 : HeaderEntryImpl(HeaderString&& key, HeaderString&& value);
119 :
120 : // HeaderEntry
121 145747 : const HeaderString& key() const override { return key_; }
122 : void value(absl::string_view value) override;
123 : void value(uint64_t value) override;
124 : void value(const HeaderEntry& header) override;
125 155684 : const HeaderString& value() const override { return value_; }
126 20344 : HeaderString& value() override { return value_; }
127 :
128 : HeaderString key_;
129 : HeaderString value_;
130 : std::list<HeaderEntryImpl>::iterator entry_;
131 : };
132 : using HeaderNode = std::list<HeaderEntryImpl>::iterator;
133 :
134 : /**
135 : * This is the static lookup table that is used to determine whether a header is one of the O(1)
136 : * headers. This uses a trie for lookup time at most equal to the size of the incoming string.
137 : */
138 : struct StaticLookupResponse {
139 : HeaderEntryImpl** entry_;
140 : const LowerCaseString* key_;
141 : };
142 :
143 : /**
144 : * Base class for a static lookup table that converts a string key into an O(1) header.
145 : */
146 : template <class Interface>
147 : struct StaticLookupTable
148 : : public TrieLookupTable<std::function<StaticLookupResponse(HeaderMapImpl&)>> {
149 : StaticLookupTable();
150 :
151 101 : void finalizeTable() {
152 101 : CustomInlineHeaderRegistry::finalize<Interface::header_map_type>();
153 101 : auto& headers = CustomInlineHeaderRegistry::headers<Interface::header_map_type>();
154 101 : size_ = headers.size();
155 2324 : for (const auto& header : headers) {
156 16588 : this->add(header.first.get().c_str(), [&header](HeaderMapImpl& h) -> StaticLookupResponse {
157 16016 : return {&h.inlineHeaders()[header.second], &header.first};
158 16016 : });
159 2324 : }
160 101 : }
161 :
162 22207 : static size_t size() {
163 : // The size of the lookup table is finalized when the singleton lookup table is created. This
164 : // allows for late binding of custom headers as well as envoy header prefix changes. This
165 : // does mean that once the first header map is created of this type, no further changes are
166 : // possible.
167 : // TODO(mattklein123): If we decide to keep this implementation, it is conceivable that header
168 : // maps could be created by an API factory that is owned by the listener/HCM, thus making
169 : // O(1) header delivery over xDS possible.
170 22207 : return ConstSingleton<StaticLookupTable>::get().size_;
171 22207 : }
172 :
173 : static absl::optional<StaticLookupResponse> lookup(HeaderMapImpl& header_map,
174 92639 : absl::string_view key) {
175 92639 : const auto& entry = ConstSingleton<StaticLookupTable>::get().find(key);
176 92639 : if (entry != nullptr) {
177 16351 : return entry(header_map);
178 86743 : } else {
179 76288 : return absl::nullopt;
180 76288 : }
181 92639 : }
182 :
183 : size_t size_;
184 : };
185 :
186 : /**
187 : * List of HeaderEntryImpl that keeps the pseudo headers (key starting with ':') in the front
188 : * of the list (as required by nghttp2) and otherwise maintains insertion order.
189 : * When the list size is greater or equal to 3, all headers are added to a map, to allow fast
190 : * access given a header key. Once the map is initialized, it will be used even
191 : * if the number of headers decreases below the threshold.
192 : *
193 : * Note: the internal iterators held in fields make this unsafe to copy and move, since the
194 : * reference to end() is not preserved across a move (see Notes in
195 : * https://en.cppreference.com/w/cpp/container/list/list). The NonCopyable will suppress both copy
196 : * and move constructors/assignment.
197 : * TODO(htuch): Maybe we want this to movable one day; for now, our header map moves happen on
198 : * HeaderMapPtr, so the performance impact should not be evident.
199 : */
200 : class HeaderList : NonCopyable {
201 : public:
202 : using HeaderNodeVector = absl::InlinedVector<HeaderNode, 1>;
203 : using HeaderLazyMap = absl::flat_hash_map<absl::string_view, HeaderNodeVector>;
204 :
205 10236 : HeaderList() : pseudo_headers_end_(headers_.end()) {}
206 :
207 73632 : template <class Key> bool isPseudoHeader(const Key& key) {
208 73632 : return !key.getStringView().empty() && key.getStringView()[0] == ':';
209 73632 : }
210 :
211 91201 : template <class Key, class... Value> HeaderNode insert(Key&& key, Value&&... value) {
212 91201 : const bool is_pseudo_header = isPseudoHeader(key);
213 91201 : HeaderNode i = headers_.emplace(is_pseudo_header ? pseudo_headers_end_ : headers_.end(),
214 91201 : std::forward<Key>(key), std::forward<Value>(value)...);
215 91201 : if (!lazy_map_.empty()) {
216 1979 : lazy_map_[i->key().getStringView()].push_back(i);
217 1979 : }
218 91201 : if (!is_pseudo_header && pseudo_headers_end_ == headers_.end()) {
219 3742 : pseudo_headers_end_ = i;
220 3742 : }
221 91201 : return i;
222 91201 : }
223 :
224 501 : HeaderNode erase(HeaderNode i, bool remove_from_map) {
225 501 : if (pseudo_headers_end_ == i) {
226 213 : pseudo_headers_end_++;
227 213 : }
228 501 : if (remove_from_map) {
229 260 : lazy_map_.erase(i->key().getStringView());
230 260 : }
231 501 : return headers_.erase(i);
232 501 : }
233 :
234 67 : template <class UnaryPredicate> void removeIf(UnaryPredicate p) {
235 67 : if (!lazy_map_.empty()) {
236 : // Lazy map is used, iterate over its elements and remove those that satisfy the predicate
237 : // from the map and from the list.
238 43 : for (auto map_it = lazy_map_.begin(); map_it != lazy_map_.end();) {
239 33 : auto& values_vec = map_it->second;
240 33 : ASSERT(!values_vec.empty());
241 : // The following call to std::remove_if removes the elements that satisfy the
242 : // UnaryPredicate and shifts the vector elements, but does not resize the vector.
243 : // The call to erase that follows erases the unneeded cells (from remove_pos to the
244 : // end) and modifies the vector's size.
245 33 : const auto remove_pos =
246 47 : std::remove_if(values_vec.begin(), values_vec.end(), [&](HeaderNode it) {
247 47 : if (p(*(it->entry_))) {
248 : // Remove the element from the list.
249 20 : if (pseudo_headers_end_ == it->entry_) {
250 12 : pseudo_headers_end_++;
251 12 : }
252 20 : headers_.erase(it);
253 20 : return true;
254 20 : }
255 27 : return false;
256 47 : });
257 33 : values_vec.erase(remove_pos, values_vec.end());
258 :
259 : // If all elements were removed from the map entry, erase it.
260 33 : if (values_vec.empty()) {
261 8 : lazy_map_.erase(map_it++);
262 25 : } else {
263 25 : map_it++;
264 25 : }
265 33 : }
266 57 : } else {
267 : // The lazy map isn't used, iterate over the list elements and remove elements that satisfy
268 : // the predicate.
269 57 : headers_.remove_if([&](const HeaderEntryImpl& entry) {
270 54 : const bool to_remove = p(entry);
271 54 : if (to_remove) {
272 5 : if (pseudo_headers_end_ == entry.entry_) {
273 3 : pseudo_headers_end_++;
274 3 : }
275 5 : }
276 54 : return to_remove;
277 54 : });
278 57 : }
279 67 : }
280 :
281 : /*
282 : * Creates and populates a map if the number of headers is at least 3.
283 : *
284 : * @return if a map was created.
285 : */
286 : bool maybeMakeMap();
287 :
288 : /*
289 : * Removes a given key and its values from the HeaderList.
290 : *
291 : * @return the number of bytes that were removed.
292 : */
293 : size_t remove(absl::string_view key);
294 :
295 866 : std::list<HeaderEntryImpl>::iterator begin() { return headers_.begin(); }
296 866 : std::list<HeaderEntryImpl>::iterator end() { return headers_.end(); }
297 18746 : std::list<HeaderEntryImpl>::const_iterator begin() const { return headers_.begin(); }
298 18746 : std::list<HeaderEntryImpl>::const_iterator end() const { return headers_.end(); }
299 6737 : std::list<HeaderEntryImpl>::const_reverse_iterator rbegin() const { return headers_.rbegin(); }
300 21719 : std::list<HeaderEntryImpl>::const_reverse_iterator rend() const { return headers_.rend(); }
301 1107 : HeaderLazyMap::iterator mapFind(absl::string_view key) { return lazy_map_.find(key); }
302 1107 : HeaderLazyMap::iterator mapEnd() { return lazy_map_.end(); }
303 36584 : size_t size() const { return headers_.size(); }
304 58 : bool empty() const { return headers_.empty(); }
305 1199 : void clear() {
306 1199 : headers_.clear();
307 1199 : pseudo_headers_end_ = headers_.end();
308 1199 : lazy_map_.clear();
309 1199 : }
310 :
311 : private:
312 : std::list<HeaderEntryImpl> headers_;
313 : HeaderNode pseudo_headers_end_;
314 : HeaderLazyMap lazy_map_;
315 : };
316 :
317 : void insertByKey(HeaderString&& key, HeaderString&& value);
318 : static uint64_t appendToHeader(HeaderString& header, absl::string_view data,
319 : absl::string_view delimiter = ",");
320 : HeaderEntryImpl& maybeCreateInline(HeaderEntryImpl** entry, const LowerCaseString& key);
321 : HeaderEntryImpl& maybeCreateInline(HeaderEntryImpl** entry, const LowerCaseString& key,
322 : HeaderString&& value);
323 :
324 : HeaderMap::NonConstGetResult getExisting(absl::string_view key);
325 : size_t removeExisting(absl::string_view key);
326 :
327 : size_t removeInline(HeaderEntryImpl** entry);
328 : void updateSize(uint64_t from_size, uint64_t to_size);
329 : void addSize(uint64_t size);
330 : void subtractSize(uint64_t size);
331 : virtual absl::optional<StaticLookupResponse> staticLookup(absl::string_view) PURE;
332 : virtual void clearInline() PURE;
333 : virtual HeaderEntryImpl** inlineHeaders() PURE;
334 :
335 : HeaderList headers_;
336 : // TODO(mattklein123): The formatter does not currently get copied when a header map gets
337 : // copied. This may be problematic in certain cases like request shadowing. This is omitted
338 : // on purpose until someone asks for it, at which point a clone() method can be created to
339 : // avoid using extra space/processing for a shared_ptr.
340 : StatefulHeaderKeyFormatterPtr formatter_;
341 : // This holds the internal byte size of the HeaderMap.
342 : uint64_t cached_byte_size_ = 0;
343 : // This holds the max size of the headers in kilobyte in the HeaderMap.
344 : const uint32_t max_headers_kb_ = UINT32_MAX;
345 : // This holds the max count of the headers in the HeaderMap.
346 : const uint32_t max_headers_count_ = UINT32_MAX;
347 : };
348 :
349 : /**
350 : * Typed derived classes for all header map types. This class implements the actual typed
351 : * interface and for the majority of methods just passes through to the HeaderMapImpl mix-in. Per
352 : * above, this avoids virtual inheritance.
353 : */
354 : template <class Interface> class TypedHeaderMapImpl : public HeaderMapImpl, public Interface {
355 : public:
356 : TypedHeaderMapImpl(const uint32_t max_headers_kb = UINT32_MAX,
357 : const uint32_t max_headers_count = UINT32_MAX)
358 10236 : : HeaderMapImpl(max_headers_kb, max_headers_count) {}
359 1975 : void setFormatter(StatefulHeaderKeyFormatterPtr&& formatter) {
360 1975 : formatter_ = std::move(formatter);
361 1975 : }
362 :
363 : // Implementation of Http::HeaderMap that passes through to HeaderMapImpl.
364 0 : bool operator==(const HeaderMap& rhs) const override { return HeaderMapImpl::operator==(rhs); }
365 0 : bool operator!=(const HeaderMap& rhs) const override { return HeaderMapImpl::operator!=(rhs); }
366 13308 : void addViaMove(HeaderString&& key, HeaderString&& value) override {
367 13308 : HeaderMapImpl::addViaMove(std::move(key), std::move(value));
368 13308 : }
369 409 : void addReference(const LowerCaseString& key, absl::string_view value) override {
370 409 : HeaderMapImpl::addReference(key, value);
371 409 : }
372 48 : void addReferenceKey(const LowerCaseString& key, uint64_t value) override {
373 48 : HeaderMapImpl::addReferenceKey(key, value);
374 48 : }
375 335 : void addReferenceKey(const LowerCaseString& key, absl::string_view value) override {
376 335 : HeaderMapImpl::addReferenceKey(key, value);
377 335 : }
378 33 : void addCopy(const LowerCaseString& key, uint64_t value) override {
379 33 : HeaderMapImpl::addCopy(key, value);
380 33 : }
381 70115 : void addCopy(const LowerCaseString& key, absl::string_view value) override {
382 70115 : HeaderMapImpl::addCopy(key, value);
383 70115 : }
384 103 : void appendCopy(const LowerCaseString& key, absl::string_view value) override {
385 103 : HeaderMapImpl::appendCopy(key, value);
386 103 : }
387 401 : void setReference(const LowerCaseString& key, absl::string_view value) override {
388 401 : HeaderMapImpl::setReference(key, value);
389 401 : }
390 239 : void setReferenceKey(const LowerCaseString& key, absl::string_view value) override {
391 239 : HeaderMapImpl::setReferenceKey(key, value);
392 239 : }
393 5 : void setCopy(const LowerCaseString& key, absl::string_view value) override {
394 5 : HeaderMapImpl::setCopy(key, value);
395 5 : }
396 38057 : uint64_t byteSize() const override { return HeaderMapImpl::byteSize(); }
397 11 : uint32_t maxHeadersKb() const override { return HeaderMapImpl::maxHeadersKb(); }
398 22 : uint32_t maxHeadersCount() const override { return HeaderMapImpl::maxHeadersCount(); }
399 6772 : HeaderMap::GetResult get(const LowerCaseString& key) const override {
400 6772 : return HeaderMapImpl::get(key);
401 6772 : }
402 10098 : void iterate(HeaderMap::ConstIterateCb cb) const override { HeaderMapImpl::iterate(cb); }
403 6737 : void iterateReverse(HeaderMap::ConstIterateCb cb) const override {
404 6737 : HeaderMapImpl::iterateReverse(cb);
405 6737 : }
406 1199 : void clear() override { HeaderMapImpl::clear(); }
407 129 : size_t remove(const LowerCaseString& key) override { return HeaderMapImpl::remove(key); }
408 0 : size_t removeIf(const HeaderMap::HeaderMatchPredicate& predicate) override {
409 0 : return HeaderMapImpl::removeIf(predicate);
410 0 : }
411 67 : size_t removePrefix(const LowerCaseString& key) override {
412 67 : return HeaderMapImpl::removePrefix(key);
413 67 : }
414 34902 : size_t size() const override { return HeaderMapImpl::size(); }
415 58 : bool empty() const override { return HeaderMapImpl::empty(); }
416 0 : void dumpState(std::ostream& os, int indent_level = 0) const override {
417 0 : HeaderMapImpl::dumpState(os, indent_level);
418 0 : }
419 758 : StatefulHeaderKeyFormatterOptConstRef formatter() const override {
420 758 : return HeaderMapImpl::formatter();
421 758 : }
422 2787 : StatefulHeaderKeyFormatterOptRef formatter() override { return HeaderMapImpl::formatter(); }
423 :
424 : // Generic custom header functions for each fully typed interface. To avoid accidental issues,
425 : // the Handle type is different for each interface, which is why these functions live here vs.
426 : // inside HeaderMapImpl.
427 : using Handle = CustomInlineHeaderRegistry::Handle<Interface::header_map_type>;
428 52709 : const HeaderEntry* getInline(Handle handle) const override {
429 52709 : ASSERT(handle.it_->second < inlineHeadersSize());
430 52709 : return constInlineHeaders()[handle.it_->second];
431 52709 : }
432 189 : void appendInline(Handle handle, absl::string_view data, absl::string_view delimiter) override {
433 189 : ASSERT(handle.it_->second < inlineHeadersSize());
434 189 : HeaderEntry& entry = maybeCreateInline(&inlineHeaders()[handle.it_->second], handle.it_->first);
435 189 : addSize(HeaderMapImpl::appendToHeader(entry.value(), data, delimiter));
436 189 : }
437 2565 : void setReferenceInline(Handle handle, absl::string_view value) override {
438 2565 : ASSERT(handle.it_->second < inlineHeadersSize());
439 2565 : HeaderEntry& entry = maybeCreateInline(&inlineHeaders()[handle.it_->second], handle.it_->first);
440 2565 : updateSize(entry.value().size(), value.size());
441 2565 : entry.value().setReference(value);
442 2565 : }
443 5343 : void setInline(Handle handle, absl::string_view value) override {
444 5343 : ASSERT(handle.it_->second < inlineHeadersSize());
445 5343 : HeaderEntry& entry = maybeCreateInline(&inlineHeaders()[handle.it_->second], handle.it_->first);
446 5343 : updateSize(entry.value().size(), value.size());
447 5343 : entry.value().setCopy(value);
448 5343 : }
449 817 : void setInline(Handle handle, uint64_t value) override {
450 817 : ASSERT(handle.it_->second < inlineHeadersSize());
451 817 : HeaderEntry& entry = maybeCreateInline(&inlineHeaders()[handle.it_->second], handle.it_->first);
452 817 : subtractSize(entry.value().size());
453 817 : entry.value().setInteger(value);
454 817 : addSize(entry.value().size());
455 817 : }
456 14060 : size_t removeInline(Handle handle) override {
457 14060 : ASSERT(handle.it_->second < inlineHeadersSize());
458 14060 : return HeaderMapImpl::removeInline(&inlineHeaders()[handle.it_->second]);
459 14060 : }
460 22207 : static size_t inlineHeadersSize() {
461 22207 : return StaticLookupTable<Interface>::size() * sizeof(HeaderEntryImpl*);
462 22207 : }
463 :
464 : protected:
465 92639 : absl::optional<StaticLookupResponse> staticLookup(absl::string_view key) override {
466 92639 : return StaticLookupTable<Interface>::lookup(*this, key);
467 92639 : }
468 : virtual const HeaderEntryImpl* const* constInlineHeaders() const PURE;
469 : };
470 :
471 : #define DEFINE_HEADER_HANDLE(name) \
472 : Handle name = \
473 : CustomInlineHeaderRegistry::getInlineHeader<header_map_type>(Headers::get().name).value();
474 :
475 : /**
476 : * Concrete implementation of RequestHeaderMap which allows for variable custom registered inline
477 : * headers.
478 : */
479 : class RequestHeaderMapImpl final : public TypedHeaderMapImpl<RequestHeaderMap>,
480 : public InlineStorage {
481 : public:
482 : static std::unique_ptr<RequestHeaderMapImpl>
483 : create(const uint32_t max_headers_kb = UINT32_MAX,
484 6541 : const uint32_t max_headers_count = UINT32_MAX) {
485 6541 : return std::unique_ptr<RequestHeaderMapImpl>(
486 6541 : new (inlineHeadersSize()) RequestHeaderMapImpl(max_headers_kb, max_headers_count));
487 6541 : }
488 :
489 : INLINE_REQ_STRING_HEADERS(DEFINE_INLINE_HEADER_STRING_FUNCS)
490 : INLINE_REQ_NUMERIC_HEADERS(DEFINE_INLINE_HEADER_NUMERIC_FUNCS)
491 : INLINE_REQ_RESP_STRING_HEADERS(DEFINE_INLINE_HEADER_STRING_FUNCS)
492 : INLINE_REQ_RESP_NUMERIC_HEADERS(DEFINE_INLINE_HEADER_NUMERIC_FUNCS)
493 :
494 : protected:
495 : // NOTE: Because inline_headers_ is a variable size member, it must be the last member in the
496 : // most derived class. This forces the definition of the following three functions to also be
497 : // in the most derived class and thus duplicated. There may be a way to consolidate thus but it's
498 : // not clear and can be deferred for now.
499 7190 : void clearInline() override { memset(inline_headers_, 0, inlineHeadersSize()); }
500 42612 : const HeaderEntryImpl* const* constInlineHeaders() const override { return inline_headers_; }
501 29817 : HeaderEntryImpl** inlineHeaders() override { return inline_headers_; }
502 :
503 : private:
504 : struct HeaderHandleValues {
505 : INLINE_REQ_STRING_HEADERS(DEFINE_HEADER_HANDLE)
506 : INLINE_REQ_NUMERIC_HEADERS(DEFINE_HEADER_HANDLE)
507 : INLINE_REQ_RESP_STRING_HEADERS(DEFINE_HEADER_HANDLE)
508 : INLINE_REQ_RESP_NUMERIC_HEADERS(DEFINE_HEADER_HANDLE)
509 : };
510 :
511 : using HeaderHandles = ConstSingleton<HeaderHandleValues>;
512 :
513 : RequestHeaderMapImpl(const uint32_t max_headers_kb = UINT32_MAX,
514 : const uint32_t max_headers_count = UINT32_MAX)
515 6541 : : TypedHeaderMapImpl<RequestHeaderMap>(max_headers_kb, max_headers_count) {
516 6541 : clearInline();
517 6541 : }
518 :
519 : HeaderEntryImpl* inline_headers_[];
520 : };
521 :
522 : /**
523 : * Concrete implementation of RequestTrailerMap which allows for variable custom registered inline
524 : * headers.
525 : */
526 : class RequestTrailerMapImpl final : public TypedHeaderMapImpl<RequestTrailerMap>,
527 : public InlineStorage {
528 : public:
529 : static std::unique_ptr<RequestTrailerMapImpl>
530 : create(const uint32_t max_headers_kb = UINT32_MAX,
531 462 : const uint32_t max_headers_count = UINT32_MAX) {
532 462 : return std::unique_ptr<RequestTrailerMapImpl>(
533 462 : new (inlineHeadersSize()) RequestTrailerMapImpl(max_headers_kb, max_headers_count));
534 462 : }
535 :
536 : protected:
537 : // See comment in RequestHeaderMapImpl.
538 624 : void clearInline() override { memset(inline_headers_, 0, inlineHeadersSize()); }
539 0 : const HeaderEntryImpl* const* constInlineHeaders() const override { return inline_headers_; }
540 0 : HeaderEntryImpl** inlineHeaders() override { return inline_headers_; }
541 :
542 : private:
543 : RequestTrailerMapImpl(const uint32_t max_headers_kb = UINT32_MAX,
544 : const uint32_t max_headers_count = UINT32_MAX)
545 462 : : TypedHeaderMapImpl<RequestTrailerMap>(max_headers_kb, max_headers_count) {
546 462 : clearInline();
547 462 : }
548 :
549 : HeaderEntryImpl* inline_headers_[];
550 : };
551 :
552 : /**
553 : * Concrete implementation of ResponseHeaderMap which allows for variable custom registered inline
554 : * headers.
555 : */
556 : class ResponseHeaderMapImpl final : public TypedHeaderMapImpl<ResponseHeaderMap>,
557 : public InlineStorage {
558 : public:
559 : static std::unique_ptr<ResponseHeaderMapImpl>
560 : create(const uint32_t max_headers_kb = UINT32_MAX,
561 2381 : const uint32_t max_headers_count = UINT32_MAX) {
562 2381 : return std::unique_ptr<ResponseHeaderMapImpl>(
563 2381 : new (inlineHeadersSize()) ResponseHeaderMapImpl(max_headers_kb, max_headers_count));
564 2381 : }
565 :
566 : INLINE_RESP_STRING_HEADERS(DEFINE_INLINE_HEADER_STRING_FUNCS)
567 : INLINE_RESP_NUMERIC_HEADERS(DEFINE_INLINE_HEADER_NUMERIC_FUNCS)
568 : INLINE_REQ_RESP_STRING_HEADERS(DEFINE_INLINE_HEADER_STRING_FUNCS)
569 : INLINE_REQ_RESP_NUMERIC_HEADERS(DEFINE_INLINE_HEADER_NUMERIC_FUNCS)
570 : INLINE_RESP_STRING_HEADERS_TRAILERS(DEFINE_INLINE_HEADER_STRING_FUNCS)
571 : INLINE_RESP_NUMERIC_HEADERS_TRAILERS(DEFINE_INLINE_HEADER_NUMERIC_FUNCS)
572 :
573 : protected:
574 : // See comment in RequestHeaderMapImpl.
575 2529 : void clearInline() override { memset(inline_headers_, 0, inlineHeadersSize()); }
576 10034 : const HeaderEntryImpl* const* constInlineHeaders() const override { return inline_headers_; }
577 9467 : HeaderEntryImpl** inlineHeaders() override { return inline_headers_; }
578 :
579 : private:
580 : struct HeaderHandleValues {
581 : INLINE_RESP_STRING_HEADERS(DEFINE_HEADER_HANDLE)
582 : INLINE_RESP_NUMERIC_HEADERS(DEFINE_HEADER_HANDLE)
583 : INLINE_REQ_RESP_STRING_HEADERS(DEFINE_HEADER_HANDLE)
584 : INLINE_REQ_RESP_NUMERIC_HEADERS(DEFINE_HEADER_HANDLE)
585 : INLINE_RESP_STRING_HEADERS_TRAILERS(DEFINE_HEADER_HANDLE)
586 : INLINE_RESP_NUMERIC_HEADERS_TRAILERS(DEFINE_HEADER_HANDLE)
587 : };
588 :
589 : using HeaderHandles = ConstSingleton<HeaderHandleValues>;
590 :
591 : ResponseHeaderMapImpl(const uint32_t max_headers_kb = UINT32_MAX,
592 : const uint32_t max_headers_count = UINT32_MAX)
593 2381 : : TypedHeaderMapImpl<ResponseHeaderMap>(max_headers_kb, max_headers_count) {
594 2381 : clearInline();
595 2381 : }
596 : HeaderEntryImpl* inline_headers_[];
597 : };
598 :
599 : /**
600 : * Concrete implementation of ResponseTrailerMap which allows for variable custom registered
601 : * inline headers.
602 : */
603 : class ResponseTrailerMapImpl final : public TypedHeaderMapImpl<ResponseTrailerMap>,
604 : public InlineStorage {
605 : public:
606 : static std::unique_ptr<ResponseTrailerMapImpl>
607 : create(const uint32_t max_headers_kb = UINT32_MAX,
608 852 : const uint32_t max_headers_count = UINT32_MAX) {
609 852 : return std::unique_ptr<ResponseTrailerMapImpl>(
610 852 : new (inlineHeadersSize()) ResponseTrailerMapImpl(max_headers_kb, max_headers_count));
611 852 : }
612 :
613 : INLINE_RESP_STRING_HEADERS_TRAILERS(DEFINE_INLINE_HEADER_STRING_FUNCS)
614 : INLINE_RESP_NUMERIC_HEADERS_TRAILERS(DEFINE_INLINE_HEADER_NUMERIC_FUNCS)
615 :
616 : protected:
617 : // See comment in RequestHeaderMapImpl.
618 1092 : void clearInline() override { memset(inline_headers_, 0, inlineHeadersSize()); }
619 63 : const HeaderEntryImpl* const* constInlineHeaders() const override { return inline_headers_; }
620 41 : HeaderEntryImpl** inlineHeaders() override { return inline_headers_; }
621 :
622 : private:
623 : struct HeaderHandleValues {
624 : INLINE_RESP_STRING_HEADERS_TRAILERS(DEFINE_HEADER_HANDLE)
625 : INLINE_RESP_NUMERIC_HEADERS_TRAILERS(DEFINE_HEADER_HANDLE)
626 : };
627 :
628 : using HeaderHandles = ConstSingleton<HeaderHandleValues>;
629 :
630 : ResponseTrailerMapImpl(const uint32_t max_headers_kb = UINT32_MAX,
631 : const uint32_t max_headers_count = UINT32_MAX)
632 852 : : TypedHeaderMapImpl<ResponseTrailerMap>(max_headers_kb, max_headers_count) {
633 852 : clearInline();
634 852 : }
635 :
636 : HeaderEntryImpl* inline_headers_[];
637 : };
638 :
639 : template <class T>
640 : std::unique_ptr<T>
641 487 : createHeaderMap(const std::initializer_list<std::pair<LowerCaseString, std::string>>& values) {
642 487 : auto new_header_map = T::create();
643 487 : HeaderMapImpl::initFromInitList(*new_header_map, values.begin(), values.end());
644 487 : return new_header_map;
645 487 : }
646 :
647 : template <class T, class It> std::unique_ptr<T> createHeaderMap(It begin, It end) {
648 : auto new_header_map = T::create();
649 : HeaderMapImpl::initFromInitList(*new_header_map, begin, end);
650 : return new_header_map;
651 : }
652 :
653 276 : template <class T> std::unique_ptr<T> createHeaderMap(const HeaderMap& rhs) {
654 : // TODO(mattklein123): Use of this function allows copying a request header map into a response
655 : // header map, etc. which is probably not what we want. Unfortunately, we do this on purpose in
656 : // a few places when dealing with gRPC headers/trailers conversions so it's not trivial to remove.
657 : // We should revisit this to figure how to make this a bit safer as a non-intentional conversion
658 : // may have surprising results with different O(1) headers, implementations, etc.
659 276 : auto new_header_map = T::create();
660 276 : HeaderMapImpl::copyFrom(*new_header_map, rhs);
661 276 : return new_header_map;
662 276 : }
663 :
664 : struct EmptyHeaders {
665 : RequestHeaderMapPtr request_headers = RequestHeaderMapImpl::create();
666 : ResponseHeaderMapPtr response_headers = ResponseHeaderMapImpl::create();
667 : ResponseTrailerMapPtr response_trailers = ResponseTrailerMapImpl::create();
668 : };
669 :
670 : using StaticEmptyHeaders = ConstSingleton<EmptyHeaders>;
671 :
672 : class HeaderMapImplUtility {
673 : public:
674 : struct HeaderMapImplInfo {
675 : // Human readable name for the header map used in info logging.
676 : std::string name_;
677 : // The byte size of the header map including both fixed space as well as variable space used
678 : // by the registered custom headers.
679 : size_t size_;
680 : // All registered custom headers for the header map.
681 : std::vector<std::string> registered_headers_;
682 : };
683 :
684 : /**
685 : * Fetch detailed information about each header map implementation for use in logging.
686 : */
687 : static std::vector<HeaderMapImplInfo> getAllHeaderMapImplInfo();
688 : };
689 :
690 : } // namespace Http
691 : } // namespace Envoy
|