1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef CHROME_BROWSER_PRERENDER_PRERENDER_LOCAL_PREDICTOR_H_ 6 #define CHROME_BROWSER_PRERENDER_PRERENDER_LOCAL_PREDICTOR_H_ 7 8 #include <map> 9 #include <vector> 10 11 #include "base/containers/hash_tables.h" 12 #include "base/memory/scoped_vector.h" 13 #include "base/memory/weak_ptr.h" 14 #include "base/task/cancelable_task_tracker.h" 15 #include "base/timer/timer.h" 16 #include "chrome/browser/history/visit_database.h" 17 #include "content/public/browser/session_storage_namespace.h" 18 #include "net/url_request/url_fetcher_delegate.h" 19 #include "url/gurl.h" 20 21 class HistoryService; 22 23 namespace base { 24 class DictionaryValue; 25 } 26 27 namespace content { 28 class WebContents; 29 } 30 31 namespace gfx { 32 class Size; 33 } 34 35 namespace prerender { 36 37 class PrerenderHandle; 38 class PrerenderManager; 39 40 // PrerenderLocalPredictor maintains local browsing history to make prerender 41 // predictions. 42 // At this point, the class is not actually creating prerenders, but just 43 // recording timing stats about the effect prerendering would have. 44 class PrerenderLocalPredictor : public history::VisitDatabaseObserver, 45 public net::URLFetcherDelegate { 46 public: 47 struct LocalPredictorURLInfo; 48 struct CandidatePrerenderInfo; 49 // A class simulating a set of URLs prefetched, for statistical purposes. 50 class PrefetchList; 51 enum Event { 52 EVENT_CONSTRUCTED = 0, 53 EVENT_INIT_SCHEDULED = 1, 54 EVENT_INIT_STARTED = 2, 55 EVENT_INIT_FAILED_NO_HISTORY = 3, 56 EVENT_INIT_SUCCEEDED = 4, 57 EVENT_ADD_VISIT = 5, 58 EVENT_ADD_VISIT_INITIALIZED = 6, 59 EVENT_ADD_VISIT_PRERENDER_IDENTIFIED = 7, 60 EVENT_ADD_VISIT_RELEVANT_TRANSITION = 8, 61 EVENT_ADD_VISIT_IDENTIFIED_PRERENDER_CANDIDATE = 9, 62 EVENT_ADD_VISIT_PRERENDERING = 10, 63 EVENT_GOT_PRERENDER_URL = 11, 64 EVENT_ERROR_NO_PRERENDER_URL_FOR_PLT = 12, 65 EVENT_ADD_VISIT_PRERENDERING_EXTENDED = 13, 66 EVENT_PRERENDER_URL_LOOKUP_RESULT = 14, 67 EVENT_PRERENDER_URL_LOOKUP_RESULT_ROOT_PAGE = 15, 68 EVENT_PRERENDER_URL_LOOKUP_RESULT_IS_HTTP = 16, 69 EVENT_PRERENDER_URL_LOOKUP_RESULT_HAS_QUERY_STRING = 17, 70 EVENT_PRERENDER_URL_LOOKUP_RESULT_CONTAINS_LOGOUT = 18, 71 EVENT_PRERENDER_URL_LOOKUP_RESULT_CONTAINS_LOGIN = 19, 72 EVENT_START_URL_LOOKUP = 20, 73 EVENT_ADD_VISIT_NOT_ROOTPAGE = 21, 74 EVENT_URL_WHITELIST_ERROR = 22, 75 EVENT_URL_WHITELIST_OK = 23, 76 EVENT_PRERENDER_URL_LOOKUP_RESULT_ON_WHITELIST = 24, 77 EVENT_PRERENDER_URL_LOOKUP_RESULT_ON_WHITELIST_ROOT_PAGE = 25, 78 EVENT_PRERENDER_URL_LOOKUP_RESULT_EXTENDED_ROOT_PAGE = 26, 79 EVENT_PRERENDER_URL_LOOKUP_RESULT_ROOT_PAGE_HTTP = 27, 80 EVENT_PRERENDER_URL_LOOKUP_FAILED = 28, 81 EVENT_PRERENDER_URL_LOOKUP_NO_SOURCE_WEBCONTENTS_FOUND = 29, 82 EVENT_PRERENDER_URL_LOOKUP_NO_LOGGED_IN_TABLE_FOUND = 30, 83 EVENT_PRERENDER_URL_LOOKUP_ISSUING_LOGGED_IN_LOOKUP = 31, 84 EVENT_CONTINUE_PRERENDER_CHECK_STARTED = 32, 85 EVENT_CONTINUE_PRERENDER_CHECK_NO_URL = 33, 86 EVENT_CONTINUE_PRERENDER_CHECK_PRIORITY_TOO_LOW = 34, 87 EVENT_CONTINUE_PRERENDER_CHECK_URLS_IDENTICAL_BUT_FRAGMENT = 35, 88 EVENT_CONTINUE_PRERENDER_CHECK_HTTPS = 36, 89 EVENT_CONTINUE_PRERENDER_CHECK_ROOT_PAGE = 37, 90 EVENT_CONTINUE_PRERENDER_CHECK_LOGOUT_URL = 38, 91 EVENT_CONTINUE_PRERENDER_CHECK_LOGIN_URL = 39, 92 EVENT_CONTINUE_PRERENDER_CHECK_NOT_LOGGED_IN = 40, 93 EVENT_CONTINUE_PRERENDER_CHECK_FALLTHROUGH_NOT_PRERENDERING = 41, 94 EVENT_CONTINUE_PRERENDER_CHECK_ISSUING_PRERENDER = 42, 95 EVENT_ISSUING_PRERENDER = 43, 96 EVENT_NO_PRERENDER_CANDIDATES = 44, 97 EVENT_GOT_HISTORY_ISSUING_LOOKUP = 45, 98 EVENT_TAB_HELPER_URL_SEEN = 46, 99 EVENT_TAB_HELPER_URL_SEEN_MATCH = 47, 100 EVENT_TAB_HELPER_URL_SEEN_NAMESPACE_MATCH = 48, 101 EVENT_PRERENDER_URL_LOOKUP_MULTIPLE_SOURCE_WEBCONTENTS_FOUND = 49, 102 EVENT_CONTINUE_PRERENDER_CHECK_ON_SIDE_EFFECT_FREE_WHITELIST = 50, 103 EVENT_CONTINUE_PRERENDER_CHECK_EXAMINE_NEXT_URL = 51, 104 EVENT_ISSUE_PRERENDER_ALREADY_PRERENDERING = 52, 105 EVENT_ISSUE_PRERENDER_NEW_PRERENDER = 53, 106 EVENT_ISSUE_PRERENDER_CANCELLED_OLD_PRERENDER = 54, 107 EVENT_CONTINUE_PRERENDER_CHECK_FALLTHROUGH_PRERENDERING = 55, 108 EVENT_PRERENDER_URL_LOOKUP_SUCCESS = 56, 109 EVENT_PRERENDER_SERVICE_DISABLED = 57, 110 EVENT_PRERENDER_SERVICE_ISSUED_LOOKUP = 58, 111 EVENT_PRERENDER_SERVICE_LOOKUP_TIMED_OUT = 59, 112 EVENT_PRERENDER_SERVICE_RECEIVED_RESULT = 60, 113 EVENT_PRERENDER_SERVICE_NO_RECORD_FOR_RESULT = 61, 114 EVENT_PRERENDER_SERVICE_PARSED_CORRECTLY = 62, 115 EVENT_PRERENDER_SERVICE_PARSE_ERROR = 63, 116 EVENT_PRERENDER_SERVICE_PARSE_ERROR_INCORRECT_JSON = 64, 117 EVENT_PRERENDER_SERVICE_HINTING_TIMED_OUT = 65, 118 EVENT_PRERENDER_SERVICE_HINTING_URL_LOOKUP_TIMED_OUT = 66, 119 EVENT_PRERENDER_SERVICE_CANDIDATE_URL_LOOKUP_TIMED_OUT = 67, 120 EVENT_CONTINUE_PRERENDER_CHECK_ON_SERVICE_WHITELIST = 68, 121 EVENT_CONTINUE_PRERENDER_CHECK_EXAMINE_NEXT_URL_LOCAL = 69, 122 EVENT_CONTINUE_PRERENDER_CHECK_EXAMINE_NEXT_URL_SERVICE = 70, 123 EVENT_ADD_VISIT_RELEVANT_TRANSITION_REPEAT_URL = 71, 124 EVENT_ADD_VISIT_RELEVANT_TRANSITION_NEW_URL = 72, 125 EVENT_TAB_HELPER_URL_SEEN_NAMESPACE_MISMATCH_NO_NAMESPACE = 73, 126 EVENT_TAB_HELPER_URL_SEEN_NAMESPACE_MISMATCH_MERGE_ISSUED = 74, 127 EVENT_NAMESPACE_MISMATCH_MERGE_RESULT_RECEIVED = 75, 128 EVENT_NAMESPACE_MISMATCH_MERGE_RESULT_NAMESPACE_NOT_FOUND = 76, 129 EVENT_NAMESPACE_MISMATCH_MERGE_RESULT_NOT_LOGGING = 77, 130 EVENT_NAMESPACE_MISMATCH_MERGE_RESULT_NO_TRANSACTIONS = 78, 131 EVENT_NAMESPACE_MISMATCH_MERGE_RESULT_TOO_MANY_TRANSACTIONS = 79, 132 EVENT_NAMESPACE_MISMATCH_MERGE_RESULT_NOT_MERGEABLE = 80, 133 EVENT_NAMESPACE_MISMATCH_MERGE_RESULT_MERGEABLE = 81, 134 EVENT_INIT_FAILED_UNENCRYPTED_SYNC_NOT_ENABLED = 82, 135 EVENT_CONTINUE_PRERENDER_CHECK_EXAMINE_NEXT_URL_NOT_SKIPPED = 83, 136 EVENT_PRERENDER_SERVICE_RETURNED_HINTING_CANDIDATES = 84, 137 EVENT_NAMESPACE_MISMATCH_MERGE_RESULT_NAMESPACE_NOT_ALIAS = 85, 138 EVENT_TAB_HELPER_URL_SEEN_MATCH_ENTRY = 86, 139 EVENT_TAB_HELPER_URL_SEEN_MATCH_BROWSER_NAVIGATE = 87, 140 EVENT_TAB_HELPER_URL_SEEN_NAMESPACE_MATCH_ENTRY = 88, 141 EVENT_TAB_HELPER_URL_SEEN_NAMESPACE_MATCH_BROWSER_NAVIGATE = 89, 142 EVENT_PREFETCH_LIST_ADDED = 90, 143 EVENT_PREFETCH_LIST_SEEN_TABCONTENTS = 91, 144 EVENT_PREFETCH_LIST_SEEN_HISTORY = 92, 145 EVENT_ISSUE_PRERENDER_CALLED = 93, 146 EVENT_ISSUE_PRERENDER_PREFETCH_ENABLED = 94, 147 EVENT_ISSUE_PRERENDER_PREFETCH_ISSUED = 95, 148 EVENT_MAX_VALUE 149 }; 150 151 // A PrerenderLocalPredictor is owned by the PrerenderManager specified 152 // in the constructor. It will be destoryed at the time its owning 153 // PrerenderManager is destroyed. 154 explicit PrerenderLocalPredictor(PrerenderManager* prerender_manager); 155 virtual ~PrerenderLocalPredictor(); 156 157 void Shutdown(); 158 159 // history::VisitDatabaseObserver implementation 160 virtual void OnAddVisit(const history::BriefVisitInfo& info) OVERRIDE; 161 162 void OnGetInitialVisitHistory( 163 scoped_ptr<std::vector<history::BriefVisitInfo> > visit_history); 164 165 void OnPLTEventForURL(const GURL& url, base::TimeDelta page_load_time); 166 167 void OnTabHelperURLSeen(const GURL& url, content::WebContents* web_contents); 168 169 // net::URLFetcherDelegate implementation: 170 void virtual OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE; 171 172 private: 173 struct PrerenderProperties; 174 HistoryService* GetHistoryIfExists() const; 175 void Init(); 176 bool IsPrerenderStillValid(PrerenderProperties* prerender) const; 177 bool DoesPrerenderMatchPLTRecord(PrerenderProperties* prerender, 178 const GURL& url, 179 base::TimeDelta plt) const; 180 void RecordEvent(Event event) const; 181 182 void OnLookupURL(scoped_ptr<CandidatePrerenderInfo> info); 183 184 // Lookup the prerender candidate in the Prerender Service (if applicable). 185 void DoPrerenderServiceCheck(scoped_ptr<CandidatePrerenderInfo> info); 186 187 // Lookup the prerender candidate in the LoggedIn Predictor. 188 void DoLoggedInLookup(scoped_ptr<CandidatePrerenderInfo> info); 189 190 // Returns an element of issued_prerenders_, which should be replaced 191 // by a new prerender of the priority indicated, or NULL, if the priority 192 // is too low (or if the URL requested is already prerendering). 193 PrerenderProperties* GetIssuedPrerenderSlotForPriority(const GURL& url, 194 double priority); 195 196 void ContinuePrerenderCheck(scoped_ptr<CandidatePrerenderInfo> info); 197 void LogCandidateURLStats(const GURL& url) const; 198 void IssuePrerender(CandidatePrerenderInfo* info, 199 LocalPredictorURLInfo* url_info); 200 void MaybeCancelURLFetcher(net::URLFetcher* fetcher); 201 // Returns true if the parsed response is semantically correct and could 202 // be fully applied. 203 bool ApplyParsedPrerenderServiceResponse( 204 base::DictionaryValue* dict, 205 CandidatePrerenderInfo* info, 206 bool* hinting_timed_out, 207 bool* hinting_url_lookup_timed_out, 208 bool* candidate_url_lookup_timed_out); 209 void ProcessNamespaceMergeResult( 210 content::SessionStorageNamespace::MergeResult result); 211 typedef std::map<net::URLFetcher*, CandidatePrerenderInfo*> 212 OutstandingFetchers; 213 OutstandingFetchers outstanding_prerender_service_requests_; 214 PrerenderManager* prerender_manager_; 215 base::OneShotTimer<PrerenderLocalPredictor> timer_; 216 217 // Delay after which to initialize, to avoid putting to much load on the 218 // database thread early on when Chrome is starting up. 219 static const int kInitDelayMs = 5 * 1000; 220 221 // Whether we're registered with the history service as a 222 // history::VisitDatabaseObserver. 223 bool is_visit_database_observer_; 224 225 base::CancelableTaskTracker history_db_tracker_; 226 227 scoped_ptr<std::vector<history::BriefVisitInfo> > visit_history_; 228 229 scoped_ptr<PrerenderProperties> current_prerender_; 230 scoped_ptr<PrerenderProperties> last_swapped_in_prerender_; 231 232 ScopedVector<PrerenderProperties> issued_prerenders_; 233 234 base::hash_set<int64> url_whitelist_; 235 236 base::WeakPtrFactory<PrerenderLocalPredictor> weak_factory_; 237 238 scoped_ptr<PrefetchList> prefetch_list_; 239 240 DISALLOW_COPY_AND_ASSIGN(PrerenderLocalPredictor); 241 }; 242 243 } // namespace prerender 244 245 #endif // CHROME_BROWSER_PRERENDER_PRERENDER_LOCAL_PREDICTOR_H_ 246