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