2 * Copyright (C) 2010 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
30 #include "IDBRequest.h"
32 #if ENABLE(INDEXED_DATABASE)
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"
47 PassRefPtr<IDBRequest> IDBRequest::create(ScriptExecutionContext* context, PassRefPtr<IDBAny> source, IDBTransaction* transaction)
49 RefPtr<IDBRequest> request(adoptRef(new IDBRequest(context, source, transaction)));
50 request->suspendIfNeeded();
51 return request.release();
54 IDBRequest::IDBRequest(ScriptExecutionContext* context, PassRefPtr<IDBAny> source, IDBTransaction* transaction)
55 : ActiveDOMObject(context, this)
58 , m_transaction(transaction)
59 , m_readyState(PENDING)
60 , m_requestAborted(false)
61 , m_cursorFinished(false)
62 , m_contextStopped(false)
63 , m_cursorType(IDBCursorBackendInterface::InvalidCursorType)
64 , m_cursorDirection(IDBCursor::NEXT)
68 m_transaction->registerRequest(this);
72 IDBRequest::~IDBRequest()
74 ASSERT(m_readyState == DONE || m_readyState == EarlyDeath || !scriptExecutionContext());
77 PassRefPtr<IDBAny> IDBRequest::result(ExceptionCode& ec) const
79 if (m_readyState != DONE) {
80 ec = IDBDatabaseException::IDB_INVALID_STATE_ERR;
86 PassRefPtr<DOMError> IDBRequest::error(ExceptionCode& ec) const
88 if (m_readyState != DONE) {
89 ec = IDBDatabaseException::IDB_INVALID_STATE_ERR;
95 unsigned short IDBRequest::errorCode(ExceptionCode& ec) const
97 if (m_readyState != DONE) {
98 ec = IDBDatabaseException::IDB_INVALID_STATE_ERR;
104 String IDBRequest::webkitErrorMessage(ExceptionCode& ec) const
106 if (m_readyState != DONE) {
107 ec = IDBDatabaseException::IDB_INVALID_STATE_ERR;
110 return m_errorMessage;
113 PassRefPtr<IDBAny> IDBRequest::source() const
118 PassRefPtr<IDBTransaction> IDBRequest::transaction() const
120 return m_transaction;
123 const String& IDBRequest::readyState() const
125 ASSERT(m_readyState == PENDING || m_readyState == DONE);
126 DEFINE_STATIC_LOCAL(AtomicString, pending, ("pending"));
127 DEFINE_STATIC_LOCAL(AtomicString, done, ("done"));
129 if (m_readyState == PENDING)
135 void IDBRequest::markEarlyDeath()
137 ASSERT(m_readyState == PENDING);
138 m_readyState = EarlyDeath;
140 m_transaction->unregisterRequest(this);
143 void IDBRequest::abort()
145 ASSERT(m_readyState == PENDING || m_readyState == DONE);
146 ASSERT(!m_requestAborted);
147 if (m_contextStopped || !scriptExecutionContext())
149 if (m_readyState == DONE)
152 EventQueue* eventQueue = scriptExecutionContext()->eventQueue();
153 for (size_t i = 0; i < m_enqueuedEvents.size(); ++i) {
154 bool removed = eventQueue->cancelEvent(m_enqueuedEvents[i].get());
155 ASSERT_UNUSED(removed, removed);
157 m_enqueuedEvents.clear();
161 m_errorMessage = String();
163 onError(IDBDatabaseError::create(IDBDatabaseException::IDB_ABORT_ERR, "The transaction was aborted, so the request cannot be fulfilled."));
164 m_requestAborted = true;
167 void IDBRequest::setCursorDetails(IDBCursorBackendInterface::CursorType cursorType, IDBCursor::Direction direction)
169 ASSERT(m_readyState == PENDING);
170 ASSERT(m_cursorType == IDBCursorBackendInterface::InvalidCursorType);
171 m_cursorType = cursorType;
172 m_cursorDirection = direction;
175 void IDBRequest::setPendingCursor(PassRefPtr<IDBCursor> cursor)
177 ASSERT(m_readyState == DONE);
178 ASSERT(scriptExecutionContext());
179 ASSERT(m_transaction);
180 ASSERT(!m_pendingCursor);
181 ASSERT(cursor == getResultCursor());
183 m_pendingCursor = cursor;
185 m_readyState = PENDING;
188 m_errorMessage = String();
189 m_transaction->registerRequest(this);
192 PassRefPtr<IDBCursor> IDBRequest::getResultCursor()
196 if (m_result->type() == IDBAny::IDBCursorType)
197 return m_result->idbCursor();
198 if (m_result->type() == IDBAny::IDBCursorWithValueType)
199 return m_result->idbCursorWithValue();
203 void IDBRequest::setResultCursor(PassRefPtr<IDBCursor> prpCursor)
205 ASSERT(m_readyState == PENDING);
206 if (m_cursorType == IDBCursorBackendInterface::IndexKeyCursor) {
207 m_result = IDBAny::create(prpCursor);
211 m_result = IDBAny::create(IDBCursorWithValue::fromCursor(prpCursor));
214 void IDBRequest::finishCursor()
216 ASSERT(m_readyState == PENDING || m_readyState == DONE);
217 m_cursorFinished = true;
220 void IDBRequest::onError(PassRefPtr<IDBDatabaseError> error)
222 ASSERT(m_readyState == PENDING || m_readyState == DONE);
223 if (m_requestAborted)
225 ASSERT(m_readyState == PENDING);
226 ASSERT(!m_errorCode && m_errorMessage.isNull() && !m_error && !m_result);
227 m_errorCode = error->code();
228 m_errorMessage = error->message();
229 m_error = DOMError::create(IDBDatabaseException::getErrorName(error->idbCode()));
230 m_pendingCursor.clear();
231 enqueueEvent(Event::create(eventNames().errorEvent, true, true));
234 static PassRefPtr<Event> createSuccessEvent()
236 return Event::create(eventNames().successEvent, false, false);
239 void IDBRequest::onSuccess(PassRefPtr<DOMStringList> domStringList)
241 IDB_TRACE("IDBRequest::onSuccess(DOMStringList)");
242 ASSERT(m_readyState == PENDING || m_readyState == DONE);
243 if (m_requestAborted)
245 ASSERT(m_readyState == PENDING);
246 ASSERT(!m_errorCode && m_errorMessage.isNull() && !m_error && !m_result);
247 m_result = IDBAny::create(domStringList);
248 enqueueEvent(createSuccessEvent());
251 void IDBRequest::onSuccess(PassRefPtr<IDBCursorBackendInterface> backend)
253 IDB_TRACE("IDBRequest::onSuccess(IDBCursor)");
254 ASSERT(m_readyState == PENDING || m_readyState == DONE);
255 if (m_requestAborted)
257 ASSERT(m_readyState == PENDING);
258 ASSERT(!m_errorCode && m_errorMessage.isNull() && !m_error && !m_result);
259 ASSERT(m_cursorType != IDBCursorBackendInterface::InvalidCursorType);
260 RefPtr<IDBCursor> cursor;
261 if (m_cursorType == IDBCursorBackendInterface::IndexKeyCursor)
262 cursor = IDBCursor::create(backend, m_cursorDirection, this, m_source.get(), m_transaction.get());
264 cursor = IDBCursorWithValue::create(backend, m_cursorDirection, this, m_source.get(), m_transaction.get());
265 setResultCursor(cursor);
267 enqueueEvent(createSuccessEvent());
270 void IDBRequest::onSuccess(PassRefPtr<IDBDatabaseBackendInterface> backend)
272 IDB_TRACE("IDBRequest::onSuccess(IDBDatabase)");
273 ASSERT(m_readyState == PENDING || m_readyState == DONE);
274 if (m_requestAborted)
276 ASSERT(m_readyState == PENDING);
277 ASSERT(!m_errorCode && m_errorMessage.isNull() && !m_error && !m_result);
278 if (m_contextStopped || !scriptExecutionContext())
281 RefPtr<IDBDatabase> idbDatabase = IDBDatabase::create(scriptExecutionContext(), backend);
282 idbDatabase->registerFrontendCallbacks();
284 m_result = IDBAny::create(idbDatabase.release());
285 enqueueEvent(createSuccessEvent());
288 void IDBRequest::onSuccess(PassRefPtr<IDBKey> idbKey)
290 IDB_TRACE("IDBRequest::onSuccess(IDBKey)");
291 ASSERT(m_readyState == PENDING || m_readyState == DONE);
292 if (m_requestAborted)
294 ASSERT(m_readyState == PENDING);
295 ASSERT(!m_errorCode && m_errorMessage.isNull() && !m_error && !m_result);
296 if (idbKey && idbKey->isValid())
297 m_result = IDBAny::create(idbKey);
299 m_result = IDBAny::create(SerializedScriptValue::undefinedValue());
300 enqueueEvent(createSuccessEvent());
303 void IDBRequest::onSuccess(PassRefPtr<IDBTransactionBackendInterface> prpBackend)
305 IDB_TRACE("IDBRequest::onSuccess(IDBTransaction)");
306 ASSERT(m_readyState == PENDING || m_readyState == DONE);
307 if (m_requestAborted)
309 ASSERT(m_readyState == PENDING);
310 ASSERT(!m_errorCode && m_errorMessage.isNull() && !m_error && !m_result);
311 RefPtr<IDBTransactionBackendInterface> backend = prpBackend;
313 if (m_contextStopped || !scriptExecutionContext()) {
318 RefPtr<IDBTransaction> frontend = IDBTransaction::create(scriptExecutionContext(), backend, IDBTransaction::VERSION_CHANGE, m_source->idbDatabase().get());
319 backend->setCallbacks(frontend.get());
320 m_transaction = frontend;
322 ASSERT(m_source->type() == IDBAny::IDBDatabaseType);
323 ASSERT(m_transaction->isVersionChange());
325 m_result = IDBAny::create(frontend.release());
326 enqueueEvent(createSuccessEvent());
329 void IDBRequest::onSuccess(PassRefPtr<SerializedScriptValue> serializedScriptValue)
331 IDB_TRACE("IDBRequest::onSuccess(SerializedScriptValue)");
332 ASSERT(m_readyState == PENDING || m_readyState == DONE);
333 if (m_requestAborted)
335 ASSERT(m_readyState == PENDING);
336 ASSERT(!m_errorCode && m_errorMessage.isNull() && !m_error && !m_result);
337 m_result = IDBAny::create(serializedScriptValue);
338 m_pendingCursor.clear();
339 enqueueEvent(createSuccessEvent());
343 void IDBRequest::onSuccess(PassRefPtr<SerializedScriptValue> prpSerializedScriptValue, PassRefPtr<IDBKey> prpPrimaryKey, const IDBKeyPath& keyPath)
345 LOG_ERROR("CHECKING: onSuccess(value, key, keypath)");
346 ASSERT(m_readyState == PENDING || m_readyState == DONE);
347 if (m_requestAborted)
349 ASSERT(m_readyState == PENDING);
350 RefPtr<SerializedScriptValue> serializedScriptValue = prpSerializedScriptValue;
352 // FIXME: Assert until we can actually inject the right value.
353 RefPtr<IDBKey> primaryKey = prpPrimaryKey;
354 RefPtr<IDBKey> expectedKey =
355 createIDBKeyFromSerializedValueAndKeyPath(serializedScriptValue, keyPath);
357 ASSERT(expectedKey->isEqual(primaryKey.get()));
359 onSuccess(serializedScriptValue.release());
362 void IDBRequest::onSuccessWithContinuation()
364 IDB_TRACE("IDBRequest::onSuccessWithContinuation");
365 ASSERT(m_readyState == PENDING || m_readyState == DONE);
366 if (m_requestAborted)
368 ASSERT(!m_errorCode && m_errorMessage.isNull() && !m_error && !m_result);
369 ASSERT(m_pendingCursor);
370 setResultCursor(m_pendingCursor.release());
371 enqueueEvent(createSuccessEvent());
374 bool IDBRequest::hasPendingActivity() const
376 // FIXME: In an ideal world, we should return true as long as anyone has a or can
377 // get a handle to us and we have event listeners. This is order to handle
378 // user generated events properly.
379 return m_readyState == PENDING || ActiveDOMObject::hasPendingActivity();
382 void IDBRequest::stop()
384 ActiveDOMObject::stop();
385 if (m_contextStopped)
388 m_contextStopped = true;
389 if (m_readyState == PENDING)
393 void IDBRequest::onBlocked()
395 ASSERT_NOT_REACHED();
398 const AtomicString& IDBRequest::interfaceName() const
400 return eventNames().interfaceForIDBRequest;
403 ScriptExecutionContext* IDBRequest::scriptExecutionContext() const
405 return ActiveDOMObject::scriptExecutionContext();
408 bool IDBRequest::dispatchEvent(PassRefPtr<Event> event)
410 IDB_TRACE("IDBRequest::dispatchEvent");
411 ASSERT(m_readyState == PENDING);
412 ASSERT(!m_contextStopped);
413 ASSERT(m_enqueuedEvents.size());
414 ASSERT(scriptExecutionContext());
415 ASSERT(event->target() == this);
416 ASSERT_WITH_MESSAGE(m_readyState < DONE, "m_readyState < DONE(%d), was %d", DONE, m_readyState);
418 if (event->type() != eventNames().blockedEvent)
421 for (size_t i = 0; i < m_enqueuedEvents.size(); ++i) {
422 if (m_enqueuedEvents[i].get() == event.get())
423 m_enqueuedEvents.remove(i);
426 Vector<RefPtr<EventTarget> > targets;
427 targets.append(this);
429 targets.append(m_transaction);
430 // If there ever are events that are associated with a database but
431 // that do not have a transaction, then this will not work and we need
432 // this object to actually hold a reference to the database (to ensure
434 targets.append(m_transaction->db());
437 // Cursor properties should not updated until the success event is being dispatched.
438 RefPtr<IDBCursor> cursorToNotify;
439 if (event->type() == eventNames().successEvent) {
440 cursorToNotify = getResultCursor();
442 cursorToNotify->setValueReady();
445 // FIXME: When we allow custom event dispatching, this will probably need to change.
446 ASSERT(event->type() == eventNames().successEvent || event->type() == eventNames().errorEvent || event->type() == eventNames().blockedEvent);
447 const bool setTransactionActive = m_transaction && (event->type() == eventNames().successEvent || (event->type() == eventNames().errorEvent && m_errorCode != IDBDatabaseException::IDB_ABORT_ERR));
449 if (setTransactionActive)
450 m_transaction->setActive(true);
451 bool dontPreventDefault = IDBEventDispatcher::dispatch(event.get(), targets);
452 if (setTransactionActive)
453 m_transaction->setActive(false);
456 cursorToNotify->postSuccessHandlerCallback();
459 if (event->type() == eventNames().errorEvent && dontPreventDefault && !m_requestAborted) {
460 m_transaction->setError(m_error);
461 ExceptionCode unused;
462 m_transaction->abort(unused);
465 if (event->type() != eventNames().blockedEvent)
466 m_transaction->backend()->didCompleteTaskEvents();
468 if (m_readyState == DONE)
469 m_transaction->unregisterRequest(this);
472 return dontPreventDefault;
475 void IDBRequest::uncaughtExceptionInEventHandler()
477 if (m_transaction && !m_requestAborted) {
478 m_transaction->setError(DOMError::create(IDBDatabaseException::getErrorName(IDBDatabaseException::IDB_ABORT_ERR)));
479 ExceptionCode unused;
480 m_transaction->abort(unused);
484 void IDBRequest::enqueueEvent(PassRefPtr<Event> event)
486 ASSERT(m_readyState == PENDING || m_readyState == DONE);
488 if (m_contextStopped || !scriptExecutionContext())
491 ASSERT(m_readyState == PENDING);
493 EventQueue* eventQueue = scriptExecutionContext()->eventQueue();
494 event->setTarget(this);
496 if (eventQueue->enqueueEvent(event.get()))
497 m_enqueuedEvents.append(event);
500 EventTargetData* IDBRequest::eventTargetData()
502 return &m_eventTargetData;
505 EventTargetData* IDBRequest::ensureEventTargetData()
507 return &m_eventTargetData;
510 } // namespace WebCore