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