blob: 1f95d2222d51b84a4779d37cf4bacb73f606bd66 [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
5#include "net/third_party/quiche/src/quic/test_tools/quic_test_client.h"
6
7#include <memory>
8#include <utility>
9#include <vector>
10
11#include "third_party/boringssl/src/include/openssl/x509.h"
12#include "net/third_party/quiche/src/quic/core/crypto/proof_verifier.h"
13#include "net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream.h"
14#include "net/third_party/quiche/src/quic/core/http/spdy_utils.h"
15#include "net/third_party/quiche/src/quic/core/quic_epoll_connection_helper.h"
16#include "net/third_party/quiche/src/quic/core/quic_packet_writer_wrapper.h"
17#include "net/third_party/quiche/src/quic/core/quic_server_id.h"
18#include "net/third_party/quiche/src/quic/core/quic_utils.h"
19#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
20#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
21#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
22#include "net/third_party/quiche/src/quic/platform/api/quic_stack_trace.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050023#include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h"
24#include "net/third_party/quiche/src/quic/test_tools/quic_client_peer.h"
25#include "net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h"
26#include "net/third_party/quiche/src/quic/test_tools/quic_spdy_session_peer.h"
27#include "net/third_party/quiche/src/quic/test_tools/quic_spdy_stream_peer.h"
28#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
29#include "net/third_party/quiche/src/quic/tools/quic_url.h"
QUICHE team6dcf6ab2019-12-11 10:10:51 -080030#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
31#include "net/third_party/quiche/src/common/platform/api/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,
QUICHE team6dcf6ab2019-12-11 10:10:51 -080052 quiche::QuicheStringPiece 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 {
60 common_name_.clear();
61 if (certs.empty()) {
62 return QUIC_FAILURE;
63 }
64
65 const uint8_t* data;
66 data = reinterpret_cast<const uint8_t*>(certs[0].data());
67 bssl::UniquePtr<X509> cert(d2i_X509(nullptr, &data, certs[0].size()));
68 if (!cert.get()) {
69 return QUIC_FAILURE;
70 }
71
72 static const unsigned kMaxCommonNameLength = 256;
73 char buf[kMaxCommonNameLength];
74 X509_NAME* subject_name = X509_get_subject_name(cert.get());
75 if (X509_NAME_get_text_by_NID(subject_name, NID_commonName, buf,
76 sizeof(buf)) <= 0) {
77 return QUIC_FAILURE;
78 }
79
80 common_name_ = buf;
81 cert_sct_ = cert_sct;
82
83 if (!verifier_) {
84 return QUIC_SUCCESS;
85 }
86
87 return verifier_->VerifyProof(hostname, port, server_config,
88 transport_version, chlo_hash, certs, cert_sct,
89 signature, context, error_details, details,
90 std::move(callback));
91 }
92
93 QuicAsyncStatus VerifyCertChain(
dschinazi17d42422019-06-18 16:35:07 -070094 const std::string& /*hostname*/,
95 const std::vector<std::string>& /*certs*/,
96 const std::string& /*ocsp_response*/,
97 const std::string& /*cert_sct*/,
98 const ProofVerifyContext* /*context*/,
99 std::string* /*error_details*/,
100 std::unique_ptr<ProofVerifyDetails>* /*details*/,
101 std::unique_ptr<ProofVerifierCallback> /*callback*/) override {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500102 return QUIC_SUCCESS;
103 }
104
105 std::unique_ptr<ProofVerifyContext> CreateDefaultContext() override {
106 return verifier_ != nullptr ? verifier_->CreateDefaultContext() : nullptr;
107 }
108
vasilvvc48c8712019-03-11 13:38:16 -0700109 const std::string& common_name() const { return common_name_; }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500110
vasilvvc48c8712019-03-11 13:38:16 -0700111 const std::string& cert_sct() const { return cert_sct_; }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500112
113 private:
114 std::unique_ptr<ProofVerifier> verifier_;
vasilvvc48c8712019-03-11 13:38:16 -0700115 std::string common_name_;
116 std::string cert_sct_;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500117};
118} // namespace
119
120class MockableQuicClientEpollNetworkHelper
121 : public QuicClientEpollNetworkHelper {
122 public:
123 using QuicClientEpollNetworkHelper::QuicClientEpollNetworkHelper;
124 ~MockableQuicClientEpollNetworkHelper() override = default;
125
126 void ProcessPacket(const QuicSocketAddress& self_address,
127 const QuicSocketAddress& peer_address,
128 const QuicReceivedPacket& packet) override {
129 QuicClientEpollNetworkHelper::ProcessPacket(self_address, peer_address,
130 packet);
131 if (track_last_incoming_packet_) {
132 last_incoming_packet_ = packet.Clone();
133 }
134 }
135
136 QuicPacketWriter* CreateQuicPacketWriter() override {
137 QuicPacketWriter* writer =
138 QuicClientEpollNetworkHelper::CreateQuicPacketWriter();
139 if (!test_writer_) {
140 return writer;
141 }
142 test_writer_->set_writer(writer);
143 return test_writer_;
144 }
145
146 const QuicReceivedPacket* last_incoming_packet() {
147 return last_incoming_packet_.get();
148 }
149
150 void set_track_last_incoming_packet(bool track) {
151 track_last_incoming_packet_ = track;
152 }
153
154 void UseWriter(QuicPacketWriterWrapper* writer) {
155 CHECK(test_writer_ == nullptr);
156 test_writer_ = writer;
157 }
158
159 void set_peer_address(const QuicSocketAddress& address) {
160 CHECK(test_writer_ != nullptr);
161 test_writer_->set_peer_address(address);
162 }
163
164 private:
165 QuicPacketWriterWrapper* test_writer_ = nullptr;
166 // The last incoming packet, iff |track_last_incoming_packet_| is true.
167 std::unique_ptr<QuicReceivedPacket> last_incoming_packet_;
168 // If true, copy each packet from ProcessPacket into |last_incoming_packet_|
169 bool track_last_incoming_packet_ = false;
170};
171
172MockableQuicClient::MockableQuicClient(
173 QuicSocketAddress server_address,
174 const QuicServerId& server_id,
175 const ParsedQuicVersionVector& supported_versions,
176 QuicEpollServer* epoll_server)
177 : MockableQuicClient(server_address,
178 server_id,
179 QuicConfig(),
180 supported_versions,
181 epoll_server) {}
182
183MockableQuicClient::MockableQuicClient(
184 QuicSocketAddress server_address,
185 const QuicServerId& server_id,
186 const QuicConfig& config,
187 const ParsedQuicVersionVector& supported_versions,
188 QuicEpollServer* epoll_server)
189 : MockableQuicClient(server_address,
190 server_id,
191 config,
192 supported_versions,
193 epoll_server,
194 nullptr) {}
195
196MockableQuicClient::MockableQuicClient(
197 QuicSocketAddress server_address,
198 const QuicServerId& server_id,
199 const QuicConfig& config,
200 const ParsedQuicVersionVector& supported_versions,
201 QuicEpollServer* epoll_server,
202 std::unique_ptr<ProofVerifier> proof_verifier)
203 : QuicClient(
204 server_address,
205 server_id,
206 supported_versions,
207 config,
208 epoll_server,
vasilvv0fc587f2019-09-06 13:33:08 -0700209 std::make_unique<MockableQuicClientEpollNetworkHelper>(epoll_server,
210 this),
QUICHE teama6ef0a62019-03-07 20:34:33 -0500211 QuicWrapUnique(
212 new RecordingProofVerifier(std::move(proof_verifier)))),
dschinazi8ff74822019-05-28 16:37:20 -0700213 override_server_connection_id_(EmptyQuicConnectionId()),
dschinazi346b7ce2019-06-05 01:38:18 -0700214 server_connection_id_overridden_(false),
215 override_client_connection_id_(EmptyQuicConnectionId()),
216 client_connection_id_overridden_(false) {}
QUICHE teama6ef0a62019-03-07 20:34:33 -0500217
218MockableQuicClient::~MockableQuicClient() {
219 if (connected()) {
220 Disconnect();
221 }
222}
223
224MockableQuicClientEpollNetworkHelper*
225MockableQuicClient::mockable_network_helper() {
226 return static_cast<MockableQuicClientEpollNetworkHelper*>(
227 epoll_network_helper());
228}
229
230const MockableQuicClientEpollNetworkHelper*
231MockableQuicClient::mockable_network_helper() const {
232 return static_cast<const MockableQuicClientEpollNetworkHelper*>(
233 epoll_network_helper());
234}
235
236QuicConnectionId MockableQuicClient::GenerateNewConnectionId() {
dschinazic8579862019-07-24 18:20:20 -0700237 if (server_connection_id_overridden_) {
238 return override_server_connection_id_;
239 }
240 if (override_server_connection_id_length_ >= 0) {
241 return QuicUtils::CreateRandomConnectionId(
242 override_server_connection_id_length_);
243 }
244 return QuicClient::GenerateNewConnectionId();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500245}
246
dschinazi8ff74822019-05-28 16:37:20 -0700247void MockableQuicClient::UseConnectionId(
248 QuicConnectionId server_connection_id) {
249 server_connection_id_overridden_ = true;
250 override_server_connection_id_ = server_connection_id;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500251}
252
dschinazic8579862019-07-24 18:20:20 -0700253void MockableQuicClient::UseConnectionIdLength(
254 int server_connection_id_length) {
255 override_server_connection_id_length_ = server_connection_id_length;
256}
257
dschinazi346b7ce2019-06-05 01:38:18 -0700258QuicConnectionId MockableQuicClient::GetClientConnectionId() {
dschinazic8579862019-07-24 18:20:20 -0700259 if (client_connection_id_overridden_) {
260 return override_client_connection_id_;
261 }
262 if (override_client_connection_id_length_ >= 0) {
263 return QuicUtils::CreateRandomConnectionId(
264 override_client_connection_id_length_);
265 }
266 return QuicClient::GetClientConnectionId();
dschinazi346b7ce2019-06-05 01:38:18 -0700267}
268
269void MockableQuicClient::UseClientConnectionId(
270 QuicConnectionId client_connection_id) {
271 client_connection_id_overridden_ = true;
272 override_client_connection_id_ = client_connection_id;
273}
274
dschinazic8579862019-07-24 18:20:20 -0700275void MockableQuicClient::UseClientConnectionIdLength(
276 int client_connection_id_length) {
277 override_client_connection_id_length_ = client_connection_id_length;
278}
279
QUICHE teama6ef0a62019-03-07 20:34:33 -0500280void MockableQuicClient::UseWriter(QuicPacketWriterWrapper* writer) {
281 mockable_network_helper()->UseWriter(writer);
282}
283
284void MockableQuicClient::set_peer_address(const QuicSocketAddress& address) {
285 mockable_network_helper()->set_peer_address(address);
286}
287
288const QuicReceivedPacket* MockableQuicClient::last_incoming_packet() {
289 return mockable_network_helper()->last_incoming_packet();
290}
291
292void MockableQuicClient::set_track_last_incoming_packet(bool track) {
293 mockable_network_helper()->set_track_last_incoming_packet(track);
294}
295
296QuicTestClient::QuicTestClient(
297 QuicSocketAddress server_address,
vasilvvc48c8712019-03-11 13:38:16 -0700298 const std::string& server_hostname,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500299 const ParsedQuicVersionVector& supported_versions)
300 : QuicTestClient(server_address,
301 server_hostname,
302 QuicConfig(),
303 supported_versions) {}
304
305QuicTestClient::QuicTestClient(
306 QuicSocketAddress server_address,
vasilvvc48c8712019-03-11 13:38:16 -0700307 const std::string& server_hostname,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500308 const QuicConfig& config,
309 const ParsedQuicVersionVector& supported_versions)
310 : client_(new MockableQuicClient(
311 server_address,
312 QuicServerId(server_hostname, server_address.port(), false),
313 config,
314 supported_versions,
315 &epoll_server_)) {
316 Initialize();
317}
318
319QuicTestClient::QuicTestClient(
320 QuicSocketAddress server_address,
vasilvvc48c8712019-03-11 13:38:16 -0700321 const std::string& server_hostname,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500322 const QuicConfig& config,
323 const ParsedQuicVersionVector& supported_versions,
324 std::unique_ptr<ProofVerifier> proof_verifier)
325 : client_(new MockableQuicClient(
326 server_address,
327 QuicServerId(server_hostname, server_address.port(), false),
328 config,
329 supported_versions,
330 &epoll_server_,
331 std::move(proof_verifier))) {
332 Initialize();
333}
334
335QuicTestClient::QuicTestClient() = default;
336
337QuicTestClient::~QuicTestClient() {
338 for (std::pair<QuicStreamId, QuicSpdyClientStream*> stream : open_streams_) {
339 stream.second->set_visitor(nullptr);
340 }
341}
342
343void QuicTestClient::Initialize() {
344 priority_ = 3;
345 connect_attempted_ = false;
346 auto_reconnect_ = false;
347 buffer_body_ = true;
348 num_requests_ = 0;
349 num_responses_ = 0;
350 ClearPerConnectionState();
rch4e7e60f2019-10-16 07:24:00 -0700351 // TODO(b/142715651): Figure out how to use QPACK in tests.
352 // Do not use the QPACK dynamic table in tests to avoid flakiness due to the
353 // uncertain order of receiving the SETTINGS frame and sending headers.
354 client_->disable_qpack_dynamic_table();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500355 // As chrome will generally do this, we want it to be the default when it's
356 // not overridden.
357 if (!client_->config()->HasSetBytesForConnectionIdToSend()) {
358 client_->config()->SetBytesForConnectionIdToSend(0);
359 }
360}
361
vasilvvc48c8712019-03-11 13:38:16 -0700362void QuicTestClient::SetUserAgentID(const std::string& user_agent_id) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500363 client_->SetUserAgentID(user_agent_id);
364}
365
vasilvvc48c8712019-03-11 13:38:16 -0700366ssize_t QuicTestClient::SendRequest(const std::string& uri) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500367 spdy::SpdyHeaderBlock headers;
368 if (!PopulateHeaderBlockFromUrl(uri, &headers)) {
369 return 0;
370 }
371 return SendMessage(headers, "");
372}
373
vasilvvc48c8712019-03-11 13:38:16 -0700374ssize_t QuicTestClient::SendRequestAndRstTogether(const std::string& uri) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500375 spdy::SpdyHeaderBlock headers;
376 if (!PopulateHeaderBlockFromUrl(uri, &headers)) {
377 return 0;
378 }
379
380 QuicSpdyClientSession* session = client()->client_session();
fayanga4b37b22019-06-18 13:37:47 -0700381 QuicConnection::ScopedPacketFlusher flusher(session->connection());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500382 ssize_t ret = SendMessage(headers, "", /*fin=*/true, /*flush=*/false);
383
384 QuicStreamId stream_id = GetNthClientInitiatedBidirectionalStreamId(
renjietangd1d00852019-09-06 10:43:12 -0700385 session->transport_version(), 0);
renjietang15afba32019-10-23 14:32:35 -0700386 QuicStream* stream = session->GetOrCreateStream(stream_id);
387 session->SendRstStream(stream_id, QUIC_STREAM_CANCELLED,
388 stream->stream_bytes_written());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500389 return ret;
390}
391
392void QuicTestClient::SendRequestsAndWaitForResponses(
vasilvvc48c8712019-03-11 13:38:16 -0700393 const std::vector<std::string>& url_list) {
394 for (const std::string& url : url_list) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500395 SendRequest(url);
396 }
397 while (client()->WaitForEvents()) {
398 }
399}
400
401ssize_t QuicTestClient::GetOrCreateStreamAndSendRequest(
402 const spdy::SpdyHeaderBlock* headers,
QUICHE team6dcf6ab2019-12-11 10:10:51 -0800403 quiche::QuicheStringPiece body,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500404 bool fin,
405 QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) {
406 if (headers) {
407 QuicClientPushPromiseIndex::TryHandle* handle;
408 QuicAsyncStatus rv =
409 client()->push_promise_index()->Try(*headers, this, &handle);
410 if (rv == QUIC_SUCCESS)
411 return 1;
412 if (rv == QUIC_PENDING) {
413 // May need to retry request if asynchronous rendezvous fails.
414 std::unique_ptr<spdy::SpdyHeaderBlock> new_headers(
415 new spdy::SpdyHeaderBlock(headers->Clone()));
vasilvv0fc587f2019-09-06 13:33:08 -0700416 push_promise_data_to_resend_ = std::make_unique<TestClientDataToResend>(
QUICHE teama6ef0a62019-03-07 20:34:33 -0500417 std::move(new_headers), body, fin, this, std::move(ack_listener));
418 return 1;
419 }
420 }
421
422 // Maybe it's better just to overload this. it's just that we need
423 // for the GetOrCreateStream function to call something else...which
424 // is icky and complicated, but maybe not worse than this.
425 QuicSpdyClientStream* stream = GetOrCreateStream();
426 if (stream == nullptr) {
427 return 0;
428 }
429 QuicSpdyStreamPeer::set_ack_listener(stream, ack_listener);
430
431 ssize_t ret = 0;
432 if (headers != nullptr) {
433 spdy::SpdyHeaderBlock spdy_headers(headers->Clone());
434 if (spdy_headers[":authority"].as_string().empty()) {
435 spdy_headers[":authority"] = client_->server_id().host();
436 }
437 ret = stream->SendRequest(std::move(spdy_headers), body, fin);
438 ++num_requests_;
439 } else {
vasilvvc48c8712019-03-11 13:38:16 -0700440 stream->WriteOrBufferBody(std::string(body), fin);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500441 ret = body.length();
442 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500443 return ret;
444}
445
446ssize_t QuicTestClient::SendMessage(const spdy::SpdyHeaderBlock& headers,
QUICHE team6dcf6ab2019-12-11 10:10:51 -0800447 quiche::QuicheStringPiece body) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500448 return SendMessage(headers, body, /*fin=*/true);
449}
450
451ssize_t QuicTestClient::SendMessage(const spdy::SpdyHeaderBlock& headers,
QUICHE team6dcf6ab2019-12-11 10:10:51 -0800452 quiche::QuicheStringPiece body,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500453 bool fin) {
454 return SendMessage(headers, body, fin, /*flush=*/true);
455}
456
457ssize_t QuicTestClient::SendMessage(const spdy::SpdyHeaderBlock& headers,
QUICHE team6dcf6ab2019-12-11 10:10:51 -0800458 quiche::QuicheStringPiece body,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500459 bool fin,
460 bool flush) {
461 // Always force creation of a stream for SendMessage.
462 latest_created_stream_ = nullptr;
463
464 ssize_t ret = GetOrCreateStreamAndSendRequest(&headers, body, fin, nullptr);
465
466 if (flush) {
467 WaitForWriteToFlush();
468 }
469 return ret;
470}
471
vasilvvc48c8712019-03-11 13:38:16 -0700472ssize_t QuicTestClient::SendData(const std::string& data, bool last_data) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500473 return SendData(data, last_data, nullptr);
474}
475
476ssize_t QuicTestClient::SendData(
vasilvvc48c8712019-03-11 13:38:16 -0700477 const std::string& data,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500478 bool last_data,
479 QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) {
QUICHE team6dcf6ab2019-12-11 10:10:51 -0800480 return GetOrCreateStreamAndSendRequest(nullptr,
481 quiche::QuicheStringPiece(data),
QUICHE teama6ef0a62019-03-07 20:34:33 -0500482 last_data, std::move(ack_listener));
483}
484
485bool QuicTestClient::response_complete() const {
486 return response_complete_;
487}
488
489int64_t QuicTestClient::response_body_size() const {
490 return response_body_size_;
491}
492
493bool QuicTestClient::buffer_body() const {
494 return buffer_body_;
495}
496
497void QuicTestClient::set_buffer_body(bool buffer_body) {
498 buffer_body_ = buffer_body;
499}
500
vasilvvc48c8712019-03-11 13:38:16 -0700501const std::string& QuicTestClient::response_body() const {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500502 return response_;
503}
504
vasilvvc48c8712019-03-11 13:38:16 -0700505std::string QuicTestClient::SendCustomSynchronousRequest(
QUICHE teama6ef0a62019-03-07 20:34:33 -0500506 const spdy::SpdyHeaderBlock& headers,
vasilvvc48c8712019-03-11 13:38:16 -0700507 const std::string& body) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500508 // Clear connection state here and only track this synchronous request.
509 ClearPerConnectionState();
510 if (SendMessage(headers, body) == 0) {
511 QUIC_DLOG(ERROR) << "Failed the request for: " << headers.DebugString();
512 // Set the response_ explicitly. Otherwise response_ will contain the
513 // response from the previously successful request.
514 response_ = "";
515 } else {
516 WaitForResponse();
517 }
518 return response_;
519}
520
vasilvvc48c8712019-03-11 13:38:16 -0700521std::string QuicTestClient::SendSynchronousRequest(const std::string& uri) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500522 spdy::SpdyHeaderBlock headers;
523 if (!PopulateHeaderBlockFromUrl(uri, &headers)) {
524 return "";
525 }
526 return SendCustomSynchronousRequest(headers, "");
527}
528
529void QuicTestClient::SendConnectivityProbing() {
530 QuicConnection* connection = client()->client_session()->connection();
531 connection->SendConnectivityProbingPacket(connection->writer(),
532 connection->peer_address());
533}
534
535void QuicTestClient::SetLatestCreatedStream(QuicSpdyClientStream* stream) {
536 latest_created_stream_ = stream;
537 if (latest_created_stream_ != nullptr) {
538 open_streams_[stream->id()] = stream;
539 stream->set_visitor(this);
540 }
541}
542
543QuicSpdyClientStream* QuicTestClient::GetOrCreateStream() {
544 if (!connect_attempted_ || auto_reconnect_) {
545 if (!connected()) {
546 Connect();
547 }
548 if (!connected()) {
549 return nullptr;
550 }
551 }
552 if (open_streams_.empty()) {
553 ClearPerConnectionState();
554 }
555 if (!latest_created_stream_) {
556 SetLatestCreatedStream(client_->CreateClientStream());
557 if (latest_created_stream_) {
fayang476683a2019-07-25 12:42:16 -0700558 latest_created_stream_->SetPriority(
559 spdy::SpdyStreamPrecedence(priority_));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500560 }
561 }
562
563 return latest_created_stream_;
564}
565
566QuicErrorCode QuicTestClient::connection_error() {
567 return client()->connection_error();
568}
569
570MockableQuicClient* QuicTestClient::client() {
571 return client_.get();
572}
573
vasilvvc48c8712019-03-11 13:38:16 -0700574const std::string& QuicTestClient::cert_common_name() const {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500575 return reinterpret_cast<RecordingProofVerifier*>(client_->proof_verifier())
576 ->common_name();
577}
578
vasilvvc48c8712019-03-11 13:38:16 -0700579const std::string& QuicTestClient::cert_sct() const {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500580 return reinterpret_cast<RecordingProofVerifier*>(client_->proof_verifier())
581 ->cert_sct();
582}
583
584QuicTagValueMap QuicTestClient::GetServerConfig() const {
585 QuicCryptoClientConfig* config = client_->crypto_config();
586 QuicCryptoClientConfig::CachedState* state =
587 config->LookupOrCreate(client_->server_id());
588 const CryptoHandshakeMessage* handshake_msg = state->GetServerConfig();
589 if (handshake_msg != nullptr) {
590 return handshake_msg->tag_value_map();
591 } else {
592 return QuicTagValueMap();
593 }
594}
595
596bool QuicTestClient::connected() const {
597 return client_->connected();
598}
599
600void QuicTestClient::Connect() {
601 DCHECK(!connected());
602 if (!connect_attempted_) {
603 client_->Initialize();
604 }
605
606 // If we've been asked to override SNI, set it now
607 if (override_sni_set_) {
608 client_->set_server_id(
609 QuicServerId(override_sni_, address().port(), false));
610 }
611
612 client_->Connect();
613 connect_attempted_ = true;
614}
615
616void QuicTestClient::ResetConnection() {
617 Disconnect();
618 Connect();
619}
620
621void QuicTestClient::Disconnect() {
622 ClearPerConnectionState();
623 client_->Disconnect();
624 connect_attempted_ = false;
625}
626
627QuicSocketAddress QuicTestClient::local_address() const {
628 return client_->network_helper()->GetLatestClientAddress();
629}
630
631void QuicTestClient::ClearPerRequestState() {
632 stream_error_ = QUIC_STREAM_NO_ERROR;
633 response_ = "";
634 response_complete_ = false;
635 response_headers_complete_ = false;
636 preliminary_headers_.clear();
637 response_headers_.clear();
638 response_trailers_.clear();
639 bytes_read_ = 0;
640 bytes_written_ = 0;
641 response_body_size_ = 0;
642}
643
644bool QuicTestClient::HaveActiveStream() {
645 return push_promise_data_to_resend_.get() || !open_streams_.empty();
646}
647
648bool QuicTestClient::WaitUntil(int timeout_ms, std::function<bool()> trigger) {
649 int64_t timeout_us = timeout_ms * kNumMicrosPerMilli;
650 int64_t old_timeout_us = epoll_server()->timeout_in_us_for_test();
651 if (timeout_us > 0) {
652 epoll_server()->set_timeout_in_us(timeout_us);
653 }
654 const QuicClock* clock =
655 QuicConnectionPeer::GetHelper(client()->session()->connection())
656 ->GetClock();
657 QuicTime end_waiting_time =
658 clock->Now() + QuicTime::Delta::FromMicroseconds(timeout_us);
659 while (HaveActiveStream() && !(trigger && trigger()) &&
660 (timeout_us < 0 || clock->Now() < end_waiting_time)) {
661 client_->WaitForEvents();
662 }
663 ReadNextResponse();
664 if (timeout_us > 0) {
665 epoll_server()->set_timeout_in_us(old_timeout_us);
666 }
667 if (trigger && !trigger()) {
QUICHE team38c190b2019-05-08 09:12:01 -0700668 QUIC_VLOG(1) << "Client WaitUntil returning with trigger returning false."
669 << QuicStackTrace();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500670 return false;
671 }
672 return true;
673}
674
dschinazib3b51de2019-12-19 16:52:04 -0800675ssize_t QuicTestClient::Send(quiche::QuicheStringPiece data) {
QUICHE team0530cc82019-12-18 12:34:11 -0800676 return SendData(std::string(data), false);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500677}
678
679bool QuicTestClient::response_headers_complete() const {
680 for (std::pair<QuicStreamId, QuicSpdyClientStream*> stream : open_streams_) {
681 if (stream.second->headers_decompressed()) {
682 return true;
683 }
684 }
685 return response_headers_complete_;
686}
687
688const spdy::SpdyHeaderBlock* QuicTestClient::response_headers() const {
689 for (std::pair<QuicStreamId, QuicSpdyClientStream*> stream : open_streams_) {
bnc0e2735f2019-04-25 09:51:18 -0700690 if (stream.second->headers_decompressed()) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500691 response_headers_ = stream.second->response_headers().Clone();
692 break;
693 }
694 }
695 return &response_headers_;
696}
697
698const spdy::SpdyHeaderBlock* QuicTestClient::preliminary_headers() const {
699 for (std::pair<QuicStreamId, QuicSpdyClientStream*> stream : open_streams_) {
700 size_t bytes_read =
701 stream.second->stream_bytes_read() + stream.second->header_bytes_read();
702 if (bytes_read > 0) {
703 preliminary_headers_ = stream.second->preliminary_headers().Clone();
704 break;
705 }
706 }
707 return &preliminary_headers_;
708}
709
710const spdy::SpdyHeaderBlock& QuicTestClient::response_trailers() const {
711 return response_trailers_;
712}
713
714int64_t QuicTestClient::response_size() const {
715 return bytes_read();
716}
717
718size_t QuicTestClient::bytes_read() const {
719 for (std::pair<QuicStreamId, QuicSpdyClientStream*> stream : open_streams_) {
720 size_t bytes_read = stream.second->total_body_bytes_read() +
721 stream.second->header_bytes_read();
722 if (bytes_read > 0) {
723 return bytes_read;
724 }
725 }
726 return bytes_read_;
727}
728
729size_t QuicTestClient::bytes_written() const {
730 for (std::pair<QuicStreamId, QuicSpdyClientStream*> stream : open_streams_) {
731 size_t bytes_written = stream.second->stream_bytes_written() +
732 stream.second->header_bytes_written();
733 if (bytes_written > 0) {
734 return bytes_written;
735 }
736 }
737 return bytes_written_;
738}
739
740void QuicTestClient::OnClose(QuicSpdyStream* stream) {
741 if (stream == nullptr) {
742 return;
743 }
744 // Always close the stream, regardless of whether it was the last stream
745 // written.
746 client()->OnClose(stream);
747 ++num_responses_;
748 if (!QuicContainsKey(open_streams_, stream->id())) {
749 return;
750 }
751 if (latest_created_stream_ == stream) {
752 latest_created_stream_ = nullptr;
753 }
754 QuicSpdyClientStream* client_stream =
755 static_cast<QuicSpdyClientStream*>(stream);
756 QuicStreamId id = client_stream->id();
757 closed_stream_states_.insert(std::make_pair(
758 id,
759 PerStreamState(
760 client_stream->stream_error(), true,
761 client_stream->headers_decompressed(),
762 client_stream->response_headers(),
763 client_stream->preliminary_headers(),
764 (buffer_body() ? client_stream->data() : ""),
765 client_stream->received_trailers(),
766 // Use NumBytesConsumed to avoid counting retransmitted stream frames.
767 client_stream->total_body_bytes_read() +
768 client_stream->header_bytes_read(),
769 client_stream->stream_bytes_written() +
770 client_stream->header_bytes_written(),
771 client_stream->data().size())));
772 open_streams_.erase(id);
773}
774
dschinazi17d42422019-06-18 16:35:07 -0700775bool QuicTestClient::CheckVary(
776 const spdy::SpdyHeaderBlock& /*client_request*/,
777 const spdy::SpdyHeaderBlock& /*promise_request*/,
778 const spdy::SpdyHeaderBlock& /*promise_response*/) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500779 return true;
780}
781
782void QuicTestClient::OnRendezvousResult(QuicSpdyStream* stream) {
783 std::unique_ptr<TestClientDataToResend> data_to_resend =
784 std::move(push_promise_data_to_resend_);
785 SetLatestCreatedStream(static_cast<QuicSpdyClientStream*>(stream));
786 if (stream) {
787 stream->OnBodyAvailable();
788 } else if (data_to_resend) {
789 data_to_resend->Resend();
790 }
791}
792
793void QuicTestClient::UseWriter(QuicPacketWriterWrapper* writer) {
794 client_->UseWriter(writer);
795}
796
dschinazi8ff74822019-05-28 16:37:20 -0700797void QuicTestClient::UseConnectionId(QuicConnectionId server_connection_id) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500798 DCHECK(!connected());
dschinazi8ff74822019-05-28 16:37:20 -0700799 client_->UseConnectionId(server_connection_id);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500800}
801
dschinazic8579862019-07-24 18:20:20 -0700802void QuicTestClient::UseConnectionIdLength(int server_connection_id_length) {
803 DCHECK(!connected());
804 client_->UseConnectionIdLength(server_connection_id_length);
805}
806
dschinazi346b7ce2019-06-05 01:38:18 -0700807void QuicTestClient::UseClientConnectionId(
808 QuicConnectionId client_connection_id) {
809 DCHECK(!connected());
810 client_->UseClientConnectionId(client_connection_id);
811}
812
dschinazic8579862019-07-24 18:20:20 -0700813void QuicTestClient::UseClientConnectionIdLength(
814 int client_connection_id_length) {
815 DCHECK(!connected());
816 client_->UseClientConnectionIdLength(client_connection_id_length);
817}
818
QUICHE teama6ef0a62019-03-07 20:34:33 -0500819bool QuicTestClient::MigrateSocket(const QuicIpAddress& new_host) {
820 return client_->MigrateSocket(new_host);
821}
822
823bool QuicTestClient::MigrateSocketWithSpecifiedPort(
824 const QuicIpAddress& new_host,
825 int port) {
826 client_->set_local_port(port);
827 return client_->MigrateSocket(new_host);
828}
829
830QuicIpAddress QuicTestClient::bind_to_address() const {
831 return client_->bind_to_address();
832}
833
834void QuicTestClient::set_bind_to_address(QuicIpAddress address) {
835 client_->set_bind_to_address(address);
836}
837
838const QuicSocketAddress& QuicTestClient::address() const {
839 return client_->server_address();
840}
841
842void QuicTestClient::WaitForWriteToFlush() {
843 while (connected() && client()->session()->HasDataToWrite()) {
844 client_->WaitForEvents();
845 }
846}
847
848QuicTestClient::TestClientDataToResend::TestClientDataToResend(
849 std::unique_ptr<spdy::SpdyHeaderBlock> headers,
QUICHE team6dcf6ab2019-12-11 10:10:51 -0800850 quiche::QuicheStringPiece body,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500851 bool fin,
852 QuicTestClient* test_client,
853 QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener)
854 : QuicClient::QuicDataToResend(std::move(headers), body, fin),
855 test_client_(test_client),
856 ack_listener_(std::move(ack_listener)) {}
857
858QuicTestClient::TestClientDataToResend::~TestClientDataToResend() = default;
859
860void QuicTestClient::TestClientDataToResend::Resend() {
861 test_client_->GetOrCreateStreamAndSendRequest(headers_.get(), body_, fin_,
862 ack_listener_);
863 headers_.reset();
864}
865
866QuicTestClient::PerStreamState::PerStreamState(const PerStreamState& other)
867 : stream_error(other.stream_error),
868 response_complete(other.response_complete),
869 response_headers_complete(other.response_headers_complete),
870 response_headers(other.response_headers.Clone()),
871 preliminary_headers(other.preliminary_headers.Clone()),
872 response(other.response),
873 response_trailers(other.response_trailers.Clone()),
874 bytes_read(other.bytes_read),
875 bytes_written(other.bytes_written),
876 response_body_size(other.response_body_size) {}
877
878QuicTestClient::PerStreamState::PerStreamState(
879 QuicRstStreamErrorCode stream_error,
880 bool response_complete,
881 bool response_headers_complete,
882 const spdy::SpdyHeaderBlock& response_headers,
883 const spdy::SpdyHeaderBlock& preliminary_headers,
vasilvvc48c8712019-03-11 13:38:16 -0700884 const std::string& response,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500885 const spdy::SpdyHeaderBlock& response_trailers,
886 uint64_t bytes_read,
887 uint64_t bytes_written,
888 int64_t response_body_size)
889 : stream_error(stream_error),
890 response_complete(response_complete),
891 response_headers_complete(response_headers_complete),
892 response_headers(response_headers.Clone()),
893 preliminary_headers(preliminary_headers.Clone()),
894 response(response),
895 response_trailers(response_trailers.Clone()),
896 bytes_read(bytes_read),
897 bytes_written(bytes_written),
898 response_body_size(response_body_size) {}
899
900QuicTestClient::PerStreamState::~PerStreamState() = default;
901
902bool QuicTestClient::PopulateHeaderBlockFromUrl(
vasilvvc48c8712019-03-11 13:38:16 -0700903 const std::string& uri,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500904 spdy::SpdyHeaderBlock* headers) {
vasilvvc48c8712019-03-11 13:38:16 -0700905 std::string url;
QUICHE team6dcf6ab2019-12-11 10:10:51 -0800906 if (quiche::QuicheTextUtils::StartsWith(uri, "https://") ||
907 quiche::QuicheTextUtils::StartsWith(uri, "http://")) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500908 url = uri;
909 } else if (uri[0] == '/') {
910 url = "https://" + client_->server_id().host() + uri;
911 } else {
912 url = "https://" + uri;
913 }
914 return SpdyUtils::PopulateHeaderBlockFromUrl(url, headers);
915}
916
917void QuicTestClient::ReadNextResponse() {
918 if (closed_stream_states_.empty()) {
919 return;
920 }
921
922 PerStreamState state(closed_stream_states_.front().second);
923
924 stream_error_ = state.stream_error;
925 response_ = state.response;
926 response_complete_ = state.response_complete;
927 response_headers_complete_ = state.response_headers_complete;
928 preliminary_headers_ = state.preliminary_headers.Clone();
929 response_headers_ = state.response_headers.Clone();
930 response_trailers_ = state.response_trailers.Clone();
931 bytes_read_ = state.bytes_read;
932 bytes_written_ = state.bytes_written;
933 response_body_size_ = state.response_body_size;
934
935 closed_stream_states_.pop_front();
936}
937
938void QuicTestClient::ClearPerConnectionState() {
939 ClearPerRequestState();
940 open_streams_.clear();
941 closed_stream_states_.clear();
942 latest_created_stream_ = nullptr;
943}
944
945void QuicTestClient::WaitForDelayedAcks() {
946 // kWaitDuration is a period of time that is long enough for all delayed
947 // acks to be sent and received on the other end.
948 const QuicTime::Delta kWaitDuration =
949 4 * QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs);
950
951 const QuicClock* clock = client()->client_session()->connection()->clock();
952
953 QuicTime wait_until = clock->ApproximateNow() + kWaitDuration;
954 while (clock->ApproximateNow() < wait_until) {
955 // This waits for up to 50 ms.
956 client()->WaitForEvents();
957 }
958}
959
960} // namespace test
961} // namespace quic