summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorwillchan@chromium.org <willchan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-03-12 01:39:55 +0000
committerwillchan@chromium.org <willchan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-03-12 01:39:55 +0000
commit2d67286973ae47301854b37eb1f142ac25d5e132 (patch)
tree468c5dfd91b57d6192cf87c34bc197ea415eca2c /net
parentc942d18826443fe7ebdde476265ab0cf026d7527 (diff)
downloadchromium_src-2d67286973ae47301854b37eb1f142ac25d5e132.zip
chromium_src-2d67286973ae47301854b37eb1f142ac25d5e132.tar.gz
chromium_src-2d67286973ae47301854b37eb1f142ac25d5e132.tar.bz2
Reland rest of r77399.
I had temporarily reverted it so I could break it up into 2 commits, so the first could be merged to 696. This is part 2. BUG=none TEST=none Review URL: http://codereview.chromium.org/6684019 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@77908 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r--net/http/http_network_transaction.cc6
-rw-r--r--net/http/http_network_transaction_unittest.cc282
-rw-r--r--net/http/http_response_info.cc12
-rw-r--r--net/http/http_response_info.h4
-rw-r--r--net/http/http_stream_factory.h7
-rw-r--r--net/http/http_stream_factory_impl.cc127
-rw-r--r--net/http/http_stream_factory_impl.h12
-rw-r--r--net/http/http_stream_factory_impl_job.cc360
-rw-r--r--net/http/http_stream_factory_impl_job.h106
-rw-r--r--net/http/http_stream_factory_impl_request.cc34
-rw-r--r--net/http/http_stream_factory_impl_request.h5
-rw-r--r--net/socket/client_socket_pool_base.cc5
-rw-r--r--net/socket/client_socket_pool_base.h2
-rw-r--r--net/spdy/spdy_network_transaction_unittest.cc148
-rw-r--r--net/url_request/url_request.h6
15 files changed, 659 insertions, 457 deletions
diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc
index 6b30fd6..4bd867d 100644
--- a/net/http/http_network_transaction.cc
+++ b/net/http/http_network_transaction.cc
@@ -20,6 +20,7 @@
#include "build/build_config.h"
#include "googleurl/src/gurl.h"
#include "net/base/auth.h"
+#include "net/base/host_port_pair.h"
#include "net/base/io_buffer.h"
#include "net/base/load_flags.h"
#include "net/base/net_errors.h"
@@ -371,8 +372,6 @@ void HttpNetworkTransaction::OnStreamReady(const SSLConfig& used_ssl_config,
stream_.reset(stream);
ssl_config_ = used_ssl_config;
proxy_info_ = used_proxy_info;
- response_.was_alternate_protocol_available =
- stream_request_->was_alternate_protocol_available();
response_.was_npn_negotiated = stream_request_->was_npn_negotiated();
response_.was_fetched_via_spdy = stream_request_->using_spdy();
response_.was_fetched_via_proxy = !proxy_info_.is_direct();
@@ -1070,7 +1069,8 @@ int HttpNetworkTransaction::HandleSSLHandshakeError(int error) {
// This could be a TLS-intolerant server, an SSL 3.0 server that
// chose a TLS-only cipher suite or a server with buggy DEFLATE
// support. Turn off TLS 1.0, DEFLATE support and retry.
- session_->http_stream_factory()->AddTLSIntolerantServer(request_->url);
+ session_->http_stream_factory()->AddTLSIntolerantServer(
+ HostPortPair::FromURL(request_->url));
ResetConnectionAndRequestForResend();
error = OK;
}
diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc
index ecd6132..b238f57 100644
--- a/net/http/http_network_transaction_unittest.cc
+++ b/net/http/http_network_transaction_unittest.cc
@@ -6437,7 +6437,6 @@ TEST_F(HttpNetworkTransactionTest, HonorAlternateProtocolHeader) {
EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
EXPECT_FALSE(response->was_fetched_via_spdy);
EXPECT_FALSE(response->was_npn_negotiated);
- EXPECT_FALSE(response->was_alternate_protocol_available);
std::string response_data;
ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data));
@@ -6478,11 +6477,6 @@ TEST_F(HttpNetworkTransactionTest, MarkBrokenAlternateProtocol) {
data_reads, arraysize(data_reads), NULL, 0);
session_deps.socket_factory.AddSocketDataProvider(&second_data);
- // TODO(willchan): Delete this extra data provider. It's necessary due to a
- // ClientSocketPoolBaseHelper bug that starts up too many ConnectJobs:
- // http://crbug.com/37454.
- session_deps.socket_factory.AddSocketDataProvider(&second_data);
-
TestCompletionCallback callback;
scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
@@ -6517,59 +6511,6 @@ TEST_F(HttpNetworkTransactionTest, MarkBrokenAlternateProtocol) {
HttpStreamFactory::set_use_alternate_protocols(false);
}
-// TODO(willchan): Redo this test to use TLS/NPN=>SPDY. Currently, the code
-// says that it does SPDY, but it just does the TLS handshake, but the NPN
-// response does not indicate SPDY, so we just do standard HTTPS over the port.
-// We should add code such that we don't fallback to HTTPS, but fallback to HTTP
-// on the original port.
-// TEST_F(HttpNetworkTransactionTest, UseAlternateProtocol) {
-// SessionDependencies session_deps;
-//
-// HttpRequestInfo request;
-// request.method = "GET";
-// request.url = GURL("http://www.google.com/");
-// request.load_flags = 0;
-//
-// MockRead data_reads[] = {
-// MockRead("HTTP/1.1 200 OK\r\n\r\n"),
-// MockRead("hello world"),
-// MockRead(true, OK),
-// };
-// StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0);
-// session_deps.socket_factory.AddSocketDataProvider(&data);
-//
-// SSLSocketDataProvider ssl(true, OK);
-// session_deps.socket_factory.AddSSLSocketDataProvider(&ssl);
-//
-// TestCompletionCallback callback;
-//
-// scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
-//
-// HostPortPair http_host_port_pair;
-// http_host_port_pair.host = "www.google.com";
-// http_host_port_pair.port = 80;
-// HttpAlternateProtocols* alternate_protocols =
-// session->mutable_alternate_protocols();
-// alternate_protocols->SetAlternateProtocolFor(
-// http_host_port_pair, 1234 /* port is ignored */,
-// HttpAlternateProtocols::NPN_SPDY_1);
-//
-// scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
-//
-// int rv = trans->Start(&request, &callback, BoundNetLog());
-// EXPECT_EQ(ERR_IO_PENDING, rv);
-// EXPECT_EQ(OK, callback.WaitForResult());
-//
-// const HttpResponseInfo* response = trans->GetResponseInfo();
-// ASSERT_TRUE(response != NULL);
-// ASSERT_TRUE(response->headers != NULL);
-// EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
-//
-// std::string response_data;
-// ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data));
-// EXPECT_EQ("hello world", response_data);
-// }
-
TEST_F(HttpNetworkTransactionTest, FailNpnSpdyAndFallback) {
HttpStreamFactory::set_use_alternate_protocols(true);
HttpStreamFactory::set_next_protos(kExpectedNPNString);
@@ -6669,6 +6610,14 @@ TEST_F(HttpNetworkTransactionTest, UseAlternateProtocolForNpnSpdy) {
spdy_writes, arraysize(spdy_writes)));
session_deps.socket_factory.AddSocketDataProvider(spdy_data);
+ MockConnect never_finishing_connect(false, ERR_IO_PENDING);
+ StaticSocketDataProvider hanging_non_alternate_protocol_socket(
+ NULL, 0, NULL, 0);
+ hanging_non_alternate_protocol_socket.set_connect_data(
+ never_finishing_connect);
+ session_deps.socket_factory.AddSocketDataProvider(
+ &hanging_non_alternate_protocol_socket);
+
TestCompletionCallback callback;
scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
@@ -6699,7 +6648,6 @@ TEST_F(HttpNetworkTransactionTest, UseAlternateProtocolForNpnSpdy) {
EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
EXPECT_TRUE(response->was_fetched_via_spdy);
EXPECT_TRUE(response->was_npn_negotiated);
- EXPECT_TRUE(response->was_alternate_protocol_available);
ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data));
EXPECT_EQ("hello!", response_data);
@@ -6708,6 +6656,200 @@ TEST_F(HttpNetworkTransactionTest, UseAlternateProtocolForNpnSpdy) {
HttpStreamFactory::set_use_alternate_protocols(false);
}
+TEST_F(HttpNetworkTransactionTest, AlternateProtocolWithSpdyLateBinding) {
+ HttpStreamFactory::set_use_alternate_protocols(true);
+ HttpStreamFactory::set_next_protos(kExpectedNPNString);
+ SessionDependencies session_deps;
+
+ HttpRequestInfo request;
+ request.method = "GET";
+ request.url = GURL("http://www.google.com/");
+ request.load_flags = 0;
+
+ MockRead data_reads[] = {
+ MockRead("HTTP/1.1 200 OK\r\n"),
+ MockRead(kAlternateProtocolHttpHeader),
+ MockRead("hello world"),
+ MockRead(true, OK),
+ };
+
+ StaticSocketDataProvider first_transaction(
+ data_reads, arraysize(data_reads), NULL, 0);
+ // Socket 1 is the HTTP transaction with the Alternate-Protocol header.
+ session_deps.socket_factory.AddSocketDataProvider(&first_transaction);
+
+ MockConnect never_finishing_connect(false, ERR_IO_PENDING);
+ StaticSocketDataProvider hanging_socket(
+ NULL, 0, NULL, 0);
+ hanging_socket.set_connect_data(never_finishing_connect);
+ // Socket 2 and 3 are the hanging Alternate-Protocol and
+ // non-Alternate-Protocol jobs from the 2nd transaction.
+ session_deps.socket_factory.AddSocketDataProvider(&hanging_socket);
+ session_deps.socket_factory.AddSocketDataProvider(&hanging_socket);
+
+ SSLSocketDataProvider ssl(true, OK);
+ ssl.next_proto_status = SSLClientSocket::kNextProtoNegotiated;
+ ssl.next_proto = "spdy/2";
+ ssl.was_npn_negotiated = true;
+ session_deps.socket_factory.AddSSLSocketDataProvider(&ssl);
+
+ scoped_ptr<spdy::SpdyFrame> req1(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
+ scoped_ptr<spdy::SpdyFrame> req2(ConstructSpdyGet(NULL, 0, false, 3, LOWEST));
+ MockWrite spdy_writes[] = {
+ CreateMockWrite(*req1),
+ CreateMockWrite(*req2),
+ };
+ scoped_ptr<spdy::SpdyFrame> resp1(ConstructSpdyGetSynReply(NULL, 0, 1));
+ scoped_ptr<spdy::SpdyFrame> data1(ConstructSpdyBodyFrame(1, true));
+ scoped_ptr<spdy::SpdyFrame> resp2(ConstructSpdyGetSynReply(NULL, 0, 3));
+ scoped_ptr<spdy::SpdyFrame> data2(ConstructSpdyBodyFrame(3, true));
+ MockRead spdy_reads[] = {
+ CreateMockRead(*resp1),
+ CreateMockRead(*data1),
+ CreateMockRead(*resp2),
+ CreateMockRead(*data2),
+ MockRead(true, 0, 0),
+ };
+
+ scoped_refptr<DelayedSocketData> spdy_data(
+ new DelayedSocketData(
+ 2, // wait for writes to finish before reading.
+ spdy_reads, arraysize(spdy_reads),
+ spdy_writes, arraysize(spdy_writes)));
+ // Socket 4 is the successful Alternate-Protocol for transaction 3.
+ session_deps.socket_factory.AddSocketDataProvider(spdy_data);
+
+ // Socket 5 is the unsuccessful non-Alternate-Protocol for transaction 3.
+ session_deps.socket_factory.AddSocketDataProvider(&hanging_socket);
+
+ scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
+ TestCompletionCallback callback1;
+ HttpNetworkTransaction trans1(session);
+
+ int rv = trans1.Start(&request, &callback1, BoundNetLog());
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_EQ(OK, callback1.WaitForResult());
+
+ const HttpResponseInfo* response = trans1.GetResponseInfo();
+ ASSERT_TRUE(response != NULL);
+ ASSERT_TRUE(response->headers != NULL);
+ EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
+
+ std::string response_data;
+ ASSERT_EQ(OK, ReadTransaction(&trans1, &response_data));
+ EXPECT_EQ("hello world", response_data);
+
+ TestCompletionCallback callback2;
+ HttpNetworkTransaction trans2(session);
+ rv = trans2.Start(&request, &callback2, BoundNetLog());
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ TestCompletionCallback callback3;
+ HttpNetworkTransaction trans3(session);
+ rv = trans3.Start(&request, &callback3, BoundNetLog());
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ EXPECT_EQ(OK, callback2.WaitForResult());
+ EXPECT_EQ(OK, callback3.WaitForResult());
+
+ response = trans2.GetResponseInfo();
+ ASSERT_TRUE(response != NULL);
+ ASSERT_TRUE(response->headers != NULL);
+ EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
+ EXPECT_TRUE(response->was_fetched_via_spdy);
+ EXPECT_TRUE(response->was_npn_negotiated);
+ ASSERT_EQ(OK, ReadTransaction(&trans2, &response_data));
+ EXPECT_EQ("hello!", response_data);
+
+ response = trans3.GetResponseInfo();
+ ASSERT_TRUE(response != NULL);
+ ASSERT_TRUE(response->headers != NULL);
+ EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
+ EXPECT_TRUE(response->was_fetched_via_spdy);
+ EXPECT_TRUE(response->was_npn_negotiated);
+ ASSERT_EQ(OK, ReadTransaction(&trans3, &response_data));
+ EXPECT_EQ("hello!", response_data);
+
+ HttpStreamFactory::set_next_protos("");
+ HttpStreamFactory::set_use_alternate_protocols(false);
+}
+
+TEST_F(HttpNetworkTransactionTest, StallAlternateProtocolForNpnSpdy) {
+ HttpStreamFactory::set_use_alternate_protocols(true);
+ HttpStreamFactory::set_next_protos(kExpectedNPNString);
+ SessionDependencies session_deps;
+
+ HttpRequestInfo request;
+ request.method = "GET";
+ request.url = GURL("http://www.google.com/");
+ request.load_flags = 0;
+
+ MockRead data_reads[] = {
+ MockRead("HTTP/1.1 200 OK\r\n"),
+ MockRead(kAlternateProtocolHttpHeader),
+ MockRead("hello world"),
+ MockRead(true, OK),
+ };
+
+ StaticSocketDataProvider first_transaction(
+ data_reads, arraysize(data_reads), NULL, 0);
+ session_deps.socket_factory.AddSocketDataProvider(&first_transaction);
+
+ SSLSocketDataProvider ssl(true, OK);
+ ssl.next_proto_status = SSLClientSocket::kNextProtoNegotiated;
+ ssl.next_proto = "spdy/2";
+ ssl.was_npn_negotiated = true;
+ session_deps.socket_factory.AddSSLSocketDataProvider(&ssl);
+
+ MockConnect never_finishing_connect(false, ERR_IO_PENDING);
+ StaticSocketDataProvider hanging_alternate_protocol_socket(
+ NULL, 0, NULL, 0);
+ hanging_alternate_protocol_socket.set_connect_data(
+ never_finishing_connect);
+ session_deps.socket_factory.AddSocketDataProvider(
+ &hanging_alternate_protocol_socket);
+
+ // 2nd request is just a copy of the first one, over HTTP again.
+ session_deps.socket_factory.AddSocketDataProvider(&first_transaction);
+
+ TestCompletionCallback callback;
+
+ scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
+ scoped_ptr<HttpNetworkTransaction> trans(new HttpNetworkTransaction(session));
+
+ int rv = trans->Start(&request, &callback, BoundNetLog());
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_EQ(OK, callback.WaitForResult());
+
+ const HttpResponseInfo* response = trans->GetResponseInfo();
+ ASSERT_TRUE(response != NULL);
+ ASSERT_TRUE(response->headers != NULL);
+ EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
+
+ std::string response_data;
+ ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data));
+ EXPECT_EQ("hello world", response_data);
+
+ trans.reset(new HttpNetworkTransaction(session));
+
+ rv = trans->Start(&request, &callback, BoundNetLog());
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_EQ(OK, callback.WaitForResult());
+
+ response = trans->GetResponseInfo();
+ ASSERT_TRUE(response != NULL);
+ ASSERT_TRUE(response->headers != NULL);
+ EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
+ EXPECT_FALSE(response->was_fetched_via_spdy);
+ EXPECT_FALSE(response->was_npn_negotiated);
+
+ ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data));
+ EXPECT_EQ("hello world", response_data);
+
+ HttpStreamFactory::set_next_protos("");
+ HttpStreamFactory::set_use_alternate_protocols(false);
+}
+
class CapturingProxyResolver : public ProxyResolver {
public:
CapturingProxyResolver() : ProxyResolver(false /* expects_pac_bytes */) {}
@@ -6807,6 +6949,14 @@ TEST_F(HttpNetworkTransactionTest, UseAlternateProtocolForTunneledNpnSpdy) {
spdy_writes, arraysize(spdy_writes)));
session_deps.socket_factory.AddSocketDataProvider(spdy_data);
+ MockConnect never_finishing_connect(false, ERR_IO_PENDING);
+ StaticSocketDataProvider hanging_non_alternate_protocol_socket(
+ NULL, 0, NULL, 0);
+ hanging_non_alternate_protocol_socket.set_connect_data(
+ never_finishing_connect);
+ session_deps.socket_factory.AddSocketDataProvider(
+ &hanging_non_alternate_protocol_socket);
+
TestCompletionCallback callback;
scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
@@ -6842,7 +6992,7 @@ TEST_F(HttpNetworkTransactionTest, UseAlternateProtocolForTunneledNpnSpdy) {
ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data));
EXPECT_EQ("hello!", response_data);
- ASSERT_EQ(2u, capturing_proxy_resolver->resolved().size());
+ ASSERT_EQ(3u, capturing_proxy_resolver->resolved().size());
EXPECT_EQ("http://www.google.com/",
capturing_proxy_resolver->resolved()[0].spec());
EXPECT_EQ("https://www.google.com/",
@@ -6958,7 +7108,6 @@ TEST_F(HttpNetworkTransactionTest,
EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
EXPECT_TRUE(response->was_fetched_via_spdy);
EXPECT_TRUE(response->was_npn_negotiated);
- EXPECT_TRUE(response->was_alternate_protocol_available);
ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data));
EXPECT_EQ("hello!", response_data);
@@ -7729,7 +7878,6 @@ TEST_F(HttpNetworkTransactionTest, NpnWithHttpOverSSL) {
EXPECT_FALSE(response->was_fetched_via_spdy);
EXPECT_TRUE(response->was_npn_negotiated);
- EXPECT_FALSE(response->was_alternate_protocol_available);
HttpStreamFactory::set_next_protos("");
HttpStreamFactory::set_use_alternate_protocols(false);
@@ -7885,9 +8033,17 @@ TEST_F(HttpNetworkTransactionTest, SpdyAlternateProtocolThroughProxy) {
ssl.next_proto = "spdy/2";
ssl.was_npn_negotiated = true;
+ MockConnect never_finishing_connect(false, ERR_IO_PENDING);
+ StaticSocketDataProvider hanging_non_alternate_protocol_socket(
+ NULL, 0, NULL, 0);
+ hanging_non_alternate_protocol_socket.set_connect_data(
+ never_finishing_connect);
+
session_deps.socket_factory.AddSocketDataProvider(&data_1);
session_deps.socket_factory.AddSocketDataProvider(data_2.get());
session_deps.socket_factory.AddSSLSocketDataProvider(&ssl);
+ session_deps.socket_factory.AddSocketDataProvider(
+ &hanging_non_alternate_protocol_socket);
scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
// First round should work and provide the Alternate-Protocol state.
diff --git a/net/http/http_response_info.cc b/net/http/http_response_info.cc
index 9b3444a..fd76462 100644
--- a/net/http/http_response_info.cc
+++ b/net/http/http_response_info.cc
@@ -52,10 +52,6 @@ enum {
// This bit is set if the request was fetched via an explicit proxy.
RESPONSE_INFO_WAS_PROXY = 1 << 15,
- // This bit is set if response could use alternate protocol. However, browser
- // will ingore the alternate protocol if spdy is not enabled.
- RESPONSE_INFO_WAS_ALTERNATE_PROTOCOL_AVAILABLE = 1 << 16,
-
// TODO(darin): Add other bits to indicate alternate request methods.
// For now, we don't support storing those.
};
@@ -64,7 +60,6 @@ HttpResponseInfo::HttpResponseInfo()
: was_cached(false),
was_fetched_via_spdy(false),
was_npn_negotiated(false),
- was_alternate_protocol_available(false),
was_fetched_via_proxy(false) {
}
@@ -72,7 +67,6 @@ HttpResponseInfo::HttpResponseInfo(const HttpResponseInfo& rhs)
: was_cached(rhs.was_cached),
was_fetched_via_spdy(rhs.was_fetched_via_spdy),
was_npn_negotiated(rhs.was_npn_negotiated),
- was_alternate_protocol_available(rhs.was_alternate_protocol_available),
was_fetched_via_proxy(rhs.was_fetched_via_proxy),
socket_address(rhs.socket_address),
request_time(rhs.request_time),
@@ -92,7 +86,6 @@ HttpResponseInfo& HttpResponseInfo::operator=(const HttpResponseInfo& rhs) {
was_cached = rhs.was_cached;
was_fetched_via_spdy = rhs.was_fetched_via_spdy;
was_npn_negotiated = rhs.was_npn_negotiated;
- was_alternate_protocol_available = rhs.was_alternate_protocol_available;
was_fetched_via_proxy = rhs.was_fetched_via_proxy;
socket_address = rhs.socket_address;
request_time = rhs.request_time;
@@ -176,9 +169,6 @@ bool HttpResponseInfo::InitFromPickle(const Pickle& pickle,
was_npn_negotiated = (flags & RESPONSE_INFO_WAS_NPN) != 0;
- was_alternate_protocol_available =
- (flags & RESPONSE_INFO_WAS_ALTERNATE_PROTOCOL_AVAILABLE) != 0;
-
was_fetched_via_proxy = (flags & RESPONSE_INFO_WAS_PROXY) != 0;
*response_truncated = (flags & RESPONSE_INFO_TRUNCATED) ? true : false;
@@ -205,8 +195,6 @@ void HttpResponseInfo::Persist(Pickle* pickle,
flags |= RESPONSE_INFO_WAS_SPDY;
if (was_npn_negotiated)
flags |= RESPONSE_INFO_WAS_NPN;
- if (was_alternate_protocol_available)
- flags |= RESPONSE_INFO_WAS_ALTERNATE_PROTOCOL_AVAILABLE;
if (was_fetched_via_proxy)
flags |= RESPONSE_INFO_WAS_PROXY;
diff --git a/net/http/http_response_info.h b/net/http/http_response_info.h
index e13f288..c925aa9 100644
--- a/net/http/http_response_info.h
+++ b/net/http/http_response_info.h
@@ -52,10 +52,6 @@ class HttpResponseInfo {
// True if the npn was negotiated for this request.
bool was_npn_negotiated;
- // True if response could use alternate protocol. However, browser
- // will ingore the alternate protocol if spdy is not enabled.
- bool was_alternate_protocol_available;
-
// True if the request was fetched via an explicit proxy. The proxy could
// be any type of proxy, HTTP or SOCKS. Note, we do not know if a
// transparent proxy may have been involved.
diff --git a/net/http/http_stream_factory.h b/net/http/http_stream_factory.h
index 3d3bada..9268746 100644
--- a/net/http/http_stream_factory.h
+++ b/net/http/http_stream_factory.h
@@ -135,9 +135,6 @@ class HttpStreamRequest {
// Returns the LoadState for the request.
virtual LoadState GetLoadState() const = 0;
- // Returns true if an AlternateProtocol for this request was available.
- virtual bool was_alternate_protocol_available() const = 0;
-
// Returns true if TLS/NPN was negotiated for this stream.
virtual bool was_npn_negotiated() const = 0;
@@ -171,8 +168,8 @@ class HttpStreamFactory {
const SSLConfig& ssl_config,
const BoundNetLog& net_log) = 0;
- virtual void AddTLSIntolerantServer(const GURL& url) = 0;
- virtual bool IsTLSIntolerantServer(const GURL& url) const = 0;
+ virtual void AddTLSIntolerantServer(const HostPortPair& server) = 0;
+ virtual bool IsTLSIntolerantServer(const HostPortPair& server) const = 0;
// Static settings
static GURL ApplyHostMappingRules(const GURL& url, HostPortPair* endpoint);
diff --git a/net/http/http_stream_factory_impl.cc b/net/http/http_stream_factory_impl.cc
index c7b0c93..8a1ee60 100644
--- a/net/http/http_stream_factory_impl.cc
+++ b/net/http/http_stream_factory_impl.cc
@@ -4,6 +4,7 @@
#include "net/http/http_stream_factory_impl.h"
+#include "base/string_number_conversions.h"
#include "base/stl_util-inl.h"
#include "googleurl/src/gurl.h"
#include "net/base/net_log.h"
@@ -15,6 +16,34 @@
namespace net {
+namespace {
+
+bool HasSpdyExclusion(const HostPortPair& endpoint) {
+ std::list<HostPortPair>* exclusions =
+ HttpStreamFactory::forced_spdy_exclusions();
+ if (!exclusions)
+ return false;
+
+ std::list<HostPortPair>::const_iterator it;
+ for (it = exclusions->begin(); it != exclusions->end(); it++)
+ if (it->Equals(endpoint))
+ return true;
+ return false;
+}
+
+GURL UpgradeUrlToHttps(const GURL& original_url) {
+ GURL::Replacements replacements;
+ // new_sheme and new_port need to be in scope here because GURL::Replacements
+ // references the memory contained by them directly.
+ const std::string new_scheme = "https";
+ const std::string new_port = base::IntToString(443);
+ replacements.SetSchemeStr(new_scheme);
+ replacements.SetPortStr(new_port);
+ return original_url.ReplaceComponents(replacements);
+}
+
+} // namespace
+
HttpStreamFactoryImpl::HttpStreamFactoryImpl(HttpNetworkSession* session)
: session_(session) {}
@@ -23,6 +52,11 @@ HttpStreamFactoryImpl::~HttpStreamFactoryImpl() {
DCHECK(spdy_session_request_map_.empty());
std::set<const Job*> tmp_job_set;
+ tmp_job_set.swap(orphaned_job_set_);
+ STLDeleteContainerPointers(tmp_job_set.begin(), tmp_job_set.end());
+ DCHECK(orphaned_job_set_.empty());
+
+ tmp_job_set.clear();
tmp_job_set.swap(preconnect_job_set_);
STLDeleteContainerPointers(tmp_job_set.begin(), tmp_job_set.end());
DCHECK(preconnect_job_set_.empty());
@@ -33,10 +67,34 @@ HttpStreamRequest* HttpStreamFactoryImpl::RequestStream(
const SSLConfig& ssl_config,
HttpStreamRequest::Delegate* delegate,
const BoundNetLog& net_log) {
- Job* job = new Job(this, session_);
Request* request = new Request(request_info.url, this, delegate, net_log);
+
+ GURL alternate_url;
+ bool has_alternate_protocol =
+ GetAlternateProtocolRequestFor(request_info.url, &alternate_url);
+ Job* alternate_job = NULL;
+ if (has_alternate_protocol) {
+ HttpRequestInfo alternate_request_info = request_info;
+ alternate_request_info.url = alternate_url;
+ alternate_job =
+ new Job(this, session_, alternate_request_info, ssl_config, net_log);
+ request->AttachJob(alternate_job);
+ alternate_job->MarkAsAlternate(request_info.url);
+ }
+
+ Job* job = new Job(this, session_, request_info, ssl_config, net_log);
request->AttachJob(job);
- job->Start(request, request_info, ssl_config, net_log);
+ if (alternate_job) {
+ job->WaitFor(alternate_job);
+ // Make sure to wait until we call WaitFor(), before starting
+ // |alternate_job|, otherwise |alternate_job| will not notify |job|
+ // appropriately.
+ alternate_job->Start(request);
+ }
+ // Even if |alternate_job| has already finished, it won't have notified the
+ // request yet, since we defer that to the next iteration of the MessageLoop,
+ // so starting |job| is always safe.
+ job->Start(request);
return request;
}
@@ -45,17 +103,66 @@ void HttpStreamFactoryImpl::PreconnectStreams(
const HttpRequestInfo& request_info,
const SSLConfig& ssl_config,
const BoundNetLog& net_log) {
- Job* job = new Job(this, session_);
+ GURL alternate_url;
+ bool has_alternate_protocol =
+ GetAlternateProtocolRequestFor(request_info.url, &alternate_url);
+ Job* job = NULL;
+ if (has_alternate_protocol) {
+ HttpRequestInfo alternate_request_info = request_info;
+ alternate_request_info.url = alternate_url;
+ job = new Job(this, session_, alternate_request_info, ssl_config, net_log);
+ job->MarkAsAlternate(request_info.url);
+ } else {
+ job = new Job(this, session_, request_info, ssl_config, net_log);
+ }
preconnect_job_set_.insert(job);
- job->Preconnect(num_streams, request_info, ssl_config, net_log);
+ job->Preconnect(num_streams);
+}
+
+void HttpStreamFactoryImpl::AddTLSIntolerantServer(const HostPortPair& server) {
+ tls_intolerant_servers_.insert(server);
}
-void HttpStreamFactoryImpl::AddTLSIntolerantServer(const GURL& url) {
- tls_intolerant_servers_.insert(GetHostAndPort(url));
+bool HttpStreamFactoryImpl::IsTLSIntolerantServer(
+ const HostPortPair& server) const {
+ return ContainsKey(tls_intolerant_servers_, server);
}
-bool HttpStreamFactoryImpl::IsTLSIntolerantServer(const GURL& url) const {
- return ContainsKey(tls_intolerant_servers_, GetHostAndPort(url));
+bool HttpStreamFactoryImpl::GetAlternateProtocolRequestFor(
+ const GURL& original_url,
+ GURL* alternate_url) const {
+ if (!spdy_enabled())
+ return false;
+
+ if (!use_alternate_protocols())
+ return false;
+
+ HostPortPair origin = HostPortPair(original_url.HostNoBrackets(),
+ original_url.EffectiveIntPort());
+
+ const HttpAlternateProtocols& alternate_protocols =
+ session_->alternate_protocols();
+ if (!alternate_protocols.HasAlternateProtocolFor(origin))
+ return false;
+
+ HttpAlternateProtocols::PortProtocolPair alternate =
+ alternate_protocols.GetAlternateProtocolFor(origin);
+ if (alternate.protocol == HttpAlternateProtocols::BROKEN)
+ return false;
+
+ DCHECK_LE(HttpAlternateProtocols::NPN_SPDY_1, alternate.protocol);
+ DCHECK_GT(HttpAlternateProtocols::NUM_ALTERNATE_PROTOCOLS,
+ alternate.protocol);
+
+ if (alternate.protocol != HttpAlternateProtocols::NPN_SPDY_2)
+ return false;
+
+ origin.set_port(alternate.port);
+ if (HasSpdyExclusion(origin))
+ return false;
+
+ *alternate_url = UpgradeUrlToHttps(original_url);
+ return true;
}
void HttpStreamFactoryImpl::OrphanJob(Job* job, const Request* request) {
@@ -74,7 +181,6 @@ void HttpStreamFactoryImpl::OnSpdySessionReady(
bool direct,
const SSLConfig& used_ssl_config,
const ProxyInfo& used_proxy_info,
- bool was_alternate_protocol_available,
bool was_npn_negotiated,
bool using_spdy,
const NetLog::Source& source) {
@@ -91,8 +197,7 @@ void HttpStreamFactoryImpl::OnSpdySessionReady(
if (!ContainsKey(spdy_session_request_map_, spdy_session_key))
break;
Request* request = *spdy_session_request_map_[spdy_session_key].begin();
- request->Complete(was_alternate_protocol_available,
- was_npn_negotiated,
+ request->Complete(was_npn_negotiated,
using_spdy,
source);
bool use_relative_url = direct || request->url().SchemeIs("https");
diff --git a/net/http/http_stream_factory_impl.h b/net/http/http_stream_factory_impl.h
index 4bdbfca..b43bf13 100644
--- a/net/http/http_stream_factory_impl.h
+++ b/net/http/http_stream_factory_impl.h
@@ -7,9 +7,9 @@
#include <map>
#include <set>
-#include <string>
#include "base/ref_counted.h"
+#include "net/base/host_port_pair.h"
#include "net/http/http_stream_factory.h"
#include "net/base/net_log.h"
#include "net/proxy/proxy_server.h"
@@ -35,8 +35,8 @@ class HttpStreamFactoryImpl : public HttpStreamFactory {
const HttpRequestInfo& info,
const SSLConfig& ssl_config,
const BoundNetLog& net_log);
- virtual void AddTLSIntolerantServer(const GURL& url);
- virtual bool IsTLSIntolerantServer(const GURL& url) const;
+ virtual void AddTLSIntolerantServer(const HostPortPair& server);
+ virtual bool IsTLSIntolerantServer(const HostPortPair& server) const;
private:
class Request;
@@ -45,6 +45,9 @@ class HttpStreamFactoryImpl : public HttpStreamFactory {
typedef std::set<Request*> RequestSet;
typedef std::map<HostPortProxyPair, RequestSet> SpdySessionRequestMap;
+ bool GetAlternateProtocolRequestFor(const GURL& original_url,
+ GURL* alternate_url) const;
+
// Detaches |job| from |request|.
void OrphanJob(Job* job, const Request* request);
@@ -55,7 +58,6 @@ class HttpStreamFactoryImpl : public HttpStreamFactory {
bool direct,
const SSLConfig& used_ssl_config,
const ProxyInfo& used_proxy_info,
- bool was_alternate_protocol_available,
bool was_npn_negotiated,
bool using_spdy,
const NetLog::Source& source);
@@ -76,7 +78,7 @@ class HttpStreamFactoryImpl : public HttpStreamFactory {
HttpNetworkSession* const session_;
- std::set<std::string> tls_intolerant_servers_;
+ std::set<HostPortPair> tls_intolerant_servers_;
// All Requests are handed out to clients. By the time HttpStreamFactoryImpl
// is destroyed, all Requests should be deleted (which should remove them from
diff --git a/net/http/http_stream_factory_impl_job.cc b/net/http/http_stream_factory_impl_job.cc
index f8d8a9e..5e65d31 100644
--- a/net/http/http_stream_factory_impl_job.cc
+++ b/net/http/http_stream_factory_impl_job.cc
@@ -6,7 +6,6 @@
#include "base/logging.h"
#include "base/stl_util-inl.h"
-#include "base/string_number_conversions.h"
#include "base/string_util.h"
#include "base/stringprintf.h"
#include "base/values.h"
@@ -34,46 +33,38 @@ namespace net {
namespace {
-GURL UpgradeUrlToHttps(const GURL& original_url) {
- GURL::Replacements replacements;
- // new_sheme and new_port need to be in scope here because GURL::Replacements
- // references the memory contained by them directly.
- const std::string new_scheme = "https";
- const std::string new_port = base::IntToString(443);
- replacements.SetSchemeStr(new_scheme);
- replacements.SetPortStr(new_port);
- return original_url.ReplaceComponents(replacements);
-}
-
} // namespace
HttpStreamFactoryImpl::Job::Job(HttpStreamFactoryImpl* stream_factory,
- HttpNetworkSession* session)
+ HttpNetworkSession* session,
+ const HttpRequestInfo& request_info,
+ const SSLConfig& ssl_config,
+ const BoundNetLog& net_log)
: request_(NULL),
+ request_info_(request_info),
+ ssl_config_(ssl_config),
+ net_log_(BoundNetLog::Make(net_log.net_log(),
+ NetLog::SOURCE_HTTP_STREAM_JOB)),
ALLOW_THIS_IN_INITIALIZER_LIST(io_callback_(this, &Job::OnIOComplete)),
connection_(new ClientSocketHandle),
session_(session),
stream_factory_(stream_factory),
next_state_(STATE_NONE),
pac_request_(NULL),
+ blocking_job_(NULL),
+ dependent_job_(NULL),
using_ssl_(false),
using_spdy_(false),
force_spdy_always_(HttpStreamFactory::force_spdy_always()),
force_spdy_over_ssl_(HttpStreamFactory::force_spdy_over_ssl()),
spdy_certificate_error_(OK),
- alternate_protocol_(HttpAlternateProtocols::UNINITIALIZED),
establishing_tunnel_(false),
- was_alternate_protocol_available_(false),
was_npn_negotiated_(false),
num_streams_(0),
spdy_session_direct_(false),
ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {
DCHECK(stream_factory);
DCHECK(session);
- if (HttpStreamFactory::use_alternate_protocols())
- alternate_protocol_mode_ = kUnspecified;
- else
- alternate_protocol_mode_ = kDoNotUseAlternateProtocol;
}
HttpStreamFactoryImpl::Job::~Job() {
@@ -95,22 +86,16 @@ HttpStreamFactoryImpl::Job::~Job() {
stream_->Close(true /* not reusable */);
}
-void HttpStreamFactoryImpl::Job::Start(Request* request,
- const HttpRequestInfo& request_info,
- const SSLConfig& ssl_config,
- const BoundNetLog& net_log) {
+void HttpStreamFactoryImpl::Job::Start(Request* request) {
DCHECK(request);
request_ = request;
- StartInternal(request_info, ssl_config, net_log);
+ StartInternal();
}
-int HttpStreamFactoryImpl::Job::Preconnect(int num_streams,
- const HttpRequestInfo& request_info,
- const SSLConfig& ssl_config,
- const BoundNetLog& net_log) {
+int HttpStreamFactoryImpl::Job::Preconnect(int num_streams) {
DCHECK_GT(num_streams, 0);
num_streams_ = num_streams;
- return StartInternal(request_info, ssl_config, net_log);
+ return StartInternal();
}
int HttpStreamFactoryImpl::Job::RestartTunnelWithProxyAuth(
@@ -134,13 +119,45 @@ LoadState HttpStreamFactoryImpl::Job::GetLoadState() const {
}
}
+void HttpStreamFactoryImpl::Job::MarkAsAlternate(const GURL& original_url) {
+ DCHECK(!original_url_.get());
+ original_url_.reset(new GURL(original_url));
+}
+
+void HttpStreamFactoryImpl::Job::WaitFor(Job* job) {
+ DCHECK_EQ(STATE_NONE, next_state_);
+ DCHECK_EQ(STATE_NONE, job->next_state_);
+ DCHECK(!blocking_job_);
+ DCHECK(!job->dependent_job_);
+ blocking_job_ = job;
+ job->dependent_job_ = this;
+}
+
+void HttpStreamFactoryImpl::Job::Resume(Job* job) {
+ DCHECK_EQ(blocking_job_, job);
+ blocking_job_ = NULL;
+
+ // We know we're blocked if the next_state_ is STATE_WAIT_FOR_JOB_COMPLETE.
+ // Unblock |this|.
+ if (next_state_ == STATE_WAIT_FOR_JOB_COMPLETE) {
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ method_factory_.NewRunnableMethod(
+ &HttpStreamFactoryImpl::Job::OnIOComplete, OK));
+ }
+}
+
void HttpStreamFactoryImpl::Job::Orphan(const Request* request) {
DCHECK_EQ(request_, request);
request_ = NULL;
-}
-
-bool HttpStreamFactoryImpl::Job::was_alternate_protocol_available() const {
- return was_alternate_protocol_available_;
+ // We've been orphaned, but there's a job we're blocked on. Don't bother
+ // racing, just cancel ourself.
+ if (blocking_job_) {
+ DCHECK(blocking_job_->dependent_job_);
+ blocking_job_->dependent_job_ = NULL;
+ blocking_job_ = NULL;
+ stream_factory_->OnOrphanedJobComplete(this);
+ }
}
bool HttpStreamFactoryImpl::Job::was_npn_negotiated() const {
@@ -174,8 +191,7 @@ void HttpStreamFactoryImpl::Job::OnStreamReadyCallback() {
if (IsOrphaned()) {
stream_factory_->OnOrphanedJobComplete(this);
} else {
- request_->Complete(was_alternate_protocol_available(),
- was_npn_negotiated(),
+ request_->Complete(was_npn_negotiated(),
using_spdy(),
net_log_.source());
request_->OnStreamReady(this, ssl_config_, proxy_info_, stream_.release());
@@ -193,8 +209,7 @@ void HttpStreamFactoryImpl::Job::OnSpdySessionReadyCallback() {
if (IsOrphaned()) {
stream_factory_->OnSpdySessionReady(
spdy_session, spdy_session_direct_, ssl_config_, proxy_info_,
- was_alternate_protocol_available(), was_npn_negotiated(),
- using_spdy(), net_log_.source());
+ was_npn_negotiated(), using_spdy(), net_log_.source());
stream_factory_->OnOrphanedJobComplete(this);
} else {
request_->OnSpdySessionReady(this, spdy_session, spdy_session_direct_);
@@ -260,8 +275,7 @@ void HttpStreamFactoryImpl::Job::OnPreconnectsComplete() {
if (new_spdy_session_) {
stream_factory_->OnSpdySessionReady(
new_spdy_session_, spdy_session_direct_, ssl_config_,
- proxy_info_, was_alternate_protocol_available(),
- was_npn_negotiated(), using_spdy(), net_log_.source());
+ proxy_info_, was_npn_negotiated(), using_spdy(), net_log_.source());
}
stream_factory_->OnPreconnectsComplete(this);
// |this| may be deleted after this call.
@@ -385,6 +399,13 @@ int HttpStreamFactoryImpl::Job::DoLoop(int result) {
case STATE_RESOLVE_PROXY_COMPLETE:
rv = DoResolveProxyComplete(rv);
break;
+ case STATE_WAIT_FOR_JOB:
+ DCHECK_EQ(OK, rv);
+ rv = DoWaitForJob();
+ break;
+ case STATE_WAIT_FOR_JOB_COMPLETE:
+ rv = DoWaitForJobComplete(rv);
+ break;
case STATE_INIT_CONNECTION:
DCHECK_EQ(OK, rv);
rv = DoInitConnection();
@@ -418,18 +439,11 @@ int HttpStreamFactoryImpl::Job::DoLoop(int result) {
return rv;
}
-int HttpStreamFactoryImpl::Job::StartInternal(
- const HttpRequestInfo& request_info,
- const SSLConfig& ssl_config,
- const BoundNetLog& net_log) {
+int HttpStreamFactoryImpl::Job::StartInternal() {
CHECK_EQ(STATE_NONE, next_state_);
- request_info_ = request_info;
- ssl_config_ = ssl_config;
- net_log_ = BoundNetLog::Make(net_log.net_log(),
- NetLog::SOURCE_HTTP_STREAM_JOB);
net_log_.BeginEvent(NetLog::TYPE_HTTP_STREAM_JOB,
make_scoped_refptr(new NetLogStringParameter(
- "url", request_info.url.GetOrigin().spec())));
+ "url", request_info_.url.GetOrigin().spec())));
next_state_ = STATE_RESOLVE_PROXY;
int rv = RunLoop(OK);
DCHECK_EQ(ERR_IO_PENDING, rv);
@@ -441,40 +455,8 @@ int HttpStreamFactoryImpl::Job::DoResolveProxy() {
next_state_ = STATE_RESOLVE_PROXY_COMPLETE;
- // |endpoint_| indicates the final destination endpoint.
- endpoint_ = HostPortPair(request_info_.url.HostNoBrackets(),
- request_info_.url.EffectiveIntPort());
-
- // Extra URL we might be attempting to resolve to.
- GURL alternate_endpoint_url = request_info_.url;
-
- // Tracks whether we are using |request_.url| or |alternate_endpoint_url|.
- const GURL *curr_endpoint_url = &request_info_.url;
-
- alternate_endpoint_url =
- HttpStreamFactory::ApplyHostMappingRules(
- alternate_endpoint_url, &endpoint_);
-
- const HttpAlternateProtocols& alternate_protocols =
- session_->alternate_protocols();
- if (HttpStreamFactory::spdy_enabled() &&
- alternate_protocols.HasAlternateProtocolFor(endpoint_)) {
- was_alternate_protocol_available_ = true;
- if (alternate_protocol_mode_ == kUnspecified) {
- HttpAlternateProtocols::PortProtocolPair alternate =
- alternate_protocols.GetAlternateProtocolFor(endpoint_);
- if (alternate.protocol != HttpAlternateProtocols::BROKEN) {
- DCHECK_LE(HttpAlternateProtocols::NPN_SPDY_1, alternate.protocol);
- DCHECK_GT(HttpAlternateProtocols::NUM_ALTERNATE_PROTOCOLS,
- alternate.protocol);
- endpoint_.set_port(alternate.port);
- alternate_protocol_ = alternate.protocol;
- alternate_protocol_mode_ = kUsingAlternateProtocol;
- alternate_endpoint_url = UpgradeUrlToHttps(*curr_endpoint_url);
- curr_endpoint_url = &alternate_endpoint_url;
- }
- }
- }
+ origin_ = HostPortPair(request_info_.url.HostNoBrackets(),
+ request_info_.url.EffectiveIntPort());
if (request_info_.load_flags & LOAD_BYPASS_PROXY) {
proxy_info_.UseDirect();
@@ -482,101 +464,104 @@ int HttpStreamFactoryImpl::Job::DoResolveProxy() {
}
return session_->proxy_service()->ResolveProxy(
- *curr_endpoint_url, &proxy_info_, &io_callback_, &pac_request_,
+ request_info_.url, &proxy_info_, &io_callback_, &pac_request_,
net_log_);
}
int HttpStreamFactoryImpl::Job::DoResolveProxyComplete(int result) {
pac_request_ = NULL;
- if (result != OK)
- return result;
-
- // TODO(mbelshe): consider retrying ResolveProxy if we came here via use of
- // AlternateProtocol.
-
- // Remove unsupported proxies from the list.
- proxy_info_.RemoveProxiesWithoutScheme(
- ProxyServer::SCHEME_DIRECT |
- ProxyServer::SCHEME_HTTP | ProxyServer::SCHEME_HTTPS |
- ProxyServer::SCHEME_SOCKS4 | ProxyServer::SCHEME_SOCKS5);
+ if (result == OK) {
+ // Remove unsupported proxies from the list.
+ proxy_info_.RemoveProxiesWithoutScheme(
+ ProxyServer::SCHEME_DIRECT |
+ ProxyServer::SCHEME_HTTP | ProxyServer::SCHEME_HTTPS |
+ ProxyServer::SCHEME_SOCKS4 | ProxyServer::SCHEME_SOCKS5);
+
+ if (proxy_info_.is_empty()) {
+ // No proxies/direct to choose from. This happens when we don't support
+ // any of the proxies in the returned list.
+ result = ERR_NO_SUPPORTED_PROXIES;
+ }
+ }
- if (proxy_info_.is_empty()) {
- // No proxies/direct to choose from. This happens when we don't support any
- // of the proxies in the returned list.
- return ERR_NO_SUPPORTED_PROXIES;
+ if (result != OK) {
+ if (dependent_job_)
+ dependent_job_->Resume(this);
+ return result;
}
- next_state_ = STATE_INIT_CONNECTION;
+ if (blocking_job_)
+ next_state_ = STATE_WAIT_FOR_JOB;
+ else
+ next_state_ = STATE_INIT_CONNECTION;
return OK;
}
-static bool HasSpdyExclusion(const HostPortPair& endpoint) {
- std::list<HostPortPair>* exclusions =
- HttpStreamFactory::forced_spdy_exclusions();
- if (!exclusions)
- return false;
+bool HttpStreamFactoryImpl::Job::ShouldForceSpdySSL() const {
+ return force_spdy_always_ && force_spdy_over_ssl_;
+}
- std::list<HostPortPair>::const_iterator it;
- for (it = exclusions->begin(); it != exclusions->end(); it++)
- if (it->Equals(endpoint))
- return true;
- return false;
+bool HttpStreamFactoryImpl::Job::ShouldForceSpdyWithoutSSL() const {
+ return force_spdy_always_ && !force_spdy_over_ssl_;
}
-bool HttpStreamFactoryImpl::Job::ShouldForceSpdySSL() {
- bool rv = force_spdy_always_ && force_spdy_over_ssl_;
- return rv && !HasSpdyExclusion(endpoint_);
+int HttpStreamFactoryImpl::Job::DoWaitForJob() {
+ DCHECK(blocking_job_);
+ next_state_ = STATE_WAIT_FOR_JOB_COMPLETE;
+ return ERR_IO_PENDING;
}
-bool HttpStreamFactoryImpl::Job::ShouldForceSpdyWithoutSSL() {
- bool rv = force_spdy_always_ && !force_spdy_over_ssl_;
- return rv && !HasSpdyExclusion(endpoint_);
+int HttpStreamFactoryImpl::Job::DoWaitForJobComplete(int result) {
+ DCHECK(!blocking_job_);
+ DCHECK_EQ(OK, result);
+ next_state_ = STATE_INIT_CONNECTION;
+ return OK;
}
int HttpStreamFactoryImpl::Job::DoInitConnection() {
+ DCHECK(!blocking_job_);
DCHECK(!connection_->is_initialized());
DCHECK(proxy_info_.proxy_server().is_valid());
next_state_ = STATE_INIT_CONNECTION_COMPLETE;
- bool want_spdy_over_npn =
- alternate_protocol_mode_ == kUsingAlternateProtocol &&
- alternate_protocol_ == HttpAlternateProtocols::NPN_SPDY_2;
- using_ssl_ = request_info_.url.SchemeIs("https") ||
- ShouldForceSpdySSL() || want_spdy_over_npn;
+ using_ssl_ = request_info_.url.SchemeIs("https") || ShouldForceSpdySSL();
using_spdy_ = false;
- // If spdy has been turned off on-the-fly, then there may be SpdySessions
- // still active. But don't use them unless spdy is currently on.
- if (HttpStreamFactory::spdy_enabled() && !HasSpdyExclusion(endpoint_)) {
- // Check first if we have a spdy session for this group. If so, then go
- // straight to using that.
- HostPortProxyPair spdy_session_key;
- if (IsHttpsProxyAndHttpUrl()) {
- spdy_session_key =
- HostPortProxyPair(proxy_info_.proxy_server().host_port_pair(),
- ProxyServer::Direct());
- } else {
- spdy_session_key =
- HostPortProxyPair(endpoint_, proxy_info_.proxy_server());
- }
- if (session_->spdy_session_pool()->HasSession(spdy_session_key)) {
- // If we're preconnecting, but we already have a SpdySession, we don't
- // actually need to preconnect any sockets, so we're done.
- if (IsPreconnecting())
- return OK;
- using_spdy_ = true;
- next_state_ = STATE_CREATE_STREAM;
+ // Check first if we have a spdy session for this group. If so, then go
+ // straight to using that.
+ HostPortProxyPair spdy_session_key;
+ if (IsHttpsProxyAndHttpUrl()) {
+ spdy_session_key =
+ HostPortProxyPair(proxy_info_.proxy_server().host_port_pair(),
+ ProxyServer::Direct());
+ } else {
+ spdy_session_key = HostPortProxyPair(origin_, proxy_info_.proxy_server());
+ }
+ if (session_->spdy_session_pool()->HasSession(spdy_session_key)) {
+ // If we're preconnecting, but we already have a SpdySession, we don't
+ // actually need to preconnect any sockets, so we're done.
+ if (IsPreconnecting())
return OK;
- } else if (request_) {
- // Update the spdy session key for the request that launched this job.
- request_->SetSpdySessionKey(spdy_session_key);
- }
+ using_spdy_ = true;
+ next_state_ = STATE_CREATE_STREAM;
+ return OK;
+ } else if (request_ && (using_ssl_ || ShouldForceSpdyWithoutSSL())) {
+ // Update the spdy session key for the request that launched this job.
+ request_->SetSpdySessionKey(spdy_session_key);
+ }
+
+ // OK, there's no available SPDY session. Let |dependent_job_| resume if it's
+ // paused.
+
+ if (dependent_job_) {
+ dependent_job_->Resume(this);
+ dependent_job_ = NULL;
}
// Build the string used to uniquely identify connections of this type.
// Determine the host and port to connect to.
- std::string connection_group = endpoint_.ToString();
+ std::string connection_group = origin_.ToString();
DCHECK(!connection_group.empty());
if (using_ssl_)
@@ -595,7 +580,7 @@ int HttpStreamFactoryImpl::Job::DoInitConnection() {
scoped_ptr<HostPortPair> proxy_host_port;
if (proxy_info_.is_direct()) {
- tcp_params = new TCPSocketParams(endpoint_, request_info_.priority,
+ tcp_params = new TCPSocketParams(origin_, request_info_.priority,
request_info_.referrer,
disable_resolver_cache);
} else {
@@ -606,19 +591,6 @@ int HttpStreamFactoryImpl::Job::DoInitConnection() {
request_info_.referrer, disable_resolver_cache));
if (proxy_info_.is_http() || proxy_info_.is_https()) {
- GURL authentication_url = request_info_.url;
- if (using_ssl_ && !authentication_url.SchemeIs("https")) {
- // If a proxy tunnel connection needs to be established due to
- // an Alternate-Protocol, the URL needs to be changed to indicate
- // https or digest authentication attempts will fail.
- // For example, suppose the initial request was for
- // "http://www.example.com/index.html". If this is an SSL
- // upgrade due to alternate protocol, the digest authorization
- // should have a uri="www.example.com:443" field rather than a
- // "/index.html" entry, even though the original request URL has not
- // changed.
- authentication_url = UpgradeUrlToHttps(authentication_url);
- }
establishing_tunnel_ = using_ssl_;
std::string user_agent;
request_info_.extra_headers.GetHeader(HttpRequestHeaders::kUserAgent,
@@ -629,16 +601,16 @@ int HttpStreamFactoryImpl::Job::DoInitConnection() {
ssl_params = GenerateSSLParams(proxy_tcp_params, NULL, NULL,
ProxyServer::SCHEME_DIRECT,
*proxy_host_port.get(),
- want_spdy_over_npn);
+ original_url_.get() ? true : false);
proxy_tcp_params = NULL;
}
http_proxy_params =
new HttpProxySocketParams(proxy_tcp_params,
ssl_params,
- authentication_url,
+ request_info_.url,
user_agent,
- endpoint_,
+ origin_,
session_->http_auth_cache(),
session_->http_auth_handler_factory(),
session_->spdy_session_pool(),
@@ -655,7 +627,7 @@ int HttpStreamFactoryImpl::Job::DoInitConnection() {
socks_params = new SOCKSSocketParams(proxy_tcp_params,
socks_version == '5',
- endpoint_,
+ origin_,
request_info_.priority,
request_info_.referrer);
}
@@ -666,8 +638,7 @@ int HttpStreamFactoryImpl::Job::DoInitConnection() {
scoped_refptr<SSLSocketParams> ssl_params =
GenerateSSLParams(tcp_params, http_proxy_params, socks_params,
proxy_info_.proxy_server().scheme(),
- HostPortPair::FromURL(request_info_.url),
- want_spdy_over_npn);
+ origin_, original_url_.get() ? true : false);
SSLClientSocketPool* ssl_pool = NULL;
if (proxy_info_.is_direct())
ssl_pool = session_->ssl_socket_pool();
@@ -734,6 +705,13 @@ int HttpStreamFactoryImpl::Job::DoInitConnectionComplete(int result) {
return OK;
}
+ // TODO(willchan): Make this a bit more exact. Maybe there are recoverable
+ // errors, such as ignoring certificate errors for Alternate-Protocol.
+ if (result < 0 && dependent_job_) {
+ dependent_job_->Resume(this);
+ dependent_job_ = NULL;
+ }
+
// |result| may be the result of any of the stacked pools. The following
// logic is used when determining how to interpret an error.
// If |result| < 0:
@@ -782,12 +760,11 @@ int HttpStreamFactoryImpl::Job::DoInitConnectionComplete(int result) {
return result;
}
- if ((!ssl_started && result < 0 &&
- alternate_protocol_mode_ == kUsingAlternateProtocol) ||
- result == ERR_NPN_NEGOTIATION_FAILED) {
+ if (!ssl_started && result < 0 && original_url_.get()) {
// Mark the alternate protocol as broken and fallback.
- MarkBrokenAlternateProtocolAndFallback();
- return OK;
+ session_->mutable_alternate_protocols()->MarkBrokenAlternateProtocolFor(
+ HostPortPair::FromURL(*original_url_));
+ return result;
}
if (result < 0 && !ssl_started)
@@ -808,7 +785,8 @@ int HttpStreamFactoryImpl::Job::DoInitConnectionComplete(int result) {
if (using_ssl_) {
DCHECK(ssl_started);
if (IsCertificateError(result)) {
- if (using_spdy_ && request_info_.url.SchemeIs("http")) {
+ if (using_spdy_ && original_url_.get() &&
+ original_url_->SchemeIs("http")) {
// We ignore certificate errors for http over spdy.
spdy_certificate_error_ = result;
result = OK;
@@ -862,7 +840,7 @@ int HttpStreamFactoryImpl::Job::DoCreateStream() {
SpdySessionPool* spdy_pool = session_->spdy_session_pool();
scoped_refptr<SpdySession> spdy_session;
- HostPortProxyPair pair(endpoint_, proxy_server);
+ HostPortProxyPair pair(origin_, proxy_server);
if (spdy_pool->HasSession(pair)) {
// We have a SPDY session to the origin server. This might be a direct
// connection, or it might be a SPDY session through an HTTP or HTTPS proxy.
@@ -966,7 +944,15 @@ void HttpStreamFactoryImpl::Job::SetSocketMotivation() {
}
bool HttpStreamFactoryImpl::Job::IsHttpsProxyAndHttpUrl() {
- return proxy_info_.is_https() && request_info_.url.SchemeIs("http");
+ if (!proxy_info_.is_https())
+ return false;
+ if (original_url_.get()) {
+ // We currently only support Alternate-Protocol where the original scheme
+ // is http.
+ DCHECK(original_url_->SchemeIs("http"));
+ return original_url_->SchemeIs("http");
+ }
+ return request_info_.url.SchemeIs("http");
}
// Returns a newly create SSLSocketParams, and sets several
@@ -976,12 +962,12 @@ scoped_refptr<SSLSocketParams> HttpStreamFactoryImpl::Job::GenerateSSLParams(
scoped_refptr<HttpProxySocketParams> http_proxy_params,
scoped_refptr<SOCKSSocketParams> socks_params,
ProxyServer::Scheme proxy_scheme,
- const HostPortPair& host_and_port,
+ const HostPortPair& origin_server,
bool want_spdy_over_npn) {
- if (stream_factory_->IsTLSIntolerantServer(request_info_.url)) {
+ if (stream_factory_->IsTLSIntolerantServer(origin_server)) {
LOG(WARNING) << "Falling back to SSLv3 because host is TLS intolerant: "
- << GetHostAndPort(request_info_.url);
+ << origin_server.ToString();
ssl_config_.ssl3_fallback = true;
ssl_config_.tls1_enabled = false;
}
@@ -1014,7 +1000,7 @@ scoped_refptr<SSLSocketParams> HttpStreamFactoryImpl::Job::GenerateSSLParams(
scoped_refptr<SSLSocketParams> ssl_params(
new SSLSocketParams(tcp_params, socks_params, http_proxy_params,
- proxy_scheme, host_and_port,
+ proxy_scheme, origin_server,
ssl_config_, load_flags,
ShouldForceSpdySSL(),
want_spdy_over_npn));
@@ -1023,24 +1009,6 @@ scoped_refptr<SSLSocketParams> HttpStreamFactoryImpl::Job::GenerateSSLParams(
}
-void HttpStreamFactoryImpl::Job::MarkBrokenAlternateProtocolAndFallback() {
- // We have to:
- // * Reset the endpoint to be the unmodified URL specified destination.
- // * Mark the endpoint as broken so we don't try again.
- // * Set the alternate protocol mode to kDoNotUseAlternateProtocol so we
- // ignore future Alternate-Protocol headers from the HostPortPair.
- // * Reset the connection and go back to STATE_INIT_CONNECTION.
-
- endpoint_ = HostPortPair(request_info_.url.HostNoBrackets(),
- request_info_.url.EffectiveIntPort());
-
- session_->mutable_alternate_protocols()->MarkBrokenAlternateProtocolFor(
- endpoint_);
-
- alternate_protocol_mode_ = kDoNotUseAlternateProtocol;
- ReturnToStateInitConnection(false /* close connection */);
-}
-
int HttpStreamFactoryImpl::Job::ReconsiderProxyAfterError(int error) {
DCHECK(!pac_request_);
diff --git a/net/http/http_stream_factory_impl_job.h b/net/http/http_stream_factory_impl_job.h
index b466640..213b590 100644
--- a/net/http/http_stream_factory_impl_job.h
+++ b/net/http/http_stream_factory_impl_job.h
@@ -35,31 +35,40 @@ class TCPSocketParams;
class HttpStreamFactoryImpl::Job {
public:
Job(HttpStreamFactoryImpl* stream_factory,
- HttpNetworkSession* session);
+ HttpNetworkSession* session,
+ const HttpRequestInfo& request_info,
+ const SSLConfig& ssl_config,
+ const BoundNetLog& net_log);
~Job();
- // Start initiates the process of creating a new HttpStream.
- // 3 parameters are passed in by reference. The caller asserts that the
- // lifecycle of these parameters will remain valid until the stream is
- // created, failed, or destroyed. In the first two cases, the delegate will
- // be called to notify completion of the request.
- void Start(Request* request,
- const HttpRequestInfo& request_info,
- const SSLConfig& ssl_config,
- const BoundNetLog& net_log);
-
- int Preconnect(int num_streams,
- const HttpRequestInfo& request_info,
- const SSLConfig& ssl_config,
- const BoundNetLog& net_log);
+ // Start initiates the process of creating a new HttpStream. |request| will be
+ // notified upon completion if the Job has not been Orphan()'d.
+ void Start(Request* request);
+
+ // Preconnect will attempt to request |num_streams| sockets from the
+ // appropriate ClientSocketPool.
+ int Preconnect(int num_streams);
int RestartTunnelWithProxyAuth(const string16& username,
const string16& password);
LoadState GetLoadState() const;
+ // Marks this Job as the "alternate" job, from Alternate-Protocol. Tracks the
+ // original url so we can mark the Alternate-Protocol as broken if
+ // we fail to connect.
+ void MarkAsAlternate(const GURL& original_url);
+
+ // Tells |this| to wait for |job| to resume it.
+ void WaitFor(Job* job);
+
+ // Tells |this| that |job| has determined it still needs to continue
+ // connecting, so allow |this| to continue. If this is not called, then
+ // |request_| is expected to cancel |this| by deleting it.
+ void Resume(Job* job);
+
+ // Used to detach the Job from |request|.
void Orphan(const Request* request);
- bool was_alternate_protocol_available() const;
bool was_npn_negotiated() const;
bool using_spdy() const;
const BoundNetLog& net_log() const { return net_log_; }
@@ -74,15 +83,28 @@ class HttpStreamFactoryImpl::Job {
bool IsOrphaned() const;
private:
- enum AlternateProtocolMode {
- kUnspecified, // Unspecified, check HttpAlternateProtocols
- kUsingAlternateProtocol, // Using an alternate protocol
- kDoNotUseAlternateProtocol, // Failed to connect once, do not try again.
- };
-
enum State {
STATE_RESOLVE_PROXY,
STATE_RESOLVE_PROXY_COMPLETE,
+
+ // Note that when Alternate-Protocol says we can connect to an alternate
+ // port using a different protocol, we have the choice of communicating over
+ // the original protocol, or speaking the alternate protocol (currently,
+ // only npn-spdy) over an alternate port. For a cold page load, the http
+ // connection that delivers the http response that has the
+ // Alternate-Protocol header will already be warm. So, blocking the next
+ // http request on establishing a new npn-spdy connection would incur extra
+ // latency. Even if the http connection was not reused, establishing a new
+ // http connection is typically faster than npn-spdy, since npn-spdy
+ // requires a SSL handshake. Therefore, we start both the http and the
+ // npn-spdy jobs in parallel. In order not to unnecessarily waste sockets,
+ // we have the http job block on the npn-spdy job after proxy resolution.
+ // The npn-spdy job will Resume() the http job if, in
+ // STATE_INIT_CONNECTION_COMPLETE, it detects an error or does not find an
+ // existing SpdySession. In that case, the http and npn-spdy jobs will race.
+ STATE_WAIT_FOR_JOB,
+ STATE_WAIT_FOR_JOB_COMPLETE,
+
STATE_INIT_CONNECTION,
STATE_INIT_CONNECTION_COMPLETE,
STATE_WAITING_USER_ACTION,
@@ -110,9 +132,7 @@ class HttpStreamFactoryImpl::Job {
void OnIOComplete(int result);
int RunLoop(int result);
int DoLoop(int result);
- int StartInternal(const HttpRequestInfo& request_info,
- const SSLConfig& ssl_config,
- const BoundNetLog& net_log);
+ int StartInternal();
// Each of these methods corresponds to a State value. Those with an input
// argument receive the result from the previous state. If a method returns
@@ -120,6 +140,8 @@ class HttpStreamFactoryImpl::Job {
// next state method as the result arg.
int DoResolveProxy();
int DoResolveProxyComplete(int result);
+ int DoWaitForJob();
+ int DoWaitForJobComplete(int result);
int DoInitConnection();
int DoInitConnectionComplete(int result);
int DoWaitingUserAction(int result);
@@ -174,31 +196,42 @@ class HttpStreamFactoryImpl::Job {
void SwitchToSpdyMode();
// Should we force SPDY to run over SSL for this stream request.
- bool ShouldForceSpdySSL();
+ bool ShouldForceSpdySSL() const;
// Should we force SPDY to run without SSL for this stream request.
- bool ShouldForceSpdyWithoutSSL();
+ bool ShouldForceSpdyWithoutSSL() const;
// Record histograms of latency until Connect() completes.
static void LogHttpConnectedMetrics(const ClientSocketHandle& handle);
Request* request_;
- HttpRequestInfo request_info_;
+ const HttpRequestInfo request_info_;
ProxyInfo proxy_info_;
SSLConfig ssl_config_;
+ const BoundNetLog net_log_;
CompletionCallbackImpl<Job> io_callback_;
scoped_ptr<ClientSocketHandle> connection_;
HttpNetworkSession* const session_;
HttpStreamFactoryImpl* const stream_factory_;
- BoundNetLog net_log_;
State next_state_;
ProxyService::PacRequest* pac_request_;
SSLInfo ssl_info_;
- // The hostname and port of the endpoint. This is not necessarily the one
- // specified by the URL, due to Alternate-Protocol or fixed testing ports.
- HostPortPair endpoint_;
+
+ // The origin server we're trying to reach.
+ HostPortPair origin_;
+
+ // If this is a Job for an "Alternate-Protocol", then this will be non-NULL
+ // and will specify the original URL.
+ scoped_ptr<GURL> original_url_;
+
+ // This is the Job we're dependent on. It will notify us if/when it's OK to
+ // proceed.
+ Job* blocking_job_;
+
+ // |dependent_job_| is dependent on |this|. Notify it when it's ok to proceed.
+ Job* dependent_job_;
// True if handling a HTTPS request, or using SPDY with SSL
bool using_ssl_;
@@ -218,21 +251,12 @@ class HttpStreamFactoryImpl::Job {
scoped_refptr<HttpAuthController>
auth_controllers_[HttpAuth::AUTH_NUM_TARGETS];
- AlternateProtocolMode alternate_protocol_mode_;
-
- // Only valid if |alternate_protocol_mode_| == kUsingAlternateProtocol.
- HttpAlternateProtocols::Protocol alternate_protocol_;
-
// True when the tunnel is in the process of being established - we can't
// read from the socket until the tunnel is done.
bool establishing_tunnel_;
scoped_ptr<HttpStream> stream_;
- // True if finding the connection for this request found an alternate
- // protocol was available.
- bool was_alternate_protocol_available_;
-
// True if we negotiated NPN.
bool was_npn_negotiated_;
diff --git a/net/http/http_stream_factory_impl_request.cc b/net/http/http_stream_factory_impl_request.cc
index b9e0cee..d8bb09f 100644
--- a/net/http/http_stream_factory_impl_request.cc
+++ b/net/http/http_stream_factory_impl_request.cc
@@ -21,7 +21,6 @@ HttpStreamFactoryImpl::Request::Request(const GURL& url,
delegate_(delegate),
net_log_(net_log),
completed_(false),
- was_alternate_protocol_available_(false),
was_npn_negotiated_(false),
using_spdy_(false) {
DCHECK(factory_);
@@ -63,13 +62,11 @@ void HttpStreamFactoryImpl::Request::AttachJob(Job* job) {
}
void HttpStreamFactoryImpl::Request::Complete(
- bool was_alternate_protocol_available,
bool was_npn_negotiated,
bool using_spdy,
const NetLog::Source& job_source) {
DCHECK(!completed_);
completed_ = true;
- was_alternate_protocol_available_ = was_alternate_protocol_available;
was_npn_negotiated_ = was_npn_negotiated;
using_spdy_ = using_spdy;
net_log_.AddEvent(
@@ -114,10 +111,23 @@ void HttpStreamFactoryImpl::Request::OnStreamFailed(
int status,
const SSLConfig& used_ssl_config) {
DCHECK_NE(OK, status);
- if (!bound_job_.get())
- OrphanJobsExcept(job);
- else
+ if (!bound_job_.get()) {
+ // Hey, we've got other jobs! Maybe one of them will succeed, let's just
+ // ignore this failure.
+ if (jobs_.size() > 1) {
+ jobs_.erase(job);
+ factory_->request_map_.erase(job);
+ delete job;
+ return;
+ } else {
+ bound_job_.reset(job);
+ jobs_.erase(job);
+ DCHECK(jobs_.empty());
+ factory_->request_map_.erase(job);
+ }
+ } else {
DCHECK(jobs_.empty());
+ }
delegate_->OnStreamFailed(status, used_ssl_config);
}
@@ -189,11 +199,6 @@ LoadState HttpStreamFactoryImpl::Request::GetLoadState() const {
return (*jobs_.begin())->GetLoadState();
}
-bool HttpStreamFactoryImpl::Request::was_alternate_protocol_available() const {
- DCHECK(completed_);
- return was_alternate_protocol_available_;
-}
-
bool HttpStreamFactoryImpl::Request::was_npn_negotiated() const {
DCHECK(completed_);
return was_npn_negotiated_;
@@ -238,14 +243,11 @@ void HttpStreamFactoryImpl::Request::OnSpdySessionReady(
// Cache these values in case the job gets deleted.
const SSLConfig used_ssl_config = job->ssl_config();
const ProxyInfo used_proxy_info = job->proxy_info();
- const bool was_alternate_protocol_available =
- job->was_alternate_protocol_available();
const bool was_npn_negotiated = job->was_npn_negotiated();
const bool using_spdy = job->using_spdy();
const NetLog::Source source = job->net_log().source();
- Complete(was_alternate_protocol_available,
- was_npn_negotiated,
+ Complete(was_npn_negotiated,
using_spdy,
source);
@@ -260,7 +262,7 @@ void HttpStreamFactoryImpl::Request::OnSpdySessionReady(
// |this| may be deleted after this point.
factory->OnSpdySessionReady(
spdy_session, direct, used_ssl_config, used_proxy_info,
- was_alternate_protocol_available, was_npn_negotiated, using_spdy, source);
+ was_npn_negotiated, using_spdy, source);
}
void HttpStreamFactoryImpl::Request::OrphanJobsExcept(Job* job) {
diff --git a/net/http/http_stream_factory_impl_request.h b/net/http/http_stream_factory_impl_request.h
index 3c1b996..248a316 100644
--- a/net/http/http_stream_factory_impl_request.h
+++ b/net/http/http_stream_factory_impl_request.h
@@ -37,8 +37,7 @@ class HttpStreamFactoryImpl::Request : public HttpStreamRequest {
// Marks completion of the request. Must be called before OnStreamReady().
// |source| is the NetLog::Source generated by the Job that fulfilled this
// request.
- void Complete(bool was_alternate_protocol_available,
- bool was_npn_negotiated,
+ void Complete(bool was_npn_negotiated,
bool using_spdy,
const NetLog::Source& source);
@@ -83,7 +82,6 @@ class HttpStreamFactoryImpl::Request : public HttpStreamRequest {
virtual int RestartTunnelWithProxyAuth(const string16& username,
const string16& password);
virtual LoadState GetLoadState() const;
- virtual bool was_alternate_protocol_available() const;
virtual bool was_npn_negotiated() const;
virtual bool using_spdy() const;
@@ -106,7 +104,6 @@ class HttpStreamFactoryImpl::Request : public HttpStreamRequest {
scoped_ptr<const HostPortProxyPair> spdy_session_key_;
bool completed_;
- bool was_alternate_protocol_available_;
bool was_npn_negotiated_;
bool using_spdy_;
diff --git a/net/socket/client_socket_pool_base.cc b/net/socket/client_socket_pool_base.cc
index c25f6ab..6d5e410 100644
--- a/net/socket/client_socket_pool_base.cc
+++ b/net/socket/client_socket_pool_base.cc
@@ -636,6 +636,11 @@ void ClientSocketPoolBaseHelper::RemoveGroup(GroupMap::iterator it) {
}
// static
+bool ClientSocketPoolBaseHelper::connect_backup_jobs_enabled() {
+ return g_connect_backup_jobs_enabled;
+}
+
+// static
void ClientSocketPoolBaseHelper::set_connect_backup_jobs_enabled(bool enabled) {
g_connect_backup_jobs_enabled = enabled;
}
diff --git a/net/socket/client_socket_pool_base.h b/net/socket/client_socket_pool_base.h
index 53c8fbc..8fcb571 100644
--- a/net/socket/client_socket_pool_base.h
+++ b/net/socket/client_socket_pool_base.h
@@ -283,7 +283,9 @@ class ClientSocketPoolBaseHelper
return connect_job_factory_->ConnectionTimeout();
}
+ static bool connect_backup_jobs_enabled();
static void set_connect_backup_jobs_enabled(bool enabled);
+
void EnableConnectBackupJobs();
// ConnectJob::Delegate methods:
diff --git a/net/spdy/spdy_network_transaction_unittest.cc b/net/spdy/spdy_network_transaction_unittest.cc
index acfb7ea..9f4e1fe 100644
--- a/net/spdy/spdy_network_transaction_unittest.cc
+++ b/net/spdy/spdy_network_transaction_unittest.cc
@@ -11,6 +11,7 @@
#include "net/base/net_log_unittest.h"
#include "net/http/http_network_session_peer.h"
#include "net/http/http_transaction_unittest.h"
+#include "net/socket/client_socket_pool_base.h"
#include "net/spdy/spdy_http_stream.h"
#include "net/spdy/spdy_http_utils.h"
#include "net/spdy/spdy_session.h"
@@ -35,17 +36,25 @@ enum SpdyNetworkTransactionTestTypes {
class SpdyNetworkTransactionTest
: public ::testing::TestWithParam<SpdyNetworkTransactionTestTypes> {
protected:
+
virtual void SetUp() {
// By default, all tests turn off compression.
EnableCompression(false);
google_get_request_initialized_ = false;
google_post_request_initialized_ = false;
google_chunked_post_request_initialized_ = false;
+
+ backup_jobs_prev_value_ =
+ internal::ClientSocketPoolBaseHelper::connect_backup_jobs_enabled();
+ internal::ClientSocketPoolBaseHelper::set_connect_backup_jobs_enabled(
+ false);
}
virtual void TearDown() {
// Empty the current queue.
MessageLoop::current()->RunAllPending();
+ internal::ClientSocketPoolBaseHelper::set_connect_backup_jobs_enabled(
+ backup_jobs_prev_value_);
}
struct TransactionHelperResult {
@@ -167,10 +176,8 @@ class SpdyNetworkTransactionTest
EXPECT_EQ(spdy_enabled_, response->was_fetched_via_spdy);
if (test_type_ == SPDYNPN && spdy_enabled_) {
EXPECT_TRUE(response->was_npn_negotiated);
- EXPECT_TRUE(response->was_alternate_protocol_available);
} else {
EXPECT_TRUE(!response->was_npn_negotiated);
- EXPECT_TRUE(!response->was_alternate_protocol_available);
}
// If SPDY is not enabled, a HTTP request should not be diverted
// over a SSL session.
@@ -237,9 +244,20 @@ class SpdyNetworkTransactionTest
ssl_->was_npn_negotiated = true;
}
ssl_vector_.push_back(ssl_);
- if(test_type_ == SPDYNPN || test_type_ == SPDYSSL)
+ if (test_type_ == SPDYNPN || test_type_ == SPDYSSL)
session_deps_->socket_factory->AddSSLSocketDataProvider(ssl_.get());
session_deps_->socket_factory->AddSocketDataProvider(data);
+ if (test_type_ == SPDYNPN) {
+ MockConnect never_finishing_connect(false, ERR_IO_PENDING);
+ linked_ptr<StaticSocketDataProvider>
+ hanging_non_alternate_protocol_socket(
+ new StaticSocketDataProvider(NULL, 0, NULL, 0));
+ hanging_non_alternate_protocol_socket->set_connect_data(
+ never_finishing_connect);
+ session_deps_->socket_factory->AddSocketDataProvider(
+ hanging_non_alternate_protocol_socket.get());
+ alternate_vector_.push_back(hanging_non_alternate_protocol_socket);
+ }
}
void AddDeterministicData(DeterministicSocketData* data) {
@@ -253,10 +271,23 @@ class SpdyNetworkTransactionTest
ssl_->was_npn_negotiated = true;
}
ssl_vector_.push_back(ssl_);
- if(test_type_ == SPDYNPN || test_type_ == SPDYSSL)
+ if (test_type_ == SPDYNPN || test_type_ == SPDYSSL) {
session_deps_->deterministic_socket_factory->
AddSSLSocketDataProvider(ssl_.get());
+ }
session_deps_->deterministic_socket_factory->AddSocketDataProvider(data);
+ if (test_type_ == SPDYNPN) {
+ MockConnect never_finishing_connect(false, ERR_IO_PENDING);
+ scoped_refptr<DeterministicSocketData>
+ hanging_non_alternate_protocol_socket(
+ new DeterministicSocketData(NULL, 0, NULL, 0));
+ hanging_non_alternate_protocol_socket->set_connect_data(
+ never_finishing_connect);
+ session_deps_->deterministic_socket_factory->AddSocketDataProvider(
+ hanging_non_alternate_protocol_socket);
+ alternate_deterministic_vector_.push_back(
+ hanging_non_alternate_protocol_socket);
+ }
}
// This can only be called after RunPreTestSetup. It adds a Data Provider,
@@ -289,6 +320,9 @@ class SpdyNetworkTransactionTest
private:
typedef std::vector<StaticSocketDataProvider*> DataVector;
typedef std::vector<linked_ptr<SSLSocketDataProvider> > SSLVector;
+ typedef std::vector<linked_ptr<StaticSocketDataProvider> > AlternateVector;
+ typedef std::vector<scoped_refptr<DeterministicSocketData> >
+ AlternateDeterministicVector;
HttpRequestInfo request_;
scoped_ptr<SpdySessionDependencies> session_deps_;
scoped_refptr<HttpNetworkSession> session_;
@@ -299,6 +333,8 @@ class SpdyNetworkTransactionTest
scoped_ptr<HttpNetworkTransaction> trans_;
scoped_ptr<HttpNetworkTransaction> trans_http_;
DataVector data_vector_;
+ AlternateVector alternate_vector_;
+ AlternateDeterministicVector alternate_deterministic_vector_;
const BoundNetLog& log_;
SpdyNetworkTransactionTestTypes test_type_;
int port_;
@@ -475,6 +511,8 @@ class SpdyNetworkTransactionTest
HttpRequestInfo google_post_request_;
HttpRequestInfo google_chunked_post_request_;
HttpRequestInfo google_get_push_request_;
+
+ bool backup_jobs_prev_value_;
};
//-----------------------------------------------------------------------------
@@ -704,7 +742,7 @@ TEST_P(SpdyNetworkTransactionTest, TwoGetsLateBinding) {
new OrderedSocketData(reads, arraysize(reads),
writes, arraysize(writes)));
- MockConnect never_finishing_connect(true, ERR_IO_PENDING);
+ MockConnect never_finishing_connect(false, ERR_IO_PENDING);
scoped_refptr<OrderedSocketData> data_placeholder(
new OrderedSocketData(NULL, 0, NULL, 0));
@@ -893,10 +931,12 @@ TEST_P(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrent) {
settings.push_back(spdy::SpdySetting(id, max_concurrent_streams));
scoped_ptr<spdy::SpdyFrame> settings_frame(ConstructSpdySettings(settings));
- MockWrite writes[] = { CreateMockWrite(*req),
- CreateMockWrite(*req2),
- CreateMockWrite(*req3),
+ MockWrite writes[] = {
+ CreateMockWrite(*req),
+ CreateMockWrite(*req2),
+ CreateMockWrite(*req3),
};
+
MockRead reads[] = {
CreateMockRead(*settings_frame, 1),
CreateMockRead(*resp),
@@ -921,14 +961,14 @@ TEST_P(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrent) {
BoundNetLog log;
TransactionHelperResult out;
{
- NormalSpdyTransactionHelper helper(CreateGetRequest(),
- BoundNetLog(), GetParam());
- helper.RunPreTestSetup();
- helper.AddData(data.get());
- // We require placeholder data because three get requests are sent out, so
- // there needs to be three sets of SSL connection data.
- helper.AddData(data_placeholder.get());
- helper.AddData(data_placeholder.get());
+ NormalSpdyTransactionHelper helper(CreateGetRequest(),
+ BoundNetLog(), GetParam());
+ helper.RunPreTestSetup();
+ helper.AddData(data.get());
+ // We require placeholder data because three get requests are sent out, so
+ // there needs to be three sets of SSL connection data.
+ helper.AddData(data_placeholder.get());
+ helper.AddData(data_placeholder.get());
scoped_ptr<HttpNetworkTransaction> trans1(
new HttpNetworkTransaction(helper.session()));
scoped_ptr<HttpNetworkTransaction> trans2(
@@ -1716,7 +1756,7 @@ TEST_P(SpdyNetworkTransactionTest, SocketWriteReturnsZero) {
scoped_refptr<DeterministicSocketData> data(
new DeterministicSocketData(reads, arraysize(reads),
- writes, arraysize(writes)));
+ writes, arraysize(writes)));
NormalSpdyTransactionHelper helper(CreateGetRequest(),
BoundNetLog(), GetParam());
helper.SetDeterministic();
@@ -3807,80 +3847,6 @@ TEST_P(SpdyNetworkTransactionTest, BufferFull) {
EXPECT_EQ("goodbye world", out.response_data);
}
-TEST_P(SpdyNetworkTransactionTest, ConnectFailureFallbackToHttp) {
- MockConnect connects[] = {
- MockConnect(true, ERR_NAME_NOT_RESOLVED),
- MockConnect(false, ERR_NAME_NOT_RESOLVED),
- MockConnect(true, ERR_INTERNET_DISCONNECTED),
- MockConnect(false, ERR_INTERNET_DISCONNECTED)
- };
-
- for (size_t index = 0; index < arraysize(connects); ++index) {
- scoped_ptr<spdy::SpdyFrame> req(
- ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
- MockWrite writes[] = {
- CreateMockWrite(*req),
- MockWrite(true, 0, 0) // EOF
- };
-
- scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
- scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true));
- MockRead reads[] = {
- CreateMockRead(*resp),
- CreateMockRead(*body),
- MockRead(true, 0, 0) // EOF
- };
-
- scoped_refptr<DelayedSocketData> data(
- new DelayedSocketData(connects[index], 1, reads, arraysize(reads),
- writes, arraysize(writes)));
- NormalSpdyTransactionHelper helper(CreateGetRequest(),
- BoundNetLog(), GetParam());
- helper.RunPreTestSetup();
- helper.AddData(data.get());
-
- // Set up http fallback data.
- MockRead http_fallback_data[] = {
- MockRead("HTTP/1.1 200 OK\r\n\r\n"),
- MockRead("hello world!!!"),
- MockRead(true, OK),
- };
-
- scoped_ptr<StaticSocketDataProvider> http_fallback(
- new StaticSocketDataProvider(http_fallback_data,
- arraysize(http_fallback_data),
- NULL, 0));
- helper.AddDataNoSSL(http_fallback.get());
- HttpNetworkTransaction* trans = helper.trans();
- TestCompletionCallback callback;
-
- int rv = trans->Start(&helper.request(), &callback, BoundNetLog());
- EXPECT_EQ(rv, ERR_IO_PENDING);
- rv = callback.WaitForResult();
- const HttpResponseInfo* response = trans->GetResponseInfo();
- if (GetParam() == SPDYNOSSL || GetParam() == SPDYSSL) {
- ASSERT_TRUE(response == NULL);
- return;
- }
- if (GetParam() != SPDYNPN)
- NOTREACHED();
- ASSERT_TRUE(response != NULL);
- ASSERT_TRUE(response->headers != NULL);
- EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
- std::string response_data;
- rv = ReadTransaction(trans, &response_data);
- EXPECT_EQ(OK, rv);
-
- EXPECT_TRUE(!response->was_fetched_via_spdy);
- EXPECT_TRUE(!response->was_npn_negotiated);
- EXPECT_TRUE(response->was_alternate_protocol_available);
- EXPECT_TRUE(http_fallback->at_read_eof());
- EXPECT_EQ(0u, data->read_index());
- EXPECT_EQ(0u, data->write_index());
- EXPECT_EQ("hello world!!!", response_data);
- }
-}
-
// Verify that basic buffering works; when multiple data frames arrive
// at the same time, ensure that we don't notify a read completion for
// each data frame individually.
diff --git a/net/url_request/url_request.h b/net/url_request/url_request.h
index c573099..2c58db1 100644
--- a/net/url_request/url_request.h
+++ b/net/url_request/url_request.h
@@ -409,12 +409,6 @@ class URLRequest : public base::NonThreadSafe {
return response_info_.was_npn_negotiated;
}
- // Returns true if the URLRequest was delivered when the alternate protocol
- // is available.
- bool was_alternate_protocol_available() const {
- return response_info_.was_alternate_protocol_available;
- }
-
// Returns true if the URLRequest was delivered through a proxy.
bool was_fetched_via_proxy() const {
return response_info_.was_fetched_via_proxy;