diff options
author | xunjieli <xunjieli@chromium.org> | 2016-03-14 06:39:23 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-03-14 13:41:07 +0000 |
commit | 2608f9bb792efa1a90730000038d518cd5bca400 (patch) | |
tree | 29c1fa2f5db6824d4e9efa68e6bd1d68474d505c /net/http | |
parent | b1e74df4227184deaaee4d192a5fb3c48116f081 (diff) | |
download | chromium_src-2608f9bb792efa1a90730000038d518cd5bca400.zip chromium_src-2608f9bb792efa1a90730000038d518cd5bca400.tar.gz chromium_src-2608f9bb792efa1a90730000038d518cd5bca400.tar.bz2 |
Implement QUIC-based net::BidirectionalStream
This CL implements a QUIC-based BidirectionalStream
and adds unit tests.
BUG=584338
Committed: https://crrev.com/0527bf95252b833b591be2f8e116cffd004ff189
Cr-Commit-Position: refs/heads/master@{#380919}
Review URL: https://codereview.chromium.org/1744693002
Cr-Commit-Position: refs/heads/master@{#380965}
Diffstat (limited to 'net/http')
-rw-r--r-- | net/http/http_stream_factory.h | 6 | ||||
-rw-r--r-- | net/http/http_stream_factory_impl.cc | 47 | ||||
-rw-r--r-- | net/http/http_stream_factory_impl.h | 1 | ||||
-rw-r--r-- | net/http/http_stream_factory_impl_job.cc | 35 | ||||
-rw-r--r-- | net/http/http_stream_factory_impl_job.h | 6 | ||||
-rw-r--r-- | net/http/http_stream_factory_impl_request.cc | 10 | ||||
-rw-r--r-- | net/http/http_stream_factory_impl_request.h | 15 | ||||
-rw-r--r-- | net/http/http_stream_factory_impl_unittest.cc | 232 |
8 files changed, 289 insertions, 63 deletions
diff --git a/net/http/http_stream_factory.h b/net/http/http_stream_factory.h index 359f7f0..f47ada1 100644 --- a/net/http/http_stream_factory.h +++ b/net/http/http_stream_factory.h @@ -54,6 +54,12 @@ struct SSLConfig; // which no callbacks will be invoked. class NET_EXPORT_PRIVATE HttpStreamRequest { public: + // Indicates which type of stream is requested. + enum StreamType { + BIDIRECTIONAL_STREAM, + HTTP_STREAM, + }; + // The HttpStreamRequest::Delegate is a set of callback methods for a // HttpStreamRequestJob. Generally, only one of these methods will be // called as a result of a stream request. diff --git a/net/http/http_stream_factory_impl.cc b/net/http/http_stream_factory_impl.cc index 06a5c0b..28fa8aa 100644 --- a/net/http/http_stream_factory_impl.cc +++ b/net/http/http_stream_factory_impl.cc @@ -54,13 +54,9 @@ HttpStreamRequest* HttpStreamFactoryImpl::RequestStream( HttpStreamRequest::Delegate* delegate, const BoundNetLog& net_log) { DCHECK(!for_websockets_); - return RequestStreamInternal(request_info, - priority, - server_ssl_config, - proxy_ssl_config, - delegate, - NULL, - net_log); + return RequestStreamInternal(request_info, priority, server_ssl_config, + proxy_ssl_config, delegate, nullptr, + HttpStreamRequest::HTTP_STREAM, net_log); } HttpStreamRequest* HttpStreamFactoryImpl::RequestWebSocketHandshakeStream( @@ -73,13 +69,9 @@ HttpStreamRequest* HttpStreamFactoryImpl::RequestWebSocketHandshakeStream( const BoundNetLog& net_log) { DCHECK(for_websockets_); DCHECK(create_helper); - return RequestStreamInternal(request_info, - priority, - server_ssl_config, - proxy_ssl_config, - delegate, - create_helper, - net_log); + return RequestStreamInternal(request_info, priority, server_ssl_config, + proxy_ssl_config, delegate, create_helper, + HttpStreamRequest::HTTP_STREAM, net_log); } HttpStreamRequest* HttpStreamFactoryImpl::RequestBidirectionalStreamJob( @@ -92,24 +84,9 @@ HttpStreamRequest* HttpStreamFactoryImpl::RequestBidirectionalStreamJob( DCHECK(!for_websockets_); DCHECK(request_info.url.SchemeIs(url::kHttpsScheme)); -// TODO(xunjieli): Create QUIC's version of BidirectionalStreamJob. -#if BUILDFLAG(ENABLE_BIDIRECTIONAL_STREAM) - HostPortPair server = HostPortPair::FromURL(request_info.url); - GURL origin_url = ApplyHostMappingRules(request_info.url, &server); - Request* request = - new Request(request_info.url, this, delegate, nullptr, net_log, - Request::BIDIRECTIONAL_STREAM_SPDY_JOB); - Job* job = new Job(this, session_, request_info, priority, server_ssl_config, - proxy_ssl_config, server, origin_url, net_log.net_log()); - request->AttachJob(job); - - job->Start(request); - return request; - -#else - DCHECK(false); - return nullptr; -#endif + return RequestStreamInternal( + request_info, priority, server_ssl_config, proxy_ssl_config, delegate, + nullptr, HttpStreamRequest::BIDIRECTIONAL_STREAM, net_log); } HttpStreamRequest* HttpStreamFactoryImpl::RequestStreamInternal( @@ -120,10 +97,11 @@ HttpStreamRequest* HttpStreamFactoryImpl::RequestStreamInternal( HttpStreamRequest::Delegate* delegate, WebSocketHandshakeStreamBase::CreateHelper* websocket_handshake_stream_create_helper, + HttpStreamRequest::StreamType stream_type, const BoundNetLog& net_log) { Request* request = new Request(request_info.url, this, delegate, websocket_handshake_stream_create_helper, - net_log, Request::HTTP_STREAM); + net_log, stream_type); HostPortPair server = HostPortPair::FromURL(request_info.url); GURL origin_url = ApplyHostMappingRules(request_info.url, &server); @@ -338,7 +316,8 @@ void HttpStreamFactoryImpl::OnNewSpdySessionReady( // TODO(ricea): Restore this code path when WebSocket over SPDY // implementation is ready. NOTREACHED(); - } else if (request->for_bidirectional()) { + } else if (request->stream_type() == + HttpStreamRequest::BIDIRECTIONAL_STREAM) { #if BUILDFLAG(ENABLE_BIDIRECTIONAL_STREAM) request->OnBidirectionalStreamJobReady( nullptr, used_ssl_config, used_proxy_info, diff --git a/net/http/http_stream_factory_impl.h b/net/http/http_stream_factory_impl.h index fac358f..d0aa390 100644 --- a/net/http/http_stream_factory_impl.h +++ b/net/http/http_stream_factory_impl.h @@ -84,6 +84,7 @@ class NET_EXPORT_PRIVATE HttpStreamFactoryImpl : public HttpStreamFactory { const SSLConfig& proxy_ssl_config, HttpStreamRequest::Delegate* delegate, WebSocketHandshakeStreamBase::CreateHelper* create_helper, + HttpStreamRequest::StreamType stream_type, const BoundNetLog& net_log); AlternativeService GetAlternativeServiceFor( diff --git a/net/http/http_stream_factory_impl_job.cc b/net/http/http_stream_factory_impl_job.cc index 179fd96..35b04ad 100644 --- a/net/http/http_stream_factory_impl_job.cc +++ b/net/http/http_stream_factory_impl_job.cc @@ -216,7 +216,7 @@ HttpStreamFactoryImpl::Job::Job(HttpStreamFactoryImpl* stream_factory, spdy_session_direct_(false), job_status_(STATUS_RUNNING), other_job_status_(STATUS_RUNNING), - for_bidirectional_(false), + stream_type_(HttpStreamRequest::BIDIRECTIONAL_STREAM), ptr_factory_(this) { DCHECK(stream_factory); DCHECK(session); @@ -248,8 +248,8 @@ HttpStreamFactoryImpl::Job::~Job() { void HttpStreamFactoryImpl::Job::Start(Request* request) { DCHECK(request); request_ = request; - // Saves |for_bidirectional_|, since request is nulled when job is orphaned. - for_bidirectional_ = request_->for_bidirectional(); + // Saves |stream_type_|, since request is nulled when job is orphaned. + stream_type_ = request_->stream_type(); StartInternal(); } @@ -502,7 +502,7 @@ void HttpStreamFactoryImpl::Job::OnNewSpdySessionReadyCallback() { } stream_factory_->OnOrphanedJobComplete(this); } else { - if (for_bidirectional_) { + if (stream_type_ == HttpStreamRequest::BIDIRECTIONAL_STREAM) { #if BUILDFLAG(ENABLE_BIDIRECTIONAL_STREAM) DCHECK(bidirectional_stream_job_); request_->OnNewSpdySessionReady(this, /*spdy_http_stream=*/nullptr, @@ -511,7 +511,6 @@ void HttpStreamFactoryImpl::Job::OnNewSpdySessionReadyCallback() { #else DCHECK(false); #endif - } else { DCHECK(stream_); request_->OnNewSpdySessionReady(this, std::move(stream_), @@ -704,7 +703,7 @@ int HttpStreamFactoryImpl::Job::RunLoop(int result) { base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::Bind(&Job::OnWebSocketHandshakeStreamReadyCallback, ptr_factory_.GetWeakPtr())); - } else if (for_bidirectional_) { + } else if (stream_type_ == HttpStreamRequest::BIDIRECTIONAL_STREAM) { #if BUILDFLAG(ENABLE_BIDIRECTIONAL_STREAM) if (!bidirectional_stream_job_) { base::ThreadTaskRunnerHandle::Get()->PostTask( @@ -1017,7 +1016,6 @@ int HttpStreamFactoryImpl::Job::DoInitConnection() { destination = server_; ssl_config = &server_ssl_config_; } - int rv = quic_request_.Request(destination, request_info_.privacy_mode, ssl_config->GetCertVerifyFlags(), url, @@ -1259,7 +1257,23 @@ int HttpStreamFactoryImpl::Job::DoInitConnectionComplete(int result) { MaybeMarkAlternativeServiceBroken(); return result; } - stream_ = quic_request_.ReleaseStream(); + if (stream_type_ == HttpStreamRequest::BIDIRECTIONAL_STREAM) { +#if BUILDFLAG(ENABLE_BIDIRECTIONAL_STREAM) + bidirectional_stream_job_ = quic_request_.CreateBidirectionalStreamJob(); + if (!bidirectional_stream_job_) { + // Quic session is closed before stream can be created. + return ERR_CONNECTION_CLOSED; + } +#else + NOTREACHED(); +#endif + } else { + stream_ = quic_request_.CreateStream(); + if (!stream_) { + // Quic session is closed before stream can be created. + return ERR_CONNECTION_CLOSED; + } + } next_state_ = STATE_NONE; return OK; } @@ -1316,13 +1330,12 @@ int HttpStreamFactoryImpl::Job::SetSpdyHttpStreamOrBidirectionalStreamJob( // implemented. if (stream_factory_->for_websockets_) return ERR_NOT_IMPLEMENTED; - if (for_bidirectional_) { + if (stream_type_ == HttpStreamRequest::BIDIRECTIONAL_STREAM) { #if BUILDFLAG(ENABLE_BIDIRECTIONAL_STREAM) - // TODO(xunjieli): Create QUIC's version of BidirectionalStreamJob. bidirectional_stream_job_.reset(new BidirectionalStreamSpdyJob(session)); return OK; #else - DCHECK(false); + NOTREACHED(); return ERR_FAILED; #endif } diff --git a/net/http/http_stream_factory_impl_job.h b/net/http/http_stream_factory_impl_job.h index 145a32f..839690a 100644 --- a/net/http/http_stream_factory_impl_job.h +++ b/net/http/http_stream_factory_impl_job.h @@ -93,7 +93,7 @@ class HttpStreamFactoryImpl::Job { NextProto protocol_negotiated() const; bool using_spdy() const; const BoundNetLog& net_log() const { return net_log_; } - bool for_bidirectional() const { return for_bidirectional_; } + HttpStreamRequest::StreamType stream_type() const { return stream_type_; } const SSLConfig& server_ssl_config() const; const SSLConfig& proxy_ssl_config() const; @@ -418,8 +418,8 @@ class HttpStreamFactoryImpl::Job { JobStatus other_job_status_; base::TimeTicks job_stream_ready_start_time_; - // True if BidirectionalStreamJob is requested. - bool for_bidirectional_; + // Type of stream that is requested. + HttpStreamRequest::StreamType stream_type_; base::WeakPtrFactory<Job> ptr_factory_; diff --git a/net/http/http_stream_factory_impl_request.cc b/net/http/http_stream_factory_impl_request.cc index 59b7b44..a335a55 100644 --- a/net/http/http_stream_factory_impl_request.cc +++ b/net/http/http_stream_factory_impl_request.cc @@ -35,7 +35,7 @@ HttpStreamFactoryImpl::Request::Request( was_npn_negotiated_(false), protocol_negotiated_(kProtoUnknown), using_spdy_(false), - for_bidirectional_(stream_type == BIDIRECTIONAL_STREAM_SPDY_JOB) { + stream_type_(stream_type) { DCHECK(factory_); DCHECK(delegate_); @@ -83,7 +83,7 @@ void HttpStreamFactoryImpl::Request::OnStreamReady( const ProxyInfo& used_proxy_info, HttpStream* stream) { DCHECK(!factory_->for_websockets_); - DCHECK(!for_bidirectional_); + DCHECK_EQ(HttpStreamRequest::HTTP_STREAM, stream_type_); DCHECK(stream); DCHECK(completed_); @@ -97,7 +97,7 @@ void HttpStreamFactoryImpl::Request::OnBidirectionalStreamJobReady( const ProxyInfo& used_proxy_info, BidirectionalStreamJob* stream_job) { DCHECK(!factory_->for_websockets_); - DCHECK(for_bidirectional_); + DCHECK_EQ(HttpStreamRequest::BIDIRECTIONAL_STREAM, stream_type_); DCHECK(stream_job); DCHECK(completed_); @@ -112,7 +112,7 @@ void HttpStreamFactoryImpl::Request::OnWebSocketHandshakeStreamReady( const ProxyInfo& used_proxy_info, WebSocketHandshakeStreamBase* stream) { DCHECK(factory_->for_websockets_); - DCHECK(!for_bidirectional_); + DCHECK_EQ(HttpStreamRequest::HTTP_STREAM, stream_type_); DCHECK(stream); DCHECK(completed_); @@ -314,7 +314,7 @@ void HttpStreamFactoryImpl::Request::OnNewSpdySessionReady( // TODO(ricea): Re-instate this code when WebSockets over SPDY is // implemented. NOTREACHED(); - } else if (for_bidirectional_) { + } else if (stream_type_ == HttpStreamRequest::BIDIRECTIONAL_STREAM) { DCHECK(bidirectional_stream_job); DCHECK(!stream); #if BUILDFLAG(ENABLE_BIDIRECTIONAL_STREAM) diff --git a/net/http/http_stream_factory_impl_request.h b/net/http/http_stream_factory_impl_request.h index a92303c..cad61af 100644 --- a/net/http/http_stream_factory_impl_request.h +++ b/net/http/http_stream_factory_impl_request.h @@ -27,12 +27,6 @@ class SpdySession; class HttpStreamFactoryImpl::Request : public HttpStreamRequest { public: - // Indicates which type of stream is requested. - enum StreamType { - BIDIRECTIONAL_STREAM_SPDY_JOB, - HTTP_STREAM, - }; - Request(const GURL& url, HttpStreamFactoryImpl* factory, HttpStreamRequest::Delegate* delegate, @@ -69,8 +63,9 @@ class HttpStreamFactoryImpl::Request : public HttpStreamRequest { void RemoveRequestFromSpdySessionRequestMap(); // Called by an attached Job if it sets up a SpdySession. - // |stream| is null when |for_bidirectional| is true. - // |bidirectional_stream_spdy_job| is null when |for_bidirectional| is false. + // |stream| is null when |stream_type| is HttpStreamRequest::HTTP_STREAM. + // |bidirectional_stream_spdy_job| is null when |stream_type| is + // HttpStreamRequest::BIDIRECTIONAL_STREAM. void OnNewSpdySessionReady( Job* job, scoped_ptr<HttpStream> stream, @@ -139,7 +134,7 @@ class HttpStreamFactoryImpl::Request : public HttpStreamRequest { NextProto protocol_negotiated() const override; bool using_spdy() const override; const ConnectionAttempts& connection_attempts() const override; - bool for_bidirectional() const { return for_bidirectional_; } + HttpStreamRequest::StreamType stream_type() const { return stream_type_; } private: // Used to bind |job| to the request and orphan all other jobs in |jobs_|. @@ -173,7 +168,7 @@ class HttpStreamFactoryImpl::Request : public HttpStreamRequest { bool using_spdy_; ConnectionAttempts connection_attempts_; - const bool for_bidirectional_; + const HttpStreamRequest::StreamType stream_type_; DISALLOW_COPY_AND_ASSIGN(Request); }; diff --git a/net/http/http_stream_factory_impl_unittest.cc b/net/http/http_stream_factory_impl_unittest.cc index 87b9d6f..67fe38c 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) +// 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) { @@ -1442,6 +1519,161 @@ TEST_P(HttpStreamFactoryTest, RequestBidirectionalStreamJob) { ->num_orphaned_jobs()); } +class HttpStreamFactoryBidirectionalQuicTest + : public ::testing::Test, + public ::testing::WithParamInterface<QuicVersion> { + protected: + HttpStreamFactoryBidirectionalQuicTest() + : clock_(new MockClock), + packet_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& packet_maker() { return packet_maker_; } + + MockClientSocketFactory& socket_factory() { return socket_factory_; } + + HttpNetworkSession* session() { return session_.get(); } + + private: + MockClock* clock_; // Owned by QuicStreamFactory + test::QuicTestPacketMaker packet_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(packet_maker().MakeRequestHeadersPacket( + 1, test::kClientDataStreamId1, /*should_include_version=*/true, + /*fin=*/true, priority, + packet_maker().GetRequestHeaders("GET", "https", "/"), + &spdy_headers_frame_length)); + size_t spdy_response_headers_frame_length; + mock_quic_data.AddRead(packet_maker().MakeResponseHeadersPacket( + 1, test::kClientDataStreamId1, /*should_include_version=*/false, + /*fin=*/true, packet_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()); |