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