Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(211)

Side by Side Diff: net/spdy/hpack/hpack_decoder_test.cc

Issue 2832973003: Split net/spdy into core and chromium subdirectories. (Closed)
Patch Set: Fix some more build rules. Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « net/spdy/hpack/hpack_decoder_interface.h ('k') | net/spdy/hpack/hpack_encoder.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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/hpack_decoder.h"
6
7 #include <map>
8
9 #include "base/logging.h"
10 #include "net/spdy/hpack/hpack_encoder.h"
11 #include "net/spdy/hpack/hpack_input_stream.h"
12 #include "net/spdy/hpack/hpack_output_stream.h"
13 #include "net/spdy/spdy_flags.h"
14 #include "net/spdy/spdy_protocol.h"
15 #include "net/spdy/spdy_test_utils.h"
16 #include "testing/gmock/include/gmock/gmock.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18
19 namespace net {
20 namespace test {
21
22 class HpackDecoderPeer {
23 public:
24 explicit HpackDecoderPeer(HpackDecoder* decoder) : decoder_(decoder) {}
25
26 void HandleHeaderRepresentation(SpdyStringPiece name, SpdyStringPiece value) {
27 decoder_->HandleHeaderRepresentation(name, value);
28 }
29 bool DecodeNextName(HpackInputStream* in, SpdyStringPiece* out) {
30 return decoder_->DecodeNextName(in, out);
31 }
32 HpackHeaderTable* header_table() { return &decoder_->header_table_; }
33
34 bool DecodeNextStringLiteral(HpackInputStream* in,
35 bool is_header_key,
36 SpdyStringPiece* str) {
37 return decoder_->DecodeNextStringLiteral(in, is_header_key, str);
38 }
39
40 const SpdyString& headers_block_buffer() const {
41 return decoder_->headers_block_buffer_;
42 }
43
44 private:
45 HpackDecoder* decoder_;
46 };
47
48 namespace {
49
50 using test::a2b_hex;
51
52 using testing::ElementsAre;
53 using testing::Pair;
54
55 class HpackDecoderTest : public ::testing::TestWithParam<bool> {
56 protected:
57 HpackDecoderTest() : decoder_(), decoder_peer_(&decoder_) {}
58
59 void SetUp() override { handler_exists_ = GetParam(); }
60
61 bool DecodeHeaderBlock(SpdyStringPiece str) {
62 if (handler_exists_) {
63 decoder_.HandleControlFrameHeadersStart(&handler_);
64 }
65 return decoder_.HandleControlFrameHeadersData(str.data(), str.size()) &&
66 decoder_.HandleControlFrameHeadersComplete(nullptr);
67 }
68
69 bool HandleControlFrameHeadersData(SpdyStringPiece str) {
70 return decoder_.HandleControlFrameHeadersData(str.data(), str.size());
71 }
72
73 bool HandleControlFrameHeadersComplete(size_t* size) {
74 return decoder_.HandleControlFrameHeadersComplete(size);
75 }
76
77 const SpdyHeaderBlock& decoded_block() const {
78 if (handler_exists_) {
79 return handler_.decoded_block();
80 } else {
81 return decoder_.decoded_block();
82 }
83 }
84
85 const SpdyHeaderBlock& DecodeBlockExpectingSuccess(SpdyStringPiece str) {
86 EXPECT_TRUE(DecodeHeaderBlock(str));
87 return decoded_block();
88 }
89
90 void expectEntry(size_t index,
91 size_t size,
92 const SpdyString& name,
93 const SpdyString& value) {
94 const HpackEntry* entry = decoder_peer_.header_table()->GetByIndex(index);
95 EXPECT_EQ(name, entry->name()) << "index " << index;
96 EXPECT_EQ(value, entry->value());
97 EXPECT_EQ(size, entry->Size());
98 EXPECT_EQ(index, decoder_peer_.header_table()->IndexOf(entry));
99 }
100
101 HpackDecoder decoder_;
102 test::HpackDecoderPeer decoder_peer_;
103 TestHeadersHandler handler_;
104 bool handler_exists_;
105 };
106
107 INSTANTIATE_TEST_CASE_P(WithAndWithoutHeadersHandler,
108 HpackDecoderTest,
109 ::testing::Bool());
110
111 TEST_P(HpackDecoderTest, AddHeaderDataWithHandleControlFrameHeadersData) {
112 // The hpack decode buffer size is limited in size. This test verifies that
113 // adding encoded data under that limit is accepted, and data that exceeds the
114 // limit is rejected.
115 const size_t kMaxBufferSizeBytes = 50;
116 decoder_.set_max_decode_buffer_size_bytes(kMaxBufferSizeBytes);
117
118 // Strings under threshold are concatenated in the buffer.
119 SpdyString first_input;
120 first_input.push_back(0x00); // Literal name and value, unindexed
121 first_input.push_back(0x7f); // Name length = 127
122 ASSERT_EQ(2u, first_input.size());
123 EXPECT_TRUE(decoder_.HandleControlFrameHeadersData(first_input.data(),
124 first_input.size()));
125 // Further 38 bytes to make 40 total buffered bytes.
126 SpdyString second_input = SpdyString(38, 'x');
127 EXPECT_TRUE(decoder_.HandleControlFrameHeadersData(second_input.data(),
128 second_input.size()));
129 // A string which would push the buffer over the threshold is refused.
130 const int kThirdInputSize =
131 kMaxBufferSizeBytes - (first_input.size() + second_input.size()) + 1;
132 SpdyString third_input = SpdyString(kThirdInputSize, 'y');
133 ASSERT_GT(first_input.size() + second_input.size() + third_input.size(),
134 kMaxBufferSizeBytes);
135 EXPECT_FALSE(decoder_.HandleControlFrameHeadersData(third_input.data(),
136 third_input.size()));
137
138 SpdyString expected(first_input);
139 expected.append(second_input);
140 EXPECT_EQ(expected, decoder_peer_.headers_block_buffer());
141 }
142
143 // Decode with incomplete data in buffer.
144 TEST_P(HpackDecoderTest, DecodeWithIncompleteData) {
145 // No need to wait for more data.
146 EXPECT_TRUE(HandleControlFrameHeadersData("\x82\x85\x82"));
147 EXPECT_EQ("", decoder_peer_.headers_block_buffer());
148
149 // Need to wait for more data.
150 EXPECT_TRUE(
151 HandleControlFrameHeadersData("\x40\x03goo"
152 "\x03gar\xbe\x40\x04spam"));
153 EXPECT_EQ("\x40\x04spam", decoder_peer_.headers_block_buffer());
154
155 // Add the needed data.
156 EXPECT_TRUE(HandleControlFrameHeadersData("\x04gggs"));
157 EXPECT_EQ("", decoder_peer_.headers_block_buffer());
158
159 size_t size = 0;
160 EXPECT_TRUE(HandleControlFrameHeadersComplete(&size));
161 EXPECT_EQ(24u, size);
162 }
163
164 TEST_P(HpackDecoderTest, HandleHeaderRepresentation) {
165 if (handler_exists_) {
166 decoder_.HandleControlFrameHeadersStart(&handler_);
167 }
168
169 // All cookie crumbs are joined.
170 decoder_peer_.HandleHeaderRepresentation("cookie", " part 1");
171 decoder_peer_.HandleHeaderRepresentation("cookie", "part 2 ");
172 decoder_peer_.HandleHeaderRepresentation("cookie", "part3");
173
174 // Already-delimited headers are passed through.
175 decoder_peer_.HandleHeaderRepresentation("passed-through",
176 SpdyString("foo\0baz", 7));
177
178 // Other headers are joined on \0. Case matters.
179 decoder_peer_.HandleHeaderRepresentation("joined", "not joined");
180 decoder_peer_.HandleHeaderRepresentation("joineD", "value 1");
181 decoder_peer_.HandleHeaderRepresentation("joineD", "value 2");
182
183 // Empty headers remain empty.
184 decoder_peer_.HandleHeaderRepresentation("empty", "");
185
186 // Joined empty headers work as expected.
187 decoder_peer_.HandleHeaderRepresentation("empty-joined", "");
188 decoder_peer_.HandleHeaderRepresentation("empty-joined", "foo");
189 decoder_peer_.HandleHeaderRepresentation("empty-joined", "");
190 decoder_peer_.HandleHeaderRepresentation("empty-joined", "");
191
192 // Non-contiguous cookie crumb.
193 decoder_peer_.HandleHeaderRepresentation("cookie", " fin!");
194
195 // Finish and emit all headers.
196 decoder_.HandleControlFrameHeadersComplete(nullptr);
197
198 // Resulting decoded headers are in the same order as input.
199 EXPECT_THAT(
200 decoded_block(),
201 ElementsAre(Pair("cookie", " part 1; part 2 ; part3; fin!"),
202 Pair("passed-through", SpdyStringPiece("foo\0baz", 7)),
203 Pair("joined", "not joined"),
204 Pair("joineD", SpdyStringPiece("value 1\0value 2", 15)),
205 Pair("empty", ""),
206 Pair("empty-joined", SpdyStringPiece("\0foo\0\0", 6))));
207 }
208
209 // Decoding an encoded name with a valid string literal should work.
210 TEST_P(HpackDecoderTest, DecodeNextNameLiteral) {
211 HpackInputStream input_stream(SpdyStringPiece("\x00\x04name", 6));
212
213 SpdyStringPiece string_piece;
214 EXPECT_TRUE(decoder_peer_.DecodeNextName(&input_stream, &string_piece));
215 EXPECT_EQ("name", string_piece);
216 EXPECT_FALSE(input_stream.HasMoreData());
217 EXPECT_FALSE(input_stream.NeedMoreData());
218 input_stream.MarkCurrentPosition();
219 EXPECT_EQ(6u, input_stream.ParsedBytes());
220 }
221
222 // Decoding an encoded name with an incomplete string literal.
223 TEST_P(HpackDecoderTest, DecodeNextNameLiteralWithIncompleteHeader) {
224 HpackInputStream input_stream(SpdyStringPiece("\x00\x04name\x00\x02g", 9));
225
226 SpdyStringPiece string_piece;
227 EXPECT_TRUE(decoder_peer_.DecodeNextName(&input_stream, &string_piece));
228 EXPECT_FALSE(input_stream.NeedMoreData());
229 input_stream.MarkCurrentPosition();
230 EXPECT_EQ(6u, input_stream.ParsedBytes());
231
232 EXPECT_FALSE(decoder_peer_.DecodeNextName(&input_stream, &string_piece));
233 EXPECT_TRUE(input_stream.NeedMoreData());
234 input_stream.MarkCurrentPosition();
235 EXPECT_EQ(8u, input_stream.ParsedBytes());
236 }
237
238 TEST_P(HpackDecoderTest, DecodeNextNameLiteralWithHuffmanEncoding) {
239 SpdyString input = a2b_hex("008825a849e95ba97d7f");
240 HpackInputStream input_stream(input);
241
242 SpdyStringPiece string_piece;
243 EXPECT_TRUE(decoder_peer_.DecodeNextName(&input_stream, &string_piece));
244 EXPECT_EQ("custom-key", string_piece);
245 EXPECT_FALSE(input_stream.HasMoreData());
246 EXPECT_FALSE(input_stream.NeedMoreData());
247 input_stream.MarkCurrentPosition();
248 EXPECT_EQ(input.size(), input_stream.ParsedBytes());
249 }
250
251 // Decode with incomplete huffman encoding.
252 TEST_P(HpackDecoderTest, DecodeNextNameLiteralWithIncompleteHuffmanEncoding) {
253 // CHECK(huffman_table_.Initialize(kHpackHuffmanCode,
254 // arraysize(kHpackHuffmanCode)));
255 // Put two copies of the same huffman encoding into input.
256 SpdyString input = a2b_hex("008825a849e95ba97d7f008825a849e95ba97d7f");
257 input.resize(input.size() - 1); // Remove the last byte.
258 HpackInputStream input_stream(input);
259
260 SpdyStringPiece string_piece;
261 EXPECT_TRUE(decoder_peer_.DecodeNextName(&input_stream, &string_piece));
262 EXPECT_FALSE(input_stream.NeedMoreData());
263 input_stream.MarkCurrentPosition();
264 EXPECT_EQ(10u, input_stream.ParsedBytes());
265
266 EXPECT_FALSE(decoder_peer_.DecodeNextName(&input_stream, &string_piece));
267 EXPECT_TRUE(input_stream.NeedMoreData());
268 input_stream.MarkCurrentPosition();
269 EXPECT_EQ(12u, input_stream.ParsedBytes());
270 }
271
272 // Decoding an encoded name with a valid index should work.
273 TEST_P(HpackDecoderTest, DecodeNextNameIndexed) {
274 HpackInputStream input_stream("\x01");
275
276 SpdyStringPiece string_piece;
277 EXPECT_TRUE(decoder_peer_.DecodeNextName(&input_stream, &string_piece));
278 EXPECT_EQ(":authority", string_piece);
279 EXPECT_FALSE(input_stream.HasMoreData());
280 EXPECT_FALSE(input_stream.NeedMoreData());
281 input_stream.MarkCurrentPosition();
282 EXPECT_EQ(1u, input_stream.ParsedBytes());
283 }
284
285 // Decoding an encoded name with an invalid index should fail.
286 TEST_P(HpackDecoderTest, DecodeNextNameInvalidIndex) {
287 // One more than the number of static table entries.
288 HpackInputStream input_stream("\x3e");
289
290 SpdyStringPiece string_piece;
291 EXPECT_FALSE(decoder_peer_.DecodeNextName(&input_stream, &string_piece));
292 EXPECT_FALSE(input_stream.NeedMoreData());
293 input_stream.MarkCurrentPosition();
294 EXPECT_EQ(1u, input_stream.ParsedBytes());
295 }
296
297 // Decoding indexed static table field should work.
298 TEST_P(HpackDecoderTest, IndexedHeaderStatic) {
299 // Reference static table entries #2 and #5.
300 const SpdyHeaderBlock& header_set1 = DecodeBlockExpectingSuccess("\x82\x85");
301 SpdyHeaderBlock expected_header_set1;
302 expected_header_set1[":method"] = "GET";
303 expected_header_set1[":path"] = "/index.html";
304 EXPECT_EQ(expected_header_set1, header_set1);
305
306 // Reference static table entry #2.
307 const SpdyHeaderBlock& header_set2 = DecodeBlockExpectingSuccess("\x82");
308 SpdyHeaderBlock expected_header_set2;
309 expected_header_set2[":method"] = "GET";
310 EXPECT_EQ(expected_header_set2, header_set2);
311 }
312
313 TEST_P(HpackDecoderTest, IndexedHeaderDynamic) {
314 // First header block: add an entry to header table.
315 const SpdyHeaderBlock& header_set1 = DecodeBlockExpectingSuccess(
316 "\x40\x03"
317 "foo"
318 "\x03"
319 "bar");
320 SpdyHeaderBlock expected_header_set1;
321 expected_header_set1["foo"] = "bar";
322 EXPECT_EQ(expected_header_set1, header_set1);
323
324 // Second header block: add another entry to header table.
325 const SpdyHeaderBlock& header_set2 = DecodeBlockExpectingSuccess(
326 "\xbe\x40\x04"
327 "spam"
328 "\x04"
329 "eggs");
330 SpdyHeaderBlock expected_header_set2;
331 expected_header_set2["foo"] = "bar";
332 expected_header_set2["spam"] = "eggs";
333 EXPECT_EQ(expected_header_set2, header_set2);
334
335 // Third header block: refer to most recently added entry.
336 const SpdyHeaderBlock& header_set3 = DecodeBlockExpectingSuccess("\xbe");
337 SpdyHeaderBlock expected_header_set3;
338 expected_header_set3["spam"] = "eggs";
339 EXPECT_EQ(expected_header_set3, header_set3);
340 }
341
342 // Test a too-large indexed header.
343 TEST_P(HpackDecoderTest, InvalidIndexedHeader) {
344 // High-bit set, and a prefix of one more than the number of static entries.
345 EXPECT_FALSE(DecodeHeaderBlock(SpdyStringPiece("\xbe", 1)));
346 }
347
348 TEST_P(HpackDecoderTest, ContextUpdateMaximumSize) {
349 EXPECT_EQ(kDefaultHeaderTableSizeSetting,
350 decoder_peer_.header_table()->max_size());
351 SpdyString input;
352 {
353 // Maximum-size update with size 126. Succeeds.
354 HpackOutputStream output_stream;
355 output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode);
356 output_stream.AppendUint32(126);
357
358 output_stream.TakeString(&input);
359 EXPECT_TRUE(DecodeHeaderBlock(SpdyStringPiece(input)));
360 EXPECT_EQ(126u, decoder_peer_.header_table()->max_size());
361 }
362 {
363 // Maximum-size update with kDefaultHeaderTableSizeSetting. Succeeds.
364 HpackOutputStream output_stream;
365 output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode);
366 output_stream.AppendUint32(kDefaultHeaderTableSizeSetting);
367
368 output_stream.TakeString(&input);
369 EXPECT_TRUE(DecodeHeaderBlock(SpdyStringPiece(input)));
370 EXPECT_EQ(kDefaultHeaderTableSizeSetting,
371 decoder_peer_.header_table()->max_size());
372 }
373 {
374 // Maximum-size update with kDefaultHeaderTableSizeSetting + 1. Fails.
375 HpackOutputStream output_stream;
376 output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode);
377 output_stream.AppendUint32(kDefaultHeaderTableSizeSetting + 1);
378
379 output_stream.TakeString(&input);
380 EXPECT_FALSE(DecodeHeaderBlock(SpdyStringPiece(input)));
381 EXPECT_EQ(kDefaultHeaderTableSizeSetting,
382 decoder_peer_.header_table()->max_size());
383 }
384 }
385
386 // Two HeaderTableSizeUpdates may appear at the beginning of the block
387 TEST_P(HpackDecoderTest, TwoTableSizeUpdates) {
388 SpdyString input;
389 {
390 // Should accept two table size updates, update to second one
391 HpackOutputStream output_stream;
392 output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode);
393 output_stream.AppendUint32(0);
394 output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode);
395 output_stream.AppendUint32(122);
396
397 output_stream.TakeString(&input);
398 EXPECT_TRUE(DecodeHeaderBlock(SpdyStringPiece(input)));
399 EXPECT_EQ(122u, decoder_peer_.header_table()->max_size());
400 }
401 }
402
403 // Three HeaderTableSizeUpdates should result in an error
404 TEST_P(HpackDecoderTest, ThreeTableSizeUpdatesError) {
405 SpdyString input;
406 {
407 // Should reject three table size updates, update to second one
408 HpackOutputStream output_stream;
409 output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode);
410 output_stream.AppendUint32(5);
411 output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode);
412 output_stream.AppendUint32(10);
413 output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode);
414 output_stream.AppendUint32(15);
415
416 output_stream.TakeString(&input);
417
418 EXPECT_FALSE(DecodeHeaderBlock(SpdyStringPiece(input)));
419 EXPECT_EQ(10u, decoder_peer_.header_table()->max_size());
420 }
421 }
422
423 // HeaderTableSizeUpdates may only appear at the beginning of the block
424 // Any other updates should result in an error
425 TEST_P(HpackDecoderTest, TableSizeUpdateSecondError) {
426 SpdyString input;
427 {
428 // Should reject a table size update appearing after a different entry
429 // The table size should remain as the default
430 HpackOutputStream output_stream;
431 output_stream.AppendBytes("\x82\x85");
432 output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode);
433 output_stream.AppendUint32(123);
434
435 output_stream.TakeString(&input);
436
437 EXPECT_FALSE(DecodeHeaderBlock(SpdyStringPiece(input)));
438 EXPECT_EQ(kDefaultHeaderTableSizeSetting,
439 decoder_peer_.header_table()->max_size());
440 }
441 }
442
443 // HeaderTableSizeUpdates may only appear at the beginning of the block
444 // Any other updates should result in an error
445 TEST_P(HpackDecoderTest, TableSizeUpdateFirstThirdError) {
446 SpdyString input;
447 {
448 // Should reject the second table size update
449 // if a different entry appears after the first update
450 // The table size should update to the first but not the second
451 HpackOutputStream output_stream;
452 output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode);
453 output_stream.AppendUint32(60);
454 output_stream.AppendBytes("\x82\x85");
455 output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode);
456 output_stream.AppendUint32(125);
457
458 output_stream.TakeString(&input);
459
460 EXPECT_FALSE(DecodeHeaderBlock(SpdyStringPiece(input)));
461 EXPECT_EQ(60u, decoder_peer_.header_table()->max_size());
462 }
463 }
464
465 // Decoding two valid encoded literal headers with no indexing should
466 // work.
467 TEST_P(HpackDecoderTest, LiteralHeaderNoIndexing) {
468 // First header with indexed name, second header with string literal
469 // name.
470 const char input[] = "\x04\x0c/sample/path\x00\x06:path2\x0e/sample/path/2";
471 const SpdyHeaderBlock& header_set =
472 DecodeBlockExpectingSuccess(SpdyStringPiece(input, arraysize(input) - 1));
473
474 SpdyHeaderBlock expected_header_set;
475 expected_header_set[":path"] = "/sample/path";
476 expected_header_set[":path2"] = "/sample/path/2";
477 EXPECT_EQ(expected_header_set, header_set);
478 }
479
480 // Decoding two valid encoded literal headers with incremental
481 // indexing and string literal names should work.
482 TEST_P(HpackDecoderTest, LiteralHeaderIncrementalIndexing) {
483 const char input[] = "\x44\x0c/sample/path\x40\x06:path2\x0e/sample/path/2";
484 const SpdyHeaderBlock& header_set =
485 DecodeBlockExpectingSuccess(SpdyStringPiece(input, arraysize(input) - 1));
486
487 SpdyHeaderBlock expected_header_set;
488 expected_header_set[":path"] = "/sample/path";
489 expected_header_set[":path2"] = "/sample/path/2";
490 EXPECT_EQ(expected_header_set, header_set);
491 }
492
493 TEST_P(HpackDecoderTest, LiteralHeaderWithIndexingInvalidNameIndex) {
494 decoder_.ApplyHeaderTableSizeSetting(0);
495
496 // Name is the last static index. Works.
497 EXPECT_TRUE(DecodeHeaderBlock(SpdyStringPiece("\x7d\x03ooo")));
498 // Name is one beyond the last static index. Fails.
499 EXPECT_FALSE(DecodeHeaderBlock(SpdyStringPiece("\x7e\x03ooo")));
500 }
501
502 TEST_P(HpackDecoderTest, LiteralHeaderNoIndexingInvalidNameIndex) {
503 // Name is the last static index. Works.
504 EXPECT_TRUE(DecodeHeaderBlock(SpdyStringPiece("\x0f\x2e\x03ooo")));
505 // Name is one beyond the last static index. Fails.
506 EXPECT_FALSE(DecodeHeaderBlock(SpdyStringPiece("\x0f\x2f\x03ooo")));
507 }
508
509 TEST_P(HpackDecoderTest, LiteralHeaderNeverIndexedInvalidNameIndex) {
510 // Name is the last static index. Works.
511 EXPECT_TRUE(DecodeHeaderBlock(SpdyStringPiece("\x1f\x2e\x03ooo")));
512 // Name is one beyond the last static index. Fails.
513 EXPECT_FALSE(DecodeHeaderBlock(SpdyStringPiece("\x1f\x2f\x03ooo")));
514 }
515
516 // Decode with incomplete string literal.
517 TEST_P(HpackDecoderTest, StringLiteralIncomplete) {
518 const char input[] = "\x0c/sample/path\x06:path2\x0e/sample/path/";
519 HpackInputStream input_stream(input);
520 SpdyStringPiece str;
521 EXPECT_TRUE(
522 decoder_peer_.DecodeNextStringLiteral(&input_stream, false, &str));
523 EXPECT_FALSE(input_stream.NeedMoreData());
524 input_stream.MarkCurrentPosition();
525 EXPECT_EQ(13u, input_stream.ParsedBytes());
526
527 EXPECT_TRUE(
528 decoder_peer_.DecodeNextStringLiteral(&input_stream, false, &str));
529 EXPECT_FALSE(input_stream.NeedMoreData());
530 input_stream.MarkCurrentPosition();
531 EXPECT_EQ(20u, input_stream.ParsedBytes());
532
533 EXPECT_FALSE(
534 decoder_peer_.DecodeNextStringLiteral(&input_stream, false, &str));
535 EXPECT_TRUE(input_stream.NeedMoreData());
536 input_stream.MarkCurrentPosition();
537 EXPECT_EQ(21u, input_stream.ParsedBytes());
538 }
539
540 // Round-tripping the header set from RFC 7541 C.3.1 should work.
541 // http://httpwg.org/specs/rfc7541.html#rfc.section.C.3.1
542 TEST_P(HpackDecoderTest, BasicC31) {
543 HpackEncoder encoder(ObtainHpackHuffmanTable());
544
545 SpdyHeaderBlock expected_header_set;
546 expected_header_set[":method"] = "GET";
547 expected_header_set[":scheme"] = "http";
548 expected_header_set[":path"] = "/";
549 expected_header_set[":authority"] = "www.example.com";
550
551 SpdyString encoded_header_set;
552 EXPECT_TRUE(
553 encoder.EncodeHeaderSet(expected_header_set, &encoded_header_set));
554
555 EXPECT_TRUE(DecodeHeaderBlock(encoded_header_set));
556 EXPECT_EQ(expected_header_set, decoded_block());
557 }
558
559 // RFC 7541, Section C.4: Request Examples with Huffman Coding
560 // http://httpwg.org/specs/rfc7541.html#rfc.section.C.4
561 TEST_P(HpackDecoderTest, SectionC4RequestHuffmanExamples) {
562 // 82 | == Indexed - Add ==
563 // | idx = 2
564 // | -> :method: GET
565 // 86 | == Indexed - Add ==
566 // | idx = 6
567 // | -> :scheme: http
568 // 84 | == Indexed - Add ==
569 // | idx = 4
570 // | -> :path: /
571 // 41 | == Literal indexed ==
572 // | Indexed name (idx = 1)
573 // | :authority
574 // 8c | Literal value (len = 15)
575 // | Huffman encoded:
576 // f1e3 c2e5 f23a 6ba0 ab90 f4ff | .....:k.....
577 // | Decoded:
578 // | www.example.com
579 // | -> :authority: www.example.com
580 SpdyString first = a2b_hex("828684418cf1e3c2e5f23a6ba0ab90f4ff");
581 const SpdyHeaderBlock& first_header_set = DecodeBlockExpectingSuccess(first);
582
583 EXPECT_THAT(
584 first_header_set,
585 ElementsAre(Pair(":method", "GET"), Pair(":scheme", "http"),
586 Pair(":path", "/"), Pair(":authority", "www.example.com")));
587
588 expectEntry(62, 57, ":authority", "www.example.com");
589 EXPECT_EQ(57u, decoder_peer_.header_table()->size());
590
591 // 82 | == Indexed - Add ==
592 // | idx = 2
593 // | -> :method: GET
594 // 86 | == Indexed - Add ==
595 // | idx = 6
596 // | -> :scheme: http
597 // 84 | == Indexed - Add ==
598 // | idx = 4
599 // | -> :path: /
600 // be | == Indexed - Add ==
601 // | idx = 62
602 // | -> :authority: www.example.com
603 // 58 | == Literal indexed ==
604 // | Indexed name (idx = 24)
605 // | cache-control
606 // 86 | Literal value (len = 8)
607 // | Huffman encoded:
608 // a8eb 1064 9cbf | ...d..
609 // | Decoded:
610 // | no-cache
611 // | -> cache-control: no-cache
612
613 SpdyString second = a2b_hex("828684be5886a8eb10649cbf");
614 const SpdyHeaderBlock& second_header_set =
615 DecodeBlockExpectingSuccess(second);
616
617 EXPECT_THAT(
618 second_header_set,
619 ElementsAre(Pair(":method", "GET"), Pair(":scheme", "http"),
620 Pair(":path", "/"), Pair(":authority", "www.example.com"),
621 Pair("cache-control", "no-cache")));
622
623 expectEntry(62, 53, "cache-control", "no-cache");
624 expectEntry(63, 57, ":authority", "www.example.com");
625 EXPECT_EQ(110u, decoder_peer_.header_table()->size());
626
627 // 82 | == Indexed - Add ==
628 // | idx = 2
629 // | -> :method: GET
630 // 87 | == Indexed - Add ==
631 // | idx = 7
632 // | -> :scheme: https
633 // 85 | == Indexed - Add ==
634 // | idx = 5
635 // | -> :path: /index.html
636 // bf | == Indexed - Add ==
637 // | idx = 63
638 // | -> :authority: www.example.com
639 // 40 | == Literal indexed ==
640 // 88 | Literal name (len = 10)
641 // | Huffman encoded:
642 // 25a8 49e9 5ba9 7d7f | %.I.[.}.
643 // | Decoded:
644 // | custom-key
645 // 89 | Literal value (len = 12)
646 // | Huffman encoded:
647 // 25a8 49e9 5bb8 e8b4 bf | %.I.[....
648 // | Decoded:
649 // | custom-value
650 // | -> custom-key: custom-value
651 SpdyString third = a2b_hex(
652 "828785bf408825a849e95ba97d7f89"
653 "25a849e95bb8e8b4bf");
654 const SpdyHeaderBlock& third_header_set = DecodeBlockExpectingSuccess(third);
655
656 EXPECT_THAT(third_header_set,
657 ElementsAre(Pair(":method", "GET"), Pair(":scheme", "https"),
658 Pair(":path", "/index.html"),
659 Pair(":authority", "www.example.com"),
660 Pair("custom-key", "custom-value")));
661
662 expectEntry(62, 54, "custom-key", "custom-value");
663 expectEntry(63, 53, "cache-control", "no-cache");
664 expectEntry(64, 57, ":authority", "www.example.com");
665 EXPECT_EQ(164u, decoder_peer_.header_table()->size());
666 }
667
668 // RFC 7541, Section C.6: Response Examples with Huffman Coding
669 // http://httpwg.org/specs/rfc7541.html#rfc.section.C.6
670 TEST_P(HpackDecoderTest, SectionC6ResponseHuffmanExamples) {
671 decoder_.ApplyHeaderTableSizeSetting(256);
672
673 // 48 | == Literal indexed ==
674 // | Indexed name (idx = 8)
675 // | :status
676 // 82 | Literal value (len = 3)
677 // | Huffman encoded:
678 // 6402 | d.
679 // | Decoded:
680 // | 302
681 // | -> :status: 302
682 // 58 | == Literal indexed ==
683 // | Indexed name (idx = 24)
684 // | cache-control
685 // 85 | Literal value (len = 7)
686 // | Huffman encoded:
687 // aec3 771a 4b | ..w.K
688 // | Decoded:
689 // | private
690 // | -> cache-control: private
691 // 61 | == Literal indexed ==
692 // | Indexed name (idx = 33)
693 // | date
694 // 96 | Literal value (len = 29)
695 // | Huffman encoded:
696 // d07a be94 1054 d444 a820 0595 040b 8166 | .z...T.D. .....f
697 // e082 a62d 1bff | ...-..
698 // | Decoded:
699 // | Mon, 21 Oct 2013 20:13:21
700 // | GMT
701 // | -> date: Mon, 21 Oct 2013
702 // | 20:13:21 GMT
703 // 6e | == Literal indexed ==
704 // | Indexed name (idx = 46)
705 // | location
706 // 91 | Literal value (len = 23)
707 // | Huffman encoded:
708 // 9d29 ad17 1863 c78f 0b97 c8e9 ae82 ae43 | .)...c.........C
709 // d3 | .
710 // | Decoded:
711 // | https://www.example.com
712 // | -> location: https://www.e
713 // | xample.com
714
715 SpdyString first = a2b_hex(
716 "488264025885aec3771a4b6196d07abe"
717 "941054d444a8200595040b8166e082a6"
718 "2d1bff6e919d29ad171863c78f0b97c8"
719 "e9ae82ae43d3");
720 const SpdyHeaderBlock& first_header_set = DecodeBlockExpectingSuccess(first);
721
722 EXPECT_THAT(
723 first_header_set,
724 ElementsAre(Pair(":status", "302"), Pair("cache-control", "private"),
725 Pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"),
726 Pair("location", "https://www.example.com")));
727
728 expectEntry(62, 63, "location", "https://www.example.com");
729 expectEntry(63, 65, "date", "Mon, 21 Oct 2013 20:13:21 GMT");
730 expectEntry(64, 52, "cache-control", "private");
731 expectEntry(65, 42, ":status", "302");
732 EXPECT_EQ(222u, decoder_peer_.header_table()->size());
733
734 // 48 | == Literal indexed ==
735 // | Indexed name (idx = 8)
736 // | :status
737 // 83 | Literal value (len = 3)
738 // | Huffman encoded:
739 // 640e ff | d..
740 // | Decoded:
741 // | 307
742 // | - evict: :status: 302
743 // | -> :status: 307
744 // c1 | == Indexed - Add ==
745 // | idx = 65
746 // | -> cache-control: private
747 // c0 | == Indexed - Add ==
748 // | idx = 64
749 // | -> date: Mon, 21 Oct 2013
750 // | 20:13:21 GMT
751 // bf | == Indexed - Add ==
752 // | idx = 63
753 // | -> location:
754 // | https://www.example.com
755 SpdyString second = a2b_hex("4883640effc1c0bf");
756 const SpdyHeaderBlock& second_header_set =
757 DecodeBlockExpectingSuccess(second);
758
759 EXPECT_THAT(
760 second_header_set,
761 ElementsAre(Pair(":status", "307"), Pair("cache-control", "private"),
762 Pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"),
763 Pair("location", "https://www.example.com")));
764
765 expectEntry(62, 42, ":status", "307");
766 expectEntry(63, 63, "location", "https://www.example.com");
767 expectEntry(64, 65, "date", "Mon, 21 Oct 2013 20:13:21 GMT");
768 expectEntry(65, 52, "cache-control", "private");
769 EXPECT_EQ(222u, decoder_peer_.header_table()->size());
770
771 // 88 | == Indexed - Add ==
772 // | idx = 8
773 // | -> :status: 200
774 // c1 | == Indexed - Add ==
775 // | idx = 65
776 // | -> cache-control: private
777 // 61 | == Literal indexed ==
778 // | Indexed name (idx = 33)
779 // | date
780 // 96 | Literal value (len = 22)
781 // | Huffman encoded:
782 // d07a be94 1054 d444 a820 0595 040b 8166 | .z...T.D. .....f
783 // e084 a62d 1bff | ...-..
784 // | Decoded:
785 // | Mon, 21 Oct 2013 20:13:22
786 // | GMT
787 // | - evict: cache-control:
788 // | private
789 // | -> date: Mon, 21 Oct 2013
790 // | 20:13:22 GMT
791 // c0 | == Indexed - Add ==
792 // | idx = 64
793 // | -> location:
794 // | https://www.example.com
795 // 5a | == Literal indexed ==
796 // | Indexed name (idx = 26)
797 // | content-encoding
798 // 83 | Literal value (len = 3)
799 // | Huffman encoded:
800 // 9bd9 ab | ...
801 // | Decoded:
802 // | gzip
803 // | - evict: date: Mon, 21 Oct
804 // | 2013 20:13:21 GMT
805 // | -> content-encoding: gzip
806 // 77 | == Literal indexed ==
807 // | Indexed name (idx = 55)
808 // | set-cookie
809 // ad | Literal value (len = 45)
810 // | Huffman encoded:
811 // 94e7 821d d7f2 e6c7 b335 dfdf cd5b 3960 | .........5...[9`
812 // d5af 2708 7f36 72c1 ab27 0fb5 291f 9587 | ..'..6r..'..)...
813 // 3160 65c0 03ed 4ee5 b106 3d50 07 | 1`e...N...=P.
814 // | Decoded:
815 // | foo=ASDJKHQKBZXOQWEOPIUAXQ
816 // | WEOIU; max-age=3600; versi
817 // | on=1
818 // | - evict: location:
819 // | https://www.example.com
820 // | - evict: :status: 307
821 // | -> set-cookie: foo=ASDJKHQ
822 // | KBZXOQWEOPIUAXQWEOIU;
823 // | max-age=3600; version=1
824 SpdyString third = a2b_hex(
825 "88c16196d07abe941054d444a8200595"
826 "040b8166e084a62d1bffc05a839bd9ab"
827 "77ad94e7821dd7f2e6c7b335dfdfcd5b"
828 "3960d5af27087f3672c1ab270fb5291f"
829 "9587316065c003ed4ee5b1063d5007");
830 const SpdyHeaderBlock& third_header_set = DecodeBlockExpectingSuccess(third);
831
832 EXPECT_THAT(
833 third_header_set,
834 ElementsAre(Pair(":status", "200"), Pair("cache-control", "private"),
835 Pair("date", "Mon, 21 Oct 2013 20:13:22 GMT"),
836 Pair("location", "https://www.example.com"),
837 Pair("content-encoding", "gzip"),
838 Pair("set-cookie",
839 "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU;"
840 " max-age=3600; version=1")));
841
842 expectEntry(62, 98, "set-cookie",
843 "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU;"
844 " max-age=3600; version=1");
845 expectEntry(63, 52, "content-encoding", "gzip");
846 expectEntry(64, 65, "date", "Mon, 21 Oct 2013 20:13:22 GMT");
847 EXPECT_EQ(215u, decoder_peer_.header_table()->size());
848 }
849
850 } // namespace
851 } // namespace test
852 } // namespace net
OLDNEW
« no previous file with comments | « net/spdy/hpack/hpack_decoder_interface.h ('k') | net/spdy/hpack/hpack_encoder.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698