Index: net/http2/decoder/http2_structure_decoder_test.cc |
diff --git a/net/http2/decoder/http2_structure_decoder_test.cc b/net/http2/decoder/http2_structure_decoder_test.cc |
deleted file mode 100644 |
index 68479a167dd40d51f9133264a634927a2430326f..0000000000000000000000000000000000000000 |
--- a/net/http2/decoder/http2_structure_decoder_test.cc |
+++ /dev/null |
@@ -1,512 +0,0 @@ |
-// Copyright 2016 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include "net/http2/decoder/http2_structure_decoder.h" |
- |
-// Tests decoding all of the fixed size HTTP/2 structures (i.e. those defined in |
-// net/http2/http2_structures.h) using Http2StructureDecoder, which handles |
-// buffering of structures split across input buffer boundaries, and in turn |
-// uses DoDecode when it has all of a structure in a contiguous buffer. |
- |
-// NOTE: This tests the first pair of Start and Resume, which don't take |
-// a remaining_payload parameter. The other pair are well tested via the |
-// payload decoder tests, though... |
-// TODO(jamessynge): Create type parameterized tests for Http2StructureDecoder |
-// where the type is the type of structure, and with testing of both pairs of |
-// Start and Resume methods; note that it appears that the first pair will be |
-// used only for Http2FrameHeader, and the other pair only for structures in the |
-// frame payload. |
- |
-#include <stddef.h> |
-#include <string> |
- |
-#include "base/bind.h" |
-#include "base/bind_helpers.h" |
-#include "base/logging.h" |
-#include "base/strings/string_piece.h" |
-#include "net/http2/decoder/decode_buffer.h" |
-#include "net/http2/decoder/decode_status.h" |
-#include "net/http2/http2_constants.h" |
-#include "net/http2/http2_structures_test_util.h" |
-#include "net/http2/tools/failure.h" |
-#include "net/http2/tools/http2_frame_builder.h" |
-#include "net/http2/tools/random_decoder_test.h" |
-#include "testing/gtest/include/gtest/gtest.h" |
- |
-using ::testing::AssertionFailure; |
-using ::testing::AssertionResult; |
-using ::testing::AssertionSuccess; |
-using base::StringPiece; |
-using std::string; |
- |
-namespace net { |
-namespace test { |
-namespace { |
-const bool kMayReturnZeroOnFirst = false; |
- |
-template <class S> |
-string SerializeStructure(const S& s) { |
- Http2FrameBuilder fb; |
- fb.Append(s); |
- EXPECT_EQ(S::EncodedSize(), fb.size()); |
- return fb.buffer(); |
-} |
- |
-template <class S> |
-class Http2StructureDecoderTest : public RandomDecoderTest { |
- protected: |
- typedef S Structure; |
- |
- Http2StructureDecoderTest() { |
- // IF the test adds more data after the encoded structure, stop as |
- // soon as the structure is decoded. |
- stop_decode_on_done_ = true; |
- } |
- |
- DecodeStatus StartDecoding(DecodeBuffer* b) override { |
- // Overwrite the current contents of |structure_|, in to which we'll |
- // decode the buffer, so that we can be confident that we really decoded |
- // the structure every time. |
- structure_.~S(); |
- new (&structure_) S; |
- uint32_t old_remaining = b->Remaining(); |
- if (structure_decoder_.Start(&structure_, b)) { |
- EXPECT_EQ(old_remaining - S::EncodedSize(), b->Remaining()); |
- ++fast_decode_count_; |
- return DecodeStatus::kDecodeDone; |
- } else { |
- EXPECT_LT(structure_decoder_.offset(), S::EncodedSize()); |
- EXPECT_EQ(0u, b->Remaining()); |
- EXPECT_EQ(old_remaining - structure_decoder_.offset(), b->Remaining()); |
- ++incomplete_start_count_; |
- return DecodeStatus::kDecodeInProgress; |
- } |
- } |
- |
- DecodeStatus ResumeDecoding(DecodeBuffer* b) override { |
- uint32_t old_offset = structure_decoder_.offset(); |
- EXPECT_LT(old_offset, S::EncodedSize()); |
- uint32_t avail = b->Remaining(); |
- if (structure_decoder_.Resume(&structure_, b)) { |
- EXPECT_LE(S::EncodedSize(), old_offset + avail); |
- EXPECT_EQ(b->Remaining(), avail - (S::EncodedSize() - old_offset)); |
- ++slow_decode_count_; |
- return DecodeStatus::kDecodeDone; |
- } else { |
- EXPECT_LT(structure_decoder_.offset(), S::EncodedSize()); |
- EXPECT_EQ(0u, b->Remaining()); |
- EXPECT_GT(S::EncodedSize(), old_offset + avail); |
- ++incomplete_resume_count_; |
- return DecodeStatus::kDecodeInProgress; |
- } |
- } |
- |
- AssertionResult ValidatorForDecodeLeadingStructure(const S* expected, |
- const DecodeBuffer& db, |
- DecodeStatus status) { |
- VERIFY_EQ(*expected, structure_); |
- return AssertionSuccess(); |
- } |
- |
- // Fully decodes the Structure at the start of data, and confirms it matches |
- // *expected (if provided). |
- AssertionResult DecodeLeadingStructure(const S* expected, StringPiece data) { |
- VERIFY_LE(S::EncodedSize(), data.size()); |
- DecodeBuffer original(data); |
- |
- // The validator is called after each of the several times that the input |
- // DecodeBuffer is decoded, each with a different segmentation of the input. |
- // Validate that structure_ matches the expected value, if provided. |
- Validator validator = |
- (expected == nullptr) |
- ? base::Bind(&SucceedingValidator) |
- : base::Bind(&Http2StructureDecoderTest:: |
- ValidatorForDecodeLeadingStructure, |
- base::Unretained(this), expected); |
- |
- // Before that, validate that decoding is done and that we've advanced |
- // the cursor the expected amount. |
- Validator wrapped_validator = |
- ValidateDoneAndOffset(S::EncodedSize(), validator); |
- |
- // Decode several times, with several segmentations of the input buffer. |
- fast_decode_count_ = 0; |
- slow_decode_count_ = 0; |
- incomplete_start_count_ = 0; |
- incomplete_resume_count_ = 0; |
- VERIFY_SUCCESS(DecodeAndValidateSeveralWays( |
- &original, kMayReturnZeroOnFirst, wrapped_validator)); |
- VERIFY_FALSE(HasFailure()); |
- VERIFY_EQ(S::EncodedSize(), structure_decoder_.offset()); |
- VERIFY_EQ(S::EncodedSize(), original.Offset()); |
- VERIFY_LT(0u, fast_decode_count_); |
- VERIFY_LT(0u, slow_decode_count_); |
- VERIFY_LT(0u, incomplete_start_count_); |
- |
- // If the structure is large enough so that SelectZeroOrOne will have |
- // caused Resume to return false, check that occurred. |
- if (S::EncodedSize() >= 2) { |
- VERIFY_LE(0u, incomplete_resume_count_); |
- } else { |
- VERIFY_EQ(0u, incomplete_resume_count_); |
- } |
- if (expected != nullptr) { |
- DVLOG(1) << "DecodeLeadingStructure expected: " << *expected; |
- DVLOG(1) << "DecodeLeadingStructure actual: " << structure_; |
- VERIFY_EQ(*expected, structure_); |
- } |
- return AssertionSuccess(); |
- } |
- |
- template <size_t N> |
- AssertionResult DecodeLeadingStructure(const char (&data)[N]) { |
- VERIFY_AND_RETURN_SUCCESS( |
- DecodeLeadingStructure(nullptr, StringPiece(data, N))); |
- } |
- |
- // Encode the structure |in_s| into bytes, then decode the bytes |
- // and validate that the decoder produced the same field values. |
- AssertionResult EncodeThenDecode(const S& in_s) { |
- string bytes = SerializeStructure(in_s); |
- VERIFY_EQ(S::EncodedSize(), bytes.size()); |
- VERIFY_AND_RETURN_SUCCESS(DecodeLeadingStructure(&in_s, bytes)); |
- } |
- |
- // Repeatedly fill a structure with random but valid contents, encode it, then |
- // decode it, and finally validate that the decoded structure matches the |
- // random input. Lather-rinse-and-repeat. |
- AssertionResult TestDecodingRandomizedStructures(size_t count) { |
- for (size_t i = 0; i < count; ++i) { |
- Structure input; |
- Randomize(&input, RandomPtr()); |
- VERIFY_SUCCESS(EncodeThenDecode(input)); |
- } |
- return AssertionSuccess(); |
- } |
- |
- AssertionResult TestDecodingRandomizedStructures() { |
- VERIFY_SUCCESS(TestDecodingRandomizedStructures(100)); |
- return AssertionSuccess(); |
- } |
- |
- uint32_t decode_offset_ = 0; |
- S structure_; |
- Http2StructureDecoder structure_decoder_; |
- size_t fast_decode_count_ = 0; |
- size_t slow_decode_count_ = 0; |
- size_t incomplete_start_count_ = 0; |
- size_t incomplete_resume_count_ = 0; |
-}; |
- |
-class Http2FrameHeaderDecoderTest |
- : public Http2StructureDecoderTest<Http2FrameHeader> {}; |
- |
-TEST_F(Http2FrameHeaderDecoderTest, DecodesLiteral) { |
- { |
- // Realistic input. |
- const char kData[] = { |
- 0x00, 0x00, 0x05, // Payload length: 5 |
- 0x01, // Frame type: HEADERS |
- 0x08, // Flags: PADDED |
- 0x00, 0x00, 0x00, 0x01, // Stream ID: 1 |
- 0x04, // Padding length: 4 |
- 0x00, 0x00, 0x00, 0x00, // Padding bytes |
- }; |
- ASSERT_TRUE(DecodeLeadingStructure(kData)); |
- EXPECT_EQ(5u, structure_.payload_length); |
- EXPECT_EQ(Http2FrameType::HEADERS, structure_.type); |
- EXPECT_EQ(Http2FrameFlag::FLAG_PADDED, structure_.flags); |
- EXPECT_EQ(1u, structure_.stream_id); |
- } |
- { |
- // Unlikely input. |
- const char kData[] = { |
- 0xffu, 0xffu, 0xffu, // Payload length: uint24 max |
- 0xffu, // Frame type: Unknown |
- 0xffu, // Flags: Unknown/All |
- 0xffu, 0xffu, 0xffu, 0xffu, // Stream ID: uint31 max, plus R-bit |
- }; |
- ASSERT_TRUE(DecodeLeadingStructure(kData)); |
- EXPECT_EQ((1u << 24) - 1u, structure_.payload_length); |
- EXPECT_EQ(static_cast<Http2FrameType>(255), structure_.type); |
- EXPECT_EQ(255, structure_.flags); |
- EXPECT_EQ(0x7FFFFFFFu, structure_.stream_id); |
- } |
-} |
- |
-TEST_F(Http2FrameHeaderDecoderTest, DecodesRandomized) { |
- TestDecodingRandomizedStructures(); |
-} |
- |
-//------------------------------------------------------------------------------ |
- |
-class Http2PriorityFieldsDecoderTest |
- : public Http2StructureDecoderTest<Http2PriorityFields> {}; |
- |
-TEST_F(Http2PriorityFieldsDecoderTest, DecodesLiteral) { |
- { |
- const char kData[] = { |
- 0x80u, 0x00, 0x00, 0x05, // Exclusive (yes) and Dependency (5) |
- 0xffu, // Weight: 256 (after adding 1) |
- }; |
- ASSERT_TRUE(DecodeLeadingStructure(kData)); |
- EXPECT_EQ(5u, structure_.stream_dependency); |
- EXPECT_EQ(256u, structure_.weight); |
- EXPECT_EQ(true, structure_.is_exclusive); |
- } |
- { |
- const char kData[] = { |
- 0x7fu, 0xffu, |
- 0xffu, 0xffu, // Exclusive (no) and Dependency (0x7fffffff) |
- 0x00u, // Weight: 1 (after adding 1) |
- }; |
- ASSERT_TRUE(DecodeLeadingStructure(kData)); |
- EXPECT_EQ(StreamIdMask(), structure_.stream_dependency); |
- EXPECT_EQ(1u, structure_.weight); |
- EXPECT_FALSE(structure_.is_exclusive); |
- } |
-} |
- |
-TEST_F(Http2PriorityFieldsDecoderTest, DecodesRandomized) { |
- TestDecodingRandomizedStructures(); |
-} |
- |
-//------------------------------------------------------------------------------ |
- |
-class Http2RstStreamFieldsDecoderTest |
- : public Http2StructureDecoderTest<Http2RstStreamFields> {}; |
- |
-TEST_F(Http2RstStreamFieldsDecoderTest, DecodesLiteral) { |
- { |
- const char kData[] = { |
- 0x00, 0x00, 0x00, 0x01, // Error: PROTOCOL_ERROR |
- }; |
- ASSERT_TRUE(DecodeLeadingStructure(kData)); |
- EXPECT_TRUE(structure_.IsSupportedErrorCode()); |
- EXPECT_EQ(Http2ErrorCode::PROTOCOL_ERROR, structure_.error_code); |
- } |
- { |
- const char kData[] = { |
- 0xffu, 0xffu, 0xffu, 0xffu, // Error: max uint32 (Unknown error code) |
- }; |
- ASSERT_TRUE(DecodeLeadingStructure(kData)); |
- EXPECT_FALSE(structure_.IsSupportedErrorCode()); |
- EXPECT_EQ(static_cast<Http2ErrorCode>(0xffffffff), structure_.error_code); |
- } |
-} |
- |
-TEST_F(Http2RstStreamFieldsDecoderTest, DecodesRandomized) { |
- TestDecodingRandomizedStructures(); |
-} |
- |
-//------------------------------------------------------------------------------ |
- |
-class Http2SettingFieldsDecoderTest |
- : public Http2StructureDecoderTest<Http2SettingFields> {}; |
- |
-TEST_F(Http2SettingFieldsDecoderTest, DecodesLiteral) { |
- { |
- const char kData[] = { |
- 0x00, 0x01, // Setting: HEADER_TABLE_SIZE |
- 0x00, 0x00, 0x40, 0x00, // Value: 16K |
- }; |
- ASSERT_TRUE(DecodeLeadingStructure(kData)); |
- EXPECT_TRUE(structure_.IsSupportedParameter()); |
- EXPECT_EQ(Http2SettingsParameter::HEADER_TABLE_SIZE, structure_.parameter); |
- EXPECT_EQ(1u << 14, structure_.value); |
- } |
- { |
- const char kData[] = { |
- 0x00, 0x00, // Setting: Unknown (0) |
- 0xffu, 0xffu, 0xffu, 0xffu, // Value: max uint32 |
- }; |
- ASSERT_TRUE(DecodeLeadingStructure(kData)); |
- EXPECT_FALSE(structure_.IsSupportedParameter()); |
- EXPECT_EQ(static_cast<Http2SettingsParameter>(0), structure_.parameter); |
- } |
-} |
- |
-TEST_F(Http2SettingFieldsDecoderTest, DecodesRandomized) { |
- TestDecodingRandomizedStructures(); |
-} |
- |
-//------------------------------------------------------------------------------ |
- |
-class Http2PushPromiseFieldsDecoderTest |
- : public Http2StructureDecoderTest<Http2PushPromiseFields> {}; |
- |
-TEST_F(Http2PushPromiseFieldsDecoderTest, DecodesLiteral) { |
- { |
- const char kData[] = { |
- 0x00, 0x01, 0x8au, 0x92u, // Promised Stream ID: 101010 |
- }; |
- ASSERT_TRUE(DecodeLeadingStructure(kData)); |
- EXPECT_EQ(101010u, structure_.promised_stream_id); |
- } |
- { |
- // Promised stream id has R-bit (reserved for future use) set, which |
- // should be cleared by the decoder. |
- const char kData[] = { |
- 0xffu, 0xffu, 0xffu, 0xffu, // Promised Stream ID: max uint31 and R-bit |
- }; |
- ASSERT_TRUE(DecodeLeadingStructure(kData)); |
- EXPECT_EQ(StreamIdMask(), structure_.promised_stream_id); |
- } |
-} |
- |
-TEST_F(Http2PushPromiseFieldsDecoderTest, DecodesRandomized) { |
- TestDecodingRandomizedStructures(); |
-} |
- |
-//------------------------------------------------------------------------------ |
- |
-class Http2PingFieldsDecoderTest |
- : public Http2StructureDecoderTest<Http2PingFields> {}; |
- |
-TEST_F(Http2PingFieldsDecoderTest, DecodesLiteral) { |
- { |
- // Each byte is different, so can detect if order changed. |
- const char kData[] = { |
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, |
- }; |
- ASSERT_TRUE(DecodeLeadingStructure(kData)); |
- EXPECT_EQ(StringPiece(kData, 8), ToStringPiece(structure_.opaque_data)); |
- } |
- { |
- // All zeros, detect problems handling NULs. |
- const char kData[] = { |
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
- }; |
- ASSERT_TRUE(DecodeLeadingStructure(kData)); |
- EXPECT_EQ(StringPiece(kData, 8), ToStringPiece(structure_.opaque_data)); |
- } |
- { |
- const char kData[] = { |
- 0xffu, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu, |
- }; |
- ASSERT_TRUE(DecodeLeadingStructure(kData)); |
- EXPECT_EQ(StringPiece(kData, 8), ToStringPiece(structure_.opaque_data)); |
- } |
-} |
- |
-TEST_F(Http2PingFieldsDecoderTest, DecodesRandomized) { |
- TestDecodingRandomizedStructures(); |
-} |
- |
-//------------------------------------------------------------------------------ |
- |
-class Http2GoAwayFieldsDecoderTest |
- : public Http2StructureDecoderTest<Http2GoAwayFields> {}; |
- |
-TEST_F(Http2GoAwayFieldsDecoderTest, DecodesLiteral) { |
- { |
- const char kData[] = { |
- 0x00, 0x00, 0x00, 0x00, // Last Stream ID: 0 |
- 0x00, 0x00, 0x00, 0x00, // Error: NO_ERROR (0) |
- }; |
- ASSERT_TRUE(DecodeLeadingStructure(kData)); |
- EXPECT_EQ(0u, structure_.last_stream_id); |
- EXPECT_TRUE(structure_.IsSupportedErrorCode()); |
- EXPECT_EQ(Http2ErrorCode::HTTP2_NO_ERROR, structure_.error_code); |
- } |
- { |
- const char kData[] = { |
- 0x00, 0x00, 0x00, 0x01, // Last Stream ID: 1 |
- 0x00, 0x00, 0x00, 0x0d, // Error: HTTP_1_1_REQUIRED |
- }; |
- ASSERT_TRUE(DecodeLeadingStructure(kData)); |
- EXPECT_EQ(1u, structure_.last_stream_id); |
- EXPECT_TRUE(structure_.IsSupportedErrorCode()); |
- EXPECT_EQ(Http2ErrorCode::HTTP_1_1_REQUIRED, structure_.error_code); |
- } |
- { |
- const char kData[] = { |
- 0xffu, 0xffu, 0xffu, 0xffu, // Last Stream ID: max uint31 and R-bit |
- 0xffu, 0xffu, 0xffu, 0xffu, // Error: max uint32 (Unknown error code) |
- }; |
- ASSERT_TRUE(DecodeLeadingStructure(kData)); |
- EXPECT_EQ(StreamIdMask(), structure_.last_stream_id); // No high-bit. |
- EXPECT_FALSE(structure_.IsSupportedErrorCode()); |
- EXPECT_EQ(static_cast<Http2ErrorCode>(0xffffffff), structure_.error_code); |
- } |
-} |
- |
-TEST_F(Http2GoAwayFieldsDecoderTest, DecodesRandomized) { |
- TestDecodingRandomizedStructures(); |
-} |
- |
-//------------------------------------------------------------------------------ |
- |
-class Http2WindowUpdateFieldsDecoderTest |
- : public Http2StructureDecoderTest<Http2WindowUpdateFields> {}; |
- |
-TEST_F(Http2WindowUpdateFieldsDecoderTest, DecodesLiteral) { |
- { |
- const char kData[] = { |
- 0x00, 0x01, 0x00, 0x00, // Window Size Increment: 2 ^ 16 |
- }; |
- ASSERT_TRUE(DecodeLeadingStructure(kData)); |
- EXPECT_EQ(1u << 16, structure_.window_size_increment); |
- } |
- { |
- // Increment must be non-zero, but we need to be able to decode the invalid |
- // zero to detect it. |
- const char kData[] = { |
- 0x00, 0x00, 0x00, 0x00, // Window Size Increment: 0 |
- }; |
- ASSERT_TRUE(DecodeLeadingStructure(kData)); |
- EXPECT_EQ(0u, structure_.window_size_increment); |
- } |
- { |
- // Increment has R-bit (reserved for future use) set, which |
- // should be cleared by the decoder. |
- const char kData[] = { |
- 0xffu, 0xffu, 0xffu, |
- 0xffu, // Window Size Increment: max uint31 and R-bit |
- }; |
- ASSERT_TRUE(DecodeLeadingStructure(kData)); |
- EXPECT_EQ(StreamIdMask(), structure_.window_size_increment); |
- } |
-} |
- |
-TEST_F(Http2WindowUpdateFieldsDecoderTest, DecodesRandomized) { |
- TestDecodingRandomizedStructures(); |
-} |
- |
-//------------------------------------------------------------------------------ |
- |
-class Http2AltSvcFieldsDecoderTest |
- : public Http2StructureDecoderTest<Http2AltSvcFields> {}; |
- |
-TEST_F(Http2AltSvcFieldsDecoderTest, DecodesLiteral) { |
- { |
- const char kData[] = { |
- 0x00, 0x00, // Origin Length: 0 |
- }; |
- ASSERT_TRUE(DecodeLeadingStructure(kData)); |
- EXPECT_EQ(0, structure_.origin_length); |
- } |
- { |
- const char kData[] = { |
- 0x00, 0x14, // Origin Length: 20 |
- }; |
- ASSERT_TRUE(DecodeLeadingStructure(kData)); |
- EXPECT_EQ(20, structure_.origin_length); |
- } |
- { |
- const char kData[] = { |
- 0xffu, 0xffu, // Origin Length: uint16 max |
- }; |
- ASSERT_TRUE(DecodeLeadingStructure(kData)); |
- EXPECT_EQ(65535, structure_.origin_length); |
- } |
-} |
- |
-TEST_F(Http2AltSvcFieldsDecoderTest, DecodesRandomized) { |
- TestDecodingRandomizedStructures(); |
-} |
- |
-} // namespace |
-} // namespace test |
-} // namespace net |