summaryrefslogtreecommitdiffstats
path: root/net/http
diff options
context:
space:
mode:
authorxunjieli <xunjieli@chromium.org>2016-03-14 06:39:23 -0700
committerCommit bot <commit-bot@chromium.org>2016-03-14 13:41:07 +0000
commit2608f9bb792efa1a90730000038d518cd5bca400 (patch)
tree29c1fa2f5db6824d4e9efa68e6bd1d68474d505c /net/http
parentb1e74df4227184deaaee4d192a5fb3c48116f081 (diff)
downloadchromium_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.h6
-rw-r--r--net/http/http_stream_factory_impl.cc47
-rw-r--r--net/http/http_stream_factory_impl.h1
-rw-r--r--net/http/http_stream_factory_impl_job.cc35
-rw-r--r--net/http/http_stream_factory_impl_job.h6
-rw-r--r--net/http/http_stream_factory_impl_request.cc10
-rw-r--r--net/http/http_stream_factory_impl_request.h15
-rw-r--r--net/http/http_stream_factory_impl_unittest.cc232
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());