xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/spdy/core/hpack/hpack_decoder_adapter_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/spdy/core/hpack/hpack_decoder_adapter.h"
6 
7 // Tests of HpackDecoderAdapter.
8 
9 #include <stdint.h>
10 
11 #include <cstddef>
12 #include <string>
13 #include <tuple>
14 #include <utility>
15 #include <vector>
16 
17 #include "absl/base/macros.h"
18 #include "absl/strings/escaping.h"
19 #include "absl/strings/string_view.h"
20 #include "quiche/http2/hpack/decoder/hpack_decoder.h"
21 #include "quiche/http2/hpack/decoder/hpack_decoder_state.h"
22 #include "quiche/http2/hpack/decoder/hpack_decoder_tables.h"
23 #include "quiche/http2/hpack/http2_hpack_constants.h"
24 #include "quiche/http2/test_tools/hpack_block_builder.h"
25 #include "quiche/http2/test_tools/http2_random.h"
26 #include "quiche/common/platform/api/quiche_logging.h"
27 #include "quiche/common/platform/api/quiche_test.h"
28 #include "quiche/common/quiche_text_utils.h"
29 #include "quiche/spdy/core/hpack/hpack_constants.h"
30 #include "quiche/spdy/core/hpack/hpack_encoder.h"
31 #include "quiche/spdy/core/hpack/hpack_output_stream.h"
32 #include "quiche/spdy/core/http2_header_block.h"
33 #include "quiche/spdy/core/recording_headers_handler.h"
34 
35 using ::http2::HpackEntryType;
36 using ::http2::HpackStringPair;
37 using ::http2::test::HpackBlockBuilder;
38 using ::http2::test::HpackDecoderPeer;
39 using ::testing::ElementsAre;
40 using ::testing::Pair;
41 
42 namespace http2 {
43 namespace test {
44 
45 class HpackDecoderStatePeer {
46  public:
GetDecoderTables(HpackDecoderState * state)47   static HpackDecoderTables* GetDecoderTables(HpackDecoderState* state) {
48     return &state->decoder_tables_;
49   }
50 };
51 
52 class HpackDecoderPeer {
53  public:
GetDecoderState(HpackDecoder * decoder)54   static HpackDecoderState* GetDecoderState(HpackDecoder* decoder) {
55     return &decoder->decoder_state_;
56   }
GetDecoderTables(HpackDecoder * decoder)57   static HpackDecoderTables* GetDecoderTables(HpackDecoder* decoder) {
58     return HpackDecoderStatePeer::GetDecoderTables(GetDecoderState(decoder));
59   }
60 };
61 
62 }  // namespace test
63 }  // namespace http2
64 
65 namespace spdy {
66 namespace test {
67 
68 class HpackDecoderAdapterPeer {
69  public:
HpackDecoderAdapterPeer(HpackDecoderAdapter * decoder)70   explicit HpackDecoderAdapterPeer(HpackDecoderAdapter* decoder)
71       : decoder_(decoder) {}
72 
HandleHeaderRepresentation(const std::string & name,const std::string & value)73   void HandleHeaderRepresentation(const std::string& name,
74                                   const std::string& value) {
75     decoder_->listener_adapter_.OnHeader(name, value);
76   }
77 
GetDecoderTables()78   http2::HpackDecoderTables* GetDecoderTables() {
79     return HpackDecoderPeer::GetDecoderTables(&decoder_->hpack_decoder_);
80   }
81 
GetTableEntry(uint32_t index)82   const HpackStringPair* GetTableEntry(uint32_t index) {
83     return GetDecoderTables()->Lookup(index);
84   }
85 
current_header_table_size()86   size_t current_header_table_size() {
87     return GetDecoderTables()->current_header_table_size();
88   }
89 
header_table_size_limit()90   size_t header_table_size_limit() {
91     return GetDecoderTables()->header_table_size_limit();
92   }
93 
set_header_table_size_limit(size_t size)94   void set_header_table_size_limit(size_t size) {
95     return GetDecoderTables()->DynamicTableSizeUpdate(size);
96   }
97 
98  private:
99   HpackDecoderAdapter* decoder_;
100 };
101 
102 class HpackEncoderPeer {
103  public:
CookieToCrumbs(const HpackEncoder::Representation & cookie,HpackEncoder::Representations * crumbs_out)104   static void CookieToCrumbs(const HpackEncoder::Representation& cookie,
105                              HpackEncoder::Representations* crumbs_out) {
106     HpackEncoder::CookieToCrumbs(cookie, crumbs_out);
107   }
108 };
109 
110 namespace {
111 
112 const bool kNoCheckDecodedSize = false;
113 const char* kCookieKey = "cookie";
114 
115 class HpackDecoderAdapterTest : public quiche::test::QuicheTestWithParam<bool> {
116  protected:
HpackDecoderAdapterTest()117   HpackDecoderAdapterTest() : decoder_(), decoder_peer_(&decoder_) {}
118 
SetUp()119   void SetUp() override { randomly_split_input_buffer_ = GetParam(); }
120 
HandleControlFrameHeadersStart()121   void HandleControlFrameHeadersStart() {
122     bytes_passed_in_ = 0;
123     decoder_.HandleControlFrameHeadersStart(&handler_);
124   }
125 
HandleControlFrameHeadersData(absl::string_view str)126   bool HandleControlFrameHeadersData(absl::string_view str) {
127     QUICHE_VLOG(3) << "HandleControlFrameHeadersData:\n"
128                    << quiche::QuicheTextUtils::HexDump(str);
129     bytes_passed_in_ += str.size();
130     return decoder_.HandleControlFrameHeadersData(str.data(), str.size());
131   }
132 
HandleControlFrameHeadersComplete()133   bool HandleControlFrameHeadersComplete() {
134     bool rc = decoder_.HandleControlFrameHeadersComplete();
135     return rc;
136   }
137 
DecodeHeaderBlock(absl::string_view str,bool check_decoded_size=true)138   bool DecodeHeaderBlock(absl::string_view str,
139                          bool check_decoded_size = true) {
140     // Don't call this again if HandleControlFrameHeadersData failed previously.
141     EXPECT_FALSE(decode_has_failed_);
142     HandleControlFrameHeadersStart();
143     if (randomly_split_input_buffer_) {
144       do {
145         // Decode some fragment of the remaining bytes.
146         size_t bytes = str.size();
147         if (!str.empty()) {
148           bytes = random_.Uniform(str.size()) + 1;
149         }
150         EXPECT_LE(bytes, str.size());
151         if (!HandleControlFrameHeadersData(str.substr(0, bytes))) {
152           decode_has_failed_ = true;
153           return false;
154         }
155         str.remove_prefix(bytes);
156       } while (!str.empty());
157     } else if (!HandleControlFrameHeadersData(str)) {
158       decode_has_failed_ = true;
159       return false;
160     }
161     if (!HandleControlFrameHeadersComplete()) {
162       decode_has_failed_ = true;
163       return false;
164     }
165     EXPECT_EQ(handler_.compressed_header_bytes(), bytes_passed_in_);
166     if (check_decoded_size) {
167       EXPECT_EQ(handler_.uncompressed_header_bytes(),
168                 SizeOfHeaders(decoded_block()));
169     }
170     return true;
171   }
172 
EncodeAndDecodeDynamicTableSizeUpdates(size_t first,size_t second)173   bool EncodeAndDecodeDynamicTableSizeUpdates(size_t first, size_t second) {
174     HpackBlockBuilder hbb;
175     hbb.AppendDynamicTableSizeUpdate(first);
176     if (second != first) {
177       hbb.AppendDynamicTableSizeUpdate(second);
178     }
179     return DecodeHeaderBlock(hbb.buffer());
180   }
181 
decoded_block() const182   const Http2HeaderBlock& decoded_block() const {
183     return handler_.decoded_block();
184   }
185 
SizeOfHeaders(const Http2HeaderBlock & headers)186   static size_t SizeOfHeaders(const Http2HeaderBlock& headers) {
187     size_t size = 0;
188     for (const auto& kv : headers) {
189       if (kv.first == kCookieKey) {
190         HpackEncoder::Representations crumbs;
191         HpackEncoderPeer::CookieToCrumbs(kv, &crumbs);
192         for (const auto& crumb : crumbs) {
193           size += crumb.first.size() + crumb.second.size();
194         }
195       } else {
196         size += kv.first.size() + kv.second.size();
197       }
198     }
199     return size;
200   }
201 
DecodeBlockExpectingSuccess(absl::string_view str)202   const Http2HeaderBlock& DecodeBlockExpectingSuccess(absl::string_view str) {
203     EXPECT_TRUE(DecodeHeaderBlock(str));
204     return decoded_block();
205   }
206 
expectEntry(size_t index,size_t size,const std::string & name,const std::string & value)207   void expectEntry(size_t index, size_t size, const std::string& name,
208                    const std::string& value) {
209     const HpackStringPair* entry = decoder_peer_.GetTableEntry(index);
210     EXPECT_EQ(name, entry->name) << "index " << index;
211     EXPECT_EQ(value, entry->value);
212     EXPECT_EQ(size, entry->size());
213   }
214 
MakeHeaderBlock(const std::vector<std::pair<std::string,std::string>> & headers)215   Http2HeaderBlock MakeHeaderBlock(
216       const std::vector<std::pair<std::string, std::string>>& headers) {
217     Http2HeaderBlock result;
218     for (const auto& kv : headers) {
219       result.AppendValueOrAddHeader(kv.first, kv.second);
220     }
221     return result;
222   }
223 
224   http2::test::Http2Random random_;
225   HpackDecoderAdapter decoder_;
226   test::HpackDecoderAdapterPeer decoder_peer_;
227   RecordingHeadersHandler handler_;
228   const Http2HeaderBlock dummy_block_;
229   bool randomly_split_input_buffer_;
230   bool decode_has_failed_ = false;
231   size_t bytes_passed_in_;
232 };
233 
234 INSTANTIATE_TEST_SUITE_P(NoHandler, HpackDecoderAdapterTest, ::testing::Bool());
235 
236 INSTANTIATE_TEST_SUITE_P(WithHandler, HpackDecoderAdapterTest,
237                          ::testing::Bool());
238 
TEST_P(HpackDecoderAdapterTest,ApplyHeaderTableSizeSetting)239 TEST_P(HpackDecoderAdapterTest, ApplyHeaderTableSizeSetting) {
240   EXPECT_EQ(4096u, decoder_.GetCurrentHeaderTableSizeSetting());
241   decoder_.ApplyHeaderTableSizeSetting(12 * 1024);
242   EXPECT_EQ(12288u, decoder_.GetCurrentHeaderTableSizeSetting());
243 }
244 
TEST_P(HpackDecoderAdapterTest,AddHeaderDataWithHandleControlFrameHeadersData)245 TEST_P(HpackDecoderAdapterTest,
246        AddHeaderDataWithHandleControlFrameHeadersData) {
247   // The hpack decode buffer size is limited in size. This test verifies that
248   // adding encoded data under that limit is accepted, and data that exceeds the
249   // limit is rejected.
250   HandleControlFrameHeadersStart();
251   const size_t kMaxBufferSizeBytes = 50;
252   const std::string a_value = std::string(49, 'x');
253   decoder_.set_max_decode_buffer_size_bytes(kMaxBufferSizeBytes);
254   HpackBlockBuilder hbb;
255   hbb.AppendLiteralNameAndValue(HpackEntryType::kNeverIndexedLiteralHeader,
256                                 false, "a", false, a_value);
257   const std::string& s = hbb.buffer();
258   EXPECT_GT(s.size(), kMaxBufferSizeBytes);
259 
260   // Any one in input buffer must not exceed kMaxBufferSizeBytes.
261   EXPECT_TRUE(HandleControlFrameHeadersData(s.substr(0, s.size() / 2)));
262   EXPECT_TRUE(HandleControlFrameHeadersData(s.substr(s.size() / 2)));
263 
264   EXPECT_FALSE(HandleControlFrameHeadersData(s));
265   Http2HeaderBlock expected_block = MakeHeaderBlock({{"a", a_value}});
266   EXPECT_EQ(expected_block, decoded_block());
267 }
268 
TEST_P(HpackDecoderAdapterTest,NameTooLong)269 TEST_P(HpackDecoderAdapterTest, NameTooLong) {
270   // Verify that a name longer than the allowed size generates an error.
271   const size_t kMaxBufferSizeBytes = 50;
272   const std::string name = std::string(2 * kMaxBufferSizeBytes, 'x');
273   const std::string value = "abc";
274 
275   decoder_.set_max_decode_buffer_size_bytes(kMaxBufferSizeBytes);
276 
277   HpackBlockBuilder hbb;
278   hbb.AppendLiteralNameAndValue(HpackEntryType::kNeverIndexedLiteralHeader,
279                                 false, name, false, value);
280 
281   const size_t fragment_size = (3 * kMaxBufferSizeBytes) / 2;
282   const std::string fragment = hbb.buffer().substr(0, fragment_size);
283 
284   HandleControlFrameHeadersStart();
285   EXPECT_FALSE(HandleControlFrameHeadersData(fragment));
286 }
287 
TEST_P(HpackDecoderAdapterTest,HeaderTooLongToBuffer)288 TEST_P(HpackDecoderAdapterTest, HeaderTooLongToBuffer) {
289   // Verify that a header longer than the allowed size generates an error if
290   // it isn't all in one input buffer.
291   const std::string name = "some-key";
292   const std::string value = "some-value";
293   const size_t kMaxBufferSizeBytes = name.size() + value.size() - 2;
294   decoder_.set_max_decode_buffer_size_bytes(kMaxBufferSizeBytes);
295 
296   HpackBlockBuilder hbb;
297   hbb.AppendLiteralNameAndValue(HpackEntryType::kNeverIndexedLiteralHeader,
298                                 false, name, false, value);
299   const size_t fragment_size = hbb.size() - 1;
300   const std::string fragment = hbb.buffer().substr(0, fragment_size);
301 
302   HandleControlFrameHeadersStart();
303   EXPECT_FALSE(HandleControlFrameHeadersData(fragment));
304 }
305 
306 // Verify that a header block that exceeds the maximum length is rejected.
TEST_P(HpackDecoderAdapterTest,HeaderBlockTooLong)307 TEST_P(HpackDecoderAdapterTest, HeaderBlockTooLong) {
308   const std::string name = "some-key";
309   const std::string value = "some-value";
310   const size_t kMaxBufferSizeBytes = 1024;
311 
312   HpackBlockBuilder hbb;
313   hbb.AppendLiteralNameAndValue(HpackEntryType::kIndexedLiteralHeader, false,
314                                 name, false, value);
315   while (hbb.size() < kMaxBufferSizeBytes) {
316     hbb.AppendLiteralNameAndValue(HpackEntryType::kIndexedLiteralHeader, false,
317                                   "", false, "");
318   }
319   // With no limit on the maximum header block size, the decoder handles the
320   // entire block successfully.
321   HandleControlFrameHeadersStart();
322   EXPECT_TRUE(HandleControlFrameHeadersData(hbb.buffer()));
323   EXPECT_TRUE(HandleControlFrameHeadersComplete());
324 
325   // When a total byte limit is imposed, the decoder bails before the end of the
326   // block.
327   decoder_.set_max_header_block_bytes(kMaxBufferSizeBytes);
328   HandleControlFrameHeadersStart();
329   EXPECT_FALSE(HandleControlFrameHeadersData(hbb.buffer()));
330 }
331 
332 // Decode with incomplete data in buffer.
TEST_P(HpackDecoderAdapterTest,DecodeWithIncompleteData)333 TEST_P(HpackDecoderAdapterTest, DecodeWithIncompleteData) {
334   HandleControlFrameHeadersStart();
335 
336   // No need to wait for more data.
337   EXPECT_TRUE(HandleControlFrameHeadersData("\x82\x85\x82"));
338   std::vector<std::pair<std::string, std::string>> expected_headers = {
339       {":method", "GET"}, {":path", "/index.html"}, {":method", "GET"}};
340 
341   Http2HeaderBlock expected_block1 = MakeHeaderBlock(expected_headers);
342   EXPECT_EQ(expected_block1, decoded_block());
343 
344   // Full and partial headers, won't add partial to the headers.
345   EXPECT_TRUE(
346       HandleControlFrameHeadersData("\x40\x03goo"
347                                     "\x03gar\xbe\x40\x04spam"));
348   expected_headers.push_back({"goo", "gar"});
349   expected_headers.push_back({"goo", "gar"});
350 
351   Http2HeaderBlock expected_block2 = MakeHeaderBlock(expected_headers);
352   EXPECT_EQ(expected_block2, decoded_block());
353 
354   // Add the needed data.
355   EXPECT_TRUE(HandleControlFrameHeadersData("\x04gggs"));
356 
357   EXPECT_TRUE(HandleControlFrameHeadersComplete());
358 
359   expected_headers.push_back({"spam", "gggs"});
360 
361   Http2HeaderBlock expected_block3 = MakeHeaderBlock(expected_headers);
362   EXPECT_EQ(expected_block3, decoded_block());
363 }
364 
TEST_P(HpackDecoderAdapterTest,HandleHeaderRepresentation)365 TEST_P(HpackDecoderAdapterTest, HandleHeaderRepresentation) {
366   // Make sure the decoder is properly initialized.
367   HandleControlFrameHeadersStart();
368   HandleControlFrameHeadersData("");
369 
370   // All cookie crumbs are joined.
371   decoder_peer_.HandleHeaderRepresentation("cookie", " part 1");
372   decoder_peer_.HandleHeaderRepresentation("cookie", "part 2 ");
373   decoder_peer_.HandleHeaderRepresentation("cookie", "part3");
374 
375   // Already-delimited headers are passed through.
376   decoder_peer_.HandleHeaderRepresentation("passed-through",
377                                            std::string("foo\0baz", 7));
378 
379   // Other headers are joined on \0. Case matters.
380   decoder_peer_.HandleHeaderRepresentation("joined", "joined");
381   decoder_peer_.HandleHeaderRepresentation("joineD", "value 1");
382   decoder_peer_.HandleHeaderRepresentation("joineD", "value 2");
383 
384   // Empty headers remain empty.
385   decoder_peer_.HandleHeaderRepresentation("empty", "");
386 
387   // Joined empty headers work as expected.
388   decoder_peer_.HandleHeaderRepresentation("empty-joined", "");
389   decoder_peer_.HandleHeaderRepresentation("empty-joined", "foo");
390   decoder_peer_.HandleHeaderRepresentation("empty-joined", "");
391   decoder_peer_.HandleHeaderRepresentation("empty-joined", "");
392 
393   // Non-contiguous cookie crumb.
394   decoder_peer_.HandleHeaderRepresentation("cookie", " fin!");
395 
396   // Finish and emit all headers.
397   decoder_.HandleControlFrameHeadersComplete();
398 
399   // Resulting decoded headers are in the same order as the inputs.
400   EXPECT_THAT(
401       decoded_block(),
402       ElementsAre(
403           Pair("cookie", " part 1; part 2 ; part3;  fin!"),
404           Pair("passed-through", absl::string_view("foo\0baz", 7)),
405           Pair("joined", absl::string_view("joined\0value 1\0value 2", 22)),
406           Pair("empty", ""),
407           Pair("empty-joined", absl::string_view("\0foo\0\0", 6))));
408 }
409 
410 // Decoding indexed static table field should work.
TEST_P(HpackDecoderAdapterTest,IndexedHeaderStatic)411 TEST_P(HpackDecoderAdapterTest, IndexedHeaderStatic) {
412   // Reference static table entries #2 and #5.
413   const Http2HeaderBlock& header_set1 = DecodeBlockExpectingSuccess("\x82\x85");
414   Http2HeaderBlock expected_header_set1;
415   expected_header_set1[":method"] = "GET";
416   expected_header_set1[":path"] = "/index.html";
417   EXPECT_EQ(expected_header_set1, header_set1);
418 
419   // Reference static table entry #2.
420   const Http2HeaderBlock& header_set2 = DecodeBlockExpectingSuccess("\x82");
421   Http2HeaderBlock expected_header_set2;
422   expected_header_set2[":method"] = "GET";
423   EXPECT_EQ(expected_header_set2, header_set2);
424 }
425 
TEST_P(HpackDecoderAdapterTest,IndexedHeaderDynamic)426 TEST_P(HpackDecoderAdapterTest, IndexedHeaderDynamic) {
427   // First header block: add an entry to header table.
428   const Http2HeaderBlock& header_set1 = DecodeBlockExpectingSuccess(
429       "\x40\x03"
430       "foo"
431       "\x03"
432       "bar");
433   Http2HeaderBlock expected_header_set1;
434   expected_header_set1["foo"] = "bar";
435   EXPECT_EQ(expected_header_set1, header_set1);
436 
437   // Second header block: add another entry to header table.
438   const Http2HeaderBlock& header_set2 = DecodeBlockExpectingSuccess(
439       "\xbe\x40\x04"
440       "spam"
441       "\x04"
442       "eggs");
443   Http2HeaderBlock expected_header_set2;
444   expected_header_set2["foo"] = "bar";
445   expected_header_set2["spam"] = "eggs";
446   EXPECT_EQ(expected_header_set2, header_set2);
447 
448   // Third header block: refer to most recently added entry.
449   const Http2HeaderBlock& header_set3 = DecodeBlockExpectingSuccess("\xbe");
450   Http2HeaderBlock expected_header_set3;
451   expected_header_set3["spam"] = "eggs";
452   EXPECT_EQ(expected_header_set3, header_set3);
453 }
454 
455 // Test a too-large indexed header.
TEST_P(HpackDecoderAdapterTest,InvalidIndexedHeader)456 TEST_P(HpackDecoderAdapterTest, InvalidIndexedHeader) {
457   // High-bit set, and a prefix of one more than the number of static entries.
458   EXPECT_FALSE(DecodeHeaderBlock("\xbe"));
459 }
460 
TEST_P(HpackDecoderAdapterTest,ContextUpdateMaximumSize)461 TEST_P(HpackDecoderAdapterTest, ContextUpdateMaximumSize) {
462   EXPECT_EQ(kDefaultHeaderTableSizeSetting,
463             decoder_peer_.header_table_size_limit());
464   std::string input;
465   {
466     // Maximum-size update with size 126. Succeeds.
467     HpackOutputStream output_stream;
468     output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode);
469     output_stream.AppendUint32(126);
470 
471     input = output_stream.TakeString();
472     EXPECT_TRUE(DecodeHeaderBlock(input));
473     EXPECT_EQ(126u, decoder_peer_.header_table_size_limit());
474   }
475   {
476     // Maximum-size update with kDefaultHeaderTableSizeSetting. Succeeds.
477     HpackOutputStream output_stream;
478     output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode);
479     output_stream.AppendUint32(kDefaultHeaderTableSizeSetting);
480 
481     input = output_stream.TakeString();
482     EXPECT_TRUE(DecodeHeaderBlock(input));
483     EXPECT_EQ(kDefaultHeaderTableSizeSetting,
484               decoder_peer_.header_table_size_limit());
485   }
486   {
487     // Maximum-size update with kDefaultHeaderTableSizeSetting + 1. Fails.
488     HpackOutputStream output_stream;
489     output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode);
490     output_stream.AppendUint32(kDefaultHeaderTableSizeSetting + 1);
491 
492     input = output_stream.TakeString();
493     EXPECT_FALSE(DecodeHeaderBlock(input));
494     EXPECT_EQ(kDefaultHeaderTableSizeSetting,
495               decoder_peer_.header_table_size_limit());
496   }
497 }
498 
499 // Two HeaderTableSizeUpdates may appear at the beginning of the block
TEST_P(HpackDecoderAdapterTest,TwoTableSizeUpdates)500 TEST_P(HpackDecoderAdapterTest, TwoTableSizeUpdates) {
501   std::string input;
502   {
503     // Should accept two table size updates, update to second one
504     HpackOutputStream output_stream;
505     output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode);
506     output_stream.AppendUint32(0);
507     output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode);
508     output_stream.AppendUint32(122);
509 
510     input = output_stream.TakeString();
511     EXPECT_TRUE(DecodeHeaderBlock(input));
512     EXPECT_EQ(122u, decoder_peer_.header_table_size_limit());
513   }
514 }
515 
516 // Three HeaderTableSizeUpdates should result in an error
TEST_P(HpackDecoderAdapterTest,ThreeTableSizeUpdatesError)517 TEST_P(HpackDecoderAdapterTest, ThreeTableSizeUpdatesError) {
518   std::string input;
519   {
520     // Should reject three table size updates, update to second one
521     HpackOutputStream output_stream;
522     output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode);
523     output_stream.AppendUint32(5);
524     output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode);
525     output_stream.AppendUint32(10);
526     output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode);
527     output_stream.AppendUint32(15);
528 
529     input = output_stream.TakeString();
530 
531     EXPECT_FALSE(DecodeHeaderBlock(input));
532     EXPECT_EQ(10u, decoder_peer_.header_table_size_limit());
533   }
534 }
535 
536 // HeaderTableSizeUpdates may only appear at the beginning of the block
537 // Any other updates should result in an error
TEST_P(HpackDecoderAdapterTest,TableSizeUpdateSecondError)538 TEST_P(HpackDecoderAdapterTest, TableSizeUpdateSecondError) {
539   std::string input;
540   {
541     // Should reject a table size update appearing after a different entry
542     // The table size should remain as the default
543     HpackOutputStream output_stream;
544     output_stream.AppendBytes("\x82\x85");
545     output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode);
546     output_stream.AppendUint32(123);
547 
548     input = output_stream.TakeString();
549 
550     EXPECT_FALSE(DecodeHeaderBlock(input));
551     EXPECT_EQ(kDefaultHeaderTableSizeSetting,
552               decoder_peer_.header_table_size_limit());
553   }
554 }
555 
556 // HeaderTableSizeUpdates may only appear at the beginning of the block
557 // Any other updates should result in an error
TEST_P(HpackDecoderAdapterTest,TableSizeUpdateFirstThirdError)558 TEST_P(HpackDecoderAdapterTest, TableSizeUpdateFirstThirdError) {
559   std::string input;
560   {
561     // Should reject the second table size update
562     // if a different entry appears after the first update
563     // The table size should update to the first but not the second
564     HpackOutputStream output_stream;
565     output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode);
566     output_stream.AppendUint32(60);
567     output_stream.AppendBytes("\x82\x85");
568     output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode);
569     output_stream.AppendUint32(125);
570 
571     input = output_stream.TakeString();
572 
573     EXPECT_FALSE(DecodeHeaderBlock(input));
574     EXPECT_EQ(60u, decoder_peer_.header_table_size_limit());
575   }
576 }
577 
578 // Decoding two valid encoded literal headers with no indexing should
579 // work.
TEST_P(HpackDecoderAdapterTest,LiteralHeaderNoIndexing)580 TEST_P(HpackDecoderAdapterTest, LiteralHeaderNoIndexing) {
581   // First header with indexed name, second header with string literal
582   // name.
583   const char input[] = "\x04\x0c/sample/path\x00\x06:path2\x0e/sample/path/2";
584   const Http2HeaderBlock& header_set = DecodeBlockExpectingSuccess(
585       absl::string_view(input, ABSL_ARRAYSIZE(input) - 1));
586 
587   Http2HeaderBlock expected_header_set;
588   expected_header_set[":path"] = "/sample/path";
589   expected_header_set[":path2"] = "/sample/path/2";
590   EXPECT_EQ(expected_header_set, header_set);
591 }
592 
593 // Decoding two valid encoded literal headers with incremental
594 // indexing and string literal names should work.
TEST_P(HpackDecoderAdapterTest,LiteralHeaderIncrementalIndexing)595 TEST_P(HpackDecoderAdapterTest, LiteralHeaderIncrementalIndexing) {
596   const char input[] = "\x44\x0c/sample/path\x40\x06:path2\x0e/sample/path/2";
597   const Http2HeaderBlock& header_set = DecodeBlockExpectingSuccess(
598       absl::string_view(input, ABSL_ARRAYSIZE(input) - 1));
599 
600   Http2HeaderBlock expected_header_set;
601   expected_header_set[":path"] = "/sample/path";
602   expected_header_set[":path2"] = "/sample/path/2";
603   EXPECT_EQ(expected_header_set, header_set);
604 }
605 
TEST_P(HpackDecoderAdapterTest,LiteralHeaderWithIndexingInvalidNameIndex)606 TEST_P(HpackDecoderAdapterTest, LiteralHeaderWithIndexingInvalidNameIndex) {
607   decoder_.ApplyHeaderTableSizeSetting(0);
608   EXPECT_TRUE(EncodeAndDecodeDynamicTableSizeUpdates(0, 0));
609 
610   // Name is the last static index. Works.
611   EXPECT_TRUE(DecodeHeaderBlock(absl::string_view("\x7d\x03ooo")));
612   // Name is one beyond the last static index. Fails.
613   EXPECT_FALSE(DecodeHeaderBlock(absl::string_view("\x7e\x03ooo")));
614 }
615 
TEST_P(HpackDecoderAdapterTest,LiteralHeaderNoIndexingInvalidNameIndex)616 TEST_P(HpackDecoderAdapterTest, LiteralHeaderNoIndexingInvalidNameIndex) {
617   // Name is the last static index. Works.
618   EXPECT_TRUE(DecodeHeaderBlock(absl::string_view("\x0f\x2e\x03ooo")));
619   // Name is one beyond the last static index. Fails.
620   EXPECT_FALSE(DecodeHeaderBlock(absl::string_view("\x0f\x2f\x03ooo")));
621 }
622 
TEST_P(HpackDecoderAdapterTest,LiteralHeaderNeverIndexedInvalidNameIndex)623 TEST_P(HpackDecoderAdapterTest, LiteralHeaderNeverIndexedInvalidNameIndex) {
624   // Name is the last static index. Works.
625   EXPECT_TRUE(DecodeHeaderBlock(absl::string_view("\x1f\x2e\x03ooo")));
626   // Name is one beyond the last static index. Fails.
627   EXPECT_FALSE(DecodeHeaderBlock(absl::string_view("\x1f\x2f\x03ooo")));
628 }
629 
TEST_P(HpackDecoderAdapterTest,TruncatedIndex)630 TEST_P(HpackDecoderAdapterTest, TruncatedIndex) {
631   // Indexed Header, varint for index requires multiple bytes,
632   // but only one provided.
633   EXPECT_FALSE(DecodeHeaderBlock("\xff"));
634 }
635 
TEST_P(HpackDecoderAdapterTest,TruncatedHuffmanLiteral)636 TEST_P(HpackDecoderAdapterTest, TruncatedHuffmanLiteral) {
637   // Literal value, Huffman encoded, but with the last byte missing (i.e.
638   // drop the final ff shown below).
639   //
640   // 41                                      | == Literal indexed ==
641   //                                         |   Indexed name (idx = 1)
642   //                                         |     :authority
643   // 8c                                      |   Literal value (len = 12)
644   //                                         |     Huffman encoded:
645   // f1e3 c2e5 f23a 6ba0 ab90 f4ff           | .....:k.....
646   //                                         |     Decoded:
647   //                                         | www.example.com
648   //                                         | -> :authority: www.example.com
649 
650   std::string first;
651   ASSERT_TRUE(absl::HexStringToBytes("418cf1e3c2e5f23a6ba0ab90f4ff", &first));
652   EXPECT_TRUE(DecodeHeaderBlock(first));
653   first.pop_back();
654   EXPECT_FALSE(DecodeHeaderBlock(first));
655 }
656 
TEST_P(HpackDecoderAdapterTest,HuffmanEOSError)657 TEST_P(HpackDecoderAdapterTest, HuffmanEOSError) {
658   // Literal value, Huffman encoded, but with an additional ff byte at the end
659   // of the string, i.e. an EOS that is longer than permitted.
660   //
661   // 41                                      | == Literal indexed ==
662   //                                         |   Indexed name (idx = 1)
663   //                                         |     :authority
664   // 8d                                      |   Literal value (len = 13)
665   //                                         |     Huffman encoded:
666   // f1e3 c2e5 f23a 6ba0 ab90 f4ff           | .....:k.....
667   //                                         |     Decoded:
668   //                                         | www.example.com
669   //                                         | -> :authority: www.example.com
670 
671   std::string first;
672   ASSERT_TRUE(absl::HexStringToBytes("418cf1e3c2e5f23a6ba0ab90f4ff", &first));
673   EXPECT_TRUE(DecodeHeaderBlock(first));
674   ASSERT_TRUE(absl::HexStringToBytes("418df1e3c2e5f23a6ba0ab90f4ffff", &first));
675   EXPECT_FALSE(DecodeHeaderBlock(first));
676 }
677 
678 // Round-tripping the header set from RFC 7541 C.3.1 should work.
679 // http://httpwg.org/specs/rfc7541.html#rfc.section.C.3.1
TEST_P(HpackDecoderAdapterTest,BasicC31)680 TEST_P(HpackDecoderAdapterTest, BasicC31) {
681   HpackEncoder encoder;
682 
683   Http2HeaderBlock expected_header_set;
684   expected_header_set[":method"] = "GET";
685   expected_header_set[":scheme"] = "http";
686   expected_header_set[":path"] = "/";
687   expected_header_set[":authority"] = "www.example.com";
688 
689   std::string encoded_header_set =
690       encoder.EncodeHeaderBlock(expected_header_set);
691 
692   EXPECT_TRUE(DecodeHeaderBlock(encoded_header_set));
693   EXPECT_EQ(expected_header_set, decoded_block());
694 }
695 
696 // RFC 7541, Section C.4: Request Examples with Huffman Coding
697 // http://httpwg.org/specs/rfc7541.html#rfc.section.C.4
TEST_P(HpackDecoderAdapterTest,SectionC4RequestHuffmanExamples)698 TEST_P(HpackDecoderAdapterTest, SectionC4RequestHuffmanExamples) {
699   // TODO(jamessynge): Use http2/hpack/tools/hpack_example.h to parse the
700   // example directly, instead of having it as a comment.
701   //
702   // 82                                      | == Indexed - Add ==
703   //                                         |   idx = 2
704   //                                         | -> :method: GET
705   // 86                                      | == Indexed - Add ==
706   //                                         |   idx = 6
707   //                                         | -> :scheme: http
708   // 84                                      | == Indexed - Add ==
709   //                                         |   idx = 4
710   //                                         | -> :path: /
711   // 41                                      | == Literal indexed ==
712   //                                         |   Indexed name (idx = 1)
713   //                                         |     :authority
714   // 8c                                      |   Literal value (len = 12)
715   //                                         |     Huffman encoded:
716   // f1e3 c2e5 f23a 6ba0 ab90 f4ff           | .....:k.....
717   //                                         |     Decoded:
718   //                                         | www.example.com
719   //                                         | -> :authority: www.example.com
720   std::string first;
721   ASSERT_TRUE(
722       absl::HexStringToBytes("828684418cf1e3c2e5f23a6ba0ab90f4ff", &first));
723   const Http2HeaderBlock& first_header_set = DecodeBlockExpectingSuccess(first);
724 
725   EXPECT_THAT(first_header_set,
726               ElementsAre(
727                   // clang-format off
728       Pair(":method", "GET"),
729       Pair(":scheme", "http"),
730       Pair(":path", "/"),
731       Pair(":authority", "www.example.com")));
732   // clang-format on
733 
734   expectEntry(62, 57, ":authority", "www.example.com");
735   EXPECT_EQ(57u, decoder_peer_.current_header_table_size());
736 
737   // 82                                      | == Indexed - Add ==
738   //                                         |   idx = 2
739   //                                         | -> :method: GET
740   // 86                                      | == Indexed - Add ==
741   //                                         |   idx = 6
742   //                                         | -> :scheme: http
743   // 84                                      | == Indexed - Add ==
744   //                                         |   idx = 4
745   //                                         | -> :path: /
746   // be                                      | == Indexed - Add ==
747   //                                         |   idx = 62
748   //                                         | -> :authority: www.example.com
749   // 58                                      | == Literal indexed ==
750   //                                         |   Indexed name (idx = 24)
751   //                                         |     cache-control
752   // 86                                      |   Literal value (len = 8)
753   //                                         |     Huffman encoded:
754   // a8eb 1064 9cbf                          | ...d..
755   //                                         |     Decoded:
756   //                                         | no-cache
757   //                                         | -> cache-control: no-cache
758 
759   std::string second;
760   ASSERT_TRUE(absl::HexStringToBytes("828684be5886a8eb10649cbf", &second));
761   const Http2HeaderBlock& second_header_set =
762       DecodeBlockExpectingSuccess(second);
763 
764   EXPECT_THAT(second_header_set,
765               ElementsAre(
766                   // clang-format off
767       Pair(":method", "GET"),
768       Pair(":scheme", "http"),
769       Pair(":path", "/"),
770       Pair(":authority", "www.example.com"),
771       Pair("cache-control", "no-cache")));
772   // clang-format on
773 
774   expectEntry(62, 53, "cache-control", "no-cache");
775   expectEntry(63, 57, ":authority", "www.example.com");
776   EXPECT_EQ(110u, decoder_peer_.current_header_table_size());
777 
778   // 82                                      | == Indexed - Add ==
779   //                                         |   idx = 2
780   //                                         | -> :method: GET
781   // 87                                      | == Indexed - Add ==
782   //                                         |   idx = 7
783   //                                         | -> :scheme: https
784   // 85                                      | == Indexed - Add ==
785   //                                         |   idx = 5
786   //                                         | -> :path: /index.html
787   // bf                                      | == Indexed - Add ==
788   //                                         |   idx = 63
789   //                                         | -> :authority: www.example.com
790   // 40                                      | == Literal indexed ==
791   // 88                                      |   Literal name (len = 10)
792   //                                         |     Huffman encoded:
793   // 25a8 49e9 5ba9 7d7f                     | %.I.[.}.
794   //                                         |     Decoded:
795   //                                         | custom-key
796   // 89                                      |   Literal value (len = 12)
797   //                                         |     Huffman encoded:
798   // 25a8 49e9 5bb8 e8b4 bf                  | %.I.[....
799   //                                         |     Decoded:
800   //                                         | custom-value
801   //                                         | -> custom-key: custom-value
802   std::string third;
803   ASSERT_TRUE(absl::HexStringToBytes(
804       "828785bf408825a849e95ba97d7f8925a849e95bb8e8b4bf", &third));
805   const Http2HeaderBlock& third_header_set = DecodeBlockExpectingSuccess(third);
806 
807   EXPECT_THAT(
808       third_header_set,
809       ElementsAre(
810           // clang-format off
811       Pair(":method", "GET"),
812       Pair(":scheme", "https"),
813       Pair(":path", "/index.html"),
814       Pair(":authority", "www.example.com"),
815       Pair("custom-key", "custom-value")));
816   // clang-format on
817 
818   expectEntry(62, 54, "custom-key", "custom-value");
819   expectEntry(63, 53, "cache-control", "no-cache");
820   expectEntry(64, 57, ":authority", "www.example.com");
821   EXPECT_EQ(164u, decoder_peer_.current_header_table_size());
822 }
823 
824 // RFC 7541, Section C.6: Response Examples with Huffman Coding
825 // http://httpwg.org/specs/rfc7541.html#rfc.section.C.6
TEST_P(HpackDecoderAdapterTest,SectionC6ResponseHuffmanExamples)826 TEST_P(HpackDecoderAdapterTest, SectionC6ResponseHuffmanExamples) {
827   // The example is based on a maximum dynamic table size of 256,
828   // which allows for testing dynamic table evictions.
829   decoder_peer_.set_header_table_size_limit(256);
830 
831   // 48                                      | == Literal indexed ==
832   //                                         |   Indexed name (idx = 8)
833   //                                         |     :status
834   // 82                                      |   Literal value (len = 3)
835   //                                         |     Huffman encoded:
836   // 6402                                    | d.
837   //                                         |     Decoded:
838   //                                         | 302
839   //                                         | -> :status: 302
840   // 58                                      | == Literal indexed ==
841   //                                         |   Indexed name (idx = 24)
842   //                                         |     cache-control
843   // 85                                      |   Literal value (len = 7)
844   //                                         |     Huffman encoded:
845   // aec3 771a 4b                            | ..w.K
846   //                                         |     Decoded:
847   //                                         | private
848   //                                         | -> cache-control: private
849   // 61                                      | == Literal indexed ==
850   //                                         |   Indexed name (idx = 33)
851   //                                         |     date
852   // 96                                      |   Literal value (len = 29)
853   //                                         |     Huffman encoded:
854   // d07a be94 1054 d444 a820 0595 040b 8166 | .z...T.D. .....f
855   // e082 a62d 1bff                          | ...-..
856   //                                         |     Decoded:
857   //                                         | Mon, 21 Oct 2013 20:13:21
858   //                                         | GMT
859   //                                         | -> date: Mon, 21 Oct 2013
860   //                                         |   20:13:21 GMT
861   // 6e                                      | == Literal indexed ==
862   //                                         |   Indexed name (idx = 46)
863   //                                         |     location
864   // 91                                      |   Literal value (len = 23)
865   //                                         |     Huffman encoded:
866   // 9d29 ad17 1863 c78f 0b97 c8e9 ae82 ae43 | .)...c.........C
867   // d3                                      | .
868   //                                         |     Decoded:
869   //                                         | https://www.example.com
870   //                                         | -> location: https://www.e
871   //                                         |    xample.com
872 
873   std::string first;
874   ASSERT_TRUE(absl::HexStringToBytes(
875       "488264025885aec3771a4b6196d07abe941054d444a8200595040b8166e082a62d1bff6e"
876       "919d29ad171863c78f0b97c8e9ae82ae43d3",
877       &first));
878   const Http2HeaderBlock& first_header_set = DecodeBlockExpectingSuccess(first);
879 
880   EXPECT_THAT(first_header_set,
881               ElementsAre(
882                   // clang-format off
883       Pair(":status", "302"),
884       Pair("cache-control", "private"),
885       Pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"),
886       Pair("location", "https://www.example.com")));
887   // clang-format on
888 
889   expectEntry(62, 63, "location", "https://www.example.com");
890   expectEntry(63, 65, "date", "Mon, 21 Oct 2013 20:13:21 GMT");
891   expectEntry(64, 52, "cache-control", "private");
892   expectEntry(65, 42, ":status", "302");
893   EXPECT_EQ(222u, decoder_peer_.current_header_table_size());
894 
895   // 48                                      | == Literal indexed ==
896   //                                         |   Indexed name (idx = 8)
897   //                                         |     :status
898   // 83                                      |   Literal value (len = 3)
899   //                                         |     Huffman encoded:
900   // 640e ff                                 | d..
901   //                                         |     Decoded:
902   //                                         | 307
903   //                                         | - evict: :status: 302
904   //                                         | -> :status: 307
905   // c1                                      | == Indexed - Add ==
906   //                                         |   idx = 65
907   //                                         | -> cache-control: private
908   // c0                                      | == Indexed - Add ==
909   //                                         |   idx = 64
910   //                                         | -> date: Mon, 21 Oct 2013
911   //                                         |   20:13:21 GMT
912   // bf                                      | == Indexed - Add ==
913   //                                         |   idx = 63
914   //                                         | -> location:
915   //                                         |   https://www.example.com
916   std::string second;
917   ASSERT_TRUE(absl::HexStringToBytes("4883640effc1c0bf", &second));
918   const Http2HeaderBlock& second_header_set =
919       DecodeBlockExpectingSuccess(second);
920 
921   EXPECT_THAT(second_header_set,
922               ElementsAre(
923                   // clang-format off
924       Pair(":status", "307"),
925       Pair("cache-control", "private"),
926       Pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"),
927       Pair("location", "https://www.example.com")));
928   // clang-format on
929 
930   expectEntry(62, 42, ":status", "307");
931   expectEntry(63, 63, "location", "https://www.example.com");
932   expectEntry(64, 65, "date", "Mon, 21 Oct 2013 20:13:21 GMT");
933   expectEntry(65, 52, "cache-control", "private");
934   EXPECT_EQ(222u, decoder_peer_.current_header_table_size());
935 
936   // 88                                      | == Indexed - Add ==
937   //                                         |   idx = 8
938   //                                         | -> :status: 200
939   // c1                                      | == Indexed - Add ==
940   //                                         |   idx = 65
941   //                                         | -> cache-control: private
942   // 61                                      | == Literal indexed ==
943   //                                         |   Indexed name (idx = 33)
944   //                                         |     date
945   // 96                                      |   Literal value (len = 22)
946   //                                         |     Huffman encoded:
947   // d07a be94 1054 d444 a820 0595 040b 8166 | .z...T.D. .....f
948   // e084 a62d 1bff                          | ...-..
949   //                                         |     Decoded:
950   //                                         | Mon, 21 Oct 2013 20:13:22
951   //                                         | GMT
952   //                                         | - evict: cache-control:
953   //                                         |   private
954   //                                         | -> date: Mon, 21 Oct 2013
955   //                                         |   20:13:22 GMT
956   // c0                                      | == Indexed - Add ==
957   //                                         |   idx = 64
958   //                                         | -> location:
959   //                                         |    https://www.example.com
960   // 5a                                      | == Literal indexed ==
961   //                                         |   Indexed name (idx = 26)
962   //                                         |     content-encoding
963   // 83                                      |   Literal value (len = 3)
964   //                                         |     Huffman encoded:
965   // 9bd9 ab                                 | ...
966   //                                         |     Decoded:
967   //                                         | gzip
968   //                                         | - evict: date: Mon, 21 Oct
969   //                                         |    2013 20:13:21 GMT
970   //                                         | -> content-encoding: gzip
971   // 77                                      | == Literal indexed ==
972   //                                         |   Indexed name (idx = 55)
973   //                                         |     set-cookie
974   // ad                                      |   Literal value (len = 45)
975   //                                         |     Huffman encoded:
976   // 94e7 821d d7f2 e6c7 b335 dfdf cd5b 3960 | .........5...[9`
977   // d5af 2708 7f36 72c1 ab27 0fb5 291f 9587 | ..'..6r..'..)...
978   // 3160 65c0 03ed 4ee5 b106 3d50 07        | 1`e...N...=P.
979   //                                         |     Decoded:
980   //                                         | foo=ASDJKHQKBZXOQWEOPIUAXQ
981   //                                         | WEOIU; max-age=3600; versi
982   //                                         | on=1
983   //                                         | - evict: location:
984   //                                         |   https://www.example.com
985   //                                         | - evict: :status: 307
986   //                                         | -> set-cookie: foo=ASDJKHQ
987   //                                         |   KBZXOQWEOPIUAXQWEOIU;
988   //                                         |   max-age=3600; version=1
989   std::string third;
990   ASSERT_TRUE(absl::HexStringToBytes(
991       "88c16196d07abe941054d444a8200595040b8166e084a62d1bffc05a839bd9ab77ad94e7"
992       "821dd7f2e6c7b335dfdfcd5b3960d5af27087f3672c1ab270fb5291f9587316065c003ed"
993       "4ee5b1063d5007",
994       &third));
995   const Http2HeaderBlock& third_header_set = DecodeBlockExpectingSuccess(third);
996 
997   EXPECT_THAT(third_header_set,
998               ElementsAre(
999                   // clang-format off
1000       Pair(":status", "200"),
1001       Pair("cache-control", "private"),
1002       Pair("date", "Mon, 21 Oct 2013 20:13:22 GMT"),
1003       Pair("location", "https://www.example.com"),
1004       Pair("content-encoding", "gzip"),
1005       Pair("set-cookie", "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU;"
1006            " max-age=3600; version=1")));
1007   // clang-format on
1008 
1009   expectEntry(62, 98, "set-cookie",
1010               "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU;"
1011               " max-age=3600; version=1");
1012   expectEntry(63, 52, "content-encoding", "gzip");
1013   expectEntry(64, 65, "date", "Mon, 21 Oct 2013 20:13:22 GMT");
1014   EXPECT_EQ(215u, decoder_peer_.current_header_table_size());
1015 }
1016 
1017 // Regression test: Found that entries with dynamic indexed names and literal
1018 // values caused "use after free" MSAN failures if the name was evicted as it
1019 // was being re-used.
TEST_P(HpackDecoderAdapterTest,ReuseNameOfEvictedEntry)1020 TEST_P(HpackDecoderAdapterTest, ReuseNameOfEvictedEntry) {
1021   // Each entry is measured as 32 bytes plus the sum of the lengths of the name
1022   // and the value. Set the size big enough for at most one entry, and a fairly
1023   // small one at that (31 ASCII characters).
1024   decoder_.ApplyHeaderTableSizeSetting(63);
1025 
1026   HpackBlockBuilder hbb;
1027   hbb.AppendDynamicTableSizeUpdate(0);
1028   hbb.AppendDynamicTableSizeUpdate(63);
1029 
1030   const absl::string_view name("some-name");
1031   const absl::string_view value1("some-value");
1032   const absl::string_view value2("another-value");
1033   const absl::string_view value3("yet-another-value");
1034 
1035   // Add an entry that will become the first in the dynamic table, entry 62.
1036   hbb.AppendLiteralNameAndValue(HpackEntryType::kIndexedLiteralHeader, false,
1037                                 name, false, value1);
1038 
1039   // Confirm that entry has been added by re-using it.
1040   hbb.AppendIndexedHeader(62);
1041 
1042   // Add another entry referring to the name of the first. This will evict the
1043   // first.
1044   hbb.AppendNameIndexAndLiteralValue(HpackEntryType::kIndexedLiteralHeader, 62,
1045                                      false, value2);
1046 
1047   // Confirm that entry has been added by re-using it.
1048   hbb.AppendIndexedHeader(62);
1049 
1050   // Add another entry referring to the name of the second. This will evict the
1051   // second.
1052   hbb.AppendNameIndexAndLiteralValue(HpackEntryType::kIndexedLiteralHeader, 62,
1053                                      false, value3);
1054 
1055   // Confirm that entry has been added by re-using it.
1056   hbb.AppendIndexedHeader(62);
1057 
1058   // Can't have DecodeHeaderBlock do the default check for size of the decoded
1059   // data because Http2HeaderBlock will join multiple headers with the same
1060   // name into a single entry, thus we won't see repeated occurrences of the
1061   // name, instead seeing separators between values.
1062   EXPECT_TRUE(DecodeHeaderBlock(hbb.buffer(), kNoCheckDecodedSize));
1063 
1064   Http2HeaderBlock expected_header_set;
1065   expected_header_set.AppendValueOrAddHeader(name, value1);
1066   expected_header_set.AppendValueOrAddHeader(name, value1);
1067   expected_header_set.AppendValueOrAddHeader(name, value2);
1068   expected_header_set.AppendValueOrAddHeader(name, value2);
1069   expected_header_set.AppendValueOrAddHeader(name, value3);
1070   expected_header_set.AppendValueOrAddHeader(name, value3);
1071 
1072   // Http2HeaderBlock stores these 6 strings as '\0' separated values.
1073   // Make sure that is what happened.
1074   std::string joined_values = expected_header_set[name].as_string();
1075   EXPECT_EQ(joined_values.size(),
1076             2 * value1.size() + 2 * value2.size() + 2 * value3.size() + 5);
1077 
1078   EXPECT_EQ(expected_header_set, decoded_block());
1079 
1080   EXPECT_EQ(handler_.uncompressed_header_bytes(),
1081             6 * name.size() + 2 * value1.size() + 2 * value2.size() +
1082                 2 * value3.size());
1083 }
1084 
1085 // Regression test for https://crbug.com/747395.
TEST_P(HpackDecoderAdapterTest,Cookies)1086 TEST_P(HpackDecoderAdapterTest, Cookies) {
1087   Http2HeaderBlock expected_header_set;
1088   expected_header_set["cookie"] = "foo; bar";
1089 
1090   std::string encoded_block;
1091   ASSERT_TRUE(absl::HexStringToBytes("608294e76003626172", &encoded_block));
1092   EXPECT_TRUE(DecodeHeaderBlock(encoded_block));
1093   EXPECT_EQ(expected_header_set, decoded_block());
1094 }
1095 
1096 }  // namespace
1097 }  // namespace test
1098 }  // namespace spdy
1099