Chromium Code Reviews| 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 for (size_t i = 0; i < arraysize(kValidHttpMethods); ++i) { | |
|
cbentzel
2011/05/02 20:27:38
DCHECK_EQ(method, StringToUpperASCII(method))
at
dominich
2011/05/02 21:04:55
Done.
| |
| 125 // method has been canonicalized to upper case at this point so we can just | |
| 126 // compare. | |
| 127 if (method.compare(kValidHttpMethods[i]) == 0) | |
| 128 return true; | |
| 129 } | |
| 130 | |
| 131 return false; | |
| 132 } | |
| 133 | |
| 114 struct PrerenderManager::PrerenderContentsData { | 134 struct PrerenderManager::PrerenderContentsData { |
| 115 PrerenderContents* contents_; | 135 PrerenderContents* contents_; |
| 116 base::Time start_time_; | 136 base::Time start_time_; |
| 117 PrerenderContentsData(PrerenderContents* contents, base::Time start_time) | 137 PrerenderContentsData(PrerenderContents* contents, base::Time start_time) |
| 118 : contents_(contents), | 138 : contents_(contents), |
| 119 start_time_(start_time) { | 139 start_time_(start_time) { |
| 120 } | 140 } |
| 121 }; | 141 }; |
| 122 | 142 |
| 123 struct PrerenderManager::PendingContentsData { | 143 struct PrerenderManager::PendingContentsData { |
| 124 PendingContentsData(const GURL& url, | 144 PendingContentsData(const GURL& url, |
| 125 const GURL& referrer) | 145 const GURL& referrer) |
| 126 : url_(url), referrer_(referrer) { } | 146 : url_(url), referrer_(referrer) { } |
| 127 ~PendingContentsData() {} | 147 ~PendingContentsData() {} |
| 128 GURL url_; | 148 GURL url_; |
| 129 GURL referrer_; | 149 GURL referrer_; |
| 130 }; | 150 }; |
| 131 | 151 |
| 132 void HandlePrefetchTagOnUIThread( | 152 void HandlePrefetchTag( |
| 133 const base::WeakPtr<PrerenderManager>& prerender_manager_weak_ptr, | 153 const base::WeakPtr<PrerenderManager>& prerender_manager_weak_ptr, |
| 134 const std::pair<int, int>& child_route_id_pair, | 154 int render_process_id, |
| 155 int render_view_id, | |
| 135 const GURL& url, | 156 const GURL& url, |
| 136 const GURL& referrer, | 157 const GURL& referrer, |
| 137 bool make_pending) { | 158 bool make_pending) { |
| 138 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 159 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 139 PrerenderManager* prerender_manager = prerender_manager_weak_ptr.get(); | 160 PrerenderManager* prerender_manager = prerender_manager_weak_ptr.get(); |
| 140 if (!prerender_manager || !prerender_manager->is_enabled()) | 161 if (!prerender_manager || !prerender_manager->is_enabled()) |
| 141 return; | 162 return; |
| 142 prerender_manager->RecordPrefetchTagObserved(); | 163 prerender_manager->RecordPrefetchTagObserved(); |
| 164 | |
| 165 std::pair<int, int> child_route_id_pair = std::make_pair(render_process_id, | |
| 166 render_view_id); | |
| 143 // TODO(cbentzel): Should the decision to make pending be done on the | 167 // TODO(cbentzel): Should the decision to make pending be done on the |
| 144 // UI thread rather than the IO thread? The page may have | 168 // UI thread rather than the IO thread? The page may have |
| 145 // become activated at this point. | 169 // become activated at this point. |
| 146 if (make_pending) | 170 if (make_pending) |
| 147 prerender_manager->AddPendingPreload(child_route_id_pair, url, referrer); | 171 prerender_manager->AddPendingPreload(child_route_id_pair, url, referrer); |
| 148 else | 172 else |
| 149 prerender_manager->AddPreload(child_route_id_pair, url, referrer); | 173 prerender_manager->AddPreload(child_route_id_pair, url, referrer); |
| 150 } | 174 } |
| 151 | 175 |
| 176 void DestroyPreloadForRenderView( | |
| 177 const base::WeakPtr<PrerenderManager>& prerender_manager_weak_ptr, | |
| 178 int render_process_id, | |
| 179 int render_view_id, | |
| 180 FinalStatus final_status) { | |
| 181 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 182 PrerenderManager* prerender_manager = prerender_manager_weak_ptr.get(); | |
| 183 if (!prerender_manager) | |
| 184 return; | |
| 185 | |
| 186 prerender_manager->DestroyPreloadForChildRouteIdPair( | |
| 187 std::make_pair(render_process_id, render_view_id), | |
| 188 final_status); | |
| 189 } | |
| 190 | |
| 152 PrerenderManager::PrerenderManager(Profile* profile) | 191 PrerenderManager::PrerenderManager(Profile* profile) |
| 153 : rate_limit_enabled_(true), | 192 : rate_limit_enabled_(true), |
| 154 enabled_(true), | 193 enabled_(true), |
| 155 profile_(profile), | 194 profile_(profile), |
| 156 max_prerender_age_(base::TimeDelta::FromSeconds( | 195 max_prerender_age_(base::TimeDelta::FromSeconds( |
| 157 kDefaultMaxPrerenderAgeSeconds)), | 196 kDefaultMaxPrerenderAgeSeconds)), |
| 158 max_prerender_memory_mb_(kDefaultMaxPrerenderMemoryMB), | 197 max_prerender_memory_mb_(kDefaultMaxPrerenderMemoryMB), |
| 159 max_elements_(kDefaultMaxPrerenderElements), | 198 max_elements_(kDefaultMaxPrerenderElements), |
| 160 prerender_contents_factory_(PrerenderContents::CreateFactory()), | 199 prerender_contents_factory_(PrerenderContents::CreateFactory()), |
| 161 last_prerender_start_time_(GetCurrentTimeTicks() - | 200 last_prerender_start_time_(GetCurrentTimeTicks() - |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 260 StartSchedulingPeriodicCleanups(); | 299 StartSchedulingPeriodicCleanups(); |
| 261 return true; | 300 return true; |
| 262 } | 301 } |
| 263 | 302 |
| 264 void PrerenderManager::AddPendingPreload( | 303 void PrerenderManager::AddPendingPreload( |
| 265 const std::pair<int, int>& child_route_id_pair, | 304 const std::pair<int, int>& child_route_id_pair, |
| 266 const GURL& url, | 305 const GURL& url, |
| 267 const GURL& referrer) { | 306 const GURL& referrer) { |
| 268 DCHECK(CalledOnValidThread()); | 307 DCHECK(CalledOnValidThread()); |
| 269 // Check if this is coming from a valid prerender RenderViewHost. | 308 // Check if this is coming from a valid prerender RenderViewHost. |
| 270 bool is_valid_prerender = false; | 309 bool is_valid_prerender = |
| 271 for (std::list<PrerenderContentsData>::iterator it = prerender_list_.begin(); | 310 (FindPrerenderContentsForChildRouteIdPair(child_route_id_pair) != |
| 272 it != prerender_list_.end(); ++it) { | 311 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 | 312 |
| 289 // If not, we could check to see if the RenderViewHost specified by the | 313 // 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 | 314 // 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 | 315 // 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 | 316 // 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 | 317 // conservative and skip the prerender which will mean some prerender requests |
| 294 // from prerendered pages will be missed if the user navigates quickly. | 318 // from prerendered pages will be missed if the user navigates quickly. |
| 295 if (!is_valid_prerender) { | 319 if (!is_valid_prerender) { |
| 296 RecordFinalStatus(FINAL_STATUS_PENDING_SKIPPED); | 320 RecordFinalStatus(FINAL_STATUS_PENDING_SKIPPED); |
| 297 return; | 321 return; |
| 298 } | 322 } |
| 299 | 323 |
| 300 PendingPrerenderList::iterator it = | 324 PendingPrerenderList::iterator it = |
| 301 pending_prerender_list_.find(child_route_id_pair); | 325 pending_prerender_list_.find(child_route_id_pair); |
| 302 if (it == pending_prerender_list_.end()) { | 326 if (it == pending_prerender_list_.end()) { |
| 303 PendingPrerenderList::value_type el = std::make_pair(child_route_id_pair, | 327 PendingPrerenderList::value_type el = std::make_pair(child_route_id_pair, |
| 304 std::vector<PendingContentsData>()); | 328 std::vector<PendingContentsData>()); |
| 305 it = pending_prerender_list_.insert(el).first; | 329 it = pending_prerender_list_.insert(el).first; |
| 306 } | 330 } |
| 307 | 331 |
| 308 it->second.push_back(PendingContentsData(url, referrer)); | 332 it->second.push_back(PendingContentsData(url, referrer)); |
| 309 } | 333 } |
| 310 | 334 |
| 335 std::list<PrerenderManager::PrerenderContentsData>::iterator | |
| 336 PrerenderManager::FindPrerenderContentsForChildRouteIdPair( | |
| 337 const std::pair<int, int>& child_route_id_pair) { | |
| 338 std::list<PrerenderContentsData>::iterator it = prerender_list_.begin(); | |
| 339 for (; it != prerender_list_.end(); ++it) { | |
| 340 PrerenderContents* prerender_contents = it->contents_; | |
| 341 | |
| 342 int child_id; | |
| 343 int route_id; | |
| 344 bool has_child_id = prerender_contents->GetChildId(&child_id); | |
| 345 bool has_route_id = has_child_id && | |
| 346 prerender_contents->GetRouteId(&route_id); | |
| 347 | |
| 348 if (has_child_id && has_route_id && | |
| 349 child_id == child_route_id_pair.first && | |
| 350 route_id == child_route_id_pair.second) { | |
| 351 break; | |
| 352 } | |
| 353 } | |
| 354 return it; | |
| 355 } | |
| 356 | |
| 357 void PrerenderManager::DestroyPreloadForChildRouteIdPair( | |
| 358 const std::pair<int, int>& child_route_id_pair, | |
| 359 FinalStatus final_status) { | |
| 360 DCHECK(CalledOnValidThread()); | |
| 361 std::list<PrerenderContentsData>::iterator it = | |
| 362 FindPrerenderContentsForChildRouteIdPair(child_route_id_pair); | |
| 363 if (it != prerender_list_.end()) { | |
| 364 PrerenderContents* prerender_contents = it->contents_; | |
| 365 prerender_contents->set_final_status(final_status); | |
| 366 RemovePendingPreload(prerender_contents); | |
| 367 | |
| 368 delete prerender_contents; | |
| 369 prerender_list_.erase(it); | |
| 370 } | |
| 371 } | |
| 372 | |
| 311 void PrerenderManager::DeleteOldEntries() { | 373 void PrerenderManager::DeleteOldEntries() { |
| 312 DCHECK(CalledOnValidThread()); | 374 DCHECK(CalledOnValidThread()); |
| 313 while (!prerender_list_.empty()) { | 375 while (!prerender_list_.empty()) { |
| 314 PrerenderContentsData data = prerender_list_.front(); | 376 PrerenderContentsData data = prerender_list_.front(); |
| 315 if (IsPrerenderElementFresh(data.start_time_)) | 377 if (IsPrerenderElementFresh(data.start_time_)) |
| 316 return; | 378 return; |
| 317 prerender_list_.pop_front(); | 379 prerender_list_.pop_front(); |
| 318 data.contents_->set_final_status(FINAL_STATUS_TIMED_OUT); | 380 data.contents_->set_final_status(FINAL_STATUS_TIMED_OUT); |
| 319 delete data.contents_; | 381 delete data.contents_; |
| 320 } | 382 } |
| (...skipping 449 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 770 return prerendered_tab_contents_set_.count(tab_contents) > 0; | 832 return prerendered_tab_contents_set_.count(tab_contents) > 0; |
| 771 } | 833 } |
| 772 | 834 |
| 773 bool PrerenderManager::WouldTabContentsBePrerendered( | 835 bool PrerenderManager::WouldTabContentsBePrerendered( |
| 774 TabContents* tab_contents) const { | 836 TabContents* tab_contents) const { |
| 775 DCHECK(CalledOnValidThread()); | 837 DCHECK(CalledOnValidThread()); |
| 776 return would_be_prerendered_tab_contents_set_.count(tab_contents) > 0; | 838 return would_be_prerendered_tab_contents_set_.count(tab_contents) > 0; |
| 777 } | 839 } |
| 778 | 840 |
| 779 } // namespace prerender | 841 } // namespace prerender |
| OLD | NEW |