Modern IDB: New database versions are never committed to SQLite.
authorbeidson@apple.com <beidson@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 27 Feb 2016 04:39:05 +0000 (04:39 +0000)
committerbeidson@apple.com <beidson@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 27 Feb 2016 04:39:05 +0000 (04:39 +0000)
<rdar://problem/24860952> and https://bugs.webkit.org/show_bug.cgi?id=154741

Modern IDB: If a database handle is not open, files are not actually deleted from disk
https://bugs.webkit.org/show_bug.cgi?id=154756

Reviewed by Alex Christensen.

Source/WebCore:

Tested by API test "IndexedDBPersistence"

* Modules/indexeddb/server/IDBServer.cpp:
(WebCore::IDBServer::IDBServer::deleteDatabase): If there's not an open handle to the database, create one.

* Modules/indexeddb/server/SQLiteIDBBackingStore.cpp:
(WebCore::IDBServer::SQLiteIDBBackingStore::beginTransaction): If a version change transaction, actually
  set the new version on disk.

* Modules/indexeddb/server/UniqueIDBDatabase.cpp:
(WebCore::IDBServer::UniqueIDBDatabase::performCurrentDeleteOperation):
(WebCore::IDBServer::UniqueIDBDatabase::deleteBackingStore): If there is no open backing store, create one.
  This is necessary to both read the current database version, and to actually delete the file on disk.
(WebCore::IDBServer::UniqueIDBDatabase::didDeleteBackingStore): If necessary, manufacture a "most recently
  deleted database info" from the version returned by deleteBackingStore.
* Modules/indexeddb/server/UniqueIDBDatabase.h:

Source/WebKit2:

Add WK2 SPI to force termination of the database process.

* UIProcess/API/Cocoa/WKProcessPool.mm:
(-[WKProcessPool _terminateDatabaseProcess]):
* UIProcess/API/Cocoa/WKProcessPoolPrivate.h:
* UIProcess/WebProcessPool.cpp:
(WebKit::WebProcessPool::terminateDatabaseProcess):
* UIProcess/WebProcessPool.h:

Tools:

This also happens to test the previously untested fix for http://trac.webkit.org/changeset/197190

* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
* TestWebKitAPI/Tests/WebKit2Cocoa/IndexedDBPersistence-1.html: Added.
* TestWebKitAPI/Tests/WebKit2Cocoa/IndexedDBPersistence-2.html: Added.
* TestWebKitAPI/Tests/WebKit2Cocoa/IndexedDBPersistence.mm: Added.
(-[IndexedDBNavigationDelegate webView:didFinishNavigation:]):
(-[IndexedDBMessageHandler userContentController:didReceiveScriptMessage:]):
(TEST):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@197231 268f45cc-cd09-0410-ab3c-d52691b4dbfc

15 files changed:
Source/WebCore/ChangeLog
Source/WebCore/Modules/indexeddb/server/IDBServer.cpp
Source/WebCore/Modules/indexeddb/server/SQLiteIDBBackingStore.cpp
Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.cpp
Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.h
Source/WebKit2/ChangeLog
Source/WebKit2/UIProcess/API/Cocoa/WKProcessPool.mm
Source/WebKit2/UIProcess/API/Cocoa/WKProcessPoolPrivate.h
Source/WebKit2/UIProcess/WebProcessPool.cpp
Source/WebKit2/UIProcess/WebProcessPool.h
Tools/ChangeLog
Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj
Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IndexedDBPersistence-1.html [new file with mode: 0644]
Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IndexedDBPersistence-2.html [new file with mode: 0644]
Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IndexedDBPersistence.mm [new file with mode: 0644]

index 868492f..8c5ed46 100644 (file)
@@ -1,3 +1,30 @@
+2016-02-26  Brady Eidson  <beidson@apple.com>
+
+        Modern IDB: New database versions are never committed to SQLite.
+        <rdar://problem/24860952> and https://bugs.webkit.org/show_bug.cgi?id=154741
+        
+        Modern IDB: If a database handle is not open, files are not actually deleted from disk
+        https://bugs.webkit.org/show_bug.cgi?id=154756
+
+        Reviewed by Alex Christensen.
+
+        Tested by API test "IndexedDBPersistence"
+
+        * Modules/indexeddb/server/IDBServer.cpp:
+        (WebCore::IDBServer::IDBServer::deleteDatabase): If there's not an open handle to the database, create one.
+
+        * Modules/indexeddb/server/SQLiteIDBBackingStore.cpp:
+        (WebCore::IDBServer::SQLiteIDBBackingStore::beginTransaction): If a version change transaction, actually
+          set the new version on disk.
+        
+        * Modules/indexeddb/server/UniqueIDBDatabase.cpp:
+        (WebCore::IDBServer::UniqueIDBDatabase::performCurrentDeleteOperation):
+        (WebCore::IDBServer::UniqueIDBDatabase::deleteBackingStore): If there is no open backing store, create one.
+          This is necessary to both read the current database version, and to actually delete the file on disk.
+        (WebCore::IDBServer::UniqueIDBDatabase::didDeleteBackingStore): If necessary, manufacture a "most recently
+          deleted database info" from the version returned by deleteBackingStore.
+        * Modules/indexeddb/server/UniqueIDBDatabase.h:
+
 2016-02-26  Chris Dumez  <cdumez@apple.com>
 
         Add API test coverage for parseHTMLInteger / parseHTMLNonNegativeInteger
index b9f4e20..68a73e6 100644 (file)
@@ -151,10 +151,8 @@ void IDBServer::deleteDatabase(const IDBRequestData& requestData)
     }
 
     auto* database = m_uniqueIDBDatabaseMap.get(requestData.databaseIdentifier());
-    if (!database) {
-        connection->didDeleteDatabase(IDBResultData::deleteDatabaseSuccess(requestData.requestIdentifier(), IDBDatabaseInfo(requestData.databaseIdentifier().databaseName(), 0)));
-        return;
-    }
+    if (!database)
+        database = &getOrCreateUniqueIDBDatabase(requestData.databaseIdentifier());
 
     database->handleDelete(*connection, requestData);
 }
index c1e8163..87ce6c6 100644 (file)
@@ -623,9 +623,16 @@ IDBError SQLiteIDBBackingStore::beginTransaction(const IDBTransactionInfo& info)
     addResult.iterator->value = std::make_unique<SQLiteIDBTransaction>(*this, info);
 
     auto error = addResult.iterator->value->begin(*m_sqliteDB);
-    if (error.isNull() && info.mode() == IndexedDB::TransactionMode::VersionChange)
+    if (error.isNull() && info.mode() == IndexedDB::TransactionMode::VersionChange) {
         m_originalDatabaseInfoBeforeVersionChange = std::make_unique<IDBDatabaseInfo>(*m_databaseInfo);
 
+        SQLiteStatement sql(*m_sqliteDB, ASCIILiteral("UPDATE IDBDatabaseInfo SET value = ? where key = 'DatabaseVersion';"));
+        if (sql.prepare() != SQLITE_OK
+            || sql.bindText(1, String::number(info.newVersion())) != SQLITE_OK
+            || sql.step() != SQLITE_DONE)
+            error = { IDBDatabaseException::UnknownError, ASCIILiteral("Failed to store new database version in database") };
+    }
+
     return error;
 }
 
index 575883e..04b939f 100644 (file)
@@ -193,30 +193,38 @@ void UniqueIDBDatabase::performCurrentDeleteOperation()
     // In that scenario only the first request will actually have to delete the database.
     // Subsequent requests can immediately notify their completion.
 
-    if (m_databaseInfo) {
-        m_deleteBackingStoreInProgress = true;
-        m_server.postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::deleteBackingStore));
-    } else {
-        ASSERT(m_mostRecentDeletedDatabaseInfo);
-        didDeleteBackingStore();
+    if (!m_deleteBackingStoreInProgress) {
+        if (!m_databaseInfo && m_mostRecentDeletedDatabaseInfo)
+            didDeleteBackingStore(0);
+        else {
+            m_deleteBackingStoreInProgress = true;
+            m_server.postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::deleteBackingStore, m_identifier));
+        }
     }
 }
 
-void UniqueIDBDatabase::deleteBackingStore()
+void UniqueIDBDatabase::deleteBackingStore(const IDBDatabaseIdentifier& identifier)
 {
     ASSERT(!isMainThread());
     LOG(IndexedDB, "(db) UniqueIDBDatabase::deleteBackingStore");
 
+    uint64_t deletedVersion = 0;
+
     if (m_backingStore) {
         m_backingStore->deleteBackingStore();
         m_backingStore = nullptr;
         m_backingStoreSupportsSimultaneousTransactions = false;
+    } else {
+        auto backingStore = m_server.createBackingStore(identifier);
+        auto databaseInfo = backingStore->getOrEstablishDatabaseInfo();
+        deletedVersion = databaseInfo.version();
+        backingStore->deleteBackingStore();
     }
 
-    m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didDeleteBackingStore));
+    m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didDeleteBackingStore, deletedVersion));
 }
 
-void UniqueIDBDatabase::didDeleteBackingStore()
+void UniqueIDBDatabase::didDeleteBackingStore(uint64_t deletedVersion)
 {
     ASSERT(isMainThread());
     LOG(IndexedDB, "(main) UniqueIDBDatabase::didDeleteBackingStore");
@@ -231,7 +239,12 @@ void UniqueIDBDatabase::didDeleteBackingStore()
     if (m_databaseInfo)
         m_mostRecentDeletedDatabaseInfo = WTFMove(m_databaseInfo);
 
-    ASSERT(m_mostRecentDeletedDatabaseInfo);
+    // If this UniqueIDBDatabase was brought into existence for the purpose of deleting the file on disk,
+    // we won't have a m_mostRecentDeletedDatabaseInfo. In that case, we'll manufacture one using the
+    // passed in deletedVersion argument.
+    if (!m_mostRecentDeletedDatabaseInfo)
+        m_mostRecentDeletedDatabaseInfo = std::make_unique<IDBDatabaseInfo>(m_identifier.databaseName(), deletedVersion);
+
     m_currentOpenDBRequest->notifyDidDeleteDatabase(*m_mostRecentDeletedDatabaseInfo);
     m_currentOpenDBRequest = nullptr;
 
index 1caacd6..bdbb384 100644 (file)
@@ -125,7 +125,7 @@ private:
     void inProgressTransactionCompleted(const IDBResourceIdentifier&);
 
     // Database thread operations
-    void deleteBackingStore();
+    void deleteBackingStore(const IDBDatabaseIdentifier&);
     void openBackingStore(const IDBDatabaseIdentifier&);
     void performCommitTransaction(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier);
     void performAbortTransaction(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier);
@@ -145,7 +145,7 @@ private:
     void performActivateTransactionInBackingStore(uint64_t callbackIdentifier, const IDBTransactionInfo&);
 
     // Main thread callbacks
-    void didDeleteBackingStore();
+    void didDeleteBackingStore(uint64_t deletedVersion);
     void didOpenBackingStore(const IDBDatabaseInfo&);
     void didPerformCreateObjectStore(uint64_t callbackIdentifier, const IDBError&, const IDBObjectStoreInfo&);
     void didPerformDeleteObjectStore(uint64_t callbackIdentifier, const IDBError&, uint64_t objectStoreIdentifier);
index 6270c91..6ef7309 100644 (file)
@@ -1,3 +1,22 @@
+2016-02-26  Brady Eidson  <beidson@apple.com>
+
+        Modern IDB: New database versions are never committed to SQLite.
+        <rdar://problem/24860952> and https://bugs.webkit.org/show_bug.cgi?id=154741
+        
+        Modern IDB: If a database handle is not open, files are not actually deleted from disk
+        https://bugs.webkit.org/show_bug.cgi?id=154756
+
+        Reviewed by Alex Christensen.
+
+        Add WK2 SPI to force termination of the database process.
+
+        * UIProcess/API/Cocoa/WKProcessPool.mm:
+        (-[WKProcessPool _terminateDatabaseProcess]):
+        * UIProcess/API/Cocoa/WKProcessPoolPrivate.h:
+        * UIProcess/WebProcessPool.cpp:
+        (WebKit::WebProcessPool::terminateDatabaseProcess):
+        * UIProcess/WebProcessPool.h:
+
 2016-02-26  Alex Christensen  <achristensen@webkit.org>
 
         Clear credentials and prevent unauthorized credential storage when using NetworkSession
index 8d59365..8c5c9a4 100644 (file)
@@ -285,6 +285,11 @@ static WebKit::HTTPCookieAcceptPolicy toHTTPCookieAcceptPolicy(NSHTTPCookieAccep
     _processPool->setAutomationSession(automationSession ? automationSession->_session.get() : nullptr);
 }
 
+- (void)_terminateDatabaseProcess
+{
+    _processPool->terminateDatabaseProcess();
+}
+
 @end
 
 #endif // WK_API_ENABLED
index 3637367..a773618 100644 (file)
@@ -61,6 +61,9 @@
 - (void)_automationCapabilitiesDidChange WK_AVAILABLE(WK_MAC_TBA, WK_IOS_TBA);
 - (void)_setAutomationSession:(_WKAutomationSession *)automationSession WK_AVAILABLE(WK_MAC_TBA, WK_IOS_TBA);
 
+// Test only. Should be called only while no web content processes are running.
+- (void)_terminateDatabaseProcess;
+
 @end
 
 #endif
index 5af1668..b2d31b5 100644 (file)
@@ -1086,6 +1086,16 @@ void WebProcessPool::clearCachedCredentials()
         m_networkProcess->send(Messages::NetworkProcess::ClearCachedCredentials(), 0);
 }
 
+void WebProcessPool::terminateDatabaseProcess()
+{
+    ASSERT(m_processes.isEmpty());
+    if (!m_databaseProcess)
+        return;
+
+    m_databaseProcess->terminate();
+    m_databaseProcess = nullptr;
+}
+
 void WebProcessPool::allowSpecificHTTPSCertificateForHost(const WebCertificateInfo* certificate, const String& host)
 {
     if (m_networkProcess)
index c81467c..24ab928 100644 (file)
@@ -244,6 +244,7 @@ public:
     bool isUsingTestingNetworkSession() const { return m_shouldUseTestingNetworkSession; }
 
     void clearCachedCredentials();
+    void terminateDatabaseProcess();
 
     void allowSpecificHTTPSCertificateForHost(const WebCertificateInfo*, const String& host);
 
index a709b96..08a8370 100644 (file)
@@ -1,3 +1,23 @@
+2016-02-26  Brady Eidson  <beidson@apple.com>
+
+        Modern IDB: New database versions are never committed to SQLite.
+        <rdar://problem/24860952> and https://bugs.webkit.org/show_bug.cgi?id=154741
+        
+        Modern IDB: If a database handle is not open, files are not actually deleted from disk
+        https://bugs.webkit.org/show_bug.cgi?id=154756
+
+        Reviewed by Alex Christensen.
+
+        This also happens to test the previously untested fix for http://trac.webkit.org/changeset/197190
+
+        * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+        * TestWebKitAPI/Tests/WebKit2Cocoa/IndexedDBPersistence-1.html: Added.
+        * TestWebKitAPI/Tests/WebKit2Cocoa/IndexedDBPersistence-2.html: Added.
+        * TestWebKitAPI/Tests/WebKit2Cocoa/IndexedDBPersistence.mm: Added.
+        (-[IndexedDBNavigationDelegate webView:didFinishNavigation:]):
+        (-[IndexedDBMessageHandler userContentController:didReceiveScriptMessage:]):
+        (TEST):
+
 2016-02-26  Commit Queue  <commit-queue@webkit.org>
 
         Unreviewed, rolling out r197216.
index f5fa06d..9d604aa 100644 (file)
@@ -62,6 +62,9 @@
                51393E221523952D005F39C5 /* DOMWindowExtensionBasic_Bundle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 51393E1D1523944A005F39C5 /* DOMWindowExtensionBasic_Bundle.cpp */; };
                5142B2731517C8C800C32B19 /* ContextMenuCanCopyURL.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 5142B2721517C89100C32B19 /* ContextMenuCanCopyURL.html */; };
                517E7E04151119C100D0B008 /* MemoryCachePruneWithinResourceLoadDelegate.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 517E7E031511187500D0B008 /* MemoryCachePruneWithinResourceLoadDelegate.html */; };
+               51B1EE8E1C80F5880064FB98 /* IndexedDBPersistence.mm in Sources */ = {isa = PBXBuildFile; fileRef = 51B1EE8D1C80F5880064FB98 /* IndexedDBPersistence.mm */; };
+               51B1EE961C80FAEF0064FB98 /* IndexedDBPersistence-1.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 51B1EE941C80FADD0064FB98 /* IndexedDBPersistence-1.html */; };
+               51B1EE971C80FAEF0064FB98 /* IndexedDBPersistence-2.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 51B1EE951C80FADD0064FB98 /* IndexedDBPersistence-2.html */; };
                51B454EC1B4E236B0085EAA6 /* WebViewCloseInsideDidFinishLoadForFrame.mm in Sources */ = {isa = PBXBuildFile; fileRef = 51B454EB1B4E236B0085EAA6 /* WebViewCloseInsideDidFinishLoadForFrame.mm */; };
                51CB4AD81B3A079C00C1B1C6 /* ModalAlertsSPI.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 51CB4AD71B3A079C00C1B1C6 /* ModalAlertsSPI.cpp */; };
                51CD1C6C1B38CE4300142CA5 /* ModalAlerts.mm in Sources */ = {isa = PBXBuildFile; fileRef = 51CD1C6A1B38CE3600142CA5 /* ModalAlerts.mm */; };
                        dstPath = TestWebKitAPI.resources;
                        dstSubfolderSpec = 7;
                        files = (
+                               51B1EE961C80FAEF0064FB98 /* IndexedDBPersistence-1.html in Copy Resources */,
+                               51B1EE971C80FAEF0064FB98 /* IndexedDBPersistence-2.html in Copy Resources */,
                                57F56A5C1C7F8CC100F31D7E /* IsNavigationActionTrusted.html in Copy Resources */,
                                A16F66BA1C40EB4F00BD4D24 /* ContentFiltering.html in Copy Resources */,
                                CDC8E4941BC6F10800594FEC /* video-with-audio.html in Copy Resources */,
                5142B2721517C89100C32B19 /* ContextMenuCanCopyURL.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = ContextMenuCanCopyURL.html; sourceTree = "<group>"; };
                517E7DFB15110EA600D0B008 /* MemoryCachePruneWithinResourceLoadDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MemoryCachePruneWithinResourceLoadDelegate.mm; sourceTree = "<group>"; };
                517E7E031511187500D0B008 /* MemoryCachePruneWithinResourceLoadDelegate.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = MemoryCachePruneWithinResourceLoadDelegate.html; sourceTree = "<group>"; };
+               51B1EE8D1C80F5880064FB98 /* IndexedDBPersistence.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = IndexedDBPersistence.mm; sourceTree = "<group>"; };
+               51B1EE941C80FADD0064FB98 /* IndexedDBPersistence-1.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "IndexedDBPersistence-1.html"; sourceTree = "<group>"; };
+               51B1EE951C80FADD0064FB98 /* IndexedDBPersistence-2.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "IndexedDBPersistence-2.html"; sourceTree = "<group>"; };
                51B454EB1B4E236B0085EAA6 /* WebViewCloseInsideDidFinishLoadForFrame.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WebViewCloseInsideDidFinishLoadForFrame.mm; sourceTree = "<group>"; };
                51CB4AD71B3A079C00C1B1C6 /* ModalAlertsSPI.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ModalAlertsSPI.cpp; sourceTree = "<group>"; };
                51CD1C6A1B38CE3600142CA5 /* ModalAlerts.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ModalAlerts.mm; sourceTree = "<group>"; };
                                A1A4FE5D18DD3DB700B5EA8A /* Download.mm */,
                                2D8104CB1BEC13E70020DA46 /* FindInPage.mm */,
                                2D1FE0AF1AD465C1006CD9E6 /* FixedLayoutSize.mm */,
+                               51B1EE8D1C80F5880064FB98 /* IndexedDBPersistence.mm */,
                                37D36ED61AF42ECD00BAF5D9 /* LoadAlternateHTMLString.mm */,
                                51CD1C6A1B38CE3600142CA5 /* ModalAlerts.mm */,
                                1ABC3DED1899BE6D004F0626 /* Navigation.mm */,
                        isa = PBXGroup;
                        children = (
                                A16F66B91C40EA2000BD4D24 /* ContentFiltering.html */,
+                               51B1EE941C80FADD0064FB98 /* IndexedDBPersistence-1.html */,
+                               51B1EE951C80FADD0064FB98 /* IndexedDBPersistence-2.html */,
                        );
                        name = Resources;
                        sourceTree = "<group>";
                                CD89D03A1C4EDB2A00040A04 /* WebCoreNSURLSession.mm in Sources */,
                                83B88A341C80056D00BB2418 /* HTMLParserIdioms.cpp in Sources */,
                                A1C4FB6E1BACCE50003742D0 /* QuickLook.mm in Sources */,
+                               51B1EE8E1C80F5880064FB98 /* IndexedDBPersistence.mm in Sources */,
                                7A5623111AD5AF3E0096B920 /* MenuTypesForMouseEvents.cpp in Sources */,
                                1AAD19F71C7CE20300831E47 /* Coding.mm in Sources */,
                                9B0786A31C58830F00D159E3 /* InjectedBundleMakeAllShadowRootsOpen.cpp in Sources */,
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IndexedDBPersistence-1.html b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IndexedDBPersistence-1.html
new file mode 100644 (file)
index 0000000..62a1baf
--- /dev/null
@@ -0,0 +1,35 @@
+<script>
+
+var request = window.indexedDB.deleteDatabase("IndexedDBPersistence");
+request.onsuccess = function(e)
+{
+    continueTest();
+}
+request.onerror = function(e)
+{
+    // Unexpected error
+    window.webkit.messageHandlers.testHandler.postMessage('Error');
+}
+
+function continueTest()
+{
+    var request = window.indexedDB.open("IndexedDBPersistence", 2);
+
+    request.onsuccess = function()
+    {
+        window.webkit.messageHandlers.testHandler.postMessage('Success');
+
+    }
+    request.onerror = function()
+    {
+        // Unexpected error
+        window.webkit.messageHandlers.testHandler.postMessage('Error');
+    }
+    request.onupgradeneeded = function(event)
+    {
+        window.webkit.messageHandlers.testHandler.postMessage('UpgradeNeeded');
+
+        event.target.result.createObjectStore("TestObjectStore");
+    }
+}
+</script>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IndexedDBPersistence-2.html b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IndexedDBPersistence-2.html
new file mode 100644 (file)
index 0000000..d8ab125
--- /dev/null
@@ -0,0 +1,22 @@
+<script>
+
+var request = window.indexedDB.open("IndexedDBPersistence");
+
+request.onsuccess = function(event)
+{
+    window.webkit.messageHandlers.testHandler.postMessage(event.target.result.version + " " + event.target.result.objectStoreNames[0]);
+}
+
+request.onerror = function()
+{
+    // Unexpected error
+    window.webkit.messageHandlers.testHandler.postMessage('Unexpected Error');
+}
+
+request.onupgradeneeded = function()
+{
+    // Unexpected error
+    window.webkit.messageHandlers.testHandler.postMessage('Unexpected UpgradeNeeded');
+}
+
+</script>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IndexedDBPersistence.mm b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IndexedDBPersistence.mm
new file mode 100644 (file)
index 0000000..f20f4fd
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#import "config.h"
+
+#import "PlatformUtilities.h"
+#import "Test.h"
+#import <WebKit/WebKit.h>
+#import <WebKit/WKProcessPoolPrivate.h>
+#import <WebKit/WKUserContentControllerPrivate.h>
+#import <WebKit/_WKProcessPoolConfiguration.h>
+#import <WebKit/_WKUserStyleSheet.h>
+#import <wtf/RetainPtr.h>
+
+#if WK_API_ENABLED
+
+static bool isDoneWithNavigation;
+
+@interface IndexedDBNavigationDelegate : NSObject <WKNavigationDelegate>
+@end
+
+@implementation IndexedDBNavigationDelegate
+
+- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation
+{
+    isDoneWithNavigation = true;
+}
+
+@end
+
+static bool receivedScriptMessage;
+static RetainPtr<WKScriptMessage> lastScriptMessage;
+
+@interface IndexedDBMessageHandler : NSObject <WKScriptMessageHandler>
+@end
+
+@implementation IndexedDBMessageHandler
+
+- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
+{
+    receivedScriptMessage = true;
+    lastScriptMessage = message;
+}
+
+@end
+
+TEST(IndexedDB, IndexedDBPersistence)
+{
+    RetainPtr<IndexedDBMessageHandler> handler = adoptNS([[IndexedDBMessageHandler alloc] init]);
+    RetainPtr<WKWebViewConfiguration> configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
+    [[configuration userContentController] addScriptMessageHandler:handler.get() name:@"testHandler"];
+
+    RetainPtr<WKWebView> webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
+
+    NSURLRequest *request = [NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:@"IndexedDBPersistence-1" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]];
+    [webView loadRequest:request];
+
+    TestWebKitAPI::Util::run(&receivedScriptMessage);
+    receivedScriptMessage = false;
+    RetainPtr<NSString> string1 = (NSString *)[lastScriptMessage body];
+
+    TestWebKitAPI::Util::run(&receivedScriptMessage);
+    receivedScriptMessage = false;
+    RetainPtr<NSString> string2 = (NSString *)[lastScriptMessage body];
+
+    // Ditch this web view (ditching its web process)
+    webView = nil;
+
+    // Terminate the database process
+    [configuration.get().processPool _terminateDatabaseProcess];
+
+    // Make a new web view to finish the test
+    webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
+
+    request = [NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:@"IndexedDBPersistence-2" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]];
+    [webView loadRequest:request];
+
+    TestWebKitAPI::Util::run(&receivedScriptMessage);
+    receivedScriptMessage = false;
+    RetainPtr<NSString> string3 = (NSString *)[lastScriptMessage body];
+
+    EXPECT_WK_STREQ(@"UpgradeNeeded", string1.get());
+    EXPECT_WK_STREQ(@"Success", string2.get());
+    EXPECT_WK_STREQ(@"2 TestObjectStore", string3.get());
+}
+
+#endif