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