From 102e27c64d9deae4c32f346214fd7c2bddaa9fb3 Mon Sep 17 00:00:00 2001 From: "willchan@chromium.org" Date: Wed, 23 Feb 2011 01:01:31 +0000 Subject: Refactor HttpStreamFactory. Rename StreamFactory and StreamRequest to HttpStreamFactory and HttpStreamRequest. Rename HttpStreamFactory to HttpStreamFactoryImpl. Create HttpStreamFactoryImpl::Request (inherits from HttpStreamRequest) and HttpStreamFactoryImpl::Job (most of the old HttpStreamRequest code, other than the interface, moved here). Currently there is still a strong binding within HttpStreamFactoryImpl between requests and jobs. This will be removed in a future changelist. Note that due to the preparation for late binding, information like HttpRequestInfo and SSLConfig and ProxyInfo are just copied. It's possible we can consider refcounting them to reduce copies, but I think it's not worth the effort / ugliness. I also did some minor cleanups like moving SpdySettingsStorage into SpdySessionPool and some CloseIdleConnections() cleanup. BUG=54371,42669 TEST=unit tests Committed: http://src.chromium.org/viewvc/chrome?view=rev&revision=75668 Review URL: http://codereview.chromium.org/6543004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@75688 0039d316-1c4b-4281-b951-d872f2087c98 --- net/http/http_cache.cc | 9 +- net/http/http_cache.h | 2 +- net/http/http_network_layer.cc | 2 +- net/http/http_network_session.cc | 13 +- net/http/http_network_session.h | 39 +- net/http/http_network_session_peer.cc | 6 + net/http/http_network_session_peer.h | 3 + net/http/http_network_transaction.cc | 39 +- net/http/http_network_transaction.h | 27 +- net/http/http_network_transaction_unittest.cc | 12 +- net/http/http_proxy_client_socket_pool.cc | 6 +- net/http/http_proxy_client_socket_pool.h | 6 - net/http/http_proxy_client_socket_pool_unittest.cc | 17 +- net/http/http_stream_factory.cc | 107 +- net/http/http_stream_factory.h | 213 +++- net/http/http_stream_factory_impl.cc | 299 ++++++ net/http/http_stream_factory_impl.h | 94 ++ net/http/http_stream_factory_impl_job.cc | 1071 +++++++++++++++++++ net/http/http_stream_factory_impl_job.h | 232 ++++ net/http/http_stream_factory_impl_unittest.cc | 320 ++++++ net/http/http_stream_factory_unittest.cc | 290 ----- net/http/http_stream_request.cc | 1105 -------------------- net/http/http_stream_request.h | 252 ----- net/http/stream_factory.h | 156 --- net/net.gyp | 9 +- net/socket/client_socket_pool_manager.cc | 49 + net/socket/client_socket_pool_manager.h | 1 + net/socket/ssl_client_socket_pool_unittest.cc | 18 +- net/spdy/spdy_http_stream_unittest.cc | 3 +- net/spdy/spdy_network_transaction_unittest.cc | 19 +- net/spdy/spdy_proxy_client_socket_unittest.cc | 17 +- net/spdy/spdy_session_pool.cc | 6 +- net/spdy/spdy_session_pool.h | 9 +- net/spdy/spdy_session_unittest.cc | 27 +- net/spdy/spdy_stream_unittest.cc | 4 +- 35 files changed, 2418 insertions(+), 2064 deletions(-) create mode 100644 net/http/http_stream_factory_impl.cc create mode 100644 net/http/http_stream_factory_impl.h create mode 100644 net/http/http_stream_factory_impl_job.cc create mode 100644 net/http/http_stream_factory_impl_job.h create mode 100644 net/http/http_stream_factory_impl_unittest.cc delete mode 100644 net/http/http_stream_factory_unittest.cc delete mode 100644 net/http/http_stream_request.cc delete mode 100644 net/http/http_stream_request.h delete mode 100644 net/http/stream_factory.h (limited to 'net') diff --git a/net/http/http_cache.cc b/net/http/http_cache.cc index 7c35f69..a821a30 100644 --- a/net/http/http_cache.cc +++ b/net/http/http_cache.cc @@ -451,15 +451,12 @@ void HttpCache::WriteMetadata(const GURL& url, writer->Write(url, expected_response_time, buf, buf_len); } -void HttpCache::CloseCurrentConnections() { +void HttpCache::CloseAllConnections() { net::HttpNetworkLayer* network = static_cast(network_layer_.get()); HttpNetworkSession* session = network->GetSession(); - if (session) { - session->FlushSocketPools(); - if (session->spdy_session_pool()) - session->spdy_session_pool()->CloseCurrentSessions(); - } + if (session) + session->CloseAllConnections(); } int HttpCache::CreateTransaction(scoped_ptr* trans) { diff --git a/net/http/http_cache.h b/net/http/http_cache.h index cdbddfe..ba7a18e 100644 --- a/net/http/http_cache.h +++ b/net/http/http_cache.h @@ -176,7 +176,7 @@ class HttpCache : public HttpTransactionFactory, // Close currently active sockets so that fresh page loads will not use any // recycled connections. For sockets currently in use, they may not close // immediately, but they will not be reusable. This is for debugging. - void CloseCurrentConnections(); + void CloseAllConnections(); // HttpTransactionFactory implementation: virtual int CreateTransaction(scoped_ptr* trans); diff --git a/net/http/http_network_layer.cc b/net/http/http_network_layer.cc index e979ad0..0fb1050 100644 --- a/net/http/http_network_layer.cc +++ b/net/http/http_network_layer.cc @@ -156,7 +156,7 @@ void HttpNetworkLayer::Suspend(bool suspend) { suspended_ = suspend; if (suspend && session_) - session_->tcp_socket_pool()->CloseIdleSockets(); + session_->CloseIdleConnections(); } } // namespace net diff --git a/net/http/http_network_session.cc b/net/http/http_network_session.cc index b50b6e9..e67390c 100644 --- a/net/http/http_network_session.cc +++ b/net/http/http_network_session.cc @@ -6,13 +6,16 @@ #include +#include "base/compiler_specific.h" #include "base/logging.h" #include "base/stl_util-inl.h" #include "base/string_util.h" #include "base/values.h" #include "net/http/http_auth_handler_factory.h" #include "net/http/http_response_body_drainer.h" +#include "net/http/http_stream_factory_impl.h" #include "net/http/url_security_manager.h" +#include "net/proxy/proxy_service.h" #include "net/socket/client_socket_factory.h" #include "net/spdy/spdy_session_pool.h" @@ -20,7 +23,10 @@ namespace net { // TODO(mbelshe): Move the socket factories into HttpStreamFactory. HttpNetworkSession::HttpNetworkSession(const Params& params) - : cert_verifier_(NULL), + : net_log_(params.net_log), + network_delegate_(params.network_delegate), + cert_verifier_(params.cert_verifier), + http_auth_handler_factory_(params.http_auth_handler_factory), proxy_service_(params.proxy_service), ssl_config_service_(params.ssl_config_service), socket_pool_manager_(params.net_log, @@ -35,9 +41,8 @@ HttpNetworkSession::HttpNetworkSession(const Params& params) params.proxy_service, params.ssl_config_service), spdy_session_pool_(params.ssl_config_service), - http_auth_handler_factory_(params.http_auth_handler_factory), - network_delegate_(params.network_delegate), - net_log_(params.net_log) { + ALLOW_THIS_IN_INITIALIZER_LIST(http_stream_factory_( + new HttpStreamFactoryImpl(this))) { DCHECK(params.proxy_service); DCHECK(params.ssl_config_service); } diff --git a/net/http/http_network_session.h b/net/http/http_network_session.h index 36cb652..5c8f705 100644 --- a/net/http/http_network_session.h +++ b/net/http/http_network_session.h @@ -71,7 +71,7 @@ class HttpNetworkSession : public base::RefCounted, explicit HttpNetworkSession(const Params& params); - HttpAuthCache* auth_cache() { return &auth_cache_; } + HttpAuthCache* http_auth_cache() { return &http_auth_cache_; } SSLClientAuthCache* ssl_client_auth_cache() { return &ssl_client_auth_cache_; } @@ -87,14 +87,6 @@ class HttpNetworkSession : public base::RefCounted, return &alternate_protocols_; } - // Access to the SpdySettingsStorage - const SpdySettingsStorage& spdy_settings() const { - return spdy_settings_; - } - SpdySettingsStorage* mutable_spdy_settings() { - return &spdy_settings_; - } - TCPClientSocketPool* tcp_socket_pool() { return socket_pool_manager_.tcp_socket_pool(); } @@ -130,7 +122,7 @@ class HttpNetworkSession : public base::RefCounted, } HttpStreamFactory* http_stream_factory() { - return &http_stream_factory_; + return http_stream_factory_.get(); } NetLog* net_log() { @@ -147,30 +139,37 @@ class HttpNetworkSession : public base::RefCounted, // responsible for deleting the returned value. Value* SpdySessionPoolInfoToValue() const; - void FlushSocketPools() { + void CloseAllConnections() { socket_pool_manager_.FlushSocketPools(); + spdy_session_pool_.CloseCurrentSessions(); + } + + void CloseIdleConnections() { + socket_pool_manager_.CloseIdleSockets(); } + private: friend class base::RefCounted; friend class HttpNetworkSessionPeer; ~HttpNetworkSession(); - HttpAuthCache auth_cache_; - SSLClientAuthCache ssl_client_auth_cache_; - HttpAlternateProtocols alternate_protocols_; - CertVerifier* cert_verifier_; + NetLog* const net_log_; + HttpNetworkDelegate* const network_delegate_; + CertVerifier* const cert_verifier_; + HttpAuthHandlerFactory* const http_auth_handler_factory_; + // Not const since it's modified by HttpNetworkSessionPeer for testing. scoped_refptr proxy_service_; const scoped_refptr ssl_config_service_; + + HttpAuthCache http_auth_cache_; + SSLClientAuthCache ssl_client_auth_cache_; + HttpAlternateProtocols alternate_protocols_; ClientSocketPoolManager socket_pool_manager_; SpdySessionPool spdy_session_pool_; - HttpStreamFactory http_stream_factory_; - HttpAuthHandlerFactory* const http_auth_handler_factory_; - HttpNetworkDelegate* const network_delegate_; - NetLog* const net_log_; - SpdySettingsStorage spdy_settings_; + scoped_ptr http_stream_factory_; std::set response_drainers_; }; diff --git a/net/http/http_network_session_peer.cc b/net/http/http_network_session_peer.cc index 7bb342c..2ed3e76 100644 --- a/net/http/http_network_session_peer.cc +++ b/net/http/http_network_session_peer.cc @@ -6,6 +6,7 @@ #include "net/http/http_network_session.h" #include "net/http/http_proxy_client_socket_pool.h" +#include "net/proxy/proxy_service.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" @@ -66,4 +67,9 @@ void HttpNetworkSessionPeer::SetProxyService(ProxyService* proxy_service) { session_->proxy_service_ = proxy_service; } +void HttpNetworkSessionPeer::SetHttpStreamFactory( + HttpStreamFactory* http_stream_factory) { + session_->http_stream_factory_.reset(http_stream_factory); +} + } // namespace net diff --git a/net/http/http_network_session_peer.h b/net/http/http_network_session_peer.h index 398488b..06101ca 100644 --- a/net/http/http_network_session_peer.h +++ b/net/http/http_network_session_peer.h @@ -13,6 +13,7 @@ namespace net { class HostPortPair; class HttpNetworkSession; class HttpProxyClientSocketPool; +class HttpStreamFactory; class ProxyService; class SOCKSClientSocketPool; class SSLClientSocketPool; @@ -42,6 +43,8 @@ class HttpNetworkSessionPeer { void SetProxyService(ProxyService* proxy_service); + void SetHttpStreamFactory(HttpStreamFactory* http_stream_factory); + private: const scoped_refptr session_; diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc index 128497f..98b9cd7 100644 --- a/net/http/http_network_transaction.cc +++ b/net/http/http_network_transaction.cc @@ -42,7 +42,7 @@ #include "net/http/http_response_body_drainer.h" #include "net/http/http_response_headers.h" #include "net/http/http_response_info.h" -#include "net/http/http_stream_request.h" +#include "net/http/http_stream_factory.h" #include "net/http/http_util.h" #include "net/http/url_security_manager.h" #include "net/socket/client_socket_factory.h" @@ -359,11 +359,15 @@ uint64 HttpNetworkTransaction::GetUploadProgress() const { return stream_->GetUploadProgress(); } -void HttpNetworkTransaction::OnStreamReady(HttpStream* stream) { +void HttpNetworkTransaction::OnStreamReady(const SSLConfig& used_ssl_config, + const ProxyInfo& used_proxy_info, + HttpStream* stream) { DCHECK_EQ(STATE_CREATE_STREAM_COMPLETE, next_state_); DCHECK(stream_request_.get()); stream_.reset(stream); + ssl_config_ = used_ssl_config; + proxy_info_ = used_proxy_info; response_.was_alternate_protocol_available = stream_request_->was_alternate_protocol_available(); response_.was_npn_negotiated = stream_request_->was_npn_negotiated(); @@ -373,23 +377,28 @@ void HttpNetworkTransaction::OnStreamReady(HttpStream* stream) { OnIOComplete(OK); } -void HttpNetworkTransaction::OnStreamFailed(int result) { +void HttpNetworkTransaction::OnStreamFailed(int result, + const SSLConfig& used_ssl_config) { DCHECK_EQ(STATE_CREATE_STREAM_COMPLETE, next_state_); DCHECK_NE(OK, result); DCHECK(stream_request_.get()); DCHECK(!stream_.get()); + ssl_config_ = used_ssl_config; OnIOComplete(result); } -void HttpNetworkTransaction::OnCertificateError(int result, - const SSLInfo& ssl_info) { +void HttpNetworkTransaction::OnCertificateError( + int result, + const SSLConfig& used_ssl_config, + const SSLInfo& ssl_info) { DCHECK_EQ(STATE_CREATE_STREAM_COMPLETE, next_state_); DCHECK_NE(OK, result); DCHECK(stream_request_.get()); DCHECK(!stream_.get()); response_.ssl_info = ssl_info; + ssl_config_ = used_ssl_config; // TODO(mbelshe): For now, we're going to pass the error through, and that // will close the stream_request in all cases. This means that we're always @@ -402,6 +411,8 @@ void HttpNetworkTransaction::OnCertificateError(int result, void HttpNetworkTransaction::OnNeedsProxyAuth( const HttpResponseInfo& proxy_response, + const SSLConfig& used_ssl_config, + const ProxyInfo& used_proxy_info, HttpAuthController* auth_controller) { DCHECK(stream_request_.get()); DCHECK_EQ(STATE_CREATE_STREAM_COMPLETE, next_state_); @@ -410,6 +421,8 @@ void HttpNetworkTransaction::OnNeedsProxyAuth( response_.headers = proxy_response.headers; response_.auth_challenge = proxy_response.auth_challenge; headers_valid_ = true; + ssl_config_ = used_ssl_config; + proxy_info_ = used_proxy_info; auth_controllers_[HttpAuth::AUTH_PROXY] = auth_controller; pending_auth_target_ = HttpAuth::AUTH_PROXY; @@ -418,20 +431,26 @@ void HttpNetworkTransaction::OnNeedsProxyAuth( } void HttpNetworkTransaction::OnNeedsClientAuth( + const SSLConfig& used_ssl_config, SSLCertRequestInfo* cert_info) { DCHECK_EQ(STATE_CREATE_STREAM_COMPLETE, next_state_); + ssl_config_ = used_ssl_config; response_.cert_request_info = cert_info; OnIOComplete(ERR_SSL_CLIENT_AUTH_CERT_NEEDED); } void HttpNetworkTransaction::OnHttpsProxyTunnelResponse( const HttpResponseInfo& response_info, + const SSLConfig& used_ssl_config, + const ProxyInfo& used_proxy_info, HttpStream* stream) { DCHECK_EQ(STATE_CREATE_STREAM_COMPLETE, next_state_); headers_valid_ = true; response_ = response_info; + ssl_config_ = used_ssl_config; + proxy_info_ = used_proxy_info; stream_.reset(stream); stream_request_.reset(); // we're done with the stream request OnIOComplete(ERR_HTTPS_PROXY_TUNNEL_RESPONSE); @@ -549,10 +568,8 @@ int HttpNetworkTransaction::DoCreateStream() { stream_request_.reset( session_->http_stream_factory()->RequestStream( - request_, - &ssl_config_, - &proxy_info_, - session_, + *request_, + ssl_config_, this, net_log_)); DCHECK(stream_request_.get()); @@ -609,7 +626,7 @@ int HttpNetworkTransaction::DoGenerateProxyAuthToken() { auth_controllers_[target] = new HttpAuthController(target, AuthURL(target), - session_->auth_cache(), + session_->http_auth_cache(), session_->http_auth_handler_factory()); return auth_controllers_[target]->MaybeGenerateAuthToken(request_, &io_callback_, @@ -630,7 +647,7 @@ int HttpNetworkTransaction::DoGenerateServerAuthToken() { auth_controllers_[target] = new HttpAuthController(target, AuthURL(target), - session_->auth_cache(), + session_->http_auth_cache(), session_->http_auth_handler_factory()); if (!ShouldApplyServerAuth()) return OK; diff --git a/net/http/http_network_transaction.h b/net/http/http_network_transaction.h index 66b6b29..3cec010 100644 --- a/net/http/http_network_transaction.h +++ b/net/http/http_network_transaction.h @@ -19,8 +19,8 @@ #include "net/http/http_auth.h" #include "net/http/http_request_headers.h" #include "net/http/http_response_info.h" +#include "net/http/http_stream_factory.h" #include "net/http/http_transaction.h" -#include "net/http/stream_factory.h" #include "net/proxy/proxy_service.h" namespace net { @@ -33,7 +33,7 @@ class IOBuffer; struct HttpRequestInfo; class HttpNetworkTransaction : public HttpTransaction, - public StreamRequest::Delegate { + public HttpStreamRequest::Delegate { public: explicit HttpNetworkTransaction(HttpNetworkSession* session); @@ -57,15 +57,25 @@ class HttpNetworkTransaction : public HttpTransaction, virtual LoadState GetLoadState() const; virtual uint64 GetUploadProgress() const; - // StreamRequest::Delegate methods: - virtual void OnStreamReady(HttpStream* stream); - virtual void OnStreamFailed(int status); - virtual void OnCertificateError(int status, const SSLInfo& ssl_info); + // HttpStreamRequest::Delegate methods: + virtual void OnStreamReady(const SSLConfig& used_ssl_config, + const ProxyInfo& used_proxy_info, + HttpStream* stream); + virtual void OnStreamFailed(int status, + const SSLConfig& used_ssl_config); + virtual void OnCertificateError(int status, + const SSLConfig& used_ssl_config, + const SSLInfo& ssl_info); virtual void OnNeedsProxyAuth( const HttpResponseInfo& response_info, + const SSLConfig& used_ssl_config, + const ProxyInfo& used_proxy_info, HttpAuthController* auth_controller); - virtual void OnNeedsClientAuth(SSLCertRequestInfo* cert_info); + virtual void OnNeedsClientAuth(const SSLConfig& used_ssl_config, + SSLCertRequestInfo* cert_info); virtual void OnHttpsProxyTunnelResponse(const HttpResponseInfo& response_info, + const SSLConfig& used_ssl_config, + const ProxyInfo& used_proxy_info, HttpStream* stream); private: @@ -215,9 +225,10 @@ class HttpNetworkTransaction : public HttpTransaction, const HttpRequestInfo* request_; HttpResponseInfo response_; + // |proxy_info_| is the ProxyInfo used by the HttpStreamRequest. ProxyInfo proxy_info_; - scoped_ptr stream_request_; + scoped_ptr stream_request_; scoped_ptr stream_; // True if we've validated the headers that the stream parser has returned. diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc index e54edf5..ecd6132 100644 --- a/net/http/http_network_transaction_unittest.cc +++ b/net/http/http_network_transaction_unittest.cc @@ -1581,7 +1581,7 @@ TEST_F(HttpNetworkTransactionTest, BasicAuthProxyNoKeepAlive) { EXPECT_TRUE(response->auth_challenge.get() == NULL); trans.reset(); - session->FlushSocketPools(); + session->CloseAllConnections(); } // Test the request-challenge-retry sequence for basic auth, over a keep-alive @@ -1695,7 +1695,7 @@ TEST_F(HttpNetworkTransactionTest, BasicAuthProxyKeepAlive) { // Flush the idle socket before the NetLog and HttpNetworkTransaction go // out of scope. - session->FlushSocketPools(); + session->CloseAllConnections(); } // Test that we don't read the response body when we fail to establish a tunnel, @@ -1753,7 +1753,7 @@ TEST_F(HttpNetworkTransactionTest, BasicAuthProxyCancelTunnel) { EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, rv); // Flush the idle socket before the HttpNetworkTransaction goes out of scope. - session->FlushSocketPools(); + session->CloseAllConnections(); } // Test when a server (non-proxy) returns a 407 (proxy-authenticate). @@ -6923,8 +6923,7 @@ TEST_F(HttpNetworkTransactionTest, HostPortPair host_port_pair("www.google.com", 443); HostPortProxyPair pair(host_port_pair, ProxyServer::Direct()); scoped_refptr spdy_session = - session->spdy_session_pool()->Get(pair, session->mutable_spdy_settings(), - BoundNetLog()); + session->spdy_session_pool()->Get(pair, BoundNetLog()); scoped_refptr tcp_params( new TCPSocketParams("www.google.com", 443, MEDIUM, GURL(), false)); @@ -8167,8 +8166,7 @@ TEST_F(HttpNetworkTransactionTest, PreconnectWithExistingSpdySession) { HostPortPair host_port_pair("www.google.com", 443); HostPortProxyPair pair(host_port_pair, ProxyServer::Direct()); scoped_refptr spdy_session = - session->spdy_session_pool()->Get(pair, session->mutable_spdy_settings(), - BoundNetLog()); + session->spdy_session_pool()->Get(pair, BoundNetLog()); scoped_refptr tcp_params( new TCPSocketParams("www.google.com", 443, MEDIUM, GURL(), false)); TestCompletionCallback callback; diff --git a/net/http/http_proxy_client_socket_pool.cc b/net/http/http_proxy_client_socket_pool.cc index 3129133..13d6286 100644 --- a/net/http/http_proxy_client_socket_pool.cc +++ b/net/http/http_proxy_client_socket_pool.cc @@ -36,12 +36,10 @@ HttpProxySocketParams::HttpProxySocketParams( 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), @@ -291,11 +289,11 @@ int HttpProxyConnectJob::DoSpdyProxyCreateStream() { transport_socket_handle_->socket()->Disconnect(); transport_socket_handle_->Reset(); } - spdy_session = spdy_pool->Get(pair, params_->spdy_settings(), net_log()); + spdy_session = spdy_pool->Get(pair, net_log()); } else { // Create a session direct to the proxy itself int rv = spdy_pool->GetSpdySessionFromSocket( - pair, params_->spdy_settings(), transport_socket_handle_.release(), + pair, transport_socket_handle_.release(), net_log(), OK, &spdy_session, /*using_ssl_*/ true); if (rv < 0) return rv; diff --git a/net/http/http_proxy_client_socket_pool.h b/net/http/http_proxy_client_socket_pool.h index 4757b27..4ae07cf 100644 --- a/net/http/http_proxy_client_socket_pool.h +++ b/net/http/http_proxy_client_socket_pool.h @@ -28,7 +28,6 @@ class HttpAuthHandlerFactory; class SSLClientSocketPool; class SSLSocketParams; class SpdySessionPool; -class SpdySettingsStorage; class SpdyStream; class TCPClientSocketPool; class TCPSocketParams; @@ -47,7 +46,6 @@ class HttpProxySocketParams : public base::RefCounted { HttpAuthCache* http_auth_cache, HttpAuthHandlerFactory* http_auth_handler_factory, SpdySessionPool* spdy_session_pool, - SpdySettingsStorage* spdy_settings, bool tunnel); const scoped_refptr& tcp_params() const { @@ -66,9 +64,6 @@ class HttpProxySocketParams : public base::RefCounted { SpdySessionPool* spdy_session_pool() { return spdy_session_pool_; } - SpdySettingsStorage* spdy_settings() { - return spdy_settings_; - } const HostResolver::RequestInfo& destination() const; bool tunnel() const { return tunnel_; } @@ -79,7 +74,6 @@ class HttpProxySocketParams : public base::RefCounted { const scoped_refptr tcp_params_; const scoped_refptr ssl_params_; SpdySessionPool* spdy_session_pool_; - SpdySettingsStorage* spdy_settings_; const GURL request_url_; const std::string user_agent_; const HostPortPair endpoint_; diff --git a/net/http/http_proxy_client_socket_pool_unittest.cc b/net/http/http_proxy_client_socket_pool_unittest.cc index 359a058..5830b3a7 100644 --- a/net/http/http_proxy_client_socket_pool_unittest.cc +++ b/net/http/http_proxy_client_socket_pool_unittest.cc @@ -94,13 +94,13 @@ class HttpProxyClientSocketPoolTest : public TestWithHttpParam { void AddAuthToCache() { const string16 kFoo(ASCIIToUTF16("foo")); const string16 kBar(ASCIIToUTF16("bar")); - session_->auth_cache()->Add(GURL("http://proxy/"), - "MyRealm1", - HttpAuth::AUTH_SCHEME_BASIC, - "Basic realm=MyRealm1", - kFoo, - kBar, - "/"); + session_->http_auth_cache()->Add(GURL("http://proxy/"), + "MyRealm1", + HttpAuth::AUTH_SCHEME_BASIC, + "Basic realm=MyRealm1", + kFoo, + kBar, + "/"); } scoped_refptr GetTcpParams() { @@ -125,10 +125,9 @@ class HttpProxyClientSocketPoolTest : public TestWithHttpParam { GURL(tunnel ? "https://www.google.com/" : "http://www.google.com"), "", HostPortPair("www.google.com", tunnel ? 443 : 80), - session_->auth_cache(), + session_->http_auth_cache(), session_->http_auth_handler_factory(), session_->spdy_session_pool(), - session_->mutable_spdy_settings(), tunnel)); } diff --git a/net/http/http_stream_factory.cc b/net/http/http_stream_factory.cc index 4673d58..9189e99 100644 --- a/net/http/http_stream_factory.cc +++ b/net/http/http_stream_factory.cc @@ -1,17 +1,16 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "net/http/http_stream_factory.h" -#include "base/stl_util-inl.h" +#include "base/logging.h" #include "base/string_number_conversions.h" #include "base/string_split.h" -#include "base/string_util.h" -#include "net/base/net_log.h" -#include "net/base/net_util.h" -#include "net/http/http_network_session.h" -#include "net/http/http_stream_request.h" +#include "googleurl/src/gurl.h" +#include "net/base/host_mapping_rules.h" +#include "net/base/host_port_pair.h" +#include "net/http/http_alternate_protocols.h" namespace net { @@ -32,62 +31,7 @@ std::list* HttpStreamFactory::forced_spdy_exclusions_ = NULL; // static bool HttpStreamFactory::ignore_certificate_errors_ = false; -HttpStreamFactory::HttpStreamFactory() { -} - -HttpStreamFactory::~HttpStreamFactory() { - RequestCallbackMap request_callback_map; - request_callback_map.swap(request_callback_map_); - for (RequestCallbackMap::iterator it = request_callback_map.begin(); - it != request_callback_map.end(); ++it) { - delete it->first; - // We don't invoke the callback in the destructor. - } -} - -// static -void HttpStreamFactory::SetHostMappingRules(const std::string& rules) { - HostMappingRules* host_mapping_rules = new HostMappingRules(); - host_mapping_rules->SetRulesFromString(rules); - delete host_mapping_rules_; - host_mapping_rules_ = host_mapping_rules; -} - -StreamRequest* HttpStreamFactory::RequestStream( - const HttpRequestInfo* request_info, - SSLConfig* ssl_config, - ProxyInfo* proxy_info, - HttpNetworkSession* session, - StreamRequest::Delegate* delegate, - const BoundNetLog& net_log) { - HttpStreamRequest* stream = new HttpStreamRequest(this, session); - stream->Start(request_info, ssl_config, proxy_info, delegate, net_log); - return stream; -} - -int HttpStreamFactory::PreconnectStreams( - int num_streams, - const HttpRequestInfo* request_info, - SSLConfig* ssl_config, - ProxyInfo* proxy_info, - HttpNetworkSession* session, - const BoundNetLog& net_log, - CompletionCallback* callback) { - HttpStreamRequest* stream = new HttpStreamRequest(this, session); - int rv = stream->Preconnect(num_streams, request_info, ssl_config, - proxy_info, this, net_log); - DCHECK_EQ(ERR_IO_PENDING, rv); - request_callback_map_[stream] = callback; - return rv; -} - -void HttpStreamFactory::AddTLSIntolerantServer(const GURL& url) { - tls_intolerant_servers_.insert(GetHostAndPort(url)); -} - -bool HttpStreamFactory::IsTLSIntolerantServer(const GURL& url) { - return ContainsKey(tls_intolerant_servers_, GetHostAndPort(url)); -} +HttpStreamFactory::~HttpStreamFactory() {} void HttpStreamFactory::ProcessAlternateProtocol( HttpAlternateProtocols* alternate_protocols, @@ -128,8 +72,7 @@ void HttpStreamFactory::ProcessAlternateProtocol( } HostPortPair host_port(http_host_port_pair); - if (host_mapping_rules_) - host_mapping_rules_->RewriteHost(&host_port); + host_mapping_rules().RewriteHost(&host_port); if (alternate_protocols->HasAlternateProtocolFor(host_port)) { const HttpAlternateProtocols::PortProtocolPair existing_alternate = @@ -144,7 +87,7 @@ void HttpStreamFactory::ProcessAlternateProtocol( GURL HttpStreamFactory::ApplyHostMappingRules(const GURL& url, HostPortPair* endpoint) { - if (host_mapping_rules_ && host_mapping_rules_->RewriteHost(endpoint)) { + if (host_mapping_rules().RewriteHost(endpoint)) { url_canon::Replacements replacements; const std::string port_str = base::IntToString(endpoint->port()); replacements.SetPort(port_str.c_str(), @@ -156,15 +99,29 @@ GURL HttpStreamFactory::ApplyHostMappingRules(const GURL& url, return url; } -void HttpStreamFactory::OnPreconnectsComplete( - HttpStreamRequest* request, int result) { - RequestCallbackMap::iterator it = request_callback_map_.find(request); - DCHECK(it != request_callback_map_.end()); - CompletionCallback* callback = it->second; - request_callback_map_.erase(it); - delete request; - callback->Run(result); +// static +void HttpStreamFactory::add_forced_spdy_exclusion(const std::string& value) { + HostPortPair pair = HostPortPair::FromURL(GURL(value)); + if (!forced_spdy_exclusions_) + forced_spdy_exclusions_ = new std::list(); + forced_spdy_exclusions_->push_back(pair); } -} // namespace net +// static +void HttpStreamFactory::SetHostMappingRules(const std::string& rules) { + HostMappingRules* host_mapping_rules = new HostMappingRules; + host_mapping_rules->SetRulesFromString(rules); + delete host_mapping_rules_; + host_mapping_rules_ = host_mapping_rules; +} + +HttpStreamFactory::HttpStreamFactory() {} +// static +const HostMappingRules& HttpStreamFactory::host_mapping_rules() { + if (!host_mapping_rules_) + host_mapping_rules_ = new HostMappingRules; + return *host_mapping_rules_; +} + +} // namespace net diff --git a/net/http/http_stream_factory.h b/net/http/http_stream_factory.h index 97bd79c..3d3bada 100644 --- a/net/http/http_stream_factory.h +++ b/net/http/http_stream_factory.h @@ -6,35 +6,176 @@ #define NET_HTTP_HTTP_STREAM_FACTORY_H_ #include -#include -#include #include -#include "base/scoped_ptr.h" +#include "base/string16.h" +#include "base/ref_counted.h" #include "net/base/completion_callback.h" -#include "net/base/host_mapping_rules.h" -#include "net/base/host_port_pair.h" -#include "net/base/ssl_config_service.h" -#include "net/http/http_auth.h" -#include "net/http/http_auth_controller.h" -#include "net/http/http_stream_request.h" -#include "net/http/stream_factory.h" -#include "net/proxy/proxy_service.h" -#include "net/socket/client_socket_handle.h" +#include "net/base/load_states.h" + +class GURL; namespace net { +class BoundNetLog; +class HostMappingRules; +class HostPortPair; +class HttpAlternateProtocols; +class HttpAuthController; class HttpNetworkSession; +class HttpResponseInfo; +class HttpStream; +class ProxyInfo; +class SSLCertRequestInfo; +class SSLInfo; +class X509Certificate; struct HttpRequestInfo; -class HttpStreamRequest; +struct SSLConfig; + +// The HttpStreamRequest is the client's handle to the worker object which +// handles the creation of an HttpStream. While the HttpStream is being +// created, this object is the creator's handle for interacting with the +// HttpStream creation process. The request is cancelled by deleting it, after +// which no callbacks will be invoked. +class HttpStreamRequest { + public: + // The HttpStreamRequest::Delegate is a set of callback methods for a + // HttpStreamRequestJob. Generally, only one of these methods will be + // called as a result of a stream request. + class Delegate { + public: + virtual ~Delegate() {} + + // This is the success case. + // |stream| is now owned by the delegate. + // |used_ssl_config| indicates the actual SSL configuration used for this + // stream, since the HttpStreamRequest may have modified the configuration + // during stream processing. + // |used_proxy_info| indicates the actual ProxyInfo used for this stream, + // since the HttpStreamRequest performs the proxy resolution. + virtual void OnStreamReady( + const SSLConfig& used_ssl_config, + const ProxyInfo& used_proxy_info, + HttpStream* stream) = 0; + + // This is the failure to create a stream case. + // |used_ssl_config| indicates the actual SSL configuration used for this + // stream, since the HttpStreamRequest may have modified the configuration + // during stream processing. + virtual void OnStreamFailed(int status, + const SSLConfig& used_ssl_config) = 0; + + // Called when we have a certificate error for the request. + // |used_ssl_config| indicates the actual SSL configuration used for this + // stream, since the HttpStreamRequest may have modified the configuration + // during stream processing. + virtual void OnCertificateError(int status, + const SSLConfig& used_ssl_config, + const SSLInfo& ssl_info) = 0; + + // This is the failure case where we need proxy authentication during + // proxy tunnel establishment. For the tunnel case, we were unable to + // create the HttpStream, so the caller provides the auth and then resumes + // the HttpStreamRequest. + // + // For the non-tunnel case, the caller will discover the authentication + // failure when reading response headers. At that point, he will handle the + // authentication failure and restart the HttpStreamRequest entirely. + // + // Ownership of |auth_controller| and |proxy_response| are owned + // by the HttpStreamRequest. |proxy_response| is not guaranteed to be usable + // after the lifetime of this callback. The delegate may take a reference + // to |auth_controller| if it is needed beyond the lifetime of this + // callback. + // + // |used_ssl_config| indicates the actual SSL configuration used for this + // stream, since the HttpStreamRequest may have modified the configuration + // during stream processing. + virtual void OnNeedsProxyAuth(const HttpResponseInfo& proxy_response, + const SSLConfig& used_ssl_config, + const ProxyInfo& used_proxy_info, + HttpAuthController* auth_controller) = 0; + + // This is the failure for SSL Client Auth + // Ownership of |cert_info| is retained by the HttpStreamRequest. The + // delegate may take a reference if it needs the cert_info beyond the + // lifetime of this callback. + virtual void OnNeedsClientAuth(const SSLConfig& used_ssl_config, + SSLCertRequestInfo* cert_info) = 0; + + // This is the failure of the CONNECT request through an HTTPS proxy. + // Headers can be read from |response_info|, while the body can be read + // from |stream|. + // + // |used_ssl_config| indicates the actual SSL configuration used for this + // stream, since the HttpStreamRequest may have modified the configuration + // during stream processing. + // + // |used_proxy_info| indicates the actual ProxyInfo used for this stream, + // since the HttpStreamRequest performs the proxy resolution. + // + // Ownership of |stream| is transferred to the delegate. + virtual void OnHttpsProxyTunnelResponse( + const HttpResponseInfo& response_info, + const SSLConfig& used_ssl_config, + const ProxyInfo& used_proxy_info, + HttpStream* stream) = 0; + }; + + virtual ~HttpStreamRequest() {} + + // When a HttpStream creation process is stalled due to necessity + // of Proxy authentication credentials, the delegate OnNeedsProxyAuth + // will have been called. It now becomes the delegate's responsibility + // to collect the necessary credentials, and then call this method to + // resume the HttpStream creation process. + virtual int RestartTunnelWithProxyAuth(const string16& username, + const string16& password) = 0; + + // Returns the LoadState for the request. + virtual LoadState GetLoadState() const = 0; + + // Returns true if an AlternateProtocol for this request was available. + virtual bool was_alternate_protocol_available() const = 0; + + // Returns true if TLS/NPN was negotiated for this stream. + virtual bool was_npn_negotiated() const = 0; + + // Returns true if this stream is being fetched over SPDY. + virtual bool using_spdy() const = 0; +}; -class HttpStreamFactory : public StreamFactory, - public HttpStreamRequest::PreconnectDelegate { +// The HttpStreamFactory defines an interface for creating usable HttpStreams. +class HttpStreamFactory { public: - HttpStreamFactory(); virtual ~HttpStreamFactory(); + void ProcessAlternateProtocol( + HttpAlternateProtocols* alternate_protocols, + const std::string& alternate_protocol_str, + const HostPortPair& http_host_port_pair); + + // Virtual interface methods. + + // Request a stream. + // Will callback to the HttpStreamRequestDelegate upon completion. + virtual HttpStreamRequest* RequestStream( + const HttpRequestInfo& info, + const SSLConfig& ssl_config, + HttpStreamRequest::Delegate* delegate, + const BoundNetLog& net_log) = 0; + + // Requests that enough connections for |num_streams| be opened. + virtual void PreconnectStreams(int num_streams, + const HttpRequestInfo& info, + const SSLConfig& ssl_config, + const BoundNetLog& net_log) = 0; + + virtual void AddTLSIntolerantServer(const GURL& url) = 0; + virtual bool IsTLSIntolerantServer(const GURL& url) const = 0; + // Static settings + static GURL ApplyHostMappingRules(const GURL& url, HostPortPair* endpoint); // Turns spdy on or off. static void set_spdy_enabled(bool value) { @@ -65,12 +206,7 @@ class HttpStreamFactory : public StreamFactory, static bool force_spdy_always() { return force_spdy_always_; } // Add a URL to exclude from forced SPDY. - static void add_forced_spdy_exclusion(const std::string& value) { - HostPortPair pair = HostPortPair::FromURL(GURL(value)); - if (!forced_spdy_exclusions_) - forced_spdy_exclusions_ = new std::list(); - forced_spdy_exclusions_->push_back(pair); - } + static void add_forced_spdy_exclusion(const std::string& value); static std::list* forced_spdy_exclusions() { return forced_spdy_exclusions_; } @@ -82,7 +218,7 @@ class HttpStreamFactory : public StreamFactory, } static const std::string* next_protos() { return next_protos_; } - // Sets the HttpStreamFactory into a mode where it can ignore certificate + // Sets the HttpStreamFactoryImpl into a mode where it can ignore certificate // errors. This is for testing. static void set_ignore_certificate_errors(bool value) { ignore_certificate_errors_ = value; @@ -93,35 +229,11 @@ class HttpStreamFactory : public StreamFactory, static void SetHostMappingRules(const std::string& rules); - // StreamFactory Interface - virtual StreamRequest* RequestStream(const HttpRequestInfo* info, - SSLConfig* ssl_config, - ProxyInfo* proxy_info, - HttpNetworkSession* session, - StreamRequest::Delegate* delegate, - const BoundNetLog& net_log); - virtual int PreconnectStreams(int num_streams, - const HttpRequestInfo* info, - SSLConfig* ssl_config, - ProxyInfo* proxy_info, - HttpNetworkSession* session, - const BoundNetLog& net_log, - CompletionCallback* callback); - virtual void AddTLSIntolerantServer(const GURL& url); - virtual bool IsTLSIntolerantServer(const GURL& url); - virtual void ProcessAlternateProtocol( - HttpAlternateProtocols* alternate_protocols, - const std::string& alternate_protocol_str, - const HostPortPair& http_host_port_pair); - virtual GURL ApplyHostMappingRules(const GURL& url, HostPortPair* endpoint); - - // HttpStreamRequest::PreconnectDelegate API - virtual void OnPreconnectsComplete(HttpStreamRequest* request, int result); + protected: + HttpStreamFactory(); private: - typedef std::map RequestCallbackMap; - RequestCallbackMap request_callback_map_; - std::set tls_intolerant_servers_; + static const HostMappingRules& host_mapping_rules(); static const HostMappingRules* host_mapping_rules_; static const std::string* next_protos_; @@ -138,4 +250,3 @@ class HttpStreamFactory : public StreamFactory, } // namespace net #endif // NET_HTTP_HTTP_STREAM_FACTORY_H_ - diff --git a/net/http/http_stream_factory_impl.cc b/net/http/http_stream_factory_impl.cc new file mode 100644 index 0000000..02dd29d --- /dev/null +++ b/net/http/http_stream_factory_impl.cc @@ -0,0 +1,299 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/http/http_stream_factory_impl.h" + +#include "base/stl_util-inl.h" +#include "net/base/net_log.h" +#include "net/base/net_util.h" +#include "net/http/http_network_session.h" +#include "net/http/http_stream_factory_impl_job.h" + +namespace net { + +class HttpStreamFactoryImpl::Request : public HttpStreamRequest { + public: + Request(HttpStreamFactoryImpl* factory, + HttpStreamRequest::Delegate* delegate); + virtual ~Request(); + + Job* job() const { return job_; } + + // Binds |job| to this request. + void BindJob(HttpStreamFactoryImpl::Job* job); + + // Marks completion of the request. Must be called before OnStreamReady(). + void Complete(bool was_alternate_protocol_available, + bool was_npn_negotiated, + bool using_spdy); + + // HttpStreamRequest::Delegate methods which we implement. Note we don't + // actually subclass HttpStreamRequest::Delegate. + + void OnStreamReady( + const SSLConfig& used_ssl_config, + const ProxyInfo& used_proxy_info, + HttpStream* stream); + void OnStreamFailed(int status, const SSLConfig& used_ssl_config); + void OnCertificateError(int status, + const SSLConfig& used_ssl_config, + const SSLInfo& ssl_info); + void OnNeedsProxyAuth(const HttpResponseInfo& proxy_response, + const SSLConfig& used_ssl_config, + const ProxyInfo& used_proxy_info, + HttpAuthController* auth_controller); + void OnNeedsClientAuth(const SSLConfig& used_ssl_config, + SSLCertRequestInfo* cert_info); + void OnHttpsProxyTunnelResponse( + const HttpResponseInfo& response_info, + const SSLConfig& used_ssl_config, + const ProxyInfo& used_proxy_info, + HttpStream* stream); + + // HttpStreamRequest methods. + + virtual int RestartTunnelWithProxyAuth(const string16& username, + const string16& password); + virtual LoadState GetLoadState() const; + virtual bool was_alternate_protocol_available() const; + virtual bool was_npn_negotiated() const; + virtual bool using_spdy() const; + + private: + HttpStreamFactoryImpl* const factory_; + HttpStreamRequest::Delegate* const delegate_; + + // The |job_| that this request is tied to. + // TODO(willchan): Revisit this when we decouple requests and jobs further. + HttpStreamFactoryImpl::Job* job_; + + bool completed_; + bool was_alternate_protocol_available_; + bool was_npn_negotiated_; + bool using_spdy_; + DISALLOW_COPY_AND_ASSIGN(Request); +}; + +HttpStreamFactoryImpl::Request::Request(HttpStreamFactoryImpl* factory, + HttpStreamRequest::Delegate* delegate) + : factory_(factory), + delegate_(delegate), + job_(NULL), + completed_(false), + was_alternate_protocol_available_(false), + was_npn_negotiated_(false), + using_spdy_(false) { + DCHECK(factory_); + DCHECK(delegate_); +} + +HttpStreamFactoryImpl::Request::~Request() { + factory_->request_map_.erase(job_); + + // TODO(willchan): Remove this when we decouple requests and jobs. + delete job_; +} + +void HttpStreamFactoryImpl::Request::BindJob(HttpStreamFactoryImpl::Job* job) { + DCHECK(job); + DCHECK(!job_); + job_ = job; +} + +void HttpStreamFactoryImpl::Request::Complete( + bool was_alternate_protocol_available, + bool was_npn_negotiated, + bool using_spdy) { + DCHECK(!completed_); + completed_ = true; + was_alternate_protocol_available_ = was_alternate_protocol_available; + was_npn_negotiated_ = was_npn_negotiated; + using_spdy_ = using_spdy; +} + +void HttpStreamFactoryImpl::Request::OnStreamReady( + const SSLConfig& used_ssl_config, + const ProxyInfo& used_proxy_info, + HttpStream* stream) { + DCHECK(stream); + DCHECK(completed_); + delegate_->OnStreamReady(used_ssl_config, used_proxy_info, stream); +} + +void HttpStreamFactoryImpl::Request::OnStreamFailed( + int status, + const SSLConfig& used_ssl_config) { + DCHECK_NE(OK, status); + delegate_->OnStreamFailed(status, used_ssl_config); +} + +void HttpStreamFactoryImpl::Request::OnCertificateError( + int status, + const SSLConfig& used_ssl_config, + const SSLInfo& ssl_info) { + DCHECK_NE(OK, status); + delegate_->OnCertificateError(status, used_ssl_config, ssl_info); +} + +void HttpStreamFactoryImpl::Request::OnNeedsProxyAuth( + const HttpResponseInfo& proxy_response, + const SSLConfig& used_ssl_config, + const ProxyInfo& used_proxy_info, + HttpAuthController* auth_controller) { + delegate_->OnNeedsProxyAuth( + proxy_response, used_ssl_config, used_proxy_info, auth_controller); +} + +void HttpStreamFactoryImpl::Request::OnNeedsClientAuth( + const SSLConfig& used_ssl_config, + SSLCertRequestInfo* cert_info) { + delegate_->OnNeedsClientAuth(used_ssl_config, cert_info); +} + +void HttpStreamFactoryImpl::Request::OnHttpsProxyTunnelResponse( + const HttpResponseInfo& response_info, + const SSLConfig& used_ssl_config, + const ProxyInfo& used_proxy_info, + HttpStream* stream) { + delegate_->OnHttpsProxyTunnelResponse( + response_info, used_ssl_config, used_proxy_info, stream); +} + +int HttpStreamFactoryImpl::Request::RestartTunnelWithProxyAuth( + const string16& username, + const string16& password) { + return job_->RestartTunnelWithProxyAuth(username, password); +} + +LoadState HttpStreamFactoryImpl::Request::GetLoadState() const { + return factory_->GetLoadState(*this); +} + +bool HttpStreamFactoryImpl::Request::was_alternate_protocol_available() const { + DCHECK(completed_); + return was_alternate_protocol_available_; +} + +bool HttpStreamFactoryImpl::Request::was_npn_negotiated() const { + DCHECK(completed_); + return was_npn_negotiated_; +} + +bool HttpStreamFactoryImpl::Request::using_spdy() const { + DCHECK(completed_); + return using_spdy_; +} + +HttpStreamFactoryImpl::HttpStreamFactoryImpl(HttpNetworkSession* session) + : session_(session) {} + +HttpStreamFactoryImpl::~HttpStreamFactoryImpl() { + DCHECK(request_map_.empty()); + + std::set tmp_job_set; + tmp_job_set.swap(preconnect_job_set_); + STLDeleteContainerPointers(tmp_job_set.begin(), tmp_job_set.end()); + DCHECK(preconnect_job_set_.empty()); +} + +HttpStreamRequest* HttpStreamFactoryImpl::RequestStream( + const HttpRequestInfo& request_info, + const SSLConfig& ssl_config, + HttpStreamRequest::Delegate* delegate, + const BoundNetLog& net_log) { + Job* job = new Job(this, session_); + Request* request = new Request(this, delegate); + request_map_[job] = request; + request->BindJob(job); + job->Start(request_info, ssl_config, net_log); + return request; +} + +void HttpStreamFactoryImpl::PreconnectStreams( + int num_streams, + const HttpRequestInfo& request_info, + const SSLConfig& ssl_config, + const BoundNetLog& net_log) { + Job* job = new Job(this, session_); + preconnect_job_set_.insert(job); + job->Preconnect(num_streams, request_info, ssl_config, net_log); +} + +void HttpStreamFactoryImpl::AddTLSIntolerantServer(const GURL& url) { + tls_intolerant_servers_.insert(GetHostAndPort(url)); +} + +bool HttpStreamFactoryImpl::IsTLSIntolerantServer(const GURL& url) const { + return ContainsKey(tls_intolerant_servers_, GetHostAndPort(url)); +} + +LoadState HttpStreamFactoryImpl::GetLoadState(const Request& request) const { + // TODO(willchan): Will break when we do late binding. + return request.job()->GetLoadState(); +} + +void HttpStreamFactoryImpl::OnStreamReady(const Job* job, + const SSLConfig& ssl_config, + const ProxyInfo& proxy_info, + HttpStream* stream) { + DCHECK(ContainsKey(request_map_, job)); + Request* request = request_map_[job]; + request->Complete(job->was_alternate_protocol_available(), + job->was_npn_negotiated(), + job->using_spdy()); + request->OnStreamReady(ssl_config, proxy_info, stream); +} + +void HttpStreamFactoryImpl::OnStreamFailed(const Job* job, + int result, + const SSLConfig& ssl_config) { + DCHECK(ContainsKey(request_map_, job)); + request_map_[job]->OnStreamFailed(result, ssl_config); +} + +void HttpStreamFactoryImpl::OnCertificateError(const Job* job, + int result, + const SSLConfig& ssl_config, + const SSLInfo& ssl_info) { + DCHECK(ContainsKey(request_map_, job)); + request_map_[job]->OnCertificateError(result, ssl_config, ssl_info); +} + +void HttpStreamFactoryImpl::OnNeedsProxyAuth( + const Job* job, + const HttpResponseInfo& response, + const SSLConfig& ssl_config, + const ProxyInfo& proxy_info, + HttpAuthController* auth_controller) { + DCHECK(ContainsKey(request_map_, job)); + request_map_[job]->OnNeedsProxyAuth( + response, ssl_config, proxy_info, auth_controller); +} + +void HttpStreamFactoryImpl::OnNeedsClientAuth( + const Job* job, + const SSLConfig& ssl_config, + SSLCertRequestInfo* cert_info) { + DCHECK(ContainsKey(request_map_, job)); + request_map_[job]->OnNeedsClientAuth(ssl_config, cert_info); +} + +void HttpStreamFactoryImpl::OnHttpsProxyTunnelResponse( + const Job* job, + const HttpResponseInfo& response_info, + const SSLConfig& ssl_config, + const ProxyInfo& proxy_info, + HttpStream* stream) { + DCHECK(ContainsKey(request_map_, job)); + request_map_[job]->OnHttpsProxyTunnelResponse( + response_info, ssl_config, proxy_info, stream); +} + +void HttpStreamFactoryImpl::OnPreconnectsComplete(const Job* job) { + preconnect_job_set_.erase(job); + delete job; + OnPreconnectsCompleteInternal(); +} + +} // namespace net diff --git a/net/http/http_stream_factory_impl.h b/net/http/http_stream_factory_impl.h new file mode 100644 index 0000000..d86a8fa --- /dev/null +++ b/net/http/http_stream_factory_impl.h @@ -0,0 +1,94 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef NET_HTTP_HTTP_STREAM_FACTORY_IMPL_H_ +#define NET_HTTP_HTTP_STREAM_FACTORY_IMPL_H_ + +#include +#include +#include + +#include "net/http/http_stream_factory.h" + +namespace net { + +class HttpNetworkSession; + +class HttpStreamFactoryImpl : public HttpStreamFactory { + public: + explicit HttpStreamFactoryImpl(HttpNetworkSession* session); + virtual ~HttpStreamFactoryImpl(); + + // HttpStreamFactory Interface + virtual HttpStreamRequest* RequestStream( + const HttpRequestInfo& info, + const SSLConfig& ssl_config, + HttpStreamRequest::Delegate* delegate, + const BoundNetLog& net_log); + + virtual void PreconnectStreams(int num_streams, + const HttpRequestInfo& info, + const SSLConfig& ssl_config, + const BoundNetLog& net_log); + virtual void AddTLSIntolerantServer(const GURL& url); + virtual bool IsTLSIntolerantServer(const GURL& url) const; + + private: + class Request; + class Job; + + LoadState GetLoadState(const Request& request) const; + + void OnStreamReady(const Job* job, + const SSLConfig& ssl_config, + const ProxyInfo& proxy_info, + HttpStream* stream); + void OnStreamFailed(const Job* job, int result, const SSLConfig& ssl_config); + void OnCertificateError(const Job* job, + int result, + const SSLConfig& ssl_config, + const SSLInfo& ssl_info); + void OnNeedsProxyAuth(const Job* job, + const HttpResponseInfo& response_info, + const SSLConfig& ssl_config, + const ProxyInfo& proxy_info, + HttpAuthController* auth_controller); + void OnNeedsClientAuth(const Job* job, + const SSLConfig& ssl_config, + SSLCertRequestInfo* cert_info); + void OnHttpsProxyTunnelResponse(const Job* job, + const HttpResponseInfo& response_info, + const SSLConfig& ssl_config, + const ProxyInfo& proxy_info, + HttpStream* stream); + + void OnPreconnectsComplete(const Job* job); + + // Called when the Preconnect completes. Used for testing. + virtual void OnPreconnectsCompleteInternal() {} + + HttpNetworkSession* const session_; + + std::set tls_intolerant_servers_; + + // All Requests are handed out to clients. By the time HttpStreamFactoryImpl + // is destroyed, all Requests should be deleted (which should remove them from + // |request_map_|. + // TODO(willchan): Change to a different key when we enable late binding. This + // is the key part that keeps things tightly bound. + // Note that currently the Request assumes ownership of the Job. We will break + // this with late binding, and the factory will own the Job. + std::map request_map_; + + // These jobs correspond to preconnect requests and have no associated Request + // object. They're owned by HttpStreamFactoryImpl. Leftover jobs will be + // deleted when the factory is destroyed. + std::set preconnect_job_set_; + + DISALLOW_COPY_AND_ASSIGN(HttpStreamFactoryImpl); +}; + +} // namespace net + +#endif // NET_HTTP_HTTP_STREAM_FACTORY_IMPL_H_ diff --git a/net/http/http_stream_factory_impl_job.cc b/net/http/http_stream_factory_impl_job.cc new file mode 100644 index 0000000..3f1968c --- /dev/null +++ b/net/http/http_stream_factory_impl_job.cc @@ -0,0 +1,1071 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/http/http_stream_factory_impl_job.h" + +#include "base/logging.h" +#include "base/stl_util-inl.h" +#include "base/string_number_conversions.h" +#include "base/string_util.h" +#include "base/stringprintf.h" +#include "net/base/connection_type_histograms.h" +#include "net/base/net_log.h" +#include "net/base/net_util.h" +#include "net/base/ssl_cert_request_info.h" +#include "net/http/http_basic_stream.h" +#include "net/http/http_network_session.h" +#include "net/http/http_proxy_client_socket.h" +#include "net/http/http_proxy_client_socket_pool.h" +#include "net/http/http_request_info.h" +#include "net/socket/client_socket_handle.h" +#include "net/socket/client_socket_pool.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" +#include "net/spdy/spdy_session_pool.h" + +namespace net { + +namespace { + +GURL UpgradeUrlToHttps(const GURL& original_url) { + GURL::Replacements replacements; + // new_sheme and new_port need to be in scope here because GURL::Replacements + // references the memory contained by them directly. + const std::string new_scheme = "https"; + const std::string new_port = base::IntToString(443); + replacements.SetSchemeStr(new_scheme); + replacements.SetPortStr(new_port); + return original_url.ReplaceComponents(replacements); +} + +} // namespace + +HttpStreamFactoryImpl::Job::Job(HttpStreamFactoryImpl* stream_factory, + HttpNetworkSession* session) + : ALLOW_THIS_IN_INITIALIZER_LIST(io_callback_(this, &Job::OnIOComplete)), + connection_(new ClientSocketHandle), + session_(session), + stream_factory_(stream_factory), + next_state_(STATE_NONE), + pac_request_(NULL), + using_ssl_(false), + using_spdy_(false), + force_spdy_always_(HttpStreamFactory::force_spdy_always()), + force_spdy_over_ssl_(HttpStreamFactory::force_spdy_over_ssl()), + spdy_certificate_error_(OK), + alternate_protocol_(HttpAlternateProtocols::UNINITIALIZED), + establishing_tunnel_(false), + was_alternate_protocol_available_(false), + was_npn_negotiated_(false), + num_streams_(0), + ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { + if (HttpStreamFactory::use_alternate_protocols()) + alternate_protocol_mode_ = kUnspecified; + else + alternate_protocol_mode_ = kDoNotUseAlternateProtocol; +} + +HttpStreamFactoryImpl::Job::~Job() { + // When we're in a partially constructed state, waiting for the user to + // provide certificate handling information or authentication, we can't reuse + // this stream at all. + if (next_state_ == STATE_WAITING_USER_ACTION) { + connection_->socket()->Disconnect(); + connection_.reset(); + } + + if (pac_request_) + session_->proxy_service()->CancelPacRequest(pac_request_); + + // The stream could be in a partial state. It is not reusable. + if (stream_.get() && next_state_ != STATE_DONE) + stream_->Close(true /* not reusable */); +} + +void HttpStreamFactoryImpl::Job::Start(const HttpRequestInfo& request_info, + const SSLConfig& ssl_config, + const BoundNetLog& net_log) { + StartInternal(request_info, ssl_config, net_log); +} + +int HttpStreamFactoryImpl::Job::Preconnect(int num_streams, + const HttpRequestInfo& request_info, + const SSLConfig& ssl_config, + const BoundNetLog& net_log) { + DCHECK_GT(num_streams, 0); + num_streams_ = num_streams; + return StartInternal(request_info, ssl_config, net_log); +} + +int HttpStreamFactoryImpl::Job::RestartTunnelWithProxyAuth( + const string16& username, const string16& password) { + DCHECK(establishing_tunnel_); + next_state_ = STATE_RESTART_TUNNEL_AUTH; + stream_.reset(); + return RunLoop(OK); +} + +LoadState HttpStreamFactoryImpl::Job::GetLoadState() const { + switch (next_state_) { + case STATE_RESOLVE_PROXY_COMPLETE: + return LOAD_STATE_RESOLVING_PROXY_FOR_URL; + case STATE_CREATE_STREAM_COMPLETE: + return connection_->GetLoadState(); + case STATE_INIT_CONNECTION_COMPLETE: + return LOAD_STATE_SENDING_REQUEST; + default: + return LOAD_STATE_IDLE; + } +} + +bool HttpStreamFactoryImpl::Job::was_alternate_protocol_available() const { + return was_alternate_protocol_available_; +} + +bool HttpStreamFactoryImpl::Job::was_npn_negotiated() const { + return was_npn_negotiated_; +} + +bool HttpStreamFactoryImpl::Job::using_spdy() const { + return using_spdy_; +} + +void HttpStreamFactoryImpl::Job::GetSSLInfo() { + DCHECK(using_ssl_); + DCHECK(!establishing_tunnel_); + DCHECK(connection_.get() && connection_->socket()); + SSLClientSocket* ssl_socket = + static_cast(connection_->socket()); + ssl_socket->GetSSLInfo(&ssl_info_); +} + +void HttpStreamFactoryImpl::Job::OnStreamReadyCallback() { + DCHECK(stream_.get()); + stream_factory_->OnStreamReady( + this, ssl_config_, proxy_info_, stream_.release()); +} + +void HttpStreamFactoryImpl::Job::OnStreamFailedCallback(int result) { + stream_factory_->OnStreamFailed(this, result, ssl_config_); +} + +void HttpStreamFactoryImpl::Job::OnCertificateErrorCallback( + int result, const SSLInfo& ssl_info) { + stream_factory_->OnCertificateError(this, result, ssl_config_, ssl_info); +} + +void HttpStreamFactoryImpl::Job::OnNeedsProxyAuthCallback( + const HttpResponseInfo& response, + HttpAuthController* auth_controller) { + stream_factory_->OnNeedsProxyAuth( + this, response, ssl_config_, proxy_info_, auth_controller); +} + +void HttpStreamFactoryImpl::Job::OnNeedsClientAuthCallback( + SSLCertRequestInfo* cert_info) { + stream_factory_->OnNeedsClientAuth(this, ssl_config_, cert_info); +} + +void HttpStreamFactoryImpl::Job::OnHttpsProxyTunnelResponseCallback( + const HttpResponseInfo& response_info, + HttpStream* stream) { + stream_factory_->OnHttpsProxyTunnelResponse( + this, response_info, ssl_config_, proxy_info_, stream); +} + +void HttpStreamFactoryImpl::Job::OnPreconnectsComplete() { + stream_factory_->OnPreconnectsComplete(this); +} + +void HttpStreamFactoryImpl::Job::OnIOComplete(int result) { + RunLoop(result); +} + +int HttpStreamFactoryImpl::Job::RunLoop(int result) { + result = DoLoop(result); + + if (result == ERR_IO_PENDING) + return result; + + if (IsPreconnecting()) { + MessageLoop::current()->PostTask( + FROM_HERE, + method_factory_.NewRunnableMethod( + &HttpStreamFactoryImpl::Job::OnPreconnectsComplete)); + return ERR_IO_PENDING; + } + + if (IsCertificateError(result)) { + // Retrieve SSL information from the socket. + GetSSLInfo(); + + next_state_ = STATE_WAITING_USER_ACTION; + MessageLoop::current()->PostTask( + FROM_HERE, + method_factory_.NewRunnableMethod( + &HttpStreamFactoryImpl::Job::OnCertificateErrorCallback, + result, ssl_info_)); + return ERR_IO_PENDING; + } + + switch (result) { + case ERR_PROXY_AUTH_REQUESTED: + { + DCHECK(connection_.get()); + DCHECK(connection_->socket()); + DCHECK(establishing_tunnel_); + + HttpProxyClientSocket* http_proxy_socket = + static_cast(connection_->socket()); + const HttpResponseInfo* tunnel_auth_response = + http_proxy_socket->GetConnectResponseInfo(); + + next_state_ = STATE_WAITING_USER_ACTION; + MessageLoop::current()->PostTask( + FROM_HERE, + method_factory_.NewRunnableMethod( + &HttpStreamFactoryImpl::Job::OnNeedsProxyAuthCallback, + *tunnel_auth_response, + http_proxy_socket->auth_controller())); + } + return ERR_IO_PENDING; + + case ERR_SSL_CLIENT_AUTH_CERT_NEEDED: + MessageLoop::current()->PostTask( + FROM_HERE, + method_factory_.NewRunnableMethod( + &HttpStreamFactoryImpl::Job::OnNeedsClientAuthCallback, + connection_->ssl_error_response_info().cert_request_info)); + return ERR_IO_PENDING; + + case ERR_HTTPS_PROXY_TUNNEL_RESPONSE: + { + DCHECK(connection_.get()); + DCHECK(connection_->socket()); + DCHECK(establishing_tunnel_); + + ProxyClientSocket* proxy_socket = + static_cast(connection_->socket()); + MessageLoop::current()->PostTask( + FROM_HERE, + method_factory_.NewRunnableMethod( + &HttpStreamFactoryImpl::Job::OnHttpsProxyTunnelResponseCallback, + *proxy_socket->GetConnectResponseInfo(), + proxy_socket->CreateConnectResponseStream())); + return ERR_IO_PENDING; + } + + case OK: + next_state_ = STATE_DONE; + MessageLoop::current()->PostTask( + FROM_HERE, + method_factory_.NewRunnableMethod( + &HttpStreamFactoryImpl::Job::OnStreamReadyCallback)); + return ERR_IO_PENDING; + + default: + MessageLoop::current()->PostTask( + FROM_HERE, + method_factory_.NewRunnableMethod( + &HttpStreamFactoryImpl::Job::OnStreamFailedCallback, + result)); + return ERR_IO_PENDING; + } + return result; +} + +int HttpStreamFactoryImpl::Job::DoLoop(int result) { + DCHECK_NE(next_state_, STATE_NONE); + int rv = result; + do { + State state = next_state_; + next_state_ = STATE_NONE; + switch (state) { + case STATE_RESOLVE_PROXY: + DCHECK_EQ(OK, rv); + rv = DoResolveProxy(); + break; + case STATE_RESOLVE_PROXY_COMPLETE: + rv = DoResolveProxyComplete(rv); + break; + case STATE_INIT_CONNECTION: + DCHECK_EQ(OK, rv); + rv = DoInitConnection(); + break; + case STATE_INIT_CONNECTION_COMPLETE: + rv = DoInitConnectionComplete(rv); + break; + case STATE_WAITING_USER_ACTION: + rv = DoWaitingUserAction(rv); + break; + case STATE_RESTART_TUNNEL_AUTH: + DCHECK_EQ(OK, rv); + rv = DoRestartTunnelAuth(); + break; + case STATE_RESTART_TUNNEL_AUTH_COMPLETE: + rv = DoRestartTunnelAuthComplete(rv); + break; + case STATE_CREATE_STREAM: + DCHECK_EQ(OK, rv); + rv = DoCreateStream(); + break; + case STATE_CREATE_STREAM_COMPLETE: + rv = DoCreateStreamComplete(rv); + break; + default: + NOTREACHED() << "bad state"; + rv = ERR_FAILED; + break; + } + } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE); + return rv; +} + +int HttpStreamFactoryImpl::Job::StartInternal( + const HttpRequestInfo& request_info, + const SSLConfig& ssl_config, + const BoundNetLog& net_log) { + CHECK_EQ(STATE_NONE, next_state_); + request_info_ = request_info; + ssl_config_ = ssl_config; + net_log_ = net_log; + next_state_ = STATE_RESOLVE_PROXY; + int rv = RunLoop(OK); + DCHECK_EQ(ERR_IO_PENDING, rv); + return rv; +} + +int HttpStreamFactoryImpl::Job::DoResolveProxy() { + DCHECK(!pac_request_); + + next_state_ = STATE_RESOLVE_PROXY_COMPLETE; + + // |endpoint_| indicates the final destination endpoint. + endpoint_ = HostPortPair(request_info_.url.HostNoBrackets(), + request_info_.url.EffectiveIntPort()); + + // Extra URL we might be attempting to resolve to. + GURL alternate_endpoint_url = request_info_.url; + + // Tracks whether we are using |request_.url| or |alternate_endpoint_url|. + const GURL *curr_endpoint_url = &request_info_.url; + + alternate_endpoint_url = + HttpStreamFactory::ApplyHostMappingRules( + alternate_endpoint_url, &endpoint_); + + const HttpAlternateProtocols& alternate_protocols = + session_->alternate_protocols(); + if (HttpStreamFactory::spdy_enabled() && + alternate_protocols.HasAlternateProtocolFor(endpoint_)) { + was_alternate_protocol_available_ = true; + if (alternate_protocol_mode_ == kUnspecified) { + HttpAlternateProtocols::PortProtocolPair alternate = + alternate_protocols.GetAlternateProtocolFor(endpoint_); + if (alternate.protocol != HttpAlternateProtocols::BROKEN) { + DCHECK_LE(HttpAlternateProtocols::NPN_SPDY_1, alternate.protocol); + DCHECK_GT(HttpAlternateProtocols::NUM_ALTERNATE_PROTOCOLS, + alternate.protocol); + endpoint_.set_port(alternate.port); + alternate_protocol_ = alternate.protocol; + alternate_protocol_mode_ = kUsingAlternateProtocol; + alternate_endpoint_url = UpgradeUrlToHttps(*curr_endpoint_url); + curr_endpoint_url = &alternate_endpoint_url; + } + } + } + + if (request_info_.load_flags & LOAD_BYPASS_PROXY) { + proxy_info_.UseDirect(); + return OK; + } + + return session_->proxy_service()->ResolveProxy( + *curr_endpoint_url, &proxy_info_, &io_callback_, &pac_request_, + net_log_); +} + +int HttpStreamFactoryImpl::Job::DoResolveProxyComplete(int result) { + pac_request_ = NULL; + + if (result != OK) + return result; + + // TODO(mbelshe): consider retrying ResolveProxy if we came here via use of + // AlternateProtocol. + + // Remove unsupported proxies from the list. + proxy_info_.RemoveProxiesWithoutScheme( + ProxyServer::SCHEME_DIRECT | + ProxyServer::SCHEME_HTTP | ProxyServer::SCHEME_HTTPS | + ProxyServer::SCHEME_SOCKS4 | ProxyServer::SCHEME_SOCKS5); + + if (proxy_info_.is_empty()) { + // No proxies/direct to choose from. This happens when we don't support any + // of the proxies in the returned list. + return ERR_NO_SUPPORTED_PROXIES; + } + + next_state_ = STATE_INIT_CONNECTION; + return OK; +} + +static bool HasSpdyExclusion(const HostPortPair& endpoint) { + std::list* exclusions = + HttpStreamFactory::forced_spdy_exclusions(); + if (!exclusions) + return false; + + std::list::const_iterator it; + for (it = exclusions->begin(); it != exclusions->end(); it++) + if (it->Equals(endpoint)) + return true; + return false; +} + +bool HttpStreamFactoryImpl::Job::ShouldForceSpdySSL() { + bool rv = force_spdy_always_ && force_spdy_over_ssl_; + return rv && !HasSpdyExclusion(endpoint_); +} + +bool HttpStreamFactoryImpl::Job::ShouldForceSpdyWithoutSSL() { + bool rv = force_spdy_always_ && !force_spdy_over_ssl_; + return rv && !HasSpdyExclusion(endpoint_); +} + +int HttpStreamFactoryImpl::Job::DoInitConnection() { + DCHECK(!connection_->is_initialized()); + DCHECK(proxy_info_.proxy_server().is_valid()); + next_state_ = STATE_INIT_CONNECTION_COMPLETE; + + bool want_spdy_over_npn = + alternate_protocol_mode_ == kUsingAlternateProtocol && + alternate_protocol_ == HttpAlternateProtocols::NPN_SPDY_2; + using_ssl_ = request_info_.url.SchemeIs("https") || + ShouldForceSpdySSL() || want_spdy_over_npn; + using_spdy_ = false; + + // If spdy has been turned off on-the-fly, then there may be SpdySessions + // still active. But don't use them unless spdy is currently on. + if (HttpStreamFactory::spdy_enabled() && !HasSpdyExclusion(endpoint_)) { + // Check first if we have a spdy session for this group. If so, then go + // straight to using that. + HostPortProxyPair pair(endpoint_, proxy_info_.proxy_server()); + if (session_->spdy_session_pool()->HasSession(pair)) { + // If we're preconnecting, but we already have a SpdySession, we don't + // actually need to preconnect any sockets, so we're done. + if (IsPreconnecting()) + return OK; + using_spdy_ = true; + next_state_ = STATE_CREATE_STREAM; + return OK; + } + // Check next if we have a spdy session for this proxy. If so, then go + // straight to using that. + if (IsHttpsProxyAndHttpUrl()) { + HostPortProxyPair proxy(proxy_info_.proxy_server().host_port_pair(), + ProxyServer::Direct()); + if (session_->spdy_session_pool()->HasSession(proxy)) { + using_spdy_ = true; + next_state_ = STATE_CREATE_STREAM; + return OK; + } + } + } + + // Build the string used to uniquely identify connections of this type. + // Determine the host and port to connect to. + std::string connection_group = endpoint_.ToString(); + DCHECK(!connection_group.empty()); + + if (using_ssl_) + connection_group = base::StringPrintf("ssl/%s", connection_group.c_str()); + + // If the user is refreshing the page, bypass the host cache. + bool disable_resolver_cache = + request_info_.load_flags & LOAD_BYPASS_CACHE || + request_info_.load_flags & LOAD_VALIDATE_CACHE || + request_info_.load_flags & LOAD_DISABLE_CACHE; + + // Build up the connection parameters. + scoped_refptr tcp_params; + scoped_refptr http_proxy_params; + scoped_refptr socks_params; + scoped_ptr proxy_host_port; + + if (proxy_info_.is_direct()) { + tcp_params = new TCPSocketParams(endpoint_, request_info_.priority, + request_info_.referrer, + disable_resolver_cache); + } else { + ProxyServer proxy_server = proxy_info_.proxy_server(); + proxy_host_port.reset(new HostPortPair(proxy_server.host_port_pair())); + scoped_refptr proxy_tcp_params( + new TCPSocketParams(*proxy_host_port, request_info_.priority, + request_info_.referrer, disable_resolver_cache)); + + if (proxy_info_.is_http() || proxy_info_.is_https()) { + GURL authentication_url = request_info_.url; + if (using_ssl_ && !authentication_url.SchemeIs("https")) { + // If a proxy tunnel connection needs to be established due to + // an Alternate-Protocol, the URL needs to be changed to indicate + // https or digest authentication attempts will fail. + // For example, suppose the initial request was for + // "http://www.example.com/index.html". If this is an SSL + // upgrade due to alternate protocol, the digest authorization + // should have a uri="www.example.com:443" field rather than a + // "/index.html" entry, even though the original request URL has not + // changed. + authentication_url = UpgradeUrlToHttps(authentication_url); + } + establishing_tunnel_ = using_ssl_; + std::string user_agent; + request_info_.extra_headers.GetHeader(HttpRequestHeaders::kUserAgent, + &user_agent); + scoped_refptr ssl_params; + if (proxy_info_.is_https()) { + // Set ssl_params, and unset proxy_tcp_params + ssl_params = GenerateSSLParams(proxy_tcp_params, NULL, NULL, + ProxyServer::SCHEME_DIRECT, + *proxy_host_port.get(), + want_spdy_over_npn); + proxy_tcp_params = NULL; + } + + http_proxy_params = + new HttpProxySocketParams(proxy_tcp_params, + ssl_params, + authentication_url, + user_agent, + endpoint_, + session_->http_auth_cache(), + session_->http_auth_handler_factory(), + session_->spdy_session_pool(), + 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 = base::StringPrintf( + "socks%c/%s", socks_version, connection_group.c_str()); + + socks_params = new SOCKSSocketParams(proxy_tcp_params, + socks_version == '5', + endpoint_, + request_info_.priority, + request_info_.referrer); + } + } + + // Deal with SSL - which layers on top of any given proxy. + if (using_ssl_) { + scoped_refptr ssl_params = + GenerateSSLParams(tcp_params, http_proxy_params, socks_params, + proxy_info_.proxy_server().scheme(), + HostPortPair::FromURL(request_info_.url), + want_spdy_over_npn); + SSLClientSocketPool* ssl_pool = NULL; + if (proxy_info_.is_direct()) + ssl_pool = session_->ssl_socket_pool(); + else + ssl_pool = session_->GetSocketPoolForSSLWithProxy(*proxy_host_port); + + if (IsPreconnecting()) { + RequestSocketsForPool(ssl_pool, connection_group, ssl_params, + num_streams_, net_log_); + return OK; + } + + return connection_->Init(connection_group, ssl_params, + request_info_.priority, &io_callback_, ssl_pool, + net_log_); + } + + // Finally, get the connection started. + if (proxy_info_.is_http() || proxy_info_.is_https()) { + HttpProxyClientSocketPool* pool = + session_->GetSocketPoolForHTTPProxy(*proxy_host_port); + if (IsPreconnecting()) { + RequestSocketsForPool(pool, connection_group, http_proxy_params, + num_streams_, net_log_); + return OK; + } + + return connection_->Init(connection_group, http_proxy_params, + request_info_.priority, &io_callback_, + pool, net_log_); + } + + if (proxy_info_.is_socks()) { + SOCKSClientSocketPool* pool = + session_->GetSocketPoolForSOCKSProxy(*proxy_host_port); + if (IsPreconnecting()) { + RequestSocketsForPool(pool, connection_group, socks_params, + num_streams_, net_log_); + return OK; + } + + return connection_->Init(connection_group, socks_params, + request_info_.priority, &io_callback_, pool, + net_log_); + } + + DCHECK(proxy_info_.is_direct()); + + TCPClientSocketPool* pool = session_->tcp_socket_pool(); + if (IsPreconnecting()) { + RequestSocketsForPool(pool, connection_group, tcp_params, + num_streams_, net_log_); + return OK; + } + + return connection_->Init(connection_group, tcp_params, + request_info_.priority, &io_callback_, + pool, net_log_); +} + +int HttpStreamFactoryImpl::Job::DoInitConnectionComplete(int result) { + if (IsPreconnecting()) { + DCHECK_EQ(OK, result); + return OK; + } + + // |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->was_npn_negotiated()) { + was_npn_negotiated_ = true; + if (ssl_socket->was_spdy_negotiated()) + SwitchToSpdyMode(); + } + if (ShouldForceSpdySSL()) + SwitchToSpdyMode(); + } else if (proxy_info_.is_https() && connection_->socket() && + result == OK) { + HttpProxyClientSocket* proxy_socket = + static_cast(connection_->socket()); + if (proxy_socket->using_spdy()) { + was_npn_negotiated_ = true; + SwitchToSpdyMode(); + } + } + + // We may be using spdy without SSL + if (ShouldForceSpdyWithoutSSL()) + SwitchToSpdyMode(); + + if (result == ERR_PROXY_AUTH_REQUESTED || + result == ERR_HTTPS_PROXY_TUNNEL_RESPONSE) { + DCHECK(!ssl_started); + // Other state (i.e. |using_ssl_|) suggests that |connection_| will have an + // SSL socket, but there was an error before that could happen. This + // puts the in progress HttpProxy socket into |connection_| in order to + // complete the auth (or read the response body). The tunnel restart code + // is careful to remove it before returning control to the rest of this + // class. + connection_.reset(connection_->release_pending_http_proxy_connection()); + return result; + } + + 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 (result < 0 && !ssl_started) + return ReconsiderProxyAfterError(result); + establishing_tunnel_ = false; + + if (connection_->socket()) { + LogHttpConnectedMetrics(*connection_); + + // We officially have a new connection. Record the type. + if (!connection_->is_reused()) { + ConnectionType type = using_spdy_ ? CONNECTION_SPDY : CONNECTION_HTTP; + UpdateConnectionTypeHistograms(type); + } + } + + // Handle SSL errors below. + if (using_ssl_) { + DCHECK(ssl_started); + if (IsCertificateError(result)) { + if (using_spdy_ && request_info_.url.SchemeIs("http")) { + // We ignore certificate errors for http over spdy. + spdy_certificate_error_ = result; + result = OK; + } else { + result = HandleCertificateError(result); + if (result == OK && !connection_->socket()->IsConnectedAndIdle()) { + connection_->socket()->Disconnect(); + connection_->Reset(); + next_state_ = STATE_INIT_CONNECTION; + return result; + } + } + } + if (result < 0) + return result; + } + + next_state_ = STATE_CREATE_STREAM; + return OK; +} + +int HttpStreamFactoryImpl::Job::DoWaitingUserAction(int result) { + // This state indicates that the stream request is in a partially + // completed state, and we've called back to the delegate for more + // information. + + // We're always waiting here for the delegate to call us back. + return ERR_IO_PENDING; +} + +int HttpStreamFactoryImpl::Job::DoCreateStream() { + next_state_ = STATE_CREATE_STREAM_COMPLETE; + + // We only set the socket motivation if we're the first to use + // this socket. Is there a race for two SPDY requests? We really + // need to plumb this through to the connect level. + if (connection_->socket() && !connection_->is_reused()) + SetSocketMotivation(); + + const ProxyServer& proxy_server = proxy_info_.proxy_server(); + + if (!using_spdy_) { + bool using_proxy = (proxy_info_.is_http() || proxy_info_.is_https()) && + request_info_.url.SchemeIs("http"); + stream_.reset(new HttpBasicStream(connection_.release(), NULL, + using_proxy)); + return OK; + } + + CHECK(!stream_.get()); + + bool direct = true; + SpdySessionPool* spdy_pool = session_->spdy_session_pool(); + scoped_refptr spdy_session; + + HostPortProxyPair pair(endpoint_, proxy_server); + if (spdy_pool->HasSession(pair)) { + // We have a SPDY session to the origin server. This might be a direct + // connection, or it might be a SPDY session through an HTTP or HTTPS proxy. + spdy_session = spdy_pool->Get(pair, net_log_); + } 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(), + ProxyServer::Direct()); + if (spdy_pool->HasSession(pair)) { + spdy_session = spdy_pool->Get(pair, net_log_); + } + direct = false; + } + + if (spdy_session.get()) { + // We picked up an existing session, so we don't need our socket. + if (connection_->socket()) + connection_->socket()->Disconnect(); + connection_->Reset(); + } else { + // SPDY can be negotiated using the TLS next protocol negotiation (NPN) + // extension, or just directly using SSL. Either way, |connection_| must + // contain an SSLClientSocket. + CHECK(connection_->socket()); + int error = spdy_pool->GetSpdySessionFromSocket( + pair, connection_.release(), net_log_, spdy_certificate_error_, + &spdy_session, using_ssl_); + if (error != OK) + return error; + } + + if (spdy_session->IsClosed()) + return ERR_CONNECTION_CLOSED; + + bool use_relative_url = direct || request_info_.url.SchemeIs("https"); + stream_.reset(new SpdyHttpStream(spdy_session, use_relative_url)); + return OK; +} + +int HttpStreamFactoryImpl::Job::DoCreateStreamComplete(int result) { + if (result < 0) + return result; + + next_state_ = STATE_NONE; + return OK; +} + +int HttpStreamFactoryImpl::Job::DoRestartTunnelAuth() { + next_state_ = STATE_RESTART_TUNNEL_AUTH_COMPLETE; + HttpProxyClientSocket* http_proxy_socket = + static_cast(connection_->socket()); + return http_proxy_socket->RestartWithAuth(&io_callback_); +} + +int HttpStreamFactoryImpl::Job::DoRestartTunnelAuthComplete(int result) { + if (result == ERR_PROXY_AUTH_REQUESTED) + return result; + + if (result == OK) { + // Now that we've got the HttpProxyClientSocket connected. We have + // to release it as an idle socket into the pool and start the connection + // process from the beginning. Trying to pass it in with the + // SSLSocketParams might cause a deadlock since params are dispatched + // interchangeably. This request won't necessarily get this http proxy + // socket, but there will be forward progress. + connection_->Reset(); + establishing_tunnel_ = false; + next_state_ = STATE_INIT_CONNECTION; + return OK; + } + + return ReconsiderProxyAfterError(result); +} + +void HttpStreamFactoryImpl::Job::SetSocketMotivation() { + if (request_info_.motivation == HttpRequestInfo::PRECONNECT_MOTIVATED) + connection_->socket()->SetSubresourceSpeculation(); + else if (request_info_.motivation == HttpRequestInfo::OMNIBOX_MOTIVATED) + connection_->socket()->SetOmniboxSpeculation(); + // TODO(mbelshe): Add other motivations (like EARLY_LOAD_MOTIVATED). +} + +bool HttpStreamFactoryImpl::Job::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 HttpStreamFactoryImpl::Job::GenerateSSLParams( + scoped_refptr tcp_params, + scoped_refptr http_proxy_params, + scoped_refptr socks_params, + ProxyServer::Scheme proxy_scheme, + const HostPortPair& host_and_port, + bool want_spdy_over_npn) { + + if (stream_factory_->IsTLSIntolerantServer(request_info_.url)) { + LOG(WARNING) << "Falling back to SSLv3 because host is TLS intolerant: " + << GetHostAndPort(request_info_.url); + ssl_config_.ssl3_fallback = true; + ssl_config_.tls1_enabled = false; + } + + if (proxy_info_.is_https() && ssl_config_.send_client_cert) { + // When connecting through an HTTPS proxy, disable TLS False Start so + // that client authentication errors can be distinguished between those + // originating from the proxy server (ERR_PROXY_CONNECTION_FAILED) and + // those originating from the endpoint (ERR_SSL_PROTOCOL_ERROR / + // ERR_BAD_SSL_CLIENT_AUTH_CERT). + // TODO(rch): This assumes that the HTTPS proxy will only request a + // client certificate during the initial handshake. + // http://crbug.com/59292 + ssl_config_.false_start_enabled = false; + } + + UMA_HISTOGRAM_ENUMERATION("Net.ConnectionUsedSSLv3Fallback", + static_cast(ssl_config_.ssl3_fallback), 2); + + int load_flags = request_info_.load_flags; + if (HttpStreamFactory::ignore_certificate_errors()) + load_flags |= LOAD_IGNORE_ALL_CERT_ERRORS; + if (request_info_.load_flags & LOAD_VERIFY_EV_CERT) + ssl_config_.verify_ev_cert = true; + + if (proxy_info_.proxy_server().scheme() == ProxyServer::SCHEME_HTTP || + proxy_info_.proxy_server().scheme() == ProxyServer::SCHEME_HTTPS) { + ssl_config_.mitm_proxies_allowed = true; + } + + scoped_refptr ssl_params( + new SSLSocketParams(tcp_params, socks_params, http_proxy_params, + proxy_scheme, host_and_port, + ssl_config_, load_flags, + ShouldForceSpdySSL(), + want_spdy_over_npn)); + + return ssl_params; +} + + +void HttpStreamFactoryImpl::Job::MarkBrokenAlternateProtocolAndFallback() { + // We have to: + // * Reset the endpoint to be the unmodified URL specified destination. + // * Mark the endpoint as broken so we don't try again. + // * Set the alternate protocol mode to kDoNotUseAlternateProtocol so we + // ignore future Alternate-Protocol headers from the HostPortPair. + // * Reset the connection and go back to STATE_INIT_CONNECTION. + + endpoint_ = HostPortPair(request_info_.url.HostNoBrackets(), + request_info_.url.EffectiveIntPort()); + + session_->mutable_alternate_protocols()->MarkBrokenAlternateProtocolFor( + endpoint_); + + alternate_protocol_mode_ = kDoNotUseAlternateProtocol; + if (connection_->socket()) + connection_->socket()->Disconnect(); + connection_->Reset(); + next_state_ = STATE_INIT_CONNECTION; +} + +int HttpStreamFactoryImpl::Job::ReconsiderProxyAfterError(int error) { + DCHECK(!pac_request_); + + // A failure to resolve the hostname or any error related to establishing a + // TCP connection could be grounds for trying a new proxy configuration. + // + // Why do this when a hostname cannot be resolved? Some URLs only make sense + // to proxy servers. The hostname in those URLs might fail to resolve if we + // are still using a non-proxy config. We need to check if a proxy config + // now exists that corresponds to a proxy server that could load the URL. + // + switch (error) { + case ERR_PROXY_CONNECTION_FAILED: + case ERR_NAME_NOT_RESOLVED: + case ERR_INTERNET_DISCONNECTED: + case ERR_ADDRESS_UNREACHABLE: + case ERR_CONNECTION_CLOSED: + case ERR_CONNECTION_RESET: + case ERR_CONNECTION_REFUSED: + case ERR_CONNECTION_ABORTED: + case ERR_TIMED_OUT: + case ERR_TUNNEL_CONNECTION_FAILED: + case ERR_SOCKS_CONNECTION_FAILED: + break; + case ERR_SOCKS_CONNECTION_HOST_UNREACHABLE: + // Remap the SOCKS-specific "host unreachable" error to a more + // generic error code (this way consumers like the link doctor + // know to substitute their error page). + // + // Note that if the host resolving was done by the SOCSK5 proxy, we can't + // differentiate between a proxy-side "host not found" versus a proxy-side + // "address unreachable" error, and will report both of these failures as + // ERR_ADDRESS_UNREACHABLE. + return ERR_ADDRESS_UNREACHABLE; + default: + return error; + } + + if (request_info_.load_flags & LOAD_BYPASS_PROXY) { + return error; + } + + if (proxy_info_.is_https() && ssl_config_.send_client_cert) { + session_->ssl_client_auth_cache()->Remove( + proxy_info_.proxy_server().host_port_pair().ToString()); + } + + int rv = session_->proxy_service()->ReconsiderProxyAfterError( + request_info_.url, &proxy_info_, &io_callback_, &pac_request_, + net_log_); + if (rv == OK || rv == ERR_IO_PENDING) { + // If the error was during connection setup, there is no socket to + // disconnect. + if (connection_->socket()) + connection_->socket()->Disconnect(); + connection_->Reset(); + next_state_ = STATE_RESOLVE_PROXY_COMPLETE; + } else { + // If ReconsiderProxyAfterError() failed synchronously, it means + // there was nothing left to fall-back to, so fail the transaction + // with the last connection error we got. + // TODO(eroman): This is a confusing contract, make it more obvious. + rv = error; + } + + return rv; +} + +int HttpStreamFactoryImpl::Job::HandleCertificateError(int error) { + DCHECK(using_ssl_); + DCHECK(IsCertificateError(error)); + + SSLClientSocket* ssl_socket = + static_cast(connection_->socket()); + ssl_socket->GetSSLInfo(&ssl_info_); + + // Add the bad certificate to the set of allowed certificates in the + // SSL info object. This data structure will be consulted after calling + // RestartIgnoringLastError(). And the user will be asked interactively + // before RestartIgnoringLastError() is ever called. + SSLConfig::CertAndStatus bad_cert; + bad_cert.cert = ssl_info_.cert; + bad_cert.cert_status = ssl_info_.cert_status; + ssl_config_.allowed_bad_certs.push_back(bad_cert); + + int load_flags = request_info_.load_flags; + if (HttpStreamFactory::ignore_certificate_errors()) + load_flags |= LOAD_IGNORE_ALL_CERT_ERRORS; + if (ssl_socket->IgnoreCertError(error, load_flags)) + return OK; + return error; +} + +void HttpStreamFactoryImpl::Job::SwitchToSpdyMode() { + if (HttpStreamFactory::spdy_enabled()) + using_spdy_ = true; +} + +// static +void HttpStreamFactoryImpl::Job::LogHttpConnectedMetrics( + const ClientSocketHandle& handle) { + UMA_HISTOGRAM_ENUMERATION("Net.HttpSocketType", handle.reuse_type(), + ClientSocketHandle::NUM_TYPES); + + switch (handle.reuse_type()) { + case ClientSocketHandle::UNUSED: + UMA_HISTOGRAM_CUSTOM_TIMES("Net.HttpConnectionLatency", + handle.setup_time(), + base::TimeDelta::FromMilliseconds(1), + base::TimeDelta::FromMinutes(10), + 100); + break; + case ClientSocketHandle::UNUSED_IDLE: + UMA_HISTOGRAM_CUSTOM_TIMES("Net.SocketIdleTimeBeforeNextUse_UnusedSocket", + handle.idle_time(), + base::TimeDelta::FromMilliseconds(1), + base::TimeDelta::FromMinutes(6), + 100); + break; + case ClientSocketHandle::REUSED_IDLE: + UMA_HISTOGRAM_CUSTOM_TIMES("Net.SocketIdleTimeBeforeNextUse_ReusedSocket", + handle.idle_time(), + base::TimeDelta::FromMilliseconds(1), + base::TimeDelta::FromMinutes(6), + 100); + break; + default: + NOTREACHED(); + break; + } +} + +bool HttpStreamFactoryImpl::Job::IsPreconnecting() const { + DCHECK_GE(num_streams_, 0); + return num_streams_ > 0; +} + +} // namespace net diff --git a/net/http/http_stream_factory_impl_job.h b/net/http/http_stream_factory_impl_job.h new file mode 100644 index 0000000..38f8081 --- /dev/null +++ b/net/http/http_stream_factory_impl_job.h @@ -0,0 +1,232 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef NET_HTTP_HTTP_STREAM_FACTORY_IMPL_JOB_H_ +#define NET_HTTP_HTTP_STREAM_FACTORY_IMPL_JOB_H_ + +#include "base/ref_counted.h" +#include "base/scoped_ptr.h" +#include "base/task.h" +#include "net/base/completion_callback.h" +#include "net/base/ssl_config_service.h" +#include "net/http/http_alternate_protocols.h" +#include "net/http/http_auth.h" +#include "net/http/http_auth_controller.h" +#include "net/http/http_request_info.h" +#include "net/http/http_stream_factory_impl.h" +#include "net/proxy/proxy_service.h" +#include "net/socket/client_socket_handle.h" + +namespace net { + +class ClientSocketHandle; +class HttpAuthController; +class HttpNetworkSession; +class HttpProxySocketParams; +class HttpStream; +class SOCKSSocketParams; +class SSLSocketParams; +class TCPSocketParams; + +// An HttpStreamRequestImpl exists for each stream which is in progress of being +// created for the StreamFactory. +class HttpStreamFactoryImpl::Job { + public: + Job(HttpStreamFactoryImpl* stream_factory, HttpNetworkSession* session); + ~Job(); + + // Start initiates the process of creating a new HttpStream. + // 3 parameters are passed in by reference. The caller asserts that the + // lifecycle of these parameters will remain valid until the stream is + // created, failed, or destroyed. In the first two cases, the delegate will + // be called to notify completion of the request. + void Start(const HttpRequestInfo& request_info, + const SSLConfig& ssl_config, + const BoundNetLog& net_log); + + int Preconnect(int num_streams, + const HttpRequestInfo& request_info, + const SSLConfig& ssl_config, + const BoundNetLog& net_log); + + int RestartTunnelWithProxyAuth(const string16& username, + const string16& password); + LoadState GetLoadState() const; + + bool was_alternate_protocol_available() const; + bool was_npn_negotiated() const; + bool using_spdy() const; + + private: + enum AlternateProtocolMode { + kUnspecified, // Unspecified, check HttpAlternateProtocols + kUsingAlternateProtocol, // Using an alternate protocol + kDoNotUseAlternateProtocol, // Failed to connect once, do not try again. + }; + + enum State { + STATE_RESOLVE_PROXY, + STATE_RESOLVE_PROXY_COMPLETE, + STATE_INIT_CONNECTION, + STATE_INIT_CONNECTION_COMPLETE, + STATE_WAITING_USER_ACTION, + STATE_RESTART_TUNNEL_AUTH, + STATE_RESTART_TUNNEL_AUTH_COMPLETE, + STATE_CREATE_STREAM, + STATE_CREATE_STREAM_COMPLETE, + STATE_DRAIN_BODY_FOR_AUTH_RESTART, + STATE_DRAIN_BODY_FOR_AUTH_RESTART_COMPLETE, + STATE_DONE, + STATE_NONE + }; + + void OnStreamReadyCallback(); + void OnStreamFailedCallback(int result); + void OnCertificateErrorCallback(int result, const SSLInfo& ssl_info); + void OnNeedsProxyAuthCallback(const HttpResponseInfo& response_info, + HttpAuthController* auth_controller); + void OnNeedsClientAuthCallback(SSLCertRequestInfo* cert_info); + void OnHttpsProxyTunnelResponseCallback(const HttpResponseInfo& response_info, + HttpStream* stream); + void OnPreconnectsComplete(); + + void OnIOComplete(int result); + int RunLoop(int result); + int DoLoop(int result); + int StartInternal(const HttpRequestInfo& request_info, + const SSLConfig& ssl_config, + const BoundNetLog& net_log); + + // Each of these methods corresponds to a State value. Those with an input + // argument receive the result from the previous state. If a method returns + // ERR_IO_PENDING, then the result from OnIOComplete will be passed to the + // next state method as the result arg. + int DoResolveProxy(); + int DoResolveProxyComplete(int result); + int DoInitConnection(); + int DoInitConnectionComplete(int result); + int DoWaitingUserAction(int result); + int DoCreateStream(); + int DoCreateStreamComplete(int result); + int DoRestartTunnelAuth(); + int DoRestartTunnelAuthComplete(int result); + + // 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 GenerateSSLParams( + scoped_refptr tcp_params, + scoped_refptr http_proxy_params, + scoped_refptr socks_params, + ProxyServer::Scheme proxy_scheme, + const HostPortPair& host_and_port, + bool want_spdy_over_npn); + + // AlternateProtocol API + void MarkBrokenAlternateProtocolAndFallback(); + + // Retrieve SSLInfo from our SSL Socket. + // This must only be called when we are using an SSLSocket. + // After calling, the caller can use ssl_info_. + void GetSSLInfo(); + + // Called when we encounter a network error that could be resolved by trying + // a new proxy configuration. If there is another proxy configuration to try + // then this method sets next_state_ appropriately and returns either OK or + // ERR_IO_PENDING depending on whether or not the new proxy configuration is + // available synchronously or asynchronously. Otherwise, the given error + // code is simply returned. + int ReconsiderProxyAfterError(int error); + + // Called to handle a certificate error. Stores the certificate in the + // allowed_bad_certs list, and checks if the error can be ignored. Returns + // OK if it can be ignored, or the error code otherwise. + int HandleCertificateError(int error); + + // Called to handle a client certificate request. + int HandleCertificateRequest(int error); + + // Moves this stream request into SPDY mode. + void SwitchToSpdyMode(); + + // Should we force SPDY to run over SSL for this stream request. + bool ShouldForceSpdySSL(); + + // Should we force SPDY to run without SSL for this stream request. + bool ShouldForceSpdyWithoutSSL(); + + // Record histograms of latency until Connect() completes. + static void LogHttpConnectedMetrics(const ClientSocketHandle& handle); + + // Indicates whether or not this job is performing a preconnect. + bool IsPreconnecting() const; + + HttpRequestInfo request_info_; + ProxyInfo proxy_info_; + SSLConfig ssl_config_; + + CompletionCallbackImpl io_callback_; + scoped_ptr connection_; + HttpNetworkSession* const session_; + HttpStreamFactoryImpl* const stream_factory_; + BoundNetLog net_log_; + State next_state_; + ProxyService::PacRequest* pac_request_; + SSLInfo ssl_info_; + // The hostname and port of the endpoint. This is not necessarily the one + // specified by the URL, due to Alternate-Protocol or fixed testing ports. + HostPortPair endpoint_; + + // True if handling a HTTPS request, or using SPDY with SSL + bool using_ssl_; + + // True if this network transaction is using SPDY instead of HTTP. + bool using_spdy_; + + // Force spdy for all connections. + bool force_spdy_always_; + + // Force spdy only for SSL connections. + bool force_spdy_over_ssl_; + + // The certificate error while using SPDY over SSL for insecure URLs. + int spdy_certificate_error_; + + scoped_refptr + auth_controllers_[HttpAuth::AUTH_NUM_TARGETS]; + + AlternateProtocolMode alternate_protocol_mode_; + + // Only valid if |alternate_protocol_mode_| == kUsingAlternateProtocol. + HttpAlternateProtocols::Protocol alternate_protocol_; + + // True when the tunnel is in the process of being established - we can't + // read from the socket until the tunnel is done. + bool establishing_tunnel_; + + scoped_ptr stream_; + + // True if finding the connection for this request found an alternate + // protocol was available. + bool was_alternate_protocol_available_; + + // True if we negotiated NPN. + bool was_npn_negotiated_; + + // 0 if we're not preconnecting. Otherwise, the number of streams to + // preconnect. + int num_streams_; + + ScopedRunnableMethodFactory method_factory_; + + DISALLOW_COPY_AND_ASSIGN(Job); +}; + +} // namespace net + +#endif // NET_HTTP_HTTP_STREAM_FACTORY_IMPL_JOB_H_ diff --git a/net/http/http_stream_factory_impl_unittest.cc b/net/http/http_stream_factory_impl_unittest.cc new file mode 100644 index 0000000..f316251 --- /dev/null +++ b/net/http/http_stream_factory_impl_unittest.cc @@ -0,0 +1,320 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/http/http_stream_factory_impl.h" + +#include + +#include "base/basictypes.h" +#include "net/base/cert_verifier.h" +#include "net/base/mock_host_resolver.h" +#include "net/base/net_log.h" +#include "net/base/ssl_config_service_defaults.h" +#include "net/base/test_completion_callback.h" +#include "net/http/http_auth_handler_factory.h" +#include "net/http/http_network_session.h" +#include "net/http/http_network_session_peer.h" +#include "net/http/http_request_info.h" +#include "net/proxy/proxy_info.h" +#include "net/proxy/proxy_service.h" +#include "net/socket/socket_test_util.h" +#include "net/spdy/spdy_session.h" +#include "net/spdy/spdy_session_pool.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace net { + +namespace { + +class MockHttpStreamFactoryImpl : public HttpStreamFactoryImpl { + public: + MockHttpStreamFactoryImpl(HttpNetworkSession* session) + : HttpStreamFactoryImpl(session), + preconnect_done_(false), + waiting_for_preconnect_(false) {} + + + void WaitForPreconnects() { + while (!preconnect_done_) { + waiting_for_preconnect_ = true; + MessageLoop::current()->Run(); + waiting_for_preconnect_ = false; + } + } + + private: + // HttpStreamFactoryImpl methods. + virtual void OnPreconnectsCompleteInternal() { + preconnect_done_ = true; + if (waiting_for_preconnect_) + MessageLoop::current()->Quit(); + } + + bool preconnect_done_; + bool waiting_for_preconnect_; +}; + +struct SessionDependencies { + // Custom proxy service dependency. + explicit SessionDependencies(ProxyService* proxy_service) + : host_resolver(new MockHostResolver), + cert_verifier(new CertVerifier), + proxy_service(proxy_service), + ssl_config_service(new SSLConfigServiceDefaults), + http_auth_handler_factory( + HttpAuthHandlerFactory::CreateDefault(host_resolver.get())), + net_log(NULL) {} + + scoped_ptr host_resolver; + scoped_ptr cert_verifier; + scoped_refptr proxy_service; + scoped_refptr ssl_config_service; + MockClientSocketFactory socket_factory; + scoped_ptr http_auth_handler_factory; + NetLog* net_log; +}; + +HttpNetworkSession* CreateSession(SessionDependencies* session_deps) { + HttpNetworkSession::Params params; + params.host_resolver = session_deps->host_resolver.get(); + params.cert_verifier = session_deps->cert_verifier.get(); + params.proxy_service = session_deps->proxy_service; + params.ssl_config_service = session_deps->ssl_config_service; + params.client_socket_factory = &session_deps->socket_factory; + params.http_auth_handler_factory = + session_deps->http_auth_handler_factory.get(); + params.net_log = session_deps->net_log; + return new HttpNetworkSession(params); +} + +struct TestCase { + int num_streams; + bool ssl; +}; + +TestCase kTests[] = { + { 1, false }, + { 2, false }, + { 1, true}, + { 2, true}, +}; + +void PreconnectHelper(const TestCase& test, + HttpNetworkSession* session) { + HttpNetworkSessionPeer peer(session); + MockHttpStreamFactoryImpl* mock_factory = + new MockHttpStreamFactoryImpl(session); + peer.SetHttpStreamFactory(mock_factory); + SSLConfig ssl_config; + session->ssl_config_service()->GetSSLConfig(&ssl_config); + + HttpRequestInfo request; + request.method = "GET"; + request.url = test.ssl ? GURL("https://www.google.com") : + GURL("http://www.google.com"); + request.load_flags = 0; + + ProxyInfo proxy_info; + TestCompletionCallback callback; + + session->http_stream_factory()->PreconnectStreams( + test.num_streams, request, ssl_config, BoundNetLog()); + mock_factory->WaitForPreconnects(); +}; + +template +class CapturePreconnectsSocketPool : public ParentPool { + public: + CapturePreconnectsSocketPool(HostResolver* host_resolver, + CertVerifier* cert_verifier); + + int last_num_streams() const { + return last_num_streams_; + } + + virtual int RequestSocket(const std::string& group_name, + const void* socket_params, + RequestPriority priority, + ClientSocketHandle* handle, + CompletionCallback* callback, + const BoundNetLog& net_log) { + ADD_FAILURE(); + return ERR_UNEXPECTED; + } + + virtual void RequestSockets(const std::string& group_name, + const void* socket_params, + int num_sockets, + const BoundNetLog& net_log) { + last_num_streams_ = num_sockets; + } + + virtual void CancelRequest(const std::string& group_name, + ClientSocketHandle* handle) { + ADD_FAILURE(); + } + virtual void ReleaseSocket(const std::string& group_name, + ClientSocket* socket, + int id) { + ADD_FAILURE(); + } + virtual void CloseIdleSockets() { + ADD_FAILURE(); + } + virtual int IdleSocketCount() const { + ADD_FAILURE(); + return 0; + } + virtual int IdleSocketCountInGroup(const std::string& group_name) const { + ADD_FAILURE(); + return 0; + } + virtual LoadState GetLoadState(const std::string& group_name, + const ClientSocketHandle* handle) const { + ADD_FAILURE(); + return LOAD_STATE_IDLE; + } + virtual base::TimeDelta ConnectionTimeout() const { + return base::TimeDelta(); + } + + private: + int last_num_streams_; +}; + +typedef CapturePreconnectsSocketPool +CapturePreconnectsTCPSocketPool; +typedef CapturePreconnectsSocketPool +CapturePreconnectsHttpProxySocketPool; +typedef CapturePreconnectsSocketPool +CapturePreconnectsSOCKSSocketPool; +typedef CapturePreconnectsSocketPool +CapturePreconnectsSSLSocketPool; + +template +CapturePreconnectsSocketPool::CapturePreconnectsSocketPool( + HostResolver* host_resolver, CertVerifier* /* cert_verifier */) + : ParentPool(0, 0, NULL, host_resolver, NULL, NULL), + last_num_streams_(-1) {} + +template<> +CapturePreconnectsHttpProxySocketPool::CapturePreconnectsSocketPool( + HostResolver* host_resolver, CertVerifier* /* cert_verifier */) + : HttpProxyClientSocketPool(0, 0, NULL, host_resolver, NULL, NULL, NULL), + last_num_streams_(-1) {} + +template<> +CapturePreconnectsSSLSocketPool::CapturePreconnectsSocketPool( + HostResolver* host_resolver, CertVerifier* cert_verifier) + : SSLClientSocketPool(0, 0, NULL, host_resolver, cert_verifier, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL), + last_num_streams_(-1) {} + +TEST(HttpStreamFactoryTest, PreconnectDirect) { + for (size_t i = 0; i < arraysize(kTests); ++i) { + SessionDependencies session_deps(ProxyService::CreateDirect()); + scoped_refptr session(CreateSession(&session_deps)); + HttpNetworkSessionPeer peer(session); + CapturePreconnectsTCPSocketPool* tcp_conn_pool = + new CapturePreconnectsTCPSocketPool( + session_deps.host_resolver.get(), + session_deps.cert_verifier.get()); + peer.SetTCPSocketPool(tcp_conn_pool); + CapturePreconnectsSSLSocketPool* ssl_conn_pool = + new CapturePreconnectsSSLSocketPool( + session_deps.host_resolver.get(), + session_deps.cert_verifier.get()); + peer.SetSSLSocketPool(ssl_conn_pool); + PreconnectHelper(kTests[i], session); + if (kTests[i].ssl) + EXPECT_EQ(kTests[i].num_streams, ssl_conn_pool->last_num_streams()); + else + EXPECT_EQ(kTests[i].num_streams, tcp_conn_pool->last_num_streams()); + } +} + +TEST(HttpStreamFactoryTest, PreconnectHttpProxy) { + for (size_t i = 0; i < arraysize(kTests); ++i) { + SessionDependencies session_deps(ProxyService::CreateFixed("http_proxy")); + scoped_refptr session(CreateSession(&session_deps)); + HttpNetworkSessionPeer peer(session); + HostPortPair proxy_host("http_proxy", 80); + CapturePreconnectsHttpProxySocketPool* http_proxy_pool = + new CapturePreconnectsHttpProxySocketPool( + session_deps.host_resolver.get(), + session_deps.cert_verifier.get()); + peer.SetSocketPoolForHTTPProxy(proxy_host, http_proxy_pool); + CapturePreconnectsSSLSocketPool* ssl_conn_pool = + new CapturePreconnectsSSLSocketPool( + session_deps.host_resolver.get(), + session_deps.cert_verifier.get()); + peer.SetSocketPoolForSSLWithProxy(proxy_host, ssl_conn_pool); + PreconnectHelper(kTests[i], session); + if (kTests[i].ssl) + EXPECT_EQ(kTests[i].num_streams, ssl_conn_pool->last_num_streams()); + else + EXPECT_EQ(kTests[i].num_streams, http_proxy_pool->last_num_streams()); + } +} + +TEST(HttpStreamFactoryTest, PreconnectSocksProxy) { + for (size_t i = 0; i < arraysize(kTests); ++i) { + SessionDependencies session_deps( + ProxyService::CreateFixed("socks4://socks_proxy:1080")); + scoped_refptr session(CreateSession(&session_deps)); + HttpNetworkSessionPeer peer(session); + HostPortPair proxy_host("socks_proxy", 1080); + CapturePreconnectsSOCKSSocketPool* socks_proxy_pool = + new CapturePreconnectsSOCKSSocketPool( + session_deps.host_resolver.get(), + session_deps.cert_verifier.get()); + peer.SetSocketPoolForSOCKSProxy(proxy_host, socks_proxy_pool); + CapturePreconnectsSSLSocketPool* ssl_conn_pool = + new CapturePreconnectsSSLSocketPool( + session_deps.host_resolver.get(), + session_deps.cert_verifier.get()); + peer.SetSocketPoolForSSLWithProxy(proxy_host, ssl_conn_pool); + PreconnectHelper(kTests[i], session); + if (kTests[i].ssl) + EXPECT_EQ(kTests[i].num_streams, ssl_conn_pool->last_num_streams()); + else + EXPECT_EQ(kTests[i].num_streams, socks_proxy_pool->last_num_streams()); + } +} + +TEST(HttpStreamFactoryTest, PreconnectDirectWithExistingSpdySession) { + for (size_t i = 0; i < arraysize(kTests); ++i) { + SessionDependencies session_deps(ProxyService::CreateDirect()); + scoped_refptr session(CreateSession(&session_deps)); + HttpNetworkSessionPeer peer(session); + + // Set an existing SpdySession in the pool. + HostPortPair host_port_pair("www.google.com", 443); + HostPortProxyPair pair(host_port_pair, ProxyServer::Direct()); + scoped_refptr spdy_session = + session->spdy_session_pool()->Get(pair, BoundNetLog()); + + CapturePreconnectsTCPSocketPool* tcp_conn_pool = + new CapturePreconnectsTCPSocketPool( + session_deps.host_resolver.get(), + session_deps.cert_verifier.get()); + peer.SetTCPSocketPool(tcp_conn_pool); + CapturePreconnectsSSLSocketPool* ssl_conn_pool = + new CapturePreconnectsSSLSocketPool( + session_deps.host_resolver.get(), + session_deps.cert_verifier.get()); + peer.SetSSLSocketPool(ssl_conn_pool); + PreconnectHelper(kTests[i], session); + // We shouldn't be preconnecting if we have an existing session, which is + // the case for https://www.google.com. + if (kTests[i].ssl) + EXPECT_EQ(-1, ssl_conn_pool->last_num_streams()); + else + EXPECT_EQ(kTests[i].num_streams, tcp_conn_pool->last_num_streams()); + } +} + +} // namespace + +} // namespace net diff --git a/net/http/http_stream_factory_unittest.cc b/net/http/http_stream_factory_unittest.cc deleted file mode 100644 index 617d885..0000000 --- a/net/http/http_stream_factory_unittest.cc +++ /dev/null @@ -1,290 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/http/http_stream_factory.h" - -#include - -#include "base/basictypes.h" -#include "net/base/cert_verifier.h" -#include "net/base/mock_host_resolver.h" -#include "net/base/net_log.h" -#include "net/base/ssl_config_service_defaults.h" -#include "net/base/test_completion_callback.h" -#include "net/http/http_auth_handler_factory.h" -#include "net/http/http_network_session.h" -#include "net/http/http_network_session_peer.h" -#include "net/http/http_request_info.h" -#include "net/socket/socket_test_util.h" -#include "net/spdy/spdy_session.h" -#include "net/spdy/spdy_session_pool.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace net { - -namespace { - -struct SessionDependencies { - // Custom proxy service dependency. - explicit SessionDependencies(ProxyService* proxy_service) - : host_resolver(new MockHostResolver), - cert_verifier(new CertVerifier), - proxy_service(proxy_service), - ssl_config_service(new SSLConfigServiceDefaults), - http_auth_handler_factory( - HttpAuthHandlerFactory::CreateDefault(host_resolver.get())), - net_log(NULL) {} - - scoped_ptr host_resolver; - scoped_ptr cert_verifier; - scoped_refptr proxy_service; - scoped_refptr ssl_config_service; - MockClientSocketFactory socket_factory; - scoped_ptr http_auth_handler_factory; - NetLog* net_log; -}; - -HttpNetworkSession* CreateSession(SessionDependencies* session_deps) { - HttpNetworkSession::Params params; - params.host_resolver = session_deps->host_resolver.get(); - params.cert_verifier = session_deps->cert_verifier.get(); - params.proxy_service = session_deps->proxy_service; - params.ssl_config_service = session_deps->ssl_config_service; - params.client_socket_factory = &session_deps->socket_factory; - params.http_auth_handler_factory = - session_deps->http_auth_handler_factory.get(); - params.net_log = session_deps->net_log; - return new HttpNetworkSession(params); -} - -struct TestCase { - int num_streams; - bool ssl; -}; - -TestCase kTests[] = { - { 1, false }, - { 2, false }, - { 1, true}, - { 2, true}, -}; - -int PreconnectHelper(const TestCase& test, - HttpNetworkSession* session) { - SSLConfig ssl_config; - session->ssl_config_service()->GetSSLConfig(&ssl_config); - - HttpRequestInfo request; - request.method = "GET"; - request.url = test.ssl ? GURL("https://www.google.com") : - GURL("http://www.google.com"); - request.load_flags = 0; - - ProxyInfo proxy_info; - TestCompletionCallback callback; - - int rv = session->http_stream_factory()->PreconnectStreams( - test.num_streams, &request, &ssl_config, &proxy_info, session, - BoundNetLog(), &callback); - if (rv != ERR_IO_PENDING) - return ERR_UNEXPECTED; - return callback.WaitForResult(); -}; - -template -class CapturePreconnectsSocketPool : public ParentPool { - public: - CapturePreconnectsSocketPool(HostResolver* host_resolver, - CertVerifier* cert_verifier); - - int last_num_streams() const { - return last_num_streams_; - } - - virtual int RequestSocket(const std::string& group_name, - const void* socket_params, - RequestPriority priority, - ClientSocketHandle* handle, - CompletionCallback* callback, - const BoundNetLog& net_log) { - ADD_FAILURE(); - return ERR_UNEXPECTED; - } - - virtual void RequestSockets(const std::string& group_name, - const void* socket_params, - int num_sockets, - const BoundNetLog& net_log) { - last_num_streams_ = num_sockets; - } - - virtual void CancelRequest(const std::string& group_name, - ClientSocketHandle* handle) { - ADD_FAILURE(); - } - virtual void ReleaseSocket(const std::string& group_name, - ClientSocket* socket, - int id) { - ADD_FAILURE(); - } - virtual void CloseIdleSockets() { - ADD_FAILURE(); - } - virtual int IdleSocketCount() const { - ADD_FAILURE(); - return 0; - } - virtual int IdleSocketCountInGroup(const std::string& group_name) const { - ADD_FAILURE(); - return 0; - } - virtual LoadState GetLoadState(const std::string& group_name, - const ClientSocketHandle* handle) const { - ADD_FAILURE(); - return LOAD_STATE_IDLE; - } - virtual base::TimeDelta ConnectionTimeout() const { - return base::TimeDelta(); - } - - private: - int last_num_streams_; -}; - -typedef CapturePreconnectsSocketPool -CapturePreconnectsTCPSocketPool; -typedef CapturePreconnectsSocketPool -CapturePreconnectsHttpProxySocketPool; -typedef CapturePreconnectsSocketPool -CapturePreconnectsSOCKSSocketPool; -typedef CapturePreconnectsSocketPool -CapturePreconnectsSSLSocketPool; - -template -CapturePreconnectsSocketPool::CapturePreconnectsSocketPool( - HostResolver* host_resolver, CertVerifier* /* cert_verifier */) - : ParentPool(0, 0, NULL, host_resolver, NULL, NULL), - last_num_streams_(-1) {} - -template<> -CapturePreconnectsHttpProxySocketPool::CapturePreconnectsSocketPool( - HostResolver* host_resolver, CertVerifier* /* cert_verifier */) - : HttpProxyClientSocketPool(0, 0, NULL, host_resolver, NULL, NULL, NULL), - last_num_streams_(-1) {} - -template<> -CapturePreconnectsSSLSocketPool::CapturePreconnectsSocketPool( - HostResolver* host_resolver, CertVerifier* cert_verifier) - : SSLClientSocketPool(0, 0, NULL, host_resolver, cert_verifier, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL), - last_num_streams_(-1) {} - -TEST(HttpStreamFactoryTest, PreconnectDirect) { - for (size_t i = 0; i < arraysize(kTests); ++i) { - SessionDependencies session_deps(ProxyService::CreateDirect()); - scoped_refptr session(CreateSession(&session_deps)); - HttpNetworkSessionPeer peer(session); - CapturePreconnectsTCPSocketPool* tcp_conn_pool = - new CapturePreconnectsTCPSocketPool( - session_deps.host_resolver.get(), - session_deps.cert_verifier.get()); - peer.SetTCPSocketPool(tcp_conn_pool); - CapturePreconnectsSSLSocketPool* ssl_conn_pool = - new CapturePreconnectsSSLSocketPool( - session_deps.host_resolver.get(), - session_deps.cert_verifier.get()); - peer.SetSSLSocketPool(ssl_conn_pool); - EXPECT_EQ(OK, PreconnectHelper(kTests[i], session)); - if (kTests[i].ssl) - EXPECT_EQ(kTests[i].num_streams, ssl_conn_pool->last_num_streams()); - else - EXPECT_EQ(kTests[i].num_streams, tcp_conn_pool->last_num_streams()); - } -} - -TEST(HttpStreamFactoryTest, PreconnectHttpProxy) { - for (size_t i = 0; i < arraysize(kTests); ++i) { - SessionDependencies session_deps(ProxyService::CreateFixed("http_proxy")); - scoped_refptr session(CreateSession(&session_deps)); - HttpNetworkSessionPeer peer(session); - HostPortPair proxy_host("http_proxy", 80); - CapturePreconnectsHttpProxySocketPool* http_proxy_pool = - new CapturePreconnectsHttpProxySocketPool( - session_deps.host_resolver.get(), - session_deps.cert_verifier.get()); - peer.SetSocketPoolForHTTPProxy(proxy_host, http_proxy_pool); - CapturePreconnectsSSLSocketPool* ssl_conn_pool = - new CapturePreconnectsSSLSocketPool( - session_deps.host_resolver.get(), - session_deps.cert_verifier.get()); - peer.SetSocketPoolForSSLWithProxy(proxy_host, ssl_conn_pool); - EXPECT_EQ(OK, PreconnectHelper(kTests[i], session)); - if (kTests[i].ssl) - EXPECT_EQ(kTests[i].num_streams, ssl_conn_pool->last_num_streams()); - else - EXPECT_EQ(kTests[i].num_streams, http_proxy_pool->last_num_streams()); - } -} - -TEST(HttpStreamFactoryTest, PreconnectSocksProxy) { - for (size_t i = 0; i < arraysize(kTests); ++i) { - SessionDependencies session_deps( - ProxyService::CreateFixed("socks4://socks_proxy:1080")); - scoped_refptr session(CreateSession(&session_deps)); - HttpNetworkSessionPeer peer(session); - HostPortPair proxy_host("socks_proxy", 1080); - CapturePreconnectsSOCKSSocketPool* socks_proxy_pool = - new CapturePreconnectsSOCKSSocketPool( - session_deps.host_resolver.get(), - session_deps.cert_verifier.get()); - peer.SetSocketPoolForSOCKSProxy(proxy_host, socks_proxy_pool); - CapturePreconnectsSSLSocketPool* ssl_conn_pool = - new CapturePreconnectsSSLSocketPool( - session_deps.host_resolver.get(), - session_deps.cert_verifier.get()); - peer.SetSocketPoolForSSLWithProxy(proxy_host, ssl_conn_pool); - EXPECT_EQ(OK, PreconnectHelper(kTests[i], session)); - if (kTests[i].ssl) - EXPECT_EQ(kTests[i].num_streams, ssl_conn_pool->last_num_streams()); - else - EXPECT_EQ(kTests[i].num_streams, socks_proxy_pool->last_num_streams()); - } -} - -TEST(HttpStreamFactoryTest, PreconnectDirectWithExistingSpdySession) { - for (size_t i = 0; i < arraysize(kTests); ++i) { - SessionDependencies session_deps(ProxyService::CreateDirect()); - scoped_refptr session(CreateSession(&session_deps)); - HttpNetworkSessionPeer peer(session); - - // Set an existing SpdySession in the pool. - HostPortPair host_port_pair("www.google.com", 443); - HostPortProxyPair pair(host_port_pair, ProxyServer::Direct()); - scoped_refptr spdy_session = - session->spdy_session_pool()->Get( - pair, session->mutable_spdy_settings(), BoundNetLog()); - - CapturePreconnectsTCPSocketPool* tcp_conn_pool = - new CapturePreconnectsTCPSocketPool( - session_deps.host_resolver.get(), - session_deps.cert_verifier.get()); - peer.SetTCPSocketPool(tcp_conn_pool); - CapturePreconnectsSSLSocketPool* ssl_conn_pool = - new CapturePreconnectsSSLSocketPool( - session_deps.host_resolver.get(), - session_deps.cert_verifier.get()); - peer.SetSSLSocketPool(ssl_conn_pool); - EXPECT_EQ(OK, PreconnectHelper(kTests[i], session)); - // We shouldn't be preconnecting if we have an existing session, which is - // the case for https://www.google.com. - if (kTests[i].ssl) - EXPECT_EQ(-1, ssl_conn_pool->last_num_streams()); - else - EXPECT_EQ(kTests[i].num_streams, tcp_conn_pool->last_num_streams()); - } -} - -} // namespace - -} // namespace net diff --git a/net/http/http_stream_request.cc b/net/http/http_stream_request.cc deleted file mode 100644 index 4814e55..0000000 --- a/net/http/http_stream_request.cc +++ /dev/null @@ -1,1105 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/http/http_stream_request.h" - -#include "base/stl_util-inl.h" -#include "base/string_number_conversions.h" -#include "base/string_util.h" -#include "base/stringprintf.h" -#include "net/base/connection_type_histograms.h" -#include "net/base/net_log.h" -#include "net/base/net_util.h" -#include "net/base/ssl_cert_request_info.h" -#include "net/http/http_basic_stream.h" -#include "net/http/http_network_session.h" -#include "net/http/http_proxy_client_socket.h" -#include "net/http/http_proxy_client_socket_pool.h" -#include "net/http/http_request_info.h" -#include "net/socket/client_socket_handle.h" -#include "net/socket/client_socket_pool.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" -#include "net/spdy/spdy_session_pool.h" - -namespace net { - -namespace { - -GURL UpgradeUrlToHttps(const GURL& original_url) { - GURL::Replacements replacements; - // new_sheme and new_port need to be in scope here because GURL::Replacements - // references the memory contained by them directly. - const std::string new_scheme = "https"; - const std::string new_port = base::IntToString(443); - replacements.SetSchemeStr(new_scheme); - replacements.SetPortStr(new_port); - return original_url.ReplaceComponents(replacements); -} - -} // namespace - -HttpStreamRequest::HttpStreamRequest( - StreamFactory* factory, - HttpNetworkSession* session) - : request_info_(NULL), - proxy_info_(NULL), - ssl_config_(NULL), - session_(session), - ALLOW_THIS_IN_INITIALIZER_LIST( - io_callback_(this, &HttpStreamRequest::OnIOComplete)), - connection_(new ClientSocketHandle), - factory_(factory), - delegate_(NULL), - next_state_(STATE_NONE), - pac_request_(NULL), - using_ssl_(false), - using_spdy_(false), - force_spdy_always_(HttpStreamFactory::force_spdy_always()), - force_spdy_over_ssl_(HttpStreamFactory::force_spdy_over_ssl()), - spdy_certificate_error_(OK), - alternate_protocol_(HttpAlternateProtocols::UNINITIALIZED), - establishing_tunnel_(false), - was_alternate_protocol_available_(false), - was_npn_negotiated_(false), - preconnect_delegate_(NULL), - num_streams_(0), - ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { - if (HttpStreamFactory::use_alternate_protocols()) - alternate_protocol_mode_ = kUnspecified; - else - alternate_protocol_mode_ = kDoNotUseAlternateProtocol; -} - -HttpStreamRequest::~HttpStreamRequest() { - // When we're in a partially constructed state, waiting for the user to - // provide certificate handling information or authentication, we can't reuse - // this stream at all. - if (next_state_ == STATE_WAITING_USER_ACTION) { - connection_->socket()->Disconnect(); - connection_.reset(); - } - - if (pac_request_) - session_->proxy_service()->CancelPacRequest(pac_request_); - - // The stream could be in a partial state. It is not reusable. - if (stream_.get() && next_state_ != STATE_DONE) - stream_->Close(true /* not reusable */); -} - -void HttpStreamRequest::Start(const HttpRequestInfo* request_info, - SSLConfig* ssl_config, - ProxyInfo* proxy_info, - Delegate* delegate, - const BoundNetLog& net_log) { - DCHECK(preconnect_delegate_ == NULL && delegate_ == NULL); - DCHECK(delegate); - delegate_ = delegate; - StartInternal(request_info, ssl_config, proxy_info, net_log); -} - -int HttpStreamRequest::Preconnect(int num_streams, - const HttpRequestInfo* request_info, - SSLConfig* ssl_config, - ProxyInfo* proxy_info, - PreconnectDelegate* delegate, - const BoundNetLog& net_log) { - DCHECK(preconnect_delegate_ == NULL && delegate_ == NULL); - DCHECK(delegate); - num_streams_ = num_streams; - preconnect_delegate_ = delegate; - return StartInternal(request_info, ssl_config, proxy_info, net_log); -} - -int HttpStreamRequest::RestartWithCertificate(X509Certificate* client_cert) { - ssl_config()->client_cert = client_cert; - ssl_config()->send_client_cert = true; - next_state_ = STATE_INIT_CONNECTION; - // Reset the other member variables. - // Note: this is necessary only with SSL renegotiation. - stream_.reset(); - return RunLoop(OK); -} - -int HttpStreamRequest::RestartTunnelWithProxyAuth(const string16& username, - const string16& password) { - DCHECK(establishing_tunnel_); - next_state_ = STATE_RESTART_TUNNEL_AUTH; - stream_.reset(); - return RunLoop(OK); -} - -LoadState HttpStreamRequest::GetLoadState() const { - switch (next_state_) { - case STATE_RESOLVE_PROXY_COMPLETE: - return LOAD_STATE_RESOLVING_PROXY_FOR_URL; - case STATE_CREATE_STREAM_COMPLETE: - return connection_->GetLoadState(); - case STATE_INIT_CONNECTION_COMPLETE: - return LOAD_STATE_SENDING_REQUEST; - default: - return LOAD_STATE_IDLE; - } -} - -bool HttpStreamRequest::was_alternate_protocol_available() const { - return was_alternate_protocol_available_; -} - -bool HttpStreamRequest::was_npn_negotiated() const { - return was_npn_negotiated_; -} - -bool HttpStreamRequest::using_spdy() const { - return using_spdy_; -} - -void HttpStreamRequest::GetSSLInfo() { - DCHECK(using_ssl_); - DCHECK(!establishing_tunnel_); - DCHECK(connection_.get() && connection_->socket()); - SSLClientSocket* ssl_socket = - static_cast(connection_->socket()); - ssl_socket->GetSSLInfo(&ssl_info_); -} - -const HttpRequestInfo& HttpStreamRequest::request_info() const { - return *request_info_; -} - -ProxyInfo* HttpStreamRequest::proxy_info() const { - return proxy_info_; -} - -SSLConfig* HttpStreamRequest::ssl_config() const { - return ssl_config_; -} - -void HttpStreamRequest::OnStreamReadyCallback() { - DCHECK(stream_.get()); - delegate_->OnStreamReady(stream_.release()); -} - -void HttpStreamRequest::OnStreamFailedCallback(int result) { - delegate_->OnStreamFailed(result); -} - -void HttpStreamRequest::OnCertificateErrorCallback(int result, - const SSLInfo& ssl_info) { - delegate_->OnCertificateError(result, ssl_info); -} - -void HttpStreamRequest::OnNeedsProxyAuthCallback( - const HttpResponseInfo& response, - HttpAuthController* auth_controller) { - delegate_->OnNeedsProxyAuth(response, auth_controller); -} - -void HttpStreamRequest::OnNeedsClientAuthCallback( - SSLCertRequestInfo* cert_info) { - delegate_->OnNeedsClientAuth(cert_info); -} - -void HttpStreamRequest::OnHttpsProxyTunnelResponseCallback( - const HttpResponseInfo& response_info, - HttpStream* stream) { - delegate_->OnHttpsProxyTunnelResponse(response_info, stream); -} - -void HttpStreamRequest::OnPreconnectsComplete(int result) { - preconnect_delegate_->OnPreconnectsComplete(this, result); -} - -void HttpStreamRequest::OnIOComplete(int result) { - RunLoop(result); -} - -int HttpStreamRequest::RunLoop(int result) { - result = DoLoop(result); - - DCHECK(delegate_ || preconnect_delegate_); - - if (result == ERR_IO_PENDING) - return result; - - if (preconnect_delegate_) { - MessageLoop::current()->PostTask( - FROM_HERE, - method_factory_.NewRunnableMethod( - &HttpStreamRequest::OnPreconnectsComplete, result)); - return ERR_IO_PENDING; - } - - if (IsCertificateError(result)) { - // Retrieve SSL information from the socket. - GetSSLInfo(); - - next_state_ = STATE_WAITING_USER_ACTION; - MessageLoop::current()->PostTask( - FROM_HERE, - method_factory_.NewRunnableMethod( - &HttpStreamRequest::OnCertificateErrorCallback, - result, ssl_info_)); - return ERR_IO_PENDING; - } - - switch (result) { - case ERR_PROXY_AUTH_REQUESTED: - { - DCHECK(connection_.get()); - DCHECK(connection_->socket()); - DCHECK(establishing_tunnel_); - - HttpProxyClientSocket* http_proxy_socket = - static_cast(connection_->socket()); - const HttpResponseInfo* tunnel_auth_response = - http_proxy_socket->GetConnectResponseInfo(); - - next_state_ = STATE_WAITING_USER_ACTION; - MessageLoop::current()->PostTask( - FROM_HERE, - method_factory_.NewRunnableMethod( - &HttpStreamRequest::OnNeedsProxyAuthCallback, - *tunnel_auth_response, - http_proxy_socket->auth_controller())); - } - return ERR_IO_PENDING; - - case ERR_SSL_CLIENT_AUTH_CERT_NEEDED: - MessageLoop::current()->PostTask( - FROM_HERE, - method_factory_.NewRunnableMethod( - &HttpStreamRequest::OnNeedsClientAuthCallback, - connection_->ssl_error_response_info().cert_request_info)); - return ERR_IO_PENDING; - - case ERR_HTTPS_PROXY_TUNNEL_RESPONSE: - { - DCHECK(connection_.get()); - DCHECK(connection_->socket()); - DCHECK(establishing_tunnel_); - - ProxyClientSocket* proxy_socket = - static_cast(connection_->socket()); - MessageLoop::current()->PostTask( - FROM_HERE, - method_factory_.NewRunnableMethod( - &HttpStreamRequest::OnHttpsProxyTunnelResponseCallback, - *proxy_socket->GetConnectResponseInfo(), - proxy_socket->CreateConnectResponseStream())); - return ERR_IO_PENDING; - } - - case OK: - next_state_ = STATE_DONE; - MessageLoop::current()->PostTask( - FROM_HERE, - method_factory_.NewRunnableMethod( - &HttpStreamRequest::OnStreamReadyCallback)); - return ERR_IO_PENDING; - - default: - MessageLoop::current()->PostTask( - FROM_HERE, - method_factory_.NewRunnableMethod( - &HttpStreamRequest::OnStreamFailedCallback, - result)); - return ERR_IO_PENDING; - } - return result; -} - -int HttpStreamRequest::DoLoop(int result) { - DCHECK_NE(next_state_, STATE_NONE); - int rv = result; - do { - State state = next_state_; - next_state_ = STATE_NONE; - switch (state) { - case STATE_RESOLVE_PROXY: - DCHECK_EQ(OK, rv); - rv = DoResolveProxy(); - break; - case STATE_RESOLVE_PROXY_COMPLETE: - rv = DoResolveProxyComplete(rv); - break; - case STATE_INIT_CONNECTION: - DCHECK_EQ(OK, rv); - rv = DoInitConnection(); - break; - case STATE_INIT_CONNECTION_COMPLETE: - rv = DoInitConnectionComplete(rv); - break; - case STATE_WAITING_USER_ACTION: - rv = DoWaitingUserAction(rv); - break; - case STATE_RESTART_TUNNEL_AUTH: - DCHECK_EQ(OK, rv); - rv = DoRestartTunnelAuth(); - break; - case STATE_RESTART_TUNNEL_AUTH_COMPLETE: - rv = DoRestartTunnelAuthComplete(rv); - break; - case STATE_CREATE_STREAM: - DCHECK_EQ(OK, rv); - rv = DoCreateStream(); - break; - case STATE_CREATE_STREAM_COMPLETE: - rv = DoCreateStreamComplete(rv); - break; - default: - NOTREACHED() << "bad state"; - rv = ERR_FAILED; - break; - } - } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE); - return rv; -} - -int HttpStreamRequest::StartInternal(const HttpRequestInfo* request_info, - SSLConfig* ssl_config, - ProxyInfo* proxy_info, - const BoundNetLog& net_log) { - CHECK_EQ(STATE_NONE, next_state_); - request_info_ = request_info; - ssl_config_ = ssl_config; - proxy_info_ = proxy_info; - net_log_ = net_log; - next_state_ = STATE_RESOLVE_PROXY; - int rv = RunLoop(OK); - DCHECK_EQ(ERR_IO_PENDING, rv); - return rv; -} - -int HttpStreamRequest::DoResolveProxy() { - DCHECK(!pac_request_); - - next_state_ = STATE_RESOLVE_PROXY_COMPLETE; - - // |endpoint_| indicates the final destination endpoint. - endpoint_ = HostPortPair(request_info().url.HostNoBrackets(), - request_info().url.EffectiveIntPort()); - - // Extra URL we might be attempting to resolve to. - GURL alternate_endpoint_url = request_info().url; - - // Tracks whether we are using |request_.url| or |alternate_endpoint_url|. - const GURL *curr_endpoint_url = &request_info().url; - - alternate_endpoint_url = - factory_->ApplyHostMappingRules(alternate_endpoint_url, &endpoint_); - - const HttpAlternateProtocols& alternate_protocols = - session_->alternate_protocols(); - if (HttpStreamFactory::spdy_enabled() && - alternate_protocols.HasAlternateProtocolFor(endpoint_)) { - was_alternate_protocol_available_ = true; - if (alternate_protocol_mode_ == kUnspecified) { - HttpAlternateProtocols::PortProtocolPair alternate = - alternate_protocols.GetAlternateProtocolFor(endpoint_); - if (alternate.protocol != HttpAlternateProtocols::BROKEN) { - DCHECK_LE(HttpAlternateProtocols::NPN_SPDY_1, alternate.protocol); - DCHECK_GT(HttpAlternateProtocols::NUM_ALTERNATE_PROTOCOLS, - alternate.protocol); - endpoint_.set_port(alternate.port); - alternate_protocol_ = alternate.protocol; - alternate_protocol_mode_ = kUsingAlternateProtocol; - alternate_endpoint_url = UpgradeUrlToHttps(*curr_endpoint_url); - curr_endpoint_url = &alternate_endpoint_url; - } - } - } - - if (request_info().load_flags & LOAD_BYPASS_PROXY) { - proxy_info()->UseDirect(); - return OK; - } - - return session_->proxy_service()->ResolveProxy( - *curr_endpoint_url, proxy_info(), &io_callback_, &pac_request_, - net_log_); -} - -int HttpStreamRequest::DoResolveProxyComplete(int result) { - pac_request_ = NULL; - - if (result != OK) - return result; - - // TODO(mbelshe): consider retrying ResolveProxy if we came here via use of - // AlternateProtocol. - - // Remove unsupported proxies from the list. - proxy_info()->RemoveProxiesWithoutScheme( - ProxyServer::SCHEME_DIRECT | - ProxyServer::SCHEME_HTTP | ProxyServer::SCHEME_HTTPS | - ProxyServer::SCHEME_SOCKS4 | ProxyServer::SCHEME_SOCKS5); - - if (proxy_info()->is_empty()) { - // No proxies/direct to choose from. This happens when we don't support any - // of the proxies in the returned list. - return ERR_NO_SUPPORTED_PROXIES; - } - - next_state_ = STATE_INIT_CONNECTION; - return OK; -} - -bool HasSpdyExclusion(const HostPortPair& endpoint) { - std::list* exclusions = - HttpStreamFactory::forced_spdy_exclusions(); - if (!exclusions) - return false; - - std::list::const_iterator it; - for (it = exclusions->begin(); it != exclusions->end(); it++) - if (it->Equals(endpoint)) - return true; - return false; -} - -bool HttpStreamRequest::ShouldForceSpdySSL() { - bool rv = force_spdy_always_ && force_spdy_over_ssl_; - return rv && !HasSpdyExclusion(endpoint_); -} - -bool HttpStreamRequest::ShouldForceSpdyWithoutSSL() { - bool rv = force_spdy_always_ && !force_spdy_over_ssl_; - return rv && !HasSpdyExclusion(endpoint_); -} - -int HttpStreamRequest::DoInitConnection() { - DCHECK(!connection_->is_initialized()); - DCHECK(proxy_info()->proxy_server().is_valid()); - next_state_ = STATE_INIT_CONNECTION_COMPLETE; - - bool want_spdy_over_npn = - alternate_protocol_mode_ == kUsingAlternateProtocol && - alternate_protocol_ == HttpAlternateProtocols::NPN_SPDY_2; - using_ssl_ = request_info().url.SchemeIs("https") || - ShouldForceSpdySSL() || want_spdy_over_npn; - using_spdy_ = false; - - // If spdy has been turned off on-the-fly, then there may be SpdySessions - // still active. But don't use them unless spdy is currently on. - if (HttpStreamFactory::spdy_enabled() && !HasSpdyExclusion(endpoint_)) { - // Check first if we have a spdy session for this group. If so, then go - // straight to using that. - HostPortProxyPair pair(endpoint_, proxy_info()->proxy_server()); - if (session_->spdy_session_pool()->HasSession(pair)) { - // If we're preconnecting, but we already have a SpdySession, we don't - // actually need to preconnect any sockets, so we're done. - if (preconnect_delegate_) - return OK; - using_spdy_ = true; - next_state_ = STATE_CREATE_STREAM; - return OK; - } - // Check next if we have a spdy session for this proxy. If so, then go - // straight to using that. - if (IsHttpsProxyAndHttpUrl()) { - HostPortProxyPair proxy(proxy_info()->proxy_server().host_port_pair(), - ProxyServer::Direct()); - if (session_->spdy_session_pool()->HasSession(proxy)) { - using_spdy_ = true; - next_state_ = STATE_CREATE_STREAM; - return OK; - } - } - } - - // Build the string used to uniquely identify connections of this type. - // Determine the host and port to connect to. - std::string connection_group = endpoint_.ToString(); - DCHECK(!connection_group.empty()); - - if (using_ssl_) - connection_group = base::StringPrintf("ssl/%s", connection_group.c_str()); - - // If the user is refreshing the page, bypass the host cache. - bool disable_resolver_cache = - request_info().load_flags & LOAD_BYPASS_CACHE || - request_info().load_flags & LOAD_VALIDATE_CACHE || - request_info().load_flags & LOAD_DISABLE_CACHE; - - // Build up the connection parameters. - scoped_refptr tcp_params; - scoped_refptr http_proxy_params; - scoped_refptr socks_params; - scoped_ptr proxy_host_port; - - if (proxy_info()->is_direct()) { - tcp_params = new TCPSocketParams(endpoint_, request_info().priority, - request_info().referrer, - disable_resolver_cache); - } else { - ProxyServer proxy_server = proxy_info()->proxy_server(); - proxy_host_port.reset(new HostPortPair(proxy_server.host_port_pair())); - scoped_refptr proxy_tcp_params( - new TCPSocketParams(*proxy_host_port, request_info().priority, - request_info().referrer, disable_resolver_cache)); - - if (proxy_info()->is_http() || proxy_info()->is_https()) { - GURL authentication_url = request_info().url; - if (using_ssl_ && !authentication_url.SchemeIs("https")) { - // If a proxy tunnel connection needs to be established due to - // an Alternate-Protocol, the URL needs to be changed to indicate - // https or digest authentication attempts will fail. - // For example, suppose the initial request was for - // "http://www.example.com/index.html". If this is an SSL - // upgrade due to alternate protocol, the digest authorization - // should have a uri="www.example.com:443" field rather than a - // "/index.html" entry, even though the original request URL has not - // changed. - authentication_url = UpgradeUrlToHttps(authentication_url); - } - establishing_tunnel_ = using_ssl_; - std::string user_agent; - request_info().extra_headers.GetHeader(HttpRequestHeaders::kUserAgent, - &user_agent); - scoped_refptr ssl_params; - if (proxy_info()->is_https()) { - // Set ssl_params, and unset proxy_tcp_params - ssl_params = GenerateSSLParams(proxy_tcp_params, NULL, NULL, - ProxyServer::SCHEME_DIRECT, - *proxy_host_port.get(), - want_spdy_over_npn); - proxy_tcp_params = NULL; - } - - http_proxy_params = - new HttpProxySocketParams(proxy_tcp_params, - ssl_params, - authentication_url, - user_agent, - 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()); - char socks_version; - if (proxy_server.scheme() == ProxyServer::SCHEME_SOCKS5) - socks_version = '5'; - else - socks_version = '4'; - connection_group = base::StringPrintf( - "socks%c/%s", socks_version, connection_group.c_str()); - - socks_params = new SOCKSSocketParams(proxy_tcp_params, - socks_version == '5', - endpoint_, - request_info().priority, - request_info().referrer); - } - } - - // Deal with SSL - which layers on top of any given proxy. - if (using_ssl_) { - scoped_refptr ssl_params = - GenerateSSLParams(tcp_params, http_proxy_params, socks_params, - proxy_info()->proxy_server().scheme(), - HostPortPair::FromURL(request_info().url), - want_spdy_over_npn); - SSLClientSocketPool* ssl_pool = NULL; - if (proxy_info()->is_direct()) - ssl_pool = session_->ssl_socket_pool(); - else - ssl_pool = session_->GetSocketPoolForSSLWithProxy(*proxy_host_port); - - if (preconnect_delegate_) { - RequestSocketsForPool(ssl_pool, connection_group, ssl_params, - num_streams_, net_log_); - return OK; - } - - return connection_->Init(connection_group, ssl_params, - request_info().priority, &io_callback_, ssl_pool, - net_log_); - } - - // Finally, get the connection started. - if (proxy_info()->is_http() || proxy_info()->is_https()) { - HttpProxyClientSocketPool* pool = - session_->GetSocketPoolForHTTPProxy(*proxy_host_port); - if (preconnect_delegate_) { - RequestSocketsForPool(pool, connection_group, http_proxy_params, - num_streams_, net_log_); - return OK; - } - - return connection_->Init(connection_group, http_proxy_params, - request_info().priority, &io_callback_, - pool, net_log_); - } - - if (proxy_info()->is_socks()) { - SOCKSClientSocketPool* pool = - session_->GetSocketPoolForSOCKSProxy(*proxy_host_port); - if (preconnect_delegate_) { - RequestSocketsForPool(pool, connection_group, socks_params, - num_streams_, net_log_); - return OK; - } - - return connection_->Init(connection_group, socks_params, - request_info().priority, &io_callback_, pool, - net_log_); - } - - DCHECK(proxy_info()->is_direct()); - - TCPClientSocketPool* pool = session_->tcp_socket_pool(); - if (preconnect_delegate_) { - RequestSocketsForPool(pool, connection_group, tcp_params, - num_streams_, net_log_); - return OK; - } - - return connection_->Init(connection_group, tcp_params, - request_info().priority, &io_callback_, - pool, net_log_); -} - -int HttpStreamRequest::DoInitConnectionComplete(int result) { - if (preconnect_delegate_) { - DCHECK_EQ(OK, result); - return OK; - } - - // |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->was_npn_negotiated()) { - was_npn_negotiated_ = true; - if (ssl_socket->was_spdy_negotiated()) - SwitchToSpdyMode(); - } - if (ShouldForceSpdySSL()) - SwitchToSpdyMode(); - } else if (proxy_info()->is_https() && connection_->socket() && - result == OK) { - HttpProxyClientSocket* proxy_socket = - static_cast(connection_->socket()); - if (proxy_socket->using_spdy()) { - was_npn_negotiated_ = true; - SwitchToSpdyMode(); - } - } - - // We may be using spdy without SSL - if (ShouldForceSpdyWithoutSSL()) - SwitchToSpdyMode(); - - if (result == ERR_PROXY_AUTH_REQUESTED || - result == ERR_HTTPS_PROXY_TUNNEL_RESPONSE) { - DCHECK(!ssl_started); - // Other state (i.e. |using_ssl_|) suggests that |connection_| will have an - // SSL socket, but there was an error before that could happen. This - // puts the in progress HttpProxy socket into |connection_| in order to - // complete the auth (or read the response body). The tunnel restart code - // is careful to remove it before returning control to the rest of this - // class. - connection_.reset(connection_->release_pending_http_proxy_connection()); - return result; - } - - 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 (result < 0 && !ssl_started) - return ReconsiderProxyAfterError(result); - establishing_tunnel_ = false; - - if (connection_->socket()) { - LogHttpConnectedMetrics(*connection_); - - // We officially have a new connection. Record the type. - if (!connection_->is_reused()) { - ConnectionType type = using_spdy_ ? CONNECTION_SPDY : CONNECTION_HTTP; - UpdateConnectionTypeHistograms(type); - } - } - - // Handle SSL errors below. - if (using_ssl_) { - DCHECK(ssl_started); - if (IsCertificateError(result)) { - if (using_spdy_ && request_info().url.SchemeIs("http")) { - // We ignore certificate errors for http over spdy. - spdy_certificate_error_ = result; - result = OK; - } else { - result = HandleCertificateError(result); - if (result == OK && !connection_->socket()->IsConnectedAndIdle()) { - connection_->socket()->Disconnect(); - connection_->Reset(); - next_state_ = STATE_INIT_CONNECTION; - return result; - } - } - } - if (result < 0) - return result; - } - - next_state_ = STATE_CREATE_STREAM; - return OK; -} - -int HttpStreamRequest::DoWaitingUserAction(int result) { - // This state indicates that the stream request is in a partially - // completed state, and we've called back to the delegate for more - // information. - - // We're always waiting here for the delegate to call us back. - return ERR_IO_PENDING; -} - -int HttpStreamRequest::DoCreateStream() { - next_state_ = STATE_CREATE_STREAM_COMPLETE; - - // We only set the socket motivation if we're the first to use - // this socket. Is there a race for two SPDY requests? We really - // need to plumb this through to the connect level. - if (connection_->socket() && !connection_->is_reused()) - SetSocketMotivation(); - - const ProxyServer& proxy_server = proxy_info()->proxy_server(); - - if (!using_spdy_) { - bool using_proxy = (proxy_info()->is_http() || proxy_info()->is_https()) && - request_info().url.SchemeIs("http"); - stream_.reset(new HttpBasicStream(connection_.release(), NULL, - using_proxy)); - return OK; - } - - CHECK(!stream_.get()); - - bool direct = true; - SpdySessionPool* spdy_pool = session_->spdy_session_pool(); - scoped_refptr spdy_session; - - HostPortProxyPair pair(endpoint_, proxy_server); - if (spdy_pool->HasSession(pair)) { - // We have a SPDY session to the origin server. This might be a direct - // connection, or it might be a SPDY session through an HTTP or HTTPS proxy. - spdy_session = - spdy_pool->Get(pair, session_->mutable_spdy_settings(), net_log_); - } 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(), - ProxyServer::Direct()); - if (spdy_pool->HasSession(pair)) { - spdy_session = - spdy_pool->Get(pair, session_->mutable_spdy_settings(), net_log_); - } - direct = false; - } - - if (spdy_session.get()) { - // We picked up an existing session, so we don't need our socket. - if (connection_->socket()) - connection_->socket()->Disconnect(); - connection_->Reset(); - } else { - // SPDY can be negotiated using the TLS next protocol negotiation (NPN) - // extension, or just directly using SSL. Either way, |connection_| must - // contain an SSLClientSocket. - CHECK(connection_->socket()); - int error = spdy_pool->GetSpdySessionFromSocket( - pair, session_->mutable_spdy_settings(), connection_.release(), - net_log_, spdy_certificate_error_, &spdy_session, using_ssl_); - if (error != OK) - return error; - } - - if (spdy_session->IsClosed()) - return ERR_CONNECTION_CLOSED; - - bool use_relative_url = direct || request_info().url.SchemeIs("https"); - stream_.reset(new SpdyHttpStream(spdy_session, use_relative_url)); - return OK; -} - -int HttpStreamRequest::DoCreateStreamComplete(int result) { - if (result < 0) - return result; - - next_state_ = STATE_NONE; - return OK; -} - -int HttpStreamRequest::DoRestartTunnelAuth() { - next_state_ = STATE_RESTART_TUNNEL_AUTH_COMPLETE; - HttpProxyClientSocket* http_proxy_socket = - static_cast(connection_->socket()); - return http_proxy_socket->RestartWithAuth(&io_callback_); -} - -int HttpStreamRequest::DoRestartTunnelAuthComplete(int result) { - if (result == ERR_PROXY_AUTH_REQUESTED) - return result; - - if (result == OK) { - // Now that we've got the HttpProxyClientSocket connected. We have - // to release it as an idle socket into the pool and start the connection - // process from the beginning. Trying to pass it in with the - // SSLSocketParams might cause a deadlock since params are dispatched - // interchangeably. This request won't necessarily get this http proxy - // socket, but there will be forward progress. - connection_->Reset(); - establishing_tunnel_ = false; - next_state_ = STATE_INIT_CONNECTION; - return OK; - } - - return ReconsiderProxyAfterError(result); -} - -void HttpStreamRequest::SetSocketMotivation() { - if (request_info_->motivation == HttpRequestInfo::PRECONNECT_MOTIVATED) - connection_->socket()->SetSubresourceSpeculation(); - else if (request_info_->motivation == HttpRequestInfo::OMNIBOX_MOTIVATED) - connection_->socket()->SetOmniboxSpeculation(); - // 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 HttpStreamRequest::GenerateSSLParams( - scoped_refptr tcp_params, - scoped_refptr http_proxy_params, - scoped_refptr socks_params, - ProxyServer::Scheme proxy_scheme, - const HostPortPair& host_and_port, - bool want_spdy_over_npn) { - - if (factory_->IsTLSIntolerantServer(request_info().url)) { - LOG(WARNING) << "Falling back to SSLv3 because host is TLS intolerant: " - << GetHostAndPort(request_info().url); - ssl_config()->ssl3_fallback = true; - ssl_config()->tls1_enabled = false; - } - - if (proxy_info()->is_https() && ssl_config()->send_client_cert) { - // When connecting through an HTTPS proxy, disable TLS False Start so - // that client authentication errors can be distinguished between those - // originating from the proxy server (ERR_PROXY_CONNECTION_FAILED) and - // those originating from the endpoint (ERR_SSL_PROTOCOL_ERROR / - // ERR_BAD_SSL_CLIENT_AUTH_CERT). - // TODO(rch): This assumes that the HTTPS proxy will only request a - // client certificate during the initial handshake. - // http://crbug.com/59292 - ssl_config()->false_start_enabled = false; - } - - UMA_HISTOGRAM_ENUMERATION("Net.ConnectionUsedSSLv3Fallback", - static_cast(ssl_config()->ssl3_fallback), 2); - - int load_flags = request_info().load_flags; - if (HttpStreamFactory::ignore_certificate_errors()) - load_flags |= LOAD_IGNORE_ALL_CERT_ERRORS; - if (request_info().load_flags & LOAD_VERIFY_EV_CERT) - ssl_config()->verify_ev_cert = true; - - if (proxy_info()->proxy_server().scheme() == ProxyServer::SCHEME_HTTP || - proxy_info()->proxy_server().scheme() == ProxyServer::SCHEME_HTTPS) { - ssl_config()->mitm_proxies_allowed = true; - } - - scoped_refptr ssl_params( - new SSLSocketParams(tcp_params, socks_params, http_proxy_params, - proxy_scheme, host_and_port, - *ssl_config(), load_flags, - ShouldForceSpdySSL(), - want_spdy_over_npn)); - - return ssl_params; -} - - -void HttpStreamRequest::MarkBrokenAlternateProtocolAndFallback() { - // We have to: - // * Reset the endpoint to be the unmodified URL specified destination. - // * Mark the endpoint as broken so we don't try again. - // * Set the alternate protocol mode to kDoNotUseAlternateProtocol so we - // ignore future Alternate-Protocol headers from the HostPortPair. - // * Reset the connection and go back to STATE_INIT_CONNECTION. - - endpoint_ = HostPortPair(request_info().url.HostNoBrackets(), - request_info().url.EffectiveIntPort()); - - session_->mutable_alternate_protocols()->MarkBrokenAlternateProtocolFor( - endpoint_); - - alternate_protocol_mode_ = kDoNotUseAlternateProtocol; - if (connection_->socket()) - connection_->socket()->Disconnect(); - connection_->Reset(); - next_state_ = STATE_INIT_CONNECTION; -} - -int HttpStreamRequest::ReconsiderProxyAfterError(int error) { - DCHECK(!pac_request_); - - // A failure to resolve the hostname or any error related to establishing a - // TCP connection could be grounds for trying a new proxy configuration. - // - // Why do this when a hostname cannot be resolved? Some URLs only make sense - // to proxy servers. The hostname in those URLs might fail to resolve if we - // are still using a non-proxy config. We need to check if a proxy config - // now exists that corresponds to a proxy server that could load the URL. - // - switch (error) { - case ERR_PROXY_CONNECTION_FAILED: - case ERR_NAME_NOT_RESOLVED: - case ERR_INTERNET_DISCONNECTED: - case ERR_ADDRESS_UNREACHABLE: - case ERR_CONNECTION_CLOSED: - case ERR_CONNECTION_RESET: - case ERR_CONNECTION_REFUSED: - case ERR_CONNECTION_ABORTED: - case ERR_TIMED_OUT: - case ERR_TUNNEL_CONNECTION_FAILED: - case ERR_SOCKS_CONNECTION_FAILED: - break; - case ERR_SOCKS_CONNECTION_HOST_UNREACHABLE: - // Remap the SOCKS-specific "host unreachable" error to a more - // generic error code (this way consumers like the link doctor - // know to substitute their error page). - // - // Note that if the host resolving was done by the SOCSK5 proxy, we can't - // differentiate between a proxy-side "host not found" versus a proxy-side - // "address unreachable" error, and will report both of these failures as - // ERR_ADDRESS_UNREACHABLE. - return ERR_ADDRESS_UNREACHABLE; - default: - return error; - } - - if (request_info().load_flags & LOAD_BYPASS_PROXY) { - return error; - } - - if (proxy_info()->is_https() && ssl_config()->send_client_cert) { - session_->ssl_client_auth_cache()->Remove( - proxy_info()->proxy_server().host_port_pair().ToString()); - } - - int rv = session_->proxy_service()->ReconsiderProxyAfterError( - request_info().url, proxy_info(), &io_callback_, &pac_request_, - net_log_); - if (rv == OK || rv == ERR_IO_PENDING) { - // If the error was during connection setup, there is no socket to - // disconnect. - if (connection_->socket()) - connection_->socket()->Disconnect(); - connection_->Reset(); - next_state_ = STATE_RESOLVE_PROXY_COMPLETE; - } else { - // If ReconsiderProxyAfterError() failed synchronously, it means - // there was nothing left to fall-back to, so fail the transaction - // with the last connection error we got. - // TODO(eroman): This is a confusing contract, make it more obvious. - rv = error; - } - - return rv; -} - -int HttpStreamRequest::HandleCertificateError(int error) { - DCHECK(using_ssl_); - DCHECK(IsCertificateError(error)); - - SSLClientSocket* ssl_socket = - static_cast(connection_->socket()); - ssl_socket->GetSSLInfo(&ssl_info_); - - // Add the bad certificate to the set of allowed certificates in the - // SSL info object. This data structure will be consulted after calling - // RestartIgnoringLastError(). And the user will be asked interactively - // before RestartIgnoringLastError() is ever called. - SSLConfig::CertAndStatus bad_cert; - bad_cert.cert = ssl_info_.cert; - bad_cert.cert_status = ssl_info_.cert_status; - ssl_config()->allowed_bad_certs.push_back(bad_cert); - - int load_flags = request_info().load_flags; - if (HttpStreamFactory::ignore_certificate_errors()) - load_flags |= LOAD_IGNORE_ALL_CERT_ERRORS; - if (ssl_socket->IgnoreCertError(error, load_flags)) - return OK; - return error; -} - -void HttpStreamRequest::SwitchToSpdyMode() { - if (HttpStreamFactory::spdy_enabled()) - using_spdy_ = true; -} - -// static -void HttpStreamRequest::LogHttpConnectedMetrics( - const ClientSocketHandle& handle) { - UMA_HISTOGRAM_ENUMERATION("Net.HttpSocketType", handle.reuse_type(), - ClientSocketHandle::NUM_TYPES); - - switch (handle.reuse_type()) { - case ClientSocketHandle::UNUSED: - UMA_HISTOGRAM_CUSTOM_TIMES("Net.HttpConnectionLatency", - handle.setup_time(), - base::TimeDelta::FromMilliseconds(1), - base::TimeDelta::FromMinutes(10), - 100); - break; - case ClientSocketHandle::UNUSED_IDLE: - UMA_HISTOGRAM_CUSTOM_TIMES("Net.SocketIdleTimeBeforeNextUse_UnusedSocket", - handle.idle_time(), - base::TimeDelta::FromMilliseconds(1), - base::TimeDelta::FromMinutes(6), - 100); - break; - case ClientSocketHandle::REUSED_IDLE: - UMA_HISTOGRAM_CUSTOM_TIMES("Net.SocketIdleTimeBeforeNextUse_ReusedSocket", - handle.idle_time(), - base::TimeDelta::FromMilliseconds(1), - base::TimeDelta::FromMinutes(6), - 100); - break; - default: - NOTREACHED(); - break; - } -} - -} // namespace net diff --git a/net/http/http_stream_request.h b/net/http/http_stream_request.h deleted file mode 100644 index fca2332..0000000 --- a/net/http/http_stream_request.h +++ /dev/null @@ -1,252 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_HTTP_HTTP_STREAM_REQUEST_H_ -#define NET_HTTP_HTTP_STREAM_REQUEST_H_ - -#include "base/scoped_ptr.h" -#include "base/task.h" -#include "net/base/completion_callback.h" -#include "net/base/host_mapping_rules.h" -#include "net/base/ssl_config_service.h" -#include "net/http/http_auth.h" -#include "net/http/http_auth_controller.h" -#include "net/http/http_alternate_protocols.h" -#include "net/http/stream_factory.h" -#include "net/proxy/proxy_service.h" -#include "net/socket/client_socket_handle.h" - -namespace net { - -class ClientSocketHandle; -class HttpAuthController; -class HttpNetworkSession; -class HttpProxySocketParams; -class SOCKSSocketParams; -class SSLSocketParams; -class StreamRequestDelegate; -class TCPSocketParams; -struct HttpRequestInfo; - -// An HttpStreamRequest exists for each stream which is in progress of being -// created for the StreamFactory. -class HttpStreamRequest : public StreamRequest { - public: - class PreconnectDelegate { - public: - virtual ~PreconnectDelegate() {} - - virtual void OnPreconnectsComplete(HttpStreamRequest* request, - int result) = 0; - }; - - HttpStreamRequest(StreamFactory* factory, - HttpNetworkSession* session); - virtual ~HttpStreamRequest(); - - // Start initiates the process of creating a new HttpStream. - // 3 parameters are passed in by reference. The caller asserts that the - // lifecycle of these parameters will remain valid until the stream is - // created, failed, or destroyed. In the first two cases, the delegate will - // be called to notify completion of the request. - void Start(const HttpRequestInfo* request_info, - SSLConfig* ssl_config, - ProxyInfo* proxy_info, - Delegate* delegate, - const BoundNetLog& net_log); - - int Preconnect(int num_streams, - const HttpRequestInfo* request_info, - SSLConfig* ssl_config, - ProxyInfo* proxy_info, - PreconnectDelegate* delegate, - const BoundNetLog& net_log); - - // StreamRequest interface - virtual int RestartWithCertificate(X509Certificate* client_cert); - virtual int RestartTunnelWithProxyAuth(const string16& username, - const string16& password); - virtual LoadState GetLoadState() const; - - virtual bool was_alternate_protocol_available() const; - virtual bool was_npn_negotiated() const; - virtual bool using_spdy() const; - - private: - enum AlternateProtocolMode { - kUnspecified, // Unspecified, check HttpAlternateProtocols - kUsingAlternateProtocol, // Using an alternate protocol - kDoNotUseAlternateProtocol, // Failed to connect once, do not try again. - }; - - enum State { - STATE_RESOLVE_PROXY, - STATE_RESOLVE_PROXY_COMPLETE, - STATE_INIT_CONNECTION, - STATE_INIT_CONNECTION_COMPLETE, - STATE_WAITING_USER_ACTION, - STATE_RESTART_TUNNEL_AUTH, - STATE_RESTART_TUNNEL_AUTH_COMPLETE, - STATE_CREATE_STREAM, - STATE_CREATE_STREAM_COMPLETE, - STATE_DRAIN_BODY_FOR_AUTH_RESTART, - STATE_DRAIN_BODY_FOR_AUTH_RESTART_COMPLETE, - STATE_DONE, - STATE_NONE - }; - - const HttpRequestInfo& request_info() const; - ProxyInfo* proxy_info() const; - SSLConfig* ssl_config() const; - - // Callbacks to the delegate. - void OnStreamReadyCallback(); - void OnStreamFailedCallback(int result); - void OnCertificateErrorCallback(int result, const SSLInfo& ssl_info); - void OnNeedsProxyAuthCallback(const HttpResponseInfo& response_info, - HttpAuthController* auth_controller); - void OnNeedsClientAuthCallback(SSLCertRequestInfo* cert_info); - void OnHttpsProxyTunnelResponseCallback(const HttpResponseInfo& response_info, - HttpStream* stream); - void OnPreconnectsComplete(int result); - - void OnIOComplete(int result); - int RunLoop(int result); - int DoLoop(int result); - int StartInternal(const HttpRequestInfo* request_info, - SSLConfig* ssl_config, - ProxyInfo* proxy_info, - const BoundNetLog& net_log); - - // Each of these methods corresponds to a State value. Those with an input - // argument receive the result from the previous state. If a method returns - // ERR_IO_PENDING, then the result from OnIOComplete will be passed to the - // next state method as the result arg. - int DoResolveProxy(); - int DoResolveProxyComplete(int result); - int DoInitConnection(); - int DoInitConnectionComplete(int result); - int DoWaitingUserAction(int result); - int DoCreateStream(); - int DoCreateStreamComplete(int result); - int DoRestartTunnelAuth(); - int DoRestartTunnelAuthComplete(int result); - - // 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 GenerateSSLParams( - scoped_refptr tcp_params, - scoped_refptr http_proxy_params, - scoped_refptr socks_params, - ProxyServer::Scheme proxy_scheme, - const HostPortPair& host_and_port, - bool want_spdy_over_npn); - - // AlternateProtocol API - void MarkBrokenAlternateProtocolAndFallback(); - - // Retrieve SSLInfo from our SSL Socket. - // This must only be called when we are using an SSLSocket. - // After calling, the caller can use ssl_info_. - void GetSSLInfo(); - - // Called when we encounter a network error that could be resolved by trying - // a new proxy configuration. If there is another proxy configuration to try - // then this method sets next_state_ appropriately and returns either OK or - // ERR_IO_PENDING depending on whether or not the new proxy configuration is - // available synchronously or asynchronously. Otherwise, the given error - // code is simply returned. - int ReconsiderProxyAfterError(int error); - - // Called to handle a certificate error. Stores the certificate in the - // allowed_bad_certs list, and checks if the error can be ignored. Returns - // OK if it can be ignored, or the error code otherwise. - int HandleCertificateError(int error); - - // Called to handle a client certificate request. - int HandleCertificateRequest(int error); - - // Moves this stream request into SPDY mode. - void SwitchToSpdyMode(); - - // Should we force SPDY to run over SSL for this stream request. - bool ShouldForceSpdySSL(); - - // Should we force SPDY to run without SSL for this stream request. - bool ShouldForceSpdyWithoutSSL(); - - // Record histograms of latency until Connect() completes. - static void LogHttpConnectedMetrics(const ClientSocketHandle& handle); - - const HttpRequestInfo* request_info_; // Use request_info(). - ProxyInfo* proxy_info_; // Use proxy_info(). - SSLConfig* ssl_config_; // Use ssl_config(). - - scoped_refptr session_; - CompletionCallbackImpl io_callback_; - scoped_ptr connection_; - StreamFactory* const factory_; - Delegate* delegate_; - BoundNetLog net_log_; - State next_state_; - ProxyService::PacRequest* pac_request_; - SSLInfo ssl_info_; - // The hostname and port of the endpoint. This is not necessarily the one - // specified by the URL, due to Alternate-Protocol or fixed testing ports. - HostPortPair endpoint_; - - // True if handling a HTTPS request, or using SPDY with SSL - bool using_ssl_; - - // True if this network transaction is using SPDY instead of HTTP. - bool using_spdy_; - - // Force spdy for all connections. - bool force_spdy_always_; - - // Force spdy only for SSL connections. - bool force_spdy_over_ssl_; - - // The certificate error while using SPDY over SSL for insecure URLs. - int spdy_certificate_error_; - - scoped_refptr - auth_controllers_[HttpAuth::AUTH_NUM_TARGETS]; - - AlternateProtocolMode alternate_protocol_mode_; - - // Only valid if |alternate_protocol_mode_| == kUsingAlternateProtocol. - HttpAlternateProtocols::Protocol alternate_protocol_; - - // True when the tunnel is in the process of being established - we can't - // read from the socket until the tunnel is done. - bool establishing_tunnel_; - - scoped_ptr stream_; - - // True if finding the connection for this request found an alternate - // protocol was available. - bool was_alternate_protocol_available_; - - // True if we negotiated NPN. - bool was_npn_negotiated_; - - PreconnectDelegate* preconnect_delegate_; - - // Only used if |preconnect_delegate_| is non-NULL. - int num_streams_; - - ScopedRunnableMethodFactory method_factory_; - - DISALLOW_COPY_AND_ASSIGN(HttpStreamRequest); -}; - -} // namespace net - -#endif // NET_HTTP_HTTP_STREAM_REQUEST_H_ diff --git a/net/http/stream_factory.h b/net/http/stream_factory.h deleted file mode 100644 index 1a7aa77..0000000 --- a/net/http/stream_factory.h +++ /dev/null @@ -1,156 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_HTTP_STREAM_FACTORY_H_ -#define NET_HTTP_STREAM_FACTORY_H_ - -#include - -#include "base/ref_counted.h" -#include "net/base/completion_callback.h" -#include "net/base/load_states.h" - -namespace net { - -class BoundNetLog; -class HostPortPair; -class HttpAlternateProtocols; -class HttpAuthController; -class HttpNetworkSession; -class HttpResponseInfo; -class HttpStream; -class ProxyInfo; -class SSLCertRequestInfo; -class SSLInfo; -class X509Certificate; -struct HttpRequestInfo; -struct SSLConfig; - -// The StreamRequest is the client's handle to the worker object which handles -// the creation of an HttpStream. While the HttpStream is being created, this -// object is the creator's handle for interacting with the HttpStream creation -// process. The request is cancelled by deleting it, after which no callbacks -// will be invoked. -class StreamRequest { - public: - // The StreamRequestDelegate is a set of callback methods for a - // StreamRequestJob. Generally, only one of these methods will be - // called as a result of a stream request. - class Delegate { - public: - virtual ~Delegate() {} - - // This is the success case. - // |stream| is now owned by the delegate. - virtual void OnStreamReady(HttpStream* stream) = 0; - - // This is the failure to create a stream case. - virtual void OnStreamFailed(int status) = 0; - - // Called when we have a certificate error for the request. - virtual void OnCertificateError(int status, const SSLInfo& ssl_info) = 0; - - // This is the failure case where we need proxy authentication during - // proxy tunnel establishment. For the tunnel case, we were unable to - // create the HttpStream, so the caller provides the auth and then resumes - // the StreamRequest. For the non-tunnel case, the caller will handle - // the authentication failure and restart the StreamRequest entirely. - // Ownership of |auth_controller| and |proxy_response| are owned - // by the StreamRequest. |proxy_response| is not guaranteed to be usable - // after the lifetime of this callback. The delegate may take a reference - // to |auth_controller| if it is needed beyond the lifetime of this - // callback. - virtual void OnNeedsProxyAuth(const HttpResponseInfo& proxy_response, - HttpAuthController* auth_controller) = 0; - - // This is the failure for SSL Client Auth - // Ownership of |cert_info| is retained by the StreamRequest. The delegate - // may take a reference if it needs the cert_info beyond the lifetime of - // this callback. - virtual void OnNeedsClientAuth(SSLCertRequestInfo* cert_info) = 0; - - // This is the failure of the CONNECT request through an HTTPS proxy. - // Headers can be read from |response_info|, while the body can be read - // from |stream|. - // Ownership of |stream| is transferred to the delegate. - virtual void OnHttpsProxyTunnelResponse( - const HttpResponseInfo& response_info, HttpStream* stream) = 0; - }; - - virtual ~StreamRequest() {} - - // When a HttpStream creation process requires a SSL Certificate, - // the delegate OnNeedsClientAuth handler will have been called. - // It now becomes the delegate's responsibility to collect the certificate - // (probably from the user), and then call this method to resume - // the HttpStream creation process. - // Ownership of |client_cert| remains with the StreamRequest. The - // delegate can take a reference if needed beyond the lifetime of this - // call. - virtual int RestartWithCertificate(X509Certificate* client_cert) = 0; - - // When a HttpStream creation process is stalled due to necessity - // of Proxy authentication credentials, the delegate OnNeedsProxyAuth - // will have been called. It now becomes the delegate's responsibility - // to collect the necessary credentials, and then call this method to - // resume the HttpStream creation process. - virtual int RestartTunnelWithProxyAuth(const string16& username, - const string16& password) = 0; - - // Returns the LoadState for the request. - virtual LoadState GetLoadState() const = 0; - - // Returns true if an AlternateProtocol for this request was available. - virtual bool was_alternate_protocol_available() const = 0; - - // Returns true if TLS/NPN was negotiated for this stream. - virtual bool was_npn_negotiated() const = 0; - - // Returns true if this stream is being fetched over SPDY. - virtual bool using_spdy() const = 0; -}; - -// The StreamFactory defines an interface for creating usable HttpStreams. -class StreamFactory { - public: - virtual ~StreamFactory() {} - - // Request a stream. - // Will callback to the StreamRequestDelegate upon completion. - // |info|, |ssl_config|, and |proxy_info| must be kept alive until - // |delegate| is called. - virtual StreamRequest* RequestStream(const HttpRequestInfo* info, - SSLConfig* ssl_config, - ProxyInfo* proxy_info, - HttpNetworkSession* session, - StreamRequest::Delegate* delegate, - const BoundNetLog& net_log) = 0; - - // Requests that enough connections for |num_streams| be opened. If - // ERR_IO_PENDING is returned, |info|, |ssl_config|, and |proxy_info| must - // be kept alive until |callback| is invoked. That callback will be given the - // final error code. - virtual int PreconnectStreams(int num_streams, - const HttpRequestInfo* info, - SSLConfig* ssl_config, - ProxyInfo* proxy_info, - HttpNetworkSession* session, - const BoundNetLog& net_log, - CompletionCallback* callback) = 0; - - virtual void AddTLSIntolerantServer(const GURL& url) = 0; - virtual bool IsTLSIntolerantServer(const GURL& url) = 0; - - virtual void ProcessAlternateProtocol( - HttpAlternateProtocols* alternate_protocols, - const std::string& alternate_protocol_str, - const HostPortPair& http_host_port_pair) = 0; - - virtual GURL ApplyHostMappingRules(const GURL& url, - HostPortPair* endpoint) = 0; -}; - -} // namespace net - -#endif // NET_HTTP_STREAM_FACTORY_H_ diff --git a/net/net.gyp b/net/net.gyp index 5266f74a..3cfd242 100644 --- a/net/net.gyp +++ b/net/net.gyp @@ -505,10 +505,12 @@ 'http/http_stream.h', 'http/http_stream_factory.cc', 'http/http_stream_factory.h', + 'http/http_stream_factory_impl.cc', + 'http/http_stream_factory_impl.h', + 'http/http_stream_factory_impl_job.cc', + 'http/http_stream_factory_impl_job.h', 'http/http_stream_parser.cc', 'http/http_stream_parser.h', - 'http/http_stream_request.cc', - 'http/http_stream_request.h', 'http/http_transaction.h', 'http/http_transaction_factory.h', 'http/url_security_manager.h', @@ -532,7 +534,6 @@ 'http/partial_data.cc', 'http/partial_data.h', 'http/proxy_client_socket.h', - 'http/stream_factory.h', 'ocsp/nss_ocsp.cc', 'ocsp/nss_ocsp.h', 'proxy/init_proxy_resolver.cc', @@ -943,7 +944,7 @@ 'http/http_request_headers_unittest.cc', 'http/http_response_body_drainer_unittest.cc', 'http/http_response_headers_unittest.cc', - 'http/http_stream_factory_unittest.cc', + 'http/http_stream_factory_impl_unittest.cc', 'http/http_transaction_unittest.cc', 'http/http_transaction_unittest.h', 'http/http_util_unittest.cc', diff --git a/net/socket/client_socket_pool_manager.cc b/net/socket/client_socket_pool_manager.cc index 8516fbc..999b4e6 100644 --- a/net/socket/client_socket_pool_manager.cc +++ b/net/socket/client_socket_pool_manager.cc @@ -152,6 +152,55 @@ void ClientSocketPoolManager::FlushSocketPools() { tcp_socket_pool_->Flush(); } +void ClientSocketPoolManager::CloseIdleSockets() { + // Close sockets in the highest level pools first, since higher level pools' + // sockets may release stuff to the lower level pools. + for (SSLSocketPoolMap::const_iterator it = + ssl_socket_pools_for_proxies_.begin(); + it != ssl_socket_pools_for_proxies_.end(); + ++it) + it->second->CloseIdleSockets(); + + for (HTTPProxySocketPoolMap::const_iterator it = + http_proxy_socket_pools_.begin(); + it != http_proxy_socket_pools_.end(); + ++it) + it->second->CloseIdleSockets(); + + for (SSLSocketPoolMap::const_iterator it = + ssl_socket_pools_for_https_proxies_.begin(); + it != ssl_socket_pools_for_https_proxies_.end(); + ++it) + it->second->CloseIdleSockets(); + + for (TCPSocketPoolMap::const_iterator it = + tcp_socket_pools_for_https_proxies_.begin(); + it != tcp_socket_pools_for_https_proxies_.end(); + ++it) + it->second->CloseIdleSockets(); + + for (TCPSocketPoolMap::const_iterator it = + tcp_socket_pools_for_http_proxies_.begin(); + it != tcp_socket_pools_for_http_proxies_.end(); + ++it) + it->second->CloseIdleSockets(); + + for (SOCKSSocketPoolMap::const_iterator it = + socks_socket_pools_.begin(); + it != socks_socket_pools_.end(); + ++it) + it->second->CloseIdleSockets(); + + for (TCPSocketPoolMap::const_iterator it = + tcp_socket_pools_for_socks_proxies_.begin(); + it != tcp_socket_pools_for_socks_proxies_.end(); + ++it) + it->second->CloseIdleSockets(); + + ssl_socket_pool_->CloseIdleSockets(); + tcp_socket_pool_->CloseIdleSockets(); +} + SOCKSClientSocketPool* ClientSocketPoolManager::GetSocketPoolForSOCKSProxy( const HostPortPair& socks_proxy) { SOCKSSocketPoolMap::const_iterator it = socks_socket_pools_.find(socks_proxy); diff --git a/net/socket/client_socket_pool_manager.h b/net/socket/client_socket_pool_manager.h index d6d09e91..7d610a9 100644 --- a/net/socket/client_socket_pool_manager.h +++ b/net/socket/client_socket_pool_manager.h @@ -71,6 +71,7 @@ class ClientSocketPoolManager : public base::NonThreadSafe { ~ClientSocketPoolManager(); void FlushSocketPools(); + void CloseIdleSockets(); TCPClientSocketPool* tcp_socket_pool() { return tcp_socket_pool_.get(); } diff --git a/net/socket/ssl_client_socket_pool_unittest.cc b/net/socket/ssl_client_socket_pool_unittest.cc index e211591..091a94ae 100644 --- a/net/socket/ssl_client_socket_pool_unittest.cc +++ b/net/socket/ssl_client_socket_pool_unittest.cc @@ -19,6 +19,7 @@ #include "net/http/http_network_session.h" #include "net/http/http_request_headers.h" #include "net/http/http_response_headers.h" +#include "net/proxy/proxy_service.h" #include "net/socket/client_socket_handle.h" #include "net/socket/client_socket_pool_histograms.h" #include "net/socket/socket_test_util.h" @@ -62,10 +63,9 @@ class SSLClientSocketPoolTest : public testing::Test { http_proxy_socket_params_(new HttpProxySocketParams( proxy_tcp_socket_params_, NULL, GURL("http://host"), "", HostPortPair("host", 80), - session_->auth_cache(), + session_->http_auth_cache(), session_->http_auth_handler_factory(), session_->spdy_session_pool(), - session_->mutable_spdy_settings(), true)), http_proxy_histograms_("MockHttpProxy"), http_proxy_socket_pool_( @@ -117,13 +117,13 @@ class SSLClientSocketPoolTest : public testing::Test { void AddAuthToCache() { const string16 kFoo(ASCIIToUTF16("foo")); const string16 kBar(ASCIIToUTF16("bar")); - session_->auth_cache()->Add(GURL("http://proxy:443/"), - "MyRealm1", - HttpAuth::AUTH_SCHEME_BASIC, - "Basic realm=MyRealm1", - kFoo, - kBar, - "/"); + session_->http_auth_cache()->Add(GURL("http://proxy:443/"), + "MyRealm1", + HttpAuth::AUTH_SCHEME_BASIC, + "Basic realm=MyRealm1", + kFoo, + kBar, + "/"); } HttpNetworkSession* CreateNetworkSession() { diff --git a/net/spdy/spdy_http_stream_unittest.cc b/net/spdy/spdy_http_stream_unittest.cc index df979ec..1688871 100644 --- a/net/spdy/spdy_http_stream_unittest.cc +++ b/net/spdy/spdy_http_stream_unittest.cc @@ -29,8 +29,7 @@ class SpdyHttpStreamTest : public testing::Test { data_ = new OrderedSocketData(reads, reads_count, writes, writes_count); session_deps_.socket_factory->AddSocketDataProvider(data_.get()); http_session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_); - session_ = http_session_->spdy_session_pool()-> - Get(pair, http_session_->mutable_spdy_settings(), BoundNetLog()); + session_ = http_session_->spdy_session_pool()->Get(pair, BoundNetLog()); tcp_params_ = new TCPSocketParams(host_port_pair.host(), host_port_pair.port(), MEDIUM, GURL(), false); diff --git a/net/spdy/spdy_network_transaction_unittest.cc b/net/spdy/spdy_network_transaction_unittest.cc index 402f2f7..019cc4c 100644 --- a/net/spdy/spdy_network_transaction_unittest.cc +++ b/net/spdy/spdy_network_transaction_unittest.cc @@ -393,8 +393,7 @@ class SpdyNetworkTransactionTest const scoped_refptr& session = helper.session(); SpdySessionPool* pool(session->spdy_session_pool()); EXPECT_TRUE(pool->HasSession(pair)); - scoped_refptr spdy_session( - pool->Get(pair, session->mutable_spdy_settings(), log)); + scoped_refptr spdy_session(pool->Get(pair, log)); ASSERT_TRUE(spdy_session.get() != NULL); EXPECT_EQ(0u, spdy_session->num_active_streams()); EXPECT_EQ(0u, spdy_session->num_unclaimed_pushed_streams()); @@ -4016,7 +4015,8 @@ TEST_P(SpdyNetworkTransactionTest, SettingsSaved) { // Verify that no settings exist initially. HostPortPair host_port_pair("www.google.com", helper.port()); - EXPECT_TRUE(helper.session()->spdy_settings().Get(host_port_pair).empty()); + SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool(); + EXPECT_TRUE(spdy_session_pool->spdy_settings().Get(host_port_pair).empty()); // Construct the request. scoped_ptr req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); @@ -4078,7 +4078,7 @@ TEST_P(SpdyNetworkTransactionTest, SettingsSaved) { { // Verify we had two persisted settings. spdy::SpdySettings saved_settings = - helper.session()->spdy_settings().Get(host_port_pair); + spdy_session_pool->spdy_settings().Get(host_port_pair); ASSERT_EQ(2u, saved_settings.size()); // Verify the first persisted setting. @@ -4124,7 +4124,8 @@ TEST_P(SpdyNetworkTransactionTest, SettingsPlayback) { // Verify that no settings exist initially. HostPortPair host_port_pair("www.google.com", helper.port()); - EXPECT_TRUE(helper.session()->spdy_settings().Get(host_port_pair).empty()); + SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool(); + EXPECT_TRUE(spdy_session_pool->spdy_settings().Get(host_port_pair).empty()); unsigned int kSampleId1 = 0x1; unsigned int kSampleValue1 = 0x0a0a0a0a; @@ -4143,14 +4144,14 @@ TEST_P(SpdyNetworkTransactionTest, SettingsPlayback) { setting.set_id(kSampleId2); settings.push_back(std::make_pair(setting, kSampleValue2)); - helper.session()->mutable_spdy_settings()->Set(host_port_pair, settings); + spdy_session_pool->mutable_spdy_settings()->Set(host_port_pair, settings); } - EXPECT_EQ(2u, helper.session()->spdy_settings().Get(host_port_pair).size()); + EXPECT_EQ(2u, spdy_session_pool->spdy_settings().Get(host_port_pair).size()); // Construct the SETTINGS frame. const spdy::SpdySettings& settings = - helper.session()->spdy_settings().Get(host_port_pair); + spdy_session_pool->spdy_settings().Get(host_port_pair); scoped_ptr settings_frame(ConstructSpdySettings(settings)); // Construct the request. @@ -4190,7 +4191,7 @@ TEST_P(SpdyNetworkTransactionTest, SettingsPlayback) { { // Verify we had two persisted settings. spdy::SpdySettings saved_settings = - helper.session()->spdy_settings().Get(host_port_pair); + spdy_session_pool->spdy_settings().Get(host_port_pair); ASSERT_EQ(2u, saved_settings.size()); // Verify the first persisted setting. diff --git a/net/spdy/spdy_proxy_client_socket_unittest.cc b/net/spdy/spdy_proxy_client_socket_unittest.cc index e4483bd..9023ca9 100644 --- a/net/spdy/spdy_proxy_client_socket_unittest.cc +++ b/net/spdy/spdy_proxy_client_socket_unittest.cc @@ -85,13 +85,13 @@ class SpdyProxyClientSocketTest : public PlatformTest { void AddAuthToCache() { const string16 kFoo(ASCIIToUTF16("foo")); const string16 kBar(ASCIIToUTF16("bar")); - session_->auth_cache()->Add(GURL(kProxyUrl), - "MyRealm1", - HttpAuth::AUTH_SCHEME_BASIC, - "Basic realm=MyRealm1", - kFoo, - kBar, - "/"); + session_->http_auth_cache()->Add(GURL(kProxyUrl), + "MyRealm1", + HttpAuth::AUTH_SCHEME_BASIC, + "Basic realm=MyRealm1", + kFoo, + kBar, + "/"); } void Run(int steps) { @@ -175,7 +175,6 @@ void SpdyProxyClientSocketTest::Initialize(MockRead* reads, // Creates a new spdy session spdy_session_ = session_->spdy_session_pool()->Get(endpoint_host_port_proxy_pair_, - session_->mutable_spdy_settings(), BoundNetLog()); // Perform the TCP connect @@ -196,7 +195,7 @@ void SpdyProxyClientSocketTest::Initialize(MockRead* reads, sock_.reset( new SpdyProxyClientSocket(spdy_stream_, user_agent_, endpoint_host_port_pair_, url_, - proxy_host_port_, session_->auth_cache(), + proxy_host_port_, session_->http_auth_cache(), session_->http_auth_handler_factory())); } diff --git a/net/spdy/spdy_session_pool.cc b/net/spdy/spdy_session_pool.cc index f4ec575..b32495e 100644 --- a/net/spdy/spdy_session_pool.cc +++ b/net/spdy/spdy_session_pool.cc @@ -34,7 +34,6 @@ SpdySessionPool::~SpdySessionPool() { scoped_refptr SpdySessionPool::Get( const HostPortProxyPair& host_port_proxy_pair, - SpdySettingsStorage* spdy_settings, const BoundNetLog& net_log) { scoped_refptr spdy_session; SpdySessionList* list = GetSessionList(host_port_proxy_pair); @@ -53,7 +52,7 @@ scoped_refptr SpdySessionPool::Get( DCHECK(list); if (!spdy_session) { - spdy_session = new SpdySession(host_port_proxy_pair, this, spdy_settings, + spdy_session = new SpdySession(host_port_proxy_pair, this, &spdy_settings_, net_log.net_log()); net_log.AddEvent( NetLog::TYPE_SPDY_SESSION_POOL_CREATED_NEW_SESSION, @@ -69,14 +68,13 @@ scoped_refptr SpdySessionPool::Get( net::Error SpdySessionPool::GetSpdySessionFromSocket( const HostPortProxyPair& host_port_proxy_pair, - SpdySettingsStorage* spdy_settings, ClientSocketHandle* connection, const BoundNetLog& net_log, int certificate_error_code, scoped_refptr* spdy_session, bool is_secure) { // Create the SPDY session and add it to the pool. - *spdy_session = new SpdySession(host_port_proxy_pair, this, spdy_settings, + *spdy_session = new SpdySession(host_port_proxy_pair, this, &spdy_settings_, net_log.net_log()); SpdySessionList* list = GetSessionList(host_port_proxy_pair); if (!list) diff --git a/net/spdy/spdy_session_pool.h b/net/spdy/spdy_session_pool.h index 7f30b20..10da747 100644 --- a/net/spdy/spdy_session_pool.h +++ b/net/spdy/spdy_session_pool.h @@ -20,6 +20,7 @@ #include "net/base/ssl_config_service.h" #include "net/proxy/proxy_config.h" #include "net/proxy/proxy_server.h" +#include "net/spdy/spdy_settings_storage.h" namespace net { // Sessions are uniquely identified by their HostPortPair and the proxy server @@ -30,7 +31,6 @@ class BoundNetLog; class ClientSocketHandle; class HttpNetworkSession; class SpdySession; -class SpdySettingsStorage; // This is a very simple pool for open SpdySessions. // TODO(mbelshe): Make this production ready. @@ -45,7 +45,6 @@ class SpdySessionPool // use. scoped_refptr Get( const HostPortProxyPair& host_port_proxy_pair, - SpdySettingsStorage* spdy_settings, const BoundNetLog& net_log); // Set the maximum concurrent sessions per domain. @@ -66,7 +65,6 @@ class SpdySessionPool // Returns an error on failure, and |spdy_session| will be NULL. net::Error GetSpdySessionFromSocket( const HostPortProxyPair& host_port_proxy_pair, - SpdySettingsStorage* spdy_settings, ClientSocketHandle* connection, const BoundNetLog& net_log, int certificate_error_code, @@ -92,6 +90,9 @@ class SpdySessionPool // responsible for deleting the returned value. Value* SpdySessionPoolInfoToValue() const; + SpdySettingsStorage* mutable_spdy_settings() { return &spdy_settings_; } + const SpdySettingsStorage& spdy_settings() const { return spdy_settings_; } + // NetworkChangeNotifier::Observer methods: // We flush all idle sessions and release references to the active ones so @@ -124,6 +125,8 @@ class SpdySessionPool const HostPortProxyPair& host_port_proxy_pair) const; void RemoveSessionList(const HostPortProxyPair& host_port_proxy_pair); + SpdySettingsStorage spdy_settings_; + // This is our weak session pool - one session per domain. SpdySessionsMap sessions_; diff --git a/net/spdy/spdy_session_unittest.cc b/net/spdy/spdy_session_unittest.cc index 44848e3..0f3b601 100644 --- a/net/spdy/spdy_session_unittest.cc +++ b/net/spdy/spdy_session_unittest.cc @@ -88,8 +88,7 @@ TEST_F(SpdySessionTest, GoAway) { SpdySessionPool* spdy_session_pool(http_session->spdy_session_pool()); EXPECT_FALSE(spdy_session_pool->HasSession(pair)); scoped_refptr session = - spdy_session_pool->Get(pair, http_session->mutable_spdy_settings(), - BoundNetLog()); + spdy_session_pool->Get(pair, BoundNetLog()); EXPECT_TRUE(spdy_session_pool->HasSession(pair)); scoped_refptr tcp_params( @@ -107,8 +106,7 @@ TEST_F(SpdySessionTest, GoAway) { EXPECT_FALSE(spdy_session_pool->HasSession(pair)); scoped_refptr session2 = - spdy_session_pool->Get(pair, http_session->mutable_spdy_settings(), - BoundNetLog()); + spdy_session_pool->Get(pair, BoundNetLog()); // Delete the first session. session = NULL; @@ -187,18 +185,17 @@ TEST_F(SpdySessionTest, OnSettings) { HostPortProxyPair pair(test_host_port_pair, ProxyServer::Direct()); // Initialize the SpdySettingsStorage with 1 max concurrent streams. + SpdySessionPool* spdy_session_pool(http_session->spdy_session_pool()); spdy::SpdySettings old_settings; id.set_flags(spdy::SETTINGS_FLAG_PLEASE_PERSIST); old_settings.push_back(spdy::SpdySetting(id, 1)); - http_session->mutable_spdy_settings()->Set( + spdy_session_pool->mutable_spdy_settings()->Set( test_host_port_pair, old_settings); // Create a session. - SpdySessionPool* spdy_session_pool(http_session->spdy_session_pool()); EXPECT_FALSE(spdy_session_pool->HasSession(pair)); scoped_refptr session = - spdy_session_pool->Get(pair, http_session->mutable_spdy_settings(), - BoundNetLog()); + spdy_session_pool->Get(pair, BoundNetLog()); ASSERT_TRUE(spdy_session_pool->HasSession(pair)); scoped_refptr tcp_params( @@ -267,19 +264,19 @@ TEST_F(SpdySessionTest, CancelPendingCreateStream) { HostPortProxyPair pair(test_host_port_pair, ProxyServer::Direct()); // Initialize the SpdySettingsStorage with 1 max concurrent streams. + SpdySessionPool* spdy_session_pool(http_session->spdy_session_pool()); spdy::SpdySettings settings; spdy::SettingsFlagsAndId id(spdy::SETTINGS_MAX_CONCURRENT_STREAMS); id.set_id(spdy::SETTINGS_MAX_CONCURRENT_STREAMS); id.set_flags(spdy::SETTINGS_FLAG_PLEASE_PERSIST); settings.push_back(spdy::SpdySetting(id, 1)); - http_session->mutable_spdy_settings()->Set(test_host_port_pair, settings); + spdy_session_pool->mutable_spdy_settings()->Set( + test_host_port_pair, settings); // Create a session. - SpdySessionPool* spdy_session_pool(http_session->spdy_session_pool()); EXPECT_FALSE(spdy_session_pool->HasSession(pair)); scoped_refptr session = - spdy_session_pool->Get(pair, http_session->mutable_spdy_settings(), - BoundNetLog()); + spdy_session_pool->Get(pair, BoundNetLog()); ASSERT_TRUE(spdy_session_pool->HasSession(pair)); scoped_refptr tcp_params( @@ -369,12 +366,12 @@ TEST_F(SpdySessionTest, SendSettingsOnNewSession) { id.set_flags(spdy::SETTINGS_FLAG_PLEASE_PERSIST); settings.clear(); settings.push_back(spdy::SpdySetting(id, kBogusSettingValue)); - http_session->mutable_spdy_settings()->Set(test_host_port_pair, settings); SpdySessionPool* spdy_session_pool(http_session->spdy_session_pool()); + spdy_session_pool->mutable_spdy_settings()->Set( + test_host_port_pair, settings); EXPECT_FALSE(spdy_session_pool->HasSession(pair)); scoped_refptr session = - spdy_session_pool->Get(pair, http_session->mutable_spdy_settings(), - BoundNetLog()); + spdy_session_pool->Get(pair, BoundNetLog()); EXPECT_TRUE(spdy_session_pool->HasSession(pair)); scoped_refptr tcp_params( diff --git a/net/spdy/spdy_stream_unittest.cc b/net/spdy/spdy_stream_unittest.cc index 9c7b934..532c79f 100644 --- a/net/spdy/spdy_stream_unittest.cc +++ b/net/spdy/spdy_stream_unittest.cc @@ -117,9 +117,7 @@ class SpdyStreamTest : public testing::Test { HostPortPair host_port_pair("www.google.com", 80); HostPortProxyPair pair(host_port_pair, ProxyServer::Direct()); scoped_refptr session( - session_->spdy_session_pool()->Get(pair, - session_->mutable_spdy_settings(), - BoundNetLog())); + session_->spdy_session_pool()->Get(pair, BoundNetLog())); return session; } -- cgit v1.1