diff options
-rw-r--r-- | net/http/http_stream_factory_impl.cc | 241 | ||||
-rw-r--r-- | net/http/http_stream_factory_impl.h | 50 | ||||
-rw-r--r-- | net/http/http_stream_factory_impl_job.cc | 136 | ||||
-rw-r--r-- | net/http/http_stream_factory_impl_job.h | 25 | ||||
-rw-r--r-- | net/http/http_stream_factory_impl_request.cc | 157 | ||||
-rw-r--r-- | net/http/http_stream_factory_impl_request.h | 94 | ||||
-rw-r--r-- | net/net.gyp | 2 | ||||
-rw-r--r-- | net/proxy/proxy_server.h | 4 | ||||
-rw-r--r-- | net/spdy/spdy_session_pool.h | 3 |
9 files changed, 412 insertions, 300 deletions
diff --git a/net/http/http_stream_factory_impl.cc b/net/http/http_stream_factory_impl.cc index 02dd29d..e4e94b1 100644 --- a/net/http/http_stream_factory_impl.cc +++ b/net/http/http_stream_factory_impl.cc @@ -5,191 +5,22 @@ #include "net/http/http_stream_factory_impl.h" #include "base/stl_util-inl.h" +#include "googleurl/src/gurl.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" +#include "net/http/http_stream_factory_impl_request.h" +#include "net/spdy/spdy_http_stream.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()); + DCHECK(spdy_session_request_map_.empty()); std::set<const Job*> tmp_job_set; tmp_job_set.swap(preconnect_job_set_); @@ -203,10 +34,10 @@ HttpStreamRequest* HttpStreamFactoryImpl::RequestStream( HttpStreamRequest::Delegate* delegate, const BoundNetLog& net_log) { Job* job = new Job(this, session_); - Request* request = new Request(this, delegate); + Request* request = new Request(request_info.url, this, delegate); request_map_[job] = request; request->BindJob(job); - job->Start(request_info, ssl_config, net_log); + job->Start(request, request_info, ssl_config, net_log); return request; } @@ -233,61 +64,21 @@ LoadState HttpStreamFactoryImpl::GetLoadState(const Request& request) const { return request.job()->GetLoadState(); } -void HttpStreamFactoryImpl::OnStreamReady(const Job* job, - const SSLConfig& ssl_config, - const ProxyInfo& proxy_info, - HttpStream* stream) { +void HttpStreamFactoryImpl::OnSpdySessionReady( + const Job* job, + scoped_refptr<SpdySession> spdy_session, + bool direct) { + DCHECK(job->using_spdy()); 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); + bool use_relative_url = direct || request->url().SchemeIs("https"); + request->OnStreamReady( + job->ssl_config(), + job->proxy_info(), + new SpdyHttpStream(spdy_session, use_relative_url)); } void HttpStreamFactoryImpl::OnPreconnectsComplete(const Job* job) { diff --git a/net/http/http_stream_factory_impl.h b/net/http/http_stream_factory_impl.h index d86a8fa..9d6e133 100644 --- a/net/http/http_stream_factory_impl.h +++ b/net/http/http_stream_factory_impl.h @@ -1,4 +1,4 @@ -// 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. @@ -9,11 +9,14 @@ #include <set> #include <string> +#include "base/ref_counted.h" #include "net/http/http_stream_factory.h" +#include "net/proxy/proxy_server.h" namespace net { class HttpNetworkSession; +class SpdySession; class HttpStreamFactoryImpl : public HttpStreamFactory { public: @@ -38,31 +41,24 @@ class HttpStreamFactoryImpl : public HttpStreamFactory { class Request; class Job; + typedef std::set<Request*> RequestSet; + typedef std::map<HostPortProxyPair, RequestSet> SpdySessionRequestMap; + 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); + // Called when a SpdySession is ready. It will find appropriate Requests and + // fulfill them. |direct| indicates whether or not |spdy_session| uses a + // proxy. + void OnSpdySessionReady(const Job* job, + scoped_refptr<SpdySession> spdy_session, + bool direct); + + // Called when the Job detects that the endpoint indicated by the + // Alternate-Protocol does not work. Lets the factory update + // HttpAlternateProtocols with the failure and resets the SPDY session key. + void OnBrokenAlternateProtocol(const Job*, const HostPortPair& origin); + // Invoked when the Job finishes preconnecting sockets. void OnPreconnectsComplete(const Job* job); // Called when the Preconnect completes. Used for testing. @@ -74,13 +70,11 @@ class HttpStreamFactoryImpl : public HttpStreamFactory { // 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. + // |request_map_|. The Requests will delete the corresponding job. std::map<const Job*, Request*> request_map_; + SpdySessionRequestMap spdy_session_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. diff --git a/net/http/http_stream_factory_impl_job.cc b/net/http/http_stream_factory_impl_job.cc index 3f1968c..6884a79 100644 --- a/net/http/http_stream_factory_impl_job.cc +++ b/net/http/http_stream_factory_impl_job.cc @@ -1,4 +1,4 @@ -// 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. @@ -18,6 +18,7 @@ #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/http/http_stream_factory_impl_request.h" #include "net/socket/client_socket_handle.h" #include "net/socket/client_socket_pool.h" #include "net/socket/socks_client_socket_pool.h" @@ -47,7 +48,8 @@ GURL UpgradeUrlToHttps(const GURL& original_url) { HttpStreamFactoryImpl::Job::Job(HttpStreamFactoryImpl* stream_factory, HttpNetworkSession* session) - : ALLOW_THIS_IN_INITIALIZER_LIST(io_callback_(this, &Job::OnIOComplete)), + : request_(NULL), + ALLOW_THIS_IN_INITIALIZER_LIST(io_callback_(this, &Job::OnIOComplete)), connection_(new ClientSocketHandle), session_(session), stream_factory_(stream_factory), @@ -63,7 +65,10 @@ HttpStreamFactoryImpl::Job::Job(HttpStreamFactoryImpl* stream_factory, was_alternate_protocol_available_(false), was_npn_negotiated_(false), num_streams_(0), + spdy_session_direct_(false), ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { + DCHECK(stream_factory); + DCHECK(session); if (HttpStreamFactory::use_alternate_protocols()) alternate_protocol_mode_ = kUnspecified; else @@ -87,9 +92,12 @@ HttpStreamFactoryImpl::Job::~Job() { stream_->Close(true /* not reusable */); } -void HttpStreamFactoryImpl::Job::Start(const HttpRequestInfo& request_info, +void HttpStreamFactoryImpl::Job::Start(Request* request, + const HttpRequestInfo& request_info, const SSLConfig& ssl_config, const BoundNetLog& net_log) { + DCHECK(request); + request_ = request; StartInternal(request_info, ssl_config, net_log); } @@ -135,6 +143,14 @@ bool HttpStreamFactoryImpl::Job::using_spdy() const { return using_spdy_; } +const SSLConfig& HttpStreamFactoryImpl::Job::ssl_config() const { + return ssl_config_; +} + +const ProxyInfo& HttpStreamFactoryImpl::Job::proxy_info() const { + return proxy_info_; +} + void HttpStreamFactoryImpl::Job::GetSSLInfo() { DCHECK(using_ssl_); DCHECK(!establishing_tunnel_); @@ -146,40 +162,59 @@ void HttpStreamFactoryImpl::Job::GetSSLInfo() { void HttpStreamFactoryImpl::Job::OnStreamReadyCallback() { DCHECK(stream_.get()); - stream_factory_->OnStreamReady( - this, ssl_config_, proxy_info_, stream_.release()); + request_->Complete(was_alternate_protocol_available(), + was_npn_negotiated(), + using_spdy()); + request_->OnStreamReady(ssl_config_, proxy_info_, stream_.release()); + // |this| may be deleted after this call. +} + +void HttpStreamFactoryImpl::Job::OnSpdySessionReadyCallback() { + DCHECK(!stream_.get()); + DCHECK(using_spdy()); + DCHECK(new_spdy_session_); + scoped_refptr<SpdySession> spdy_session = new_spdy_session_; + new_spdy_session_ = NULL; + stream_factory_->OnSpdySessionReady(this, spdy_session, spdy_session_direct_); + // |this| may be deleted after this call. } void HttpStreamFactoryImpl::Job::OnStreamFailedCallback(int result) { - stream_factory_->OnStreamFailed(this, result, ssl_config_); + request_->OnStreamFailed(result, ssl_config_); + // |this| may be deleted after this call. } void HttpStreamFactoryImpl::Job::OnCertificateErrorCallback( int result, const SSLInfo& ssl_info) { - stream_factory_->OnCertificateError(this, result, ssl_config_, ssl_info); + request_->OnCertificateError(result, ssl_config_, ssl_info); + // |this| may be deleted after this call. } void HttpStreamFactoryImpl::Job::OnNeedsProxyAuthCallback( const HttpResponseInfo& response, HttpAuthController* auth_controller) { - stream_factory_->OnNeedsProxyAuth( - this, response, ssl_config_, proxy_info_, auth_controller); + request_->OnNeedsProxyAuth( + response, ssl_config_, proxy_info_, auth_controller); + // |this| may be deleted after this call. } void HttpStreamFactoryImpl::Job::OnNeedsClientAuthCallback( SSLCertRequestInfo* cert_info) { - stream_factory_->OnNeedsClientAuth(this, ssl_config_, cert_info); + request_->OnNeedsClientAuth(ssl_config_, cert_info); + // |this| may be deleted after this call. } void HttpStreamFactoryImpl::Job::OnHttpsProxyTunnelResponseCallback( const HttpResponseInfo& response_info, HttpStream* stream) { - stream_factory_->OnHttpsProxyTunnelResponse( - this, response_info, ssl_config_, proxy_info_, stream); + request_->OnHttpsProxyTunnelResponse( + response_info, ssl_config_, proxy_info_, stream); + // |this| may be deleted after this call. } void HttpStreamFactoryImpl::Job::OnPreconnectsComplete() { stream_factory_->OnPreconnectsComplete(this); + // |this| may be deleted after this call. } void HttpStreamFactoryImpl::Job::OnIOComplete(int result) { @@ -262,10 +297,17 @@ int HttpStreamFactoryImpl::Job::RunLoop(int result) { case OK: next_state_ = STATE_DONE; - MessageLoop::current()->PostTask( - FROM_HERE, - method_factory_.NewRunnableMethod( - &HttpStreamFactoryImpl::Job::OnStreamReadyCallback)); + if (new_spdy_session_) { + MessageLoop::current()->PostTask( + FROM_HERE, + method_factory_.NewRunnableMethod( + &HttpStreamFactoryImpl::Job::OnSpdySessionReadyCallback)); + } else { + MessageLoop::current()->PostTask( + FROM_HERE, + method_factory_.NewRunnableMethod( + &HttpStreamFactoryImpl::Job::OnStreamReadyCallback)); + } return ERR_IO_PENDING; default: @@ -455,8 +497,16 @@ int HttpStreamFactoryImpl::Job::DoInitConnection() { 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)) { + HostPortProxyPair spdy_session_key; + if (IsHttpsProxyAndHttpUrl()) { + spdy_session_key = + HostPortProxyPair(proxy_info_.proxy_server().host_port_pair(), + ProxyServer::Direct()); + } else { + spdy_session_key = + HostPortProxyPair(endpoint_, proxy_info_.proxy_server()); + } + if (session_->spdy_session_pool()->HasSession(spdy_session_key)) { // 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()) @@ -464,17 +514,9 @@ int HttpStreamFactoryImpl::Job::DoInitConnection() { 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; - } + } else if (!IsPreconnecting()) { + // Update the spdy session key for the request that launched this job. + request_->SetSpdySessionKey(spdy_session_key); } } @@ -719,9 +761,7 @@ int HttpStreamFactoryImpl::Job::DoInitConnectionComplete(int result) { } else { result = HandleCertificateError(result); if (result == OK && !connection_->socket()->IsConnectedAndIdle()) { - connection_->socket()->Disconnect(); - connection_->Reset(); - next_state_ = STATE_INIT_CONNECTION; + ReturnToStateInitConnection(true /* close connection */); return result; } } @@ -775,7 +815,7 @@ int HttpStreamFactoryImpl::Job::DoCreateStream() { 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 + // 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)) { @@ -799,11 +839,19 @@ int HttpStreamFactoryImpl::Job::DoCreateStream() { &spdy_session, using_ssl_); if (error != OK) return error; + new_spdy_session_ = spdy_session; + spdy_session_direct_ = direct; + return OK; } if (spdy_session->IsClosed()) return ERR_CONNECTION_CLOSED; + // TODO(willchan): Delete this code, because eventually, the + // HttpStreamFactoryImpl will be creating all the SpdyHttpStreams, since it + // will know when SpdySessions become available. The above HasSession() checks + // will be able to be deleted too. + bool use_relative_url = direct || request_info_.url.SchemeIs("https"); stream_.reset(new SpdyHttpStream(spdy_session, use_relative_url)); return OK; @@ -835,15 +883,26 @@ int HttpStreamFactoryImpl::Job::DoRestartTunnelAuthComplete(int result) { // 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; + ReturnToStateInitConnection(false /* do not close connection */); return OK; } return ReconsiderProxyAfterError(result); } +void HttpStreamFactoryImpl::Job::ReturnToStateInitConnection( + bool close_connection) { + if (close_connection && connection_->socket()) + connection_->socket()->Disconnect(); + connection_->Reset(); + + if (request_) + request_->RemoveRequestFromSpdySessionRequestMap(); + + next_state_ = STATE_INIT_CONNECTION; +} + void HttpStreamFactoryImpl::Job::SetSocketMotivation() { if (request_info_.motivation == HttpRequestInfo::PRECONNECT_MOTIVATED) connection_->socket()->SetSubresourceSpeculation(); @@ -925,10 +984,7 @@ void HttpStreamFactoryImpl::Job::MarkBrokenAlternateProtocolAndFallback() { endpoint_); alternate_protocol_mode_ = kDoNotUseAlternateProtocol; - if (connection_->socket()) - connection_->socket()->Disconnect(); - connection_->Reset(); - next_state_ = STATE_INIT_CONNECTION; + ReturnToStateInitConnection(false /* close connection */); } int HttpStreamFactoryImpl::Job::ReconsiderProxyAfterError(int error) { @@ -987,6 +1043,8 @@ int HttpStreamFactoryImpl::Job::ReconsiderProxyAfterError(int error) { if (connection_->socket()) connection_->socket()->Disconnect(); connection_->Reset(); + if (request_) + request_->RemoveRequestFromSpdySessionRequestMap(); next_state_ = STATE_RESOLVE_PROXY_COMPLETE; } else { // If ReconsiderProxyAfterError() failed synchronously, it means diff --git a/net/http/http_stream_factory_impl_job.h b/net/http/http_stream_factory_impl_job.h index 38f8081..59b0b09 100644 --- a/net/http/http_stream_factory_impl_job.h +++ b/net/http/http_stream_factory_impl_job.h @@ -33,7 +33,8 @@ class TCPSocketParams; // created for the StreamFactory. class HttpStreamFactoryImpl::Job { public: - Job(HttpStreamFactoryImpl* stream_factory, HttpNetworkSession* session); + Job(HttpStreamFactoryImpl* stream_factory, + HttpNetworkSession* session); ~Job(); // Start initiates the process of creating a new HttpStream. @@ -41,7 +42,8 @@ class HttpStreamFactoryImpl::Job { // 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, + void Start(Request* request, + const HttpRequestInfo& request_info, const SSLConfig& ssl_config, const BoundNetLog& net_log); @@ -58,6 +60,12 @@ class HttpStreamFactoryImpl::Job { bool was_npn_negotiated() const; bool using_spdy() const; + const SSLConfig& ssl_config() const; + const ProxyInfo& proxy_info() const; + + // Indicates whether or not this job is performing a preconnect. + bool IsPreconnecting() const; + private: enum AlternateProtocolMode { kUnspecified, // Unspecified, check HttpAlternateProtocols @@ -82,6 +90,7 @@ class HttpStreamFactoryImpl::Job { }; void OnStreamReadyCallback(); + void OnSpdySessionReadyCallback(); void OnStreamFailedCallback(int result); void OnCertificateErrorCallback(int result, const SSLInfo& ssl_info); void OnNeedsProxyAuthCallback(const HttpResponseInfo& response_info, @@ -112,6 +121,9 @@ class HttpStreamFactoryImpl::Job { int DoRestartTunnelAuth(); int DoRestartTunnelAuthComplete(int result); + // Returns to STATE_INIT_CONNECTION and resets some state. + void ReturnToStateInitConnection(bool close_connection); + // Set the motivation for this request onto the underlying socket. void SetSocketMotivation(); @@ -163,8 +175,7 @@ class HttpStreamFactoryImpl::Job { // 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; + Request* request_; HttpRequestInfo request_info_; ProxyInfo proxy_info_; @@ -222,6 +233,12 @@ class HttpStreamFactoryImpl::Job { // preconnect. int num_streams_; + // Initialized when we create a new SpdySession. + scoped_refptr<SpdySession> new_spdy_session_; + + // Only used if |new_spdy_session_| is non-NULL. + bool spdy_session_direct_; + ScopedRunnableMethodFactory<Job> method_factory_; DISALLOW_COPY_AND_ASSIGN(Job); diff --git a/net/http/http_stream_factory_impl_request.cc b/net/http/http_stream_factory_impl_request.cc new file mode 100644 index 0000000..7826659 --- /dev/null +++ b/net/http/http_stream_factory_impl_request.cc @@ -0,0 +1,157 @@ +// 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_impl_request.h" + +#include "base/logging.h" +#include "base/stl_util-inl.h" +#include "net/http/http_stream_factory_impl_job.h" + +namespace net { + +HttpStreamFactoryImpl::Request::Request(const GURL& url, + HttpStreamFactoryImpl* factory, + HttpStreamRequest::Delegate* delegate) + : url_(url), + 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_; + + RemoveRequestFromSpdySessionRequestMap(); +} + +void HttpStreamFactoryImpl::Request::SetSpdySessionKey( + const HostPortProxyPair& spdy_session_key) { + DCHECK(!spdy_session_key_.get()); + spdy_session_key_.reset(new HostPortProxyPair(spdy_session_key)); + RequestSet& request_set = + factory_->spdy_session_request_map_[spdy_session_key]; + DCHECK(!ContainsKey(request_set, this)); + request_set.insert(this); +} + +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) { + // We're restarting the job, so ditch the old key. Note that we could actually + // keep it around and eliminate the DCHECK in set_spdy_session_key() that + // |spdy_session_key_| is NULL, but I prefer to keep the assertion. + RemoveRequestFromSpdySessionRequestMap(); + 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_; +} + +void +HttpStreamFactoryImpl::Request::RemoveRequestFromSpdySessionRequestMap() { + if (spdy_session_key_.get()) { + SpdySessionRequestMap& spdy_session_request_map = + factory_->spdy_session_request_map_; + DCHECK(ContainsKey(spdy_session_request_map, *spdy_session_key_)); + RequestSet& request_set = + spdy_session_request_map[*spdy_session_key_]; + DCHECK(ContainsKey(request_set, this)); + request_set.erase(this); + if (request_set.empty()) + spdy_session_request_map.erase(*spdy_session_key_); + spdy_session_key_.reset(); + } +} + +} // namespace net diff --git a/net/http/http_stream_factory_impl_request.h b/net/http/http_stream_factory_impl_request.h new file mode 100644 index 0000000..468ebd3 --- /dev/null +++ b/net/http/http_stream_factory_impl_request.h @@ -0,0 +1,94 @@ +// 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_REQUEST_H_ +#define NET_HTTP_HTTP_STREAM_FACTORY_IMPL_REQUEST_H_ + +#include "base/scoped_ptr.h" +#include "googleurl/src/gurl.h" +#include "net/http/http_stream_factory_impl.h" + +namespace net { + +class HttpStreamFactoryImpl::Request : public HttpStreamRequest { + public: + Request(const GURL& url, + HttpStreamFactoryImpl* factory, + HttpStreamRequest::Delegate* delegate); + virtual ~Request(); + + // Returns the Job that the Request started up. + Job* job() const { return job_; } + + // The GURL from the HttpRequestInfo the started the Request. + const GURL& url() const { return url_; } + + // Called when the Job determines the appropriate |spdy_session_key| for the + // Request. Note that this does not mean that SPDY is necessarily supported + // for this HostPortProxyPair, since we may need to wait for NPN to complete + // before knowing if SPDY is available. + void SetSpdySessionKey(const HostPortProxyPair& spdy_session_key); + + // 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); + + // If this Request has a spdy_session_key, remove this session from the + // SpdySessionRequestMap. + void RemoveRequestFromSpdySessionRequestMap(); + + // 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: + const GURL url_; + HttpStreamFactoryImpl* const factory_; + HttpStreamRequest::Delegate* const delegate_; + + // The |job_| that this request is tied to. + HttpStreamFactoryImpl::Job* job_; + scoped_ptr<const HostPortProxyPair> spdy_session_key_; + + bool completed_; + bool was_alternate_protocol_available_; + bool was_npn_negotiated_; + bool using_spdy_; + + DISALLOW_COPY_AND_ASSIGN(Request); +}; + +} // namespace net +#endif // NET_HTTP_HTTP_STREAM_FACTORY_IMPL_H_ diff --git a/net/net.gyp b/net/net.gyp index df9f2f8..bd14ccc 100644 --- a/net/net.gyp +++ b/net/net.gyp @@ -511,6 +511,8 @@ 'http/http_stream_factory_impl.h', 'http/http_stream_factory_impl_job.cc', 'http/http_stream_factory_impl_job.h', + 'http/http_stream_factory_impl_request.cc', + 'http/http_stream_factory_impl_request.h', 'http/http_stream_parser.cc', 'http/http_stream_parser.h', 'http/http_transaction.h', diff --git a/net/proxy/proxy_server.h b/net/proxy/proxy_server.h index 3167252..c127aad 100644 --- a/net/proxy/proxy_server.h +++ b/net/proxy/proxy_server.h @@ -42,7 +42,7 @@ class ProxyServer { bool is_valid() const { return scheme_ != SCHEME_INVALID; } - // Gets the proxy's scheme (i.e. SOCKS4, SOCKS5, HTTP} + // Gets the proxy's scheme (i.e. SOCKS4, SOCKS5, HTTP) Scheme scheme() const { return scheme_; } // Returns true if this ProxyServer is actually just a DIRECT connection. @@ -158,6 +158,8 @@ class ProxyServer { HostPortPair host_port_pair_; }; +typedef std::pair<HostPortPair, ProxyServer> HostPortProxyPair; + } // namespace net #endif // NET_PROXY_PROXY_SERVER_H_ diff --git a/net/spdy/spdy_session_pool.h b/net/spdy/spdy_session_pool.h index 10da747..91ff8cb 100644 --- a/net/spdy/spdy_session_pool.h +++ b/net/spdy/spdy_session_pool.h @@ -23,9 +23,6 @@ #include "net/spdy/spdy_settings_storage.h" namespace net { -// Sessions are uniquely identified by their HostPortPair and the proxy server -// that will be used to connect to it (may be DIRECT). -typedef std::pair<HostPortPair, ProxyServer> HostPortProxyPair; class BoundNetLog; class ClientSocketHandle; |