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