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