diff options
Diffstat (limited to 'Source/WebCore/inspector/InspectorIndexedDBAgent.cpp')
-rw-r--r-- | Source/WebCore/inspector/InspectorIndexedDBAgent.cpp | 669 |
1 files changed, 318 insertions, 351 deletions
diff --git a/Source/WebCore/inspector/InspectorIndexedDBAgent.cpp b/Source/WebCore/inspector/InspectorIndexedDBAgent.cpp index af3c598f7..ef3d268d0 100644 --- a/Source/WebCore/inspector/InspectorIndexedDBAgent.cpp +++ b/Source/WebCore/inspector/InspectorIndexedDBAgent.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2012 Google Inc. All rights reserved. + * 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 @@ -29,25 +30,23 @@ */ #include "config.h" - -#if ENABLE(INSPECTOR) && ENABLE(INDEXED_DATABASE) - #include "InspectorIndexedDBAgent.h" +#if ENABLE(INDEXED_DATABASE) + #include "DOMStringList.h" #include "DOMWindow.h" #include "DOMWindowIndexedDatabase.h" #include "Document.h" #include "Event.h" #include "EventListener.h" +#include "EventNames.h" #include "EventTarget.h" -#include "ExceptionCode.h" #include "Frame.h" +#include "IDBBindingUtilities.h" #include "IDBCursor.h" #include "IDBCursorWithValue.h" #include "IDBDatabase.h" -#include "IDBDatabaseCallbacks.h" -#include "IDBDatabaseMetadata.h" #include "IDBFactory.h" #include "IDBIndex.h" #include "IDBKey.h" @@ -55,32 +54,35 @@ #include "IDBKeyRange.h" #include "IDBObjectStore.h" #include "IDBOpenDBRequest.h" -#include "IDBPendingTransactionMonitor.h" #include "IDBRequest.h" #include "IDBTransaction.h" #include "InspectorPageAgent.h" -#include "InspectorWebFrontendDispatchers.h" #include "InstrumentingAgents.h" +#include "ScriptState.h" #include "SecurityOrigin.h" +#include <heap/HeapInlines.h> #include <inspector/InjectedScript.h> #include <inspector/InjectedScriptManager.h> +#include <inspector/InspectorFrontendDispatchers.h> +#include <inspector/InspectorFrontendRouter.h> #include <inspector/InspectorValues.h> +#include <wtf/NeverDestroyed.h> #include <wtf/Vector.h> -using Inspector::TypeBuilder::Array; -using Inspector::TypeBuilder::IndexedDB::DatabaseWithObjectStores; -using Inspector::TypeBuilder::IndexedDB::DataEntry; -using Inspector::TypeBuilder::IndexedDB::Key; -using Inspector::TypeBuilder::IndexedDB::KeyPath; -using Inspector::TypeBuilder::IndexedDB::KeyRange; -using Inspector::TypeBuilder::IndexedDB::ObjectStore; -using Inspector::TypeBuilder::IndexedDB::ObjectStoreIndex; - -typedef Inspector::InspectorBackendDispatcher::CallbackBase RequestCallback; -typedef Inspector::InspectorIndexedDBBackendDispatcherHandler::RequestDatabaseNamesCallback RequestDatabaseNamesCallback; -typedef Inspector::InspectorIndexedDBBackendDispatcherHandler::RequestDatabaseCallback RequestDatabaseCallback; -typedef Inspector::InspectorIndexedDBBackendDispatcherHandler::RequestDataCallback RequestDataCallback; -typedef Inspector::InspectorIndexedDBBackendDispatcherHandler::ClearObjectStoreCallback ClearObjectStoreCallback; +using Inspector::Protocol::Array; +using Inspector::Protocol::IndexedDB::DatabaseWithObjectStores; +using Inspector::Protocol::IndexedDB::DataEntry; +using Inspector::Protocol::IndexedDB::Key; +using Inspector::Protocol::IndexedDB::KeyPath; +using Inspector::Protocol::IndexedDB::KeyRange; +using Inspector::Protocol::IndexedDB::ObjectStore; +using Inspector::Protocol::IndexedDB::ObjectStoreIndex; + +typedef Inspector::BackendDispatcher::CallbackBase RequestCallback; +typedef Inspector::IndexedDBBackendDispatcherHandler::RequestDatabaseNamesCallback RequestDatabaseNamesCallback; +typedef Inspector::IndexedDBBackendDispatcherHandler::RequestDatabaseCallback RequestDatabaseCallback; +typedef Inspector::IndexedDBBackendDispatcherHandler::RequestDataCallback RequestDataCallback; +typedef Inspector::IndexedDBBackendDispatcherHandler::ClearObjectStoreCallback ClearObjectStoreCallback; using namespace Inspector; @@ -88,283 +90,220 @@ namespace WebCore { namespace { -class GetDatabaseNamesCallback : public EventListener { - WTF_MAKE_NONCOPYABLE(GetDatabaseNamesCallback); -public: - static PassRefPtr<GetDatabaseNamesCallback> create(PassRefPtr<RequestDatabaseNamesCallback> requestCallback, const String& securityOrigin) - { - return adoptRef(new GetDatabaseNamesCallback(requestCallback, securityOrigin)); - } - - virtual ~GetDatabaseNamesCallback() { } - - virtual bool operator==(const EventListener& other) override - { - return this == &other; - } - - virtual void handleEvent(ScriptExecutionContext*, Event* event) override - { - if (!m_requestCallback->isActive()) - return; - if (event->type() != eventNames().successEvent) { - m_requestCallback->sendFailure("Unexpected event type."); - return; - } - - IDBRequest* idbRequest = static_cast<IDBRequest*>(event->target()); - ExceptionCode ec = 0; - RefPtr<IDBAny> requestResult = idbRequest->result(ec); - if (ec) { - m_requestCallback->sendFailure("Could not get result in callback."); - return; - } - if (requestResult->type() != IDBAny::DOMStringListType) { - m_requestCallback->sendFailure("Unexpected result type."); - return; - } - - RefPtr<DOMStringList> databaseNamesList = requestResult->domStringList(); - RefPtr<Inspector::TypeBuilder::Array<String>> databaseNames = Inspector::TypeBuilder::Array<String>::create(); - for (size_t i = 0; i < databaseNamesList->length(); ++i) - databaseNames->addItem(databaseNamesList->item(i)); - m_requestCallback->sendSuccess(databaseNames.release()); - } - -private: - GetDatabaseNamesCallback(PassRefPtr<RequestDatabaseNamesCallback> requestCallback, const String& securityOrigin) - : EventListener(EventListener::CPPEventListenerType) - , m_requestCallback(requestCallback) - , m_securityOrigin(securityOrigin) { } - RefPtr<RequestDatabaseNamesCallback> m_requestCallback; - String m_securityOrigin; -}; - class ExecutableWithDatabase : public RefCounted<ExecutableWithDatabase> { public: ExecutableWithDatabase(ScriptExecutionContext* context) : m_context(context) { } - virtual ~ExecutableWithDatabase() { }; + virtual ~ExecutableWithDatabase() { } void start(IDBFactory*, SecurityOrigin*, const String& databaseName); - virtual void execute(PassRefPtr<IDBDatabase>) = 0; - virtual RequestCallback* requestCallback() = 0; - ScriptExecutionContext* context() { return m_context; }; + virtual void execute(IDBDatabase&) = 0; + virtual RequestCallback& requestCallback() = 0; + ScriptExecutionContext* context() const { return m_context; } private: ScriptExecutionContext* m_context; }; -class OpenDatabaseCallback : public EventListener { +class OpenDatabaseCallback final : public EventListener { public: - static PassRefPtr<OpenDatabaseCallback> create(ExecutableWithDatabase* executableWithDatabase) + static Ref<OpenDatabaseCallback> create(ExecutableWithDatabase& executableWithDatabase) { - return adoptRef(new OpenDatabaseCallback(executableWithDatabase)); + return adoptRef(*new OpenDatabaseCallback(executableWithDatabase)); } - virtual ~OpenDatabaseCallback() { } - - virtual bool operator==(const EventListener& other) override + bool operator==(const EventListener& other) const final { return this == &other; } - virtual void handleEvent(ScriptExecutionContext*, Event* event) override + void handleEvent(ScriptExecutionContext*, Event* event) final { if (event->type() != eventNames().successEvent) { - m_executableWithDatabase->requestCallback()->sendFailure("Unexpected event type."); + m_executableWithDatabase->requestCallback().sendFailure("Unexpected event type."); return; } - IDBOpenDBRequest* idbOpenDBRequest = static_cast<IDBOpenDBRequest*>(event->target()); - ExceptionCode ec = 0; - RefPtr<IDBAny> requestResult = idbOpenDBRequest->result(ec); - if (ec) { - m_executableWithDatabase->requestCallback()->sendFailure("Could not get result in callback."); + auto& request = static_cast<IDBOpenDBRequest&>(*event->target()); + + auto result = request.result(); + if (result.hasException()) { + m_executableWithDatabase->requestCallback().sendFailure("Could not get result in callback."); return; } - if (requestResult->type() != IDBAny::IDBDatabaseType) { - m_executableWithDatabase->requestCallback()->sendFailure("Unexpected result type."); + + auto resultValue = result.releaseReturnValue(); + if (!resultValue || !WTF::holds_alternative<RefPtr<IDBDatabase>>(resultValue.value())) { + m_executableWithDatabase->requestCallback().sendFailure("Unexpected result type."); return; } - RefPtr<IDBDatabase> idbDatabase = requestResult->idbDatabase(); - m_executableWithDatabase->execute(idbDatabase); - IDBPendingTransactionMonitor::deactivateNewTransactions(); - idbDatabase->close(); + auto databaseResult = WTF::get<RefPtr<IDBDatabase>>(resultValue.value()); + m_executableWithDatabase->execute(*databaseResult); + databaseResult->close(); } private: - OpenDatabaseCallback(ExecutableWithDatabase* executableWithDatabase) + OpenDatabaseCallback(ExecutableWithDatabase& executableWithDatabase) : EventListener(EventListener::CPPEventListenerType) , m_executableWithDatabase(executableWithDatabase) { } - RefPtr<ExecutableWithDatabase> m_executableWithDatabase; + Ref<ExecutableWithDatabase> m_executableWithDatabase; }; void ExecutableWithDatabase::start(IDBFactory* idbFactory, SecurityOrigin*, const String& databaseName) { - RefPtr<OpenDatabaseCallback> callback = OpenDatabaseCallback::create(this); - ExceptionCode ec = 0; - RefPtr<IDBOpenDBRequest> idbOpenDBRequest = idbFactory->open(context(), databaseName, ec); - if (ec) { - requestCallback()->sendFailure("Could not open database."); + if (!context()) { + requestCallback().sendFailure("Could not open database."); + return; + } + + auto result = idbFactory->open(*context(), databaseName, std::nullopt); + if (result.hasException()) { + requestCallback().sendFailure("Could not open database."); return; } - idbOpenDBRequest->addEventListener(eventNames().successEvent, callback, false); + + result.releaseReturnValue()->addEventListener(eventNames().successEvent, OpenDatabaseCallback::create(*this), false); } -static PassRefPtr<IDBTransaction> transactionForDatabase(ScriptExecutionContext* scriptExecutionContext, IDBDatabase* idbDatabase, const String& objectStoreName, const String& mode = IDBTransaction::modeReadOnly()) + +static RefPtr<KeyPath> keyPathFromIDBKeyPath(const std::optional<IDBKeyPath>& idbKeyPath) { - ExceptionCode ec = 0; - RefPtr<IDBTransaction> idbTransaction = idbDatabase->transaction(scriptExecutionContext, objectStoreName, mode, ec); - if (ec) - return nullptr; - return idbTransaction; + if (!idbKeyPath) + return KeyPath::create().setType(KeyPath::Type::Null).release(); + + auto visitor = WTF::makeVisitor([](const String& string) { + RefPtr<KeyPath> keyPath = KeyPath::create().setType(KeyPath::Type::String).release(); + keyPath->setString(string); + return keyPath; + }, [](const Vector<String>& vector) { + auto array = Inspector::Protocol::Array<String>::create(); + for (auto& string : vector) + array->addItem(string); + RefPtr<KeyPath> keyPath = KeyPath::create().setType(KeyPath::Type::Array).release(); + keyPath->setArray(WTFMove(array)); + return keyPath; + }); + return WTF::visit(visitor, idbKeyPath.value()); } -static PassRefPtr<IDBObjectStore> objectStoreForTransaction(IDBTransaction* idbTransaction, const String& objectStoreName) +static RefPtr<IDBTransaction> transactionForDatabase(IDBDatabase* idbDatabase, const String& objectStoreName, IDBTransactionMode mode = IDBTransactionMode::Readonly) { - ExceptionCode ec = 0; - RefPtr<IDBObjectStore> idbObjectStore = idbTransaction->objectStore(objectStoreName, ec); - if (ec) + auto result = idbDatabase->transaction(objectStoreName, mode); + if (result.hasException()) return nullptr; - return idbObjectStore; + return result.releaseReturnValue(); } -static PassRefPtr<IDBIndex> indexForObjectStore(IDBObjectStore* idbObjectStore, const String& indexName) +static RefPtr<IDBObjectStore> objectStoreForTransaction(IDBTransaction* idbTransaction, const String& objectStoreName) { - ExceptionCode ec = 0; - RefPtr<IDBIndex> idbIndex = idbObjectStore->index(indexName, ec); - if (ec) + auto result = idbTransaction->objectStore(objectStoreName); + if (result.hasException()) return nullptr; - return idbIndex; + return result.releaseReturnValue(); } -#if !PLATFORM(MAC) -static PassRefPtr<KeyPath> keyPathFromIDBKeyPath(const IDBKeyPath& idbKeyPath) +static RefPtr<IDBIndex> indexForObjectStore(IDBObjectStore* idbObjectStore, const String& indexName) { - RefPtr<KeyPath> keyPath; - switch (idbKeyPath.type()) { - case IDBKeyPath::NullType: - keyPath = KeyPath::create().setType(KeyPath::Type::Null); - break; - case IDBKeyPath::StringType: - keyPath = KeyPath::create().setType(KeyPath::Type::String); - keyPath->setString(idbKeyPath.string()); - break; - case IDBKeyPath::ArrayType: { - keyPath = KeyPath::create().setType(KeyPath::Type::Array); - RefPtr<Inspector::TypeBuilder::Array<String>> array = Inspector::TypeBuilder::Array<String>::create(); - const Vector<String>& stringArray = idbKeyPath.array(); - for (size_t i = 0; i < stringArray.size(); ++i) - array->addItem(stringArray[i]); - keyPath->setArray(array); - break; - } - default: - ASSERT_NOT_REACHED(); - } - - return keyPath.release(); + auto index = idbObjectStore->index(indexName); + if (index.hasException()) + return nullptr; + return index.releaseReturnValue(); } -#endif // !PLATFORM(MAC) -class DatabaseLoader : public ExecutableWithDatabase { +class DatabaseLoader final : public ExecutableWithDatabase { public: - static PassRefPtr<DatabaseLoader> create(ScriptExecutionContext* context, PassRefPtr<RequestDatabaseCallback> requestCallback) + static Ref<DatabaseLoader> create(ScriptExecutionContext* context, Ref<RequestDatabaseCallback>&& requestCallback) { - return adoptRef(new DatabaseLoader(context, requestCallback)); + return adoptRef(*new DatabaseLoader(context, WTFMove(requestCallback))); } virtual ~DatabaseLoader() { } - virtual void execute(PassRefPtr<IDBDatabase> prpDatabase) override + void execute(IDBDatabase& database) override { -#if PLATFORM(MAC) - ASSERT_UNUSED(prpDatabase, prpDatabase); -#else - RefPtr<IDBDatabase> idbDatabase = prpDatabase; - if (!requestCallback()->isActive()) + if (!requestCallback().isActive()) return; - - const IDBDatabaseMetadata databaseMetadata = idbDatabase->metadata(); - - RefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::IndexedDB::ObjectStore>> objectStores = Inspector::TypeBuilder::Array<Inspector::TypeBuilder::IndexedDB::ObjectStore>::create(); - - for (IDBDatabaseMetadata::ObjectStoreMap::const_iterator it = databaseMetadata.objectStores.begin(); it != databaseMetadata.objectStores.end(); ++it) { - const IDBObjectStoreMetadata& objectStoreMetadata = it->value; - - RefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::IndexedDB::ObjectStoreIndex>> indexes = Inspector::TypeBuilder::Array<Inspector::TypeBuilder::IndexedDB::ObjectStoreIndex>::create(); - - for (IDBObjectStoreMetadata::IndexMap::const_iterator it = objectStoreMetadata.indexes.begin(); it != objectStoreMetadata.indexes.end(); ++it) { - const IDBIndexMetadata& indexMetadata = it->value; - - RefPtr<ObjectStoreIndex> objectStoreIndex = ObjectStoreIndex::create() - .setName(indexMetadata.name) - .setKeyPath(keyPathFromIDBKeyPath(indexMetadata.keyPath)) - .setUnique(indexMetadata.unique) - .setMultiEntry(indexMetadata.multiEntry); - indexes->addItem(objectStoreIndex); + + auto& databaseInfo = database.info(); + auto objectStores = Inspector::Protocol::Array<Inspector::Protocol::IndexedDB::ObjectStore>::create(); + auto objectStoreNames = databaseInfo.objectStoreNames(); + for (auto& name : objectStoreNames) { + auto* objectStoreInfo = databaseInfo.infoForExistingObjectStore(name); + if (!objectStoreInfo) + continue; + + auto indexes = Inspector::Protocol::Array<Inspector::Protocol::IndexedDB::ObjectStoreIndex>::create(); + + for (auto& indexInfo : objectStoreInfo->indexMap().values()) { + auto objectStoreIndex = ObjectStoreIndex::create() + .setName(indexInfo.name()) + .setKeyPath(keyPathFromIDBKeyPath(indexInfo.keyPath())) + .setUnique(indexInfo.unique()) + .setMultiEntry(indexInfo.multiEntry()) + .release(); + indexes->addItem(WTFMove(objectStoreIndex)); } - - RefPtr<ObjectStore> objectStore = ObjectStore::create() - .setName(objectStoreMetadata.name) - .setKeyPath(keyPathFromIDBKeyPath(objectStoreMetadata.keyPath)) - .setAutoIncrement(objectStoreMetadata.autoIncrement) - .setIndexes(indexes); - objectStores->addItem(objectStore); + + auto objectStore = ObjectStore::create() + .setName(objectStoreInfo->name()) + .setKeyPath(keyPathFromIDBKeyPath(objectStoreInfo->keyPath())) + .setAutoIncrement(objectStoreInfo->autoIncrement()) + .setIndexes(WTFMove(indexes)) + .release(); + objectStores->addItem(WTFMove(objectStore)); } - RefPtr<DatabaseWithObjectStores> result = DatabaseWithObjectStores::create() - .setName(databaseMetadata.name) - .setIntVersion(databaseMetadata.version) - .setVersion(String::number(databaseMetadata.version)) - .setObjectStores(objectStores); - - m_requestCallback->sendSuccess(result); -#endif // PLATFORM(MAC) + + auto result = DatabaseWithObjectStores::create() + .setName(databaseInfo.name()) + .setVersion(databaseInfo.version()) + .setObjectStores(WTFMove(objectStores)) + .release(); + m_requestCallback->sendSuccess(WTFMove(result)); } - virtual RequestCallback* requestCallback() override { return m_requestCallback.get(); } + RequestCallback& requestCallback() override { return m_requestCallback.get(); } private: - DatabaseLoader(ScriptExecutionContext* context, PassRefPtr<RequestDatabaseCallback> requestCallback) + DatabaseLoader(ScriptExecutionContext* context, Ref<RequestDatabaseCallback>&& requestCallback) : ExecutableWithDatabase(context) - , m_requestCallback(requestCallback) { } - RefPtr<RequestDatabaseCallback> m_requestCallback; + , m_requestCallback(WTFMove(requestCallback)) { } + Ref<RequestDatabaseCallback> m_requestCallback; }; -static PassRefPtr<IDBKey> idbKeyFromInspectorObject(InspectorObject* key) +static RefPtr<IDBKey> idbKeyFromInspectorObject(InspectorObject* key) { - RefPtr<IDBKey> idbKey; - String type; - if (!key->getString("type", &type)) + if (!key->getString("type", type)) return nullptr; - DEFINE_STATIC_LOCAL(String, number, (ASCIILiteral("number"))); - DEFINE_STATIC_LOCAL(String, string, (ASCIILiteral("string"))); - DEFINE_STATIC_LOCAL(String, date, (ASCIILiteral("date"))); - DEFINE_STATIC_LOCAL(String, array, (ASCIILiteral("array"))); + static NeverDestroyed<const String> numberType(ASCIILiteral("number")); + static NeverDestroyed<const String> stringType(ASCIILiteral("string")); + static NeverDestroyed<const String> dateType(ASCIILiteral("date")); + static NeverDestroyed<const String> arrayType(ASCIILiteral("array")); - if (type == number) { + RefPtr<IDBKey> idbKey; + if (type == numberType) { double number; - if (!key->getNumber("number", &number)) + if (!key->getDouble("number", number)) return nullptr; idbKey = IDBKey::createNumber(number); - } else if (type == string) { + } else if (type == stringType) { String string; - if (!key->getString("string", &string)) + if (!key->getString("string", string)) return nullptr; idbKey = IDBKey::createString(string); - } else if (type == date) { + } else if (type == dateType) { double date; - if (!key->getNumber("date", &date)) + if (!key->getDouble("date", date)) return nullptr; idbKey = IDBKey::createDate(date); - } else if (type == array) { - IDBKey::KeyArray keyArray; - RefPtr<InspectorArray> array = key->getArray("array"); + } else if (type == arrayType) { + Vector<RefPtr<IDBKey>> keyArray; + RefPtr<InspectorArray> array; + if (!key->getArray("array", array)) + return nullptr; for (size_t i = 0; i < array->length(); ++i) { RefPtr<InspectorValue> value = array->get(i); RefPtr<InspectorObject> object; - if (!value->asObject(&object)) + if (!value->asObject(object)) return nullptr; keyArray.append(idbKeyFromInspectorObject(object.get())); } @@ -372,80 +311,77 @@ static PassRefPtr<IDBKey> idbKeyFromInspectorObject(InspectorObject* key) } else return nullptr; - return idbKey.release(); + return idbKey; } -static PassRefPtr<IDBKeyRange> idbKeyRangeFromKeyRange(InspectorObject* keyRange) +static RefPtr<IDBKeyRange> idbKeyRangeFromKeyRange(const InspectorObject* keyRange) { - RefPtr<InspectorObject> lower = keyRange->getObject("lower"); - RefPtr<IDBKey> idbLower = lower ? idbKeyFromInspectorObject(lower.get()) : nullptr; - if (lower && !idbLower) - return nullptr; + RefPtr<IDBKey> idbLower; + RefPtr<InspectorObject> lower; + if (keyRange->getObject(ASCIILiteral("lower"), lower)) { + idbLower = idbKeyFromInspectorObject(lower.get()); + if (!idbLower) + return nullptr; + } - RefPtr<InspectorObject> upper = keyRange->getObject("upper"); - RefPtr<IDBKey> idbUpper = upper ? idbKeyFromInspectorObject(upper.get()) : nullptr; - if (upper && !idbUpper) - return nullptr; + RefPtr<IDBKey> idbUpper; + RefPtr<InspectorObject> upper; + if (keyRange->getObject(ASCIILiteral("upper"), upper)) { + idbUpper = idbKeyFromInspectorObject(upper.get()); + if (!idbUpper) + return nullptr; + } bool lowerOpen; - if (!keyRange->getBoolean("lowerOpen", &lowerOpen)) + if (!keyRange->getBoolean(ASCIILiteral("lowerOpen"), lowerOpen)) return nullptr; - IDBKeyRange::LowerBoundType lowerBoundType = lowerOpen ? IDBKeyRange::LowerBoundOpen : IDBKeyRange::LowerBoundClosed; bool upperOpen; - if (!keyRange->getBoolean("upperOpen", &upperOpen)) + if (!keyRange->getBoolean(ASCIILiteral("upperOpen"), upperOpen)) return nullptr; - IDBKeyRange::UpperBoundType upperBoundType = upperOpen ? IDBKeyRange::UpperBoundOpen : IDBKeyRange::UpperBoundClosed; - RefPtr<IDBKeyRange> idbKeyRange = IDBKeyRange::create(idbLower, idbUpper, lowerBoundType, upperBoundType); - return idbKeyRange.release(); + return IDBKeyRange::create(WTFMove(idbLower), WTFMove(idbUpper), lowerOpen, upperOpen); } -class DataLoader; - -class OpenCursorCallback : public EventListener { +class OpenCursorCallback final : public EventListener { public: - static PassRefPtr<OpenCursorCallback> create(InjectedScript injectedScript, PassRefPtr<RequestDataCallback> requestCallback, int skipCount, unsigned pageSize) + static Ref<OpenCursorCallback> create(InjectedScript injectedScript, Ref<RequestDataCallback>&& requestCallback, int skipCount, unsigned pageSize) { - return adoptRef(new OpenCursorCallback(injectedScript, requestCallback, skipCount, pageSize)); + return adoptRef(*new OpenCursorCallback(injectedScript, WTFMove(requestCallback), skipCount, pageSize)); } virtual ~OpenCursorCallback() { } - virtual bool operator==(const EventListener& other) override + bool operator==(const EventListener& other) const override { return this == &other; } - virtual void handleEvent(ScriptExecutionContext*, Event* event) override + void handleEvent(ScriptExecutionContext* context, Event* event) override { if (event->type() != eventNames().successEvent) { m_requestCallback->sendFailure("Unexpected event type."); return; } - IDBRequest* idbRequest = static_cast<IDBRequest*>(event->target()); - ExceptionCode ec = 0; - RefPtr<IDBAny> requestResult = idbRequest->result(ec); - if (ec) { + auto& request = static_cast<IDBRequest&>(*event->target()); + + auto result = request.result(); + if (result.hasException()) { m_requestCallback->sendFailure("Could not get result in callback."); return; } - if (requestResult->type() == IDBAny::ScriptValueType) { + + auto resultValue = result.releaseReturnValue(); + if (!resultValue || !WTF::holds_alternative<RefPtr<IDBCursor>>(resultValue.value())) { end(false); return; } - if (requestResult->type() != IDBAny::IDBCursorWithValueType) { - m_requestCallback->sendFailure("Unexpected result type."); - return; - } - RefPtr<IDBCursorWithValue> idbCursor = requestResult->idbCursorWithValue(); + auto cursor = WTF::get<RefPtr<IDBCursor>>(resultValue.value()); if (m_skipCount) { - ExceptionCode ec = 0; - idbCursor->advance(m_skipCount, ec); - if (ec) + if (cursor->advance(m_skipCount).hasException()) m_requestCallback->sendFailure("Could not advance cursor."); m_skipCount = 0; return; @@ -457,97 +393,116 @@ public: } // Continue cursor before making injected script calls, otherwise transaction might be finished. - idbCursor->continueFunction(nullptr, ec); - if (ec) { + if (cursor->continueFunction(nullptr).hasException()) { m_requestCallback->sendFailure("Could not continue cursor."); return; } - RefPtr<DataEntry> dataEntry = DataEntry::create() - .setKey(m_injectedScript.wrapObject(idbCursor->key(), String())) - .setPrimaryKey(m_injectedScript.wrapObject(idbCursor->primaryKey(), String())) - .setValue(m_injectedScript.wrapObject(idbCursor->value(), String())); - m_result->addItem(dataEntry); + auto* state = context ? context->execState() : nullptr; + if (!state) + return; + auto dataEntry = DataEntry::create() + .setKey(m_injectedScript.wrapObject(cursor->key(), String(), true)) + .setPrimaryKey(m_injectedScript.wrapObject(cursor->primaryKey(), String(), true)) + .setValue(m_injectedScript.wrapObject(cursor->value(), String(), true)) + .release(); + m_result->addItem(WTFMove(dataEntry)); } void end(bool hasMore) { if (!m_requestCallback->isActive()) return; - m_requestCallback->sendSuccess(m_result.release(), hasMore); + m_requestCallback->sendSuccess(WTFMove(m_result), hasMore); } private: - OpenCursorCallback(InjectedScript injectedScript, PassRefPtr<RequestDataCallback> requestCallback, int skipCount, unsigned pageSize) + OpenCursorCallback(InjectedScript injectedScript, Ref<RequestDataCallback>&& requestCallback, int skipCount, unsigned pageSize) : EventListener(EventListener::CPPEventListenerType) , m_injectedScript(injectedScript) - , m_requestCallback(requestCallback) + , m_requestCallback(WTFMove(requestCallback)) + , m_result(Array<DataEntry>::create()) , m_skipCount(skipCount) , m_pageSize(pageSize) { - m_result = Array<DataEntry>::create(); } InjectedScript m_injectedScript; - RefPtr<RequestDataCallback> m_requestCallback; + Ref<RequestDataCallback> m_requestCallback; + Ref<Array<DataEntry>> m_result; int m_skipCount; unsigned m_pageSize; - RefPtr<Array<DataEntry>> m_result; }; -class DataLoader : public ExecutableWithDatabase { +class DataLoader final : public ExecutableWithDatabase { public: - static PassRefPtr<DataLoader> create(ScriptExecutionContext* context, PassRefPtr<RequestDataCallback> requestCallback, const InjectedScript& injectedScript, const String& objectStoreName, const String& indexName, PassRefPtr<IDBKeyRange> idbKeyRange, int skipCount, unsigned pageSize) + static Ref<DataLoader> create(ScriptExecutionContext* context, Ref<RequestDataCallback>&& requestCallback, const InjectedScript& injectedScript, const String& objectStoreName, const String& indexName, RefPtr<IDBKeyRange>&& idbKeyRange, int skipCount, unsigned pageSize) { - return adoptRef(new DataLoader(context, requestCallback, injectedScript, objectStoreName, indexName, idbKeyRange, skipCount, pageSize)); + return adoptRef(*new DataLoader(context, WTFMove(requestCallback), injectedScript, objectStoreName, indexName, WTFMove(idbKeyRange), skipCount, pageSize)); } virtual ~DataLoader() { } - virtual void execute(PassRefPtr<IDBDatabase> prpDatabase) override + void execute(IDBDatabase& database) override { - RefPtr<IDBDatabase> idbDatabase = prpDatabase; - if (!requestCallback()->isActive()) + if (!requestCallback().isActive()) return; - RefPtr<IDBTransaction> idbTransaction = transactionForDatabase(context(), idbDatabase.get(), m_objectStoreName); + + auto idbTransaction = transactionForDatabase(&database, m_objectStoreName); if (!idbTransaction) { m_requestCallback->sendFailure("Could not get transaction"); return; } - RefPtr<IDBObjectStore> idbObjectStore = objectStoreForTransaction(idbTransaction.get(), m_objectStoreName); + + auto idbObjectStore = objectStoreForTransaction(idbTransaction.get(), m_objectStoreName); if (!idbObjectStore) { m_requestCallback->sendFailure("Could not get object store"); return; } - RefPtr<OpenCursorCallback> openCursorCallback = OpenCursorCallback::create(m_injectedScript, m_requestCallback, m_skipCount, m_pageSize); - - ExceptionCode ec = 0; + TransactionActivator activator(idbTransaction.get()); RefPtr<IDBRequest> idbRequest; + auto* exec = context() ? context()->execState() : nullptr; if (!m_indexName.isEmpty()) { - RefPtr<IDBIndex> idbIndex = indexForObjectStore(idbObjectStore.get(), m_indexName); + auto idbIndex = indexForObjectStore(idbObjectStore.get(), m_indexName); if (!idbIndex) { m_requestCallback->sendFailure("Could not get index"); return; } - idbRequest = idbIndex->openCursor(context(), PassRefPtr<IDBKeyRange>(m_idbKeyRange), ec); - } else - idbRequest = idbObjectStore->openCursor(context(), PassRefPtr<IDBKeyRange>(m_idbKeyRange), ec); - idbRequest->addEventListener(eventNames().successEvent, openCursorCallback, false); + if (exec) { + auto result = idbIndex->openCursor(*exec, m_idbKeyRange.get(), IDBCursorDirection::Next); + if (!result.hasException()) + idbRequest = result.releaseReturnValue(); + } + } else { + if (exec) { + auto result = idbObjectStore->openCursor(*exec, m_idbKeyRange.get(), IDBCursorDirection::Next); + if (!result.hasException()) + idbRequest = result.releaseReturnValue(); + } + } + + if (!idbRequest) { + m_requestCallback->sendFailure("Could not open cursor to populate database data"); + return; + } + + auto openCursorCallback = OpenCursorCallback::create(m_injectedScript, m_requestCallback.copyRef(), m_skipCount, m_pageSize); + idbRequest->addEventListener(eventNames().successEvent, WTFMove(openCursorCallback), false); } - virtual RequestCallback* requestCallback() override { return m_requestCallback.get(); } - DataLoader(ScriptExecutionContext* scriptExecutionContext, PassRefPtr<RequestDataCallback> requestCallback, const InjectedScript& injectedScript, const String& objectStoreName, const String& indexName, PassRefPtr<IDBKeyRange> idbKeyRange, int skipCount, unsigned pageSize) + RequestCallback& requestCallback() override { return m_requestCallback.get(); } + DataLoader(ScriptExecutionContext* scriptExecutionContext, Ref<RequestDataCallback>&& requestCallback, const InjectedScript& injectedScript, const String& objectStoreName, const String& indexName, RefPtr<IDBKeyRange> idbKeyRange, int skipCount, unsigned pageSize) : ExecutableWithDatabase(scriptExecutionContext) - , m_requestCallback(requestCallback) + , m_requestCallback(WTFMove(requestCallback)) , m_injectedScript(injectedScript) , m_objectStoreName(objectStoreName) , m_indexName(indexName) - , m_idbKeyRange(idbKeyRange) + , m_idbKeyRange(WTFMove(idbKeyRange)) , m_skipCount(skipCount) , m_pageSize(pageSize) { } - RefPtr<RequestDataCallback> m_requestCallback; + Ref<RequestDataCallback> m_requestCallback; InjectedScript m_injectedScript; String m_objectStoreName; String m_indexName; @@ -558,9 +513,10 @@ public: } // namespace -InspectorIndexedDBAgent::InspectorIndexedDBAgent(InstrumentingAgents* instrumentingAgents, InjectedScriptManager* injectedScriptManager, InspectorPageAgent* pageAgent) - : InspectorAgentBase(ASCIILiteral("IndexedDB"), instrumentingAgents) - , m_injectedScriptManager(injectedScriptManager) +InspectorIndexedDBAgent::InspectorIndexedDBAgent(WebAgentContext& context, InspectorPageAgent* pageAgent) + : InspectorAgentBase(ASCIILiteral("IndexedDB"), context) + , m_injectedScriptManager(context.injectedScriptManager) + , m_backendDispatcher(Inspector::IndexedDBBackendDispatcher::create(context.backendDispatcher, this)) , m_pageAgent(pageAgent) { } @@ -569,122 +525,129 @@ InspectorIndexedDBAgent::~InspectorIndexedDBAgent() { } -void InspectorIndexedDBAgent::didCreateFrontendAndBackend(Inspector::InspectorFrontendChannel*, InspectorBackendDispatcher* backendDispatcher) +void InspectorIndexedDBAgent::didCreateFrontendAndBackend(Inspector::FrontendRouter*, Inspector::BackendDispatcher*) { - m_backendDispatcher = InspectorIndexedDBBackendDispatcher::create(backendDispatcher, this); } -void InspectorIndexedDBAgent::willDestroyFrontendAndBackend(InspectorDisconnectReason) +void InspectorIndexedDBAgent::willDestroyFrontendAndBackend(Inspector::DisconnectReason) { - m_backendDispatcher.clear(); - - disable(nullptr); + ErrorString unused; + disable(unused); } -void InspectorIndexedDBAgent::enable(ErrorString*) +void InspectorIndexedDBAgent::enable(ErrorString&) { } -void InspectorIndexedDBAgent::disable(ErrorString*) +void InspectorIndexedDBAgent::disable(ErrorString&) { } -static Document* assertDocument(ErrorString* errorString, Frame* frame) +static Document* assertDocument(ErrorString& errorString, Frame* frame) { Document* document = frame ? frame->document() : nullptr; - if (!document) - *errorString = "No document for given frame found"; - + errorString = ASCIILiteral("No document for given frame found"); return document; } -static IDBFactory* assertIDBFactory(ErrorString* errorString, Document* document) +static IDBFactory* assertIDBFactory(ErrorString& errorString, Document* document) { DOMWindow* domWindow = document->domWindow(); if (!domWindow) { - *errorString = "No IndexedDB factory for given frame found"; + errorString = ASCIILiteral("No IndexedDB factory for given frame found"); return nullptr; } - IDBFactory* idbFactory = DOMWindowIndexedDatabase::indexedDB(domWindow); + IDBFactory* idbFactory = DOMWindowIndexedDatabase::indexedDB(*domWindow); if (!idbFactory) - *errorString = "No IndexedDB factory for given frame found"; + errorString = ASCIILiteral("No IndexedDB factory for given frame found"); return idbFactory; } -void InspectorIndexedDBAgent::requestDatabaseNames(ErrorString* errorString, const String& securityOrigin, PassRefPtr<RequestDatabaseNamesCallback> requestCallback) +void InspectorIndexedDBAgent::requestDatabaseNames(ErrorString& errorString, const String& securityOrigin, Ref<RequestDatabaseNamesCallback>&& requestCallback) { Frame* frame = m_pageAgent->findFrameWithSecurityOrigin(securityOrigin); Document* document = assertDocument(errorString, frame); if (!document) return; + + auto& openingOrigin = document->securityOrigin(); + + auto& topOrigin = document->topOrigin(); + IDBFactory* idbFactory = assertIDBFactory(errorString, document); if (!idbFactory) return; - ExceptionCode ec = 0; - RefPtr<IDBRequest> idbRequest = idbFactory->getDatabaseNames(document, ec); - if (ec) { - requestCallback->sendFailure("Could not obtain database names."); - return; - } - idbRequest->addEventListener(eventNames().successEvent, GetDatabaseNamesCallback::create(requestCallback, document->securityOrigin()->toRawString()), false); + RefPtr<RequestDatabaseNamesCallback> callback = WTFMove(requestCallback); + idbFactory->getAllDatabaseNames(topOrigin, openingOrigin, [callback](auto& databaseNames) { + if (!callback->isActive()) + return; + + Ref<Inspector::Protocol::Array<String>> databaseNameArray = Inspector::Protocol::Array<String>::create(); + for (auto& databaseName : databaseNames) + databaseNameArray->addItem(databaseName); + + callback->sendSuccess(WTFMove(databaseNameArray)); + }); } -void InspectorIndexedDBAgent::requestDatabase(ErrorString* errorString, const String& securityOrigin, const String& databaseName, PassRefPtr<RequestDatabaseCallback> requestCallback) +void InspectorIndexedDBAgent::requestDatabase(ErrorString& errorString, const String& securityOrigin, const String& databaseName, Ref<RequestDatabaseCallback>&& requestCallback) { Frame* frame = m_pageAgent->findFrameWithSecurityOrigin(securityOrigin); Document* document = assertDocument(errorString, frame); if (!document) return; + IDBFactory* idbFactory = assertIDBFactory(errorString, document); if (!idbFactory) return; - RefPtr<DatabaseLoader> databaseLoader = DatabaseLoader::create(document, requestCallback); - databaseLoader->start(idbFactory, document->securityOrigin(), databaseName); + Ref<DatabaseLoader> databaseLoader = DatabaseLoader::create(document, WTFMove(requestCallback)); + databaseLoader->start(idbFactory, &document->securityOrigin(), databaseName); } -void InspectorIndexedDBAgent::requestData(ErrorString* errorString, const String& securityOrigin, const String& databaseName, const String& objectStoreName, const String& indexName, int skipCount, int pageSize, const RefPtr<InspectorObject>* keyRange, PassRefPtr<RequestDataCallback> requestCallback) +void InspectorIndexedDBAgent::requestData(ErrorString& errorString, const String& securityOrigin, const String& databaseName, const String& objectStoreName, const String& indexName, int skipCount, int pageSize, const InspectorObject* keyRange, Ref<RequestDataCallback>&& requestCallback) { Frame* frame = m_pageAgent->findFrameWithSecurityOrigin(securityOrigin); Document* document = assertDocument(errorString, frame); if (!document) return; + IDBFactory* idbFactory = assertIDBFactory(errorString, document); if (!idbFactory) return; - InjectedScript injectedScript = m_injectedScriptManager->injectedScriptFor(mainWorldExecState(frame)); + InjectedScript injectedScript = m_injectedScriptManager.injectedScriptFor(mainWorldExecState(frame)); - RefPtr<IDBKeyRange> idbKeyRange = keyRange ? idbKeyRangeFromKeyRange(keyRange->get()) : nullptr; + RefPtr<IDBKeyRange> idbKeyRange = keyRange ? idbKeyRangeFromKeyRange(keyRange) : nullptr; if (keyRange && !idbKeyRange) { - *errorString = "Can not parse key range."; + errorString = ASCIILiteral("Can not parse key range."); return; } - RefPtr<DataLoader> dataLoader = DataLoader::create(document, requestCallback, injectedScript, objectStoreName, indexName, idbKeyRange, skipCount, pageSize); - dataLoader->start(idbFactory, document->securityOrigin(), databaseName); + Ref<DataLoader> dataLoader = DataLoader::create(document, WTFMove(requestCallback), injectedScript, objectStoreName, indexName, WTFMove(idbKeyRange), skipCount, pageSize); + dataLoader->start(idbFactory, &document->securityOrigin(), databaseName); } -class ClearObjectStoreListener : public EventListener { +class ClearObjectStoreListener final : public EventListener { WTF_MAKE_NONCOPYABLE(ClearObjectStoreListener); public: - static PassRefPtr<ClearObjectStoreListener> create(PassRefPtr<ClearObjectStoreCallback> requestCallback) + static Ref<ClearObjectStoreListener> create(Ref<ClearObjectStoreCallback> requestCallback) { - return adoptRef(new ClearObjectStoreListener(requestCallback)); + return adoptRef(*new ClearObjectStoreListener(WTFMove(requestCallback))); } virtual ~ClearObjectStoreListener() { } - virtual bool operator==(const EventListener& other) override + bool operator==(const EventListener& other) const override { return this == &other; } - virtual void handleEvent(ScriptExecutionContext*, Event* event) override + void handleEvent(ScriptExecutionContext*, Event* event) override { if (!m_requestCallback->isActive()) return; @@ -696,63 +659,68 @@ public: m_requestCallback->sendSuccess(); } private: - ClearObjectStoreListener(PassRefPtr<ClearObjectStoreCallback> requestCallback) + ClearObjectStoreListener(Ref<ClearObjectStoreCallback>&& requestCallback) : EventListener(EventListener::CPPEventListenerType) - , m_requestCallback(requestCallback) + , m_requestCallback(WTFMove(requestCallback)) { } - RefPtr<ClearObjectStoreCallback> m_requestCallback; + Ref<ClearObjectStoreCallback> m_requestCallback; }; - -class ClearObjectStore : public ExecutableWithDatabase { +class ClearObjectStore final : public ExecutableWithDatabase { public: - static PassRefPtr<ClearObjectStore> create(ScriptExecutionContext* context, const String& objectStoreName, PassRefPtr<ClearObjectStoreCallback> requestCallback) + static Ref<ClearObjectStore> create(ScriptExecutionContext* context, const String& objectStoreName, Ref<ClearObjectStoreCallback>&& requestCallback) { - return adoptRef(new ClearObjectStore(context, objectStoreName, requestCallback)); + return adoptRef(*new ClearObjectStore(context, objectStoreName, WTFMove(requestCallback))); } - ClearObjectStore(ScriptExecutionContext* context, const String& objectStoreName, PassRefPtr<ClearObjectStoreCallback> requestCallback) + ClearObjectStore(ScriptExecutionContext* context, const String& objectStoreName, Ref<ClearObjectStoreCallback>&& requestCallback) : ExecutableWithDatabase(context) , m_objectStoreName(objectStoreName) - , m_requestCallback(requestCallback) + , m_requestCallback(WTFMove(requestCallback)) { } - virtual void execute(PassRefPtr<IDBDatabase> prpDatabase) override + void execute(IDBDatabase& database) override { - RefPtr<IDBDatabase> idbDatabase = prpDatabase; - if (!requestCallback()->isActive()) + if (!requestCallback().isActive()) return; - RefPtr<IDBTransaction> idbTransaction = transactionForDatabase(context(), idbDatabase.get(), m_objectStoreName, IDBTransaction::modeReadWrite()); + + auto idbTransaction = transactionForDatabase(&database, m_objectStoreName, IDBTransactionMode::Readwrite); if (!idbTransaction) { m_requestCallback->sendFailure("Could not get transaction"); return; } - RefPtr<IDBObjectStore> idbObjectStore = objectStoreForTransaction(idbTransaction.get(), m_objectStoreName); + + auto idbObjectStore = objectStoreForTransaction(idbTransaction.get(), m_objectStoreName); if (!idbObjectStore) { m_requestCallback->sendFailure("Could not get object store"); return; } - ExceptionCode ec = 0; - RefPtr<IDBRequest> idbRequest = idbObjectStore->clear(context(), ec); - ASSERT(!ec); - if (ec) { - m_requestCallback->sendFailure(String::format("Could not clear object store '%s': %d", m_objectStoreName.utf8().data(), ec)); - return; + TransactionActivator activator(idbTransaction.get()); + RefPtr<IDBRequest> idbRequest; + if (auto* exec = context() ? context()->execState() : nullptr) { + auto result = idbObjectStore->clear(*exec); + ASSERT(!result.hasException()); + if (result.hasException()) { + m_requestCallback->sendFailure(String::format("Could not clear object store '%s': %d", m_objectStoreName.utf8().data(), result.releaseException().code())); + return; + } + idbRequest = result.releaseReturnValue(); } - idbTransaction->addEventListener(eventNames().completeEvent, ClearObjectStoreListener::create(m_requestCallback), false); + + idbTransaction->addEventListener(eventNames().completeEvent, ClearObjectStoreListener::create(m_requestCallback.copyRef()), false); } - virtual RequestCallback* requestCallback() override { return m_requestCallback.get(); } + RequestCallback& requestCallback() override { return m_requestCallback.get(); } private: const String m_objectStoreName; - RefPtr<ClearObjectStoreCallback> m_requestCallback; + Ref<ClearObjectStoreCallback> m_requestCallback; }; -void InspectorIndexedDBAgent::clearObjectStore(ErrorString* errorString, const String& securityOrigin, const String& databaseName, const String& objectStoreName, PassRefPtr<ClearObjectStoreCallback> requestCallback) +void InspectorIndexedDBAgent::clearObjectStore(ErrorString& errorString, const String& securityOrigin, const String& databaseName, const String& objectStoreName, Ref<ClearObjectStoreCallback>&& requestCallback) { Frame* frame = m_pageAgent->findFrameWithSecurityOrigin(securityOrigin); Document* document = assertDocument(errorString, frame); @@ -762,10 +730,9 @@ void InspectorIndexedDBAgent::clearObjectStore(ErrorString* errorString, const S if (!idbFactory) return; - RefPtr<ClearObjectStore> clearObjectStore = ClearObjectStore::create(document, objectStoreName, requestCallback); - clearObjectStore->start(idbFactory, document->securityOrigin(), databaseName); + Ref<ClearObjectStore> clearObjectStore = ClearObjectStore::create(document, objectStoreName, WTFMove(requestCallback)); + clearObjectStore->start(idbFactory, &document->securityOrigin(), databaseName); } } // namespace WebCore - -#endif // ENABLE(INSPECTOR) && ENABLE(INDEXED_DATABASE) +#endif // ENABLE(INDEXED_DATABASE) |