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/logging.h" | 10 #include "base/logging.h" |
(...skipping 19 matching lines...) Expand all Loading... |
30 void HandleHeaderRepresentation(StringPiece name, StringPiece value) { | 30 void HandleHeaderRepresentation(StringPiece name, StringPiece value) { |
31 decoder_->HandleHeaderRepresentation(name, value); | 31 decoder_->HandleHeaderRepresentation(name, value); |
32 } | 32 } |
33 bool DecodeNextName(HpackInputStream* in, StringPiece* out) { | 33 bool DecodeNextName(HpackInputStream* in, StringPiece* out) { |
34 return decoder_->DecodeNextName(in, out); | 34 return decoder_->DecodeNextName(in, out); |
35 } | 35 } |
36 HpackHeaderTable* header_table() { return &decoder_->header_table_; } | 36 HpackHeaderTable* header_table() { return &decoder_->header_table_; } |
37 const SpdyHeaderBlock& decoded_block() const { | 37 const SpdyHeaderBlock& decoded_block() const { |
38 return decoder_->decoded_block_; | 38 return decoder_->decoded_block_; |
39 } | 39 } |
| 40 |
| 41 bool DecodeNextStringLiteral(HpackInputStream* in, |
| 42 bool is_header_key, |
| 43 StringPiece* str) { |
| 44 return decoder_->DecodeNextStringLiteral(in, is_header_key, str); |
| 45 } |
| 46 |
40 const string& headers_block_buffer() const { | 47 const string& headers_block_buffer() const { |
41 return decoder_->headers_block_buffer_; | 48 return decoder_->headers_block_buffer_; |
42 } | 49 } |
43 | 50 |
44 private: | 51 private: |
45 HpackDecoder* decoder_; | 52 HpackDecoder* decoder_; |
46 }; | 53 }; |
47 | 54 |
48 namespace { | 55 namespace { |
49 | 56 |
50 using base::StringPiece; | 57 using base::StringPiece; |
51 using std::string; | 58 using std::string; |
52 using test::a2b_hex; | 59 using test::a2b_hex; |
53 | 60 |
54 using testing::ElementsAre; | 61 using testing::ElementsAre; |
55 using testing::Pair; | 62 using testing::Pair; |
56 | 63 |
57 const size_t kLiteralBound = 1024; | 64 const size_t kLiteralBound = 1024; |
58 | 65 |
59 class HpackDecoderTest : public ::testing::TestWithParam<bool> { | 66 class HpackDecoderTest : public ::testing::TestWithParam<bool> { |
60 protected: | 67 protected: |
61 HpackDecoderTest() : decoder_(), decoder_peer_(&decoder_) {} | 68 HpackDecoderTest() : decoder_(), decoder_peer_(&decoder_) {} |
62 | 69 |
| 70 void SetUp() override { handler_exists_ = GetParam(); } |
| 71 |
63 bool DecodeHeaderBlock(StringPiece str) { | 72 bool DecodeHeaderBlock(StringPiece str) { |
64 if (GetParam()) { | 73 if (handler_exists_) { |
65 decoder_.HandleControlFrameHeadersStart(&handler_); | 74 decoder_.HandleControlFrameHeadersStart(&handler_); |
66 } | 75 } |
67 return decoder_.HandleControlFrameHeadersData(str.data(), str.size()) && | 76 return decoder_.HandleControlFrameHeadersData(str.data(), str.size()) && |
68 decoder_.HandleControlFrameHeadersComplete(nullptr); | 77 decoder_.HandleControlFrameHeadersComplete(nullptr); |
69 } | 78 } |
70 | 79 |
| 80 bool HandleControlFrameHeadersData(StringPiece str) { |
| 81 return decoder_.HandleControlFrameHeadersData(str.data(), str.size()); |
| 82 } |
| 83 |
| 84 bool HandleControlFrameHeadersComplete(size_t* size) { |
| 85 return decoder_.HandleControlFrameHeadersComplete(size); |
| 86 } |
| 87 |
71 const SpdyHeaderBlock& decoded_block() const { | 88 const SpdyHeaderBlock& decoded_block() const { |
72 if (GetParam()) { | 89 if (handler_exists_) { |
73 return handler_.decoded_block(); | 90 return handler_.decoded_block(); |
74 } else { | 91 } else { |
75 return decoder_peer_.decoded_block(); | 92 return decoder_peer_.decoded_block(); |
76 } | 93 } |
77 } | 94 } |
78 | 95 |
79 const SpdyHeaderBlock& DecodeBlockExpectingSuccess(StringPiece str) { | 96 const SpdyHeaderBlock& DecodeBlockExpectingSuccess(StringPiece str) { |
80 EXPECT_TRUE(DecodeHeaderBlock(str)); | 97 EXPECT_TRUE(DecodeHeaderBlock(str)); |
81 return decoded_block(); | 98 return decoded_block(); |
82 } | 99 } |
83 | 100 |
84 void expectEntry(size_t index, | 101 void expectEntry(size_t index, |
85 size_t size, | 102 size_t size, |
86 const string& name, | 103 const string& name, |
87 const string& value) { | 104 const string& value) { |
88 const HpackEntry* entry = decoder_peer_.header_table()->GetByIndex(index); | 105 const HpackEntry* entry = decoder_peer_.header_table()->GetByIndex(index); |
89 EXPECT_EQ(name, entry->name()) << "index " << index; | 106 EXPECT_EQ(name, entry->name()) << "index " << index; |
90 EXPECT_EQ(value, entry->value()); | 107 EXPECT_EQ(value, entry->value()); |
91 EXPECT_EQ(size, entry->Size()); | 108 EXPECT_EQ(size, entry->Size()); |
92 EXPECT_EQ(index, decoder_peer_.header_table()->IndexOf(entry)); | 109 EXPECT_EQ(index, decoder_peer_.header_table()->IndexOf(entry)); |
93 } | 110 } |
94 | 111 |
95 HpackDecoder decoder_; | 112 HpackDecoder decoder_; |
96 test::HpackDecoderPeer decoder_peer_; | 113 test::HpackDecoderPeer decoder_peer_; |
97 TestHeadersHandler handler_; | 114 TestHeadersHandler handler_; |
| 115 bool handler_exists_; |
98 }; | 116 }; |
99 | 117 |
100 INSTANTIATE_TEST_CASE_P(WithAndWithoutHeadersHandler, | 118 INSTANTIATE_TEST_CASE_P(WithAndWithoutHeadersHandler, |
101 HpackDecoderTest, | 119 HpackDecoderTest, |
102 ::testing::Bool()); | 120 ::testing::Bool()); |
103 | 121 |
104 TEST_P(HpackDecoderTest, HandleControlFrameHeadersData) { | 122 TEST_P(HpackDecoderTest, AddHeaderDataWithHandleControlFrameHeadersData) { |
105 // Strings under threshold are concatenated in the buffer. | 123 // Strings under threshold are concatenated in the buffer. |
106 EXPECT_TRUE(decoder_.HandleControlFrameHeadersData("small string one", 16)); | 124 EXPECT_TRUE(decoder_.HandleControlFrameHeadersData("small string one", 16)); |
107 EXPECT_TRUE(decoder_.HandleControlFrameHeadersData("small string two", 16)); | 125 EXPECT_TRUE(decoder_.HandleControlFrameHeadersData("small string two", 16)); |
108 // A string which would push the buffer over the threshold is refused. | 126 // A string which would push the buffer over the threshold is refused. |
109 EXPECT_FALSE(decoder_.HandleControlFrameHeadersData( | 127 EXPECT_FALSE(decoder_.HandleControlFrameHeadersData( |
110 "fails", kMaxDecodeBufferSize - 32 + 1)); | 128 "fails", kMaxDecodeBufferSize - 32 + 1)); |
111 | 129 |
112 EXPECT_EQ(decoder_peer_.headers_block_buffer(), | 130 EXPECT_EQ(decoder_peer_.headers_block_buffer(), |
113 "small string onesmall string two"); | 131 "small string onesmall string two"); |
114 } | 132 } |
115 | 133 |
| 134 // Decode with incomplete data in buffer. |
| 135 TEST_P(HpackDecoderTest, DecodeWithIncompleteData) { |
| 136 // No need to wait for more data. |
| 137 EXPECT_TRUE(HandleControlFrameHeadersData("\x82\x85\x82")); |
| 138 EXPECT_EQ("", decoder_peer_.headers_block_buffer()); |
| 139 |
| 140 // Need to wait for more data. |
| 141 EXPECT_TRUE( |
| 142 HandleControlFrameHeadersData("\x40\x03goo" |
| 143 "\x03gar\xbe\x40\x04spam")); |
| 144 EXPECT_EQ("\x40\x04spam", decoder_peer_.headers_block_buffer()); |
| 145 |
| 146 // Add the needed data. |
| 147 EXPECT_TRUE(HandleControlFrameHeadersData("\x04gggs")); |
| 148 EXPECT_EQ("", decoder_peer_.headers_block_buffer()); |
| 149 |
| 150 size_t size = 0; |
| 151 EXPECT_TRUE(HandleControlFrameHeadersComplete(&size)); |
| 152 EXPECT_EQ(24u, size); |
| 153 } |
| 154 |
116 TEST_P(HpackDecoderTest, HandleHeaderRepresentation) { | 155 TEST_P(HpackDecoderTest, HandleHeaderRepresentation) { |
117 if (GetParam()) { | 156 if (handler_exists_) { |
118 decoder_.HandleControlFrameHeadersStart(&handler_); | 157 decoder_.HandleControlFrameHeadersStart(&handler_); |
119 } | 158 } |
120 | 159 |
121 // All cookie crumbs are joined. | 160 // All cookie crumbs are joined. |
122 decoder_peer_.HandleHeaderRepresentation("cookie", " part 1"); | 161 decoder_peer_.HandleHeaderRepresentation("cookie", " part 1"); |
123 decoder_peer_.HandleHeaderRepresentation("cookie", "part 2 "); | 162 decoder_peer_.HandleHeaderRepresentation("cookie", "part 2 "); |
124 decoder_peer_.HandleHeaderRepresentation("cookie", "part3"); | 163 decoder_peer_.HandleHeaderRepresentation("cookie", "part3"); |
125 | 164 |
126 // Already-delimited headers are passed through. | 165 // Already-delimited headers are passed through. |
127 decoder_peer_.HandleHeaderRepresentation("passed-through", | 166 decoder_peer_.HandleHeaderRepresentation("passed-through", |
(...skipping 30 matching lines...) Expand all Loading... |
158 } | 197 } |
159 | 198 |
160 // Decoding an encoded name with a valid string literal should work. | 199 // Decoding an encoded name with a valid string literal should work. |
161 TEST_P(HpackDecoderTest, DecodeNextNameLiteral) { | 200 TEST_P(HpackDecoderTest, DecodeNextNameLiteral) { |
162 HpackInputStream input_stream(kLiteralBound, StringPiece("\x00\x04name", 6)); | 201 HpackInputStream input_stream(kLiteralBound, StringPiece("\x00\x04name", 6)); |
163 | 202 |
164 StringPiece string_piece; | 203 StringPiece string_piece; |
165 EXPECT_TRUE(decoder_peer_.DecodeNextName(&input_stream, &string_piece)); | 204 EXPECT_TRUE(decoder_peer_.DecodeNextName(&input_stream, &string_piece)); |
166 EXPECT_EQ("name", string_piece); | 205 EXPECT_EQ("name", string_piece); |
167 EXPECT_FALSE(input_stream.HasMoreData()); | 206 EXPECT_FALSE(input_stream.HasMoreData()); |
| 207 EXPECT_FALSE(input_stream.NeedMoreData()); |
| 208 input_stream.MarkCurrentPosition(); |
| 209 EXPECT_EQ(6u, input_stream.ParsedBytes()); |
| 210 } |
| 211 |
| 212 // Decoding an encoded name with an incomplete string literal. |
| 213 TEST_P(HpackDecoderTest, DecodeNextNameLiteralWithIncompleteHeader) { |
| 214 HpackInputStream input_stream(kLiteralBound, |
| 215 StringPiece("\x00\x04name\x00\x02g", 9)); |
| 216 |
| 217 StringPiece string_piece; |
| 218 EXPECT_TRUE(decoder_peer_.DecodeNextName(&input_stream, &string_piece)); |
| 219 EXPECT_FALSE(input_stream.NeedMoreData()); |
| 220 input_stream.MarkCurrentPosition(); |
| 221 EXPECT_EQ(6u, input_stream.ParsedBytes()); |
| 222 |
| 223 EXPECT_FALSE(decoder_peer_.DecodeNextName(&input_stream, &string_piece)); |
| 224 EXPECT_TRUE(input_stream.NeedMoreData()); |
| 225 input_stream.MarkCurrentPosition(); |
| 226 EXPECT_EQ(8u, input_stream.ParsedBytes()); |
168 } | 227 } |
169 | 228 |
170 TEST_P(HpackDecoderTest, DecodeNextNameLiteralWithHuffmanEncoding) { | 229 TEST_P(HpackDecoderTest, DecodeNextNameLiteralWithHuffmanEncoding) { |
171 string input = a2b_hex("008825a849e95ba97d7f"); | 230 string input = a2b_hex("008825a849e95ba97d7f"); |
172 HpackInputStream input_stream(kLiteralBound, input); | 231 HpackInputStream input_stream(kLiteralBound, input); |
173 | 232 |
174 StringPiece string_piece; | 233 StringPiece string_piece; |
175 EXPECT_TRUE(decoder_peer_.DecodeNextName(&input_stream, &string_piece)); | 234 EXPECT_TRUE(decoder_peer_.DecodeNextName(&input_stream, &string_piece)); |
176 EXPECT_EQ("custom-key", string_piece); | 235 EXPECT_EQ("custom-key", string_piece); |
177 EXPECT_FALSE(input_stream.HasMoreData()); | 236 EXPECT_FALSE(input_stream.HasMoreData()); |
| 237 EXPECT_FALSE(input_stream.NeedMoreData()); |
| 238 input_stream.MarkCurrentPosition(); |
| 239 EXPECT_EQ(input.size(), input_stream.ParsedBytes()); |
| 240 } |
| 241 |
| 242 // Decode with incomplete huffman encoding. |
| 243 TEST_P(HpackDecoderTest, DecodeNextNameLiteralWithIncompleteHuffmanEncoding) { |
| 244 // CHECK(huffman_table_.Initialize(kHpackHuffmanCode, |
| 245 // arraysize(kHpackHuffmanCode))); |
| 246 // Put two copies of the same huffman encoding into input. |
| 247 string input = a2b_hex("008825a849e95ba97d7f008825a849e95ba97d7f"); |
| 248 input.resize(input.size() - 1); // Remove the last byte. |
| 249 HpackInputStream input_stream(kLiteralBound, input); |
| 250 |
| 251 StringPiece string_piece; |
| 252 EXPECT_TRUE(decoder_peer_.DecodeNextName(&input_stream, &string_piece)); |
| 253 EXPECT_FALSE(input_stream.NeedMoreData()); |
| 254 input_stream.MarkCurrentPosition(); |
| 255 EXPECT_EQ(10u, input_stream.ParsedBytes()); |
| 256 |
| 257 EXPECT_FALSE(decoder_peer_.DecodeNextName(&input_stream, &string_piece)); |
| 258 EXPECT_TRUE(input_stream.NeedMoreData()); |
| 259 input_stream.MarkCurrentPosition(); |
| 260 EXPECT_EQ(12u, input_stream.ParsedBytes()); |
178 } | 261 } |
179 | 262 |
180 // Decoding an encoded name with a valid index should work. | 263 // Decoding an encoded name with a valid index should work. |
181 TEST_P(HpackDecoderTest, DecodeNextNameIndexed) { | 264 TEST_P(HpackDecoderTest, DecodeNextNameIndexed) { |
182 HpackInputStream input_stream(kLiteralBound, "\x01"); | 265 HpackInputStream input_stream(kLiteralBound, "\x01"); |
183 | 266 |
184 StringPiece string_piece; | 267 StringPiece string_piece; |
185 EXPECT_TRUE(decoder_peer_.DecodeNextName(&input_stream, &string_piece)); | 268 EXPECT_TRUE(decoder_peer_.DecodeNextName(&input_stream, &string_piece)); |
186 EXPECT_EQ(":authority", string_piece); | 269 EXPECT_EQ(":authority", string_piece); |
187 EXPECT_FALSE(input_stream.HasMoreData()); | 270 EXPECT_FALSE(input_stream.HasMoreData()); |
| 271 EXPECT_FALSE(input_stream.NeedMoreData()); |
| 272 input_stream.MarkCurrentPosition(); |
| 273 EXPECT_EQ(1u, input_stream.ParsedBytes()); |
188 } | 274 } |
189 | 275 |
190 // Decoding an encoded name with an invalid index should fail. | 276 // Decoding an encoded name with an invalid index should fail. |
191 TEST_P(HpackDecoderTest, DecodeNextNameInvalidIndex) { | 277 TEST_P(HpackDecoderTest, DecodeNextNameInvalidIndex) { |
192 // One more than the number of static table entries. | 278 // One more than the number of static table entries. |
193 HpackInputStream input_stream(kLiteralBound, "\x3e"); | 279 HpackInputStream input_stream(kLiteralBound, "\x3e"); |
194 | 280 |
195 StringPiece string_piece; | 281 StringPiece string_piece; |
196 EXPECT_FALSE(decoder_peer_.DecodeNextName(&input_stream, &string_piece)); | 282 EXPECT_FALSE(decoder_peer_.DecodeNextName(&input_stream, &string_piece)); |
| 283 EXPECT_FALSE(input_stream.NeedMoreData()); |
| 284 input_stream.MarkCurrentPosition(); |
| 285 EXPECT_EQ(1u, input_stream.ParsedBytes()); |
197 } | 286 } |
198 | 287 |
199 // Decoding indexed static table field should work. | 288 // Decoding indexed static table field should work. |
200 TEST_P(HpackDecoderTest, IndexedHeaderStatic) { | 289 TEST_P(HpackDecoderTest, IndexedHeaderStatic) { |
201 // Reference static table entries #2 and #5. | 290 // Reference static table entries #2 and #5. |
202 SpdyHeaderBlock header_set1 = DecodeBlockExpectingSuccess("\x82\x85"); | 291 SpdyHeaderBlock header_set1 = DecodeBlockExpectingSuccess("\x82\x85"); |
203 SpdyHeaderBlock expected_header_set1; | 292 SpdyHeaderBlock expected_header_set1; |
204 expected_header_set1[":method"] = "GET"; | 293 expected_header_set1[":method"] = "GET"; |
205 expected_header_set1[":path"] = "/index.html"; | 294 expected_header_set1[":path"] = "/index.html"; |
206 EXPECT_EQ(expected_header_set1, header_set1); | 295 EXPECT_EQ(expected_header_set1, header_set1); |
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
346 EXPECT_FALSE(DecodeHeaderBlock(StringPiece("\x0f\x2f\x03ooo"))); | 435 EXPECT_FALSE(DecodeHeaderBlock(StringPiece("\x0f\x2f\x03ooo"))); |
347 } | 436 } |
348 | 437 |
349 TEST_P(HpackDecoderTest, LiteralHeaderNeverIndexedInvalidNameIndex) { | 438 TEST_P(HpackDecoderTest, LiteralHeaderNeverIndexedInvalidNameIndex) { |
350 // Name is the last static index. Works. | 439 // Name is the last static index. Works. |
351 EXPECT_TRUE(DecodeHeaderBlock(StringPiece("\x1f\x2e\x03ooo"))); | 440 EXPECT_TRUE(DecodeHeaderBlock(StringPiece("\x1f\x2e\x03ooo"))); |
352 // Name is one beyond the last static index. Fails. | 441 // Name is one beyond the last static index. Fails. |
353 EXPECT_FALSE(DecodeHeaderBlock(StringPiece("\x1f\x2f\x03ooo"))); | 442 EXPECT_FALSE(DecodeHeaderBlock(StringPiece("\x1f\x2f\x03ooo"))); |
354 } | 443 } |
355 | 444 |
| 445 // Decode with incomplete string literal. |
| 446 TEST_P(HpackDecoderTest, StringLiteralIncomplete) { |
| 447 const char input[] = "\x0c/sample/path\x06:path2\x0e/sample/path/"; |
| 448 HpackInputStream input_stream(kLiteralBound, input); |
| 449 StringPiece str; |
| 450 EXPECT_TRUE( |
| 451 decoder_peer_.DecodeNextStringLiteral(&input_stream, false, &str)); |
| 452 EXPECT_FALSE(input_stream.NeedMoreData()); |
| 453 input_stream.MarkCurrentPosition(); |
| 454 EXPECT_EQ(13u, input_stream.ParsedBytes()); |
| 455 |
| 456 EXPECT_TRUE( |
| 457 decoder_peer_.DecodeNextStringLiteral(&input_stream, false, &str)); |
| 458 EXPECT_FALSE(input_stream.NeedMoreData()); |
| 459 input_stream.MarkCurrentPosition(); |
| 460 EXPECT_EQ(20u, input_stream.ParsedBytes()); |
| 461 |
| 462 EXPECT_FALSE( |
| 463 decoder_peer_.DecodeNextStringLiteral(&input_stream, false, &str)); |
| 464 EXPECT_TRUE(input_stream.NeedMoreData()); |
| 465 input_stream.MarkCurrentPosition(); |
| 466 EXPECT_EQ(21u, input_stream.ParsedBytes()); |
| 467 } |
| 468 |
356 // Round-tripping the header set from E.2.1 should work. | 469 // Round-tripping the header set from E.2.1 should work. |
357 TEST_P(HpackDecoderTest, BasicE21) { | 470 TEST_P(HpackDecoderTest, BasicE21) { |
358 HpackEncoder encoder(ObtainHpackHuffmanTable()); | 471 HpackEncoder encoder(ObtainHpackHuffmanTable()); |
359 | 472 |
360 SpdyHeaderBlock expected_header_set; | 473 SpdyHeaderBlock expected_header_set; |
361 expected_header_set[":method"] = "GET"; | 474 expected_header_set[":method"] = "GET"; |
362 expected_header_set[":scheme"] = "http"; | 475 expected_header_set[":scheme"] = "http"; |
363 expected_header_set[":path"] = "/"; | 476 expected_header_set[":path"] = "/"; |
364 expected_header_set[":authority"] = "www.example.com"; | 477 expected_header_set[":authority"] = "www.example.com"; |
365 | 478 |
(...skipping 291 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
657 "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU;" | 770 "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU;" |
658 " max-age=3600; version=1"); | 771 " max-age=3600; version=1"); |
659 expectEntry(63, 52, "content-encoding", "gzip"); | 772 expectEntry(63, 52, "content-encoding", "gzip"); |
660 expectEntry(64, 65, "date", "Mon, 21 Oct 2013 20:13:22 GMT"); | 773 expectEntry(64, 65, "date", "Mon, 21 Oct 2013 20:13:22 GMT"); |
661 EXPECT_EQ(215u, decoder_peer_.header_table()->size()); | 774 EXPECT_EQ(215u, decoder_peer_.header_table()->size()); |
662 } | 775 } |
663 | 776 |
664 } // namespace | 777 } // namespace |
665 } // namespace test | 778 } // namespace test |
666 } // namespace net | 779 } // namespace net |
OLD | NEW |