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