• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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