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.
4
5 #include "net/tools/quic/test_tools/quic_test_client.h"
6
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_server_id.h"
14 #include "net/quic/test_tools/quic_connection_peer.h"
15 #include "net/quic/test_tools/quic_session_peer.h"
16 #include "net/quic/test_tools/quic_test_utils.h"
17 #include "net/quic/test_tools/reliable_quic_stream_peer.h"
18 #include "net/tools/balsa/balsa_headers.h"
19 #include "net/tools/quic/quic_epoll_connection_helper.h"
20 #include "net/tools/quic/quic_packet_writer_wrapper.h"
21 #include "net/tools/quic/quic_spdy_client_stream.h"
22 #include "net/tools/quic/test_tools/http_message.h"
23 #include "net/tools/quic/test_tools/quic_client_peer.h"
24 #include "url/gurl.h"
25
26 using base::StringPiece;
27 using net::QuicServerId;
28 using net::test::QuicConnectionPeer;
29 using net::test::QuicSessionPeer;
30 using net::test::ReliableQuicStreamPeer;
31 using std::string;
32 using std::vector;
33
34 namespace net {
35 namespace tools {
36 namespace test {
37 namespace {
38
39 // RecordingProofVerifier accepts any certificate chain and records the common
40 // name of the leaf.
41 class RecordingProofVerifier : public ProofVerifier {
42 public:
43 // ProofVerifier interface.
VerifyProof(const string & hostname,const string & server_config,const vector<string> & certs,const string & signature,const ProofVerifyContext * context,string * error_details,scoped_ptr<ProofVerifyDetails> * details,ProofVerifierCallback * callback)44 virtual QuicAsyncStatus VerifyProof(
45 const string& hostname,
46 const string& server_config,
47 const vector<string>& certs,
48 const string& signature,
49 const ProofVerifyContext* context,
50 string* error_details,
51 scoped_ptr<ProofVerifyDetails>* details,
52 ProofVerifierCallback* callback) OVERRIDE {
53 common_name_.clear();
54 if (certs.empty()) {
55 return QUIC_FAILURE;
56 }
57
58 // Convert certs to X509Certificate.
59 vector<StringPiece> cert_pieces(certs.size());
60 for (unsigned i = 0; i < certs.size(); i++) {
61 cert_pieces[i] = StringPiece(certs[i]);
62 }
63 scoped_refptr<net::X509Certificate> cert =
64 net::X509Certificate::CreateFromDERCertChain(cert_pieces);
65 if (!cert.get()) {
66 return QUIC_FAILURE;
67 }
68
69 common_name_ = cert->subject().GetDisplayName();
70 return QUIC_SUCCESS;
71 }
72
common_name() const73 const string& common_name() const { return common_name_; }
74
75 private:
76 string common_name_;
77 };
78
79 } // anonymous namespace
80
MungeHeaders(const BalsaHeaders * const_headers,bool secure)81 BalsaHeaders* MungeHeaders(const BalsaHeaders* const_headers,
82 bool secure) {
83 StringPiece uri = const_headers->request_uri();
84 if (uri.empty()) {
85 return NULL;
86 }
87 if (const_headers->request_method() == "CONNECT") {
88 return NULL;
89 }
90 BalsaHeaders* headers = new BalsaHeaders;
91 headers->CopyFrom(*const_headers);
92 if (!uri.starts_with("https://") &&
93 !uri.starts_with("http://")) {
94 // If we have a relative URL, set some defaults.
95 string full_uri = secure ? "https://www.google.com" :
96 "http://www.google.com";
97 full_uri.append(uri.as_string());
98 headers->SetRequestUri(full_uri);
99 }
100 return headers;
101 }
102
MockableQuicClient(IPEndPoint server_address,const QuicServerId & server_id,const QuicVersionVector & supported_versions,EpollServer * epoll_server)103 MockableQuicClient::MockableQuicClient(
104 IPEndPoint server_address,
105 const QuicServerId& server_id,
106 const QuicVersionVector& supported_versions,
107 EpollServer* epoll_server)
108 : QuicClient(server_address,
109 server_id,
110 supported_versions,
111 false,
112 epoll_server),
113 override_connection_id_(0),
114 test_writer_(NULL) {}
115
MockableQuicClient(IPEndPoint server_address,const QuicServerId & server_id,const QuicConfig & config,const QuicVersionVector & supported_versions,EpollServer * epoll_server)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 false,
126 config,
127 epoll_server),
128 override_connection_id_(0),
129 test_writer_(NULL) {}
130
~MockableQuicClient()131 MockableQuicClient::~MockableQuicClient() {
132 if (connected()) {
133 Disconnect();
134 }
135 }
136
CreateQuicPacketWriter()137 QuicPacketWriter* MockableQuicClient::CreateQuicPacketWriter() {
138 QuicPacketWriter* writer = QuicClient::CreateQuicPacketWriter();
139 if (!test_writer_) {
140 return writer;
141 }
142 test_writer_->set_writer(writer);
143 return test_writer_;
144 }
145
GenerateConnectionId()146 QuicConnectionId MockableQuicClient::GenerateConnectionId() {
147 return override_connection_id_ ? override_connection_id_
148 : QuicClient::GenerateConnectionId();
149 }
150
151 // Takes ownership of writer.
UseWriter(QuicPacketWriterWrapper * writer)152 void MockableQuicClient::UseWriter(QuicPacketWriterWrapper* writer) {
153 CHECK(test_writer_ == NULL);
154 test_writer_ = writer;
155 }
156
UseConnectionId(QuicConnectionId connection_id)157 void MockableQuicClient::UseConnectionId(QuicConnectionId connection_id) {
158 override_connection_id_ = connection_id;
159 }
160
QuicTestClient(IPEndPoint server_address,const string & server_hostname,const QuicVersionVector & supported_versions)161 QuicTestClient::QuicTestClient(IPEndPoint server_address,
162 const string& server_hostname,
163 const QuicVersionVector& supported_versions)
164 : client_(new MockableQuicClient(server_address,
165 QuicServerId(server_hostname,
166 server_address.port(),
167 false,
168 PRIVACY_MODE_DISABLED),
169 supported_versions,
170 &epoll_server_)) {
171 Initialize(true);
172 }
173
QuicTestClient(IPEndPoint server_address,const string & server_hostname,bool secure,const QuicVersionVector & supported_versions)174 QuicTestClient::QuicTestClient(IPEndPoint server_address,
175 const string& server_hostname,
176 bool secure,
177 const QuicVersionVector& supported_versions)
178 : client_(new MockableQuicClient(server_address,
179 QuicServerId(server_hostname,
180 server_address.port(),
181 secure,
182 PRIVACY_MODE_DISABLED),
183 supported_versions,
184 &epoll_server_)) {
185 Initialize(secure);
186 }
187
QuicTestClient(IPEndPoint server_address,const string & server_hostname,bool secure,const QuicConfig & config,const QuicVersionVector & supported_versions)188 QuicTestClient::QuicTestClient(
189 IPEndPoint server_address,
190 const string& server_hostname,
191 bool secure,
192 const QuicConfig& config,
193 const QuicVersionVector& supported_versions)
194 : client_(
195 new MockableQuicClient(server_address,
196 QuicServerId(server_hostname,
197 server_address.port(),
198 secure,
199 PRIVACY_MODE_DISABLED),
200 config,
201 supported_versions,
202 &epoll_server_)) {
203 Initialize(secure);
204 }
205
QuicTestClient()206 QuicTestClient::QuicTestClient() {
207 }
208
~QuicTestClient()209 QuicTestClient::~QuicTestClient() {
210 if (stream_) {
211 stream_->set_visitor(NULL);
212 }
213 }
214
Initialize(bool secure)215 void QuicTestClient::Initialize(bool secure) {
216 priority_ = 3;
217 connect_attempted_ = false;
218 secure_ = secure;
219 auto_reconnect_ = false;
220 buffer_body_ = true;
221 fec_policy_ = FEC_PROTECT_OPTIONAL;
222 proof_verifier_ = NULL;
223 ClearPerRequestState();
224 ExpectCertificates(secure_);
225 }
226
ExpectCertificates(bool on)227 void QuicTestClient::ExpectCertificates(bool on) {
228 if (on) {
229 proof_verifier_ = new RecordingProofVerifier;
230 client_->SetProofVerifier(proof_verifier_);
231 } else {
232 proof_verifier_ = NULL;
233 client_->SetProofVerifier(NULL);
234 }
235 }
236
SetUserAgentID(const string & user_agent_id)237 void QuicTestClient::SetUserAgentID(const string& user_agent_id) {
238 client_->SetUserAgentID(user_agent_id);
239 }
240
SendRequest(const string & uri)241 ssize_t QuicTestClient::SendRequest(const string& uri) {
242 HTTPMessage message(HttpConstants::HTTP_1_1,
243 HttpConstants::GET,
244 uri);
245 return SendMessage(message);
246 }
247
SendMessage(const HTTPMessage & message)248 ssize_t QuicTestClient::SendMessage(const HTTPMessage& message) {
249 stream_ = NULL; // Always force creation of a stream for SendMessage.
250
251 // If we're not connected, try to find an sni hostname.
252 if (!connected()) {
253 GURL url(message.headers()->request_uri().as_string());
254 if (!url.host().empty()) {
255 client_->set_server_id(
256 QuicServerId(url.host(),
257 url.EffectiveIntPort(),
258 url.SchemeIs("https"),
259 PRIVACY_MODE_DISABLED));
260 }
261 }
262
263 QuicSpdyClientStream* stream = GetOrCreateStream();
264 if (!stream) { return 0; }
265
266 scoped_ptr<BalsaHeaders> munged_headers(MungeHeaders(message.headers(),
267 secure_));
268 ssize_t ret = GetOrCreateStream()->SendRequest(
269 munged_headers.get() ? *munged_headers.get() : *message.headers(),
270 message.body(),
271 message.has_complete_message());
272 WaitForWriteToFlush();
273 return ret;
274 }
275
SendData(string data,bool last_data)276 ssize_t QuicTestClient::SendData(string data, bool last_data) {
277 QuicSpdyClientStream* stream = GetOrCreateStream();
278 if (!stream) { return 0; }
279 GetOrCreateStream()->SendBody(data, last_data);
280 WaitForWriteToFlush();
281 return data.length();
282 }
283
response_complete() const284 bool QuicTestClient::response_complete() const {
285 return response_complete_;
286 }
287
response_header_size() const288 int QuicTestClient::response_header_size() const {
289 return response_header_size_;
290 }
291
response_body_size() const292 int64 QuicTestClient::response_body_size() const {
293 return response_body_size_;
294 }
295
buffer_body() const296 bool QuicTestClient::buffer_body() const {
297 return buffer_body_;
298 }
299
set_buffer_body(bool buffer_body)300 void QuicTestClient::set_buffer_body(bool buffer_body) {
301 buffer_body_ = buffer_body;
302 }
303
ServerInLameDuckMode() const304 bool QuicTestClient::ServerInLameDuckMode() const {
305 return false;
306 }
307
response_body()308 const string& QuicTestClient::response_body() {
309 return response_;
310 }
311
SendCustomSynchronousRequest(const HTTPMessage & message)312 string QuicTestClient::SendCustomSynchronousRequest(
313 const HTTPMessage& message) {
314 SendMessage(message);
315 WaitForResponse();
316 return response_;
317 }
318
SendSynchronousRequest(const string & uri)319 string QuicTestClient::SendSynchronousRequest(const string& uri) {
320 if (SendRequest(uri) == 0) {
321 DLOG(ERROR) << "Failed the request for uri:" << uri;
322 return "";
323 }
324 WaitForResponse();
325 return response_;
326 }
327
GetOrCreateStream()328 QuicSpdyClientStream* QuicTestClient::GetOrCreateStream() {
329 if (!connect_attempted_ || auto_reconnect_) {
330 if (!connected()) {
331 Connect();
332 }
333 if (!connected()) {
334 return NULL;
335 }
336 }
337 if (!stream_) {
338 stream_ = client_->CreateReliableClientStream();
339 if (stream_ == NULL) {
340 return NULL;
341 }
342 stream_->set_visitor(this);
343 reinterpret_cast<QuicSpdyClientStream*>(stream_)->set_priority(priority_);
344 // Set FEC policy on stream.
345 ReliableQuicStreamPeer::SetFecPolicy(stream_, fec_policy_);
346 }
347
348 return stream_;
349 }
350
connection_error()351 QuicErrorCode QuicTestClient::connection_error() {
352 return client()->session()->error();
353 }
354
client()355 MockableQuicClient* QuicTestClient::client() { return client_.get(); }
356
cert_common_name() const357 const string& QuicTestClient::cert_common_name() const {
358 return reinterpret_cast<RecordingProofVerifier*>(proof_verifier_)
359 ->common_name();
360 }
361
GetServerConfig() const362 QuicTagValueMap QuicTestClient::GetServerConfig() const {
363 QuicCryptoClientConfig* config =
364 QuicClientPeer::GetCryptoConfig(client_.get());
365 QuicCryptoClientConfig::CachedState* state =
366 config->LookupOrCreate(client_->server_id());
367 const CryptoHandshakeMessage* handshake_msg = state->GetServerConfig();
368 if (handshake_msg != NULL) {
369 return handshake_msg->tag_value_map();
370 } else {
371 return QuicTagValueMap();
372 }
373 }
374
connected() const375 bool QuicTestClient::connected() const {
376 return client_->connected();
377 }
378
Connect()379 void QuicTestClient::Connect() {
380 DCHECK(!connected());
381 if (!connect_attempted_) {
382 client_->Initialize();
383 }
384 client_->Connect();
385 connect_attempted_ = true;
386 }
387
ResetConnection()388 void QuicTestClient::ResetConnection() {
389 Disconnect();
390 Connect();
391 }
392
Disconnect()393 void QuicTestClient::Disconnect() {
394 client_->Disconnect();
395 connect_attempted_ = false;
396 }
397
LocalSocketAddress() const398 IPEndPoint QuicTestClient::LocalSocketAddress() const {
399 return client_->client_address();
400 }
401
ClearPerRequestState()402 void QuicTestClient::ClearPerRequestState() {
403 stream_error_ = QUIC_STREAM_NO_ERROR;
404 stream_ = NULL;
405 response_ = "";
406 response_complete_ = false;
407 response_headers_complete_ = false;
408 headers_.Clear();
409 bytes_read_ = 0;
410 bytes_written_ = 0;
411 response_header_size_ = 0;
412 response_body_size_ = 0;
413 }
414
WaitForResponseForMs(int timeout_ms)415 void QuicTestClient::WaitForResponseForMs(int timeout_ms) {
416 int64 timeout_us = timeout_ms * base::Time::kMicrosecondsPerMillisecond;
417 int64 old_timeout_us = epoll_server()->timeout_in_us();
418 if (timeout_us > 0) {
419 epoll_server()->set_timeout_in_us(timeout_us);
420 }
421 const QuicClock* clock =
422 QuicConnectionPeer::GetHelper(client()->session()->connection())->
423 GetClock();
424 QuicTime end_waiting_time = clock->Now().Add(
425 QuicTime::Delta::FromMicroseconds(timeout_us));
426 while (stream_ != NULL &&
427 !client_->session()->IsClosedStream(stream_->id()) &&
428 (timeout_us < 0 || clock->Now() < end_waiting_time)) {
429 client_->WaitForEvents();
430 }
431 if (timeout_us > 0) {
432 epoll_server()->set_timeout_in_us(old_timeout_us);
433 }
434 }
435
WaitForInitialResponseForMs(int timeout_ms)436 void QuicTestClient::WaitForInitialResponseForMs(int timeout_ms) {
437 int64 timeout_us = timeout_ms * base::Time::kMicrosecondsPerMillisecond;
438 int64 old_timeout_us = epoll_server()->timeout_in_us();
439 if (timeout_us > 0) {
440 epoll_server()->set_timeout_in_us(timeout_us);
441 }
442 const QuicClock* clock =
443 QuicConnectionPeer::GetHelper(client()->session()->connection())->
444 GetClock();
445 QuicTime end_waiting_time = clock->Now().Add(
446 QuicTime::Delta::FromMicroseconds(timeout_us));
447 while (stream_ != NULL &&
448 !client_->session()->IsClosedStream(stream_->id()) &&
449 stream_->stream_bytes_read() == 0 &&
450 (timeout_us < 0 || clock->Now() < end_waiting_time)) {
451 client_->WaitForEvents();
452 }
453 if (timeout_us > 0) {
454 epoll_server()->set_timeout_in_us(old_timeout_us);
455 }
456 }
457
Send(const void * buffer,size_t size)458 ssize_t QuicTestClient::Send(const void *buffer, size_t size) {
459 return SendData(string(static_cast<const char*>(buffer), size), false);
460 }
461
response_headers_complete() const462 bool QuicTestClient::response_headers_complete() const {
463 if (stream_ != NULL) {
464 return stream_->headers_decompressed();
465 } else {
466 return response_headers_complete_;
467 }
468 }
469
response_headers() const470 const BalsaHeaders* QuicTestClient::response_headers() const {
471 if (stream_ != NULL) {
472 return &stream_->headers();
473 } else {
474 return &headers_;
475 }
476 }
477
response_size() const478 int64 QuicTestClient::response_size() const {
479 return bytes_read_;
480 }
481
bytes_read() const482 size_t QuicTestClient::bytes_read() const {
483 return bytes_read_;
484 }
485
bytes_written() const486 size_t QuicTestClient::bytes_written() const {
487 return bytes_written_;
488 }
489
OnClose(QuicDataStream * stream)490 void QuicTestClient::OnClose(QuicDataStream* stream) {
491 if (stream_ != stream) {
492 return;
493 }
494 if (buffer_body()) {
495 // TODO(fnk): The stream still buffers the whole thing. Fix that.
496 response_ = stream_->data();
497 }
498 response_complete_ = true;
499 response_headers_complete_ = stream_->headers_decompressed();
500 headers_.CopyFrom(stream_->headers());
501 stream_error_ = stream_->stream_error();
502 bytes_read_ = stream_->stream_bytes_read() + stream_->header_bytes_read();
503 bytes_written_ =
504 stream_->stream_bytes_written() + stream_->header_bytes_written();
505 response_header_size_ = headers_.GetSizeForWriteBuffer();
506 response_body_size_ = stream_->data().size();
507 stream_ = NULL;
508 }
509
UseWriter(QuicPacketWriterWrapper * writer)510 void QuicTestClient::UseWriter(QuicPacketWriterWrapper* writer) {
511 client_->UseWriter(writer);
512 }
513
UseConnectionId(QuicConnectionId connection_id)514 void QuicTestClient::UseConnectionId(QuicConnectionId connection_id) {
515 DCHECK(!connected());
516 client_->UseConnectionId(connection_id);
517 }
518
SendAndWaitForResponse(const void * buffer,size_t size)519 ssize_t QuicTestClient::SendAndWaitForResponse(const void *buffer,
520 size_t size) {
521 LOG(DFATAL) << "Not implemented";
522 return 0;
523 }
524
Bind(IPEndPoint * local_address)525 void QuicTestClient::Bind(IPEndPoint* local_address) {
526 DLOG(WARNING) << "Bind will be done during connect";
527 }
528
SerializeMessage(const HTTPMessage & message)529 string QuicTestClient::SerializeMessage(const HTTPMessage& message) {
530 LOG(DFATAL) << "Not implemented";
531 return "";
532 }
533
bind_to_address() const534 IPAddressNumber QuicTestClient::bind_to_address() const {
535 return client_->bind_to_address();
536 }
537
set_bind_to_address(IPAddressNumber address)538 void QuicTestClient::set_bind_to_address(IPAddressNumber address) {
539 client_->set_bind_to_address(address);
540 }
541
address() const542 const IPEndPoint& QuicTestClient::address() const {
543 LOG(DFATAL) << "Not implemented";
544 return client_->server_address();
545 }
546
requests_sent() const547 size_t QuicTestClient::requests_sent() const {
548 LOG(DFATAL) << "Not implemented";
549 return 0;
550 }
551
WaitForWriteToFlush()552 void QuicTestClient::WaitForWriteToFlush() {
553 while (connected() && client()->session()->HasDataToWrite()) {
554 client_->WaitForEvents();
555 }
556 }
557
SetFecPolicy(FecPolicy fec_policy)558 void QuicTestClient::SetFecPolicy(FecPolicy fec_policy) {
559 fec_policy_ = fec_policy;
560 // Set policy for headers and crypto streams.
561 ReliableQuicStreamPeer::SetFecPolicy(
562 QuicSessionPeer::GetHeadersStream(client()->session()), fec_policy);
563 ReliableQuicStreamPeer::SetFecPolicy(client()->session()->GetCryptoStream(),
564 fec_policy);
565 }
566
567 } // namespace test
568 } // namespace tools
569 } // namespace net
570