• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
create(PassRefPtrWillBeRawPtr<RequestDatabaseNamesCallback> requestCallback,const String & securityOrigin)93     static PassRefPtr<GetDatabaseNamesCallback> create(PassRefPtrWillBeRawPtr<RequestDatabaseNamesCallback> requestCallback, const String& securityOrigin)
94     {
95         return adoptRef(new GetDatabaseNamesCallback(requestCallback, securityOrigin));
96     }
97 
~GetDatabaseNamesCallback()98     virtual ~GetDatabaseNamesCallback() { }
99 
operator ==(const EventListener & other)100     virtual bool operator==(const EventListener& other) OVERRIDE
101     {
102         return this == &other;
103     }
104 
handleEvent(ExecutionContext *,Event * event)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:
GetDatabaseNamesCallback(PassRefPtrWillBeRawPtr<RequestDatabaseNamesCallback> requestCallback,const String & securityOrigin)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:
ExecutableWithDatabase(ScriptState * scriptState)139     ExecutableWithDatabase(ScriptState* scriptState)
140         : m_scriptState(scriptState) { }
~ExecutableWithDatabase()141     virtual ~ExecutableWithDatabase() { };
142     void start(IDBFactory*, SecurityOrigin*, const String& databaseName);
143     virtual void execute(IDBDatabase*) = 0;
144     virtual RequestCallback* requestCallback() = 0;
context() const145     ExecutionContext* context() const { return m_scriptState->executionContext(); }
scriptState() const146     ScriptState* scriptState() const { return m_scriptState.get(); }
147 private:
148     RefPtr<ScriptState> m_scriptState;
149 };
150 
151 class OpenDatabaseCallback FINAL : public EventListener {
152 public:
create(ExecutableWithDatabase * executableWithDatabase)153     static PassRefPtr<OpenDatabaseCallback> create(ExecutableWithDatabase* executableWithDatabase)
154     {
155         return adoptRef(new OpenDatabaseCallback(executableWithDatabase));
156     }
157 
~OpenDatabaseCallback()158     virtual ~OpenDatabaseCallback() { }
159 
operator ==(const EventListener & other)160     virtual bool operator==(const EventListener& other) OVERRIDE
161     {
162         return this == &other;
163     }
164 
handleEvent(ExecutionContext * context,Event * event)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:
OpenDatabaseCallback(ExecutableWithDatabase * executableWithDatabase)186     OpenDatabaseCallback(ExecutableWithDatabase* executableWithDatabase)
187         : EventListener(EventListener::CPPEventListenerType)
188         , m_executableWithDatabase(executableWithDatabase) { }
189     RefPtr<ExecutableWithDatabase> m_executableWithDatabase;
190 };
191 
start(IDBFactory * idbFactory,SecurityOrigin *,const String & databaseName)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 
transactionForDatabase(ScriptState * scriptState,IDBDatabase * idbDatabase,const String & objectStoreName,const String & mode=IndexedDBNames::readonly)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 
objectStoreForTransaction(IDBTransaction * idbTransaction,const String & objectStoreName)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 
indexForObjectStore(IDBObjectStore * idbObjectStore,const String & indexName)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 
keyPathFromIDBKeyPath(const IDBKeyPath & idbKeyPath)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:
create(ScriptState * scriptState,PassRefPtrWillBeRawPtr<RequestDatabaseCallback> requestCallback)260     static PassRefPtr<DatabaseLoader> create(ScriptState* scriptState, PassRefPtrWillBeRawPtr<RequestDatabaseCallback> requestCallback)
261     {
262         return adoptRef(new DatabaseLoader(scriptState, requestCallback));
263     }
264 
~DatabaseLoader()265     virtual ~DatabaseLoader() { }
266 
execute(IDBDatabase * idbDatabase)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 
requestCallback()308     virtual RequestCallback* requestCallback() OVERRIDE { return m_requestCallback.get(); }
309 private:
DatabaseLoader(ScriptState * scriptState,PassRefPtrWillBeRawPtr<RequestDatabaseCallback> requestCallback)310     DatabaseLoader(ScriptState* scriptState, PassRefPtrWillBeRawPtr<RequestDatabaseCallback> requestCallback)
311         : ExecutableWithDatabase(scriptState)
312         , m_requestCallback(requestCallback) { }
313     RefPtrWillBePersistent<RequestDatabaseCallback> m_requestCallback;
314 };
315 
idbKeyFromInspectorObject(JSONObject * key)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 
idbKeyRangeFromKeyRange(JSONObject * keyRange)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:
create(ScriptState * scriptState,PassRefPtrWillBeRawPtr<RequestDataCallback> requestCallback,int skipCount,unsigned pageSize)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 
~OpenCursorCallback()396     virtual ~OpenCursorCallback() { }
397 
operator ==(const EventListener & other)398     virtual bool operator==(const EventListener& other) OVERRIDE
399     {
400         return this == &other;
401     }
402 
handleEvent(ExecutionContext *,Event * event)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 
end(bool hasMore)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:
OpenCursorCallback(ScriptState * scriptState,PassRefPtrWillBeRawPtr<RequestDataCallback> requestCallback,int skipCount,unsigned pageSize)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:
create(ScriptState * scriptState,PassRefPtrWillBeRawPtr<RequestDataCallback> requestCallback,const String & objectStoreName,const String & indexName,IDBKeyRange * idbKeyRange,int skipCount,unsigned pageSize)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 
~DataLoader()497     virtual ~DataLoader() { }
498 
execute(IDBDatabase * idbDatabase)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 
requestCallback()531     virtual RequestCallback* requestCallback() OVERRIDE { return m_requestCallback.get(); }
DataLoader(ScriptState * scriptState,PassRefPtrWillBeRawPtr<RequestDataCallback> requestCallback,const String & objectStoreName,const String & indexName,IDBKeyRange * idbKeyRange,int skipCount,unsigned pageSize)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 
findFrameWithSecurityOrigin(Page * page,const String & securityOrigin)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 
provideTo(Page * page)565 void InspectorIndexedDBAgent::provideTo(Page* page)
566 {
567     OwnPtrWillBeRawPtr<InspectorIndexedDBAgent> agent(adoptPtrWillBeNoop(new InspectorIndexedDBAgent(page)));
568     page->inspectorController().registerModuleAgent(agent.release());
569 }
570 
InspectorIndexedDBAgent(Page * page)571 InspectorIndexedDBAgent::InspectorIndexedDBAgent(Page* page)
572     : InspectorBaseAgent<InspectorIndexedDBAgent>("IndexedDB")
573     , m_page(page)
574 {
575 }
576 
~InspectorIndexedDBAgent()577 InspectorIndexedDBAgent::~InspectorIndexedDBAgent()
578 {
579 }
580 
clearFrontend()581 void InspectorIndexedDBAgent::clearFrontend()
582 {
583     disable(0);
584 }
585 
restore()586 void InspectorIndexedDBAgent::restore()
587 {
588     if (m_state->getBoolean(IndexedDBAgentState::indexedDBAgentEnabled)) {
589         ErrorString error;
590         enable(&error);
591     }
592 }
593 
enable(ErrorString *)594 void InspectorIndexedDBAgent::enable(ErrorString*)
595 {
596     m_state->setBoolean(IndexedDBAgentState::indexedDBAgentEnabled, true);
597 }
598 
disable(ErrorString *)599 void InspectorIndexedDBAgent::disable(ErrorString*)
600 {
601     m_state->setBoolean(IndexedDBAgentState::indexedDBAgentEnabled, false);
602 }
603 
assertDocument(ErrorString * errorString,LocalFrame * frame)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 
assertIDBFactory(ErrorString * errorString,Document * document)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 
requestDatabaseNames(ErrorString * errorString,const String & securityOrigin,PassRefPtrWillBeRawPtr<RequestDatabaseNamesCallback> requestCallback)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 
requestDatabase(ErrorString * errorString,const String & securityOrigin,const String & databaseName,PassRefPtrWillBeRawPtr<RequestDatabaseCallback> requestCallback)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 
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)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:
create(PassRefPtrWillBeRawPtr<ClearObjectStoreCallback> requestCallback)691     static PassRefPtr<ClearObjectStoreListener> create(PassRefPtrWillBeRawPtr<ClearObjectStoreCallback> requestCallback)
692     {
693         return adoptRef(new ClearObjectStoreListener(requestCallback));
694     }
695 
~ClearObjectStoreListener()696     virtual ~ClearObjectStoreListener() { }
697 
operator ==(const EventListener & other)698     virtual bool operator==(const EventListener& other) OVERRIDE
699     {
700         return this == &other;
701     }
702 
handleEvent(ExecutionContext *,Event * event)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:
ClearObjectStoreListener(PassRefPtrWillBeRawPtr<ClearObjectStoreCallback> requestCallback)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:
create(ScriptState * scriptState,const String & objectStoreName,PassRefPtrWillBeRawPtr<ClearObjectStoreCallback> requestCallback)727     static PassRefPtr<ClearObjectStore> create(ScriptState* scriptState, const String& objectStoreName, PassRefPtrWillBeRawPtr<ClearObjectStoreCallback> requestCallback)
728     {
729         return adoptRef(new ClearObjectStore(scriptState, objectStoreName, requestCallback));
730     }
731 
ClearObjectStore(ScriptState * scriptState,const String & objectStoreName,PassRefPtrWillBeRawPtr<ClearObjectStoreCallback> requestCallback)732     ClearObjectStore(ScriptState* scriptState, const String& objectStoreName, PassRefPtrWillBeRawPtr<ClearObjectStoreCallback> requestCallback)
733         : ExecutableWithDatabase(scriptState)
734         , m_objectStoreName(objectStoreName)
735         , m_requestCallback(requestCallback)
736     {
737     }
738 
execute(IDBDatabase * idbDatabase)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 
requestCallback()765     virtual RequestCallback* requestCallback() OVERRIDE { return m_requestCallback.get(); }
766 private:
767     const String m_objectStoreName;
768     RefPtrWillBePersistent<ClearObjectStoreCallback> m_requestCallback;
769 };
770 
clearObjectStore(ErrorString * errorString,const String & securityOrigin,const String & databaseName,const String & objectStoreName,PassRefPtrWillBeRawPtr<ClearObjectStoreCallback> requestCallback)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 
trace(Visitor * visitor)787 void InspectorIndexedDBAgent::trace(Visitor* visitor)
788 {
789     visitor->trace(m_page);
790     InspectorBaseAgent::trace(visitor);
791 }
792 
793 } // namespace blink
794