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