summaryrefslogtreecommitdiff
path: root/Source/WebCore/Modules/indexeddb/client
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/Modules/indexeddb/client')
-rw-r--r--Source/WebCore/Modules/indexeddb/client/IDBConnectionProxy.cpp562
-rw-r--r--Source/WebCore/Modules/indexeddb/client/IDBConnectionProxy.h177
-rw-r--r--Source/WebCore/Modules/indexeddb/client/IDBConnectionToServer.cpp446
-rw-r--r--Source/WebCore/Modules/indexeddb/client/IDBConnectionToServer.h155
-rw-r--r--Source/WebCore/Modules/indexeddb/client/IDBConnectionToServerDelegate.h98
-rw-r--r--Source/WebCore/Modules/indexeddb/client/TransactionOperation.cpp53
-rw-r--r--Source/WebCore/Modules/indexeddb/client/TransactionOperation.h270
7 files changed, 1761 insertions, 0 deletions
diff --git a/Source/WebCore/Modules/indexeddb/client/IDBConnectionProxy.cpp b/Source/WebCore/Modules/indexeddb/client/IDBConnectionProxy.cpp
new file mode 100644
index 000000000..4db50c0b9
--- /dev/null
+++ b/Source/WebCore/Modules/indexeddb/client/IDBConnectionProxy.cpp
@@ -0,0 +1,562 @@
+/*
+ * 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.
+ */
+
+#include "config.h"
+#include "IDBConnectionProxy.h"
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include "IDBCursorInfo.h"
+#include "IDBDatabase.h"
+#include "IDBGetRecordData.h"
+#include "IDBIterateCursorData.h"
+#include "IDBKeyRangeData.h"
+#include "IDBOpenDBRequest.h"
+#include "IDBRequestData.h"
+#include "IDBResultData.h"
+#include "ScriptExecutionContext.h"
+#include "SecurityOrigin.h"
+#include <wtf/MainThread.h>
+
+namespace WebCore {
+namespace IDBClient {
+
+IDBConnectionProxy::IDBConnectionProxy(IDBConnectionToServer& connection)
+ : m_connectionToServer(connection)
+ , m_serverConnectionIdentifier(connection.identifier())
+{
+ ASSERT(isMainThread());
+}
+
+void IDBConnectionProxy::ref()
+{
+ m_connectionToServer.ref();
+}
+
+void IDBConnectionProxy::deref()
+{
+ m_connectionToServer.deref();
+}
+
+Ref<IDBOpenDBRequest> IDBConnectionProxy::openDatabase(ScriptExecutionContext& context, const IDBDatabaseIdentifier& databaseIdentifier, uint64_t version)
+{
+ RefPtr<IDBOpenDBRequest> request;
+ {
+ Locker<Lock> locker(m_openDBRequestMapLock);
+
+ request = IDBOpenDBRequest::createOpenRequest(context, *this, databaseIdentifier, version);
+ ASSERT(!m_openDBRequestMap.contains(request->resourceIdentifier()));
+ m_openDBRequestMap.set(request->resourceIdentifier(), request.get());
+ }
+
+ callConnectionOnMainThread(&IDBConnectionToServer::openDatabase, IDBRequestData(*this, *request));
+
+ return request.releaseNonNull();
+}
+
+Ref<IDBOpenDBRequest> IDBConnectionProxy::deleteDatabase(ScriptExecutionContext& context, const IDBDatabaseIdentifier& databaseIdentifier)
+{
+ RefPtr<IDBOpenDBRequest> request;
+ {
+ Locker<Lock> locker(m_openDBRequestMapLock);
+
+ request = IDBOpenDBRequest::createDeleteRequest(context, *this, databaseIdentifier);
+ ASSERT(!m_openDBRequestMap.contains(request->resourceIdentifier()));
+ m_openDBRequestMap.set(request->resourceIdentifier(), request.get());
+ }
+
+ callConnectionOnMainThread(&IDBConnectionToServer::deleteDatabase, IDBRequestData(*this, *request));
+
+ return request.releaseNonNull();
+}
+
+void IDBConnectionProxy::didOpenDatabase(const IDBResultData& resultData)
+{
+ completeOpenDBRequest(resultData);
+}
+
+void IDBConnectionProxy::didDeleteDatabase(const IDBResultData& resultData)
+{
+ completeOpenDBRequest(resultData);
+}
+
+void IDBConnectionProxy::completeOpenDBRequest(const IDBResultData& resultData)
+{
+ ASSERT(isMainThread());
+
+ RefPtr<IDBOpenDBRequest> request;
+ {
+ Locker<Lock> locker(m_openDBRequestMapLock);
+ request = m_openDBRequestMap.take(resultData.requestIdentifier());
+ }
+
+ if (!request)
+ return;
+
+ request->performCallbackOnOriginThread(*request, &IDBOpenDBRequest::requestCompleted, resultData);
+}
+
+void IDBConnectionProxy::createObjectStore(TransactionOperation& operation, const IDBObjectStoreInfo& info)
+{
+ const IDBRequestData requestData { operation };
+ saveOperation(operation);
+
+ callConnectionOnMainThread(&IDBConnectionToServer::createObjectStore, requestData, info);
+}
+
+void IDBConnectionProxy::renameObjectStore(TransactionOperation& operation, uint64_t objectStoreIdentifier, const String& newName)
+{
+ const IDBRequestData requestData { operation };
+ saveOperation(operation);
+
+ callConnectionOnMainThread(&IDBConnectionToServer::renameObjectStore, requestData, objectStoreIdentifier, newName);
+}
+
+void IDBConnectionProxy::renameIndex(TransactionOperation& operation, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, const String& newName)
+{
+ const IDBRequestData requestData { operation };
+ saveOperation(operation);
+
+ callConnectionOnMainThread(&IDBConnectionToServer::renameIndex, requestData, objectStoreIdentifier, indexIdentifier, newName);
+}
+
+void IDBConnectionProxy::deleteObjectStore(TransactionOperation& operation, const String& objectStoreName)
+{
+ const IDBRequestData requestData { operation };
+ saveOperation(operation);
+
+ callConnectionOnMainThread(&IDBConnectionToServer::deleteObjectStore, requestData, objectStoreName);
+}
+
+void IDBConnectionProxy::clearObjectStore(TransactionOperation& operation, uint64_t objectStoreIdentifier)
+{
+ const IDBRequestData requestData { operation };
+ saveOperation(operation);
+
+ callConnectionOnMainThread(&IDBConnectionToServer::clearObjectStore, requestData, objectStoreIdentifier);
+}
+
+void IDBConnectionProxy::createIndex(TransactionOperation& operation, const IDBIndexInfo& info)
+{
+ const IDBRequestData requestData { operation };
+ saveOperation(operation);
+
+ callConnectionOnMainThread(&IDBConnectionToServer::createIndex, requestData, info);
+}
+
+void IDBConnectionProxy::deleteIndex(TransactionOperation& operation, uint64_t objectStoreIdentifier, const String& indexName)
+{
+ const IDBRequestData requestData { operation };
+ saveOperation(operation);
+
+ callConnectionOnMainThread(&IDBConnectionToServer::deleteIndex, requestData, WTFMove(objectStoreIdentifier), indexName);
+}
+
+void IDBConnectionProxy::putOrAdd(TransactionOperation& operation, IDBKeyData&& keyData, const IDBValue& value, const IndexedDB::ObjectStoreOverwriteMode mode)
+{
+ const IDBRequestData requestData { operation };
+ saveOperation(operation);
+
+ callConnectionOnMainThread(&IDBConnectionToServer::putOrAdd, requestData, keyData, value, mode);
+}
+
+void IDBConnectionProxy::getRecord(TransactionOperation& operation, const IDBGetRecordData& getRecordData)
+{
+ const IDBRequestData requestData { operation };
+ saveOperation(operation);
+
+ callConnectionOnMainThread(&IDBConnectionToServer::getRecord, requestData, getRecordData);
+}
+
+void IDBConnectionProxy::getAllRecords(TransactionOperation& operation, const IDBGetAllRecordsData& getAllRecordsData)
+{
+ const IDBRequestData requestData { operation };
+ saveOperation(operation);
+
+ callConnectionOnMainThread(&IDBConnectionToServer::getAllRecords, requestData, getAllRecordsData);
+}
+
+void IDBConnectionProxy::getCount(TransactionOperation& operation, const IDBKeyRangeData& keyRange)
+{
+ const IDBRequestData requestData { operation };
+ saveOperation(operation);
+
+ callConnectionOnMainThread(&IDBConnectionToServer::getCount, requestData, keyRange);
+}
+
+void IDBConnectionProxy::deleteRecord(TransactionOperation& operation, const IDBKeyRangeData& keyRange)
+{
+ const IDBRequestData requestData { operation };
+ saveOperation(operation);
+
+ callConnectionOnMainThread(&IDBConnectionToServer::deleteRecord, requestData, keyRange);
+}
+
+void IDBConnectionProxy::openCursor(TransactionOperation& operation, const IDBCursorInfo& info)
+{
+ const IDBRequestData requestData { operation };
+ saveOperation(operation);
+
+ callConnectionOnMainThread(&IDBConnectionToServer::openCursor, requestData, info);
+}
+
+void IDBConnectionProxy::iterateCursor(TransactionOperation& operation, const IDBIterateCursorData& data)
+{
+ const IDBRequestData requestData { operation };
+ saveOperation(operation);
+
+ callConnectionOnMainThread(&IDBConnectionToServer::iterateCursor, requestData, data);
+}
+
+void IDBConnectionProxy::saveOperation(TransactionOperation& operation)
+{
+ Locker<Lock> locker(m_transactionOperationLock);
+
+ ASSERT(!m_activeOperations.contains(operation.identifier()));
+ m_activeOperations.set(operation.identifier(), &operation);
+}
+
+void IDBConnectionProxy::completeOperation(const IDBResultData& resultData)
+{
+ RefPtr<TransactionOperation> operation;
+ {
+ Locker<Lock> locker(m_transactionOperationLock);
+ operation = m_activeOperations.take(resultData.requestIdentifier());
+ }
+
+ if (!operation)
+ return;
+
+ operation->transitionToComplete(resultData, WTFMove(operation));
+}
+
+void IDBConnectionProxy::abortOpenAndUpgradeNeeded(uint64_t databaseConnectionIdentifier, const IDBResourceIdentifier& transactionIdentifier)
+{
+ callConnectionOnMainThread(&IDBConnectionToServer::abortOpenAndUpgradeNeeded, databaseConnectionIdentifier, transactionIdentifier);
+}
+
+void IDBConnectionProxy::fireVersionChangeEvent(uint64_t databaseConnectionIdentifier, const IDBResourceIdentifier& requestIdentifier, uint64_t requestedVersion)
+{
+ RefPtr<IDBDatabase> database;
+ {
+ Locker<Lock> locker(m_databaseConnectionMapLock);
+ database = m_databaseConnectionMap.get(databaseConnectionIdentifier);
+ }
+
+ if (!database)
+ return;
+
+ database->performCallbackOnOriginThread(*database, &IDBDatabase::fireVersionChangeEvent, requestIdentifier, requestedVersion);
+}
+
+void IDBConnectionProxy::didFireVersionChangeEvent(uint64_t databaseConnectionIdentifier, const IDBResourceIdentifier& requestIdentifier)
+{
+ callConnectionOnMainThread(&IDBConnectionToServer::didFireVersionChangeEvent, databaseConnectionIdentifier, requestIdentifier);
+}
+
+void IDBConnectionProxy::notifyOpenDBRequestBlocked(const IDBResourceIdentifier& requestIdentifier, uint64_t oldVersion, uint64_t newVersion)
+{
+ ASSERT(isMainThread());
+
+ RefPtr<IDBOpenDBRequest> request;
+ {
+ Locker<Lock> locker(m_openDBRequestMapLock);
+ request = m_openDBRequestMap.get(requestIdentifier);
+ }
+
+ if (!request)
+ return;
+
+ request->performCallbackOnOriginThread(*request, &IDBOpenDBRequest::requestBlocked, oldVersion, newVersion);
+}
+
+void IDBConnectionProxy::openDBRequestCancelled(const IDBRequestData& requestData)
+{
+ callConnectionOnMainThread(&IDBConnectionToServer::openDBRequestCancelled, requestData);
+}
+
+void IDBConnectionProxy::establishTransaction(IDBTransaction& transaction)
+{
+ {
+ Locker<Lock> locker(m_transactionMapLock);
+ ASSERT(!hasRecordOfTransaction(transaction));
+ m_pendingTransactions.set(transaction.info().identifier(), &transaction);
+ }
+
+ callConnectionOnMainThread(&IDBConnectionToServer::establishTransaction, transaction.database().databaseConnectionIdentifier(), transaction.info());
+}
+
+void IDBConnectionProxy::didStartTransaction(const IDBResourceIdentifier& transactionIdentifier, const IDBError& error)
+{
+ RefPtr<IDBTransaction> transaction;
+ {
+ Locker<Lock> locker(m_transactionMapLock);
+ transaction = m_pendingTransactions.take(transactionIdentifier);
+ }
+
+ ASSERT(transaction);
+
+ transaction->performCallbackOnOriginThread(*transaction, &IDBTransaction::didStart, error);
+}
+
+void IDBConnectionProxy::commitTransaction(IDBTransaction& transaction)
+{
+ {
+ Locker<Lock> locker(m_transactionMapLock);
+ ASSERT(!m_committingTransactions.contains(transaction.info().identifier()));
+ m_committingTransactions.set(transaction.info().identifier(), &transaction);
+ }
+
+ callConnectionOnMainThread(&IDBConnectionToServer::commitTransaction, transaction.info().identifier());
+}
+
+void IDBConnectionProxy::didCommitTransaction(const IDBResourceIdentifier& transactionIdentifier, const IDBError& error)
+{
+ RefPtr<IDBTransaction> transaction;
+ {
+ Locker<Lock> locker(m_transactionMapLock);
+ transaction = m_committingTransactions.take(transactionIdentifier);
+ }
+
+ if (!transaction)
+ return;
+
+ transaction->performCallbackOnOriginThread(*transaction, &IDBTransaction::didCommit, error);
+}
+
+void IDBConnectionProxy::abortTransaction(IDBTransaction& transaction)
+{
+ {
+ Locker<Lock> locker(m_transactionMapLock);
+ ASSERT(!m_abortingTransactions.contains(transaction.info().identifier()));
+ m_abortingTransactions.set(transaction.info().identifier(), &transaction);
+ }
+
+ callConnectionOnMainThread(&IDBConnectionToServer::abortTransaction, transaction.info().identifier());
+}
+
+void IDBConnectionProxy::didAbortTransaction(const IDBResourceIdentifier& transactionIdentifier, const IDBError& error)
+{
+ RefPtr<IDBTransaction> transaction;
+ {
+ Locker<Lock> locker(m_transactionMapLock);
+ transaction = m_abortingTransactions.take(transactionIdentifier);
+ }
+
+ if (!transaction)
+ return;
+
+ transaction->performCallbackOnOriginThread(*transaction, &IDBTransaction::didAbort, error);
+}
+
+bool IDBConnectionProxy::hasRecordOfTransaction(const IDBTransaction& transaction) const
+{
+ ASSERT(m_transactionMapLock.isLocked());
+
+ auto identifier = transaction.info().identifier();
+ return m_pendingTransactions.contains(identifier) || m_committingTransactions.contains(identifier) || m_abortingTransactions.contains(identifier);
+}
+
+void IDBConnectionProxy::didFinishHandlingVersionChangeTransaction(uint64_t databaseConnectionIdentifier, IDBTransaction& transaction)
+{
+ callConnectionOnMainThread(&IDBConnectionToServer::didFinishHandlingVersionChangeTransaction, databaseConnectionIdentifier, transaction.info().identifier());
+}
+
+void IDBConnectionProxy::databaseConnectionPendingClose(IDBDatabase& database)
+{
+ callConnectionOnMainThread(&IDBConnectionToServer::databaseConnectionPendingClose, database.databaseConnectionIdentifier());
+}
+
+void IDBConnectionProxy::databaseConnectionClosed(IDBDatabase& database)
+{
+ callConnectionOnMainThread(&IDBConnectionToServer::databaseConnectionClosed, database.databaseConnectionIdentifier());
+}
+
+void IDBConnectionProxy::didCloseFromServer(uint64_t databaseConnectionIdentifier, const IDBError& error)
+{
+ RefPtr<IDBDatabase> database;
+ {
+ Locker<Lock> locker(m_databaseConnectionMapLock);
+ database = m_databaseConnectionMap.get(databaseConnectionIdentifier);
+ }
+
+ // If the IDBDatabase object is gone, message back to the server so it doesn't hang
+ // waiting for a reply that will never come.
+ if (!database) {
+ m_connectionToServer.confirmDidCloseFromServer(databaseConnectionIdentifier);
+ return;
+ }
+
+ database->performCallbackOnOriginThread(*database, &IDBDatabase::didCloseFromServer, error);
+}
+
+void IDBConnectionProxy::confirmDidCloseFromServer(IDBDatabase& database)
+{
+ callConnectionOnMainThread(&IDBConnectionToServer::confirmDidCloseFromServer, database.databaseConnectionIdentifier());
+}
+
+void IDBConnectionProxy::connectionToServerLost(const IDBError& error)
+{
+ Vector<uint64_t> databaseConnectionIdentifiers;
+ {
+ Locker<Lock> locker(m_databaseConnectionMapLock);
+ copyKeysToVector(m_databaseConnectionMap, databaseConnectionIdentifiers);
+ }
+
+ for (auto connectionIdentifier : databaseConnectionIdentifiers) {
+ RefPtr<IDBDatabase> database;
+ {
+ Locker<Lock> locker(m_databaseConnectionMapLock);
+ database = m_databaseConnectionMap.get(connectionIdentifier);
+ }
+
+ if (!database)
+ continue;
+
+ database->performCallbackOnOriginThread(*database, &IDBDatabase::connectionToServerLost, error);
+ }
+
+ Vector<IDBResourceIdentifier> openDBRequestIdentifiers;
+ {
+ Locker<Lock> locker(m_openDBRequestMapLock);
+ copyKeysToVector(m_openDBRequestMap, openDBRequestIdentifiers);
+ }
+
+ for (auto& requestIdentifier : openDBRequestIdentifiers) {
+ RefPtr<IDBOpenDBRequest> request;
+ {
+ Locker<Lock> locker(m_openDBRequestMapLock);
+ request = m_openDBRequestMap.get(requestIdentifier);
+ }
+
+ if (!request)
+ continue;
+
+ auto result = IDBResultData::error(requestIdentifier, error);
+ request->performCallbackOnOriginThread(*request, &IDBOpenDBRequest::requestCompleted, result);
+ }
+}
+
+void IDBConnectionProxy::scheduleMainThreadTasks()
+{
+ Locker<Lock> locker(m_mainThreadTaskLock);
+ if (m_mainThreadProtector)
+ return;
+
+ m_mainThreadProtector = &m_connectionToServer;
+ callOnMainThread([this] {
+ handleMainThreadTasks();
+ });
+}
+
+void IDBConnectionProxy::handleMainThreadTasks()
+{
+ RefPtr<IDBConnectionToServer> protector;
+ {
+ Locker<Lock> locker(m_mainThreadTaskLock);
+ ASSERT(m_mainThreadProtector);
+ protector = WTFMove(m_mainThreadProtector);
+ }
+
+ while (auto task = m_mainThreadQueue.tryGetMessage())
+ task->performTask();
+}
+
+void IDBConnectionProxy::getAllDatabaseNames(const SecurityOrigin& mainFrameOrigin, const SecurityOrigin& openingOrigin, std::function<void (const Vector<String>&)> callback)
+{
+ // This method is only meant to be called by the web inspector on the main thread.
+ RELEASE_ASSERT(isMainThread());
+
+ m_connectionToServer.getAllDatabaseNames(mainFrameOrigin, openingOrigin, callback);
+}
+
+void IDBConnectionProxy::registerDatabaseConnection(IDBDatabase& database)
+{
+ Locker<Lock> locker(m_databaseConnectionMapLock);
+
+ ASSERT(!m_databaseConnectionMap.contains(database.databaseConnectionIdentifier()));
+ m_databaseConnectionMap.set(database.databaseConnectionIdentifier(), &database);
+}
+
+void IDBConnectionProxy::unregisterDatabaseConnection(IDBDatabase& database)
+{
+ Locker<Lock> locker(m_databaseConnectionMapLock);
+
+ ASSERT(!m_databaseConnectionMap.contains(database.databaseConnectionIdentifier()) || m_databaseConnectionMap.get(database.databaseConnectionIdentifier()) == &database);
+ m_databaseConnectionMap.remove(database.databaseConnectionIdentifier());
+}
+
+void IDBConnectionProxy::forgetActiveOperations(const Vector<RefPtr<TransactionOperation>>& operations)
+{
+ Locker<Lock> locker(m_transactionOperationLock);
+
+ for (auto& operation : operations)
+ m_activeOperations.remove(operation->identifier());
+}
+
+template<typename KeyType, typename ValueType>
+void removeItemsMatchingCurrentThread(HashMap<KeyType, ValueType>& map)
+{
+ auto currentThreadID = currentThread();
+
+ Vector<KeyType> keys;
+ keys.reserveInitialCapacity(map.size());
+ for (auto& iterator : map) {
+ if (iterator.value->originThreadID() == currentThreadID)
+ keys.uncheckedAppend(iterator.key);
+ }
+
+ for (auto& key : keys)
+ map.remove(key);
+}
+
+void IDBConnectionProxy::forgetActivityForCurrentThread()
+{
+ ASSERT(!isMainThread());
+
+ {
+ Locker<Lock> lock(m_databaseConnectionMapLock);
+ removeItemsMatchingCurrentThread(m_databaseConnectionMap);
+ }
+ {
+ Locker<Lock> lock(m_openDBRequestMapLock);
+ removeItemsMatchingCurrentThread(m_openDBRequestMap);
+ }
+ {
+ Locker<Lock> lock(m_transactionMapLock);
+ removeItemsMatchingCurrentThread(m_pendingTransactions);
+ removeItemsMatchingCurrentThread(m_committingTransactions);
+ removeItemsMatchingCurrentThread(m_abortingTransactions);
+ }
+ {
+ Locker<Lock> lock(m_transactionOperationLock);
+ removeItemsMatchingCurrentThread(m_activeOperations);
+ }
+}
+
+} // namesapce IDBClient
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)
diff --git a/Source/WebCore/Modules/indexeddb/client/IDBConnectionProxy.h b/Source/WebCore/Modules/indexeddb/client/IDBConnectionProxy.h
new file mode 100644
index 000000000..5c01ac34c
--- /dev/null
+++ b/Source/WebCore/Modules/indexeddb/client/IDBConnectionProxy.h
@@ -0,0 +1,177 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include "IDBConnectionToServer.h"
+#include "IDBResourceIdentifier.h"
+#include "TransactionOperation.h"
+#include <functional>
+#include <wtf/CrossThreadQueue.h>
+#include <wtf/CrossThreadTask.h>
+#include <wtf/HashMap.h>
+#include <wtf/MainThread.h>
+#include <wtf/RefPtr.h>
+#include <wtf/Vector.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class IDBDatabase;
+class IDBDatabaseIdentifier;
+class IDBError;
+class IDBOpenDBRequest;
+class IDBResultData;
+class IDBTransaction;
+class ScriptExecutionContext;
+class SecurityOrigin;
+
+struct IDBGetRecordData;
+struct IDBIterateCursorData;
+
+namespace IDBClient {
+
+class IDBConnectionToServer;
+
+class IDBConnectionProxy {
+public:
+ IDBConnectionProxy(IDBConnectionToServer&);
+
+ Ref<IDBOpenDBRequest> openDatabase(ScriptExecutionContext&, const IDBDatabaseIdentifier&, uint64_t version);
+ void didOpenDatabase(const IDBResultData&);
+
+ Ref<IDBOpenDBRequest> deleteDatabase(ScriptExecutionContext&, const IDBDatabaseIdentifier&);
+ void didDeleteDatabase(const IDBResultData&);
+
+ void createObjectStore(TransactionOperation&, const IDBObjectStoreInfo&);
+ void deleteObjectStore(TransactionOperation&, const String& objectStoreName);
+ void clearObjectStore(TransactionOperation&, uint64_t objectStoreIdentifier);
+ void createIndex(TransactionOperation&, const IDBIndexInfo&);
+ void deleteIndex(TransactionOperation&, uint64_t objectStoreIdentifier, const String& indexName);
+ void putOrAdd(TransactionOperation&, IDBKeyData&&, const IDBValue&, const IndexedDB::ObjectStoreOverwriteMode);
+ void getRecord(TransactionOperation&, const IDBGetRecordData&);
+ void getAllRecords(TransactionOperation&, const IDBGetAllRecordsData&);
+ void getCount(TransactionOperation&, const IDBKeyRangeData&);
+ void deleteRecord(TransactionOperation&, const IDBKeyRangeData&);
+ void openCursor(TransactionOperation&, const IDBCursorInfo&);
+ void iterateCursor(TransactionOperation&, const IDBIterateCursorData&);
+ void renameObjectStore(TransactionOperation&, uint64_t objectStoreIdentifier, const String& newName);
+ void renameIndex(TransactionOperation&, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, const String& newName);
+
+ void fireVersionChangeEvent(uint64_t databaseConnectionIdentifier, const IDBResourceIdentifier& requestIdentifier, uint64_t requestedVersion);
+ void didFireVersionChangeEvent(uint64_t databaseConnectionIdentifier, const IDBResourceIdentifier& requestIdentifier);
+
+ void notifyOpenDBRequestBlocked(const IDBResourceIdentifier& requestIdentifier, uint64_t oldVersion, uint64_t newVersion);
+ void openDBRequestCancelled(const IDBRequestData&);
+
+ void establishTransaction(IDBTransaction&);
+ void commitTransaction(IDBTransaction&);
+ void abortTransaction(IDBTransaction&);
+
+ void didStartTransaction(const IDBResourceIdentifier& transactionIdentifier, const IDBError&);
+ void didCommitTransaction(const IDBResourceIdentifier& transactionIdentifier, const IDBError&);
+ void didAbortTransaction(const IDBResourceIdentifier& transactionIdentifier, const IDBError&);
+
+ void didFinishHandlingVersionChangeTransaction(uint64_t databaseConnectionIdentifier, IDBTransaction&);
+ void databaseConnectionPendingClose(IDBDatabase&);
+ void databaseConnectionClosed(IDBDatabase&);
+
+ void didCloseFromServer(uint64_t databaseConnectionIdentifier, const IDBError&);
+ void confirmDidCloseFromServer(IDBDatabase&);
+
+ void connectionToServerLost(const IDBError&);
+
+ void abortOpenAndUpgradeNeeded(uint64_t databaseConnectionIdentifier, const IDBResourceIdentifier& transactionIdentifier);
+
+ void completeOperation(const IDBResultData&);
+
+ uint64_t serverConnectionIdentifier() const { return m_serverConnectionIdentifier; }
+
+ void ref();
+ void deref();
+
+ void getAllDatabaseNames(const SecurityOrigin& mainFrameOrigin, const SecurityOrigin& openingOrigin, std::function<void (const Vector<String>&)>);
+
+ void registerDatabaseConnection(IDBDatabase&);
+ void unregisterDatabaseConnection(IDBDatabase&);
+
+ void forgetActiveOperations(const Vector<RefPtr<TransactionOperation>>&);
+ void forgetActivityForCurrentThread();
+
+private:
+ void completeOpenDBRequest(const IDBResultData&);
+ bool hasRecordOfTransaction(const IDBTransaction&) const;
+
+ void saveOperation(TransactionOperation&);
+
+ template<typename... Parameters, typename... Arguments>
+ void callConnectionOnMainThread(void (IDBConnectionToServer::*method)(Parameters...), Arguments&&... arguments)
+ {
+ if (isMainThread())
+ (m_connectionToServer.*method)(std::forward<Arguments>(arguments)...);
+ else
+ postMainThreadTask(m_connectionToServer, method, arguments...);
+ }
+
+ template<typename... Arguments>
+ void postMainThreadTask(Arguments&&... arguments)
+ {
+ auto task = createCrossThreadTask(arguments...);
+ m_mainThreadQueue.append(WTFMove(task));
+
+ scheduleMainThreadTasks();
+ }
+
+ void scheduleMainThreadTasks();
+ void handleMainThreadTasks();
+
+ IDBConnectionToServer& m_connectionToServer;
+ uint64_t m_serverConnectionIdentifier;
+
+ HashMap<uint64_t, IDBDatabase*> m_databaseConnectionMap;
+ Lock m_databaseConnectionMapLock;
+
+ HashMap<IDBResourceIdentifier, RefPtr<IDBOpenDBRequest>> m_openDBRequestMap;
+ Lock m_openDBRequestMapLock;
+
+ HashMap<IDBResourceIdentifier, RefPtr<IDBTransaction>> m_pendingTransactions;
+ HashMap<IDBResourceIdentifier, RefPtr<IDBTransaction>> m_committingTransactions;
+ HashMap<IDBResourceIdentifier, RefPtr<IDBTransaction>> m_abortingTransactions;
+ Lock m_transactionMapLock;
+
+ HashMap<IDBResourceIdentifier, RefPtr<TransactionOperation>> m_activeOperations;
+ Lock m_transactionOperationLock;
+
+ CrossThreadQueue<CrossThreadTask> m_mainThreadQueue;
+ Lock m_mainThreadTaskLock;
+ RefPtr<IDBConnectionToServer> m_mainThreadProtector;
+};
+
+} // namespace IDBClient
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)
diff --git a/Source/WebCore/Modules/indexeddb/client/IDBConnectionToServer.cpp b/Source/WebCore/Modules/indexeddb/client/IDBConnectionToServer.cpp
new file mode 100644
index 000000000..75c5773a5
--- /dev/null
+++ b/Source/WebCore/Modules/indexeddb/client/IDBConnectionToServer.cpp
@@ -0,0 +1,446 @@
+/*
+ * Copyright (C) 2015 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 "IDBConnectionToServer.h"
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include "IDBConnectionProxy.h"
+#include "IDBDatabase.h"
+#include "IDBGetRecordData.h"
+#include "IDBKeyRangeData.h"
+#include "IDBOpenDBRequest.h"
+#include "IDBRequestData.h"
+#include "IDBResultData.h"
+#include "Logging.h"
+#include "TransactionOperation.h"
+#include <wtf/MainThread.h>
+
+namespace WebCore {
+namespace IDBClient {
+
+Ref<IDBConnectionToServer> IDBConnectionToServer::create(IDBConnectionToServerDelegate& delegate)
+{
+ return adoptRef(*new IDBConnectionToServer(delegate));
+}
+
+IDBConnectionToServer::IDBConnectionToServer(IDBConnectionToServerDelegate& delegate)
+ : m_delegate(delegate)
+ , m_proxy(std::make_unique<IDBConnectionProxy>(*this))
+{
+}
+
+uint64_t IDBConnectionToServer::identifier() const
+{
+ return m_delegate->identifier();
+}
+
+IDBConnectionProxy& IDBConnectionToServer::proxy()
+{
+ ASSERT(m_proxy);
+ return *m_proxy;
+}
+
+void IDBConnectionToServer::deleteDatabase(const IDBRequestData& request)
+{
+ LOG(IndexedDB, "IDBConnectionToServer::deleteDatabase - %s", request.databaseIdentifier().debugString().utf8().data());
+ m_delegate->deleteDatabase(request);
+}
+
+void IDBConnectionToServer::didDeleteDatabase(const IDBResultData& resultData)
+{
+ LOG(IndexedDB, "IDBConnectionToServer::didDeleteDatabase");
+ m_proxy->didDeleteDatabase(resultData);
+}
+
+void IDBConnectionToServer::openDatabase(const IDBRequestData& request)
+{
+ LOG(IndexedDB, "IDBConnectionToServer::openDatabase - %s (%s) (%" PRIu64 ")", request.databaseIdentifier().debugString().utf8().data(), request.requestIdentifier().loggingString().utf8().data(), request.requestedVersion());
+ m_delegate->openDatabase(request);
+}
+
+void IDBConnectionToServer::didOpenDatabase(const IDBResultData& resultData)
+{
+ LOG(IndexedDB, "IDBConnectionToServer::didOpenDatabase");
+ m_proxy->didOpenDatabase(resultData);
+}
+
+void IDBConnectionToServer::createObjectStore(const IDBRequestData& requestData, const IDBObjectStoreInfo& info)
+{
+ LOG(IndexedDB, "IDBConnectionToServer::createObjectStore");
+ ASSERT(isMainThread());
+
+ m_delegate->createObjectStore(requestData, info);
+}
+
+void IDBConnectionToServer::didCreateObjectStore(const IDBResultData& resultData)
+{
+ LOG(IndexedDB, "IDBConnectionToServer::didCreateObjectStore");
+ m_proxy->completeOperation(resultData);
+}
+
+void IDBConnectionToServer::deleteObjectStore(const IDBRequestData& requestData, const String& objectStoreName)
+{
+ LOG(IndexedDB, "IDBConnectionToServer::deleteObjectStore");
+ ASSERT(isMainThread());
+
+ m_delegate->deleteObjectStore(requestData, objectStoreName);
+}
+
+void IDBConnectionToServer::didDeleteObjectStore(const IDBResultData& resultData)
+{
+ LOG(IndexedDB, "IDBConnectionToServer::didDeleteObjectStore");
+ m_proxy->completeOperation(resultData);
+}
+
+void IDBConnectionToServer::renameObjectStore(const IDBRequestData& requestData, uint64_t objectStoreIdentifier, const String& newName)
+{
+ LOG(IndexedDB, "IDBConnectionToServer::renameObjectStore");
+ ASSERT(isMainThread());
+
+ m_delegate->renameObjectStore(requestData, objectStoreIdentifier, newName);
+}
+
+void IDBConnectionToServer::didRenameObjectStore(const IDBResultData& resultData)
+{
+ LOG(IndexedDB, "IDBConnectionToServer::didRenameObjectStore");
+ m_proxy->completeOperation(resultData);
+}
+
+void IDBConnectionToServer::clearObjectStore(const IDBRequestData& requestData, uint64_t objectStoreIdentifier)
+{
+ LOG(IndexedDB, "IDBConnectionToServer::clearObjectStore");
+ ASSERT(isMainThread());
+
+ m_delegate->clearObjectStore(requestData, objectStoreIdentifier);
+}
+
+void IDBConnectionToServer::didClearObjectStore(const IDBResultData& resultData)
+{
+ LOG(IndexedDB, "IDBConnectionToServer::didClearObjectStore");
+ m_proxy->completeOperation(resultData);
+}
+
+void IDBConnectionToServer::createIndex(const IDBRequestData& requestData, const IDBIndexInfo& info)
+{
+ LOG(IndexedDB, "IDBConnectionToServer::createIndex");
+ ASSERT(isMainThread());
+
+ m_delegate->createIndex(requestData, info);
+}
+
+void IDBConnectionToServer::didCreateIndex(const IDBResultData& resultData)
+{
+ LOG(IndexedDB, "IDBConnectionToServer::didCreateIndex");
+ m_proxy->completeOperation(resultData);
+}
+
+void IDBConnectionToServer::deleteIndex(const IDBRequestData& requestData, uint64_t objectStoreIdentifier, const String& indexName)
+{
+ LOG(IndexedDB, "IDBConnectionToServer::deleteIndex");
+ ASSERT(isMainThread());
+
+ m_delegate->deleteIndex(requestData, objectStoreIdentifier, indexName);
+}
+
+void IDBConnectionToServer::didDeleteIndex(const IDBResultData& resultData)
+{
+ LOG(IndexedDB, "IDBConnectionToServer::didDeleteIndex");
+ m_proxy->completeOperation(resultData);
+}
+
+void IDBConnectionToServer::renameIndex(const IDBRequestData& requestData, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, const String& newName)
+{
+ LOG(IndexedDB, "IDBConnectionToServer::renameIndex");
+ ASSERT(isMainThread());
+
+ m_delegate->renameIndex(requestData, objectStoreIdentifier, indexIdentifier, newName);
+}
+
+void IDBConnectionToServer::didRenameIndex(const IDBResultData& resultData)
+{
+ LOG(IndexedDB, "IDBConnectionToServer::didRenameIndex");
+ m_proxy->completeOperation(resultData);
+}
+
+void IDBConnectionToServer::putOrAdd(const IDBRequestData& requestData, const IDBKeyData& key, const IDBValue& value, const IndexedDB::ObjectStoreOverwriteMode overwriteMode)
+{
+ LOG(IndexedDB, "IDBConnectionToServer::putOrAdd");
+ ASSERT(isMainThread());
+
+ m_delegate->putOrAdd(requestData, key, value, overwriteMode);
+}
+
+void IDBConnectionToServer::didPutOrAdd(const IDBResultData& resultData)
+{
+ LOG(IndexedDB, "IDBConnectionToServer::didPutOrAdd");
+ m_proxy->completeOperation(resultData);
+}
+
+void IDBConnectionToServer::getRecord(const IDBRequestData& requestData, const IDBGetRecordData& getRecordData)
+{
+ LOG(IndexedDB, "IDBConnectionToServer::getRecord");
+ ASSERT(isMainThread());
+ ASSERT(!getRecordData.keyRangeData.isNull);
+
+ m_delegate->getRecord(requestData, getRecordData);
+}
+
+void IDBConnectionToServer::didGetRecord(const IDBResultData& resultData)
+{
+ LOG(IndexedDB, "IDBConnectionToServer::didGetRecord");
+ m_proxy->completeOperation(resultData);
+}
+
+void IDBConnectionToServer::getAllRecords(const IDBRequestData& requestData, const IDBGetAllRecordsData& getAllRecordsData)
+{
+ LOG(IndexedDB, "IDBConnectionToServer::getAllRecords");
+ ASSERT(isMainThread());
+
+ m_delegate->getAllRecords(requestData, getAllRecordsData);
+}
+
+void IDBConnectionToServer::didGetAllRecords(const IDBResultData& resultData)
+{
+ LOG(IndexedDB, "IDBConnectionToServer::didGetAllRecords");
+ m_proxy->completeOperation(resultData);
+}
+
+void IDBConnectionToServer::getCount(const IDBRequestData& requestData, const IDBKeyRangeData& keyRangeData)
+{
+ LOG(IndexedDB, "IDBConnectionToServer::getCount");
+ ASSERT(isMainThread());
+ ASSERT(!keyRangeData.isNull);
+
+ m_delegate->getCount(requestData, keyRangeData);
+}
+
+void IDBConnectionToServer::didGetCount(const IDBResultData& resultData)
+{
+ LOG(IndexedDB, "IDBConnectionToServer::didGetCount");
+ m_proxy->completeOperation(resultData);
+}
+
+void IDBConnectionToServer::deleteRecord(const IDBRequestData& requestData, const IDBKeyRangeData& keyRangeData)
+{
+ LOG(IndexedDB, "IDBConnectionToServer::deleteRecord");
+ ASSERT(isMainThread());
+ ASSERT(!keyRangeData.isNull);
+
+ m_delegate->deleteRecord(requestData, keyRangeData);
+}
+
+void IDBConnectionToServer::didDeleteRecord(const IDBResultData& resultData)
+{
+ LOG(IndexedDB, "IDBConnectionToServer::didDeleteRecord");
+ m_proxy->completeOperation(resultData);
+}
+
+void IDBConnectionToServer::openCursor(const IDBRequestData& requestData, const IDBCursorInfo& info)
+{
+ LOG(IndexedDB, "IDBConnectionToServer::openCursor");
+ ASSERT(isMainThread());
+
+ m_delegate->openCursor(requestData, info);
+}
+
+void IDBConnectionToServer::didOpenCursor(const IDBResultData& resultData)
+{
+ LOG(IndexedDB, "IDBConnectionToServer::didOpenCursor");
+ m_proxy->completeOperation(resultData);
+}
+
+void IDBConnectionToServer::iterateCursor(const IDBRequestData& requestData, const IDBIterateCursorData& data)
+{
+ LOG(IndexedDB, "IDBConnectionToServer::iterateCursor");
+ ASSERT(isMainThread());
+
+ m_delegate->iterateCursor(requestData, data);
+}
+
+void IDBConnectionToServer::didIterateCursor(const IDBResultData& resultData)
+{
+ LOG(IndexedDB, "IDBConnectionToServer::didIterateCursor");
+ m_proxy->completeOperation(resultData);
+}
+
+void IDBConnectionToServer::establishTransaction(uint64_t databaseConnectionIdentifier, const IDBTransactionInfo& info)
+{
+ LOG(IndexedDB, "IDBConnectionToServer::establishTransaction");
+ ASSERT(isMainThread());
+
+ m_delegate->establishTransaction(databaseConnectionIdentifier, info);
+}
+
+void IDBConnectionToServer::commitTransaction(const IDBResourceIdentifier& transactionIdentifier)
+{
+ LOG(IndexedDB, "IDBConnectionToServer::commitTransaction");
+ ASSERT(isMainThread());
+
+ m_delegate->commitTransaction(transactionIdentifier);
+}
+
+void IDBConnectionToServer::didCommitTransaction(const IDBResourceIdentifier& transactionIdentifier, const IDBError& error)
+{
+ LOG(IndexedDB, "IDBConnectionToServer::didCommitTransaction");
+ ASSERT(isMainThread());
+
+ m_proxy->didCommitTransaction(transactionIdentifier, error);
+}
+
+void IDBConnectionToServer::didFinishHandlingVersionChangeTransaction(uint64_t databaseConnectionIdentifier, const IDBResourceIdentifier& transactionIdentifier)
+{
+ LOG(IndexedDB, "IDBConnectionToServer::didFinishHandlingVersionChangeTransaction");
+ ASSERT(isMainThread());
+
+ m_delegate->didFinishHandlingVersionChangeTransaction(databaseConnectionIdentifier, transactionIdentifier);
+}
+
+void IDBConnectionToServer::abortTransaction(const IDBResourceIdentifier& transactionIdentifier)
+{
+ LOG(IndexedDB, "IDBConnectionToServer::abortTransaction");
+ ASSERT(isMainThread());
+
+ m_delegate->abortTransaction(transactionIdentifier);
+}
+
+void IDBConnectionToServer::didAbortTransaction(const IDBResourceIdentifier& transactionIdentifier, const IDBError& error)
+{
+ LOG(IndexedDB, "IDBConnectionToServer::didAbortTransaction");
+ ASSERT(isMainThread());
+
+ m_proxy->didAbortTransaction(transactionIdentifier, error);
+}
+
+void IDBConnectionToServer::fireVersionChangeEvent(uint64_t databaseConnectionIdentifier, const IDBResourceIdentifier& requestIdentifier, uint64_t requestedVersion)
+{
+ LOG(IndexedDB, "IDBConnectionToServer::fireVersionChangeEvent");
+ ASSERT(isMainThread());
+
+ m_proxy->fireVersionChangeEvent(databaseConnectionIdentifier, requestIdentifier, requestedVersion);
+}
+
+void IDBConnectionToServer::didFireVersionChangeEvent(uint64_t databaseConnectionIdentifier, const IDBResourceIdentifier& requestIdentifier)
+{
+ LOG(IndexedDB, "IDBConnectionToServer::didFireVersionChangeEvent");
+ ASSERT(isMainThread());
+
+ m_delegate->didFireVersionChangeEvent(databaseConnectionIdentifier, requestIdentifier);
+}
+
+void IDBConnectionToServer::didStartTransaction(const IDBResourceIdentifier& transactionIdentifier, const IDBError& error)
+{
+ LOG(IndexedDB, "IDBConnectionToServer::didStartTransaction");
+ ASSERT(isMainThread());
+
+ m_proxy->didStartTransaction(transactionIdentifier, error);
+}
+
+void IDBConnectionToServer::didCloseFromServer(uint64_t databaseConnectionIdentifier, const IDBError& error)
+{
+ LOG(IndexedDB, "IDBConnectionToServer::didCloseFromServer");
+ ASSERT(isMainThread());
+
+ m_proxy->didCloseFromServer(databaseConnectionIdentifier, error);
+}
+
+void IDBConnectionToServer::confirmDidCloseFromServer(uint64_t databaseConnectionIdentifier)
+{
+ LOG(IndexedDB, "IDBConnectionToServer::confirmDidCloseFromServer");
+ ASSERT(isMainThread());
+
+ m_delegate->confirmDidCloseFromServer(databaseConnectionIdentifier);
+}
+
+void IDBConnectionToServer::connectionToServerLost(const IDBError& error)
+{
+ LOG(IndexedDB, "IDBConnectionToServer::connectionToServerLost");
+ ASSERT(isMainThread());
+
+ m_proxy->connectionToServerLost(error);
+}
+
+void IDBConnectionToServer::notifyOpenDBRequestBlocked(const IDBResourceIdentifier& requestIdentifier, uint64_t oldVersion, uint64_t newVersion)
+{
+ LOG(IndexedDB, "IDBConnectionToServer::didStartTransaction");
+ ASSERT(isMainThread());
+
+ m_proxy->notifyOpenDBRequestBlocked(requestIdentifier, oldVersion, newVersion);
+}
+
+void IDBConnectionToServer::openDBRequestCancelled(const IDBRequestData& requestData)
+{
+ LOG(IndexedDB, "IDBConnectionToServer::openDBRequestCancelled");
+ ASSERT(isMainThread());
+
+ m_delegate->openDBRequestCancelled(requestData);
+}
+
+void IDBConnectionToServer::databaseConnectionPendingClose(uint64_t databaseConnectionIdentifier)
+{
+ LOG(IndexedDB, "IDBConnectionToServer::databaseConnectionPendingClose");
+ ASSERT(isMainThread());
+
+ m_delegate->databaseConnectionPendingClose(databaseConnectionIdentifier);
+}
+
+void IDBConnectionToServer::databaseConnectionClosed(uint64_t databaseConnectionIdentifier)
+{
+ LOG(IndexedDB, "IDBConnectionToServer::databaseConnectionClosed");
+ ASSERT(isMainThread());
+
+ m_delegate->databaseConnectionClosed(databaseConnectionIdentifier);
+}
+
+void IDBConnectionToServer::abortOpenAndUpgradeNeeded(uint64_t databaseConnectionIdentifier, const IDBResourceIdentifier& transactionIdentifier)
+{
+ LOG(IndexedDB, "IDBConnectionToServer::abortOpenAndUpgradeNeeded");
+ ASSERT(isMainThread());
+
+ m_delegate->abortOpenAndUpgradeNeeded(databaseConnectionIdentifier, transactionIdentifier);
+}
+
+void IDBConnectionToServer::getAllDatabaseNames(const SecurityOrigin& mainFrameOrigin, const SecurityOrigin& openingOrigin, std::function<void (const Vector<String>&)> callback)
+{
+ static uint64_t callbackID = 0;
+
+ m_getAllDatabaseNamesCallbacks.add(++callbackID, WTFMove(callback));
+
+ m_delegate->getAllDatabaseNames(SecurityOriginData::fromSecurityOrigin(mainFrameOrigin), SecurityOriginData::fromSecurityOrigin(openingOrigin), callbackID);
+}
+
+void IDBConnectionToServer::didGetAllDatabaseNames(uint64_t callbackID, const Vector<String>& databaseNames)
+{
+ auto callback = m_getAllDatabaseNamesCallbacks.take(callbackID);
+ ASSERT(callback);
+
+ callback(databaseNames);
+}
+
+} // namespace IDBClient
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)
diff --git a/Source/WebCore/Modules/indexeddb/client/IDBConnectionToServer.h b/Source/WebCore/Modules/indexeddb/client/IDBConnectionToServer.h
new file mode 100644
index 000000000..7651f4305
--- /dev/null
+++ b/Source/WebCore/Modules/indexeddb/client/IDBConnectionToServer.h
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2015, 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.
+ */
+
+#pragma once
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include "IDBConnectionProxy.h"
+#include "IDBConnectionToServerDelegate.h"
+#include "IDBResourceIdentifier.h"
+#include <wtf/HashMap.h>
+#include <wtf/Ref.h>
+#include <wtf/ThreadSafeRefCounted.h>
+
+namespace WebCore {
+
+class IDBCursorInfo;
+class IDBDatabase;
+class IDBError;
+class IDBObjectStoreInfo;
+class IDBResultData;
+class IDBValue;
+class SecurityOrigin;
+
+struct IDBGetAllRecordsData;
+struct IDBGetRecordData;
+struct IDBIterateCursorData;
+
+namespace IDBClient {
+
+class IDBConnectionToServer : public ThreadSafeRefCounted<IDBConnectionToServer> {
+public:
+ WEBCORE_EXPORT static Ref<IDBConnectionToServer> create(IDBConnectionToServerDelegate&);
+
+ uint64_t identifier() const;
+
+ IDBConnectionProxy& proxy();
+
+ void deleteDatabase(const IDBRequestData&);
+ WEBCORE_EXPORT void didDeleteDatabase(const IDBResultData&);
+
+ void openDatabase(const IDBRequestData&);
+ WEBCORE_EXPORT void didOpenDatabase(const IDBResultData&);
+
+ void createObjectStore(const IDBRequestData&, const IDBObjectStoreInfo&);
+ WEBCORE_EXPORT void didCreateObjectStore(const IDBResultData&);
+
+ void deleteObjectStore(const IDBRequestData&, const String& objectStoreName);
+ WEBCORE_EXPORT void didDeleteObjectStore(const IDBResultData&);
+
+ void renameObjectStore(const IDBRequestData&, uint64_t objectStoreIdentifier, const String& newName);
+ WEBCORE_EXPORT void didRenameObjectStore(const IDBResultData&);
+
+ void clearObjectStore(const IDBRequestData&, uint64_t objectStoreIdentifier);
+ WEBCORE_EXPORT void didClearObjectStore(const IDBResultData&);
+
+ void createIndex(const IDBRequestData&, const IDBIndexInfo&);
+ WEBCORE_EXPORT void didCreateIndex(const IDBResultData&);
+
+ void deleteIndex(const IDBRequestData&, uint64_t objectStoreIdentifier, const String& indexName);
+ WEBCORE_EXPORT void didDeleteIndex(const IDBResultData&);
+
+ void renameIndex(const IDBRequestData&, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, const String& newName);
+ WEBCORE_EXPORT void didRenameIndex(const IDBResultData&);
+
+ void putOrAdd(const IDBRequestData&, const IDBKeyData&, const IDBValue&, const IndexedDB::ObjectStoreOverwriteMode);
+ WEBCORE_EXPORT void didPutOrAdd(const IDBResultData&);
+
+ void getRecord(const IDBRequestData&, const IDBGetRecordData&);
+ WEBCORE_EXPORT void didGetRecord(const IDBResultData&);
+
+ void getAllRecords(const IDBRequestData&, const IDBGetAllRecordsData&);
+ WEBCORE_EXPORT void didGetAllRecords(const IDBResultData&);
+
+ void getCount(const IDBRequestData&, const IDBKeyRangeData&);
+ WEBCORE_EXPORT void didGetCount(const IDBResultData&);
+
+ void deleteRecord(const IDBRequestData&, const IDBKeyRangeData&);
+ WEBCORE_EXPORT void didDeleteRecord(const IDBResultData&);
+
+ void openCursor(const IDBRequestData&, const IDBCursorInfo&);
+ WEBCORE_EXPORT void didOpenCursor(const IDBResultData&);
+
+ void iterateCursor(const IDBRequestData&, const IDBIterateCursorData&);
+ WEBCORE_EXPORT void didIterateCursor(const IDBResultData&);
+
+ void commitTransaction(const IDBResourceIdentifier& transactionIdentifier);
+ WEBCORE_EXPORT void didCommitTransaction(const IDBResourceIdentifier& transactionIdentifier, const IDBError&);
+
+ void didFinishHandlingVersionChangeTransaction(uint64_t databaseConnectionIdentifier, const IDBResourceIdentifier&);
+
+ void abortTransaction(const IDBResourceIdentifier& transactionIdentifier);
+ WEBCORE_EXPORT void didAbortTransaction(const IDBResourceIdentifier& transactionIdentifier, const IDBError&);
+
+ WEBCORE_EXPORT void fireVersionChangeEvent(uint64_t databaseConnectionIdentifier, const IDBResourceIdentifier& requestIdentifier, uint64_t requestedVersion);
+ void didFireVersionChangeEvent(uint64_t databaseConnectionIdentifier, const IDBResourceIdentifier& requestIdentifier);
+
+ WEBCORE_EXPORT void didStartTransaction(const IDBResourceIdentifier& transactionIdentifier, const IDBError&);
+
+ WEBCORE_EXPORT void didCloseFromServer(uint64_t databaseConnectionIdentifier, const IDBError&);
+ void confirmDidCloseFromServer(uint64_t databaseConnectionIdentifier);
+
+ WEBCORE_EXPORT void connectionToServerLost(const IDBError&);
+
+ WEBCORE_EXPORT void notifyOpenDBRequestBlocked(const IDBResourceIdentifier& requestIdentifier, uint64_t oldVersion, uint64_t newVersion);
+ void openDBRequestCancelled(const IDBRequestData&);
+
+ void establishTransaction(uint64_t databaseConnectionIdentifier, const IDBTransactionInfo&);
+
+ void databaseConnectionPendingClose(uint64_t databaseConnectionIdentifier);
+ void databaseConnectionClosed(uint64_t databaseConnectionIdentifier);
+
+ // To be used when an IDBOpenDBRequest gets a new database connection, optionally with a
+ // versionchange transaction, but the page is already torn down.
+ void abortOpenAndUpgradeNeeded(uint64_t databaseConnectionIdentifier, const IDBResourceIdentifier& transactionIdentifier);
+
+ void getAllDatabaseNames(const SecurityOrigin& mainFrameOrigin, const SecurityOrigin& openingOrigin, std::function<void (const Vector<String>&)>);
+ WEBCORE_EXPORT void didGetAllDatabaseNames(uint64_t callbackID, const Vector<String>& databaseNames);
+
+private:
+ IDBConnectionToServer(IDBConnectionToServerDelegate&);
+
+ Ref<IDBConnectionToServerDelegate> m_delegate;
+
+ HashMap<uint64_t, std::function<void (const Vector<String>&)>> m_getAllDatabaseNamesCallbacks;
+
+ std::unique_ptr<IDBConnectionProxy> m_proxy;
+};
+
+} // namespace IDBClient
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)
diff --git a/Source/WebCore/Modules/indexeddb/client/IDBConnectionToServerDelegate.h b/Source/WebCore/Modules/indexeddb/client/IDBConnectionToServerDelegate.h
new file mode 100644
index 000000000..a61c283a2
--- /dev/null
+++ b/Source/WebCore/Modules/indexeddb/client/IDBConnectionToServerDelegate.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2015, 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.
+ */
+
+#pragma once
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class IDBCursorInfo;
+class IDBIndexInfo;
+class IDBKeyData;
+class IDBObjectStoreInfo;
+class IDBRequestData;
+class IDBResourceIdentifier;
+class IDBTransactionInfo;
+class IDBValue;
+
+struct IDBGetAllRecordsData;
+struct IDBGetRecordData;
+struct IDBIterateCursorData;
+struct SecurityOriginData;
+
+namespace IndexedDB {
+enum class ObjectStoreOverwriteMode;
+}
+
+struct IDBKeyRangeData;
+
+namespace IDBClient {
+
+class IDBConnectionToServerDelegate {
+public:
+ virtual ~IDBConnectionToServerDelegate() { }
+
+ virtual uint64_t identifier() const = 0;
+ virtual void deleteDatabase(const IDBRequestData&) = 0;
+ virtual void openDatabase(const IDBRequestData&) = 0;
+ virtual void abortTransaction(const IDBResourceIdentifier&) = 0;
+ virtual void commitTransaction(const IDBResourceIdentifier&) = 0;
+ virtual void didFinishHandlingVersionChangeTransaction(uint64_t databaseConnectionIdentifier, const IDBResourceIdentifier&) = 0;
+ virtual void createObjectStore(const IDBRequestData&, const IDBObjectStoreInfo&) = 0;
+ virtual void deleteObjectStore(const IDBRequestData&, const String& objectStoreName) = 0;
+ virtual void renameObjectStore(const IDBRequestData&, uint64_t objectStoreIdentifier, const String& newName) = 0;
+ virtual void clearObjectStore(const IDBRequestData&, uint64_t objectStoreIdentifier) = 0;
+ virtual void createIndex(const IDBRequestData&, const IDBIndexInfo&) = 0;
+ virtual void deleteIndex(const IDBRequestData&, uint64_t objectStoreIdentifier, const String& indexName) = 0;
+ virtual void renameIndex(const IDBRequestData&, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, const String& newName) = 0;
+ virtual void putOrAdd(const IDBRequestData&, const IDBKeyData&, const IDBValue&, const IndexedDB::ObjectStoreOverwriteMode) = 0;
+ virtual void getRecord(const IDBRequestData&, const IDBGetRecordData&) = 0;
+ virtual void getAllRecords(const IDBRequestData&, const IDBGetAllRecordsData&) = 0;
+ virtual void getCount(const IDBRequestData&, const IDBKeyRangeData&) = 0;
+ virtual void deleteRecord(const IDBRequestData&, const IDBKeyRangeData&) = 0;
+ virtual void openCursor(const IDBRequestData&, const IDBCursorInfo&) = 0;
+ virtual void iterateCursor(const IDBRequestData&, const IDBIterateCursorData&) = 0;
+
+ virtual void establishTransaction(uint64_t databaseConnectionIdentifier, const IDBTransactionInfo&) = 0;
+ virtual void databaseConnectionPendingClose(uint64_t databaseConnectionIdentifier) = 0;
+ virtual void databaseConnectionClosed(uint64_t databaseConnectionIdentifier) = 0;
+ virtual void abortOpenAndUpgradeNeeded(uint64_t databaseConnectionIdentifier, const IDBResourceIdentifier& transactionIdentifier) = 0;
+ virtual void didFireVersionChangeEvent(uint64_t databaseConnectionIdentifier, const IDBResourceIdentifier& requestIdentifier) = 0;
+ virtual void openDBRequestCancelled(const IDBRequestData&) = 0;
+ virtual void confirmDidCloseFromServer(uint64_t databaseConnectionIdentifier) = 0;
+
+ virtual void getAllDatabaseNames(const SecurityOriginData& mainFrameOrigin, const SecurityOriginData& openingOrigin, uint64_t callbackID) = 0;
+
+ virtual void ref() = 0;
+ virtual void deref() = 0;
+};
+
+} // namespace IDBClient
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)
diff --git a/Source/WebCore/Modules/indexeddb/client/TransactionOperation.cpp b/Source/WebCore/Modules/indexeddb/client/TransactionOperation.cpp
new file mode 100644
index 000000000..8f3547522
--- /dev/null
+++ b/Source/WebCore/Modules/indexeddb/client/TransactionOperation.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2015 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 "TransactionOperation.h"
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include "IDBCursor.h"
+#include <heap/HeapInlines.h>
+
+namespace WebCore {
+namespace IDBClient {
+
+TransactionOperation::TransactionOperation(IDBTransaction& transaction, IDBRequest& request)
+ : TransactionOperation(transaction)
+{
+ m_objectStoreIdentifier = request.sourceObjectStoreIdentifier();
+ m_indexIdentifier = request.sourceIndexIdentifier();
+ if (m_indexIdentifier)
+ m_indexRecordType = request.requestedIndexRecordType();
+ if (auto* cursor = request.pendingCursor())
+ m_cursorIdentifier = std::make_unique<IDBResourceIdentifier>(cursor->info().identifier());
+
+ m_idbRequest = &request;
+}
+
+} // namespace IDBClient
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)
diff --git a/Source/WebCore/Modules/indexeddb/client/TransactionOperation.h b/Source/WebCore/Modules/indexeddb/client/TransactionOperation.h
new file mode 100644
index 000000000..cd95befd5
--- /dev/null
+++ b/Source/WebCore/Modules/indexeddb/client/TransactionOperation.h
@@ -0,0 +1,270 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#pragma once
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include "IDBRequest.h"
+#include "IDBRequestData.h"
+#include "IDBResourceIdentifier.h"
+#include "IDBResultData.h"
+#include "IDBTransaction.h"
+#include <wtf/MainThread.h>
+#include <wtf/Threading.h>
+
+namespace WebCore {
+
+class IDBResultData;
+
+namespace IndexedDB {
+enum class IndexRecordType;
+}
+
+namespace IDBClient {
+
+class TransactionOperation : public ThreadSafeRefCounted<TransactionOperation> {
+ friend IDBRequestData::IDBRequestData(TransactionOperation&);
+public:
+ virtual ~TransactionOperation()
+ {
+ ASSERT(m_originThreadID == currentThread());
+ }
+
+ void perform()
+ {
+ ASSERT(m_originThreadID == currentThread());
+ ASSERT(m_performFunction);
+ m_performFunction();
+ m_performFunction = { };
+ }
+
+ void transitionToCompleteOnThisThread(const IDBResultData& data)
+ {
+ ASSERT(m_originThreadID == currentThread());
+ m_transaction->operationCompletedOnServer(data, *this);
+ }
+
+ void transitionToComplete(const IDBResultData& data, RefPtr<TransactionOperation>&& lastRef)
+ {
+ ASSERT(isMainThread());
+
+ if (m_originThreadID == currentThread())
+ transitionToCompleteOnThisThread(data);
+ else {
+ m_transaction->performCallbackOnOriginThread(*this, &TransactionOperation::transitionToCompleteOnThisThread, data);
+ m_transaction->callFunctionOnOriginThread([lastRef = WTFMove(lastRef)]() {
+ });
+ }
+ }
+
+ void doComplete(const IDBResultData& data)
+ {
+ ASSERT(m_originThreadID == currentThread());
+
+ // Due to race conditions between the server sending an "operation complete" message and the client
+ // forcefully aborting an operation, it's unavoidable that this method might be called twice.
+ // It's okay to handle that gracefully with an early return.
+ if (!m_completeFunction)
+ return;
+
+ m_completeFunction(data);
+ m_transaction->operationCompletedOnClient(*this);
+
+ // m_completeFunction might be holding the last ref to this TransactionOperation,
+ // so we need to do this trick to null it out without first destroying it.
+ std::function<void (const IDBResultData&)> oldCompleteFunction;
+ std::swap(m_completeFunction, oldCompleteFunction);
+ }
+
+ const IDBResourceIdentifier& identifier() const { return m_identifier; }
+
+ ThreadIdentifier originThreadID() const { return m_originThreadID; }
+
+ IDBRequest* idbRequest() { return m_idbRequest.get(); }
+
+ bool nextRequestCanGoToServer() const { return m_nextRequestCanGoToServer && m_idbRequest; }
+ void setNextRequestCanGoToServer(bool nextRequestCanGoToServer) { m_nextRequestCanGoToServer = nextRequestCanGoToServer; }
+
+protected:
+ TransactionOperation(IDBTransaction& transaction)
+ : m_transaction(transaction)
+ , m_identifier(transaction.connectionProxy())
+ {
+ }
+
+ TransactionOperation(IDBTransaction&, IDBRequest&);
+
+ Ref<IDBTransaction> m_transaction;
+ IDBResourceIdentifier m_identifier;
+ uint64_t m_objectStoreIdentifier { 0 };
+ uint64_t m_indexIdentifier { 0 };
+ std::unique_ptr<IDBResourceIdentifier> m_cursorIdentifier;
+ IndexedDB::IndexRecordType m_indexRecordType;
+ std::function<void ()> m_performFunction;
+ std::function<void (const IDBResultData&)> m_completeFunction;
+
+private:
+ IDBResourceIdentifier transactionIdentifier() const { return m_transaction->info().identifier(); }
+ uint64_t objectStoreIdentifier() const { return m_objectStoreIdentifier; }
+ uint64_t indexIdentifier() const { return m_indexIdentifier; }
+ IDBResourceIdentifier* cursorIdentifier() const { return m_cursorIdentifier.get(); }
+ IDBTransaction& transaction() { return m_transaction.get(); }
+ IndexedDB::IndexRecordType indexRecordType() const { return m_indexRecordType; }
+
+ ThreadIdentifier m_originThreadID { currentThread() };
+ RefPtr<IDBRequest> m_idbRequest;
+ bool m_nextRequestCanGoToServer { true };
+};
+
+template <typename... Arguments>
+class TransactionOperationImpl final : public TransactionOperation {
+public:
+ TransactionOperationImpl(IDBTransaction& transaction, void (IDBTransaction::*completeMethod)(const IDBResultData&), void (IDBTransaction::*performMethod)(TransactionOperation&, Arguments...), Arguments&&... arguments)
+ : TransactionOperation(transaction)
+ {
+ RefPtr<TransactionOperation> protectedThis(this);
+
+ ASSERT(performMethod);
+ m_performFunction = [protectedThis, this, performMethod, arguments...] {
+ (&m_transaction.get()->*performMethod)(*this, arguments...);
+ };
+
+ if (completeMethod) {
+ m_completeFunction = [protectedThis, this, completeMethod](const IDBResultData& resultData) {
+ if (completeMethod)
+ (&m_transaction.get()->*completeMethod)(resultData);
+ };
+ }
+ }
+
+ TransactionOperationImpl(IDBTransaction& transaction, IDBRequest& request, void (IDBTransaction::*completeMethod)(IDBRequest&, const IDBResultData&), void (IDBTransaction::*performMethod)(TransactionOperation&, Arguments...), Arguments&&... arguments)
+ : TransactionOperation(transaction, request)
+ {
+ RefPtr<TransactionOperation> protectedThis(this);
+
+ ASSERT(performMethod);
+ m_performFunction = [protectedThis, this, performMethod, arguments...] {
+ (&m_transaction.get()->*performMethod)(*this, arguments...);
+ };
+
+ if (completeMethod) {
+ RefPtr<IDBRequest> refRequest(&request);
+ m_completeFunction = [protectedThis, this, refRequest, completeMethod](const IDBResultData& resultData) {
+ if (completeMethod)
+ (&m_transaction.get()->*completeMethod)(*refRequest, resultData);
+ };
+ }
+ }
+};
+
+inline RefPtr<TransactionOperation> createTransactionOperation(
+ IDBTransaction& transaction,
+ void (IDBTransaction::*complete)(const IDBResultData&),
+ void (IDBTransaction::*perform)(TransactionOperation&))
+{
+ auto operation = new TransactionOperationImpl<>(transaction, complete, perform);
+ return adoptRef(operation);
+}
+
+template<typename MP1, typename P1>
+RefPtr<TransactionOperation> createTransactionOperation(
+ IDBTransaction& transaction,
+ void (IDBTransaction::*complete)(const IDBResultData&),
+ void (IDBTransaction::*perform)(TransactionOperation&, MP1),
+ const P1& parameter1)
+{
+ auto operation = new TransactionOperationImpl<MP1>(transaction, complete, perform, parameter1);
+ return adoptRef(operation);
+}
+
+template<typename MP1, typename P1, typename MP2, typename P2>
+RefPtr<TransactionOperation> createTransactionOperation(
+ IDBTransaction& transaction,
+ void (IDBTransaction::*complete)(const IDBResultData&),
+ void (IDBTransaction::*perform)(TransactionOperation&, MP1, MP2),
+ const P1& parameter1,
+ const P2& parameter2)
+{
+ auto operation = new TransactionOperationImpl<MP1, MP2>(transaction, complete, perform, parameter1, parameter2);
+ return adoptRef(operation);
+}
+
+template<typename MP1, typename P1, typename MP2, typename P2, typename MP3, typename P3>
+RefPtr<TransactionOperation> createTransactionOperation(
+ IDBTransaction& transaction,
+ void (IDBTransaction::*complete)(const IDBResultData&),
+ void (IDBTransaction::*perform)(TransactionOperation&, MP1, MP2, MP3),
+ const P1& parameter1,
+ const P2& parameter2,
+ const P3& parameter3)
+{
+ auto operation = new TransactionOperationImpl<MP1, MP2, MP3>(transaction, complete, perform, parameter1, parameter2, parameter3);
+ return adoptRef(operation);
+}
+
+template<typename MP1, typename P1>
+RefPtr<TransactionOperation> createTransactionOperation(
+ IDBTransaction& transaction,
+ IDBRequest& request,
+ void (IDBTransaction::*complete)(IDBRequest&, const IDBResultData&),
+ void (IDBTransaction::*perform)(TransactionOperation&, MP1),
+ const P1& parameter1)
+{
+ auto operation = new TransactionOperationImpl<MP1>(transaction, request, complete, perform, parameter1);
+ return adoptRef(operation);
+}
+
+template<typename MP1, typename P1, typename MP2, typename P2>
+RefPtr<TransactionOperation> createTransactionOperation(
+ IDBTransaction& transaction,
+ IDBRequest& request,
+ void (IDBTransaction::*complete)(IDBRequest&, const IDBResultData&),
+ void (IDBTransaction::*perform)(TransactionOperation&, MP1, MP2),
+ const P1& parameter1,
+ const P2& parameter2)
+{
+ auto operation = new TransactionOperationImpl<MP1, MP2>(transaction, request, complete, perform, parameter1, parameter2);
+ return adoptRef(operation);
+}
+
+template<typename MP1, typename MP2, typename MP3, typename P1, typename P2, typename P3>
+RefPtr<TransactionOperation> createTransactionOperation(
+ IDBTransaction& transaction,
+ IDBRequest& request,
+ void (IDBTransaction::*complete)(IDBRequest&, const IDBResultData&),
+ void (IDBTransaction::*perform)(TransactionOperation&, MP1, MP2, MP3),
+ const P1& parameter1,
+ const P2& parameter2,
+ const P3& parameter3)
+{
+ auto operation = new TransactionOperationImpl<MP1, MP2, MP3>(transaction, request, complete, perform, parameter1, parameter2, parameter3);
+ return adoptRef(operation);
+}
+
+} // namespace IDBClient
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)