diff options
author | michaeln@google.com <michaeln@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-02-26 00:28:43 +0000 |
---|---|---|
committer | michaeln@google.com <michaeln@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-02-26 00:28:43 +0000 |
commit | 19eb8015c483fff874bf1eddb80bd26cf4167f33 (patch) | |
tree | be896411dde17d24eb8dbcd67e7b4c5cad2ef1b6 | |
parent | f02074331bddc7d89b20e6b3a8fb934e6891207c (diff) | |
download | chromium_src-19eb8015c483fff874bf1eddb80bd26cf4167f33.zip chromium_src-19eb8015c483fff874bf1eddb80bd26cf4167f33.tar.gz chromium_src-19eb8015c483fff874bf1eddb80bd26cf4167f33.tar.bz2 |
Add an accessor for an ExtensionSpecialStoragePolicy to the Profile class
and use it in the extension service, data remover, and storage subsystems.
BUG=52357
TEST=extension_service_unittest.cc
Review URL: http://codereview.chromium.org/6551028
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@76126 0039d316-1c4b-4281-b951-d872f2087c98
40 files changed, 354 insertions, 555 deletions
diff --git a/chrome/browser/browsing_data_remover.cc b/chrome/browser/browsing_data_remover.cc index 6361e30..f926126 100644 --- a/chrome/browser/browsing_data_remover.cc +++ b/chrome/browser/browsing_data_remover.cc @@ -12,6 +12,7 @@ #include "chrome/browser/browser_process.h" #include "chrome/browser/download/download_manager.h" #include "chrome/browser/extensions/extension_service.h" +#include "chrome/browser/extensions/extension_special_storage_policy.h" #include "chrome/browser/history/history.h" #include "chrome/browser/io_thread.h" #include "chrome/browser/metrics/user_metrics.h" @@ -49,6 +50,7 @@ BrowsingDataRemover::BrowsingDataRemover(Profile* profile, base::Time delete_begin, base::Time delete_end) : profile_(profile), + special_storage_policy_(profile->GetExtensionSpecialStoragePolicy()), delete_begin_(delete_begin), delete_end_(delete_end), ALLOW_THIS_IN_INITIALIZER_LIST(database_cleared_callback_( @@ -76,6 +78,7 @@ BrowsingDataRemover::BrowsingDataRemover(Profile* profile, TimePeriod time_period, base::Time delete_end) : profile_(profile), + special_storage_policy_(profile->GetExtensionSpecialStoragePolicy()), delete_begin_(CalculateBeginDeleteTime(time_period)), delete_end_(delete_end), ALLOW_THIS_IN_INITIALIZER_LIST(database_cleared_callback_( @@ -108,25 +111,6 @@ void BrowsingDataRemover::Remove(int remove_mask) { DCHECK(!removing_); removing_ = true; - std::vector<GURL> origin_whitelist; - ExtensionService* extensions_service = profile_->GetExtensionService(); - if (extensions_service && extensions_service->HasInstalledExtensions()) { - std::map<GURL, int> whitelist_map = - extensions_service->protected_storage_map(); - for (std::map<GURL, int>::const_iterator iter = whitelist_map.begin(); - iter != whitelist_map.end(); ++iter) { - origin_whitelist.push_back(iter->first); - } - } - - std::vector<string16> webkit_db_whitelist; - for (size_t i = 0; i < origin_whitelist.size(); ++i) { - webkit_db_whitelist.push_back( - webkit_database::DatabaseUtil::GetOriginIdentifier( - origin_whitelist[i])); - } - - if (remove_mask & REMOVE_HISTORY) { HistoryService* history_service = profile_->GetHistoryService(Profile::EXPLICIT_ACCESS); @@ -194,8 +178,9 @@ void BrowsingDataRemover::Remove(int remove_mask) { // REMOVE_COOKIES is actually "cookies and other site data" so we make sure // to remove other data such local databases, STS state, etc. - profile_->GetWebKitContext()->DeleteDataModifiedSince( - delete_begin_, chrome::kExtensionScheme, webkit_db_whitelist); + // We assume the end time is now. + + profile_->GetWebKitContext()->DeleteDataModifiedSince(delete_begin_); database_tracker_ = profile_->GetDatabaseTracker(); if (database_tracker_.get()) { @@ -204,26 +189,24 @@ void BrowsingDataRemover::Remove(int remove_mask) { BrowserThread::FILE, FROM_HERE, NewRunnableMethod( this, - &BrowsingDataRemover::ClearDatabasesOnFILEThread, - delete_begin_, - webkit_db_whitelist)); + &BrowsingDataRemover::ClearDatabasesOnFILEThread)); } + waiting_for_clear_appcache_ = true; BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, NewRunnableMethod( - profile_->GetTransportSecurityState(), - &net::TransportSecurityState::DeleteSince, - delete_begin_)); + this, + &BrowsingDataRemover::ClearAppCacheOnIOThread)); + + // TODO(michaeln): delete temporary file system data too - waiting_for_clear_appcache_ = true; BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, NewRunnableMethod( - this, - &BrowsingDataRemover::ClearAppCacheOnIOThread, - delete_begin_, // we assume end time == now - origin_whitelist)); + profile_->GetTransportSecurityState(), + &net::TransportSecurityState::DeleteSince, + delete_begin_)); } if (remove_mask & REMOVE_PASSWORDS) { @@ -464,13 +447,11 @@ void BrowsingDataRemover::OnClearedDatabases(int rv) { NotifyAndDeleteIfDone(); } -void BrowsingDataRemover::ClearDatabasesOnFILEThread(base::Time delete_begin, - const std::vector<string16>& webkit_db_whitelist) { +void BrowsingDataRemover::ClearDatabasesOnFILEThread() { // This function should be called on the FILE thread. DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); - int rv = database_tracker_->DeleteDataModifiedSince( - delete_begin, webkit_db_whitelist, &database_cleared_callback_); + delete_begin_, &database_cleared_callback_); if (rv != net::ERR_IO_PENDING) OnClearedDatabases(rv); } @@ -483,17 +464,13 @@ void BrowsingDataRemover::OnClearedAppCache() { DCHECK(result); return; } - appcache_whitelist_.clear(); waiting_for_clear_appcache_ = false; NotifyAndDeleteIfDone(); } -void BrowsingDataRemover::ClearAppCacheOnIOThread(base::Time delete_begin, - const std::vector<GURL>& origin_whitelist) { +void BrowsingDataRemover::ClearAppCacheOnIOThread() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); DCHECK(waiting_for_clear_appcache_); - - appcache_whitelist_ = origin_whitelist; appcache_info_ = new appcache::AppCacheInfoCollection; GetAppCacheService()->GetAllAppCacheInfo( appcache_info_, &appcache_got_info_callback_); @@ -507,14 +484,8 @@ void BrowsingDataRemover::OnGotAppCacheInfo(int rv) { for (InfoByOrigin::const_iterator origin = appcache_info_->infos_by_origin.begin(); origin != appcache_info_->infos_by_origin.end(); ++origin) { - bool found_in_whitelist = false; - for (size_t i = 0; i < appcache_whitelist_.size(); ++i) { - if (appcache_whitelist_[i] == origin->first) - found_in_whitelist = true; - } - if (found_in_whitelist) + if (special_storage_policy_->IsStorageProtected(origin->first)) continue; - for (AppCacheInfoVector::const_iterator info = origin->second.begin(); info != origin->second.end(); ++info) { if (info->creation_time > delete_begin_) { diff --git a/chrome/browser/browsing_data_remover.h b/chrome/browser/browsing_data_remover.h index f9667ca..56d19dd7 100644 --- a/chrome/browser/browsing_data_remover.h +++ b/chrome/browser/browsing_data_remover.h @@ -16,6 +16,7 @@ #include "content/browser/appcache/chrome_appcache_service.h" #include "content/browser/cancelable_request.h" +class ExtensionSpecialStoragePolicy; class IOThread; class PluginDataRemover; class Profile; @@ -138,19 +139,15 @@ class BrowsingDataRemover : public NotificationObserver, // NotifyAndDeleteIfDone. void OnClearedDatabases(int rv); - // Invoked on the FILE thread to delete HTML5 databases. Ignores any within - // the |webkit_db_whitelist|. - void ClearDatabasesOnFILEThread(base::Time delete_begin, - const std::vector<string16>& webkit_db_whitelist); + // Invoked on the FILE thread to delete HTML5 databases. + void ClearDatabasesOnFILEThread(); // Callback when the appcache has been cleared. Invokes // NotifyAndDeleteIfDone. void OnClearedAppCache(); - // Invoked on the IO thread to delete from the AppCache, ignoring data from - // any origins within the |origin_whitelist|. - void ClearAppCacheOnIOThread(base::Time delete_begin, - const std::vector<GURL>& origin_whitelist); + // Invoked on the IO thread to delete from the AppCache. + void ClearAppCacheOnIOThread(); // Lower level helpers. void OnGotAppCacheInfo(int rv); @@ -174,6 +171,9 @@ class BrowsingDataRemover : public NotificationObserver, // Profile we're to remove from. Profile* profile_; + // 'Protected' origins are not subject to data removal. + scoped_refptr<ExtensionSpecialStoragePolicy> special_storage_policy_; + // Start time to delete from. const base::Time delete_begin_; @@ -193,7 +193,6 @@ class BrowsingDataRemover : public NotificationObserver, net::CompletionCallbackImpl<BrowsingDataRemover> appcache_got_info_callback_; net::CompletionCallbackImpl<BrowsingDataRemover> appcache_deleted_callback_; scoped_refptr<appcache::AppCacheInfoCollection> appcache_info_; - std::vector<GURL> appcache_whitelist_; int appcaches_to_be_deleted_count_; // Used to delete data from the HTTP caches. diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc index 5a19f48..b3bb620 100644 --- a/chrome/browser/extensions/extension_service.cc +++ b/chrome/browser/extensions/extension_service.cc @@ -37,6 +37,7 @@ #include "chrome/browser/extensions/extension_management_api.h" #include "chrome/browser/extensions/extension_process_manager.h" #include "chrome/browser/extensions/extension_processes_api.h" +#include "chrome/browser/extensions/extension_special_storage_policy.h" #include "chrome/browser/extensions/extension_updater.h" #include "chrome/browser/extensions/extension_web_ui.h" #include "chrome/browser/extensions/extension_webnavigation_api.h" @@ -106,35 +107,6 @@ ManifestReloadReason ShouldReloadExtensionManifest(const ExtensionInfo& info) { return NOT_NEEDED; } -void GetExplicitOriginsInExtent(const Extension* extension, - std::vector<GURL>* origins) { - typedef std::vector<URLPattern> PatternList; - std::set<GURL> set; - const PatternList& patterns = extension->web_extent().patterns(); - for (PatternList::const_iterator pattern = patterns.begin(); - pattern != patterns.end(); ++pattern) { - if (pattern->match_subdomains() || pattern->match_all_urls()) - continue; - // Wildcard URL schemes won't parse into a valid GURL, so explicit schemes - // must be used. - PatternList explicit_patterns = pattern->ConvertToExplicitSchemes(); - for (PatternList::const_iterator explicit_p = explicit_patterns.begin(); - explicit_p != explicit_patterns.end(); ++explicit_p) { - GURL origin = GURL(explicit_p->GetAsString()).GetOrigin(); - if (origin.is_valid()) { - set.insert(origin); - } else { - NOTREACHED(); - } - } - } - - for (std::set<GURL>::const_iterator unique = set.begin(); - unique != set.end(); ++unique) { - origins->push_back(*unique); - } -} - } // namespace PendingExtensionInfo::PendingExtensionInfo( @@ -1090,15 +1062,8 @@ void ExtensionService::NotifyExtensionLoaded(const Extension* extension) { // extension. if (profile_) { profile_->RegisterExtensionWithRequestContexts(extension); - - // Check if this permission requires unlimited storage quota - if (extension->HasApiPermission(Extension::kUnlimitedStoragePermission)) - GrantUnlimitedStorage(extension); - - // If the extension is an app, protect its local storage from - // "Clear browsing data." - if (extension->is_app()) - GrantProtectedStorage(extension); + profile_->GetExtensionSpecialStoragePolicy()-> + GrantRightsForExtension(extension); } NotificationService::current()->Notify( @@ -1117,106 +1082,8 @@ void ExtensionService::NotifyExtensionUnloaded( if (profile_) { profile_->UnregisterExtensionWithRequestContexts(extension); - - // Check if this permission required unlimited storage quota, reset its - // in-memory quota. - if (extension->HasApiPermission(Extension::kUnlimitedStoragePermission)) - RevokeUnlimitedStorage(extension); - - // If this is an app, then stop protecting its storage so it can be deleted. - if (extension->is_app()) - RevokeProtectedStorage(extension); - } -} - -void ExtensionService::GrantProtectedStorage(const Extension* extension) { - DCHECK(extension->is_app()) << "Only Apps are allowed protected storage."; - std::vector<GURL> origins; - GetExplicitOriginsInExtent(extension, &origins); - for (size_t i = 0; i < origins.size(); ++i) - ++protected_storage_map_[origins[i]]; -} - -void ExtensionService::RevokeProtectedStorage(const Extension* extension) { - DCHECK(extension->is_app()) << "Attempting to revoke protected storage from " - << " a non-app extension."; - std::vector<GURL> origins; - GetExplicitOriginsInExtent(extension, &origins); - for (size_t i = 0; i < origins.size(); ++i) { - const GURL& origin = origins[i]; - DCHECK(protected_storage_map_[origin] > 0); - if (--protected_storage_map_[origin] <= 0) - protected_storage_map_.erase(origin); - } -} - -void ExtensionService::GrantUnlimitedStorage(const Extension* extension) { - DCHECK(extension->HasApiPermission(Extension::kUnlimitedStoragePermission)); - std::vector<GURL> origins; - GetExplicitOriginsInExtent(extension, &origins); - origins.push_back(extension->url()); - - for (size_t i = 0; i < origins.size(); ++i) { - const GURL& origin = origins[i]; - if (++unlimited_storage_map_[origin] == 1) { - string16 origin_identifier = - webkit_database::DatabaseUtil::GetOriginIdentifier(origin); - BrowserThread::PostTask( - BrowserThread::FILE, FROM_HERE, - NewRunnableMethod( - profile_->GetDatabaseTracker(), - &webkit_database::DatabaseTracker::SetOriginQuotaInMemory, - origin_identifier, - kint64max)); - BrowserThread::PostTask( - BrowserThread::IO, FROM_HERE, - NewRunnableMethod( - profile_->GetAppCacheService(), - &ChromeAppCacheService::SetOriginQuotaInMemory, - origin, - kint64max)); - BrowserThread::PostTask( - BrowserThread::IO, FROM_HERE, - NewRunnableMethod( - profile_->GetFileSystemContext(), - &fileapi::FileSystemContext::SetOriginQuotaUnlimited, - origin)); - } - } -} - -void ExtensionService::RevokeUnlimitedStorage(const Extension* extension) { - DCHECK(extension->HasApiPermission(Extension::kUnlimitedStoragePermission)); - std::vector<GURL> origins; - GetExplicitOriginsInExtent(extension, &origins); - origins.push_back(extension->url()); - - for (size_t i = 0; i < origins.size(); ++i) { - const GURL& origin = origins[i]; - DCHECK(unlimited_storage_map_[origin] > 0); - if (--unlimited_storage_map_[origin] == 0) { - unlimited_storage_map_.erase(origin); - string16 origin_identifier = - webkit_database::DatabaseUtil::GetOriginIdentifier(origin); - BrowserThread::PostTask( - BrowserThread::FILE, FROM_HERE, - NewRunnableMethod( - profile_->GetDatabaseTracker(), - &webkit_database::DatabaseTracker::ResetOriginQuotaInMemory, - origin_identifier)); - BrowserThread::PostTask( - BrowserThread::IO, FROM_HERE, - NewRunnableMethod( - profile_->GetAppCacheService(), - &ChromeAppCacheService::ResetOriginQuotaInMemory, - origin)); - BrowserThread::PostTask( - BrowserThread::IO, FROM_HERE, - NewRunnableMethod( - profile_->GetFileSystemContext(), - &fileapi::FileSystemContext::ResetOriginQuotaUnlimited, - origin)); - } + profile_->GetExtensionSpecialStoragePolicy()-> + RevokeRightsForExtension(extension); } } @@ -1454,6 +1321,10 @@ void ExtensionService::UnloadExtension( } void ExtensionService::UnloadAllExtensions() { + if (profile_) { + profile_->GetExtensionSpecialStoragePolicy()-> + RevokeRightsForAllExtensions(); + } extensions_.clear(); disabled_extensions_.clear(); terminated_extension_ids_.clear(); diff --git a/chrome/browser/extensions/extension_service.h b/chrome/browser/extensions/extension_service.h index 67a59be..402f644 100644 --- a/chrome/browser/extensions/extension_service.h +++ b/chrome/browser/extensions/extension_service.h @@ -408,10 +408,6 @@ class ExtensionService return browser_event_router_.get(); } - const std::map<GURL, int>& protected_storage_map() const { - return protected_storage_map_; - } - // Notify the frontend that there was an error loading an extension. // This method is public because ExtensionServiceBackend can post to here. void ReportExtensionLoadError(const FilePath& extension_path, @@ -516,12 +512,6 @@ class ExtensionService // Helper method. Loads extension from prefs. void LoadInstalledExtension(const ExtensionInfo& info, bool write_to_prefs); - // Helper methods to configure the storage services accordingly. - void GrantProtectedStorage(const Extension* extension); - void RevokeProtectedStorage(const Extension* extension); - void GrantUnlimitedStorage(const Extension* extension); - void RevokeUnlimitedStorage(const Extension* extension); - // The profile this ExtensionService is part of. Profile* profile_; @@ -603,18 +593,6 @@ class ExtensionService typedef std::vector<ComponentExtensionInfo> RegisteredComponentExtensions; RegisteredComponentExtensions component_extension_manifests_; - // Collection of origins we've granted unlimited storage to. This is a - // map from origin to the number of extensions requiring unlimited - // storage within that origin. - typedef std::map<GURL, int> UnlimitedStorageMap; - UnlimitedStorageMap unlimited_storage_map_; - - // Collection of origins whose storage is protected by "Clear browsing data." - // A map from origin to the number of Apps currently installed and therefore - // intrinsically protected. - typedef std::map<GURL, int> ProtectedStorageMap; - ProtectedStorageMap protected_storage_map_; - // Manages the installation of default apps and the promotion of them in the // app launcher. DefaultApps default_apps_; diff --git a/chrome/browser/extensions/extension_service_unittest.cc b/chrome/browser/extensions/extension_service_unittest.cc index c5d35e6..b2b1623 100644 --- a/chrome/browser/extensions/extension_service_unittest.cc +++ b/chrome/browser/extensions/extension_service_unittest.cc @@ -26,6 +26,7 @@ #include "chrome/browser/extensions/extension_creator.h" #include "chrome/browser/extensions/extension_error_reporter.h" #include "chrome/browser/extensions/extension_service.h" +#include "chrome/browser/extensions/extension_special_storage_policy.h" #include "chrome/browser/extensions/external_extension_provider_interface.h" #include "chrome/browser/extensions/external_extension_provider_impl.h" #include "chrome/browser/extensions/external_pref_extension_loader.h" @@ -341,11 +342,13 @@ class ExtensionTestingProfile : public TestingProfile { appcache_service_ = new ChromeAppCacheService; BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, - NewRunnableMethod(appcache_service_.get(), - &ChromeAppCacheService::InitializeOnIOThread, - GetPath(), IsOffTheRecord(), - make_scoped_refptr(GetHostContentSettingsMap()), - false)); + NewRunnableMethod( + appcache_service_.get(), + &ChromeAppCacheService::InitializeOnIOThread, + GetPath(), IsOffTheRecord(), + make_scoped_refptr(GetHostContentSettingsMap()), + make_scoped_refptr(GetExtensionSpecialStoragePolicy()), + false)); } return appcache_service_; } @@ -353,7 +356,7 @@ class ExtensionTestingProfile : public TestingProfile { virtual fileapi::FileSystemContext* GetFileSystemContext() { if (!file_system_context_) file_system_context_ = CreateFileSystemContext( - GetPath(), IsOffTheRecord()); + GetPath(), IsOffTheRecord(), GetExtensionSpecialStoragePolicy()); return file_system_context_; } @@ -1674,13 +1677,11 @@ TEST_F(ExtensionServiceTest, UpdateApps) { TEST_F(ExtensionServiceTest, InstallAppsWithUnlimtedStorage) { InitializeEmptyExtensionService(); EXPECT_TRUE(service_->extensions()->empty()); - EXPECT_TRUE(service_->unlimited_storage_map_.empty()); FilePath extensions_path; ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); extensions_path = extensions_path.AppendASCII("extensions"); int pref_count = 0; - ChromeAppCacheService* appcache_service = profile_->GetAppCacheService(); // Install app1 with unlimited storage. PackAndInstallExtension(extensions_path.AppendASCII("app1"), true); @@ -1693,9 +1694,8 @@ TEST_F(ExtensionServiceTest, InstallAppsWithUnlimtedStorage) { EXPECT_TRUE(extension->web_extent().ContainsURL( extension->GetFullLaunchURL())); const GURL origin1(extension->GetFullLaunchURL().GetOrigin()); - EXPECT_EQ(kint64max, - appcache_service->storage()->GetOriginQuotaInMemory(origin1)); - EXPECT_FALSE(service_->unlimited_storage_map_.empty()); + EXPECT_TRUE(profile_->GetExtensionSpecialStoragePolicy()-> + IsStorageUnlimited(origin1)); // Install app2 from the same origin with unlimited storage. PackAndInstallExtension(extensions_path.AppendASCII("app2"), true); @@ -1709,32 +1709,30 @@ TEST_F(ExtensionServiceTest, InstallAppsWithUnlimtedStorage) { extension->GetFullLaunchURL())); const GURL origin2(extension->GetFullLaunchURL().GetOrigin()); EXPECT_EQ(origin1, origin2); - EXPECT_EQ(kint64max, - appcache_service->storage()->GetOriginQuotaInMemory(origin2)); - EXPECT_FALSE(service_->unlimited_storage_map_.empty()); + EXPECT_TRUE(profile_->GetExtensionSpecialStoragePolicy()-> + IsStorageUnlimited(origin2)); + // Uninstall one of them, unlimited storage should still be granted // to the origin. service_->UninstallExtension(id1, false); loop_.RunAllPending(); EXPECT_EQ(1u, service_->extensions()->size()); - EXPECT_EQ(kint64max, - appcache_service->storage()->GetOriginQuotaInMemory(origin1)); - EXPECT_FALSE(service_->unlimited_storage_map_.empty()); + EXPECT_TRUE(profile_->GetExtensionSpecialStoragePolicy()-> + IsStorageUnlimited(origin1)); + // Uninstall the other, unlimited storage should be revoked. service_->UninstallExtension(id2, false); loop_.RunAllPending(); EXPECT_EQ(0u, service_->extensions()->size()); - EXPECT_EQ(-1L, - appcache_service->storage()->GetOriginQuotaInMemory(origin2)); - EXPECT_TRUE(service_->unlimited_storage_map_.empty()); + EXPECT_FALSE(profile_->GetExtensionSpecialStoragePolicy()-> + IsStorageUnlimited(origin2)); } TEST_F(ExtensionServiceTest, InstallAppsAndCheckStorageProtection) { InitializeEmptyExtensionService(); EXPECT_TRUE(service_->extensions()->empty()); - EXPECT_TRUE(service_->protected_storage_map_.empty()); FilePath extensions_path; ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); @@ -1747,9 +1745,9 @@ TEST_F(ExtensionServiceTest, InstallAppsAndCheckStorageProtection) { const Extension* extension = service_->extensions()->at(0); EXPECT_TRUE(extension->is_app()); const std::string id1 = extension->id(); - EXPECT_FALSE(service_->protected_storage_map_.empty()); const GURL origin1(extension->GetFullLaunchURL().GetOrigin()); - ASSERT_EQ(1, service_->protected_storage_map_[origin1]); + EXPECT_TRUE(profile_->GetExtensionSpecialStoragePolicy()-> + IsStorageProtected(origin1)); // App 4 has a different origin (maps.google.com). PackAndInstallExtension(extensions_path.AppendASCII("app4"), true); @@ -1757,21 +1755,23 @@ TEST_F(ExtensionServiceTest, InstallAppsAndCheckStorageProtection) { ASSERT_EQ(2u, service_->extensions()->size()); extension = service_->extensions()->at(1); const std::string id2 = extension->id(); - EXPECT_FALSE(service_->protected_storage_map_.empty()); const GURL origin2(extension->GetFullLaunchURL().GetOrigin()); ASSERT_NE(origin1, origin2); - ASSERT_EQ(1, service_->protected_storage_map_[origin2]); + EXPECT_TRUE(profile_->GetExtensionSpecialStoragePolicy()-> + IsStorageProtected(origin2)); service_->UninstallExtension(id1, false); loop_.RunAllPending(); EXPECT_EQ(1u, service_->extensions()->size()); - EXPECT_FALSE(service_->protected_storage_map_.empty()); service_->UninstallExtension(id2, false); loop_.RunAllPending(); EXPECT_TRUE(service_->extensions()->empty()); - EXPECT_TRUE(service_->protected_storage_map_.empty()); + EXPECT_FALSE(profile_->GetExtensionSpecialStoragePolicy()-> + IsStorageProtected(origin1)); + EXPECT_FALSE(profile_->GetExtensionSpecialStoragePolicy()-> + IsStorageProtected(origin2)); } // Test that when an extension version is reinstalled, nothing happens. diff --git a/chrome/browser/profiles/profile.cc b/chrome/browser/profiles/profile.cc index db1579b..3d202cd 100644 --- a/chrome/browser/profiles/profile.cc +++ b/chrome/browser/profiles/profile.cc @@ -22,6 +22,7 @@ #include "chrome/browser/extensions/extension_message_service.h" #include "chrome/browser/extensions/extension_pref_store.h" #include "chrome/browser/extensions/extension_process_manager.h" +#include "chrome/browser/extensions/extension_special_storage_policy.h" #include "chrome/browser/net/pref_proxy_config_service.h" #include "chrome/browser/notifications/desktop_notification_service.h" #include "chrome/browser/prefs/pref_service.h" @@ -157,9 +158,7 @@ class OffTheRecordProfileImpl : public Profile, : profile_(real_profile), prefs_(real_profile->GetOffTheRecordPrefs()), ALLOW_THIS_IN_INITIALIZER_LIST(io_data_(this)), - start_time_(Time::Now()), - db_tracker_(new webkit_database::DatabaseTracker( - profile_->GetPath(), true)) { + start_time_(Time::Now()) { extension_process_manager_.reset(ExtensionProcessManager::Create(this)); BrowserList::AddObserver(this); @@ -183,11 +182,12 @@ class OffTheRecordProfileImpl : public Profile, Source<Profile>(this), NotificationService::NoDetails()); // Clean up all DB files/directories - BrowserThread::PostTask( - BrowserThread::FILE, FROM_HERE, - NewRunnableMethod( - db_tracker_.get(), - &webkit_database::DatabaseTracker::DeleteIncognitoDBDirectory)); + if (db_tracker_) + BrowserThread::PostTask( + BrowserThread::FILE, FROM_HERE, + NewRunnableMethod( + db_tracker_.get(), + &webkit_database::DatabaseTracker::DeleteIncognitoDBDirectory)); BrowserList::RemoveObserver(this); @@ -227,16 +227,22 @@ class OffTheRecordProfileImpl : public Profile, appcache_service_ = new ChromeAppCacheService; BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, - NewRunnableMethod(appcache_service_.get(), - &ChromeAppCacheService::InitializeOnIOThread, - GetPath(), IsOffTheRecord(), - make_scoped_refptr(GetHostContentSettingsMap()), - false)); + NewRunnableMethod( + appcache_service_.get(), + &ChromeAppCacheService::InitializeOnIOThread, + GetPath(), IsOffTheRecord(), + make_scoped_refptr(GetHostContentSettingsMap()), + make_scoped_refptr(GetExtensionSpecialStoragePolicy()), + false)); } return appcache_service_; } virtual webkit_database::DatabaseTracker* GetDatabaseTracker() { + if (!db_tracker_.get()) { + db_tracker_ = new webkit_database::DatabaseTracker( + GetPath(), IsOffTheRecord(), GetExtensionSpecialStoragePolicy()); + } return db_tracker_; } @@ -284,6 +290,10 @@ class OffTheRecordProfileImpl : public Profile, return GetOriginalProfile()->GetExtensionIOEventRouter(); } + virtual ExtensionSpecialStoragePolicy* GetExtensionSpecialStoragePolicy() { + return GetOriginalProfile()->GetExtensionSpecialStoragePolicy(); + } + virtual SSLHostState* GetSSLHostState() { if (!ssl_host_state_.get()) ssl_host_state_.reset(new SSLHostState()); @@ -380,7 +390,7 @@ class OffTheRecordProfileImpl : public Profile, virtual fileapi::FileSystemContext* GetFileSystemContext() { if (!file_system_context_) file_system_context_ = CreateFileSystemContext( - GetPath(), IsOffTheRecord()); + GetPath(), IsOffTheRecord(), GetExtensionSpecialStoragePolicy()); DCHECK(file_system_context_.get()); return file_system_context_.get(); } diff --git a/chrome/browser/profiles/profile.h b/chrome/browser/profiles/profile.h index 42252da..c45b072 100644 --- a/chrome/browser/profiles/profile.h +++ b/chrome/browser/profiles/profile.h @@ -68,6 +68,7 @@ class ExtensionMessageService; class ExtensionPrefValueMap; class ExtensionProcessManager; class ExtensionService; +class ExtensionSpecialStoragePolicy; class FaviconService; class FilePath; class FindBarState; @@ -229,6 +230,10 @@ class Profile { // Accessor. The instance is created at startup. virtual ExtensionIOEventRouter* GetExtensionIOEventRouter() = 0; + // Accessor. The instance is created upon first access. + virtual ExtensionSpecialStoragePolicy* + GetExtensionSpecialStoragePolicy() = 0; + // Retrieves a pointer to the SSLHostState associated with this profile. // The SSLHostState is lazily created the first time that this method is // called. diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc index 4b51e82..f639147 100644 --- a/chrome/browser/profiles/profile_impl.cc +++ b/chrome/browser/profiles/profile_impl.cc @@ -36,6 +36,7 @@ #include "chrome/browser/extensions/extension_pref_store.h" #include "chrome/browser/extensions/extension_process_manager.h" #include "chrome/browser/extensions/extension_service.h" +#include "chrome/browser/extensions/extension_special_storage_policy.h" #include "chrome/browser/extensions/user_script_master.h" #include "chrome/browser/favicon_service.h" #include "chrome/browser/geolocation/geolocation_content_settings_map.h" @@ -642,11 +643,13 @@ ChromeAppCacheService* ProfileImpl::GetAppCacheService() { appcache_service_ = new ChromeAppCacheService; BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, - NewRunnableMethod(appcache_service_.get(), - &ChromeAppCacheService::InitializeOnIOThread, - GetPath(), IsOffTheRecord(), - make_scoped_refptr(GetHostContentSettingsMap()), - clear_local_state_on_exit_)); + NewRunnableMethod( + appcache_service_.get(), + &ChromeAppCacheService::InitializeOnIOThread, + GetPath(), IsOffTheRecord(), + make_scoped_refptr(GetHostContentSettingsMap()), + make_scoped_refptr(GetExtensionSpecialStoragePolicy()), + clear_local_state_on_exit_)); } return appcache_service_; } @@ -654,7 +657,7 @@ ChromeAppCacheService* ProfileImpl::GetAppCacheService() { webkit_database::DatabaseTracker* ProfileImpl::GetDatabaseTracker() { if (!db_tracker_) { db_tracker_ = new webkit_database::DatabaseTracker( - GetPath(), IsOffTheRecord()); + GetPath(), IsOffTheRecord(), GetExtensionSpecialStoragePolicy()); } return db_tracker_; } @@ -709,6 +712,13 @@ ExtensionIOEventRouter* ProfileImpl::GetExtensionIOEventRouter() { return extension_io_event_router_.get(); } +ExtensionSpecialStoragePolicy* + ProfileImpl::GetExtensionSpecialStoragePolicy() { + if (!extension_special_storage_policy_.get()) + extension_special_storage_policy_ = new ExtensionSpecialStoragePolicy(); + return extension_special_storage_policy_.get(); +} + SSLHostState* ProfileImpl::GetSSLHostState() { if (!ssl_host_state_.get()) ssl_host_state_.reset(new SSLHostState()); @@ -1065,7 +1075,7 @@ PersonalDataManager* ProfileImpl::GetPersonalDataManager() { fileapi::FileSystemContext* ProfileImpl::GetFileSystemContext() { if (!file_system_context_.get()) file_system_context_ = CreateFileSystemContext( - GetPath(), IsOffTheRecord()); + GetPath(), IsOffTheRecord(), GetExtensionSpecialStoragePolicy()); DCHECK(file_system_context_.get()); return file_system_context_.get(); } diff --git a/chrome/browser/profiles/profile_impl.h b/chrome/browser/profiles/profile_impl.h index 5eea88cb..ef35079 100644 --- a/chrome/browser/profiles/profile_impl.h +++ b/chrome/browser/profiles/profile_impl.h @@ -63,6 +63,7 @@ class ProfileImpl : public Profile, virtual ExtensionMessageService* GetExtensionMessageService(); virtual ExtensionEventRouter* GetExtensionEventRouter(); virtual ExtensionIOEventRouter* GetExtensionIOEventRouter(); + virtual ExtensionSpecialStoragePolicy* GetExtensionSpecialStoragePolicy(); virtual FaviconService* GetFaviconService(ServiceAccessType sat); virtual HistoryService* GetHistoryService(ServiceAccessType sat); virtual HistoryService* GetHistoryServiceWithoutCreating(); @@ -201,6 +202,8 @@ class ProfileImpl : public Profile, scoped_refptr<ExtensionMessageService> extension_message_service_; scoped_ptr<ExtensionEventRouter> extension_event_router_; scoped_refptr<ExtensionIOEventRouter> extension_io_event_router_; + scoped_refptr<ExtensionSpecialStoragePolicy> + extension_special_storage_policy_; scoped_ptr<SSLHostState> ssl_host_state_; scoped_refptr<net::TransportSecurityState> transport_security_state_; diff --git a/chrome/test/testing_profile.cc b/chrome/test/testing_profile.cc index a9baafd..892a29e 100644 --- a/chrome/test/testing_profile.cc +++ b/chrome/test/testing_profile.cc @@ -18,6 +18,7 @@ #include "chrome/browser/custom_handlers/protocol_handler_registry.h" #include "chrome/browser/extensions/extension_pref_value_map.h" #include "chrome/browser/extensions/extension_service.h" +#include "chrome/browser/extensions/extension_special_storage_policy.h" #include "chrome/browser/favicon_service.h" #include "chrome/browser/geolocation/geolocation_content_settings_map.h" #include "chrome/browser/geolocation/geolocation_permission_context.h" @@ -396,8 +397,10 @@ ChromeAppCacheService* TestingProfile::GetAppCacheService() { } webkit_database::DatabaseTracker* TestingProfile::GetDatabaseTracker() { - if (!db_tracker_) - db_tracker_ = new webkit_database::DatabaseTracker(GetPath(), false); + if (!db_tracker_) { + db_tracker_ = new webkit_database::DatabaseTracker( + GetPath(), false, GetExtensionSpecialStoragePolicy()); + } return db_tracker_; } @@ -433,6 +436,13 @@ ExtensionIOEventRouter* TestingProfile::GetExtensionIOEventRouter() { return NULL; } +ExtensionSpecialStoragePolicy* +TestingProfile::GetExtensionSpecialStoragePolicy() { + if (!extension_special_storage_policy_) + extension_special_storage_policy_ = new ExtensionSpecialStoragePolicy(); + return extension_special_storage_policy_; +} + SSLHostState* TestingProfile::GetSSLHostState() { return NULL; } diff --git a/chrome/test/testing_profile.h b/chrome/test/testing_profile.h index a8a610a..5517553 100644 --- a/chrome/test/testing_profile.h +++ b/chrome/test/testing_profile.h @@ -28,6 +28,7 @@ class DesktopNotificationService; class ExtensionPrefs; class ExtensionPrefStore; class ExtensionPrefValueMap; +class ExtensionSpecialStoragePolicy; class FaviconService; class FindBarState; class GeolocationContentSettingsMap; @@ -153,6 +154,7 @@ class TestingProfile : public Profile { virtual ExtensionMessageService* GetExtensionMessageService(); virtual ExtensionEventRouter* GetExtensionEventRouter(); virtual ExtensionIOEventRouter* GetExtensionIOEventRouter(); + virtual ExtensionSpecialStoragePolicy* GetExtensionSpecialStoragePolicy(); virtual SSLHostState* GetSSLHostState(); virtual net::TransportSecurityState* GetTransportSecurityState(); virtual FaviconService* GetFaviconService(ServiceAccessType access); @@ -392,6 +394,9 @@ class TestingProfile : public Profile { scoped_ptr<ExtensionPrefValueMap> extension_pref_value_map_; + scoped_refptr<ExtensionSpecialStoragePolicy> + extension_special_storage_policy_; + // The proxy prefs tracker. scoped_refptr<PrefProxyConfigTracker> pref_proxy_config_tracker_; diff --git a/content/browser/appcache/chrome_appcache_service.cc b/content/browser/appcache/chrome_appcache_service.cc index 68c7ece..5f6107a 100644 --- a/content/browser/appcache/chrome_appcache_service.cc +++ b/content/browser/appcache/chrome_appcache_service.cc @@ -38,6 +38,7 @@ ChromeAppCacheService::ChromeAppCacheService() void ChromeAppCacheService::InitializeOnIOThread( const FilePath& profile_path, bool is_incognito, scoped_refptr<HostContentSettingsMap> content_settings_map, + scoped_refptr<quota::SpecialStoragePolicy> special_storage_policy, bool clear_local_state_on_exit) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); @@ -57,6 +58,7 @@ void ChromeAppCacheService::InitializeOnIOThread( Initialize(cache_path_, BrowserThread::GetMessageLoopProxyForThread(BrowserThread::CACHE)); set_appcache_policy(this); + set_special_storage_policy(special_storage_policy); } ChromeAppCacheService::~ChromeAppCacheService() { @@ -69,20 +71,8 @@ ChromeAppCacheService::~ChromeAppCacheService() { } } -void ChromeAppCacheService::SetOriginQuotaInMemory( - const GURL& origin, int64 quota) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - if (storage()) - storage()->SetOriginQuotaInMemory(origin, quota); -} - -void ChromeAppCacheService::ResetOriginQuotaInMemory(const GURL& origin) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - if (storage()) - storage()->ResetOriginQuotaInMemory(origin); -} - void ChromeAppCacheService::SetClearLocalStateOnExit(bool clear_local_state) { + // TODO(michaeln): How is 'protected' status granted to apps in this case? if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, diff --git a/content/browser/appcache/chrome_appcache_service.h b/content/browser/appcache/chrome_appcache_service.h index 8081122..ad77477 100644 --- a/content/browser/appcache/chrome_appcache_service.h +++ b/content/browser/appcache/chrome_appcache_service.h @@ -12,6 +12,7 @@ #include "content/browser/browser_thread.h" #include "webkit/appcache/appcache_policy.h" #include "webkit/appcache/appcache_service.h" +#include "webkit/quota/special_storage_policy.h" class ChromeURLRequestContext; class FilePath; @@ -36,13 +37,9 @@ class ChromeAppCacheService void InitializeOnIOThread( const FilePath& profile_path, bool is_incognito, scoped_refptr<HostContentSettingsMap> content_settings_map, + scoped_refptr<quota::SpecialStoragePolicy> special_storage_policy, bool clear_local_state_on_exit); - // Helpers used by the extension service to grant and revoke - // unlimited storage to app extensions. - void SetOriginQuotaInMemory(const GURL& origin, int64 quota); - void ResetOriginQuotaInMemory(const GURL& origin); - void SetClearLocalStateOnExit(bool clear_local_state); private: diff --git a/content/browser/appcache/chrome_appcache_service_unittest.cc b/content/browser/appcache/chrome_appcache_service_unittest.cc index 0c5c512..fb6b80e 100644 --- a/content/browser/appcache/chrome_appcache_service_unittest.cc +++ b/content/browser/appcache/chrome_appcache_service_unittest.cc @@ -49,6 +49,7 @@ TEST_F(ChromeAppCacheServiceTest, KeepOnDestruction) { &ChromeAppCacheService::InitializeOnIOThread, temp_dir_.path(), false, scoped_refptr<HostContentSettingsMap>(NULL), + scoped_refptr<quota::SpecialStoragePolicy>(NULL), false)); // Make the steps needed to initialize the storage of AppCache data. message_loop_.RunAllPending(); @@ -79,6 +80,7 @@ TEST_F(ChromeAppCacheServiceTest, RemoveOnDestruction) { &ChromeAppCacheService::InitializeOnIOThread, temp_dir_.path(), false, scoped_refptr<HostContentSettingsMap>(NULL), + scoped_refptr<quota::SpecialStoragePolicy>(NULL), true)); // Make the steps needed to initialize the storage of AppCache data. message_loop_.RunAllPending(); diff --git a/content/browser/file_system/browser_file_system_helper.cc b/content/browser/file_system/browser_file_system_helper.cc index 81666f0..960d838 100644 --- a/content/browser/file_system/browser_file_system_helper.cc +++ b/content/browser/file_system/browser_file_system_helper.cc @@ -10,10 +10,12 @@ #include "content/browser/browser_thread.h" scoped_refptr<fileapi::FileSystemContext> CreateFileSystemContext( - const FilePath& profile_path, bool is_incognito) { + const FilePath& profile_path, bool is_incognito, + quota::SpecialStoragePolicy* special_storage_policy) { return new fileapi::FileSystemContext( BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE), BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO), + special_storage_policy, profile_path, is_incognito, CommandLine::ForCurrentProcess()->HasSwitch( diff --git a/content/browser/file_system/browser_file_system_helper.h b/content/browser/file_system/browser_file_system_helper.h index 55c6e3a..84eb26c 100644 --- a/content/browser/file_system/browser_file_system_helper.h +++ b/content/browser/file_system/browser_file_system_helper.h @@ -9,9 +9,14 @@ #include "base/scoped_ptr.h" #include "webkit/fileapi/file_system_context.h" +namespace quota { +class SpecialStoragePolicy; +} + // Helper method that returns FileSystemContext constructed for // the browser process. scoped_refptr<fileapi::FileSystemContext> CreateFileSystemContext( - const FilePath& profile_path, bool is_incognito); + const FilePath& profile_path, bool is_incognito, + quota::SpecialStoragePolicy* special_storage_policy); #endif // CONTENT_BROWSER_FILE_SYSTEM_BROWSER_FILE_SYSTEM_HELPER_H_ diff --git a/content/browser/in_process_webkit/dom_storage_context.cc b/content/browser/in_process_webkit/dom_storage_context.cc index c39d75a..184cb24 100644 --- a/content/browser/in_process_webkit/dom_storage_context.cc +++ b/content/browser/in_process_webkit/dom_storage_context.cc @@ -9,6 +9,7 @@ #include "base/file_path.h" #include "base/file_util.h" #include "base/string_util.h" +#include "chrome/browser/extensions/extension_special_storage_policy.h" #include "chrome/common/dom_storage_common.h" #include "chrome/common/url_constants.h" #include "content/browser/browser_thread.h" @@ -17,14 +18,14 @@ #include "content/browser/in_process_webkit/webkit_context.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebSecurityOrigin.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebString.h" +#include "webkit/quota/special_storage_policy.h" #include "webkit/glue/webkit_glue.h" using WebKit::WebSecurityOrigin; namespace { -void ClearLocalState(const FilePath& domstorage_path, - const char* url_scheme_to_be_skipped) { +void ClearLocalState(const FilePath& domstorage_path) { file_util::FileEnumerator file_enumerator( domstorage_path, false, file_util::FileEnumerator::FILES); for (FilePath file_path = file_enumerator.Next(); !file_path.empty(); @@ -33,8 +34,9 @@ void ClearLocalState(const FilePath& domstorage_path, WebSecurityOrigin web_security_origin = WebSecurityOrigin::createFromDatabaseIdentifier( webkit_glue::FilePathToWebString(file_path.BaseName())); + // TODO(michaeln): how is protected status provided to apps at this time? if (!EqualsASCII(web_security_origin.protocol(), - url_scheme_to_be_skipped)) { + chrome::kExtensionScheme)) { file_util::Delete(file_path, false); } } @@ -49,11 +51,14 @@ const FilePath::CharType DOMStorageContext::kLocalStorageDirectory[] = const FilePath::CharType DOMStorageContext::kLocalStorageExtension[] = FILE_PATH_LITERAL(".localstorage"); -DOMStorageContext::DOMStorageContext(WebKitContext* webkit_context) +DOMStorageContext::DOMStorageContext( + WebKitContext* webkit_context, + quota::SpecialStoragePolicy* special_storage_policy) : last_storage_area_id_(0), last_session_storage_namespace_id_on_ui_thread_(kLocalStorageNamespaceId), last_session_storage_namespace_id_on_io_thread_(kLocalStorageNamespaceId), - clear_local_state_on_exit_(false) { + clear_local_state_on_exit_(false), + special_storage_policy_(special_storage_policy) { data_path_ = webkit_context->data_path(); } @@ -71,8 +76,7 @@ DOMStorageContext::~DOMStorageContext() { // where no clean up is needed. if (clear_local_state_on_exit_ && BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)) { - ClearLocalState(data_path_.Append(kLocalStorageDirectory), - chrome::kExtensionScheme); + ClearLocalState(data_path_.Append(kLocalStorageDirectory)); } } @@ -176,10 +180,7 @@ void DOMStorageContext::PurgeMemory() { local_storage->PurgeMemory(); } -void DOMStorageContext::DeleteDataModifiedSince( - const base::Time& cutoff, - const char* url_scheme_to_be_skipped, - const std::vector<string16>& protected_origins) { +void DOMStorageContext::DeleteDataModifiedSince(const base::Time& cutoff) { // Make sure that we don't delete a database that's currently being accessed // by unloading all of the databases temporarily. PurgeMemory(); @@ -189,16 +190,9 @@ void DOMStorageContext::DeleteDataModifiedSince( file_util::FileEnumerator::FILES); for (FilePath path = file_enumerator.Next(); !path.value().empty(); path = file_enumerator.Next()) { - WebSecurityOrigin web_security_origin = - WebSecurityOrigin::createFromDatabaseIdentifier( - webkit_glue::FilePathToWebString(path.BaseName())); - if (EqualsASCII(web_security_origin.protocol(), url_scheme_to_be_skipped)) - continue; - - std::vector<string16>::const_iterator find_iter = - std::find(protected_origins.begin(), protected_origins.end(), - web_security_origin.databaseIdentifier()); - if (find_iter != protected_origins.end()) + GURL origin(WebSecurityOrigin::createFromDatabaseIdentifier( + webkit_glue::FilePathToWebString(path.BaseName())).toString()); + if (special_storage_policy_->IsStorageProtected(origin)) continue; file_util::FileEnumerator::FindInfo find_info; diff --git a/content/browser/in_process_webkit/dom_storage_context.h b/content/browser/in_process_webkit/dom_storage_context.h index 6810453..c865d8a 100644 --- a/content/browser/in_process_webkit/dom_storage_context.h +++ b/content/browser/in_process_webkit/dom_storage_context.h @@ -10,6 +10,7 @@ #include <set> #include "base/file_path.h" +#include "base/ref_counted.h" #include "base/string16.h" #include "base/time.h" @@ -18,6 +19,10 @@ class DOMStorageMessageFilter; class DOMStorageNamespace; class WebKitContext; +namespace quota { +class SpecialStoragePolicy; +} + // This is owned by WebKitContext and is all the dom storage information that's // shared by all the DOMStorageMessageFilters that share the same profile. The // specifics of responsibilities are fairly well documented here and in @@ -27,7 +32,8 @@ class WebKitContext; // NOTE: Virtual methods facilitate mocking functions for testing. class DOMStorageContext { public: - explicit DOMStorageContext(WebKitContext* webkit_context); + DOMStorageContext(WebKitContext* webkit_context, + quota::SpecialStoragePolicy* special_storage_policy); virtual ~DOMStorageContext(); // Invalid storage id. No storage session will ever report this value. @@ -70,10 +76,9 @@ class DOMStorageContext { virtual void PurgeMemory(); // Delete any local storage files that have been touched since the cutoff - // date that's supplied. - void DeleteDataModifiedSince(const base::Time& cutoff, - const char* url_scheme_to_be_skipped, - const std::vector<string16>& protected_origins); + // date that's supplied. Protected origins, per the SpecialStoragePolicy, + // are not deleted by this method. + void DeleteDataModifiedSince(const base::Time& cutoff); // Deletes a single local storage file. void DeleteLocalStorageFile(const FilePath& file_path); @@ -151,6 +156,8 @@ class DOMStorageContext { typedef std::map<int64, DOMStorageNamespace*> StorageNamespaceMap; StorageNamespaceMap storage_namespace_map_; + scoped_refptr<quota::SpecialStoragePolicy> special_storage_policy_; + DISALLOW_IMPLICIT_CONSTRUCTORS(DOMStorageContext); }; diff --git a/content/browser/in_process_webkit/webkit_context.cc b/content/browser/in_process_webkit/webkit_context.cc index b19fdbf..41cd58e 100644 --- a/content/browser/in_process_webkit/webkit_context.cc +++ b/content/browser/in_process_webkit/webkit_context.cc @@ -5,6 +5,7 @@ #include "content/browser/in_process_webkit/webkit_context.h" #include "base/command_line.h" +#include "chrome/browser/extensions/extension_special_storage_policy.h" #include "chrome/browser/profiles/profile.h" #include "content/browser/browser_thread.h" @@ -13,7 +14,8 @@ WebKitContext::WebKitContext(Profile* profile, bool clear_local_state_on_exit) is_incognito_(profile->IsOffTheRecord()), clear_local_state_on_exit_(clear_local_state_on_exit), ALLOW_THIS_IN_INITIALIZER_LIST( - dom_storage_context_(new DOMStorageContext(this))), + dom_storage_context_(new DOMStorageContext( + this, profile->GetExtensionSpecialStoragePolicy()))), ALLOW_THIS_IN_INITIALIZER_LIST( indexed_db_context_(new IndexedDBContext(this))) { } @@ -52,20 +54,16 @@ void WebKitContext::PurgeMemory() { dom_storage_context_->PurgeMemory(); } -void WebKitContext::DeleteDataModifiedSince( - const base::Time& cutoff, - const char* url_scheme_to_be_skipped, - const std::vector<string16>& protected_origins) { +void WebKitContext::DeleteDataModifiedSince(const base::Time& cutoff) { if (!BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)) { BrowserThread::PostTask( BrowserThread::WEBKIT, FROM_HERE, NewRunnableMethod(this, &WebKitContext::DeleteDataModifiedSince, - cutoff, url_scheme_to_be_skipped, protected_origins)); + cutoff)); return; } - dom_storage_context_->DeleteDataModifiedSince( - cutoff, url_scheme_to_be_skipped, protected_origins); + dom_storage_context_->DeleteDataModifiedSince(cutoff); } diff --git a/content/browser/in_process_webkit/webkit_context.h b/content/browser/in_process_webkit/webkit_context.h index 5f647ef..c912c62 100644 --- a/content/browser/in_process_webkit/webkit_context.h +++ b/content/browser/in_process_webkit/webkit_context.h @@ -57,9 +57,7 @@ class WebKitContext // Tell all children (where applicable) to delete any objects that were // last modified on or after the following time. - void DeleteDataModifiedSince(const base::Time& cutoff, - const char* url_scheme_to_be_skipped, - const std::vector<string16>& protected_origins); + void DeleteDataModifiedSince(const base::Time& cutoff); // Delete the session storage namespace associated with this id. Can be // called from any thread. diff --git a/content/browser/in_process_webkit/webkit_context_unittest.cc b/content/browser/in_process_webkit/webkit_context_unittest.cc index 811a3d0..9998142 100644 --- a/content/browser/in_process_webkit/webkit_context_unittest.cc +++ b/content/browser/in_process_webkit/webkit_context_unittest.cc @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "chrome/browser/extensions/extension_special_storage_policy.h" #include "chrome/test/testing_profile.h" #include "content/browser/browser_thread.h" #include "content/browser/in_process_webkit/dom_storage_context.h" @@ -11,7 +12,7 @@ class MockDOMStorageContext : public DOMStorageContext { public: explicit MockDOMStorageContext(WebKitContext* webkit_context) - : DOMStorageContext(webkit_context), + : DOMStorageContext(webkit_context, new ExtensionSpecialStoragePolicy), purge_count_(0) { } diff --git a/webkit/appcache/appcache_service.cc b/webkit/appcache/appcache_service.cc index 1eb4673..e748434 100644 --- a/webkit/appcache/appcache_service.cc +++ b/webkit/appcache/appcache_service.cc @@ -10,6 +10,7 @@ #include "webkit/appcache/appcache_backend_impl.h" #include "webkit/appcache/appcache_entry.h" #include "webkit/appcache/appcache_storage_impl.h" +#include "webkit/quota/special_storage_policy.h" namespace appcache { @@ -216,6 +217,10 @@ void AppCacheService::DeleteAppCacheGroup(const GURL& manifest_url, helper->Start(); } +void AppCacheService::set_special_storage_policy( + quota::SpecialStoragePolicy* policy) { + special_storage_policy_ = policy; +} void AppCacheService::RegisterBackend( AppCacheBackendImpl* backend_impl) { DCHECK(backends_.find(backend_impl->process_id()) == backends_.end()); diff --git a/webkit/appcache/appcache_service.h b/webkit/appcache/appcache_service.h index 6a0c931..b36951f 100644 --- a/webkit/appcache/appcache_service.h +++ b/webkit/appcache/appcache_service.h @@ -27,6 +27,10 @@ namespace base { class MessageLoopProxy; } +namespace quota { +class SpecialStoragePolicy; +} + namespace appcache { class AppCacheBackendImpl; @@ -95,6 +99,11 @@ class AppCacheService { appcache_policy_ = policy; } + quota::SpecialStoragePolicy* special_storage_policy() const { + return special_storage_policy_.get(); + } + void set_special_storage_policy(quota::SpecialStoragePolicy* policy); + // Each child process in chrome uses a distinct backend instance. // See chrome/browser/AppCacheDispatcherHost. void RegisterBackend(AppCacheBackendImpl* backend_impl); @@ -117,6 +126,7 @@ class AppCacheService { AppCachePolicy* appcache_policy_; scoped_ptr<AppCacheStorage> storage_; + scoped_refptr<quota::SpecialStoragePolicy> special_storage_policy_; PendingAsyncHelpers pending_helpers_; BackendMap backends_; // One 'backend' per child process. // Context for use during cache updates. diff --git a/webkit/appcache/appcache_storage.cc b/webkit/appcache/appcache_storage.cc index 01c18f1..a30088f 100644 --- a/webkit/appcache/appcache_storage.cc +++ b/webkit/appcache/appcache_storage.cc @@ -87,25 +87,5 @@ void AppCacheStorage::LoadResponseInfo( info_load->StartIfNeeded(); } -void AppCacheStorage::SetOriginQuotaInMemory(const GURL& origin, int64 quota) { - DCHECK(quota >= 0); - DCHECK(origin == origin.GetOrigin()); - if (IsSchemeSupported(origin)) - in_memory_quotas_[origin] = quota; -} - -void AppCacheStorage::ResetOriginQuotaInMemory(const GURL& origin) { - DCHECK(origin == origin.GetOrigin()); - in_memory_quotas_.erase(origin); -} - -int64 AppCacheStorage::GetOriginQuotaInMemory(const GURL& origin) { - DCHECK(origin == origin.GetOrigin()); - QuotaMap::const_iterator found = in_memory_quotas_.find(origin); - if (found == in_memory_quotas_.end()) - return -1; - return found->second; -} - } // namespace appcache diff --git a/webkit/appcache/appcache_storage.h b/webkit/appcache/appcache_storage.h index 1d64ef9..1767127 100644 --- a/webkit/appcache/appcache_storage.h +++ b/webkit/appcache/appcache_storage.h @@ -167,11 +167,6 @@ class AppCacheStorage { virtual void PurgeMemory() = 0; - // Maintain a collection of quota overrides in memory. - void SetOriginQuotaInMemory(const GURL& origin, int64 quota); - void ResetOriginQuotaInMemory(const GURL& origin); - int64 GetOriginQuotaInMemory(const GURL& origin); - // Generates unique storage ids for different object types. int64 NewCacheId() { return ++last_cache_id_; @@ -283,11 +278,6 @@ class AppCacheStorage { return ++last_response_id_; } - // Store quotas for extensions in memory, in order to prevent writing a row - // to quota_table_ every time an extention is loaded. - typedef std::map<GURL, int64> QuotaMap; - QuotaMap in_memory_quotas_; - // The last storage id used for different object types. int64 last_cache_id_; int64 last_group_id_; diff --git a/webkit/appcache/appcache_storage_impl.cc b/webkit/appcache/appcache_storage_impl.cc index 8d21105..0f78b77 100644 --- a/webkit/appcache/appcache_storage_impl.cc +++ b/webkit/appcache/appcache_storage_impl.cc @@ -22,6 +22,7 @@ #include "webkit/appcache/appcache_response.h" #include "webkit/appcache/appcache_service.h" #include "webkit/appcache/appcache_thread.h" +#include "webkit/quota/special_storage_policy.h" namespace { // Helper with no return value for use with NewRunnableFunction. @@ -410,8 +411,7 @@ AppCacheStorageImpl::StoreGroupAndCacheTask::StoreGroupAndCacheTask( AppCacheStorageImpl* storage, AppCacheGroup* group, AppCache* newest_cache) : StoreOrLoadTask(storage), group_(group), cache_(newest_cache), success_(false), would_exceed_quota_(false), - quota_override_( - storage->GetOriginQuotaInMemory(group->manifest_url().GetOrigin())) { + quota_override_(-1) { group_record_.group_id = group->group_id(); group_record_.manifest_url = group->manifest_url(); group_record_.origin = group_record_.manifest_url.GetOrigin(); @@ -419,6 +419,12 @@ AppCacheStorageImpl::StoreGroupAndCacheTask::StoreGroupAndCacheTask( group, &cache_record_, &entry_records_, &fallback_namespace_records_, &online_whitelist_records_); + + if (storage->service()->special_storage_policy() && + storage->service()->special_storage_policy()->IsStorageUnlimited( + group_record_.origin)) { + quota_override_ = kint64max; + } } void AppCacheStorageImpl::StoreGroupAndCacheTask::Run() { diff --git a/webkit/appcache/appcache_storage_impl_unittest.cc b/webkit/appcache/appcache_storage_impl_unittest.cc index 2f25b65..1d874bc 100644 --- a/webkit/appcache/appcache_storage_impl_unittest.cc +++ b/webkit/appcache/appcache_storage_impl_unittest.cc @@ -547,19 +547,14 @@ class AppCacheStorageImplTest : public testing::Test { PushNextTask(NewRunnableMethod( this, &AppCacheStorageImplTest::Verify_FailStoreGroup)); - // Set a low quota to force a failure. - const GURL kOrigin(kManifestUrl.GetOrigin()); - EXPECT_EQ(-1L, storage()->GetOriginQuotaInMemory(kOrigin)); - storage()->SetOriginQuotaInMemory(kManifestUrl.GetOrigin(), 0); - EXPECT_EQ(0L, storage()->GetOriginQuotaInMemory(kOrigin)); - // Setup some preconditions. Create a group and newest cache that - // appear to be "unstored". + // appear to be "unstored" and big enough to exceed the 5M limit. + const int64 kTooBig = 10 * 1024 * 1024; // 10M group_ = new AppCacheGroup( service(), kManifestUrl, storage()->NewGroupId()); cache_ = new AppCache(service(), storage()->NewCacheId()); cache_->AddEntry(kManifestUrl, - AppCacheEntry(AppCacheEntry::MANIFEST, 1, 1024)); + AppCacheEntry(AppCacheEntry::MANIFEST, 1, kTooBig)); // 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. @@ -578,10 +573,6 @@ class AppCacheStorageImplTest : public testing::Test { EXPECT_FALSE(database()->FindGroup(group_->group_id(), &group_record)); EXPECT_FALSE(database()->FindCache(cache_->cache_id(), &cache_record)); - const GURL kOrigin(kManifestUrl.GetOrigin()); - storage()->ResetOriginQuotaInMemory(kOrigin); - EXPECT_EQ(-1L, storage()->GetOriginQuotaInMemory(kOrigin)); - TestFinished(); } diff --git a/webkit/database/database_tracker.cc b/webkit/database/database_tracker.cc index 46e9dc1..20f5971 100644 --- a/webkit/database/database_tracker.cc +++ b/webkit/database/database_tracker.cc @@ -17,8 +17,10 @@ #include "base/string_number_conversions.h" #include "base/utf_string_conversions.h" #include "net/base/net_errors.h" +#include "webkit/database/database_util.h" #include "webkit/database/databases_table.h" #include "webkit/database/quota_table.h" +#include "webkit/quota/special_storage_policy.h" namespace { @@ -78,8 +80,10 @@ string16 OriginInfo::GetDatabaseDescription( OriginInfo::OriginInfo(const string16& origin, int64 total_size, int64 quota) : origin_(origin), total_size_(total_size), quota_(quota) {} -DatabaseTracker::DatabaseTracker(const FilePath& profile_path, - bool is_incognito) +DatabaseTracker::DatabaseTracker( + const FilePath& profile_path, + bool is_incognito, + quota::SpecialStoragePolicy* special_storage_policy) : is_initialized_(false), is_incognito_(is_incognito), shutting_down_(false), @@ -91,6 +95,7 @@ DatabaseTracker::DatabaseTracker(const FilePath& profile_path, databases_table_(NULL), meta_table_(NULL), default_quota_(5 * 1024 * 1024), + special_storage_policy_(special_storage_policy), incognito_origin_directories_generator_(0) { } @@ -289,16 +294,6 @@ void DatabaseTracker::SetOriginQuota(const string16& origin_identifier, } } -void DatabaseTracker::SetOriginQuotaInMemory(const string16& origin_identifier, - int64 new_quota) { - DCHECK(new_quota >= 0); - in_memory_quotas_[origin_identifier] = new_quota; -} - -void DatabaseTracker::ResetOriginQuotaInMemory( - const string16& origin_identifier) { - in_memory_quotas_.erase(origin_identifier); -} bool DatabaseTracker::DeleteClosedDatabase(const string16& origin_identifier, const string16& database_name) { @@ -464,8 +459,12 @@ DatabaseTracker::CachedOriginInfo* DatabaseTracker::GetCachedOriginInfo( origin_info.SetDatabaseDescription(it->database_name, it->description); } - if (in_memory_quotas_.find(origin_identifier) != in_memory_quotas_.end()) { - origin_info.SetQuota(in_memory_quotas_[origin_identifier]); + if (special_storage_policy_.get() && + special_storage_policy_->IsStorageUnlimited( + DatabaseUtil::GetOriginFromIdentifier(origin_identifier))) { + // TODO(michaeln): handle the case where it changes status sometime after + // the cached origin_info has been established + origin_info.SetQuota(kint64max); } else { int64 origin_quota = quota_table_->GetOriginQuota(origin_identifier); if (origin_quota > 0) @@ -554,7 +553,6 @@ int DatabaseTracker::DeleteDatabase(const string16& origin_identifier, int DatabaseTracker::DeleteDataModifiedSince( const base::Time& cutoff, - const std::vector<string16>& protected_origins, net::CompletionCallback* callback) { if (!LazyInit()) return net::ERR_FAILED; @@ -563,19 +561,17 @@ int DatabaseTracker::DeleteDataModifiedSince( deletion_callbacks_.find(callback) == deletion_callbacks_.end()); DatabaseSet to_be_deleted; - std::vector<string16> origins; - if (!databases_table_->GetAllOrigins(&origins)) + std::vector<string16> origins_identifiers; + if (!databases_table_->GetAllOrigins(&origins_identifiers)) return net::ERR_FAILED; int rv = net::OK; - for (std::vector<string16>::const_iterator ori = origins.begin(); - ori != origins.end(); ++ori) { - if (StartsWith(*ori, ASCIIToUTF16(kExtensionOriginIdentifierPrefix), true)) - continue; - - std::vector<string16>::const_iterator find_iter = - std::find(protected_origins.begin(), protected_origins.end(), *ori); - if (find_iter != protected_origins.end()) + for (std::vector<string16>::const_iterator ori = origins_identifiers.begin(); + ori != origins_identifiers.end(); ++ori) { + if (special_storage_policy_.get() && + special_storage_policy_->IsStorageProtected( + DatabaseUtil::GetOriginFromIdentifier(*ori))) { continue; + } std::vector<DatabaseDetails> details; if (!databases_table_->GetAllDatabaseDetailsForOrigin(*ori, &details)) diff --git a/webkit/database/database_tracker.h b/webkit/database/database_tracker.h index 08a66b2..140753e 100644 --- a/webkit/database/database_tracker.h +++ b/webkit/database/database_tracker.h @@ -25,6 +25,10 @@ class Connection; class MetaTable; } +namespace quota { +class SpecialStoragePolicy; +} + namespace webkit_database { extern const FilePath::CharType kDatabaseDirectoryName[]; @@ -83,7 +87,8 @@ class DatabaseTracker virtual ~Observer() {} }; - DatabaseTracker(const FilePath& profile_path, bool is_incognito); + DatabaseTracker(const FilePath& profile_path, bool is_incognito, + quota::SpecialStoragePolicy* special_storage_policy); void DatabaseOpened(const string16& origin_identifier, const string16& database_name, @@ -108,9 +113,6 @@ class DatabaseTracker bool GetAllOriginsInfo(std::vector<OriginInfo>* origins_info); void SetOriginQuota(const string16& origin_identifier, int64 new_quota); - void SetOriginQuotaInMemory(const string16& origin_identifier, - int64 new_quota); - void ResetOriginQuotaInMemory(const string16& origin_identifier); int64 GetDefaultQuota() { return default_quota_; } // Sets the default quota for all origins. Should be used in tests only. @@ -130,9 +132,9 @@ class DatabaseTracker // supplied, omitting any that match IDs within |protected_origins|. // Returns net::OK on success, net::FAILED if not all databases could be // deleted, and net::ERR_IO_PENDING and |callback| is invoked upon completion, - // if non-NULL. + // if non-NULL. Protected origins, according the the SpecialStoragePolicy, + // are not deleted by this method. int DeleteDataModifiedSince(const base::Time& cutoff, - const std::vector<string16>& protected_origins, net::CompletionCallback* callback); // Delete all databases that belong to the given origin. Returns net::OK on @@ -238,9 +240,8 @@ class DatabaseTracker // Default quota for all origins; changed only by tests int64 default_quota_; - // Store quotas for extensions in memory, in order to prevent writing a row - // to quota_table_ every time an extention is loaded. - std::map<string16, int64> in_memory_quotas_; + // Apps and Extensions can have special rights. + scoped_refptr<quota::SpecialStoragePolicy> special_storage_policy_; // When in incognito mode, store a DELETE_ON_CLOSE handle to each // main DB and journal file that was accessed. When the incognito profile diff --git a/webkit/database/database_tracker_unittest.cc b/webkit/database/database_tracker_unittest.cc index 641c207..a8d2928 100644 --- a/webkit/database/database_tracker_unittest.cc +++ b/webkit/database/database_tracker_unittest.cc @@ -12,9 +12,25 @@ #include "net/base/test_completion_callback.h" #include "testing/gtest/include/gtest/gtest.h" #include "webkit/database/database_tracker.h" +#include "webkit/database/database_util.h" +#include "webkit/quota/special_storage_policy.h" namespace { +const char kOrigin1Url[] = "http://origin1"; +const char kOrigin2Url[] = "http://protected_origin2"; + +class TestSpecialStoragePolicy : public quota::SpecialStoragePolicy { + public: + virtual bool IsStorageProtected(const GURL& origin) { + return origin == GURL(kOrigin2Url); + } + + virtual bool IsStorageUnlimited(const GURL& origin) { + return false; + } +}; + class TestObserver : public webkit_database::DatabaseTracker::Observer { public: TestObserver() : new_notification_received_(false) {} @@ -85,13 +101,16 @@ class DatabaseTracker_TestHelper_Test { ScopedTempDir temp_dir; ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); scoped_refptr<DatabaseTracker> tracker( - new DatabaseTracker(temp_dir.path(), incognito_mode)); + new DatabaseTracker(temp_dir.path(), incognito_mode, + new TestSpecialStoragePolicy)); // Create and open three databases. int64 database_size = 0; int64 space_available = 0; - const string16 kOrigin1 = ASCIIToUTF16("origin1"); - const string16 kOrigin2 = ASCIIToUTF16("origin2"); + const string16 kOrigin1 = + DatabaseUtil::GetOriginIdentifier(GURL(kOrigin1Url)); + const string16 kOrigin2 = + DatabaseUtil::GetOriginIdentifier(GURL(kOrigin2Url)); const string16 kDB1 = ASCIIToUTF16("db1"); const string16 kDB2 = ASCIIToUTF16("db2"); const string16 kDB3 = ASCIIToUTF16("db3"); @@ -160,10 +179,8 @@ class DatabaseTracker_TestHelper_Test { // Delete databases modified since yesterday. db2 is whitelisted. base::Time yesterday = base::Time::Now(); yesterday -= base::TimeDelta::FromDays(1); - std::vector<string16> protected_origins; - protected_origins.push_back(kOrigin2); result = tracker->DeleteDataModifiedSince( - yesterday, protected_origins, &callback); + yesterday, &callback); EXPECT_EQ(net::ERR_IO_PENDING, result); ASSERT_FALSE(callback.have_result()); EXPECT_TRUE(observer.DidReceiveNewNotification()); @@ -187,7 +204,8 @@ class DatabaseTracker_TestHelper_Test { ScopedTempDir temp_dir; ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); scoped_refptr<DatabaseTracker> tracker( - new DatabaseTracker(temp_dir.path(), incognito_mode)); + new DatabaseTracker(temp_dir.path(), incognito_mode, + new TestSpecialStoragePolicy)); // Add two observers. TestObserver observer1; @@ -198,8 +216,10 @@ class DatabaseTracker_TestHelper_Test { // Open three new databases. int64 database_size = 0; int64 space_available = 0; - const string16 kOrigin1 = ASCIIToUTF16("origin1"); - const string16 kOrigin2 = ASCIIToUTF16("origin2"); + const string16 kOrigin1 = + DatabaseUtil::GetOriginIdentifier(GURL(kOrigin1Url)); + const string16 kOrigin2 = + DatabaseUtil::GetOriginIdentifier(GURL(kOrigin2Url)); const string16 kDB1 = ASCIIToUTF16("db1"); const string16 kDB2 = ASCIIToUTF16("db2"); const string16 kDB3 = ASCIIToUTF16("db3"); diff --git a/webkit/database/database_util.cc b/webkit/database/database_util.cc index 8002d81..2886095 100644 --- a/webkit/database/database_util.cc +++ b/webkit/database/database_util.cc @@ -71,4 +71,11 @@ string16 DatabaseUtil::GetOriginIdentifier(const GURL& url) { return WebKit::WebSecurityOrigin::createFromString(spec).databaseIdentifier(); } +GURL DatabaseUtil::GetOriginFromIdentifier(const string16& origin_identifier) { + GURL origin(WebKit::WebSecurityOrigin::createFromDatabaseIdentifier( + origin_identifier).toString()); + DCHECK(origin == origin.GetOrigin()); + return origin; +} + } // namespace webkit_database diff --git a/webkit/database/database_util.h b/webkit/database/database_util.h index cecea79..20410dc 100644 --- a/webkit/database/database_util.h +++ b/webkit/database/database_util.h @@ -25,6 +25,7 @@ class DatabaseUtil { static FilePath GetFullFilePathForVfsFile(DatabaseTracker* db_tracker, const string16& vfs_file_name); static string16 GetOriginIdentifier(const GURL& url); + static GURL GetOriginFromIdentifier(const string16& origin_identifier); }; } // namespace webkit_database diff --git a/webkit/fileapi/file_system_context.cc b/webkit/fileapi/file_system_context.cc index 5007fff..6cb97e9 100644 --- a/webkit/fileapi/file_system_context.cc +++ b/webkit/fileapi/file_system_context.cc @@ -15,6 +15,7 @@ namespace fileapi { FileSystemContext::FileSystemContext( scoped_refptr<base::MessageLoopProxy> file_message_loop, scoped_refptr<base::MessageLoopProxy> io_message_loop, + scoped_refptr<quota::SpecialStoragePolicy> special_storage_policy, const FilePath& profile_path, bool is_incognito, bool allow_file_access, @@ -24,7 +25,7 @@ FileSystemContext::FileSystemContext( path_manager_(new FileSystemPathManager( file_message_loop, profile_path, is_incognito, allow_file_access)), quota_manager_(new FileSystemQuotaManager( - allow_file_access, unlimited_quota)), + allow_file_access, unlimited_quota, special_storage_policy)), usage_tracker_(new FileSystemUsageTracker( file_message_loop, profile_path, is_incognito)) { } @@ -45,16 +46,6 @@ void FileSystemContext::DeleteDataForOriginOnFileThread( file_util::Delete(path_for_origin, true /* recursive */); } -void FileSystemContext::SetOriginQuotaUnlimited(const GURL& url) { - DCHECK(io_message_loop_->BelongsToCurrentThread()); - quota_manager()->SetOriginQuotaUnlimited(url); -} - -void FileSystemContext::ResetOriginQuotaUnlimited(const GURL& url) { - DCHECK(io_message_loop_->BelongsToCurrentThread()); - quota_manager()->ResetOriginQuotaUnlimited(url); -} - void FileSystemContext::DeleteOnCorrectThread() const { if (!io_message_loop_->BelongsToCurrentThread()) { io_message_loop_->DeleteSoon(FROM_HERE, this); diff --git a/webkit/fileapi/file_system_context.h b/webkit/fileapi/file_system_context.h index 5c94c5f..d9552946 100644 --- a/webkit/fileapi/file_system_context.h +++ b/webkit/fileapi/file_system_context.h @@ -7,6 +7,7 @@ #include "base/ref_counted.h" #include "base/scoped_ptr.h" +#include "webkit/quota/special_storage_policy.h" class FilePath; class GURL; @@ -32,6 +33,7 @@ class FileSystemContext FileSystemContext( scoped_refptr<base::MessageLoopProxy> file_message_loop, scoped_refptr<base::MessageLoopProxy> io_message_loop, + scoped_refptr<quota::SpecialStoragePolicy> special_storage_policy, const FilePath& profile_path, bool is_incognito, bool allow_file_access_from_files, @@ -40,10 +42,6 @@ class FileSystemContext void DeleteDataForOriginOnFileThread(const GURL& origin_url); - // Quota related methods. - void SetOriginQuotaUnlimited(const GURL& url); - void ResetOriginQuotaUnlimited(const GURL& url); - FileSystemPathManager* path_manager() { return path_manager_.get(); } FileSystemQuotaManager* quota_manager() { return quota_manager_.get(); } FileSystemUsageTracker* usage_tracker() { return usage_tracker_.get(); } diff --git a/webkit/fileapi/file_system_quota_manager.cc b/webkit/fileapi/file_system_quota_manager.cc index 13a33f6..69ff706 100644 --- a/webkit/fileapi/file_system_quota_manager.cc +++ b/webkit/fileapi/file_system_quota_manager.cc @@ -8,6 +8,7 @@ #include "base/file_util_proxy.h" #include "base/ref_counted.h" #include "base/scoped_callback_factory.h" +#include "webkit/quota/special_storage_policy.h" namespace fileapi { @@ -15,9 +16,11 @@ const int64 FileSystemQuotaManager::kUnknownSize = -1; FileSystemQuotaManager::FileSystemQuotaManager( bool allow_file_access_from_files, - bool unlimited_quota) + bool unlimited_quota, + quota::SpecialStoragePolicy* special_storage_policy) : allow_file_access_from_files_(allow_file_access_from_files), - unlimited_quota_(unlimited_quota) { + unlimited_quota_(unlimited_quota), + special_storage_policy_(special_storage_policy) { } FileSystemQuotaManager::~FileSystemQuotaManager() {} @@ -26,26 +29,10 @@ bool FileSystemQuotaManager::CheckOriginQuota(const GURL& origin, int64) { // If allow-file-access-from-files flag is explicitly given and the scheme // is file, or if unlimited quota for this process was explicitly requested, // return true. - if (unlimited_quota_ || - (origin.SchemeIsFile() && allow_file_access_from_files_)) - return true; - return CheckIfOriginGrantedUnlimitedQuota(origin); -} - -void FileSystemQuotaManager::SetOriginQuotaUnlimited(const GURL& origin) { - DCHECK(origin == origin.GetOrigin()); - unlimited_quota_origins_.insert(origin); -} - -void FileSystemQuotaManager::ResetOriginQuotaUnlimited(const GURL& origin) { - DCHECK(origin == origin.GetOrigin()); - unlimited_quota_origins_.erase(origin); -} - -bool FileSystemQuotaManager::CheckIfOriginGrantedUnlimitedQuota( - const GURL& origin) { - std::set<GURL>::const_iterator found = unlimited_quota_origins_.find(origin); - return (found != unlimited_quota_origins_.end()); + return unlimited_quota_ || + (allow_file_access_from_files_ && origin.SchemeIsFile()) || + (special_storage_policy_.get() && + special_storage_policy_->IsStorageUnlimited(origin)); } } // namespace fileapi diff --git a/webkit/fileapi/file_system_quota_manager.h b/webkit/fileapi/file_system_quota_manager.h index f1c94e1..b7d4d04 100644 --- a/webkit/fileapi/file_system_quota_manager.h +++ b/webkit/fileapi/file_system_quota_manager.h @@ -8,8 +8,13 @@ #include <set> #include "base/basictypes.h" +#include "base/ref_counted.h" #include "googleurl/src/gurl.h" +namespace quota { +class SpecialStoragePolicy; +} + namespace fileapi { // A quota manager for FileSystem. For now it has little implementation @@ -23,7 +28,8 @@ class FileSystemQuotaManager { // If |unlimited_quota| is true, unlimited access is granted for every // origin. This flag must be used only for testing. FileSystemQuotaManager(bool allow_file_access_from_files, - bool unlimited_quota); + bool unlimited_quota, + quota::SpecialStoragePolicy* special_storage_policy); ~FileSystemQuotaManager(); // Checks if the origin can grow its usage by |growth| bytes. @@ -32,17 +38,13 @@ class FileSystemQuotaManager { // that are not in the in-memory unlimited_quota_origins map. bool CheckOriginQuota(const GURL& origin, int64 growth); - // Maintains origins in memory that are allowed to have unlimited quota. - void SetOriginQuotaUnlimited(const GURL& origin); - void ResetOriginQuotaUnlimited(const GURL& origin); - bool CheckIfOriginGrantedUnlimitedQuota(const GURL& origin); - private: // For some extensions/apps we allow unlimited quota. std::set<GURL> unlimited_quota_origins_; const bool allow_file_access_from_files_; const bool unlimited_quota_; + scoped_refptr<quota::SpecialStoragePolicy> special_storage_policy_; DISALLOW_COPY_AND_ASSIGN(FileSystemQuotaManager); }; diff --git a/webkit/fileapi/file_system_quota_manager_unittest.cc b/webkit/fileapi/file_system_quota_manager_unittest.cc index 3bc7ac3..b22a33f9 100644 --- a/webkit/fileapi/file_system_quota_manager_unittest.cc +++ b/webkit/fileapi/file_system_quota_manager_unittest.cc @@ -9,24 +9,10 @@ #include "base/scoped_ptr.h" #include "base/string_number_conversions.h" #include "testing/gtest/include/gtest/gtest.h" +#include "webkit/quota/special_storage_policy.h" using namespace fileapi; -class FileSystemQuotaManagerTest : public testing::Test { - public: - FileSystemQuotaManagerTest() { } - - void SetUp() { - quota_.reset(new FileSystemQuotaManager(false, false)); - } - - FileSystemQuotaManager* quota() const { return quota_.get(); } - - protected: - scoped_ptr<FileSystemQuotaManager> quota_; - DISALLOW_COPY_AND_ASSIGN(FileSystemQuotaManagerTest); -}; - namespace { static const char* const kTestOrigins[] = { @@ -36,111 +22,81 @@ static const char* const kTestOrigins[] = { "file:///", }; +class TestSpecialStoragePolicy : public quota::SpecialStoragePolicy { + public: + virtual bool IsStorageProtected(const GURL& origin) { + return false; + } + + virtual bool IsStorageUnlimited(const GURL& origin) { + return origin == GURL(kTestOrigins[1]); + } +}; + } // anonymous namespace -TEST_F(FileSystemQuotaManagerTest, CheckOriginQuotaNotAllowed) { +TEST(FileSystemQuotaManagerTest, CheckNotAllowed) { + FileSystemQuotaManager quota(false, false, NULL); for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTestOrigins); ++i) { SCOPED_TRACE(testing::Message() << "CheckOriginQuotaNotAllowed #" << i << " " << kTestOrigins[i]); // Should fail no matter how much size is requested. - EXPECT_FALSE(quota()->CheckOriginQuota(GURL(kTestOrigins[i]), -1)); - EXPECT_FALSE(quota()->CheckOriginQuota(GURL(kTestOrigins[i]), 0)); - EXPECT_FALSE(quota()->CheckOriginQuota(GURL(kTestOrigins[i]), 100)); + GURL origin(kTestOrigins[i]); + EXPECT_FALSE(quota.CheckOriginQuota(origin, -1)); + EXPECT_FALSE(quota.CheckOriginQuota(origin, 0)); + EXPECT_FALSE(quota.CheckOriginQuota(origin, 100)); } } -TEST_F(FileSystemQuotaManagerTest, CheckOriginQuotaUnlimited) { - // Tests if SetOriginQuotaUnlimited and ResetOriginQuotaUnlimited - // are working as expected. +TEST(FileSystemQuotaManagerTest, CheckUnlimitedFlag) { + FileSystemQuotaManager quota(false, true, NULL); for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTestOrigins); ++i) { - SCOPED_TRACE(testing::Message() << "CheckOriginQuotaUnlimited #" - << i << " " << kTestOrigins[i]); - GURL url(kTestOrigins[i]); - EXPECT_FALSE(quota()->CheckIfOriginGrantedUnlimitedQuota(url)); - EXPECT_FALSE(quota()->CheckOriginQuota(url, 0)); - - quota()->SetOriginQuotaUnlimited(url); - EXPECT_TRUE(quota()->CheckIfOriginGrantedUnlimitedQuota(url)); - EXPECT_TRUE(quota()->CheckOriginQuota(url, -1)); - EXPECT_TRUE(quota()->CheckOriginQuota(url, 0)); - EXPECT_TRUE(quota()->CheckOriginQuota(url, 100)); - - quota()->ResetOriginQuotaUnlimited(url); - EXPECT_FALSE(quota()->CheckIfOriginGrantedUnlimitedQuota(url)); - EXPECT_FALSE(quota()->CheckOriginQuota(url, -1)); - EXPECT_FALSE(quota()->CheckOriginQuota(url, 0)); - EXPECT_FALSE(quota()->CheckOriginQuota(url, 100)); - } -} - -TEST_F(FileSystemQuotaManagerTest, CheckOriginQuotaWithMixedSet) { - // Tests setting unlimited quota for some urls doesn't affect - // other urls. - GURL test_url1("http://foo.bar.com/"); - GURL test_url2("http://example.com/"); - quota()->SetOriginQuotaUnlimited(test_url1); - quota()->SetOriginQuotaUnlimited(test_url2); - - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTestOrigins); ++i) { - SCOPED_TRACE(testing::Message() << "CheckOriginQuotaMixedSet #" + SCOPED_TRACE(testing::Message() << "CheckOriginQuotaNotAllowed #" << i << " " << kTestOrigins[i]); - GURL url(kTestOrigins[i]); - EXPECT_FALSE(quota()->CheckOriginQuota(url, 0)); - EXPECT_FALSE(quota()->CheckIfOriginGrantedUnlimitedQuota(url)); + // Should succeed no matter how much size is requested. + GURL origin(kTestOrigins[i]); + EXPECT_TRUE(quota.CheckOriginQuota(origin, -1)); + EXPECT_TRUE(quota.CheckOriginQuota(origin, 0)); + EXPECT_TRUE(quota.CheckOriginQuota(origin, 100)); } } -TEST_F(FileSystemQuotaManagerTest, CheckOriginQuotaMixedWithDifferentScheme) { - // Tests setting unlimited quota for urls doesn't affect - // pages in the same hosts but with different scheme. +TEST(FileSystemQuotaManagerTest, CheckAllowFileFlag) { + FileSystemQuotaManager quota(true, false, NULL); for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTestOrigins); ++i) { - GURL url(kTestOrigins[i]); - if (url.SchemeIsFile()) - continue; - ASSERT_TRUE(url == url.GetOrigin()); - std::string new_scheme = "https"; - if (url.SchemeIsSecure()) - new_scheme = "http"; - else - ASSERT_TRUE(url.SchemeIs("http")); - std::string new_url_string = new_scheme + "://" + url.host(); - if (url.has_port()) - new_url_string += ":" + url.port(); - quota()->SetOriginQuotaUnlimited(GURL(new_url_string)); - } - - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTestOrigins); ++i) { - SCOPED_TRACE(testing::Message() - << "CheckOriginQuotaMixedWithDifferentScheme #" + SCOPED_TRACE(testing::Message() << "CheckOriginQuotaNotAllowed #" << i << " " << kTestOrigins[i]); - GURL url(kTestOrigins[i]); - EXPECT_FALSE(quota()->CheckOriginQuota(url, 0)); - EXPECT_FALSE(quota()->CheckIfOriginGrantedUnlimitedQuota(url)); + // Should succeed only for file:// urls + GURL origin(kTestOrigins[i]); + if (origin.SchemeIsFile()) { + EXPECT_TRUE(quota.CheckOriginQuota(origin, -1)); + EXPECT_TRUE(quota.CheckOriginQuota(origin, 0)); + EXPECT_TRUE(quota.CheckOriginQuota(origin, 100)); + } else { + EXPECT_FALSE(quota.CheckOriginQuota(origin, -1)); + EXPECT_FALSE(quota.CheckOriginQuota(origin, 0)); + EXPECT_FALSE(quota.CheckOriginQuota(origin, 100)); + } } } -TEST_F(FileSystemQuotaManagerTest, CheckOriginQuotaMixedWithDifferentPort) { - // Tests setting unlimited quota for urls doesn't affect - // pages in the same scheme/hosts but with different port number. - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTestOrigins); ++i) { - GURL url(kTestOrigins[i]); - if (url.SchemeIsFile()) - continue; - ASSERT_TRUE(url == url.GetOrigin()); - int port = 81; - if (url.has_port()) - port = url.IntPort() + 1; - GURL new_url(url.scheme() + "://" + url.host() + ":" + - base::IntToString(port)); - quota()->SetOriginQuotaUnlimited(new_url); - } +TEST(FileSystemQuotaManagerTest, CheckSpecialPolicy) { + scoped_refptr<TestSpecialStoragePolicy> policy(new TestSpecialStoragePolicy); + FileSystemQuotaManager quota(false, false, policy); for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTestOrigins); ++i) { - SCOPED_TRACE(testing::Message() - << "CheckOriginQuotaMixedWithDifferentPort #" + SCOPED_TRACE(testing::Message() << "CheckOriginQuotaNotAllowed #" << i << " " << kTestOrigins[i]); - GURL url(kTestOrigins[i]); - EXPECT_FALSE(quota()->CheckOriginQuota(url, 0)); - EXPECT_FALSE(quota()->CheckIfOriginGrantedUnlimitedQuota(url)); + // Should succeed only for unlimited origins according to the policy. + GURL origin(kTestOrigins[i]); + if (policy->IsStorageUnlimited(origin)) { + EXPECT_TRUE(quota.CheckOriginQuota(origin, -1)); + EXPECT_TRUE(quota.CheckOriginQuota(origin, 0)); + EXPECT_TRUE(quota.CheckOriginQuota(origin, 100)); + } else { + EXPECT_FALSE(quota.CheckOriginQuota(origin, -1)); + EXPECT_FALSE(quota.CheckOriginQuota(origin, 0)); + EXPECT_FALSE(quota.CheckOriginQuota(origin, 100)); + } } } diff --git a/webkit/tools/test_shell/simple_database_system.cc b/webkit/tools/test_shell/simple_database_system.cc index dc80f69..d9f0cbc 100644 --- a/webkit/tools/test_shell/simple_database_system.cc +++ b/webkit/tools/test_shell/simple_database_system.cc @@ -29,7 +29,7 @@ SimpleDatabaseSystem* SimpleDatabaseSystem::GetInstance() { SimpleDatabaseSystem::SimpleDatabaseSystem() : waiting_for_dbs_to_close_(false) { CHECK(temp_dir_.CreateUniqueTempDir()); - db_tracker_ = new DatabaseTracker(temp_dir_.path(), false); + db_tracker_ = new DatabaseTracker(temp_dir_.path(), false, NULL); db_tracker_->AddObserver(this); DCHECK(!instance_); instance_ = this; diff --git a/webkit/tools/test_shell/simple_file_system.cc b/webkit/tools/test_shell/simple_file_system.cc index ea33007..6016255 100644 --- a/webkit/tools/test_shell/simple_file_system.cc +++ b/webkit/tools/test_shell/simple_file_system.cc @@ -121,6 +121,7 @@ SimpleFileSystem::SimpleFileSystem() { file_system_context_ = new FileSystemContext( base::MessageLoopProxy::CreateForCurrentThread(), base::MessageLoopProxy::CreateForCurrentThread(), + NULL /* special storage policy */, file_system_dir_.path(), false /* incognito */, true /* allow_file_access */, diff --git a/webkit/tools/test_shell/test_shell.gypi b/webkit/tools/test_shell/test_shell.gypi index 67b34b5..565f18d 100644 --- a/webkit/tools/test_shell/test_shell.gypi +++ b/webkit/tools/test_shell/test_shell.gypi @@ -44,6 +44,7 @@ '<(DEPTH)/webkit/support/webkit_support.gyp:database', '<(DEPTH)/webkit/support/webkit_support.gyp:fileapi', '<(DEPTH)/webkit/support/webkit_support.gyp:glue', + '<(DEPTH)/webkit/support/webkit_support.gyp:quota', '<(DEPTH)/webkit/support/webkit_support.gyp:webkit_gpu', '<(DEPTH)/webkit/support/webkit_support.gyp:webkit_resources', '<(DEPTH)/webkit/support/webkit_support.gyp:webkit_support_common', |