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