OLD | NEW |
| (Empty) |
1 // Copyright 2016 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/http2/decoder/decode_http2_structures.h" | |
6 | |
7 // Tests decoding all of the fixed size HTTP/2 structures (i.e. those defined | |
8 // in net/http2/http2_structures.h). | |
9 | |
10 // TODO(jamessynge): Combine tests of DoDecode, MaybeDecode, SlowDecode and | |
11 // Http2StructureDecoder test using gUnit's support for tests parameterized | |
12 // by type. | |
13 | |
14 #include <stddef.h> | |
15 #include <string> | |
16 | |
17 #include "base/bind.h" | |
18 #include "base/bind_helpers.h" | |
19 #include "base/logging.h" | |
20 #include "base/strings/string_piece.h" | |
21 #include "net/http2/decoder/decode_buffer.h" | |
22 #include "net/http2/decoder/decode_status.h" | |
23 #include "net/http2/http2_constants.h" | |
24 #include "net/http2/http2_structures_test_util.h" | |
25 #include "net/http2/tools/http2_frame_builder.h" | |
26 #include "net/http2/tools/random_decoder_test.h" | |
27 #include "testing/gtest/include/gtest/gtest.h" | |
28 | |
29 using ::testing::AssertionFailure; | |
30 using ::testing::AssertionResult; | |
31 using ::testing::AssertionSuccess; | |
32 using base::StringPiece; | |
33 using std::string; | |
34 | |
35 namespace net { | |
36 namespace test { | |
37 namespace { | |
38 | |
39 template <class S> | |
40 string SerializeStructure(const S& s) { | |
41 Http2FrameBuilder fb; | |
42 fb.Append(s); | |
43 EXPECT_EQ(S::EncodedSize(), fb.size()); | |
44 return fb.buffer(); | |
45 } | |
46 | |
47 template <class S> | |
48 class StructureDecoderTest : public RandomDecoderTest { | |
49 protected: | |
50 typedef S Structure; | |
51 | |
52 StructureDecoderTest() { | |
53 // IF the test adds more data after the encoded structure, stop as | |
54 // soon as the structure is decoded. | |
55 stop_decode_on_done_ = true; | |
56 } | |
57 | |
58 // Reset the decoding to the start of the structure, and overwrite the | |
59 // current contents of |structure_|, in to which we'll decode the buffer. | |
60 DecodeStatus StartDecoding(DecodeBuffer* b) override { | |
61 decode_offset_ = 0; | |
62 Randomize(&structure_); | |
63 return ResumeDecoding(b); | |
64 } | |
65 | |
66 DecodeStatus ResumeDecoding(DecodeBuffer* b) override { | |
67 // If we're at the start... | |
68 if (decode_offset_ == 0) { | |
69 const uint32_t start_offset = b->Offset(); | |
70 const char* const start_cursor = b->cursor(); | |
71 // ... attempt to decode the entire structure. | |
72 if (MaybeDecode(&structure_, b)) { | |
73 ++fast_decode_count_; | |
74 EXPECT_EQ(S::EncodedSize(), b->Offset() - start_offset); | |
75 | |
76 if (!HasFailure()) { | |
77 // Success. Confirm that SlowDecode produces the same result. | |
78 DecodeBuffer b2(start_cursor, b->Offset() - start_offset); | |
79 S second; | |
80 Randomize(&second); | |
81 uint32_t second_offset = 0; | |
82 EXPECT_TRUE(SlowDecode(&second, &b2, &second_offset)); | |
83 EXPECT_EQ(S::EncodedSize(), second_offset); | |
84 EXPECT_EQ(structure_, second); | |
85 } | |
86 | |
87 // Test can't easily tell if MaybeDecode or SlowDecode is used, so | |
88 // update decode_offset_ as if SlowDecode had been used to completely | |
89 // decode. | |
90 decode_offset_ = S::EncodedSize(); | |
91 return DecodeStatus::kDecodeDone; | |
92 } | |
93 } | |
94 | |
95 // We didn't have enough in the first buffer to decode everything, so we'll | |
96 // reach here multiple times until we've completely decoded the structure. | |
97 if (SlowDecode(&structure_, b, &decode_offset_)) { | |
98 ++slow_decode_count_; | |
99 EXPECT_EQ(S::EncodedSize(), decode_offset_); | |
100 return DecodeStatus::kDecodeDone; | |
101 } | |
102 | |
103 // Drained the input buffer, but not yet done. | |
104 EXPECT_TRUE(b->Empty()); | |
105 EXPECT_GT(S::EncodedSize(), decode_offset_); | |
106 | |
107 return DecodeStatus::kDecodeInProgress; | |
108 } | |
109 | |
110 // Set the fields of |*p| to random values. | |
111 void Randomize(S* p) { ::net::test::Randomize(p, RandomPtr()); } | |
112 | |
113 AssertionResult ValidatorForDecodeLeadingStructure(const S* expected, | |
114 const DecodeBuffer& db, | |
115 DecodeStatus status) { | |
116 if (expected != nullptr && *expected != structure_) { | |
117 return AssertionFailure() | |
118 << "Expected structs to be equal\nExpected: " << *expected | |
119 << "\n Actual: " << structure_; | |
120 } | |
121 return AssertionSuccess(); | |
122 } | |
123 | |
124 // Fully decodes the Structure at the start of data, and confirms it matches | |
125 // *expected (if provided). | |
126 void DecodeLeadingStructure(const S* expected, StringPiece data) { | |
127 ASSERT_LE(S::EncodedSize(), data.size()); | |
128 DecodeBuffer original(data); | |
129 | |
130 // The validator is called after each of the several times that the input | |
131 // DecodeBuffer is decoded, each with a different segmentation of the input. | |
132 // Validate that structure_ matches the expected value, if provided. | |
133 Validator validator = | |
134 base::Bind(&StructureDecoderTest::ValidatorForDecodeLeadingStructure, | |
135 base::Unretained(this), expected); | |
136 | |
137 // First validate that decoding is done and that we've advanced the cursor | |
138 // the expected amount. | |
139 Validator wrapped_validator = | |
140 ValidateDoneAndOffset(S::EncodedSize(), validator); | |
141 | |
142 // Decode several times, with several segmentations of the input buffer. | |
143 fast_decode_count_ = 0; | |
144 slow_decode_count_ = 0; | |
145 EXPECT_TRUE(DecodeAndValidateSeveralWays( | |
146 &original, false /*return_non_zero_on_first*/, wrapped_validator)); | |
147 | |
148 if (!HasFailure()) { | |
149 EXPECT_EQ(S::EncodedSize(), decode_offset_); | |
150 EXPECT_EQ(S::EncodedSize(), original.Offset()); | |
151 EXPECT_LT(0u, fast_decode_count_); | |
152 EXPECT_LT(0u, slow_decode_count_); | |
153 if (expected != nullptr) { | |
154 DVLOG(1) << "DecodeLeadingStructure expected: " << *expected; | |
155 DVLOG(1) << "DecodeLeadingStructure actual: " << structure_; | |
156 EXPECT_EQ(*expected, structure_); | |
157 } | |
158 } | |
159 } | |
160 | |
161 template <size_t N> | |
162 void DecodeLeadingStructure(const char (&data)[N]) { | |
163 DecodeLeadingStructure(nullptr, StringPiece(data, N)); | |
164 } | |
165 | |
166 // Encode the structure |in_s| into bytes, then decode the bytes | |
167 // and validate that the decoder produced the same field values. | |
168 void EncodeThenDecode(const S& in_s) { | |
169 string bytes = SerializeStructure(in_s); | |
170 EXPECT_EQ(S::EncodedSize(), bytes.size()); | |
171 DecodeLeadingStructure(&in_s, bytes); | |
172 } | |
173 | |
174 // Generate | |
175 void TestDecodingRandomizedStructures(size_t count) { | |
176 for (size_t i = 0; i < count && !HasFailure(); ++i) { | |
177 Structure input; | |
178 Randomize(&input); | |
179 EncodeThenDecode(input); | |
180 } | |
181 } | |
182 | |
183 uint32_t decode_offset_ = 0; | |
184 S structure_; | |
185 size_t fast_decode_count_ = 0; | |
186 size_t slow_decode_count_ = 0; | |
187 }; | |
188 | |
189 class FrameHeaderDecoderTest : public StructureDecoderTest<Http2FrameHeader> {}; | |
190 | |
191 TEST_F(FrameHeaderDecoderTest, DecodesLiteral) { | |
192 { | |
193 // Realistic input. | |
194 const char kData[] = { | |
195 0x00, 0x00, 0x05, // Payload length: 5 | |
196 0x01, // Frame type: HEADERS | |
197 0x08, // Flags: PADDED | |
198 0x00, 0x00, 0x00, 0x01, // Stream ID: 1 | |
199 0x04, // Padding length: 4 | |
200 0x00, 0x00, 0x00, 0x00, // Padding bytes | |
201 }; | |
202 DecodeLeadingStructure(kData); | |
203 if (!HasFailure()) { | |
204 EXPECT_EQ(5u, structure_.payload_length); | |
205 EXPECT_EQ(Http2FrameType::HEADERS, structure_.type); | |
206 EXPECT_EQ(Http2FrameFlag::FLAG_PADDED, structure_.flags); | |
207 EXPECT_EQ(1u, structure_.stream_id); | |
208 } | |
209 } | |
210 { | |
211 // Unlikely input. | |
212 const char kData[] = { | |
213 0xffu, 0xffu, 0xffu, // Payload length: uint24 max | |
214 0xffu, // Frame type: Unknown | |
215 0xffu, // Flags: Unknown/All | |
216 0xffu, 0xffu, 0xffu, 0xffu, // Stream ID: uint31 max, plus R-bit | |
217 }; | |
218 DecodeLeadingStructure(kData); | |
219 if (!HasFailure()) { | |
220 EXPECT_EQ((1u << 24) - 1, structure_.payload_length); | |
221 EXPECT_EQ(static_cast<Http2FrameType>(255), structure_.type); | |
222 EXPECT_EQ(255, structure_.flags); | |
223 EXPECT_EQ(0x7FFFFFFFu, structure_.stream_id); | |
224 } | |
225 } | |
226 } | |
227 | |
228 TEST_F(FrameHeaderDecoderTest, DecodesRandomized) { | |
229 TestDecodingRandomizedStructures(100); | |
230 } | |
231 | |
232 //------------------------------------------------------------------------------ | |
233 | |
234 class PriorityFieldsDecoderTest | |
235 : public StructureDecoderTest<Http2PriorityFields> {}; | |
236 | |
237 TEST_F(PriorityFieldsDecoderTest, DecodesLiteral) { | |
238 { | |
239 const char kData[] = { | |
240 0x80u, 0x00, 0x00, 0x05, // Exclusive (yes) and Dependency (5) | |
241 0xffu, // Weight: 256 (after adding 1) | |
242 }; | |
243 DecodeLeadingStructure(kData); | |
244 if (!HasFailure()) { | |
245 EXPECT_EQ(5u, structure_.stream_dependency); | |
246 EXPECT_EQ(256u, structure_.weight); | |
247 EXPECT_EQ(true, structure_.is_exclusive); | |
248 } | |
249 } | |
250 { | |
251 const char kData[] = { | |
252 0x7f, 0xffu, | |
253 0xffu, 0xffu, // Exclusive (no) and Dependency (0x7fffffff) | |
254 0x00, // Weight: 1 (after adding 1) | |
255 }; | |
256 DecodeLeadingStructure(kData); | |
257 if (!HasFailure()) { | |
258 EXPECT_EQ(StreamIdMask(), structure_.stream_dependency); | |
259 EXPECT_EQ(1u, structure_.weight); | |
260 EXPECT_FALSE(structure_.is_exclusive); | |
261 } | |
262 } | |
263 } | |
264 | |
265 TEST_F(PriorityFieldsDecoderTest, DecodesRandomized) { | |
266 TestDecodingRandomizedStructures(100); | |
267 } | |
268 | |
269 //------------------------------------------------------------------------------ | |
270 | |
271 class RstStreamFieldsDecoderTest | |
272 : public StructureDecoderTest<Http2RstStreamFields> {}; | |
273 | |
274 TEST_F(RstStreamFieldsDecoderTest, DecodesLiteral) { | |
275 { | |
276 const char kData[] = { | |
277 0x00, 0x00, 0x00, 0x01, // Error: PROTOCOL_ERROR | |
278 }; | |
279 DecodeLeadingStructure(kData); | |
280 if (!HasFailure()) { | |
281 EXPECT_TRUE(structure_.IsSupportedErrorCode()); | |
282 EXPECT_EQ(Http2ErrorCode::PROTOCOL_ERROR, structure_.error_code); | |
283 } | |
284 } | |
285 { | |
286 const char kData[] = { | |
287 0xffu, 0xffu, 0xffu, 0xffu, // Error: max uint32 (Unknown error code) | |
288 }; | |
289 DecodeLeadingStructure(kData); | |
290 if (!HasFailure()) { | |
291 EXPECT_FALSE(structure_.IsSupportedErrorCode()); | |
292 EXPECT_EQ(static_cast<Http2ErrorCode>(0xffffffff), structure_.error_code); | |
293 } | |
294 } | |
295 } | |
296 | |
297 TEST_F(RstStreamFieldsDecoderTest, DecodesRandomized) { | |
298 TestDecodingRandomizedStructures(100); | |
299 } | |
300 | |
301 //------------------------------------------------------------------------------ | |
302 | |
303 class SettingFieldsDecoderTest | |
304 : public StructureDecoderTest<Http2SettingFields> {}; | |
305 | |
306 TEST_F(SettingFieldsDecoderTest, DecodesLiteral) { | |
307 { | |
308 const char kData[] = { | |
309 0x00, 0x01, // Setting: HEADER_TABLE_SIZE | |
310 0x00, 0x00, 0x40, 0x00, // Value: 16K | |
311 }; | |
312 DecodeLeadingStructure(kData); | |
313 if (!HasFailure()) { | |
314 EXPECT_TRUE(structure_.IsSupportedParameter()); | |
315 EXPECT_EQ(Http2SettingsParameter::HEADER_TABLE_SIZE, | |
316 structure_.parameter); | |
317 EXPECT_EQ(1u << 14, structure_.value); | |
318 } | |
319 } | |
320 { | |
321 const char kData[] = { | |
322 0x00, 0x00, // Setting: Unknown (0) | |
323 0xffu, 0xffu, 0xffu, 0xffu, // Value: max uint32 | |
324 }; | |
325 DecodeLeadingStructure(kData); | |
326 if (!HasFailure()) { | |
327 EXPECT_FALSE(structure_.IsSupportedParameter()); | |
328 EXPECT_EQ(static_cast<Http2SettingsParameter>(0), structure_.parameter); | |
329 } | |
330 } | |
331 } | |
332 | |
333 TEST_F(SettingFieldsDecoderTest, DecodesRandomized) { | |
334 TestDecodingRandomizedStructures(100); | |
335 } | |
336 | |
337 //------------------------------------------------------------------------------ | |
338 | |
339 class PushPromiseFieldsDecoderTest | |
340 : public StructureDecoderTest<Http2PushPromiseFields> {}; | |
341 | |
342 TEST_F(PushPromiseFieldsDecoderTest, DecodesLiteral) { | |
343 { | |
344 const char kData[] = { | |
345 0x00, 0x01, 0x8au, 0x92u, // Promised Stream ID: 101010 | |
346 }; | |
347 DecodeLeadingStructure(kData); | |
348 if (!HasFailure()) { | |
349 EXPECT_EQ(101010u, structure_.promised_stream_id); | |
350 } | |
351 } | |
352 { | |
353 // Promised stream id has R-bit (reserved for future use) set, which | |
354 // should be cleared by the decoder. | |
355 const char kData[] = { | |
356 0xffu, 0xffu, 0xffu, 0xffu, // Promised Stream ID: max uint31 and R-bit | |
357 }; | |
358 DecodeLeadingStructure(kData); | |
359 if (!HasFailure()) { | |
360 EXPECT_EQ(StreamIdMask(), structure_.promised_stream_id); | |
361 } | |
362 } | |
363 } | |
364 | |
365 TEST_F(PushPromiseFieldsDecoderTest, DecodesRandomized) { | |
366 TestDecodingRandomizedStructures(100); | |
367 } | |
368 | |
369 //------------------------------------------------------------------------------ | |
370 | |
371 class PingFieldsDecoderTest : public StructureDecoderTest<Http2PingFields> {}; | |
372 | |
373 TEST_F(PingFieldsDecoderTest, DecodesLiteral) { | |
374 { | |
375 // Each byte is different, so can detect if order changed. | |
376 const char kData[] = { | |
377 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, | |
378 }; | |
379 DecodeLeadingStructure(kData); | |
380 if (!HasFailure()) { | |
381 EXPECT_EQ(StringPiece(kData, 8), ToStringPiece(structure_.opaque_data)); | |
382 } | |
383 } | |
384 { | |
385 // All zeros, detect problems handling NULs. | |
386 const char kData[] = { | |
387 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
388 }; | |
389 DecodeLeadingStructure(kData); | |
390 if (!HasFailure()) { | |
391 EXPECT_EQ(StringPiece(kData, 8), ToStringPiece(structure_.opaque_data)); | |
392 } | |
393 } | |
394 { | |
395 const char kData[] = { | |
396 0xffu, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu, | |
397 }; | |
398 DecodeLeadingStructure(kData); | |
399 if (!HasFailure()) { | |
400 EXPECT_EQ(StringPiece(kData, 8), ToStringPiece(structure_.opaque_data)); | |
401 } | |
402 } | |
403 } | |
404 | |
405 TEST_F(PingFieldsDecoderTest, DecodesRandomized) { | |
406 TestDecodingRandomizedStructures(100); | |
407 } | |
408 | |
409 //------------------------------------------------------------------------------ | |
410 | |
411 class GoAwayFieldsDecoderTest : public StructureDecoderTest<Http2GoAwayFields> { | |
412 }; | |
413 | |
414 TEST_F(GoAwayFieldsDecoderTest, DecodesLiteral) { | |
415 { | |
416 const char kData[] = { | |
417 0x00, 0x00, 0x00, 0x00, // Last Stream ID: 0 | |
418 0x00, 0x00, 0x00, 0x00, // Error: NO_ERROR (0) | |
419 }; | |
420 DecodeLeadingStructure(kData); | |
421 if (!HasFailure()) { | |
422 EXPECT_EQ(0u, structure_.last_stream_id); | |
423 EXPECT_TRUE(structure_.IsSupportedErrorCode()); | |
424 EXPECT_EQ(Http2ErrorCode::HTTP2_NO_ERROR, structure_.error_code); | |
425 } | |
426 } | |
427 { | |
428 const char kData[] = { | |
429 0x00, 0x00, 0x00, 0x01, // Last Stream ID: 1 | |
430 0x00, 0x00, 0x00, 0x0d, // Error: HTTP_1_1_REQUIRED | |
431 }; | |
432 DecodeLeadingStructure(kData); | |
433 if (!HasFailure()) { | |
434 EXPECT_EQ(1u, structure_.last_stream_id); | |
435 EXPECT_TRUE(structure_.IsSupportedErrorCode()); | |
436 EXPECT_EQ(Http2ErrorCode::HTTP_1_1_REQUIRED, structure_.error_code); | |
437 } | |
438 } | |
439 { | |
440 const char kData[] = { | |
441 0xffu, 0xffu, 0xffu, 0xffu, // Last Stream ID: max uint31 and R-bit | |
442 0xffu, 0xffu, 0xffu, 0xffu, // Error: max uint32 (Unknown error code) | |
443 }; | |
444 DecodeLeadingStructure(kData); | |
445 if (!HasFailure()) { | |
446 EXPECT_EQ(StreamIdMask(), structure_.last_stream_id); // No high-bit. | |
447 EXPECT_FALSE(structure_.IsSupportedErrorCode()); | |
448 EXPECT_EQ(static_cast<Http2ErrorCode>(0xffffffff), structure_.error_code); | |
449 } | |
450 } | |
451 } | |
452 | |
453 TEST_F(GoAwayFieldsDecoderTest, DecodesRandomized) { | |
454 TestDecodingRandomizedStructures(100); | |
455 } | |
456 | |
457 //------------------------------------------------------------------------------ | |
458 | |
459 class WindowUpdateFieldsDecoderTest | |
460 : public StructureDecoderTest<Http2WindowUpdateFields> {}; | |
461 | |
462 TEST_F(WindowUpdateFieldsDecoderTest, DecodesLiteral) { | |
463 { | |
464 const char kData[] = { | |
465 0x00, 0x01, 0x00, 0x00, // Window Size Increment: 2 ^ 16 | |
466 }; | |
467 DecodeLeadingStructure(kData); | |
468 if (!HasFailure()) { | |
469 EXPECT_EQ(1u << 16, structure_.window_size_increment); | |
470 } | |
471 } | |
472 { | |
473 // Increment must be non-zero, but we need to be able to decode the invalid | |
474 // zero to detect it. | |
475 const char kData[] = { | |
476 0x00, 0x00, 0x00, 0x00, // Window Size Increment: 0 | |
477 }; | |
478 DecodeLeadingStructure(kData); | |
479 if (!HasFailure()) { | |
480 EXPECT_EQ(0u, structure_.window_size_increment); | |
481 } | |
482 } | |
483 { | |
484 // Increment has R-bit (reserved for future use) set, which | |
485 // should be cleared by the decoder. | |
486 const char kData[] = { | |
487 0xffu, 0xffu, 0xffu, | |
488 0xffu, // Window Size Increment: max uint31 and R-bit | |
489 }; | |
490 DecodeLeadingStructure(kData); | |
491 if (!HasFailure()) { | |
492 EXPECT_EQ(StreamIdMask(), structure_.window_size_increment); | |
493 } | |
494 } | |
495 } | |
496 | |
497 TEST_F(WindowUpdateFieldsDecoderTest, DecodesRandomized) { | |
498 TestDecodingRandomizedStructures(100); | |
499 } | |
500 | |
501 //------------------------------------------------------------------------------ | |
502 | |
503 class AltSvcFieldsDecoderTest : public StructureDecoderTest<Http2AltSvcFields> { | |
504 }; | |
505 | |
506 TEST_F(AltSvcFieldsDecoderTest, DecodesLiteral) { | |
507 { | |
508 const char kData[] = { | |
509 0x00, 0x00, // Origin Length: 0 | |
510 }; | |
511 DecodeLeadingStructure(kData); | |
512 if (!HasFailure()) { | |
513 EXPECT_EQ(0, structure_.origin_length); | |
514 } | |
515 } | |
516 { | |
517 const char kData[] = { | |
518 0x00, 0x14, // Origin Length: 20 | |
519 }; | |
520 DecodeLeadingStructure(kData); | |
521 if (!HasFailure()) { | |
522 EXPECT_EQ(20, structure_.origin_length); | |
523 } | |
524 } | |
525 { | |
526 const char kData[] = { | |
527 0xffu, 0xffu, // Origin Length: uint16 max | |
528 }; | |
529 DecodeLeadingStructure(kData); | |
530 if (!HasFailure()) { | |
531 EXPECT_EQ(65535, structure_.origin_length); | |
532 } | |
533 } | |
534 } | |
535 | |
536 TEST_F(AltSvcFieldsDecoderTest, DecodesRandomized) { | |
537 TestDecodingRandomizedStructures(100); | |
538 } | |
539 | |
540 } // namespace | |
541 } // namespace test | |
542 } // namespace net | |
OLD | NEW |