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 "InspectorState.h"
65#include "InspectorValues.h"
66#include "InstrumentingAgents.h"
67#include "SecurityOrigin.h"
68
69#include <wtf/Vector.h>
70
71using WebCore::TypeBuilder::Array;
72using WebCore::TypeBuilder::IndexedDB::DatabaseWithObjectStores;
73using WebCore::TypeBuilder::IndexedDB::DataEntry;
74using WebCore::TypeBuilder::IndexedDB::Key;
75using WebCore::TypeBuilder::IndexedDB::KeyPath;
76using WebCore::TypeBuilder::IndexedDB::KeyRange;
77using WebCore::TypeBuilder::IndexedDB::ObjectStore;
78using WebCore::TypeBuilder::IndexedDB::ObjectStoreIndex;
79
80typedef WebCore::InspectorBackendDispatcher::IndexedDBCommandHandler::RequestDatabaseNamesCallback RequestDatabaseNamesCallback;
81typedef WebCore::InspectorBackendDispatcher::IndexedDBCommandHandler::RequestDatabaseCallback RequestDatabaseCallback;
82typedef WebCore::InspectorBackendDispatcher::IndexedDBCommandHandler::RequestDataCallback RequestDataCallback;
83typedef WebCore::InspectorBackendDispatcher::CallbackBase RequestCallback;
84typedef WebCore::InspectorBackendDispatcher::IndexedDBCommandHandler::ClearObjectStoreCallback ClearObjectStoreCallback;
85
86namespace WebCore {
87
88namespace IndexedDBAgentState {
89static const char indexedDBAgentEnabled[] = "indexedDBAgentEnabled";
90};
91
92namespace {
93
94class GetDatabaseNamesCallback : public EventListener {
95    WTF_MAKE_NONCOPYABLE(GetDatabaseNamesCallback);
96public:
97    static PassRefPtr<GetDatabaseNamesCallback> create(PassRefPtr<RequestDatabaseNamesCallback> requestCallback, const String& securityOrigin)
98    {
99        return adoptRef(new GetDatabaseNamesCallback(requestCallback, securityOrigin));
100    }
101
102    virtual ~GetDatabaseNamesCallback() { }
103
104    virtual bool operator==(const EventListener& other) OVERRIDE
105    {
106        return this == &other;
107    }
108
109    virtual void handleEvent(ScriptExecutionContext*, Event* event) OVERRIDE
110    {
111        if (!m_requestCallback->isActive())
112            return;
113        if (event->type() != eventNames().successEvent) {
114            m_requestCallback->sendFailure("Unexpected event type.");
115            return;
116        }
117
118        IDBRequest* idbRequest = static_cast<IDBRequest*>(event->target());
119        ExceptionCode ec = 0;
120        RefPtr<IDBAny> requestResult = idbRequest->result(ec);
121        if (ec) {
122            m_requestCallback->sendFailure("Could not get result in callback.");
123            return;
124        }
125        if (requestResult->type() != IDBAny::DOMStringListType) {
126            m_requestCallback->sendFailure("Unexpected result type.");
127            return;
128        }
129
130        RefPtr<DOMStringList> databaseNamesList = requestResult->domStringList();
131        RefPtr<TypeBuilder::Array<String> > databaseNames = TypeBuilder::Array<String>::create();
132        for (size_t i = 0; i < databaseNamesList->length(); ++i)
133            databaseNames->addItem(databaseNamesList->item(i));
134        m_requestCallback->sendSuccess(databaseNames.release());
135    }
136
137private:
138    GetDatabaseNamesCallback(PassRefPtr<RequestDatabaseNamesCallback> requestCallback, const String& securityOrigin)
139        : EventListener(EventListener::CPPEventListenerType)
140        , m_requestCallback(requestCallback)
141        , m_securityOrigin(securityOrigin) { }
142    RefPtr<RequestDatabaseNamesCallback> m_requestCallback;
143    String m_securityOrigin;
144};
145
146class ExecutableWithDatabase : public RefCounted<ExecutableWithDatabase> {
147public:
148    ExecutableWithDatabase(ScriptExecutionContext* context)
149        : m_context(context) { }
150    virtual ~ExecutableWithDatabase() { };
151    void start(IDBFactory*, SecurityOrigin*, const String& databaseName);
152    virtual void execute(PassRefPtr<IDBDatabase>) = 0;
153    virtual RequestCallback* requestCallback() = 0;
154    ScriptExecutionContext* context() { return m_context; };
155private:
156    ScriptExecutionContext* m_context;
157};
158
159class OpenDatabaseCallback : public EventListener {
160public:
161    static PassRefPtr<OpenDatabaseCallback> create(ExecutableWithDatabase* executableWithDatabase)
162    {
163        return adoptRef(new OpenDatabaseCallback(executableWithDatabase));
164    }
165
166    virtual ~OpenDatabaseCallback() { }
167
168    virtual bool operator==(const EventListener& other) OVERRIDE
169    {
170        return this == &other;
171    }
172
173    virtual void handleEvent(ScriptExecutionContext*, Event* event) OVERRIDE
174    {
175        if (event->type() != eventNames().successEvent) {
176            m_executableWithDatabase->requestCallback()->sendFailure("Unexpected event type.");
177            return;
178        }
179
180        IDBOpenDBRequest* idbOpenDBRequest = static_cast<IDBOpenDBRequest*>(event->target());
181        ExceptionCode ec = 0;
182        RefPtr<IDBAny> requestResult = idbOpenDBRequest->result(ec);
183        if (ec) {
184            m_executableWithDatabase->requestCallback()->sendFailure("Could not get result in callback.");
185            return;
186        }
187        if (requestResult->type() != IDBAny::IDBDatabaseType) {
188            m_executableWithDatabase->requestCallback()->sendFailure("Unexpected result type.");
189            return;
190        }
191
192        RefPtr<IDBDatabase> idbDatabase = requestResult->idbDatabase();
193        m_executableWithDatabase->execute(idbDatabase);
194        IDBPendingTransactionMonitor::deactivateNewTransactions();
195        idbDatabase->close();
196    }
197
198private:
199    OpenDatabaseCallback(ExecutableWithDatabase* executableWithDatabase)
200        : EventListener(EventListener::CPPEventListenerType)
201        , m_executableWithDatabase(executableWithDatabase) { }
202    RefPtr<ExecutableWithDatabase> m_executableWithDatabase;
203};
204
205void ExecutableWithDatabase::start(IDBFactory* idbFactory, SecurityOrigin*, const String& databaseName)
206{
207    RefPtr<OpenDatabaseCallback> callback = OpenDatabaseCallback::create(this);
208    ExceptionCode ec = 0;
209    RefPtr<IDBOpenDBRequest> idbOpenDBRequest = idbFactory->open(context(), databaseName, ec);
210    if (ec) {
211        requestCallback()->sendFailure("Could not open database.");
212        return;
213    }
214    idbOpenDBRequest->addEventListener(eventNames().successEvent, callback, false);
215}
216
217static PassRefPtr<IDBTransaction> transactionForDatabase(ScriptExecutionContext* scriptExecutionContext, IDBDatabase* idbDatabase, const String& objectStoreName, const String& mode = IDBTransaction::modeReadOnly())
218{
219    ExceptionCode ec = 0;
220    RefPtr<IDBTransaction> idbTransaction = idbDatabase->transaction(scriptExecutionContext, objectStoreName, mode, ec);
221    if (ec)
222        return 0;
223    return idbTransaction;
224}
225
226static PassRefPtr<IDBObjectStore> objectStoreForTransaction(IDBTransaction* idbTransaction, const String& objectStoreName)
227{
228    ExceptionCode ec = 0;
229    RefPtr<IDBObjectStore> idbObjectStore = idbTransaction->objectStore(objectStoreName, ec);
230    if (ec)
231        return 0;
232    return idbObjectStore;
233}
234
235static PassRefPtr<IDBIndex> indexForObjectStore(IDBObjectStore* idbObjectStore, const String& indexName)
236{
237    ExceptionCode ec = 0;
238    RefPtr<IDBIndex> idbIndex = idbObjectStore->index(indexName, ec);
239    if (ec)
240        return 0;
241    return idbIndex;
242}
243
244static PassRefPtr<KeyPath> keyPathFromIDBKeyPath(const IDBKeyPath& idbKeyPath)
245{
246    RefPtr<KeyPath> keyPath;
247    switch (idbKeyPath.type()) {
248    case IDBKeyPath::NullType:
249        keyPath = KeyPath::create().setType(KeyPath::Type::Null);
250        break;
251    case IDBKeyPath::StringType:
252        keyPath = KeyPath::create().setType(KeyPath::Type::String);
253        keyPath->setString(idbKeyPath.string());
254        break;
255    case IDBKeyPath::ArrayType: {
256        keyPath = KeyPath::create().setType(KeyPath::Type::Array);
257        RefPtr<TypeBuilder::Array<String> > array = TypeBuilder::Array<String>::create();
258        const Vector<String>& stringArray = idbKeyPath.array();
259        for (size_t i = 0; i < stringArray.size(); ++i)
260            array->addItem(stringArray[i]);
261        keyPath->setArray(array);
262        break;
263    }
264    default:
265        ASSERT_NOT_REACHED();
266    }
267
268    return keyPath.release();
269}
270
271class DatabaseLoader : public ExecutableWithDatabase {
272public:
273    static PassRefPtr<DatabaseLoader> create(ScriptExecutionContext* context, PassRefPtr<RequestDatabaseCallback> requestCallback)
274    {
275        return adoptRef(new DatabaseLoader(context, requestCallback));
276    }
277
278    virtual ~DatabaseLoader() { }
279
280    virtual void execute(PassRefPtr<IDBDatabase> prpDatabase)
281    {
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.intVersion)
316            .setVersion(databaseMetadata.version)
317            .setObjectStores(objectStores);
318
319        m_requestCallback->sendSuccess(result);
320    }
321
322    virtual RequestCallback* requestCallback() { return m_requestCallback.get(); }
323private:
324    DatabaseLoader(ScriptExecutionContext* context, PassRefPtr<RequestDatabaseCallback> requestCallback)
325        : ExecutableWithDatabase(context)
326        , m_requestCallback(requestCallback) { }
327    RefPtr<RequestDatabaseCallback> m_requestCallback;
328};
329
330static PassRefPtr<IDBKey> idbKeyFromInspectorObject(InspectorObject* key)
331{
332    RefPtr<IDBKey> idbKey;
333
334    String type;
335    if (!key->getString("type", &type))
336        return 0;
337
338    DEFINE_STATIC_LOCAL(String, number, (ASCIILiteral("number")));
339    DEFINE_STATIC_LOCAL(String, string, (ASCIILiteral("string")));
340    DEFINE_STATIC_LOCAL(String, date, (ASCIILiteral("date")));
341    DEFINE_STATIC_LOCAL(String, array, (ASCIILiteral("array")));
342
343    if (type == number) {
344        double number;
345        if (!key->getNumber("number", &number))
346            return 0;
347        idbKey = IDBKey::createNumber(number);
348    } else if (type == string) {
349        String string;
350        if (!key->getString("string", &string))
351            return 0;
352        idbKey = IDBKey::createString(string);
353    } else if (type == date) {
354        double date;
355        if (!key->getNumber("date", &date))
356            return 0;
357        idbKey = IDBKey::createDate(date);
358    } else if (type == array) {
359        IDBKey::KeyArray keyArray;
360        RefPtr<InspectorArray> array = key->getArray("array");
361        for (size_t i = 0; i < array->length(); ++i) {
362            RefPtr<InspectorValue> value = array->get(i);
363            RefPtr<InspectorObject> object;
364            if (!value->asObject(&object))
365                return 0;
366            keyArray.append(idbKeyFromInspectorObject(object.get()));
367        }
368        idbKey = IDBKey::createArray(keyArray);
369    } else
370        return 0;
371
372    return idbKey.release();
373}
374
375static PassRefPtr<IDBKeyRange> idbKeyRangeFromKeyRange(InspectorObject* keyRange)
376{
377    RefPtr<InspectorObject> lower = keyRange->getObject("lower");
378    RefPtr<IDBKey> idbLower = lower ? idbKeyFromInspectorObject(lower.get()) : 0;
379    if (lower && !idbLower)
380        return 0;
381
382    RefPtr<InspectorObject> upper = keyRange->getObject("upper");
383    RefPtr<IDBKey> idbUpper = upper ? idbKeyFromInspectorObject(upper.get()) : 0;
384    if (upper && !idbUpper)
385        return 0;
386
387    bool lowerOpen;
388    if (!keyRange->getBoolean("lowerOpen", &lowerOpen))
389        return 0;
390    IDBKeyRange::LowerBoundType lowerBoundType = lowerOpen ? IDBKeyRange::LowerBoundOpen : IDBKeyRange::LowerBoundClosed;
391
392    bool upperOpen;
393    if (!keyRange->getBoolean("upperOpen", &upperOpen))
394        return 0;
395    IDBKeyRange::UpperBoundType upperBoundType = upperOpen ? IDBKeyRange::UpperBoundOpen : IDBKeyRange::UpperBoundClosed;
396
397    RefPtr<IDBKeyRange> idbKeyRange = IDBKeyRange::create(idbLower, idbUpper, lowerBoundType, upperBoundType);
398    return idbKeyRange.release();
399}
400
401class DataLoader;
402
403class OpenCursorCallback : public EventListener {
404public:
405    static PassRefPtr<OpenCursorCallback> create(InjectedScript injectedScript, PassRefPtr<RequestDataCallback> requestCallback, int skipCount, unsigned pageSize)
406    {
407        return adoptRef(new OpenCursorCallback(injectedScript, requestCallback, skipCount, pageSize));
408    }
409
410    virtual ~OpenCursorCallback() { }
411
412    virtual bool operator==(const EventListener& other) OVERRIDE
413    {
414        return this == &other;
415    }
416
417    virtual void handleEvent(ScriptExecutionContext*, Event* event) OVERRIDE
418    {
419        if (event->type() != eventNames().successEvent) {
420            m_requestCallback->sendFailure("Unexpected event type.");
421            return;
422        }
423
424        IDBRequest* idbRequest = static_cast<IDBRequest*>(event->target());
425        ExceptionCode ec = 0;
426        RefPtr<IDBAny> requestResult = idbRequest->result(ec);
427        if (ec) {
428            m_requestCallback->sendFailure("Could not get result in callback.");
429            return;
430        }
431        if (requestResult->type() == IDBAny::ScriptValueType) {
432            end(false);
433            return;
434        }
435        if (requestResult->type() != IDBAny::IDBCursorWithValueType) {
436            m_requestCallback->sendFailure("Unexpected result type.");
437            return;
438        }
439
440        RefPtr<IDBCursorWithValue> idbCursor = requestResult->idbCursorWithValue();
441
442        if (m_skipCount) {
443            ExceptionCode ec = 0;
444            idbCursor->advance(m_skipCount, ec);
445            if (ec)
446                m_requestCallback->sendFailure("Could not advance cursor.");
447            m_skipCount = 0;
448            return;
449        }
450
451        if (m_result->length() == m_pageSize) {
452            end(true);
453            return;
454        }
455
456        // Continue cursor before making injected script calls, otherwise transaction might be finished.
457        idbCursor->continueFunction(0, ec);
458        if (ec) {
459            m_requestCallback->sendFailure("Could not continue cursor.");
460            return;
461        }
462
463        RefPtr<DataEntry> dataEntry = DataEntry::create()
464            .setKey(m_injectedScript.wrapObject(idbCursor->key(), String()))
465            .setPrimaryKey(m_injectedScript.wrapObject(idbCursor->primaryKey(), String()))
466            .setValue(m_injectedScript.wrapObject(idbCursor->value(), String()));
467        m_result->addItem(dataEntry);
468
469    }
470
471    void end(bool hasMore)
472    {
473        if (!m_requestCallback->isActive())
474            return;
475        m_requestCallback->sendSuccess(m_result.release(), hasMore);
476    }
477
478private:
479    OpenCursorCallback(InjectedScript injectedScript, PassRefPtr<RequestDataCallback> requestCallback, int skipCount, unsigned pageSize)
480        : EventListener(EventListener::CPPEventListenerType)
481        , m_injectedScript(injectedScript)
482        , m_requestCallback(requestCallback)
483        , m_skipCount(skipCount)
484        , m_pageSize(pageSize)
485    {
486        m_result = Array<DataEntry>::create();
487    }
488    InjectedScript m_injectedScript;
489    RefPtr<RequestDataCallback> m_requestCallback;
490    int m_skipCount;
491    unsigned m_pageSize;
492    RefPtr<Array<DataEntry> > m_result;
493};
494
495class DataLoader : public ExecutableWithDatabase {
496public:
497    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)
498    {
499        return adoptRef(new DataLoader(context, requestCallback, injectedScript, objectStoreName, indexName, idbKeyRange, skipCount, pageSize));
500    }
501
502    virtual ~DataLoader() { }
503
504    virtual void execute(PassRefPtr<IDBDatabase> prpDatabase)
505    {
506        RefPtr<IDBDatabase> idbDatabase = prpDatabase;
507        if (!requestCallback()->isActive())
508            return;
509        RefPtr<IDBTransaction> idbTransaction = transactionForDatabase(context(), idbDatabase.get(), m_objectStoreName);
510        if (!idbTransaction) {
511            m_requestCallback->sendFailure("Could not get transaction");
512            return;
513        }
514        RefPtr<IDBObjectStore> idbObjectStore = objectStoreForTransaction(idbTransaction.get(), m_objectStoreName);
515        if (!idbObjectStore) {
516            m_requestCallback->sendFailure("Could not get object store");
517            return;
518        }
519
520        RefPtr<OpenCursorCallback> openCursorCallback = OpenCursorCallback::create(m_injectedScript, m_requestCallback, m_skipCount, m_pageSize);
521
522        ExceptionCode ec = 0;
523        RefPtr<IDBRequest> idbRequest;
524        if (!m_indexName.isEmpty()) {
525            RefPtr<IDBIndex> idbIndex = indexForObjectStore(idbObjectStore.get(), m_indexName);
526            if (!idbIndex) {
527                m_requestCallback->sendFailure("Could not get index");
528                return;
529            }
530
531            idbRequest = idbIndex->openCursor(context(), PassRefPtr<IDBKeyRange>(m_idbKeyRange), ec);
532        } else
533            idbRequest = idbObjectStore->openCursor(context(), PassRefPtr<IDBKeyRange>(m_idbKeyRange), ec);
534        idbRequest->addEventListener(eventNames().successEvent, openCursorCallback, false);
535    }
536
537    virtual RequestCallback* requestCallback() { return m_requestCallback.get(); }
538    DataLoader(ScriptExecutionContext* scriptExecutionContext, PassRefPtr<RequestDataCallback> requestCallback, const InjectedScript& injectedScript, const String& objectStoreName, const String& indexName, PassRefPtr<IDBKeyRange> idbKeyRange, int skipCount, unsigned pageSize)
539        : ExecutableWithDatabase(scriptExecutionContext)
540        , m_requestCallback(requestCallback)
541        , m_injectedScript(injectedScript)
542        , m_objectStoreName(objectStoreName)
543        , m_indexName(indexName)
544        , m_idbKeyRange(idbKeyRange)
545        , m_skipCount(skipCount)
546        , m_pageSize(pageSize) { }
547    RefPtr<RequestDataCallback> m_requestCallback;
548    InjectedScript m_injectedScript;
549    String m_objectStoreName;
550    String m_indexName;
551    RefPtr<IDBKeyRange> m_idbKeyRange;
552    int m_skipCount;
553    unsigned m_pageSize;
554};
555
556} // namespace
557
558InspectorIndexedDBAgent::InspectorIndexedDBAgent(InstrumentingAgents* instrumentingAgents, InspectorCompositeState* state, InjectedScriptManager* injectedScriptManager, InspectorPageAgent* pageAgent)
559    : InspectorBaseAgent<InspectorIndexedDBAgent>("IndexedDB", instrumentingAgents, state)
560    , m_injectedScriptManager(injectedScriptManager)
561    , m_pageAgent(pageAgent)
562{
563}
564
565InspectorIndexedDBAgent::~InspectorIndexedDBAgent()
566{
567}
568
569void InspectorIndexedDBAgent::clearFrontend()
570{
571    disable(0);
572}
573
574void InspectorIndexedDBAgent::restore()
575{
576    if (m_state->getBoolean(IndexedDBAgentState::indexedDBAgentEnabled)) {
577        ErrorString error;
578        enable(&error);
579    }
580}
581
582void InspectorIndexedDBAgent::enable(ErrorString*)
583{
584    m_state->setBoolean(IndexedDBAgentState::indexedDBAgentEnabled, true);
585}
586
587void InspectorIndexedDBAgent::disable(ErrorString*)
588{
589    m_state->setBoolean(IndexedDBAgentState::indexedDBAgentEnabled, false);
590}
591
592static Document* assertDocument(ErrorString* errorString, Frame* frame)
593{
594    Document* document = frame ? frame->document() : 0;
595
596    if (!document)
597        *errorString = "No document for given frame found";
598
599    return document;
600}
601
602static 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 0;
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
617void 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
636void 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
650void 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(mainWorldScriptState(frame));
661
662    RefPtr<IDBKeyRange> idbKeyRange = keyRange ? idbKeyRangeFromKeyRange(keyRange->get()) : 0;
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
672class ClearObjectStoreListener : public EventListener {
673    WTF_MAKE_NONCOPYABLE(ClearObjectStoreListener);
674public:
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    }
698private:
699    ClearObjectStoreListener(PassRefPtr<ClearObjectStoreCallback> requestCallback)
700        : EventListener(EventListener::CPPEventListenerType)
701        , m_requestCallback(requestCallback)
702    {
703    }
704
705    RefPtr<ClearObjectStoreCallback> m_requestCallback;
706};
707
708
709class ClearObjectStore : public ExecutableWithDatabase {
710public:
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)
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() { return m_requestCallback.get(); }
750private:
751    const String m_objectStoreName;
752    RefPtr<ClearObjectStoreCallback> m_requestCallback;
753};
754
755void 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)
772