diff options
author | jar@chromium.org <jar@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-06-23 01:22:43 +0000 |
---|---|---|
committer | jar@chromium.org <jar@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-06-23 01:22:43 +0000 |
commit | c5629c3842ca9fab0a6bb71a478df3fc528b8837 (patch) | |
tree | 8141f7d0b43e0cba093f049b688a336693abab1b /chrome/browser | |
parent | 3f9345838d9af871413f7350ca587b0152299e02 (diff) | |
download | chromium_src-c5629c3842ca9fab0a6bb71a478df3fc528b8837.zip chromium_src-c5629c3842ca9fab0a6bb71a478df3fc528b8837.tar.gz chromium_src-c5629c3842ca9fab0a6bb71a478df3fc528b8837.tar.bz2 |
Do speculative preconnection based on network traffic (not just DNS)
This rev also handles the triple of scheme/host/port for recording
both referrers and speculative connections, so that we
can soon support SSL warming as well as "mere" TCP/IP
preconnection.
r=mbelshe
Review URL: http://codereview.chromium.org/2563004
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@50563 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r-- | chrome/browser/io_thread.cc | 29 | ||||
-rw-r--r-- | chrome/browser/io_thread.h | 22 | ||||
-rw-r--r-- | chrome/browser/net/connect_interceptor.cc | 41 | ||||
-rw-r--r-- | chrome/browser/net/connect_interceptor.h | 40 | ||||
-rw-r--r-- | chrome/browser/net/dns_global.cc | 173 | ||||
-rw-r--r-- | chrome/browser/net/dns_global.h | 19 | ||||
-rw-r--r-- | chrome/browser/net/dns_host_info.cc | 20 | ||||
-rw-r--r-- | chrome/browser/net/dns_host_info.h | 20 | ||||
-rw-r--r-- | chrome/browser/net/dns_host_info_unittest.cc | 10 | ||||
-rw-r--r-- | chrome/browser/net/dns_master.cc | 216 | ||||
-rw-r--r-- | chrome/browser/net/dns_master.h | 51 | ||||
-rw-r--r-- | chrome/browser/net/dns_master_unittest.cc | 206 | ||||
-rw-r--r-- | chrome/browser/net/preconnect.cc | 12 | ||||
-rw-r--r-- | chrome/browser/net/preconnect.h | 4 | ||||
-rw-r--r-- | chrome/browser/net/referrer.cc | 44 | ||||
-rw-r--r-- | chrome/browser/net/referrer.h | 15 |
16 files changed, 547 insertions, 375 deletions
diff --git a/chrome/browser/io_thread.cc b/chrome/browser/io_thread.cc index 5fcdb3d..d2b8fdd 100644 --- a/chrome/browser/io_thread.cc +++ b/chrome/browser/io_thread.cc @@ -86,6 +86,7 @@ DISABLE_RUNNABLE_METHOD_REFCOUNT(IOThread); IOThread::IOThread() : BrowserProcessSubThread(ChromeThread::IO), globals_(NULL), + speculative_interceptor_(NULL), prefetch_observer_(NULL), dns_master_(NULL) {} @@ -105,7 +106,7 @@ void IOThread::InitDnsMaster( bool prefetching_enabled, base::TimeDelta max_queue_delay, size_t max_concurrent, - const chrome_common_net::NameList& hostnames_to_prefetch, + const chrome_common_net::UrlList& startup_urls, ListValue* referral_list, bool preconnect_enabled) { DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); @@ -115,7 +116,7 @@ void IOThread::InitDnsMaster( this, &IOThread::InitDnsMasterOnIOThread, prefetching_enabled, max_queue_delay, max_concurrent, - hostnames_to_prefetch, referral_list, preconnect_enabled)); + startup_urls, referral_list, preconnect_enabled)); } void IOThread::ChangedToOnTheRecord() { @@ -149,8 +150,6 @@ void IOThread::CleanUp() { // Not initialized in Init(). May not be initialized. if (dns_master_) { - DCHECK(prefetch_observer_); - dns_master_->Shutdown(); // TODO(willchan): Stop reference counting DnsMaster. It's owned by @@ -160,6 +159,10 @@ void IOThread::CleanUp() { chrome_browser_net::FreeDnsPrefetchResources(); } + // Deletion will unregister this interceptor. + delete speculative_interceptor_; + speculative_interceptor_ = NULL; + // Not initialized in Init(). May not be initialized. if (prefetch_observer_) { globals_->host_resolver->RemoveObserver(prefetch_observer_); @@ -241,7 +244,7 @@ void IOThread::InitDnsMasterOnIOThread( bool prefetching_enabled, base::TimeDelta max_queue_delay, size_t max_concurrent, - chrome_common_net::NameList hostnames_to_prefetch, + const chrome_common_net::UrlList& startup_urls, ListValue* referral_list, bool preconnect_enabled) { DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); @@ -256,12 +259,20 @@ void IOThread::InitDnsMasterOnIOThread( preconnect_enabled); dns_master_->AddRef(); - DCHECK(!prefetch_observer_); - prefetch_observer_ = chrome_browser_net::CreatePrefetchObserver(); - globals_->host_resolver->AddObserver(prefetch_observer_); + // TODO(jar): Until connection notification and DNS observation handling are + // properly combined into a learning model, we'll only use one observation + // mechanism or the other. + if (preconnect_enabled) { + DCHECK(!speculative_interceptor_); + speculative_interceptor_ = new chrome_browser_net::ConnectInterceptor; + } else { + DCHECK(!prefetch_observer_); + prefetch_observer_ = chrome_browser_net::CreatePrefetchObserver(); + globals_->host_resolver->AddObserver(prefetch_observer_); + } FinalizeDnsPrefetchInitialization( - dns_master_, prefetch_observer_, hostnames_to_prefetch, referral_list); + dns_master_, prefetch_observer_, startup_urls, referral_list); } void IOThread::ChangedToOnTheRecordOnIOThread() { diff --git a/chrome/browser/io_thread.h b/chrome/browser/io_thread.h index 4c7374e..83a781d 100644 --- a/chrome/browser/io_thread.h +++ b/chrome/browser/io_thread.h @@ -5,6 +5,8 @@ #ifndef CHROME_BROWSER_IO_THREAD_H_ #define CHROME_BROWSER_IO_THREAD_H_ +#include <vector> + #include "base/basictypes.h" #include "base/ref_counted.h" #include "base/scoped_ptr.h" @@ -12,6 +14,7 @@ #include "chrome/browser/browser_process_sub_thread.h" #include "chrome/browser/net/chrome_network_delegate.h" #include "chrome/common/net/dns.h" +#include "chrome/browser/net/connect_interceptor.h" #include "net/base/host_resolver.h" class ChromeNetLog; @@ -47,14 +50,15 @@ class IOThread : public BrowserProcessSubThread { // Can only be called on the IO thread. Globals* globals(); - // Initializes the DnsMaster. |prefetching_enabled| indicates whether or - // not dns prefetching should be enabled. This should be called by the UI - // thread. It will post a task to the IO thread to perform the actual - // initialization. + // Initializes the network predictor, which induces DNS pre-resolution and/or + // TCP/IP preconnections. |prefetching_enabled| indicates whether or not DNS + // prefetching should be enabled, and |preconnect_enabled| controls whether + // TCP/IP preconnection is enabled. This should be called by the UI thread. + // It will post a task to the IO thread to perform the actual initialization. void InitDnsMaster(bool prefetching_enabled, base::TimeDelta max_queue_delay, size_t max_concurrent, - const chrome_common_net::NameList& hostnames_to_prefetch, + const chrome_common_net::UrlList& startup_urls, ListValue* referral_list, bool preconnect_enabled); @@ -74,7 +78,8 @@ class IOThread : public BrowserProcessSubThread { bool prefetching_enabled, base::TimeDelta max_queue_delay, size_t max_concurrent, - chrome_common_net::NameList hostnames_to_prefetch, + const chrome_common_net::UrlList& startup_urls, + ListValue* referral_list, bool preconnect_enabled); @@ -99,6 +104,11 @@ class IOThread : public BrowserProcessSubThread { // These member variables are initialized by a task posted to the IO thread, // which gets posted by calling certain member functions of IOThread. + // Note: we user explicit pointers rather than smart pointers to be more + // explicit about destruction order, and ensure that there is no chance that + // these observers would be used accidentally after we have begun to tear + // down. + chrome_browser_net::ConnectInterceptor* speculative_interceptor_; net::HostResolver::Observer* prefetch_observer_; chrome_browser_net::DnsMaster* dns_master_; diff --git a/chrome/browser/net/connect_interceptor.cc b/chrome/browser/net/connect_interceptor.cc new file mode 100644 index 0000000..ab45ddb --- /dev/null +++ b/chrome/browser/net/connect_interceptor.cc @@ -0,0 +1,41 @@ +// 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 "chrome/browser/net/connect_interceptor.h" + +#include "chrome/browser/net/dns_global.h" + +namespace chrome_browser_net { + +ConnectInterceptor::ConnectInterceptor() { + URLRequest::RegisterRequestInterceptor(this); +} + +ConnectInterceptor::~ConnectInterceptor() { + URLRequest::UnregisterRequestInterceptor(this); +} + +URLRequestJob* ConnectInterceptor::MaybeIntercept(URLRequest* request) { + if (!request->referrer().empty()) { + // Learn about our referring URL, for use in the future. + GURL referring_url(GURL(request->referrer()).GetWithEmptyPath()); + // TODO(jar): Only call if we think this was part of a frame load, and not a + // link navigation. For now, we'll "learn" that to preconnect when a user + // actually does a click... which will probably waste space in our referrers + // table (since it probably won't be that deterministic). + NonlinkNavigation(referring_url, request->url().GetWithEmptyPath()); + } + // Now we use previous learning and setup for our subresources. + if (request->was_fetched_via_proxy()) + return NULL; + // TODO(jar): Only call if we believe this is a frame, and might have + // subresources. We could "guess" by looking at path extensions (such as + // foo.jpg or goo.gif etc.), but better would be to get this info from webkit + // and have it add the info to the request (we currently only set the + // priority, but we could record whether it was a frame). + NavigatingToFrame(request->url().GetWithEmptyPath()); + return NULL; +} + +} // namespace chrome_browser_net diff --git a/chrome/browser/net/connect_interceptor.h b/chrome/browser/net/connect_interceptor.h new file mode 100644 index 0000000..21a6b00 --- /dev/null +++ b/chrome/browser/net/connect_interceptor.h @@ -0,0 +1,40 @@ +// 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 CHROME_BROWSER_NET_CONNECT_INTERCEPTOR_H_ +#define CHROME_BROWSER_NET_CONNECT_INTERCEPTOR_H_ + +#include "net/url_request/url_request.h" + +namespace chrome_browser_net { + +//------------------------------------------------------------------------------ +// An interceptor to monitor URLRequests so that we can do speculative DNS +// resolution and/or speculative TCP preconnections. +class ConnectInterceptor : public URLRequest::Interceptor { + public: + // Construction includes registration as an URL. + ConnectInterceptor(); + // Destruction includes unregistering. + virtual ~ConnectInterceptor(); + + protected: + // URLRequest::Interceptor overrides + // Learn about referrers, and optionally preconnect based on history. + virtual URLRequestJob* MaybeIntercept(URLRequest* request); + virtual URLRequestJob* MaybeInterceptResponse(URLRequest* request) { + return NULL; + } + virtual URLRequestJob* MaybeInterceptRedirect(URLRequest* request, + const GURL& location) { + return NULL; + } + + private: + DISALLOW_COPY_AND_ASSIGN(ConnectInterceptor); +}; + +} // namespace chrome_browser_net + +#endif // CHROME_BROWSER_NET_CONNECT_INTERCEPTOR_H_ diff --git a/chrome/browser/net/dns_global.cc b/chrome/browser/net/dns_global.cc index f57e029..fa33217 100644 --- a/chrome/browser/net/dns_global.cc +++ b/chrome/browser/net/dns_global.cc @@ -35,13 +35,13 @@ using base::TimeDelta; namespace chrome_browser_net { -static void DnsMotivatedPrefetch(const net::HostPortPair& hostport, +static void DnsMotivatedPrefetch(const GURL& url, DnsHostInfo::ResolutionMotivation motivation); -static void DnsPrefetchMotivatedList(const NameList& hostnames, +static void DnsPrefetchMotivatedList(const UrlList& urls, DnsHostInfo::ResolutionMotivation motivation); -static NameList GetDnsPrefetchHostNamesAtStartup( +static UrlList GetPrefetchUrlListAtStartup( PrefService* user_prefs, PrefService* local_state); // static @@ -52,7 +52,37 @@ const int DnsGlobalInit::kMaxPrefetchQueueingDelayMs = 500; // A version number for prefs that are saved. This should be incremented when // we change the format so that we discard old data. -static const int kDnsStartupFormatVersion = 0; +static const int kDnsStartupFormatVersion = 1; + +//------------------------------------------------------------------------------ +// Static helper functions +//------------------------------------------------------------------------------ + +// Put URL in canonical form, including a scheme, host, and port. +// Returns GURL::EmptyGURL() if the scheme is not http/https or if the url +// cannot be otherwise canonicalized. +static GURL CanonicalizeUrl(const GURL& url) { + if (!url.has_host()) + return GURL::EmptyGURL(); + + std::string scheme; + if (url.has_scheme()) { + scheme = url.scheme(); + if (scheme != "http" && scheme != "https") + return GURL::EmptyGURL(); + if (url.has_port()) + return url.GetWithEmptyPath(); + } else { + scheme = "http"; + } + + // If we omit a port, it will default to 80 or 443 as appropriate. + std::string colon_plus_port; + if (url.has_port()) + colon_plus_port = ":" + url.port(); + + return GURL(scheme + "://" + url.host() + colon_plus_port); +} //------------------------------------------------------------------------------ // This section contains all the globally accessable API entry points for the @@ -99,12 +129,20 @@ static DnsMaster* dns_master = NULL; // includes both Page-Scan, and Link-Hover prefetching. // TODO(jar): Separate out link-hover prefetching, and page-scan results. void DnsPrefetchList(const NameList& hostnames) { + // TODO(jar): Push GURL transport further back into renderer. + UrlList urls; + for (NameList::const_iterator it = hostnames.begin(); + it < hostnames.end(); + ++it) { + urls.push_back(GURL("http://" + *it + ":80")); + } + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); - DnsPrefetchMotivatedList(hostnames, DnsHostInfo::PAGE_SCAN_MOTIVATED); + DnsPrefetchMotivatedList(urls, DnsHostInfo::PAGE_SCAN_MOTIVATED); } static void DnsPrefetchMotivatedList( - const NameList& hostnames, + const UrlList& urls, DnsHostInfo::ResolutionMotivation motivation) { DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI) || ChromeThread::CurrentlyOn(ChromeThread::IO)); @@ -112,13 +150,13 @@ static void DnsPrefetchMotivatedList( return; if (ChromeThread::CurrentlyOn(ChromeThread::IO)) { - dns_master->ResolveList(hostnames, motivation); + dns_master->ResolveList(urls, motivation); } else { ChromeThread::PostTask( ChromeThread::IO, FROM_HERE, NewRunnableMethod(dns_master, - &DnsMaster::ResolveList, hostnames, motivation)); + &DnsMaster::ResolveList, urls, motivation)); } } @@ -147,7 +185,7 @@ void DnsPrefetchUrl(const GURL& url, bool preconnectable) { } last_prefetch_for_host = now; - net::HostPortPair hostport(url.HostNoBrackets(), url.EffectiveIntPort()); + GURL canonical_url(CanonicalizeUrl(url)); if (dns_master->preconnect_enabled() && preconnectable) { static base::TimeTicks last_keepalive; @@ -159,26 +197,25 @@ void DnsPrefetchUrl(const GURL& url, bool preconnectable) { return; last_keepalive = now; - if (Preconnect::PreconnectOnUIThread(hostport)) + if (Preconnect::PreconnectOnUIThread(canonical_url)) return; // Skip pre-resolution, since we'll open a connection. } // Perform at least DNS pre-resolution. - // TODO(jar): We could propogate a hostport here instead of a host. - DnsMotivatedPrefetch(hostport, DnsHostInfo::OMNIBOX_MOTIVATED); + DnsMotivatedPrefetch(canonical_url, DnsHostInfo::OMNIBOX_MOTIVATED); } -static void DnsMotivatedPrefetch(const net::HostPortPair& hostport, +static void DnsMotivatedPrefetch(const GURL& url, DnsHostInfo::ResolutionMotivation motivation) { DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); - if (!dns_prefetch_enabled || NULL == dns_master || hostport.host.empty()) + if (!dns_prefetch_enabled || NULL == dns_master || !url.has_host()) return; ChromeThread::PostTask( ChromeThread::IO, FROM_HERE, NewRunnableMethod(dns_master, - &DnsMaster::Resolve, hostport, motivation)); + &DnsMaster::Resolve, url, motivation)); } //------------------------------------------------------------------------------ @@ -190,23 +227,34 @@ static void DnsMotivatedPrefetch(const net::HostPortPair& hostport, // This function determines if there was a saving by prefetching the hostname // for which the navigation_info is supplied. -static bool AccruePrefetchBenefits(const GURL& referrer, +static bool AccruePrefetchBenefits(const GURL& referrer_url, DnsHostInfo* navigation_info) { DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); if (!dns_prefetch_enabled || NULL == dns_master) return false; - return dns_master->AccruePrefetchBenefits( - net::HostPortPair(referrer.host(), referrer.EffectiveIntPort()), - navigation_info); + DCHECK(referrer_url == referrer_url.GetWithEmptyPath()); + return dns_master->AccruePrefetchBenefits(referrer_url, navigation_info); +} + +void NavigatingTo(const GURL& url) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); + if (!dns_prefetch_enabled || NULL == dns_master) + return; + dns_master->NavigatingTo(url); +} + +void NavigatingToFrame(const GURL& url) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); + if (!dns_prefetch_enabled || NULL == dns_master) + return; + dns_master->NavigatingToFrame(url); } -// When we navigate, we may know in advance some other domains that will need to -// be resolved. This function initiates those side effects. -static void NavigatingTo(const net::HostPortPair& hostport) { +void NonlinkNavigation(const GURL& referring_url, const GURL& target_url) { DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); if (!dns_prefetch_enabled || NULL == dns_master) return; - dns_master->NavigatingTo(hostport); + dns_master->NonlinkNavigation(referring_url, target_url); } // The observer class needs to connect starts and finishes of HTTP network @@ -218,7 +266,7 @@ typedef std::map<int, DnsHostInfo> ObservedResolutionMap; // resolutions made by the network stack. class PrefetchObserver : public net::HostResolver::Observer { public: - typedef std::map<net::HostPortPair, DnsHostInfo> FirstResolutionMap; + typedef std::map<GURL, DnsHostInfo> FirstResolutionMap; // net::HostResolver::Observer implementation: virtual void OnStartResolution( @@ -261,8 +309,14 @@ void PrefetchObserver::OnStartResolution( DCHECK_NE(0U, request_info.hostname().length()); DnsHostInfo navigation_info; - navigation_info.SetHostname(net::HostPortPair(request_info.hostname(), - request_info.port())); + // TODO(jar): Remove hack which guestimates ssl via port number, and perhaps + // have actual URL passed down in request_info instead. + bool is_ssl(443 == request_info.port()); + std::string url_spec = is_ssl ? "https://" : "http://"; + url_spec += request_info.hostname(); + url_spec += ":"; + url_spec += IntToString(request_info.port()); + navigation_info.SetUrl(GURL(url_spec)); navigation_info.SetStartedState(); // This entry will be deleted either by OnFinishResolutionWithStatus(), or @@ -291,12 +345,16 @@ void PrefetchObserver::OnFinishResolutionWithStatus( } navigation_info.SetFinishedState(was_resolved); // Get timing info - AccruePrefetchBenefits(request_info.referrer(), &navigation_info); + AccruePrefetchBenefits(CanonicalizeUrl(request_info.referrer()), + &navigation_info); // Handle sub-resource resolutions now that the critical navigational // resolution has completed. This prevents us from in any way delaying that // navigational resolution. - NavigatingTo(net::HostPortPair(request_info.hostname(), request_info.port())); + std::string url_spec; + StringAppendF(&url_spec, "http%s://%s:%d", "", + request_info.hostname().c_str(), request_info.port()); + NavigatingTo(GURL(url_spec)); if (kStartupResolutionCount <= startup_count || !was_resolved) return; @@ -329,9 +387,9 @@ void PrefetchObserver::StartupListAppend(const DnsHostInfo& navigation_info) { return; if (kStartupResolutionCount <= first_resolutions_.size()) return; // Someone just added the last item. - if (ContainsKey(first_resolutions_, navigation_info.hostport())) + if (ContainsKey(first_resolutions_, navigation_info.url())) return; // We already have this hostname listed. - first_resolutions_[navigation_info.hostport()] = navigation_info; + first_resolutions_[navigation_info.url()] = navigation_info; } void PrefetchObserver::GetInitialDnsResolutionList(ListValue* startup_list) { @@ -343,8 +401,8 @@ void PrefetchObserver::GetInitialDnsResolutionList(ListValue* startup_list) { for (FirstResolutionMap::iterator it = first_resolutions_.begin(); it != first_resolutions_.end(); ++it) { - startup_list->Append(new StringValue(it->first.host)); - startup_list->Append(new FundamentalValue(it->first.port)); + DCHECK(it->first == CanonicalizeUrl(it->first)); + startup_list->Append(new StringValue(it->first.spec())); } } @@ -435,7 +493,8 @@ void DnsPrefetchGetHtmlInfo(std::string* output) { output->append("Incognito mode is active in a window."); } else { dns_master->GetHtmlInfo(output); - g_prefetch_observer->DnsGetFirstResolutionsHtml(output); + if (g_prefetch_observer) + g_prefetch_observer->DnsGetFirstResolutionsHtml(output); dns_master->GetHtmlReferrerLists(output); } } @@ -455,22 +514,22 @@ static void InitDnsPrefetch(TimeDelta max_queue_delay, size_t max_concurrent, user_prefs->GetBoolean(prefs::kDnsPrefetchingEnabled); // Gather the list of hostnames to prefetch on startup. - NameList hostnames = - GetDnsPrefetchHostNamesAtStartup(user_prefs, local_state); + UrlList urls = + GetPrefetchUrlListAtStartup(user_prefs, local_state); ListValue* referral_list = static_cast<ListValue*>( local_state->GetMutableList(prefs::kDnsHostReferralList)->DeepCopy()); g_browser_process->io_thread()->InitDnsMaster( - prefetching_enabled, max_queue_delay, max_concurrent, hostnames, + prefetching_enabled, max_queue_delay, max_concurrent, urls, referral_list, preconnect_enabled); } void FinalizeDnsPrefetchInitialization( DnsMaster* global_dns_master, net::HostResolver::Observer* global_prefetch_observer, - const NameList& hostnames_to_prefetch, + const UrlList& startup_urls, ListValue* referral_list) { DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); dns_master = global_dns_master; @@ -480,7 +539,7 @@ void FinalizeDnsPrefetchInitialization( DLOG(INFO) << "DNS Prefetch service started"; // Prefetch these hostnames on startup. - DnsPrefetchMotivatedList(hostnames_to_prefetch, + DnsPrefetchMotivatedList(startup_urls, DnsHostInfo::STARTUP_LIST_MOTIVATED); dns_master->DeserializeReferrersThenDelete(referral_list); } @@ -511,7 +570,8 @@ static void SaveDnsPrefetchStateForNextStartupAndTrimOnIOThread( return; } - g_prefetch_observer->GetInitialDnsResolutionList(startup_list); + if (g_prefetch_observer) + g_prefetch_observer->GetInitialDnsResolutionList(startup_list); // TODO(jar): Trimming should be done more regularly, such as every 48 hours // of physical time, or perhaps after 48 hours of running (excluding time @@ -544,11 +604,11 @@ void SaveDnsPrefetchStateForNextStartupAndTrim(PrefService* prefs) { completion.Wait(); } -static NameList GetDnsPrefetchHostNamesAtStartup(PrefService* user_prefs, - PrefService* local_state) { +static UrlList GetPrefetchUrlListAtStartup(PrefService* user_prefs, + PrefService* local_state) { DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); - NameList hostnames; - // Prefetch DNS for hostnames we learned about during last session. + UrlList urls; + // Recall list of URLs we learned about during last session. // This may catch secondary hostnames, pulled in by the homepages. It will // also catch more of the "primary" home pages, since that was (presumably) // rendered first (and will be rendered first this time too). @@ -562,15 +622,18 @@ static NameList GetDnsPrefetchHostNamesAtStartup(PrefService* user_prefs, format_version == kDnsStartupFormatVersion) { ++it; for (; it != startup_list->end(); ++it) { - std::string hostname; - if (!(*it)->GetAsString(&hostname)) + std::string url_spec; + if (!(*it)->GetAsString(&url_spec)) { + LOG(DFATAL); break; // Format incompatibility. - int port; - if (!(*++it)->GetAsInteger(&port)) + } + GURL url(url_spec); + if (!url.has_host() || !url.has_scheme()) { + LOG(DFATAL); break; // Format incompatibility. + } - // TODO(jar): We sohould accept hostport pairs. - hostnames.push_back(hostname); + urls.push_back(url); } } } @@ -582,15 +645,17 @@ static NameList GetDnsPrefetchHostNamesAtStartup(PrefService* user_prefs, if (SessionStartupPref::URLS == tab_start_pref.type) { for (size_t i = 0; i < tab_start_pref.urls.size(); i++) { GURL gurl = tab_start_pref.urls[i]; - if (gurl.is_valid() && !gurl.host().empty()) - hostnames.push_back(gurl.HostNoBrackets()); + if (!gurl.is_valid() || gurl.SchemeIsFile() || gurl.host().empty()) + continue; + if (gurl.SchemeIs("http") || gurl.SchemeIs("https")) + urls.push_back(gurl.GetWithEmptyPath()); } } - if (hostnames.empty()) - hostnames.push_back("www.google.com"); + if (urls.empty()) + urls.push_back(GURL("http://www.google.com:80")); - return hostnames; + return urls; } //------------------------------------------------------------------------------ diff --git a/chrome/browser/net/dns_global.h b/chrome/browser/net/dns_global.h index 639f614..0abacc5 100644 --- a/chrome/browser/net/dns_global.h +++ b/chrome/browser/net/dns_global.h @@ -13,6 +13,7 @@ #include <string> +#include <vector> #include "base/field_trial.h" #include "base/scoped_ptr.h" @@ -28,7 +29,7 @@ namespace chrome_browser_net { void FinalizeDnsPrefetchInitialization( DnsMaster* global_dns_master, net::HostResolver::Observer* global_prefetch_observer, - const NameList& hostnames_to_prefetch, + const std::vector<GURL>& urls_to_prefetch, ListValue* referral_list); // Free all resources allocated by FinalizeDnsPrefetchInitialization. After that @@ -45,6 +46,7 @@ void RegisterPrefs(PrefService* local_state); void RegisterUserPrefs(PrefService* user_prefs); // Renderer bundles up list and sends to this browser API via IPC. +// TODO(jar): Use UrlList instead to include port and scheme. void DnsPrefetchList(const NameList& hostnames); // This API is used by the autocomplete popup box (as user types). @@ -56,6 +58,21 @@ void DnsPrefetchUrl(const GURL& url, bool preconnectable); void DnsPrefetchGetHtmlInfo(std::string* output); //------------------------------------------------------------------------------ +// When we navigate, we may know in advance some other domains that will need to +// be resolved. This function initiates those side effects. +void NavigatingTo(const GURL& url); + +// When we navigate to a frame that may contain embedded resources, we may know +// in advance some other URLs that will need to be connected to (via TCP and +// sometimes SSL). This function initiates those connections +void NavigatingToFrame(const GURL& url); + +// Call when we should learn from a navigation about a relationship to a +// subresource target, and its containing frame, which was loaded as a referring +// URL. +void NonlinkNavigation(const GURL& referring_url, const GURL& target_url); + +//------------------------------------------------------------------------------ void SaveDnsPrefetchStateForNextStartupAndTrim(PrefService* prefs); // Helper class to handle global init and shutdown. class DnsGlobalInit { diff --git a/chrome/browser/net/dns_host_info.cc b/chrome/browser/net/dns_host_info.cc index 2fb626d..522b69e 100644 --- a/chrome/browser/net/dns_host_info.cc +++ b/chrome/browser/net/dns_host_info.cc @@ -170,11 +170,11 @@ void DnsHostInfo::SetFinishedState(bool was_resolved) { DLogResultsStats("DNS HTTP Finished"); } -void DnsHostInfo::SetHostname(const net::HostPortPair& hostport) { - if (hostport_.host.empty()) // Not yet initialized. - hostport_ = hostport; +void DnsHostInfo::SetUrl(const GURL& url) { + if (url_.is_empty()) // Not yet initialized. + url_ = url; else - DCHECK(hostport_.Equals(hostport)); + DCHECK_EQ(url_, url); } // IsStillCached() guesses if the DNS cache still has IP data, @@ -200,7 +200,7 @@ bool DnsHostInfo::IsStillCached() const { DnsBenefit DnsHostInfo::AccruePrefetchBenefits(DnsHostInfo* navigation_info) { DCHECK(FINISHED == navigation_info->state_ || FINISHED_UNRESOLVED == navigation_info->state_); - DCHECK(navigation_info->hostport().Equals(hostport_)); + DCHECK(navigation_info->url() == url_); if ((0 == benefits_remaining_.InMilliseconds()) || (FOUND != state_ && NO_SUCH_NAME != state_)) { @@ -220,7 +220,7 @@ DnsBenefit DnsHostInfo::AccruePrefetchBenefits(DnsHostInfo* navigation_info) { navigation_info->motivation_ = motivation_; if (LEARNED_REFERAL_MOTIVATED == motivation_ || STATIC_REFERAL_MOTIVATED == motivation_) - navigation_info->referring_hostport_ = referring_hostport_; + navigation_info->referring_url_ = referring_url_; if (navigation_info->resolve_duration_ > kMaxNonNetworkDnsLookupDuration) { // Our precache effort didn't help since HTTP stack hit the network. @@ -255,7 +255,7 @@ void DnsHostInfo::DLogResultsStats(const char* message) const { << resolve_duration().InMilliseconds() << "ms\tp=" << benefits_remaining_.InMilliseconds() << "ms\tseq=" << sequence_number_ - << "\t" << hostport_.ToString(); + << "\t" << url_.spec(); } //------------------------------------------------------------------------------ @@ -361,7 +361,7 @@ void DnsHostInfo::GetHtmlTable(const DnsInfoTable host_infos, it != host_infos.end(); it++) { queue.sample((it->queue_duration_.InMilliseconds())); StringAppendF(output, row_format, - RemoveJs(it->hostport_.ToString()).c_str(), + RemoveJs(it->url_.spec()).c_str(), preresolve.sample((it->benefits_remaining_.InMilliseconds())), resolve.sample((it->resolve_duration_.InMilliseconds())), HoursMinutesSeconds(when.sample( @@ -426,10 +426,10 @@ std::string DnsHostInfo::GetAsciiMotivation() const { return "n/a"; case STATIC_REFERAL_MOTIVATED: - return RemoveJs(referring_hostport_.ToString()) + "*"; + return RemoveJs(referring_url_.spec()) + "*"; case LEARNED_REFERAL_MOTIVATED: - return RemoveJs(referring_hostport_.ToString()); + return RemoveJs(referring_url_.spec()); default: return ""; diff --git a/chrome/browser/net/dns_host_info.h b/chrome/browser/net/dns_host_info.h index 73a0b2e..6c34025 100644 --- a/chrome/browser/net/dns_host_info.h +++ b/chrome/browser/net/dns_host_info.h @@ -44,7 +44,7 @@ class DnsHostInfo { NO_PREFETCH_MOTIVATION, // Browser navigation info (not prefetch related). // The following involve predictive prefetching, triggered by a navigation. - // The referring_hostport_ is also set when these are used. + // The referrinrg_url_ is also set when these are used. // TODO(jar): Support STATIC_REFERAL_MOTIVATED API and integration. STATIC_REFERAL_MOTIVATED, // External database suggested this resolution. LEARNED_REFERAL_MOTIVATED, // Prior navigation taught us this resolution. @@ -106,13 +106,13 @@ class DnsHostInfo { void SetFinishedState(bool was_resolved); // Finish initialization. Must only be called once. - void SetHostname(const net::HostPortPair& hostport); + void SetUrl(const GURL& url); bool was_linked() const { return was_linked_; } - net::HostPortPair referring_hostname() const { return referring_hostport_; } - void SetReferringHostname(const net::HostPortPair& hostport) { - referring_hostport_ = hostport; + GURL referring_url() const { return referring_url_; } + void SetReferringHostname(const GURL& url) { + referring_url_ = url; } bool was_found() const { return FOUND == state_; } @@ -121,10 +121,10 @@ class DnsHostInfo { return ASSIGNED == state_ || ASSIGNED_BUT_MARKED == state_; } bool is_marked_to_delete() const { return ASSIGNED_BUT_MARKED == state_; } - const net::HostPortPair hostport() const { return hostport_; } + const GURL url() const { return url_; } - bool HasHostname(const net::HostPortPair& hostport) const { - return (hostport.Equals(hostport_)); + bool HasUrl(const GURL& url) const { + return url_ == url; } base::TimeDelta resolve_duration() const { return resolve_duration_;} @@ -167,7 +167,7 @@ class DnsHostInfo { // out of the queue. DnsProcessingState old_prequeue_state_; - net::HostPortPair hostport_; // Hostname for this info. + GURL url_; // Host, port and scheme for this info. // When was last state changed (usually lookup completed). base::TimeTicks time_; @@ -190,7 +190,7 @@ class DnsHostInfo { // If this instance holds data about a navigation, we store the referrer. // If this instance hold data about a prefetch, and the prefetch was // instigated by a referrer, we store it here (for use in about:dns). - net::HostPortPair referring_hostport_; + GURL referring_url_; // We put these objects into a std::map, and hence we // need some "evil" constructors. diff --git a/chrome/browser/net/dns_host_info_unittest.cc b/chrome/browser/net/dns_host_info_unittest.cc index 7c145a4..ffe122f 100644 --- a/chrome/browser/net/dns_host_info_unittest.cc +++ b/chrome/browser/net/dns_host_info_unittest.cc @@ -22,19 +22,19 @@ typedef chrome_browser_net::DnsHostInfo DnsHostInfo; TEST(DnsHostInfoTest, StateChangeTest) { DnsHostInfo info_practice, info; - net::HostPortPair hostname1("domain1.com", 80), hostname2("domain2.com", 443); + GURL url1("http://domain1.com:80"), url2("https://domain2.com:443"); // First load DLL, so that their load time won't interfere with tests. // Some tests involve timing function performance, and DLL time can overwhelm // test durations (which are considering network vs cache response times). - info_practice.SetHostname(hostname2); + info_practice.SetUrl(url2); info_practice.SetQueuedState(DnsHostInfo::UNIT_TEST_MOTIVATED); info_practice.SetAssignedState(); info_practice.SetFoundState(); PlatformThread::Sleep(500); // Allow time for DLLs to fully load. // Complete the construction of real test object. - info.SetHostname(hostname1); + info.SetUrl(url1); EXPECT_TRUE(info.NeedsDnsUpdate()) << "error in construction state"; info.SetQueuedState(DnsHostInfo::UNIT_TEST_MOTIVATED); @@ -93,9 +93,9 @@ TEST(DnsHostInfoTest, StateChangeTest) { // the state transitions used in such congestion handling. TEST(DnsHostInfoTest, CongestionResetStateTest) { DnsHostInfo info; - net::HostPortPair hostname1("domain1.com", 80); + GURL url("http://domain1.com:80"); - info.SetHostname(hostname1); + info.SetUrl(url); info.SetQueuedState(DnsHostInfo::UNIT_TEST_MOTIVATED); info.SetAssignedState(); EXPECT_TRUE(info.is_assigned()); diff --git a/chrome/browser/net/dns_master.cc b/chrome/browser/net/dns_master.cc index 11f65d7..972759f 100644 --- a/chrome/browser/net/dns_master.cc +++ b/chrome/browser/net/dns_master.cc @@ -30,11 +30,11 @@ class DnsMaster::LookupRequest { public: LookupRequest(DnsMaster* master, net::HostResolver* host_resolver, - const net::HostPortPair& hostport) + const GURL& url) : ALLOW_THIS_IN_INITIALIZER_LIST( net_callback_(this, &LookupRequest::OnLookupFinished)), master_(master), - hostport_(hostport), + url_(url), resolver_(host_resolver) { } @@ -43,7 +43,8 @@ class DnsMaster::LookupRequest { // net:ERR_IO_PENDING ==> Network will callback later with result. // anything else ==> Host was not found synchronously. int Start() { - net::HostResolver::RequestInfo resolve_info(hostport_.host, hostport_.port); + net::HostResolver::RequestInfo resolve_info(url_.host(), + url_.EffectiveIntPort()); // Make a note that this is a speculative resolve request. This allows us // to separate it from real navigations in the observer's callback, and @@ -55,7 +56,7 @@ class DnsMaster::LookupRequest { private: void OnLookupFinished(int result) { - master_->OnLookupFinished(this, hostport_, result == net::OK); + master_->OnLookupFinished(this, url_, result == net::OK); } // HostResolver will call us using this callback when resolution is complete. @@ -63,7 +64,7 @@ class DnsMaster::LookupRequest { DnsMaster* master_; // Master which started us. - const net::HostPortPair hostport_; // Hostname to resolve. + const GURL url_; // Hostname to resolve. net::SingleRequestHostResolver resolver_; net::AddressList addresses_; @@ -98,38 +99,37 @@ void DnsMaster::Shutdown() { } // Overloaded Resolve() to take a vector of names. -void DnsMaster::ResolveList(const NameList& hostnames, +void DnsMaster::ResolveList(const UrlList& urls, DnsHostInfo::ResolutionMotivation motivation) { DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); - NameList::const_iterator it; - for (it = hostnames.begin(); it < hostnames.end(); ++it) - // TODO(jar): I should pass port all the way in from renderer. - AppendToResolutionQueue(net::HostPortPair(*it, 80), motivation); + for (UrlList::const_iterator it = urls.begin(); it < urls.end(); ++it) { + AppendToResolutionQueue(*it, motivation); + } } // Basic Resolve() takes an invidual name, and adds it // to the queue. -void DnsMaster::Resolve(const net::HostPortPair& hostport, +void DnsMaster::Resolve(const GURL& url, DnsHostInfo::ResolutionMotivation motivation) { DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); - if (hostport.host.empty()) + if (!url.has_host()) return; - AppendToResolutionQueue(hostport, motivation); + AppendToResolutionQueue(url, motivation); } -bool DnsMaster::AccruePrefetchBenefits(const net::HostPortPair& referrer, +bool DnsMaster::AccruePrefetchBenefits(const GURL& referrer, DnsHostInfo* navigation_info) { DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); - net::HostPortPair hostport = navigation_info->hostport(); - Results::iterator it = results_.find(hostport); + GURL url = navigation_info->url(); + Results::iterator it = results_.find(url); if (it == results_.end()) { // Use UMA histogram to quantify potential future gains here. UMA_HISTOGRAM_LONG_TIMES("DNS.UnexpectedResolutionL", navigation_info->resolve_duration()); navigation_info->DLogResultsStats("DNS UnexpectedResolution"); - NonlinkNavigation(referrer, navigation_info); + NonlinkNavigation(referrer, navigation_info->url()); return false; } DnsHostInfo& prefetched_host_info(it->second); @@ -141,7 +141,7 @@ bool DnsMaster::AccruePrefetchBenefits(const net::HostPortPair& referrer, bool referrer_based_prefetch = !prefetched_host_info.was_linked(); if (referrer_based_prefetch) { // This wasn't the first time this host refered to *some* referrer. - NonlinkNavigation(referrer, navigation_info); + NonlinkNavigation(referrer, navigation_info->url()); } DnsBenefit benefit = prefetched_host_info.AccruePrefetchBenefits( @@ -151,15 +151,15 @@ bool DnsMaster::AccruePrefetchBenefits(const net::HostPortPair& referrer, case PREFETCH_NAME_NONEXISTANT: cache_hits_.push_back(*navigation_info); if (referrer_based_prefetch) { - if (!referrer.host.empty()) { + if (referrer.has_host()) { referrers_[referrer].AccrueValue( - navigation_info->benefits_remaining(), hostport); + navigation_info->benefits_remaining(), url); } } return true; case PREFETCH_CACHE_EVICTION: - cache_eviction_map_[hostport] = *navigation_info; + cache_eviction_map_[url] = *navigation_info; return false; case PREFETCH_NO_BENEFIT: @@ -172,36 +172,45 @@ bool DnsMaster::AccruePrefetchBenefits(const net::HostPortPair& referrer, } } -void DnsMaster::NonlinkNavigation(const net::HostPortPair& referring_hostport, - const DnsHostInfo* navigation_info) { +void DnsMaster::NonlinkNavigation(const GURL& referring_url, + const GURL& target_url) { DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); - if (referring_hostport.host.empty() || - referring_hostport.Equals(navigation_info->hostport())) - return; - referrers_[referring_hostport].SuggestHost(navigation_info->hostport()); + if (referring_url.has_host() && + referring_url != target_url) { + DCHECK(referring_url == referring_url.GetWithEmptyPath()); + referrers_[referring_url].SuggestHost(target_url); + } } -void DnsMaster::NavigatingTo(const net::HostPortPair& hostport) { +void DnsMaster::NavigatingTo(const GURL& url) { DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); - Referrers::iterator it = referrers_.find(hostport); + Referrers::iterator it = referrers_.find(url); if (referrers_.end() == it) return; Referrer* referrer = &(it->second); referrer->IncrementUseCount(); - for (Referrer::iterator future_hostport = referrer->begin(); - future_hostport != referrer->end(); ++future_hostport) { - if (preconnect_enabled_) { - if (future_hostport->second.IsPreconnectWorthDoing()) { - Preconnect::PreconnectOnIOThread(future_hostport->first); - continue; // No need he pre-resolve DNS. - } - // Fall through and do DNS pre-resolution. - } + for (Referrer::iterator future_url = referrer->begin(); + future_url != referrer->end(); ++future_url) { DnsHostInfo* queued_info = AppendToResolutionQueue( - future_hostport->first, + future_url->first, DnsHostInfo::LEARNED_REFERAL_MOTIVATED); if (queued_info) - queued_info->SetReferringHostname(hostport); + queued_info->SetReferringHostname(url); + } +} + +void DnsMaster::NavigatingToFrame(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(); + for (Referrer::iterator future_url = referrer->begin(); + future_url != referrer->end(); ++future_url) { + if (future_url->second.IsPreconnectWorthDoing()) + Preconnect::PreconnectOnIOThread(future_url->first); } } @@ -278,7 +287,7 @@ void DnsMaster::GetHtmlReferrerLists(std::string* output) { // TODO(jar): Remove any plausible JavaScript from names before displaying. - typedef std::set<net::HostPortPair, struct RightToLeftStringSorter> + typedef std::set<GURL, struct RightToLeftStringSorter> SortedNames; SortedNames sorted_names; @@ -300,23 +309,23 @@ void DnsMaster::GetHtmlReferrerLists(std::string* output) { sorted_names.end() != it; ++it) { Referrer* referrer = &(referrers_[*it]); bool first_set_of_futures = true; - for (Referrer::iterator future_hostport = referrer->begin(); - future_hostport != referrer->end(); ++future_hostport) { + for (Referrer::iterator future_url = referrer->begin(); + future_url != referrer->end(); ++future_url) { output->append("<tr align=right>"); if (first_set_of_futures) StringAppendF(output, "<td rowspan=%d>%s</td><td rowspan=%d>%d</td>", static_cast<int>(referrer->size()), - it->ToString().c_str(), + it->spec().c_str(), static_cast<int>(referrer->size()), static_cast<int>(referrer->use_count())); first_set_of_futures = false; StringAppendF(output, "<td>%d</td><td>%d</td><td>%2.3f</td><td>%dms</td><td>%s</td></tr>", - static_cast<int>(future_hostport->second.navigation_count()), - static_cast<int>(future_hostport->second.preconnection_count()), - static_cast<double>(future_hostport->second.subresource_use_rate()), - static_cast<int>(future_hostport->second.latency().InMilliseconds()), - future_hostport->first.ToString().c_str()); + static_cast<int>(future_url->second.navigation_count()), + static_cast<int>(future_url->second.preconnection_count()), + static_cast<double>(future_url->second.subresource_use_rate()), + static_cast<int>(future_url->second.latency().InMilliseconds()), + future_url->first.spec().c_str()); } } output->append("</table>"); @@ -332,7 +341,7 @@ void DnsMaster::GetHtmlInfo(std::string* output) { DnsHostInfo::DnsInfoTable already_cached; // Get copies of all useful data. - typedef std::map<net::HostPortPair, DnsHostInfo, RightToLeftStringSorter> + typedef std::map<GURL, DnsHostInfo, RightToLeftStringSorter> Snapshot; Snapshot snapshot; { @@ -393,20 +402,20 @@ void DnsMaster::GetHtmlInfo(std::string* output) { } DnsHostInfo* DnsMaster::AppendToResolutionQueue( - const net::HostPortPair& hostport, + const GURL& url, DnsHostInfo::ResolutionMotivation motivation) { DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); - DCHECK(!hostport.host.empty()); + DCHECK(url.has_host()); if (shutdown_) return NULL; - DnsHostInfo* info = &results_[hostport]; - info->SetHostname(hostport); // Initialize or DCHECK. + DnsHostInfo* info = &results_[url]; + info->SetUrl(url); // Initialize or DCHECK. // TODO(jar): I need to discard names that have long since expired. // Currently we only add to the domain map :-/ - DCHECK(info->HasHostname(hostport)); + DCHECK(info->HasUrl(url)); if (!info->NeedsDnsUpdate()) { info->DLogResultsStats("DNS PrefetchNotUpdated"); @@ -414,7 +423,7 @@ DnsHostInfo* DnsMaster::AppendToResolutionQueue( } info->SetQueuedState(motivation); - work_queue_.Push(hostport, motivation); + work_queue_.Push(url, motivation); StartSomeQueuedResolutions(); return info; } @@ -424,9 +433,9 @@ void DnsMaster::StartSomeQueuedResolutions() { while (!work_queue_.IsEmpty() && pending_lookups_.size() < max_concurrent_lookups_) { - const net::HostPortPair hostport(work_queue_.Pop()); - DnsHostInfo* info = &results_[hostport]; - DCHECK(info->HasHostname(hostport)); + const GURL url(work_queue_.Pop()); + DnsHostInfo* info = &results_[url]; + DCHECK(info->HasUrl(url)); info->SetAssignedState(); if (CongestionControlPerformed(info)) { @@ -434,7 +443,7 @@ void DnsMaster::StartSomeQueuedResolutions() { return; } - LookupRequest* request = new LookupRequest(this, host_resolver_, hostport); + LookupRequest* request = new LookupRequest(this, host_resolver_, url); int status = request->Start(); if (status == net::ERR_IO_PENDING) { // Will complete asynchronously. @@ -445,7 +454,7 @@ void DnsMaster::StartSomeQueuedResolutions() { // Completed synchronously (was already cached by HostResolver), or else // there was (equivalently) some network error that prevents us from // finding the name. Status net::OK means it was "found." - LookupFinished(request, hostport, status == net::OK); + LookupFinished(request, url, status == net::OK); delete request; } } @@ -469,26 +478,24 @@ bool DnsMaster::CongestionControlPerformed(DnsHostInfo* info) { return true; } -void DnsMaster::OnLookupFinished(LookupRequest* request, - const net::HostPortPair& hostport, +void DnsMaster::OnLookupFinished(LookupRequest* request, const GURL& url, bool found) { DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); - LookupFinished(request, hostport, found); + LookupFinished(request, url, found); pending_lookups_.erase(request); delete request; StartSomeQueuedResolutions(); } -void DnsMaster::LookupFinished(LookupRequest* request, - const net::HostPortPair& hostport, +void DnsMaster::LookupFinished(LookupRequest* request, const GURL& url, bool found) { DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); - DnsHostInfo* info = &results_[hostport]; - DCHECK(info->HasHostname(hostport)); + DnsHostInfo* info = &results_[url]; + DCHECK(info->HasUrl(url)); if (info->is_marked_to_delete()) { - results_.erase(hostport); + results_.erase(url); } else { if (found) info->SetFoundState(); @@ -508,9 +515,9 @@ void DnsMaster::DiscardAllResults() { // Try to delete anything in our work queue. while (!work_queue_.IsEmpty()) { // Emulate processing cycle as though host was not found. - net::HostPortPair hostport = work_queue_.Pop(); - DnsHostInfo* info = &results_[hostport]; - DCHECK(info->HasHostname(hostport)); + GURL url = work_queue_.Pop(); + DnsHostInfo* info = &results_[url]; + DCHECK(info->HasUrl(url)); info->SetAssignedState(); info->SetNoSuchNameState(); } @@ -521,12 +528,12 @@ void DnsMaster::DiscardAllResults() { // We can't erase anything being worked on. Results assignees; for (Results::iterator it = results_.begin(); results_.end() != it; ++it) { - net::HostPortPair hostport(it->first); + GURL url(it->first); DnsHostInfo* info = &it->second; - DCHECK(info->HasHostname(hostport)); + DCHECK(info->HasUrl(url)); if (info->is_assigned()) { info->SetPendingDeleteState(); - assignees[hostport] = *info; + assignees[url] = *info; } } DCHECK(assignees.size() <= max_concurrent_lookups_); @@ -540,13 +547,13 @@ void DnsMaster::DiscardAllResults() { void DnsMaster::TrimReferrers() { DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); - std::vector<net::HostPortPair> hosts; + std::vector<GURL> urls; for (Referrers::const_iterator it = referrers_.begin(); it != referrers_.end(); ++it) - hosts.push_back(it->first); - for (size_t i = 0; i < hosts.size(); ++i) - if (!referrers_[hosts[i]].Trim()) - referrers_.erase(hosts[i]); + urls.push_back(it->first); + for (size_t i = 0; i < urls.size(); ++i) + if (!referrers_[urls[i]].Trim()) + referrers_.erase(urls[i]); } void DnsMaster::SerializeReferrers(ListValue* referral_list) { @@ -560,8 +567,7 @@ void DnsMaster::SerializeReferrers(ListValue* referral_list) { // Create a list for each referer. ListValue* motivator(new ListValue); - motivator->Append(new FundamentalValue(it->first.port)); - motivator->Append(new StringValue(it->first.host)); + motivator->Append(new StringValue(it->first.spec())); motivator->Append(subresource_list); referral_list->Append(motivator); @@ -578,30 +584,21 @@ void DnsMaster::DeserializeReferrers(const ListValue& referral_list) { ListValue* motivator; if (!referral_list.GetList(i, &motivator)) { NOTREACHED(); - continue; - } - int motivating_port; - if (!motivator->GetInteger(0, &motivating_port)) { - NOTREACHED(); - continue; + return; } - std::string motivating_host; - if (!motivator->GetString(1, &motivating_host)) { + std::string motivating_url_spec; + if (!motivator->GetString(0, &motivating_url_spec)) { NOTREACHED(); - continue; - } - if (motivating_host.empty()) { - NOTREACHED(); - continue; + return; } Value* subresource_list; - if (!motivator->Get(2, &subresource_list)) { + if (!motivator->Get(1, &subresource_list)) { NOTREACHED(); - continue; + return; } - net::HostPortPair motivating_hostport(motivating_host, motivating_port); - referrers_[motivating_hostport].Deserialize(*subresource_list); + + referrers_[GURL(motivating_url_spec)].Deserialize(*subresource_list); } } } @@ -615,17 +612,17 @@ DnsMaster::HostNameQueue::HostNameQueue() { DnsMaster::HostNameQueue::~HostNameQueue() { } -void DnsMaster::HostNameQueue::Push(const net::HostPortPair& hostport, +void DnsMaster::HostNameQueue::Push(const GURL& url, DnsHostInfo::ResolutionMotivation motivation) { switch (motivation) { case DnsHostInfo::STATIC_REFERAL_MOTIVATED: case DnsHostInfo::LEARNED_REFERAL_MOTIVATED: case DnsHostInfo::MOUSE_OVER_MOTIVATED: - rush_queue_.push(hostport); + rush_queue_.push(url); break; default: - background_queue_.push(hostport); + background_queue_.push(url); break; } } @@ -634,16 +631,13 @@ bool DnsMaster::HostNameQueue::IsEmpty() const { return rush_queue_.empty() && background_queue_.empty(); } -net::HostPortPair DnsMaster::HostNameQueue::Pop() { +GURL DnsMaster::HostNameQueue::Pop() { DCHECK(!IsEmpty()); - if (!rush_queue_.empty()) { - net::HostPortPair hostport(rush_queue_.front()); - rush_queue_.pop(); - return hostport; - } - net::HostPortPair hostport(background_queue_.front()); - background_queue_.pop(); - return hostport; + std::queue<GURL> *queue(rush_queue_.empty() ? &background_queue_ + : &rush_queue_); + GURL url(queue->front()); + queue->pop(); + return url; } } // namespace chrome_browser_net diff --git a/chrome/browser/net/dns_master.h b/chrome/browser/net/dns_master.h index 0586b1c..29d3278 100644 --- a/chrome/browser/net/dns_master.h +++ b/chrome/browser/net/dns_master.h @@ -18,6 +18,7 @@ #include <queue> #include <set> #include <string> +#include <vector> #include "base/gtest_prod_util.h" #include "base/ref_counted.h" @@ -32,8 +33,9 @@ class HostResolver; namespace chrome_browser_net { +typedef chrome_common_net::UrlList UrlList; typedef chrome_common_net::NameList NameList; -typedef std::map<net::HostPortPair, DnsHostInfo> Results; +typedef std::map<GURL, DnsHostInfo> Results; // Note that DNS master is not thread safe, and must only be called from // the IO thread. Failure to do so will result in a DCHECK at runtime. @@ -41,7 +43,7 @@ class DnsMaster : public base::RefCountedThreadSafe<DnsMaster> { public: // A version number for prefs that are saved. This should be incremented when // we change the format so that we discard old data. - enum {DNS_REFERRER_VERSION = 0 }; + enum { DNS_REFERRER_VERSION = 1 }; // |max_concurrent| specifies how many concurrent (parallel) prefetches will // be performed. Host lookups will be issued through |host_resolver|. @@ -60,24 +62,26 @@ class DnsMaster : public base::RefCountedThreadSafe<DnsMaster> { void DiscardAllResults(); // Add hostname(s) to the queue for processing. - void ResolveList(const NameList& hostnames, + void ResolveList(const UrlList& urls, DnsHostInfo::ResolutionMotivation motivation); - void Resolve(const net::HostPortPair& hostport, + void Resolve(const GURL& url, DnsHostInfo::ResolutionMotivation motivation); // Get latency benefit of the prefetch that we are navigating to. - bool AccruePrefetchBenefits(const net::HostPortPair& referrer, + bool AccruePrefetchBenefits(const GURL& referrer, DnsHostInfo* navigation_info); - // Instigate prefetch of any domains we predict will be needed after this + // Instigate preresolution of any domains we predict will be needed after this // navigation. - void NavigatingTo(const net::HostPortPair& hostport); + void NavigatingTo(const GURL& url); + + // Instigate pre-connection to any URLs we predict will be needed after this + // navigation (typically more-embedded resources on a page). + void NavigatingToFrame(const GURL& url); // Record details of a navigation so that we can preresolve the host name // ahead of time the next time the users navigates to the indicated host. - // TODO(eroman): can this be a const& instead? - void NonlinkNavigation(const net::HostPortPair& referrer, - const DnsHostInfo* navigation_info); + void NonlinkNavigation(const GURL& referring_url, const GURL& target_url); // Dump HTML table containing list of referrers for about:dns. void GetHtmlReferrerLists(std::string* output); @@ -140,17 +144,17 @@ class DnsMaster : public base::RefCountedThreadSafe<DnsMaster> { public: HostNameQueue(); ~HostNameQueue(); - void Push(const net::HostPortPair& hostport, + void Push(const GURL& url, DnsHostInfo::ResolutionMotivation motivation); bool IsEmpty() const; - net::HostPortPair Pop(); + GURL Pop(); private: // The names in the queue that should be serviced (popped) ASAP. - std::queue<net::HostPortPair> rush_queue_; + std::queue<GURL> rush_queue_; // The names in the queue that should only be serviced when rush_queue is // empty. - std::queue<net::HostPortPair> background_queue_; + std::queue<GURL> background_queue_; DISALLOW_COPY_AND_ASSIGN(HostNameQueue); }; @@ -158,39 +162,38 @@ class DnsMaster : public base::RefCountedThreadSafe<DnsMaster> { // A map that is keyed with the host/port that we've learned were the cause // of loading additional URLs. The list of additional targets is held // in a Referrer instance, which is a value in this map. - typedef std::map<net::HostPortPair, Referrer> Referrers; + typedef std::map<GURL, Referrer> Referrers; // Only for testing. Returns true if hostname has been successfully resolved // (name found). - bool WasFound(const net::HostPortPair& hostport) const { - Results::const_iterator it(results_.find(hostport)); + bool WasFound(const GURL& url) const { + Results::const_iterator it(results_.find(url)); return (it != results_.end()) && it->second.was_found(); } // Only for testing. Return how long was the resolution // or DnsHostInfo::kNullDuration if it hasn't been resolved yet. - base::TimeDelta GetResolutionDuration(const net::HostPortPair& hostport) { + base::TimeDelta GetResolutionDuration(const GURL& url) { - if (results_.find(hostport) == results_.end()) + if (results_.find(url) == results_.end()) return DnsHostInfo::kNullDuration; - return results_[hostport].resolve_duration(); + return results_[url].resolve_duration(); } // Only for testing; size_t peak_pending_lookups() const { return peak_pending_lookups_; } // Access method for use by async lookup request to pass resolution result. - void OnLookupFinished(LookupRequest* request, - const net::HostPortPair& hostport, bool found); + void OnLookupFinished(LookupRequest* request, const GURL& url, bool found); // Underlying method for both async and synchronous lookup to update state. void LookupFinished(LookupRequest* request, - const net::HostPortPair& hostport, bool found); + const GURL& url, bool found); // Queue hostname for resolution. If queueing was done, return the pointer // to the queued instance, otherwise return NULL. - DnsHostInfo* AppendToResolutionQueue(const net::HostPortPair& hostport, + DnsHostInfo* AppendToResolutionQueue(const GURL& url, DnsHostInfo::ResolutionMotivation motivation); // Check to see if too much queuing delay has been noted for the given info, diff --git a/chrome/browser/net/dns_master_unittest.cc b/chrome/browser/net/dns_master_unittest.cc index 2699b1f..63323bb 100644 --- a/chrome/browser/net/dns_master_unittest.cc +++ b/chrome/browser/net/dns_master_unittest.cc @@ -32,7 +32,7 @@ typedef base::RepeatingTimer<WaitForResolutionHelper> HelperTimer; class WaitForResolutionHelper { public: - WaitForResolutionHelper(DnsMaster* master, const NameList& hosts, + WaitForResolutionHelper(DnsMaster* master, const UrlList& hosts, HelperTimer* timer) : master_(master), hosts_(hosts), @@ -40,8 +40,8 @@ class WaitForResolutionHelper { } void Run() { - for (NameList::const_iterator i = hosts_.begin(); i != hosts_.end(); ++i) - if (master_->GetResolutionDuration(net::HostPortPair(*i, 80)) == + for (UrlList::const_iterator i = hosts_.begin(); i != hosts_.end(); ++i) + if (master_->GetResolutionDuration(*i) == DnsHostInfo::kNullDuration) return; // We don't have resolution for that host. @@ -54,7 +54,7 @@ class WaitForResolutionHelper { private: DnsMaster* master_; - const NameList hosts_; + const UrlList hosts_; HelperTimer* timer_; }; @@ -82,7 +82,7 @@ class DnsMasterTest : public testing::Test { rules->AddRuleWithLatency("gmail.com", "127.0.0.1", 63); } - void WaitForResolution(DnsMaster* master, const NameList& hosts) { + void WaitForResolution(DnsMaster* master, const UrlList& hosts) { HelperTimer* timer = new HelperTimer(); timer->Start(TimeDelta::FromMilliseconds(100), new WaitForResolutionHelper(master, hosts, timer), @@ -122,17 +122,17 @@ TEST_F(DnsMasterTest, BenefitLookupTest) { DnsGlobalInit::kMaxPrefetchConcurrentLookups, false); - net::HostPortPair goog("www.google.com", 80), - goog2("gmail.google.com.com", 80), - goog3("mail.google.com", 80), - goog4("gmail.com", 80); + GURL goog("http://www.google.com:80"), + goog2("http://gmail.google.com.com:80"), + goog3("http://mail.google.com:80"), + goog4("http://gmail.com:80"); DnsHostInfo goog_info, goog2_info, goog3_info, goog4_info; // Simulate getting similar names from a network observer - goog_info.SetHostname(goog); - goog2_info.SetHostname(goog2); - goog3_info.SetHostname(goog3); - goog4_info.SetHostname(goog4); + goog_info.SetUrl(goog); + goog2_info.SetUrl(goog2); + goog3_info.SetUrl(goog3); + goog4_info.SetUrl(goog4); goog_info.SetStartedState(); goog2_info.SetStartedState(); @@ -144,11 +144,11 @@ TEST_F(DnsMasterTest, BenefitLookupTest) { goog3_info.SetFinishedState(true); goog4_info.SetFinishedState(true); - NameList names; - names.push_back(goog.host); - names.push_back(goog2.host); - names.push_back(goog3.host); - names.push_back(goog4.host); + UrlList names; + names.push_back(goog); + names.push_back(goog2); + names.push_back(goog3); + names.push_back(goog4); testing_master->ResolveList(names, DnsHostInfo::PAGE_SCAN_MOTIVATED); @@ -162,7 +162,7 @@ TEST_F(DnsMasterTest, BenefitLookupTest) { // With the mock DNS, each of these should have taken some time, and hence // shown a benefit (i.e., prefetch cost more than network access time). - net::HostPortPair referer; // Null host. + GURL referer; // Null host. // Simulate actual navigation, and acrue the benefit for "helping" the DNS // part of the navigation. @@ -190,9 +190,9 @@ TEST_F(DnsMasterTest, ShutdownWhenResolutionIsPendingTest) { DnsGlobalInit::kMaxPrefetchConcurrentLookups, false); - net::HostPortPair localhost("127.0.0.1", 80); - NameList names; - names.push_back(localhost.host); + GURL localhost("http://127.0.0.1:80"); + UrlList names; + names.push_back(localhost); testing_master->ResolveList(names, DnsHostInfo::PAGE_SCAN_MOTIVATED); @@ -215,10 +215,10 @@ TEST_F(DnsMasterTest, SingleLookupTest) { DnsGlobalInit::kMaxPrefetchConcurrentLookups, false); - net::HostPortPair goog("www.google.com", 80); + GURL goog("http://www.google.com:80"); - NameList names; - names.push_back(goog.host); + UrlList names; + names.push_back(goog); // Try to flood the master with many concurrent requests. for (int i = 0; i < 10; i++) @@ -246,21 +246,21 @@ TEST_F(DnsMasterTest, ConcurrentLookupTest) { DnsGlobalInit::kMaxPrefetchConcurrentLookups, false); - net::HostPortPair goog("www.google.com", 80), - goog2("gmail.google.com.com", 80), - goog3("mail.google.com", 80), - goog4("gmail.com", 80); - net::HostPortPair bad1("bad1.notfound", 80), - bad2("bad2.notfound", 80); - - NameList names; - names.push_back(goog.host); - names.push_back(goog3.host); - names.push_back(bad1.host); - names.push_back(goog2.host); - names.push_back(bad2.host); - names.push_back(goog4.host); - names.push_back(goog.host); + GURL goog("http://www.google.com:80"), + goog2("http://gmail.google.com.com:80"), + goog3("http://mail.google.com:80"), + goog4("http://gmail.com:80"); + GURL bad1("http://bad1.notfound:80"), + bad2("http://bad2.notfound:80"); + + UrlList names; + names.push_back(goog); + names.push_back(goog3); + names.push_back(bad1); + names.push_back(goog2); + names.push_back(bad2); + names.push_back(goog4); + names.push_back(goog); // Try to flood the master with many concurrent requests. for (int i = 0; i < 10; i++) @@ -297,9 +297,9 @@ TEST_F(DnsMasterTest, MassiveConcurrentLookupTest) { DnsGlobalInit::kMaxPrefetchConcurrentLookups, false); - NameList names; + UrlList names; for (int i = 0; i < 100; i++) - names.push_back("host" + IntToString(i) + ".notfound"); + names.push_back(GURL("http://host" + IntToString(i) + ".notfound:80")); // Try to flood the master with many concurrent requests. for (int i = 0; i < 10; i++) @@ -323,7 +323,7 @@ TEST_F(DnsMasterTest, MassiveConcurrentLookupTest) { // Return a motivation_list if we can find one for the given motivating_host (or // NULL if a match is not found). static ListValue* FindSerializationMotivation( - const net::HostPortPair& motivation, const ListValue& referral_list) { + const GURL& motivation, const ListValue& referral_list) { CHECK_LT(0u, referral_list.GetSize()); // Room for version. int format_version = -1; CHECK(referral_list.GetInteger(0, &format_version)); @@ -331,11 +331,9 @@ static ListValue* FindSerializationMotivation( ListValue* motivation_list(NULL); for (size_t i = 1; i < referral_list.GetSize(); ++i) { referral_list.GetList(i, &motivation_list); - std::string existing_host; - int existing_port; - EXPECT_TRUE(motivation_list->GetInteger(0, &existing_port)); - EXPECT_TRUE(motivation_list->GetString(1, &existing_host)); - if (motivation.host == existing_host && motivation.port == existing_port) + std::string existing_spec; + EXPECT_TRUE(motivation_list->GetString(0, &existing_spec)); + if (motivation == GURL(existing_spec)) return motivation_list; } return NULL; @@ -351,8 +349,8 @@ static ListValue* NewEmptySerializationList() { // Add a motivating_host and a subresource_host to a serialized list, using // this given latency. This is a helper function for quickly building these // lists. -static void AddToSerializedList(const net::HostPortPair& motivation, - const net::HostPortPair& subresource, +static void AddToSerializedList(const GURL& motivation, + const GURL& subresource, int latency, double rate, ListValue* referral_list ) { @@ -362,8 +360,7 @@ static void AddToSerializedList(const net::HostPortPair& motivation, if (!motivation_list) { // This is the first mention of this motivation, so build a list. motivation_list = new ListValue; - motivation_list->Append(new FundamentalValue(motivation.port)); - motivation_list->Append(new StringValue(motivation.host)); + motivation_list->Append(new StringValue(motivation.spec())); // Provide empty subresource list. motivation_list->Append(new ListValue()); @@ -372,15 +369,14 @@ static void AddToSerializedList(const net::HostPortPair& motivation, } ListValue* subresource_list(NULL); - // 0 == port; 1 == host; 2 == subresource_list. - EXPECT_TRUE(motivation_list->GetList(2, &subresource_list)); + // 0 == url; 1 == subresource_list. + EXPECT_TRUE(motivation_list->GetList(1, &subresource_list)); // We won't bother to check for the subresource being there already. Worst // case, during deserialization, the latency value we supply plus the // existing value(s) will be added to the referrer. - subresource_list->Append(new FundamentalValue(subresource.port)); - subresource_list->Append(new StringValue(subresource.host)); + subresource_list->Append(new StringValue(subresource.spec())); subresource_list->Append(new FundamentalValue(latency)); subresource_list->Append(new FundamentalValue(rate)); } @@ -391,8 +387,8 @@ static const int kLatencyNotFound = -1; // listed. This assume a well formed serialization, which has at most one such // entry for any pair of names. If no such pair is found, then return false. // Data is written into rate and latency arguments. -static bool GetDataFromSerialization(const net::HostPortPair& motivation, - const net::HostPortPair& subresource, +static bool GetDataFromSerialization(const GURL& motivation, + const GURL& subresource, const ListValue& referral_list, double* rate, int* latency) { @@ -401,15 +397,13 @@ static bool GetDataFromSerialization(const net::HostPortPair& motivation, if (!motivation_list) return false; ListValue* subresource_list; - EXPECT_TRUE(motivation_list->GetList(2, &subresource_list)); + EXPECT_TRUE(motivation_list->GetList(1, &subresource_list)); for (size_t i = 0; i < subresource_list->GetSize();) { - std::string host; - int port; - EXPECT_TRUE(subresource_list->GetInteger(i++, &port)); - EXPECT_TRUE(subresource_list->GetString(i++, &host)); + std::string url_spec; + EXPECT_TRUE(subresource_list->GetString(i++, &url_spec)); EXPECT_TRUE(subresource_list->GetInteger(i++, latency)); EXPECT_TRUE(subresource_list->GetReal(i++, rate)); - if (subresource.host == host && subresource.port == port) { + if (subresource == GURL(url_spec)) { return true; } } @@ -428,7 +422,7 @@ TEST_F(DnsMasterTest, ReferrerSerializationNilTest) { master->SerializeReferrers(referral_list.get()); EXPECT_EQ(1U, referral_list->GetSize()); EXPECT_FALSE(GetDataFromSerialization( - net::HostPortPair("a.com", 79), net::HostPortPair("b.com", 78), + GURL("http://a.com:79"), GURL("http://b.com:78"), *referral_list.get(), NULL, NULL)); master->Shutdown(); @@ -442,13 +436,13 @@ TEST_F(DnsMasterTest, ReferrerSerializationSingleReferrerTest) { default_max_queueing_delay_, DnsGlobalInit::kMaxPrefetchConcurrentLookups, false); - const net::HostPortPair motivation_hostport("www.google.com", 91); - const net::HostPortPair subresource_hostport("icons.google.com", 90); + const GURL motivation_url("http://www.google.com:91"); + const GURL subresource_url("http://icons.google.com:90"); const int kLatency = 3; const double kRate = 23.4; scoped_ptr<ListValue> referral_list(NewEmptySerializationList()); - AddToSerializedList(motivation_hostport, subresource_hostport, + AddToSerializedList(motivation_url, subresource_url, kLatency, kRate, referral_list.get()); master->DeserializeReferrers(*referral_list.get()); @@ -459,7 +453,7 @@ TEST_F(DnsMasterTest, ReferrerSerializationSingleReferrerTest) { int latency; double rate; EXPECT_TRUE(GetDataFromSerialization( - motivation_hostport, subresource_hostport, recovered_referral_list, &rate, + motivation_url, subresource_url, recovered_referral_list, &rate, &latency)); EXPECT_EQ(rate, kRate); EXPECT_EQ(latency, kLatency); @@ -473,21 +467,21 @@ TEST_F(DnsMasterTest, ReferrerSerializationTrimTest) { default_max_queueing_delay_, DnsGlobalInit::kMaxPrefetchConcurrentLookups, false); - net::HostPortPair motivation_hostport("www.google.com", 110); + GURL motivation_url("http://www.google.com:110"); - net::HostPortPair icon_subresource_hostport("icons.google.com", 111); + GURL icon_subresource_url("http://icons.google.com:111"); const int kLatencyIcon = 10; const double kRateIcon = 0.; // User low rate, so latency will dominate. - net::HostPortPair img_subresource_hostport("img.google.com", 118); + GURL img_subresource_url("http://img.google.com:118"); const int kLatencyImg = 3; const double kRateImg = 0.; scoped_ptr<ListValue> referral_list(NewEmptySerializationList()); AddToSerializedList( - motivation_hostport, icon_subresource_hostport, + motivation_url, icon_subresource_url, kLatencyIcon, kRateIcon, referral_list.get()); AddToSerializedList( - motivation_hostport, img_subresource_hostport, + motivation_url, img_subresource_url, kLatencyImg, kRateImg, referral_list.get()); master->DeserializeReferrers(*referral_list.get()); @@ -498,13 +492,13 @@ TEST_F(DnsMasterTest, ReferrerSerializationTrimTest) { int latency; double rate; EXPECT_TRUE(GetDataFromSerialization( - motivation_hostport, icon_subresource_hostport, recovered_referral_list, + motivation_url, icon_subresource_url, recovered_referral_list, &rate, &latency)); EXPECT_EQ(latency, kLatencyIcon); EXPECT_EQ(rate, kRateIcon); EXPECT_TRUE(GetDataFromSerialization( - motivation_hostport, img_subresource_hostport, recovered_referral_list, + motivation_url, img_subresource_url, recovered_referral_list, &rate, &latency)); EXPECT_EQ(latency, kLatencyImg); EXPECT_EQ(rate, kRateImg); @@ -515,13 +509,13 @@ TEST_F(DnsMasterTest, ReferrerSerializationTrimTest) { master->SerializeReferrers(&recovered_referral_list); EXPECT_EQ(2U, recovered_referral_list.GetSize()); EXPECT_TRUE(GetDataFromSerialization( - motivation_hostport, icon_subresource_hostport, recovered_referral_list, + motivation_url, icon_subresource_url, recovered_referral_list, &rate, &latency)); EXPECT_EQ(latency, kLatencyIcon / 2); EXPECT_EQ(rate, kRateIcon); EXPECT_TRUE(GetDataFromSerialization( - motivation_hostport, img_subresource_hostport, recovered_referral_list, + motivation_url, img_subresource_url, recovered_referral_list, &rate, &latency)); EXPECT_EQ(latency, kLatencyImg / 2); EXPECT_EQ(rate, kRateImg); @@ -530,13 +524,13 @@ TEST_F(DnsMasterTest, ReferrerSerializationTrimTest) { master->SerializeReferrers(&recovered_referral_list); EXPECT_EQ(2U, recovered_referral_list.GetSize()); EXPECT_TRUE(GetDataFromSerialization( - motivation_hostport, icon_subresource_hostport, recovered_referral_list, + motivation_url, icon_subresource_url, recovered_referral_list, &rate, &latency)); EXPECT_EQ(latency, kLatencyIcon / 4); EXPECT_EQ(rate, kRateIcon); // Img is down to zero, but we don't delete it yet. EXPECT_TRUE(GetDataFromSerialization( - motivation_hostport, img_subresource_hostport, recovered_referral_list, + motivation_url, img_subresource_url, recovered_referral_list, &rate, &latency)); EXPECT_EQ(kLatencyImg / 4, 0); EXPECT_EQ(latency, kLatencyImg / 4); @@ -546,14 +540,14 @@ TEST_F(DnsMasterTest, ReferrerSerializationTrimTest) { master->SerializeReferrers(&recovered_referral_list); EXPECT_EQ(2U, recovered_referral_list.GetSize()); EXPECT_TRUE(GetDataFromSerialization( - motivation_hostport, icon_subresource_hostport, recovered_referral_list, + motivation_url, icon_subresource_url, recovered_referral_list, &rate, &latency)); EXPECT_EQ(latency, kLatencyIcon / 8); EXPECT_EQ(rate, kRateIcon); // Img is down to zero, but we don't delete it yet. EXPECT_TRUE(GetDataFromSerialization( - motivation_hostport, img_subresource_hostport, recovered_referral_list, + motivation_url, img_subresource_url, recovered_referral_list, &rate, &latency)); EXPECT_EQ(kLatencyImg / 8, 0); EXPECT_EQ(latency, kLatencyImg / 8); @@ -564,10 +558,10 @@ TEST_F(DnsMasterTest, ReferrerSerializationTrimTest) { // Icon is also trimmed away, so entire set gets discarded. EXPECT_EQ(1U, recovered_referral_list.GetSize()); EXPECT_FALSE(GetDataFromSerialization( - motivation_hostport, icon_subresource_hostport, recovered_referral_list, + motivation_url, icon_subresource_url, recovered_referral_list, &rate, &latency)); EXPECT_FALSE(GetDataFromSerialization( - motivation_hostport, img_subresource_hostport, recovered_referral_list, + motivation_url, img_subresource_url, recovered_referral_list, &rate, &latency)); master->Shutdown(); @@ -577,7 +571,7 @@ TEST_F(DnsMasterTest, ReferrerSerializationTrimTest) { TEST_F(DnsMasterTest, PriorityQueuePushPopTest) { DnsMaster::HostNameQueue queue; - net::HostPortPair first("first", 80), second("second", 90); + GURL first("http://first:80"), second("http://second:90"); // First check high priority queue FIFO functionality. EXPECT_TRUE(queue.IsEmpty()); @@ -585,9 +579,9 @@ TEST_F(DnsMasterTest, PriorityQueuePushPopTest) { EXPECT_FALSE(queue.IsEmpty()); queue.Push(second, DnsHostInfo::MOUSE_OVER_MOTIVATED); EXPECT_FALSE(queue.IsEmpty()); - EXPECT_EQ(queue.Pop().ToString(), first.ToString()); + EXPECT_EQ(queue.Pop(), first); EXPECT_FALSE(queue.IsEmpty()); - EXPECT_EQ(queue.Pop().ToString(), second.ToString()); + EXPECT_EQ(queue.Pop(), second); EXPECT_TRUE(queue.IsEmpty()); // Then check low priority queue FIFO functionality. @@ -595,9 +589,9 @@ TEST_F(DnsMasterTest, PriorityQueuePushPopTest) { EXPECT_FALSE(queue.IsEmpty()); queue.Push(second, DnsHostInfo::OMNIBOX_MOTIVATED); EXPECT_FALSE(queue.IsEmpty()); - EXPECT_EQ(queue.Pop().ToString(), first.ToString()); + EXPECT_EQ(queue.Pop(), first); EXPECT_FALSE(queue.IsEmpty()); - EXPECT_EQ(queue.Pop().ToString(), second.ToString()); + EXPECT_EQ(queue.Pop(), second); EXPECT_TRUE(queue.IsEmpty()); } @@ -605,14 +599,14 @@ TEST_F(DnsMasterTest, PriorityQueueReorderTest) { DnsMaster::HostNameQueue queue; // Push all the low priority items. - net::HostPortPair low1("low1", 80), - low2("low2", 80), - low3("low3", 443), - low4("low4", 80), - low5("low5", 80), - hi1("hi1", 80), - hi2("hi2", 80), - hi3("hi3", 80); + GURL low1("http://low1:80"), + low2("http://low2:80"), + low3("http://low3:443"), + low4("http://low4:80"), + low5("http://low5:80"), + hi1("http://hi1:80"), + hi2("http://hi2:80"), + hi3("http://hi3:80"); EXPECT_TRUE(queue.IsEmpty()); queue.Push(low1, DnsHostInfo::PAGE_SCAN_MOTIVATED); @@ -628,17 +622,17 @@ TEST_F(DnsMasterTest, PriorityQueueReorderTest) { queue.Push(hi3, DnsHostInfo::MOUSE_OVER_MOTIVATED); // Check that high priority stuff comes out first, and in FIFO order. - EXPECT_EQ(queue.Pop().ToString(), hi1.ToString()); - EXPECT_EQ(queue.Pop().ToString(), hi2.ToString()); - EXPECT_EQ(queue.Pop().ToString(), hi3.ToString()); + EXPECT_EQ(queue.Pop(), hi1); + EXPECT_EQ(queue.Pop(), hi2); + EXPECT_EQ(queue.Pop(), hi3); // ...and then low priority strings. - EXPECT_EQ(queue.Pop().ToString(), low1.ToString()); - EXPECT_EQ(queue.Pop().ToString(), low2.ToString()); - EXPECT_EQ(queue.Pop().ToString(), low3.ToString()); - EXPECT_EQ(queue.Pop().ToString(), low4.ToString()); - EXPECT_EQ(queue.Pop().ToString(), low5.ToString()); - EXPECT_EQ(queue.Pop().ToString(), low4.ToString()); + EXPECT_EQ(queue.Pop(), low1); + EXPECT_EQ(queue.Pop(), low2); + EXPECT_EQ(queue.Pop(), low3); + EXPECT_EQ(queue.Pop(), low4); + EXPECT_EQ(queue.Pop(), low5); + EXPECT_EQ(queue.Pop(), low4); EXPECT_TRUE(queue.IsEmpty()); } diff --git a/chrome/browser/net/preconnect.cc b/chrome/browser/net/preconnect.cc index ff200de..c4c7c97 100644 --- a/chrome/browser/net/preconnect.cc +++ b/chrome/browser/net/preconnect.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// 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. @@ -20,7 +20,7 @@ namespace chrome_browser_net { Preconnect* Preconnect::callback_instance_; // static -bool Preconnect::PreconnectOnUIThread(const net::HostPortPair& hostport) { +bool Preconnect::PreconnectOnUIThread(const GURL& url) { // Try to do connection warming for this search provider. URLRequestContextGetter* getter = Profile::GetDefaultRequestContext(); if (!getter) @@ -29,12 +29,12 @@ bool Preconnect::PreconnectOnUIThread(const net::HostPortPair& hostport) { ChromeThread::PostTask( ChromeThread::IO, FROM_HERE, - NewRunnableFunction(Preconnect::PreconnectOnIOThread, hostport)); + NewRunnableFunction(Preconnect::PreconnectOnIOThread, url)); return true; } // static -void Preconnect::PreconnectOnIOThread(const net::HostPortPair& hostport) { +void Preconnect::PreconnectOnIOThread(const GURL& url) { URLRequestContextGetter* getter = Profile::GetDefaultRequestContext(); if (!getter) return; @@ -47,7 +47,7 @@ void Preconnect::PreconnectOnIOThread(const net::HostPortPair& hostport) { net::HttpNetworkSession* session = factory->GetSession(); scoped_refptr<net::TCPClientSocketPool> pool = session->tcp_socket_pool(); - net::TCPSocketParams params(hostport.host, hostport.port, net::LOW, + net::TCPSocketParams params(url.host(), url.EffectiveIntPort(), net::LOW, GURL(), false); net::ClientSocketHandle handle; @@ -55,7 +55,7 @@ void Preconnect::PreconnectOnIOThread(const net::HostPortPair& hostport) { callback_instance_ = new Preconnect; // TODO(jar): This does not handle proxies currently. - handle.Init(hostport.ToString() , params, net::LOWEST, + handle.Init(url.spec(), params, net::LOWEST, callback_instance_, pool, net::BoundNetLog()); handle.Reset(); } diff --git a/chrome/browser/net/preconnect.h b/chrome/browser/net/preconnect.h index d4fb0dd..5251c05 100644 --- a/chrome/browser/net/preconnect.h +++ b/chrome/browser/net/preconnect.h @@ -19,9 +19,9 @@ namespace chrome_browser_net { class Preconnect : public net::CompletionCallback { public: - static bool PreconnectOnUIThread(const net::HostPortPair& hostport); + static bool PreconnectOnUIThread(const GURL& url); - static void PreconnectOnIOThread(const net::HostPortPair& hostport); + static void PreconnectOnIOThread(const GURL& url); private: Preconnect() {} diff --git a/chrome/browser/net/referrer.cc b/chrome/browser/net/referrer.cc index 736790a..936d25b 100644 --- a/chrome/browser/net/referrer.cc +++ b/chrome/browser/net/referrer.cc @@ -44,7 +44,7 @@ static const double kInitialExpectedValue = 0.0; // static bool Referrer::use_preconnect_valuations_ = false; -void Referrer::SuggestHost(const net::HostPortPair& hostport) { +void Referrer::SuggestHost(const GURL& url) { // Limit how large our list can get, in case we make mistakes about what // hostnames are in sub-resources (example: Some advertisments have a link to // the ad agency, and then provide a "surprising" redirect to the advertised @@ -53,9 +53,10 @@ void Referrer::SuggestHost(const net::HostPortPair& hostport) { // TODO(jar): Do experiments to optimize the max count of suggestions. static const size_t kMaxSuggestions = 10; - if (hostport.host.empty()) // Is this really needed???? + if (!url.has_host()) // TODO(jar): Is this really needed???? return; - SubresourceMap::iterator it = find(hostport); + DCHECK(url == url.GetWithEmptyPath()); + SubresourceMap::iterator it = find(url); if (it != end()) { it->second.SubresourceIsNeeded(); return; @@ -65,13 +66,13 @@ void Referrer::SuggestHost(const net::HostPortPair& hostport) { DeleteLeastUseful(); DCHECK(kMaxSuggestions > size()); } - (*this)[hostport].SubresourceIsNeeded(); + (*this)[url].SubresourceIsNeeded(); } void Referrer::DeleteLeastUseful() { // Find the item with the lowest value. Most important is preconnection_rate, // next is latency savings, and last is lifetime (age). - net::HostPortPair least_useful_hostport; + GURL least_useful_url; double lowest_rate_seen = 0.0; // We use longs for durations because we will use multiplication on them. int64 lowest_latency_seen = 0; // Duration in milliseconds. @@ -82,7 +83,7 @@ void Referrer::DeleteLeastUseful() { int64 lifetime = (kNow - it->second.birth_time()).InMilliseconds(); int64 latency = it->second.latency().InMilliseconds(); double rate = it->second.subresource_use_rate(); - if (!least_useful_hostport.host.empty()) { + if (least_useful_url.has_host()) { if (rate > lowest_rate_seen) continue; if (!latency && !lowest_latency_seen) { @@ -102,21 +103,21 @@ void Referrer::DeleteLeastUseful() { } } } - least_useful_hostport = it->first; + least_useful_url = it->first; lowest_rate_seen = rate; lowest_latency_seen = latency; least_useful_lifetime = lifetime; } - erase(least_useful_hostport); - // Note: there is a small chance that we will discard a least_useful_hostport + erase(least_useful_url); + // Note: there is a small chance that we will discard a least_useful_url // that is currently being prefetched because it *was* in this referer list. // In that case, when a benefit appears in AccrueValue() below, we are careful // to check before accessing the member. } void Referrer::AccrueValue(const base::TimeDelta& delta, - const net::HostPortPair& hostport) { - SubresourceMap::iterator it = find(hostport); + const GURL& url) { + SubresourceMap::iterator it = find(url); // Be careful that we weren't evicted from this referrer in DeleteLeastUseful. if (it != end()) it->second.AccrueValue(delta); @@ -144,11 +145,8 @@ void Referrer::Deserialize(const Value& value) { const ListValue* subresource_list(static_cast<const ListValue*>(&value)); size_t index = 0; // Bounds checking is done by subresource_list->Get*(). while (true) { - int port; - if (!subresource_list->GetInteger(index++, &port)) - return; - std::string host; - if (!subresource_list->GetString(index++, &host)) + std::string url_spec; + if (!subresource_list->GetString(index++, &url_spec)) return; int latency_ms; if (!subresource_list->GetInteger(index++, &latency_ms)) @@ -157,24 +155,23 @@ void Referrer::Deserialize(const Value& value) { if (!subresource_list->GetReal(index++, &rate)) return; - net::HostPortPair hostport(host, port); + GURL url(url_spec); base::TimeDelta latency = base::TimeDelta::FromMilliseconds(latency_ms); // TODO(jar): We could be more direct, and change birth date or similar to // show that this is a resurrected value we're adding in. I'm not yet sure // of how best to optimize the learning and pruning (Trim) algorithm at this // level, so for now, we just suggest subresources, which leaves them all // with the same birth date (typically start of process). - SuggestHost(hostport); - AccrueValue(latency, hostport); - (*this)[hostport].SetSubresourceUseRate(rate); + SuggestHost(url); + AccrueValue(latency, url); + (*this)[url].SetSubresourceUseRate(rate); } } Value* Referrer::Serialize() const { ListValue* subresource_list(new ListValue); for (const_iterator it = begin(); it != end(); ++it) { - FundamentalValue* port(new FundamentalValue(it->first.port)); - StringValue* host(new StringValue(it->first.host)); + StringValue* url_spec(new StringValue(it->first.spec())); int latency_integer = static_cast<int>(it->second.latency(). InMilliseconds()); // Watch out for overflow in the above static_cast! Check to see if we went @@ -188,8 +185,7 @@ Value* Referrer::Serialize() const { FundamentalValue* rate(new FundamentalValue( it->second.subresource_use_rate())); - subresource_list->Append(port); - subresource_list->Append(host); + subresource_list->Append(url_spec); subresource_list->Append(latency); subresource_list->Append(rate); } diff --git a/chrome/browser/net/referrer.h b/chrome/browser/net/referrer.h index bef13a1..8b98a5c 100644 --- a/chrome/browser/net/referrer.h +++ b/chrome/browser/net/referrer.h @@ -20,6 +20,7 @@ #include "base/basictypes.h" #include "base/time.h" #include "base/values.h" +#include "googleurl/src/gurl.h" #include "net/base/host_port_pair.h" namespace chrome_browser_net { @@ -74,7 +75,7 @@ class ReferrerValue { // A list of domain names to pre-resolve. The names are the keys to this map, // and the values indicate the amount of benefit derived from having each name // around. -typedef std::map<net::HostPortPair, ReferrerValue> SubresourceMap; +typedef std::map<GURL, ReferrerValue> SubresourceMap; //------------------------------------------------------------------------------ // There is one Referrer instance for each hostname that has acted as an HTTP @@ -91,15 +92,15 @@ class Referrer : public SubresourceMap { void IncrementUseCount() { ++use_count_; } int64 use_count() const { return use_count_; } - // Add the indicated host/port to the list of hosts that are resolved via DNS - // when the user navigates to this referrer. Note that if the list is long, - // an entry may be discarded to make room for this insertion. - void SuggestHost(const net::HostPortPair& hostport); + // Add the indicated url to the list that are resolved via DNS when the user + // navigates to this referrer. Note that if the list is long, an entry may be + // discarded to make room for this insertion. + void SuggestHost(const GURL& url); - // Record additional usefulness of having this host/port name in the list. + // Record additional usefulness of having this url in the list. // Value is expressed as positive latency of amount delta. void AccrueValue(const base::TimeDelta& delta, - const net::HostPortPair& hostport); + const GURL& url); // Trim the Referrer, by first diminishing (scaling down) the latency for each // ReferredValue. |