summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/autocomplete/autocomplete_edit.cc9
-rw-r--r--chrome/browser/autofill/autofill_browsertest.cc1
-rw-r--r--chrome/browser/browser_about_handler.cc10
-rw-r--r--chrome/browser/browser_process_impl.cc1
-rw-r--r--chrome/browser/browser_shutdown.cc5
-rw-r--r--chrome/browser/browsing_data_remover.cc9
-rw-r--r--chrome/browser/chrome_browser_main.cc99
-rw-r--r--chrome/browser/chrome_browser_main.h4
-rw-r--r--chrome/browser/chrome_content_browser_client.cc8
-rw-r--r--chrome/browser/io_thread.cc99
-rw-r--r--chrome/browser/io_thread.h52
-rw-r--r--chrome/browser/net/connect_interceptor.cc33
-rw-r--r--chrome/browser/net/connect_interceptor.h30
-rw-r--r--chrome/browser/net/net_pref_observer.cc12
-rw-r--r--chrome/browser/net/net_pref_observer.h8
-rw-r--r--chrome/browser/net/predictor.cc932
-rw-r--r--chrome/browser/net/predictor.h250
-rw-r--r--chrome/browser/net/predictor_unittest.cc191
-rw-r--r--chrome/browser/prefs/browser_prefs.cc4
-rw-r--r--chrome/browser/profiles/profile.cc4
-rw-r--r--chrome/browser/profiles/profile.h6
-rw-r--r--chrome/browser/profiles/profile_impl.cc22
-rw-r--r--chrome/browser/profiles/profile_impl.h3
-rw-r--r--chrome/browser/profiles/profile_impl_io_data.cc35
-rw-r--r--chrome/browser/profiles/profile_impl_io_data.h11
-rw-r--r--chrome/browser/renderer_host/chrome_render_message_filter.cc9
-rw-r--r--chrome/browser/renderer_host/chrome_render_view_host_observer.cc13
-rw-r--r--chrome/browser/renderer_host/chrome_render_view_host_observer.h9
-rw-r--r--chrome/browser/ui/browser_init.cc8
-rw-r--r--chrome/chrome_browser.gypi2
30 files changed, 1251 insertions, 628 deletions
diff --git a/chrome/browser/autocomplete/autocomplete_edit.cc b/chrome/browser/autocomplete/autocomplete_edit.cc
index b4950e8..8c4958e 100644
--- a/chrome/browser/autocomplete/autocomplete_edit.cc
+++ b/chrome/browser/autocomplete/autocomplete_edit.cc
@@ -22,7 +22,7 @@
#include "chrome/browser/extensions/extension_omnibox_api.h"
#include "chrome/browser/google/google_url_tracker.h"
#include "chrome/browser/instant/instant_controller.h"
-#include "chrome/browser/net/predictor_api.h"
+#include "chrome/browser/net/predictor.h"
#include "chrome/browser/net/url_fixer_upper.h"
#include "chrome/browser/prerender/prerender_manager.h"
#include "chrome/browser/profiles/profile.h"
@@ -1035,8 +1035,11 @@ void AutocompleteEditModel::DoPreconnect(const AutocompleteMatch& match) {
// Warm up DNS Prefetch cache, or preconnect to a search service.
UMA_HISTOGRAM_ENUMERATION("Autocomplete.MatchType", match.type,
AutocompleteMatch::NUM_TYPES);
- chrome_browser_net::AnticipateOmniboxUrl(match.destination_url,
- NetworkActionPredictor::IsPreconnectable(match));
+ if (profile_->GetNetworkPredictor()) {
+ profile_->GetNetworkPredictor()->AnticipateOmniboxUrl(
+ match.destination_url,
+ NetworkActionPredictor::IsPreconnectable(match));
+ }
// We could prefetch the alternate nav URL, if any, but because there
// can be many of these as a user types an initial series of characters,
// the OS DNS cache could suffer eviction problems for minimal gain.
diff --git a/chrome/browser/autofill/autofill_browsertest.cc b/chrome/browser/autofill/autofill_browsertest.cc
index 16bdb70..7d45bb0 100644
--- a/chrome/browser/autofill/autofill_browsertest.cc
+++ b/chrome/browser/autofill/autofill_browsertest.cc
@@ -13,7 +13,6 @@
#include "chrome/browser/autofill/autofill_profile.h"
#include "chrome/browser/autofill/personal_data_manager.h"
#include "chrome/browser/infobars/infobar_tab_helper.h"
-#include "chrome/browser/net/predictor_api.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/translate/translate_infobar_delegate.h"
#include "chrome/browser/translate/translate_manager.h"
diff --git a/chrome/browser/browser_about_handler.cc b/chrome/browser/browser_about_handler.cc
index aeb75e5..1574cf5 100644
--- a/chrome/browser/browser_about_handler.cc
+++ b/chrome/browser/browser_about_handler.cc
@@ -30,7 +30,7 @@
#include "chrome/browser/defaults.h"
#include "chrome/browser/memory_details.h"
#include "chrome/browser/metrics/histogram_synchronizer.h"
-#include "chrome/browser/net/predictor_api.h"
+#include "chrome/browser/net/predictor.h"
#include "chrome/browser/net/url_fixer_upper.h"
#include "chrome/browser/plugin_prefs.h"
#include "chrome/browser/profiles/profile.h"
@@ -726,18 +726,20 @@ class AboutDnsHandler : public base::RefCountedThreadSafe<AboutDnsHandler> {
// Calls FinishOnUIThread() on completion.
void StartOnUIThread() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ chrome_browser_net::Predictor* predictor =
+ source_->profile()->GetNetworkPredictor();
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
- NewRunnableMethod(this, &AboutDnsHandler::StartOnIOThread));
+ NewRunnableMethod(this, &AboutDnsHandler::StartOnIOThread, predictor));
}
- void StartOnIOThread() {
+ void StartOnIOThread(chrome_browser_net::Predictor* predictor) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
std::string data;
AppendHeader(&data, 0, "About DNS");
AppendBody(&data);
- chrome_browser_net::PredictorGetHtmlInfo(&data);
+ chrome_browser_net::Predictor::PredictorGetHtmlInfo(predictor, &data);
AppendFooter(&data);
BrowserThread::PostTask(
diff --git a/chrome/browser/browser_process_impl.cc b/chrome/browser/browser_process_impl.cc
index a66a818..e2a5544 100644
--- a/chrome/browser/browser_process_impl.cc
+++ b/chrome/browser/browser_process_impl.cc
@@ -37,7 +37,6 @@
#include "chrome/browser/metrics/metrics_service.h"
#include "chrome/browser/metrics/thread_watcher.h"
#include "chrome/browser/net/chrome_net_log.h"
-#include "chrome/browser/net/predictor_api.h"
#include "chrome/browser/net/sdch_dictionary_fetcher.h"
#include "chrome/browser/notifications/notification_ui_manager.h"
#include "chrome/browser/policy/browser_policy_connector.h"
diff --git a/chrome/browser/browser_shutdown.cc b/chrome/browser/browser_shutdown.cc
index 92683fe..c18d22f 100644
--- a/chrome/browser/browser_shutdown.cc
+++ b/chrome/browser/browser_shutdown.cc
@@ -38,7 +38,6 @@
#include "content/browser/renderer_host/render_process_host.h"
#include "content/browser/renderer_host/render_view_host.h"
#include "content/browser/renderer_host/render_widget_host.h"
-#include "net/predictor_api.h"
#include "ui/base/resource/resource_bundle.h"
#if defined(OS_WIN)
@@ -140,10 +139,6 @@ void Shutdown() {
// time to get here. If you have something that *must* happen on end session,
// consider putting it in BrowserProcessImpl::EndSession.
PrefService* prefs = g_browser_process->local_state();
- ProfileManager* profile_manager = g_browser_process->profile_manager();
- PrefService* user_prefs = profile_manager->GetDefaultProfile()->GetPrefs();
-
- chrome_browser_net::SavePredictorStateForNextStartupAndTrim(user_prefs);
MetricsService* metrics = g_browser_process->metrics_service();
if (metrics)
diff --git a/chrome/browser/browsing_data_remover.cc b/chrome/browser/browsing_data_remover.cc
index b759d1d..92c4d9d 100644
--- a/chrome/browser/browsing_data_remover.cc
+++ b/chrome/browser/browsing_data_remover.cc
@@ -20,6 +20,7 @@
#include "chrome/browser/io_thread.h"
#include "chrome/browser/net/chrome_net_log.h"
#include "chrome/browser/net/chrome_url_request_context.h"
+#include "chrome/browser/net/predictor.h"
#include "chrome/browser/password_manager/password_store.h"
#include "chrome/browser/plugin_data_remover.h"
#include "chrome/browser/prefs/pref_member.h"
@@ -388,7 +389,13 @@ void BrowsingDataRemover::ClearNetworkingHistory(IOThread* io_thread) {
// This function should be called on the IO thread.
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- io_thread->ClearNetworkingHistory();
+ io_thread->ClearHostCache();
+
+ chrome_browser_net::Predictor* predictor = profile_->GetNetworkPredictor();
+ if (predictor) {
+ predictor->DiscardInitialNavigationHistory();
+ predictor->DiscardAllResults();
+ }
// Notify the UI thread that we are done.
BrowserThread::PostTask(
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc
index e503636..52c860d 100644
--- a/chrome/browser/chrome_browser_main.cc
+++ b/chrome/browser/chrome_browser_main.cc
@@ -51,7 +51,7 @@
#include "chrome/browser/net/chrome_dns_cert_provenance_checker.h"
#include "chrome/browser/net/chrome_dns_cert_provenance_checker_factory.h"
#include "chrome/browser/net/chrome_net_log.h"
-#include "chrome/browser/net/predictor_api.h"
+#include "chrome/browser/net/predictor.h"
#include "chrome/browser/net/sdch_dictionary_fetcher.h"
#include "chrome/browser/plugin_prefs.h"
#include "chrome/browser/policy/browser_policy_connector.h"
@@ -974,6 +974,88 @@ void ChromeBrowserMainParts::ConnectBackupJobsFieldTrial() {
}
}
+void ChromeBrowserMainParts::PredictorFieldTrial() {
+ const base::FieldTrial::Probability kDivisor = 1000;
+ // For each option (i.e., non-default), we have a fixed probability.
+ // 0.1% probability.
+ const base::FieldTrial::Probability kProbabilityPerGroup = 1;
+
+ // After June 30, 2011 builds, it will always be in default group
+ // (default_enabled_prefetch).
+ scoped_refptr<base::FieldTrial> trial(
+ new base::FieldTrial("DnsImpact", kDivisor,
+ "default_enabled_prefetch", 2011, 10, 30));
+
+ // First option is to disable prefetching completely.
+ int disabled_prefetch = trial->AppendGroup("disabled_prefetch",
+ kProbabilityPerGroup);
+
+ // We're running two experiments at the same time. The first set of trials
+ // modulates the delay-time until we declare a congestion event (and purge
+ // our queue). The second modulates the number of concurrent resolutions
+ // we do at any time. Users are in exactly one trial (or the default) during
+ // any one run, and hence only one experiment at a time.
+ // Experiment 1:
+ // Set congestion detection at 250, 500, or 750ms, rather than the 1 second
+ // default.
+ int max_250ms_prefetch = trial->AppendGroup("max_250ms_queue_prefetch",
+ kProbabilityPerGroup);
+ int max_500ms_prefetch = trial->AppendGroup("max_500ms_queue_prefetch",
+ kProbabilityPerGroup);
+ int max_750ms_prefetch = trial->AppendGroup("max_750ms_queue_prefetch",
+ kProbabilityPerGroup);
+ // Set congestion detection at 2 seconds instead of the 1 second default.
+ int max_2s_prefetch = trial->AppendGroup("max_2s_queue_prefetch",
+ kProbabilityPerGroup);
+ // Experiment 2:
+ // Set max simultaneous resoultions to 2, 4, or 6, and scale the congestion
+ // limit proportionally (so we don't impact average probability of asserting
+ // congesion very much).
+ int max_2_concurrent_prefetch = trial->AppendGroup(
+ "max_2 concurrent_prefetch", kProbabilityPerGroup);
+ int max_4_concurrent_prefetch = trial->AppendGroup(
+ "max_4 concurrent_prefetch", kProbabilityPerGroup);
+ int max_6_concurrent_prefetch = trial->AppendGroup(
+ "max_6 concurrent_prefetch", kProbabilityPerGroup);
+
+ if (trial->group() != disabled_prefetch) {
+ // Initialize the DNS prefetch system.
+ size_t max_parallel_resolves =
+ chrome_browser_net::Predictor::kMaxSpeculativeParallelResolves;
+ int max_queueing_delay_ms =
+ chrome_browser_net::Predictor::kMaxSpeculativeResolveQueueDelayMs;
+
+ if (trial->group() == max_2_concurrent_prefetch)
+ max_parallel_resolves = 2;
+ else if (trial->group() == max_4_concurrent_prefetch)
+ max_parallel_resolves = 4;
+ else if (trial->group() == max_6_concurrent_prefetch)
+ max_parallel_resolves = 6;
+ chrome_browser_net::Predictor::set_max_parallel_resolves(
+ max_parallel_resolves);
+
+ if (trial->group() == max_250ms_prefetch) {
+ max_queueing_delay_ms =
+ (250 * chrome_browser_net::Predictor::kTypicalSpeculativeGroupSize) /
+ max_parallel_resolves;
+ } else if (trial->group() == max_500ms_prefetch) {
+ max_queueing_delay_ms =
+ (500 * chrome_browser_net::Predictor::kTypicalSpeculativeGroupSize) /
+ max_parallel_resolves;
+ } else if (trial->group() == max_750ms_prefetch) {
+ max_queueing_delay_ms =
+ (750 * chrome_browser_net::Predictor::kTypicalSpeculativeGroupSize) /
+ max_parallel_resolves;
+ } else if (trial->group() == max_2s_prefetch) {
+ max_queueing_delay_ms =
+ (2000 * chrome_browser_net::Predictor::kTypicalSpeculativeGroupSize) /
+ max_parallel_resolves;
+ }
+ chrome_browser_net::Predictor::set_max_queueing_delay(
+ max_queueing_delay_ms);
+ }
+}
+
// Test the impact on subsequent Google searches of getting suggestions from
// www.google.TLD instead of clients1.google.TLD.
void ChromeBrowserMainParts::SuggestPrefixFieldTrial() {
@@ -1045,6 +1127,7 @@ void ChromeBrowserMainParts::SetupFieldTrials(bool metrics_recording_enabled,
ConnectBackupJobsFieldTrial();
SuggestPrefixFieldTrial();
WarmConnectionFieldTrial();
+ PredictorFieldTrial();
}
// -----------------------------------------------------------------------------
@@ -1559,20 +1642,6 @@ int ChromeBrowserMainParts::PreMainMessageLoopRunInternal() {
RegisterApplicationRestart(parsed_command_line());
#endif // OS_WIN
- // Initialize and maintain network predictor module, which handles DNS
- // pre-resolution, as well as TCP/IP connection pre-warming.
- // This also registers an observer to discard data when closing incognito
- // mode.
- bool preconnect_enabled = true; // Default status (easy to change!).
- if (parsed_command_line().HasSwitch(switches::kDisablePreconnect))
- preconnect_enabled = false;
- else if (parsed_command_line().HasSwitch(switches::kEnablePreconnect))
- preconnect_enabled = true;
- chrome_browser_net::PredictorInit dns_prefetch(
- user_prefs,
- local_state,
- preconnect_enabled);
-
#if defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD)
// Init the RLZ library. This just binds the dll and schedules a task on the
// file thread to be run sometime later. If this is the first run we record
diff --git a/chrome/browser/chrome_browser_main.h b/chrome/browser/chrome_browser_main.h
index 503de23..74ed9ec 100644
--- a/chrome/browser/chrome_browser_main.h
+++ b/chrome/browser/chrome_browser_main.h
@@ -75,6 +75,10 @@ class ChromeBrowserMainParts : public content::BrowserMainParts {
// A/B test for using a different host prefix in Google search suggest.
void SuggestPrefixFieldTrial();
+ // Field trial to see what disabling DNS pre-resolution does to
+ // latency of page loads.
+ void PredictorFieldTrial();
+
// Methods for |SetupMetricsAndFieldTrials()| --------------------------------
static MetricsService* InitializeMetrics(
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 41b84cc..ce7a52c 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -153,7 +153,13 @@ TabContentsView* ChromeContentBrowserClient::CreateTabContentsView(
void ChromeContentBrowserClient::RenderViewHostCreated(
RenderViewHost* render_view_host) {
- new ChromeRenderViewHostObserver(render_view_host);
+
+ SiteInstance* site_instance = render_view_host->site_instance();
+ Profile* profile = Profile::FromBrowserContext(
+ site_instance->browsing_instance()->browser_context());
+
+ new ChromeRenderViewHostObserver(render_view_host,
+ profile->GetNetworkPredictor());
new ExtensionMessageHandler(render_view_host);
}
diff --git a/chrome/browser/io_thread.cc b/chrome/browser/io_thread.cc
index b018554..38474c6 100644
--- a/chrome/browser/io_thread.cc
+++ b/chrome/browser/io_thread.cc
@@ -24,7 +24,6 @@
#include "chrome/browser/net/chrome_url_request_context.h"
#include "chrome/browser/net/connect_interceptor.h"
#include "chrome/browser/net/passive_log_collector.h"
-#include "chrome/browser/net/predictor_api.h"
#include "chrome/browser/net/pref_proxy_config_service.h"
#include "chrome/browser/net/proxy_service_factory.h"
#include "chrome/browser/prefs/pref_service.h"
@@ -344,8 +343,6 @@ IOThread::IOThread(
net_log_(net_log),
extension_event_router_forwarder_(extension_event_router_forwarder),
globals_(NULL),
- speculative_interceptor_(NULL),
- predictor_(NULL),
ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {
// We call RegisterPrefs() here (instead of inside browser_prefs.cc) to make
// sure that everything is initialized in the right order.
@@ -387,33 +384,6 @@ ChromeNetLog* IOThread::net_log() {
return net_log_;
}
-void IOThread::InitNetworkPredictor(
- bool prefetching_enabled,
- base::TimeDelta max_dns_queue_delay,
- size_t max_speculative_parallel_resolves,
- const chrome_common_net::UrlList& startup_urls,
- ListValue* referral_list,
- bool preconnect_enabled) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- message_loop()->PostTask(
- FROM_HERE,
- NewRunnableMethod(
- this,
- &IOThread::InitNetworkPredictorOnIOThread,
- prefetching_enabled, max_dns_queue_delay,
- max_speculative_parallel_resolves,
- startup_urls, referral_list, preconnect_enabled));
-}
-
-void IOThread::ChangedToOnTheRecord() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- message_loop()->PostTask(
- FROM_HERE,
- NewRunnableMethod(
- this,
- &IOThread::ChangedToOnTheRecordOnIOThread));
-}
-
net::URLRequestContextGetter* IOThread::system_url_request_context_getter() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (!system_url_request_context_getter_) {
@@ -422,15 +392,6 @@ net::URLRequestContextGetter* IOThread::system_url_request_context_getter() {
return system_url_request_context_getter_;
}
-void IOThread::ClearNetworkingHistory() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- ClearHostCache();
- // Discard acrued data used to speculate in the future.
- chrome_browser_net::DiscardInitialNavigationHistory();
- if (predictor_)
- predictor_->DiscardAllResults();
-}
-
void IOThread::Init() {
// Though this thread is called the "IO" thread, it actually just routes
// messages around; it shouldn't be allowed to perform any blocking disk I/O.
@@ -528,21 +489,6 @@ void IOThread::CleanUp() {
// This must be reset before the ChromeNetLog is destroyed.
network_change_observer_.reset();
- // Not initialized in Init(). May not be initialized.
- if (predictor_) {
- predictor_->Shutdown();
-
- // TODO(willchan): Stop reference counting Predictor. It's owned by
- // IOThread now.
- predictor_->Release();
- predictor_ = NULL;
- chrome_browser_net::FreePredictorResources();
- }
-
- // Deletion will unregister this interceptor.
- delete speculative_interceptor_;
- speculative_interceptor_ = NULL;
-
system_proxy_config_service_.reset();
delete globals_;
@@ -599,51 +545,6 @@ net::HttpAuthHandlerFactory* IOThread::CreateDefaultAuthHandlerFactory(
negotiate_enable_port_);
}
-void IOThread::InitNetworkPredictorOnIOThread(
- bool prefetching_enabled,
- base::TimeDelta max_dns_queue_delay,
- size_t max_speculative_parallel_resolves,
- const chrome_common_net::UrlList& startup_urls,
- ListValue* referral_list,
- bool preconnect_enabled) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- CHECK(!predictor_);
-
- chrome_browser_net::EnablePredictor(prefetching_enabled);
-
- predictor_ = new chrome_browser_net::Predictor(
- globals_->host_resolver.get(),
- max_dns_queue_delay,
- max_speculative_parallel_resolves,
- preconnect_enabled);
- predictor_->AddRef();
-
- // Speculative_interceptor_ is used to predict subresource usage.
- DCHECK(!speculative_interceptor_);
- speculative_interceptor_ = new chrome_browser_net::ConnectInterceptor;
-
- FinalizePredictorInitialization(predictor_, startup_urls, referral_list);
-}
-
-void IOThread::ChangedToOnTheRecordOnIOThread() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-
- if (predictor_) {
- // Destroy all evidence of our OTR session.
- // Note: OTR mode never saves InitialNavigationHistory data.
- predictor_->Predictor::DiscardAllResults();
- }
-
- // Clear the host cache to avoid showing entries from the OTR session
- // in about:net-internals.
- ClearHostCache();
-
- // Clear all of the passively logged data.
- // TODO(eroman): this is a bit heavy handed, really all we need to do is
- // clear the data pertaining to incognito context.
- net_log_->ClearAllPassivelyCapturedEvents();
-}
-
void IOThread::ClearHostCache() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
diff --git a/chrome/browser/io_thread.h b/chrome/browser/io_thread.h
index a2b42b5..9340f39 100644
--- a/chrome/browser/io_thread.h
+++ b/chrome/browser/io_thread.h
@@ -14,7 +14,6 @@
#include "chrome/browser/browser_process_sub_thread.h"
#include "chrome/browser/net/ssl_config_service_manager.h"
#include "chrome/browser/prefs/pref_member.h"
-#include "chrome/common/net/predictor_common.h"
#include "net/base/network_change_notifier.h"
class ChromeNetLog;
@@ -29,11 +28,6 @@ namespace base {
class ListValue;
}
-namespace chrome_browser_net {
-class ConnectInterceptor;
-class Predictor;
-} // namespace chrome_browser_net
-
namespace net {
class CertVerifier;
class CookieStore;
@@ -109,28 +103,13 @@ class IOThread : public BrowserProcessSubThread {
ChromeNetLog* net_log();
- // 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 InitNetworkPredictor(bool prefetching_enabled,
- base::TimeDelta max_dns_queue_delay,
- size_t max_speculative_parallel_resolves,
- const chrome_common_net::UrlList& startup_urls,
- base::ListValue* referral_list,
- bool preconnect_enabled);
-
- // Handles changing to On The Record mode, discarding confidential data.
- void ChangedToOnTheRecord();
-
// Returns a getter for the URLRequestContext. Only called on the UI thread.
net::URLRequestContextGetter* system_url_request_context_getter();
- // Clear all network stack history, including the host cache, as well as
- // speculative data about subresources of visited sites, and startup-time
- // navigations.
- void ClearNetworkingHistory();
+ // Clears the host cache. Intended to be used to prevent exposing recently
+ // visited sites on about:net-internals/#dns and about:dns pages. Must be
+ // called on the IO thread.
+ void ClearHostCache();
protected:
virtual void Init();
@@ -152,21 +131,6 @@ class IOThread : public BrowserProcessSubThread {
// SystemURLRequestContextGetter. To be called on IO thread.
void InitSystemRequestContextOnIOThread();
- void InitNetworkPredictorOnIOThread(
- bool prefetching_enabled,
- base::TimeDelta max_dns_queue_delay,
- size_t max_speculative_parallel_resolves,
- const chrome_common_net::UrlList& startup_urls,
- base::ListValue* referral_list,
- bool preconnect_enabled);
-
- void ChangedToOnTheRecordOnIOThread();
-
- // Clears the host cache. Intended to be used to prevent exposing recently
- // visited sites on about:net-internals/#dns and about:dns pages. Must be
- // called on the IO thread.
- void ClearHostCache();
-
// Returns an SSLConfigService instance.
net::SSLConfigService* GetSSLConfigService();
@@ -208,14 +172,6 @@ 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_;
- chrome_browser_net::Predictor* predictor_;
-
scoped_ptr<net::ProxyConfigService> system_proxy_config_service_;
scoped_refptr<PrefProxyConfigTracker> pref_proxy_config_tracker_;
diff --git a/chrome/browser/net/connect_interceptor.cc b/chrome/browser/net/connect_interceptor.cc
index 5938df2..0ea6dbd 100644
--- a/chrome/browser/net/connect_interceptor.cc
+++ b/chrome/browser/net/connect_interceptor.cc
@@ -4,8 +4,9 @@
#include "chrome/browser/net/connect_interceptor.h"
-#include "chrome/browser/net/predictor_api.h"
+#include "chrome/browser/net/predictor.h"
#include "net/base/load_flags.h"
+#include "net/url_request/url_request.h"
namespace chrome_browser_net {
@@ -16,24 +17,24 @@ namespace chrome_browser_net {
// TODO(jar): We should do a persistent field trial to validate/optimize this.
static const int kMaxUnusedSocketLifetimeSecondsWithoutAGet = 10;
-ConnectInterceptor::ConnectInterceptor()
+ConnectInterceptor::ConnectInterceptor(Predictor* predictor)
: timed_cache_(base::TimeDelta::FromSeconds(
- kMaxUnusedSocketLifetimeSecondsWithoutAGet)) {
- net::URLRequest::Deprecated::RegisterRequestInterceptor(this);
+ kMaxUnusedSocketLifetimeSecondsWithoutAGet)),
+ predictor_(predictor) {
+ DCHECK(predictor);
}
ConnectInterceptor::~ConnectInterceptor() {
- net::URLRequest::Deprecated::UnregisterRequestInterceptor(this);
}
net::URLRequestJob* ConnectInterceptor::MaybeIntercept(
- net::URLRequest* request) {
+ net::URLRequest* request) const {
GURL request_scheme_host(Predictor::CanonicalizeUrl(request->url()));
if (request_scheme_host == GURL::EmptyGURL())
return NULL;
// Learn what URLs are likely to be needed during next startup.
- LearnAboutInitialNavigation(request_scheme_host);
+ predictor_->LearnAboutInitialNavigation(request_scheme_host);
bool redirected_host = false;
if (request->referrer().empty()) {
@@ -55,7 +56,8 @@ net::URLRequestJob* ConnectInterceptor::MaybeIntercept(
if (request->original_url().path().length() <= 1 &&
timed_cache_.WasRecentlySeen(original_scheme_host)) {
// TODO(jar): These definite redirects could be learned much faster.
- LearnFromNavigation(original_scheme_host, request_scheme_host);
+ predictor_->LearnFromNavigation(original_scheme_host,
+ request_scheme_host);
}
}
}
@@ -64,7 +66,8 @@ net::URLRequestJob* ConnectInterceptor::MaybeIntercept(
bool is_subresource = !(request->load_flags() & net::LOAD_MAIN_FRAME);
// Learn about our referring URL, for use in the future.
if (is_subresource && timed_cache_.WasRecentlySeen(referring_scheme_host))
- LearnFromNavigation(referring_scheme_host, request_scheme_host);
+ predictor_->LearnFromNavigation(referring_scheme_host,
+ request_scheme_host);
if (referring_scheme_host == request_scheme_host) {
// We've already made any/all predictions when we navigated to the
// referring host, so we can bail out here.
@@ -80,18 +83,18 @@ net::URLRequestJob* ConnectInterceptor::MaybeIntercept(
// main frame request - way back in RenderViewHost::Navigate. So only handle
// predictions now for subresources or for redirected hosts.
if ((request->load_flags() & net::LOAD_SUB_FRAME) || redirected_host)
- PredictFrameSubresources(request_scheme_host);
+ predictor_->PredictFrameSubresources(request_scheme_host);
return NULL;
}
net::URLRequestJob* ConnectInterceptor::MaybeInterceptResponse(
- net::URLRequest* request) {
+ net::URLRequest* request) const {
return NULL;
}
net::URLRequestJob* ConnectInterceptor::MaybeInterceptRedirect(
- net::URLRequest* request,
- const GURL& location) {
+ const GURL& location,
+ net::URLRequest* request) const {
return NULL;
}
@@ -103,7 +106,7 @@ ConnectInterceptor::TimedCache::TimedCache(const base::TimeDelta& max_duration)
// Make Clang compilation happy with explicit destructor.
ConnectInterceptor::TimedCache::~TimedCache() {}
-bool ConnectInterceptor::TimedCache::WasRecentlySeen(const GURL& url) {
+bool ConnectInterceptor::TimedCache::WasRecentlySeen(const GURL& url) const {
DCHECK_EQ(url.GetWithEmptyPath(), url);
// Evict any overly old entries.
base::TimeTicks now = base::TimeTicks::Now();
@@ -117,7 +120,7 @@ bool ConnectInterceptor::TimedCache::WasRecentlySeen(const GURL& url) {
return mru_cache_.end() != mru_cache_.Peek(url);
}
-void ConnectInterceptor::TimedCache::SetRecentlySeen(const GURL& url) {
+void ConnectInterceptor::TimedCache::SetRecentlySeen(const GURL& url) const {
DCHECK_EQ(url.GetWithEmptyPath(), url);
mru_cache_.Put(url, base::TimeTicks::Now());
}
diff --git a/chrome/browser/net/connect_interceptor.h b/chrome/browser/net/connect_interceptor.h
index eca1c17..657700e 100644
--- a/chrome/browser/net/connect_interceptor.h
+++ b/chrome/browser/net/connect_interceptor.h
@@ -6,30 +6,34 @@
#define CHROME_BROWSER_NET_CONNECT_INTERCEPTOR_H_
#pragma once
-#include "net/url_request/url_request.h"
-
#include "base/gtest_prod_util.h"
#include "base/memory/mru_cache.h"
+#include "base/time.h"
+#include "net/url_request/url_request_job_factory.h"
namespace chrome_browser_net {
+class Predictor;
+
//------------------------------------------------------------------------------
// An interceptor to monitor URLRequests so that we can do speculative DNS
// resolution and/or speculative TCP preconnections.
-class ConnectInterceptor : public net::URLRequest::Interceptor {
+class ConnectInterceptor : public net::URLRequestJobFactory::Interceptor {
public:
// Construction includes registration as an URL.
- ConnectInterceptor();
+ explicit ConnectInterceptor(Predictor* predictor);
// Destruction includes unregistering.
virtual ~ConnectInterceptor();
protected:
// Overridden from net::URLRequest::Interceptor:
// Learn about referrers, and optionally preconnect based on history.
- virtual net::URLRequestJob* MaybeIntercept(net::URLRequest* request);
- virtual net::URLRequestJob* MaybeInterceptResponse(net::URLRequest* request);
- virtual net::URLRequestJob* MaybeInterceptRedirect(net::URLRequest* request,
- const GURL& location);
+ virtual net::URLRequestJob* MaybeIntercept(
+ net::URLRequest* request) const OVERRIDE;
+ virtual net::URLRequestJob* MaybeInterceptResponse(
+ net::URLRequest* request) const OVERRIDE;
+ virtual net::URLRequestJob* MaybeInterceptRedirect(
+ const GURL& location, net::URLRequest* request) const OVERRIDE;
private:
// Provide access to local class TimedCache for testing.
@@ -48,17 +52,20 @@ class ConnectInterceptor : public net::URLRequest::Interceptor {
// Evicts any entries that have been in the FIFO "too long," and then checks
// to see if the given url is (still) in the FIFO cache.
- bool WasRecentlySeen(const GURL& url);
+ bool WasRecentlySeen(const GURL& url) const;
// Adds the given url to the cache, where it will remain for max_duration_.
- void SetRecentlySeen(const GURL& url);
+ void SetRecentlySeen(const GURL& url) const;
private:
// Our cache will be keyed on a URL (actually, just a scheme/host/port).
// We will always track the time it was last added to the FIFO cache by
// remembering a TimeTicks value.
typedef base::MRUCache<GURL, base::TimeTicks> UrlMruTimedCache;
- UrlMruTimedCache mru_cache_;
+ // mru_cache_ has to be mutable in order to be accessed from the overriden
+ // URLRequestJob functions. It is mutable because it tracks the urls and
+ // caches them.
+ mutable UrlMruTimedCache mru_cache_;
// The longest time an entry can persist in the cache, and still be found.
const base::TimeDelta max_duration_;
@@ -66,6 +73,7 @@ class ConnectInterceptor : public net::URLRequest::Interceptor {
DISALLOW_COPY_AND_ASSIGN(TimedCache);
};
TimedCache timed_cache_;
+ Predictor* const predictor_;
DISALLOW_COPY_AND_ASSIGN(ConnectInterceptor);
};
diff --git a/chrome/browser/net/net_pref_observer.cc b/chrome/browser/net/net_pref_observer.cc
index 7d57d97..8d59995 100644
--- a/chrome/browser/net/net_pref_observer.cc
+++ b/chrome/browser/net/net_pref_observer.cc
@@ -5,7 +5,7 @@
#include "chrome/browser/net/net_pref_observer.h"
#include "base/task.h"
-#include "chrome/browser/net/predictor_api.h"
+#include "chrome/browser/net/predictor.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/prerender/prerender_manager.h"
#include "chrome/browser/profiles/profile.h"
@@ -28,10 +28,14 @@ void SetEnforceThrottlingOnThrottlerManager(bool enforce) {
}
NetPrefObserver::NetPrefObserver(PrefService* prefs,
- prerender::PrerenderManager* prerender_manager)
- : prerender_manager_(prerender_manager) {
+ prerender::PrerenderManager* prerender_manager,
+ chrome_browser_net::Predictor* predictor)
+ : prerender_manager_(prerender_manager),
+ predictor_(predictor) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(prefs);
+ DCHECK(predictor);
+
network_prediction_enabled_.Init(prefs::kNetworkPredictionEnabled, prefs,
this);
spdy_disabled_.Init(prefs::kDisableSpdy, prefs, this);
@@ -56,7 +60,7 @@ void NetPrefObserver::Observe(int type,
void NetPrefObserver::ApplySettings(const std::string* pref_name) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- chrome_browser_net::EnablePredictor(*network_prediction_enabled_);
+ predictor_->EnablePredictor(*network_prediction_enabled_);
if (prerender_manager_)
prerender_manager_->set_enabled(*network_prediction_enabled_);
net::HttpStreamFactory::set_spdy_enabled(!*spdy_disabled_);
diff --git a/chrome/browser/net/net_pref_observer.h b/chrome/browser/net/net_pref_observer.h
index b7b60c0..4d2ca47 100644
--- a/chrome/browser/net/net_pref_observer.h
+++ b/chrome/browser/net/net_pref_observer.h
@@ -14,6 +14,10 @@
class Profile;
+namespace chrome_browser_net {
+class Predictor;
+}
+
namespace prerender {
class PrerenderManager;
}
@@ -27,7 +31,8 @@ class NetPrefObserver : public NotificationObserver {
// |prerender_manager| may be NULL. If not, |*prerender_manager| must
// outlive this.
NetPrefObserver(PrefService* prefs,
- prerender::PrerenderManager* prerender_manager);
+ prerender::PrerenderManager* prerender_manager,
+ chrome_browser_net::Predictor* predictor);
virtual ~NetPrefObserver();
// NotificationObserver
@@ -45,6 +50,7 @@ class NetPrefObserver : public NotificationObserver {
BooleanPrefMember spdy_disabled_;
BooleanPrefMember http_throttling_enabled_;
prerender::PrerenderManager* prerender_manager_;
+ chrome_browser_net::Predictor* predictor_;
DISALLOW_COPY_AND_ASSIGN(NetPrefObserver);
};
diff --git a/chrome/browser/net/predictor.cc b/chrome/browser/net/predictor.cc
index 7a2320ce..ed4aa4b 100644
--- a/chrome/browser/net/predictor.cc
+++ b/chrome/browser/net/predictor.cc
@@ -9,12 +9,23 @@
#include <set>
#include <sstream>
+#include "base/bind.h"
+#include "base/command_line.h"
#include "base/compiler_specific.h"
#include "base/metrics/histogram.h"
+#include "base/stl_util.h"
#include "base/stringprintf.h"
+#include "base/synchronization/waitable_event.h"
#include "base/time.h"
#include "base/values.h"
+#include "chrome/browser/io_thread.h"
#include "chrome/browser/net/preconnect.h"
+#include "chrome/browser/prefs/browser_prefs.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/prefs/scoped_user_pref_update.h"
+#include "chrome/browser/prefs/session_startup_pref.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/pref_names.h"
#include "content/browser/browser_thread.h"
#include "net/base/address_list.h"
#include "net/base/completion_callback.h"
@@ -48,6 +59,22 @@ const TimeDelta Predictor::kDurationBetweenTrimmings = TimeDelta::FromHours(1);
const TimeDelta Predictor::kDurationBetweenTrimmingIncrements =
TimeDelta::FromSeconds(15);
const size_t Predictor::kUrlsTrimmedPerIncrement = 5u;
+const size_t Predictor::kMaxSpeculativeParallelResolves = 3;
+// To control our congestion avoidance system, which discards a queue when
+// resolutions are "taking too long," we need an expected resolution time.
+// Common average is in the range of 300-500ms.
+const int kExpectedResolutionTimeMs = 500;
+const int Predictor::kTypicalSpeculativeGroupSize = 8;
+const int Predictor::kMaxSpeculativeResolveQueueDelayMs =
+ (kExpectedResolutionTimeMs * Predictor::kTypicalSpeculativeGroupSize) /
+ Predictor::kMaxSpeculativeParallelResolves;
+
+static int g_max_queueing_delay_ms = 0;
+static size_t g_max_parallel_resolves = 0u;
+
+// 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 kPredictorStartupFormatVersion = 1;
class Predictor::LookupRequest {
public:
@@ -94,76 +121,89 @@ class Predictor::LookupRequest {
DISALLOW_COPY_AND_ASSIGN(LookupRequest);
};
-Predictor::Predictor(net::HostResolver* host_resolver,
- TimeDelta max_dns_queue_delay,
- size_t max_concurrent,
- bool preconnect_enabled)
- : peak_pending_lookups_(0),
+Predictor::Predictor(bool preconnect_enabled)
+ : initial_observer_(NULL),
+ predictor_enabled_(true),
+ peak_pending_lookups_(0),
shutdown_(false),
- max_concurrent_dns_lookups_(max_concurrent),
- max_dns_queue_delay_(max_dns_queue_delay),
- host_resolver_(host_resolver),
+ max_concurrent_dns_lookups_(g_max_parallel_resolves),
+ max_dns_queue_delay_(
+ TimeDelta::FromMilliseconds(g_max_queueing_delay_ms)),
+ host_resolver_(NULL),
preconnect_enabled_(preconnect_enabled),
consecutive_omnibox_preconnect_count_(0),
- next_trim_time_(base::TimeTicks::Now() + kDurationBetweenTrimmings),
- ALLOW_THIS_IN_INITIALIZER_LIST(trim_task_factory_(this)) {
+ next_trim_time_(base::TimeTicks::Now() + kDurationBetweenTrimmings) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
}
Predictor::~Predictor() {
+ // TODO(rlp): Add DCHECK for CurrentlyOn(BrowserThread::IO) when the
+ // ProfileManagerTest has been updated with a mock profile.
DCHECK(shutdown_);
}
-void Predictor::Shutdown() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- DCHECK(!shutdown_);
- shutdown_ = true;
-
- std::set<LookupRequest*>::iterator it;
- for (it = pending_lookups_.begin(); it != pending_lookups_.end(); ++it)
- delete *it;
+// static
+Predictor* Predictor::CreatePredictor(
+ bool preconnect_enabled, bool simple_shutdown) {
+ if (simple_shutdown)
+ return new SimplePredictor(preconnect_enabled);
+ return new Predictor(preconnect_enabled);
}
-// Overloaded Resolve() to take a vector of names.
-void Predictor::ResolveList(const UrlList& urls,
- UrlInfo::ResolutionMotivation motivation) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-
- for (UrlList::const_iterator it = urls.begin(); it < urls.end(); ++it) {
- AppendToResolutionQueue(*it, motivation);
- }
+void Predictor::RegisterUserPrefs(PrefService* user_prefs) {
+ user_prefs->RegisterListPref(prefs::kDnsPrefetchingStartupList,
+ PrefService::UNSYNCABLE_PREF);
+ user_prefs->RegisterListPref(prefs::kDnsPrefetchingHostReferralList,
+ PrefService::UNSYNCABLE_PREF);
}
-// Basic Resolve() takes an invidual name, and adds it
-// to the queue.
-void Predictor::Resolve(const GURL& url,
- UrlInfo::ResolutionMotivation motivation) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- if (!url.has_host())
- return;
- AppendToResolutionQueue(url, motivation);
-}
-
-void Predictor::LearnFromNavigation(const GURL& referring_url,
- const GURL& target_url) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- DCHECK_EQ(referring_url, Predictor::CanonicalizeUrl(referring_url));
- DCHECK_NE(referring_url, GURL::EmptyGURL());
- DCHECK_EQ(target_url, Predictor::CanonicalizeUrl(target_url));
- DCHECK_NE(target_url, GURL::EmptyGURL());
+// --------------------- Start UI methods. ------------------------------------
+
+void Predictor::InitNetworkPredictor(PrefService* user_prefs,
+ PrefService* local_state,
+ IOThread* io_thread) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ bool predictor_enabled =
+ user_prefs->GetBoolean(prefs::kNetworkPredictionEnabled);
+
+ // Gather the list of hostnames to prefetch on startup.
+ UrlList urls = GetPredictedUrlListAtStartup(user_prefs, local_state);
+
+ base::ListValue* referral_list =
+ static_cast<base::ListValue*>(user_prefs->GetList(
+ prefs::kDnsPrefetchingHostReferralList)->DeepCopy());
+
+ // Remove obsolete preferences from local state if necessary.
+ int current_version =
+ local_state->GetInteger(prefs::kMultipleProfilePrefMigration);
+ if ((current_version & browser::DNS_PREFS) == 0) {
+ local_state->RegisterListPref(prefs::kDnsStartupPrefetchList,
+ PrefService::UNSYNCABLE_PREF);
+ local_state->RegisterListPref(prefs::kDnsHostReferralList,
+ PrefService::UNSYNCABLE_PREF);
+ local_state->ClearPref(prefs::kDnsStartupPrefetchList);
+ local_state->ClearPref(prefs::kDnsHostReferralList);
+ local_state->SetInteger(prefs::kMultipleProfilePrefMigration,
+ current_version | browser::DNS_PREFS);
+ }
- referrers_[referring_url].SuggestHost(target_url);
- // Possibly do some referrer trimming.
- TrimReferrers();
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(
+ &Predictor::FinalizeInitializationOnIOThread,
+ base::Unretained(this),
+ urls, referral_list,
+ io_thread, predictor_enabled));
}
-enum SubresourceValue {
- PRECONNECTION,
- PRERESOLUTION,
- TOO_NEW,
- SUBRESOURCE_VALUE_MAX
-};
-
void Predictor::AnticipateOmniboxUrl(const GURL& url, bool preconnectable) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (!predictor_enabled_)
+ return;
+ if (!url.is_valid() || !url.has_host())
+ return;
std::string host = url.HostNoBrackets();
bool is_new_host_request = (host != last_omnibox_host_);
last_omnibox_host_ = host;
@@ -227,11 +267,16 @@ void Predictor::AnticipateOmniboxUrl(const GURL& url, bool preconnectable) {
BrowserThread::PostTask(
BrowserThread::IO,
FROM_HERE,
- NewRunnableMethod(this, &Predictor::Resolve, CanonicalizeUrl(url),
- motivation));
+ base::Bind(&Predictor::Resolve, base::Unretained(this),
+ CanonicalizeUrl(url), motivation));
}
void Predictor::PreconnectUrlAndSubresources(const GURL& url) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (!predictor_enabled_)
+ return;
+ if (!url.is_valid() || !url.has_host())
+ return;
if (preconnect_enabled()) {
std::string host = url.HostNoBrackets();
UrlInfo::ResolutionMotivation motivation(UrlInfo::EARLY_LOAD_MOTIVATED);
@@ -242,65 +287,188 @@ void Predictor::PreconnectUrlAndSubresources(const GURL& url) {
}
}
-void Predictor::PredictFrameSubresources(const GURL& url) {
- DCHECK_EQ(url.GetWithEmptyPath(), url);
- // Add one pass through the message loop to allow current navigation to
- // proceed.
+UrlList Predictor::GetPredictedUrlListAtStartup(
+ PrefService* user_prefs,
+ PrefService* local_state) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ 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).
+ const ListValue* startup_list =
+ user_prefs->GetList(prefs::kDnsPrefetchingStartupList);
+
+ if (startup_list) {
+ base::ListValue::const_iterator it = startup_list->begin();
+ int format_version = -1;
+ if (it != startup_list->end() &&
+ (*it)->GetAsInteger(&format_version) &&
+ format_version == kPredictorStartupFormatVersion) {
+ ++it;
+ for (; it != startup_list->end(); ++it) {
+ std::string url_spec;
+ if (!(*it)->GetAsString(&url_spec)) {
+ LOG(DFATAL);
+ break; // Format incompatibility.
+ }
+ GURL url(url_spec);
+ if (!url.has_host() || !url.has_scheme()) {
+ LOG(DFATAL);
+ break; // Format incompatibility.
+ }
+
+ urls.push_back(url);
+ }
+ }
+ }
+
+ // Prepare for any static home page(s) the user has in prefs. The user may
+ // have a LOT of tab's specified, so we may as well try to warm them all.
+ SessionStartupPref tab_start_pref =
+ SessionStartupPref::GetStartupPref(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.SchemeIsFile() || gurl.host().empty())
+ continue;
+ if (gurl.SchemeIs("http") || gurl.SchemeIs("https"))
+ urls.push_back(gurl.GetWithEmptyPath());
+ }
+ }
+
+ if (urls.empty())
+ urls.push_back(GURL("http://www.google.com:80"));
+
+ return urls;
+}
+
+void Predictor::set_max_queueing_delay(int max_queueing_delay_ms) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ g_max_queueing_delay_ms = max_queueing_delay_ms;
+}
+
+void Predictor::set_max_parallel_resolves(size_t max_parallel_resolves) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ g_max_parallel_resolves = max_parallel_resolves;
+}
+
+void Predictor::ShutdownOnUIThread(PrefService* user_prefs) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ SaveStateForNextStartupAndTrim(user_prefs);
+
BrowserThread::PostTask(
BrowserThread::IO,
FROM_HERE,
- NewRunnableMethod(this, &Predictor::PrepareFrameSubresources, url));
+ base::Bind(&Predictor::Shutdown, base::Unretained(this)));
}
-void Predictor::PrepareFrameSubresources(const GURL& url) {
+// ---------------------- End UI methods. -------------------------------------
+
+// --------------------- Start IO methods. ------------------------------------
+
+void Predictor::Shutdown() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- DCHECK_EQ(url.GetWithEmptyPath(), url);
- Referrers::iterator it = referrers_.find(url);
- if (referrers_.end() == it) {
- // Only when we don't know anything about this url, make 2 connections
- // available. We could do this completely via learning (by prepopulating
- // the referrer_ list with this expected value), but it would swell the
- // size of the list with all the "Leaf" nodes in the tree (nodes that don't
- // load any subresources). If we learn about this resource, we will instead
- // provide a more carefully estimated preconnection count.
- if (preconnect_enabled_)
- PreconnectOnIOThread(url, UrlInfo::SELF_REFERAL_MOTIVATED, 2);
- return;
+ DCHECK(!shutdown_);
+ shutdown_ = true;
+
+ STLDeleteElements(&pending_lookups_);
+}
+
+void Predictor::DiscardAllResults() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ // Delete anything listed so far in this session that shows in about:dns.
+ referrers_.clear();
+
+
+ // Try to delete anything in our work queue.
+ while (!work_queue_.IsEmpty()) {
+ // Emulate processing cycle as though host was not found.
+ GURL url = work_queue_.Pop();
+ UrlInfo* info = &results_[url];
+ DCHECK(info->HasUrl(url));
+ info->SetAssignedState();
+ info->SetNoSuchNameState();
}
+ // Now every result_ is either resolved, or is being resolved
+ // (see LookupRequest).
- Referrer* referrer = &(it->second);
- referrer->IncrementUseCount();
- const UrlInfo::ResolutionMotivation motivation =
- UrlInfo::LEARNED_REFERAL_MOTIVATED;
- for (Referrer::iterator future_url = referrer->begin();
- future_url != referrer->end(); ++future_url) {
- SubresourceValue evalution(TOO_NEW);
- double connection_expectation = future_url->second.subresource_use_rate();
- UMA_HISTOGRAM_CUSTOM_COUNTS("Net.PreconnectSubresourceExpectation",
- static_cast<int>(connection_expectation * 100),
- 10, 5000, 50);
- future_url->second.ReferrerWasObserved();
- if (preconnect_enabled_ &&
- connection_expectation > kPreconnectWorthyExpectedValue) {
- evalution = PRECONNECTION;
- future_url->second.IncrementPreconnectionCount();
- int count = static_cast<int>(std::ceil(connection_expectation));
- if (url.host() == future_url->first.host())
- ++count;
- PreconnectOnIOThread(future_url->first, motivation, count);
- } else if (connection_expectation > kDNSPreresolutionWorthyExpectedValue) {
- evalution = PRERESOLUTION;
- future_url->second.preresolution_increment();
- UrlInfo* queued_info = AppendToResolutionQueue(future_url->first,
- motivation);
- if (queued_info)
- queued_info->SetReferringHostname(url);
+ // Step through result_, recording names of all hosts that can't be erased.
+ // We can't erase anything being worked on.
+ Results assignees;
+ for (Results::iterator it = results_.begin(); results_.end() != it; ++it) {
+ GURL url(it->first);
+ UrlInfo* info = &it->second;
+ DCHECK(info->HasUrl(url));
+ if (info->is_assigned()) {
+ info->SetPendingDeleteState();
+ assignees[url] = *info;
}
- UMA_HISTOGRAM_ENUMERATION("Net.PreconnectSubresourceEval", evalution,
- SUBRESOURCE_VALUE_MAX);
+ }
+ DCHECK_LE(assignees.size(), max_concurrent_dns_lookups_);
+ results_.clear();
+ // Put back in the names being worked on.
+ for (Results::iterator it = assignees.begin(); assignees.end() != it; ++it) {
+ DCHECK(it->second.is_marked_to_delete());
+ results_[it->first] = it->second;
}
}
+// Overloaded Resolve() to take a vector of names.
+void Predictor::ResolveList(const UrlList& urls,
+ UrlInfo::ResolutionMotivation motivation) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+ 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 Predictor::Resolve(const GURL& url,
+ UrlInfo::ResolutionMotivation motivation) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ if (!url.has_host())
+ return;
+ AppendToResolutionQueue(url, motivation);
+}
+
+void Predictor::LearnFromNavigation(const GURL& referring_url,
+ const GURL& target_url) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ if (!predictor_enabled_)
+ return;
+ DCHECK_EQ(referring_url, Predictor::CanonicalizeUrl(referring_url));
+ DCHECK_NE(referring_url, GURL::EmptyGURL());
+ DCHECK_EQ(target_url, Predictor::CanonicalizeUrl(target_url));
+ DCHECK_NE(target_url, GURL::EmptyGURL());
+
+ referrers_[referring_url].SuggestHost(target_url);
+ // Possibly do some referrer trimming.
+ TrimReferrers();
+}
+
+//-----------------------------------------------------------------------------
+// This section supports the about:dns page.
+
+void Predictor::PredictorGetHtmlInfo(Predictor* predictor,
+ std::string* output) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+ output->append("<html><head><title>About DNS</title>"
+ // We'd like the following no-cache... but it doesn't work.
+ // "<META HTTP-EQUIV=\"Pragma\" CONTENT=\"no-cache\">"
+ "</head><body>");
+ if (predictor && predictor->predictor_enabled()) {
+ predictor->GetHtmlInfo(output);
+ } else {
+ output->append("DNS pre-resolution and TCP pre-connection is disabled.");
+ }
+ output->append("</body></html>");
+}
+
// Provide sort order so all .com's are together, etc.
struct RightToLeftStringSorter {
bool operator()(const GURL& left,
@@ -413,6 +581,11 @@ void Predictor::GetHtmlReferrerLists(std::string* output) {
void Predictor::GetHtmlInfo(std::string* output) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ if (initial_observer_.get())
+ initial_observer_->GetFirstResolutionsHtml(output);
+ // Show list of subresource predictions and stats.
+ GetHtmlReferrerLists(output);
+
// Local lists for calling UrlInfo
UrlInfo::UrlInfoTable name_not_found;
UrlInfo::UrlInfoTable name_preresolved;
@@ -448,81 +621,308 @@ void Predictor::GetHtmlInfo(std::string* output) {
"Preresolving DNS records revealed non-existence for ", brief, output);
}
-UrlInfo* Predictor::AppendToResolutionQueue(
- const GURL& url,
- UrlInfo::ResolutionMotivation motivation) {
+void Predictor::TrimReferrersNow() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- DCHECK(url.has_host());
+ // Just finish up work if an incremental trim is in progress.
+ if (urls_being_trimmed_.empty())
+ LoadUrlsForTrimming();
+ IncrementalTrimReferrers(true); // Do everything now.
+}
- if (shutdown_)
- return NULL;
+void Predictor::SerializeReferrers(base::ListValue* referral_list) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ referral_list->Clear();
+ referral_list->Append(new base::FundamentalValue(kPredictorReferrerVersion));
+ for (Referrers::const_iterator it = referrers_.begin();
+ it != referrers_.end(); ++it) {
+ // Serialize the list of subresource names.
+ Value* subresource_list(it->second.Serialize());
- UrlInfo* 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 :-/
+ // Create a list for each referer.
+ ListValue* motivator(new ListValue);
+ motivator->Append(new StringValue(it->first.spec()));
+ motivator->Append(subresource_list);
- DCHECK(info->HasUrl(url));
+ referral_list->Append(motivator);
+ }
+}
- if (!info->NeedsDnsUpdate()) {
- info->DLogResultsStats("DNS PrefetchNotUpdated");
- return NULL;
+void Predictor::DeserializeReferrers(const base::ListValue& referral_list) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ int format_version = -1;
+ if (referral_list.GetSize() > 0 &&
+ referral_list.GetInteger(0, &format_version) &&
+ format_version == kPredictorReferrerVersion) {
+ for (size_t i = 1; i < referral_list.GetSize(); ++i) {
+ base::ListValue* motivator;
+ if (!referral_list.GetList(i, &motivator)) {
+ NOTREACHED();
+ return;
+ }
+ std::string motivating_url_spec;
+ if (!motivator->GetString(0, &motivating_url_spec)) {
+ NOTREACHED();
+ return;
+ }
+
+ Value* subresource_list;
+ if (!motivator->Get(1, &subresource_list)) {
+ NOTREACHED();
+ return;
+ }
+
+ referrers_[GURL(motivating_url_spec)].Deserialize(*subresource_list);
+ }
}
+}
- info->SetQueuedState(motivation);
- work_queue_.Push(url, motivation);
- StartSomeQueuedResolutions();
- return info;
+void Predictor::DeserializeReferrersThenDelete(
+ base::ListValue* referral_list) {
+ DeserializeReferrers(*referral_list);
+ delete referral_list;
}
-void Predictor::StartSomeQueuedResolutions() {
+void Predictor::DiscardInitialNavigationHistory() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ if (initial_observer_.get())
+ initial_observer_->DiscardInitialNavigationHistory();
+}
- while (!work_queue_.IsEmpty() &&
- pending_lookups_.size() < max_concurrent_dns_lookups_) {
- const GURL url(work_queue_.Pop());
- UrlInfo* info = &results_[url];
- DCHECK(info->HasUrl(url));
- info->SetAssignedState();
+void Predictor::FinalizeInitializationOnIOThread(
+ const UrlList& startup_urls,
+ base::ListValue* referral_list,
+ IOThread* io_thread,
+ bool predictor_enabled) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- if (CongestionControlPerformed(info)) {
- DCHECK(work_queue_.IsEmpty());
- return;
- }
+ predictor_enabled_ = predictor_enabled;
+ initial_observer_.reset(new InitialObserver());
+ host_resolver_ = io_thread->globals()->host_resolver.get();
- LookupRequest* request = new LookupRequest(this, host_resolver_, url);
- int status = request->Start();
- if (status == net::ERR_IO_PENDING) {
- // Will complete asynchronously.
- pending_lookups_.insert(request);
- peak_pending_lookups_ = std::max(peak_pending_lookups_,
- pending_lookups_.size());
- } else {
- // 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, url, status == net::OK);
- delete request;
- }
+ // ScopedRunnableMethodFactory instances need to be created and destroyed
+ // on the same thread. The predictor lives on the IO thread and will die
+ // from there so now that we're on the IO thread we need to properly
+ // initialize the ScopedrunnableMethodFactory.
+ trim_task_factory_.reset(new ScopedRunnableMethodFactory<Predictor>(this));
+
+ // Prefetch these hostnames on startup.
+ DnsPrefetchMotivatedList(startup_urls, UrlInfo::STARTUP_LIST_MOTIVATED);
+ DeserializeReferrersThenDelete(referral_list);
+}
+
+//-----------------------------------------------------------------------------
+// This section intermingles prefetch results with actual browser HTTP
+// network activity. It supports calculating of the benefit of a prefetch, as
+// well as recording what prefetched hostname resolutions might be potentially
+// helpful during the next chrome-startup.
+//-----------------------------------------------------------------------------
+
+void Predictor::LearnAboutInitialNavigation(const GURL& url) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ if (!predictor_enabled_ || NULL == initial_observer_.get() )
+ return;
+ initial_observer_->Append(url, this);
+}
+
+// This API is only used in the browser process.
+// It is called from an IPC message originating in the renderer. It currently
+// includes both Page-Scan, and Link-Hover prefetching.
+// TODO(jar): Separate out link-hover prefetching, and page-scan results.
+void Predictor::DnsPrefetchList(const NameList& hostnames) {
+ // TODO(jar): Push GURL transport further back into renderer, but this will
+ // require a Webkit change in the observer :-/.
+ UrlList urls;
+ for (NameList::const_iterator it = hostnames.begin();
+ it < hostnames.end();
+ ++it) {
+ urls.push_back(GURL("http://" + *it + ":80"));
}
+
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DnsPrefetchMotivatedList(urls, UrlInfo::PAGE_SCAN_MOTIVATED);
}
-bool Predictor::CongestionControlPerformed(UrlInfo* info) {
+void Predictor::DnsPrefetchMotivatedList(
+ const UrlList& urls,
+ UrlInfo::ResolutionMotivation motivation) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) ||
+ BrowserThread::CurrentlyOn(BrowserThread::IO));
+ if (!predictor_enabled_)
+ return;
+
+ if (BrowserThread::CurrentlyOn(BrowserThread::IO)) {
+ ResolveList(urls, motivation);
+ } else {
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(&Predictor::ResolveList, base::Unretained(this),
+ urls, motivation));
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Functions to handle saving of hostnames from one session to the next, to
+// expedite startup times.
+
+static void SaveDnsPrefetchStateForNextStartupAndTrimOnIOThread(
+ base::ListValue* startup_list,
+ base::ListValue* referral_list,
+ base::WaitableEvent* completion,
+ Predictor* predictor) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- // Note: queue_duration is ONLY valid after we go to assigned state.
- if (info->queue_duration() < max_dns_queue_delay_)
- return false;
- // We need to discard all entries in our queue, as we're keeping them waiting
- // too long. By doing this, we'll have a chance to quickly service urgent
- // resolutions, and not have a bogged down system.
- while (true) {
- info->RemoveFromQueue();
- if (work_queue_.IsEmpty())
- break;
- info = &results_[work_queue_.Pop()];
- info->SetAssignedState();
+
+ if (NULL == predictor) {
+ completion->Signal();
+ return;
+ }
+ predictor->SaveDnsPrefetchStateForNextStartupAndTrim(
+ startup_list, referral_list, completion);
+}
+
+void Predictor::SaveStateForNextStartupAndTrim(PrefService* prefs) {
+ if (!predictor_enabled_)
+ return;
+
+ base::WaitableEvent completion(true, false);
+
+ ListPrefUpdate update_startup_list(prefs, prefs::kDnsPrefetchingStartupList);
+ ListPrefUpdate update_referral_list(prefs,
+ prefs::kDnsPrefetchingHostReferralList);
+ if (BrowserThread::CurrentlyOn(BrowserThread::IO)) {
+ SaveDnsPrefetchStateForNextStartupAndTrimOnIOThread(
+ update_startup_list.Get(),
+ update_referral_list.Get(),
+ &completion,
+ this);
+ } else {
+ bool posted = BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(
+ SaveDnsPrefetchStateForNextStartupAndTrimOnIOThread,
+ update_startup_list.Get(),
+ update_referral_list.Get(),
+ &completion,
+ this));
+
+ // TODO(jar): Synchronous waiting for the IO thread is a potential source
+ // to deadlocks and should be investigated. See http://crbug.com/78451.
+ DCHECK(posted);
+ if (posted)
+ completion.Wait();
+ }
+}
+
+void Predictor::SaveDnsPrefetchStateForNextStartupAndTrim(
+ base::ListValue* startup_list,
+ base::ListValue* referral_list,
+ base::WaitableEvent* completion) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ if (initial_observer_.get())
+ initial_observer_->GetInitialDnsResolutionList(startup_list);
+
+ // Do at least one trim at shutdown, in case the user wasn't running long
+ // enough to do any regular trimming of referrers.
+ TrimReferrersNow();
+ SerializeReferrers(referral_list);
+
+ completion->Signal();
+}
+
+void Predictor::EnablePredictor(bool enable) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) ||
+ BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+ if (BrowserThread::CurrentlyOn(BrowserThread::IO)) {
+ EnablePredictorOnIOThread(enable);
+ } else {
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(&Predictor::EnablePredictorOnIOThread,
+ base::Unretained(this), enable));
+ }
+}
+
+void Predictor::EnablePredictorOnIOThread(bool enable) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ predictor_enabled_ = enable;
+}
+
+void Predictor::PredictFrameSubresources(const GURL& url) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) ||
+ BrowserThread::CurrentlyOn(BrowserThread::IO));
+ if (!predictor_enabled_)
+ return;
+ DCHECK_EQ(url.GetWithEmptyPath(), url);
+ // Add one pass through the message loop to allow current navigation to
+ // proceed.
+ if (BrowserThread::CurrentlyOn(BrowserThread::IO)) {
+ PrepareFrameSubresources(url);
+ } else {
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(&Predictor::PrepareFrameSubresources,
+ base::Unretained(this), url));
+ }
+}
+
+enum SubresourceValue {
+ PRECONNECTION,
+ PRERESOLUTION,
+ TOO_NEW,
+ SUBRESOURCE_VALUE_MAX
+};
+
+void Predictor::PrepareFrameSubresources(const GURL& url) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_EQ(url.GetWithEmptyPath(), url);
+ Referrers::iterator it = referrers_.find(url);
+ if (referrers_.end() == it) {
+ // Only when we don't know anything about this url, make 2 connections
+ // available. We could do this completely via learning (by prepopulating
+ // the referrer_ list with this expected value), but it would swell the
+ // size of the list with all the "Leaf" nodes in the tree (nodes that don't
+ // load any subresources). If we learn about this resource, we will instead
+ // provide a more carefully estimated preconnection count.
+ if (preconnect_enabled_)
+ PreconnectOnIOThread(url, UrlInfo::SELF_REFERAL_MOTIVATED, 2);
+ return;
+ }
+
+ Referrer* referrer = &(it->second);
+ referrer->IncrementUseCount();
+ const UrlInfo::ResolutionMotivation motivation =
+ UrlInfo::LEARNED_REFERAL_MOTIVATED;
+ for (Referrer::iterator future_url = referrer->begin();
+ future_url != referrer->end(); ++future_url) {
+ SubresourceValue evalution(TOO_NEW);
+ double connection_expectation = future_url->second.subresource_use_rate();
+ UMA_HISTOGRAM_CUSTOM_COUNTS("Net.PreconnectSubresourceExpectation",
+ static_cast<int>(connection_expectation * 100),
+ 10, 5000, 50);
+ future_url->second.ReferrerWasObserved();
+ if (preconnect_enabled_ &&
+ connection_expectation > kPreconnectWorthyExpectedValue) {
+ evalution = PRECONNECTION;
+ future_url->second.IncrementPreconnectionCount();
+ int count = static_cast<int>(std::ceil(connection_expectation));
+ if (url.host() == future_url->first.host())
+ ++count;
+ PreconnectOnIOThread(future_url->first, motivation, count);
+ } else if (connection_expectation > kDNSPreresolutionWorthyExpectedValue) {
+ evalution = PRERESOLUTION;
+ future_url->second.preresolution_increment();
+ UrlInfo* queued_info = AppendToResolutionQueue(future_url->first,
+ motivation);
+ if (queued_info)
+ queued_info->SetReferringHostname(url);
+ }
+ UMA_HISTOGRAM_ENUMERATION("Net.PreconnectSubresourceEval", evalution,
+ SUBRESOURCE_VALUE_MAX);
}
- return true;
}
void Predictor::OnLookupFinished(LookupRequest* request, const GURL& url,
@@ -551,96 +951,79 @@ void Predictor::LookupFinished(LookupRequest* request, const GURL& url,
}
}
-void Predictor::DiscardAllResults() {
+UrlInfo* Predictor::AppendToResolutionQueue(
+ const GURL& url,
+ UrlInfo::ResolutionMotivation motivation) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- // Delete anything listed so far in this session that shows in about:dns.
- referrers_.clear();
+ DCHECK(url.has_host());
+ if (shutdown_)
+ return NULL;
- // Try to delete anything in our work queue.
- while (!work_queue_.IsEmpty()) {
- // Emulate processing cycle as though host was not found.
- GURL url = work_queue_.Pop();
- UrlInfo* info = &results_[url];
- DCHECK(info->HasUrl(url));
- info->SetAssignedState();
- info->SetNoSuchNameState();
- }
- // Now every result_ is either resolved, or is being resolved
- // (see LookupRequest).
+ UrlInfo* 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 :-/
- // Step through result_, recording names of all hosts that can't be erased.
- // We can't erase anything being worked on.
- Results assignees;
- for (Results::iterator it = results_.begin(); results_.end() != it; ++it) {
- GURL url(it->first);
- UrlInfo* info = &it->second;
- DCHECK(info->HasUrl(url));
- if (info->is_assigned()) {
- info->SetPendingDeleteState();
- assignees[url] = *info;
- }
- }
- DCHECK(assignees.size() <= max_concurrent_dns_lookups_);
- results_.clear();
- // Put back in the names being worked on.
- for (Results::iterator it = assignees.begin(); assignees.end() != it; ++it) {
- DCHECK(it->second.is_marked_to_delete());
- results_[it->first] = it->second;
+ DCHECK(info->HasUrl(url));
+
+ if (!info->NeedsDnsUpdate()) {
+ info->DLogResultsStats("DNS PrefetchNotUpdated");
+ return NULL;
}
-}
-void Predictor::TrimReferrersNow() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- // Just finish up work if an incremental trim is in progress.
- if (urls_being_trimmed_.empty())
- LoadUrlsForTrimming();
- IncrementalTrimReferrers(true); // Do everything now.
+ info->SetQueuedState(motivation);
+ work_queue_.Push(url, motivation);
+ StartSomeQueuedResolutions();
+ return info;
}
-void Predictor::SerializeReferrers(ListValue* referral_list) {
+bool Predictor::CongestionControlPerformed(UrlInfo* info) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- referral_list->Clear();
- referral_list->Append(new base::FundamentalValue(kPredictorReferrerVersion));
- for (Referrers::const_iterator it = referrers_.begin();
- it != referrers_.end(); ++it) {
- // Serialize the list of subresource names.
- Value* subresource_list(it->second.Serialize());
-
- // Create a list for each referer.
- ListValue* motivator(new ListValue);
- motivator->Append(new StringValue(it->first.spec()));
- motivator->Append(subresource_list);
-
- referral_list->Append(motivator);
+ // Note: queue_duration is ONLY valid after we go to assigned state.
+ if (info->queue_duration() < max_dns_queue_delay_)
+ return false;
+ // We need to discard all entries in our queue, as we're keeping them waiting
+ // too long. By doing this, we'll have a chance to quickly service urgent
+ // resolutions, and not have a bogged down system.
+ while (true) {
+ info->RemoveFromQueue();
+ if (work_queue_.IsEmpty())
+ break;
+ info = &results_[work_queue_.Pop()];
+ info->SetAssignedState();
}
+ return true;
}
-void Predictor::DeserializeReferrers(const ListValue& referral_list) {
+void Predictor::StartSomeQueuedResolutions() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- int format_version = -1;
- if (referral_list.GetSize() > 0 &&
- referral_list.GetInteger(0, &format_version) &&
- format_version == kPredictorReferrerVersion) {
- for (size_t i = 1; i < referral_list.GetSize(); ++i) {
- ListValue* motivator;
- if (!referral_list.GetList(i, &motivator)) {
- NOTREACHED();
- return;
- }
- std::string motivating_url_spec;
- if (!motivator->GetString(0, &motivating_url_spec)) {
- NOTREACHED();
- return;
- }
- Value* subresource_list;
- if (!motivator->Get(1, &subresource_list)) {
- NOTREACHED();
- return;
- }
+ while (!work_queue_.IsEmpty() &&
+ pending_lookups_.size() < max_concurrent_dns_lookups_) {
+ const GURL url(work_queue_.Pop());
+ UrlInfo* info = &results_[url];
+ DCHECK(info->HasUrl(url));
+ info->SetAssignedState();
- referrers_[GURL(motivating_url_spec)].Deserialize(*subresource_list);
+ if (CongestionControlPerformed(info)) {
+ DCHECK(work_queue_.IsEmpty());
+ return;
+ }
+
+ LookupRequest* request = new LookupRequest(this, host_resolver_, url);
+ int status = request->Start();
+ if (status == net::ERR_IO_PENDING) {
+ // Will complete asynchronously.
+ pending_lookups_.insert(request);
+ peak_pending_lookups_ = std::max(peak_pending_lookups_,
+ pending_lookups_.size());
+ } else {
+ // 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, url, status == net::OK);
+ delete request;
}
}
}
@@ -673,8 +1056,8 @@ void Predictor::PostIncrementalTrimTask() {
return;
MessageLoop::current()->PostDelayedTask(
FROM_HERE,
- trim_task_factory_.NewRunnableMethod(&Predictor::IncrementalTrimReferrers,
- false),
+ trim_task_factory_->NewRunnableMethod(
+ &Predictor::IncrementalTrimReferrers, false),
kDurationBetweenTrimmingIncrements.InMilliseconds());
}
@@ -693,7 +1076,9 @@ void Predictor::IncrementalTrimReferrers(bool trim_all_now) {
PostIncrementalTrimTask();
}
-//------------------------------------------------------------------------------
+// ---------------------- End IO methods. -------------------------------------
+
+//-----------------------------------------------------------------------------
Predictor::HostNameQueue::HostNameQueue() {
}
@@ -729,15 +1114,69 @@ GURL Predictor::HostNameQueue::Pop() {
return url;
}
-void Predictor::DeserializeReferrersThenDelete(ListValue* referral_list) {
- DeserializeReferrers(*referral_list);
- delete referral_list;
+//-----------------------------------------------------------------------------
+// Member definitions for InitialObserver class.
+
+Predictor::InitialObserver::InitialObserver() {
+}
+
+Predictor::InitialObserver::~InitialObserver() {
+}
+
+void Predictor::InitialObserver::Append(const GURL& url,
+ Predictor* predictor) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+ // TODO(rlp): Do we really need the predictor check here?
+ if (NULL == predictor)
+ return;
+ if (kStartupResolutionCount <= first_navigations_.size())
+ return;
+
+ DCHECK(url.SchemeIs("http") || url.SchemeIs("https"));
+ DCHECK_EQ(url, Predictor::CanonicalizeUrl(url));
+ if (first_navigations_.find(url) == first_navigations_.end())
+ first_navigations_[url] = base::TimeTicks::Now();
}
+void Predictor::InitialObserver::GetInitialDnsResolutionList(
+ base::ListValue* startup_list) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK(startup_list);
+ startup_list->Clear();
+ DCHECK_EQ(0u, startup_list->GetSize());
+ startup_list->Append(
+ new base::FundamentalValue(kPredictorStartupFormatVersion));
+ for (FirstNavigations::iterator it = first_navigations_.begin();
+ it != first_navigations_.end();
+ ++it) {
+ DCHECK(it->first == Predictor::CanonicalizeUrl(it->first));
+ startup_list->Append(new StringValue(it->first.spec()));
+ }
+}
-//------------------------------------------------------------------------------
+void Predictor::InitialObserver::GetFirstResolutionsHtml(
+ std::string* output) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+ UrlInfo::UrlInfoTable resolution_list;
+ {
+ for (FirstNavigations::iterator it(first_navigations_.begin());
+ it != first_navigations_.end();
+ it++) {
+ UrlInfo info;
+ info.SetUrl(it->first);
+ info.set_time(it->second);
+ resolution_list.push_back(info);
+ }
+ }
+ UrlInfo::GetHtmlTable(resolution_list,
+ "Future startups will prefetch DNS records for ", false, output);
+}
+
+//-----------------------------------------------------------------------------
// Helper functions
-//------------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
// static
GURL Predictor::CanonicalizeUrl(const GURL& url) {
@@ -763,5 +1202,14 @@ GURL Predictor::CanonicalizeUrl(const GURL& url) {
return GURL(scheme + "://" + url.host() + colon_plus_port);
}
+void SimplePredictor::InitNetworkPredictor(PrefService* user_prefs,
+ PrefService* local_state,
+ IOThread* io_thread) {
+ // Empty function for unittests.
+}
+
+void SimplePredictor::ShutdownOnUIThread(PrefService* user_prefs) {
+ SetShutdown(true);
+}
} // namespace chrome_browser_net
diff --git a/chrome/browser/net/predictor.h b/chrome/browser/net/predictor.h
index dcd8006..710b8ae 100644
--- a/chrome/browser/net/predictor.h
+++ b/chrome/browser/net/predictor.h
@@ -27,7 +27,7 @@
#include <vector>
#include "base/gtest_prod_util.h"
-#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
#include "chrome/browser/net/url_info.h"
#include "chrome/browser/net/referrer.h"
#include "chrome/common/net/predictor_common.h"
@@ -37,29 +37,97 @@ namespace base {
class ListValue;
}
+namespace base {
+class WaitableEvent;
+}
+
namespace net {
class HostResolver;
} // namespace net
+class IOThread;
+class PrefService;
+class Profile;
+
namespace chrome_browser_net {
typedef chrome_common_net::UrlList UrlList;
typedef chrome_common_net::NameList NameList;
typedef std::map<GURL, UrlInfo> Results;
-// Note that Predictor is not thread safe, and must only be called from
-// the IO thread. Failure to do so will result in a DCHECK at runtime.
-class Predictor : public base::RefCountedThreadSafe<Predictor> {
+// Predictor is constructed during Profile construction (on the UI thread),
+// but it is destroyed on the IO thread when ProfileIOData goes away. All of
+// its core state and functionality happens on the IO thread. The only UI
+// methods are initialization / shutdown related (including preconnect
+// initialization), or convenience methods that internally forward calls to
+// the IO thread.
+class Predictor {
public:
// 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 kPredictorReferrerVersion;
+ // Given that the underlying Chromium resolver defaults to a total maximum of
+ // 8 paralell resolutions, we will avoid any chance of starving navigational
+ // resolutions by limiting the number of paralell speculative resolutions.
+ // This is used in the field trials and testing.
+ // TODO(jar): Move this limitation into the resolver.
+ static const size_t kMaxSpeculativeParallelResolves;
+
+ // To control the congestion avoidance system, we need an estimate of how
+ // many speculative requests may arrive at once. Since we currently only
+ // keep 8 subresource names for each frame, we'll use that as our basis.
+ // Note that when scanning search results lists, we might actually get 10 at
+ // a time, and wikipedia can often supply (during a page scan) upwards of 50.
+ // In those odd cases, we may discard some of the later speculative requests
+ // mistakenly assuming that the resolutions took too long.
+ static const int kTypicalSpeculativeGroupSize;
+
+ // The next constant specifies an amount of queueing delay that is
+ // "too large," and indicative of problems with resolutions (perhaps due to
+ // an overloaded router, or such). When we exceed this delay, congestion
+ // avoidance will kick in and all speculations in the queue will be discarded.
+ static const int kMaxSpeculativeResolveQueueDelayMs;
+
// |max_concurrent| specifies how many concurrent (parallel) prefetches will
// be performed. Host lookups will be issued through |host_resolver|.
- Predictor(net::HostResolver* host_resolver,
- base::TimeDelta max_queue_delay_ms, size_t max_concurrent,
- bool preconnect_enabled);
+ explicit Predictor(bool preconnect_enabled);
+
+ virtual ~Predictor();
+
+ // This function is used to create a predictor. For testing, we can create
+ // a version which does a simpler shutdown.
+ static Predictor* CreatePredictor(bool preconnect_enabled,
+ bool simple_shutdown);
+
+ static void RegisterUserPrefs(PrefService* user_prefs);
+
+ // ------------- Start UI thread methods.
+
+ virtual void InitNetworkPredictor(PrefService* user_prefs,
+ PrefService* local_state,
+ IOThread* io_thread);
+
+ // The Omnibox has proposed a given url to the user, and if it is a search
+ // URL, then it also indicates that this is preconnectable (i.e., we could
+ // preconnect to the search server).
+ void AnticipateOmniboxUrl(const GURL& url, bool preconnectable);
+
+ // Preconnect a URL and all of its subresource domains.
+ void PreconnectUrlAndSubresources(const GURL& url);
+
+ static UrlList GetPredictedUrlListAtStartup(PrefService* user_prefs,
+ PrefService* local_state);
+
+ static void set_max_queueing_delay(int max_queueing_delay_ms);
+
+ static void set_max_parallel_resolves(size_t max_parallel_resolves);
+
+ virtual void ShutdownOnUIThread(PrefService* user_prefs);
+
+ // ------------- End UI thread methods.
+
+ // ------------- Start IO thread methods.
// Cancel pending requests and prevent new ones from being made.
void Shutdown();
@@ -74,23 +142,8 @@ class Predictor : public base::RefCountedThreadSafe<Predictor> {
// Add hostname(s) to the queue for processing.
void ResolveList(const UrlList& urls,
UrlInfo::ResolutionMotivation motivation);
- void Resolve(const GURL& url,
- UrlInfo::ResolutionMotivation motivation);
-
- // 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);
- // The Omnibox has proposed a given url to the user, and if it is a search
- // URL, then it also indicates that this is preconnectable (i.e., we could
- // preconnect to the search server).
- void AnticipateOmniboxUrl(const GURL& url, bool preconnectable);
-
- // Preconnect a URL and all of its subresource domains.
- void PreconnectUrlAndSubresources(const GURL& url);
+ void Resolve(const GURL& url, UrlInfo::ResolutionMotivation motivation);
// 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.
@@ -98,11 +151,14 @@ class Predictor : public base::RefCountedThreadSafe<Predictor> {
// canonicalized to not have a path.
void LearnFromNavigation(const GURL& referring_url, const GURL& target_url);
+ // When displaying info in about:dns, the following API is called.
+ static void PredictorGetHtmlInfo(Predictor* predictor, std::string* output);
+
// Dump HTML table containing list of referrers for about:dns.
void GetHtmlReferrerLists(std::string* output);
// Dump the list of currently known referrer domains and related prefetchable
- // domains.
+ // domains for about:dns.
void GetHtmlInfo(std::string* output);
// Discards any referrer for which all the suggested host names are currently
@@ -124,21 +180,83 @@ class Predictor : public base::RefCountedThreadSafe<Predictor> {
void DeserializeReferrersThenDelete(base::ListValue* referral_list);
- // For unit test code only.
- size_t max_concurrent_dns_lookups() const {
- return max_concurrent_dns_lookups_;
- }
+ void DiscardInitialNavigationHistory();
- // Flag setting to use preconnection instead of just DNS pre-fetching.
- bool preconnect_enabled() const { return preconnect_enabled_; }
+ void FinalizeInitializationOnIOThread(
+ const std::vector<GURL>& urls_to_prefetch,
+ base::ListValue* referral_list,
+ IOThread* io_thread,
+ bool predictor_enabled);
+
+ // During startup, we learn what the first N urls visited are, and then
+ // resolve the associated hosts ASAP during our next startup.
+ void LearnAboutInitialNavigation(const GURL& url);
+
+ // 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);
+
+ // May be called from either the IO or UI thread and will PostTask
+ // to the IO thread if necessary.
+ void DnsPrefetchMotivatedList(const UrlList& urls,
+ UrlInfo::ResolutionMotivation motivation);
+
+ // May be called from either the IO or UI thread and will PostTask
+ // to the IO thread if necessary.
+ void SaveStateForNextStartupAndTrim(PrefService* prefs);
+
+ void SaveDnsPrefetchStateForNextStartupAndTrim(
+ base::ListValue* startup_list,
+ base::ListValue* referral_list,
+ base::WaitableEvent* completion);
+
+ // May be called from either the IO or UI thread and will PostTask
+ // to the IO thread if necessary.
+ void EnablePredictor(bool enable);
+
+ void EnablePredictorOnIOThread(bool enable);
+
+ // ------------- End IO thread methods.
+
+ // The following methods may be called on either the IO or UI threads.
+
+ // 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);
// 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);
+ // Used for testing.
+ void SetHostResolver(net::HostResolver* host_resolver) {
+ host_resolver_ = host_resolver;
+ }
+ // Used for testing.
+ size_t max_concurrent_dns_lookups() const {
+ return max_concurrent_dns_lookups_;
+ }
+ // Used for testing.
+ void SetShutdown(bool shutdown) {
+ shutdown_ = shutdown;
+ }
+
+ // Flag setting to use preconnection instead of just DNS pre-fetching.
+ bool preconnect_enabled() const {
+ return preconnect_enabled_;
+ }
+
+ // Flag setting for whether we are prefetching dns lookups.
+ bool predictor_enabled() const {
+ return predictor_enabled_;
+ }
+
+
private:
- friend class base::RefCountedThreadSafe<Predictor>;
FRIEND_TEST_ALL_PREFIXES(PredictorTest, BenefitLookupTest);
FRIEND_TEST_ALL_PREFIXES(PredictorTest, ShutdownWhenResolutionIsPendingTest);
FRIEND_TEST_ALL_PREFIXES(PredictorTest, SingleLookupTest);
@@ -178,6 +296,38 @@ class Predictor : public base::RefCountedThreadSafe<Predictor> {
DISALLOW_COPY_AND_ASSIGN(HostNameQueue);
};
+ // The InitialObserver monitors navigations made by the network stack. This
+ // is only used to identify startup time resolutions (for re-resolution
+ // during our next process startup).
+ // TODO(jar): Consider preconnecting at startup, which may be faster than
+ // waiting for render process to start and request a connection.
+ class InitialObserver {
+ public:
+ InitialObserver();
+ ~InitialObserver();
+ // Recording of when we observed each navigation.
+ typedef std::map<GURL, base::TimeTicks> FirstNavigations;
+
+ // Potentially add a new URL to our startup list.
+ void Append(const GURL& url, Predictor* predictor);
+
+ // Get an HTML version of our current planned first_navigations_.
+ void GetFirstResolutionsHtml(std::string* output);
+
+ // Persist the current first_navigations_ for storage in a list.
+ void GetInitialDnsResolutionList(base::ListValue* startup_list);
+
+ // Discards all initial loading history.
+ void DiscardInitialNavigationHistory() { first_navigations_.clear(); }
+
+ private:
+ // List of the first N URL resolutions observed in this run.
+ FirstNavigations first_navigations_;
+
+ // The number of URLs we'll save for pre-resolving at next startup.
+ static const size_t kStartupResolutionCount = 10;
+ };
+
// 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.
@@ -206,13 +356,6 @@ class Predictor : public base::RefCountedThreadSafe<Predictor> {
// Number of referring URLs processed in an incremental trimming.
static const size_t kUrlsTrimmedPerIncrement;
- ~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 {
@@ -232,6 +375,13 @@ class Predictor : public base::RefCountedThreadSafe<Predictor> {
// Only for testing;
size_t peak_pending_lookups() const { return peak_pending_lookups_; }
+ // ------------- Start IO thread methods.
+
+ // 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);
+
// Access method for use by async lookup request to pass resolution result.
void OnLookupFinished(LookupRequest* request, const GURL& url, bool found);
@@ -277,6 +427,14 @@ class Predictor : public base::RefCountedThreadSafe<Predictor> {
// continue with them shortly (i.e., it yeilds and continues).
void IncrementalTrimReferrers(bool trim_all_now);
+ // ------------- End IO thread methods.
+
+ scoped_ptr<InitialObserver> initial_observer_;
+
+ // Status of speculative DNS resolution and speculative TCP/IP connection
+ // feature.
+ bool predictor_enabled_;
+
// work_queue_ holds a list of names we need to look up.
HostNameQueue work_queue_;
@@ -302,7 +460,7 @@ class Predictor : public base::RefCountedThreadSafe<Predictor> {
const base::TimeDelta max_dns_queue_delay_;
// The host resolver we warm DNS entries for.
- net::HostResolver* const host_resolver_;
+ net::HostResolver* host_resolver_;
// Are we currently using preconnection, rather than just DNS resolution, for
// subresources and omni-box search URLs.
@@ -334,11 +492,23 @@ class Predictor : public base::RefCountedThreadSafe<Predictor> {
// A time after which we need to do more trimming of referrers.
base::TimeTicks next_trim_time_;
- ScopedRunnableMethodFactory<Predictor> trim_task_factory_;
+ scoped_ptr<ScopedRunnableMethodFactory<Predictor> > trim_task_factory_;
DISALLOW_COPY_AND_ASSIGN(Predictor);
};
+// This version of the predictor is used for testing.
+class SimplePredictor : public Predictor {
+ public:
+ explicit SimplePredictor(bool preconnect_enabled)
+ : Predictor(preconnect_enabled) {}
+ virtual ~SimplePredictor() {}
+ virtual void InitNetworkPredictor(PrefService* user_prefs,
+ PrefService* local_state,
+ IOThread* io_thread);
+ virtual void ShutdownOnUIThread(PrefService* user_prefs);
+};
+
} // namespace chrome_browser_net
#endif // CHROME_BROWSER_NET_PREDICTOR_H_
diff --git a/chrome/browser/net/predictor_unittest.cc b/chrome/browser/net/predictor_unittest.cc
index 23b4ca0..c2426c8 100644
--- a/chrome/browser/net/predictor_unittest.cc
+++ b/chrome/browser/net/predictor_unittest.cc
@@ -13,7 +13,7 @@
#include "base/string_number_conversions.h"
#include "base/timer.h"
#include "base/values.h"
-#include "chrome/browser/net/predictor_api.h"
+#include "chrome/browser/net/predictor.h"
#include "chrome/browser/net/url_info.h"
#include "chrome/common/net/predictor_common.h"
#include "content/browser/browser_thread.h"
@@ -62,10 +62,9 @@ class WaitForResolutionHelper {
class PredictorTest : public testing::Test {
public:
PredictorTest()
- : io_thread_(BrowserThread::IO, &loop_),
- host_resolver_(new net::MockCachingHostResolver()),
- default_max_queueing_delay_(TimeDelta::FromMilliseconds(
- PredictorInit::kMaxSpeculativeResolveQueueDelayMs)) {
+ : ui_thread_(BrowserThread::UI, &loop_),
+ io_thread_(BrowserThread::IO, &loop_),
+ host_resolver_(new net::MockCachingHostResolver()) {
}
protected:
@@ -73,6 +72,10 @@ class PredictorTest : public testing::Test {
#if defined(OS_WIN)
net::EnsureWinsockInit();
#endif
+ Predictor::set_max_parallel_resolves(
+ Predictor::kMaxSpeculativeParallelResolves);
+ Predictor::set_max_queueing_delay(
+ Predictor::kMaxSpeculativeResolveQueueDelayMs);
// Since we are using a caching HostResolver, the following latencies will
// only be incurred by the first request, after which the result will be
// cached internally by |host_resolver_|.
@@ -95,26 +98,19 @@ class PredictorTest : public testing::Test {
// IMPORTANT: do not move this below |host_resolver_|; the host resolver
// must not outlive the message loop, otherwise bad things can happen
// (like posting to a deleted message loop).
- MessageLoop loop_;
+ MessageLoopForUI loop_;
+ BrowserThread ui_thread_;
BrowserThread io_thread_;
protected:
scoped_ptr<net::MockCachingHostResolver> host_resolver_;
-
- // Shorthand to access TimeDelta of PredictorInit::kMaxQueueingDelayMs.
- // (It would be a static constant... except style rules preclude that :-/ ).
- const TimeDelta default_max_queueing_delay_;
};
//------------------------------------------------------------------------------
TEST_F(PredictorTest, StartupShutdownTest) {
- scoped_refptr<Predictor> testing_master(
- new Predictor(host_resolver_.get(),
- default_max_queueing_delay_,
- PredictorInit::kMaxSpeculativeParallelResolves,
- false));
- testing_master->Shutdown();
+ Predictor testing_master(true);
+ testing_master.Shutdown();
}
@@ -123,25 +119,22 @@ TEST_F(PredictorTest, ShutdownWhenResolutionIsPendingTest) {
new net::WaitingHostResolverProc(NULL));
host_resolver_->Reset(resolver_proc);
- scoped_refptr<Predictor> testing_master(
- new Predictor(host_resolver_.get(),
- default_max_queueing_delay_,
- PredictorInit::kMaxSpeculativeParallelResolves,
- false));
+ Predictor testing_master(true);
+ testing_master.SetHostResolver(host_resolver_.get());
GURL localhost("http://localhost:80");
UrlList names;
names.push_back(localhost);
- testing_master->ResolveList(names, UrlInfo::PAGE_SCAN_MOTIVATED);
+ testing_master.ResolveList(names, UrlInfo::PAGE_SCAN_MOTIVATED);
MessageLoop::current()->PostDelayedTask(FROM_HERE,
new MessageLoop::QuitTask(), 500);
MessageLoop::current()->Run();
- EXPECT_FALSE(testing_master->WasFound(localhost));
+ EXPECT_FALSE(testing_master.WasFound(localhost));
- testing_master->Shutdown();
+ testing_master.Shutdown();
// Clean up after ourselves.
resolver_proc->Signal();
@@ -149,11 +142,8 @@ TEST_F(PredictorTest, ShutdownWhenResolutionIsPendingTest) {
}
TEST_F(PredictorTest, SingleLookupTest) {
- scoped_refptr<Predictor> testing_master(
- new Predictor(host_resolver_.get(),
- default_max_queueing_delay_,
- PredictorInit::kMaxSpeculativeParallelResolves,
- false));
+ Predictor testing_master(true);
+ testing_master.SetHostResolver(host_resolver_.get());
GURL goog("http://www.google.com:80");
@@ -162,30 +152,27 @@ TEST_F(PredictorTest, SingleLookupTest) {
// Try to flood the predictor with many concurrent requests.
for (int i = 0; i < 10; i++)
- testing_master->ResolveList(names, UrlInfo::PAGE_SCAN_MOTIVATED);
+ testing_master.ResolveList(names, UrlInfo::PAGE_SCAN_MOTIVATED);
- WaitForResolution(testing_master, names);
+ WaitForResolution(&testing_master, names);
- EXPECT_TRUE(testing_master->WasFound(goog));
+ EXPECT_TRUE(testing_master.WasFound(goog));
MessageLoop::current()->RunAllPending();
- EXPECT_GT(testing_master->peak_pending_lookups(), names.size() / 2);
- EXPECT_LE(testing_master->peak_pending_lookups(), names.size());
- EXPECT_LE(testing_master->peak_pending_lookups(),
- testing_master->max_concurrent_dns_lookups());
+ EXPECT_GT(testing_master.peak_pending_lookups(), names.size() / 2);
+ EXPECT_LE(testing_master.peak_pending_lookups(), names.size());
+ EXPECT_LE(testing_master.peak_pending_lookups(),
+ testing_master.max_concurrent_dns_lookups());
- testing_master->Shutdown();
+ testing_master.Shutdown();
}
TEST_F(PredictorTest, ConcurrentLookupTest) {
host_resolver_->rules()->AddSimulatedFailure("*.notfound");
- scoped_refptr<Predictor> testing_master(
- new Predictor(host_resolver_.get(),
- default_max_queueing_delay_,
- PredictorInit::kMaxSpeculativeParallelResolves,
- false));
+ Predictor testing_master(true);
+ testing_master.SetHostResolver(host_resolver_.get());
GURL goog("http://www.google.com:80"),
goog2("http://gmail.google.com.com:80"),
@@ -205,37 +192,34 @@ TEST_F(PredictorTest, ConcurrentLookupTest) {
// Try to flood the predictor with many concurrent requests.
for (int i = 0; i < 10; i++)
- testing_master->ResolveList(names, UrlInfo::PAGE_SCAN_MOTIVATED);
+ testing_master.ResolveList(names, UrlInfo::PAGE_SCAN_MOTIVATED);
- WaitForResolution(testing_master, names);
+ WaitForResolution(&testing_master, names);
- EXPECT_TRUE(testing_master->WasFound(goog));
- EXPECT_TRUE(testing_master->WasFound(goog3));
- EXPECT_TRUE(testing_master->WasFound(goog2));
- EXPECT_TRUE(testing_master->WasFound(goog4));
- EXPECT_FALSE(testing_master->WasFound(bad1));
- EXPECT_FALSE(testing_master->WasFound(bad2));
+ EXPECT_TRUE(testing_master.WasFound(goog));
+ EXPECT_TRUE(testing_master.WasFound(goog3));
+ EXPECT_TRUE(testing_master.WasFound(goog2));
+ EXPECT_TRUE(testing_master.WasFound(goog4));
+ EXPECT_FALSE(testing_master.WasFound(bad1));
+ EXPECT_FALSE(testing_master.WasFound(bad2));
MessageLoop::current()->RunAllPending();
- EXPECT_FALSE(testing_master->WasFound(bad1));
- EXPECT_FALSE(testing_master->WasFound(bad2));
+ EXPECT_FALSE(testing_master.WasFound(bad1));
+ EXPECT_FALSE(testing_master.WasFound(bad2));
- EXPECT_LE(testing_master->peak_pending_lookups(), names.size());
- EXPECT_LE(testing_master->peak_pending_lookups(),
- testing_master->max_concurrent_dns_lookups());
+ EXPECT_LE(testing_master.peak_pending_lookups(), names.size());
+ EXPECT_LE(testing_master.peak_pending_lookups(),
+ testing_master.max_concurrent_dns_lookups());
- testing_master->Shutdown();
+ testing_master.Shutdown();
}
TEST_F(PredictorTest, MassiveConcurrentLookupTest) {
host_resolver_->rules()->AddSimulatedFailure("*.notfound");
- scoped_refptr<Predictor> testing_master(
- new Predictor(host_resolver_.get(),
- default_max_queueing_delay_,
- PredictorInit::kMaxSpeculativeParallelResolves,
- false));
+ Predictor testing_master(true);
+ testing_master.SetHostResolver(host_resolver_.get());
UrlList names;
for (int i = 0; i < 100; i++)
@@ -244,17 +228,17 @@ TEST_F(PredictorTest, MassiveConcurrentLookupTest) {
// Try to flood the predictor with many concurrent requests.
for (int i = 0; i < 10; i++)
- testing_master->ResolveList(names, UrlInfo::PAGE_SCAN_MOTIVATED);
+ testing_master.ResolveList(names, UrlInfo::PAGE_SCAN_MOTIVATED);
- WaitForResolution(testing_master, names);
+ WaitForResolution(&testing_master, names);
MessageLoop::current()->RunAllPending();
- EXPECT_LE(testing_master->peak_pending_lookups(), names.size());
- EXPECT_LE(testing_master->peak_pending_lookups(),
- testing_master->max_concurrent_dns_lookups());
+ EXPECT_LE(testing_master.peak_pending_lookups(), names.size());
+ EXPECT_LE(testing_master.peak_pending_lookups(),
+ testing_master.max_concurrent_dns_lookups());
- testing_master->Shutdown();
+ testing_master.Shutdown();
}
//------------------------------------------------------------------------------
@@ -352,30 +336,25 @@ static bool GetDataFromSerialization(const GURL& motivation,
// Make sure nil referral lists really have no entries, and no latency listed.
TEST_F(PredictorTest, ReferrerSerializationNilTest) {
- scoped_refptr<Predictor> predictor(
- new Predictor(host_resolver_.get(),
- default_max_queueing_delay_,
- PredictorInit::kMaxSpeculativeParallelResolves,
- false));
+ Predictor predictor(true);
+ predictor.SetHostResolver(host_resolver_.get());
+
scoped_ptr<ListValue> referral_list(NewEmptySerializationList());
- predictor->SerializeReferrers(referral_list.get());
+ predictor.SerializeReferrers(referral_list.get());
EXPECT_EQ(1U, referral_list->GetSize());
EXPECT_FALSE(GetDataFromSerialization(
GURL("http://a.com:79"), GURL("http://b.com:78"),
*referral_list.get(), NULL));
- predictor->Shutdown();
+ predictor.Shutdown();
}
// Make sure that when a serialization list includes a value, that it can be
// deserialized into the database, and can be extracted back out via
// serialization without being changed.
TEST_F(PredictorTest, ReferrerSerializationSingleReferrerTest) {
- scoped_refptr<Predictor> predictor(
- new Predictor(host_resolver_.get(),
- default_max_queueing_delay_,
- PredictorInit::kMaxSpeculativeParallelResolves,
- false));
+ Predictor predictor(true);
+ predictor.SetHostResolver(host_resolver_.get());
const GURL motivation_url("http://www.google.com:91");
const GURL subresource_url("http://icons.google.com:90");
const double kUseRate = 23.4;
@@ -384,17 +363,17 @@ TEST_F(PredictorTest, ReferrerSerializationSingleReferrerTest) {
AddToSerializedList(motivation_url, subresource_url,
kUseRate, referral_list.get());
- predictor->DeserializeReferrers(*referral_list.get());
+ predictor.DeserializeReferrers(*referral_list.get());
ListValue recovered_referral_list;
- predictor->SerializeReferrers(&recovered_referral_list);
+ predictor.SerializeReferrers(&recovered_referral_list);
EXPECT_EQ(2U, recovered_referral_list.GetSize());
double rate;
EXPECT_TRUE(GetDataFromSerialization(
motivation_url, subresource_url, recovered_referral_list, &rate));
EXPECT_EQ(rate, kUseRate);
- predictor->Shutdown();
+ predictor.Shutdown();
}
// Verify that two floats are within 1% of each other in value.
@@ -409,11 +388,8 @@ TEST_F(PredictorTest, ReferrerSerializationSingleReferrerTest) {
// Make sure the Trim() functionality works as expected.
TEST_F(PredictorTest, ReferrerSerializationTrimTest) {
- scoped_refptr<Predictor> predictor(
- new Predictor(host_resolver_.get(),
- default_max_queueing_delay_,
- PredictorInit::kMaxSpeculativeParallelResolves,
- false));
+ Predictor predictor(true);
+ predictor.SetHostResolver(host_resolver_.get());
GURL motivation_url("http://www.google.com:110");
GURL icon_subresource_url("http://icons.google.com:111");
@@ -427,10 +403,10 @@ TEST_F(PredictorTest, ReferrerSerializationTrimTest) {
AddToSerializedList(
motivation_url, img_subresource_url, kRateImg, referral_list.get());
- predictor->DeserializeReferrers(*referral_list.get());
+ predictor.DeserializeReferrers(*referral_list.get());
ListValue recovered_referral_list;
- predictor->SerializeReferrers(&recovered_referral_list);
+ predictor.SerializeReferrers(&recovered_referral_list);
EXPECT_EQ(2U, recovered_referral_list.GetSize());
double rate;
EXPECT_TRUE(GetDataFromSerialization(
@@ -445,8 +421,8 @@ TEST_F(PredictorTest, ReferrerSerializationTrimTest) {
// Each time we Trim 24 times, the user_rate figures should reduce by a factor
// of two, until they are small, and then a trim will delete the whole entry.
for (int i = 0; i < 24; ++i)
- predictor->TrimReferrersNow();
- predictor->SerializeReferrers(&recovered_referral_list);
+ predictor.TrimReferrersNow();
+ predictor.SerializeReferrers(&recovered_referral_list);
EXPECT_EQ(2U, recovered_referral_list.GetSize());
EXPECT_TRUE(GetDataFromSerialization(
motivation_url, icon_subresource_url, recovered_referral_list, &rate));
@@ -457,8 +433,8 @@ TEST_F(PredictorTest, ReferrerSerializationTrimTest) {
EXPECT_SIMILAR(rate, kRateImg / 2);
for (int i = 0; i < 24; ++i)
- predictor->TrimReferrersNow();
- predictor->SerializeReferrers(&recovered_referral_list);
+ predictor.TrimReferrersNow();
+ predictor.SerializeReferrers(&recovered_referral_list);
EXPECT_EQ(2U, recovered_referral_list.GetSize());
EXPECT_TRUE(GetDataFromSerialization(
motivation_url, icon_subresource_url, recovered_referral_list, &rate));
@@ -468,8 +444,8 @@ TEST_F(PredictorTest, ReferrerSerializationTrimTest) {
EXPECT_SIMILAR(rate, kRateImg / 4);
for (int i = 0; i < 24; ++i)
- predictor->TrimReferrersNow();
- predictor->SerializeReferrers(&recovered_referral_list);
+ predictor.TrimReferrersNow();
+ predictor.SerializeReferrers(&recovered_referral_list);
EXPECT_EQ(2U, recovered_referral_list.GetSize());
EXPECT_TRUE(GetDataFromSerialization(
motivation_url, icon_subresource_url, recovered_referral_list, &rate));
@@ -480,8 +456,8 @@ TEST_F(PredictorTest, ReferrerSerializationTrimTest) {
motivation_url, img_subresource_url, recovered_referral_list, &rate));
for (int i = 0; i < 24; ++i)
- predictor->TrimReferrersNow();
- predictor->SerializeReferrers(&recovered_referral_list);
+ predictor.TrimReferrersNow();
+ predictor.SerializeReferrers(&recovered_referral_list);
// Icon is also trimmed away, so entire set gets discarded.
EXPECT_EQ(1U, recovered_referral_list.GetSize());
EXPECT_FALSE(GetDataFromSerialization(
@@ -489,7 +465,7 @@ TEST_F(PredictorTest, ReferrerSerializationTrimTest) {
EXPECT_FALSE(GetDataFromSerialization(
motivation_url, img_subresource_url, recovered_referral_list, &rate));
- predictor->Shutdown();
+ predictor.Shutdown();
}
@@ -601,27 +577,24 @@ TEST_F(PredictorTest, CanonicalizeUrl) {
}
TEST_F(PredictorTest, DiscardPredictorResults) {
- scoped_refptr<Predictor> predictor(
- new Predictor(host_resolver_.get(),
- default_max_queueing_delay_,
- PredictorInit::kMaxSpeculativeParallelResolves,
- false));
+ Predictor predictor(true);
+ predictor.SetHostResolver(host_resolver_.get());
ListValue referral_list;
- predictor->SerializeReferrers(&referral_list);
+ predictor.SerializeReferrers(&referral_list);
EXPECT_EQ(1U, referral_list.GetSize());
GURL host_1("http://test_1");
GURL host_2("http://test_2");
- predictor->LearnFromNavigation(host_1, host_2);
+ predictor.LearnFromNavigation(host_1, host_2);
- predictor->SerializeReferrers(&referral_list);
+ predictor.SerializeReferrers(&referral_list);
EXPECT_EQ(2U, referral_list.GetSize());
- predictor->DiscardAllResults();
- predictor->SerializeReferrers(&referral_list);
+ predictor.DiscardAllResults();
+ predictor.SerializeReferrers(&referral_list);
EXPECT_EQ(1U, referral_list.GetSize());
- predictor->Shutdown();
+ predictor.Shutdown();
}
} // namespace chrome_browser_net
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index d4d3daa..56ba81e 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -27,7 +27,7 @@
#include "chrome/browser/metrics/metrics_log.h"
#include "chrome/browser/metrics/metrics_service.h"
#include "chrome/browser/net/net_pref_observer.h"
-#include "chrome/browser/net/predictor_api.h"
+#include "chrome/browser/net/predictor.h"
#include "chrome/browser/net/pref_proxy_config_service.h"
#include "chrome/browser/net/ssl_config_service_manager.h"
#include "chrome/browser/notifications/desktop_notification_service.h"
@@ -146,7 +146,7 @@ void RegisterUserPrefs(PrefService* user_prefs) {
BookmarkModel::RegisterUserPrefs(user_prefs);
Browser::RegisterUserPrefs(user_prefs);
PasswordManager::RegisterUserPrefs(user_prefs);
- chrome_browser_net::RegisterUserPrefs(user_prefs);
+ chrome_browser_net::Predictor::RegisterUserPrefs(user_prefs);
DownloadPrefs::RegisterUserPrefs(user_prefs);
bookmark_utils::RegisterUserPrefs(user_prefs);
TabContentsWrapper::RegisterUserPrefs(user_prefs);
diff --git a/chrome/browser/profiles/profile.cc b/chrome/browser/profiles/profile.cc
index 22d1e85..23b24d3 100644
--- a/chrome/browser/profiles/profile.cc
+++ b/chrome/browser/profiles/profile.cc
@@ -225,3 +225,7 @@ bool Profile::IsSyncAccessible() {
ProfileSyncService* syncService = GetProfileSyncService();
return syncService && !syncService->IsManaged();
}
+
+chrome_browser_net::Predictor* Profile::GetNetworkPredictor() {
+ return NULL;
+}
diff --git a/chrome/browser/profiles/profile.h b/chrome/browser/profiles/profile.h
index c2ba480..2cd49e4 100644
--- a/chrome/browser/profiles/profile.h
+++ b/chrome/browser/profiles/profile.h
@@ -52,6 +52,10 @@ namespace speech_input {
class SpeechRecognizer;
}
+namespace chrome_browser_net {
+class Predictor;
+}
+
class AutocompleteClassifier;
class BookmarkModel;
class ChromeAppCacheService;
@@ -543,6 +547,8 @@ class Profile : public content::BrowserContext {
// Creates an OffTheRecordProfile which points to this Profile.
Profile* CreateOffTheRecordProfile();
+ virtual chrome_browser_net::Predictor* GetNetworkPredictor();
+
protected:
friend class OffTheRecordProfileImpl;
diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc
index 02a9374..af5435f 100644
--- a/chrome/browser/profiles/profile_impl.cc
+++ b/chrome/browser/profiles/profile_impl.cc
@@ -47,6 +47,7 @@
#include "chrome/browser/net/chrome_url_request_context.h"
#include "chrome/browser/net/gaia/token_service.h"
#include "chrome/browser/net/net_pref_observer.h"
+#include "chrome/browser/net/predictor.h"
#include "chrome/browser/net/pref_proxy_config_service.h"
#include "chrome/browser/net/ssl_config_service_manager.h"
#include "chrome/browser/password_manager/password_store_default.h"
@@ -308,7 +309,8 @@ ProfileImpl::ProfileImpl(const FilePath& path,
#if defined(OS_WIN)
checked_instant_promo_(false),
#endif
- delegate_(delegate) {
+ delegate_(delegate),
+ predictor_(NULL) {
DCHECK(!path.empty()) << "Using an empty path will attempt to write " <<
"profile files to the root directory!";
@@ -316,6 +318,13 @@ ProfileImpl::ProfileImpl(const FilePath& path,
TimeDelta::FromMilliseconds(kCreateSessionServiceDelayMS), this,
&ProfileImpl::EnsureSessionServiceCreated);
+ // Determine if prefetch is enabled for this profile.
+ // If not profile_manager is present, it means we are in a unittest.
+ const CommandLine* command_line = CommandLine::ForCurrentProcess();
+ predictor_ = chrome_browser_net::Predictor::CreatePredictor(
+ !command_line->HasSwitch(switches::kDisablePreconnect),
+ g_browser_process->profile_manager() == NULL);
+
if (delegate_) {
prefs_.reset(PrefService::CreatePrefService(
GetPrefFilePath(),
@@ -436,9 +445,12 @@ void ProfileImpl::DoFinalInit() {
// Make sure we initialize the ProfileIOData after everything else has been
// initialized that we might be reading from the IO thread.
+
io_data_.Init(cookie_path, origin_bound_cert_path, cache_path,
cache_max_size, media_cache_path, media_cache_max_size,
- extensions_cookie_path, app_path);
+ extensions_cookie_path, app_path, predictor_,
+ g_browser_process->local_state(),
+ g_browser_process->io_thread());
ChromePluginServiceFilter::GetInstance()->RegisterResourceContext(
PluginPrefs::GetForProfile(this), &GetResourceContext());
@@ -922,7 +934,7 @@ void ProfileImpl::OnPrefsLoaded(bool success) {
DCHECK(!net_pref_observer_.get());
net_pref_observer_.reset(
- new NetPrefObserver(prefs_.get(), GetPrerenderManager()));
+ new NetPrefObserver(prefs_.get(), GetPrerenderManager(), predictor_));
DoFinalInit();
}
@@ -1739,6 +1751,10 @@ prerender::PrerenderManager* ProfileImpl::GetPrerenderManager() {
return prerender_manager_.get();
}
+chrome_browser_net::Predictor* ProfileImpl::GetNetworkPredictor() {
+ return predictor_;
+}
+
SpellCheckProfile* ProfileImpl::GetSpellCheckProfile() {
if (!spellcheck_profile_.get())
spellcheck_profile_.reset(new SpellCheckProfile());
diff --git a/chrome/browser/profiles/profile_impl.h b/chrome/browser/profiles/profile_impl.h
index cdc2985..850b421 100644
--- a/chrome/browser/profiles/profile_impl.h
+++ b/chrome/browser/profiles/profile_impl.h
@@ -122,6 +122,7 @@ class ProfileImpl : public Profile,
virtual ExtensionInfoMap* GetExtensionInfoMap();
virtual PromoCounter* GetInstantPromoCounter();
virtual ChromeURLDataManager* GetChromeURLDataManager();
+ virtual chrome_browser_net::Predictor* GetNetworkPredictor();
#if defined(OS_CHROMEOS)
virtual void ChangeAppLocale(const std::string& locale, AppLocaleChangedVia);
@@ -290,6 +291,8 @@ class ProfileImpl : public Profile,
Profile::Delegate* delegate_;
+ chrome_browser_net::Predictor* predictor_;
+
DISALLOW_COPY_AND_ASSIGN(ProfileImpl);
};
diff --git a/chrome/browser/profiles/profile_impl_io_data.cc b/chrome/browser/profiles/profile_impl_io_data.cc
index 8ef2f4a..c523c25 100644
--- a/chrome/browser/profiles/profile_impl_io_data.cc
+++ b/chrome/browser/profiles/profile_impl_io_data.cc
@@ -12,6 +12,8 @@
#include "chrome/browser/io_thread.h"
#include "chrome/browser/net/chrome_net_log.h"
#include "chrome/browser/net/chrome_network_delegate.h"
+#include "chrome/browser/net/connect_interceptor.h"
+#include "chrome/browser/net/predictor.h"
#include "chrome/browser/net/sqlite_origin_bound_cert_store.h"
#include "chrome/browser/net/sqlite_persistent_cookie_store.h"
#include "chrome/browser/prefs/pref_member.h"
@@ -25,6 +27,7 @@
#include "net/base/origin_bound_cert_service.h"
#include "net/ftp/ftp_network_layer.h"
#include "net/http/http_cache.h"
+#include "net/url_request/url_request_job_factory.h"
ProfileImplIOData::Handle::Handle(Profile* profile)
: io_data_(new ProfileImplIOData),
@@ -43,6 +46,8 @@ ProfileImplIOData::Handle::~Handle() {
if (extensions_request_context_getter_)
extensions_request_context_getter_->CleanupOnUIThread();
+ io_data_->predictor_->ShutdownOnUIThread(profile_->GetPrefs());
+
// Clean up all isolated app request contexts.
for (ChromeURLRequestContextGetterMap::iterator iter =
app_request_context_getter_map_.begin();
@@ -54,16 +59,22 @@ ProfileImplIOData::Handle::~Handle() {
io_data_->ShutdownOnUIThread();
}
-void ProfileImplIOData::Handle::Init(const FilePath& cookie_path,
- const FilePath& origin_bound_cert_path,
- const FilePath& cache_path,
- int cache_max_size,
- const FilePath& media_cache_path,
- int media_cache_max_size,
- const FilePath& extensions_cookie_path,
- const FilePath& app_path) {
+void ProfileImplIOData::Handle::Init(
+ const FilePath& cookie_path,
+ const FilePath& origin_bound_cert_path,
+ const FilePath& cache_path,
+ int cache_max_size,
+ const FilePath& media_cache_path,
+ int media_cache_max_size,
+ const FilePath& extensions_cookie_path,
+ const FilePath& app_path,
+ chrome_browser_net::Predictor* predictor,
+ PrefService* local_state,
+ IOThread* io_thread) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(!io_data_->lazy_params_.get());
+ DCHECK(predictor);
+
LazyParams* lazy_params = new LazyParams;
lazy_params->cookie_path = cookie_path;
@@ -78,6 +89,11 @@ void ProfileImplIOData::Handle::Init(const FilePath& cookie_path,
// Keep track of isolated app path separately so we can use it on demand.
io_data_->app_path_ = app_path;
+
+ io_data_->predictor_.reset(predictor);
+ io_data_->predictor_->InitNetworkPredictor(profile_->GetPrefs(),
+ local_state,
+ io_thread);
}
base::Callback<ChromeURLDataManagerBackend*(void)>
@@ -336,6 +352,9 @@ void ProfileImplIOData::LazyInitializeInternal(
media_request_context_->set_job_factory(job_factory());
extensions_context->set_job_factory(job_factory());
+ job_factory()->AddInterceptor(
+ new chrome_browser_net::ConnectInterceptor(predictor_.get()));
+
lazy_params_.reset();
}
diff --git a/chrome/browser/profiles/profile_impl_io_data.h b/chrome/browser/profiles/profile_impl_io_data.h
index 6a5f531..e0f61ff 100644
--- a/chrome/browser/profiles/profile_impl_io_data.h
+++ b/chrome/browser/profiles/profile_impl_io_data.h
@@ -12,6 +12,10 @@
#include "base/memory/ref_counted.h"
#include "chrome/browser/profiles/profile_io_data.h"
+namespace chrome_browser_net {
+class Predictor;
+}
+
namespace net {
class HttpTransactionFactory;
} // namespace net
@@ -36,7 +40,10 @@ class ProfileImplIOData : public ProfileIOData {
const FilePath& media_cache_path,
int media_cache_max_size,
const FilePath& extensions_cookie_path,
- const FilePath& app_path);
+ const FilePath& app_path,
+ chrome_browser_net::Predictor* predictor,
+ PrefService* local_state,
+ IOThread* io_thread);
base::Callback<ChromeURLDataManagerBackend*(void)>
GetChromeURLDataManagerBackendGetter() const;
@@ -127,6 +134,8 @@ class ProfileImplIOData : public ProfileIOData {
mutable scoped_ptr<net::HttpTransactionFactory> main_http_factory_;
mutable scoped_ptr<net::HttpTransactionFactory> media_http_factory_;
+ mutable scoped_ptr<chrome_browser_net::Predictor> predictor_;
+
// Parameters needed for isolated apps.
FilePath app_path_;
mutable bool clear_local_state_on_exit_;
diff --git a/chrome/browser/renderer_host/chrome_render_message_filter.cc b/chrome/browser/renderer_host/chrome_render_message_filter.cc
index b7d438e..26e84bf 100644
--- a/chrome/browser/renderer_host/chrome_render_message_filter.cc
+++ b/chrome/browser/renderer_host/chrome_render_message_filter.cc
@@ -17,7 +17,7 @@
#include "chrome/browser/metrics/histogram_synchronizer.h"
#include "chrome/browser/nacl_host/nacl_process_host.h"
#include "chrome/browser/net/chrome_url_request_context.h"
-#include "chrome/browser/net/predictor_api.h"
+#include "chrome/browser/net/predictor.h"
#include "chrome/browser/prefs/pref_member.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/task_manager/task_manager.h"
@@ -196,7 +196,8 @@ void ChromeRenderMessageFilter::OnLaunchNaCl(
void ChromeRenderMessageFilter::OnDnsPrefetch(
const std::vector<std::string>& hostnames) {
- chrome_browser_net::DnsPrefetchList(hostnames);
+ if (profile_->GetNetworkPredictor())
+ profile_->GetNetworkPredictor()->DnsPrefetchList(hostnames);
}
void ChromeRenderMessageFilter::OnRendererHistograms(
@@ -514,7 +515,9 @@ void ChromeRenderMessageFilter::OnCanTriggerClipboardWrite(const GURL& url,
void ChromeRenderMessageFilter::OnClearPredictorCache(int* result) {
// This function is disabled unless the user has enabled
// benchmarking extensions.
- chrome_browser_net::ClearPredictorCache();
+ chrome_browser_net::Predictor* predictor = profile_->GetNetworkPredictor();
+ if (predictor)
+ predictor->DiscardAllResults();
*result = 0;
}
diff --git a/chrome/browser/renderer_host/chrome_render_view_host_observer.cc b/chrome/browser/renderer_host/chrome_render_view_host_observer.cc
index 7390cec..ada4a3b 100644
--- a/chrome/browser/renderer_host/chrome_render_view_host_observer.cc
+++ b/chrome/browser/renderer_host/chrome_render_view_host_observer.cc
@@ -7,7 +7,7 @@
#include "base/command_line.h"
#include "chrome/browser/dom_operation_notification_details.h"
#include "chrome/browser/extensions/extension_service.h"
-#include "chrome/browser/net/predictor_api.h"
+#include "chrome/browser/net/predictor.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_notification_types.h"
#include "chrome/common/chrome_switches.h"
@@ -24,8 +24,9 @@
#include "content/common/view_messages.h"
ChromeRenderViewHostObserver::ChromeRenderViewHostObserver(
- RenderViewHost* render_view_host)
- : RenderViewHostObserver(render_view_host) {
+ RenderViewHost* render_view_host, chrome_browser_net::Predictor* predictor)
+ : RenderViewHostObserver(render_view_host),
+ predictor_(predictor) {
InitRenderViewHostForExtensions();
}
@@ -39,9 +40,11 @@ void ChromeRenderViewHostObserver::RenderViewHostInitialized() {
void ChromeRenderViewHostObserver::Navigate(
const ViewMsg_Navigate_Params& params) {
const GURL& url = params.url;
+ if (!predictor_)
+ return;
if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kChromeFrame) &&
- (url.SchemeIs(chrome::kHttpScheme) || url.SchemeIs(chrome::kHttpsScheme)))
- chrome_browser_net::PreconnectUrlAndSubresources(url);
+ (url.SchemeIs(chrome::kHttpScheme) || url.SchemeIs(chrome::kHttpsScheme)))
+ predictor_->PreconnectUrlAndSubresources(url);
}
bool ChromeRenderViewHostObserver::OnMessageReceived(
diff --git a/chrome/browser/renderer_host/chrome_render_view_host_observer.h b/chrome/browser/renderer_host/chrome_render_view_host_observer.h
index 411a953..5a5eaa8 100644
--- a/chrome/browser/renderer_host/chrome_render_view_host_observer.h
+++ b/chrome/browser/renderer_host/chrome_render_view_host_observer.h
@@ -8,13 +8,18 @@
#include "content/browser/renderer_host/render_view_host_observer.h"
+namespace chrome_browser_net {
+class Predictor;
+}
+
class Extension;
// This class holds the Chrome specific parts of RenderViewHost, and has the
// same lifetime.
class ChromeRenderViewHostObserver : public RenderViewHostObserver {
public:
- explicit ChromeRenderViewHostObserver(RenderViewHost* render_view_host);
+ ChromeRenderViewHostObserver(RenderViewHost* render_view_host,
+ chrome_browser_net::Predictor* predictor);
virtual ~ChromeRenderViewHostObserver();
// RenderViewHostObserver overrides.
@@ -35,6 +40,8 @@ class ChromeRenderViewHostObserver : public RenderViewHostObserver {
void OnDomOperationResponse(const std::string& json_string,
int automation_id);
+ chrome_browser_net::Predictor* predictor_;
+
DISALLOW_COPY_AND_ASSIGN(ChromeRenderViewHostObserver);
};
diff --git a/chrome/browser/ui/browser_init.cc b/chrome/browser/ui/browser_init.cc
index 42d6dae..543d2fb 100644
--- a/chrome/browser/ui/browser_init.cc
+++ b/chrome/browser/ui/browser_init.cc
@@ -31,7 +31,7 @@
#include "chrome/browser/extensions/pack_extension_job.h"
#include "chrome/browser/first_run/first_run.h"
#include "chrome/browser/infobars/infobar_tab_helper.h"
-#include "chrome/browser/net/predictor_api.h"
+#include "chrome/browser/net/predictor.h"
#include "chrome/browser/net/url_fixer_upper.h"
#include "chrome/browser/notifications/desktop_notification_service.h"
#include "chrome/browser/prefs/incognito_mode_prefs.h"
@@ -668,8 +668,10 @@ bool BrowserInit::LaunchWithProfile::Launch(
if (command_line_.HasSwitch(switches::kDnsLogDetails))
chrome_browser_net::EnablePredictorDetailedLog(true);
- if (command_line_.HasSwitch(switches::kDnsPrefetchDisable))
- chrome_browser_net::EnablePredictor(false);
+ if (command_line_.HasSwitch(switches::kDnsPrefetchDisable) &&
+ profile->GetNetworkPredictor()) {
+ profile->GetNetworkPredictor()->EnablePredictor(false);
+ }
if (command_line_.HasSwitch(switches::kDumpHistogramsOnExit))
base::StatisticsRecorder::set_dump_on_exit(true);
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 7740237..24a44a5 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -1518,8 +1518,6 @@
'browser/net/preconnect.h',
'browser/net/predictor.cc',
'browser/net/predictor.h',
- 'browser/net/predictor_api.cc',
- 'browser/net/predictor_api.h',
'browser/net/pref_proxy_config_service.cc',
'browser/net/pref_proxy_config_service.h',
'browser/net/proxy_service_factory.cc',