Move HPACK implementation to net/spdy/hpack directory.
[chromium-blink-merge.git] / net / spdy / hpack / hpack_decoder_test.cc
blobb20a9b27a9af53dcb09196ebc250f6f72be6aa79
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.
5 #include "net/spdy/hpack/hpack_decoder.h"
7 #include <map>
8 #include <string>
10 #include "base/basictypes.h"
11 #include "base/logging.h"
12 #include "base/strings/string_piece.h"
13 #include "net/spdy/hpack/hpack_encoder.h"
14 #include "net/spdy/hpack/hpack_input_stream.h"
15 #include "net/spdy/hpack/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"
20 namespace net {
22 namespace test {
24 using base::StringPiece;
25 using std::string;
27 class HpackDecoderPeer {
28 public:
29 explicit HpackDecoderPeer(HpackDecoder* decoder) : decoder_(decoder) {}
31 void HandleHeaderRepresentation(StringPiece name, StringPiece value) {
32 decoder_->HandleHeaderRepresentation(name, value);
34 bool DecodeNextName(HpackInputStream* in, StringPiece* out) {
35 return decoder_->DecodeNextName(in, out);
37 HpackHeaderTable* header_table() { return &decoder_->header_table_; }
38 void set_cookie_value(string value) { decoder_->cookie_value_ = value; }
39 string cookie_value() { return decoder_->cookie_value_; }
40 const SpdyHeaderBlock& decoded_block() const {
41 return decoder_->decoded_block_;
43 const string& headers_block_buffer() const {
44 return decoder_->headers_block_buffer_;
47 private:
48 HpackDecoder* decoder_;
51 } // namespace test
53 namespace {
55 using base::StringPiece;
56 using std::string;
57 using test::a2b_hex;
59 using testing::ElementsAre;
60 using testing::Pair;
62 const size_t kLiteralBound = 1024;
64 class HpackDecoderTest : public ::testing::Test {
65 protected:
66 HpackDecoderTest()
67 : decoder_(ObtainHpackHuffmanTable()), decoder_peer_(&decoder_) {}
69 bool DecodeHeaderBlock(StringPiece str) {
70 return decoder_.HandleControlFrameHeadersData(0, str.data(), str.size()) &&
71 decoder_.HandleControlFrameHeadersComplete(0, nullptr);
74 const SpdyHeaderBlock& decoded_block() const {
75 // TODO(jgraettinger): HpackDecoderTest should implement
76 // SpdyHeadersHandlerInterface, and collect headers for examination.
77 return decoder_peer_.decoded_block();
80 const SpdyHeaderBlock& DecodeBlockExpectingSuccess(StringPiece str) {
81 EXPECT_TRUE(DecodeHeaderBlock(str));
82 return decoded_block();
85 void expectEntry(size_t index,
86 size_t size,
87 const string& name,
88 const string& value) {
89 const HpackEntry* entry = decoder_peer_.header_table()->GetByIndex(index);
90 EXPECT_EQ(name, entry->name()) << "index " << index;
91 EXPECT_EQ(value, entry->value());
92 EXPECT_EQ(size, entry->Size());
93 EXPECT_EQ(index, decoder_peer_.header_table()->IndexOf(entry));
96 HpackDecoder decoder_;
97 test::HpackDecoderPeer decoder_peer_;
100 TEST_F(HpackDecoderTest, HandleControlFrameHeadersData) {
101 // Strings under threshold are concatenated in the buffer.
102 EXPECT_TRUE(
103 decoder_.HandleControlFrameHeadersData(0, "small string one", 16));
104 EXPECT_TRUE(
105 decoder_.HandleControlFrameHeadersData(0, "small string two", 16));
106 // A string which would push the buffer over the threshold is refused.
107 EXPECT_FALSE(decoder_.HandleControlFrameHeadersData(
108 0, "fails", kMaxDecodeBufferSize - 32 + 1));
110 EXPECT_EQ(decoder_peer_.headers_block_buffer(),
111 "small string onesmall string two");
114 TEST_F(HpackDecoderTest, HandleControlFrameHeadersComplete) {
115 decoder_peer_.set_cookie_value("foobar=baz");
117 // Incremental cookie buffer should be emitted and cleared.
118 decoder_.HandleControlFrameHeadersData(0, "\x82\x85", 2);
119 decoder_.HandleControlFrameHeadersComplete(0, nullptr);
121 EXPECT_THAT(decoded_block(),
122 ElementsAre(Pair(":method", "GET"), Pair(":path", "/index.html"),
123 Pair("cookie", "foobar=baz")));
124 EXPECT_EQ(decoder_peer_.cookie_value(), "");
127 TEST_F(HpackDecoderTest, HandleHeaderRepresentation) {
128 // All cookie crumbs are joined.
129 decoder_peer_.HandleHeaderRepresentation("cookie", " part 1");
130 decoder_peer_.HandleHeaderRepresentation("cookie", "part 2 ");
131 decoder_peer_.HandleHeaderRepresentation("cookie", "part3");
133 // Already-delimited headers are passed through.
134 decoder_peer_.HandleHeaderRepresentation("passed-through",
135 string("foo\0baz", 7));
137 // Other headers are joined on \0. Case matters.
138 decoder_peer_.HandleHeaderRepresentation("joined", "not joined");
139 decoder_peer_.HandleHeaderRepresentation("joineD", "value 1");
140 decoder_peer_.HandleHeaderRepresentation("joineD", "value 2");
142 // Empty headers remain empty.
143 decoder_peer_.HandleHeaderRepresentation("empty", "");
145 // Joined empty headers work as expected.
146 decoder_peer_.HandleHeaderRepresentation("empty-joined", "");
147 decoder_peer_.HandleHeaderRepresentation("empty-joined", "foo");
148 decoder_peer_.HandleHeaderRepresentation("empty-joined", "");
149 decoder_peer_.HandleHeaderRepresentation("empty-joined", "");
151 // Non-contiguous cookie crumb.
152 decoder_peer_.HandleHeaderRepresentation("cookie", " fin!");
154 // Finish and emit all headers.
155 decoder_.HandleControlFrameHeadersComplete(0, nullptr);
157 EXPECT_THAT(decoded_block(),
158 ElementsAre(Pair("cookie", " part 1; part 2 ; part3; fin!"),
159 Pair("empty", ""),
160 Pair("empty-joined", string("\0foo\0\0", 6)),
161 Pair("joineD", string("value 1\0value 2", 15)),
162 Pair("joined", "not joined"),
163 Pair("passed-through", string("foo\0baz", 7))));
166 // Decoding an encoded name with a valid string literal should work.
167 TEST_F(HpackDecoderTest, DecodeNextNameLiteral) {
168 HpackInputStream input_stream(kLiteralBound, StringPiece("\x00\x04name", 6));
170 StringPiece string_piece;
171 EXPECT_TRUE(decoder_peer_.DecodeNextName(&input_stream, &string_piece));
172 EXPECT_EQ("name", string_piece);
173 EXPECT_FALSE(input_stream.HasMoreData());
176 TEST_F(HpackDecoderTest, DecodeNextNameLiteralWithHuffmanEncoding) {
177 string input = a2b_hex("008825a849e95ba97d7f");
178 HpackInputStream input_stream(kLiteralBound, input);
180 StringPiece string_piece;
181 EXPECT_TRUE(decoder_peer_.DecodeNextName(&input_stream, &string_piece));
182 EXPECT_EQ("custom-key", string_piece);
183 EXPECT_FALSE(input_stream.HasMoreData());
186 // Decoding an encoded name with a valid index should work.
187 TEST_F(HpackDecoderTest, DecodeNextNameIndexed) {
188 HpackInputStream input_stream(kLiteralBound, "\x01");
190 StringPiece string_piece;
191 EXPECT_TRUE(decoder_peer_.DecodeNextName(&input_stream, &string_piece));
192 EXPECT_EQ(":authority", string_piece);
193 EXPECT_FALSE(input_stream.HasMoreData());
196 // Decoding an encoded name with an invalid index should fail.
197 TEST_F(HpackDecoderTest, DecodeNextNameInvalidIndex) {
198 // One more than the number of static table entries.
199 HpackInputStream input_stream(kLiteralBound, "\x3e");
201 StringPiece string_piece;
202 EXPECT_FALSE(decoder_peer_.DecodeNextName(&input_stream, &string_piece));
205 // Decoding indexed static table field should work.
206 TEST_F(HpackDecoderTest, IndexedHeaderStatic) {
207 // Reference static table entries #2 and #5.
208 SpdyHeaderBlock header_set1 = DecodeBlockExpectingSuccess("\x82\x85");
209 SpdyHeaderBlock expected_header_set1;
210 expected_header_set1[":method"] = "GET";
211 expected_header_set1[":path"] = "/index.html";
212 EXPECT_EQ(expected_header_set1, header_set1);
214 // Reference static table entry #2.
215 SpdyHeaderBlock header_set2 = DecodeBlockExpectingSuccess("\x82");
216 SpdyHeaderBlock expected_header_set2;
217 expected_header_set2[":method"] = "GET";
218 EXPECT_EQ(expected_header_set2, header_set2);
221 TEST_F(HpackDecoderTest, IndexedHeaderDynamic) {
222 // First header block: add an entry to header table.
223 SpdyHeaderBlock header_set1 = DecodeBlockExpectingSuccess(
224 "\x40\x03"
225 "foo"
226 "\x03"
227 "bar");
228 SpdyHeaderBlock expected_header_set1;
229 expected_header_set1["foo"] = "bar";
230 EXPECT_EQ(expected_header_set1, header_set1);
232 // Second header block: add another entry to header table.
233 SpdyHeaderBlock header_set2 = DecodeBlockExpectingSuccess(
234 "\xbe\x40\x04"
235 "spam"
236 "\x04"
237 "eggs");
238 SpdyHeaderBlock expected_header_set2;
239 expected_header_set2["foo"] = "bar";
240 expected_header_set2["spam"] = "eggs";
241 EXPECT_EQ(expected_header_set2, header_set2);
243 // Third header block: refer to most recently added entry.
244 SpdyHeaderBlock header_set3 = DecodeBlockExpectingSuccess("\xbe");
245 SpdyHeaderBlock expected_header_set3;
246 expected_header_set3["spam"] = "eggs";
247 EXPECT_EQ(expected_header_set3, header_set3);
250 // Test a too-large indexed header.
251 TEST_F(HpackDecoderTest, InvalidIndexedHeader) {
252 // High-bit set, and a prefix of one more than the number of static entries.
253 EXPECT_FALSE(DecodeHeaderBlock(StringPiece("\xbe", 1)));
256 // Test that a header block with a pseudo-header field following a regular one
257 // is treated as malformed. (HTTP2 draft-14 8.1.2.1., HPACK draft-09 3.1.)
259 TEST_F(HpackDecoderTest, InvalidPseudoHeaderPositionStatic) {
260 // Okay: ":path" (static entry 4) followed by "allow" (static entry 20).
261 EXPECT_TRUE(DecodeHeaderBlock(a2b_hex("8494")));
262 // Malformed: "allow" (static entry 20) followed by ":path" (static entry 4).
263 EXPECT_FALSE(DecodeHeaderBlock(a2b_hex("9484")));
266 TEST_F(HpackDecoderTest, InvalidPseudoHeaderPositionLiteral) {
267 // Okay: literal ":bar" followed by literal "foo".
268 EXPECT_TRUE(DecodeHeaderBlock(a2b_hex("40043a626172004003666f6f00")));
269 // Malformed: literal "foo" followed by literal ":bar".
270 EXPECT_FALSE(DecodeHeaderBlock(a2b_hex("4003666f6f0040043a62617200")));
273 TEST_F(HpackDecoderTest, ContextUpdateMaximumSize) {
274 EXPECT_EQ(kDefaultHeaderTableSizeSetting,
275 decoder_peer_.header_table()->max_size());
276 string input;
278 // Maximum-size update with size 126. Succeeds.
279 HpackOutputStream output_stream;
280 output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode);
281 output_stream.AppendUint32(126);
283 output_stream.TakeString(&input);
284 EXPECT_TRUE(DecodeHeaderBlock(StringPiece(input)));
285 EXPECT_EQ(126u, decoder_peer_.header_table()->max_size());
288 // Maximum-size update with kDefaultHeaderTableSizeSetting. Succeeds.
289 HpackOutputStream output_stream;
290 output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode);
291 output_stream.AppendUint32(kDefaultHeaderTableSizeSetting);
293 output_stream.TakeString(&input);
294 EXPECT_TRUE(DecodeHeaderBlock(StringPiece(input)));
295 EXPECT_EQ(kDefaultHeaderTableSizeSetting,
296 decoder_peer_.header_table()->max_size());
299 // Maximum-size update with kDefaultHeaderTableSizeSetting + 1. Fails.
300 HpackOutputStream output_stream;
301 output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode);
302 output_stream.AppendUint32(kDefaultHeaderTableSizeSetting + 1);
304 output_stream.TakeString(&input);
305 EXPECT_FALSE(DecodeHeaderBlock(StringPiece(input)));
306 EXPECT_EQ(kDefaultHeaderTableSizeSetting,
307 decoder_peer_.header_table()->max_size());
311 // Decoding two valid encoded literal headers with no indexing should
312 // work.
313 TEST_F(HpackDecoderTest, LiteralHeaderNoIndexing) {
314 // First header with indexed name, second header with string literal
315 // name.
316 const char input[] = "\x04\x0c/sample/path\x00\x06:path2\x0e/sample/path/2";
317 SpdyHeaderBlock header_set =
318 DecodeBlockExpectingSuccess(StringPiece(input, arraysize(input) - 1));
320 SpdyHeaderBlock expected_header_set;
321 expected_header_set[":path"] = "/sample/path";
322 expected_header_set[":path2"] = "/sample/path/2";
323 EXPECT_EQ(expected_header_set, header_set);
326 // Decoding two valid encoded literal headers with incremental
327 // indexing and string literal names should work.
328 TEST_F(HpackDecoderTest, LiteralHeaderIncrementalIndexing) {
329 const char input[] = "\x44\x0c/sample/path\x40\x06:path2\x0e/sample/path/2";
330 SpdyHeaderBlock header_set =
331 DecodeBlockExpectingSuccess(StringPiece(input, arraysize(input) - 1));
333 SpdyHeaderBlock expected_header_set;
334 expected_header_set[":path"] = "/sample/path";
335 expected_header_set[":path2"] = "/sample/path/2";
336 EXPECT_EQ(expected_header_set, header_set);
339 TEST_F(HpackDecoderTest, LiteralHeaderWithIndexingInvalidNameIndex) {
340 decoder_.ApplyHeaderTableSizeSetting(0);
342 // Name is the last static index. Works.
343 EXPECT_TRUE(DecodeHeaderBlock(StringPiece("\x7d\x03ooo")));
344 // Name is one beyond the last static index. Fails.
345 EXPECT_FALSE(DecodeHeaderBlock(StringPiece("\x7e\x03ooo")));
348 TEST_F(HpackDecoderTest, LiteralHeaderNoIndexingInvalidNameIndex) {
349 // Name is the last static index. Works.
350 EXPECT_TRUE(DecodeHeaderBlock(StringPiece("\x0f\x2e\x03ooo")));
351 // Name is one beyond the last static index. Fails.
352 EXPECT_FALSE(DecodeHeaderBlock(StringPiece("\x0f\x2f\x03ooo")));
355 TEST_F(HpackDecoderTest, LiteralHeaderNeverIndexedInvalidNameIndex) {
356 // Name is the last static index. Works.
357 EXPECT_TRUE(DecodeHeaderBlock(StringPiece("\x1f\x2e\x03ooo")));
358 // Name is one beyond the last static index. Fails.
359 EXPECT_FALSE(DecodeHeaderBlock(StringPiece("\x1f\x2f\x03ooo")));
362 // Round-tripping the header set from E.2.1 should work.
363 TEST_F(HpackDecoderTest, BasicE21) {
364 HpackEncoder encoder(ObtainHpackHuffmanTable());
366 SpdyHeaderBlock expected_header_set;
367 expected_header_set[":method"] = "GET";
368 expected_header_set[":scheme"] = "http";
369 expected_header_set[":path"] = "/";
370 expected_header_set[":authority"] = "www.example.com";
372 string encoded_header_set;
373 EXPECT_TRUE(
374 encoder.EncodeHeaderSet(expected_header_set, &encoded_header_set));
376 EXPECT_TRUE(DecodeHeaderBlock(encoded_header_set));
377 EXPECT_EQ(expected_header_set, decoded_block());
380 TEST_F(HpackDecoderTest, SectionD4RequestHuffmanExamples) {
381 SpdyHeaderBlock header_set;
383 // 82 | == Indexed - Add ==
384 // | idx = 2
385 // | -> :method: GET
386 // 86 | == Indexed - Add ==
387 // | idx = 6
388 // | -> :scheme: http
389 // 84 | == Indexed - Add ==
390 // | idx = 4
391 // | -> :path: /
392 // 41 | == Literal indexed ==
393 // | Indexed name (idx = 1)
394 // | :authority
395 // 8c | Literal value (len = 15)
396 // | Huffman encoded:
397 // f1e3 c2e5 f23a 6ba0 ab90 f4ff | .....:k.....
398 // | Decoded:
399 // | www.example.com
400 // | -> :authority: www.example.com
401 string first = a2b_hex(
402 "828684418cf1e3c2e5f23a6ba0ab90f4"
403 "ff");
404 header_set = DecodeBlockExpectingSuccess(first);
406 EXPECT_THAT(
407 header_set,
408 ElementsAre(Pair(":authority", "www.example.com"), Pair(":method", "GET"),
409 Pair(":path", "/"), Pair(":scheme", "http")));
411 expectEntry(62, 57, ":authority", "www.example.com");
412 EXPECT_EQ(57u, decoder_peer_.header_table()->size());
414 // 82 | == Indexed - Add ==
415 // | idx = 2
416 // | -> :method: GET
417 // 86 | == Indexed - Add ==
418 // | idx = 6
419 // | -> :scheme: http
420 // 84 | == Indexed - Add ==
421 // | idx = 4
422 // | -> :path: /
423 // be | == Indexed - Add ==
424 // | idx = 62
425 // | -> :authority: www.example.com
426 // 58 | == Literal indexed ==
427 // | Indexed name (idx = 24)
428 // | cache-control
429 // 86 | Literal value (len = 8)
430 // | Huffman encoded:
431 // a8eb 1064 9cbf | ...d..
432 // | Decoded:
433 // | no-cache
434 // | -> cache-control: no-cache
436 string second = a2b_hex("828684be5886a8eb10649cbf");
437 header_set = DecodeBlockExpectingSuccess(second);
439 EXPECT_THAT(
440 header_set,
441 ElementsAre(Pair(":authority", "www.example.com"), Pair(":method", "GET"),
442 Pair(":path", "/"), Pair(":scheme", "http"),
443 Pair("cache-control", "no-cache")));
445 expectEntry(62, 53, "cache-control", "no-cache");
446 expectEntry(63, 57, ":authority", "www.example.com");
447 EXPECT_EQ(110u, decoder_peer_.header_table()->size());
449 // 82 | == Indexed - Add ==
450 // | idx = 2
451 // | -> :method: GET
452 // 87 | == Indexed - Add ==
453 // | idx = 7
454 // | -> :scheme: https
455 // 85 | == Indexed - Add ==
456 // | idx = 5
457 // | -> :path: /index.html
458 // bf | == Indexed - Add ==
459 // | idx = 63
460 // | -> :authority: www.example.com
461 // 40 | == Literal indexed ==
462 // 88 | Literal name (len = 10)
463 // | Huffman encoded:
464 // 25a8 49e9 5ba9 7d7f | %.I.[.}.
465 // | Decoded:
466 // | custom-key
467 // 89 | Literal value (len = 12)
468 // | Huffman encoded:
469 // 25a8 49e9 5bb8 e8b4 bf | %.I.[....
470 // | Decoded:
471 // | custom-value
472 // | -> custom-key: custom-value
473 string third = a2b_hex(
474 "828785bf408825a849e95ba97d7f89"
475 "25a849e95bb8e8b4bf");
476 header_set = DecodeBlockExpectingSuccess(third);
478 EXPECT_THAT(
479 header_set,
480 ElementsAre(Pair(":authority", "www.example.com"), Pair(":method", "GET"),
481 Pair(":path", "/index.html"), Pair(":scheme", "https"),
482 Pair("custom-key", "custom-value")));
484 expectEntry(62, 54, "custom-key", "custom-value");
485 expectEntry(63, 53, "cache-control", "no-cache");
486 expectEntry(64, 57, ":authority", "www.example.com");
487 EXPECT_EQ(164u, decoder_peer_.header_table()->size());
490 TEST_F(HpackDecoderTest, SectionD6ResponseHuffmanExamples) {
491 SpdyHeaderBlock header_set;
492 decoder_.ApplyHeaderTableSizeSetting(256);
494 // 48 | == Literal indexed ==
495 // | Indexed name (idx = 8)
496 // | :status
497 // 82 | Literal value (len = 3)
498 // | Huffman encoded:
499 // 6402 | d.
500 // | Decoded:
501 // | 302
502 // | -> :status: 302
503 // 58 | == Literal indexed ==
504 // | Indexed name (idx = 24)
505 // | cache-control
506 // 85 | Literal value (len = 7)
507 // | Huffman encoded:
508 // aec3 771a 4b | ..w.K
509 // | Decoded:
510 // | private
511 // | -> cache-control: private
512 // 61 | == Literal indexed ==
513 // | Indexed name (idx = 33)
514 // | date
515 // 96 | Literal value (len = 29)
516 // | Huffman encoded:
517 // d07a be94 1054 d444 a820 0595 040b 8166 | .z...T.D. .....f
518 // e082 a62d 1bff | ...-..
519 // | Decoded:
520 // | Mon, 21 Oct 2013 20:13:21
521 // | GMT
522 // | -> date: Mon, 21 Oct 2013
523 // | 20:13:21 GMT
524 // 6e | == Literal indexed ==
525 // | Indexed name (idx = 46)
526 // | location
527 // 91 | Literal value (len = 23)
528 // | Huffman encoded:
529 // 9d29 ad17 1863 c78f 0b97 c8e9 ae82 ae43 | .)...c.........C
530 // d3 | .
531 // | Decoded:
532 // | https://www.example.com
533 // | -> location: https://www.e
534 // | xample.com
536 string first = a2b_hex(
537 "488264025885aec3771a4b6196d07abe"
538 "941054d444a8200595040b8166e082a6"
539 "2d1bff6e919d29ad171863c78f0b97c8"
540 "e9ae82ae43d3");
541 header_set = DecodeBlockExpectingSuccess(first);
543 EXPECT_THAT(
544 header_set,
545 ElementsAre(Pair(":status", "302"), Pair("cache-control", "private"),
546 Pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"),
547 Pair("location", "https://www.example.com")));
549 expectEntry(62, 63, "location", "https://www.example.com");
550 expectEntry(63, 65, "date", "Mon, 21 Oct 2013 20:13:21 GMT");
551 expectEntry(64, 52, "cache-control", "private");
552 expectEntry(65, 42, ":status", "302");
553 EXPECT_EQ(222u, decoder_peer_.header_table()->size());
555 // 48 | == Literal indexed ==
556 // | Indexed name (idx = 8)
557 // | :status
558 // 83 | Literal value (len = 3)
559 // | Huffman encoded:
560 // 640e ff | d..
561 // | Decoded:
562 // | 307
563 // | - evict: :status: 302
564 // | -> :status: 307
565 // c1 | == Indexed - Add ==
566 // | idx = 65
567 // | -> cache-control: private
568 // c0 | == Indexed - Add ==
569 // | idx = 64
570 // | -> date: Mon, 21 Oct 2013
571 // | 20:13:21 GMT
572 // bf | == Indexed - Add ==
573 // | idx = 63
574 // | -> location:
575 // | https://www.example.com
576 string second = a2b_hex("4883640effc1c0bf");
577 header_set = DecodeBlockExpectingSuccess(second);
579 EXPECT_THAT(
580 header_set,
581 ElementsAre(Pair(":status", "307"), Pair("cache-control", "private"),
582 Pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"),
583 Pair("location", "https://www.example.com")));
585 expectEntry(62, 42, ":status", "307");
586 expectEntry(63, 63, "location", "https://www.example.com");
587 expectEntry(64, 65, "date", "Mon, 21 Oct 2013 20:13:21 GMT");
588 expectEntry(65, 52, "cache-control", "private");
589 EXPECT_EQ(222u, decoder_peer_.header_table()->size());
591 // 88 | == Indexed - Add ==
592 // | idx = 8
593 // | -> :status: 200
594 // c1 | == Indexed - Add ==
595 // | idx = 65
596 // | -> cache-control: private
597 // 61 | == Literal indexed ==
598 // | Indexed name (idx = 33)
599 // | date
600 // 96 | Literal value (len = 22)
601 // | Huffman encoded:
602 // d07a be94 1054 d444 a820 0595 040b 8166 | .z...T.D. .....f
603 // e084 a62d 1bff | ...-..
604 // | Decoded:
605 // | Mon, 21 Oct 2013 20:13:22
606 // | GMT
607 // | - evict: cache-control:
608 // | private
609 // | -> date: Mon, 21 Oct 2013
610 // | 20:13:22 GMT
611 // c0 | == Indexed - Add ==
612 // | idx = 64
613 // | -> location:
614 // | https://www.example.com
615 // 5a | == Literal indexed ==
616 // | Indexed name (idx = 26)
617 // | content-encoding
618 // 83 | Literal value (len = 3)
619 // | Huffman encoded:
620 // 9bd9 ab | ...
621 // | Decoded:
622 // | gzip
623 // | - evict: date: Mon, 21 Oct
624 // | 2013 20:13:21 GMT
625 // | -> content-encoding: gzip
626 // 77 | == Literal indexed ==
627 // | Indexed name (idx = 55)
628 // | set-cookie
629 // ad | Literal value (len = 45)
630 // | Huffman encoded:
631 // 94e7 821d d7f2 e6c7 b335 dfdf cd5b 3960 | .........5...[9`
632 // d5af 2708 7f36 72c1 ab27 0fb5 291f 9587 | ..'..6r..'..)...
633 // 3160 65c0 03ed 4ee5 b106 3d50 07 | 1`e...N...=P.
634 // | Decoded:
635 // | foo=ASDJKHQKBZXOQWEOPIUAXQ
636 // | WEOIU; max-age=3600; versi
637 // | on=1
638 // | - evict: location:
639 // | https://www.example.com
640 // | - evict: :status: 307
641 // | -> set-cookie: foo=ASDJKHQ
642 // | KBZXOQWEOPIUAXQWEOIU;
643 // | max-age=3600; version=1
644 string third = a2b_hex(
645 "88c16196d07abe941054d444a8200595"
646 "040b8166e084a62d1bffc05a839bd9ab"
647 "77ad94e7821dd7f2e6c7b335dfdfcd5b"
648 "3960d5af27087f3672c1ab270fb5291f"
649 "9587316065c003ed4ee5b1063d5007");
650 header_set = DecodeBlockExpectingSuccess(third);
652 EXPECT_THAT(
653 header_set,
654 ElementsAre(Pair(":status", "200"), Pair("cache-control", "private"),
655 Pair("content-encoding", "gzip"),
656 Pair("date", "Mon, 21 Oct 2013 20:13:22 GMT"),
657 Pair("location", "https://www.example.com"),
658 Pair("set-cookie",
659 "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU;"
660 " max-age=3600; version=1")));
662 expectEntry(62, 98, "set-cookie",
663 "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU;"
664 " max-age=3600; version=1");
665 expectEntry(63, 52, "content-encoding", "gzip");
666 expectEntry(64, 65, "date", "Mon, 21 Oct 2013 20:13:22 GMT");
667 EXPECT_EQ(215u, decoder_peer_.header_table()->size());
670 } // namespace
672 } // namespace net