summaryrefslogtreecommitdiffstats
path: root/webkit/appcache
diff options
context:
space:
mode:
authormichaeln@chromium.org <michaeln@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-01-21 02:39:40 +0000
committermichaeln@chromium.org <michaeln@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-01-21 02:39:40 +0000
commit9b7a0c551268395816959eb8df1c44086583824e (patch)
tree2be7bdf092e8776b0161b0eff83c0122626dc5bf /webkit/appcache
parent6f526b9ac1ec6fb252d3cfe1f625a694d76f643f (diff)
downloadchromium_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.cc68
-rw-r--r--webkit/appcache/appcache_database.h14
-rw-r--r--webkit/appcache/appcache_database_unittest.cc68
-rw-r--r--webkit/appcache/appcache_storage_impl.cc9
-rw-r--r--webkit/appcache/appcache_storage_impl_unittest.cc4
-rw-r--r--webkit/appcache/appcache_update_job.cc5
-rw-r--r--webkit/appcache/mock_appcache_storage.cc6
-rw-r--r--webkit/appcache/mock_appcache_storage_unittest.cc4
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) {