xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/http2/hpack/decoder/hpack_decoder_test.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2017 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 #include "quiche/http2/hpack/decoder/hpack_decoder.h"
6 
7 // Tests of HpackDecoder.
8 
9 #include <string>
10 #include <tuple>
11 #include <utility>
12 #include <vector>
13 
14 #include "quiche/http2/decoder/decode_buffer.h"
15 #include "quiche/http2/hpack/decoder/hpack_decoder_listener.h"
16 #include "quiche/http2/hpack/decoder/hpack_decoder_state.h"
17 #include "quiche/http2/hpack/decoder/hpack_decoder_tables.h"
18 #include "quiche/http2/hpack/http2_hpack_constants.h"
19 #include "quiche/http2/http2_constants.h"
20 #include "quiche/http2/test_tools/hpack_block_builder.h"
21 #include "quiche/http2/test_tools/hpack_example.h"
22 #include "quiche/http2/test_tools/http2_random.h"
23 #include "quiche/http2/test_tools/random_util.h"
24 #include "quiche/http2/test_tools/verify_macros.h"
25 #include "quiche/common/platform/api/quiche_logging.h"
26 #include "quiche/common/platform/api/quiche_test.h"
27 
28 using ::testing::AssertionResult;
29 using ::testing::AssertionSuccess;
30 using ::testing::ElementsAreArray;
31 using ::testing::Eq;
32 
33 namespace http2 {
34 namespace test {
35 class HpackDecoderStatePeer {
36  public:
GetDecoderTables(HpackDecoderState * state)37   static HpackDecoderTables* GetDecoderTables(HpackDecoderState* state) {
38     return &state->decoder_tables_;
39   }
set_listener(HpackDecoderState * state,HpackDecoderListener * listener)40   static void set_listener(HpackDecoderState* state,
41                            HpackDecoderListener* listener) {
42     state->listener_ = listener;
43   }
44 };
45 class HpackDecoderPeer {
46  public:
GetDecoderState(HpackDecoder * decoder)47   static HpackDecoderState* GetDecoderState(HpackDecoder* decoder) {
48     return &decoder->decoder_state_;
49   }
GetDecoderTables(HpackDecoder * decoder)50   static HpackDecoderTables* GetDecoderTables(HpackDecoder* decoder) {
51     return HpackDecoderStatePeer::GetDecoderTables(GetDecoderState(decoder));
52   }
53 };
54 
55 namespace {
56 
57 typedef std::pair<std::string, std::string> HpackHeaderEntry;
58 typedef std::vector<HpackHeaderEntry> HpackHeaderEntries;
59 
60 // TODO(jamessynge): Create a ...test_utils.h file with the mock listener
61 // and with VerifyDynamicTableContents.
62 class MockHpackDecoderListener : public HpackDecoderListener {
63  public:
64   MOCK_METHOD(void, OnHeaderListStart, (), (override));
65   MOCK_METHOD(void, OnHeader, (absl::string_view name, absl::string_view value),
66               (override));
67   MOCK_METHOD(void, OnHeaderListEnd, (), (override));
68   MOCK_METHOD(void, OnHeaderErrorDetected, (absl::string_view error_message),
69               (override));
70 };
71 
72 class HpackDecoderTest : public quiche::test::QuicheTestWithParam<bool>,
73                          public HpackDecoderListener {
74  protected:
75   // Note that we initialize the random number generator with the same seed
76   // for each individual test, therefore the order in which the tests are
77   // executed does not effect the sequence produced by the RNG within any
78   // one test.
HpackDecoderTest()79   HpackDecoderTest() : decoder_(this, 4096) {
80     fragment_the_hpack_block_ = GetParam();
81   }
82   ~HpackDecoderTest() override = default;
83 
OnHeaderListStart()84   void OnHeaderListStart() override {
85     ASSERT_FALSE(saw_start_);
86     ASSERT_FALSE(saw_end_);
87     saw_start_ = true;
88     header_entries_.clear();
89   }
90 
91   // Called for each header name-value pair that is decoded, in the order they
92   // appear in the HPACK block. Multiple values for a given key will be emitted
93   // as multiple calls to OnHeader.
OnHeader(absl::string_view name,absl::string_view value)94   void OnHeader(absl::string_view name, absl::string_view value) override {
95     ASSERT_TRUE(saw_start_);
96     ASSERT_FALSE(saw_end_);
97     header_entries_.emplace_back(name, value);
98   }
99 
100   // OnHeaderBlockEnd is called after successfully decoding an HPACK block. Will
101   // only be called once per block, even if it extends into CONTINUATION frames.
102   // A callback method which notifies when the parser finishes handling a
103   // header block (i.e. the containing frame has the END_STREAM flag set).
104   // Also indicates the total number of bytes in this block.
OnHeaderListEnd()105   void OnHeaderListEnd() override {
106     ASSERT_TRUE(saw_start_);
107     ASSERT_FALSE(saw_end_);
108     ASSERT_TRUE(error_messages_.empty());
109     saw_end_ = true;
110   }
111 
112   // OnHeaderErrorDetected is called if an error is detected while decoding.
113   // error_message may be used in a GOAWAY frame as the Opaque Data.
OnHeaderErrorDetected(absl::string_view error_message)114   void OnHeaderErrorDetected(absl::string_view error_message) override {
115     ASSERT_TRUE(saw_start_);
116     error_messages_.push_back(std::string(error_message));
117     // No further callbacks should be made at this point, so replace 'this' as
118     // the listener with mock_listener_, which is a strict mock, so will
119     // generate an error for any calls.
120     HpackDecoderStatePeer::set_listener(
121         HpackDecoderPeer::GetDecoderState(&decoder_), &mock_listener_);
122   }
123 
DecodeBlock(absl::string_view block)124   AssertionResult DecodeBlock(absl::string_view block) {
125     QUICHE_VLOG(1) << "HpackDecoderTest::DecodeBlock";
126 
127     HTTP2_VERIFY_FALSE(decoder_.DetectError());
128     HTTP2_VERIFY_TRUE(error_messages_.empty());
129     HTTP2_VERIFY_FALSE(saw_start_);
130     HTTP2_VERIFY_FALSE(saw_end_);
131     header_entries_.clear();
132 
133     HTTP2_VERIFY_FALSE(decoder_.DetectError());
134     HTTP2_VERIFY_TRUE(decoder_.StartDecodingBlock());
135     HTTP2_VERIFY_FALSE(decoder_.DetectError());
136 
137     if (fragment_the_hpack_block_) {
138       // See note in ctor regarding RNG.
139       while (!block.empty()) {
140         size_t fragment_size = random_.RandomSizeSkewedLow(block.size());
141         DecodeBuffer db(block.substr(0, fragment_size));
142         HTTP2_VERIFY_TRUE(decoder_.DecodeFragment(&db));
143         HTTP2_VERIFY_EQ(0u, db.Remaining());
144         block.remove_prefix(fragment_size);
145       }
146     } else {
147       DecodeBuffer db(block);
148       HTTP2_VERIFY_TRUE(decoder_.DecodeFragment(&db));
149       HTTP2_VERIFY_EQ(0u, db.Remaining());
150     }
151     HTTP2_VERIFY_FALSE(decoder_.DetectError());
152 
153     HTTP2_VERIFY_TRUE(decoder_.EndDecodingBlock());
154     if (saw_end_) {
155       HTTP2_VERIFY_FALSE(decoder_.DetectError());
156       HTTP2_VERIFY_TRUE(error_messages_.empty());
157     } else {
158       HTTP2_VERIFY_TRUE(decoder_.DetectError());
159       HTTP2_VERIFY_FALSE(error_messages_.empty());
160     }
161 
162     saw_start_ = saw_end_ = false;
163     return AssertionSuccess();
164   }
165 
GetDecoderTables()166   const HpackDecoderTables& GetDecoderTables() {
167     return *HpackDecoderPeer::GetDecoderTables(&decoder_);
168   }
Lookup(size_t index)169   const HpackStringPair* Lookup(size_t index) {
170     return GetDecoderTables().Lookup(index);
171   }
current_header_table_size()172   size_t current_header_table_size() {
173     return GetDecoderTables().current_header_table_size();
174   }
header_table_size_limit()175   size_t header_table_size_limit() {
176     return GetDecoderTables().header_table_size_limit();
177   }
set_header_table_size_limit(size_t size)178   void set_header_table_size_limit(size_t size) {
179     HpackDecoderPeer::GetDecoderTables(&decoder_)->DynamicTableSizeUpdate(size);
180   }
181 
182   // dynamic_index is one-based, because that is the way RFC 7541 shows it.
VerifyEntry(size_t dynamic_index,const char * name,const char * value)183   AssertionResult VerifyEntry(size_t dynamic_index, const char* name,
184                               const char* value) {
185     const HpackStringPair* entry =
186         Lookup(dynamic_index + kFirstDynamicTableIndex - 1);
187     HTTP2_VERIFY_NE(entry, nullptr);
188     HTTP2_VERIFY_EQ(entry->name, name);
189     HTTP2_VERIFY_EQ(entry->value, value);
190     return AssertionSuccess();
191   }
VerifyNoEntry(size_t dynamic_index)192   AssertionResult VerifyNoEntry(size_t dynamic_index) {
193     const HpackStringPair* entry =
194         Lookup(dynamic_index + kFirstDynamicTableIndex - 1);
195     HTTP2_VERIFY_EQ(entry, nullptr);
196     return AssertionSuccess();
197   }
VerifyDynamicTableContents(const std::vector<std::pair<const char *,const char * >> & entries)198   AssertionResult VerifyDynamicTableContents(
199       const std::vector<std::pair<const char*, const char*>>& entries) {
200     size_t index = 1;
201     for (const auto& entry : entries) {
202       HTTP2_VERIFY_SUCCESS(VerifyEntry(index, entry.first, entry.second));
203       ++index;
204     }
205     HTTP2_VERIFY_SUCCESS(VerifyNoEntry(index));
206     return AssertionSuccess();
207   }
208 
209   Http2Random random_;
210   HpackDecoder decoder_;
211   testing::StrictMock<MockHpackDecoderListener> mock_listener_;
212   HpackHeaderEntries header_entries_;
213   std::vector<std::string> error_messages_;
214   bool fragment_the_hpack_block_;
215   bool saw_start_ = false;
216   bool saw_end_ = false;
217 };
218 INSTANTIATE_TEST_SUITE_P(AllWays, HpackDecoderTest, ::testing::Bool());
219 
220 // Test based on RFC 7541, section C.3: Request Examples without Huffman Coding.
221 // This section shows several consecutive header lists, corresponding to HTTP
222 // requests, on the same connection.
223 // http://httpwg.org/specs/rfc7541.html#rfc.section.C.3
TEST_P(HpackDecoderTest,C3_RequestExamples)224 TEST_P(HpackDecoderTest, C3_RequestExamples) {
225   // C.3.1 First Request
226   std::string hpack_block = HpackExampleToStringOrDie(R"(
227       82                                      | == Indexed - Add ==
228                                               |   idx = 2
229                                               | -> :method: GET
230       86                                      | == Indexed - Add ==
231                                               |   idx = 6
232                                               | -> :scheme: http
233       84                                      | == Indexed - Add ==
234                                               |   idx = 4
235                                               | -> :path: /
236       41                                      | == Literal indexed ==
237                                               |   Indexed name (idx = 1)
238                                               |     :authority
239       0f                                      |   Literal value (len = 15)
240       7777 772e 6578 616d 706c 652e 636f 6d   | www.example.com
241                                               | -> :authority:
242                                               |   www.example.com
243   )");
244   EXPECT_TRUE(DecodeBlock(hpack_block));
245   ASSERT_THAT(header_entries_,
246               ElementsAreArray({
247                   HpackHeaderEntry{":method", "GET"},
248                   HpackHeaderEntry{":scheme", "http"},
249                   HpackHeaderEntry{":path", "/"},
250                   HpackHeaderEntry{":authority", "www.example.com"},
251               }));
252 
253   // Dynamic Table (after decoding):
254   //
255   //   [  1] (s =  57) :authority: www.example.com
256   //         Table size:  57
257   ASSERT_TRUE(VerifyDynamicTableContents({{":authority", "www.example.com"}}));
258   ASSERT_EQ(57u, current_header_table_size());
259 
260   // C.3.2 Second Request
261   hpack_block = HpackExampleToStringOrDie(R"(
262       82                                      | == Indexed - Add ==
263                                               |   idx = 2
264                                               | -> :method: GET
265       86                                      | == Indexed - Add ==
266                                               |   idx = 6
267                                               | -> :scheme: http
268       84                                      | == Indexed - Add ==
269                                               |   idx = 4
270                                               | -> :path: /
271       be                                      | == Indexed - Add ==
272                                               |   idx = 62
273                                               | -> :authority:
274                                               |   www.example.com
275       58                                      | == Literal indexed ==
276                                               |   Indexed name (idx = 24)
277                                               |     cache-control
278       08                                      |   Literal value (len = 8)
279       6e6f 2d63 6163 6865                     | no-cache
280                                               | -> cache-control: no-cache
281   )");
282   EXPECT_TRUE(DecodeBlock(hpack_block));
283   ASSERT_THAT(header_entries_,
284               ElementsAreArray({
285                   HpackHeaderEntry{":method", "GET"},
286                   HpackHeaderEntry{":scheme", "http"},
287                   HpackHeaderEntry{":path", "/"},
288                   HpackHeaderEntry{":authority", "www.example.com"},
289                   HpackHeaderEntry{"cache-control", "no-cache"},
290               }));
291 
292   // Dynamic Table (after decoding):
293   //
294   //   [  1] (s =  53) cache-control: no-cache
295   //   [  2] (s =  57) :authority: www.example.com
296   //         Table size: 110
297   ASSERT_TRUE(VerifyDynamicTableContents(
298       {{"cache-control", "no-cache"}, {":authority", "www.example.com"}}));
299   ASSERT_EQ(110u, current_header_table_size());
300 
301   // C.3.2 Third Request
302   hpack_block = HpackExampleToStringOrDie(R"(
303       82                                      | == Indexed - Add ==
304                                               |   idx = 2
305                                               | -> :method: GET
306       87                                      | == Indexed - Add ==
307                                               |   idx = 7
308                                               | -> :scheme: https
309       85                                      | == Indexed - Add ==
310                                               |   idx = 5
311                                               | -> :path: /index.html
312       bf                                      | == Indexed - Add ==
313                                               |   idx = 63
314                                               | -> :authority:
315                                               |   www.example.com
316       40                                      | == Literal indexed ==
317       0a                                      |   Literal name (len = 10)
318       6375 7374 6f6d 2d6b 6579                | custom-key
319       0c                                      |   Literal value (len = 12)
320       6375 7374 6f6d 2d76 616c 7565           | custom-value
321                                               | -> custom-key:
322                                               |   custom-value
323   )");
324   EXPECT_TRUE(DecodeBlock(hpack_block));
325   ASSERT_THAT(header_entries_,
326               ElementsAreArray({
327                   HpackHeaderEntry{":method", "GET"},
328                   HpackHeaderEntry{":scheme", "https"},
329                   HpackHeaderEntry{":path", "/index.html"},
330                   HpackHeaderEntry{":authority", "www.example.com"},
331                   HpackHeaderEntry{"custom-key", "custom-value"},
332               }));
333 
334   // Dynamic Table (after decoding):
335   //
336   //   [  1] (s =  54) custom-key: custom-value
337   //   [  2] (s =  53) cache-control: no-cache
338   //   [  3] (s =  57) :authority: www.example.com
339   //         Table size: 164
340   ASSERT_TRUE(VerifyDynamicTableContents({{"custom-key", "custom-value"},
341                                           {"cache-control", "no-cache"},
342                                           {":authority", "www.example.com"}}));
343   ASSERT_EQ(164u, current_header_table_size());
344 }
345 
346 // Test based on RFC 7541, section C.4 Request Examples with Huffman Coding.
347 // This section shows the same examples as the previous section but uses
348 // Huffman encoding for the literal values.
349 // http://httpwg.org/specs/rfc7541.html#rfc.section.C.4
TEST_P(HpackDecoderTest,C4_RequestExamplesWithHuffmanEncoding)350 TEST_P(HpackDecoderTest, C4_RequestExamplesWithHuffmanEncoding) {
351   // C.4.1 First Request
352   std::string hpack_block = HpackExampleToStringOrDie(R"(
353       82                                      | == Indexed - Add ==
354                                               |   idx = 2
355                                               | -> :method: GET
356       86                                      | == Indexed - Add ==
357                                               |   idx = 6
358                                               | -> :scheme: http
359       84                                      | == Indexed - Add ==
360                                               |   idx = 4
361                                               | -> :path: /
362       41                                      | == Literal indexed ==
363                                               |   Indexed name (idx = 1)
364                                               |     :authority
365       8c                                      |   Literal value (len = 12)
366                                               |     Huffman encoded:
367       f1e3 c2e5 f23a 6ba0 ab90 f4ff           | .....:k.....
368                                               |     Decoded:
369                                               | www.example.com
370                                               | -> :authority:
371                                               |   www.example.com
372   )");
373   EXPECT_TRUE(DecodeBlock(hpack_block));
374   ASSERT_THAT(header_entries_,
375               ElementsAreArray({
376                   HpackHeaderEntry{":method", "GET"},
377                   HpackHeaderEntry{":scheme", "http"},
378                   HpackHeaderEntry{":path", "/"},
379                   HpackHeaderEntry{":authority", "www.example.com"},
380               }));
381 
382   // Dynamic Table (after decoding):
383   //
384   //   [  1] (s =  57) :authority: www.example.com
385   //         Table size:  57
386   ASSERT_TRUE(VerifyDynamicTableContents({{":authority", "www.example.com"}}));
387   ASSERT_EQ(57u, current_header_table_size());
388 
389   // C.4.2 Second Request
390   hpack_block = HpackExampleToStringOrDie(R"(
391       82                                      | == Indexed - Add ==
392                                               |   idx = 2
393                                               | -> :method: GET
394       86                                      | == Indexed - Add ==
395                                               |   idx = 6
396                                               | -> :scheme: http
397       84                                      | == Indexed - Add ==
398                                               |   idx = 4
399                                               | -> :path: /
400       be                                      | == Indexed - Add ==
401                                               |   idx = 62
402                                               | -> :authority:
403                                               |   www.example.com
404       58                                      | == Literal indexed ==
405                                               |   Indexed name (idx = 24)
406                                               |     cache-control
407       86                                      |   Literal value (len = 6)
408                                               |     Huffman encoded:
409       a8eb 1064 9cbf                          | ...d..
410                                               |     Decoded:
411                                               | no-cache
412                                               | -> cache-control: no-cache
413   )");
414   EXPECT_TRUE(DecodeBlock(hpack_block));
415   ASSERT_THAT(header_entries_,
416               ElementsAreArray({
417                   HpackHeaderEntry{":method", "GET"},
418                   HpackHeaderEntry{":scheme", "http"},
419                   HpackHeaderEntry{":path", "/"},
420                   HpackHeaderEntry{":authority", "www.example.com"},
421                   HpackHeaderEntry{"cache-control", "no-cache"},
422               }));
423 
424   // Dynamic Table (after decoding):
425   //
426   //   [  1] (s =  53) cache-control: no-cache
427   //   [  2] (s =  57) :authority: www.example.com
428   //         Table size: 110
429   ASSERT_TRUE(VerifyDynamicTableContents(
430       {{"cache-control", "no-cache"}, {":authority", "www.example.com"}}));
431   ASSERT_EQ(110u, current_header_table_size());
432 
433   // C.4.2 Third Request
434   hpack_block = HpackExampleToStringOrDie(R"(
435     82                                      | == Indexed - Add ==
436                                             |   idx = 2
437                                             | -> :method: GET
438     87                                      | == Indexed - Add ==
439                                             |   idx = 7
440                                             | -> :scheme: https
441     85                                      | == Indexed - Add ==
442                                             |   idx = 5
443                                             | -> :path: /index.html
444     bf                                      | == Indexed - Add ==
445                                             |   idx = 63
446                                             | -> :authority:
447                                             |   www.example.com
448     40                                      | == Literal indexed ==
449     88                                      |   Literal name (len = 8)
450                                             |     Huffman encoded:
451     25a8 49e9 5ba9 7d7f                     | %.I.[.}.
452                                             |     Decoded:
453                                             | custom-key
454     89                                      |   Literal value (len = 9)
455                                             |     Huffman encoded:
456     25a8 49e9 5bb8 e8b4 bf                  | %.I.[....
457                                             |     Decoded:
458                                             | custom-value
459                                             | -> custom-key:
460                                             |   custom-value
461   )");
462   EXPECT_TRUE(DecodeBlock(hpack_block));
463   ASSERT_THAT(header_entries_,
464               ElementsAreArray({
465                   HpackHeaderEntry{":method", "GET"},
466                   HpackHeaderEntry{":scheme", "https"},
467                   HpackHeaderEntry{":path", "/index.html"},
468                   HpackHeaderEntry{":authority", "www.example.com"},
469                   HpackHeaderEntry{"custom-key", "custom-value"},
470               }));
471 
472   // Dynamic Table (after decoding):
473   //
474   //   [  1] (s =  54) custom-key: custom-value
475   //   [  2] (s =  53) cache-control: no-cache
476   //   [  3] (s =  57) :authority: www.example.com
477   //         Table size: 164
478   ASSERT_TRUE(VerifyDynamicTableContents({{"custom-key", "custom-value"},
479                                           {"cache-control", "no-cache"},
480                                           {":authority", "www.example.com"}}));
481   ASSERT_EQ(164u, current_header_table_size());
482 }
483 
484 // Test based on RFC 7541, section C.5: Response Examples without Huffman
485 // Coding. This section shows several consecutive header lists, corresponding
486 // to HTTP responses, on the same connection. The HTTP/2 setting parameter
487 // SETTINGS_HEADER_TABLE_SIZE is set to the value of 256 octets, causing
488 // some evictions to occur.
489 // http://httpwg.org/specs/rfc7541.html#rfc.section.C.5
TEST_P(HpackDecoderTest,C5_ResponseExamples)490 TEST_P(HpackDecoderTest, C5_ResponseExamples) {
491   set_header_table_size_limit(256);
492 
493   // C.5.1 First Response
494   //
495   // Header list to encode:
496   //
497   //   :status: 302
498   //   cache-control: private
499   //   date: Mon, 21 Oct 2013 20:13:21 GMT
500   //   location: https://www.example.com
501 
502   std::string hpack_block = HpackExampleToStringOrDie(R"(
503       48                                      | == Literal indexed ==
504                                               |   Indexed name (idx = 8)
505                                               |     :status
506       03                                      |   Literal value (len = 3)
507       3330 32                                 | 302
508                                               | -> :status: 302
509       58                                      | == Literal indexed ==
510                                               |   Indexed name (idx = 24)
511                                               |     cache-control
512       07                                      |   Literal value (len = 7)
513       7072 6976 6174 65                       | private
514                                               | -> cache-control: private
515       61                                      | == Literal indexed ==
516                                               |   Indexed name (idx = 33)
517                                               |     date
518       1d                                      |   Literal value (len = 29)
519       4d6f 6e2c 2032 3120 4f63 7420 3230 3133 | Mon, 21 Oct 2013
520       2032 303a 3133 3a32 3120 474d 54        |  20:13:21 GMT
521                                               | -> date: Mon, 21 Oct 2013
522                                               |   20:13:21 GMT
523       6e                                      | == Literal indexed ==
524                                               |   Indexed name (idx = 46)
525                                               |     location
526       17                                      |   Literal value (len = 23)
527       6874 7470 733a 2f2f 7777 772e 6578 616d | https://www.exam
528       706c 652e 636f 6d                       | ple.com
529                                               | -> location:
530                                               |   https://www.example.com
531   )");
532   EXPECT_TRUE(DecodeBlock(hpack_block));
533   ASSERT_THAT(header_entries_,
534               ElementsAreArray({
535                   HpackHeaderEntry{":status", "302"},
536                   HpackHeaderEntry{"cache-control", "private"},
537                   HpackHeaderEntry{"date", "Mon, 21 Oct 2013 20:13:21 GMT"},
538                   HpackHeaderEntry{"location", "https://www.example.com"},
539               }));
540 
541   // Dynamic Table (after decoding):
542   //
543   //   [  1] (s =  63) location: https://www.example.com
544   //   [  2] (s =  65) date: Mon, 21 Oct 2013 20:13:21 GMT
545   //   [  3] (s =  52) cache-control: private
546   //   [  4] (s =  42) :status: 302
547   //         Table size: 222
548   ASSERT_TRUE(
549       VerifyDynamicTableContents({{"location", "https://www.example.com"},
550                                   {"date", "Mon, 21 Oct 2013 20:13:21 GMT"},
551                                   {"cache-control", "private"},
552                                   {":status", "302"}}));
553   ASSERT_EQ(222u, current_header_table_size());
554 
555   // C.5.2 Second Response
556   //
557   // The (":status", "302") header field is evicted from the dynamic table to
558   // free space to allow adding the (":status", "307") header field.
559   //
560   // Header list to encode:
561   //
562   //   :status: 307
563   //   cache-control: private
564   //   date: Mon, 21 Oct 2013 20:13:21 GMT
565   //   location: https://www.example.com
566 
567   hpack_block = HpackExampleToStringOrDie(R"(
568       48                                      | == Literal indexed ==
569                                               |   Indexed name (idx = 8)
570                                               |     :status
571       03                                      |   Literal value (len = 3)
572       3330 37                                 | 307
573                                               | - evict: :status: 302
574                                               | -> :status: 307
575       c1                                      | == Indexed - Add ==
576                                               |   idx = 65
577                                               | -> cache-control: private
578       c0                                      | == Indexed - Add ==
579                                               |   idx = 64
580                                               | -> date: Mon, 21 Oct 2013
581                                               |   20:13:21 GMT
582       bf                                      | == Indexed - Add ==
583                                               |   idx = 63
584                                               | -> location:
585                                               |   https://www.example.com
586   )");
587   EXPECT_TRUE(DecodeBlock(hpack_block));
588   ASSERT_THAT(header_entries_,
589               ElementsAreArray({
590                   HpackHeaderEntry{":status", "307"},
591                   HpackHeaderEntry{"cache-control", "private"},
592                   HpackHeaderEntry{"date", "Mon, 21 Oct 2013 20:13:21 GMT"},
593                   HpackHeaderEntry{"location", "https://www.example.com"},
594               }));
595 
596   // Dynamic Table (after decoding):
597   //
598   //   [  1] (s =  42) :status: 307
599   //   [  2] (s =  63) location: https://www.example.com
600   //   [  3] (s =  65) date: Mon, 21 Oct 2013 20:13:21 GMT
601   //   [  4] (s =  52) cache-control: private
602   //         Table size: 222
603 
604   ASSERT_TRUE(
605       VerifyDynamicTableContents({{":status", "307"},
606                                   {"location", "https://www.example.com"},
607                                   {"date", "Mon, 21 Oct 2013 20:13:21 GMT"},
608                                   {"cache-control", "private"}}));
609   ASSERT_EQ(222u, current_header_table_size());
610 
611   // C.5.3 Third Response
612   //
613   // Several header fields are evicted from the dynamic table during the
614   // processing of this header list.
615   //
616   // Header list to encode:
617   //
618   //   :status: 200
619   //   cache-control: private
620   //   date: Mon, 21 Oct 2013 20:13:22 GMT
621   //   location: https://www.example.com
622   //   content-encoding: gzip
623   //   set-cookie: foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1
624   hpack_block = HpackExampleToStringOrDie(R"(
625       88                                      | == Indexed - Add ==
626                                               |   idx = 8
627                                               | -> :status: 200
628       c1                                      | == Indexed - Add ==
629                                               |   idx = 65
630                                               | -> cache-control: private
631       61                                      | == Literal indexed ==
632                                               |   Indexed name (idx = 33)
633                                               |     date
634       1d                                      |   Literal value (len = 29)
635       4d6f 6e2c 2032 3120 4f63 7420 3230 3133 | Mon, 21 Oct 2013
636       2032 303a 3133 3a32 3220 474d 54        |  20:13:22 GMT
637                                               | - evict: cache-control:
638                                               |   private
639                                               | -> date: Mon, 21 Oct 2013
640                                               |   20:13:22 GMT
641       c0                                      | == Indexed - Add ==
642                                               |   idx = 64
643                                               | -> location:
644                                               |   https://www.example.com
645       5a                                      | == Literal indexed ==
646                                               |   Indexed name (idx = 26)
647                                               |     content-encoding
648       04                                      |   Literal value (len = 4)
649       677a 6970                               | gzip
650                                               | - evict: date: Mon, 21 Oct
651                                               |    2013 20:13:21 GMT
652                                               | -> content-encoding: gzip
653       77                                      | == Literal indexed ==
654                                               |   Indexed name (idx = 55)
655                                               |     set-cookie
656       38                                      |   Literal value (len = 56)
657       666f 6f3d 4153 444a 4b48 514b 425a 584f | foo=ASDJKHQKBZXO
658       5157 454f 5049 5541 5851 5745 4f49 553b | QWEOPIUAXQWEOIU;
659       206d 6178 2d61 6765 3d33 3630 303b 2076 |  max-age=3600; v
660       6572 7369 6f6e 3d31                     | ersion=1
661                                               | - evict: location:
662                                               |   https://www.example.com
663                                               | - evict: :status: 307
664                                               | -> set-cookie: foo=ASDJKHQ
665                                               |   KBZXOQWEOPIUAXQWEOIU; ma
666                                               |   x-age=3600; version=1
667   )");
668   EXPECT_TRUE(DecodeBlock(hpack_block));
669   ASSERT_THAT(
670       header_entries_,
671       ElementsAreArray({
672           HpackHeaderEntry{":status", "200"},
673           HpackHeaderEntry{"cache-control", "private"},
674           HpackHeaderEntry{"date", "Mon, 21 Oct 2013 20:13:22 GMT"},
675           HpackHeaderEntry{"location", "https://www.example.com"},
676           HpackHeaderEntry{"content-encoding", "gzip"},
677           HpackHeaderEntry{
678               "set-cookie",
679               "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"},
680       }));
681 
682   // Dynamic Table (after decoding):
683   //
684   //   [  1] (s =  98) set-cookie: foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU;
685   //                    max-age=3600; version=1
686   //   [  2] (s =  52) content-encoding: gzip
687   //   [  3] (s =  65) date: Mon, 21 Oct 2013 20:13:22 GMT
688   //         Table size: 215
689   ASSERT_TRUE(VerifyDynamicTableContents(
690       {{"set-cookie",
691         "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"},
692        {"content-encoding", "gzip"},
693        {"date", "Mon, 21 Oct 2013 20:13:22 GMT"}}));
694   ASSERT_EQ(215u, current_header_table_size());
695 }
696 
697 // Test based on RFC 7541, section C.6: Response Examples with Huffman Coding.
698 // This section shows the same examples as the previous section but uses Huffman
699 // encoding for the literal values. The HTTP/2 setting parameter
700 // SETTINGS_HEADER_TABLE_SIZE is set to the value of 256 octets, causing some
701 // evictions to occur. The eviction mechanism uses the length of the decoded
702 // literal values, so the same evictions occur as in the previous section.
703 // http://httpwg.org/specs/rfc7541.html#rfc.section.C.6
TEST_P(HpackDecoderTest,C6_ResponseExamplesWithHuffmanEncoding)704 TEST_P(HpackDecoderTest, C6_ResponseExamplesWithHuffmanEncoding) {
705   set_header_table_size_limit(256);
706 
707   // C.5.1 First Response
708   //
709   // Header list to encode:
710   //
711   //   :status: 302
712   //   cache-control: private
713   //   date: Mon, 21 Oct 2013 20:13:21 GMT
714   //   location: https://www.example.com
715   std::string hpack_block = HpackExampleToStringOrDie(R"(
716       48                                      | == Literal indexed ==
717                                               |   Indexed name (idx = 8)
718                                               |     :status
719       03                                      |   Literal value (len = 3)
720       3330 32                                 | 302
721                                               | -> :status: 302
722       58                                      | == Literal indexed ==
723                                               |   Indexed name (idx = 24)
724                                               |     cache-control
725       07                                      |   Literal value (len = 7)
726       7072 6976 6174 65                       | private
727                                               | -> cache-control: private
728       61                                      | == Literal indexed ==
729                                               |   Indexed name (idx = 33)
730                                               |     date
731       1d                                      |   Literal value (len = 29)
732       4d6f 6e2c 2032 3120 4f63 7420 3230 3133 | Mon, 21 Oct 2013
733       2032 303a 3133 3a32 3120 474d 54        |  20:13:21 GMT
734                                               | -> date: Mon, 21 Oct 2013
735                                               |   20:13:21 GMT
736       6e                                      | == Literal indexed ==
737                                               |   Indexed name (idx = 46)
738                                               |     location
739       17                                      |   Literal value (len = 23)
740       6874 7470 733a 2f2f 7777 772e 6578 616d | https://www.exam
741       706c 652e 636f 6d                       | ple.com
742                                               | -> location:
743                                               |   https://www.example.com
744   )");
745   EXPECT_TRUE(DecodeBlock(hpack_block));
746   ASSERT_THAT(header_entries_,
747               ElementsAreArray({
748                   HpackHeaderEntry{":status", "302"},
749                   HpackHeaderEntry{"cache-control", "private"},
750                   HpackHeaderEntry{"date", "Mon, 21 Oct 2013 20:13:21 GMT"},
751                   HpackHeaderEntry{"location", "https://www.example.com"},
752               }));
753 
754   // Dynamic Table (after decoding):
755   //
756   //   [  1] (s =  63) location: https://www.example.com
757   //   [  2] (s =  65) date: Mon, 21 Oct 2013 20:13:21 GMT
758   //   [  3] (s =  52) cache-control: private
759   //   [  4] (s =  42) :status: 302
760   //         Table size: 222
761   ASSERT_TRUE(
762       VerifyDynamicTableContents({{"location", "https://www.example.com"},
763                                   {"date", "Mon, 21 Oct 2013 20:13:21 GMT"},
764                                   {"cache-control", "private"},
765                                   {":status", "302"}}));
766   ASSERT_EQ(222u, current_header_table_size());
767 
768   // C.5.2 Second Response
769   //
770   // The (":status", "302") header field is evicted from the dynamic table to
771   // free space to allow adding the (":status", "307") header field.
772   //
773   // Header list to encode:
774   //
775   //   :status: 307
776   //   cache-control: private
777   //   date: Mon, 21 Oct 2013 20:13:21 GMT
778   //   location: https://www.example.com
779   hpack_block = HpackExampleToStringOrDie(R"(
780       48                                      | == Literal indexed ==
781                                               |   Indexed name (idx = 8)
782                                               |     :status
783       03                                      |   Literal value (len = 3)
784       3330 37                                 | 307
785                                               | - evict: :status: 302
786                                               | -> :status: 307
787       c1                                      | == Indexed - Add ==
788                                               |   idx = 65
789                                               | -> cache-control: private
790       c0                                      | == Indexed - Add ==
791                                               |   idx = 64
792                                               | -> date: Mon, 21 Oct 2013
793                                               |   20:13:21 GMT
794       bf                                      | == Indexed - Add ==
795                                               |   idx = 63
796                                               | -> location:
797                                               |   https://www.example.com
798   )");
799   EXPECT_TRUE(DecodeBlock(hpack_block));
800   ASSERT_THAT(header_entries_,
801               ElementsAreArray({
802                   HpackHeaderEntry{":status", "307"},
803                   HpackHeaderEntry{"cache-control", "private"},
804                   HpackHeaderEntry{"date", "Mon, 21 Oct 2013 20:13:21 GMT"},
805                   HpackHeaderEntry{"location", "https://www.example.com"},
806               }));
807 
808   // Dynamic Table (after decoding):
809   //
810   //   [  1] (s =  42) :status: 307
811   //   [  2] (s =  63) location: https://www.example.com
812   //   [  3] (s =  65) date: Mon, 21 Oct 2013 20:13:21 GMT
813   //   [  4] (s =  52) cache-control: private
814   //         Table size: 222
815   ASSERT_TRUE(
816       VerifyDynamicTableContents({{":status", "307"},
817                                   {"location", "https://www.example.com"},
818                                   {"date", "Mon, 21 Oct 2013 20:13:21 GMT"},
819                                   {"cache-control", "private"}}));
820   ASSERT_EQ(222u, current_header_table_size());
821 
822   // C.5.3 Third Response
823   //
824   // Several header fields are evicted from the dynamic table during the
825   // processing of this header list.
826   //
827   // Header list to encode:
828   //
829   //   :status: 200
830   //   cache-control: private
831   //   date: Mon, 21 Oct 2013 20:13:22 GMT
832   //   location: https://www.example.com
833   //   content-encoding: gzip
834   //   set-cookie: foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1
835   hpack_block = HpackExampleToStringOrDie(R"(
836       88                                      | == Indexed - Add ==
837                                               |   idx = 8
838                                               | -> :status: 200
839       c1                                      | == Indexed - Add ==
840                                               |   idx = 65
841                                               | -> cache-control: private
842       61                                      | == Literal indexed ==
843                                               |   Indexed name (idx = 33)
844                                               |     date
845       1d                                      |   Literal value (len = 29)
846       4d6f 6e2c 2032 3120 4f63 7420 3230 3133 | Mon, 21 Oct 2013
847       2032 303a 3133 3a32 3220 474d 54        |  20:13:22 GMT
848                                               | - evict: cache-control:
849                                               |   private
850                                               | -> date: Mon, 21 Oct 2013
851                                               |   20:13:22 GMT
852       c0                                      | == Indexed - Add ==
853                                               |   idx = 64
854                                               | -> location:
855                                               |   https://www.example.com
856       5a                                      | == Literal indexed ==
857                                               |   Indexed name (idx = 26)
858                                               |     content-encoding
859       04                                      |   Literal value (len = 4)
860       677a 6970                               | gzip
861                                               | - evict: date: Mon, 21 Oct
862                                               |    2013 20:13:21 GMT
863                                               | -> content-encoding: gzip
864       77                                      | == Literal indexed ==
865                                               |   Indexed name (idx = 55)
866                                               |     set-cookie
867       38                                      |   Literal value (len = 56)
868       666f 6f3d 4153 444a 4b48 514b 425a 584f | foo=ASDJKHQKBZXO
869       5157 454f 5049 5541 5851 5745 4f49 553b | QWEOPIUAXQWEOIU;
870       206d 6178 2d61 6765 3d33 3630 303b 2076 |  max-age=3600; v
871       6572 7369 6f6e 3d31                     | ersion=1
872                                               | - evict: location:
873                                               |   https://www.example.com
874                                               | - evict: :status: 307
875                                               | -> set-cookie: foo=ASDJKHQ
876                                               |   KBZXOQWEOPIUAXQWEOIU; ma
877                                               |   x-age=3600; version=1
878   )");
879   EXPECT_TRUE(DecodeBlock(hpack_block));
880   ASSERT_THAT(
881       header_entries_,
882       ElementsAreArray({
883           HpackHeaderEntry{":status", "200"},
884           HpackHeaderEntry{"cache-control", "private"},
885           HpackHeaderEntry{"date", "Mon, 21 Oct 2013 20:13:22 GMT"},
886           HpackHeaderEntry{"location", "https://www.example.com"},
887           HpackHeaderEntry{"content-encoding", "gzip"},
888           HpackHeaderEntry{
889               "set-cookie",
890               "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"},
891       }));
892 
893   // Dynamic Table (after decoding):
894   //
895   //   [  1] (s =  98) set-cookie: foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU;
896   //                    max-age=3600; version=1
897   //   [  2] (s =  52) content-encoding: gzip
898   //   [  3] (s =  65) date: Mon, 21 Oct 2013 20:13:22 GMT
899   //         Table size: 215
900   ASSERT_TRUE(VerifyDynamicTableContents(
901       {{"set-cookie",
902         "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"},
903        {"content-encoding", "gzip"},
904        {"date", "Mon, 21 Oct 2013 20:13:22 GMT"}}));
905   ASSERT_EQ(215u, current_header_table_size());
906 }
907 
908 // Confirm that the table size can be changed, but at most twice.
TEST_P(HpackDecoderTest,ProcessesOptionalTableSizeUpdates)909 TEST_P(HpackDecoderTest, ProcessesOptionalTableSizeUpdates) {
910   EXPECT_EQ(Http2SettingsInfo::DefaultHeaderTableSize(),
911             header_table_size_limit());
912   // One update allowed.
913   {
914     HpackBlockBuilder hbb;
915     hbb.AppendDynamicTableSizeUpdate(3000);
916     EXPECT_TRUE(DecodeBlock(hbb.buffer()));
917     EXPECT_EQ(3000u, header_table_size_limit());
918     EXPECT_EQ(0u, current_header_table_size());
919     EXPECT_TRUE(header_entries_.empty());
920   }
921   // Two updates allowed.
922   {
923     HpackBlockBuilder hbb;
924     hbb.AppendDynamicTableSizeUpdate(2000);
925     hbb.AppendDynamicTableSizeUpdate(2500);
926     EXPECT_TRUE(DecodeBlock(hbb.buffer()));
927     EXPECT_EQ(2500u, header_table_size_limit());
928     EXPECT_EQ(0u, current_header_table_size());
929     EXPECT_TRUE(header_entries_.empty());
930   }
931   // A third update in the same HPACK block is rejected, so the final
932   // size is 1000, not 500.
933   {
934     HpackBlockBuilder hbb;
935     hbb.AppendDynamicTableSizeUpdate(1500);
936     hbb.AppendDynamicTableSizeUpdate(1000);
937     hbb.AppendDynamicTableSizeUpdate(500);
938     EXPECT_FALSE(DecodeBlock(hbb.buffer()));
939     EXPECT_EQ(HpackDecodingError::kDynamicTableSizeUpdateNotAllowed,
940               decoder_.error());
941     EXPECT_EQ(1u, error_messages_.size());
942     EXPECT_THAT(error_messages_[0],
943                 Eq("Dynamic table size update not allowed"));
944     EXPECT_EQ(1000u, header_table_size_limit());
945     EXPECT_EQ(0u, current_header_table_size());
946     EXPECT_TRUE(header_entries_.empty());
947   }
948   // An error has been detected, so calls to HpackDecoder::DecodeFragment
949   // should return immediately.
950   DecodeBuffer db("\x80");
951   EXPECT_FALSE(decoder_.DecodeFragment(&db));
952   EXPECT_EQ(0u, db.Offset());
953   EXPECT_EQ(1u, error_messages_.size());
954 }
955 
956 // Confirm that the table size can be changed when required, but at most twice.
TEST_P(HpackDecoderTest,ProcessesRequiredTableSizeUpdate)957 TEST_P(HpackDecoderTest, ProcessesRequiredTableSizeUpdate) {
958   EXPECT_EQ(4096u, decoder_.GetCurrentHeaderTableSizeSetting());
959   // One update required, two allowed, one provided, followed by a header.
960   decoder_.ApplyHeaderTableSizeSetting(1024);
961   decoder_.ApplyHeaderTableSizeSetting(2048);
962   EXPECT_EQ(Http2SettingsInfo::DefaultHeaderTableSize(),
963             header_table_size_limit());
964   EXPECT_EQ(2048u, decoder_.GetCurrentHeaderTableSizeSetting());
965   {
966     HpackBlockBuilder hbb;
967     hbb.AppendDynamicTableSizeUpdate(1024);
968     hbb.AppendIndexedHeader(4);  // :path: /
969     EXPECT_TRUE(DecodeBlock(hbb.buffer()));
970     EXPECT_THAT(header_entries_,
971                 ElementsAreArray({HpackHeaderEntry{":path", "/"}}));
972     EXPECT_EQ(1024u, header_table_size_limit());
973     EXPECT_EQ(0u, current_header_table_size());
974   }
975   // One update required, two allowed, two provided, followed by a header.
976   decoder_.ApplyHeaderTableSizeSetting(1000);
977   decoder_.ApplyHeaderTableSizeSetting(1500);
978   EXPECT_EQ(1500u, decoder_.GetCurrentHeaderTableSizeSetting());
979   {
980     HpackBlockBuilder hbb;
981     hbb.AppendDynamicTableSizeUpdate(500);
982     hbb.AppendDynamicTableSizeUpdate(1250);
983     hbb.AppendIndexedHeader(5);  // :path: /index.html
984     EXPECT_TRUE(DecodeBlock(hbb.buffer()));
985     EXPECT_THAT(header_entries_,
986                 ElementsAreArray({HpackHeaderEntry{":path", "/index.html"}}));
987     EXPECT_EQ(1250u, header_table_size_limit());
988     EXPECT_EQ(0u, current_header_table_size());
989   }
990   // One update required, two allowed, three provided, followed by a header.
991   // The third update is rejected, so the final size is 1000, not 500.
992   decoder_.ApplyHeaderTableSizeSetting(500);
993   decoder_.ApplyHeaderTableSizeSetting(1000);
994   EXPECT_EQ(1000u, decoder_.GetCurrentHeaderTableSizeSetting());
995   {
996     HpackBlockBuilder hbb;
997     hbb.AppendDynamicTableSizeUpdate(200);
998     hbb.AppendDynamicTableSizeUpdate(700);
999     hbb.AppendDynamicTableSizeUpdate(900);
1000     hbb.AppendIndexedHeader(5);  // Not decoded.
1001     EXPECT_FALSE(DecodeBlock(hbb.buffer()));
1002     EXPECT_FALSE(saw_end_);
1003     EXPECT_EQ(HpackDecodingError::kDynamicTableSizeUpdateNotAllowed,
1004               decoder_.error());
1005     EXPECT_EQ(1u, error_messages_.size());
1006     EXPECT_THAT(error_messages_[0],
1007                 Eq("Dynamic table size update not allowed"));
1008     EXPECT_EQ(700u, header_table_size_limit());
1009     EXPECT_EQ(0u, current_header_table_size());
1010     EXPECT_TRUE(header_entries_.empty());
1011   }
1012   EXPECT_EQ(1000u, decoder_.GetCurrentHeaderTableSizeSetting());
1013   // Now that an error has been detected, StartDecodingBlock should return
1014   // false.
1015   EXPECT_FALSE(decoder_.StartDecodingBlock());
1016 }
1017 
1018 // Confirm that required size updates are validated.
TEST_P(HpackDecoderTest,InvalidRequiredSizeUpdate)1019 TEST_P(HpackDecoderTest, InvalidRequiredSizeUpdate) {
1020   // Require a size update, but provide one that isn't small enough (must be
1021   // zero or one, in this case).
1022   decoder_.ApplyHeaderTableSizeSetting(1);
1023   decoder_.ApplyHeaderTableSizeSetting(1024);
1024   HpackBlockBuilder hbb;
1025   hbb.AppendDynamicTableSizeUpdate(2);
1026   EXPECT_TRUE(decoder_.StartDecodingBlock());
1027   DecodeBuffer db(hbb.buffer());
1028   EXPECT_FALSE(decoder_.DecodeFragment(&db));
1029   EXPECT_FALSE(saw_end_);
1030   EXPECT_EQ(
1031       HpackDecodingError::kInitialDynamicTableSizeUpdateIsAboveLowWaterMark,
1032       decoder_.error());
1033   EXPECT_EQ(1u, error_messages_.size());
1034   EXPECT_THAT(error_messages_[0],
1035               Eq("Initial dynamic table size update is above low water mark"));
1036   EXPECT_EQ(Http2SettingsInfo::DefaultHeaderTableSize(),
1037             header_table_size_limit());
1038 }
1039 
1040 // Confirm that required size updates are indeed required before the end.
TEST_P(HpackDecoderTest,RequiredTableSizeChangeBeforeEnd)1041 TEST_P(HpackDecoderTest, RequiredTableSizeChangeBeforeEnd) {
1042   decoder_.ApplyHeaderTableSizeSetting(1024);
1043   EXPECT_FALSE(DecodeBlock(""));
1044   EXPECT_EQ(HpackDecodingError::kMissingDynamicTableSizeUpdate,
1045             decoder_.error());
1046   EXPECT_EQ(1u, error_messages_.size());
1047   EXPECT_THAT(error_messages_[0], Eq("Missing dynamic table size update"));
1048   EXPECT_FALSE(saw_end_);
1049 }
1050 
1051 // Confirm that required size updates are indeed required before an
1052 // indexed header.
TEST_P(HpackDecoderTest,RequiredTableSizeChangeBeforeIndexedHeader)1053 TEST_P(HpackDecoderTest, RequiredTableSizeChangeBeforeIndexedHeader) {
1054   decoder_.ApplyHeaderTableSizeSetting(1024);
1055   HpackBlockBuilder hbb;
1056   hbb.AppendIndexedHeader(1);
1057   EXPECT_FALSE(DecodeBlock(hbb.buffer()));
1058   EXPECT_EQ(HpackDecodingError::kMissingDynamicTableSizeUpdate,
1059             decoder_.error());
1060   EXPECT_EQ(1u, error_messages_.size());
1061   EXPECT_THAT(error_messages_[0], Eq("Missing dynamic table size update"));
1062   EXPECT_FALSE(saw_end_);
1063   EXPECT_TRUE(header_entries_.empty());
1064 }
1065 
1066 // Confirm that required size updates are indeed required before an indexed
1067 // header name.
1068 // TODO(jamessynge): Move some of these to hpack_decoder_state_test.cc.
TEST_P(HpackDecoderTest,RequiredTableSizeChangeBeforeIndexedHeaderName)1069 TEST_P(HpackDecoderTest, RequiredTableSizeChangeBeforeIndexedHeaderName) {
1070   decoder_.ApplyHeaderTableSizeSetting(1024);
1071   HpackBlockBuilder hbb;
1072   hbb.AppendNameIndexAndLiteralValue(HpackEntryType::kIndexedLiteralHeader, 2,
1073                                      false, "PUT");
1074   EXPECT_FALSE(DecodeBlock(hbb.buffer()));
1075   EXPECT_EQ(HpackDecodingError::kMissingDynamicTableSizeUpdate,
1076             decoder_.error());
1077   EXPECT_EQ(1u, error_messages_.size());
1078   EXPECT_THAT(error_messages_[0], Eq("Missing dynamic table size update"));
1079   EXPECT_FALSE(saw_end_);
1080   EXPECT_TRUE(header_entries_.empty());
1081 }
1082 
1083 // Confirm that required size updates are indeed required before a literal
1084 // header name.
TEST_P(HpackDecoderTest,RequiredTableSizeChangeBeforeLiteralName)1085 TEST_P(HpackDecoderTest, RequiredTableSizeChangeBeforeLiteralName) {
1086   decoder_.ApplyHeaderTableSizeSetting(1024);
1087   HpackBlockBuilder hbb;
1088   hbb.AppendLiteralNameAndValue(HpackEntryType::kNeverIndexedLiteralHeader,
1089                                 false, "name", false, "some data.");
1090   EXPECT_FALSE(DecodeBlock(hbb.buffer()));
1091   EXPECT_EQ(HpackDecodingError::kMissingDynamicTableSizeUpdate,
1092             decoder_.error());
1093   EXPECT_EQ(1u, error_messages_.size());
1094   EXPECT_THAT(error_messages_[0], Eq("Missing dynamic table size update"));
1095   EXPECT_FALSE(saw_end_);
1096   EXPECT_TRUE(header_entries_.empty());
1097 }
1098 
1099 // Confirm that an excessively long varint is detected, in this case an
1100 // index of 127, but with lots of additional high-order 0 bits provided,
1101 // too many to be allowed.
TEST_P(HpackDecoderTest,InvalidIndexedHeaderVarint)1102 TEST_P(HpackDecoderTest, InvalidIndexedHeaderVarint) {
1103   EXPECT_TRUE(decoder_.StartDecodingBlock());
1104   DecodeBuffer db("\xff\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x00");
1105   EXPECT_FALSE(decoder_.DecodeFragment(&db));
1106   EXPECT_TRUE(decoder_.DetectError());
1107   EXPECT_FALSE(saw_end_);
1108   EXPECT_EQ(HpackDecodingError::kIndexVarintError, decoder_.error());
1109   EXPECT_EQ(1u, error_messages_.size());
1110   EXPECT_THAT(error_messages_[0],
1111               Eq("Index varint beyond implementation limit"));
1112   EXPECT_TRUE(header_entries_.empty());
1113   // Now that an error has been detected, EndDecodingBlock should not succeed.
1114   EXPECT_FALSE(decoder_.EndDecodingBlock());
1115 }
1116 
1117 // Confirm that an invalid index into the tables is detected, in this case an
1118 // index of 0.
TEST_P(HpackDecoderTest,InvalidIndex)1119 TEST_P(HpackDecoderTest, InvalidIndex) {
1120   EXPECT_TRUE(decoder_.StartDecodingBlock());
1121   DecodeBuffer db("\x80");
1122   EXPECT_FALSE(decoder_.DecodeFragment(&db));
1123   EXPECT_TRUE(decoder_.DetectError());
1124   EXPECT_FALSE(saw_end_);
1125   EXPECT_EQ(HpackDecodingError::kInvalidIndex, decoder_.error());
1126   EXPECT_EQ(1u, error_messages_.size());
1127   EXPECT_THAT(error_messages_[0],
1128               Eq("Invalid index in indexed header field representation"));
1129   EXPECT_TRUE(header_entries_.empty());
1130   // Now that an error has been detected, EndDecodingBlock should not succeed.
1131   EXPECT_FALSE(decoder_.EndDecodingBlock());
1132 }
1133 
1134 // Confirm that EndDecodingBlock detects a truncated HPACK block.
TEST_P(HpackDecoderTest,TruncatedBlock)1135 TEST_P(HpackDecoderTest, TruncatedBlock) {
1136   HpackBlockBuilder hbb;
1137   hbb.AppendDynamicTableSizeUpdate(3000);
1138   EXPECT_EQ(3u, hbb.size());
1139   hbb.AppendDynamicTableSizeUpdate(4000);
1140   EXPECT_EQ(6u, hbb.size());
1141   // Decodes this block if the whole thing is provided.
1142   EXPECT_TRUE(DecodeBlock(hbb.buffer()));
1143   EXPECT_EQ(4000u, header_table_size_limit());
1144   // Multiple times even.
1145   EXPECT_TRUE(DecodeBlock(hbb.buffer()));
1146   EXPECT_EQ(4000u, header_table_size_limit());
1147   // But not if the block is truncated.
1148   EXPECT_FALSE(DecodeBlock(hbb.buffer().substr(0, hbb.size() - 1)));
1149   EXPECT_FALSE(saw_end_);
1150   EXPECT_EQ(HpackDecodingError::kTruncatedBlock, decoder_.error());
1151   EXPECT_EQ(1u, error_messages_.size());
1152   EXPECT_THAT(error_messages_[0],
1153               Eq("Block ends in the middle of an instruction"));
1154   // The first update was decoded.
1155   EXPECT_EQ(3000u, header_table_size_limit());
1156   EXPECT_EQ(0u, current_header_table_size());
1157   EXPECT_TRUE(header_entries_.empty());
1158 }
1159 
1160 // Confirm that an oversized string is detected, ending decoding.
TEST_P(HpackDecoderTest,OversizeStringDetected)1161 TEST_P(HpackDecoderTest, OversizeStringDetected) {
1162   HpackBlockBuilder hbb;
1163   hbb.AppendLiteralNameAndValue(HpackEntryType::kNeverIndexedLiteralHeader,
1164                                 false, "name", false, "some data.");
1165   hbb.AppendLiteralNameAndValue(HpackEntryType::kUnindexedLiteralHeader, false,
1166                                 "name2", false, "longer data");
1167 
1168   // Normally able to decode this block.
1169   EXPECT_TRUE(DecodeBlock(hbb.buffer()));
1170   EXPECT_THAT(header_entries_,
1171               ElementsAreArray({HpackHeaderEntry{"name", "some data."},
1172                                 HpackHeaderEntry{"name2", "longer data"}}));
1173 
1174   // But not if the maximum size of strings is less than the longest string.
1175   decoder_.set_max_string_size_bytes(10);
1176   EXPECT_FALSE(DecodeBlock(hbb.buffer()));
1177   EXPECT_THAT(header_entries_,
1178               ElementsAreArray({HpackHeaderEntry{"name", "some data."}}));
1179   EXPECT_FALSE(saw_end_);
1180   EXPECT_EQ(HpackDecodingError::kValueTooLong, decoder_.error());
1181   EXPECT_EQ(1u, error_messages_.size());
1182   EXPECT_THAT(error_messages_[0], Eq("Value length exceeds buffer limit"));
1183 }
1184 
1185 }  // namespace
1186 }  // namespace test
1187 }  // namespace http2
1188