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