Home | History | Annotate | Download | only in indexeddb
      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