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());
}