| // Copyright 2014 The Chromium Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #ifndef QUICHE_SPDY_CORE_HPACK_HPACK_HEADER_TABLE_H_ | |
| #define QUICHE_SPDY_CORE_HPACK_HPACK_HEADER_TABLE_H_ | |
| #include <cstddef> | |
| #include <cstdint> | |
| #include <deque> | |
| #include <memory> | |
| #include "absl/base/attributes.h" | |
| #include "absl/container/flat_hash_map.h" | |
| #include "absl/container/flat_hash_set.h" | |
| #include "absl/hash/hash.h" | |
| #include "absl/strings/string_view.h" | |
| #include "common/platform/api/quiche_export.h" | |
| #include "spdy/core/hpack/hpack_entry.h" | |
| // All section references below are to http://tools.ietf.org/html/rfc7541. | |
| namespace spdy { | |
| namespace test { | |
| class HpackHeaderTablePeer; | |
| } // namespace test | |
| // Return value of GetByName() and GetByNameAndValue() if matching entry is not | |
| // found. This value is never used in HPACK for indexing entries, see | |
| // https://httpwg.org/specs/rfc7541.html#index.address.space. | |
| constexpr size_t kHpackEntryNotFound = 0; | |
| // A data structure for the static table (2.3.1) and the dynamic table (2.3.2). | |
| class QUICHE_EXPORT_PRIVATE HpackHeaderTable { | |
| public: | |
| friend class test::HpackHeaderTablePeer; | |
| // Use a lightweight, memory efficient container for the static table, which | |
| // is initialized once and never changed after. | |
| using StaticEntryTable = std::vector<HpackEntry>; | |
| // HpackHeaderTable takes advantage of the deque property that references | |
| // remain valid, so long as insertions & deletions are at the head & tail. | |
| // This precludes the use of base::circular_deque. | |
| // TODO(b/182349990): Change to a more memory efficient container. | |
| using DynamicEntryTable = std::deque<HpackEntry>; | |
| using NameValueToEntryMap = absl::flat_hash_map<HpackLookupEntry, size_t>; | |
| using NameToEntryMap = absl::flat_hash_map<absl::string_view, size_t>; | |
| HpackHeaderTable(); | |
| HpackHeaderTable(const HpackHeaderTable&) = delete; | |
| HpackHeaderTable& operator=(const HpackHeaderTable&) = delete; | |
| ~HpackHeaderTable(); | |
| // Last-acknowledged value of SETTINGS_HEADER_TABLE_SIZE. | |
| size_t settings_size_bound() const { return settings_size_bound_; } | |
| // Current and maximum estimated byte size of the table, as described in | |
| // 4.1. Notably, this is /not/ the number of entries in the table. | |
| size_t size() const { return size_; } | |
| size_t max_size() const { return max_size_; } | |
| // The HPACK indexing scheme used by GetByName() and GetByNameAndValue() is | |
| // defined at https://httpwg.org/specs/rfc7541.html#index.address.space. | |
| // Returns the index of the lowest-index entry matching |name|, | |
| // or kHpackEntryNotFound if no matching entry is found. | |
| size_t GetByName(absl::string_view name); | |
| // Returns the index of the lowest-index entry matching |name| and |value|, | |
| // or kHpackEntryNotFound if no matching entry is found. | |
| size_t GetByNameAndValue(absl::string_view name, absl::string_view value); | |
| // Sets the maximum size of the header table, evicting entries if | |
| // necessary as described in 5.2. | |
| void SetMaxSize(size_t max_size); | |
| // Sets the SETTINGS_HEADER_TABLE_SIZE bound of the table. Will call | |
| // SetMaxSize() as needed to preserve max_size() <= settings_size_bound(). | |
| void SetSettingsHeaderTableSize(size_t settings_size); | |
| // Determine the set of entries which would be evicted by the insertion | |
| // of |name| & |value| into the table, as per section 4.4. No eviction | |
| // actually occurs. The set is returned via range [begin_out, end_out). | |
| void EvictionSet(absl::string_view name, | |
| absl::string_view value, | |
| DynamicEntryTable::iterator* begin_out, | |
| DynamicEntryTable::iterator* end_out); | |
| // Adds an entry for the representation, evicting entries as needed. |name| | |
| // and |value| must not point to an entry in |dynamic_entries_| which is about | |
| // to be evicted, but they may point to an entry which is not. | |
| // The added HpackEntry is returned, or NULL is returned if all entries were | |
| // evicted and the empty table is of insufficent size for the representation. | |
| const HpackEntry* TryAddEntry(absl::string_view name, | |
| absl::string_view value); | |
| private: | |
| // Returns number of evictions required to enter |name| & |value|. | |
| size_t EvictionCountForEntry(absl::string_view name, | |
| absl::string_view value) const; | |
| // Returns number of evictions required to reclaim |reclaim_size| table size. | |
| size_t EvictionCountToReclaim(size_t reclaim_size) const; | |
| // Evicts |count| oldest entries from the table. | |
| void Evict(size_t count); | |
| // |static_entries_|, |static_index_|, and |static_name_index_| are owned by | |
| // HpackStaticTable singleton. | |
| // Stores HpackEntries. | |
| const StaticEntryTable& static_entries_; | |
| DynamicEntryTable dynamic_entries_; | |
| // Tracks the index of the unique HpackEntry for a given header name and | |
| // value. Keys consist of string_views that point to strings stored in | |
| // |static_entries_|. | |
| const NameValueToEntryMap& static_index_; | |
| // Tracks the index of the first static entry for each name in the static | |
| // table. Each key is a string_view that points to a name string stored in | |
| // |static_entries_|. | |
| const NameToEntryMap& static_name_index_; | |
| // Tracks the index of the most recently inserted HpackEntry for a given | |
| // header name and value. Keys consist of string_views that point to strings | |
| // stored in |dynamic_entries_|. | |
| NameValueToEntryMap dynamic_index_; | |
| // Tracks the index of the most recently inserted HpackEntry for a given | |
| // header name. Each key is a string_view that points to a name string stored | |
| // in |dynamic_entries_|. | |
| NameToEntryMap dynamic_name_index_; | |
| // Last acknowledged value for SETTINGS_HEADER_TABLE_SIZE. | |
| size_t settings_size_bound_; | |
| // Estimated current and maximum byte size of the table. | |
| // |max_size_| <= |settings_size_bound_| | |
| size_t size_; | |
| size_t max_size_; | |
| // Total number of dynamic table insertions so far | |
| // (including entries that have been evicted). | |
| size_t dynamic_table_insertions_; | |
| }; | |
| } // namespace spdy | |
| #endif // QUICHE_SPDY_CORE_HPACK_HPACK_HEADER_TABLE_H_ |