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 base::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 base::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