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