| // 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 "http2/decoder/http2_frame_decoder.h" | 
 |  | 
 | // Tests of Http2FrameDecoder. | 
 |  | 
 | #include <string> | 
 | #include <vector> | 
 |  | 
 | #include "absl/strings/string_view.h" | 
 | #include "http2/http2_constants.h" | 
 | #include "http2/platform/api/http2_flags.h" | 
 | #include "http2/platform/api/http2_logging.h" | 
 | #include "http2/platform/api/http2_test_helpers.h" | 
 | #include "http2/test_tools/frame_parts.h" | 
 | #include "http2/test_tools/frame_parts_collector_listener.h" | 
 | #include "http2/test_tools/http2_random.h" | 
 | #include "http2/tools/random_decoder_test.h" | 
 |  | 
 | using ::testing::AssertionSuccess; | 
 |  | 
 | namespace http2 { | 
 | namespace test { | 
 | class Http2FrameDecoderPeer { | 
 |  public: | 
 |   static size_t remaining_total_payload(Http2FrameDecoder* decoder) { | 
 |     return decoder->frame_decoder_state_.remaining_total_payload(); | 
 |   } | 
 | }; | 
 |  | 
 | namespace { | 
 |  | 
 | class Http2FrameDecoderTest : public RandomDecoderTest { | 
 |  protected: | 
 |   void SetUp() override { | 
 |     // On any one run of this suite, we'll always choose the same value for | 
 |     // use_default_constructor_ because the random seed is the same for each | 
 |     // test case, but across runs the random seed changes. | 
 |     use_default_constructor_ = Random().OneIn(2); | 
 |   } | 
 |  | 
 |   DecodeStatus StartDecoding(DecodeBuffer* db) override { | 
 |     HTTP2_DVLOG(2) << "StartDecoding, db->Remaining=" << db->Remaining(); | 
 |     collector_.Reset(); | 
 |     PrepareDecoder(); | 
 |  | 
 |     DecodeStatus status = decoder_->DecodeFrame(db); | 
 |     if (status != DecodeStatus::kDecodeInProgress) { | 
 |       // Keep track of this so that a concrete test can verify that both fast | 
 |       // and slow decoding paths have been tested. | 
 |       ++fast_decode_count_; | 
 |       if (status == DecodeStatus::kDecodeError) { | 
 |         ConfirmDiscardsRemainingPayload(); | 
 |       } | 
 |     } | 
 |     return status; | 
 |   } | 
 |  | 
 |   DecodeStatus ResumeDecoding(DecodeBuffer* db) override { | 
 |     HTTP2_DVLOG(2) << "ResumeDecoding, db->Remaining=" << db->Remaining(); | 
 |     DecodeStatus status = decoder_->DecodeFrame(db); | 
 |     if (status != DecodeStatus::kDecodeInProgress) { | 
 |       // Keep track of this so that a concrete test can verify that both fast | 
 |       // and slow decoding paths have been tested. | 
 |       ++slow_decode_count_; | 
 |       if (status == DecodeStatus::kDecodeError) { | 
 |         ConfirmDiscardsRemainingPayload(); | 
 |       } | 
 |     } | 
 |     return status; | 
 |   } | 
 |  | 
 |   // When an error is returned, the decoder is in state kDiscardPayload, and | 
 |   // stays there until the remaining bytes of the frame's payload have been | 
 |   // skipped over. There are no callbacks for this situation. | 
 |   void ConfirmDiscardsRemainingPayload() { | 
 |     ASSERT_TRUE(decoder_->IsDiscardingPayload()); | 
 |     size_t remaining = | 
 |         Http2FrameDecoderPeer::remaining_total_payload(decoder_.get()); | 
 |     // The decoder will discard the remaining bytes, but not go beyond that, | 
 |     // which these conditions verify. | 
 |     size_t extra = 10; | 
 |     std::string junk(remaining + extra, '0'); | 
 |     DecodeBuffer tmp(junk); | 
 |     EXPECT_EQ(DecodeStatus::kDecodeDone, decoder_->DecodeFrame(&tmp)); | 
 |     EXPECT_EQ(remaining, tmp.Offset()); | 
 |     EXPECT_EQ(extra, tmp.Remaining()); | 
 |     EXPECT_FALSE(decoder_->IsDiscardingPayload()); | 
 |   } | 
 |  | 
 |   void PrepareDecoder() { | 
 |     // Alternate which constructor is used. | 
 |     if (use_default_constructor_) { | 
 |       decoder_ = std::make_unique<Http2FrameDecoder>(); | 
 |       decoder_->set_listener(&collector_); | 
 |     } else { | 
 |       decoder_ = std::make_unique<Http2FrameDecoder>(&collector_); | 
 |     } | 
 |     decoder_->set_maximum_payload_size(maximum_payload_size_); | 
 |  | 
 |     use_default_constructor_ = !use_default_constructor_; | 
 |   } | 
 |  | 
 |   void ResetDecodeSpeedCounters() { | 
 |     fast_decode_count_ = 0; | 
 |     slow_decode_count_ = 0; | 
 |   } | 
 |  | 
 |   AssertionResult VerifyCollected(const FrameParts& expected) { | 
 |     VERIFY_FALSE(collector_.IsInProgress()); | 
 |     VERIFY_EQ(1u, collector_.size()); | 
 |     VERIFY_AND_RETURN_SUCCESS(expected.VerifyEquals(*collector_.frame(0))); | 
 |   } | 
 |  | 
 |   AssertionResult DecodePayloadAndValidateSeveralWays(absl::string_view payload, | 
 |                                                       Validator validator) { | 
 |     DecodeBuffer db(payload); | 
 |     bool start_decoding_requires_non_empty = false; | 
 |     return DecodeAndValidateSeveralWays(&db, start_decoding_requires_non_empty, | 
 |                                         validator); | 
 |   } | 
 |  | 
 |   // Decode one frame's payload and confirm that the listener recorded the | 
 |   // expected FrameParts instance, and only one FrameParts instance. The | 
 |   // payload will be decoded several times with different partitionings | 
 |   // of the payload, and after each the validator will be called. | 
 |   AssertionResult DecodePayloadAndValidateSeveralWays( | 
 |       absl::string_view payload, | 
 |       const FrameParts& expected) { | 
 |     auto validator = [&expected, this](const DecodeBuffer& /*input*/, | 
 |                                        DecodeStatus status) -> AssertionResult { | 
 |       VERIFY_EQ(status, DecodeStatus::kDecodeDone); | 
 |       VERIFY_AND_RETURN_SUCCESS(VerifyCollected(expected)); | 
 |     }; | 
 |     ResetDecodeSpeedCounters(); | 
 |     VERIFY_SUCCESS(DecodePayloadAndValidateSeveralWays( | 
 |         payload, ValidateDoneAndEmpty(validator))); | 
 |     VERIFY_GT(fast_decode_count_, 0u); | 
 |     VERIFY_GT(slow_decode_count_, 0u); | 
 |  | 
 |     // Repeat with more input; it should stop without reading that input. | 
 |     std::string next_frame = Random().RandString(10); | 
 |     std::string input(payload.data(), payload.size()); | 
 |     input += next_frame; | 
 |  | 
 |     ResetDecodeSpeedCounters(); | 
 |     VERIFY_SUCCESS(DecodePayloadAndValidateSeveralWays( | 
 |         payload, ValidateDoneAndOffset(payload.size(), validator))); | 
 |     VERIFY_GT(fast_decode_count_, 0u); | 
 |     VERIFY_GT(slow_decode_count_, 0u); | 
 |  | 
 |     return AssertionSuccess(); | 
 |   } | 
 |  | 
 |   template <size_t N> | 
 |   AssertionResult DecodePayloadAndValidateSeveralWays( | 
 |       const char (&buf)[N], | 
 |       const FrameParts& expected) { | 
 |     return DecodePayloadAndValidateSeveralWays(absl::string_view(buf, N), | 
 |                                                expected); | 
 |   } | 
 |  | 
 |   template <size_t N> | 
 |   AssertionResult DecodePayloadAndValidateSeveralWays( | 
 |       const char (&buf)[N], | 
 |       const Http2FrameHeader& header) { | 
 |     return DecodePayloadAndValidateSeveralWays(absl::string_view(buf, N), | 
 |                                                FrameParts(header)); | 
 |   } | 
 |  | 
 |   template <size_t N> | 
 |   AssertionResult DecodePayloadExpectingError(const char (&buf)[N], | 
 |                                               const FrameParts& expected) { | 
 |     auto validator = [&expected, this](const DecodeBuffer& /*input*/, | 
 |                                        DecodeStatus status) -> AssertionResult { | 
 |       VERIFY_EQ(status, DecodeStatus::kDecodeError); | 
 |       VERIFY_AND_RETURN_SUCCESS(VerifyCollected(expected)); | 
 |     }; | 
 |     ResetDecodeSpeedCounters(); | 
 |     EXPECT_TRUE( | 
 |         DecodePayloadAndValidateSeveralWays(ToStringPiece(buf), validator)); | 
 |     EXPECT_GT(fast_decode_count_, 0u); | 
 |     EXPECT_GT(slow_decode_count_, 0u); | 
 |     return AssertionSuccess(); | 
 |   } | 
 |  | 
 |   template <size_t N> | 
 |   AssertionResult DecodePayloadExpectingFrameSizeError(const char (&buf)[N], | 
 |                                                        FrameParts expected) { | 
 |     expected.SetHasFrameSizeError(true); | 
 |     VERIFY_AND_RETURN_SUCCESS(DecodePayloadExpectingError(buf, expected)); | 
 |   } | 
 |  | 
 |   template <size_t N> | 
 |   AssertionResult DecodePayloadExpectingFrameSizeError( | 
 |       const char (&buf)[N], | 
 |       const Http2FrameHeader& header) { | 
 |     return DecodePayloadExpectingFrameSizeError(buf, FrameParts(header)); | 
 |   } | 
 |  | 
 |   // Count of payloads that are fully decoded by StartDecodingPayload or for | 
 |   // which an error was detected by StartDecodingPayload. | 
 |   size_t fast_decode_count_ = 0; | 
 |  | 
 |   // Count of payloads that required calling ResumeDecodingPayload in order to | 
 |   // decode completely, or for which an error was detected by | 
 |   // ResumeDecodingPayload. | 
 |   size_t slow_decode_count_ = 0; | 
 |  | 
 |   uint32_t maximum_payload_size_ = Http2SettingsInfo::DefaultMaxFrameSize(); | 
 |   FramePartsCollectorListener collector_; | 
 |   std::unique_ptr<Http2FrameDecoder> decoder_; | 
 |   bool use_default_constructor_; | 
 | }; | 
 |  | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | // Tests that pass the minimum allowed size for the frame type, which is often | 
 | // empty. The tests are in order by frame type value (i.e. 0 for DATA frames). | 
 |  | 
 | TEST_F(Http2FrameDecoderTest, DataEmpty) { | 
 |   const char kFrameData[] = { | 
 |       '\x00', '\x00', '\x00',  // Payload length: 0 | 
 |       '\x00',                  // DATA | 
 |       '\x00',                  // Flags: none | 
 |       '\x00', '\x00', '\x00', | 
 |       '\x00',  // Stream ID: 0 (invalid but unchecked here) | 
 |   }; | 
 |   Http2FrameHeader header(0, Http2FrameType::DATA, 0, 0); | 
 |   FrameParts expected(header, ""); | 
 |   EXPECT_TRUE(DecodePayloadAndValidateSeveralWays(kFrameData, expected)); | 
 | } | 
 |  | 
 | TEST_F(Http2FrameDecoderTest, HeadersEmpty) { | 
 |   const char kFrameData[] = { | 
 |       '\x00', '\x00', '\x00',          // Payload length: 0 | 
 |       '\x01',                          // HEADERS | 
 |       '\x00',                          // Flags: none | 
 |       '\x00', '\x00', '\x00', '\x01',  // Stream ID: 0  (REQUIRES ID) | 
 |   }; | 
 |   Http2FrameHeader header(0, Http2FrameType::HEADERS, 0, 1); | 
 |   FrameParts expected(header, ""); | 
 |   EXPECT_TRUE(DecodePayloadAndValidateSeveralWays(kFrameData, expected)); | 
 | } | 
 |  | 
 | TEST_F(Http2FrameDecoderTest, Priority) { | 
 |   const char kFrameData[] = { | 
 |       '\x00', '\x00', '\x05',          // Length: 5 | 
 |       '\x02',                          //   Type: PRIORITY | 
 |       '\x00',                          //  Flags: none | 
 |       '\x00', '\x00', '\x00', '\x02',  // Stream: 2 | 
 |       '\x80', '\x00', '\x00', '\x01',  // Parent: 1 (Exclusive) | 
 |       '\x10',                          // Weight: 17 | 
 |   }; | 
 |   Http2FrameHeader header(5, Http2FrameType::PRIORITY, 0, 2); | 
 |   FrameParts expected(header); | 
 |   expected.SetOptPriority(Http2PriorityFields(1, 17, true)); | 
 |   EXPECT_TRUE(DecodePayloadAndValidateSeveralWays(kFrameData, expected)); | 
 | } | 
 |  | 
 | TEST_F(Http2FrameDecoderTest, RstStream) { | 
 |   const char kFrameData[] = { | 
 |       '\x00', '\x00', '\x04',          // Length: 4 | 
 |       '\x03',                          //   Type: RST_STREAM | 
 |       '\x00',                          //  Flags: none | 
 |       '\x00', '\x00', '\x00', '\x01',  // Stream: 1 | 
 |       '\x00', '\x00', '\x00', '\x01',  //  Error: PROTOCOL_ERROR | 
 |   }; | 
 |   Http2FrameHeader header(4, Http2FrameType::RST_STREAM, 0, 1); | 
 |   FrameParts expected(header); | 
 |   expected.SetOptRstStreamErrorCode(Http2ErrorCode::PROTOCOL_ERROR); | 
 |   EXPECT_TRUE(DecodePayloadAndValidateSeveralWays(kFrameData, expected)); | 
 | } | 
 |  | 
 | TEST_F(Http2FrameDecoderTest, SettingsEmpty) { | 
 |   const char kFrameData[] = { | 
 |       '\x00', '\x00', '\x00',          // Length: 0 | 
 |       '\x04',                          //   Type: SETTINGS | 
 |       '\x00',                          //  Flags: none | 
 |       '\x00', '\x00', '\x00', '\x01',  // Stream: 1 (invalid but unchecked here) | 
 |   }; | 
 |   Http2FrameHeader header(0, Http2FrameType::SETTINGS, 0, 1); | 
 |   EXPECT_TRUE(DecodePayloadAndValidateSeveralWays(kFrameData, header)); | 
 | } | 
 |  | 
 | TEST_F(Http2FrameDecoderTest, SettingsAck) { | 
 |   const char kFrameData[] = { | 
 |       '\x00', '\x00', '\x00',          //   Length: 6 | 
 |       '\x04',                          //     Type: SETTINGS | 
 |       '\x01',                          //    Flags: ACK | 
 |       '\x00', '\x00', '\x00', '\x00',  //   Stream: 0 | 
 |   }; | 
 |   Http2FrameHeader header(0, Http2FrameType::SETTINGS, Http2FrameFlag::ACK, 0); | 
 |   FrameParts expected(header); | 
 |   EXPECT_TRUE(DecodePayloadAndValidateSeveralWays(kFrameData, expected)); | 
 | } | 
 |  | 
 | TEST_F(Http2FrameDecoderTest, PushPromiseMinimal) { | 
 |   const char kFrameData[] = { | 
 |       '\x00', '\x00', '\x04',  // Payload length: 4 | 
 |       '\x05',                  // PUSH_PROMISE | 
 |       '\x04',                  // Flags: END_HEADERS | 
 |       '\x00', '\x00', '\x00', | 
 |       '\x02',  //   Stream: 2 (invalid but unchecked here) | 
 |       '\x00', '\x00', '\x00', | 
 |       '\x01',  // Promised: 1 (invalid but unchecked here) | 
 |   }; | 
 |   Http2FrameHeader header(4, Http2FrameType::PUSH_PROMISE, | 
 |                           Http2FrameFlag::END_HEADERS, 2); | 
 |   FrameParts expected(header, ""); | 
 |   expected.SetOptPushPromise(Http2PushPromiseFields{1}); | 
 |   EXPECT_TRUE(DecodePayloadAndValidateSeveralWays(kFrameData, expected)); | 
 | } | 
 |  | 
 | TEST_F(Http2FrameDecoderTest, Ping) { | 
 |   const char kFrameData[] = { | 
 |       '\x00', '\x00', '\x08',          //   Length: 8 | 
 |       '\x06',                          //     Type: PING | 
 |       '\xfe',                          //    Flags: no valid flags | 
 |       '\x00', '\x00', '\x00', '\x00',  //   Stream: 0 | 
 |       's',    'o',    'm',    'e',     // "some" | 
 |       'd',    'a',    't',    'a',     // "data" | 
 |   }; | 
 |   Http2FrameHeader header(8, Http2FrameType::PING, 0, 0); | 
 |   FrameParts expected(header); | 
 |   expected.SetOptPing( | 
 |       Http2PingFields{{'s', 'o', 'm', 'e', 'd', 'a', 't', 'a'}}); | 
 |   EXPECT_TRUE(DecodePayloadAndValidateSeveralWays(kFrameData, expected)); | 
 | } | 
 |  | 
 | TEST_F(Http2FrameDecoderTest, PingAck) { | 
 |   const char kFrameData[] = { | 
 |       '\x00', '\x00', '\x08',          //   Length: 8 | 
 |       '\x06',                          //     Type: PING | 
 |       '\xff',                          //    Flags: ACK (plus all invalid flags) | 
 |       '\x00', '\x00', '\x00', '\x00',  //   Stream: 0 | 
 |       's',    'o',    'm',    'e',     // "some" | 
 |       'd',    'a',    't',    'a',     // "data" | 
 |   }; | 
 |   Http2FrameHeader header(8, Http2FrameType::PING, Http2FrameFlag::ACK, 0); | 
 |   FrameParts expected(header); | 
 |   expected.SetOptPing( | 
 |       Http2PingFields{{'s', 'o', 'm', 'e', 'd', 'a', 't', 'a'}}); | 
 |   EXPECT_TRUE(DecodePayloadAndValidateSeveralWays(kFrameData, expected)); | 
 | } | 
 |  | 
 | TEST_F(Http2FrameDecoderTest, GoAwayMinimal) { | 
 |   const char kFrameData[] = { | 
 |       '\x00', '\x00', '\x08',          // Length: 8 (no opaque data) | 
 |       '\x07',                          //   Type: GOAWAY | 
 |       '\xff',                          //  Flags: 0xff (no valid flags) | 
 |       '\x00', '\x00', '\x00', '\x01',  // Stream: 1 (invalid but unchecked here) | 
 |       '\x80', '\x00', '\x00', '\xff',  //   Last: 255 (plus R bit) | 
 |       '\x00', '\x00', '\x00', '\x09',  //  Error: COMPRESSION_ERROR | 
 |   }; | 
 |   Http2FrameHeader header(8, Http2FrameType::GOAWAY, 0, 1); | 
 |   FrameParts expected(header); | 
 |   expected.SetOptGoaway( | 
 |       Http2GoAwayFields(255, Http2ErrorCode::COMPRESSION_ERROR)); | 
 |   EXPECT_TRUE(DecodePayloadAndValidateSeveralWays(kFrameData, expected)); | 
 | } | 
 |  | 
 | TEST_F(Http2FrameDecoderTest, WindowUpdate) { | 
 |   const char kFrameData[] = { | 
 |       '\x00', '\x00', '\x04',          // Length: 4 | 
 |       '\x08',                          //   Type: WINDOW_UPDATE | 
 |       '\x0f',                          //  Flags: 0xff (no valid flags) | 
 |       '\x00', '\x00', '\x00', '\x01',  // Stream: 1 | 
 |       '\x80', '\x00', '\x04', '\x00',  //   Incr: 1024 (plus R bit) | 
 |   }; | 
 |   Http2FrameHeader header(4, Http2FrameType::WINDOW_UPDATE, 0, 1); | 
 |   FrameParts expected(header); | 
 |   expected.SetOptWindowUpdateIncrement(1024); | 
 |   EXPECT_TRUE(DecodePayloadAndValidateSeveralWays(kFrameData, expected)); | 
 | } | 
 |  | 
 | TEST_F(Http2FrameDecoderTest, ContinuationEmpty) { | 
 |   const char kFrameData[] = { | 
 |       '\x00', '\x00', '\x00',  // Payload length: 0 | 
 |       '\x09',                  // CONTINUATION | 
 |       '\x00',                  // Flags: none | 
 |       '\x00', '\x00', '\x00', | 
 |       '\x00',  // Stream ID: 0 (invalid but unchecked here) | 
 |   }; | 
 |   Http2FrameHeader header(0, Http2FrameType::CONTINUATION, 0, 0); | 
 |   FrameParts expected(header); | 
 |   EXPECT_TRUE(DecodePayloadAndValidateSeveralWays(kFrameData, expected)); | 
 | } | 
 |  | 
 | TEST_F(Http2FrameDecoderTest, AltSvcMinimal) { | 
 |   const char kFrameData[] = { | 
 |       '\x00', '\x00', '\x02',  // Payload length: 2 | 
 |       '\x0a',                  // ALTSVC | 
 |       '\xff',                  // Flags: none (plus 0xff) | 
 |       '\x00', '\x00', '\x00', | 
 |       '\x00',          // Stream ID: 0 (invalid but unchecked here) | 
 |       '\x00', '\x00',  // Origin Length: 0 | 
 |   }; | 
 |   Http2FrameHeader header(2, Http2FrameType::ALTSVC, 0, 0); | 
 |   FrameParts expected(header); | 
 |   expected.SetOptAltsvcOriginLength(0); | 
 |   expected.SetOptAltsvcValueLength(0); | 
 |   EXPECT_TRUE(DecodePayloadAndValidateSeveralWays(kFrameData, expected)); | 
 | } | 
 |  | 
 | TEST_F(Http2FrameDecoderTest, UnknownEmpty) { | 
 |   const char kFrameData[] = { | 
 |       '\x00', '\x00', '\x00',          // Payload length: 0 | 
 |       '\x20',                          // 32 (unknown) | 
 |       '\xff',                          // Flags: all | 
 |       '\x00', '\x00', '\x00', '\x00',  // Stream ID: 0 | 
 |   }; | 
 |   Http2FrameHeader header(0, static_cast<Http2FrameType>(32), 0xff, 0); | 
 |   FrameParts expected(header); | 
 |   EXPECT_TRUE(DecodePayloadAndValidateSeveralWays(kFrameData, expected)); | 
 | } | 
 |  | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | // Tests of longer payloads, for those frame types that allow longer payloads. | 
 |  | 
 | TEST_F(Http2FrameDecoderTest, DataPayload) { | 
 |   const char kFrameData[] = { | 
 |       '\x00', '\x00', '\x03',          // Payload length: 7 | 
 |       '\x00',                          // DATA | 
 |       '\x80',                          // Flags: 0x80 | 
 |       '\x00', '\x00', '\x02', '\x02',  // Stream ID: 514 | 
 |       'a',    'b',    'c',             // Data | 
 |   }; | 
 |   Http2FrameHeader header(3, Http2FrameType::DATA, 0, 514); | 
 |   FrameParts expected(header, "abc"); | 
 |   EXPECT_TRUE(DecodePayloadAndValidateSeveralWays(kFrameData, expected)); | 
 | } | 
 |  | 
 | TEST_F(Http2FrameDecoderTest, HeadersPayload) { | 
 |   const char kFrameData[] = { | 
 |       '\x00', '\x00', '\x03',          // Payload length: 3 | 
 |       '\x01',                          // HEADERS | 
 |       '\x05',                          // Flags: END_STREAM | END_HEADERS | 
 |       '\x00', '\x00', '\x00', '\x02',  // Stream ID: 0  (REQUIRES ID) | 
 |       'a',    'b',    'c',  // HPACK fragment (doesn't have to be valid) | 
 |   }; | 
 |   Http2FrameHeader header( | 
 |       3, Http2FrameType::HEADERS, | 
 |       Http2FrameFlag::END_STREAM | Http2FrameFlag::END_HEADERS, 2); | 
 |   FrameParts expected(header, "abc"); | 
 |   EXPECT_TRUE(DecodePayloadAndValidateSeveralWays(kFrameData, expected)); | 
 | } | 
 |  | 
 | TEST_F(Http2FrameDecoderTest, HeadersPriority) { | 
 |   const char kFrameData[] = { | 
 |       '\x00', '\x00', '\x05',          // Payload length: 5 | 
 |       '\x01',                          // HEADERS | 
 |       '\x20',                          // Flags: PRIORITY | 
 |       '\x00', '\x00', '\x00', '\x02',  // Stream ID: 0  (REQUIRES ID) | 
 |       '\x00', '\x00', '\x00', '\x01',  // Parent: 1 (Not Exclusive) | 
 |       '\xff',                          // Weight: 256 | 
 |   }; | 
 |   Http2FrameHeader header(5, Http2FrameType::HEADERS, Http2FrameFlag::PRIORITY, | 
 |                           2); | 
 |   FrameParts expected(header); | 
 |   expected.SetOptPriority(Http2PriorityFields(1, 256, false)); | 
 |   EXPECT_TRUE(DecodePayloadAndValidateSeveralWays(kFrameData, expected)); | 
 | } | 
 |  | 
 | TEST_F(Http2FrameDecoderTest, Settings) { | 
 |   const char kFrameData[] = { | 
 |       '\x00', '\x00', '\x0c',          // Length: 12 | 
 |       '\x04',                          //   Type: SETTINGS | 
 |       '\x00',                          //  Flags: none | 
 |       '\x00', '\x00', '\x00', '\x00',  // Stream: 0 | 
 |       '\x00', '\x04',                  //  Param: INITIAL_WINDOW_SIZE | 
 |       '\x0a', '\x0b', '\x0c', '\x0d',  //  Value: 168496141 | 
 |       '\x00', '\x02',                  //  Param: ENABLE_PUSH | 
 |       '\x00', '\x00', '\x00', '\x03',  //  Value: 3 (invalid but unchecked here) | 
 |   }; | 
 |   Http2FrameHeader header(12, Http2FrameType::SETTINGS, 0, 0); | 
 |   FrameParts expected(header); | 
 |   expected.AppendSetting(Http2SettingFields( | 
 |       Http2SettingsParameter::INITIAL_WINDOW_SIZE, 168496141)); | 
 |   expected.AppendSetting( | 
 |       Http2SettingFields(Http2SettingsParameter::ENABLE_PUSH, 3)); | 
 |   EXPECT_TRUE(DecodePayloadAndValidateSeveralWays(kFrameData, expected)); | 
 | } | 
 |  | 
 | TEST_F(Http2FrameDecoderTest, PushPromisePayload) { | 
 |   const char kFrameData[] = { | 
 |       '\x00', '\x00', 7,               // Payload length: 7 | 
 |       '\x05',                          // PUSH_PROMISE | 
 |       '\x04',                          // Flags: END_HEADERS | 
 |       '\x00', '\x00', '\x00', '\xff',  // Stream ID: 255 | 
 |       '\x00', '\x00', '\x01', '\x00',  // Promised: 256 | 
 |       'a',    'b',    'c',  // HPACK fragment (doesn't have to be valid) | 
 |   }; | 
 |   Http2FrameHeader header(7, Http2FrameType::PUSH_PROMISE, | 
 |                           Http2FrameFlag::END_HEADERS, 255); | 
 |   FrameParts expected(header, "abc"); | 
 |   expected.SetOptPushPromise(Http2PushPromiseFields{256}); | 
 |   EXPECT_TRUE(DecodePayloadAndValidateSeveralWays(kFrameData, expected)); | 
 | } | 
 |  | 
 | TEST_F(Http2FrameDecoderTest, GoAwayOpaqueData) { | 
 |   const char kFrameData[] = { | 
 |       '\x00', '\x00', '\x0e',          // Length: 14 | 
 |       '\x07',                          //   Type: GOAWAY | 
 |       '\xff',                          //  Flags: 0xff (no valid flags) | 
 |       '\x80', '\x00', '\x00', '\x00',  // Stream: 0 (plus R bit) | 
 |       '\x00', '\x00', '\x01', '\x00',  //   Last: 256 | 
 |       '\x00', '\x00', '\x00', '\x03',  //  Error: FLOW_CONTROL_ERROR | 
 |       'o',    'p',    'a',    'q',    'u', 'e', | 
 |   }; | 
 |   Http2FrameHeader header(14, Http2FrameType::GOAWAY, 0, 0); | 
 |   FrameParts expected(header, "opaque"); | 
 |   expected.SetOptGoaway( | 
 |       Http2GoAwayFields(256, Http2ErrorCode::FLOW_CONTROL_ERROR)); | 
 |   EXPECT_TRUE(DecodePayloadAndValidateSeveralWays(kFrameData, expected)); | 
 | } | 
 |  | 
 | TEST_F(Http2FrameDecoderTest, ContinuationPayload) { | 
 |   const char kFrameData[] = { | 
 |       '\x00', '\x00', '\x03',          // Payload length: 3 | 
 |       '\x09',                          // CONTINUATION | 
 |       '\xff',                          // Flags: END_HEADERS | 0xfb | 
 |       '\x00', '\x00', '\x00', '\x02',  // Stream ID: 2 | 
 |       'a',    'b',    'c',             // Data | 
 |   }; | 
 |   Http2FrameHeader header(3, Http2FrameType::CONTINUATION, | 
 |                           Http2FrameFlag::END_HEADERS, 2); | 
 |   FrameParts expected(header, "abc"); | 
 |   EXPECT_TRUE(DecodePayloadAndValidateSeveralWays(kFrameData, expected)); | 
 | } | 
 |  | 
 | TEST_F(Http2FrameDecoderTest, AltSvcPayload) { | 
 |   const char kFrameData[] = { | 
 |       '\x00', '\x00', '\x08',          // Payload length: 3 | 
 |       '\x0a',                          // ALTSVC | 
 |       '\x00',                          // Flags: none | 
 |       '\x00', '\x00', '\x00', '\x02',  // Stream ID: 2 | 
 |       '\x00', '\x03',                  // Origin Length: 0 | 
 |       'a',    'b',    'c',             // Origin | 
 |       'd',    'e',    'f',             // Value | 
 |   }; | 
 |   Http2FrameHeader header(8, Http2FrameType::ALTSVC, 0, 2); | 
 |   FrameParts expected(header); | 
 |   expected.SetAltSvcExpected("abc", "def"); | 
 |   EXPECT_TRUE(DecodePayloadAndValidateSeveralWays(kFrameData, expected)); | 
 | } | 
 |  | 
 | TEST_F(Http2FrameDecoderTest, PriorityUpdatePayload) { | 
 |   const char kFrameData[] = { | 
 |       '\x00', '\x00', '\x07',          // Payload length: 7 | 
 |       '\x10',                          // PRIORITY_UPDATE | 
 |       '\x00',                          // Flags: none | 
 |       '\x00', '\x00', '\x00', '\x00',  // Stream ID: 0 | 
 |       '\x00', '\x00', '\x00', '\x05',  // Prioritized Stream ID: 5 | 
 |       'a',    'b',    'c',             // Priority Field Value | 
 |   }; | 
 |   Http2FrameHeader header(7, Http2FrameType::PRIORITY_UPDATE, 0, 0); | 
 |  | 
 |   FrameParts expected(header, "abc"); | 
 |   expected.SetOptPriorityUpdate(Http2PriorityUpdateFields{5}); | 
 |   EXPECT_TRUE(DecodePayloadAndValidateSeveralWays(kFrameData, expected)); | 
 | } | 
 |  | 
 | TEST_F(Http2FrameDecoderTest, UnknownPayload) { | 
 |   const char kFrameData[] = { | 
 |       '\x00', '\x00', '\x03',          // Payload length: 3 | 
 |       '\x30',                          // 48 (unknown) | 
 |       '\x00',                          // Flags: none | 
 |       '\x00', '\x00', '\x00', '\x02',  // Stream ID: 2 | 
 |       'a',    'b',    'c',             // Payload | 
 |   }; | 
 |   Http2FrameHeader header(3, static_cast<Http2FrameType>(48), 0, 2); | 
 |   FrameParts expected(header, "abc"); | 
 |   EXPECT_TRUE(DecodePayloadAndValidateSeveralWays(kFrameData, expected)); | 
 | } | 
 |  | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | // Tests of padded payloads, for those frame types that allow padding. | 
 |  | 
 | TEST_F(Http2FrameDecoderTest, DataPayloadAndPadding) { | 
 |   const char kFrameData[] = { | 
 |       '\x00', '\x00', '\x07',          // Payload length: 7 | 
 |       '\x00',                          // DATA | 
 |       '\x09',                          // Flags: END_STREAM | PADDED | 
 |       '\x00', '\x00', '\x00', '\x02',  // Stream ID: 0  (REQUIRES ID) | 
 |       '\x03',                          // Pad Len | 
 |       'a',    'b',    'c',             // Data | 
 |       '\x00', '\x00', '\x00',          // Padding | 
 |   }; | 
 |   Http2FrameHeader header(7, Http2FrameType::DATA, | 
 |                           Http2FrameFlag::END_STREAM | Http2FrameFlag::PADDED, | 
 |                           2); | 
 |   size_t total_pad_length = 4;  // Including the Pad Length field. | 
 |   FrameParts expected(header, "abc", total_pad_length); | 
 |   EXPECT_TRUE(DecodePayloadAndValidateSeveralWays(kFrameData, expected)); | 
 | } | 
 |  | 
 | TEST_F(Http2FrameDecoderTest, HeadersPayloadAndPadding) { | 
 |   const char kFrameData[] = { | 
 |       '\x00', '\x00', '\x07',          // Payload length: 7 | 
 |       '\x01',                          // HEADERS | 
 |       '\x08',                          // Flags: PADDED | 
 |       '\x00', '\x00', '\x00', '\x02',  // Stream ID: 0  (REQUIRES ID) | 
 |       '\x03',                          // Pad Len | 
 |       'a',    'b',    'c',     // HPACK fragment (doesn't have to be valid) | 
 |       '\x00', '\x00', '\x00',  // Padding | 
 |   }; | 
 |   Http2FrameHeader header(7, Http2FrameType::HEADERS, Http2FrameFlag::PADDED, | 
 |                           2); | 
 |   size_t total_pad_length = 4;  // Including the Pad Length field. | 
 |   FrameParts expected(header, "abc", total_pad_length); | 
 |   EXPECT_TRUE(DecodePayloadAndValidateSeveralWays(kFrameData, expected)); | 
 | } | 
 |  | 
 | TEST_F(Http2FrameDecoderTest, HeadersPayloadPriorityAndPadding) { | 
 |   const char kFrameData[] = { | 
 |       '\x00', '\x00', '\x0c',          // Payload length: 12 | 
 |       '\x01',                          // HEADERS | 
 |       '\xff',                          // Flags: all, including undefined | 
 |       '\x00', '\x00', '\x00', '\x02',  // Stream ID: 0  (REQUIRES ID) | 
 |       '\x03',                          // Pad Len | 
 |       '\x80', '\x00', '\x00', '\x01',  // Parent: 1 (Exclusive) | 
 |       '\x10',                          // Weight: 17 | 
 |       'a',    'b',    'c',     // HPACK fragment (doesn't have to be valid) | 
 |       '\x00', '\x00', '\x00',  // Padding | 
 |   }; | 
 |   Http2FrameHeader header(12, Http2FrameType::HEADERS, | 
 |                           Http2FrameFlag::END_STREAM | | 
 |                               Http2FrameFlag::END_HEADERS | | 
 |                               Http2FrameFlag::PADDED | Http2FrameFlag::PRIORITY, | 
 |                           2); | 
 |   size_t total_pad_length = 4;  // Including the Pad Length field. | 
 |   FrameParts expected(header, "abc", total_pad_length); | 
 |   expected.SetOptPriority(Http2PriorityFields(1, 17, true)); | 
 |   EXPECT_TRUE(DecodePayloadAndValidateSeveralWays(kFrameData, expected)); | 
 | } | 
 |  | 
 | TEST_F(Http2FrameDecoderTest, PushPromisePayloadAndPadding) { | 
 |   const char kFrameData[] = { | 
 |       '\x00', '\x00', 11,              // Payload length: 11 | 
 |       '\x05',                          // PUSH_PROMISE | 
 |       '\xff',                          // Flags: END_HEADERS | PADDED | 0xf3 | 
 |       '\x00', '\x00', '\x00', '\x01',  // Stream ID: 1 | 
 |       '\x03',                          // Pad Len | 
 |       '\x00', '\x00', '\x00', '\x02',  // Promised: 2 | 
 |       'a',    'b',    'c',     // HPACK fragment (doesn't have to be valid) | 
 |       '\x00', '\x00', '\x00',  // Padding | 
 |   }; | 
 |   Http2FrameHeader header(11, Http2FrameType::PUSH_PROMISE, | 
 |                           Http2FrameFlag::END_HEADERS | Http2FrameFlag::PADDED, | 
 |                           1); | 
 |   size_t total_pad_length = 4;  // Including the Pad Length field. | 
 |   FrameParts expected(header, "abc", total_pad_length); | 
 |   expected.SetOptPushPromise(Http2PushPromiseFields{2}); | 
 |   EXPECT_TRUE(DecodePayloadAndValidateSeveralWays(kFrameData, expected)); | 
 | } | 
 |  | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | // Payload too short errors. | 
 |  | 
 | TEST_F(Http2FrameDecoderTest, DataMissingPadLengthField) { | 
 |   const char kFrameData[] = { | 
 |       '\x00', '\x00', '\x00',          // Payload length: 0 | 
 |       '\x00',                          // DATA | 
 |       '\x08',                          // Flags: PADDED | 
 |       '\x00', '\x00', '\x00', '\x01',  // Stream ID: 1 | 
 |   }; | 
 |   Http2FrameHeader header(0, Http2FrameType::DATA, Http2FrameFlag::PADDED, 1); | 
 |   FrameParts expected(header); | 
 |   expected.SetOptMissingLength(1); | 
 |   EXPECT_TRUE(DecodePayloadExpectingError(kFrameData, expected)); | 
 | } | 
 |  | 
 | TEST_F(Http2FrameDecoderTest, HeaderPaddingTooLong) { | 
 |   const char kFrameData[] = { | 
 |       '\x00', '\x00', '\x02',          // Payload length: 0 | 
 |       '\x01',                          // HEADERS | 
 |       '\x08',                          // Flags: PADDED | 
 |       '\x00', '\x01', '\x00', '\x00',  // Stream ID: 65536 | 
 |       '\xff',                          // Pad Len: 255 | 
 |       '\x00',                          // Only one byte of padding | 
 |   }; | 
 |   Http2FrameHeader header(2, Http2FrameType::HEADERS, Http2FrameFlag::PADDED, | 
 |                           65536); | 
 |   FrameParts expected(header); | 
 |   expected.SetOptMissingLength(254); | 
 |   EXPECT_TRUE(DecodePayloadExpectingError(kFrameData, expected)); | 
 | } | 
 |  | 
 | TEST_F(Http2FrameDecoderTest, HeaderMissingPriority) { | 
 |   const char kFrameData[] = { | 
 |       '\x00', '\x00', '\x04',          // Payload length: 0 | 
 |       '\x01',                          // HEADERS | 
 |       '\x20',                          // Flags: PRIORITY | 
 |       '\x00', '\x01', '\x00', '\x00',  // Stream ID: 65536 | 
 |       '\x00', '\x00', '\x00', '\x00',  // Priority (truncated) | 
 |   }; | 
 |   Http2FrameHeader header(4, Http2FrameType::HEADERS, Http2FrameFlag::PRIORITY, | 
 |                           65536); | 
 |   EXPECT_TRUE(DecodePayloadExpectingFrameSizeError(kFrameData, header)); | 
 | } | 
 |  | 
 | TEST_F(Http2FrameDecoderTest, PriorityTooShort) { | 
 |   const char kFrameData[] = { | 
 |       '\x00', '\x00', '\x04',          // Length: 5 | 
 |       '\x02',                          //   Type: PRIORITY | 
 |       '\x00',                          //  Flags: none | 
 |       '\x00', '\x00', '\x00', '\x02',  // Stream: 2 | 
 |       '\x80', '\x00', '\x00', '\x01',  // Parent: 1 (Exclusive) | 
 |   }; | 
 |   Http2FrameHeader header(4, Http2FrameType::PRIORITY, 0, 2); | 
 |   EXPECT_TRUE(DecodePayloadExpectingFrameSizeError(kFrameData, header)); | 
 | } | 
 |  | 
 | TEST_F(Http2FrameDecoderTest, RstStreamTooShort) { | 
 |   const char kFrameData[] = { | 
 |       '\x00', '\x00', '\x03',          // Length: 4 | 
 |       '\x03',                          //   Type: RST_STREAM | 
 |       '\x00',                          //  Flags: none | 
 |       '\x00', '\x00', '\x00', '\x01',  // Stream: 1 | 
 |       '\x00', '\x00', '\x00',          //  Truncated | 
 |   }; | 
 |   Http2FrameHeader header(3, Http2FrameType::RST_STREAM, 0, 1); | 
 |   EXPECT_TRUE(DecodePayloadExpectingFrameSizeError(kFrameData, header)); | 
 | } | 
 |  | 
 | // SETTINGS frames must a multiple of 6 bytes long, so an 9 byte payload is | 
 | // invalid. | 
 | TEST_F(Http2FrameDecoderTest, SettingsWrongSize) { | 
 |   const char kFrameData[] = { | 
 |       '\x00', '\x00', '\x09',          // Length: 2 | 
 |       '\x04',                          //   Type: SETTINGS | 
 |       '\x00',                          //  Flags: none | 
 |       '\x00', '\x00', '\x00', '\x00',  // Stream: 0 | 
 |       '\x00', '\x02',                  //  Param: ENABLE_PUSH | 
 |       '\x00', '\x00', '\x00', '\x03',  //  Value: 1 | 
 |       '\x00', '\x04',                  //  Param: INITIAL_WINDOW_SIZE | 
 |       '\x00',                          //  Value: Truncated | 
 |   }; | 
 |   Http2FrameHeader header(9, Http2FrameType::SETTINGS, 0, 0); | 
 |   FrameParts expected(header); | 
 |   expected.AppendSetting( | 
 |       Http2SettingFields(Http2SettingsParameter::ENABLE_PUSH, 3)); | 
 |   EXPECT_TRUE(DecodePayloadExpectingFrameSizeError(kFrameData, expected)); | 
 | } | 
 |  | 
 | TEST_F(Http2FrameDecoderTest, PushPromiseTooShort) { | 
 |   const char kFrameData[] = { | 
 |       '\x00', '\x00', 3,               // Payload length: 3 | 
 |       '\x05',                          // PUSH_PROMISE | 
 |       '\x00',                          // Flags: none | 
 |       '\x00', '\x00', '\x00', '\x01',  // Stream ID: 1 | 
 |       '\x00', '\x00', '\x00',          // Truncated promise id | 
 |   }; | 
 |   Http2FrameHeader header(3, Http2FrameType::PUSH_PROMISE, 0, 1); | 
 |   EXPECT_TRUE(DecodePayloadExpectingFrameSizeError(kFrameData, header)); | 
 | } | 
 |  | 
 | TEST_F(Http2FrameDecoderTest, PushPromisePaddedTruncatedPromise) { | 
 |   const char kFrameData[] = { | 
 |       '\x00', '\x00', 4,               // Payload length: 4 | 
 |       '\x05',                          // PUSH_PROMISE | 
 |       '\x08',                          // Flags: PADDED | 
 |       '\x00', '\x00', '\x00', '\x01',  // Stream ID: 1 | 
 |       '\x00',                          // Pad Len | 
 |       '\x00', '\x00', '\x00',          // Truncated promise id | 
 |   }; | 
 |   Http2FrameHeader header(4, Http2FrameType::PUSH_PROMISE, | 
 |                           Http2FrameFlag::PADDED, 1); | 
 |   EXPECT_TRUE(DecodePayloadExpectingFrameSizeError(kFrameData, header)); | 
 | } | 
 |  | 
 | TEST_F(Http2FrameDecoderTest, PingTooShort) { | 
 |   const char kFrameData[] = { | 
 |       '\x00', '\x00', '\x07',          //   Length: 8 | 
 |       '\x06',                          //     Type: PING | 
 |       '\xfe',                          //    Flags: no valid flags | 
 |       '\x00', '\x00', '\x00', '\x00',  //   Stream: 0 | 
 |       's',    'o',    'm',    'e',     // "some" | 
 |       'd',    'a',    't',             // Too little | 
 |   }; | 
 |   Http2FrameHeader header(7, Http2FrameType::PING, 0, 0); | 
 |   EXPECT_TRUE(DecodePayloadExpectingFrameSizeError(kFrameData, header)); | 
 | } | 
 |  | 
 | TEST_F(Http2FrameDecoderTest, GoAwayTooShort) { | 
 |   const char kFrameData[] = { | 
 |       '\x00', '\x00', '\x00',          // Length: 0 | 
 |       '\x07',                          //   Type: GOAWAY | 
 |       '\xff',                          //  Flags: 0xff (no valid flags) | 
 |       '\x00', '\x00', '\x00', '\x00',  // Stream: 0 | 
 |   }; | 
 |   Http2FrameHeader header(0, Http2FrameType::GOAWAY, 0, 0); | 
 |   EXPECT_TRUE(DecodePayloadExpectingFrameSizeError(kFrameData, header)); | 
 | } | 
 |  | 
 | TEST_F(Http2FrameDecoderTest, WindowUpdateTooShort) { | 
 |   const char kFrameData[] = { | 
 |       '\x00', '\x00', '\x03',          // Length: 3 | 
 |       '\x08',                          //   Type: WINDOW_UPDATE | 
 |       '\x0f',                          //  Flags: 0xff (no valid flags) | 
 |       '\x00', '\x00', '\x00', '\x01',  // Stream: 1 | 
 |       '\x80', '\x00', '\x04',          // Truncated | 
 |   }; | 
 |   Http2FrameHeader header(3, Http2FrameType::WINDOW_UPDATE, 0, 1); | 
 |   EXPECT_TRUE(DecodePayloadExpectingFrameSizeError(kFrameData, header)); | 
 | } | 
 |  | 
 | TEST_F(Http2FrameDecoderTest, AltSvcTruncatedOriginLength) { | 
 |   const char kFrameData[] = { | 
 |       '\x00', '\x00', '\x01',          // Payload length: 3 | 
 |       '\x0a',                          // ALTSVC | 
 |       '\x00',                          // Flags: none | 
 |       '\x00', '\x00', '\x00', '\x02',  // Stream ID: 2 | 
 |       '\x00',                          // Origin Length: truncated | 
 |   }; | 
 |   Http2FrameHeader header(1, Http2FrameType::ALTSVC, 0, 2); | 
 |   EXPECT_TRUE(DecodePayloadExpectingFrameSizeError(kFrameData, header)); | 
 | } | 
 |  | 
 | TEST_F(Http2FrameDecoderTest, AltSvcTruncatedOrigin) { | 
 |   const char kFrameData[] = { | 
 |       '\x00', '\x00', '\x05',          // Payload length: 3 | 
 |       '\x0a',                          // ALTSVC | 
 |       '\x00',                          // Flags: none | 
 |       '\x00', '\x00', '\x00', '\x02',  // Stream ID: 2 | 
 |       '\x00', '\x04',                  // Origin Length: 4 (too long) | 
 |       'a',    'b',    'c',             // Origin | 
 |   }; | 
 |   Http2FrameHeader header(5, Http2FrameType::ALTSVC, 0, 2); | 
 |   EXPECT_TRUE(DecodePayloadExpectingFrameSizeError(kFrameData, header)); | 
 | } | 
 |  | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | // Payload too long errors. | 
 |  | 
 | // The decoder calls the listener's OnFrameSizeError method if the frame's | 
 | // payload is longer than the currently configured maximum payload size. | 
 | TEST_F(Http2FrameDecoderTest, BeyondMaximum) { | 
 |   maximum_payload_size_ = 2; | 
 |   const char kFrameData[] = { | 
 |       '\x00', '\x00', '\x07',          // Payload length: 7 | 
 |       '\x00',                          // DATA | 
 |       '\x09',                          // Flags: END_STREAM | PADDED | 
 |       '\x00', '\x00', '\x00', '\x02',  // Stream ID: 0  (REQUIRES ID) | 
 |       '\x03',                          // Pad Len | 
 |       'a',    'b',    'c',             // Data | 
 |       '\x00', '\x00', '\x00',          // Padding | 
 |   }; | 
 |   Http2FrameHeader header(7, Http2FrameType::DATA, | 
 |                           Http2FrameFlag::END_STREAM | Http2FrameFlag::PADDED, | 
 |                           2); | 
 |   FrameParts expected(header); | 
 |   expected.SetHasFrameSizeError(true); | 
 |   auto validator = [&expected, this](const DecodeBuffer& input, | 
 |                                      DecodeStatus status) -> AssertionResult { | 
 |     VERIFY_EQ(status, DecodeStatus::kDecodeError); | 
 |     // The decoder detects this error after decoding the header, and without | 
 |     // trying to decode the payload. | 
 |     VERIFY_EQ(input.Offset(), Http2FrameHeader::EncodedSize()); | 
 |     VERIFY_AND_RETURN_SUCCESS(VerifyCollected(expected)); | 
 |   }; | 
 |   ResetDecodeSpeedCounters(); | 
 |   EXPECT_TRUE(DecodePayloadAndValidateSeveralWays(ToStringPiece(kFrameData), | 
 |                                                   validator)); | 
 |   EXPECT_GT(fast_decode_count_, 0u); | 
 |   EXPECT_GT(slow_decode_count_, 0u); | 
 | } | 
 |  | 
 | TEST_F(Http2FrameDecoderTest, PriorityTooLong) { | 
 |   const char kFrameData[] = { | 
 |       '\x00', '\x00', '\x06',          // Length: 5 | 
 |       '\x02',                          //   Type: PRIORITY | 
 |       '\x00',                          //  Flags: none | 
 |       '\x00', '\x00', '\x00', '\x02',  // Stream: 2 | 
 |       '\x80', '\x00', '\x00', '\x01',  // Parent: 1 (Exclusive) | 
 |       '\x10',                          // Weight: 17 | 
 |       '\x00',                          // Too much | 
 |   }; | 
 |   Http2FrameHeader header(6, Http2FrameType::PRIORITY, 0, 2); | 
 |   EXPECT_TRUE(DecodePayloadExpectingFrameSizeError(kFrameData, header)); | 
 | } | 
 |  | 
 | TEST_F(Http2FrameDecoderTest, RstStreamTooLong) { | 
 |   const char kFrameData[] = { | 
 |       '\x00', '\x00', '\x05',          // Length: 4 | 
 |       '\x03',                          //   Type: RST_STREAM | 
 |       '\x00',                          //  Flags: none | 
 |       '\x00', '\x00', '\x00', '\x01',  // Stream: 1 | 
 |       '\x00', '\x00', '\x00', '\x01',  //  Error: PROTOCOL_ERROR | 
 |       '\x00',                          // Too much | 
 |   }; | 
 |   Http2FrameHeader header(5, Http2FrameType::RST_STREAM, 0, 1); | 
 |   EXPECT_TRUE(DecodePayloadExpectingFrameSizeError(kFrameData, header)); | 
 | } | 
 |  | 
 | TEST_F(Http2FrameDecoderTest, SettingsAckTooLong) { | 
 |   const char kFrameData[] = { | 
 |       '\x00', '\x00', '\x06',          //   Length: 6 | 
 |       '\x04',                          //     Type: SETTINGS | 
 |       '\x01',                          //    Flags: ACK | 
 |       '\x00', '\x00', '\x00', '\x00',  //   Stream: 0 | 
 |       '\x00', '\x00',                  //   Extra | 
 |       '\x00', '\x00', '\x00', '\x00',  //   Extra | 
 |   }; | 
 |   Http2FrameHeader header(6, Http2FrameType::SETTINGS, Http2FrameFlag::ACK, 0); | 
 |   EXPECT_TRUE(DecodePayloadExpectingFrameSizeError(kFrameData, header)); | 
 | } | 
 |  | 
 | TEST_F(Http2FrameDecoderTest, PingAckTooLong) { | 
 |   const char kFrameData[] = { | 
 |       '\x00', '\x00', '\x09',          //   Length: 8 | 
 |       '\x06',                          //     Type: PING | 
 |       '\xff',                          //    Flags: ACK | 0xfe | 
 |       '\x00', '\x00', '\x00', '\x00',  //   Stream: 0 | 
 |       's',    'o',    'm',    'e',     // "some" | 
 |       'd',    'a',    't',    'a',     // "data" | 
 |       '\x00',                          // Too much | 
 |   }; | 
 |   Http2FrameHeader header(9, Http2FrameType::PING, Http2FrameFlag::ACK, 0); | 
 |   EXPECT_TRUE(DecodePayloadExpectingFrameSizeError(kFrameData, header)); | 
 | } | 
 |  | 
 | TEST_F(Http2FrameDecoderTest, WindowUpdateTooLong) { | 
 |   const char kFrameData[] = { | 
 |       '\x00', '\x00', '\x05',          // Length: 5 | 
 |       '\x08',                          //   Type: WINDOW_UPDATE | 
 |       '\x0f',                          //  Flags: 0xff (no valid flags) | 
 |       '\x00', '\x00', '\x00', '\x01',  // Stream: 1 | 
 |       '\x80', '\x00', '\x04', '\x00',  //   Incr: 1024 (plus R bit) | 
 |       '\x00',                          // Too much | 
 |   }; | 
 |   Http2FrameHeader header(5, Http2FrameType::WINDOW_UPDATE, 0, 1); | 
 |   EXPECT_TRUE(DecodePayloadExpectingFrameSizeError(kFrameData, header)); | 
 | } | 
 |  | 
 | }  // namespace | 
 | }  // namespace test | 
 | }  // namespace http2 |