Project import generated by Copybara.
PiperOrigin-RevId: 237361882
Change-Id: I109a68f44db867b20f8c6a7732b0ce657133e52a
diff --git a/quic/core/quic_framer_test.cc b/quic/core/quic_framer_test.cc
new file mode 100644
index 0000000..bcd9db6
--- /dev/null
+++ b/quic/core/quic_framer_test.cc
@@ -0,0 +1,12929 @@
+// 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 <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_string.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));
+}
+
+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_ = QuicString(associated_data);
+ plaintext_ = QuicString(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_;
+ QuicString associated_data_;
+ QuicString 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_ = QuicString(associated_data);
+ ciphertext_ = QuicString(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_;
+ QuicString associated_data_;
+ QuicString 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.
+ QuicString* string_data =
+ new QuicString(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.
+ QuicString* string_data =
+ new QuicString(frame.data_buffer, frame.data_length);
+ crypto_data_.push_back(QuicWrapUnique(string_data));
+ crypto_frames_.push_back(QuicMakeUnique<QuicCryptoFrame>(
+ ENCRYPTION_NONE, 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<QuicString>> stream_data_;
+ std::vector<std::unique_ptr<QuicString>> crypto_data_;
+};
+
+// Simple struct for defining a packet's content, and associated
+// parse error.
+struct PacketFragment {
+ QuicString 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_NONE,
+ std::unique_ptr<QuicDecrypter>(decrypter_));
+ framer_.SetEncrypter(ENCRYPTION_NONE,
+ 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) {
+ QuicString 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,
+ QuicString 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,
+ QuicString 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(QuicString str, QuicStreamFrame* frame) {
+ EXPECT_EQ(str, QuicString(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) {
+ QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT);
+ framer_.SetDecrypter(ENCRYPTION_NONE,
+ 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,
+
+ // 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 (long header with packet type ZERO_RTT_PROTECTED)
+ 0xFC,
+ // version tag
+ QUIC_VERSION_BYTES,
+ // connection_id length
+ 0x50,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0x12, 0x34, 0x56, 0x78,
+
+ // frame type - STREAM with LEN, FIN, 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', '!',
+ };
+ // clang-format on
+
+ unsigned char* p = packet;
+ 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_FALSE(framer_.ProcessPacket(encrypted));
+ if (framer_.transport_version() > QUIC_VERSION_43) {
+ // Cannot read diversification nonce.
+ EXPECT_EQ(QUIC_INVALID_PACKET_HEADER, framer_.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_NONE,
+ 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_NONE,
+ 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_NONE, kStreamOffset,
+ crypto_frame_contents.length());
+ data_producer.SaveCryptoData(ENCRYPTION_NONE, 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!", QuicString(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 = QuicString(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 = QuicString(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 = QuicString(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_NONE);
+
+ 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_NONE);
+ 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_NONE);
+ 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_NONE);
+ 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_NONE);
+ 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_NONE);
+ 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_NONE, 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_NONE, 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_NONE, 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_NONE, 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_NONE, 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 &&
+ QuicString(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_NONE,
+ QuicMakeUnique<NullDecrypter>(framer_.perspective()));
+ framer_.SetEncrypter(ENCRYPTION_NONE,
+ 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 (framer_.version().transport_version < QUIC_VERSION_47) {
+ 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_NONE,
+ QuicMakeUnique<NullDecrypter>(framer_.perspective()));
+ framer_.SetEncrypter(ENCRYPTION_NONE,
+ 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, 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, QuicString((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)));
+
+ QuicString 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);
+}
+
+} // namespace
+} // namespace test
+} // namespace quic