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 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 47 PrecacheManager::~PrecacheManager() {} 48 49 // static 50 bool PrecacheManager::IsPrecachingEnabled() { 51 return base::FieldTrialList::FindFullName(kPrecacheFieldTrialName) == 52 kPrecacheFieldTrialEnabledGroup || 53 CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnablePrecache); 54 } 55 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 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 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 101 bool PrecacheManager::IsPrecaching() const { 102 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 103 return is_precaching_; 104 } 105 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 139 void PrecacheManager::Shutdown() { 140 CancelPrecaching(); 141 } 142 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 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