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