summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/prefetch/prefetch_field_trial.cc5
-rw-r--r--chrome/browser/prerender/prerender_field_trial.cc19
-rw-r--r--chrome/browser/prerender/prerender_field_trial.h7
-rw-r--r--chrome/browser/prerender/prerender_local_predictor.cc87
-rw-r--r--chrome/browser/prerender/prerender_local_predictor.h9
-rw-r--r--chrome/browser/prerender/prerender_manager.cc4
6 files changed, 109 insertions, 22 deletions
diff --git a/chrome/browser/prefetch/prefetch_field_trial.cc b/chrome/browser/prefetch/prefetch_field_trial.cc
index d88e0c7..0db983b 100644
--- a/chrome/browser/prefetch/prefetch_field_trial.cc
+++ b/chrome/browser/prefetch/prefetch_field_trial.cc
@@ -8,6 +8,7 @@
#include "base/metrics/field_trial.h"
#include "base/strings/string_util.h"
+#include "chrome/browser/prerender/prerender_field_trial.h"
namespace prefetch {
@@ -15,6 +16,10 @@ bool IsPrefetchFieldTrialEnabled() {
std::string experiment = base::FieldTrialList::FindFullName("Prefetch");
if (StartsWithASCII(experiment, "ExperimentYes", false))
return true;
+ // If this client needs to prefetch for the Prerender Local Predictor,
+ // enable prefetching.
+ if (prerender::IsLocalPredictorPrerenderPrefetchEnabled())
+ return true;
return false;
}
diff --git a/chrome/browser/prerender/prerender_field_trial.cc b/chrome/browser/prerender/prerender_field_trial.cc
index 759b269..9a750be2c 100644
--- a/chrome/browser/prerender/prerender_field_trial.cc
+++ b/chrome/browser/prerender/prerender_field_trial.cc
@@ -44,6 +44,7 @@ const char kLocalPredictorUnencryptedSyncOnlyKeyName[] =
const char kSideEffectFreeWhitelistKeyName[] = "SideEffectFreeWhitelist";
const char kPrerenderLaunchKeyName[] = "PrerenderLaunch";
const char kPrerenderAlwaysControlKeyName[] = "PrerenderAlwaysControl";
+const char kPrerenderPrefetchKeyName[] = "PrerenderPrefetch";
const char kPrerenderQueryPrerenderServiceKeyName[] =
"PrerenderQueryPrerenderService";
const char kPrerenderQueryPrerenderServiceCurrentURLKeyName[] =
@@ -57,6 +58,7 @@ const char kPrerenderTTLKeyName[] = "PrerenderTTLSeconds";
const char kPrerenderPriorityHalfLifeTimeKeyName[] =
"PrerenderPriorityHalfLifeTimeSeconds";
const char kMaxConcurrentPrerenderKeyName[] = "MaxConcurrentPrerenders";
+const char kMaxLaunchPrerenderKeyName[] = "MaxLaunchPrerenders";
const char kSkipFragment[] = "SkipFragment";
const char kSkipHTTPS[] = "SkipHTTPS";
const char kSkipWhitelist[] = "SkipWhitelist";
@@ -328,7 +330,14 @@ bool IsLocalPredictorPrerenderLaunchEnabled() {
}
bool IsLocalPredictorPrerenderAlwaysControlEnabled() {
- return GetLocalPredictorSpecValue(kPrerenderAlwaysControlKeyName) ==
+ // If we prefetch rather than prerender, we automatically also prerender
+ // as a control group only.
+ return (GetLocalPredictorSpecValue(kPrerenderAlwaysControlKeyName) ==
+ kEnabledGroup) || IsLocalPredictorPrerenderPrefetchEnabled();
+}
+
+bool IsLocalPredictorPrerenderPrefetchEnabled() {
+ return GetLocalPredictorSpecValue(kPrerenderPrefetchKeyName) ==
kEnabledGroup;
}
@@ -396,6 +405,14 @@ int GetLocalPredictorMaxConcurrentPrerenders() {
return std::min(std::max(num_prerenders, 1), 10);
}
+int GetLocalPredictorMaxLaunchPrerenders() {
+ int num_prerenders;
+ StringToInt(GetLocalPredictorSpecValue(kMaxLaunchPrerenderKeyName),
+ &num_prerenders);
+ // Sanity check: Ensure the number of prerenders is between 1 and 10.
+ return std::min(std::max(num_prerenders, 1), 10);
+}
+
bool SkipLocalPredictorFragment() {
return GetLocalPredictorSpecValue(kSkipFragment) == kEnabledGroup;
}
diff --git a/chrome/browser/prerender/prerender_field_trial.h b/chrome/browser/prerender/prerender_field_trial.h
index 038f734..ef7c6e3 100644
--- a/chrome/browser/prerender/prerender_field_trial.h
+++ b/chrome/browser/prerender/prerender_field_trial.h
@@ -48,6 +48,9 @@ bool IsLocalPredictorPrerenderLaunchEnabled();
// is irrelevant.
bool IsLocalPredictorPrerenderAlwaysControlEnabled();
+// Returns true if the local predictor should prefetch rather than prerender.
+bool IsLocalPredictorPrerenderPrefetchEnabled();
+
// Returns true if we should query the prerender service for the profile
// provided.
bool ShouldQueryPrerenderService(Profile* profile);
@@ -79,6 +82,10 @@ int GetLocalPredictorPrerenderPriorityHalfLifeTimeSeconds();
// may maintain.
int GetLocalPredictorMaxConcurrentPrerenders();
+// Returns the maximum number of concurrent prerenders the local predictor
+// may launch concurrently.
+int GetLocalPredictorMaxLaunchPrerenders();
+
// The following functions return whether certain LocalPredictor checks should
// be skipped, as indicated by the name.
bool SkipLocalPredictorFragment();
diff --git a/chrome/browser/prerender/prerender_local_predictor.cc b/chrome/browser/prerender/prerender_local_predictor.cc
index cc3b1f5..d3f7578 100644
--- a/chrome/browser/prerender/prerender_local_predictor.cc
+++ b/chrome/browser/prerender/prerender_local_predictor.cc
@@ -32,9 +32,12 @@
#include "chrome/browser/safe_browsing/database_manager.h"
#include "chrome/browser/safe_browsing/safe_browsing_service.h"
#include "chrome/browser/ui/tab_contents/tab_contents_iterator.h"
+#include "chrome/common/prefetch_messages.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/navigation_entry.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_process_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/page_transition_types.h"
#include "crypto/secure_hash.h"
@@ -50,6 +53,7 @@ using base::ListValue;
using base::Value;
using content::BrowserThread;
using content::PageTransition;
+using content::RenderFrameHost;
using content::SessionStorageNamespace;
using content::WebContents;
using history::URLID;
@@ -64,6 +68,8 @@ namespace {
static const size_t kURLHashSize = 5;
static const int kNumPrerenderCandidates = 5;
+static const int kInvalidProcessId = -1;
+static const int kInvalidFrameId = -1;
} // namespace
@@ -90,9 +96,16 @@ struct PrerenderLocalPredictor::CandidatePrerenderInfo {
LocalPredictorURLInfo source_url_;
vector<LocalPredictorURLInfo> candidate_urls_;
scoped_refptr<SessionStorageNamespace> session_storage_namespace_;
+ // Render Process ID and Route ID of the page causing the prerender to be
+ // issued. Needed so that we can cause its renderer to issue prefetches within
+ // its context.
+ int render_process_id_;
+ int render_frame_id_;
scoped_ptr<gfx::Size> size_;
base::Time start_time_; // used for various time measurements
- explicit CandidatePrerenderInfo(URLID source_id) {
+ explicit CandidatePrerenderInfo(URLID source_id)
+ : render_process_id_(kInvalidProcessId),
+ render_frame_id_(kInvalidFrameId) {
source_url_.id = source_id;
}
void MaybeAddCandidateURLFromLocalData(URLID id, double priority) {
@@ -598,6 +611,9 @@ void PrerenderLocalPredictor::OnLookupURL(
info->session_storage_namespace_ =
source_web_contents->GetController().GetDefaultSessionStorageNamespace();
+ RenderFrameHost* rfh = source_web_contents->GetMainFrame();
+ info->render_process_id_ = rfh->GetProcess()->GetID();
+ info->render_frame_id_ = rfh->GetRoutingID();
gfx::Rect container_bounds = source_web_contents->GetContainerBounds();
info->size_.reset(new gfx::Size(container_bounds.size()));
@@ -1053,10 +1069,25 @@ bool PrerenderLocalPredictor::DoesPrerenderMatchPLTRecord(
}
PrerenderLocalPredictor::PrerenderProperties*
-PrerenderLocalPredictor::GetIssuedPrerenderSlotForPriority(double priority) {
+PrerenderLocalPredictor::GetIssuedPrerenderSlotForPriority(const GURL& url,
+ double priority) {
int num_prerenders = GetLocalPredictorMaxConcurrentPrerenders();
while (static_cast<int>(issued_prerenders_.size()) < num_prerenders)
issued_prerenders_.push_back(new PrerenderProperties());
+ // First, check if we already have a prerender for the same URL issued.
+ // If yes, we don't want to prerender this URL again, so we return NULL
+ // (on matching slot found).
+ for (int i = 0; i < static_cast<int>(issued_prerenders_.size()); i++) {
+ PrerenderProperties* p = issued_prerenders_[i];
+ DCHECK(p != NULL);
+ if (p->prerender_handle && p->prerender_handle->IsPrerendering() &&
+ p->prerender_handle->Matches(url, NULL)) {
+ return NULL;
+ }
+ }
+ // Otherwise, let's see if there are any empty slots. If yes, return the first
+ // one we find. Otherwise, if the lowest priority prerender has a lower
+ // priority than the page we want to prerender, use its slot.
PrerenderProperties* lowest_priority_prerender = NULL;
for (int i = 0; i < static_cast<int>(issued_prerenders_.size()); i++) {
PrerenderProperties* p = issued_prerenders_[i];
@@ -1091,8 +1122,10 @@ void PrerenderLocalPredictor::ContinuePrerenderCheck(
g_browser_process->safe_browsing_service()->database_manager();
#endif
PrerenderProperties* prerender_properties = NULL;
-
+ int num_issued = 0;
for (int i = 0; i < static_cast<int>(info->candidate_urls_.size()); i++) {
+ if (num_issued > GetLocalPredictorMaxLaunchPrerenders())
+ return;
RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_EXAMINE_NEXT_URL);
url_info.reset(new LocalPredictorURLInfo(info->candidate_urls_[i]));
if (url_info->local_history_based) {
@@ -1126,7 +1159,7 @@ void PrerenderLocalPredictor::ContinuePrerenderCheck(
continue;
}
prerender_properties =
- GetIssuedPrerenderSlotForPriority(url_info->priority);
+ GetIssuedPrerenderSlotForPriority(url_info->url, url_info->priority);
if (!prerender_properties) {
RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_PRIORITY_TOO_LOW);
url_info.reset(NULL);
@@ -1148,7 +1181,9 @@ void PrerenderLocalPredictor::ContinuePrerenderCheck(
// For root pages, we assume that they are reasonably safe, and we
// will just prerender them without any additional checks.
RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_ROOT_PAGE);
- break;
+ IssuePrerender(info.get(), url_info.get(), prerender_properties);
+ num_issued++;
+ continue;
}
if (IsLogOutURL(url_info->url)) {
RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_LOGOUT_URL);
@@ -1166,40 +1201,48 @@ void PrerenderLocalPredictor::ContinuePrerenderCheck(
// If a page is on the side-effect free whitelist, we will just prerender
// it without any additional checks.
RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_ON_SIDE_EFFECT_FREE_WHITELIST);
- break;
+ IssuePrerender(info.get(), url_info.get(), prerender_properties);
+ num_issued++;
+ continue;
}
#endif
if (!SkipLocalPredictorServiceWhitelist() &&
url_info->service_whitelist && url_info->service_whitelist_lookup_ok) {
RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_ON_SERVICE_WHITELIST);
- break;
+ IssuePrerender(info.get(), url_info.get(), prerender_properties);
+ num_issued++;
+ continue;
}
if (!SkipLocalPredictorLoggedIn() &&
!url_info->logged_in && url_info->logged_in_lookup_ok) {
RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_NOT_LOGGED_IN);
- break;
+ IssuePrerender(info.get(), url_info.get(), prerender_properties);
+ num_issued++;
+ continue;
}
if (!SkipLocalPredictorDefaultNoPrerender()) {
RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_FALLTHROUGH_NOT_PRERENDERING);
url_info.reset(NULL);
} else {
RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_FALLTHROUGH_PRERENDERING);
+ IssuePrerender(info.get(), url_info.get(), prerender_properties);
+ num_issued++;
+ continue;
}
}
- if (!url_info.get())
- return;
- RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_ISSUING_PRERENDER);
- DCHECK(prerender_properties != NULL);
- if (IsLocalPredictorPrerenderLaunchEnabled()) {
- IssuePrerender(info.Pass(), url_info.Pass(), prerender_properties);
- }
}
void PrerenderLocalPredictor::IssuePrerender(
- scoped_ptr<CandidatePrerenderInfo> info,
- scoped_ptr<LocalPredictorURLInfo> url_info,
+ CandidatePrerenderInfo* info,
+ LocalPredictorURLInfo* url_info,
PrerenderProperties* prerender_properties) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_ISSUING_PRERENDER);
+ DCHECK(prerender_properties != NULL);
+ DCHECK(info != NULL);
+ DCHECK(url_info != NULL);
+ if (!IsLocalPredictorPrerenderLaunchEnabled())
+ return;
URLID url_id = url_info->id;
const GURL& url = url_info->url;
double priority = url_info->priority;
@@ -1243,6 +1286,16 @@ void PrerenderLocalPredictor::IssuePrerender(
new_prerender_handle->OnCancel();
RecordEvent(EVENT_ISSUE_PRERENDER_CANCELLED_OLD_PRERENDER);
}
+ // If we are prefetching rather than prerendering, now is the time to launch
+ // the prefetch.
+ if (IsLocalPredictorPrerenderPrefetchEnabled()) {
+ // Obtain the render frame host that caused this prefetch.
+ RenderFrameHost* rfh = RenderFrameHost::FromID(info->render_process_id_,
+ info->render_frame_id_);
+ // If it is still alive, launch the prefresh.
+ if (rfh)
+ rfh->Send(new PrefetchMsg_Prefetch(rfh->GetRoutingID(), url));
+ }
}
RecordEvent(EVENT_ADD_VISIT_PRERENDERING);
diff --git a/chrome/browser/prerender/prerender_local_predictor.h b/chrome/browser/prerender/prerender_local_predictor.h
index 3081d4f..64d47b6 100644
--- a/chrome/browser/prerender/prerender_local_predictor.h
+++ b/chrome/browser/prerender/prerender_local_predictor.h
@@ -181,13 +181,14 @@ class PrerenderLocalPredictor : public history::VisitDatabaseObserver,
// Returns an element of issued_prerenders_, which should be replaced
// by a new prerender of the priority indicated, or NULL, if the priority
- // is too low.
- PrerenderProperties* GetIssuedPrerenderSlotForPriority(double priority);
+ // is too low (or if the URL requested is already prerendering).
+ PrerenderProperties* GetIssuedPrerenderSlotForPriority(const GURL& url,
+ double priority);
void ContinuePrerenderCheck(scoped_ptr<CandidatePrerenderInfo> info);
void LogCandidateURLStats(const GURL& url) const;
- void IssuePrerender(scoped_ptr<CandidatePrerenderInfo> info,
- scoped_ptr<LocalPredictorURLInfo> url_info,
+ void IssuePrerender(CandidatePrerenderInfo* info,
+ LocalPredictorURLInfo* url_info,
PrerenderProperties* prerender_properties);
void MaybeCancelURLFetcher(net::URLFetcher* fetcher);
// Returns true if the parsed response is semantically correct and could
diff --git a/chrome/browser/prerender/prerender_manager.cc b/chrome/browser/prerender/prerender_manager.cc
index 62ed58d..04f1008 100644
--- a/chrome/browser/prerender/prerender_manager.cc
+++ b/chrome/browser/prerender/prerender_manager.cc
@@ -1533,6 +1533,10 @@ bool PrerenderManager::DoesRateLimitAllowPrerender(Origin origin) const {
histograms_->RecordTimeBetweenPrerenderRequests(origin, elapsed_time);
if (!config_.rate_limit_enabled)
return true;
+ // The LocalPredictor may issue multiple prerenders simultaneously (if so
+ // configured), so no throttling.
+ if (origin == ORIGIN_LOCAL_PREDICTOR)
+ return true;
return elapsed_time >=
base::TimeDelta::FromMilliseconds(kMinTimeBetweenPrerendersMs);
}