9fdf90b069f155adb7c733a5f95dfad7161b20ae
[WebKit-https.git] / Source / WebCore / inspector / agents / InspectorIndexedDBAgent.cpp
1 /*
2  * Copyright (C) 2012 Google Inc. All rights reserved.
3  * Copyright (C) 2015-2017 Apple Inc. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  *     * Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  *     * Redistributions in binary form must reproduce the above
12  * copyright notice, this list of conditions and the following disclaimer
13  * in the documentation and/or other materials provided with the
14  * distribution.
15  *     * Neither the name of Google Inc. nor the names of its
16  * contributors may be used to endorse or promote products derived from
17  * this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31
32 #include "config.h"
33 #include "InspectorIndexedDBAgent.h"
34
35 #if ENABLE(INDEXED_DATABASE)
36
37 #include "DOMStringList.h"
38 #include "DOMWindow.h"
39 #include "DOMWindowIndexedDatabase.h"
40 #include "Document.h"
41 #include "Event.h"
42 #include "EventListener.h"
43 #include "EventNames.h"
44 #include "EventTarget.h"
45 #include "Frame.h"
46 #include "IDBBindingUtilities.h"
47 #include "IDBCursor.h"
48 #include "IDBCursorWithValue.h"
49 #include "IDBDatabase.h"
50 #include "IDBFactory.h"
51 #include "IDBIndex.h"
52 #include "IDBKey.h"
53 #include "IDBKeyPath.h"
54 #include "IDBKeyRange.h"
55 #include "IDBObjectStore.h"
56 #include "IDBOpenDBRequest.h"
57 #include "IDBRequest.h"
58 #include "IDBTransaction.h"
59 #include "InspectorPageAgent.h"
60 #include "InstrumentingAgents.h"
61 #include "ScriptState.h"
62 #include "SecurityOrigin.h"
63 #include <JavaScriptCore/HeapInlines.h>
64 #include <JavaScriptCore/InjectedScript.h>
65 #include <JavaScriptCore/InjectedScriptManager.h>
66 #include <JavaScriptCore/InspectorFrontendDispatchers.h>
67 #include <JavaScriptCore/InspectorFrontendRouter.h>
68 #include <wtf/JSONValues.h>
69 #include <wtf/NeverDestroyed.h>
70 #include <wtf/Vector.h>
71 #include <wtf/text/StringConcatenateNumbers.h>
72
73 using JSON::ArrayOf;
74 using Inspector::Protocol::IndexedDB::DatabaseWithObjectStores;
75 using Inspector::Protocol::IndexedDB::DataEntry;
76 using Inspector::Protocol::IndexedDB::Key;
77 using Inspector::Protocol::IndexedDB::KeyPath;
78 using Inspector::Protocol::IndexedDB::KeyRange;
79 using Inspector::Protocol::IndexedDB::ObjectStore;
80 using Inspector::Protocol::IndexedDB::ObjectStoreIndex;
81
82 typedef Inspector::BackendDispatcher::CallbackBase RequestCallback;
83 typedef Inspector::IndexedDBBackendDispatcherHandler::RequestDatabaseNamesCallback RequestDatabaseNamesCallback;
84 typedef Inspector::IndexedDBBackendDispatcherHandler::RequestDatabaseCallback RequestDatabaseCallback;
85 typedef Inspector::IndexedDBBackendDispatcherHandler::RequestDataCallback RequestDataCallback;
86 typedef Inspector::IndexedDBBackendDispatcherHandler::ClearObjectStoreCallback ClearObjectStoreCallback;
87
88 typedef String ErrorString;
89
90 template <typename T>
91 using ErrorStringOr = Expected<T, ErrorString>;
92
93 namespace WebCore {
94
95 using namespace Inspector;
96
97 namespace {
98
99 class ExecutableWithDatabase : public RefCounted<ExecutableWithDatabase> {
100 public:
101     ExecutableWithDatabase(ScriptExecutionContext* context)
102         : m_context(context) { }
103     virtual ~ExecutableWithDatabase() = default;
104     void start(IDBFactory*, SecurityOrigin*, const String& databaseName);
105     virtual void execute(IDBDatabase&) = 0;
106     virtual RequestCallback& requestCallback() = 0;
107     ScriptExecutionContext* context() const { return m_context; }
108 private:
109     ScriptExecutionContext* m_context;
110 };
111
112 class OpenDatabaseCallback final : public EventListener {
113 public:
114     static Ref<OpenDatabaseCallback> create(ExecutableWithDatabase& executableWithDatabase)
115     {
116         return adoptRef(*new OpenDatabaseCallback(executableWithDatabase));
117     }
118
119     bool operator==(const EventListener& other) const final
120     {
121         return this == &other;
122     }
123
124     void handleEvent(ScriptExecutionContext&, Event& event) final
125     {
126         if (event.type() != eventNames().successEvent) {
127             m_executableWithDatabase->requestCallback().sendFailure("Unexpected event type.");
128             return;
129         }
130
131         auto& request = static_cast<IDBOpenDBRequest&>(*event.target());
132
133         auto result = request.result();
134         if (result.hasException()) {
135             m_executableWithDatabase->requestCallback().sendFailure("Could not get result in callback.");
136             return;
137         }
138
139         auto resultValue = result.releaseReturnValue();
140         if (!WTF::holds_alternative<RefPtr<IDBDatabase>>(resultValue)) {
141             m_executableWithDatabase->requestCallback().sendFailure("Unexpected result type.");
142             return;
143         }
144
145         auto databaseResult = WTF::get<RefPtr<IDBDatabase>>(resultValue);
146         m_executableWithDatabase->execute(*databaseResult);
147         databaseResult->close();
148     }
149
150 private:
151     OpenDatabaseCallback(ExecutableWithDatabase& executableWithDatabase)
152         : EventListener(EventListener::CPPEventListenerType)
153         , m_executableWithDatabase(executableWithDatabase) { }
154     Ref<ExecutableWithDatabase> m_executableWithDatabase;
155 };
156
157 void ExecutableWithDatabase::start(IDBFactory* idbFactory, SecurityOrigin*, const String& databaseName)
158 {
159     if (!context()) {
160         requestCallback().sendFailure("Could not open database.");
161         return;
162     }
163
164     auto result = idbFactory->open(*context(), databaseName, WTF::nullopt);
165     if (result.hasException()) {
166         requestCallback().sendFailure("Could not open database.");
167         return;
168     }
169
170     result.releaseReturnValue()->addEventListener(eventNames().successEvent, OpenDatabaseCallback::create(*this), false);
171 }
172
173
174 static RefPtr<KeyPath> keyPathFromIDBKeyPath(const Optional<IDBKeyPath>& idbKeyPath)
175 {
176     if (!idbKeyPath)
177         return KeyPath::create().setType(KeyPath::Type::Null).release();
178
179     auto visitor = WTF::makeVisitor([](const String& string) {
180         auto keyPath = KeyPath::create().setType(KeyPath::Type::String).release();
181         keyPath->setString(string);
182         return keyPath;
183     }, [](const Vector<String>& vector) {
184         auto array = JSON::ArrayOf<String>::create();
185         for (auto& string : vector)
186             array->addItem(string);
187         auto keyPath = KeyPath::create().setType(KeyPath::Type::Array).release();
188         keyPath->setArray(WTFMove(array));
189         return keyPath;
190     });
191     return WTF::visit(visitor, idbKeyPath.value());
192 }
193
194 static RefPtr<IDBTransaction> transactionForDatabase(IDBDatabase* idbDatabase, const String& objectStoreName, IDBTransactionMode mode = IDBTransactionMode::Readonly)
195 {
196     auto result = idbDatabase->transaction(objectStoreName, mode);
197     if (result.hasException())
198         return nullptr;
199     return result.releaseReturnValue();
200 }
201
202 static RefPtr<IDBObjectStore> objectStoreForTransaction(IDBTransaction* idbTransaction, const String& objectStoreName)
203 {
204     auto result = idbTransaction->objectStore(objectStoreName);
205     if (result.hasException())
206         return nullptr;
207     return result.releaseReturnValue();
208 }
209
210 static RefPtr<IDBIndex> indexForObjectStore(IDBObjectStore* idbObjectStore, const String& indexName)
211 {
212     auto index = idbObjectStore->index(indexName);
213     if (index.hasException())
214         return nullptr;
215     return index.releaseReturnValue();
216 }
217
218 class DatabaseLoader final : public ExecutableWithDatabase {
219 public:
220     static Ref<DatabaseLoader> create(ScriptExecutionContext* context, Ref<RequestDatabaseCallback>&& requestCallback)
221     {
222         return adoptRef(*new DatabaseLoader(context, WTFMove(requestCallback)));
223     }
224
225     virtual ~DatabaseLoader() = default;
226
227     void execute(IDBDatabase& database) override
228     {
229         if (!requestCallback().isActive())
230             return;
231     
232         auto& databaseInfo = database.info();
233         auto objectStores = JSON::ArrayOf<Inspector::Protocol::IndexedDB::ObjectStore>::create();
234         auto objectStoreNames = databaseInfo.objectStoreNames();
235         for (auto& name : objectStoreNames) {
236             auto* objectStoreInfo = databaseInfo.infoForExistingObjectStore(name);
237             if (!objectStoreInfo)
238                 continue;
239
240             auto indexes = JSON::ArrayOf<Inspector::Protocol::IndexedDB::ObjectStoreIndex>::create();
241     
242             for (auto& indexInfo : objectStoreInfo->indexMap().values()) {
243                 auto objectStoreIndex = ObjectStoreIndex::create()
244                     .setName(indexInfo.name())
245                     .setKeyPath(keyPathFromIDBKeyPath(indexInfo.keyPath()))
246                     .setUnique(indexInfo.unique())
247                     .setMultiEntry(indexInfo.multiEntry())
248                     .release();
249                 indexes->addItem(WTFMove(objectStoreIndex));
250             }
251     
252             auto objectStore = ObjectStore::create()
253                 .setName(objectStoreInfo->name())
254                 .setKeyPath(keyPathFromIDBKeyPath(objectStoreInfo->keyPath()))
255                 .setAutoIncrement(objectStoreInfo->autoIncrement())
256                 .setIndexes(WTFMove(indexes))
257                 .release();
258             objectStores->addItem(WTFMove(objectStore));
259         }
260     
261         auto result = DatabaseWithObjectStores::create()
262             .setName(databaseInfo.name())
263             .setVersion(databaseInfo.version())
264             .setObjectStores(WTFMove(objectStores))
265             .release();
266         m_requestCallback->sendSuccess(WTFMove(result));
267     }
268
269     RequestCallback& requestCallback() override { return m_requestCallback.get(); }
270 private:
271     DatabaseLoader(ScriptExecutionContext* context, Ref<RequestDatabaseCallback>&& requestCallback)
272         : ExecutableWithDatabase(context)
273         , m_requestCallback(WTFMove(requestCallback)) { }
274     Ref<RequestDatabaseCallback> m_requestCallback;
275 };
276
277 static RefPtr<IDBKey> idbKeyFromInspectorObject(JSON::Object* key)
278 {
279     String type;
280     if (!key->getString("type", type))
281         return nullptr;
282
283     static NeverDestroyed<const String> numberType(MAKE_STATIC_STRING_IMPL("number"));
284     static NeverDestroyed<const String> stringType(MAKE_STATIC_STRING_IMPL("string"));
285     static NeverDestroyed<const String> dateType(MAKE_STATIC_STRING_IMPL("date"));
286     static NeverDestroyed<const String> arrayType(MAKE_STATIC_STRING_IMPL("array"));
287
288     RefPtr<IDBKey> idbKey;
289     if (type == numberType) {
290         double number;
291         if (!key->getDouble("number", number))
292             return nullptr;
293         idbKey = IDBKey::createNumber(number);
294     } else if (type == stringType) {
295         String string;
296         if (!key->getString("string", string))
297             return nullptr;
298         idbKey = IDBKey::createString(string);
299     } else if (type == dateType) {
300         double date;
301         if (!key->getDouble("date", date))
302             return nullptr;
303         idbKey = IDBKey::createDate(date);
304     } else if (type == arrayType) {
305         Vector<RefPtr<IDBKey>> keyArray;
306         RefPtr<JSON::Array> array;
307         if (!key->getArray("array", array))
308             return nullptr;
309         for (size_t i = 0; i < array->length(); ++i) {
310             RefPtr<JSON::Value> value = array->get(i);
311             RefPtr<JSON::Object> object;
312             if (!value->asObject(object))
313                 return nullptr;
314             keyArray.append(idbKeyFromInspectorObject(object.get()));
315         }
316         idbKey = IDBKey::createArray(keyArray);
317     } else
318         return nullptr;
319
320     return idbKey;
321 }
322
323 static RefPtr<IDBKeyRange> idbKeyRangeFromKeyRange(const JSON::Object* keyRange)
324 {
325     RefPtr<IDBKey> idbLower;
326     RefPtr<JSON::Object> lower;
327     if (keyRange->getObject("lower"_s, lower)) {
328         idbLower = idbKeyFromInspectorObject(lower.get());
329         if (!idbLower)
330             return nullptr;
331     }
332
333     RefPtr<IDBKey> idbUpper;
334     RefPtr<JSON::Object> upper;
335     if (keyRange->getObject("upper"_s, upper)) {
336         idbUpper = idbKeyFromInspectorObject(upper.get());
337         if (!idbUpper)
338             return nullptr;
339     }
340
341     bool lowerOpen;
342     if (!keyRange->getBoolean("lowerOpen"_s, lowerOpen))
343         return nullptr;
344
345     bool upperOpen;
346     if (!keyRange->getBoolean("upperOpen"_s, upperOpen))
347         return nullptr;
348
349     return IDBKeyRange::create(WTFMove(idbLower), WTFMove(idbUpper), lowerOpen, upperOpen);
350 }
351
352 class OpenCursorCallback final : public EventListener {
353 public:
354     static Ref<OpenCursorCallback> create(InjectedScript injectedScript, Ref<RequestDataCallback>&& requestCallback, int skipCount, unsigned pageSize)
355     {
356         return adoptRef(*new OpenCursorCallback(injectedScript, WTFMove(requestCallback), skipCount, pageSize));
357     }
358
359     virtual ~OpenCursorCallback() = default;
360
361     bool operator==(const EventListener& other) const override
362     {
363         return this == &other;
364     }
365
366     void handleEvent(ScriptExecutionContext& context, Event& event) override
367     {
368         if (event.type() != eventNames().successEvent) {
369             m_requestCallback->sendFailure("Unexpected event type.");
370             return;
371         }
372
373         auto& request = static_cast<IDBRequest&>(*event.target());
374
375         auto result = request.result();
376         if (result.hasException()) {
377             m_requestCallback->sendFailure("Could not get result in callback.");
378             return;
379         }
380         
381         auto resultValue = result.releaseReturnValue();
382         if (!WTF::holds_alternative<RefPtr<IDBCursor>>(resultValue)) {
383             end(false);
384             return;
385         }
386
387         auto cursor = WTF::get<RefPtr<IDBCursor>>(resultValue);
388
389         if (m_skipCount) {
390             if (cursor->advance(m_skipCount).hasException())
391                 m_requestCallback->sendFailure("Could not advance cursor.");
392             m_skipCount = 0;
393             return;
394         }
395
396         if (m_result->length() == m_pageSize) {
397             end(true);
398             return;
399         }
400
401         // Continue cursor before making injected script calls, otherwise transaction might be finished.
402         if (cursor->continueFunction(nullptr).hasException()) {
403             m_requestCallback->sendFailure("Could not continue cursor.");
404             return;
405         }
406
407         auto* state = context.execState();
408         auto key =  toJS(*state, *state->lexicalGlobalObject(), cursor->key());
409         auto primaryKey = toJS(*state, *state->lexicalGlobalObject(), cursor->primaryKey());
410         auto value = deserializeIDBValueToJSValue(*state, cursor->value());
411         auto dataEntry = DataEntry::create()
412             .setKey(m_injectedScript.wrapObject(key, String(), true))
413             .setPrimaryKey(m_injectedScript.wrapObject(primaryKey, String(), true))
414             .setValue(m_injectedScript.wrapObject(value, String(), true))
415             .release();
416         m_result->addItem(WTFMove(dataEntry));
417     }
418
419     void end(bool hasMore)
420     {
421         if (!m_requestCallback->isActive())
422             return;
423         m_requestCallback->sendSuccess(WTFMove(m_result), hasMore);
424     }
425
426 private:
427     OpenCursorCallback(InjectedScript injectedScript, Ref<RequestDataCallback>&& requestCallback, int skipCount, unsigned pageSize)
428         : EventListener(EventListener::CPPEventListenerType)
429         , m_injectedScript(injectedScript)
430         , m_requestCallback(WTFMove(requestCallback))
431         , m_result(JSON::ArrayOf<DataEntry>::create())
432         , m_skipCount(skipCount)
433         , m_pageSize(pageSize)
434     {
435     }
436     InjectedScript m_injectedScript;
437     Ref<RequestDataCallback> m_requestCallback;
438     Ref<JSON::ArrayOf<DataEntry>> m_result;
439     int m_skipCount;
440     unsigned m_pageSize;
441 };
442
443 class DataLoader final : public ExecutableWithDatabase {
444 public:
445     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)
446     {
447         return adoptRef(*new DataLoader(context, WTFMove(requestCallback), injectedScript, objectStoreName, indexName, WTFMove(idbKeyRange), skipCount, pageSize));
448     }
449
450     virtual ~DataLoader() = default;
451
452     void execute(IDBDatabase& database) override
453     {
454         if (!requestCallback().isActive())
455             return;
456
457         auto idbTransaction = transactionForDatabase(&database, m_objectStoreName);
458         if (!idbTransaction) {
459             m_requestCallback->sendFailure("Could not get transaction");
460             return;
461         }
462
463         auto idbObjectStore = objectStoreForTransaction(idbTransaction.get(), m_objectStoreName);
464         if (!idbObjectStore) {
465             m_requestCallback->sendFailure("Could not get object store");
466             return;
467         }
468
469         TransactionActivator activator(idbTransaction.get());
470         RefPtr<IDBRequest> idbRequest;
471         auto* exec = context() ? context()->execState() : nullptr;
472         if (!m_indexName.isEmpty()) {
473             auto idbIndex = indexForObjectStore(idbObjectStore.get(), m_indexName);
474             if (!idbIndex) {
475                 m_requestCallback->sendFailure("Could not get index");
476                 return;
477             }
478
479             if (exec) {
480                 auto result = idbIndex->openCursor(*exec, m_idbKeyRange.get(), IDBCursorDirection::Next);
481                 if (!result.hasException())
482                     idbRequest = result.releaseReturnValue();
483             }
484         } else {
485             if (exec) {
486                 auto result = idbObjectStore->openCursor(*exec, m_idbKeyRange.get(), IDBCursorDirection::Next);
487                 if (!result.hasException())
488                     idbRequest = result.releaseReturnValue();
489             }
490         }
491
492         if (!idbRequest) {
493             m_requestCallback->sendFailure("Could not open cursor to populate database data");
494             return;
495         }
496
497         auto openCursorCallback = OpenCursorCallback::create(m_injectedScript, m_requestCallback.copyRef(), m_skipCount, m_pageSize);
498         idbRequest->addEventListener(eventNames().successEvent, WTFMove(openCursorCallback), false);
499     }
500
501     RequestCallback& requestCallback() override { return m_requestCallback.get(); }
502     DataLoader(ScriptExecutionContext* scriptExecutionContext, Ref<RequestDataCallback>&& requestCallback, const InjectedScript& injectedScript, const String& objectStoreName, const String& indexName, RefPtr<IDBKeyRange> idbKeyRange, int skipCount, unsigned pageSize)
503         : ExecutableWithDatabase(scriptExecutionContext)
504         , m_requestCallback(WTFMove(requestCallback))
505         , m_injectedScript(injectedScript)
506         , m_objectStoreName(objectStoreName)
507         , m_indexName(indexName)
508         , m_idbKeyRange(WTFMove(idbKeyRange))
509         , m_skipCount(skipCount)
510         , m_pageSize(pageSize) { }
511     Ref<RequestDataCallback> m_requestCallback;
512     InjectedScript m_injectedScript;
513     String m_objectStoreName;
514     String m_indexName;
515     RefPtr<IDBKeyRange> m_idbKeyRange;
516     int m_skipCount;
517     unsigned m_pageSize;
518 };
519
520 } // namespace
521
522 InspectorIndexedDBAgent::InspectorIndexedDBAgent(PageAgentContext& context)
523     : InspectorAgentBase("IndexedDB"_s, context)
524     , m_injectedScriptManager(context.injectedScriptManager)
525     , m_backendDispatcher(Inspector::IndexedDBBackendDispatcher::create(context.backendDispatcher, this))
526     , m_inspectedPage(context.inspectedPage)
527 {
528 }
529
530 InspectorIndexedDBAgent::~InspectorIndexedDBAgent() = default;
531
532 void InspectorIndexedDBAgent::didCreateFrontendAndBackend(Inspector::FrontendRouter*, Inspector::BackendDispatcher*)
533 {
534 }
535
536 void InspectorIndexedDBAgent::willDestroyFrontendAndBackend(Inspector::DisconnectReason)
537 {
538     ErrorString ignored;
539     disable(ignored);
540 }
541
542 void InspectorIndexedDBAgent::enable(ErrorString&)
543 {
544 }
545
546 void InspectorIndexedDBAgent::disable(ErrorString&)
547 {
548 }
549
550 static ErrorStringOr<Document*> documentFromFrame(Frame* frame)
551 {
552     Document* document = frame ? frame->document() : nullptr;
553     if (!document)
554         return makeUnexpected("Missing document for given frame"_s);
555     
556     return document;
557 }
558
559 static ErrorStringOr<IDBFactory*> IDBFactoryFromDocument(Document* document)
560 {
561     DOMWindow* domWindow = document->domWindow();
562     if (!domWindow)
563         return makeUnexpected("Missing window for given document"_s);
564
565     IDBFactory* idbFactory = DOMWindowIndexedDatabase::indexedDB(*domWindow);
566     if (!idbFactory)
567         makeUnexpected("Missing IndexedDB factory of window for given document"_s);
568     
569     return idbFactory;
570 }
571
572 static bool getDocumentAndIDBFactoryFromFrameOrSendFailure(Frame* frame, Document*& out_document, IDBFactory*& out_idbFactory, BackendDispatcher::CallbackBase& callback)
573 {
574     ErrorStringOr<Document*> document = documentFromFrame(frame);
575     if (!document.has_value()) {
576         callback.sendFailure(document.error());
577         return false;
578     }
579
580     ErrorStringOr<IDBFactory*> idbFactory = IDBFactoryFromDocument(document.value());
581     if (!idbFactory.has_value()) {
582         callback.sendFailure(idbFactory.error());
583         return false;
584     }
585     
586     out_document = document.value();
587     out_idbFactory = idbFactory.value();
588     return true;
589 }
590     
591 void InspectorIndexedDBAgent::requestDatabaseNames(const String& securityOrigin, Ref<RequestDatabaseNamesCallback>&& callback)
592 {
593     auto* frame = InspectorPageAgent::findFrameWithSecurityOrigin(m_inspectedPage, securityOrigin);
594     Document* document;
595     IDBFactory* idbFactory;
596     if (!getDocumentAndIDBFactoryFromFrameOrSendFailure(frame, document, idbFactory, callback))
597         return;
598
599     auto& openingOrigin = document->securityOrigin();
600     auto& topOrigin = document->topOrigin();
601     idbFactory->getAllDatabaseNames(topOrigin, openingOrigin, [callback = WTFMove(callback)](auto& databaseNames) {
602         if (!callback->isActive())
603             return;
604
605         Ref<JSON::ArrayOf<String>> databaseNameArray = JSON::ArrayOf<String>::create();
606         for (auto& databaseName : databaseNames)
607             databaseNameArray->addItem(databaseName);
608
609         callback->sendSuccess(WTFMove(databaseNameArray));
610     });
611 }
612
613 void InspectorIndexedDBAgent::requestDatabase(const String& securityOrigin, const String& databaseName, Ref<RequestDatabaseCallback>&& callback)
614 {
615     auto* frame = InspectorPageAgent::findFrameWithSecurityOrigin(m_inspectedPage, securityOrigin);
616     Document* document;
617     IDBFactory* idbFactory;
618     if (!getDocumentAndIDBFactoryFromFrameOrSendFailure(frame, document, idbFactory, callback))
619         return;
620
621     Ref<DatabaseLoader> databaseLoader = DatabaseLoader::create(document, WTFMove(callback));
622     databaseLoader->start(idbFactory, &document->securityOrigin(), databaseName);
623 }
624
625 void InspectorIndexedDBAgent::requestData(const String& securityOrigin, const String& databaseName, const String& objectStoreName, const String& indexName, int skipCount, int pageSize, const JSON::Object* keyRange, Ref<RequestDataCallback>&& callback)
626 {
627     auto* frame = InspectorPageAgent::findFrameWithSecurityOrigin(m_inspectedPage, securityOrigin);
628     Document* document;
629     IDBFactory* idbFactory;
630     if (!getDocumentAndIDBFactoryFromFrameOrSendFailure(frame, document, idbFactory, callback))
631         return;
632
633     InjectedScript injectedScript = m_injectedScriptManager.injectedScriptFor(mainWorldExecState(frame));
634     RefPtr<IDBKeyRange> idbKeyRange = keyRange ? idbKeyRangeFromKeyRange(keyRange) : nullptr;
635     if (keyRange && !idbKeyRange) {
636         callback->sendFailure("Could not parse key range."_s);
637         return;
638     }
639
640     Ref<DataLoader> dataLoader = DataLoader::create(document, WTFMove(callback), injectedScript, objectStoreName, indexName, WTFMove(idbKeyRange), skipCount, pageSize);
641     dataLoader->start(idbFactory, &document->securityOrigin(), databaseName);
642 }
643
644 namespace {
645
646 class ClearObjectStoreListener final : public EventListener {
647     WTF_MAKE_NONCOPYABLE(ClearObjectStoreListener);
648 public:
649     static Ref<ClearObjectStoreListener> create(Ref<ClearObjectStoreCallback> requestCallback)
650     {
651         return adoptRef(*new ClearObjectStoreListener(WTFMove(requestCallback)));
652     }
653
654     virtual ~ClearObjectStoreListener() = default;
655
656     bool operator==(const EventListener& other) const override
657     {
658         return this == &other;
659     }
660
661     void handleEvent(ScriptExecutionContext&, Event& event) override
662     {
663         if (!m_requestCallback->isActive())
664             return;
665         if (event.type() != eventNames().completeEvent) {
666             m_requestCallback->sendFailure("Unexpected event type.");
667             return;
668         }
669
670         m_requestCallback->sendSuccess();
671     }
672 private:
673     ClearObjectStoreListener(Ref<ClearObjectStoreCallback>&& requestCallback)
674         : EventListener(EventListener::CPPEventListenerType)
675         , m_requestCallback(WTFMove(requestCallback))
676     {
677     }
678
679     Ref<ClearObjectStoreCallback> m_requestCallback;
680 };
681
682 class ClearObjectStore final : public ExecutableWithDatabase {
683 public:
684     static Ref<ClearObjectStore> create(ScriptExecutionContext* context, const String& objectStoreName, Ref<ClearObjectStoreCallback>&& requestCallback)
685     {
686         return adoptRef(*new ClearObjectStore(context, objectStoreName, WTFMove(requestCallback)));
687     }
688
689     ClearObjectStore(ScriptExecutionContext* context, const String& objectStoreName, Ref<ClearObjectStoreCallback>&& requestCallback)
690         : ExecutableWithDatabase(context)
691         , m_objectStoreName(objectStoreName)
692         , m_requestCallback(WTFMove(requestCallback))
693     {
694     }
695
696     void execute(IDBDatabase& database) override
697     {
698         if (!requestCallback().isActive())
699             return;
700
701         auto idbTransaction = transactionForDatabase(&database, m_objectStoreName, IDBTransactionMode::Readwrite);
702         if (!idbTransaction) {
703             m_requestCallback->sendFailure("Could not get transaction");
704             return;
705         }
706
707         auto idbObjectStore = objectStoreForTransaction(idbTransaction.get(), m_objectStoreName);
708         if (!idbObjectStore) {
709             m_requestCallback->sendFailure("Could not get object store");
710             return;
711         }
712
713         TransactionActivator activator(idbTransaction.get());
714         RefPtr<IDBRequest> idbRequest;
715         if (auto* exec = context() ? context()->execState() : nullptr) {
716             auto result = idbObjectStore->clear(*exec);
717             ASSERT(!result.hasException());
718             if (result.hasException()) {
719                 m_requestCallback->sendFailure(makeString("Could not clear object store '", m_objectStoreName, "': ", static_cast<int>(result.releaseException().code())));
720                 return;
721             }
722             idbRequest = result.releaseReturnValue();
723         }
724
725         idbTransaction->addEventListener(eventNames().completeEvent, ClearObjectStoreListener::create(m_requestCallback.copyRef()), false);
726     }
727
728     RequestCallback& requestCallback() override { return m_requestCallback.get(); }
729 private:
730     const String m_objectStoreName;
731     Ref<ClearObjectStoreCallback> m_requestCallback;
732 };
733
734 } // anonymous namespace
735
736 void InspectorIndexedDBAgent::clearObjectStore(const String& securityOrigin, const String& databaseName, const String& objectStoreName, Ref<ClearObjectStoreCallback>&& callback)
737 {
738     auto* frame = InspectorPageAgent::findFrameWithSecurityOrigin(m_inspectedPage, securityOrigin);
739     Document* document;
740     IDBFactory* idbFactory;
741     if (!getDocumentAndIDBFactoryFromFrameOrSendFailure(frame, document, idbFactory, callback))
742         return;
743
744     Ref<ClearObjectStore> clearObjectStore = ClearObjectStore::create(document, objectStoreName, WTFMove(callback));
745     clearObjectStore->start(idbFactory, &document->securityOrigin(), databaseName);
746 }
747
748 } // namespace WebCore
749 #endif // ENABLE(INDEXED_DATABASE)