OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/spdy/hpack/hpack_decoder.h" | 5 #include "net/spdy/hpack/hpack_decoder.h" |
6 | 6 |
7 #include <map> | 7 #include <map> |
8 #include <string> | 8 #include <string> |
9 | 9 |
10 #include "base/basictypes.h" | 10 #include "base/basictypes.h" |
11 #include "base/logging.h" | 11 #include "base/logging.h" |
12 #include "base/strings/string_piece.h" | 12 #include "base/strings/string_piece.h" |
13 #include "net/spdy/hpack/hpack_encoder.h" | 13 #include "net/spdy/hpack/hpack_encoder.h" |
14 #include "net/spdy/hpack/hpack_input_stream.h" | 14 #include "net/spdy/hpack/hpack_input_stream.h" |
15 #include "net/spdy/hpack/hpack_output_stream.h" | 15 #include "net/spdy/hpack/hpack_output_stream.h" |
16 #include "net/spdy/spdy_test_utils.h" | 16 #include "net/spdy/spdy_test_utils.h" |
17 #include "testing/gmock/include/gmock/gmock.h" | 17 #include "testing/gmock/include/gmock/gmock.h" |
18 #include "testing/gtest/include/gtest/gtest.h" | 18 #include "testing/gtest/include/gtest/gtest.h" |
19 | 19 |
20 namespace net { | 20 namespace net { |
21 | |
22 namespace test { | 21 namespace test { |
23 | 22 |
24 using base::StringPiece; | 23 using base::StringPiece; |
25 using std::string; | 24 using std::string; |
26 | 25 |
27 class HpackDecoderPeer { | 26 class HpackDecoderPeer { |
28 public: | 27 public: |
29 explicit HpackDecoderPeer(HpackDecoder* decoder) : decoder_(decoder) {} | 28 explicit HpackDecoderPeer(HpackDecoder* decoder) : decoder_(decoder) {} |
30 | 29 |
31 void HandleHeaderRepresentation(StringPiece name, StringPiece value) { | 30 void HandleHeaderRepresentation(StringPiece name, StringPiece value) { |
32 decoder_->HandleHeaderRepresentation(name, value); | 31 decoder_->HandleHeaderRepresentation(name, value); |
33 } | 32 } |
34 bool DecodeNextName(HpackInputStream* in, StringPiece* out) { | 33 bool DecodeNextName(HpackInputStream* in, StringPiece* out) { |
35 return decoder_->DecodeNextName(in, out); | 34 return decoder_->DecodeNextName(in, out); |
36 } | 35 } |
37 HpackHeaderTable* header_table() { return &decoder_->header_table_; } | 36 HpackHeaderTable* header_table() { return &decoder_->header_table_; } |
38 void set_cookie_value(string value) { decoder_->cookie_value_ = value; } | 37 void set_cookie_value(string value) { decoder_->cookie_value_ = value; } |
39 string cookie_value() { return decoder_->cookie_value_; } | 38 string cookie_value() { return decoder_->cookie_value_; } |
40 const SpdyHeaderBlock& decoded_block() const { | 39 const SpdyHeaderBlock& decoded_block() const { |
41 return decoder_->decoded_block_; | 40 return decoder_->decoded_block_; |
42 } | 41 } |
43 const string& headers_block_buffer() const { | 42 const string& headers_block_buffer() const { |
44 return decoder_->headers_block_buffer_; | 43 return decoder_->headers_block_buffer_; |
45 } | 44 } |
46 | 45 |
47 private: | 46 private: |
48 HpackDecoder* decoder_; | 47 HpackDecoder* decoder_; |
49 }; | 48 }; |
50 | 49 |
51 } // namespace test | |
52 | |
53 namespace { | 50 namespace { |
54 | 51 |
55 using base::StringPiece; | 52 using base::StringPiece; |
56 using std::string; | 53 using std::string; |
57 using test::a2b_hex; | 54 using test::a2b_hex; |
58 | 55 |
59 using testing::ElementsAre; | 56 using testing::ElementsAre; |
60 using testing::Pair; | 57 using testing::Pair; |
61 | 58 |
62 const size_t kLiteralBound = 1024; | 59 const size_t kLiteralBound = 1024; |
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
202 EXPECT_FALSE(decoder_peer_.DecodeNextName(&input_stream, &string_piece)); | 199 EXPECT_FALSE(decoder_peer_.DecodeNextName(&input_stream, &string_piece)); |
203 } | 200 } |
204 | 201 |
205 // Decoding indexed static table field should work. | 202 // Decoding indexed static table field should work. |
206 TEST_F(HpackDecoderTest, IndexedHeaderStatic) { | 203 TEST_F(HpackDecoderTest, IndexedHeaderStatic) { |
207 // Reference static table entries #2 and #5. | 204 // Reference static table entries #2 and #5. |
208 SpdyHeaderBlock header_set1 = DecodeBlockExpectingSuccess("\x82\x85"); | 205 SpdyHeaderBlock header_set1 = DecodeBlockExpectingSuccess("\x82\x85"); |
209 SpdyHeaderBlock expected_header_set1; | 206 SpdyHeaderBlock expected_header_set1; |
210 expected_header_set1[":method"] = "GET"; | 207 expected_header_set1[":method"] = "GET"; |
211 expected_header_set1[":path"] = "/index.html"; | 208 expected_header_set1[":path"] = "/index.html"; |
212 EXPECT_EQ(expected_header_set1, header_set1); | 209 EXPECT_TRUE(CompareSpdyHeaderBlocks(expected_header_set1, header_set1)); |
213 | 210 |
214 // Reference static table entry #2. | 211 // Reference static table entry #2. |
215 SpdyHeaderBlock header_set2 = DecodeBlockExpectingSuccess("\x82"); | 212 SpdyHeaderBlock header_set2 = DecodeBlockExpectingSuccess("\x82"); |
216 SpdyHeaderBlock expected_header_set2; | 213 SpdyHeaderBlock expected_header_set2; |
217 expected_header_set2[":method"] = "GET"; | 214 expected_header_set2[":method"] = "GET"; |
218 EXPECT_EQ(expected_header_set2, header_set2); | 215 EXPECT_TRUE(CompareSpdyHeaderBlocks(expected_header_set2, header_set2)); |
219 } | 216 } |
220 | 217 |
221 TEST_F(HpackDecoderTest, IndexedHeaderDynamic) { | 218 TEST_F(HpackDecoderTest, IndexedHeaderDynamic) { |
222 // First header block: add an entry to header table. | 219 // First header block: add an entry to header table. |
223 SpdyHeaderBlock header_set1 = DecodeBlockExpectingSuccess( | 220 SpdyHeaderBlock header_set1 = DecodeBlockExpectingSuccess( |
224 "\x40\x03" | 221 "\x40\x03" |
225 "foo" | 222 "foo" |
226 "\x03" | 223 "\x03" |
227 "bar"); | 224 "bar"); |
228 SpdyHeaderBlock expected_header_set1; | 225 SpdyHeaderBlock expected_header_set1; |
229 expected_header_set1["foo"] = "bar"; | 226 expected_header_set1["foo"] = "bar"; |
230 EXPECT_EQ(expected_header_set1, header_set1); | 227 EXPECT_TRUE(CompareSpdyHeaderBlocks(expected_header_set1, header_set1)); |
231 | 228 |
232 // Second header block: add another entry to header table. | 229 // Second header block: add another entry to header table. |
233 SpdyHeaderBlock header_set2 = DecodeBlockExpectingSuccess( | 230 SpdyHeaderBlock header_set2 = DecodeBlockExpectingSuccess( |
234 "\xbe\x40\x04" | 231 "\xbe\x40\x04" |
235 "spam" | 232 "spam" |
236 "\x04" | 233 "\x04" |
237 "eggs"); | 234 "eggs"); |
238 SpdyHeaderBlock expected_header_set2; | 235 SpdyHeaderBlock expected_header_set2; |
239 expected_header_set2["foo"] = "bar"; | 236 expected_header_set2["foo"] = "bar"; |
240 expected_header_set2["spam"] = "eggs"; | 237 expected_header_set2["spam"] = "eggs"; |
241 EXPECT_EQ(expected_header_set2, header_set2); | 238 EXPECT_TRUE(CompareSpdyHeaderBlocks(expected_header_set2, header_set2)); |
242 | 239 |
243 // Third header block: refer to most recently added entry. | 240 // Third header block: refer to most recently added entry. |
244 SpdyHeaderBlock header_set3 = DecodeBlockExpectingSuccess("\xbe"); | 241 SpdyHeaderBlock header_set3 = DecodeBlockExpectingSuccess("\xbe"); |
245 SpdyHeaderBlock expected_header_set3; | 242 SpdyHeaderBlock expected_header_set3; |
246 expected_header_set3["spam"] = "eggs"; | 243 expected_header_set3["spam"] = "eggs"; |
247 EXPECT_EQ(expected_header_set3, header_set3); | 244 EXPECT_TRUE(CompareSpdyHeaderBlocks(expected_header_set3, header_set3)); |
248 } | 245 } |
249 | 246 |
250 // Test a too-large indexed header. | 247 // Test a too-large indexed header. |
251 TEST_F(HpackDecoderTest, InvalidIndexedHeader) { | 248 TEST_F(HpackDecoderTest, InvalidIndexedHeader) { |
252 // High-bit set, and a prefix of one more than the number of static entries. | 249 // High-bit set, and a prefix of one more than the number of static entries. |
253 EXPECT_FALSE(DecodeHeaderBlock(StringPiece("\xbe", 1))); | 250 EXPECT_FALSE(DecodeHeaderBlock(StringPiece("\xbe", 1))); |
254 } | 251 } |
255 | 252 |
256 // Test that a header block with a pseudo-header field following a regular one | 253 // 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.) | 254 // is treated as malformed. (HTTP2 draft-14 8.1.2.1., HPACK draft-09 3.1.) |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
313 TEST_F(HpackDecoderTest, LiteralHeaderNoIndexing) { | 310 TEST_F(HpackDecoderTest, LiteralHeaderNoIndexing) { |
314 // First header with indexed name, second header with string literal | 311 // First header with indexed name, second header with string literal |
315 // name. | 312 // name. |
316 const char input[] = "\x04\x0c/sample/path\x00\x06:path2\x0e/sample/path/2"; | 313 const char input[] = "\x04\x0c/sample/path\x00\x06:path2\x0e/sample/path/2"; |
317 SpdyHeaderBlock header_set = | 314 SpdyHeaderBlock header_set = |
318 DecodeBlockExpectingSuccess(StringPiece(input, arraysize(input) - 1)); | 315 DecodeBlockExpectingSuccess(StringPiece(input, arraysize(input) - 1)); |
319 | 316 |
320 SpdyHeaderBlock expected_header_set; | 317 SpdyHeaderBlock expected_header_set; |
321 expected_header_set[":path"] = "/sample/path"; | 318 expected_header_set[":path"] = "/sample/path"; |
322 expected_header_set[":path2"] = "/sample/path/2"; | 319 expected_header_set[":path2"] = "/sample/path/2"; |
323 EXPECT_EQ(expected_header_set, header_set); | 320 EXPECT_TRUE(CompareSpdyHeaderBlocks(expected_header_set, header_set)); |
324 } | 321 } |
325 | 322 |
326 // Decoding two valid encoded literal headers with incremental | 323 // Decoding two valid encoded literal headers with incremental |
327 // indexing and string literal names should work. | 324 // indexing and string literal names should work. |
328 TEST_F(HpackDecoderTest, LiteralHeaderIncrementalIndexing) { | 325 TEST_F(HpackDecoderTest, LiteralHeaderIncrementalIndexing) { |
329 const char input[] = "\x44\x0c/sample/path\x40\x06:path2\x0e/sample/path/2"; | 326 const char input[] = "\x44\x0c/sample/path\x40\x06:path2\x0e/sample/path/2"; |
330 SpdyHeaderBlock header_set = | 327 SpdyHeaderBlock header_set = |
331 DecodeBlockExpectingSuccess(StringPiece(input, arraysize(input) - 1)); | 328 DecodeBlockExpectingSuccess(StringPiece(input, arraysize(input) - 1)); |
332 | 329 |
333 SpdyHeaderBlock expected_header_set; | 330 SpdyHeaderBlock expected_header_set; |
334 expected_header_set[":path"] = "/sample/path"; | 331 expected_header_set[":path"] = "/sample/path"; |
335 expected_header_set[":path2"] = "/sample/path/2"; | 332 expected_header_set[":path2"] = "/sample/path/2"; |
336 EXPECT_EQ(expected_header_set, header_set); | 333 EXPECT_TRUE(CompareSpdyHeaderBlocks(expected_header_set, header_set)); |
337 } | 334 } |
338 | 335 |
339 TEST_F(HpackDecoderTest, LiteralHeaderWithIndexingInvalidNameIndex) { | 336 TEST_F(HpackDecoderTest, LiteralHeaderWithIndexingInvalidNameIndex) { |
340 decoder_.ApplyHeaderTableSizeSetting(0); | 337 decoder_.ApplyHeaderTableSizeSetting(0); |
341 | 338 |
342 // Name is the last static index. Works. | 339 // Name is the last static index. Works. |
343 EXPECT_TRUE(DecodeHeaderBlock(StringPiece("\x7d\x03ooo"))); | 340 EXPECT_TRUE(DecodeHeaderBlock(StringPiece("\x7d\x03ooo"))); |
344 // Name is one beyond the last static index. Fails. | 341 // Name is one beyond the last static index. Fails. |
345 EXPECT_FALSE(DecodeHeaderBlock(StringPiece("\x7e\x03ooo"))); | 342 EXPECT_FALSE(DecodeHeaderBlock(StringPiece("\x7e\x03ooo"))); |
346 } | 343 } |
(...skipping 20 matching lines...) Expand all Loading... |
367 expected_header_set[":method"] = "GET"; | 364 expected_header_set[":method"] = "GET"; |
368 expected_header_set[":scheme"] = "http"; | 365 expected_header_set[":scheme"] = "http"; |
369 expected_header_set[":path"] = "/"; | 366 expected_header_set[":path"] = "/"; |
370 expected_header_set[":authority"] = "www.example.com"; | 367 expected_header_set[":authority"] = "www.example.com"; |
371 | 368 |
372 string encoded_header_set; | 369 string encoded_header_set; |
373 EXPECT_TRUE( | 370 EXPECT_TRUE( |
374 encoder.EncodeHeaderSet(expected_header_set, &encoded_header_set)); | 371 encoder.EncodeHeaderSet(expected_header_set, &encoded_header_set)); |
375 | 372 |
376 EXPECT_TRUE(DecodeHeaderBlock(encoded_header_set)); | 373 EXPECT_TRUE(DecodeHeaderBlock(encoded_header_set)); |
377 EXPECT_EQ(expected_header_set, decoded_block()); | 374 EXPECT_TRUE(CompareSpdyHeaderBlocks(expected_header_set, decoded_block())); |
378 } | 375 } |
379 | 376 |
380 TEST_F(HpackDecoderTest, SectionD4RequestHuffmanExamples) { | 377 TEST_F(HpackDecoderTest, SectionD4RequestHuffmanExamples) { |
381 SpdyHeaderBlock header_set; | 378 SpdyHeaderBlock header_set; |
382 | 379 |
383 // 82 | == Indexed - Add == | 380 // 82 | == Indexed - Add == |
384 // | idx = 2 | 381 // | idx = 2 |
385 // | -> :method: GET | 382 // | -> :method: GET |
386 // 86 | == Indexed - Add == | 383 // 86 | == Indexed - Add == |
387 // | idx = 6 | 384 // | idx = 6 |
(...skipping 273 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
661 | 658 |
662 expectEntry(62, 98, "set-cookie", | 659 expectEntry(62, 98, "set-cookie", |
663 "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU;" | 660 "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU;" |
664 " max-age=3600; version=1"); | 661 " max-age=3600; version=1"); |
665 expectEntry(63, 52, "content-encoding", "gzip"); | 662 expectEntry(63, 52, "content-encoding", "gzip"); |
666 expectEntry(64, 65, "date", "Mon, 21 Oct 2013 20:13:22 GMT"); | 663 expectEntry(64, 65, "date", "Mon, 21 Oct 2013 20:13:22 GMT"); |
667 EXPECT_EQ(215u, decoder_peer_.header_table()->size()); | 664 EXPECT_EQ(215u, decoder_peer_.header_table()->size()); |
668 } | 665 } |
669 | 666 |
670 } // namespace | 667 } // namespace |
671 | 668 } // namespace test |
672 } // namespace net | 669 } // namespace net |
OLD | NEW |