Home | History | Annotate | Download | only in spdy
      1 // Copyright 2014 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/spdy/hpack_decoder.h"
      6 
      7 #include <map>
      8 #include <string>
      9 
     10 #include "base/basictypes.h"
     11 #include "base/logging.h"
     12 #include "base/strings/string_piece.h"
     13 #include "net/spdy/hpack_encoder.h"
     14 #include "net/spdy/hpack_input_stream.h"
     15 #include "net/spdy/hpack_output_stream.h"
     16 #include "net/spdy/spdy_test_utils.h"
     17 #include "testing/gmock/include/gmock/gmock.h"
     18 #include "testing/gtest/include/gtest/gtest.h"
     19 
     20 namespace net {
     21 
     22 namespace test {
     23 
     24 using base::StringPiece;
     25 using std::string;
     26 
     27 class HpackDecoderPeer {
     28  public:
     29   explicit HpackDecoderPeer(HpackDecoder* decoder)
     30       : decoder_(decoder) {}
     31 
     32   void HandleHeaderRepresentation(StringPiece name, StringPiece value) {
     33     decoder_->HandleHeaderRepresentation(name, value);
     34   }
     35   bool DecodeNextName(HpackInputStream* in, StringPiece* out) {
     36     return decoder_->DecodeNextName(in, out);
     37   }
     38   HpackHeaderTable* header_table() {
     39     return &decoder_->header_table_;
     40   }
     41   void set_cookie_value(string value) {
     42     decoder_->cookie_value_ = value;
     43   }
     44   string cookie_value() {
     45     return decoder_->cookie_value_;
     46   }
     47   const std::map<string, string>& decoded_block() const {
     48     return decoder_->decoded_block_;
     49   }
     50   const string& headers_block_buffer() const {
     51     return decoder_->headers_block_buffer_;
     52   }
     53 
     54  private:
     55   HpackDecoder* decoder_;
     56 };
     57 
     58 }  // namespace test
     59 
     60 namespace {
     61 
     62 using base::StringPiece;
     63 using std::string;
     64 using test::a2b_hex;
     65 
     66 using testing::ElementsAre;
     67 using testing::Pair;
     68 
     69 const size_t kLiteralBound = 1024;
     70 
     71 class HpackDecoderTest : public ::testing::Test {
     72  protected:
     73   HpackDecoderTest()
     74       : decoder_(ObtainHpackHuffmanTable()),
     75         decoder_peer_(&decoder_) {}
     76 
     77   bool DecodeHeaderBlock(StringPiece str) {
     78     return decoder_.HandleControlFrameHeadersData(0, str.data(), str.size()) &&
     79         decoder_.HandleControlFrameHeadersComplete(0);
     80   }
     81 
     82   const std::map<string, string>& decoded_block() const {
     83     // TODO(jgraettinger): HpackDecoderTest should implement
     84     // SpdyHeadersHandlerInterface, and collect headers for examination.
     85     return decoder_peer_.decoded_block();
     86   }
     87 
     88   const std::map<string, string>& DecodeBlockExpectingSuccess(StringPiece str) {
     89     EXPECT_TRUE(DecodeHeaderBlock(str));
     90     return decoded_block();
     91   }
     92 
     93   void expectEntry(size_t index, size_t size, const string& name,
     94                    const string& value) {
     95     HpackEntry* entry = decoder_peer_.header_table()->GetByIndex(index);
     96     EXPECT_EQ(name, entry->name()) << "index " << index;
     97     EXPECT_EQ(value, entry->value());
     98     EXPECT_EQ(size, entry->Size());
     99     EXPECT_EQ(index, decoder_peer_.header_table()->IndexOf(entry));
    100   }
    101 
    102   void expectStaticEntry(size_t index) {
    103     HpackEntry* entry = decoder_peer_.header_table()->GetByIndex(index);
    104     EXPECT_TRUE(entry->IsStatic()) << "index " << index;
    105   }
    106 
    107   HpackDecoder decoder_;
    108   test::HpackDecoderPeer decoder_peer_;
    109 };
    110 
    111 TEST_F(HpackDecoderTest, HandleControlFrameHeadersData) {
    112   // Strings under threshold are concatenated in the buffer.
    113   EXPECT_TRUE(decoder_.HandleControlFrameHeadersData(
    114       0, "small string one", 16));
    115   EXPECT_TRUE(decoder_.HandleControlFrameHeadersData(
    116       0, "small string two", 16));
    117   // A string which would push the buffer over the threshold is refused.
    118   EXPECT_FALSE(decoder_.HandleControlFrameHeadersData(
    119       0, "fails", kMaxDecodeBufferSize - 32 + 1));
    120 
    121   EXPECT_EQ(decoder_peer_.headers_block_buffer(),
    122             "small string onesmall string two");
    123 }
    124 
    125 TEST_F(HpackDecoderTest, HandleControlFrameHeadersComplete) {
    126   // Decode a block which toggles two static headers into the reference set.
    127   EXPECT_TRUE(DecodeHeaderBlock("\x82\x86"));
    128 
    129   decoder_peer_.set_cookie_value("foobar=baz");
    130 
    131   // Headers in the reference set should be emitted.
    132   // Incremental cookie buffer should be emitted and cleared.
    133   decoder_.HandleControlFrameHeadersData(0, NULL, 0);
    134   decoder_.HandleControlFrameHeadersComplete(0);
    135 
    136   EXPECT_THAT(decoded_block(), ElementsAre(
    137       Pair(":method", "GET"),
    138       Pair(":path", "/index.html"),
    139       Pair("cookie", "foobar=baz")));
    140   EXPECT_EQ(decoder_peer_.cookie_value(), "");
    141 }
    142 
    143 TEST_F(HpackDecoderTest, HandleHeaderRepresentation) {
    144   // All cookie crumbs are joined.
    145   decoder_peer_.HandleHeaderRepresentation("cookie", " part 1");
    146   decoder_peer_.HandleHeaderRepresentation("cookie", "part 2 ");
    147   decoder_peer_.HandleHeaderRepresentation("cookie", "part3");
    148 
    149   // Already-delimited headers are passed through.
    150   decoder_peer_.HandleHeaderRepresentation("passed-through",
    151                                            string("foo\0baz", 7));
    152 
    153   // Other headers are joined on \0. Case matters.
    154   decoder_peer_.HandleHeaderRepresentation("joined", "not joined");
    155   decoder_peer_.HandleHeaderRepresentation("joineD", "value 1");
    156   decoder_peer_.HandleHeaderRepresentation("joineD", "value 2");
    157 
    158   // Empty headers remain empty.
    159   decoder_peer_.HandleHeaderRepresentation("empty", "");
    160 
    161   // Joined empty headers work as expected.
    162   decoder_peer_.HandleHeaderRepresentation("empty-joined", "");
    163   decoder_peer_.HandleHeaderRepresentation("empty-joined", "foo");
    164   decoder_peer_.HandleHeaderRepresentation("empty-joined", "");
    165   decoder_peer_.HandleHeaderRepresentation("empty-joined", "");
    166 
    167   // Non-contiguous cookie crumb.
    168   decoder_peer_.HandleHeaderRepresentation("cookie", " fin!");
    169 
    170   // Finish and emit all headers.
    171   decoder_.HandleControlFrameHeadersComplete(0);
    172 
    173   EXPECT_THAT(decoded_block(), ElementsAre(
    174       Pair("cookie", " part 1; part 2 ; part3;  fin!"),
    175       Pair("empty", ""),
    176       Pair("empty-joined", string("\0foo\0\0", 6)),
    177       Pair("joineD", string("value 1\0value 2", 15)),
    178       Pair("joined", "not joined"),
    179       Pair("passed-through", string("foo\0baz", 7))));
    180 }
    181 
    182 // Decoding an encoded name with a valid string literal should work.
    183 TEST_F(HpackDecoderTest, DecodeNextNameLiteral) {
    184   HpackInputStream input_stream(kLiteralBound, StringPiece("\x00\x04name", 6));
    185 
    186   StringPiece string_piece;
    187   EXPECT_TRUE(decoder_peer_.DecodeNextName(&input_stream, &string_piece));
    188   EXPECT_EQ("name", string_piece);
    189   EXPECT_FALSE(input_stream.HasMoreData());
    190 }
    191 
    192 TEST_F(HpackDecoderTest, DecodeNextNameLiteralWithHuffmanEncoding) {
    193   string input = a2b_hex("0088571c5cdb737b2faf");
    194   HpackInputStream input_stream(kLiteralBound, input);
    195 
    196   StringPiece string_piece;
    197   EXPECT_TRUE(decoder_peer_.DecodeNextName(&input_stream, &string_piece));
    198   EXPECT_EQ("custom-key", string_piece);
    199   EXPECT_FALSE(input_stream.HasMoreData());
    200 }
    201 
    202 // Decoding an encoded name with a valid index should work.
    203 TEST_F(HpackDecoderTest, DecodeNextNameIndexed) {
    204   HpackInputStream input_stream(kLiteralBound, "\x01");
    205 
    206   StringPiece string_piece;
    207   EXPECT_TRUE(decoder_peer_.DecodeNextName(&input_stream, &string_piece));
    208   EXPECT_EQ(":authority", string_piece);
    209   EXPECT_FALSE(input_stream.HasMoreData());
    210 }
    211 
    212 // Decoding an encoded name with an invalid index should fail.
    213 TEST_F(HpackDecoderTest, DecodeNextNameInvalidIndex) {
    214   // One more than the number of static table entries.
    215   HpackInputStream input_stream(kLiteralBound, "\x3e");
    216 
    217   StringPiece string_piece;
    218   EXPECT_FALSE(decoder_peer_.DecodeNextName(&input_stream, &string_piece));
    219 }
    220 
    221 // Decoding an indexed header should toggle the index's presence in
    222 // the reference set, making a copy of static table entries if
    223 // necessary. It should also emit the header if toggled on (and only
    224 // as many times as it was toggled on).
    225 TEST_F(HpackDecoderTest, IndexedHeaderBasic) {
    226   // Toggle on static table entry #2 (and make a copy at index #1),
    227   // then toggle on static table entry #5 (which is now #6 because of
    228   // the copy of #2).
    229   std::map<string, string> header_set1 =
    230       DecodeBlockExpectingSuccess("\x82\x86");
    231   std::map<string, string> expected_header_set1;
    232   expected_header_set1[":method"] = "GET";
    233   expected_header_set1[":path"] = "/index.html";
    234   EXPECT_EQ(expected_header_set1, header_set1);
    235 
    236   std::map<string, string> expected_header_set2;
    237   expected_header_set2[":path"] = "/index.html";
    238   // Toggle off the copy of static table entry #5.
    239   std::map<string, string> header_set2 =
    240       DecodeBlockExpectingSuccess("\x82");
    241   EXPECT_EQ(expected_header_set2, header_set2);
    242 }
    243 
    244 // Test a too-large indexed header.
    245 TEST_F(HpackDecoderTest, InvalidIndexedHeader) {
    246   // High-bit set, and a prefix of one more than the number of static entries.
    247   EXPECT_FALSE(DecodeHeaderBlock(StringPiece("\xbe", 1)));
    248 }
    249 
    250 TEST_F(HpackDecoderTest, ContextUpdateMaximumSize) {
    251   EXPECT_EQ(kDefaultHeaderTableSizeSetting,
    252             decoder_peer_.header_table()->max_size());
    253   string input;
    254   {
    255     // Maximum-size update with size 126. Succeeds.
    256     HpackOutputStream output_stream;
    257     output_stream.AppendPrefix(kEncodingContextOpcode);
    258     output_stream.AppendPrefix(kEncodingContextNewMaximumSize);
    259     output_stream.AppendUint32(126);
    260 
    261     output_stream.TakeString(&input);
    262     EXPECT_TRUE(DecodeHeaderBlock(StringPiece(input)));
    263     EXPECT_EQ(126u, decoder_peer_.header_table()->max_size());
    264   }
    265   {
    266     // Maximum-size update with kDefaultHeaderTableSizeSetting. Succeeds.
    267     HpackOutputStream output_stream;
    268     output_stream.AppendPrefix(kEncodingContextOpcode);
    269     output_stream.AppendPrefix(kEncodingContextNewMaximumSize);
    270     output_stream.AppendUint32(kDefaultHeaderTableSizeSetting);
    271 
    272     output_stream.TakeString(&input);
    273     EXPECT_TRUE(DecodeHeaderBlock(StringPiece(input)));
    274     EXPECT_EQ(kDefaultHeaderTableSizeSetting,
    275               decoder_peer_.header_table()->max_size());
    276   }
    277   {
    278     // Maximum-size update with kDefaultHeaderTableSizeSetting + 1. Fails.
    279     HpackOutputStream output_stream;
    280     output_stream.AppendPrefix(kEncodingContextOpcode);
    281     output_stream.AppendPrefix(kEncodingContextNewMaximumSize);
    282     output_stream.AppendUint32(kDefaultHeaderTableSizeSetting + 1);
    283 
    284     output_stream.TakeString(&input);
    285     EXPECT_FALSE(DecodeHeaderBlock(StringPiece(input)));
    286     EXPECT_EQ(kDefaultHeaderTableSizeSetting,
    287               decoder_peer_.header_table()->max_size());
    288   }
    289 }
    290 
    291 TEST_F(HpackDecoderTest, ContextUpdateClearReferenceSet) {
    292   // Toggle on a couple of headers.
    293   std::map<string, string> header_set1 =
    294       DecodeBlockExpectingSuccess("\x82\x86");
    295   std::map<string, string> expected_header_set1;
    296   expected_header_set1[":method"] = "GET";
    297   expected_header_set1[":path"] = "/index.html";
    298   EXPECT_EQ(expected_header_set1, header_set1);
    299 
    300   // Send a context update to clear the reference set.
    301   std::map<string, string> header_set2 =
    302       DecodeBlockExpectingSuccess("\x30");
    303   std::map<string, string> expected_header_set2;
    304   EXPECT_EQ(expected_header_set2, header_set2);
    305 }
    306 
    307 // Decoding two valid encoded literal headers with no indexing should
    308 // work.
    309 TEST_F(HpackDecoderTest, LiteralHeaderNoIndexing) {
    310   // First header with indexed name, second header with string literal
    311   // name.
    312   const char input[] = "\x04\x0c/sample/path\x00\x06:path2\x0e/sample/path/2";
    313   std::map<string, string> header_set =
    314       DecodeBlockExpectingSuccess(StringPiece(input, arraysize(input) - 1));
    315 
    316   std::map<string, string> expected_header_set;
    317   expected_header_set[":path"] = "/sample/path";
    318   expected_header_set[":path2"] = "/sample/path/2";
    319   EXPECT_EQ(expected_header_set, header_set);
    320 }
    321 
    322 // Decoding two valid encoded literal headers with incremental
    323 // indexing and string literal names should work and add the headers
    324 // to the reference set.
    325 TEST_F(HpackDecoderTest, LiteralHeaderIncrementalIndexing) {
    326   const char input[] = "\x44\x0c/sample/path\x40\x06:path2\x0e/sample/path/2";
    327   std::map<string, string> header_set =
    328       DecodeBlockExpectingSuccess(StringPiece(input, arraysize(input) - 1));
    329 
    330   std::map<string, string> expected_header_set;
    331   expected_header_set[":path"] = "/sample/path";
    332   expected_header_set[":path2"] = "/sample/path/2";
    333   EXPECT_EQ(expected_header_set, header_set);
    334 
    335   // Decoding an empty string should just return the reference set.
    336   std::map<string, string> header_set2 = DecodeBlockExpectingSuccess("");
    337   EXPECT_EQ(expected_header_set, header_set2);
    338 }
    339 
    340 TEST_F(HpackDecoderTest, LiteralHeaderWithIndexingInvalidNameIndex) {
    341   decoder_.ApplyHeaderTableSizeSetting(0);
    342 
    343   // Name is the last static index. Works.
    344   EXPECT_TRUE(DecodeHeaderBlock(StringPiece("\x7d\x03ooo")));
    345   // Name is one beyond the last static index. Fails.
    346   EXPECT_FALSE(DecodeHeaderBlock(StringPiece("\x7e\x03ooo")));
    347 }
    348 
    349 TEST_F(HpackDecoderTest, LiteralHeaderNoIndexingInvalidNameIndex) {
    350   // Name is the last static index. Works.
    351   EXPECT_TRUE(DecodeHeaderBlock(StringPiece("\x0f\x2e\x03ooo")));
    352   // Name is one beyond the last static index. Fails.
    353   EXPECT_FALSE(DecodeHeaderBlock(StringPiece("\x0f\x2f\x03ooo")));
    354 }
    355 
    356 TEST_F(HpackDecoderTest, LiteralHeaderNeverIndexedInvalidNameIndex) {
    357   // Name is the last static index. Works.
    358   EXPECT_TRUE(DecodeHeaderBlock(StringPiece("\x1f\x2e\x03ooo")));
    359   // Name is one beyond the last static index. Fails.
    360   EXPECT_FALSE(DecodeHeaderBlock(StringPiece("\x1f\x2f\x03ooo")));
    361 }
    362 
    363 // Round-tripping the header set from E.2.1 should work.
    364 TEST_F(HpackDecoderTest, BasicE21) {
    365   HpackEncoder encoder(ObtainHpackHuffmanTable());
    366 
    367   std::map<string, string> expected_header_set;
    368   expected_header_set[":method"] = "GET";
    369   expected_header_set[":scheme"] = "http";
    370   expected_header_set[":path"] = "/";
    371   expected_header_set[":authority"] = "www.example.com";
    372 
    373   string encoded_header_set;
    374   EXPECT_TRUE(encoder.EncodeHeaderSet(
    375       expected_header_set, &encoded_header_set));
    376 
    377   EXPECT_TRUE(DecodeHeaderBlock(encoded_header_set));
    378   EXPECT_EQ(expected_header_set, decoded_block());
    379 }
    380 
    381 TEST_F(HpackDecoderTest, SectionD3RequestHuffmanExamples) {
    382   std::map<string, string> header_set;
    383 
    384   // 82                                      | == Indexed - Add ==
    385   //                                         |   idx = 2
    386   //                                         | -> :method: GET
    387   // 87                                      | == Indexed - Add ==
    388   //                                         |   idx = 7
    389   //                                         | -> :scheme: http
    390   // 86                                      | == Indexed - Add ==
    391   //                                         |   idx = 6
    392   //                                         | -> :path: /
    393   // 44                                      | == Literal indexed ==
    394   //                                         |   Indexed name (idx = 4)
    395   //                                         |     :authority
    396   // 8c                                      |   Literal value (len = 15)
    397   //                                         |     Huffman encoded:
    398   // e7cf 9beb e89b 6fb1 6fa9 b6ff           | ......o.o...
    399   //                                         |     Decoded:
    400   //                                         | www.example.com
    401   //                                         | -> :authority: www.example.com
    402   string first = a2b_hex("828786448ce7cf9bebe89b6fb16fa9b6ff");
    403   header_set = DecodeBlockExpectingSuccess(first);
    404 
    405   EXPECT_THAT(header_set, ElementsAre(
    406       Pair(":authority", "www.example.com"),
    407       Pair(":method", "GET"),
    408       Pair(":path", "/"),
    409       Pair(":scheme", "http")));
    410 
    411   expectEntry(1, 57, ":authority", "www.example.com");
    412   expectEntry(2, 38, ":path", "/");
    413   expectEntry(3, 43, ":scheme", "http");
    414   expectEntry(4, 42, ":method", "GET");
    415   expectStaticEntry(5);
    416   EXPECT_EQ(180u, decoder_peer_.header_table()->size());
    417 
    418   // 5c                                      | == Literal indexed ==
    419   //                                         |   Indexed name (idx = 28)
    420   //                                         |     cache-control
    421   // 86                                      |   Literal value (len = 8)
    422   //                                         |     Huffman encoded:
    423   // b9b9 9495 56bf                          | ....V.
    424   //                                         |     Decoded:
    425   //                                         | no-cache
    426   //                                         | -> cache-control: no-cache
    427   string second = a2b_hex("5c86b9b9949556bf");
    428   header_set = DecodeBlockExpectingSuccess(second);
    429 
    430   EXPECT_THAT(header_set, ElementsAre(
    431       Pair(":authority", "www.example.com"),
    432       Pair(":method", "GET"),
    433       Pair(":path", "/"),
    434       Pair(":scheme", "http"),
    435       Pair("cache-control", "no-cache")));
    436 
    437   expectEntry(1, 53, "cache-control", "no-cache");
    438   expectEntry(2, 57, ":authority", "www.example.com");
    439   expectEntry(3, 38, ":path", "/");
    440   expectEntry(4, 43, ":scheme", "http");
    441   expectEntry(5, 42, ":method", "GET");
    442   expectStaticEntry(6);
    443   EXPECT_EQ(233u, decoder_peer_.header_table()->size());
    444 
    445   // 30                                      | == Empty reference set ==
    446   //                                         |   idx = 0
    447   //                                         |   flag = 1
    448   // 85                                      | == Indexed - Add ==
    449   //                                         |   idx = 5
    450   //                                         | -> :method: GET
    451   // 8c                                      | == Indexed - Add ==
    452   //                                         |   idx = 12
    453   //                                         | -> :scheme: https
    454   // 8b                                      | == Indexed - Add ==
    455   //                                         |   idx = 11
    456   //                                         | -> :path: /index.html
    457   // 84                                      | == Indexed - Add ==
    458   //                                         |   idx = 4
    459   //                                         | -> :authority: www.example.com
    460   // 40                                      | == Literal indexed ==
    461   // 88                                      |   Literal name (len = 10)
    462   //                                         |     Huffman encoded:
    463   // 571c 5cdb 737b 2faf                     | W.\.s{/.
    464   //                                         |     Decoded:
    465   //                                         | custom-key
    466   // 89                                      |   Literal value (len = 12)
    467   //                                         |     Huffman encoded:
    468   // 571c 5cdb 7372 4d9c 57                  | W.\.srM.W
    469   //                                         |     Decoded:
    470   //                                         | custom-value
    471   //                                         | -> custom-key: custom-value
    472   string third = a2b_hex("30858c8b844088571c5cdb737b2faf89"
    473                          "571c5cdb73724d9c57");
    474   header_set = DecodeBlockExpectingSuccess(third);
    475 
    476   EXPECT_THAT(header_set, ElementsAre(
    477       Pair(":authority", "www.example.com"),
    478       Pair(":method", "GET"),
    479       Pair(":path", "/index.html"),
    480       Pair(":scheme", "https"),
    481       Pair("custom-key", "custom-value")));
    482 
    483   expectEntry(1, 54, "custom-key", "custom-value");
    484   expectEntry(2, 48, ":path", "/index.html");
    485   expectEntry(3, 44, ":scheme", "https");
    486   expectEntry(4, 53, "cache-control", "no-cache");
    487   expectEntry(5, 57, ":authority", "www.example.com");
    488   expectEntry(6, 38, ":path", "/");
    489   expectEntry(7, 43, ":scheme", "http");
    490   expectEntry(8, 42, ":method", "GET");
    491   expectStaticEntry(9);
    492   EXPECT_EQ(379u, decoder_peer_.header_table()->size());
    493 }
    494 
    495 TEST_F(HpackDecoderTest, SectionD5ResponseHuffmanExamples) {
    496   std::map<string, string> header_set;
    497   decoder_.ApplyHeaderTableSizeSetting(256);
    498 
    499   // 48                                      | == Literal indexed ==
    500   //                                         |   Indexed name (idx = 8)
    501   //                                         |     :status
    502   // 82                                      |   Literal value (len = 3)
    503   //                                         |     Huffman encoded:
    504   // 4017                                    | @.
    505   //                                         |     Decoded:
    506   //                                         | 302
    507   //                                         | -> :status: 302
    508   // 59                                      | == Literal indexed ==
    509   //                                         |   Indexed name (idx = 25)
    510   //                                         |     cache-control
    511   // 85                                      |   Literal value (len = 7)
    512   //                                         |     Huffman encoded:
    513   // bf06 724b 97                            | ..rK.
    514   //                                         |     Decoded:
    515   //                                         | private
    516   //                                         | -> cache-control: private
    517   // 63                                      | == Literal indexed ==
    518   //                                         |   Indexed name (idx = 35)
    519   //                                         |     date
    520   // 93                                      |   Literal value (len = 29)
    521   //                                         |     Huffman encoded:
    522   // d6db b298 84de 2a71 8805 0620 9851 3109 | ......*q... .Q1.
    523   // b56b a3                                 | .k.
    524   //                                         |     Decoded:
    525   //                                         | Mon, 21 Oct 2013 20:13:21
    526   //                                         | GMT
    527   //                                         | -> date: Mon, 21 Oct 2013
    528   //                                         |   20:13:21 GMT
    529   // 71                                      | == Literal indexed ==
    530   //                                         |   Indexed name (idx = 49)
    531   //                                         |     location
    532   // 91                                      |   Literal value (len = 23)
    533   //                                         |     Huffman encoded:
    534   // adce bf19 8e7e 7cf9 bebe 89b6 fb16 fa9b | ......|.........
    535   // 6f                                      | o
    536   //                                         |     Decoded:
    537   //                                         | https://www.example.com
    538   //                                         | -> location: https://www.e
    539   //                                         |    xample.com
    540   string first = a2b_hex("488240175985bf06724b976393d6dbb2"
    541                          "9884de2a718805062098513109b56ba3"
    542                          "7191adcebf198e7e7cf9bebe89b6fb16"
    543                          "fa9b6f");
    544   header_set = DecodeBlockExpectingSuccess(first);
    545 
    546   EXPECT_THAT(header_set, ElementsAre(
    547       Pair(":status", "302"),
    548       Pair("cache-control", "private"),
    549       Pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"),
    550       Pair("location", "https://www.example.com")));
    551 
    552   expectEntry(1, 63, "location", "https://www.example.com");
    553   expectEntry(2, 65, "date", "Mon, 21 Oct 2013 20:13:21 GMT");
    554   expectEntry(3, 52, "cache-control", "private");
    555   expectEntry(4, 42, ":status", "302");
    556   expectStaticEntry(5);
    557   EXPECT_EQ(222u, decoder_peer_.header_table()->size());
    558 
    559   // 8c                                      | == Indexed - Add ==
    560   //                                         |   idx = 12
    561   //                                         | - evict: :status: 302
    562   //                                         | -> :status: 200
    563   string second = a2b_hex("8c");
    564   header_set = DecodeBlockExpectingSuccess(second);
    565 
    566   EXPECT_THAT(header_set, ElementsAre(
    567       Pair(":status", "200"),
    568       Pair("cache-control", "private"),
    569       Pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"),
    570       Pair("location", "https://www.example.com")));
    571 
    572   expectEntry(1, 42, ":status", "200");
    573   expectEntry(2, 63, "location", "https://www.example.com");
    574   expectEntry(3, 65, "date", "Mon, 21 Oct 2013 20:13:21 GMT");
    575   expectEntry(4, 52, "cache-control", "private");
    576   expectStaticEntry(5);
    577   EXPECT_EQ(222u, decoder_peer_.header_table()->size());
    578 
    579   // 84                                      | == Indexed - Remove ==
    580   //                                         |   idx = 4
    581   //                                         | -> cache-control: private
    582   // 84                                      | == Indexed - Add ==
    583   //                                         |   idx = 4
    584   //                                         | -> cache-control: private
    585   // 43                                      | == Literal indexed ==
    586   //                                         |   Indexed name (idx = 3)
    587   //                                         |     date
    588   // 93                                      |   Literal value (len = 29)
    589   //                                         |     Huffman encoded:
    590   // d6db b298 84de 2a71 8805 0620 9851 3111 | ......*q... .Q1.
    591   // b56b a3                                 | .k.
    592   //                                         |     Decoded:
    593   //                                         | Mon, 21 Oct 2013 20:13:22
    594   //                                         | GMT
    595   //                                         | - evict: cache-control: pr
    596   //                                         |   ivate
    597   //                                         | -> date: Mon, 21 Oct 2013
    598   //                                         |   20:13:22 GMT
    599   // 5e                                      | == Literal indexed ==
    600   //                                         |   Indexed name (idx = 30)
    601   //                                         |     content-encoding
    602   // 84                                      |   Literal value (len = 4)
    603   //                                         |     Huffman encoded:
    604   // abdd 97ff                               | ....
    605   //                                         |     Decoded:
    606   //                                         | gzip
    607   //                                         | - evict: date: Mon, 21 Oct
    608   //                                         |    2013 20:13:21 GMT
    609   //                                         | -> content-encoding: gzip
    610   // 84                                      | == Indexed - Remove ==
    611   //                                         |   idx = 4
    612   //                                         | -> location: https://www.e
    613   //                                         |   xample.com
    614   // 84                                      | == Indexed - Add ==
    615   //                                         |   idx = 4
    616   //                                         | -> location: https://www.e
    617   //                                         |   xample.com
    618   // 83                                      | == Indexed - Remove ==
    619   //                                         |   idx = 3
    620   //                                         | -> :status: 200
    621   // 83                                      | == Indexed - Add ==
    622   //                                         |   idx = 3
    623   //                                         | -> :status: 200
    624   // 7b                                      | == Literal indexed ==
    625   //                                         |   Indexed name (idx = 59)
    626   //                                         |     set-cookie
    627   // b1                                      |   Literal value (len = 56)
    628   //                                         |     Huffman encoded:
    629   // e0d6 cf9f 6e8f 9fd3 e5f6 fa76 fefd 3c7e | ....n......v....
    630   // df9e ff1f 2f0f 3cfe 9f6f cf7f 8f87 9f61 | ..../....o.....a
    631   // ad4f 4cc9 a973 a220 0ec3 725e 18b1 b74e | .OL..s. ..r^...N
    632   // 3f                                      | ?
    633   //                                         |     Decoded:
    634   //                                         | foo=ASDJKHQKBZXOQWEOPIUAXQ
    635   //                                         | WEOIU; max-age=3600; versi
    636   //                                         | on=1
    637   //                                         | - evict: location: https:/
    638   //                                         |   /www.example.com
    639   //                                         | - evict: :status: 200
    640   //                                         | -> set-cookie: foo=ASDJKHQ
    641   //                                         |   KBZXOQWEOPIUAXQWEOIU; ma
    642   //                                         |   x-age=3600; version=1
    643   string third = a2b_hex("84844393d6dbb29884de2a7188050620"
    644                          "98513111b56ba35e84abdd97ff848483"
    645                          "837bb1e0d6cf9f6e8f9fd3e5f6fa76fe"
    646                          "fd3c7edf9eff1f2f0f3cfe9f6fcf7f8f"
    647                          "879f61ad4f4cc9a973a2200ec3725e18"
    648                          "b1b74e3f");
    649   header_set = DecodeBlockExpectingSuccess(third);
    650 
    651   EXPECT_THAT(header_set, ElementsAre(
    652       Pair(":status", "200"),
    653       Pair("cache-control", "private"),
    654       Pair("content-encoding", "gzip"),
    655       Pair("date", "Mon, 21 Oct 2013 20:13:22 GMT"),
    656       Pair("location", "https://www.example.com"),
    657       Pair("set-cookie", "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU;"
    658            " max-age=3600; version=1")));
    659 
    660   expectEntry(1, 98, "set-cookie", "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU;"
    661               " max-age=3600; version=1");
    662   expectEntry(2, 52, "content-encoding", "gzip");
    663   expectEntry(3, 65, "date", "Mon, 21 Oct 2013 20:13:22 GMT");
    664   expectStaticEntry(4);
    665   EXPECT_EQ(215u, decoder_peer_.header_table()->size());
    666 }
    667 
    668 }  // namespace
    669 
    670 }  // namespace net
    671