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