1 // Copyright 2016 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_HTTP2_HPACK_DECODER_HPACK_DECODER_TABLES_H_ 6 #define QUICHE_HTTP2_HPACK_DECODER_HPACK_DECODER_TABLES_H_ 7 8 // Static and dynamic tables for the HPACK decoder. See: 9 // http://httpwg.org/specs/rfc7541.html#indexing.tables 10 11 // Note that the Lookup methods return nullptr if the requested index was not 12 // found. This should be treated as a COMPRESSION error according to the HTTP/2 13 // spec, which is a connection level protocol error (i.e. the connection must 14 // be terminated). See these sections in the two RFCs: 15 // http://httpwg.org/specs/rfc7541.html#indexed.header.representation 16 // http://httpwg.org/specs/rfc7541.html#index.address.space 17 // http://httpwg.org/specs/rfc7540.html#HeaderBlock 18 19 #include <stddef.h> 20 21 #include <cstdint> 22 #include <iosfwd> 23 #include <string> 24 #include <utility> 25 #include <vector> 26 27 #include "quiche/http2/http2_constants.h" 28 #include "quiche/common/platform/api/quiche_export.h" 29 #include "quiche/common/quiche_circular_deque.h" 30 31 namespace http2 { 32 namespace test { 33 class HpackDecoderTablesPeer; 34 } // namespace test 35 36 struct QUICHE_EXPORT HpackStringPair { 37 HpackStringPair(std::string name, std::string value); 38 ~HpackStringPair(); 39 40 // Returns the size of a header entry with this name and value, per the RFC: 41 // http://httpwg.org/specs/rfc7541.html#calculating.table.size sizeHpackStringPair42 size_t size() const { return 32 + name.size() + value.size(); } 43 44 std::string DebugString() const; 45 46 const std::string name; 47 const std::string value; 48 }; 49 50 QUICHE_EXPORT std::ostream& operator<<(std::ostream& os, 51 const HpackStringPair& p); 52 53 // See http://httpwg.org/specs/rfc7541.html#static.table.definition for the 54 // contents, and http://httpwg.org/specs/rfc7541.html#index.address.space for 55 // info about accessing the static table. 56 class QUICHE_EXPORT HpackDecoderStaticTable { 57 public: 58 explicit HpackDecoderStaticTable(const std::vector<HpackStringPair>* table); 59 // Uses a global table shared by all threads. 60 HpackDecoderStaticTable(); 61 62 // If index is valid, returns a pointer to the entry, otherwise returns 63 // nullptr. 64 const HpackStringPair* Lookup(size_t index) const; 65 66 private: 67 friend class test::HpackDecoderTablesPeer; 68 const std::vector<HpackStringPair>* const table_; 69 }; 70 71 // HpackDecoderDynamicTable implements HPACK compression feature "indexed 72 // headers"; previously sent headers may be referenced later by their index 73 // in the dynamic table. See these sections of the RFC: 74 // http://httpwg.org/specs/rfc7541.html#dynamic.table 75 // http://httpwg.org/specs/rfc7541.html#dynamic.table.management 76 class QUICHE_EXPORT HpackDecoderDynamicTable { 77 public: 78 HpackDecoderDynamicTable(); 79 ~HpackDecoderDynamicTable(); 80 81 HpackDecoderDynamicTable(const HpackDecoderDynamicTable&) = delete; 82 HpackDecoderDynamicTable& operator=(const HpackDecoderDynamicTable&) = delete; 83 84 // Sets a new size limit, received from the peer; performs evictions if 85 // necessary to ensure that the current size does not exceed the new limit. 86 // The caller needs to have validated that size_limit does not 87 // exceed the acknowledged value of SETTINGS_HEADER_TABLE_SIZE. 88 void DynamicTableSizeUpdate(size_t size_limit); 89 90 // Insert entry if possible. 91 // If entry is too large to insert, then dynamic table will be empty. 92 void Insert(std::string name, std::string value); 93 94 // If index is valid, returns a pointer to the entry, otherwise returns 95 // nullptr. 96 const HpackStringPair* Lookup(size_t index) const; 97 size_limit()98 size_t size_limit() const { return size_limit_; } current_size()99 size_t current_size() const { return current_size_; } 100 101 private: 102 friend class test::HpackDecoderTablesPeer; 103 104 // Drop older entries to ensure the size is not greater than limit. 105 void EnsureSizeNoMoreThan(size_t limit); 106 107 // Removes the oldest dynamic table entry. 108 void RemoveLastEntry(); 109 110 quiche::QuicheCircularDeque<HpackStringPair> table_; 111 112 // The last received DynamicTableSizeUpdate value, initialized to 113 // SETTINGS_HEADER_TABLE_SIZE. 114 size_t size_limit_ = Http2SettingsInfo::DefaultHeaderTableSize(); 115 116 size_t current_size_ = 0; 117 118 // insert_count_ and debug_listener_ are used by a QUIC experiment; remove 119 // when the experiment is done. 120 size_t insert_count_; 121 }; 122 123 class QUICHE_EXPORT HpackDecoderTables { 124 public: 125 HpackDecoderTables(); 126 ~HpackDecoderTables(); 127 128 HpackDecoderTables(const HpackDecoderTables&) = delete; 129 HpackDecoderTables& operator=(const HpackDecoderTables&) = delete; 130 131 // Sets a new size limit, received from the peer; performs evictions if 132 // necessary to ensure that the current size does not exceed the new limit. 133 // The caller needs to have validated that size_limit does not 134 // exceed the acknowledged value of SETTINGS_HEADER_TABLE_SIZE. DynamicTableSizeUpdate(size_t size_limit)135 void DynamicTableSizeUpdate(size_t size_limit) { 136 dynamic_table_.DynamicTableSizeUpdate(size_limit); 137 } 138 139 // Insert entry if possible. 140 // If entry is too large to insert, then dynamic table will be empty. Insert(std::string name,std::string value)141 void Insert(std::string name, std::string value) { 142 dynamic_table_.Insert(std::move(name), std::move(value)); 143 } 144 145 // If index is valid, returns a pointer to the entry, otherwise returns 146 // nullptr. 147 const HpackStringPair* Lookup(size_t index) const; 148 149 // The size limit that the peer (the HPACK encoder) has told the decoder it is 150 // currently operating with. Defaults to SETTINGS_HEADER_TABLE_SIZE, 4096. header_table_size_limit()151 size_t header_table_size_limit() const { return dynamic_table_.size_limit(); } 152 153 // Sum of the sizes of the dynamic table entries. current_header_table_size()154 size_t current_header_table_size() const { 155 return dynamic_table_.current_size(); 156 } 157 158 private: 159 friend class test::HpackDecoderTablesPeer; 160 HpackDecoderStaticTable static_table_; 161 HpackDecoderDynamicTable dynamic_table_; 162 }; 163 164 } // namespace http2 165 166 #endif // QUICHE_HTTP2_HPACK_DECODER_HPACK_DECODER_TABLES_H_ 167