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