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