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 #include "chrome/browser/predictors/resource_prefetcher_manager.h" 6 7 #include "base/bind.h" 8 #include "base/stl_util.h" 9 #include "chrome/browser/predictors/resource_prefetch_predictor.h" 10 #include "content/public/browser/browser_thread.h" 11 #include "net/url_request/url_request.h" 12 #include "net/url_request/url_request_context_getter.h" 13 14 using content::BrowserThread; 15 16 namespace predictors { 17 18 ResourcePrefetcherManager::ResourcePrefetcherManager( 19 ResourcePrefetchPredictor* predictor, 20 const ResourcePrefetchPredictorConfig& config, 21 net::URLRequestContextGetter* context_getter) 22 : predictor_(predictor), 23 config_(config), 24 context_getter_(context_getter) { 25 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 26 CHECK(predictor_); 27 CHECK(context_getter_); 28 } 29 30 ResourcePrefetcherManager::~ResourcePrefetcherManager() { 31 DCHECK(prefetcher_map_.empty()) 32 << "Did not call ShutdownOnUIThread or ShutdownOnIOThread. " 33 " Will leak Prefetcher pointers."; 34 } 35 36 void ResourcePrefetcherManager::ShutdownOnUIThread() { 37 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 38 39 predictor_ = NULL; 40 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, 41 base::Bind(&ResourcePrefetcherManager::ShutdownOnIOThread, 42 this)); 43 } 44 45 void ResourcePrefetcherManager::ShutdownOnIOThread() { 46 CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 47 STLDeleteContainerPairSecondPointers(prefetcher_map_.begin(), 48 prefetcher_map_.end()); 49 } 50 51 void ResourcePrefetcherManager::MaybeAddPrefetch( 52 const NavigationID& navigation_id, 53 PrefetchKeyType key_type, 54 scoped_ptr<ResourcePrefetcher::RequestVector> requests) { 55 CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 56 57 // Don't add a duplicate prefetch for the same host or URL. 58 std::string key = key_type == PREFETCH_KEY_TYPE_HOST ? 59 navigation_id.main_frame_url.host() : navigation_id.main_frame_url.spec(); 60 PrefetcherMap::iterator prefetcher_it = prefetcher_map_.find(key); 61 if (prefetcher_it != prefetcher_map_.end()) 62 return; 63 64 ResourcePrefetcher* prefetcher = new ResourcePrefetcher( 65 this, config_, navigation_id, key_type, requests.Pass()); 66 prefetcher_map_.insert(std::make_pair(key, prefetcher)); 67 prefetcher->Start(); 68 } 69 70 void ResourcePrefetcherManager::MaybeRemovePrefetch( 71 const NavigationID& navigation_id) { 72 CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 73 74 // Look for a URL based prefetch first. 75 PrefetcherMap::iterator it = prefetcher_map_.find( 76 navigation_id.main_frame_url.spec()); 77 if (it != prefetcher_map_.end() && 78 it->second->navigation_id() == navigation_id) { 79 it->second->Stop(); 80 return; 81 } 82 83 // No URL based prefetching, look for host based. 84 it = prefetcher_map_.find(navigation_id.main_frame_url.host()); 85 if (it != prefetcher_map_.end() && 86 it->second->navigation_id() == navigation_id) { 87 it->second->Stop(); 88 } 89 } 90 91 void ResourcePrefetcherManager::ResourcePrefetcherFinished( 92 ResourcePrefetcher* resource_prefetcher, 93 ResourcePrefetcher::RequestVector* requests) { 94 CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 95 96 // |predictor_| can only be accessed from the UI thread. 97 scoped_ptr<ResourcePrefetcher::RequestVector> requests_ptr(requests); 98 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 99 base::Bind(&ResourcePrefetcherManager::ResourcePrefetcherFinishedOnUI, 100 this, 101 resource_prefetcher->navigation_id(), 102 resource_prefetcher->key_type(), 103 base::Passed(&requests_ptr))); 104 105 const GURL& main_frame_url = 106 resource_prefetcher->navigation_id().main_frame_url; 107 const std::string key = 108 resource_prefetcher->key_type() == PREFETCH_KEY_TYPE_HOST ? 109 main_frame_url.host() : main_frame_url.spec(); 110 PrefetcherMap::iterator it = prefetcher_map_.find(key); 111 DCHECK(it != prefetcher_map_.end()); 112 delete it->second; 113 prefetcher_map_.erase(it); 114 } 115 116 void ResourcePrefetcherManager::ResourcePrefetcherFinishedOnUI( 117 const NavigationID& navigation_id, 118 PrefetchKeyType key_type, 119 scoped_ptr<ResourcePrefetcher::RequestVector> requests) { 120 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 121 122 // |predictor_| may have been set to NULL if the predictor is shutting down. 123 if (predictor_) 124 predictor_->FinishedPrefetchForNavigation(navigation_id, 125 key_type, 126 requests.release()); 127 } 128 129 net::URLRequestContext* ResourcePrefetcherManager::GetURLRequestContext() { 130 CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 131 132 return context_getter_->GetURLRequestContext(); 133 } 134 135 } // namespace predictors 136