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"
28 using base::StringPiece
;
29 using net::QuicServerId
;
30 using net::test::QuicConnectionPeer
;
31 using net::test::QuicSpdySessionPeer
;
32 using net::test::ReliableQuicStreamPeer
;
41 // RecordingProofVerifier accepts any certificate chain and records the common
43 class RecordingProofVerifier
: public ProofVerifier
{
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
{
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
);
70 common_name_
= cert
->subject().GetDisplayName();
74 const string
& common_name() const { return common_name_
; }
80 } // anonymous namespace
82 BalsaHeaders
* MungeHeaders(const BalsaHeaders
* const_headers
,
84 StringPiece uri
= const_headers
->request_uri();
88 if (const_headers
->request_method() == "CONNECT") {
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
);
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
,
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
,
127 override_connection_id_(0),
128 test_writer_(nullptr) {}
130 MockableQuicClient::~MockableQuicClient() {
136 QuicPacketWriter
* MockableQuicClient::CreateQuicPacketWriter() {
137 QuicPacketWriter
* writer
= QuicClient::CreateQuicPacketWriter();
141 test_writer_
->set_writer(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
,
163 const QuicVersionVector
& supported_versions
)
164 : client_(new MockableQuicClient(server_address
,
165 QuicServerId(server_hostname
,
166 server_address
.port(),
168 PRIVACY_MODE_DISABLED
),
174 QuicTestClient::QuicTestClient(
175 IPEndPoint server_address
,
176 const string
& server_hostname
,
178 const QuicConfig
& config
,
179 const QuicVersionVector
& supported_versions
)
181 new MockableQuicClient(server_address
,
182 QuicServerId(server_hostname
,
183 server_address
.port(),
185 PRIVACY_MODE_DISABLED
),
192 QuicTestClient::QuicTestClient() {
195 QuicTestClient::~QuicTestClient() {
197 stream_
->set_visitor(nullptr);
201 void QuicTestClient::Initialize(bool secure
) {
203 connect_attempted_
= false;
205 auto_reconnect_
= false;
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
213 if (!client_
->config()->HasSetBytesForConnectionIdToSend()) {
214 client_
->config()->SetBytesForConnectionIdToSend(0);
218 void QuicTestClient::ExpectCertificates(bool on
) {
220 proof_verifier_
= new RecordingProofVerifier
;
221 client_
->SetProofVerifier(proof_verifier_
);
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
,
236 return SendMessage(message
);
239 void QuicTestClient::SendRequestsAndWaitForResponses(
240 const vector
<string
>& url_list
) {
241 for (const string
& url
: url_list
) {
244 while (client()->WaitForEvents()) {
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.
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(),
269 SpdyHeaderBlock spdy_headers
= SpdyBalsaUtils::RequestHeadersToSpdyHeaders(
270 munged_headers
.get() ? *munged_headers
: *message
.headers(),
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")) {
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();
286 ssize_t
QuicTestClient::SendData(string data
, bool last_data
) {
287 return SendData(data
, last_data
, nullptr);
290 ssize_t
QuicTestClient::SendData(string 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 {
316 void QuicTestClient::set_buffer_body(bool buffer_body
) {
317 buffer_body_
= buffer_body
;
320 bool QuicTestClient::ServerInLameDuckMode() const {
324 const string
& QuicTestClient::response_body() {
328 string
QuicTestClient::SendCustomSynchronousRequest(
329 const HTTPMessage
& message
) {
330 SendMessage(message
);
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.
347 QuicSpdyClientStream
* QuicTestClient::GetOrCreateStream() {
348 if (!connect_attempted_
|| auto_reconnect_
) {
357 stream_
= client_
->CreateReliableClientStream();
358 if (stream_
== 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_
);
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_
)
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();
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();
404 connect_attempted_
= true;
407 void QuicTestClient::ResetConnection() {
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
;
425 response_complete_
= false;
426 response_headers_complete_
= false;
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())->
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())->
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_
,
498 int64
QuicTestClient::response_size() const {
502 size_t QuicTestClient::bytes_read() const {
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
514 client()->OnClose(stream
);
516 if (stream_
!= stream
) {
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_
,
527 stream_error_
= stream_
->stream_error();
528 bytes_read_
= stream_
->stream_bytes_read() + stream_
->header_bytes_read();
530 stream_
->stream_bytes_written() + stream_
->header_bytes_written();
531 response_header_size_
= headers_
.GetSizeForWriteBuffer();
532 response_body_size_
= stream_
->data().size();
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
,
547 LOG(DFATAL
) << "Not implemented";
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";
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";
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(),