diff options
Diffstat (limited to 'chrome/browser/net')
-rw-r--r-- | chrome/browser/net/preconnect.cc | 64 | ||||
-rw-r--r-- | chrome/browser/net/preconnect.h | 24 | ||||
-rw-r--r-- | chrome/browser/net/predictor.cc | 14 | ||||
-rw-r--r-- | chrome/browser/net/predictor.h | 16 |
4 files changed, 88 insertions, 30 deletions
diff --git a/chrome/browser/net/preconnect.cc b/chrome/browser/net/preconnect.cc index e8038ff..3872d2a 100644 --- a/chrome/browser/net/preconnect.cc +++ b/chrome/browser/net/preconnect.cc @@ -21,18 +21,22 @@ namespace chrome_browser_net { // static bool Preconnect::preconnect_despite_proxy_ = false; -// We will deliberately leak this singular instance, which is used only for -// callbacks. -// static -Preconnect* Preconnect::callback_instance_; + +Preconnect::~Preconnect() { + if (!handle_.is_initialized()) + return; + DCHECK(motivation_ == UrlInfo::LEARNED_REFERAL_MOTIVATED || + motivation_ == UrlInfo::OMNIBOX_MOTIVATED); + if (motivation_ == UrlInfo::OMNIBOX_MOTIVATED) + handle_.socket()->SetOmniboxSpeculation(); + else + handle_.socket()->SetSubresourceSpeculation(); + handle_.Reset(); +} // static void Preconnect::PreconnectOnUIThread(const GURL& url, UrlInfo::ResolutionMotivation motivation) { - // Try to do connection warming for this search provider. - URLRequestContextGetter* getter = Profile::GetDefaultRequestContext(); - if (!getter) - return; // Prewarm connection to Search URL. ChromeThread::PostTask( ChromeThread::IO, @@ -57,6 +61,13 @@ static void HistogramPreconnectStatus(ProxyStatus status) { // static void Preconnect::PreconnectOnIOThread(const GURL& url, UrlInfo::ResolutionMotivation motivation) { + scoped_refptr<Preconnect> preconnect = new Preconnect(motivation); + // TODO(jar): Should I use PostTask for LearnedSubresources to delay the + // preconnection a tad? + preconnect->Connect(url); +} + +void Preconnect::Connect(const GURL& url) { URLRequestContextGetter* getter = Profile::GetDefaultRequestContext(); if (!getter) return; @@ -64,6 +75,9 @@ void Preconnect::PreconnectOnIOThread(const GURL& url, LOG(DFATAL) << "This must be run only on the IO thread."; return; } + + AddRef(); // Stay alive until socket is available. + URLRequestContext* context = getter->GetURLRequestContext(); if (preconnect_despite_proxy_) { @@ -86,16 +100,12 @@ void Preconnect::PreconnectOnIOThread(const GURL& url, } } - UMA_HISTOGRAM_ENUMERATION("Net.PreconnectMotivation", motivation, + UMA_HISTOGRAM_ENUMERATION("Net.PreconnectMotivation", motivation_, UrlInfo::MAX_MOTIVATED); net::HttpTransactionFactory* factory = context->http_transaction_factory(); net::HttpNetworkSession* session = factory->GetSession(); - net::ClientSocketHandle handle; - if (!callback_instance_) - callback_instance_ = new Preconnect; - scoped_refptr<net::TCPSocketParams> tcp_params = new net::TCPSocketParams(url.host(), url.EffectiveIntPort(), net::LOW, GURL(), false); @@ -103,6 +113,19 @@ void Preconnect::PreconnectOnIOThread(const GURL& url, net::HostPortPair endpoint(url.host(), url.EffectiveIntPort()); std::string group_name = endpoint.ToString(); + // It almost doesn't matter whether we use net::LOWEST or net::HIGHEST + // priority here, as we won't make a request, and will surrender the created + // socket to the pool as soon as we can. However, we would like to mark the + // speculative socket as such, and IF we use a net::LOWEST priority, and if + // a navigation asked for a socket (after us) then it would get our socket, + // and we'd get its later-arriving socket, which might make us record that + // the speculation didn't help :-/. By using net::HIGHEST, we ensure that + // a socket is given to us if "we asked first" and this allows us to mark it + // as speculative, and better detect stats (if it gets used). + // TODO(jar): histogram to see how often we accidentally use a previously- + // unused socket, when a previously used socket was available. + net::RequestPriority priority = net::HIGHEST; + if (url.SchemeIs("https")) { group_name = StringPrintf("ssl/%s", group_name.c_str()); @@ -120,21 +143,20 @@ void Preconnect::PreconnectOnIOThread(const GURL& url, const scoped_refptr<net::SSLClientSocketPool>& pool = session->ssl_socket_pool(); - handle.Init(group_name, ssl_params, net::LOWEST, callback_instance_, pool, - net::BoundNetLog()); - handle.Reset(); + handle_.Init(group_name, ssl_params, priority, this, pool, + net::BoundNetLog()); return; } const scoped_refptr<net::TCPClientSocketPool>& pool = session->tcp_socket_pool(); - handle.Init(group_name, tcp_params, net::LOWEST, callback_instance_, pool, - net::BoundNetLog()); - handle.Reset(); + handle_.Init(group_name, tcp_params, priority, this, pool, + net::BoundNetLog()); } void Preconnect::RunWithParams(const Tuple1<int>& params) { - // This will rarely be called, as we reset the connection just after creating. - NOTREACHED(); + if (params.a < 0 && handle_.socket()) + handle_.socket()->Disconnect(); + Release(); } } // chrome_browser_net diff --git a/chrome/browser/net/preconnect.h b/chrome/browser/net/preconnect.h index d773636..f7d574d 100644 --- a/chrome/browser/net/preconnect.h +++ b/chrome/browser/net/preconnect.h @@ -19,7 +19,8 @@ namespace chrome_browser_net { -class Preconnect : public net::CompletionCallback { +class Preconnect : public net::CompletionCallback, + public base::RefCountedThreadSafe<Preconnect> { public: // Try to preconnect. Typically motivated by OMNIBOX to reach search service. static void PreconnectOnUIThread(const GURL& url, @@ -35,11 +36,15 @@ class Preconnect : public net::CompletionCallback { } private: - Preconnect() {} + friend class base::RefCountedThreadSafe<Preconnect>; - // Supply an instance that could have been used in an IO callback, but will - // never actually be used (because we reset the connection so quickly). - static Preconnect* callback_instance_; + explicit Preconnect(UrlInfo::ResolutionMotivation motivation) + : motivation_(motivation) { + } + ~Preconnect(); + + // Request actual connection. + void Connect(const GURL& url); // IO Callback which whould be performed when the connection is established. virtual void RunWithParams(const Tuple1<int>& params); @@ -50,6 +55,15 @@ class Preconnect : public net::CompletionCallback { // much work anway). static bool preconnect_despite_proxy_; + // The handle holding the request. We need this so that we can mark the + // request as speculative when an actual socket is bound to it. + net::ClientSocketHandle handle_; + + // Generally either LEARNED_REFERAL_MOTIVATED or OMNIBOX_MOTIVATED to indicate + // why we were trying to do a preconnection. + const UrlInfo::ResolutionMotivation motivation_; + + DISALLOW_COPY_AND_ASSIGN(Preconnect); }; } // chrome_browser_net diff --git a/chrome/browser/net/predictor.cc b/chrome/browser/net/predictor.cc index eb4992c..5c1b518 100644 --- a/chrome/browser/net/predictor.cc +++ b/chrome/browser/net/predictor.cc @@ -149,6 +149,20 @@ void Predictor::PredictFrameSubresources(const GURL& url) { Referrers::iterator it = referrers_.find(url); if (referrers_.end() == it) return; + ChromeThread::PostTask( + ChromeThread::IO, + FROM_HERE, + NewRunnableMethod(this, + &Predictor::PrepareFrameSubresources, url)); +} + +void Predictor::PrepareFrameSubresources(const GURL& url) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); + DCHECK(url.GetWithEmptyPath() == url); + Referrers::iterator it = referrers_.find(url); + if (referrers_.end() == it) + return; + Referrer* referrer = &(it->second); referrer->IncrementUseCount(); const UrlInfo::ResolutionMotivation motivation = diff --git a/chrome/browser/net/predictor.h b/chrome/browser/net/predictor.h index a5b71e7..c613093 100644 --- a/chrome/browser/net/predictor.h +++ b/chrome/browser/net/predictor.h @@ -83,8 +83,11 @@ class Predictor : public base::RefCountedThreadSafe<Predictor> { void Resolve(const GURL& url, UrlInfo::ResolutionMotivation motivation); - // Instigate pre-connection to any URLs we predict will be needed after this - // navigation (typically more-embedded resources on a page). + // Instigate pre-connection to any URLs, or pre-resolution of related host, + // that we predict will be needed after this navigation (typically + // more-embedded resources on a page). This method will actually post a task + // to do the actual work, so as not to jump ahead of the frame navigation that + // instigated this activity. void PredictFrameSubresources(const GURL& url); // Record details of a navigation so that we can preresolve the host name @@ -138,8 +141,6 @@ class Predictor : public base::RefCountedThreadSafe<Predictor> { FRIEND_TEST_ALL_PREFIXES(PredictorTest, PriorityQueueReorderTest); friend class WaitForResolutionHelper; // For testing. - ~Predictor(); - class LookupRequest; // A simple priority queue for handling host names. @@ -174,6 +175,13 @@ class Predictor : public base::RefCountedThreadSafe<Predictor> { // in a Referrer instance, which is a value in this map. typedef std::map<GURL, Referrer> Referrers; + ~Predictor(); + + // Perform actual resolution or preconnection to subresources now. This is + // an internal worker method that is reached via a post task from + // PredictFrameSubresources(). + void PrepareFrameSubresources(const GURL& url); + // Only for testing. Returns true if hostname has been successfully resolved // (name found). bool WasFound(const GURL& url) const { |