Home | History | Annotate | Download | only in content
      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