diff options
Diffstat (limited to 'Source/WebCore/Modules/indexeddb/IDBOpenDBRequest.cpp')
-rw-r--r-- | Source/WebCore/Modules/indexeddb/IDBOpenDBRequest.cpp | 268 |
1 files changed, 173 insertions, 95 deletions
diff --git a/Source/WebCore/Modules/indexeddb/IDBOpenDBRequest.cpp b/Source/WebCore/Modules/indexeddb/IDBOpenDBRequest.cpp index e929c6c2b..6b79850be 100644 --- a/Source/WebCore/Modules/indexeddb/IDBOpenDBRequest.cpp +++ b/Source/WebCore/Modules/indexeddb/IDBOpenDBRequest.cpp @@ -1,26 +1,26 @@ /* - * Copyright (C) 2012 Google Inc. All rights reserved. + * 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. * - * 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 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 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. + * 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" @@ -28,128 +28,206 @@ #if ENABLE(INDEXED_DATABASE) +#include "DOMError.h" +#include "EventNames.h" +#include "IDBConnectionProxy.h" +#include "IDBConnectionToServer.h" #include "IDBDatabase.h" -#include "IDBDatabaseCallbacksImpl.h" -#include "IDBPendingTransactionMonitor.h" +#include "IDBError.h" +#include "IDBRequestCompletionEvent.h" +#include "IDBResultData.h" +#include "IDBTransaction.h" #include "IDBVersionChangeEvent.h" #include "Logging.h" #include "ScriptExecutionContext.h" namespace WebCore { -PassRefPtr<IDBOpenDBRequest> IDBOpenDBRequest::create(ScriptExecutionContext* context, PassRefPtr<IDBDatabaseCallbacks> callbacks, int64_t transactionId, uint64_t version, IndexedDB::VersionNullness versionNullness) +Ref<IDBOpenDBRequest> IDBOpenDBRequest::createDeleteRequest(ScriptExecutionContext& context, IDBClient::IDBConnectionProxy& connectionProxy, const IDBDatabaseIdentifier& databaseIdentifier) { - RefPtr<IDBOpenDBRequest> request(adoptRef(new IDBOpenDBRequest(context, callbacks, transactionId, version, versionNullness))); - request->suspendIfNeeded(); - return request.release(); + return adoptRef(*new IDBOpenDBRequest(context, connectionProxy, databaseIdentifier, 0, IndexedDB::RequestType::Delete)); } -IDBOpenDBRequest::IDBOpenDBRequest(ScriptExecutionContext* context, PassRefPtr<IDBDatabaseCallbacks> callbacks, int64_t transactionId, uint64_t version, IndexedDB::VersionNullness versionNullness) - : IDBRequest(context, IDBAny::createNull(), IDBDatabaseBackend::NormalTask, 0) - , m_databaseCallbacks(callbacks) - , m_transactionId(transactionId) +Ref<IDBOpenDBRequest> IDBOpenDBRequest::createOpenRequest(ScriptExecutionContext& context, IDBClient::IDBConnectionProxy& connectionProxy, const IDBDatabaseIdentifier& databaseIdentifier, uint64_t version) +{ + return adoptRef(*new IDBOpenDBRequest(context, connectionProxy, databaseIdentifier, version, IndexedDB::RequestType::Open)); +} + +IDBOpenDBRequest::IDBOpenDBRequest(ScriptExecutionContext& context, IDBClient::IDBConnectionProxy& connectionProxy, const IDBDatabaseIdentifier& databaseIdentifier, uint64_t version, IndexedDB::RequestType requestType) + : IDBRequest(context, connectionProxy) + , m_databaseIdentifier(databaseIdentifier) , m_version(version) - , m_versionNullness(versionNullness) { - ASSERT(!m_result); + m_requestType = requestType; } IDBOpenDBRequest::~IDBOpenDBRequest() { + ASSERT(currentThread() == originThreadID()); } -EventTargetInterface IDBOpenDBRequest::eventTargetInterface() const +void IDBOpenDBRequest::onError(const IDBResultData& data) { - return IDBOpenDBRequestEventTargetInterfaceType; + ASSERT(currentThread() == originThreadID()); + + m_domError = DOMError::create(data.error().name(), data.error().message()); + enqueueEvent(IDBRequestCompletionEvent::create(eventNames().errorEvent, true, true, *this)); } -void IDBOpenDBRequest::onBlocked(uint64_t oldVersion) +void IDBOpenDBRequest::versionChangeTransactionDidFinish() { - LOG(StorageAPI, "IDBOpenDBRequest::onBlocked()"); - if (!shouldEnqueueEvent()) - return; - - enqueueEvent(IDBVersionChangeEvent::create(oldVersion, m_version, m_versionNullness, eventNames().blockedEvent)); + ASSERT(currentThread() == originThreadID()); + + // 3.3.7 "versionchange" transaction steps + // When the transaction is finished, after firing complete/abort on the transaction, immediately set request's transaction property to null. + m_shouldExposeTransactionToDOM = false; } -void IDBOpenDBRequest::onUpgradeNeeded(uint64_t oldVersion, PassRefPtr<IDBDatabaseBackend> prpDatabaseBackend, const IDBDatabaseMetadata& metadata) +void IDBOpenDBRequest::fireSuccessAfterVersionChangeCommit() { - LOG(StorageAPI, "IDBOpenDBRequest::onUpgradeNeeded()"); - if (m_contextStopped || !scriptExecutionContext()) { - RefPtr<IDBDatabaseBackend> db = prpDatabaseBackend; - db->abort(m_transactionId); - db->close(m_databaseCallbacks); - return; - } - if (!shouldEnqueueEvent()) - return; + LOG(IndexedDB, "IDBOpenDBRequest::fireSuccessAfterVersionChangeCommit() - %s", resourceIdentifier().loggingString().utf8().data()); + + ASSERT(currentThread() == originThreadID()); + ASSERT(hasPendingActivity()); + m_transaction->addRequest(*this); - ASSERT(m_databaseCallbacks); + auto event = IDBRequestCompletionEvent::create(eventNames().successEvent, false, false, *this); + m_openDatabaseSuccessEvent = &event.get(); - RefPtr<IDBDatabaseBackend> databaseBackend = prpDatabaseBackend; + enqueueEvent(WTFMove(event)); +} - RefPtr<IDBDatabase> idbDatabase = IDBDatabase::create(scriptExecutionContext(), databaseBackend, m_databaseCallbacks); - idbDatabase->setMetadata(metadata); - m_databaseCallbacks->connect(idbDatabase.get()); - m_databaseCallbacks = 0; +void IDBOpenDBRequest::fireErrorAfterVersionChangeCompletion() +{ + LOG(IndexedDB, "IDBOpenDBRequest::fireErrorAfterVersionChangeCompletion() - %s", resourceIdentifier().loggingString().utf8().data()); - IDBDatabaseMetadata oldMetadata(metadata); - oldMetadata.version = oldVersion; + ASSERT(currentThread() == originThreadID()); + ASSERT(hasPendingActivity()); - m_transaction = IDBTransaction::create(scriptExecutionContext(), m_transactionId, idbDatabase.get(), this, oldMetadata); - m_result = IDBAny::create(idbDatabase.release()); + IDBError idbError(IDBDatabaseException::AbortError); + m_domError = DOMError::create(idbError.name(), idbError.message()); + setResultToUndefined(); - if (m_versionNullness == IndexedDB::VersionNullness::Null) - m_version = 1; - enqueueEvent(IDBVersionChangeEvent::create(oldVersion, m_version, m_versionNullness, eventNames().upgradeneededEvent)); + m_transaction->addRequest(*this); + enqueueEvent(IDBRequestCompletionEvent::create(eventNames().errorEvent, true, true, *this)); } -void IDBOpenDBRequest::onSuccess(PassRefPtr<IDBDatabaseBackend> prpBackend, const IDBDatabaseMetadata& metadata) +void IDBOpenDBRequest::cancelForStop() { - LOG(StorageAPI, "IDBOpenDBRequest::onSuccess()"); - if (!shouldEnqueueEvent()) - return; + connectionProxy().openDBRequestCancelled({ connectionProxy(), *this }); +} - RefPtr<IDBDatabaseBackend> backend = prpBackend; - RefPtr<IDBDatabase> idbDatabase; - if (m_result) { - idbDatabase = m_result->idbDatabase(); - ASSERT(idbDatabase); - ASSERT(!m_databaseCallbacks); - } else { - ASSERT(m_databaseCallbacks); - idbDatabase = IDBDatabase::create(scriptExecutionContext(), backend.release(), m_databaseCallbacks); - m_databaseCallbacks->connect(idbDatabase.get()); - m_databaseCallbacks = 0; - m_result = IDBAny::create(idbDatabase.get()); - } - idbDatabase->setMetadata(metadata); - enqueueEvent(Event::create(eventNames().successEvent, false, false)); +bool IDBOpenDBRequest::dispatchEvent(Event& event) +{ + ASSERT(currentThread() == originThreadID()); + + bool result = IDBRequest::dispatchEvent(event); + + if (m_transaction && m_transaction->isVersionChange() && (event.type() == eventNames().errorEvent || event.type() == eventNames().successEvent)) + m_transaction->database().connectionProxy().didFinishHandlingVersionChangeTransaction(m_transaction->database().databaseConnectionIdentifier(), *m_transaction); + + return result; } -bool IDBOpenDBRequest::shouldEnqueueEvent() const +void IDBOpenDBRequest::onSuccess(const IDBResultData& resultData) { - if (m_contextStopped || !scriptExecutionContext()) - return false; - ASSERT(m_readyState == PENDING || m_readyState == DONE); - if (m_requestAborted) - return false; - return true; + LOG(IndexedDB, "IDBOpenDBRequest::onSuccess()"); + + ASSERT(currentThread() == originThreadID()); + + setResult(IDBDatabase::create(*scriptExecutionContext(), connectionProxy(), resultData)); + m_readyState = ReadyState::Done; + + enqueueEvent(IDBRequestCompletionEvent::create(eventNames().successEvent, false, false, *this)); } -bool IDBOpenDBRequest::dispatchEvent(PassRefPtr<Event> event) +void IDBOpenDBRequest::onUpgradeNeeded(const IDBResultData& resultData) { - // If the connection closed between onUpgradeNeeded and the delivery of the "success" event, - // an "error" event should be fired instead. - if (event->type() == eventNames().successEvent && m_result->type() == IDBAny::IDBDatabaseType && m_result->idbDatabase()->isClosePending()) { - m_result.clear(); - onError(IDBDatabaseError::create(IDBDatabaseException::AbortError, "The connection was closed.")); - return false; + ASSERT(currentThread() == originThreadID()); + + Ref<IDBDatabase> database = IDBDatabase::create(*scriptExecutionContext(), connectionProxy(), resultData); + Ref<IDBTransaction> transaction = database->startVersionChangeTransaction(resultData.transactionInfo(), *this); + + ASSERT(transaction->info().mode() == IDBTransactionMode::Versionchange); + ASSERT(transaction->originalDatabaseInfo()); + + uint64_t oldVersion = transaction->originalDatabaseInfo()->version(); + uint64_t newVersion = transaction->info().newVersion(); + + LOG(IndexedDB, "IDBOpenDBRequest::onUpgradeNeeded() - current version is %" PRIu64 ", new is %" PRIu64, oldVersion, newVersion); + + setResult(WTFMove(database)); + m_readyState = ReadyState::Done; + m_transaction = WTFMove(transaction); + m_transaction->addRequest(*this); + + enqueueEvent(IDBVersionChangeEvent::create(oldVersion, newVersion, eventNames().upgradeneededEvent)); +} + +void IDBOpenDBRequest::onDeleteDatabaseSuccess(const IDBResultData& resultData) +{ + ASSERT(currentThread() == originThreadID()); + + uint64_t oldVersion = resultData.databaseInfo().version(); + + LOG(IndexedDB, "IDBOpenDBRequest::onDeleteDatabaseSuccess() - current version is %" PRIu64, oldVersion); + + m_readyState = ReadyState::Done; + setResultToUndefined(); + + enqueueEvent(IDBVersionChangeEvent::create(oldVersion, 0, eventNames().successEvent)); +} + +void IDBOpenDBRequest::requestCompleted(const IDBResultData& data) +{ + LOG(IndexedDB, "IDBOpenDBRequest::requestCompleted"); + + ASSERT(currentThread() == originThreadID()); + + // If an Open request was completed after the page has navigated, leaving this request + // with a stopped script execution context, we need to message back to the server so it + // doesn't hang waiting on a database connection or transaction that will never exist. + if (m_contextStopped) { + switch (data.type()) { + case IDBResultType::OpenDatabaseSuccess: + connectionProxy().abortOpenAndUpgradeNeeded(data.databaseConnectionIdentifier(), IDBResourceIdentifier::emptyValue()); + break; + case IDBResultType::OpenDatabaseUpgradeNeeded: + connectionProxy().abortOpenAndUpgradeNeeded(data.databaseConnectionIdentifier(), data.transactionInfo().identifier()); + break; + default: + break; + } + + return; } - return IDBRequest::dispatchEvent(event); + switch (data.type()) { + case IDBResultType::Error: + onError(data); + break; + case IDBResultType::OpenDatabaseSuccess: + onSuccess(data); + break; + case IDBResultType::OpenDatabaseUpgradeNeeded: + onUpgradeNeeded(data); + break; + case IDBResultType::DeleteDatabaseSuccess: + onDeleteDatabaseSuccess(data); + break; + default: + RELEASE_ASSERT_NOT_REACHED(); + } +} + +void IDBOpenDBRequest::requestBlocked(uint64_t oldVersion, uint64_t newVersion) +{ + ASSERT(currentThread() == originThreadID()); + + LOG(IndexedDB, "IDBOpenDBRequest::requestBlocked"); + enqueueEvent(IDBVersionChangeEvent::create(oldVersion, newVersion, eventNames().blockedEvent)); } } // namespace WebCore -#endif +#endif // ENABLE(INDEXED_DATABASE) |