blob: 7cc3ff9be3b64608d049d5a642cf8c860c839f47 [file] [log] [blame]
QUICHE teama6ef0a62019-03-07 20:34:33 -05001// Copyright (c) 2012 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
QUICHE team5be974e2020-12-29 18:35:24 -05005#include "quic/test_tools/quic_test_client.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -05006
7#include <memory>
8#include <utility>
9#include <vector>
10
vasilvv89fe24d2020-10-26 14:55:28 -070011#include "absl/strings/match.h"
vasilvv5f225b02020-10-08 11:49:09 -040012#include "absl/strings/string_view.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050013#include "third_party/boringssl/src/include/openssl/x509.h"
QUICHE team5be974e2020-12-29 18:35:24 -050014#include "quic/core/crypto/proof_verifier.h"
15#include "quic/core/http/quic_spdy_client_stream.h"
16#include "quic/core/http/spdy_utils.h"
17#include "quic/core/quic_epoll_connection_helper.h"
18#include "quic/core/quic_packet_writer_wrapper.h"
19#include "quic/core/quic_server_id.h"
20#include "quic/core/quic_utils.h"
21#include "quic/platform/api/quic_flags.h"
22#include "quic/platform/api/quic_logging.h"
QUICHE team5be974e2020-12-29 18:35:24 -050023#include "quic/platform/api/quic_stack_trace.h"
24#include "quic/test_tools/crypto_test_utils.h"
25#include "quic/test_tools/quic_client_peer.h"
26#include "quic/test_tools/quic_connection_peer.h"
27#include "quic/test_tools/quic_spdy_session_peer.h"
28#include "quic/test_tools/quic_spdy_stream_peer.h"
29#include "quic/test_tools/quic_test_utils.h"
30#include "quic/tools/quic_url.h"
bnc9de6abe2021-04-28 06:24:19 -070031#include "common/quiche_text_utils.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050032
33namespace quic {
34namespace test {
35namespace {
36
37// RecordingProofVerifier accepts any certificate chain and records the common
38// name of the leaf and then delegates the actual verification to an actual
39// verifier. If no optional verifier is provided, then VerifyProof will return
40// success.
41class RecordingProofVerifier : public ProofVerifier {
42 public:
43 explicit RecordingProofVerifier(std::unique_ptr<ProofVerifier> verifier)
44 : verifier_(std::move(verifier)) {}
45
46 // ProofVerifier interface.
47 QuicAsyncStatus VerifyProof(
vasilvvc48c8712019-03-11 13:38:16 -070048 const std::string& hostname,
QUICHE teama6ef0a62019-03-07 20:34:33 -050049 const uint16_t port,
vasilvvc48c8712019-03-11 13:38:16 -070050 const std::string& server_config,
QUICHE teama6ef0a62019-03-07 20:34:33 -050051 QuicTransportVersion transport_version,
vasilvv5f225b02020-10-08 11:49:09 -040052 absl::string_view chlo_hash,
vasilvvc48c8712019-03-11 13:38:16 -070053 const std::vector<std::string>& certs,
54 const std::string& cert_sct,
55 const std::string& signature,
QUICHE teama6ef0a62019-03-07 20:34:33 -050056 const ProofVerifyContext* context,
vasilvvc48c8712019-03-11 13:38:16 -070057 std::string* error_details,
QUICHE teama6ef0a62019-03-07 20:34:33 -050058 std::unique_ptr<ProofVerifyDetails>* details,
59 std::unique_ptr<ProofVerifierCallback> callback) override {
nharper35d60192020-03-26 12:15:47 -070060 QuicAsyncStatus process_certs_result = ProcessCerts(certs, cert_sct);
61 if (process_certs_result != QUIC_SUCCESS) {
62 return process_certs_result;
63 }
64
65 if (!verifier_) {
66 return QUIC_SUCCESS;
67 }
68
69 return verifier_->VerifyProof(hostname, port, server_config,
70 transport_version, chlo_hash, certs, cert_sct,
71 signature, context, error_details, details,
72 std::move(callback));
73 }
74
75 QuicAsyncStatus VerifyCertChain(
76 const std::string& /*hostname*/,
nharper5ab78c82020-06-05 15:03:44 -070077 const uint16_t /*port*/,
nharper35d60192020-03-26 12:15:47 -070078 const std::vector<std::string>& certs,
79 const std::string& /*ocsp_response*/,
80 const std::string& cert_sct,
81 const ProofVerifyContext* /*context*/,
82 std::string* /*error_details*/,
83 std::unique_ptr<ProofVerifyDetails>* /*details*/,
nharper54fc9ab2020-11-12 11:07:39 -080084 uint8_t* /*out_alert*/,
nharper35d60192020-03-26 12:15:47 -070085 std::unique_ptr<ProofVerifierCallback> /*callback*/) override {
86 return ProcessCerts(certs, cert_sct);
87 }
88
89 std::unique_ptr<ProofVerifyContext> CreateDefaultContext() override {
90 return verifier_ != nullptr ? verifier_->CreateDefaultContext() : nullptr;
91 }
92
93 const std::string& common_name() const { return common_name_; }
94
95 const std::string& cert_sct() const { return cert_sct_; }
96
97 private:
98 QuicAsyncStatus ProcessCerts(const std::vector<std::string>& certs,
99 const std::string& cert_sct) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500100 common_name_.clear();
101 if (certs.empty()) {
102 return QUIC_FAILURE;
103 }
104
105 const uint8_t* data;
106 data = reinterpret_cast<const uint8_t*>(certs[0].data());
107 bssl::UniquePtr<X509> cert(d2i_X509(nullptr, &data, certs[0].size()));
108 if (!cert.get()) {
109 return QUIC_FAILURE;
110 }
111
112 static const unsigned kMaxCommonNameLength = 256;
113 char buf[kMaxCommonNameLength];
114 X509_NAME* subject_name = X509_get_subject_name(cert.get());
115 if (X509_NAME_get_text_by_NID(subject_name, NID_commonName, buf,
116 sizeof(buf)) <= 0) {
117 return QUIC_FAILURE;
118 }
119
120 common_name_ = buf;
121 cert_sct_ = cert_sct;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500122 return QUIC_SUCCESS;
123 }
124
QUICHE teama6ef0a62019-03-07 20:34:33 -0500125 std::unique_ptr<ProofVerifier> verifier_;
vasilvvc48c8712019-03-11 13:38:16 -0700126 std::string common_name_;
127 std::string cert_sct_;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500128};
129} // namespace
130
131class MockableQuicClientEpollNetworkHelper
132 : public QuicClientEpollNetworkHelper {
133 public:
134 using QuicClientEpollNetworkHelper::QuicClientEpollNetworkHelper;
135 ~MockableQuicClientEpollNetworkHelper() override = default;
136
137 void ProcessPacket(const QuicSocketAddress& self_address,
138 const QuicSocketAddress& peer_address,
139 const QuicReceivedPacket& packet) override {
140 QuicClientEpollNetworkHelper::ProcessPacket(self_address, peer_address,
141 packet);
142 if (track_last_incoming_packet_) {
143 last_incoming_packet_ = packet.Clone();
144 }
145 }
146
147 QuicPacketWriter* CreateQuicPacketWriter() override {
148 QuicPacketWriter* writer =
149 QuicClientEpollNetworkHelper::CreateQuicPacketWriter();
150 if (!test_writer_) {
151 return writer;
152 }
153 test_writer_->set_writer(writer);
154 return test_writer_;
155 }
156
157 const QuicReceivedPacket* last_incoming_packet() {
158 return last_incoming_packet_.get();
159 }
160
161 void set_track_last_incoming_packet(bool track) {
162 track_last_incoming_packet_ = track;
163 }
164
165 void UseWriter(QuicPacketWriterWrapper* writer) {
vasilvvf8035162021-02-01 14:49:14 -0800166 QUICHE_CHECK(test_writer_ == nullptr);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500167 test_writer_ = writer;
168 }
169
170 void set_peer_address(const QuicSocketAddress& address) {
vasilvvf8035162021-02-01 14:49:14 -0800171 QUICHE_CHECK(test_writer_ != nullptr);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500172 test_writer_->set_peer_address(address);
173 }
174
175 private:
176 QuicPacketWriterWrapper* test_writer_ = nullptr;
177 // The last incoming packet, iff |track_last_incoming_packet_| is true.
178 std::unique_ptr<QuicReceivedPacket> last_incoming_packet_;
179 // If true, copy each packet from ProcessPacket into |last_incoming_packet_|
180 bool track_last_incoming_packet_ = false;
181};
182
183MockableQuicClient::MockableQuicClient(
184 QuicSocketAddress server_address,
185 const QuicServerId& server_id,
186 const ParsedQuicVersionVector& supported_versions,
187 QuicEpollServer* epoll_server)
188 : MockableQuicClient(server_address,
189 server_id,
190 QuicConfig(),
191 supported_versions,
192 epoll_server) {}
193
194MockableQuicClient::MockableQuicClient(
195 QuicSocketAddress server_address,
196 const QuicServerId& server_id,
197 const QuicConfig& config,
198 const ParsedQuicVersionVector& supported_versions,
199 QuicEpollServer* epoll_server)
200 : MockableQuicClient(server_address,
201 server_id,
202 config,
203 supported_versions,
204 epoll_server,
205 nullptr) {}
206
207MockableQuicClient::MockableQuicClient(
208 QuicSocketAddress server_address,
209 const QuicServerId& server_id,
210 const QuicConfig& config,
211 const ParsedQuicVersionVector& supported_versions,
212 QuicEpollServer* epoll_server,
213 std::unique_ptr<ProofVerifier> proof_verifier)
nharper2110bbd2020-06-08 18:24:30 -0700214 : MockableQuicClient(server_address,
215 server_id,
216 config,
217 supported_versions,
218 epoll_server,
219 std::move(proof_verifier),
220 nullptr) {}
221
222MockableQuicClient::MockableQuicClient(
223 QuicSocketAddress server_address,
224 const QuicServerId& server_id,
225 const QuicConfig& config,
226 const ParsedQuicVersionVector& supported_versions,
227 QuicEpollServer* epoll_server,
228 std::unique_ptr<ProofVerifier> proof_verifier,
229 std::unique_ptr<SessionCache> session_cache)
QUICHE teama6ef0a62019-03-07 20:34:33 -0500230 : QuicClient(
231 server_address,
232 server_id,
233 supported_versions,
234 config,
235 epoll_server,
vasilvv0fc587f2019-09-06 13:33:08 -0700236 std::make_unique<MockableQuicClientEpollNetworkHelper>(epoll_server,
237 this),
bnc38b5aed2021-04-02 10:57:41 -0700238 std::make_unique<RecordingProofVerifier>(std::move(proof_verifier)),
nharper2110bbd2020-06-08 18:24:30 -0700239 std::move(session_cache)),
dschinazi8ff74822019-05-28 16:37:20 -0700240 override_server_connection_id_(EmptyQuicConnectionId()),
dschinazi346b7ce2019-06-05 01:38:18 -0700241 server_connection_id_overridden_(false),
242 override_client_connection_id_(EmptyQuicConnectionId()),
243 client_connection_id_overridden_(false) {}
QUICHE teama6ef0a62019-03-07 20:34:33 -0500244
245MockableQuicClient::~MockableQuicClient() {
246 if (connected()) {
247 Disconnect();
248 }
249}
250
251MockableQuicClientEpollNetworkHelper*
252MockableQuicClient::mockable_network_helper() {
253 return static_cast<MockableQuicClientEpollNetworkHelper*>(
254 epoll_network_helper());
255}
256
257const MockableQuicClientEpollNetworkHelper*
258MockableQuicClient::mockable_network_helper() const {
259 return static_cast<const MockableQuicClientEpollNetworkHelper*>(
260 epoll_network_helper());
261}
262
263QuicConnectionId MockableQuicClient::GenerateNewConnectionId() {
dschinazic8579862019-07-24 18:20:20 -0700264 if (server_connection_id_overridden_) {
265 return override_server_connection_id_;
266 }
267 if (override_server_connection_id_length_ >= 0) {
268 return QuicUtils::CreateRandomConnectionId(
269 override_server_connection_id_length_);
270 }
271 return QuicClient::GenerateNewConnectionId();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500272}
273
dschinazi8ff74822019-05-28 16:37:20 -0700274void MockableQuicClient::UseConnectionId(
275 QuicConnectionId server_connection_id) {
276 server_connection_id_overridden_ = true;
277 override_server_connection_id_ = server_connection_id;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500278}
279
dschinazic8579862019-07-24 18:20:20 -0700280void MockableQuicClient::UseConnectionIdLength(
281 int server_connection_id_length) {
282 override_server_connection_id_length_ = server_connection_id_length;
283}
284
dschinazi346b7ce2019-06-05 01:38:18 -0700285QuicConnectionId MockableQuicClient::GetClientConnectionId() {
dschinazic8579862019-07-24 18:20:20 -0700286 if (client_connection_id_overridden_) {
287 return override_client_connection_id_;
288 }
289 if (override_client_connection_id_length_ >= 0) {
290 return QuicUtils::CreateRandomConnectionId(
291 override_client_connection_id_length_);
292 }
293 return QuicClient::GetClientConnectionId();
dschinazi346b7ce2019-06-05 01:38:18 -0700294}
295
296void MockableQuicClient::UseClientConnectionId(
297 QuicConnectionId client_connection_id) {
298 client_connection_id_overridden_ = true;
299 override_client_connection_id_ = client_connection_id;
300}
301
dschinazic8579862019-07-24 18:20:20 -0700302void MockableQuicClient::UseClientConnectionIdLength(
303 int client_connection_id_length) {
304 override_client_connection_id_length_ = client_connection_id_length;
305}
306
QUICHE teama6ef0a62019-03-07 20:34:33 -0500307void MockableQuicClient::UseWriter(QuicPacketWriterWrapper* writer) {
308 mockable_network_helper()->UseWriter(writer);
309}
310
311void MockableQuicClient::set_peer_address(const QuicSocketAddress& address) {
312 mockable_network_helper()->set_peer_address(address);
haoyuewang1c1771f2021-03-15 15:01:53 -0700313 if (client_session() != nullptr) {
314 client_session()->AddKnownServerAddress(address);
315 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500316}
317
318const QuicReceivedPacket* MockableQuicClient::last_incoming_packet() {
319 return mockable_network_helper()->last_incoming_packet();
320}
321
322void MockableQuicClient::set_track_last_incoming_packet(bool track) {
323 mockable_network_helper()->set_track_last_incoming_packet(track);
324}
325
326QuicTestClient::QuicTestClient(
327 QuicSocketAddress server_address,
vasilvvc48c8712019-03-11 13:38:16 -0700328 const std::string& server_hostname,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500329 const ParsedQuicVersionVector& supported_versions)
330 : QuicTestClient(server_address,
331 server_hostname,
332 QuicConfig(),
333 supported_versions) {}
334
335QuicTestClient::QuicTestClient(
336 QuicSocketAddress server_address,
vasilvvc48c8712019-03-11 13:38:16 -0700337 const std::string& server_hostname,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500338 const QuicConfig& config,
339 const ParsedQuicVersionVector& supported_versions)
340 : client_(new MockableQuicClient(
341 server_address,
342 QuicServerId(server_hostname, server_address.port(), false),
343 config,
344 supported_versions,
345 &epoll_server_)) {
346 Initialize();
347}
348
349QuicTestClient::QuicTestClient(
350 QuicSocketAddress server_address,
vasilvvc48c8712019-03-11 13:38:16 -0700351 const std::string& server_hostname,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500352 const QuicConfig& config,
353 const ParsedQuicVersionVector& supported_versions,
354 std::unique_ptr<ProofVerifier> proof_verifier)
355 : client_(new MockableQuicClient(
356 server_address,
357 QuicServerId(server_hostname, server_address.port(), false),
358 config,
359 supported_versions,
360 &epoll_server_,
361 std::move(proof_verifier))) {
362 Initialize();
363}
364
nharper2110bbd2020-06-08 18:24:30 -0700365QuicTestClient::QuicTestClient(
366 QuicSocketAddress server_address,
367 const std::string& server_hostname,
368 const QuicConfig& config,
369 const ParsedQuicVersionVector& supported_versions,
370 std::unique_ptr<ProofVerifier> proof_verifier,
371 std::unique_ptr<SessionCache> session_cache)
372 : client_(new MockableQuicClient(
373 server_address,
374 QuicServerId(server_hostname, server_address.port(), false),
375 config,
376 supported_versions,
377 &epoll_server_,
378 std::move(proof_verifier),
379 std::move(session_cache))) {
380 Initialize();
381}
382
QUICHE teama6ef0a62019-03-07 20:34:33 -0500383QuicTestClient::QuicTestClient() = default;
384
385QuicTestClient::~QuicTestClient() {
386 for (std::pair<QuicStreamId, QuicSpdyClientStream*> stream : open_streams_) {
387 stream.second->set_visitor(nullptr);
388 }
389}
390
391void QuicTestClient::Initialize() {
392 priority_ = 3;
393 connect_attempted_ = false;
394 auto_reconnect_ = false;
395 buffer_body_ = true;
396 num_requests_ = 0;
397 num_responses_ = 0;
398 ClearPerConnectionState();
399 // As chrome will generally do this, we want it to be the default when it's
400 // not overridden.
401 if (!client_->config()->HasSetBytesForConnectionIdToSend()) {
402 client_->config()->SetBytesForConnectionIdToSend(0);
403 }
404}
405
vasilvvc48c8712019-03-11 13:38:16 -0700406void QuicTestClient::SetUserAgentID(const std::string& user_agent_id) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500407 client_->SetUserAgentID(user_agent_id);
408}
409
vasilvvc48c8712019-03-11 13:38:16 -0700410ssize_t QuicTestClient::SendRequest(const std::string& uri) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500411 spdy::SpdyHeaderBlock headers;
412 if (!PopulateHeaderBlockFromUrl(uri, &headers)) {
413 return 0;
414 }
415 return SendMessage(headers, "");
416}
417
vasilvvc48c8712019-03-11 13:38:16 -0700418ssize_t QuicTestClient::SendRequestAndRstTogether(const std::string& uri) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500419 spdy::SpdyHeaderBlock headers;
420 if (!PopulateHeaderBlockFromUrl(uri, &headers)) {
421 return 0;
422 }
423
424 QuicSpdyClientSession* session = client()->client_session();
fayanga4b37b22019-06-18 13:37:47 -0700425 QuicConnection::ScopedPacketFlusher flusher(session->connection());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500426 ssize_t ret = SendMessage(headers, "", /*fin=*/true, /*flush=*/false);
427
428 QuicStreamId stream_id = GetNthClientInitiatedBidirectionalStreamId(
renjietangd1d00852019-09-06 10:43:12 -0700429 session->transport_version(), 0);
renjietangff4240d2020-07-01 06:19:55 -0700430 session->ResetStream(stream_id, QUIC_STREAM_CANCELLED);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500431 return ret;
432}
433
434void QuicTestClient::SendRequestsAndWaitForResponses(
vasilvvc48c8712019-03-11 13:38:16 -0700435 const std::vector<std::string>& url_list) {
436 for (const std::string& url : url_list) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500437 SendRequest(url);
438 }
439 while (client()->WaitForEvents()) {
440 }
441}
442
443ssize_t QuicTestClient::GetOrCreateStreamAndSendRequest(
444 const spdy::SpdyHeaderBlock* headers,
vasilvv5f225b02020-10-08 11:49:09 -0400445 absl::string_view body,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500446 bool fin,
447 QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) {
448 if (headers) {
449 QuicClientPushPromiseIndex::TryHandle* handle;
450 QuicAsyncStatus rv =
451 client()->push_promise_index()->Try(*headers, this, &handle);
452 if (rv == QUIC_SUCCESS)
453 return 1;
454 if (rv == QUIC_PENDING) {
455 // May need to retry request if asynchronous rendezvous fails.
456 std::unique_ptr<spdy::SpdyHeaderBlock> new_headers(
457 new spdy::SpdyHeaderBlock(headers->Clone()));
vasilvv0fc587f2019-09-06 13:33:08 -0700458 push_promise_data_to_resend_ = std::make_unique<TestClientDataToResend>(
QUICHE teama6ef0a62019-03-07 20:34:33 -0500459 std::move(new_headers), body, fin, this, std::move(ack_listener));
460 return 1;
461 }
462 }
463
464 // Maybe it's better just to overload this. it's just that we need
465 // for the GetOrCreateStream function to call something else...which
466 // is icky and complicated, but maybe not worse than this.
467 QuicSpdyClientStream* stream = GetOrCreateStream();
468 if (stream == nullptr) {
469 return 0;
470 }
471 QuicSpdyStreamPeer::set_ack_listener(stream, ack_listener);
472
473 ssize_t ret = 0;
474 if (headers != nullptr) {
475 spdy::SpdyHeaderBlock spdy_headers(headers->Clone());
476 if (spdy_headers[":authority"].as_string().empty()) {
477 spdy_headers[":authority"] = client_->server_id().host();
478 }
479 ret = stream->SendRequest(std::move(spdy_headers), body, fin);
480 ++num_requests_;
481 } else {
vasilvvc48c8712019-03-11 13:38:16 -0700482 stream->WriteOrBufferBody(std::string(body), fin);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500483 ret = body.length();
484 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500485 return ret;
486}
487
488ssize_t QuicTestClient::SendMessage(const spdy::SpdyHeaderBlock& headers,
vasilvv5f225b02020-10-08 11:49:09 -0400489 absl::string_view body) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500490 return SendMessage(headers, body, /*fin=*/true);
491}
492
493ssize_t QuicTestClient::SendMessage(const spdy::SpdyHeaderBlock& headers,
vasilvv5f225b02020-10-08 11:49:09 -0400494 absl::string_view body,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500495 bool fin) {
496 return SendMessage(headers, body, fin, /*flush=*/true);
497}
498
499ssize_t QuicTestClient::SendMessage(const spdy::SpdyHeaderBlock& headers,
vasilvv5f225b02020-10-08 11:49:09 -0400500 absl::string_view body,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500501 bool fin,
502 bool flush) {
503 // Always force creation of a stream for SendMessage.
504 latest_created_stream_ = nullptr;
505
506 ssize_t ret = GetOrCreateStreamAndSendRequest(&headers, body, fin, nullptr);
507
508 if (flush) {
509 WaitForWriteToFlush();
510 }
511 return ret;
512}
513
vasilvvc48c8712019-03-11 13:38:16 -0700514ssize_t QuicTestClient::SendData(const std::string& data, bool last_data) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500515 return SendData(data, last_data, nullptr);
516}
517
518ssize_t QuicTestClient::SendData(
vasilvvc48c8712019-03-11 13:38:16 -0700519 const std::string& data,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500520 bool last_data,
521 QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) {
vasilvv5f225b02020-10-08 11:49:09 -0400522 return GetOrCreateStreamAndSendRequest(nullptr, absl::string_view(data),
QUICHE teama6ef0a62019-03-07 20:34:33 -0500523 last_data, std::move(ack_listener));
524}
525
526bool QuicTestClient::response_complete() const {
527 return response_complete_;
528}
529
530int64_t QuicTestClient::response_body_size() const {
531 return response_body_size_;
532}
533
534bool QuicTestClient::buffer_body() const {
535 return buffer_body_;
536}
537
538void QuicTestClient::set_buffer_body(bool buffer_body) {
539 buffer_body_ = buffer_body;
540}
541
vasilvvc48c8712019-03-11 13:38:16 -0700542const std::string& QuicTestClient::response_body() const {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500543 return response_;
544}
545
vasilvvc48c8712019-03-11 13:38:16 -0700546std::string QuicTestClient::SendCustomSynchronousRequest(
QUICHE teama6ef0a62019-03-07 20:34:33 -0500547 const spdy::SpdyHeaderBlock& headers,
vasilvvc48c8712019-03-11 13:38:16 -0700548 const std::string& body) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500549 // Clear connection state here and only track this synchronous request.
550 ClearPerConnectionState();
551 if (SendMessage(headers, body) == 0) {
552 QUIC_DLOG(ERROR) << "Failed the request for: " << headers.DebugString();
553 // Set the response_ explicitly. Otherwise response_ will contain the
554 // response from the previously successful request.
555 response_ = "";
556 } else {
557 WaitForResponse();
558 }
559 return response_;
560}
561
vasilvvc48c8712019-03-11 13:38:16 -0700562std::string QuicTestClient::SendSynchronousRequest(const std::string& uri) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500563 spdy::SpdyHeaderBlock headers;
564 if (!PopulateHeaderBlockFromUrl(uri, &headers)) {
565 return "";
566 }
567 return SendCustomSynchronousRequest(headers, "");
568}
569
570void QuicTestClient::SendConnectivityProbing() {
571 QuicConnection* connection = client()->client_session()->connection();
572 connection->SendConnectivityProbingPacket(connection->writer(),
573 connection->peer_address());
574}
575
576void QuicTestClient::SetLatestCreatedStream(QuicSpdyClientStream* stream) {
577 latest_created_stream_ = stream;
578 if (latest_created_stream_ != nullptr) {
579 open_streams_[stream->id()] = stream;
580 stream->set_visitor(this);
581 }
582}
583
584QuicSpdyClientStream* QuicTestClient::GetOrCreateStream() {
585 if (!connect_attempted_ || auto_reconnect_) {
586 if (!connected()) {
587 Connect();
588 }
589 if (!connected()) {
590 return nullptr;
591 }
592 }
593 if (open_streams_.empty()) {
594 ClearPerConnectionState();
595 }
596 if (!latest_created_stream_) {
597 SetLatestCreatedStream(client_->CreateClientStream());
598 if (latest_created_stream_) {
fayang476683a2019-07-25 12:42:16 -0700599 latest_created_stream_->SetPriority(
600 spdy::SpdyStreamPrecedence(priority_));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500601 }
602 }
603
604 return latest_created_stream_;
605}
606
607QuicErrorCode QuicTestClient::connection_error() {
608 return client()->connection_error();
609}
610
vasilvvc48c8712019-03-11 13:38:16 -0700611const std::string& QuicTestClient::cert_common_name() const {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500612 return reinterpret_cast<RecordingProofVerifier*>(client_->proof_verifier())
613 ->common_name();
614}
615
vasilvvc48c8712019-03-11 13:38:16 -0700616const std::string& QuicTestClient::cert_sct() const {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500617 return reinterpret_cast<RecordingProofVerifier*>(client_->proof_verifier())
618 ->cert_sct();
619}
620
621QuicTagValueMap QuicTestClient::GetServerConfig() const {
622 QuicCryptoClientConfig* config = client_->crypto_config();
623 QuicCryptoClientConfig::CachedState* state =
624 config->LookupOrCreate(client_->server_id());
625 const CryptoHandshakeMessage* handshake_msg = state->GetServerConfig();
626 if (handshake_msg != nullptr) {
627 return handshake_msg->tag_value_map();
628 } else {
629 return QuicTagValueMap();
630 }
631}
632
633bool QuicTestClient::connected() const {
634 return client_->connected();
635}
636
637void QuicTestClient::Connect() {
dschinazi5af19672020-07-01 16:10:01 -0700638 if (connected()) {
QUICHE team62acb1d2021-03-16 15:11:08 -0700639 QUIC_BUG(quic_bug_10133_1) << "Cannot connect already-connected client";
dschinazi5af19672020-07-01 16:10:01 -0700640 return;
641 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500642 if (!connect_attempted_) {
643 client_->Initialize();
644 }
645
646 // If we've been asked to override SNI, set it now
647 if (override_sni_set_) {
648 client_->set_server_id(
649 QuicServerId(override_sni_, address().port(), false));
650 }
651
652 client_->Connect();
653 connect_attempted_ = true;
654}
655
656void QuicTestClient::ResetConnection() {
657 Disconnect();
658 Connect();
659}
660
661void QuicTestClient::Disconnect() {
662 ClearPerConnectionState();
QUICHE team9aef1152021-01-14 15:56:32 -0800663 if (client_->initialized()) {
664 client_->Disconnect();
665 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500666 connect_attempted_ = false;
667}
668
669QuicSocketAddress QuicTestClient::local_address() const {
670 return client_->network_helper()->GetLatestClientAddress();
671}
672
673void QuicTestClient::ClearPerRequestState() {
674 stream_error_ = QUIC_STREAM_NO_ERROR;
675 response_ = "";
676 response_complete_ = false;
677 response_headers_complete_ = false;
678 preliminary_headers_.clear();
679 response_headers_.clear();
680 response_trailers_.clear();
681 bytes_read_ = 0;
682 bytes_written_ = 0;
683 response_body_size_ = 0;
684}
685
686bool QuicTestClient::HaveActiveStream() {
687 return push_promise_data_to_resend_.get() || !open_streams_.empty();
688}
689
690bool QuicTestClient::WaitUntil(int timeout_ms, std::function<bool()> trigger) {
691 int64_t timeout_us = timeout_ms * kNumMicrosPerMilli;
692 int64_t old_timeout_us = epoll_server()->timeout_in_us_for_test();
693 if (timeout_us > 0) {
694 epoll_server()->set_timeout_in_us(timeout_us);
695 }
696 const QuicClock* clock =
697 QuicConnectionPeer::GetHelper(client()->session()->connection())
698 ->GetClock();
699 QuicTime end_waiting_time =
700 clock->Now() + QuicTime::Delta::FromMicroseconds(timeout_us);
fayangac3b4e02020-06-05 08:46:54 -0700701 while (HaveActiveStream() && !(trigger && trigger()) &&
QUICHE teama6ef0a62019-03-07 20:34:33 -0500702 (timeout_us < 0 || clock->Now() < end_waiting_time)) {
703 client_->WaitForEvents();
704 }
705 ReadNextResponse();
706 if (timeout_us > 0) {
707 epoll_server()->set_timeout_in_us(old_timeout_us);
708 }
709 if (trigger && !trigger()) {
haoyuewang87d145b2020-11-02 16:09:32 -0800710 QUIC_VLOG(1) << "Client WaitUntil returning with trigger returning false.";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500711 return false;
712 }
713 return true;
714}
715
vasilvv5f225b02020-10-08 11:49:09 -0400716ssize_t QuicTestClient::Send(absl::string_view data) {
QUICHE team0530cc82019-12-18 12:34:11 -0800717 return SendData(std::string(data), false);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500718}
719
720bool QuicTestClient::response_headers_complete() const {
721 for (std::pair<QuicStreamId, QuicSpdyClientStream*> stream : open_streams_) {
722 if (stream.second->headers_decompressed()) {
723 return true;
724 }
725 }
726 return response_headers_complete_;
727}
728
729const spdy::SpdyHeaderBlock* QuicTestClient::response_headers() const {
730 for (std::pair<QuicStreamId, QuicSpdyClientStream*> stream : open_streams_) {
bnc0e2735f2019-04-25 09:51:18 -0700731 if (stream.second->headers_decompressed()) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500732 response_headers_ = stream.second->response_headers().Clone();
733 break;
734 }
735 }
736 return &response_headers_;
737}
738
739const spdy::SpdyHeaderBlock* QuicTestClient::preliminary_headers() const {
740 for (std::pair<QuicStreamId, QuicSpdyClientStream*> stream : open_streams_) {
741 size_t bytes_read =
742 stream.second->stream_bytes_read() + stream.second->header_bytes_read();
743 if (bytes_read > 0) {
744 preliminary_headers_ = stream.second->preliminary_headers().Clone();
745 break;
746 }
747 }
748 return &preliminary_headers_;
749}
750
751const spdy::SpdyHeaderBlock& QuicTestClient::response_trailers() const {
752 return response_trailers_;
753}
754
755int64_t QuicTestClient::response_size() const {
756 return bytes_read();
757}
758
759size_t QuicTestClient::bytes_read() const {
760 for (std::pair<QuicStreamId, QuicSpdyClientStream*> stream : open_streams_) {
761 size_t bytes_read = stream.second->total_body_bytes_read() +
762 stream.second->header_bytes_read();
763 if (bytes_read > 0) {
764 return bytes_read;
765 }
766 }
767 return bytes_read_;
768}
769
770size_t QuicTestClient::bytes_written() const {
771 for (std::pair<QuicStreamId, QuicSpdyClientStream*> stream : open_streams_) {
772 size_t bytes_written = stream.second->stream_bytes_written() +
773 stream.second->header_bytes_written();
774 if (bytes_written > 0) {
775 return bytes_written;
776 }
777 }
778 return bytes_written_;
779}
780
781void QuicTestClient::OnClose(QuicSpdyStream* stream) {
782 if (stream == nullptr) {
783 return;
784 }
785 // Always close the stream, regardless of whether it was the last stream
786 // written.
787 client()->OnClose(stream);
788 ++num_responses_;
789 if (!QuicContainsKey(open_streams_, stream->id())) {
790 return;
791 }
792 if (latest_created_stream_ == stream) {
793 latest_created_stream_ = nullptr;
794 }
795 QuicSpdyClientStream* client_stream =
796 static_cast<QuicSpdyClientStream*>(stream);
797 QuicStreamId id = client_stream->id();
798 closed_stream_states_.insert(std::make_pair(
799 id,
800 PerStreamState(
wub009726e2021-03-01 11:01:03 -0800801 // Set response_complete to true iff stream is closed while connected.
802 client_stream->stream_error(), connected(),
QUICHE teama6ef0a62019-03-07 20:34:33 -0500803 client_stream->headers_decompressed(),
804 client_stream->response_headers(),
805 client_stream->preliminary_headers(),
806 (buffer_body() ? client_stream->data() : ""),
807 client_stream->received_trailers(),
808 // Use NumBytesConsumed to avoid counting retransmitted stream frames.
809 client_stream->total_body_bytes_read() +
810 client_stream->header_bytes_read(),
811 client_stream->stream_bytes_written() +
812 client_stream->header_bytes_written(),
813 client_stream->data().size())));
814 open_streams_.erase(id);
815}
816
dschinazi17d42422019-06-18 16:35:07 -0700817bool QuicTestClient::CheckVary(
818 const spdy::SpdyHeaderBlock& /*client_request*/,
819 const spdy::SpdyHeaderBlock& /*promise_request*/,
820 const spdy::SpdyHeaderBlock& /*promise_response*/) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500821 return true;
822}
823
824void QuicTestClient::OnRendezvousResult(QuicSpdyStream* stream) {
825 std::unique_ptr<TestClientDataToResend> data_to_resend =
826 std::move(push_promise_data_to_resend_);
827 SetLatestCreatedStream(static_cast<QuicSpdyClientStream*>(stream));
828 if (stream) {
829 stream->OnBodyAvailable();
830 } else if (data_to_resend) {
831 data_to_resend->Resend();
832 }
833}
834
835void QuicTestClient::UseWriter(QuicPacketWriterWrapper* writer) {
836 client_->UseWriter(writer);
837}
838
dschinazi8ff74822019-05-28 16:37:20 -0700839void QuicTestClient::UseConnectionId(QuicConnectionId server_connection_id) {
vasilvvf8035162021-02-01 14:49:14 -0800840 QUICHE_DCHECK(!connected());
dschinazi8ff74822019-05-28 16:37:20 -0700841 client_->UseConnectionId(server_connection_id);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500842}
843
dschinazic8579862019-07-24 18:20:20 -0700844void QuicTestClient::UseConnectionIdLength(int server_connection_id_length) {
vasilvvf8035162021-02-01 14:49:14 -0800845 QUICHE_DCHECK(!connected());
dschinazic8579862019-07-24 18:20:20 -0700846 client_->UseConnectionIdLength(server_connection_id_length);
847}
848
dschinazi346b7ce2019-06-05 01:38:18 -0700849void QuicTestClient::UseClientConnectionId(
850 QuicConnectionId client_connection_id) {
vasilvvf8035162021-02-01 14:49:14 -0800851 QUICHE_DCHECK(!connected());
dschinazi346b7ce2019-06-05 01:38:18 -0700852 client_->UseClientConnectionId(client_connection_id);
853}
854
dschinazic8579862019-07-24 18:20:20 -0700855void QuicTestClient::UseClientConnectionIdLength(
856 int client_connection_id_length) {
vasilvvf8035162021-02-01 14:49:14 -0800857 QUICHE_DCHECK(!connected());
dschinazic8579862019-07-24 18:20:20 -0700858 client_->UseClientConnectionIdLength(client_connection_id_length);
859}
860
QUICHE teama6ef0a62019-03-07 20:34:33 -0500861bool QuicTestClient::MigrateSocket(const QuicIpAddress& new_host) {
862 return client_->MigrateSocket(new_host);
863}
864
865bool QuicTestClient::MigrateSocketWithSpecifiedPort(
866 const QuicIpAddress& new_host,
867 int port) {
868 client_->set_local_port(port);
869 return client_->MigrateSocket(new_host);
870}
871
872QuicIpAddress QuicTestClient::bind_to_address() const {
873 return client_->bind_to_address();
874}
875
876void QuicTestClient::set_bind_to_address(QuicIpAddress address) {
877 client_->set_bind_to_address(address);
878}
879
880const QuicSocketAddress& QuicTestClient::address() const {
881 return client_->server_address();
882}
883
884void QuicTestClient::WaitForWriteToFlush() {
fayangac3b4e02020-06-05 08:46:54 -0700885 while (connected() && client()->session()->HasDataToWrite()) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500886 client_->WaitForEvents();
887 }
888}
889
890QuicTestClient::TestClientDataToResend::TestClientDataToResend(
891 std::unique_ptr<spdy::SpdyHeaderBlock> headers,
vasilvv5f225b02020-10-08 11:49:09 -0400892 absl::string_view body,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500893 bool fin,
894 QuicTestClient* test_client,
895 QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener)
896 : QuicClient::QuicDataToResend(std::move(headers), body, fin),
897 test_client_(test_client),
898 ack_listener_(std::move(ack_listener)) {}
899
900QuicTestClient::TestClientDataToResend::~TestClientDataToResend() = default;
901
902void QuicTestClient::TestClientDataToResend::Resend() {
903 test_client_->GetOrCreateStreamAndSendRequest(headers_.get(), body_, fin_,
904 ack_listener_);
905 headers_.reset();
906}
907
908QuicTestClient::PerStreamState::PerStreamState(const PerStreamState& other)
909 : stream_error(other.stream_error),
910 response_complete(other.response_complete),
911 response_headers_complete(other.response_headers_complete),
912 response_headers(other.response_headers.Clone()),
913 preliminary_headers(other.preliminary_headers.Clone()),
914 response(other.response),
915 response_trailers(other.response_trailers.Clone()),
916 bytes_read(other.bytes_read),
917 bytes_written(other.bytes_written),
918 response_body_size(other.response_body_size) {}
919
920QuicTestClient::PerStreamState::PerStreamState(
921 QuicRstStreamErrorCode stream_error,
922 bool response_complete,
923 bool response_headers_complete,
924 const spdy::SpdyHeaderBlock& response_headers,
925 const spdy::SpdyHeaderBlock& preliminary_headers,
vasilvvc48c8712019-03-11 13:38:16 -0700926 const std::string& response,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500927 const spdy::SpdyHeaderBlock& response_trailers,
928 uint64_t bytes_read,
929 uint64_t bytes_written,
930 int64_t response_body_size)
931 : stream_error(stream_error),
932 response_complete(response_complete),
933 response_headers_complete(response_headers_complete),
934 response_headers(response_headers.Clone()),
935 preliminary_headers(preliminary_headers.Clone()),
936 response(response),
937 response_trailers(response_trailers.Clone()),
938 bytes_read(bytes_read),
939 bytes_written(bytes_written),
940 response_body_size(response_body_size) {}
941
942QuicTestClient::PerStreamState::~PerStreamState() = default;
943
944bool QuicTestClient::PopulateHeaderBlockFromUrl(
vasilvvc48c8712019-03-11 13:38:16 -0700945 const std::string& uri,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500946 spdy::SpdyHeaderBlock* headers) {
vasilvvc48c8712019-03-11 13:38:16 -0700947 std::string url;
vasilvv89fe24d2020-10-26 14:55:28 -0700948 if (absl::StartsWith(uri, "https://") || absl::StartsWith(uri, "http://")) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500949 url = uri;
950 } else if (uri[0] == '/') {
951 url = "https://" + client_->server_id().host() + uri;
952 } else {
953 url = "https://" + uri;
954 }
955 return SpdyUtils::PopulateHeaderBlockFromUrl(url, headers);
956}
957
958void QuicTestClient::ReadNextResponse() {
959 if (closed_stream_states_.empty()) {
960 return;
961 }
962
963 PerStreamState state(closed_stream_states_.front().second);
964
965 stream_error_ = state.stream_error;
966 response_ = state.response;
967 response_complete_ = state.response_complete;
968 response_headers_complete_ = state.response_headers_complete;
969 preliminary_headers_ = state.preliminary_headers.Clone();
970 response_headers_ = state.response_headers.Clone();
971 response_trailers_ = state.response_trailers.Clone();
972 bytes_read_ = state.bytes_read;
973 bytes_written_ = state.bytes_written;
974 response_body_size_ = state.response_body_size;
975
976 closed_stream_states_.pop_front();
977}
978
979void QuicTestClient::ClearPerConnectionState() {
980 ClearPerRequestState();
981 open_streams_.clear();
982 closed_stream_states_.clear();
983 latest_created_stream_ = nullptr;
984}
985
986void QuicTestClient::WaitForDelayedAcks() {
987 // kWaitDuration is a period of time that is long enough for all delayed
988 // acks to be sent and received on the other end.
989 const QuicTime::Delta kWaitDuration =
990 4 * QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs);
991
992 const QuicClock* clock = client()->client_session()->connection()->clock();
993
994 QuicTime wait_until = clock->ApproximateNow() + kWaitDuration;
fayangaa4f3f22020-06-05 16:22:00 -0700995 while (connected() && clock->ApproximateNow() < wait_until) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500996 // This waits for up to 50 ms.
997 client()->WaitForEvents();
998 }
999}
1000
1001} // namespace test
1002} // namespace quic