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