15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/prerender/prerender_local_predictor.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <ctype.h>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm>
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <map>
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <set>
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string>
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <utility>
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/metrics/field_trial.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/metrics/histogram.h"
17eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/timer/timer.h"
1890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "chrome/browser/browser_process.h"
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/history/history_database.h"
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/history/history_db_task.h"
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/history/history_service.h"
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/history/history_service_factory.h"
237d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "chrome/browser/prerender/prerender_field_trial.h"
24b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "chrome/browser/prerender/prerender_handle.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/prerender/prerender_histograms.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/prerender/prerender_manager.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h"
2890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "chrome/browser/safe_browsing/database_manager.h"
2990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "chrome/browser/safe_browsing/safe_browsing_service.h"
30b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "chrome/browser/ui/tab_contents/tab_contents_iterator.h"
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/browser_thread.h"
32b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "content/public/browser/navigation_controller.h"
33b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "content/public/browser/session_storage_namespace.h"
34b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "content/public/browser/web_contents.h"
35b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "content/public/browser/web_contents_view.h"
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/common/page_transition_types.h"
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "crypto/secure_hash.h"
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/browser_resources.h"
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/resource/resource_bundle.h"
40eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "url/url_canon.h"
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::BrowserThread;
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::PageTransition;
44b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)using content::SessionStorageNamespace;
45b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)using content::WebContents;
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using history::URLID;
47b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)using predictors::LoggedInPredictorTable;
48b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)using std::string;
49b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)using std::vector;
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace prerender {
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const size_t kURLHashSize = 5;
56b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)static const int kNumPrerenderCandidates = 5;
57b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
58b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}  // namespace
59b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
60b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)// When considering a candidate URL to be prerendered, we need to collect the
61b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)// data in this struct to make the determination whether we should issue the
62b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)// prerender or not.
63b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)struct PrerenderLocalPredictor::LocalPredictorURLInfo {
64b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  URLID id;
65b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  GURL url;
66b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  bool url_lookup_success;
67b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  bool logged_in;
68b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  bool logged_in_lookup_ok;
69b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  double priority;
70b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)};
71b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
72b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)// A struct consisting of everything needed for launching a potential prerender
73b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)// on a navigation: The navigation URL (source) triggering potential prerenders,
74b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)// and a set of candidate URLs.
75b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)struct PrerenderLocalPredictor::LocalPredictorURLLookupInfo {
76b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  LocalPredictorURLInfo source_url_;
77b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  vector<LocalPredictorURLInfo> candidate_urls_;
78b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  explicit LocalPredictorURLLookupInfo(URLID source_id) {
79b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    source_url_.id = source_id;
80b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  }
81b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  void MaybeAddCandidateURL(URLID id, double priority) {
82b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    // TODO(tburkard): clean up this code, potentially using a list or a heap
83b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    LocalPredictorURLInfo info;
84b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    info.id = id;
85b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    info.priority = priority;
86b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    int insert_pos = candidate_urls_.size();
87b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    if (insert_pos < kNumPrerenderCandidates)
88b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      candidate_urls_.push_back(info);
89b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    while (insert_pos > 0 &&
90b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)           candidate_urls_[insert_pos - 1].priority < info.priority) {
91b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      if (insert_pos < kNumPrerenderCandidates)
92b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        candidate_urls_[insert_pos] = candidate_urls_[insert_pos - 1];
93b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      insert_pos--;
94b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    }
95b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    if (insert_pos < kNumPrerenderCandidates)
96b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      candidate_urls_[insert_pos] = info;
97b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  }
98b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)};
99b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
100b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)namespace {
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Task to lookup the URL for a given URLID.
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class GetURLForURLIDTask : public history::HistoryDBTask {
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
105b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  GetURLForURLIDTask(
106b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      PrerenderLocalPredictor::LocalPredictorURLLookupInfo* request,
107b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      const base::Closure& callback)
108b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      : request_(request),
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        callback_(callback),
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        start_time_(base::Time::Now()) {
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual bool RunOnDBThread(history::HistoryBackend* backend,
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             history::HistoryDatabase* db) OVERRIDE {
115b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    DoURLLookup(db, &request_->source_url_);
116b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    for (int i = 0; i < static_cast<int>(request_->candidate_urls_.size()); i++)
117b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      DoURLLookup(db, &request_->candidate_urls_[i]);
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void DoneRunOnMainThread() OVERRIDE {
122b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    callback_.Run();
123b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    UMA_HISTOGRAM_CUSTOM_TIMES("Prerender.LocalPredictorURLLookupTime",
124b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                               base::Time::Now() - start_time_,
125b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                               base::TimeDelta::FromMilliseconds(10),
126b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                               base::TimeDelta::FromSeconds(10),
127b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                               50);
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~GetURLForURLIDTask() {}
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
133b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  void DoURLLookup(history::HistoryDatabase* db,
134b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                   PrerenderLocalPredictor::LocalPredictorURLInfo* request) {
135b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    history::URLRow url_row;
136b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    request->url_lookup_success = db->GetURLRow(request->id, &url_row);
137b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    if (request->url_lookup_success)
138b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      request->url = url_row.url();
139b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  }
140b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
141b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  PrerenderLocalPredictor::LocalPredictorURLLookupInfo* request_;
142b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  base::Closure callback_;
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::Time start_time_;
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(GetURLForURLIDTask);
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Task to load history from the visit database on startup.
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class GetVisitHistoryTask : public history::HistoryDBTask {
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetVisitHistoryTask(PrerenderLocalPredictor* local_predictor,
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      int max_visits)
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : local_predictor_(local_predictor),
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        max_visits_(max_visits),
154b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        visit_history_(new vector<history::BriefVisitInfo>) {
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual bool RunOnDBThread(history::HistoryBackend* backend,
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             history::HistoryDatabase* db) OVERRIDE {
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db->GetBriefVisitInfoOfMostRecentVisits(max_visits_, visit_history_.get());
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void DoneRunOnMainThread() OVERRIDE {
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    local_predictor_->OnGetInitialVisitHistory(visit_history_.Pass());
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~GetVisitHistoryTask() {}
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PrerenderLocalPredictor* local_predictor_;
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int max_visits_;
172b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  scoped_ptr<vector<history::BriefVisitInfo> > visit_history_;
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(GetVisitHistoryTask);
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Maximum visit history to retrieve from the visit database.
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kMaxVisitHistory = 100 * 1000;
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Visit history size at which to trigger pruning, and number of items to prune.
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kVisitHistoryPruneThreshold = 120 * 1000;
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kVisitHistoryPruneAmount = 20 * 1000;
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kMinLocalPredictionTimeMs = 500;
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1857d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)int GetMaxLocalPredictionTimeMs() {
1867d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return GetLocalPredictorTTLSeconds() * 1000;
1877d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
1887d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool IsBackForward(PageTransition transition) {
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (transition & content::PAGE_TRANSITION_FORWARD_BACK) != 0;
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool IsHomePage(PageTransition transition) {
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (transition & content::PAGE_TRANSITION_HOME_PAGE) != 0;
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool IsIntermediateRedirect(PageTransition transition) {
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (transition & content::PAGE_TRANSITION_CHAIN_END) == 0;
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20158e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdochbool IsFormSubmit(PageTransition transition) {
20258e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  return (transition & content::PAGE_TRANSITION_FORM_SUBMIT) != 0;
20358e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch}
20458e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ShouldExcludeTransitionForPrediction(PageTransition transition) {
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return IsBackForward(transition) || IsHomePage(transition) ||
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      IsIntermediateRedirect(transition);
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)base::Time GetCurrentTime() {
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return base::Time::Now();
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
214b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)bool StringContainsIgnoringCase(string haystack, string needle) {
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::transform(haystack.begin(), haystack.end(), haystack.begin(), ::tolower);
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::transform(needle.begin(), needle.end(), needle.begin(), ::tolower);
217b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  return haystack.find(needle) != string::npos;
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool IsExtendedRootURL(const GURL& url) {
221b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  const string& path = url.path();
2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return path == "/index.html" || path == "/home.html" ||
2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      path == "/main.html" ||
2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      path == "/index.htm" || path == "/home.htm" || path == "/main.htm" ||
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      path == "/index.php" || path == "/home.php" || path == "/main.php" ||
2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      path == "/index.asp" || path == "/home.asp" || path == "/main.asp" ||
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      path == "/index.py" || path == "/home.py" || path == "/main.py" ||
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      path == "/index.pl" || path == "/home.pl" || path == "/main.pl";
2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool IsRootPageURL(const GURL& url) {
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return (url.path() == "/" || url.path() == "" || IsExtendedRootURL(url)) &&
2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      (!url.has_query()) && (!url.has_ref());
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
236b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)bool IsLogInURL(const GURL& url) {
237b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  return StringContainsIgnoringCase(url.spec().c_str(), "login") ||
238b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      StringContainsIgnoringCase(url.spec().c_str(), "signin");
239b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
240b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
241b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)bool IsLogOutURL(const GURL& url) {
242b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  return StringContainsIgnoringCase(url.spec().c_str(), "logout") ||
243b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      StringContainsIgnoringCase(url.spec().c_str(), "signout");
244b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
245b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int64 URLHashToInt64(const unsigned char* data) {
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  COMPILE_ASSERT(kURLHashSize < sizeof(int64), url_hash_must_fit_in_int64);
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int64 value = 0;
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memcpy(&value, data, kURLHashSize);
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return value;
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int64 GetInt64URLHashForURL(const GURL& url) {
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  COMPILE_ASSERT(kURLHashSize < sizeof(int64), url_hash_must_fit_in_int64);
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<crypto::SecureHash> hash(
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int64 hash_value = 0;
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char* url_string = url.spec().c_str();
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hash->Update(url_string, strlen(url_string));
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hash->Finish(&hash_value, kURLHashSize);
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return hash_value;
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
264b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)bool URLsIdenticalIgnoringFragments(const GURL& url1, const GURL& url2) {
265b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  url_canon::Replacements<char> replacement;
266b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  replacement.ClearRef();
267b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  GURL u1 = url1.ReplaceComponents(replacement);
268b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  GURL u2 = url2.ReplaceComponents(replacement);
269b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  return (u1 == u2);
270b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
271b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
272b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void LookupLoggedInStatesOnDBThread(
273b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    scoped_refptr<LoggedInPredictorTable> logged_in_predictor_table,
274b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    PrerenderLocalPredictor::LocalPredictorURLLookupInfo* request_) {
275b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
276b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  for (int i = 0; i < static_cast<int>(request_->candidate_urls_.size()); i++) {
277b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    PrerenderLocalPredictor::LocalPredictorURLInfo* info =
278b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        &request_->candidate_urls_[i];
279b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    if (info->url_lookup_success) {
280b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      logged_in_predictor_table->HasUserLoggedIn(
281b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)          info->url, &info->logged_in, &info->logged_in_lookup_ok);
282b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    } else {
283b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      info->logged_in_lookup_ok = false;
284b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    }
285b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  }
286b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
287b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
290b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)struct PrerenderLocalPredictor::PrerenderProperties {
291b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  PrerenderProperties(URLID url_id, const GURL& url, double priority,
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                base::Time start_time)
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : url_id(url_id),
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        url(url),
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        priority(priority),
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        start_time(start_time) {
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2997d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // Default constructor for dummy element
3007d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  PrerenderProperties()
3017d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      : priority(0.0) {
3027d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  }
3037d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
3047d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  double GetCurrentDecayedPriority() {
3057d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    // If we are no longer prerendering, the priority is 0.
3067d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    if (!prerender_handle || !prerender_handle->IsPrerendering())
3077d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      return 0.0;
3087d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    int half_life_time_seconds =
3097d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        GetLocalPredictorPrerenderPriorityHalfLifeTimeSeconds();
3107d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    if (half_life_time_seconds < 1)
3117d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      return priority;
3127d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    double multiple_elapsed =
3137d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        (GetCurrentTime() - actual_start_time).InMillisecondsF() /
3147d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        base::TimeDelta::FromSeconds(half_life_time_seconds).InMillisecondsF();
3157d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    // Decay factor: 2 ^ (-multiple_elapsed)
3167d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    double decay_factor = exp(- multiple_elapsed * log(2.0));
3177d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return priority * decay_factor;
3187d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  }
3197d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLID url_id;
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GURL url;
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  double priority;
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // For expiration purposes, this is a synthetic start time consisting either
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // of the actual start time, or of the last time the page was re-requested
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // for prerendering - 10 seconds (unless the original request came after
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // that).  This is to emulate the effect of re-prerendering a page that is
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // about to expire, because it was re-requested for prerendering a second
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // time after the actual prerender being kept around.
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::Time start_time;
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The actual time this page was last requested for prerendering.
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::Time actual_start_time;
3327d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  scoped_ptr<PrerenderHandle> prerender_handle;
3337d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // Indicates whether this prerender would have matched a URL navigated to,
3347d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // but was not swapped in for some reason.
3357d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  bool would_have_matched;
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PrerenderLocalPredictor::PrerenderLocalPredictor(
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PrerenderManager* prerender_manager)
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : prerender_manager_(prerender_manager),
341b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      is_visit_database_observer_(false),
3427d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      weak_factory_(this) {
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RecordEvent(EVENT_CONSTRUCTED);
34490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (base::MessageLoop::current()) {
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    timer_.Start(FROM_HERE,
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 base::TimeDelta::FromMilliseconds(kInitDelayMs),
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 this,
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 &PrerenderLocalPredictor::Init);
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RecordEvent(EVENT_INIT_SCHEDULED);
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const size_t kChecksumHashSize = 32;
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::RefCountedStaticMemory* url_whitelist_data =
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ResourceBundle::GetSharedInstance().LoadDataResourceBytes(
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          IDR_PRERENDER_URL_WHITELIST);
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t size = url_whitelist_data->size();
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const unsigned char* front = url_whitelist_data->front();
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (size < kChecksumHashSize ||
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (size - kChecksumHashSize) % kURLHashSize != 0) {
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RecordEvent(EVENT_URL_WHITELIST_ERROR);
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<crypto::SecureHash> hash(
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hash->Update(front + kChecksumHashSize, size - kChecksumHashSize);
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char hash_value[kChecksumHashSize];
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hash->Finish(hash_value, kChecksumHashSize);
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (memcmp(hash_value, front, kChecksumHashSize)) {
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RecordEvent(EVENT_URL_WHITELIST_ERROR);
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (const unsigned char* p = front + kChecksumHashSize;
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       p < front + size;
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       p += kURLHashSize) {
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_whitelist_.insert(URLHashToInt64(p));
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RecordEvent(EVENT_URL_WHITELIST_OK);
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PrerenderLocalPredictor::~PrerenderLocalPredictor() {
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Shutdown();
3827d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  for (int i = 0; i < static_cast<int>(issued_prerenders_.size()); i++) {
3837d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    PrerenderProperties* p = issued_prerenders_[i];
3847d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    DCHECK(p != NULL);
3857d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    if (p->prerender_handle)
3867d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      p->prerender_handle->OnCancel();
3877d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  }
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PrerenderLocalPredictor::Shutdown() {
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  timer_.Stop();
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (is_visit_database_observer_) {
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HistoryService* history = GetHistoryIfExists();
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CHECK(history);
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    history->RemoveVisitDatabaseObserver(this);
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    is_visit_database_observer_ = false;
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PrerenderLocalPredictor::OnAddVisit(const history::BriefVisitInfo& info) {
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RecordEvent(EVENT_ADD_VISIT);
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!visit_history_.get())
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  visit_history_->push_back(info);
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (static_cast<int>(visit_history_->size()) > kVisitHistoryPruneThreshold) {
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    visit_history_->erase(visit_history_->begin(),
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          visit_history_->begin() + kVisitHistoryPruneAmount);
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RecordEvent(EVENT_ADD_VISIT_INITIALIZED);
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (current_prerender_.get() &&
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      current_prerender_->url_id == info.url_id &&
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      IsPrerenderStillValid(current_prerender_.get())) {
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UMA_HISTOGRAM_CUSTOM_TIMES(
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "Prerender.LocalPredictorTimeUntilUsed",
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        GetCurrentTime() - current_prerender_->actual_start_time,
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::TimeDelta::FromMilliseconds(10),
4187d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        base::TimeDelta::FromMilliseconds(GetMaxLocalPredictionTimeMs()),
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        50);
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    last_swapped_in_prerender_.reset(current_prerender_.release());
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RecordEvent(EVENT_ADD_VISIT_PRERENDER_IDENTIFIED);
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (ShouldExcludeTransitionForPrediction(info.transition))
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RecordEvent(EVENT_ADD_VISIT_RELEVANT_TRANSITION);
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::TimeDelta max_age =
4277d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      base::TimeDelta::FromMilliseconds(GetMaxLocalPredictionTimeMs());
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::TimeDelta min_age =
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::TimeDelta::FromMilliseconds(kMinLocalPredictionTimeMs);
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::set<URLID> next_urls_currently_found;
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::map<URLID, int> next_urls_num_found;
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int num_occurrences_of_current_visit = 0;
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::Time last_visited;
434b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  scoped_ptr<LocalPredictorURLLookupInfo> lookup_info(
435b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      new LocalPredictorURLLookupInfo(info.url_id));
436b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  const vector<history::BriefVisitInfo>& visits = *(visit_history_.get());
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < static_cast<int>(visits.size()); i++) {
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!ShouldExcludeTransitionForPrediction(visits[i].transition)) {
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (visits[i].url_id == info.url_id) {
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        last_visited = visits[i].time;
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        num_occurrences_of_current_visit++;
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        next_urls_currently_found.clear();
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        continue;
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!last_visited.is_null() &&
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          last_visited > visits[i].time - max_age &&
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          last_visited < visits[i].time - min_age) {
44858e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch        if (!IsFormSubmit(visits[i].transition))
44958e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch          next_urls_currently_found.insert(visits[i].url_id);
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (i == static_cast<int>(visits.size()) - 1 ||
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        visits[i+1].url_id == info.url_id) {
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for (std::set<URLID>::iterator it = next_urls_currently_found.begin();
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           it != next_urls_currently_found.end();
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           ++it) {
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        std::pair<std::map<URLID, int>::iterator, bool> insert_ret =
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            next_urls_num_found.insert(std::pair<URLID, int>(*it, 0));
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        std::map<URLID, int>::iterator num_found_it = insert_ret.first;
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        num_found_it->second++;
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
465b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  for (std::map<URLID, int>::const_iterator it = next_urls_num_found.begin();
466b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)       it != next_urls_num_found.end();
467b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)       ++it) {
468b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    // Only consider a candidate next page for prerendering if it was viewed
469b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    // at least twice, and at least 10% of the time.
470b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    if (num_occurrences_of_current_visit > 0 &&
471b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        it->second > 1 &&
472b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        it->second * 10 >= num_occurrences_of_current_visit) {
473b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      RecordEvent(EVENT_ADD_VISIT_IDENTIFIED_PRERENDER_CANDIDATE);
474b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      double priority = static_cast<double>(it->second) /
475b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)          static_cast<double>(num_occurrences_of_current_visit);
476b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      lookup_info->MaybeAddCandidateURL(it->first, priority);
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
479b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
480b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (lookup_info->candidate_urls_.size() == 0) {
481b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    RecordEvent(EVENT_NO_PRERENDER_CANDIDATES);
482b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    return;
483b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  }
484b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
485b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  RecordEvent(EVENT_START_URL_LOOKUP);
486b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  HistoryService* history = GetHistoryIfExists();
487b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (history) {
488b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    RecordEvent(EVENT_GOT_HISTORY_ISSUING_LOOKUP);
489b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    LocalPredictorURLLookupInfo* lookup_info_ptr = lookup_info.get();
490b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    history->ScheduleDBTask(
491b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        new GetURLForURLIDTask(
492b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)            lookup_info_ptr,
493b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)            base::Bind(&PrerenderLocalPredictor::OnLookupURL,
494b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                       base::Unretained(this),
495b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                       base::Passed(&lookup_info))),
496b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        &history_db_consumer_);
497b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  }
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
500b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void PrerenderLocalPredictor::OnLookupURL(
501b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    scoped_ptr<LocalPredictorURLLookupInfo> info) {
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RecordEvent(EVENT_PRERENDER_URL_LOOKUP_RESULT);
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
504b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  DCHECK_GE(static_cast<int>(info->candidate_urls_.size()), 1);
505b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
506b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!info->source_url_.url_lookup_success) {
507b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    RecordEvent(EVENT_PRERENDER_URL_LOOKUP_FAILED);
508b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    return;
509b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  }
510b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
511b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  LogCandidateURLStats(info->candidate_urls_[0].url);
512b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
513b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  WebContents* source_web_contents = NULL;
514a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  bool multiple_source_web_contents_candidates = false;
515b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
516b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#if !defined(OS_ANDROID)
517b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  // We need to figure out what tab launched the prerender. We do this by
518b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  // comparing URLs. This may not always work: the URL may occur in two
519b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  // tabs, and we pick the wrong one, or the tab we should have picked
520b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  // may have navigated elsewhere. Hopefully, this doesn't happen too often,
521b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  // so we ignore these cases for now.
522b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  // TODO(tburkard): Reconsider this, potentially measure it, and fix this
523b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  // in the future.
524b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  for (TabContentsIterator it; !it.done(); it.Next()) {
525b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    if (it->GetURL() == info->source_url_.url) {
526a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      if (!source_web_contents)
527a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        source_web_contents = *it;
528a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      else
529a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        multiple_source_web_contents_candidates = true;
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
532b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#endif
533b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
534b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!source_web_contents) {
535b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    RecordEvent(EVENT_PRERENDER_URL_LOOKUP_NO_SOURCE_WEBCONTENTS_FOUND);
536b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    return;
537b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  }
538b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
539a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  if (multiple_source_web_contents_candidates)
540a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    RecordEvent(EVENT_PRERENDER_URL_LOOKUP_MULTIPLE_SOURCE_WEBCONTENTS_FOUND);
541a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
542a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
543b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  scoped_refptr<SessionStorageNamespace> session_storage_namespace =
544ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      source_web_contents->GetController().GetDefaultSessionStorageNamespace();
545b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
546b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  gfx::Rect container_bounds;
547b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  source_web_contents->GetView()->GetContainerBounds(&container_bounds);
548b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  scoped_ptr<gfx::Size> size(new gfx::Size(container_bounds.size()));
549b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
550b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  scoped_refptr<LoggedInPredictorTable> logged_in_table =
551b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      prerender_manager_->logged_in_predictor_table();
552b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
553b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!logged_in_table.get()) {
554b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    RecordEvent(EVENT_PRERENDER_URL_LOOKUP_NO_LOGGED_IN_TABLE_FOUND);
555b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    return;
556b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  }
557b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
558b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  RecordEvent(EVENT_PRERENDER_URL_LOOKUP_ISSUING_LOGGED_IN_LOOKUP);
559b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
560b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  LocalPredictorURLLookupInfo* info_ptr = info.get();
561b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  BrowserThread::PostTaskAndReply(
562b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      BrowserThread::DB, FROM_HERE,
563b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      base::Bind(&LookupLoggedInStatesOnDBThread,
564b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                 logged_in_table,
565b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                 info_ptr),
566b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      base::Bind(&PrerenderLocalPredictor::ContinuePrerenderCheck,
567b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                 weak_factory_.GetWeakPtr(),
568b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                 session_storage_namespace,
569b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                 base::Passed(&size),
570b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                 base::Passed(&info)));
571b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
573b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void PrerenderLocalPredictor::LogCandidateURLStats(const GURL& url) const {
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (url_whitelist_.count(GetInt64URLHashForURL(url)) > 0) {
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RecordEvent(EVENT_PRERENDER_URL_LOOKUP_RESULT_ON_WHITELIST);
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (IsRootPageURL(url))
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      RecordEvent(EVENT_PRERENDER_URL_LOOKUP_RESULT_ON_WHITELIST_ROOT_PAGE);
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (IsRootPageURL(url))
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RecordEvent(EVENT_PRERENDER_URL_LOOKUP_RESULT_ROOT_PAGE);
5812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (IsExtendedRootURL(url))
5822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    RecordEvent(EVENT_PRERENDER_URL_LOOKUP_RESULT_EXTENDED_ROOT_PAGE);
5832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (IsRootPageURL(url) && url.SchemeIs("http"))
5842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    RecordEvent(EVENT_PRERENDER_URL_LOOKUP_RESULT_ROOT_PAGE_HTTP);
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (url.SchemeIs("http"))
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RecordEvent(EVENT_PRERENDER_URL_LOOKUP_RESULT_IS_HTTP);
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (url.has_query())
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RecordEvent(EVENT_PRERENDER_URL_LOOKUP_RESULT_HAS_QUERY_STRING);
589b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (IsLogOutURL(url))
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RecordEvent(EVENT_PRERENDER_URL_LOOKUP_RESULT_CONTAINS_LOGOUT);
591b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (IsLogInURL(url))
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RecordEvent(EVENT_PRERENDER_URL_LOOKUP_RESULT_CONTAINS_LOGIN);
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PrerenderLocalPredictor::OnGetInitialVisitHistory(
596b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    scoped_ptr<vector<history::BriefVisitInfo> > visit_history) {
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!visit_history_.get());
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RecordEvent(EVENT_INIT_SUCCEEDED);
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Since the visit history has descending timestamps, we must reverse it.
601b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  visit_history_.reset(new vector<history::BriefVisitInfo>(
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      visit_history->rbegin(), visit_history->rend()));
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HistoryService* PrerenderLocalPredictor::GetHistoryIfExists() const {
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Profile* profile = prerender_manager_->profile();
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!profile)
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return HistoryServiceFactory::GetForProfileWithoutCreating(profile);
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PrerenderLocalPredictor::Init() {
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RecordEvent(EVENT_INIT_STARTED);
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HistoryService* history = GetHistoryIfExists();
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (history) {
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CHECK(!is_visit_database_observer_);
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    history->ScheduleDBTask(
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        new GetVisitHistoryTask(this, kMaxVisitHistory),
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        &history_db_consumer_);
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    history->AddVisitDatabaseObserver(this);
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    is_visit_database_observer_ = true;
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RecordEvent(EVENT_INIT_FAILED_NO_HISTORY);
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PrerenderLocalPredictor::OnPLTEventForURL(const GURL& url,
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               base::TimeDelta page_load_time) {
630b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  scoped_ptr<PrerenderProperties> prerender;
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (DoesPrerenderMatchPLTRecord(last_swapped_in_prerender_.get(),
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  url, page_load_time)) {
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    prerender.reset(last_swapped_in_prerender_.release());
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (DoesPrerenderMatchPLTRecord(current_prerender_.get(),
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  url, page_load_time)) {
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    prerender.reset(current_prerender_.release());
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!prerender.get())
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (IsPrerenderStillValid(prerender.get())) {
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UMA_HISTOGRAM_CUSTOM_TIMES("Prerender.SimulatedLocalBrowsingBaselinePLT",
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               page_load_time,
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               base::TimeDelta::FromMilliseconds(10),
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               base::TimeDelta::FromSeconds(60),
6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               100);
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::TimeDelta prerender_age = GetCurrentTime() - prerender->start_time;
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (prerender_age > page_load_time) {
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::TimeDelta new_plt;
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (prerender_age <  2 * page_load_time)
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        new_plt = 2 * page_load_time - prerender_age;
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      UMA_HISTOGRAM_CUSTOM_TIMES("Prerender.SimulatedLocalBrowsingPLT",
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 new_plt,
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 base::TimeDelta::FromMilliseconds(10),
6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 base::TimeDelta::FromSeconds(60),
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 100);
6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool PrerenderLocalPredictor::IsPrerenderStillValid(
663b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    PrerenderLocalPredictor::PrerenderProperties* prerender) const {
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (prerender &&
6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          (prerender->start_time +
6667d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)           base::TimeDelta::FromMilliseconds(GetMaxLocalPredictionTimeMs()))
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          > GetCurrentTime());
6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PrerenderLocalPredictor::RecordEvent(
6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PrerenderLocalPredictor::Event event) const {
672c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  UMA_HISTOGRAM_ENUMERATION("Prerender.LocalPredictorEvent",
6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      event, PrerenderLocalPredictor::EVENT_MAX_VALUE);
6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool PrerenderLocalPredictor::DoesPrerenderMatchPLTRecord(
677b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    PrerenderProperties* prerender,
678b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    const GURL& url,
679b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    base::TimeDelta plt) const {
6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (prerender && prerender->start_time < GetCurrentTime() - plt) {
6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (prerender->url.is_empty())
6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      RecordEvent(EVENT_ERROR_NO_PRERENDER_URL_FOR_PLT);
6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return (prerender->url == url);
6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6897d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)PrerenderLocalPredictor::PrerenderProperties*
6907d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)PrerenderLocalPredictor::GetIssuedPrerenderSlotForPriority(double priority) {
6917d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  int num_prerenders = GetLocalPredictorMaxConcurrentPrerenders();
6927d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  while (static_cast<int>(issued_prerenders_.size()) < num_prerenders)
6937d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    issued_prerenders_.push_back(new PrerenderProperties());
6947d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  PrerenderProperties* lowest_priority_prerender = NULL;
6957d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  for (int i = 0; i < static_cast<int>(issued_prerenders_.size()); i++) {
6967d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    PrerenderProperties* p = issued_prerenders_[i];
6977d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    DCHECK(p != NULL);
6987d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    if (!p->prerender_handle || !p->prerender_handle->IsPrerendering())
6997d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      return p;
7007d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    double decayed_priority = p->GetCurrentDecayedPriority();
7017d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    if (decayed_priority > priority)
7027d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      continue;
7037d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    if (lowest_priority_prerender == NULL ||
7047d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        lowest_priority_prerender->GetCurrentDecayedPriority() >
7057d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        decayed_priority) {
7067d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      lowest_priority_prerender = p;
7077d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    }
7087d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  }
7097d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return lowest_priority_prerender;
710b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
711b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
712b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void PrerenderLocalPredictor::ContinuePrerenderCheck(
713b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    scoped_refptr<SessionStorageNamespace> session_storage_namespace,
714b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    scoped_ptr<gfx::Size> size,
715b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    scoped_ptr<LocalPredictorURLLookupInfo> info) {
716b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_STARTED);
717b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  scoped_ptr<LocalPredictorURLInfo> url_info;
71890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  scoped_refptr<SafeBrowsingDatabaseManager> sb_db_manager =
71990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      g_browser_process->safe_browsing_service()->database_manager();
7207d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  PrerenderProperties* prerender_properties = NULL;
72190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
722b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  for (int i = 0; i < static_cast<int>(info->candidate_urls_.size()); i++) {
72358e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch    RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_EXAMINE_NEXT_URL);
724b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    url_info.reset(new LocalPredictorURLInfo(info->candidate_urls_[i]));
725b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
726b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    // We need to check whether we can issue a prerender for this URL.
727b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    // We test a set of conditions. Each condition can either rule out
728b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    // a prerender (in which case we reset url_info, so that it will not
729b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    // be prerendered, and we continue, which means try the next candidate
730b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    // URL), or it can be sufficient to issue the prerender without any
731b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    // further checks (in which case we just break).
732b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    // The order of the checks is critical, because it prescribes the logic
733b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    // we use here to decide what to prerender.
734b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    if (!url_info->url_lookup_success) {
735b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_NO_URL);
736b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      url_info.reset(NULL);
737b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      continue;
738b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    }
7397d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    prerender_properties =
7407d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        GetIssuedPrerenderSlotForPriority(url_info->priority);
7417d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    if (!prerender_properties) {
742b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_PRIORITY_TOO_LOW);
743b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      url_info.reset(NULL);
744b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      continue;
745b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    }
7462385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    if (!SkipLocalPredictorFragment() &&
7472385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch        URLsIdenticalIgnoringFragments(info->source_url_.url,
748b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                       url_info->url)) {
749b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_URLS_IDENTICAL_BUT_FRAGMENT);
750b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      url_info.reset(NULL);
751b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      continue;
752b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    }
7532385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    if (!SkipLocalPredictorHTTPS() && url_info->url.SchemeIs("https")) {
754b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_HTTPS);
755b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      url_info.reset(NULL);
756b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      continue;
757b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    }
758b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    if (IsRootPageURL(url_info->url)) {
759b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      // For root pages, we assume that they are reasonably safe, and we
760b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      // will just prerender them without any additional checks.
761b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_ROOT_PAGE);
762b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      break;
763b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    }
764b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    if (IsLogOutURL(url_info->url)) {
765b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_LOGOUT_URL);
766b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      url_info.reset(NULL);
767b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      continue;
768b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    }
769b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    if (IsLogInURL(url_info->url)) {
770b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_LOGIN_URL);
771b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      url_info.reset(NULL);
772b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      continue;
773b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    }
7742385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    if (!SkipLocalPredictorWhitelist() &&
7752385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch        sb_db_manager->CheckSideEffectFreeWhitelistUrl(url_info->url)) {
77690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      // If a page is on the side-effect free whitelist, we will just prerender
77790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      // it without any additional checks.
77890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_ON_SIDE_EFFECT_FREE_WHITELIST);
77990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      break;
78090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
7812385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    if (!SkipLocalPredictorLoggedIn() &&
7822385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch        !url_info->logged_in && url_info->logged_in_lookup_ok) {
783b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_NOT_LOGGED_IN);
784b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      break;
785b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    }
7862385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    if (!SkipLocalPredictorDefaultNoPrerender()) {
7872385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch      RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_FALLTHROUGH_NOT_PRERENDERING);
7882385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch      url_info.reset(NULL);
7892385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    } else {
7902385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch      RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_FALLTHROUGH_PRERENDERING);
7912385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    }
792b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  }
793b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!url_info.get())
794b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    return;
795b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_ISSUING_PRERENDER);
7967d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  DCHECK(prerender_properties != NULL);
7977d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (IsLocalPredictorPrerenderLaunchEnabled()) {
7987d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    IssuePrerender(session_storage_namespace, size.Pass(),
7997d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                   url_info.Pass(), prerender_properties);
8007d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  }
801b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
802b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
803b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void PrerenderLocalPredictor::IssuePrerender(
804b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    scoped_refptr<SessionStorageNamespace> session_storage_namespace,
805b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    scoped_ptr<gfx::Size> size,
8067d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    scoped_ptr<LocalPredictorURLInfo> info,
8077d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    PrerenderProperties* prerender_properties) {
808b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  URLID url_id = info->id;
809b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  const GURL& url = info->url;
810b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  double priority = info->priority;
811b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  base::Time current_time = GetCurrentTime();
812b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  RecordEvent(EVENT_ISSUING_PRERENDER);
813b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
8147d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // Issue the prerender and obtain a new handle.
8157d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  scoped_ptr<prerender::PrerenderHandle> new_prerender_handle(
8167d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      prerender_manager_->AddPrerenderFromLocalPredictor(
8177d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)          url, session_storage_namespace.get(), *size));
8187d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
8197d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // Check if this is a duplicate of an existing prerender. If yes, clean up
8207d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // the new handle.
8217d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  for (int i = 0; i < static_cast<int>(issued_prerenders_.size()); i++) {
8227d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    PrerenderProperties* p = issued_prerenders_[i];
8237d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    DCHECK(p != NULL);
8247d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    if (new_prerender_handle &&
8257d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        new_prerender_handle->RepresentingSamePrerenderAs(
8267d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)            p->prerender_handle.get())) {
8277d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      new_prerender_handle->OnCancel();
8287d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      new_prerender_handle.reset(NULL);
82958e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch      RecordEvent(EVENT_ISSUE_PRERENDER_ALREADY_PRERENDERING);
8307d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      break;
8317d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    }
8327d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  }
8337d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
8347d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (new_prerender_handle.get()) {
83558e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch    RecordEvent(EVENT_ISSUE_PRERENDER_NEW_PRERENDER);
8367d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    // The new prerender does not match any existing prerenders. Update
8377d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    // prerender_properties so that it reflects the new entry.
8387d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    prerender_properties->url_id = url_id;
8397d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    prerender_properties->url = url;
8407d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    prerender_properties->priority = priority;
8417d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    prerender_properties->start_time = current_time;
8427d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    prerender_properties->actual_start_time = current_time;
8437d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    prerender_properties->would_have_matched = false;
8447d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    prerender_properties->prerender_handle.swap(new_prerender_handle);
8457d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    // new_prerender_handle now represents the old previou prerender that we
8467d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    // are replacing. So we need to cancel it.
84758e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch    if (new_prerender_handle) {
8487d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      new_prerender_handle->OnCancel();
84958e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch      RecordEvent(EVENT_ISSUE_PRERENDER_CANCELLED_OLD_PRERENDER);
85058e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch    }
8517d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  }
852b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
853b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  RecordEvent(EVENT_ADD_VISIT_PRERENDERING);
854b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (current_prerender_.get() && current_prerender_->url_id == url_id) {
855b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    RecordEvent(EVENT_ADD_VISIT_PRERENDERING_EXTENDED);
856b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    if (priority > current_prerender_->priority)
857b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      current_prerender_->priority = priority;
858b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    // If the prerender already existed, we want to extend it.  However,
859b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    // we do not want to set its start_time to the current time to
860b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    // disadvantage PLT computations when the prerender is swapped in.
861b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    // So we set the new start time to current_time - 10s (since the vast
862b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    // majority of PLTs are < 10s), provided that is not before the actual
863b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    // time the prerender was started (so as to not artificially advantage
864b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    // the PLT computation).
865b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    base::Time simulated_new_start_time =
866b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        current_time - base::TimeDelta::FromSeconds(10);
867b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    if (simulated_new_start_time > current_prerender_->start_time)
868b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      current_prerender_->start_time = simulated_new_start_time;
869b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  } else {
870b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    current_prerender_.reset(
871b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        new PrerenderProperties(url_id, url, priority, current_time));
872b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  }
873b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  current_prerender_->actual_start_time = current_time;
8745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
876a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)void PrerenderLocalPredictor::OnTabHelperURLSeen(
877a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    const GURL& url, WebContents* web_contents) {
878a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  RecordEvent(EVENT_TAB_HELPER_URL_SEEN);
8797d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
880a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  // If the namespace matches and the URL matches, we might be able to swap
881a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  // in. However, the actual code initating the swapin is in the renderer
882a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  // and is checking for other criteria (such as POSTs). There may
883a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  // also be conditions when a swapin should happen but does not. By recording
884a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  // the two previous events, we can keep an eye on the magnitude of the
885a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  // discrepancy.
8867d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
8877d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  PrerenderProperties* best_matched_prerender = NULL;
8887d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  bool session_storage_namespace_matches = false;
8897d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  for (int i = 0; i < static_cast<int>(issued_prerenders_.size()); i++) {
8907d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    PrerenderProperties* p = issued_prerenders_[i];
8917d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    DCHECK(p != NULL);
8927d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    if (!p->prerender_handle.get() ||
8937d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        !p->prerender_handle->Matches(url, NULL) ||
8947d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        p->would_have_matched) {
8957d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      continue;
8967d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    }
8977d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    if (!best_matched_prerender || !session_storage_namespace_matches) {
8987d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      best_matched_prerender = p;
8997d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      session_storage_namespace_matches =
9007d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)          p->prerender_handle->Matches(
9017d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)              url,
9027d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)              web_contents->GetController().
903ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch              GetDefaultSessionStorageNamespace());
9047d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    }
9057d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  }
9067d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (best_matched_prerender) {
9077d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    RecordEvent(EVENT_TAB_HELPER_URL_SEEN_MATCH);
9087d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    best_matched_prerender->would_have_matched = true;
9097d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    if (session_storage_namespace_matches)
9107d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      RecordEvent(EVENT_TAB_HELPER_URL_SEEN_NAMESPACE_MATCH);
9117d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  }
912a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)}
913a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
9145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace prerender
915