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