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_spdy_client_session.h"
12 #include "quiche/quic/core/quic_config.h"
13 #include "quiche/quic/core/quic_connection.h"
14 #include "quiche/quic/core/quic_connection_id.h"
15 #include "quiche/quic/core/quic_packet_writer.h"
16 #include "quiche/quic/core/quic_packets.h"
17 #include "quiche/quic/core/quic_types.h"
18 #include "quiche/quic/core/quic_versions.h"
19 #include "quiche/quic/platform/api/quic_ip_address.h"
20 #include "quiche/quic/platform/api/quic_socket_address.h"
21 #include "quiche/quic/test_tools/crypto_test_utils.h"
22 #include "quiche/quic/test_tools/mock_connection_id_generator.h"
23 #include "quiche/quic/test_tools/quic_connection_peer.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(QuicEcnCodepoint ecn=ECN_NOT_ECT)57 void GenerateFirstFlight(QuicEcnCodepoint ecn = ECN_NOT_ECT) {
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 if (ecn != ECN_NOT_ECT) {
67 QuicConnectionPeer::DisableEcnCodepointValidation(connection_);
68 connection_->set_ecn_codepoint(ecn);
69 }
70 connection_->set_client_connection_id(client_connection_id_);
71 session_ = std::make_unique<QuicSpdyClientSession>(
72 config_, ParsedQuicVersionVector{version_},
73 connection_, // session_ takes ownership of connection_ here.
74 TestServerId(), crypto_config_.get());
75 session_->Initialize();
76 session_->CryptoConnect();
77 }
78
OnDelegatedPacket(const char * buffer,size_t buf_len,const QuicIpAddress &,const QuicSocketAddress &,PerPacketOptions *,const QuicPacketWriterParams & params)79 void OnDelegatedPacket(const char* buffer, size_t buf_len,
80 const QuicIpAddress& /*self_client_address*/,
81 const QuicSocketAddress& /*peer_client_address*/,
82 PerPacketOptions* /*options*/,
83 const QuicPacketWriterParams& params) override {
84 packets_.emplace_back(
85 QuicReceivedPacket(buffer, buf_len,
86 connection_helper_.GetClock()->ApproximateNow(),
87 /*owns_buffer=*/false, /*ttl=*/0, /*ttl_valid=*/true,
88 /*packet_headers=*/nullptr, /*headers_length=*/0,
89 /*owns_header_buffer=*/false, params.ecn_codepoint)
90 .Clone());
91 }
92
ConsumePackets()93 std::vector<std::unique_ptr<QuicReceivedPacket>>&& ConsumePackets() {
94 return std::move(packets_);
95 }
96
GetCryptoStreamBytesWritten() const97 uint64_t GetCryptoStreamBytesWritten() const {
98 QUICHE_DCHECK(session_);
99 QUICHE_DCHECK(session_->GetCryptoStream());
100 return session_->GetCryptoStream()->BytesSentOnLevel(
101 EncryptionLevel::ENCRYPTION_INITIAL);
102 }
103
104 private:
105 ParsedQuicVersion version_;
106 QuicConnectionId server_connection_id_;
107 QuicConnectionId client_connection_id_;
108 MockQuicConnectionHelper connection_helper_;
109 MockAlarmFactory alarm_factory_;
110 DelegatedPacketWriter writer_;
111 QuicConfig config_;
112 std::unique_ptr<QuicCryptoClientConfig> crypto_config_;
113 QuicConnection* connection_; // Owned by session_.
114 std::unique_ptr<QuicSpdyClientSession> session_;
115 std::vector<std::unique_ptr<QuicReceivedPacket>> packets_;
116 MockConnectionIdGenerator connection_id_generator_;
117 };
118
GetFirstFlightOfPackets(const ParsedQuicVersion & version,const QuicConfig & config,const QuicConnectionId & server_connection_id,const QuicConnectionId & client_connection_id,std::unique_ptr<QuicCryptoClientConfig> crypto_config,QuicEcnCodepoint ecn)119 std::vector<std::unique_ptr<QuicReceivedPacket>> GetFirstFlightOfPackets(
120 const ParsedQuicVersion& version, const QuicConfig& config,
121 const QuicConnectionId& server_connection_id,
122 const QuicConnectionId& client_connection_id,
123 std::unique_ptr<QuicCryptoClientConfig> crypto_config,
124 QuicEcnCodepoint ecn) {
125 FirstFlightExtractor first_flight_extractor(
126 version, config, server_connection_id, client_connection_id,
127 std::move(crypto_config));
128 first_flight_extractor.GenerateFirstFlight(ecn);
129 return first_flight_extractor.ConsumePackets();
130 }
131
GetFirstFlightOfPackets(const ParsedQuicVersion & version,const QuicConfig & config,const QuicConnectionId & server_connection_id,const QuicConnectionId & client_connection_id,std::unique_ptr<QuicCryptoClientConfig> crypto_config)132 std::vector<std::unique_ptr<QuicReceivedPacket>> GetFirstFlightOfPackets(
133 const ParsedQuicVersion& version, const QuicConfig& config,
134 const QuicConnectionId& server_connection_id,
135 const QuicConnectionId& client_connection_id,
136 std::unique_ptr<QuicCryptoClientConfig> crypto_config) {
137 return GetFirstFlightOfPackets(version, config, server_connection_id,
138 client_connection_id, std::move(crypto_config),
139 ECN_NOT_ECT);
140 }
141
GetFirstFlightOfPackets(const ParsedQuicVersion & version,const QuicConfig & config,const QuicConnectionId & server_connection_id,const QuicConnectionId & client_connection_id)142 std::vector<std::unique_ptr<QuicReceivedPacket>> GetFirstFlightOfPackets(
143 const ParsedQuicVersion& version, const QuicConfig& config,
144 const QuicConnectionId& server_connection_id,
145 const QuicConnectionId& client_connection_id) {
146 FirstFlightExtractor first_flight_extractor(
147 version, config, server_connection_id, client_connection_id);
148 first_flight_extractor.GenerateFirstFlight();
149 return first_flight_extractor.ConsumePackets();
150 }
151
GetFirstFlightOfPackets(const ParsedQuicVersion & version,const QuicConfig & config,const QuicConnectionId & server_connection_id)152 std::vector<std::unique_ptr<QuicReceivedPacket>> GetFirstFlightOfPackets(
153 const ParsedQuicVersion& version, const QuicConfig& config,
154 const QuicConnectionId& server_connection_id) {
155 return GetFirstFlightOfPackets(version, config, server_connection_id,
156 EmptyQuicConnectionId());
157 }
158
GetFirstFlightOfPackets(const ParsedQuicVersion & version,const QuicConfig & config)159 std::vector<std::unique_ptr<QuicReceivedPacket>> GetFirstFlightOfPackets(
160 const ParsedQuicVersion& version, const QuicConfig& config) {
161 return GetFirstFlightOfPackets(version, config, TestConnectionId());
162 }
163
GetFirstFlightOfPackets(const ParsedQuicVersion & version,const QuicConnectionId & server_connection_id,const QuicConnectionId & client_connection_id)164 std::vector<std::unique_ptr<QuicReceivedPacket>> GetFirstFlightOfPackets(
165 const ParsedQuicVersion& version,
166 const QuicConnectionId& server_connection_id,
167 const QuicConnectionId& client_connection_id) {
168 return GetFirstFlightOfPackets(version, DefaultQuicConfig(),
169 server_connection_id, client_connection_id);
170 }
171
GetFirstFlightOfPackets(const ParsedQuicVersion & version,const QuicConnectionId & server_connection_id)172 std::vector<std::unique_ptr<QuicReceivedPacket>> GetFirstFlightOfPackets(
173 const ParsedQuicVersion& version,
174 const QuicConnectionId& server_connection_id) {
175 return GetFirstFlightOfPackets(version, DefaultQuicConfig(),
176 server_connection_id, EmptyQuicConnectionId());
177 }
178
GetFirstFlightOfPackets(const ParsedQuicVersion & version)179 std::vector<std::unique_ptr<QuicReceivedPacket>> GetFirstFlightOfPackets(
180 const ParsedQuicVersion& version) {
181 return GetFirstFlightOfPackets(version, DefaultQuicConfig(),
182 TestConnectionId());
183 }
184
GetAnnotatedFirstFlightOfPackets(const ParsedQuicVersion & version,const QuicConfig & config,const QuicConnectionId & server_connection_id,const QuicConnectionId & client_connection_id,std::unique_ptr<QuicCryptoClientConfig> crypto_config)185 AnnotatedPackets GetAnnotatedFirstFlightOfPackets(
186 const ParsedQuicVersion& version, const QuicConfig& config,
187 const QuicConnectionId& server_connection_id,
188 const QuicConnectionId& client_connection_id,
189 std::unique_ptr<QuicCryptoClientConfig> crypto_config) {
190 FirstFlightExtractor first_flight_extractor(
191 version, config, server_connection_id, client_connection_id,
192 std::move(crypto_config));
193 first_flight_extractor.GenerateFirstFlight();
194 return AnnotatedPackets{first_flight_extractor.ConsumePackets(),
195 first_flight_extractor.GetCryptoStreamBytesWritten()};
196 }
197
GetAnnotatedFirstFlightOfPackets(const ParsedQuicVersion & version,const QuicConfig & config)198 AnnotatedPackets GetAnnotatedFirstFlightOfPackets(
199 const ParsedQuicVersion& version, const QuicConfig& config) {
200 FirstFlightExtractor first_flight_extractor(
201 version, config, TestConnectionId(), EmptyQuicConnectionId());
202 first_flight_extractor.GenerateFirstFlight();
203 return AnnotatedPackets{first_flight_extractor.ConsumePackets(),
204 first_flight_extractor.GetCryptoStreamBytesWritten()};
205 }
206
207 } // namespace test
208 } // namespace quic
209