1 // Copyright 2014 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef QUICHE_SPDY_CORE_HPACK_HPACK_HEADER_TABLE_H_ 6 #define QUICHE_SPDY_CORE_HPACK_HPACK_HEADER_TABLE_H_ 7 8 #include <cstddef> 9 #include <cstdint> 10 #include <deque> 11 #include <memory> 12 13 #include "absl/base/attributes.h" 14 #include "absl/container/flat_hash_map.h" 15 #include "absl/container/flat_hash_set.h" 16 #include "absl/hash/hash.h" 17 #include "absl/strings/string_view.h" 18 #include "quiche/common/platform/api/quiche_export.h" 19 #include "quiche/common/quiche_circular_deque.h" 20 #include "quiche/spdy/core/hpack/hpack_entry.h" 21 22 // All section references below are to http://tools.ietf.org/html/rfc7541. 23 24 namespace spdy { 25 26 namespace test { 27 class HpackHeaderTablePeer; 28 } // namespace test 29 30 // Return value of GetByName() and GetByNameAndValue() if matching entry is not 31 // found. This value is never used in HPACK for indexing entries, see 32 // https://httpwg.org/specs/rfc7541.html#index.address.space. 33 constexpr size_t kHpackEntryNotFound = 0; 34 35 // A data structure for the static table (2.3.1) and the dynamic table (2.3.2). 36 class QUICHE_EXPORT HpackHeaderTable { 37 public: 38 friend class test::HpackHeaderTablePeer; 39 40 // Use a lightweight, memory efficient container for the static table, which 41 // is initialized once and never changed after. 42 using StaticEntryTable = std::vector<HpackEntry>; 43 44 // HpackHeaderTable takes advantage of the deque property that references 45 // remain valid, so long as insertions & deletions are at the head & tail. 46 using DynamicEntryTable = 47 quiche::QuicheCircularDeque<std::unique_ptr<HpackEntry>>; 48 49 using NameValueToEntryMap = absl::flat_hash_map<HpackLookupEntry, size_t>; 50 using NameToEntryMap = absl::flat_hash_map<absl::string_view, size_t>; 51 52 HpackHeaderTable(); 53 HpackHeaderTable(const HpackHeaderTable&) = delete; 54 HpackHeaderTable& operator=(const HpackHeaderTable&) = delete; 55 56 ~HpackHeaderTable(); 57 58 // Last-acknowledged value of SETTINGS_HEADER_TABLE_SIZE. settings_size_bound()59 size_t settings_size_bound() const { return settings_size_bound_; } 60 61 // Current and maximum estimated byte size of the table, as described in 62 // 4.1. Notably, this is /not/ the number of entries in the table. size()63 size_t size() const { return size_; } max_size()64 size_t max_size() const { return max_size_; } 65 66 // The HPACK indexing scheme used by GetByName() and GetByNameAndValue() is 67 // defined at https://httpwg.org/specs/rfc7541.html#index.address.space. 68 69 // Returns the index of the lowest-index entry matching |name|, 70 // or kHpackEntryNotFound if no matching entry is found. 71 size_t GetByName(absl::string_view name); 72 73 // Returns the index of the lowest-index entry matching |name| and |value|, 74 // or kHpackEntryNotFound if no matching entry is found. 75 size_t GetByNameAndValue(absl::string_view name, absl::string_view value); 76 77 // Sets the maximum size of the header table, evicting entries if 78 // necessary as described in 5.2. 79 void SetMaxSize(size_t max_size); 80 81 // Sets the SETTINGS_HEADER_TABLE_SIZE bound of the table. Will call 82 // SetMaxSize() as needed to preserve max_size() <= settings_size_bound(). 83 void SetSettingsHeaderTableSize(size_t settings_size); 84 85 // Determine the set of entries which would be evicted by the insertion 86 // of |name| & |value| into the table, as per section 4.4. No eviction 87 // actually occurs. The set is returned via range [begin_out, end_out). 88 void EvictionSet(absl::string_view name, absl::string_view value, 89 DynamicEntryTable::iterator* begin_out, 90 DynamicEntryTable::iterator* end_out); 91 92 // Adds an entry for the representation, evicting entries as needed. |name| 93 // and |value| must not point to an entry in |dynamic_entries_| which is about 94 // to be evicted, but they may point to an entry which is not. 95 // The added HpackEntry is returned, or NULL is returned if all entries were 96 // evicted and the empty table is of insufficent size for the representation. 97 const HpackEntry* TryAddEntry(absl::string_view name, 98 absl::string_view value); 99 100 private: 101 // Returns number of evictions required to enter |name| & |value|. 102 size_t EvictionCountForEntry(absl::string_view name, 103 absl::string_view value) const; 104 105 // Returns number of evictions required to reclaim |reclaim_size| table size. 106 size_t EvictionCountToReclaim(size_t reclaim_size) const; 107 108 // Evicts |count| oldest entries from the table. 109 void Evict(size_t count); 110 111 // |static_entries_|, |static_index_|, and |static_name_index_| are owned by 112 // HpackStaticTable singleton. 113 114 // Stores HpackEntries. 115 const StaticEntryTable& static_entries_; 116 DynamicEntryTable dynamic_entries_; 117 118 // Tracks the index of the unique HpackEntry for a given header name and 119 // value. Keys consist of string_views that point to strings stored in 120 // |static_entries_|. 121 const NameValueToEntryMap& static_index_; 122 123 // Tracks the index of the first static entry for each name in the static 124 // table. Each key is a string_view that points to a name string stored in 125 // |static_entries_|. 126 const NameToEntryMap& static_name_index_; 127 128 // Tracks the index of the most recently inserted HpackEntry for a given 129 // header name and value. Keys consist of string_views that point to strings 130 // stored in |dynamic_entries_|. 131 NameValueToEntryMap dynamic_index_; 132 133 // Tracks the index of the most recently inserted HpackEntry for a given 134 // header name. Each key is a string_view that points to a name string stored 135 // in |dynamic_entries_|. 136 NameToEntryMap dynamic_name_index_; 137 138 // Last acknowledged value for SETTINGS_HEADER_TABLE_SIZE. 139 size_t settings_size_bound_; 140 141 // Estimated current and maximum byte size of the table. 142 // |max_size_| <= |settings_size_bound_| 143 size_t size_; 144 size_t max_size_; 145 146 // Total number of dynamic table insertions so far 147 // (including entries that have been evicted). 148 size_t dynamic_table_insertions_; 149 }; 150 151 } // namespace spdy 152 153 #endif // QUICHE_SPDY_CORE_HPACK_HPACK_HEADER_TABLE_H_ 154