|  | // 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 <iosfwd> | 
|  | #include <string> | 
|  | #include <utility> | 
|  | #include <vector> | 
|  |  | 
|  | #include "http2/http2_constants.h" | 
|  | #include "common/platform/api/quiche_export.h" | 
|  | #include "common/quiche_circular_deque.h" | 
|  |  | 
|  | namespace http2 { | 
|  | namespace test { | 
|  | class HpackDecoderTablesPeer; | 
|  | }  // namespace test | 
|  |  | 
|  | struct QUICHE_EXPORT_PRIVATE HpackStringPair { | 
|  | HpackStringPair(std::string name, std::string value); | 
|  | ~HpackStringPair(); | 
|  |  | 
|  | // Returns the size of a header entry with this name and value, per the RFC: | 
|  | // http://httpwg.org/specs/rfc7541.html#calculating.table.size | 
|  | size_t size() const { return 32 + name.size() + value.size(); } | 
|  |  | 
|  | std::string DebugString() const; | 
|  |  | 
|  | const std::string name; | 
|  | const std::string value; | 
|  | }; | 
|  |  | 
|  | QUICHE_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os, | 
|  | const HpackStringPair& p); | 
|  |  | 
|  | // 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 QUICHE_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 QUICHE_EXPORT_PRIVATE HpackDecoderDynamicTable { | 
|  | public: | 
|  | HpackDecoderDynamicTable(); | 
|  | ~HpackDecoderDynamicTable(); | 
|  |  | 
|  | HpackDecoderDynamicTable(const HpackDecoderDynamicTable&) = delete; | 
|  | HpackDecoderDynamicTable& operator=(const HpackDecoderDynamicTable&) = delete; | 
|  |  | 
|  | // 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); | 
|  |  | 
|  | // Insert entry if possible. | 
|  | // If entry is too large to insert, then dynamic table will be empty. | 
|  | void Insert(std::string name, std::string 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; | 
|  |  | 
|  | // 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(); | 
|  |  | 
|  | quiche::QuicheCircularDeque<HpackStringPair> 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_; | 
|  | }; | 
|  |  | 
|  | class QUICHE_EXPORT_PRIVATE HpackDecoderTables { | 
|  | public: | 
|  | HpackDecoderTables(); | 
|  | ~HpackDecoderTables(); | 
|  |  | 
|  | HpackDecoderTables(const HpackDecoderTables&) = delete; | 
|  | HpackDecoderTables& operator=(const HpackDecoderTables&) = delete; | 
|  |  | 
|  | // 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); | 
|  | } | 
|  |  | 
|  | // Insert entry if possible. | 
|  | // If entry is too large to insert, then dynamic table will be empty. | 
|  | void Insert(std::string name, std::string value) { | 
|  | dynamic_table_.Insert(std::move(name), std::move(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_ |