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