33705467c3b5c0a17946dfe16964ebd7fa534825
[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 "EventNames.h"
45 #include "EventTarget.h"
46 #include "ExceptionCode.h"
47 #include "Frame.h"
48 #include "IDBBindingUtilities.h"
49 #include "IDBCursor.h"
50 #include "IDBCursorWithValue.h"
51 #include "IDBDatabase.h"
52 #include "IDBFactory.h"
53 #include "IDBIndex.h"
54 #include "IDBKey.h"
55 #include "IDBKeyPath.h"
56 #include "IDBKeyRange.h"
57 #include "IDBObjectStore.h"
58 #include "IDBOpenDBRequest.h"
59 #include "IDBRequest.h"
60 #include "IDBTransaction.h"
61 #include "InspectorPageAgent.h"
62 #include "InstrumentingAgents.h"
63 #include "ScriptState.h"
64 #include "SecurityOrigin.h"
65 #include <inspector/InjectedScript.h>
66 #include <inspector/InjectedScriptManager.h>
67 #include <inspector/InspectorFrontendDispatchers.h>
68 #include <inspector/InspectorFrontendRouter.h>
69 #include <inspector/InspectorValues.h>
70 #include <wtf/NeverDestroyed.h>
71 #include <wtf/Vector.h>
72
73 using Inspector::Protocol::Array;
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 using namespace Inspector;
89
90 namespace WebCore {
91
92 namespace {
93
94 class ExecutableWithDatabase : public RefCounted<ExecutableWithDatabase> {
95 public:
96     ExecutableWithDatabase(ScriptExecutionContext* context)
97         : m_context(context) { }
98     virtual ~ExecutableWithDatabase() { }
99     void start(IDBFactory*, SecurityOrigin*, const String& databaseName);
100     virtual void execute(IDBDatabase&) = 0;
101     virtual RequestCallback& requestCallback() = 0;
102     ScriptExecutionContext* context() const { return m_context; }
103 private:
104     ScriptExecutionContext* m_context;
105 };
106
107 class OpenDatabaseCallback final : public EventListener {
108 public:
109     static Ref<OpenDatabaseCallback> create(ExecutableWithDatabase* executableWithDatabase)
110     {
111         return adoptRef(*new OpenDatabaseCallback(executableWithDatabase));
112     }
113
114     virtual ~OpenDatabaseCallback() { }
115
116     bool operator==(const EventListener& other) const override
117     {
118         return this == &other;
119     }
120
121     void handleEvent(ScriptExecutionContext*, Event* event) override
122     {
123         if (event->type() != eventNames().successEvent) {
124             m_executableWithDatabase->requestCallback().sendFailure("Unexpected event type.");
125             return;
126         }
127
128         auto& request = static_cast<IDBOpenDBRequest&>(*event->target());
129         if (!request.isDone()) {
130             m_executableWithDatabase->requestCallback().sendFailure("Could not get result in callback.");
131             return;
132         }
133         auto databaseResult = request.databaseResult();
134         if (!databaseResult) {
135             m_executableWithDatabase->requestCallback().sendFailure("Unexpected result type.");
136             return;
137         }
138
139         m_executableWithDatabase->execute(*databaseResult);
140         databaseResult->close();
141     }
142
143 private:
144     OpenDatabaseCallback(ExecutableWithDatabase* executableWithDatabase)
145         : EventListener(EventListener::CPPEventListenerType)
146         , m_executableWithDatabase(executableWithDatabase) { }
147     RefPtr<ExecutableWithDatabase> m_executableWithDatabase;
148 };
149
150 void ExecutableWithDatabase::start(IDBFactory* idbFactory, SecurityOrigin*, const String& databaseName)
151 {
152     if (!context()) {
153         requestCallback().sendFailure("Could not open database.");
154         return;
155     }
156
157     ExceptionCodeWithMessage ec;
158     RefPtr<IDBOpenDBRequest> idbOpenDBRequest = idbFactory->open(*context(), databaseName, Nullopt, ec);
159     if (ec.code) {
160         requestCallback().sendFailure("Could not open database.");
161         return;
162     }
163
164     Ref<OpenDatabaseCallback> callback = OpenDatabaseCallback::create(this);
165     idbOpenDBRequest->addEventListener(eventNames().successEvent, WTFMove(callback), false);
166 }
167
168
169 static RefPtr<KeyPath> keyPathFromIDBKeyPath(const IDBKeyPath& idbKeyPath)
170 {
171     RefPtr<KeyPath> keyPath;
172     switch (idbKeyPath.type()) {
173     case IDBKeyPath::Type::Null:
174         keyPath = KeyPath::create()
175             .setType(KeyPath::Type::Null)
176             .release();
177         break;
178
179     case IDBKeyPath::Type::String:
180         keyPath = KeyPath::create()
181             .setType(KeyPath::Type::String)
182             .release();
183         keyPath->setString(idbKeyPath.string());
184         break;
185
186     case IDBKeyPath::Type::Array: {
187         auto array = Inspector::Protocol::Array<String>::create();
188         for (auto& string : idbKeyPath.array())
189             array->addItem(string);
190         keyPath = KeyPath::create()
191             .setType(KeyPath::Type::Array)
192             .release();
193         keyPath->setArray(WTFMove(array));
194         break;
195     }
196
197     default:
198         ASSERT_NOT_REACHED();
199     }
200
201     return keyPath;
202 }
203
204 static RefPtr<IDBTransaction> transactionForDatabase(ScriptExecutionContext* scriptExecutionContext, IDBDatabase* idbDatabase, const String& objectStoreName, const String& mode = IDBTransaction::modeReadOnly())
205 {
206     ExceptionCodeWithMessage ec;
207     RefPtr<IDBTransaction> idbTransaction = idbDatabase->transaction(scriptExecutionContext, objectStoreName, mode, ec);
208     if (ec.code)
209         return nullptr;
210     return idbTransaction;
211 }
212
213 static RefPtr<IDBObjectStore> objectStoreForTransaction(IDBTransaction* idbTransaction, const String& objectStoreName)
214 {
215     ExceptionCodeWithMessage ec;
216     RefPtr<IDBObjectStore> idbObjectStore = idbTransaction->objectStore(objectStoreName, ec);
217     if (ec.code)
218         return nullptr;
219     return idbObjectStore;
220 }
221
222 static RefPtr<IDBIndex> indexForObjectStore(IDBObjectStore* idbObjectStore, const String& indexName)
223 {
224     ExceptionCodeWithMessage ec;
225     RefPtr<IDBIndex> idbIndex = idbObjectStore->index(indexName, ec);
226     if (ec.code)
227         return nullptr;
228     return idbIndex;
229 }
230
231 class DatabaseLoader final : public ExecutableWithDatabase {
232 public:
233     static Ref<DatabaseLoader> create(ScriptExecutionContext* context, Ref<RequestDatabaseCallback>&& requestCallback)
234     {
235         return adoptRef(*new DatabaseLoader(context, WTFMove(requestCallback)));
236     }
237
238     virtual ~DatabaseLoader() { }
239
240     void execute(IDBDatabase& database) override
241     {
242         if (!requestCallback().isActive())
243             return;
244     
245         auto& databaseInfo = database.info();
246         auto objectStores = Inspector::Protocol::Array<Inspector::Protocol::IndexedDB::ObjectStore>::create();
247         auto objectStoreNames = databaseInfo.objectStoreNames();
248         for (auto& name : objectStoreNames) {
249             auto* objectStoreInfo = databaseInfo.infoForExistingObjectStore(name);
250             if (!objectStoreInfo)
251                 continue;
252
253             auto indexes = Inspector::Protocol::Array<Inspector::Protocol::IndexedDB::ObjectStoreIndex>::create();
254     
255             for (auto& indexInfo : objectStoreInfo->indexMap().values()) {
256                 Ref<ObjectStoreIndex> objectStoreIndex = ObjectStoreIndex::create()
257                     .setName(indexInfo.name())
258                     .setKeyPath(keyPathFromIDBKeyPath(indexInfo.keyPath()))
259                     .setUnique(indexInfo.unique())
260                     .setMultiEntry(indexInfo.multiEntry())
261                     .release();
262                 indexes->addItem(WTFMove(objectStoreIndex));
263             }
264     
265             Ref<ObjectStore> objectStore = ObjectStore::create()
266                 .setName(objectStoreInfo->name())
267                 .setKeyPath(keyPathFromIDBKeyPath(objectStoreInfo->keyPath()))
268                 .setAutoIncrement(objectStoreInfo->autoIncrement())
269                 .setIndexes(WTFMove(indexes))
270                 .release();
271             objectStores->addItem(WTFMove(objectStore));
272         }
273     
274         Ref<DatabaseWithObjectStores> result = DatabaseWithObjectStores::create()
275             .setName(databaseInfo.name())
276             .setVersion(databaseInfo.version())
277             .setObjectStores(WTFMove(objectStores))
278             .release();
279         m_requestCallback->sendSuccess(WTFMove(result));
280     }
281
282     RequestCallback& requestCallback() override { return m_requestCallback.get(); }
283 private:
284     DatabaseLoader(ScriptExecutionContext* context, Ref<RequestDatabaseCallback>&& requestCallback)
285         : ExecutableWithDatabase(context)
286         , m_requestCallback(WTFMove(requestCallback)) { }
287     Ref<RequestDatabaseCallback> m_requestCallback;
288 };
289
290 static RefPtr<IDBKey> idbKeyFromInspectorObject(InspectorObject* key)
291 {
292     String type;
293     if (!key->getString("type", type))
294         return nullptr;
295
296     static NeverDestroyed<const String> numberType(ASCIILiteral("number"));
297     static NeverDestroyed<const String> stringType(ASCIILiteral("string"));
298     static NeverDestroyed<const String> dateType(ASCIILiteral("date"));
299     static NeverDestroyed<const String> arrayType(ASCIILiteral("array"));
300
301     RefPtr<IDBKey> idbKey;
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;
334 }
335
336 static RefPtr<IDBKeyRange> idbKeyRangeFromKeyRange(const InspectorObject* keyRange)
337 {
338     RefPtr<InspectorObject> lower;
339     if (!keyRange->getObject(ASCIILiteral("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(ASCIILiteral("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(ASCIILiteral("lowerOpen"), lowerOpen))
354         return nullptr;
355
356     bool upperOpen;
357     if (!keyRange->getBoolean(ASCIILiteral("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             end(false);
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     void end(bool hasMore)
438     {
439         if (!m_requestCallback->isActive())
440             return;
441         m_requestCallback->sendSuccess(WTFMove(m_result), hasMore);
442     }
443
444 private:
445     OpenCursorCallback(InjectedScript injectedScript, Ref<RequestDataCallback>&& requestCallback, int skipCount, unsigned pageSize)
446         : EventListener(EventListener::CPPEventListenerType)
447         , m_injectedScript(injectedScript)
448         , m_requestCallback(WTFMove(requestCallback))
449         , m_result(Array<DataEntry>::create())
450         , m_skipCount(skipCount)
451         , m_pageSize(pageSize)
452     {
453     }
454     InjectedScript m_injectedScript;
455     Ref<RequestDataCallback> m_requestCallback;
456     Ref<Array<DataEntry>> m_result;
457     int m_skipCount;
458     unsigned m_pageSize;
459 };
460
461 class DataLoader : public ExecutableWithDatabase {
462 public:
463     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)
464     {
465         return adoptRef(*new DataLoader(context, WTFMove(requestCallback), injectedScript, objectStoreName, indexName, WTFMove(idbKeyRange), skipCount, pageSize));
466     }
467
468     virtual ~DataLoader() { }
469
470     void execute(IDBDatabase& database) override
471     {
472         if (!requestCallback().isActive())
473             return;
474
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         TransactionActivator activator(idbTransaction.get());
487         ExceptionCodeWithMessage ec;
488         RefPtr<IDBRequest> idbRequest;
489         if (!m_indexName.isEmpty()) {
490             RefPtr<IDBIndex> idbIndex = indexForObjectStore(idbObjectStore.get(), m_indexName);
491             if (!idbIndex) {
492                 m_requestCallback->sendFailure("Could not get index");
493                 return;
494             }
495
496             idbRequest = idbIndex->openCursor(*context(), m_idbKeyRange.get(), IDBCursor::directionNext(), ec);
497         } else
498             idbRequest = idbObjectStore->openCursor(*context(), m_idbKeyRange.get(), IDBCursor::directionNext(), ec);
499
500         if (!idbRequest) {
501             m_requestCallback->sendFailure("Could not open cursor to populate database data");
502             return;
503         }
504
505         Ref<OpenCursorCallback> openCursorCallback = OpenCursorCallback::create(m_injectedScript, m_requestCallback.copyRef(), 0, m_pageSize);
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](auto& 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
714         RefPtr<IDBObjectStore> idbObjectStore = objectStoreForTransaction(idbTransaction.get(), m_objectStoreName);
715         if (!idbObjectStore) {
716             m_requestCallback->sendFailure("Could not get object store");
717             return;
718         }
719
720         ExceptionCodeWithMessage ec;
721         RefPtr<IDBRequest> idbRequest = idbObjectStore->clear(*context(), ec);
722         ASSERT(!ec.code);
723         if (ec.code) {
724             m_requestCallback->sendFailure(String::format("Could not clear object store '%s': %d", m_objectStoreName.utf8().data(), ec.code));
725             return;
726         }
727         idbTransaction->addEventListener(eventNames().completeEvent, ClearObjectStoreListener::create(m_requestCallback.copyRef()), false);
728     }
729
730     RequestCallback& requestCallback() override { return m_requestCallback.get(); }
731 private:
732     const String m_objectStoreName;
733     Ref<ClearObjectStoreCallback> m_requestCallback;
734 };
735
736 void InspectorIndexedDBAgent::clearObjectStore(ErrorString& errorString, const String& securityOrigin, const String& databaseName, const String& objectStoreName, Ref<ClearObjectStoreCallback>&& requestCallback)
737 {
738     Frame* frame = m_pageAgent->findFrameWithSecurityOrigin(securityOrigin);
739     Document* document = assertDocument(errorString, frame);
740     if (!document)
741         return;
742     IDBFactory* idbFactory = assertIDBFactory(errorString, document);
743     if (!idbFactory)
744         return;
745
746     Ref<ClearObjectStore> clearObjectStore = ClearObjectStore::create(document, objectStoreName, WTFMove(requestCallback));
747     clearObjectStore->start(idbFactory, document->securityOrigin(), databaseName);
748 }
749
750 } // namespace WebCore
751
752 #endif // ENABLE(INDEXED_DATABASE)