blob: 087aafddcf780759e1d105c2899aa74edf4abec6 [file] [log] [blame]
// 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/quic/core/quic_framer.h"
#include <string.h>
#include <algorithm>
#include <map>
#include <memory>
#include <string>
#include <vector>
#include "base/logging.h"
#include "base/stl_util.h"
#include "net/quic/core/crypto/null_decrypter.h"
#include "net/quic/core/crypto/quic_decrypter.h"
#include "net/quic/core/crypto/quic_encrypter.h"
#include "net/quic/core/quic_protocol.h"
#include "net/quic/core/quic_utils.h"
#include "net/quic/test_tools/quic_framer_peer.h"
#include "net/quic/test_tools/quic_test_utils.h"
#include "net/test/gtest_util.h"
using base::StringPiece;
using std::make_pair;
using std::map;
using std::numeric_limits;
using std::pair;
using std::string;
using std::vector;
using testing::Return;
using testing::Truly;
using testing::_;
namespace net {
namespace test {
const QuicPacketNumber kEpoch = UINT64_C(1) << 48;
const QuicPacketNumber kMask = kEpoch - 1;
// Use fields in which each byte is distinct to ensure that every byte is
// framed correctly. The values are otherwise arbitrary.
const QuicConnectionId kConnectionId = UINT64_C(0xFEDCBA9876543210);
const QuicPathId kPathId = 0x42;
const QuicPacketNumber kPacketNumber = UINT64_C(0x123456789ABC);
const QuicPacketNumber kLargestObserved = UINT64_C(0x0123456789ABF);
const QuicPacketNumber kSmallLargestObserved = UINT16_C(0x1234);
const QuicPacketNumber kMissingPacket = UINT64_C(0x0123456789ABE);
const QuicPacketNumber kSmallMissingPacket = UINT16_C(0x1233);
const QuicPacketNumber kLeastUnacked = UINT64_C(0x0123456789AA0);
const QuicStreamId kStreamId = UINT64_C(0x01020304);
const QuicStreamOffset kStreamOffset = UINT64_C(0xBA98FEDC32107654);
const QuicPublicResetNonceProof kNonceProof = UINT64_C(0xABCDEF0123456789);
// Index into the connection_id offset in the header.
const size_t kConnectionIdOffset = kPublicFlagsSize;
// Index into the version string in the header. (if present).
const size_t kVersionOffset = kConnectionIdOffset + PACKET_8BYTE_CONNECTION_ID;
// Size in bytes of the stream frame fields for an arbitrary StreamID and
// offset and the last frame in a packet.
size_t GetMinStreamFrameSize() {
return kQuicFrameTypeSize + kQuicMaxStreamIdSize + kQuicMaxStreamOffsetSize;
}
// Index into the path id offset in the header (if present).
size_t GetPathIdOffset(QuicConnectionIdLength connection_id_length,
bool include_version) {
return kConnectionIdOffset + connection_id_length +
(include_version ? kQuicVersionSize : 0);
}
// Index into the packet number offset in the header.
size_t GetPacketNumberOffset(QuicConnectionIdLength connection_id_length,
bool include_version,
bool include_path_id) {
return kConnectionIdOffset + connection_id_length +
(include_version ? kQuicVersionSize : 0) +
(include_path_id ? kQuicPathIdSize : 0);
}
size_t GetPacketNumberOffset(bool include_version, bool include_path_id) {
return GetPacketNumberOffset(PACKET_8BYTE_CONNECTION_ID, include_version,
include_path_id);
}
// Index into the private flags offset in the data packet header.
size_t GetPrivateFlagsOffset(QuicConnectionIdLength connection_id_length,
bool include_version,
bool include_path_id) {
return GetPacketNumberOffset(connection_id_length, include_version,
include_path_id) +
PACKET_6BYTE_PACKET_NUMBER;
}
size_t GetPrivateFlagsOffset(bool include_version, bool include_path_id) {
return GetPrivateFlagsOffset(PACKET_8BYTE_CONNECTION_ID, include_version,
include_path_id);
}
size_t GetPrivateFlagsOffset(bool include_version,
bool include_path_id,
QuicPacketNumberLength packet_number_length) {
return GetPacketNumberOffset(PACKET_8BYTE_CONNECTION_ID, include_version,
include_path_id) +
packet_number_length;
}
// Index into the message tag of the public reset packet.
// Public resets always have full connection_ids.
const size_t kPublicResetPacketMessageTagOffset =
kConnectionIdOffset + PACKET_8BYTE_CONNECTION_ID;
class TestEncrypter : public QuicEncrypter {
public:
~TestEncrypter() override {}
bool SetKey(StringPiece key) override { return true; }
bool SetNoncePrefix(StringPiece nonce_prefix) override { return true; }
bool EncryptPacket(QuicPathId path_id,
QuicPacketNumber packet_number,
StringPiece associated_data,
StringPiece plaintext,
char* output,
size_t* output_length,
size_t max_output_length) override {
path_id_ = path_id;
packet_number_ = packet_number;
associated_data_ = associated_data.as_string();
plaintext_ = plaintext.as_string();
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 GetMaxPlaintextSize(size_t ciphertext_size) const override {
return ciphertext_size;
}
size_t GetCiphertextSize(size_t plaintext_size) const override {
return plaintext_size;
}
StringPiece GetKey() const override { return StringPiece(); }
StringPiece GetNoncePrefix() const override { return StringPiece(); }
QuicPathId path_id_;
QuicPacketNumber packet_number_;
string associated_data_;
string plaintext_;
};
class TestDecrypter : public QuicDecrypter {
public:
~TestDecrypter() override {}
bool SetKey(StringPiece key) override { return true; }
bool SetNoncePrefix(StringPiece nonce_prefix) override { return true; }
bool SetPreliminaryKey(StringPiece key) override {
QUIC_BUG << "should not be called";
return false;
}
bool SetDiversificationNonce(DiversificationNonce key) override {
return true;
}
bool DecryptPacket(QuicPathId path_id,
QuicPacketNumber packet_number,
StringPiece associated_data,
StringPiece ciphertext,
char* output,
size_t* output_length,
size_t max_output_length) override {
path_id_ = path_id;
packet_number_ = packet_number;
associated_data_ = associated_data.as_string();
ciphertext_ = ciphertext.as_string();
memcpy(output, ciphertext.data(), ciphertext.length());
*output_length = ciphertext.length();
return true;
}
StringPiece GetKey() const override { return StringPiece(); }
StringPiece GetNoncePrefix() const override { return StringPiece(); }
const char* cipher_name() const override { return "Test"; }
// Use a distinct value starting with 0xFFFFFF, which is never used by TLS.
uint32_t cipher_id() const override { return 0xFFFFFFF2; }
QuicPathId path_id_;
QuicPacketNumber packet_number_;
string associated_data_;
string ciphertext_;
};
class TestQuicVisitor : public QuicFramerVisitorInterface {
public:
TestQuicVisitor()
: error_count_(0),
version_mismatch_(0),
packet_count_(0),
frame_count_(0),
complete_packets_(0),
accept_packet_(true),
accept_public_header_(true) {}
~TestQuicVisitor() override {
base::STLDeleteElements(&stream_frames_);
base::STLDeleteElements(&ack_frames_);
base::STLDeleteElements(&stop_waiting_frames_);
base::STLDeleteElements(&padding_frames_);
base::STLDeleteElements(&ping_frames_);
base::STLDeleteElements(&stream_data_);
}
void OnError(QuicFramer* f) override {
DVLOG(1) << "QuicFramer Error: " << QuicUtils::ErrorToString(f->error())
<< " (" << f->error() << ")";
++error_count_;
}
void OnPacket() override {}
void OnPublicResetPacket(const QuicPublicResetPacket& packet) override {
public_reset_packet_.reset(new QuicPublicResetPacket(packet));
}
void OnVersionNegotiationPacket(
const QuicVersionNegotiationPacket& packet) override {
version_negotiation_packet_.reset(new QuicVersionNegotiationPacket(packet));
}
bool OnProtocolVersionMismatch(QuicVersion version) override {
DVLOG(1) << "QuicFramer Version Mismatch, version: " << version;
++version_mismatch_;
return true;
}
bool OnUnauthenticatedPublicHeader(
const QuicPacketPublicHeader& header) override {
public_header_.reset(new QuicPacketPublicHeader(header));
return accept_public_header_;
}
bool OnUnauthenticatedHeader(const QuicPacketHeader& header) override {
return true;
}
void OnDecryptedPacket(EncryptionLevel level) override {}
bool OnPacketHeader(const QuicPacketHeader& header) override {
if (header.fec_flag) {
// Drop any FEC packet.
return false;
}
++packet_count_;
header_.reset(new QuicPacketHeader(header));
return accept_packet_;
}
bool OnStreamFrame(const QuicStreamFrame& frame) override {
++frame_count_;
// Save a copy of the data so it is valid after the packet is processed.
string* string_data = new string();
StringPiece(frame.data_buffer, frame.data_length)
.AppendToString(string_data);
stream_data_.push_back(string_data);
stream_frames_.push_back(new QuicStreamFrame(frame.stream_id, frame.fin,
frame.offset, *string_data));
return true;
}
bool OnAckFrame(const QuicAckFrame& frame) override {
++frame_count_;
ack_frames_.push_back(new QuicAckFrame(frame));
return true;
}
bool OnStopWaitingFrame(const QuicStopWaitingFrame& frame) override {
++frame_count_;
stop_waiting_frames_.push_back(new QuicStopWaitingFrame(frame));
return true;
}
bool OnPaddingFrame(const QuicPaddingFrame& frame) override {
padding_frames_.push_back(new QuicPaddingFrame(frame));
return true;
}
bool OnPingFrame(const QuicPingFrame& frame) override {
++frame_count_;
ping_frames_.push_back(new QuicPingFrame(frame));
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 OnGoAwayFrame(const QuicGoAwayFrame& frame) override {
goaway_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 OnPathCloseFrame(const QuicPathCloseFrame& frame) override {
path_close_frame_ = frame;
return true;
}
// 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<QuicPacketPublicHeader> public_header_;
std::unique_ptr<QuicPublicResetPacket> public_reset_packet_;
std::unique_ptr<QuicVersionNegotiationPacket> version_negotiation_packet_;
vector<QuicStreamFrame*> stream_frames_;
vector<QuicAckFrame*> ack_frames_;
vector<QuicStopWaitingFrame*> stop_waiting_frames_;
vector<QuicPaddingFrame*> padding_frames_;
vector<QuicPingFrame*> ping_frames_;
QuicRstStreamFrame rst_stream_frame_;
QuicConnectionCloseFrame connection_close_frame_;
QuicGoAwayFrame goaway_frame_;
QuicWindowUpdateFrame window_update_frame_;
QuicBlockedFrame blocked_frame_;
QuicPathCloseFrame path_close_frame_;
vector<string*> stream_data_;
};
class QuicFramerTest : public ::testing::TestWithParam<QuicVersion> {
public:
QuicFramerTest()
: encrypter_(new test::TestEncrypter()),
decrypter_(new test::TestDecrypter()),
start_(QuicTime::Zero() + QuicTime::Delta::FromMicroseconds(0x10)),
framer_(AllSupportedVersions(), start_, Perspective::IS_SERVER) {
version_ = GetParam();
framer_.set_version(version_);
framer_.SetDecrypter(ENCRYPTION_NONE, decrypter_);
framer_.SetEncrypter(ENCRYPTION_NONE, encrypter_);
framer_.set_visitor(&visitor_);
framer_.set_received_entropy_calculator(&entropy_calculator_);
}
// Helper function to get unsigned char representation of digit in the
// units place of the current QUIC version number.
unsigned char GetQuicVersionDigitOnes() {
return static_cast<unsigned char>('0' + version_ % 10);
}
// Helper function to get unsigned char representation of digit in the
// tens place of the current QUIC version number.
unsigned char GetQuicVersionDigitTens() {
return static_cast<unsigned char>('0' + (version_ / 10) % 10);
}
bool CheckEncryption(QuicPathId path_id,
QuicPacketNumber packet_number,
QuicPacket* packet) {
if (packet_number != encrypter_->packet_number_) {
LOG(ERROR) << "Encrypted incorrect packet number. expected "
<< packet_number << " actual: " << encrypter_->packet_number_;
return false;
}
if (packet->AssociatedData(framer_.version()) !=
encrypter_->associated_data_) {
LOG(ERROR) << "Encrypted incorrect associated data. expected "
<< packet->AssociatedData(framer_.version())
<< " actual: " << encrypter_->associated_data_;
return false;
}
if (packet->Plaintext(framer_.version()) != encrypter_->plaintext_) {
LOG(ERROR) << "Encrypted incorrect plaintext data. expected "
<< packet->Plaintext(framer_.version())
<< " actual: " << encrypter_->plaintext_;
return false;
}
return true;
}
bool CheckDecryption(const QuicEncryptedPacket& encrypted,
bool includes_version,
bool includes_path_id,
bool includes_diversification_nonce) {
if (visitor_.header_->packet_number != decrypter_->packet_number_) {
LOG(ERROR) << "Decrypted incorrect packet number. expected "
<< visitor_.header_->packet_number
<< " actual: " << decrypter_->packet_number_;
return false;
}
if (QuicFramer::GetAssociatedDataFromEncryptedPacket(
framer_.version(), encrypted, PACKET_8BYTE_CONNECTION_ID,
includes_version, includes_path_id, includes_diversification_nonce,
PACKET_6BYTE_PACKET_NUMBER) != decrypter_->associated_data_) {
LOG(ERROR) << "Decrypted incorrect associated data. expected "
<< QuicFramer::GetAssociatedDataFromEncryptedPacket(
framer_.version(), encrypted,
PACKET_8BYTE_CONNECTION_ID, includes_version,
includes_path_id, includes_diversification_nonce,
PACKET_6BYTE_PACKET_NUMBER)
<< " actual: " << decrypter_->associated_data_;
return false;
}
StringPiece ciphertext(
encrypted.AsStringPiece().substr(GetStartOfEncryptedData(
framer_.version(), PACKET_8BYTE_CONNECTION_ID, includes_version,
includes_path_id, includes_diversification_nonce,
PACKET_6BYTE_PACKET_NUMBER)));
if (ciphertext != decrypter_->ciphertext_) {
LOG(ERROR) << "Decrypted incorrect ciphertext data. expected "
<< ciphertext << " actual: " << decrypter_->ciphertext_;
return false;
}
return true;
}
char* AsChars(unsigned char* data) { return reinterpret_cast<char*>(data); }
void CheckProcessingFails(unsigned char* packet,
size_t len,
string expected_error,
QuicErrorCode error_code) {
QuicEncryptedPacket encrypted(AsChars(packet), len, false);
EXPECT_FALSE(framer_.ProcessPacket(encrypted)) << "len: " << len;
EXPECT_EQ(expected_error, framer_.detailed_error()) << "len: " << len;
EXPECT_EQ(error_code, framer_.error()) << "len: " << len;
}
// Checks if the supplied string matches data in the supplied StreamFrame.
void CheckStreamFrameData(string str, QuicStreamFrame* frame) {
EXPECT_EQ(str, string(frame->data_buffer, frame->data_length));
}
void CheckStreamFrameBoundaries(unsigned char* packet,
size_t stream_id_size,
bool include_version) {
// Now test framing boundaries.
for (size_t i = kQuicFrameTypeSize; i < GetMinStreamFrameSize(); ++i) {
string expected_error;
if (i < kQuicFrameTypeSize + stream_id_size) {
expected_error = "Unable to read stream_id.";
} else if (i < kQuicFrameTypeSize + stream_id_size +
kQuicMaxStreamOffsetSize) {
expected_error = "Unable to read offset.";
} else {
expected_error = "Unable to read frame data.";
}
CheckProcessingFails(
packet,
i + GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
include_version, !kIncludePathId,
!kIncludeDiversificationNonce,
PACKET_6BYTE_PACKET_NUMBER),
expected_error, QUIC_INVALID_STREAM_DATA);
}
}
void CheckCalculatePacketNumber(QuicPacketNumber expected_packet_number,
QuicPacketNumber last_packet_number) {
QuicPacketNumber wire_packet_number = expected_packet_number & kMask;
QuicFramerPeer::SetLastPacketNumber(&framer_, last_packet_number);
EXPECT_EQ(
expected_packet_number,
QuicFramerPeer::CalculatePacketNumberFromWire(
&framer_, PACKET_6BYTE_PACKET_NUMBER,
QuicFramerPeer::GetLastPacketNumber(&framer_), wire_packet_number))
<< "last_packet_number: " << last_packet_number
<< " wire_packet_number: " << wire_packet_number;
}
QuicPacket* BuildDataPacket(const QuicPacketHeader& header,
const QuicFrames& frames) {
return BuildUnsizedDataPacket(&framer_, header, frames);
}
QuicPacket* BuildDataPacket(const QuicPacketHeader& header,
const QuicFrames& frames,
size_t packet_size) {
return BuildUnsizedDataPacket(&framer_, header, frames, packet_size);
}
QuicFlagSaver flags_; // Save/restore all QUIC flag values.
test::TestEncrypter* encrypter_;
test::TestDecrypter* decrypter_;
QuicVersion version_;
QuicTime start_;
QuicFramer framer_;
test::TestQuicVisitor visitor_;
test::TestEntropyCalculator entropy_calculator_;
};
// Run all framer tests with all supported versions of QUIC.
INSTANTIATE_TEST_CASE_P(QuicFramerTests,
QuicFramerTest,
::testing::ValuesIn(kSupportedQuicVersions));
TEST_P(QuicFramerTest, CalculatePacketNumberFromWireNearEpochStart) {
// A few quick manual sanity checks.
CheckCalculatePacketNumber(UINT64_C(1), UINT64_C(0));
CheckCalculatePacketNumber(kEpoch + 1, kMask);
CheckCalculatePacketNumber(kEpoch, kMask);
// Cases where the last number was close to the start of the range.
for (uint64_t last = 0; last < 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 = 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++) {
uint64_t last = 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 = 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 = 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 = 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)
0x38,
// connection_id
0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
// private flags
0x00,
};
// clang-format on
const size_t header_size = GetPacketHeaderSize(
framer_.version(), PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion,
!kIncludePathId, !kIncludeDiversificationNonce,
PACKET_6BYTE_PACKET_NUMBER);
memset(packet + header_size, 0, kMaxPacketSize - header_size);
QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), 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(kConnectionId, visitor_.header_->public_header.connection_id);
// Make sure the correct error is propagated.
EXPECT_EQ(QUIC_PACKET_TOO_LARGE, framer_.error());
}
TEST_P(QuicFramerTest, PacketHeader) {
// clang-format off
unsigned char packet[] = {
// public flags (8 byte connection_id)
0x38,
// connection_id
0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
// private flags
0x00,
};
unsigned char packet_34[] = {
// public flags (8 byte connection_id)
0x38,
// connection_id
0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
};
// clang-format on
QuicEncryptedPacket encrypted(
AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
: arraysize(packet_34),
false);
EXPECT_FALSE(framer_.ProcessPacket(encrypted));
EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error());
ASSERT_TRUE(visitor_.header_.get());
EXPECT_EQ(kConnectionId, visitor_.header_->public_header.connection_id);
EXPECT_FALSE(visitor_.header_->public_header.multipath_flag);
EXPECT_FALSE(visitor_.header_->public_header.reset_flag);
EXPECT_FALSE(visitor_.header_->public_header.version_flag);
EXPECT_FALSE(visitor_.header_->fec_flag);
EXPECT_FALSE(visitor_.header_->entropy_flag);
EXPECT_EQ(0, visitor_.header_->entropy_hash);
EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number);
// Now test framing boundaries.
for (size_t i = 0;
i < GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
!kIncludeVersion, !kIncludePathId,
!kIncludeDiversificationNonce,
PACKET_6BYTE_PACKET_NUMBER);
++i) {
string expected_error;
if (i < kConnectionIdOffset) {
expected_error = "Unable to read public flags.";
} else if (i < GetPacketNumberOffset(!kIncludeVersion, !kIncludePathId)) {
expected_error = "Unable to read ConnectionId.";
} else {
if (framer_.version() <= QUIC_VERSION_33) {
if (i < GetPrivateFlagsOffset(!kIncludeVersion, !kIncludePathId)) {
expected_error = "Unable to read packet number.";
} else {
expected_error = "Unable to read private flags.";
}
} else {
expected_error = "Unable to read packet number.";
}
}
CheckProcessingFails(
framer_.version() <= QUIC_VERSION_33 ? packet : packet_34, i,
expected_error, QUIC_INVALID_PACKET_HEADER);
}
}
TEST_P(QuicFramerTest, PacketHeaderWith0ByteConnectionId) {
QuicFramerPeer::SetLastSerializedConnectionId(&framer_, kConnectionId);
// clang-format off
unsigned char packet[] = {
// public flags (0 byte connection_id)
0x30,
// connection_id
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// private flags
0x00,
};
unsigned char packet_34[] = {
// public flags (0 byte connection_id)
0x30,
// connection_id
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
};
// clang-format on
QuicEncryptedPacket encrypted(
AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
: arraysize(packet_34),
false);
EXPECT_FALSE(framer_.ProcessPacket(encrypted));
EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error());
ASSERT_TRUE(visitor_.header_.get());
EXPECT_EQ(kConnectionId, visitor_.header_->public_header.connection_id);
EXPECT_FALSE(visitor_.header_->public_header.multipath_flag);
EXPECT_FALSE(visitor_.header_->public_header.reset_flag);
EXPECT_FALSE(visitor_.header_->public_header.version_flag);
EXPECT_FALSE(visitor_.header_->fec_flag);
EXPECT_FALSE(visitor_.header_->entropy_flag);
EXPECT_EQ(0, visitor_.header_->entropy_hash);
EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number);
// Now test framing boundaries.
for (size_t i = 0;
i < GetPacketHeaderSize(framer_.version(), PACKET_0BYTE_CONNECTION_ID,
!kIncludeVersion, !kIncludePathId,
!kIncludeDiversificationNonce,
PACKET_6BYTE_PACKET_NUMBER);
++i) {
string expected_error;
if (i < kConnectionIdOffset) {
expected_error = "Unable to read public flags.";
} else if (i < GetPacketNumberOffset(PACKET_0BYTE_CONNECTION_ID,
!kIncludeVersion, !kIncludePathId)) {
expected_error = "Unable to read ConnectionId.";
} else {
if (framer_.version() <= QUIC_VERSION_33) {
if (i < GetPrivateFlagsOffset(PACKET_0BYTE_CONNECTION_ID,
!kIncludeVersion, !kIncludePathId)) {
expected_error = "Unable to read packet number.";
} else {
expected_error = "Unable to read private flags.";
}
} else {
expected_error = "Unable to read packet number.";
}
}
CheckProcessingFails(
framer_.version() <= QUIC_VERSION_33 ? packet : packet_34, i,
expected_error, QUIC_INVALID_PACKET_HEADER);
}
}
TEST_P(QuicFramerTest, PacketHeaderWithVersionFlag) {
// clang-format off
unsigned char packet[] = {
// public flags (version)
0x39,
// connection_id
0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
// version tag
'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes(),
// packet number
0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
// private flags
0x00,
};
unsigned char packet_34[] = {
// public flags (version)
0x39,
// connection_id
0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
// version tag
'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes(),
// packet number
0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
};
// clang-format on
QuicEncryptedPacket encrypted(
AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
: arraysize(packet_34),
false);
EXPECT_FALSE(framer_.ProcessPacket(encrypted));
EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error());
ASSERT_TRUE(visitor_.header_.get());
EXPECT_EQ(kConnectionId, visitor_.header_->public_header.connection_id);
EXPECT_FALSE(visitor_.header_->public_header.multipath_flag);
EXPECT_FALSE(visitor_.header_->public_header.reset_flag);
EXPECT_TRUE(visitor_.header_->public_header.version_flag);
EXPECT_EQ(GetParam(), visitor_.header_->public_header.versions[0]);
EXPECT_FALSE(visitor_.header_->fec_flag);
EXPECT_FALSE(visitor_.header_->entropy_flag);
EXPECT_EQ(0, visitor_.header_->entropy_hash);
EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number);
// Now test framing boundaries.
for (size_t i = 0;
i < GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
kIncludeVersion, !kIncludePathId,
!kIncludeDiversificationNonce,
PACKET_6BYTE_PACKET_NUMBER);
++i) {
string expected_error;
if (i < kConnectionIdOffset) {
expected_error = "Unable to read public flags.";
} else if (i < kVersionOffset) {
expected_error = "Unable to read ConnectionId.";
} else if (i < GetPacketNumberOffset(kIncludeVersion, !kIncludePathId)) {
expected_error = "Unable to read protocol version.";
} else {
if (framer_.version() <= QUIC_VERSION_33) {
if (i < GetPrivateFlagsOffset(kIncludeVersion, !kIncludePathId)) {
expected_error = "Unable to read packet number.";
} else {
expected_error = "Unable to read private flags.";
}
} else {
expected_error = "Unable to read packet number.";
}
}
CheckProcessingFails(
framer_.version() <= QUIC_VERSION_33 ? packet : packet_34, i,
expected_error, QUIC_INVALID_PACKET_HEADER);
}
}
TEST_P(QuicFramerTest, PacketHeaderWithMultipathFlag) {
// clang-format off
unsigned char packet[] = {
// public flags (version)
0x78,
// connection_id
0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
// path_id
0x42,
// packet number
0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
// private flags
0x00,
};
unsigned char packet_34[] = {
// public flags (version)
0x78,
// connection_id
0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
// path_id
0x42,
// packet number
0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
};
// clang-format on
QuicEncryptedPacket encrypted(
AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
: arraysize(packet_34),
false);
EXPECT_FALSE(framer_.ProcessPacket(encrypted));
EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error());
ASSERT_TRUE(visitor_.header_.get());
EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, kIncludePathId,
!kIncludeDiversificationNonce));
EXPECT_EQ(kConnectionId, visitor_.header_->public_header.connection_id);
EXPECT_TRUE(visitor_.header_->public_header.multipath_flag);
EXPECT_FALSE(visitor_.header_->public_header.reset_flag);
EXPECT_FALSE(visitor_.header_->public_header.version_flag);
EXPECT_FALSE(visitor_.header_->fec_flag);
EXPECT_FALSE(visitor_.header_->entropy_flag);
EXPECT_EQ(0, visitor_.header_->entropy_hash);
EXPECT_EQ(kPathId, visitor_.header_->path_id);
EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number);
// Now test framing boundaries.
for (size_t i = 0;
i < GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
!kIncludeVersion, kIncludePathId,
!kIncludeDiversificationNonce,
PACKET_6BYTE_PACKET_NUMBER);
++i) {
string expected_error;
if (i < kConnectionIdOffset) {
expected_error = "Unable to read public flags.";
} else if (i <
GetPathIdOffset(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion)) {
expected_error = "Unable to read ConnectionId.";
} else if (i < GetPacketNumberOffset(!kIncludeVersion, kIncludePathId)) {
expected_error = "Unable to read path id.";
} else {
if (framer_.version() <= QUIC_VERSION_33) {
if (i < GetPrivateFlagsOffset(!kIncludeVersion, kIncludePathId)) {
expected_error = "Unable to read packet number.";
} else {
expected_error = "Unable to read private flags.";
}
} else {
expected_error = "Unable to read packet number.";
}
}
CheckProcessingFails(
framer_.version() <= QUIC_VERSION_33 ? packet : packet_34, i,
expected_error, QUIC_INVALID_PACKET_HEADER);
}
}
TEST_P(QuicFramerTest, PacketHeaderWithBothVersionFlagAndMultipathFlag) {
// clang-format off
unsigned char packet[] = {
// public flags (version)
0x79,
// connection_id
0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
// version tag
'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes(),
// path_id
0x42,
// packet number
0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
// private flags
0x00,
};
unsigned char packet_34[] = {
// public flags (version)
0x79,
// connection_id
0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
// version tag
'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes(),
// path_id
0x42,
// packet number
0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
};
// clang-format on
QuicEncryptedPacket encrypted(
AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
: arraysize(packet_34),
false);
EXPECT_FALSE(framer_.ProcessPacket(encrypted));
EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error());
ASSERT_TRUE(visitor_.header_.get());
EXPECT_TRUE(CheckDecryption(encrypted, kIncludeVersion, kIncludePathId,
!kIncludeDiversificationNonce));
EXPECT_EQ(kConnectionId, visitor_.header_->public_header.connection_id);
EXPECT_TRUE(visitor_.header_->public_header.multipath_flag);
EXPECT_FALSE(visitor_.header_->public_header.reset_flag);
EXPECT_TRUE(visitor_.header_->public_header.version_flag);
EXPECT_EQ(GetParam(), visitor_.header_->public_header.versions[0]);
EXPECT_FALSE(visitor_.header_->fec_flag);
EXPECT_FALSE(visitor_.header_->entropy_flag);
EXPECT_EQ(0, visitor_.header_->entropy_hash);
EXPECT_EQ(kPathId, visitor_.header_->path_id);
EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number);
// Now test framing boundaries.
for (size_t i = 0;
i < GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
!kIncludeVersion, kIncludePathId,
!kIncludeDiversificationNonce,
PACKET_6BYTE_PACKET_NUMBER);
++i) {
string expected_error;
if (i < kConnectionIdOffset) {
expected_error = "Unable to read public flags.";
} else if (i < kVersionOffset) {
expected_error = "Unable to read ConnectionId.";
} else if (i <
GetPathIdOffset(PACKET_8BYTE_CONNECTION_ID, kIncludeVersion)) {
expected_error = "Unable to read protocol version.";
} else if (i < GetPacketNumberOffset(kIncludeVersion, kIncludePathId)) {
expected_error = "Unable to read path id.";
} else {
if (framer_.version() <= QUIC_VERSION_33) {
if (i < GetPrivateFlagsOffset(kIncludeVersion, kIncludePathId)) {
expected_error = "Unable to read packet number.";
} else {
expected_error = "Unable to read private flags.";
}
} else {
expected_error = "Unable to read packet number.";
}
}
CheckProcessingFails(
framer_.version() <= QUIC_VERSION_33 ? packet : packet_34, i,
expected_error, QUIC_INVALID_PACKET_HEADER);
}
}
TEST_P(QuicFramerTest, PacketHeaderWithPathChange) {
// Packet 1 from path 0x42.
// clang-format off
unsigned char packet1[] = {
// public flags (version)
0x78,
// connection_id
0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
// path_id
0x42,
// packet number
0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
// private flags
0x00,
};
unsigned char packet1_34[] = {
// public flags (version)
0x78,
// connection_id
0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
// path_id
0x42,
// packet number
0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
};
// clang-format on
EXPECT_EQ(0u, QuicFramerPeer::GetLastPacketNumber(&framer_));
EXPECT_EQ(kInvalidPathId, QuicFramerPeer::GetLastPathId(&framer_));
QuicEncryptedPacket encrypted1(
AsChars(framer_.version() <= QUIC_VERSION_33 ? packet1 : packet1_34),
framer_.version() <= QUIC_VERSION_33 ? arraysize(packet1)
: arraysize(packet1_34),
false);
EXPECT_FALSE(framer_.ProcessPacket(encrypted1));
EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error());
ASSERT_TRUE(visitor_.header_.get());
EXPECT_EQ(kConnectionId, visitor_.header_->public_header.connection_id);
EXPECT_EQ(kPathId, visitor_.header_->path_id);
EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number);
EXPECT_EQ(kPacketNumber, QuicFramerPeer::GetLastPacketNumber(&framer_));
EXPECT_EQ(kPathId, QuicFramerPeer::GetLastPathId(&framer_));
// Packet 2 from default path.
// clang-format off
unsigned char packet2[] = {
// public flags (version)
0x78,
// connection_id
0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
// path_id
0x00,
// packet number
0xCC, 0x9A, 0x78, 0x56, 0x34, 0x12,
// private flags
0x00,
};
unsigned char packet2_34[] = {
// public flags (version)
0x78,
// connection_id
0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
// path_id
0x00,
// packet number
0xCC, 0x9A, 0x78, 0x56, 0x34, 0x12,
};
// clang-format on
QuicEncryptedPacket encrypted2(
AsChars(framer_.version() <= QUIC_VERSION_33 ? packet2 : packet2_34),
framer_.version() <= QUIC_VERSION_33 ? arraysize(packet2)
: arraysize(packet2_34),
false);
EXPECT_FALSE(framer_.ProcessPacket(encrypted2));
EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error());
ASSERT_TRUE(visitor_.header_.get());
EXPECT_EQ(kConnectionId, visitor_.header_->public_header.connection_id);
EXPECT_EQ(kDefaultPathId, visitor_.header_->path_id);
EXPECT_EQ(kPacketNumber + 16, visitor_.header_->packet_number);
EXPECT_EQ(kPacketNumber + 16, QuicFramerPeer::GetLastPacketNumber(&framer_));
EXPECT_EQ(kDefaultPathId, QuicFramerPeer::GetLastPathId(&framer_));
// Packet 3 from path 0x42.
// clang-format off
unsigned char packet3[] = {
// public flags (version)
0x78,
// connection_id
0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
// path_id
0x42,
// packet number
0xBD, 0x9A, 0x78, 0x56, 0x34, 0x12,
// private flags
0x00,
};
unsigned char packet3_34[] = {
// public flags (version)
0x78,
// connection_id
0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
// path_id
0x42,
// packet number
0xBD, 0x9A, 0x78, 0x56, 0x34, 0x12,
};
// clang-format on
QuicEncryptedPacket encrypted3(
AsChars(framer_.version() <= QUIC_VERSION_33 ? packet3 : packet3_34),
framer_.version() <= QUIC_VERSION_33 ? arraysize(packet3)
: arraysize(packet3_34),
false);
EXPECT_FALSE(framer_.ProcessPacket(encrypted3));
EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error());
ASSERT_TRUE(visitor_.header_.get());
EXPECT_EQ(kConnectionId, visitor_.header_->public_header.connection_id);
EXPECT_EQ(kPathId, visitor_.header_->path_id);
EXPECT_EQ(kPacketNumber + 1, visitor_.header_->packet_number);
EXPECT_EQ(kPacketNumber + 1, QuicFramerPeer::GetLastPacketNumber(&framer_));
EXPECT_EQ(kPathId, QuicFramerPeer::GetLastPathId(&framer_));
}
TEST_P(QuicFramerTest, ReceivedPacketOnClosedPath) {
// Packet 1 from path 0x42.
// clang-format off
unsigned char packet[] = {
// public flags (version)
0x78,
// connection_id
0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
// path_id
0x42,
// packet number
0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
// private flags
0x00,
};
unsigned char packet_34[] = {
// public flags (version)
0x78,
// connection_id
0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
// path_id
0x42,
// packet number
0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
// private flags
0x00,
};
// clang-format on
framer_.OnPathClosed(kPathId);
QuicEncryptedPacket encrypted(
AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
: arraysize(packet_34),
false);
EXPECT_FALSE(framer_.ProcessPacket(encrypted));
EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
EXPECT_EQ(0u, QuicFramerPeer::GetLastPacketNumber(&framer_));
EXPECT_EQ(kInvalidPathId, QuicFramerPeer::GetLastPathId(&framer_));
}
TEST_P(QuicFramerTest, PacketHeaderWith4BytePacketNumber) {
QuicFramerPeer::SetLastPacketNumber(&framer_, kPacketNumber - 2);
// clang-format off
unsigned char packet[] = {
// public flags (8 byte connection_id and 4 byte packet number)
0x28,
// connection_id
0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56,
// private flags
0x00,
};
unsigned char packet_34[] = {
// public flags (8 byte connection_id and 4 byte packet number)
0x28,
// connection_id
0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56,
};
// clang-format on
QuicEncryptedPacket encrypted(
AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
: arraysize(packet_34),
false);
EXPECT_FALSE(framer_.ProcessPacket(encrypted));
EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error());
ASSERT_TRUE(visitor_.header_.get());
EXPECT_EQ(kConnectionId, visitor_.header_->public_header.connection_id);
EXPECT_FALSE(visitor_.header_->public_header.multipath_flag);
EXPECT_FALSE(visitor_.header_->public_header.reset_flag);
EXPECT_FALSE(visitor_.header_->public_header.version_flag);
EXPECT_FALSE(visitor_.header_->fec_flag);
EXPECT_FALSE(visitor_.header_->entropy_flag);
EXPECT_EQ(0, visitor_.header_->entropy_hash);
EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number);
// Now test framing boundaries.
for (size_t i = 0;
i < GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
!kIncludeVersion, !kIncludePathId,
!kIncludeDiversificationNonce,
PACKET_4BYTE_PACKET_NUMBER);
++i) {
string expected_error;
if (i < kConnectionIdOffset) {
expected_error = "Unable to read public flags.";
} else if (i < GetPacketNumberOffset(!kIncludeVersion, !kIncludePathId)) {
expected_error = "Unable to read ConnectionId.";
} else {
if (framer_.version() <= QUIC_VERSION_33) {
if (i < GetPrivateFlagsOffset(!kIncludeVersion, !kIncludePathId,
PACKET_4BYTE_PACKET_NUMBER)) {
expected_error = "Unable to read packet number.";
} else {
expected_error = "Unable to read private flags.";
}
} else {
expected_error = "Unable to read packet number.";
}
}
CheckProcessingFails(
framer_.version() <= QUIC_VERSION_33 ? packet : packet_34, i,
expected_error, QUIC_INVALID_PACKET_HEADER);
}
}
TEST_P(QuicFramerTest, PacketHeaderWith2BytePacketNumber) {
QuicFramerPeer::SetLastPacketNumber(&framer_, kPacketNumber - 2);
// clang-format off
unsigned char packet[] = {
// public flags (8 byte connection_id and 2 byte packet number)
0x18,
// connection_id
0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A,
// private flags
0x00,
};
unsigned char packet_34[] = {
// public flags (8 byte connection_id and 2 byte packet number)
0x18,
// connection_id
0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A,
};
// clang-format on
QuicEncryptedPacket encrypted(
AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
: arraysize(packet_34),
false);
EXPECT_FALSE(framer_.ProcessPacket(encrypted));
EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error());
ASSERT_TRUE(visitor_.header_.get());
EXPECT_EQ(kConnectionId, visitor_.header_->public_header.connection_id);
EXPECT_FALSE(visitor_.header_->public_header.multipath_flag);
EXPECT_FALSE(visitor_.header_->public_header.reset_flag);
EXPECT_FALSE(visitor_.header_->public_header.version_flag);
EXPECT_FALSE(visitor_.header_->fec_flag);
EXPECT_FALSE(visitor_.header_->entropy_flag);
EXPECT_EQ(0, visitor_.header_->entropy_hash);
EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number);
// Now test framing boundaries.
for (size_t i = 0;
i < GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
!kIncludeVersion, !kIncludePathId,
!kIncludeDiversificationNonce,
PACKET_2BYTE_PACKET_NUMBER);
++i) {
string expected_error;
if (i < kConnectionIdOffset) {
expected_error = "Unable to read public flags.";
} else if (i < GetPacketNumberOffset(!kIncludeVersion, !kIncludePathId)) {
expected_error = "Unable to read ConnectionId.";
} else {
if (framer_.version() <= QUIC_VERSION_33) {
if (i < GetPrivateFlagsOffset(!kIncludeVersion, !kIncludePathId,
PACKET_2BYTE_PACKET_NUMBER)) {
expected_error = "Unable to read packet number.";
} else {
expected_error = "Unable to read private flags.";
}
} else {
expected_error = "Unable to read packet number.";
}
}
CheckProcessingFails(
framer_.version() <= QUIC_VERSION_33 ? packet : packet_34, i,
expected_error, QUIC_INVALID_PACKET_HEADER);
}
}
TEST_P(QuicFramerTest, PacketHeaderWith1BytePacketNumber) {
QuicFramerPeer::SetLastPacketNumber(&framer_, kPacketNumber - 2);
// clang-format off
unsigned char packet[] = {
// public flags (8 byte connection_id and 1 byte packet number)
0x08,
// connection_id
0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC,
// private flags
0x00,
};
unsigned char packet_34[] = {
// public flags (8 byte connection_id and 1 byte packet number)
0x08,
// connection_id
0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC,
};
// clang-format on
QuicEncryptedPacket encrypted(
AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
: arraysize(packet_34),
false);
EXPECT_FALSE(framer_.ProcessPacket(encrypted));
EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error());
ASSERT_TRUE(visitor_.header_.get());
EXPECT_EQ(kConnectionId, visitor_.header_->public_header.connection_id);
EXPECT_FALSE(visitor_.header_->public_header.multipath_flag);
EXPECT_FALSE(visitor_.header_->public_header.reset_flag);
EXPECT_FALSE(visitor_.header_->public_header.version_flag);
EXPECT_FALSE(visitor_.header_->fec_flag);
EXPECT_FALSE(visitor_.header_->entropy_flag);
EXPECT_EQ(0, visitor_.header_->entropy_hash);
EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number);
// Now test framing boundaries.
for (size_t i = 0;
i < GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
!kIncludeVersion, !kIncludePathId,
!kIncludeDiversificationNonce,
PACKET_1BYTE_PACKET_NUMBER);
++i) {
string expected_error;
if (i < kConnectionIdOffset) {
expected_error = "Unable to read public flags.";
} else if (i < GetPacketNumberOffset(!kIncludeVersion, !kIncludePathId)) {
expected_error = "Unable to read ConnectionId.";
} else {
if (framer_.version() <= QUIC_VERSION_33) {
if (i < GetPrivateFlagsOffset(!kIncludeVersion, !kIncludePathId,
PACKET_1BYTE_PACKET_NUMBER)) {
expected_error = "Unable to read packet number.";
} else {
expected_error = "Unable to read private flags.";
}
} else {
expected_error = "Unable to read packet number.";
}
}
CheckProcessingFails(
framer_.version() <= QUIC_VERSION_33 ? packet : packet_34, i,
expected_error, QUIC_INVALID_PACKET_HEADER);
}
}
TEST_P(QuicFramerTest, InvalidPublicFlag) {
if (framer_.version() > QUIC_VERSION_33) {
return;
}
// clang-format off
unsigned char packet[] = {
// public flags: all flags set but the public reset flag and version flag.
0xF8,
// connection_id
0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
// private flags
0x00,
// frame type (padding)
0x00,
0x00, 0x00, 0x00, 0x00
};
// clang-format on
CheckProcessingFails(packet, arraysize(packet), "Illegal public flags value.",
QUIC_INVALID_PACKET_HEADER);
// Now turn off validation.
framer_.set_validate_flags(false);
QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
EXPECT_TRUE(framer_.ProcessPacket(encrypted));
};
TEST_P(QuicFramerTest, PacketWithDiversificationNonce) {
// clang-format off
unsigned char packet[] = {
// public flags: includes nonce flag
0x7C,
// connection_id
0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
// 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
0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
// private flags
0x00,
// frame type (padding)
0x00,
0x00, 0x00, 0x00, 0x00
};
unsigned char packet_34[] = {
// public flags: includes nonce flag
0x7C,
// connection_id
0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
// 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
0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
// frame type (padding)
0x00,
0x00, 0x00, 0x00, 0x00
};
// clang-format on
QuicEncryptedPacket encrypted(
AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
: arraysize(packet_34),
false);
QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT);
if (framer_.version() > QUIC_VERSION_32) {
EXPECT_TRUE(framer_.ProcessPacket(encrypted));
ASSERT_TRUE(visitor_.public_header_->nonce != nullptr);
for (char i = 0; i < 32; ++i) {
EXPECT_EQ(i, (*visitor_.public_header_->nonce)[static_cast<int>(i)]);
}
} else if (framer_.version() < QUIC_VERSION_32) {
// Packet is successfully parsed by accident.
EXPECT_TRUE(framer_.ProcessPacket(encrypted));
ASSERT_TRUE(visitor_.public_header_ != nullptr);
} else {
EXPECT_FALSE(framer_.ProcessPacket(encrypted));
EXPECT_EQ(QUIC_INVALID_PACKET_HEADER, framer_.error());
EXPECT_EQ("Illegal private flags value.", framer_.detailed_error());
}
};
TEST_P(QuicFramerTest, InvalidPublicFlagWithMatchingVersions) {
if (framer_.version() > QUIC_VERSION_33) {
return;
}
// clang-format off
unsigned char packet[] = {
// public flags (8 byte connection_id and version flag and an unknown flag)
0x8D,
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// version tag
'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes(),
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// private flags
0x00,
// frame type (padding)
0x00,
0x00, 0x00, 0x00, 0x00
};
// clang-format on
CheckProcessingFails(packet, arraysize(packet), "Illegal public flags value.",
QUIC_INVALID_PACKET_HEADER);
};
TEST_P(QuicFramerTest, LargePublicFlagWithMismatchedVersions) {
// clang-format off
unsigned char packet[] = {
// public flags (8 byte connection_id, version flag and an unknown flag)
0x79,
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// version tag
'Q', '0', '0', '0',
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// private flags
0x00,
// frame type (padding frame)
0x00,
0x00, 0x00, 0x00, 0x00
};
unsigned char packet_34[] = {
// public flags (8 byte connection_id, version flag and an unknown flag)
0x79,
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// version tag
'Q', '0', '0', '0',
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// frame type (padding frame)
0x00,
0x00, 0x00, 0x00, 0x00
};
// clang-format on
QuicEncryptedPacket encrypted(
AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
: arraysize(packet_34),
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_);
};
TEST_P(QuicFramerTest, InvalidPrivateFlag) {
if (framer_.version() > QUIC_VERSION_33) {
return;
}
// clang-format off
unsigned char packet[] = {
// public flags (8 byte connection_id)
0x38,
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// private flags
0x10,
// frame type (padding)
0x00,
0x00, 0x00, 0x00, 0x00
};
// clang-format on
CheckProcessingFails(packet, arraysize(packet),
"Illegal private flags value.",
QUIC_INVALID_PACKET_HEADER);
};
TEST_P(QuicFramerTest, InvalidFECGroupOffset) {
if (framer_.version() > QUIC_VERSION_33) {
return;
}
// clang-format off
unsigned char packet[] = {
// public flags (8 byte connection_id)
0x38,
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// packet number
0x01, 0x00, 0x00, 0x00,
0x00, 0x00,
// private flags (fec group)
0x02,
// first fec protected packet offset
0x10
};
// clang-format on
if (framer_.version() > QUIC_VERSION_31) {
CheckProcessingFails(packet, arraysize(packet),
"Illegal private flags value.",
QUIC_INVALID_PACKET_HEADER);
} else {
CheckProcessingFails(packet, arraysize(packet),
"First fec protected packet offset must be less "
"than the packet number.",
QUIC_INVALID_PACKET_HEADER);
}
};
TEST_P(QuicFramerTest, PaddingFrame) {
// clang-format off
unsigned char packet[] = {
// public flags (8 byte connection_id)
0x38,
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// private flags
0x00,
// frame type (padding frame)
0x00,
// Ignored data (which in this case is a stream frame)
// frame type (stream frame with fin)
0xFF,
// stream id
0x04, 0x03, 0x02, 0x01,
// offset
0x54, 0x76, 0x10, 0x32,
0xDC, 0xFE, 0x98, 0xBA,
// data length
0x0c, 0x00,
// data
'h', 'e', 'l', 'l',
'o', ' ', 'w', 'o',
'r', 'l', 'd', '!',
};
unsigned char packet_34[] = {
// public flags (8 byte connection_id)
0x38,
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// frame type (padding frame)
0x00,
// Ignored data (which in this case is a stream frame)
// frame type (stream frame with fin)
0xFF,
// stream id
0x04, 0x03, 0x02, 0x01,
// offset
0x54, 0x76, 0x10, 0x32,
0xDC, 0xFE, 0x98, 0xBA,
// data length
0x0c, 0x00,
// data
'h', 'e', 'l', 'l',
'o', ' ', 'w', 'o',
'r', 'l', 'd', '!',
};
// clang-format on
QuicEncryptedPacket encrypted(
AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
: arraysize(packet_34),
false);
EXPECT_TRUE(framer_.ProcessPacket(encrypted));
EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
ASSERT_TRUE(visitor_.header_.get());
EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
!kIncludeDiversificationNonce));
ASSERT_EQ(0u, visitor_.stream_frames_.size());
EXPECT_EQ(0u, visitor_.ack_frames_.size());
// A packet with no frames is not acceptable.
CheckProcessingFails(
packet, GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
!kIncludeVersion, !kIncludePathId,
!kIncludeDiversificationNonce,
PACKET_6BYTE_PACKET_NUMBER),
"Packet has no frames.", QUIC_MISSING_PAYLOAD);
}
TEST_P(QuicFramerTest, StreamFrame) {
// clang-format off
unsigned char packet[] = {
// public flags (8 byte connection_id)
0x38,
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// private flags
0x00,
// frame type (stream frame with fin)
0xFF,
// stream id
0x04, 0x03, 0x02, 0x01,
// offset
0x54, 0x76, 0x10, 0x32,
0xDC, 0xFE, 0x98, 0xBA,
// data length
0x0c, 0x00,
// data
'h', 'e', 'l', 'l',
'o', ' ', 'w', 'o',
'r', 'l', 'd', '!',
};
unsigned char packet_34[] = {
// public flags (8 byte connection_id)
0x38,
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// frame type (stream frame with fin)
0xFF,
// stream id
0x04, 0x03, 0x02, 0x01,
// offset
0x54, 0x76, 0x10, 0x32,
0xDC, 0xFE, 0x98, 0xBA,
// data length
0x0c, 0x00,
// data
'h', 'e', 'l', 'l',
'o', ' ', 'w', 'o',
'r', 'l', 'd', '!',
};
// clang-format on
QuicEncryptedPacket encrypted(
AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
: arraysize(packet_34),
false);
EXPECT_TRUE(framer_.ProcessPacket(encrypted));
EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
ASSERT_TRUE(visitor_.header_.get());
EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
!kIncludeDiversificationNonce));
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]);
// Now test framing boundaries.
CheckStreamFrameBoundaries(
framer_.version() <= QUIC_VERSION_33 ? packet : packet_34,
kQuicMaxStreamIdSize, !kIncludeVersion);
}
TEST_P(QuicFramerTest, MissingDiversificationNonce) {
QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT);
framer_.SetDecrypter(ENCRYPTION_NONE, new NullDecrypter());
decrypter_ = new test::TestDecrypter();
framer_.SetAlternativeDecrypter(ENCRYPTION_INITIAL, decrypter_, false);
// clang-format off
unsigned char packet[] = {
// public flags (8 byte connection_id)
0x38,
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// private flags
0x00,
// frame type (stream frame with fin)
0xFF,
// stream id
0x04, 0x03, 0x02, 0x01,
// offset
0x54, 0x76, 0x10, 0x32,
0xDC, 0xFE, 0x98, 0xBA,
// data length
0x0c, 0x00,
// data
'h', 'e', 'l', 'l',
'o', ' ', 'w', 'o',
'r', 'l', 'd', '!',
};
unsigned char packet_34[] = {
// public flags (8 byte connection_id)
0x38,
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// frame type (stream frame with fin)
0xFF,
// stream id
0x04, 0x03, 0x02, 0x01,
// offset
0x54, 0x76, 0x10, 0x32,
0xDC, 0xFE, 0x98, 0xBA,
// data length
0x0c, 0x00,
// data
'h', 'e', 'l', 'l',
'o', ' ', 'w', 'o',
'r', 'l', 'd', '!',
};
// clang-format on
QuicEncryptedPacket encrypted(
AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
: arraysize(packet_34),
false);
if (framer_.version() > QUIC_VERSION_32) {
EXPECT_FALSE(framer_.ProcessPacket(encrypted));
EXPECT_EQ(QUIC_DECRYPTION_FAILURE, framer_.error());
} else {
EXPECT_TRUE(framer_.ProcessPacket(encrypted));
EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
ASSERT_TRUE(visitor_.header_.get());
EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
!kIncludeDiversificationNonce));
}
}
TEST_P(QuicFramerTest, StreamFrame3ByteStreamId) {
// clang-format off
unsigned char packet[] = {
// public flags (8 byte connection_id)
0x38,
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// private flags
0x00,
// frame type (stream frame with fin)
0xFE,
// stream id
0x04, 0x03, 0x02,
// offset
0x54, 0x76, 0x10, 0x32,
0xDC, 0xFE, 0x98, 0xBA,
// data length
0x0c, 0x00,
// data
'h', 'e', 'l', 'l',
'o', ' ', 'w', 'o',
'r', 'l', 'd', '!',
};
unsigned char packet_34[] = {
// public flags (8 byte connection_id)
0x38,
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// frame type (stream frame with fin)
0xFE,
// stream id
0x04, 0x03, 0x02,
// offset
0x54, 0x76, 0x10, 0x32,
0xDC, 0xFE, 0x98, 0xBA,
// data length
0x0c, 0x00,
// data
'h', 'e', 'l', 'l',
'o', ' ', 'w', 'o',
'r', 'l', 'd', '!',
};
// clang-format on
QuicEncryptedPacket encrypted(
AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
: arraysize(packet_34),
false);
EXPECT_TRUE(framer_.ProcessPacket(encrypted));
EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
ASSERT_TRUE(visitor_.header_.get());
EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
!kIncludeDiversificationNonce));
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]);
// Now test framing boundaries.
const size_t stream_id_size = 3;
CheckStreamFrameBoundaries(
framer_.version() <= QUIC_VERSION_33 ? packet : packet_34, stream_id_size,
!kIncludeVersion);
}
TEST_P(QuicFramerTest, StreamFrame2ByteStreamId) {
// clang-format off
unsigned char packet[] = {
// public flags (8 byte connection_id)
0x38,
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// private flags
0x00,
// frame type (stream frame with fin)
0xFD,
// stream id
0x04, 0x03,
// offset
0x54, 0x76, 0x10, 0x32,
0xDC, 0xFE, 0x98, 0xBA,
// data length
0x0c, 0x00,
// data
'h', 'e', 'l', 'l',
'o', ' ', 'w', 'o',
'r', 'l', 'd', '!',
};
unsigned char packet_34[] = {
// public flags (8 byte connection_id)
0x38,
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// frame type (stream frame with fin)
0xFD,
// stream id
0x04, 0x03,
// offset
0x54, 0x76, 0x10, 0x32,
0xDC, 0xFE, 0x98, 0xBA,
// data length
0x0c, 0x00,
// data
'h', 'e', 'l', 'l',
'o', ' ', 'w', 'o',
'r', 'l', 'd', '!',
};
// clang-format on
QuicEncryptedPacket encrypted(
AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
: arraysize(packet_34),
false);
EXPECT_TRUE(framer_.ProcessPacket(encrypted));
EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
ASSERT_TRUE(visitor_.header_.get());
EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
!kIncludeDiversificationNonce));
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]);
// Now test framing boundaries.
const size_t stream_id_size = 2;
CheckStreamFrameBoundaries(
framer_.version() <= QUIC_VERSION_33 ? packet : packet_34, stream_id_size,
!kIncludeVersion);
}
TEST_P(QuicFramerTest, StreamFrame1ByteStreamId) {
// clang-format off
unsigned char packet[] = {
// public flags (8 byte connection_id)
0x38,
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// private flags
0x00,
// frame type (stream frame with fin)
0xFC,
// stream id
0x04,
// offset
0x54, 0x76, 0x10, 0x32,
0xDC, 0xFE, 0x98, 0xBA,
// data length
0x0c, 0x00,
// data
'h', 'e', 'l', 'l',
'o', ' ', 'w', 'o',
'r', 'l', 'd', '!',
};
unsigned char packet_34[] = {
// public flags (8 byte connection_id)
0x38,
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// frame type (stream frame with fin)
0xFC,
// stream id
0x04,
// offset
0x54, 0x76, 0x10, 0x32,
0xDC, 0xFE, 0x98, 0xBA,
// data length
0x0c, 0x00,
// data
'h', 'e', 'l', 'l',
'o', ' ', 'w', 'o',
'r', 'l', 'd', '!',
};
// clang-format on
QuicEncryptedPacket encrypted(
AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
: arraysize(packet_34),
false);
EXPECT_TRUE(framer_.ProcessPacket(encrypted));
EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
ASSERT_TRUE(visitor_.header_.get());
EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
!kIncludeDiversificationNonce));
ASSERT_EQ(1u, visitor_.stream_frames_.size());
EXPECT_EQ(0u, visitor_.ack_frames_.size());
// Stream ID should be the last 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]);
// Now test framing boundaries.
const size_t stream_id_size = 1;
CheckStreamFrameBoundaries(
framer_.version() <= QUIC_VERSION_33 ? packet : packet_34, stream_id_size,
!kIncludeVersion);
}
TEST_P(QuicFramerTest, StreamFrameWithVersion) {
// clang-format off
unsigned char packet[] = {
// public flags (version, 8 byte connection_id)
0x39,
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// version tag
'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes(),
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// private flags
0x00,
// frame type (stream frame with fin)
0xFF,
// stream id
0x04, 0x03, 0x02, 0x01,
// offset
0x54, 0x76, 0x10, 0x32,
0xDC, 0xFE, 0x98, 0xBA,
// data length
0x0c, 0x00,
// data
'h', 'e', 'l', 'l',
'o', ' ', 'w', 'o',
'r', 'l', 'd', '!',
};
unsigned char packet_34[] = {
// public flags (version, 8 byte connection_id)
0x39,
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// version tag
'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes(),
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// frame type (stream frame with fin)
0xFF,
// stream id
0x04, 0x03, 0x02, 0x01,
// offset
0x54, 0x76, 0x10, 0x32,
0xDC, 0xFE, 0x98, 0xBA,
// data length
0x0c, 0x00,
// data
'h', 'e', 'l', 'l',
'o', ' ', 'w', 'o',
'r', 'l', 'd', '!',
};
// clang-format on
QuicEncryptedPacket encrypted(
AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
: arraysize(packet_34),
false);
EXPECT_TRUE(framer_.ProcessPacket(encrypted));
EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
ASSERT_TRUE(visitor_.header_.get());
EXPECT_TRUE(visitor_.header_->public_header.version_flag);
EXPECT_EQ(GetParam(), visitor_.header_->public_header.versions[0]);
EXPECT_TRUE(CheckDecryption(encrypted, kIncludeVersion, !kIncludePathId,
!kIncludeDiversificationNonce));
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]);
// Now test framing boundaries.
CheckStreamFrameBoundaries(
framer_.version() <= QUIC_VERSION_33 ? packet : packet_34,
kQuicMaxStreamIdSize, kIncludeVersion);
}
TEST_P(QuicFramerTest, RejectPacket) {
visitor_.accept_packet_ = false;
// clang-format off
unsigned char packet[] = {
// public flags (8 byte connection_id)
0x38,
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// private flags
0x00,
// frame type (stream frame with fin)
0xFF,
// stream id
0x04, 0x03, 0x02, 0x01,
// offset
0x54, 0x76, 0x10, 0x32,
0xDC, 0xFE, 0x98, 0xBA,
// data length
0x0c, 0x00,
// data
'h', 'e', 'l', 'l',
'o', ' ', 'w', 'o',
'r', 'l', 'd', '!',
};
unsigned char packet_34[] = {
// public flags (8 byte connection_id)
0x38,
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// frame type (stream frame with fin)
0xFF,
// stream id
0x04, 0x03, 0x02, 0x01,
// offset
0x54, 0x76, 0x10, 0x32,
0xDC, 0xFE, 0x98, 0xBA,
// data length
0x0c, 0x00,
// data
'h', 'e', 'l', 'l',
'o', ' ', 'w', 'o',
'r', 'l', 'd', '!',
};
// clang-format on
QuicEncryptedPacket encrypted(
AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
: arraysize(packet_34),
false);
EXPECT_TRUE(framer_.ProcessPacket(encrypted));
EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
ASSERT_TRUE(visitor_.header_.get());
EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
!kIncludeDiversificationNonce));
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)
0x38,
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
};
// clang-format on
QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
EXPECT_TRUE(framer_.ProcessPacket(encrypted));
EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
ASSERT_TRUE(visitor_.public_header_.get());
ASSERT_FALSE(visitor_.header_.get());
}
TEST_P(QuicFramerTest, AckFrameTwoTimestamp) {
// clang-format off
unsigned char packet[] = {
// public flags (8 byte connection_id)
0x38,
// connection_id
0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xA8, 0x9A, 0x78, 0x56, 0x34, 0x12,
// private flags (entropy)
0x01,
// frame type (ack frame)
// (has nacks, not truncated, 6 byte largest observed, 1 byte delta)
0x6C,
// entropy hash of all received packets.
0xBA,
// largest observed packet number
0xBF, 0x9A, 0x78, 0x56, 0x34, 0x12,
// Zero delta time.
0x00, 0x00,
// Number of timestamps.
0x02,
// Delta from largest observed.
0x01,
// Delta time.
0x10, 0x32, 0x54, 0x76,
// Delta from largest observed.
0x02,
// Delta time.
0x10, 0x32,
// num missing packets
0x01,
// missing packet delta
0x01,
// 0 more missing packets in range.
0x00,
// Number of revived packets.
0x00,
};
// clang-format on
if (framer_.version() > QUIC_VERSION_31) {
return;
}
QuicEncryptedPacket encrypted(AsChars(packet), 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, !kIncludePathId,
!kIncludeDiversificationNonce));
EXPECT_EQ(0u, visitor_.stream_frames_.size());
ASSERT_EQ(1u, visitor_.ack_frames_.size());
const QuicAckFrame& frame = *visitor_.ack_frames_[0];
EXPECT_EQ(0xBA, frame.entropy_hash);
EXPECT_EQ(kLargestObserved, frame.largest_observed);
ASSERT_EQ(1u, frame.packets.NumPacketsSlow());
ASSERT_EQ(2u, frame.received_packet_times.size());
EXPECT_EQ(kMissingPacket, frame.packets.Min());
const size_t kReceivedEntropyOffset = kQuicFrameTypeSize;
const size_t kLargestObservedOffset =
kReceivedEntropyOffset + kQuicEntropyHashSize;
const size_t kMissingDeltaTimeOffset =
kLargestObservedOffset + PACKET_6BYTE_PACKET_NUMBER;
const size_t kNumTimestampsOffset =
kMissingDeltaTimeOffset + kQuicDeltaTimeLargestObservedSize;
const size_t kTimestampDeltaLargestObserved1 =
kNumTimestampsOffset + kQuicNumTimestampsSize;
const size_t kTimestampTimeDeltaLargestObserved1 =
kTimestampDeltaLargestObserved1 + 1;
const size_t kTimestampDeltaLargestObserved2 =
kTimestampTimeDeltaLargestObserved1 + 4;
const size_t kTimestampTimeDeltaLargestObserved2 =
kTimestampDeltaLargestObserved2 + 1;
const size_t kNumMissingPacketOffset =
kTimestampTimeDeltaLargestObserved2 + 2;
const size_t kMissingPacketsOffset =
kNumMissingPacketOffset + kNumberOfNackRangesSize;
const size_t kMissingPacketsRange =
kMissingPacketsOffset + PACKET_1BYTE_PACKET_NUMBER;
const size_t kRevivedPacketsLength =
kMissingPacketsRange + PACKET_1BYTE_PACKET_NUMBER;
// Now test framing boundaries.
const size_t ack_frame_size =
kRevivedPacketsLength + PACKET_1BYTE_PACKET_NUMBER;
for (size_t i = kQuicFrameTypeSize; i < ack_frame_size; ++i) {
string expected_error;
if (i < kLargestObservedOffset) {
expected_error = "Unable to read entropy hash for received packets.";
} else if (i < kMissingDeltaTimeOffset) {
expected_error = "Unable to read largest observed.";
} else if (i < kNumTimestampsOffset) {
expected_error = "Unable to read ack delay time.";
} else if (i < kTimestampDeltaLargestObserved1) {
expected_error = "Unable to read num received packets.";
} else if (i < kTimestampTimeDeltaLargestObserved1) {
expected_error = "Unable to read sequence delta in received packets.";
} else if (i < kTimestampDeltaLargestObserved2) {
expected_error = "Unable to read time delta in received packets.";
} else if (i < kTimestampTimeDeltaLargestObserved2) {
expected_error = "Unable to read sequence delta in received packets.";
} else if (i < kNumMissingPacketOffset) {
expected_error =
"Unable to read incremental time delta in received packets.";
} else if (i < kMissingPacketsOffset) {
expected_error = "Unable to read num missing packet ranges.";
} else if (i < kMissingPacketsRange) {
expected_error = "Unable to read missing packet number delta.";
} else if (i < kRevivedPacketsLength) {
expected_error = "Unable to read missing packet number range.";
} else {
expected_error = "Unable to read num revived packets.";
}
CheckProcessingFails(
packet,
i + GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
!kIncludeVersion, !kIncludePathId,
!kIncludeDiversificationNonce,
PACKET_6BYTE_PACKET_NUMBER),
expected_error, QUIC_INVALID_ACK_DATA);
}
}
TEST_P(QuicFramerTest, AckFrameTwoTimestampVersion32) {
// clang-format off
unsigned char packet[] = {
// public flags (8 byte connection_id)
0x3C,
// connection_id
0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xA8, 0x9A, 0x78, 0x56, 0x34, 0x12,
// private flags (entropy)
0x01,
// frame type (ack frame)
// (has nacks, not truncated, 6 byte largest observed, 1 byte delta)
0x6C,
// entropy hash of all received packets.
0xBA,
// largest observed packet number
0xBF, 0x9A, 0x78, 0x56, 0x34, 0x12,
// Zero delta time.
0x00, 0x00,
// Number of timestamps.
0x02,
// Delta from largest observed.
0x01,
// Delta time.
0x10, 0x32, 0x54, 0x76,
// Delta from largest observed.
0x02,
// Delta time.
0x10, 0x32,
// num missing packets
0x01,
// missing packet delta
0x01,
// 0 more missing packets in range.
0x00,
};
// clang-format on
if (framer_.version() <= QUIC_VERSION_31 ||
framer_.version() > QUIC_VERSION_33) {
return;
}
QuicEncryptedPacket encrypted(AsChars(packet), 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, !kIncludePathId,
!kIncludeDiversificationNonce));
EXPECT_EQ(0u, visitor_.stream_frames_.size());
ASSERT_EQ(1u, visitor_.ack_frames_.size());
const QuicAckFrame& frame = *visitor_.ack_frames_[0];
EXPECT_EQ(0xBA, frame.entropy_hash);
EXPECT_EQ(kLargestObserved, frame.largest_observed);
ASSERT_EQ(1u, frame.packets.NumPacketsSlow());
ASSERT_EQ(2u, frame.received_packet_times.size());
EXPECT_EQ(kMissingPacket, frame.packets.Min());
const size_t kReceivedEntropyOffset = kQuicFrameTypeSize;
const size_t kLargestObservedOffset =
kReceivedEntropyOffset + kQuicEntropyHashSize;
const size_t kMissingDeltaTimeOffset =
kLargestObservedOffset + PACKET_6BYTE_PACKET_NUMBER;
const size_t kNumTimestampsOffset =
kMissingDeltaTimeOffset + kQuicDeltaTimeLargestObservedSize;
const size_t kTimestampDeltaLargestObserved1 =
kNumTimestampsOffset + kQuicNumTimestampsSize;
const size_t kTimestampTimeDeltaLargestObserved1 =
kTimestampDeltaLargestObserved1 + 1;
const size_t kTimestampDeltaLargestObserved2 =
kTimestampTimeDeltaLargestObserved1 + 4;
const size_t kTimestampTimeDeltaLargestObserved2 =
kTimestampDeltaLargestObserved2 + 1;
const size_t kNumMissingPacketOffset =
kTimestampTimeDeltaLargestObserved2 + 2;
const size_t kMissingPacketsOffset =
kNumMissingPacketOffset + kNumberOfNackRangesSize;
// Now test framing boundaries.
const size_t ack_frame_size = PACKET_1BYTE_PACKET_NUMBER;
for (size_t i = kQuicFrameTypeSize; i < ack_frame_size; ++i) {
string expected_error;
if (i < kLargestObservedOffset) {
expected_error = "Unable to read entropy hash for received packets.";
} else if (i < kMissingDeltaTimeOffset) {
expected_error = "Unable to read largest observed.";
} else if (i < kNumTimestampsOffset) {
expected_error = "Unable to read ack delay time.";
} else if (i < kTimestampDeltaLargestObserved1) {
expected_error = "Unable to read num received packets.";
} else if (i < kTimestampTimeDeltaLargestObserved1) {
expected_error = "Unable to read sequence delta in received packets.";
} else if (i < kTimestampDeltaLargestObserved2) {
expected_error = "Unable to read time delta in received packets.";
} else if (i < kTimestampTimeDeltaLargestObserved2) {
expected_error = "Unable to read sequence delta in received packets.";
} else if (i < kNumMissingPacketOffset) {
expected_error =
"Unable to read incremental time delta in received packets.";
} else if (i < kMissingPacketsOffset) {
expected_error = "Unable to read num missing packet ranges.";
} else {
expected_error = "Unable to read missing packet number delta.";
}
CheckProcessingFails(
packet,
i + GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
!kIncludeVersion, !kIncludePathId,
!kIncludeDiversificationNonce,
PACKET_6BYTE_PACKET_NUMBER),
expected_error, QUIC_INVALID_ACK_DATA);
}
}
TEST_P(QuicFramerTest, AckFrameOneTimestamp) {
// clang-format off
unsigned char packet[] = {
// public flags (8 byte connection_id)
0x38,
// connection_id
0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xA8, 0x9A, 0x78, 0x56, 0x34, 0x12,
// private flags (entropy)
0x01,
// frame type (ack frame)
// (has nacks, not truncated, 6 byte largest observed, 1 byte delta)
0x6C,
// entropy hash of all received packets.
0xBA,
// largest observed packet number
0xBF, 0x9A, 0x78, 0x56, 0x34, 0x12,
// Zero delta time.
0x00, 0x00,
// Number of timestamps.
0x01,
// Delta from largest observed.
0x01,
// Delta time.
0x10, 0x32, 0x54, 0x76,
// num missing packets
0x01,
// missing packet delta
0x01,
// 0 more missing packets in range.
0x00,
// Number of revived packets.
0x00,
};
// clang-format on
if (framer_.version() > QUIC_VERSION_31) {
return;
}
QuicEncryptedPacket encrypted(AsChars(packet), 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, !kIncludePathId,
!kIncludeDiversificationNonce));
EXPECT_EQ(0u, visitor_.stream_frames_.size());
ASSERT_EQ(1u, visitor_.ack_frames_.size());
const QuicAckFrame& frame = *visitor_.ack_frames_[0];
EXPECT_EQ(0xBA, frame.entropy_hash);
EXPECT_EQ(kLargestObserved, frame.largest_observed);
ASSERT_EQ(1u, frame.packets.NumPacketsSlow());
ASSERT_EQ(1u, frame.received_packet_times.size());
EXPECT_EQ(kMissingPacket, frame.packets.Min());
const size_t kReceivedEntropyOffset = kQuicFrameTypeSize;
const size_t kLargestObservedOffset =
kReceivedEntropyOffset + kQuicEntropyHashSize;
const size_t kMissingDeltaTimeOffset =
kLargestObservedOffset + PACKET_6BYTE_PACKET_NUMBER;
const size_t kNumTimestampsOffset =
kMissingDeltaTimeOffset + kQuicDeltaTimeLargestObservedSize;
const size_t kTimestampDeltaLargestObserved =
kNumTimestampsOffset + kQuicNumTimestampsSize;
const size_t kTimestampTimeDeltaLargestObserved =
kTimestampDeltaLargestObserved + 1;
const size_t kNumMissingPacketOffset = kTimestampTimeDeltaLargestObserved + 4;
const size_t kMissingPacketsOffset =
kNumMissingPacketOffset + kNumberOfNackRangesSize;
const size_t kMissingPacketsRange =
kMissingPacketsOffset + PACKET_1BYTE_PACKET_NUMBER;
const size_t kRevivedPacketsLength =
kMissingPacketsRange + PACKET_1BYTE_PACKET_NUMBER;
// Now test framing boundaries.
const size_t ack_frame_size =
kRevivedPacketsLength + PACKET_1BYTE_PACKET_NUMBER;
for (size_t i = kQuicFrameTypeSize; i < ack_frame_size; ++i) {
string expected_error;
if (i < kLargestObservedOffset) {
expected_error = "Unable to read entropy hash for received packets.";
} else if (i < kMissingDeltaTimeOffset) {
expected_error = "Unable to read largest observed.";
} else if (i < kNumTimestampsOffset) {
expected_error = "Unable to read ack delay time.";
} else if (i < kTimestampDeltaLargestObserved) {
expected_error = "Unable to read num received packets.";
} else if (i < kTimestampTimeDeltaLargestObserved) {
expected_error = "Unable to read sequence delta in received packets.";
} else if (i < kNumMissingPacketOffset) {
expected_error = "Unable to read time delta in received packets.";
} else if (i < kMissingPacketsOffset) {
expected_error = "Unable to read num missing packet ranges.";
} else if (i < kMissingPacketsRange) {
expected_error = "Unable to read missing packet number delta.";
} else if (i < kRevivedPacketsLength) {
expected_error = "Unable to read missing packet number range.";
} else {
expected_error = "Unable to read num revived packets.";
}
CheckProcessingFails(
packet,
i + GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
!kIncludeVersion, !kIncludePathId,
!kIncludeDiversificationNonce,
PACKET_6BYTE_PACKET_NUMBER),
expected_error, QUIC_INVALID_ACK_DATA);
}
}
TEST_P(QuicFramerTest, AckFrameOneTimestampVersion32) {
// clang-format off
unsigned char packet[] = {
// public flags (8 byte connection_id)
0x3C,
// connection_id
0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xA8, 0x9A, 0x78, 0x56, 0x34, 0x12,
// private flags (entropy)
0x01,
// frame type (ack frame)
// (has nacks, not truncated, 6 byte largest observed, 1 byte delta)
0x6C,
// entropy hash of all received packets.
0xBA,
// largest observed packet number
0xBF, 0x9A, 0x78, 0x56, 0x34, 0x12,
// Zero delta time.
0x00, 0x00,
// Number of timestamps.
0x01,
// Delta from largest observed.
0x01,
// Delta time.
0x10, 0x32, 0x54, 0x76,
// num missing packets
0x01,
// missing packet delta
0x01,
// 0 more missing packets in range.
0x00,
};
// clang-format on
if (framer_.version() <= QUIC_VERSION_31 ||
framer_.version() > QUIC_VERSION_33) {
return;
}
QuicEncryptedPacket encrypted(AsChars(packet), 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, !kIncludePathId,
!kIncludeDiversificationNonce));
EXPECT_EQ(0u, visitor_.stream_frames_.size());
ASSERT_EQ(1u, visitor_.ack_frames_.size());
const QuicAckFrame& frame = *visitor_.ack_frames_[0];
EXPECT_EQ(0xBA, frame.entropy_hash);
EXPECT_EQ(kLargestObserved, frame.largest_observed);
ASSERT_EQ(1u, frame.packets.NumPacketsSlow());
ASSERT_EQ(1u, frame.received_packet_times.size());
EXPECT_EQ(kMissingPacket, frame.packets.Min());
const size_t kReceivedEntropyOffset = kQuicFrameTypeSize;
const size_t kLargestObservedOffset =
kReceivedEntropyOffset + kQuicEntropyHashSize;
const size_t kMissingDeltaTimeOffset =
kLargestObservedOffset + PACKET_6BYTE_PACKET_NUMBER;
const size_t kNumTimestampsOffset =
kMissingDeltaTimeOffset + kQuicDeltaTimeLargestObservedSize;
const size_t kTimestampDeltaLargestObserved =
kNumTimestampsOffset + kQuicNumTimestampsSize;
const size_t kTimestampTimeDeltaLargestObserved =
kTimestampDeltaLargestObserved + 1;
const size_t kNumMissingPacketOffset = kTimestampTimeDeltaLargestObserved + 4;
const size_t kMissingPacketsOffset =
kNumMissingPacketOffset + kNumberOfNackRangesSize;
// Now test framing boundaries.
const size_t ack_frame_size = PACKET_1BYTE_PACKET_NUMBER;
for (size_t i = kQuicFrameTypeSize; i < ack_frame_size; ++i) {
string expected_error;
if (i < kLargestObservedOffset) {
expected_error = "Unable to read entropy hash for received packets.";
} else if (i < kMissingDeltaTimeOffset) {
expected_error = "Unable to read largest observed.";
} else if (i < kNumTimestampsOffset) {
expected_error = "Unable to read ack delay time.";
} else if (i < kTimestampDeltaLargestObserved) {
expected_error = "Unable to read num received packets.";
} else if (i < kTimestampTimeDeltaLargestObserved) {
expected_error = "Unable to read sequence delta in received packets.";
} else if (i < kNumMissingPacketOffset) {
expected_error = "Unable to read time delta in received packets.";
} else if (i < kMissingPacketsOffset) {
expected_error = "Unable to read num missing packet ranges.";
} else {
expected_error = "Unable to read missing packet number delta.";
}
CheckProcessingFails(
packet,
i + GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
!kIncludeVersion, !kIncludePathId,
!kIncludeDiversificationNonce,
PACKET_6BYTE_PACKET_NUMBER),
expected_error, QUIC_INVALID_ACK_DATA);
}
}
TEST_P(QuicFramerTest, AckFrame) {
// clang-format off
unsigned char packet[] = {
// public flags (8 byte connection_id)
0x3C,
// connection_id
0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xA8, 0x9A, 0x78, 0x56, 0x34, 0x12,
// private flags (entropy)
0x01,
// frame type (ack frame)
// (has nacks, not truncated, 6 byte largest observed, 1 byte delta)
0x6C,
// entropy hash of all received packets.
0xBA,
// largest observed packet number
0xBF, 0x9A, 0x78, 0x56, 0x34, 0x12,
// Zero delta time.
0x00, 0x00,
// Number of timestamps.
0x00,
// num missing packets
0x01,
// missing packet delta
0x01,
// 0 more missing packets in range.
0x00,
// Number of revived packets.
0x00,
};
// clang-format on
if (framer_.version() > QUIC_VERSION_31) {
return;
}
QuicEncryptedPacket encrypted(AsChars(packet), 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, !kIncludePathId,
!kIncludeDiversificationNonce));
EXPECT_EQ(0u, visitor_.stream_frames_.size());
ASSERT_EQ(1u, visitor_.ack_frames_.size());
const QuicAckFrame& frame = *visitor_.ack_frames_[0];
EXPECT_EQ(0xBA, frame.entropy_hash);
EXPECT_EQ(kLargestObserved, frame.largest_observed);
ASSERT_EQ(1u, frame.packets.NumPacketsSlow());
EXPECT_EQ(kMissingPacket, frame.packets.Min());
const size_t kReceivedEntropyOffset = kQuicFrameTypeSize;
const size_t kLargestObservedOffset =
kReceivedEntropyOffset + kQuicEntropyHashSize;
const size_t kMissingDeltaTimeOffset =
kLargestObservedOffset + PACKET_6BYTE_PACKET_NUMBER;
const size_t kNumTimestampsOffset =
kMissingDeltaTimeOffset + kQuicDeltaTimeLargestObservedSize;
const size_t kNumMissingPacketOffset =
kNumTimestampsOffset + kQuicNumTimestampsSize;
const size_t kMissingPacketsOffset =
kNumMissingPacketOffset + kNumberOfNackRangesSize;
const size_t kMissingPacketsRange =
kMissingPacketsOffset + PACKET_1BYTE_PACKET_NUMBER;
const size_t kRevivedPacketsLength =
kMissingPacketsRange + PACKET_1BYTE_PACKET_NUMBER;
// Now test framing boundaries.
const size_t ack_frame_size =
kRevivedPacketsLength + PACKET_1BYTE_PACKET_NUMBER;
for (size_t i = kQuicFrameTypeSize; i < ack_frame_size; ++i) {
string expected_error;
if (i < kLargestObservedOffset) {
expected_error = "Unable to read entropy hash for received packets.";
} else if (i < kMissingDeltaTimeOffset) {
expected_error = "Unable to read largest observed.";
} else if (i < kNumTimestampsOffset) {
expected_error = "Unable to read ack delay time.";
} else if (i < kNumMissingPacketOffset) {
expected_error = "Unable to read num received packets.";
} else if (i < kMissingPacketsOffset) {
expected_error = "Unable to read num missing packet ranges.";
} else if (i < kMissingPacketsRange) {
expected_error = "Unable to read missing packet number delta.";
} else if (i < kRevivedPacketsLength) {
expected_error = "Unable to read missing packet number range.";
} else {
expected_error = "Unable to read num revived packets.";
}
CheckProcessingFails(
packet,
i + GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
!kIncludeVersion, !kIncludePathId,
!kIncludeDiversificationNonce,
PACKET_6BYTE_PACKET_NUMBER),
expected_error, QUIC_INVALID_ACK_DATA);
}
}
TEST_P(QuicFramerTest, NewAckFrameOneAckBlock) {
// clang-format off
unsigned char packet[] = {
// public flags (8 byte connection_id)
0x3C,
// connection_id
0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
// frame type (ack frame)
// (one ack block, 2 byte largest observed, 2 byte block length)
0x45,
// largest acked
0x34, 0x12,
// Zero delta time.
0x00, 0x00,
// first ack block length.
0x34, 0x12,
// num timestamps.
0x00,
};
// clang-format on
if (framer_.version() <= QUIC_VERSION_33) {
return;
}
QuicEncryptedPacket encrypted(AsChars(packet), 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, !kIncludePathId,
!kIncludeDiversificationNonce));
EXPECT_EQ(0u, visitor_.stream_frames_.size());
ASSERT_EQ(1u, visitor_.ack_frames_.size());
const QuicAckFrame& frame = *visitor_.ack_frames_[0];
EXPECT_EQ(kSmallLargestObserved, frame.largest_observed);
EXPECT_FALSE(frame.missing);
ASSERT_EQ(4660u, frame.packets.NumPacketsSlow());
const size_t kLargestAckedOffset = kQuicFrameTypeSize;
const size_t kLargestAckedDeltaTimeOffset =
kLargestAckedOffset + PACKET_2BYTE_PACKET_NUMBER;
const size_t kFirstAckBlockLengthOffset =
kLargestAckedDeltaTimeOffset + kQuicDeltaTimeLargestObservedSize;
const size_t kNumTimestampsOffset =
kFirstAckBlockLengthOffset + PACKET_2BYTE_PACKET_NUMBER;
// Now test framing boundaries.
const size_t ack_frame_size =
kFirstAckBlockLengthOffset + PACKET_2BYTE_PACKET_NUMBER;
for (size_t i = kQuicFrameTypeSize; i < ack_frame_size; ++i) {
string expected_error;
if (i < kLargestAckedDeltaTimeOffset) {
expected_error = "Unable to read largest acked.";
} else if (i < kFirstAckBlockLengthOffset) {
expected_error = "Unable to read ack delay time.";
} else if (i < kNumTimestampsOffset) {
expected_error = "Unable to read first ack block length.";
} else {
expected_error = "Unable to read num received packets.";
}
CheckProcessingFails(
packet,
i + GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
!kIncludeVersion, !kIncludePathId,
!kIncludeDiversificationNonce,
PACKET_6BYTE_PACKET_NUMBER),
expected_error, QUIC_INVALID_ACK_DATA);
}
}
TEST_P(QuicFramerTest, NewAckFrameTwoTimeStampsMultipleAckBlocks) {
// clang-format off
unsigned char packet[] = {
// public flags (8 byte connection_id)
0x3C,
// connection_id
0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
// frame type (ack frame)
// (more than one ack block, 2 byte largest observed, 2 byte block length)
0x65,
// largest acked
0x34, 0x12,
// Zero delta time.
0x00, 0x00,
// num ack blocks ranges.
0x04,
// first ack block length.
0x01, 0x00,
// gap to next block.
0x01,
// ack block length.
0xaf, 0x0e,
// gap to next block.
0xff,
// ack block length.
0x00, 0x00,
// gap to next block.
0x91,
// ack block length.
0xea, 0x01,
// gap to next block.
0x05,
// ack block length.
0x04, 0x00,
// Number of timestamps.
0x02,
// Delta from largest observed.
0x01,
// Delta time.
0x10, 0x32, 0x54, 0x76,
// Delta from largest observed.
0x02,
// Delta time.
0x10, 0x32,
};
// clang-format on
if (framer_.version() <= QUIC_VERSION_33) {
return;
}
QuicEncryptedPacket encrypted(AsChars(packet), 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, !kIncludePathId,
!kIncludeDiversificationNonce));
EXPECT_EQ(0u, visitor_.stream_frames_.size());
ASSERT_EQ(1u, visitor_.ack_frames_.size());
const QuicAckFrame& frame = *visitor_.ack_frames_[0];
EXPECT_EQ(kSmallLargestObserved, frame.largest_observed);
EXPECT_FALSE(frame.missing);
ASSERT_EQ(4254u, frame.packets.NumPacketsSlow());
const size_t kLargestAckedOffset = kQuicFrameTypeSize;
const size_t kLargestAckedDeltaTimeOffset =
kLargestAckedOffset + PACKET_2BYTE_PACKET_NUMBER;
const size_t kNumberOfAckBlocksOffset =
kLargestAckedDeltaTimeOffset + kQuicDeltaTimeLargestObservedSize;
const size_t kFirstAckBlockLengthOffset =
kNumberOfAckBlocksOffset + kNumberOfAckBlocksSize;
const size_t kGapToNextBlockOffset1 =
kFirstAckBlockLengthOffset + PACKET_2BYTE_PACKET_NUMBER;
const size_t kAckBlockLengthOffset1 = kGapToNextBlockOffset1 + 1;
const size_t kGapToNextBlockOffset2 =
kAckBlockLengthOffset1 + PACKET_2BYTE_PACKET_NUMBER;
const size_t kAckBlockLengthOffset2 = kGapToNextBlockOffset2 + 1;
const size_t kGapToNextBlockOffset3 =
kAckBlockLengthOffset2 + PACKET_2BYTE_PACKET_NUMBER;
const size_t kAckBlockLengthOffset3 = kGapToNextBlockOffset3 + 1;
const size_t kGapToNextBlockOffset4 =
kAckBlockLengthOffset3 + PACKET_2BYTE_PACKET_NUMBER;
const size_t kAckBlockLengthOffset4 = kGapToNextBlockOffset3 + 1;
const size_t kNumTimestampsOffset =
kAckBlockLengthOffset4 + PACKET_2BYTE_PACKET_NUMBER;
const size_t kTimestampDeltaLargestObserved1 =
kNumTimestampsOffset + kQuicNumTimestampsSize;
const size_t kTimestampTimeDeltaLargestObserved1 =
kTimestampDeltaLargestObserved1 + 1;
const size_t kTimestampDeltaLargestObserved2 =
kTimestampTimeDeltaLargestObserved1 + 4;
const size_t kTimestampTimeDeltaLargestObserved2 =
kTimestampDeltaLargestObserved2 + 1;
// Now test framing boundaries.
const size_t ack_frame_size =
kAckBlockLengthOffset4 + PACKET_2BYTE_PACKET_NUMBER;
for (size_t i = kQuicFrameTypeSize; i < ack_frame_size; ++i) {
string expected_error;
if (i < kLargestAckedDeltaTimeOffset) {
expected_error = "Unable to read largest acked.";
} else if (i < kNumberOfAckBlocksOffset) {
expected_error = "Unable to read ack delay time.";
} else if (i < kFirstAckBlockLengthOffset) {
expected_error = "Unable to read num of ack blocks.";
} else if (i < kGapToNextBlockOffset1) {
expected_error = "Unable to read first ack block length.";
} else if (i < kAckBlockLengthOffset1) {
expected_error = "Unable to read gap to next ack block.";
} else if (i < kGapToNextBlockOffset2) {
expected_error = "Unable to ack block length.";
} else if (i < kAckBlockLengthOffset2) {
expected_error = "Unable to read gap to next ack block.";
} else if (i < kGapToNextBlockOffset3) {
expected_error = "Unable to ack block length.";
} else if (i < kAckBlockLengthOffset3) {
expected_error = "Unable to read gap to next ack block.";
} else if (i < kGapToNextBlockOffset4) {
expected_error = "Unable to ack block length.";
} else if (i < kAckBlockLengthOffset4) {
expected_error = "Unable to read gap to next ack block.";
} else if (i < kNumTimestampsOffset) {
expected_error = "Unable to ack block length.";
} else if (i < kTimestampDeltaLargestObserved1) {
expected_error = "Unable to read num received packets.";
} else if (i < kTimestampTimeDeltaLargestObserved1) {
expected_error = "Unable to read sequence delta in received packets.";
} else if (i < kTimestampDeltaLargestObserved2) {
expected_error = "Unable to read time delta in received packets.";
} else if (i < kTimestampTimeDeltaLargestObserved2) {
expected_error = "Unable to read sequence delta in received packets.";
} else {
expected_error =
"Unable to read incremental time delta in received packets.";
}
CheckProcessingFails(
packet,
i + GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
!kIncludeVersion, !kIncludePathId,
!kIncludeDiversificationNonce,
PACKET_6BYTE_PACKET_NUMBER),
expected_error, QUIC_INVALID_ACK_DATA);
}
}
TEST_P(QuicFramerTest, AckFrameVersion32) {
// clang-format off
unsigned char packet[] = {
// public flags (8 byte connection_id)
0x38,
// connection_id
0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xA8, 0x9A, 0x78, 0x56, 0x34, 0x12,
// private flags (entropy)
0x01,
// frame type (ack frame)
// (has nacks, not truncated, 6 byte largest observed, 1 byte delta)
0x6C,
// entropy hash of all received packets.
0xBA,
// largest observed packet number
0xBF, 0x9A, 0x78, 0x56, 0x34, 0x12,
// Zero delta time.
0x00, 0x00,
// Number of timestamps.
0x00,
// num missing packets
0x01,
// missing packet delta
0x01,
// 0 more missing packets in range.
0x00,
};
// clang-format on
if (framer_.version() <= QUIC_VERSION_31 ||
framer_.version() > QUIC_VERSION_33) {
return;
}
QuicEncryptedPacket encrypted(AsChars(packet), 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, !kIncludePathId,
!kIncludeDiversificationNonce));
EXPECT_EQ(0u, visitor_.stream_frames_.size());
ASSERT_EQ(1u, visitor_.ack_frames_.size());
const QuicAckFrame& frame = *visitor_.ack_frames_[0];
EXPECT_EQ(0xBA, frame.entropy_hash);
EXPECT_EQ(kLargestObserved, frame.largest_observed);
ASSERT_EQ(1u, frame.packets.NumPacketsSlow());
EXPECT_EQ(kMissingPacket, frame.packets.Min());
const size_t kReceivedEntropyOffset = kQuicFrameTypeSize;
const size_t kLargestObservedOffset =
kReceivedEntropyOffset + kQuicEntropyHashSize;
const size_t kMissingDeltaTimeOffset =
kLargestObservedOffset + PACKET_6BYTE_PACKET_NUMBER;
const size_t kNumTimestampsOffset =
kMissingDeltaTimeOffset + kQuicDeltaTimeLargestObservedSize;
const size_t kNumMissingPacketOffset =
kNumTimestampsOffset + kQuicNumTimestampsSize;
const size_t kMissingPacketsOffset =
kNumMissingPacketOffset + kNumberOfNackRangesSize;
// Now test framing boundaries.
const size_t ack_frame_size = PACKET_1BYTE_PACKET_NUMBER;
for (size_t i = kQuicFrameTypeSize; i < ack_frame_size; ++i) {
string expected_error;
if (i < kLargestObservedOffset) {
expected_error = "Unable to read entropy hash for received packets.";
} else if (i < kMissingDeltaTimeOffset) {
expected_error = "Unable to read largest observed.";
} else if (i < kNumTimestampsOffset) {
expected_error = "Unable to read ack delay time.";
} else if (i < kNumMissingPacketOffset) {
expected_error = "Unable to read num received packets.";
} else if (i < kMissingPacketsOffset) {
expected_error = "Unable to read num missing packet ranges.";
} else {
expected_error = "Unable to read missing packet number delta.";
}
CheckProcessingFails(
packet,
i + GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
!kIncludeVersion, !kIncludePathId,
!kIncludeDiversificationNonce,
PACKET_6BYTE_PACKET_NUMBER),
expected_error, QUIC_INVALID_ACK_DATA);
}
}
TEST_P(QuicFramerTest, AckFrameRevivedPackets) {
// clang-format off
unsigned char packet[] = {
// public flags (8 byte connection_id)
0x38,
// connection_id
0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xA8, 0x9A, 0x78, 0x56, 0x34, 0x12,
// private flags (entropy)
0x01,
// frame type (ack frame)
// (has nacks, not truncated, 6 byte largest observed, 1 byte delta)
0x6C,
// entropy hash of all received packets.
0xBA,
// largest observed packet number
0xBF, 0x9A, 0x78, 0x56, 0x34, 0x12,
// Zero delta time.
0x00, 0x00,
// num received packets.
0x00,
// num missing packets
0x01,
// missing packet delta
0x01,
// 0 more missing packets in range.
0x00,
// Number of revived packets.
0x01,
// Revived packet number.
0xBE, 0x9A, 0x78, 0x56, 0x34, 0x12,
// Number of revived packets.
0x00,
};
// clang-format on
if (framer_.version() > QUIC_VERSION_31) {
return;
}
QuicEncryptedPacket encrypted(AsChars(packet), 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, !kIncludePathId,
!kIncludeDiversificationNonce));
EXPECT_EQ(0u, visitor_.stream_frames_.size());
ASSERT_EQ(1u, visitor_.ack_frames_.size());
const QuicAckFrame& frame = *visitor_.ack_frames_[0];
EXPECT_EQ(0xBA, frame.entropy_hash);
EXPECT_EQ(kLargestObserved, frame.largest_observed);
ASSERT_EQ(1u, frame.packets.NumPacketsSlow());
EXPECT_EQ(kMissingPacket, frame.packets.Min());
const size_t kReceivedEntropyOffset = kQuicFrameTypeSize;
const size_t kLargestObservedOffset =
kReceivedEntropyOffset + kQuicEntropyHashSize;
const size_t kMissingDeltaTimeOffset =
kLargestObservedOffset + PACKET_6BYTE_PACKET_NUMBER;
const size_t kNumTimestampsOffset =
kMissingDeltaTimeOffset + kQuicDeltaTimeLargestObservedSize;
const size_t kNumMissingPacketOffset =
kNumTimestampsOffset + kQuicNumTimestampsSize;
const size_t kMissingPacketsOffset =
kNumMissingPacketOffset + kNumberOfNackRangesSize;
const size_t kMissingPacketsRange =
kMissingPacketsOffset + PACKET_1BYTE_PACKET_NUMBER;
const size_t kRevivedPacketsLength =
kMissingPacketsRange + PACKET_1BYTE_PACKET_NUMBER;
const size_t kRevivedPacketSequenceNumberLength =
kRevivedPacketsLength + PACKET_1BYTE_PACKET_NUMBER;
// Now test framing boundaries.
const size_t ack_frame_size =
kRevivedPacketSequenceNumberLength + PACKET_6BYTE_PACKET_NUMBER;
for (size_t i = kQuicFrameTypeSize; i < ack_frame_size; ++i) {
string expected_error;
if (i < kReceivedEntropyOffset) {
expected_error = "Unable to read least unacked delta.";
} else if (i < kLargestObservedOffset) {
expected_error = "Unable to read entropy hash for received packets.";
} else if (i < kMissingDeltaTimeOffset) {
expected_error = "Unable to read largest observed.";
} else if (i < kNumTimestampsOffset) {
expected_error = "Unable to read ack delay time.";
} else if (i < kNumMissingPacketOffset) {
expected_error = "Unable to read num received packets.";
} else if (i < kMissingPacketsOffset) {
expected_error = "Unable to read num missing packet ranges.";
} else if (i < kMissingPacketsRange) {
expected_error = "Unable to read missing packet number delta.";
} else if (i < kRevivedPacketsLength) {
expected_error = "Unable to read missing packet number range.";
} else if (i < kRevivedPacketSequenceNumberLength) {
expected_error = "Unable to read num revived packets.";
} else {
expected_error = "Unable to read revived packet.";
}
CheckProcessingFails(
packet,
i + GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
!kIncludeVersion, !kIncludePathId,
!kIncludeDiversificationNonce,
PACKET_6BYTE_PACKET_NUMBER),
expected_error, QUIC_INVALID_ACK_DATA);
}
}
TEST_P(QuicFramerTest, AckFrameNoNacks) {
// clang-format off
unsigned char packet[] = {
// public flags (8 byte connection_id)
static_cast<unsigned char>(
framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
// connection_id
0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xA8, 0x9A, 0x78, 0x56, 0x34, 0x12,
// private flags (entropy)
0x01,
// frame type (ack frame)
// (no nacks, not truncated, 6 byte largest observed, 1 byte delta)
0x4C,
// entropy hash of all received packets.
0xBA,
// largest observed packet number
0xBF, 0x9A, 0x78, 0x56, 0x34, 0x12,
// Zero delta time.
0x00, 0x00,
// Number of received packets.
0x00,
};
// clang-format on
if (framer_.version() >= QUIC_VERSION_31) {
return;
}
QuicEncryptedPacket encrypted(AsChars(packet), 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, !kIncludePathId,
!kIncludeDiversificationNonce));
EXPECT_EQ(0u, visitor_.stream_frames_.size());
ASSERT_EQ(1u, visitor_.ack_frames_.size());
QuicAckFrame* frame = visitor_.ack_frames_[0];
EXPECT_EQ(0xBA, frame->entropy_hash);
EXPECT_EQ(kLargestObserved, frame->largest_observed);
ASSERT_TRUE(frame->packets.Empty());
// Verify that the packet re-serializes identically.
QuicFrames frames;
frames.push_back(QuicFrame(frame));
std::unique_ptr<QuicPacket> data(BuildDataPacket(*visitor_.header_, frames));
ASSERT_TRUE(data != nullptr);
test::CompareCharArraysWithHexError("constructed packet", data->data(),
data->length(), AsChars(packet),
arraysize(packet));
}
TEST_P(QuicFramerTest, AckFrame500Nacks) {
// clang-format off
unsigned char packet[] = {
// public flags (8 byte connection_id)
static_cast<unsigned char>(
framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
// connection_id
0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xA8, 0x9A, 0x78, 0x56, 0x34, 0x12,
// private flags (entropy)
0x01,
// frame type (ack frame)
// (has nacks, not truncated, 6 byte largest observed, 1 byte delta)
0x6C,
// entropy hash of all received packets.
0xBA,
// largest observed packet number
0xBF, 0x9A, 0x78, 0x56, 0x34, 0x12,
// Zero delta time.
0x00, 0x00,
// No received packets.
0x00,
// num missing packet ranges
0x02,
// missing packet delta
0x01,
// 243 more missing packets in range.
// The ranges are listed in this order so the re-constructed packet
// matches.
0xF3,
// No gap between ranges
0x00,
// 255 more missing packets in range.
0xFF,
// No revived packets.
0x00,
};
// clang-format on
if (framer_.version() > QUIC_VERSION_31) {
return;
}
QuicEncryptedPacket encrypted(AsChars(packet), 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, !kIncludePathId,
!kIncludeDiversificationNonce));
EXPECT_EQ(0u, visitor_.stream_frames_.size());
ASSERT_EQ(1u, visitor_.ack_frames_.size());
QuicAckFrame* frame = visitor_.ack_frames_[0];
EXPECT_EQ(0xBA, frame->entropy_hash);
EXPECT_EQ(kLargestObserved, frame->largest_observed);
ASSERT_EQ(500u, frame->packets.NumPacketsSlow());
EXPECT_EQ(kMissingPacket - 499, frame->packets.Min());
EXPECT_EQ(kMissingPacket, frame->packets.Max());
// Verify that the packet re-serializes identically.
QuicFrames frames;
frames.push_back(QuicFrame(frame));
std::unique_ptr<QuicPacket> data(BuildDataPacket(*visitor_.header_, frames));
ASSERT_TRUE(data != nullptr);
test::CompareCharArraysWithHexError("constructed packet", data->data(),
data->length(), AsChars(packet),
arraysize(packet));
}
TEST_P(QuicFramerTest, AckFrame500NacksVersion32) {
// clang-format off
unsigned char packet[] = {
// public flags (8 byte connection_id)
static_cast<unsigned char>(
framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
// connection_id
0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xA8, 0x9A, 0x78, 0x56, 0x34, 0x12,
// private flags (entropy)
0x01,
// frame type (ack frame)
// (has nacks, not truncated, 6 byte largest observed, 1 byte delta)
0x6C,
// entropy hash of all received packets.
0xBA,
// largest observed packet number
0xBF, 0x9A, 0x78, 0x56, 0x34, 0x12,
// Zero delta time.
0x00, 0x00,
// No received packets.
0x00,
// num missing packet ranges
0x02,
// missing packet delta
0x01,
// 243 more missing packets in range.
// The ranges are listed in this order so the re-constructed packet
// matches.
0xF3,
// No gap between ranges
0x00,
// 255 more missing packets in range.
0xFF,
};
// clang-format on
if (framer_.version() <= QUIC_VERSION_31 ||
framer_.version() > QUIC_VERSION_33) {
return;
}
QuicEncryptedPacket encrypted(AsChars(packet), 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, !kIncludePathId,
!kIncludeDiversificationNonce));
EXPECT_EQ(0u, visitor_.stream_frames_.size());
ASSERT_EQ(1u, visitor_.ack_frames_.size());
QuicAckFrame* frame = visitor_.ack_frames_[0];
EXPECT_EQ(0xBA, frame->entropy_hash);
EXPECT_EQ(kLargestObserved, frame->largest_observed);
ASSERT_EQ(500u, frame->packets.NumPacketsSlow());
EXPECT_EQ(kMissingPacket - 499, frame->packets.Min());
EXPECT_EQ(kMissingPacket, frame->packets.Max());
// Verify that the packet re-serializes identically.
QuicFrames frames;
frames.push_back(QuicFrame(frame));
std::unique_ptr<QuicPacket> data(BuildDataPacket(*visitor_.header_, frames));
ASSERT_TRUE(data != nullptr);
test::CompareCharArraysWithHexError("constructed packet", data->data(),
data->length(), AsChars(packet),
arraysize(packet));
}
TEST_P(QuicFramerTest, StopWaitingFrame) {
if (framer_.version() > QUIC_VERSION_33) {
return;
}
// clang-format off
unsigned char packet[] = {
// public flags (8 byte connection_id)
0x38,
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xA8, 0x9A, 0x78, 0x56,
0x34, 0x12,
// private flags (entropy)
0x01,
// frame type (ack frame)
// (has nacks, not truncated, 6 byte largest observed, 1 byte delta)
0x06,
// entropy hash of sent packets till least awaiting - 1.
0xAB,
// least packet number awaiting an ack, delta from packet number.
0x08, 0x00, 0x00, 0x00,
0x00, 0x00,
};
// clang-format on
QuicEncryptedPacket encrypted(AsChars(packet), 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, !kIncludePathId,
!kIncludeDiversificationNonce));
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(0xAB, frame.entropy_hash);
EXPECT_EQ(kLeastUnacked, frame.least_unacked);
const size_t kSentEntropyOffset = kQuicFrameTypeSize;
const size_t kLeastUnackedOffset = kSentEntropyOffset + kQuicEntropyHashSize;
const size_t frame_size = 7;
for (size_t i = kQuicFrameTypeSize; i < frame_size; ++i) {
string expected_error;
if (i < kLeastUnackedOffset) {
expected_error = "Unable to read entropy hash for sent packets.";
} else {
expected_error = "Unable to read least unacked delta.";
}
CheckProcessingFails(
packet,
i + GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
!kIncludeVersion, !kIncludePathId,
!kIncludeDiversificationNonce,
PACKET_6BYTE_PACKET_NUMBER),
expected_error, QUIC_INVALID_STOP_WAITING_DATA);
}
}
TEST_P(QuicFramerTest, NewStopWaitingFrame) {
if (framer_.version() <= QUIC_VERSION_33) {
return;
}
// clang-format off
unsigned char packet[] = {
// public flags (8 byte connection_id)
0x3C,
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xA8, 0x9A, 0x78, 0x56,
0x34, 0x12,
// frame type (stop waiting frame)
0x06,
// least packet number awaiting an ack, delta from packet number.
0x08, 0x00, 0x00, 0x00,
0x00, 0x00,
};
// clang-format on
QuicEncryptedPacket encrypted(AsChars(packet), 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, !kIncludePathId,
!kIncludeDiversificationNonce));
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);
const size_t frame_size = 7;
for (size_t i = kQuicFrameTypeSize; i < frame_size; ++i) {
string expected_error;
expected_error = "Unable to read least unacked delta.";
CheckProcessingFails(
packet,
i + GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
!kIncludeVersion, !kIncludePathId,
!kIncludeDiversificationNonce,
PACKET_6BYTE_PACKET_NUMBER),
expected_error, QUIC_INVALID_STOP_WAITING_DATA);
}
}
TEST_P(QuicFramerTest, RstStreamFrameQuic) {
// clang-format off
unsigned char packet[] = {
// public flags (8 byte connection_id)
0x38,
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// private flags
0x00,
// frame type (rst stream frame)
0x01,
// stream id
0x04, 0x03, 0x02, 0x01,
// sent byte offset
0x54, 0x76, 0x10, 0x32,
0xDC, 0xFE, 0x98, 0xBA,
// error code
0x01, 0x00, 0x00, 0x00,
};
unsigned char packet_34[] = {
// public flags (8 byte connection_id)
0x38,
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// frame type (rst stream frame)
0x01,
// stream id
0x04, 0x03, 0x02, 0x01,
// sent byte offset
0x54, 0x76, 0x10, 0x32,
0xDC, 0xFE, 0x98, 0xBA,
// error code
0x01, 0x00, 0x00, 0x00,
};
// clang-format on
QuicEncryptedPacket encrypted(
AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
: arraysize(packet_34),
false);
EXPECT_TRUE(framer_.ProcessPacket(encrypted));
EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
ASSERT_TRUE(visitor_.header_.get());
EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
!kIncludeDiversificationNonce));
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);
// Now test framing boundaries.
for (size_t i = kQuicFrameTypeSize; i < QuicFramer::GetRstStreamFrameSize();
++i) {
string expected_error;
if (i < kQuicFrameTypeSize + kQuicMaxStreamIdSize) {
expected_error = "Unable to read stream_id.";
} else if (i < kQuicFrameTypeSize + kQuicMaxStreamIdSize +
kQuicMaxStreamOffsetSize) {
expected_error = "Unable to read rst stream sent byte offset.";
} else if (i < kQuicFrameTypeSize + kQuicMaxStreamIdSize +
kQuicMaxStreamOffsetSize + kQuicErrorCodeSize) {
expected_error = "Unable to read rst stream error code.";
}
CheckProcessingFails(
framer_.version() <= QUIC_VERSION_33 ? packet : packet_34,
i + GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
!kIncludeVersion, !kIncludePathId,
!kIncludeDiversificationNonce,
PACKET_6BYTE_PACKET_NUMBER),
expected_error, QUIC_INVALID_RST_STREAM_DATA);
}
}
TEST_P(QuicFramerTest, ConnectionCloseFrame) {
// clang-format off
unsigned char packet[] = {
// public flags (8 byte connection_id)
0x38,
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// private flags
0x00,
// frame type (connection close frame)
0x02,
// error code
0x11, 0x00, 0x00, 0x00,
// error details length
0x0d, 0x00,
// error details
'b', 'e', 'c', 'a',
'u', 's', 'e', ' ',
'I', ' ', 'c', 'a',
'n',
};
unsigned char packet_34[] = {
// public flags (8 byte connection_id)
0x38,
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// frame type (connection close frame)
0x02,
// error code
0x11, 0x00, 0x00, 0x00,
// error details length
0x0d, 0x00,
// error details
'b', 'e', 'c', 'a',
'u', 's', 'e', ' ',
'I', ' ', 'c', 'a',
'n',
};
// clang-format on
QuicEncryptedPacket encrypted(
AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
: arraysize(packet_34),
false);
EXPECT_TRUE(framer_.ProcessPacket(encrypted));
EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
ASSERT_TRUE(visitor_.header_.get());
EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
!kIncludeDiversificationNonce));
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);
ASSERT_EQ(0u, visitor_.ack_frames_.size());
// Now test framing boundaries.
for (size_t i = kQuicFrameTypeSize;
i < QuicFramer::GetMinConnectionCloseFrameSize(); ++i) {
string expected_error;
if (i < kQuicFrameTypeSize + kQuicErrorCodeSize) {
expected_error = "Unable to read connection close error code.";
} else {
expected_error = "Unable to read connection close error details.";
}
CheckProcessingFails(
framer_.version() <= QUIC_VERSION_33 ? packet : packet_34,
i + GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
!kIncludeVersion, !kIncludePathId,
!kIncludeDiversificationNonce,
PACKET_6BYTE_PACKET_NUMBER),
expected_error, QUIC_INVALID_CONNECTION_CLOSE_DATA);
}
}
TEST_P(QuicFramerTest, GoAwayFrame) {
// clang-format off
unsigned char packet[] = {
// public flags (8 byte connection_id)
0x38,
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// private flags
0x00,
// frame type (go away frame)
0x03,
// error code
0x09, 0x00, 0x00, 0x00,
// stream id
0x04, 0x03, 0x02, 0x01,
// error details length
0x0d, 0x00,
// error details
'b', 'e', 'c', 'a',
'u', 's', 'e', ' ',
'I', ' ', 'c', 'a',
'n',
};
unsigned char packet_34[] = {
// public flags (8 byte connection_id)
0x38,
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// frame type (go away frame)
0x03,
// error code
0x09, 0x00, 0x00, 0x00,
// stream id
0x04, 0x03, 0x02, 0x01,
// error details length
0x0d, 0x00,
// error details
'b', 'e', 'c', 'a',
'u', 's', 'e', ' ',
'I', ' ', 'c', 'a',
'n',
};
// clang-format on
QuicEncryptedPacket encrypted(
AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
: arraysize(packet_34),
false);
EXPECT_TRUE(framer_.ProcessPacket(encrypted));
EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
ASSERT_TRUE(visitor_.header_.get());
EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
!kIncludeDiversificationNonce));
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);
const size_t reason_size = arraysize("because I can") - 1;
// Now test framing boundaries.
for (size_t i = kQuicFrameTypeSize;
i < QuicFramer::GetMinGoAwayFrameSize() + reason_size; ++i) {
string expected_error;
if (i < kQuicFrameTypeSize + kQuicErrorCodeSize) {
expected_error = "Unable to read go away error code.";
} else if (i <
kQuicFrameTypeSize + kQuicErrorCodeSize + kQuicMaxStreamIdSize) {
expected_error = "Unable to read last good stream id.";
} else {
expected_error = "Unable to read goaway reason.";
}
CheckProcessingFails(
framer_.version() <= QUIC_VERSION_33 ? packet : packet_34,
i + GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
!kIncludeVersion, !kIncludePathId,
!kIncludeDiversificationNonce,
PACKET_6BYTE_PACKET_NUMBER),
expected_error, QUIC_INVALID_GOAWAY_DATA);
}
}
TEST_P(QuicFramerTest, WindowUpdateFrame) {
// clang-format off
unsigned char packet[] = {
// public flags (8 byte connection_id)
0x38,
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// private flags
0x00,
// frame type (window update frame)
0x04,
// stream id
0x04, 0x03, 0x02, 0x01,
// byte offset
0x54, 0x76, 0x10, 0x32,
0xDC, 0xFE, 0x98, 0xBA,
};
unsigned char packet_34[] = {
// public flags (8 byte connection_id)
0x38,
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// frame type (window update frame)
0x04,
// stream id
0x04, 0x03, 0x02, 0x01,
// byte offset
0x54, 0x76, 0x10, 0x32,
0xDC, 0xFE, 0x98, 0xBA,
};
// clang-format on
QuicEncryptedPacket encrypted(
AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
: arraysize(packet_34),
false);
EXPECT_TRUE(framer_.ProcessPacket(encrypted));
EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
ASSERT_TRUE(visitor_.header_.get());
EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
!kIncludeDiversificationNonce));
EXPECT_EQ(kStreamId, visitor_.window_update_frame_.stream_id);
EXPECT_EQ(kStreamOffset, visitor_.window_update_frame_.byte_offset);
// Now test framing boundaries.
for (size_t i = kQuicFrameTypeSize;
i < QuicFramer::GetWindowUpdateFrameSize(); ++i) {
string expected_error;
if (i < kQuicFrameTypeSize + kQuicMaxStreamIdSize) {
expected_error = "Unable to read stream_id.";
} else {
expected_error = "Unable to read window byte_offset.";
}
CheckProcessingFails(
framer_.version() <= QUIC_VERSION_33 ? packet : packet_34,
i + GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
!kIncludeVersion, !kIncludePathId,
!kIncludeDiversificationNonce,
PACKET_6BYTE_PACKET_NUMBER),
expected_error, QUIC_INVALID_WINDOW_UPDATE_DATA);
}
}
TEST_P(QuicFramerTest, BlockedFrame) {
// clang-format off
unsigned char packet[] = {
// public flags (8 byte connection_id)
0x38,
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// private flags
0x00,
// frame type (blocked frame)
0x05,
// stream id
0x04, 0x03, 0x02, 0x01,
};
unsigned char packet_34[] = {
// public flags (8 byte connection_id)
0x38,
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// frame type (blocked frame)
0x05,
// stream id
0x04, 0x03, 0x02, 0x01,
};
// clang-format on
QuicEncryptedPacket encrypted(
AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
: arraysize(packet_34),
false);
EXPECT_TRUE(framer_.ProcessPacket(encrypted));
EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
ASSERT_TRUE(visitor_.header_.get());
EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
!kIncludeDiversificationNonce));
EXPECT_EQ(kStreamId, visitor_.blocked_frame_.stream_id);
// Now test framing boundaries.
for (size_t i = kQuicFrameTypeSize; i < QuicFramer::GetBlockedFrameSize();
++i) {
string expected_error = "Unable to read stream_id.";
CheckProcessingFails(
framer_.version() <= QUIC_VERSION_33 ? packet : packet_34,
i + GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
!kIncludeVersion, !kIncludePathId,
!kIncludeDiversificationNonce,
PACKET_6BYTE_PACKET_NUMBER),
expected_error, QUIC_INVALID_BLOCKED_DATA);
}
}
TEST_P(QuicFramerTest, PingFrame) {
// clang-format off
unsigned char packet[] = {
// public flags (8 byte connection_id)
0x38,
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// private flags
0x00,
// frame type (ping frame)
0x07,
};
unsigned char packet_34[] = {
// public flags (8 byte connection_id)
0x38,
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// frame type (ping frame)
0x07,
};
// clang-format on
QuicEncryptedPacket encrypted(
AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
: arraysize(packet_34),
false);
EXPECT_TRUE(framer_.ProcessPacket(encrypted));
EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
ASSERT_TRUE(visitor_.header_.get());
EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
!kIncludeDiversificationNonce));
EXPECT_EQ(1u, visitor_.ping_frames_.size());
// No need to check the PING frame boundaries because it has no payload.
}
TEST_P(QuicFramerTest, PathCloseFrame) {
// clang-format off
unsigned char packet[] = {
// public flags (version)
0x78,
// connection_id
0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
// path_id
0x00,
// packet number
0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
// private flags
0x00,
// frame type (path_close_frame)
0x08,
// path id
0x42,
};
unsigned char packet_34[] = {
// public flags (version)
0x78,
// connection_id
0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
// path_id
0x00,
// packet number
0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
// frame type (path_close_frame)
0x08,
// path id
0x42,
};
// clang-format on
QuicEncryptedPacket encrypted(
AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
: arraysize(packet_34),
false);
EXPECT_TRUE(framer_.ProcessPacket(encrypted));
EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
ASSERT_TRUE(visitor_.header_.get());
// TODO(fayang): CheckDecryption after cl/110553865 is landed.
EXPECT_EQ(kPathId, visitor_.path_close_frame_.path_id);
// Now test framing boundaries.
for (size_t i = kQuicFrameTypeSize; i < QuicFramer::GetPathCloseFrameSize();
++i) {
string expected_error;
if (i < kQuicFrameTypeSize + kQuicPathIdSize) {
expected_error = "Unable to read path_id.";
}
CheckProcessingFails(
framer_.version() <= QUIC_VERSION_33 ? packet : packet_34,
i + GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
!kIncludeVersion, kIncludePathId,
!kIncludeDiversificationNonce,
PACKET_6BYTE_PACKET_NUMBER),
expected_error, QUIC_INVALID_PATH_CLOSE_DATA);
}
}
TEST_P(QuicFramerTest, PublicResetPacketV33) {
// clang-format off
unsigned char packet[] = {
// public flags (public reset, 8 byte connection_id)
0x0A,
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// 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
QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
EXPECT_TRUE(framer_.ProcessPacket(encrypted));
ASSERT_EQ(QUIC_NO_ERROR, framer_.error());
ASSERT_TRUE(visitor_.public_reset_packet_.get());
EXPECT_EQ(kConnectionId,
visitor_.public_reset_packet_->public_header.connection_id);
EXPECT_TRUE(visitor_.public_reset_packet_->public_header.reset_flag);
EXPECT_FALSE(visitor_.public_reset_packet_->public_header.version_flag);
EXPECT_EQ(kNonceProof, visitor_.public_reset_packet_->nonce_proof);
EXPECT_EQ(0u, visitor_.public_reset_packet_->rejected_packet_number);
EXPECT_EQ(ADDRESS_FAMILY_UNSPECIFIED,
visitor_.public_reset_packet_->client_address.GetFamily());
// Now test framing boundaries.
for (size_t i = 0; i < arraysize(packet); ++i) {
string expected_error;
DVLOG(1) << "iteration: " << i;
if (i < kConnectionIdOffset) {
expected_error = "Unable to read public flags.";
CheckProcessingFails(packet, i, expected_error,
QUIC_INVALID_PACKET_HEADER);
} else if (i < kPublicResetPacketMessageTagOffset) {
expected_error = "Unable to read ConnectionId.";
CheckProcessingFails(packet, i, expected_error,
QUIC_INVALID_PACKET_HEADER);
} else {
expected_error = "Unable to read reset message.";
CheckProcessingFails(packet, i, expected_error,
QUIC_INVALID_PUBLIC_RST_PACKET);
}
}
}
TEST_P(QuicFramerTest, PublicResetPacket) {
QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT);
// clang-format off
unsigned char packet[] = {
// public flags (public reset, 8 byte connection_id)
0x0E,
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// 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
QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
EXPECT_TRUE(framer_.ProcessPacket(encrypted));
ASSERT_EQ(QUIC_NO_ERROR, framer_.error());
ASSERT_TRUE(visitor_.public_reset_packet_.get());
EXPECT_EQ(kConnectionId,
visitor_.public_reset_packet_->public_header.connection_id);
EXPECT_TRUE(visitor_.public_reset_packet_->public_header.reset_flag);
EXPECT_FALSE(visitor_.public_reset_packet_->public_header.version_flag);
EXPECT_EQ(kNonceProof, visitor_.public_reset_packet_->nonce_proof);
EXPECT_EQ(0u, visitor_.public_reset_packet_->rejected_packet_number);
EXPECT_EQ(ADDRESS_FAMILY_UNSPECIFIED,
visitor_.public_reset_packet_->client_address.GetFamily());
// Now test framing boundaries.
for (size_t i = 0; i < arraysize(packet); ++i) {
string expected_error;
DVLOG(1) << "iteration: " << i;
if (i < kConnectionIdOffset) {
expected_error = "Unable to read public flags.";
CheckProcessingFails(packet, i, expected_error,
QUIC_INVALID_PACKET_HEADER);
} else if (i < kPublicResetPacketMessageTagOffset) {
expected_error = "Unable to read ConnectionId.";
CheckProcessingFails(packet, i, expected_error,
QUIC_INVALID_PACKET_HEADER);
} else {
expected_error = "Unable to read reset message.";
CheckProcessingFails(packet, i, expected_error,
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
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// 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
string expected_error = "Unable to read reset message.";
CheckProcessingFails(packet, arraysize(packet), expected_error,
QUIC_INVALID_PUBLIC_RST_PACKET);
}
TEST_P(QuicFramerTest, PublicResetPacketWithClientAddress) {
// clang-format off
unsigned char packet[] = {
// public flags (public reset, 8 byte connection_id)
0x0A,
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// message tag (kPRST)
'P', 'R', 'S', 'T',
// num_entries (3) + 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
QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
EXPECT_TRUE(framer_.ProcessPacket(encrypted));
ASSERT_EQ(QUIC_NO_ERROR, framer_.error());
ASSERT_TRUE(visitor_.public_reset_packet_.get());
EXPECT_EQ(kConnectionId,
visitor_.public_reset_packet_->public_header.connection_id);
EXPECT_TRUE(visitor_.public_reset_packet_->public_header.reset_flag);
EXPECT_FALSE(visitor_.public_reset_packet_->public_header.version_flag);
EXPECT_EQ(kNonceProof, visitor_.public_reset_packet_->nonce_proof);
EXPECT_EQ(0u, visitor_.public_reset_packet_->rejected_packet_number);
EXPECT_EQ("4.31.198.44",
visitor_.public_reset_packet_->client_address.address().ToString());
EXPECT_EQ(443, visitor_.public_reset_packet_->client_address.port());
// Now test framing boundaries.
for (size_t i = 0; i < arraysize(packet); ++i) {
string expected_error;
DVLOG(1) << "iteration: " << i;
if (i < kConnectionIdOffset) {
expected_error = "Unable to read public flags.";
CheckProcessingFails(packet, i, expected_error,
QUIC_INVALID_PACKET_HEADER);
} else if (i < kPublicResetPacketMessageTagOffset) {
expected_error = "Unable to read ConnectionId.";
CheckProcessingFails(packet, i, expected_error,
QUIC_INVALID_PACKET_HEADER);
} else {
expected_error = "Unable to read reset message.";
CheckProcessingFails(packet, i, expected_error,
QUIC_INVALID_PUBLIC_RST_PACKET);
}
}
}
TEST_P(QuicFramerTest, VersionNegotiationPacket) {
// clang-format off
unsigned char packet[] = {
// public flags (version, 8 byte connection_id)
0x39,
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// version tag
'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes(),
'Q', '2', '.', '0',
};
// clang-format on
QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT);
QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
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]);
for (size_t i = 0; i <= kPublicFlagsSize + PACKET_8BYTE_CONNECTION_ID; ++i) {
string expected_error;
QuicErrorCode error_code = QUIC_INVALID_PACKET_HEADER;
if (i < kConnectionIdOffset) {
expected_error = "Unable to read public flags.";
} else if (i < kVersionOffset) {
expected_error = "Unable to read ConnectionId.";
} else {
expected_error = "Unable to read supported version in negotiation.";
error_code = QUIC_INVALID_VERSION_NEGOTIATION_PACKET;
}
CheckProcessingFails(packet, i, expected_error, error_code);
}
}
TEST_P(QuicFramerTest, OldVersionNegotiationPacket) {
// clang-format off
unsigned char packet[] = {
// public flags (version, 8 byte connection_id)
0x3D,
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// version tag
'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes(),
'Q', '2', '.', '0',
};
// clang-format on
QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT);
QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
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]);
for (size_t i = 0; i <= kPublicFlagsSize + PACKET_8BYTE_CONNECTION_ID; ++i) {
string expected_error;
QuicErrorCode error_code = QUIC_INVALID_PACKET_HEADER;
if (i < kConnectionIdOffset) {
expected_error = "Unable to read public flags.";
} else if (i < kVersionOffset) {
expected_error = "Unable to read ConnectionId.";
} else {
expected_error = "Unable to read supported version in negotiation.";
error_code = QUIC_INVALID_VERSION_NEGOTIATION_PACKET;
}
CheckProcessingFails(packet, i, expected_error, error_code);
}
}
TEST_P(QuicFramerTest, DropFecPacket) {
// clang-format off
unsigned char packet[] = {
// public flags (8 byte connection_id)
0x38,
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// private flags (fec group & FEC)
0x06,
// first fec protected packet offset
0x01,
// redundancy
'a', 'b', 'c', 'd',
'e', 'f', 'g', 'h',
'i', 'j', 'k', 'l',
'm', 'n', 'o', 'p',
};
if (framer_.version() > QUIC_VERSION_33) {
return;
}
QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
if (framer_.version() <= QUIC_VERSION_31) {
EXPECT_TRUE(framer_.ProcessPacket(encrypted));
EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
} else {
EXPECT_FALSE(framer_.ProcessPacket(encrypted));
EXPECT_EQ(QUIC_INVALID_PACKET_HEADER, framer_.error());
}
EXPECT_FALSE(visitor_.header_.get());
}
TEST_P(QuicFramerTest, BuildPaddingFramePacket) {
QuicPacketHeader header;
header.public_header.connection_id = kConnectionId;
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.fec_flag = false;
header.entropy_flag = false;
header.packet_number = kPacketNumber;
QuicPaddingFrame padding_frame;
QuicFrames frames;
frames.push_back(QuicFrame(padding_frame));
// clang-format off
unsigned char packet[kMaxPacketSize] = {
// public flags (8 byte connection_id)
static_cast<unsigned char>(
framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// private flags
0x00,
// frame type (padding frame)
0x00,
0x00, 0x00, 0x00, 0x00
};
unsigned char packet_34[kMaxPacketSize] = {
// public flags (8 byte connection_id)
0x38,
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// frame type (padding frame)
0x00,
0x00, 0x00, 0x00, 0x00
};
// clang-format on
uint64_t header_size = GetPacketHeaderSize(
framer_.version(), PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion,
!kIncludePathId, !kIncludeDiversificationNonce,
PACKET_6BYTE_PACKET_NUMBER);
memset((framer_.version() <= QUIC_VERSION_33 ? packet : packet_34) +
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(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
: arraysize(packet_34));
}
TEST_P(QuicFramerTest, Build4ByteSequenceNumberPaddingFramePacket) {
QuicPacketHeader header;
header.public_header.connection_id = kConnectionId;
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.fec_flag = false;
header.entropy_flag = false;
header.public_header.packet_number_length = PACKET_4BYTE_PACKET_NUMBER;
header.packet_number = kPacketNumber;
QuicPaddingFrame padding_frame;
QuicFrames frames;
frames.push_back(QuicFrame(padding_frame));
// clang-format off
unsigned char packet[kMaxPacketSize] = {
// public flags (8 byte connection_id and 4 byte packet number)
static_cast<unsigned char>(
framer_.version() > QUIC_VERSION_32 ? 0x28 : 0x2C),
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56,
// private flags
0x00,
// frame type (padding frame)
0x00,
0x00, 0x00, 0x00, 0x00
};
unsigned char packet_34[kMaxPacketSize] = {
// public flags (8 byte connection_id and 4 byte packet number)
0x28,
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56,
// frame type (padding frame)
0x00,
0x00, 0x00, 0x00, 0x00
};
// clang-format on
uint64_t header_size = GetPacketHeaderSize(
framer_.version(), PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion,
!kIncludePathId, !kIncludeDiversificationNonce,
PACKET_4BYTE_PACKET_NUMBER);
memset((framer_.version() <= QUIC_VERSION_33 ? packet : packet_34) +
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(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
: arraysize(packet_34));
}
TEST_P(QuicFramerTest, Build2ByteSequenceNumberPaddingFramePacket) {
QuicPacketHeader header;
header.public_header.connection_id = kConnectionId;
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.fec_flag = false;
header.entropy_flag = false;
header.public_header.packet_number_length = PACKET_2BYTE_PACKET_NUMBER;
header.packet_number = kPacketNumber;
QuicPaddingFrame padding_frame;
QuicFrames frames;
frames.push_back(QuicFrame(padding_frame));
// clang-format off
unsigned char packet[kMaxPacketSize] = {
// public flags (8 byte connection_id and 2 byte packet number)
static_cast<unsigned char>(
framer_.version() > QUIC_VERSION_32 ? 0x18 : 0x1C),
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A,
// private flags
0x00,
// frame type (padding frame)
0x00,
0x00, 0x00, 0x00, 0x00
};
unsigned char packet_34[kMaxPacketSize] = {
// public flags (8 byte connection_id and 2 byte packet number)
0x18,
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A,
// frame type (padding frame)
0x00,
0x00, 0x00, 0x00, 0x00
};
// clang-format on
uint64_t header_size = GetPacketHeaderSize(
framer_.version(), PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion,
!kIncludePathId, !kIncludeDiversificationNonce,
PACKET_2BYTE_PACKET_NUMBER);
memset((framer_.version() <= QUIC_VERSION_33 ? packet : packet_34) +
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(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
: arraysize(packet_34));
}
TEST_P(QuicFramerTest, Build1ByteSequenceNumberPaddingFramePacket) {
QuicPacketHeader header;
header.public_header.connection_id = kConnectionId;
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.fec_flag = false;
header.entropy_flag = false;
header.public_header.packet_number_length = PACKET_1BYTE_PACKET_NUMBER;
header.packet_number = kPacketNumber;
QuicPaddingFrame padding_frame;
QuicFrames frames;
frames.push_back(QuicFrame(padding_frame));
// clang-format off
unsigned char packet[kMaxPacketSize] = {
// public flags (8 byte connection_id and 1 byte packet number)
static_cast<unsigned char>(
framer_.version() > QUIC_VERSION_32 ? 0x08 : 0x0C),
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC,
// private flags
0x00,
// frame type (padding frame)
0x00,
0x00, 0x00, 0x00, 0x00
};
unsigned char packet_34[kMaxPacketSize] = {
// public flags (8 byte connection_id and 1 byte packet number)
0x08,
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC,
// frame type (padding frame)
0x00,
0x00, 0x00, 0x00, 0x00
};
// clang-format on
uint64_t header_size = GetPacketHeaderSize(
framer_.version(), PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion,
!kIncludePathId, !kIncludeDiversificationNonce,
PACKET_1BYTE_PACKET_NUMBER);
memset((framer_.version() <= QUIC_VERSION_33 ? packet : packet_34) +
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(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
: arraysize(packet_34));
}
TEST_P(QuicFramerTest, BuildStreamFramePacket) {
QuicPacketHeader header;
header.public_header.connection_id = kConnectionId;
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.fec_flag = false;
header.entropy_flag = true;
header.packet_number = kPacketNumber;
QuicStreamFrame stream_frame(kStreamId, true, kStreamOffset,
StringPiece("hello world!"));
QuicFrames frames;
frames.push_back(QuicFrame(&stream_frame));
// clang-format off
unsigned char packet[] = {
// public flags (8 byte connection_id)
static_cast<unsigned char>(
framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// private flags (entropy)
0x01,
// frame type (stream frame with fin and no length)
0xDF,
// stream id
0x04, 0x03, 0x02, 0x01,
// offset
0x54, 0x76, 0x10, 0x32,
0xDC, 0xFE, 0x98, 0xBA,
// data
'h', 'e', 'l', 'l',
'o', ' ', 'w', 'o',
'r', 'l', 'd', '!',
};
unsigned char packet_34[] = {
// public flags (8 byte connection_id)
0x38,
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// frame type (stream frame with fin and no length)
0xDF,
// stream id
0x04, 0x03, 0x02, 0x01,
// offset
0x54, 0x76, 0x10, 0x32,
0xDC, 0xFE, 0x98, 0xBA,
// 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);
test::CompareCharArraysWithHexError(
"constructed packet", data->data(), data->length(),
AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
: arraysize(packet_34));
}
TEST_P(QuicFramerTest, BuildStreamFramePacketWithVersionFlag) {
QuicPacketHeader header;
header.public_header.connection_id = kConnectionId;
header.public_header.reset_flag = false;
header.public_header.version_flag = true;
header.fec_flag = false;
header.entropy_flag = true;
header.packet_number = kPacketNumber;
QuicStreamFrame stream_frame(kStreamId, true, kStreamOffset,
StringPiece("hello world!"));
QuicFrames frames;
frames.push_back(QuicFrame(&stream_frame));
// clang-format off
unsigned char packet[] = {
// public flags (version, 8 byte connection_id)
static_cast<unsigned char>(
(FLAGS_quic_remove_v33_hacks &&
framer_.version() > QUIC_VERSION_32) ? 0x39 : 0x3D),
// connection_id
0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
// version tag
'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes(),
// packet number
0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
// private flags (entropy)
0x01,
// frame type (stream frame with fin and no length)
0xDF,
// stream id
0x04, 0x03, 0x02, 0x01,
// offset
0x54, 0x76, 0x10, 0x32, 0xDC, 0xFE, 0x98, 0xBA,
// data
'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!',
};
unsigned char packet_34[] = {
// public flags (version, 8 byte connection_id)
static_cast<unsigned char>(
FLAGS_quic_remove_v33_hacks ? 0x39 : 0x3D),
// connection_id
0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
// version tag
'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes(),
// packet number
0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
// frame type (stream frame with fin and no length)
0xDF,
// stream id
0x04, 0x03, 0x02, 0x01,
// offset
0x54, 0x76, 0x10, 0x32, 0xDC, 0xFE, 0x98, 0xBA,
// 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);
test::CompareCharArraysWithHexError(
"constructed packet", data->data(), data->length(),
AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
: arraysize(packet_34));
}
TEST_P(QuicFramerTest, BuildStreamFramePacketWithMultipathFlag) {
QuicPacketHeader header;
header.public_header.connection_id = kConnectionId;
header.public_header.multipath_flag = true;
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.fec_flag = false;
header.entropy_flag = true;
header.path_id = kPathId;
header.packet_number = kPacketNumber;
QuicStreamFrame stream_frame(kStreamId, true, kStreamOffset,
StringPiece("hello world!"));
QuicFrames frames;
frames.push_back(QuicFrame(&stream_frame));
// clang-format off
unsigned char packet[] = {
// public flags (8 byte connection_id)
static_cast<unsigned char>(
framer_.version() > QUIC_VERSION_32 ? 0x78 : 0x7C),
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// path_id
0x42,
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// private flags (entropy)
0x01,
// frame type (stream frame with fin and no length)
0xDF,
// stream id
0x04, 0x03, 0x02, 0x01,
// offset
0x54, 0x76, 0x10, 0x32,
0xDC, 0xFE, 0x98, 0xBA,
// data
'h', 'e', 'l', 'l',
'o', ' ', 'w', 'o',
'r', 'l', 'd', '!',
};
unsigned char packet_34[] = {
// public flags (8 byte connection_id)
0x78,
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// path_id
0x42,
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// frame type (stream frame with fin and no length)
0xDF,
// stream id
0x04, 0x03, 0x02, 0x01,
// offset
0x54, 0x76, 0x10, 0x32,
0xDC, 0xFE, 0x98, 0xBA,
// 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);
test::CompareCharArraysWithHexError(
"constructed packet", data->data(), data->length(),
AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
: arraysize(packet_34));
}
TEST_P(QuicFramerTest, BuildStreamFramePacketWithBothVersionAndMultipathFlag) {
QuicPacketHeader header;
header.public_header.connection_id = kConnectionId;
header.public_header.multipath_flag = true;
header.public_header.reset_flag = false;
header.public_header.version_flag = true;
header.fec_flag = false;
header.entropy_flag = true;
header.path_id = kPathId;
header.packet_number = kPacketNumber;
QuicStreamFrame stream_frame(kStreamId, true, kStreamOffset,
StringPiece("hello world!"));
QuicFrames frames;
frames.push_back(QuicFrame(&stream_frame));
// clang-format off
unsigned char packet[] = {
// public flags (8 byte connection_id)
static_cast<unsigned char>(
(FLAGS_quic_remove_v33_hacks &&
framer_.version() > QUIC_VERSION_32) ? 0x79 : 0x7D),
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// version tag
'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes(),
// path_id
0x42,
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// private flags (entropy)
0x01,
// frame type (stream frame with fin and no length)
0xDF,
// stream id
0x04, 0x03, 0x02, 0x01,
// offset
0x54, 0x76, 0x10, 0x32,
0xDC, 0xFE, 0x98, 0xBA,
// data
'h', 'e', 'l', 'l',
'o', ' ', 'w', 'o',
'r', 'l', 'd', '!',
};
unsigned char packet_34[] = {
// public flags (8 byte connection_id)
static_cast<unsigned char>(
FLAGS_quic_remove_v33_hacks ? 0x79 : 0x7D),
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// version tag
'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes(),
// path_id
0x42,
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// frame type (stream frame with fin and no length)
0xDF,
// stream id
0x04, 0x03, 0x02, 0x01,
// offset
0x54, 0x76, 0x10, 0x32,
0xDC, 0xFE, 0x98, 0xBA,
// 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);
test::CompareCharArraysWithHexError(
"constructed packet", data->data(), data->length(),
AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
: arraysize(packet_34));
}
TEST_P(QuicFramerTest, BuildVersionNegotiationPacket) {
// clang-format off
unsigned char packet[] = {
// public flags (version, 8 byte connection_id)
0x0D,
// connection_id
0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
// version tag
'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes(),
};
// clang-format on
QuicConnectionId connection_id = kConnectionId;
std::unique_ptr<QuicEncryptedPacket> data(
framer_.BuildVersionNegotiationPacket(connection_id,
SupportedVersions(GetParam())));
test::CompareCharArraysWithHexError("constructed packet", data->data(),
data->length(), AsChars(packet),
arraysize(packet));
}
TEST_P(QuicFramerTest, BuildAckFramePacket) {
if (framer_.version() > QUIC_VERSION_33) {
return;
}
QuicPacketHeader header;
header.public_header.connection_id = kConnectionId;
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.fec_flag = false;
header.entropy_flag = true;
header.packet_number = kPacketNumber;
QuicAckFrame ack_frame;
ack_frame.entropy_hash = 0x43;
ack_frame.largest_observed = kLargestObserved;
ack_frame.ack_delay_time = QuicTime::Delta::Zero();
ack_frame.packets.Add(kMissingPacket);
QuicFrames frames;
frames.push_back(QuicFrame(&ack_frame));
// clang-format off
unsigned char packet[] = {
// public flags (8 byte connection_id)
0x3C,
// connection_id
0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
// private flags (entropy)
0x01,
// frame type (ack frame)
// (has nacks, not truncated, 6 byte largest observed, 1 byte delta)
0x6C,
// entropy hash of all received packets.
0x43,
// largest observed packet number
0xBF, 0x9A, 0x78, 0x56, 0x34, 0x12,
// Zero delta time.
0x00, 0x00,
// num received packets.
0x00,
// num missing packet ranges
0x01,
// missing packet delta
0x01,
// 0 more missing packets in range.
0x00,
// 0 revived packets.
0x00,
};
// clang-format on
// clang-format off
unsigned char packet_version32[] = {
// public flags (8 byte connection_id)
static_cast<unsigned char>(
framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
// connection_id
0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
// private flags (entropy)
0x01,
// frame type (ack frame)
// (has nacks, not truncated, 6 byte largest observed, 1 byte delta)
0x6C,
// entropy hash of all received packets.
0x43,
// largest observed packet number
0xBF, 0x9A, 0x78, 0x56, 0x34, 0x12,
// Zero delta time.
0x00, 0x00,
// num received packets.
0x00,
// num missing packet ranges
0x01,
// missing packet delta
0x01,
// 0 more missing packets in range.
0x00,
};
// clang-format on
std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
ASSERT_TRUE(data != nullptr);
if (framer_.version() <= QUIC_VERSION_31) {
test::CompareCharArraysWithHexError("constructed packet", data->data(),
data->length(), AsChars(packet),
arraysize(packet));
} else {
test::CompareCharArraysWithHexError(
"constructed packet", data->data(), data->length(),
AsChars(packet_version32), arraysize(packet_version32));
}
}
// TODO(jri): Add test for tuncated packets in which the original ack frame had
// revived packets. (In both the large and small packet cases below).
TEST_P(QuicFramerTest, BuildTruncatedAckFrameLargePacket) {
if (framer_.version() > QUIC_VERSION_33) {
return;
}
QuicPacketHeader header;
header.public_header.connection_id = kConnectionId;
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.fec_flag = false;
header.entropy_flag = true;
header.packet_number = kPacketNumber;
QuicAckFrame ack_frame;
// This entropy hash is different from what shows up in the packet below,
// since entropy is recomputed by the framer on ack truncation (by
// TestEntropyCalculator for this test.)
ack_frame.entropy_hash = 0x43;
ack_frame.largest_observed = 2 * 300;
ack_frame.ack_delay_time = QuicTime::Delta::Zero();
for (size_t i = 1; i < 2 * 300; i += 2) {
ack_frame.packets.Add(i);
}
QuicFrames frames;
frames.push_back(QuicFrame(&ack_frame));
// clang-format off
unsigned char packet[] = {
// public flags (8 byte connection_id)
0x3C,
// connection_id
0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
// private flags (entropy)
0x01,
// frame type (ack frame)
// (has nacks, is truncated, 2 byte largest observed, 1 byte delta)
0x74,
// entropy hash of all received packets, set to 1 by TestEntropyCalculator
// since ack is truncated.
0x01,
// 2-byte largest observed packet number.
// Expected to be 510 (0x1FE), since only 255 nack ranges can fit.
0xFE, 0x01,
// Zero delta time.
0x00, 0x00,
// num missing packet ranges (limited to 255 by size of this field).
0xFF,
// {missing packet delta, further missing packets in range}
// 6 nack ranges x 42 + 3 nack ranges
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
// 0 revived packets.
0x00,
};
// clang-format on
// clang-format off
unsigned char packet_version32[] = {
// public flags (8 byte connection_id)
static_cast<unsigned char>(
framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
// connection_id
0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
// private flags (entropy)
0x01,
// frame type (ack frame)
// (has nacks, is truncated, 2 byte largest observed, 1 byte delta)
0x74,
// entropy hash of all received packets, set to 1 by TestEntropyCalculator
// since ack is truncated.
0x01,
// 2-byte largest observed packet number.
// Expected to be 510 (0x1FE), since only 255 nack ranges can fit.
0xFE, 0x01,
// Zero delta time.
0x00, 0x00,
// num missing packet ranges (limited to 255 by size of this field).
0xFF,
// {missing packet delta, further missing packets in range}
// 6 nack ranges x 42 + 3 nack ranges
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
};
// clang-format on
std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
ASSERT_TRUE(data != nullptr);
if (framer_.version() <= QUIC_VERSION_31) {
test::CompareCharArraysWithHexError("constructed packet", data->data(),
data->length(), AsChars(packet),
arraysize(packet));
} else {
test::CompareCharArraysWithHexError(
"constructed packet", data->data(), data->length(),
AsChars(packet_version32), arraysize(packet_version32));
}
}
TEST_P(QuicFramerTest, BuildTruncatedAckFrameSmallPacket) {
if (framer_.version() > QUIC_VERSION_33) {
return;
}
QuicPacketHeader header;
header.public_header.connection_id = kConnectionId;
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.fec_flag = false;
header.entropy_flag = true;
header.packet_number = kPacketNumber;
QuicAckFrame ack_frame;
// This entropy hash is different from what shows up in the packet below,
// since entropy is recomputed by the framer on ack truncation (by
// TestEntropyCalculator for this test.)
ack_frame.entropy_hash = 0x43;
ack_frame.largest_observed = 2 * 300;
ack_frame.ack_delay_time = QuicTime::Delta::Zero();
for (size_t i = 1; i < 2 * 300; i += 2) {
ack_frame.packets.Add(i);
}
QuicFrames frames;
frames.push_back(QuicFrame(&ack_frame));
// clang-format off
unsigned char packet[] = {
// public flags (8 byte connection_id)
0x3C,
// connection_id
0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
// private flags (entropy)
0x01,
// frame type (ack frame)
// (has nacks, is truncated, 2 byte largest observed, 1 byte delta)
0x74,
// entropy hash of all received packets, set to 1 by TestEntropyCalculator
// since ack is truncated.
0x01,
// 2-byte largest observed packet number.
// Expected to be 12 (0x0C), since only 6 nack ranges can fit.
0x0C, 0x00,
// Zero delta time.
0x00, 0x00,
// num missing packet ranges (limited to 6 by packet size of 37).
0x06,
// {missing packet delta, further missing packets in range}
// 6 nack ranges
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
// 0 revived packets.
0x00,
};
// clang-format on
// clang-format off
unsigned char packet_version32[] = {
// public flags (8 byte connection_id)
static_cast<unsigned char>(
framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
// connection_id
0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
// private flags (entropy)
0x01,
// frame type (ack frame)
// (has nacks, is truncated, 2 byte largest observed, 1 byte delta)
0x74,
// entropy hash of all received packets, set to 1 by TestEntropyCalculator
// since ack is truncated.
0x01,
// 2-byte largest observed packet number.
// Expected to be 12 (0x0C), since only 6 nack ranges can fit.
0x0C, 0x00,
// Zero delta time.
0x00, 0x00,
// num missing packet ranges (limited to 6 by packet size of 37).
0x06,
// {missing packet delta, further missing packets in range}
// 6 nack ranges
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
};
// clang-format on
if (framer_.version() <= QUIC_VERSION_31) {
std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames, 37u));
ASSERT_TRUE(data != nullptr);
// Expect 1 byte unused since at least 2 bytes are needed to fit more nacks.
EXPECT_EQ(36u, data->length());
test::CompareCharArraysWithHexError("constructed packet", data->data(),
data->length(), AsChars(packet),
arraysize(packet));
} else {
std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames, 36u));
ASSERT_TRUE(data != nullptr);
// Expect 1 byte unused since at least 2 bytes are needed to fit more nacks.
EXPECT_EQ(35u, data->length());
test::CompareCharArraysWithHexError(
"constructed packet", data->data(), data->length(),
AsChars(packet_version32), arraysize(packet_version32));
}
}
TEST_P(QuicFramerTest, BuildNewAckFramePacketOneAckBlock) {
if (framer_.version() <= QUIC_VERSION_33) {
return;
}
QuicPacketHeader header;
header.public_header.connection_id = kConnectionId;
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.packet_number = kPacketNumber;
// Use kSmallLargestObserved to make this test finished in a short time.
QuicAckFrame ack_frame;
ack_frame.largest_observed = kSmallLargestObserved;
ack_frame.ack_delay_time = QuicTime::Delta::Zero();
ack_frame.missing = false;
ack_frame.packets.Add(1, kSmallLargestObserved + 1);
QuicFrames frames;
frames.push_back(QuicFrame(&ack_frame));
// clang-format off
unsigned char packet[] = {
// public flags (8 byte connection_id)
0x38,
// connection_id
0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
// frame type (ack frame)
// (no ack blocks, 2 byte largest observed, 2 byte block length)
0x45,
// largest acked
0x34, 0x12,
// Zero delta time.
0x00, 0x00,
// first ack block length.
0x34, 0x12,
// num timestamps.
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(packet),
arraysize(packet));
}
TEST_P(QuicFramerTest, BuildNewAckFramePacketMultipleAckBlocks) {
if (framer_.version() <= QUIC_VERSION_33) {
return;
}
QuicPacketHeader header;
header.public_header.connection_id = kConnectionId;
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.packet_number = kPacketNumber;
// Use kSmallLargestObserved to make this test finished in a short time.
QuicAckFrame ack_frame;
ack_frame.largest_observed = kSmallLargestObserved;
ack_frame.ack_delay_time = QuicTime::Delta::Zero();
ack_frame.missing = false;
ack_frame.packets.Add(1, 5);
ack_frame.packets.Add(10, 500);
ack_frame.packets.Add(900, kSmallMissingPacket);
ack_frame.packets.Add(kSmallMissingPacket + 1, kSmallLargestObserved + 1);
QuicFrames frames;
frames.push_back(QuicFrame(&ack_frame));
// clang-format off
unsigned char packet[] = {
// public flags (8 byte connection_id)
0x38,
// connection_id
0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
// frame type (ack frame)
// (has ack blocks, 2 byte largest observed, 2 byte block length)
0x65,
// largest acked
0x34, 0x12,
// Zero delta time.
0x00, 0x00,
// num ack blocks ranges.
0x04,
// first ack block length.
0x01, 0x00,
// gap to next block.
0x01,
// ack block length.
0xaf, 0x0e,
// gap to next block.
0xff,
// ack block length.
0x00, 0x00,
// gap to next block.
0x91,
// ack block length.
0xea, 0x01,
// gap to next block.
0x05,
// ack block length.
0x04, 0x00,
// num timestamps.
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(packet),
arraysize(packet));
}
TEST_P(QuicFramerTest, BuildNewAckFramePacketMaxAckBlocks) {
if (framer_.version() <= QUIC_VERSION_33) {
return;
}
QuicPacketHeader header;
header.public_header.connection_id = kConnectionId;
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.packet_number = kPacketNumber;
// Use kSmallLargestObservedto make this test finished in a short time.
QuicAckFrame ack_frame;
ack_frame.largest_observed = kSmallLargestObserved;
ack_frame.ack_delay_time = QuicTime::Delta::Zero();
ack_frame.missing = false;
// 300 ack blocks.
for (size_t i = 2; i < 2 * 300; i += 2) {
ack_frame.packets.Add(i);
}
ack_frame.packets.Add(600, kSmallLargestObserved + 1);
QuicFrames frames;
frames.push_back(QuicFrame(&ack_frame));
// clang-format off
unsigned char packet[] = {
// public flags (8 byte connection_id)
0x38,
// connection_id
0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
// frame type (ack frame)
// (has ack blocks, 2 byte largest observed, 2 byte block length)
0x65,
// largest acked
0x34, 0x12,
// Zero delta time.
0x00, 0x00,
// num ack blocks ranges.
0xff,
// first ack block length.
0xdd, 0x0f,
// 255 = 4 * 63 + 3
0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
// num timestamps.
0x00,
};
std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
ASSERT_TRUE(data != nullptr);
test::CompareCharArraysWithHexError("constructed packet", data->data(),
data->length(), AsChars(packet),
arraysize(packet));
}
TEST_P(QuicFramerTest, BuildStopWaitingPacket) {
if (framer_.version() > QUIC_VERSION_33) {
return;
}
QuicPacketHeader header;
header.public_header.connection_id = kConnectionId;
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.fec_flag = false;
header.entropy_flag = true;
header.packet_number = kPacketNumber;
QuicStopWaitingFrame stop_waiting_frame;
stop_waiting_frame.entropy_hash = 0x14;
stop_waiting_frame.least_unacked = kLeastUnacked;
QuicFrames frames;
frames.push_back(QuicFrame(&stop_waiting_frame));
// clang-format off
unsigned char packet[] = {
// public flags (8 byte connection_id)
static_cast<unsigned char>(
framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
// private flags (entropy)
0x01,
// frame type (stop waiting frame)
0x06,
// entropy hash of sent packets till least awaiting - 1.
0x14,
// least packet number awaiting an ack, delta from packet number.
0x1C, 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(packet),
arraysize(packet));
}
TEST_P(QuicFramerTest, BuildNewStopWaitingPacket) {
if (framer_.version() <= QUIC_VERSION_33) {
return;
}
QuicPacketHeader header;
header.public_header.connection_id = kConnectionId;
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.fec_flag = false;
header.entropy_flag = false;
header.packet_number = kPacketNumber;
QuicStopWaitingFrame stop_waiting_frame;
stop_waiting_frame.least_unacked = kLeastUnacked;
QuicFrames frames;
frames.push_back(QuicFrame(&stop_waiting_frame));
// clang-format off
unsigned char packet[] = {
// public flags (8 byte connection_id)
0x38,
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
// frame type (stop waiting frame)
0x06,
// least packet number awaiting an ack, delta from packet number.
0x1C, 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(packet),
arraysize(packet));
}
TEST_P(QuicFramerTest, BuildRstFramePacketQuic) {
QuicPacketHeader header;
header.public_header.connection_id = kConnectionId;
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.fec_flag = false;
header.entropy_flag = false;
header.packet_number = kPacketNumber;
QuicRstStreamFrame rst_frame;
rst_frame.stream_id = kStreamId;
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)
static_cast<unsigned char>(
framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// private flags
0x00,
// frame type (rst stream frame)
0x01,
// stream id
0x04, 0x03, 0x02, 0x01,
// sent byte offset
0x01, 0x02, 0x03, 0x04,
0x05, 0x06, 0x07, 0x08,
// error code
0x08, 0x07, 0x06, 0x05,
};
unsigned char packet_34[] = {
// public flags (8 byte connection_id)
0x38,
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// frame type (rst stream frame)
0x01,
// stream id
0x04, 0x03, 0x02, 0x01,
// sent byte offset
0x01, 0x02, 0x03, 0x04,
0x05, 0x06, 0x07, 0x08,
// error code
0x08, 0x07, 0x06, 0x05,
};
// clang-format on
QuicFrames frames;
frames.push_back(QuicFrame(&rst_frame));
std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
ASSERT_TRUE(data != nullptr);
test::CompareCharArraysWithHexError(
"constructed packet", data->data(), data->length(),
AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
: arraysize(packet_34));
}
TEST_P(QuicFramerTest, BuildCloseFramePacket) {
QuicPacketHeader header;
header.public_header.connection_id = kConnectionId;
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.fec_flag = false;
header.entropy_flag = true;
header.packet_number = kPacketNumber;
QuicConnectionCloseFrame close_frame;
close_frame.error_code = static_cast<QuicErrorCode>(0x05060708);
close_frame.error_details = "because I can";
QuicFrames frames;
frames.push_back(QuicFrame(&close_frame));
// clang-format off
unsigned char packet[] = {
// public flags (8 byte connection_id)
static_cast<unsigned char>(
framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// private flags (entropy)
0x01,
// frame type (connection close frame)
0x02,
// error code
0x08, 0x07, 0x06, 0x05,
// error details length
0x0d, 0x00,
// error details
'b', 'e', 'c', 'a',
'u', 's', 'e', ' ',
'I', ' ', 'c', 'a',
'n',
};
unsigned char packet_34[] = {
// public flags (8 byte connection_id)
static_cast<unsigned char>(
framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// frame type (connection close frame)
0x02,
// error code
0x08, 0x07, 0x06, 0x05,
// error details length
0x0d, 0x00,
// 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(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
: arraysize(packet_34));
}
TEST_P(QuicFramerTest, BuildGoAwayPacket) {
QuicPacketHeader header;
header.public_header.connection_id = kConnectionId;
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.fec_flag = false;
header.entropy_flag = true;
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;
frames.push_back(QuicFrame(&goaway_frame));
// clang-format off
unsigned char packet[] = {
// public flags (8 byte connection_id)
static_cast<unsigned char>(
framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// private flags(entropy)
0x01,
// frame type (go away frame)
0x03,
// error code
0x08, 0x07, 0x06, 0x05,
// stream id
0x04, 0x03, 0x02, 0x01,
// error details length
0x0d, 0x00,
// error details
'b', 'e', 'c', 'a',
'u', 's', 'e', ' ',
'I', ' ', 'c', 'a',
'n',
};
unsigned char packet_34[] = {
// public flags (8 byte connection_id)
0x38,
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// frame type (go away frame)
0x03,
// error code
0x08, 0x07, 0x06, 0x05,
// stream id
0x04, 0x03, 0x02, 0x01,
// error details length
0x0d, 0x00,
// 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(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
: arraysize(packet_34));
}
TEST_P(QuicFramerTest, BuildWindowUpdatePacket) {
QuicPacketHeader header;
header.public_header.connection_id = kConnectionId;
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.fec_flag = false;
header.entropy_flag = true;
header.packet_number = kPacketNumber;
QuicWindowUpdateFrame window_update_frame;
window_update_frame.stream_id = kStreamId;
window_update_frame.byte_offset = 0x1122334455667788;
QuicFrames frames;
frames.push_back(QuicFrame(&window_update_frame));
// clang-format off
unsigned char packet[] = {
// public flags (8 byte connection_id)
static_cast<unsigned char>(
framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// private flags(entropy)
0x01,
// frame type (window update frame)
0x04,
// stream id
0x04, 0x03, 0x02, 0x01,
// byte offset
0x88, 0x77, 0x66, 0x55,
0x44, 0x33, 0x22, 0x11,
};
unsigned char packet_34[] = {
// public flags (8 byte connection_id)
0x38,
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// frame type (window update frame)
0x04,
// stream id
0x04, 0x03, 0x02, 0x01,
// byte offset
0x88, 0x77, 0x66, 0x55,
0x44, 0x33, 0x22, 0x11,
};
// clang-format on
std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
ASSERT_TRUE(data != nullptr);
test::CompareCharArraysWithHexError(
"constructed packet", data->data(), data->length(),
AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
: arraysize(packet_34));
}
TEST_P(QuicFramerTest, BuildBlockedPacket) {
QuicPacketHeader header;
header.public_header.connection_id = kConnectionId;
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.fec_flag = false;
header.entropy_flag = true;
header.packet_number = kPacketNumber;
QuicBlockedFrame blocked_frame;
blocked_frame.stream_id = kStreamId;
QuicFrames frames;
frames.push_back(QuicFrame(&blocked_frame));
// clang-format off
unsigned char packet[] = {
// public flags (8 byte connection_id)
static_cast<unsigned char>(
framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// private flags(entropy)
0x01,
// frame type (blocked frame)
0x05,
// stream id
0x04, 0x03, 0x02, 0x01,
};
unsigned char packet_34[] = {
// public flags (8 byte connection_id)
0x38,
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// frame type (blocked frame)
0x05,
// stream id
0x04, 0x03, 0x02, 0x01,
};
// clang-format on
std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
ASSERT_TRUE(data != nullptr);
test::CompareCharArraysWithHexError(
"constructed packet", data->data(), data->length(),
AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
: arraysize(packet_34));
}
TEST_P(QuicFramerTest, BuildPingPacket) {
QuicPacketHeader header;
header.public_header.connection_id = kConnectionId;
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.fec_flag = false;
header.entropy_flag = true;
header.packet_number = kPacketNumber;
QuicPingFrame ping_frame;
QuicFrames frames;
frames.push_back(QuicFrame(ping_frame));
// clang-format off
unsigned char packet[] = {
// public flags (8 byte connection_id)
static_cast<unsigned char>(
framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// private flags(entropy)
0x01,
// frame type (ping frame)
0x07,
};
unsigned char packet_34[] = {
// public flags (8 byte connection_id)
static_cast<unsigned char>(
framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// frame type (ping frame)
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(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
: arraysize(packet_34));
}
TEST_P(QuicFramerTest, BuildPathClosePacket) {
QuicPacketHeader header;
header.public_header.connection_id = kConnectionId;
header.public_header.multipath_flag = true;
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.fec_flag = false;
header.entropy_flag = true;
header.path_id = kDefaultPathId;
header.packet_number = kPacketNumber;
QuicPathCloseFrame path_close;
path_close.path_id = kPathId;
QuicFrames frames;
frames.push_back(QuicFrame(&path_close));
// clang-format off
unsigned char packet[] = {
// public flags (version)
static_cast<unsigned char>(
framer_.version() > QUIC_VERSION_32 ? 0x78 : 0X7C),
// connection_id
0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
// path_id
0x00,
// packet number
0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
// private flags (entropy)
0x01,
// frame type (path_close_frame)
0x08,
// path id
0x42,
};
unsigned char packet_34[] = {
// public flags (version)
static_cast<unsigned char>(
framer_.version() > QUIC_VERSION_32 ? 0x78 : 0X7C),
// connection_id
0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
// path_id
0x00,
// packet number
0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
// frame type (path_close_frame)
0x08,
// path id
0x42,
};
// clang-format on
std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
ASSERT_TRUE(data != nullptr);
test::CompareCharArraysWithHexError(
"constructed packet", data->data(), data->length(),
AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
: arraysize(packet_34));
}
// Test that the MTU discovery packet is serialized correctly as a PING packet.
TEST_P(QuicFramerTest, BuildMtuDiscoveryPacket) {
QuicPacketHeader header;
header.public_header.connection_id = kConnectionId;
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.fec_flag = false;
header.entropy_flag = true;
header.packet_number = kPacketNumber;
QuicMtuDiscoveryFrame mtu_discovery_frame;
QuicFrames frames;
frames.push_back(QuicFrame(mtu_discovery_frame));
// clang-format off
unsigned char packet[] = {
// public flags (8 byte connection_id)
static_cast<unsigned char>(
framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// private flags(entropy)
0x01,
// frame type (ping frame)
0x07,
};
unsigned char packet_34[] = {
// public flags (8 byte connection_id)
static_cast<unsigned char>(
framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// frame type (ping frame)
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(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
: arraysize(packet_34));
}
TEST_P(QuicFramerTest, BuildPublicResetPacketOld) {
FLAGS_quic_use_old_public_reset_packets = true;
QuicPublicResetPacket reset_packet;
reset_packet.public_header.connection_id = kConnectionId;
reset_packet.public_header.reset_flag = true;
reset_packet.public_header.version_flag = false;
reset_packet.rejected_packet_number = kPacketNumber;
reset_packet.nonce_proof = kNonceProof;
// clang-format off
unsigned char packet[] = {
// public flags (public reset, 8 byte ConnectionId)
0x0E,
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// 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
std::unique_ptr<QuicEncryptedPacket> data(
framer_.BuildPublicResetPacket(reset_packet));
ASSERT_TRUE(data != nullptr);
test::CompareCharArraysWithHexError("constructed packet", data->data(),
data->length(), AsChars(packet),
arraysize(packet));
}
TEST_P(QuicFramerTest, BuildPublicResetPacket) {
FLAGS_quic_use_old_public_reset_packets = false;
QuicPublicResetPacket reset_packet;
reset_packet.public_header.connection_id = kConnectionId;
reset_packet.public_header.reset_flag = true;
reset_packet.public_header.version_flag = false;
reset_packet.rejected_packet_number = kPacketNumber;
reset_packet.nonce_proof = kNonceProof;
// clang-format off
unsigned char packet[] = {
// public flags (public reset, 8 byte ConnectionId)
0x0A,
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// 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
std::unique_ptr<QuicEncryptedPacket> data(
framer_.BuildPublicResetPacket(reset_packet));
ASSERT_TRUE(data != nullptr);
test::CompareCharArraysWithHexError("constructed packet", data->data(),
data->length(), AsChars(packet),
arraysize(packet));
}
TEST_P(QuicFramerTest, BuildPublicResetPacketWithClientAddress) {
FLAGS_quic_use_old_public_reset_packets = false;
QuicPublicResetPacket reset_packet;
reset_packet.public_header.connection_id = kConnectionId;
reset_packet.public_header.reset_flag = true;
reset_packet.public_header.version_flag = false;
reset_packet.rejected_packet_number = kPacketNumber;
reset_packet.nonce_proof = kNonceProof;
reset_packet.client_address = IPEndPoint(Loopback4(), 0x1234);
// clang-format off
unsigned char packet[] = {
// public flags (public reset, 8 byte ConnectionId)
0x0A,
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// message tag (kPRST)
'P', 'R', 'S', 'T',
// num_entries (3) + 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
0x02, 0x00,
0x7F, 0x00, 0x00, 0x01,
0x34, 0x12,
};
// clang-format on
std::unique_ptr<QuicEncryptedPacket> data(
framer_.BuildPublicResetPacket(reset_packet));
ASSERT_TRUE(data != nullptr);
test::CompareCharArraysWithHexError("constructed packet", data->data(),
data->length(), AsChars(packet),
arraysize(packet));
}
TEST_P(QuicFramerTest, EncryptPacket) {
QuicPacketNumber packet_number = kPacketNumber;
// clang-format off
unsigned char packet[] = {
// public flags (8 byte connection_id)
static_cast<unsigned char>(
framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// private flags
0x00,
// redundancy
'a', 'b', 'c', 'd',
'e', 'f', 'g', 'h',
'i', 'j', 'k', 'l',
'm', 'n', 'o', 'p',
};
unsigned char packet_34[] = {
// public flags (8 byte connection_id)
static_cast<unsigned char>(
framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// redundancy
'a', 'b', 'c', 'd',
'e', 'f', 'g', 'h',
'i', 'j', 'k', 'l',
'm', 'n', 'o', 'p',
};
// clang-format on
std::unique_ptr<QuicPacket> raw(new QuicPacket(
AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
: arraysize(packet_34),
false, PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, !kIncludePathId,
!kIncludeDiversificationNonce, PACKET_6BYTE_PACKET_NUMBER));
char buffer[kMaxPacketSize];
size_t encrypted_length =
framer_.EncryptPayload(ENCRYPTION_NONE, kDefaultPathId, packet_number,
*raw, buffer, kMaxPacketSize);
ASSERT_NE(0u, encrypted_length);
EXPECT_TRUE(CheckEncryption(kDefaultPathId, 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)
0x39,
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// version tag
'Q', '.', '1', '0',
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// private flags
0x00,
// redundancy
'a', 'b', 'c', 'd',
'e', 'f', 'g', 'h',
'i', 'j', 'k', 'l',
'm', 'n', 'o', 'p',
};
unsigned char packet_34[] = {
// public flags (version, 8 byte connection_id)
0x39,
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// version tag
'Q', '.', '1', '0',
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// redundancy
'a', 'b', 'c', 'd',
'e', 'f', 'g', 'h',
'i', 'j', 'k', 'l',
'm', 'n', 'o', 'p',
};
// clang-format on
std::unique_ptr<QuicPacket> raw(new QuicPacket(
AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
: arraysize(packet_34),
false, PACKET_8BYTE_CONNECTION_ID, kIncludeVersion, !kIncludePathId,
!kIncludeDiversificationNonce, PACKET_6BYTE_PACKET_NUMBER));
char buffer[kMaxPacketSize];
size_t encrypted_length =
framer_.EncryptPayload(ENCRYPTION_NONE, kDefaultPathId, packet_number,
*raw, buffer, kMaxPacketSize);
ASSERT_NE(0u, encrypted_length);
EXPECT_TRUE(CheckEncryption(kDefaultPathId, packet_number, raw.get()));
}
TEST_P(QuicFramerTest, EncryptPacketWithMultipathFlag) {
QuicPacketNumber packet_number = kPacketNumber;
// clang-format off
unsigned char packet[] = {
// public flags (version, 8 byte connection_id)
0x78,
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// path_id
0x42,
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// private flags
0x00,
// redundancy
'a', 'b', 'c', 'd',
'e', 'f', 'g', 'h',
'i', 'j', 'k', 'l',
'm', 'n', 'o', 'p',
};
unsigned char packet_34[] = {
// public flags (version, 8 byte connection_id)
0x78,
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// path_id
0x42,
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// redundancy
'a', 'b', 'c', 'd',
'e', 'f', 'g', 'h',
'i', 'j', 'k', 'l',
'm', 'n', 'o', 'p',
};
// clang-format on
std::unique_ptr<QuicPacket> raw(new QuicPacket(
AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
: arraysize(packet_34),
false, PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, kIncludePathId,
!kIncludeDiversificationNonce, PACKET_6BYTE_PACKET_NUMBER));
char buffer[kMaxPacketSize];
size_t encrypted_length = framer_.EncryptPayload(
ENCRYPTION_NONE, kPathId, packet_number, *raw, buffer, kMaxPacketSize);
ASSERT_NE(0u, encrypted_length);
EXPECT_TRUE(CheckEncryption(kPathId, packet_number, raw.get()));
}
TEST_P(QuicFramerTest, EncryptPacketWithBothVersionFlagAndMultipathFlag) {
QuicPacketNumber packet_number = kPacketNumber;
// clang-format off
unsigned char packet[] = {
// public flags (version, 8 byte connection_id)
0x79,
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// version tag
'Q', '.', '1', '0',
// path_id
0x42,
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// private flags
0x00,
// redundancy
'a', 'b', 'c', 'd',
'e', 'f', 'g', 'h',
'i', 'j', 'k', 'l',
'm', 'n', 'o', 'p',
};
unsigned char packet_34[] = {
// public flags (version, 8 byte connection_id)
0x79,
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// version tag
'Q', '.', '1', '0',
// path_id
0x42,
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// redundancy
'a', 'b', 'c', 'd',
'e', 'f', 'g', 'h',
'i', 'j', 'k', 'l',
'm', 'n', 'o', 'p',
};
// clang-format on
std::unique_ptr<QuicPacket> raw(new QuicPacket(
AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
: arraysize(packet_34),
false, PACKET_8BYTE_CONNECTION_ID, kIncludeVersion, kIncludePathId,
!kIncludeDiversificationNonce, PACKET_6BYTE_PACKET_NUMBER));
char buffer[kMaxPacketSize];
size_t encrypted_length = framer_.EncryptPayload(
ENCRYPTION_NONE, kPathId, packet_number, *raw, buffer, kMaxPacketSize);
ASSERT_NE(0u, encrypted_length);
EXPECT_TRUE(CheckEncryption(kPathId, packet_number, raw.get()));
}
TEST_P(QuicFramerTest, AckTruncationLargePacket) {
QuicPacketHeader header;
header.public_header.connection_id = kConnectionId;
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.fec_flag = false;
header.entropy_flag = false;
header.packet_number = kPacketNumber;
QuicAckFrame ack_frame;
// Create a packet with just the ack.
if (framer_.version() <= QUIC_VERSION_33) {
ack_frame = MakeAckFrameWithNackRanges(300, 0u);
} else {
ack_frame = MakeAckFrameWithAckBlocks(300, 0u);
}
QuicFrame frame;
frame.type = ACK_FRAME;
frame.ack_frame = &ack_frame;
QuicFrames frames;
frames.push_back(frame);
// Build an ack packet with truncation due to limit in number of nack ranges.
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, kDefaultPathId, 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.
ASSERT_TRUE(framer_.ProcessPacket(
QuicEncryptedPacket(buffer, encrypted_length, false)));
ASSERT_EQ(1u, visitor_.ack_frames_.size());
QuicAckFrame& processed_ack_frame = *visitor_.ack_frames_[0];
if (framer_.version() <= QUIC_VERSION_33) {
EXPECT_TRUE(processed_ack_frame.is_truncated);
EXPECT_EQ(510u, processed_ack_frame.largest_observed);
EXPECT_TRUE(processed_ack_frame.missing);
ASSERT_EQ(255u, processed_ack_frame.packets.NumPacketsSlow());
EXPECT_EQ(1u, processed_ack_frame.packets.Min());
EXPECT_EQ(509u, processed_ack_frame.packets.Max());
} else {
EXPECT_FALSE(processed_ack_frame.is_truncated);
EXPECT_FALSE(processed_ack_frame.missing);
EXPECT_EQ(600u, processed_ack_frame.largest_observed);
ASSERT_EQ(256u, processed_ack_frame.packets.NumPacketsSlow());
EXPECT_EQ(90u, processed_ack_frame.packets.Min());
EXPECT_EQ(600u, processed_ack_frame.packets.Max());
}
}
TEST_P(QuicFramerTest, AckTruncationSmallPacket) {
QuicPacketHeader header;
header.public_header.connection_id = kConnectionId;
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.fec_flag = false;
header.entropy_flag = false;
header.packet_number = kPacketNumber;
// Create a packet with just the ack.
QuicAckFrame ack_frame;
if (framer_.version() <= QUIC_VERSION_33) {
ack_frame = MakeAckFrameWithNackRanges(300, 0u);
} else {
ack_frame = MakeAckFrameWithAckBlocks(300, 0u);
}
QuicFrame frame;
frame.type = ACK_FRAME;
frame.ack_frame = &ack_frame;
QuicFrames frames;
frames.push_back(frame);
// Build an ack packet with truncation due to limit in number of nack ranges.
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, kDefaultPathId, 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.
ASSERT_TRUE(framer_.ProcessPacket(
QuicEncryptedPacket(buffer, encrypted_length, false)));
ASSERT_EQ(1u, visitor_.ack_frames_.size());
QuicAckFrame& processed_ack_frame = *visitor_.ack_frames_[0];
if (framer_.version() <= QUIC_VERSION_33) {
EXPECT_TRUE(processed_ack_frame.is_truncated);
EXPECT_EQ(476u, processed_ack_frame.largest_observed);
EXPECT_TRUE(processed_ack_frame.missing);
ASSERT_EQ(238u, processed_ack_frame.packets.NumPacketsSlow());
EXPECT_EQ(1u, processed_ack_frame.packets.Min());
EXPECT_EQ(475u, processed_ack_frame.packets.Max());
} else {
EXPECT_FALSE(processed_ack_frame.is_truncated);
EXPECT_EQ(600u, processed_ack_frame.largest_observed);
EXPECT_FALSE(processed_ack_frame.missing);
ASSERT_EQ(239u, processed_ack_frame.packets.NumPacketsSlow());
EXPECT_EQ(124u, processed_ack_frame.packets.Min());
EXPECT_EQ(600u, processed_ack_frame.packets.Max());
}
}
TEST_P(QuicFramerTest, CleanTruncation) {
QuicPacketHeader header;
header.public_header.connection_id = kConnectionId;
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.fec_flag = false;
header.entropy_flag = true;
header.packet_number = kPacketNumber;
QuicAckFrame ack_frame;
ack_frame.largest_observed = 201;
ack_frame.packets.Add(1, ack_frame.largest_observed);
// Create a packet with just the ack.
QuicFrame frame;
frame.type = ACK_FRAME;
frame.ack_frame = &ack_frame;
QuicFrames frames;
frames.push_back(frame);
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, kDefaultPathId, 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.
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();
frame.type = ACK_FRAME;
frame.ack_frame = visitor_.ack_frames_[0];
frames.push_back(frame);
size_t original_raw_length = raw_ack_packet->length();
raw_ack_packet.reset(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, EntropyFlagTest) {
if (framer_.version() > QUIC_VERSION_33) {
return;
}
// clang-format off
unsigned char packet[] = {
// public flags (8 byte connection_id)
static_cast<unsigned char>(
framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// private flags (Entropy)
0x01,
// frame type (stream frame with fin and no length)
0xDF,
// stream id
0x04, 0x03, 0x02, 0x01,
// offset
0x54, 0x76, 0x10, 0x32,
0xDC, 0xFE, 0x98, 0xBA,
// data
'h', 'e', 'l', 'l',
'o', ' ', 'w', 'o',
'r', 'l', 'd', '!',
};
// clang-format on
QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
EXPECT_TRUE(framer_.ProcessPacket(encrypted));
EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
ASSERT_TRUE(visitor_.header_.get());
EXPECT_TRUE(visitor_.header_->entropy_flag);
EXPECT_EQ(1 << 4, visitor_.header_->entropy_hash);
EXPECT_FALSE(visitor_.header_->fec_flag);
};
TEST_P(QuicFramerTest, StopPacketProcessing) {
// clang-format off
unsigned char packet[] = {
// public flags (8 byte connection_id)
static_cast<unsigned char>(
framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// Entropy
0x01,
// frame type (stream frame with fin)
0xFF,
// stream id
0x04, 0x03, 0x02, 0x01,
// offset
0x54, 0x76, 0x10, 0x32,
0xDC, 0xFE, 0x98, 0xBA,
// data length
0x0c, 0x00,
// data
'h', 'e', 'l', 'l',
'o', ' ', 'w', 'o',
'r', 'l', 'd', '!',
// frame type (ack frame)
0x40,
// entropy hash of sent packets till least awaiting - 1.
0x14,
// least packet number awaiting an ack
0xA0, 0x9A, 0x78, 0x56,
0x34, 0x12,
// entropy hash of all received packets.
0x43,
// largest observed packet number
0xBF, 0x9A, 0x78, 0x56,
0x34, 0x12,
// num missing packets
0x01,
// missing packet
0xBE, 0x9A, 0x78, 0x56,
0x34, 0x12,
};
unsigned char packet_34[] = {
// public flags (8 byte connection_id)
static_cast<unsigned char>(
framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// frame type (stream frame with fin)
0xFF,
// stream id
0x04, 0x03, 0x02, 0x01,
// offset
0x54, 0x76, 0x10, 0x32,
0xDC, 0xFE, 0x98, 0xBA,
// data length
0x0c, 0x00,
// data
'h', 'e', 'l', 'l',
'o', ' ', 'w', 'o',
'r', 'l', 'd', '!',
// frame type (ack frame)
0x40,
// entropy hash of sent packets till least awaiting - 1.
0x14,
// least packet number awaiting an ack
0xA0, 0x9A, 0x78, 0x56,
0x34, 0x12,
// entropy hash of all received packets.
0x43,
// largest observed packet number
0xBF, 0x9A, 0x78, 0x56,
0x34, 0x12,
// num missing packets
0x01,
// missing packet
0xBE, 0x9A, 0x78, 0x56,
0x34, 0x12,
};
// 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, OnAckFrame(_)).Times(0);
EXPECT_CALL(visitor, OnPacketComplete());
EXPECT_CALL(visitor, OnUnauthenticatedPublicHeader(_)).WillOnce(Return(true));
EXPECT_CALL(visitor, OnUnauthenticatedHeader(_)).WillOnce(Return(true));
EXPECT_CALL(visitor, OnDecryptedPacket(_));
QuicEncryptedPacket encrypted(
AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
: arraysize(packet_34),
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.fin &&
frame.offset == 0 &&
string(frame.data_buffer, frame.data_length) == kTestString;
// FIN is hard-coded false in ConstructEncryptedPacket.
// Offset 0 is hard-coded in ConstructEncryptedPacket.
}
// Verify that the packet returned by ConstructEncryptedPacket() can be properly
// parsed by the framer.
TEST_P(QuicFramerTest, ConstructEncryptedPacket) {
// Since we are using ConstructEncryptedPacket, we have to set the framer's
// crypto to be Null.
framer_.SetDecrypter(ENCRYPTION_NONE, QuicDecrypter::Create(kNULL));
framer_.SetEncrypter(ENCRYPTION_NONE, QuicEncrypter::Create(kNULL));
QuicVersionVector versions;
versions.push_back(framer_.version());
std::unique_ptr<QuicEncryptedPacket> packet(ConstructEncryptedPacket(
42, false, false, false, kDefaultPathId, kTestQuicStreamId, kTestString,
PACKET_8BYTE_CONNECTION_ID, PACKET_6BYTE_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);
EXPECT_CALL(visitor, OnStreamFrame(Truly(ExpectedStreamFrame))).Times(1);
EXPECT_CALL(visitor, OnAckFrame(_)).Times(0);
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, QuicDecrypter::Create(kNULL));
framer_.SetEncrypter(ENCRYPTION_NONE, QuicEncrypter::Create(kNULL));
QuicVersionVector versions;
versions.push_back(framer_.version());
std::unique_ptr<QuicEncryptedPacket> packet(ConstructMisFramedEncryptedPacket(
42, false, false, false, kDefaultPathId, kTestQuicStreamId, kTestString,
PACKET_8BYTE_CONNECTION_ID, PACKET_6BYTE_PACKET_NUMBER, &versions,
Perspective::IS_SERVER));
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));
if (framer_.version() <= QUIC_VERSION_33) {
EXPECT_CALL(visitor, OnPacketHeader(_)).Times(0);
} else {
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, OnAckFrame(_)).Times(0);
EXPECT_CALL(visitor, OnPacketComplete()).Times(0);
EXPECT_FALSE(framer_.ProcessPacket(*packet));
if (framer_.version() <= QUIC_VERSION_33) {
EXPECT_EQ(QUIC_INVALID_PACKET_HEADER, framer_.error());
} else {
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) {
QuicFramer framer(AllSupportedVersions(), QuicTime::Zero(),
Perspective::IS_SERVER);
const char* const packet_bytes = reinterpret_cast<const char*>(data);
// Test the CryptoFramer.
StringPiece 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);
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)
0x3C,
// connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// private flags
0x00,
// frame type (stream frame with fin)
0xFF,
// stream id
0x04, 0x03, 0x02, 0x01,
// offset
0x54, 0x76, 0x10, 0x32,
0xDC, 0xFE, 0x98, 0xBA,
// data length
0x0c, 0x00,
// data
'h', 'e', 'l', 'l',
'o', ' ', 'w', 'o',
'r', 'l', 'd', '!',
};
// clang-format on
QuicFramerFuzzFunc(packet, arraysize(packet));
}
} // namespace test
} // namespace net