diff options
author | michaeln@chromium.org <michaeln@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-01-21 02:39:40 +0000 |
---|---|---|
committer | michaeln@chromium.org <michaeln@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-01-21 02:39:40 +0000 |
commit | 9b7a0c551268395816959eb8df1c44086583824e (patch) | |
tree | 2be7bdf092e8776b0161b0eff83c0122626dc5bf /webkit/appcache | |
parent | 6f526b9ac1ec6fb252d3cfe1f625a694d76f643f (diff) | |
download | chromium_src-9b7a0c551268395816959eb8df1c44086583824e.zip chromium_src-9b7a0c551268395816959eb8df1c44086583824e.tar.gz chromium_src-9b7a0c551268395816959eb8df1c44086583824e.tar.bz2 |
Enforce a hard coded 5MB per origin quota for appcache storage.
TEST=yes
BUG=none
Review URL: http://codereview.chromium.org/554008
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@36723 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/appcache')
-rw-r--r-- | webkit/appcache/appcache_database.cc | 68 | ||||
-rw-r--r-- | webkit/appcache/appcache_database.h | 14 | ||||
-rw-r--r-- | webkit/appcache/appcache_database_unittest.cc | 68 | ||||
-rw-r--r-- | webkit/appcache/appcache_storage_impl.cc | 9 | ||||
-rw-r--r-- | webkit/appcache/appcache_storage_impl_unittest.cc | 4 | ||||
-rw-r--r-- | webkit/appcache/appcache_update_job.cc | 5 | ||||
-rw-r--r-- | webkit/appcache/mock_appcache_storage.cc | 6 | ||||
-rw-r--r-- | webkit/appcache/mock_appcache_storage_unittest.cc | 4 |
8 files changed, 151 insertions, 27 deletions
diff --git a/webkit/appcache/appcache_database.cc b/webkit/appcache/appcache_database.cc index 7182141..1553561 100644 --- a/webkit/appcache/appcache_database.cc +++ b/webkit/appcache/appcache_database.cc @@ -11,12 +11,14 @@ #include "base/auto_reset.h" #include "base/file_util.h" #include "base/logging.h" +#include "base/utf_string_conversions.h" #include "webkit/appcache/appcache_entry.h" +#include "webkit/database/quota_table.h" // Schema ------------------------------------------------------------------- namespace { -const int kCurrentVersion = 0; +const int kCurrentVersion = 1; const int kCompatibleVersion = 0; const char* kGroupsTable = "Groups"; @@ -144,17 +146,36 @@ AppCacheDatabase::~AppCacheDatabase() { void AppCacheDatabase::CloseConnection() { // We can't close the connection for an in-memory database w/o // losing all of the data, so we don't do that. - if (!db_file_path_.empty()) { - meta_table_.reset(); - db_.reset(); - } + if (!db_file_path_.empty()) + ResetConnectionAndTables(); } void AppCacheDatabase::Disable() { LOG(INFO) << "Disabling appcache database."; is_disabled_ = true; - meta_table_.reset(); - db_.reset(); + ResetConnectionAndTables(); +} + +int64 AppCacheDatabase::GetOriginUsage(const GURL& origin) { + std::vector<CacheRecord> records; + if (!FindCachesForOrigin(origin, &records)) + return 0; + + int64 origin_usage = 0; + std::vector<CacheRecord>::const_iterator iter = records.begin(); + while (iter != records.end()) { + origin_usage += iter->cache_size; + ++iter; + } + return origin_usage; +} + +int64 AppCacheDatabase::GetOriginQuota(const GURL& origin) { + if (!LazyOpen(false)) + return GetDefaultOriginQuota(); + int64 quota = quota_table_->GetOriginQuota( + UTF8ToUTF16(origin.spec().c_str())); + return (quota >= 0) ? quota : GetDefaultOriginQuota(); } bool AppCacheDatabase::FindOriginsWithGroups(std::set<GURL>* origins) { @@ -384,6 +405,23 @@ bool AppCacheDatabase::FindCacheForGroup(int64 group_id, CacheRecord* record) { return true; } +bool AppCacheDatabase::FindCachesForOrigin( + const GURL& origin, std::vector<CacheRecord>* records) { + DCHECK(records); + std::vector<GroupRecord> group_records; + if (!FindGroupsForOrigin(origin, &group_records)) + return false; + + CacheRecord cache_record; + std::vector<GroupRecord>::const_iterator iter = group_records.begin(); + while (iter != group_records.end()) { + if (FindCacheForGroup(iter->group_id, &cache_record)) + records->push_back(cache_record); + ++iter; + } + return true; +} + bool AppCacheDatabase::InsertCache(const CacheRecord* record) { if (!LazyOpen(true)) return false; @@ -921,6 +959,7 @@ bool AppCacheDatabase::LazyOpen(bool create_if_needed) { db_.reset(new sql::Connection); meta_table_.reset(new sql::MetaTable); + quota_table_.reset(new webkit_database::QuotaTable(db_.get())); bool opened = false; if (use_in_memory_db) { @@ -971,8 +1010,10 @@ bool AppCacheDatabase::CreateSchema() { if (!transaction.Begin()) return false; - if (!meta_table_->Init(db_.get(), kCurrentVersion, kCompatibleVersion)) + if (!meta_table_->Init(db_.get(), kCurrentVersion, kCompatibleVersion) || + !quota_table_->Init()) { return false; + } for (int i = 0; i < kTableCount; ++i) { std::string sql("CREATE TABLE "); @@ -1000,8 +1041,6 @@ bool AppCacheDatabase::CreateSchema() { } bool AppCacheDatabase::UpgradeSchema() { - DCHECK(false); // We don't have any upgrades yet since we're at version 0 - // Upgrade logic goes here // If there is no upgrade path for the version on disk to the current @@ -1009,12 +1048,17 @@ bool AppCacheDatabase::UpgradeSchema() { return DeleteExistingAndCreateNewDatabase(); } +void AppCacheDatabase::ResetConnectionAndTables() { + quota_table_.reset(); + meta_table_.reset(); + db_.reset(); +} + bool AppCacheDatabase::DeleteExistingAndCreateNewDatabase() { DCHECK(!db_file_path_.empty()); DCHECK(file_util::PathExists(db_file_path_)); - meta_table_.reset(); - db_.reset(); + ResetConnectionAndTables(); FilePath directory = db_file_path_.DirName(); if (!file_util::Delete(directory, true) || diff --git a/webkit/appcache/appcache_database.h b/webkit/appcache/appcache_database.h index 89fc330..97ed9e2 100644 --- a/webkit/appcache/appcache_database.h +++ b/webkit/appcache/appcache_database.h @@ -22,6 +22,10 @@ class Statement; class StatementID; } +namespace webkit_database { +class QuotaTable; +} + namespace appcache { class AppCacheDatabase { @@ -73,6 +77,10 @@ class AppCacheDatabase { void Disable(); bool is_disabled() const { return is_disabled_; } + int64 GetDefaultOriginQuota() { return 5 * 1024 * 1024; } + int64 GetOriginUsage(const GURL& origin); + int64 GetOriginQuota(const GURL& origin); + bool FindOriginsWithGroups(std::set<GURL>* origins); bool FindLastStorageIds( int64* last_group_id, int64* last_cache_id, int64* last_response_id, @@ -88,6 +96,8 @@ class AppCacheDatabase { bool FindCache(int64 cache_id, CacheRecord* record); bool FindCacheForGroup(int64 group_id, CacheRecord* record); + bool FindCachesForOrigin( + const GURL& origin, std::vector<CacheRecord>* records); bool InsertCache(const CacheRecord* record); bool DeleteCache(int64 cache_id); @@ -167,6 +177,8 @@ class AppCacheDatabase { bool CreateSchema(); bool UpgradeSchema(); + void ResetConnectionAndTables(); + // Deletes the existing database file and the entire directory containing // the database file including the disk cache in which response headers // and bodies are stored, and then creates a new database file. @@ -175,6 +187,7 @@ class AppCacheDatabase { FilePath db_file_path_; scoped_ptr<sql::Connection> db_; scoped_ptr<sql::MetaTable> meta_table_; + scoped_ptr<webkit_database::QuotaTable> quota_table_; bool is_disabled_; bool is_recreating_; @@ -186,6 +199,7 @@ class AppCacheDatabase { FRIEND_TEST(AppCacheDatabaseTest, OnlineWhiteListRecords); FRIEND_TEST(AppCacheDatabaseTest, ReCreate); FRIEND_TEST(AppCacheDatabaseTest, DeletableResponseIds); + FRIEND_TEST(AppCacheDatabaseTest, Quotas); DISALLOW_COPY_AND_ASSIGN(AppCacheDatabase); }; diff --git a/webkit/appcache/appcache_database_unittest.cc b/webkit/appcache/appcache_database_unittest.cc index b2a35c5..763cd9a 100644 --- a/webkit/appcache/appcache_database_unittest.cc +++ b/webkit/appcache/appcache_database_unittest.cc @@ -517,4 +517,72 @@ TEST(AppCacheDatabaseTest, DeletableResponseIds) { EXPECT_EQ(i + 5, ids[i]); } +TEST(AppCacheDatabaseTest, Quotas) { + const GURL kManifestUrl("http://blah/manifest"); + const GURL kManifestUrl2("http://blah/manifest2"); + const GURL kOrigin(kManifestUrl.GetOrigin()); + const GURL kOtherOriginManifestUrl("http://other/manifest"); + const GURL kOtherOrigin(kOtherOriginManifestUrl.GetOrigin()); + + const FilePath kEmptyPath; + AppCacheDatabase db(kEmptyPath); + EXPECT_TRUE(db.LazyOpen(true)); + + scoped_refptr<TestErrorDelegate> error_delegate(new TestErrorDelegate); + db.db_->set_error_delegate(error_delegate); + + std::vector<AppCacheDatabase::CacheRecord> cache_records; + EXPECT_EQ(db.GetDefaultOriginQuota(), db.GetOriginQuota(kOrigin)); + EXPECT_EQ(0, db.GetOriginUsage(kOrigin)); + EXPECT_TRUE(db.FindCachesForOrigin(kOrigin, &cache_records)); + EXPECT_TRUE(cache_records.empty()); + + AppCacheDatabase::GroupRecord group_record; + group_record.group_id = 1; + group_record.manifest_url = kManifestUrl; + group_record.origin = kOrigin; + EXPECT_TRUE(db.InsertGroup(&group_record)); + AppCacheDatabase::CacheRecord cache_record; + cache_record.cache_id = 1; + cache_record.group_id = 1; + cache_record.online_wildcard = true; + cache_record.update_time = kZeroTimeTicks; + cache_record.cache_size = 100; + EXPECT_TRUE(db.InsertCache(&cache_record)); + + EXPECT_EQ(100, db.GetOriginUsage(kOrigin)); + + group_record.group_id = 2; + group_record.manifest_url = kManifestUrl2; + group_record.origin = kOrigin; + EXPECT_TRUE(db.InsertGroup(&group_record)); + cache_record.cache_id = 2; + cache_record.group_id = 2; + cache_record.online_wildcard = true; + cache_record.update_time = kZeroTimeTicks; + cache_record.cache_size = 1000; + EXPECT_TRUE(db.InsertCache(&cache_record)); + + EXPECT_EQ(1100, db.GetOriginUsage(kOrigin)); + + group_record.group_id = 3; + group_record.manifest_url = kOtherOriginManifestUrl; + group_record.origin = kOtherOrigin; + EXPECT_TRUE(db.InsertGroup(&group_record)); + cache_record.cache_id = 3; + cache_record.group_id = 3; + cache_record.online_wildcard = true; + cache_record.update_time = kZeroTimeTicks; + cache_record.cache_size = 5000; + EXPECT_TRUE(db.InsertCache(&cache_record)); + + EXPECT_EQ(5000, db.GetOriginUsage(kOtherOrigin)); + + EXPECT_TRUE(db.FindCachesForOrigin(kOrigin, &cache_records)); + EXPECT_EQ(2U, cache_records.size()); + cache_records.clear(); + EXPECT_TRUE(db.FindCachesForOrigin(kOtherOrigin, &cache_records)); + EXPECT_EQ(1U, cache_records.size()); +} + } // namespace appcache diff --git a/webkit/appcache/appcache_storage_impl.cc b/webkit/appcache/appcache_storage_impl.cc index 6e91892..50d2aef 100644 --- a/webkit/appcache/appcache_storage_impl.cc +++ b/webkit/appcache/appcache_storage_impl.cc @@ -408,14 +408,18 @@ void AppCacheStorageImpl::StoreGroupAndCacheTask::Run() { database_->InsertEntryRecords(entry_records_) && database_->InsertFallbackNameSpaceRecords(fallback_namespace_records_)&& database_->InsertOnlineWhiteListRecords(online_whitelist_records_) && + (database_->GetOriginUsage(group_record_.origin) <= + database_->GetOriginQuota(group_record_.origin)) && transaction.Commit(); } void AppCacheStorageImpl::StoreGroupAndCacheTask::RunCompleted() { if (success_) { storage_->origins_with_groups_.insert(group_->manifest_url().GetOrigin()); - if (cache_ != group_->newest_complete_cache()) + if (cache_ != group_->newest_complete_cache()) { + cache_->set_complete(true); group_->AddCache(cache_); + } group_->AddNewlyDeletableResponseIds(&newly_deletable_response_ids_); } FOR_EACH_DELEGATE(delegates_, OnGroupAndNewestCacheStored(group_, success_)); @@ -826,8 +830,7 @@ void AppCacheStorageImpl::StoreGroupAndNewestCache( // whole new cache. The StoreGroupAndCacheTask as written will handle // the simple update case in a very heavy weight way (delete all and // the reinsert all over again). - DCHECK(group && delegate); - DCHECK(newest_cache && newest_cache->is_complete()); + DCHECK(group && delegate && newest_cache); scoped_refptr<StoreGroupAndCacheTask> task = new StoreGroupAndCacheTask(this, group, newest_cache); task->AddDelegate(GetOrCreateDelegateReference(delegate)); diff --git a/webkit/appcache/appcache_storage_impl_unittest.cc b/webkit/appcache/appcache_storage_impl_unittest.cc index cbb366a..fac6319 100644 --- a/webkit/appcache/appcache_storage_impl_unittest.cc +++ b/webkit/appcache/appcache_storage_impl_unittest.cc @@ -387,7 +387,6 @@ class AppCacheStorageImplTest : public testing::Test { group_ = new AppCacheGroup( service(), kManifestUrl, storage()->NewGroupId()); cache_ = new AppCache(service(), storage()->NewCacheId()); - cache_->set_complete(true); // Hold a ref to the cache simulate the UpdateJob holding that ref, // and hold a ref to the group to simulate the CacheHost holding that ref. @@ -400,6 +399,7 @@ class AppCacheStorageImplTest : public testing::Test { EXPECT_TRUE(delegate()->stored_group_success_); EXPECT_EQ(group_.get(), delegate()->stored_group_.get()); EXPECT_EQ(cache_.get(), group_->newest_complete_cache()); + EXPECT_TRUE(cache_->is_complete()); // Should have been stored in the database. AppCacheDatabase::GroupRecord group_record; @@ -422,7 +422,6 @@ class AppCacheStorageImplTest : public testing::Test { // And a newest unstored complete cache. cache2_ = new AppCache(service(), 2); - cache2_->set_complete(true); // Conduct the test. storage()->StoreGroupAndNewestCache(group_, cache2_, delegate()); @@ -433,6 +432,7 @@ class AppCacheStorageImplTest : public testing::Test { EXPECT_TRUE(delegate()->stored_group_success_); EXPECT_EQ(group_.get(), delegate()->stored_group_.get()); EXPECT_EQ(cache2_.get(), group_->newest_complete_cache()); + EXPECT_TRUE(cache2_->is_complete()); // The new cache should have been stored in the database. AppCacheDatabase::GroupRecord group_record; diff --git a/webkit/appcache/appcache_update_job.cc b/webkit/appcache/appcache_update_job.cc index f138f4d..fa65f71 100644 --- a/webkit/appcache/appcache_update_job.cc +++ b/webkit/appcache/appcache_update_job.cc @@ -553,10 +553,6 @@ void AppCacheUpdateJob::HandleUrlFetchCompleted(URLRequest* request) { LOG(INFO) << "Request status: " << request->status().status() << " os_error: " << request->status().os_error() << " response code: " << response_code; - - // TODO(jennb): Discard any stored data for this entry? May be unnecessary - // if handled automatically by storage layer. - if (entry.IsExplicit() || entry.IsFallback()) { internal_state_ = CACHE_FAILURE; CancelAllUrlFetches(); @@ -719,7 +715,6 @@ void AppCacheUpdateJob::OnManifestDataWriteComplete(int result) { void AppCacheUpdateJob::CompleteInprogressCache() { inprogress_cache_->set_update_time(base::TimeTicks::Now()); - inprogress_cache_->set_complete(true); service_->storage()->StoreGroupAndNewestCache(group_, inprogress_cache_, this); // async protect_new_cache_.swap(inprogress_cache_); diff --git a/webkit/appcache/mock_appcache_storage.cc b/webkit/appcache/mock_appcache_storage.cc index 750a8ce..a279ea0 100644 --- a/webkit/appcache/mock_appcache_storage.cc +++ b/webkit/appcache/mock_appcache_storage.cc @@ -72,8 +72,7 @@ void MockAppCacheStorage::LoadOrCreateGroup( void MockAppCacheStorage::StoreGroupAndNewestCache( AppCacheGroup* group, AppCache* newest_cache, Delegate* delegate) { - DCHECK(group && delegate); - DCHECK(newest_cache && newest_cache->is_complete()); + DCHECK(group && delegate && newest_cache); // Always make this operation look async. ScheduleTask(method_factory_.NewRunnableMethod( @@ -195,8 +194,9 @@ void MockAppCacheStorage::ProcessStoreGroupAndNewestCache( AddStoredGroup(group); if (newest_cache != group->newest_complete_cache()) { - AddStoredCache(newest_cache); + newest_cache->set_complete(true); group->AddCache(newest_cache); + AddStoredCache(newest_cache); // Copy the collection prior to removal, on final release // of a cache the group's collection will change. diff --git a/webkit/appcache/mock_appcache_storage_unittest.cc b/webkit/appcache/mock_appcache_storage_unittest.cc index 521c967..77e6558 100644 --- a/webkit/appcache/mock_appcache_storage_unittest.cc +++ b/webkit/appcache/mock_appcache_storage_unittest.cc @@ -209,7 +209,6 @@ TEST_F(MockAppCacheStorageTest, StoreNewGroup) { new AppCacheGroup(&service, manifest_url, 111); int64 cache_id = storage->NewCacheId(); scoped_refptr<AppCache> cache = new AppCache(&service, cache_id); - cache->set_complete(true); // Hold a ref to the cache simulate the UpdateJob holding that ref, // and hold a ref to the group to simulate the CacheHost holding that ref. @@ -226,6 +225,7 @@ TEST_F(MockAppCacheStorageTest, StoreNewGroup) { EXPECT_FALSE(storage->stored_caches_.empty()); EXPECT_FALSE(storage->stored_groups_.empty()); EXPECT_EQ(cache, group->newest_complete_cache()); + EXPECT_TRUE(cache->is_complete()); } TEST_F(MockAppCacheStorageTest, StoreExistingGroup) { @@ -247,7 +247,6 @@ TEST_F(MockAppCacheStorageTest, StoreExistingGroup) { storage->AddStoredCache(old_cache); int64 new_cache_id = storage->NewCacheId(); scoped_refptr<AppCache> new_cache = new AppCache(&service, new_cache_id); - new_cache->set_complete(true); // Hold our refs to simulate the UpdateJob holding these refs. // Conduct the test. @@ -269,6 +268,7 @@ TEST_F(MockAppCacheStorageTest, StoreExistingGroup) { EXPECT_FALSE(storage->IsCacheStored(old_cache)); EXPECT_TRUE(storage->IsCacheStored(new_cache)); EXPECT_EQ(new_cache.get(), group->newest_complete_cache()); + EXPECT_TRUE(new_cache->is_complete()); } TEST_F(MockAppCacheStorageTest, StoreExistingGroupExistingCache) { |