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

Side by Side Diff: net/http2/decoder/decode_http2_structures_test.cc

Issue 2554683003: Revert of Add new HTTP/2 and HPACK decoder in net/http2/. (Closed)
Patch Set: Created 4 years 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/http2/decoder/decode_http2_structures.cc ('k') | net/http2/decoder/decode_status.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 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
OLDNEW
« no previous file with comments | « net/http2/decoder/decode_http2_structures.cc ('k') | net/http2/decoder/decode_status.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698