Skip to content

Commit

Permalink
DatabaseTracker: Clearing session-only databases on exit.
Browse files Browse the repository at this point in the history
BUG=47049
TEST=DatabaseTrackerTest.DatabaseTrackerClearSessionOnlyDatabasesOnExit


Review URL: http://codereview.chromium.org/7800040

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@100135 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
marja@chromium.org committed Sep 8, 2011
1 parent db15183 commit f5d75f7
Show file tree
Hide file tree
Showing 11 changed files with 184 additions and 9 deletions.
17 changes: 17 additions & 0 deletions chrome/browser/extensions/extension_special_storage_policy.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "base/logging.h"
#include "chrome/browser/content_settings/host_content_settings_map.h"
#include "chrome/common/content_settings.h"
#include "chrome/common/content_settings_types.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/url_constants.h"
#include "content/browser/browser_thread.h"
Expand Down Expand Up @@ -37,6 +38,22 @@ bool ExtensionSpecialStoragePolicy::IsStorageSessionOnly(const GURL& origin) {
return (content_setting == CONTENT_SETTING_SESSION_ONLY);
}

bool ExtensionSpecialStoragePolicy::HasSessionOnlyOrigins() {
if (host_content_settings_map_ == NULL)
return false;
if (host_content_settings_map_->GetDefaultContentSetting(
CONTENT_SETTINGS_TYPE_COOKIES) == CONTENT_SETTING_SESSION_ONLY)
return true;
HostContentSettingsMap::SettingsForOneType entries;
host_content_settings_map_->GetSettingsForOneType(
CONTENT_SETTINGS_TYPE_COOKIES, "", &entries);
for (size_t i = 0; i < entries.size(); ++i) {
if (entries[i].c == CONTENT_SETTING_SESSION_ONLY)
return true;
}
return false;
}

bool ExtensionSpecialStoragePolicy::IsFileHandler(
const std::string& extension_id) {
base::AutoLock locker(lock_);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class ExtensionSpecialStoragePolicy : public quota::SpecialStoragePolicy {
virtual bool IsStorageUnlimited(const GURL& origin);
virtual bool IsStorageSessionOnly(const GURL& origin);
virtual bool IsFileHandler(const std::string& extension_id);
virtual bool HasSessionOnlyOrigins();

// Methods used by the ExtensionService to populate this class.
void GrantRightsForExtension(const Extension* extension);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,13 @@
// found in the LICENSE file.

#include "base/values.h"
#include "chrome/browser/content_settings/host_content_settings_map.h"
#include "chrome/browser/extensions/extension_special_storage_policy.h"
#include "chrome/common/content_settings.h"
#include "chrome/common/content_settings_types.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_constants.h"
#include "chrome/test/base/testing_profile.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace keys = extension_manifest_keys;
Expand Down Expand Up @@ -210,3 +214,42 @@ TEST_F(ExtensionSpecialStoragePolicyTest, OverlappingApps) {
EXPECT_FALSE(policy->IsStorageProtected(GURL("http://foo.wildcards/")));
EXPECT_FALSE(policy->IsStorageProtected(GURL("https://bar.wildcards/")));
}

TEST_F(ExtensionSpecialStoragePolicyTest, HasSessionOnlyOrigins) {
MessageLoop message_loop;
BrowserThread ui_thread(BrowserThread::UI, &message_loop);

TestingProfile profile;
HostContentSettingsMap* host_content_settings_map =
profile.GetHostContentSettingsMap();
scoped_refptr<ExtensionSpecialStoragePolicy> policy(
new ExtensionSpecialStoragePolicy(host_content_settings_map));

EXPECT_FALSE(policy->HasSessionOnlyOrigins());

// The default setting can be session-only.
host_content_settings_map->SetDefaultContentSetting(
CONTENT_SETTINGS_TYPE_COOKIES, CONTENT_SETTING_SESSION_ONLY);
EXPECT_TRUE(policy->HasSessionOnlyOrigins());

host_content_settings_map->SetDefaultContentSetting(
CONTENT_SETTINGS_TYPE_COOKIES, CONTENT_SETTING_ALLOW);
EXPECT_FALSE(policy->HasSessionOnlyOrigins());

// Or the session-onlyness can affect individual origins.
ContentSettingsPattern pattern =
ContentSettingsPattern::FromString("pattern.com");

host_content_settings_map->SetContentSetting(
pattern, ContentSettingsPattern::Wildcard(),
CONTENT_SETTINGS_TYPE_COOKIES, "", CONTENT_SETTING_SESSION_ONLY);

EXPECT_TRUE(policy->HasSessionOnlyOrigins());

// Clearing an origin-spesific rule.
host_content_settings_map->SetContentSetting(
pattern, ContentSettingsPattern::Wildcard(),
CONTENT_SETTINGS_TYPE_COOKIES, "", CONTENT_SETTING_DEFAULT);

EXPECT_FALSE(policy->HasSessionOnlyOrigins());
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,7 @@ bool MockExtensionSpecialStoragePolicy::IsFileHandler(
const std::string& extension_id) {
return file_handlers_.find(extension_id) != file_handlers_.end();
}

bool MockExtensionSpecialStoragePolicy::HasSessionOnlyOrigins() {
return !session_only_.empty();
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ class MockExtensionSpecialStoragePolicy : public ExtensionSpecialStoragePolicy {
virtual bool IsStorageUnlimited(const GURL& origin);
virtual bool IsStorageSessionOnly(const GURL& origin);
virtual bool IsFileHandler(const std::string& extension_id);
virtual bool HasSessionOnlyOrigins();

void AddProtected(const GURL& origin) {
protected_.insert(origin);
Expand Down
26 changes: 21 additions & 5 deletions webkit/database/database_tracker.cc
Original file line number Diff line number Diff line change
Expand Up @@ -797,17 +797,33 @@ void DatabaseTracker::DeleteIncognitoDBDirectory() {
file_util::Delete(incognito_db_dir, true);
}

void DatabaseTracker::ClearLocalState() {
void DatabaseTracker::ClearLocalState(bool clear_all_databases) {
shutting_down_ = true;

bool has_session_only_databases =
special_storage_policy_.get() &&
special_storage_policy_->HasSessionOnlyOrigins();

// Clearning only session-only databases, and there are none.
if (!clear_all_databases && !has_session_only_databases)
return;

if (!LazyInit())
return;

std::vector<string16> origin_identifiers;
GetAllOriginIdentifiers(&origin_identifiers);

for (std::vector<string16>::iterator origin = origin_identifiers.begin();
origin != origin_identifiers.end(); ++origin) {
GURL origin_url =
webkit_database::DatabaseUtil::GetOriginFromIdentifier(*origin);
if (!clear_all_databases &&
!special_storage_policy_->IsStorageSessionOnly(origin_url)) {
continue;
}
if (special_storage_policy_.get() &&
special_storage_policy_->IsStorageProtected(
webkit_database::DatabaseUtil::GetOriginFromIdentifier(*origin))) {
special_storage_policy_->IsStorageProtected(origin_url)) {
continue;
}
webkit_database::OriginInfo origin_info;
Expand Down Expand Up @@ -840,8 +856,8 @@ void DatabaseTracker::Shutdown() {
}
if (is_incognito_)
DeleteIncognitoDBDirectory();
else if (clear_local_state_on_exit_ && LazyInit())
ClearLocalState();
else
ClearLocalState(clear_local_state_on_exit_);
}

void DatabaseTracker::SetClearLocalStateOnExit(bool clear_local_state_on_exit) {
Expand Down
8 changes: 4 additions & 4 deletions webkit/database/database_tracker.h
Original file line number Diff line number Diff line change
Expand Up @@ -198,10 +198,10 @@ class DatabaseTracker
// Deletes the directory that stores all DBs in incognito mode, if it exists.
void DeleteIncognitoDBDirectory();

// Deletes databases not protected by the special storage policy if
// |clear_local_state_on_exit_| is true and blocks databases from being
// created/opened.
void ClearLocalState();
// If clear_all_databases is true, deletes all databases not protected by
// special storage policy. Otherwise deletes session-only databases. Blocks
// databases from being created/opened.
void ClearLocalState(bool clear_all_databases);

bool DeleteClosedDatabase(const string16& origin_identifier,
const string16& database_name);
Expand Down
85 changes: 85 additions & 0 deletions webkit/database/database_tracker_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -608,6 +608,85 @@ class DatabaseTracker_TestHelper_Test {
EXPECT_FALSE(file_util::PathExists(origin1_db_dir));
}

static void DatabaseTrackerClearSessionOnlyDatabasesOnExit() {
int64 database_size = 0;
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 kDescription = ASCIIToUTF16("database_description");

// Initialize the tracker database.
ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
FilePath origin1_db_dir;
FilePath origin2_db_dir;
{
scoped_refptr<quota::MockSpecialStoragePolicy> special_storage_policy =
new quota::MockSpecialStoragePolicy;
special_storage_policy->AddSessionOnly(GURL(kOrigin2Url));
scoped_refptr<DatabaseTracker> tracker(
new DatabaseTracker(
temp_dir.path(), false, false /*clear_local_state_on_exit*/,
special_storage_policy, NULL,
base::MessageLoopProxy::current()));

// Open two new databases.
tracker->DatabaseOpened(kOrigin1, kDB1, kDescription, 0,
&database_size);
EXPECT_EQ(0, database_size);
tracker->DatabaseOpened(kOrigin2, kDB2, kDescription, 0,
&database_size);
EXPECT_EQ(0, database_size);

// Write some data to each file.
FilePath db_file;
db_file = tracker->GetFullDBFilePath(kOrigin1, kDB1);
EXPECT_TRUE(file_util::CreateDirectory(db_file.DirName()));
EXPECT_TRUE(EnsureFileOfSize(db_file, 1));

db_file = tracker->GetFullDBFilePath(kOrigin2, kDB2);
EXPECT_TRUE(file_util::CreateDirectory(db_file.DirName()));
EXPECT_TRUE(EnsureFileOfSize(db_file, 2));

// Store the origin database directories as long as they still exist.
origin1_db_dir = tracker->GetFullDBFilePath(kOrigin1, kDB1).DirName();
origin2_db_dir = tracker->GetFullDBFilePath(kOrigin2, kDB2).DirName();

tracker->DatabaseModified(kOrigin1, kDB1);
tracker->DatabaseModified(kOrigin2, kDB2);

// Close all databases.
tracker->DatabaseClosed(kOrigin1, kDB1);
tracker->DatabaseClosed(kOrigin2, kDB2);

tracker->Shutdown();
}

// At this point, the database tracker should be gone. Create a new one.
scoped_refptr<DatabaseTracker> tracker(
new DatabaseTracker(temp_dir.path(), false, false,
NULL, NULL, NULL));

// Get all data for all origins.
std::vector<OriginInfo> origins_info;
EXPECT_TRUE(tracker->GetAllOriginsInfo(&origins_info));
// kOrigin1 was not session-only, so it survived. kOrigin2 was session-only
// and it got deleted.
EXPECT_EQ(size_t(1), origins_info.size());
EXPECT_EQ(kOrigin1, origins_info[0].GetOrigin());
EXPECT_TRUE(
file_util::PathExists(tracker->GetFullDBFilePath(kOrigin1, kDB1)));
EXPECT_EQ(FilePath(), tracker->GetFullDBFilePath(kOrigin2, kDB2));

// The origin directory of kOrigin1 remains, but the origin directory of
// kOrigin2 is deleted.
EXPECT_TRUE(file_util::PathExists(origin1_db_dir));
EXPECT_FALSE(file_util::PathExists(origin2_db_dir));
}

static void EmptyDatabaseNameIsValid() {
const GURL kOrigin(kOrigin1Url);
const string16 kOriginId = DatabaseUtil::GetOriginIdentifier(kOrigin);
Expand Down Expand Up @@ -681,6 +760,12 @@ TEST(DatabaseTrackerTest, DatabaseTrackerClearLocalStateOnExit) {
DatabaseTracker_TestHelper_Test::DatabaseTrackerClearLocalStateOnExit();
}

TEST(DatabaseTrackerTest, DatabaseTrackerClearSessionOnlyDatabasesOnExit) {
// Only works for regular mode.
DatabaseTracker_TestHelper_Test::
DatabaseTrackerClearSessionOnlyDatabasesOnExit();
}

TEST(DatabaseTrackerTest, EmptyDatabaseNameIsValid) {
DatabaseTracker_TestHelper_Test::EmptyDatabaseNameIsValid();
}
Expand Down
4 changes: 4 additions & 0 deletions webkit/quota/mock_special_storage_policy.cc
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,8 @@ bool MockSpecialStoragePolicy::IsFileHandler(const std::string& extension_id) {
return file_handlers_.find(extension_id) != file_handlers_.end();
}

bool MockSpecialStoragePolicy::HasSessionOnlyOrigins() {
return !session_only_.empty();
}

} // namespace quota
1 change: 1 addition & 0 deletions webkit/quota/mock_special_storage_policy.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class MockSpecialStoragePolicy : public quota::SpecialStoragePolicy {
virtual bool IsStorageUnlimited(const GURL& origin);
virtual bool IsStorageSessionOnly(const GURL& origin);
virtual bool IsFileHandler(const std::string& extension_id);
virtual bool HasSessionOnlyOrigins();

void AddProtected(const GURL& origin) {
protected_.insert(origin);
Expand Down
3 changes: 3 additions & 0 deletions webkit/quota/special_storage_policy.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ class SpecialStoragePolicy
// when the session ends.
virtual bool IsStorageSessionOnly(const GURL& origin) = 0;

// Returns true if some origins are only allowed session-only storage.
virtual bool HasSessionOnlyOrigins() = 0;

// Adds/removes an observer, the policy does not take
// ownership of the observer. Should only be called on the IO thread.
void AddObserver(Observer* observer);
Expand Down

0 comments on commit f5d75f7

Please sign in to comment.