| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "net/third_party/quiche/src/quic/core/quic_framer.h" |
| |
| #include <algorithm> |
| #include <cstdint> |
| #include <map> |
| #include <memory> |
| #include <vector> |
| |
| #include "net/third_party/quiche/src/quic/core/crypto/null_decrypter.h" |
| #include "net/third_party/quiche/src/quic/core/crypto/null_encrypter.h" |
| #include "net/third_party/quiche/src/quic/core/crypto/quic_decrypter.h" |
| #include "net/third_party/quiche/src/quic/core/crypto/quic_encrypter.h" |
| #include "net/third_party/quiche/src/quic/core/quic_packets.h" |
| #include "net/third_party/quiche/src/quic/core/quic_types.h" |
| #include "net/third_party/quiche/src/quic/core/quic_utils.h" |
| #include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h" |
| #include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h" |
| #include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" |
| #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" |
| #include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" |
| #include "net/third_party/quiche/src/quic/platform/api/quic_string.h" |
| #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" |
| #include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" |
| #include "net/third_party/quiche/src/quic/test_tools/quic_framer_peer.h" |
| #include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" |
| #include "net/third_party/quiche/src/quic/test_tools/simple_data_producer.h" |
| |
| using testing::_; |
| using testing::Return; |
| using testing::Truly; |
| |
| namespace quic { |
| namespace test { |
| namespace { |
| |
| const uint64_t kEpoch = UINT64_C(1) << 32; |
| const uint64_t kMask = kEpoch - 1; |
| |
| const QuicUint128 kTestStatelessResetToken = 1010101; // 0x0F69B5 |
| |
| // Use fields in which each byte is distinct to ensure that every byte is |
| // framed correctly. The values are otherwise arbitrary. |
| QuicConnectionId FramerTestConnectionId() { |
| return TestConnectionId(UINT64_C(0xFEDCBA9876543210)); |
| } |
| |
| QuicConnectionId FramerTestConnectionIdPlusOne() { |
| return TestConnectionId(UINT64_C(0xFEDCBA9876543211)); |
| } |
| |
| const QuicPacketNumber kPacketNumber = QuicPacketNumber(UINT64_C(0x12345678)); |
| const QuicPacketNumber kSmallLargestObserved = |
| QuicPacketNumber(UINT16_C(0x1234)); |
| const QuicPacketNumber kSmallMissingPacket = QuicPacketNumber(UINT16_C(0x1233)); |
| const QuicPacketNumber kLeastUnacked = QuicPacketNumber(UINT64_C(0x012345670)); |
| const QuicStreamId kStreamId = UINT64_C(0x01020304); |
| // Note that the high 4 bits of the stream offset must be less than 0x40 |
| // in order to ensure that the value can be encoded using VarInt62 encoding. |
| const QuicStreamOffset kStreamOffset = UINT64_C(0x3A98FEDC32107654); |
| const QuicPublicResetNonceProof kNonceProof = UINT64_C(0xABCDEF0123456789); |
| |
| // In testing that we can ack the full range of packets... |
| // This is the largest packet number that can be represented in IETF QUIC |
| // varint62 format. |
| const QuicPacketNumber kLargestIetfLargestObserved = |
| QuicPacketNumber(UINT64_C(0x3fffffffffffffff)); |
| // Encodings for the two bits in a VarInt62 that |
| // describe the length of the VarInt61. For binary packet |
| // formats in this file, the convention is to code the |
| // first byte as |
| // kVarInt62FourBytes + 0x<value_in_that_byte> |
| const uint8_t kVarInt62OneByte = 0x00; |
| const uint8_t kVarInt62TwoBytes = 0x40; |
| const uint8_t kVarInt62FourBytes = 0x80; |
| const uint8_t kVarInt62EightBytes = 0xc0; |
| |
| class TestEncrypter : public QuicEncrypter { |
| public: |
| ~TestEncrypter() override {} |
| bool SetKey(QuicStringPiece key) override { return true; } |
| bool SetNoncePrefix(QuicStringPiece nonce_prefix) override { return true; } |
| bool SetIV(QuicStringPiece iv) override { return true; } |
| bool EncryptPacket(uint64_t packet_number, |
| QuicStringPiece associated_data, |
| QuicStringPiece plaintext, |
| char* output, |
| size_t* output_length, |
| size_t max_output_length) override { |
| packet_number_ = QuicPacketNumber(packet_number); |
| associated_data_ = QuicString(associated_data); |
| plaintext_ = QuicString(plaintext); |
| memcpy(output, plaintext.data(), plaintext.length()); |
| *output_length = plaintext.length(); |
| return true; |
| } |
| size_t GetKeySize() const override { return 0; } |
| size_t GetNoncePrefixSize() const override { return 0; } |
| size_t GetIVSize() const override { return 0; } |
| size_t GetMaxPlaintextSize(size_t ciphertext_size) const override { |
| return ciphertext_size; |
| } |
| size_t GetCiphertextSize(size_t plaintext_size) const override { |
| return plaintext_size; |
| } |
| QuicStringPiece GetKey() const override { return QuicStringPiece(); } |
| QuicStringPiece GetNoncePrefix() const override { return QuicStringPiece(); } |
| |
| QuicPacketNumber packet_number_; |
| QuicString associated_data_; |
| QuicString plaintext_; |
| }; |
| |
| class TestDecrypter : public QuicDecrypter { |
| public: |
| ~TestDecrypter() override {} |
| bool SetKey(QuicStringPiece key) override { return true; } |
| bool SetNoncePrefix(QuicStringPiece nonce_prefix) override { return true; } |
| bool SetIV(QuicStringPiece iv) override { return true; } |
| bool SetPreliminaryKey(QuicStringPiece key) override { |
| QUIC_BUG << "should not be called"; |
| return false; |
| } |
| bool SetDiversificationNonce(const DiversificationNonce& key) override { |
| return true; |
| } |
| bool DecryptPacket(uint64_t packet_number, |
| QuicStringPiece associated_data, |
| QuicStringPiece ciphertext, |
| char* output, |
| size_t* output_length, |
| size_t max_output_length) override { |
| packet_number_ = QuicPacketNumber(packet_number); |
| associated_data_ = QuicString(associated_data); |
| ciphertext_ = QuicString(ciphertext); |
| memcpy(output, ciphertext.data(), ciphertext.length()); |
| *output_length = ciphertext.length(); |
| return true; |
| } |
| size_t GetKeySize() const override { return 0; } |
| size_t GetIVSize() const override { return 0; } |
| QuicStringPiece GetKey() const override { return QuicStringPiece(); } |
| QuicStringPiece GetNoncePrefix() const override { return QuicStringPiece(); } |
| // Use a distinct value starting with 0xFFFFFF, which is never used by TLS. |
| uint32_t cipher_id() const override { return 0xFFFFFFF2; } |
| QuicPacketNumber packet_number_; |
| QuicString associated_data_; |
| QuicString ciphertext_; |
| }; |
| |
| class TestQuicVisitor : public QuicFramerVisitorInterface { |
| public: |
| TestQuicVisitor() |
| : error_count_(0), |
| version_mismatch_(0), |
| packet_count_(0), |
| frame_count_(0), |
| complete_packets_(0), |
| accept_packet_(true), |
| accept_public_header_(true) {} |
| |
| ~TestQuicVisitor() override {} |
| |
| void OnError(QuicFramer* f) override { |
| QUIC_DLOG(INFO) << "QuicFramer Error: " << QuicErrorCodeToString(f->error()) |
| << " (" << f->error() << ")"; |
| ++error_count_; |
| } |
| |
| void OnPacket() override {} |
| |
| void OnPublicResetPacket(const QuicPublicResetPacket& packet) override { |
| public_reset_packet_ = QuicMakeUnique<QuicPublicResetPacket>((packet)); |
| } |
| |
| void OnVersionNegotiationPacket( |
| const QuicVersionNegotiationPacket& packet) override { |
| version_negotiation_packet_ = |
| QuicMakeUnique<QuicVersionNegotiationPacket>((packet)); |
| } |
| |
| bool OnProtocolVersionMismatch(ParsedQuicVersion received_version, |
| PacketHeaderFormat /*form*/) override { |
| QUIC_DLOG(INFO) << "QuicFramer Version Mismatch, version: " |
| << received_version; |
| ++version_mismatch_; |
| return true; |
| } |
| |
| bool OnUnauthenticatedPublicHeader(const QuicPacketHeader& header) override { |
| header_ = QuicMakeUnique<QuicPacketHeader>((header)); |
| return accept_public_header_; |
| } |
| |
| bool OnUnauthenticatedHeader(const QuicPacketHeader& header) override { |
| return true; |
| } |
| |
| void OnDecryptedPacket(EncryptionLevel level) override {} |
| |
| bool OnPacketHeader(const QuicPacketHeader& header) override { |
| ++packet_count_; |
| header_ = QuicMakeUnique<QuicPacketHeader>((header)); |
| return accept_packet_; |
| } |
| |
| void OnCoalescedPacket(const QuicEncryptedPacket& packet) override { |
| size_t coalesced_data_length = packet.length(); |
| char* coalesced_data = new char[coalesced_data_length]; |
| memcpy(coalesced_data, packet.data(), coalesced_data_length); |
| coalesced_packets_.push_back(QuicMakeUnique<QuicEncryptedPacket>( |
| coalesced_data, coalesced_data_length, |
| /*owns_buffer=*/true)); |
| } |
| |
| bool OnStreamFrame(const QuicStreamFrame& frame) override { |
| ++frame_count_; |
| // Save a copy of the data so it is valid after the packet is processed. |
| QuicString* string_data = |
| new QuicString(frame.data_buffer, frame.data_length); |
| stream_data_.push_back(QuicWrapUnique(string_data)); |
| stream_frames_.push_back(QuicMakeUnique<QuicStreamFrame>( |
| frame.stream_id, frame.fin, frame.offset, *string_data)); |
| return true; |
| } |
| |
| bool OnCryptoFrame(const QuicCryptoFrame& frame) override { |
| ++frame_count_; |
| // Save a copy of the data so it is valid after the packet is processed. |
| QuicString* string_data = |
| new QuicString(frame.data_buffer, frame.data_length); |
| crypto_data_.push_back(QuicWrapUnique(string_data)); |
| crypto_frames_.push_back(QuicMakeUnique<QuicCryptoFrame>( |
| ENCRYPTION_NONE, frame.offset, *string_data)); |
| return true; |
| } |
| |
| bool OnAckFrameStart(QuicPacketNumber largest_acked, |
| QuicTime::Delta ack_delay_time) override { |
| ++frame_count_; |
| QuicAckFrame ack_frame; |
| ack_frame.largest_acked = largest_acked; |
| ack_frame.ack_delay_time = ack_delay_time; |
| ack_frames_.push_back(QuicMakeUnique<QuicAckFrame>(ack_frame)); |
| return true; |
| } |
| |
| bool OnAckRange(QuicPacketNumber start, QuicPacketNumber end) override { |
| DCHECK(!ack_frames_.empty()); |
| ack_frames_[ack_frames_.size() - 1]->packets.AddRange(start, end); |
| return true; |
| } |
| |
| bool OnAckTimestamp(QuicPacketNumber packet_number, |
| QuicTime timestamp) override { |
| ack_frames_[ack_frames_.size() - 1]->received_packet_times.push_back( |
| std::make_pair(packet_number, timestamp)); |
| return true; |
| } |
| |
| bool OnAckFrameEnd(QuicPacketNumber /*start*/) override { return true; } |
| |
| bool OnStopWaitingFrame(const QuicStopWaitingFrame& frame) override { |
| ++frame_count_; |
| stop_waiting_frames_.push_back(QuicMakeUnique<QuicStopWaitingFrame>(frame)); |
| return true; |
| } |
| |
| bool OnPaddingFrame(const QuicPaddingFrame& frame) override { |
| padding_frames_.push_back(QuicMakeUnique<QuicPaddingFrame>(frame)); |
| return true; |
| } |
| |
| bool OnPingFrame(const QuicPingFrame& frame) override { |
| ++frame_count_; |
| ping_frames_.push_back(QuicMakeUnique<QuicPingFrame>(frame)); |
| return true; |
| } |
| |
| bool OnMessageFrame(const QuicMessageFrame& frame) override { |
| ++frame_count_; |
| message_frames_.push_back( |
| QuicMakeUnique<QuicMessageFrame>(frame.data, frame.message_length)); |
| return true; |
| } |
| |
| void OnPacketComplete() override { ++complete_packets_; } |
| |
| bool OnRstStreamFrame(const QuicRstStreamFrame& frame) override { |
| rst_stream_frame_ = frame; |
| return true; |
| } |
| |
| bool OnConnectionCloseFrame(const QuicConnectionCloseFrame& frame) override { |
| connection_close_frame_ = frame; |
| return true; |
| } |
| |
| bool OnApplicationCloseFrame( |
| const QuicApplicationCloseFrame& frame) override { |
| application_close_frame_ = frame; |
| return true; |
| } |
| |
| bool OnStopSendingFrame(const QuicStopSendingFrame& frame) override { |
| stop_sending_frame_ = frame; |
| return true; |
| } |
| |
| bool OnPathChallengeFrame(const QuicPathChallengeFrame& frame) override { |
| path_challenge_frame_ = frame; |
| return true; |
| } |
| |
| bool OnPathResponseFrame(const QuicPathResponseFrame& frame) override { |
| path_response_frame_ = frame; |
| return true; |
| } |
| |
| bool OnGoAwayFrame(const QuicGoAwayFrame& frame) override { |
| goaway_frame_ = frame; |
| return true; |
| } |
| |
| bool OnMaxStreamIdFrame(const QuicMaxStreamIdFrame& frame) override { |
| max_stream_id_frame_ = frame; |
| return true; |
| } |
| |
| bool OnStreamIdBlockedFrame(const QuicStreamIdBlockedFrame& frame) override { |
| stream_id_blocked_frame_ = frame; |
| return true; |
| } |
| |
| bool OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) override { |
| window_update_frame_ = frame; |
| return true; |
| } |
| |
| bool OnBlockedFrame(const QuicBlockedFrame& frame) override { |
| blocked_frame_ = frame; |
| return true; |
| } |
| |
| bool OnNewConnectionIdFrame(const QuicNewConnectionIdFrame& frame) override { |
| new_connection_id_ = frame; |
| return true; |
| } |
| |
| bool OnRetireConnectionIdFrame( |
| const QuicRetireConnectionIdFrame& frame) override { |
| retire_connection_id_ = frame; |
| return true; |
| } |
| |
| bool OnNewTokenFrame(const QuicNewTokenFrame& frame) override { |
| new_token_ = frame; |
| return true; |
| } |
| |
| bool IsValidStatelessResetToken(QuicUint128 token) const override { |
| return token == kTestStatelessResetToken; |
| } |
| |
| void OnAuthenticatedIetfStatelessResetPacket( |
| const QuicIetfStatelessResetPacket& packet) override { |
| stateless_reset_packet_ = |
| QuicMakeUnique<QuicIetfStatelessResetPacket>(packet); |
| } |
| |
| // Counters from the visitor_ callbacks. |
| int error_count_; |
| int version_mismatch_; |
| int packet_count_; |
| int frame_count_; |
| int complete_packets_; |
| bool accept_packet_; |
| bool accept_public_header_; |
| |
| std::unique_ptr<QuicPacketHeader> header_; |
| std::unique_ptr<QuicPublicResetPacket> public_reset_packet_; |
| std::unique_ptr<QuicIetfStatelessResetPacket> stateless_reset_packet_; |
| std::unique_ptr<QuicVersionNegotiationPacket> version_negotiation_packet_; |
| std::vector<std::unique_ptr<QuicStreamFrame>> stream_frames_; |
| std::vector<std::unique_ptr<QuicCryptoFrame>> crypto_frames_; |
| std::vector<std::unique_ptr<QuicAckFrame>> ack_frames_; |
| std::vector<std::unique_ptr<QuicStopWaitingFrame>> stop_waiting_frames_; |
| std::vector<std::unique_ptr<QuicPaddingFrame>> padding_frames_; |
| std::vector<std::unique_ptr<QuicPingFrame>> ping_frames_; |
| std::vector<std::unique_ptr<QuicMessageFrame>> message_frames_; |
| std::vector<std::unique_ptr<QuicEncryptedPacket>> coalesced_packets_; |
| QuicRstStreamFrame rst_stream_frame_; |
| QuicConnectionCloseFrame connection_close_frame_; |
| QuicApplicationCloseFrame application_close_frame_; |
| QuicStopSendingFrame stop_sending_frame_; |
| QuicGoAwayFrame goaway_frame_; |
| QuicPathChallengeFrame path_challenge_frame_; |
| QuicPathResponseFrame path_response_frame_; |
| QuicWindowUpdateFrame window_update_frame_; |
| QuicBlockedFrame blocked_frame_; |
| QuicStreamIdBlockedFrame stream_id_blocked_frame_; |
| QuicMaxStreamIdFrame max_stream_id_frame_; |
| QuicNewConnectionIdFrame new_connection_id_; |
| QuicRetireConnectionIdFrame retire_connection_id_; |
| QuicNewTokenFrame new_token_; |
| std::vector<std::unique_ptr<QuicString>> stream_data_; |
| std::vector<std::unique_ptr<QuicString>> crypto_data_; |
| }; |
| |
| // Simple struct for defining a packet's content, and associated |
| // parse error. |
| struct PacketFragment { |
| QuicString error_if_missing; |
| std::vector<unsigned char> fragment; |
| }; |
| |
| using PacketFragments = std::vector<struct PacketFragment>; |
| |
| ParsedQuicVersionVector AllSupportedVersionsIncludingTls() { |
| QuicFlagSaver flags; |
| SetQuicFlag(&FLAGS_quic_supports_tls_handshake, true); |
| return AllSupportedVersions(); |
| } |
| |
| class QuicFramerTest : public QuicTestWithParam<ParsedQuicVersion> { |
| public: |
| QuicFramerTest() |
| : encrypter_(new test::TestEncrypter()), |
| decrypter_(new test::TestDecrypter()), |
| version_(GetParam()), |
| start_(QuicTime::Zero() + QuicTime::Delta::FromMicroseconds(0x10)), |
| framer_(AllSupportedVersionsIncludingTls(), |
| start_, |
| Perspective::IS_SERVER) { |
| SetQuicFlag(&FLAGS_quic_supports_tls_handshake, true); |
| framer_.set_version(version_); |
| framer_.SetDecrypter(ENCRYPTION_NONE, |
| std::unique_ptr<QuicDecrypter>(decrypter_)); |
| framer_.SetEncrypter(ENCRYPTION_NONE, |
| std::unique_ptr<QuicEncrypter>(encrypter_)); |
| |
| framer_.set_visitor(&visitor_); |
| framer_.InferPacketHeaderTypeFromVersion(); |
| } |
| |
| // Helper function to get unsigned char representation of the handshake |
| // protocol byte of the current QUIC version number. |
| unsigned char GetQuicVersionProtocolByte() { |
| return (CreateQuicVersionLabel(version_) >> 24) & 0xff; |
| } |
| |
| // Helper function to get unsigned char representation of digit in the |
| // units place of the current QUIC version number. |
| unsigned char GetQuicVersionDigitOnes() { |
| return CreateQuicVersionLabel(version_) & 0xff; |
| } |
| |
| // Helper function to get unsigned char representation of digit in the |
| // tens place of the current QUIC version number. |
| unsigned char GetQuicVersionDigitTens() { |
| return (CreateQuicVersionLabel(version_) >> 8) & 0xff; |
| } |
| |
| bool CheckEncryption(QuicPacketNumber packet_number, QuicPacket* packet) { |
| if (packet_number != encrypter_->packet_number_) { |
| QUIC_LOG(ERROR) << "Encrypted incorrect packet number. expected " |
| << packet_number |
| << " actual: " << encrypter_->packet_number_; |
| return false; |
| } |
| if (packet->AssociatedData(framer_.transport_version()) != |
| encrypter_->associated_data_) { |
| QUIC_LOG(ERROR) << "Encrypted incorrect associated data. expected " |
| << packet->AssociatedData(framer_.transport_version()) |
| << " actual: " << encrypter_->associated_data_; |
| return false; |
| } |
| if (packet->Plaintext(framer_.transport_version()) != |
| encrypter_->plaintext_) { |
| QUIC_LOG(ERROR) << "Encrypted incorrect plaintext data. expected " |
| << packet->Plaintext(framer_.transport_version()) |
| << " actual: " << encrypter_->plaintext_; |
| return false; |
| } |
| return true; |
| } |
| |
| bool CheckDecryption(const QuicEncryptedPacket& encrypted, |
| bool includes_version, |
| bool includes_diversification_nonce, |
| QuicConnectionIdLength destination_connection_id_length, |
| QuicConnectionIdLength source_connection_id_length) { |
| return CheckDecryption( |
| encrypted, includes_version, includes_diversification_nonce, |
| destination_connection_id_length, source_connection_id_length, |
| VARIABLE_LENGTH_INTEGER_LENGTH_0, 0, VARIABLE_LENGTH_INTEGER_LENGTH_0); |
| } |
| |
| bool CheckDecryption( |
| const QuicEncryptedPacket& encrypted, |
| bool includes_version, |
| bool includes_diversification_nonce, |
| QuicConnectionIdLength destination_connection_id_length, |
| QuicConnectionIdLength source_connection_id_length, |
| QuicVariableLengthIntegerLength retry_token_length_length, |
| size_t retry_token_length, |
| QuicVariableLengthIntegerLength length_length) { |
| if (visitor_.header_->packet_number != decrypter_->packet_number_) { |
| QUIC_LOG(ERROR) << "Decrypted incorrect packet number. expected " |
| << visitor_.header_->packet_number |
| << " actual: " << decrypter_->packet_number_; |
| return false; |
| } |
| QuicStringPiece associated_data = |
| QuicFramer::GetAssociatedDataFromEncryptedPacket( |
| framer_.transport_version(), encrypted, |
| destination_connection_id_length, source_connection_id_length, |
| includes_version, includes_diversification_nonce, |
| PACKET_4BYTE_PACKET_NUMBER, retry_token_length_length, |
| retry_token_length, length_length); |
| if (associated_data != decrypter_->associated_data_) { |
| QUIC_LOG(ERROR) << "Decrypted incorrect associated data. expected " |
| << QuicTextUtils::HexEncode(associated_data) |
| << " actual: " |
| << QuicTextUtils::HexEncode(decrypter_->associated_data_); |
| return false; |
| } |
| QuicStringPiece ciphertext( |
| encrypted.AsStringPiece().substr(GetStartOfEncryptedData( |
| framer_.transport_version(), destination_connection_id_length, |
| source_connection_id_length, includes_version, |
| includes_diversification_nonce, PACKET_4BYTE_PACKET_NUMBER, |
| retry_token_length_length, retry_token_length, length_length))); |
| if (ciphertext != decrypter_->ciphertext_) { |
| QUIC_LOG(ERROR) << "Decrypted incorrect ciphertext data. expected " |
| << QuicTextUtils::HexEncode(ciphertext) << " actual: " |
| << QuicTextUtils::HexEncode(decrypter_->ciphertext_) |
| << " associated data: " |
| << QuicTextUtils::HexEncode(associated_data); |
| return false; |
| } |
| return true; |
| } |
| |
| char* AsChars(unsigned char* data) { return reinterpret_cast<char*>(data); } |
| |
| // Creates a new QuicEncryptedPacket by concatenating the various |
| // packet fragments in |fragments|. |
| std::unique_ptr<QuicEncryptedPacket> AssemblePacketFromFragments( |
| const PacketFragments& fragments) { |
| char* buffer = new char[kMaxPacketSize + 1]; |
| size_t len = 0; |
| for (const auto& fragment : fragments) { |
| memcpy(buffer + len, fragment.fragment.data(), fragment.fragment.size()); |
| len += fragment.fragment.size(); |
| } |
| return QuicMakeUnique<QuicEncryptedPacket>(buffer, len, true); |
| } |
| |
| void CheckFramingBoundaries(const PacketFragments& fragments, |
| QuicErrorCode error_code) { |
| std::unique_ptr<QuicEncryptedPacket> packet( |
| AssemblePacketFromFragments(fragments)); |
| // Check all the various prefixes of |packet| for the expected |
| // parse error and error code. |
| for (size_t i = 0; i < packet->length(); ++i) { |
| QuicString expected_error; |
| size_t len = 0; |
| for (const auto& fragment : fragments) { |
| len += fragment.fragment.size(); |
| if (i < len) { |
| expected_error = fragment.error_if_missing; |
| break; |
| } |
| } |
| |
| if (expected_error.empty()) |
| continue; |
| |
| CheckProcessingFails(*packet, i, expected_error, error_code); |
| } |
| } |
| |
| void CheckProcessingFails(const QuicEncryptedPacket& packet, |
| size_t len, |
| QuicString expected_error, |
| QuicErrorCode error_code) { |
| QuicEncryptedPacket encrypted(packet.data(), len, false); |
| EXPECT_FALSE(framer_.ProcessPacket(encrypted)) << "len: " << len; |
| EXPECT_EQ(expected_error, framer_.detailed_error()) << "len: " << len; |
| EXPECT_EQ(error_code, framer_.error()) << "len: " << len; |
| } |
| |
| void CheckProcessingFails(unsigned char* packet, |
| size_t len, |
| QuicString expected_error, |
| QuicErrorCode error_code) { |
| QuicEncryptedPacket encrypted(AsChars(packet), len, false); |
| EXPECT_FALSE(framer_.ProcessPacket(encrypted)) << "len: " << len; |
| EXPECT_EQ(expected_error, framer_.detailed_error()) << "len: " << len; |
| EXPECT_EQ(error_code, framer_.error()) << "len: " << len; |
| } |
| |
| // Checks if the supplied string matches data in the supplied StreamFrame. |
| void CheckStreamFrameData(QuicString str, QuicStreamFrame* frame) { |
| EXPECT_EQ(str, QuicString(frame->data_buffer, frame->data_length)); |
| } |
| |
| void CheckCalculatePacketNumber(uint64_t expected_packet_number, |
| QuicPacketNumber last_packet_number) { |
| uint64_t wire_packet_number = expected_packet_number & kMask; |
| EXPECT_EQ(expected_packet_number, |
| QuicFramerPeer::CalculatePacketNumberFromWire( |
| &framer_, PACKET_4BYTE_PACKET_NUMBER, last_packet_number, |
| wire_packet_number)) |
| << "last_packet_number: " << last_packet_number |
| << " wire_packet_number: " << wire_packet_number; |
| } |
| |
| std::unique_ptr<QuicPacket> BuildDataPacket(const QuicPacketHeader& header, |
| const QuicFrames& frames) { |
| return BuildUnsizedDataPacket(&framer_, header, frames); |
| } |
| |
| std::unique_ptr<QuicPacket> BuildDataPacket(const QuicPacketHeader& header, |
| const QuicFrames& frames, |
| size_t packet_size) { |
| return BuildUnsizedDataPacket(&framer_, header, frames, packet_size); |
| } |
| |
| // N starts at 1. |
| QuicStreamId GetNthStreamid(QuicTransportVersion transport_version, |
| Perspective perspective, |
| bool bidirectional, |
| int n) { |
| if (bidirectional) { |
| return QuicUtils::GetFirstBidirectionalStreamId(transport_version, |
| perspective) + |
| ((n - 1) * QuicUtils::StreamIdDelta(transport_version)); |
| } |
| // Unidirectional |
| return QuicUtils::GetFirstUnidirectionalStreamId(transport_version, |
| perspective) + |
| ((n - 1) * QuicUtils::StreamIdDelta(transport_version)); |
| } |
| |
| test::TestEncrypter* encrypter_; |
| test::TestDecrypter* decrypter_; |
| ParsedQuicVersion version_; |
| QuicTime start_; |
| QuicFramer framer_; |
| test::TestQuicVisitor visitor_; |
| SimpleBufferAllocator allocator_; |
| }; |
| |
| // Multiple test cases of QuicFramerTest use byte arrays to define packets for |
| // testing, and these byte arrays contain the QUIC version. This macro explodes |
| // the 32-bit version into four bytes in network order. Since it uses methods of |
| // QuicFramerTest, it is only valid to use this in a QuicFramerTest. |
| #define QUIC_VERSION_BYTES \ |
| GetQuicVersionProtocolByte(), '0', GetQuicVersionDigitTens(), \ |
| GetQuicVersionDigitOnes() |
| |
| // Run all framer tests with all supported versions of QUIC. |
| INSTANTIATE_TEST_SUITE_P( |
| QuicFramerTests, |
| QuicFramerTest, |
| ::testing::ValuesIn(AllSupportedVersionsIncludingTls())); |
| |
| TEST_P(QuicFramerTest, CalculatePacketNumberFromWireNearEpochStart) { |
| // A few quick manual sanity checks. |
| CheckCalculatePacketNumber(UINT64_C(1), QuicPacketNumber()); |
| CheckCalculatePacketNumber(kEpoch + 1, QuicPacketNumber(kMask)); |
| CheckCalculatePacketNumber(kEpoch, QuicPacketNumber(kMask)); |
| for (uint64_t j = 0; j < 10; j++) { |
| CheckCalculatePacketNumber(j, QuicPacketNumber()); |
| CheckCalculatePacketNumber(kEpoch - 1 - j, QuicPacketNumber()); |
| } |
| |
| // Cases where the last number was close to the start of the range. |
| for (QuicPacketNumber last = QuicPacketNumber(1); last < QuicPacketNumber(10); |
| last++) { |
| // Small numbers should not wrap (even if they're out of order). |
| for (uint64_t j = 0; j < 10; j++) { |
| CheckCalculatePacketNumber(j, last); |
| } |
| |
| // Large numbers should not wrap either (because we're near 0 already). |
| for (uint64_t j = 0; j < 10; j++) { |
| CheckCalculatePacketNumber(kEpoch - 1 - j, last); |
| } |
| } |
| } |
| |
| TEST_P(QuicFramerTest, CalculatePacketNumberFromWireNearEpochEnd) { |
| // Cases where the last number was close to the end of the range |
| for (uint64_t i = 0; i < 10; i++) { |
| QuicPacketNumber last = QuicPacketNumber(kEpoch - i); |
| |
| // Small numbers should wrap. |
| for (uint64_t j = 0; j < 10; j++) { |
| CheckCalculatePacketNumber(kEpoch + j, last); |
| } |
| |
| // Large numbers should not (even if they're out of order). |
| for (uint64_t j = 0; j < 10; j++) { |
| CheckCalculatePacketNumber(kEpoch - 1 - j, last); |
| } |
| } |
| } |
| |
| // Next check where we're in a non-zero epoch to verify we handle |
| // reverse wrapping, too. |
| TEST_P(QuicFramerTest, CalculatePacketNumberFromWireNearPrevEpoch) { |
| const uint64_t prev_epoch = 1 * kEpoch; |
| const uint64_t cur_epoch = 2 * kEpoch; |
| // Cases where the last number was close to the start of the range |
| for (uint64_t i = 0; i < 10; i++) { |
| QuicPacketNumber last = QuicPacketNumber(cur_epoch + i); |
| // Small number should not wrap (even if they're out of order). |
| for (uint64_t j = 0; j < 10; j++) { |
| CheckCalculatePacketNumber(cur_epoch + j, last); |
| } |
| |
| // But large numbers should reverse wrap. |
| for (uint64_t j = 0; j < 10; j++) { |
| uint64_t num = kEpoch - 1 - j; |
| CheckCalculatePacketNumber(prev_epoch + num, last); |
| } |
| } |
| } |
| |
| TEST_P(QuicFramerTest, CalculatePacketNumberFromWireNearNextEpoch) { |
| const uint64_t cur_epoch = 2 * kEpoch; |
| const uint64_t next_epoch = 3 * kEpoch; |
| // Cases where the last number was close to the end of the range |
| for (uint64_t i = 0; i < 10; i++) { |
| QuicPacketNumber last = QuicPacketNumber(next_epoch - 1 - i); |
| |
| // Small numbers should wrap. |
| for (uint64_t j = 0; j < 10; j++) { |
| CheckCalculatePacketNumber(next_epoch + j, last); |
| } |
| |
| // but large numbers should not (even if they're out of order). |
| for (uint64_t j = 0; j < 10; j++) { |
| uint64_t num = kEpoch - 1 - j; |
| CheckCalculatePacketNumber(cur_epoch + num, last); |
| } |
| } |
| } |
| |
| TEST_P(QuicFramerTest, CalculatePacketNumberFromWireNearNextMax) { |
| const uint64_t max_number = std::numeric_limits<uint64_t>::max(); |
| const uint64_t max_epoch = max_number & ~kMask; |
| |
| // Cases where the last number was close to the end of the range |
| for (uint64_t i = 0; i < 10; i++) { |
| // Subtract 1, because the expected next packet number is 1 more than the |
| // last packet number. |
| QuicPacketNumber last = QuicPacketNumber(max_number - i - 1); |
| |
| // Small numbers should not wrap, because they have nowhere to go. |
| for (uint64_t j = 0; j < 10; j++) { |
| CheckCalculatePacketNumber(max_epoch + j, last); |
| } |
| |
| // Large numbers should not wrap either. |
| for (uint64_t j = 0; j < 10; j++) { |
| uint64_t num = kEpoch - 1 - j; |
| CheckCalculatePacketNumber(max_epoch + num, last); |
| } |
| } |
| } |
| |
| TEST_P(QuicFramerTest, EmptyPacket) { |
| char packet[] = {0x00}; |
| QuicEncryptedPacket encrypted(packet, 0, false); |
| EXPECT_FALSE(framer_.ProcessPacket(encrypted)); |
| EXPECT_EQ(QUIC_INVALID_PACKET_HEADER, framer_.error()); |
| } |
| |
| TEST_P(QuicFramerTest, LargePacket) { |
| // clang-format off |
| unsigned char packet[kMaxPacketSize + 1] = { |
| // public flags (8 byte connection_id) |
| 0x28, |
| // connection_id |
| 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, |
| // packet number |
| 0x78, 0x56, 0x34, 0x12, |
| // private flags |
| 0x00, |
| }; |
| unsigned char packet44[kMaxPacketSize + 1] = { |
| // type (short header 4 byte packet number) |
| 0x32, |
| // connection_id |
| 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, |
| // packet number |
| 0x78, 0x56, 0x34, 0x12, |
| }; |
| unsigned char packet46[kMaxPacketSize + 1] = { |
| // type (short header 4 byte packet number) |
| 0x43, |
| // connection_id |
| 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, |
| // packet number |
| 0x78, 0x56, 0x34, 0x12, |
| }; |
| // clang-format on |
| unsigned char* p = packet; |
| size_t p_size = QUIC_ARRAYSIZE(packet); |
| if (framer_.transport_version() > QUIC_VERSION_44) { |
| p = packet46; |
| p_size = QUIC_ARRAYSIZE(packet46); |
| } else if (framer_.transport_version() > QUIC_VERSION_43) { |
| p = packet44; |
| p_size = QUIC_ARRAYSIZE(packet44); |
| } |
| |
| const size_t header_size = GetPacketHeaderSize( |
| framer_.transport_version(), PACKET_8BYTE_CONNECTION_ID, |
| PACKET_0BYTE_CONNECTION_ID, !kIncludeVersion, |
| !kIncludeDiversificationNonce, PACKET_4BYTE_PACKET_NUMBER, |
| VARIABLE_LENGTH_INTEGER_LENGTH_0, 0, VARIABLE_LENGTH_INTEGER_LENGTH_0); |
| |
| memset(p + header_size, 0, kMaxPacketSize - header_size); |
| |
| QuicEncryptedPacket encrypted(AsChars(p), p_size, false); |
| EXPECT_QUIC_BUG(framer_.ProcessPacket(encrypted), "Packet too large:1"); |
| |
| ASSERT_TRUE(visitor_.header_.get()); |
| // Make sure we've parsed the packet header, so we can send an error. |
| EXPECT_EQ(FramerTestConnectionId(), |
| visitor_.header_->destination_connection_id); |
| // Make sure the correct error is propagated. |
| EXPECT_EQ(QUIC_PACKET_TOO_LARGE, framer_.error()); |
| } |
| |
| TEST_P(QuicFramerTest, PacketHeader) { |
| if (framer_.transport_version() > QUIC_VERSION_43) { |
| return; |
| } |
| |
| // clang-format off |
| PacketFragments packet = { |
| // public flags (8 byte connection_id) |
| {"Unable to read public flags.", |
| {0x28}}, |
| // connection_id |
| {"Unable to read ConnectionId.", |
| {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, |
| // packet number |
| {"Unable to read packet number.", |
| {0x12, 0x34, 0x56, 0x78}}, |
| }; |
| // clang-format on |
| |
| PacketFragments& fragments = packet; |
| |
| std::unique_ptr<QuicEncryptedPacket> encrypted( |
| AssemblePacketFromFragments(fragments)); |
| |
| EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); |
| EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error()); |
| ASSERT_TRUE(visitor_.header_.get()); |
| EXPECT_EQ(FramerTestConnectionId(), |
| visitor_.header_->destination_connection_id); |
| EXPECT_FALSE(visitor_.header_->reset_flag); |
| EXPECT_FALSE(visitor_.header_->version_flag); |
| EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number); |
| |
| CheckFramingBoundaries(fragments, QUIC_INVALID_PACKET_HEADER); |
| } |
| |
| TEST_P(QuicFramerTest, LongPacketHeader) { |
| // clang-format off |
| PacketFragments packet44 = { |
| // type (long header with packet type INITIAL) |
| {"Unable to read type.", |
| {0xFF}}, |
| // version tag |
| {"Unable to read protocol version.", |
| {QUIC_VERSION_BYTES}}, |
| // connection_id length |
| {"Unable to read ConnectionId length.", |
| {0x50}}, |
| // connection_id |
| {"Unable to read Destination ConnectionId.", |
| {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, |
| // packet number |
| {"Unable to read packet number.", |
| {0x12, 0x34, 0x56, 0x78}}, |
| }; |
| PacketFragments packet46 = { |
| // type (long header with packet type INITIAL) |
| {"Unable to read type.", |
| {0xC3}}, |
| // version tag |
| {"Unable to read protocol version.", |
| {QUIC_VERSION_BYTES}}, |
| // connection_id length |
| {"Unable to read ConnectionId length.", |
| {0x50}}, |
| // connection_id |
| {"Unable to read Destination ConnectionId.", |
| {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, |
| // packet number |
| {"Unable to read packet number.", |
| {0x12, 0x34, 0x56, 0x78}}, |
| }; |
| // clang-format on |
| |
| if (framer_.transport_version() <= QUIC_VERSION_43 || |
| QuicVersionHasLongHeaderLengths(framer_.transport_version())) { |
| return; |
| } |
| |
| PacketFragments& fragments = |
| framer_.transport_version() > QUIC_VERSION_44 ? packet46 : packet44; |
| std::unique_ptr<QuicEncryptedPacket> encrypted( |
| AssemblePacketFromFragments(fragments)); |
| |
| EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); |
| EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error()); |
| ASSERT_TRUE(visitor_.header_.get()); |
| EXPECT_EQ(FramerTestConnectionId(), |
| visitor_.header_->destination_connection_id); |
| EXPECT_FALSE(visitor_.header_->reset_flag); |
| EXPECT_TRUE(visitor_.header_->version_flag); |
| EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number); |
| |
| CheckFramingBoundaries( |
| framer_.transport_version() > QUIC_VERSION_44 ? packet46 : packet44, |
| QUIC_INVALID_PACKET_HEADER); |
| } |
| |
| TEST_P(QuicFramerTest, PacketHeaderWith0ByteConnectionId) { |
| QuicFramerPeer::SetLastSerializedConnectionId(&framer_, |
| FramerTestConnectionId()); |
| QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); |
| |
| // clang-format off |
| PacketFragments packet = { |
| // public flags (0 byte connection_id) |
| {"Unable to read public flags.", |
| {0x20}}, |
| // connection_id |
| // packet number |
| {"Unable to read packet number.", |
| {0x12, 0x34, 0x56, 0x78}}, |
| }; |
| |
| PacketFragments packet44 = { |
| // type (short header, 4 byte packet number) |
| {"Unable to read type.", |
| {0x32}}, |
| // connection_id |
| // packet number |
| {"Unable to read packet number.", |
| {0x12, 0x34, 0x56, 0x78}}, |
| }; |
| |
| PacketFragments packet46 = { |
| // type (short header, 4 byte packet number) |
| {"Unable to read type.", |
| {0x43}}, |
| // connection_id |
| // packet number |
| {"Unable to read packet number.", |
| {0x12, 0x34, 0x56, 0x78}}, |
| }; |
| // clang-format on |
| |
| PacketFragments& fragments = |
| framer_.transport_version() > QUIC_VERSION_44 |
| ? packet46 |
| : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 : packet); |
| std::unique_ptr<QuicEncryptedPacket> encrypted( |
| AssemblePacketFromFragments(fragments)); |
| EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); |
| EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error()); |
| ASSERT_TRUE(visitor_.header_.get()); |
| EXPECT_EQ(FramerTestConnectionId(), |
| visitor_.header_->destination_connection_id); |
| EXPECT_FALSE(visitor_.header_->reset_flag); |
| EXPECT_FALSE(visitor_.header_->version_flag); |
| EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number); |
| |
| CheckFramingBoundaries(fragments, QUIC_INVALID_PACKET_HEADER); |
| } |
| |
| TEST_P(QuicFramerTest, PacketHeaderWithVersionFlag) { |
| // clang-format off |
| PacketFragments packet = { |
| // public flags (0 byte connection_id) |
| {"Unable to read public flags.", |
| {0x29}}, |
| // connection_id |
| {"Unable to read ConnectionId.", |
| {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, |
| // version tag |
| {"Unable to read protocol version.", |
| {QUIC_VERSION_BYTES}}, |
| // packet number |
| {"Unable to read packet number.", |
| {0x12, 0x34, 0x56, 0x78}}, |
| }; |
| |
| PacketFragments packet44 = { |
| // type (long header with packet type ZERO_RTT_PROTECTED) |
| {"Unable to read type.", |
| {0xFC}}, |
| // version tag |
| {"Unable to read protocol version.", |
| {QUIC_VERSION_BYTES}}, |
| // connection_id length |
| {"Unable to read ConnectionId length.", |
| {0x50}}, |
| // connection_id |
| {"Unable to read Destination ConnectionId.", |
| {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, |
| // packet number |
| {"Unable to read packet number.", |
| {0x12, 0x34, 0x56, 0x78}}, |
| }; |
| |
| PacketFragments packet46 = { |
| // type (long header with packet type ZERO_RTT_PROTECTED and 4 bytes |
| // packet number) |
| {"Unable to read type.", |
| {0xD3}}, |
| // version tag |
| {"Unable to read protocol version.", |
| {QUIC_VERSION_BYTES}}, |
| // connection_id length |
| {"Unable to read ConnectionId length.", |
| {0x50}}, |
| // connection_id |
| {"Unable to read Destination ConnectionId.", |
| {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, |
| // packet number |
| {"Unable to read packet number.", |
| {0x12, 0x34, 0x56, 0x78}}, |
| }; |
| |
| PacketFragments packet99 = { |
| // type (long header with packet type ZERO_RTT_PROTECTED and 4 bytes |
| // packet number) |
| {"Unable to read type.", |
| {0xD3}}, |
| // version tag |
| {"Unable to read protocol version.", |
| {QUIC_VERSION_BYTES}}, |
| // connection_id length |
| {"Unable to read ConnectionId length.", |
| {0x50}}, |
| // connection_id |
| {"Unable to read Destination ConnectionId.", |
| {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, |
| // long header packet length |
| {"Unable to read long header payload length.", |
| {0x04}}, |
| // packet number |
| {"Long header payload length longer than packet.", |
| {0x12, 0x34, 0x56, 0x78}}, |
| }; |
| // clang-format on |
| |
| PacketFragments& fragments = |
| framer_.transport_version() == QUIC_VERSION_99 |
| ? packet99 |
| : framer_.transport_version() > QUIC_VERSION_44 |
| ? packet46 |
| : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 |
| : packet); |
| std::unique_ptr<QuicEncryptedPacket> encrypted( |
| AssemblePacketFromFragments(fragments)); |
| EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); |
| EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error()); |
| ASSERT_TRUE(visitor_.header_.get()); |
| EXPECT_EQ(FramerTestConnectionId(), |
| visitor_.header_->destination_connection_id); |
| EXPECT_FALSE(visitor_.header_->reset_flag); |
| EXPECT_TRUE(visitor_.header_->version_flag); |
| EXPECT_EQ(GetParam(), visitor_.header_->version); |
| EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number); |
| |
| CheckFramingBoundaries(fragments, QUIC_INVALID_PACKET_HEADER); |
| } |
| |
| TEST_P(QuicFramerTest, PacketHeaderWith4BytePacketNumber) { |
| QuicFramerPeer::SetLargestPacketNumber(&framer_, kPacketNumber - 2); |
| |
| // clang-format off |
| PacketFragments packet = { |
| // public flags (8 byte connection_id and 4 byte packet number) |
| {"Unable to read public flags.", |
| {0x28}}, |
| // connection_id |
| {"Unable to read ConnectionId.", |
| {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, |
| // packet number |
| {"Unable to read packet number.", |
| {0x12, 0x34, 0x56, 0x78}}, |
| }; |
| |
| PacketFragments packet44 = { |
| // type (short header, 4 byte packet number) |
| {"Unable to read type.", |
| {0x32}}, |
| // connection_id |
| {"Unable to read Destination ConnectionId.", |
| {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, |
| // packet number |
| {"Unable to read packet number.", |
| {0x12, 0x34, 0x56, 0x78}}, |
| }; |
| |
| PacketFragments packet46 = { |
| // type (short header, 4 byte packet number) |
| {"Unable to read type.", |
| {0x43}}, |
| // connection_id |
| {"Unable to read Destination ConnectionId.", |
| {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, |
| // packet number |
| {"Unable to read packet number.", |
| {0x12, 0x34, 0x56, 0x78}}, |
| }; |
| // clang-format on |
| |
| PacketFragments& fragments = |
| framer_.transport_version() > QUIC_VERSION_44 |
| ? packet46 |
| : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 : packet); |
| std::unique_ptr<QuicEncryptedPacket> encrypted( |
| AssemblePacketFromFragments(fragments)); |
| EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); |
| EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error()); |
| ASSERT_TRUE(visitor_.header_.get()); |
| EXPECT_EQ(FramerTestConnectionId(), |
| visitor_.header_->destination_connection_id); |
| EXPECT_FALSE(visitor_.header_->reset_flag); |
| EXPECT_FALSE(visitor_.header_->version_flag); |
| EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number); |
| |
| CheckFramingBoundaries(fragments, QUIC_INVALID_PACKET_HEADER); |
| } |
| |
| TEST_P(QuicFramerTest, PacketHeaderWith2BytePacketNumber) { |
| QuicFramerPeer::SetLargestPacketNumber(&framer_, kPacketNumber - 2); |
| |
| // clang-format off |
| PacketFragments packet = { |
| // public flags (8 byte connection_id and 2 byte packet number) |
| {"Unable to read public flags.", |
| {0x18}}, |
| // connection_id |
| {"Unable to read ConnectionId.", |
| {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, |
| // packet number |
| {"Unable to read packet number.", |
| {0x56, 0x78}}, |
| }; |
| |
| PacketFragments packet44 = { |
| // type (short header, 2 byte packet number) |
| {"Unable to read type.", |
| {0x31}}, |
| // connection_id |
| {"Unable to read Destination ConnectionId.", |
| {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, |
| // packet number |
| {"Unable to read packet number.", |
| {0x56, 0x78}}, |
| }; |
| |
| PacketFragments packet46 = { |
| // type (short header, 2 byte packet number) |
| {"Unable to read type.", |
| {0x41}}, |
| // connection_id |
| {"Unable to read Destination ConnectionId.", |
| {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, |
| // packet number |
| {"Unable to read packet number.", |
| {0x56, 0x78}}, |
| }; |
| // clang-format on |
| |
| PacketFragments& fragments = |
| framer_.transport_version() > QUIC_VERSION_44 |
| ? packet46 |
| : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 : packet); |
| std::unique_ptr<QuicEncryptedPacket> encrypted( |
| AssemblePacketFromFragments(fragments)); |
| EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); |
| EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error()); |
| ASSERT_TRUE(visitor_.header_.get()); |
| EXPECT_EQ(FramerTestConnectionId(), |
| visitor_.header_->destination_connection_id); |
| EXPECT_FALSE(visitor_.header_->reset_flag); |
| EXPECT_FALSE(visitor_.header_->version_flag); |
| EXPECT_EQ(PACKET_2BYTE_PACKET_NUMBER, visitor_.header_->packet_number_length); |
| EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number); |
| |
| CheckFramingBoundaries(fragments, QUIC_INVALID_PACKET_HEADER); |
| } |
| |
| TEST_P(QuicFramerTest, PacketHeaderWith1BytePacketNumber) { |
| QuicFramerPeer::SetLargestPacketNumber(&framer_, kPacketNumber - 2); |
| |
| // clang-format off |
| PacketFragments packet = { |
| // public flags (8 byte connection_id and 1 byte packet number) |
| {"Unable to read public flags.", |
| {0x08}}, |
| // connection_id |
| {"Unable to read ConnectionId.", |
| {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, |
| // packet number |
| {"Unable to read packet number.", |
| {0x78}}, |
| }; |
| |
| PacketFragments packet44 = { |
| // type (8 byte connection_id and 1 byte packet number) |
| {"Unable to read type.", |
| {0x30}}, |
| // connection_id |
| {"Unable to read Destination ConnectionId.", |
| {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, |
| // packet number |
| {"Unable to read packet number.", |
| {0x78}}, |
| }; |
| |
| PacketFragments packet46 = { |
| // type (8 byte connection_id and 1 byte packet number) |
| {"Unable to read type.", |
| {0x40}}, |
| // connection_id |
| {"Unable to read Destination ConnectionId.", |
| {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, |
| // packet number |
| {"Unable to read packet number.", |
| {0x78}}, |
| }; |
| |
| // clang-format on |
| |
| PacketFragments& fragments = |
| framer_.transport_version() > QUIC_VERSION_44 |
| ? packet46 |
| : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 : packet); |
| std::unique_ptr<QuicEncryptedPacket> encrypted( |
| AssemblePacketFromFragments(fragments)); |
| EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); |
| EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error()); |
| ASSERT_TRUE(visitor_.header_.get()); |
| EXPECT_EQ(FramerTestConnectionId(), |
| visitor_.header_->destination_connection_id); |
| EXPECT_FALSE(visitor_.header_->reset_flag); |
| EXPECT_FALSE(visitor_.header_->version_flag); |
| EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER, visitor_.header_->packet_number_length); |
| EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number); |
| |
| CheckFramingBoundaries(fragments, QUIC_INVALID_PACKET_HEADER); |
| } |
| |
| TEST_P(QuicFramerTest, PacketNumberDecreasesThenIncreases) { |
| // Test the case when a packet is received from the past and future packet |
| // numbers are still calculated relative to the largest received packet. |
| QuicPacketHeader header; |
| header.destination_connection_id = FramerTestConnectionId(); |
| header.reset_flag = false; |
| header.version_flag = false; |
| header.packet_number = kPacketNumber - 2; |
| |
| QuicFrames frames = {QuicFrame(QuicPaddingFrame())}; |
| QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); |
| std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); |
| ASSERT_TRUE(data != nullptr); |
| |
| QuicEncryptedPacket encrypted(data->data(), data->length(), false); |
| QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_SERVER); |
| EXPECT_TRUE(framer_.ProcessPacket(encrypted)); |
| ASSERT_TRUE(visitor_.header_.get()); |
| EXPECT_EQ(FramerTestConnectionId(), |
| visitor_.header_->destination_connection_id); |
| EXPECT_EQ(PACKET_4BYTE_PACKET_NUMBER, visitor_.header_->packet_number_length); |
| EXPECT_EQ(kPacketNumber - 2, visitor_.header_->packet_number); |
| |
| // Receive a 1 byte packet number. |
| header.packet_number = kPacketNumber; |
| header.packet_number_length = PACKET_1BYTE_PACKET_NUMBER; |
| QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); |
| data = BuildDataPacket(header, frames); |
| QuicEncryptedPacket encrypted1(data->data(), data->length(), false); |
| QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_SERVER); |
| EXPECT_TRUE(framer_.ProcessPacket(encrypted1)); |
| ASSERT_TRUE(visitor_.header_.get()); |
| EXPECT_EQ(FramerTestConnectionId(), |
| visitor_.header_->destination_connection_id); |
| EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER, visitor_.header_->packet_number_length); |
| EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number); |
| |
| // Process a 2 byte packet number 256 packets ago. |
| header.packet_number = kPacketNumber - 256; |
| header.packet_number_length = PACKET_2BYTE_PACKET_NUMBER; |
| QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); |
| data = BuildDataPacket(header, frames); |
| QuicEncryptedPacket encrypted2(data->data(), data->length(), false); |
| QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_SERVER); |
| EXPECT_TRUE(framer_.ProcessPacket(encrypted2)); |
| ASSERT_TRUE(visitor_.header_.get()); |
| EXPECT_EQ(FramerTestConnectionId(), |
| visitor_.header_->destination_connection_id); |
| EXPECT_EQ(PACKET_2BYTE_PACKET_NUMBER, visitor_.header_->packet_number_length); |
| EXPECT_EQ(kPacketNumber - 256, visitor_.header_->packet_number); |
| |
| // Process another 1 byte packet number and ensure it works. |
| header.packet_number = kPacketNumber - 1; |
| header.packet_number_length = PACKET_1BYTE_PACKET_NUMBER; |
| QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); |
| data = BuildDataPacket(header, frames); |
| QuicEncryptedPacket encrypted3(data->data(), data->length(), false); |
| QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_SERVER); |
| EXPECT_TRUE(framer_.ProcessPacket(encrypted3)); |
| ASSERT_TRUE(visitor_.header_.get()); |
| EXPECT_EQ(FramerTestConnectionId(), |
| visitor_.header_->destination_connection_id); |
| EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER, visitor_.header_->packet_number_length); |
| EXPECT_EQ(kPacketNumber - 1, visitor_.header_->packet_number); |
| } |
| |
| TEST_P(QuicFramerTest, PacketWithDiversificationNonce) { |
| // clang-format off |
| unsigned char packet[] = { |
| // public flags: includes nonce flag |
| 0x2C, |
| // connection_id |
| 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, |
| // nonce |
| 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, |
| 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, |
| 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, |
| 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, |
| // packet number |
| 0x12, 0x34, 0x56, 0x78, |
| |
| // frame type (padding) |
| 0x00, |
| 0x00, 0x00, 0x00, 0x00 |
| }; |
| |
| unsigned char packet44[] = { |
| // type: Long header with packet type ZERO_RTT_PROTECTED |
| 0xFC, |
| // version tag |
| QUIC_VERSION_BYTES, |
| // connection_id length |
| 0x05, |
| // connection_id |
| 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, |
| // packet number |
| 0x12, 0x34, 0x56, 0x78, |
| // nonce |
| 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, |
| 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, |
| 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, |
| 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, |
| |
| // frame type (padding) |
| 0x00, |
| 0x00, 0x00, 0x00, 0x00 |
| }; |
| |
| unsigned char packet46[] = { |
| // type: Long header with packet type ZERO_RTT_PROTECTED and 1 byte packet |
| // number. |
| 0xD0, |
| // version tag |
| QUIC_VERSION_BYTES, |
| // connection_id length |
| 0x05, |
| // connection_id |
| 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, |
| // packet number |
| 0x78, |
| // nonce |
| 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, |
| 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, |
| 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, |
| 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, |
| |
| // frame type (padding) |
| 0x00, |
| 0x00, 0x00, 0x00, 0x00 |
| }; |
| |
| unsigned char packet99[] = { |
| // type: Long header with packet type ZERO_RTT_PROTECTED and 1 byte packet |
| // number. |
| 0xD0, |
| // version tag |
| QUIC_VERSION_BYTES, |
| // connection_id length |
| 0x05, |
| // connection_id |
| 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, |
| // long header packet length |
| 0x26, |
| // packet number |
| 0x78, |
| // nonce |
| 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, |
| 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, |
| 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, |
| 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, |
| |
| // frame type (padding) |
| 0x00, |
| 0x00, 0x00, 0x00, 0x00 |
| }; |
| // clang-format on |
| |
| if (framer_.version().handshake_protocol != PROTOCOL_QUIC_CRYPTO) { |
| return; |
| } |
| |
| unsigned char* p = packet; |
| size_t p_size = QUIC_ARRAYSIZE(packet); |
| if (framer_.transport_version() == QUIC_VERSION_99) { |
| p = packet99; |
| p_size = QUIC_ARRAYSIZE(packet99); |
| } else if (framer_.transport_version() > QUIC_VERSION_44) { |
| p = packet46; |
| p_size = QUIC_ARRAYSIZE(packet46); |
| } else if (framer_.transport_version() > QUIC_VERSION_43) { |
| p = packet44; |
| p_size = QUIC_ARRAYSIZE(packet44); |
| } |
| |
| QuicEncryptedPacket encrypted(AsChars(p), p_size, false); |
| QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); |
| EXPECT_TRUE(framer_.ProcessPacket(encrypted)); |
| ASSERT_TRUE(visitor_.header_->nonce != nullptr); |
| for (char i = 0; i < 32; ++i) { |
| EXPECT_EQ(i, (*visitor_.header_->nonce)[static_cast<size_t>(i)]); |
| } |
| EXPECT_EQ(1u, visitor_.padding_frames_.size()); |
| EXPECT_EQ(5, visitor_.padding_frames_[0]->num_padding_bytes); |
| } |
| |
| TEST_P(QuicFramerTest, LargePublicFlagWithMismatchedVersions) { |
| // clang-format off |
| unsigned char packet[] = { |
| // public flags (8 byte connection_id, version flag and an unknown flag) |
| 0x29, |
| // connection_id |
| 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, |
| // version tag |
| 'Q', '0', '0', '0', |
| // packet number |
| 0x12, 0x34, 0x56, 0x78, |
| |
| // frame type (padding frame) |
| 0x00, |
| 0x00, 0x00, 0x00, 0x00 |
| }; |
| |
| unsigned char packet44[] = { |
| // type (long header with packet type ZERO_RTT_PROTECTED) |
| 0xFC, |
| // version tag |
| 'Q', '0', '0', '0', |
| // connection_id length |
| 0x50, |
| // connection_id |
| 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, |
| // packet number |
| 0x12, 0x34, 0x56, 0x78, |
| |
| // frame type (padding frame) |
| 0x00, |
| 0x00, 0x00, 0x00, 0x00 |
| }; |
| // clang-format on |
| |
| QuicEncryptedPacket encrypted( |
| AsChars(framer_.transport_version() > QUIC_VERSION_43 ? packet44 |
| : packet), |
| framer_.transport_version() > QUIC_VERSION_43 ? QUIC_ARRAYSIZE(packet44) |
| : QUIC_ARRAYSIZE(packet), |
| false); |
| EXPECT_TRUE(framer_.ProcessPacket(encrypted)); |
| EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); |
| ASSERT_TRUE(visitor_.header_.get()); |
| EXPECT_EQ(0, visitor_.frame_count_); |
| EXPECT_EQ(1, visitor_.version_mismatch_); |
| EXPECT_EQ(1u, visitor_.padding_frames_.size()); |
| EXPECT_EQ(5, visitor_.padding_frames_[0]->num_padding_bytes); |
| } |
| |
| TEST_P(QuicFramerTest, PaddingFrame) { |
| // clang-format off |
| unsigned char packet[] = { |
| // public flags (8 byte connection_id) |
| 0x28, |
| // connection_id |
| 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, |
| // packet number |
| 0x12, 0x34, 0x56, 0x78, |
| |
| // paddings |
| 0x00, 0x00, |
| // frame type (stream frame with fin) |
| 0xFF, |
| // stream id |
| 0x01, 0x02, 0x03, 0x04, |
| // offset |
| 0x3A, 0x98, 0xFE, 0xDC, |
| 0x32, 0x10, 0x76, 0x54, |
| // data length |
| 0x00, 0x0c, |
| // data |
| 'h', 'e', 'l', 'l', |
| 'o', ' ', 'w', 'o', |
| 'r', 'l', 'd', '!', |
| // paddings |
| 0x00, 0x00, |
| }; |
| |
| unsigned char packet44[] = { |
| // type (short header, 4 byte packet number) |
| 0x32, |
| // connection_id |
| 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, |
| // packet number |
| 0x12, 0x34, 0x56, 0x78, |
| |
| // paddings |
| 0x00, 0x00, |
| // frame type (stream frame with fin) |
| 0xFF, |
| // stream id |
| 0x01, 0x02, 0x03, 0x04, |
| // offset |
| 0x3A, 0x98, 0xFE, 0xDC, |
| 0x32, 0x10, 0x76, 0x54, |
| // data length |
| 0x00, 0x0c, |
| // data |
| 'h', 'e', 'l', 'l', |
| 'o', ' ', 'w', 'o', |
| 'r', 'l', 'd', '!', |
| // paddings |
| 0x00, 0x00, |
| }; |
| |
| unsigned char packet46[] = { |
| // type (short header, 4 byte packet number) |
| 0x43, |
| // connection_id |
| 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, |
| // packet number |
| 0x12, 0x34, 0x56, 0x78, |
| |
| // paddings |
| 0x00, 0x00, |
| // frame type (stream frame with fin) |
| 0xFF, |
| // stream id |
| 0x01, 0x02, 0x03, 0x04, |
| // offset |
| 0x3A, 0x98, 0xFE, 0xDC, |
| 0x32, 0x10, 0x76, 0x54, |
| // data length |
| 0x00, 0x0c, |
| // data |
| 'h', 'e', 'l', 'l', |
| 'o', ' ', 'w', 'o', |
| 'r', 'l', 'd', '!', |
| // paddings |
| 0x00, 0x00, |
| }; |
| |
| unsigned char packet99[] = { |
| // type (short header, 4 byte packet number) |
| 0x43, |
| // connection_id |
| 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, |
| // packet number |
| 0x12, 0x34, 0x56, 0x78, |
| |
| // paddings |
| 0x00, 0x00, |
| // frame type - IETF_STREAM with FIN, LEN, and OFFSET bits set. |
| 0x08 | 0x01 | 0x02 | 0x04, |
| |
| // stream id |
| kVarInt62FourBytes + 0x01, 0x02, 0x03, 0x04, |
| // offset |
| kVarInt62EightBytes + 0x3A, 0x98, 0xFE, 0xDC, |
| 0x32, 0x10, 0x76, 0x54, |
| // data length |
| kVarInt62OneByte + 0x0c, |
| // data |
| 'h', 'e', 'l', 'l', |
| 'o', ' ', 'w', 'o', |
| 'r', 'l', 'd', '!', |
| // paddings |
| 0x00, 0x00, |
| }; |
| // clang-format on |
| |
| unsigned char* p = packet; |
| size_t p_size = QUIC_ARRAYSIZE(packet); |
| if (framer_.transport_version() == QUIC_VERSION_99) { |
| p = packet99; |
| p_size = QUIC_ARRAYSIZE(packet99); |
| } else if (framer_.transport_version() > QUIC_VERSION_44) { |
| p = packet46; |
| p_size = QUIC_ARRAYSIZE(packet46); |
| } else if (framer_.transport_version() > QUIC_VERSION_43) { |
| p = packet44; |
| p_size = QUIC_ARRAYSIZE(packet44); |
| } |
| |
| QuicEncryptedPacket encrypted(AsChars(p), p_size, false); |
| EXPECT_TRUE(framer_.ProcessPacket(encrypted)); |
| EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); |
| ASSERT_TRUE(visitor_.header_.get()); |
| EXPECT_TRUE(CheckDecryption( |
| encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, |
| PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); |
| |
| ASSERT_EQ(1u, visitor_.stream_frames_.size()); |
| EXPECT_EQ(0u, visitor_.ack_frames_.size()); |
| EXPECT_EQ(2u, visitor_.padding_frames_.size()); |
| EXPECT_EQ(2, visitor_.padding_frames_[0]->num_padding_bytes); |
| EXPECT_EQ(2, visitor_.padding_frames_[1]->num_padding_bytes); |
| EXPECT_EQ(kStreamId, visitor_.stream_frames_[0]->stream_id); |
| EXPECT_TRUE(visitor_.stream_frames_[0]->fin); |
| EXPECT_EQ(kStreamOffset, visitor_.stream_frames_[0]->offset); |
| CheckStreamFrameData("hello world!", visitor_.stream_frames_[0].get()); |
| } |
| |
| TEST_P(QuicFramerTest, StreamFrame) { |
| // clang-format off |
| PacketFragments packet = { |
| // public flags (8 byte connection_id) |
| {"", |
| {0x28}}, |
| // connection_id |
| {"", |
| {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, |
| // packet number |
| {"", |
| {0x12, 0x34, 0x56, 0x78}}, |
| // frame type (stream frame with fin) |
| {"", |
| {0xFF}}, |
| // stream id |
| {"Unable to read stream_id.", |
| {0x01, 0x02, 0x03, 0x04}}, |
| // offset |
| {"Unable to read offset.", |
| {0x3A, 0x98, 0xFE, 0xDC, |
| 0x32, 0x10, 0x76, 0x54}}, |
| {"Unable to read frame data.", |
| { |
| // data length |
| 0x00, 0x0c, |
| // data |
| 'h', 'e', 'l', 'l', |
| 'o', ' ', 'w', 'o', |
| 'r', 'l', 'd', '!'}}, |
| }; |
| |
| PacketFragments packet44 = { |
| // type (short header, 4 byte packet number) |
| {"", |
| {0x32}}, |
| // connection_id |
| {"", |
| {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, |
| // packet number |
| {"", |
| {0x12, 0x34, 0x56, 0x78}}, |
| // frame type (stream frame with fin) |
| {"", |
| {0xFF}}, |
| // stream id |
| {"Unable to read stream_id.", |
| {0x01, 0x02, 0x03, 0x04}}, |
| // offset |
| {"Unable to read offset.", |
| {0x3A, 0x98, 0xFE, 0xDC, |
| 0x32, 0x10, 0x76, 0x54}}, |
| {"Unable to read frame data.", |
| { |
| // data length |
| 0x00, 0x0c, |
| // data |
| 'h', 'e', 'l', 'l', |
| 'o', ' ', 'w', 'o', |
| 'r', 'l', 'd', '!'}}, |
| }; |
| |
| PacketFragments packet46 = { |
| // type (short header, 4 byte packet number) |
| {"", |
| {0x43}}, |
| // connection_id |
| {"", |
| {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, |
| // packet number |
| {"", |
| {0x12, 0x34, 0x56, 0x78}}, |
| // frame type (stream frame with fin) |
| {"", |
| {0xFF}}, |
| // stream id |
| {"Unable to read stream_id.", |
| {0x01, 0x02, 0x03, 0x04}}, |
| // offset |
| {"Unable to read offset.", |
| {0x3A, 0x98, 0xFE, 0xDC, |
| 0x32, 0x10, 0x76, 0x54}}, |
| {"Unable to read frame data.", |
| { |
| // data length |
| 0x00, 0x0c, |
| // data |
| 'h', 'e', 'l', 'l', |
| 'o', ' ', 'w', 'o', |
| 'r', 'l', 'd', '!'}}, |
| }; |
| |
| PacketFragments packet99 = { |
| // type (short header, 4 byte packet number) |
| {"", |
| {0x43}}, |
| // connection_id |
| {"", |
| {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, |
| // packet number |
| {"", |
| {0x12, 0x34, 0x56, 0x78}}, |
| // frame type - IETF_STREAM with FIN, LEN, and OFFSET bits set. |
| {"", |
| { 0x08 | 0x01 | 0x02 | 0x04 }}, |
| // stream id |
| {"Unable to read stream_id.", |
| {kVarInt62FourBytes + 0x01, 0x02, 0x03, 0x04}}, |
| // offset |
| {"Unable to read stream data offset.", |
| {kVarInt62EightBytes + 0x3A, 0x98, 0xFE, 0xDC, |
| 0x32, 0x10, 0x76, 0x54}}, |
| // data length |
| {"Unable to read stream data length.", |
| {kVarInt62OneByte + 0x0c}}, |
| // data |
| {"Unable to read frame data.", |
| { 'h', 'e', 'l', 'l', |
| 'o', ' ', 'w', 'o', |
| 'r', 'l', 'd', '!'}}, |
| }; |
| // clang-format on |
| |
| PacketFragments& fragments = |
| framer_.transport_version() == QUIC_VERSION_99 |
| ? packet99 |
| : (framer_.transport_version() > QUIC_VERSION_44 |
| ? packet46 |
| : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 |
| : packet)); |
| std::unique_ptr<QuicEncryptedPacket> encrypted( |
| AssemblePacketFromFragments(fragments)); |
| EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); |
| |
| EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); |
| ASSERT_TRUE(visitor_.header_.get()); |
| EXPECT_TRUE(CheckDecryption( |
| *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, |
| PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); |
| |
| ASSERT_EQ(1u, visitor_.stream_frames_.size()); |
| EXPECT_EQ(0u, visitor_.ack_frames_.size()); |
| EXPECT_EQ(kStreamId, visitor_.stream_frames_[0]->stream_id); |
| EXPECT_TRUE(visitor_.stream_frames_[0]->fin); |
| EXPECT_EQ(kStreamOffset, visitor_.stream_frames_[0]->offset); |
| CheckStreamFrameData("hello world!", visitor_.stream_frames_[0].get()); |
| |
| CheckFramingBoundaries(fragments, QUIC_INVALID_STREAM_DATA); |
| } |
| |
| // Test an empty (no data) stream frame. |
| TEST_P(QuicFramerTest, EmptyStreamFrame) { |
| // Only the IETF QUIC spec explicitly says that empty |
| // stream frames are supported. |
| if (framer_.transport_version() != QUIC_VERSION_99) { |
| return; |
| } |
| // clang-format off |
| PacketFragments packet = { |
| // type (short header, 4 byte packet number) |
| {"", |
| {0x43}}, |
| // connection_id |
| {"", |
| {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, |
| // packet number |
| {"", |
| {0x12, 0x34, 0x56, 0x78}}, |
| // frame type - IETF_STREAM with FIN, LEN, and OFFSET bits set. |
| {"", |
| { 0x08 | 0x01 | 0x02 | 0x04 }}, |
| // stream id |
| {"Unable to read stream_id.", |
| {kVarInt62FourBytes + 0x01, 0x02, 0x03, 0x04}}, |
| // offset |
| {"Unable to read stream data offset.", |
| {kVarInt62EightBytes + 0x3A, 0x98, 0xFE, 0xDC, |
| 0x32, 0x10, 0x76, 0x54}}, |
| // data length |
| {"Unable to read stream data length.", |
| {kVarInt62OneByte + 0x00}}, |
| }; |
| // clang-format on |
| |
| std::unique_ptr<QuicEncryptedPacket> encrypted( |
| AssemblePacketFromFragments(packet)); |
| EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); |
| |
| EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); |
| ASSERT_TRUE(visitor_.header_.get()); |
| EXPECT_TRUE(CheckDecryption( |
| *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, |
| PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); |
| |
| ASSERT_EQ(1u, visitor_.stream_frames_.size()); |
| EXPECT_EQ(0u, visitor_.ack_frames_.size()); |
| EXPECT_EQ(kStreamId, visitor_.stream_frames_[0]->stream_id); |
| EXPECT_TRUE(visitor_.stream_frames_[0]->fin); |
| EXPECT_EQ(kStreamOffset, visitor_.stream_frames_[0]->offset); |
| EXPECT_EQ(visitor_.stream_frames_[0].get()->data_length, 0u); |
| |
| CheckFramingBoundaries(packet, QUIC_INVALID_STREAM_DATA); |
| } |
| |
| TEST_P(QuicFramerTest, MissingDiversificationNonce) { |
| QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); |
| framer_.SetDecrypter(ENCRYPTION_NONE, |
| QuicMakeUnique<NullDecrypter>(Perspective::IS_CLIENT)); |
| decrypter_ = new test::TestDecrypter(); |
| framer_.SetAlternativeDecrypter( |
| ENCRYPTION_ZERO_RTT, std::unique_ptr<QuicDecrypter>(decrypter_), false); |
| |
| // clang-format off |
| unsigned char packet[] = { |
| // public flags (8 byte connection_id) |
| 0x28, |
| // connection_id |
| 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, |
| // packet number |
| 0x12, 0x34, 0x56, 0x78, |
| |
| // frame type (stream frame with fin) |
| 0xFF, |
| // stream id |
| 0x01, 0x02, 0x03, 0x04, |
| // offset |
| 0x3A, 0x98, 0xFE, 0xDC, |
| 0x32, 0x10, 0x76, 0x54, |
| // data length |
| 0x00, 0x0c, |
| // data |
| 'h', 'e', 'l', 'l', |
| 'o', ' ', 'w', 'o', |
| 'r', 'l', 'd', '!', |
| }; |
| |
| unsigned char packet44[] = { |
| // type (long header with packet type ZERO_RTT_PROTECTED) |
| 0xFC, |
| // version tag |
| QUIC_VERSION_BYTES, |
| // connection_id length |
| 0x50, |
| // connection_id |
| 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, |
| // packet number |
| 0x12, 0x34, 0x56, 0x78, |
| |
| // frame type - STREAM with LEN, FIN, and OFFSET bits set. |
| 0x10 | 0x01 | 0x02 | 0x04, |
| // stream id |
| 0x01, 0x02, 0x03, 0x04, |
| // offset |
| 0x3A, 0x98, 0xFE, 0xDC, |
| 0x32, 0x10, 0x76, 0x54, |
| // data length |
| 0x00, 0x0c, |
| // data |
| 'h', 'e', 'l', 'l', |
| 'o', ' ', 'w', 'o', |
| 'r', 'l', 'd', '!', |
| }; |
| // clang-format on |
| |
| unsigned char* p = packet; |
| if (framer_.transport_version() > QUIC_VERSION_43) { |
| p = packet44; |
| } |
| QuicEncryptedPacket encrypted(AsChars(p), |
| framer_.transport_version() > QUIC_VERSION_43 |
| ? QUIC_ARRAYSIZE(packet44) |
| : QUIC_ARRAYSIZE(packet), |
| false); |
| EXPECT_FALSE(framer_.ProcessPacket(encrypted)); |
| if (framer_.transport_version() > QUIC_VERSION_43) { |
| // Cannot read diversification nonce. |
| EXPECT_EQ(QUIC_INVALID_PACKET_HEADER, framer_.error()); |
| } else { |
| EXPECT_EQ(QUIC_DECRYPTION_FAILURE, framer_.error()); |
| } |
| } |
| |
| TEST_P(QuicFramerTest, StreamFrame3ByteStreamId) { |
| if (framer_.transport_version() > QUIC_VERSION_43) { |
| // This test is nonsensical for IETF Quic. |
| return; |
| } |
| // clang-format off |
| PacketFragments packet = { |
| // public flags (8 byte connection_id) |
| {"", |
| {0x28}}, |
| // connection_id |
| {"", |
| {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, |
| // packet number |
| {"", |
| {0x12, 0x34, 0x56, 0x78}}, |
| // frame type (stream frame with fin) |
| {"", |
| {0xFE}}, |
| // stream id |
| {"Unable to read stream_id.", |
| {0x02, 0x03, 0x04}}, |
| // offset |
| {"Unable to read offset.", |
| {0x3A, 0x98, 0xFE, 0xDC, |
| 0x32, 0x10, 0x76, 0x54}}, |
| {"Unable to read frame data.", |
| { |
| // data length |
| 0x00, 0x0c, |
| // data |
| 'h', 'e', 'l', 'l', |
| 'o', ' ', 'w', 'o', |
| 'r', 'l', 'd', '!'}}, |
| }; |
| // clang-format on |
| |
| PacketFragments& fragments = packet; |
| std::unique_ptr<QuicEncryptedPacket> encrypted( |
| AssemblePacketFromFragments(fragments)); |
| EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); |
| |
| EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); |
| ASSERT_TRUE(visitor_.header_.get()); |
| EXPECT_TRUE(CheckDecryption( |
| *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, |
| PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); |
| |
| ASSERT_EQ(1u, visitor_.stream_frames_.size()); |
| EXPECT_EQ(0u, visitor_.ack_frames_.size()); |
| // Stream ID should be the last 3 bytes of kStreamId. |
| EXPECT_EQ(0x00FFFFFF & kStreamId, visitor_.stream_frames_[0]->stream_id); |
| EXPECT_TRUE(visitor_.stream_frames_[0]->fin); |
| EXPECT_EQ(kStreamOffset, visitor_.stream_frames_[0]->offset); |
| CheckStreamFrameData("hello world!", visitor_.stream_frames_[0].get()); |
| |
| CheckFramingBoundaries(fragments, QUIC_INVALID_STREAM_DATA); |
| } |
| |
| TEST_P(QuicFramerTest, StreamFrame2ByteStreamId) { |
| // clang-format off |
| PacketFragments packet = { |
| // public flags (8 byte connection_id) |
| {"", |
| {0x28}}, |
| // connection_id |
| {"", |
| {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, |
| // packet number |
| {"", |
| {0x12, 0x34, 0x56, 0x78}}, |
| // frame type (stream frame with fin) |
| {"", |
| {0xFD}}, |
| // stream id |
| {"Unable to read stream_id.", |
| {0x03, 0x04}}, |
| // offset |
| {"Unable to read offset.", |
| {0x3A, 0x98, 0xFE, 0xDC, |
| 0x32, 0x10, 0x76, 0x54}}, |
| {"Unable to read frame data.", |
| { |
| // data length |
| 0x00, 0x0c, |
| // data |
| 'h', 'e', 'l', 'l', |
| 'o', ' ', 'w', 'o', |
| 'r', 'l', 'd', '!'}}, |
| }; |
| |
| PacketFragments packet44 = { |
| // type (short header, 4 byte packet number) |
| {"", |
| {0x32}}, |
| // connection_id |
| {"", |
| {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, |
| // packet number |
| {"", |
| {0x12, 0x34, 0x56, 0x78}}, |
| // frame type (stream frame with fin) |
| {"", |
| {0xFD}}, |
| // stream id |
| {"Unable to read stream_id.", |
| {0x03, 0x04}}, |
| // offset |
| {"Unable to read offset.", |
| {0x3A, 0x98, 0xFE, 0xDC, |
| 0x32, 0x10, 0x76, 0x54}}, |
| {"Unable to read frame data.", |
| { |
| // data length |
| 0x00, 0x0c, |
| // data |
| 'h', 'e', 'l', 'l', |
| 'o', ' ', 'w', 'o', |
| 'r', 'l', 'd', '!'}}, |
| }; |
| |
| PacketFragments packet46 = { |
| // type (short header, 4 byte packet number) |
| {"", |
| {0x43}}, |
| // connection_id |
| {"", |
| {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, |
| // packet number |
| {"", |
| {0x12, 0x34, 0x56, 0x78}}, |
| // frame type (stream frame with fin) |
| {"", |
| {0xFD}}, |
| // stream id |
| {"Unable to read stream_id.", |
| {0x03, 0x04}}, |
| // offset |
| {"Unable to read offset.", |
| {0x3A, 0x98, 0xFE, 0xDC, |
| 0x32, 0x10, 0x76, 0x54}}, |
| {"Unable to read frame data.", |
| { |
| // data length |
| 0x00, 0x0c, |
| // data |
| 'h', 'e', 'l', 'l', |
| 'o', ' ', 'w', 'o', |
| 'r', 'l', 'd', '!'}}, |
| }; |
| |
| PacketFragments packet99 = { |
| // type (short header, 4 byte packet number) |
| {"", |
| {0x43}}, |
| // connection_id |
| {"", |
| {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, |
| // packet number |
| {"", |
| {0x12, 0x34, 0x56, 0x78}}, |
| // frame type (IETF_STREAM frame with LEN, FIN, and OFFSET bits set) |
| {"", |
| {0x08 | 0x01 | 0x02 | 0x04}}, |
| // stream id |
| {"Unable to read stream_id.", |
| {kVarInt62TwoBytes + 0x03, 0x04}}, |
| // offset |
| {"Unable to read stream data offset.", |
| {kVarInt62EightBytes + 0x3A, 0x98, 0xFE, 0xDC, |
| 0x32, 0x10, 0x76, 0x54}}, |
| // data length |
| {"Unable to read stream data length.", |
| {kVarInt62OneByte + 0x0c}}, |
| // data |
| {"Unable to read frame data.", |
| { 'h', 'e', 'l', 'l', |
| 'o', ' ', 'w', 'o', |
| 'r', 'l', 'd', '!'}}, |
| }; |
| // clang-format on |
| |
| PacketFragments& fragments = |
| framer_.transport_version() == QUIC_VERSION_99 |
| ? packet99 |
| : (framer_.transport_version() > QUIC_VERSION_44 |
| ? packet46 |
| : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 |
| : packet)); |
| std::unique_ptr<QuicEncryptedPacket> encrypted( |
| AssemblePacketFromFragments(fragments)); |
| EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); |
| |
| EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); |
| ASSERT_TRUE(visitor_.header_.get()); |
| EXPECT_TRUE(CheckDecryption( |
| *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, |
| PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); |
| |
| ASSERT_EQ(1u, visitor_.stream_frames_.size()); |
| EXPECT_EQ(0u, visitor_.ack_frames_.size()); |
| // Stream ID should be the last 2 bytes of kStreamId. |
| EXPECT_EQ(0x0000FFFF & kStreamId, visitor_.stream_frames_[0]->stream_id); |
| EXPECT_TRUE(visitor_.stream_frames_[0]->fin); |
| EXPECT_EQ(kStreamOffset, visitor_.stream_frames_[0]->offset); |
| CheckStreamFrameData("hello world!", visitor_.stream_frames_[0].get()); |
| |
| CheckFramingBoundaries(fragments, QUIC_INVALID_STREAM_DATA); |
| } |
| |
| TEST_P(QuicFramerTest, StreamFrame1ByteStreamId) { |
| // clang-format off |
| PacketFragments packet = { |
| // public flags (8 byte connection_id) |
| {"", |
| {0x28}}, |
| // connection_id |
| {"", |
| {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, |
| // packet number |
| {"", |
| {0x12, 0x34, 0x56, 0x78}}, |
| // frame type (stream frame with fin) |
| {"", |
| {0xFC}}, |
| // stream id |
| {"Unable to read stream_id.", |
| {0x04}}, |
| // offset |
| {"Unable to read offset.", |
| {0x3A, 0x98, 0xFE, 0xDC, |
| 0x32, 0x10, 0x76, 0x54}}, |
| {"Unable to read frame data.", |
| { |
| // data length |
| 0x00, 0x0c, |
| // data |
| 'h', 'e', 'l', 'l', |
| 'o', ' ', 'w', 'o', |
| 'r', 'l', 'd', '!'}}, |
| }; |
| |
| PacketFragments packet44 = { |
| // type (short header, 4 byte packet number) |
| {"", |
| {0x32}}, |
| // connection_id |
| {"", |
| {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, |
| // packet number |
| {"", |
| {0x12, 0x34, 0x56, 0x78}}, |
| // frame type (stream frame with fin) |
| {"", |
| {0xFC}}, |
| // stream id |
| {"Unable to read stream_id.", |
| {0x04}}, |
| // offset |
| {"Unable to read offset.", |
| {0x3A, 0x98, 0xFE, 0xDC, |
| 0x32, 0x10, 0x76, 0x54}}, |
| {"Unable to read frame data.", |
| { |
| // data length |
| 0x00, 0x0c, |
| // data |
| 'h', 'e', 'l', 'l', |
| 'o', ' ', 'w', 'o', |
| 'r', 'l', 'd', '!'}}, |
| }; |
| |
| PacketFragments packet46 = { |
| // type (short header, 4 byte packet number) |
| {"", |
| {0x43}}, |
| // connection_id |
| {"", |
| {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, |
| // packet number |
| {"", |
| {0x12, 0x34, 0x56, 0x78}}, |
| // frame type (stream frame with fin) |
| {"", |
| {0xFC}}, |
| // stream id |
| {"Unable to read stream_id.", |
| {0x04}}, |
| // offset |
| {"Unable to read offset.", |
| {0x3A, 0x98, 0xFE, 0xDC, |
| 0x32, 0x10, 0x76, 0x54}}, |
| {"Unable to read frame data.", |
| { |
| // data length |
| 0x00, 0x0c, |
| // data |
| 'h', 'e', 'l', 'l', |
| 'o', ' ', 'w', 'o', |
| 'r', 'l', 'd', '!'}}, |
| }; |
| |
| PacketFragments packet99 = { |
| // type (short header, 4 byte packet number) |
| {"", |
| {0x43}}, |
| // connection_id |
| {"", |
| {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, |
| // packet number |
| {"", |
| {0x12, 0x34, 0x56, 0x78}}, |
| // frame type (IETF_STREAM frame with LEN, FIN, and OFFSET bits set) |
| {"", |
| {0x08 | 0x01 | 0x02 | 0x04}}, |
| // stream id |
| {"Unable to read stream_id.", |
| {kVarInt62OneByte + 0x04}}, |
| // offset |
| {"Unable to read stream data offset.", |
| {kVarInt62EightBytes + 0x3A, 0x98, 0xFE, 0xDC, |
| 0x32, 0x10, 0x76, 0x54}}, |
| // data length |
| {"Unable to read stream data length.", |
| {kVarInt62OneByte + 0x0c}}, |
| // data |
| {"Unable to read frame data.", |
| { 'h', 'e', 'l', 'l', |
| 'o', ' ', 'w', 'o', |
| 'r', 'l', 'd', '!'}}, |
| }; |
| // clang-format on |
| |
| PacketFragments& fragments = |
| framer_.transport_version() == QUIC_VERSION_99 |
| ? packet99 |
| : (framer_.transport_version() > QUIC_VERSION_44 |
| ? packet46 |
| : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 |
| : packet)); |
| std::unique_ptr<QuicEncryptedPacket> encrypted( |
| AssemblePacketFromFragments(fragments)); |
| EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); |
| |
| EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); |
| ASSERT_TRUE(visitor_.header_.get()); |
| EXPECT_TRUE(CheckDecryption( |
| *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, |
| PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); |
| |
| ASSERT_EQ(1u, visitor_.stream_frames_.size()); |
| EXPECT_EQ(0u, visitor_.ack_frames_.size()); |
| // Stream ID should be the last 1 byte of kStreamId. |
| EXPECT_EQ(0x000000FF & kStreamId, visitor_.stream_frames_[0]->stream_id); |
| EXPECT_TRUE(visitor_.stream_frames_[0]->fin); |
| EXPECT_EQ(kStreamOffset, visitor_.stream_frames_[0]->offset); |
| CheckStreamFrameData("hello world!", visitor_.stream_frames_[0].get()); |
| |
| CheckFramingBoundaries(fragments, QUIC_INVALID_STREAM_DATA); |
| } |
| |
| TEST_P(QuicFramerTest, StreamFrameWithVersion) { |
| // clang-format off |
| PacketFragments packet = { |
| // public flags (version, 8 byte connection_id) |
| {"", |
| {0x29}}, |
| // connection_id |
| {"", |
| {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, |
| // version tag |
| {"", |
| {QUIC_VERSION_BYTES}}, |
| // packet number |
| {"", |
| {0x12, 0x34, 0x56, 0x78}}, |
| // frame type (stream frame with fin) |
| {"", |
| {0xFE}}, |
| // stream id |
| {"Unable to read stream_id.", |
| {0x02, 0x03, 0x04}}, |
| // offset |
| {"Unable to read offset.", |
| {0x3A, 0x98, 0xFE, 0xDC, |
| 0x32, 0x10, 0x76, 0x54}}, |
| {"Unable to read frame data.", |
| { |
| // data length |
| 0x00, 0x0c, |
| // data |
| 'h', 'e', 'l', 'l', |
| 'o', ' ', 'w', 'o', |
| 'r', 'l', 'd', '!'}}, |
| }; |
| |
| PacketFragments packet44 = { |
| // public flags (long header with packet type ZERO_RTT_PROTECTED) |
| {"", |
| {0xFC}}, |
| // version tag |
| {"", |
| {QUIC_VERSION_BYTES}}, |
| // connection_id length |
| {"", |
| {0x50}}, |
| // connection_id |
| {"", |
| {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, |
| // packet number |
| {"", |
| {0x12, 0x34, 0x56, 0x78}}, |
| // frame type (stream frame with fin) |
| {"", |
| {0xFE}}, |
| // stream id |
| {"Unable to read stream_id.", |
| {0x02, 0x03, 0x04}}, |
| // offset |
| {"Unable to read offset.", |
| {0x3A, 0x98, 0xFE, 0xDC, |
| 0x32, 0x10, 0x76, 0x54}}, |
| {"Unable to read frame data.", |
| { |
| // data length |
| 0x00, 0x0c, |
| // data |
| 'h', 'e', 'l', 'l', |
| 'o', ' ', 'w', 'o', |
| 'r', 'l', 'd', '!'}}, |
| }; |
| |
| PacketFragments packet46 = { |
| // public flags (long header with packet type ZERO_RTT_PROTECTED and |
| // 4-byte packet number) |
| {"", |
| {0xD3}}, |
| // version tag |
| {"", |
| {QUIC_VERSION_BYTES}}, |
| // connection_id length |
| {"", |
| {0x50}}, |
| // connection_id |
| {"", |
| {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, |
| // packet number |
| {"", |
| {0x12, 0x34, 0x56, 0x78}}, |
| // frame type (stream frame with fin) |
| {"", |
| {0xFE}}, |
| // stream id |
| {"Unable to read stream_id.", |
| {0x02, 0x03, 0x04}}, |
| // offset |
| {"Unable to read offset.", |
| {0x3A, 0x98, 0xFE, 0xDC, |
| 0x32, 0x10, 0x76, 0x54}}, |
| {"Unable to read frame data.", |
| { |
| // data length |
| 0x00, 0x0c, |
| // data |
| 'h', 'e', 'l', 'l', |
| 'o', ' ', 'w', 'o', |
| 'r', 'l', 'd', '!'}}, |
| }; |
| |
| PacketFragments packet99 = { |
| // public flags (long header with packet type ZERO_RTT_PROTECTED and |
| // 4-byte packet number) |
| {"", |
| {0xD3}}, |
| // version tag |
| {"", |
| {QUIC_VERSION_BYTES}}, |
| // connection_id length |
| {"", |
| {0x50}}, |
| // connection_id |
| {"", |
| {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, |
| // long header packet length |
| {"", |
| {0x1E}}, |
| // packet number |
| {"", |
| {0x12, 0x34, 0x56, 0x78}}, |
| // frame type (IETF_STREAM frame with FIN, LEN, and OFFSET bits set) |
| {"", |
| {0x08 | 0x01 | 0x02 | 0x04}}, |
| // stream id |
| {"Long header payload length longer than packet.", |
| {kVarInt62FourBytes + 0x00, 0x02, 0x03, 0x04}}, |
| // offset |
| {"Long header payload length longer than packet.", |
| {kVarInt62EightBytes + 0x3A, 0x98, 0xFE, 0xDC, |
| 0x32, 0x10, 0x76, 0x54}}, |
| // data length |
| {"Long header payload length longer than packet.", |
| {kVarInt62OneByte + 0x0c}}, |
| // data |
| {"Long header payload length longer than packet.", |
| { 'h', 'e', 'l', 'l', |
| 'o', ' ', 'w', 'o', |
| 'r', 'l', 'd', '!'}}, |
| }; |
| // clang-format on |
| |
| QuicVariableLengthIntegerLength retry_token_length_length = |
| VARIABLE_LENGTH_INTEGER_LENGTH_0; |
| size_t retry_token_length = 0; |
| QuicVariableLengthIntegerLength length_length = |
| QuicVersionHasLongHeaderLengths(framer_.transport_version()) |
| ? VARIABLE_LENGTH_INTEGER_LENGTH_1 |
| : VARIABLE_LENGTH_INTEGER_LENGTH_0; |
| |
| PacketFragments& fragments = |
| framer_.transport_version() == QUIC_VERSION_99 |
| ? packet99 |
| : (framer_.transport_version() > QUIC_VERSION_44 |
| ? packet46 |
| : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 |
| : packet)); |
| std::unique_ptr<QuicEncryptedPacket> encrypted( |
| AssemblePacketFromFragments(fragments)); |
| EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); |
| |
| EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); |
| ASSERT_TRUE(visitor_.header_.get()); |
| EXPECT_TRUE(CheckDecryption( |
| *encrypted, kIncludeVersion, !kIncludeDiversificationNonce, |
| PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID, |
| retry_token_length_length, retry_token_length, length_length)); |
| |
| ASSERT_EQ(1u, visitor_.stream_frames_.size()); |
| EXPECT_EQ(0u, visitor_.ack_frames_.size()); |
| // Stream ID should be the last 3 bytes of kStreamId. |
| EXPECT_EQ(0x00FFFFFF & kStreamId, visitor_.stream_frames_[0]->stream_id); |
| EXPECT_TRUE(visitor_.stream_frames_[0]->fin); |
| EXPECT_EQ(kStreamOffset, visitor_.stream_frames_[0]->offset); |
| CheckStreamFrameData("hello world!", visitor_.stream_frames_[0].get()); |
| |
| CheckFramingBoundaries(fragments, |
| framer_.transport_version() == QUIC_VERSION_99 |
| ? QUIC_INVALID_PACKET_HEADER |
| : QUIC_INVALID_STREAM_DATA); |
| } |
| |
| TEST_P(QuicFramerTest, RejectPacket) { |
| visitor_.accept_packet_ = false; |
| |
| // clang-format off |
| unsigned char packet[] = { |
| // public flags (8 byte connection_id) |
| 0x28, |
| // connection_id |
| 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, |
| // packet number |
| 0x12, 0x34, 0x56, 0x78, |
| |
| // frame type (stream frame with fin) |
| 0xFF, |
| // stream id |
| 0x01, 0x02, 0x03, 0x04, |
| // offset |
| 0x3A, 0x98, 0xFE, 0xDC, |
| 0x32, 0x10, 0x76, 0x54, |
| // data length |
| 0x00, 0x0c, |
| // data |
| 'h', 'e', 'l', 'l', |
| 'o', ' ', 'w', 'o', |
| 'r', 'l', 'd', '!', |
| }; |
| |
| unsigned char packet44[] = { |
| // type (short header, 4 byte packet number) |
| 0x32, |
| // connection_id |
| 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, |
| // packet number |
| 0x12, 0x34, 0x56, 0x78, |
| |
| // frame type (STREAM Frame with FIN, LEN, and OFFSET bits set) |
| 0x10 | 0x01 | 0x02 | 0x04, |
| // stream id |
| kVarInt62FourBytes + 0x01, 0x02, 0x03, 0x04, |
| // offset |
| kVarInt62EightBytes + 0x3A, 0x98, 0xFE, 0xDC, |
| 0x32, 0x10, 0x76, 0x54, |
| // data length |
| kVarInt62OneByte + 0x0c, |
| // data |
| 'h', 'e', 'l', 'l', |
| 'o', ' ', 'w', 'o', |
| 'r', 'l', 'd', '!', |
| }; |
| |
| unsigned char packet46[] = { |
| // type (short header, 4 byte packet number) |
| 0x43, |
| // connection_id |
| 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, |
| // packet number |
| 0x12, 0x34, 0x56, 0x78, |
| |
| // frame type (STREAM Frame with FIN, LEN, and OFFSET bits set) |
| 0x10 | 0x01 | 0x02 | 0x04, |
| // stream id |
| kVarInt62FourBytes + 0x01, 0x02, 0x03, 0x04, |
| // offset |
| kVarInt62EightBytes + 0x3A, 0x98, 0xFE, 0xDC, |
| 0x32, 0x10, 0x76, 0x54, |
| // data length |
| kVarInt62OneByte + 0x0c, |
| // data |
| 'h', 'e', 'l', 'l', |
| 'o', ' ', 'w', 'o', |
| 'r', 'l', 'd', '!', |
| }; |
| // clang-format on |
| |
| unsigned char* p = packet; |
| if (framer_.transport_version() > QUIC_VERSION_44) { |
| p = packet46; |
| } else if (framer_.transport_version() > QUIC_VERSION_43) { |
| p = packet44; |
| } |
| QuicEncryptedPacket encrypted(AsChars(p), |
| framer_.transport_version() > QUIC_VERSION_43 |
| ? QUIC_ARRAYSIZE(packet44) |
| : QUIC_ARRAYSIZE(packet), |
| false); |
| EXPECT_TRUE(framer_.ProcessPacket(encrypted)); |
| |
| EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); |
| ASSERT_TRUE(visitor_.header_.get()); |
| EXPECT_TRUE(CheckDecryption( |
| encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, |
| PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); |
| |
| ASSERT_EQ(0u, visitor_.stream_frames_.size()); |
| EXPECT_EQ(0u, visitor_.ack_frames_.size()); |
| } |
| |
| TEST_P(QuicFramerTest, RejectPublicHeader) { |
| visitor_.accept_public_header_ = false; |
| |
| // clang-format off |
| unsigned char packet[] = { |
| // public flags (8 byte connection_id) |
| 0x28, |
| // connection_id |
| 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, |
| }; |
| |
| unsigned char packet44[] = { |
| // type (short header, 1 byte packet number) |
| 0x30, |
| // connection_id |
| 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, |
| // packet number |
| 0x01, |
| }; |
| |
| unsigned char packet46[] = { |
| // type (short header, 1 byte packet number) |
| 0x40, |
| // connection_id |
| 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, |
| // packet number |
| 0x01, |
| }; |
| // clang-format on |
| |
| QuicEncryptedPacket encrypted( |
| framer_.transport_version() > QUIC_VERSION_44 |
| ? AsChars(packet46) |
| : (framer_.transport_version() > QUIC_VERSION_43 ? AsChars(packet44) |
| : AsChars(packet)), |
| framer_.transport_version() > QUIC_VERSION_44 |
| ? QUIC_ARRAYSIZE(packet46) |
| : (framer_.transport_version() > QUIC_VERSION_43 |
| ? QUIC_ARRAYSIZE(packet44) |
| : QUIC_ARRAYSIZE(packet)), |
| false); |
| EXPECT_TRUE(framer_.ProcessPacket(encrypted)); |
| |
| EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); |
| ASSERT_TRUE(visitor_.header_.get()); |
| EXPECT_FALSE(visitor_.header_->packet_number.IsInitialized()); |
| } |
| |
| TEST_P(QuicFramerTest, AckFrameOneAckBlock) { |
| // clang-format off |
| PacketFragments packet = { |
| // public flags (8 byte connection_id) |
| {"", |
| {0x2C}}, |
| // connection_id |
| {"", |
| {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, |
| // packet number |
| {"", |
| {0x12, 0x34, 0x56, 0x78}}, |
| // frame type (ack frame) |
| // (one ack block, 2 byte largest observed, 2 byte block length) |
| {"", |
| {0x45}}, |
| // largest acked |
| {"Unable to read largest acked.", |
| {0x12, 0x34}}, |
| // Zero delta time. |
| {"Unable to read ack delay time.", |
| {0x00, 0x00}}, |
| // first ack block length. |
| {"Unable to read first ack block length.", |
| {0x12, 0x34}}, |
| // num timestamps. |
| {"Unable to read num received packets.", |
| {0x00}} |
| }; |
| |
| PacketFragments packet44 = { |
| // type (short packet, 4 byte packet number) |
| {"", |
| {0x32}}, |
| // connection_id |
| {"", |
| {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, |
| // packet number |
| {"", |
| {0x12, 0x34, 0x56, 0x78}}, |
| // frame type (ack frame) |
| // (one ack block, 2 byte largest observed, 2 byte block length) |
| {"", |
| {0x45}}, |
| // largest acked |
| {"Unable to read largest acked.", |
| {0x12, 0x34}}, |
| // Zero delta time. |
| {"Unable to read ack delay time.", |
| {0x00, 0x00}}, |
| // first ack block length. |
| {"Unable to read first ack block length.", |
| {0x12, 0x34}}, |
| // num timestamps. |
| {"Unable to read num received packets.", |
| {0x00}} |
| }; |
| |
| PacketFragments packet46 = { |
| // type (short packet, 4 byte packet number) |
| {"", |
| {0x43}}, |
| // connection_id |
| {"", |
| {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, |
| // packet number |
| {"", |
| {0x12, 0x34, 0x56, 0x78}}, |
| // frame type (ack frame) |
| // (one ack block, 2 byte largest observed, 2 byte block length) |
| {"", |
| {0x45}}, |
| // largest acked |
| {"Unable to read largest acked.", |
| {0x12, 0x34}}, |
| // Zero delta time. |
| {"Unable to read ack delay time.", |
| {0x00, 0x00}}, |
| // first ack block length. |
| {"Unable to read first ack block length.", |
| {0x12, 0x34}}, |
| // num timestamps. |
| {"Unable to read num received packets.", |
| {0x00}} |
| }; |
| |
| PacketFragments packet99 = { |
| // type (short packet, 4 byte packet number) |
| {"", |
| {0x43}}, |
| // connection_id |
| {"", |
| {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, |
| // packet number |
| {"", |
| {0x12, 0x34, 0x56, 0x78}}, |
| // frame type (IETF_ACK) |
| // (one ack block, 2 byte largest observed, 2 byte block length) |
| // IETF-Quic ignores the bit-fields in the ack type, all of |
| // that information is encoded elsewhere in the frame. |
| {"", |
| {0x02}}, |
| // largest acked |
| {"Unable to read largest acked.", |
| {kVarInt62TwoBytes + 0x12, 0x34}}, |
| // Zero delta time. |
| {"Unable to read ack delay time.", |
| {kVarInt62OneByte + 0x00}}, |
| // Ack block count (0 -- no blocks after the first) |
| {"Unable to read ack block count.", |
| {kVarInt62OneByte + 0x00}}, |
| // first ack block length - 1. |
| // IETF Quic defines the ack block's value as the "number of |
| // packets that preceed the largest packet number in the block" |
| // which for the 1st ack block is the largest acked field, |
| // above. This means that if we are acking just packet 0x1234 |
| // then the 1st ack block will be 0. |
| {"Unable to read first ack block length.", |
| {kVarInt62TwoBytes + 0x12, 0x33}} |
| }; |
| // clang-format on |
| |
| PacketFragments& fragments = |
| framer_.transport_version() == QUIC_VERSION_99 |
| ? packet99 |
| : (framer_.transport_version() > QUIC_VERSION_44 |
| ? packet46 |
| : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 |
| : packet)); |
| std::unique_ptr<QuicEncryptedPacket> encrypted( |
| AssemblePacketFromFragments(fragments)); |
| EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); |
| |
| EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); |
| ASSERT_TRUE(visitor_.header_.get()); |
| EXPECT_TRUE(CheckDecryption( |
| *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, |
| PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); |
| |
| EXPECT_EQ(0u, visitor_.stream_frames_.size()); |
| ASSERT_EQ(1u, visitor_.ack_frames_.size()); |
| const QuicAckFrame& frame = *visitor_.ack_frames_[0]; |
| EXPECT_EQ(kSmallLargestObserved, LargestAcked(frame)); |
| ASSERT_EQ(4660u, frame.packets.NumPacketsSlow()); |
| |
| CheckFramingBoundaries(fragments, QUIC_INVALID_ACK_DATA); |
| } |
| |
| // This test checks that the ack frame processor correctly identifies |
| // and handles the case where the first ack block is larger than the |
| // largest_acked packet. |
| TEST_P(QuicFramerTest, FirstAckFrameUnderflow) { |
| // clang-format off |
| PacketFragments packet = { |
| // public flags (8 byte connection_id) |
| {"", |
| {0x2C}}, |
| // connection_id |
| {"", |
| {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, |
| // packet number |
| {"", |
| {0x12, 0x34, 0x56, 0x78}}, |
| // frame type (ack frame) |
| // (one ack block, 2 byte largest observed, 2 byte block length) |
| {"", |
| {0x45}}, |
| // largest acked |
| {"Unable to read largest acked.", |
| {0x12, 0x34}}, |
| // Zero delta time. |
| {"Unable to read ack delay time.", |
| {0x00, 0x00}}, |
| // first ack block length. |
| {"Unable to read first ack block length.", |
| {0x88, 0x88}}, |
| // num timestamps. |
| {"Underflow with first ack block length 34952 largest acked is 4660.", |
| {0x00}} |
| }; |
| |
| PacketFragments packet44 = { |
| // type (short header, 4 byte packet num
|