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