Index: content/browser/cache_storage/cache_storage.cc |
diff --git a/content/browser/cache_storage/cache_storage.cc b/content/browser/cache_storage/cache_storage.cc |
index 42f0215b8477c7a4afac97353e844b331c97e3f4..e385480624a3944127e91e5f43b47dedb87d86d4 100644 |
--- a/content/browser/cache_storage/cache_storage.cc |
+++ b/content/browser/cache_storage/cache_storage.cc |
@@ -9,6 +9,7 @@ |
#include "base/barrier_closure.h" |
#include "base/files/file_util.h" |
#include "base/files/memory_mapped_file.h" |
+#include "base/guid.h" |
#include "base/location.h" |
#include "base/memory/ref_counted.h" |
#include "base/metrics/histogram_macros.h" |
@@ -33,6 +34,13 @@ namespace content { |
namespace { |
+std::string HexedHash(const std::string& value) { |
+ std::string value_hash = base::SHA1HashString(value); |
+ std::string valued_hexed_hash = base::ToLowerASCII( |
+ base::HexEncode(value_hash.c_str(), value_hash.length())); |
+ return valued_hexed_hash; |
+} |
+ |
void CloseAllCachesDidCloseCache(const scoped_refptr<CacheStorageCache>& cache, |
const base::Closure& barrier_closure) { |
barrier_closure.Run(); |
@@ -42,8 +50,7 @@ void CloseAllCachesDidCloseCache(const scoped_refptr<CacheStorageCache>& cache, |
const char CacheStorage::kIndexFileName[] = "index.txt"; |
-// Handles the loading and clean up of CacheStorageCache objects. The |
-// callback of every public method is guaranteed to be called. |
+// Handles the loading and clean up of CacheStorageCache objects. |
class CacheStorage::CacheLoader { |
public: |
typedef base::Callback<void(const scoped_refptr<CacheStorageCache>&)> |
@@ -74,8 +81,8 @@ class CacheStorage::CacheLoader { |
const std::string& cache_name) = 0; |
// Deletes any pre-existing cache of the same name and then loads it. |
- virtual void CreateCache(const std::string& cache_name, |
- const CacheCallback& callback) = 0; |
+ virtual void PrepareNewCacheDestination(const std::string& cache_name, |
+ const CacheCallback& callback) = 0; |
// After the backend has been deleted, do any extra house keeping such as |
// removing the cache's directory. |
@@ -122,8 +129,8 @@ class CacheStorage::MemoryLoader : public CacheStorage::CacheLoader { |
origin_, request_context_getter_, quota_manager_proxy_, blob_context_); |
} |
- void CreateCache(const std::string& cache_name, |
- const CacheCallback& callback) override { |
+ void PrepareNewCacheDestination(const std::string& cache_name, |
+ const CacheCallback& callback) override { |
scoped_refptr<CacheStorageCache> cache = CreateCache(cache_name); |
cache_refs_.insert(std::make_pair(cache_name, cache)); |
callback.Run(cache); |
@@ -177,56 +184,61 @@ class CacheStorage::SimpleCacheLoader : public CacheStorage::CacheLoader { |
scoped_refptr<CacheStorageCache> CreateCache( |
const std::string& cache_name) override { |
DCHECK_CURRENTLY_ON(BrowserThread::IO); |
+ DCHECK(ContainsKey(cache_name_to_cache_dir_, cache_name)); |
+ std::string cache_dir = cache_name_to_cache_dir_[cache_name]; |
+ base::FilePath cache_path = origin_path_.AppendASCII(cache_dir); |
return CacheStorageCache::CreatePersistentCache( |
- origin_, CreatePersistentCachePath(origin_path_, cache_name), |
- request_context_getter_, quota_manager_proxy_, blob_context_); |
+ origin_, cache_path, request_context_getter_, quota_manager_proxy_, |
+ blob_context_); |
} |
- void CreateCache(const std::string& cache_name, |
- const CacheCallback& callback) override { |
+ void PrepareNewCacheDestination(const std::string& cache_name, |
+ const CacheCallback& callback) override { |
DCHECK_CURRENTLY_ON(BrowserThread::IO); |
- // 1. Delete the cache's directory if it exists. |
- // (CreateCacheDeleteFilesInPool) |
- // 2. Load the cache. (LoadCreateDirectoryInPool) |
- |
- base::FilePath cache_path = |
- CreatePersistentCachePath(origin_path_, cache_name); |
- |
PostTaskAndReplyWithResult( |
cache_task_runner_.get(), FROM_HERE, |
- base::Bind(&SimpleCacheLoader::CreateCachePrepDirInPool, cache_path), |
- base::Bind(&SimpleCacheLoader::CreateCachePreppedDir, cache_name, |
- callback, weak_ptr_factory_.GetWeakPtr())); |
+ base::Bind(&SimpleCacheLoader::PrepareNewCacheDirectoryInPool, |
+ origin_path_), |
+ base::Bind(&SimpleCacheLoader::PrepareNewCacheCreateCache, |
+ weak_ptr_factory_.GetWeakPtr(), cache_name, callback)); |
} |
- static bool CreateCachePrepDirInPool(const base::FilePath& cache_path) { |
- if (base::PathExists(cache_path)) |
- base::DeleteFile(cache_path, /* recursive */ true); |
- return base::CreateDirectory(cache_path); |
+ // Runs on the cache_task_runner_. |
+ static std::string PrepareNewCacheDirectoryInPool( |
+ const base::FilePath& origin_path) { |
+ std::string cache_dir; |
+ base::FilePath cache_path; |
+ do { |
+ cache_dir = base::GenerateGUID(); |
+ cache_path = origin_path.AppendASCII(cache_dir); |
+ } while (base::PathExists(cache_path)); |
+ |
+ return base::CreateDirectory(cache_path) ? cache_dir : ""; |
} |
- static void CreateCachePreppedDir(const std::string& cache_name, |
- const CacheCallback& callback, |
- base::WeakPtr<SimpleCacheLoader> loader, |
- bool success) { |
- if (!success || !loader) { |
+ void PrepareNewCacheCreateCache(const std::string& cache_name, |
+ const CacheCallback& callback, |
+ const std::string& cache_dir) { |
+ if (cache_dir.empty()) { |
callback.Run(scoped_refptr<CacheStorageCache>()); |
return; |
} |
- callback.Run(loader->CreateCache(cache_name)); |
+ cache_name_to_cache_dir_[cache_name] = cache_dir; |
+ callback.Run(CreateCache(cache_name)); |
} |
void CleanUpDeletedCache(const std::string& cache_name, |
const BoolCallback& callback) override { |
DCHECK_CURRENTLY_ON(BrowserThread::IO); |
- |
- // 1. Delete the cache's directory. (CleanUpDeleteCacheDirInPool) |
+ DCHECK(ContainsKey(cache_name_to_cache_dir_, cache_name)); |
base::FilePath cache_path = |
- CreatePersistentCachePath(origin_path_, cache_name); |
+ origin_path_.AppendASCII(cache_name_to_cache_dir_[cache_name]); |
+ cache_name_to_cache_dir_.erase(cache_name); |
+ |
cache_task_runner_->PostTask( |
FROM_HERE, |
base::Bind(&SimpleCacheLoader::CleanUpDeleteCacheDirInPool, cache_path, |
@@ -252,8 +264,11 @@ class CacheStorage::SimpleCacheLoader : public CacheStorage::CacheLoader { |
index.set_origin(origin_.spec()); |
for (size_t i = 0u, max = cache_names.size(); i < max; ++i) { |
+ DCHECK(ContainsKey(cache_name_to_cache_dir_, cache_names[i])); |
+ |
CacheStorageIndex::Cache* index_cache = index.add_cache(); |
index_cache->set_name(cache_names[i]); |
+ index_cache->set_cache_dir(cache_name_to_cache_dir_[cache_names[i]]); |
} |
std::string serialized; |
@@ -297,35 +312,26 @@ class CacheStorage::SimpleCacheLoader : public CacheStorage::CacheLoader { |
base::FilePath index_path = |
origin_path_.AppendASCII(CacheStorage::kIndexFileName); |
- cache_task_runner_->PostTask( |
- FROM_HERE, base::Bind(&SimpleCacheLoader::LoadIndexReadFileInPool, |
- index_path, base::Passed(names.Pass()), callback, |
- base::ThreadTaskRunnerHandle::Get())); |
- } |
- |
- static void LoadIndexReadFileInPool( |
- const base::FilePath& index_path, |
- scoped_ptr<std::vector<std::string>> names, |
- const StringVectorCallback& callback, |
- const scoped_refptr<base::SingleThreadTaskRunner>& original_task_runner) { |
- std::string body; |
- base::ReadFileToString(index_path, &body); |
- |
- original_task_runner->PostTask( |
- FROM_HERE, base::Bind(&SimpleCacheLoader::LoadIndexDidReadFile, |
- base::Passed(names.Pass()), callback, body)); |
+ PostTaskAndReplyWithResult( |
+ cache_task_runner_.get(), FROM_HERE, |
+ base::Bind(&SimpleCacheLoader::ReadAndMigrateIndexInPool, index_path), |
+ base::Bind(&SimpleCacheLoader::LoadIndexDidReadFile, |
+ weak_ptr_factory_.GetWeakPtr(), base::Passed(&names), |
+ callback)); |
} |
- static void LoadIndexDidReadFile(scoped_ptr<std::vector<std::string>> names, |
- const StringVectorCallback& callback, |
- const std::string& serialized) { |
+ void LoadIndexDidReadFile(scoped_ptr<std::vector<std::string>> names, |
+ const StringVectorCallback& callback, |
+ const std::string& serialized) { |
DCHECK_CURRENTLY_ON(BrowserThread::IO); |
CacheStorageIndex index; |
if (index.ParseFromString(serialized)) { |
for (int i = 0, max = index.cache_size(); i < max; ++i) { |
const CacheStorageIndex::Cache& cache = index.cache(i); |
+ DCHECK(cache.has_cache_dir()); |
names->push_back(cache.name()); |
+ cache_name_to_cache_dir_[cache.name()] = cache.cache_dir(); |
} |
} |
@@ -335,22 +341,72 @@ class CacheStorage::SimpleCacheLoader : public CacheStorage::CacheLoader { |
} |
private: |
+ friend class MigratedLegacyCacheDirectoryNameTest; |
~SimpleCacheLoader() override {} |
- static std::string HexedHash(const std::string& value) { |
- std::string value_hash = base::SHA1HashString(value); |
- std::string valued_hexed_hash = base::ToLowerASCII( |
- base::HexEncode(value_hash.c_str(), value_hash.length())); |
- return valued_hexed_hash; |
+ // Runs on cache_task_runner_ |
+ static std::string MigrateCachesIfNecessaryInPool( |
+ const std::string& body, |
+ const base::FilePath& index_path) { |
+ CacheStorageIndex index; |
+ if (!index.ParseFromString(body)) |
+ return body; |
+ |
+ base::FilePath origin_path = index_path.DirName(); |
+ bool index_is_dirty = false; |
+ const std::string kBadIndexState(""); |
+ |
+ // Look for caches that have no cache_dir. Give any such caches a directory |
+ // with a random name and move them there. Then, rewrite the index file. |
+ for (int i = 0, max = index.cache_size(); i < max; ++i) { |
+ const CacheStorageIndex::Cache& cache = index.cache(i); |
+ if (!cache.has_cache_dir()) { |
+ // Find a new home for the cache. |
+ base::FilePath legacy_cache_path = |
+ origin_path.AppendASCII(HexedHash(cache.name())); |
+ std::string cache_dir; |
+ base::FilePath cache_path; |
+ do { |
+ cache_dir = base::GenerateGUID(); |
+ cache_path = origin_path.AppendASCII(cache_dir); |
+ } while (base::PathExists(cache_path)); |
+ |
+ if (!base::Move(legacy_cache_path, cache_path)) { |
+ // If the move fails then the cache is in a bad state. Return an empty |
+ // index so that the CacheStorage can start fresh. The unreferenced |
+ // caches will be discarded later in initialization. |
+ return kBadIndexState; |
+ } |
+ |
+ index.mutable_cache(i)->set_cache_dir(cache_dir); |
+ index_is_dirty = true; |
+ } |
+ } |
+ |
+ if (index_is_dirty) { |
+ std::string new_body; |
+ if (!index.SerializeToString(&new_body)) |
+ return kBadIndexState; |
+ if (base::WriteFile(index_path, new_body.c_str(), new_body.size()) != |
+ base::checked_cast<int>(new_body.size())) |
+ return kBadIndexState; |
+ return new_body; |
+ } |
+ |
+ return body; |
} |
- static base::FilePath CreatePersistentCachePath( |
- const base::FilePath& origin_path, |
- const std::string& cache_name) { |
- return origin_path.AppendASCII(HexedHash(cache_name)); |
+ // Runs on cache_task_runner_ |
+ static std::string ReadAndMigrateIndexInPool( |
+ const base::FilePath& index_path) { |
+ std::string body; |
+ base::ReadFileToString(index_path, &body); |
+ |
+ return MigrateCachesIfNecessaryInPool(body, index_path); |
} |
const base::FilePath origin_path_; |
+ std::map<std::string, std::string> cache_name_to_cache_dir_; |
base::WeakPtrFactory<SimpleCacheLoader> weak_ptr_factory_; |
}; |
@@ -569,7 +625,7 @@ void CacheStorage::OpenCacheImpl(const std::string& cache_name, |
return; |
} |
- cache_loader_->CreateCache( |
+ cache_loader_->PrepareNewCacheDestination( |
cache_name, base::Bind(&CacheStorage::CreateCacheDidCreateCache, |
weak_factory_.GetWeakPtr(), cache_name, callback)); |
} |
@@ -612,8 +668,7 @@ void CacheStorage::CreateCacheDidWriteIndex( |
void CacheStorage::HasCacheImpl(const std::string& cache_name, |
const BoolAndErrorCallback& callback) { |
- bool has_cache = cache_map_.find(cache_name) != cache_map_.end(); |
- |
+ bool has_cache = ContainsKey(cache_map_, cache_name); |
callback.Run(has_cache, CACHE_STORAGE_OK); |
} |