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