Commit e82f0728 authored by jsbell's avatar jsbell Committed by Commit bot

Use "database identifier" rather than raw origin as directory hash input

When we allow non-Service Workers to have access to the Cache Storage
API we will want to match other storage systems and use a database
identifier generated from a Blink SecurityOrigin object, rather than
just the origin URL, as the key for per-origin storage.

This change changes the computation of the directory name on disk (a
hash) from using the origin to a database identifier, in anticipation
of an identifier being passed in after some future CLs.

Existing data is preserved by preceding the uses of the directory name
(open, delete, or enumeration) with a directory rename from the
"legacy" name computed from the origin to the "new" name computed from
the directory identifier. The rename is done by posting a task to the
cache task runner just before the actual task. After a few releases we
remove the migration code.

R=michaeln,jkarlin
BUG=439389

Review URL: https://codereview.chromium.org/1020413002

Cr-Commit-Position: refs/heads/master@{#322055}
parent 58023982
......@@ -21,6 +21,7 @@
#include "content/public/browser/browser_thread.h"
#include "net/base/net_util.h"
#include "storage/browser/quota/quota_manager_proxy.h"
#include "storage/common/database/database_identifier.h"
#include "storage/common/quota/quota_status_code.h"
#include "url/gurl.h"
......@@ -28,14 +29,6 @@ namespace content {
namespace {
base::FilePath ConstructOriginPath(const base::FilePath& root_path,
const GURL& origin) {
std::string origin_hash = base::SHA1HashString(origin.spec());
std::string origin_hash_hex = base::StringToLowerASCII(
base::HexEncode(origin_hash.c_str(), origin_hash.length()));
return root_path.AppendASCII(origin_hash_hex);
}
bool DeleteDir(const base::FilePath& path) {
return base::DeleteFile(path, true /* recursive */);
}
......@@ -214,6 +207,7 @@ void ServiceWorkerCacheStorageManager::GetOriginUsage(
return;
}
MigrateOrigin(origin_url);
PostTaskAndReplyWithResult(
cache_task_runner_.get(),
FROM_HERE,
......@@ -298,6 +292,7 @@ void ServiceWorkerCacheStorageManager::DeleteOriginDidClose(
return;
}
cache_manager->MigrateOrigin(origin);
PostTaskAndReplyWithResult(
cache_manager->cache_task_runner_.get(), FROM_HERE,
base::Bind(&DeleteDir,
......@@ -328,6 +323,7 @@ ServiceWorkerCacheStorageManager::FindOrCreateServiceWorkerCacheManager(
ServiceWorkerCacheStorageMap::const_iterator it =
cache_storage_map_.find(origin);
if (it == cache_storage_map_.end()) {
MigrateOrigin(origin);
ServiceWorkerCacheStorage* cache_storage =
new ServiceWorkerCacheStorage(ConstructOriginPath(root_path_, origin),
IsMemoryBacked(),
......@@ -343,4 +339,47 @@ ServiceWorkerCacheStorageManager::FindOrCreateServiceWorkerCacheManager(
return it->second;
}
// static
base::FilePath ServiceWorkerCacheStorageManager::ConstructLegacyOriginPath(
const base::FilePath& root_path,
const GURL& origin) {
const std::string origin_hash = base::SHA1HashString(origin.spec());
const std::string origin_hash_hex = base::StringToLowerASCII(
base::HexEncode(origin_hash.c_str(), origin_hash.length()));
return root_path.AppendASCII(origin_hash_hex);
}
// static
base::FilePath ServiceWorkerCacheStorageManager::ConstructOriginPath(
const base::FilePath& root_path,
const GURL& origin) {
const std::string identifier = storage::GetIdentifierFromOrigin(origin);
const std::string origin_hash = base::SHA1HashString(identifier);
const std::string origin_hash_hex = base::StringToLowerASCII(
base::HexEncode(origin_hash.c_str(), origin_hash.length()));
return root_path.AppendASCII(origin_hash_hex);
}
// Migrate from old origin-based path to storage identifier-based path.
// TODO(jsbell); Remove after a few releases.
void ServiceWorkerCacheStorageManager::MigrateOrigin(const GURL& origin) {
if (IsMemoryBacked())
return;
base::FilePath old_path = ConstructLegacyOriginPath(root_path_, origin);
base::FilePath new_path = ConstructOriginPath(root_path_, origin);
cache_task_runner_->PostTask(
FROM_HERE, base::Bind(&MigrateOriginOnTaskRunner, old_path, new_path));
}
// static
void ServiceWorkerCacheStorageManager::MigrateOriginOnTaskRunner(
const base::FilePath& old_path,
const base::FilePath& new_path) {
if (base::PathExists(old_path)) {
if (!base::PathExists(new_path))
base::Move(old_path, new_path);
base::DeleteFile(old_path, /*recursive*/ true);
}
}
} // namespace content
......@@ -10,6 +10,7 @@
#include "base/basictypes.h"
#include "base/files/file_path.h"
#include "base/gtest_prod_util.h"
#include "content/browser/service_worker/service_worker_cache_storage.h"
#include "content/common/content_export.h"
#include "storage/browser/quota/quota_client.h"
......@@ -31,7 +32,6 @@ class QuotaManagerProxy;
namespace content {
class ServiceWorkerCacheQuotaClient;
class ServiceWorkerCacheStorageManagerTest;
// Keeps track of a ServiceWorkerCacheStorage per origin. There is one
// ServiceWorkerCacheStorageManager per ServiceWorkerContextCore.
......@@ -87,6 +87,7 @@ class CONTENT_EXPORT ServiceWorkerCacheStorageManager {
private:
friend class ServiceWorkerCacheQuotaClient;
friend class ServiceWorkerCacheStorageManagerTest;
friend class ServiceWorkerCacheStorageMigrationTest;
typedef std::map<GURL, ServiceWorkerCacheStorage*>
ServiceWorkerCacheStorageMap;
......@@ -129,6 +130,21 @@ class CONTENT_EXPORT ServiceWorkerCacheStorageManager {
bool IsMemoryBacked() const { return root_path_.empty(); }
// Map a origin to the path. Exposed for testing.
static base::FilePath ConstructLegacyOriginPath(
const base::FilePath& root_path,
const GURL& origin);
// Map a database identifier (computed from an origin) to the path. Exposed
// for testing.
static base::FilePath ConstructOriginPath(const base::FilePath& root_path,
const GURL& origin);
// Migrate from old origin-based path to storage identifier-based path.
// TODO(jsbell); Remove method and all calls after a few releases.
void MigrateOrigin(const GURL& origin);
static void MigrateOriginOnTaskRunner(const base::FilePath& old_path,
const base::FilePath& new_path);
base::FilePath root_path_;
scoped_refptr<base::SequencedTaskRunner> cache_task_runner_;
......
......@@ -5,9 +5,11 @@
#include "content/browser/service_worker/service_worker_cache_storage_manager.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/message_loop/message_loop_proxy.h"
#include "base/run_loop.h"
#include "base/stl_util.h"
#include "content/browser/fileapi/chrome_blob_storage_context.h"
#include "content/browser/quota/mock_quota_manager_proxy.h"
#include "content/browser/service_worker/service_worker_cache_quota_client.h"
......@@ -567,6 +569,115 @@ TEST_F(ServiceWorkerCacheStorageManagerTest, MemoryBackedSizePersistent) {
EXPECT_EQ(0, cache_storage->MemoryBackedSize());
}
class ServiceWorkerCacheStorageMigrationTest
: public ServiceWorkerCacheStorageManagerTest {
protected:
ServiceWorkerCacheStorageMigrationTest() : cache1_("foo"), cache2_("bar") {}
void SetUp() override {
ServiceWorkerCacheStorageManagerTest::SetUp();
// Populate a cache, then move it to the "legacy" location
// so that tests can verify the results of migration.
legacy_path_ = ServiceWorkerCacheStorageManager::ConstructLegacyOriginPath(
cache_manager_->root_path(), origin1_);
new_path_ = ServiceWorkerCacheStorageManager::ConstructOriginPath(
cache_manager_->root_path(), origin1_);
ASSERT_FALSE(base::DirectoryExists(legacy_path_));
ASSERT_FALSE(base::DirectoryExists(new_path_));
ASSERT_TRUE(Open(origin1_, cache1_));
ASSERT_TRUE(Open(origin1_, cache2_));
callback_cache_ = nullptr;
ASSERT_FALSE(base::DirectoryExists(legacy_path_));
ASSERT_TRUE(base::DirectoryExists(new_path_));
quota_manager_proxy_->SimulateQuotaManagerDestroyed();
cache_manager_ =
ServiceWorkerCacheStorageManager::Create(cache_manager_.get());
ASSERT_TRUE(base::Move(new_path_, legacy_path_));
ASSERT_TRUE(base::DirectoryExists(legacy_path_));
ASSERT_FALSE(base::DirectoryExists(new_path_));
}
int64 GetOriginUsage(const GURL& origin) {
scoped_ptr<base::RunLoop> loop(new base::RunLoop());
cache_manager_->GetOriginUsage(
origin,
base::Bind(&ServiceWorkerCacheStorageMigrationTest::UsageCallback,
base::Unretained(this), base::Unretained(loop.get())));
loop->Run();
return callback_usage_;
}
void UsageCallback(base::RunLoop* run_loop, int64 usage) {
callback_usage_ = usage;
run_loop->Quit();
}
base::FilePath legacy_path_;
base::FilePath new_path_;
const std::string cache1_;
const std::string cache2_;
int64 callback_usage_;
DISALLOW_COPY_AND_ASSIGN(ServiceWorkerCacheStorageMigrationTest);
};
TEST_F(ServiceWorkerCacheStorageMigrationTest, OpenCache) {
EXPECT_TRUE(Open(origin1_, cache1_));
EXPECT_FALSE(base::DirectoryExists(legacy_path_));
EXPECT_TRUE(base::DirectoryExists(new_path_));
EXPECT_TRUE(Keys(origin1_));
std::vector<std::string> expected_keys;
expected_keys.push_back(cache1_);
expected_keys.push_back(cache2_);
EXPECT_EQ(expected_keys, callback_strings_);
}
TEST_F(ServiceWorkerCacheStorageMigrationTest, DeleteCache) {
EXPECT_TRUE(Delete(origin1_, cache1_));
EXPECT_FALSE(base::DirectoryExists(legacy_path_));
EXPECT_TRUE(base::DirectoryExists(new_path_));
EXPECT_TRUE(Keys(origin1_));
std::vector<std::string> expected_keys;
expected_keys.push_back(cache2_);
EXPECT_EQ(expected_keys, callback_strings_);
}
TEST_F(ServiceWorkerCacheStorageMigrationTest, GetOriginUsage) {
EXPECT_GT(GetOriginUsage(origin1_), 0);
EXPECT_FALSE(base::DirectoryExists(legacy_path_));
EXPECT_TRUE(base::DirectoryExists(new_path_));
}
TEST_F(ServiceWorkerCacheStorageMigrationTest, MoveFailure) {
// Revert the migration.
ASSERT_TRUE(base::Move(legacy_path_, new_path_));
ASSERT_FALSE(base::DirectoryExists(legacy_path_));
ASSERT_TRUE(base::DirectoryExists(new_path_));
// Make a dummy legacy directory.
ASSERT_TRUE(base::CreateDirectory(legacy_path_));
// Ensure that migration doesn't stomp existing new directory,
// but does clean up old directory.
EXPECT_TRUE(Open(origin1_, cache1_));
EXPECT_FALSE(base::DirectoryExists(legacy_path_));
EXPECT_TRUE(base::DirectoryExists(new_path_));
EXPECT_TRUE(Keys(origin1_));
std::vector<std::string> expected_keys;
expected_keys.push_back(cache1_);
expected_keys.push_back(cache2_);
EXPECT_EQ(expected_keys, callback_strings_);
}
class ServiceWorkerCacheQuotaClientTest
: public ServiceWorkerCacheStorageManagerTest {
protected:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment