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