| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/tools/quic/test_tools/quic_test_client.h" | 5 #include "net/tools/quic/test_tools/quic_test_client.h" |
| 6 | 6 |
| 7 #include <memory> | 7 #include <memory> |
| 8 #include <utility> | 8 #include <utility> |
| 9 #include <vector> | 9 #include <vector> |
| 10 | 10 |
| 11 #include "base/memory/ptr_util.h" | 11 #include "base/memory/ptr_util.h" |
| 12 #include "base/time/time.h" | 12 #include "base/time/time.h" |
| 13 #include "net/base/completion_callback.h" | 13 #include "net/base/completion_callback.h" |
| 14 #include "net/base/net_errors.h" | 14 #include "net/base/net_errors.h" |
| 15 #include "net/cert/cert_verify_result.h" | 15 #include "net/cert/cert_verify_result.h" |
| 16 #include "net/cert/x509_certificate.h" | 16 #include "net/cert/x509_certificate.h" |
| 17 #include "net/quic/core/crypto/proof_verifier.h" | 17 #include "net/quic/core/crypto/proof_verifier.h" |
| 18 #include "net/quic/core/quic_flags.h" | 18 #include "net/quic/core/quic_flags.h" |
| 19 #include "net/quic/core/quic_server_id.h" | 19 #include "net/quic/core/quic_server_id.h" |
| 20 #include "net/quic/core/quic_utils.h" | 20 #include "net/quic/core/quic_utils.h" |
| 21 #include "net/quic/core/spdy_utils.h" |
| 21 #include "net/quic/test_tools/crypto_test_utils.h" | 22 #include "net/quic/test_tools/crypto_test_utils.h" |
| 22 #include "net/quic/test_tools/quic_connection_peer.h" | 23 #include "net/quic/test_tools/quic_connection_peer.h" |
| 23 #include "net/quic/test_tools/quic_spdy_session_peer.h" | 24 #include "net/quic/test_tools/quic_spdy_session_peer.h" |
| 24 #include "net/quic/test_tools/quic_test_utils.h" | 25 #include "net/quic/test_tools/quic_test_utils.h" |
| 25 #include "net/quic/test_tools/reliable_quic_stream_peer.h" | 26 #include "net/quic/test_tools/reliable_quic_stream_peer.h" |
| 26 #include "net/tools/balsa/balsa_headers.h" | |
| 27 #include "net/tools/quic/quic_epoll_connection_helper.h" | 27 #include "net/tools/quic/quic_epoll_connection_helper.h" |
| 28 #include "net/tools/quic/quic_packet_writer_wrapper.h" | 28 #include "net/tools/quic/quic_packet_writer_wrapper.h" |
| 29 #include "net/tools/quic/quic_spdy_client_stream.h" | 29 #include "net/tools/quic/quic_spdy_client_stream.h" |
| 30 #include "net/tools/quic/spdy_balsa_utils.h" | 30 #include "net/tools/quic/spdy_balsa_utils.h" |
| 31 #include "net/tools/quic/test_tools/http_message.h" | 31 #include "net/tools/quic/test_tools/http_message.h" |
| 32 #include "net/tools/quic/test_tools/quic_client_peer.h" | 32 #include "net/tools/quic/test_tools/quic_client_peer.h" |
| 33 #include "url/gurl.h" | 33 #include "url/gurl.h" |
| 34 | 34 |
| 35 using base::StringPiece; | 35 using base::StringPiece; |
| 36 using net::QuicServerId; | 36 using net::QuicServerId; |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 113 const string& cert_sct() const { return cert_sct_; } | 113 const string& cert_sct() const { return cert_sct_; } |
| 114 | 114 |
| 115 private: | 115 private: |
| 116 std::unique_ptr<ProofVerifier> verifier_; | 116 std::unique_ptr<ProofVerifier> verifier_; |
| 117 string common_name_; | 117 string common_name_; |
| 118 string cert_sct_; | 118 string cert_sct_; |
| 119 }; | 119 }; |
| 120 | 120 |
| 121 } // anonymous namespace | 121 } // anonymous namespace |
| 122 | 122 |
| 123 BalsaHeaders* MungeHeaders(const BalsaHeaders* const_headers) { | |
| 124 StringPiece uri = const_headers->request_uri(); | |
| 125 if (uri.empty()) { | |
| 126 return nullptr; | |
| 127 } | |
| 128 if (const_headers->request_method() == "CONNECT") { | |
| 129 return nullptr; | |
| 130 } | |
| 131 BalsaHeaders* headers = new BalsaHeaders; | |
| 132 headers->CopyFrom(*const_headers); | |
| 133 if (!base::StartsWith(uri, "https://", | |
| 134 base::CompareCase::INSENSITIVE_ASCII) && | |
| 135 !base::StartsWith(uri, "http://", base::CompareCase::INSENSITIVE_ASCII)) { | |
| 136 // If we have a relative URL, set some defaults. | |
| 137 string full_uri = "https://test.example.com"; | |
| 138 full_uri.append(uri.as_string()); | |
| 139 headers->SetRequestUri(full_uri); | |
| 140 } | |
| 141 return headers; | |
| 142 } | |
| 143 | |
| 144 MockableQuicClient::MockableQuicClient( | 123 MockableQuicClient::MockableQuicClient( |
| 145 IPEndPoint server_address, | 124 IPEndPoint server_address, |
| 146 const QuicServerId& server_id, | 125 const QuicServerId& server_id, |
| 147 const QuicVersionVector& supported_versions, | 126 const QuicVersionVector& supported_versions, |
| 148 EpollServer* epoll_server) | 127 EpollServer* epoll_server) |
| 149 : MockableQuicClient(server_address, | 128 : MockableQuicClient(server_address, |
| 150 server_id, | 129 server_id, |
| 151 QuicConfig(), | 130 QuicConfig(), |
| 152 supported_versions, | 131 supported_versions, |
| 153 epoll_server) {} | 132 epoll_server) {} |
| (...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 286 if (!client_->config()->HasSetBytesForConnectionIdToSend()) { | 265 if (!client_->config()->HasSetBytesForConnectionIdToSend()) { |
| 287 client_->config()->SetBytesForConnectionIdToSend(0); | 266 client_->config()->SetBytesForConnectionIdToSend(0); |
| 288 } | 267 } |
| 289 } | 268 } |
| 290 | 269 |
| 291 void QuicTestClient::SetUserAgentID(const string& user_agent_id) { | 270 void QuicTestClient::SetUserAgentID(const string& user_agent_id) { |
| 292 client_->SetUserAgentID(user_agent_id); | 271 client_->SetUserAgentID(user_agent_id); |
| 293 } | 272 } |
| 294 | 273 |
| 295 ssize_t QuicTestClient::SendRequest(const string& uri) { | 274 ssize_t QuicTestClient::SendRequest(const string& uri) { |
| 296 HTTPMessage message; | 275 SpdyHeaderBlock headers; |
| 297 FillInRequest(uri, &message); | 276 if (!PopulateHeaderBlockFromUrl(uri, &headers)) { |
| 298 return SendMessage(message); | 277 return 0; |
| 278 } |
| 279 return SendMessage(headers, ""); |
| 299 } | 280 } |
| 300 | 281 |
| 301 void QuicTestClient::SendRequestsAndWaitForResponses( | 282 void QuicTestClient::SendRequestsAndWaitForResponses( |
| 302 const std::vector<string>& url_list) { | 283 const std::vector<string>& url_list) { |
| 303 for (const string& url : url_list) { | 284 for (const string& url : url_list) { |
| 304 SendRequest(url); | 285 SendRequest(url); |
| 305 } | 286 } |
| 306 while (client()->WaitForEvents()) { | 287 while (client()->WaitForEvents()) { |
| 307 } | 288 } |
| 308 return; | 289 return; |
| 309 } | 290 } |
| 310 | 291 |
| 311 ssize_t QuicTestClient::GetOrCreateStreamAndSendRequest( | 292 ssize_t QuicTestClient::GetOrCreateStreamAndSendRequest( |
| 312 const BalsaHeaders* headers, | 293 const SpdyHeaderBlock* headers, |
| 313 StringPiece body, | 294 StringPiece body, |
| 314 bool fin, | 295 bool fin, |
| 315 QuicAckListenerInterface* delegate) { | 296 QuicAckListenerInterface* delegate) { |
| 316 if (headers) { | 297 if (headers) { |
| 317 QuicClientPushPromiseIndex::TryHandle* handle; | 298 QuicClientPushPromiseIndex::TryHandle* handle; |
| 318 QuicAsyncStatus rv = client()->push_promise_index()->Try( | 299 QuicAsyncStatus rv = |
| 319 SpdyBalsaUtils::RequestHeadersToSpdyHeaders(*headers), this, &handle); | 300 client()->push_promise_index()->Try(*headers, this, &handle); |
| 320 if (rv == QUIC_SUCCESS) | 301 if (rv == QUIC_SUCCESS) |
| 321 return 1; | 302 return 1; |
| 322 if (rv == QUIC_PENDING) { | 303 if (rv == QUIC_PENDING) { |
| 323 // May need to retry request if asynchronous rendezvous fails. | 304 // May need to retry request if asynchronous rendezvous fails. |
| 324 std::unique_ptr<SpdyHeaderBlock> new_headers(new SpdyHeaderBlock( | 305 std::unique_ptr<SpdyHeaderBlock> new_headers( |
| 325 SpdyBalsaUtils::RequestHeadersToSpdyHeaders(*headers))); | 306 new SpdyHeaderBlock(headers->Clone())); |
| 326 push_promise_data_to_resend_.reset(new TestClientDataToResend( | 307 push_promise_data_to_resend_.reset(new TestClientDataToResend( |
| 327 std::move(new_headers), body, fin, this, delegate)); | 308 std::move(new_headers), body, fin, this, delegate)); |
| 328 return 1; | 309 return 1; |
| 329 } | 310 } |
| 330 } | 311 } |
| 331 | 312 |
| 332 // Maybe it's better just to overload this. it's just that we need | 313 // Maybe it's better just to overload this. it's just that we need |
| 333 // for the GetOrCreateStream function to call something else...which | 314 // for the GetOrCreateStream function to call something else...which |
| 334 // is icky and complicated, but maybe not worse than this. | 315 // is icky and complicated, but maybe not worse than this. |
| 335 QuicSpdyClientStream* stream = GetOrCreateStream(); | 316 QuicSpdyClientStream* stream = GetOrCreateStream(); |
| 336 if (stream == nullptr) { | 317 if (stream == nullptr) { |
| 337 return 0; | 318 return 0; |
| 338 } | 319 } |
| 339 | 320 |
| 340 ssize_t ret = 0; | 321 ssize_t ret = 0; |
| 341 if (headers != nullptr) { | 322 if (headers != nullptr) { |
| 342 SpdyHeaderBlock spdy_headers = | 323 SpdyHeaderBlock spdy_headers(headers->Clone()); |
| 343 SpdyBalsaUtils::RequestHeadersToSpdyHeaders(*headers); | 324 if (spdy_headers[":authority"].as_string().empty()) { |
| 344 if (headers->HasHeader("transfer-encoding")) { | |
| 345 // We have tests which rely on sending a non-standards-compliant | |
| 346 // T-E header. | |
| 347 string encoding; | |
| 348 headers->GetAllOfHeaderAsString("transfer-encoding", &encoding); | |
| 349 spdy_headers.insert(std::make_pair("transfer-encoding", encoding)); | |
| 350 } | |
| 351 auto authority = spdy_headers.find(":authority"); | |
| 352 if (authority == spdy_headers.end() || authority->second.empty()) { | |
| 353 // HTTP/2 requests should include the :authority pseudo hader. | |
| 354 spdy_headers[":authority"] = client_->server_id().host(); | 325 spdy_headers[":authority"] = client_->server_id().host(); |
| 355 } | 326 } |
| 356 ret = stream->SendRequest(std::move(spdy_headers), body, fin); | 327 ret = stream->SendRequest(std::move(spdy_headers), body, fin); |
| 357 ++num_requests_; | 328 ++num_requests_; |
| 358 } else { | 329 } else { |
| 359 stream->WriteOrBufferBody(body.as_string(), fin, delegate); | 330 stream->WriteOrBufferBody(body.as_string(), fin, delegate); |
| 360 ret = body.length(); | 331 ret = body.length(); |
| 361 } | 332 } |
| 362 if (FLAGS_enable_quic_stateless_reject_support) { | 333 if (FLAGS_enable_quic_stateless_reject_support) { |
| 363 std::unique_ptr<SpdyHeaderBlock> new_headers; | 334 std::unique_ptr<SpdyHeaderBlock> new_headers; |
| 364 if (headers) { | 335 if (headers) { |
| 365 new_headers.reset(new SpdyHeaderBlock( | 336 new_headers.reset(new SpdyHeaderBlock(headers->Clone())); |
| 366 SpdyBalsaUtils::RequestHeadersToSpdyHeaders(*headers))); | |
| 367 } | 337 } |
| 368 std::unique_ptr<QuicClientBase::QuicDataToResend> data_to_resend( | 338 std::unique_ptr<QuicClientBase::QuicDataToResend> data_to_resend( |
| 369 new TestClientDataToResend(std::move(new_headers), body, fin, this, | 339 new TestClientDataToResend(std::move(new_headers), body, fin, this, |
| 370 delegate)); | 340 delegate)); |
| 371 client()->MaybeAddQuicDataToResend(std::move(data_to_resend)); | 341 client()->MaybeAddQuicDataToResend(std::move(data_to_resend)); |
| 372 } | 342 } |
| 373 return ret; | 343 return ret; |
| 374 } | 344 } |
| 375 | 345 |
| 376 ssize_t QuicTestClient::SendMessage(const HTTPMessage& message) { | 346 ssize_t QuicTestClient::SendMessage(const SpdyHeaderBlock& headers, |
| 347 StringPiece body) { |
| 348 return SendMessage(headers, body, /*fin=*/true); |
| 349 } |
| 350 |
| 351 ssize_t QuicTestClient::SendMessage(const SpdyHeaderBlock& headers, |
| 352 StringPiece body, |
| 353 bool fin) { |
| 377 stream_ = nullptr; // Always force creation of a stream for SendMessage. | 354 stream_ = nullptr; // Always force creation of a stream for SendMessage. |
| 378 // Any response we might have received for a previous request would no longer | 355 // Any response we might have received for a previous request would no longer |
| 379 // be valid. TODO(jeffpiazza): There's probably additional client state that | 356 // be valid. TODO(jeffpiazza): There's probably additional client state that |
| 380 // should be reset here, too, if we were being more careful. | 357 // should be reset here, too, if we were being more careful. |
| 381 response_complete_ = false; | 358 response_complete_ = false; |
| 382 | 359 |
| 383 // If we're not connected, try to find an sni hostname. | 360 // If we're not connected, try to find an sni hostname. |
| 384 if (!connected()) { | 361 if (!connected()) { |
| 385 GURL url(message.headers()->request_uri()); | 362 GURL url(SpdyUtils::GetUrlFromHeaderBlock(headers)); |
| 386 if (override_sni_set_) { | 363 if (override_sni_set_) { |
| 387 client_->set_server_id(QuicServerId(override_sni_, url.EffectiveIntPort(), | 364 client_->set_server_id(QuicServerId(override_sni_, url.EffectiveIntPort(), |
| 388 PRIVACY_MODE_DISABLED)); | 365 PRIVACY_MODE_DISABLED)); |
| 389 } else { | |
| 390 if (!url.host().empty()) { | |
| 391 client_->set_server_id(QuicServerId(url.host(), url.EffectiveIntPort(), | |
| 392 PRIVACY_MODE_DISABLED)); | |
| 393 } | |
| 394 } | 366 } |
| 395 } | 367 } |
| 396 | 368 |
| 397 // TODO(rtenneti): Add support for HTTPMessage::body_chunks(). | 369 ssize_t ret = GetOrCreateStreamAndSendRequest(&headers, body, fin, nullptr); |
| 398 // CHECK(message.body_chunks().empty()) | |
| 399 // << "HTTPMessage::body_chunks not supported"; | |
| 400 | |
| 401 std::unique_ptr<BalsaHeaders> munged_headers(MungeHeaders(message.headers())); | |
| 402 ssize_t ret = GetOrCreateStreamAndSendRequest( | |
| 403 (munged_headers.get() ? munged_headers.get() : message.headers()), | |
| 404 message.body(), message.has_complete_message(), nullptr); | |
| 405 WaitForWriteToFlush(); | 370 WaitForWriteToFlush(); |
| 406 return ret; | 371 return ret; |
| 407 } | 372 } |
| 408 | 373 |
| 409 ssize_t QuicTestClient::SendData(const string& data, bool last_data) { | 374 ssize_t QuicTestClient::SendData(const string& data, bool last_data) { |
| 410 return SendData(data, last_data, nullptr); | 375 return SendData(data, last_data, nullptr); |
| 411 } | 376 } |
| 412 | 377 |
| 413 ssize_t QuicTestClient::SendData(const string& data, | 378 ssize_t QuicTestClient::SendData(const string& data, |
| 414 bool last_data, | 379 bool last_data, |
| (...skipping 16 matching lines...) Expand all Loading... |
| 431 | 396 |
| 432 void QuicTestClient::set_buffer_body(bool buffer_body) { | 397 void QuicTestClient::set_buffer_body(bool buffer_body) { |
| 433 buffer_body_ = buffer_body; | 398 buffer_body_ = buffer_body; |
| 434 } | 399 } |
| 435 | 400 |
| 436 const string& QuicTestClient::response_body() { | 401 const string& QuicTestClient::response_body() { |
| 437 return response_; | 402 return response_; |
| 438 } | 403 } |
| 439 | 404 |
| 440 string QuicTestClient::SendCustomSynchronousRequest( | 405 string QuicTestClient::SendCustomSynchronousRequest( |
| 441 const HTTPMessage& message) { | 406 const SpdyHeaderBlock& headers, |
| 442 if (SendMessage(message) == 0) { | 407 const string& body) { |
| 443 DLOG(ERROR) << "Failed the request for uri:" | 408 if (SendMessage(headers, body) == 0) { |
| 444 << message.headers()->request_uri(); | 409 DLOG(ERROR) << "Failed the request for: " << headers.DebugString(); |
| 445 // Set the response_ explicitly. Otherwise response_ will contain the | 410 // Set the response_ explicitly. Otherwise response_ will contain the |
| 446 // response from the previously successful request. | 411 // response from the previously successful request. |
| 447 response_ = ""; | 412 response_ = ""; |
| 448 } else { | 413 } else { |
| 449 WaitForResponse(); | 414 WaitForResponse(); |
| 450 } | 415 } |
| 451 return response_; | 416 return response_; |
| 452 } | 417 } |
| 453 | 418 |
| 454 string QuicTestClient::SendSynchronousRequest(const string& uri) { | 419 string QuicTestClient::SendSynchronousRequest(const string& uri) { |
| 455 HTTPMessage message; | 420 SpdyHeaderBlock headers; |
| 456 FillInRequest(uri, &message); | 421 if (!PopulateHeaderBlockFromUrl(uri, &headers)) { |
| 457 return SendCustomSynchronousRequest(message); | 422 return ""; |
| 423 } |
| 424 return SendCustomSynchronousRequest(headers, ""); |
| 458 } | 425 } |
| 459 | 426 |
| 460 void QuicTestClient::SetStream(QuicSpdyClientStream* stream) { | 427 void QuicTestClient::SetStream(QuicSpdyClientStream* stream) { |
| 461 stream_ = stream; | 428 stream_ = stream; |
| 462 if (stream_ != nullptr) { | 429 if (stream_ != nullptr) { |
| 463 response_complete_ = false; | 430 response_complete_ = false; |
| 464 stream_->set_visitor(this); | 431 stream_->set_visitor(this); |
| 465 } | 432 } |
| 466 } | 433 } |
| 467 | 434 |
| (...skipping 231 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 699 return client_->server_address(); | 666 return client_->server_address(); |
| 700 } | 667 } |
| 701 | 668 |
| 702 void QuicTestClient::WaitForWriteToFlush() { | 669 void QuicTestClient::WaitForWriteToFlush() { |
| 703 while (connected() && client()->session()->HasDataToWrite()) { | 670 while (connected() && client()->session()->HasDataToWrite()) { |
| 704 client_->WaitForEvents(); | 671 client_->WaitForEvents(); |
| 705 } | 672 } |
| 706 } | 673 } |
| 707 | 674 |
| 708 void QuicTestClient::TestClientDataToResend::Resend() { | 675 void QuicTestClient::TestClientDataToResend::Resend() { |
| 709 BalsaHeaders balsa_headers; | 676 test_client_->GetOrCreateStreamAndSendRequest(headers_.get(), body_, fin_, |
| 710 SpdyBalsaUtils::SpdyHeadersToRequestHeaders(*headers_, &balsa_headers); | |
| 711 test_client_->GetOrCreateStreamAndSendRequest(&balsa_headers, body_, fin_, | |
| 712 delegate_); | 677 delegate_); |
| 713 headers_.reset(); | 678 headers_.reset(); |
| 714 } | 679 } |
| 715 | 680 |
| 716 // static | 681 bool QuicTestClient::PopulateHeaderBlockFromUrl(const string& uri, |
| 717 void QuicTestClient::FillInRequest(const string& uri, HTTPMessage* message) { | 682 SpdyHeaderBlock* headers) { |
| 718 CHECK(message); | 683 string url; |
| 719 message->headers()->SetRequestVersion( | 684 if (base::StartsWith(uri, "https://", base::CompareCase::INSENSITIVE_ASCII) || |
| 720 HTTPMessage::VersionToString(HttpConstants::HTTP_1_1)); | 685 base::StartsWith(uri, "http://", base::CompareCase::INSENSITIVE_ASCII)) { |
| 721 message->headers()->SetRequestMethod( | 686 url = uri; |
| 722 HTTPMessage::MethodToString(HttpConstants::GET)); | 687 } else if (uri[0] == '/') { |
| 723 message->headers()->SetRequestUri(uri); | 688 url = "https://" + client_->server_id().host() + uri; |
| 689 } else { |
| 690 url = "https://" + uri; |
| 691 } |
| 692 return SpdyUtils::PopulateHeaderBlockFromUrl(url, headers); |
| 724 } | 693 } |
| 725 | 694 |
| 726 } // namespace test | 695 } // namespace test |
| 727 } // namespace net | 696 } // namespace net |
| OLD | NEW |