summaryrefslogtreecommitdiffstats
path: root/net/http
diff options
context:
space:
mode:
authorrch@chromium.org <rch@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-10-13 22:37:16 +0000
committerrch@chromium.org <rch@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-10-13 22:37:16 +0000
commitd9da5fe263e748c75d85816ee6bae46b2b9de9c9 (patch)
treef6dbf611550dc1118fcff2cfe9429ca721a5c1bf /net/http
parenta691b8874c225cf530396661264a77159db38780 (diff)
downloadchromium_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.cc212
-rw-r--r--net/http/http_proxy_client_socket_pool.cc114
-rw-r--r--net/http/http_proxy_client_socket_pool.h21
-rw-r--r--net/http/http_proxy_client_socket_pool_unittest.cc416
-rw-r--r--net/http/http_stream_request.cc18
-rw-r--r--net/http/http_stream_request.h2
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(