From e60e47ad57e7ff423c39cff9c88725a7aed85118 Mon Sep 17 00:00:00 2001 From: "vandebo@chromium.org" Date: Wed, 14 Jul 2010 03:37:18 +0000 Subject: Implement SSLClientSocketPool. To support SSLClientSocketPool, ClientSocketPoolBase and ClientSocketHandle require a notion of additional error state reported from the pool. Overtime the error handling may get become more integrated, alleviating the need for some of the additional error state. To support getting Http Proxy credentials from the user, the SSLClientSocketPool will release unauthenticated HttpProxyClientSocket's into the pool as idle. However, it checks their authentication status when receiving one, completing the authentication once the user has provided the credentials. BUG=30357 TEST=existing unit tests, ClientSocketPoolBaseTest.AdditionalErrorState*, SSLClientSocketPoolTest.* Review URL: http://codereview.chromium.org/2870030 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@52275 0039d316-1c4b-4281-b951-d872f2087c98 --- net/http/http_network_session.cc | 65 ++- net/http/http_network_session.h | 44 ++- net/http/http_network_transaction.cc | 438 +++++++++------------ net/http/http_network_transaction.h | 4 - net/http/http_network_transaction_unittest.cc | 112 ++++-- net/http/http_proxy_client_socket.cc | 14 +- net/http/http_proxy_client_socket.h | 4 + net/http/http_proxy_client_socket_pool.h | 5 +- net/http/http_proxy_client_socket_pool_unittest.cc | 77 +--- 9 files changed, 385 insertions(+), 378 deletions(-) (limited to 'net/http') diff --git a/net/http/http_network_session.cc b/net/http/http_network_session.cc index e49674b..971786a 100644 --- a/net/http/http_network_session.cc +++ b/net/http/http_network_session.cc @@ -44,18 +44,21 @@ HttpNetworkSession::HttpNetworkSession( HttpAuthHandlerFactory* http_auth_handler_factory, HttpNetworkDelegate* network_delegate, NetLog* net_log) - // TODO(vandebo) when we've completely converted to pools, the base TCP - // pool name should get changed to TCP instead of Transport. - : tcp_pool_histograms_(new ClientSocketPoolHistograms("Transport")), + : tcp_pool_histograms_(new ClientSocketPoolHistograms("TCP")), tcp_for_http_proxy_pool_histograms_( new ClientSocketPoolHistograms("TCPforHTTPProxy")), http_proxy_pool_histograms_(new ClientSocketPoolHistograms("HTTPProxy")), tcp_for_socks_pool_histograms_( new ClientSocketPoolHistograms("TCPforSOCKS")), socks_pool_histograms_(new ClientSocketPoolHistograms("SOCK")), - tcp_socket_pool_(new TCPClientSocketPool(g_max_sockets, - g_max_sockets_per_group, tcp_pool_histograms_, host_resolver, - client_socket_factory, net_log)), + ssl_pool_histograms_(new ClientSocketPoolHistograms("SSL")), + tcp_socket_pool_(new TCPClientSocketPool( + g_max_sockets, g_max_sockets_per_group, tcp_pool_histograms_, + host_resolver, client_socket_factory, net_log)), + ssl_socket_pool_(new SSLClientSocketPool( + g_max_sockets, g_max_sockets_per_group, ssl_pool_histograms_, + host_resolver, client_socket_factory, tcp_socket_pool_, NULL, + NULL, net_log)), socket_factory_(client_socket_factory), host_resolver_(host_resolver), proxy_service_(proxy_service), @@ -74,12 +77,12 @@ HttpNetworkSession::~HttpNetworkSession() { const scoped_refptr& HttpNetworkSession::GetSocketPoolForHTTPProxy(const HostPortPair& http_proxy) { HTTPProxySocketPoolMap::const_iterator it = - http_proxy_socket_pool_.find(http_proxy); - if (it != http_proxy_socket_pool_.end()) + http_proxy_socket_pools_.find(http_proxy); + if (it != http_proxy_socket_pools_.end()) return it->second; std::pair ret = - http_proxy_socket_pool_.insert( + http_proxy_socket_pools_.insert( std::make_pair( http_proxy, new HttpProxyClientSocketPool( @@ -97,18 +100,42 @@ HttpNetworkSession::GetSocketPoolForHTTPProxy(const HostPortPair& http_proxy) { const scoped_refptr& HttpNetworkSession::GetSocketPoolForSOCKSProxy( const HostPortPair& socks_proxy) { - SOCKSSocketPoolMap::const_iterator it = socks_socket_pool_.find(socks_proxy); - if (it != socks_socket_pool_.end()) + SOCKSSocketPoolMap::const_iterator it = socks_socket_pools_.find(socks_proxy); + if (it != socks_socket_pools_.end()) return it->second; - std::pair ret = socks_socket_pool_.insert( - std::make_pair(socks_proxy, new SOCKSClientSocketPool( - g_max_sockets_per_proxy_server, g_max_sockets_per_group, - socks_pool_histograms_, host_resolver_, - new TCPClientSocketPool(g_max_sockets_per_proxy_server, - g_max_sockets_per_group, tcp_for_socks_pool_histograms_, - host_resolver_, socket_factory_, net_log_), - net_log_))); + std::pair ret = + socks_socket_pools_.insert( + std::make_pair(socks_proxy, new SOCKSClientSocketPool( + g_max_sockets_per_proxy_server, g_max_sockets_per_group, + socks_pool_histograms_, host_resolver_, + new TCPClientSocketPool(g_max_sockets_per_proxy_server, + g_max_sockets_per_group, tcp_for_socks_pool_histograms_, + host_resolver_, socket_factory_, net_log_), + net_log_))); + + return ret.first->second; +} + +const scoped_refptr& +HttpNetworkSession::GetSocketPoolForSSLWithProxy( + const HostPortPair& proxy_server) { + SSLSocketPoolMap::const_iterator it = + ssl_socket_pools_for_proxies_.find(proxy_server); + if (it != ssl_socket_pools_for_proxies_.end()) + return it->second; + + SSLClientSocketPool* new_pool = new SSLClientSocketPool( + g_max_sockets_per_proxy_server, g_max_sockets_per_group, + ssl_pool_histograms_, host_resolver_, socket_factory_, + NULL, + GetSocketPoolForHTTPProxy(proxy_server), + GetSocketPoolForSOCKSProxy(proxy_server), + net_log_); + + std::pair ret = + ssl_socket_pools_for_proxies_.insert(std::make_pair(proxy_server, + new_pool)); return ret.first->second; } diff --git a/net/http/http_network_session.h b/net/http/http_network_session.h index 5f1b869..de57eba 100644 --- a/net/http/http_network_session.h +++ b/net/http/http_network_session.h @@ -21,6 +21,7 @@ #include "net/proxy/proxy_service.h" #include "net/socket/client_socket_pool_histograms.h" #include "net/socket/socks_client_socket_pool.h" +#include "net/socket/ssl_client_socket_pool.h" #include "net/socket/tcp_client_socket_pool.h" #include "net/spdy/spdy_settings_storage.h" @@ -71,12 +72,19 @@ class HttpNetworkSession : public base::RefCounted, return tcp_socket_pool_; } + const scoped_refptr& ssl_socket_pool() { + return ssl_socket_pool_; + } + const scoped_refptr& GetSocketPoolForSOCKSProxy( const HostPortPair& socks_proxy); const scoped_refptr& GetSocketPoolForHTTPProxy( const HostPortPair& http_proxy); + const scoped_refptr& GetSocketPoolForSSLWithProxy( + const HostPortPair& proxy_server); + // SSL sockets come from the socket_factory(). ClientSocketFactory* socket_factory() { return socket_factory_; } HostResolver* host_resolver() { return host_resolver_; } @@ -100,11 +108,40 @@ class HttpNetworkSession : public base::RefCounted, static uint16 fixed_https_port(); static void set_fixed_https_port(uint16 port); +#ifdef UNIT_TEST + void FlushSocketPools() { + if (ssl_socket_pool_.get()) + ssl_socket_pool_->Flush(); + if (tcp_socket_pool_.get()) + tcp_socket_pool_->Flush(); + + for (SSLSocketPoolMap::const_iterator it = + ssl_socket_pools_for_proxies_.begin(); + it != ssl_socket_pools_for_proxies_.end(); + it++) + it->second->Flush(); + + for (SOCKSSocketPoolMap::const_iterator it = + socks_socket_pools_.begin(); + it != socks_socket_pools_.end(); + it++) + it->second->Flush(); + + for (HTTPProxySocketPoolMap::const_iterator it = + http_proxy_socket_pools_.begin(); + it != http_proxy_socket_pools_.end(); + it++) + it->second->Flush(); + } +#endif + private: typedef std::map > HTTPProxySocketPoolMap; typedef std::map > SOCKSSocketPoolMap; + typedef std::map > + SSLSocketPoolMap; friend class base::RefCounted; friend class HttpNetworkSessionPeer; @@ -119,9 +156,12 @@ class HttpNetworkSession : public base::RefCounted, scoped_refptr http_proxy_pool_histograms_; scoped_refptr tcp_for_socks_pool_histograms_; scoped_refptr socks_pool_histograms_; + scoped_refptr ssl_pool_histograms_; scoped_refptr tcp_socket_pool_; - HTTPProxySocketPoolMap http_proxy_socket_pool_; - SOCKSSocketPoolMap socks_socket_pool_; + scoped_refptr ssl_socket_pool_; + HTTPProxySocketPoolMap http_proxy_socket_pools_; + SOCKSSocketPoolMap socks_socket_pools_; + SSLSocketPoolMap ssl_socket_pools_for_proxies_; ClientSocketFactory* socket_factory_; scoped_refptr host_resolver_; scoped_refptr proxy_service_; diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc index 32f8530..7f9b696 100644 --- a/net/http/http_network_transaction.cc +++ b/net/http/http_network_transaction.cc @@ -41,6 +41,7 @@ #include "net/socket/client_socket_factory.h" #include "net/socket/socks_client_socket_pool.h" #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_http_stream.h" #include "net/spdy/spdy_session.h" @@ -260,7 +261,7 @@ int HttpNetworkTransaction::Start(const HttpRequestInfo* request_info, int HttpNetworkTransaction::RestartIgnoringLastError( CompletionCallback* callback) { - if (connection_->socket()->IsConnectedAndIdle()) { + if (connection_->socket() && connection_->socket()->IsConnectedAndIdle()) { // TODO(wtc): Should we update any of the connection histograms that we // update in DoSSLConnectComplete if |result| is OK? if (using_spdy_) { @@ -270,7 +271,8 @@ int HttpNetworkTransaction::RestartIgnoringLastError( next_state_ = STATE_GENERATE_PROXY_AUTH_TOKEN; } } else { - connection_->socket()->Disconnect(); + if (connection_->socket()) + connection_->socket()->Disconnect(); connection_->Reset(); next_state_ = STATE_INIT_CONNECTION; } @@ -314,8 +316,8 @@ int HttpNetworkTransaction::RestartWithAuth( if (target == HttpAuth::AUTH_PROXY && using_ssl_ && proxy_info_.is_http()) { DCHECK(establishing_tunnel_); + next_state_ = STATE_INIT_CONNECTION; ResetStateForRestart(); - next_state_ = STATE_TUNNEL_RESTART_WITH_AUTH; } else { PrepareForAuthRestart(target); } @@ -377,22 +379,8 @@ int HttpNetworkTransaction::Read(IOBuffer* buf, int buf_len, State next_state = STATE_NONE; - // Are we using SPDY or HTTP? - if (using_spdy_) { - DCHECK(!http_stream_.get()); - DCHECK(spdy_http_stream_->GetResponseInfo()->headers); - next_state = STATE_SPDY_READ_BODY; - } else { - DCHECK(!spdy_http_stream_.get()); - next_state = STATE_READ_BODY; - - if (!connection_->is_initialized()) - return 0; // connection_->has been reset. Treat like EOF. - } - scoped_refptr headers = GetResponseHeaders(); - DCHECK(headers.get()); - if (establishing_tunnel_) { + if (headers_valid_ && headers.get() && establishing_tunnel_) { // We're trying to read the body of the response but we're still trying // to establish an SSL tunnel through the proxy. We can't read these // bytes when establishing a tunnel because they might be controlled by @@ -408,6 +396,19 @@ int HttpNetworkTransaction::Read(IOBuffer* buf, int buf_len, return ERR_TUNNEL_CONNECTION_FAILED; } + // Are we using SPDY or HTTP? + if (using_spdy_) { + DCHECK(!http_stream_.get()); + DCHECK(spdy_http_stream_->GetResponseInfo()->headers); + next_state = STATE_SPDY_READ_BODY; + } else { + DCHECK(!spdy_http_stream_.get()); + next_state = STATE_READ_BODY; + + if (!connection_->is_initialized()) + return 0; // |*connection_| has been reset. Treat like EOF. + } + read_buf_ = buf; read_buf_len_ = buf_len; @@ -517,17 +518,6 @@ int HttpNetworkTransaction::DoLoop(int result) { case STATE_INIT_CONNECTION_COMPLETE: rv = DoInitConnectionComplete(rv); break; - case STATE_TUNNEL_RESTART_WITH_AUTH: - DCHECK_EQ(OK, rv); - rv = DoTunnelRestartWithAuth(); - break; - case STATE_SSL_CONNECT: - DCHECK_EQ(OK, rv); - rv = DoSSLConnect(); - break; - case STATE_SSL_CONNECT_COMPLETE: - rv = DoSSLConnectComplete(rv); - break; case STATE_GENERATE_PROXY_AUTH_TOKEN: DCHECK_EQ(OK, rv); rv = DoGenerateProxyAuthToken(); @@ -702,6 +692,7 @@ int HttpNetworkTransaction::DoResolveProxyComplete(int result) { int HttpNetworkTransaction::DoInitConnection() { DCHECK(!connection_->is_initialized()); DCHECK(proxy_info_.proxy_server().is_valid()); + next_state_ = STATE_INIT_CONNECTION_COMPLETE; // Now that the proxy server has been resolved, create the auth_controllers_. for (int i = 0; i < HttpAuth::AUTH_NUM_TARGETS; i++) { @@ -712,17 +703,11 @@ int HttpNetworkTransaction::DoInitConnection() { session_); } - next_state_ = STATE_INIT_CONNECTION_COMPLETE; - - using_ssl_ = request_->url.SchemeIs("https") || - (alternate_protocol_mode_ == kUsingAlternateProtocol && - alternate_protocol_ == HttpAlternateProtocols::NPN_SPDY_1); - + bool want_spdy = alternate_protocol_mode_ == kUsingAlternateProtocol + && alternate_protocol_ == HttpAlternateProtocols::NPN_SPDY_1; + using_ssl_ = request_->url.SchemeIs("https") || want_spdy; using_spdy_ = false; - - // Build the string used to uniquely identify connections of this type. - // Determine the host and port to connect to. - std::string connection_group; + response_.was_fetched_via_proxy = !proxy_info_.is_direct(); // Use the fixed testing ports if they've been provided. if (using_ssl_) { @@ -732,17 +717,18 @@ int HttpNetworkTransaction::DoInitConnection() { endpoint_.port = session_->fixed_http_port(); } - response_.was_fetched_via_proxy = !proxy_info_.is_direct(); - // Check first if we have a spdy session for this group. If so, then go // straight to using that. if (session_->spdy_session_pool()->HasSession(endpoint_)) { using_spdy_ = true; reused_socket_ = true; + next_state_ = STATE_SPDY_SEND_REQUEST; return OK; } - connection_group = endpoint_.ToString(); + // Build the string used to uniquely identify connections of this type. + // Determine the host and port to connect to. + std::string connection_group = endpoint_.ToString(); DCHECK(!connection_group.empty()); if (using_ssl_) @@ -753,206 +739,175 @@ int HttpNetworkTransaction::DoInitConnection() { request_->load_flags & LOAD_VALIDATE_CACHE || request_->load_flags & LOAD_DISABLE_CACHE; - int rv; - if (!proxy_info_.is_direct()) { - ProxyServer proxy_server = proxy_info_.proxy_server(); - HostPortPair proxy_host_port_pair(proxy_server.HostNoBrackets(), - proxy_server.port()); + // Build up the connection parameters. + scoped_refptr tcp_params; + scoped_refptr http_proxy_params; + scoped_refptr socks_params; + scoped_ptr proxy_host_port; - scoped_refptr tcp_params = - new TCPSocketParams(proxy_host_port_pair, request_->priority, + if (proxy_info_.is_direct()) { + tcp_params = new TCPSocketParams(endpoint_, request_->priority, + request_->referrer, + disable_resolver_cache); + } else { + ProxyServer proxy_server = proxy_info_.proxy_server(); + proxy_host_port.reset(new HostPortPair(proxy_server.HostNoBrackets(), + proxy_server.port())); + scoped_refptr proxy_tcp_params = + new TCPSocketParams(*proxy_host_port, request_->priority, request_->referrer, disable_resolver_cache); - if (proxy_info_.is_socks()) { - const char* socks_version; - bool socks_v5; - if (proxy_info_.proxy_server().scheme() == ProxyServer::SCHEME_SOCKS5) { - socks_version = "5"; - socks_v5 = true; - } else { - socks_version = "4"; - socks_v5 = false; - } - - connection_group = - StringPrintf("socks%s/%s", socks_version, connection_group.c_str()); - - scoped_refptr socks_params = - new SOCKSSocketParams(tcp_params, socks_v5, endpoint_, - request_->priority, request_->referrer); - - rv = connection_->Init( - connection_group, socks_params, request_->priority, - &io_callback_, - session_->GetSocketPoolForSOCKSProxy(proxy_host_port_pair), net_log_); - } else { - DCHECK(proxy_info_.is_http()); + if (proxy_info_.is_http()) { scoped_refptr http_proxy_auth; if (using_ssl_) { http_proxy_auth = auth_controllers_[HttpAuth::AUTH_PROXY]; establishing_tunnel_ = true; } + http_proxy_params = new HttpProxySocketParams(proxy_tcp_params, + request_->url, endpoint_, + http_proxy_auth, + using_ssl_); + } else { + DCHECK(proxy_info_.is_socks()); + char socks_version; + if (proxy_server.scheme() == ProxyServer::SCHEME_SOCKS5) + socks_version = '5'; + else + socks_version = '4'; + connection_group = + StringPrintf("socks%c/%s", socks_version, connection_group.c_str()); - scoped_refptr http_proxy_params = - new HttpProxySocketParams(tcp_params, request_->url, endpoint_, - http_proxy_auth, using_ssl_); - - rv = connection_->Init(connection_group, http_proxy_params, - request_->priority, &io_callback_, - session_->GetSocketPoolForHTTPProxy( - proxy_host_port_pair), - net_log_); + socks_params = new SOCKSSocketParams(proxy_tcp_params, + socks_version == '5', + endpoint_, + request_->priority, + request_->referrer); } - } else { - scoped_refptr tcp_params = - new TCPSocketParams(endpoint_, request_->priority, request_->referrer, - disable_resolver_cache); - rv = connection_->Init(connection_group, tcp_params, request_->priority, - &io_callback_, session_->tcp_socket_pool(), - net_log_); } - return rv; -} - -int HttpNetworkTransaction::DoInitConnectionComplete(int result) { - if (result < 0) { - if (result == ERR_RETRY_CONNECTION) { - DCHECK(establishing_tunnel_); - next_state_ = STATE_INIT_CONNECTION; - connection_->socket()->Disconnect(); - connection_->Reset(); - return OK; + // Deal with SSL - which layers on top of any given proxy. + if (using_ssl_) { + if (ContainsKey(*g_tls_intolerant_servers, GetHostAndPort(request_->url))) { + LOG(WARNING) << "Falling back to SSLv3 because host is TLS intolerant: " + << GetHostAndPort(request_->url); + ssl_config_.ssl3_fallback = true; + ssl_config_.tls1_enabled = false; } - if (result == ERR_PROXY_AUTH_REQUESTED) { - DCHECK(establishing_tunnel_); - HttpProxyClientSocket* tunnel_socket = - static_cast(connection_->socket()); - DCHECK(tunnel_socket); - DCHECK(!tunnel_socket->IsConnected()); - const HttpResponseInfo* auth_response = tunnel_socket->GetResponseInfo(); - - response_.headers = auth_response->headers; - headers_valid_ = true; - response_.auth_challenge = auth_response->auth_challenge; - pending_auth_target_ = HttpAuth::AUTH_PROXY; - return OK; - } + UMA_HISTOGRAM_ENUMERATION("Net.ConnectionUsedSSLv3Fallback", + (int) ssl_config_.ssl3_fallback, 2); - if (alternate_protocol_mode_ == kUsingAlternateProtocol) { - // Mark the alternate protocol as broken and fallback. - MarkBrokenAlternateProtocolAndFallback(); - return OK; - } + int load_flags = request_->load_flags; + if (g_ignore_certificate_errors) + load_flags |= LOAD_IGNORE_ALL_CERT_ERRORS; + if (request_->load_flags & LOAD_VERIFY_EV_CERT) + ssl_config_.verify_ev_cert = true; - return ReconsiderProxyAfterError(result); - } + scoped_refptr ssl_params = + new SSLSocketParams(tcp_params, http_proxy_params, socks_params, + proxy_info_.proxy_server().scheme(), + request_->url.HostNoBrackets(), ssl_config_, + load_flags, want_spdy); - DCHECK_EQ(OK, result); - if (establishing_tunnel_) { - DCHECK(connection_->socket()->IsConnected()); - establishing_tunnel_ = false; - } + scoped_refptr ssl_pool; + if (proxy_info_.is_direct()) + ssl_pool = session_->ssl_socket_pool(); + else + ssl_pool = session_->GetSocketPoolForSSLWithProxy(*proxy_host_port); - if (using_spdy_) { - DCHECK(!connection_->is_initialized()); - // TODO(cbentzel): Add auth support to spdy. See http://crbug.com/46620 - next_state_ = STATE_SPDY_SEND_REQUEST; - return OK; + return connection_->Init(connection_group, ssl_params, request_->priority, + &io_callback_, ssl_pool, net_log_); } - LogHttpConnectedMetrics(*connection_); + // Finally, get the connection started. + if (proxy_info_.is_http()) { + return connection_->Init( + connection_group, http_proxy_params, request_->priority, &io_callback_, + session_->GetSocketPoolForHTTPProxy(*proxy_host_port), net_log_); + } - // Set the reused_socket_ flag to indicate that we are using a keep-alive - // connection. This flag is used to handle errors that occur while we are - // trying to reuse a keep-alive connection. - reused_socket_ = connection_->is_reused(); - if (reused_socket_) { - if (using_ssl_) { - SSLClientSocket* ssl_socket = - reinterpret_cast(connection_->socket()); - response_.was_npn_negotiated = ssl_socket->wasNpnNegotiated(); - } - next_state_ = STATE_GENERATE_PROXY_AUTH_TOKEN; - } else { - // Now we have a TCP connected socket. Perform other connection setup as - // needed. - UpdateConnectionTypeHistograms(CONNECTION_HTTP); - if (using_ssl_) - next_state_ = STATE_SSL_CONNECT; - else - next_state_ = STATE_GENERATE_PROXY_AUTH_TOKEN; + if (proxy_info_.is_socks()) { + return connection_->Init( + connection_group, socks_params, request_->priority, &io_callback_, + session_->GetSocketPoolForSOCKSProxy(*proxy_host_port), net_log_); } - return OK; + DCHECK(proxy_info_.is_direct()); + return connection_->Init(connection_group, tcp_params, request_->priority, + &io_callback_, session_->tcp_socket_pool(), + net_log_); } -int HttpNetworkTransaction::DoTunnelRestartWithAuth() { - next_state_ = STATE_INIT_CONNECTION_COMPLETE; - HttpProxyClientSocket* tunnel_socket = - reinterpret_cast(connection_->socket()); - - return tunnel_socket->RestartWithAuth(&io_callback_); -} +int HttpNetworkTransaction::DoInitConnectionComplete(int result) { + // |result| may be the result of any of the stacked pools. The following + // logic is used when determining how to interpret an error. + // If |result| < 0: + // and connection_->socket() != NULL, then the SSL handshake ran and it + // is a potentially recoverable error. + // and connection_->socket == NULL and connection_->is_ssl_error() is true, + // then the SSL handshake ran with an unrecoverable error. + // otherwise, the error came from one of the other pools. + bool ssl_started = using_ssl_ && (result == OK || connection_->socket() || + connection_->is_ssl_error()); + + if (ssl_started && (result == OK || IsCertificateError(result))) { + SSLClientSocket* ssl_socket = + static_cast(connection_->socket()); + if (ssl_socket->wasNpnNegotiated()) { + response_.was_npn_negotiated = true; + std::string proto; + ssl_socket->GetNextProto(&proto); + if (SSLClientSocket::NextProtoFromString(proto) == + SSLClientSocket::kProtoSPDY1) + using_spdy_ = true; + } + } -int HttpNetworkTransaction::DoSSLConnect() { - next_state_ = STATE_SSL_CONNECT_COMPLETE; + if (result == ERR_PROXY_AUTH_REQUESTED) { + DCHECK(!ssl_started); + const HttpResponseInfo& tunnel_auth_response = + connection_->tunnel_auth_response_info(); - if (ContainsKey(*g_tls_intolerant_servers, GetHostAndPort(request_->url))) { - LOG(WARNING) << "Falling back to SSLv3 because host is TLS intolerant: " - << GetHostAndPort(request_->url); - ssl_config_.ssl3_fallback = true; - ssl_config_.tls1_enabled = false; + response_.headers = tunnel_auth_response.headers; + response_.auth_challenge = tunnel_auth_response.auth_challenge; + headers_valid_ = true; + pending_auth_target_ = HttpAuth::AUTH_PROXY; + return OK; } - UMA_HISTOGRAM_ENUMERATION("Net.ConnectionUsedSSLv3Fallback", - (int) ssl_config_.ssl3_fallback, 2); + if ((!ssl_started && result < 0 && + alternate_protocol_mode_ == kUsingAlternateProtocol) || + result == ERR_NPN_NEGOTIATION_FAILED) { + // Mark the alternate protocol as broken and fallback. + MarkBrokenAlternateProtocolAndFallback(); + return OK; + } - if (request_->load_flags & LOAD_VERIFY_EV_CERT) - ssl_config_.verify_ev_cert = true; + if (result < 0 && !ssl_started) + return ReconsiderProxyAfterError(result); + establishing_tunnel_ = false; - ssl_connect_start_time_ = base::TimeTicks::Now(); + if (connection_->socket()) { + LogHttpConnectedMetrics(*connection_); - // Add a SSL socket on top of our existing transport socket. - ClientSocket* s = connection_->release_socket(); - s = session_->socket_factory()->CreateSSLClientSocket( - s, request_->url.HostNoBrackets(), ssl_config_); - connection_->set_socket(s); - return connection_->socket()->Connect(&io_callback_); -} + // Set the reused_socket_ flag to indicate that we are using a keep-alive + // connection. This flag is used to handle errors that occur while we are + // trying to reuse a keep-alive connection. + reused_socket_ = connection_->is_reused(); + // TODO(vandebo) should we exclude SPDY in the following if? + if (!reused_socket_) + UpdateConnectionTypeHistograms(CONNECTION_HTTP); -int HttpNetworkTransaction::DoSSLConnectComplete(int result) { - SSLClientSocket* ssl_socket = - reinterpret_cast(connection_->socket()); - - SSLClientSocket::NextProtoStatus status = - SSLClientSocket::kNextProtoUnsupported; - std::string proto; - // GetNextProto will fail and and trigger a NOTREACHED if we pass in a socket - // that hasn't had SSL_ImportFD called on it. If we get a certificate error - // here, then we know that we called SSL_ImportFD. - if (result == OK || IsCertificateError(result)) - status = ssl_socket->GetNextProto(&proto); - - if (status == SSLClientSocket::kNextProtoNegotiated) { - ssl_socket->setWasNpnNegotiated(true); - response_.was_npn_negotiated = true; - if (SSLClientSocket::NextProtoFromString(proto) == - SSLClientSocket::kProtoSPDY1) { - using_spdy_ = true; + if (!using_ssl_) { + DCHECK_EQ(OK, result); + next_state_ = STATE_GENERATE_PROXY_AUTH_TOKEN; + return result; } } - if (alternate_protocol_mode_ == kUsingAlternateProtocol && - alternate_protocol_ == HttpAlternateProtocols::NPN_SPDY_1 && - !using_spdy_) { - // We tried using the NPN_SPDY_1 alternate protocol, but failed, so we - // fallback. - MarkBrokenAlternateProtocolAndFallback(); - return OK; - } - + // Handle SSL errors below. + DCHECK(using_ssl_); + DCHECK(ssl_started); if (IsCertificateError(result)) { if (using_spdy_ && request_->url.SchemeIs("http")) { // We ignore certificate errors for http over spdy. @@ -969,36 +924,19 @@ int HttpNetworkTransaction::DoSSLConnectComplete(int result) { } } - if (result == OK) { - DCHECK(ssl_connect_start_time_ != base::TimeTicks()); - base::TimeDelta connect_duration = - base::TimeTicks::Now() - ssl_connect_start_time_; - - if (using_spdy_) { - UMA_HISTOGRAM_CUSTOM_TIMES("Net.SpdyConnectionLatency", - connect_duration, - base::TimeDelta::FromMilliseconds(1), - base::TimeDelta::FromMinutes(10), - 100); - - UpdateConnectionTypeHistograms(CONNECTION_SPDY); - // TODO(cbentzel): Add auth support to spdy. See http://crbug.com/46620 - next_state_ = STATE_SPDY_SEND_REQUEST; - } else { - UMA_HISTOGRAM_CUSTOM_TIMES("Net.SSL_Connection_Latency", - connect_duration, - base::TimeDelta::FromMilliseconds(1), - base::TimeDelta::FromMinutes(10), - 100); + if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) + return HandleCertificateRequest(result); + if (result < 0) + return HandleSSLHandshakeError(result); - next_state_ = STATE_GENERATE_PROXY_AUTH_TOKEN; - } - } else if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) { - result = HandleCertificateRequest(result); + if (using_spdy_) { + UpdateConnectionTypeHistograms(CONNECTION_SPDY); + // TODO(cbentzel): Add auth support to spdy. See http://crbug.com/46620 + next_state_ = STATE_SPDY_SEND_REQUEST; } else { - result = HandleSSLHandshakeError(result); + next_state_ = STATE_GENERATE_PROXY_AUTH_TOKEN; } - return result; + return OK; } int HttpNetworkTransaction::DoGenerateProxyAuthToken() { @@ -1196,7 +1134,7 @@ int HttpNetworkTransaction::DoReadHeadersComplete(int result) { if (using_ssl_) { SSLClientSocket* ssl_socket = - reinterpret_cast(connection_->socket()); + static_cast(connection_->socket()); ssl_socket->GetSSLInfo(&response_.ssl_info); } @@ -1539,7 +1477,7 @@ int HttpNetworkTransaction::HandleCertificateError(int error) { DCHECK(IsCertificateError(error)); SSLClientSocket* ssl_socket = - reinterpret_cast(connection_->socket()); + static_cast(connection_->socket()); ssl_socket->GetSSLInfo(&response_.ssl_info); // Add the bad certificate to the set of allowed certificates in the @@ -1551,29 +1489,11 @@ int HttpNetworkTransaction::HandleCertificateError(int error) { bad_cert.cert_status = response_.ssl_info.cert_status; ssl_config_.allowed_bad_certs.push_back(bad_cert); + int load_flags = request_->load_flags; if (g_ignore_certificate_errors) + load_flags |= LOAD_IGNORE_ALL_CERT_ERRORS; + if (ssl_socket->IgnoreCertError(error, load_flags)) return OK; - - const int kCertFlags = LOAD_IGNORE_CERT_COMMON_NAME_INVALID | - LOAD_IGNORE_CERT_DATE_INVALID | - LOAD_IGNORE_CERT_AUTHORITY_INVALID | - LOAD_IGNORE_CERT_WRONG_USAGE; - if (request_->load_flags & kCertFlags) { - switch (error) { - case ERR_CERT_COMMON_NAME_INVALID: - if (request_->load_flags & LOAD_IGNORE_CERT_COMMON_NAME_INVALID) - error = OK; - break; - case ERR_CERT_DATE_INVALID: - if (request_->load_flags & LOAD_IGNORE_CERT_DATE_INVALID) - error = OK; - break; - case ERR_CERT_AUTHORITY_INVALID: - if (request_->load_flags & LOAD_IGNORE_CERT_AUTHORITY_INVALID) - error = OK; - break; - } - } return error; } @@ -1590,7 +1510,7 @@ int HttpNetworkTransaction::HandleCertificateRequest(int error) { response_.cert_request_info = new SSLCertRequestInfo; SSLClientSocket* ssl_socket = - reinterpret_cast(connection_->socket()); + static_cast(connection_->socket()); ssl_socket->GetSSLCertRequestInfo(response_.cert_request_info); // Close the connection while the user is selecting a certificate to send @@ -1695,11 +1615,13 @@ bool HttpNetworkTransaction::ShouldResendRequest(int error) const { } void HttpNetworkTransaction::ResetConnectionAndRequestForResend() { - connection_->socket()->Disconnect(); + if (connection_->socket()) + connection_->socket()->Disconnect(); connection_->Reset(); // We need to clear request_headers_ because it contains the real request // headers, but we may need to resend the CONNECT request first to recreate // the SSL tunnel. + request_headers_.clear(); next_state_ = STATE_INIT_CONNECTION; // Resend the request. } diff --git a/net/http/http_network_transaction.h b/net/http/http_network_transaction.h index 373aba8..a5207da 100644 --- a/net/http/http_network_transaction.h +++ b/net/http/http_network_transaction.h @@ -127,7 +127,6 @@ class HttpNetworkTransaction : public HttpTransaction { int DoResolveProxyComplete(int result); int DoInitConnection(); int DoInitConnectionComplete(int result); - int DoTunnelRestartWithAuth(); int DoSSLConnect(); int DoSSLConnectComplete(int result); int DoGenerateProxyAuthToken(); @@ -305,9 +304,6 @@ class HttpNetworkTransaction : public HttpTransaction { // The time the Start method was called. base::Time start_time_; - // The time the DoSSLConnect() method was called (if it got called). - base::TimeTicks ssl_connect_start_time_; - // The next state in the state machine. State next_state_; diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc index 976452d..48945db 100644 --- a/net/http/http_network_transaction_unittest.cc +++ b/net/http/http_network_transaction_unittest.cc @@ -59,13 +59,23 @@ class HttpNetworkSessionPeer { void SetSocketPoolForSOCKSProxy( const HostPortPair& socks_proxy, const scoped_refptr& pool) { - session_->socks_socket_pool_[socks_proxy] = pool; + session_->socks_socket_pools_[socks_proxy] = pool; } void SetSocketPoolForHTTPProxy( const HostPortPair& http_proxy, const scoped_refptr& pool) { - session_->http_proxy_socket_pool_[http_proxy] = pool; + session_->http_proxy_socket_pools_[http_proxy] = pool; + } + + void SetSSLSocketPool(const scoped_refptr& pool) { + session_->ssl_socket_pool_ = pool; + } + + void SetSocketPoolForSSLWithProxy( + const HostPortPair& proxy_host, + const scoped_refptr& pool) { + session_->ssl_socket_pools_for_proxies_[proxy_host] = pool; } private: @@ -238,13 +248,11 @@ std::string MockGetHostName() { return "WTC-WIN7"; } -template -class CaptureGroupNameSocketPool : public EmulatedClientSocketPool { +template +class CaptureGroupNameSocketPool : public ParentPool { public: - explicit CaptureGroupNameSocketPool(HttpNetworkSession* session) - : EmulatedClientSocketPool(0, 0, NULL, session->host_resolver(), NULL, - NULL) { - } + explicit CaptureGroupNameSocketPool(HttpNetworkSession* session); + const std::string last_group_name_received() const { return last_group_name_; } @@ -290,6 +298,19 @@ typedef CaptureGroupNameSocketPool CaptureGroupNameHttpProxySocketPool; typedef CaptureGroupNameSocketPool CaptureGroupNameSOCKSSocketPool; +typedef CaptureGroupNameSocketPool +CaptureGroupNameSSLSocketPool; + +template +CaptureGroupNameSocketPool::CaptureGroupNameSocketPool( + HttpNetworkSession* session) + : ParentPool(0, 0, NULL, session->host_resolver(), NULL, NULL) {} + +template<> +CaptureGroupNameSSLSocketPool::CaptureGroupNameSocketPool( + HttpNetworkSession* session) + : SSLClientSocketPool(0, 0, NULL, session->host_resolver(), NULL, NULL, + NULL, NULL, NULL) {} //----------------------------------------------------------------------------- @@ -1404,12 +1425,9 @@ TEST_F(HttpNetworkTransactionTest, BasicAuthProxyKeepAlive) { EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm); EXPECT_EQ(L"basic", response->auth_challenge->scheme); - // Cleanup the transaction so that the sockets are destroyed before the - // net log goes out of scope. - trans.reset(); - - // We also need to run the message queue for the socket releases to complete. - MessageLoop::current()->RunAllPending(); + // Flush the idle socket before the NetLog and HttpNetworkTransaction go + // out of scope. + session->FlushSocketPools(); } // Test that we don't read the response body when we fail to establish a tunnel, @@ -1465,6 +1483,9 @@ TEST_F(HttpNetworkTransactionTest, BasicAuthProxyCancelTunnel) { std::string response_data; rv = ReadTransaction(trans.get(), &response_data); EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, rv); + + // Flush the idle socket before the HttpNetworkTransaction goes out of scope. + session->FlushSocketPools(); } // Test when a server (non-proxy) returns a 407 (proxy-authenticate). @@ -3977,6 +3998,7 @@ struct GroupNameTest { std::string proxy_server; std::string url; std::string expected_group_name; + bool ssl; }; scoped_refptr SetupSessionForGroupNameTests( @@ -4015,11 +4037,13 @@ TEST_F(HttpNetworkTransactionTest, GroupNameForDirectConnections) { "", // unused "http://www.google.com/direct", "www.google.com:80", + false, }, { "", // unused "http://[2001:1418:13:1::25]/direct", "[2001:1418:13:1::25]:80", + false, }, // SSL Tests @@ -4027,16 +4051,19 @@ TEST_F(HttpNetworkTransactionTest, GroupNameForDirectConnections) { "", // unused "https://www.google.com/direct_ssl", "ssl/www.google.com:443", + true, }, { "", // unused "https://[2001:1418:13:1::25]/direct", "ssl/[2001:1418:13:1::25]:443", + true, }, { "", // unused "http://host.with.alternate/direct", "ssl/host.with.alternate:443", + true, }, }; @@ -4050,11 +4077,18 @@ TEST_F(HttpNetworkTransactionTest, GroupNameForDirectConnections) { scoped_refptr tcp_conn_pool( new CaptureGroupNameTCPSocketPool(session.get())); peer.SetTCPSocketPool(tcp_conn_pool); + scoped_refptr ssl_conn_pool( + new CaptureGroupNameSSLSocketPool(session.get())); + peer.SetSSLSocketPool(ssl_conn_pool); EXPECT_EQ(ERR_IO_PENDING, GroupNameTransactionHelper(tests[i].url, session)); - EXPECT_EQ(tests[i].expected_group_name, - tcp_conn_pool->last_group_name_received()); + if (tests[i].ssl) + EXPECT_EQ(tests[i].expected_group_name, + ssl_conn_pool->last_group_name_received()); + else + EXPECT_EQ(tests[i].expected_group_name, + tcp_conn_pool->last_group_name_received()); } HttpNetworkTransaction::SetUseAlternateProtocols(false); @@ -4066,6 +4100,7 @@ TEST_F(HttpNetworkTransactionTest, GroupNameForHTTPProxyConnections) { "http_proxy", "http://www.google.com/http_proxy_normal", "www.google.com:80", + false, }, // SSL Tests @@ -4073,12 +4108,14 @@ TEST_F(HttpNetworkTransactionTest, GroupNameForHTTPProxyConnections) { "http_proxy", "https://www.google.com/http_connect_ssl", "ssl/www.google.com:443", + true, }, { "http_proxy", "http://host.with.alternate/direct", "ssl/host.with.alternate:443", + true, }, }; @@ -4090,15 +4127,22 @@ TEST_F(HttpNetworkTransactionTest, GroupNameForHTTPProxyConnections) { HttpNetworkSessionPeer peer(session); + HostPortPair proxy_host("http_proxy", 80); scoped_refptr http_proxy_pool( new CaptureGroupNameHttpProxySocketPool(session.get())); - peer.SetSocketPoolForHTTPProxy( - HostPortPair("http_proxy", 80), http_proxy_pool); + peer.SetSocketPoolForHTTPProxy(proxy_host, http_proxy_pool); + scoped_refptr ssl_conn_pool( + new CaptureGroupNameSSLSocketPool(session.get())); + peer.SetSocketPoolForSSLWithProxy(proxy_host, ssl_conn_pool); EXPECT_EQ(ERR_IO_PENDING, GroupNameTransactionHelper(tests[i].url, session)); - EXPECT_EQ(tests[i].expected_group_name, - http_proxy_pool->last_group_name_received()); + if (tests[i].ssl) + EXPECT_EQ(tests[i].expected_group_name, + ssl_conn_pool->last_group_name_received()); + else + EXPECT_EQ(tests[i].expected_group_name, + http_proxy_pool->last_group_name_received()); } HttpNetworkTransaction::SetUseAlternateProtocols(false); @@ -4110,11 +4154,13 @@ TEST_F(HttpNetworkTransactionTest, GroupNameForSOCKSConnections) { "socks4://socks_proxy:1080", "http://www.google.com/socks4_direct", "socks4/www.google.com:80", + false, }, { "socks5://socks_proxy:1080", "http://www.google.com/socks5_direct", "socks5/www.google.com:80", + false, }, // SSL Tests @@ -4122,17 +4168,20 @@ TEST_F(HttpNetworkTransactionTest, GroupNameForSOCKSConnections) { "socks4://socks_proxy:1080", "https://www.google.com/socks4_ssl", "socks4/ssl/www.google.com:443", + true, }, { "socks5://socks_proxy:1080", "https://www.google.com/socks5_ssl", "socks5/ssl/www.google.com:443", + true, }, { "socks4://socks_proxy:1080", "http://host.with.alternate/direct", "socks4/ssl/host.with.alternate:443", + true, }, }; @@ -4143,17 +4192,24 @@ TEST_F(HttpNetworkTransactionTest, GroupNameForSOCKSConnections) { SetupSessionForGroupNameTests(tests[i].proxy_server)); HttpNetworkSessionPeer peer(session); + HostPortPair proxy_host("socks_proxy", 1080); scoped_refptr socks_conn_pool( new CaptureGroupNameSOCKSSocketPool(session.get())); - peer.SetSocketPoolForSOCKSProxy( - HostPortPair("socks_proxy", 1080), socks_conn_pool); + peer.SetSocketPoolForSOCKSProxy(proxy_host, socks_conn_pool); + scoped_refptr ssl_conn_pool( + new CaptureGroupNameSSLSocketPool(session.get())); + peer.SetSocketPoolForSSLWithProxy(proxy_host, ssl_conn_pool); scoped_ptr trans(new HttpNetworkTransaction(session)); EXPECT_EQ(ERR_IO_PENDING, GroupNameTransactionHelper(tests[i].url, session)); - EXPECT_EQ(tests[i].expected_group_name, - socks_conn_pool->last_group_name_received()); + if (tests[i].ssl) + EXPECT_EQ(tests[i].expected_group_name, + ssl_conn_pool->last_group_name_received()); + else + EXPECT_EQ(tests[i].expected_group_name, + socks_conn_pool->last_group_name_received()); } HttpNetworkTransaction::SetUseAlternateProtocols(false); @@ -5869,6 +5925,9 @@ TEST_F(HttpNetworkTransactionTest, GenerateAuthToken) { } } } + + // Flush the idle socket before the HttpNetworkTransaction goes out of scope. + session->FlushSocketPools(); } class TLSDecompressionFailureSocketDataProvider : public SocketDataProvider { @@ -5919,6 +5978,11 @@ TEST_F(HttpNetworkTransactionTest, RestartAfterTLSDecompressionFailure) { session_deps.socket_factory.AddSSLSocketDataProvider( &ssl_socket_data_provider2); + // Work around http://crbug.com/37454 + StaticSocketDataProvider bug37454_connection; + bug37454_connection.set_connect_data(MockConnect(true, ERR_UNEXPECTED)); + session_deps.socket_factory.AddSocketDataProvider(&bug37454_connection); + scoped_refptr session(CreateSession(&session_deps)); scoped_ptr trans(new HttpNetworkTransaction(session)); TestCompletionCallback callback; diff --git a/net/http/http_proxy_client_socket.cc b/net/http/http_proxy_client_socket.cc index df64589..ec4b753 100644 --- a/net/http/http_proxy_client_socket.cc +++ b/net/http/http_proxy_client_socket.cc @@ -159,12 +159,15 @@ void HttpProxyClientSocket::Disconnect() { } bool HttpProxyClientSocket::IsConnected() const { - return next_state_ == STATE_DONE && transport_->socket()->IsConnected(); + return transport_->socket()->IsConnected(); } bool HttpProxyClientSocket::IsConnectedAndIdle() const { - return next_state_ == STATE_DONE - && transport_->socket()->IsConnectedAndIdle(); + return transport_->socket()->IsConnectedAndIdle(); +} + +bool HttpProxyClientSocket::NeedsRestartWithAuth() const { + return next_state_ != STATE_DONE; } int HttpProxyClientSocket::Read(IOBuffer* buf, int buf_len, @@ -336,11 +339,8 @@ int HttpProxyClientSocket::DoReadHeaders() { } int HttpProxyClientSocket::DoReadHeadersComplete(int result) { - if (result < 0) { - if (result == ERR_CONNECTION_CLOSED) - result = ERR_TUNNEL_CONNECTION_FAILED; + if (result < 0) return result; - } // Require the "HTTP/1.x" status line for SSL CONNECT. if (response_.headers->GetParsedHttpVersion() < HttpVersion(1, 0)) diff --git a/net/http/http_proxy_client_socket.h b/net/http/http_proxy_client_socket.h index 692cc19e..61e8158 100644 --- a/net/http/http_proxy_client_socket.h +++ b/net/http/http_proxy_client_socket.h @@ -45,6 +45,10 @@ class HttpProxyClientSocket : public ClientSocket { // RestartWithAuth. int RestartWithAuth(CompletionCallback* callback); + // Indicates if RestartWithAuth needs to be called. i.e. if Connect + // returned PROXY_AUTH_REQUESTED. Only valid after Connect has been called. + bool NeedsRestartWithAuth() const; + const HttpResponseInfo* GetResponseInfo() const { return response_.headers ? &response_ : NULL; } diff --git a/net/http/http_proxy_client_socket_pool.h b/net/http/http_proxy_client_socket_pool.h index 7a40424..a23318f 100644 --- a/net/http/http_proxy_client_socket_pool.h +++ b/net/http/http_proxy_client_socket_pool.h @@ -13,6 +13,7 @@ #include "base/time.h" #include "net/base/host_port_pair.h" #include "net/base/host_resolver.h" +#include "net/http/http_auth.h" #include "net/proxy/proxy_server.h" #include "net/socket/client_socket_pool_base.h" #include "net/socket/client_socket_pool_histograms.h" @@ -37,7 +38,7 @@ class HttpProxySocketParams : public base::RefCounted { } const GURL& request_url() const { return request_url_; } const HostPortPair& endpoint() const { return endpoint_; } - const scoped_refptr& auth_controller() const { + const scoped_refptr& auth_controller() { return auth_controller_; } bool tunnel() const { return tunnel_; } @@ -51,6 +52,8 @@ class HttpProxySocketParams : public base::RefCounted { const HostPortPair endpoint_; const scoped_refptr auth_controller_; const bool tunnel_; + + DISALLOW_COPY_AND_ASSIGN(HttpProxySocketParams); }; // HttpProxyConnectJob optionally establishes a tunnel through the proxy diff --git a/net/http/http_proxy_client_socket_pool_unittest.cc b/net/http/http_proxy_client_socket_pool_unittest.cc index 228b6a8..9400dd8 100644 --- a/net/http/http_proxy_client_socket_pool_unittest.cc +++ b/net/http/http_proxy_client_socket_pool_unittest.cc @@ -6,16 +6,9 @@ #include "base/callback.h" #include "base/compiler_specific.h" -#include "base/time.h" -#include "net/base/auth.h" -#include "net/base/mock_host_resolver.h" #include "net/base/net_errors.h" #include "net/base/test_completion_callback.h" -#include "net/http/http_auth_controller.h" -#include "net/http/http_network_session.h" -#include "net/http/http_request_headers.h" -#include "net/http/http_response_headers.h" -#include "net/socket/client_socket_factory.h" +#include "net/http/http_proxy_client_socket.h" #include "net/socket/client_socket_handle.h" #include "net/socket/client_socket_pool_histograms.h" #include "net/socket/socket_test_util.h" @@ -28,60 +21,6 @@ namespace { const int kMaxSockets = 32; const int kMaxSocketsPerGroup = 6; -struct MockHttpAuthControllerData { - MockHttpAuthControllerData(std::string header) : auth_header(header) {} - - std::string auth_header; -}; - -class MockHttpAuthController : public HttpAuthController { - public: - MockHttpAuthController() - : HttpAuthController(HttpAuth::AUTH_PROXY, GURL(), - scoped_refptr(NULL)), - data_(NULL), - data_index_(0), - data_count_(0) { - } - - void SetMockAuthControllerData(struct MockHttpAuthControllerData* data, - size_t data_length) { - data_ = data; - data_count_ = data_length; - } - - // HttpAuthController methods. - virtual int MaybeGenerateAuthToken(const HttpRequestInfo* request, - CompletionCallback* callback, - const BoundNetLog& net_log) { - return OK; - } - virtual void AddAuthorizationHeader( - HttpRequestHeaders* authorization_headers) { - authorization_headers->AddHeadersFromString(CurrentData().auth_header); - } - virtual int HandleAuthChallenge(scoped_refptr headers, - bool do_not_send_server_auth, - bool establishing_tunnel, - const BoundNetLog& net_log) { - return OK; - } - virtual bool HaveAuthHandler() const { return HaveAuth(); } - virtual bool HaveAuth() const { - return CurrentData().auth_header.size() != 0; } - - private: - virtual ~MockHttpAuthController() {} - const struct MockHttpAuthControllerData& CurrentData() const { - DCHECK(data_index_ < data_count_); - return data_[data_index_]; - } - - MockHttpAuthControllerData* data_; - size_t data_index_; - size_t data_count_; -}; - class HttpProxyClientSocketPoolTest : public ClientSocketPoolTest { protected: HttpProxyClientSocketPoolTest() @@ -131,6 +70,9 @@ TEST_F(HttpProxyClientSocketPoolTest, NoTunnel) { EXPECT_EQ(OK, rv); EXPECT_TRUE(handle.is_initialized()); EXPECT_TRUE(handle.socket()); + HttpProxyClientSocket* tunnel_socket = + static_cast(handle.socket()); + EXPECT_FALSE(tunnel_socket->NeedsRestartWithAuth()); } TEST_F(HttpProxyClientSocketPoolTest, NeedAuth) { @@ -166,6 +108,9 @@ TEST_F(HttpProxyClientSocketPoolTest, NeedAuth) { EXPECT_EQ(ERR_PROXY_AUTH_REQUESTED, callback.WaitForResult()); EXPECT_TRUE(handle.is_initialized()); EXPECT_TRUE(handle.socket()); + HttpProxyClientSocket* tunnel_socket = + static_cast(handle.socket()); + EXPECT_TRUE(tunnel_socket->NeedsRestartWithAuth()); } TEST_F(HttpProxyClientSocketPoolTest, HaveAuth) { @@ -196,6 +141,9 @@ TEST_F(HttpProxyClientSocketPoolTest, HaveAuth) { EXPECT_EQ(OK, rv); EXPECT_TRUE(handle.is_initialized()); EXPECT_TRUE(handle.socket()); + HttpProxyClientSocket* tunnel_socket = + static_cast(handle.socket()); + EXPECT_FALSE(tunnel_socket->NeedsRestartWithAuth()); } TEST_F(HttpProxyClientSocketPoolTest, AsyncHaveAuth) { @@ -228,6 +176,9 @@ TEST_F(HttpProxyClientSocketPoolTest, AsyncHaveAuth) { EXPECT_EQ(OK, callback.WaitForResult()); EXPECT_TRUE(handle.is_initialized()); EXPECT_TRUE(handle.socket()); + HttpProxyClientSocket* tunnel_socket = + static_cast(handle.socket()); + EXPECT_FALSE(tunnel_socket->NeedsRestartWithAuth()); } TEST_F(HttpProxyClientSocketPoolTest, TCPError) { @@ -277,7 +228,7 @@ TEST_F(HttpProxyClientSocketPoolTest, TunnelUnexpectedClose) { EXPECT_FALSE(handle.is_initialized()); EXPECT_FALSE(handle.socket()); - EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, callback.WaitForResult()); + EXPECT_EQ(ERR_CONNECTION_CLOSED, callback.WaitForResult()); EXPECT_FALSE(handle.is_initialized()); EXPECT_FALSE(handle.socket()); } -- cgit v1.1