|  | // 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 "quic/test_tools/first_flight.h" | 
|  |  | 
|  | #include <memory> | 
|  | #include <vector> | 
|  |  | 
|  | #include "quic/core/crypto/quic_crypto_client_config.h" | 
|  | #include "quic/core/http/quic_client_push_promise_index.h" | 
|  | #include "quic/core/http/quic_spdy_client_session.h" | 
|  | #include "quic/core/quic_config.h" | 
|  | #include "quic/core/quic_connection.h" | 
|  | #include "quic/core/quic_connection_id.h" | 
|  | #include "quic/core/quic_packet_writer.h" | 
|  | #include "quic/core/quic_packets.h" | 
|  | #include "quic/core/quic_versions.h" | 
|  | #include "quic/platform/api/quic_ip_address.h" | 
|  | #include "quic/platform/api/quic_socket_address.h" | 
|  | #include "quic/test_tools/crypto_test_utils.h" | 
|  | #include "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) | 
|  | : version_(version), | 
|  | server_connection_id_(server_connection_id), | 
|  | client_connection_id_(client_connection_id), | 
|  | writer_(this), | 
|  | config_(config), | 
|  | crypto_config_(crypto_test_utils::ProofVerifierForTesting()) { | 
|  | EXPECT_NE(version_, UnsupportedQuicVersion()); | 
|  | } | 
|  |  | 
|  | 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_->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_, &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_); | 
|  | } | 
|  |  | 
|  | private: | 
|  | ParsedQuicVersion version_; | 
|  | QuicConnectionId server_connection_id_; | 
|  | QuicConnectionId client_connection_id_; | 
|  | MockQuicConnectionHelper connection_helper_; | 
|  | MockAlarmFactory alarm_factory_; | 
|  | DelegatedPacketWriter writer_; | 
|  | QuicConfig config_; | 
|  | QuicCryptoClientConfig crypto_config_; | 
|  | QuicClientPushPromiseIndex push_promise_index_; | 
|  | QuicConnection* connection_;  // Owned by session_. | 
|  | std::unique_ptr<QuicSpdyClientSession> session_; | 
|  | std::vector<std::unique_ptr<QuicReceivedPacket>> packets_; | 
|  | }; | 
|  |  | 
|  | 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()); | 
|  | } | 
|  |  | 
|  | }  // namespace test | 
|  | }  // namespace quic |