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