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