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