Title: [223427] trunk
Revision
223427
Author
ryanhad...@apple.com
Date
2017-10-16 13:20:53 -0700 (Mon, 16 Oct 2017)

Log Message

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

Patch by Maureen Daum <md...@apple.com> on 2017-10-16
Reviewed by Brady Eidson.

Source/WebCore:

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.

Tools:

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):

Modified Paths

Added Paths

Removed Paths

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
+
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to