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