| // Copyright (c) 2020 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 "quiche/quic/test_tools/first_flight.h" | |
| #include <memory> | |
| #include <vector> | |
| #include "quiche/quic/core/crypto/quic_crypto_client_config.h" | |
| #include "quiche/quic/core/http/quic_client_push_promise_index.h" | |
| #include "quiche/quic/core/http/quic_spdy_client_session.h" | |
| #include "quiche/quic/core/quic_config.h" | |
| #include "quiche/quic/core/quic_connection.h" | |
| #include "quiche/quic/core/quic_connection_id.h" | |
| #include "quiche/quic/core/quic_packet_writer.h" | |
| #include "quiche/quic/core/quic_packets.h" | |
| #include "quiche/quic/core/quic_types.h" | |
| #include "quiche/quic/core/quic_versions.h" | |
| #include "quiche/quic/platform/api/quic_ip_address.h" | |
| #include "quiche/quic/platform/api/quic_socket_address.h" | |
| #include "quiche/quic/test_tools/crypto_test_utils.h" | |
| #include "quiche/quic/test_tools/mock_connection_id_generator.h" | |
| #include "quiche/quic/test_tools/quic_test_utils.h" | |
| namespace quic { | |
| namespace test { | |
| // Utility class that creates a custom HTTP/3 session and QUIC connection in | |
| // order to extract the first flight of packets it sends. This is meant to only | |
| // be used by GetFirstFlightOfPackets() below. | |
| class FirstFlightExtractor : public DelegatedPacketWriter::Delegate { | |
| public: | |
| FirstFlightExtractor(const ParsedQuicVersion& version, | |
| const QuicConfig& config, | |
| const QuicConnectionId& server_connection_id, | |
| const QuicConnectionId& client_connection_id, | |
| std::unique_ptr<QuicCryptoClientConfig> crypto_config) | |
| : version_(version), | |
| server_connection_id_(server_connection_id), | |
| client_connection_id_(client_connection_id), | |
| writer_(this), | |
| config_(config), | |
| crypto_config_(std::move(crypto_config)) { | |
| EXPECT_NE(version_, UnsupportedQuicVersion()); | |
| } | |
| FirstFlightExtractor(const ParsedQuicVersion& version, | |
| const QuicConfig& config, | |
| const QuicConnectionId& server_connection_id, | |
| const QuicConnectionId& client_connection_id) | |
| : FirstFlightExtractor( | |
| version, config, server_connection_id, client_connection_id, | |
| std::make_unique<QuicCryptoClientConfig>( | |
| crypto_test_utils::ProofVerifierForTesting())) {} | |
| void GenerateFirstFlight() { | |
| crypto_config_->set_alpn(AlpnForVersion(version_)); | |
| connection_ = new QuicConnection( | |
| server_connection_id_, | |
| /*initial_self_address=*/QuicSocketAddress(), | |
| QuicSocketAddress(TestPeerIPAddress(), kTestPort), &connection_helper_, | |
| &alarm_factory_, &writer_, | |
| /*owns_writer=*/false, Perspective::IS_CLIENT, | |
| ParsedQuicVersionVector{version_}, connection_id_generator_); | |
| connection_->set_client_connection_id(client_connection_id_); | |
| session_ = std::make_unique<QuicSpdyClientSession>( | |
| config_, ParsedQuicVersionVector{version_}, | |
| connection_, // session_ takes ownership of connection_ here. | |
| TestServerId(), crypto_config_.get(), &push_promise_index_); | |
| session_->Initialize(); | |
| session_->CryptoConnect(); | |
| } | |
| void OnDelegatedPacket(const char* buffer, size_t buf_len, | |
| const QuicIpAddress& /*self_client_address*/, | |
| const QuicSocketAddress& /*peer_client_address*/, | |
| PerPacketOptions* /*options*/) override { | |
| packets_.emplace_back( | |
| QuicReceivedPacket(buffer, buf_len, | |
| connection_helper_.GetClock()->ApproximateNow(), | |
| /*owns_buffer=*/false) | |
| .Clone()); | |
| } | |
| std::vector<std::unique_ptr<QuicReceivedPacket>>&& ConsumePackets() { | |
| return std::move(packets_); | |
| } | |
| uint64_t GetCryptoStreamBytesWritten() const { | |
| QUICHE_DCHECK(session_); | |
| QUICHE_DCHECK(session_->GetCryptoStream()); | |
| return session_->GetCryptoStream()->BytesSentOnLevel( | |
| EncryptionLevel::ENCRYPTION_INITIAL); | |
| } | |
| private: | |
| ParsedQuicVersion version_; | |
| QuicConnectionId server_connection_id_; | |
| QuicConnectionId client_connection_id_; | |
| MockQuicConnectionHelper connection_helper_; | |
| MockAlarmFactory alarm_factory_; | |
| DelegatedPacketWriter writer_; | |
| QuicConfig config_; | |
| std::unique_ptr<QuicCryptoClientConfig> crypto_config_; | |
| QuicClientPushPromiseIndex push_promise_index_; | |
| QuicConnection* connection_; // Owned by session_. | |
| std::unique_ptr<QuicSpdyClientSession> session_; | |
| std::vector<std::unique_ptr<QuicReceivedPacket>> packets_; | |
| MockConnectionIdGenerator connection_id_generator_; | |
| }; | |
| std::vector<std::unique_ptr<QuicReceivedPacket>> GetFirstFlightOfPackets( | |
| const ParsedQuicVersion& version, const QuicConfig& config, | |
| const QuicConnectionId& server_connection_id, | |
| const QuicConnectionId& client_connection_id, | |
| std::unique_ptr<QuicCryptoClientConfig> crypto_config) { | |
| FirstFlightExtractor first_flight_extractor( | |
| version, config, server_connection_id, client_connection_id, | |
| std::move(crypto_config)); | |
| first_flight_extractor.GenerateFirstFlight(); | |
| return first_flight_extractor.ConsumePackets(); | |
| } | |
| std::vector<std::unique_ptr<QuicReceivedPacket>> GetFirstFlightOfPackets( | |
| const ParsedQuicVersion& version, const QuicConfig& config, | |
| const QuicConnectionId& server_connection_id, | |
| const QuicConnectionId& client_connection_id) { | |
| FirstFlightExtractor first_flight_extractor( | |
| version, config, server_connection_id, client_connection_id); | |
| first_flight_extractor.GenerateFirstFlight(); | |
| return first_flight_extractor.ConsumePackets(); | |
| } | |
| std::vector<std::unique_ptr<QuicReceivedPacket>> GetFirstFlightOfPackets( | |
| const ParsedQuicVersion& version, const QuicConfig& config, | |
| const QuicConnectionId& server_connection_id) { | |
| return GetFirstFlightOfPackets(version, config, server_connection_id, | |
| EmptyQuicConnectionId()); | |
| } | |
| std::vector<std::unique_ptr<QuicReceivedPacket>> GetFirstFlightOfPackets( | |
| const ParsedQuicVersion& version, const QuicConfig& config) { | |
| return GetFirstFlightOfPackets(version, config, TestConnectionId()); | |
| } | |
| std::vector<std::unique_ptr<QuicReceivedPacket>> GetFirstFlightOfPackets( | |
| const ParsedQuicVersion& version, | |
| const QuicConnectionId& server_connection_id, | |
| const QuicConnectionId& client_connection_id) { | |
| return GetFirstFlightOfPackets(version, DefaultQuicConfig(), | |
| server_connection_id, client_connection_id); | |
| } | |
| std::vector<std::unique_ptr<QuicReceivedPacket>> GetFirstFlightOfPackets( | |
| const ParsedQuicVersion& version, | |
| const QuicConnectionId& server_connection_id) { | |
| return GetFirstFlightOfPackets(version, DefaultQuicConfig(), | |
| server_connection_id, EmptyQuicConnectionId()); | |
| } | |
| std::vector<std::unique_ptr<QuicReceivedPacket>> GetFirstFlightOfPackets( | |
| const ParsedQuicVersion& version) { | |
| return GetFirstFlightOfPackets(version, DefaultQuicConfig(), | |
| TestConnectionId()); | |
| } | |
| AnnotatedPackets GetAnnotatedFirstFlightOfPackets( | |
| const ParsedQuicVersion& version, const QuicConfig& config, | |
| const QuicConnectionId& server_connection_id, | |
| const QuicConnectionId& client_connection_id, | |
| std::unique_ptr<QuicCryptoClientConfig> crypto_config) { | |
| FirstFlightExtractor first_flight_extractor( | |
| version, config, server_connection_id, client_connection_id, | |
| std::move(crypto_config)); | |
| first_flight_extractor.GenerateFirstFlight(); | |
| return AnnotatedPackets{first_flight_extractor.ConsumePackets(), | |
| first_flight_extractor.GetCryptoStreamBytesWritten()}; | |
| } | |
| AnnotatedPackets GetAnnotatedFirstFlightOfPackets( | |
| const ParsedQuicVersion& version, const QuicConfig& config) { | |
| FirstFlightExtractor first_flight_extractor( | |
| version, config, TestConnectionId(), EmptyQuicConnectionId()); | |
| first_flight_extractor.GenerateFirstFlight(); | |
| return AnnotatedPackets{first_flight_extractor.ConsumePackets(), | |
| first_flight_extractor.GetCryptoStreamBytesWritten()}; | |
| } | |
| } // namespace test | |
| } // namespace quic |