xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/http2/hpack/decoder/hpack_decoder_state_test.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #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