Title: [194587] trunk
Revision
194587
Author
[email protected]
Date
2016-01-05 09:44:50 -0800 (Tue, 05 Jan 2016)

Log Message

Modern IDB: Transactions from a previous page can leak forward to the next.
https://bugs.webkit.org/show_bug.cgi?id=152698

Reviewed by Alex Christensen.

Source/WebCore:

Test: storage/indexeddb/modern/transactions-stop-on-navigation.html

This patch is mostly about actually implementing IDBDatabase::stop and IDBTransaction::stop.
Most of the rest of the scattered changes are about cleaning up now-incorrect ASSERTs.

* Modules/indexeddb/client/IDBDatabaseImpl.cpp:
(WebCore::IDBClient::IDBDatabase::close):
(WebCore::IDBClient::IDBDatabase::maybeCloseInServer):
(WebCore::IDBClient::IDBDatabase::stop):
(WebCore::IDBClient::IDBDatabase::startVersionChangeTransaction):
(WebCore::IDBClient::IDBDatabase::didAbortTransaction):
* Modules/indexeddb/client/IDBDatabaseImpl.h:

* Modules/indexeddb/client/IDBOpenDBRequestImpl.cpp:
(WebCore::IDBClient::IDBOpenDBRequest::requestCompleted):

* Modules/indexeddb/client/IDBRequestImpl.h:

* Modules/indexeddb/client/IDBTransactionImpl.cpp:
(WebCore::IDBClient::IDBTransaction::IDBTransaction):
(WebCore::IDBClient::IDBTransaction::stop):
(WebCore::IDBClient::IDBTransaction::abortOnServerAndCancelRequests):

* Modules/indexeddb/server/UniqueIDBDatabase.cpp:
(WebCore::IDBServer::UniqueIDBDatabase::performCurrentDeleteOperation):
(WebCore::IDBServer::UniqueIDBDatabase::didPerformAbortTransaction):

LayoutTests:

* storage/indexeddb/modern/resources/transactions-stop-on-navigation-2.html: Added.
* storage/indexeddb/modern/resources/transactions-stop-on-navigation.js: Added.
* storage/indexeddb/modern/transactions-stop-on-navigation-expected.txt: Added.
* storage/indexeddb/modern/transactions-stop-on-navigation.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (194586 => 194587)


--- trunk/LayoutTests/ChangeLog	2016-01-05 17:31:46 UTC (rev 194586)
+++ trunk/LayoutTests/ChangeLog	2016-01-05 17:44:50 UTC (rev 194587)
@@ -1,3 +1,15 @@
+2016-01-05  Brady Eidson  <[email protected]>
+
+        Modern IDB: Transactions from a previous page can leak forward to the next.
+        https://bugs.webkit.org/show_bug.cgi?id=152698
+
+        Reviewed by Alex Christensen.
+
+        * storage/indexeddb/modern/resources/transactions-stop-on-navigation-2.html: Added.
+        * storage/indexeddb/modern/resources/transactions-stop-on-navigation.js: Added.
+        * storage/indexeddb/modern/transactions-stop-on-navigation-expected.txt: Added.
+        * storage/indexeddb/modern/transactions-stop-on-navigation.html: Added.
+
 2016-01-05  Youenn Fablet  <[email protected]>
 
         Marking imported/w3c/web-platform-tests/html/dom/dynamic-markup-insertion/opening-the-input-stream/010.html

Added: trunk/LayoutTests/storage/indexeddb/modern/resources/transactions-stop-on-navigation-2.html (0 => 194587)


--- trunk/LayoutTests/storage/indexeddb/modern/resources/transactions-stop-on-navigation-2.html	                        (rev 0)
+++ trunk/LayoutTests/storage/indexeddb/modern/resources/transactions-stop-on-navigation-2.html	2016-01-05 17:44:50 UTC (rev 194587)
@@ -0,0 +1,40 @@
+Makes sure transactions stop on navigation to a new page.<br>
+If the previous page's transaction is blindly charging forward, this test will probably timeout.<br>
+If the previous page's connection/transactions did not clean up properly, the delete request in this test will incorrectly be blocked.<br>
+If every thing is peachy keen, the delete request in this test will correctly succeed.<br>
+<div id="logger"></div>
+<script>
+
+function log(msg)
+{
+    document.getElementById("logger").innerHTML += msg + "<br>";
+}
+
+function done()
+{
+    log("Done.");
+    if (window.testRunner)
+        testRunner.notifyDone();
+}
+
+// Calling "deleteDatabase" while there are already open connections causes those connections to first receive a versionChange event.
+// If the transaction/connection from the previous page is still active, then deleting the database will timeout because the previous connection will never be able to respond to the version change event.
+// Deleting the database should immediately succeed.
+
+var request = window.indexedDB.deleteDatabase('transactions-stop-on-navigation.html');
+request._onsuccess_ = deleteSuccess;
+request._onblocked_ = deleteBlocked;
+
+function deleteSuccess()
+{
+    log("Delete request was successful.");
+    done();
+}
+
+function deleteBlocked()
+{
+    log("Delete request was blocked - it should not have been.");
+    done();
+}
+
+</script>

Added: trunk/LayoutTests/storage/indexeddb/modern/resources/transactions-stop-on-navigation.js (0 => 194587)


--- trunk/LayoutTests/storage/indexeddb/modern/resources/transactions-stop-on-navigation.js	                        (rev 0)
+++ trunk/LayoutTests/storage/indexeddb/modern/resources/transactions-stop-on-navigation.js	2016-01-05 17:44:50 UTC (rev 194587)
@@ -0,0 +1,28 @@
+description("Makes sure transactions stop on navigation to a new page.");
+
+indexedDBTest(prepareDatabase, openSuccess);
+
+function prepareDatabase()
+{
+    evalAndLog("connection = event.target.result;");
+
+    evalAndLog("store = connection.createObjectStore('name');");
+    evalAndLog("index = store.createIndex('name', 'foo');");
+}
+
+function openSuccess()
+{
+    evalAndLog("connection.close();");
+    evalAndLog("request = window.indexedDB.open('transactions-stop-on-navigation.html');");
+    evalAndLog("request._onsuccess_ = opened;");
+}
+
+function opened(event)
+{
+    evalAndLog("connection = event.target.result;");
+    evalAndLog("transaction = connection.transaction('name', 'readwrite');");
+    for (var i = 0; i < 100; ++i)
+        evalAndLog("transaction.objectStore('name').put('bar', 'foo');");
+    
+    window.location.href = ""
+}

Added: trunk/LayoutTests/storage/indexeddb/modern/transactions-stop-on-navigation-expected.txt (0 => 194587)


--- trunk/LayoutTests/storage/indexeddb/modern/transactions-stop-on-navigation-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/storage/indexeddb/modern/transactions-stop-on-navigation-expected.txt	2016-01-05 17:44:50 UTC (rev 194587)
@@ -0,0 +1,7 @@
+Makes sure transactions stop on navigation to a new page.
+If the previous page's transaction is blindly charging forward, this test will probably timeout.
+If the previous page's connection/transactions did not clean up properly, the delete request in this test will incorrectly be blocked.
+If every thing is peachy keen, the delete request in this test will correctly succeed.
+Delete request was successful.
+Done.
+

Added: trunk/LayoutTests/storage/indexeddb/modern/transactions-stop-on-navigation.html (0 => 194587)


--- trunk/LayoutTests/storage/indexeddb/modern/transactions-stop-on-navigation.html	                        (rev 0)
+++ trunk/LayoutTests/storage/indexeddb/modern/transactions-stop-on-navigation.html	2016-01-05 17:44:50 UTC (rev 194587)
@@ -0,0 +1,9 @@
+<html>
+<head>
+<script src=""
+<script src=""
+</head>
+<body>
+<script src=""
+</body>
+</html>

Modified: trunk/Source/WebCore/ChangeLog (194586 => 194587)


--- trunk/Source/WebCore/ChangeLog	2016-01-05 17:31:46 UTC (rev 194586)
+++ trunk/Source/WebCore/ChangeLog	2016-01-05 17:44:50 UTC (rev 194587)
@@ -1,3 +1,37 @@
+2016-01-05  Brady Eidson  <[email protected]>
+
+        Modern IDB: Transactions from a previous page can leak forward to the next.
+        https://bugs.webkit.org/show_bug.cgi?id=152698
+
+        Reviewed by Alex Christensen.
+
+        Test: storage/indexeddb/modern/transactions-stop-on-navigation.html
+
+        This patch is mostly about actually implementing IDBDatabase::stop and IDBTransaction::stop.
+        Most of the rest of the scattered changes are about cleaning up now-incorrect ASSERTs.
+
+        * Modules/indexeddb/client/IDBDatabaseImpl.cpp:
+        (WebCore::IDBClient::IDBDatabase::close):
+        (WebCore::IDBClient::IDBDatabase::maybeCloseInServer):
+        (WebCore::IDBClient::IDBDatabase::stop):
+        (WebCore::IDBClient::IDBDatabase::startVersionChangeTransaction):
+        (WebCore::IDBClient::IDBDatabase::didAbortTransaction):
+        * Modules/indexeddb/client/IDBDatabaseImpl.h:
+        
+        * Modules/indexeddb/client/IDBOpenDBRequestImpl.cpp:
+        (WebCore::IDBClient::IDBOpenDBRequest::requestCompleted):
+        
+        * Modules/indexeddb/client/IDBRequestImpl.h:
+        
+        * Modules/indexeddb/client/IDBTransactionImpl.cpp:
+        (WebCore::IDBClient::IDBTransaction::IDBTransaction):
+        (WebCore::IDBClient::IDBTransaction::stop):
+        (WebCore::IDBClient::IDBTransaction::abortOnServerAndCancelRequests):
+        
+        * Modules/indexeddb/server/UniqueIDBDatabase.cpp:
+        (WebCore::IDBServer::UniqueIDBDatabase::performCurrentDeleteOperation):
+        (WebCore::IDBServer::UniqueIDBDatabase::didPerformAbortTransaction):
+
 2016-01-05  Zan Dobersek  <[email protected]>
 
         Unreviewed. Attempting to fix the AppleWin build after r194577.

Modified: trunk/Source/WebCore/Modules/indexeddb/client/IDBDatabaseImpl.cpp (194586 => 194587)


--- trunk/Source/WebCore/Modules/indexeddb/client/IDBDatabaseImpl.cpp	2016-01-05 17:31:46 UTC (rev 194586)
+++ trunk/Source/WebCore/Modules/indexeddb/client/IDBDatabaseImpl.cpp	2016-01-05 17:44:50 UTC (rev 194587)
@@ -223,12 +223,16 @@
 
 void IDBDatabase::close()
 {
+    LOG(IndexedDB, "IDBDatabase::close - %" PRIu64, m_databaseConnectionIdentifier);
+
     m_closePending = true;
     maybeCloseInServer();
 }
 
 void IDBDatabase::maybeCloseInServer()
 {
+    LOG(IndexedDB, "IDBDatabase::maybeCloseInServer - %" PRIu64, m_databaseConnectionIdentifier);
+
     if (m_closedInServer)
         return;
 
@@ -254,12 +258,33 @@
     return true;
 }
 
+void IDBDatabase::stop()
+{
+    LOG(IndexedDB, "IDBDatabase::stop - %" PRIu64, m_databaseConnectionIdentifier);
+
+    Vector<IDBResourceIdentifier> transactionIdentifiers;
+    transactionIdentifiers.reserveInitialCapacity(m_activeTransactions.size());
+
+    for (auto& id : m_activeTransactions.keys())
+        transactionIdentifiers.uncheckedAppend(id);
+
+    for (auto& id : transactionIdentifiers) {
+        IDBTransaction* transaction = m_activeTransactions.get(id);
+        if (transaction)
+            transaction->stop();
+    }
+
+    close();
+}
+
 Ref<IDBTransaction> IDBDatabase::startVersionChangeTransaction(const IDBTransactionInfo& info, IDBOpenDBRequest& request)
 {
     LOG(IndexedDB, "IDBDatabase::startVersionChangeTransaction %s", info.identifier().loggingString().utf8().data());
 
     ASSERT(!m_versionChangeTransaction);
     ASSERT(info.mode() == IndexedDB::TransactionMode::VersionChange);
+    ASSERT(!m_closePending);
+    ASSERT(scriptExecutionContext());
 
     Ref<IDBTransaction> transaction = IDBTransaction::create(*this, info, request);
     m_versionChangeTransaction = &transaction.get();
@@ -323,8 +348,7 @@
         ASSERT(transaction.originalDatabaseInfo());
         ASSERT(m_info.version() == transaction.originalDatabaseInfo()->version());
         m_closePending = true;
-        m_closedInServer = true;
-        m_serverConnection->databaseConnectionClosed(*this);
+        maybeCloseInServer();
     }
 
     didCommitOrAbortTransaction(transaction);

Modified: trunk/Source/WebCore/Modules/indexeddb/client/IDBDatabaseImpl.h (194586 => 194587)


--- trunk/Source/WebCore/Modules/indexeddb/client/IDBDatabaseImpl.h	2016-01-05 17:31:46 UTC (rev 194586)
+++ trunk/Source/WebCore/Modules/indexeddb/client/IDBDatabaseImpl.h	2016-01-05 17:44:50 UTC (rev 194587)
@@ -68,6 +68,7 @@
 
     virtual const char* activeDOMObjectName() const override final;
     virtual bool canSuspendForDocumentSuspension() const override final;
+    virtual void stop() override final;
 
     const IDBDatabaseInfo& info() const { return m_info; }
     uint64_t databaseConnectionIdentifier() const { return m_databaseConnectionIdentifier; }

Modified: trunk/Source/WebCore/Modules/indexeddb/client/IDBOpenDBRequestImpl.cpp (194586 => 194587)


--- trunk/Source/WebCore/Modules/indexeddb/client/IDBOpenDBRequestImpl.cpp	2016-01-05 17:31:46 UTC (rev 194586)
+++ trunk/Source/WebCore/Modules/indexeddb/client/IDBOpenDBRequestImpl.cpp	2016-01-05 17:44:50 UTC (rev 194587)
@@ -162,6 +162,9 @@
 {
     LOG(IndexedDB, "IDBOpenDBRequest::requestCompleted");
 
+    if (m_contextStopped)
+        return;
+
     switch (data.type()) {
     case IDBResultType::Error:
         onError(data);

Modified: trunk/Source/WebCore/Modules/indexeddb/client/IDBRequestImpl.h (194586 => 194587)


--- trunk/Source/WebCore/Modules/indexeddb/client/IDBRequestImpl.h	2016-01-05 17:31:46 UTC (rev 194586)
+++ trunk/Source/WebCore/Modules/indexeddb/client/IDBRequestImpl.h	2016-01-05 17:44:50 UTC (rev 194587)
@@ -129,6 +129,7 @@
     RefPtr<DOMError> m_domError;
     IDBError m_idbError;
     IndexedDB::RequestType m_requestType = { IndexedDB::RequestType::Other };
+    bool m_contextStopped { false };
 
 private:
     void onError();
@@ -143,8 +144,6 @@
     IndexedDB::IndexRecordType m_requestedIndexRecordType;
 
     RefPtr<IDBCursor> m_pendingCursor;
-
-    bool m_contextStopped { false };
 };
 
 } // namespace IDBClient

Modified: trunk/Source/WebCore/Modules/indexeddb/client/IDBTransactionImpl.cpp (194586 => 194587)


--- trunk/Source/WebCore/Modules/indexeddb/client/IDBTransactionImpl.cpp	2016-01-05 17:31:46 UTC (rev 194586)
+++ trunk/Source/WebCore/Modules/indexeddb/client/IDBTransactionImpl.cpp	2016-01-05 17:44:50 UTC (rev 194587)
@@ -67,6 +67,8 @@
     , m_openDBRequest(request)
 
 {
+    LOG(IndexedDB, "IDBTransaction::IDBTransaction - %s", m_info.loggingString().utf8().data());
+
     relaxAdoptionRequirement();
 
     if (m_info.mode() == IndexedDB::TransactionMode::VersionChange) {
@@ -211,9 +213,7 @@
     for (auto& operation : m_abortQueue)
         operation->completed(IDBResultData::error(operation->identifier(), error));
 
-    // Since we're aborting, this abortOnServerAndCancelRequests() operation should be the only
-    // in-progress operation, and it should be impossible to have queued any further operations.
-    ASSERT(m_transactionOperationMap.size() == 1);
+    // Since we're aborting, it should be impossible to have queued any further operations.
     ASSERT(m_transactionOperationQueue.isEmpty());
 }
 
@@ -234,8 +234,20 @@
 
 void IDBTransaction::stop()
 {
-    ASSERT(!m_contextStopped);
+    LOG(IndexedDB, "IDBTransaction::stop");
+
+    // IDBDatabase::stop() calls IDBTransaction::stop() for each of its active transactions.
+    // Since the order of calling ActiveDOMObject::stop() is random, we might already have been stopped.
+    if (m_contextStopped)
+        return;
+
     m_contextStopped = true;
+
+    if (isFinishedOrFinishing())
+        return;
+
+    ExceptionCodeWithMessage ec;
+    abort(ec);
 }
 
 bool IDBTransaction::isActive() const

Modified: trunk/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.cpp (194586 => 194587)


--- trunk/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.cpp	2016-01-05 17:31:46 UTC (rev 194586)
+++ trunk/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.cpp	2016-01-05 17:44:50 UTC (rev 194587)
@@ -178,8 +178,14 @@
         return;
     }
 
+    // Even though we have no open database connections, we might have close-pending database connections
+    // that are waiting on transactions to complete.
+    if (!m_inProgressTransactions.isEmpty()) {
+        ASSERT(!m_closePendingDatabaseConnections.isEmpty());
+        return;
+    }
+
     ASSERT(!hasAnyPendingCallbacks());
-    ASSERT(m_inProgressTransactions.isEmpty());
     ASSERT(m_pendingTransactions.isEmpty());
     ASSERT(m_openDatabaseConnections.isEmpty());
 
@@ -975,7 +981,7 @@
     LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformAbortTransaction");
 
     if (m_versionChangeTransaction && m_versionChangeTransaction->info().identifier() == transactionIdentifier) {
-        ASSERT(&m_versionChangeTransaction->databaseConnection() == m_versionChangeDatabaseConnection);
+        ASSERT(!m_versionChangeDatabaseConnection || &m_versionChangeTransaction->databaseConnection() == m_versionChangeDatabaseConnection);
         ASSERT(m_versionChangeTransaction->originalDatabaseInfo());
         m_databaseInfo = std::make_unique<IDBDatabaseInfo>(*m_versionChangeTransaction->originalDatabaseInfo());
     }
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to