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