63a48be935a5fb46d752f71153a6db95019b6d7f
[WebKit-https.git] / Source / WebCore / 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 "IDBRequest.h"
31
32 #if ENABLE(INDEXED_DATABASE)
33
34 #include "EventException.h"
35 #include "EventListener.h"
36 #include "EventNames.h"
37 #include "EventQueue.h"
38 #include "IDBBindingUtilities.h"
39 #include "IDBCursorWithValue.h"
40 #include "IDBDatabase.h"
41 #include "IDBEventDispatcher.h"
42 #include "IDBTracing.h"
43 #include "IDBTransaction.h"
44
45 namespace WebCore {
46
47 PassRefPtr<IDBRequest> IDBRequest::create(ScriptExecutionContext* context, PassRefPtr<IDBAny> source, IDBTransaction* transaction)
48 {
49     RefPtr<IDBRequest> request(adoptRef(new IDBRequest(context, source, transaction)));
50     request->suspendIfNeeded();
51     return request.release();
52 }
53
54 IDBRequest::IDBRequest(ScriptExecutionContext* context, PassRefPtr<IDBAny> source, IDBTransaction* transaction)
55     : ActiveDOMObject(context, this)
56     , m_errorCode(0)
57     , m_source(source)
58     , m_transaction(transaction)
59     , m_readyState(PENDING)
60     , m_requestAborted(false)
61     , m_requestFinished(false)
62     , m_cursorFinished(false)
63     , m_contextStopped(false)
64     , m_cursorType(IDBCursorBackendInterface::InvalidCursorType)
65     , m_cursorDirection(IDBCursor::NEXT)
66     , m_cursor(0)
67 {
68     if (m_transaction) {
69         m_transaction->registerRequest(this);
70     }
71 }
72
73 IDBRequest::~IDBRequest()
74 {
75     ASSERT(m_readyState == DONE || m_readyState == EarlyDeath || !scriptExecutionContext());
76 }
77
78 PassRefPtr<IDBAny> IDBRequest::result(ExceptionCode& ec) const
79 {
80     if (m_readyState != DONE) {
81         ec = IDBDatabaseException::IDB_INVALID_STATE_ERR;
82         return 0;
83     }
84     return m_result;
85 }
86
87 PassRefPtr<DOMError> IDBRequest::error(ExceptionCode& ec) const
88 {
89     if (m_readyState != DONE) {
90         ec = IDBDatabaseException::IDB_INVALID_STATE_ERR;
91         return 0;
92     }
93     return m_error;
94 }
95
96 unsigned short IDBRequest::errorCode(ExceptionCode& ec) const
97 {
98     if (m_readyState != DONE) {
99         ec = IDBDatabaseException::IDB_INVALID_STATE_ERR;
100         return 0;
101     }
102     return m_errorCode;
103 }
104
105 String IDBRequest::webkitErrorMessage(ExceptionCode& ec) const
106 {
107     if (m_readyState != DONE) {
108         ec = IDBDatabaseException::IDB_INVALID_STATE_ERR;
109         return String();
110     }
111     return m_errorMessage;
112 }
113
114 PassRefPtr<IDBAny> IDBRequest::source() const
115 {
116     return m_source;
117 }
118
119 PassRefPtr<IDBTransaction> IDBRequest::transaction() const
120 {
121     return m_transaction;
122 }
123
124 const String& IDBRequest::readyState() const
125 {
126     ASSERT(m_readyState == PENDING || m_readyState == DONE);
127     DEFINE_STATIC_LOCAL(AtomicString, pending, ("pending"));
128     DEFINE_STATIC_LOCAL(AtomicString, done, ("done"));
129
130     if (m_readyState == PENDING)
131         return pending;
132
133     return done;
134 }
135
136 void IDBRequest::markEarlyDeath()
137 {
138     ASSERT(m_readyState == PENDING);
139     m_readyState = EarlyDeath;
140     if (m_transaction)
141         m_transaction->unregisterRequest(this);
142 }
143
144 bool IDBRequest::resetReadyState(IDBTransaction* transaction)
145 {
146     ASSERT(!m_requestFinished);
147     ASSERT(scriptExecutionContext());
148     ASSERT_UNUSED(transaction, transaction == m_transaction);
149     if (m_readyState != DONE)
150         return false;
151
152     m_readyState = PENDING;
153     m_result.clear();
154     m_errorCode = 0;
155     m_error.clear();
156     m_errorMessage = String();
157     ASSERT(m_transaction);
158     m_transaction->registerRequest(this);
159
160     return true;
161 }
162
163 IDBAny* IDBRequest::source()
164 {
165     return m_source.get();
166 }
167
168 void IDBRequest::abort()
169 {
170     ASSERT(!m_requestAborted);
171     if (m_contextStopped || !scriptExecutionContext())
172         return;
173
174     if (m_readyState != PENDING) {
175         ASSERT(m_readyState == DONE);
176         return;
177     }
178
179     EventQueue* eventQueue = scriptExecutionContext()->eventQueue();
180     for (size_t i = 0; i < m_enqueuedEvents.size(); ++i) {
181         bool removed = eventQueue->cancelEvent(m_enqueuedEvents[i].get());
182         ASSERT_UNUSED(removed, removed);
183     }
184     m_enqueuedEvents.clear();
185
186     m_errorCode = 0;
187     m_error.clear();
188     m_errorMessage = String();
189     m_result.clear();
190     onError(IDBDatabaseError::create(IDBDatabaseException::IDB_ABORT_ERR, "The transaction was aborted, so the request cannot be fulfilled."));
191     m_requestAborted = true;
192 }
193
194 void IDBRequest::setCursorDetails(IDBCursorBackendInterface::CursorType cursorType, IDBCursor::Direction direction)
195 {
196     ASSERT(m_cursorType == IDBCursorBackendInterface::InvalidCursorType);
197     m_cursorType = cursorType;
198     m_cursorDirection = direction;
199 }
200
201 void IDBRequest::setCursor(PassRefPtr<IDBCursor> cursor)
202 {
203     ASSERT(!m_cursor);
204     m_cursor = cursor;
205 }
206
207 void IDBRequest::finishCursor()
208 {
209     m_cursorFinished = true;
210     if (m_readyState != PENDING)
211         m_requestFinished = true;
212 }
213
214 void IDBRequest::onError(PassRefPtr<IDBDatabaseError> error)
215 {
216     if (m_requestAborted)
217         return;
218     ASSERT(!m_errorCode && m_errorMessage.isNull() && !m_result);
219     m_errorCode = error->code();
220     ASSERT(!m_error);
221     m_error = DOMError::create(IDBDatabaseException::getErrorName(error->idbCode()));
222     m_errorMessage = error->message();
223     m_cursor.clear();
224     enqueueEvent(Event::create(eventNames().errorEvent, true, true));
225 }
226
227 static PassRefPtr<Event> createSuccessEvent()
228 {
229     return Event::create(eventNames().successEvent, false, false);
230 }
231
232 void IDBRequest::onSuccess(PassRefPtr<DOMStringList> domStringList)
233 {
234     IDB_TRACE("IDBRequest::onSuccess(DOMStringList)");
235     if (m_requestAborted)
236         return;
237     ASSERT(!m_errorCode && m_errorMessage.isNull() && !m_error && !m_result);
238     m_result = IDBAny::create(domStringList);
239     enqueueEvent(createSuccessEvent());
240 }
241
242 void IDBRequest::onSuccess(PassRefPtr<IDBCursorBackendInterface> backend)
243 {
244     IDB_TRACE("IDBRequest::onSuccess(IDBCursor)");
245     if (m_requestAborted)
246         return;
247     ASSERT(!m_errorCode && m_errorMessage.isNull() && !m_error && !m_result);
248     ASSERT(m_cursorType != IDBCursorBackendInterface::InvalidCursorType);
249     RefPtr<IDBCursor> cursor;
250     if (m_cursorType == IDBCursorBackendInterface::IndexKeyCursor)
251         cursor = IDBCursor::create(backend, m_cursorDirection, this, m_source.get(), m_transaction.get());
252     else
253         cursor = IDBCursorWithValue::create(backend, m_cursorDirection, this, m_source.get(), m_transaction.get());
254     setResultCursor(cursor, m_cursorType);
255
256     enqueueEvent(createSuccessEvent());
257 }
258
259 void IDBRequest::onSuccess(PassRefPtr<IDBDatabaseBackendInterface> backend)
260 {
261     IDB_TRACE("IDBRequest::onSuccess(IDBDatabase)");
262     if (m_requestAborted)
263         return;
264     ASSERT(!m_errorCode && m_errorMessage.isNull() && !m_error && !m_result);
265     if (m_contextStopped || !scriptExecutionContext())
266         return;
267
268     RefPtr<IDBDatabase> idbDatabase = IDBDatabase::create(scriptExecutionContext(), backend);
269     idbDatabase->registerFrontendCallbacks();
270
271     m_result = IDBAny::create(idbDatabase.release());
272     enqueueEvent(createSuccessEvent());
273 }
274
275 void IDBRequest::onSuccess(PassRefPtr<IDBKey> idbKey)
276 {
277     IDB_TRACE("IDBRequest::onSuccess(IDBKey)");
278     if (m_requestAborted)
279         return;
280     ASSERT(!m_errorCode && m_errorMessage.isNull() && !m_error && !m_result);
281     if (idbKey && idbKey->isValid())
282         m_result = IDBAny::create(idbKey);
283     else
284         m_result = IDBAny::create(SerializedScriptValue::undefinedValue());
285     enqueueEvent(createSuccessEvent());
286 }
287
288 void IDBRequest::onSuccess(PassRefPtr<IDBTransactionBackendInterface> prpBackend)
289 {
290     IDB_TRACE("IDBRequest::onSuccess(IDBTransaction)");
291     if (m_requestAborted)
292         return;
293     ASSERT(!m_errorCode && m_errorMessage.isNull() && !m_error && !m_result);
294     RefPtr<IDBTransactionBackendInterface> backend = prpBackend;
295
296     if (m_contextStopped || !scriptExecutionContext()) {
297         backend->abort();
298         return;
299     }
300
301     RefPtr<IDBTransaction> frontend = IDBTransaction::create(scriptExecutionContext(), backend, IDBTransaction::VERSION_CHANGE, m_source->idbDatabase().get());
302     backend->setCallbacks(frontend.get());
303     m_transaction = frontend;
304
305     ASSERT(m_source->type() == IDBAny::IDBDatabaseType);
306     ASSERT(m_transaction->isVersionChange());
307
308     m_result = IDBAny::create(frontend.release());
309     enqueueEvent(createSuccessEvent());
310 }
311
312 void IDBRequest::onSuccess(PassRefPtr<SerializedScriptValue> serializedScriptValue)
313 {
314     IDB_TRACE("IDBRequest::onSuccess(SerializedScriptValue)");
315     if (m_requestAborted)
316         return;
317     ASSERT(!m_errorCode && m_errorMessage.isNull() && !m_error && !m_result);
318     m_result = IDBAny::create(serializedScriptValue);
319     m_cursor.clear();
320     enqueueEvent(createSuccessEvent());
321 }
322
323
324 void IDBRequest::onSuccess(PassRefPtr<SerializedScriptValue> prpSerializedScriptValue, PassRefPtr<IDBKey> prpPrimaryKey, const IDBKeyPath& keyPath)
325 {
326     LOG_ERROR("CHECKING: onSuccess(value, key, keypath)");
327     if (m_requestAborted)
328         return;
329     RefPtr<SerializedScriptValue> serializedScriptValue = prpSerializedScriptValue;
330 #ifndef NDEBUG
331     // FIXME: Assert until we can actually inject the right value.
332     RefPtr<IDBKey> primaryKey = prpPrimaryKey;
333     RefPtr<IDBKey> expectedKey =
334               createIDBKeyFromSerializedValueAndKeyPath(serializedScriptValue, keyPath);
335     ASSERT(primaryKey);
336     ASSERT(expectedKey->isEqual(primaryKey.get()));
337 #endif
338     onSuccess(serializedScriptValue.release());
339 }
340
341 void IDBRequest::onSuccessWithContinuation()
342 {
343     IDB_TRACE("IDBRequest::onSuccessWithContinuation");
344     if (m_requestAborted)
345         return;
346     ASSERT(!m_errorCode && m_errorMessage.isNull() && !m_error && !m_result);
347     ASSERT(m_cursor);
348     setResultCursor(m_cursor, m_cursorType);
349     m_cursor.clear();
350     enqueueEvent(createSuccessEvent());
351 }
352
353 bool IDBRequest::hasPendingActivity() const
354 {
355     // FIXME: In an ideal world, we should return true as long as anyone has a or can
356     //        get a handle to us and we have event listeners. This is order to handle
357     //        user generated events properly.
358     return !m_requestFinished || ActiveDOMObject::hasPendingActivity();
359 }
360
361 void IDBRequest::stop()
362 {
363     ActiveDOMObject::stop();
364     if (m_contextStopped)
365         return;
366
367     m_contextStopped = true;
368     if (m_readyState == PENDING)
369         markEarlyDeath();
370 }
371
372 void IDBRequest::onBlocked()
373 {
374     ASSERT_NOT_REACHED();
375 }
376
377 const AtomicString& IDBRequest::interfaceName() const
378 {
379     return eventNames().interfaceForIDBRequest;
380 }
381
382 ScriptExecutionContext* IDBRequest::scriptExecutionContext() const
383 {
384     return ActiveDOMObject::scriptExecutionContext();
385 }
386
387 bool IDBRequest::dispatchEvent(PassRefPtr<Event> event)
388 {
389     IDB_TRACE("IDBRequest::dispatchEvent");
390     ASSERT(!m_requestFinished);
391     ASSERT(!m_contextStopped);
392     ASSERT(m_enqueuedEvents.size());
393     ASSERT(scriptExecutionContext());
394     ASSERT(event->target() == this);
395     ASSERT_WITH_MESSAGE(m_readyState < DONE, "m_readyState < DONE(%d), was %d", DONE, m_readyState);
396     if (event->type() != eventNames().blockedEvent)
397         m_readyState = DONE;
398
399     for (size_t i = 0; i < m_enqueuedEvents.size(); ++i) {
400         if (m_enqueuedEvents[i].get() == event.get())
401             m_enqueuedEvents.remove(i);
402     }
403
404     Vector<RefPtr<EventTarget> > targets;
405     targets.append(this);
406     if (m_transaction) {
407         targets.append(m_transaction);
408         // If there ever are events that are associated with a database but
409         // that do not have a transaction, then this will not work and we need
410         // this object to actually hold a reference to the database (to ensure
411         // it stays alive).
412         targets.append(m_transaction->db());
413     }
414
415     RefPtr<IDBCursor> cursorToNotify;
416     if (m_result) {
417         if (m_result->type() == IDBAny::IDBCursorType)
418             cursorToNotify = m_result->idbCursor();
419         else if (m_result->type() == IDBAny::IDBCursorWithValueType)
420             cursorToNotify = m_result->idbCursorWithValue();
421         if (cursorToNotify)
422             cursorToNotify->setValueReady();
423     }
424
425     // FIXME: When we allow custom event dispatching, this will probably need to change.
426     ASSERT(event->type() == eventNames().successEvent || event->type() == eventNames().errorEvent || event->type() == eventNames().blockedEvent);
427     const bool setTransactionActive = m_transaction && (event->type() == eventNames().successEvent || (event->type() == eventNames().errorEvent && m_errorCode != IDBDatabaseException::IDB_ABORT_ERR));
428
429     if (setTransactionActive)
430         m_transaction->setActive(true);
431     bool dontPreventDefault = IDBEventDispatcher::dispatch(event.get(), targets);
432     if (setTransactionActive)
433         m_transaction->setActive(false);
434
435     // If the result was of type IDBCursor, or a onBlocked event, then we'll fire again.
436     if (event->type() != eventNames().blockedEvent && (!cursorToNotify || m_cursorFinished))
437         m_requestFinished = true;
438
439     if (cursorToNotify)
440         cursorToNotify->postSuccessHandlerCallback();
441
442     if (m_transaction && event->type() != eventNames().blockedEvent) {
443         // If an error event and the default wasn't prevented...
444         if (dontPreventDefault && event->type() == eventNames().errorEvent) {
445             m_transaction->setError(m_error);
446             m_transaction->abort();
447         }
448         m_transaction->backend()->didCompleteTaskEvents();
449     }
450
451     if (m_transaction && m_readyState == DONE)
452         m_transaction->unregisterRequest(this);
453
454     return dontPreventDefault;
455 }
456
457 void IDBRequest::uncaughtExceptionInEventHandler()
458 {
459     if (m_transaction)
460         m_transaction->backend()->abort();
461 }
462
463 void IDBRequest::enqueueEvent(PassRefPtr<Event> event)
464 {
465     ASSERT(!m_requestFinished);
466
467     if (m_contextStopped || !scriptExecutionContext())
468         return;
469
470     ASSERT(m_readyState < DONE);
471
472     EventQueue* eventQueue = scriptExecutionContext()->eventQueue();
473     event->setTarget(this);
474
475     if (eventQueue->enqueueEvent(event.get()))
476         m_enqueuedEvents.append(event);
477 }
478
479 EventTargetData* IDBRequest::eventTargetData()
480 {
481     return &m_eventTargetData;
482 }
483
484 EventTargetData* IDBRequest::ensureEventTargetData()
485 {
486     return &m_eventTargetData;
487 }
488
489 void IDBRequest::setResultCursor(PassRefPtr<IDBCursor> prpCursor, IDBCursorBackendInterface::CursorType type)
490 {
491     if (type == IDBCursorBackendInterface::IndexKeyCursor) {
492         m_result = IDBAny::create(prpCursor);
493         return;
494     }
495
496     m_result = IDBAny::create(IDBCursorWithValue::fromCursor(prpCursor));
497 }
498
499 } // namespace WebCore
500
501 #endif