| 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..8a7c0c3fa3f45038ccc6fd3aaa266afa503b3d3c 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,17 +34,78 @@ 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();
|
| }
|
|
|
| +std::string MigrateCachesIfNecessaryInPool(const std::string& body,
|
| + const base::FilePath& index_path) {
|
| + CacheStorageIndex index;
|
| + base::FilePath origin_path = index_path.DirName();
|
| +
|
| + if (!index.ParseFromString(body))
|
| + return body;
|
| +
|
| + bool index_is_dirty = false;
|
| +
|
| + // 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))
|
| + return "";
|
| +
|
| + index.mutable_cache(0)->set_cache_dir(cache_dir);
|
| + index_is_dirty = true;
|
| + }
|
| + }
|
| +
|
| + if (index_is_dirty) {
|
| + std::string new_body;
|
| + if (!index.SerializeToString(&new_body))
|
| + return "";
|
| + if (base::WriteFile(index_path, new_body.c_str(), new_body.size()) !=
|
| + base::checked_cast<int>(new_body.size()))
|
| + return "";
|
| + return new_body;
|
| + }
|
| +
|
| + return body;
|
| +}
|
| +
|
| +std::string ReadAndMigrateIndexInPool(const base::FilePath& index_path) {
|
| + std::string body;
|
| + base::ReadFileToString(index_path, &body);
|
| +
|
| + return MigrateCachesIfNecessaryInPool(body, index_path);
|
| +}
|
| +
|
| } // namespace
|
|
|
| +class MigratedLegacyCacheDirectoryNameTest;
|
| +
|
| 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 +136,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 +184,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 +239,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 +319,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 +367,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(&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 +396,11 @@ 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;
|
| - }
|
| -
|
| - static base::FilePath CreatePersistentCachePath(
|
| - const base::FilePath& origin_path,
|
| - const std::string& cache_name) {
|
| - return origin_path.AppendASCII(HexedHash(cache_name));
|
| - }
|
| -
|
| const base::FilePath origin_path_;
|
| + std::map<std::string, std::string> cache_name_to_cache_dir_;
|
|
|
| base::WeakPtrFactory<SimpleCacheLoader> weak_ptr_factory_;
|
| };
|
| @@ -569,7 +619,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 +662,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);
|
| }
|
|
|
|
|