| // Copyright 2016 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_HTTP2_HPACK_DECODER_HPACK_DECODER_TABLES_H_ | |
| #define QUICHE_HTTP2_HPACK_DECODER_HPACK_DECODER_TABLES_H_ | |
| // Static and dynamic tables for the HPACK decoder. See: | |
| // http://httpwg.org/specs/rfc7541.html#indexing.tables | |
| // Note that the Lookup methods return nullptr if the requested index was not | |
| // found. This should be treated as a COMPRESSION error according to the HTTP/2 | |
| // spec, which is a connection level protocol error (i.e. the connection must | |
| // be terminated). See these sections in the two RFCs: | |
| // http://httpwg.org/specs/rfc7541.html#indexed.header.representation | |
| // http://httpwg.org/specs/rfc7541.html#index.address.space | |
| // http://httpwg.org/specs/rfc7540.html#HeaderBlock | |
| #include <stddef.h> | |
| #include <cstdint> | |
| #include <vector> | |
| #include "net/third_party/quiche/src/http2/hpack/hpack_string.h" | |
| #include "net/third_party/quiche/src/http2/http2_constants.h" | |
| #include "net/third_party/quiche/src/http2/platform/api/http2_containers.h" | |
| #include "net/third_party/quiche/src/http2/platform/api/http2_export.h" | |
| namespace http2 { | |
| namespace test { | |
| class HpackDecoderTablesPeer; | |
| } // namespace test | |
| // HpackDecoderTablesDebugListener supports a QUIC experiment, enabling | |
| // the gathering of information about the time-line of use of HPACK | |
| // dynamic table entries. | |
| class HTTP2_EXPORT_PRIVATE HpackDecoderTablesDebugListener { | |
| public: | |
| HpackDecoderTablesDebugListener(); | |
| virtual ~HpackDecoderTablesDebugListener(); | |
| HpackDecoderTablesDebugListener(const HpackDecoderTablesDebugListener&) = | |
| delete; | |
| HpackDecoderTablesDebugListener& operator=( | |
| const HpackDecoderTablesDebugListener&) = delete; | |
| // The entry has been inserted into the dynamic table. insert_count starts at | |
| // 62 because 61 is the last index in the static table; insert_count increases | |
| // by 1 with each insert into the dynamic table; it is not incremented when | |
| // when a entry is too large to fit into the dynamic table at all (which has | |
| // the effect of emptying the dynamic table). | |
| // Returns a value that can be used as time_added in OnUseEntry. | |
| virtual int64_t OnEntryInserted(const HpackStringPair& entry, | |
| size_t insert_count) = 0; | |
| // The entry has been used, either for the name or for the name and value. | |
| // insert_count is the same as passed to OnEntryInserted when entry was | |
| // inserted to the dynamic table, and time_added is the value that was | |
| // returned by OnEntryInserted. | |
| virtual void OnUseEntry(const HpackStringPair& entry, | |
| size_t insert_count, | |
| int64_t time_added) = 0; | |
| }; | |
| // See http://httpwg.org/specs/rfc7541.html#static.table.definition for the | |
| // contents, and http://httpwg.org/specs/rfc7541.html#index.address.space for | |
| // info about accessing the static table. | |
| class HTTP2_EXPORT_PRIVATE HpackDecoderStaticTable { | |
| public: | |
| explicit HpackDecoderStaticTable(const std::vector<HpackStringPair>* table); | |
| // Uses a global table shared by all threads. | |
| HpackDecoderStaticTable(); | |
| // If index is valid, returns a pointer to the entry, otherwise returns | |
| // nullptr. | |
| const HpackStringPair* Lookup(size_t index) const; | |
| private: | |
| friend class test::HpackDecoderTablesPeer; | |
| const std::vector<HpackStringPair>* const table_; | |
| }; | |
| // HpackDecoderDynamicTable implements HPACK compression feature "indexed | |
| // headers"; previously sent headers may be referenced later by their index | |
| // in the dynamic table. See these sections of the RFC: | |
| // http://httpwg.org/specs/rfc7541.html#dynamic.table | |
| // http://httpwg.org/specs/rfc7541.html#dynamic.table.management | |
| class HTTP2_EXPORT_PRIVATE HpackDecoderDynamicTable { | |
| public: | |
| HpackDecoderDynamicTable(); | |
| ~HpackDecoderDynamicTable(); | |
| HpackDecoderDynamicTable(const HpackDecoderDynamicTable&) = delete; | |
| HpackDecoderDynamicTable& operator=(const HpackDecoderDynamicTable&) = delete; | |
| // Set the listener to be notified of insertions into this table, and later | |
| // uses of those entries. Added for evaluation of changes to QUIC's use | |
| // of HPACK. | |
| void set_debug_listener(HpackDecoderTablesDebugListener* debug_listener) { | |
| debug_listener_ = debug_listener; | |
| } | |
| // Sets a new size limit, received from the peer; performs evictions if | |
| // necessary to ensure that the current size does not exceed the new limit. | |
| // The caller needs to have validated that size_limit does not | |
| // exceed the acknowledged value of SETTINGS_HEADER_TABLE_SIZE. | |
| void DynamicTableSizeUpdate(size_t size_limit); | |
| // Returns true if inserted, false if too large (at which point the | |
| // dynamic table will be empty.) | |
| bool Insert(const HpackString& name, const HpackString& value); | |
| // If index is valid, returns a pointer to the entry, otherwise returns | |
| // nullptr. | |
| const HpackStringPair* Lookup(size_t index) const; | |
| size_t size_limit() const { return size_limit_; } | |
| size_t current_size() const { return current_size_; } | |
| private: | |
| friend class test::HpackDecoderTablesPeer; | |
| struct HpackDecoderTableEntry : public HpackStringPair { | |
| HpackDecoderTableEntry(const HpackString& name, const HpackString& value); | |
| int64_t time_added; | |
| }; | |
| // Drop older entries to ensure the size is not greater than limit. | |
| void EnsureSizeNoMoreThan(size_t limit); | |
| // Removes the oldest dynamic table entry. | |
| void RemoveLastEntry(); | |
| Http2Deque<HpackDecoderTableEntry> table_; | |
| // The last received DynamicTableSizeUpdate value, initialized to | |
| // SETTINGS_HEADER_TABLE_SIZE. | |
| size_t size_limit_ = Http2SettingsInfo::DefaultHeaderTableSize(); | |
| size_t current_size_ = 0; | |
| // insert_count_ and debug_listener_ are used by a QUIC experiment; remove | |
| // when the experiment is done. | |
| size_t insert_count_; | |
| HpackDecoderTablesDebugListener* debug_listener_; | |
| }; | |
| class HTTP2_EXPORT_PRIVATE HpackDecoderTables { | |
| public: | |
| HpackDecoderTables(); | |
| ~HpackDecoderTables(); | |
| HpackDecoderTables(const HpackDecoderTables&) = delete; | |
| HpackDecoderTables& operator=(const HpackDecoderTables&) = delete; | |
| // Set the listener to be notified of insertions into the dynamic table, and | |
| // later uses of those entries. Added for evaluation of changes to QUIC's use | |
| // of HPACK. | |
| void set_debug_listener(HpackDecoderTablesDebugListener* debug_listener); | |
| // Sets a new size limit, received from the peer; performs evictions if | |
| // necessary to ensure that the current size does not exceed the new limit. | |
| // The caller needs to have validated that size_limit does not | |
| // exceed the acknowledged value of SETTINGS_HEADER_TABLE_SIZE. | |
| void DynamicTableSizeUpdate(size_t size_limit) { | |
| dynamic_table_.DynamicTableSizeUpdate(size_limit); | |
| } | |
| // Returns true if inserted, false if too large (at which point the | |
| // dynamic table will be empty.) | |
| // TODO(jamessynge): Add methods for moving the string(s) into the table, | |
| // or for otherwise avoiding unnecessary copies. | |
| bool Insert(const HpackString& name, const HpackString& value) { | |
| return dynamic_table_.Insert(name, value); | |
| } | |
| // If index is valid, returns a pointer to the entry, otherwise returns | |
| // nullptr. | |
| const HpackStringPair* Lookup(size_t index) const; | |
| // The size limit that the peer (the HPACK encoder) has told the decoder it is | |
| // currently operating with. Defaults to SETTINGS_HEADER_TABLE_SIZE, 4096. | |
| size_t header_table_size_limit() const { return dynamic_table_.size_limit(); } | |
| // Sum of the sizes of the dynamic table entries. | |
| size_t current_header_table_size() const { | |
| return dynamic_table_.current_size(); | |
| } | |
| private: | |
| friend class test::HpackDecoderTablesPeer; | |
| HpackDecoderStaticTable static_table_; | |
| HpackDecoderDynamicTable dynamic_table_; | |
| }; | |
| } // namespace http2 | |
| #endif // QUICHE_HTTP2_HPACK_DECODER_HPACK_DECODER_TABLES_H_ |