// Copyright 2013 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // // Provides a simple interface for QUIC tests to create a variety of packets. #ifndef NET_QUIC_QUIC_TEST_PACKET_MAKER_H_ #define NET_QUIC_QUIC_TEST_PACKET_MAKER_H_ #include #include #include #include #include #include #include "base/memory/raw_ptr.h" #include "net/base/request_priority.h" #include "net/third_party/quiche/src/quiche/quic/core/http/http_encoder.h" #include "net/third_party/quiche/src/quiche/quic/core/qpack/qpack_encoder.h" #include "net/third_party/quiche/src/quiche/quic/core/quic_clock.h" #include "net/third_party/quiche/src/quiche/quic/core/quic_packets.h" #include "net/third_party/quiche/src/quiche/quic/core/quic_stream_frame_data_producer.h" #include "net/third_party/quiche/src/quiche/quic/core/quic_types.h" #include "net/third_party/quiche/src/quiche/quic/core/quic_utils.h" #include "net/third_party/quiche/src/quiche/quic/test_tools/mock_random.h" #include "net/third_party/quiche/src/quiche/quic/test_tools/qpack/qpack_test_utils.h" #include "net/third_party/quiche/src/quiche/quic/test_tools/simple_data_producer.h" namespace net::test { class QuicTestPacketMaker { public: // |client_priority_uses_incremental| affects the output of any method that // includes HTTP3 priority data. The protocol default is to omit the // incremental flag in the priority data but HTTP streams may enable it // if the client supports incremental streams. QuicTestPacketMaker(quic::ParsedQuicVersion version, quic::QuicConnectionId connection_id, const quic::QuicClock* clock, const std::string& host, quic::Perspective perspective, bool client_priority_uses_incremental = false, bool use_priority_header = false); QuicTestPacketMaker(const QuicTestPacketMaker&) = delete; QuicTestPacketMaker& operator=(const QuicTestPacketMaker&) = delete; ~QuicTestPacketMaker(); void set_hostname(const std::string& host); void set_use_priority_header(const bool use_priority_header) { use_priority_header_ = use_priority_header; } void set_connection_id(const quic::QuicConnectionId& connection_id) { connection_id_ = connection_id; } std::unique_ptr MakeConnectivityProbingPacket( uint64_t num); std::unique_ptr MakePingPacket(uint64_t num); std::unique_ptr MakeRetireConnectionIdPacket( uint64_t num, uint64_t sequence_number); std::unique_ptr MakeNewConnectionIdPacket( uint64_t num, const quic::QuicConnectionId& cid, uint64_t sequence_number, uint64_t retire_prior_to); std::unique_ptr MakeAckAndNewConnectionIdPacket( uint64_t num, uint64_t largest_received, uint64_t smallest_received, const quic::QuicConnectionId& cid, uint64_t sequence_number, uint64_t retire_prior_to); std::unique_ptr MakeDummyCHLOPacket( uint64_t packet_num); std::unique_ptr MakeAckAndPingPacket( uint64_t num, uint64_t largest_received, uint64_t smallest_received); std::unique_ptr MakeAckAndRetireConnectionIdPacket( uint64_t num, uint64_t largest_received, uint64_t smallest_received, uint64_t sequence_number); std::unique_ptr MakeRetransmissionAndRetireConnectionIdPacket( uint64_t num, const std::vector& original_packet_numbers, uint64_t sequence_number); std::unique_ptr MakeStreamsBlockedPacket( uint64_t num, quic::QuicStreamCount stream_count, bool unidirectional); std::unique_ptr MakeMaxStreamsPacket( uint64_t num, quic::QuicStreamCount stream_count, bool unidirectional); std::unique_ptr MakeRstPacket( uint64_t num, quic::QuicStreamId stream_id, quic::QuicRstStreamErrorCode error_code); std::unique_ptr MakeRstPacket( uint64_t num, quic::QuicStreamId stream_id, quic::QuicRstStreamErrorCode error_code, bool include_stop_sending_if_v99); std::unique_ptr MakeRstAndDataPacket( uint64_t num, quic::QuicStreamId rst_stream_id, quic::QuicRstStreamErrorCode rst_error_code, quic::QuicStreamId data_stream_id, std::string_view data); std::unique_ptr MakeRetransmissionRstAndDataPacket( const std::vector& original_packet_numbers, uint64_t num, quic::QuicStreamId rst_stream_id, quic::QuicRstStreamErrorCode rst_error_code, quic::QuicStreamId data_stream_id, std::string_view data, uint64_t retransmit_frame_count = 0); std::unique_ptr MakeDataAndRstPacket( uint64_t num, quic::QuicStreamId data_stream_id, std::string_view data, quic::QuicStreamId rst_stream_id, quic::QuicRstStreamErrorCode rst_error_code); std::unique_ptr MakeDataRstAndAckPacket( uint64_t num, quic::QuicStreamId data_stream_id, std::string_view data, quic::QuicStreamId rst_stream_id, quic::QuicRstStreamErrorCode rst_error_code, uint64_t largest_received, uint64_t smallest_received); std::unique_ptr MakeAckAndRstPacket( uint64_t num, quic::QuicStreamId stream_id, quic::QuicRstStreamErrorCode error_code, uint64_t largest_received, uint64_t smallest_received); std::unique_ptr MakeAckAndRstPacket( uint64_t num, quic::QuicStreamId stream_id, quic::QuicRstStreamErrorCode error_code, uint64_t largest_received, uint64_t smallest_received, bool include_stop_sending_if_v99); std::unique_ptr MakeRstAckAndConnectionClosePacket( uint64_t num, quic::QuicStreamId stream_id, quic::QuicRstStreamErrorCode error_code, uint64_t largest_received, uint64_t smallest_received, quic::QuicErrorCode quic_error, const std::string& quic_error_details); std::unique_ptr MakeRstAckAndDataPacket( uint64_t num, quic::QuicStreamId stream_id, quic::QuicRstStreamErrorCode error_code, uint64_t largest_received, uint64_t smallest_received, quic::QuicStreamId data_id, bool fin, std::string_view data); std::unique_ptr MakeAckDataAndRst( uint64_t num, quic::QuicStreamId stream_id, quic::QuicRstStreamErrorCode error_code, uint64_t largest_received, uint64_t smallest_received, quic::QuicStreamId data_id, bool fin, std::string_view data); std::unique_ptr MakeAckRstAndDataPacket( uint64_t num, quic::QuicStreamId stream_id, quic::QuicRstStreamErrorCode error_code, uint64_t largest_received, uint64_t smallest_received, quic::QuicStreamId data_id, bool fin, std::string_view data); std::unique_ptr MakeRstAndConnectionClosePacket( uint64_t num, quic::QuicStreamId stream_id, quic::QuicRstStreamErrorCode error_code, quic::QuicErrorCode quic_error, const std::string& quic_error_details); std::unique_ptr MakeDataRstAndConnectionClosePacket( uint64_t num, quic::QuicStreamId data_stream_id, std::string_view data, quic::QuicStreamId rst_stream_id, quic::QuicRstStreamErrorCode error_code, quic::QuicErrorCode quic_error, const std::string& quic_error_details); std::unique_ptr MakeDataRstAckAndConnectionClosePacket( uint64_t num, quic::QuicStreamId data_stream_id, std::string_view data, quic::QuicStreamId rst_stream_id, quic::QuicRstStreamErrorCode error_code, uint64_t largest_received, uint64_t smallest_received, quic::QuicErrorCode quic_error, const std::string& quic_error_details); std::unique_ptr MakeDataRstAckAndConnectionClosePacket( uint64_t num, quic::QuicStreamId data_stream_id, std::string_view data, quic::QuicStreamId rst_stream_id, quic::QuicRstStreamErrorCode error_code, uint64_t largest_received, uint64_t smallest_received, quic::QuicErrorCode quic_error, const std::string& quic_error_details, uint64_t frame_type); std::unique_ptr MakeStopSendingPacket( uint64_t num, quic::QuicStreamId stream_id, quic::QuicRstStreamErrorCode error_code); std::unique_ptr MakeAckAndConnectionClosePacket( uint64_t num, uint64_t largest_received, uint64_t smallest_received, quic::QuicErrorCode quic_error, const std::string& quic_error_details, uint64_t frame_type); std::unique_ptr MakeConnectionClosePacket( uint64_t num, quic::QuicErrorCode quic_error, const std::string& quic_error_details); std::unique_ptr MakeGoAwayPacket( uint64_t num, quic::QuicErrorCode error_code, std::string reason_phrase); std::unique_ptr MakeAckPacket( uint64_t packet_number, uint64_t largest_received, uint64_t smallest_received); std::unique_ptr MakeAckPacket( uint64_t packet_number, uint64_t first_received, uint64_t largest_received, uint64_t smallest_received, std::optional ecn = std::nullopt); std::unique_ptr MakeDataPacket( uint64_t packet_number, quic::QuicStreamId stream_id, bool fin, std::string_view data); std::unique_ptr MakeDatagramPacket( uint64_t packet_number, std::string_view datagram); std::unique_ptr MakeDatagramPacket( uint64_t packet_number, std::vector datagrams); std::unique_ptr MakeAckAndDataPacket( uint64_t packet_number, quic::QuicStreamId stream_id, uint64_t largest_received, uint64_t smallest_received, bool fin, std::string_view data); std::unique_ptr MakeAckAndDatagramPacket( uint64_t packet_number, uint64_t largest_received, uint64_t smallest_received, std::string_view data); std::unique_ptr MakeAckRetransmissionAndDataPacket( uint64_t packet_number, const std::vector& original_packet_numbers, quic::QuicStreamId stream_id, uint64_t largest_received, uint64_t smallest_received, bool fin, std::string_view data); std::unique_ptr MakeAckAndRetransmissionPacket( uint64_t packet_number, uint64_t first_received, uint64_t largest_received, uint64_t smallest_received, const std::vector& original_packet_numbers); std::unique_ptr MakeRequestHeadersAndMultipleDataFramesPacket( uint64_t packet_number, quic::QuicStreamId stream_id, bool fin, spdy::SpdyPriority spdy_priority, spdy::Http2HeaderBlock headers, size_t* spdy_headers_frame_length, const std::vector& data_writes); // If |spdy_headers_frame_length| is non-null, it will be set to the size of // the SPDY headers frame created for this packet. std::unique_ptr MakeRequestHeadersPacket( uint64_t packet_number, quic::QuicStreamId stream_id, bool fin, spdy::SpdyPriority spdy_priority, spdy::Http2HeaderBlock headers, size_t* spdy_headers_frame_length, bool should_include_priority_frame = true); std::unique_ptr MakeRetransmissionAndRequestHeadersPacket( const std::vector& original_packet_numbers, uint64_t packet_number, quic::QuicStreamId stream_id, bool fin, spdy::SpdyPriority spdy_priority, spdy::Http2HeaderBlock headers, size_t* spdy_headers_frame_length); std::unique_ptr MakeRequestHeadersAndRstPacket( uint64_t packet_number, quic::QuicStreamId stream_id, bool fin, spdy::SpdyPriority spdy_priority, spdy::Http2HeaderBlock headers, size_t* spdy_headers_frame_length, quic::QuicRstStreamErrorCode error_code); // If |spdy_headers_frame_length| is non-null, it will be set to the size of // the SPDY headers frame created for this packet. std::unique_ptr MakeResponseHeadersPacket( uint64_t packet_number, quic::QuicStreamId stream_id, bool fin, spdy::Http2HeaderBlock headers, size_t* spdy_headers_frame_length); // Creates a packet containing the initial SETTINGS frame, and saves the // headers stream offset into |offset|. std::unique_ptr MakeInitialSettingsPacket( uint64_t packet_number); std::unique_ptr MakePriorityPacket( uint64_t packet_number, quic::QuicStreamId id, spdy::SpdyPriority spdy_priority); std::unique_ptr MakeAckAndPriorityPacket( uint64_t packet_number, uint64_t largest_received, uint64_t smallest_received, quic::QuicStreamId id, spdy::SpdyPriority spdy_priority); std::unique_ptr MakeRetransmissionPacket( uint64_t original_packet_number, uint64_t new_packet_number); std::unique_ptr MakeCombinedRetransmissionPacket( const std::vector& original_packet_numbers, uint64_t new_packet_number); std::unique_ptr MakeAckAndPriorityUpdatePacket( uint64_t packet_number, uint64_t largest_received, uint64_t smallest_received, quic::QuicStreamId id, spdy::SpdyPriority spdy_priority); std::unique_ptr MakeStatelessResetPacket(); // Removes all stream frames associated with |stream_id|. void RemoveSavedStreamFrames(quic::QuicStreamId stream_id); void SetEncryptionLevel(quic::EncryptionLevel level); spdy::Http2HeaderBlock GetRequestHeaders(const std::string& method, const std::string& scheme, const std::string& path) const; spdy::Http2HeaderBlock ConnectRequestHeaders( const std::string& host_port) const; spdy::Http2HeaderBlock GetResponseHeaders(const std::string& status) const; spdy::Http2HeaderBlock GetResponseHeaders(const std::string& status, const std::string& alt_svc) const; void Reset(); quic::QuicStreamOffset stream_offset(quic::QuicStreamId stream_id) { return stream_offsets_[stream_id]; } void set_save_packet_frames(bool save_packet_frames) { save_packet_frames_ = save_packet_frames; } std::string QpackEncodeHeaders(quic::QuicStreamId stream_id, spdy::Http2HeaderBlock headers, size_t* encoded_data_length); void set_ecn_codepoint(quic::QuicEcnCodepoint ecn) { ecn_codepoint_ = ecn; } private: // Initialize header of next packet to build. void InitializeHeader(uint64_t packet_number); // Add frames to current packet. void AddQuicPaddingFrame(); void AddQuicPingFrame(); void AddQuicRetireConnectionIdFrame(uint64_t sequence_number); void AddQuicNewConnectionIdFrame(const quic::QuicConnectionId& cid, uint64_t sequence_number, uint64_t retire_prior_to, quic::StatelessResetToken reset_token); void AddQuicMaxStreamsFrame(quic::QuicControlFrameId control_frame_id, quic::QuicStreamCount stream_count, bool unidirectional); void AddQuicStreamsBlockedFrame(quic::QuicControlFrameId control_frame_id, quic::QuicStreamCount stream_count, bool unidirectional); // Use and increase stream's current offset. void AddQuicStreamFrame(quic::QuicStreamId stream_id, bool fin, std::string_view data); // Use |offset| and do not change stream's current offset. void AddQuicStreamFrameWithOffset(quic::QuicStreamId stream_id, bool fin, quic::QuicStreamOffset offset, std::string_view data); void AddQuicAckFrame(uint64_t largest_received, uint64_t smallest_received); void AddQuicAckFrame(uint64_t first_received, uint64_t largest_received, uint64_t smallest_received, std::optional ecn = std::nullopt); void AddQuicMessageFrame(std::string_view data); void AddQuicRstStreamFrame(quic::QuicStreamId stream_id, quic::QuicRstStreamErrorCode error_code); void AddQuicConnectionCloseFrame(quic::QuicErrorCode quic_error, const std::string& quic_error_details); void AddQuicConnectionCloseFrame(quic::QuicErrorCode quic_error, const std::string& quic_error_details, uint64_t frame_type); void AddQuicGoAwayFrame(quic::QuicErrorCode error_code, std::string reason_phrase); void AddQuicPathResponseFrame(); void AddQuicPathChallengeFrame(); void AddQuicStopSendingFrame(quic::QuicStreamId stream_id, quic::QuicRstStreamErrorCode error_code); void AddQuicCryptoFrame(quic::EncryptionLevel level, quic::QuicStreamOffset offset, quic::QuicPacketLength data_length); void AddPriorityHeader(spdy::SpdyPriority spdy_priority, spdy::Http2HeaderBlock* headers); // Build packet using |header_|, |frames_|, and |data_producer_|, // and clear |frames_| and |data_producer_| afterwards. std::unique_ptr BuildPacket(); // Build packet using |header_|, |frames|, and |data_producer|. std::unique_ptr BuildPacketImpl( const quic::QuicFrames& frames, quic::QuicStreamFrameDataProducer* data_producer); bool ShouldIncludeVersion() const; quic::QuicConnectionId DestinationConnectionId() const; quic::QuicConnectionId SourceConnectionId() const; quic::QuicStreamId GetFirstBidirectionalStreamId() const; std::string GenerateHttp3SettingsData(); std::string GenerateHttp3PriorityData(spdy::SpdyPriority spdy_priority, quic::QuicStreamId stream_id); std::string GenerateHttp3GreaseData(); void MaybeAddHttp3SettingsFrames(); bool MaybeCoalesceStreamFrame(const quic::QuicFrame& frame); // Parameters used throughout the lifetime of the class. quic::ParsedQuicVersion version_; quic::QuicConnectionId connection_id_; raw_ptr clock_; // Not owned. std::string host_; quic::NoopDecoderStreamErrorDelegate decoder_stream_error_delegate_; quic::test::NoopQpackStreamSenderDelegate encoder_stream_sender_delegate_; quic::QpackEncoder qpack_encoder_; quic::test::MockRandom random_generator_; std::map stream_offsets_; quic::Perspective perspective_; quic::EncryptionLevel encryption_level_ = quic::ENCRYPTION_FORWARD_SECURE; quic::QuicLongHeaderType long_header_type_ = quic::INVALID_PACKET_TYPE; // The value of incremental flag in generated priority headers. bool client_priority_uses_incremental_; // Add the priority header to outbound requests bool use_priority_header_; // Save a copy of stream frame data that QuicStreamFrame objects can refer to. std::vector> saved_stream_data_; // If |save_packet_frames_| is true, save generated packets in // |saved_frames_|, allowing retransmission packets to be built. bool save_packet_frames_ = false; std::map saved_frames_; // State necessary for building the current packet. quic::QuicPacketHeader header_; quic::QuicFrames frames_; std::unique_ptr data_producer_; // Explicit Congestion Notification (ECN) codepoint to use when making // packets. quic::QuicEcnCodepoint ecn_codepoint_ = quic::ECN_NOT_ECT; }; } // namespace net::test #endif // NET_QUIC_QUIC_TEST_PACKET_MAKER_H_