Index: net/http/http_proxy_client_socket_pool.cc |
=================================================================== |
--- net/http/http_proxy_client_socket_pool.cc (revision 62460) |
+++ net/http/http_proxy_client_socket_pool.cc (working copy) |
@@ -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 @@ |
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 @@ |
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 @@ |
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 @@ |
// 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::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 @@ |
// 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 @@ |
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) { |