| Index: net/http/http_stream_factory_impl_unittest.cc
|
| diff --git a/net/http/http_stream_factory_impl_unittest.cc b/net/http/http_stream_factory_impl_unittest.cc
|
| index 002e3609fe3d60c282f5678ff2e13050f073a6b9..3b394793c0d5b5be3445c7c8814c71a090f50cfc 100644
|
| --- a/net/http/http_stream_factory_impl_unittest.cc
|
| +++ b/net/http/http_stream_factory_impl_unittest.cc
|
| @@ -11,8 +11,10 @@
|
|
|
| #include "base/compiler_specific.h"
|
| #include "base/macros.h"
|
| +#include "base/run_loop.h"
|
| #include "net/base/port_util.h"
|
| #include "net/base/test_completion_callback.h"
|
| +#include "net/base/test_data_directory.h"
|
| #include "net/cert/mock_cert_verifier.h"
|
| #include "net/dns/mock_host_resolver.h"
|
| #include "net/http/http_auth_handler_factory.h"
|
| @@ -28,8 +30,14 @@
|
| #include "net/net_features.h"
|
| #include "net/proxy/proxy_info.h"
|
| #include "net/proxy/proxy_service.h"
|
| +#include "net/quic/quic_http_utils.h"
|
| #include "net/quic/quic_server_id.h"
|
| +#include "net/quic/test_tools/crypto_test_utils.h"
|
| +#include "net/quic/test_tools/mock_crypto_client_stream_factory.h"
|
| +#include "net/quic/test_tools/mock_random.h"
|
| #include "net/quic/test_tools/quic_stream_factory_peer.h"
|
| +#include "net/quic/test_tools/quic_test_packet_maker.h"
|
| +#include "net/quic/test_tools/quic_test_utils.h"
|
| #include "net/socket/client_socket_handle.h"
|
| #include "net/socket/mock_client_socket_pool_manager.h"
|
| #include "net/socket/next_proto.h"
|
| @@ -39,6 +47,8 @@
|
| #include "net/spdy/spdy_test_util_common.h"
|
| #include "net/ssl/ssl_config_service.h"
|
| #include "net/ssl/ssl_config_service_defaults.h"
|
| +#include "net/test/cert_test_util.h"
|
| +
|
| // This file can be included from net/http even though
|
| // it is in net/websockets because it doesn't
|
| // introduce any link dependency to net/websockets.
|
| @@ -47,6 +57,7 @@
|
|
|
| #if BUILDFLAG(ENABLE_BIDIRECTIONAL_STREAM)
|
| #include "net/http/bidirectional_stream_job.h"
|
| +#include "net/http/bidirectional_stream_request_info.h"
|
| #endif
|
|
|
| namespace net {
|
| @@ -738,6 +749,72 @@ TEST_P(HttpStreamFactoryTest, UnreachableQuicProxyMarkedAsBad) {
|
| }
|
| }
|
|
|
| +#if BUILDFLAG(ENABLE_BIDIRECTIONAL_STREAM)
|
| +// a BidirectionalStreamJob::Delegate to wait until response headers are
|
| +// received.
|
| +class TestBidirectionalDelegate : public BidirectionalStreamJob::Delegate {
|
| + public:
|
| + void WaitUntilDone() { loop_.Run(); }
|
| +
|
| + const SpdyHeaderBlock& response_headers() const { return response_headers_; }
|
| +
|
| + private:
|
| + void OnHeadersSent() override {}
|
| + void OnHeadersReceived(const SpdyHeaderBlock& response_headers) override {
|
| + response_headers_ = response_headers;
|
| + loop_.Quit();
|
| + }
|
| + void OnDataRead(int bytes_read) override { NOTREACHED(); }
|
| + void OnDataSent() override { NOTREACHED(); }
|
| + void OnTrailersReceived(const SpdyHeaderBlock& trailers) override {
|
| + NOTREACHED();
|
| + }
|
| + void OnFailed(int error) override { NOTREACHED(); }
|
| + base::RunLoop loop_;
|
| + SpdyHeaderBlock response_headers_;
|
| +};
|
| +
|
| +// Helper class to encapsulate MockReads and MockWrites for QUIC.
|
| +// Simplify ownership issues and the interaction with the MockSocketFactory.
|
| +class MockQuicData {
|
| + public:
|
| + MockQuicData() : packet_number_(0) {}
|
| +
|
| + ~MockQuicData() { STLDeleteElements(&packets_); }
|
| +
|
| + void AddRead(scoped_ptr<QuicEncryptedPacket> packet) {
|
| + reads_.push_back(
|
| + MockRead(ASYNC, packet->data(), packet->length(), packet_number_++));
|
| + packets_.push_back(packet.release());
|
| + }
|
| +
|
| + void AddRead(IoMode mode, int rv) {
|
| + reads_.push_back(MockRead(mode, rv, packet_number_++));
|
| + }
|
| +
|
| + void AddWrite(scoped_ptr<QuicEncryptedPacket> packet) {
|
| + writes_.push_back(MockWrite(SYNCHRONOUS, packet->data(), packet->length(),
|
| + packet_number_++));
|
| + packets_.push_back(packet.release());
|
| + }
|
| +
|
| + void AddSocketDataToFactory(MockClientSocketFactory* factory) {
|
| + MockRead* reads = reads_.empty() ? nullptr : &reads_[0];
|
| + MockWrite* writes = writes_.empty() ? nullptr : &writes_[0];
|
| + socket_data_.reset(
|
| + new SequencedSocketData(reads, reads_.size(), writes, writes_.size()));
|
| + factory->AddSocketDataProvider(socket_data_.get());
|
| + }
|
| +
|
| + private:
|
| + std::vector<QuicEncryptedPacket*> packets_;
|
| + std::vector<MockWrite> writes_;
|
| + std::vector<MockRead> reads_;
|
| + size_t packet_number_;
|
| + scoped_ptr<SequencedSocketData> socket_data_;
|
| +};
|
| +#endif
|
| +
|
| } // namespace
|
|
|
| TEST_P(HttpStreamFactoryTest, QuicLossyProxyMarkedAsBad) {
|
| @@ -1440,6 +1517,160 @@ TEST_P(HttpStreamFactoryTest, RequestBidirectionalStreamJob) {
|
| ->num_orphaned_jobs());
|
| }
|
|
|
| +class HttpStreamFactoryBidirectionalQuicTest
|
| + : public ::testing::Test,
|
| + public ::testing::WithParamInterface<QuicVersion> {
|
| + protected:
|
| + HttpStreamFactoryBidirectionalQuicTest()
|
| + : clock_(new MockClock),
|
| + maker_(GetParam(), 0, clock_, "www.example.org"),
|
| + random_generator_(0),
|
| + proxy_service_(ProxyService::CreateDirect()),
|
| + ssl_config_service_(new SSLConfigServiceDefaults) {
|
| + clock_->AdvanceTime(QuicTime::Delta::FromMilliseconds(20));
|
| + }
|
| +
|
| + void Initialize() {
|
| + params_.enable_quic = true;
|
| + params_.http_server_properties = http_server_properties_.GetWeakPtr();
|
| + params_.quic_host_whitelist.insert("www.example.org");
|
| + params_.quic_random = &random_generator_;
|
| + params_.quic_clock = clock_;
|
| +
|
| + // Load a certificate that is valid for *.example.org
|
| + scoped_refptr<X509Certificate> test_cert(
|
| + ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem"));
|
| + EXPECT_TRUE(test_cert.get());
|
| + verify_details_.cert_verify_result.verified_cert = test_cert;
|
| + verify_details_.cert_verify_result.is_issued_by_known_root = true;
|
| + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details_);
|
| + crypto_client_stream_factory_.set_handshake_mode(
|
| + MockCryptoClientStream::CONFIRM_HANDSHAKE);
|
| + params_.quic_crypto_client_stream_factory = &crypto_client_stream_factory_;
|
| + params_.quic_supported_versions = test::SupportedVersions(GetParam());
|
| + params_.transport_security_state = &transport_security_state_;
|
| + params_.host_resolver = &host_resolver_;
|
| + params_.proxy_service = proxy_service_.get();
|
| + params_.ssl_config_service = ssl_config_service_.get();
|
| + params_.client_socket_factory = &socket_factory_;
|
| + session_.reset(new HttpNetworkSession(params_));
|
| + session_->quic_stream_factory()->set_require_confirmation(false);
|
| + }
|
| +
|
| + void AddQuicAlternativeService() {
|
| + const AlternativeService alternative_service(QUIC, "www.example.org", 443);
|
| + AlternativeServiceInfoVector alternative_service_info_vector;
|
| + base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1);
|
| + alternative_service_info_vector.push_back(
|
| + AlternativeServiceInfo(alternative_service, 1.0, expiration));
|
| + HostPortPair host_port_pair(alternative_service.host_port_pair());
|
| + http_server_properties_.SetAlternativeServices(
|
| + host_port_pair, alternative_service_info_vector);
|
| + };
|
| +
|
| + test::QuicTestPacketMaker& maker() { return maker_; }
|
| +
|
| + MockClientSocketFactory& socket_factory() { return socket_factory_; }
|
| +
|
| + HttpNetworkSession* session() { return session_.get(); }
|
| +
|
| + private:
|
| + MockClock* clock_; // Owned by QuicStreamFactory
|
| + test::QuicTestPacketMaker maker_;
|
| + MockClientSocketFactory socket_factory_;
|
| + scoped_ptr<HttpNetworkSession> session_;
|
| + test::MockRandom random_generator_;
|
| + ProofVerifyDetailsChromium verify_details_;
|
| + MockCryptoClientStreamFactory crypto_client_stream_factory_;
|
| + HttpServerPropertiesImpl http_server_properties_;
|
| + TransportSecurityState transport_security_state_;
|
| + MockHostResolver host_resolver_;
|
| + scoped_ptr<ProxyService> proxy_service_;
|
| + scoped_refptr<SSLConfigServiceDefaults> ssl_config_service_;
|
| + HttpNetworkSession::Params params_;
|
| +};
|
| +
|
| +INSTANTIATE_TEST_CASE_P(Version,
|
| + HttpStreamFactoryBidirectionalQuicTest,
|
| + ::testing::ValuesIn(QuicSupportedVersions()));
|
| +
|
| +TEST_P(HttpStreamFactoryBidirectionalQuicTest,
|
| + RequestBidirectionalStreamJobQuicAlternative) {
|
| + GURL url = GURL("https://www.example.org");
|
| +
|
| + MockQuicData mock_quic_data;
|
| + SpdyPriority priority =
|
| + ConvertRequestPriorityToQuicPriority(DEFAULT_PRIORITY);
|
| + size_t spdy_headers_frame_length;
|
| + mock_quic_data.AddWrite(maker().MakeRequestHeadersPacket(
|
| + 1, test::kClientDataStreamId1, /*should_include_version=*/true,
|
| + /*fin=*/true, priority, maker().GetRequestHeaders("GET", "https", "/"),
|
| + &spdy_headers_frame_length));
|
| + size_t spdy_response_headers_frame_length;
|
| + mock_quic_data.AddRead(maker().MakeResponseHeadersPacket(
|
| + 1, test::kClientDataStreamId1, /*should_include_version=*/false,
|
| + /*fin=*/true, maker().GetResponseHeaders("200"),
|
| + &spdy_response_headers_frame_length));
|
| + mock_quic_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); // No more read data.
|
| + mock_quic_data.AddSocketDataToFactory(&socket_factory());
|
| +
|
| + // Add hanging data for http job.
|
| + scoped_ptr<StaticSocketDataProvider> hanging_data;
|
| + hanging_data.reset(new StaticSocketDataProvider());
|
| + MockConnect hanging_connect(SYNCHRONOUS, ERR_IO_PENDING);
|
| + hanging_data->set_connect_data(hanging_connect);
|
| + socket_factory().AddSocketDataProvider(hanging_data.get());
|
| + SSLSocketDataProvider ssl_data(ASYNC, OK);
|
| + socket_factory().AddSSLSocketDataProvider(&ssl_data);
|
| +
|
| + // Set up QUIC as alternative_service.
|
| + AddQuicAlternativeService();
|
| + Initialize();
|
| +
|
| + // Now request a stream.
|
| + SSLConfig ssl_config;
|
| + HttpRequestInfo request_info;
|
| + request_info.method = "GET";
|
| + request_info.url = GURL("https://www.example.org");
|
| + request_info.load_flags = 0;
|
| +
|
| + StreamRequestWaiter waiter;
|
| + scoped_ptr<HttpStreamRequest> request(
|
| + session()->http_stream_factory()->RequestBidirectionalStreamJob(
|
| + request_info, DEFAULT_PRIORITY, ssl_config, ssl_config, &waiter,
|
| + BoundNetLog()));
|
| +
|
| + waiter.WaitForStream();
|
| + EXPECT_TRUE(waiter.stream_done());
|
| + EXPECT_FALSE(waiter.websocket_stream());
|
| + ASSERT_FALSE(waiter.stream());
|
| + ASSERT_TRUE(waiter.bidirectional_stream_job());
|
| + BidirectionalStreamJob* job = waiter.bidirectional_stream_job();
|
| +
|
| + BidirectionalStreamRequestInfo bidi_request_info;
|
| + bidi_request_info.method = "GET";
|
| + bidi_request_info.url = GURL("https://www.example.org/");
|
| + bidi_request_info.end_stream_on_headers = true;
|
| + bidi_request_info.priority = LOWEST;
|
| +
|
| + TestBidirectionalDelegate delegate;
|
| + job->Start(&bidi_request_info, BoundNetLog(), &delegate, nullptr);
|
| + delegate.WaitUntilDone();
|
| +
|
| + scoped_refptr<IOBuffer> buffer = new net::IOBuffer(1);
|
| + EXPECT_EQ(OK, job->ReadData(buffer.get(), 1));
|
| + EXPECT_EQ("200", delegate.response_headers().find(":status")->second);
|
| + EXPECT_EQ(1, GetSocketPoolGroupCount(session()->GetTransportSocketPool(
|
| + HttpNetworkSession::NORMAL_SOCKET_POOL)));
|
| + EXPECT_EQ(1, GetSocketPoolGroupCount(session()->GetSSLSocketPool(
|
| + HttpNetworkSession::NORMAL_SOCKET_POOL)));
|
| + EXPECT_EQ(0, GetSocketPoolGroupCount(session()->GetTransportSocketPool(
|
| + HttpNetworkSession::WEBSOCKET_SOCKET_POOL)));
|
| + EXPECT_EQ(0, GetSocketPoolGroupCount(session()->GetSSLSocketPool(
|
| + HttpNetworkSession::WEBSOCKET_SOCKET_POOL)));
|
| + EXPECT_TRUE(waiter.used_proxy_info().is_direct());
|
| +}
|
| +
|
| TEST_P(HttpStreamFactoryTest, RequestBidirectionalStreamJobFailure) {
|
| SpdySessionDependencies session_deps(GetParam(),
|
| ProxyService::CreateDirect());
|
|
|