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