| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/prerender/prerender_manager.h" | 5 #include "chrome/browser/prerender/prerender_manager.h" |
| 6 | 6 |
| 7 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "base/metrics/field_trial.h" | 8 #include "base/metrics/field_trial.h" |
| 9 #include "base/metrics/histogram.h" | 9 #include "base/metrics/histogram.h" |
| 10 #include "base/time.h" | 10 #include "base/time.h" |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 43 // Time window for which we will record windowed PLT's from the last | 43 // Time window for which we will record windowed PLT's from the last |
| 44 // observed link rel=prefetch tag. | 44 // observed link rel=prefetch tag. |
| 45 const int kWindowDurationSeconds = 30; | 45 const int kWindowDurationSeconds = 30; |
| 46 | 46 |
| 47 // Time interval at which periodic cleanups are performed. | 47 // Time interval at which periodic cleanups are performed. |
| 48 const int kPeriodicCleanupIntervalMs = 1000; | 48 const int kPeriodicCleanupIntervalMs = 1000; |
| 49 | 49 |
| 50 // Time interval before a new prerender is allowed. | 50 // Time interval before a new prerender is allowed. |
| 51 const int kMinTimeBetweenPrerendersMs = 500; | 51 const int kMinTimeBetweenPrerendersMs = 500; |
| 52 | 52 |
| 53 // Valid HTTP methods for prerendering. |
| 54 const char* const kValidHttpMethods[] = { |
| 55 "OPTIONS", |
| 56 "GET", |
| 57 "HEAD", |
| 58 "TRACE", |
| 59 }; |
| 60 |
| 53 } // namespace | 61 } // namespace |
| 54 | 62 |
| 55 // static | 63 // static |
| 56 int PrerenderManager::prerenders_per_session_count_ = 0; | 64 int PrerenderManager::prerenders_per_session_count_ = 0; |
| 57 | 65 |
| 58 // static | 66 // static |
| 59 PrerenderManager::PrerenderManagerMode PrerenderManager::mode_ = | 67 PrerenderManager::PrerenderManagerMode PrerenderManager::mode_ = |
| 60 PRERENDER_MODE_ENABLED; | 68 PRERENDER_MODE_ENABLED; |
| 61 | 69 |
| 62 // static | 70 // static |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 104 GURL new_url(string16(decoded_url.data(), decoded_url.length())); | 112 GURL new_url(string16(decoded_url.data(), decoded_url.length())); |
| 105 if (!new_url.is_empty() && new_url.is_valid()) { | 113 if (!new_url.is_empty() && new_url.is_valid()) { |
| 106 *alias_url = new_url; | 114 *alias_url = new_url; |
| 107 return true; | 115 return true; |
| 108 } | 116 } |
| 109 return false; | 117 return false; |
| 110 } | 118 } |
| 111 return false; | 119 return false; |
| 112 } | 120 } |
| 113 | 121 |
| 122 // static |
| 123 bool PrerenderManager::IsValidHttpMethod(const std::string& method) { |
| 124 // method has been canonicalized to upper case at this point so we can just |
| 125 // compare them. |
| 126 DCHECK_EQ(method, StringToUpperASCII(method)); |
| 127 for (size_t i = 0; i < arraysize(kValidHttpMethods); ++i) { |
| 128 if (method.compare(kValidHttpMethods[i]) == 0) |
| 129 return true; |
| 130 } |
| 131 |
| 132 return false; |
| 133 } |
| 134 |
| 114 struct PrerenderManager::PrerenderContentsData { | 135 struct PrerenderManager::PrerenderContentsData { |
| 115 PrerenderContents* contents_; | 136 PrerenderContents* contents_; |
| 116 base::Time start_time_; | 137 base::Time start_time_; |
| 117 PrerenderContentsData(PrerenderContents* contents, base::Time start_time) | 138 PrerenderContentsData(PrerenderContents* contents, base::Time start_time) |
| 118 : contents_(contents), | 139 : contents_(contents), |
| 119 start_time_(start_time) { | 140 start_time_(start_time) { |
| 120 } | 141 } |
| 121 }; | 142 }; |
| 122 | 143 |
| 123 struct PrerenderManager::PendingContentsData { | 144 struct PrerenderManager::PendingContentsData { |
| 124 PendingContentsData(const GURL& url, | 145 PendingContentsData(const GURL& url, |
| 125 const GURL& referrer) | 146 const GURL& referrer) |
| 126 : url_(url), referrer_(referrer) { } | 147 : url_(url), referrer_(referrer) { } |
| 127 ~PendingContentsData() {} | 148 ~PendingContentsData() {} |
| 128 GURL url_; | 149 GURL url_; |
| 129 GURL referrer_; | 150 GURL referrer_; |
| 130 }; | 151 }; |
| 131 | 152 |
| 132 void HandlePrefetchTagOnUIThread( | 153 void HandlePrefetchTag( |
| 133 const base::WeakPtr<PrerenderManager>& prerender_manager_weak_ptr, | 154 const base::WeakPtr<PrerenderManager>& prerender_manager_weak_ptr, |
| 134 const std::pair<int, int>& child_route_id_pair, | 155 int render_process_id, |
| 156 int render_view_id, |
| 135 const GURL& url, | 157 const GURL& url, |
| 136 const GURL& referrer, | 158 const GURL& referrer, |
| 137 bool make_pending) { | 159 bool make_pending) { |
| 138 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 160 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 139 PrerenderManager* prerender_manager = prerender_manager_weak_ptr.get(); | 161 PrerenderManager* prerender_manager = prerender_manager_weak_ptr.get(); |
| 140 if (!prerender_manager || !prerender_manager->is_enabled()) | 162 if (!prerender_manager || !prerender_manager->is_enabled()) |
| 141 return; | 163 return; |
| 142 prerender_manager->RecordPrefetchTagObserved(); | 164 prerender_manager->RecordPrefetchTagObserved(); |
| 165 |
| 166 std::pair<int, int> child_route_id_pair = std::make_pair(render_process_id, |
| 167 render_view_id); |
| 143 // TODO(cbentzel): Should the decision to make pending be done on the | 168 // TODO(cbentzel): Should the decision to make pending be done on the |
| 144 // UI thread rather than the IO thread? The page may have | 169 // UI thread rather than the IO thread? The page may have |
| 145 // become activated at this point. | 170 // become activated at this point. |
| 146 if (make_pending) | 171 if (make_pending) |
| 147 prerender_manager->AddPendingPreload(child_route_id_pair, url, referrer); | 172 prerender_manager->AddPendingPreload(child_route_id_pair, url, referrer); |
| 148 else | 173 else |
| 149 prerender_manager->AddPreload(child_route_id_pair, url, referrer); | 174 prerender_manager->AddPreload(child_route_id_pair, url, referrer); |
| 150 } | 175 } |
| 151 | 176 |
| 177 void DestroyPreloadForRenderView( |
| 178 const base::WeakPtr<PrerenderManager>& prerender_manager_weak_ptr, |
| 179 int render_process_id, |
| 180 int render_view_id, |
| 181 FinalStatus final_status) { |
| 182 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 183 PrerenderManager* prerender_manager = prerender_manager_weak_ptr.get(); |
| 184 if (!prerender_manager) |
| 185 return; |
| 186 |
| 187 prerender_manager->DestroyPreloadForChildRouteIdPair( |
| 188 std::make_pair(render_process_id, render_view_id), |
| 189 final_status); |
| 190 } |
| 191 |
| 152 PrerenderManager::PrerenderManager(Profile* profile) | 192 PrerenderManager::PrerenderManager(Profile* profile) |
| 153 : rate_limit_enabled_(true), | 193 : rate_limit_enabled_(true), |
| 154 enabled_(true), | 194 enabled_(true), |
| 155 profile_(profile), | 195 profile_(profile), |
| 156 max_prerender_age_(base::TimeDelta::FromSeconds( | 196 max_prerender_age_(base::TimeDelta::FromSeconds( |
| 157 kDefaultMaxPrerenderAgeSeconds)), | 197 kDefaultMaxPrerenderAgeSeconds)), |
| 158 max_prerender_memory_mb_(kDefaultMaxPrerenderMemoryMB), | 198 max_prerender_memory_mb_(kDefaultMaxPrerenderMemoryMB), |
| 159 max_elements_(kDefaultMaxPrerenderElements), | 199 max_elements_(kDefaultMaxPrerenderElements), |
| 160 prerender_contents_factory_(PrerenderContents::CreateFactory()), | 200 prerender_contents_factory_(PrerenderContents::CreateFactory()), |
| 161 last_prerender_start_time_(GetCurrentTimeTicks() - | 201 last_prerender_start_time_(GetCurrentTimeTicks() - |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 260 StartSchedulingPeriodicCleanups(); | 300 StartSchedulingPeriodicCleanups(); |
| 261 return true; | 301 return true; |
| 262 } | 302 } |
| 263 | 303 |
| 264 void PrerenderManager::AddPendingPreload( | 304 void PrerenderManager::AddPendingPreload( |
| 265 const std::pair<int, int>& child_route_id_pair, | 305 const std::pair<int, int>& child_route_id_pair, |
| 266 const GURL& url, | 306 const GURL& url, |
| 267 const GURL& referrer) { | 307 const GURL& referrer) { |
| 268 DCHECK(CalledOnValidThread()); | 308 DCHECK(CalledOnValidThread()); |
| 269 // Check if this is coming from a valid prerender RenderViewHost. | 309 // Check if this is coming from a valid prerender RenderViewHost. |
| 270 bool is_valid_prerender = false; | 310 bool is_valid_prerender = |
| 271 for (std::list<PrerenderContentsData>::iterator it = prerender_list_.begin(); | 311 (FindPrerenderContentsForChildRouteIdPair(child_route_id_pair) != |
| 272 it != prerender_list_.end(); ++it) { | 312 prerender_list_.end()); |
| 273 PrerenderContents* prerender_contents = it->contents_; | |
| 274 | |
| 275 int child_id; | |
| 276 int route_id; | |
| 277 bool has_child_id = prerender_contents->GetChildId(&child_id); | |
| 278 bool has_route_id = has_child_id && | |
| 279 prerender_contents->GetRouteId(&route_id); | |
| 280 | |
| 281 if (has_child_id && has_route_id && | |
| 282 child_id == child_route_id_pair.first && | |
| 283 route_id == child_route_id_pair.second) { | |
| 284 is_valid_prerender = true; | |
| 285 break; | |
| 286 } | |
| 287 } | |
| 288 | 313 |
| 289 // If not, we could check to see if the RenderViewHost specified by the | 314 // If not, we could check to see if the RenderViewHost specified by the |
| 290 // child_route_id_pair exists and if so just start prerendering, as this | 315 // child_route_id_pair exists and if so just start prerendering, as this |
| 291 // suggests that the link was clicked, though this might prerender something | 316 // suggests that the link was clicked, though this might prerender something |
| 292 // that the user has already navigated away from. For now, we'll be | 317 // that the user has already navigated away from. For now, we'll be |
| 293 // conservative and skip the prerender which will mean some prerender requests | 318 // conservative and skip the prerender which will mean some prerender requests |
| 294 // from prerendered pages will be missed if the user navigates quickly. | 319 // from prerendered pages will be missed if the user navigates quickly. |
| 295 if (!is_valid_prerender) { | 320 if (!is_valid_prerender) { |
| 296 RecordFinalStatus(FINAL_STATUS_PENDING_SKIPPED); | 321 RecordFinalStatus(FINAL_STATUS_PENDING_SKIPPED); |
| 297 return; | 322 return; |
| 298 } | 323 } |
| 299 | 324 |
| 300 PendingPrerenderList::iterator it = | 325 PendingPrerenderList::iterator it = |
| 301 pending_prerender_list_.find(child_route_id_pair); | 326 pending_prerender_list_.find(child_route_id_pair); |
| 302 if (it == pending_prerender_list_.end()) { | 327 if (it == pending_prerender_list_.end()) { |
| 303 PendingPrerenderList::value_type el = std::make_pair(child_route_id_pair, | 328 PendingPrerenderList::value_type el = std::make_pair(child_route_id_pair, |
| 304 std::vector<PendingContentsData>()); | 329 std::vector<PendingContentsData>()); |
| 305 it = pending_prerender_list_.insert(el).first; | 330 it = pending_prerender_list_.insert(el).first; |
| 306 } | 331 } |
| 307 | 332 |
| 308 it->second.push_back(PendingContentsData(url, referrer)); | 333 it->second.push_back(PendingContentsData(url, referrer)); |
| 309 } | 334 } |
| 310 | 335 |
| 336 std::list<PrerenderManager::PrerenderContentsData>::iterator |
| 337 PrerenderManager::FindPrerenderContentsForChildRouteIdPair( |
| 338 const std::pair<int, int>& child_route_id_pair) { |
| 339 std::list<PrerenderContentsData>::iterator it = prerender_list_.begin(); |
| 340 for (; it != prerender_list_.end(); ++it) { |
| 341 PrerenderContents* prerender_contents = it->contents_; |
| 342 |
| 343 int child_id; |
| 344 int route_id; |
| 345 bool has_child_id = prerender_contents->GetChildId(&child_id); |
| 346 bool has_route_id = has_child_id && |
| 347 prerender_contents->GetRouteId(&route_id); |
| 348 |
| 349 if (has_child_id && has_route_id && |
| 350 child_id == child_route_id_pair.first && |
| 351 route_id == child_route_id_pair.second) { |
| 352 break; |
| 353 } |
| 354 } |
| 355 return it; |
| 356 } |
| 357 |
| 358 void PrerenderManager::DestroyPreloadForChildRouteIdPair( |
| 359 const std::pair<int, int>& child_route_id_pair, |
| 360 FinalStatus final_status) { |
| 361 DCHECK(CalledOnValidThread()); |
| 362 std::list<PrerenderContentsData>::iterator it = |
| 363 FindPrerenderContentsForChildRouteIdPair(child_route_id_pair); |
| 364 if (it != prerender_list_.end()) { |
| 365 PrerenderContents* prerender_contents = it->contents_; |
| 366 prerender_contents->set_final_status(final_status); |
| 367 RemovePendingPreload(prerender_contents); |
| 368 |
| 369 delete prerender_contents; |
| 370 prerender_list_.erase(it); |
| 371 } |
| 372 } |
| 373 |
| 311 void PrerenderManager::DeleteOldEntries() { | 374 void PrerenderManager::DeleteOldEntries() { |
| 312 DCHECK(CalledOnValidThread()); | 375 DCHECK(CalledOnValidThread()); |
| 313 while (!prerender_list_.empty()) { | 376 while (!prerender_list_.empty()) { |
| 314 PrerenderContentsData data = prerender_list_.front(); | 377 PrerenderContentsData data = prerender_list_.front(); |
| 315 if (IsPrerenderElementFresh(data.start_time_)) | 378 if (IsPrerenderElementFresh(data.start_time_)) |
| 316 return; | 379 return; |
| 317 prerender_list_.pop_front(); | 380 prerender_list_.pop_front(); |
| 318 data.contents_->set_final_status(FINAL_STATUS_TIMED_OUT); | 381 data.contents_->set_final_status(FINAL_STATUS_TIMED_OUT); |
| 319 delete data.contents_; | 382 delete data.contents_; |
| 320 } | 383 } |
| (...skipping 449 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 770 return prerendered_tab_contents_set_.count(tab_contents) > 0; | 833 return prerendered_tab_contents_set_.count(tab_contents) > 0; |
| 771 } | 834 } |
| 772 | 835 |
| 773 bool PrerenderManager::WouldTabContentsBePrerendered( | 836 bool PrerenderManager::WouldTabContentsBePrerendered( |
| 774 TabContents* tab_contents) const { | 837 TabContents* tab_contents) const { |
| 775 DCHECK(CalledOnValidThread()); | 838 DCHECK(CalledOnValidThread()); |
| 776 return would_be_prerendered_tab_contents_set_.count(tab_contents) > 0; | 839 return would_be_prerendered_tab_contents_set_.count(tab_contents) > 0; |
| 777 } | 840 } |
| 778 | 841 |
| 779 } // namespace prerender | 842 } // namespace prerender |
| OLD | NEW |