diff options
author | tzik@google.com <tzik@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-05-11 11:01:17 +0000 |
---|---|---|
committer | tzik@google.com <tzik@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-05-11 11:01:17 +0000 |
commit | d6fcf7e808e51f8f865423b7cd935c9e707debbc (patch) | |
tree | de7d7522adef0e4d55ded5c7c8b2a86c7f38b8aa /webkit/quota | |
parent | 845b43a8e2652e74447fedd648216769e3d1e566 (diff) | |
download | chromium_src-d6fcf7e808e51f8f865423b7cd935c9e707debbc.zip chromium_src-d6fcf7e808e51f8f865423b7cd935c9e707debbc.tar.gz chromium_src-d6fcf7e808e51f8f865423b7cd935c9e707debbc.tar.bz2 |
Added {Get,Set}PersistentHostQuota
BUG=61676
TEST='QuotaManagerTests.*'
Review URL: http://codereview.chromium.org/6904042
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@84963 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/quota')
-rw-r--r-- | webkit/quota/mock_storage_client.cc | 30 | ||||
-rw-r--r-- | webkit/quota/mock_storage_client.h | 8 | ||||
-rw-r--r-- | webkit/quota/quota_manager.cc | 300 | ||||
-rw-r--r-- | webkit/quota/quota_manager.h | 21 | ||||
-rw-r--r-- | webkit/quota/quota_manager_unittest.cc | 379 | ||||
-rw-r--r-- | webkit/quota/quota_types.h | 61 |
6 files changed, 718 insertions, 81 deletions
diff --git a/webkit/quota/mock_storage_client.cc b/webkit/quota/mock_storage_client.cc index ee1a0b1..74f5e28 100644 --- a/webkit/quota/mock_storage_client.cc +++ b/webkit/quota/mock_storage_client.cc @@ -19,6 +19,8 @@ namespace quota { namespace { +using std::make_pair; + class MockStorageClientIDSequencer { public: static MockStorageClientIDSequencer* GetInstance() { @@ -54,17 +56,21 @@ MockStorageClient::~MockStorageClient() { void MockStorageClient::AddMockOriginData( const GURL& origin_url, StorageType type, int64 size) { - origin_data_.insert(std::make_pair(origin_url, MockOriginData(type, size))); + origin_data_[make_pair(origin_url, type)] = size; } void MockStorageClient::ModifyMockOriginDataSize( const GURL& origin_url, StorageType type, int64 delta) { - std::map<GURL, MockOriginData>::iterator find = origin_data_.find(origin_url); - if (find == origin_data_.end() || find->second.type != type) { + OriginDataMap::iterator find = origin_data_.find(make_pair(origin_url, type)); + if (find == origin_data_.end()) { DCHECK(delta >= 0); AddMockOriginData(origin_url, type, delta); return; } + find->second += delta; + DCHECK(find->second >= 0); + + // TODO(tzik): Check quota to prevent usage exceed quota_manager_proxy_->NotifyStorageModified(id(), origin_url, type, delta); } @@ -109,11 +115,11 @@ void MockStorageClient::RunGetOriginUsage( const GURL& origin_url, StorageType type, GetUsageCallback* callback_ptr) { usage_callbacks_.erase(callback_ptr); scoped_ptr<GetUsageCallback> callback(callback_ptr); - std::map<GURL, MockOriginData>::iterator find = origin_data_.find(origin_url); + OriginDataMap::iterator find = origin_data_.find(make_pair(origin_url, type)); if (find == origin_data_.end()) { callback->Run(0); } else { - callback->Run(find->second.usage); + callback->Run(find->second); } } @@ -122,10 +128,10 @@ void MockStorageClient::RunGetOriginsForType( scoped_ptr<GetOriginsCallback> callback(callback_ptr); origins_callbacks_.erase(callback_ptr); std::set<GURL> origins; - for (std::map<GURL, MockOriginData>::iterator iter = origin_data_.begin(); + for (OriginDataMap::iterator iter = origin_data_.begin(); iter != origin_data_.end(); ++iter) { - if (type == iter->second.type) - origins.insert(iter->first); + if (type == iter->first.second) + origins.insert(iter->first.first); } callback->Run(origins); } @@ -136,11 +142,11 @@ void MockStorageClient::RunGetOriginsForHost( scoped_ptr<GetOriginsCallback> callback(callback_ptr); origins_callbacks_.erase(callback_ptr); std::set<GURL> origins; - for (std::map<GURL, MockOriginData>::iterator iter = origin_data_.begin(); + for (OriginDataMap::iterator iter = origin_data_.begin(); iter != origin_data_.end(); ++iter) { - std::string host_or_spec = net::GetHostOrSpecFromURL(iter->first); - if (type == iter->second.type && host == host_or_spec) - origins.insert(iter->first); + std::string host_or_spec = net::GetHostOrSpecFromURL(iter->first.first); + if (type == iter->first.second && host == host_or_spec) + origins.insert(iter->first.first); } callback->Run(origins); } diff --git a/webkit/quota/mock_storage_client.h b/webkit/quota/mock_storage_client.h index ac2545b..e1ad61e 100644 --- a/webkit/quota/mock_storage_client.h +++ b/webkit/quota/mock_storage_client.h @@ -51,12 +51,8 @@ class MockStorageClient : public QuotaClient { scoped_refptr<QuotaManagerProxy> quota_manager_proxy_; const ID id_; - struct MockOriginData { - MockOriginData(StorageType type, int64 usage) : type(type), usage(usage) { } - StorageType type; - int64 usage; - }; - std::map<GURL, MockOriginData> origin_data_; + typedef std::map<std::pair<GURL, StorageType>, int64> OriginDataMap; + OriginDataMap origin_data_; std::set<GetUsageCallback*> usage_callbacks_; std::set<GetOriginsCallback*> origins_callbacks_; diff --git a/webkit/quota/quota_manager.cc b/webkit/quota/quota_manager.cc index 16b44ef..2e2db35 100644 --- a/webkit/quota/quota_manager.cc +++ b/webkit/quota/quota_manager.cc @@ -84,12 +84,16 @@ class QuotaManager::UsageAndQuotaDispatcherTask : public QuotaTask { CheckCompleted(); } - void DidGetGlobalQuota(int64 quota) { + void DidGetGlobalQuota(QuotaStatusCode status, int64 quota) { + quota_status_ = status; quota_ = quota; CheckCompleted(); } - void DidGetHostQuota(const std::string& host_unused, int64 quota) { + void DidGetHostQuota(QuotaStatusCode status, + const std::string& host_unused, + int64 quota) { + quota_status_ = status; quota_ = quota; CheckCompleted(); } @@ -105,6 +109,7 @@ class QuotaManager::UsageAndQuotaDispatcherTask : public QuotaTask { quota_(-1), global_usage_(-1), host_usage_(-1), + quota_status_(kQuotaStatusUnknown), callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {} virtual ~UsageAndQuotaDispatcherTask() { @@ -136,6 +141,7 @@ class QuotaManager::UsageAndQuotaDispatcherTask : public QuotaTask { int64 quota() const { return quota_; } int64 global_usage() const { return global_usage_; } int64 host_usage() const { return host_usage_; } + QuotaStatusCode status() const { return quota_status_; } UsageCallback* NewGlobalUsageCallback() { return callback_factory_.NewCallback( @@ -182,6 +188,7 @@ class QuotaManager::UsageAndQuotaDispatcherTask : public QuotaTask { int64 quota_; int64 global_usage_; int64 host_usage_; + QuotaStatusCode quota_status_; CallbackList callbacks_; ScopedCallbackFactory<UsageAndQuotaDispatcherTask> callback_factory_; @@ -213,7 +220,7 @@ class QuotaManager::UsageAndQuotaDispatcherTaskForTemporary // to return {usage, quota - nonevictable_usage} once eviction is // supported. int64 other_usage = global_usage() - host_usage(); - callback->Run(kQuotaStatusOk, host_usage(), quota() - other_usage); + callback->Run(status(), host_usage(), quota() - other_usage); } }; @@ -237,7 +244,7 @@ class QuotaManager::UsageAndQuotaDispatcherTaskForPersistent } virtual void DispatchCallback(GetUsageAndQuotaCallback* callback) OVERRIDE { - callback->Run(kQuotaStatusOk, host_usage(), quota()); + callback->Run(status(), host_usage(), quota()); } }; @@ -292,10 +299,10 @@ class QuotaManager::InitializeTask : public QuotaThreadTask { virtual void Completed() OVERRIDE { DCHECK(manager_); - if (manager_->temporary_global_quota_ < 0) - manager_->DidGetTemporaryGlobalQuota(temporary_storage_quota_); manager_->db_initialized_ = !db_disabled_; manager_->db_disabled_ = db_disabled_; + if (manager_->temporary_global_quota_ < 0) + manager_->DidGetTemporaryGlobalQuota(temporary_storage_quota_); } private: @@ -306,36 +313,122 @@ class QuotaManager::InitializeTask : public QuotaThreadTask { bool db_disabled_; }; -class QuotaManager::TemporaryGlobalQuotaUpdateTask : public QuotaThreadTask { +class QuotaManager::TemporaryGlobalQuotaUpdateTask + : public QuotaThreadTask { public: TemporaryGlobalQuotaUpdateTask( QuotaManager* manager, QuotaDatabase* database, scoped_refptr<base::MessageLoopProxy> db_message_loop, - int64 new_quota) + int64 new_quota, + QuotaCallback* callback) : QuotaThreadTask(manager, db_message_loop), manager_(manager), database_(database), new_quota_(new_quota), + callback_(callback), db_disabled_(false) { DCHECK(database_); + DCHECK(new_quota >=0); } protected: virtual void RunOnTargetThread() OVERRIDE { - if (!database_->SetGlobalQuota(kStorageTypeTemporary, new_quota_)) + if (!database_->SetGlobalQuota(kStorageTypeTemporary, new_quota_)) { db_disabled_ = true; + new_quota_ = 0; + } } virtual void Completed() OVERRIDE { DCHECK(manager_); manager_->db_disabled_ = db_disabled_; + callback_->Run(db_disabled_ ? kQuotaErrorInvalidAccess : kQuotaStatusOk, + new_quota_); + } + + private: + QuotaManager* manager_; + QuotaDatabase* database_; + int64 new_quota_; + scoped_ptr<QuotaCallback> callback_; + bool db_disabled_; +}; + +class QuotaManager::PersistentHostQuotaQueryTask : public QuotaThreadTask { + public: + PersistentHostQuotaQueryTask( + QuotaManager* manager, + QuotaDatabase* database, + scoped_refptr<base::MessageLoopProxy> db_message_loop, + const std::string& host, + HostQuotaCallback* callback) + : QuotaThreadTask(manager, db_message_loop), + manager_(manager), + database_(database), + host_(host), + quota_(-1), + callback_(callback) { + DCHECK(manager_); + DCHECK(database_); + DCHECK(!host_.empty()); + } + protected: + virtual void RunOnTargetThread() OVERRIDE { + if (!database_->GetHostQuota(host_, kStorageTypePersistent, "a_)) + quota_ = 0; + } + virtual void Completed() OVERRIDE { + callback_->Run(kQuotaStatusOk, host_, quota_); + } + private: + QuotaManager* manager_; + QuotaDatabase* database_; + std::string host_; + int64 quota_; + scoped_ptr<HostQuotaCallback> callback_; +}; + +class QuotaManager::PersistentHostQuotaUpdateTask : public QuotaThreadTask { + public: + PersistentHostQuotaUpdateTask( + QuotaManager* manager, + QuotaDatabase* database, + scoped_refptr<base::MessageLoopProxy> db_message_loop, + const std::string& host, + int new_quota, + HostQuotaCallback* callback) + : QuotaThreadTask(manager, db_message_loop), + manager_(manager), + database_(database), + host_(host), + new_quota_(new_quota), + callback_(callback), + db_disabled_(false) { + DCHECK(manager_); + DCHECK(database_); + DCHECK(!host_.empty()); + DCHECK(new_quota_ >= 0); + } + protected: + virtual void RunOnTargetThread() OVERRIDE { + if (!database_->SetHostQuota(host_, kStorageTypePersistent, new_quota_)) { + db_disabled_ = true; + new_quota_ = 0; + } } + virtual void Completed() OVERRIDE { + manager_->db_disabled_ = db_disabled_; + callback_->Run(db_disabled_ ? kQuotaErrorInvalidAccess : kQuotaStatusOk, + host_, new_quota_); + } private: QuotaManager* manager_; QuotaDatabase* database_; + std::string host_; int64 new_quota_; + scoped_ptr<HostQuotaCallback> callback_; bool db_disabled_; }; @@ -411,7 +504,7 @@ void QuotaManager::GetTemporaryGlobalQuota(QuotaCallback* callback) { if (temporary_global_quota_ >= 0) { // TODO(kinuko): The in-memory quota value should be periodically // updated not to exceed the current available space in the hard drive. - callback->Run(temporary_global_quota_); + callback->Run(kQuotaStatusOk, temporary_global_quota_); delete callback; return; } @@ -419,39 +512,56 @@ void QuotaManager::GetTemporaryGlobalQuota(QuotaCallback* callback) { temporary_global_quota_callbacks_.Add(callback); } -void QuotaManager::SetTemporaryGlobalQuota(int64 new_quota) { +void QuotaManager::SetTemporaryGlobalQuota(int64 new_quota, + QuotaCallback* callback) { LazyInitialize(); - DCHECK(new_quota >= 0); + if (new_quota < 0) { + callback->Run(kQuotaErrorInvalidModification, -1); + delete callback; + return; + } + DidGetTemporaryGlobalQuota(new_quota); if (!db_disabled_) { scoped_refptr<TemporaryGlobalQuotaUpdateTask> task( new TemporaryGlobalQuotaUpdateTask( - this, database_.get(), db_thread_, new_quota)); + this, database_.get(), db_thread_, new_quota, callback)); task->Start(); + } else { + callback->Run(kQuotaErrorInvalidAccess, -1); + delete callback; } } void QuotaManager::GetPersistentHostQuota(const std::string& host, HostQuotaCallback* callback) { LazyInitialize(); - std::map<std::string, int64>::iterator found = - persistent_host_quota_.find(host); - if (found != persistent_host_quota_.end()) { - callback->Run(host, found->second); - delete callback; - return; - } - if (persistent_host_quota_callbacks_.Add(host, callback)) { - // This is the first call for this host. - // TODO(kinuko): Dispatch a task to get the host quota for the host - // once QuotaDatabase is updated to accept hosts instead of origins. - } + + scoped_refptr<PersistentHostQuotaQueryTask> task( + new PersistentHostQuotaQueryTask( + this, database_.get(), db_thread_, host, callback)); + task->Start(); } void QuotaManager::SetPersistentHostQuota(const std::string& host, - int64 new_quota) { + int64 new_quota, + HostQuotaCallback* callback) { LazyInitialize(); - // TODO(kinuko): Implement once QuotaDatabase is updated. + if (new_quota < 0) { + callback->Run(kQuotaErrorInvalidModification, host, -1); + delete callback; + return; + } + + if (!db_disabled_) { + scoped_refptr<PersistentHostQuotaUpdateTask> task( + new PersistentHostQuotaUpdateTask( + this, database_.get(), db_thread_, host, new_quota, callback)); + task->Start(); + } else { + callback->Run(kQuotaErrorInvalidAccess, host, -1); + delete callback; + } } void QuotaManager::LazyInitialize() { @@ -505,14 +615,9 @@ UsageTracker* QuotaManager::GetUsageTracker(StorageType type) const { void QuotaManager::DidGetTemporaryGlobalQuota(int64 quota) { temporary_global_quota_ = quota; - temporary_global_quota_callbacks_.Run(quota); -} - -void QuotaManager::DidGetPersistentHostQuota(const std::string& host, - int64 quota) { - DCHECK(persistent_host_quota_.find(host) == persistent_host_quota_.end()); - persistent_host_quota_[host] = quota; - persistent_host_quota_callbacks_.Run(host, host, quota); + temporary_global_quota_callbacks_.Run( + db_disabled_ ? kQuotaErrorInvalidAccess : kQuotaStatusOk, + quota); } void QuotaManager::DeleteOnCorrectThread() const { @@ -523,6 +628,131 @@ void QuotaManager::DeleteOnCorrectThread() const { delete this; } +class QuotaManager::GlobalUsageQueryTask : public QuotaTask { + public: + GlobalUsageQueryTask(QuotaManager* manager, + StorageType type, + UsageCallback* callback) + : QuotaTask(manager), + manager_(manager), + callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)), + type_(type), + usage_(0), + callback_(callback) {} + + protected: + virtual void Run() OVERRIDE { + UsageTracker* tracker = NULL; + + switch (type_) { + case kStorageTypeTemporary: + tracker = manager_->temporary_usage_tracker_.get(); + break; + case kStorageTypePersistent: + tracker = manager_->persistent_usage_tracker_.get(); + break; + default: + NOTREACHED(); + } + + DCHECK(tracker); + tracker->GetGlobalUsage( + callback_factory_.NewCallback( + &GlobalUsageQueryTask::DidGetGlobalUsage)); + } + + virtual void Aborted() OVERRIDE { + delete this; + } + + virtual void Completed() OVERRIDE { + callback_->Run(usage_); + delete this; + } + private: + QuotaManager* manager_; + ScopedCallbackFactory<GlobalUsageQueryTask> callback_factory_; + StorageType type_; + int64 usage_; + UsageCallback* callback_; + + void DidGetGlobalUsage(int64 usage) { + usage_ += usage; + CallCompleted(); + } +}; + +class QuotaManager::HostUsageQueryTask : public QuotaTask { + public: + HostUsageQueryTask(QuotaManager* manager, + const std::string& host, + StorageType type, + HostUsageCallback* callback) + : QuotaTask(manager), + manager_(manager), + callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)), + usage_(0), + host_(host), + type_(type), + callback_(callback) {} + + protected: + virtual void Run() OVERRIDE { + UsageTracker* tracker = NULL; + switch (type_) { + case kStorageTypeTemporary: + tracker = manager_->temporary_usage_tracker_.get(); + break; + case kStorageTypePersistent: + tracker = manager_->persistent_usage_tracker_.get(); + break; + default: + NOTREACHED(); + } + + DCHECK(tracker); + tracker->GetHostUsage( + host_, + callback_factory_.NewCallback( + &HostUsageQueryTask::DidGetHostUsage)); + } + + virtual void Aborted() OVERRIDE { + delete this; + } + + virtual void Completed() OVERRIDE { + callback_->Run(host_, usage_); + delete this; + } + private: + QuotaManager* manager_; + ScopedCallbackFactory<HostUsageQueryTask> callback_factory_; + int task_count_; + int64 usage_; + std::string host_; + StorageType type_; + HostUsageCallback* callback_; + + void DidGetHostUsage(const std::string&, int64 usage) { + usage_ = usage; + CallCompleted(); + } +}; + +void QuotaManager::GetGlobalUsage(StorageType type, UsageCallback* callback){ + LazyInitialize(); + QuotaTask* task = new GlobalUsageQueryTask(this, type, callback); + task->Start(); +} + +void QuotaManager::GetHostUsage(const std::string& host, StorageType type, + HostUsageCallback* callback) { + LazyInitialize(); + QuotaTask* task = new HostUsageQueryTask(this, host, type, callback); + task->Start(); +} + // QuotaManagerProxy ---------------------------------------------------------- void QuotaManagerProxy::GetUsageAndQuota( diff --git a/webkit/quota/quota_manager.h b/webkit/quota/quota_manager.h index 16c0588..d54336f 100644 --- a/webkit/quota/quota_manager.h +++ b/webkit/quota/quota_manager.h @@ -67,14 +67,16 @@ class QuotaManager : public QuotaTaskObserver, // Called by UI and internal modules. void GetTemporaryGlobalQuota(QuotaCallback* callback); - void SetTemporaryGlobalQuota(int64 new_quota); + void SetTemporaryGlobalQuota(int64 new_quota, QuotaCallback* callback); void GetPersistentHostQuota(const std::string& host, HostQuotaCallback* callback); - void SetPersistentHostQuota(const std::string& host, int64 new_quota); + void SetPersistentHostQuota(const std::string& host, + int64 new_quota, + HostQuotaCallback* callback); - // TODO(kinuko): Add more APIs for UI: - // - Get temporary global/per-host usage - // - Get persistent global/per-host usage + void GetGlobalUsage(StorageType type, UsageCallback* callback); + void GetHostUsage(const std::string& host, StorageType type, + HostUsageCallback* callback); const static int64 kTemporaryStorageQuotaDefaultSize; const static int64 kTemporaryStorageQuotaMaxSize; @@ -85,11 +87,16 @@ class QuotaManager : public QuotaTaskObserver, private: class InitializeTask; class TemporaryGlobalQuotaUpdateTask; + class PersistentHostQuotaUpdateTask; + class PersistentHostQuotaQueryTask; class UsageAndQuotaDispatcherTask; class UsageAndQuotaDispatcherTaskForTemporary; class UsageAndQuotaDispatcherTaskForPersistent; + class GlobalUsageQueryTask; + class HostUsageQueryTask; + typedef std::pair<std::string, StorageType> HostAndType; typedef std::map<HostAndType, UsageAndQuotaDispatcherTask*> UsageAndQuotaDispatcherTaskMap; @@ -119,7 +126,6 @@ class QuotaManager : public QuotaTaskObserver, UsageTracker* GetUsageTracker(StorageType type) const; void DidGetTemporaryGlobalQuota(int64 quota); - void DidGetPersistentHostQuota(const std::string& host, int64 quota); void DeleteOnCorrectThread() const; @@ -143,9 +149,6 @@ class QuotaManager : public QuotaTaskObserver, int64 temporary_global_quota_; QuotaCallbackQueue temporary_global_quota_callbacks_; - std::map<std::string, int64> persistent_host_quota_; - HostQuotaCallbackMap persistent_host_quota_callbacks_; - DISALLOW_COPY_AND_ASSIGN(QuotaManager); }; diff --git a/webkit/quota/quota_manager_unittest.cc b/webkit/quota/quota_manager_unittest.cc index eb0af8f..d931cab 100644 --- a/webkit/quota/quota_manager_unittest.cc +++ b/webkit/quota/quota_manager_unittest.cc @@ -72,7 +72,7 @@ class QuotaManagerTest : public testing::Test { } void GetUsageAndQuota(const GURL& origin, StorageType type) { - status_ = kQuotaStatusUnknown; + quota_status_ = kQuotaStatusUnknown; usage_ = -1; quota_ = -1; quota_manager_->GetUsageAndQuota(origin, type, @@ -80,6 +80,52 @@ class QuotaManagerTest : public testing::Test { &QuotaManagerTest::DidGetUsageAndQuota)); } + void GetTemporaryGlobalQuota() { + quota_status_ = kQuotaStatusUnknown; + quota_ = -1; + quota_manager_->GetTemporaryGlobalQuota( + callback_factory_.NewCallback( + &QuotaManagerTest::DidGetQuota)); + } + + void SetTemporaryGlobalQuota(int64 new_quota) { + quota_status_ = kQuotaStatusUnknown; + quota_ = -1; + quota_manager_->SetTemporaryGlobalQuota(new_quota, + callback_factory_.NewCallback( + &QuotaManagerTest::DidGetQuota)); + } + + void GetPersistentHostQuota(const std::string& host) { + quota_status_ = kQuotaStatusUnknown; + quota_ = -1; + quota_manager_->GetPersistentHostQuota(host, + callback_factory_.NewCallback( + &QuotaManagerTest::DidGetHostQuota)); + } + + void SetPersistentHostQuota(const std::string& host, int64 new_quota) { + quota_status_ = kQuotaStatusUnknown; + quota_ = -1; + quota_manager_->SetPersistentHostQuota(host, new_quota, + callback_factory_.NewCallback( + &QuotaManagerTest::DidGetHostQuota)); + } + + void GetGlobalUsage(StorageType type) { + usage_ = -1; + quota_manager_->GetGlobalUsage(type, + callback_factory_.NewCallback( + &QuotaManagerTest::DidGetGlobalUsage)); + } + + void GetHostUsage(const std::string& host, StorageType type) { + usage_ = -1; + quota_manager_->GetHostUsage(host, type, + callback_factory_.NewCallback( + &QuotaManagerTest::DidGetHostUsage)); + } + void RunAdditionalUsageAndQuotaTask(const GURL& origin, StorageType type) { quota_manager_->GetUsageAndQuota(origin, type, callback_factory_.NewCallback( @@ -87,11 +133,31 @@ class QuotaManagerTest : public testing::Test { } void DidGetUsageAndQuota(QuotaStatusCode status, int64 usage, int64 quota) { - status_ = status; + quota_status_ = status; usage_ = usage; quota_ = quota; } + void DidGetQuota(QuotaStatusCode status, int64 quota) { + quota_status_ = status; + quota_ = quota; + } + + void DidGetHostQuota(QuotaStatusCode status, + const std::string& host, int64 quota) { + quota_status_ = status; + host_ = host; + quota_ = quota; + } + + void DidGetGlobalUsage(int64 usage) { + usage_ = usage; + } + + void DidGetHostUsage(const std::string&, int64 usage) { + usage_ = usage; + } + void set_additional_callback_count(int c) { additional_callback_count_ = c; } int additional_callback_count() const { return additional_callback_count_; } void DidGetUsageAndQuotaAdditional( @@ -104,7 +170,7 @@ class QuotaManagerTest : public testing::Test { quota_manager_ = quota_manager; } - QuotaStatusCode status() const { return status_; } + QuotaStatusCode status() const { return quota_status_; } int64 usage() const { return usage_; } int64 quota() const { return quota_; } @@ -114,7 +180,8 @@ class QuotaManagerTest : public testing::Test { scoped_refptr<QuotaManager> quota_manager_; - QuotaStatusCode status_; + QuotaStatusCode quota_status_; + std::string host_; int64 usage_; int64 quota_; @@ -123,19 +190,25 @@ class QuotaManagerTest : public testing::Test { DISALLOW_COPY_AND_ASSIGN(QuotaManagerTest); }; -TEST_F(QuotaManagerTest, GetTemporaryUsageAndQuota_Simple) { +TEST_F(QuotaManagerTest, GetUsageAndQuota_Simple) { const static MockOriginData kData[] = { { "http://foo.com/", kStorageTypeTemporary, 10 }, { "http://foo.com/", kStorageTypePersistent, 80 }, }; RegisterClient(CreateClient(kData, ARRAYSIZE_UNSAFE(kData))); + GetUsageAndQuota(GURL("http://foo.com/"), kStorageTypePersistent); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(kQuotaStatusOk, status()); + EXPECT_EQ(80, usage()); + EXPECT_EQ(0, quota()); + GetUsageAndQuota(GURL("http://foo.com/"), kStorageTypeTemporary); MessageLoop::current()->RunAllPending(); EXPECT_EQ(kQuotaStatusOk, status()); EXPECT_EQ(10, usage()); - EXPECT_GT(quota(), 0); - EXPECT_LE(quota(), QuotaManager::kTemporaryStorageQuotaMaxSize); + EXPECT_LE(0, quota()); + EXPECT_GE(QuotaManager::kTemporaryStorageQuotaMaxSize, quota()); int64 quota_returned_for_foo = quota(); GetUsageAndQuota(GURL("http://bar.com/"), kStorageTypeTemporary); @@ -145,19 +218,61 @@ TEST_F(QuotaManagerTest, GetTemporaryUsageAndQuota_Simple) { EXPECT_EQ(quota_returned_for_foo - 10, quota()); } -TEST_F(QuotaManagerTest, GetTemporaryUsage_NoClient) { +TEST_F(QuotaManagerTest, GetUsage_NoClient) { GetUsageAndQuota(GURL("http://foo.com/"), kStorageTypeTemporary); MessageLoop::current()->RunAllPending(); EXPECT_EQ(kQuotaStatusOk, status()); EXPECT_EQ(0, usage()); + + GetUsageAndQuota(GURL("http://foo.com/"), kStorageTypePersistent); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(kQuotaStatusOk, status()); + EXPECT_EQ(0, usage()); + + GetHostUsage("foo.com", kStorageTypeTemporary); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(0, usage()); + + GetHostUsage("foo.com", kStorageTypePersistent); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(0, usage()); + + GetGlobalUsage(kStorageTypeTemporary); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(0, usage()); + + GetGlobalUsage(kStorageTypePersistent); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(0, usage()); } -TEST_F(QuotaManagerTest, GetTemporaryUsage_EmptyClient) { +TEST_F(QuotaManagerTest, GetUsage_EmptyClient) { RegisterClient(CreateClient(NULL, 0)); GetUsageAndQuota(GURL("http://foo.com/"), kStorageTypeTemporary); MessageLoop::current()->RunAllPending(); EXPECT_EQ(kQuotaStatusOk, status()); EXPECT_EQ(0, usage()); + + GetUsageAndQuota(GURL("http://foo.com/"), kStorageTypePersistent); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(kQuotaStatusOk, status()); + EXPECT_EQ(0, usage()); + + GetHostUsage("foo.com", kStorageTypeTemporary); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(0, usage()); + + GetHostUsage("foo.com", kStorageTypePersistent); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(0, usage()); + + GetGlobalUsage(kStorageTypeTemporary); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(0, usage()); + + GetGlobalUsage(kStorageTypePersistent); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(0, usage()); } TEST_F(QuotaManagerTest, GetTemporaryUsageAndQuota_MultiOrigins) { @@ -172,7 +287,10 @@ TEST_F(QuotaManagerTest, GetTemporaryUsageAndQuota_MultiOrigins) { RegisterClient(CreateClient(kData, ARRAYSIZE_UNSAFE(kData))); // This time explicitly sets a temporary global quota. - quota_manager()->SetTemporaryGlobalQuota(100); + SetTemporaryGlobalQuota(100); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(kQuotaStatusOk, status()); + EXPECT_EQ(100, quota()); GetUsageAndQuota(GURL("http://foo.com/"), kStorageTypeTemporary); MessageLoop::current()->RunAllPending(); @@ -189,10 +307,11 @@ TEST_F(QuotaManagerTest, GetTemporaryUsageAndQuota_MultiOrigins) { EXPECT_EQ(100 - (10 + 20 + 30), quota()); } -TEST_F(QuotaManagerTest, GetTemporaryUsage_MultipleClients) { +TEST_F(QuotaManagerTest, GetUsage_MultipleClients) { const static MockOriginData kData1[] = { { "http://foo.com/", kStorageTypeTemporary, 10 }, { "http://bar.com/", kStorageTypeTemporary, 20 }, + { "http://bar.com/", kStorageTypePersistent, 50 }, }; const static MockOriginData kData2[] = { { "https://foo.com/", kStorageTypeTemporary, 30 }, @@ -205,6 +324,21 @@ TEST_F(QuotaManagerTest, GetTemporaryUsage_MultipleClients) { MessageLoop::current()->RunAllPending(); EXPECT_EQ(kQuotaStatusOk, status()); EXPECT_EQ(10 + 30, usage()); + + GetUsageAndQuota(GURL("http://bar.com/"), kStorageTypePersistent); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(kQuotaStatusOk, status()); + EXPECT_EQ(50, usage()); + + GetGlobalUsage(kStorageTypeTemporary); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(kQuotaStatusOk, status()); + EXPECT_EQ(10 + 20 + 30, usage()); + + GetGlobalUsage(kStorageTypePersistent); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(kQuotaStatusOk, status()); + EXPECT_EQ(40 + 50, usage()); } TEST_F(QuotaManagerTest, GetTemporaryUsage_WithModify) { @@ -246,7 +380,7 @@ TEST_F(QuotaManagerTest, GetTemporaryUsageAndQuota_WithAdditionalTasks) { { "http://foo.com/", kStorageTypePersistent, 40 }, }; RegisterClient(CreateClient(kData, ARRAYSIZE_UNSAFE(kData))); - quota_manager()->SetTemporaryGlobalQuota(100); + SetTemporaryGlobalQuota(100); GetUsageAndQuota(GURL("http://foo.com/"), kStorageTypeTemporary); GetUsageAndQuota(GURL("http://foo.com/"), kStorageTypeTemporary); @@ -277,7 +411,7 @@ TEST_F(QuotaManagerTest, GetTemporaryUsageAndQuota_NukeManager) { { "http://foo.com/", kStorageTypePersistent, 40 }, }; RegisterClient(CreateClient(kData, ARRAYSIZE_UNSAFE(kData))); - quota_manager()->SetTemporaryGlobalQuota(100); + SetTemporaryGlobalQuota(100); set_additional_callback_count(0); GetUsageAndQuota(GURL("http://foo.com/"), kStorageTypeTemporary); @@ -292,4 +426,223 @@ TEST_F(QuotaManagerTest, GetTemporaryUsageAndQuota_NukeManager) { EXPECT_EQ(kQuotaErrorAbort, status()); } +TEST_F(QuotaManagerTest, GetAndSetPerststentHostQuota) { + RegisterClient(CreateClient(NULL, 0)); + + GetPersistentHostQuota("foo.com"); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(0, quota()); + + SetPersistentHostQuota("foo.com", 100); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(100, quota()); + + GetPersistentHostQuota("foo.com"); + SetPersistentHostQuota("foo.com", 200); + GetPersistentHostQuota("foo.com"); + SetPersistentHostQuota("foo.com", 300); + GetPersistentHostQuota("foo.com"); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(300, quota()); +} + +TEST_F(QuotaManagerTest, GetAndSetPersistentUsageAndQuota) { + RegisterClient(CreateClient(NULL, 0)); + + GetUsageAndQuota(GURL("http://foo.com/"), kStorageTypePersistent); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(kQuotaStatusOk, status()); + EXPECT_EQ(0, usage()); + EXPECT_EQ(0, quota()); + + SetPersistentHostQuota("foo.com",100); + GetUsageAndQuota(GURL("http://foo.com/"), kStorageTypePersistent); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(kQuotaStatusOk, status()); + EXPECT_EQ(0, usage()); + EXPECT_EQ(100, quota()); +} + +TEST_F(QuotaManagerTest, GetPersistentUsageAndQuota_MultiOrigins) { + const static MockOriginData kData[] = { + { "http://foo.com/", kStorageTypePersistent, 10 }, + { "http://foo.com:8080/", kStorageTypePersistent, 20 }, + { "https://foo.com/", kStorageTypePersistent, 13 }, + { "https://foo.com:8081/", kStorageTypePersistent, 19 }, + { "http://bar.com/", kStorageTypePersistent, 5 }, + { "https://bar.com/", kStorageTypePersistent, 7 }, + { "http://baz.com/", kStorageTypePersistent, 30 }, + { "http://foo.com/", kStorageTypeTemporary, 40 }, + }; + RegisterClient(CreateClient(kData, ARRAYSIZE_UNSAFE(kData))); + + SetPersistentHostQuota("foo.com", 100); + GetUsageAndQuota(GURL("http://foo.com/"), kStorageTypePersistent); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(kQuotaStatusOk, status()); + EXPECT_EQ(10 + 20 + 13 + 19, usage()); + EXPECT_EQ(100, quota()); +} + +TEST_F(QuotaManagerTest, GetPersistentUsage_WithModify) { + const static MockOriginData kData[] = { + { "http://foo.com/", kStorageTypePersistent, 10 }, + { "http://foo.com:1/", kStorageTypePersistent, 20 }, + }; + MockStorageClient* client = CreateClient(kData, ARRAYSIZE_UNSAFE(kData)); + RegisterClient(client); + + GetUsageAndQuota(GURL("http://foo.com/"), kStorageTypePersistent); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(kQuotaStatusOk, status()); + EXPECT_EQ(10 + 20, usage()); + + client->ModifyMockOriginDataSize( + GURL("http://foo.com/"), kStorageTypePersistent, 20); + client->ModifyMockOriginDataSize( + GURL("http://foo.com:1/"), kStorageTypePersistent, -5); + client->ModifyMockOriginDataSize( + GURL("http://bar.com/"), kStorageTypePersistent, 33); + + GetUsageAndQuota(GURL("http://foo.com/"), kStorageTypePersistent); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(kQuotaStatusOk, status()); + EXPECT_EQ(10 + 20 + 20 - 5, usage()); + + GetUsageAndQuota(GURL("http://bar.com/"), kStorageTypePersistent); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(kQuotaStatusOk, status()); + EXPECT_EQ(33, usage()); +} + +TEST_F(QuotaManagerTest, GetPersistentUsageAndQuota_WithAdditionalTasks) { + const static MockOriginData kData[] = { + { "http://foo.com/", kStorageTypePersistent, 10 }, + { "http://foo.com:8080/", kStorageTypePersistent, 20 }, + { "http://bar.com/", kStorageTypePersistent, 13 }, + { "http://foo.com/", kStorageTypeTemporary, 40 }, + }; + RegisterClient(CreateClient(kData, ARRAYSIZE_UNSAFE(kData))); + SetPersistentHostQuota("foo.com",100); + + GetUsageAndQuota(GURL("http://foo.com/"), kStorageTypePersistent); + GetUsageAndQuota(GURL("http://foo.com/"), kStorageTypePersistent); + GetUsageAndQuota(GURL("http://foo.com/"), kStorageTypePersistent); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(kQuotaStatusOk, status()); + EXPECT_EQ(10 + 20, usage()); + EXPECT_EQ(100, quota()); + + set_additional_callback_count(0); + RunAdditionalUsageAndQuotaTask(GURL("http://foo.com/"), + kStorageTypePersistent); + GetUsageAndQuota(GURL("http://foo.com/"), kStorageTypePersistent); + RunAdditionalUsageAndQuotaTask(GURL("http://bar.com/"), + kStorageTypePersistent); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(kQuotaStatusOk, status()); + EXPECT_EQ(10 + 20, usage()); + EXPECT_EQ(2, additional_callback_count()); +} + +TEST_F(QuotaManagerTest, GetPersistentUsageAndQuota_NukeManager) { + const static MockOriginData kData[] = { + { "http://foo.com/", kStorageTypePersistent, 10 }, + { "http://foo.com:8080/", kStorageTypePersistent, 20 }, + { "http://bar.com/", kStorageTypePersistent, 13 }, + { "http://foo.com/", kStorageTypeTemporary, 40 }, + }; + RegisterClient(CreateClient(kData, ARRAYSIZE_UNSAFE(kData))); + SetPersistentHostQuota("foo.com", 100); + + set_additional_callback_count(0); + GetUsageAndQuota(GURL("http://foo.com/"), kStorageTypePersistent); + RunAdditionalUsageAndQuotaTask(GURL("http://foo.com/"), + kStorageTypePersistent); + RunAdditionalUsageAndQuotaTask(GURL("http://bar.com/"), + kStorageTypePersistent); + + // Nuke before waiting for callbacks. + set_quota_manager(NULL); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(kQuotaErrorAbort, status()); +} + +TEST_F(QuotaManagerTest, GetUsage_Simple) { + const static MockOriginData kData[] = { + { "http://foo.com/", kStorageTypePersistent, 1 }, + { "http://foo.com:1/", kStorageTypePersistent, 20 }, + { "http://bar.com/", kStorageTypeTemporary, 300 }, + { "https://buz.com/", kStorageTypeTemporary, 4000 }, + { "http://buz.com/", kStorageTypeTemporary, 50000 }, + { "http://bar.com:1/", kStorageTypePersistent, 600000 }, + { "http://foo.com/", kStorageTypeTemporary, 7000000 }, + }; + RegisterClient(CreateClient(kData, ARRAYSIZE_UNSAFE(kData))); + + GetGlobalUsage(kStorageTypePersistent); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(usage(), 1 + 20 + 600000); + + GetGlobalUsage(kStorageTypeTemporary); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(usage(), 300 + 4000 + 50000 + 7000000); + + GetHostUsage("foo.com", kStorageTypePersistent); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(usage(), 1 + 20); + + GetHostUsage("buz.com", kStorageTypeTemporary); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(usage(), 4000 + 50000); +} + +TEST_F(QuotaManagerTest, GetUsage_WithModification) { + const static MockOriginData kData[] = { + { "http://foo.com/", kStorageTypePersistent, 1 }, + { "http://foo.com:1/", kStorageTypePersistent, 20 }, + { "http://bar.com/", kStorageTypeTemporary, 300 }, + { "https://buz.com/", kStorageTypeTemporary, 4000 }, + { "http://buz.com/", kStorageTypeTemporary, 50000 }, + { "http://bar.com:1/", kStorageTypePersistent, 600000 }, + { "http://foo.com/", kStorageTypeTemporary, 7000000 }, + }; + + MockStorageClient* client = CreateClient(kData, ARRAYSIZE_UNSAFE(kData)); + RegisterClient(client); + + GetGlobalUsage(kStorageTypePersistent); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(usage(), 1 + 20 + 600000); + + client->ModifyMockOriginDataSize( + GURL("http://foo.com/"), kStorageTypePersistent, 80000000); + + GetGlobalUsage(kStorageTypePersistent); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(usage(), 1 + 20 + 600000 + 80000000); + + GetGlobalUsage(kStorageTypeTemporary); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(usage(), 300 + 4000 + 50000 + 7000000); + + client->ModifyMockOriginDataSize( + GURL("http://foo.com/"), kStorageTypeTemporary, 1); + + GetGlobalUsage(kStorageTypeTemporary); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(usage(), 300 + 4000 + 50000 + 7000000 + 1); + + GetHostUsage("buz.com", kStorageTypeTemporary); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(usage(), 4000 + 50000); + + client->ModifyMockOriginDataSize( + GURL("http://buz.com/"), kStorageTypeTemporary, 900000000); + + GetHostUsage("buz.com", kStorageTypeTemporary); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(usage(), 4000 + 50000 + 900000000); +} + } // namespace quota diff --git a/webkit/quota/quota_types.h b/webkit/quota/quota_types.h index 2d42440..f4d7d26 100644 --- a/webkit/quota/quota_types.h +++ b/webkit/quota/quota_types.h @@ -22,19 +22,26 @@ enum StorageType { kStorageTypeUnknown, }; +// TODO(tzik): Add assertions to +// content/browser/renderer_host/quota_dispatcher_host.cc +// ref) third_party/WebKit/Source/WebCore/dom/ExceptionCode.h, enum QuotaStatusCode { kQuotaStatusOk = 0, - kQuotaErrorNotSupported = 9, - kQuotaErrorAbort = 20, + kQuotaErrorNotSupported = 9, // NOT_SUPPORTED_ERR + kQuotaErrorInvalidModification = 13, // INVALID_MODIFICATION_ERR + kQuotaErrorInvalidAccess = 15, // INVALID_ACCESS_ERR + kQuotaErrorAbort = 20, // ABORT_ERR kQuotaStatusUnknown = -1, }; // Common callback types that are used throughout in the quota module. typedef Callback1<int64>::Type UsageCallback; -typedef Callback1<int64>::Type QuotaCallback; +typedef Callback2<QuotaStatusCode, + int64>::Type QuotaCallback; typedef Callback2<const std::string& /* host */, int64>::Type HostUsageCallback; -typedef Callback2<const std::string& /* host */, +typedef Callback3<QuotaStatusCode, + const std::string& /* host */, int64>::Type HostQuotaCallback; // Simple template wrapper for a callback queue. @@ -93,8 +100,24 @@ class CallbackQueue2 : public CallbackQueueBase<CallbackType2> { } }; +template <typename CallbackType3, typename A1, typename A2, typename A3> +class CallbackQueue3 : public CallbackQueueBase<CallbackType3> { + public: + typedef typename CallbackQueueBase<CallbackType3>::Queue Queue; + // Runs the callbacks added to the queue and clears the queue. + void Run(A1 arg1, A2 arg2, A3 arg3) { + for (typename Queue::iterator iter = this->callbacks_.begin(); + iter != this->callbacks_.end(); ++iter) { + (*iter)->Run(arg1, arg2, arg3); + delete *iter; + } + this->callbacks_.clear(); + } +}; + typedef CallbackQueue1<UsageCallback*, int64> UsageCallbackQueue; -typedef CallbackQueue1<QuotaCallback*, int64> QuotaCallbackQueue; +typedef CallbackQueue2<QuotaCallback*, + QuotaStatusCode, int64> QuotaCallbackQueue; template <typename CallbackType, typename CallbackQueueType, typename KEY> class CallbackQueueMapBase { @@ -165,9 +188,35 @@ class CallbackQueueMap2 } }; +template <typename CallbackType3, typename KEY, + typename ARG1, typename ARG2, typename ARG3> +class CallbackQueueMap3 + : public CallbackQueueMapBase<CallbackType3, + CallbackQueue3<CallbackType3, + ARG1, ARG2, ARG3>, + KEY> { + public: + typedef typename CallbackQueueMapBase< + CallbackType3, + CallbackQueue3<CallbackType3, ARG1, ARG2, ARG3>, + KEY>::iterator iterator; + typedef CallbackQueue3<CallbackType3, ARG1, ARG2, ARG3> Queue; + + // Runs the callbacks added for the given |key| and clears the key + // from the map. + void Run(const KEY& key, ARG1 arg1, ARG2 arg2, ARG3 arg3) { + if (!this->HasCallbacks(key)) + return; + Queue& queue = this->callback_map_[key]; + queue.Run(arg1, arg2, arg3); + this->callback_map_.erase(key); + } +}; + typedef CallbackQueueMap2<HostUsageCallback*, std::string, const std::string&, int64> HostUsageCallbackMap; -typedef CallbackQueueMap2<HostUsageCallback*, std::string, +typedef CallbackQueueMap3<HostQuotaCallback*, std::string, + QuotaStatusCode, const std::string&, int64> HostQuotaCallbackMap; } // namespace quota |