1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "quiche/http2/hpack/decoder/hpack_decoder_state.h"
6
7 // Tests of HpackDecoderState.
8
9 #include <utility>
10 #include <vector>
11
12 #include "absl/strings/string_view.h"
13 #include "quiche/http2/hpack/http2_hpack_constants.h"
14 #include "quiche/http2/http2_constants.h"
15 #include "quiche/http2/test_tools/verify_macros.h"
16 #include "quiche/common/platform/api/quiche_logging.h"
17 #include "quiche/common/platform/api/quiche_test.h"
18
19 using ::testing::AssertionResult;
20 using ::testing::AssertionSuccess;
21 using ::testing::Eq;
22 using ::testing::Mock;
23 using ::testing::StrictMock;
24
25 namespace http2 {
26 namespace test {
27 class HpackDecoderStatePeer {
28 public:
GetDecoderTables(HpackDecoderState * state)29 static HpackDecoderTables* GetDecoderTables(HpackDecoderState* state) {
30 return &state->decoder_tables_;
31 }
32 };
33
34 namespace {
35
36 class MockHpackDecoderListener : public HpackDecoderListener {
37 public:
38 MOCK_METHOD(void, OnHeaderListStart, (), (override));
39 MOCK_METHOD(void, OnHeader, (absl::string_view name, absl::string_view value),
40 (override));
41 MOCK_METHOD(void, OnHeaderListEnd, (), (override));
42 MOCK_METHOD(void, OnHeaderErrorDetected, (absl::string_view error_message),
43 (override));
44 };
45
46 enum StringBacking { UNBUFFERED, BUFFERED };
47
48 class HpackDecoderStateTest : public quiche::test::QuicheTest {
49 protected:
HpackDecoderStateTest()50 HpackDecoderStateTest() : decoder_state_(&listener_) {}
51
GetDecoderTables()52 HpackDecoderTables* GetDecoderTables() {
53 return HpackDecoderStatePeer::GetDecoderTables(&decoder_state_);
54 }
55
Lookup(size_t index)56 const HpackStringPair* Lookup(size_t index) {
57 return GetDecoderTables()->Lookup(index);
58 }
59
current_header_table_size()60 size_t current_header_table_size() {
61 return GetDecoderTables()->current_header_table_size();
62 }
63
header_table_size_limit()64 size_t header_table_size_limit() {
65 return GetDecoderTables()->header_table_size_limit();
66 }
67
set_header_table_size_limit(size_t size)68 void set_header_table_size_limit(size_t size) {
69 GetDecoderTables()->DynamicTableSizeUpdate(size);
70 }
71
SetStringBuffer(absl::string_view s,StringBacking backing,HpackDecoderStringBuffer * string_buffer)72 void SetStringBuffer(absl::string_view s, StringBacking backing,
73 HpackDecoderStringBuffer* string_buffer) {
74 string_buffer->OnStart(false, s.size());
75 EXPECT_TRUE(string_buffer->OnData(s.data(), s.size()));
76 EXPECT_TRUE(string_buffer->OnEnd());
77 if (backing == BUFFERED) {
78 string_buffer->BufferStringIfUnbuffered();
79 }
80 }
81
SetName(absl::string_view s,StringBacking backing)82 void SetName(absl::string_view s, StringBacking backing) {
83 SetStringBuffer(s, backing, &name_buffer_);
84 }
85
SetValue(absl::string_view s,StringBacking backing)86 void SetValue(absl::string_view s, StringBacking backing) {
87 SetStringBuffer(s, backing, &value_buffer_);
88 }
89
SendStartAndVerifyCallback()90 void SendStartAndVerifyCallback() {
91 EXPECT_CALL(listener_, OnHeaderListStart());
92 decoder_state_.OnHeaderBlockStart();
93 Mock::VerifyAndClearExpectations(&listener_);
94 }
95
SendSizeUpdate(size_t size)96 void SendSizeUpdate(size_t size) {
97 decoder_state_.OnDynamicTableSizeUpdate(size);
98 Mock::VerifyAndClearExpectations(&listener_);
99 }
100
SendIndexAndVerifyCallback(size_t index,HpackEntryType,absl::string_view expected_name,absl::string_view expected_value)101 void SendIndexAndVerifyCallback(size_t index,
102 HpackEntryType /*expected_type*/,
103 absl::string_view expected_name,
104 absl::string_view expected_value) {
105 EXPECT_CALL(listener_, OnHeader(Eq(expected_name), Eq(expected_value)));
106 decoder_state_.OnIndexedHeader(index);
107 Mock::VerifyAndClearExpectations(&listener_);
108 }
109
SendValueAndVerifyCallback(size_t name_index,HpackEntryType entry_type,absl::string_view name,absl::string_view value,StringBacking value_backing)110 void SendValueAndVerifyCallback(size_t name_index, HpackEntryType entry_type,
111 absl::string_view name,
112 absl::string_view value,
113 StringBacking value_backing) {
114 SetValue(value, value_backing);
115 EXPECT_CALL(listener_, OnHeader(Eq(name), Eq(value)));
116 decoder_state_.OnNameIndexAndLiteralValue(entry_type, name_index,
117 &value_buffer_);
118 Mock::VerifyAndClearExpectations(&listener_);
119 }
120
SendNameAndValueAndVerifyCallback(HpackEntryType entry_type,absl::string_view name,StringBacking name_backing,absl::string_view value,StringBacking value_backing)121 void SendNameAndValueAndVerifyCallback(HpackEntryType entry_type,
122 absl::string_view name,
123 StringBacking name_backing,
124 absl::string_view value,
125 StringBacking value_backing) {
126 SetName(name, name_backing);
127 SetValue(value, value_backing);
128 EXPECT_CALL(listener_, OnHeader(Eq(name), Eq(value)));
129 decoder_state_.OnLiteralNameAndValue(entry_type, &name_buffer_,
130 &value_buffer_);
131 Mock::VerifyAndClearExpectations(&listener_);
132 }
133
SendEndAndVerifyCallback()134 void SendEndAndVerifyCallback() {
135 EXPECT_CALL(listener_, OnHeaderListEnd());
136 decoder_state_.OnHeaderBlockEnd();
137 Mock::VerifyAndClearExpectations(&listener_);
138 }
139
140 // dynamic_index is one-based, because that is the way RFC 7541 shows it.
VerifyEntry(size_t dynamic_index,absl::string_view name,absl::string_view value)141 AssertionResult VerifyEntry(size_t dynamic_index, absl::string_view name,
142 absl::string_view value) {
143 const HpackStringPair* entry =
144 Lookup(dynamic_index + kFirstDynamicTableIndex - 1);
145 HTTP2_VERIFY_NE(entry, nullptr);
146 HTTP2_VERIFY_EQ(entry->name, name);
147 HTTP2_VERIFY_EQ(entry->value, value);
148 return AssertionSuccess();
149 }
VerifyNoEntry(size_t dynamic_index)150 AssertionResult VerifyNoEntry(size_t dynamic_index) {
151 const HpackStringPair* entry =
152 Lookup(dynamic_index + kFirstDynamicTableIndex - 1);
153 HTTP2_VERIFY_EQ(entry, nullptr);
154 return AssertionSuccess();
155 }
VerifyDynamicTableContents(const std::vector<std::pair<absl::string_view,absl::string_view>> & entries)156 AssertionResult VerifyDynamicTableContents(
157 const std::vector<std::pair<absl::string_view, absl::string_view>>&
158 entries) {
159 size_t index = 1;
160 for (const auto& entry : entries) {
161 HTTP2_VERIFY_SUCCESS(VerifyEntry(index, entry.first, entry.second));
162 ++index;
163 }
164 HTTP2_VERIFY_SUCCESS(VerifyNoEntry(index));
165 return AssertionSuccess();
166 }
167
168 StrictMock<MockHpackDecoderListener> listener_;
169 HpackDecoderState decoder_state_;
170 HpackDecoderStringBuffer name_buffer_, value_buffer_;
171 };
172
173 // Test based on RFC 7541, section C.3: Request Examples without Huffman Coding.
174 // This section shows several consecutive header lists, corresponding to HTTP
175 // requests, on the same connection.
TEST_F(HpackDecoderStateTest,C3_RequestExamples)176 TEST_F(HpackDecoderStateTest, C3_RequestExamples) {
177 // C.3.1 First Request
178 //
179 // Header list to encode:
180 //
181 // :method: GET
182 // :scheme: http
183 // :path: /
184 // :authority: www.example.com
185
186 SendStartAndVerifyCallback();
187 SendIndexAndVerifyCallback(2, HpackEntryType::kIndexedHeader, ":method",
188 "GET");
189 SendIndexAndVerifyCallback(6, HpackEntryType::kIndexedHeader, ":scheme",
190 "http");
191 SendIndexAndVerifyCallback(4, HpackEntryType::kIndexedHeader, ":path", "/");
192 SendValueAndVerifyCallback(1, HpackEntryType::kIndexedLiteralHeader,
193 ":authority", "www.example.com", UNBUFFERED);
194 SendEndAndVerifyCallback();
195
196 // Dynamic Table (after decoding):
197 //
198 // [ 1] (s = 57) :authority: www.example.com
199 // Table size: 57
200
201 ASSERT_TRUE(VerifyDynamicTableContents({{":authority", "www.example.com"}}));
202 ASSERT_EQ(57u, current_header_table_size());
203
204 // C.3.2 Second Request
205 //
206 // Header list to encode:
207 //
208 // :method: GET
209 // :scheme: http
210 // :path: /
211 // :authority: www.example.com
212 // cache-control: no-cache
213
214 SendStartAndVerifyCallback();
215 SendIndexAndVerifyCallback(2, HpackEntryType::kIndexedHeader, ":method",
216 "GET");
217 SendIndexAndVerifyCallback(6, HpackEntryType::kIndexedHeader, ":scheme",
218 "http");
219 SendIndexAndVerifyCallback(4, HpackEntryType::kIndexedHeader, ":path", "/");
220 SendIndexAndVerifyCallback(62, HpackEntryType::kIndexedHeader, ":authority",
221 "www.example.com");
222 SendValueAndVerifyCallback(24, HpackEntryType::kIndexedLiteralHeader,
223 "cache-control", "no-cache", UNBUFFERED);
224 SendEndAndVerifyCallback();
225
226 // Dynamic Table (after decoding):
227 //
228 // [ 1] (s = 53) cache-control: no-cache
229 // [ 2] (s = 57) :authority: www.example.com
230 // Table size: 110
231
232 ASSERT_TRUE(VerifyDynamicTableContents(
233 {{"cache-control", "no-cache"}, {":authority", "www.example.com"}}));
234 ASSERT_EQ(110u, current_header_table_size());
235
236 // C.3.3 Third Request
237 //
238 // Header list to encode:
239 //
240 // :method: GET
241 // :scheme: https
242 // :path: /index.html
243 // :authority: www.example.com
244 // custom-key: custom-value
245
246 SendStartAndVerifyCallback();
247 SendIndexAndVerifyCallback(2, HpackEntryType::kIndexedHeader, ":method",
248 "GET");
249 SendIndexAndVerifyCallback(7, HpackEntryType::kIndexedHeader, ":scheme",
250 "https");
251 SendIndexAndVerifyCallback(5, HpackEntryType::kIndexedHeader, ":path",
252 "/index.html");
253 SendIndexAndVerifyCallback(63, HpackEntryType::kIndexedHeader, ":authority",
254 "www.example.com");
255 SendNameAndValueAndVerifyCallback(HpackEntryType::kIndexedLiteralHeader,
256 "custom-key", UNBUFFERED, "custom-value",
257 UNBUFFERED);
258 SendEndAndVerifyCallback();
259
260 // Dynamic Table (after decoding):
261 //
262 // [ 1] (s = 54) custom-key: custom-value
263 // [ 2] (s = 53) cache-control: no-cache
264 // [ 3] (s = 57) :authority: www.example.com
265 // Table size: 164
266
267 ASSERT_TRUE(VerifyDynamicTableContents({{"custom-key", "custom-value"},
268 {"cache-control", "no-cache"},
269 {":authority", "www.example.com"}}));
270 ASSERT_EQ(164u, current_header_table_size());
271 }
272
273 // Test based on RFC 7541, section C.5: Response Examples without Huffman
274 // Coding. This section shows several consecutive header lists, corresponding
275 // to HTTP responses, on the same connection. The HTTP/2 setting parameter
276 // SETTINGS_HEADER_TABLE_SIZE is set to the value of 256 octets, causing
277 // some evictions to occur.
TEST_F(HpackDecoderStateTest,C5_ResponseExamples)278 TEST_F(HpackDecoderStateTest, C5_ResponseExamples) {
279 set_header_table_size_limit(256);
280
281 // C.5.1 First Response
282 //
283 // Header list to encode:
284 //
285 // :status: 302
286 // cache-control: private
287 // date: Mon, 21 Oct 2013 20:13:21 GMT
288 // location: https://www.example.com
289
290 SendStartAndVerifyCallback();
291 SendValueAndVerifyCallback(8, HpackEntryType::kIndexedLiteralHeader,
292 ":status", "302", BUFFERED);
293 SendValueAndVerifyCallback(24, HpackEntryType::kIndexedLiteralHeader,
294 "cache-control", "private", UNBUFFERED);
295 SendValueAndVerifyCallback(33, HpackEntryType::kIndexedLiteralHeader, "date",
296 "Mon, 21 Oct 2013 20:13:21 GMT", UNBUFFERED);
297 SendValueAndVerifyCallback(46, HpackEntryType::kIndexedLiteralHeader,
298 "location", "https://www.example.com", UNBUFFERED);
299 SendEndAndVerifyCallback();
300
301 // Dynamic Table (after decoding):
302 //
303 // [ 1] (s = 63) location: https://www.example.com
304 // [ 2] (s = 65) date: Mon, 21 Oct 2013 20:13:21 GMT
305 // [ 3] (s = 52) cache-control: private
306 // [ 4] (s = 42) :status: 302
307 // Table size: 222
308
309 ASSERT_TRUE(
310 VerifyDynamicTableContents({{"location", "https://www.example.com"},
311 {"date", "Mon, 21 Oct 2013 20:13:21 GMT"},
312 {"cache-control", "private"},
313 {":status", "302"}}));
314 ASSERT_EQ(222u, current_header_table_size());
315
316 // C.5.2 Second Response
317 //
318 // The (":status", "302") header field is evicted from the dynamic table to
319 // free space to allow adding the (":status", "307") header field.
320 //
321 // Header list to encode:
322 //
323 // :status: 307
324 // cache-control: private
325 // date: Mon, 21 Oct 2013 20:13:21 GMT
326 // location: https://www.example.com
327
328 SendStartAndVerifyCallback();
329 SendValueAndVerifyCallback(8, HpackEntryType::kIndexedLiteralHeader,
330 ":status", "307", BUFFERED);
331 SendIndexAndVerifyCallback(65, HpackEntryType::kIndexedHeader,
332 "cache-control", "private");
333 SendIndexAndVerifyCallback(64, HpackEntryType::kIndexedHeader, "date",
334 "Mon, 21 Oct 2013 20:13:21 GMT");
335 SendIndexAndVerifyCallback(63, HpackEntryType::kIndexedHeader, "location",
336 "https://www.example.com");
337 SendEndAndVerifyCallback();
338
339 // Dynamic Table (after decoding):
340 //
341 // [ 1] (s = 42) :status: 307
342 // [ 2] (s = 63) location: https://www.example.com
343 // [ 3] (s = 65) date: Mon, 21 Oct 2013 20:13:21 GMT
344 // [ 4] (s = 52) cache-control: private
345 // Table size: 222
346
347 ASSERT_TRUE(
348 VerifyDynamicTableContents({{":status", "307"},
349 {"location", "https://www.example.com"},
350 {"date", "Mon, 21 Oct 2013 20:13:21 GMT"},
351 {"cache-control", "private"}}));
352 ASSERT_EQ(222u, current_header_table_size());
353
354 // C.5.3 Third Response
355 //
356 // Several header fields are evicted from the dynamic table during the
357 // processing of this header list.
358 //
359 // Header list to encode:
360 //
361 // :status: 200
362 // cache-control: private
363 // date: Mon, 21 Oct 2013 20:13:22 GMT
364 // location: https://www.example.com
365 // content-encoding: gzip
366 // set-cookie: foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1
367
368 SendStartAndVerifyCallback();
369 SendIndexAndVerifyCallback(8, HpackEntryType::kIndexedHeader, ":status",
370 "200");
371 SendIndexAndVerifyCallback(65, HpackEntryType::kIndexedHeader,
372 "cache-control", "private");
373 SendValueAndVerifyCallback(33, HpackEntryType::kIndexedLiteralHeader, "date",
374 "Mon, 21 Oct 2013 20:13:22 GMT", BUFFERED);
375 SendIndexAndVerifyCallback(64, HpackEntryType::kIndexedHeader, "location",
376 "https://www.example.com");
377 SendValueAndVerifyCallback(26, HpackEntryType::kIndexedLiteralHeader,
378 "content-encoding", "gzip", UNBUFFERED);
379 SendValueAndVerifyCallback(
380 55, HpackEntryType::kIndexedLiteralHeader, "set-cookie",
381 "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1", BUFFERED);
382 SendEndAndVerifyCallback();
383
384 // Dynamic Table (after decoding):
385 //
386 // [ 1] (s = 98) set-cookie: foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU;
387 // max-age=3600; version=1
388 // [ 2] (s = 52) content-encoding: gzip
389 // [ 3] (s = 65) date: Mon, 21 Oct 2013 20:13:22 GMT
390 // Table size: 215
391
392 ASSERT_TRUE(VerifyDynamicTableContents(
393 {{"set-cookie",
394 "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"},
395 {"content-encoding", "gzip"},
396 {"date", "Mon, 21 Oct 2013 20:13:22 GMT"}}));
397 ASSERT_EQ(215u, current_header_table_size());
398 }
399
400 // Confirm that the table size can be changed, but at most twice.
TEST_F(HpackDecoderStateTest,OptionalTableSizeChanges)401 TEST_F(HpackDecoderStateTest, OptionalTableSizeChanges) {
402 SendStartAndVerifyCallback();
403 EXPECT_EQ(Http2SettingsInfo::DefaultHeaderTableSize(),
404 header_table_size_limit());
405 SendSizeUpdate(1024);
406 EXPECT_EQ(1024u, header_table_size_limit());
407 SendSizeUpdate(0);
408 EXPECT_EQ(0u, header_table_size_limit());
409
410 // Three updates aren't allowed.
411 EXPECT_CALL(listener_, OnHeaderErrorDetected(
412 Eq("Dynamic table size update not allowed")));
413 SendSizeUpdate(0);
414 }
415
416 // Confirm that required size updates are indeed required before headers.
TEST_F(HpackDecoderStateTest,RequiredTableSizeChangeBeforeHeader)417 TEST_F(HpackDecoderStateTest, RequiredTableSizeChangeBeforeHeader) {
418 EXPECT_EQ(4096u, decoder_state_.GetCurrentHeaderTableSizeSetting());
419 decoder_state_.ApplyHeaderTableSizeSetting(1024);
420 decoder_state_.ApplyHeaderTableSizeSetting(2048);
421 EXPECT_EQ(2048u, decoder_state_.GetCurrentHeaderTableSizeSetting());
422
423 // First provide the required update, and an allowed second update.
424 SendStartAndVerifyCallback();
425 EXPECT_EQ(Http2SettingsInfo::DefaultHeaderTableSize(),
426 header_table_size_limit());
427 SendSizeUpdate(1024);
428 EXPECT_EQ(1024u, header_table_size_limit());
429 SendSizeUpdate(1500);
430 EXPECT_EQ(1500u, header_table_size_limit());
431 SendEndAndVerifyCallback();
432
433 // Another HPACK block, but this time missing the required size update.
434 decoder_state_.ApplyHeaderTableSizeSetting(1024);
435 EXPECT_EQ(1024u, decoder_state_.GetCurrentHeaderTableSizeSetting());
436 SendStartAndVerifyCallback();
437 EXPECT_CALL(listener_,
438 OnHeaderErrorDetected(Eq("Missing dynamic table size update")));
439 decoder_state_.OnIndexedHeader(1);
440
441 // Further decoded entries are ignored.
442 decoder_state_.OnIndexedHeader(1);
443 decoder_state_.OnDynamicTableSizeUpdate(1);
444 SetValue("value", UNBUFFERED);
445 decoder_state_.OnNameIndexAndLiteralValue(
446 HpackEntryType::kIndexedLiteralHeader, 4, &value_buffer_);
447 SetName("name", UNBUFFERED);
448 decoder_state_.OnLiteralNameAndValue(HpackEntryType::kIndexedLiteralHeader,
449 &name_buffer_, &value_buffer_);
450 decoder_state_.OnHeaderBlockEnd();
451 decoder_state_.OnHpackDecodeError(HpackDecodingError::kIndexVarintError);
452 }
453
454 // Confirm that required size updates are validated.
TEST_F(HpackDecoderStateTest,InvalidRequiredSizeUpdate)455 TEST_F(HpackDecoderStateTest, InvalidRequiredSizeUpdate) {
456 // Require a size update, but provide one that isn't small enough.
457 decoder_state_.ApplyHeaderTableSizeSetting(1024);
458 SendStartAndVerifyCallback();
459 EXPECT_EQ(Http2SettingsInfo::DefaultHeaderTableSize(),
460 header_table_size_limit());
461 EXPECT_CALL(
462 listener_,
463 OnHeaderErrorDetected(
464 Eq("Initial dynamic table size update is above low water mark")));
465 SendSizeUpdate(2048);
466 }
467
468 // Confirm that required size updates are indeed required before the end.
TEST_F(HpackDecoderStateTest,RequiredTableSizeChangeBeforeEnd)469 TEST_F(HpackDecoderStateTest, RequiredTableSizeChangeBeforeEnd) {
470 decoder_state_.ApplyHeaderTableSizeSetting(1024);
471 SendStartAndVerifyCallback();
472 EXPECT_CALL(listener_,
473 OnHeaderErrorDetected(Eq("Missing dynamic table size update")));
474 decoder_state_.OnHeaderBlockEnd();
475 }
476
477 // Confirm that optional size updates are validated.
TEST_F(HpackDecoderStateTest,InvalidOptionalSizeUpdate)478 TEST_F(HpackDecoderStateTest, InvalidOptionalSizeUpdate) {
479 // Require a size update, but provide one that isn't small enough.
480 SendStartAndVerifyCallback();
481 EXPECT_EQ(Http2SettingsInfo::DefaultHeaderTableSize(),
482 header_table_size_limit());
483 EXPECT_CALL(listener_,
484 OnHeaderErrorDetected(Eq(
485 "Dynamic table size update is above acknowledged setting")));
486 SendSizeUpdate(Http2SettingsInfo::DefaultHeaderTableSize() + 1);
487 }
488
TEST_F(HpackDecoderStateTest,InvalidStaticIndex)489 TEST_F(HpackDecoderStateTest, InvalidStaticIndex) {
490 SendStartAndVerifyCallback();
491 EXPECT_CALL(listener_,
492 OnHeaderErrorDetected(
493 Eq("Invalid index in indexed header field representation")));
494 decoder_state_.OnIndexedHeader(0);
495 }
496
TEST_F(HpackDecoderStateTest,InvalidDynamicIndex)497 TEST_F(HpackDecoderStateTest, InvalidDynamicIndex) {
498 SendStartAndVerifyCallback();
499 EXPECT_CALL(listener_,
500 OnHeaderErrorDetected(
501 Eq("Invalid index in indexed header field representation")));
502 decoder_state_.OnIndexedHeader(kFirstDynamicTableIndex);
503 }
504
TEST_F(HpackDecoderStateTest,InvalidNameIndex)505 TEST_F(HpackDecoderStateTest, InvalidNameIndex) {
506 SendStartAndVerifyCallback();
507 EXPECT_CALL(listener_,
508 OnHeaderErrorDetected(Eq("Invalid index in literal header field "
509 "with indexed name representation")));
510 SetValue("value", UNBUFFERED);
511 decoder_state_.OnNameIndexAndLiteralValue(
512 HpackEntryType::kIndexedLiteralHeader, kFirstDynamicTableIndex,
513 &value_buffer_);
514 }
515
TEST_F(HpackDecoderStateTest,ErrorsSuppressCallbacks)516 TEST_F(HpackDecoderStateTest, ErrorsSuppressCallbacks) {
517 SendStartAndVerifyCallback();
518 EXPECT_CALL(listener_,
519 OnHeaderErrorDetected(Eq("Name Huffman encoding error")));
520 decoder_state_.OnHpackDecodeError(HpackDecodingError::kNameHuffmanError);
521
522 // Further decoded entries are ignored.
523 decoder_state_.OnIndexedHeader(1);
524 decoder_state_.OnDynamicTableSizeUpdate(1);
525 SetValue("value", UNBUFFERED);
526 decoder_state_.OnNameIndexAndLiteralValue(
527 HpackEntryType::kIndexedLiteralHeader, 4, &value_buffer_);
528 SetName("name", UNBUFFERED);
529 decoder_state_.OnLiteralNameAndValue(HpackEntryType::kIndexedLiteralHeader,
530 &name_buffer_, &value_buffer_);
531 decoder_state_.OnHeaderBlockEnd();
532 decoder_state_.OnHpackDecodeError(HpackDecodingError::kIndexVarintError);
533 }
534
535 } // namespace
536 } // namespace test
537 } // namespace http2
538