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
ResourcePrefetcherManager(ResourcePrefetchPredictor * predictor,const ResourcePrefetchPredictorConfig & config,net::URLRequestContextGetter * context_getter)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
~ResourcePrefetcherManager()30 ResourcePrefetcherManager::~ResourcePrefetcherManager() {
31 DCHECK(prefetcher_map_.empty())
32 << "Did not call ShutdownOnUIThread or ShutdownOnIOThread. "
33 " Will leak Prefetcher pointers.";
34 }
35
ShutdownOnUIThread()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
ShutdownOnIOThread()45 void ResourcePrefetcherManager::ShutdownOnIOThread() {
46 CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
47 STLDeleteContainerPairSecondPointers(prefetcher_map_.begin(),
48 prefetcher_map_.end());
49 }
50
MaybeAddPrefetch(const NavigationID & navigation_id,PrefetchKeyType key_type,scoped_ptr<ResourcePrefetcher::RequestVector> requests)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
MaybeRemovePrefetch(const NavigationID & navigation_id)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
ResourcePrefetcherFinished(ResourcePrefetcher * resource_prefetcher,ResourcePrefetcher::RequestVector * requests)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
ResourcePrefetcherFinishedOnUI(const NavigationID & navigation_id,PrefetchKeyType key_type,scoped_ptr<ResourcePrefetcher::RequestVector> requests)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
GetURLRequestContext()129 net::URLRequestContext* ResourcePrefetcherManager::GetURLRequestContext() {
130 CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
131
132 return context_getter_->GetURLRequestContext();
133 }
134
135 } // namespace predictors
136