summaryrefslogtreecommitdiffstats
path: root/webkit/database
diff options
context:
space:
mode:
authormichaeln@google.com <michaeln@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2012-02-18 01:04:14 +0000
committermichaeln@google.com <michaeln@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2012-02-18 01:04:14 +0000
commit1f1db25fa346abd6ff84d195c449215c655d57f0 (patch)
treefc2b31d014a188dd999d789e6cdd66706b6b8c9a /webkit/database
parentf8892656467b06fa87f3e75091f6b940f203623b (diff)
downloadchromium_src-1f1db25fa346abd6ff84d195c449215c655d57f0.zip
chromium_src-1f1db25fa346abd6ff84d195c449215c655d57f0.tar.gz
chromium_src-1f1db25fa346abd6ff84d195c449215c655d57f0.tar.bz2
Nuke from orbit corrupt websql databases.
BUG=98939 Review URL: https://chromiumcodereview.appspot.com/9371008 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@122651 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/database')
-rw-r--r--webkit/database/database_tracker.cc19
-rw-r--r--webkit/database/database_tracker.h4
-rw-r--r--webkit/database/database_tracker_unittest.cc97
3 files changed, 119 insertions, 1 deletions
diff --git a/webkit/database/database_tracker.cc b/webkit/database/database_tracker.cc
index f225129..2264997 100644
--- a/webkit/database/database_tracker.cc
+++ b/webkit/database/database_tracker.cc
@@ -19,6 +19,7 @@
#include "sql/diagnostic_error_delegate.h"
#include "sql/meta_table.h"
#include "sql/transaction.h"
+#include "third_party/sqlite/sqlite3.h"
#include "webkit/database/database_quota_client.h"
#include "webkit/database/database_util.h"
#include "webkit/database/databases_table.h"
@@ -179,6 +180,24 @@ void DatabaseTracker::DatabaseClosed(const string16& origin_identifier,
DeleteDatabaseIfNeeded(origin_identifier, database_name);
}
+void DatabaseTracker::HandleSqliteError(
+ const string16& origin_identifier,
+ const string16& database_name,
+ int error) {
+ // We only handle errors that indicate corruption and we
+ // do so with a heavy hand, we delete it. Any renderers/workers
+ // with this database open will receive a message to close it
+ // immediately, once all have closed, the files will be deleted.
+ // In the interim, all attempts to open a new connection to that
+ // database will fail.
+ // Note: the client-side filters out all but these two errors as
+ // a small optimization, see WebDatabaseObserverImpl::HandleSqliteError.
+ if (error == SQLITE_CORRUPT || error == SQLITE_NOTADB) {
+ DeleteDatabase(origin_identifier, database_name,
+ net::CompletionCallback());
+ }
+}
+
void DatabaseTracker::CloseDatabases(const DatabaseConnections& connections) {
if (database_connections_.IsEmpty()) {
DCHECK(!is_initialized_ || connections.IsEmpty());
diff --git a/webkit/database/database_tracker.h b/webkit/database/database_tracker.h
index d3d0473..340cdcc 100644
--- a/webkit/database/database_tracker.h
+++ b/webkit/database/database_tracker.h
@@ -105,6 +105,10 @@ class DatabaseTracker
const string16& database_name);
void DatabaseClosed(const string16& origin_identifier,
const string16& database_name);
+ void HandleSqliteError(const string16& origin_identifier,
+ const string16& database_name,
+ int error);
+
void CloseDatabases(const DatabaseConnections& connections);
void AddObserver(Observer* observer);
diff --git a/webkit/database/database_tracker_unittest.cc b/webkit/database/database_tracker_unittest.cc
index 408046b..88babea 100644
--- a/webkit/database/database_tracker_unittest.cc
+++ b/webkit/database/database_tracker_unittest.cc
@@ -13,6 +13,7 @@
#include "net/base/net_errors.h"
#include "net/base/test_completion_callback.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/sqlite/sqlite3.h"
#include "webkit/database/database_tracker.h"
#include "webkit/database/database_util.h"
#include "webkit/quota/mock_special_storage_policy.h"
@@ -25,11 +26,23 @@ const char kOrigin2Url[] = "http://protected_origin2";
class TestObserver : public webkit_database::DatabaseTracker::Observer {
public:
- TestObserver() : new_notification_received_(false) {}
+ TestObserver()
+ : new_notification_received_(false),
+ observe_size_changes_(true),
+ observe_scheduled_deletions_(true) {
+ }
+ TestObserver(bool observe_size_changes, bool observe_scheduled_deletions)
+ : new_notification_received_(false),
+ observe_size_changes_(observe_size_changes),
+ observe_scheduled_deletions_(observe_scheduled_deletions) {
+ }
+
virtual ~TestObserver() {}
virtual void OnDatabaseSizeChanged(const string16& origin_identifier,
const string16& database_name,
int64 database_size) {
+ if (!observe_size_changes_)
+ return;
new_notification_received_ = true;
origin_identifier_ = origin_identifier;
database_name_ = database_name;
@@ -37,6 +50,8 @@ class TestObserver : public webkit_database::DatabaseTracker::Observer {
}
virtual void OnDatabaseScheduledForDeletion(const string16& origin_identifier,
const string16& database_name) {
+ if (!observe_scheduled_deletions_)
+ return;
new_notification_received_ = true;
origin_identifier_ = origin_identifier;
database_name_ = database_name;
@@ -52,6 +67,8 @@ class TestObserver : public webkit_database::DatabaseTracker::Observer {
private:
bool new_notification_received_;
+ bool observe_size_changes_;
+ bool observe_scheduled_deletions_;
string16 origin_identifier_;
string16 database_name_;
int64 database_size_;
@@ -812,6 +829,80 @@ class DatabaseTracker_TestHelper_Test {
EXPECT_TRUE(tracker->GetAllOriginsInfo(&infos));
EXPECT_TRUE(infos.empty());
}
+
+ static void HandleSqliteError() {
+ const GURL kOrigin(kOrigin1Url);
+ const string16 kOriginId = DatabaseUtil::GetOriginIdentifier(kOrigin);
+ const string16 kName(ASCIIToUTF16("name"));
+ const string16 kDescription(ASCIIToUTF16("description"));
+
+ // Initialize a tracker database, no need to put it on disk.
+ const bool kUseInMemoryTrackerDatabase = true;
+ ScopedTempDir temp_dir;
+ ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+ scoped_refptr<DatabaseTracker> tracker(
+ new DatabaseTracker(temp_dir.path(), kUseInMemoryTrackerDatabase,
+ false, NULL, NULL, NULL));
+
+ // Setup to observe OnScheduledForDelete notifications.
+ TestObserver observer(false, true);
+ tracker->AddObserver(&observer);
+
+ // Verify does no harm when there is no such database.
+ tracker->HandleSqliteError(kOriginId, kName, SQLITE_CORRUPT);
+ EXPECT_FALSE(tracker->IsDatabaseScheduledForDeletion(kOriginId, kName));
+ EXPECT_FALSE(observer.DidReceiveNewNotification());
+
+ // --------------------------------------------------------
+ // Create a record of a database in the tracker db and create
+ // a spoof_db_file on disk in the expected location.
+ int64 database_size = 0;
+ tracker->DatabaseOpened(kOriginId, kName, kDescription, 0,
+ &database_size);
+ FilePath spoof_db_file = tracker->GetFullDBFilePath(kOriginId, kName);
+ EXPECT_FALSE(tracker->GetFullDBFilePath(kOriginId, kName).empty());
+ EXPECT_TRUE(file_util::CreateDirectory(spoof_db_file.DirName()));
+ EXPECT_TRUE(EnsureFileOfSize(spoof_db_file, 1));
+
+ // Verify does no harm with a non-error is reported.
+ tracker->HandleSqliteError(kOriginId, kName, SQLITE_OK);
+ EXPECT_FALSE(tracker->IsDatabaseScheduledForDeletion(kOriginId, kName));
+ EXPECT_FALSE(observer.DidReceiveNewNotification());
+
+ // Verify that with a connection open, the db is scheduled for deletion,
+ // but that the file still exists.
+ tracker->HandleSqliteError(kOriginId, kName, SQLITE_CORRUPT);
+ EXPECT_TRUE(tracker->IsDatabaseScheduledForDeletion(kOriginId, kName));
+ EXPECT_TRUE(observer.DidReceiveNewNotification());
+ EXPECT_TRUE(file_util::PathExists(spoof_db_file));
+
+ // Verify that once closed, the file is deleted and the record in the
+ // tracker db is removed.
+ tracker->DatabaseClosed(kOriginId, kName);
+ EXPECT_FALSE(file_util::PathExists(spoof_db_file));
+ EXPECT_TRUE(tracker->GetFullDBFilePath(kOriginId, kName).empty());
+
+ // --------------------------------------------------------
+ // Create another record of a database in the tracker db and create
+ // a spoof_db_file on disk in the expected location.
+ tracker->DatabaseOpened(kOriginId, kName, kDescription, 0,
+ &database_size);
+ FilePath spoof_db_file2 = tracker->GetFullDBFilePath(kOriginId, kName);
+ EXPECT_FALSE(tracker->GetFullDBFilePath(kOriginId, kName).empty());
+ EXPECT_NE(spoof_db_file, spoof_db_file2);
+ EXPECT_TRUE(file_util::CreateDirectory(spoof_db_file2.DirName()));
+ EXPECT_TRUE(EnsureFileOfSize(spoof_db_file2, 1));
+
+ // Verify that with no connection open, the db is deleted immediately.
+ tracker->DatabaseClosed(kOriginId, kName);
+ tracker->HandleSqliteError(kOriginId, kName, SQLITE_CORRUPT);
+ EXPECT_FALSE(tracker->IsDatabaseScheduledForDeletion(kOriginId, kName));
+ EXPECT_FALSE(observer.DidReceiveNewNotification());
+ EXPECT_TRUE(tracker->GetFullDBFilePath(kOriginId, kName).empty());
+ EXPECT_FALSE(file_util::PathExists(spoof_db_file2));
+
+ tracker->RemoveObserver(&observer);
+ }
};
TEST(DatabaseTrackerTest, DeleteOpenDatabase) {
@@ -855,4 +946,8 @@ TEST(DatabaseTrackerTest, EmptyDatabaseNameIsValid) {
DatabaseTracker_TestHelper_Test::EmptyDatabaseNameIsValid();
}
+TEST(DatabaseTrackerTest, HandleSqliteError) {
+ DatabaseTracker_TestHelper_Test::HandleSqliteError();
+}
+
} // namespace webkit_database