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/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 
     67 using blink::TypeBuilder::Array;
     68 using blink::TypeBuilder::IndexedDB::DatabaseWithObjectStores;
     69 using blink::TypeBuilder::IndexedDB::DataEntry;
     70 using blink::TypeBuilder::IndexedDB::Key;
     71 using blink::TypeBuilder::IndexedDB::KeyPath;
     72 using blink::TypeBuilder::IndexedDB::KeyRange;
     73 using blink::TypeBuilder::IndexedDB::ObjectStore;
     74 using blink::TypeBuilder::IndexedDB::ObjectStoreIndex;
     75 
     76 typedef blink::InspectorBackendDispatcher::IndexedDBCommandHandler::RequestDatabaseNamesCallback RequestDatabaseNamesCallback;
     77 typedef blink::InspectorBackendDispatcher::IndexedDBCommandHandler::RequestDatabaseCallback RequestDatabaseCallback;
     78 typedef blink::InspectorBackendDispatcher::IndexedDBCommandHandler::RequestDataCallback RequestDataCallback;
     79 typedef blink::InspectorBackendDispatcher::CallbackBase RequestCallback;
     80 typedef blink::InspectorBackendDispatcher::IndexedDBCommandHandler::ClearObjectStoreCallback ClearObjectStoreCallback;
     81 
     82 namespace blink {
     83 
     84 namespace IndexedDBAgentState {
     85 static const char indexedDBAgentEnabled[] = "indexedDBAgentEnabled";
     86 };
     87 
     88 namespace {
     89 
     90 class GetDatabaseNamesCallback FINAL : public EventListener {
     91     WTF_MAKE_NONCOPYABLE(GetDatabaseNamesCallback);
     92 public:
     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 
    128 private:
    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 
    137 class ExecutableWithDatabase : public RefCounted<ExecutableWithDatabase> {
    138 public:
    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(); }
    147 private:
    148     RefPtr<ScriptState> m_scriptState;
    149 };
    150 
    151 class OpenDatabaseCallback FINAL : public EventListener {
    152 public:
    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 
    185 private:
    186     OpenDatabaseCallback(ExecutableWithDatabase* executableWithDatabase)
    187         : EventListener(EventListener::CPPEventListenerType)
    188         , m_executableWithDatabase(executableWithDatabase) { }
    189     RefPtr<ExecutableWithDatabase> m_executableWithDatabase;
    190 };
    191 
    192 void 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 
    204 static 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 
    213 static 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 
    222 static 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 
    231 static 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 
    258 class DatabaseLoader FINAL : public ExecutableWithDatabase {
    259 public:
    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(); }
    309 private:
    310     DatabaseLoader(ScriptState* scriptState, PassRefPtrWillBeRawPtr<RequestDatabaseCallback> requestCallback)
    311         : ExecutableWithDatabase(scriptState)
    312         , m_requestCallback(requestCallback) { }
    313     RefPtrWillBePersistent<RequestDatabaseCallback> m_requestCallback;
    314 };
    315 
    316 static 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 
    362 static 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 
    387 class DataLoader;
    388 
    389 class OpenCursorCallback FINAL : public EventListener {
    390 public:
    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 
    472 private:
    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 
    490 class DataLoader FINAL : public ExecutableWithDatabase {
    491 public:
    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 
    551 LocalFrame* 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 
    565 void InspectorIndexedDBAgent::provideTo(Page* page)
    566 {
    567     OwnPtrWillBeRawPtr<InspectorIndexedDBAgent> agent(adoptPtrWillBeNoop(new InspectorIndexedDBAgent(page)));
    568     page->inspectorController().registerModuleAgent(agent.release());
    569 }
    570 
    571 InspectorIndexedDBAgent::InspectorIndexedDBAgent(Page* page)
    572     : InspectorBaseAgent<InspectorIndexedDBAgent>("IndexedDB")
    573     , m_page(page)
    574 {
    575 }
    576 
    577 InspectorIndexedDBAgent::~InspectorIndexedDBAgent()
    578 {
    579 }
    580 
    581 void InspectorIndexedDBAgent::clearFrontend()
    582 {
    583     disable(0);
    584 }
    585 
    586 void InspectorIndexedDBAgent::restore()
    587 {
    588     if (m_state->getBoolean(IndexedDBAgentState::indexedDBAgentEnabled)) {
    589         ErrorString error;
    590         enable(&error);
    591     }
    592 }
    593 
    594 void InspectorIndexedDBAgent::enable(ErrorString*)
    595 {
    596     m_state->setBoolean(IndexedDBAgentState::indexedDBAgentEnabled, true);
    597 }
    598 
    599 void InspectorIndexedDBAgent::disable(ErrorString*)
    600 {
    601     m_state->setBoolean(IndexedDBAgentState::indexedDBAgentEnabled, false);
    602 }
    603 
    604 static 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 
    614 static 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 
    629 void 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 
    650 void 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 
    666 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, 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 
    688 class ClearObjectStoreListener FINAL : public EventListener {
    689     WTF_MAKE_NONCOPYABLE(ClearObjectStoreListener);
    690 public:
    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     }
    714 private:
    715     ClearObjectStoreListener(PassRefPtrWillBeRawPtr<ClearObjectStoreCallback> requestCallback)
    716         : EventListener(EventListener::CPPEventListenerType)
    717         , m_requestCallback(requestCallback)
    718     {
    719     }
    720 
    721     RefPtrWillBePersistent<ClearObjectStoreCallback> m_requestCallback;
    722 };
    723 
    724 
    725 class ClearObjectStore FINAL : public ExecutableWithDatabase {
    726 public:
    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(); }
    766 private:
    767     const String m_objectStoreName;
    768     RefPtrWillBePersistent<ClearObjectStoreCallback> m_requestCallback;
    769 };
    770 
    771 void 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 
    787 void InspectorIndexedDBAgent::trace(Visitor* visitor)
    788 {
    789     visitor->trace(m_page);
    790     InspectorBaseAgent::trace(visitor);
    791 }
    792 
    793 } // namespace blink
    794