summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorwillchan@chromium.org <willchan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-03-09 16:30:42 +0000
committerwillchan@chromium.org <willchan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-03-09 16:30:42 +0000
commit564b491ea6d163724307331648bd7b45cdada99e (patch)
tree135aa4b4e6e36e5ace999fb363c20b7913f4061d /net
parentad54c1966904ed5b3d7e71c8f6caf4606c7e6a93 (diff)
downloadchromium_src-564b491ea6d163724307331648bd7b45cdada99e.zip
chromium_src-564b491ea6d163724307331648bd7b45cdada99e.tar.gz
chromium_src-564b491ea6d163724307331648bd7b45cdada99e.tar.bz2
SPDY: Add basic support for Alternate-Protocol header.
Review URL: http://codereview.chromium.org/668197 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@41032 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r--net/base/host_port_pair.cc14
-rw-r--r--net/base/host_port_pair.h33
-rw-r--r--net/http/http_alternate_protocols.cc87
-rw-r--r--net/http/http_alternate_protocols.h72
-rw-r--r--net/http/http_alternate_protocols_unittest.cc53
-rw-r--r--net/http/http_network_session.h9
-rw-r--r--net/http/http_network_transaction.cc94
-rw-r--r--net/http/http_network_transaction.h9
-rw-r--r--net/http/http_network_transaction_unittest.cc170
-rw-r--r--net/net.gyp5
-rw-r--r--net/spdy/spdy_session_pool.h18
11 files changed, 546 insertions, 18 deletions
diff --git a/net/base/host_port_pair.cc b/net/base/host_port_pair.cc
new file mode 100644
index 0000000..06a95fb
--- /dev/null
+++ b/net/base/host_port_pair.cc
@@ -0,0 +1,14 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/base/host_port_pair.h"
+#include "base/string_util.h"
+
+namespace net {
+
+std::string HostPortPair::ToString() const {
+ return StringPrintf("[Host: %s, Port: %u]", host.c_str(), port);
+}
+
+} // namespace net
diff --git a/net/base/host_port_pair.h b/net/base/host_port_pair.h
new file mode 100644
index 0000000..ab7f312
--- /dev/null
+++ b/net/base/host_port_pair.h
@@ -0,0 +1,33 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_BASE_HOST_PORT_PAIR_H_
+#define NET_BASE_HOST_PORT_PAIR_H_
+
+#include <string>
+#include "base/basictypes.h"
+
+namespace net {
+
+struct HostPortPair {
+ HostPortPair() {}
+ HostPortPair(const std::string& in_host, uint16 in_port)
+ : host(in_host), port(in_port) {}
+
+ // Comparator function so this can be placed in a std::map.
+ bool operator<(const HostPortPair& other) const {
+ if (host != other.host)
+ return host < other.host;
+ return port < other.port;
+ }
+
+ std::string ToString() const;
+
+ std::string host;
+ uint16 port;
+};
+
+} // namespace net
+
+#endif // NET_BASE_HOST_PORT_PAIR_H_
diff --git a/net/http/http_alternate_protocols.cc b/net/http/http_alternate_protocols.cc
new file mode 100644
index 0000000..7f8bdfa
--- /dev/null
+++ b/net/http/http_alternate_protocols.cc
@@ -0,0 +1,87 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/http/http_alternate_protocols.h"
+
+#include "base/logging.h"
+#include "base/stl_util-inl.h"
+
+namespace net {
+
+const char HttpAlternateProtocols::kHeader[] = "Alternate-Protocol";
+const char HttpAlternateProtocols::kSpdyProtocol[] = "SPDY";
+
+HttpAlternateProtocols::HttpAlternateProtocols() {}
+HttpAlternateProtocols::~HttpAlternateProtocols() {}
+
+bool HttpAlternateProtocols::HasAlternateProtocolFor(
+ const HostPortPair& http_host_port_pair) const {
+ return ContainsKey(protocol_map_, http_host_port_pair);
+}
+
+bool HttpAlternateProtocols::HasAlternateProtocolFor(
+ const std::string& host, uint16 port) const {
+ struct HostPortPair http_host_port_pair;
+ http_host_port_pair.host = host;
+ http_host_port_pair.port = port;
+ return HasAlternateProtocolFor(http_host_port_pair);
+}
+
+HttpAlternateProtocols::PortProtocolPair
+HttpAlternateProtocols::GetAlternateProtocolFor(
+ const HostPortPair& http_host_port_pair) const {
+ DCHECK(ContainsKey(protocol_map_, http_host_port_pair));
+ return protocol_map_.find(http_host_port_pair)->second;
+}
+
+HttpAlternateProtocols::PortProtocolPair
+HttpAlternateProtocols::GetAlternateProtocolFor(
+ const std::string& host, uint16 port) const {
+ struct HostPortPair http_host_port_pair;
+ http_host_port_pair.host = host;
+ http_host_port_pair.port = port;
+ return GetAlternateProtocolFor(http_host_port_pair);
+}
+
+void HttpAlternateProtocols::SetAlternateProtocolFor(
+ const HostPortPair& http_host_port_pair,
+ uint16 alternate_port,
+ Protocol alternate_protocol) {
+ if (alternate_protocol == BROKEN) {
+ LOG(DFATAL) << "Call MarkBrokenAlternateProtocolFor() instead.";
+ return;
+ }
+
+ PortProtocolPair alternate;
+ alternate.port = alternate_port;
+ alternate.protocol = alternate_protocol;
+ if (HasAlternateProtocolFor(http_host_port_pair)) {
+ const PortProtocolPair existing_alternate =
+ GetAlternateProtocolFor(http_host_port_pair);
+
+ if (existing_alternate.protocol == BROKEN) {
+ DLOG(INFO) << "Ignore alternate protocol since it's known to be broken.";
+ return;
+ }
+
+ if (alternate_protocol != BROKEN && !existing_alternate.Equals(alternate)) {
+ LOG(WARNING) << "Changing the alternate protocol for: "
+ << http_host_port_pair.ToString()
+ << " from [Port: " << existing_alternate.port
+ << ", Protocol: " << existing_alternate.protocol
+ << "] to [Port: " << alternate_port
+ << ", Protocol: " << alternate_protocol
+ << "].";
+ }
+ }
+
+ protocol_map_[http_host_port_pair] = alternate;
+}
+
+void HttpAlternateProtocols::MarkBrokenAlternateProtocolFor(
+ const HostPortPair& http_host_port_pair) {
+ protocol_map_[http_host_port_pair].protocol = BROKEN;
+}
+
+} // namespace net
diff --git a/net/http/http_alternate_protocols.h b/net/http/http_alternate_protocols.h
new file mode 100644
index 0000000..9ce5157
--- /dev/null
+++ b/net/http/http_alternate_protocols.h
@@ -0,0 +1,72 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// HttpAlternateProtocols is an in-memory data structure used for keeping track
+// of which HTTP HostPortPairs have an alternate protocol that can be used
+// instead of HTTP on a different port.
+
+#ifndef NET_HTTP_HTTP_ALTERNATE_PROTOCOLS_H_
+#define NET_HTTP_HTTP_ALTERNATE_PROTOCOLS_H_
+
+#include <map>
+#include <utility>
+#include "base/basictypes.h"
+#include "net/base/host_port_pair.h"
+
+namespace net {
+
+class HttpAlternateProtocols {
+ public:
+ enum Protocol {
+ BROKEN, // The alternate protocol is known to be broken.
+ SPDY,
+ NUM_ALTERNATE_PROTOCOLS,
+ };
+
+ struct PortProtocolPair {
+ bool Equals(const PortProtocolPair& other) const {
+ return port == other.port && protocol == other.protocol;
+ }
+
+ uint16 port;
+ Protocol protocol;
+ };
+
+ static const char kHeader[];
+ static const char kSpdyProtocol[];
+
+ HttpAlternateProtocols();
+ ~HttpAlternateProtocols();
+
+ // Reports whether or not we have received Alternate-Protocol for
+ // |http_host_port_pair|.
+ bool HasAlternateProtocolFor(const HostPortPair& http_host_port_pair) const;
+ bool HasAlternateProtocolFor(const std::string& host, uint16 port) const;
+
+ PortProtocolPair GetAlternateProtocolFor(
+ const HostPortPair& http_host_port_pair) const;
+ PortProtocolPair GetAlternateProtocolFor(
+ const std::string& host, uint16 port) const;
+
+ // SetAlternateProtocolFor() will ignore the request if the alternate protocol
+ // has already been marked broken via MarkBrokenAlternateProtocolFor().
+ void SetAlternateProtocolFor(const HostPortPair& http_host_port_pair,
+ uint16 alternate_port,
+ Protocol alternate_protocol);
+
+ // Marks the alternate protocol as broken. Once marked broken, any further
+ // attempts to set the alternate protocol for |http_host_port_pair| will fail.
+ void MarkBrokenAlternateProtocolFor(const HostPortPair& http_host_port_pair);
+
+ private:
+ typedef std::map<HostPortPair, PortProtocolPair> ProtocolMap;
+
+ ProtocolMap protocol_map_;
+
+ DISALLOW_COPY_AND_ASSIGN(HttpAlternateProtocols);
+};
+
+} // namespace net
+
+#endif // NET_HTTP_HTTP_ALTERNATE_PROTOCOLS_H_
diff --git a/net/http/http_alternate_protocols_unittest.cc b/net/http/http_alternate_protocols_unittest.cc
new file mode 100644
index 0000000..df1a832
--- /dev/null
+++ b/net/http/http_alternate_protocols_unittest.cc
@@ -0,0 +1,53 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// HttpAlternateProtocols is an in-memory data structure used for keeping track
+// of which HTTP HostPortPairs have an alternate protocol that can be used
+// instead of HTTP on a different port.
+
+#include "net/http/http_alternate_protocols.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+namespace {
+
+TEST(HttpAlternateProtocols, Basic) {
+ HttpAlternateProtocols alternate_protocols;
+ HostPortPair test_host_port_pair;
+ test_host_port_pair.host = "foo";
+ test_host_port_pair.port = 80;
+ EXPECT_FALSE(
+ alternate_protocols.HasAlternateProtocolFor(test_host_port_pair));
+ alternate_protocols.SetAlternateProtocolFor(test_host_port_pair,
+ 443,
+ HttpAlternateProtocols::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);
+}
+
+TEST(HttpAlternateProtocols, SetBroken) {
+ HttpAlternateProtocols alternate_protocols;
+ HostPortPair test_host_port_pair;
+ test_host_port_pair.host = "foo";
+ test_host_port_pair.port = 80;
+ alternate_protocols.MarkBrokenAlternateProtocolFor(test_host_port_pair);
+ ASSERT_TRUE(alternate_protocols.HasAlternateProtocolFor(test_host_port_pair));
+ HttpAlternateProtocols::PortProtocolPair alternate =
+ alternate_protocols.GetAlternateProtocolFor(test_host_port_pair);
+ EXPECT_EQ(HttpAlternateProtocols::BROKEN, alternate.protocol);
+
+ alternate_protocols.SetAlternateProtocolFor(
+ test_host_port_pair,
+ 1234,
+ HttpAlternateProtocols::SPDY),
+ alternate = alternate_protocols.GetAlternateProtocolFor(test_host_port_pair);
+ EXPECT_EQ(HttpAlternateProtocols::BROKEN, alternate.protocol)
+ << "Second attempt should be ignored.";
+}
+
+} // namespace
+} // namespace net
diff --git a/net/http/http_network_session.h b/net/http/http_network_session.h
index 3681970..633798ec 100644
--- a/net/http/http_network_session.h
+++ b/net/http/http_network_session.h
@@ -9,6 +9,7 @@
#include "net/base/host_resolver.h"
#include "net/base/ssl_client_auth_cache.h"
#include "net/base/ssl_config_service.h"
+#include "net/http/http_alternate_protocols.h"
#include "net/http/http_auth_cache.h"
#include "net/proxy/proxy_service.h"
#include "net/socket/tcp_client_socket_pool.h"
@@ -37,6 +38,13 @@ class HttpNetworkSession : public base::RefCounted<HttpNetworkSession> {
return &ssl_client_auth_cache_;
}
+ const HttpAlternateProtocols& alternate_protocols() const {
+ return alternate_protocols_;
+ }
+ HttpAlternateProtocols* mutable_alternate_protocols() {
+ return &alternate_protocols_;
+ }
+
// TCP sockets come from the tcp_socket_pool().
TCPClientSocketPool* tcp_socket_pool() { return tcp_socket_pool_; }
// SSL sockets come frmo the socket_factory().
@@ -82,6 +90,7 @@ class HttpNetworkSession : public base::RefCounted<HttpNetworkSession> {
HttpAuthCache auth_cache_;
SSLClientAuthCache ssl_client_auth_cache_;
+ HttpAlternateProtocols alternate_protocols_;
NetworkChangeNotifier* const network_change_notifier_;
scoped_refptr<TCPClientSocketPool> tcp_socket_pool_;
ClientSocketFactory* socket_factory_;
diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc
index d42dcda..fd26195 100644
--- a/net/http/http_network_transaction.cc
+++ b/net/http/http_network_transaction.cc
@@ -138,6 +138,55 @@ void BuildTunnelRequest(const HttpRequestInfo* request_info,
*request_headers += "\r\n";
}
+void ProcessAlternateProtocol(const HttpResponseHeaders& headers,
+ const HostPortPair& http_host_port_pair,
+ HttpAlternateProtocols* alternate_protocols) {
+ std::string alternate_protocol_str;
+ if (!headers.EnumerateHeader(NULL, HttpAlternateProtocols::kHeader,
+ &alternate_protocol_str)) {
+ // Header is not present.
+ return;
+ }
+
+ std::vector<std::string> port_protocol_vector;
+ SplitString(alternate_protocol_str, ':', &port_protocol_vector);
+ if (port_protocol_vector.size() != 2) {
+ DLOG(WARNING) << HttpAlternateProtocols::kHeader
+ << " header has too many tokens: "
+ << alternate_protocol_str;
+ return;
+ }
+
+ int port;
+ if (!StringToInt(port_protocol_vector[0], &port) ||
+ port <= 0 || port >= 1 << 16) {
+ DLOG(WARNING) << HttpAlternateProtocols::kHeader
+ << " header has unrecognizable port: "
+ << port_protocol_vector[0];
+ return;
+ }
+
+ if (port_protocol_vector[1] != HttpAlternateProtocols::kSpdyProtocol) {
+ // Currently, we only recognize the Spdy protocol.
+ DLOG(WARNING) << HttpAlternateProtocols::kHeader
+ << " header has unrecognized protocol: "
+ << port_protocol_vector[1];
+ return;
+ }
+
+ if (alternate_protocols->HasAlternateProtocolFor(http_host_port_pair)) {
+ const HttpAlternateProtocols::PortProtocolPair existing_alternate =
+ alternate_protocols->GetAlternateProtocolFor(http_host_port_pair);
+ // If we think the alternate protocol is broken, don't change it.
+ if (existing_alternate.protocol == HttpAlternateProtocols::BROKEN)
+ return;
+ }
+
+ alternate_protocols->SetAlternateProtocolFor(http_host_port_pair,
+ port,
+ HttpAlternateProtocols::SPDY);
+}
+
} // namespace
//-----------------------------------------------------------------------------
@@ -161,6 +210,7 @@ HttpNetworkTransaction::HttpNetworkTransaction(HttpNetworkSession* session)
proxy_mode_(kDirectConnection),
establishing_tunnel_(false),
using_spdy_(false),
+ alternate_protocol_mode_(kUnspecified),
embedded_identity_used_(false),
read_buf_len_(0),
next_state_(STATE_NONE) {
@@ -652,6 +702,20 @@ int HttpNetworkTransaction::DoInitConnection() {
} else {
host = request_->url.HostNoBrackets();
port = request_->url.EffectiveIntPort();
+ if (alternate_protocol_mode_ == kUnspecified) {
+ const HttpAlternateProtocols& alternate_protocols =
+ session_->alternate_protocols();
+ if (alternate_protocols.HasAlternateProtocolFor(host, port)) {
+ HttpAlternateProtocols::PortProtocolPair alternate =
+ alternate_protocols.GetAlternateProtocolFor(host, port);
+ if (alternate.protocol != HttpAlternateProtocols::BROKEN) {
+ DCHECK_EQ(HttpAlternateProtocols::SPDY, alternate.protocol);
+ port = alternate.port;
+ using_ssl_ = true;
+ alternate_protocol_mode_ = kUsingAlternateProtocol;
+ }
+ }
+ }
}
// Use the fixed testing ports if they've been provided.
@@ -693,8 +757,28 @@ int HttpNetworkTransaction::DoInitConnection() {
}
int HttpNetworkTransaction::DoInitConnectionComplete(int result) {
- if (result < 0)
+ 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;
+ return OK;
+ }
+
return ReconsiderProxyAfterError(result);
+ }
DCHECK_EQ(OK, result);
@@ -1019,6 +1103,14 @@ int HttpNetworkTransaction::DoReadHeadersComplete(int result) {
return OK;
}
+ HostPortPair http_host_port_pair;
+ http_host_port_pair.host = request_->url.host();
+ http_host_port_pair.port = request_->url.EffectiveIntPort();
+
+ ProcessAlternateProtocol(*response_.headers,
+ http_host_port_pair,
+ session_->mutable_alternate_protocols());
+
int rv = HandleAuthChallenge();
if (rv != OK)
return rv;
diff --git a/net/http/http_network_transaction.h b/net/http/http_network_transaction.h
index e4eef52..80957bf 100644
--- a/net/http/http_network_transaction.h
+++ b/net/http/http_network_transaction.h
@@ -103,6 +103,12 @@ class HttpNetworkTransaction : public HttpTransaction {
kSOCKSProxy, // If using a SOCKS proxy
};
+ enum AlternateProtocolMode {
+ kUnspecified, // Unspecified, check HttpAlternateProtocols
+ kUsingAlternateProtocol, // Using an alternate protocol
+ kDoNotUseAlternateProtocol, // Failed to connect once, do not try again.
+ };
+
void DoCallback(int result);
void OnIOComplete(int result);
@@ -321,6 +327,9 @@ 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_;
+
// 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,
// preventing an infinite auth restart loop.
diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc
index 8d547cf..1cdc818 100644
--- a/net/http/http_network_transaction_unittest.cc
+++ b/net/http/http_network_transaction_unittest.cc
@@ -4252,4 +4252,174 @@ TEST_F(HttpNetworkTransactionTest, ChangeAuthRealms) {
EXPECT_TRUE(response->auth_challenge.get() == NULL);
}
+TEST_F(HttpNetworkTransactionTest, HonorAlternateProtocolHeader) {
+ SessionDependencies session_deps;
+
+ MockRead data_reads[] = {
+ MockRead("HTTP/1.1 200 OK\r\n"),
+ MockRead("Alternate-Protocol: 443:SPDY\r\n\r\n"),
+ MockRead("hello world"),
+ MockRead(false, OK),
+ };
+
+ HttpRequestInfo request;
+ request.method = "GET";
+ request.url = GURL("http://www.google.com/");
+ request.load_flags = 0;
+
+ StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0);
+
+ session_deps.socket_factory.AddSocketDataProvider(&data);
+
+ TestCompletionCallback callback;
+
+ scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
+ scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
+
+ int rv = trans->Start(&request, &callback, NULL);
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ HostPortPair http_host_port_pair;
+ http_host_port_pair.host = "www.google.com";
+ http_host_port_pair.port = 80;
+ const HttpAlternateProtocols& alternate_protocols =
+ session->alternate_protocols();
+ EXPECT_FALSE(
+ alternate_protocols.HasAlternateProtocolFor(http_host_port_pair));
+
+ 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);
+
+ ASSERT_TRUE(alternate_protocols.HasAlternateProtocolFor(http_host_port_pair));
+ const HttpAlternateProtocols::PortProtocolPair alternate =
+ alternate_protocols.GetAlternateProtocolFor(http_host_port_pair);
+ HttpAlternateProtocols::PortProtocolPair expected_alternate;
+ expected_alternate.port = 443;
+ expected_alternate.protocol = HttpAlternateProtocols::SPDY;
+ EXPECT_TRUE(expected_alternate.Equals(alternate));
+}
+
+TEST_F(HttpNetworkTransactionTest, MarkBrokenAlternateProtocol) {
+ SessionDependencies session_deps;
+
+ HttpRequestInfo request;
+ request.method = "GET";
+ request.url = GURL("http://www.google.com/");
+ request.load_flags = 0;
+
+ MockConnect mock_connect(true, ERR_CONNECTION_REFUSED);
+ StaticSocketDataProvider first_data;
+ first_data.set_connect_data(mock_connect);
+ session_deps.socket_factory.AddSocketDataProvider(&first_data);
+
+ MockRead data_reads[] = {
+ MockRead("HTTP/1.1 200 OK\r\n\r\n"),
+ MockRead("hello world"),
+ MockRead(true, OK),
+ };
+ StaticSocketDataProvider second_data(
+ 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));
+
+ 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 by MockConnect anyway */,
+ HttpAlternateProtocols::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);
+
+ ASSERT_TRUE(
+ alternate_protocols->HasAlternateProtocolFor(http_host_port_pair));
+ const HttpAlternateProtocols::PortProtocolPair alternate =
+ alternate_protocols->GetAlternateProtocolFor(http_host_port_pair);
+ EXPECT_EQ(HttpAlternateProtocols::BROKEN, alternate.protocol);
+}
+
+// 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::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);
+}
+
} // namespace net
diff --git a/net/net.gyp b/net/net.gyp
index 0addbbf..ddb42d5 100644
--- a/net/net.gyp
+++ b/net/net.gyp
@@ -64,6 +64,8 @@
'base/gzip_header.h',
'base/host_cache.cc',
'base/host_cache.h',
+ 'base/host_port_pair.cc',
+ 'base/host_port_pair.h',
'base/host_resolver.cc',
'base/host_resolver.h',
'base/host_resolver_impl.cc',
@@ -307,6 +309,8 @@
'ftp/ftp_util.h',
'http/des.cc',
'http/des.h',
+ 'http/http_alternate_protocols.cc',
+ 'http/http_alternate_protocols.h',
'http/http_atom_list.h',
'http/http_auth.cc',
'http/http_auth.h',
@@ -647,6 +651,7 @@
'ftp/ftp_network_transaction_unittest.cc',
'ftp/ftp_util_unittest.cc',
'http/des_unittest.cc',
+ 'http/http_alternate_protocols_unittest.cc',
'http/http_auth_cache_unittest.cc',
'http/http_auth_filter_unittest.cc',
'http/http_auth_handler_basic_unittest.cc',
diff --git a/net/spdy/spdy_session_pool.h b/net/spdy/spdy_session_pool.h
index 8c50577..db4ec42 100644
--- a/net/spdy/spdy_session_pool.h
+++ b/net/spdy/spdy_session_pool.h
@@ -12,6 +12,7 @@
#include "base/basictypes.h"
#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
+#include "net/base/host_port_pair.h"
namespace net {
@@ -19,23 +20,6 @@ class ClientSocketHandle;
class HttpNetworkSession;
class SpdySession;
-// TODO(willchan): Move this to net/base.
-struct HostPortPair {
- HostPortPair() {}
- HostPortPair(const std::string& in_host, uint16 in_port)
- : host(in_host), port(in_port) {}
-
- // Comparator function so this can be placed in a std::map.
- bool operator<(const HostPortPair& other) const {
- if (host != other.host)
- return host < other.host;
- return port < other.port;
- }
-
- std::string host;
- uint16 port;
-};
-
// This is a very simple pool for open SpdySessions.
// TODO(mbelshe): Make this production ready.
class SpdySessionPool : public base::RefCounted<SpdySessionPool> {