diff options
author | rch@chromium.org <rch@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-10-13 22:37:16 +0000 |
---|---|---|
committer | rch@chromium.org <rch@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-10-13 22:37:16 +0000 |
commit | d9da5fe263e748c75d85816ee6bae46b2b9de9c9 (patch) | |
tree | f6dbf611550dc1118fcff2cfe9429ca721a5c1bf /net/http | |
parent | a691b8874c225cf530396661264a77159db38780 (diff) | |
download | chromium_src-d9da5fe263e748c75d85816ee6bae46b2b9de9c9.zip chromium_src-d9da5fe263e748c75d85816ee6bae46b2b9de9c9.tar.gz chromium_src-d9da5fe263e748c75d85816ee6bae46b2b9de9c9.tar.bz2 |
Integrate the SpdyProxyClientSocket into the HttpStreamRequest
to support fetching HTTPS URLS over a SPDY Proxy.
BUG=29625
TEST=HttpNetworkTransactionTest.HttpsProxySpdyConnect
Review URL: http://codereview.chromium.org/3417010
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@62468 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/http')
-rw-r--r-- | net/http/http_network_transaction_unittest.cc | 212 | ||||
-rw-r--r-- | net/http/http_proxy_client_socket_pool.cc | 114 | ||||
-rw-r--r-- | net/http/http_proxy_client_socket_pool.h | 21 | ||||
-rw-r--r-- | net/http/http_proxy_client_socket_pool_unittest.cc | 416 | ||||
-rw-r--r-- | net/http/http_stream_request.cc | 18 | ||||
-rw-r--r-- | net/http/http_stream_request.h | 2 |
6 files changed, 633 insertions, 150 deletions
diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc index 508cc28..e37eea6 100644 --- a/net/http/http_network_transaction_unittest.cc +++ b/net/http/http_network_transaction_unittest.cc @@ -1829,6 +1829,218 @@ TEST_F(HttpNetworkTransactionTest, HttpsProxySpdyGet) { EXPECT_EQ(net::kUploadData, response_data); } +// Test a SPDY CONNECT through an HTTPS Proxy to an HTTPS (non-SPDY) Server. +TEST_F(HttpNetworkTransactionTest, HttpsProxySpdyConnectHttps) { + // 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("https://www.google.com/"); + request.load_flags = 0; + + // CONNECT to www.google.com:443 via SPDY + scoped_ptr<spdy::SpdyFrame> connect(ConstructSpdyConnect(NULL, 0, 1)); + // fetch https://www.google.com/ via HTTP + + const char get[] = "GET / HTTP/1.1\r\n" + "Host: www.google.com\r\n" + "Connection: keep-alive\r\n\r\n"; + scoped_ptr<spdy::SpdyFrame> wrapped_get( + ConstructSpdyBodyFrame(1, get, strlen(get), false)); + MockWrite spdy_writes[] = { + CreateMockWrite(*connect, 1), + CreateMockWrite(*wrapped_get, 3) + }; + + scoped_ptr<spdy::SpdyFrame> conn_resp(ConstructSpdyGetSynReply(NULL, 0, 1)); + const char resp[] = "HTTP/1.1 200 OK\r\n" + "Content-Length: 10\r\n\r\n"; + + scoped_ptr<spdy::SpdyFrame> wrapped_get_resp( + ConstructSpdyBodyFrame(1, resp, strlen(resp), false)); + scoped_ptr<spdy::SpdyFrame> wrapped_body( + ConstructSpdyBodyFrame(1, "1234567890", 10, false)); + MockRead spdy_reads[] = { + CreateMockRead(*conn_resp, 2, true), + CreateMockRead(*wrapped_get_resp, 4, true), + CreateMockRead(*wrapped_body, 5, true), + CreateMockRead(*wrapped_body, 6, true), + MockRead(true, 0, 7), + }; + + scoped_refptr<OrderedSocketData> spdy_data( + new OrderedSocketData( + 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); + SSLSocketDataProvider ssl2(true, OK); + ssl2.was_npn_negotiated = false; + session_deps.socket_factory.AddSSLSocketDataProvider(&ssl2); + + 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("1234567890", response_data); +} + +// Test a SPDY CONNECT through an HTTPS Proxy to a SPDY server. +TEST_F(HttpNetworkTransactionTest, HttpsProxySpdyConnectSpdy) { + // 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("https://www.google.com/"); + request.load_flags = 0; + + // CONNECT to www.google.com:443 via SPDY + scoped_ptr<spdy::SpdyFrame> connect(ConstructSpdyConnect(NULL, 0, 1)); + // fetch https://www.google.com/ via SPDY + const char* const kMyUrl = "https://www.google.com/"; + scoped_ptr<spdy::SpdyFrame> get(ConstructSpdyGet(kMyUrl, false, 1, LOWEST)); + scoped_ptr<spdy::SpdyFrame> wrapped_get(ConstructWrappedSpdyFrame(get, 1)); + MockWrite spdy_writes[] = { + CreateMockWrite(*connect, 1), + CreateMockWrite(*wrapped_get, 3) + }; + + scoped_ptr<spdy::SpdyFrame> conn_resp(ConstructSpdyGetSynReply(NULL, 0, 1)); + scoped_ptr<spdy::SpdyFrame> get_resp(ConstructSpdyGetSynReply(NULL, 0, 1)); + scoped_ptr<spdy::SpdyFrame> wrapped_get_resp( + ConstructWrappedSpdyFrame(get_resp, 1)); + scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true)); + scoped_ptr<spdy::SpdyFrame> wrapped_body(ConstructWrappedSpdyFrame(body, 1)); + MockRead spdy_reads[] = { + CreateMockRead(*conn_resp, 2, true), + CreateMockRead(*wrapped_get_resp, 4, true), + CreateMockRead(*wrapped_body, 5, true), + MockRead(true, 0, 1), + }; + + scoped_refptr<OrderedSocketData> spdy_data( + new OrderedSocketData( + 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); + SSLSocketDataProvider ssl2(true, OK); + ssl2.next_proto_status = SSLClientSocket::kNextProtoNegotiated; + ssl2.next_proto = "spdy/2"; + ssl2.was_npn_negotiated = true; + session_deps.socket_factory.AddSSLSocketDataProvider(&ssl2); + + 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 a SPDY CONNECT failure through an HTTPS Proxy. +TEST_F(HttpNetworkTransactionTest, HttpsProxySpdyConnectFailure) { + // 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("https://www.google.com/"); + request.load_flags = 0; + + // CONNECT to www.google.com:443 via SPDY + scoped_ptr<spdy::SpdyFrame> connect(ConstructSpdyConnect(NULL, 0, 1)); + scoped_ptr<spdy::SpdyFrame> get(ConstructSpdyRstStream(1, spdy::CANCEL)); + + MockWrite spdy_writes[] = { + CreateMockWrite(*connect, 1), + CreateMockWrite(*get, 3), + }; + + scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdySynReplyError(1)); + scoped_ptr<spdy::SpdyFrame> data(ConstructSpdyBodyFrame(1, true)); + MockRead spdy_reads[] = { + CreateMockRead(*resp, 2, true), + MockRead(true, 0, 4), + }; + + scoped_refptr<OrderedSocketData> spdy_data( + new OrderedSocketData( + 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); + SSLSocketDataProvider ssl2(true, OK); + ssl2.next_proto_status = SSLClientSocket::kNextProtoNegotiated; + ssl2.next_proto = "spdy/2"; + ssl2.was_npn_negotiated = true; + session_deps.socket_factory.AddSSLSocketDataProvider(&ssl2); + + TestCompletionCallback callback1; + + int rv = trans->Start(&request, &callback1, log.bound()); + EXPECT_EQ(ERR_IO_PENDING, rv); + + rv = callback1.WaitForResult(); + EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, rv); + + const HttpResponseInfo* response = trans->GetResponseInfo(); + ASSERT_TRUE(response == NULL); +} + // 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_pool.cc b/net/http/http_proxy_client_socket_pool.cc index 4a5495b..a5bbb53 100644 --- a/net/http/http_proxy_client_socket_pool.cc +++ b/net/http/http_proxy_client_socket_pool.cc @@ -19,6 +19,11 @@ #include "net/socket/ssl_client_socket.h" #include "net/socket/ssl_client_socket_pool.h" #include "net/socket/tcp_client_socket_pool.h" +#include "net/spdy/spdy_proxy_client_socket.h" +#include "net/spdy/spdy_session.h" +#include "net/spdy/spdy_session_pool.h" +#include "net/spdy/spdy_settings_storage.h" +#include "net/spdy/spdy_stream.h" namespace net { @@ -30,9 +35,13 @@ HttpProxySocketParams::HttpProxySocketParams( HostPortPair endpoint, HttpAuthCache* http_auth_cache, HttpAuthHandlerFactory* http_auth_handler_factory, + SpdySessionPool* spdy_session_pool, + SpdySettingsStorage* spdy_settings, bool tunnel) : tcp_params_(tcp_params), ssl_params_(ssl_params), + spdy_session_pool_(spdy_session_pool), + spdy_settings_(spdy_settings), request_url_(request_url), user_agent_(user_agent), endpoint_(endpoint), @@ -87,6 +96,8 @@ LoadState HttpProxyConnectJob::GetLoadState() const { return transport_socket_handle_->GetLoadState(); case STATE_HTTP_PROXY_CONNECT: case STATE_HTTP_PROXY_CONNECT_COMPLETE: + case STATE_SPDY_PROXY_CREATE_STREAM: + case STATE_SPDY_PROXY_CREATE_STREAM_COMPLETE: return LOAD_STATE_ESTABLISHING_PROXY_TUNNEL; default: NOTREACHED(); @@ -137,6 +148,13 @@ int HttpProxyConnectJob::DoLoop(int result) { case STATE_HTTP_PROXY_CONNECT_COMPLETE: rv = DoHttpProxyConnectComplete(rv); break; + case STATE_SPDY_PROXY_CREATE_STREAM: + DCHECK_EQ(OK, rv); + rv = DoSpdyProxyCreateStream(); + break; + case STATE_SPDY_PROXY_CREATE_STREAM_COMPLETE: + rv = DoSpdyProxyCreateStreamComplete(rv); + break; default: NOTREACHED() << "bad state"; rv = ERR_FAILED; @@ -165,11 +183,21 @@ int HttpProxyConnectJob::DoTCPConnectComplete(int result) { // longer to timeout than it should. ResetTimer(base::TimeDelta::FromSeconds( kHttpProxyConnectJobTimeoutInSeconds)); + next_state_ = STATE_HTTP_PROXY_CONNECT; return result; } int HttpProxyConnectJob::DoSSLConnect() { + if (params_->tunnel()) { + HostPortProxyPair pair(params_->destination().host_port_pair(), + ProxyServer::Direct()); + if (params_->spdy_session_pool()->HasSession(pair)) { + using_spdy_ = true; + next_state_ = STATE_SPDY_PROXY_CREATE_STREAM; + return OK; + } + } next_state_ = STATE_SSL_CONNECT_COMPLETE; transport_socket_handle_.reset(new ClientSocketHandle()); return transport_socket_handle_->Init( @@ -179,15 +207,21 @@ int HttpProxyConnectJob::DoSSLConnect() { } int HttpProxyConnectJob::DoSSLConnectComplete(int result) { - if (IsCertificateError(result) && - params_->ssl_params()->load_flags() & LOAD_IGNORE_ALL_CERT_ERRORS) - result = OK; + // TODO(rch): enable support for client auth to the proxy + if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) + return ERR_PROXY_AUTH_UNSUPPORTED; + if (IsCertificateError(result)) { + if (params_->ssl_params()->load_flags() & LOAD_IGNORE_ALL_CERT_ERRORS) + result = OK; + else + // TODO(rch): allow the user to deal with proxy cert errors in the + // same way as server cert errors. + return ERR_PROXY_CERTIFICATE_INVALID; + } if (result < 0) { - // TODO(eroman): return ERR_PROXY_CONNECTION_FAILED if failed with the - // TCP connection. if (transport_socket_handle_->socket()) transport_socket_handle_->socket()->Disconnect(); - return result; + return ERR_PROXY_CONNECTION_FAILED; } SSLClientSocket* ssl = @@ -199,10 +233,67 @@ int HttpProxyConnectJob::DoSSLConnectComplete(int result) { // longer to timeout than it should. ResetTimer(base::TimeDelta::FromSeconds( kHttpProxyConnectJobTimeoutInSeconds)); - next_state_ = STATE_HTTP_PROXY_CONNECT; + // TODO(rch): If we ever decide to implement a "trusted" SPDY proxy + // (one that we speak SPDY over SSL to, but to which we send HTTPS + // request directly instead of through CONNECT tunnels, then we + // need to add a predicate to this if statement so we fall through + // to the else case. (HttpProxyClientSocket currently acts as + // a "trusted" SPDY proxy). + if (using_spdy_ && params_->tunnel()) + next_state_ = STATE_SPDY_PROXY_CREATE_STREAM; + else + next_state_ = STATE_HTTP_PROXY_CONNECT; return result; } +int HttpProxyConnectJob::DoSpdyProxyCreateStream() { + DCHECK(using_spdy_); + DCHECK(params_->tunnel()); + + HostPortProxyPair pair(params_->destination().host_port_pair(), + ProxyServer::Direct()); + SpdySessionPool* spdy_pool = params_->spdy_session_pool(); + scoped_refptr<SpdySession> spdy_session; + // It's possible that a session to the proxy has recently been created + if (spdy_pool->HasSession(pair)) { + if (transport_socket_handle_->socket()) + transport_socket_handle_->socket()->Disconnect(); + transport_socket_handle_->Reset(); + spdy_session = spdy_pool->Get(pair, params_->spdy_settings(), net_log()); + } else { + // Create a session direct to the proxy itself + int rv = spdy_pool->GetSpdySessionFromSocket( + pair, params_->spdy_settings(), transport_socket_handle_.release(), + net_log(), OK, &spdy_session, /*using_ssl_*/ true); + if (rv < 0) { + if (transport_socket_handle_->socket()) + transport_socket_handle_->socket()->Disconnect(); + return rv; + } + } + + next_state_ = STATE_SPDY_PROXY_CREATE_STREAM_COMPLETE; + return spdy_session->CreateStream(params_->request_url(), + params_->destination().priority(), + &spdy_stream_, net_log(), &callback_); +} + +int HttpProxyConnectJob::DoSpdyProxyCreateStreamComplete(int result) { + if (result < 0) + return result; + + next_state_ = STATE_HTTP_PROXY_CONNECT_COMPLETE; + transport_socket_.reset( + new SpdyProxyClientSocket(spdy_stream_, + params_->user_agent(), + params_->endpoint(), + params_->request_url(), + params_->destination().host_port_pair(), + params_->http_auth_cache(), + params_->http_auth_handler_factory())); + return transport_socket_->Connect(&callback_); +} + int HttpProxyConnectJob::DoHttpProxyConnect() { next_state_ = STATE_HTTP_PROXY_CONNECT_COMPLETE; const HostResolver::RequestInfo& tcp_destination = params_->destination(); @@ -219,14 +310,7 @@ int HttpProxyConnectJob::DoHttpProxyConnect() { params_->http_auth_handler_factory(), params_->tunnel(), using_spdy_)); - int result = transport_socket_->Connect(&callback_); - - // Clear the circular reference to HttpNetworkSession (|params_| reference - // HttpNetworkSession, which reference HttpProxyClientSocketPool, which - // references |this|) here because it is safe to do so now but not at other - // points. This may cancel this ConnectJob. - params_ = NULL; - return result; + return transport_socket_->Connect(&callback_); } int HttpProxyConnectJob::DoHttpProxyConnectComplete(int result) { diff --git a/net/http/http_proxy_client_socket_pool.h b/net/http/http_proxy_client_socket_pool.h index f95a054..a08a573 100644 --- a/net/http/http_proxy_client_socket_pool.h +++ b/net/http/http_proxy_client_socket_pool.h @@ -25,6 +25,9 @@ class HttpAuthCache; class HttpAuthHandlerFactory; class SSLClientSocketPool; class SSLSocketParams; +class SpdySessionPool; +class SpdySettingsStorage; +class SpdyStream; class TCPClientSocketPool; class TCPSocketParams; @@ -41,6 +44,8 @@ class HttpProxySocketParams : public base::RefCounted<HttpProxySocketParams> { HostPortPair endpoint, HttpAuthCache* http_auth_cache, HttpAuthHandlerFactory* http_auth_handler_factory, + SpdySessionPool* spdy_session_pool, + SpdySettingsStorage* spdy_settings, bool tunnel); const scoped_refptr<TCPSocketParams>& tcp_params() const { @@ -56,6 +61,12 @@ class HttpProxySocketParams : public base::RefCounted<HttpProxySocketParams> { HttpAuthHandlerFactory* http_auth_handler_factory() const { return http_auth_handler_factory_; } + SpdySessionPool* spdy_session_pool() { + return spdy_session_pool_; + } + SpdySettingsStorage* spdy_settings() { + return spdy_settings_; + } const HostResolver::RequestInfo& destination() const; bool tunnel() const { return tunnel_; } @@ -65,6 +76,8 @@ class HttpProxySocketParams : public base::RefCounted<HttpProxySocketParams> { const scoped_refptr<TCPSocketParams> tcp_params_; const scoped_refptr<SSLSocketParams> ssl_params_; + SpdySessionPool* spdy_session_pool_; + SpdySettingsStorage* spdy_settings_; const GURL request_url_; const std::string user_agent_; const HostPortPair endpoint_; @@ -100,6 +113,9 @@ class HttpProxyConnectJob : public ConnectJob { STATE_SSL_CONNECT_COMPLETE, STATE_HTTP_PROXY_CONNECT, STATE_HTTP_PROXY_CONNECT_COMPLETE, + STATE_SPDY_PROXY_CREATE_STREAM, + STATE_SPDY_PROXY_CREATE_STREAM_COMPLETE, + STATE_SPDY_PROXY_CONNECT_COMPLETE, STATE_NONE, }; @@ -127,6 +143,9 @@ class HttpProxyConnectJob : public ConnectJob { int DoHttpProxyConnect(); int DoHttpProxyConnectComplete(int result); + int DoSpdyProxyCreateStream(); + int DoSpdyProxyCreateStreamComplete(int result); + scoped_refptr<HttpProxySocketParams> params_; TCPClientSocketPool* const tcp_pool_; SSLClientSocketPool* const ssl_pool_; @@ -138,6 +157,8 @@ class HttpProxyConnectJob : public ConnectJob { scoped_ptr<ClientSocket> transport_socket_; bool using_spdy_; + scoped_refptr<SpdyStream> spdy_stream_; + DISALLOW_COPY_AND_ASSIGN(HttpProxyConnectJob); }; diff --git a/net/http/http_proxy_client_socket_pool_unittest.cc b/net/http/http_proxy_client_socket_pool_unittest.cc index 4fe8873..71485e9 100644 --- a/net/http/http_proxy_client_socket_pool_unittest.cc +++ b/net/http/http_proxy_client_socket_pool_unittest.cc @@ -19,7 +19,9 @@ #include "net/socket/client_socket_handle.h" #include "net/socket/client_socket_pool_histograms.h" #include "net/socket/socket_test_util.h" +#include "net/spdy/spdy_protocol.h" #include "net/spdy/spdy_session_pool.h" +#include "net/spdy/spdy_test_util.h" #include "testing/gtest/include/gtest/gtest.h" namespace net { @@ -28,34 +30,48 @@ namespace { const int kMaxSockets = 32; const int kMaxSocketsPerGroup = 6; +const char * const kAuthHeaders[] = { + "proxy-authorization", "Basic Zm9vOmJhcg==" +}; +const int kAuthHeadersSize = arraysize(kAuthHeaders) / 2; enum HttpProxyType { HTTP, - HTTPS + HTTPS, + SPDY }; typedef ::testing::TestWithParam<HttpProxyType> TestWithHttpParam; +} // namespace + class HttpProxyClientSocketPoolTest : public TestWithHttpParam { protected: HttpProxyClientSocketPoolTest() : ssl_config_(), ignored_tcp_socket_params_(new TCPSocketParams( - HostPortPair("proxy", 80), MEDIUM, GURL(), false)), + HostPortPair("proxy", 80), LOWEST, GURL(), false)), ignored_ssl_socket_params_(new SSLSocketParams( ignored_tcp_socket_params_, NULL, NULL, ProxyServer::SCHEME_DIRECT, - "host", ssl_config_, 0, false, false)), + "www.google.com", ssl_config_, 0, false, false)), tcp_histograms_("MockTCP"), tcp_socket_pool_( kMaxSockets, kMaxSocketsPerGroup, &tcp_histograms_, - &tcp_client_socket_factory_), + &socket_factory_), ssl_histograms_("MockSSL"), + ssl_config_service_(new SSLConfigServiceDefaults), + host_resolver_(new MockHostResolver), ssl_socket_pool_(kMaxSockets, kMaxSocketsPerGroup, &ssl_histograms_, - &tcp_client_socket_factory_, - &tcp_socket_pool_), - host_resolver_(new MockHostResolver), + host_resolver_.get(), + NULL /* dnsrr_resolver */, + &socket_factory_, + &tcp_socket_pool_, + NULL, + NULL, + ssl_config_service_.get(), + BoundNetLog().net_log()), http_auth_handler_factory_( HttpAuthHandlerFactory::CreateDefault(host_resolver_.get())), session_(new HttpNetworkSession(host_resolver_.get(), @@ -68,6 +84,8 @@ class HttpProxyClientSocketPoolTest : public TestWithHttpParam { NULL, NULL)), http_proxy_histograms_("HttpProxyUnitTest"), + ssl_data_(NULL), + data_(NULL), pool_(kMaxSockets, kMaxSocketsPerGroup, &http_proxy_histograms_, NULL, @@ -87,7 +105,7 @@ class HttpProxyClientSocketPoolTest : public TestWithHttpParam { } scoped_refptr<TCPSocketParams> GetTcpParams() { - if (GetParam() == HTTPS) + if (GetParam() != HTTP) return scoped_refptr<TCPSocketParams>(); return ignored_tcp_socket_params_; } @@ -105,11 +123,13 @@ class HttpProxyClientSocketPoolTest : public TestWithHttpParam { new HttpProxySocketParams( GetTcpParams(), GetSslParams(), - GURL("http://host/"), + GURL(tunnel ? "https://www.google.com/" : "http://www.google.com"), "", - HostPortPair("host", 80), + HostPortPair("www.google.com", tunnel ? 443 : 80), session_->auth_cache(), session_->http_auth_handler_factory(), + session_->spdy_session_pool(), + session_->mutable_spdy_settings(), tunnel)); } @@ -121,227 +141,363 @@ class HttpProxyClientSocketPoolTest : public TestWithHttpParam { return GetParams(false); } + DeterministicMockClientSocketFactory& socket_factory() { + return socket_factory_; + } + + void Initialize(bool async, MockRead* reads, size_t reads_count, + MockWrite* writes, size_t writes_count, + MockRead* spdy_reads, size_t spdy_reads_count, + MockWrite* spdy_writes, size_t spdy_writes_count) { + if (GetParam() == SPDY) + data_ = new DeterministicSocketData(spdy_reads, spdy_reads_count, + spdy_writes, spdy_writes_count); + else + data_ = new DeterministicSocketData(reads, reads_count, writes, + writes_count); + + data_->set_connect_data(MockConnect(async, 0)); + data_->StopAfter(2); // Request / Response + + socket_factory_.AddSocketDataProvider(data_.get()); + + if (GetParam() != HTTP) { + ssl_data_.reset(new SSLSocketDataProvider(async, OK)); + if (GetParam() == SPDY) { + InitializeSpdySsl(); + } + socket_factory_.AddSSLSocketDataProvider(ssl_data_.get()); + } + } + + void InitializeSpdySsl() { + spdy::SpdyFramer::set_enable_compression_default(false); + ssl_data_->next_proto_status = SSLClientSocket::kNextProtoNegotiated; + ssl_data_->next_proto = "spdy/2"; + ssl_data_->was_npn_negotiated = true; + } + + private: SSLConfig ssl_config_; scoped_refptr<TCPSocketParams> ignored_tcp_socket_params_; scoped_refptr<SSLSocketParams> ignored_ssl_socket_params_; ClientSocketPoolHistograms tcp_histograms_; - MockClientSocketFactory tcp_client_socket_factory_; + DeterministicMockClientSocketFactory socket_factory_; MockTCPClientSocketPool tcp_socket_pool_; ClientSocketPoolHistograms ssl_histograms_; - MockSSLClientSocketPool ssl_socket_pool_; - - MockClientSocketFactory socket_factory_; + scoped_refptr<SSLConfigService> ssl_config_service_; scoped_ptr<HostResolver> host_resolver_; + SSLClientSocketPool ssl_socket_pool_; + scoped_ptr<HttpAuthHandlerFactory> http_auth_handler_factory_; scoped_refptr<HttpNetworkSession> session_; ClientSocketPoolHistograms http_proxy_histograms_; + + protected: + scoped_ptr<SSLSocketDataProvider> ssl_data_; + scoped_refptr<DeterministicSocketData> data_; HttpProxyClientSocketPool pool_; + ClientSocketHandle handle_; + TestCompletionCallback callback_; }; //----------------------------------------------------------------------------- -// All tests are run with three different connection types: SPDY after NPN -// negotiation, SPDY without SSL, and SPDY with SSL. +// All tests are run with three different proxy types: HTTP, HTTPS (non-SPDY) +// and SPDY. INSTANTIATE_TEST_CASE_P(HttpProxyClientSocketPoolTests, HttpProxyClientSocketPoolTest, - ::testing::Values(HTTP, HTTPS)); + ::testing::Values(HTTP, HTTPS, SPDY)); TEST_P(HttpProxyClientSocketPoolTest, NoTunnel) { - StaticSocketDataProvider data; - data.set_connect_data(MockConnect(false, 0)); - tcp_client_socket_factory_.AddSocketDataProvider(&data); + Initialize(false, NULL, 0, NULL, 0, NULL, 0, NULL, 0); - ClientSocketHandle handle; - int rv = handle.Init("a", GetNoTunnelParams(), LOW, NULL, &pool_, + int rv = handle_.Init("a", GetNoTunnelParams(), LOW, NULL, &pool_, BoundNetLog()); EXPECT_EQ(OK, rv); - EXPECT_TRUE(handle.is_initialized()); - EXPECT_TRUE(handle.socket()); + EXPECT_TRUE(handle_.is_initialized()); + ASSERT_TRUE(handle_.socket()); HttpProxyClientSocket* tunnel_socket = - static_cast<HttpProxyClientSocket*>(handle.socket()); + static_cast<HttpProxyClientSocket*>(handle_.socket()); EXPECT_TRUE(tunnel_socket->IsConnected()); } TEST_P(HttpProxyClientSocketPoolTest, NeedAuth) { MockWrite writes[] = { - MockWrite("CONNECT host:80 HTTP/1.1\r\n" - "Host: host\r\n" - "Proxy-Connection: keep-alive\r\n\r\n"), + MockWrite(true, 0, "CONNECT www.google.com:443 HTTP/1.1\r\n" + "Host: www.google.com\r\n" + "Proxy-Connection: keep-alive\r\n\r\n"), }; MockRead reads[] = { - // No credentials. - MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"), - MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), - MockRead("Content-Length: 10\r\n\r\n"), - MockRead("0123456789"), + // No credentials. + MockRead(true, 1, "HTTP/1.1 407 Proxy Authentication Required\r\n"), + MockRead(true, 2, "Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), + MockRead(true, 3, "Content-Length: 10\r\n\r\n"), + MockRead(true, 4, "0123456789"), + }; + scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyConnect(NULL, 0, 1)); + scoped_ptr<spdy::SpdyFrame> rst(ConstructSpdyRstStream(1, spdy::CANCEL)); + MockWrite spdy_writes[] = { + CreateMockWrite(*req, 0, true), + CreateMockWrite(*rst, 2, true), + }; + scoped_ptr<spdy::SpdyFrame> resp( + ConstructSpdySynReplyError("407 Proxy Authentication Required", 1)); + MockRead spdy_reads[] = { + CreateMockWrite(*resp, 1, true), + MockRead(true, 0, 3) }; - StaticSocketDataProvider data(reads, arraysize(reads), writes, - arraysize(writes)); - tcp_client_socket_factory_.AddSocketDataProvider(&data); + Initialize(false, reads, arraysize(reads), writes, arraysize(writes), + spdy_reads, arraysize(spdy_reads), spdy_writes, + arraysize(spdy_writes)); - ClientSocketHandle handle; - TestCompletionCallback callback; - int rv = handle.Init("a", GetTunnelParams(), LOW, &callback, &pool_, + data_->StopAfter(4); + int rv = handle_.Init("a", GetTunnelParams(), LOW, &callback_, &pool_, BoundNetLog()); EXPECT_EQ(ERR_IO_PENDING, rv); - EXPECT_FALSE(handle.is_initialized()); - EXPECT_FALSE(handle.socket()); - - EXPECT_EQ(ERR_PROXY_AUTH_REQUESTED, callback.WaitForResult()); - EXPECT_TRUE(handle.is_initialized()); - EXPECT_TRUE(handle.socket()); - HttpProxyClientSocket* tunnel_socket = - static_cast<HttpProxyClientSocket*>(handle.socket()); - EXPECT_FALSE(tunnel_socket->IsConnected()); + EXPECT_FALSE(handle_.is_initialized()); + EXPECT_FALSE(handle_.socket()); + + data_->RunFor(4); + rv = callback_.WaitForResult(); + if (GetParam() != SPDY) { + EXPECT_EQ(ERR_PROXY_AUTH_REQUESTED, rv); + EXPECT_TRUE(handle_.is_initialized()); + ASSERT_TRUE(handle_.socket()); + HttpProxyClientSocket* tunnel_socket = + static_cast<HttpProxyClientSocket*>(handle_.socket()); + EXPECT_FALSE(tunnel_socket->IsConnected()); + EXPECT_FALSE(tunnel_socket->using_spdy()); + } else { + // Proxy auth is not really implemented for SPDY yet + EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, rv); + EXPECT_FALSE(handle_.is_initialized()); + EXPECT_FALSE(handle_.socket()); + } } TEST_P(HttpProxyClientSocketPoolTest, HaveAuth) { + // It's pretty much impossible to make the SPDY case becave synchronously + // so we skip this test for SPDY + if (GetParam() == SPDY) + return; MockWrite writes[] = { - MockWrite(false, - "CONNECT host:80 HTTP/1.1\r\n" - "Host: host\r\n" - "Proxy-Connection: keep-alive\r\n" - "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), + MockWrite(false, 0, + "CONNECT www.google.com:443 HTTP/1.1\r\n" + "Host: www.google.com\r\n" + "Proxy-Connection: keep-alive\r\n" + "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), }; MockRead reads[] = { - MockRead(false, "HTTP/1.1 200 Connection Established\r\n\r\n"), + MockRead(false, 1, "HTTP/1.1 200 Connection Established\r\n\r\n"), }; - StaticSocketDataProvider data(reads, arraysize(reads), writes, - arraysize(writes)); - data.set_connect_data(MockConnect(false, 0)); - tcp_client_socket_factory_.AddSocketDataProvider(&data); + Initialize(false, reads, arraysize(reads), writes, arraysize(writes), NULL, 0, + NULL, 0); AddAuthToCache(); - ClientSocketHandle handle; - TestCompletionCallback callback; - int rv = handle.Init("a", GetTunnelParams(), LOW, &callback, &pool_, + int rv = handle_.Init("a", GetTunnelParams(), LOW, &callback_, &pool_, BoundNetLog()); EXPECT_EQ(OK, rv); - EXPECT_TRUE(handle.is_initialized()); - EXPECT_TRUE(handle.socket()); + EXPECT_TRUE(handle_.is_initialized()); + ASSERT_TRUE(handle_.socket()); HttpProxyClientSocket* tunnel_socket = - static_cast<HttpProxyClientSocket*>(handle.socket()); + static_cast<HttpProxyClientSocket*>(handle_.socket()); EXPECT_TRUE(tunnel_socket->IsConnected()); } TEST_P(HttpProxyClientSocketPoolTest, AsyncHaveAuth) { MockWrite writes[] = { - MockWrite("CONNECT host:80 HTTP/1.1\r\n" - "Host: host\r\n" - "Proxy-Connection: keep-alive\r\n" - "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), + MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" + "Host: www.google.com\r\n" + "Proxy-Connection: keep-alive\r\n" + "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), }; MockRead reads[] = { - MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"), + MockRead(false, "HTTP/1.1 200 Connection Established\r\n\r\n"), + }; + + scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyConnect(kAuthHeaders, + kAuthHeadersSize, 1)); + MockWrite spdy_writes[] = { + CreateMockWrite(*req, 0, true) + }; + scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); + MockRead spdy_reads[] = { + CreateMockRead(*resp, 1, true), + MockRead(true, 0, 2) }; - StaticSocketDataProvider data(reads, arraysize(reads), writes, - arraysize(writes)); - tcp_client_socket_factory_.AddSocketDataProvider(&data); + Initialize(false, reads, arraysize(reads), writes, arraysize(writes), + spdy_reads, arraysize(spdy_reads), spdy_writes, + arraysize(spdy_writes)); AddAuthToCache(); - ClientSocketHandle handle; - TestCompletionCallback callback; - int rv = handle.Init("a", GetTunnelParams(), LOW, &callback, &pool_, + int rv = handle_.Init("a", GetTunnelParams(), LOW, &callback_, &pool_, BoundNetLog()); EXPECT_EQ(ERR_IO_PENDING, rv); - EXPECT_FALSE(handle.is_initialized()); - EXPECT_FALSE(handle.socket()); + EXPECT_FALSE(handle_.is_initialized()); + EXPECT_FALSE(handle_.socket()); - EXPECT_EQ(OK, callback.WaitForResult()); - EXPECT_TRUE(handle.is_initialized()); - EXPECT_TRUE(handle.socket()); + data_->RunFor(2); + EXPECT_EQ(OK, callback_.WaitForResult()); + EXPECT_TRUE(handle_.is_initialized()); + ASSERT_TRUE(handle_.socket()); HttpProxyClientSocket* tunnel_socket = - static_cast<HttpProxyClientSocket*>(handle.socket()); + static_cast<HttpProxyClientSocket*>(handle_.socket()); EXPECT_TRUE(tunnel_socket->IsConnected()); } TEST_P(HttpProxyClientSocketPoolTest, TCPError) { - StaticSocketDataProvider data; - data.set_connect_data(MockConnect(true, ERR_CONNECTION_CLOSED)); + if (GetParam() == SPDY) return; + data_ = new DeterministicSocketData(NULL, 0, NULL, 0); + data_->set_connect_data(MockConnect(true, ERR_CONNECTION_CLOSED)); - tcp_client_socket_factory_.AddSocketDataProvider(&data); + socket_factory().AddSocketDataProvider(data_.get()); - ClientSocketHandle handle; - TestCompletionCallback callback; - int rv = handle.Init("a", GetTunnelParams(), LOW, &callback, &pool_, + int rv = handle_.Init("a", GetTunnelParams(), LOW, &callback_, &pool_, BoundNetLog()); EXPECT_EQ(ERR_IO_PENDING, rv); - EXPECT_FALSE(handle.is_initialized()); - EXPECT_FALSE(handle.socket()); + EXPECT_FALSE(handle_.is_initialized()); + EXPECT_FALSE(handle_.socket()); - if (GetParam() == HTTP) - EXPECT_EQ(ERR_PROXY_CONNECTION_FAILED, callback.WaitForResult()); - else - EXPECT_EQ(ERR_CONNECTION_CLOSED, callback.WaitForResult()); + EXPECT_EQ(ERR_PROXY_CONNECTION_FAILED, callback_.WaitForResult()); - EXPECT_FALSE(handle.is_initialized()); - EXPECT_FALSE(handle.socket()); + EXPECT_FALSE(handle_.is_initialized()); + EXPECT_FALSE(handle_.socket()); +} + +TEST_P(HttpProxyClientSocketPoolTest, SSLError) { + if (GetParam() == HTTP) return; + data_ = new DeterministicSocketData(NULL, 0, NULL, 0); + data_->set_connect_data(MockConnect(true, OK)); + socket_factory().AddSocketDataProvider(data_.get()); + + ssl_data_.reset(new SSLSocketDataProvider(true, + ERR_CERT_AUTHORITY_INVALID)); + if (GetParam() == SPDY) { + InitializeSpdySsl(); + } + socket_factory().AddSSLSocketDataProvider(ssl_data_.get()); + + int rv = handle_.Init("a", GetTunnelParams(), LOW, &callback_, &pool_, + BoundNetLog()); + EXPECT_EQ(ERR_IO_PENDING, rv); + EXPECT_FALSE(handle_.is_initialized()); + EXPECT_FALSE(handle_.socket()); + + EXPECT_EQ(ERR_PROXY_CERTIFICATE_INVALID, callback_.WaitForResult()); + + EXPECT_FALSE(handle_.is_initialized()); + EXPECT_FALSE(handle_.socket()); +} + +TEST_P(HttpProxyClientSocketPoolTest, SslClientAuth) { + if (GetParam() == HTTP) return; + data_ = new DeterministicSocketData(NULL, 0, NULL, 0); + data_->set_connect_data(MockConnect(true, OK)); + socket_factory().AddSocketDataProvider(data_.get()); + + ssl_data_.reset(new SSLSocketDataProvider(true, + ERR_SSL_CLIENT_AUTH_CERT_NEEDED)); + if (GetParam() == SPDY) { + InitializeSpdySsl(); + } + socket_factory().AddSSLSocketDataProvider(ssl_data_.get()); + + int rv = handle_.Init("a", GetTunnelParams(), LOW, &callback_, &pool_, + BoundNetLog()); + EXPECT_EQ(ERR_IO_PENDING, rv); + EXPECT_FALSE(handle_.is_initialized()); + EXPECT_FALSE(handle_.socket()); + + EXPECT_EQ(ERR_PROXY_AUTH_UNSUPPORTED, callback_.WaitForResult()); + + EXPECT_FALSE(handle_.is_initialized()); + EXPECT_FALSE(handle_.socket()); } TEST_P(HttpProxyClientSocketPoolTest, TunnelUnexpectedClose) { MockWrite writes[] = { - MockWrite("CONNECT host:80 HTTP/1.1\r\n" - "Host: host\r\n" - "Proxy-Connection: keep-alive\r\n" - "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), + MockWrite(true, 0, + "CONNECT www.google.com:443 HTTP/1.1\r\n" + "Host: www.google.com\r\n" + "Proxy-Connection: keep-alive\r\n" + "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), }; MockRead reads[] = { - MockRead("HTTP/1.1 200 Conn"), - MockRead(true, ERR_CONNECTION_CLOSED), + MockRead(true, 1, "HTTP/1.1 200 Conn"), + MockRead(true, ERR_CONNECTION_CLOSED, 2), + }; + scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyConnect(kAuthHeaders, + kAuthHeadersSize, 1)); + MockWrite spdy_writes[] = { + CreateMockWrite(*req, 0, true) + }; + MockRead spdy_reads[] = { + MockRead(true, ERR_CONNECTION_CLOSED, 1), }; - StaticSocketDataProvider data(reads, arraysize(reads), writes, - arraysize(writes)); - tcp_client_socket_factory_.AddSocketDataProvider(&data); + Initialize(false, reads, arraysize(reads), writes, arraysize(writes), + spdy_reads, arraysize(spdy_reads), spdy_writes, + arraysize(spdy_writes)); AddAuthToCache(); - ClientSocketHandle handle; - TestCompletionCallback callback; - int rv = handle.Init("a", GetTunnelParams(), LOW, &callback, &pool_, + int rv = handle_.Init("a", GetTunnelParams(), LOW, &callback_, &pool_, BoundNetLog()); EXPECT_EQ(ERR_IO_PENDING, rv); - EXPECT_FALSE(handle.is_initialized()); - EXPECT_FALSE(handle.socket()); + EXPECT_FALSE(handle_.is_initialized()); + EXPECT_FALSE(handle_.socket()); - EXPECT_EQ(ERR_CONNECTION_CLOSED, callback.WaitForResult()); - EXPECT_FALSE(handle.is_initialized()); - EXPECT_FALSE(handle.socket()); + data_->RunFor(3); + EXPECT_EQ(ERR_CONNECTION_CLOSED, callback_.WaitForResult()); + EXPECT_FALSE(handle_.is_initialized()); + EXPECT_FALSE(handle_.socket()); } TEST_P(HttpProxyClientSocketPoolTest, TunnelSetupError) { MockWrite writes[] = { - MockWrite("CONNECT host:80 HTTP/1.1\r\n" - "Host: host\r\n" - "Proxy-Connection: keep-alive\r\n" - "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), + MockWrite(true, 0, + "CONNECT www.google.com:443 HTTP/1.1\r\n" + "Host: www.google.com\r\n" + "Proxy-Connection: keep-alive\r\n" + "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), }; MockRead reads[] = { - MockRead("HTTP/1.1 304 Not Modified\r\n\r\n"), + MockRead(true, 1, "HTTP/1.1 304 Not Modified\r\n\r\n"), + }; + scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyConnect(kAuthHeaders, + kAuthHeadersSize, 1)); + scoped_ptr<spdy::SpdyFrame> rst(ConstructSpdyRstStream(1, spdy::CANCEL)); + MockWrite spdy_writes[] = { + CreateMockWrite(*req, 0, true), + CreateMockWrite(*rst, 2, true), + }; + scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdySynReplyError(1)); + MockRead spdy_reads[] = { + CreateMockRead(*resp, 1, true), + MockRead(true, 0, 3), }; - StaticSocketDataProvider data(reads, arraysize(reads), writes, - arraysize(writes)); - tcp_client_socket_factory_.AddSocketDataProvider(&data); + Initialize(false, reads, arraysize(reads), writes, arraysize(writes), + spdy_reads, arraysize(spdy_reads), spdy_writes, + arraysize(spdy_writes)); AddAuthToCache(); - ClientSocketHandle handle; - TestCompletionCallback callback; - int rv = handle.Init("a", GetTunnelParams(), LOW, &callback, &pool_, + int rv = handle_.Init("a", GetTunnelParams(), LOW, &callback_, &pool_, BoundNetLog()); EXPECT_EQ(ERR_IO_PENDING, rv); - EXPECT_FALSE(handle.is_initialized()); - EXPECT_FALSE(handle.socket()); + EXPECT_FALSE(handle_.is_initialized()); + EXPECT_FALSE(handle_.socket()); + + data_->RunFor(2); - EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, callback.WaitForResult()); - EXPECT_FALSE(handle.is_initialized()); - EXPECT_FALSE(handle.socket()); + EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, callback_.WaitForResult()); + EXPECT_FALSE(handle_.is_initialized()); + EXPECT_FALSE(handle_.socket()); } // It would be nice to also test the timeouts in HttpProxyClientSocketPool. -} // namespace - } // namespace net diff --git a/net/http/http_stream_request.cc b/net/http/http_stream_request.cc index 35832c7..f60a86c 100644 --- a/net/http/http_stream_request.cc +++ b/net/http/http_stream_request.cc @@ -460,9 +460,9 @@ int HttpStreamRequest::DoInitConnection() { } // Check next if we have a spdy session for this proxy. If so, then go // straight to using that. - if (proxy_info()->is_https()) { + if (IsHttpsProxyAndHttpUrl()) { HostPortProxyPair proxy(proxy_info()->proxy_server().host_port_pair(), - proxy_info()->proxy_server()); + ProxyServer::Direct()); if (session_->spdy_session_pool()->HasSession(proxy)) { using_spdy_ = true; next_state_ = STATE_CREATE_STREAM; @@ -537,6 +537,8 @@ int HttpStreamRequest::DoInitConnection() { endpoint_, session_->auth_cache(), session_->http_auth_handler_factory(), + session_->spdy_session_pool(), + session_->mutable_spdy_settings(), using_ssl_); } else { DCHECK(proxy_info()->is_socks()); @@ -725,10 +727,11 @@ int HttpStreamRequest::DoCreateStream() { // connection, or it might be a SPDY session through an HTTP or HTTPS proxy. spdy_session = spdy_pool->Get(pair, session_->mutable_spdy_settings(), net_log_); - } else if (proxy_info()->is_https()) { + } else if (IsHttpsProxyAndHttpUrl()) { // 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); + pair = HostPortProxyPair(proxy_server.host_port_pair(), + ProxyServer::Direct()); if (spdy_pool->HasSession(pair)) { spdy_session = spdy_pool->Get(pair, session_->mutable_spdy_settings(), net_log_); @@ -751,7 +754,8 @@ int HttpStreamRequest::DoCreateStream() { if (spdy_session->IsClosed()) return ERR_CONNECTION_CLOSED; - stream_.reset(new SpdyHttpStream(spdy_session, direct)); + bool useRelativeUrl = direct || request_info().url.SchemeIs("https"); + stream_.reset(new SpdyHttpStream(spdy_session, useRelativeUrl)); return OK; } @@ -798,6 +802,10 @@ void HttpStreamRequest::SetSocketMotivation() { // TODO(mbelshe): Add other motivations (like EARLY_LOAD_MOTIVATED). } +bool HttpStreamRequest::IsHttpsProxyAndHttpUrl() { + return proxy_info()->is_https() && request_info().url.SchemeIs("http"); +} + // Returns a newly create SSLSocketParams, and sets several // fields of ssl_config_. scoped_refptr<SSLSocketParams> HttpStreamRequest::GenerateSslParams( diff --git a/net/http/http_stream_request.h b/net/http/http_stream_request.h index 5a3ccb7..cad0e59 100644 --- a/net/http/http_stream_request.h +++ b/net/http/http_stream_request.h @@ -112,6 +112,8 @@ class HttpStreamRequest : public StreamFactory::StreamRequestJob { // Set the motivation for this request onto the underlying socket. void SetSocketMotivation(); + bool IsHttpsProxyAndHttpUrl(); + // Returns a newly create SSLSocketParams, and sets several // fields of ssl_config_. scoped_refptr<SSLSocketParams> GenerateSslParams( |