// 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. #ifdef UNSAFE_BUFFERS_BUILD // TODO(crbug.com/40284755): Remove this and spanify to fix the errors. #pragma allow_unsafe_buffers #endif #include "net/quic/quic_test_packet_maker.h" #include #include #include "base/functional/callback.h" #include "base/strings/strcat.h" #include "base/strings/string_number_conversions.h" #include "base/test/bind.h" #include "net/base/features.h" #include "net/quic/mock_crypto_client_stream.h" #include "net/quic/quic_chromium_client_session.h" #include "net/quic/quic_http_utils.h" #include "net/spdy/spdy_http_utils.h" #include "net/third_party/quiche/src/quiche/common/quiche_buffer_allocator.h" #include "net/third_party/quiche/src/quiche/common/simple_buffer_allocator.h" #include "net/third_party/quiche/src/quiche/quic/core/http/http_constants.h" #include "net/third_party/quiche/src/quiche/quic/core/qpack/qpack_instruction_encoder.h" #include "net/third_party/quiche/src/quiche/quic/core/quic_framer.h" #include "net/third_party/quiche/src/quiche/quic/core/quic_stream.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/quic_test_utils.h" namespace net::test { namespace { quic::QuicFrames CloneFrames(const quic::QuicFrames& frames) { quic::QuicFrames new_frames = frames; for (auto& frame : new_frames) { switch (frame.type) { // Frames smaller than a pointer are inlined, so don't need to be cloned. case quic::PADDING_FRAME: case quic::MTU_DISCOVERY_FRAME: case quic::PING_FRAME: case quic::MAX_STREAMS_FRAME: case quic::STOP_WAITING_FRAME: case quic::STREAMS_BLOCKED_FRAME: case quic::STREAM_FRAME: case quic::HANDSHAKE_DONE_FRAME: case quic::BLOCKED_FRAME: case quic::WINDOW_UPDATE_FRAME: case quic::STOP_SENDING_FRAME: case quic::PATH_CHALLENGE_FRAME: case quic::PATH_RESPONSE_FRAME: break; case quic::ACK_FRAME: frame.ack_frame = new quic::QuicAckFrame(*frame.ack_frame); break; case quic::RST_STREAM_FRAME: frame.rst_stream_frame = new quic::QuicRstStreamFrame(*frame.rst_stream_frame); break; case quic::CONNECTION_CLOSE_FRAME: frame.connection_close_frame = new quic::QuicConnectionCloseFrame(*frame.connection_close_frame); break; case quic::GOAWAY_FRAME: frame.goaway_frame = new quic::QuicGoAwayFrame(*frame.goaway_frame); break; case quic::NEW_CONNECTION_ID_FRAME: frame.new_connection_id_frame = new quic::QuicNewConnectionIdFrame(*frame.new_connection_id_frame); break; case quic::RETIRE_CONNECTION_ID_FRAME: frame.retire_connection_id_frame = new quic::QuicRetireConnectionIdFrame( *frame.retire_connection_id_frame); break; case quic::MESSAGE_FRAME: frame.message_frame = new quic::QuicMessageFrame( frame.message_frame->message_id, quiche::QuicheMemSlice(quiche::QuicheBuffer::Copy( quiche::SimpleBufferAllocator::Get(), frame.message_frame->message_data.data()->AsStringView()))); break; case quic::CRYPTO_FRAME: frame.crypto_frame = new quic::QuicCryptoFrame(*frame.crypto_frame); break; case quic::NEW_TOKEN_FRAME: frame.new_token_frame = new quic::QuicNewTokenFrame(*frame.new_token_frame); break; case quic::ACK_FREQUENCY_FRAME: frame.ack_frequency_frame = new quic::QuicAckFrequencyFrame(*frame.ack_frequency_frame); break; case quic::RESET_STREAM_AT_FRAME: frame.reset_stream_at_frame = new quic::QuicResetStreamAtFrame(*frame.reset_stream_at_frame); break; case quic::NUM_FRAME_TYPES: DCHECK(false) << "Cannot clone frame type: " << frame.type; } } return new_frames; } } // namespace QuicTestPacketMaker::ConnectionState::ConnectionState() = default; QuicTestPacketMaker::ConnectionState::~ConnectionState() { for (auto& kv : saved_frames) { quic::DeleteFrames(&(kv.second)); } } std::string_view QuicTestPacketMaker::ConnectionState::SaveStreamData( std::string_view data) { saved_stream_data.push_back(std::make_unique(data)); return *saved_stream_data.back(); } void QuicTestPacketMaker::ConnectionState::Reset() { stream_offsets.clear(); } QuicTestPacketMaker::QuicTestPacketMaker(quic::ParsedQuicVersion version, quic::QuicConnectionId connection_id, const quic::QuicClock* clock, const std::string& host, quic::Perspective perspective, bool client_priority_uses_incremental, bool use_priority_header) : version_(version), clock_(clock), host_(host), qpack_encoder_(&decoder_stream_error_delegate_, quic::HuffmanEncoding::kEnabled, quic::CookieCrumbling::kEnabled), perspective_(perspective), client_priority_uses_incremental_(client_priority_uses_incremental), use_priority_header_(use_priority_header) { DCHECK(version.HasIetfQuicFrames()); DCHECK(!(perspective_ == quic::Perspective::IS_SERVER && client_priority_uses_incremental_)); set_connection_id(connection_id); qpack_encoder_.set_qpack_stream_sender_delegate( &encoder_stream_sender_delegate_); } QuicTestPacketMaker::~QuicTestPacketMaker() { CHECK(!builder_) << "QuicTestPacketMacker destroyed with unfinished packet " "build operation"; } void QuicTestPacketMaker::set_hostname(const std::string& host) { host_.assign(host); } QuicTestPacketBuilder& QuicTestPacketMaker::Packet(uint64_t packet_number) { CHECK(!builder_); builder_ = std::make_unique(packet_number, this, &connection_state_); return *builder_.get(); } std::unique_ptr QuicTestPacketMaker::MakeDummyCHLOPacket(uint64_t packet_number) { SetEncryptionLevel(quic::ENCRYPTION_INITIAL); auto& builder = Packet(packet_number); quic::CryptoHandshakeMessage message = MockCryptoClientStream::GetDummyCHLOMessage(); const quic::QuicData& data = message.GetSerialized(); builder.AddCryptoFrame(quic::ENCRYPTION_INITIAL, 0, data); builder.AddPaddingFrame(); return builder.Build(); } std::unique_ptr QuicTestPacketMaker::MakeAckAndRetransmissionPacket( uint64_t packet_number, uint64_t first_received, uint64_t largest_received, uint64_t smallest_received, const std::vector& original_packet_numbers) { DCHECK(connection_state_.save_packet_frames); auto& builder = Packet(packet_number); builder.AddAckFrame(first_received, largest_received, smallest_received); for (auto it : original_packet_numbers) { builder.AddPacketRetransmission(it); } return builder.Build(); } quic::QuicFrames QuicTestPacketMaker::CloneSavedFrames(uint64_t packet_number) { DCHECK(connection_state_.save_packet_frames); return CloneFrames( connection_state_.saved_frames[quic::QuicPacketNumber(packet_number)]); } std::unique_ptr QuicTestPacketMaker::MakeCombinedRetransmissionPacket( const std::vector& original_packet_numbers, uint64_t new_packet_number) { DCHECK(connection_state_.save_packet_frames); auto& builder = Packet(new_packet_number); for (auto it : original_packet_numbers) { for (auto& frame : CloneFrames( connection_state_.saved_frames[quic::QuicPacketNumber(it)])) { if (frame.type != quic::PADDING_FRAME) { builder.AddFrameWithCoalescing(frame); } } } return builder.Build(); } std::unique_ptr QuicTestPacketMaker::MakeAckAndDatagramPacket(uint64_t packet_number, uint64_t largest_received, uint64_t smallest_received, std::string_view data) { return Packet(packet_number) .AddAckFrame(/*first_received=*/1, largest_received, smallest_received) .AddMessageFrame(data) .Build(); } std::unique_ptr QuicTestPacketMaker::MakeRequestHeadersAndMultipleDataFramesPacket( uint64_t packet_number, quic::QuicStreamId stream_id, bool fin, spdy::SpdyPriority spdy_priority, quiche::HttpHeaderBlock headers, size_t* spdy_headers_frame_length, const std::vector& data_writes) { auto& builder = Packet(packet_number); builder.MaybeAddHttp3SettingsFrames(); std::string priority_data = GenerateHttp3PriorityData(spdy_priority, stream_id); if (!priority_data.empty()) { builder.AddStreamFrame(2, false, priority_data); } AddPriorityHeader(spdy_priority, &headers); std::string data = QpackEncodeHeaders(stream_id, std::move(headers), spdy_headers_frame_length); for (const auto& data_write : data_writes) { data += data_write; } builder.AddStreamFrame(stream_id, fin, data); return builder.Build(); } std::unique_ptr QuicTestPacketMaker::MakeRequestHeadersPacket( uint64_t packet_number, quic::QuicStreamId stream_id, bool fin, spdy::SpdyPriority spdy_priority, quiche::HttpHeaderBlock headers, size_t* spdy_headers_frame_length, bool should_include_priority_frame) { auto& builder = Packet(packet_number); builder.MaybeAddHttp3SettingsFrames(); if (should_include_priority_frame) { std::string priority_data = GenerateHttp3PriorityData(spdy_priority, stream_id); if (!priority_data.empty()) { builder.AddStreamFrame(2, false, priority_data); } } AddPriorityHeader(spdy_priority, &headers); std::string data = QpackEncodeHeaders(stream_id, std::move(headers), spdy_headers_frame_length); builder.AddStreamFrame(stream_id, fin, data); return builder.Build(); } std::unique_ptr QuicTestPacketMaker::MakeRetransmissionAndRequestHeadersPacket( const std::vector& original_packet_numbers, uint64_t packet_number, quic::QuicStreamId stream_id, bool fin, spdy::SpdyPriority spdy_priority, quiche::HttpHeaderBlock headers, size_t* spdy_headers_frame_length) { DCHECK(connection_state_.save_packet_frames); auto& builder = Packet(packet_number); for (auto it : original_packet_numbers) { builder.AddPacketRetransmission(it); } builder.MaybeAddHttp3SettingsFrames(); std::string priority_data = GenerateHttp3PriorityData(spdy_priority, stream_id); if (!priority_data.empty()) { builder.AddStreamFrame(2, false, priority_data); } AddPriorityHeader(spdy_priority, &headers); std::string data = QpackEncodeHeaders(stream_id, std::move(headers), spdy_headers_frame_length); builder.AddStreamFrame(stream_id, fin, data); return builder.Build(); } std::unique_ptr QuicTestPacketMaker::MakeRequestHeadersAndRstPacket( uint64_t packet_number, quic::QuicStreamId stream_id, bool fin, spdy::SpdyPriority spdy_priority, quiche::HttpHeaderBlock headers, size_t* spdy_headers_frame_length, quic::QuicRstStreamErrorCode error_code) { auto& builder = Packet(packet_number); builder.MaybeAddHttp3SettingsFrames(); std::string priority_data = GenerateHttp3PriorityData(spdy_priority, stream_id); if (!priority_data.empty()) { builder.AddStreamFrame(2, false, priority_data); } AddPriorityHeader(spdy_priority, &headers); std::string data = QpackEncodeHeaders(stream_id, std::move(headers), spdy_headers_frame_length); builder.AddStreamFrame(stream_id, fin, data); builder.AddStopSendingFrame(stream_id, error_code); builder.AddRstStreamFrame(stream_id, error_code); return builder.Build(); } std::unique_ptr QuicTestPacketMaker::MakeResponseHeadersPacket( uint64_t packet_number, quic::QuicStreamId stream_id, bool fin, quiche::HttpHeaderBlock headers, size_t* spdy_headers_frame_length) { std::string data = QpackEncodeHeaders(stream_id, std::move(headers), spdy_headers_frame_length); return Packet(packet_number).AddStreamFrame(stream_id, fin, data).Build(); } std::unique_ptr QuicTestPacketMaker::MakeInitialSettingsPacket(uint64_t packet_number) { return Packet(packet_number).MaybeAddHttp3SettingsFrames().Build(); } std::unique_ptr QuicTestPacketMaker::MakePriorityPacket(uint64_t packet_number, quic::QuicStreamId id, spdy::SpdyPriority spdy_priority) { auto& builder = Packet(packet_number); std::string priority_data = GenerateHttp3PriorityData(spdy_priority, id); if (!priority_data.empty()) { builder.AddStreamFrame(2, false, priority_data); } return builder.Build(); } std::unique_ptr QuicTestPacketMaker::MakeRetransmissionPacket(uint64_t original_packet_number, uint64_t new_packet_number) { DCHECK(connection_state_.save_packet_frames); auto& builder = Packet(new_packet_number); builder.AddPacketRetransmission(original_packet_number); return builder.Build(); } std::unique_ptr QuicTestPacketMaker::MakeStatelessResetPacket() { auto connection_id = quic::test::TestConnectionId(); return quic::QuicFramer::BuildIetfStatelessResetPacket( connection_id, quic::QuicFramer::GetMinStatelessResetPacketLength() + 1, quic::QuicUtils::GenerateStatelessResetToken(connection_id)); } void QuicTestPacketMaker::RemoveSavedStreamFrames( quic::QuicStreamId stream_id) { for (auto& kv : connection_state_.saved_frames) { auto* it = kv.second.begin(); while (it != kv.second.end()) { if (it->type == quic::STREAM_FRAME && it->stream_frame.stream_id == stream_id) { it = kv.second.erase(it); } else { ++it; } } } } void QuicTestPacketMaker::SetEncryptionLevel(quic::EncryptionLevel level) { encryption_level_ = level; switch (level) { case quic::ENCRYPTION_INITIAL: long_header_type_ = quic::INITIAL; break; case quic::ENCRYPTION_ZERO_RTT: long_header_type_ = quic::ZERO_RTT_PROTECTED; break; case quic::ENCRYPTION_FORWARD_SECURE: long_header_type_ = quic::INVALID_PACKET_TYPE; break; default: LOG(DFATAL) << quic::EncryptionLevelToString(level); long_header_type_ = quic::INVALID_PACKET_TYPE; } } quiche::HttpHeaderBlock QuicTestPacketMaker::GetRequestHeaders( const std::string& method, const std::string& scheme, const std::string& path) const { quiche::HttpHeaderBlock headers; headers[":method"] = method; headers[":authority"] = host_; headers[":scheme"] = scheme; headers[":path"] = path; return headers; } quiche::HttpHeaderBlock QuicTestPacketMaker::ConnectRequestHeaders( const std::string& host_port) const { quiche::HttpHeaderBlock headers; headers[":method"] = "CONNECT"; headers[":authority"] = host_port; return headers; } quiche::HttpHeaderBlock QuicTestPacketMaker::GetResponseHeaders( const std::string& status) const { quiche::HttpHeaderBlock headers; headers[":status"] = status; headers["content-type"] = "text/plain"; return headers; } quiche::HttpHeaderBlock QuicTestPacketMaker::GetResponseHeaders( const std::string& status, const std::string& alt_svc) const { quiche::HttpHeaderBlock headers; headers[":status"] = status; headers["alt-svc"] = alt_svc; headers["content-type"] = "text/plain"; return headers; } void QuicTestPacketMaker::Reset() { connection_state_.Reset(); } std::string QuicTestPacketMaker::QpackEncodeHeaders( quic::QuicStreamId stream_id, quiche::HttpHeaderBlock headers, size_t* encoded_data_length) { std::string data; std::string encoded_headers = qpack_encoder_.EncodeHeaderList(stream_id, headers, nullptr); // Generate HEADERS frame header. const std::string headers_frame_header = quic::HttpEncoder::SerializeHeadersFrameHeader(encoded_headers.size()); // Add the HEADERS frame header. data += headers_frame_header; // Add the HEADERS frame payload. data += encoded_headers; // Compute the total data length. if (encoded_data_length) { *encoded_data_length = data.length(); } return data; } std::unique_ptr QuicTestPacketMaker::FinishPacket( quic::QuicPacketHeader header, quic::QuicFrames frames, std::unique_ptr data_producer) { CHECK(builder_); builder_ = nullptr; quic::QuicFramer framer(quic::test::SupportedVersions(version_), clock_->Now(), perspective_, quic::kQuicDefaultConnectionIdLength); if (encryption_level_ == quic::ENCRYPTION_INITIAL) { framer.SetInitialObfuscators(perspective_ == quic::Perspective::IS_CLIENT ? header.destination_connection_id : header.source_connection_id); } else { framer.SetEncrypter( encryption_level_, std::make_unique( // IN-TEST encryption_level_)); } if (data_producer != nullptr) { framer.set_data_producer(data_producer.get()); } size_t max_plaintext_size = framer.GetMaxPlaintextSize(max_plaintext_size_); size_t packet_size = quic::GetPacketHeaderSize(version_.transport_version, header); size_t frames_size = 0; for (size_t i = 0; i < frames.size(); ++i) { bool first_frame = i == 0; bool last_frame = i == frames.size() - 1; const size_t frame_size = framer.GetSerializedFrameLength( frames[i], max_plaintext_size - packet_size, first_frame, last_frame, header.packet_number_length); packet_size += frame_size; frames_size += frame_size; } const size_t min_plaintext_packet_size = quic::QuicPacketCreator::MinPlaintextPacketSize( version_, header.packet_number_length); if (frames_size < min_plaintext_packet_size) { frames.insert(frames.begin(), quic::QuicFrame(quic::QuicPaddingFrame( min_plaintext_packet_size - frames_size))); } std::unique_ptr packet(quic::test::BuildUnsizedDataPacket( &framer, header, frames, max_plaintext_size)); char buffer[quic::kMaxOutgoingPacketSize]; size_t encrypted_size = framer.EncryptPayload(encryption_level_, header.packet_number, *packet, buffer, quic::kMaxOutgoingPacketSize); EXPECT_NE(0u, encrypted_size); quic::QuicReceivedPacket encrypted(buffer, encrypted_size, clock_->Now(), false, 0, true, nullptr, 0, false, ecn_codepoint_); if (connection_state_.save_packet_frames) { connection_state_.saved_frames[header.packet_number] = std::move(frames); } else { connection_state_.saved_stream_data.clear(); DeleteFrames(&frames); } return encrypted.Clone(); } quic::QuicStreamId QuicTestPacketMaker::GetFirstBidirectionalStreamId() const { return quic::QuicUtils::GetFirstBidirectionalStreamId( version_.transport_version, perspective_); } std::string QuicTestPacketMaker::GenerateHttp3PriorityData( spdy::SpdyPriority spdy_priority, quic::QuicStreamId stream_id) { std::string priority_data; quic::PriorityUpdateFrame priority_update; quic::HttpStreamPriority priority{ spdy_priority, quic::HttpStreamPriority::kDefaultIncremental}; if (client_priority_uses_incremental_) { priority.incremental = kDefaultPriorityIncremental; } if (priority.urgency != quic::HttpStreamPriority::kDefaultUrgency || priority.incremental != quic::HttpStreamPriority::kDefaultIncremental) { priority_update.priority_field_value = quic::SerializePriorityFieldValue(priority); } // Only generate a frame if a non-empty string was generated. if (!priority_update.priority_field_value.empty()) { priority_update.prioritized_element_id = stream_id; priority_data = quic::HttpEncoder::SerializePriorityUpdateFrame(priority_update); } return priority_data; } void QuicTestPacketMaker::AddPriorityHeader(spdy::SpdyPriority spdy_priority, quiche::HttpHeaderBlock* headers) { if (use_priority_header_) { quic::HttpStreamPriority priority{ spdy_priority, quic::HttpStreamPriority::kDefaultIncremental}; if (client_priority_uses_incremental_) { priority.incremental = kDefaultPriorityIncremental; } std::string serialized_priority = quic::SerializePriorityFieldValue(priority); if (!serialized_priority.empty()) { (*headers)[net::kHttp2PriorityHeader] = serialized_priority; } } } QuicTestPacketBuilder::QuicTestPacketBuilder( uint64_t packet_number, QuicTestPacketMaker* maker, QuicTestPacketMaker::ConnectionState* connection_state) : maker_(maker), connection_state_(connection_state) { CHECK(maker_); InitializeHeader(packet_number); } QuicTestPacketBuilder::~QuicTestPacketBuilder() { CHECK(!maker_) << "QuicTestPacketBuilder is missing a call to Build()"; DeleteFrames(&frames_); } QuicTestPacketBuilder& QuicTestPacketBuilder::AddPaddingFrame(size_t length) { quic::QuicPaddingFrame padding_frame = (length > 0) ? quic::QuicPaddingFrame(length) : quic::QuicPaddingFrame(); AddFrame(quic::QuicFrame(padding_frame)); return *this; } QuicTestPacketBuilder& QuicTestPacketBuilder::AddPingFrame() { quic::QuicPingFrame ping_frame; AddFrame(quic::QuicFrame(ping_frame)); return *this; } QuicTestPacketBuilder& QuicTestPacketBuilder::AddRetireConnectionIdFrame( uint64_t sequence_number) { auto* retire_cid_frame = new quic::QuicRetireConnectionIdFrame(); retire_cid_frame->sequence_number = sequence_number; AddFrame(quic::QuicFrame(retire_cid_frame)); return *this; } QuicTestPacketBuilder& QuicTestPacketBuilder::AddNewConnectionIdFrame( const quic::QuicConnectionId& cid, uint64_t sequence_number, uint64_t retire_prior_to) { auto* new_cid_frame = new quic::QuicNewConnectionIdFrame(); new_cid_frame->connection_id = cid; new_cid_frame->sequence_number = sequence_number; new_cid_frame->retire_prior_to = retire_prior_to; new_cid_frame->stateless_reset_token = quic::QuicUtils::GenerateStatelessResetToken(cid); AddFrame(quic::QuicFrame(new_cid_frame)); return *this; } QuicTestPacketBuilder& QuicTestPacketBuilder::AddMaxStreamsFrame( quic::QuicControlFrameId control_frame_id, quic::QuicStreamCount stream_count, bool unidirectional) { quic::QuicMaxStreamsFrame max_streams_frame(control_frame_id, stream_count, unidirectional); AddFrame(quic::QuicFrame(max_streams_frame)); return *this; } QuicTestPacketBuilder& QuicTestPacketBuilder::AddStreamsBlockedFrame( quic::QuicControlFrameId control_frame_id, quic::QuicStreamCount stream_count, bool unidirectional) { quic::QuicStreamsBlockedFrame streams_blocked_frame( control_frame_id, stream_count, unidirectional); AddFrame(quic::QuicFrame(streams_blocked_frame)); return *this; } QuicTestPacketBuilder& QuicTestPacketBuilder::AddStreamFrame( quic::QuicStreamId stream_id, bool fin, std::string_view data) { quic::QuicStreamOffset offset = connection_state_->stream_offsets[stream_id]; std::string_view saved_data = connection_state_->SaveStreamData(data); quic::QuicStreamFrame stream_frame(stream_id, fin, offset, saved_data); AddFrame(quic::QuicFrame(stream_frame)); connection_state_->stream_offsets[stream_id] += data.length(); return *this; } QuicTestPacketBuilder& QuicTestPacketBuilder::AddAckFrame( uint64_t first_received, uint64_t largest_received, uint64_t smallest_received, std::optional ecn) { auto* ack_frame = new quic::QuicAckFrame; ack_frame->largest_acked = quic::QuicPacketNumber(largest_received); ack_frame->ack_delay_time = quic::QuicTime::Delta::Zero(); for (uint64_t i = smallest_received; i <= largest_received; ++i) { ack_frame->received_packet_times.emplace_back(quic::QuicPacketNumber(i), maker_->clock()->Now()); } if (largest_received > 0) { DCHECK_GE(largest_received, first_received); ack_frame->packets.AddRange(quic::QuicPacketNumber(first_received), quic::QuicPacketNumber(largest_received + 1)); } ack_frame->ecn_counters = ecn; AddFrame(quic::QuicFrame(ack_frame)); return *this; } QuicTestPacketBuilder& QuicTestPacketBuilder::AddMessageFrame( std::string_view data) { auto* message_frame = new quic::QuicMessageFrame( /*message_id=*/0, quiche::QuicheMemSlice(quiche::QuicheBuffer::Copy( quiche::SimpleBufferAllocator::Get(), data))); AddFrame(quic::QuicFrame(message_frame)); return *this; } QuicTestPacketBuilder& QuicTestPacketBuilder::AddRstStreamFrame( quic::QuicStreamId stream_id, quic::QuicRstStreamErrorCode error_code) { auto* rst_stream_frame = new quic::QuicRstStreamFrame( 1, stream_id, error_code, connection_state_->stream_offsets[stream_id]); AddFrame(quic::QuicFrame(rst_stream_frame)); return *this; } QuicTestPacketBuilder& QuicTestPacketBuilder::AddConnectionCloseFrame( quic::QuicErrorCode quic_error, const std::string& quic_error_details, uint64_t frame_type) { auto* close_frame = new quic::QuicConnectionCloseFrame( maker_->version().transport_version, quic_error, quic::NO_IETF_QUIC_ERROR, quic_error_details, frame_type); AddFrame(quic::QuicFrame(close_frame)); return *this; } QuicTestPacketBuilder& QuicTestPacketBuilder::AddGoAwayFrame( quic::QuicErrorCode error_code, std::string reason_phrase) { auto* goaway_frame = new quic::QuicGoAwayFrame(); goaway_frame->error_code = error_code; goaway_frame->last_good_stream_id = 0; goaway_frame->reason_phrase = reason_phrase; AddFrame(quic::QuicFrame(goaway_frame)); return *this; } QuicTestPacketBuilder& QuicTestPacketBuilder::AddPathResponseFrame() { quic::test::MockRandom rand(0); quic::QuicPathFrameBuffer payload; rand.RandBytes(payload.data(), payload.size()); auto path_response_frame = quic::QuicPathResponseFrame(0, payload); AddFrame(quic::QuicFrame(path_response_frame)); return *this; } QuicTestPacketBuilder& QuicTestPacketBuilder::AddPathChallengeFrame() { quic::test::MockRandom rand(0); quic::QuicPathFrameBuffer payload; rand.RandBytes(payload.data(), payload.size()); auto path_challenge_frame = quic::QuicPathChallengeFrame(0, payload); AddFrame(quic::QuicFrame(path_challenge_frame)); return *this; } QuicTestPacketBuilder& QuicTestPacketBuilder::AddStopSendingFrame( quic::QuicStreamId stream_id, quic::QuicRstStreamErrorCode error_code) { auto stop_sending_frame = quic::QuicStopSendingFrame(1, stream_id, error_code); AddFrame(quic::QuicFrame(stop_sending_frame)); return *this; } QuicTestPacketBuilder& QuicTestPacketBuilder::AddCryptoFrame( quic::EncryptionLevel level, quic::QuicStreamOffset offset, const quic::QuicData& data) { if (!data_producer_) { data_producer_ = std::make_unique(); // IN-TEST } data_producer_->SaveCryptoData(level, offset, data.AsStringPiece()); auto* crypto_frame = new quic::QuicCryptoFrame(level, offset, data.length()); AddFrame(quic::QuicFrame(crypto_frame)); return *this; } QuicTestPacketBuilder& QuicTestPacketBuilder::AddFrame(quic::QuicFrame frame) { CHECK(maker_); frames_.push_back(std::move(frame)); DVLOG(1) << "Adding frame: " << frames_.back(); return *this; } QuicTestPacketBuilder& QuicTestPacketBuilder::AddFrameWithCoalescing( const quic::QuicFrame& frame) { if (frames_.empty()) { return AddFrame(frame); } if (frame.type != quic::STREAM_FRAME || frames_.back().type != quic::STREAM_FRAME) { return AddFrame(frame); } // Make sure they are congruent data segments in the stream. const quic::QuicStreamFrame* new_frame = &frame.stream_frame; quic::QuicStreamFrame* previous_frame = &frames_.back().stream_frame; if (new_frame->stream_id != previous_frame->stream_id || new_frame->offset != previous_frame->offset + previous_frame->data_length) { return AddFrame(frame); } // Extend the data buffer to include the data from both frames (into a copy // buffer). This doesn't attempt to limit coalescing to a particular packet // size limit and may need to be updated if a test comes along that // retransmits enough stream data to span multiple packets. std::string data(previous_frame->data_buffer, previous_frame->data_length); data += std::string(new_frame->data_buffer, new_frame->data_length); connection_state_->saved_stream_data.push_back( std::make_unique(data)); std::string_view saved_data = *connection_state_->saved_stream_data.back(); previous_frame->data_buffer = saved_data.data(); previous_frame->data_length = saved_data.length(); // Copy the fin state from the last frame. previous_frame->fin = new_frame->fin; return *this; } QuicTestPacketBuilder& QuicTestPacketBuilder::AddPacketRetransmission( uint64_t packet_number, base::RepeatingCallback filter) { for (auto frame : connection_state_->saved_frames[quic::QuicPacketNumber(packet_number)]) { if (!filter || filter.Run(frame)) { AddFrameWithCoalescing(frame); } } return *this; } std::unique_ptr QuicTestPacketBuilder::Build() { CHECK(maker_); QuicTestPacketMaker* maker = maker_; maker_ = nullptr; return maker->FinishPacket(std::move(header_), std::move(frames_), std::move(data_producer_)); } QuicTestPacketBuilder& QuicTestPacketBuilder::MaybeAddHttp3SettingsFrames() { quic::QuicStreamId stream_id = quic::QuicUtils::GetFirstUnidirectionalStreamId( maker_->version().transport_version, maker_->perspective()); // If the control stream has already been written to, do nothing. if (connection_state_->stream_offsets[stream_id] != 0) { return *this; } // A stream frame containing stream type will be written on the control // stream first. std::string type(1, 0x00); std::string settings_data = GenerateHttp3SettingsData(); std::string grease_data = GenerateHttp3GreaseData(); // The type and the SETTINGS frame may be sent in multiple QUIC STREAM // frames. std::string data = type + settings_data + grease_data; AddStreamFrame(stream_id, false, data); return *this; } std::string QuicTestPacketBuilder::GenerateHttp3SettingsData() const { quic::SettingsFrame settings; settings.values[quic::SETTINGS_MAX_FIELD_SECTION_SIZE] = kQuicMaxHeaderListSize; settings.values[quic::SETTINGS_QPACK_MAX_TABLE_CAPACITY] = quic::kDefaultQpackMaxDynamicTableCapacity; settings.values[quic::SETTINGS_QPACK_BLOCKED_STREAMS] = quic::kDefaultMaximumBlockedStreams; settings.values[quic::SETTINGS_H3_DATAGRAM] = 1; // Greased setting. settings.values[0x40] = 20; return quic::HttpEncoder::SerializeSettingsFrame(settings); } std::string QuicTestPacketBuilder::GenerateHttp3GreaseData() const { return quic::HttpEncoder::SerializeGreasingFrame(); } void QuicTestPacketBuilder::InitializeHeader(uint64_t packet_number) { header_.destination_connection_id = DestinationConnectionId(); header_.destination_connection_id_included = quic::CONNECTION_ID_PRESENT; header_.source_connection_id = SourceConnectionId(); header_.source_connection_id_included = quic::CONNECTION_ID_PRESENT; header_.reset_flag = false; header_.version_flag = ShouldIncludeVersion(); header_.form = header_.version_flag ? quic::IETF_QUIC_LONG_HEADER_PACKET : quic::IETF_QUIC_SHORT_HEADER_PACKET; header_.long_packet_type = maker_->long_header_type(); header_.packet_number_length = quic::PACKET_1BYTE_PACKET_NUMBER; header_.packet_number = quic::QuicPacketNumber(packet_number); if (header_.version_flag) { if (maker_->long_header_type() == quic::INITIAL) { header_.retry_token_length_length = quiche::VARIABLE_LENGTH_INTEGER_LENGTH_1; } header_.length_length = quiche::VARIABLE_LENGTH_INTEGER_LENGTH_2; } } quic::QuicConnectionId QuicTestPacketBuilder::DestinationConnectionId() const { if (maker_->perspective() == quic::Perspective::IS_SERVER) { return quic::EmptyQuicConnectionId(); } return maker_->connection_id(); } quic::QuicConnectionId QuicTestPacketBuilder::SourceConnectionId() const { if (maker_->perspective() == quic::Perspective::IS_CLIENT) { return quic::EmptyQuicConnectionId(); } return maker_->connection_id(); } bool QuicTestPacketBuilder::ShouldIncludeVersion() const { return maker_->encryption_level() < quic::ENCRYPTION_FORWARD_SECURE; } } // namespace net::test