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