LCOV - code coverage report
Current view: top level - source/common/http - header_map_impl.h (source / functions) Hit Total Coverage
Test: coverage.dat Lines: 274 284 96.5 %
Date: 2024-01-05 06:35:25 Functions: 277 650 42.6 %

          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

Generated by: LCOV version 1.15