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