Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / net / tools / quic / test_tools / quic_test_client.cc
blob4d577e5ec34bc0efdcd0801a357c9513655b7561
1 // 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.
5 #include "net/tools/quic/test_tools/quic_test_client.h"
7 #include "base/time/time.h"
8 #include "net/base/completion_callback.h"
9 #include "net/base/net_errors.h"
10 #include "net/cert/cert_verify_result.h"
11 #include "net/cert/x509_certificate.h"
12 #include "net/quic/crypto/proof_verifier.h"
13 #include "net/quic/quic_flags.h"
14 #include "net/quic/quic_server_id.h"
15 #include "net/quic/test_tools/quic_connection_peer.h"
16 #include "net/quic/test_tools/quic_spdy_session_peer.h"
17 #include "net/quic/test_tools/quic_test_utils.h"
18 #include "net/quic/test_tools/reliable_quic_stream_peer.h"
19 #include "net/tools/balsa/balsa_headers.h"
20 #include "net/tools/quic/quic_epoll_connection_helper.h"
21 #include "net/tools/quic/quic_packet_writer_wrapper.h"
22 #include "net/tools/quic/quic_spdy_client_stream.h"
23 #include "net/tools/quic/spdy_balsa_utils.h"
24 #include "net/tools/quic/test_tools/http_message.h"
25 #include "net/tools/quic/test_tools/quic_client_peer.h"
26 #include "url/gurl.h"
28 using base::StringPiece;
29 using net::QuicServerId;
30 using net::test::QuicConnectionPeer;
31 using net::test::QuicSpdySessionPeer;
32 using net::test::ReliableQuicStreamPeer;
33 using std::string;
34 using std::vector;
36 namespace net {
37 namespace tools {
38 namespace test {
39 namespace {
41 // RecordingProofVerifier accepts any certificate chain and records the common
42 // name of the leaf.
43 class RecordingProofVerifier : public ProofVerifier {
44 public:
45 // ProofVerifier interface.
46 QuicAsyncStatus VerifyProof(const string& hostname,
47 const string& server_config,
48 const vector<string>& certs,
49 const string& signature,
50 const ProofVerifyContext* context,
51 string* error_details,
52 scoped_ptr<ProofVerifyDetails>* details,
53 ProofVerifierCallback* callback) override {
54 common_name_.clear();
55 if (certs.empty()) {
56 return QUIC_FAILURE;
59 // Convert certs to X509Certificate.
60 vector<StringPiece> cert_pieces(certs.size());
61 for (unsigned i = 0; i < certs.size(); i++) {
62 cert_pieces[i] = StringPiece(certs[i]);
64 scoped_refptr<net::X509Certificate> cert =
65 net::X509Certificate::CreateFromDERCertChain(cert_pieces);
66 if (!cert.get()) {
67 return QUIC_FAILURE;
70 common_name_ = cert->subject().GetDisplayName();
71 return QUIC_SUCCESS;
74 const string& common_name() const { return common_name_; }
76 private:
77 string common_name_;
80 } // anonymous namespace
82 BalsaHeaders* MungeHeaders(const BalsaHeaders* const_headers,
83 bool secure) {
84 StringPiece uri = const_headers->request_uri();
85 if (uri.empty()) {
86 return nullptr;
88 if (const_headers->request_method() == "CONNECT") {
89 return nullptr;
91 BalsaHeaders* headers = new BalsaHeaders;
92 headers->CopyFrom(*const_headers);
93 if (!uri.starts_with("https://") &&
94 !uri.starts_with("http://")) {
95 // If we have a relative URL, set some defaults.
96 string full_uri = secure ? "https://www.google.com" :
97 "http://www.google.com";
98 full_uri.append(uri.as_string());
99 headers->SetRequestUri(full_uri);
101 return headers;
104 MockableQuicClient::MockableQuicClient(
105 IPEndPoint server_address,
106 const QuicServerId& server_id,
107 const QuicVersionVector& supported_versions,
108 EpollServer* epoll_server)
109 : QuicClient(server_address,
110 server_id,
111 supported_versions,
112 epoll_server),
113 override_connection_id_(0),
114 test_writer_(nullptr) {}
116 MockableQuicClient::MockableQuicClient(
117 IPEndPoint server_address,
118 const QuicServerId& server_id,
119 const QuicConfig& config,
120 const QuicVersionVector& supported_versions,
121 EpollServer* epoll_server)
122 : QuicClient(server_address,
123 server_id,
124 supported_versions,
125 config,
126 epoll_server),
127 override_connection_id_(0),
128 test_writer_(nullptr) {}
130 MockableQuicClient::~MockableQuicClient() {
131 if (connected()) {
132 Disconnect();
136 QuicPacketWriter* MockableQuicClient::CreateQuicPacketWriter() {
137 QuicPacketWriter* writer = QuicClient::CreateQuicPacketWriter();
138 if (!test_writer_) {
139 return writer;
141 test_writer_->set_writer(writer);
142 return test_writer_;
145 QuicConnectionId MockableQuicClient::GenerateConnectionId() {
146 return override_connection_id_ ? override_connection_id_
147 : QuicClient::GenerateConnectionId();
150 // Takes ownership of writer.
151 void MockableQuicClient::UseWriter(QuicPacketWriterWrapper* writer) {
152 CHECK(test_writer_ == nullptr);
153 test_writer_ = writer;
156 void MockableQuicClient::UseConnectionId(QuicConnectionId connection_id) {
157 override_connection_id_ = connection_id;
160 QuicTestClient::QuicTestClient(IPEndPoint server_address,
161 const string& server_hostname,
162 bool secure,
163 const QuicVersionVector& supported_versions)
164 : client_(new MockableQuicClient(server_address,
165 QuicServerId(server_hostname,
166 server_address.port(),
167 secure,
168 PRIVACY_MODE_DISABLED),
169 supported_versions,
170 &epoll_server_)) {
171 Initialize(secure);
174 QuicTestClient::QuicTestClient(
175 IPEndPoint server_address,
176 const string& server_hostname,
177 bool secure,
178 const QuicConfig& config,
179 const QuicVersionVector& supported_versions)
180 : client_(
181 new MockableQuicClient(server_address,
182 QuicServerId(server_hostname,
183 server_address.port(),
184 secure,
185 PRIVACY_MODE_DISABLED),
186 config,
187 supported_versions,
188 &epoll_server_)) {
189 Initialize(secure);
192 QuicTestClient::QuicTestClient() {
195 QuicTestClient::~QuicTestClient() {
196 if (stream_) {
197 stream_->set_visitor(nullptr);
201 void QuicTestClient::Initialize(bool secure) {
202 priority_ = 3;
203 connect_attempted_ = false;
204 secure_ = secure;
205 auto_reconnect_ = false;
206 buffer_body_ = true;
207 fec_policy_ = FEC_PROTECT_OPTIONAL;
208 proof_verifier_ = nullptr;
209 ClearPerRequestState();
210 ExpectCertificates(secure_);
211 // As chrome will generally do this, we want it to be the default when it's
212 // not overridden.
213 if (!client_->config()->HasSetBytesForConnectionIdToSend()) {
214 client_->config()->SetBytesForConnectionIdToSend(0);
218 void QuicTestClient::ExpectCertificates(bool on) {
219 if (on) {
220 proof_verifier_ = new RecordingProofVerifier;
221 client_->SetProofVerifier(proof_verifier_);
222 } else {
223 proof_verifier_ = nullptr;
224 client_->SetProofVerifier(nullptr);
228 void QuicTestClient::SetUserAgentID(const string& user_agent_id) {
229 client_->SetUserAgentID(user_agent_id);
232 ssize_t QuicTestClient::SendRequest(const string& uri) {
233 HTTPMessage message(HttpConstants::HTTP_1_1,
234 HttpConstants::GET,
235 uri);
236 return SendMessage(message);
239 void QuicTestClient::SendRequestsAndWaitForResponses(
240 const vector<string>& url_list) {
241 for (const string& url : url_list) {
242 SendRequest(url);
244 while (client()->WaitForEvents()) {
246 return;
249 ssize_t QuicTestClient::SendMessage(const HTTPMessage& message) {
250 stream_ = nullptr; // Always force creation of a stream for SendMessage.
252 // If we're not connected, try to find an sni hostname.
253 if (!connected()) {
254 GURL url(message.headers()->request_uri().as_string());
255 if (!url.host().empty()) {
256 client_->set_server_id(
257 QuicServerId(url.host(),
258 url.EffectiveIntPort(),
259 url.SchemeIs("https"),
260 PRIVACY_MODE_DISABLED));
264 QuicSpdyClientStream* stream = GetOrCreateStream();
265 if (!stream) { return 0; }
267 scoped_ptr<BalsaHeaders> munged_headers(MungeHeaders(message.headers(),
268 secure_));
269 SpdyHeaderBlock spdy_headers = SpdyBalsaUtils::RequestHeadersToSpdyHeaders(
270 munged_headers.get() ? *munged_headers : *message.headers(),
271 stream->version());
272 if (FLAGS_spdy_strip_invalid_headers) {
273 // We have tests which rely on sending a non-standards-compliant T-E header.
274 if (message.headers()->HasHeader("transfer-encoding")) {
275 string encoding;
276 message.headers()->GetAllOfHeaderAsString("transfer-encoding", &encoding);
277 spdy_headers.insert(std::make_pair("transfer-encoding", encoding));
280 ssize_t ret = GetOrCreateStream()->SendRequest(
281 spdy_headers, message.body(), message.has_complete_message());
282 WaitForWriteToFlush();
283 return ret;
286 ssize_t QuicTestClient::SendData(string data, bool last_data) {
287 return SendData(data, last_data, nullptr);
290 ssize_t QuicTestClient::SendData(string data,
291 bool last_data,
292 QuicAckNotifier::DelegateInterface* delegate) {
293 QuicSpdyClientStream* stream = GetOrCreateStream();
294 if (!stream) { return 0; }
295 GetOrCreateStream()->SendBody(data, last_data, delegate);
296 WaitForWriteToFlush();
297 return data.length();
300 bool QuicTestClient::response_complete() const {
301 return response_complete_;
304 int QuicTestClient::response_header_size() const {
305 return response_header_size_;
308 int64 QuicTestClient::response_body_size() const {
309 return response_body_size_;
312 bool QuicTestClient::buffer_body() const {
313 return buffer_body_;
316 void QuicTestClient::set_buffer_body(bool buffer_body) {
317 buffer_body_ = buffer_body;
320 bool QuicTestClient::ServerInLameDuckMode() const {
321 return false;
324 const string& QuicTestClient::response_body() {
325 return response_;
328 string QuicTestClient::SendCustomSynchronousRequest(
329 const HTTPMessage& message) {
330 SendMessage(message);
331 WaitForResponse();
332 return response_;
335 string QuicTestClient::SendSynchronousRequest(const string& uri) {
336 if (SendRequest(uri) == 0) {
337 DLOG(ERROR) << "Failed the request for uri:" << uri;
338 // Set the response_ explicitly. Otherwise response_ will contain the
339 // response from the previously successful request.
340 response_ = "";
341 } else {
342 WaitForResponse();
344 return response_;
347 QuicSpdyClientStream* QuicTestClient::GetOrCreateStream() {
348 if (!connect_attempted_ || auto_reconnect_) {
349 if (!connected()) {
350 Connect();
352 if (!connected()) {
353 return nullptr;
356 if (!stream_) {
357 stream_ = client_->CreateReliableClientStream();
358 if (stream_ == nullptr) {
359 return nullptr;
361 stream_->set_visitor(this);
362 reinterpret_cast<QuicSpdyClientStream*>(stream_)->set_priority(priority_);
363 // Set FEC policy on stream.
364 ReliableQuicStreamPeer::SetFecPolicy(stream_, fec_policy_);
367 return stream_;
370 QuicErrorCode QuicTestClient::connection_error() {
371 return client()->session()->error();
374 MockableQuicClient* QuicTestClient::client() { return client_.get(); }
376 const string& QuicTestClient::cert_common_name() const {
377 return reinterpret_cast<RecordingProofVerifier*>(proof_verifier_)
378 ->common_name();
381 QuicTagValueMap QuicTestClient::GetServerConfig() const {
382 QuicCryptoClientConfig* config =
383 QuicClientPeer::GetCryptoConfig(client_.get());
384 QuicCryptoClientConfig::CachedState* state =
385 config->LookupOrCreate(client_->server_id());
386 const CryptoHandshakeMessage* handshake_msg = state->GetServerConfig();
387 if (handshake_msg != nullptr) {
388 return handshake_msg->tag_value_map();
389 } else {
390 return QuicTagValueMap();
394 bool QuicTestClient::connected() const {
395 return client_->connected();
398 void QuicTestClient::Connect() {
399 DCHECK(!connected());
400 if (!connect_attempted_) {
401 client_->Initialize();
403 client_->Connect();
404 connect_attempted_ = true;
407 void QuicTestClient::ResetConnection() {
408 Disconnect();
409 Connect();
412 void QuicTestClient::Disconnect() {
413 client_->Disconnect();
414 connect_attempted_ = false;
417 IPEndPoint QuicTestClient::LocalSocketAddress() const {
418 return client_->client_address();
421 void QuicTestClient::ClearPerRequestState() {
422 stream_error_ = QUIC_STREAM_NO_ERROR;
423 stream_ = nullptr;
424 response_ = "";
425 response_complete_ = false;
426 response_headers_complete_ = false;
427 headers_.Clear();
428 bytes_read_ = 0;
429 bytes_written_ = 0;
430 response_header_size_ = 0;
431 response_body_size_ = 0;
434 void QuicTestClient::WaitForResponseForMs(int timeout_ms) {
435 int64 timeout_us = timeout_ms * base::Time::kMicrosecondsPerMillisecond;
436 int64 old_timeout_us = epoll_server()->timeout_in_us();
437 if (timeout_us > 0) {
438 epoll_server()->set_timeout_in_us(timeout_us);
440 const QuicClock* clock =
441 QuicConnectionPeer::GetHelper(client()->session()->connection())->
442 GetClock();
443 QuicTime end_waiting_time = clock->Now().Add(
444 QuicTime::Delta::FromMicroseconds(timeout_us));
445 while (stream_ != nullptr &&
446 !client_->session()->IsClosedStream(stream_->id()) &&
447 (timeout_us < 0 || clock->Now() < end_waiting_time)) {
448 client_->WaitForEvents();
450 if (timeout_us > 0) {
451 epoll_server()->set_timeout_in_us(old_timeout_us);
455 void QuicTestClient::WaitForInitialResponseForMs(int timeout_ms) {
456 int64 timeout_us = timeout_ms * base::Time::kMicrosecondsPerMillisecond;
457 int64 old_timeout_us = epoll_server()->timeout_in_us();
458 if (timeout_us > 0) {
459 epoll_server()->set_timeout_in_us(timeout_us);
461 const QuicClock* clock =
462 QuicConnectionPeer::GetHelper(client()->session()->connection())->
463 GetClock();
464 QuicTime end_waiting_time = clock->Now().Add(
465 QuicTime::Delta::FromMicroseconds(timeout_us));
466 while (stream_ != nullptr &&
467 !client_->session()->IsClosedStream(stream_->id()) &&
468 stream_->stream_bytes_read() == 0 &&
469 (timeout_us < 0 || clock->Now() < end_waiting_time)) {
470 client_->WaitForEvents();
472 if (timeout_us > 0) {
473 epoll_server()->set_timeout_in_us(old_timeout_us);
477 ssize_t QuicTestClient::Send(const void *buffer, size_t size) {
478 return SendData(string(static_cast<const char*>(buffer), size), false);
481 bool QuicTestClient::response_headers_complete() const {
482 if (stream_ != nullptr) {
483 return stream_->headers_decompressed();
485 return response_headers_complete_;
488 const BalsaHeaders* QuicTestClient::response_headers() const {
489 if (stream_ != nullptr) {
490 SpdyBalsaUtils::SpdyHeadersToResponseHeaders(stream_->headers(), &headers_,
491 stream_->version());
492 return &headers_;
493 } else {
494 return &headers_;
498 int64 QuicTestClient::response_size() const {
499 return bytes_read_;
502 size_t QuicTestClient::bytes_read() const {
503 return bytes_read_;
506 size_t QuicTestClient::bytes_written() const {
507 return bytes_written_;
510 void QuicTestClient::OnClose(QuicDataStream* stream) {
511 if (stream != nullptr) {
512 // Always close the stream, regardless of whether it was the last stream
513 // written.
514 client()->OnClose(stream);
516 if (stream_ != stream) {
517 return;
519 if (buffer_body()) {
520 // TODO(fnk): The stream still buffers the whole thing. Fix that.
521 response_ = stream_->data();
523 response_complete_ = true;
524 response_headers_complete_ = stream_->headers_decompressed();
525 SpdyBalsaUtils::SpdyHeadersToResponseHeaders(stream_->headers(), &headers_,
526 stream_->version());
527 stream_error_ = stream_->stream_error();
528 bytes_read_ = stream_->stream_bytes_read() + stream_->header_bytes_read();
529 bytes_written_ =
530 stream_->stream_bytes_written() + stream_->header_bytes_written();
531 response_header_size_ = headers_.GetSizeForWriteBuffer();
532 response_body_size_ = stream_->data().size();
533 stream_ = nullptr;
536 void QuicTestClient::UseWriter(QuicPacketWriterWrapper* writer) {
537 client_->UseWriter(writer);
540 void QuicTestClient::UseConnectionId(QuicConnectionId connection_id) {
541 DCHECK(!connected());
542 client_->UseConnectionId(connection_id);
545 ssize_t QuicTestClient::SendAndWaitForResponse(const void *buffer,
546 size_t size) {
547 LOG(DFATAL) << "Not implemented";
548 return 0;
551 void QuicTestClient::Bind(IPEndPoint* local_address) {
552 DLOG(WARNING) << "Bind will be done during connect";
555 string QuicTestClient::SerializeMessage(const HTTPMessage& message) {
556 LOG(DFATAL) << "Not implemented";
557 return "";
560 IPAddressNumber QuicTestClient::bind_to_address() const {
561 return client_->bind_to_address();
564 void QuicTestClient::set_bind_to_address(IPAddressNumber address) {
565 client_->set_bind_to_address(address);
568 const IPEndPoint& QuicTestClient::address() const {
569 LOG(DFATAL) << "Not implemented";
570 return client_->server_address();
573 size_t QuicTestClient::requests_sent() const {
574 LOG(DFATAL) << "Not implemented";
575 return 0;
578 void QuicTestClient::WaitForWriteToFlush() {
579 while (connected() && client()->session()->HasDataToWrite()) {
580 client_->WaitForEvents();
584 void QuicTestClient::SetFecPolicy(FecPolicy fec_policy) {
585 fec_policy_ = fec_policy;
586 // Set policy for headers and crypto streams.
587 ReliableQuicStreamPeer::SetFecPolicy(
588 QuicSpdySessionPeer::GetHeadersStream(client()->session()), fec_policy);
589 ReliableQuicStreamPeer::SetFecPolicy(client()->session()->GetCryptoStream(),
590 fec_policy);
593 } // namespace test
594 } // namespace tools
595 } // namespace net