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: 92 static PassRefPtr<GetDatabaseNamesCallback> create(PassRefPtr<RequestDatabaseNamesCallback> requestCallback, const String& securityOrigin) 93 { 94 return adoptRef(new GetDatabaseNamesCallback(requestCallback, securityOrigin)); 95 } 96 97 virtual ~GetDatabaseNamesCallback() { } 98 99 virtual bool operator==(const EventListener& other) OVERRIDE 100 { 101 return this == &other; 102 } 103 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: 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: 138 ExecutableWithDatabase(ScriptState* scriptState) 139 : m_scriptState(scriptState) { } 140 virtual ~ExecutableWithDatabase() { }; 141 void start(IDBFactory*, SecurityOrigin*, const String& databaseName); 142 virtual void execute(IDBDatabase*) = 0; 143 virtual RequestCallback* requestCallback() = 0; 144 ExecutionContext* context() const { return m_scriptState->executionContext(); } 145 ScriptState* scriptState() const { return m_scriptState.get(); } 146 private: 147 RefPtr<ScriptState> m_scriptState; 148 }; 149 150 class OpenDatabaseCallback FINAL : public EventListener { 151 public: 152 static PassRefPtr<OpenDatabaseCallback> create(ExecutableWithDatabase* executableWithDatabase) 153 { 154 return adoptRef(new OpenDatabaseCallback(executableWithDatabase)); 155 } 156 157 virtual ~OpenDatabaseCallback() { } 158 159 virtual bool operator==(const EventListener& other) OVERRIDE 160 { 161 return this == &other; 162 } 163 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: 185 OpenDatabaseCallback(ExecutableWithDatabase* executableWithDatabase) 186 : EventListener(EventListener::CPPEventListenerType) 187 , m_executableWithDatabase(executableWithDatabase) { } 188 RefPtr<ExecutableWithDatabase> m_executableWithDatabase; 189 }; 190 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 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 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 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 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: 259 static PassRefPtr<DatabaseLoader> create(ScriptState* scriptState, PassRefPtr<RequestDatabaseCallback> requestCallback) 260 { 261 return adoptRef(new DatabaseLoader(scriptState, requestCallback)); 262 } 263 264 virtual ~DatabaseLoader() { } 265 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 307 virtual RequestCallback* requestCallback() OVERRIDE { return m_requestCallback.get(); } 308 private: 309 DatabaseLoader(ScriptState* scriptState, PassRefPtr<RequestDatabaseCallback> requestCallback) 310 : ExecutableWithDatabase(scriptState) 311 , m_requestCallback(requestCallback) { } 312 RefPtr<RequestDatabaseCallback> m_requestCallback; 313 }; 314 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 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: 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 395 virtual ~OpenCursorCallback() { } 396 397 virtual bool operator==(const EventListener& other) OVERRIDE 398 { 399 return this == &other; 400 } 401 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 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: 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: 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 487 virtual ~DataLoader() { } 488 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 521 virtual RequestCallback* requestCallback() OVERRIDE { return m_requestCallback.get(); } 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 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 555 void InspectorIndexedDBAgent::provideTo(Page* page) 556 { 557 OwnPtr<InspectorIndexedDBAgent> agent(adoptPtr(new InspectorIndexedDBAgent(page))); 558 page->inspectorController().registerModuleAgent(agent.release()); 559 } 560 561 InspectorIndexedDBAgent::InspectorIndexedDBAgent(Page* page) 562 : InspectorBaseAgent<InspectorIndexedDBAgent>("IndexedDB") 563 , m_page(page) 564 { 565 } 566 567 InspectorIndexedDBAgent::~InspectorIndexedDBAgent() 568 { 569 } 570 571 void InspectorIndexedDBAgent::clearFrontend() 572 { 573 disable(0); 574 } 575 576 void InspectorIndexedDBAgent::restore() 577 { 578 if (m_state->getBoolean(IndexedDBAgentState::indexedDBAgentEnabled)) { 579 ErrorString error; 580 enable(&error); 581 } 582 } 583 584 void InspectorIndexedDBAgent::enable(ErrorString*) 585 { 586 m_state->setBoolean(IndexedDBAgentState::indexedDBAgentEnabled, true); 587 } 588 589 void InspectorIndexedDBAgent::disable(ErrorString*) 590 { 591 m_state->setBoolean(IndexedDBAgentState::indexedDBAgentEnabled, false); 592 } 593 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 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 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 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 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: 681 static PassRefPtr<ClearObjectStoreListener> create(PassRefPtr<ClearObjectStoreCallback> requestCallback) 682 { 683 return adoptRef(new ClearObjectStoreListener(requestCallback)); 684 } 685 686 virtual ~ClearObjectStoreListener() { } 687 688 virtual bool operator==(const EventListener& other) OVERRIDE 689 { 690 return this == &other; 691 } 692 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: 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: 717 static PassRefPtr<ClearObjectStore> create(ScriptState* scriptState, const String& objectStoreName, PassRefPtr<ClearObjectStoreCallback> requestCallback) 718 { 719 return adoptRef(new ClearObjectStore(scriptState, objectStoreName, requestCallback)); 720 } 721 722 ClearObjectStore(ScriptState* scriptState, const String& objectStoreName, PassRefPtr<ClearObjectStoreCallback> requestCallback) 723 : ExecutableWithDatabase(scriptState) 724 , m_objectStoreName(objectStoreName) 725 , m_requestCallback(requestCallback) 726 { 727 } 728 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 755 virtual RequestCallback* requestCallback() OVERRIDE { return m_requestCallback.get(); } 756 private: 757 const String m_objectStoreName; 758 RefPtr<ClearObjectStoreCallback> m_requestCallback; 759 }; 760 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