|  | // Copyright (c) 2012 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/third_party/quiche/src/quic/core/quic_framer.h" | 
|  |  | 
|  | #include <algorithm> | 
|  | #include <cstdint> | 
|  | #include <map> | 
|  | #include <memory> | 
|  | #include <string> | 
|  | #include <vector> | 
|  |  | 
|  | #include "net/third_party/quiche/src/quic/core/crypto/null_decrypter.h" | 
|  | #include "net/third_party/quiche/src/quic/core/crypto/null_encrypter.h" | 
|  | #include "net/third_party/quiche/src/quic/core/crypto/quic_decrypter.h" | 
|  | #include "net/third_party/quiche/src/quic/core/crypto/quic_encrypter.h" | 
|  | #include "net/third_party/quiche/src/quic/core/quic_connection_id.h" | 
|  | #include "net/third_party/quiche/src/quic/core/quic_packets.h" | 
|  | #include "net/third_party/quiche/src/quic/core/quic_types.h" | 
|  | #include "net/third_party/quiche/src/quic/core/quic_utils.h" | 
|  | #include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h" | 
|  | #include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h" | 
|  | #include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" | 
|  | #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" | 
|  | #include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" | 
|  | #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" | 
|  | #include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" | 
|  | #include "net/third_party/quiche/src/quic/test_tools/quic_framer_peer.h" | 
|  | #include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" | 
|  | #include "net/third_party/quiche/src/quic/test_tools/simple_data_producer.h" | 
|  |  | 
|  | using testing::_; | 
|  | using testing::Return; | 
|  | using testing::Truly; | 
|  |  | 
|  | namespace quic { | 
|  | namespace test { | 
|  | namespace { | 
|  |  | 
|  | const uint64_t kEpoch = UINT64_C(1) << 32; | 
|  | const uint64_t kMask = kEpoch - 1; | 
|  |  | 
|  | const QuicUint128 kTestStatelessResetToken = 1010101;  // 0x0F69B5 | 
|  |  | 
|  | // Use fields in which each byte is distinct to ensure that every byte is | 
|  | // framed correctly. The values are otherwise arbitrary. | 
|  | QuicConnectionId FramerTestConnectionId() { | 
|  | return TestConnectionId(UINT64_C(0xFEDCBA9876543210)); | 
|  | } | 
|  |  | 
|  | QuicConnectionId FramerTestConnectionIdPlusOne() { | 
|  | return TestConnectionId(UINT64_C(0xFEDCBA9876543211)); | 
|  | } | 
|  |  | 
|  | QuicConnectionId FramerTestConnectionIdNineBytes() { | 
|  | char connection_id_bytes[9] = {0xFE, 0xDC, 0xBA, 0x98, 0x76, | 
|  | 0x54, 0x32, 0x10, 0x42}; | 
|  | return QuicConnectionId(connection_id_bytes, sizeof(connection_id_bytes)); | 
|  | } | 
|  |  | 
|  | const QuicPacketNumber kPacketNumber = QuicPacketNumber(UINT64_C(0x12345678)); | 
|  | const QuicPacketNumber kSmallLargestObserved = | 
|  | QuicPacketNumber(UINT16_C(0x1234)); | 
|  | const QuicPacketNumber kSmallMissingPacket = QuicPacketNumber(UINT16_C(0x1233)); | 
|  | const QuicPacketNumber kLeastUnacked = QuicPacketNumber(UINT64_C(0x012345670)); | 
|  | const QuicStreamId kStreamId = UINT64_C(0x01020304); | 
|  | // Note that the high 4 bits of the stream offset must be less than 0x40 | 
|  | // in order to ensure that the value can be encoded using VarInt62 encoding. | 
|  | const QuicStreamOffset kStreamOffset = UINT64_C(0x3A98FEDC32107654); | 
|  | const QuicPublicResetNonceProof kNonceProof = UINT64_C(0xABCDEF0123456789); | 
|  |  | 
|  | // In testing that we can ack the full range of packets... | 
|  | // This is the largest packet number that can be represented in IETF QUIC | 
|  | // varint62 format. | 
|  | const QuicPacketNumber kLargestIetfLargestObserved = | 
|  | QuicPacketNumber(UINT64_C(0x3fffffffffffffff)); | 
|  | // Encodings for the two bits in a VarInt62 that | 
|  | // describe the length of the VarInt61. For binary packet | 
|  | // formats in this file, the convention is to code the | 
|  | // first byte as | 
|  | //   kVarInt62FourBytes + 0x<value_in_that_byte> | 
|  | const uint8_t kVarInt62OneByte = 0x00; | 
|  | const uint8_t kVarInt62TwoBytes = 0x40; | 
|  | const uint8_t kVarInt62FourBytes = 0x80; | 
|  | const uint8_t kVarInt62EightBytes = 0xc0; | 
|  |  | 
|  | class TestEncrypter : public QuicEncrypter { | 
|  | public: | 
|  | ~TestEncrypter() override {} | 
|  | bool SetKey(QuicStringPiece key) override { return true; } | 
|  | bool SetNoncePrefix(QuicStringPiece nonce_prefix) override { return true; } | 
|  | bool SetIV(QuicStringPiece iv) override { return true; } | 
|  | bool EncryptPacket(uint64_t packet_number, | 
|  | QuicStringPiece associated_data, | 
|  | QuicStringPiece plaintext, | 
|  | char* output, | 
|  | size_t* output_length, | 
|  | size_t max_output_length) override { | 
|  | packet_number_ = QuicPacketNumber(packet_number); | 
|  | associated_data_ = std::string(associated_data); | 
|  | plaintext_ = std::string(plaintext); | 
|  | memcpy(output, plaintext.data(), plaintext.length()); | 
|  | *output_length = plaintext.length(); | 
|  | return true; | 
|  | } | 
|  | size_t GetKeySize() const override { return 0; } | 
|  | size_t GetNoncePrefixSize() const override { return 0; } | 
|  | size_t GetIVSize() const override { return 0; } | 
|  | size_t GetMaxPlaintextSize(size_t ciphertext_size) const override { | 
|  | return ciphertext_size; | 
|  | } | 
|  | size_t GetCiphertextSize(size_t plaintext_size) const override { | 
|  | return plaintext_size; | 
|  | } | 
|  | QuicStringPiece GetKey() const override { return QuicStringPiece(); } | 
|  | QuicStringPiece GetNoncePrefix() const override { return QuicStringPiece(); } | 
|  |  | 
|  | QuicPacketNumber packet_number_; | 
|  | std::string associated_data_; | 
|  | std::string plaintext_; | 
|  | }; | 
|  |  | 
|  | class TestDecrypter : public QuicDecrypter { | 
|  | public: | 
|  | ~TestDecrypter() override {} | 
|  | bool SetKey(QuicStringPiece key) override { return true; } | 
|  | bool SetNoncePrefix(QuicStringPiece nonce_prefix) override { return true; } | 
|  | bool SetIV(QuicStringPiece iv) override { return true; } | 
|  | bool SetPreliminaryKey(QuicStringPiece key) override { | 
|  | QUIC_BUG << "should not be called"; | 
|  | return false; | 
|  | } | 
|  | bool SetDiversificationNonce(const DiversificationNonce& key) override { | 
|  | return true; | 
|  | } | 
|  | bool DecryptPacket(uint64_t packet_number, | 
|  | QuicStringPiece associated_data, | 
|  | QuicStringPiece ciphertext, | 
|  | char* output, | 
|  | size_t* output_length, | 
|  | size_t max_output_length) override { | 
|  | packet_number_ = QuicPacketNumber(packet_number); | 
|  | associated_data_ = std::string(associated_data); | 
|  | ciphertext_ = std::string(ciphertext); | 
|  | memcpy(output, ciphertext.data(), ciphertext.length()); | 
|  | *output_length = ciphertext.length(); | 
|  | return true; | 
|  | } | 
|  | size_t GetKeySize() const override { return 0; } | 
|  | size_t GetIVSize() const override { return 0; } | 
|  | QuicStringPiece GetKey() const override { return QuicStringPiece(); } | 
|  | QuicStringPiece GetNoncePrefix() const override { return QuicStringPiece(); } | 
|  | // Use a distinct value starting with 0xFFFFFF, which is never used by TLS. | 
|  | uint32_t cipher_id() const override { return 0xFFFFFFF2; } | 
|  | QuicPacketNumber packet_number_; | 
|  | std::string associated_data_; | 
|  | std::string ciphertext_; | 
|  | }; | 
|  |  | 
|  | class TestQuicVisitor : public QuicFramerVisitorInterface { | 
|  | public: | 
|  | TestQuicVisitor() | 
|  | : error_count_(0), | 
|  | version_mismatch_(0), | 
|  | packet_count_(0), | 
|  | frame_count_(0), | 
|  | complete_packets_(0), | 
|  | accept_packet_(true), | 
|  | accept_public_header_(true) {} | 
|  |  | 
|  | ~TestQuicVisitor() override {} | 
|  |  | 
|  | void OnError(QuicFramer* f) override { | 
|  | QUIC_DLOG(INFO) << "QuicFramer Error: " << QuicErrorCodeToString(f->error()) | 
|  | << " (" << f->error() << ")"; | 
|  | ++error_count_; | 
|  | } | 
|  |  | 
|  | void OnPacket() override {} | 
|  |  | 
|  | void OnPublicResetPacket(const QuicPublicResetPacket& packet) override { | 
|  | public_reset_packet_ = QuicMakeUnique<QuicPublicResetPacket>((packet)); | 
|  | } | 
|  |  | 
|  | void OnVersionNegotiationPacket( | 
|  | const QuicVersionNegotiationPacket& packet) override { | 
|  | version_negotiation_packet_ = | 
|  | QuicMakeUnique<QuicVersionNegotiationPacket>((packet)); | 
|  | } | 
|  |  | 
|  | bool OnProtocolVersionMismatch(ParsedQuicVersion received_version, | 
|  | PacketHeaderFormat /*form*/) override { | 
|  | QUIC_DLOG(INFO) << "QuicFramer Version Mismatch, version: " | 
|  | << received_version; | 
|  | ++version_mismatch_; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool OnUnauthenticatedPublicHeader(const QuicPacketHeader& header) override { | 
|  | header_ = QuicMakeUnique<QuicPacketHeader>((header)); | 
|  | return accept_public_header_; | 
|  | } | 
|  |  | 
|  | bool OnUnauthenticatedHeader(const QuicPacketHeader& header) override { | 
|  | return true; | 
|  | } | 
|  |  | 
|  | void OnDecryptedPacket(EncryptionLevel level) override {} | 
|  |  | 
|  | bool OnPacketHeader(const QuicPacketHeader& header) override { | 
|  | ++packet_count_; | 
|  | header_ = QuicMakeUnique<QuicPacketHeader>((header)); | 
|  | return accept_packet_; | 
|  | } | 
|  |  | 
|  | void OnCoalescedPacket(const QuicEncryptedPacket& packet) override { | 
|  | size_t coalesced_data_length = packet.length(); | 
|  | char* coalesced_data = new char[coalesced_data_length]; | 
|  | memcpy(coalesced_data, packet.data(), coalesced_data_length); | 
|  | coalesced_packets_.push_back(QuicMakeUnique<QuicEncryptedPacket>( | 
|  | coalesced_data, coalesced_data_length, | 
|  | /*owns_buffer=*/true)); | 
|  | } | 
|  |  | 
|  | bool OnStreamFrame(const QuicStreamFrame& frame) override { | 
|  | ++frame_count_; | 
|  | // Save a copy of the data so it is valid after the packet is processed. | 
|  | std::string* string_data = | 
|  | new std::string(frame.data_buffer, frame.data_length); | 
|  | stream_data_.push_back(QuicWrapUnique(string_data)); | 
|  | stream_frames_.push_back(QuicMakeUnique<QuicStreamFrame>( | 
|  | frame.stream_id, frame.fin, frame.offset, *string_data)); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool OnCryptoFrame(const QuicCryptoFrame& frame) override { | 
|  | ++frame_count_; | 
|  | // Save a copy of the data so it is valid after the packet is processed. | 
|  | std::string* string_data = | 
|  | new std::string(frame.data_buffer, frame.data_length); | 
|  | crypto_data_.push_back(QuicWrapUnique(string_data)); | 
|  | crypto_frames_.push_back(QuicMakeUnique<QuicCryptoFrame>( | 
|  | ENCRYPTION_INITIAL, frame.offset, *string_data)); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool OnAckFrameStart(QuicPacketNumber largest_acked, | 
|  | QuicTime::Delta ack_delay_time) override { | 
|  | ++frame_count_; | 
|  | QuicAckFrame ack_frame; | 
|  | ack_frame.largest_acked = largest_acked; | 
|  | ack_frame.ack_delay_time = ack_delay_time; | 
|  | ack_frames_.push_back(QuicMakeUnique<QuicAckFrame>(ack_frame)); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool OnAckRange(QuicPacketNumber start, QuicPacketNumber end) override { | 
|  | DCHECK(!ack_frames_.empty()); | 
|  | ack_frames_[ack_frames_.size() - 1]->packets.AddRange(start, end); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool OnAckTimestamp(QuicPacketNumber packet_number, | 
|  | QuicTime timestamp) override { | 
|  | ack_frames_[ack_frames_.size() - 1]->received_packet_times.push_back( | 
|  | std::make_pair(packet_number, timestamp)); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool OnAckFrameEnd(QuicPacketNumber /*start*/) override { return true; } | 
|  |  | 
|  | bool OnStopWaitingFrame(const QuicStopWaitingFrame& frame) override { | 
|  | ++frame_count_; | 
|  | stop_waiting_frames_.push_back(QuicMakeUnique<QuicStopWaitingFrame>(frame)); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool OnPaddingFrame(const QuicPaddingFrame& frame) override { | 
|  | padding_frames_.push_back(QuicMakeUnique<QuicPaddingFrame>(frame)); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool OnPingFrame(const QuicPingFrame& frame) override { | 
|  | ++frame_count_; | 
|  | ping_frames_.push_back(QuicMakeUnique<QuicPingFrame>(frame)); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool OnMessageFrame(const QuicMessageFrame& frame) override { | 
|  | ++frame_count_; | 
|  | message_frames_.push_back( | 
|  | QuicMakeUnique<QuicMessageFrame>(frame.data, frame.message_length)); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | void OnPacketComplete() override { ++complete_packets_; } | 
|  |  | 
|  | bool OnRstStreamFrame(const QuicRstStreamFrame& frame) override { | 
|  | rst_stream_frame_ = frame; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool OnConnectionCloseFrame(const QuicConnectionCloseFrame& frame) override { | 
|  | connection_close_frame_ = frame; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool OnApplicationCloseFrame( | 
|  | const QuicApplicationCloseFrame& frame) override { | 
|  | application_close_frame_ = frame; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool OnStopSendingFrame(const QuicStopSendingFrame& frame) override { | 
|  | stop_sending_frame_ = frame; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool OnPathChallengeFrame(const QuicPathChallengeFrame& frame) override { | 
|  | path_challenge_frame_ = frame; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool OnPathResponseFrame(const QuicPathResponseFrame& frame) override { | 
|  | path_response_frame_ = frame; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool OnGoAwayFrame(const QuicGoAwayFrame& frame) override { | 
|  | goaway_frame_ = frame; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool OnMaxStreamIdFrame(const QuicMaxStreamIdFrame& frame) override { | 
|  | max_stream_id_frame_ = frame; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool OnStreamIdBlockedFrame(const QuicStreamIdBlockedFrame& frame) override { | 
|  | stream_id_blocked_frame_ = frame; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) override { | 
|  | window_update_frame_ = frame; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool OnBlockedFrame(const QuicBlockedFrame& frame) override { | 
|  | blocked_frame_ = frame; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool OnNewConnectionIdFrame(const QuicNewConnectionIdFrame& frame) override { | 
|  | new_connection_id_ = frame; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool OnRetireConnectionIdFrame( | 
|  | const QuicRetireConnectionIdFrame& frame) override { | 
|  | retire_connection_id_ = frame; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool OnNewTokenFrame(const QuicNewTokenFrame& frame) override { | 
|  | new_token_ = frame; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool IsValidStatelessResetToken(QuicUint128 token) const override { | 
|  | return token == kTestStatelessResetToken; | 
|  | } | 
|  |  | 
|  | void OnAuthenticatedIetfStatelessResetPacket( | 
|  | const QuicIetfStatelessResetPacket& packet) override { | 
|  | stateless_reset_packet_ = | 
|  | QuicMakeUnique<QuicIetfStatelessResetPacket>(packet); | 
|  | } | 
|  |  | 
|  | // Counters from the visitor_ callbacks. | 
|  | int error_count_; | 
|  | int version_mismatch_; | 
|  | int packet_count_; | 
|  | int frame_count_; | 
|  | int complete_packets_; | 
|  | bool accept_packet_; | 
|  | bool accept_public_header_; | 
|  |  | 
|  | std::unique_ptr<QuicPacketHeader> header_; | 
|  | std::unique_ptr<QuicPublicResetPacket> public_reset_packet_; | 
|  | std::unique_ptr<QuicIetfStatelessResetPacket> stateless_reset_packet_; | 
|  | std::unique_ptr<QuicVersionNegotiationPacket> version_negotiation_packet_; | 
|  | std::vector<std::unique_ptr<QuicStreamFrame>> stream_frames_; | 
|  | std::vector<std::unique_ptr<QuicCryptoFrame>> crypto_frames_; | 
|  | std::vector<std::unique_ptr<QuicAckFrame>> ack_frames_; | 
|  | std::vector<std::unique_ptr<QuicStopWaitingFrame>> stop_waiting_frames_; | 
|  | std::vector<std::unique_ptr<QuicPaddingFrame>> padding_frames_; | 
|  | std::vector<std::unique_ptr<QuicPingFrame>> ping_frames_; | 
|  | std::vector<std::unique_ptr<QuicMessageFrame>> message_frames_; | 
|  | std::vector<std::unique_ptr<QuicEncryptedPacket>> coalesced_packets_; | 
|  | QuicRstStreamFrame rst_stream_frame_; | 
|  | QuicConnectionCloseFrame connection_close_frame_; | 
|  | QuicApplicationCloseFrame application_close_frame_; | 
|  | QuicStopSendingFrame stop_sending_frame_; | 
|  | QuicGoAwayFrame goaway_frame_; | 
|  | QuicPathChallengeFrame path_challenge_frame_; | 
|  | QuicPathResponseFrame path_response_frame_; | 
|  | QuicWindowUpdateFrame window_update_frame_; | 
|  | QuicBlockedFrame blocked_frame_; | 
|  | QuicStreamIdBlockedFrame stream_id_blocked_frame_; | 
|  | QuicMaxStreamIdFrame max_stream_id_frame_; | 
|  | QuicNewConnectionIdFrame new_connection_id_; | 
|  | QuicRetireConnectionIdFrame retire_connection_id_; | 
|  | QuicNewTokenFrame new_token_; | 
|  | std::vector<std::unique_ptr<std::string>> stream_data_; | 
|  | std::vector<std::unique_ptr<std::string>> crypto_data_; | 
|  | }; | 
|  |  | 
|  | // Simple struct for defining a packet's content, and associated | 
|  | // parse error. | 
|  | struct PacketFragment { | 
|  | std::string error_if_missing; | 
|  | std::vector<unsigned char> fragment; | 
|  | }; | 
|  |  | 
|  | using PacketFragments = std::vector<struct PacketFragment>; | 
|  |  | 
|  | ParsedQuicVersionVector AllSupportedVersionsIncludingTls() { | 
|  | QuicFlagSaver flags; | 
|  | SetQuicFlag(&FLAGS_quic_supports_tls_handshake, true); | 
|  | return AllSupportedVersions(); | 
|  | } | 
|  |  | 
|  | class QuicFramerTest : public QuicTestWithParam<ParsedQuicVersion> { | 
|  | public: | 
|  | QuicFramerTest() | 
|  | : encrypter_(new test::TestEncrypter()), | 
|  | decrypter_(new test::TestDecrypter()), | 
|  | version_(GetParam()), | 
|  | start_(QuicTime::Zero() + QuicTime::Delta::FromMicroseconds(0x10)), | 
|  | framer_(AllSupportedVersionsIncludingTls(), | 
|  | start_, | 
|  | Perspective::IS_SERVER, | 
|  | kQuicDefaultConnectionIdLength) { | 
|  | SetQuicFlag(&FLAGS_quic_supports_tls_handshake, true); | 
|  | framer_.set_version(version_); | 
|  | framer_.SetDecrypter(ENCRYPTION_INITIAL, | 
|  | std::unique_ptr<QuicDecrypter>(decrypter_)); | 
|  | framer_.SetEncrypter(ENCRYPTION_INITIAL, | 
|  | std::unique_ptr<QuicEncrypter>(encrypter_)); | 
|  |  | 
|  | framer_.set_visitor(&visitor_); | 
|  | framer_.InferPacketHeaderTypeFromVersion(); | 
|  | } | 
|  |  | 
|  | // Helper function to get unsigned char representation of the handshake | 
|  | // protocol byte of the current QUIC version number. | 
|  | unsigned char GetQuicVersionProtocolByte() { | 
|  | return (CreateQuicVersionLabel(version_) >> 24) & 0xff; | 
|  | } | 
|  |  | 
|  | // Helper function to get unsigned char representation of digit in the | 
|  | // units place of the current QUIC version number. | 
|  | unsigned char GetQuicVersionDigitOnes() { | 
|  | return CreateQuicVersionLabel(version_) & 0xff; | 
|  | } | 
|  |  | 
|  | // Helper function to get unsigned char representation of digit in the | 
|  | // tens place of the current QUIC version number. | 
|  | unsigned char GetQuicVersionDigitTens() { | 
|  | return (CreateQuicVersionLabel(version_) >> 8) & 0xff; | 
|  | } | 
|  |  | 
|  | bool CheckEncryption(QuicPacketNumber packet_number, QuicPacket* packet) { | 
|  | if (packet_number != encrypter_->packet_number_) { | 
|  | QUIC_LOG(ERROR) << "Encrypted incorrect packet number.  expected " | 
|  | << packet_number | 
|  | << " actual: " << encrypter_->packet_number_; | 
|  | return false; | 
|  | } | 
|  | if (packet->AssociatedData(framer_.transport_version()) != | 
|  | encrypter_->associated_data_) { | 
|  | QUIC_LOG(ERROR) << "Encrypted incorrect associated data.  expected " | 
|  | << packet->AssociatedData(framer_.transport_version()) | 
|  | << " actual: " << encrypter_->associated_data_; | 
|  | return false; | 
|  | } | 
|  | if (packet->Plaintext(framer_.transport_version()) != | 
|  | encrypter_->plaintext_) { | 
|  | QUIC_LOG(ERROR) << "Encrypted incorrect plaintext data.  expected " | 
|  | << packet->Plaintext(framer_.transport_version()) | 
|  | << " actual: " << encrypter_->plaintext_; | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool CheckDecryption(const QuicEncryptedPacket& encrypted, | 
|  | bool includes_version, | 
|  | bool includes_diversification_nonce, | 
|  | QuicConnectionIdLength destination_connection_id_length, | 
|  | QuicConnectionIdLength source_connection_id_length) { | 
|  | return CheckDecryption( | 
|  | encrypted, includes_version, includes_diversification_nonce, | 
|  | destination_connection_id_length, source_connection_id_length, | 
|  | VARIABLE_LENGTH_INTEGER_LENGTH_0, 0, VARIABLE_LENGTH_INTEGER_LENGTH_0); | 
|  | } | 
|  |  | 
|  | bool CheckDecryption( | 
|  | const QuicEncryptedPacket& encrypted, | 
|  | bool includes_version, | 
|  | bool includes_diversification_nonce, | 
|  | QuicConnectionIdLength destination_connection_id_length, | 
|  | QuicConnectionIdLength source_connection_id_length, | 
|  | QuicVariableLengthIntegerLength retry_token_length_length, | 
|  | size_t retry_token_length, | 
|  | QuicVariableLengthIntegerLength length_length) { | 
|  | if (visitor_.header_->packet_number != decrypter_->packet_number_) { | 
|  | QUIC_LOG(ERROR) << "Decrypted incorrect packet number.  expected " | 
|  | << visitor_.header_->packet_number | 
|  | << " actual: " << decrypter_->packet_number_; | 
|  | return false; | 
|  | } | 
|  | QuicStringPiece associated_data = | 
|  | QuicFramer::GetAssociatedDataFromEncryptedPacket( | 
|  | framer_.transport_version(), encrypted, | 
|  | destination_connection_id_length, source_connection_id_length, | 
|  | includes_version, includes_diversification_nonce, | 
|  | PACKET_4BYTE_PACKET_NUMBER, retry_token_length_length, | 
|  | retry_token_length, length_length); | 
|  | if (associated_data != decrypter_->associated_data_) { | 
|  | QUIC_LOG(ERROR) << "Decrypted incorrect associated data.  expected " | 
|  | << QuicTextUtils::HexEncode(associated_data) | 
|  | << " actual: " | 
|  | << QuicTextUtils::HexEncode(decrypter_->associated_data_); | 
|  | return false; | 
|  | } | 
|  | QuicStringPiece ciphertext( | 
|  | encrypted.AsStringPiece().substr(GetStartOfEncryptedData( | 
|  | framer_.transport_version(), destination_connection_id_length, | 
|  | source_connection_id_length, includes_version, | 
|  | includes_diversification_nonce, PACKET_4BYTE_PACKET_NUMBER, | 
|  | retry_token_length_length, retry_token_length, length_length))); | 
|  | if (ciphertext != decrypter_->ciphertext_) { | 
|  | QUIC_LOG(ERROR) << "Decrypted incorrect ciphertext data.  expected " | 
|  | << QuicTextUtils::HexEncode(ciphertext) << " actual: " | 
|  | << QuicTextUtils::HexEncode(decrypter_->ciphertext_) | 
|  | << " associated data: " | 
|  | << QuicTextUtils::HexEncode(associated_data); | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | char* AsChars(unsigned char* data) { return reinterpret_cast<char*>(data); } | 
|  |  | 
|  | // Creates a new QuicEncryptedPacket by concatenating the various | 
|  | // packet fragments in |fragments|. | 
|  | std::unique_ptr<QuicEncryptedPacket> AssemblePacketFromFragments( | 
|  | const PacketFragments& fragments) { | 
|  | char* buffer = new char[kMaxPacketSize + 1]; | 
|  | size_t len = 0; | 
|  | for (const auto& fragment : fragments) { | 
|  | memcpy(buffer + len, fragment.fragment.data(), fragment.fragment.size()); | 
|  | len += fragment.fragment.size(); | 
|  | } | 
|  | return QuicMakeUnique<QuicEncryptedPacket>(buffer, len, true); | 
|  | } | 
|  |  | 
|  | void CheckFramingBoundaries(const PacketFragments& fragments, | 
|  | QuicErrorCode error_code) { | 
|  | std::unique_ptr<QuicEncryptedPacket> packet( | 
|  | AssemblePacketFromFragments(fragments)); | 
|  | // Check all the various prefixes of |packet| for the expected | 
|  | // parse error and error code. | 
|  | for (size_t i = 0; i < packet->length(); ++i) { | 
|  | std::string expected_error; | 
|  | size_t len = 0; | 
|  | for (const auto& fragment : fragments) { | 
|  | len += fragment.fragment.size(); | 
|  | if (i < len) { | 
|  | expected_error = fragment.error_if_missing; | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (expected_error.empty()) | 
|  | continue; | 
|  |  | 
|  | CheckProcessingFails(*packet, i, expected_error, error_code); | 
|  | } | 
|  | } | 
|  |  | 
|  | void CheckProcessingFails(const QuicEncryptedPacket& packet, | 
|  | size_t len, | 
|  | std::string expected_error, | 
|  | QuicErrorCode error_code) { | 
|  | QuicEncryptedPacket encrypted(packet.data(), len, false); | 
|  | EXPECT_FALSE(framer_.ProcessPacket(encrypted)) << "len: " << len; | 
|  | EXPECT_EQ(expected_error, framer_.detailed_error()) << "len: " << len; | 
|  | EXPECT_EQ(error_code, framer_.error()) << "len: " << len; | 
|  | } | 
|  |  | 
|  | void CheckProcessingFails(unsigned char* packet, | 
|  | size_t len, | 
|  | std::string expected_error, | 
|  | QuicErrorCode error_code) { | 
|  | QuicEncryptedPacket encrypted(AsChars(packet), len, false); | 
|  | EXPECT_FALSE(framer_.ProcessPacket(encrypted)) << "len: " << len; | 
|  | EXPECT_EQ(expected_error, framer_.detailed_error()) << "len: " << len; | 
|  | EXPECT_EQ(error_code, framer_.error()) << "len: " << len; | 
|  | } | 
|  |  | 
|  | // Checks if the supplied string matches data in the supplied StreamFrame. | 
|  | void CheckStreamFrameData(std::string str, QuicStreamFrame* frame) { | 
|  | EXPECT_EQ(str, std::string(frame->data_buffer, frame->data_length)); | 
|  | } | 
|  |  | 
|  | void CheckCalculatePacketNumber(uint64_t expected_packet_number, | 
|  | QuicPacketNumber last_packet_number) { | 
|  | uint64_t wire_packet_number = expected_packet_number & kMask; | 
|  | EXPECT_EQ(expected_packet_number, | 
|  | QuicFramerPeer::CalculatePacketNumberFromWire( | 
|  | &framer_, PACKET_4BYTE_PACKET_NUMBER, last_packet_number, | 
|  | wire_packet_number)) | 
|  | << "last_packet_number: " << last_packet_number | 
|  | << " wire_packet_number: " << wire_packet_number; | 
|  | } | 
|  |  | 
|  | std::unique_ptr<QuicPacket> BuildDataPacket(const QuicPacketHeader& header, | 
|  | const QuicFrames& frames) { | 
|  | return BuildUnsizedDataPacket(&framer_, header, frames); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<QuicPacket> BuildDataPacket(const QuicPacketHeader& header, | 
|  | const QuicFrames& frames, | 
|  | size_t packet_size) { | 
|  | return BuildUnsizedDataPacket(&framer_, header, frames, packet_size); | 
|  | } | 
|  |  | 
|  | // N starts at 1. | 
|  | QuicStreamId GetNthStreamid(QuicTransportVersion transport_version, | 
|  | Perspective perspective, | 
|  | bool bidirectional, | 
|  | int n) { | 
|  | if (bidirectional) { | 
|  | return QuicUtils::GetFirstBidirectionalStreamId(transport_version, | 
|  | perspective) + | 
|  | ((n - 1) * QuicUtils::StreamIdDelta(transport_version)); | 
|  | } | 
|  | // Unidirectional | 
|  | return QuicUtils::GetFirstUnidirectionalStreamId(transport_version, | 
|  | perspective) + | 
|  | ((n - 1) * QuicUtils::StreamIdDelta(transport_version)); | 
|  | } | 
|  |  | 
|  | test::TestEncrypter* encrypter_; | 
|  | test::TestDecrypter* decrypter_; | 
|  | ParsedQuicVersion version_; | 
|  | QuicTime start_; | 
|  | QuicFramer framer_; | 
|  | test::TestQuicVisitor visitor_; | 
|  | SimpleBufferAllocator allocator_; | 
|  | }; | 
|  |  | 
|  | // Multiple test cases of QuicFramerTest use byte arrays to define packets for | 
|  | // testing, and these byte arrays contain the QUIC version. This macro explodes | 
|  | // the 32-bit version into four bytes in network order. Since it uses methods of | 
|  | // QuicFramerTest, it is only valid to use this in a QuicFramerTest. | 
|  | #define QUIC_VERSION_BYTES                                      \ | 
|  | GetQuicVersionProtocolByte(), '0', GetQuicVersionDigitTens(), \ | 
|  | GetQuicVersionDigitOnes() | 
|  |  | 
|  | // Run all framer tests with all supported versions of QUIC. | 
|  | INSTANTIATE_TEST_SUITE_P( | 
|  | QuicFramerTests, | 
|  | QuicFramerTest, | 
|  | ::testing::ValuesIn(AllSupportedVersionsIncludingTls())); | 
|  |  | 
|  | TEST_P(QuicFramerTest, CalculatePacketNumberFromWireNearEpochStart) { | 
|  | // A few quick manual sanity checks. | 
|  | CheckCalculatePacketNumber(UINT64_C(1), QuicPacketNumber()); | 
|  | CheckCalculatePacketNumber(kEpoch + 1, QuicPacketNumber(kMask)); | 
|  | CheckCalculatePacketNumber(kEpoch, QuicPacketNumber(kMask)); | 
|  | for (uint64_t j = 0; j < 10; j++) { | 
|  | CheckCalculatePacketNumber(j, QuicPacketNumber()); | 
|  | CheckCalculatePacketNumber(kEpoch - 1 - j, QuicPacketNumber()); | 
|  | } | 
|  |  | 
|  | // Cases where the last number was close to the start of the range. | 
|  | for (QuicPacketNumber last = QuicPacketNumber(1); last < QuicPacketNumber(10); | 
|  | last++) { | 
|  | // Small numbers should not wrap (even if they're out of order). | 
|  | for (uint64_t j = 0; j < 10; j++) { | 
|  | CheckCalculatePacketNumber(j, last); | 
|  | } | 
|  |  | 
|  | // Large numbers should not wrap either (because we're near 0 already). | 
|  | for (uint64_t j = 0; j < 10; j++) { | 
|  | CheckCalculatePacketNumber(kEpoch - 1 - j, last); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, CalculatePacketNumberFromWireNearEpochEnd) { | 
|  | // Cases where the last number was close to the end of the range | 
|  | for (uint64_t i = 0; i < 10; i++) { | 
|  | QuicPacketNumber last = QuicPacketNumber(kEpoch - i); | 
|  |  | 
|  | // Small numbers should wrap. | 
|  | for (uint64_t j = 0; j < 10; j++) { | 
|  | CheckCalculatePacketNumber(kEpoch + j, last); | 
|  | } | 
|  |  | 
|  | // Large numbers should not (even if they're out of order). | 
|  | for (uint64_t j = 0; j < 10; j++) { | 
|  | CheckCalculatePacketNumber(kEpoch - 1 - j, last); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // Next check where we're in a non-zero epoch to verify we handle | 
|  | // reverse wrapping, too. | 
|  | TEST_P(QuicFramerTest, CalculatePacketNumberFromWireNearPrevEpoch) { | 
|  | const uint64_t prev_epoch = 1 * kEpoch; | 
|  | const uint64_t cur_epoch = 2 * kEpoch; | 
|  | // Cases where the last number was close to the start of the range | 
|  | for (uint64_t i = 0; i < 10; i++) { | 
|  | QuicPacketNumber last = QuicPacketNumber(cur_epoch + i); | 
|  | // Small number should not wrap (even if they're out of order). | 
|  | for (uint64_t j = 0; j < 10; j++) { | 
|  | CheckCalculatePacketNumber(cur_epoch + j, last); | 
|  | } | 
|  |  | 
|  | // But large numbers should reverse wrap. | 
|  | for (uint64_t j = 0; j < 10; j++) { | 
|  | uint64_t num = kEpoch - 1 - j; | 
|  | CheckCalculatePacketNumber(prev_epoch + num, last); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, CalculatePacketNumberFromWireNearNextEpoch) { | 
|  | const uint64_t cur_epoch = 2 * kEpoch; | 
|  | const uint64_t next_epoch = 3 * kEpoch; | 
|  | // Cases where the last number was close to the end of the range | 
|  | for (uint64_t i = 0; i < 10; i++) { | 
|  | QuicPacketNumber last = QuicPacketNumber(next_epoch - 1 - i); | 
|  |  | 
|  | // Small numbers should wrap. | 
|  | for (uint64_t j = 0; j < 10; j++) { | 
|  | CheckCalculatePacketNumber(next_epoch + j, last); | 
|  | } | 
|  |  | 
|  | // but large numbers should not (even if they're out of order). | 
|  | for (uint64_t j = 0; j < 10; j++) { | 
|  | uint64_t num = kEpoch - 1 - j; | 
|  | CheckCalculatePacketNumber(cur_epoch + num, last); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, CalculatePacketNumberFromWireNearNextMax) { | 
|  | const uint64_t max_number = std::numeric_limits<uint64_t>::max(); | 
|  | const uint64_t max_epoch = max_number & ~kMask; | 
|  |  | 
|  | // Cases where the last number was close to the end of the range | 
|  | for (uint64_t i = 0; i < 10; i++) { | 
|  | // Subtract 1, because the expected next packet number is 1 more than the | 
|  | // last packet number. | 
|  | QuicPacketNumber last = QuicPacketNumber(max_number - i - 1); | 
|  |  | 
|  | // Small numbers should not wrap, because they have nowhere to go. | 
|  | for (uint64_t j = 0; j < 10; j++) { | 
|  | CheckCalculatePacketNumber(max_epoch + j, last); | 
|  | } | 
|  |  | 
|  | // Large numbers should not wrap either. | 
|  | for (uint64_t j = 0; j < 10; j++) { | 
|  | uint64_t num = kEpoch - 1 - j; | 
|  | CheckCalculatePacketNumber(max_epoch + num, last); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, EmptyPacket) { | 
|  | char packet[] = {0x00}; | 
|  | QuicEncryptedPacket encrypted(packet, 0, false); | 
|  | EXPECT_FALSE(framer_.ProcessPacket(encrypted)); | 
|  | EXPECT_EQ(QUIC_INVALID_PACKET_HEADER, framer_.error()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, LargePacket) { | 
|  | // clang-format off | 
|  | unsigned char packet[kMaxPacketSize + 1] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x28, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x78, 0x56, 0x34, 0x12, | 
|  | // private flags | 
|  | 0x00, | 
|  | }; | 
|  | unsigned char packet44[kMaxPacketSize + 1] = { | 
|  | // type (short header 4 byte packet number) | 
|  | 0x32, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x78, 0x56, 0x34, 0x12, | 
|  | }; | 
|  | unsigned char packet46[kMaxPacketSize + 1] = { | 
|  | // type (short header 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x78, 0x56, 0x34, 0x12, | 
|  | }; | 
|  | // clang-format on | 
|  | unsigned char* p = packet; | 
|  | size_t p_size = QUIC_ARRAYSIZE(packet); | 
|  | if (framer_.transport_version() > QUIC_VERSION_44) { | 
|  | p = packet46; | 
|  | p_size = QUIC_ARRAYSIZE(packet46); | 
|  | } else if (framer_.transport_version() > QUIC_VERSION_43) { | 
|  | p = packet44; | 
|  | p_size = QUIC_ARRAYSIZE(packet44); | 
|  | } | 
|  |  | 
|  | const size_t header_size = GetPacketHeaderSize( | 
|  | framer_.transport_version(), PACKET_8BYTE_CONNECTION_ID, | 
|  | PACKET_0BYTE_CONNECTION_ID, !kIncludeVersion, | 
|  | !kIncludeDiversificationNonce, PACKET_4BYTE_PACKET_NUMBER, | 
|  | VARIABLE_LENGTH_INTEGER_LENGTH_0, 0, VARIABLE_LENGTH_INTEGER_LENGTH_0); | 
|  |  | 
|  | memset(p + header_size, 0, kMaxPacketSize - header_size); | 
|  |  | 
|  | QuicEncryptedPacket encrypted(AsChars(p), p_size, false); | 
|  | EXPECT_QUIC_BUG(framer_.ProcessPacket(encrypted), "Packet too large:1"); | 
|  |  | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | // Make sure we've parsed the packet header, so we can send an error. | 
|  | EXPECT_EQ(FramerTestConnectionId(), | 
|  | visitor_.header_->destination_connection_id); | 
|  | // Make sure the correct error is propagated. | 
|  | EXPECT_EQ(QUIC_PACKET_TOO_LARGE, framer_.error()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, PacketHeader) { | 
|  | if (framer_.transport_version() > QUIC_VERSION_43) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | // clang-format off | 
|  | PacketFragments packet = { | 
|  | // public flags (8 byte connection_id) | 
|  | {"Unable to read public flags.", | 
|  | {0x28}}, | 
|  | // connection_id | 
|  | {"Unable to read ConnectionId.", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"Unable to read packet number.", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | PacketFragments& fragments = packet; | 
|  |  | 
|  | std::unique_ptr<QuicEncryptedPacket> encrypted( | 
|  | AssemblePacketFromFragments(fragments)); | 
|  |  | 
|  | EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); | 
|  | EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_EQ(FramerTestConnectionId(), | 
|  | visitor_.header_->destination_connection_id); | 
|  | EXPECT_FALSE(visitor_.header_->reset_flag); | 
|  | EXPECT_FALSE(visitor_.header_->version_flag); | 
|  | EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number); | 
|  |  | 
|  | CheckFramingBoundaries(fragments, QUIC_INVALID_PACKET_HEADER); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, LongPacketHeader) { | 
|  | // clang-format off | 
|  | PacketFragments packet44 = { | 
|  | // type (long header with packet type INITIAL) | 
|  | {"Unable to read type.", | 
|  | {0xFF}}, | 
|  | // version tag | 
|  | {"Unable to read protocol version.", | 
|  | {QUIC_VERSION_BYTES}}, | 
|  | // connection_id length | 
|  | {"Unable to read ConnectionId length.", | 
|  | {0x50}}, | 
|  | // connection_id | 
|  | {"Unable to read Destination ConnectionId.", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"Unable to read packet number.", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | }; | 
|  | PacketFragments packet46 = { | 
|  | // type (long header with packet type INITIAL) | 
|  | {"Unable to read type.", | 
|  | {0xC3}}, | 
|  | // version tag | 
|  | {"Unable to read protocol version.", | 
|  | {QUIC_VERSION_BYTES}}, | 
|  | // connection_id length | 
|  | {"Unable to read ConnectionId length.", | 
|  | {0x50}}, | 
|  | // connection_id | 
|  | {"Unable to read Destination ConnectionId.", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"Unable to read packet number.", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | if (framer_.transport_version() <= QUIC_VERSION_43 || | 
|  | QuicVersionHasLongHeaderLengths(framer_.transport_version())) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | PacketFragments& fragments = | 
|  | framer_.transport_version() > QUIC_VERSION_44 ? packet46 : packet44; | 
|  | std::unique_ptr<QuicEncryptedPacket> encrypted( | 
|  | AssemblePacketFromFragments(fragments)); | 
|  |  | 
|  | EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); | 
|  | EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_EQ(FramerTestConnectionId(), | 
|  | visitor_.header_->destination_connection_id); | 
|  | EXPECT_FALSE(visitor_.header_->reset_flag); | 
|  | EXPECT_TRUE(visitor_.header_->version_flag); | 
|  | EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number); | 
|  |  | 
|  | CheckFramingBoundaries( | 
|  | framer_.transport_version() > QUIC_VERSION_44 ? packet46 : packet44, | 
|  | QUIC_INVALID_PACKET_HEADER); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, PacketHeaderWith0ByteConnectionId) { | 
|  | QuicFramerPeer::SetLastSerializedConnectionId(&framer_, | 
|  | FramerTestConnectionId()); | 
|  | QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); | 
|  |  | 
|  | // clang-format off | 
|  | PacketFragments packet = { | 
|  | // public flags (0 byte connection_id) | 
|  | {"Unable to read public flags.", | 
|  | {0x20}}, | 
|  | // connection_id | 
|  | // packet number | 
|  | {"Unable to read packet number.", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | }; | 
|  |  | 
|  | PacketFragments packet44 = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"Unable to read type.", | 
|  | {0x32}}, | 
|  | // connection_id | 
|  | // packet number | 
|  | {"Unable to read packet number.", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | }; | 
|  |  | 
|  | PacketFragments packet46 = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"Unable to read type.", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | // packet number | 
|  | {"Unable to read packet number.", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | PacketFragments& fragments = | 
|  | framer_.transport_version() > QUIC_VERSION_44 | 
|  | ? packet46 | 
|  | : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 : packet); | 
|  | std::unique_ptr<QuicEncryptedPacket> encrypted( | 
|  | AssemblePacketFromFragments(fragments)); | 
|  | EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); | 
|  | EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_EQ(FramerTestConnectionId(), | 
|  | visitor_.header_->destination_connection_id); | 
|  | EXPECT_FALSE(visitor_.header_->reset_flag); | 
|  | EXPECT_FALSE(visitor_.header_->version_flag); | 
|  | EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number); | 
|  |  | 
|  | CheckFramingBoundaries(fragments, QUIC_INVALID_PACKET_HEADER); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, PacketHeaderWithVersionFlag) { | 
|  | // clang-format off | 
|  | PacketFragments packet = { | 
|  | // public flags (0 byte connection_id) | 
|  | {"Unable to read public flags.", | 
|  | {0x29}}, | 
|  | // connection_id | 
|  | {"Unable to read ConnectionId.", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // version tag | 
|  | {"Unable to read protocol version.", | 
|  | {QUIC_VERSION_BYTES}}, | 
|  | // packet number | 
|  | {"Unable to read packet number.", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | }; | 
|  |  | 
|  | PacketFragments packet44 = { | 
|  | // type (long header with packet type ZERO_RTT_PROTECTED) | 
|  | {"Unable to read type.", | 
|  | {0xFC}}, | 
|  | // version tag | 
|  | {"Unable to read protocol version.", | 
|  | {QUIC_VERSION_BYTES}}, | 
|  | // connection_id length | 
|  | {"Unable to read ConnectionId length.", | 
|  | {0x50}}, | 
|  | // connection_id | 
|  | {"Unable to read Destination ConnectionId.", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"Unable to read packet number.", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | }; | 
|  |  | 
|  | PacketFragments packet46 = { | 
|  | // type (long header with packet type ZERO_RTT_PROTECTED and 4 bytes | 
|  | // packet number) | 
|  | {"Unable to read type.", | 
|  | {0xD3}}, | 
|  | // version tag | 
|  | {"Unable to read protocol version.", | 
|  | {QUIC_VERSION_BYTES}}, | 
|  | // connection_id length | 
|  | {"Unable to read ConnectionId length.", | 
|  | {0x50}}, | 
|  | // connection_id | 
|  | {"Unable to read Destination ConnectionId.", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"Unable to read packet number.", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | }; | 
|  |  | 
|  | PacketFragments packet99 = { | 
|  | // type (long header with packet type ZERO_RTT_PROTECTED and 4 bytes | 
|  | // packet number) | 
|  | {"Unable to read type.", | 
|  | {0xD3}}, | 
|  | // version tag | 
|  | {"Unable to read protocol version.", | 
|  | {QUIC_VERSION_BYTES}}, | 
|  | // connection_id length | 
|  | {"Unable to read ConnectionId length.", | 
|  | {0x50}}, | 
|  | // connection_id | 
|  | {"Unable to read Destination ConnectionId.", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // long header packet length | 
|  | {"Unable to read long header payload length.", | 
|  | {0x04}}, | 
|  | // packet number | 
|  | {"Long header payload length longer than packet.", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | PacketFragments& fragments = | 
|  | framer_.transport_version() == QUIC_VERSION_99 | 
|  | ? packet99 | 
|  | : framer_.transport_version() > QUIC_VERSION_44 | 
|  | ? packet46 | 
|  | : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 | 
|  | : packet); | 
|  | std::unique_ptr<QuicEncryptedPacket> encrypted( | 
|  | AssemblePacketFromFragments(fragments)); | 
|  | EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); | 
|  | EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_EQ(FramerTestConnectionId(), | 
|  | visitor_.header_->destination_connection_id); | 
|  | EXPECT_FALSE(visitor_.header_->reset_flag); | 
|  | EXPECT_TRUE(visitor_.header_->version_flag); | 
|  | EXPECT_EQ(GetParam(), visitor_.header_->version); | 
|  | EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number); | 
|  |  | 
|  | CheckFramingBoundaries(fragments, QUIC_INVALID_PACKET_HEADER); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, PacketHeaderWith4BytePacketNumber) { | 
|  | QuicFramerPeer::SetLargestPacketNumber(&framer_, kPacketNumber - 2); | 
|  |  | 
|  | // clang-format off | 
|  | PacketFragments packet = { | 
|  | // public flags (8 byte connection_id and 4 byte packet number) | 
|  | {"Unable to read public flags.", | 
|  | {0x28}}, | 
|  | // connection_id | 
|  | {"Unable to read ConnectionId.", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"Unable to read packet number.", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | }; | 
|  |  | 
|  | PacketFragments packet44 = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"Unable to read type.", | 
|  | {0x32}}, | 
|  | // connection_id | 
|  | {"Unable to read Destination ConnectionId.", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"Unable to read packet number.", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | }; | 
|  |  | 
|  | PacketFragments packet46 = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"Unable to read type.", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"Unable to read Destination ConnectionId.", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"Unable to read packet number.", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | PacketFragments& fragments = | 
|  | framer_.transport_version() > QUIC_VERSION_44 | 
|  | ? packet46 | 
|  | : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 : packet); | 
|  | std::unique_ptr<QuicEncryptedPacket> encrypted( | 
|  | AssemblePacketFromFragments(fragments)); | 
|  | EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); | 
|  | EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_EQ(FramerTestConnectionId(), | 
|  | visitor_.header_->destination_connection_id); | 
|  | EXPECT_FALSE(visitor_.header_->reset_flag); | 
|  | EXPECT_FALSE(visitor_.header_->version_flag); | 
|  | EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number); | 
|  |  | 
|  | CheckFramingBoundaries(fragments, QUIC_INVALID_PACKET_HEADER); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, PacketHeaderWith2BytePacketNumber) { | 
|  | QuicFramerPeer::SetLargestPacketNumber(&framer_, kPacketNumber - 2); | 
|  |  | 
|  | // clang-format off | 
|  | PacketFragments packet = { | 
|  | // public flags (8 byte connection_id and 2 byte packet number) | 
|  | {"Unable to read public flags.", | 
|  | {0x18}}, | 
|  | // connection_id | 
|  | {"Unable to read ConnectionId.", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"Unable to read packet number.", | 
|  | {0x56, 0x78}}, | 
|  | }; | 
|  |  | 
|  | PacketFragments packet44 = { | 
|  | // type (short header, 2 byte packet number) | 
|  | {"Unable to read type.", | 
|  | {0x31}}, | 
|  | // connection_id | 
|  | {"Unable to read Destination ConnectionId.", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"Unable to read packet number.", | 
|  | {0x56, 0x78}}, | 
|  | }; | 
|  |  | 
|  | PacketFragments packet46 = { | 
|  | // type (short header, 2 byte packet number) | 
|  | {"Unable to read type.", | 
|  | {0x41}}, | 
|  | // connection_id | 
|  | {"Unable to read Destination ConnectionId.", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"Unable to read packet number.", | 
|  | {0x56, 0x78}}, | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | PacketFragments& fragments = | 
|  | framer_.transport_version() > QUIC_VERSION_44 | 
|  | ? packet46 | 
|  | : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 : packet); | 
|  | std::unique_ptr<QuicEncryptedPacket> encrypted( | 
|  | AssemblePacketFromFragments(fragments)); | 
|  | EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); | 
|  | EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_EQ(FramerTestConnectionId(), | 
|  | visitor_.header_->destination_connection_id); | 
|  | EXPECT_FALSE(visitor_.header_->reset_flag); | 
|  | EXPECT_FALSE(visitor_.header_->version_flag); | 
|  | EXPECT_EQ(PACKET_2BYTE_PACKET_NUMBER, visitor_.header_->packet_number_length); | 
|  | EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number); | 
|  |  | 
|  | CheckFramingBoundaries(fragments, QUIC_INVALID_PACKET_HEADER); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, PacketHeaderWith1BytePacketNumber) { | 
|  | QuicFramerPeer::SetLargestPacketNumber(&framer_, kPacketNumber - 2); | 
|  |  | 
|  | // clang-format off | 
|  | PacketFragments packet = { | 
|  | // public flags (8 byte connection_id and 1 byte packet number) | 
|  | {"Unable to read public flags.", | 
|  | {0x08}}, | 
|  | // connection_id | 
|  | {"Unable to read ConnectionId.", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"Unable to read packet number.", | 
|  | {0x78}}, | 
|  | }; | 
|  |  | 
|  | PacketFragments packet44 = { | 
|  | // type (8 byte connection_id and 1 byte packet number) | 
|  | {"Unable to read type.", | 
|  | {0x30}}, | 
|  | // connection_id | 
|  | {"Unable to read Destination ConnectionId.", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"Unable to read packet number.", | 
|  | {0x78}}, | 
|  | }; | 
|  |  | 
|  | PacketFragments packet46 = { | 
|  | // type (8 byte connection_id and 1 byte packet number) | 
|  | {"Unable to read type.", | 
|  | {0x40}}, | 
|  | // connection_id | 
|  | {"Unable to read Destination ConnectionId.", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"Unable to read packet number.", | 
|  | {0x78}}, | 
|  | }; | 
|  |  | 
|  | // clang-format on | 
|  |  | 
|  | PacketFragments& fragments = | 
|  | framer_.transport_version() > QUIC_VERSION_44 | 
|  | ? packet46 | 
|  | : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 : packet); | 
|  | std::unique_ptr<QuicEncryptedPacket> encrypted( | 
|  | AssemblePacketFromFragments(fragments)); | 
|  | EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); | 
|  | EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_EQ(FramerTestConnectionId(), | 
|  | visitor_.header_->destination_connection_id); | 
|  | EXPECT_FALSE(visitor_.header_->reset_flag); | 
|  | EXPECT_FALSE(visitor_.header_->version_flag); | 
|  | EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER, visitor_.header_->packet_number_length); | 
|  | EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number); | 
|  |  | 
|  | CheckFramingBoundaries(fragments, QUIC_INVALID_PACKET_HEADER); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, PacketNumberDecreasesThenIncreases) { | 
|  | // Test the case when a packet is received from the past and future packet | 
|  | // numbers are still calculated relative to the largest received packet. | 
|  | QuicPacketHeader header; | 
|  | header.destination_connection_id = FramerTestConnectionId(); | 
|  | header.reset_flag = false; | 
|  | header.version_flag = false; | 
|  | header.packet_number = kPacketNumber - 2; | 
|  |  | 
|  | QuicFrames frames = {QuicFrame(QuicPaddingFrame())}; | 
|  | QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); | 
|  | std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  |  | 
|  | QuicEncryptedPacket encrypted(data->data(), data->length(), false); | 
|  | QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_SERVER); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(encrypted)); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_EQ(FramerTestConnectionId(), | 
|  | visitor_.header_->destination_connection_id); | 
|  | EXPECT_EQ(PACKET_4BYTE_PACKET_NUMBER, visitor_.header_->packet_number_length); | 
|  | EXPECT_EQ(kPacketNumber - 2, visitor_.header_->packet_number); | 
|  |  | 
|  | // Receive a 1 byte packet number. | 
|  | header.packet_number = kPacketNumber; | 
|  | header.packet_number_length = PACKET_1BYTE_PACKET_NUMBER; | 
|  | QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); | 
|  | data = BuildDataPacket(header, frames); | 
|  | QuicEncryptedPacket encrypted1(data->data(), data->length(), false); | 
|  | QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_SERVER); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(encrypted1)); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_EQ(FramerTestConnectionId(), | 
|  | visitor_.header_->destination_connection_id); | 
|  | EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER, visitor_.header_->packet_number_length); | 
|  | EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number); | 
|  |  | 
|  | // Process a 2 byte packet number 256 packets ago. | 
|  | header.packet_number = kPacketNumber - 256; | 
|  | header.packet_number_length = PACKET_2BYTE_PACKET_NUMBER; | 
|  | QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); | 
|  | data = BuildDataPacket(header, frames); | 
|  | QuicEncryptedPacket encrypted2(data->data(), data->length(), false); | 
|  | QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_SERVER); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(encrypted2)); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_EQ(FramerTestConnectionId(), | 
|  | visitor_.header_->destination_connection_id); | 
|  | EXPECT_EQ(PACKET_2BYTE_PACKET_NUMBER, visitor_.header_->packet_number_length); | 
|  | EXPECT_EQ(kPacketNumber - 256, visitor_.header_->packet_number); | 
|  |  | 
|  | // Process another 1 byte packet number and ensure it works. | 
|  | header.packet_number = kPacketNumber - 1; | 
|  | header.packet_number_length = PACKET_1BYTE_PACKET_NUMBER; | 
|  | QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); | 
|  | data = BuildDataPacket(header, frames); | 
|  | QuicEncryptedPacket encrypted3(data->data(), data->length(), false); | 
|  | QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_SERVER); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(encrypted3)); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_EQ(FramerTestConnectionId(), | 
|  | visitor_.header_->destination_connection_id); | 
|  | EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER, visitor_.header_->packet_number_length); | 
|  | EXPECT_EQ(kPacketNumber - 1, visitor_.header_->packet_number); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, PacketWithDiversificationNonce) { | 
|  | // clang-format off | 
|  | unsigned char packet[] = { | 
|  | // public flags: includes nonce flag | 
|  | 0x2C, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // nonce | 
|  | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, | 
|  | 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, | 
|  | 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, | 
|  | 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (padding) | 
|  | 0x00, | 
|  | 0x00, 0x00, 0x00, 0x00 | 
|  | }; | 
|  |  | 
|  | unsigned char packet44[] = { | 
|  | // type: Long header with packet type ZERO_RTT_PROTECTED | 
|  | 0xFC, | 
|  | // version tag | 
|  | QUIC_VERSION_BYTES, | 
|  | // connection_id length | 
|  | 0x05, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  | // nonce | 
|  | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, | 
|  | 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, | 
|  | 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, | 
|  | 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, | 
|  |  | 
|  | // frame type (padding) | 
|  | 0x00, | 
|  | 0x00, 0x00, 0x00, 0x00 | 
|  | }; | 
|  |  | 
|  | unsigned char packet46[] = { | 
|  | // type: Long header with packet type ZERO_RTT_PROTECTED and 1 byte packet | 
|  | // number. | 
|  | 0xD0, | 
|  | // version tag | 
|  | QUIC_VERSION_BYTES, | 
|  | // connection_id length | 
|  | 0x05, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x78, | 
|  | // nonce | 
|  | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, | 
|  | 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, | 
|  | 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, | 
|  | 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, | 
|  |  | 
|  | // frame type (padding) | 
|  | 0x00, | 
|  | 0x00, 0x00, 0x00, 0x00 | 
|  | }; | 
|  |  | 
|  | unsigned char packet99[] = { | 
|  | // type: Long header with packet type ZERO_RTT_PROTECTED and 1 byte packet | 
|  | // number. | 
|  | 0xD0, | 
|  | // version tag | 
|  | QUIC_VERSION_BYTES, | 
|  | // connection_id length | 
|  | 0x05, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // long header packet length | 
|  | 0x26, | 
|  | // packet number | 
|  | 0x78, | 
|  | // nonce | 
|  | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, | 
|  | 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, | 
|  | 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, | 
|  | 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, | 
|  |  | 
|  | // frame type (padding) | 
|  | 0x00, | 
|  | 0x00, 0x00, 0x00, 0x00 | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | if (framer_.version().handshake_protocol != PROTOCOL_QUIC_CRYPTO) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | unsigned char* p = packet; | 
|  | size_t p_size = QUIC_ARRAYSIZE(packet); | 
|  | if (framer_.transport_version() == QUIC_VERSION_99) { | 
|  | p = packet99; | 
|  | p_size = QUIC_ARRAYSIZE(packet99); | 
|  | } else if (framer_.transport_version() > QUIC_VERSION_44) { | 
|  | p = packet46; | 
|  | p_size = QUIC_ARRAYSIZE(packet46); | 
|  | } else if (framer_.transport_version() > QUIC_VERSION_43) { | 
|  | p = packet44; | 
|  | p_size = QUIC_ARRAYSIZE(packet44); | 
|  | } | 
|  |  | 
|  | QuicEncryptedPacket encrypted(AsChars(p), p_size, false); | 
|  | QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(encrypted)); | 
|  | ASSERT_TRUE(visitor_.header_->nonce != nullptr); | 
|  | for (char i = 0; i < 32; ++i) { | 
|  | EXPECT_EQ(i, (*visitor_.header_->nonce)[static_cast<size_t>(i)]); | 
|  | } | 
|  | EXPECT_EQ(1u, visitor_.padding_frames_.size()); | 
|  | EXPECT_EQ(5, visitor_.padding_frames_[0]->num_padding_bytes); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, LargePublicFlagWithMismatchedVersions) { | 
|  | // clang-format off | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id, version flag and an unknown flag) | 
|  | 0x29, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // version tag | 
|  | 'Q', '0', '0', '0', | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (padding frame) | 
|  | 0x00, | 
|  | 0x00, 0x00, 0x00, 0x00 | 
|  | }; | 
|  |  | 
|  | unsigned char packet44[] = { | 
|  | // type (long header with packet type ZERO_RTT_PROTECTED) | 
|  | 0xFC, | 
|  | // version tag | 
|  | 'Q', '0', '0', '0', | 
|  | // connection_id length | 
|  | 0x50, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (padding frame) | 
|  | 0x00, | 
|  | 0x00, 0x00, 0x00, 0x00 | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | QuicEncryptedPacket encrypted( | 
|  | AsChars(framer_.transport_version() > QUIC_VERSION_43 ? packet44 | 
|  | : packet), | 
|  | framer_.transport_version() > QUIC_VERSION_43 ? QUIC_ARRAYSIZE(packet44) | 
|  | : QUIC_ARRAYSIZE(packet), | 
|  | false); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(encrypted)); | 
|  | EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_EQ(0, visitor_.frame_count_); | 
|  | EXPECT_EQ(1, visitor_.version_mismatch_); | 
|  | EXPECT_EQ(1u, visitor_.padding_frames_.size()); | 
|  | EXPECT_EQ(5, visitor_.padding_frames_[0]->num_padding_bytes); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, PaddingFrame) { | 
|  | // clang-format off | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x28, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // paddings | 
|  | 0x00, 0x00, | 
|  | // frame type (stream frame with fin) | 
|  | 0xFF, | 
|  | // stream id | 
|  | 0x01, 0x02, 0x03, 0x04, | 
|  | // offset | 
|  | 0x3A, 0x98, 0xFE, 0xDC, | 
|  | 0x32, 0x10, 0x76, 0x54, | 
|  | // data length | 
|  | 0x00, 0x0c, | 
|  | // data | 
|  | 'h',  'e',  'l',  'l', | 
|  | 'o',  ' ',  'w',  'o', | 
|  | 'r',  'l',  'd',  '!', | 
|  | // paddings | 
|  | 0x00, 0x00, | 
|  | }; | 
|  |  | 
|  | unsigned char packet44[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x32, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // paddings | 
|  | 0x00, 0x00, | 
|  | // frame type (stream frame with fin) | 
|  | 0xFF, | 
|  | // stream id | 
|  | 0x01, 0x02, 0x03, 0x04, | 
|  | // offset | 
|  | 0x3A, 0x98, 0xFE, 0xDC, | 
|  | 0x32, 0x10, 0x76, 0x54, | 
|  | // data length | 
|  | 0x00, 0x0c, | 
|  | // data | 
|  | 'h',  'e',  'l',  'l', | 
|  | 'o',  ' ',  'w',  'o', | 
|  | 'r',  'l',  'd',  '!', | 
|  | // paddings | 
|  | 0x00, 0x00, | 
|  | }; | 
|  |  | 
|  | unsigned char packet46[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // paddings | 
|  | 0x00, 0x00, | 
|  | // frame type (stream frame with fin) | 
|  | 0xFF, | 
|  | // stream id | 
|  | 0x01, 0x02, 0x03, 0x04, | 
|  | // offset | 
|  | 0x3A, 0x98, 0xFE, 0xDC, | 
|  | 0x32, 0x10, 0x76, 0x54, | 
|  | // data length | 
|  | 0x00, 0x0c, | 
|  | // data | 
|  | 'h',  'e',  'l',  'l', | 
|  | 'o',  ' ',  'w',  'o', | 
|  | 'r',  'l',  'd',  '!', | 
|  | // paddings | 
|  | 0x00, 0x00, | 
|  | }; | 
|  |  | 
|  | unsigned char packet99[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // paddings | 
|  | 0x00, 0x00, | 
|  | // frame type - IETF_STREAM with FIN, LEN, and OFFSET bits set. | 
|  | 0x08 | 0x01 | 0x02 | 0x04, | 
|  |  | 
|  | // stream id | 
|  | kVarInt62FourBytes + 0x01, 0x02, 0x03, 0x04, | 
|  | // offset | 
|  | kVarInt62EightBytes + 0x3A, 0x98, 0xFE, 0xDC, | 
|  | 0x32, 0x10, 0x76, 0x54, | 
|  | // data length | 
|  | kVarInt62OneByte + 0x0c, | 
|  | // data | 
|  | 'h',  'e',  'l',  'l', | 
|  | 'o',  ' ',  'w',  'o', | 
|  | 'r',  'l',  'd',  '!', | 
|  | // paddings | 
|  | 0x00, 0x00, | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | unsigned char* p = packet; | 
|  | size_t p_size = QUIC_ARRAYSIZE(packet); | 
|  | if (framer_.transport_version() == QUIC_VERSION_99) { | 
|  | p = packet99; | 
|  | p_size = QUIC_ARRAYSIZE(packet99); | 
|  | } else if (framer_.transport_version() > QUIC_VERSION_44) { | 
|  | p = packet46; | 
|  | p_size = QUIC_ARRAYSIZE(packet46); | 
|  | } else if (framer_.transport_version() > QUIC_VERSION_43) { | 
|  | p = packet44; | 
|  | p_size = QUIC_ARRAYSIZE(packet44); | 
|  | } | 
|  |  | 
|  | QuicEncryptedPacket encrypted(AsChars(p), p_size, false); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(encrypted)); | 
|  | EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_TRUE(CheckDecryption( | 
|  | encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, | 
|  | PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); | 
|  |  | 
|  | ASSERT_EQ(1u, visitor_.stream_frames_.size()); | 
|  | EXPECT_EQ(0u, visitor_.ack_frames_.size()); | 
|  | EXPECT_EQ(2u, visitor_.padding_frames_.size()); | 
|  | EXPECT_EQ(2, visitor_.padding_frames_[0]->num_padding_bytes); | 
|  | EXPECT_EQ(2, visitor_.padding_frames_[1]->num_padding_bytes); | 
|  | EXPECT_EQ(kStreamId, visitor_.stream_frames_[0]->stream_id); | 
|  | EXPECT_TRUE(visitor_.stream_frames_[0]->fin); | 
|  | EXPECT_EQ(kStreamOffset, visitor_.stream_frames_[0]->offset); | 
|  | CheckStreamFrameData("hello world!", visitor_.stream_frames_[0].get()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, StreamFrame) { | 
|  | // clang-format off | 
|  | PacketFragments packet = { | 
|  | // public flags (8 byte connection_id) | 
|  | {"", | 
|  | {0x28}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | // frame type (stream frame with fin) | 
|  | {"", | 
|  | {0xFF}}, | 
|  | // stream id | 
|  | {"Unable to read stream_id.", | 
|  | {0x01, 0x02, 0x03, 0x04}}, | 
|  | // offset | 
|  | {"Unable to read offset.", | 
|  | {0x3A, 0x98, 0xFE, 0xDC, | 
|  | 0x32, 0x10, 0x76, 0x54}}, | 
|  | {"Unable to read frame data.", | 
|  | { | 
|  | // data length | 
|  | 0x00, 0x0c, | 
|  | // data | 
|  | 'h',  'e',  'l',  'l', | 
|  | 'o',  ' ',  'w',  'o', | 
|  | 'r',  'l',  'd',  '!'}}, | 
|  | }; | 
|  |  | 
|  | PacketFragments packet44 = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x32}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | // frame type (stream frame with fin) | 
|  | {"", | 
|  | {0xFF}}, | 
|  | // stream id | 
|  | {"Unable to read stream_id.", | 
|  | {0x01, 0x02, 0x03, 0x04}}, | 
|  | // offset | 
|  | {"Unable to read offset.", | 
|  | {0x3A, 0x98, 0xFE, 0xDC, | 
|  | 0x32, 0x10, 0x76, 0x54}}, | 
|  | {"Unable to read frame data.", | 
|  | { | 
|  | // data length | 
|  | 0x00, 0x0c, | 
|  | // data | 
|  | 'h',  'e',  'l',  'l', | 
|  | 'o',  ' ',  'w',  'o', | 
|  | 'r',  'l',  'd',  '!'}}, | 
|  | }; | 
|  |  | 
|  | PacketFragments packet46 = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | // frame type (stream frame with fin) | 
|  | {"", | 
|  | {0xFF}}, | 
|  | // stream id | 
|  | {"Unable to read stream_id.", | 
|  | {0x01, 0x02, 0x03, 0x04}}, | 
|  | // offset | 
|  | {"Unable to read offset.", | 
|  | {0x3A, 0x98, 0xFE, 0xDC, | 
|  | 0x32, 0x10, 0x76, 0x54}}, | 
|  | {"Unable to read frame data.", | 
|  | { | 
|  | // data length | 
|  | 0x00, 0x0c, | 
|  | // data | 
|  | 'h',  'e',  'l',  'l', | 
|  | 'o',  ' ',  'w',  'o', | 
|  | 'r',  'l',  'd',  '!'}}, | 
|  | }; | 
|  |  | 
|  | PacketFragments packet99 = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | // frame type - IETF_STREAM with FIN, LEN, and OFFSET bits set. | 
|  | {"", | 
|  | { 0x08 | 0x01 | 0x02 | 0x04 }}, | 
|  | // stream id | 
|  | {"Unable to read stream_id.", | 
|  | {kVarInt62FourBytes + 0x01, 0x02, 0x03, 0x04}}, | 
|  | // offset | 
|  | {"Unable to read stream data offset.", | 
|  | {kVarInt62EightBytes + 0x3A, 0x98, 0xFE, 0xDC, | 
|  | 0x32, 0x10, 0x76, 0x54}}, | 
|  | // data length | 
|  | {"Unable to read stream data length.", | 
|  | {kVarInt62OneByte + 0x0c}}, | 
|  | // data | 
|  | {"Unable to read frame data.", | 
|  | { 'h',  'e',  'l',  'l', | 
|  | 'o',  ' ',  'w',  'o', | 
|  | 'r',  'l',  'd',  '!'}}, | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | PacketFragments& fragments = | 
|  | framer_.transport_version() == QUIC_VERSION_99 | 
|  | ? packet99 | 
|  | : (framer_.transport_version() > QUIC_VERSION_44 | 
|  | ? packet46 | 
|  | : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 | 
|  | : packet)); | 
|  | std::unique_ptr<QuicEncryptedPacket> encrypted( | 
|  | AssemblePacketFromFragments(fragments)); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); | 
|  |  | 
|  | EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_TRUE(CheckDecryption( | 
|  | *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, | 
|  | PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); | 
|  |  | 
|  | ASSERT_EQ(1u, visitor_.stream_frames_.size()); | 
|  | EXPECT_EQ(0u, visitor_.ack_frames_.size()); | 
|  | EXPECT_EQ(kStreamId, visitor_.stream_frames_[0]->stream_id); | 
|  | EXPECT_TRUE(visitor_.stream_frames_[0]->fin); | 
|  | EXPECT_EQ(kStreamOffset, visitor_.stream_frames_[0]->offset); | 
|  | CheckStreamFrameData("hello world!", visitor_.stream_frames_[0].get()); | 
|  |  | 
|  | CheckFramingBoundaries(fragments, QUIC_INVALID_STREAM_DATA); | 
|  | } | 
|  |  | 
|  | // Test an empty (no data) stream frame. | 
|  | TEST_P(QuicFramerTest, EmptyStreamFrame) { | 
|  | // Only the IETF QUIC spec explicitly says that empty | 
|  | // stream frames are supported. | 
|  | if (framer_.transport_version() != QUIC_VERSION_99) { | 
|  | return; | 
|  | } | 
|  | // clang-format off | 
|  | PacketFragments packet = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | // frame type - IETF_STREAM with FIN, LEN, and OFFSET bits set. | 
|  | {"", | 
|  | { 0x08 | 0x01 | 0x02 | 0x04 }}, | 
|  | // stream id | 
|  | {"Unable to read stream_id.", | 
|  | {kVarInt62FourBytes + 0x01, 0x02, 0x03, 0x04}}, | 
|  | // offset | 
|  | {"Unable to read stream data offset.", | 
|  | {kVarInt62EightBytes + 0x3A, 0x98, 0xFE, 0xDC, | 
|  | 0x32, 0x10, 0x76, 0x54}}, | 
|  | // data length | 
|  | {"Unable to read stream data length.", | 
|  | {kVarInt62OneByte + 0x00}}, | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | std::unique_ptr<QuicEncryptedPacket> encrypted( | 
|  | AssemblePacketFromFragments(packet)); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); | 
|  |  | 
|  | EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_TRUE(CheckDecryption( | 
|  | *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, | 
|  | PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); | 
|  |  | 
|  | ASSERT_EQ(1u, visitor_.stream_frames_.size()); | 
|  | EXPECT_EQ(0u, visitor_.ack_frames_.size()); | 
|  | EXPECT_EQ(kStreamId, visitor_.stream_frames_[0]->stream_id); | 
|  | EXPECT_TRUE(visitor_.stream_frames_[0]->fin); | 
|  | EXPECT_EQ(kStreamOffset, visitor_.stream_frames_[0]->offset); | 
|  | EXPECT_EQ(visitor_.stream_frames_[0].get()->data_length, 0u); | 
|  |  | 
|  | CheckFramingBoundaries(packet, QUIC_INVALID_STREAM_DATA); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, MissingDiversificationNonce) { | 
|  | if (framer_.version().handshake_protocol != PROTOCOL_QUIC_CRYPTO) { | 
|  | // TLS does not use diversification nonces. | 
|  | return; | 
|  | } | 
|  | QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); | 
|  | framer_.SetDecrypter(ENCRYPTION_INITIAL, | 
|  | QuicMakeUnique<NullDecrypter>(Perspective::IS_CLIENT)); | 
|  | decrypter_ = new test::TestDecrypter(); | 
|  | framer_.SetAlternativeDecrypter( | 
|  | ENCRYPTION_ZERO_RTT, std::unique_ptr<QuicDecrypter>(decrypter_), false); | 
|  |  | 
|  | // clang-format off | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x28, | 
|  | // connection_id | 
|  | 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  | // padding frame | 
|  | 0x00, | 
|  | }; | 
|  |  | 
|  | unsigned char packet44[] = { | 
|  | // type (long header, ZERO_RTT_PROTECTED, 4-byte packet number) | 
|  | 0xFC, | 
|  | // version tag | 
|  | QUIC_VERSION_BYTES, | 
|  | // connection_id length | 
|  | 0x05, | 
|  | // connection_id | 
|  | 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  | // padding frame | 
|  | 0x00, | 
|  | }; | 
|  |  | 
|  | unsigned char packet46[] = { | 
|  | // type (long header, ZERO_RTT_PROTECTED, 4-byte packet number) | 
|  | 0xD3, | 
|  | // version tag | 
|  | QUIC_VERSION_BYTES, | 
|  | // connection_id length | 
|  | 0x05, | 
|  | // connection_id | 
|  | 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  | // padding frame | 
|  | 0x00, | 
|  | }; | 
|  |  | 
|  | unsigned char packet99[] = { | 
|  | // type (long header, ZERO_RTT_PROTECTED, 4-byte packet number) | 
|  | 0xD3, | 
|  | // version tag | 
|  | QUIC_VERSION_BYTES, | 
|  | // connection_id length | 
|  | 0x05, | 
|  | // connection_id | 
|  | 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, | 
|  | // IETF long header payload length | 
|  | 0x05, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  | // padding frame | 
|  | 0x00, | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | unsigned char* p = packet; | 
|  | size_t p_length = QUIC_ARRAYSIZE(packet); | 
|  | if (framer_.transport_version() == QUIC_VERSION_99) { | 
|  | p = packet99; | 
|  | p_length = QUIC_ARRAYSIZE(packet99); | 
|  | } else if (framer_.transport_version() >= QUIC_VERSION_46) { | 
|  | p = packet46; | 
|  | p_length = QUIC_ARRAYSIZE(packet46); | 
|  | } else if (framer_.transport_version() >= QUIC_VERSION_44) { | 
|  | p = packet44; | 
|  | p_length = QUIC_ARRAYSIZE(packet44); | 
|  | } | 
|  | QuicEncryptedPacket encrypted(AsChars(p), p_length, false); | 
|  | EXPECT_FALSE(framer_.ProcessPacket(encrypted)); | 
|  | if (framer_.transport_version() >= QUIC_VERSION_44) { | 
|  | // Cannot read diversification nonce. | 
|  | EXPECT_EQ(QUIC_INVALID_PACKET_HEADER, framer_.error()); | 
|  | EXPECT_EQ("Unable to read nonce.", framer_.detailed_error()); | 
|  | } else { | 
|  | EXPECT_EQ(QUIC_DECRYPTION_FAILURE, framer_.error()); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, StreamFrame3ByteStreamId) { | 
|  | if (framer_.transport_version() > QUIC_VERSION_43) { | 
|  | // This test is nonsensical for IETF Quic. | 
|  | return; | 
|  | } | 
|  | // clang-format off | 
|  | PacketFragments packet = { | 
|  | // public flags (8 byte connection_id) | 
|  | {"", | 
|  | {0x28}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | // frame type (stream frame with fin) | 
|  | {"", | 
|  | {0xFE}}, | 
|  | // stream id | 
|  | {"Unable to read stream_id.", | 
|  | {0x02, 0x03, 0x04}}, | 
|  | // offset | 
|  | {"Unable to read offset.", | 
|  | {0x3A, 0x98, 0xFE, 0xDC, | 
|  | 0x32, 0x10, 0x76, 0x54}}, | 
|  | {"Unable to read frame data.", | 
|  | { | 
|  | // data length | 
|  | 0x00, 0x0c, | 
|  | // data | 
|  | 'h',  'e',  'l',  'l', | 
|  | 'o',  ' ',  'w',  'o', | 
|  | 'r',  'l',  'd',  '!'}}, | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | PacketFragments& fragments = packet; | 
|  | std::unique_ptr<QuicEncryptedPacket> encrypted( | 
|  | AssemblePacketFromFragments(fragments)); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); | 
|  |  | 
|  | EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_TRUE(CheckDecryption( | 
|  | *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, | 
|  | PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); | 
|  |  | 
|  | ASSERT_EQ(1u, visitor_.stream_frames_.size()); | 
|  | EXPECT_EQ(0u, visitor_.ack_frames_.size()); | 
|  | // Stream ID should be the last 3 bytes of kStreamId. | 
|  | EXPECT_EQ(0x00FFFFFF & kStreamId, visitor_.stream_frames_[0]->stream_id); | 
|  | EXPECT_TRUE(visitor_.stream_frames_[0]->fin); | 
|  | EXPECT_EQ(kStreamOffset, visitor_.stream_frames_[0]->offset); | 
|  | CheckStreamFrameData("hello world!", visitor_.stream_frames_[0].get()); | 
|  |  | 
|  | CheckFramingBoundaries(fragments, QUIC_INVALID_STREAM_DATA); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, StreamFrame2ByteStreamId) { | 
|  | // clang-format off | 
|  | PacketFragments packet = { | 
|  | // public flags (8 byte connection_id) | 
|  | {"", | 
|  | {0x28}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | // frame type (stream frame with fin) | 
|  | {"", | 
|  | {0xFD}}, | 
|  | // stream id | 
|  | {"Unable to read stream_id.", | 
|  | {0x03, 0x04}}, | 
|  | // offset | 
|  | {"Unable to read offset.", | 
|  | {0x3A, 0x98, 0xFE, 0xDC, | 
|  | 0x32, 0x10, 0x76, 0x54}}, | 
|  | {"Unable to read frame data.", | 
|  | { | 
|  | // data length | 
|  | 0x00, 0x0c, | 
|  | // data | 
|  | 'h',  'e',  'l',  'l', | 
|  | 'o',  ' ',  'w',  'o', | 
|  | 'r',  'l',  'd',  '!'}}, | 
|  | }; | 
|  |  | 
|  | PacketFragments packet44 = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x32}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | // frame type (stream frame with fin) | 
|  | {"", | 
|  | {0xFD}}, | 
|  | // stream id | 
|  | {"Unable to read stream_id.", | 
|  | {0x03, 0x04}}, | 
|  | // offset | 
|  | {"Unable to read offset.", | 
|  | {0x3A, 0x98, 0xFE, 0xDC, | 
|  | 0x32, 0x10, 0x76, 0x54}}, | 
|  | {"Unable to read frame data.", | 
|  | { | 
|  | // data length | 
|  | 0x00, 0x0c, | 
|  | // data | 
|  | 'h',  'e',  'l',  'l', | 
|  | 'o',  ' ',  'w',  'o', | 
|  | 'r',  'l',  'd',  '!'}}, | 
|  | }; | 
|  |  | 
|  | PacketFragments packet46 = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | // frame type (stream frame with fin) | 
|  | {"", | 
|  | {0xFD}}, | 
|  | // stream id | 
|  | {"Unable to read stream_id.", | 
|  | {0x03, 0x04}}, | 
|  | // offset | 
|  | {"Unable to read offset.", | 
|  | {0x3A, 0x98, 0xFE, 0xDC, | 
|  | 0x32, 0x10, 0x76, 0x54}}, | 
|  | {"Unable to read frame data.", | 
|  | { | 
|  | // data length | 
|  | 0x00, 0x0c, | 
|  | // data | 
|  | 'h',  'e',  'l',  'l', | 
|  | 'o',  ' ',  'w',  'o', | 
|  | 'r',  'l',  'd',  '!'}}, | 
|  | }; | 
|  |  | 
|  | PacketFragments packet99 = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | // frame type (IETF_STREAM frame with LEN, FIN, and OFFSET bits set) | 
|  | {"", | 
|  | {0x08 | 0x01 | 0x02 | 0x04}}, | 
|  | // stream id | 
|  | {"Unable to read stream_id.", | 
|  | {kVarInt62TwoBytes + 0x03, 0x04}}, | 
|  | // offset | 
|  | {"Unable to read stream data offset.", | 
|  | {kVarInt62EightBytes + 0x3A, 0x98, 0xFE, 0xDC, | 
|  | 0x32, 0x10, 0x76, 0x54}}, | 
|  | // data length | 
|  | {"Unable to read stream data length.", | 
|  | {kVarInt62OneByte + 0x0c}}, | 
|  | // data | 
|  | {"Unable to read frame data.", | 
|  | { 'h',  'e',  'l',  'l', | 
|  | 'o',  ' ',  'w',  'o', | 
|  | 'r',  'l',  'd',  '!'}}, | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | PacketFragments& fragments = | 
|  | framer_.transport_version() == QUIC_VERSION_99 | 
|  | ? packet99 | 
|  | : (framer_.transport_version() > QUIC_VERSION_44 | 
|  | ? packet46 | 
|  | : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 | 
|  | : packet)); | 
|  | std::unique_ptr<QuicEncryptedPacket> encrypted( | 
|  | AssemblePacketFromFragments(fragments)); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); | 
|  |  | 
|  | EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_TRUE(CheckDecryption( | 
|  | *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, | 
|  | PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); | 
|  |  | 
|  | ASSERT_EQ(1u, visitor_.stream_frames_.size()); | 
|  | EXPECT_EQ(0u, visitor_.ack_frames_.size()); | 
|  | // Stream ID should be the last 2 bytes of kStreamId. | 
|  | EXPECT_EQ(0x0000FFFF & kStreamId, visitor_.stream_frames_[0]->stream_id); | 
|  | EXPECT_TRUE(visitor_.stream_frames_[0]->fin); | 
|  | EXPECT_EQ(kStreamOffset, visitor_.stream_frames_[0]->offset); | 
|  | CheckStreamFrameData("hello world!", visitor_.stream_frames_[0].get()); | 
|  |  | 
|  | CheckFramingBoundaries(fragments, QUIC_INVALID_STREAM_DATA); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, StreamFrame1ByteStreamId) { | 
|  | // clang-format off | 
|  | PacketFragments packet = { | 
|  | // public flags (8 byte connection_id) | 
|  | {"", | 
|  | {0x28}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | // frame type (stream frame with fin) | 
|  | {"", | 
|  | {0xFC}}, | 
|  | // stream id | 
|  | {"Unable to read stream_id.", | 
|  | {0x04}}, | 
|  | // offset | 
|  | {"Unable to read offset.", | 
|  | {0x3A, 0x98, 0xFE, 0xDC, | 
|  | 0x32, 0x10, 0x76, 0x54}}, | 
|  | {"Unable to read frame data.", | 
|  | { | 
|  | // data length | 
|  | 0x00, 0x0c, | 
|  | // data | 
|  | 'h',  'e',  'l',  'l', | 
|  | 'o',  ' ',  'w',  'o', | 
|  | 'r',  'l',  'd',  '!'}}, | 
|  | }; | 
|  |  | 
|  | PacketFragments packet44 = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x32}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | // frame type (stream frame with fin) | 
|  | {"", | 
|  | {0xFC}}, | 
|  | // stream id | 
|  | {"Unable to read stream_id.", | 
|  | {0x04}}, | 
|  | // offset | 
|  | {"Unable to read offset.", | 
|  | {0x3A, 0x98, 0xFE, 0xDC, | 
|  | 0x32, 0x10, 0x76, 0x54}}, | 
|  | {"Unable to read frame data.", | 
|  | { | 
|  | // data length | 
|  | 0x00, 0x0c, | 
|  | // data | 
|  | 'h',  'e',  'l',  'l', | 
|  | 'o',  ' ',  'w',  'o', | 
|  | 'r',  'l',  'd',  '!'}}, | 
|  | }; | 
|  |  | 
|  | PacketFragments packet46 = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | // frame type (stream frame with fin) | 
|  | {"", | 
|  | {0xFC}}, | 
|  | // stream id | 
|  | {"Unable to read stream_id.", | 
|  | {0x04}}, | 
|  | // offset | 
|  | {"Unable to read offset.", | 
|  | {0x3A, 0x98, 0xFE, 0xDC, | 
|  | 0x32, 0x10, 0x76, 0x54}}, | 
|  | {"Unable to read frame data.", | 
|  | { | 
|  | // data length | 
|  | 0x00, 0x0c, | 
|  | // data | 
|  | 'h',  'e',  'l',  'l', | 
|  | 'o',  ' ',  'w',  'o', | 
|  | 'r',  'l',  'd',  '!'}}, | 
|  | }; | 
|  |  | 
|  | PacketFragments packet99 = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | // frame type (IETF_STREAM frame with LEN, FIN, and OFFSET bits set) | 
|  | {"", | 
|  | {0x08 | 0x01 | 0x02 | 0x04}}, | 
|  | // stream id | 
|  | {"Unable to read stream_id.", | 
|  | {kVarInt62OneByte + 0x04}}, | 
|  | // offset | 
|  | {"Unable to read stream data offset.", | 
|  | {kVarInt62EightBytes + 0x3A, 0x98, 0xFE, 0xDC, | 
|  | 0x32, 0x10, 0x76, 0x54}}, | 
|  | // data length | 
|  | {"Unable to read stream data length.", | 
|  | {kVarInt62OneByte + 0x0c}}, | 
|  | // data | 
|  | {"Unable to read frame data.", | 
|  | { 'h',  'e',  'l',  'l', | 
|  | 'o',  ' ',  'w',  'o', | 
|  | 'r',  'l',  'd',  '!'}}, | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | PacketFragments& fragments = | 
|  | framer_.transport_version() == QUIC_VERSION_99 | 
|  | ? packet99 | 
|  | : (framer_.transport_version() > QUIC_VERSION_44 | 
|  | ? packet46 | 
|  | : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 | 
|  | : packet)); | 
|  | std::unique_ptr<QuicEncryptedPacket> encrypted( | 
|  | AssemblePacketFromFragments(fragments)); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); | 
|  |  | 
|  | EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_TRUE(CheckDecryption( | 
|  | *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, | 
|  | PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); | 
|  |  | 
|  | ASSERT_EQ(1u, visitor_.stream_frames_.size()); | 
|  | EXPECT_EQ(0u, visitor_.ack_frames_.size()); | 
|  | // Stream ID should be the last 1 byte of kStreamId. | 
|  | EXPECT_EQ(0x000000FF & kStreamId, visitor_.stream_frames_[0]->stream_id); | 
|  | EXPECT_TRUE(visitor_.stream_frames_[0]->fin); | 
|  | EXPECT_EQ(kStreamOffset, visitor_.stream_frames_[0]->offset); | 
|  | CheckStreamFrameData("hello world!", visitor_.stream_frames_[0].get()); | 
|  |  | 
|  | CheckFramingBoundaries(fragments, QUIC_INVALID_STREAM_DATA); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, StreamFrameWithVersion) { | 
|  | // clang-format off | 
|  | PacketFragments packet = { | 
|  | // public flags (version, 8 byte connection_id) | 
|  | {"", | 
|  | {0x29}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // version tag | 
|  | {"", | 
|  | {QUIC_VERSION_BYTES}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | // frame type (stream frame with fin) | 
|  | {"", | 
|  | {0xFE}}, | 
|  | // stream id | 
|  | {"Unable to read stream_id.", | 
|  | {0x02, 0x03, 0x04}}, | 
|  | // offset | 
|  | {"Unable to read offset.", | 
|  | {0x3A, 0x98, 0xFE, 0xDC, | 
|  | 0x32, 0x10, 0x76, 0x54}}, | 
|  | {"Unable to read frame data.", | 
|  | { | 
|  | // data length | 
|  | 0x00, 0x0c, | 
|  | // data | 
|  | 'h',  'e',  'l',  'l', | 
|  | 'o',  ' ',  'w',  'o', | 
|  | 'r',  'l',  'd',  '!'}}, | 
|  | }; | 
|  |  | 
|  | PacketFragments packet44 = { | 
|  | // public flags (long header with packet type ZERO_RTT_PROTECTED) | 
|  | {"", | 
|  | {0xFC}}, | 
|  | // version tag | 
|  | {"", | 
|  | {QUIC_VERSION_BYTES}}, | 
|  | // connection_id length | 
|  | {"", | 
|  | {0x50}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | // frame type (stream frame with fin) | 
|  | {"", | 
|  | {0xFE}}, | 
|  | // stream id | 
|  | {"Unable to read stream_id.", | 
|  | {0x02, 0x03, 0x04}}, | 
|  | // offset | 
|  | {"Unable to read offset.", | 
|  | {0x3A, 0x98, 0xFE, 0xDC, | 
|  | 0x32, 0x10, 0x76, 0x54}}, | 
|  | {"Unable to read frame data.", | 
|  | { | 
|  | // data length | 
|  | 0x00, 0x0c, | 
|  | // data | 
|  | 'h',  'e',  'l',  'l', | 
|  | 'o',  ' ',  'w',  'o', | 
|  | 'r',  'l',  'd',  '!'}}, | 
|  | }; | 
|  |  | 
|  | PacketFragments packet46 = { | 
|  | // public flags (long header with packet type ZERO_RTT_PROTECTED and | 
|  | // 4-byte packet number) | 
|  | {"", | 
|  | {0xD3}}, | 
|  | // version tag | 
|  | {"", | 
|  | {QUIC_VERSION_BYTES}}, | 
|  | // connection_id length | 
|  | {"", | 
|  | {0x50}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | // frame type (stream frame with fin) | 
|  | {"", | 
|  | {0xFE}}, | 
|  | // stream id | 
|  | {"Unable to read stream_id.", | 
|  | {0x02, 0x03, 0x04}}, | 
|  | // offset | 
|  | {"Unable to read offset.", | 
|  | {0x3A, 0x98, 0xFE, 0xDC, | 
|  | 0x32, 0x10, 0x76, 0x54}}, | 
|  | {"Unable to read frame data.", | 
|  | { | 
|  | // data length | 
|  | 0x00, 0x0c, | 
|  | // data | 
|  | 'h',  'e',  'l',  'l', | 
|  | 'o',  ' ',  'w',  'o', | 
|  | 'r',  'l',  'd',  '!'}}, | 
|  | }; | 
|  |  | 
|  | PacketFragments packet99 = { | 
|  | // public flags (long header with packet type ZERO_RTT_PROTECTED and | 
|  | // 4-byte packet number) | 
|  | {"", | 
|  | {0xD3}}, | 
|  | // version tag | 
|  | {"", | 
|  | {QUIC_VERSION_BYTES}}, | 
|  | // connection_id length | 
|  | {"", | 
|  | {0x50}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // long header packet length | 
|  | {"", | 
|  | {0x1E}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | // frame type (IETF_STREAM frame with FIN, LEN, and OFFSET bits set) | 
|  | {"", | 
|  | {0x08 | 0x01 | 0x02 | 0x04}}, | 
|  | // stream id | 
|  | {"Long header payload length longer than packet.", | 
|  | {kVarInt62FourBytes + 0x00, 0x02, 0x03, 0x04}}, | 
|  | // offset | 
|  | {"Long header payload length longer than packet.", | 
|  | {kVarInt62EightBytes + 0x3A, 0x98, 0xFE, 0xDC, | 
|  | 0x32, 0x10, 0x76, 0x54}}, | 
|  | // data length | 
|  | {"Long header payload length longer than packet.", | 
|  | {kVarInt62OneByte + 0x0c}}, | 
|  | // data | 
|  | {"Long header payload length longer than packet.", | 
|  | { 'h',  'e',  'l',  'l', | 
|  | 'o',  ' ',  'w',  'o', | 
|  | 'r',  'l',  'd',  '!'}}, | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | QuicVariableLengthIntegerLength retry_token_length_length = | 
|  | VARIABLE_LENGTH_INTEGER_LENGTH_0; | 
|  | size_t retry_token_length = 0; | 
|  | QuicVariableLengthIntegerLength length_length = | 
|  | QuicVersionHasLongHeaderLengths(framer_.transport_version()) | 
|  | ? VARIABLE_LENGTH_INTEGER_LENGTH_1 | 
|  | : VARIABLE_LENGTH_INTEGER_LENGTH_0; | 
|  |  | 
|  | PacketFragments& fragments = | 
|  | framer_.transport_version() == QUIC_VERSION_99 | 
|  | ? packet99 | 
|  | : (framer_.transport_version() > QUIC_VERSION_44 | 
|  | ? packet46 | 
|  | : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 | 
|  | : packet)); | 
|  | std::unique_ptr<QuicEncryptedPacket> encrypted( | 
|  | AssemblePacketFromFragments(fragments)); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); | 
|  |  | 
|  | EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_TRUE(CheckDecryption( | 
|  | *encrypted, kIncludeVersion, !kIncludeDiversificationNonce, | 
|  | PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID, | 
|  | retry_token_length_length, retry_token_length, length_length)); | 
|  |  | 
|  | ASSERT_EQ(1u, visitor_.stream_frames_.size()); | 
|  | EXPECT_EQ(0u, visitor_.ack_frames_.size()); | 
|  | // Stream ID should be the last 3 bytes of kStreamId. | 
|  | EXPECT_EQ(0x00FFFFFF & kStreamId, visitor_.stream_frames_[0]->stream_id); | 
|  | EXPECT_TRUE(visitor_.stream_frames_[0]->fin); | 
|  | EXPECT_EQ(kStreamOffset, visitor_.stream_frames_[0]->offset); | 
|  | CheckStreamFrameData("hello world!", visitor_.stream_frames_[0].get()); | 
|  |  | 
|  | CheckFramingBoundaries(fragments, | 
|  | framer_.transport_version() == QUIC_VERSION_99 | 
|  | ? QUIC_INVALID_PACKET_HEADER | 
|  | : QUIC_INVALID_STREAM_DATA); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, RejectPacket) { | 
|  | visitor_.accept_packet_ = false; | 
|  |  | 
|  | // clang-format off | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x28, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (stream frame with fin) | 
|  | 0xFF, | 
|  | // stream id | 
|  | 0x01, 0x02, 0x03, 0x04, | 
|  | // offset | 
|  | 0x3A, 0x98, 0xFE, 0xDC, | 
|  | 0x32, 0x10, 0x76, 0x54, | 
|  | // data length | 
|  | 0x00, 0x0c, | 
|  | // data | 
|  | 'h',  'e',  'l',  'l', | 
|  | 'o',  ' ',  'w',  'o', | 
|  | 'r',  'l',  'd',  '!', | 
|  | }; | 
|  |  | 
|  | unsigned char packet44[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x32, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (STREAM Frame with FIN, LEN, and OFFSET bits set) | 
|  | 0x10 | 0x01 | 0x02 | 0x04, | 
|  | // stream id | 
|  | kVarInt62FourBytes + 0x01, 0x02, 0x03, 0x04, | 
|  | // offset | 
|  | kVarInt62EightBytes + 0x3A, 0x98, 0xFE, 0xDC, | 
|  | 0x32, 0x10, 0x76, 0x54, | 
|  | // data length | 
|  | kVarInt62OneByte + 0x0c, | 
|  | // data | 
|  | 'h',  'e',  'l',  'l', | 
|  | 'o',  ' ',  'w',  'o', | 
|  | 'r',  'l',  'd',  '!', | 
|  | }; | 
|  |  | 
|  | unsigned char packet46[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (STREAM Frame with FIN, LEN, and OFFSET bits set) | 
|  | 0x10 | 0x01 | 0x02 | 0x04, | 
|  | // stream id | 
|  | kVarInt62FourBytes + 0x01, 0x02, 0x03, 0x04, | 
|  | // offset | 
|  | kVarInt62EightBytes + 0x3A, 0x98, 0xFE, 0xDC, | 
|  | 0x32, 0x10, 0x76, 0x54, | 
|  | // data length | 
|  | kVarInt62OneByte + 0x0c, | 
|  | // data | 
|  | 'h',  'e',  'l',  'l', | 
|  | 'o',  ' ',  'w',  'o', | 
|  | 'r',  'l',  'd',  '!', | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | unsigned char* p = packet; | 
|  | if (framer_.transport_version() > QUIC_VERSION_44) { | 
|  | p = packet46; | 
|  | } else if (framer_.transport_version() > QUIC_VERSION_43) { | 
|  | p = packet44; | 
|  | } | 
|  | QuicEncryptedPacket encrypted(AsChars(p), | 
|  | framer_.transport_version() > QUIC_VERSION_43 | 
|  | ? QUIC_ARRAYSIZE(packet44) | 
|  | : QUIC_ARRAYSIZE(packet), | 
|  | false); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(encrypted)); | 
|  |  | 
|  | EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_TRUE(CheckDecryption( | 
|  | encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, | 
|  | PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); | 
|  |  | 
|  | ASSERT_EQ(0u, visitor_.stream_frames_.size()); | 
|  | EXPECT_EQ(0u, visitor_.ack_frames_.size()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, RejectPublicHeader) { | 
|  | visitor_.accept_public_header_ = false; | 
|  |  | 
|  | // clang-format off | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x28, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | }; | 
|  |  | 
|  | unsigned char packet44[] = { | 
|  | // type (short header, 1 byte packet number) | 
|  | 0x30, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x01, | 
|  | }; | 
|  |  | 
|  | unsigned char packet46[] = { | 
|  | // type (short header, 1 byte packet number) | 
|  | 0x40, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x01, | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | QuicEncryptedPacket encrypted( | 
|  | framer_.transport_version() > QUIC_VERSION_44 | 
|  | ? AsChars(packet46) | 
|  | : (framer_.transport_version() > QUIC_VERSION_43 ? AsChars(packet44) | 
|  | : AsChars(packet)), | 
|  | framer_.transport_version() > QUIC_VERSION_44 | 
|  | ? QUIC_ARRAYSIZE(packet46) | 
|  | : (framer_.transport_version() > QUIC_VERSION_43 | 
|  | ? QUIC_ARRAYSIZE(packet44) | 
|  | : QUIC_ARRAYSIZE(packet)), | 
|  | false); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(encrypted)); | 
|  |  | 
|  | EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_FALSE(visitor_.header_->packet_number.IsInitialized()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, AckFrameOneAckBlock) { | 
|  | // clang-format off | 
|  | PacketFragments packet = { | 
|  | // public flags (8 byte connection_id) | 
|  | {"", | 
|  | {0x2C}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | // frame type (ack frame) | 
|  | // (one ack block, 2 byte largest observed, 2 byte block length) | 
|  | {"", | 
|  | {0x45}}, | 
|  | // largest acked | 
|  | {"Unable to read largest acked.", | 
|  | {0x12, 0x34}}, | 
|  | // Zero delta time. | 
|  | {"Unable to read ack delay time.", | 
|  | {0x00, 0x00}}, | 
|  | // first ack block length. | 
|  | {"Unable to read first ack block length.", | 
|  | {0x12, 0x34}}, | 
|  | // num timestamps. | 
|  | {"Unable to read num received packets.", | 
|  | {0x00}} | 
|  | }; | 
|  |  | 
|  | PacketFragments packet44 = { | 
|  | // type (short packet, 4 byte packet number) | 
|  | {"", | 
|  | {0x32}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | // frame type (ack frame) | 
|  | // (one ack block, 2 byte largest observed, 2 byte block length) | 
|  | {"", | 
|  | {0x45}}, | 
|  | // largest acked | 
|  | {"Unable to read largest acked.", | 
|  | {0x12, 0x34}}, | 
|  | // Zero delta time. | 
|  | {"Unable to read ack delay time.", | 
|  | {0x00, 0x00}}, | 
|  | // first ack block length. | 
|  | {"Unable to read first ack block length.", | 
|  | {0x12, 0x34}}, | 
|  | // num timestamps. | 
|  | {"Unable to read num received packets.", | 
|  | {0x00}} | 
|  | }; | 
|  |  | 
|  | PacketFragments packet46 = { | 
|  | // type (short packet, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | // frame type (ack frame) | 
|  | // (one ack block, 2 byte largest observed, 2 byte block length) | 
|  | {"", | 
|  | {0x45}}, | 
|  | // largest acked | 
|  | {"Unable to read largest acked.", | 
|  | {0x12, 0x34}}, | 
|  | // Zero delta time. | 
|  | {"Unable to read ack delay time.", | 
|  | {0x00, 0x00}}, | 
|  | // first ack block length. | 
|  | {"Unable to read first ack block length.", | 
|  | {0x12, 0x34}}, | 
|  | // num timestamps. | 
|  | {"Unable to read num received packets.", | 
|  | {0x00}} | 
|  | }; | 
|  |  | 
|  | PacketFragments packet99 = { | 
|  | // type (short packet, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | // frame type (IETF_ACK) | 
|  | // (one ack block, 2 byte largest observed, 2 byte block length) | 
|  | // IETF-Quic ignores the bit-fields in the ack type, all of | 
|  | // that information is encoded elsewhere in the frame. | 
|  | {"", | 
|  | {0x02}}, | 
|  | // largest acked | 
|  | {"Unable to read largest acked.", | 
|  | {kVarInt62TwoBytes  + 0x12, 0x34}}, | 
|  | // Zero delta time. | 
|  | {"Unable to read ack delay time.", | 
|  | {kVarInt62OneByte + 0x00}}, | 
|  | // Ack block count (0 -- no blocks after the first) | 
|  | {"Unable to read ack block count.", | 
|  | {kVarInt62OneByte + 0x00}}, | 
|  | // first ack block length - 1. | 
|  | // IETF Quic defines the ack block's value as the "number of | 
|  | // packets that preceed the largest packet number in the block" | 
|  | // which for the 1st ack block is the largest acked field, | 
|  | // above. This means that if we are acking just packet 0x1234 | 
|  | // then the 1st ack block will be 0. | 
|  | {"Unable to read first ack block length.", | 
|  | {kVarInt62TwoBytes + 0x12, 0x33}} | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | PacketFragments& fragments = | 
|  | framer_.transport_version() == QUIC_VERSION_99 | 
|  | ? packet99 | 
|  | : (framer_.transport_version() > QUIC_VERSION_44 | 
|  | ? packet46 | 
|  | : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 | 
|  | : packet)); | 
|  | std::unique_ptr<QuicEncryptedPacket> encrypted( | 
|  | AssemblePacketFromFragments(fragments)); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); | 
|  |  | 
|  | EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_TRUE(CheckDecryption( | 
|  | *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, | 
|  | PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); | 
|  |  | 
|  | EXPECT_EQ(0u, visitor_.stream_frames_.size()); | 
|  | ASSERT_EQ(1u, visitor_.ack_frames_.size()); | 
|  | const QuicAckFrame& frame = *visitor_.ack_frames_[0]; | 
|  | EXPECT_EQ(kSmallLargestObserved, LargestAcked(frame)); | 
|  | ASSERT_EQ(4660u, frame.packets.NumPacketsSlow()); | 
|  |  | 
|  | CheckFramingBoundaries(fragments, QUIC_INVALID_ACK_DATA); | 
|  | } | 
|  |  | 
|  | // This test checks that the ack frame processor correctly identifies | 
|  | // and handles the case where the first ack block is larger than the | 
|  | // largest_acked packet. | 
|  | TEST_P(QuicFramerTest, FirstAckFrameUnderflow) { | 
|  | // clang-format off | 
|  | PacketFragments packet = { | 
|  | // public flags (8 byte connection_id) | 
|  | {"", | 
|  | {0x2C}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | // frame type (ack frame) | 
|  | // (one ack block, 2 byte largest observed, 2 byte block length) | 
|  | {"", | 
|  | {0x45}}, | 
|  | // largest acked | 
|  | {"Unable to read largest acked.", | 
|  | {0x12, 0x34}}, | 
|  | // Zero delta time. | 
|  | {"Unable to read ack delay time.", | 
|  | {0x00, 0x00}}, | 
|  | // first ack block length. | 
|  | {"Unable to read first ack block length.", | 
|  | {0x88, 0x88}}, | 
|  | // num timestamps. | 
|  | {"Underflow with first ack block length 34952 largest acked is 4660.", | 
|  | {0x00}} | 
|  | }; | 
|  |  | 
|  | PacketFragments packet44 = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x32}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | // frame type (ack frame) | 
|  | // (one ack block, 2 byte largest observed, 2 byte block length) | 
|  | {"", | 
|  | {0x45}}, | 
|  | // largest acked | 
|  | {"Unable to read largest acked.", | 
|  | {0x12, 0x34}}, | 
|  | // Zero delta time. | 
|  | {"Unable to read ack delay time.", | 
|  | {0x00, 0x00}}, | 
|  | // first ack block length. | 
|  | {"Unable to read first ack block length.", | 
|  | {0x88, 0x88}}, | 
|  | // num timestamps. | 
|  | {"Underflow with first ack block length 34952 largest acked is 4660.", | 
|  | {0x00}} | 
|  | }; | 
|  |  | 
|  | PacketFragments packet46 = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | // frame type (ack frame) | 
|  | // (one ack block, 2 byte largest observed, 2 byte block length) | 
|  | {"", | 
|  | {0x45}}, | 
|  | // largest acked | 
|  | {"Unable to read largest acked.", | 
|  | {0x12, 0x34}}, | 
|  | // Zero delta time. | 
|  | {"Unable to read ack delay time.", | 
|  | {0x00, 0x00}}, | 
|  | // first ack block length. | 
|  | {"Unable to read first ack block length.", | 
|  | {0x88, 0x88}}, | 
|  | // num timestamps. | 
|  | {"Underflow with first ack block length 34952 largest acked is 4660.", | 
|  | {0x00}} | 
|  | }; | 
|  |  | 
|  | PacketFragments packet99 = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | // frame type (IETF_ACK) | 
|  | {"", | 
|  | {0x02}}, | 
|  | // largest acked | 
|  | {"Unable to read largest acked.", | 
|  | {kVarInt62TwoBytes  + 0x12, 0x34}}, | 
|  | // Zero delta time. | 
|  | {"Unable to read ack delay time.", | 
|  | {kVarInt62OneByte + 0x00}}, | 
|  | // Ack block count (0 -- no blocks after the first) | 
|  | {"Unable to read ack block count.", | 
|  | {kVarInt62OneByte + 0x00}}, | 
|  | // first ack block length. | 
|  | {"Unable to read first ack block length.", | 
|  | {kVarInt62TwoBytes + 0x28, 0x88}} | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | PacketFragments& fragments = | 
|  | framer_.transport_version() == QUIC_VERSION_99 | 
|  | ? packet99 | 
|  | : (framer_.transport_version() > QUIC_VERSION_44 | 
|  | ? packet46 | 
|  | : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 | 
|  | : packet)); | 
|  | std::unique_ptr<QuicEncryptedPacket> encrypted( | 
|  | AssemblePacketFromFragments(fragments)); | 
|  | EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); | 
|  | CheckFramingBoundaries(fragments, QUIC_INVALID_ACK_DATA); | 
|  | } | 
|  |  | 
|  | // This test checks that the ack frame processor correctly identifies | 
|  | // and handles the case where the third ack block's gap is larger than the | 
|  | // available space in the ack range. | 
|  | TEST_P(QuicFramerTest, ThirdAckBlockUnderflowGap) { | 
|  | if (framer_.transport_version() != QUIC_VERSION_99) { | 
|  | // for now, only v99 | 
|  | return; | 
|  | } | 
|  | // clang-format off | 
|  | PacketFragments packet99 = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | // frame type (IETF_ACK frame) | 
|  | {"", | 
|  | {0x02}}, | 
|  | // largest acked | 
|  | {"Unable to read largest acked.", | 
|  | {kVarInt62OneByte  + 63}}, | 
|  | // Zero delta time. | 
|  | {"Unable to read ack delay time.", | 
|  | {kVarInt62OneByte + 0x00}}, | 
|  | // Ack block count (2 -- 2 blocks after the first) | 
|  | {"Unable to read ack block count.", | 
|  | {kVarInt62OneByte + 0x02}}, | 
|  | // first ack block length. | 
|  | {"Unable to read first ack block length.", | 
|  | {kVarInt62OneByte + 13}},  // Ack 14 packets, range 50..63 (inclusive) | 
|  |  | 
|  | {"Unable to read gap block value.", | 
|  | {kVarInt62OneByte + 9}},  // Gap 10 packets, 40..49 (inclusive) | 
|  | {"Unable to read ack block value.", | 
|  | {kVarInt62OneByte + 9}},  // Ack 10 packets, 30..39 (inclusive) | 
|  | {"Unable to read gap block value.", | 
|  | {kVarInt62OneByte + 29}},  // A gap of 30 packets (0..29 inclusive) | 
|  | // should be too big, leaving no room | 
|  | // for the ack. | 
|  | {"Underflow with gap block length 30 previous ack block start is 30.", | 
|  | {kVarInt62OneByte + 10}},  // Don't care | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | std::unique_ptr<QuicEncryptedPacket> encrypted( | 
|  | AssemblePacketFromFragments(packet99)); | 
|  | EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); | 
|  | EXPECT_EQ( | 
|  | framer_.detailed_error(), | 
|  | "Underflow with gap block length 30 previous ack block start is 30."); | 
|  | CheckFramingBoundaries(packet99, QUIC_INVALID_ACK_DATA); | 
|  | } | 
|  |  | 
|  | // This test checks that the ack frame processor correctly identifies | 
|  | // and handles the case where the third ack block's length is larger than the | 
|  | // available space in the ack range. | 
|  | TEST_P(QuicFramerTest, ThirdAckBlockUnderflowAck) { | 
|  | if (framer_.transport_version() != QUIC_VERSION_99) { | 
|  | // for now, only v99 | 
|  | return; | 
|  | } | 
|  | // clang-format off | 
|  | PacketFragments packet99 = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | // frame type (IETF_ACK frame) | 
|  | {"", | 
|  | {0x02}}, | 
|  | // largest acked | 
|  | {"Unable to read largest acked.", | 
|  | {kVarInt62OneByte  + 63}}, | 
|  | // Zero delta time. | 
|  | {"Unable to read ack delay time.", | 
|  | {kVarInt62OneByte + 0x00}}, | 
|  | // Ack block count (2 -- 2 blocks after the first) | 
|  | {"Unable to read ack block count.", | 
|  | {kVarInt62OneByte + 0x02}}, | 
|  | // first ack block length. | 
|  | {"Unable to read first ack block length.", | 
|  | {kVarInt62OneByte + 13}},  // only 50 packet numbers "left" | 
|  |  | 
|  | {"Unable to read gap block value.", | 
|  | {kVarInt62OneByte + 10}},  // Only 40 packet numbers left | 
|  | {"Unable to read ack block value.", | 
|  | {kVarInt62OneByte + 10}},  // only 30 packet numbers left. | 
|  | {"Unable to read gap block value.", | 
|  | {kVarInt62OneByte + 1}},  // Gap is OK, 29 packet numbers left | 
|  | {"Unable to read ack block value.", | 
|  | {kVarInt62OneByte + 30}},  // Use up all 30, should be an error | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | std::unique_ptr<QuicEncryptedPacket> encrypted( | 
|  | AssemblePacketFromFragments(packet99)); | 
|  | EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); | 
|  | EXPECT_EQ(framer_.detailed_error(), | 
|  | "Underflow with ack block length 31 latest ack block end is 25."); | 
|  | CheckFramingBoundaries(packet99, QUIC_INVALID_ACK_DATA); | 
|  | } | 
|  |  | 
|  | // Tests a variety of ack block wrap scenarios. For example, if the | 
|  | // N-1th block causes packet 0 to be acked, then a gap would wrap | 
|  | // around to 0x3fffffff ffffffff... Make sure we detect this | 
|  | // condition. | 
|  | TEST_P(QuicFramerTest, AckBlockUnderflowGapWrap) { | 
|  | if (framer_.transport_version() != QUIC_VERSION_99) { | 
|  | // for now, only v99 | 
|  | return; | 
|  | } | 
|  | // clang-format off | 
|  | PacketFragments packet99 = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | // frame type (IETF_ACK frame) | 
|  | {"", | 
|  | {0x02}}, | 
|  | // largest acked | 
|  | {"Unable to read largest acked.", | 
|  | {kVarInt62OneByte  + 10}}, | 
|  | // Zero delta time. | 
|  | {"Unable to read ack delay time.", | 
|  | {kVarInt62OneByte + 0x00}}, | 
|  | // Ack block count (1 -- 1 blocks after the first) | 
|  | {"Unable to read ack block count.", | 
|  | {kVarInt62OneByte + 1}}, | 
|  | // first ack block length. | 
|  | {"Unable to read first ack block length.", | 
|  | {kVarInt62OneByte + 9}},  // Ack packets 1..10 (inclusive) | 
|  |  | 
|  | {"Unable to read gap block value.", | 
|  | {kVarInt62OneByte + 1}},  // Gap of 2 packets (-1...0), should wrap | 
|  | {"Underflow with gap block length 2 previous ack block start is 1.", | 
|  | {kVarInt62OneByte + 9}},  // irrelevant | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | std::unique_ptr<QuicEncryptedPacket> encrypted( | 
|  | AssemblePacketFromFragments(packet99)); | 
|  | EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); | 
|  | EXPECT_EQ(framer_.detailed_error(), | 
|  | "Underflow with gap block length 2 previous ack block start is 1."); | 
|  | CheckFramingBoundaries(packet99, QUIC_INVALID_ACK_DATA); | 
|  | } | 
|  |  | 
|  | // As AckBlockUnderflowGapWrap, but in this test, it's the ack | 
|  | // component of the ack-block that causes the wrap, not the gap. | 
|  | TEST_P(QuicFramerTest, AckBlockUnderflowAckWrap) { | 
|  | if (framer_.transport_version() != QUIC_VERSION_99) { | 
|  | // for now, only v99 | 
|  | return; | 
|  | } | 
|  | // clang-format off | 
|  | PacketFragments packet99 = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | // frame type (IETF_ACK frame) | 
|  | {"", | 
|  | {0x02}}, | 
|  | // largest acked | 
|  | {"Unable to read largest acked.", | 
|  | {kVarInt62OneByte  + 10}}, | 
|  | // Zero delta time. | 
|  | {"Unable to read ack delay time.", | 
|  | {kVarInt62OneByte + 0x00}}, | 
|  | // Ack block count (1 -- 1 blocks after the first) | 
|  | {"Unable to read ack block count.", | 
|  | {kVarInt62OneByte + 1}}, | 
|  | // first ack block length. | 
|  | {"Unable to read first ack block length.", | 
|  | {kVarInt62OneByte + 6}},  // Ack packets 4..10 (inclusive) | 
|  |  | 
|  | {"Unable to read gap block value.", | 
|  | {kVarInt62OneByte + 1}},  // Gap of 2 packets (2..3) | 
|  | {"Unable to read ack block value.", | 
|  | {kVarInt62OneByte + 9}},  // Should wrap. | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | std::unique_ptr<QuicEncryptedPacket> encrypted( | 
|  | AssemblePacketFromFragments(packet99)); | 
|  | EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); | 
|  | EXPECT_EQ(framer_.detailed_error(), | 
|  | "Underflow with ack block length 10 latest ack block end is 1."); | 
|  | CheckFramingBoundaries(packet99, QUIC_INVALID_ACK_DATA); | 
|  | } | 
|  |  | 
|  | // An ack block that acks the entire range, 1...0x3fffffffffffffff | 
|  | TEST_P(QuicFramerTest, AckBlockAcksEverything) { | 
|  | if (framer_.transport_version() != QUIC_VERSION_99) { | 
|  | // for now, only v99 | 
|  | return; | 
|  | } | 
|  | // clang-format off | 
|  | PacketFragments packet99 = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | // frame type (IETF_ACK frame) | 
|  | {"", | 
|  | {0x02}}, | 
|  | // largest acked | 
|  | {"Unable to read largest acked.", | 
|  | {kVarInt62EightBytes  + 0x3f, 0xff, 0xff, 0xff, | 
|  | 0xff, 0xff, 0xff, 0xff}}, | 
|  | // Zero delta time. | 
|  | {"Unable to read ack delay time.", | 
|  | {kVarInt62OneByte + 0x00}}, | 
|  | // Ack block count No additional blocks | 
|  | {"Unable to read ack block count.", | 
|  | {kVarInt62OneByte + 0}}, | 
|  | // first ack block length. | 
|  | {"Unable to read first ack block length.", | 
|  | {kVarInt62EightBytes  + 0x3f, 0xff, 0xff, 0xff, | 
|  | 0xff, 0xff, 0xff, 0xfe}}, | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | std::unique_ptr<QuicEncryptedPacket> encrypted( | 
|  | AssemblePacketFromFragments(packet99)); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); | 
|  | EXPECT_EQ(1u, visitor_.ack_frames_.size()); | 
|  | const QuicAckFrame& frame = *visitor_.ack_frames_[0]; | 
|  | EXPECT_EQ(1u, frame.packets.NumIntervals()); | 
|  | EXPECT_EQ(kLargestIetfLargestObserved, LargestAcked(frame)); | 
|  | EXPECT_EQ(kLargestIetfLargestObserved.ToUint64(), | 
|  | frame.packets.NumPacketsSlow()); | 
|  | } | 
|  |  | 
|  | // This test looks for a malformed ack where | 
|  | //  - There is a largest-acked value (that is, the frame is acking | 
|  | //    something, | 
|  | //  - But the length of the first ack block is 0 saying that no frames | 
|  | //    are being acked with the largest-acked value or there are no | 
|  | //    additional ack blocks. | 
|  | // | 
|  | TEST_P(QuicFramerTest, AckFrameFirstAckBlockLengthZero) { | 
|  | if (framer_.transport_version() == QUIC_VERSION_99) { | 
|  | // Not applicable to version 99 -- first ack block contains the | 
|  | // number of packets that preceed the largest_acked packet. | 
|  | // A value of 0 means no packets preceed --- that the block's | 
|  | // length is 1. Therefore the condition that this test checks can | 
|  | // not arise. | 
|  | return; | 
|  | } | 
|  |  | 
|  | // clang-format off | 
|  | PacketFragments packet = { | 
|  | // public flags (8 byte connection_id) | 
|  | {"", | 
|  | { 0x2C }}, | 
|  | // connection_id | 
|  | {"", | 
|  | { 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 }}, | 
|  | // packet number | 
|  | {"", | 
|  | { 0x12, 0x34, 0x56, 0x78 }}, | 
|  |  | 
|  | // frame type (ack frame) | 
|  | // (more than one ack block, 2 byte largest observed, 2 byte block length) | 
|  | {"", | 
|  | { 0x65 }}, | 
|  | // largest acked | 
|  | {"Unable to read largest acked.", | 
|  | { 0x12, 0x34 }}, | 
|  | // Zero delta time. | 
|  | {"Unable to read ack delay time.", | 
|  | { 0x00, 0x00 }}, | 
|  | // num ack blocks ranges. | 
|  | {"Unable to read num of ack blocks.", | 
|  | { 0x01 }}, | 
|  | // first ack block length. | 
|  | {"Unable to read first ack block length.", | 
|  | { 0x00, 0x00 }}, | 
|  | // gap to next block. | 
|  | { "First block length is zero.", | 
|  | { 0x01 }}, | 
|  | // ack block length. | 
|  | { "First block length is zero.", | 
|  | { 0x0e, 0xaf }}, | 
|  | // Number of timestamps. | 
|  | { "First block length is zero.", | 
|  | { 0x00 }}, | 
|  | }; | 
|  |  | 
|  | PacketFragments packet44 = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | { 0x32 }}, | 
|  | // connection_id | 
|  | {"", | 
|  | { 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 }}, | 
|  | // packet number | 
|  | {"", | 
|  | { 0x12, 0x34, 0x56, 0x78 }}, | 
|  |  | 
|  | // frame type (ack frame) | 
|  | // (more than one ack block, 2 byte largest observed, 2 byte block length) | 
|  | {"", | 
|  | { 0x65 }}, | 
|  | // largest acked | 
|  | {"Unable to read largest acked.", | 
|  | { 0x12, 0x34 }}, | 
|  | // Zero delta time. | 
|  | {"Unable to read ack delay time.", | 
|  | { 0x00, 0x00 }}, | 
|  | // num ack blocks ranges. | 
|  | {"Unable to read num of ack blocks.", | 
|  | { 0x01 }}, | 
|  | // first ack block length. | 
|  | {"Unable to read first ack block length.", | 
|  | { 0x00, 0x00 }}, | 
|  | // gap to next block. | 
|  | { "First block length is zero.", | 
|  | { 0x01 }}, | 
|  | // ack block length. | 
|  | { "First block length is zero.", | 
|  | { 0x0e, 0xaf }}, | 
|  | // Number of timestamps. | 
|  | { "First block length is zero.", | 
|  | { 0x00 }}, | 
|  | }; | 
|  |  | 
|  | PacketFragments packet46 = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | { 0x43 }}, | 
|  | // connection_id | 
|  | {"", | 
|  | { 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 }}, | 
|  | // packet number | 
|  | {"", | 
|  | { 0x12, 0x34, 0x56, 0x78 }}, | 
|  |  | 
|  | // frame type (ack frame) | 
|  | // (more than one ack block, 2 byte largest observed, 2 byte block length) | 
|  | {"", | 
|  | { 0x65 }}, | 
|  | // largest acked | 
|  | {"Unable to read largest acked.", | 
|  | { 0x12, 0x34 }}, | 
|  | // Zero delta time. | 
|  | {"Unable to read ack delay time.", | 
|  | { 0x00, 0x00 }}, | 
|  | // num ack blocks ranges. | 
|  | {"Unable to read num of ack blocks.", | 
|  | { 0x01 }}, | 
|  | // first ack block length. | 
|  | {"Unable to read first ack block length.", | 
|  | { 0x00, 0x00 }}, | 
|  | // gap to next block. | 
|  | { "First block length is zero.", | 
|  | { 0x01 }}, | 
|  | // ack block length. | 
|  | { "First block length is zero.", | 
|  | { 0x0e, 0xaf }}, | 
|  | // Number of timestamps. | 
|  | { "First block length is zero.", | 
|  | { 0x00 }}, | 
|  | }; | 
|  |  | 
|  | // clang-format on | 
|  | PacketFragments& fragments = | 
|  | framer_.transport_version() > QUIC_VERSION_44 | 
|  | ? packet46 | 
|  | : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 : packet); | 
|  |  | 
|  | std::unique_ptr<QuicEncryptedPacket> encrypted( | 
|  | AssemblePacketFromFragments(fragments)); | 
|  |  | 
|  | EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); | 
|  | EXPECT_EQ(QUIC_INVALID_ACK_DATA, framer_.error()); | 
|  |  | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_TRUE(CheckDecryption( | 
|  | *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, | 
|  | PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); | 
|  |  | 
|  | EXPECT_EQ(0u, visitor_.stream_frames_.size()); | 
|  | ASSERT_EQ(1u, visitor_.ack_frames_.size()); | 
|  |  | 
|  | CheckFramingBoundaries(fragments, QUIC_INVALID_ACK_DATA); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, AckFrameOneAckBlockMaxLength) { | 
|  | // clang-format off | 
|  | PacketFragments packet = { | 
|  | // public flags (8 byte connection_id) | 
|  | {"", | 
|  | {0x2C}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | // frame type (ack frame) | 
|  | // (one ack block, 4 byte largest observed, 2 byte block length) | 
|  | {"", | 
|  | {0x49}}, | 
|  | // largest acked | 
|  | {"Unable to read largest acked.", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | // Zero delta time. | 
|  | {"Unable to read ack delay time.", | 
|  | {0x00, 0x00}}, | 
|  | // first ack block length. | 
|  | {"Unable to read first ack block length.", | 
|  | {0x12, 0x34}}, | 
|  | // num timestamps. | 
|  | {"Unable to read num received packets.", | 
|  | {0x00}} | 
|  | }; | 
|  |  | 
|  | PacketFragments packet44 = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x32}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x56, 0x78, 0x9A, 0xBC}}, | 
|  | // frame type (ack frame) | 
|  | // (one ack block, 4 byte largest observed, 2 byte block length) | 
|  | {"", | 
|  | {0x49}}, | 
|  | // largest acked | 
|  | {"Unable to read largest acked.", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | // Zero delta time. | 
|  | {"Unable to read ack delay time.", | 
|  | {0x00, 0x00}}, | 
|  | // first ack block length. | 
|  | {"Unable to read first ack block length.", | 
|  | {0x12, 0x34}}, | 
|  | // num timestamps. | 
|  | {"Unable to read num received packets.", | 
|  | {0x00}} | 
|  | }; | 
|  |  | 
|  | PacketFragments packet46 = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x56, 0x78, 0x9A, 0xBC}}, | 
|  | // frame type (ack frame) | 
|  | // (one ack block, 4 byte largest observed, 2 byte block length) | 
|  | {"", | 
|  | {0x49}}, | 
|  | // largest acked | 
|  | {"Unable to read largest acked.", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | // Zero delta time. | 
|  | {"Unable to read ack delay time.", | 
|  | {0x00, 0x00}}, | 
|  | // first ack block length. | 
|  | {"Unable to read first ack block length.", | 
|  | {0x12, 0x34}}, | 
|  | // num timestamps. | 
|  | {"Unable to read num received packets.", | 
|  | {0x00}} | 
|  | }; | 
|  |  | 
|  | PacketFragments packet99 = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x56, 0x78, 0x9A, 0xBC}}, | 
|  | // frame type (IETF_ACK frame) | 
|  | {"", | 
|  | {0x02}}, | 
|  | // largest acked | 
|  | {"Unable to read largest acked.", | 
|  | {kVarInt62FourBytes  + 0x12, 0x34, 0x56, 0x78}}, | 
|  | // Zero delta time. | 
|  | {"Unable to read ack delay time.", | 
|  | {kVarInt62OneByte + 0x00}}, | 
|  | // Number of ack blocks after first | 
|  | {"Unable to read ack block count.", | 
|  | {kVarInt62OneByte + 0x00}}, | 
|  | // first ack block length. | 
|  | {"Unable to read first ack block length.", | 
|  | {kVarInt62TwoBytes  + 0x12, 0x33}} | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | PacketFragments& fragments = | 
|  | framer_.transport_version() == QUIC_VERSION_99 | 
|  | ? packet99 | 
|  | : (framer_.transport_version() > QUIC_VERSION_44 | 
|  | ? packet46 | 
|  | : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 | 
|  | : packet)); | 
|  | std::unique_ptr<QuicEncryptedPacket> encrypted( | 
|  | AssemblePacketFromFragments(fragments)); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); | 
|  |  | 
|  | EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_TRUE(CheckDecryption( | 
|  | *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, | 
|  | PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); | 
|  |  | 
|  | EXPECT_EQ(0u, visitor_.stream_frames_.size()); | 
|  | ASSERT_EQ(1u, visitor_.ack_frames_.size()); | 
|  | const QuicAckFrame& frame = *visitor_.ack_frames_[0]; | 
|  | EXPECT_EQ(kPacketNumber, LargestAcked(frame)); | 
|  | ASSERT_EQ(4660u, frame.packets.NumPacketsSlow()); | 
|  |  | 
|  | CheckFramingBoundaries(fragments, QUIC_INVALID_ACK_DATA); | 
|  | } | 
|  |  | 
|  | // Tests ability to handle multiple ackblocks after the first ack | 
|  | // block. Non-version-99 tests include multiple timestamps as well. | 
|  | TEST_P(QuicFramerTest, AckFrameTwoTimeStampsMultipleAckBlocks) { | 
|  | // clang-format off | 
|  | PacketFragments packet = { | 
|  | // public flags (8 byte connection_id) | 
|  | {"", | 
|  | { 0x2C }}, | 
|  | // connection_id | 
|  | {"", | 
|  | { 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 }}, | 
|  | // packet number | 
|  | {"", | 
|  | { 0x12, 0x34, 0x56, 0x78 }}, | 
|  |  | 
|  | // frame type (ack frame) | 
|  | // (more than one ack block, 2 byte largest observed, 2 byte block length) | 
|  | {"", | 
|  | { 0x65 }}, | 
|  | // largest acked | 
|  | {"Unable to read largest acked.", | 
|  | { 0x12, 0x34 }}, | 
|  | // Zero delta time. | 
|  | {"Unable to read ack delay time.", | 
|  | { 0x00, 0x00 }}, | 
|  | // num ack blocks ranges. | 
|  | {"Unable to read num of ack blocks.", | 
|  | { 0x04 }}, | 
|  | // first ack block length. | 
|  | {"Unable to read first ack block length.", | 
|  | { 0x00, 0x01 }}, | 
|  | // gap to next block. | 
|  | { "Unable to read gap to next ack block.", | 
|  | { 0x01 }}, | 
|  | // ack block length. | 
|  | { "Unable to ack block length.", | 
|  | { 0x0e, 0xaf }}, | 
|  | // gap to next block. | 
|  | { "Unable to read gap to next ack block.", | 
|  | { 0xff }}, | 
|  | // ack block length. | 
|  | { "Unable to ack block length.", | 
|  | { 0x00, 0x00 }}, | 
|  | // gap to next block. | 
|  | { "Unable to read gap to next ack block.", | 
|  | { 0x91 }}, | 
|  | // ack block length. | 
|  | { "Unable to ack block length.", | 
|  | { 0x01, 0xea }}, | 
|  | // gap to next block. | 
|  | { "Unable to read gap to next ack block.", | 
|  | { 0x05 }}, | 
|  | // ack block length. | 
|  | { "Unable to ack block length.", | 
|  | { 0x00, 0x04 }}, | 
|  | // Number of timestamps. | 
|  | { "Unable to read num received packets.", | 
|  | { 0x02 }}, | 
|  | // Delta from largest observed. | 
|  | { "Unable to read sequence delta in received packets.", | 
|  | { 0x01 }}, | 
|  | // Delta time. | 
|  | { "Unable to read time delta in received packets.", | 
|  | { 0x76, 0x54, 0x32, 0x10 }}, | 
|  | // Delta from largest observed. | 
|  | { "Unable to read sequence delta in received packets.", | 
|  | { 0x02 }}, | 
|  | // Delta time. | 
|  | { "Unable to read incremental time delta in received packets.", | 
|  | { 0x32, 0x10 }}, | 
|  | }; | 
|  |  | 
|  | PacketFragments packet44 = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | { 0x32 }}, | 
|  | // connection_id | 
|  | {"", | 
|  | { 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 }}, | 
|  | // packet number | 
|  | {"", | 
|  | { 0x12, 0x34, 0x56, 0x78 }}, | 
|  |  | 
|  | // frame type (ack frame) | 
|  | // (more than one ack block, 2 byte largest observed, 2 byte block length) | 
|  | {"", | 
|  | { 0x65 }}, | 
|  | // largest acked | 
|  | {"Unable to read largest acked.", | 
|  | { 0x12, 0x34 }}, | 
|  | // Zero delta time. | 
|  | {"Unable to read ack delay time.", | 
|  | { 0x00, 0x00 }}, | 
|  | // num ack blocks ranges. | 
|  | {"Unable to read num of ack blocks.", | 
|  | { 0x04 }}, | 
|  | // first ack block length. | 
|  | {"Unable to read first ack block length.", | 
|  | { 0x00, 0x01 }}, | 
|  | // gap to next block. | 
|  | { "Unable to read gap to next ack block.", | 
|  | { 0x01 }}, | 
|  | // ack block length. | 
|  | { "Unable to ack block length.", | 
|  | { 0x0e, 0xaf }}, | 
|  | // gap to next block. | 
|  | { "Unable to read gap to next ack block.", | 
|  | { 0xff }}, | 
|  | // ack block length. | 
|  | { "Unable to ack block length.", | 
|  | { 0x00, 0x00 }}, | 
|  | // gap to next block. | 
|  | { "Unable to read gap to next ack block.", | 
|  | { 0x91 }}, | 
|  | // ack block length. | 
|  | { "Unable to ack block length.", | 
|  | { 0x01, 0xea }}, | 
|  | // gap to next block. | 
|  | { "Unable to read gap to next ack block.", | 
|  | { 0x05 }}, | 
|  | // ack block length. | 
|  | { "Unable to ack block length.", | 
|  | { 0x00, 0x04 }}, | 
|  | // Number of timestamps. | 
|  | { "Unable to read num received packets.", | 
|  | { 0x02 }}, | 
|  | // Delta from largest observed. | 
|  | { "Unable to read sequence delta in received packets.", | 
|  | { 0x01 }}, | 
|  | // Delta time. | 
|  | { "Unable to read time delta in received packets.", | 
|  | { 0x76, 0x54, 0x32, 0x10 }}, | 
|  | // Delta from largest observed. | 
|  | { "Unable to read sequence delta in received packets.", | 
|  | { 0x02 }}, | 
|  | // Delta time. | 
|  | { "Unable to read incremental time delta in received packets.", | 
|  | { 0x32, 0x10 }}, | 
|  | }; | 
|  |  | 
|  | PacketFragments packet46 = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | { 0x43 }}, | 
|  | // connection_id | 
|  | {"", | 
|  | { 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 }}, | 
|  | // packet number | 
|  | {"", | 
|  | { 0x12, 0x34, 0x56, 0x78 }}, | 
|  |  | 
|  | // frame type (ack frame) | 
|  | // (more than one ack block, 2 byte largest observed, 2 byte block length) | 
|  | {"", | 
|  | { 0x65 }}, | 
|  | // largest acked | 
|  | {"Unable to read largest acked.", | 
|  | { 0x12, 0x34 }}, | 
|  | // Zero delta time. | 
|  | {"Unable to read ack delay time.", | 
|  | { 0x00, 0x00 }}, | 
|  | // num ack blocks ranges. | 
|  | {"Unable to read num of ack blocks.", | 
|  | { 0x04 }}, | 
|  | // first ack block length. | 
|  | {"Unable to read first ack block length.", | 
|  | { 0x00, 0x01 }}, | 
|  | // gap to next block. | 
|  | { "Unable to read gap to next ack block.", | 
|  | { 0x01 }}, | 
|  | // ack block length. | 
|  | { "Unable to ack block length.", | 
|  | { 0x0e, 0xaf }}, | 
|  | // gap to next block. | 
|  | { "Unable to read gap to next ack block.", | 
|  | { 0xff }}, | 
|  | // ack block length. | 
|  | { "Unable to ack block length.", | 
|  | { 0x00, 0x00 }}, | 
|  | // gap to next block. | 
|  | { "Unable to read gap to next ack block.", | 
|  | { 0x91 }}, | 
|  | // ack block length. | 
|  | { "Unable to ack block length.", | 
|  | { 0x01, 0xea }}, | 
|  | // gap to next block. | 
|  | { "Unable to read gap to next ack block.", | 
|  | { 0x05 }}, | 
|  | // ack block length. | 
|  | { "Unable to ack block length.", | 
|  | { 0x00, 0x04 }}, | 
|  | // Number of timestamps. | 
|  | { "Unable to read num received packets.", | 
|  | { 0x02 }}, | 
|  | // Delta from largest observed. | 
|  | { "Unable to read sequence delta in received packets.", | 
|  | { 0x01 }}, | 
|  | // Delta time. | 
|  | { "Unable to read time delta in received packets.", | 
|  | { 0x76, 0x54, 0x32, 0x10 }}, | 
|  | // Delta from largest observed. | 
|  | { "Unable to read sequence delta in received packets.", | 
|  | { 0x02 }}, | 
|  | // Delta time. | 
|  | { "Unable to read incremental time delta in received packets.", | 
|  | { 0x32, 0x10 }}, | 
|  | }; | 
|  |  | 
|  | PacketFragments packet99 = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | { 0x43 }}, | 
|  | // connection_id | 
|  | {"", | 
|  | { 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 }}, | 
|  | // packet number | 
|  | {"", | 
|  | { 0x12, 0x34, 0x56, 0x78 }}, | 
|  |  | 
|  | // frame type (IETF_ACK frame) | 
|  | {"", | 
|  | { 0x02 }}, | 
|  | // largest acked | 
|  | {"Unable to read largest acked.", | 
|  | { kVarInt62TwoBytes + 0x12, 0x34 }},   // = 4660 | 
|  | // Zero delta time. | 
|  | {"Unable to read ack delay time.", | 
|  | { kVarInt62OneByte + 0x00 }}, | 
|  | // number of additional ack blocks | 
|  | {"Unable to read ack block count.", | 
|  | { kVarInt62OneByte + 0x03 }}, | 
|  | // first ack block length. | 
|  | {"Unable to read first ack block length.", | 
|  | { kVarInt62OneByte + 0x00 }},  // 1st block length = 1 | 
|  |  | 
|  | // Additional ACK Block #1 | 
|  | // gap to next block. | 
|  | { "Unable to read gap block value.", | 
|  | { kVarInt62OneByte + 0x00 }},   // gap of 1 packet | 
|  | // ack block length. | 
|  | { "Unable to read ack block value.", | 
|  | { kVarInt62TwoBytes + 0x0e, 0xae }},   // 3759 | 
|  |  | 
|  | // pre-version-99 test includes an ack block of 0 length. this | 
|  | // can not happen in version 99. ergo the second block is not | 
|  | // present in the v99 test and the gap length of the next block | 
|  | // is the sum of the two gaps in the pre-version-99 tests. | 
|  | // Additional ACK Block #2 | 
|  | // gap to next block. | 
|  | { "Unable to read gap block value.", | 
|  | { kVarInt62TwoBytes + 0x01, 0x8f }},  // Gap is 400 (0x190) pkts | 
|  | // ack block length. | 
|  | { "Unable to read ack block value.", | 
|  | { kVarInt62TwoBytes + 0x01, 0xe9 }},  // block is 389 (x1ea) pkts | 
|  |  | 
|  | // Additional ACK Block #3 | 
|  | // gap to next block. | 
|  | { "Unable to read gap block value.", | 
|  | { kVarInt62OneByte + 0x04 }},   // Gap is 5 packets. | 
|  | // ack block length. | 
|  | { "Unable to read ack block value.", | 
|  | { kVarInt62OneByte + 0x03 }},   // block is 3 packets. | 
|  | }; | 
|  |  | 
|  | // clang-format on | 
|  | PacketFragments& fragments = | 
|  | framer_.transport_version() == QUIC_VERSION_99 | 
|  | ? packet99 | 
|  | : (framer_.transport_version() > QUIC_VERSION_44 | 
|  | ? packet46 | 
|  | : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 | 
|  | : packet)); | 
|  |  | 
|  | std::unique_ptr<QuicEncryptedPacket> encrypted( | 
|  | AssemblePacketFromFragments(fragments)); | 
|  |  | 
|  | framer_.set_process_timestamps(true); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); | 
|  |  | 
|  | EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_TRUE(CheckDecryption( | 
|  | *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, | 
|  | PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); | 
|  |  | 
|  | EXPECT_EQ(0u, visitor_.stream_frames_.size()); | 
|  | ASSERT_EQ(1u, visitor_.ack_frames_.size()); | 
|  | const QuicAckFrame& frame = *visitor_.ack_frames_[0]; | 
|  | EXPECT_EQ(kSmallLargestObserved, LargestAcked(frame)); | 
|  | ASSERT_EQ(4254u, frame.packets.NumPacketsSlow()); | 
|  | EXPECT_EQ(4u, frame.packets.NumIntervals()); | 
|  | if (framer_.transport_version() == QUIC_VERSION_99) { | 
|  | EXPECT_EQ(0u, frame.received_packet_times.size()); | 
|  | } else { | 
|  | EXPECT_EQ(2u, frame.received_packet_times.size()); | 
|  | } | 
|  | CheckFramingBoundaries(fragments, QUIC_INVALID_ACK_DATA); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, AckFrameTimeStampDeltaTooHigh) { | 
|  | // clang-format off | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x28, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (ack frame) | 
|  | // (no ack blocks, 1 byte largest observed, 1 byte block length) | 
|  | 0x40, | 
|  | // largest acked | 
|  | 0x01, | 
|  | // Zero delta time. | 
|  | 0x00, 0x00, | 
|  | // first ack block length. | 
|  | 0x01, | 
|  | // num timestamps. | 
|  | 0x01, | 
|  | // Delta from largest observed. | 
|  | 0x01, | 
|  | // Delta time. | 
|  | 0x10, 0x32, 0x54, 0x76, | 
|  | }; | 
|  |  | 
|  | unsigned char packet44[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x32, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (ack frame) | 
|  | // (no ack blocks, 1 byte largest observed, 1 byte block length) | 
|  | 0x40, | 
|  | // largest acked | 
|  | 0x01, | 
|  | // Zero delta time. | 
|  | 0x00, 0x00, | 
|  | // first ack block length. | 
|  | 0x01, | 
|  | // num timestamps. | 
|  | 0x01, | 
|  | // Delta from largest observed. | 
|  | 0x01, | 
|  | // Delta time. | 
|  | 0x10, 0x32, 0x54, 0x76, | 
|  | }; | 
|  |  | 
|  | unsigned char packet46[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (ack frame) | 
|  | // (no ack blocks, 1 byte largest observed, 1 byte block length) | 
|  | 0x40, | 
|  | // largest acked | 
|  | 0x01, | 
|  | // Zero delta time. | 
|  | 0x00, 0x00, | 
|  | // first ack block length. | 
|  | 0x01, | 
|  | // num timestamps. | 
|  | 0x01, | 
|  | // Delta from largest observed. | 
|  | 0x01, | 
|  | // Delta time. | 
|  | 0x10, 0x32, 0x54, 0x76, | 
|  | }; | 
|  | // clang-format on | 
|  | if (framer_.transport_version() == QUIC_VERSION_99) { | 
|  | return; | 
|  | } | 
|  | QuicEncryptedPacket encrypted( | 
|  | AsChars(framer_.transport_version() > QUIC_VERSION_44 | 
|  | ? packet46 | 
|  | : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 | 
|  | : packet)), | 
|  | QUIC_ARRAYSIZE(packet), false); | 
|  | EXPECT_FALSE(framer_.ProcessPacket(encrypted)); | 
|  | EXPECT_TRUE(QuicTextUtils::StartsWith( | 
|  | framer_.detailed_error(), "delta_from_largest_observed too high")); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, AckFrameTimeStampSecondDeltaTooHigh) { | 
|  | // clang-format off | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x28, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (ack frame) | 
|  | // (no ack blocks, 1 byte largest observed, 1 byte block length) | 
|  | 0x40, | 
|  | // largest acked | 
|  | 0x03, | 
|  | // Zero delta time. | 
|  | 0x00, 0x00, | 
|  | // first ack block length. | 
|  | 0x03, | 
|  | // num timestamps. | 
|  | 0x02, | 
|  | // Delta from largest observed. | 
|  | 0x01, | 
|  | // Delta time. | 
|  | 0x10, 0x32, 0x54, 0x76, | 
|  | // Delta from largest observed. | 
|  | 0x03, | 
|  | // Delta time. | 
|  | 0x10, 0x32, | 
|  | }; | 
|  |  | 
|  | unsigned char packet44[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x32, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (ack frame) | 
|  | // (no ack blocks, 1 byte largest observed, 1 byte block length) | 
|  | 0x40, | 
|  | // largest acked | 
|  | 0x03, | 
|  | // Zero delta time. | 
|  | 0x00, 0x00, | 
|  | // first ack block length. | 
|  | 0x03, | 
|  | // num timestamps. | 
|  | 0x02, | 
|  | // Delta from largest observed. | 
|  | 0x01, | 
|  | // Delta time. | 
|  | 0x10, 0x32, 0x54, 0x76, | 
|  | // Delta from largest observed. | 
|  | 0x03, | 
|  | // Delta time. | 
|  | 0x10, 0x32, | 
|  | }; | 
|  |  | 
|  | unsigned char packet46[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (ack frame) | 
|  | // (no ack blocks, 1 byte largest observed, 1 byte block length) | 
|  | 0x40, | 
|  | // largest acked | 
|  | 0x03, | 
|  | // Zero delta time. | 
|  | 0x00, 0x00, | 
|  | // first ack block length. | 
|  | 0x03, | 
|  | // num timestamps. | 
|  | 0x02, | 
|  | // Delta from largest observed. | 
|  | 0x01, | 
|  | // Delta time. | 
|  | 0x10, 0x32, 0x54, 0x76, | 
|  | // Delta from largest observed. | 
|  | 0x03, | 
|  | // Delta time. | 
|  | 0x10, 0x32, | 
|  | }; | 
|  | // clang-format on | 
|  | if (framer_.transport_version() == QUIC_VERSION_99) { | 
|  | return; | 
|  | } | 
|  | QuicEncryptedPacket encrypted( | 
|  | AsChars(framer_.transport_version() > QUIC_VERSION_44 | 
|  | ? packet46 | 
|  | : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 | 
|  | : packet)), | 
|  | QUIC_ARRAYSIZE(packet), false); | 
|  | EXPECT_FALSE(framer_.ProcessPacket(encrypted)); | 
|  | EXPECT_TRUE(QuicTextUtils::StartsWith( | 
|  | framer_.detailed_error(), "delta_from_largest_observed too high")); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, NewStopWaitingFrame) { | 
|  | if (version_.transport_version == QUIC_VERSION_99) { | 
|  | return; | 
|  | } | 
|  | // clang-format off | 
|  | PacketFragments packet = { | 
|  | // public flags (8 byte connection_id) | 
|  | {"", | 
|  | {0x2C}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | // frame type (stop waiting frame) | 
|  | {"", | 
|  | {0x06}}, | 
|  | // least packet number awaiting an ack, delta from packet number. | 
|  | {"Unable to read least unacked delta.", | 
|  | {0x00, 0x00, 0x00, 0x08}} | 
|  | }; | 
|  |  | 
|  | PacketFragments packet44 = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x32}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | // frame type (stop waiting frame) | 
|  | {"", | 
|  | {0x06}}, | 
|  | // least packet number awaiting an ack, delta from packet number. | 
|  | {"Unable to read least unacked delta.", | 
|  | {0x00, 0x00, 0x00, 0x08}} | 
|  | }; | 
|  |  | 
|  | PacketFragments packet46 = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | // frame type (stop waiting frame) | 
|  | {"", | 
|  | {0x06}}, | 
|  | // least packet number awaiting an ack, delta from packet number. | 
|  | {"Unable to read least unacked delta.", | 
|  | {0x00, 0x00, 0x00, 0x08}} | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | PacketFragments& fragments = | 
|  | framer_.transport_version() > QUIC_VERSION_44 | 
|  | ? packet46 | 
|  | : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 : packet); | 
|  |  | 
|  | std::unique_ptr<QuicEncryptedPacket> encrypted( | 
|  | AssemblePacketFromFragments(fragments)); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); | 
|  |  | 
|  | EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_TRUE(CheckDecryption( | 
|  | *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, | 
|  | PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); | 
|  |  | 
|  | EXPECT_EQ(0u, visitor_.stream_frames_.size()); | 
|  | ASSERT_EQ(1u, visitor_.stop_waiting_frames_.size()); | 
|  | const QuicStopWaitingFrame& frame = *visitor_.stop_waiting_frames_[0]; | 
|  | EXPECT_EQ(kLeastUnacked, frame.least_unacked); | 
|  |  | 
|  | CheckFramingBoundaries(fragments, QUIC_INVALID_STOP_WAITING_DATA); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, InvalidNewStopWaitingFrame) { | 
|  | if (version_.transport_version == QUIC_VERSION_99) { | 
|  | return; | 
|  | } | 
|  | // clang-format off | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x2C, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  | // frame type (stop waiting frame) | 
|  | 0x06, | 
|  | // least packet number awaiting an ack, delta from packet number. | 
|  | 0x13, 0x34, 0x56, 0x78, | 
|  | 0x9A, 0xA8, | 
|  | }; | 
|  |  | 
|  | unsigned char packet44[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x32, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  | // frame type (stop waiting frame) | 
|  | 0x06, | 
|  | // least packet number awaiting an ack, delta from packet number. | 
|  | 0x57, 0x78, 0x9A, 0xA8, | 
|  | }; | 
|  |  | 
|  | unsigned char packet46[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  | // frame type (stop waiting frame) | 
|  | 0x06, | 
|  | // least packet number awaiting an ack, delta from packet number. | 
|  | 0x57, 0x78, 0x9A, 0xA8, | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | QuicEncryptedPacket encrypted( | 
|  | AsChars(framer_.transport_version() > QUIC_VERSION_44 | 
|  | ? packet46 | 
|  | : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 | 
|  | : packet)), | 
|  | framer_.transport_version() > QUIC_VERSION_43 ? QUIC_ARRAYSIZE(packet44) | 
|  | : QUIC_ARRAYSIZE(packet), | 
|  | false); | 
|  | EXPECT_FALSE(framer_.ProcessPacket(encrypted)); | 
|  | EXPECT_EQ(QUIC_INVALID_STOP_WAITING_DATA, framer_.error()); | 
|  | EXPECT_EQ("Invalid unacked delta.", framer_.detailed_error()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, RstStreamFrame) { | 
|  | // clang-format off | 
|  | PacketFragments packet = { | 
|  | // public flags (8 byte connection_id) | 
|  | {"", | 
|  | {0x28}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | // frame type (rst stream frame) | 
|  | {"", | 
|  | {0x01}}, | 
|  | // stream id | 
|  | {"Unable to read stream_id.", | 
|  | {0x01, 0x02, 0x03, 0x04}}, | 
|  | // sent byte offset | 
|  | {"Unable to read rst stream sent byte offset.", | 
|  | {0x3A, 0x98, 0xFE, 0xDC, | 
|  | 0x32, 0x10, 0x76, 0x54}}, | 
|  | // error code | 
|  | {"Unable to read rst stream error code.", | 
|  | {0x00, 0x00, 0x00, 0x01}} | 
|  | }; | 
|  |  | 
|  | PacketFragments packet44 = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x32}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | // frame type (rst stream frame) | 
|  | {"", | 
|  | {0x01}}, | 
|  | // stream id | 
|  | {"Unable to read stream_id.", | 
|  | {0x01, 0x02, 0x03, 0x04}}, | 
|  | // sent byte offset | 
|  | {"Unable to read rst stream sent byte offset.", | 
|  | {0x3A, 0x98, 0xFE, 0xDC, | 
|  | 0x32, 0x10, 0x76, 0x54}}, | 
|  | // error code | 
|  | {"Unable to read rst stream error code.", | 
|  | {0x00, 0x00, 0x00, 0x01}} | 
|  | }; | 
|  |  | 
|  | PacketFragments packet46 = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | // frame type (rst stream frame) | 
|  | {"", | 
|  | {0x01}}, | 
|  | // stream id | 
|  | {"Unable to read stream_id.", | 
|  | {0x01, 0x02, 0x03, 0x04}}, | 
|  | // sent byte offset | 
|  | {"Unable to read rst stream sent byte offset.", | 
|  | {0x3A, 0x98, 0xFE, 0xDC, | 
|  | 0x32, 0x10, 0x76, 0x54}}, | 
|  | // error code | 
|  | {"Unable to read rst stream error code.", | 
|  | {0x00, 0x00, 0x00, 0x01}} | 
|  | }; | 
|  |  | 
|  | PacketFragments packet99 = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | // frame type (IETF_RST_STREAM frame) | 
|  | {"", | 
|  | {0x04}}, | 
|  | // stream id | 
|  | {"Unable to read rst stream stream id.", | 
|  | {kVarInt62FourBytes + 0x01, 0x02, 0x03, 0x04}}, | 
|  | // application error code | 
|  | {"Unable to read rst stream error code.", | 
|  | {0x00, 0x01}},   // Not varint62 encoded | 
|  | // Final Offset | 
|  | {"Unable to read rst stream sent byte offset.", | 
|  | {kVarInt62EightBytes + 0x3a, 0x98, 0xFE, 0xDC, 0x32, 0x10, 0x76, 0x54}} | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | PacketFragments& fragments = | 
|  | framer_.transport_version() == QUIC_VERSION_99 | 
|  | ? packet99 | 
|  | : (framer_.transport_version() > QUIC_VERSION_44 | 
|  | ? packet46 | 
|  | : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 | 
|  | : packet)); | 
|  | std::unique_ptr<QuicEncryptedPacket> encrypted( | 
|  | AssemblePacketFromFragments(fragments)); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); | 
|  |  | 
|  | EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_TRUE(CheckDecryption( | 
|  | *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, | 
|  | PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); | 
|  |  | 
|  | EXPECT_EQ(kStreamId, visitor_.rst_stream_frame_.stream_id); | 
|  | EXPECT_EQ(0x01, visitor_.rst_stream_frame_.error_code); | 
|  | EXPECT_EQ(kStreamOffset, visitor_.rst_stream_frame_.byte_offset); | 
|  | CheckFramingBoundaries(fragments, QUIC_INVALID_RST_STREAM_DATA); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, ConnectionCloseFrame) { | 
|  | // clang-format off | 
|  | PacketFragments packet = { | 
|  | // public flags (8 byte connection_id) | 
|  | {"", | 
|  | {0x28}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | // frame type (connection close frame) | 
|  | {"", | 
|  | {0x02}}, | 
|  | // error code | 
|  | {"Unable to read connection close error code.", | 
|  | {0x00, 0x00, 0x00, 0x11}}, | 
|  | {"Unable to read connection close error details.", | 
|  | { | 
|  | // error details length | 
|  | 0x0, 0x0d, | 
|  | // error details | 
|  | 'b',  'e',  'c',  'a', | 
|  | 'u',  's',  'e',  ' ', | 
|  | 'I',  ' ',  'c',  'a', | 
|  | 'n'} | 
|  | } | 
|  | }; | 
|  |  | 
|  | PacketFragments packet44 = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x32}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | // frame type (connection close frame) | 
|  | {"", | 
|  | {0x02}}, | 
|  | // error code | 
|  | {"Unable to read connection close error code.", | 
|  | {0x00, 0x00, 0x00, 0x11}}, | 
|  | {"Unable to read connection close error details.", | 
|  | { | 
|  | // error details length | 
|  | 0x0, 0x0d, | 
|  | // error details | 
|  | 'b',  'e',  'c',  'a', | 
|  | 'u',  's',  'e',  ' ', | 
|  | 'I',  ' ',  'c',  'a', | 
|  | 'n'} | 
|  | } | 
|  | }; | 
|  |  | 
|  | PacketFragments packet46 = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | // frame type (connection close frame) | 
|  | {"", | 
|  | {0x02}}, | 
|  | // error code | 
|  | {"Unable to read connection close error code.", | 
|  | {0x00, 0x00, 0x00, 0x11}}, | 
|  | {"Unable to read connection close error details.", | 
|  | { | 
|  | // error details length | 
|  | 0x0, 0x0d, | 
|  | // error details | 
|  | 'b',  'e',  'c',  'a', | 
|  | 'u',  's',  'e',  ' ', | 
|  | 'I',  ' ',  'c',  'a', | 
|  | 'n'} | 
|  | } | 
|  | }; | 
|  |  | 
|  | PacketFragments packet99 = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | // frame type (IETF_CONNECTION_CLOSE frame) | 
|  | {"", | 
|  | {0x1c}}, | 
|  | // error code | 
|  | {"Unable to read connection close error code.", | 
|  | {0x00, 0x11}}, | 
|  | {"Unable to read connection close frame type.", | 
|  | {kVarInt62TwoBytes + 0x12, 0x34 }}, | 
|  | {"Unable to read connection close error details.", | 
|  | { | 
|  | // error details length | 
|  | kVarInt62OneByte + 0x0d, | 
|  | // error details | 
|  | 'b',  'e',  'c',  'a', | 
|  | 'u',  's',  'e',  ' ', | 
|  | 'I',  ' ',  'c',  'a', | 
|  | 'n'} | 
|  | } | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | PacketFragments& fragments = | 
|  | framer_.transport_version() == QUIC_VERSION_99 | 
|  | ? packet99 | 
|  | : (framer_.transport_version() > QUIC_VERSION_44 | 
|  | ? packet46 | 
|  | : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 | 
|  | : packet)); | 
|  | std::unique_ptr<QuicEncryptedPacket> encrypted( | 
|  | AssemblePacketFromFragments(fragments)); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); | 
|  |  | 
|  | EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_TRUE(CheckDecryption( | 
|  | *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, | 
|  | PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); | 
|  |  | 
|  | EXPECT_EQ(0u, visitor_.stream_frames_.size()); | 
|  |  | 
|  | EXPECT_EQ(0x11, visitor_.connection_close_frame_.error_code); | 
|  | EXPECT_EQ("because I can", visitor_.connection_close_frame_.error_details); | 
|  | if (framer_.transport_version() == QUIC_VERSION_99) { | 
|  | EXPECT_EQ(0x1234u, visitor_.connection_close_frame_.frame_type); | 
|  | } | 
|  |  | 
|  | ASSERT_EQ(0u, visitor_.ack_frames_.size()); | 
|  |  | 
|  | CheckFramingBoundaries(fragments, QUIC_INVALID_CONNECTION_CLOSE_DATA); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, ApplicationCloseFrame) { | 
|  | if (framer_.transport_version() != QUIC_VERSION_99) { | 
|  | // This frame does not exist in versions other than 99. | 
|  | return; | 
|  | } | 
|  |  | 
|  | // clang-format off | 
|  | PacketFragments packet99 = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | // frame type (IETF_APPLICATION_CLOSE frame) | 
|  | {"", | 
|  | {0x1d}}, | 
|  | // error code | 
|  | {"Unable to read application close error code.", | 
|  | {0x00, 0x11}}, | 
|  | {"Unable to read application close error details.", | 
|  | { | 
|  | // error details length | 
|  | kVarInt62OneByte + 0x0d, | 
|  | // error details | 
|  | 'b',  'e',  'c',  'a', | 
|  | 'u',  's',  'e',  ' ', | 
|  | 'I',  ' ',  'c',  'a', | 
|  | 'n'} | 
|  | } | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | std::unique_ptr<QuicEncryptedPacket> encrypted( | 
|  | AssemblePacketFromFragments(packet99)); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); | 
|  |  | 
|  | EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_TRUE(CheckDecryption( | 
|  | *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, | 
|  | PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); | 
|  |  | 
|  | EXPECT_EQ(0u, visitor_.stream_frames_.size()); | 
|  |  | 
|  | EXPECT_EQ(0x11, visitor_.application_close_frame_.error_code); | 
|  | EXPECT_EQ("because I can", visitor_.application_close_frame_.error_details); | 
|  |  | 
|  | ASSERT_EQ(0u, visitor_.ack_frames_.size()); | 
|  |  | 
|  | CheckFramingBoundaries(packet99, QUIC_INVALID_APPLICATION_CLOSE_DATA); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, GoAwayFrame) { | 
|  | if (framer_.transport_version() == QUIC_VERSION_99) { | 
|  | // This frame is not supported in version 99. | 
|  | return; | 
|  | } | 
|  | // clang-format off | 
|  | PacketFragments packet = { | 
|  | // public flags (8 byte connection_id) | 
|  | {"", | 
|  | {0x28}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | // frame type (go away frame) | 
|  | {"", | 
|  | {0x03}}, | 
|  | // error code | 
|  | {"Unable to read go away error code.", | 
|  | {0x00, 0x00, 0x00, 0x09}}, | 
|  | // stream id | 
|  | {"Unable to read last good stream id.", | 
|  | {0x01, 0x02, 0x03, 0x04}}, | 
|  | // stream id | 
|  | {"Unable to read goaway reason.", | 
|  | { | 
|  | // error details length | 
|  | 0x0, 0x0d, | 
|  | // error details | 
|  | 'b',  'e',  'c',  'a', | 
|  | 'u',  's',  'e',  ' ', | 
|  | 'I',  ' ',  'c',  'a', | 
|  | 'n'} | 
|  | } | 
|  | }; | 
|  |  | 
|  | PacketFragments packet44 = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x32}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | // frame type (go away frame) | 
|  | {"", | 
|  | {0x03}}, | 
|  | // error code | 
|  | {"Unable to read go away error code.", | 
|  | {0x00, 0x00, 0x00, 0x09}}, | 
|  | // stream id | 
|  | {"Unable to read last good stream id.", | 
|  | {0x01, 0x02, 0x03, 0x04}}, | 
|  | // stream id | 
|  | {"Unable to read goaway reason.", | 
|  | { | 
|  | // error details length | 
|  | 0x0, 0x0d, | 
|  | // error details | 
|  | 'b',  'e',  'c',  'a', | 
|  | 'u',  's',  'e',  ' ', | 
|  | 'I',  ' ',  'c',  'a', | 
|  | 'n'} | 
|  | } | 
|  | }; | 
|  |  | 
|  | PacketFragments packet46 = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | // frame type (go away frame) | 
|  | {"", | 
|  | {0x03}}, | 
|  | // error code | 
|  | {"Unable to read go away error code.", | 
|  | {0x00, 0x00, 0x00, 0x09}}, | 
|  | // stream id | 
|  | {"Unable to read last good stream id.", | 
|  | {0x01, 0x02, 0x03, 0x04}}, | 
|  | // stream id | 
|  | {"Unable to read goaway reason.", | 
|  | { | 
|  | // error details length | 
|  | 0x0, 0x0d, | 
|  | // error details | 
|  | 'b',  'e',  'c',  'a', | 
|  | 'u',  's',  'e',  ' ', | 
|  | 'I',  ' ',  'c',  'a', | 
|  | 'n'} | 
|  | } | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | PacketFragments& fragments = | 
|  | framer_.transport_version() > QUIC_VERSION_44 | 
|  | ? packet46 | 
|  | : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 : packet); | 
|  | std::unique_ptr<QuicEncryptedPacket> encrypted( | 
|  | AssemblePacketFromFragments(fragments)); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); | 
|  |  | 
|  | EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_TRUE(CheckDecryption( | 
|  | *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, | 
|  | PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); | 
|  |  | 
|  | EXPECT_EQ(kStreamId, visitor_.goaway_frame_.last_good_stream_id); | 
|  | EXPECT_EQ(0x9, visitor_.goaway_frame_.error_code); | 
|  | EXPECT_EQ("because I can", visitor_.goaway_frame_.reason_phrase); | 
|  |  | 
|  | CheckFramingBoundaries(fragments, QUIC_INVALID_GOAWAY_DATA); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, WindowUpdateFrame) { | 
|  | if (framer_.transport_version() == QUIC_VERSION_99) { | 
|  | // This frame is not in version 99, see MaxDataFrame and MaxStreamDataFrame | 
|  | // for Version 99 equivalents. | 
|  | return; | 
|  | } | 
|  | // clang-format off | 
|  | PacketFragments packet = { | 
|  | // public flags (8 byte connection_id) | 
|  | {"", | 
|  | {0x28}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | // frame type (window update frame) | 
|  | {"", | 
|  | {0x04}}, | 
|  | // stream id | 
|  | {"Unable to read stream_id.", | 
|  | {0x01, 0x02, 0x03, 0x04}}, | 
|  | // byte offset | 
|  | {"Unable to read window byte_offset.", | 
|  | {0x3A, 0x98, 0xFE, 0xDC, | 
|  | 0x32, 0x10, 0x76, 0x54}}, | 
|  | }; | 
|  |  | 
|  | PacketFragments packet44 = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x32}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | // frame type (window update frame) | 
|  | {"", | 
|  | {0x04}}, | 
|  | // stream id | 
|  | {"Unable to read stream_id.", | 
|  | {0x01, 0x02, 0x03, 0x04}}, | 
|  | // byte offset | 
|  | {"Unable to read window byte_offset.", | 
|  | {0x3A, 0x98, 0xFE, 0xDC, | 
|  | 0x32, 0x10, 0x76, 0x54}}, | 
|  | }; | 
|  |  | 
|  | PacketFragments packet46 = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | // frame type (window update frame) | 
|  | {"", | 
|  | {0x04}}, | 
|  | // stream id | 
|  | {"Unable to read stream_id.", | 
|  | {0x01, 0x02, 0x03, 0x04}}, | 
|  | // byte offset | 
|  | {"Unable to read window byte_offset.", | 
|  | {0x3A, 0x98, 0xFE, 0xDC, | 
|  | 0x32, 0x10, 0x76, 0x54}}, | 
|  | }; | 
|  |  | 
|  | // clang-format on | 
|  |  | 
|  | PacketFragments& fragments = | 
|  | framer_.transport_version() > QUIC_VERSION_44 | 
|  | ? packet46 | 
|  | : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 : packet); | 
|  | std::unique_ptr<QuicEncryptedPacket> encrypted( | 
|  | AssemblePacketFromFragments(fragments)); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); | 
|  |  | 
|  | EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_TRUE(CheckDecryption( | 
|  | *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, | 
|  | PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); | 
|  |  | 
|  | EXPECT_EQ(kStreamId, visitor_.window_update_frame_.stream_id); | 
|  | EXPECT_EQ(kStreamOffset, visitor_.window_update_frame_.byte_offset); | 
|  |  | 
|  | CheckFramingBoundaries(fragments, QUIC_INVALID_WINDOW_UPDATE_DATA); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, MaxDataFrame) { | 
|  | if (framer_.transport_version() != QUIC_VERSION_99) { | 
|  | // This frame is available only in version 99. | 
|  | return; | 
|  | } | 
|  | // clang-format off | 
|  | PacketFragments packet99 = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | // frame type (IETF_MAX_DATA frame) | 
|  | {"", | 
|  | {0x10}}, | 
|  | // byte offset | 
|  | {"Can not read MAX_DATA byte-offset", | 
|  | {kVarInt62EightBytes + 0x3A, 0x98, 0xFE, 0xDC, | 
|  | 0x32, 0x10, 0x76, 0x54}}, | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | std::unique_ptr<QuicEncryptedPacket> encrypted( | 
|  | AssemblePacketFromFragments(packet99)); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); | 
|  |  | 
|  | EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_TRUE(CheckDecryption( | 
|  | *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, | 
|  | PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); | 
|  |  | 
|  | EXPECT_EQ(QuicUtils::GetInvalidStreamId(framer_.transport_version()), | 
|  | visitor_.window_update_frame_.stream_id); | 
|  | EXPECT_EQ(kStreamOffset, visitor_.window_update_frame_.byte_offset); | 
|  |  | 
|  | CheckFramingBoundaries(packet99, QUIC_INVALID_MAX_DATA_FRAME_DATA); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, MaxStreamDataFrame) { | 
|  | if (framer_.transport_version() != QUIC_VERSION_99) { | 
|  | // This frame available only in version 99. | 
|  | return; | 
|  | } | 
|  | // clang-format off | 
|  | PacketFragments packet99 = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | // frame type (IETF_MAX_STREAM_DATA frame) | 
|  | {"", | 
|  | {0x11}}, | 
|  | // stream id | 
|  | {"Can not read MAX_STREAM_DATA stream id", | 
|  | {kVarInt62FourBytes + 0x01, 0x02, 0x03, 0x04}}, | 
|  | // byte offset | 
|  | {"Can not read MAX_STREAM_DATA byte-count", | 
|  | {kVarInt62EightBytes + 0x3A, 0x98, 0xFE, 0xDC, | 
|  | 0x32, 0x10, 0x76, 0x54}}, | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | std::unique_ptr<QuicEncryptedPacket> encrypted( | 
|  | AssemblePacketFromFragments(packet99)); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); | 
|  |  | 
|  | EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_TRUE(CheckDecryption( | 
|  | *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, | 
|  | PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); | 
|  |  | 
|  | EXPECT_EQ(kStreamId, visitor_.window_update_frame_.stream_id); | 
|  | EXPECT_EQ(kStreamOffset, visitor_.window_update_frame_.byte_offset); | 
|  |  | 
|  | CheckFramingBoundaries(packet99, QUIC_INVALID_MAX_STREAM_DATA_FRAME_DATA); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, BlockedFrame) { | 
|  | // clang-format off | 
|  | PacketFragments packet = { | 
|  | // public flags (8 byte connection_id) | 
|  | {"", | 
|  | {0x28}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | // frame type (blocked frame) | 
|  | {"", | 
|  | {0x05}}, | 
|  | // stream id | 
|  | {"Unable to read stream_id.", | 
|  | {0x01, 0x02, 0x03, 0x04}}, | 
|  | }; | 
|  |  | 
|  | PacketFragments packet44 = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x32}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | // frame type (blocked frame) | 
|  | {"", | 
|  | {0x05}}, | 
|  | // stream id | 
|  | {"Unable to read stream_id.", | 
|  | {0x01, 0x02, 0x03, 0x04}}, | 
|  | }; | 
|  |  | 
|  | PacketFragments packet46 = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | // frame type (blocked frame) | 
|  | {"", | 
|  | {0x05}}, | 
|  | // stream id | 
|  | {"Unable to read stream_id.", | 
|  | {0x01, 0x02, 0x03, 0x04}}, | 
|  | }; | 
|  |  | 
|  | PacketFragments packet99 = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | // frame type (IETF_STREAM_BLOCKED frame) | 
|  | {"", | 
|  | {0x15}}, | 
|  | // stream id | 
|  | {"Can not read stream blocked stream id.", | 
|  | {kVarInt62FourBytes + 0x01, 0x02, 0x03, 0x04}}, | 
|  | // Offset | 
|  | {"Can not read stream blocked offset.", | 
|  | {kVarInt62EightBytes + 0x3a, 0x98, 0xFE, 0xDC, 0x32, 0x10, 0x76, 0x54}}, | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | PacketFragments& fragments = | 
|  | framer_.transport_version() == QUIC_VERSION_99 | 
|  | ? packet99 | 
|  | : (framer_.transport_version() > QUIC_VERSION_44 | 
|  | ? packet46 | 
|  | : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 | 
|  | : packet)); | 
|  | std::unique_ptr<QuicEncryptedPacket> encrypted( | 
|  | AssemblePacketFromFragments(fragments)); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); | 
|  |  | 
|  | EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_TRUE(CheckDecryption( | 
|  | *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, | 
|  | PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); | 
|  |  | 
|  | if (framer_.transport_version() == QUIC_VERSION_99) { | 
|  | EXPECT_EQ(kStreamOffset, visitor_.blocked_frame_.offset); | 
|  | } else { | 
|  | EXPECT_EQ(0u, visitor_.blocked_frame_.offset); | 
|  | } | 
|  | EXPECT_EQ(kStreamId, visitor_.blocked_frame_.stream_id); | 
|  |  | 
|  | if (framer_.transport_version() == QUIC_VERSION_99) { | 
|  | CheckFramingBoundaries(fragments, QUIC_INVALID_STREAM_BLOCKED_DATA); | 
|  | } else { | 
|  | CheckFramingBoundaries(fragments, QUIC_INVALID_BLOCKED_DATA); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, PingFrame) { | 
|  | // clang-format off | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x28, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (ping frame) | 
|  | 0x07, | 
|  | }; | 
|  |  | 
|  | unsigned char packet44[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x32, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type | 
|  | 0x07, | 
|  | }; | 
|  |  | 
|  | unsigned char packet46[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type | 
|  | 0x07, | 
|  | }; | 
|  |  | 
|  | unsigned char packet99[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (IETF_PING frame) | 
|  | 0x01, | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | QuicEncryptedPacket encrypted( | 
|  | AsChars(framer_.transport_version() == QUIC_VERSION_99 | 
|  | ? packet99 | 
|  | : (framer_.transport_version() > QUIC_VERSION_44 | 
|  | ? packet46 | 
|  | : framer_.transport_version() > QUIC_VERSION_43 | 
|  | ? packet44 | 
|  | : packet)), | 
|  | framer_.transport_version() == QUIC_VERSION_99 | 
|  | ? QUIC_ARRAYSIZE(packet99) | 
|  | : (framer_.transport_version() > QUIC_VERSION_44 | 
|  | ? QUIC_ARRAYSIZE(packet46) | 
|  | : framer_.transport_version() > QUIC_VERSION_43 | 
|  | ? QUIC_ARRAYSIZE(packet44) | 
|  | : QUIC_ARRAYSIZE(packet)), | 
|  | false); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(encrypted)); | 
|  |  | 
|  | EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_TRUE(CheckDecryption( | 
|  | encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, | 
|  | PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); | 
|  |  | 
|  | EXPECT_EQ(1u, visitor_.ping_frames_.size()); | 
|  |  | 
|  | // No need to check the PING frame boundaries because it has no payload. | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, MessageFrame) { | 
|  | if (framer_.transport_version() <= QUIC_VERSION_44) { | 
|  | return; | 
|  | } | 
|  | // clang-format off | 
|  | PacketFragments packet45 = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x32}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | // message frame type. | 
|  | {"", | 
|  | { 0x21 }}, | 
|  | // message length | 
|  | {"Unable to read message length", | 
|  | {0x07}}, | 
|  | // message data | 
|  | {"Unable to read message data", | 
|  | {'m', 'e', 's', 's', 'a', 'g', 'e'}}, | 
|  | // message frame no length. | 
|  | {"", | 
|  | { 0x20 }}, | 
|  | // message data | 
|  | {{}, | 
|  | {'m', 'e', 's', 's', 'a', 'g', 'e', '2'}}, | 
|  | }; | 
|  |  | 
|  | PacketFragments packet46 = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | // message frame type. | 
|  | {"", | 
|  | { 0x21 }}, | 
|  | // message length | 
|  | {"Unable to read message length", | 
|  | {0x07}}, | 
|  | // message data | 
|  | {"Unable to read message data", | 
|  | {'m', 'e', 's', 's', 'a', 'g', 'e'}}, | 
|  | // message frame no length. | 
|  | {"", | 
|  | { 0x20 }}, | 
|  | // message data | 
|  | {{}, | 
|  | {'m', 'e', 's', 's', 'a', 'g', 'e', '2'}}, | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | std::unique_ptr<QuicEncryptedPacket> encrypted(AssemblePacketFromFragments( | 
|  | framer_.transport_version() > QUIC_VERSION_44 ? packet46 : packet45)); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); | 
|  |  | 
|  | EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_TRUE(CheckDecryption( | 
|  | *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, | 
|  | PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); | 
|  |  | 
|  | ASSERT_EQ(2u, visitor_.message_frames_.size()); | 
|  | EXPECT_EQ(7u, visitor_.message_frames_[0]->message_length); | 
|  | EXPECT_EQ(8u, visitor_.message_frames_[1]->message_length); | 
|  |  | 
|  | CheckFramingBoundaries( | 
|  | framer_.transport_version() > QUIC_VERSION_44 ? packet46 : packet45, | 
|  | QUIC_INVALID_MESSAGE_DATA); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, PublicResetPacketV33) { | 
|  | // clang-format off | 
|  | PacketFragments packet = { | 
|  | // public flags (public reset, 8 byte connection_id) | 
|  | {"", | 
|  | {0x0A}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | {"Unable to read reset message.", | 
|  | { | 
|  | // message tag (kPRST) | 
|  | 'P', 'R', 'S', 'T', | 
|  | // num_entries (2) + padding | 
|  | 0x02, 0x00, 0x00, 0x00, | 
|  | // tag kRNON | 
|  | 'R', 'N', 'O', 'N', | 
|  | // end offset 8 | 
|  | 0x08, 0x00, 0x00, 0x00, | 
|  | // tag kRSEQ | 
|  | 'R', 'S', 'E', 'Q', | 
|  | // end offset 16 | 
|  | 0x10, 0x00, 0x00, 0x00, | 
|  | // nonce proof | 
|  | 0x89, 0x67, 0x45, 0x23, | 
|  | 0x01, 0xEF, 0xCD, 0xAB, | 
|  | // rejected packet number | 
|  | 0xBC, 0x9A, 0x78, 0x56, | 
|  | 0x34, 0x12, 0x00, 0x00, | 
|  | } | 
|  | } | 
|  | }; | 
|  | // clang-format on | 
|  | if (framer_.transport_version() > QUIC_VERSION_43) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | std::unique_ptr<QuicEncryptedPacket> encrypted( | 
|  | AssemblePacketFromFragments(packet)); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); | 
|  | ASSERT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.public_reset_packet_.get()); | 
|  | EXPECT_EQ(FramerTestConnectionId(), | 
|  | visitor_.public_reset_packet_->connection_id); | 
|  | EXPECT_EQ(kNonceProof, visitor_.public_reset_packet_->nonce_proof); | 
|  | EXPECT_EQ( | 
|  | IpAddressFamily::IP_UNSPEC, | 
|  | visitor_.public_reset_packet_->client_address.host().address_family()); | 
|  |  | 
|  | CheckFramingBoundaries(packet, QUIC_INVALID_PUBLIC_RST_PACKET); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, PublicResetPacket) { | 
|  | QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); | 
|  |  | 
|  | // clang-format off | 
|  | PacketFragments packet = { | 
|  | // public flags (public reset, 8 byte connection_id) | 
|  | {"", | 
|  | {0x0E}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | {"Unable to read reset message.", | 
|  | { | 
|  | // message tag (kPRST) | 
|  | 'P', 'R', 'S', 'T', | 
|  | // num_entries (2) + padding | 
|  | 0x02, 0x00, 0x00, 0x00, | 
|  | // tag kRNON | 
|  | 'R', 'N', 'O', 'N', | 
|  | // end offset 8 | 
|  | 0x08, 0x00, 0x00, 0x00, | 
|  | // tag kRSEQ | 
|  | 'R', 'S', 'E', 'Q', | 
|  | // end offset 16 | 
|  | 0x10, 0x00, 0x00, 0x00, | 
|  | // nonce proof | 
|  | 0x89, 0x67, 0x45, 0x23, | 
|  | 0x01, 0xEF, 0xCD, 0xAB, | 
|  | // rejected packet number | 
|  | 0xBC, 0x9A, 0x78, 0x56, | 
|  | 0x34, 0x12, 0x00, 0x00, | 
|  | } | 
|  | } | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | if (framer_.transport_version() > QUIC_VERSION_43) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | std::unique_ptr<QuicEncryptedPacket> encrypted( | 
|  | AssemblePacketFromFragments(packet)); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); | 
|  | ASSERT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.public_reset_packet_.get()); | 
|  | EXPECT_EQ(FramerTestConnectionId(), | 
|  | visitor_.public_reset_packet_->connection_id); | 
|  | EXPECT_EQ(kNonceProof, visitor_.public_reset_packet_->nonce_proof); | 
|  | EXPECT_EQ( | 
|  | IpAddressFamily::IP_UNSPEC, | 
|  | visitor_.public_reset_packet_->client_address.host().address_family()); | 
|  |  | 
|  | CheckFramingBoundaries(packet, QUIC_INVALID_PUBLIC_RST_PACKET); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, PublicResetPacketWithTrailingJunk) { | 
|  | // clang-format off | 
|  | unsigned char packet[] = { | 
|  | // public flags (public reset, 8 byte connection_id) | 
|  | 0x0A, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // message tag (kPRST) | 
|  | 'P', 'R', 'S', 'T', | 
|  | // num_entries (2) + padding | 
|  | 0x02, 0x00, 0x00, 0x00, | 
|  | // tag kRNON | 
|  | 'R', 'N', 'O', 'N', | 
|  | // end offset 8 | 
|  | 0x08, 0x00, 0x00, 0x00, | 
|  | // tag kRSEQ | 
|  | 'R', 'S', 'E', 'Q', | 
|  | // end offset 16 | 
|  | 0x10, 0x00, 0x00, 0x00, | 
|  | // nonce proof | 
|  | 0x89, 0x67, 0x45, 0x23, | 
|  | 0x01, 0xEF, 0xCD, 0xAB, | 
|  | // rejected packet number | 
|  | 0xBC, 0x9A, 0x78, 0x56, | 
|  | 0x34, 0x12, 0x00, 0x00, | 
|  | // trailing junk | 
|  | 'j', 'u', 'n', 'k', | 
|  | }; | 
|  | // clang-format on | 
|  | if (framer_.transport_version() > QUIC_VERSION_43) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | QuicEncryptedPacket encrypted(AsChars(packet), QUIC_ARRAYSIZE(packet), false); | 
|  | EXPECT_FALSE(framer_.ProcessPacket(encrypted)); | 
|  | ASSERT_EQ(QUIC_INVALID_PUBLIC_RST_PACKET, framer_.error()); | 
|  | EXPECT_EQ("Unable to read reset message.", framer_.detailed_error()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, PublicResetPacketWithClientAddress) { | 
|  | // clang-format off | 
|  | PacketFragments packet = { | 
|  | // public flags (public reset, 8 byte connection_id) | 
|  | {"", | 
|  | {0x0A}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | {"Unable to read reset message.", | 
|  | { | 
|  | // message tag (kPRST) | 
|  | 'P', 'R', 'S', 'T', | 
|  | // num_entries (2) + padding | 
|  | 0x03, 0x00, 0x00, 0x00, | 
|  | // tag kRNON | 
|  | 'R', 'N', 'O', 'N', | 
|  | // end offset 8 | 
|  | 0x08, 0x00, 0x00, 0x00, | 
|  | // tag kRSEQ | 
|  | 'R', 'S', 'E', 'Q', | 
|  | // end offset 16 | 
|  | 0x10, 0x00, 0x00, 0x00, | 
|  | // tag kCADR | 
|  | 'C', 'A', 'D', 'R', | 
|  | // end offset 24 | 
|  | 0x18, 0x00, 0x00, 0x00, | 
|  | // nonce proof | 
|  | 0x89, 0x67, 0x45, 0x23, | 
|  | 0x01, 0xEF, 0xCD, 0xAB, | 
|  | // rejected packet number | 
|  | 0xBC, 0x9A, 0x78, 0x56, | 
|  | 0x34, 0x12, 0x00, 0x00, | 
|  | // client address: 4.31.198.44:443 | 
|  | 0x02, 0x00, | 
|  | 0x04, 0x1F, 0xC6, 0x2C, | 
|  | 0xBB, 0x01, | 
|  | } | 
|  | } | 
|  | }; | 
|  | // clang-format on | 
|  | if (framer_.transport_version() > QUIC_VERSION_43) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | std::unique_ptr<QuicEncryptedPacket> encrypted( | 
|  | AssemblePacketFromFragments(packet)); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); | 
|  | ASSERT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.public_reset_packet_.get()); | 
|  | EXPECT_EQ(FramerTestConnectionId(), | 
|  | visitor_.public_reset_packet_->connection_id); | 
|  | EXPECT_EQ(kNonceProof, visitor_.public_reset_packet_->nonce_proof); | 
|  | EXPECT_EQ("4.31.198.44", | 
|  | visitor_.public_reset_packet_->client_address.host().ToString()); | 
|  | EXPECT_EQ(443, visitor_.public_reset_packet_->client_address.port()); | 
|  |  | 
|  | CheckFramingBoundaries(packet, QUIC_INVALID_PUBLIC_RST_PACKET); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, IetfStatelessResetPacket) { | 
|  | // clang-format off | 
|  | unsigned char packet[] = { | 
|  | // type (short packet, 1 byte packet number) | 
|  | 0x50, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // Random bytes | 
|  | 0x01, 0x11, 0x02, 0x22, 0x03, 0x33, 0x04, 0x44, | 
|  | 0x01, 0x11, 0x02, 0x22, 0x03, 0x33, 0x04, 0x44, | 
|  | 0x01, 0x11, 0x02, 0x22, 0x03, 0x33, 0x04, 0x44, | 
|  | 0x01, 0x11, 0x02, 0x22, 0x03, 0x33, 0x04, 0x44, | 
|  | // stateless reset token | 
|  | 0xB5, 0x69, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, | 
|  | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 
|  | }; | 
|  | // clang-format on | 
|  | if (framer_.transport_version() <= QUIC_VERSION_43) { | 
|  | return; | 
|  | } | 
|  | QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); | 
|  | framer_.SetDecrypter(ENCRYPTION_INITIAL, | 
|  | QuicMakeUnique<NullDecrypter>(Perspective::IS_CLIENT)); | 
|  | decrypter_ = new test::TestDecrypter(); | 
|  | framer_.SetAlternativeDecrypter( | 
|  | ENCRYPTION_ZERO_RTT, std::unique_ptr<QuicDecrypter>(decrypter_), false); | 
|  | // This packet cannot be decrypted because diversification nonce is missing. | 
|  | QuicEncryptedPacket encrypted(AsChars(packet), QUIC_ARRAYSIZE(packet), false); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(encrypted)); | 
|  | ASSERT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.stateless_reset_packet_.get()); | 
|  | EXPECT_EQ(kTestStatelessResetToken, | 
|  | visitor_.stateless_reset_packet_->stateless_reset_token); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, IetfStatelessResetPacketInvalidStatelessResetToken) { | 
|  | // clang-format off | 
|  | unsigned char packet[] = { | 
|  | // type (short packet, 1 byte packet number) | 
|  | 0x50, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // stateless reset token | 
|  | 0xB6, 0x69, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, | 
|  | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 
|  | }; | 
|  | // clang-format on | 
|  | if (framer_.transport_version() <= QUIC_VERSION_43) { | 
|  | return; | 
|  | } | 
|  | QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); | 
|  | framer_.SetDecrypter(ENCRYPTION_INITIAL, | 
|  | QuicMakeUnique<NullDecrypter>(Perspective::IS_CLIENT)); | 
|  | decrypter_ = new test::TestDecrypter(); | 
|  | framer_.SetAlternativeDecrypter( | 
|  | ENCRYPTION_ZERO_RTT, std::unique_ptr<QuicDecrypter>(decrypter_), false); | 
|  | // This packet cannot be decrypted because diversification nonce is missing. | 
|  | QuicEncryptedPacket encrypted(AsChars(packet), QUIC_ARRAYSIZE(packet), false); | 
|  | EXPECT_FALSE(framer_.ProcessPacket(encrypted)); | 
|  | EXPECT_EQ(QUIC_DECRYPTION_FAILURE, framer_.error()); | 
|  | ASSERT_FALSE(visitor_.stateless_reset_packet_); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, VersionNegotiationPacket) { | 
|  | // clang-format off | 
|  | PacketFragments packet = { | 
|  | // public flags (version, 8 byte connection_id) | 
|  | {"", | 
|  | {0x29}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // version tag | 
|  | {"Unable to read supported version in negotiation.", | 
|  | {QUIC_VERSION_BYTES, | 
|  | 'Q', '2', '.', '0'}}, | 
|  | }; | 
|  |  | 
|  | PacketFragments packet44 = { | 
|  | // type (long header) | 
|  | {"", | 
|  | {0x8F}}, | 
|  | // version tag | 
|  | {"", | 
|  | {0x00, 0x00, 0x00, 0x00}}, | 
|  | {"", | 
|  | {0x05}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // Supported versions | 
|  | {"Unable to read supported version in negotiation.", | 
|  | {QUIC_VERSION_BYTES, | 
|  | 'Q', '2', '.', '0'}}, | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); | 
|  |  | 
|  | PacketFragments& fragments = | 
|  | framer_.transport_version() > QUIC_VERSION_43 ? packet44 : packet; | 
|  | std::unique_ptr<QuicEncryptedPacket> encrypted( | 
|  | AssemblePacketFromFragments(fragments)); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); | 
|  | ASSERT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.version_negotiation_packet_.get()); | 
|  | EXPECT_EQ(2u, visitor_.version_negotiation_packet_->versions.size()); | 
|  | EXPECT_EQ(GetParam(), visitor_.version_negotiation_packet_->versions[0]); | 
|  |  | 
|  | // Remove the last version from the packet so that every truncated | 
|  | // version of the packet is invalid, otherwise checking boundaries | 
|  | // is annoyingly complicated. | 
|  | for (size_t i = 0; i < 4; ++i) { | 
|  | fragments.back().fragment.pop_back(); | 
|  | } | 
|  | CheckFramingBoundaries(fragments, QUIC_INVALID_VERSION_NEGOTIATION_PACKET); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, OldVersionNegotiationPacket) { | 
|  | // clang-format off | 
|  | PacketFragments packet = { | 
|  | // public flags (version, 8 byte connection_id) | 
|  | {"", | 
|  | {0x2D}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // version tag | 
|  | {"Unable to read supported version in negotiation.", | 
|  | {QUIC_VERSION_BYTES, | 
|  | 'Q', '2', '.', '0'}}, | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | if (framer_.transport_version() > QUIC_VERSION_43) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); | 
|  |  | 
|  | std::unique_ptr<QuicEncryptedPacket> encrypted( | 
|  | AssemblePacketFromFragments(packet)); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); | 
|  | ASSERT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.version_negotiation_packet_.get()); | 
|  | EXPECT_EQ(2u, visitor_.version_negotiation_packet_->versions.size()); | 
|  | EXPECT_EQ(GetParam(), visitor_.version_negotiation_packet_->versions[0]); | 
|  |  | 
|  | // Remove the last version from the packet so that every truncated | 
|  | // version of the packet is invalid, otherwise checking boundaries | 
|  | // is annoyingly complicated. | 
|  | for (size_t i = 0; i < 4; ++i) { | 
|  | packet.back().fragment.pop_back(); | 
|  | } | 
|  | CheckFramingBoundaries(packet, QUIC_INVALID_VERSION_NEGOTIATION_PACKET); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, BuildPaddingFramePacket) { | 
|  | QuicPacketHeader header; | 
|  | header.destination_connection_id = FramerTestConnectionId(); | 
|  | header.reset_flag = false; | 
|  | header.version_flag = false; | 
|  | header.packet_number = kPacketNumber; | 
|  |  | 
|  | QuicFrames frames = {QuicFrame(QuicPaddingFrame())}; | 
|  |  | 
|  | // clang-format off | 
|  | unsigned char packet[kMaxPacketSize] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x28, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (padding frame) | 
|  | 0x00, | 
|  | 0x00, 0x00, 0x00, 0x00 | 
|  | }; | 
|  |  | 
|  | unsigned char packet44[kMaxPacketSize] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x32, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (padding frame) | 
|  | 0x00, | 
|  | 0x00, 0x00, 0x00, 0x00 | 
|  | }; | 
|  |  | 
|  | unsigned char packet46[kMaxPacketSize] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (padding frame) | 
|  | 0x00, | 
|  | 0x00, 0x00, 0x00, 0x00 | 
|  | }; | 
|  |  | 
|  | unsigned char packet99[kMaxPacketSize] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (padding frame) | 
|  | 0x00, | 
|  | 0x00, 0x00, 0x00, 0x00 | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | unsigned char* p = packet; | 
|  | if (framer_.transport_version() == QUIC_VERSION_99) { | 
|  | p = packet99; | 
|  | } else if (framer_.transport_version() > QUIC_VERSION_44) { | 
|  | p = packet46; | 
|  | } else if (framer_.transport_version() > QUIC_VERSION_43) { | 
|  | p = packet44; | 
|  | } | 
|  |  | 
|  | uint64_t header_size = GetPacketHeaderSize( | 
|  | framer_.transport_version(), PACKET_8BYTE_CONNECTION_ID, | 
|  | PACKET_0BYTE_CONNECTION_ID, !kIncludeVersion, | 
|  | !kIncludeDiversificationNonce, PACKET_4BYTE_PACKET_NUMBER, | 
|  | VARIABLE_LENGTH_INTEGER_LENGTH_0, 0, VARIABLE_LENGTH_INTEGER_LENGTH_0); | 
|  | memset(p + header_size + 1, 0x00, kMaxPacketSize - header_size - 1); | 
|  |  | 
|  | std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  |  | 
|  | test::CompareCharArraysWithHexError( | 
|  | "constructed packet", data->data(), data->length(), AsChars(p), | 
|  | framer_.transport_version() > QUIC_VERSION_43 ? QUIC_ARRAYSIZE(packet44) | 
|  | : QUIC_ARRAYSIZE(packet)); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, BuildStreamFramePacketWithNewPaddingFrame) { | 
|  | QuicPacketHeader header; | 
|  | header.destination_connection_id = FramerTestConnectionId(); | 
|  | header.reset_flag = false; | 
|  | header.version_flag = false; | 
|  | header.packet_number = kPacketNumber; | 
|  | QuicStreamFrame stream_frame(kStreamId, true, kStreamOffset, | 
|  | QuicStringPiece("hello world!")); | 
|  | QuicPaddingFrame padding_frame(2); | 
|  | QuicFrames frames = {QuicFrame(padding_frame), QuicFrame(stream_frame), | 
|  | QuicFrame(padding_frame)}; | 
|  |  | 
|  | // clang-format off | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x28, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // paddings | 
|  | 0x00, 0x00, | 
|  | // frame type (stream frame with fin) | 
|  | 0xFF, | 
|  | // stream id | 
|  | 0x01, 0x02, 0x03, 0x04, | 
|  | // offset | 
|  | 0x3A, 0x98, 0xFE, 0xDC, | 
|  | 0x32, 0x10, 0x76, 0x54, | 
|  | // data length | 
|  | 0x00, 0x0c, | 
|  | // data | 
|  | 'h',  'e',  'l',  'l', | 
|  | 'o',  ' ',  'w',  'o', | 
|  | 'r',  'l',  'd',  '!', | 
|  | // paddings | 
|  | 0x00, 0x00, | 
|  | }; | 
|  |  | 
|  | unsigned char packet44[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x32, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // paddings | 
|  | 0x00, 0x00, | 
|  | // frame type (stream frame with fin) | 
|  | 0xFF, | 
|  | // stream id | 
|  | 0x01, 0x02, 0x03, 0x04, | 
|  | // offset | 
|  | 0x3A, 0x98, 0xFE, 0xDC, | 
|  | 0x32, 0x10, 0x76, 0x54, | 
|  | // data length | 
|  | 0x00, 0x0c, | 
|  | // data | 
|  | 'h',  'e',  'l',  'l', | 
|  | 'o',  ' ',  'w',  'o', | 
|  | 'r',  'l',  'd',  '!', | 
|  | // paddings | 
|  | 0x00, 0x00, | 
|  | }; | 
|  |  | 
|  | unsigned char packet46[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // paddings | 
|  | 0x00, 0x00, | 
|  | // frame type (stream frame with fin) | 
|  | 0xFF, | 
|  | // stream id | 
|  | 0x01, 0x02, 0x03, 0x04, | 
|  | // offset | 
|  | 0x3A, 0x98, 0xFE, 0xDC, | 
|  | 0x32, 0x10, 0x76, 0x54, | 
|  | // data length | 
|  | 0x00, 0x0c, | 
|  | // data | 
|  | 'h',  'e',  'l',  'l', | 
|  | 'o',  ' ',  'w',  'o', | 
|  | 'r',  'l',  'd',  '!', | 
|  | // paddings | 
|  | 0x00, 0x00, | 
|  | }; | 
|  |  | 
|  | unsigned char packet99[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // paddings | 
|  | 0x00, 0x00, | 
|  | // frame type (IETF_STREAM with FIN, LEN, and OFFSET bits set) | 
|  | 0x08 | 0x01 | 0x02 | 0x04, | 
|  | // stream id | 
|  | kVarInt62FourBytes + 0x01, 0x02, 0x03, 0x04, | 
|  | // offset | 
|  | kVarInt62EightBytes + 0x3A, 0x98, 0xFE, 0xDC, | 
|  | 0x32, 0x10, 0x76, 0x54, | 
|  | // data length | 
|  | kVarInt62OneByte + 0x0c, | 
|  | // data | 
|  | 'h',  'e',  'l',  'l', | 
|  | 'o',  ' ',  'w',  'o', | 
|  | 'r',  'l',  'd',  '!', | 
|  | // paddings | 
|  | 0x00, 0x00, | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  |  | 
|  | unsigned char* p = packet; | 
|  | size_t p_size = QUIC_ARRAYSIZE(packet); | 
|  | if (framer_.transport_version() == QUIC_VERSION_99) { | 
|  | p = packet99; | 
|  | p_size = QUIC_ARRAYSIZE(packet99); | 
|  | } else if (framer_.transport_version() > QUIC_VERSION_44) { | 
|  | p = packet46; | 
|  | p_size = QUIC_ARRAYSIZE(packet46); | 
|  | } else if (framer_.transport_version() > QUIC_VERSION_43) { | 
|  | p = packet44; | 
|  | p_size = QUIC_ARRAYSIZE(packet44); | 
|  | } | 
|  | QuicEncryptedPacket encrypted(AsChars(p), p_size, false); | 
|  |  | 
|  | test::CompareCharArraysWithHexError("constructed packet", data->data(), | 
|  | data->length(), AsChars(p), p_size); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, Build4ByteSequenceNumberPaddingFramePacket) { | 
|  | QuicPacketHeader header; | 
|  | header.destination_connection_id = FramerTestConnectionId(); | 
|  | header.reset_flag = false; | 
|  | header.version_flag = false; | 
|  | header.packet_number_length = PACKET_4BYTE_PACKET_NUMBER; | 
|  | header.packet_number = kPacketNumber; | 
|  |  | 
|  | QuicFrames frames = {QuicFrame(QuicPaddingFrame())}; | 
|  |  | 
|  | // clang-format off | 
|  | unsigned char packet[kMaxPacketSize] = { | 
|  | // public flags (8 byte connection_id and 4 byte packet number) | 
|  | 0x28, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (padding frame) | 
|  | 0x00, | 
|  | 0x00, 0x00, 0x00, 0x00 | 
|  | }; | 
|  |  | 
|  | unsigned char packet44[kMaxPacketSize] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x32, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (padding frame) | 
|  | 0x00, | 
|  | 0x00, 0x00, 0x00, 0x00 | 
|  | }; | 
|  |  | 
|  | unsigned char packet46[kMaxPacketSize] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (padding frame) | 
|  | 0x00, | 
|  | 0x00, 0x00, 0x00, 0x00 | 
|  | }; | 
|  |  | 
|  | unsigned char packet99[kMaxPacketSize] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (padding frame) | 
|  | 0x00, | 
|  | 0x00, 0x00, 0x00, 0x00 | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | unsigned char* p = packet; | 
|  | if (framer_.transport_version() == QUIC_VERSION_99) { | 
|  | p = packet99; | 
|  | } else if (framer_.transport_version() > QUIC_VERSION_44) { | 
|  | p = packet46; | 
|  | } else if (framer_.transport_version() > QUIC_VERSION_43) { | 
|  | p = packet44; | 
|  | } | 
|  |  | 
|  | uint64_t header_size = GetPacketHeaderSize( | 
|  | framer_.transport_version(), PACKET_8BYTE_CONNECTION_ID, | 
|  | PACKET_0BYTE_CONNECTION_ID, !kIncludeVersion, | 
|  | !kIncludeDiversificationNonce, PACKET_4BYTE_PACKET_NUMBER, | 
|  | VARIABLE_LENGTH_INTEGER_LENGTH_0, 0, VARIABLE_LENGTH_INTEGER_LENGTH_0); | 
|  | memset(p + header_size + 1, 0x00, kMaxPacketSize - header_size - 1); | 
|  |  | 
|  | std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  |  | 
|  | test::CompareCharArraysWithHexError( | 
|  | "constructed packet", data->data(), data->length(), AsChars(p), | 
|  | framer_.transport_version() > QUIC_VERSION_43 ? QUIC_ARRAYSIZE(packet44) | 
|  | : QUIC_ARRAYSIZE(packet)); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, Build2ByteSequenceNumberPaddingFramePacket) { | 
|  | QuicPacketHeader header; | 
|  | header.destination_connection_id = FramerTestConnectionId(); | 
|  | header.reset_flag = false; | 
|  | header.version_flag = false; | 
|  | header.packet_number_length = PACKET_2BYTE_PACKET_NUMBER; | 
|  | header.packet_number = kPacketNumber; | 
|  |  | 
|  | QuicFrames frames = {QuicFrame(QuicPaddingFrame())}; | 
|  |  | 
|  | // clang-format off | 
|  | unsigned char packet[kMaxPacketSize] = { | 
|  | // public flags (8 byte connection_id and 2 byte packet number) | 
|  | 0x18, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x56, 0x78, | 
|  |  | 
|  | // frame type (padding frame) | 
|  | 0x00, | 
|  | 0x00, 0x00, 0x00, 0x00 | 
|  | }; | 
|  |  | 
|  | unsigned char packet44[kMaxPacketSize] = { | 
|  | // type (short header, 2 byte packet number) | 
|  | 0x31, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x56, 0x78, | 
|  |  | 
|  | // frame type (padding frame) | 
|  | 0x00, | 
|  | 0x00, 0x00, 0x00, 0x00 | 
|  | }; | 
|  |  | 
|  | unsigned char packet46[kMaxPacketSize] = { | 
|  | // type (short header, 2 byte packet number) | 
|  | 0x41, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x56, 0x78, | 
|  |  | 
|  | // frame type (padding frame) | 
|  | 0x00, | 
|  | 0x00, 0x00, 0x00, 0x00 | 
|  | }; | 
|  |  | 
|  | unsigned char packet99[kMaxPacketSize] = { | 
|  | // type (short header, 2 byte packet number) | 
|  | 0x41, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x56, 0x78, | 
|  |  | 
|  | // frame type (padding frame) | 
|  | 0x00, | 
|  | 0x00, 0x00, 0x00, 0x00 | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | unsigned char* p = packet; | 
|  | if (framer_.transport_version() == QUIC_VERSION_99) { | 
|  | p = packet99; | 
|  | } else if (framer_.transport_version() > QUIC_VERSION_44) { | 
|  | p = packet46; | 
|  | } else if (framer_.transport_version() > QUIC_VERSION_43) { | 
|  | p = packet44; | 
|  | } | 
|  |  | 
|  | uint64_t header_size = GetPacketHeaderSize( | 
|  | framer_.transport_version(), PACKET_8BYTE_CONNECTION_ID, | 
|  | PACKET_0BYTE_CONNECTION_ID, !kIncludeVersion, | 
|  | !kIncludeDiversificationNonce, PACKET_2BYTE_PACKET_NUMBER, | 
|  | VARIABLE_LENGTH_INTEGER_LENGTH_0, 0, VARIABLE_LENGTH_INTEGER_LENGTH_0); | 
|  | memset(p + header_size + 1, 0x00, kMaxPacketSize - header_size - 1); | 
|  |  | 
|  | std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  |  | 
|  | test::CompareCharArraysWithHexError( | 
|  | "constructed packet", data->data(), data->length(), AsChars(p), | 
|  | framer_.transport_version() > QUIC_VERSION_43 ? QUIC_ARRAYSIZE(packet44) | 
|  | : QUIC_ARRAYSIZE(packet)); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, Build1ByteSequenceNumberPaddingFramePacket) { | 
|  | QuicPacketHeader header; | 
|  | header.destination_connection_id = FramerTestConnectionId(); | 
|  | header.reset_flag = false; | 
|  | header.version_flag = false; | 
|  | header.packet_number_length = PACKET_1BYTE_PACKET_NUMBER; | 
|  | header.packet_number = kPacketNumber; | 
|  |  | 
|  | QuicFrames frames = {QuicFrame(QuicPaddingFrame())}; | 
|  |  | 
|  | // clang-format off | 
|  | unsigned char packet[kMaxPacketSize] = { | 
|  | // public flags (8 byte connection_id and 1 byte packet number) | 
|  | 0x08, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x78, | 
|  |  | 
|  | // frame type (padding frame) | 
|  | 0x00, | 
|  | 0x00, 0x00, 0x00, 0x00 | 
|  | }; | 
|  |  | 
|  | unsigned char packet44[kMaxPacketSize] = { | 
|  | // type (short header, 1 byte packet number) | 
|  | 0x30, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x78, | 
|  |  | 
|  | // frame type (padding frame) | 
|  | 0x00, | 
|  | 0x00, 0x00, 0x00, 0x00 | 
|  | }; | 
|  |  | 
|  | unsigned char packet46[kMaxPacketSize] = { | 
|  | // type (short header, 1 byte packet number) | 
|  | 0x40, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x78, | 
|  |  | 
|  | // frame type (padding frame) | 
|  | 0x00, | 
|  | 0x00, 0x00, 0x00, 0x00 | 
|  | }; | 
|  |  | 
|  | unsigned char packet99[kMaxPacketSize] = { | 
|  | // type (short header, 1 byte packet number) | 
|  | 0x40, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x78, | 
|  |  | 
|  | // frame type (padding frame) | 
|  | 0x00, | 
|  | 0x00, 0x00, 0x00, 0x00 | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | unsigned char* p = packet; | 
|  | if (framer_.transport_version() == QUIC_VERSION_99) { | 
|  | p = packet99; | 
|  | } else if (framer_.transport_version() > QUIC_VERSION_44) { | 
|  | p = packet46; | 
|  | } else if (framer_.transport_version() > QUIC_VERSION_43) { | 
|  | p = packet44; | 
|  | } | 
|  |  | 
|  | uint64_t header_size = GetPacketHeaderSize( | 
|  | framer_.transport_version(), PACKET_8BYTE_CONNECTION_ID, | 
|  | PACKET_0BYTE_CONNECTION_ID, !kIncludeVersion, | 
|  | !kIncludeDiversificationNonce, PACKET_1BYTE_PACKET_NUMBER, | 
|  | VARIABLE_LENGTH_INTEGER_LENGTH_0, 0, VARIABLE_LENGTH_INTEGER_LENGTH_0); | 
|  | memset(p + header_size + 1, 0x00, kMaxPacketSize - header_size - 1); | 
|  |  | 
|  | std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  |  | 
|  | test::CompareCharArraysWithHexError( | 
|  | "constructed packet", data->data(), data->length(), AsChars(p), | 
|  | framer_.transport_version() > QUIC_VERSION_43 ? QUIC_ARRAYSIZE(packet44) | 
|  | : QUIC_ARRAYSIZE(packet)); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, BuildStreamFramePacket) { | 
|  | QuicPacketHeader header; | 
|  | header.destination_connection_id = FramerTestConnectionId(); | 
|  | header.reset_flag = false; | 
|  | header.version_flag = false; | 
|  | header.packet_number = kPacketNumber; | 
|  | if (QuicVersionHasLongHeaderLengths(framer_.transport_version())) { | 
|  | header.length_length = VARIABLE_LENGTH_INTEGER_LENGTH_2; | 
|  | } | 
|  |  | 
|  | QuicStreamFrame stream_frame(kStreamId, true, kStreamOffset, | 
|  | QuicStringPiece("hello world!")); | 
|  |  | 
|  | QuicFrames frames = {QuicFrame(stream_frame)}; | 
|  |  | 
|  | // clang-format off | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x28, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (stream frame with fin and no length) | 
|  | 0xDF, | 
|  | // stream id | 
|  | 0x01, 0x02, 0x03, 0x04, | 
|  | // offset | 
|  | 0x3A, 0x98, 0xFE, 0xDC, | 
|  | 0x32, 0x10, 0x76, 0x54, | 
|  | // data | 
|  | 'h',  'e',  'l',  'l', | 
|  | 'o',  ' ',  'w',  'o', | 
|  | 'r',  'l',  'd',  '!', | 
|  | }; | 
|  |  | 
|  | unsigned char packet44[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x32, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (stream frame with fin and no length) | 
|  | 0xDF, | 
|  | // stream id | 
|  | 0x01, 0x02, 0x03, 0x04, | 
|  | // offset | 
|  | 0x3A, 0x98, 0xFE, 0xDC, | 
|  | 0x32, 0x10, 0x76, 0x54, | 
|  | // data | 
|  | 'h',  'e',  'l',  'l', | 
|  | 'o',  ' ',  'w',  'o', | 
|  | 'r',  'l',  'd',  '!', | 
|  | }; | 
|  |  | 
|  | unsigned char packet46[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (stream frame with fin and no length) | 
|  | 0xDF, | 
|  | // stream id | 
|  | 0x01, 0x02, 0x03, 0x04, | 
|  | // offset | 
|  | 0x3A, 0x98, 0xFE, 0xDC, | 
|  | 0x32, 0x10, 0x76, 0x54, | 
|  | // data | 
|  | 'h',  'e',  'l',  'l', | 
|  | 'o',  ' ',  'w',  'o', | 
|  | 'r',  'l',  'd',  '!', | 
|  | }; | 
|  |  | 
|  | unsigned char packet99[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (IETF_STREAM frame with FIN and OFFSET, no length) | 
|  | 0x08 | 0x01 | 0x04, | 
|  | // stream id | 
|  | kVarInt62FourBytes + 0x01, 0x02, 0x03, 0x04, | 
|  | // offset | 
|  | kVarInt62EightBytes + 0x3A, 0x98, 0xFE, 0xDC, | 
|  | 0x32, 0x10, 0x76, 0x54, | 
|  | // data | 
|  | 'h',  'e',  'l',  'l', | 
|  | 'o',  ' ',  'w',  'o', | 
|  | 'r',  'l',  'd',  '!', | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  |  | 
|  | unsigned char* p = packet; | 
|  | size_t p_size = QUIC_ARRAYSIZE(packet); | 
|  | if (framer_.transport_version() == QUIC_VERSION_99) { | 
|  | p = packet99; | 
|  | p_size = QUIC_ARRAYSIZE(packet99); | 
|  | } else if (framer_.transport_version() > QUIC_VERSION_44) { | 
|  | p = packet46; | 
|  | p_size = QUIC_ARRAYSIZE(packet46); | 
|  | } else if (framer_.transport_version() > QUIC_VERSION_43) { | 
|  | p = packet44; | 
|  | p_size = QUIC_ARRAYSIZE(packet44); | 
|  | } | 
|  | test::CompareCharArraysWithHexError("constructed packet", data->data(), | 
|  | data->length(), AsChars(p), p_size); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, BuildStreamFramePacketWithVersionFlag) { | 
|  | QuicPacketHeader header; | 
|  | header.destination_connection_id = FramerTestConnectionId(); | 
|  | header.reset_flag = false; | 
|  | header.version_flag = true; | 
|  | if (framer_.transport_version() > QUIC_VERSION_43) { | 
|  | header.long_packet_type = ZERO_RTT_PROTECTED; | 
|  | } | 
|  | header.packet_number = kPacketNumber; | 
|  | if (QuicVersionHasLongHeaderLengths(framer_.transport_version())) { | 
|  | header.length_length = VARIABLE_LENGTH_INTEGER_LENGTH_2; | 
|  | } | 
|  |  | 
|  | QuicStreamFrame stream_frame(kStreamId, true, kStreamOffset, | 
|  | QuicStringPiece("hello world!")); | 
|  | QuicFrames frames = {QuicFrame(stream_frame)}; | 
|  |  | 
|  | // clang-format off | 
|  | unsigned char packet[] = { | 
|  | // public flags (version, 8 byte connection_id) | 
|  | 0x2D, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // version tag | 
|  | QUIC_VERSION_BYTES, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (stream frame with fin and no length) | 
|  | 0xDF, | 
|  | // stream id | 
|  | 0x01, 0x02, 0x03, 0x04, | 
|  | // offset | 
|  | 0x3A, 0x98, 0xFE, 0xDC, 0x32, 0x10, 0x76, 0x54, | 
|  | // data | 
|  | 'h',  'e',  'l',  'l',  'o',  ' ',  'w',  'o',  'r', 'l', 'd', '!', | 
|  | }; | 
|  |  | 
|  | unsigned char packet44[] = { | 
|  | // type (long header with packet type ZERO_RTT_PROTECTED) | 
|  | 0xFC, | 
|  | // version tag | 
|  | QUIC_VERSION_BYTES, | 
|  | // connection_id length | 
|  | 0x50, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (stream frame with fin and no length) | 
|  | 0xDF, | 
|  | // stream id | 
|  | 0x01, 0x02, 0x03, 0x04, | 
|  | // offset | 
|  | 0x3A, 0x98, 0xFE, 0xDC, 0x32, 0x10, 0x76, 0x54, | 
|  | // data | 
|  | 'h',  'e',  'l',  'l',  'o',  ' ',  'w',  'o',  'r', 'l', 'd', '!', | 
|  | }; | 
|  |  | 
|  | unsigned char packet46[] = { | 
|  | // type (long header with packet type ZERO_RTT_PROTECTED) | 
|  | 0xD3, | 
|  | // version tag | 
|  | QUIC_VERSION_BYTES, | 
|  | // connection_id length | 
|  | 0x50, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (stream frame with fin and no length) | 
|  | 0xDF, | 
|  | // stream id | 
|  | 0x01, 0x02, 0x03, 0x04, | 
|  | // offset | 
|  | 0x3A, 0x98, 0xFE, 0xDC, 0x32, 0x10, 0x76, 0x54, | 
|  | // data | 
|  | 'h',  'e',  'l',  'l',  'o',  ' ',  'w',  'o',  'r', 'l', 'd', '!', | 
|  | }; | 
|  |  | 
|  | unsigned char packet99[] = { | 
|  | // type (long header with packet type ZERO_RTT_PROTECTED) | 
|  | 0xD3, | 
|  | // version tag | 
|  | QUIC_VERSION_BYTES, | 
|  | // connection_id length | 
|  | 0x50, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // length | 
|  | 0x40, 0x1D, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (IETF_STREAM frame with fin and offset, no length) | 
|  | 0x08 | 0x01 | 0x04, | 
|  | // stream id | 
|  | kVarInt62FourBytes + 0x01, 0x02, 0x03, 0x04, | 
|  | // offset | 
|  | kVarInt62EightBytes + 0x3A, 0x98, 0xFE, 0xDC, 0x32, 0x10, 0x76, 0x54, | 
|  | // data | 
|  | 'h',  'e',  'l',  'l',  'o',  ' ',  'w',  'o',  'r', 'l', 'd', '!', | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); | 
|  | std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  |  | 
|  | unsigned char* p = packet; | 
|  | size_t p_size = QUIC_ARRAYSIZE(packet); | 
|  | if (framer_.transport_version() == QUIC_VERSION_99) { | 
|  | p = packet99; | 
|  | p_size = QUIC_ARRAYSIZE(packet99); | 
|  | } else if (framer_.transport_version() > QUIC_VERSION_44) { | 
|  | p = packet46; | 
|  | p_size = QUIC_ARRAYSIZE(packet46); | 
|  | } else if (framer_.transport_version() > QUIC_VERSION_43) { | 
|  | p = packet44; | 
|  | p_size = QUIC_ARRAYSIZE(packet44); | 
|  | } | 
|  | test::CompareCharArraysWithHexError("constructed packet", data->data(), | 
|  | data->length(), AsChars(p), p_size); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, BuildCryptoFramePacket) { | 
|  | if (framer_.transport_version() < QUIC_VERSION_99) { | 
|  | // CRYPTO frames aren't supported prior to v46. | 
|  | return; | 
|  | } | 
|  | QuicPacketHeader header; | 
|  | header.destination_connection_id = FramerTestConnectionId(); | 
|  | header.reset_flag = false; | 
|  | header.version_flag = false; | 
|  | header.packet_number = kPacketNumber; | 
|  |  | 
|  | SimpleDataProducer data_producer; | 
|  | framer_.set_data_producer(&data_producer); | 
|  |  | 
|  | QuicStringPiece crypto_frame_contents("hello world!"); | 
|  | QuicCryptoFrame crypto_frame(ENCRYPTION_INITIAL, kStreamOffset, | 
|  | crypto_frame_contents.length()); | 
|  | data_producer.SaveCryptoData(ENCRYPTION_INITIAL, kStreamOffset, | 
|  | crypto_frame_contents); | 
|  |  | 
|  | QuicFrames frames = {QuicFrame(&crypto_frame)}; | 
|  |  | 
|  | // clang-format off | 
|  | unsigned char packet[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (IETF_CRYPTO frame) | 
|  | 0x06, | 
|  | // offset | 
|  | kVarInt62EightBytes + 0x3A, 0x98, 0xFE, 0xDC, | 
|  | 0x32, 0x10, 0x76, 0x54, | 
|  | // length | 
|  | kVarInt62OneByte + 12, | 
|  | // data | 
|  | 'h',  'e',  'l',  'l', | 
|  | 'o',  ' ',  'w',  'o', | 
|  | 'r',  'l',  'd',  '!', | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | size_t packet_size = QUIC_ARRAYSIZE(packet); | 
|  |  | 
|  | std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  | test::CompareCharArraysWithHexError("constructed packet", data->data(), | 
|  | data->length(), AsChars(packet), | 
|  | packet_size); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, CryptoFrame) { | 
|  | if (framer_.transport_version() < QUIC_VERSION_99) { | 
|  | // CRYPTO frames aren't supported prior to v46. | 
|  | return; | 
|  | } | 
|  |  | 
|  | // clang-format off | 
|  | PacketFragments packet = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | // frame type (IETF_CRYPTO frame) | 
|  | {"", | 
|  | {0x06}}, | 
|  | // offset | 
|  | {"", | 
|  | {kVarInt62EightBytes + 0x3A, 0x98, 0xFE, 0xDC, | 
|  | 0x32, 0x10, 0x76, 0x54}}, | 
|  | // data length | 
|  | {"Invalid data length.", | 
|  | {kVarInt62OneByte + 12}}, | 
|  | // data | 
|  | {"Unable to read frame data.", | 
|  | {'h',  'e',  'l',  'l', | 
|  | 'o',  ' ',  'w',  'o', | 
|  | 'r',  'l',  'd',  '!'}}, | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | std::unique_ptr<QuicEncryptedPacket> encrypted( | 
|  | AssemblePacketFromFragments(packet)); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); | 
|  |  | 
|  | EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_TRUE(CheckDecryption( | 
|  | *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, | 
|  | PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); | 
|  | ASSERT_EQ(1u, visitor_.crypto_frames_.size()); | 
|  | QuicCryptoFrame* frame = visitor_.crypto_frames_[0].get(); | 
|  | EXPECT_EQ(kStreamOffset, frame->offset); | 
|  | EXPECT_EQ("hello world!", | 
|  | std::string(frame->data_buffer, frame->data_length)); | 
|  |  | 
|  | CheckFramingBoundaries(packet, QUIC_INVALID_FRAME_DATA); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, BuildVersionNegotiationPacket) { | 
|  | // clang-format off | 
|  | unsigned char packet[] = { | 
|  | // public flags (version, 8 byte connection_id) | 
|  | 0x0D, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // version tag | 
|  | QUIC_VERSION_BYTES, | 
|  | }; | 
|  | unsigned char packet44[] = { | 
|  | // type (long header) | 
|  | 0x80, | 
|  | // version tag | 
|  | 0x00, 0x00, 0x00, 0x00, | 
|  | // connection_id length | 
|  | 0x05, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // version tag | 
|  | QUIC_VERSION_BYTES, | 
|  | }; | 
|  | // clang-format on | 
|  | unsigned char* p = packet; | 
|  | size_t p_size = QUIC_ARRAYSIZE(packet); | 
|  | if (framer_.transport_version() > QUIC_VERSION_43) { | 
|  | p = packet44; | 
|  | p_size = QUIC_ARRAYSIZE(packet44); | 
|  | } | 
|  |  | 
|  | QuicConnectionId connection_id = FramerTestConnectionId(); | 
|  | std::unique_ptr<QuicEncryptedPacket> data( | 
|  | framer_.BuildVersionNegotiationPacket( | 
|  | connection_id, framer_.transport_version() > QUIC_VERSION_43, | 
|  | SupportedVersions(GetParam()))); | 
|  | test::CompareCharArraysWithHexError("constructed packet", data->data(), | 
|  | data->length(), AsChars(p), p_size); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, BuildAckFramePacketOneAckBlock) { | 
|  | QuicPacketHeader header; | 
|  | header.destination_connection_id = FramerTestConnectionId(); | 
|  | header.reset_flag = false; | 
|  | header.version_flag = false; | 
|  | header.packet_number = kPacketNumber; | 
|  |  | 
|  | // Use kSmallLargestObserved to make this test finished in a short time. | 
|  | QuicAckFrame ack_frame = InitAckFrame(kSmallLargestObserved); | 
|  | ack_frame.ack_delay_time = QuicTime::Delta::Zero(); | 
|  |  | 
|  | QuicFrames frames = {QuicFrame(&ack_frame)}; | 
|  |  | 
|  | // clang-format off | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x28, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (ack frame) | 
|  | // (no ack blocks, 2 byte largest observed, 2 byte block length) | 
|  | 0x45, | 
|  | // largest acked | 
|  | 0x12, 0x34, | 
|  | // Zero delta time. | 
|  | 0x00, 0x00, | 
|  | // first ack block length. | 
|  | 0x12, 0x34, | 
|  | // num timestamps. | 
|  | 0x00, | 
|  | }; | 
|  |  | 
|  | unsigned char packet44[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x32, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (ack frame) | 
|  | // (no ack blocks, 2 byte largest observed, 2 byte block length) | 
|  | 0x45, | 
|  | // largest acked | 
|  | 0x12, 0x34, | 
|  | // Zero delta time. | 
|  | 0x00, 0x00, | 
|  | // first ack block length. | 
|  | 0x12, 0x34, | 
|  | // num timestamps. | 
|  | 0x00, | 
|  | }; | 
|  |  | 
|  | unsigned char packet46[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (ack frame) | 
|  | // (no ack blocks, 2 byte largest observed, 2 byte block length) | 
|  | 0x45, | 
|  | // largest acked | 
|  | 0x12, 0x34, | 
|  | // Zero delta time. | 
|  | 0x00, 0x00, | 
|  | // first ack block length. | 
|  | 0x12, 0x34, | 
|  | // num timestamps. | 
|  | 0x00, | 
|  | }; | 
|  |  | 
|  | unsigned char packet99[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (IETF_ACK frame) | 
|  | 0x02, | 
|  | // largest acked | 
|  | kVarInt62TwoBytes + 0x12, 0x34, | 
|  | // Zero delta time. | 
|  | kVarInt62OneByte + 0x00, | 
|  | // Number of additional ack blocks. | 
|  | kVarInt62OneByte + 0x00, | 
|  | // first ack block length. | 
|  | kVarInt62TwoBytes + 0x12, 0x33, | 
|  | }; | 
|  | // clang-format on | 
|  | unsigned char* p = packet; | 
|  | size_t p_size = QUIC_ARRAYSIZE(packet); | 
|  | if (framer_.transport_version() == QUIC_VERSION_99) { | 
|  | p = packet99; | 
|  | p_size = QUIC_ARRAYSIZE(packet99); | 
|  | } else if (framer_.transport_version() > QUIC_VERSION_44) { | 
|  | p = packet46; | 
|  | p_size = QUIC_ARRAYSIZE(packet46); | 
|  | } else if (framer_.transport_version() > QUIC_VERSION_43) { | 
|  | p = packet44; | 
|  | p_size = QUIC_ARRAYSIZE(packet44); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  | test::CompareCharArraysWithHexError("constructed packet", data->data(), | 
|  | data->length(), AsChars(p), p_size); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, BuildAckFramePacketOneAckBlockMaxLength) { | 
|  | QuicPacketHeader header; | 
|  | header.destination_connection_id = FramerTestConnectionId(); | 
|  | header.reset_flag = false; | 
|  | header.version_flag = false; | 
|  | header.packet_number = kPacketNumber; | 
|  |  | 
|  | QuicAckFrame ack_frame = InitAckFrame(kPacketNumber); | 
|  | ack_frame.ack_delay_time = QuicTime::Delta::Zero(); | 
|  |  | 
|  | QuicFrames frames = {QuicFrame(&ack_frame)}; | 
|  |  | 
|  | // clang-format off | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x28, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (ack frame) | 
|  | // (no ack blocks, 4 byte largest observed, 4 byte block length) | 
|  | 0x4A, | 
|  | // largest acked | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  | // Zero delta time. | 
|  | 0x00, 0x00, | 
|  | // first ack block length. | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  | // num timestamps. | 
|  | 0x00, | 
|  | }; | 
|  |  | 
|  | unsigned char packet44[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x32, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (ack frame) | 
|  | // (no ack blocks, 4 byte largest observed, 4 byte block length) | 
|  | 0x4A, | 
|  | // largest acked | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  | // Zero delta time. | 
|  | 0x00, 0x00, | 
|  | // first ack block length. | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  | // num timestamps. | 
|  | 0x00, | 
|  | }; | 
|  |  | 
|  | unsigned char packet46[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (ack frame) | 
|  | // (no ack blocks, 4 byte largest observed, 4 byte block length) | 
|  | 0x4A, | 
|  | // largest acked | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  | // Zero delta time. | 
|  | 0x00, 0x00, | 
|  | // first ack block length. | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  | // num timestamps. | 
|  | 0x00, | 
|  | }; | 
|  |  | 
|  |  | 
|  | unsigned char packet99[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (IETF_ACK frame) | 
|  | 0x02, | 
|  | // largest acked | 
|  | kVarInt62FourBytes + 0x12, 0x34, 0x56, 0x78, | 
|  | // Zero delta time. | 
|  | kVarInt62OneByte + 0x00, | 
|  | // Nr. of additional ack blocks | 
|  | kVarInt62OneByte + 0x00, | 
|  | // first ack block length. | 
|  | kVarInt62FourBytes + 0x12, 0x34, 0x56, 0x77, | 
|  | }; | 
|  | // clang-format on | 
|  | unsigned char* p = packet; | 
|  | size_t p_size = QUIC_ARRAYSIZE(packet); | 
|  | if (framer_.transport_version() == QUIC_VERSION_99) { | 
|  | p = packet99; | 
|  | p_size = QUIC_ARRAYSIZE(packet99); | 
|  | } else if (framer_.transport_version() > QUIC_VERSION_44) { | 
|  | p = packet46; | 
|  | p_size = QUIC_ARRAYSIZE(packet46); | 
|  | } else if (framer_.transport_version() > QUIC_VERSION_43) { | 
|  | p = packet44; | 
|  | p_size = QUIC_ARRAYSIZE(packet44); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  | test::CompareCharArraysWithHexError("constructed packet", data->data(), | 
|  | data->length(), AsChars(p), p_size); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, BuildAckFramePacketMultipleAckBlocks) { | 
|  | QuicPacketHeader header; | 
|  | header.destination_connection_id = FramerTestConnectionId(); | 
|  | header.reset_flag = false; | 
|  | header.version_flag = false; | 
|  | header.packet_number = kPacketNumber; | 
|  |  | 
|  | // Use kSmallLargestObserved to make this test finished in a short time. | 
|  | QuicAckFrame ack_frame = | 
|  | InitAckFrame({{QuicPacketNumber(1), QuicPacketNumber(5)}, | 
|  | {QuicPacketNumber(10), QuicPacketNumber(500)}, | 
|  | {QuicPacketNumber(900), kSmallMissingPacket}, | 
|  | {kSmallMissingPacket + 1, kSmallLargestObserved + 1}}); | 
|  | ack_frame.ack_delay_time = QuicTime::Delta::Zero(); | 
|  |  | 
|  | QuicFrames frames = {QuicFrame(&ack_frame)}; | 
|  |  | 
|  | // clang-format off | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x28, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (ack frame) | 
|  | // (has ack blocks, 2 byte largest observed, 2 byte block length) | 
|  | 0x65, | 
|  | // largest acked | 
|  | 0x12, 0x34, | 
|  | // Zero delta time. | 
|  | 0x00, 0x00, | 
|  | // num ack blocks ranges. | 
|  | 0x04, | 
|  | // first ack block length. | 
|  | 0x00, 0x01, | 
|  | // gap to next block. | 
|  | 0x01, | 
|  | // ack block length. | 
|  | 0x0e, 0xaf, | 
|  | // gap to next block. | 
|  | 0xff, | 
|  | // ack block length. | 
|  | 0x00, 0x00, | 
|  | // gap to next block. | 
|  | 0x91, | 
|  | // ack block length. | 
|  | 0x01, 0xea, | 
|  | // gap to next block. | 
|  | 0x05, | 
|  | // ack block length. | 
|  | 0x00, 0x04, | 
|  | // num timestamps. | 
|  | 0x00, | 
|  | }; | 
|  |  | 
|  | unsigned char packet44[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x32, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (ack frame) | 
|  | // (has ack blocks, 2 byte largest observed, 2 byte block length) | 
|  | 0x65, | 
|  | // largest acked | 
|  | 0x12, 0x34, | 
|  | // Zero delta time. | 
|  | 0x00, 0x00, | 
|  | // num ack blocks ranges. | 
|  | 0x04, | 
|  | // first ack block length. | 
|  | 0x00, 0x01, | 
|  | // gap to next block. | 
|  | 0x01, | 
|  | // ack block length. | 
|  | 0x0e, 0xaf, | 
|  | // gap to next block. | 
|  | 0xff, | 
|  | // ack block length. | 
|  | 0x00, 0x00, | 
|  | // gap to next block. | 
|  | 0x91, | 
|  | // ack block length. | 
|  | 0x01, 0xea, | 
|  | // gap to next block. | 
|  | 0x05, | 
|  | // ack block length. | 
|  | 0x00, 0x04, | 
|  | // num timestamps. | 
|  | 0x00, | 
|  | }; | 
|  |  | 
|  | unsigned char packet46[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (ack frame) | 
|  | // (has ack blocks, 2 byte largest observed, 2 byte block length) | 
|  | 0x65, | 
|  | // largest acked | 
|  | 0x12, 0x34, | 
|  | // Zero delta time. | 
|  | 0x00, 0x00, | 
|  | // num ack blocks ranges. | 
|  | 0x04, | 
|  | // first ack block length. | 
|  | 0x00, 0x01, | 
|  | // gap to next block. | 
|  | 0x01, | 
|  | // ack block length. | 
|  | 0x0e, 0xaf, | 
|  | // gap to next block. | 
|  | 0xff, | 
|  | // ack block length. | 
|  | 0x00, 0x00, | 
|  | // gap to next block. | 
|  | 0x91, | 
|  | // ack block length. | 
|  | 0x01, 0xea, | 
|  | // gap to next block. | 
|  | 0x05, | 
|  | // ack block length. | 
|  | 0x00, 0x04, | 
|  | // num timestamps. | 
|  | 0x00, | 
|  | }; | 
|  |  | 
|  | unsigned char packet99[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (IETF_ACK frame) | 
|  | 0x02, | 
|  | // largest acked | 
|  | kVarInt62TwoBytes + 0x12, 0x34, | 
|  | // Zero delta time. | 
|  | kVarInt62OneByte + 0x00, | 
|  | // num additional ack blocks. | 
|  | kVarInt62OneByte + 0x03, | 
|  | // first ack block length. | 
|  | kVarInt62OneByte + 0x00, | 
|  |  | 
|  | // gap to next block. | 
|  | kVarInt62OneByte + 0x00, | 
|  | // ack block length. | 
|  | kVarInt62TwoBytes + 0x0e, 0xae, | 
|  |  | 
|  | // gap to next block. | 
|  | kVarInt62TwoBytes + 0x01, 0x8f, | 
|  | // ack block length. | 
|  | kVarInt62TwoBytes + 0x01, 0xe9, | 
|  |  | 
|  | // gap to next block. | 
|  | kVarInt62OneByte + 0x04, | 
|  | // ack block length. | 
|  | kVarInt62OneByte + 0x03, | 
|  | }; | 
|  | // clang-format on | 
|  | unsigned char* p = packet; | 
|  | size_t p_size = QUIC_ARRAYSIZE(packet); | 
|  | if (framer_.transport_version() == QUIC_VERSION_99) { | 
|  | p = packet99; | 
|  | p_size = QUIC_ARRAYSIZE(packet99); | 
|  | } else if (framer_.transport_version() > QUIC_VERSION_44) { | 
|  | p = packet46; | 
|  | p_size = QUIC_ARRAYSIZE(packet46); | 
|  | } else if (framer_.transport_version() > QUIC_VERSION_43) { | 
|  | p = packet44; | 
|  | p_size = QUIC_ARRAYSIZE(packet44); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  |  | 
|  | test::CompareCharArraysWithHexError("constructed packet", data->data(), | 
|  | data->length(), AsChars(p), p_size); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, BuildAckFramePacketMaxAckBlocks) { | 
|  | QuicPacketHeader header; | 
|  | header.destination_connection_id = FramerTestConnectionId(); | 
|  | header.reset_flag = false; | 
|  | header.version_flag = false; | 
|  | header.packet_number = kPacketNumber; | 
|  |  | 
|  | // Use kSmallLargestObservedto make this test finished in a short time. | 
|  | QuicAckFrame ack_frame; | 
|  | ack_frame.largest_acked = kSmallLargestObserved; | 
|  | ack_frame.ack_delay_time = QuicTime::Delta::Zero(); | 
|  | // 300 ack blocks. | 
|  | for (size_t i = 2; i < 2 * 300; i += 2) { | 
|  | ack_frame.packets.Add(QuicPacketNumber(i)); | 
|  | } | 
|  | ack_frame.packets.AddRange(QuicPacketNumber(600), kSmallLargestObserved + 1); | 
|  |  | 
|  | QuicFrames frames = {QuicFrame(&ack_frame)}; | 
|  |  | 
|  | // clang-format off | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x28, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  | // frame type (ack frame) | 
|  | // (has ack blocks, 2 byte largest observed, 2 byte block length) | 
|  | 0x65, | 
|  | // largest acked | 
|  | 0x12, 0x34, | 
|  | // Zero delta time. | 
|  | 0x00, 0x00, | 
|  | // num ack blocks ranges. | 
|  | 0xff, | 
|  | // first ack block length. | 
|  | 0x0f, 0xdd, | 
|  | // 255 = 4 * 63 + 3 | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  |  | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  |  | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  |  | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  |  | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  |  | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  |  | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | // num timestamps. | 
|  | 0x00, | 
|  | }; | 
|  |  | 
|  | unsigned char packet44[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x32, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  | // frame type (ack frame) | 
|  | // (has ack blocks, 2 byte largest observed, 2 byte block length) | 
|  | 0x65, | 
|  | // largest acked | 
|  | 0x12, 0x34, | 
|  | // Zero delta time. | 
|  | 0x00, 0x00, | 
|  | // num ack blocks ranges. | 
|  | 0xff, | 
|  | // first ack block length. | 
|  | 0x0f, 0xdd, | 
|  | // 255 = 4 * 63 + 3 | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  |  | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  |  | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  |  | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  |  | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  |  | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  |  | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | // num timestamps. | 
|  | 0x00, | 
|  | }; | 
|  |  | 
|  | unsigned char packet46[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  | // frame type (ack frame) | 
|  | // (has ack blocks, 2 byte largest observed, 2 byte block length) | 
|  | 0x65, | 
|  | // largest acked | 
|  | 0x12, 0x34, | 
|  | // Zero delta time. | 
|  | 0x00, 0x00, | 
|  | // num ack blocks ranges. | 
|  | 0xff, | 
|  | // first ack block length. | 
|  | 0x0f, 0xdd, | 
|  | // 255 = 4 * 63 + 3 | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  |  | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  |  | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  |  | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  |  | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  |  | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  |  | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, | 
|  | // num timestamps. | 
|  | 0x00, | 
|  | }; | 
|  |  | 
|  | unsigned char packet99[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  | // frame type (IETF_ACK frame) | 
|  | 0x02, | 
|  | // largest acked | 
|  | kVarInt62TwoBytes + 0x12, 0x34, | 
|  | // Zero delta time. | 
|  | kVarInt62OneByte + 0x00, | 
|  | // num ack blocks ranges. | 
|  | kVarInt62TwoBytes + 0x01, 0x2b, | 
|  | // first ack block length. | 
|  | kVarInt62TwoBytes + 0x0f, 0xdc, | 
|  | // 255 added blocks of gap_size == 1, ack_size == 1 | 
|  | #define V99AddedBLOCK kVarInt62OneByte + 0x00, kVarInt62OneByte + 0x00 | 
|  | V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, | 
|  | V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, | 
|  | V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, | 
|  | V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, | 
|  | V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, | 
|  | V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, | 
|  | V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, | 
|  | V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, | 
|  | V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, | 
|  | V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, | 
|  | V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, | 
|  | V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, | 
|  | V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, | 
|  | V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, | 
|  | V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, | 
|  | V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, | 
|  | V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, | 
|  | V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, | 
|  | V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, | 
|  | V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, | 
|  |  | 
|  | V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, | 
|  | V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, | 
|  | V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, | 
|  | V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, | 
|  | V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, | 
|  | V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, | 
|  | V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, | 
|  | V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, | 
|  | V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, | 
|  | V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, | 
|  | V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, | 
|  | V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, | 
|  | V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, | 
|  | V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, | 
|  | V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, | 
|  | V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, | 
|  | V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, | 
|  | V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, | 
|  | V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, | 
|  | V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, | 
|  |  | 
|  | V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, | 
|  | V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, | 
|  | V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, | 
|  | V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, | 
|  | V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, | 
|  | V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, | 
|  | V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, | 
|  | V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, | 
|  | V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, | 
|  | V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, | 
|  | V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, | 
|  | V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, | 
|  | V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, | 
|  | V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, | 
|  | V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, | 
|  | V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, | 
|  | V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, | 
|  | V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, | 
|  | V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, | 
|  | V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, V99AddedBLOCK, | 
|  |  | 
|  | #undef V99AddedBLOCK | 
|  | }; | 
|  | // clang-format on | 
|  | unsigned char* p = packet; | 
|  | size_t p_size = QUIC_ARRAYSIZE(packet); | 
|  | if (framer_.transport_version() == QUIC_VERSION_99) { | 
|  | p = packet99; | 
|  | p_size = QUIC_ARRAYSIZE(packet99); | 
|  | } else if (framer_.transport_version() > QUIC_VERSION_44) { | 
|  | p = packet46; | 
|  | p_size = QUIC_ARRAYSIZE(packet46); | 
|  | } else if (framer_.transport_version() > QUIC_VERSION_43) { | 
|  | p = packet44; | 
|  | p_size = QUIC_ARRAYSIZE(packet44); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  |  | 
|  | test::CompareCharArraysWithHexError("constructed packet", data->data(), | 
|  | data->length(), AsChars(p), p_size); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, BuildNewStopWaitingPacket) { | 
|  | if (version_.transport_version > QUIC_VERSION_43) { | 
|  | return; | 
|  | } | 
|  | QuicPacketHeader header; | 
|  | header.destination_connection_id = FramerTestConnectionId(); | 
|  | header.reset_flag = false; | 
|  | header.version_flag = false; | 
|  | header.packet_number = kPacketNumber; | 
|  |  | 
|  | QuicStopWaitingFrame stop_waiting_frame; | 
|  | stop_waiting_frame.least_unacked = kLeastUnacked; | 
|  |  | 
|  | QuicFrames frames = {QuicFrame(stop_waiting_frame)}; | 
|  |  | 
|  | // clang-format off | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x28, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (stop waiting frame) | 
|  | 0x06, | 
|  | // least packet number awaiting an ack, delta from packet number. | 
|  | 0x00, 0x00, 0x00, 0x08, | 
|  | }; | 
|  |  | 
|  | // clang-format on | 
|  |  | 
|  | std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  |  | 
|  | test::CompareCharArraysWithHexError("constructed packet", data->data(), | 
|  | data->length(), AsChars(packet), | 
|  | QUIC_ARRAYSIZE(packet)); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, BuildRstFramePacketQuic) { | 
|  | QuicPacketHeader header; | 
|  | header.destination_connection_id = FramerTestConnectionId(); | 
|  | header.reset_flag = false; | 
|  | header.version_flag = false; | 
|  | header.packet_number = kPacketNumber; | 
|  |  | 
|  | QuicRstStreamFrame rst_frame; | 
|  | rst_frame.stream_id = kStreamId; | 
|  | if (framer_.transport_version() == QUIC_VERSION_99) { | 
|  | rst_frame.ietf_error_code = 0x01; | 
|  | } else { | 
|  | rst_frame.error_code = static_cast<QuicRstStreamErrorCode>(0x05060708); | 
|  | } | 
|  | rst_frame.byte_offset = 0x0807060504030201; | 
|  |  | 
|  | // clang-format off | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x28, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (rst stream frame) | 
|  | 0x01, | 
|  | // stream id | 
|  | 0x01, 0x02, 0x03, 0x04, | 
|  | // sent byte offset | 
|  | 0x08, 0x07, 0x06, 0x05, | 
|  | 0x04, 0x03, 0x02, 0x01, | 
|  | // error code | 
|  | 0x05, 0x06, 0x07, 0x08, | 
|  | }; | 
|  |  | 
|  | unsigned char packet44[] = { | 
|  | // type (short packet, 4 byte packet number) | 
|  | 0x32, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (rst stream frame) | 
|  | 0x01, | 
|  | // stream id | 
|  | 0x01, 0x02, 0x03, 0x04, | 
|  | // sent byte offset | 
|  | 0x08, 0x07, 0x06, 0x05, | 
|  | 0x04, 0x03, 0x02, 0x01, | 
|  | // error code | 
|  | 0x05, 0x06, 0x07, 0x08, | 
|  | }; | 
|  |  | 
|  | unsigned char packet46[] = { | 
|  | // type (short packet, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (rst stream frame) | 
|  | 0x01, | 
|  | // stream id | 
|  | 0x01, 0x02, 0x03, 0x04, | 
|  | // sent byte offset | 
|  | 0x08, 0x07, 0x06, 0x05, | 
|  | 0x04, 0x03, 0x02, 0x01, | 
|  | // error code | 
|  | 0x05, 0x06, 0x07, 0x08, | 
|  | }; | 
|  |  | 
|  | unsigned char packet99[] = { | 
|  | // type (short packet, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (IETF_RST_STREAM frame) | 
|  | 0x04, | 
|  | // stream id | 
|  | kVarInt62FourBytes + 0x01, 0x02, 0x03, 0x04, | 
|  | // error code (not VarInt32 encoded) | 
|  | 0x00, 0x01, | 
|  | // sent byte offset | 
|  | kVarInt62EightBytes + 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01 | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | QuicFrames frames = {QuicFrame(&rst_frame)}; | 
|  |  | 
|  | std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  |  | 
|  | unsigned char* p = packet; | 
|  | size_t p_size = QUIC_ARRAYSIZE(packet); | 
|  | if (framer_.transport_version() == QUIC_VERSION_99) { | 
|  | p = packet99; | 
|  | p_size = QUIC_ARRAYSIZE(packet99); | 
|  | } else if (framer_.transport_version() > QUIC_VERSION_44) { | 
|  | p = packet46; | 
|  | p_size = QUIC_ARRAYSIZE(packet46); | 
|  | } else if (framer_.transport_version() > QUIC_VERSION_43) { | 
|  | p = packet44; | 
|  | p_size = QUIC_ARRAYSIZE(packet44); | 
|  | } | 
|  | QuicEncryptedPacket encrypted(AsChars(p), p_size, false); | 
|  |  | 
|  | test::CompareCharArraysWithHexError("constructed packet", data->data(), | 
|  | data->length(), AsChars(p), p_size); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, BuildCloseFramePacket) { | 
|  | QuicPacketHeader header; | 
|  | header.destination_connection_id = FramerTestConnectionId(); | 
|  | header.reset_flag = false; | 
|  | header.version_flag = false; | 
|  | header.packet_number = kPacketNumber; | 
|  |  | 
|  | QuicConnectionCloseFrame close_frame; | 
|  | if (framer_.transport_version() == QUIC_VERSION_99) { | 
|  | close_frame.ietf_error_code = | 
|  | static_cast<QuicIetfTransportErrorCodes>(0x11); | 
|  | close_frame.frame_type = 0x05; | 
|  | } else { | 
|  | close_frame.error_code = static_cast<QuicErrorCode>(0x05060708); | 
|  | } | 
|  | close_frame.error_details = "because I can"; | 
|  |  | 
|  | QuicFrames frames = {QuicFrame(&close_frame)}; | 
|  |  | 
|  | // clang-format off | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x28, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (connection close frame) | 
|  | 0x02, | 
|  | // error code | 
|  | 0x05, 0x06, 0x07, 0x08, | 
|  | // error details length | 
|  | 0x00, 0x0d, | 
|  | // error details | 
|  | 'b',  'e',  'c',  'a', | 
|  | 'u',  's',  'e',  ' ', | 
|  | 'I',  ' ',  'c',  'a', | 
|  | 'n', | 
|  | }; | 
|  |  | 
|  | unsigned char packet44[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x32, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (connection close frame) | 
|  | 0x02, | 
|  | // error code | 
|  | 0x05, 0x06, 0x07, 0x08, | 
|  | // error details length | 
|  | 0x00, 0x0d, | 
|  | // error details | 
|  | 'b',  'e',  'c',  'a', | 
|  | 'u',  's',  'e',  ' ', | 
|  | 'I',  ' ',  'c',  'a', | 
|  | 'n', | 
|  | }; | 
|  |  | 
|  | unsigned char packet46[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (connection close frame) | 
|  | 0x02, | 
|  | // error code | 
|  | 0x05, 0x06, 0x07, 0x08, | 
|  | // error details length | 
|  | 0x00, 0x0d, | 
|  | // error details | 
|  | 'b',  'e',  'c',  'a', | 
|  | 'u',  's',  'e',  ' ', | 
|  | 'I',  ' ',  'c',  'a', | 
|  | 'n', | 
|  | }; | 
|  |  | 
|  | unsigned char packet99[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (IETF_CONNECTION_CLOSE frame) | 
|  | 0x1c, | 
|  | // error code | 
|  | 0x00, 0x11, | 
|  | // Frame type within the CONNECTION_CLOSE frame | 
|  | kVarInt62OneByte + 0x05, | 
|  | // error details length | 
|  | kVarInt62OneByte + 0x0d, | 
|  | // error details | 
|  | 'b',  'e',  'c',  'a', | 
|  | 'u',  's',  'e',  ' ', | 
|  | 'I',  ' ',  'c',  'a', | 
|  | 'n', | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | unsigned char* p = packet; | 
|  | size_t p_size = QUIC_ARRAYSIZE(packet); | 
|  | if (framer_.transport_version() == QUIC_VERSION_99) { | 
|  | p = packet99; | 
|  | p_size = QUIC_ARRAYSIZE(packet99); | 
|  | } else if (framer_.transport_version() > QUIC_VERSION_44) { | 
|  | p = packet46; | 
|  | p_size = QUIC_ARRAYSIZE(packet46); | 
|  | } else if (framer_.transport_version() > QUIC_VERSION_43) { | 
|  | p = packet44; | 
|  | p_size = QUIC_ARRAYSIZE(packet44); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  |  | 
|  | test::CompareCharArraysWithHexError("constructed packet", data->data(), | 
|  | data->length(), AsChars(p), p_size); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, BuildTruncatedCloseFramePacket) { | 
|  | QuicPacketHeader header; | 
|  | header.destination_connection_id = FramerTestConnectionId(); | 
|  | header.reset_flag = false; | 
|  | header.version_flag = false; | 
|  | header.packet_number = kPacketNumber; | 
|  |  | 
|  | QuicConnectionCloseFrame close_frame; | 
|  | if (framer_.transport_version() == QUIC_VERSION_99) { | 
|  | close_frame.ietf_error_code = PROTOCOL_VIOLATION;  // value is 0x0a | 
|  | EXPECT_EQ(0u, close_frame.frame_type); | 
|  | } else { | 
|  | close_frame.error_code = static_cast<QuicErrorCode>(0x05060708); | 
|  | } | 
|  | close_frame.error_details = std::string(2048, 'A'); | 
|  | QuicFrames frames = {QuicFrame(&close_frame)}; | 
|  |  | 
|  | // clang-format off | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x28, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (connection close frame) | 
|  | 0x02, | 
|  | // error code | 
|  | 0x05, 0x06, 0x07, 0x08, | 
|  | // error details length | 
|  | 0x01, 0x00, | 
|  | // error details (truncated to 256 bytes) | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | }; | 
|  |  | 
|  | unsigned char packet44[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x32, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (connection close frame) | 
|  | 0x02, | 
|  | // error code | 
|  | 0x05, 0x06, 0x07, 0x08, | 
|  | // error details length | 
|  | 0x01, 0x00, | 
|  | // error details (truncated to 256 bytes) | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | }; | 
|  |  | 
|  | unsigned char packet46[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (connection close frame) | 
|  | 0x02, | 
|  | // error code | 
|  | 0x05, 0x06, 0x07, 0x08, | 
|  | // error details length | 
|  | 0x01, 0x00, | 
|  | // error details (truncated to 256 bytes) | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | }; | 
|  |  | 
|  | unsigned char packet99[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (IETF_CONNECTION_CLOSE frame) | 
|  | 0x1c, | 
|  | // error code | 
|  | 0x00, 0x0a, | 
|  | // Frame type within the CONNECTION_CLOSE frame | 
|  | kVarInt62OneByte + 0x00, | 
|  | // error details length | 
|  | kVarInt62TwoBytes + 0x01, 0x00, | 
|  | // error details (truncated to 256 bytes) | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | unsigned char* p = packet; | 
|  | size_t p_size = QUIC_ARRAYSIZE(packet); | 
|  | if (framer_.transport_version() == QUIC_VERSION_99) { | 
|  | p = packet99; | 
|  | p_size = QUIC_ARRAYSIZE(packet99); | 
|  | } else if (framer_.transport_version() > QUIC_VERSION_44) { | 
|  | p = packet46; | 
|  | p_size = QUIC_ARRAYSIZE(packet46); | 
|  | } else if (framer_.transport_version() > QUIC_VERSION_43) { | 
|  | p = packet44; | 
|  | p_size = QUIC_ARRAYSIZE(packet44); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  |  | 
|  | test::CompareCharArraysWithHexError("constructed packet", data->data(), | 
|  | data->length(), AsChars(p), p_size); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, BuildApplicationCloseFramePacket) { | 
|  | if (framer_.transport_version() != QUIC_VERSION_99) { | 
|  | // Versions other than 99 do not have ApplicationClose | 
|  | return; | 
|  | } | 
|  | QuicPacketHeader header; | 
|  | header.destination_connection_id = FramerTestConnectionId(); | 
|  | header.reset_flag = false; | 
|  | header.version_flag = false; | 
|  | header.packet_number = kPacketNumber; | 
|  |  | 
|  | QuicApplicationCloseFrame app_close_frame; | 
|  | app_close_frame.error_code = static_cast<QuicErrorCode>(0x11); | 
|  | app_close_frame.error_details = "because I can"; | 
|  |  | 
|  | QuicFrames frames = {QuicFrame(&app_close_frame)}; | 
|  |  | 
|  | // clang-format off | 
|  |  | 
|  | unsigned char packet99[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (IETF_APPLICATION_CLOSE frame) | 
|  | 0x1d, | 
|  | // error code | 
|  | 0x00, 0x11, | 
|  | // error details length | 
|  | kVarInt62OneByte + 0x0d, | 
|  | // error details | 
|  | 'b',  'e',  'c',  'a', | 
|  | 'u',  's',  'e',  ' ', | 
|  | 'I',  ' ',  'c',  'a', | 
|  | 'n', | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  |  | 
|  | test::CompareCharArraysWithHexError("constructed packet", data->data(), | 
|  | data->length(), AsChars(packet99), | 
|  | QUIC_ARRAYSIZE(packet99)); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, BuildTruncatedApplicationCloseFramePacket) { | 
|  | if (framer_.transport_version() != QUIC_VERSION_99) { | 
|  | // Versions other than 99 do not have this frame. | 
|  | return; | 
|  | } | 
|  | QuicPacketHeader header; | 
|  | header.destination_connection_id = FramerTestConnectionId(); | 
|  | header.reset_flag = false; | 
|  | header.version_flag = false; | 
|  | header.packet_number = kPacketNumber; | 
|  |  | 
|  | QuicApplicationCloseFrame app_close_frame; | 
|  | app_close_frame.error_code = static_cast<QuicErrorCode>(0x11); | 
|  | app_close_frame.error_details = std::string(2048, 'A'); | 
|  |  | 
|  | QuicFrames frames = {QuicFrame(&app_close_frame)}; | 
|  |  | 
|  | // clang-format off | 
|  | unsigned char packet99[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (IETF_APPLICATION_CLOSE frame) | 
|  | 0x1d, | 
|  | // error code | 
|  | 0x00, 0x11, | 
|  | // error details length | 
|  | kVarInt62TwoBytes + 0x01, 0x00, | 
|  | // error details (truncated to 256 bytes) | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  |  | 
|  | test::CompareCharArraysWithHexError("constructed packet", data->data(), | 
|  | data->length(), AsChars(packet99), | 
|  | QUIC_ARRAYSIZE(packet99)); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, BuildGoAwayPacket) { | 
|  | if (framer_.transport_version() == QUIC_VERSION_99) { | 
|  | // This frame type is not supported in version 99. | 
|  | return; | 
|  | } | 
|  | QuicPacketHeader header; | 
|  | header.destination_connection_id = FramerTestConnectionId(); | 
|  | header.reset_flag = false; | 
|  | header.version_flag = false; | 
|  | header.packet_number = kPacketNumber; | 
|  |  | 
|  | QuicGoAwayFrame goaway_frame; | 
|  | goaway_frame.error_code = static_cast<QuicErrorCode>(0x05060708); | 
|  | goaway_frame.last_good_stream_id = kStreamId; | 
|  | goaway_frame.reason_phrase = "because I can"; | 
|  |  | 
|  | QuicFrames frames = {QuicFrame(&goaway_frame)}; | 
|  |  | 
|  | // clang-format off | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x28, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (go away frame) | 
|  | 0x03, | 
|  | // error code | 
|  | 0x05, 0x06, 0x07, 0x08, | 
|  | // stream id | 
|  | 0x01, 0x02, 0x03, 0x04, | 
|  | // error details length | 
|  | 0x00, 0x0d, | 
|  | // error details | 
|  | 'b',  'e',  'c',  'a', | 
|  | 'u',  's',  'e',  ' ', | 
|  | 'I',  ' ',  'c',  'a', | 
|  | 'n', | 
|  | }; | 
|  |  | 
|  | unsigned char packet44[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x32, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (go away frame) | 
|  | 0x03, | 
|  | // error code | 
|  | 0x05, 0x06, 0x07, 0x08, | 
|  | // stream id | 
|  | 0x01, 0x02, 0x03, 0x04, | 
|  | // error details length | 
|  | 0x00, 0x0d, | 
|  | // error details | 
|  | 'b',  'e',  'c',  'a', | 
|  | 'u',  's',  'e',  ' ', | 
|  | 'I',  ' ',  'c',  'a', | 
|  | 'n', | 
|  | }; | 
|  |  | 
|  | unsigned char packet46[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (go away frame) | 
|  | 0x03, | 
|  | // error code | 
|  | 0x05, 0x06, 0x07, 0x08, | 
|  | // stream id | 
|  | 0x01, 0x02, 0x03, 0x04, | 
|  | // error details length | 
|  | 0x00, 0x0d, | 
|  | // error details | 
|  | 'b',  'e',  'c',  'a', | 
|  | 'u',  's',  'e',  ' ', | 
|  | 'I',  ' ',  'c',  'a', | 
|  | 'n', | 
|  | }; | 
|  |  | 
|  | // clang-format on | 
|  |  | 
|  | unsigned char* p = packet; | 
|  | size_t p_size = QUIC_ARRAYSIZE(packet); | 
|  | if (framer_.transport_version() > QUIC_VERSION_44) { | 
|  | p = packet46; | 
|  | p_size = QUIC_ARRAYSIZE(packet46); | 
|  | } else if (framer_.transport_version() > QUIC_VERSION_43) { | 
|  | p = packet44; | 
|  | p_size = QUIC_ARRAYSIZE(packet44); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  |  | 
|  | test::CompareCharArraysWithHexError("constructed packet", data->data(), | 
|  | data->length(), AsChars(p), p_size); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, BuildTruncatedGoAwayPacket) { | 
|  | if (framer_.transport_version() == QUIC_VERSION_99) { | 
|  | // This frame type is not supported in version 99. | 
|  | return; | 
|  | } | 
|  | QuicPacketHeader header; | 
|  | header.destination_connection_id = FramerTestConnectionId(); | 
|  | header.reset_flag = false; | 
|  | header.version_flag = false; | 
|  | header.packet_number = kPacketNumber; | 
|  |  | 
|  | QuicGoAwayFrame goaway_frame; | 
|  | goaway_frame.error_code = static_cast<QuicErrorCode>(0x05060708); | 
|  | goaway_frame.last_good_stream_id = kStreamId; | 
|  | goaway_frame.reason_phrase = std::string(2048, 'A'); | 
|  |  | 
|  | QuicFrames frames = {QuicFrame(&goaway_frame)}; | 
|  |  | 
|  | // clang-format off | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x28, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (go away frame) | 
|  | 0x03, | 
|  | // error code | 
|  | 0x05, 0x06, 0x07, 0x08, | 
|  | // stream id | 
|  | 0x01, 0x02, 0x03, 0x04, | 
|  | // error details length | 
|  | 0x01, 0x00, | 
|  | // error details (truncated to 256 bytes) | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | }; | 
|  |  | 
|  | unsigned char packet44[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x32, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (go away frame) | 
|  | 0x03, | 
|  | // error code | 
|  | 0x05, 0x06, 0x07, 0x08, | 
|  | // stream id | 
|  | 0x01, 0x02, 0x03, 0x04, | 
|  | // error details length | 
|  | 0x01, 0x00, | 
|  | // error details (truncated to 256 bytes) | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | }; | 
|  |  | 
|  | unsigned char packet46[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (go away frame) | 
|  | 0x03, | 
|  | // error code | 
|  | 0x05, 0x06, 0x07, 0x08, | 
|  | // stream id | 
|  | 0x01, 0x02, 0x03, 0x04, | 
|  | // error details length | 
|  | 0x01, 0x00, | 
|  | // error details (truncated to 256 bytes) | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | 'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A', | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | unsigned char* p = packet; | 
|  | size_t p_size = QUIC_ARRAYSIZE(packet); | 
|  | if (framer_.transport_version() > QUIC_VERSION_44) { | 
|  | p = packet46; | 
|  | p_size = QUIC_ARRAYSIZE(packet46); | 
|  | } else if (framer_.transport_version() > QUIC_VERSION_43) { | 
|  | p = packet44; | 
|  | p_size = QUIC_ARRAYSIZE(packet44); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  |  | 
|  | test::CompareCharArraysWithHexError("constructed packet", data->data(), | 
|  | data->length(), AsChars(p), p_size); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, BuildWindowUpdatePacket) { | 
|  | QuicPacketHeader header; | 
|  | header.destination_connection_id = FramerTestConnectionId(); | 
|  | header.reset_flag = false; | 
|  | header.version_flag = false; | 
|  | header.packet_number = kPacketNumber; | 
|  |  | 
|  | QuicWindowUpdateFrame window_update_frame; | 
|  | window_update_frame.stream_id = kStreamId; | 
|  | window_update_frame.byte_offset = 0x1122334455667788; | 
|  |  | 
|  | QuicFrames frames = {QuicFrame(&window_update_frame)}; | 
|  |  | 
|  | // clang-format off | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x28, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (window update frame) | 
|  | 0x04, | 
|  | // stream id | 
|  | 0x01, 0x02, 0x03, 0x04, | 
|  | // byte offset | 
|  | 0x11, 0x22, 0x33, 0x44, | 
|  | 0x55, 0x66, 0x77, 0x88, | 
|  | }; | 
|  |  | 
|  | unsigned char packet44[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x32, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (window update frame) | 
|  | 0x04, | 
|  | // stream id | 
|  | 0x01, 0x02, 0x03, 0x04, | 
|  | // byte offset | 
|  | 0x11, 0x22, 0x33, 0x44, | 
|  | 0x55, 0x66, 0x77, 0x88, | 
|  | }; | 
|  |  | 
|  | unsigned char packet46[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (window update frame) | 
|  | 0x04, | 
|  | // stream id | 
|  | 0x01, 0x02, 0x03, 0x04, | 
|  | // byte offset | 
|  | 0x11, 0x22, 0x33, 0x44, | 
|  | 0x55, 0x66, 0x77, 0x88, | 
|  | }; | 
|  |  | 
|  | unsigned char packet99[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (IETF_MAX_STREAM_DATA frame) | 
|  | 0x11, | 
|  | // stream id | 
|  | kVarInt62FourBytes + 0x01, 0x02, 0x03, 0x04, | 
|  | // byte offset | 
|  | kVarInt62EightBytes + 0x11, 0x22, 0x33, 0x44, | 
|  | 0x55, 0x66, 0x77, 0x88, | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  |  | 
|  | unsigned char* p = packet; | 
|  | size_t p_size = QUIC_ARRAYSIZE(packet); | 
|  | if (framer_.transport_version() == QUIC_VERSION_99) { | 
|  | p = packet99; | 
|  | p_size = QUIC_ARRAYSIZE(packet99); | 
|  | } else if (framer_.transport_version() > QUIC_VERSION_44) { | 
|  | p = packet46; | 
|  | p_size = QUIC_ARRAYSIZE(packet46); | 
|  | } else if (framer_.transport_version() > QUIC_VERSION_43) { | 
|  | p = packet44; | 
|  | p_size = QUIC_ARRAYSIZE(packet44); | 
|  | } | 
|  |  | 
|  | test::CompareCharArraysWithHexError("constructed packet", data->data(), | 
|  | data->length(), AsChars(p), p_size); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, BuildMaxStreamDataPacket) { | 
|  | if (framer_.transport_version() != QUIC_VERSION_99) { | 
|  | // This frame is available only in this version. | 
|  | return; | 
|  | } | 
|  | QuicPacketHeader header; | 
|  | header.destination_connection_id = FramerTestConnectionId(); | 
|  | header.reset_flag = false; | 
|  | header.version_flag = false; | 
|  | header.packet_number = kPacketNumber; | 
|  |  | 
|  | QuicWindowUpdateFrame window_update_frame; | 
|  | window_update_frame.stream_id = kStreamId; | 
|  | window_update_frame.byte_offset = 0x1122334455667788; | 
|  |  | 
|  | QuicFrames frames = {QuicFrame(&window_update_frame)}; | 
|  |  | 
|  | // clang-format off | 
|  | unsigned char packet99[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (IETF_MAX_STREAM_DATA frame) | 
|  | 0x11, | 
|  | // stream id | 
|  | kVarInt62FourBytes + 0x01, 0x02, 0x03, 0x04, | 
|  | // byte offset | 
|  | kVarInt62EightBytes + 0x11, 0x22, 0x33, 0x44, | 
|  | 0x55, 0x66, 0x77, 0x88, | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  |  | 
|  | test::CompareCharArraysWithHexError("constructed packet", data->data(), | 
|  | data->length(), AsChars(packet99), | 
|  | QUIC_ARRAYSIZE(packet99)); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, BuildMaxDataPacket) { | 
|  | if (framer_.transport_version() != QUIC_VERSION_99) { | 
|  | // This frame is available only in this version. | 
|  | return; | 
|  | } | 
|  | QuicPacketHeader header; | 
|  | header.destination_connection_id = FramerTestConnectionId(); | 
|  | header.reset_flag = false; | 
|  | header.version_flag = false; | 
|  | header.packet_number = kPacketNumber; | 
|  |  | 
|  | QuicWindowUpdateFrame window_update_frame; | 
|  | window_update_frame.stream_id = | 
|  | QuicUtils::GetInvalidStreamId(framer_.transport_version()); | 
|  | window_update_frame.byte_offset = 0x1122334455667788; | 
|  |  | 
|  | QuicFrames frames = {QuicFrame(&window_update_frame)}; | 
|  |  | 
|  | // clang-format off | 
|  | unsigned char packet99[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (IETF_MAX_DATA frame) | 
|  | 0x10, | 
|  | // byte offset | 
|  | kVarInt62EightBytes + 0x11, 0x22, 0x33, 0x44, | 
|  | 0x55, 0x66, 0x77, 0x88, | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  |  | 
|  | test::CompareCharArraysWithHexError("constructed packet", data->data(), | 
|  | data->length(), AsChars(packet99), | 
|  | QUIC_ARRAYSIZE(packet99)); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, BuildBlockedPacket) { | 
|  | QuicPacketHeader header; | 
|  | header.destination_connection_id = FramerTestConnectionId(); | 
|  | header.reset_flag = false; | 
|  | header.version_flag = false; | 
|  | header.packet_number = kPacketNumber; | 
|  |  | 
|  | QuicBlockedFrame blocked_frame; | 
|  | if (framer_.transport_version() == QUIC_VERSION_99) { | 
|  | // For V99, the stream ID must be <invalid> for the frame | 
|  | // to be a BLOCKED frame. if it's valid, it will be a | 
|  | // STREAM_BLOCKED frame. | 
|  | blocked_frame.stream_id = | 
|  | QuicUtils::GetInvalidStreamId(framer_.transport_version()); | 
|  | } else { | 
|  | blocked_frame.stream_id = kStreamId; | 
|  | } | 
|  | blocked_frame.offset = kStreamOffset; | 
|  |  | 
|  | QuicFrames frames = {QuicFrame(&blocked_frame)}; | 
|  |  | 
|  | // clang-format off | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x28, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (blocked frame) | 
|  | 0x05, | 
|  | // stream id | 
|  | 0x01, 0x02, 0x03, 0x04, | 
|  | }; | 
|  |  | 
|  | unsigned char packet44[] = { | 
|  | // type (short packet, 4 byte packet number) | 
|  | 0x32, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (blocked frame) | 
|  | 0x05, | 
|  | // stream id | 
|  | 0x01, 0x02, 0x03, 0x04, | 
|  | }; | 
|  |  | 
|  | unsigned char packet46[] = { | 
|  | // type (short packet, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (blocked frame) | 
|  | 0x05, | 
|  | // stream id | 
|  | 0x01, 0x02, 0x03, 0x04, | 
|  | }; | 
|  |  | 
|  | unsigned char packet99[] = { | 
|  | // type (short packet, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (IETF_BLOCKED frame) | 
|  | 0x14, | 
|  | // Offset | 
|  | kVarInt62EightBytes + 0x3a, 0x98, 0xFE, 0xDC, 0x32, 0x10, 0x76, 0x54 | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  |  | 
|  | unsigned char* p = packet; | 
|  | size_t p_size = QUIC_ARRAYSIZE(packet); | 
|  | if (framer_.transport_version() == QUIC_VERSION_99) { | 
|  | p = packet99; | 
|  | p_size = QUIC_ARRAYSIZE(packet99); | 
|  | } else if (framer_.transport_version() > QUIC_VERSION_44) { | 
|  | p = packet46; | 
|  | p_size = QUIC_ARRAYSIZE(packet46); | 
|  | } else if (framer_.transport_version() > QUIC_VERSION_43) { | 
|  | p = packet44; | 
|  | p_size = QUIC_ARRAYSIZE(packet44); | 
|  | } | 
|  |  | 
|  | test::CompareCharArraysWithHexError("constructed packet", data->data(), | 
|  | data->length(), AsChars(p), p_size); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, BuildPingPacket) { | 
|  | QuicPacketHeader header; | 
|  | header.destination_connection_id = FramerTestConnectionId(); | 
|  | header.reset_flag = false; | 
|  | header.version_flag = false; | 
|  | header.packet_number = kPacketNumber; | 
|  |  | 
|  | QuicFrames frames = {QuicFrame(QuicPingFrame())}; | 
|  |  | 
|  | // clang-format off | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x28, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (ping frame) | 
|  | 0x07, | 
|  | }; | 
|  |  | 
|  | unsigned char packet44[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x32, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type | 
|  | 0x07, | 
|  | }; | 
|  |  | 
|  | unsigned char packet46[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type | 
|  | 0x07, | 
|  | }; | 
|  |  | 
|  | unsigned char packet99[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (IETF_PING frame) | 
|  | 0x01, | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | unsigned char* p = packet; | 
|  | if (framer_.transport_version() == QUIC_VERSION_99) { | 
|  | p = packet99; | 
|  | } else if (framer_.transport_version() > QUIC_VERSION_44) { | 
|  | p = packet46; | 
|  | } else if (framer_.transport_version() > QUIC_VERSION_43) { | 
|  | p = packet44; | 
|  | } | 
|  |  | 
|  | std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  |  | 
|  | test::CompareCharArraysWithHexError( | 
|  | "constructed packet", data->data(), data->length(), AsChars(p), | 
|  | framer_.transport_version() > QUIC_VERSION_43 ? QUIC_ARRAYSIZE(packet44) | 
|  | : QUIC_ARRAYSIZE(packet)); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, BuildMessagePacket) { | 
|  | if (framer_.transport_version() <= QUIC_VERSION_44) { | 
|  | return; | 
|  | } | 
|  | QuicPacketHeader header; | 
|  | header.destination_connection_id = FramerTestConnectionId(); | 
|  | header.reset_flag = false; | 
|  | header.version_flag = false; | 
|  | header.packet_number = kPacketNumber; | 
|  | QuicMemSliceStorage storage(nullptr, 0, nullptr, 0); | 
|  |  | 
|  | QuicMessageFrame frame(1); | 
|  | MakeSpan(&allocator_, "message", &storage).SaveMemSlicesAsMessageData(&frame); | 
|  | QuicMessageFrame frame2(2); | 
|  | MakeSpan(&allocator_, "message2", &storage) | 
|  | .SaveMemSlicesAsMessageData(&frame2); | 
|  | QuicFrames frames = {QuicFrame(&frame), QuicFrame(&frame2)}; | 
|  |  | 
|  | // clang-format off | 
|  | unsigned char packet45[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x32, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (message frame) | 
|  | 0x21, | 
|  | // Length | 
|  | 0x07, | 
|  | // Message Data | 
|  | 'm', 'e', 's', 's', 'a', 'g', 'e', | 
|  | // frame type (message frame no length) | 
|  | 0x20, | 
|  | // Message Data | 
|  | 'm', 'e', 's', 's', 'a', 'g', 'e', '2' | 
|  | }; | 
|  |  | 
|  | unsigned char packet46[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (message frame) | 
|  | 0x21, | 
|  | // Length | 
|  | 0x07, | 
|  | // Message Data | 
|  | 'm', 'e', 's', 's', 'a', 'g', 'e', | 
|  | // frame type (message frame no length) | 
|  | 0x20, | 
|  | // Message Data | 
|  | 'm', 'e', 's', 's', 'a', 'g', 'e', '2' | 
|  | }; | 
|  |  | 
|  | unsigned char packet99[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (IETF_MESSAGE frame) | 
|  | 0x21, | 
|  | // Length | 
|  | 0x07, | 
|  | // Message Data | 
|  | 'm', 'e', 's', 's', 'a', 'g', 'e', | 
|  | // frame type (message frame no length) | 
|  | 0x20, | 
|  | // Message Data | 
|  | 'm', 'e', 's', 's', 'a', 'g', 'e', '2' | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | unsigned char* p = packet45; | 
|  | if (framer_.transport_version() == QUIC_VERSION_99) { | 
|  | p = packet99; | 
|  | } else if (framer_.transport_version() > QUIC_VERSION_44) { | 
|  | p = packet46; | 
|  | } | 
|  |  | 
|  | std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  |  | 
|  | test::CompareCharArraysWithHexError("constructed packet", data->data(), | 
|  | data->length(), AsChars(p), | 
|  | QUIC_ARRAYSIZE(packet45)); | 
|  | } | 
|  |  | 
|  | // Test that the connectivity probing packet is serialized correctly as a | 
|  | // padded PING packet. | 
|  | TEST_P(QuicFramerTest, BuildConnectivityProbingPacket) { | 
|  | QuicPacketHeader header; | 
|  | header.destination_connection_id = FramerTestConnectionId(); | 
|  | header.reset_flag = false; | 
|  | header.version_flag = false; | 
|  | header.packet_number = kPacketNumber; | 
|  |  | 
|  | // clang-format off | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x28, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (ping frame) | 
|  | 0x07, | 
|  | // frame type (padding frame) | 
|  | 0x00, | 
|  | 0x00, 0x00, 0x00, 0x00 | 
|  | }; | 
|  |  | 
|  | unsigned char packet44[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x32, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type | 
|  | 0x07, | 
|  | // frame type (padding frame) | 
|  | 0x00, | 
|  | 0x00, 0x00, 0x00, 0x00 | 
|  | }; | 
|  |  | 
|  | unsigned char packet46[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type | 
|  | 0x07, | 
|  | // frame type (padding frame) | 
|  | 0x00, | 
|  | 0x00, 0x00, 0x00, 0x00 | 
|  | }; | 
|  |  | 
|  | unsigned char packet99[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (IETF_PING frame) | 
|  | 0x01, | 
|  | // frame type (padding frame) | 
|  | 0x00, | 
|  | 0x00, 0x00, 0x00, 0x00 | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | unsigned char* p = packet; | 
|  | size_t packet_size = QUIC_ARRAYSIZE(packet); | 
|  | if (framer_.transport_version() == QUIC_VERSION_99) { | 
|  | p = packet99; | 
|  | packet_size = QUIC_ARRAYSIZE(packet99); | 
|  | } else if (framer_.transport_version() > QUIC_VERSION_44) { | 
|  | p = packet46; | 
|  | packet_size = QUIC_ARRAYSIZE(packet46); | 
|  | } else if (framer_.transport_version() > QUIC_VERSION_43) { | 
|  | p = packet44; | 
|  | packet_size = QUIC_ARRAYSIZE(packet44); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<char[]> buffer(new char[kMaxPacketSize]); | 
|  |  | 
|  | size_t length = framer_.BuildConnectivityProbingPacket( | 
|  | header, buffer.get(), packet_size, ENCRYPTION_INITIAL); | 
|  |  | 
|  | EXPECT_NE(0u, length); | 
|  | QuicPacket data(framer_.transport_version(), buffer.release(), length, true, | 
|  | header); | 
|  |  | 
|  | test::CompareCharArraysWithHexError("constructed packet", data.data(), | 
|  | data.length(), AsChars(p), packet_size); | 
|  | } | 
|  |  | 
|  | // Test that the path challenge connectivity probing packet is serialized | 
|  | // correctly as a padded PATH CHALLENGE packet. | 
|  | TEST_P(QuicFramerTest, BuildPaddedPathChallengePacket) { | 
|  | if (framer_.transport_version() != QUIC_VERSION_99) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | QuicPacketHeader header; | 
|  | header.destination_connection_id = FramerTestConnectionId(); | 
|  | header.reset_flag = false; | 
|  | header.version_flag = false; | 
|  | header.packet_number = kPacketNumber; | 
|  | QuicPathFrameBuffer payload; | 
|  |  | 
|  | // clang-format off | 
|  | unsigned char packet[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // Path Challenge Frame type (IETF_PATH_CHALLENGE) | 
|  | 0x1a, | 
|  | // 8 "random" bytes, MockRandom makes lots of r's | 
|  | 'r', 'r', 'r', 'r', 'r', 'r', 'r', 'r', | 
|  | // frame type (padding frame) | 
|  | 0x00, | 
|  | 0x00, 0x00, 0x00, 0x00 | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | std::unique_ptr<char[]> buffer(new char[kMaxPacketSize]); | 
|  | MockRandom randomizer; | 
|  |  | 
|  | size_t length = framer_.BuildPaddedPathChallengePacket( | 
|  | header, buffer.get(), QUIC_ARRAYSIZE(packet), &payload, &randomizer, | 
|  | ENCRYPTION_INITIAL); | 
|  | EXPECT_EQ(length, QUIC_ARRAYSIZE(packet)); | 
|  |  | 
|  | // Payload has the random bytes that were generated. Copy them into packet, | 
|  | // above, before checking that the generated packet is correct. | 
|  | EXPECT_EQ(kQuicPathFrameBufferSize, payload.size()); | 
|  |  | 
|  | QuicPacket data(framer_.transport_version(), buffer.release(), length, true, | 
|  | header); | 
|  |  | 
|  | test::CompareCharArraysWithHexError("constructed packet", data.data(), | 
|  | data.length(), AsChars(packet), | 
|  | QUIC_ARRAYSIZE(packet)); | 
|  | } | 
|  |  | 
|  | // Several tests that the path response connectivity probing packet is | 
|  | // serialized correctly as either a padded and unpadded PATH RESPONSE | 
|  | // packet. Also generates packets with 1 and 3 PATH_RESPONSES in them to | 
|  | // exercised the single- and multiple- payload cases. | 
|  | TEST_P(QuicFramerTest, BuildPathResponsePacket1ResponseUnpadded) { | 
|  | if (framer_.transport_version() != QUIC_VERSION_99) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | QuicPacketHeader header; | 
|  | header.destination_connection_id = FramerTestConnectionId(); | 
|  | header.reset_flag = false; | 
|  | header.version_flag = false; | 
|  | header.packet_number = kPacketNumber; | 
|  | QuicPathFrameBuffer payload0 = { | 
|  | {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}}; | 
|  |  | 
|  | // Build 1 PATH RESPONSE, not padded | 
|  | // clang-format off | 
|  | unsigned char packet[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // Path Response Frame type (IETF_PATH_RESPONSE) | 
|  | 0x1b, | 
|  | // 8 "random" bytes | 
|  | 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, | 
|  | }; | 
|  | // clang-format on | 
|  | std::unique_ptr<char[]> buffer(new char[kMaxPacketSize]); | 
|  | QuicDeque<QuicPathFrameBuffer> payloads; | 
|  | payloads.push_back(payload0); | 
|  | size_t length = framer_.BuildPathResponsePacket( | 
|  | header, buffer.get(), QUIC_ARRAYSIZE(packet), payloads, | 
|  | /*is_padded=*/false, ENCRYPTION_INITIAL); | 
|  | EXPECT_EQ(length, QUIC_ARRAYSIZE(packet)); | 
|  | QuicPacket data(framer_.transport_version(), buffer.release(), length, true, | 
|  | header); | 
|  |  | 
|  | test::CompareCharArraysWithHexError("constructed packet", data.data(), | 
|  | data.length(), AsChars(packet), | 
|  | QUIC_ARRAYSIZE(packet)); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, BuildPathResponsePacket1ResponsePadded) { | 
|  | if (framer_.transport_version() != QUIC_VERSION_99) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | QuicPacketHeader header; | 
|  | header.destination_connection_id = FramerTestConnectionId(); | 
|  | header.reset_flag = false; | 
|  | header.version_flag = false; | 
|  | header.packet_number = kPacketNumber; | 
|  | QuicPathFrameBuffer payload0 = { | 
|  | {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}}; | 
|  |  | 
|  | // Build 1 PATH RESPONSE, padded | 
|  | // clang-format off | 
|  | unsigned char packet[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // Path Response Frame type (IETF_PATH_RESPONSE) | 
|  | 0x1b, | 
|  | // 8 "random" bytes | 
|  | 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, | 
|  | // Padding type and pad | 
|  | 0x00, 0x00, 0x00, 0x00, 0x00 | 
|  | }; | 
|  | // clang-format on | 
|  | std::unique_ptr<char[]> buffer(new char[kMaxPacketSize]); | 
|  | QuicDeque<QuicPathFrameBuffer> payloads; | 
|  | payloads.push_back(payload0); | 
|  | size_t length = framer_.BuildPathResponsePacket( | 
|  | header, buffer.get(), QUIC_ARRAYSIZE(packet), payloads, | 
|  | /*is_padded=*/true, ENCRYPTION_INITIAL); | 
|  | EXPECT_EQ(length, QUIC_ARRAYSIZE(packet)); | 
|  | QuicPacket data(framer_.transport_version(), buffer.release(), length, true, | 
|  | header); | 
|  |  | 
|  | test::CompareCharArraysWithHexError("constructed packet", data.data(), | 
|  | data.length(), AsChars(packet), | 
|  | QUIC_ARRAYSIZE(packet)); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, BuildPathResponsePacket3ResponsesUnpadded) { | 
|  | if (framer_.transport_version() != QUIC_VERSION_99) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | QuicPacketHeader header; | 
|  | header.destination_connection_id = FramerTestConnectionId(); | 
|  | header.reset_flag = false; | 
|  | header.version_flag = false; | 
|  | header.packet_number = kPacketNumber; | 
|  | QuicPathFrameBuffer payload0 = { | 
|  | {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}}; | 
|  | QuicPathFrameBuffer payload1 = { | 
|  | {0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18}}; | 
|  | QuicPathFrameBuffer payload2 = { | 
|  | {0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28}}; | 
|  |  | 
|  | // Build one packet with 3 PATH RESPONSES, no padding | 
|  | // clang-format off | 
|  | unsigned char packet[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // 3 path response frames (IETF_PATH_RESPONSE type byte and payload) | 
|  | 0x1b, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, | 
|  | 0x1b, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, | 
|  | 0x1b, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | std::unique_ptr<char[]> buffer(new char[kMaxPacketSize]); | 
|  | QuicDeque<QuicPathFrameBuffer> payloads; | 
|  | payloads.push_back(payload0); | 
|  | payloads.push_back(payload1); | 
|  | payloads.push_back(payload2); | 
|  | size_t length = framer_.BuildPathResponsePacket( | 
|  | header, buffer.get(), QUIC_ARRAYSIZE(packet), payloads, | 
|  | /*is_padded=*/false, ENCRYPTION_INITIAL); | 
|  | EXPECT_EQ(length, QUIC_ARRAYSIZE(packet)); | 
|  | QuicPacket data(framer_.transport_version(), buffer.release(), length, true, | 
|  | header); | 
|  |  | 
|  | test::CompareCharArraysWithHexError("constructed packet", data.data(), | 
|  | data.length(), AsChars(packet), | 
|  | QUIC_ARRAYSIZE(packet)); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, BuildPathResponsePacket3ResponsesPadded) { | 
|  | if (framer_.transport_version() != QUIC_VERSION_99) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | QuicPacketHeader header; | 
|  | header.destination_connection_id = FramerTestConnectionId(); | 
|  | header.reset_flag = false; | 
|  | header.version_flag = false; | 
|  | header.packet_number = kPacketNumber; | 
|  | QuicPathFrameBuffer payload0 = { | 
|  | {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}}; | 
|  | QuicPathFrameBuffer payload1 = { | 
|  | {0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18}}; | 
|  | QuicPathFrameBuffer payload2 = { | 
|  | {0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28}}; | 
|  |  | 
|  | // Build one packet with 3 PATH RESPONSES, with padding | 
|  | // clang-format off | 
|  | unsigned char packet[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // 3 path response frames (IETF_PATH_RESPONSE byte and payload) | 
|  | 0x1b, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, | 
|  | 0x1b, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, | 
|  | 0x1b, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, | 
|  | // Padding | 
|  | 0x00, 0x00, 0x00, 0x00, 0x00 | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | std::unique_ptr<char[]> buffer(new char[kMaxPacketSize]); | 
|  | QuicDeque<QuicPathFrameBuffer> payloads; | 
|  | payloads.push_back(payload0); | 
|  | payloads.push_back(payload1); | 
|  | payloads.push_back(payload2); | 
|  | size_t length = framer_.BuildPathResponsePacket( | 
|  | header, buffer.get(), QUIC_ARRAYSIZE(packet), payloads, | 
|  | /*is_padded=*/true, ENCRYPTION_INITIAL); | 
|  | EXPECT_EQ(length, QUIC_ARRAYSIZE(packet)); | 
|  | QuicPacket data(framer_.transport_version(), buffer.release(), length, true, | 
|  | header); | 
|  |  | 
|  | test::CompareCharArraysWithHexError("constructed packet", data.data(), | 
|  | data.length(), AsChars(packet), | 
|  | QUIC_ARRAYSIZE(packet)); | 
|  | } | 
|  |  | 
|  | // Test that the MTU discovery packet is serialized correctly as a PING packet. | 
|  | TEST_P(QuicFramerTest, BuildMtuDiscoveryPacket) { | 
|  | QuicPacketHeader header; | 
|  | header.destination_connection_id = FramerTestConnectionId(); | 
|  | header.reset_flag = false; | 
|  | header.version_flag = false; | 
|  | header.packet_number = kPacketNumber; | 
|  |  | 
|  | QuicFrames frames = {QuicFrame(QuicMtuDiscoveryFrame())}; | 
|  |  | 
|  | // clang-format off | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x28, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (ping frame) | 
|  | 0x07, | 
|  | }; | 
|  |  | 
|  | unsigned char packet44[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x32, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type | 
|  | 0x07, | 
|  | }; | 
|  |  | 
|  | unsigned char packet46[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type | 
|  | 0x07, | 
|  | }; | 
|  |  | 
|  | unsigned char packet99[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (IETF_PING frame) | 
|  | 0x01, | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  |  | 
|  | unsigned char* p = packet; | 
|  | if (framer_.transport_version() == QUIC_VERSION_99) { | 
|  | p = packet99; | 
|  | } else if (framer_.transport_version() > QUIC_VERSION_44) { | 
|  | p = packet46; | 
|  | } else if (framer_.transport_version() > QUIC_VERSION_43) { | 
|  | p = packet44; | 
|  | } | 
|  |  | 
|  | test::CompareCharArraysWithHexError( | 
|  | "constructed packet", data->data(), data->length(), AsChars(p), | 
|  | framer_.transport_version() > QUIC_VERSION_43 ? QUIC_ARRAYSIZE(packet44) | 
|  | : QUIC_ARRAYSIZE(packet)); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, BuildPublicResetPacket) { | 
|  | QuicPublicResetPacket reset_packet; | 
|  | reset_packet.connection_id = FramerTestConnectionId(); | 
|  | reset_packet.nonce_proof = kNonceProof; | 
|  |  | 
|  | // clang-format off | 
|  | unsigned char packet[] = { | 
|  | // public flags (public reset, 8 byte ConnectionId) | 
|  | 0x0E, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // message tag (kPRST) | 
|  | 'P', 'R', 'S', 'T', | 
|  | // num_entries (1) + padding | 
|  | 0x01, 0x00, 0x00, 0x00, | 
|  | // tag kRNON | 
|  | 'R', 'N', 'O', 'N', | 
|  | // end offset 8 | 
|  | 0x08, 0x00, 0x00, 0x00, | 
|  | // nonce proof | 
|  | 0x89, 0x67, 0x45, 0x23, | 
|  | 0x01, 0xEF, 0xCD, 0xAB, | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | if (framer_.transport_version() > QUIC_VERSION_43) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | std::unique_ptr<QuicEncryptedPacket> data( | 
|  | framer_.BuildPublicResetPacket(reset_packet)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  | test::CompareCharArraysWithHexError("constructed packet", data->data(), | 
|  | data->length(), AsChars(packet), | 
|  | QUIC_ARRAYSIZE(packet)); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, BuildPublicResetPacketWithClientAddress) { | 
|  | QuicPublicResetPacket reset_packet; | 
|  | reset_packet.connection_id = FramerTestConnectionId(); | 
|  | reset_packet.nonce_proof = kNonceProof; | 
|  | reset_packet.client_address = | 
|  | QuicSocketAddress(QuicIpAddress::Loopback4(), 0x1234); | 
|  |  | 
|  | // clang-format off | 
|  | unsigned char packet[] = { | 
|  | // public flags (public reset, 8 byte ConnectionId) | 
|  | 0x0E, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, | 
|  | 0x76, 0x54, 0x32, 0x10, | 
|  | // message tag (kPRST) | 
|  | 'P', 'R', 'S', 'T', | 
|  | // num_entries (2) + padding | 
|  | 0x02, 0x00, 0x00, 0x00, | 
|  | // tag kRNON | 
|  | 'R', 'N', 'O', 'N', | 
|  | // end offset 8 | 
|  | 0x08, 0x00, 0x00, 0x00, | 
|  | // tag kCADR | 
|  | 'C', 'A', 'D', 'R', | 
|  | // end offset 16 | 
|  | 0x10, 0x00, 0x00, 0x00, | 
|  | // nonce proof | 
|  | 0x89, 0x67, 0x45, 0x23, | 
|  | 0x01, 0xEF, 0xCD, 0xAB, | 
|  | // client address | 
|  | 0x02, 0x00, | 
|  | 0x7F, 0x00, 0x00, 0x01, | 
|  | 0x34, 0x12, | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | if (framer_.transport_version() > QUIC_VERSION_43) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | std::unique_ptr<QuicEncryptedPacket> data( | 
|  | framer_.BuildPublicResetPacket(reset_packet)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  |  | 
|  | test::CompareCharArraysWithHexError("constructed packet", data->data(), | 
|  | data->length(), AsChars(packet), | 
|  | QUIC_ARRAYSIZE(packet)); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, BuildPublicResetPacketWithEndpointId) { | 
|  | QuicPublicResetPacket reset_packet; | 
|  | reset_packet.connection_id = FramerTestConnectionId(); | 
|  | reset_packet.nonce_proof = kNonceProof; | 
|  | reset_packet.endpoint_id = "FakeServerId"; | 
|  |  | 
|  | // The tag value map in CryptoHandshakeMessage is a std::map, so the two tags | 
|  | // in the packet, kRNON and kEPID, have unspecified ordering w.r.t each other. | 
|  | // clang-format off | 
|  | unsigned char packet_variant1[] = { | 
|  | // public flags (public reset, 8 byte ConnectionId) | 
|  | 0x0E, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, | 
|  | 0x76, 0x54, 0x32, 0x10, | 
|  | // message tag (kPRST) | 
|  | 'P', 'R', 'S', 'T', | 
|  | // num_entries (2) + padding | 
|  | 0x02, 0x00, 0x00, 0x00, | 
|  | // tag kRNON | 
|  | 'R', 'N', 'O', 'N', | 
|  | // end offset 8 | 
|  | 0x08, 0x00, 0x00, 0x00, | 
|  | // tag kEPID | 
|  | 'E', 'P', 'I', 'D', | 
|  | // end offset 20 | 
|  | 0x14, 0x00, 0x00, 0x00, | 
|  | // nonce proof | 
|  | 0x89, 0x67, 0x45, 0x23, | 
|  | 0x01, 0xEF, 0xCD, 0xAB, | 
|  | // Endpoint ID | 
|  | 'F', 'a', 'k', 'e', 'S', 'e', 'r', 'v', 'e', 'r', 'I', 'd', | 
|  | }; | 
|  | unsigned char packet_variant2[] = { | 
|  | // public flags (public reset, 8 byte ConnectionId) | 
|  | 0x0E, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, | 
|  | 0x76, 0x54, 0x32, 0x10, | 
|  | // message tag (kPRST) | 
|  | 'P', 'R', 'S', 'T', | 
|  | // num_entries (2) + padding | 
|  | 0x02, 0x00, 0x00, 0x00, | 
|  | // tag kEPID | 
|  | 'E', 'P', 'I', 'D', | 
|  | // end offset 12 | 
|  | 0x0C, 0x00, 0x00, 0x00, | 
|  | // tag kRNON | 
|  | 'R', 'N', 'O', 'N', | 
|  | // end offset 20 | 
|  | 0x14, 0x00, 0x00, 0x00, | 
|  | // Endpoint ID | 
|  | 'F', 'a', 'k', 'e', 'S', 'e', 'r', 'v', 'e', 'r', 'I', 'd', | 
|  | // nonce proof | 
|  | 0x89, 0x67, 0x45, 0x23, | 
|  | 0x01, 0xEF, 0xCD, 0xAB, | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | if (framer_.transport_version() > QUIC_VERSION_43) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | std::unique_ptr<QuicEncryptedPacket> data( | 
|  | framer_.BuildPublicResetPacket(reset_packet)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  |  | 
|  | // Variant 1 ends with char 'd'. Variant 1 ends with char 0xAB. | 
|  | if ('d' == data->data()[data->length() - 1]) { | 
|  | test::CompareCharArraysWithHexError( | 
|  | "constructed packet", data->data(), data->length(), | 
|  | AsChars(packet_variant1), QUIC_ARRAYSIZE(packet_variant1)); | 
|  | } else { | 
|  | test::CompareCharArraysWithHexError( | 
|  | "constructed packet", data->data(), data->length(), | 
|  | AsChars(packet_variant2), QUIC_ARRAYSIZE(packet_variant2)); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, BuildIetfStatelessResetPacket) { | 
|  | // clang-format off | 
|  | unsigned char packet44[] = { | 
|  | // type (short header, 1 byte packet number) | 
|  | 0x70, | 
|  | // random packet number | 
|  | 0xFE, | 
|  | // stateless reset token | 
|  | 0xB5, 0x69, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, | 
|  | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | std::unique_ptr<QuicEncryptedPacket> data( | 
|  | framer_.BuildIetfStatelessResetPacket(FramerTestConnectionId(), | 
|  | kTestStatelessResetToken)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  | // Skip packet number byte which is random in stateless reset packet. | 
|  | test::CompareCharArraysWithHexError("constructed packet", data->data(), 1, | 
|  | AsChars(packet44), 1); | 
|  | const size_t random_bytes_length = | 
|  | data->length() - kPacketHeaderTypeSize - sizeof(kTestStatelessResetToken); | 
|  | EXPECT_EQ(kMinRandomBytesLengthInStatelessReset, random_bytes_length); | 
|  | // Verify stateless reset token is correct. | 
|  | test::CompareCharArraysWithHexError( | 
|  | "constructed packet", | 
|  | data->data() + data->length() - sizeof(kTestStatelessResetToken), | 
|  | sizeof(kTestStatelessResetToken), | 
|  | AsChars(packet44) + QUIC_ARRAYSIZE(packet44) - | 
|  | sizeof(kTestStatelessResetToken), | 
|  | sizeof(kTestStatelessResetToken)); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, EncryptPacket) { | 
|  | QuicPacketNumber packet_number = kPacketNumber; | 
|  | // clang-format off | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x28, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // redundancy | 
|  | 'a',  'b',  'c',  'd', | 
|  | 'e',  'f',  'g',  'h', | 
|  | 'i',  'j',  'k',  'l', | 
|  | 'm',  'n',  'o',  'p', | 
|  | }; | 
|  |  | 
|  | unsigned char packet44[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x32, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // redundancy | 
|  | 'a',  'b',  'c',  'd', | 
|  | 'e',  'f',  'g',  'h', | 
|  | 'i',  'j',  'k',  'l', | 
|  | 'm',  'n',  'o',  'p', | 
|  | }; | 
|  |  | 
|  | unsigned char packet46[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // redundancy | 
|  | 'a',  'b',  'c',  'd', | 
|  | 'e',  'f',  'g',  'h', | 
|  | 'i',  'j',  'k',  'l', | 
|  | 'm',  'n',  'o',  'p', | 
|  | }; | 
|  |  | 
|  | unsigned char packet99[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // redundancy | 
|  | 'a',  'b',  'c',  'd', | 
|  | 'e',  'f',  'g',  'h', | 
|  | 'i',  'j',  'k',  'l', | 
|  | 'm',  'n',  'o',  'p', | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | unsigned char* p = packet; | 
|  | if (framer_.transport_version() == QUIC_VERSION_99) { | 
|  | p = packet99; | 
|  | } else if (framer_.transport_version() > QUIC_VERSION_44) { | 
|  | p = packet46; | 
|  | } else if (framer_.transport_version() > QUIC_VERSION_43) { | 
|  | p = packet44; | 
|  | } | 
|  |  | 
|  | std::unique_ptr<QuicPacket> raw(new QuicPacket( | 
|  | AsChars(p), QUIC_ARRAYSIZE(packet), false, PACKET_8BYTE_CONNECTION_ID, | 
|  | PACKET_0BYTE_CONNECTION_ID, !kIncludeVersion, | 
|  | !kIncludeDiversificationNonce, PACKET_4BYTE_PACKET_NUMBER, | 
|  | VARIABLE_LENGTH_INTEGER_LENGTH_0, 0, VARIABLE_LENGTH_INTEGER_LENGTH_0)); | 
|  | char buffer[kMaxPacketSize]; | 
|  | size_t encrypted_length = framer_.EncryptPayload( | 
|  | ENCRYPTION_INITIAL, packet_number, *raw, buffer, kMaxPacketSize); | 
|  |  | 
|  | ASSERT_NE(0u, encrypted_length); | 
|  | EXPECT_TRUE(CheckEncryption(packet_number, raw.get())); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, EncryptPacketWithVersionFlag) { | 
|  | QuicPacketNumber packet_number = kPacketNumber; | 
|  | // clang-format off | 
|  | unsigned char packet[] = { | 
|  | // public flags (version, 8 byte connection_id) | 
|  | 0x29, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // version tag | 
|  | 'Q', '.', '1', '0', | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // redundancy | 
|  | 'a',  'b',  'c',  'd', | 
|  | 'e',  'f',  'g',  'h', | 
|  | 'i',  'j',  'k',  'l', | 
|  | 'm',  'n',  'o',  'p', | 
|  | }; | 
|  |  | 
|  | unsigned char packet44[] = { | 
|  | // type (long header with packet type ZERO_RTT_PROTECTED) | 
|  | 0xFC, | 
|  | // version tag | 
|  | 'Q', '.', '1', '0', | 
|  | // connection_id length | 
|  | 0x50, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // redundancy | 
|  | 'a',  'b',  'c',  'd', | 
|  | 'e',  'f',  'g',  'h', | 
|  | 'i',  'j',  'k',  'l', | 
|  | 'm',  'n',  'o',  'p', | 
|  | }; | 
|  |  | 
|  | unsigned char packet46[] = { | 
|  | // type (long header with packet type ZERO_RTT_PROTECTED) | 
|  | 0xD3, | 
|  | // version tag | 
|  | 'Q', '.', '1', '0', | 
|  | // connection_id length | 
|  | 0x50, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // redundancy | 
|  | 'a',  'b',  'c',  'd', | 
|  | 'e',  'f',  'g',  'h', | 
|  | 'i',  'j',  'k',  'l', | 
|  | 'm',  'n',  'o',  'p', | 
|  | }; | 
|  |  | 
|  | unsigned char packet99[] = { | 
|  | // type (long header with packet type ZERO_RTT_PROTECTED) | 
|  | 0xD3, | 
|  | // version tag | 
|  | 'Q', '.', '1', '0', | 
|  | // connection_id length | 
|  | 0x50, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // redundancy | 
|  | 'a',  'b',  'c',  'd', | 
|  | 'e',  'f',  'g',  'h', | 
|  | 'i',  'j',  'k',  'l', | 
|  | 'm',  'n',  'o',  'p', | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | unsigned char* p = packet; | 
|  | if (framer_.transport_version() == QUIC_VERSION_99) { | 
|  | p = packet99; | 
|  | } else if (framer_.transport_version() > QUIC_VERSION_44) { | 
|  | p = packet46; | 
|  | } else if (framer_.transport_version() > QUIC_VERSION_43) { | 
|  | p = packet44; | 
|  | } | 
|  |  | 
|  | std::unique_ptr<QuicPacket> raw(new QuicPacket( | 
|  | AsChars(p), | 
|  | framer_.transport_version() > QUIC_VERSION_43 ? QUIC_ARRAYSIZE(packet44) | 
|  | : QUIC_ARRAYSIZE(packet), | 
|  | false, PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID, | 
|  | kIncludeVersion, !kIncludeDiversificationNonce, | 
|  | PACKET_4BYTE_PACKET_NUMBER, VARIABLE_LENGTH_INTEGER_LENGTH_0, 0, | 
|  | VARIABLE_LENGTH_INTEGER_LENGTH_0)); | 
|  | char buffer[kMaxPacketSize]; | 
|  | size_t encrypted_length = framer_.EncryptPayload( | 
|  | ENCRYPTION_INITIAL, packet_number, *raw, buffer, kMaxPacketSize); | 
|  |  | 
|  | ASSERT_NE(0u, encrypted_length); | 
|  | EXPECT_TRUE(CheckEncryption(packet_number, raw.get())); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, AckTruncationLargePacket) { | 
|  | if (framer_.transport_version() == QUIC_VERSION_99) { | 
|  | // This test is not applicable to this version; the range count is | 
|  | // effectively unlimited | 
|  | return; | 
|  | } | 
|  |  | 
|  | QuicPacketHeader header; | 
|  | header.destination_connection_id = FramerTestConnectionId(); | 
|  | header.reset_flag = false; | 
|  | header.version_flag = false; | 
|  | header.packet_number = kPacketNumber; | 
|  |  | 
|  | QuicAckFrame ack_frame; | 
|  | // Create a packet with just the ack. | 
|  | ack_frame = MakeAckFrameWithAckBlocks(300, 0u); | 
|  | QuicFrames frames = {QuicFrame(&ack_frame)}; | 
|  |  | 
|  | // Build an ack packet with truncation due to limit in number of nack ranges. | 
|  | QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); | 
|  | std::unique_ptr<QuicPacket> raw_ack_packet(BuildDataPacket(header, frames)); | 
|  | ASSERT_TRUE(raw_ack_packet != nullptr); | 
|  | char buffer[kMaxPacketSize]; | 
|  | size_t encrypted_length = | 
|  | framer_.EncryptPayload(ENCRYPTION_INITIAL, header.packet_number, | 
|  | *raw_ack_packet, buffer, kMaxPacketSize); | 
|  | ASSERT_NE(0u, encrypted_length); | 
|  | // Now make sure we can turn our ack packet back into an ack frame. | 
|  | QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_SERVER); | 
|  | ASSERT_TRUE(framer_.ProcessPacket( | 
|  | QuicEncryptedPacket(buffer, encrypted_length, false))); | 
|  | ASSERT_EQ(1u, visitor_.ack_frames_.size()); | 
|  | QuicAckFrame& processed_ack_frame = *visitor_.ack_frames_[0]; | 
|  | EXPECT_EQ(QuicPacketNumber(600u), LargestAcked(processed_ack_frame)); | 
|  | ASSERT_EQ(256u, processed_ack_frame.packets.NumPacketsSlow()); | 
|  | EXPECT_EQ(QuicPacketNumber(90u), processed_ack_frame.packets.Min()); | 
|  | EXPECT_EQ(QuicPacketNumber(600u), processed_ack_frame.packets.Max()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, AckTruncationSmallPacket) { | 
|  | if (framer_.transport_version() == QUIC_VERSION_99) { | 
|  | // This test is not applicable to this version; the range count is | 
|  | // effectively unlimited | 
|  | return; | 
|  | } | 
|  |  | 
|  | QuicPacketHeader header; | 
|  | header.destination_connection_id = FramerTestConnectionId(); | 
|  | header.reset_flag = false; | 
|  | header.version_flag = false; | 
|  | header.packet_number = kPacketNumber; | 
|  |  | 
|  | // Create a packet with just the ack. | 
|  | QuicAckFrame ack_frame; | 
|  | ack_frame = MakeAckFrameWithAckBlocks(300, 0u); | 
|  | QuicFrames frames = {QuicFrame(&ack_frame)}; | 
|  |  | 
|  | // Build an ack packet with truncation due to limit in number of nack ranges. | 
|  | QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); | 
|  | std::unique_ptr<QuicPacket> raw_ack_packet( | 
|  | BuildDataPacket(header, frames, 500)); | 
|  | ASSERT_TRUE(raw_ack_packet != nullptr); | 
|  | char buffer[kMaxPacketSize]; | 
|  | size_t encrypted_length = | 
|  | framer_.EncryptPayload(ENCRYPTION_INITIAL, header.packet_number, | 
|  | *raw_ack_packet, buffer, kMaxPacketSize); | 
|  | ASSERT_NE(0u, encrypted_length); | 
|  | // Now make sure we can turn our ack packet back into an ack frame. | 
|  | QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_SERVER); | 
|  | ASSERT_TRUE(framer_.ProcessPacket( | 
|  | QuicEncryptedPacket(buffer, encrypted_length, false))); | 
|  | ASSERT_EQ(1u, visitor_.ack_frames_.size()); | 
|  | QuicAckFrame& processed_ack_frame = *visitor_.ack_frames_[0]; | 
|  | EXPECT_EQ(QuicPacketNumber(600u), LargestAcked(processed_ack_frame)); | 
|  | ASSERT_EQ(240u, processed_ack_frame.packets.NumPacketsSlow()); | 
|  | EXPECT_EQ(QuicPacketNumber(122u), processed_ack_frame.packets.Min()); | 
|  | EXPECT_EQ(QuicPacketNumber(600u), processed_ack_frame.packets.Max()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, CleanTruncation) { | 
|  | if (framer_.transport_version() == QUIC_VERSION_99) { | 
|  | // This test is not applicable to this version; the range count is | 
|  | // effectively unlimited | 
|  | return; | 
|  | } | 
|  |  | 
|  | QuicPacketHeader header; | 
|  | header.destination_connection_id = FramerTestConnectionId(); | 
|  | header.reset_flag = false; | 
|  | header.version_flag = false; | 
|  | header.packet_number = kPacketNumber; | 
|  |  | 
|  | QuicAckFrame ack_frame = InitAckFrame(201); | 
|  |  | 
|  | // Create a packet with just the ack. | 
|  | QuicFrames frames = {QuicFrame(&ack_frame)}; | 
|  | QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); | 
|  | std::unique_ptr<QuicPacket> raw_ack_packet(BuildDataPacket(header, frames)); | 
|  | ASSERT_TRUE(raw_ack_packet != nullptr); | 
|  |  | 
|  | char buffer[kMaxPacketSize]; | 
|  | size_t encrypted_length = | 
|  | framer_.EncryptPayload(ENCRYPTION_INITIAL, header.packet_number, | 
|  | *raw_ack_packet, buffer, kMaxPacketSize); | 
|  | ASSERT_NE(0u, encrypted_length); | 
|  |  | 
|  | // Now make sure we can turn our ack packet back into an ack frame. | 
|  | QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_SERVER); | 
|  | ASSERT_TRUE(framer_.ProcessPacket( | 
|  | QuicEncryptedPacket(buffer, encrypted_length, false))); | 
|  |  | 
|  | // Test for clean truncation of the ack by comparing the length of the | 
|  | // original packets to the re-serialized packets. | 
|  | frames.clear(); | 
|  | frames.push_back(QuicFrame(visitor_.ack_frames_[0].get())); | 
|  |  | 
|  | size_t original_raw_length = raw_ack_packet->length(); | 
|  | QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); | 
|  | raw_ack_packet = BuildDataPacket(header, frames); | 
|  | ASSERT_TRUE(raw_ack_packet != nullptr); | 
|  | EXPECT_EQ(original_raw_length, raw_ack_packet->length()); | 
|  | ASSERT_TRUE(raw_ack_packet != nullptr); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, StopPacketProcessing) { | 
|  | // clang-format off | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x28, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (stream frame with fin) | 
|  | 0xFF, | 
|  | // stream id | 
|  | 0x01, 0x02, 0x03, 0x04, | 
|  | // offset | 
|  | 0x3A, 0x98, 0xFE, 0xDC, | 
|  | 0x32, 0x10, 0x76, 0x54, | 
|  | // data length | 
|  | 0x00, 0x0c, | 
|  | // data | 
|  | 'h',  'e',  'l',  'l', | 
|  | 'o',  ' ',  'w',  'o', | 
|  | 'r',  'l',  'd',  '!', | 
|  |  | 
|  | // frame type (ack frame) | 
|  | 0x40, | 
|  | // least packet number awaiting an ack | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  | 0x9A, 0xA0, | 
|  | // largest observed packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  | 0x9A, 0xBF, | 
|  | // num missing packets | 
|  | 0x01, | 
|  | // missing packet | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  | 0x9A, 0xBE, | 
|  | }; | 
|  |  | 
|  | unsigned char packet44[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x32, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (stream frame with fin) | 
|  | 0xFF, | 
|  | // stream id | 
|  | 0x01, 0x02, 0x03, 0x04, | 
|  | // offset | 
|  | 0x3A, 0x98, 0xFE, 0xDC, | 
|  | 0x32, 0x10, 0x76, 0x54, | 
|  | // data length | 
|  | 0x00, 0x0c, | 
|  | // data | 
|  | 'h',  'e',  'l',  'l', | 
|  | 'o',  ' ',  'w',  'o', | 
|  | 'r',  'l',  'd',  '!', | 
|  |  | 
|  | // frame type (ack frame) | 
|  | 0x40, | 
|  | // least packet number awaiting an ack | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  | 0x9A, 0xA0, | 
|  | // largest observed packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  | 0x9A, 0xBF, | 
|  | // num missing packets | 
|  | 0x01, | 
|  | // missing packet | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  | 0x9A, 0xBE, | 
|  | }; | 
|  |  | 
|  | unsigned char packet46[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (stream frame with fin) | 
|  | 0xFF, | 
|  | // stream id | 
|  | 0x01, 0x02, 0x03, 0x04, | 
|  | // offset | 
|  | 0x3A, 0x98, 0xFE, 0xDC, | 
|  | 0x32, 0x10, 0x76, 0x54, | 
|  | // data length | 
|  | 0x00, 0x0c, | 
|  | // data | 
|  | 'h',  'e',  'l',  'l', | 
|  | 'o',  ' ',  'w',  'o', | 
|  | 'r',  'l',  'd',  '!', | 
|  |  | 
|  | // frame type (ack frame) | 
|  | 0x40, | 
|  | // least packet number awaiting an ack | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  | 0x9A, 0xA0, | 
|  | // largest observed packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  | 0x9A, 0xBF, | 
|  | // num missing packets | 
|  | 0x01, | 
|  | // missing packet | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  | 0x9A, 0xBE, | 
|  | }; | 
|  |  | 
|  | unsigned char packet99[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (IETF_STREAM frame with fin, length, and offset bits set) | 
|  | 0x08 | 0x01 | 0x02 | 0x04, | 
|  | // stream id | 
|  | kVarInt62FourBytes + 0x01, 0x02, 0x03, 0x04, | 
|  | // offset | 
|  | kVarInt62EightBytes + 0x3A, 0x98, 0xFE, 0xDC, | 
|  | 0x32, 0x10, 0x76, 0x54, | 
|  | // data length | 
|  | kVarInt62TwoBytes + 0x00, 0x0c, | 
|  | // data | 
|  | 'h',  'e',  'l',  'l', | 
|  | 'o',  ' ',  'w',  'o', | 
|  | 'r',  'l',  'd',  '!', | 
|  |  | 
|  | // frame type (ack frame) | 
|  | 0x0d, | 
|  | // largest observed packet number | 
|  | kVarInt62FourBytes + 0x12, 0x34, 0x56, 0x78, | 
|  | // Delta time | 
|  | kVarInt62OneByte + 0x00, | 
|  | // Ack Block count | 
|  | kVarInt62OneByte + 0x01, | 
|  | // First block size (one packet) | 
|  | kVarInt62OneByte + 0x00, | 
|  |  | 
|  | // Next gap size & ack. Missing all preceding packets | 
|  | kVarInt62FourBytes + 0x12, 0x34, 0x56, 0x77, | 
|  | kVarInt62OneByte + 0x00, | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | MockFramerVisitor visitor; | 
|  | framer_.set_visitor(&visitor); | 
|  | EXPECT_CALL(visitor, OnPacket()); | 
|  | EXPECT_CALL(visitor, OnPacketHeader(_)); | 
|  | EXPECT_CALL(visitor, OnStreamFrame(_)).WillOnce(Return(false)); | 
|  | EXPECT_CALL(visitor, OnPacketComplete()); | 
|  | EXPECT_CALL(visitor, OnUnauthenticatedPublicHeader(_)).WillOnce(Return(true)); | 
|  | EXPECT_CALL(visitor, OnUnauthenticatedHeader(_)).WillOnce(Return(true)); | 
|  | EXPECT_CALL(visitor, OnDecryptedPacket(_)); | 
|  |  | 
|  | unsigned char* p = packet; | 
|  | size_t p_size = QUIC_ARRAYSIZE(packet); | 
|  | if (framer_.transport_version() == QUIC_VERSION_99) { | 
|  | p = packet99; | 
|  | p_size = QUIC_ARRAYSIZE(packet99); | 
|  | } else if (framer_.transport_version() > QUIC_VERSION_44) { | 
|  | p = packet46; | 
|  | p_size = QUIC_ARRAYSIZE(packet46); | 
|  | } else if (framer_.transport_version() > QUIC_VERSION_43) { | 
|  | p = packet44; | 
|  | p_size = QUIC_ARRAYSIZE(packet44); | 
|  | } | 
|  | QuicEncryptedPacket encrypted(AsChars(p), p_size, false); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(encrypted)); | 
|  | EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | } | 
|  |  | 
|  | static char kTestString[] = "At least 20 characters."; | 
|  | static QuicStreamId kTestQuicStreamId = 1; | 
|  | static bool ExpectedStreamFrame(const QuicStreamFrame& frame) { | 
|  | return (frame.stream_id == kTestQuicStreamId || | 
|  | frame.stream_id == QuicUtils::GetCryptoStreamId(QUIC_VERSION_99)) && | 
|  | !frame.fin && frame.offset == 0 && | 
|  | std::string(frame.data_buffer, frame.data_length) == kTestString; | 
|  | // FIN is hard-coded false in ConstructEncryptedPacket. | 
|  | // Offset 0 is hard-coded in ConstructEncryptedPacket. | 
|  | } | 
|  |  | 
|  | // Verify that the packet returned by ConstructEncryptedPacket() can be properly | 
|  | // parsed by the framer. | 
|  | TEST_P(QuicFramerTest, ConstructEncryptedPacket) { | 
|  | // Since we are using ConstructEncryptedPacket, we have to set the framer's | 
|  | // crypto to be Null. | 
|  | framer_.SetDecrypter(ENCRYPTION_INITIAL, | 
|  | QuicMakeUnique<NullDecrypter>(framer_.perspective())); | 
|  | framer_.SetEncrypter(ENCRYPTION_INITIAL, | 
|  | QuicMakeUnique<NullEncrypter>(framer_.perspective())); | 
|  | ParsedQuicVersionVector versions; | 
|  | versions.push_back(framer_.version()); | 
|  | std::unique_ptr<QuicEncryptedPacket> packet(ConstructEncryptedPacket( | 
|  | TestConnectionId(), EmptyQuicConnectionId(), false, false, | 
|  | kTestQuicStreamId, kTestString, CONNECTION_ID_PRESENT, | 
|  | CONNECTION_ID_ABSENT, PACKET_4BYTE_PACKET_NUMBER, &versions)); | 
|  |  | 
|  | MockFramerVisitor visitor; | 
|  | framer_.set_visitor(&visitor); | 
|  | EXPECT_CALL(visitor, OnPacket()).Times(1); | 
|  | EXPECT_CALL(visitor, OnUnauthenticatedPublicHeader(_)) | 
|  | .Times(1) | 
|  | .WillOnce(Return(true)); | 
|  | EXPECT_CALL(visitor, OnUnauthenticatedHeader(_)) | 
|  | .Times(1) | 
|  | .WillOnce(Return(true)); | 
|  | EXPECT_CALL(visitor, OnPacketHeader(_)).Times(1).WillOnce(Return(true)); | 
|  | EXPECT_CALL(visitor, OnDecryptedPacket(_)).Times(1); | 
|  | EXPECT_CALL(visitor, OnError(_)).Times(0); | 
|  | EXPECT_CALL(visitor, OnStreamFrame(_)).Times(0); | 
|  | if (!QuicVersionUsesCryptoFrames(framer_.version().transport_version)) { | 
|  | EXPECT_CALL(visitor, OnStreamFrame(Truly(ExpectedStreamFrame))).Times(1); | 
|  | } else { | 
|  | EXPECT_CALL(visitor, OnCryptoFrame(_)).Times(1); | 
|  | } | 
|  | EXPECT_CALL(visitor, OnPacketComplete()).Times(1); | 
|  |  | 
|  | EXPECT_TRUE(framer_.ProcessPacket(*packet)); | 
|  | EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | } | 
|  |  | 
|  | // Verify that the packet returned by ConstructMisFramedEncryptedPacket() | 
|  | // does cause the framer to return an error. | 
|  | TEST_P(QuicFramerTest, ConstructMisFramedEncryptedPacket) { | 
|  | // Since we are using ConstructEncryptedPacket, we have to set the framer's | 
|  | // crypto to be Null. | 
|  | framer_.SetDecrypter(ENCRYPTION_INITIAL, | 
|  | QuicMakeUnique<NullDecrypter>(framer_.perspective())); | 
|  | framer_.SetEncrypter(ENCRYPTION_INITIAL, | 
|  | QuicMakeUnique<NullEncrypter>(framer_.perspective())); | 
|  | ParsedQuicVersionVector versions; | 
|  | versions.push_back(framer_.version()); | 
|  | std::unique_ptr<QuicEncryptedPacket> packet(ConstructMisFramedEncryptedPacket( | 
|  | TestConnectionId(), EmptyQuicConnectionId(), false, false, | 
|  | kTestQuicStreamId, kTestString, CONNECTION_ID_PRESENT, | 
|  | CONNECTION_ID_ABSENT, PACKET_4BYTE_PACKET_NUMBER, &versions, | 
|  | Perspective::IS_CLIENT)); | 
|  |  | 
|  | MockFramerVisitor visitor; | 
|  | framer_.set_visitor(&visitor); | 
|  | EXPECT_CALL(visitor, OnPacket()).Times(1); | 
|  | EXPECT_CALL(visitor, OnUnauthenticatedPublicHeader(_)) | 
|  | .Times(1) | 
|  | .WillOnce(Return(true)); | 
|  | EXPECT_CALL(visitor, OnUnauthenticatedHeader(_)) | 
|  | .Times(1) | 
|  | .WillOnce(Return(true)); | 
|  | EXPECT_CALL(visitor, OnPacketHeader(_)).Times(1); | 
|  | EXPECT_CALL(visitor, OnDecryptedPacket(_)).Times(1); | 
|  | EXPECT_CALL(visitor, OnError(_)).Times(1); | 
|  | EXPECT_CALL(visitor, OnStreamFrame(_)).Times(0); | 
|  | EXPECT_CALL(visitor, OnPacketComplete()).Times(0); | 
|  |  | 
|  | EXPECT_FALSE(framer_.ProcessPacket(*packet)); | 
|  | EXPECT_EQ(QUIC_INVALID_FRAME_DATA, framer_.error()); | 
|  | } | 
|  |  | 
|  | // Tests for fuzzing with Dr. Fuzz | 
|  | // Xref http://www.chromium.org/developers/testing/dr-fuzz for more details. | 
|  | #ifdef __cplusplus | 
|  | extern "C" { | 
|  | #endif | 
|  |  | 
|  | // target function to be fuzzed by Dr. Fuzz | 
|  | void QuicFramerFuzzFunc(unsigned char* data, | 
|  | size_t size, | 
|  | const ParsedQuicVersion& version) { | 
|  | QuicFramer framer(AllSupportedVersions(), QuicTime::Zero(), | 
|  | Perspective::IS_SERVER, kQuicDefaultConnectionIdLength); | 
|  | ASSERT_EQ(GetQuicFlag(FLAGS_quic_supports_tls_handshake), true); | 
|  | const char* const packet_bytes = reinterpret_cast<const char*>(data); | 
|  |  | 
|  | // Test the CryptoFramer. | 
|  | QuicStringPiece crypto_input(packet_bytes, size); | 
|  | std::unique_ptr<CryptoHandshakeMessage> handshake_message( | 
|  | CryptoFramer::ParseMessage(crypto_input)); | 
|  |  | 
|  | // Test the regular QuicFramer with the same input. | 
|  | NoOpFramerVisitor visitor; | 
|  | framer.set_visitor(&visitor); | 
|  | framer.set_version(version); | 
|  | QuicEncryptedPacket packet(packet_bytes, size); | 
|  | framer.ProcessPacket(packet); | 
|  | } | 
|  |  | 
|  | #ifdef __cplusplus | 
|  | } | 
|  | #endif | 
|  |  | 
|  | TEST_P(QuicFramerTest, FramerFuzzTest) { | 
|  | // clang-format off | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x2C, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  | // private flags | 
|  | 0x00, | 
|  |  | 
|  | // frame type (stream frame with fin) | 
|  | 0xFF, | 
|  | // stream id | 
|  | 0x01, 0x02, 0x03, 0x04, | 
|  | // offset | 
|  | 0x3A, 0x98, 0xFE, 0xDC, | 
|  | 0x32, 0x10, 0x76, 0x54, | 
|  | // data length | 
|  | 0x00, 0x0c, | 
|  | // data | 
|  | 'h',  'e',  'l',  'l', | 
|  | 'o',  ' ',  'w',  'o', | 
|  | 'r',  'l',  'd',  '!', | 
|  | }; | 
|  |  | 
|  | unsigned char packet44[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x32, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (stream frame with fin, length, and offset bits set) | 
|  | 0x10 | 0x01 | 0x02 | 0x04, | 
|  | // stream id | 
|  | 0x01, 0x02, 0x03, 0x04, | 
|  | // offset | 
|  | 0x3A, 0x98, 0xFE, 0xDC, | 
|  | 0x32, 0x10, 0x76, 0x54, | 
|  | // data length | 
|  | 0x00, 0x0c, | 
|  | // data | 
|  | 'h',  'e',  'l',  'l', | 
|  | 'o',  ' ',  'w',  'o', | 
|  | 'r',  'l',  'd',  '!', | 
|  | }; | 
|  |  | 
|  | unsigned char packet46[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (stream frame with fin, length, and offset bits set) | 
|  | 0x10 | 0x01 | 0x02 | 0x04, | 
|  | // stream id | 
|  | 0x01, 0x02, 0x03, 0x04, | 
|  | // offset | 
|  | 0x3A, 0x98, 0xFE, 0xDC, | 
|  | 0x32, 0x10, 0x76, 0x54, | 
|  | // data length | 
|  | 0x00, 0x0c, | 
|  | // data | 
|  | 'h',  'e',  'l',  'l', | 
|  | 'o',  ' ',  'w',  'o', | 
|  | 'r',  'l',  'd',  '!', | 
|  | }; | 
|  |  | 
|  | unsigned char packet99[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (IETF_STREAM frame with fin, length, and offset bits set) | 
|  | 0x08 | 0x01 | 0x02 | 0x04, | 
|  | // stream id | 
|  | 0x01, 0x02, 0x03, 0x04, | 
|  | // offset | 
|  | 0x3A, 0x98, 0xFE, 0xDC, | 
|  | 0x32, 0x10, 0x76, 0x54, | 
|  | // data length | 
|  | 0x00, 0x0c, | 
|  | // data | 
|  | 'h',  'e',  'l',  'l', | 
|  | 'o',  ' ',  'w',  'o', | 
|  | 'r',  'l',  'd',  '!', | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | unsigned char* p = packet; | 
|  | if (framer_.transport_version() == QUIC_VERSION_99) { | 
|  | p = packet99; | 
|  | } else if (framer_.transport_version() > QUIC_VERSION_44) { | 
|  | p = packet46; | 
|  | } else if (framer_.transport_version() > QUIC_VERSION_43) { | 
|  | p = packet44; | 
|  | } | 
|  | QuicFramerFuzzFunc(p, | 
|  | framer_.transport_version() > QUIC_VERSION_43 | 
|  | ? QUIC_ARRAYSIZE(packet44) | 
|  | : QUIC_ARRAYSIZE(packet), | 
|  | framer_.version()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, StartsWithChlo) { | 
|  | SimpleDataProducer producer; | 
|  | framer_.set_data_producer(&producer); | 
|  | QuicStringPiece data("CHLOCHLO"); | 
|  | struct iovec iovec; | 
|  | iovec.iov_base = const_cast<char*>(data.data()); | 
|  | iovec.iov_len = data.length(); | 
|  | producer.SaveStreamData( | 
|  | QuicUtils::GetCryptoStreamId(framer_.transport_version()), &iovec, 1, 0, | 
|  | data.length()); | 
|  | for (size_t offset = 0; offset < 5; ++offset) { | 
|  | if (offset == 0 || offset == 4) { | 
|  | EXPECT_TRUE(framer_.StartsWithChlo( | 
|  | QuicUtils::GetCryptoStreamId(framer_.transport_version()), offset)); | 
|  | } else { | 
|  | EXPECT_FALSE(framer_.StartsWithChlo( | 
|  | QuicUtils::GetCryptoStreamId(framer_.transport_version()), offset)); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, IetfBlockedFrame) { | 
|  | // This test only for version 99. | 
|  | if (framer_.transport_version() != QUIC_VERSION_99) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | // clang-format off | 
|  | PacketFragments packet99 = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x9A, 0xBC}}, | 
|  | // frame type (IETF_BLOCKED) | 
|  | {"", | 
|  | {0x14}}, | 
|  | // blocked offset | 
|  | {"Can not read blocked offset.", | 
|  | {kVarInt62EightBytes + 0x3a, 0x98, 0xFE, 0xDC, 0x32, 0x10, 0x76, 0x54}}, | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | std::unique_ptr<QuicEncryptedPacket> encrypted( | 
|  | AssemblePacketFromFragments(packet99)); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); | 
|  |  | 
|  | EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_TRUE(CheckDecryption( | 
|  | *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, | 
|  | PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); | 
|  |  | 
|  | EXPECT_EQ(kStreamOffset, visitor_.blocked_frame_.offset); | 
|  |  | 
|  | CheckFramingBoundaries(packet99, QUIC_INVALID_BLOCKED_DATA); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, BuildIetfBlockedPacket) { | 
|  | // This test only for version 99. | 
|  | if (framer_.transport_version() != QUIC_VERSION_99) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | QuicPacketHeader header; | 
|  | header.destination_connection_id = FramerTestConnectionId(); | 
|  | header.reset_flag = false; | 
|  | header.version_flag = false; | 
|  | header.packet_number = kPacketNumber; | 
|  |  | 
|  | QuicBlockedFrame frame; | 
|  | frame.stream_id = QuicUtils::GetInvalidStreamId(framer_.transport_version()); | 
|  | frame.offset = kStreamOffset; | 
|  | QuicFrames frames = {QuicFrame(&frame)}; | 
|  |  | 
|  | // clang-format off | 
|  | unsigned char packet99[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (IETF_BLOCKED) | 
|  | 0x14, | 
|  | // Offset | 
|  | kVarInt62EightBytes + 0x3a, 0x98, 0xFE, 0xDC, 0x32, 0x10, 0x76, 0x54 | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  |  | 
|  | test::CompareCharArraysWithHexError("constructed packet", data->data(), | 
|  | data->length(), AsChars(packet99), | 
|  | QUIC_ARRAYSIZE(packet99)); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, IetfStreamBlockedFrame) { | 
|  | // This test only for version 99. | 
|  | if (framer_.transport_version() != QUIC_VERSION_99) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | // clang-format off | 
|  | PacketFragments packet99 = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x9A, 0xBC}}, | 
|  | // frame type (IETF_STREAM_BLOCKED) | 
|  | {"", | 
|  | {0x15}}, | 
|  | // blocked offset | 
|  | {"Can not read stream blocked stream id.", | 
|  | {kVarInt62FourBytes + 0x01, 0x02, 0x03, 0x04}}, | 
|  | {"Can not read stream blocked offset.", | 
|  | {kVarInt62EightBytes + 0x3a, 0x98, 0xFE, 0xDC, 0x32, 0x10, 0x76, 0x54}}, | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | std::unique_ptr<QuicEncryptedPacket> encrypted( | 
|  | AssemblePacketFromFragments(packet99)); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); | 
|  |  | 
|  | EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_TRUE(CheckDecryption( | 
|  | *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, | 
|  | PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); | 
|  |  | 
|  | EXPECT_EQ(kStreamId, visitor_.blocked_frame_.stream_id); | 
|  | EXPECT_EQ(kStreamOffset, visitor_.blocked_frame_.offset); | 
|  |  | 
|  | CheckFramingBoundaries(packet99, QUIC_INVALID_STREAM_BLOCKED_DATA); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, BuildIetfStreamBlockedPacket) { | 
|  | // This test only for version 99. | 
|  | if (framer_.transport_version() != QUIC_VERSION_99) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | QuicPacketHeader header; | 
|  | header.destination_connection_id = FramerTestConnectionId(); | 
|  | header.reset_flag = false; | 
|  | header.version_flag = false; | 
|  | header.packet_number = kPacketNumber; | 
|  |  | 
|  | QuicBlockedFrame frame; | 
|  | frame.stream_id = kStreamId; | 
|  | frame.offset = kStreamOffset; | 
|  | QuicFrames frames = {QuicFrame(&frame)}; | 
|  |  | 
|  | // clang-format off | 
|  | unsigned char packet99[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (IETF_STREAM_BLOCKED) | 
|  | 0x15, | 
|  | // Stream ID | 
|  | kVarInt62FourBytes + 0x01, 0x02, 0x03, 0x04, | 
|  | // Offset | 
|  | kVarInt62EightBytes + 0x3a, 0x98, 0xFE, 0xDC, 0x32, 0x10, 0x76, 0x54 | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  |  | 
|  | test::CompareCharArraysWithHexError("constructed packet", data->data(), | 
|  | data->length(), AsChars(packet99), | 
|  | QUIC_ARRAYSIZE(packet99)); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, ServerBiDiMaxStreamsFrame) { | 
|  | // This test only for version 99. | 
|  | if (framer_.transport_version() != QUIC_VERSION_99) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | // clang-format off | 
|  | PacketFragments packet99 = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x9A, 0xBC}}, | 
|  | // frame type (IETF_MAX_STREAMS_BIDIRECTIONAL) | 
|  | {"", | 
|  | {0x12}}, | 
|  | // max. streams | 
|  | {"Can not read MAX_STREAMS stream count.", | 
|  | {kVarInt62OneByte + 0x03}}, | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | std::unique_ptr<QuicEncryptedPacket> encrypted( | 
|  | AssemblePacketFromFragments(packet99)); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); | 
|  |  | 
|  | EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_TRUE(CheckDecryption( | 
|  | *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, | 
|  | PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); | 
|  |  | 
|  | // This test is a server receiving a MAX_STREAMS frame. The | 
|  | // stream ID that it generates should be a server-initiated | 
|  | // stream ID. The expected Stream ID is | 
|  | //                 ((0x3-1) * 4) | 0x1 = 0x9 | 
|  | //                  count-to-id      server inited, bidi | 
|  | EXPECT_EQ(GetNthStreamid(QUIC_VERSION_99, Perspective::IS_SERVER, | 
|  | /*bidirectional=*/true, 3), | 
|  | visitor_.max_stream_id_frame_.max_stream_id); | 
|  | CheckFramingBoundaries(packet99, QUIC_MAX_STREAM_ID_DATA); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, ClientBiDiMaxStreamsFrame) { | 
|  | // This test only for version 99. | 
|  | if (framer_.transport_version() != QUIC_VERSION_99) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | // clang-format off | 
|  | PacketFragments packet99 = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // Test runs in client mode, no connection id | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x9A, 0xBC}}, | 
|  | // frame type (IETF_MAX_STREAMS_BIDIRECTIONAL) | 
|  | {"", | 
|  | {0x12}}, | 
|  | // max. streams | 
|  | {"Can not read MAX_STREAMS stream count.", | 
|  | {kVarInt62OneByte + 0x03}}, | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | std::unique_ptr<QuicEncryptedPacket> encrypted( | 
|  | AssemblePacketFromFragments(packet99)); | 
|  | QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); | 
|  |  | 
|  | EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_TRUE(CheckDecryption( | 
|  | *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, | 
|  | PACKET_0BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); | 
|  |  | 
|  | // This test is a client receiving a MAX_STREAMS frame. The | 
|  | // stream ID that it generates should be a client-initiated | 
|  | // stream ID. The expected Stream ID is | 
|  | //                ((0x3-1) * 4)       = 0xc | 
|  | // It is not 8 because a client-initiated, bidi stream ID's | 
|  | // low bits are 00 - which means that the old crypto stream | 
|  | // falls into this category, and the first stream is streamid=4, | 
|  | // not streamid=0. | 
|  | EXPECT_EQ(GetNthStreamid(QUIC_VERSION_99, Perspective::IS_CLIENT, | 
|  | /*bidirectional=*/true, 3), | 
|  | visitor_.max_stream_id_frame_.max_stream_id); | 
|  |  | 
|  | CheckFramingBoundaries(packet99, QUIC_MAX_STREAM_ID_DATA); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, ServerUniDiMaxStreamsFrame) { | 
|  | // This test only for version 99. | 
|  | if (framer_.transport_version() != QUIC_VERSION_99) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | // clang-format off | 
|  | PacketFragments packet99 = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x9A, 0xBC}}, | 
|  | // frame type (IETF_MAX_STREAMS_UNIDIRECTIONAL) | 
|  | {"", | 
|  | {0x13}}, | 
|  | // max. streams | 
|  | {"Can not read MAX_STREAMS stream count.", | 
|  | {kVarInt62OneByte + 0x03}}, | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | std::unique_ptr<QuicEncryptedPacket> encrypted( | 
|  | AssemblePacketFromFragments(packet99)); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); | 
|  |  | 
|  | EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_TRUE(CheckDecryption( | 
|  | *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, | 
|  | PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); | 
|  |  | 
|  | // This test is a server receiving a MAX_STREAMS frame. The | 
|  | // stream ID that it generates should be a server-initiated | 
|  | // stream ID. The expected Stream ID is | 
|  | //      ((0x3-1) * 4) | 0x1 | 0x2 = 0xb | 
|  | //        count-to-id      server inited, unidi | 
|  | EXPECT_EQ(GetNthStreamid(QUIC_VERSION_99, Perspective::IS_SERVER, | 
|  | /*bidirectional=*/false, 3), | 
|  | visitor_.max_stream_id_frame_.max_stream_id); | 
|  |  | 
|  | CheckFramingBoundaries(packet99, QUIC_MAX_STREAM_ID_DATA); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, ClientUniDiMaxStreamsFrame) { | 
|  | // This test only for version 99. | 
|  | if (framer_.transport_version() != QUIC_VERSION_99) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | // clang-format off | 
|  | PacketFragments packet99 = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // Test runs in client mode, no connection id | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x9A, 0xBC}}, | 
|  | // frame type (IETF_MAX_STREAMS_UNIDIRECTIONAL) | 
|  | {"", | 
|  | {0x13}}, | 
|  | // max. streams | 
|  | {"Can not read MAX_STREAMS stream count.", | 
|  | {kVarInt62OneByte + 0x03}}, | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | std::unique_ptr<QuicEncryptedPacket> encrypted( | 
|  | AssemblePacketFromFragments(packet99)); | 
|  | QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); | 
|  |  | 
|  | EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_TRUE(CheckDecryption( | 
|  | *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, | 
|  | PACKET_0BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); | 
|  |  | 
|  | // This test is a client receiving a MAX_STREAMS frame. The | 
|  | // stream ID that it generates should be a client-initiated | 
|  | // stream ID. The expected Stream ID is | 
|  | //               ((0x3-1) * 4) | 0x02= 0xa | 
|  | //                count-to-id      client/unidi | 
|  | EXPECT_EQ(GetNthStreamid(QUIC_VERSION_99, Perspective::IS_CLIENT, | 
|  | /*bidirectional=*/false, 3), | 
|  | visitor_.max_stream_id_frame_.max_stream_id); | 
|  |  | 
|  | CheckFramingBoundaries(packet99, QUIC_MAX_STREAM_ID_DATA); | 
|  | } | 
|  |  | 
|  | // The following four tests ensure that the framer can deserialize a stream | 
|  | // count that is large enough to cause the resulting stream ID to exceed the | 
|  | // current implementation limit(32 bits). The intent is that when this happens, | 
|  | // the stream limit is pegged to the maximum supported value. There are four | 
|  | // tests, for the four combinations of uni- and bi-directional, server- and | 
|  | // client- initiated. | 
|  | TEST_P(QuicFramerTest, ServerBiDiMaxStreamsFrameTooBig) { | 
|  | // This test only for version 99. | 
|  | if (framer_.transport_version() != QUIC_VERSION_99) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | // clang-format off | 
|  | unsigned char packet99[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x9A, 0xBC, | 
|  | // frame type (IETF_MAX_STREAMS_BIDIRECTIONAL) | 
|  | 0x12, | 
|  |  | 
|  | // max. streams. Max stream ID allowed is 0xffffffff | 
|  | // This encodes a count of 0x40000000, leading to stream | 
|  | // IDs in the range 0x1 00000000 to 0x1 00000003. | 
|  | kVarInt62EightBytes + 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00 | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | QuicEncryptedPacket encrypted(AsChars(packet99), QUIC_ARRAYSIZE(packet99), | 
|  | false); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(encrypted)); | 
|  | EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_TRUE(CheckDecryption( | 
|  | encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, | 
|  | PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); | 
|  |  | 
|  | // This test is a server receiving a MAX_STREAMS frame. The | 
|  | // stream ID that it generates should be a server-initiated | 
|  | // stream ID. The expected Stream ID is | 
|  | //            0xfffffffc | 0x01  --> 0xfffffffd | 
|  | //              maxid     server inited, bidi | 
|  | EXPECT_EQ(GetNthStreamid(QUIC_VERSION_99, Perspective::IS_SERVER, | 
|  | /*bidirectional=*/true, 0x40000000), | 
|  | visitor_.max_stream_id_frame_.max_stream_id); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, ClientBiDiMaxStreamsFrameTooBig) { | 
|  | // This test only for version 99. | 
|  | if (framer_.transport_version() != QUIC_VERSION_99) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | // clang-format off | 
|  | unsigned char packet99[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // Test runs in client mode, no connection id | 
|  | // packet number | 
|  | 0x12, 0x34, 0x9A, 0xBC, | 
|  | // frame type (IETF_MAX_STREAMS_BIDIRECTIONAL) | 
|  | 0x12, | 
|  |  | 
|  | // max. streams. Max stream ID allowed is 0xffffffff | 
|  | // This encodes a count of 0x40000000, leading to stream | 
|  | // IDs in the range 0x1 00000000 to 0x1 00000003. | 
|  | kVarInt62EightBytes + 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00 | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | QuicEncryptedPacket encrypted(AsChars(packet99), QUIC_ARRAYSIZE(packet99), | 
|  | false); | 
|  | QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(encrypted)); | 
|  |  | 
|  | EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_TRUE(CheckDecryption( | 
|  | encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, | 
|  | PACKET_0BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); | 
|  |  | 
|  | // This test is a client receiving a MAX_STREAMS frame. The | 
|  | // stream ID that it generates should be a client-initiated | 
|  | // stream ID. The expected Stream ID is | 
|  | //            0xfffffffc         --> 0xfffffffc | 
|  | //            max id       bidi/client-inited | 
|  | // TODO(fkastenholz): Change -2 to -1 when stream id 0 is no longer | 
|  | // special. | 
|  | // Subtract 1 because client/bidi stream ids start counting at | 
|  | // 4, not 0. If we didn;t subtract 1, the resulting math would wrap to stream | 
|  | // id 0, not 0xfffffffc. | 
|  | EXPECT_EQ(GetNthStreamid(QUIC_VERSION_99, Perspective::IS_CLIENT, | 
|  | /*bidirectional=*/true, (0x40000000 - 1)), | 
|  | visitor_.max_stream_id_frame_.max_stream_id); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, ServerUniDiMaxStreamsFrameTooBig) { | 
|  | // This test only for version 99. | 
|  | if (framer_.transport_version() != QUIC_VERSION_99) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | // clang-format off | 
|  | unsigned char packet99[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x9A, 0xBC, | 
|  | // frame type (IETF_MAX_STREAMS_UNIDIRECTIONAL) | 
|  | 0x13, | 
|  |  | 
|  | // max. streams. Max stream ID allowed is 0xffffffff | 
|  | // This encodes a count of 0x40000000, leading to stream | 
|  | // IDs in the range 0x1 00000000 to 0x1 00000003. | 
|  | kVarInt62EightBytes + 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00 | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | QuicEncryptedPacket encrypted(AsChars(packet99), QUIC_ARRAYSIZE(packet99), | 
|  | false); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(encrypted)); | 
|  |  | 
|  | EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_TRUE(CheckDecryption( | 
|  | encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, | 
|  | PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); | 
|  |  | 
|  | // This test is a server receiving a MAX_STREAMS frame. The | 
|  | // stream ID that it generates should be a server-initiated | 
|  | // stream ID. The expected Stream ID is | 
|  | //      0xfffffffc | 0x1 | 0x2 = 0xffffffff | 
|  | //        maxid      server inited, unidi | 
|  | EXPECT_EQ(GetNthStreamid(QUIC_VERSION_99, Perspective::IS_SERVER, | 
|  | /*bidirectional=*/false, 0x40000000), | 
|  | visitor_.max_stream_id_frame_.max_stream_id); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, ClientUniDiMaxStreamsFrameTooBig) { | 
|  | // This test only for version 99. | 
|  | if (framer_.transport_version() != QUIC_VERSION_99) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | // clang-format off | 
|  | unsigned char packet99[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // Test runs in client mode, no connection id | 
|  | // packet number | 
|  | 0x12, 0x34, 0x9A, 0xBC, | 
|  | // frame type (IETF_MAX_STREAMS_UNDIRECTIONAL) | 
|  | 0x13, | 
|  |  | 
|  | // max. streams. Max stream ID allowed is 0xffffffff | 
|  | // This encodes a count of 0x40000000, leading to stream | 
|  | // IDs in the range 0x1 00000000 to 0x1 00000003. | 
|  | kVarInt62EightBytes + 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00 | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | QuicEncryptedPacket encrypted(AsChars(packet99), QUIC_ARRAYSIZE(packet99), | 
|  | false); | 
|  | QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(encrypted)); | 
|  |  | 
|  | EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_TRUE(CheckDecryption( | 
|  | encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, | 
|  | PACKET_0BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); | 
|  |  | 
|  | // This test is a client receiving a MAX_STREAMS frame. The | 
|  | // stream ID that it generates should be a client-initiated | 
|  | // stream ID. The expected Stream ID is | 
|  | //               0xfffffffc | 0x02= 0xfffffffe | 
|  | //                maxid       client/unidi | 
|  | EXPECT_EQ(GetNthStreamid(QUIC_VERSION_99, Perspective::IS_CLIENT, | 
|  | /*bidirectional=*/false, 0x40000000), | 
|  | visitor_.max_stream_id_frame_.max_stream_id); | 
|  | } | 
|  |  | 
|  | // Check that a stream count of 0 is rejected. | 
|  | // Directionality and intiation are not important for | 
|  | // this test. | 
|  | TEST_P(QuicFramerTest, MaxStreamsFrameZeroCount) { | 
|  | // This test only for version 99. | 
|  | if (framer_.transport_version() != QUIC_VERSION_99) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | // clang-format off | 
|  | unsigned char packet99[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x9A, 0xBC, | 
|  | // frame type (IETF_MAX_STREAMS_BIDIRECTIONAL) | 
|  | 0x12, | 
|  | // max. streams == 0. | 
|  | kVarInt62OneByte + 0x00 | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | QuicEncryptedPacket encrypted(AsChars(packet99), QUIC_ARRAYSIZE(packet99), | 
|  | false); | 
|  | EXPECT_FALSE(framer_.ProcessPacket(encrypted)); | 
|  | EXPECT_EQ(QUIC_MAX_STREAM_ID_DATA, framer_.error()); | 
|  | EXPECT_EQ(framer_.detailed_error(), | 
|  | "MAX_STREAMS stream count of 0 not supported."); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, ServerBiDiStreamsBlockedFrame) { | 
|  | // This test only for version 99. | 
|  | if (framer_.transport_version() != QUIC_VERSION_99) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | // clang-format off | 
|  | PacketFragments packet99 = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x9A, 0xBC}}, | 
|  | // frame type (IETF_STREAMS_BLOCKED_BIDIRECTIONAL frame) | 
|  | {"", | 
|  | {0x16}}, | 
|  | // stream id | 
|  | {"Can not read STREAMS_BLOCKED stream id.", | 
|  | {kVarInt62OneByte + 0x03}}, | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | std::unique_ptr<QuicEncryptedPacket> encrypted( | 
|  | AssemblePacketFromFragments(packet99)); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); | 
|  |  | 
|  | EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_TRUE(CheckDecryption( | 
|  | *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, | 
|  | PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); | 
|  |  | 
|  | // This test is a server receiving a STREAMS_BLOCKED frame. The | 
|  | // stream ID that it generates should be a client-initiated | 
|  | // stream ID. The expected Stream ID is | 
|  | //                ((0x3-1) * 4)        = 0xc | 
|  | //                 count-to-id      client inited, bidi | 
|  | // It is not 8 because a client-initiated, bidi stream ID's | 
|  | // low bits are 00 - which means that the old crypto stream | 
|  | // falls into this category, and the first stream is streamid=4, | 
|  | // not streamid=0. | 
|  | EXPECT_EQ(GetNthStreamid(QUIC_VERSION_99, Perspective::IS_CLIENT, | 
|  | /*bidirectional=*/true, 3), | 
|  | visitor_.stream_id_blocked_frame_.stream_id); | 
|  |  | 
|  | CheckFramingBoundaries(packet99, QUIC_STREAM_ID_BLOCKED_DATA); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, ClientBiDiStreamsBlockedFrame) { | 
|  | // This test only for version 99. | 
|  | if (framer_.transport_version() != QUIC_VERSION_99) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | // clang-format off | 
|  | PacketFragments packet99 = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // Test runs in client mode, no connection id | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x9A, 0xBC}}, | 
|  | // frame type (IETF_STREAMS_BLOCKED_BIDIRECTIONAL frame) | 
|  | {"", | 
|  | {0x16}}, | 
|  | // stream id | 
|  | {"Can not read STREAMS_BLOCKED stream id.", | 
|  | {kVarInt62OneByte + 0x03}}, | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | std::unique_ptr<QuicEncryptedPacket> encrypted( | 
|  | AssemblePacketFromFragments(packet99)); | 
|  | QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); | 
|  |  | 
|  | EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_TRUE(CheckDecryption( | 
|  | *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, | 
|  | PACKET_0BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); | 
|  |  | 
|  | // This test is a client receiving a STREAMS_BLOCKED frame. The | 
|  | // stream ID that it generates should be a server-initiated | 
|  | // stream ID. The expected Stream ID is | 
|  | //                ((0x3-1) * 4) | 0x01 = 0x9 | 
|  | //                 count-to-id      server inited, bidi | 
|  | EXPECT_EQ(GetNthStreamid(QUIC_VERSION_99, Perspective::IS_SERVER, | 
|  | /*bidirectional=*/true, 3), | 
|  | visitor_.stream_id_blocked_frame_.stream_id); | 
|  |  | 
|  | CheckFramingBoundaries(packet99, QUIC_STREAM_ID_BLOCKED_DATA); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, ServerUniDiStreamsBlockedFrame) { | 
|  | // This test only for version 99. | 
|  | if (framer_.transport_version() != QUIC_VERSION_99) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | // clang-format off | 
|  | PacketFragments packet99 = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x9A, 0xBC}}, | 
|  | // frame type (IETF_STREAMS_BLOCKED_UNIDIRECTIONAL frame) | 
|  | {"", | 
|  | {0x17}}, | 
|  | // stream id | 
|  | {"Can not read STREAMS_BLOCKED stream id.", | 
|  | {kVarInt62OneByte + 0x03}}, | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | std::unique_ptr<QuicEncryptedPacket> encrypted( | 
|  | AssemblePacketFromFragments(packet99)); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); | 
|  |  | 
|  | EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_TRUE(CheckDecryption( | 
|  | *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, | 
|  | PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); | 
|  |  | 
|  | // This test is a server receiving a STREAMS_BLOCKED frame. The | 
|  | // stream ID that it generates should be a client-initiated | 
|  | // stream ID. The expected Stream ID is | 
|  | //                ((0x3-1) * 4)  | 0x2  = 0xa | 
|  | //                 count-to-id      client inited, unidi | 
|  | EXPECT_EQ(GetNthStreamid(QUIC_VERSION_99, Perspective::IS_CLIENT, | 
|  | /*bidirectional=*/false, 3), | 
|  | visitor_.stream_id_blocked_frame_.stream_id); | 
|  |  | 
|  | CheckFramingBoundaries(packet99, QUIC_STREAM_ID_BLOCKED_DATA); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, ClientUniDiStreamsBlockedFrame) { | 
|  | // This test only for version 99. | 
|  | if (framer_.transport_version() != QUIC_VERSION_99) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | // clang-format off | 
|  | PacketFragments packet99 = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // Test runs in client mode, no connection id | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x9A, 0xBC}}, | 
|  | // frame type (IETF_STREAMS_BLOCKED_UNIDIRECTIONAL frame) | 
|  | {"", | 
|  | {0x17}}, | 
|  | // stream id | 
|  | {"Can not read STREAMS_BLOCKED stream id.", | 
|  | {kVarInt62OneByte + 0x03}}, | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | std::unique_ptr<QuicEncryptedPacket> encrypted( | 
|  | AssemblePacketFromFragments(packet99)); | 
|  | QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); | 
|  |  | 
|  | EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_TRUE(CheckDecryption( | 
|  | *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, | 
|  | PACKET_0BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); | 
|  |  | 
|  | // This test is a client receiving a STREAMS_BLOCKED frame. The | 
|  | // stream ID that it generates should be a server-initiated | 
|  | // stream ID. The expected Stream ID is | 
|  | //                ((0x3-1) * 4) | 0x01 | 0x2 = 0xb | 
|  | //                 count-to-id      server inited, bidi | 
|  | EXPECT_EQ(GetNthStreamid(QUIC_VERSION_99, Perspective::IS_SERVER, | 
|  | /*bidirectional=*/false, 3), | 
|  | visitor_.stream_id_blocked_frame_.stream_id); | 
|  |  | 
|  | CheckFramingBoundaries(packet99, QUIC_STREAM_ID_BLOCKED_DATA); | 
|  | } | 
|  |  | 
|  | // Check that when we get a STREAMS_BLOCKED frame that specifies too large | 
|  | // a stream count, we reject with an appropriate error. There is no need to | 
|  | // check for different combinations of Uni/Bi directional and client/server | 
|  | // initiated; the logic does not take these into account. | 
|  | TEST_P(QuicFramerTest, StreamsBlockedFrameTooBig) { | 
|  | // This test only for version 99. | 
|  | if (framer_.transport_version() != QUIC_VERSION_99) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | // clang-format off | 
|  | unsigned char packet99[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // Test runs in client mode, no connection id | 
|  | // packet number | 
|  | 0x12, 0x34, 0x9A, 0xBC, | 
|  | // frame type (IETF_STREAMS_BLOCKED_BIDIRECTIONAL) | 
|  | 0x17, | 
|  |  | 
|  | // max. streams. Max stream ID allowed is 0xffffffff | 
|  | // This encodes a count of 0x40000000, leading to stream | 
|  | // IDs in the range 0x1 00000000 to 0x1 00000003. | 
|  | kVarInt62EightBytes + 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x01 | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | QuicEncryptedPacket encrypted(AsChars(packet99), QUIC_ARRAYSIZE(packet99), | 
|  | false); | 
|  | QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); | 
|  | EXPECT_FALSE(framer_.ProcessPacket(encrypted)); | 
|  |  | 
|  | EXPECT_EQ(QUIC_STREAM_ID_BLOCKED_DATA, framer_.error()); | 
|  | EXPECT_EQ(framer_.detailed_error(), | 
|  | "STREAMS_BLOCKED stream count exceeds implementation limit."); | 
|  | } | 
|  |  | 
|  | // Test that count==0 is rejected. | 
|  | TEST_P(QuicFramerTest, StreamsBlockedFrameZeroCount) { | 
|  | // This test only for version 99. | 
|  | if (framer_.transport_version() != QUIC_VERSION_99) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | // clang-format off | 
|  | unsigned char packet99[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // Test runs in client mode, no connection id | 
|  | // packet number | 
|  | 0x12, 0x34, 0x9A, 0xBC, | 
|  | // frame type (IETF_STREAMS_BLOCKED_BIDIRECTIONAL) | 
|  | 0x17, | 
|  |  | 
|  | // max. streams = 0 | 
|  | kVarInt62OneByte + 0x00 | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | QuicEncryptedPacket encrypted(AsChars(packet99), QUIC_ARRAYSIZE(packet99), | 
|  | false); | 
|  | QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); | 
|  | EXPECT_FALSE(framer_.ProcessPacket(encrypted)); | 
|  |  | 
|  | EXPECT_EQ(QUIC_STREAM_ID_BLOCKED_DATA, framer_.error()); | 
|  | EXPECT_EQ(framer_.detailed_error(), | 
|  | "STREAMS_BLOCKED stream count 0 not supported."); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, BuildServerBiDiStreamsBlockedPacket) { | 
|  | // This test only for version 99. | 
|  | if (framer_.transport_version() != QUIC_VERSION_99) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | QuicPacketHeader header; | 
|  | header.destination_connection_id = FramerTestConnectionId(); | 
|  | header.reset_flag = false; | 
|  | header.version_flag = false; | 
|  | header.packet_number = kPacketNumber; | 
|  |  | 
|  | QuicStreamIdBlockedFrame frame; | 
|  | // A server building a STREAMS_BLOCKED frame generates | 
|  | // a server-initiated stream ID. This test is bidirectional. | 
|  | // The low two bits of the stream ID are 01 | 
|  | // Expected value is 0x8u | 0x1u; | 
|  | frame.stream_id = GetNthStreamid(QUIC_VERSION_99, Perspective::IS_SERVER, | 
|  | /*bidirectional=*/true, 3); | 
|  |  | 
|  | QuicFrames frames = {QuicFrame(frame)}; | 
|  |  | 
|  | // clang-format off | 
|  | unsigned char packet99[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (IETF_STREAMS_BLOCKED_BIDIRECTIONAL frame) | 
|  | 0x16, | 
|  | // Stream count | 
|  | kVarInt62OneByte + 0x03 | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  |  | 
|  | test::CompareCharArraysWithHexError("constructed packet", data->data(), | 
|  | data->length(), AsChars(packet99), | 
|  | QUIC_ARRAYSIZE(packet99)); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, BuildClientBiDiStreamsBlockedPacket) { | 
|  | // This test only for version 99. | 
|  | if (framer_.transport_version() != QUIC_VERSION_99) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | // This test runs in client mode. | 
|  | QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); | 
|  |  | 
|  | QuicPacketHeader header; | 
|  | header.destination_connection_id = FramerTestConnectionId(); | 
|  | header.reset_flag = false; | 
|  | header.version_flag = false; | 
|  | header.packet_number = kPacketNumber; | 
|  |  | 
|  | QuicStreamIdBlockedFrame frame; | 
|  | // A client building a STREAMS_BLOCKED frame generates | 
|  | // a client-initiated stream ID. This test is bidirectional. | 
|  | // The low two bits of the stream ID are 00. Expected value is 0x8 | 
|  | frame.stream_id = GetNthStreamid(QUIC_VERSION_99, Perspective::IS_CLIENT, | 
|  | /*bidirectional=*/true, 3); | 
|  | QuicFrames frames = {QuicFrame(frame)}; | 
|  |  | 
|  | // clang-format off | 
|  | unsigned char packet99[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (IETF_STREAMS_BLOCKED_BIDIRECTIONAL frame) | 
|  | 0x16, | 
|  | // Stream count | 
|  | kVarInt62OneByte + 0x03 | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  |  | 
|  | test::CompareCharArraysWithHexError("constructed packet", data->data(), | 
|  | data->length(), AsChars(packet99), | 
|  | QUIC_ARRAYSIZE(packet99)); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, BuildServerUniStreamsBlockedPacket) { | 
|  | // This test only for version 99. | 
|  | if (framer_.transport_version() != QUIC_VERSION_99) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | QuicPacketHeader header; | 
|  | header.destination_connection_id = FramerTestConnectionId(); | 
|  | header.reset_flag = false; | 
|  | header.version_flag = false; | 
|  | header.packet_number = kPacketNumber; | 
|  |  | 
|  | QuicStreamIdBlockedFrame frame; | 
|  | // A server building a STREAMS_BLOCKED frame generates | 
|  | // a server-initiated stream ID. This test is bidirectional. | 
|  | // The low two bits of the stream ID are 11. Expected value is 0xb | 
|  | frame.stream_id = GetNthStreamid(QUIC_VERSION_99, Perspective::IS_SERVER, | 
|  | /*bidirectional=*/false, 3); | 
|  | QuicFrames frames = {QuicFrame(frame)}; | 
|  |  | 
|  | // clang-format off | 
|  | unsigned char packet99[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (IETF_STREAMS_BLOCKED_UNIDIRECTIONAL frame) | 
|  | 0x17, | 
|  | // Stream count | 
|  | kVarInt62OneByte + 0x03 | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  |  | 
|  | test::CompareCharArraysWithHexError("constructed packet", data->data(), | 
|  | data->length(), AsChars(packet99), | 
|  | QUIC_ARRAYSIZE(packet99)); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, BuildClientUniDiStreamsBlockedPacket) { | 
|  | // This test only for version 99. | 
|  | if (framer_.transport_version() != QUIC_VERSION_99) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | // This test runs in client mode. | 
|  | QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); | 
|  |  | 
|  | QuicPacketHeader header; | 
|  | header.destination_connection_id = FramerTestConnectionId(); | 
|  | header.reset_flag = false; | 
|  | header.version_flag = false; | 
|  | header.packet_number = kPacketNumber; | 
|  |  | 
|  | QuicStreamIdBlockedFrame frame; | 
|  | // A client building a STREAMS_BLOCKED frame generates | 
|  | // a client-initiated stream ID. This test is bidirectional. | 
|  | // The low two bits of the stream ID are 10. Expected value is 0xa | 
|  | frame.stream_id = GetNthStreamid(QUIC_VERSION_99, Perspective::IS_CLIENT, | 
|  | /*bidirectional=*/false, 3); | 
|  | QuicFrames frames = {QuicFrame(frame)}; | 
|  |  | 
|  | // clang-format off | 
|  | unsigned char packet99[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (IETF_STREAMS_BLOCKED_UNIDIRECTIONAL frame) | 
|  | 0x17, | 
|  | // Stream count | 
|  | kVarInt62OneByte + 0x03 | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  |  | 
|  | test::CompareCharArraysWithHexError("constructed packet", data->data(), | 
|  | data->length(), AsChars(packet99), | 
|  | QUIC_ARRAYSIZE(packet99)); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, BuildServerBiDiMaxStreamsPacket) { | 
|  | // This test only for version 99. | 
|  | if (framer_.transport_version() != QUIC_VERSION_99) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | QuicPacketHeader header; | 
|  | header.destination_connection_id = FramerTestConnectionId(); | 
|  | header.reset_flag = false; | 
|  | header.version_flag = false; | 
|  | header.packet_number = kPacketNumber; | 
|  |  | 
|  | QuicMaxStreamIdFrame frame; | 
|  | // A server building a MAX_STREAMS frame generates | 
|  | // a client-initiated stream ID. This test is bidirectional. | 
|  | // The low two bits of the stream ID are 00. Expected value is 0xc | 
|  | // because streamid==0 is special and the first client/bidi | 
|  | // stream is 4, not 0. | 
|  | frame.max_stream_id = GetNthStreamid(QUIC_VERSION_99, Perspective::IS_CLIENT, | 
|  | /*bidirectional=*/true, 3); | 
|  | QuicFrames frames = {QuicFrame(frame)}; | 
|  |  | 
|  | // clang-format off | 
|  | unsigned char packet99[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (IETF_MAX_STREAMS_BIDIRECTIONAL frame) | 
|  | 0x12, | 
|  | // Stream count | 
|  | kVarInt62OneByte + 0x03 | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  |  | 
|  | test::CompareCharArraysWithHexError("constructed packet", data->data(), | 
|  | data->length(), AsChars(packet99), | 
|  | QUIC_ARRAYSIZE(packet99)); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, BuildClientBiDiMaxStreamsPacket) { | 
|  | // This test only for version 99. | 
|  | if (framer_.transport_version() != QUIC_VERSION_99) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | // This test runs in client mode. | 
|  | QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); | 
|  |  | 
|  | QuicPacketHeader header; | 
|  | header.destination_connection_id = FramerTestConnectionId(); | 
|  | header.reset_flag = false; | 
|  | header.version_flag = false; | 
|  | header.packet_number = kPacketNumber; | 
|  |  | 
|  | QuicMaxStreamIdFrame frame; | 
|  | // A client building a MAX_STREAMS frame generates | 
|  | // a server-initiated stream ID. This test is bidirectional. | 
|  | // The low two bits of the stream ID are 01. Expected value is 0x9 | 
|  | frame.max_stream_id = GetNthStreamid(QUIC_VERSION_99, Perspective::IS_SERVER, | 
|  | /*bidirectional=*/true, 3); | 
|  | QuicFrames frames = {QuicFrame(frame)}; | 
|  |  | 
|  | // clang-format off | 
|  | unsigned char packet99[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (IETF_MAX_STREAMS_BIDIRECTIONAL frame) | 
|  | 0x12, | 
|  | // Stream count | 
|  | kVarInt62OneByte + 0x03 | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  |  | 
|  | test::CompareCharArraysWithHexError("constructed packet", data->data(), | 
|  | data->length(), AsChars(packet99), | 
|  | QUIC_ARRAYSIZE(packet99)); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, BuildServerUniMaxStreamsPacket) { | 
|  | // This test only for version 99. | 
|  | if (framer_.transport_version() != QUIC_VERSION_99) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | QuicPacketHeader header; | 
|  | header.destination_connection_id = FramerTestConnectionId(); | 
|  | header.reset_flag = false; | 
|  | header.version_flag = false; | 
|  | header.packet_number = kPacketNumber; | 
|  |  | 
|  | QuicMaxStreamIdFrame frame; | 
|  | // A server building a MAX_STREAMS frame generates | 
|  | // a client-initiated stream ID. This test is bidirectional. | 
|  | // The low two bits of the stream ID are 10. Expected value is 0xa | 
|  | frame.max_stream_id = GetNthStreamid(QUIC_VERSION_99, Perspective::IS_CLIENT, | 
|  | /*bidirectional=*/false, 3); | 
|  | QuicFrames frames = {QuicFrame(frame)}; | 
|  |  | 
|  | // clang-format off | 
|  | unsigned char packet99[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (IETF_MAX_STREAMS_UNIDIRECTIONAL frame) | 
|  | 0x13, | 
|  | // Stream count | 
|  | kVarInt62OneByte + 0x03 | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  |  | 
|  | test::CompareCharArraysWithHexError("constructed packet", data->data(), | 
|  | data->length(), AsChars(packet99), | 
|  | QUIC_ARRAYSIZE(packet99)); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, BuildClientUniDiMaxStreamsPacket) { | 
|  | // This test only for version 99. | 
|  | if (framer_.transport_version() != QUIC_VERSION_99) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | // This test runs in client mode. | 
|  | QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); | 
|  |  | 
|  | QuicPacketHeader header; | 
|  | header.destination_connection_id = FramerTestConnectionId(); | 
|  | header.reset_flag = false; | 
|  | header.version_flag = false; | 
|  | header.packet_number = kPacketNumber; | 
|  |  | 
|  | QuicMaxStreamIdFrame frame; | 
|  | // A client building a MAX_STREAMS frame generates | 
|  | // a server-initiated stream ID. This test is bidirectional. | 
|  | // The low two bits of the stream ID are 11. Expected value is 0xb | 
|  | frame.max_stream_id = GetNthStreamid(QUIC_VERSION_99, Perspective::IS_SERVER, | 
|  | /*bidirectional=*/false, 3); | 
|  | QuicFrames frames = {QuicFrame(frame)}; | 
|  |  | 
|  | // clang-format off | 
|  | unsigned char packet99[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (IETF_MAX_STREAMS_UNIDIRECTIONAL frame) | 
|  | 0x13, | 
|  | // Stream count | 
|  | kVarInt62OneByte + 0x03 | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  |  | 
|  | test::CompareCharArraysWithHexError("constructed packet", data->data(), | 
|  | data->length(), AsChars(packet99), | 
|  | QUIC_ARRAYSIZE(packet99)); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, NewConnectionIdFrame) { | 
|  | if (framer_.transport_version() != QUIC_VERSION_99) { | 
|  | // This frame is only for version 99. | 
|  | return; | 
|  | } | 
|  | // clang-format off | 
|  | PacketFragments packet99 = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | // frame type (IETF_NEW_CONNECTION_ID frame) | 
|  | {"", | 
|  | {0x18}}, | 
|  | // error code | 
|  | {"Unable to read new connection ID frame sequence number.", | 
|  | {kVarInt62OneByte + 0x11}}, | 
|  | {"Unable to read new connection ID frame connection id length.", | 
|  | {0x08}},  // connection ID length | 
|  | {"Unable to read new connection ID frame connection id.", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x11}}, | 
|  | {"Can not read new connection ID frame reset token.", | 
|  | {0xb5, 0x69, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, | 
|  | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}} | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | std::unique_ptr<QuicEncryptedPacket> encrypted( | 
|  | AssemblePacketFromFragments(packet99)); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); | 
|  |  | 
|  | EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_TRUE(CheckDecryption( | 
|  | *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, | 
|  | PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); | 
|  |  | 
|  | EXPECT_EQ(0u, visitor_.stream_frames_.size()); | 
|  |  | 
|  | EXPECT_EQ(FramerTestConnectionIdPlusOne(), | 
|  | visitor_.new_connection_id_.connection_id); | 
|  | EXPECT_EQ(0x11u, visitor_.new_connection_id_.sequence_number); | 
|  | EXPECT_EQ(kTestStatelessResetToken, | 
|  | visitor_.new_connection_id_.stateless_reset_token); | 
|  |  | 
|  | ASSERT_EQ(0u, visitor_.ack_frames_.size()); | 
|  |  | 
|  | CheckFramingBoundaries(packet99, QUIC_INVALID_NEW_CONNECTION_ID_DATA); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, NewConnectionIdFrameVariableLength) { | 
|  | if (!QuicUtils::VariableLengthConnectionIdAllowedForVersion( | 
|  | framer_.transport_version())) { | 
|  | return; | 
|  | } | 
|  | // clang-format off | 
|  | PacketFragments packet99 = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | // frame type (IETF_NEW_CONNECTION_ID frame) | 
|  | {"", | 
|  | {0x18}}, | 
|  | // error code | 
|  | {"Unable to read new connection ID frame sequence number.", | 
|  | {kVarInt62OneByte + 0x11}}, | 
|  | {"Unable to read new connection ID frame connection id length.", | 
|  | {0x09}},  // connection ID length | 
|  | {"Unable to read new connection ID frame connection id.", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, 0x42}}, | 
|  | {"Can not read new connection ID frame reset token.", | 
|  | {0xb5, 0x69, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, | 
|  | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}} | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | std::unique_ptr<QuicEncryptedPacket> encrypted( | 
|  | AssemblePacketFromFragments(packet99)); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); | 
|  |  | 
|  | EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_TRUE(CheckDecryption( | 
|  | *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, | 
|  | PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); | 
|  |  | 
|  | EXPECT_EQ(0u, visitor_.stream_frames_.size()); | 
|  |  | 
|  | EXPECT_EQ(FramerTestConnectionIdNineBytes(), | 
|  | visitor_.new_connection_id_.connection_id); | 
|  | EXPECT_EQ(0x11u, visitor_.new_connection_id_.sequence_number); | 
|  | EXPECT_EQ(kTestStatelessResetToken, | 
|  | visitor_.new_connection_id_.stateless_reset_token); | 
|  |  | 
|  | ASSERT_EQ(0u, visitor_.ack_frames_.size()); | 
|  |  | 
|  | CheckFramingBoundaries(packet99, QUIC_INVALID_NEW_CONNECTION_ID_DATA); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, BuildNewConnectionIdFramePacket) { | 
|  | if (framer_.transport_version() != QUIC_VERSION_99) { | 
|  | // This frame is only for version 99. | 
|  | return; | 
|  | } | 
|  | QuicPacketHeader header; | 
|  | header.destination_connection_id = FramerTestConnectionId(); | 
|  | header.reset_flag = false; | 
|  | header.version_flag = false; | 
|  | header.packet_number = kPacketNumber; | 
|  |  | 
|  | QuicNewConnectionIdFrame frame; | 
|  | frame.sequence_number = 0x11; | 
|  | // Use this value to force a 4-byte encoded variable length connection ID | 
|  | // in the frame. | 
|  | frame.connection_id = FramerTestConnectionIdPlusOne(); | 
|  | frame.stateless_reset_token = kTestStatelessResetToken; | 
|  |  | 
|  | QuicFrames frames = {QuicFrame(&frame)}; | 
|  |  | 
|  | // clang-format off | 
|  | unsigned char packet99[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (IETF_NEW_CONNECTION_ID frame) | 
|  | 0x18, | 
|  | // sequence number | 
|  | kVarInt62OneByte + 0x11, | 
|  | // new connection id length | 
|  | 0x08, | 
|  | // new connection id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x11, | 
|  | // stateless reset token | 
|  | 0xb5, 0x69, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, | 
|  | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  |  | 
|  | test::CompareCharArraysWithHexError("constructed packet", data->data(), | 
|  | data->length(), AsChars(packet99), | 
|  | QUIC_ARRAYSIZE(packet99)); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, NewTokenFrame) { | 
|  | if (framer_.transport_version() != QUIC_VERSION_99) { | 
|  | // This frame is only for version 99. | 
|  | return; | 
|  | } | 
|  | // clang-format off | 
|  | PacketFragments packet = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | // frame type (IETF_NEW_TOKEN frame) | 
|  | {"", | 
|  | {0x07}}, | 
|  | // Length | 
|  | {"Unable to read new token length.", | 
|  | {kVarInt62OneByte + 0x08}}, | 
|  | {"Unable to read new token data.", | 
|  | {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}} | 
|  | }; | 
|  | // clang-format on | 
|  | uint8_t expected_token_value[] = {0x00, 0x01, 0x02, 0x03, | 
|  | 0x04, 0x05, 0x06, 0x07}; | 
|  |  | 
|  | std::unique_ptr<QuicEncryptedPacket> encrypted( | 
|  | AssemblePacketFromFragments(packet)); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); | 
|  |  | 
|  | EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_TRUE(CheckDecryption( | 
|  | *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, | 
|  | PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); | 
|  |  | 
|  | EXPECT_EQ(0u, visitor_.stream_frames_.size()); | 
|  |  | 
|  | EXPECT_EQ(sizeof(expected_token_value), visitor_.new_token_.token.length()); | 
|  | EXPECT_EQ(0, memcmp(expected_token_value, visitor_.new_token_.token.data(), | 
|  | sizeof(expected_token_value))); | 
|  |  | 
|  | CheckFramingBoundaries(packet, QUIC_INVALID_NEW_TOKEN); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, BuildNewTokenFramePacket) { | 
|  | if (framer_.transport_version() != QUIC_VERSION_99) { | 
|  | // This frame is only for version 99. | 
|  | return; | 
|  | } | 
|  | QuicPacketHeader header; | 
|  | header.destination_connection_id = FramerTestConnectionId(); | 
|  | header.reset_flag = false; | 
|  | header.version_flag = false; | 
|  | header.packet_number = kPacketNumber; | 
|  |  | 
|  | uint8_t expected_token_value[] = {0x00, 0x01, 0x02, 0x03, | 
|  | 0x04, 0x05, 0x06, 0x07}; | 
|  |  | 
|  | QuicNewTokenFrame frame(0, std::string((const char*)(expected_token_value), | 
|  | sizeof(expected_token_value))); | 
|  |  | 
|  | QuicFrames frames = {QuicFrame(&frame)}; | 
|  |  | 
|  | // clang-format off | 
|  | unsigned char packet[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (IETF_NEW_TOKEN frame) | 
|  | 0x07, | 
|  | // Length and token | 
|  | kVarInt62OneByte + 0x08, | 
|  | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  |  | 
|  | test::CompareCharArraysWithHexError("constructed packet", data->data(), | 
|  | data->length(), AsChars(packet), | 
|  | QUIC_ARRAYSIZE(packet)); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, IetfStopSendingFrame) { | 
|  | // This test is only for version 99. | 
|  | if (framer_.transport_version() != QUIC_VERSION_99) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | // clang-format off | 
|  | PacketFragments packet99 = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x9A, 0xBC}}, | 
|  | // frame type (IETF_STOP_SENDING frame) | 
|  | {"", | 
|  | {0x05}}, | 
|  | // stream id | 
|  | {"Unable to read stop sending stream id.", | 
|  | {kVarInt62FourBytes + 0x01, 0x02, 0x03, 0x04}}, | 
|  | {"Unable to read stop sending application error code.", | 
|  | {0x76, 0x54}}, | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | std::unique_ptr<QuicEncryptedPacket> encrypted( | 
|  | AssemblePacketFromFragments(packet99)); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); | 
|  |  | 
|  | EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_TRUE(CheckDecryption( | 
|  | *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, | 
|  | PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); | 
|  |  | 
|  | EXPECT_EQ(kStreamId, visitor_.stop_sending_frame_.stream_id); | 
|  | EXPECT_EQ(0x7654, visitor_.stop_sending_frame_.application_error_code); | 
|  |  | 
|  | CheckFramingBoundaries(packet99, QUIC_INVALID_STOP_SENDING_FRAME_DATA); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, BuildIetfStopSendingPacket) { | 
|  | // This test is only for version 99. | 
|  | if (framer_.transport_version() != QUIC_VERSION_99) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | QuicPacketHeader header; | 
|  | header.destination_connection_id = FramerTestConnectionId(); | 
|  | header.reset_flag = false; | 
|  | header.version_flag = false; | 
|  | header.packet_number = kPacketNumber; | 
|  |  | 
|  | QuicStopSendingFrame frame; | 
|  | frame.stream_id = kStreamId; | 
|  | frame.application_error_code = 0xffff; | 
|  | QuicFrames frames = {QuicFrame(&frame)}; | 
|  |  | 
|  | // clang-format off | 
|  | unsigned char packet99[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (IETF_STOP_SENDING frame) | 
|  | 0x05, | 
|  | // Stream ID | 
|  | kVarInt62FourBytes + 0x01, 0x02, 0x03, 0x04, | 
|  | // Application error code | 
|  | 0xff, 0xff | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  |  | 
|  | test::CompareCharArraysWithHexError("constructed packet", data->data(), | 
|  | data->length(), AsChars(packet99), | 
|  | QUIC_ARRAYSIZE(packet99)); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, IetfPathChallengeFrame) { | 
|  | // This test only for version 99. | 
|  | if (framer_.transport_version() != QUIC_VERSION_99) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | // clang-format off | 
|  | PacketFragments packet99 = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x9A, 0xBC}}, | 
|  | // frame type (IETF_PATH_CHALLENGE) | 
|  | {"", | 
|  | {0x1a}}, | 
|  | // data | 
|  | {"Can not read path challenge data.", | 
|  | {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}}, | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | std::unique_ptr<QuicEncryptedPacket> encrypted( | 
|  | AssemblePacketFromFragments(packet99)); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); | 
|  |  | 
|  | EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_TRUE(CheckDecryption( | 
|  | *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, | 
|  | PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); | 
|  |  | 
|  | EXPECT_EQ(QuicPathFrameBuffer({{0, 1, 2, 3, 4, 5, 6, 7}}), | 
|  | visitor_.path_challenge_frame_.data_buffer); | 
|  |  | 
|  | CheckFramingBoundaries(packet99, QUIC_INVALID_PATH_CHALLENGE_DATA); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, BuildIetfPathChallengePacket) { | 
|  | // This test only for version 99. | 
|  | if (framer_.transport_version() != QUIC_VERSION_99) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | QuicPacketHeader header; | 
|  | header.destination_connection_id = FramerTestConnectionId(); | 
|  | header.reset_flag = false; | 
|  | header.version_flag = false; | 
|  | header.packet_number = kPacketNumber; | 
|  |  | 
|  | QuicPathChallengeFrame frame; | 
|  | frame.data_buffer = QuicPathFrameBuffer({{0, 1, 2, 3, 4, 5, 6, 7}}); | 
|  | QuicFrames frames = {QuicFrame(&frame)}; | 
|  |  | 
|  | // clang-format off | 
|  | unsigned char packet99[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (IETF_PATH_CHALLENGE) | 
|  | 0x1a, | 
|  | // Data | 
|  | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  |  | 
|  | test::CompareCharArraysWithHexError("constructed packet", data->data(), | 
|  | data->length(), AsChars(packet99), | 
|  | QUIC_ARRAYSIZE(packet99)); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, IetfPathResponseFrame) { | 
|  | // This test only for version 99. | 
|  | if (framer_.transport_version() != QUIC_VERSION_99) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | // clang-format off | 
|  | PacketFragments packet99 = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x9A, 0xBC}}, | 
|  | // frame type (IETF_PATH_RESPONSE) | 
|  | {"", | 
|  | {0x1b}}, | 
|  | // data | 
|  | {"Can not read path response data.", | 
|  | {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}}, | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | std::unique_ptr<QuicEncryptedPacket> encrypted( | 
|  | AssemblePacketFromFragments(packet99)); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); | 
|  |  | 
|  | EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_TRUE(CheckDecryption( | 
|  | *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, | 
|  | PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); | 
|  |  | 
|  | EXPECT_EQ(QuicPathFrameBuffer({{0, 1, 2, 3, 4, 5, 6, 7}}), | 
|  | visitor_.path_response_frame_.data_buffer); | 
|  |  | 
|  | CheckFramingBoundaries(packet99, QUIC_INVALID_PATH_RESPONSE_DATA); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, BuildIetfPathResponsePacket) { | 
|  | // This test only for version 99. | 
|  | if (framer_.transport_version() != QUIC_VERSION_99) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | QuicPacketHeader header; | 
|  | header.destination_connection_id = FramerTestConnectionId(); | 
|  | header.reset_flag = false; | 
|  | header.version_flag = false; | 
|  | header.packet_number = kPacketNumber; | 
|  |  | 
|  | QuicPathResponseFrame frame; | 
|  | frame.data_buffer = QuicPathFrameBuffer({{0, 1, 2, 3, 4, 5, 6, 7}}); | 
|  | QuicFrames frames = {QuicFrame(&frame)}; | 
|  |  | 
|  | // clang-format off | 
|  | unsigned char packet99[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (IETF_PATH_RESPONSE) | 
|  | 0x1b, | 
|  | // Data | 
|  | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  |  | 
|  | test::CompareCharArraysWithHexError("constructed packet", data->data(), | 
|  | data->length(), AsChars(packet99), | 
|  | QUIC_ARRAYSIZE(packet99)); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, GetRetransmittableControlFrameSize) { | 
|  | QuicRstStreamFrame rst_stream(1, 3, QUIC_STREAM_CANCELLED, 1024); | 
|  | EXPECT_EQ(QuicFramer::GetRstStreamFrameSize(framer_.transport_version(), | 
|  | rst_stream), | 
|  | QuicFramer::GetRetransmittableControlFrameSize( | 
|  | framer_.transport_version(), QuicFrame(&rst_stream))); | 
|  |  | 
|  | std::string error_detail(2048, 'e'); | 
|  | QuicConnectionCloseFrame connection_close(QUIC_NETWORK_IDLE_TIMEOUT, | 
|  | error_detail); | 
|  | EXPECT_EQ(QuicFramer::GetMinConnectionCloseFrameSize( | 
|  | framer_.transport_version(), connection_close) + | 
|  | 256, | 
|  | QuicFramer::GetRetransmittableControlFrameSize( | 
|  | framer_.transport_version(), QuicFrame(&connection_close))); | 
|  |  | 
|  | QuicGoAwayFrame goaway(2, QUIC_PEER_GOING_AWAY, 3, error_detail); | 
|  | EXPECT_EQ(QuicFramer::GetMinGoAwayFrameSize() + 256, | 
|  | QuicFramer::GetRetransmittableControlFrameSize( | 
|  | framer_.transport_version(), QuicFrame(&goaway))); | 
|  |  | 
|  | QuicWindowUpdateFrame window_update(3, 3, 1024); | 
|  | EXPECT_EQ(QuicFramer::GetWindowUpdateFrameSize(framer_.transport_version(), | 
|  | window_update), | 
|  | QuicFramer::GetRetransmittableControlFrameSize( | 
|  | framer_.transport_version(), QuicFrame(&window_update))); | 
|  |  | 
|  | QuicBlockedFrame blocked(4, 3, 1024); | 
|  | EXPECT_EQ( | 
|  | QuicFramer::GetBlockedFrameSize(framer_.transport_version(), blocked), | 
|  | QuicFramer::GetRetransmittableControlFrameSize( | 
|  | framer_.transport_version(), QuicFrame(&blocked))); | 
|  |  | 
|  | if (framer_.transport_version() != QUIC_VERSION_99) { | 
|  | return; | 
|  | } | 
|  | QuicApplicationCloseFrame application_close; | 
|  | EXPECT_EQ(QuicFramer::GetMinApplicationCloseFrameSize( | 
|  | framer_.transport_version(), application_close), | 
|  | QuicFramer::GetRetransmittableControlFrameSize( | 
|  | framer_.transport_version(), QuicFrame(&application_close))); | 
|  |  | 
|  | QuicNewConnectionIdFrame new_connection_id(5, TestConnectionId(), 1, 101111); | 
|  | EXPECT_EQ(QuicFramer::GetNewConnectionIdFrameSize(new_connection_id), | 
|  | QuicFramer::GetRetransmittableControlFrameSize( | 
|  | framer_.transport_version(), QuicFrame(&new_connection_id))); | 
|  |  | 
|  | QuicMaxStreamIdFrame max_stream_id(6, 3); | 
|  | EXPECT_EQ(QuicFramer::GetMaxStreamsFrameSize(framer_.transport_version(), | 
|  | max_stream_id), | 
|  | QuicFramer::GetRetransmittableControlFrameSize( | 
|  | framer_.transport_version(), QuicFrame(max_stream_id))); | 
|  |  | 
|  | QuicStreamIdBlockedFrame stream_id_blocked(7, 3); | 
|  | EXPECT_EQ(QuicFramer::GetStreamsBlockedFrameSize(framer_.transport_version(), | 
|  | stream_id_blocked), | 
|  | QuicFramer::GetRetransmittableControlFrameSize( | 
|  | framer_.transport_version(), QuicFrame(stream_id_blocked))); | 
|  |  | 
|  | QuicPathFrameBuffer buffer = { | 
|  | {0x80, 0x91, 0xa2, 0xb3, 0xc4, 0xd5, 0xe5, 0xf7}}; | 
|  | QuicPathResponseFrame path_response_frame(8, buffer); | 
|  | EXPECT_EQ(QuicFramer::GetPathResponseFrameSize(path_response_frame), | 
|  | QuicFramer::GetRetransmittableControlFrameSize( | 
|  | framer_.transport_version(), QuicFrame(&path_response_frame))); | 
|  |  | 
|  | QuicPathChallengeFrame path_challenge_frame(9, buffer); | 
|  | EXPECT_EQ(QuicFramer::GetPathChallengeFrameSize(path_challenge_frame), | 
|  | QuicFramer::GetRetransmittableControlFrameSize( | 
|  | framer_.transport_version(), QuicFrame(&path_challenge_frame))); | 
|  |  | 
|  | QuicStopSendingFrame stop_sending_frame(10, 3, 20); | 
|  | EXPECT_EQ(QuicFramer::GetStopSendingFrameSize(stop_sending_frame), | 
|  | QuicFramer::GetRetransmittableControlFrameSize( | 
|  | framer_.transport_version(), QuicFrame(&stop_sending_frame))); | 
|  | } | 
|  |  | 
|  | // A set of tests to ensure that bad frame-type encodings | 
|  | // are properly detected and handled. | 
|  | // First, four tests to see that unknown frame types generate | 
|  | // a QUIC_INVALID_FRAME_DATA error with detailed information | 
|  | // "Illegal frame type." This regardless of the encoding of the type | 
|  | // (1/2/4/8 bytes). | 
|  | // This only for version 99. | 
|  | TEST_P(QuicFramerTest, IetfFrameTypeEncodingErrorUnknown1Byte) { | 
|  | // This test only for version 99. | 
|  | if (framer_.transport_version() != QUIC_VERSION_99) { | 
|  | return; | 
|  | } | 
|  | // clang-format off | 
|  | PacketFragments packet = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x9A, 0xBC}}, | 
|  | // frame type (unknown value, single-byte encoding) | 
|  | {"", | 
|  | {0x38}} | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | std::unique_ptr<QuicEncryptedPacket> encrypted( | 
|  | AssemblePacketFromFragments(packet)); | 
|  |  | 
|  | EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); | 
|  |  | 
|  | EXPECT_EQ(QUIC_INVALID_FRAME_DATA, framer_.error()); | 
|  | EXPECT_EQ("Illegal frame type.", framer_.detailed_error()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, IetfFrameTypeEncodingErrorUnknown2Bytes) { | 
|  | // This test only for version 99. | 
|  | if (framer_.transport_version() != QUIC_VERSION_99) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | // clang-format off | 
|  | PacketFragments packet = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x9A, 0xBC}}, | 
|  | // frame type (unknown value, two-byte encoding) | 
|  | {"", | 
|  | {kVarInt62TwoBytes + 0x01, 0x38}} | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | std::unique_ptr<QuicEncryptedPacket> encrypted( | 
|  | AssemblePacketFromFragments(packet)); | 
|  |  | 
|  | EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); | 
|  |  | 
|  | EXPECT_EQ(QUIC_INVALID_FRAME_DATA, framer_.error()); | 
|  | EXPECT_EQ("Illegal frame type.", framer_.detailed_error()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, IetfFrameTypeEncodingErrorUnknown4Bytes) { | 
|  | // This test only for version 99. | 
|  | if (framer_.transport_version() != QUIC_VERSION_99) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | // clang-format off | 
|  | PacketFragments packet = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x9A, 0xBC}}, | 
|  | // frame type (unknown value, four-byte encoding) | 
|  | {"", | 
|  | {kVarInt62FourBytes + 0x01, 0x00, 0x00, 0x38}} | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | std::unique_ptr<QuicEncryptedPacket> encrypted( | 
|  | AssemblePacketFromFragments(packet)); | 
|  |  | 
|  | EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); | 
|  |  | 
|  | EXPECT_EQ(QUIC_INVALID_FRAME_DATA, framer_.error()); | 
|  | EXPECT_EQ("Illegal frame type.", framer_.detailed_error()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, IetfFrameTypeEncodingErrorUnknown8Bytes) { | 
|  | // This test only for version 99. | 
|  | if (framer_.transport_version() != QUIC_VERSION_99) { | 
|  | return; | 
|  | } | 
|  | // clang-format off | 
|  | PacketFragments packet = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x9A, 0xBC}}, | 
|  | // frame type (unknown value, eight-byte encoding) | 
|  | {"", | 
|  | {kVarInt62EightBytes + 0x01, 0x00, 0x00, 0x01, 0x02, 0x34, 0x56, 0x38}} | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | std::unique_ptr<QuicEncryptedPacket> encrypted( | 
|  | AssemblePacketFromFragments(packet)); | 
|  |  | 
|  | EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); | 
|  |  | 
|  | EXPECT_EQ(QUIC_INVALID_FRAME_DATA, framer_.error()); | 
|  | EXPECT_EQ("Illegal frame type.", framer_.detailed_error()); | 
|  | } | 
|  |  | 
|  | // Three tests to check that known frame types that are not minimally | 
|  | // encoded generate IETF_QUIC_PROTOCOL_VIOLATION errors with detailed | 
|  | // information "Frame type not minimally encoded." | 
|  | // Look at the frame-type encoded in 2, 4, and 8 bytes. | 
|  | TEST_P(QuicFramerTest, IetfFrameTypeEncodingErrorKnown2Bytes) { | 
|  | // This test only for version 99. | 
|  | if (framer_.transport_version() != QUIC_VERSION_99) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | // clang-format off | 
|  | PacketFragments packet = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x9A, 0xBC}}, | 
|  | // frame type (Blocked, two-byte encoding) | 
|  | {"", | 
|  | {kVarInt62TwoBytes + 0x00, 0x08}} | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | std::unique_ptr<QuicEncryptedPacket> encrypted( | 
|  | AssemblePacketFromFragments(packet)); | 
|  |  | 
|  | EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); | 
|  |  | 
|  | EXPECT_EQ(IETF_QUIC_PROTOCOL_VIOLATION, framer_.error()); | 
|  | EXPECT_EQ("Frame type not minimally encoded.", framer_.detailed_error()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, IetfFrameTypeEncodingErrorKnown4Bytes) { | 
|  | // This test only for version 99. | 
|  | if (framer_.transport_version() != QUIC_VERSION_99) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | // clang-format off | 
|  | PacketFragments packet = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x9A, 0xBC}}, | 
|  | // frame type (Blocked, four-byte encoding) | 
|  | {"", | 
|  | {kVarInt62FourBytes + 0x00, 0x00, 0x00, 0x08}} | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | std::unique_ptr<QuicEncryptedPacket> encrypted( | 
|  | AssemblePacketFromFragments(packet)); | 
|  |  | 
|  | EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); | 
|  |  | 
|  | EXPECT_EQ(IETF_QUIC_PROTOCOL_VIOLATION, framer_.error()); | 
|  | EXPECT_EQ("Frame type not minimally encoded.", framer_.detailed_error()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, IetfFrameTypeEncodingErrorKnown8Bytes) { | 
|  | // This test only for version 99. | 
|  | if (framer_.transport_version() != QUIC_VERSION_99) { | 
|  | return; | 
|  | } | 
|  | // clang-format off | 
|  | PacketFragments packet = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x9A, 0xBC}}, | 
|  | // frame type (Blocked, eight-byte encoding) | 
|  | {"", | 
|  | {kVarInt62EightBytes + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08}} | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | std::unique_ptr<QuicEncryptedPacket> encrypted( | 
|  | AssemblePacketFromFragments(packet)); | 
|  |  | 
|  | EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); | 
|  |  | 
|  | EXPECT_EQ(IETF_QUIC_PROTOCOL_VIOLATION, framer_.error()); | 
|  | EXPECT_EQ("Frame type not minimally encoded.", framer_.detailed_error()); | 
|  | } | 
|  |  | 
|  | // Tests to check that all known OETF frame types that are not minimally | 
|  | // encoded generate IETF_QUIC_PROTOCOL_VIOLATION errors with detailed | 
|  | // information "Frame type not minimally encoded." | 
|  | // Just look at 2-byte encoding. | 
|  | TEST_P(QuicFramerTest, IetfFrameTypeEncodingErrorKnown2BytesAllTypes) { | 
|  | // This test only for version 99. | 
|  | if (framer_.transport_version() != QUIC_VERSION_99) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | // clang-format off | 
|  | PacketFragments packets[] = { | 
|  | { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x9A, 0xBC}}, | 
|  | // frame type (two-byte encoding) | 
|  | {"", | 
|  | {kVarInt62TwoBytes + 0x00, 0x00}} | 
|  | }, | 
|  | { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x9A, 0xBC}}, | 
|  | // frame type (two-byte encoding) | 
|  | {"", | 
|  | {kVarInt62TwoBytes + 0x00, 0x01}} | 
|  | }, | 
|  | { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x9A, 0xBC}}, | 
|  | // frame type (two-byte encoding) | 
|  | {"", | 
|  | {kVarInt62TwoBytes + 0x00, 0x02}} | 
|  | }, | 
|  | { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x9A, 0xBC}}, | 
|  | // frame type (two-byte encoding) | 
|  | {"", | 
|  | {kVarInt62TwoBytes + 0x00, 0x03}} | 
|  | }, | 
|  | { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x9A, 0xBC}}, | 
|  | // frame type (two-byte encoding) | 
|  | {"", | 
|  | {kVarInt62TwoBytes + 0x00, 0x04}} | 
|  | }, | 
|  | { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x9A, 0xBC}}, | 
|  | // frame type (two-byte encoding) | 
|  | {"", | 
|  | {kVarInt62TwoBytes + 0x00, 0x05}} | 
|  | }, | 
|  | { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x9A, 0xBC}}, | 
|  | // frame type (two-byte encoding) | 
|  | {"", | 
|  | {kVarInt62TwoBytes + 0x00, 0x06}} | 
|  | }, | 
|  | { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x9A, 0xBC}}, | 
|  | // frame type (two-byte encoding) | 
|  | {"", | 
|  | {kVarInt62TwoBytes + 0x00, 0x07}} | 
|  | }, | 
|  | { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x9A, 0xBC}}, | 
|  | // frame type (two-byte encoding) | 
|  | {"", | 
|  | {kVarInt62TwoBytes + 0x00, 0x08}} | 
|  | }, | 
|  | { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x9A, 0xBC}}, | 
|  | // frame type (two-byte encoding) | 
|  | {"", | 
|  | {kVarInt62TwoBytes + 0x00, 0x09}} | 
|  | }, | 
|  | { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x9A, 0xBC}}, | 
|  | // frame type (two-byte encoding) | 
|  | {"", | 
|  | {kVarInt62TwoBytes + 0x00, 0x0a}} | 
|  | }, | 
|  | { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x9A, 0xBC}}, | 
|  | // frame type (two-byte encoding) | 
|  | {"", | 
|  | {kVarInt62TwoBytes + 0x00, 0x0b}} | 
|  | }, | 
|  | { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x9A, 0xBC}}, | 
|  | // frame type (two-byte encoding) | 
|  | {"", | 
|  | {kVarInt62TwoBytes + 0x00, 0x0c}} | 
|  | }, | 
|  | { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x9A, 0xBC}}, | 
|  | // frame type (two-byte encoding) | 
|  | {"", | 
|  | {kVarInt62TwoBytes + 0x00, 0x0d}} | 
|  | }, | 
|  | { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x9A, 0xBC}}, | 
|  | // frame type (two-byte encoding) | 
|  | {"", | 
|  | {kVarInt62TwoBytes + 0x00, 0x0e}} | 
|  | }, | 
|  | { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x9A, 0xBC}}, | 
|  | // frame type (two-byte encoding) | 
|  | {"", | 
|  | {kVarInt62TwoBytes + 0x00, 0x0f}} | 
|  | }, | 
|  | { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x9A, 0xBC}}, | 
|  | // frame type (two-byte encoding) | 
|  | {"", | 
|  | {kVarInt62TwoBytes + 0x00, 0x10}} | 
|  | }, | 
|  | { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x9A, 0xBC}}, | 
|  | // frame type (two-byte encoding) | 
|  | {"", | 
|  | {kVarInt62TwoBytes + 0x00, 0x11}} | 
|  | }, | 
|  | { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x9A, 0xBC}}, | 
|  | // frame type (two-byte encoding) | 
|  | {"", | 
|  | {kVarInt62TwoBytes + 0x00, 0x12}} | 
|  | }, | 
|  | { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x9A, 0xBC}}, | 
|  | // frame type (two-byte encoding) | 
|  | {"", | 
|  | {kVarInt62TwoBytes + 0x00, 0x13}} | 
|  | }, | 
|  | { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x9A, 0xBC}}, | 
|  | // frame type (two-byte encoding) | 
|  | {"", | 
|  | {kVarInt62TwoBytes + 0x00, 0x14}} | 
|  | }, | 
|  | { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x9A, 0xBC}}, | 
|  | // frame type (two-byte encoding) | 
|  | {"", | 
|  | {kVarInt62TwoBytes + 0x00, 0x15}} | 
|  | }, | 
|  | { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x9A, 0xBC}}, | 
|  | // frame type (two-byte encoding) | 
|  | {"", | 
|  | {kVarInt62TwoBytes + 0x00, 0x16}} | 
|  | }, | 
|  | { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x9A, 0xBC}}, | 
|  | // frame type (two-byte encoding) | 
|  | {"", | 
|  | {kVarInt62TwoBytes + 0x00, 0x17}} | 
|  | }, | 
|  | { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x9A, 0xBC}}, | 
|  | // frame type (two-byte encoding) | 
|  | {"", | 
|  | {kVarInt62TwoBytes + 0x00, 0x18}} | 
|  | }, | 
|  | { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x9A, 0xBC}}, | 
|  | // frame type (two-byte encoding) | 
|  | {"", | 
|  | {kVarInt62TwoBytes + 0x00, 0x20}} | 
|  | }, | 
|  | { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x9A, 0xBC}}, | 
|  | // frame type (two-byte encoding) | 
|  | {"", | 
|  | {kVarInt62TwoBytes + 0x00, 0x21}} | 
|  | }, | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | for (PacketFragments& packet : packets) { | 
|  | std::unique_ptr<QuicEncryptedPacket> encrypted( | 
|  | AssemblePacketFromFragments(packet)); | 
|  |  | 
|  | EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); | 
|  |  | 
|  | EXPECT_EQ(IETF_QUIC_PROTOCOL_VIOLATION, framer_.error()); | 
|  | EXPECT_EQ("Frame type not minimally encoded.", framer_.detailed_error()); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, RetireConnectionIdFrame) { | 
|  | if (framer_.transport_version() != QUIC_VERSION_99) { | 
|  | // This frame is only for version 99. | 
|  | return; | 
|  | } | 
|  | // clang-format off | 
|  | PacketFragments packet99 = { | 
|  | // type (short header, 4 byte packet number) | 
|  | {"", | 
|  | {0x43}}, | 
|  | // connection_id | 
|  | {"", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, | 
|  | // packet number | 
|  | {"", | 
|  | {0x12, 0x34, 0x56, 0x78}}, | 
|  | // frame type (IETF_RETIRE_CONNECTION_ID frame) | 
|  | {"", | 
|  | {0x19}}, | 
|  | // Sequence number | 
|  | {"Unable to read retire connection ID frame sequence number.", | 
|  | {kVarInt62TwoBytes + 0x11, 0x22}} | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | std::unique_ptr<QuicEncryptedPacket> encrypted( | 
|  | AssemblePacketFromFragments(packet99)); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); | 
|  |  | 
|  | EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_TRUE(CheckDecryption( | 
|  | *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, | 
|  | PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); | 
|  |  | 
|  | EXPECT_EQ(0u, visitor_.stream_frames_.size()); | 
|  |  | 
|  | EXPECT_EQ(0x1122u, visitor_.retire_connection_id_.sequence_number); | 
|  |  | 
|  | ASSERT_EQ(0u, visitor_.ack_frames_.size()); | 
|  |  | 
|  | CheckFramingBoundaries(packet99, QUIC_INVALID_RETIRE_CONNECTION_ID_DATA); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, BuildRetireConnectionIdFramePacket) { | 
|  | if (framer_.transport_version() != QUIC_VERSION_99) { | 
|  | // This frame is only for version 99. | 
|  | return; | 
|  | } | 
|  | QuicPacketHeader header; | 
|  | header.destination_connection_id = FramerTestConnectionId(); | 
|  | header.reset_flag = false; | 
|  | header.version_flag = false; | 
|  | header.packet_number = kPacketNumber; | 
|  |  | 
|  | QuicRetireConnectionIdFrame frame; | 
|  | frame.sequence_number = 0x1122; | 
|  |  | 
|  | QuicFrames frames = {QuicFrame(&frame)}; | 
|  |  | 
|  | // clang-format off | 
|  | unsigned char packet99[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (IETF_RETIRE_CONNECTION_ID frame) | 
|  | 0x19, | 
|  | // sequence number | 
|  | kVarInt62TwoBytes + 0x11, 0x22 | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  |  | 
|  | test::CompareCharArraysWithHexError("constructed packet", data->data(), | 
|  | data->length(), AsChars(packet99), | 
|  | QUIC_ARRAYSIZE(packet99)); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, AckFrameWithInvalidLargestObserved) { | 
|  | // clang-format off | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x2C, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (ack frame) | 
|  | 0x45, | 
|  | // largest observed | 
|  | 0x00, 0x00, | 
|  | // Zero delta time. | 
|  | 0x00, 0x00, | 
|  | // first ack block length. | 
|  | 0x00, 0x00, | 
|  | // num timestamps. | 
|  | 0x00 | 
|  | }; | 
|  |  | 
|  | unsigned char packet44[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x32, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (ack frame) | 
|  | 0x45, | 
|  | // largest observed | 
|  | 0x00, 0x00, | 
|  | // Zero delta time. | 
|  | 0x00, 0x00, | 
|  | // first ack block length. | 
|  | 0x00, 0x00, | 
|  | // num timestamps. | 
|  | 0x00 | 
|  | }; | 
|  |  | 
|  | unsigned char packet46[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (ack frame) | 
|  | 0x45, | 
|  | // largest observed | 
|  | 0x00, 0x00, | 
|  | // Zero delta time. | 
|  | 0x00, 0x00, | 
|  | // first ack block length. | 
|  | 0x00, 0x00, | 
|  | // num timestamps. | 
|  | 0x00 | 
|  | }; | 
|  |  | 
|  | unsigned char packet99[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (IETF_ACK frame) | 
|  | 0x02, | 
|  | // Largest acked | 
|  | kVarInt62OneByte + 0x00, | 
|  | // Zero delta time. | 
|  | kVarInt62OneByte + 0x00, | 
|  | // Ack block count 0 | 
|  | kVarInt62OneByte + 0x00, | 
|  | // First ack block length | 
|  | kVarInt62OneByte + 0x00, | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | unsigned char* p = packet; | 
|  | size_t p_size = QUIC_ARRAYSIZE(packet); | 
|  | if (framer_.transport_version() == QUIC_VERSION_99) { | 
|  | p = packet99; | 
|  | p_size = QUIC_ARRAYSIZE(packet99); | 
|  | } else if (framer_.transport_version() > QUIC_VERSION_44) { | 
|  | p = packet46; | 
|  | } else if (framer_.transport_version() > QUIC_VERSION_43) { | 
|  | p = packet44; | 
|  | p_size = QUIC_ARRAYSIZE(packet44); | 
|  | } | 
|  |  | 
|  | QuicEncryptedPacket encrypted(AsChars(p), p_size, false); | 
|  | EXPECT_FALSE(framer_.ProcessPacket(encrypted)); | 
|  | EXPECT_EQ(framer_.detailed_error(), "Largest acked is 0."); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, FirstAckBlockJustUnderFlow) { | 
|  | // clang-format off | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x2C, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (ack frame) | 
|  | 0x45, | 
|  | // largest observed | 
|  | 0x00, 0x02, | 
|  | // Zero delta time. | 
|  | 0x00, 0x00, | 
|  | // first ack block length. | 
|  | 0x00, 0x03, | 
|  | // num timestamps. | 
|  | 0x00 | 
|  | }; | 
|  |  | 
|  | unsigned char packet44[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x32, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (ack frame) | 
|  | 0x45, | 
|  | // largest observed | 
|  | 0x00, 0x02, | 
|  | // Zero delta time. | 
|  | 0x00, 0x00, | 
|  | // first ack block length. | 
|  | 0x00, 0x03, | 
|  | // num timestamps. | 
|  | 0x00 | 
|  | }; | 
|  |  | 
|  | unsigned char packet46[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (ack frame) | 
|  | 0x45, | 
|  | // largest observed | 
|  | 0x00, 0x02, | 
|  | // Zero delta time. | 
|  | 0x00, 0x00, | 
|  | // first ack block length. | 
|  | 0x00, 0x03, | 
|  | // num timestamps. | 
|  | 0x00 | 
|  | }; | 
|  |  | 
|  | unsigned char packet99[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (IETF_ACK frame) | 
|  | 0x02, | 
|  | // Largest acked | 
|  | kVarInt62OneByte + 0x02, | 
|  | // Zero delta time. | 
|  | kVarInt62OneByte + 0x00, | 
|  | // Ack block count 0 | 
|  | kVarInt62OneByte + 0x00, | 
|  | // First ack block length | 
|  | kVarInt62OneByte + 0x02, | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | unsigned char* p = packet; | 
|  | size_t p_size = QUIC_ARRAYSIZE(packet); | 
|  | if (framer_.transport_version() == QUIC_VERSION_99) { | 
|  | p = packet99; | 
|  | p_size = QUIC_ARRAYSIZE(packet99); | 
|  | } else if (framer_.transport_version() > QUIC_VERSION_44) { | 
|  | p = packet46; | 
|  | p_size = QUIC_ARRAYSIZE(packet46); | 
|  | } else if (framer_.transport_version() > QUIC_VERSION_43) { | 
|  | p = packet44; | 
|  | p_size = QUIC_ARRAYSIZE(packet44); | 
|  | } | 
|  |  | 
|  | QuicEncryptedPacket encrypted(AsChars(p), p_size, false); | 
|  | EXPECT_FALSE(framer_.ProcessPacket(encrypted)); | 
|  | EXPECT_EQ(framer_.detailed_error(), | 
|  | "Underflow with first ack block length 3 largest acked is 2."); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, ThirdAckBlockJustUnderflow) { | 
|  | // clang-format off | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x2C, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (ack frame) | 
|  | 0x60, | 
|  | // largest observed | 
|  | 0x0A, | 
|  | // Zero delta time. | 
|  | 0x00, 0x00, | 
|  | // Num of ack blocks | 
|  | 0x02, | 
|  | // first ack block length. | 
|  | 0x02, | 
|  | // gap to next block | 
|  | 0x01, | 
|  | // ack block length | 
|  | 0x01, | 
|  | // gap to next block | 
|  | 0x01, | 
|  | // ack block length | 
|  | 0x06, | 
|  | // num timestamps. | 
|  | 0x00 | 
|  | }; | 
|  |  | 
|  | unsigned char packet44[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x32, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (ack frame) | 
|  | 0x60, | 
|  | // largest observed | 
|  | 0x0A, | 
|  | // Zero delta time. | 
|  | 0x00, 0x00, | 
|  | // Num of ack blocks | 
|  | 0x02, | 
|  | // first ack block length. | 
|  | 0x02, | 
|  | // gap to next block | 
|  | 0x01, | 
|  | // ack block length | 
|  | 0x01, | 
|  | // gap to next block | 
|  | 0x01, | 
|  | // ack block length | 
|  | 0x06, | 
|  | // num timestamps. | 
|  | 0x00 | 
|  | }; | 
|  |  | 
|  | unsigned char packet46[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (ack frame) | 
|  | 0x60, | 
|  | // largest observed | 
|  | 0x0A, | 
|  | // Zero delta time. | 
|  | 0x00, 0x00, | 
|  | // Num of ack blocks | 
|  | 0x02, | 
|  | // first ack block length. | 
|  | 0x02, | 
|  | // gap to next block | 
|  | 0x01, | 
|  | // ack block length | 
|  | 0x01, | 
|  | // gap to next block | 
|  | 0x01, | 
|  | // ack block length | 
|  | 0x06, | 
|  | // num timestamps. | 
|  | 0x00 | 
|  | }; | 
|  |  | 
|  | unsigned char packet99[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  |  | 
|  | // frame type (IETF_ACK frame) | 
|  | 0x02, | 
|  | // Largest acked | 
|  | kVarInt62OneByte + 0x0A, | 
|  | // Zero delta time. | 
|  | kVarInt62OneByte + 0x00, | 
|  | // Ack block count 2 | 
|  | kVarInt62OneByte + 0x02, | 
|  | // First ack block length | 
|  | kVarInt62OneByte + 0x01, | 
|  | // gap to next block length | 
|  | kVarInt62OneByte + 0x00, | 
|  | // ack block length | 
|  | kVarInt62OneByte + 0x00, | 
|  | // gap to next block length | 
|  | kVarInt62OneByte + 0x00, | 
|  | // ack block length | 
|  | kVarInt62OneByte + 0x05, | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | unsigned char* p = packet; | 
|  | size_t p_size = QUIC_ARRAYSIZE(packet); | 
|  | if (framer_.transport_version() == QUIC_VERSION_99) { | 
|  | p = packet99; | 
|  | p_size = QUIC_ARRAYSIZE(packet99); | 
|  | } else if (framer_.transport_version() > QUIC_VERSION_44) { | 
|  | p = packet46; | 
|  | p_size = QUIC_ARRAYSIZE(packet46); | 
|  | } else if (framer_.transport_version() > QUIC_VERSION_43) { | 
|  | p = packet44; | 
|  | p_size = QUIC_ARRAYSIZE(packet44); | 
|  | } | 
|  |  | 
|  | QuicEncryptedPacket encrypted(AsChars(p), p_size, false); | 
|  | EXPECT_FALSE(framer_.ProcessPacket(encrypted)); | 
|  | if (framer_.transport_version() == QUIC_VERSION_99) { | 
|  | EXPECT_EQ(framer_.detailed_error(), | 
|  | "Underflow with ack block length 6 latest ack block end is 5."); | 
|  | } else { | 
|  | EXPECT_EQ(framer_.detailed_error(), | 
|  | "Underflow with ack block length 6, end of block is 6."); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, CoalescedPacket) { | 
|  | if (!QuicVersionHasLongHeaderLengths(framer_.transport_version())) { | 
|  | return; | 
|  | } | 
|  | // clang-format off | 
|  | unsigned char packet[] = { | 
|  | // first coalesced packet | 
|  | // public flags (long header with packet type ZERO_RTT_PROTECTED and | 
|  | // 4-byte packet number) | 
|  | 0xD3, | 
|  | // version | 
|  | QUIC_VERSION_BYTES, | 
|  | // destination connection ID length | 
|  | 0x50, | 
|  | // destination connection ID | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // long header packet length | 
|  | 0x1E, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  | // frame type (IETF_STREAM frame with FIN, LEN, and OFFSET bits set) | 
|  | 0x08 | 0x01 | 0x02 | 0x04, | 
|  | // stream id | 
|  | kVarInt62FourBytes + 0x00, 0x02, 0x03, 0x04, | 
|  | // offset | 
|  | kVarInt62EightBytes + 0x3A, 0x98, 0xFE, 0xDC, | 
|  | 0x32, 0x10, 0x76, 0x54, | 
|  | // data length | 
|  | kVarInt62OneByte + 0x0c, | 
|  | // data | 
|  | 'h',  'e',  'l',  'l', | 
|  | 'o',  ' ',  'w',  'o', | 
|  | 'r',  'l',  'd',  '!', | 
|  | // second coalesced packet | 
|  | // public flags (long header with packet type ZERO_RTT_PROTECTED and | 
|  | // 4-byte packet number) | 
|  | 0xD3, | 
|  | // version | 
|  | QUIC_VERSION_BYTES, | 
|  | // destination connection ID length | 
|  | 0x50, | 
|  | // destination connection ID | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // long header packet length | 
|  | 0x1E, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x79, | 
|  | // frame type (IETF_STREAM frame with FIN, LEN, and OFFSET bits set) | 
|  | 0x08 | 0x01 | 0x02 | 0x04, | 
|  | // stream id | 
|  | kVarInt62FourBytes + 0x00, 0x02, 0x03, 0x04, | 
|  | // offset | 
|  | kVarInt62EightBytes + 0x3A, 0x98, 0xFE, 0xDC, | 
|  | 0x32, 0x10, 0x76, 0x54, | 
|  | // data length | 
|  | kVarInt62OneByte + 0x0c, | 
|  | // data | 
|  | 'H',  'E',  'L',  'L', | 
|  | 'O',  '_',  'W',  'O', | 
|  | 'R',  'L',  'D',  '?', | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | QuicEncryptedPacket encrypted(AsChars(packet), QUIC_ARRAYSIZE(packet), false); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(encrypted)); | 
|  |  | 
|  | EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  |  | 
|  | ASSERT_EQ(1u, visitor_.stream_frames_.size()); | 
|  | EXPECT_EQ(0u, visitor_.ack_frames_.size()); | 
|  |  | 
|  | // Stream ID should be the last 3 bytes of kStreamId. | 
|  | EXPECT_EQ(0x00FFFFFF & kStreamId, visitor_.stream_frames_[0]->stream_id); | 
|  | EXPECT_TRUE(visitor_.stream_frames_[0]->fin); | 
|  | EXPECT_EQ(kStreamOffset, visitor_.stream_frames_[0]->offset); | 
|  | CheckStreamFrameData("hello world!", visitor_.stream_frames_[0].get()); | 
|  |  | 
|  | ASSERT_EQ(visitor_.coalesced_packets_.size(), 1u); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(*visitor_.coalesced_packets_[0].get())); | 
|  |  | 
|  | EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  |  | 
|  | ASSERT_EQ(2u, visitor_.stream_frames_.size()); | 
|  | EXPECT_EQ(0u, visitor_.ack_frames_.size()); | 
|  |  | 
|  | // Stream ID should be the last 3 bytes of kStreamId. | 
|  | EXPECT_EQ(0x00FFFFFF & kStreamId, visitor_.stream_frames_[1]->stream_id); | 
|  | EXPECT_TRUE(visitor_.stream_frames_[1]->fin); | 
|  | EXPECT_EQ(kStreamOffset, visitor_.stream_frames_[1]->offset); | 
|  | CheckStreamFrameData("HELLO_WORLD?", visitor_.stream_frames_[1].get()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, MismatchedCoalescedPacket) { | 
|  | if (!QuicVersionHasLongHeaderLengths(framer_.transport_version())) { | 
|  | return; | 
|  | } | 
|  | // clang-format off | 
|  | unsigned char packet[] = { | 
|  | // first coalesced packet | 
|  | // public flags (long header with packet type ZERO_RTT_PROTECTED and | 
|  | // 4-byte packet number) | 
|  | 0xD3, | 
|  | // version | 
|  | QUIC_VERSION_BYTES, | 
|  | // destination connection ID length | 
|  | 0x50, | 
|  | // destination connection ID | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // long header packet length | 
|  | 0x1E, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  | // frame type (IETF_STREAM frame with FIN, LEN, and OFFSET bits set) | 
|  | 0x08 | 0x01 | 0x02 | 0x04, | 
|  | // stream id | 
|  | kVarInt62FourBytes + 0x00, 0x02, 0x03, 0x04, | 
|  | // offset | 
|  | kVarInt62EightBytes + 0x3A, 0x98, 0xFE, 0xDC, | 
|  | 0x32, 0x10, 0x76, 0x54, | 
|  | // data length | 
|  | kVarInt62OneByte + 0x0c, | 
|  | // data | 
|  | 'h',  'e',  'l',  'l', | 
|  | 'o',  ' ',  'w',  'o', | 
|  | 'r',  'l',  'd',  '!', | 
|  | // second coalesced packet | 
|  | // public flags (long header with packet type ZERO_RTT_PROTECTED and | 
|  | // 4-byte packet number) | 
|  | 0xD3, | 
|  | // version | 
|  | QUIC_VERSION_BYTES, | 
|  | // destination connection ID length | 
|  | 0x50, | 
|  | // destination connection ID | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x11, | 
|  | // long header packet length | 
|  | 0x1E, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x79, | 
|  | // frame type (IETF_STREAM frame with FIN, LEN, and OFFSET bits set) | 
|  | 0x08 | 0x01 | 0x02 | 0x04, | 
|  | // stream id | 
|  | kVarInt62FourBytes + 0x00, 0x02, 0x03, 0x04, | 
|  | // offset | 
|  | kVarInt62EightBytes + 0x3A, 0x98, 0xFE, 0xDC, | 
|  | 0x32, 0x10, 0x76, 0x54, | 
|  | // data length | 
|  | kVarInt62OneByte + 0x0c, | 
|  | // data | 
|  | 'H',  'E',  'L',  'L', | 
|  | 'O',  '_',  'W',  'O', | 
|  | 'R',  'L',  'D',  '?', | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | QuicEncryptedPacket encrypted(AsChars(packet), QUIC_ARRAYSIZE(packet), false); | 
|  | EXPECT_QUIC_PEER_BUG(EXPECT_TRUE(framer_.ProcessPacket(encrypted)), | 
|  | "Server: Received mismatched coalesced header.*"); | 
|  |  | 
|  | EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  |  | 
|  | ASSERT_EQ(1u, visitor_.stream_frames_.size()); | 
|  | EXPECT_EQ(0u, visitor_.ack_frames_.size()); | 
|  |  | 
|  | // Stream ID should be the last 3 bytes of kStreamId. | 
|  | EXPECT_EQ(0x00FFFFFF & kStreamId, visitor_.stream_frames_[0]->stream_id); | 
|  | EXPECT_TRUE(visitor_.stream_frames_[0]->fin); | 
|  | EXPECT_EQ(kStreamOffset, visitor_.stream_frames_[0]->offset); | 
|  | CheckStreamFrameData("hello world!", visitor_.stream_frames_[0].get()); | 
|  |  | 
|  | ASSERT_EQ(visitor_.coalesced_packets_.size(), 0u); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, InvalidCoalescedPacket) { | 
|  | if (!QuicVersionHasLongHeaderLengths(framer_.transport_version())) { | 
|  | return; | 
|  | } | 
|  | // clang-format off | 
|  | unsigned char packet[] = { | 
|  | // first coalesced packet | 
|  | // public flags (long header with packet type ZERO_RTT_PROTECTED and | 
|  | // 4-byte packet number) | 
|  | 0xD3, | 
|  | // version | 
|  | QUIC_VERSION_BYTES, | 
|  | // destination connection ID length | 
|  | 0x50, | 
|  | // destination connection ID | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, | 
|  | // long header packet length | 
|  | 0x1E, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  | // frame type (IETF_STREAM frame with FIN, LEN, and OFFSET bits set) | 
|  | 0x08 | 0x01 | 0x02 | 0x04, | 
|  | // stream id | 
|  | kVarInt62FourBytes + 0x00, 0x02, 0x03, 0x04, | 
|  | // offset | 
|  | kVarInt62EightBytes + 0x3A, 0x98, 0xFE, 0xDC, | 
|  | 0x32, 0x10, 0x76, 0x54, | 
|  | // data length | 
|  | kVarInt62OneByte + 0x0c, | 
|  | // data | 
|  | 'h',  'e',  'l',  'l', | 
|  | 'o',  ' ',  'w',  'o', | 
|  | 'r',  'l',  'd',  '!', | 
|  | // second coalesced packet | 
|  | // public flags (long header with packet type ZERO_RTT_PROTECTED and | 
|  | // 4-byte packet number) | 
|  | 0xD3, | 
|  | // version would be here but we cut off the invalid coalesced header. | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | QuicEncryptedPacket encrypted(AsChars(packet), QUIC_ARRAYSIZE(packet), false); | 
|  | EXPECT_QUIC_PEER_BUG(EXPECT_TRUE(framer_.ProcessPacket(encrypted)), | 
|  | "Server: Failed to parse received coalesced header.*"); | 
|  |  | 
|  | EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  |  | 
|  | ASSERT_EQ(1u, visitor_.stream_frames_.size()); | 
|  | EXPECT_EQ(0u, visitor_.ack_frames_.size()); | 
|  |  | 
|  | // Stream ID should be the last 3 bytes of kStreamId. | 
|  | EXPECT_EQ(0x00FFFFFF & kStreamId, visitor_.stream_frames_[0]->stream_id); | 
|  | EXPECT_TRUE(visitor_.stream_frames_[0]->fin); | 
|  | EXPECT_EQ(kStreamOffset, visitor_.stream_frames_[0]->offset); | 
|  | CheckStreamFrameData("hello world!", visitor_.stream_frames_[0].get()); | 
|  |  | 
|  | ASSERT_EQ(visitor_.coalesced_packets_.size(), 0u); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, PacketHeaderWithVariableLengthConnectionId) { | 
|  | if (framer_.transport_version() < QUIC_VERSION_46) { | 
|  | return; | 
|  | } | 
|  | char connection_id_bytes[9] = {0xFE, 0xDC, 0xBA, 0x98, 0x76, | 
|  | 0x54, 0x32, 0x10, 0x42}; | 
|  | QuicConnectionId connection_id(connection_id_bytes, | 
|  | sizeof(connection_id_bytes)); | 
|  | QuicFramerPeer::SetLargestPacketNumber(&framer_, kPacketNumber - 2); | 
|  | QuicFramerPeer::SetExpectedConnectionIDLength(&framer_, | 
|  | connection_id.length()); | 
|  |  | 
|  | // clang-format off | 
|  | PacketFragments packet = { | 
|  | // type (8 byte connection_id and 1 byte packet number) | 
|  | {"Unable to read type.", | 
|  | {0x40}}, | 
|  | // connection_id | 
|  | {"Unable to read Destination ConnectionId.", | 
|  | {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, 0x42}}, | 
|  | // packet number | 
|  | {"Unable to read packet number.", | 
|  | {0x78}}, | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | std::unique_ptr<QuicEncryptedPacket> encrypted( | 
|  | AssemblePacketFromFragments(packet)); | 
|  | EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); | 
|  | EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_EQ(connection_id, visitor_.header_->destination_connection_id); | 
|  | EXPECT_FALSE(visitor_.header_->reset_flag); | 
|  | EXPECT_FALSE(visitor_.header_->version_flag); | 
|  | EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER, visitor_.header_->packet_number_length); | 
|  | EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number); | 
|  |  | 
|  | CheckFramingBoundaries(packet, QUIC_INVALID_PACKET_HEADER); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, UpdateExpectedConnectionIdLength) { | 
|  | if (framer_.transport_version() < QUIC_VERSION_46) { | 
|  | return; | 
|  | } | 
|  | framer_.SetShouldUpdateExpectedConnectionIdLength(true); | 
|  |  | 
|  | // clang-format off | 
|  | unsigned char long_header_packet[] = { | 
|  | // public flags (long header with packet type ZERO_RTT_PROTECTED and | 
|  | // 4-byte packet number) | 
|  | 0xD3, | 
|  | // version | 
|  | QUIC_VERSION_BYTES, | 
|  | // destination connection ID length | 
|  | 0x60, | 
|  | // destination connection ID | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, 0x42, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  | // padding frame | 
|  | 0x00, | 
|  | }; | 
|  | unsigned char long_header_packet99[] = { | 
|  | // public flags (long header with packet type ZERO_RTT_PROTECTED and | 
|  | // 4-byte packet number) | 
|  | 0xD3, | 
|  | // version | 
|  | QUIC_VERSION_BYTES, | 
|  | // destination connection ID length | 
|  | 0x60, | 
|  | // destination connection ID | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, 0x42, | 
|  | // long header packet length | 
|  | 0x05, | 
|  | // packet number | 
|  | 0x12, 0x34, 0x56, 0x78, | 
|  | // padding frame | 
|  | 0x00, | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | if (!QuicVersionHasLongHeaderLengths(framer_.transport_version())) { | 
|  | EXPECT_TRUE(framer_.ProcessPacket( | 
|  | QuicEncryptedPacket(AsChars(long_header_packet), | 
|  | QUIC_ARRAYSIZE(long_header_packet), false))); | 
|  | } else { | 
|  | EXPECT_TRUE(framer_.ProcessPacket( | 
|  | QuicEncryptedPacket(AsChars(long_header_packet99), | 
|  | QUIC_ARRAYSIZE(long_header_packet99), false))); | 
|  | } | 
|  |  | 
|  | EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_EQ(visitor_.header_.get()->destination_connection_id, | 
|  | FramerTestConnectionIdNineBytes()); | 
|  | EXPECT_EQ(visitor_.header_.get()->packet_number, | 
|  | QuicPacketNumber(UINT64_C(0x12345678))); | 
|  |  | 
|  | // clang-format off | 
|  | unsigned char short_header_packet[] = { | 
|  | // type (short header, 4 byte packet number) | 
|  | 0x43, | 
|  | // connection_id | 
|  | 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, 0x42, | 
|  | // packet number | 
|  | 0x13, 0x37, 0x42, 0x33, | 
|  | // padding frame | 
|  | 0x00, | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | QuicEncryptedPacket short_header_encrypted( | 
|  | AsChars(short_header_packet), QUIC_ARRAYSIZE(short_header_packet), false); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(short_header_encrypted)); | 
|  |  | 
|  | EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_EQ(visitor_.header_.get()->destination_connection_id, | 
|  | FramerTestConnectionIdNineBytes()); | 
|  | EXPECT_EQ(visitor_.header_.get()->packet_number, | 
|  | QuicPacketNumber(UINT64_C(0x13374233))); | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  | }  // namespace test | 
|  | }  // namespace quic |