Use "= default" to denote default constructor or destructor
[WebKit-https.git] / Source / WebCore / inspector / InspectorIndexedDBAgent.cpp
1 /*
2  * Copyright (C) 2012 Google Inc. All rights reserved.
3  * Copyright (C) 2015-2017 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
88 namespace WebCore {
89 using namespace Inspector;
90
91 namespace {
92
93 class ExecutableWithDatabase : public RefCounted<ExecutableWithDatabase> {
94 public:
95     ExecutableWithDatabase(ScriptExecutionContext* context)
96         : m_context(context) { }
97     virtual ~ExecutableWithDatabase() = default;
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() = default;
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(MAKE_STATIC_STRING_IMPL("number"));
278     static NeverDestroyed<const String> stringType(MAKE_STATIC_STRING_IMPL("string"));
279     static NeverDestroyed<const String> dateType(MAKE_STATIC_STRING_IMPL("date"));
280     static NeverDestroyed<const String> arrayType(MAKE_STATIC_STRING_IMPL("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() = default;
354
355     bool operator==(const EventListener& other) const override
356     {
357         return this == &other;
358     }
359
360     void handleEvent(ScriptExecutionContext&, 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 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() = default;
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(), IDBCursorDirection::Next);
471                 if (!result.hasException())
472                     idbRequest = result.releaseReturnValue();
473             }
474         } else {
475             if (exec) {
476                 auto result = idbObjectStore->openCursor(*exec, m_idbKeyRange.get(), IDBCursorDirection::Next);
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() = default;
521
522 void InspectorIndexedDBAgent::didCreateFrontendAndBackend(Inspector::FrontendRouter*, Inspector::BackendDispatcher*)
523 {
524 }
525
526 void InspectorIndexedDBAgent::willDestroyFrontendAndBackend(Inspector::DisconnectReason)
527 {
528     ErrorString unused;
529     disable(unused);
530 }
531
532 void InspectorIndexedDBAgent::enable(ErrorString&)
533 {
534 }
535
536 void InspectorIndexedDBAgent::disable(ErrorString&)
537 {
538 }
539
540 static Document* assertDocument(ErrorString& errorString, Frame* frame)
541 {
542     Document* document = frame ? frame->document() : nullptr;
543     if (!document)
544         errorString = ASCIILiteral("No document for given frame found");
545     return document;
546 }
547
548 static IDBFactory* assertIDBFactory(ErrorString& errorString, Document* document)
549 {
550     DOMWindow* domWindow = document->domWindow();
551     if (!domWindow) {
552         errorString = ASCIILiteral("No IndexedDB factory for given frame found");
553         return nullptr;
554     }
555
556     IDBFactory* idbFactory = DOMWindowIndexedDatabase::indexedDB(*domWindow);
557     if (!idbFactory)
558         errorString = ASCIILiteral("No IndexedDB factory for given frame found");
559
560     return idbFactory;
561 }
562
563 void InspectorIndexedDBAgent::requestDatabaseNames(ErrorString& errorString, const String& securityOrigin, Ref<RequestDatabaseNamesCallback>&& requestCallback)
564 {
565     Frame* frame = m_pageAgent->findFrameWithSecurityOrigin(securityOrigin);
566     Document* document = assertDocument(errorString, frame);
567     if (!document)
568         return;
569
570     auto& openingOrigin = document->securityOrigin();
571
572     auto& topOrigin = document->topOrigin();
573
574     IDBFactory* idbFactory = assertIDBFactory(errorString, document);
575     if (!idbFactory)
576         return;
577
578     idbFactory->getAllDatabaseNames(topOrigin, openingOrigin, [callback = WTFMove(requestCallback)](auto& databaseNames) {
579         if (!callback->isActive())
580             return;
581
582         Ref<Inspector::Protocol::Array<String>> databaseNameArray = Inspector::Protocol::Array<String>::create();
583         for (auto& databaseName : databaseNames)
584             databaseNameArray->addItem(databaseName);
585
586         callback->sendSuccess(WTFMove(databaseNameArray));
587     });
588 }
589
590 void InspectorIndexedDBAgent::requestDatabase(ErrorString& errorString, const String& securityOrigin, const String& databaseName, Ref<RequestDatabaseCallback>&& requestCallback)
591 {
592     Frame* frame = m_pageAgent->findFrameWithSecurityOrigin(securityOrigin);
593     Document* document = assertDocument(errorString, frame);
594     if (!document)
595         return;
596
597     IDBFactory* idbFactory = assertIDBFactory(errorString, document);
598     if (!idbFactory)
599         return;
600
601     Ref<DatabaseLoader> databaseLoader = DatabaseLoader::create(document, WTFMove(requestCallback));
602     databaseLoader->start(idbFactory, &document->securityOrigin(), databaseName);
603 }
604
605 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)
606 {
607     Frame* frame = m_pageAgent->findFrameWithSecurityOrigin(securityOrigin);
608     Document* document = assertDocument(errorString, frame);
609     if (!document)
610         return;
611
612     IDBFactory* idbFactory = assertIDBFactory(errorString, document);
613     if (!idbFactory)
614         return;
615
616     InjectedScript injectedScript = m_injectedScriptManager.injectedScriptFor(mainWorldExecState(frame));
617
618     RefPtr<IDBKeyRange> idbKeyRange = keyRange ? idbKeyRangeFromKeyRange(keyRange) : nullptr;
619     if (keyRange && !idbKeyRange) {
620         errorString = ASCIILiteral("Can not parse key range.");
621         return;
622     }
623
624     Ref<DataLoader> dataLoader = DataLoader::create(document, WTFMove(requestCallback), injectedScript, objectStoreName, indexName, WTFMove(idbKeyRange), skipCount, pageSize);
625     dataLoader->start(idbFactory, &document->securityOrigin(), databaseName);
626 }
627
628 class ClearObjectStoreListener final : public EventListener {
629     WTF_MAKE_NONCOPYABLE(ClearObjectStoreListener);
630 public:
631     static Ref<ClearObjectStoreListener> create(Ref<ClearObjectStoreCallback> requestCallback)
632     {
633         return adoptRef(*new ClearObjectStoreListener(WTFMove(requestCallback)));
634     }
635
636     virtual ~ClearObjectStoreListener() = default;
637
638     bool operator==(const EventListener& other) const override
639     {
640         return this == &other;
641     }
642
643     void handleEvent(ScriptExecutionContext&, Event& event) override
644     {
645         if (!m_requestCallback->isActive())
646             return;
647         if (event.type() != eventNames().completeEvent) {
648             m_requestCallback->sendFailure("Unexpected event type.");
649             return;
650         }
651
652         m_requestCallback->sendSuccess();
653     }
654 private:
655     ClearObjectStoreListener(Ref<ClearObjectStoreCallback>&& requestCallback)
656         : EventListener(EventListener::CPPEventListenerType)
657         , m_requestCallback(WTFMove(requestCallback))
658     {
659     }
660
661     Ref<ClearObjectStoreCallback> m_requestCallback;
662 };
663
664 class ClearObjectStore final : public ExecutableWithDatabase {
665 public:
666     static Ref<ClearObjectStore> create(ScriptExecutionContext* context, const String& objectStoreName, Ref<ClearObjectStoreCallback>&& requestCallback)
667     {
668         return adoptRef(*new ClearObjectStore(context, objectStoreName, WTFMove(requestCallback)));
669     }
670
671     ClearObjectStore(ScriptExecutionContext* context, const String& objectStoreName, Ref<ClearObjectStoreCallback>&& requestCallback)
672         : ExecutableWithDatabase(context)
673         , m_objectStoreName(objectStoreName)
674         , m_requestCallback(WTFMove(requestCallback))
675     {
676     }
677
678     void execute(IDBDatabase& database) override
679     {
680         if (!requestCallback().isActive())
681             return;
682
683         auto idbTransaction = transactionForDatabase(&database, m_objectStoreName, IDBTransactionMode::Readwrite);
684         if (!idbTransaction) {
685             m_requestCallback->sendFailure("Could not get transaction");
686             return;
687         }
688
689         auto idbObjectStore = objectStoreForTransaction(idbTransaction.get(), m_objectStoreName);
690         if (!idbObjectStore) {
691             m_requestCallback->sendFailure("Could not get object store");
692             return;
693         }
694
695         TransactionActivator activator(idbTransaction.get());
696         RefPtr<IDBRequest> idbRequest;
697         if (auto* exec = context() ? context()->execState() : nullptr) {
698             auto result = idbObjectStore->clear(*exec);
699             ASSERT(!result.hasException());
700             if (result.hasException()) {
701                 m_requestCallback->sendFailure(String::format("Could not clear object store '%s': %d", m_objectStoreName.utf8().data(), result.releaseException().code()));
702                 return;
703             }
704             idbRequest = result.releaseReturnValue();
705         }
706
707         idbTransaction->addEventListener(eventNames().completeEvent, ClearObjectStoreListener::create(m_requestCallback.copyRef()), false);
708     }
709
710     RequestCallback& requestCallback() override { return m_requestCallback.get(); }
711 private:
712     const String m_objectStoreName;
713     Ref<ClearObjectStoreCallback> m_requestCallback;
714 };
715
716 void InspectorIndexedDBAgent::clearObjectStore(ErrorString& errorString, const String& securityOrigin, const String& databaseName, const String& objectStoreName, Ref<ClearObjectStoreCallback>&& requestCallback)
717 {
718     Frame* frame = m_pageAgent->findFrameWithSecurityOrigin(securityOrigin);
719     Document* document = assertDocument(errorString, frame);
720     if (!document)
721         return;
722     IDBFactory* idbFactory = assertIDBFactory(errorString, document);
723     if (!idbFactory)
724         return;
725
726     Ref<ClearObjectStore> clearObjectStore = ClearObjectStore::create(document, objectStoreName, WTFMove(requestCallback));
727     clearObjectStore->start(idbFactory, &document->securityOrigin(), databaseName);
728 }
729
730 } // namespace WebCore
731 #endif // ENABLE(INDEXED_DATABASE)