summaryrefslogtreecommitdiffstats
path: root/net/http
diff options
context:
space:
mode:
authorrch@chromium.org <rch@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-09-01 20:55:17 +0000
committerrch@chromium.org <rch@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-09-01 20:55:17 +0000
commit7642b5aed675a2b99007a833d58b705b493b5ef4 (patch)
treeee9b7ce6cb84cc495eb26ac5ece10b89a7ff038a /net/http
parentf30394e222a0df68576c8564ecb4e1a8b4bf0d20 (diff)
downloadchromium_src-7642b5aed675a2b99007a833d58b705b493b5ef4.zip
chromium_src-7642b5aed675a2b99007a833d58b705b493b5ef4.tar.gz
chromium_src-7642b5aed675a2b99007a833d58b705b493b5ef4.tar.bz2
Add support for speaking SPDY to an HTTPS proxy.
Currently only http urls are supported. BUG=29625 TEST=HttpNetworkTransactionTest.HttpsProxySpdyGet Review URL: http://codereview.chromium.org/3259006 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@58236 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/http')
-rw-r--r--net/http/http_network_transaction_unittest.cc59
-rw-r--r--net/http/http_proxy_client_socket.cc11
-rw-r--r--net/http/http_proxy_client_socket.h9
-rw-r--r--net/http/http_proxy_client_socket_pool.cc11
-rw-r--r--net/http/http_proxy_client_socket_pool.h1
-rw-r--r--net/http/http_stream_request.cc43
6 files changed, 124 insertions, 10 deletions
diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc
index 5d21eba..d0ed59b 100644
--- a/net/http/http_network_transaction_unittest.cc
+++ b/net/http/http_network_transaction_unittest.cc
@@ -1722,6 +1722,65 @@ TEST_F(HttpNetworkTransactionTest, HttpsProxyGet) {
EXPECT_TRUE(response->auth_challenge.get() == NULL);
}
+// Test a SPDY get through an HTTPS Proxy.
+TEST_F(HttpNetworkTransactionTest, HttpsProxySpdyGet) {
+ // Configure against https proxy server "proxy:70".
+ SessionDependencies session_deps(CreateFixedProxyService("https://proxy:70"));
+ CapturingBoundNetLog log(CapturingNetLog::kUnbounded);
+ session_deps.net_log = log.bound().net_log();
+ scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
+
+ scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
+
+ HttpRequestInfo request;
+ request.method = "GET";
+ request.url = GURL("http://www.google.com/");
+ request.load_flags = 0;
+
+ // fetch http://www.google.com/ via SPDY
+ scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST,
+ false));
+ MockWrite spdy_writes[] = { CreateMockWrite(*req) };
+
+ scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
+ scoped_ptr<spdy::SpdyFrame> data(ConstructSpdyBodyFrame(1, true));
+ MockRead spdy_reads[] = {
+ CreateMockRead(*resp),
+ CreateMockRead(*data),
+ MockRead(true, 0, 0),
+ };
+
+ scoped_refptr<DelayedSocketData> spdy_data(
+ new DelayedSocketData(
+ 1, // wait for one write to finish before reading.
+ spdy_reads, arraysize(spdy_reads),
+ spdy_writes, arraysize(spdy_writes)));
+ session_deps.socket_factory.AddSocketDataProvider(spdy_data);
+
+ 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);
+
+ TestCompletionCallback callback1;
+
+ int rv = trans->Start(&request, &callback1, log.bound());
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ rv = callback1.WaitForResult();
+ EXPECT_EQ(OK, rv);
+
+ 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(net::kUploadData, response_data);
+}
+
// Test the challenge-response-retry sequence through an HTTPS Proxy
TEST_F(HttpNetworkTransactionTest, HttpsProxyAuthRetry) {
// Configure against https proxy server "proxy:70".
diff --git a/net/http/http_proxy_client_socket.cc b/net/http/http_proxy_client_socket.cc
index 7ed80a5..eccd652 100644
--- a/net/http/http_proxy_client_socket.cc
+++ b/net/http/http_proxy_client_socket.cc
@@ -53,7 +53,8 @@ HttpProxyClientSocket::HttpProxyClientSocket(
ClientSocketHandle* transport_socket, const GURL& request_url,
const std::string& user_agent, const HostPortPair& endpoint,
const HostPortPair& proxy_server,
- const scoped_refptr<HttpNetworkSession>& session, bool tunnel)
+ const scoped_refptr<HttpNetworkSession>& session, bool tunnel,
+ bool using_spdy)
: ALLOW_THIS_IN_INITIALIZER_LIST(
io_callback_(this, &HttpProxyClientSocket::OnIOComplete)),
next_state_(STATE_NONE),
@@ -65,6 +66,7 @@ HttpProxyClientSocket::HttpProxyClientSocket(
GURL("http://" + proxy_server.ToString()),
session) : NULL),
tunnel_(tunnel),
+ using_spdy_(using_spdy),
net_log_(transport_socket->socket()->NetLog()) {
// Synthesize the bits of a request that we actually use.
request_.url = request_url;
@@ -83,7 +85,12 @@ int HttpProxyClientSocket::Connect(CompletionCallback* callback) {
DCHECK(transport_->socket());
DCHECK(!user_callback_);
- if (!tunnel_)
+ // TODO(rch): figure out the right way to set up a tunnel with SPDY.
+ // This approach sends the complete HTTPS request to the proxy
+ // which allows the proxy to see "private" data. Instead, we should
+ // create an SSL tunnel to the origin server using the CONNECT method
+ // inside a single SPDY stream.
+ if (using_spdy_ || !tunnel_)
next_state_ = STATE_DONE;
if (next_state_ == STATE_DONE)
return OK;
diff --git a/net/http/http_proxy_client_socket.h b/net/http/http_proxy_client_socket.h
index 488fbdc..adfcc11 100644
--- a/net/http/http_proxy_client_socket.h
+++ b/net/http/http_proxy_client_socket.h
@@ -39,7 +39,8 @@ class HttpProxyClientSocket : public ClientSocket {
const HostPortPair& endpoint,
const HostPortPair& proxy_server,
const scoped_refptr<HttpNetworkSession>& session,
- bool tunnel);
+ bool tunnel,
+ bool using_spdy);
// On destruction Disconnect() is called.
virtual ~HttpProxyClientSocket();
@@ -57,6 +58,10 @@ class HttpProxyClientSocket : public ClientSocket {
return auth_;
}
+ bool using_spdy() {
+ return using_spdy_;
+ }
+
// ClientSocket methods:
// Authenticates to the Http Proxy and then passes data freely.
@@ -140,6 +145,8 @@ class HttpProxyClientSocket : public ClientSocket {
const HostPortPair endpoint_;
scoped_refptr<HttpAuthController> auth_;
const bool tunnel_;
+ // If true, then the connection to the proxy is a SPDY connection.
+ const bool using_spdy_;
std::string request_headers_;
diff --git a/net/http/http_proxy_client_socket_pool.cc b/net/http/http_proxy_client_socket_pool.cc
index 34bc0bb..f11ad30 100644
--- a/net/http/http_proxy_client_socket_pool.cc
+++ b/net/http/http_proxy_client_socket_pool.cc
@@ -16,6 +16,7 @@
#include "net/socket/client_socket_handle.h"
#include "net/socket/client_socket_pool_base.h"
#include "net/socket/tcp_client_socket_pool.h"
+#include "net/socket/ssl_client_socket.h"
namespace net {
@@ -67,7 +68,8 @@ HttpProxyConnectJob::HttpProxyConnectJob(
ssl_pool_(ssl_pool),
resolver_(host_resolver),
ALLOW_THIS_IN_INITIALIZER_LIST(
- callback_(this, &HttpProxyConnectJob::OnIOComplete)) {
+ callback_(this, &HttpProxyConnectJob::OnIOComplete)),
+ using_spdy_(false) {
}
HttpProxyConnectJob::~HttpProxyConnectJob() {}
@@ -182,6 +184,10 @@ int HttpProxyConnectJob::DoSSLConnectComplete(int result) {
return result;
}
+ SSLClientSocket* ssl =
+ static_cast<SSLClientSocket*>(transport_socket_handle_->socket());
+ using_spdy_ = ssl->was_spdy_negotiated();
+
// Reset the timer to just the length of time allowed for HttpProxy handshake
// so that a fast SSL connection plus a slow HttpProxy failure doesn't take
// longer to timeout than it should.
@@ -204,7 +210,8 @@ int HttpProxyConnectJob::DoHttpProxyConnect() {
params_->user_agent(),
params_->endpoint(),
proxy_server, params_->session(),
- params_->tunnel()));
+ params_->tunnel(),
+ using_spdy_));
int result = transport_socket_->Connect(&callback_);
// Clear the circular reference to HttpNetworkSession (|params_| reference
diff --git a/net/http/http_proxy_client_socket_pool.h b/net/http/http_proxy_client_socket_pool.h
index 8a16e22..20c0f26 100644
--- a/net/http/http_proxy_client_socket_pool.h
+++ b/net/http/http_proxy_client_socket_pool.h
@@ -132,6 +132,7 @@ class HttpProxyConnectJob : public ConnectJob {
CompletionCallbackImpl<HttpProxyConnectJob> callback_;
scoped_ptr<ClientSocketHandle> transport_socket_handle_;
scoped_ptr<ClientSocket> transport_socket_;
+ bool using_spdy_;
DISALLOW_COPY_AND_ASSIGN(HttpProxyConnectJob);
};
diff --git a/net/http/http_stream_request.cc b/net/http/http_stream_request.cc
index 6a53a72..4d6895c 100644
--- a/net/http/http_stream_request.cc
+++ b/net/http/http_stream_request.cc
@@ -427,6 +427,17 @@ int HttpStreamRequest::DoInitConnection() {
next_state_ = STATE_CREATE_STREAM;
return OK;
}
+ // Check next if we have a spdy session for this proxy. If so, then go
+ // straight to using that.
+ if (proxy_info()->is_https()) {
+ HostPortProxyPair proxy(proxy_info()->proxy_server().host_port_pair(),
+ proxy_info()->proxy_server());
+ if (session_->spdy_session_pool()->HasSession(proxy)) {
+ using_spdy_ = true;
+ next_state_ = STATE_CREATE_STREAM;
+ return OK;
+ }
+ }
// Build the string used to uniquely identify connections of this type.
// Determine the host and port to connect to.
@@ -569,6 +580,14 @@ int HttpStreamRequest::DoInitConnectionComplete(int result) {
}
if (force_spdy_over_ssl_ && force_spdy_always_)
using_spdy_ = true;
+ } else if (proxy_info()->is_https() && connection_->socket() &&
+ result == OK) {
+ HttpProxyClientSocket* proxy_socket =
+ static_cast<HttpProxyClientSocket*>(connection_->socket());
+ if (proxy_socket->using_spdy()) {
+ was_npn_negotiated_ = true;
+ using_spdy_ = true;
+ }
}
// We may be using spdy without SSL
@@ -654,15 +673,29 @@ int HttpStreamRequest::DoCreateStream() {
CHECK(!stream_.get());
+ bool direct = true;
const scoped_refptr<SpdySessionPool> spdy_pool =
session_->spdy_session_pool();
scoped_refptr<SpdySession> spdy_session;
- HostPortProxyPair pair(endpoint_, proxy_info()->proxy_server());
- if (session_->spdy_session_pool()->HasSession(pair)) {
+ const ProxyServer& proxy_server = proxy_info()->proxy_server();
+ HostPortProxyPair pair(endpoint_, 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.
spdy_session =
- session_->spdy_session_pool()->Get(pair, session_, net_log_);
- } else {
+ spdy_pool->Get(pair, session_, net_log_);
+ } else if (proxy_info()->is_https()) {
+ // If we don't have a direct SPDY session, and we're using an HTTPS
+ // proxy, then we might have a SPDY session to the proxy
+ pair = HostPortProxyPair(proxy_server.host_port_pair(), proxy_server);
+ if (spdy_pool->HasSession(pair)) {
+ spdy_session = spdy_pool->Get(pair, session_, net_log_);
+ }
+ direct = false;
+ }
+
+ if (!spdy_session.get()) {
// SPDY can be negotiated using the TLS next protocol negotiation (NPN)
// extension, or just directly using SSL. Either way, |connection_| must
// contain an SSLClientSocket.
@@ -677,7 +710,7 @@ int HttpStreamRequest::DoCreateStream() {
if (spdy_session->IsClosed())
return ERR_CONNECTION_CLOSED;
- SpdyHttpStream* stream = new SpdyHttpStream(spdy_session);
+ SpdyHttpStream* stream = new SpdyHttpStream(spdy_session, direct);
stream_.reset(new HttpStreamHandle(NULL, stream));
return OK;
}