Home | History | Annotate | Download | only in test_tools
      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 "net/base/completion_callback.h"
      8 #include "net/base/net_errors.h"
      9 #include "net/cert/cert_verify_result.h"
     10 #include "net/cert/x509_certificate.h"
     11 #include "net/quic/crypto/proof_verifier.h"
     12 #include "net/tools/flip_server/balsa_headers.h"
     13 #include "net/tools/quic/quic_epoll_connection_helper.h"
     14 #include "net/tools/quic/test_tools/http_message_test_utils.h"
     15 #include "url/gurl.h"
     16 
     17 using std::string;
     18 using std::vector;
     19 using base::StringPiece;
     20 
     21 namespace {
     22 
     23 // RecordingProofVerifier accepts any certificate chain and records the common
     24 // name of the leaf.
     25 class RecordingProofVerifier : public net::ProofVerifier {
     26  public:
     27   // ProofVerifier interface.
     28   virtual net::ProofVerifier::Status VerifyProof(
     29       net::QuicVersion version,
     30       const string& hostname,
     31       const string& server_config,
     32       const vector<string>& certs,
     33       const string& signature,
     34       string* error_details,
     35       scoped_ptr<net::ProofVerifyDetails>* details,
     36       net::ProofVerifierCallback* callback) OVERRIDE {
     37     delete callback;
     38 
     39     common_name_.clear();
     40     if (certs.empty()) {
     41       return FAILURE;
     42     }
     43 
     44     // Convert certs to X509Certificate.
     45     vector<StringPiece> cert_pieces(certs.size());
     46     for (unsigned i = 0; i < certs.size(); i++) {
     47       cert_pieces[i] = StringPiece(certs[i]);
     48     }
     49     scoped_refptr<net::X509Certificate> cert =
     50         net::X509Certificate::CreateFromDERCertChain(cert_pieces);
     51     if (!cert.get()) {
     52       return FAILURE;
     53     }
     54 
     55     common_name_ = cert->subject().GetDisplayName();
     56     return SUCCESS;
     57   }
     58 
     59   const string& common_name() const { return common_name_; }
     60 
     61  private:
     62   string common_name_;
     63 };
     64 
     65 }  // anonymous namespace
     66 
     67 namespace net {
     68 namespace tools {
     69 namespace test {
     70 
     71 BalsaHeaders* MungeHeaders(const BalsaHeaders* const_headers,
     72                            bool secure) {
     73   StringPiece uri = const_headers->request_uri();
     74   if (uri.empty()) {
     75     return NULL;
     76   }
     77   if (const_headers->request_method() == "CONNECT") {
     78     return NULL;
     79   }
     80   BalsaHeaders* headers = new BalsaHeaders;
     81   headers->CopyFrom(*const_headers);
     82   if (!uri.starts_with("https://") &&
     83       !uri.starts_with("http://")) {
     84     // If we have a relative URL, set some defaults.
     85     string full_uri = secure ? "https://www.google.com" :
     86                                "http://www.google.com";
     87     full_uri.append(uri.as_string());
     88     headers->SetRequestUri(full_uri);
     89   }
     90   return headers;
     91 }
     92 
     93 // A quic client which allows mocking out writes.
     94 class QuicEpollClient : public QuicClient {
     95  public:
     96   typedef QuicClient Super;
     97 
     98   QuicEpollClient(IPEndPoint server_address,
     99              const string& server_hostname,
    100              const QuicVersion version)
    101       : Super(server_address, server_hostname, version) {
    102   }
    103 
    104   QuicEpollClient(IPEndPoint server_address,
    105              const string& server_hostname,
    106              const QuicConfig& config,
    107              const QuicVersion version)
    108       : Super(server_address, server_hostname, config, version) {
    109   }
    110 
    111   virtual ~QuicEpollClient() {
    112     if (connected()) {
    113       Disconnect();
    114     }
    115   }
    116 
    117   virtual QuicEpollConnectionHelper* CreateQuicConnectionHelper() OVERRIDE {
    118     if (writer_.get() != NULL) {
    119       writer_->set_fd(fd());
    120       return new QuicEpollConnectionHelper(writer_.get(), epoll_server());
    121     } else {
    122       return Super::CreateQuicConnectionHelper();
    123     }
    124   }
    125 
    126   void UseWriter(QuicTestWriter* writer) { writer_.reset(writer); }
    127 
    128  private:
    129   scoped_ptr<QuicTestWriter> writer_;
    130 };
    131 
    132 QuicTestClient::QuicTestClient(IPEndPoint address, const string& hostname,
    133                                const QuicVersion version)
    134     : client_(new QuicEpollClient(address, hostname, version)) {
    135   Initialize(address, hostname, true);
    136 }
    137 
    138 QuicTestClient::QuicTestClient(IPEndPoint address,
    139                                const string& hostname,
    140                                bool secure,
    141                                const QuicVersion version)
    142     : client_(new QuicEpollClient(address, hostname, version)) {
    143   Initialize(address, hostname, secure);
    144 }
    145 
    146 QuicTestClient::QuicTestClient(IPEndPoint address,
    147                                const string& hostname,
    148                                bool secure,
    149                                const QuicConfig& config,
    150                                const QuicVersion version)
    151     : client_(new QuicEpollClient(address, hostname, config, version)) {
    152   Initialize(address, hostname, secure);
    153 }
    154 
    155 void QuicTestClient::Initialize(IPEndPoint address,
    156                                 const string& hostname,
    157                                 bool secure) {
    158   server_address_ = address;
    159   stream_ = NULL;
    160   stream_error_ = QUIC_STREAM_NO_ERROR;
    161   bytes_read_ = 0;
    162   bytes_written_= 0;
    163   never_connected_ = true;
    164   secure_ = secure;
    165   auto_reconnect_ = false;
    166   proof_verifier_ = NULL;
    167   ExpectCertificates(secure_);
    168 }
    169 
    170 QuicTestClient::~QuicTestClient() {
    171   if (stream_) {
    172     stream_->set_visitor(NULL);
    173   }
    174 }
    175 
    176 void QuicTestClient::ExpectCertificates(bool on) {
    177   if (on) {
    178     proof_verifier_ = new RecordingProofVerifier;
    179     client_->SetProofVerifier(proof_verifier_);
    180   } else {
    181     proof_verifier_ = NULL;
    182     client_->SetProofVerifier(NULL);
    183   }
    184 }
    185 
    186 ssize_t QuicTestClient::SendRequest(const string& uri) {
    187   HTTPMessage message(HttpConstants::HTTP_1_1, HttpConstants::GET, uri);
    188   return SendMessage(message);
    189 }
    190 
    191 ssize_t QuicTestClient::SendMessage(const HTTPMessage& message) {
    192   stream_ = NULL;  // Always force creation of a stream for SendMessage.
    193 
    194   // If we're not connected, try to find an sni hostname.
    195   if (!connected()) {
    196     GURL url(message.headers()->request_uri().as_string());
    197     if (!url.host().empty()) {
    198       client_->set_server_hostname(url.host());
    199     }
    200   }
    201 
    202   QuicReliableClientStream* stream = GetOrCreateStream();
    203   if (!stream) { return 0; }
    204 
    205   scoped_ptr<BalsaHeaders> munged_headers(MungeHeaders(message.headers(),
    206                                           secure_));
    207   return GetOrCreateStream()->SendRequest(
    208       munged_headers.get() ? *munged_headers.get() : *message.headers(),
    209       message.body(),
    210       message.has_complete_message());
    211 }
    212 
    213 ssize_t QuicTestClient::SendData(string data, bool last_data) {
    214   QuicReliableClientStream* stream = GetOrCreateStream();
    215   if (!stream) { return 0; }
    216   GetOrCreateStream()->SendBody(data, last_data);
    217   return data.length();
    218 }
    219 
    220 string QuicTestClient::SendCustomSynchronousRequest(
    221     const HTTPMessage& message) {
    222   SendMessage(message);
    223   WaitForResponse();
    224   return response_;
    225 }
    226 
    227 string QuicTestClient::SendSynchronousRequest(const string& uri) {
    228   if (SendRequest(uri) == 0) {
    229     DLOG(ERROR) << "Failed the request for uri:" << uri;
    230     return "";
    231   }
    232   WaitForResponse();
    233   return response_;
    234 }
    235 
    236 QuicReliableClientStream* QuicTestClient::GetOrCreateStream() {
    237   if (never_connected_ == true || auto_reconnect_) {
    238     if (!connected()) {
    239       Connect();
    240     }
    241     if (!connected()) {
    242       return NULL;
    243     }
    244   }
    245   if (!stream_) {
    246     stream_ = client_->CreateReliableClientStream();
    247     if (stream_ != NULL) {
    248       stream_->set_visitor(this);
    249     }
    250   }
    251   return stream_;
    252 }
    253 
    254 const string& QuicTestClient::cert_common_name() const {
    255   return reinterpret_cast<RecordingProofVerifier*>(proof_verifier_)
    256       ->common_name();
    257 }
    258 
    259 bool QuicTestClient::connected() const {
    260   return client_->connected();
    261 }
    262 
    263 void QuicTestClient::WaitForResponse() {
    264   if (stream_ == NULL) {
    265     // The client has likely disconnected.
    266     return;
    267   }
    268   client_->WaitForStreamToClose(stream_->id());
    269 }
    270 
    271 void QuicTestClient::Connect() {
    272   DCHECK(!connected());
    273   client_->Initialize();
    274   client_->Connect();
    275   never_connected_ = false;
    276 }
    277 
    278 void QuicTestClient::ResetConnection() {
    279   Disconnect();
    280   Connect();
    281 }
    282 
    283 void QuicTestClient::Disconnect() {
    284   client_->Disconnect();
    285 }
    286 
    287 IPEndPoint QuicTestClient::LocalSocketAddress() const {
    288   return client_->client_address();
    289 }
    290 
    291 void QuicTestClient::ClearPerRequestState() {
    292   stream_error_ = QUIC_STREAM_NO_ERROR;
    293   stream_ = NULL;
    294   response_ = "";
    295   headers_.Clear();
    296   bytes_read_ = 0;
    297   bytes_written_ = 0;
    298 }
    299 
    300 void QuicTestClient::WaitForInitialResponse() {
    301   DCHECK(stream_ != NULL);
    302   while (stream_ && stream_->stream_bytes_read() == 0) {
    303     client_->WaitForEvents();
    304   }
    305 }
    306 
    307 ssize_t QuicTestClient::Send(const void *buffer, size_t size) {
    308   return SendData(string(static_cast<const char*>(buffer), size), false);
    309 }
    310 
    311 int QuicTestClient::response_size() const {
    312   return bytes_read_;
    313 }
    314 
    315 size_t QuicTestClient::bytes_read() const {
    316   return bytes_read_;
    317 }
    318 
    319 size_t QuicTestClient::bytes_written() const {
    320   return bytes_written_;
    321 }
    322 
    323 void QuicTestClient::OnClose(ReliableQuicStream* stream) {
    324   if (stream_ != stream) {
    325     return;
    326   }
    327   response_ = stream_->data();
    328   headers_.CopyFrom(stream_->headers());
    329   stream_error_ = stream_->stream_error();
    330   bytes_read_ = stream_->stream_bytes_read();
    331   bytes_written_ = stream_->stream_bytes_written();
    332   stream_ = NULL;
    333 }
    334 
    335 void QuicTestClient::UseWriter(QuicTestWriter* writer) {
    336   DCHECK(!connected());
    337   reinterpret_cast<QuicEpollClient*>(client_.get())->UseWriter(writer);
    338 }
    339 
    340 }  // namespace test
    341 }  // namespace tools
    342 }  // namespace net
    343