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

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

Issue 1914193002: Implements incremental decode in HPACK. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 7 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.cc ('k') | net/spdy/hpack/hpack_input_stream.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
OLDNEW
« no previous file with comments | « net/spdy/hpack/hpack_decoder.cc ('k') | net/spdy/hpack/hpack_input_stream.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698