1 // Copyright 2013 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 "components/precache/content/precache_manager.h"
6
7 #include "base/bind.h"
8 #include "base/command_line.h"
9 #include "base/files/file_path.h"
10 #include "base/logging.h"
11 #include "base/metrics/field_trial.h"
12 #include "base/prefs/pref_service.h"
13 #include "base/time/time.h"
14 #include "components/data_reduction_proxy/common/data_reduction_proxy_pref_names.h"
15 #include "components/precache/core/precache_database.h"
16 #include "components/precache/core/precache_switches.h"
17 #include "components/precache/core/url_list_provider.h"
18 #include "components/user_prefs/user_prefs.h"
19 #include "content/public/browser/browser_context.h"
20 #include "content/public/browser/browser_thread.h"
21 #include "net/base/network_change_notifier.h"
22
23 using content::BrowserThread;
24
25 namespace {
26
27 const char kPrecacheFieldTrialName[] = "Precache";
28 const char kPrecacheFieldTrialEnabledGroup[] = "Enabled";
29
30 } // namespace
31
32 namespace precache {
33
PrecacheManager(content::BrowserContext * browser_context)34 PrecacheManager::PrecacheManager(content::BrowserContext* browser_context)
35 : browser_context_(browser_context),
36 precache_database_(new PrecacheDatabase()),
37 is_precaching_(false) {
38 base::FilePath db_path(browser_context_->GetPath().Append(
39 base::FilePath(FILE_PATH_LITERAL("PrecacheDatabase"))));
40
41 BrowserThread::PostTask(
42 BrowserThread::DB, FROM_HERE,
43 base::Bind(base::IgnoreResult(&PrecacheDatabase::Init),
44 precache_database_, db_path));
45 }
46
~PrecacheManager()47 PrecacheManager::~PrecacheManager() {}
48
49 // static
IsPrecachingEnabled()50 bool PrecacheManager::IsPrecachingEnabled() {
51 return base::FieldTrialList::FindFullName(kPrecacheFieldTrialName) ==
52 kPrecacheFieldTrialEnabledGroup ||
53 CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnablePrecache);
54 }
55
IsPrecachingAllowed()56 bool PrecacheManager::IsPrecachingAllowed() {
57 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
58 return user_prefs::UserPrefs::Get(browser_context_)->GetBoolean(
59 data_reduction_proxy::prefs::kDataReductionProxyEnabled);
60 }
61
StartPrecaching(const PrecacheCompletionCallback & precache_completion_callback,URLListProvider * url_list_provider)62 void PrecacheManager::StartPrecaching(
63 const PrecacheCompletionCallback& precache_completion_callback,
64 URLListProvider* url_list_provider) {
65 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
66
67 if (is_precaching_) {
68 DLOG(WARNING) << "Cannot start precaching because precaching is already "
69 "in progress.";
70 return;
71 }
72 is_precaching_ = true;
73
74 BrowserThread::PostTask(
75 BrowserThread::DB, FROM_HERE,
76 base::Bind(&PrecacheDatabase::DeleteExpiredPrecacheHistory,
77 precache_database_, base::Time::Now()));
78
79 precache_completion_callback_ = precache_completion_callback;
80
81 url_list_provider->GetURLs(
82 base::Bind(&PrecacheManager::OnURLsReceived, AsWeakPtr()));
83 }
84
CancelPrecaching()85 void PrecacheManager::CancelPrecaching() {
86 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
87
88 if (!is_precaching_) {
89 // Do nothing if precaching is not in progress.
90 return;
91 }
92 is_precaching_ = false;
93
94 // Destroying the |precache_fetcher_| will cancel any fetch in progress.
95 precache_fetcher_.reset();
96
97 // Uninitialize the callback so that any scoped_refptrs in it are released.
98 precache_completion_callback_.Reset();
99 }
100
IsPrecaching() const101 bool PrecacheManager::IsPrecaching() const {
102 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
103 return is_precaching_;
104 }
105
RecordStatsForFetch(const GURL & url,const base::Time & fetch_time,int64 size,bool was_cached)106 void PrecacheManager::RecordStatsForFetch(const GURL& url,
107 const base::Time& fetch_time,
108 int64 size,
109 bool was_cached) {
110 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
111
112 if (size == 0 || url.is_empty() || !url.SchemeIsHTTPOrHTTPS()) {
113 // Ignore empty responses, empty URLs, or URLs that aren't HTTP or HTTPS.
114 return;
115 }
116
117 if (is_precaching_) {
118 // Assume that precache is responsible for all requests made while
119 // precaching is currently in progress.
120 // TODO(sclittle): Make PrecacheFetcher explicitly mark precache-motivated
121 // fetches, and use that to determine whether or not a fetch was motivated
122 // by precaching.
123 BrowserThread::PostTask(
124 BrowserThread::DB, FROM_HERE,
125 base::Bind(&PrecacheDatabase::RecordURLPrecached, precache_database_,
126 url, fetch_time, size, was_cached));
127 } else {
128 bool is_connection_cellular =
129 net::NetworkChangeNotifier::IsConnectionCellular(
130 net::NetworkChangeNotifier::GetConnectionType());
131
132 BrowserThread::PostTask(
133 BrowserThread::DB, FROM_HERE,
134 base::Bind(&PrecacheDatabase::RecordURLFetched, precache_database_, url,
135 fetch_time, size, was_cached, is_connection_cellular));
136 }
137 }
138
Shutdown()139 void PrecacheManager::Shutdown() {
140 CancelPrecaching();
141 }
142
OnDone()143 void PrecacheManager::OnDone() {
144 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
145
146 // If OnDone has been called, then we should just be finishing precaching.
147 DCHECK(is_precaching_);
148 is_precaching_ = false;
149
150 precache_fetcher_.reset();
151
152 precache_completion_callback_.Run();
153 // Uninitialize the callback so that any scoped_refptrs in it are released.
154 precache_completion_callback_.Reset();
155 }
156
OnURLsReceived(const std::list<GURL> & urls)157 void PrecacheManager::OnURLsReceived(const std::list<GURL>& urls) {
158 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
159
160 if (!is_precaching_) {
161 // Don't start precaching if it was canceled while waiting for the list of
162 // URLs.
163 return;
164 }
165
166 // Start precaching.
167 precache_fetcher_.reset(
168 new PrecacheFetcher(urls, browser_context_->GetRequestContext(), this));
169 precache_fetcher_->Start();
170 }
171
172 } // namespace precache
173