Remove LegacyIDB.
[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 "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 "SecurityOrigin.h"
62 #include <inspector/InjectedScript.h>
63 #include <inspector/InjectedScriptManager.h>
64 #include <inspector/InspectorFrontendDispatchers.h>
65 #include <inspector/InspectorFrontendRouter.h>
66 #include <inspector/InspectorValues.h>
67 #include <wtf/NeverDestroyed.h>
68 #include <wtf/Vector.h>
69
70 using Inspector::Protocol::Array;
71 using Inspector::Protocol::IndexedDB::DatabaseWithObjectStores;
72 using Inspector::Protocol::IndexedDB::DataEntry;
73 using Inspector::Protocol::IndexedDB::Key;
74 using Inspector::Protocol::IndexedDB::KeyPath;
75 using Inspector::Protocol::IndexedDB::KeyRange;
76 using Inspector::Protocol::IndexedDB::ObjectStore;
77 using Inspector::Protocol::IndexedDB::ObjectStoreIndex;
78
79 typedef Inspector::BackendDispatcher::CallbackBase RequestCallback;
80 typedef Inspector::IndexedDBBackendDispatcherHandler::RequestDatabaseNamesCallback RequestDatabaseNamesCallback;
81 typedef Inspector::IndexedDBBackendDispatcherHandler::RequestDatabaseCallback RequestDatabaseCallback;
82 typedef Inspector::IndexedDBBackendDispatcherHandler::RequestDataCallback RequestDataCallback;
83 typedef Inspector::IndexedDBBackendDispatcherHandler::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 Ref<GetDatabaseNamesCallback> create(Ref<RequestDatabaseNamesCallback>&& requestCallback, const String& securityOrigin)
95     {
96         return adoptRef(*new GetDatabaseNamesCallback(WTFMove(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         ExceptionCodeWithMessage ec;
117         RefPtr<IDBAny> requestResult = idbRequest->result(ec);
118         if (ec.code) {
119             m_requestCallback->sendFailure("Could not get result in callback.");
120             return;
121         }
122         if (requestResult->type() != IDBAny::Type::DOMStringList) {
123             m_requestCallback->sendFailure("Unexpected result type.");
124             return;
125         }
126
127         RefPtr<DOMStringList> databaseNamesList = requestResult->domStringList();
128         Ref<Inspector::Protocol::Array<String>> databaseNames = Inspector::Protocol::Array<String>::create();
129         for (size_t i = 0; i < databaseNamesList->length(); ++i)
130             databaseNames->addItem(databaseNamesList->item(i));
131         m_requestCallback->sendSuccess(WTFMove(databaseNames));
132     }
133
134 private:
135     GetDatabaseNamesCallback(Ref<RequestDatabaseNamesCallback>&& requestCallback, const String& securityOrigin)
136         : EventListener(EventListener::CPPEventListenerType)
137         , m_requestCallback(WTFMove(requestCallback))
138         , m_securityOrigin(securityOrigin) { }
139     Ref<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() = 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 Ref<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         ExceptionCodeWithMessage ec;
179         RefPtr<IDBAny> requestResult = idbOpenDBRequest->result(ec);
180         if (ec.code) {
181             m_executableWithDatabase->requestCallback().sendFailure("Could not get result in callback.");
182             return;
183         }
184         if (requestResult->type() != IDBAny::Type::IDBDatabase) {
185             m_executableWithDatabase->requestCallback().sendFailure("Unexpected result type.");
186             return;
187         }
188         if (!requestResult->isLegacy()) {
189             m_executableWithDatabase->requestCallback().sendFailure("Only Legacy IDB is supported right now.");
190             return;
191         }
192
193         // FIXME (webkit.org/b/154686) - Reimplement this.
194         m_executableWithDatabase->execute();
195     }
196
197 private:
198     OpenDatabaseCallback(ExecutableWithDatabase* executableWithDatabase)
199         : EventListener(EventListener::CPPEventListenerType)
200         , m_executableWithDatabase(executableWithDatabase) { }
201     RefPtr<ExecutableWithDatabase> m_executableWithDatabase;
202 };
203
204 void ExecutableWithDatabase::start(IDBFactory* idbFactory, SecurityOrigin*, const String& databaseName)
205 {
206     Ref<OpenDatabaseCallback> callback = OpenDatabaseCallback::create(this);
207     ExceptionCode ec = 0;
208     RefPtr<IDBOpenDBRequest> idbOpenDBRequest = idbFactory->open(context(), databaseName, ec);
209     if (ec) {
210         requestCallback().sendFailure("Could not open database.");
211         return;
212     }
213     idbOpenDBRequest->addEventListener(eventNames().successEvent, WTFMove(callback), false);
214 }
215
216 class DatabaseLoader : public ExecutableWithDatabase {
217 public:
218     static Ref<DatabaseLoader> create(ScriptExecutionContext* context, Ref<RequestDatabaseCallback>&& requestCallback)
219     {
220         return adoptRef(*new DatabaseLoader(context, WTFMove(requestCallback)));
221     }
222
223     virtual ~DatabaseLoader() { }
224
225     virtual void execute() override
226     {
227         if (!requestCallback().isActive())
228             return;
229
230         // FIXME (webkit.org/b/154686) - Reimplement this.
231     }
232
233     virtual RequestCallback& requestCallback() override { return m_requestCallback.get(); }
234 private:
235     DatabaseLoader(ScriptExecutionContext* context, Ref<RequestDatabaseCallback>&& requestCallback)
236         : ExecutableWithDatabase(context)
237         , m_requestCallback(WTFMove(requestCallback)) { }
238     Ref<RequestDatabaseCallback> m_requestCallback;
239 };
240
241 static RefPtr<IDBKey> idbKeyFromInspectorObject(InspectorObject* key)
242 {
243     RefPtr<IDBKey> idbKey;
244
245     String type;
246     if (!key->getString("type", type))
247         return nullptr;
248
249     static NeverDestroyed<const String> numberType(ASCIILiteral("number"));
250     static NeverDestroyed<const String> stringType(ASCIILiteral("string"));
251     static NeverDestroyed<const String> dateType(ASCIILiteral("date"));
252     static NeverDestroyed<const String> arrayType(ASCIILiteral("array"));
253
254     if (type == numberType) {
255         double number;
256         if (!key->getDouble("number", number))
257             return nullptr;
258         idbKey = IDBKey::createNumber(number);
259     } else if (type == stringType) {
260         String string;
261         if (!key->getString("string", string))
262             return nullptr;
263         idbKey = IDBKey::createString(string);
264     } else if (type == dateType) {
265         double date;
266         if (!key->getDouble("date", date))
267             return nullptr;
268         idbKey = IDBKey::createDate(date);
269     } else if (type == arrayType) {
270         Vector<RefPtr<IDBKey>> keyArray;
271         RefPtr<InspectorArray> array;
272         if (!key->getArray("array", array))
273             return nullptr;
274         for (size_t i = 0; i < array->length(); ++i) {
275             RefPtr<InspectorValue> value = array->get(i);
276             RefPtr<InspectorObject> object;
277             if (!value->asObject(object))
278                 return nullptr;
279             keyArray.append(idbKeyFromInspectorObject(object.get()));
280         }
281         idbKey = IDBKey::createArray(keyArray);
282     } else
283         return nullptr;
284
285     return idbKey.release();
286 }
287
288 static RefPtr<IDBKeyRange> idbKeyRangeFromKeyRange(const InspectorObject* keyRange)
289 {
290     RefPtr<InspectorObject> lower;
291     if (!keyRange->getObject("lower", lower))
292         return nullptr;
293     RefPtr<IDBKey> idbLower = idbKeyFromInspectorObject(lower.get());
294     if (!idbLower)
295         return nullptr;
296
297     RefPtr<InspectorObject> upper;
298     if (!keyRange->getObject("upper", upper))
299         return nullptr;
300     RefPtr<IDBKey> idbUpper = idbKeyFromInspectorObject(upper.get());
301     if (!idbUpper)
302         return nullptr;
303
304     bool lowerOpen;
305     if (!keyRange->getBoolean("lowerOpen", lowerOpen))
306         return nullptr;
307     IDBKeyRange::LowerBoundType lowerBoundType = lowerOpen ? IDBKeyRange::LowerBoundOpen : IDBKeyRange::LowerBoundClosed;
308
309     bool upperOpen;
310     if (!keyRange->getBoolean("upperOpen", upperOpen))
311         return nullptr;
312     IDBKeyRange::UpperBoundType upperBoundType = upperOpen ? IDBKeyRange::UpperBoundOpen : IDBKeyRange::UpperBoundClosed;
313
314     return IDBKeyRange::create(idbLower, idbUpper, lowerBoundType, upperBoundType);
315 }
316
317 class DataLoader;
318
319 class OpenCursorCallback : public EventListener {
320 public:
321     static Ref<OpenCursorCallback> create(InjectedScript injectedScript, Ref<RequestDataCallback>&& requestCallback, int skipCount, unsigned pageSize)
322     {
323         return adoptRef(*new OpenCursorCallback(injectedScript, WTFMove(requestCallback), skipCount, pageSize));
324     }
325
326     virtual ~OpenCursorCallback() { }
327
328     virtual bool operator==(const EventListener& other) override
329     {
330         return this == &other;
331     }
332
333     virtual void handleEvent(ScriptExecutionContext*, Event* event) override
334     {
335         if (event->type() != eventNames().successEvent) {
336             m_requestCallback->sendFailure("Unexpected event type.");
337             return;
338         }
339
340         IDBRequest* idbRequest = static_cast<IDBRequest*>(event->target());
341         ExceptionCodeWithMessage ecwm;
342         RefPtr<IDBAny> requestResult = idbRequest->result(ecwm);
343         if (ecwm.code) {
344             m_requestCallback->sendFailure("Could not get result in callback.");
345             return;
346         }
347         if (requestResult->type() == IDBAny::Type::ScriptValue) {
348             end(false);
349             return;
350         }
351         if (requestResult->type() != IDBAny::Type::IDBCursorWithValue) {
352             m_requestCallback->sendFailure("Unexpected result type.");
353             return;
354         }
355
356         RefPtr<IDBCursorWithValue> idbCursor = requestResult->idbCursorWithValue();
357
358         if (m_skipCount) {
359             ExceptionCodeWithMessage ec;
360             idbCursor->advance(m_skipCount, ec);
361             if (ec.code)
362                 m_requestCallback->sendFailure("Could not advance cursor.");
363             m_skipCount = 0;
364             return;
365         }
366
367         if (m_result->length() == m_pageSize) {
368             end(true);
369             return;
370         }
371
372         // Continue cursor before making injected script calls, otherwise transaction might be finished.
373         ExceptionCodeWithMessage ec;
374         idbCursor->continueFunction(nullptr, ec);
375         if (ec.code) {
376             m_requestCallback->sendFailure("Could not continue cursor.");
377             return;
378         }
379
380         RefPtr<DataEntry> dataEntry = DataEntry::create()
381             .setKey(m_injectedScript.wrapObject(idbCursor->key(), String(), true))
382             .setPrimaryKey(m_injectedScript.wrapObject(idbCursor->primaryKey(), String(), true))
383             .setValue(m_injectedScript.wrapObject(idbCursor->value(), String(), true))
384             .release();
385         m_result->addItem(WTFMove(dataEntry));
386
387     }
388
389     void end(bool hasMore)
390     {
391         if (!m_requestCallback->isActive())
392             return;
393         m_requestCallback->sendSuccess(WTFMove(m_result), hasMore);
394     }
395
396 private:
397     OpenCursorCallback(InjectedScript injectedScript, Ref<RequestDataCallback>&& requestCallback, int skipCount, unsigned pageSize)
398         : EventListener(EventListener::CPPEventListenerType)
399         , m_injectedScript(injectedScript)
400         , m_requestCallback(WTFMove(requestCallback))
401         , m_skipCount(skipCount)
402         , m_pageSize(pageSize)
403         , m_result(Array<DataEntry>::create())
404     {
405     }
406     InjectedScript m_injectedScript;
407     Ref<RequestDataCallback> m_requestCallback;
408     int m_skipCount;
409     unsigned m_pageSize;
410     Ref<Array<DataEntry>> m_result;
411 };
412
413 class DataLoader : public ExecutableWithDatabase {
414 public:
415     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)
416     {
417         return adoptRef(*new DataLoader(context, WTFMove(requestCallback), injectedScript, objectStoreName, indexName, WTFMove(idbKeyRange), skipCount, pageSize));
418     }
419
420     virtual ~DataLoader() { }
421
422     virtual void execute() override
423     {
424         if (!requestCallback().isActive())
425             return;
426
427         // FIXME (webkit.org/b/154686) - Reimplement this.
428     }
429
430     virtual RequestCallback& requestCallback() override { return m_requestCallback.get(); }
431     DataLoader(ScriptExecutionContext* scriptExecutionContext, Ref<RequestDataCallback>&& requestCallback, const InjectedScript& injectedScript, const String& objectStoreName, const String& indexName, RefPtr<IDBKeyRange> idbKeyRange, int skipCount, unsigned pageSize)
432         : ExecutableWithDatabase(scriptExecutionContext)
433         , m_requestCallback(WTFMove(requestCallback))
434         , m_injectedScript(injectedScript)
435         , m_objectStoreName(objectStoreName)
436         , m_indexName(indexName)
437         , m_idbKeyRange(WTFMove(idbKeyRange))
438         , m_skipCount(skipCount)
439         , m_pageSize(pageSize) { }
440     Ref<RequestDataCallback> m_requestCallback;
441     InjectedScript m_injectedScript;
442     String m_objectStoreName;
443     String m_indexName;
444     RefPtr<IDBKeyRange> m_idbKeyRange;
445     int m_skipCount;
446     unsigned m_pageSize;
447 };
448
449 } // namespace
450
451 InspectorIndexedDBAgent::InspectorIndexedDBAgent(WebAgentContext& context, InspectorPageAgent* pageAgent)
452     : InspectorAgentBase(ASCIILiteral("IndexedDB"), context)
453     , m_injectedScriptManager(context.injectedScriptManager)
454     , m_backendDispatcher(Inspector::IndexedDBBackendDispatcher::create(context.backendDispatcher, this))
455     , m_pageAgent(pageAgent)
456 {
457 }
458
459 InspectorIndexedDBAgent::~InspectorIndexedDBAgent()
460 {
461 }
462
463 void InspectorIndexedDBAgent::didCreateFrontendAndBackend(Inspector::FrontendRouter*, Inspector::BackendDispatcher*)
464 {
465 }
466
467 void InspectorIndexedDBAgent::willDestroyFrontendAndBackend(Inspector::DisconnectReason)
468 {
469     ErrorString unused;
470     disable(unused);
471 }
472
473 void InspectorIndexedDBAgent::enable(ErrorString&)
474 {
475 }
476
477 void InspectorIndexedDBAgent::disable(ErrorString&)
478 {
479 }
480
481 static Document* assertDocument(ErrorString& errorString, Frame* frame)
482 {
483     Document* document = frame ? frame->document() : nullptr;
484     if (!document)
485         errorString = ASCIILiteral("No document for given frame found");
486     return document;
487 }
488
489 static IDBFactory* assertIDBFactory(ErrorString& errorString, Document* document)
490 {
491     DOMWindow* domWindow = document->domWindow();
492     if (!domWindow) {
493         errorString = ASCIILiteral("No IndexedDB factory for given frame found");
494         return nullptr;
495     }
496
497     IDBFactory* idbFactory = DOMWindowIndexedDatabase::indexedDB(domWindow);
498     if (!idbFactory)
499         errorString = ASCIILiteral("No IndexedDB factory for given frame found");
500
501     return idbFactory;
502 }
503
504 void InspectorIndexedDBAgent::requestDatabaseNames(ErrorString& errorString, const String& securityOrigin, Ref<RequestDatabaseNamesCallback>&& requestCallback)
505 {
506     Frame* frame = m_pageAgent->findFrameWithSecurityOrigin(securityOrigin);
507     Document* document = assertDocument(errorString, frame);
508     if (!document)
509         return;
510
511     IDBFactory* idbFactory = assertIDBFactory(errorString, document);
512     if (!idbFactory)
513         return;
514
515     ExceptionCode ec = 0;
516     RefPtr<IDBRequest> idbRequest = idbFactory->getDatabaseNames(document, ec);
517     if (!idbRequest || ec) {
518         requestCallback->sendFailure("Could not obtain database names.");
519         return;
520     }
521
522     idbRequest->addEventListener(eventNames().successEvent, GetDatabaseNamesCallback::create(WTFMove(requestCallback), document->securityOrigin()->toRawString()), false);
523 }
524
525 void InspectorIndexedDBAgent::requestDatabase(ErrorString& errorString, const String& securityOrigin, const String& databaseName, Ref<RequestDatabaseCallback>&& requestCallback)
526 {
527     Frame* frame = m_pageAgent->findFrameWithSecurityOrigin(securityOrigin);
528     Document* document = assertDocument(errorString, frame);
529     if (!document)
530         return;
531
532     IDBFactory* idbFactory = assertIDBFactory(errorString, document);
533     if (!idbFactory)
534         return;
535
536     Ref<DatabaseLoader> databaseLoader = DatabaseLoader::create(document, WTFMove(requestCallback));
537     databaseLoader->start(idbFactory, document->securityOrigin(), databaseName);
538 }
539
540 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)
541 {
542     Frame* frame = m_pageAgent->findFrameWithSecurityOrigin(securityOrigin);
543     Document* document = assertDocument(errorString, frame);
544     if (!document)
545         return;
546
547     IDBFactory* idbFactory = assertIDBFactory(errorString, document);
548     if (!idbFactory)
549         return;
550
551     InjectedScript injectedScript = m_injectedScriptManager.injectedScriptFor(mainWorldExecState(frame));
552
553     RefPtr<IDBKeyRange> idbKeyRange = keyRange ? idbKeyRangeFromKeyRange(keyRange) : nullptr;
554     if (keyRange && !idbKeyRange) {
555         errorString = ASCIILiteral("Can not parse key range.");
556         return;
557     }
558
559     Ref<DataLoader> dataLoader = DataLoader::create(document, WTFMove(requestCallback), injectedScript, objectStoreName, indexName, WTFMove(idbKeyRange), skipCount, pageSize);
560     dataLoader->start(idbFactory, document->securityOrigin(), databaseName);
561 }
562
563 class ClearObjectStoreListener : public EventListener {
564     WTF_MAKE_NONCOPYABLE(ClearObjectStoreListener);
565 public:
566     static Ref<ClearObjectStoreListener> create(Ref<ClearObjectStoreCallback> requestCallback)
567     {
568         return adoptRef(*new ClearObjectStoreListener(WTFMove(requestCallback)));
569     }
570
571     virtual ~ClearObjectStoreListener() { }
572
573     virtual bool operator==(const EventListener& other) override
574     {
575         return this == &other;
576     }
577
578     virtual void handleEvent(ScriptExecutionContext*, Event* event) override
579     {
580         if (!m_requestCallback->isActive())
581             return;
582         if (event->type() != eventNames().completeEvent) {
583             m_requestCallback->sendFailure("Unexpected event type.");
584             return;
585         }
586
587         m_requestCallback->sendSuccess();
588     }
589 private:
590     ClearObjectStoreListener(Ref<ClearObjectStoreCallback>&& requestCallback)
591         : EventListener(EventListener::CPPEventListenerType)
592         , m_requestCallback(WTFMove(requestCallback))
593     {
594     }
595
596     Ref<ClearObjectStoreCallback> m_requestCallback;
597 };
598
599
600 class ClearObjectStore : public ExecutableWithDatabase {
601 public:
602     static Ref<ClearObjectStore> create(ScriptExecutionContext* context, const String& objectStoreName, Ref<ClearObjectStoreCallback>&& requestCallback)
603     {
604         return adoptRef(*new ClearObjectStore(context, objectStoreName, WTFMove(requestCallback)));
605     }
606
607     ClearObjectStore(ScriptExecutionContext* context, const String& objectStoreName, Ref<ClearObjectStoreCallback>&& requestCallback)
608         : ExecutableWithDatabase(context)
609         , m_objectStoreName(objectStoreName)
610         , m_requestCallback(WTFMove(requestCallback))
611     {
612     }
613
614     virtual void execute() override
615     {
616         if (!requestCallback().isActive())
617             return;
618
619         // FIXME (webkit.org/b/154686) - Reimplement this.
620     }
621
622     virtual RequestCallback& requestCallback() override { return m_requestCallback.get(); }
623 private:
624     const String m_objectStoreName;
625     Ref<ClearObjectStoreCallback> m_requestCallback;
626 };
627
628 void InspectorIndexedDBAgent::clearObjectStore(ErrorString& errorString, const String& securityOrigin, const String& databaseName, const String& objectStoreName, Ref<ClearObjectStoreCallback>&& requestCallback)
629 {
630     Frame* frame = m_pageAgent->findFrameWithSecurityOrigin(securityOrigin);
631     Document* document = assertDocument(errorString, frame);
632     if (!document)
633         return;
634     IDBFactory* idbFactory = assertIDBFactory(errorString, document);
635     if (!idbFactory)
636         return;
637
638     Ref<ClearObjectStore> clearObjectStore = ClearObjectStore::create(document, objectStoreName, WTFMove(requestCallback));
639     clearObjectStore->start(idbFactory, document->securityOrigin(), databaseName);
640 }
641
642 } // namespace WebCore
643
644 #endif // ENABLE(INDEXED_DATABASE)