1 // Copyright (c) 2020 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "quiche/quic/test_tools/first_flight.h"
6
7 #include <memory>
8 #include <vector>
9
10 #include "quiche/quic/core/crypto/quic_crypto_client_config.h"
11 #include "quiche/quic/core/http/quic_client_push_promise_index.h"
12 #include "quiche/quic/core/http/quic_spdy_client_session.h"
13 #include "quiche/quic/core/quic_config.h"
14 #include "quiche/quic/core/quic_connection.h"
15 #include "quiche/quic/core/quic_connection_id.h"
16 #include "quiche/quic/core/quic_packet_writer.h"
17 #include "quiche/quic/core/quic_packets.h"
18 #include "quiche/quic/core/quic_types.h"
19 #include "quiche/quic/core/quic_versions.h"
20 #include "quiche/quic/platform/api/quic_ip_address.h"
21 #include "quiche/quic/platform/api/quic_socket_address.h"
22 #include "quiche/quic/test_tools/crypto_test_utils.h"
23 #include "quiche/quic/test_tools/mock_connection_id_generator.h"
24 #include "quiche/quic/test_tools/quic_test_utils.h"
25
26 namespace quic {
27 namespace test {
28
29 // Utility class that creates a custom HTTP/3 session and QUIC connection in
30 // order to extract the first flight of packets it sends. This is meant to only
31 // be used by GetFirstFlightOfPackets() below.
32 class FirstFlightExtractor : public DelegatedPacketWriter::Delegate {
33 public:
FirstFlightExtractor(const ParsedQuicVersion & version,const QuicConfig & config,const QuicConnectionId & server_connection_id,const QuicConnectionId & client_connection_id,std::unique_ptr<QuicCryptoClientConfig> crypto_config)34 FirstFlightExtractor(const ParsedQuicVersion& version,
35 const QuicConfig& config,
36 const QuicConnectionId& server_connection_id,
37 const QuicConnectionId& client_connection_id,
38 std::unique_ptr<QuicCryptoClientConfig> crypto_config)
39 : version_(version),
40 server_connection_id_(server_connection_id),
41 client_connection_id_(client_connection_id),
42 writer_(this),
43 config_(config),
44 crypto_config_(std::move(crypto_config)) {
45 EXPECT_NE(version_, UnsupportedQuicVersion());
46 }
47
FirstFlightExtractor(const ParsedQuicVersion & version,const QuicConfig & config,const QuicConnectionId & server_connection_id,const QuicConnectionId & client_connection_id)48 FirstFlightExtractor(const ParsedQuicVersion& version,
49 const QuicConfig& config,
50 const QuicConnectionId& server_connection_id,
51 const QuicConnectionId& client_connection_id)
52 : FirstFlightExtractor(
53 version, config, server_connection_id, client_connection_id,
54 std::make_unique<QuicCryptoClientConfig>(
55 crypto_test_utils::ProofVerifierForTesting())) {}
56
GenerateFirstFlight()57 void GenerateFirstFlight() {
58 crypto_config_->set_alpn(AlpnForVersion(version_));
59 connection_ = new QuicConnection(
60 server_connection_id_,
61 /*initial_self_address=*/QuicSocketAddress(),
62 QuicSocketAddress(TestPeerIPAddress(), kTestPort), &connection_helper_,
63 &alarm_factory_, &writer_,
64 /*owns_writer=*/false, Perspective::IS_CLIENT,
65 ParsedQuicVersionVector{version_}, connection_id_generator_);
66 connection_->set_client_connection_id(client_connection_id_);
67 session_ = std::make_unique<QuicSpdyClientSession>(
68 config_, ParsedQuicVersionVector{version_},
69 connection_, // session_ takes ownership of connection_ here.
70 TestServerId(), crypto_config_.get(), &push_promise_index_);
71 session_->Initialize();
72 session_->CryptoConnect();
73 }
74
OnDelegatedPacket(const char * buffer,size_t buf_len,const QuicIpAddress &,const QuicSocketAddress &,PerPacketOptions *)75 void OnDelegatedPacket(const char* buffer, size_t buf_len,
76 const QuicIpAddress& /*self_client_address*/,
77 const QuicSocketAddress& /*peer_client_address*/,
78 PerPacketOptions* /*options*/) override {
79 packets_.emplace_back(
80 QuicReceivedPacket(buffer, buf_len,
81 connection_helper_.GetClock()->ApproximateNow(),
82 /*owns_buffer=*/false)
83 .Clone());
84 }
85
ConsumePackets()86 std::vector<std::unique_ptr<QuicReceivedPacket>>&& ConsumePackets() {
87 return std::move(packets_);
88 }
89
GetCryptoStreamBytesWritten() const90 uint64_t GetCryptoStreamBytesWritten() const {
91 QUICHE_DCHECK(session_);
92 QUICHE_DCHECK(session_->GetCryptoStream());
93 return session_->GetCryptoStream()->BytesSentOnLevel(
94 EncryptionLevel::ENCRYPTION_INITIAL);
95 }
96
97 private:
98 ParsedQuicVersion version_;
99 QuicConnectionId server_connection_id_;
100 QuicConnectionId client_connection_id_;
101 MockQuicConnectionHelper connection_helper_;
102 MockAlarmFactory alarm_factory_;
103 DelegatedPacketWriter writer_;
104 QuicConfig config_;
105 std::unique_ptr<QuicCryptoClientConfig> crypto_config_;
106 QuicClientPushPromiseIndex push_promise_index_;
107 QuicConnection* connection_; // Owned by session_.
108 std::unique_ptr<QuicSpdyClientSession> session_;
109 std::vector<std::unique_ptr<QuicReceivedPacket>> packets_;
110 MockConnectionIdGenerator connection_id_generator_;
111 };
112
GetFirstFlightOfPackets(const ParsedQuicVersion & version,const QuicConfig & config,const QuicConnectionId & server_connection_id,const QuicConnectionId & client_connection_id,std::unique_ptr<QuicCryptoClientConfig> crypto_config)113 std::vector<std::unique_ptr<QuicReceivedPacket>> GetFirstFlightOfPackets(
114 const ParsedQuicVersion& version, const QuicConfig& config,
115 const QuicConnectionId& server_connection_id,
116 const QuicConnectionId& client_connection_id,
117 std::unique_ptr<QuicCryptoClientConfig> crypto_config) {
118 FirstFlightExtractor first_flight_extractor(
119 version, config, server_connection_id, client_connection_id,
120 std::move(crypto_config));
121 first_flight_extractor.GenerateFirstFlight();
122 return first_flight_extractor.ConsumePackets();
123 }
124
GetFirstFlightOfPackets(const ParsedQuicVersion & version,const QuicConfig & config,const QuicConnectionId & server_connection_id,const QuicConnectionId & client_connection_id)125 std::vector<std::unique_ptr<QuicReceivedPacket>> GetFirstFlightOfPackets(
126 const ParsedQuicVersion& version, const QuicConfig& config,
127 const QuicConnectionId& server_connection_id,
128 const QuicConnectionId& client_connection_id) {
129 FirstFlightExtractor first_flight_extractor(
130 version, config, server_connection_id, client_connection_id);
131 first_flight_extractor.GenerateFirstFlight();
132 return first_flight_extractor.ConsumePackets();
133 }
134
GetFirstFlightOfPackets(const ParsedQuicVersion & version,const QuicConfig & config,const QuicConnectionId & server_connection_id)135 std::vector<std::unique_ptr<QuicReceivedPacket>> GetFirstFlightOfPackets(
136 const ParsedQuicVersion& version, const QuicConfig& config,
137 const QuicConnectionId& server_connection_id) {
138 return GetFirstFlightOfPackets(version, config, server_connection_id,
139 EmptyQuicConnectionId());
140 }
141
GetFirstFlightOfPackets(const ParsedQuicVersion & version,const QuicConfig & config)142 std::vector<std::unique_ptr<QuicReceivedPacket>> GetFirstFlightOfPackets(
143 const ParsedQuicVersion& version, const QuicConfig& config) {
144 return GetFirstFlightOfPackets(version, config, TestConnectionId());
145 }
146
GetFirstFlightOfPackets(const ParsedQuicVersion & version,const QuicConnectionId & server_connection_id,const QuicConnectionId & client_connection_id)147 std::vector<std::unique_ptr<QuicReceivedPacket>> GetFirstFlightOfPackets(
148 const ParsedQuicVersion& version,
149 const QuicConnectionId& server_connection_id,
150 const QuicConnectionId& client_connection_id) {
151 return GetFirstFlightOfPackets(version, DefaultQuicConfig(),
152 server_connection_id, client_connection_id);
153 }
154
GetFirstFlightOfPackets(const ParsedQuicVersion & version,const QuicConnectionId & server_connection_id)155 std::vector<std::unique_ptr<QuicReceivedPacket>> GetFirstFlightOfPackets(
156 const ParsedQuicVersion& version,
157 const QuicConnectionId& server_connection_id) {
158 return GetFirstFlightOfPackets(version, DefaultQuicConfig(),
159 server_connection_id, EmptyQuicConnectionId());
160 }
161
GetFirstFlightOfPackets(const ParsedQuicVersion & version)162 std::vector<std::unique_ptr<QuicReceivedPacket>> GetFirstFlightOfPackets(
163 const ParsedQuicVersion& version) {
164 return GetFirstFlightOfPackets(version, DefaultQuicConfig(),
165 TestConnectionId());
166 }
167
GetAnnotatedFirstFlightOfPackets(const ParsedQuicVersion & version,const QuicConfig & config,const QuicConnectionId & server_connection_id,const QuicConnectionId & client_connection_id,std::unique_ptr<QuicCryptoClientConfig> crypto_config)168 AnnotatedPackets GetAnnotatedFirstFlightOfPackets(
169 const ParsedQuicVersion& version, const QuicConfig& config,
170 const QuicConnectionId& server_connection_id,
171 const QuicConnectionId& client_connection_id,
172 std::unique_ptr<QuicCryptoClientConfig> crypto_config) {
173 FirstFlightExtractor first_flight_extractor(
174 version, config, server_connection_id, client_connection_id,
175 std::move(crypto_config));
176 first_flight_extractor.GenerateFirstFlight();
177 return AnnotatedPackets{first_flight_extractor.ConsumePackets(),
178 first_flight_extractor.GetCryptoStreamBytesWritten()};
179 }
180
GetAnnotatedFirstFlightOfPackets(const ParsedQuicVersion & version,const QuicConfig & config)181 AnnotatedPackets GetAnnotatedFirstFlightOfPackets(
182 const ParsedQuicVersion& version, const QuicConfig& config) {
183 FirstFlightExtractor first_flight_extractor(
184 version, config, TestConnectionId(), EmptyQuicConnectionId());
185 first_flight_extractor.GenerateFirstFlight();
186 return AnnotatedPackets{first_flight_extractor.ConsumePackets(),
187 first_flight_extractor.GetCryptoStreamBytesWritten()};
188 }
189
190 } // namespace test
191 } // namespace quic
192