Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / net / spdy / hpack_decoder_test.cc
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 "testing/gmock/include/gmock/gmock.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18
19 namespace net {
20
21 namespace test {
22
23 using base::StringPiece;
24 using std::string;
25
26 class HpackDecoderPeer {
27  public:
28   explicit HpackDecoderPeer(HpackDecoder* decoder)
29       : decoder_(decoder) {}
30
31   void HandleHeaderRepresentation(StringPiece name, StringPiece value) {
32     decoder_->HandleHeaderRepresentation(name, value);
33   }
34   bool DecodeNextName(HpackInputStream* in, StringPiece* out) {
35     return decoder_->DecodeNextName(in, out);
36   }
37   const HpackHeaderTable& header_table() {
38     return decoder_->header_table_;
39   }
40   void set_cookie_name(string name) {
41     decoder_->cookie_name_ = name;
42   }
43   string cookie_name() {
44     return decoder_->cookie_name_;
45   }
46   void set_cookie_value(string value) {
47     decoder_->cookie_value_ = value;
48   }
49   string cookie_value() {
50     return decoder_->cookie_value_;
51   }
52   const std::map<string, string>& decoded_block() const {
53     return decoder_->decoded_block_;
54   }
55   const string& headers_block_buffer() const {
56     return decoder_->headers_block_buffer_;
57   }
58
59  private:
60   HpackDecoder* decoder_;
61 };
62
63 }  // namespace test
64
65 namespace {
66
67 using base::StringPiece;
68 using std::string;
69
70 using testing::ElementsAre;
71 using testing::Pair;
72
73 const size_t kLiteralBound = 1024;
74
75 class HpackDecoderTest : public ::testing::Test {
76  protected:
77   HpackDecoderTest()
78       : decoder_(ObtainHpackHuffmanTable()),
79         decoder_peer_(&decoder_) {}
80
81   bool DecodeHeaderBlock(StringPiece str) {
82     return decoder_.HandleControlFrameHeadersData(0, str.data(), str.size()) &&
83         decoder_.HandleControlFrameHeadersComplete(0);
84   }
85   const std::map<string, string>& decoded_block() const {
86     // TODO(jgraettinger): HpackDecoderTest should implement
87     // SpdyHeadersHandlerInterface, and collect headers for examination.
88     return decoder_peer_.decoded_block();
89   }
90   // TODO(jgraettinger): Eliminate uses of this in tests below. Prefer
91   // DecodeHeaderBlock().
92   const std::map<string, string>& DecodeUniqueHeaderSet(StringPiece str) {
93     EXPECT_TRUE(DecodeHeaderBlock(str));
94     return decoded_block();
95   }
96
97   HpackDecoder decoder_;
98   test::HpackDecoderPeer decoder_peer_;
99 };
100
101 TEST_F(HpackDecoderTest, HandleControlFrameHeadersData) {
102   // Strings under threshold are concatenated in the buffer.
103   EXPECT_TRUE(decoder_.HandleControlFrameHeadersData(
104       0, "small string one", 16));
105   EXPECT_TRUE(decoder_.HandleControlFrameHeadersData(
106       0, "small string two", 16));
107   // A string which would push the buffer over the threshold is refused.
108   EXPECT_FALSE(decoder_.HandleControlFrameHeadersData(
109       0, "fails", kMaxDecodeBufferSize - 32 + 1));
110
111   EXPECT_EQ(decoder_peer_.headers_block_buffer(),
112             "small string onesmall string two");
113 }
114
115 TEST_F(HpackDecoderTest, HandleControlFrameHeadersComplete) {
116   // Decode a block which toggles two static headers into the reference set.
117   EXPECT_TRUE(DecodeHeaderBlock("\x82\x86"));
118
119   decoder_peer_.set_cookie_name("CooKie");
120   decoder_peer_.set_cookie_value("foobar=baz");
121
122   // Headers in the reference set should be emitted.
123   // Incremental cookie buffer should be emitted and cleared.
124   decoder_.HandleControlFrameHeadersData(0, NULL, 0);
125   decoder_.HandleControlFrameHeadersComplete(0);
126
127   EXPECT_THAT(decoded_block(), ElementsAre(
128       Pair(":method", "GET"),
129       Pair(":path", "/index.html"),
130       Pair("CooKie", "foobar=baz")));
131
132   EXPECT_EQ(decoder_peer_.cookie_name(), "");
133   EXPECT_EQ(decoder_peer_.cookie_value(), "");
134 }
135
136 TEST_F(HpackDecoderTest, HandleHeaderRepresentation) {
137   // Casing of first Cookie is retained, but all instances are joined.
138   decoder_peer_.HandleHeaderRepresentation("cOOkie", " part 1");
139   decoder_peer_.HandleHeaderRepresentation("cookie", "part 2 ");
140   decoder_peer_.HandleHeaderRepresentation("cookie", "part3");
141
142   // Already-delimited headers are passed through.
143   decoder_peer_.HandleHeaderRepresentation("passed-through",
144                                            string("foo\0baz", 7));
145
146   // Other headers are joined on \0. Case matters.
147   decoder_peer_.HandleHeaderRepresentation("joined", "not joined");
148   decoder_peer_.HandleHeaderRepresentation("joineD", "value 1");
149   decoder_peer_.HandleHeaderRepresentation("joineD", "value 2");
150
151   // Empty headers remain empty.
152   decoder_peer_.HandleHeaderRepresentation("empty", "");
153
154   // Joined empty headers work as expected.
155   decoder_peer_.HandleHeaderRepresentation("empty-joined", "");
156   decoder_peer_.HandleHeaderRepresentation("empty-joined", "foo");
157   decoder_peer_.HandleHeaderRepresentation("empty-joined", "");
158   decoder_peer_.HandleHeaderRepresentation("empty-joined", "");
159
160   // Non-contiguous cookie crumb.
161   decoder_peer_.HandleHeaderRepresentation("Cookie", " fin!");
162
163   // Finish and emit all headers.
164   decoder_.HandleControlFrameHeadersComplete(0);
165
166   EXPECT_THAT(decoded_block(), ElementsAre(
167       Pair("cOOkie", " part 1; part 2 ; part3;  fin!"),
168       Pair("empty", ""),
169       Pair("empty-joined", string("\0foo\0\0", 6)),
170       Pair("joineD", string("value 1\0value 2", 15)),
171       Pair("joined", "not joined"),
172       Pair("passed-through", string("foo\0baz", 7))));
173 }
174
175 // Decoding an encoded name with a valid string literal should work.
176 TEST_F(HpackDecoderTest, DecodeNextNameLiteral) {
177   HpackInputStream input_stream(kLiteralBound, StringPiece("\x00\x04name", 6));
178
179   StringPiece string_piece;
180   EXPECT_TRUE(decoder_peer_.DecodeNextName(&input_stream, &string_piece));
181   EXPECT_EQ("name", string_piece);
182   EXPECT_FALSE(input_stream.HasMoreData());
183 }
184
185 TEST_F(HpackDecoderTest, DecodeNextNameLiteralWithHuffmanEncoding) {
186   char input[] = "\x00\x88\x4e\xb0\x8b\x74\x97\x90\xfa\x7f";
187   StringPiece foo(input, arraysize(input) - 1);
188   HpackInputStream input_stream(kLiteralBound, foo);
189
190   StringPiece string_piece;
191   EXPECT_TRUE(decoder_peer_.DecodeNextName(&input_stream, &string_piece));
192   EXPECT_EQ("custom-key", string_piece);
193   EXPECT_FALSE(input_stream.HasMoreData());
194 }
195
196 // Decoding an encoded name with a valid index should work.
197 TEST_F(HpackDecoderTest, DecodeNextNameIndexed) {
198   HpackInputStream input_stream(kLiteralBound, "\x01");
199
200   StringPiece string_piece;
201   EXPECT_TRUE(decoder_peer_.DecodeNextName(&input_stream, &string_piece));
202   EXPECT_EQ(":authority", string_piece);
203   EXPECT_FALSE(input_stream.HasMoreData());
204 }
205
206 // Decoding an encoded name with an invalid index should fail.
207 TEST_F(HpackDecoderTest, DecodeNextNameInvalidIndex) {
208   // One more than the number of static table entries.
209   HpackInputStream input_stream(kLiteralBound, "\x3d");
210
211   StringPiece string_piece;
212   EXPECT_FALSE(decoder_peer_.DecodeNextName(&input_stream, &string_piece));
213 }
214
215 // Decoding an indexed header should toggle the index's presence in
216 // the reference set, making a copy of static table entries if
217 // necessary. It should also emit the header if toggled on (and only
218 // as many times as it was toggled on).
219 TEST_F(HpackDecoderTest, IndexedHeaderBasic) {
220   // Toggle on static table entry #2 (and make a copy at index #1),
221   // then toggle on static table entry #5 (which is now #6 because of
222   // the copy of #2).
223   std::map<string, string> header_set1 =
224       DecodeUniqueHeaderSet("\x82\x86");
225   std::map<string, string> expected_header_set1;
226   expected_header_set1[":method"] = "GET";
227   expected_header_set1[":path"] = "/index.html";
228   EXPECT_EQ(expected_header_set1, header_set1);
229
230   std::map<string, string> expected_header_set2;
231   expected_header_set2[":path"] = "/index.html";
232   // Toggle off the copy of static table entry #5.
233   std::map<string, string> header_set2 =
234       DecodeUniqueHeaderSet("\x82");
235   EXPECT_EQ(expected_header_set2, header_set2);
236 }
237
238 // Test a too-large indexed header.
239 TEST_F(HpackDecoderTest, InvalidIndexedHeader) {
240   // High-bit set, and a prefix of one more than the number of static entries.
241   EXPECT_FALSE(DecodeHeaderBlock(StringPiece("\xbd", 1)));
242 }
243
244 TEST_F(HpackDecoderTest, ContextUpdateMaximumSize) {
245   EXPECT_EQ(kDefaultHeaderTableSizeSetting,
246             decoder_peer_.header_table().max_size());
247   {
248     // Maximum-size update with size 126. Succeeds.
249     EXPECT_TRUE(DecodeHeaderBlock(StringPiece("\x80\x7e", 2)));
250     EXPECT_EQ(126u, decoder_peer_.header_table().max_size());
251   }
252   string input;
253   {
254     // Maximum-size update with kDefaultHeaderTableSizeSetting. Succeeds.
255     HpackOutputStream output_stream;
256     output_stream.AppendBits(0x80, 8);  // Context update.
257     output_stream.AppendBits(0x00, 1);  // Size update.
258     output_stream.AppendUint32(kDefaultHeaderTableSizeSetting);
259
260     output_stream.TakeString(&input);
261     EXPECT_TRUE(DecodeHeaderBlock(StringPiece(input)));
262     EXPECT_EQ(kDefaultHeaderTableSizeSetting,
263               decoder_peer_.header_table().max_size());
264   }
265   {
266     // Maximum-size update with kDefaultHeaderTableSizeSetting + 1. Fails.
267     HpackOutputStream output_stream;
268     output_stream.AppendBits(0x80, 8);  // Context update.
269     output_stream.AppendBits(0x00, 1);  // Size update.
270     output_stream.AppendUint32(kDefaultHeaderTableSizeSetting + 1);
271
272     output_stream.TakeString(&input);
273     EXPECT_FALSE(DecodeHeaderBlock(StringPiece(input)));
274     EXPECT_EQ(kDefaultHeaderTableSizeSetting,
275               decoder_peer_.header_table().max_size());
276   }
277 }
278
279 TEST_F(HpackDecoderTest, ContextUpdateClearReferenceSet) {
280   // Toggle on a couple of headers.
281   std::map<string, string> header_set1 =
282       DecodeUniqueHeaderSet("\x82\x86");
283   std::map<string, string> expected_header_set1;
284   expected_header_set1[":method"] = "GET";
285   expected_header_set1[":path"] = "/index.html";
286   EXPECT_EQ(expected_header_set1, header_set1);
287
288   // Send a context update to clear the reference set.
289   std::map<string, string> header_set2 =
290       DecodeUniqueHeaderSet("\x80\x80");
291   std::map<string, string> expected_header_set2;
292   EXPECT_EQ(expected_header_set2, header_set2);
293 }
294
295 // Decoding two valid encoded literal headers with no indexing should
296 // work.
297 TEST_F(HpackDecoderTest, LiteralHeaderNoIndexing) {
298   // First header with indexed name, second header with string literal
299   // name.
300   std::map<string, string> header_set =
301       DecodeUniqueHeaderSet(
302           "\x44\x0c/sample/path\x40\x06:path2\x0e/sample/path/2");
303
304   std::map<string, string> expected_header_set;
305   expected_header_set[":path"] = "/sample/path";
306   expected_header_set[":path2"] = "/sample/path/2";
307   EXPECT_EQ(expected_header_set, header_set);
308 }
309
310 // Decoding two valid encoded literal headers with incremental
311 // indexing and string literal names should work and add the headers
312 // to the reference set.
313 TEST_F(HpackDecoderTest, LiteralHeaderIncrementalIndexing) {
314   std::map<string, string> header_set = DecodeUniqueHeaderSet(
315       StringPiece("\x04\x0c/sample/path\x00\x06:path2\x0e/sample/path/2", 37));
316
317   std::map<string, string> expected_header_set;
318   expected_header_set[":path"] = "/sample/path";
319   expected_header_set[":path2"] = "/sample/path/2";
320   EXPECT_EQ(expected_header_set, header_set);
321
322   // Decoding an empty string should just return the reference set.
323   std::map<string, string> header_set2 = DecodeUniqueHeaderSet("");
324   EXPECT_EQ(expected_header_set, header_set2);
325 }
326
327 // Decoding literal headers with invalid indices should fail
328 // gracefully.
329 TEST_F(HpackDecoderTest, LiteralHeaderInvalidIndices) {
330   // No indexing.
331
332   // One more than the number of static table entries.
333   EXPECT_FALSE(DecodeHeaderBlock(StringPiece("\x7d", 1)));
334   EXPECT_FALSE(DecodeHeaderBlock(StringPiece("\x40", 1)));
335
336   // Incremental indexing.
337
338   // One more than the number of static table entries.
339   EXPECT_FALSE(DecodeHeaderBlock(StringPiece("\x3d", 1)));
340   EXPECT_FALSE(DecodeHeaderBlock(StringPiece("\x00", 1)));
341 }
342
343 // Round-tripping the header set from E.2.1 should work.
344 TEST_F(HpackDecoderTest, BasicE21) {
345   HpackEncoder encoder(ObtainHpackHuffmanTable());
346
347   std::map<string, string> expected_header_set;
348   expected_header_set[":method"] = "GET";
349   expected_header_set[":scheme"] = "http";
350   expected_header_set[":path"] = "/";
351   expected_header_set[":authority"] = "www.example.com";
352
353   string encoded_header_set;
354   EXPECT_TRUE(encoder.EncodeHeaderSet(
355       expected_header_set, &encoded_header_set));
356
357   EXPECT_TRUE(DecodeHeaderBlock(encoded_header_set));
358   EXPECT_EQ(expected_header_set, decoded_block());
359 }
360
361 TEST_F(HpackDecoderTest, SectionD3RequestHuffmanExamples) {
362   std::map<string, string> header_set;
363
364   // 82                                      | == Indexed - Add ==
365   //                                         |   idx = 2
366   //                                         | -> :method: GET
367   // 87                                      | == Indexed - Add ==
368   //                                         |   idx = 7
369   //                                         | -> :scheme: http
370   // 86                                      | == Indexed - Add ==
371   //                                         |   idx = 6
372   //                                         | -> :path: /
373   // 04                                      | == Literal indexed ==
374   //                                         |   Indexed name (idx = 4)
375   //                                         |     :authority
376   // 8b                                      |   Literal value (len = 15)
377   //                                         |     Huffman encoded:
378   // db6d 883e 68d1 cb12 25ba 7f             | .m..h...%..
379   //                                         |     Decoded:
380   //                                         | www.example.com
381   //                                         | -> :authority: www.example.com
382   char first[] =
383       "\x82\x87\x86\x04\x8b\xdb\x6d\x88\x3e\x68\xd1\xcb\x12\x25\xba\x7f";
384   header_set = DecodeUniqueHeaderSet(StringPiece(first, arraysize(first)-1));
385
386   // TODO(jgraettinger): Create HpackEncodingContext and
387   // HpackDecoder peers, and inspect the header table here.
388   EXPECT_THAT(header_set, ElementsAre(
389       Pair(":authority", "www.example.com"),
390       Pair(":method", "GET"),
391       Pair(":path", "/"),
392       Pair(":scheme", "http")));
393
394   // 1b                                      | == Literal indexed ==
395   //                                         |   Indexed name (idx = 27)
396   //                                         |     cache-control
397   // 86                                      |   Literal value (len = 8)
398   //                                         |     Huffman encoded:
399   // 6365 4a13 98ff                          | ceJ...
400   //                                         |     Decoded:
401   //                                         | no-cache
402   //                                         | -> cache-control: no-cache
403   char second[] = "\x1b\x86\x63\x65\x4a\x13\x98\xff";
404   header_set = DecodeUniqueHeaderSet(StringPiece(second, arraysize(second)-1));
405
406   EXPECT_THAT(header_set, ElementsAre(
407       Pair(":authority", "www.example.com"),
408       Pair(":method", "GET"),
409       Pair(":path", "/"),
410       Pair(":scheme", "http"),
411       Pair("cache-control", "no-cache")));
412
413   // 8080                                    | == Empty reference set ==
414   //                                         |   idx = 0
415   //                                         |   flag = 1
416   // 85                                      | == Indexed - Add ==
417   //                                         |   idx = 5
418   //                                         | -> :method: GET
419   // 8c                                      | == Indexed - Add ==
420   //                                         |   idx = 12
421   //                                         | -> :scheme: https
422   // 8b                                      | == Indexed - Add ==
423   //                                         |   idx = 11
424   //                                         | -> :path: /index.html
425   // 84                                      | == Indexed - Add ==
426   //                                         |   idx = 4
427   //                                         | -> :authority: www.example.com
428   // 00                                      | == Literal indexed ==
429   // 88                                      |   Literal name (len = 10)
430   //                                         |     Huffman encoded:
431   // 4eb0 8b74 9790 fa7f                     | N..t....
432   //                                         |     Decoded:
433   //                                         | custom-key
434   // 89                                      |   Literal value (len = 12)
435   //                                         |     Huffman encoded:
436   // 4eb0 8b74 979a 17a8 ff                  | N..t.....
437   //                                         |     Decoded:
438   //                                         | custom-value
439   //                                         | -> custom-key: custom-value
440   char third[] =
441       "\x80\x80\x85\x8c\x8b\x84\x00\x88\x4e\xb0\x8b\x74\x97\x90\xfa\x7f\x89"
442       "\x4e\xb0\x8b\x74\x97\x9a\x17\xa8\xff";
443   header_set = DecodeUniqueHeaderSet(StringPiece(third, arraysize(third)-1));
444
445   EXPECT_THAT(header_set, ElementsAre(
446       Pair(":authority", "www.example.com"),
447       Pair(":method", "GET"),
448       Pair(":path", "/index.html"),
449       Pair(":scheme", "https"),
450       Pair("custom-key", "custom-value")));
451 }
452
453 TEST_F(HpackDecoderTest, SectionD5ResponseHuffmanExamples) {
454   std::map<string, string> header_set;
455   decoder_.ApplyHeaderTableSizeSetting(256);
456
457   // 08                                      | == Literal indexed ==
458   //                                         |   Indexed name (idx = 8)
459   //                                         |     :status
460   // 82                                      |   Literal value (len = 3)
461   //                                         |     Huffman encoded:
462   // 98a7                                    | ..
463   //                                         |     Decoded:
464   //                                         | 302
465   //                                         | -> :status: 302
466   // 18                                      | == Literal indexed ==
467   //                                         |   Indexed name (idx = 24)
468   //                                         |     cache-control
469   // 85                                      |   Literal value (len = 7)
470   //                                         |     Huffman encoded:
471   // 73d5 cd11 1f                            | s....
472   //                                         |     Decoded:
473   //                                         | private
474   //                                         | -> cache-control: private
475   // 22                                      | == Literal indexed ==
476   //                                         |   Indexed name (idx = 34)
477   //                                         |     date
478   // 98                                      |   Literal value (len = 29)
479   //                                         |     Huffman encoded:
480   // ef6b 3a7a 0e6e 8fa2 63d0 729a 6e83 97d8 | .k:z.n..c.r.n...
481   // 69bd 8737 47bb bfc7                     | i..7G...
482   //                                         |     Decoded:
483   //                                         | Mon, 21 Oct 2013 20:13:21
484   //                                         | GMT
485   //                                         | -> date: Mon, 21 Oct 2013
486   //                                         |   20:13:21 GMT
487   // 30                                      | == Literal indexed ==
488   //                                         |   Indexed name (idx = 48)
489   //                                         |     location
490   // 90                                      |   Literal value (len = 23)
491   //                                         |     Huffman encoded:
492   // ce31 743d 801b 6db1 07cd 1a39 6244 b74f | .1t=..m....9bD.O
493   //                                         |     Decoded:
494   //                                         | https://www.example.com
495   //                                         | -> location: https://www.e
496   //                                         |    xample.com
497   char first[] =
498       "\x08\x82\x98\xa7\x18\x85\x73\xd5\xcd\x11\x1f\x22\x98\xef\x6b"
499       "\x3a\x7a\x0e\x6e\x8f\xa2\x63\xd0\x72\x9a\x6e\x83\x97\xd8\x69\xbd\x87"
500       "\x37\x47\xbb\xbf\xc7\x30\x90\xce\x31\x74\x3d\x80\x1b\x6d\xb1\x07\xcd"
501       "\x1a\x39\x62\x44\xb7\x4f";
502   header_set = DecodeUniqueHeaderSet(StringPiece(first, arraysize(first)-1));
503
504   EXPECT_THAT(header_set, ElementsAre(
505       Pair(":status", "302"),
506       Pair("cache-control", "private"),
507       Pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"),
508       Pair("location", "https://www.example.com")));
509
510   // 8c                                      | == Indexed - Add ==
511   //                                         |   idx = 12
512   //                                         | - evict: :status: 302
513   //                                         | -> :status: 200
514   char second[] = "\x8c";
515   header_set = DecodeUniqueHeaderSet(StringPiece(second, arraysize(second)-1));
516
517   EXPECT_THAT(header_set, ElementsAre(
518       Pair(":status", "200"),
519       Pair("cache-control", "private"),
520       Pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"),
521       Pair("location", "https://www.example.com")));
522
523   // 84                                      | == Indexed - Remove ==
524   //                                         |   idx = 4
525   //                                         | -> cache-control: private
526   // 84                                      | == Indexed - Add ==
527   //                                         |   idx = 4
528   //                                         | -> cache-control: private
529   // 03                                      | == Literal indexed ==
530   //                                         |   Indexed name (idx = 3)
531   //                                         |     date
532   // 98                                      |   Literal value (len = 29)
533   //                                         |     Huffman encoded:
534   // ef6b 3a7a 0e6e 8fa2 63d0 729a 6e83 97d8 | .k:z.n..c.r.n...
535   // 69bd 873f 47bb bfc7                     | i..?G...
536   //                                         |     Decoded:
537   //                                         | Mon, 21 Oct 2013 20:13:22
538   //                                         | GMT
539   //                                         | - evict: cache-control: pr
540   //                                         |   ivate
541   //                                         | -> date: Mon, 21 Oct 2013
542   //                                         |   20:13:22 GMT
543   // 1d                                      | == Literal indexed ==
544   //                                         |   Indexed name (idx = 29)
545   //                                         |     content-encoding
546   // 83                                      |   Literal value (len = 4)
547   //                                         |     Huffman encoded:
548   // cbd5 4e                                 | ..N
549   //                                         |     Decoded:
550   //                                         | gzip
551   //                                         | - evict: date: Mon, 21 Oct
552   //                                         |    2013 20:13:21 GMT
553   //                                         | -> content-encoding: gzip
554   // 84                                      | == Indexed - Remove ==
555   //                                         |   idx = 4
556   //                                         | -> location: https://www.e
557   //                                         |   xample.com
558   // 84                                      | == Indexed - Add ==
559   //                                         |   idx = 4
560   //                                         | -> location: https://www.e
561   //                                         |   xample.com
562   // 83                                      | == Indexed - Remove ==
563   //                                         |   idx = 3
564   //                                         | -> :status: 200
565   // 83                                      | == Indexed - Add ==
566   //                                         |   idx = 3
567   //                                         | -> :status: 200
568   // 3a                                      | == Literal indexed ==
569   //                                         |   Indexed name (idx = 58)
570   //                                         |     set-cookie
571   // b3                                      |   Literal value (len = 56)
572   //                                         |     Huffman encoded:
573   // c5ad b77f 876f c7fb f7fd bfbe bff3 f7f4 | .....o..........
574   // fb7e bbbe 9f5f 87e3 7fef edfa eefa 7c3f | ....._........|?
575   // 1d5d 1a23 ce54 6436 cd49 4bd5 d1cc 5f05 | .].#.Td6.IK..._.
576   // 3596 9b                                 | 5..
577   //                                         |     Decoded:
578   //                                         | foo=ASDJKHQKBZXOQWEOPIUAXQ
579   //                                         | WEOIU; max-age=3600; versi
580   //                                         | on=1
581   //                                         | - evict: location: https:/
582   //                                         |   /www.example.com
583   //                                         | - evict: :status: 200
584   //                                         | -> set-cookie: foo=ASDJKHQ
585   //                                         |   KBZXOQWEOPIUAXQWEOIU; ma
586   //                                         |   x-age=3600; version=1
587   char third[] =
588       "\x84\x84\x03\x98\xef\x6b\x3a\x7a\x0e\x6e\x8f\xa2\x63\xd0\x72"
589       "\x9a\x6e\x83\x97\xd8\x69\xbd\x87\x3f\x47\xbb\xbf\xc7\x1d\x83\xcb\xd5"
590       "\x4e\x84\x84\x83\x83\x3a\xb3\xc5\xad\xb7\x7f\x87\x6f\xc7\xfb\xf7\xfd"
591       "\xbf\xbe\xbf\xf3\xf7\xf4\xfb\x7e\xbb\xbe\x9f\x5f\x87\xe3\x7f\xef\xed"
592       "\xfa\xee\xfa\x7c\x3f\x1d\x5d\x1a\x23\xce\x54\x64\x36\xcd\x49\x4b\xd5"
593       "\xd1\xcc\x5f\x05\x35\x96\x9b";
594   header_set = DecodeUniqueHeaderSet(StringPiece(third, arraysize(third)-1));
595
596   EXPECT_THAT(header_set, ElementsAre(
597       Pair(":status", "200"),
598       Pair("cache-control", "private"),
599       Pair("content-encoding", "gzip"),
600       Pair("date", "Mon, 21 Oct 2013 20:13:22 GMT"),
601       Pair("location", "https://www.example.com"),
602       Pair("set-cookie", "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU;"
603            " max-age=3600; version=1")));
604 }
605
606 }  // namespace
607
608 }  // namespace net