1 /* 2 * Copyright (C) 2010 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 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 14 * its contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include "config.h" 30 #include "modules/indexeddb/IDBRequest.h" 31 32 #include "bindings/core/v8/ExceptionState.h" 33 #include "bindings/core/v8/ExceptionStatePlaceholder.h" 34 #include "bindings/modules/v8/IDBBindingUtilities.h" 35 #include "core/dom/ExecutionContext.h" 36 #include "core/events/EventQueue.h" 37 #include "modules/IndexedDBNames.h" 38 #include "modules/indexeddb/IDBCursorWithValue.h" 39 #include "modules/indexeddb/IDBDatabase.h" 40 #include "modules/indexeddb/IDBEventDispatcher.h" 41 #include "modules/indexeddb/IDBPendingTransactionMonitor.h" 42 #include "modules/indexeddb/IDBTracing.h" 43 #include "platform/SharedBuffer.h" 44 #include "public/platform/WebBlobInfo.h" 45 46 using blink::WebIDBCursor; 47 48 namespace blink { 49 50 IDBRequest* IDBRequest::create(ScriptState* scriptState, IDBAny* source, IDBTransaction* transaction) 51 { 52 IDBRequest* request = adoptRefCountedGarbageCollectedWillBeNoop(new IDBRequest(scriptState, source, transaction)); 53 request->suspendIfNeeded(); 54 // Requests associated with IDBFactory (open/deleteDatabase/getDatabaseNames) are not associated with transactions. 55 if (transaction) 56 transaction->registerRequest(request); 57 return request; 58 } 59 60 IDBRequest::IDBRequest(ScriptState* scriptState, IDBAny* source, IDBTransaction* transaction) 61 : ActiveDOMObject(scriptState->executionContext()) 62 , m_contextStopped(false) 63 , m_transaction(transaction) 64 , m_readyState(PENDING) 65 , m_requestAborted(false) 66 , m_scriptState(scriptState) 67 , m_source(source) 68 , m_hasPendingActivity(true) 69 , m_cursorType(IndexedDB::CursorKeyAndValue) 70 , m_cursorDirection(WebIDBCursorDirectionNext) 71 , m_pendingCursor(nullptr) 72 , m_didFireUpgradeNeededEvent(false) 73 , m_preventPropagation(false) 74 , m_resultDirty(true) 75 { 76 } 77 78 IDBRequest::~IDBRequest() 79 { 80 ASSERT(m_readyState == DONE || m_readyState == EarlyDeath || !executionContext()); 81 ASSERT(!m_blobInfo || m_blobInfo->size() == 0); 82 } 83 84 void IDBRequest::dispose() 85 { 86 handleBlobAcks(); 87 } 88 89 void IDBRequest::trace(Visitor* visitor) 90 { 91 visitor->trace(m_transaction); 92 visitor->trace(m_source); 93 visitor->trace(m_result); 94 visitor->trace(m_error); 95 #if ENABLE(OILPAN) 96 visitor->trace(m_enqueuedEvents); 97 #endif 98 visitor->trace(m_pendingCursor); 99 visitor->trace(m_cursorKey); 100 visitor->trace(m_cursorPrimaryKey); 101 EventTargetWithInlineData::trace(visitor); 102 } 103 104 ScriptValue IDBRequest::result(ExceptionState& exceptionState) 105 { 106 if (m_readyState != DONE) { 107 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::requestNotFinishedErrorMessage); 108 return ScriptValue(); 109 } 110 if (m_contextStopped || !executionContext()) 111 return ScriptValue(); 112 m_resultDirty = false; 113 ScriptValue value = idbAnyToScriptValue(m_scriptState.get(), m_result); 114 handleBlobAcks(); 115 return value; 116 } 117 118 PassRefPtrWillBeRawPtr<DOMError> IDBRequest::error(ExceptionState& exceptionState) const 119 { 120 if (m_readyState != DONE) { 121 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::requestNotFinishedErrorMessage); 122 return nullptr; 123 } 124 return m_error; 125 } 126 127 ScriptValue IDBRequest::source() const 128 { 129 if (m_contextStopped || !executionContext()) 130 return ScriptValue(); 131 132 return idbAnyToScriptValue(m_scriptState.get(), m_source); 133 } 134 135 const String& IDBRequest::readyState() const 136 { 137 ASSERT(m_readyState == PENDING || m_readyState == DONE); 138 139 if (m_readyState == PENDING) 140 return IndexedDBNames::pending; 141 142 return IndexedDBNames::done; 143 } 144 145 void IDBRequest::abort() 146 { 147 ASSERT(!m_requestAborted); 148 if (m_contextStopped || !executionContext()) 149 return; 150 ASSERT(m_readyState == PENDING || m_readyState == DONE); 151 if (m_readyState == DONE) 152 return; 153 154 EventQueue* eventQueue = executionContext()->eventQueue(); 155 for (size_t i = 0; i < m_enqueuedEvents.size(); ++i) { 156 bool removed = eventQueue->cancelEvent(m_enqueuedEvents[i].get()); 157 ASSERT_UNUSED(removed, removed); 158 } 159 m_enqueuedEvents.clear(); 160 161 m_error.clear(); 162 m_result.clear(); 163 onError(DOMError::create(AbortError, "The transaction was aborted, so the request cannot be fulfilled.")); 164 m_requestAborted = true; 165 } 166 167 void IDBRequest::setCursorDetails(IndexedDB::CursorType cursorType, WebIDBCursorDirection direction) 168 { 169 ASSERT(m_readyState == PENDING); 170 ASSERT(!m_pendingCursor); 171 m_cursorType = cursorType; 172 m_cursorDirection = direction; 173 } 174 175 void IDBRequest::setPendingCursor(IDBCursor* cursor) 176 { 177 ASSERT(m_readyState == DONE); 178 ASSERT(executionContext()); 179 ASSERT(m_transaction); 180 ASSERT(!m_pendingCursor); 181 ASSERT(cursor == getResultCursor()); 182 183 m_hasPendingActivity = true; 184 m_pendingCursor = cursor; 185 setResult(0); 186 m_readyState = PENDING; 187 m_error.clear(); 188 m_transaction->registerRequest(this); 189 } 190 191 IDBCursor* IDBRequest::getResultCursor() const 192 { 193 if (!m_result) 194 return 0; 195 if (m_result->type() == IDBAny::IDBCursorType) 196 return m_result->idbCursor(); 197 if (m_result->type() == IDBAny::IDBCursorWithValueType) 198 return m_result->idbCursorWithValue(); 199 return 0; 200 } 201 202 void IDBRequest::setResultCursor(IDBCursor* cursor, IDBKey* key, IDBKey* primaryKey, PassRefPtr<SharedBuffer> value, PassOwnPtr<Vector<WebBlobInfo> > blobInfo) 203 { 204 ASSERT(m_readyState == PENDING); 205 m_cursorKey = key; 206 m_cursorPrimaryKey = primaryKey; 207 m_cursorValue = value; 208 setBlobInfo(blobInfo); 209 210 onSuccessInternal(IDBAny::create(cursor)); 211 } 212 213 void IDBRequest::setBlobInfo(PassOwnPtr<Vector<WebBlobInfo>> blobInfo) 214 { 215 ASSERT(!m_blobInfo); 216 m_blobInfo = blobInfo; 217 if (m_blobInfo && m_blobInfo->size() > 0) 218 V8PerIsolateData::from(scriptState()->isolate())->ensureIDBPendingTransactionMonitor()->registerRequest(*this); 219 } 220 221 void IDBRequest::handleBlobAcks() 222 { 223 if (m_blobInfo.get() && m_blobInfo->size()) { 224 m_transaction->db()->ackReceivedBlobs(m_blobInfo.get()); 225 m_blobInfo.clear(); 226 V8PerIsolateData::from(scriptState()->isolate())->ensureIDBPendingTransactionMonitor()->unregisterRequest(*this); 227 } 228 } 229 230 bool IDBRequest::shouldEnqueueEvent() const 231 { 232 if (m_contextStopped || !executionContext()) 233 return false; 234 ASSERT(m_readyState == PENDING || m_readyState == DONE); 235 if (m_requestAborted) 236 return false; 237 ASSERT(m_readyState == PENDING); 238 ASSERT(!m_error && !m_result); 239 return true; 240 } 241 242 void IDBRequest::onError(PassRefPtrWillBeRawPtr<DOMError> error) 243 { 244 IDB_TRACE("IDBRequest::onError()"); 245 if (!shouldEnqueueEvent()) 246 return; 247 248 m_error = error; 249 setResult(IDBAny::createUndefined()); 250 m_pendingCursor.clear(); 251 enqueueEvent(Event::createCancelableBubble(EventTypeNames::error)); 252 } 253 254 void IDBRequest::onSuccess(const Vector<String>& stringList) 255 { 256 IDB_TRACE("IDBRequest::onSuccess(StringList)"); 257 if (!shouldEnqueueEvent()) 258 return; 259 260 RefPtrWillBeRawPtr<DOMStringList> domStringList = DOMStringList::create(); 261 for (size_t i = 0; i < stringList.size(); ++i) 262 domStringList->append(stringList[i]); 263 onSuccessInternal(IDBAny::create(domStringList.release())); 264 } 265 266 void IDBRequest::onSuccess(PassOwnPtr<WebIDBCursor> backend, IDBKey* key, IDBKey* primaryKey, PassRefPtr<SharedBuffer> value, PassOwnPtr<Vector<WebBlobInfo> > blobInfo) 267 { 268 IDB_TRACE("IDBRequest::onSuccess(IDBCursor)"); 269 if (!shouldEnqueueEvent()) 270 return; 271 272 ASSERT(!m_pendingCursor); 273 IDBCursor* cursor = 0; 274 switch (m_cursorType) { 275 case IndexedDB::CursorKeyOnly: 276 cursor = IDBCursor::create(backend, m_cursorDirection, this, m_source.get(), m_transaction.get()); 277 break; 278 case IndexedDB::CursorKeyAndValue: 279 cursor = IDBCursorWithValue::create(backend, m_cursorDirection, this, m_source.get(), m_transaction.get()); 280 break; 281 default: 282 ASSERT_NOT_REACHED(); 283 } 284 setResultCursor(cursor, key, primaryKey, value, blobInfo); 285 } 286 287 void IDBRequest::onSuccess(IDBKey* idbKey) 288 { 289 IDB_TRACE("IDBRequest::onSuccess(IDBKey)"); 290 if (!shouldEnqueueEvent()) 291 return; 292 293 if (idbKey && idbKey->isValid()) 294 onSuccessInternal(IDBAny::create(idbKey)); 295 else 296 onSuccessInternal(IDBAny::createUndefined()); 297 } 298 299 void IDBRequest::onSuccess(PassRefPtr<SharedBuffer> valueBuffer, PassOwnPtr<Vector<WebBlobInfo> > blobInfo) 300 { 301 IDB_TRACE("IDBRequest::onSuccess(SharedBuffer)"); 302 if (!shouldEnqueueEvent()) 303 return; 304 305 if (m_pendingCursor) { 306 // Value should be null, signifying the end of the cursor's range. 307 ASSERT(!valueBuffer.get()); 308 ASSERT(!blobInfo->size()); 309 m_pendingCursor->close(); 310 m_pendingCursor.clear(); 311 } 312 313 setBlobInfo(blobInfo); 314 onSuccessInternal(IDBAny::create(valueBuffer, m_blobInfo.get())); 315 } 316 317 #if ENABLE(ASSERT) 318 static IDBObjectStore* effectiveObjectStore(IDBAny* source) 319 { 320 if (source->type() == IDBAny::IDBObjectStoreType) 321 return source->idbObjectStore(); 322 if (source->type() == IDBAny::IDBIndexType) 323 return source->idbIndex()->objectStore(); 324 325 ASSERT_NOT_REACHED(); 326 return 0; 327 } 328 #endif 329 330 void IDBRequest::onSuccess(PassRefPtr<SharedBuffer> prpValueBuffer, PassOwnPtr<Vector<WebBlobInfo> > blobInfo, IDBKey* prpPrimaryKey, const IDBKeyPath& keyPath) 331 { 332 IDB_TRACE("IDBRequest::onSuccess(SharedBuffer, IDBKey, IDBKeyPath)"); 333 if (!shouldEnqueueEvent()) 334 return; 335 336 ASSERT(keyPath == effectiveObjectStore(m_source)->metadata().keyPath); 337 338 RefPtr<SharedBuffer> valueBuffer = prpValueBuffer; 339 IDBKey* primaryKey = prpPrimaryKey; 340 setBlobInfo(blobInfo); 341 342 #if ENABLE(ASSERT) 343 assertPrimaryKeyValidOrInjectable(m_scriptState.get(), valueBuffer, m_blobInfo.get(), primaryKey, keyPath); 344 #endif 345 346 onSuccessInternal(IDBAny::create(valueBuffer, m_blobInfo.get(), primaryKey, keyPath)); 347 } 348 349 void IDBRequest::onSuccess(int64_t value) 350 { 351 IDB_TRACE("IDBRequest::onSuccess(int64_t)"); 352 if (!shouldEnqueueEvent()) 353 return; 354 onSuccessInternal(IDBAny::create(value)); 355 } 356 357 void IDBRequest::onSuccess() 358 { 359 IDB_TRACE("IDBRequest::onSuccess()"); 360 if (!shouldEnqueueEvent()) 361 return; 362 onSuccessInternal(IDBAny::createUndefined()); 363 } 364 365 void IDBRequest::onSuccessInternal(IDBAny* result) 366 { 367 ASSERT(!m_contextStopped); 368 ASSERT(!m_pendingCursor); 369 setResult(result); 370 enqueueEvent(Event::create(EventTypeNames::success)); 371 } 372 373 void IDBRequest::setResult(IDBAny* result) 374 { 375 m_result = result; 376 m_resultDirty = true; 377 } 378 379 void IDBRequest::onSuccess(IDBKey* key, IDBKey* primaryKey, PassRefPtr<SharedBuffer> value, PassOwnPtr<Vector<WebBlobInfo> > blobInfo) 380 { 381 IDB_TRACE("IDBRequest::onSuccess(key, primaryKey, value)"); 382 if (!shouldEnqueueEvent()) 383 return; 384 385 ASSERT(m_pendingCursor); 386 setResultCursor(m_pendingCursor.release(), key, primaryKey, value, blobInfo); 387 } 388 389 bool IDBRequest::hasPendingActivity() const 390 { 391 // FIXME: In an ideal world, we should return true as long as anyone has a or can 392 // get a handle to us and we have event listeners. This is order to handle 393 // user generated events properly. 394 return m_hasPendingActivity && !m_contextStopped; 395 } 396 397 void IDBRequest::stop() 398 { 399 if (m_contextStopped) 400 return; 401 402 m_contextStopped = true; 403 404 if (m_readyState == PENDING) { 405 m_readyState = EarlyDeath; 406 if (m_transaction) { 407 m_transaction->unregisterRequest(this); 408 m_transaction.clear(); 409 } 410 } 411 412 m_enqueuedEvents.clear(); 413 if (m_source) 414 m_source->contextWillBeDestroyed(); 415 if (m_result) 416 m_result->contextWillBeDestroyed(); 417 if (m_pendingCursor) 418 m_pendingCursor->contextWillBeDestroyed(); 419 } 420 421 const AtomicString& IDBRequest::interfaceName() const 422 { 423 return EventTargetNames::IDBRequest; 424 } 425 426 ExecutionContext* IDBRequest::executionContext() const 427 { 428 return ActiveDOMObject::executionContext(); 429 } 430 431 bool IDBRequest::dispatchEvent(PassRefPtrWillBeRawPtr<Event> event) 432 { 433 IDB_TRACE("IDBRequest::dispatchEvent"); 434 if (m_contextStopped || !executionContext()) 435 return false; 436 ASSERT(m_readyState == PENDING); 437 ASSERT(m_hasPendingActivity); 438 ASSERT(m_enqueuedEvents.size()); 439 ASSERT(event->target() == this); 440 441 ScriptState::Scope scope(m_scriptState.get()); 442 443 if (event->type() != EventTypeNames::blocked) 444 m_readyState = DONE; 445 dequeueEvent(event.get()); 446 447 WillBeHeapVector<RefPtrWillBeMember<EventTarget> > targets; 448 targets.append(this); 449 if (m_transaction && !m_preventPropagation) { 450 targets.append(m_transaction); 451 // If there ever are events that are associated with a database but 452 // that do not have a transaction, then this will not work and we need 453 // this object to actually hold a reference to the database (to ensure 454 // it stays alive). 455 targets.append(m_transaction->db()); 456 } 457 458 // Cursor properties should not be updated until the success event is being dispatched. 459 IDBCursor* cursorToNotify = 0; 460 if (event->type() == EventTypeNames::success) { 461 cursorToNotify = getResultCursor(); 462 if (cursorToNotify) { 463 if (m_blobInfo && m_blobInfo->size() > 0) 464 V8PerIsolateData::from(scriptState()->isolate())->ensureIDBPendingTransactionMonitor()->unregisterRequest(*this); 465 cursorToNotify->setValueReady(m_cursorKey.release(), m_cursorPrimaryKey.release(), m_cursorValue.release(), m_blobInfo.release()); 466 } 467 } 468 469 if (event->type() == EventTypeNames::upgradeneeded) { 470 ASSERT(!m_didFireUpgradeNeededEvent); 471 m_didFireUpgradeNeededEvent = true; 472 } 473 474 // FIXME: When we allow custom event dispatching, this will probably need to change. 475 ASSERT_WITH_MESSAGE(event->type() == EventTypeNames::success || event->type() == EventTypeNames::error || event->type() == EventTypeNames::blocked || event->type() == EventTypeNames::upgradeneeded, "event type was %s", event->type().utf8().data()); 476 const bool setTransactionActive = m_transaction && (event->type() == EventTypeNames::success || event->type() == EventTypeNames::upgradeneeded || (event->type() == EventTypeNames::error && !m_requestAborted)); 477 478 if (setTransactionActive) 479 m_transaction->setActive(true); 480 481 bool dontPreventDefault = IDBEventDispatcher::dispatch(event.get(), targets); 482 483 if (m_transaction) { 484 if (m_readyState == DONE) 485 m_transaction->unregisterRequest(this); 486 487 // Possibly abort the transaction. This must occur after unregistering (so this request 488 // doesn't receive a second error) and before deactivating (which might trigger commit). 489 if (event->type() == EventTypeNames::error && dontPreventDefault && !m_requestAborted) { 490 m_transaction->setError(m_error); 491 m_transaction->abort(IGNORE_EXCEPTION); 492 } 493 494 // If this was the last request in the transaction's list, it may commit here. 495 if (setTransactionActive) 496 m_transaction->setActive(false); 497 } 498 499 if (cursorToNotify) 500 cursorToNotify->postSuccessHandlerCallback(); 501 502 // An upgradeneeded event will always be followed by a success or error event, so must 503 // be kept alive. 504 if (m_readyState == DONE && event->type() != EventTypeNames::upgradeneeded) 505 m_hasPendingActivity = false; 506 507 return dontPreventDefault; 508 } 509 510 void IDBRequest::uncaughtExceptionInEventHandler() 511 { 512 if (m_transaction && !m_requestAborted) { 513 m_transaction->setError(DOMError::create(AbortError, "Uncaught exception in event handler.")); 514 m_transaction->abort(IGNORE_EXCEPTION); 515 } 516 } 517 518 void IDBRequest::transactionDidFinishAndDispatch() 519 { 520 ASSERT(m_transaction); 521 ASSERT(m_transaction->isVersionChange()); 522 ASSERT(m_didFireUpgradeNeededEvent); 523 ASSERT(m_readyState == DONE); 524 ASSERT(executionContext()); 525 m_transaction.clear(); 526 527 if (m_contextStopped) 528 return; 529 530 m_readyState = PENDING; 531 } 532 533 void IDBRequest::enqueueEvent(PassRefPtrWillBeRawPtr<Event> event) 534 { 535 ASSERT(m_readyState == PENDING || m_readyState == DONE); 536 537 if (m_contextStopped || !executionContext()) 538 return; 539 540 ASSERT_WITH_MESSAGE(m_readyState == PENDING || m_didFireUpgradeNeededEvent, "When queueing event %s, m_readyState was %d", event->type().utf8().data(), m_readyState); 541 542 EventQueue* eventQueue = executionContext()->eventQueue(); 543 event->setTarget(this); 544 545 // Keep track of enqueued events in case we need to abort prior to dispatch, 546 // in which case these must be cancelled. If the events not dispatched for 547 // other reasons they must be removed from this list via dequeueEvent(). 548 if (eventQueue->enqueueEvent(event.get())) 549 m_enqueuedEvents.append(event); 550 } 551 552 void IDBRequest::dequeueEvent(Event* event) 553 { 554 for (size_t i = 0; i < m_enqueuedEvents.size(); ++i) { 555 if (m_enqueuedEvents[i].get() == event) 556 m_enqueuedEvents.remove(i); 557 } 558 } 559 560 } // namespace blink 561