Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / content / browser / cache_storage / cache_storage_manager.cc
blobcc13c443a3c41d4c9fbf143a13e6e68e1b676979
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/strings/string_number_conversions.h"
16 #include "base/strings/string_util.h"
17 #include "content/browser/cache_storage/cache_storage.h"
18 #include "content/browser/cache_storage/cache_storage.pb.h"
19 #include "content/browser/cache_storage/cache_storage_quota_client.h"
20 #include "content/browser/service_worker/service_worker_context_core.h"
21 #include "content/public/browser/browser_thread.h"
22 #include "net/base/net_util.h"
23 #include "storage/browser/quota/quota_manager_proxy.h"
24 #include "storage/common/database/database_identifier.h"
25 #include "storage/common/quota/quota_status_code.h"
26 #include "url/gurl.h"
28 namespace content {
30 namespace {
32 bool DeleteDir(const base::FilePath& path) {
33 return base::DeleteFile(path, true /* recursive */);
36 void DeleteOriginDidDeleteDir(
37 const storage::QuotaClient::DeletionCallback& callback,
38 bool rv) {
39 DCHECK_CURRENTLY_ON(BrowserThread::IO);
41 callback.Run(rv ? storage::kQuotaStatusOk : storage::kQuotaErrorAbort);
44 std::set<GURL> ListOriginsOnDisk(base::FilePath root_path_) {
45 std::set<GURL> origins;
46 base::FileEnumerator file_enum(root_path_, false /* recursive */,
47 base::FileEnumerator::DIRECTORIES);
49 base::FilePath path;
50 while (!(path = file_enum.Next()).empty()) {
51 std::string protobuf;
52 base::ReadFileToString(path.AppendASCII(CacheStorage::kIndexFileName),
53 &protobuf);
55 CacheStorageIndex index;
56 if (index.ParseFromString(protobuf)) {
57 if (index.has_origin())
58 origins.insert(GURL(index.origin()));
62 return origins;
65 void GetOriginsForHostDidListOrigins(
66 const std::string& host,
67 const storage::QuotaClient::GetOriginsCallback& callback,
68 const std::set<GURL>& origins) {
69 std::set<GURL> out_origins;
70 for (const GURL& origin : origins) {
71 if (host == net::GetHostOrSpecFromURL(origin))
72 out_origins.insert(origin);
74 callback.Run(out_origins);
77 } // namespace
79 // static
80 scoped_ptr<CacheStorageManager> CacheStorageManager::Create(
81 const base::FilePath& path,
82 const scoped_refptr<base::SequencedTaskRunner>& cache_task_runner,
83 const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy) {
84 base::FilePath root_path = path;
85 if (!path.empty()) {
86 root_path = path.Append(ServiceWorkerContextCore::kServiceWorkerDirectory)
87 .AppendASCII("CacheStorage");
90 return make_scoped_ptr(new CacheStorageManager(root_path, cache_task_runner,
91 quota_manager_proxy));
94 // static
95 scoped_ptr<CacheStorageManager> CacheStorageManager::Create(
96 CacheStorageManager* old_manager) {
97 scoped_ptr<CacheStorageManager> manager(new CacheStorageManager(
98 old_manager->root_path(), old_manager->cache_task_runner(),
99 old_manager->quota_manager_proxy_.get()));
100 // These values may be NULL, in which case this will be called again later by
101 // the dispatcher host per usual.
102 manager->SetBlobParametersForCache(old_manager->url_request_context_getter(),
103 old_manager->blob_storage_context());
104 return manager.Pass();
107 CacheStorageManager::~CacheStorageManager() {
108 DCHECK_CURRENTLY_ON(BrowserThread::IO);
109 for (CacheStorageMap::iterator it = cache_storage_map_.begin();
110 it != cache_storage_map_.end(); ++it) {
111 delete it->second;
115 void CacheStorageManager::OpenCache(
116 const GURL& origin,
117 const std::string& cache_name,
118 const CacheStorage::CacheAndErrorCallback& callback) {
119 DCHECK_CURRENTLY_ON(BrowserThread::IO);
121 CacheStorage* cache_storage = FindOrCreateCacheStorage(origin);
123 cache_storage->OpenCache(cache_name, callback);
126 void CacheStorageManager::HasCache(
127 const GURL& origin,
128 const std::string& cache_name,
129 const CacheStorage::BoolAndErrorCallback& callback) {
130 DCHECK_CURRENTLY_ON(BrowserThread::IO);
132 CacheStorage* cache_storage = FindOrCreateCacheStorage(origin);
133 cache_storage->HasCache(cache_name, callback);
136 void CacheStorageManager::DeleteCache(
137 const GURL& origin,
138 const std::string& cache_name,
139 const CacheStorage::BoolAndErrorCallback& callback) {
140 DCHECK_CURRENTLY_ON(BrowserThread::IO);
142 CacheStorage* cache_storage = FindOrCreateCacheStorage(origin);
143 cache_storage->DeleteCache(cache_name, callback);
146 void CacheStorageManager::EnumerateCaches(
147 const GURL& origin,
148 const CacheStorage::StringsAndErrorCallback& callback) {
149 DCHECK_CURRENTLY_ON(BrowserThread::IO);
151 CacheStorage* cache_storage = FindOrCreateCacheStorage(origin);
153 cache_storage->EnumerateCaches(callback);
156 void CacheStorageManager::MatchCache(
157 const GURL& origin,
158 const std::string& cache_name,
159 scoped_ptr<ServiceWorkerFetchRequest> request,
160 const CacheStorageCache::ResponseCallback& callback) {
161 CacheStorage* cache_storage = FindOrCreateCacheStorage(origin);
163 cache_storage->MatchCache(cache_name, request.Pass(), callback);
166 void CacheStorageManager::MatchAllCaches(
167 const GURL& origin,
168 scoped_ptr<ServiceWorkerFetchRequest> request,
169 const CacheStorageCache::ResponseCallback& callback) {
170 CacheStorage* cache_storage = FindOrCreateCacheStorage(origin);
172 cache_storage->MatchAllCaches(request.Pass(), callback);
175 void CacheStorageManager::SetBlobParametersForCache(
176 const scoped_refptr<net::URLRequestContextGetter>& request_context_getter,
177 base::WeakPtr<storage::BlobStorageContext> blob_storage_context) {
178 DCHECK_CURRENTLY_ON(BrowserThread::IO);
179 DCHECK(cache_storage_map_.empty());
180 DCHECK(!request_context_getter_ ||
181 request_context_getter_.get() == request_context_getter.get());
182 DCHECK(!blob_context_ || blob_context_.get() == blob_storage_context.get());
183 request_context_getter_ = request_context_getter;
184 blob_context_ = blob_storage_context;
187 void CacheStorageManager::GetOriginUsage(
188 const GURL& origin_url,
189 const storage::QuotaClient::GetUsageCallback& callback) {
190 DCHECK_CURRENTLY_ON(BrowserThread::IO);
192 if (IsMemoryBacked()) {
193 int64 sum = 0;
194 for (const auto& key_value : cache_storage_map_)
195 sum += key_value.second->MemoryBackedSize();
196 callback.Run(sum);
197 return;
200 MigrateOrigin(origin_url);
201 PostTaskAndReplyWithResult(
202 cache_task_runner_.get(), FROM_HERE,
203 base::Bind(base::ComputeDirectorySize,
204 ConstructOriginPath(root_path_, origin_url)),
205 base::Bind(callback));
208 void CacheStorageManager::GetOrigins(
209 const storage::QuotaClient::GetOriginsCallback& callback) {
210 DCHECK_CURRENTLY_ON(BrowserThread::IO);
212 if (IsMemoryBacked()) {
213 std::set<GURL> origins;
214 for (const auto& key_value : cache_storage_map_)
215 origins.insert(key_value.first);
217 callback.Run(origins);
218 return;
221 PostTaskAndReplyWithResult(cache_task_runner_.get(), FROM_HERE,
222 base::Bind(&ListOriginsOnDisk, root_path_),
223 base::Bind(callback));
226 void CacheStorageManager::GetOriginsForHost(
227 const std::string& host,
228 const storage::QuotaClient::GetOriginsCallback& callback) {
229 DCHECK_CURRENTLY_ON(BrowserThread::IO);
231 if (IsMemoryBacked()) {
232 std::set<GURL> origins;
233 for (const auto& key_value : cache_storage_map_) {
234 if (host == net::GetHostOrSpecFromURL(key_value.first))
235 origins.insert(key_value.first);
237 callback.Run(origins);
238 return;
241 PostTaskAndReplyWithResult(
242 cache_task_runner_.get(), FROM_HERE,
243 base::Bind(&ListOriginsOnDisk, root_path_),
244 base::Bind(&GetOriginsForHostDidListOrigins, host, callback));
247 void CacheStorageManager::DeleteOriginData(
248 const GURL& origin,
249 const storage::QuotaClient::DeletionCallback& callback) {
250 DCHECK_CURRENTLY_ON(BrowserThread::IO);
252 CacheStorage* cache_storage = FindOrCreateCacheStorage(origin);
253 cache_storage_map_.erase(origin);
254 cache_storage->CloseAllCaches(
255 base::Bind(&CacheStorageManager::DeleteOriginDidClose, origin, callback,
256 base::Passed(make_scoped_ptr(cache_storage)),
257 weak_ptr_factory_.GetWeakPtr()));
260 // static
261 void CacheStorageManager::DeleteOriginDidClose(
262 const GURL& origin,
263 const storage::QuotaClient::DeletionCallback& callback,
264 scoped_ptr<CacheStorage> cache_storage,
265 base::WeakPtr<CacheStorageManager> cache_manager) {
266 // TODO(jkarlin): Deleting the storage leaves any unfinished operations
267 // hanging, resulting in unresolved promises. Fix this by guaranteeing that
268 // callbacks are called in ServiceWorkerStorage.
269 cache_storage.reset();
271 if (!cache_manager) {
272 callback.Run(storage::kQuotaErrorAbort);
273 return;
276 if (cache_manager->IsMemoryBacked()) {
277 callback.Run(storage::kQuotaStatusOk);
278 return;
281 cache_manager->MigrateOrigin(origin);
282 PostTaskAndReplyWithResult(
283 cache_manager->cache_task_runner_.get(), FROM_HERE,
284 base::Bind(&DeleteDir,
285 ConstructOriginPath(cache_manager->root_path_, origin)),
286 base::Bind(&DeleteOriginDidDeleteDir, callback));
289 CacheStorageManager::CacheStorageManager(
290 const base::FilePath& path,
291 const scoped_refptr<base::SequencedTaskRunner>& cache_task_runner,
292 const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy)
293 : root_path_(path),
294 cache_task_runner_(cache_task_runner),
295 quota_manager_proxy_(quota_manager_proxy),
296 weak_ptr_factory_(this) {
297 if (quota_manager_proxy_.get()) {
298 quota_manager_proxy_->RegisterClient(
299 new CacheStorageQuotaClient(weak_ptr_factory_.GetWeakPtr()));
303 CacheStorage* CacheStorageManager::FindOrCreateCacheStorage(
304 const GURL& origin) {
305 DCHECK_CURRENTLY_ON(BrowserThread::IO);
306 DCHECK(request_context_getter_);
307 CacheStorageMap::const_iterator it = cache_storage_map_.find(origin);
308 if (it == cache_storage_map_.end()) {
309 MigrateOrigin(origin);
310 CacheStorage* cache_storage = new CacheStorage(
311 ConstructOriginPath(root_path_, origin), IsMemoryBacked(),
312 cache_task_runner_.get(), request_context_getter_, quota_manager_proxy_,
313 blob_context_, origin);
314 // The map owns fetch_stores.
315 cache_storage_map_.insert(std::make_pair(origin, cache_storage));
316 return cache_storage;
318 return it->second;
321 // static
322 base::FilePath CacheStorageManager::ConstructLegacyOriginPath(
323 const base::FilePath& root_path,
324 const GURL& origin) {
325 const std::string origin_hash = base::SHA1HashString(origin.spec());
326 const std::string origin_hash_hex = base::StringToLowerASCII(
327 base::HexEncode(origin_hash.c_str(), origin_hash.length()));
328 return root_path.AppendASCII(origin_hash_hex);
331 // static
332 base::FilePath CacheStorageManager::ConstructOriginPath(
333 const base::FilePath& root_path,
334 const GURL& origin) {
335 const std::string identifier = storage::GetIdentifierFromOrigin(origin);
336 const std::string origin_hash = base::SHA1HashString(identifier);
337 const std::string origin_hash_hex = base::StringToLowerASCII(
338 base::HexEncode(origin_hash.c_str(), origin_hash.length()));
339 return root_path.AppendASCII(origin_hash_hex);
342 // Migrate from old origin-based path to storage identifier-based path.
343 // TODO(jsbell); Remove after a few releases.
344 void CacheStorageManager::MigrateOrigin(const GURL& origin) {
345 if (IsMemoryBacked())
346 return;
347 base::FilePath old_path = ConstructLegacyOriginPath(root_path_, origin);
348 base::FilePath new_path = ConstructOriginPath(root_path_, origin);
349 cache_task_runner_->PostTask(
350 FROM_HERE, base::Bind(&MigrateOriginOnTaskRunner, old_path, new_path));
353 // static
354 void CacheStorageManager::MigrateOriginOnTaskRunner(
355 const base::FilePath& old_path,
356 const base::FilePath& new_path) {
357 if (base::PathExists(old_path)) {
358 if (!base::PathExists(new_path))
359 base::Move(old_path, new_path);
360 base::DeleteFile(old_path, /*recursive*/ true);
364 } // namespace content