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_indexed_db_helper.h"
      6 
      7 #include <vector>
      8 
      9 #include "base/bind.h"
     10 #include "base/callback.h"
     11 #include "base/compiler_specific.h"
     12 #include "base/memory/scoped_ptr.h"
     13 #include "base/message_loop/message_loop.h"
     14 #include "base/strings/string_util.h"
     15 #include "base/strings/utf_string_conversions.h"
     16 #include "chrome/browser/browsing_data/browsing_data_helper.h"
     17 #include "content/public/browser/browser_thread.h"
     18 #include "content/public/browser/indexed_db_context.h"
     19 
     20 using content::BrowserThread;
     21 using content::IndexedDBContext;
     22 using content::IndexedDBInfo;
     23 
     24 namespace {
     25 
     26 class BrowsingDataIndexedDBHelperImpl : public BrowsingDataIndexedDBHelper {
     27  public:
     28   explicit BrowsingDataIndexedDBHelperImpl(
     29       IndexedDBContext* indexed_db_context);
     30 
     31   virtual void StartFetching(
     32       const base::Callback<void(const std::list<IndexedDBInfo>&)>&
     33           callback) OVERRIDE;
     34   virtual void DeleteIndexedDB(const GURL& origin) OVERRIDE;
     35 
     36  private:
     37   virtual ~BrowsingDataIndexedDBHelperImpl();
     38 
     39   // Enumerates all indexed database files in the IndexedDB thread.
     40   void FetchIndexedDBInfoInIndexedDBThread();
     41   // Notifies the completion callback in the UI thread.
     42   void NotifyInUIThread();
     43   // Delete a single indexed database in the IndexedDB thread.
     44   void DeleteIndexedDBInIndexedDBThread(const GURL& origin);
     45 
     46   scoped_refptr<IndexedDBContext> indexed_db_context_;
     47 
     48   // Access to |indexed_db_info_| is triggered indirectly via the UI thread and
     49   // guarded by |is_fetching_|. This means |indexed_db_info_| is only accessed
     50   // while |is_fetching_| is true. The flag |is_fetching_| is only accessed on
     51   // the UI thread.
     52   // In the context of this class |indexed_db_info_| is only accessed on the
     53   // context's IndexedDB thread.
     54   std::list<IndexedDBInfo> indexed_db_info_;
     55 
     56   // This only mutates on the UI thread.
     57   base::Callback<void(const std::list<IndexedDBInfo>&)> completion_callback_;
     58 
     59   // Indicates whether or not we're currently fetching information:
     60   // it's true when StartFetching() is called in the UI thread, and it's reset
     61   // after we notified the callback in the UI thread.
     62   // This only mutates on the UI thread.
     63   bool is_fetching_;
     64 
     65   DISALLOW_COPY_AND_ASSIGN(BrowsingDataIndexedDBHelperImpl);
     66 };
     67 
     68 BrowsingDataIndexedDBHelperImpl::BrowsingDataIndexedDBHelperImpl(
     69     IndexedDBContext* indexed_db_context)
     70     : indexed_db_context_(indexed_db_context),
     71       is_fetching_(false) {
     72   DCHECK(indexed_db_context_.get());
     73 }
     74 
     75 BrowsingDataIndexedDBHelperImpl::~BrowsingDataIndexedDBHelperImpl() {
     76 }
     77 
     78 void BrowsingDataIndexedDBHelperImpl::StartFetching(
     79     const base::Callback<void(const std::list<IndexedDBInfo>&)>& callback) {
     80   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     81   DCHECK(!is_fetching_);
     82   DCHECK_EQ(false, callback.is_null());
     83 
     84   is_fetching_ = true;
     85   completion_callback_ = callback;
     86   indexed_db_context_->TaskRunner()->PostTask(
     87       FROM_HERE,
     88       base::Bind(
     89           &BrowsingDataIndexedDBHelperImpl::FetchIndexedDBInfoInIndexedDBThread,
     90           this));
     91 }
     92 
     93 void BrowsingDataIndexedDBHelperImpl::DeleteIndexedDB(
     94     const GURL& origin) {
     95   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     96   indexed_db_context_->TaskRunner()->PostTask(
     97       FROM_HERE,
     98       base::Bind(
     99           &BrowsingDataIndexedDBHelperImpl::DeleteIndexedDBInIndexedDBThread,
    100           this,
    101           origin));
    102 }
    103 
    104 void BrowsingDataIndexedDBHelperImpl::FetchIndexedDBInfoInIndexedDBThread() {
    105   DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
    106   std::vector<IndexedDBInfo> origins = indexed_db_context_->GetAllOriginsInfo();
    107   for (std::vector<IndexedDBInfo>::const_iterator iter = origins.begin();
    108        iter != origins.end(); ++iter) {
    109     const IndexedDBInfo& origin = *iter;
    110     if (!BrowsingDataHelper::HasWebScheme(origin.origin_))
    111       continue;  // Non-websafe state is not considered browsing data.
    112 
    113     indexed_db_info_.push_back(origin);
    114   }
    115 
    116   BrowserThread::PostTask(
    117       BrowserThread::UI, FROM_HERE,
    118       base::Bind(&BrowsingDataIndexedDBHelperImpl::NotifyInUIThread, this));
    119 }
    120 
    121 void BrowsingDataIndexedDBHelperImpl::NotifyInUIThread() {
    122   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    123   DCHECK(is_fetching_);
    124   completion_callback_.Run(indexed_db_info_);
    125   completion_callback_.Reset();
    126   is_fetching_ = false;
    127 }
    128 
    129 void BrowsingDataIndexedDBHelperImpl::DeleteIndexedDBInIndexedDBThread(
    130     const GURL& origin) {
    131   DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
    132   indexed_db_context_->DeleteForOrigin(origin);
    133 }
    134 
    135 }  // namespace
    136 
    137 
    138 // static
    139 BrowsingDataIndexedDBHelper* BrowsingDataIndexedDBHelper::Create(
    140     IndexedDBContext* indexed_db_context) {
    141   return new BrowsingDataIndexedDBHelperImpl(indexed_db_context);
    142 }
    143 
    144 CannedBrowsingDataIndexedDBHelper::
    145 PendingIndexedDBInfo::PendingIndexedDBInfo(const GURL& origin,
    146                                            const string16& name)
    147     : origin(origin),
    148       name(name) {
    149 }
    150 
    151 CannedBrowsingDataIndexedDBHelper::
    152 PendingIndexedDBInfo::~PendingIndexedDBInfo() {
    153 }
    154 
    155 bool CannedBrowsingDataIndexedDBHelper::PendingIndexedDBInfo::operator<(
    156     const PendingIndexedDBInfo& other) const {
    157   if (origin == other.origin)
    158     return name < other.name;
    159   return origin < other.origin;
    160 }
    161 
    162 CannedBrowsingDataIndexedDBHelper::CannedBrowsingDataIndexedDBHelper()
    163     : is_fetching_(false) {
    164 }
    165 
    166 CannedBrowsingDataIndexedDBHelper::~CannedBrowsingDataIndexedDBHelper() {}
    167 
    168 CannedBrowsingDataIndexedDBHelper* CannedBrowsingDataIndexedDBHelper::Clone() {
    169   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    170   CannedBrowsingDataIndexedDBHelper* clone =
    171       new CannedBrowsingDataIndexedDBHelper();
    172 
    173   clone->pending_indexed_db_info_ = pending_indexed_db_info_;
    174   clone->indexed_db_info_ = indexed_db_info_;
    175   return clone;
    176 }
    177 
    178 void CannedBrowsingDataIndexedDBHelper::AddIndexedDB(
    179     const GURL& origin, const string16& name) {
    180   if (!BrowsingDataHelper::HasWebScheme(origin))
    181     return;  // Non-websafe state is not considered browsing data.
    182 
    183   pending_indexed_db_info_.insert(PendingIndexedDBInfo(origin, name));
    184 }
    185 
    186 void CannedBrowsingDataIndexedDBHelper::Reset() {
    187   indexed_db_info_.clear();
    188   pending_indexed_db_info_.clear();
    189 }
    190 
    191 bool CannedBrowsingDataIndexedDBHelper::empty() const {
    192   return indexed_db_info_.empty() && pending_indexed_db_info_.empty();
    193 }
    194 
    195 size_t CannedBrowsingDataIndexedDBHelper::GetIndexedDBCount() const {
    196   return pending_indexed_db_info_.size();
    197 }
    198 
    199 const std::set<CannedBrowsingDataIndexedDBHelper::PendingIndexedDBInfo>&
    200 CannedBrowsingDataIndexedDBHelper::GetIndexedDBInfo() const  {
    201   return pending_indexed_db_info_;
    202 }
    203 
    204 void CannedBrowsingDataIndexedDBHelper::StartFetching(
    205     const base::Callback<void(const std::list<IndexedDBInfo>&)>& callback) {
    206   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    207   DCHECK(!is_fetching_);
    208   DCHECK_EQ(false, callback.is_null());
    209 
    210   is_fetching_ = true;
    211   completion_callback_ = callback;
    212 
    213   // We post a task to emulate async fetching behavior.
    214   base::MessageLoop::current()->PostTask(
    215       FROM_HERE,
    216       base::Bind(&CannedBrowsingDataIndexedDBHelper::
    217                      ConvertPendingInfo,
    218                  this));
    219 }
    220 
    221 void CannedBrowsingDataIndexedDBHelper::ConvertPendingInfo() {
    222   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    223   indexed_db_info_.clear();
    224   for (std::set<PendingIndexedDBInfo>::const_iterator
    225        pending_info = pending_indexed_db_info_.begin();
    226        pending_info != pending_indexed_db_info_.end(); ++pending_info) {
    227     IndexedDBInfo info(
    228         pending_info->origin, 0, base::Time(), base::FilePath(), 0);
    229     indexed_db_info_.push_back(info);
    230   }
    231 
    232   completion_callback_.Run(indexed_db_info_);
    233   completion_callback_.Reset();
    234   is_fetching_ = false;
    235 }
    236