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)
1558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "base/json/json_reader.h"
1658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "base/json/json_writer.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/metrics/field_trial.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/metrics/histogram.h"
1958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "base/stl_util.h"
20eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/timer/timer.h"
2190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "chrome/browser/browser_process.h"
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/history/history_database.h"
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/history/history_db_task.h"
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/history/history_service.h"
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/history/history_service_factory.h"
267d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "chrome/browser/prerender/prerender_field_trial.h"
27b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "chrome/browser/prerender/prerender_handle.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/prerender/prerender_histograms.h"
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/prerender/prerender_manager.h"
30a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "chrome/browser/prerender/prerender_util.h"
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h"
3290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "chrome/browser/safe_browsing/database_manager.h"
3390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "chrome/browser/safe_browsing/safe_browsing_service.h"
34b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "chrome/browser/ui/tab_contents/tab_contents_iterator.h"
356d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#include "chrome/common/prefetch_messages.h"
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/browser_thread.h"
37b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "content/public/browser/navigation_controller.h"
38a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "content/public/browser/navigation_entry.h"
396d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#include "content/public/browser/render_frame_host.h"
406d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#include "content/public/browser/render_process_host.h"
41b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "content/public/browser/web_contents.h"
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "crypto/secure_hash.h"
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/browser_resources.h"
4458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "net/base/escape.h"
45d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "net/base/load_flags.h"
4658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "net/url_request/url_fetcher.h"
471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "ui/base/page_transition_types.h"
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/resource/resource_bundle.h"
49eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "url/url_canon.h"
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)using base::DictionaryValue;
5258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)using base::ListValue;
5358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)using base::Value;
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::BrowserThread;
551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciusing ui::PageTransition;
566d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)using content::RenderFrameHost;
57b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)using content::SessionStorageNamespace;
58b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)using content::WebContents;
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using history::URLID;
6058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)using net::URLFetcher;
61b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)using predictors::LoggedInPredictorTable;
62b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)using std::string;
63b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)using std::vector;
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace prerender {
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const size_t kURLHashSize = 5;
70b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)static const int kNumPrerenderCandidates = 5;
716d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)static const int kInvalidProcessId = -1;
726d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)static const int kInvalidFrameId = -1;
735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)static const int kMaxPrefetchItems = 100;
74b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
75b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}  // namespace
76b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
77b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)// When considering a candidate URL to be prerendered, we need to collect the
78b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)// data in this struct to make the determination whether we should issue the
79b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)// prerender or not.
80b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)struct PrerenderLocalPredictor::LocalPredictorURLInfo {
81b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  URLID id;
82b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  GURL url;
83b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  bool url_lookup_success;
84b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  bool logged_in;
85b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  bool logged_in_lookup_ok;
8658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  bool local_history_based;
8758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  bool service_whitelist;
8858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  bool service_whitelist_lookup_ok;
8958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  bool service_whitelist_reported;
90b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  double priority;
91b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)};
92b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
93b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)// A struct consisting of everything needed for launching a potential prerender
94b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)// on a navigation: The navigation URL (source) triggering potential prerenders,
95b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)// and a set of candidate URLs.
9658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)struct PrerenderLocalPredictor::CandidatePrerenderInfo {
97b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  LocalPredictorURLInfo source_url_;
98b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  vector<LocalPredictorURLInfo> candidate_urls_;
9958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  scoped_refptr<SessionStorageNamespace> session_storage_namespace_;
1006d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // Render Process ID and Route ID of the page causing the prerender to be
1016d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // issued. Needed so that we can cause its renderer to issue prefetches within
1026d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // its context.
1036d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  int render_process_id_;
1046d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  int render_frame_id_;
10558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  scoped_ptr<gfx::Size> size_;
10658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  base::Time start_time_;  // used for various time measurements
1076d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  explicit CandidatePrerenderInfo(URLID source_id)
1086d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      : render_process_id_(kInvalidProcessId),
1096d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        render_frame_id_(kInvalidFrameId) {
110b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    source_url_.id = source_id;
111b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  }
11258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  void MaybeAddCandidateURLFromLocalData(URLID id, double priority) {
113b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    LocalPredictorURLInfo info;
114b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    info.id = id;
11558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    info.local_history_based = true;
11658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    info.service_whitelist = false;
11758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    info.service_whitelist_lookup_ok = false;
11858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    info.service_whitelist_reported = false;
11958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    info.priority = priority;
12058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    MaybeAddCandidateURLInternal(info);
12158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
12258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  void MaybeAddCandidateURLFromService(GURL url, double priority,
12358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                                       bool whitelist,
12458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                                       bool whitelist_lookup_ok) {
12558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    LocalPredictorURLInfo info;
12658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    info.id = kint64max;
12758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    info.url = url;
12858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    info.url_lookup_success = true;
12958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    info.local_history_based = false;
13058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    info.service_whitelist = whitelist;
13158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    info.service_whitelist_lookup_ok = whitelist_lookup_ok;
13258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    info.service_whitelist_reported = true;
133b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    info.priority = priority;
13458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    MaybeAddCandidateURLInternal(info);
13558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
13658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  void MaybeAddCandidateURLInternal(const LocalPredictorURLInfo& info) {
13758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // TODO(tburkard): clean up this code, potentially using a list or a heap
13858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    int max_candidates = kNumPrerenderCandidates;
13958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // We first insert local candidates, then service candidates.
14058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // Since we want to keep kNumPrerenderCandidates for both local & service
14158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // candidates, we need to double the maximum number of candidates once
14258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // we start seeing service candidates.
14358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if (!info.local_history_based)
14458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      max_candidates *= 2;
145b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    int insert_pos = candidate_urls_.size();
14658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if (insert_pos < max_candidates)
147b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      candidate_urls_.push_back(info);
148b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    while (insert_pos > 0 &&
149b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)           candidate_urls_[insert_pos - 1].priority < info.priority) {
15058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      if (insert_pos < max_candidates)
151b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        candidate_urls_[insert_pos] = candidate_urls_[insert_pos - 1];
152b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      insert_pos--;
153b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    }
15458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if (insert_pos < max_candidates)
155b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      candidate_urls_[insert_pos] = info;
156b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  }
157b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)};
158b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
159b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)namespace {
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#define TIMING_HISTOGRAM(name, value)                               \
16258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  UMA_HISTOGRAM_CUSTOM_TIMES(name, value,                           \
16358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                             base::TimeDelta::FromMilliseconds(10), \
16458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                             base::TimeDelta::FromSeconds(10),      \
16558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                             50);
16658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Task to lookup the URL for a given URLID.
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class GetURLForURLIDTask : public history::HistoryDBTask {
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
170b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  GetURLForURLIDTask(
17158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      PrerenderLocalPredictor::CandidatePrerenderInfo* request,
172b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      const base::Closure& callback)
173b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      : request_(request),
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        callback_(callback),
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        start_time_(base::Time::Now()) {
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual bool RunOnDBThread(history::HistoryBackend* backend,
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             history::HistoryDatabase* db) OVERRIDE {
180b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    DoURLLookup(db, &request_->source_url_);
181b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    for (int i = 0; i < static_cast<int>(request_->candidate_urls_.size()); i++)
182b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      DoURLLookup(db, &request_->candidate_urls_[i]);
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void DoneRunOnMainThread() OVERRIDE {
187b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    callback_.Run();
18858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    TIMING_HISTOGRAM("Prerender.LocalPredictorURLLookupTime",
18958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                     base::Time::Now() - start_time_);
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~GetURLForURLIDTask() {}
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
195b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  void DoURLLookup(history::HistoryDatabase* db,
196b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                   PrerenderLocalPredictor::LocalPredictorURLInfo* request) {
197b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    history::URLRow url_row;
198b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    request->url_lookup_success = db->GetURLRow(request->id, &url_row);
199b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    if (request->url_lookup_success)
200b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      request->url = url_row.url();
201b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  }
202b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
20358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  PrerenderLocalPredictor::CandidatePrerenderInfo* request_;
204b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  base::Closure callback_;
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::Time start_time_;
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(GetURLForURLIDTask);
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Task to load history from the visit database on startup.
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class GetVisitHistoryTask : public history::HistoryDBTask {
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetVisitHistoryTask(PrerenderLocalPredictor* local_predictor,
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      int max_visits)
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : local_predictor_(local_predictor),
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        max_visits_(max_visits),
216b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        visit_history_(new vector<history::BriefVisitInfo>) {
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual bool RunOnDBThread(history::HistoryBackend* backend,
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             history::HistoryDatabase* db) OVERRIDE {
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db->GetBriefVisitInfoOfMostRecentVisits(max_visits_, visit_history_.get());
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void DoneRunOnMainThread() OVERRIDE {
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    local_predictor_->OnGetInitialVisitHistory(visit_history_.Pass());
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~GetVisitHistoryTask() {}
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PrerenderLocalPredictor* local_predictor_;
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int max_visits_;
234b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  scoped_ptr<vector<history::BriefVisitInfo> > visit_history_;
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(GetVisitHistoryTask);
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Maximum visit history to retrieve from the visit database.
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kMaxVisitHistory = 100 * 1000;
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Visit history size at which to trigger pruning, and number of items to prune.
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kVisitHistoryPruneThreshold = 120 * 1000;
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kVisitHistoryPruneAmount = 20 * 1000;
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kMinLocalPredictionTimeMs = 500;
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2477d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)int GetMaxLocalPredictionTimeMs() {
2487d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return GetLocalPredictorTTLSeconds() * 1000;
2497d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
2507d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool IsBackForward(PageTransition transition) {
2521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return (transition & ui::PAGE_TRANSITION_FORWARD_BACK) != 0;
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool IsHomePage(PageTransition transition) {
2561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return (transition & ui::PAGE_TRANSITION_HOME_PAGE) != 0;
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool IsIntermediateRedirect(PageTransition transition) {
2601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return (transition & ui::PAGE_TRANSITION_CHAIN_END) == 0;
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26358e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdochbool IsFormSubmit(PageTransition transition) {
2641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return ui::PageTransitionCoreTypeIs(transition,
2651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                      ui::PAGE_TRANSITION_FORM_SUBMIT);
26658e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch}
26758e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ShouldExcludeTransitionForPrediction(PageTransition transition) {
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return IsBackForward(transition) || IsHomePage(transition) ||
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      IsIntermediateRedirect(transition);
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)base::Time GetCurrentTime() {
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return base::Time::Now();
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
277b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)bool StringContainsIgnoringCase(string haystack, string needle) {
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::transform(haystack.begin(), haystack.end(), haystack.begin(), ::tolower);
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::transform(needle.begin(), needle.end(), needle.begin(), ::tolower);
280b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  return haystack.find(needle) != string::npos;
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool IsExtendedRootURL(const GURL& url) {
284b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  const string& path = url.path();
2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return path == "/index.html" || path == "/home.html" ||
2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      path == "/main.html" ||
2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      path == "/index.htm" || path == "/home.htm" || path == "/main.htm" ||
2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      path == "/index.php" || path == "/home.php" || path == "/main.php" ||
2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      path == "/index.asp" || path == "/home.asp" || path == "/main.asp" ||
2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      path == "/index.py" || path == "/home.py" || path == "/main.py" ||
2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      path == "/index.pl" || path == "/home.pl" || path == "/main.pl";
2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool IsRootPageURL(const GURL& url) {
2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return (url.path() == "/" || url.path() == "" || IsExtendedRootURL(url)) &&
2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      (!url.has_query()) && (!url.has_ref());
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
299b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)bool IsLogInURL(const GURL& url) {
300b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  return StringContainsIgnoringCase(url.spec().c_str(), "login") ||
301b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      StringContainsIgnoringCase(url.spec().c_str(), "signin");
302b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
303b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
304b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)bool IsLogOutURL(const GURL& url) {
305b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  return StringContainsIgnoringCase(url.spec().c_str(), "logout") ||
306b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      StringContainsIgnoringCase(url.spec().c_str(), "signout");
307b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
308b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int64 URLHashToInt64(const unsigned char* data) {
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  COMPILE_ASSERT(kURLHashSize < sizeof(int64), url_hash_must_fit_in_int64);
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int64 value = 0;
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memcpy(&value, data, kURLHashSize);
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return value;
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int64 GetInt64URLHashForURL(const GURL& url) {
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  COMPILE_ASSERT(kURLHashSize < sizeof(int64), url_hash_must_fit_in_int64);
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<crypto::SecureHash> hash(
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int64 hash_value = 0;
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char* url_string = url.spec().c_str();
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hash->Update(url_string, strlen(url_string));
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hash->Finish(&hash_value, kURLHashSize);
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return hash_value;
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
327b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)bool URLsIdenticalIgnoringFragments(const GURL& url1, const GURL& url2) {
3285c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  url::Replacements<char> replacement;
329b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  replacement.ClearRef();
330b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  GURL u1 = url1.ReplaceComponents(replacement);
331b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  GURL u2 = url2.ReplaceComponents(replacement);
332b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  return (u1 == u2);
333b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
334b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
335b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void LookupLoggedInStatesOnDBThread(
336b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    scoped_refptr<LoggedInPredictorTable> logged_in_predictor_table,
33758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    PrerenderLocalPredictor::CandidatePrerenderInfo* request) {
338b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
33958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  for (int i = 0; i < static_cast<int>(request->candidate_urls_.size()); i++) {
340b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    PrerenderLocalPredictor::LocalPredictorURLInfo* info =
34158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        &request->candidate_urls_[i];
342b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    if (info->url_lookup_success) {
343b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      logged_in_predictor_table->HasUserLoggedIn(
344b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)          info->url, &info->logged_in, &info->logged_in_lookup_ok);
345b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    } else {
346b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      info->logged_in_lookup_ok = false;
347b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    }
348b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  }
349b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
350b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
353b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)struct PrerenderLocalPredictor::PrerenderProperties {
354b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  PrerenderProperties(URLID url_id, const GURL& url, double priority,
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                base::Time start_time)
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : url_id(url_id),
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        url(url),
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        priority(priority),
359424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        start_time(start_time),
360424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        would_have_matched(false) {
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3637d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // Default constructor for dummy element
3647d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  PrerenderProperties()
365424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      : priority(0.0), would_have_matched(false) {
3667d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  }
3677d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
3687d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  double GetCurrentDecayedPriority() {
3697d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    // If we are no longer prerendering, the priority is 0.
3707d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    if (!prerender_handle || !prerender_handle->IsPrerendering())
3717d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      return 0.0;
3727d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    int half_life_time_seconds =
3737d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        GetLocalPredictorPrerenderPriorityHalfLifeTimeSeconds();
3747d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    if (half_life_time_seconds < 1)
3757d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      return priority;
3767d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    double multiple_elapsed =
3777d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        (GetCurrentTime() - actual_start_time).InMillisecondsF() /
3787d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        base::TimeDelta::FromSeconds(half_life_time_seconds).InMillisecondsF();
3797d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    // Decay factor: 2 ^ (-multiple_elapsed)
3807d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    double decay_factor = exp(- multiple_elapsed * log(2.0));
3817d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return priority * decay_factor;
3827d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  }
3837d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLID url_id;
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GURL url;
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  double priority;
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // For expiration purposes, this is a synthetic start time consisting either
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // of the actual start time, or of the last time the page was re-requested
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // for prerendering - 10 seconds (unless the original request came after
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // that).  This is to emulate the effect of re-prerendering a page that is
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // about to expire, because it was re-requested for prerendering a second
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // time after the actual prerender being kept around.
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::Time start_time;
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The actual time this page was last requested for prerendering.
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::Time actual_start_time;
3967d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  scoped_ptr<PrerenderHandle> prerender_handle;
3977d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // Indicates whether this prerender would have matched a URL navigated to,
3987d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // but was not swapped in for some reason.
3997d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  bool would_have_matched;
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// A class simulating a set of URLs prefetched, for statistical purposes.
4035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)class PrerenderLocalPredictor::PrefetchList {
4045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) public:
4055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  enum SeenType {
4065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    SEEN_TABCONTENTS_OBSERVER,
4075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    SEEN_HISTORY,
4085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    SEEN_MAX_VALUE
4095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  };
4105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  PrefetchList() {}
4125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  ~PrefetchList() {
4135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    STLDeleteValues(&entries_);
4145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
4155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Adds a new URL being prefetched. If the URL is already in the list,
4175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // nothing will happen. Returns whether a new prefetch was added.
4185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  bool AddURL(const GURL& url) {
4195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    ExpireOldItems();
4205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    string url_string = url.spec().c_str();
4215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    base::hash_map<string, ListEntry*>::iterator it = entries_.find(url_string);
4225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (it != entries_.end()) {
4235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      // If a prefetch previously existed, and has not been seen yet in either
4245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      // a tab contents or a history, we will not re-issue it. Otherwise, if it
4255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      // may have been consumed by either tab contents or history, we will
4265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      // permit re-issuing another one.
4275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      if (!it->second->seen_history_ &&
4285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          !it->second->seen_tabcontents_) {
4295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return false;
4305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      }
4315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
4325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    ListEntry* entry = new ListEntry(url_string);
4335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    entries_[entry->url_] = entry;
4345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    entry_list_.push_back(entry);
4355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    ExpireOldItems();
4365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return true;
4375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
4385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Marks the URL provided as seen in the context specified. Returns true
4405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // iff the item is currently in the list and had not been seen before in
4415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // the context specified, i.e. the marking was successful.
4425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  bool MarkURLSeen(const GURL& url, SeenType type) {
4435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    ExpireOldItems();
4445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    bool return_value = false;
4455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    base::hash_map<string, ListEntry*>::iterator it =
4465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        entries_.find(url.spec().c_str());
4475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (it == entries_.end())
4485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return return_value;
4495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (type == SEEN_TABCONTENTS_OBSERVER && !it->second->seen_tabcontents_) {
4505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      it->second->seen_tabcontents_ = true;
4515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return_value = true;
4525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
4535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (type == SEEN_HISTORY && !it->second->seen_history_) {
4545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      it->second->seen_history_ = true;
4555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return_value = true;
4565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
4575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // If the item has been seen in both the history and in tab contents,
45803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    // and the page load time has been recorded, erase it from the map to
45903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    // make room for new prefetches.
46003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if (it->second->seen_tabcontents_ && it->second->seen_history_ &&
46103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        it->second->seen_plt_) {
4625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      entries_.erase(url.spec().c_str());
46303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    }
4645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return return_value;
4655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
4665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
46703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // Marks the PLT for the provided UR as seen. Returns true
46803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // iff the item is currently in the list and the PLT had not been seen
46903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // before, i.e. the sighting was successful.
47003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  bool MarkPLTSeen(const GURL& url, base::TimeDelta plt) {
47103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    ExpireOldItems();
47203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    base::hash_map<string, ListEntry*>::iterator it =
47303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        entries_.find(url.spec().c_str());
47403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if (it == entries_.end() || it->second->seen_plt_ ||
47503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        it->second->add_time_ > GetCurrentTime() - plt) {
47603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      return false;
47703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    }
47803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    it->second->seen_plt_ = true;
47903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    // If the item has been seen in both the history and in tab contents,
48003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    // and the page load time has been recorded, erase it from the map to
48103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    // make room for new prefetches.
48203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if (it->second->seen_tabcontents_ && it->second->seen_history_ &&
48303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        it->second->seen_plt_) {
48403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      entries_.erase(url.spec().c_str());
48503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    }
48603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return true;
48703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
48803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
4895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) private:
4905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  struct ListEntry {
4915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    explicit ListEntry(const string& url)
4925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        : url_(url),
4935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          add_time_(GetCurrentTime()),
4945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          seen_tabcontents_(false),
49503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)          seen_history_(false),
49603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)          seen_plt_(false) {
4975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
4985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    std::string url_;
4995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    base::Time add_time_;
5005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    bool seen_tabcontents_;
5015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    bool seen_history_;
50203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    bool seen_plt_;
5035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  };
5045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
5055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  void ExpireOldItems() {
5065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    base::Time expiry_cutoff = GetCurrentTime() -
5075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        base::TimeDelta::FromSeconds(GetPrerenderPrefetchListTimeoutSeconds());
5085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    while (!entry_list_.empty() &&
5095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)           (entry_list_.front()->add_time_ < expiry_cutoff ||
5105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            entries_.size() > kMaxPrefetchItems)) {
5115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      ListEntry* entry = entry_list_.front();
5125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      entry_list_.pop_front();
5135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      // If the entry to be deleted is still the one active in entries_,
5145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      // we must erase it from entries_.
5155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      base::hash_map<string, ListEntry*>::iterator it =
5165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          entries_.find(entry->url_);
5175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      if (it != entries_.end() && it->second == entry)
5185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        entries_.erase(entry->url_);
5195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      delete entry;
5205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
5215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
5225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
5235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  base::hash_map<string, ListEntry*> entries_;
5245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  std::list<ListEntry*> entry_list_;
5255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(PrefetchList);
5265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)};
5275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PrerenderLocalPredictor::PrerenderLocalPredictor(
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PrerenderManager* prerender_manager)
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : prerender_manager_(prerender_manager),
531b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      is_visit_database_observer_(false),
5325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      weak_factory_(this),
5335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      prefetch_list_(new PrefetchList()) {
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RecordEvent(EVENT_CONSTRUCTED);
53590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (base::MessageLoop::current()) {
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    timer_.Start(FROM_HERE,
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 base::TimeDelta::FromMilliseconds(kInitDelayMs),
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 this,
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 &PrerenderLocalPredictor::Init);
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RecordEvent(EVENT_INIT_SCHEDULED);
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const size_t kChecksumHashSize = 32;
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::RefCountedStaticMemory* url_whitelist_data =
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ResourceBundle::GetSharedInstance().LoadDataResourceBytes(
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          IDR_PRERENDER_URL_WHITELIST);
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t size = url_whitelist_data->size();
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const unsigned char* front = url_whitelist_data->front();
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (size < kChecksumHashSize ||
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (size - kChecksumHashSize) % kURLHashSize != 0) {
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RecordEvent(EVENT_URL_WHITELIST_ERROR);
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<crypto::SecureHash> hash(
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hash->Update(front + kChecksumHashSize, size - kChecksumHashSize);
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char hash_value[kChecksumHashSize];
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hash->Finish(hash_value, kChecksumHashSize);
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (memcmp(hash_value, front, kChecksumHashSize)) {
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RecordEvent(EVENT_URL_WHITELIST_ERROR);
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (const unsigned char* p = front + kChecksumHashSize;
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       p < front + size;
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       p += kURLHashSize) {
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_whitelist_.insert(URLHashToInt64(p));
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RecordEvent(EVENT_URL_WHITELIST_OK);
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PrerenderLocalPredictor::~PrerenderLocalPredictor() {
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Shutdown();
5737d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  for (int i = 0; i < static_cast<int>(issued_prerenders_.size()); i++) {
5747d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    PrerenderProperties* p = issued_prerenders_[i];
5757d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    DCHECK(p != NULL);
5767d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    if (p->prerender_handle)
5777d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      p->prerender_handle->OnCancel();
5787d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  }
57958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  STLDeleteContainerPairPointers(
58058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      outstanding_prerender_service_requests_.begin(),
58158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      outstanding_prerender_service_requests_.end());
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PrerenderLocalPredictor::Shutdown() {
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  timer_.Stop();
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (is_visit_database_observer_) {
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HistoryService* history = GetHistoryIfExists();
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CHECK(history);
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    history->RemoveVisitDatabaseObserver(this);
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    is_visit_database_observer_ = false;
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PrerenderLocalPredictor::OnAddVisit(const history::BriefVisitInfo& info) {
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RecordEvent(EVENT_ADD_VISIT);
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!visit_history_.get())
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  visit_history_->push_back(info);
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (static_cast<int>(visit_history_->size()) > kVisitHistoryPruneThreshold) {
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    visit_history_->erase(visit_history_->begin(),
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          visit_history_->begin() + kVisitHistoryPruneAmount);
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RecordEvent(EVENT_ADD_VISIT_INITIALIZED);
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (current_prerender_.get() &&
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      current_prerender_->url_id == info.url_id &&
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      IsPrerenderStillValid(current_prerender_.get())) {
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UMA_HISTOGRAM_CUSTOM_TIMES(
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "Prerender.LocalPredictorTimeUntilUsed",
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        GetCurrentTime() - current_prerender_->actual_start_time,
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::TimeDelta::FromMilliseconds(10),
6127d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        base::TimeDelta::FromMilliseconds(GetMaxLocalPredictionTimeMs()),
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        50);
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    last_swapped_in_prerender_.reset(current_prerender_.release());
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RecordEvent(EVENT_ADD_VISIT_PRERENDER_IDENTIFIED);
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (ShouldExcludeTransitionForPrediction(info.transition))
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
6191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  Profile* profile = prerender_manager_->profile();
6201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!profile ||
6211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      ShouldDisableLocalPredictorDueToPreferencesAndNetwork(profile)) {
6221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return;
6231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RecordEvent(EVENT_ADD_VISIT_RELEVANT_TRANSITION);
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::TimeDelta max_age =
6267d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      base::TimeDelta::FromMilliseconds(GetMaxLocalPredictionTimeMs());
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::TimeDelta min_age =
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::TimeDelta::FromMilliseconds(kMinLocalPredictionTimeMs);
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::set<URLID> next_urls_currently_found;
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::map<URLID, int> next_urls_num_found;
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int num_occurrences_of_current_visit = 0;
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::Time last_visited;
63358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  scoped_ptr<CandidatePrerenderInfo> lookup_info(
63458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      new CandidatePrerenderInfo(info.url_id));
635b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  const vector<history::BriefVisitInfo>& visits = *(visit_history_.get());
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < static_cast<int>(visits.size()); i++) {
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!ShouldExcludeTransitionForPrediction(visits[i].transition)) {
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (visits[i].url_id == info.url_id) {
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        last_visited = visits[i].time;
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        num_occurrences_of_current_visit++;
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        next_urls_currently_found.clear();
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        continue;
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!last_visited.is_null() &&
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          last_visited > visits[i].time - max_age &&
6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          last_visited < visits[i].time - min_age) {
64758e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch        if (!IsFormSubmit(visits[i].transition))
64858e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch          next_urls_currently_found.insert(visits[i].url_id);
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (i == static_cast<int>(visits.size()) - 1 ||
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        visits[i+1].url_id == info.url_id) {
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for (std::set<URLID>::iterator it = next_urls_currently_found.begin();
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           it != next_urls_currently_found.end();
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           ++it) {
6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        std::pair<std::map<URLID, int>::iterator, bool> insert_ret =
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            next_urls_num_found.insert(std::pair<URLID, int>(*it, 0));
6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        std::map<URLID, int>::iterator num_found_it = insert_ret.first;
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        num_found_it->second++;
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
66458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (num_occurrences_of_current_visit > 1) {
66558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    RecordEvent(EVENT_ADD_VISIT_RELEVANT_TRANSITION_REPEAT_URL);
66658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  } else {
66758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    RecordEvent(EVENT_ADD_VISIT_RELEVANT_TRANSITION_NEW_URL);
66858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
66958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
670b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  for (std::map<URLID, int>::const_iterator it = next_urls_num_found.begin();
671b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)       it != next_urls_num_found.end();
672b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)       ++it) {
673b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    // Only consider a candidate next page for prerendering if it was viewed
674b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    // at least twice, and at least 10% of the time.
675b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    if (num_occurrences_of_current_visit > 0 &&
676b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        it->second > 1 &&
677b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        it->second * 10 >= num_occurrences_of_current_visit) {
678b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      RecordEvent(EVENT_ADD_VISIT_IDENTIFIED_PRERENDER_CANDIDATE);
679b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      double priority = static_cast<double>(it->second) /
680b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)          static_cast<double>(num_occurrences_of_current_visit);
68158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      lookup_info->MaybeAddCandidateURLFromLocalData(it->first, priority);
6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
684b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
685b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  RecordEvent(EVENT_START_URL_LOOKUP);
686b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  HistoryService* history = GetHistoryIfExists();
687b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (history) {
688b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    RecordEvent(EVENT_GOT_HISTORY_ISSUING_LOOKUP);
68958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    CandidatePrerenderInfo* lookup_info_ptr = lookup_info.get();
690b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    history->ScheduleDBTask(
6915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        scoped_ptr<history::HistoryDBTask>(
6925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            new GetURLForURLIDTask(
6935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                lookup_info_ptr,
6945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                base::Bind(&PrerenderLocalPredictor::OnLookupURL,
6955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                           base::Unretained(this),
6965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                           base::Passed(&lookup_info)))),
697116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        &history_db_tracker_);
698b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  }
6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
701b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void PrerenderLocalPredictor::OnLookupURL(
70258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    scoped_ptr<CandidatePrerenderInfo> info) {
70358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
70558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  RecordEvent(EVENT_PRERENDER_URL_LOOKUP_RESULT);
706b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
707b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!info->source_url_.url_lookup_success) {
708b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    RecordEvent(EVENT_PRERENDER_URL_LOOKUP_FAILED);
709b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    return;
710b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  }
711b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
7125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (prefetch_list_->MarkURLSeen(info->source_url_.url,
7135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                  PrefetchList::SEEN_HISTORY)) {
7145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    RecordEvent(EVENT_PREFETCH_LIST_SEEN_HISTORY);
7155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
7165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
71758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (info->candidate_urls_.size() > 0 &&
71858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      info->candidate_urls_[0].url_lookup_success) {
71958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    LogCandidateURLStats(info->candidate_urls_[0].url);
72058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
721b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
722b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  WebContents* source_web_contents = NULL;
723a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  bool multiple_source_web_contents_candidates = false;
724b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
725b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#if !defined(OS_ANDROID)
726b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  // We need to figure out what tab launched the prerender. We do this by
727b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  // comparing URLs. This may not always work: the URL may occur in two
728b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  // tabs, and we pick the wrong one, or the tab we should have picked
729b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  // may have navigated elsewhere. Hopefully, this doesn't happen too often,
730b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  // so we ignore these cases for now.
731b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  // TODO(tburkard): Reconsider this, potentially measure it, and fix this
732b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  // in the future.
733b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  for (TabContentsIterator it; !it.done(); it.Next()) {
734b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    if (it->GetURL() == info->source_url_.url) {
735a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      if (!source_web_contents)
736a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        source_web_contents = *it;
737a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      else
738a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        multiple_source_web_contents_candidates = true;
7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
741b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#endif
742b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
743b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!source_web_contents) {
744b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    RecordEvent(EVENT_PRERENDER_URL_LOOKUP_NO_SOURCE_WEBCONTENTS_FOUND);
745b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    return;
746b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  }
747b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
748a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  if (multiple_source_web_contents_candidates)
749a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    RecordEvent(EVENT_PRERENDER_URL_LOOKUP_MULTIPLE_SOURCE_WEBCONTENTS_FOUND);
750a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
75158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  info->session_storage_namespace_ =
752ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      source_web_contents->GetController().GetDefaultSessionStorageNamespace();
7536d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  RenderFrameHost* rfh = source_web_contents->GetMainFrame();
7546d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  info->render_process_id_ = rfh->GetProcess()->GetID();
7556d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  info->render_frame_id_ = rfh->GetRoutingID();
756b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
757010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  gfx::Rect container_bounds = source_web_contents->GetContainerBounds();
75858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  info->size_.reset(new gfx::Size(container_bounds.size()));
75958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
76058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  RecordEvent(EVENT_PRERENDER_URL_LOOKUP_SUCCESS);
76158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
76258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  DoPrerenderServiceCheck(info.Pass());
76358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
76458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
76558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void PrerenderLocalPredictor::DoPrerenderServiceCheck(
76658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    scoped_ptr<CandidatePrerenderInfo> info) {
76758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
76858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (!ShouldQueryPrerenderService(prerender_manager_->profile())) {
76958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    RecordEvent(EVENT_PRERENDER_SERVICE_DISABLED);
77058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    DoLoggedInLookup(info.Pass());
77158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return;
77258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
77358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  /*
77458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    Create a JSON request.
77558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    Here is a sample request:
77658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    { "prerender_request": {
77758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        "version": 1,
77858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        "behavior_id": 6,
77958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        "hint_request": {
78058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          "browse_history": [
78158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            { "url": "http://www.cnn.com/"
78258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            }
78358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          ]
78458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        },
78558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        "candidate_check_request": {
78658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          "candidates": [
78758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            { "url": "http://www.cnn.com/sports/"
78858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            },
78958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            { "url": "http://www.cnn.com/politics/"
79058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            }
79158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          ]
79258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        }
79358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      }
79458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    }
79558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  */
7965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::DictionaryValue json_data;
7975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::DictionaryValue* req = new base::DictionaryValue();
79858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  req->SetInteger("version", 1);
79958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  req->SetInteger("behavior_id", GetPrerenderServiceBehaviorID());
80058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (ShouldQueryPrerenderServiceForCurrentURL() &&
80158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      info->source_url_.url_lookup_success) {
8025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::ListValue* browse_history = new base::ListValue();
8035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::DictionaryValue* browse_item = new base::DictionaryValue();
80458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    browse_item->SetString("url", info->source_url_.url.spec());
80558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    browse_history->Append(browse_item);
8065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::DictionaryValue* hint_request = new base::DictionaryValue();
80758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    hint_request->Set("browse_history", browse_history);
80858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    req->Set("hint_request", hint_request);
80958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
81058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  int num_candidate_urls = 0;
81158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  for (int i = 0; i < static_cast<int>(info->candidate_urls_.size()); i++) {
81258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if (info->candidate_urls_[i].url_lookup_success)
81358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      num_candidate_urls++;
81458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
81558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (ShouldQueryPrerenderServiceForCandidateURLs() &&
81658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      num_candidate_urls > 0) {
8175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::ListValue* candidates = new base::ListValue();
8185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::DictionaryValue* candidate;
81958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    for (int i = 0; i < static_cast<int>(info->candidate_urls_.size()); i++) {
82058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      if (info->candidate_urls_[i].url_lookup_success) {
8215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        candidate = new base::DictionaryValue();
82258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        candidate->SetString("url", info->candidate_urls_[i].url.spec());
82358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        candidates->Append(candidate);
82458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      }
82558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    }
8265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::DictionaryValue* candidate_check_request =
8275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        new base::DictionaryValue();
82858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    candidate_check_request->Set("candidates", candidates);
82958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    req->Set("candidate_check_request", candidate_check_request);
83058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
83158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  json_data.Set("prerender_request", req);
83258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  string request_string;
83358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  base::JSONWriter::Write(&json_data, &request_string);
83458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  GURL fetch_url(GetPrerenderServiceURLPrefix() +
83558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                 net::EscapeQueryParamValue(request_string, false));
83658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  net::URLFetcher* fetcher = net::URLFetcher::Create(
83758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      0,
83858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      fetch_url,
83958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      URLFetcher::GET, this);
84058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  fetcher->SetRequestContext(
84158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      prerender_manager_->profile()->GetRequestContext());
842d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  fetcher->SetLoadFlags(net::LOAD_DISABLE_CACHE |
843d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                        net::LOAD_DO_NOT_SAVE_COOKIES |
844d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                        net::LOAD_DO_NOT_SEND_COOKIES);
84558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  fetcher->AddExtraRequestHeader("Pragma: no-cache");
84658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  info->start_time_ = base::Time::Now();
84758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  outstanding_prerender_service_requests_.insert(
84858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      std::make_pair(fetcher, info.release()));
84958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  base::MessageLoop::current()->PostDelayedTask(
85058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      FROM_HERE,
85158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      base::Bind(&PrerenderLocalPredictor::MaybeCancelURLFetcher,
85258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                 weak_factory_.GetWeakPtr(), fetcher),
85358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      base::TimeDelta::FromMilliseconds(GetPrerenderServiceFetchTimeoutMs()));
85458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  RecordEvent(EVENT_PRERENDER_SERVICE_ISSUED_LOOKUP);
85558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  fetcher->Start();
85658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
85758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
85858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void PrerenderLocalPredictor::MaybeCancelURLFetcher(net::URLFetcher* fetcher) {
85958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
86058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  OutstandingFetchers::iterator it =
86158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      outstanding_prerender_service_requests_.find(fetcher);
86258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (it == outstanding_prerender_service_requests_.end())
86358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return;
86458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  delete it->first;
86558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  scoped_ptr<CandidatePrerenderInfo> info(it->second);
86658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  outstanding_prerender_service_requests_.erase(it);
86758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  RecordEvent(EVENT_PRERENDER_SERVICE_LOOKUP_TIMED_OUT);
86858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  DoLoggedInLookup(info.Pass());
86958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
87058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
87158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)bool PrerenderLocalPredictor::ApplyParsedPrerenderServiceResponse(
8725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::DictionaryValue* dict,
87358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    CandidatePrerenderInfo* info,
87458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    bool* hinting_timed_out,
87558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    bool* hinting_url_lookup_timed_out,
87658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    bool* candidate_url_lookup_timed_out) {
87758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  /*
87858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    Process the response to the request.
87958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    Here is a sample response to illustrate the format.
88058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    {
88158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      "prerender_response": {
88258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        "behavior_id": 6,
88358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        "hint_response": {
88458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          "hinting_timed_out": 0,
88558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          "candidates": [
88658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            { "url": "http://www.cnn.com/story-1",
88758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)              "in_index": 1,
88858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)              "likelihood": 0.60,
88958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)              "in_index_timed_out": 0
89058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            },
89158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            { "url": "http://www.cnn.com/story-2",
89258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)              "in_index": 1,
89358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)              "likelihood": 0.30,
89458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)              "in_index_timed_out": 0
89558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            }
89658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          ]
89758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        },
89858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        "candidate_check_response": {
89958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          "candidates": [
90058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            { "url": "http://www.cnn.com/sports/",
90158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)              "in_index": 1,
90258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)              "in_index_timed_out": 0
90358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            },
90458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            { "url": "http://www.cnn.com/politics/",
90558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)              "in_index": 0,
90658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)              "in_index_timed_out": "1"
90758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            }
90858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          ]
90958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        }
91058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      }
91158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    }
91258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  */
9135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::ListValue* list = NULL;
91458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  int int_value;
91558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (!dict->GetInteger("prerender_response.behavior_id", &int_value) ||
91658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      int_value != GetPrerenderServiceBehaviorID()) {
91758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return false;
91858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
91958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (!dict->GetList("prerender_response.candidate_check_response.candidates",
92058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                     &list)) {
92158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if (ShouldQueryPrerenderServiceForCandidateURLs()) {
92258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      for (int i = 0; i < static_cast<int>(info->candidate_urls_.size()); i++) {
92358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        if (info->candidate_urls_[i].url_lookup_success)
92458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          return false;
92558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      }
92658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    }
92758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  } else {
92858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    for (size_t i = 0; i < list->GetSize(); i++) {
9295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::DictionaryValue* d;
93058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      if (!list->GetDictionary(i, &d))
93158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        return false;
93258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      string url_string;
93358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      if (!d->GetString("url", &url_string) || !GURL(url_string).is_valid())
93458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        return false;
93558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      GURL url(url_string);
93658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      int in_index_timed_out = 0;
93758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      int in_index = 0;
93858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      if ((!d->GetInteger("in_index_timed_out", &in_index_timed_out) ||
93958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)           in_index_timed_out != 1) &&
94058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          !d->GetInteger("in_index", &in_index)) {
94158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        return false;
94258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      }
94358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      if (in_index < 0 || in_index > 1 ||
94458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          in_index_timed_out < 0 || in_index_timed_out > 1) {
94558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        return false;
94658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      }
94758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      if (in_index_timed_out == 1)
94858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        *candidate_url_lookup_timed_out = true;
94958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      for (size_t j = 0; j < info->candidate_urls_.size(); j++) {
95058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        if (info->candidate_urls_[j].url == url) {
95158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          info->candidate_urls_[j].service_whitelist_reported = true;
95258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          info->candidate_urls_[j].service_whitelist = (in_index == 1);
95358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          info->candidate_urls_[j].service_whitelist_lookup_ok =
95458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)              ((1 - in_index_timed_out) == 1);
95558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        }
95658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      }
95758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    }
95858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    for (size_t i = 0; i < info->candidate_urls_.size(); i++) {
95958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      if (info->candidate_urls_[i].url_lookup_success &&
96058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          !info->candidate_urls_[i].service_whitelist_reported) {
96158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        return false;
96258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      }
96358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    }
96458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
96558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
96658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (ShouldQueryPrerenderServiceForCurrentURL() &&
96758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      info->source_url_.url_lookup_success) {
96858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    list = NULL;
96958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if (dict->GetInteger("prerender_response.hint_response.hinting_timed_out",
97058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                         &int_value) &&
97158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        int_value == 1) {
97258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      *hinting_timed_out = true;
97358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    } else if (!dict->GetList("prerender_response.hint_response.candidates",
97458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                              &list)) {
97558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      return false;
97658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    } else {
97758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      for (int i = 0; i < static_cast<int>(list->GetSize()); i++) {
9785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        base::DictionaryValue* d;
97958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        if (!list->GetDictionary(i, &d))
98058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          return false;
98158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        string url;
982116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        if (!d->GetString("url", &url) || !GURL(url).is_valid())
983116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          return false;
98458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        double priority;
985116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        if (!d->GetDouble("likelihood", &priority) || priority < 0.0 ||
986116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch            priority > 1.0) {
98758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          return false;
98858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        }
98958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        int in_index_timed_out = 0;
99058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        int in_index = 0;
99158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        if ((!d->GetInteger("in_index_timed_out", &in_index_timed_out) ||
99258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)             in_index_timed_out != 1) &&
99358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            !d->GetInteger("in_index", &in_index)) {
99458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          return false;
99558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        }
996116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        if (in_index < 0 || in_index > 1 || in_index_timed_out < 0 ||
997116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch            in_index_timed_out > 1) {
99858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          return false;
99958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        }
100058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        if (in_index_timed_out == 1)
100158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          *hinting_url_lookup_timed_out = true;
100258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        info->MaybeAddCandidateURLFromService(GURL(url),
100358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                                              priority,
100458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                                              in_index == 1,
1005116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                              !in_index_timed_out);
100658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      }
10078bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      if (list->GetSize() > 0)
100803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        RecordEvent(EVENT_PRERENDER_SERVICE_RETURNED_HINTING_CANDIDATES);
100958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    }
101058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
1011b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
101258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return true;
101358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
101458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
101558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void PrerenderLocalPredictor::OnURLFetchComplete(
101658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const net::URLFetcher* source) {
101758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
101858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  RecordEvent(EVENT_PRERENDER_SERVICE_RECEIVED_RESULT);
101958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  net::URLFetcher* fetcher = const_cast<net::URLFetcher*>(source);
102058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  OutstandingFetchers::iterator it =
102158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      outstanding_prerender_service_requests_.find(fetcher);
102258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (it == outstanding_prerender_service_requests_.end()) {
102358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    RecordEvent(EVENT_PRERENDER_SERVICE_NO_RECORD_FOR_RESULT);
102458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return;
102558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
102658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  scoped_ptr<CandidatePrerenderInfo> info(it->second);
102758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  outstanding_prerender_service_requests_.erase(it);
102858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  TIMING_HISTOGRAM("Prerender.LocalPredictorServiceLookupTime",
102958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                   base::Time::Now() - info->start_time_);
103058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  string result;
103158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  fetcher->GetResponseAsString(&result);
10325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<base::Value> root;
103358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  root.reset(base::JSONReader::Read(result));
103458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  bool hinting_timed_out = false;
103558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  bool hinting_url_lookup_timed_out = false;
103658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  bool candidate_url_lookup_timed_out = false;
10375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!root.get() || !root->IsType(base::Value::TYPE_DICTIONARY)) {
103858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    RecordEvent(EVENT_PRERENDER_SERVICE_PARSE_ERROR_INCORRECT_JSON);
103958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  } else {
104058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if (ApplyParsedPrerenderServiceResponse(
10415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            static_cast<base::DictionaryValue*>(root.get()),
104258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            info.get(),
104358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            &hinting_timed_out,
104458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            &hinting_url_lookup_timed_out,
104558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            &candidate_url_lookup_timed_out)) {
104658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      // We finished parsing the result, and found no errors.
104758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      RecordEvent(EVENT_PRERENDER_SERVICE_PARSED_CORRECTLY);
104858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      if (hinting_timed_out)
104958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        RecordEvent(EVENT_PRERENDER_SERVICE_HINTING_TIMED_OUT);
105058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      if (hinting_url_lookup_timed_out)
105158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        RecordEvent(EVENT_PRERENDER_SERVICE_HINTING_URL_LOOKUP_TIMED_OUT);
105258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      if (candidate_url_lookup_timed_out)
105358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        RecordEvent(EVENT_PRERENDER_SERVICE_CANDIDATE_URL_LOOKUP_TIMED_OUT);
105458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      DoLoggedInLookup(info.Pass());
105558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      return;
105658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    }
105758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
105858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
105958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // If we did not return earlier, an error happened during parsing.
106058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Record this, and proceed.
106158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  RecordEvent(EVENT_PRERENDER_SERVICE_PARSE_ERROR);
106258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  DoLoggedInLookup(info.Pass());
106358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
106458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
106558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void PrerenderLocalPredictor:: DoLoggedInLookup(
106658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    scoped_ptr<CandidatePrerenderInfo> info) {
106758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1068b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  scoped_refptr<LoggedInPredictorTable> logged_in_table =
1069b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      prerender_manager_->logged_in_predictor_table();
1070b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
1071b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!logged_in_table.get()) {
1072b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    RecordEvent(EVENT_PRERENDER_URL_LOOKUP_NO_LOGGED_IN_TABLE_FOUND);
1073b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    return;
1074b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  }
1075b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
1076b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  RecordEvent(EVENT_PRERENDER_URL_LOOKUP_ISSUING_LOGGED_IN_LOOKUP);
1077b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
107858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  info->start_time_ = base::Time::Now();
107958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
108058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  CandidatePrerenderInfo* info_ptr = info.get();
1081b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  BrowserThread::PostTaskAndReply(
1082b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      BrowserThread::DB, FROM_HERE,
1083b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      base::Bind(&LookupLoggedInStatesOnDBThread,
1084b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                 logged_in_table,
1085b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                 info_ptr),
1086b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      base::Bind(&PrerenderLocalPredictor::ContinuePrerenderCheck,
1087b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                 weak_factory_.GetWeakPtr(),
1088b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                 base::Passed(&info)));
1089b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
10905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1091b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void PrerenderLocalPredictor::LogCandidateURLStats(const GURL& url) const {
10925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (url_whitelist_.count(GetInt64URLHashForURL(url)) > 0) {
10935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RecordEvent(EVENT_PRERENDER_URL_LOOKUP_RESULT_ON_WHITELIST);
10945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (IsRootPageURL(url))
10955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      RecordEvent(EVENT_PRERENDER_URL_LOOKUP_RESULT_ON_WHITELIST_ROOT_PAGE);
10965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (IsRootPageURL(url))
10985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RecordEvent(EVENT_PRERENDER_URL_LOOKUP_RESULT_ROOT_PAGE);
10992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (IsExtendedRootURL(url))
11002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    RecordEvent(EVENT_PRERENDER_URL_LOOKUP_RESULT_EXTENDED_ROOT_PAGE);
11012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (IsRootPageURL(url) && url.SchemeIs("http"))
11022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    RecordEvent(EVENT_PRERENDER_URL_LOOKUP_RESULT_ROOT_PAGE_HTTP);
11035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (url.SchemeIs("http"))
11045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RecordEvent(EVENT_PRERENDER_URL_LOOKUP_RESULT_IS_HTTP);
11055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (url.has_query())
11065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RecordEvent(EVENT_PRERENDER_URL_LOOKUP_RESULT_HAS_QUERY_STRING);
1107b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (IsLogOutURL(url))
11085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RecordEvent(EVENT_PRERENDER_URL_LOOKUP_RESULT_CONTAINS_LOGOUT);
1109b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (IsLogInURL(url))
11105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RecordEvent(EVENT_PRERENDER_URL_LOOKUP_RESULT_CONTAINS_LOGIN);
11115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PrerenderLocalPredictor::OnGetInitialVisitHistory(
1114b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    scoped_ptr<vector<history::BriefVisitInfo> > visit_history) {
11155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
11165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!visit_history_.get());
11175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RecordEvent(EVENT_INIT_SUCCEEDED);
11185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Since the visit history has descending timestamps, we must reverse it.
1119b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  visit_history_.reset(new vector<history::BriefVisitInfo>(
11205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      visit_history->rbegin(), visit_history->rend()));
11215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HistoryService* PrerenderLocalPredictor::GetHistoryIfExists() const {
11245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Profile* profile = prerender_manager_->profile();
11255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!profile)
11265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
11275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return HistoryServiceFactory::GetForProfileWithoutCreating(profile);
11285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PrerenderLocalPredictor::Init() {
11315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
11325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RecordEvent(EVENT_INIT_STARTED);
11338bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  Profile* profile = prerender_manager_->profile();
11341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!profile ||
11351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      ShouldDisableLocalPredictorBasedOnSyncAndConfiguration(profile)) {
11368bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    RecordEvent(EVENT_INIT_FAILED_UNENCRYPTED_SYNC_NOT_ENABLED);
11378bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    return;
11388bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
11395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HistoryService* history = GetHistoryIfExists();
11405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (history) {
11415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CHECK(!is_visit_database_observer_);
11425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    history->ScheduleDBTask(
11435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        scoped_ptr<history::HistoryDBTask>(
11445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            new GetVisitHistoryTask(this, kMaxVisitHistory)),
11455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        &history_db_tracker_);
11465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    history->AddVisitDatabaseObserver(this);
11475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    is_visit_database_observer_ = true;
11485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
11495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RecordEvent(EVENT_INIT_FAILED_NO_HISTORY);
11505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PrerenderLocalPredictor::OnPLTEventForURL(const GURL& url,
11545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               base::TimeDelta page_load_time) {
115503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (prefetch_list_->MarkPLTSeen(url, page_load_time)) {
115603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    UMA_HISTOGRAM_CUSTOM_TIMES("Prerender.LocalPredictorPrefetchMatchPLT",
115703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                               page_load_time,
115803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                               base::TimeDelta::FromMilliseconds(10),
115903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                               base::TimeDelta::FromSeconds(60),
116003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                               100);
116103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
116203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
1163b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  scoped_ptr<PrerenderProperties> prerender;
11645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (DoesPrerenderMatchPLTRecord(last_swapped_in_prerender_.get(),
11655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  url, page_load_time)) {
11665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    prerender.reset(last_swapped_in_prerender_.release());
11675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (DoesPrerenderMatchPLTRecord(current_prerender_.get(),
11695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  url, page_load_time)) {
11705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    prerender.reset(current_prerender_.release());
11715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!prerender.get())
11735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
11745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (IsPrerenderStillValid(prerender.get())) {
11755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UMA_HISTOGRAM_CUSTOM_TIMES("Prerender.SimulatedLocalBrowsingBaselinePLT",
11765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               page_load_time,
11775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               base::TimeDelta::FromMilliseconds(10),
11785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               base::TimeDelta::FromSeconds(60),
11795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               100);
11805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::TimeDelta prerender_age = GetCurrentTime() - prerender->start_time;
11825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (prerender_age > page_load_time) {
11835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::TimeDelta new_plt;
11845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (prerender_age <  2 * page_load_time)
11855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        new_plt = 2 * page_load_time - prerender_age;
11865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      UMA_HISTOGRAM_CUSTOM_TIMES("Prerender.SimulatedLocalBrowsingPLT",
11875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 new_plt,
11885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 base::TimeDelta::FromMilliseconds(10),
11895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 base::TimeDelta::FromSeconds(60),
11905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 100);
11915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
11925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool PrerenderLocalPredictor::IsPrerenderStillValid(
1196b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    PrerenderLocalPredictor::PrerenderProperties* prerender) const {
11975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (prerender &&
11985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          (prerender->start_time +
11997d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)           base::TimeDelta::FromMilliseconds(GetMaxLocalPredictionTimeMs()))
12005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          > GetCurrentTime());
12015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PrerenderLocalPredictor::RecordEvent(
12045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PrerenderLocalPredictor::Event event) const {
1205c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  UMA_HISTOGRAM_ENUMERATION("Prerender.LocalPredictorEvent",
12065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      event, PrerenderLocalPredictor::EVENT_MAX_VALUE);
12075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool PrerenderLocalPredictor::DoesPrerenderMatchPLTRecord(
1210b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    PrerenderProperties* prerender,
1211b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    const GURL& url,
1212b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    base::TimeDelta plt) const {
12135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (prerender && prerender->start_time < GetCurrentTime() - plt) {
12145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (prerender->url.is_empty())
12155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      RecordEvent(EVENT_ERROR_NO_PRERENDER_URL_FOR_PLT);
12165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return (prerender->url == url);
12175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
12185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
12195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
12205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12227d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)PrerenderLocalPredictor::PrerenderProperties*
12236d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)PrerenderLocalPredictor::GetIssuedPrerenderSlotForPriority(const GURL& url,
12246d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                                                           double priority) {
12257d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  int num_prerenders = GetLocalPredictorMaxConcurrentPrerenders();
12267d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  while (static_cast<int>(issued_prerenders_.size()) < num_prerenders)
12277d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    issued_prerenders_.push_back(new PrerenderProperties());
12286d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // First, check if we already have a prerender for the same URL issued.
12296d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // If yes, we don't want to prerender this URL again, so we return NULL
12306d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // (on matching slot found).
12316d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  for (int i = 0; i < static_cast<int>(issued_prerenders_.size()); i++) {
12326d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    PrerenderProperties* p = issued_prerenders_[i];
12336d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    DCHECK(p != NULL);
12346d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    if (p->prerender_handle && p->prerender_handle->IsPrerendering() &&
12356d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        p->prerender_handle->Matches(url, NULL)) {
12366d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      return NULL;
12376d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    }
12386d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  }
12396d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // Otherwise, let's see if there are any empty slots. If yes, return the first
12406d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // one we find. Otherwise, if the lowest priority prerender has a lower
12416d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // priority than the page we want to prerender, use its slot.
12427d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  PrerenderProperties* lowest_priority_prerender = NULL;
12437d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  for (int i = 0; i < static_cast<int>(issued_prerenders_.size()); i++) {
12447d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    PrerenderProperties* p = issued_prerenders_[i];
12457d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    DCHECK(p != NULL);
12467d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    if (!p->prerender_handle || !p->prerender_handle->IsPrerendering())
12477d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      return p;
12487d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    double decayed_priority = p->GetCurrentDecayedPriority();
12497d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    if (decayed_priority > priority)
12507d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      continue;
12517d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    if (lowest_priority_prerender == NULL ||
12527d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        lowest_priority_prerender->GetCurrentDecayedPriority() >
12537d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        decayed_priority) {
12547d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      lowest_priority_prerender = p;
12557d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    }
12567d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  }
12577d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return lowest_priority_prerender;
1258b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
1259b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
1260b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void PrerenderLocalPredictor::ContinuePrerenderCheck(
126158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    scoped_ptr<CandidatePrerenderInfo> info) {
126258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
126358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  TIMING_HISTOGRAM("Prerender.LocalPredictorLoggedInLookupTime",
126458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                   base::Time::Now() - info->start_time_);
1265b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_STARTED);
126658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (info->candidate_urls_.size() == 0) {
126758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    RecordEvent(EVENT_NO_PRERENDER_CANDIDATES);
126858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return;
126958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
1270b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  scoped_ptr<LocalPredictorURLInfo> url_info;
1271f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#if defined(FULL_SAFE_BROWSING)
127290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  scoped_refptr<SafeBrowsingDatabaseManager> sb_db_manager =
127390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      g_browser_process->safe_browsing_service()->database_manager();
1274f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#endif
12756d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  int num_issued = 0;
1276b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  for (int i = 0; i < static_cast<int>(info->candidate_urls_.size()); i++) {
12775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (num_issued >= GetLocalPredictorMaxLaunchPrerenders())
12786d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      return;
127958e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch    RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_EXAMINE_NEXT_URL);
1280b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    url_info.reset(new LocalPredictorURLInfo(info->candidate_urls_[i]));
128158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if (url_info->local_history_based) {
128258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      if (SkipLocalPredictorLocalCandidates()) {
128358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        url_info.reset(NULL);
128458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        continue;
128558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      }
128658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_EXAMINE_NEXT_URL_LOCAL);
128758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    }
128858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if (!url_info->local_history_based) {
128958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      if (SkipLocalPredictorServiceCandidates()) {
129058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        url_info.reset(NULL);
129158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        continue;
129258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      }
129358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_EXAMINE_NEXT_URL_SERVICE);
129458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    }
1295b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
12968bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_EXAMINE_NEXT_URL_NOT_SKIPPED);
12978bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
1298b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    // We need to check whether we can issue a prerender for this URL.
1299b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    // We test a set of conditions. Each condition can either rule out
1300b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    // a prerender (in which case we reset url_info, so that it will not
1301b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    // be prerendered, and we continue, which means try the next candidate
1302b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    // URL), or it can be sufficient to issue the prerender without any
1303b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    // further checks (in which case we just break).
1304b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    // The order of the checks is critical, because it prescribes the logic
1305b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    // we use here to decide what to prerender.
1306b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    if (!url_info->url_lookup_success) {
1307b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_NO_URL);
1308b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      url_info.reset(NULL);
1309b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      continue;
1310b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    }
13112385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    if (!SkipLocalPredictorFragment() &&
13122385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch        URLsIdenticalIgnoringFragments(info->source_url_.url,
1313b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                       url_info->url)) {
1314b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_URLS_IDENTICAL_BUT_FRAGMENT);
1315b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      url_info.reset(NULL);
1316b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      continue;
1317b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    }
13182385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    if (!SkipLocalPredictorHTTPS() && url_info->url.SchemeIs("https")) {
1319b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_HTTPS);
1320b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      url_info.reset(NULL);
1321b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      continue;
1322b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    }
1323b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    if (IsRootPageURL(url_info->url)) {
1324b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      // For root pages, we assume that they are reasonably safe, and we
1325b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      // will just prerender them without any additional checks.
1326b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_ROOT_PAGE);
13275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      IssuePrerender(info.get(), url_info.get());
13286d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      num_issued++;
13296d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      continue;
1330b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    }
1331b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    if (IsLogOutURL(url_info->url)) {
1332b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_LOGOUT_URL);
1333b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      url_info.reset(NULL);
1334b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      continue;
1335b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    }
1336b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    if (IsLogInURL(url_info->url)) {
1337b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_LOGIN_URL);
1338b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      url_info.reset(NULL);
1339b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      continue;
1340b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    }
1341f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#if defined(FULL_SAFE_BROWSING)
13421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (!SkipLocalPredictorWhitelist() && sb_db_manager.get() &&
13432385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch        sb_db_manager->CheckSideEffectFreeWhitelistUrl(url_info->url)) {
134490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      // If a page is on the side-effect free whitelist, we will just prerender
134590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      // it without any additional checks.
134690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_ON_SIDE_EFFECT_FREE_WHITELIST);
13475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      IssuePrerender(info.get(), url_info.get());
13486d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      num_issued++;
13496d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      continue;
135090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
1351f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#endif
135258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if (!SkipLocalPredictorServiceWhitelist() &&
135358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        url_info->service_whitelist && url_info->service_whitelist_lookup_ok) {
135458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_ON_SERVICE_WHITELIST);
13555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      IssuePrerender(info.get(), url_info.get());
13566d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      num_issued++;
13576d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      continue;
135858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    }
13592385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    if (!SkipLocalPredictorLoggedIn() &&
13602385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch        !url_info->logged_in && url_info->logged_in_lookup_ok) {
1361b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_NOT_LOGGED_IN);
13625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      IssuePrerender(info.get(), url_info.get());
13636d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      num_issued++;
13646d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      continue;
1365b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    }
13662385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    if (!SkipLocalPredictorDefaultNoPrerender()) {
13672385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch      RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_FALLTHROUGH_NOT_PRERENDERING);
13682385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch      url_info.reset(NULL);
13692385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    } else {
13702385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch      RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_FALLTHROUGH_PRERENDERING);
13715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      IssuePrerender(info.get(), url_info.get());
13726d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      num_issued++;
13736d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      continue;
13742385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    }
1375b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  }
1376b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
1377b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
1378b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void PrerenderLocalPredictor::IssuePrerender(
13796d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    CandidatePrerenderInfo* info,
13805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    LocalPredictorURLInfo* url_info) {
138158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
13821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  RecordEvent(EVENT_ISSUE_PRERENDER_CALLED);
138303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (prefetch_list_->AddURL(url_info->url)) {
13845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    RecordEvent(EVENT_PREFETCH_LIST_ADDED);
138503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    // If we are prefetching rather than prerendering, now is the time to launch
138603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    // the prefetch.
138703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if (IsLocalPredictorPrerenderPrefetchEnabled()) {
13881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      RecordEvent(EVENT_ISSUE_PRERENDER_PREFETCH_ENABLED);
138903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      // Obtain the render frame host that caused this prefetch.
139003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      RenderFrameHost* rfh = RenderFrameHost::FromID(info->render_process_id_,
139103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                                                     info->render_frame_id_);
139203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      // If it is still alive, launch the prefresh.
13931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      if (rfh) {
139403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        rfh->Send(new PrefetchMsg_Prefetch(rfh->GetRoutingID(), url_info->url));
13951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        RecordEvent(EVENT_ISSUE_PRERENDER_PREFETCH_ISSUED);
13961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      }
139703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    }
139803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
13995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  PrerenderProperties* prerender_properties =
14005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      GetIssuedPrerenderSlotForPriority(url_info->url, url_info->priority);
14015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!prerender_properties) {
14025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_PRIORITY_TOO_LOW);
14035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return;
14045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
14056d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_ISSUING_PRERENDER);
14066d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  DCHECK(prerender_properties != NULL);
14076d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  DCHECK(info != NULL);
14086d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  DCHECK(url_info != NULL);
14096d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  if (!IsLocalPredictorPrerenderLaunchEnabled())
14106d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    return;
141158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  URLID url_id = url_info->id;
141258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  const GURL& url = url_info->url;
141358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  double priority = url_info->priority;
1414b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  base::Time current_time = GetCurrentTime();
1415b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  RecordEvent(EVENT_ISSUING_PRERENDER);
1416b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
14177d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // Issue the prerender and obtain a new handle.
14187d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  scoped_ptr<prerender::PrerenderHandle> new_prerender_handle(
14197d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      prerender_manager_->AddPrerenderFromLocalPredictor(
142058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          url, info->session_storage_namespace_.get(), *(info->size_)));
14217d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
14227d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // Check if this is a duplicate of an existing prerender. If yes, clean up
14237d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // the new handle.
14247d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  for (int i = 0; i < static_cast<int>(issued_prerenders_.size()); i++) {
14257d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    PrerenderProperties* p = issued_prerenders_[i];
14267d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    DCHECK(p != NULL);
14277d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    if (new_prerender_handle &&
14287d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        new_prerender_handle->RepresentingSamePrerenderAs(
14297d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)            p->prerender_handle.get())) {
14307d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      new_prerender_handle->OnCancel();
14317d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      new_prerender_handle.reset(NULL);
143258e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch      RecordEvent(EVENT_ISSUE_PRERENDER_ALREADY_PRERENDERING);
14337d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      break;
14347d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    }
14357d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  }
14367d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
14377d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (new_prerender_handle.get()) {
143858e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch    RecordEvent(EVENT_ISSUE_PRERENDER_NEW_PRERENDER);
14397d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    // The new prerender does not match any existing prerenders. Update
14407d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    // prerender_properties so that it reflects the new entry.
14417d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    prerender_properties->url_id = url_id;
14427d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    prerender_properties->url = url;
14437d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    prerender_properties->priority = priority;
14447d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    prerender_properties->start_time = current_time;
14457d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    prerender_properties->actual_start_time = current_time;
14467d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    prerender_properties->would_have_matched = false;
14477d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    prerender_properties->prerender_handle.swap(new_prerender_handle);
14487d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    // new_prerender_handle now represents the old previou prerender that we
14497d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    // are replacing. So we need to cancel it.
145058e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch    if (new_prerender_handle) {
14517d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      new_prerender_handle->OnCancel();
145258e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch      RecordEvent(EVENT_ISSUE_PRERENDER_CANCELLED_OLD_PRERENDER);
145358e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch    }
14547d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  }
1455b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
1456b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  RecordEvent(EVENT_ADD_VISIT_PRERENDERING);
1457b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (current_prerender_.get() && current_prerender_->url_id == url_id) {
1458b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    RecordEvent(EVENT_ADD_VISIT_PRERENDERING_EXTENDED);
1459b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    if (priority > current_prerender_->priority)
1460b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      current_prerender_->priority = priority;
1461b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    // If the prerender already existed, we want to extend it.  However,
1462b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    // we do not want to set its start_time to the current time to
1463b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    // disadvantage PLT computations when the prerender is swapped in.
1464b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    // So we set the new start time to current_time - 10s (since the vast
1465b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    // majority of PLTs are < 10s), provided that is not before the actual
1466b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    // time the prerender was started (so as to not artificially advantage
1467b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    // the PLT computation).
1468b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    base::Time simulated_new_start_time =
1469b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        current_time - base::TimeDelta::FromSeconds(10);
1470b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    if (simulated_new_start_time > current_prerender_->start_time)
1471b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      current_prerender_->start_time = simulated_new_start_time;
1472b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  } else {
1473b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    current_prerender_.reset(
1474b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        new PrerenderProperties(url_id, url, priority, current_time));
1475b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  }
1476b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  current_prerender_->actual_start_time = current_time;
14775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1479a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)void PrerenderLocalPredictor::OnTabHelperURLSeen(
1480a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    const GURL& url, WebContents* web_contents) {
1481a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  RecordEvent(EVENT_TAB_HELPER_URL_SEEN);
14827d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
14835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (prefetch_list_->MarkURLSeen(url, PrefetchList::SEEN_TABCONTENTS_OBSERVER))
14845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    RecordEvent(EVENT_PREFETCH_LIST_SEEN_TABCONTENTS);
1485a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  bool browser_navigate_initiated = false;
1486a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  const content::NavigationEntry* entry =
1487a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      web_contents->GetController().GetPendingEntry();
1488a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (entry) {
1489a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    base::string16 result;
1490a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    browser_navigate_initiated =
1491a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        entry->GetExtraData(kChromeNavigateExtraDataKey, &result);
1492a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
1493a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
1494a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  // If the namespace matches and the URL matches, we might be able to swap
1495a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  // in. However, the actual code initating the swapin is in the renderer
1496a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  // and is checking for other criteria (such as POSTs). There may
1497a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  // also be conditions when a swapin should happen but does not. By recording
1498a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  // the two previous events, we can keep an eye on the magnitude of the
1499a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  // discrepancy.
15007d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
15017d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  PrerenderProperties* best_matched_prerender = NULL;
15027d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  bool session_storage_namespace_matches = false;
15034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  SessionStorageNamespace* tab_session_storage_namespace =
15044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      web_contents->GetController().GetDefaultSessionStorageNamespace();
15057d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  for (int i = 0; i < static_cast<int>(issued_prerenders_.size()); i++) {
15067d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    PrerenderProperties* p = issued_prerenders_[i];
15077d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    DCHECK(p != NULL);
15087d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    if (!p->prerender_handle.get() ||
15097d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        !p->prerender_handle->Matches(url, NULL) ||
15107d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        p->would_have_matched) {
15117d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      continue;
15127d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    }
15137d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    if (!best_matched_prerender || !session_storage_namespace_matches) {
15147d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      best_matched_prerender = p;
15157d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      session_storage_namespace_matches =
15164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          p->prerender_handle->Matches(url, tab_session_storage_namespace);
15177d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    }
15187d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  }
15197d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (best_matched_prerender) {
15207d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    RecordEvent(EVENT_TAB_HELPER_URL_SEEN_MATCH);
1521a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    if (entry)
1522a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      RecordEvent(EVENT_TAB_HELPER_URL_SEEN_MATCH_ENTRY);
1523a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    if (browser_navigate_initiated)
1524a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      RecordEvent(EVENT_TAB_HELPER_URL_SEEN_MATCH_BROWSER_NAVIGATE);
15257d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    best_matched_prerender->would_have_matched = true;
15264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    if (session_storage_namespace_matches) {
15277d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      RecordEvent(EVENT_TAB_HELPER_URL_SEEN_NAMESPACE_MATCH);
1528a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      if (entry)
1529a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        RecordEvent(EVENT_TAB_HELPER_URL_SEEN_NAMESPACE_MATCH_ENTRY);
1530a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      if (browser_navigate_initiated)
1531a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        RecordEvent(EVENT_TAB_HELPER_URL_SEEN_NAMESPACE_MATCH_BROWSER_NAVIGATE);
15324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    } else {
15334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      SessionStorageNamespace* prerender_session_storage_namespace =
15344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          best_matched_prerender->prerender_handle->
15354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          GetSessionStorageNamespace();
15364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      if (!prerender_session_storage_namespace) {
15374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        RecordEvent(EVENT_TAB_HELPER_URL_SEEN_NAMESPACE_MISMATCH_NO_NAMESPACE);
15384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      } else {
15394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        RecordEvent(EVENT_TAB_HELPER_URL_SEEN_NAMESPACE_MISMATCH_MERGE_ISSUED);
1540f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        prerender_session_storage_namespace->Merge(
1541f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            false,
15424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)            best_matched_prerender->prerender_handle->GetChildId(),
15434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)            tab_session_storage_namespace,
15444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)            base::Bind(&PrerenderLocalPredictor::ProcessNamespaceMergeResult,
15454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                       weak_factory_.GetWeakPtr()));
15464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      }
15474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    }
15484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
15494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
15504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
15514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void PrerenderLocalPredictor::ProcessNamespaceMergeResult(
15524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    content::SessionStorageNamespace::MergeResult result) {
15534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  RecordEvent(EVENT_NAMESPACE_MISMATCH_MERGE_RESULT_RECEIVED);
15544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  switch (result) {
15554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    case content::SessionStorageNamespace::MERGE_RESULT_NAMESPACE_NOT_FOUND:
15564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      RecordEvent(EVENT_NAMESPACE_MISMATCH_MERGE_RESULT_NAMESPACE_NOT_FOUND);
15574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      break;
1558f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    case content::SessionStorageNamespace::MERGE_RESULT_NAMESPACE_NOT_ALIAS:
1559f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      RecordEvent(EVENT_NAMESPACE_MISMATCH_MERGE_RESULT_NAMESPACE_NOT_ALIAS);
1560f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      break;
15614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    case content::SessionStorageNamespace::MERGE_RESULT_NOT_LOGGING:
15624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      RecordEvent(EVENT_NAMESPACE_MISMATCH_MERGE_RESULT_NOT_LOGGING);
15634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      break;
15644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    case content::SessionStorageNamespace::MERGE_RESULT_NO_TRANSACTIONS:
15654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      RecordEvent(EVENT_NAMESPACE_MISMATCH_MERGE_RESULT_NO_TRANSACTIONS);
15664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      break;
15674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    case content::SessionStorageNamespace::MERGE_RESULT_TOO_MANY_TRANSACTIONS:
15684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      RecordEvent(EVENT_NAMESPACE_MISMATCH_MERGE_RESULT_TOO_MANY_TRANSACTIONS);
15694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      break;
15704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    case content::SessionStorageNamespace::MERGE_RESULT_NOT_MERGEABLE:
15714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      RecordEvent(EVENT_NAMESPACE_MISMATCH_MERGE_RESULT_NOT_MERGEABLE);
15724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      break;
15734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    case content::SessionStorageNamespace::MERGE_RESULT_MERGEABLE:
15744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      RecordEvent(EVENT_NAMESPACE_MISMATCH_MERGE_RESULT_MERGEABLE);
15754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      break;
15764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    default:
15774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      NOTREACHED();
15787d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  }
1579a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)}
1580a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
15815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace prerender
1582