diff options
-rw-r--r-- | net/http/http_alternate_protocols.cc | 4 | ||||
-rw-r--r-- | net/http/http_alternate_protocols.h | 6 | ||||
-rw-r--r-- | net/http/http_alternate_protocols_unittest.cc | 6 | ||||
-rw-r--r-- | net/http/http_network_transaction.cc | 62 | ||||
-rw-r--r-- | net/http/http_network_transaction.h | 9 | ||||
-rw-r--r-- | net/http/http_network_transaction_unittest.cc | 76 |
6 files changed, 122 insertions, 41 deletions
diff --git a/net/http/http_alternate_protocols.cc b/net/http/http_alternate_protocols.cc index 7f8bdfa..a945917 100644 --- a/net/http/http_alternate_protocols.cc +++ b/net/http/http_alternate_protocols.cc @@ -10,7 +10,9 @@ namespace net { const char HttpAlternateProtocols::kHeader[] = "Alternate-Protocol"; -const char HttpAlternateProtocols::kSpdyProtocol[] = "SPDY"; +const char* const HttpAlternateProtocols::kProtocolStrings[] = { + "npn-spdy", +}; HttpAlternateProtocols::HttpAlternateProtocols() {} HttpAlternateProtocols::~HttpAlternateProtocols() {} diff --git a/net/http/http_alternate_protocols.h b/net/http/http_alternate_protocols.h index 9ce5157..a6ccab33 100644 --- a/net/http/http_alternate_protocols.h +++ b/net/http/http_alternate_protocols.h @@ -19,9 +19,9 @@ namespace net { class HttpAlternateProtocols { public: enum Protocol { - BROKEN, // The alternate protocol is known to be broken. - SPDY, + NPN_SPDY, NUM_ALTERNATE_PROTOCOLS, + BROKEN, // The alternate protocol is known to be broken. }; struct PortProtocolPair { @@ -34,7 +34,7 @@ class HttpAlternateProtocols { }; static const char kHeader[]; - static const char kSpdyProtocol[]; + static const char* const kProtocolStrings[NUM_ALTERNATE_PROTOCOLS]; HttpAlternateProtocols(); ~HttpAlternateProtocols(); diff --git a/net/http/http_alternate_protocols_unittest.cc b/net/http/http_alternate_protocols_unittest.cc index df1a832..7f94534 100644 --- a/net/http/http_alternate_protocols_unittest.cc +++ b/net/http/http_alternate_protocols_unittest.cc @@ -21,12 +21,12 @@ TEST(HttpAlternateProtocols, Basic) { alternate_protocols.HasAlternateProtocolFor(test_host_port_pair)); alternate_protocols.SetAlternateProtocolFor(test_host_port_pair, 443, - HttpAlternateProtocols::SPDY); + HttpAlternateProtocols::NPN_SPDY); ASSERT_TRUE(alternate_protocols.HasAlternateProtocolFor(test_host_port_pair)); const HttpAlternateProtocols::PortProtocolPair alternate = alternate_protocols.GetAlternateProtocolFor(test_host_port_pair); EXPECT_EQ(443, alternate.port); - EXPECT_EQ(HttpAlternateProtocols::SPDY, alternate.protocol); + EXPECT_EQ(HttpAlternateProtocols::NPN_SPDY, alternate.protocol); } TEST(HttpAlternateProtocols, SetBroken) { @@ -43,7 +43,7 @@ TEST(HttpAlternateProtocols, SetBroken) { alternate_protocols.SetAlternateProtocolFor( test_host_port_pair, 1234, - HttpAlternateProtocols::SPDY), + HttpAlternateProtocols::NPN_SPDY), alternate = alternate_protocols.GetAlternateProtocolFor(test_host_port_pair); EXPECT_EQ(HttpAlternateProtocols::BROKEN, alternate.protocol) << "Second attempt should be ignored."; diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc index fd26195..10f32431 100644 --- a/net/http/http_network_transaction.cc +++ b/net/http/http_network_transaction.cc @@ -44,6 +44,8 @@ namespace net { namespace { +const std::string* g_next_protos = NULL; + void BuildRequestHeaders(const HttpRequestInfo* request_info, const std::string& authorization_headers, const UploadDataStream* upload_data_stream, @@ -141,6 +143,12 @@ void BuildTunnelRequest(const HttpRequestInfo* request_info, void ProcessAlternateProtocol(const HttpResponseHeaders& headers, const HostPortPair& http_host_port_pair, HttpAlternateProtocols* alternate_protocols) { + if (!g_next_protos || g_next_protos->empty()) { + // This implies that NPN is not suppoted. We don't currently support any + // alternate protocols that don't use NPN. + return; + } + std::string alternate_protocol_str; if (!headers.EnumerateHeader(NULL, HttpAlternateProtocols::kHeader, &alternate_protocol_str)) { @@ -166,8 +174,10 @@ void ProcessAlternateProtocol(const HttpResponseHeaders& headers, return; } - if (port_protocol_vector[1] != HttpAlternateProtocols::kSpdyProtocol) { - // Currently, we only recognize the Spdy protocol. + if (port_protocol_vector[1] != + HttpAlternateProtocols::kProtocolStrings[ + HttpAlternateProtocols::NPN_SPDY]) { + // Currently, we only recognize the npn-spdy protocol. DLOG(WARNING) << HttpAlternateProtocols::kHeader << " header has unrecognized protocol: " << port_protocol_vector[1]; @@ -182,16 +192,14 @@ void ProcessAlternateProtocol(const HttpResponseHeaders& headers, return; } - alternate_protocols->SetAlternateProtocolFor(http_host_port_pair, - port, - HttpAlternateProtocols::SPDY); + alternate_protocols->SetAlternateProtocolFor( + http_host_port_pair, port, HttpAlternateProtocols::NPN_SPDY); } } // namespace //----------------------------------------------------------------------------- -std::string* HttpNetworkTransaction::g_next_protos = NULL; bool HttpNetworkTransaction::g_ignore_certificate_errors = false; HttpNetworkTransaction::HttpNetworkTransaction(HttpNetworkSession* session) @@ -709,9 +717,10 @@ int HttpNetworkTransaction::DoInitConnection() { HttpAlternateProtocols::PortProtocolPair alternate = alternate_protocols.GetAlternateProtocolFor(host, port); if (alternate.protocol != HttpAlternateProtocols::BROKEN) { - DCHECK_EQ(HttpAlternateProtocols::SPDY, alternate.protocol); + DCHECK_EQ(HttpAlternateProtocols::NPN_SPDY, alternate.protocol); port = alternate.port; using_ssl_ = true; + alternate_protocol_ = HttpAlternateProtocols::NPN_SPDY; alternate_protocol_mode_ = kUsingAlternateProtocol; } } @@ -760,20 +769,7 @@ int HttpNetworkTransaction::DoInitConnectionComplete(int result) { if (result < 0) { if (alternate_protocol_mode_ == kUsingAlternateProtocol) { // Mark the alternate protocol as broken and fallback. - - HostPortPair http_host_port_pair; - http_host_port_pair.host = request_->url.host(); - http_host_port_pair.port = request_->url.EffectiveIntPort(); - - session_->mutable_alternate_protocols()->MarkBrokenAlternateProtocolFor( - http_host_port_pair); - - alternate_protocol_mode_ = kDoNotUseAlternateProtocol; - - if (connection_->socket()) - connection_->socket()->Disconnect(); - connection_->Reset(); - next_state_ = STATE_INIT_CONNECTION; + MarkBrokenAlternateProtocolAndFallback(); return OK; } @@ -881,6 +877,15 @@ int HttpNetworkTransaction::DoSSLConnectComplete(int result) { using_spdy_ = (status == SSLClientSocket::kNextProtoNegotiated && proto == kSpdyProto); + if (alternate_protocol_mode_ == kUsingAlternateProtocol && + alternate_protocol_ == HttpAlternateProtocols::NPN_SPDY && + !using_spdy_) { + // We tried using the NPN_SPDY alternate protocol, but failed, so we + // fallback. + MarkBrokenAlternateProtocolAndFallback(); + return OK; + } + if (IsCertificateError(result)) { result = HandleCertificateError(result); if (result == OK && !connection_->socket()->IsConnectedAndIdle()) { @@ -1913,4 +1918,19 @@ void HttpNetworkTransaction::PopulateAuthChallenge(HttpAuth::Target target, response_.auth_challenge = auth_info; } +void HttpNetworkTransaction::MarkBrokenAlternateProtocolAndFallback() { + HostPortPair http_host_port_pair; + http_host_port_pair.host = request_->url.host(); + http_host_port_pair.port = request_->url.EffectiveIntPort(); + + session_->mutable_alternate_protocols()->MarkBrokenAlternateProtocolFor( + http_host_port_pair); + + alternate_protocol_mode_ = kDoNotUseAlternateProtocol; + if (connection_->socket()) + connection_->socket()->Disconnect(); + connection_->Reset(); + next_state_ = STATE_INIT_CONNECTION; +} + } // namespace net diff --git a/net/http/http_network_transaction.h b/net/http/http_network_transaction.h index 80957bf..bf5327a 100644 --- a/net/http/http_network_transaction.h +++ b/net/http/http_network_transaction.h @@ -17,6 +17,7 @@ #include "net/base/load_flags.h" #include "net/base/load_states.h" #include "net/base/ssl_config_service.h" +#include "net/http/http_alternate_protocols.h" #include "net/http/http_auth.h" #include "net/http/http_auth_handler.h" #include "net/http/http_response_info.h" @@ -262,12 +263,12 @@ class HttpNetworkTransaction : public HttpTransaction { // For proxy authentication the path is always empty string. std::string AuthPath(HttpAuth::Target target) const; + void MarkBrokenAlternateProtocolAndFallback(); + // Returns a string representation of a HttpAuth::Target value that can be // used in log messages. static std::string AuthTargetString(HttpAuth::Target target); - static std::string* g_next_protos; - static bool g_ignore_certificate_errors; // The following three auth members are arrays of size two -- index 0 is @@ -327,8 +328,10 @@ class HttpNetworkTransaction : public HttpTransaction { // True if this network transaction is using SPDY instead of HTTP. bool using_spdy_; - // True if this network transaction is using an alternate protocol to connect. AlternateProtocolMode alternate_protocol_mode_; + + // Only valid if |alternate_protocol_mode_| == kUsingAlternateProtocol. + HttpAlternateProtocols::Protocol alternate_protocol_; // True if we've used the username/password embedded in the URL. This // makes sure we use the embedded identity only once for the transaction, diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc index 1cdc818..aa0bca8 100644 --- a/net/http/http_network_transaction_unittest.cc +++ b/net/http/http_network_transaction_unittest.cc @@ -4253,11 +4253,13 @@ TEST_F(HttpNetworkTransactionTest, ChangeAuthRealms) { } TEST_F(HttpNetworkTransactionTest, HonorAlternateProtocolHeader) { + HttpNetworkTransaction::SetNextProtos("needs_to_be_set_for_this_test"); + SessionDependencies session_deps; MockRead data_reads[] = { MockRead("HTTP/1.1 200 OK\r\n"), - MockRead("Alternate-Protocol: 443:SPDY\r\n\r\n"), + MockRead("Alternate-Protocol: 443:npn-spdy\r\n\r\n"), MockRead("hello world"), MockRead(false, OK), }; @@ -4303,8 +4305,10 @@ TEST_F(HttpNetworkTransactionTest, HonorAlternateProtocolHeader) { alternate_protocols.GetAlternateProtocolFor(http_host_port_pair); HttpAlternateProtocols::PortProtocolPair expected_alternate; expected_alternate.port = 443; - expected_alternate.protocol = HttpAlternateProtocols::SPDY; + expected_alternate.protocol = HttpAlternateProtocols::NPN_SPDY; EXPECT_TRUE(expected_alternate.Equals(alternate)); + + HttpNetworkTransaction::SetNextProtos(""); } TEST_F(HttpNetworkTransactionTest, MarkBrokenAlternateProtocol) { @@ -4345,7 +4349,7 @@ TEST_F(HttpNetworkTransactionTest, MarkBrokenAlternateProtocol) { session->mutable_alternate_protocols(); alternate_protocols->SetAlternateProtocolFor( http_host_port_pair, 1234 /* port is ignored by MockConnect anyway */, - HttpAlternateProtocols::SPDY); + HttpAlternateProtocols::NPN_SPDY); scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); @@ -4374,7 +4378,55 @@ TEST_F(HttpNetworkTransactionTest, MarkBrokenAlternateProtocol) { // 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) { +// 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); +// +// scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); +// +// int rv = trans->Start(&request, &callback, NULL); +// 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) { SessionDependencies session_deps; HttpRequestInfo request; @@ -4382,16 +4434,20 @@ TEST_F(HttpNetworkTransactionTest, UseAlternateProtocol) { request.url = GURL("http://www.google.com/"); request.load_flags = 0; + StaticSocketDataProvider first_tcp_connect; + session_deps.socket_factory.AddSocketDataProvider(&first_tcp_connect); + + SSLSocketDataProvider ssl(true, OK); + session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); + 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); + StaticSocketDataProvider fallback_data( + data_reads, arraysize(data_reads), NULL, 0); + session_deps.socket_factory.AddSocketDataProvider(&fallback_data); TestCompletionCallback callback; @@ -4404,7 +4460,7 @@ TEST_F(HttpNetworkTransactionTest, UseAlternateProtocol) { session->mutable_alternate_protocols(); alternate_protocols->SetAlternateProtocolFor( http_host_port_pair, 1234 /* port is ignored */, - HttpAlternateProtocols::SPDY); + HttpAlternateProtocols::NPN_SPDY); scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); |