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