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