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

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

Powered by Google App Engine
This is Rietveld 408576698