xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/http2/hpack/decoder/hpack_decoder_tables.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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