[refactor] More post-NSS WebCrypto cleanups (utility functions).
[chromium-blink-merge.git] / content / browser / cache_storage / cache_storage_manager.cc
blob939797d71e82fea692ae8edb64bec21e43d1af8c
1 // Copyright 2014 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.
5 #include "content/browser/cache_storage/cache_storage_manager.h"
7 #include <map>
8 #include <string>
10 #include "base/bind.h"
11 #include "base/files/file_enumerator.h"
12 #include "base/files/file_util.h"
13 #include "base/id_map.h"
14 #include "base/sha1.h"
15 #include "base/stl_util.h"
16 #include "base/strings/string_number_conversions.h"
17 #include "base/strings/string_util.h"
18 #include "base/time/time.h"
19 #include "content/browser/cache_storage/cache_storage.h"
20 #include "content/browser/cache_storage/cache_storage.pb.h"
21 #include "content/browser/cache_storage/cache_storage_quota_client.h"
22 #include "content/browser/service_worker/service_worker_context_core.h"
23 #include "content/public/browser/browser_thread.h"
24 #include "net/base/net_util.h"
25 #include "storage/browser/quota/quota_manager_proxy.h"
26 #include "storage/common/database/database_identifier.h"
27 #include "storage/common/quota/quota_status_code.h"
28 #include "url/gurl.h"
30 namespace content {
32 namespace {
34 bool DeleteDir(const base::FilePath& path) {
35 return base::DeleteFile(path, true /* recursive */);
38 void DeleteOriginDidDeleteDir(
39 const storage::QuotaClient::DeletionCallback& callback,
40 bool rv) {
41 DCHECK_CURRENTLY_ON(BrowserThread::IO);
43 callback.Run(rv ? storage::kQuotaStatusOk : storage::kQuotaErrorAbort);
46 std::set<GURL> ListOriginsOnDisk(base::FilePath root_path) {
47 std::set<GURL> origins;
48 base::FileEnumerator file_enum(root_path, false /* recursive */,
49 base::FileEnumerator::DIRECTORIES);
51 base::FilePath path;
52 while (!(path = file_enum.Next()).empty()) {
53 std::string protobuf;
54 base::ReadFileToString(path.AppendASCII(CacheStorage::kIndexFileName),
55 &protobuf);
57 CacheStorageIndex index;
58 if (index.ParseFromString(protobuf)) {
59 if (index.has_origin())
60 origins.insert(GURL(index.origin()));
64 return origins;
67 std::vector<CacheStorageUsageInfo> GetAllOriginsUsageOnTaskRunner(
68 const base::FilePath root_path) {
69 std::vector<CacheStorageUsageInfo> entries;
70 const std::set<GURL> origins = ListOriginsOnDisk(root_path);
71 entries.reserve(origins.size());
72 for (const GURL& origin : origins) {
73 base::FilePath path =
74 CacheStorageManager::ConstructOriginPath(root_path, origin);
75 int64 size = base::ComputeDirectorySize(path);
76 base::File::Info file_info;
77 base::Time last_modified;
78 if (base::GetFileInfo(path, &file_info))
79 last_modified = file_info.last_modified;
80 entries.push_back(CacheStorageUsageInfo(origin, size, last_modified));
82 return entries;
85 void GetOriginsForHostDidListOrigins(
86 const std::string& host,
87 const storage::QuotaClient::GetOriginsCallback& callback,
88 const std::set<GURL>& origins) {
89 std::set<GURL> out_origins;
90 for (const GURL& origin : origins) {
91 if (host == net::GetHostOrSpecFromURL(origin))
92 out_origins.insert(origin);
94 callback.Run(out_origins);
97 void EmptyQuotaStatusCallback(storage::QuotaStatusCode code) {}
99 } // namespace
101 // static
102 scoped_ptr<CacheStorageManager> CacheStorageManager::Create(
103 const base::FilePath& path,
104 const scoped_refptr<base::SequencedTaskRunner>& cache_task_runner,
105 const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy) {
106 base::FilePath root_path = path;
107 if (!path.empty()) {
108 root_path = path.Append(ServiceWorkerContextCore::kServiceWorkerDirectory)
109 .AppendASCII("CacheStorage");
112 return make_scoped_ptr(new CacheStorageManager(root_path, cache_task_runner,
113 quota_manager_proxy));
116 // static
117 scoped_ptr<CacheStorageManager> CacheStorageManager::Create(
118 CacheStorageManager* old_manager) {
119 scoped_ptr<CacheStorageManager> manager(new CacheStorageManager(
120 old_manager->root_path(), old_manager->cache_task_runner(),
121 old_manager->quota_manager_proxy_.get()));
122 // These values may be NULL, in which case this will be called again later by
123 // the dispatcher host per usual.
124 manager->SetBlobParametersForCache(old_manager->url_request_context_getter(),
125 old_manager->blob_storage_context());
126 return manager.Pass();
129 CacheStorageManager::~CacheStorageManager() {
130 DCHECK_CURRENTLY_ON(BrowserThread::IO);
131 for (CacheStorageMap::iterator it = cache_storage_map_.begin();
132 it != cache_storage_map_.end(); ++it) {
133 delete it->second;
137 void CacheStorageManager::OpenCache(
138 const GURL& origin,
139 const std::string& cache_name,
140 const CacheStorage::CacheAndErrorCallback& callback) {
141 DCHECK_CURRENTLY_ON(BrowserThread::IO);
143 CacheStorage* cache_storage = FindOrCreateCacheStorage(origin);
145 cache_storage->OpenCache(cache_name, callback);
148 void CacheStorageManager::HasCache(
149 const GURL& origin,
150 const std::string& cache_name,
151 const CacheStorage::BoolAndErrorCallback& callback) {
152 DCHECK_CURRENTLY_ON(BrowserThread::IO);
154 CacheStorage* cache_storage = FindOrCreateCacheStorage(origin);
155 cache_storage->HasCache(cache_name, callback);
158 void CacheStorageManager::DeleteCache(
159 const GURL& origin,
160 const std::string& cache_name,
161 const CacheStorage::BoolAndErrorCallback& callback) {
162 DCHECK_CURRENTLY_ON(BrowserThread::IO);
164 CacheStorage* cache_storage = FindOrCreateCacheStorage(origin);
165 cache_storage->DeleteCache(cache_name, callback);
168 void CacheStorageManager::EnumerateCaches(
169 const GURL& origin,
170 const CacheStorage::StringsAndErrorCallback& callback) {
171 DCHECK_CURRENTLY_ON(BrowserThread::IO);
173 CacheStorage* cache_storage = FindOrCreateCacheStorage(origin);
175 cache_storage->EnumerateCaches(callback);
178 void CacheStorageManager::MatchCache(
179 const GURL& origin,
180 const std::string& cache_name,
181 scoped_ptr<ServiceWorkerFetchRequest> request,
182 const CacheStorageCache::ResponseCallback& callback) {
183 CacheStorage* cache_storage = FindOrCreateCacheStorage(origin);
185 cache_storage->MatchCache(cache_name, request.Pass(), callback);
188 void CacheStorageManager::MatchAllCaches(
189 const GURL& origin,
190 scoped_ptr<ServiceWorkerFetchRequest> request,
191 const CacheStorageCache::ResponseCallback& callback) {
192 CacheStorage* cache_storage = FindOrCreateCacheStorage(origin);
194 cache_storage->MatchAllCaches(request.Pass(), callback);
197 void CacheStorageManager::SetBlobParametersForCache(
198 const scoped_refptr<net::URLRequestContextGetter>& request_context_getter,
199 base::WeakPtr<storage::BlobStorageContext> blob_storage_context) {
200 DCHECK_CURRENTLY_ON(BrowserThread::IO);
201 DCHECK(cache_storage_map_.empty());
202 DCHECK(!request_context_getter_ ||
203 request_context_getter_.get() == request_context_getter.get());
204 DCHECK(!blob_context_ || blob_context_.get() == blob_storage_context.get());
205 request_context_getter_ = request_context_getter;
206 blob_context_ = blob_storage_context;
209 void CacheStorageManager::GetAllOriginsUsage(
210 const CacheStorageContext::GetUsageInfoCallback& callback) {
211 DCHECK_CURRENTLY_ON(BrowserThread::IO);
213 if (IsMemoryBacked()) {
214 std::vector<CacheStorageUsageInfo> entries;
215 entries.reserve(cache_storage_map_.size());
216 for (const auto& origin_details : cache_storage_map_) {
217 entries.push_back(CacheStorageUsageInfo(
218 origin_details.first, origin_details.second->MemoryBackedSize(),
219 base::Time()));
221 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
222 base::Bind(callback, entries));
223 return;
226 PostTaskAndReplyWithResult(
227 cache_task_runner_.get(), FROM_HERE,
228 base::Bind(&GetAllOriginsUsageOnTaskRunner, root_path_),
229 base::Bind(callback));
232 void CacheStorageManager::GetOriginUsage(
233 const GURL& origin_url,
234 const storage::QuotaClient::GetUsageCallback& callback) {
235 DCHECK_CURRENTLY_ON(BrowserThread::IO);
237 if (IsMemoryBacked()) {
238 int64 usage = 0;
239 if (ContainsKey(cache_storage_map_, origin_url))
240 usage = cache_storage_map_[origin_url]->MemoryBackedSize();
241 callback.Run(usage);
242 return;
245 MigrateOrigin(origin_url);
246 PostTaskAndReplyWithResult(
247 cache_task_runner_.get(), FROM_HERE,
248 base::Bind(base::ComputeDirectorySize,
249 ConstructOriginPath(root_path_, origin_url)),
250 base::Bind(callback));
253 void CacheStorageManager::GetOrigins(
254 const storage::QuotaClient::GetOriginsCallback& callback) {
255 DCHECK_CURRENTLY_ON(BrowserThread::IO);
257 if (IsMemoryBacked()) {
258 std::set<GURL> origins;
259 for (const auto& key_value : cache_storage_map_)
260 origins.insert(key_value.first);
262 callback.Run(origins);
263 return;
266 PostTaskAndReplyWithResult(cache_task_runner_.get(), FROM_HERE,
267 base::Bind(&ListOriginsOnDisk, root_path_),
268 base::Bind(callback));
271 void CacheStorageManager::GetOriginsForHost(
272 const std::string& host,
273 const storage::QuotaClient::GetOriginsCallback& callback) {
274 DCHECK_CURRENTLY_ON(BrowserThread::IO);
276 if (IsMemoryBacked()) {
277 std::set<GURL> origins;
278 for (const auto& key_value : cache_storage_map_) {
279 if (host == net::GetHostOrSpecFromURL(key_value.first))
280 origins.insert(key_value.first);
282 callback.Run(origins);
283 return;
286 PostTaskAndReplyWithResult(
287 cache_task_runner_.get(), FROM_HERE,
288 base::Bind(&ListOriginsOnDisk, root_path_),
289 base::Bind(&GetOriginsForHostDidListOrigins, host, callback));
292 void CacheStorageManager::DeleteOriginData(
293 const GURL& origin,
294 const storage::QuotaClient::DeletionCallback& callback) {
295 DCHECK_CURRENTLY_ON(BrowserThread::IO);
297 CacheStorage* cache_storage = FindOrCreateCacheStorage(origin);
298 cache_storage_map_.erase(origin);
299 cache_storage->CloseAllCaches(
300 base::Bind(&CacheStorageManager::DeleteOriginDidClose, origin, callback,
301 base::Passed(make_scoped_ptr(cache_storage)),
302 weak_ptr_factory_.GetWeakPtr()));
305 void CacheStorageManager::DeleteOriginData(const GURL& origin) {
306 DCHECK_CURRENTLY_ON(BrowserThread::IO);
307 DeleteOriginData(origin, base::Bind(&EmptyQuotaStatusCallback));
310 // static
311 void CacheStorageManager::DeleteOriginDidClose(
312 const GURL& origin,
313 const storage::QuotaClient::DeletionCallback& callback,
314 scoped_ptr<CacheStorage> cache_storage,
315 base::WeakPtr<CacheStorageManager> cache_manager) {
316 // TODO(jkarlin): Deleting the storage leaves any unfinished operations
317 // hanging, resulting in unresolved promises. Fix this by guaranteeing that
318 // callbacks are called in ServiceWorkerStorage.
319 cache_storage.reset();
321 if (!cache_manager) {
322 callback.Run(storage::kQuotaErrorAbort);
323 return;
326 if (cache_manager->IsMemoryBacked()) {
327 callback.Run(storage::kQuotaStatusOk);
328 return;
331 cache_manager->MigrateOrigin(origin);
332 PostTaskAndReplyWithResult(
333 cache_manager->cache_task_runner_.get(), FROM_HERE,
334 base::Bind(&DeleteDir,
335 ConstructOriginPath(cache_manager->root_path_, origin)),
336 base::Bind(&DeleteOriginDidDeleteDir, callback));
339 CacheStorageManager::CacheStorageManager(
340 const base::FilePath& path,
341 const scoped_refptr<base::SequencedTaskRunner>& cache_task_runner,
342 const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy)
343 : root_path_(path),
344 cache_task_runner_(cache_task_runner),
345 quota_manager_proxy_(quota_manager_proxy),
346 weak_ptr_factory_(this) {
347 if (quota_manager_proxy_.get()) {
348 quota_manager_proxy_->RegisterClient(
349 new CacheStorageQuotaClient(weak_ptr_factory_.GetWeakPtr()));
353 CacheStorage* CacheStorageManager::FindOrCreateCacheStorage(
354 const GURL& origin) {
355 DCHECK_CURRENTLY_ON(BrowserThread::IO);
356 DCHECK(request_context_getter_);
357 CacheStorageMap::const_iterator it = cache_storage_map_.find(origin);
358 if (it == cache_storage_map_.end()) {
359 MigrateOrigin(origin);
360 CacheStorage* cache_storage = new CacheStorage(
361 ConstructOriginPath(root_path_, origin), IsMemoryBacked(),
362 cache_task_runner_.get(), request_context_getter_, quota_manager_proxy_,
363 blob_context_, origin);
364 // The map owns fetch_stores.
365 cache_storage_map_.insert(std::make_pair(origin, cache_storage));
366 return cache_storage;
368 return it->second;
371 // static
372 base::FilePath CacheStorageManager::ConstructLegacyOriginPath(
373 const base::FilePath& root_path,
374 const GURL& origin) {
375 const std::string origin_hash = base::SHA1HashString(origin.spec());
376 const std::string origin_hash_hex = base::ToLowerASCII(
377 base::HexEncode(origin_hash.c_str(), origin_hash.length()));
378 return root_path.AppendASCII(origin_hash_hex);
381 // static
382 base::FilePath CacheStorageManager::ConstructOriginPath(
383 const base::FilePath& root_path,
384 const GURL& origin) {
385 const std::string identifier = storage::GetIdentifierFromOrigin(origin);
386 const std::string origin_hash = base::SHA1HashString(identifier);
387 const std::string origin_hash_hex = base::ToLowerASCII(
388 base::HexEncode(origin_hash.c_str(), origin_hash.length()));
389 return root_path.AppendASCII(origin_hash_hex);
392 // Migrate from old origin-based path to storage identifier-based path.
393 // TODO(jsbell); Remove after a few releases.
394 void CacheStorageManager::MigrateOrigin(const GURL& origin) {
395 if (IsMemoryBacked())
396 return;
397 base::FilePath old_path = ConstructLegacyOriginPath(root_path_, origin);
398 base::FilePath new_path = ConstructOriginPath(root_path_, origin);
399 cache_task_runner_->PostTask(
400 FROM_HERE, base::Bind(&MigrateOriginOnTaskRunner, old_path, new_path));
403 // static
404 void CacheStorageManager::MigrateOriginOnTaskRunner(
405 const base::FilePath& old_path,
406 const base::FilePath& new_path) {
407 if (base::PathExists(old_path)) {
408 if (!base::PathExists(new_path))
409 base::Move(old_path, new_path);
410 base::DeleteFile(old_path, /*recursive*/ true);
414 } // namespace content