Home | History | Annotate | Download | only in browsing_data
      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/browsing_data/browsing_data_file_system_helper.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/compiler_specific.h"
      9 #include "base/memory/scoped_ptr.h"
     10 #include "base/message_loop/message_loop.h"
     11 #include "base/sequenced_task_runner.h"
     12 #include "base/strings/string_util.h"
     13 #include "base/strings/utf_string_conversions.h"
     14 #include "chrome/browser/browsing_data/browsing_data_helper.h"
     15 #include "content/public/browser/browser_thread.h"
     16 #include "webkit/browser/fileapi/file_system_context.h"
     17 #include "webkit/browser/fileapi/file_system_quota_util.h"
     18 #include "webkit/common/fileapi/file_system_types.h"
     19 
     20 using content::BrowserThread;
     21 
     22 namespace fileapi {
     23 class FileSystemContext;
     24 }
     25 
     26 namespace {
     27 
     28 // An implementation of the BrowsingDataFileSystemHelper interface that pulls
     29 // data from a given |filesystem_context| and returns a list of FileSystemInfo
     30 // items to a client.
     31 class BrowsingDataFileSystemHelperImpl : public BrowsingDataFileSystemHelper {
     32  public:
     33   // BrowsingDataFileSystemHelper implementation
     34   explicit BrowsingDataFileSystemHelperImpl(
     35       fileapi::FileSystemContext* filesystem_context);
     36   virtual void StartFetching(const base::Callback<
     37       void(const std::list<FileSystemInfo>&)>& callback) OVERRIDE;
     38   virtual void DeleteFileSystemOrigin(const GURL& origin) OVERRIDE;
     39 
     40  private:
     41   virtual ~BrowsingDataFileSystemHelperImpl();
     42 
     43   // Enumerates all filesystem files, storing the resulting list into
     44   // file_system_file_ for later use. This must be called on the file
     45   // task runner.
     46   void FetchFileSystemInfoInFileThread();
     47 
     48   // Triggers the success callback as the end of a StartFetching workflow. This
     49   // must be called on the UI thread.
     50   void NotifyOnUIThread();
     51 
     52   // Deletes all file systems associated with |origin|. This must be called on
     53   // the file task runner.
     54   void DeleteFileSystemOriginInFileThread(const GURL& origin);
     55 
     56   // Returns the file task runner for the |filesystem_context_|.
     57   base::SequencedTaskRunner* file_task_runner() {
     58     return filesystem_context_->default_file_task_runner();
     59   }
     60 
     61   // Keep a reference to the FileSystemContext object for the current profile
     62   // for use on the file task runner.
     63   scoped_refptr<fileapi::FileSystemContext> filesystem_context_;
     64 
     65   // Holds the current list of file systems returned to the client after
     66   // StartFetching is called. Access to |file_system_info_| is triggered
     67   // indirectly via the UI thread and guarded by |is_fetching_|. This means
     68   // |file_system_info_| is only accessed while |is_fetching_| is true. The
     69   // flag |is_fetching_| is only accessed on the UI thread. In the context of
     70   // this class |file_system_info_| only mutates on the file task runner.
     71   std::list<FileSystemInfo> file_system_info_;
     72 
     73   // Holds the callback passed in at the beginning of the StartFetching workflow
     74   // so that it can be triggered via NotifyOnUIThread. This only mutates on the
     75   // UI thread.
     76   base::Callback<void(const std::list<FileSystemInfo>&)> completion_callback_;
     77 
     78   // Indicates whether or not we're currently fetching information: set to true
     79   // when StartFetching is called on the UI thread, and reset to false when
     80   // NotifyOnUIThread triggers the success callback.
     81   // This property only mutates on the UI thread.
     82   bool is_fetching_;
     83 
     84   DISALLOW_COPY_AND_ASSIGN(BrowsingDataFileSystemHelperImpl);
     85 };
     86 
     87 BrowsingDataFileSystemHelperImpl::BrowsingDataFileSystemHelperImpl(
     88     fileapi::FileSystemContext* filesystem_context)
     89     : filesystem_context_(filesystem_context),
     90       is_fetching_(false) {
     91   DCHECK(filesystem_context_.get());
     92 }
     93 
     94 BrowsingDataFileSystemHelperImpl::~BrowsingDataFileSystemHelperImpl() {
     95 }
     96 
     97 void BrowsingDataFileSystemHelperImpl::StartFetching(
     98     const base::Callback<void(const std::list<FileSystemInfo>&)>& callback) {
     99   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    100   DCHECK(!is_fetching_);
    101   DCHECK_EQ(false, callback.is_null());
    102   is_fetching_ = true;
    103   completion_callback_ = callback;
    104   file_task_runner()->PostTask(
    105       FROM_HERE,
    106       base::Bind(
    107           &BrowsingDataFileSystemHelperImpl::FetchFileSystemInfoInFileThread,
    108           this));
    109 }
    110 
    111 void BrowsingDataFileSystemHelperImpl::DeleteFileSystemOrigin(
    112     const GURL& origin) {
    113   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    114   file_task_runner()->PostTask(
    115       FROM_HERE,
    116       base::Bind(
    117           &BrowsingDataFileSystemHelperImpl::DeleteFileSystemOriginInFileThread,
    118           this, origin));
    119 }
    120 
    121 void BrowsingDataFileSystemHelperImpl::FetchFileSystemInfoInFileThread() {
    122   DCHECK(file_task_runner()->RunsTasksOnCurrentThread());
    123 
    124   // We check usage for these filesystem types.
    125   const fileapi::FileSystemType types[] = {
    126     fileapi::kFileSystemTypeTemporary,
    127     fileapi::kFileSystemTypePersistent,
    128     fileapi::kFileSystemTypeSyncable,
    129   };
    130 
    131   typedef std::map<GURL, FileSystemInfo> OriginInfoMap;
    132   OriginInfoMap file_system_info_map;
    133   for (size_t i = 0; i < arraysize(types); ++i) {
    134     fileapi::FileSystemType type = types[i];
    135     fileapi::FileSystemQuotaUtil* quota_util =
    136       filesystem_context_->GetQuotaUtil(type);
    137     DCHECK(quota_util);
    138     std::set<GURL> origins;
    139     quota_util->GetOriginsForTypeOnFileThread(type, &origins);
    140     for (std::set<GURL>::iterator iter = origins.begin();
    141         iter != origins.end(); ++iter) {
    142       const GURL& current = *iter;
    143       if (!BrowsingDataHelper::HasWebScheme(current))
    144         continue;  // Non-websafe state is not considered browsing data.
    145       int64 usage = quota_util->GetOriginUsageOnFileThread(
    146           filesystem_context_.get(), current, type);
    147       OriginInfoMap::iterator inserted =
    148           file_system_info_map.insert(
    149               std::make_pair(current, FileSystemInfo(current))).first;
    150       inserted->second.usage_map[type] = usage;
    151     }
    152   }
    153 
    154   for (OriginInfoMap::iterator iter = file_system_info_map.begin();
    155        iter != file_system_info_map.end(); ++iter) {
    156     file_system_info_.push_back(iter->second);
    157   }
    158 
    159   BrowserThread::PostTask(
    160       BrowserThread::UI, FROM_HERE,
    161       base::Bind(&BrowsingDataFileSystemHelperImpl::NotifyOnUIThread, this));
    162 }
    163 
    164 void BrowsingDataFileSystemHelperImpl::NotifyOnUIThread() {
    165   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    166   DCHECK(is_fetching_);
    167   completion_callback_.Run(file_system_info_);
    168   completion_callback_.Reset();
    169   is_fetching_ = false;
    170 }
    171 
    172 void BrowsingDataFileSystemHelperImpl::DeleteFileSystemOriginInFileThread(
    173     const GURL& origin) {
    174   DCHECK(file_task_runner()->RunsTasksOnCurrentThread());
    175   filesystem_context_->DeleteDataForOriginOnFileThread(origin);
    176 }
    177 
    178 }  // namespace
    179 
    180 BrowsingDataFileSystemHelper::FileSystemInfo::FileSystemInfo(
    181     const GURL& origin) : origin(origin) {}
    182 
    183 BrowsingDataFileSystemHelper::FileSystemInfo::~FileSystemInfo() {}
    184 
    185 // static
    186 BrowsingDataFileSystemHelper* BrowsingDataFileSystemHelper::Create(
    187     fileapi::FileSystemContext* filesystem_context) {
    188   return new BrowsingDataFileSystemHelperImpl(filesystem_context);
    189 }
    190 
    191 CannedBrowsingDataFileSystemHelper::CannedBrowsingDataFileSystemHelper(
    192     Profile* profile)
    193     : is_fetching_(false) {
    194 }
    195 
    196 CannedBrowsingDataFileSystemHelper::CannedBrowsingDataFileSystemHelper()
    197     : is_fetching_(false) {
    198 }
    199 
    200 CannedBrowsingDataFileSystemHelper::~CannedBrowsingDataFileSystemHelper() {}
    201 
    202 CannedBrowsingDataFileSystemHelper*
    203     CannedBrowsingDataFileSystemHelper::Clone() {
    204   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    205   CannedBrowsingDataFileSystemHelper* clone =
    206       new CannedBrowsingDataFileSystemHelper();
    207   // This list only mutates on the UI thread, so it's safe to work with it here
    208   // (given the DCHECK above).
    209   clone->file_system_info_ = file_system_info_;
    210   return clone;
    211 }
    212 
    213 void CannedBrowsingDataFileSystemHelper::AddFileSystem(
    214     const GURL& origin, const fileapi::FileSystemType type, const int64 size) {
    215   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    216   // This canned implementation of AddFileSystem uses an O(n^2) algorithm; which
    217   // is fine, as it isn't meant for use in a high-volume context. If it turns
    218   // out that we want to start using this in a context with many, many origins,
    219   // we should think about reworking the implementation.
    220   bool duplicate_origin = false;
    221   for (std::list<FileSystemInfo>::iterator
    222            file_system = file_system_info_.begin();
    223        file_system != file_system_info_.end();
    224        ++file_system) {
    225     if (file_system->origin == origin) {
    226       file_system->usage_map[type] = size;
    227       duplicate_origin = true;
    228       break;
    229     }
    230   }
    231   if (duplicate_origin)
    232     return;
    233 
    234   if (!BrowsingDataHelper::HasWebScheme(origin))
    235     return;  // Non-websafe state is not considered browsing data.
    236 
    237   FileSystemInfo info(origin);
    238   info.usage_map[type] = size;
    239   file_system_info_.push_back(info);
    240 }
    241 
    242 void CannedBrowsingDataFileSystemHelper::Reset() {
    243   file_system_info_.clear();
    244 }
    245 
    246 bool CannedBrowsingDataFileSystemHelper::empty() const {
    247   return file_system_info_.empty();
    248 }
    249 
    250 size_t CannedBrowsingDataFileSystemHelper::GetFileSystemCount() const {
    251   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    252   return file_system_info_.size();
    253 }
    254 
    255 void CannedBrowsingDataFileSystemHelper::StartFetching(
    256     const base::Callback<void(const std::list<FileSystemInfo>&)>& callback) {
    257   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    258   DCHECK(!is_fetching_);
    259   DCHECK_EQ(false, callback.is_null());
    260   is_fetching_ = true;
    261   completion_callback_ = callback;
    262 
    263   BrowserThread::PostTask(
    264       BrowserThread::UI, FROM_HERE,
    265       base::Bind(&CannedBrowsingDataFileSystemHelper::NotifyOnUIThread, this));
    266 }
    267 
    268 void CannedBrowsingDataFileSystemHelper::NotifyOnUIThread() {
    269   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    270   DCHECK(is_fetching_);
    271   completion_callback_.Run(file_system_info_);
    272   completion_callback_.Reset();
    273   is_fetching_ = false;
    274 }
    275