Diff
Modified: trunk/Source/WebCore/ChangeLog (223426 => 223427)
--- trunk/Source/WebCore/ChangeLog 2017-10-16 20:16:57 UTC (rev 223426)
+++ trunk/Source/WebCore/ChangeLog 2017-10-16 20:20:53 UTC (rev 223427)
@@ -1,3 +1,39 @@
+2017-10-16 Maureen Daum <md...@apple.com>
+
+ If we fail to delete any database file, don't remove its information from the tracker database
+ <rdar://problem/34576132> and https://bugs.webkit.org/show_bug.cgi?id=178251
+
+ Reviewed by Brady Eidson.
+
+ New tests:
+ DatabaseTracker.DeleteDatabase
+ DatabaseTracker.DeleteDatabaseWhenDatabaseDoesNotExist
+ DatabaseTracker.DeleteOrigin
+ DatabaseTracker.DeleteOriginWhenDeletingADatabaseFails
+ DatabaseTracker.DeleteOriginWhenDatabaseDoesNotExist
+
+ * Modules/webdatabase/DatabaseTracker.cpp:
+ (WebCore::DatabaseTracker::deleteDatabasesModifiedSince):
+ If the database doesn't exist, we previously deleted it but failed to remove the
+ information from the tracker database. We still want to delete all of the information
+ associated with this database from the tracker database, so add it to databaseNamesToDelete.
+ (WebCore::DatabaseTracker::deleteOrigin):
+ If a database doesn't exist, don't try to delete it. We don't need to, but more
+ importantly, deleteDatabaseFile() will fail if the database doesn't exist, which
+ will cause us to incorrectly think we failed to remove database information from disk.
+ If we actually fail to delete any database file, return before we remove the origin
+ information from the tracker database so we don't lose track of the database.
+ (WebCore::DatabaseTracker::deleteDatabase):
+ If a database doesn't exist, don't try to delete it. We don't need to, but also it
+ will cause us to incorrectly think that we were unable to delete a database, so we
+ would bail before we remove the database information from the tracker database. We
+ want to remove the database information from the tracker database because the database
+ doesn't exist.
+ * Modules/webdatabase/DatabaseTracker.h:
+ Expose fullPathForDatabase() for use by tests.
+ * platform/Logging.h:
+ Add a logging channel.
+
2017-10-16 Alex Christensen <achristen...@webkit.org>
Remove unnecessary include from Document.h
Modified: trunk/Source/WebCore/Modules/webdatabase/DatabaseTracker.cpp (223426 => 223427)
--- trunk/Source/WebCore/Modules/webdatabase/DatabaseTracker.cpp 2017-10-16 20:16:57 UTC (rev 223426)
+++ trunk/Source/WebCore/Modules/webdatabase/DatabaseTracker.cpp 2017-10-16 20:20:53 UTC (rev 223427)
@@ -782,12 +782,17 @@
for (const auto& databaseName : databaseNames) {
auto fullPath = fullPathForDatabase(origin, databaseName, false);
- time_t modificationTime;
- if (!getFileModificationTime(fullPath, modificationTime))
- continue;
+ // If the file doesn't exist, we previously deleted it but failed to remove the information
+ // from the tracker database. We want to delete all of the information associated with this
+ // database from the tracker database, so still add its name to databaseNamesToDelete.
+ if (fileExists(fullPath)) {
+ time_t modificationTime;
+ if (!getFileModificationTime(fullPath, modificationTime))
+ continue;
- if (modificationTime < std::chrono::system_clock::to_time_t(time))
- continue;
+ if (modificationTime < std::chrono::system_clock::to_time_t(time))
+ continue;
+ }
databaseNamesToDelete.uncheckedAppend(databaseName);
}
@@ -831,13 +836,22 @@
}
// We drop the lock here because holding locks during a call to deleteDatabaseFile will deadlock.
+ bool failedToDeleteAnyDatabaseFile = false;
for (auto& name : databaseNames) {
- if (!deleteDatabaseFile(origin, name, deletionMode)) {
+ if (fileExists(fullPathForDatabase(origin, name, false)) && !deleteDatabaseFile(origin, name, deletionMode)) {
// Even if the file can't be deleted, we want to try and delete the rest, don't return early here.
LOG_ERROR("Unable to delete file for database %s in origin %s", name.utf8().data(), origin.databaseIdentifier().utf8().data());
+ failedToDeleteAnyDatabaseFile = true;
}
}
+ // If we failed to delete any database file, don't remove the origin from the tracker
+ // database because we didn't successfully remove all of its data.
+ if (failedToDeleteAnyDatabaseFile) {
+ RELEASE_LOG_ERROR(DatabaseTracker, "Failed to delete database for origin");
+ return false;
+ }
+
{
LockHolder lockDatabase(m_databaseGuard);
deleteOriginLockFor(origin);
@@ -1037,7 +1051,7 @@
}
// We drop the lock here because holding locks during a call to deleteDatabaseFile will deadlock.
- if (!deleteDatabaseFile(origin, name, DeletionMode::Default)) {
+ if (fileExists(fullPathForDatabase(origin, name, false)) && !deleteDatabaseFile(origin, name, DeletionMode::Default)) {
LOG_ERROR("Unable to delete file for database %s in origin %s", name.utf8().data(), origin.databaseIdentifier().utf8().data());
LockHolder lockDatabase(m_databaseGuard);
doneDeletingDatabase(origin, name);
Modified: trunk/Source/WebCore/Modules/webdatabase/DatabaseTracker.h (223426 => 223427)
--- trunk/Source/WebCore/Modules/webdatabase/DatabaseTracker.h 2017-10-16 20:16:57 UTC (rev 223426)
+++ trunk/Source/WebCore/Modules/webdatabase/DatabaseTracker.h 2017-10-16 20:20:53 UTC (rev 223427)
@@ -69,7 +69,7 @@
ExceptionOr<void> retryCanEstablishDatabase(DatabaseContext&, const String& name, unsigned estimatedSize);
void setDatabaseDetails(const SecurityOriginData&, const String& name, const String& displayName, unsigned estimatedSize);
- String fullPathForDatabase(const SecurityOriginData&, const String& name, bool createIfDoesNotExist);
+ WEBCORE_EXPORT String fullPathForDatabase(const SecurityOriginData&, const String& name, bool createIfDoesNotExist);
void addOpenDatabase(Database&);
void removeOpenDatabase(Database&);
Modified: trunk/Source/WebCore/platform/Logging.h (223426 => 223427)
--- trunk/Source/WebCore/platform/Logging.h 2017-10-16 20:16:57 UTC (rev 223426)
+++ trunk/Source/WebCore/platform/Logging.h 2017-10-16 20:20:53 UTC (rev 223427)
@@ -42,6 +42,7 @@
M(Archives) \
M(Compositing) \
M(ContentFiltering) \
+ M(DatabaseTracker) \
M(DisplayLists) \
M(DOMTimers) \
M(Editing) \
Modified: trunk/Tools/ChangeLog (223426 => 223427)
--- trunk/Tools/ChangeLog 2017-10-16 20:16:57 UTC (rev 223426)
+++ trunk/Tools/ChangeLog 2017-10-16 20:20:53 UTC (rev 223427)
@@ -1,3 +1,25 @@
+2017-10-16 Maureen Daum <md...@apple.com>
+
+ If we fail to delete any database file, don't remove its information from the tracker database
+ <rdar://problem/34576132> and https://bugs.webkit.org/show_bug.cgi?id=178251
+
+ Reviewed by Brady Eidson.
+
+ Add tests that verify we correctly delete databases and remove their information from
+ the tracker database, even if the database doesn't exist. Verify that if we fail to
+ delete a database, we don't remove its information from the tracker database.
+
+ * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+ Move DatabaseTrackerTest.cpp to DatabaseTrackerTest.mm so that we can use the cocoa
+ method for creating a temporary directory in the tests.
+ * TestWebKitAPI/Tests/WebCore/DatabaseTrackerTest.cpp: Removed.
+ The existing test was copied to DatabaseTrackerTest.mm.
+ * TestWebKitAPI/Tests/WebCore/cocoa/DatabaseTrackerTest.mm: Added.
+ (TestWebKitAPI::TEST):
+ (TestWebKitAPI::addToDatabasesTable):
+ (TestWebKitAPI::removeDirectoryAndAllContents):
+ (TestWebKitAPI::createFileAtPath):
+
2017-10-16 Ryan Haddad <ryanhad...@apple.com>
Unreviewed, rolling out r223422.
Modified: trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj (223426 => 223427)
--- trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj 2017-10-16 20:16:57 UTC (rev 223426)
+++ trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj 2017-10-16 20:20:53 UTC (rev 223427)
@@ -251,8 +251,8 @@
6356FB221EC4E0BA0044BF18 /* VisibleContentRect.mm in Sources */ = {isa = PBXBuildFile; fileRef = 6356FB211EC4E0BA0044BF18 /* VisibleContentRect.mm */; };
636353A71E98665D0009F8AF /* GeolocationGetCurrentPositionResult.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 636353A61E9861940009F8AF /* GeolocationGetCurrentPositionResult.html */; };
6BFD294C1D5E6C1D008EC968 /* HashCountedSet.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7A38D7E51C752D5F004F157D /* HashCountedSet.cpp */; };
+ 751B05D61F8EAC410028A09E /* DatabaseTrackerTest.mm in Sources */ = {isa = PBXBuildFile; fileRef = 751B05D51F8EAC1A0028A09E /* DatabaseTrackerTest.mm */; };
754CEC811F6722F200D0039A /* AutoFillAvailable.mm in Sources */ = {isa = PBXBuildFile; fileRef = 754CEC801F6722DC00D0039A /* AutoFillAvailable.mm */; };
- 755A20AF1E6E38630093C69F /* DatabaseTrackerTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 755A20AE1E6E38630093C69F /* DatabaseTrackerTest.cpp */; };
764322D71B61CCC30024F801 /* WordBoundaryTypingAttributes.mm in Sources */ = {isa = PBXBuildFile; fileRef = 764322D51B61CCA40024F801 /* WordBoundaryTypingAttributes.mm */; };
7673499D1930C5BB00E44DF9 /* StopLoadingDuringDidFailProvisionalLoad_bundle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7673499A1930182E00E44DF9 /* StopLoadingDuringDidFailProvisionalLoad_bundle.cpp */; };
76E182DD1547569100F1FADD /* WillSendSubmitEvent_Bundle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 76E182DC1547569100F1FADD /* WillSendSubmitEvent_Bundle.cpp */; };
@@ -1374,8 +1374,8 @@
634910DF1E9D3FF300880309 /* CoreLocation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreLocation.framework; path = System/Library/Frameworks/CoreLocation.framework; sourceTree = SDKROOT; };
6356FB211EC4E0BA0044BF18 /* VisibleContentRect.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = VisibleContentRect.mm; sourceTree = "<group>"; };
636353A61E9861940009F8AF /* GeolocationGetCurrentPositionResult.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = GeolocationGetCurrentPositionResult.html; sourceTree = "<group>"; };
+ 751B05D51F8EAC1A0028A09E /* DatabaseTrackerTest.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = DatabaseTrackerTest.mm; sourceTree = "<group>"; };
754CEC801F6722DC00D0039A /* AutoFillAvailable.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = AutoFillAvailable.mm; sourceTree = "<group>"; };
- 755A20AE1E6E38630093C69F /* DatabaseTrackerTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DatabaseTrackerTest.cpp; sourceTree = "<group>"; };
7560917719259C59009EF06E /* MemoryCacheAddImageToCacheIOS.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MemoryCacheAddImageToCacheIOS.mm; sourceTree = "<group>"; };
75F3133F18C171B70041CAEC /* EphemeralSessionPushStateNoHistoryCallback.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EphemeralSessionPushStateNoHistoryCallback.cpp; sourceTree = "<group>"; };
764322D51B61CCA40024F801 /* WordBoundaryTypingAttributes.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WordBoundaryTypingAttributes.mm; sourceTree = "<group>"; };
@@ -2124,7 +2124,6 @@
1C9EB8401E380DA1005C6442 /* ComplexTextController.cpp */,
7CB184C41AA3F2100066EDFD /* ContentExtensions.cpp */,
CD5451E919E41F9D0016936F /* CSSParser.cpp */,
- 755A20AE1E6E38630093C69F /* DatabaseTrackerTest.cpp */,
260BA5781B1D2E7B004FA07C /* DFACombiner.cpp */,
260BA57A1B1D2EE2004FA07C /* DFAHelpers.h */,
26F6E1EF1ADC749B00DE696B /* DFAMinimizer.cpp */,
@@ -2887,6 +2886,7 @@
CD89D0371C4EDB1300040A04 /* cocoa */ = {
isa = PBXGroup;
children = (
+ 751B05D51F8EAC1A0028A09E /* DatabaseTrackerTest.mm */,
5769C50A1D9B0001000847FB /* SerializedCryptoKeyWrap.mm */,
A17991861E1C994E00A505ED /* SharedBuffer.mm */,
93A7EB3C18FA63A4009E7670 /* URLExtras.mm */,
@@ -3237,7 +3237,6 @@
7CCE7F291A411B1000447C4C /* CustomProtocolsInvalidScheme.mm in Sources */,
7CCE7F2A1A411B1000447C4C /* CustomProtocolsSyncXHRTest.mm in Sources */,
7CCE7F2B1A411B1000447C4C /* CustomProtocolsTest.mm in Sources */,
- 755A20AF1E6E38630093C69F /* DatabaseTrackerTest.cpp in Sources */,
2DC4CF771D2D9DD800ECCC94 /* DataDetection.mm in Sources */,
F4D4F3B61E4E2BCB00BB2767 /* DataInteractionSimulator.mm in Sources */,
F4D4F3B91E4E36E400BB2767 /* DataInteractionTests.mm in Sources */,
@@ -3535,6 +3534,7 @@
0F3B94A71A77267400DE3272 /* WKWebViewEvaluateJavaScript.mm in Sources */,
D34E08761E4E42E1005FF14A /* WKWebViewGetContents.mm in Sources */,
F4FA91811E61849B007B8C1D /* WKWebViewMacEditingTests.mm in Sources */,
+ 751B05D61F8EAC410028A09E /* DatabaseTrackerTest.mm in Sources */,
93F56DA91E5F919D003EDE84 /* WKWebViewSnapshot.mm in Sources */,
9984FACC1CFFAF60008D198C /* WKWebViewTextInput.mm in Sources */,
764322D71B61CCC30024F801 /* WordBoundaryTypingAttributes.mm in Sources */,
Deleted: trunk/Tools/TestWebKitAPI/Tests/WebCore/DatabaseTrackerTest.cpp (223426 => 223427)
--- trunk/Tools/TestWebKitAPI/Tests/WebCore/DatabaseTrackerTest.cpp 2017-10-16 20:16:57 UTC (rev 223426)
+++ trunk/Tools/TestWebKitAPI/Tests/WebCore/DatabaseTrackerTest.cpp 2017-10-16 20:20:53 UTC (rev 223427)
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2017 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-
-#if PLATFORM(IOS)
-
-#include <WebCore/DatabaseTracker.h>
-#include <WebCore/FileSystem.h>
-
-using namespace WebCore;
-
-namespace TestWebKitAPI {
-
-TEST(DatabaseTracker, DeleteDatabaseFileIfEmpty)
-{
- PlatformFileHandle handle;
- String databaseFilePath = openTemporaryFile("tempEmptyDatabase", handle);
- closeFile(handle);
-
- long long fileSize;
- getFileSize(databaseFilePath, fileSize);
- EXPECT_EQ(0, fileSize);
-
- EXPECT_TRUE(DatabaseTracker::deleteDatabaseFileIfEmpty(databaseFilePath));
-
- bool fileStillExists = fileExists(databaseFilePath);
- EXPECT_FALSE(fileStillExists);
-
- if (fileStillExists)
- deleteFile(databaseFilePath);
-}
-
-} // namespace TestWebKitAPI
-
-#endif // PLATFORM(IOS)
Added: trunk/Tools/TestWebKitAPI/Tests/WebCore/cocoa/DatabaseTrackerTest.mm (0 => 223427)
--- trunk/Tools/TestWebKitAPI/Tests/WebCore/cocoa/DatabaseTrackerTest.mm (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/WebCore/cocoa/DatabaseTrackerTest.mm 2017-10-16 20:20:53 UTC (rev 223427)
@@ -0,0 +1,307 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <WebCore/DatabaseTracker.h>
+#include <WebCore/FileSystem.h>
+#include <WebCore/OriginLock.h>
+#include <WebCore/SQLiteDatabase.h>
+#include <WebCore/SQLiteStatement.h>
+#include <WebCore/SecurityOriginData.h>
+
+using namespace WebCore;
+
+namespace TestWebKitAPI {
+
+#if PLATFORM(IOS)
+
+TEST(DatabaseTracker, DeleteDatabaseFileIfEmpty)
+{
+ PlatformFileHandle handle;
+ String databaseFilePath = openTemporaryFile("tempEmptyDatabase", handle);
+ closeFile(handle);
+
+ long long fileSize;
+ getFileSize(databaseFilePath, fileSize);
+ EXPECT_EQ(0, fileSize);
+
+ EXPECT_TRUE(DatabaseTracker::deleteDatabaseFileIfEmpty(databaseFilePath));
+
+ bool fileStillExists = fileExists(databaseFilePath);
+ EXPECT_FALSE(fileStillExists);
+
+ if (fileStillExists)
+ deleteFile(databaseFilePath);
+}
+
+#endif // PLATFORM(IOS)
+
+#if PLATFORM(COCOA)
+
+static void addToDatabasesTable(const String& databasePath, const SecurityOriginData& origin, const String& newDatabaseName, const String& newDatabasePath)
+{
+ SQLiteDatabase database;
+ database.open(databasePath);
+
+ SQLiteStatement addDatabaseStatement(database, "INSERT INTO Databases (origin, name, path) VALUES (?, ?, ?);");
+ addDatabaseStatement.prepare();
+ addDatabaseStatement.bindText(1, origin.databaseIdentifier());
+ addDatabaseStatement.bindText(2, newDatabaseName);
+ addDatabaseStatement.bindText(3, newDatabasePath);
+ addDatabaseStatement.executeCommand();
+
+ database.close();
+}
+
+static void removeDirectoryAndAllContents(const String& directoryPath)
+{
+ for (const auto& file : listDirectory(directoryPath, "*"))
+ EXPECT_TRUE(deleteFile(file));
+
+ if (fileExists(directoryPath))
+ EXPECT_TRUE(deleteEmptyDirectory(directoryPath));
+}
+
+static void createFileAtPath(const String& path)
+{
+ PlatformFileHandle fileHandle = openFile(path, OpenForWrite);
+ EXPECT_NE(-1, fileHandle);
+ closeFile(fileHandle);
+ EXPECT_TRUE(fileExists(path));
+}
+
+TEST(DatabaseTracker, DeleteOrigin)
+{
+ // Test the expected case. There is an entry in both the Origins and Databases
+ // tables, and an actual database on disk.
+ // In this case, we should remove the origin's information from both the Origins
+ // and Databases tables, and remove the database from disk.
+ NSString *webSQLDirectory = createTemporaryDirectory(@"WebSQL");
+ String databaseDirectoryPath(webSQLDirectory.UTF8String);
+
+ std::unique_ptr<DatabaseTracker> databaseTracker = DatabaseTracker::trackerWithDatabasePath(databaseDirectoryPath);
+ SecurityOriginData origin("https", "webkit.org", 443);
+
+ databaseTracker->setQuota(origin, 5242880);
+ EXPECT_EQ((unsigned)1, databaseTracker->origins().size());
+
+ String databasePath = pathByAppendingComponent(databaseDirectoryPath, "Databases.db");
+ EXPECT_TRUE(fileExists(databasePath));
+
+ String webDatabaseName = "database_name";
+ addToDatabasesTable(databasePath, origin, webDatabaseName, "database.db");
+ EXPECT_EQ((unsigned)1, databaseTracker->databaseNames(origin).size());
+
+ String originPath = pathByAppendingComponent(databaseDirectoryPath, origin.databaseIdentifier());
+ EXPECT_TRUE(makeAllDirectories(originPath));
+ EXPECT_TRUE(fileExists(originPath));
+
+ String fullWebDatabasePath = databaseTracker->fullPathForDatabase(origin, webDatabaseName, false);
+ createFileAtPath(fullWebDatabasePath);
+
+ EXPECT_TRUE(databaseTracker->deleteOrigin(origin));
+ EXPECT_TRUE(databaseTracker->origins().isEmpty());
+ EXPECT_TRUE(databaseTracker->databaseNames(origin).isEmpty());
+
+#if PLATFORM(IOS)
+ EXPECT_TRUE(DatabaseTracker::deleteDatabaseFileIfEmpty(fullWebDatabasePath));
+ EXPECT_TRUE(deleteEmptyDirectory(originPath));
+#else
+ EXPECT_FALSE(fileExists(fullWebDatabasePath));
+ EXPECT_FALSE(fileExists(originPath));
+#endif
+
+ removeDirectoryAndAllContents(databaseDirectoryPath);
+ EXPECT_FALSE(fileExists(databaseDirectoryPath));
+}
+
+TEST(DatabaseTracker, DeleteOriginWhenDatabaseDoesNotExist)
+{
+ // Test the case where there is an entry in both the Origins and Databases tables,
+ // but not an actual database on disk.
+ // The information should still be removed from the tables.
+ NSString *webSQLDirectory = createTemporaryDirectory(@"WebSQL");
+ String databaseDirectoryPath(webSQLDirectory.UTF8String);
+
+ std::unique_ptr<DatabaseTracker> databaseTracker = DatabaseTracker::trackerWithDatabasePath(databaseDirectoryPath);
+ SecurityOriginData origin("https", "webkit.org", 443);
+
+ databaseTracker->setQuota(origin, 5242880);
+ EXPECT_EQ((unsigned)1, databaseTracker->origins().size());
+
+ String databasePath = pathByAppendingComponent(databaseDirectoryPath, "Databases.db");
+ EXPECT_TRUE(fileExists(databasePath));
+
+ String webDatabaseName = "database_name";
+ addToDatabasesTable(databasePath, origin, webDatabaseName, "database.db");
+ EXPECT_EQ((unsigned)1, databaseTracker->databaseNames(origin).size());
+
+ String webDatabaseFullPath = databaseTracker->fullPathForDatabase(origin, webDatabaseName, false);
+ EXPECT_FALSE(fileExists(webDatabaseFullPath));
+
+ EXPECT_TRUE(databaseTracker->deleteOrigin(origin));
+
+ EXPECT_TRUE(databaseTracker->origins().isEmpty());
+ EXPECT_TRUE(databaseTracker->databaseNames(origin).isEmpty());
+
+ removeDirectoryAndAllContents(databaseDirectoryPath);
+ EXPECT_FALSE(fileExists(databaseDirectoryPath));
+}
+
+TEST(DatabaseTracker, DeleteOriginWhenDeletingADatabaseFails)
+{
+ // Test the case where there are entries in both the Databases and Origins tables.
+ // There are also databases on disk.
+ // When we call deleteOrigin(), deleting one of these databases fails.
+ // In this case, we shouldn't remove the information from either the Databases or
+ // Origins tables.
+ NSString *webSQLDirectory = createTemporaryDirectory(@"WebSQL");
+ String databaseDirectoryPath(webSQLDirectory.UTF8String);
+
+ std::unique_ptr<DatabaseTracker> databaseTracker = DatabaseTracker::trackerWithDatabasePath(databaseDirectoryPath);
+ SecurityOriginData origin("https", "webkit.org", 443);
+
+ databaseTracker->setQuota(origin, 5242880);
+ EXPECT_EQ((unsigned)1, databaseTracker->origins().size());
+
+ String databasePath = pathByAppendingComponent(databaseDirectoryPath, "Databases.db");
+ EXPECT_TRUE(fileExists(databasePath));
+
+ String webDatabaseName = "database_name";
+ addToDatabasesTable(databasePath, origin, webDatabaseName, "database.db");
+ EXPECT_EQ((unsigned)1, databaseTracker->databaseNames(origin).size());
+
+ String originPath = pathByAppendingComponent(databaseDirectoryPath, origin.databaseIdentifier());
+ EXPECT_TRUE(makeAllDirectories(originPath));
+ EXPECT_TRUE(fileExists(originPath));
+
+ String fullWebDatabasePath = databaseTracker->fullPathForDatabase(origin, webDatabaseName, false);
+ createFileAtPath(fullWebDatabasePath);
+
+ chmod(fullWebDatabasePath.utf8().data(), 555);
+
+#if !PLATFORM(IOS)
+ chflags(fullWebDatabasePath.utf8().data(), UF_IMMUTABLE);
+#endif
+
+ EXPECT_FALSE(databaseTracker->deleteOrigin(origin));
+
+ EXPECT_TRUE(fileExists(fullWebDatabasePath));
+ EXPECT_TRUE(fileExists(originPath));
+
+ EXPECT_EQ((unsigned)1, databaseTracker->origins().size());
+ EXPECT_EQ((unsigned)1, databaseTracker->databaseNames(origin).size());
+
+ chmod(fullWebDatabasePath.utf8().data(), 666);
+
+#if !PLATFORM(IOS)
+ chflags(fullWebDatabasePath.utf8().data(), 0);
+#endif
+
+ EXPECT_TRUE(deleteFile(fullWebDatabasePath));
+ EXPECT_TRUE(deleteEmptyDirectory(originPath));
+
+ removeDirectoryAndAllContents(databaseDirectoryPath);
+ EXPECT_FALSE(fileExists(databaseDirectoryPath));
+}
+
+TEST(DatabaseTracker, DeleteDatabase)
+{
+ // Test the expected case. There is an entry in the Databases table
+ // and a database on disk. After the deletion, the database should be deleted
+ // from disk, and the information should be gone from the Databases table.
+ NSString *webSQLDirectory = createTemporaryDirectory(@"WebSQL");
+ String databaseDirectoryPath(webSQLDirectory.UTF8String);
+
+ std::unique_ptr<DatabaseTracker> databaseTracker = DatabaseTracker::trackerWithDatabasePath(databaseDirectoryPath);
+ SecurityOriginData origin("https", "webkit.org", 443);
+
+ databaseTracker->setQuota(origin, 5242880);
+ EXPECT_EQ((unsigned)1, databaseTracker->origins().size());
+
+ String databasePath = pathByAppendingComponent(databaseDirectoryPath, "Databases.db");
+ EXPECT_TRUE(fileExists(databasePath));
+
+ String webDatabaseName = "database_name";
+ addToDatabasesTable(databasePath, origin, webDatabaseName, "database.db");
+ EXPECT_EQ((unsigned)1, databaseTracker->databaseNames(origin).size());
+
+ String originPath = pathByAppendingComponent(databaseDirectoryPath, origin.databaseIdentifier());
+ EXPECT_TRUE(makeAllDirectories(originPath));
+ EXPECT_TRUE(fileExists(originPath));
+
+ String fullWebDatabasePath = databaseTracker->fullPathForDatabase(origin, webDatabaseName, false);
+ createFileAtPath(fullWebDatabasePath);
+
+ EXPECT_TRUE(databaseTracker->deleteDatabase(origin, webDatabaseName));
+ EXPECT_TRUE(databaseTracker->databaseNames(origin).isEmpty());
+
+#if PLATFORM(IOS)
+ EXPECT_TRUE(DatabaseTracker::deleteDatabaseFileIfEmpty(fullWebDatabasePath));
+#else
+ EXPECT_FALSE(fileExists(fullWebDatabasePath));
+#endif
+
+ EXPECT_EQ((unsigned)1, databaseTracker->origins().size());
+ EXPECT_TRUE(deleteEmptyDirectory(originPath));
+ removeDirectoryAndAllContents(databaseDirectoryPath);
+ EXPECT_FALSE(fileExists(databaseDirectoryPath));
+}
+
+TEST(DatabaseTracker, DeleteDatabaseWhenDatabaseDoesNotExist)
+{
+ // Test the case where we try to delete a database that doesn't exist on disk.
+ // We should still remove the database information from the Databases table.
+ NSString *webSQLDirectory = createTemporaryDirectory(@"WebSQL");
+ String databaseDirectoryPath(webSQLDirectory.UTF8String);
+
+ std::unique_ptr<DatabaseTracker> databaseTracker = DatabaseTracker::trackerWithDatabasePath(databaseDirectoryPath);
+ SecurityOriginData origin("https", "webkit.org", 443);
+
+ databaseTracker->setQuota(origin, 5242880);
+ EXPECT_EQ((unsigned)1, databaseTracker->origins().size());
+
+ String databasePath = pathByAppendingComponent(databaseDirectoryPath, "Databases.db");
+ EXPECT_TRUE(fileExists(databasePath));
+
+ String webDatabaseName = "database_name";
+ addToDatabasesTable(databasePath, origin, webDatabaseName, "database.db");
+ EXPECT_EQ((unsigned)1, databaseTracker->databaseNames(origin).size());
+
+ String webDatabaseFullPath = databaseTracker->fullPathForDatabase(origin, webDatabaseName, false);
+ EXPECT_FALSE(fileExists(webDatabaseFullPath));
+
+ EXPECT_TRUE(databaseTracker->deleteDatabase(origin, webDatabaseName));
+ EXPECT_TRUE(databaseTracker->databaseNames(origin).isEmpty());
+
+ removeDirectoryAndAllContents(databaseDirectoryPath);
+ EXPECT_FALSE(fileExists(databaseDirectoryPath));
+}
+
+#endif // PLATFORM(COCOA)
+
+} // namespace TestWebKitAPI
+