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 "Document.h"
35 #include "EventException.h"
36 #include "EventListener.h"
37 #include "EventNames.h"
38 #include "EventQueue.h"
39 #include "IDBCursorWithValue.h"
40 #include "IDBDatabase.h"
41 #include "IDBEventDispatcher.h"
42 #include "IDBPendingTransactionMonitor.h"
43 #include "IDBTransaction.h"
44
45 namespace WebCore {
46
create(ScriptExecutionContext * context,PassRefPtr<IDBAny> source,IDBTransaction * transaction)47 PassRefPtr<IDBRequest> IDBRequest::create(ScriptExecutionContext* context, PassRefPtr<IDBAny> source, IDBTransaction* transaction)
48 {
49 return adoptRef(new IDBRequest(context, source, transaction));
50 }
51
IDBRequest(ScriptExecutionContext * context,PassRefPtr<IDBAny> source,IDBTransaction * transaction)52 IDBRequest::IDBRequest(ScriptExecutionContext* context, PassRefPtr<IDBAny> source, IDBTransaction* transaction)
53 : ActiveDOMObject(context, this)
54 , m_errorCode(0)
55 , m_source(source)
56 , m_transaction(transaction)
57 , m_readyState(LOADING)
58 , m_finished(false)
59 , m_cursorType(IDBCursorBackendInterface::InvalidCursorType)
60 {
61 if (m_transaction) {
62 m_transaction->registerRequest(this);
63 IDBPendingTransactionMonitor::removePendingTransaction(m_transaction->backend());
64 }
65 }
66
~IDBRequest()67 IDBRequest::~IDBRequest()
68 {
69 ASSERT(m_readyState == DONE || m_readyState == EarlyDeath);
70 if (m_transaction)
71 m_transaction->unregisterRequest(this);
72 }
73
result(ExceptionCode & ec) const74 PassRefPtr<IDBAny> IDBRequest::result(ExceptionCode& ec) const
75 {
76 if (m_readyState != DONE) {
77 ec = IDBDatabaseException::NOT_ALLOWED_ERR;
78 return 0;
79 }
80 return m_result;
81 }
82
errorCode(ExceptionCode & ec) const83 unsigned short IDBRequest::errorCode(ExceptionCode& ec) const
84 {
85 if (m_readyState != DONE) {
86 ec = IDBDatabaseException::NOT_ALLOWED_ERR;
87 return 0;
88 }
89 return m_errorCode;
90 }
91
webkitErrorMessage(ExceptionCode & ec) const92 String IDBRequest::webkitErrorMessage(ExceptionCode& ec) const
93 {
94 if (m_readyState != DONE) {
95 ec = IDBDatabaseException::NOT_ALLOWED_ERR;
96 return String();
97 }
98 return m_errorMessage;
99 }
100
source() const101 PassRefPtr<IDBAny> IDBRequest::source() const
102 {
103 return m_source;
104 }
105
transaction() const106 PassRefPtr<IDBTransaction> IDBRequest::transaction() const
107 {
108 return m_transaction;
109 }
110
readyState() const111 unsigned short IDBRequest::readyState() const
112 {
113 ASSERT(m_readyState == LOADING || m_readyState == DONE);
114 return m_readyState;
115 }
116
markEarlyDeath()117 void IDBRequest::markEarlyDeath()
118 {
119 ASSERT(m_readyState == LOADING);
120 m_readyState = EarlyDeath;
121 }
122
resetReadyState(IDBTransaction * transaction)123 bool IDBRequest::resetReadyState(IDBTransaction* transaction)
124 {
125 ASSERT(!m_finished);
126 ASSERT(scriptExecutionContext());
127 ASSERT(transaction == m_transaction);
128 if (m_readyState != DONE)
129 return false;
130
131 m_readyState = LOADING;
132 m_result.clear();
133 m_errorCode = 0;
134 m_errorMessage = String();
135
136 IDBPendingTransactionMonitor::removePendingTransaction(m_transaction->backend());
137
138 return true;
139 }
140
source()141 IDBAny* IDBRequest::source()
142 {
143 return m_source.get();
144 }
145
abort()146 void IDBRequest::abort()
147 {
148 if (m_readyState != LOADING) {
149 ASSERT(m_readyState == DONE);
150 return;
151 }
152
153 ASSERT(scriptExecutionContext()->isDocument());
154 EventQueue* eventQueue = static_cast<Document*>(scriptExecutionContext())->eventQueue();
155 for (size_t i = 0; i < m_enqueuedEvents.size(); ++i) {
156 bool removed = eventQueue->cancelEvent(m_enqueuedEvents[i].get());
157 ASSERT_UNUSED(removed, removed);
158 }
159 m_enqueuedEvents.clear();
160
161 m_errorCode = 0;
162 m_errorMessage = String();
163 m_result.clear();
164 onError(IDBDatabaseError::create(IDBDatabaseException::ABORT_ERR, "The transaction was aborted, so the request cannot be fulfilled."));
165 }
166
setCursorType(IDBCursorBackendInterface::CursorType cursorType)167 void IDBRequest::setCursorType(IDBCursorBackendInterface::CursorType cursorType)
168 {
169 ASSERT(m_cursorType == IDBCursorBackendInterface::InvalidCursorType);
170 m_cursorType = cursorType;
171 }
172
onError(PassRefPtr<IDBDatabaseError> error)173 void IDBRequest::onError(PassRefPtr<IDBDatabaseError> error)
174 {
175 ASSERT(!m_errorCode && m_errorMessage.isNull() && !m_result);
176 m_errorCode = error->code();
177 m_errorMessage = error->message();
178 enqueueEvent(Event::create(eventNames().errorEvent, true, true));
179 }
180
createSuccessEvent()181 static PassRefPtr<Event> createSuccessEvent()
182 {
183 return Event::create(eventNames().successEvent, false, false);
184 }
185
onSuccess(PassRefPtr<IDBCursorBackendInterface> backend)186 void IDBRequest::onSuccess(PassRefPtr<IDBCursorBackendInterface> backend)
187 {
188 ASSERT(!m_errorCode && m_errorMessage.isNull() && !m_result);
189 ASSERT(m_cursorType != IDBCursorBackendInterface::InvalidCursorType);
190 if (m_cursorType == IDBCursorBackendInterface::IndexKeyCursor)
191 m_result = IDBAny::create(IDBCursor::create(backend, this, m_source.get(), m_transaction.get()));
192 else
193 m_result = IDBAny::create(IDBCursorWithValue::create(backend, this, m_source.get(), m_transaction.get()));
194 enqueueEvent(createSuccessEvent());
195 }
196
onSuccess(PassRefPtr<IDBDatabaseBackendInterface> backend)197 void IDBRequest::onSuccess(PassRefPtr<IDBDatabaseBackendInterface> backend)
198 {
199 ASSERT(!m_errorCode && m_errorMessage.isNull() && !m_result);
200 RefPtr<IDBDatabase> idbDatabase = IDBDatabase::create(scriptExecutionContext(), backend);
201 idbDatabase->open();
202
203 m_result = IDBAny::create(idbDatabase.release());
204 enqueueEvent(createSuccessEvent());
205 }
206
onSuccess(PassRefPtr<IDBKey> idbKey)207 void IDBRequest::onSuccess(PassRefPtr<IDBKey> idbKey)
208 {
209 ASSERT(!m_errorCode && m_errorMessage.isNull() && !m_result);
210 m_result = IDBAny::create(idbKey);
211 enqueueEvent(createSuccessEvent());
212 }
213
onSuccess(PassRefPtr<IDBTransactionBackendInterface> prpBackend)214 void IDBRequest::onSuccess(PassRefPtr<IDBTransactionBackendInterface> prpBackend)
215 {
216 ASSERT(!m_errorCode && m_errorMessage.isNull() && !m_result);
217 if (!scriptExecutionContext())
218 return;
219
220 RefPtr<IDBTransactionBackendInterface> backend = prpBackend;
221 RefPtr<IDBTransaction> frontend = IDBTransaction::create(scriptExecutionContext(), backend, m_source->idbDatabase().get());
222 backend->setCallbacks(frontend.get());
223 m_transaction = frontend;
224
225 ASSERT(m_source->type() == IDBAny::IDBDatabaseType);
226 m_source->idbDatabase()->setSetVersionTransaction(frontend.get());
227
228 IDBPendingTransactionMonitor::removePendingTransaction(m_transaction->backend());
229
230 m_result = IDBAny::create(frontend.release());
231 enqueueEvent(createSuccessEvent());
232 }
233
onSuccess(PassRefPtr<SerializedScriptValue> serializedScriptValue)234 void IDBRequest::onSuccess(PassRefPtr<SerializedScriptValue> serializedScriptValue)
235 {
236 ASSERT(!m_errorCode && m_errorMessage.isNull() && !m_result);
237 m_result = IDBAny::create(serializedScriptValue);
238 enqueueEvent(createSuccessEvent());
239 }
240
hasPendingActivity() const241 bool IDBRequest::hasPendingActivity() const
242 {
243 // FIXME: In an ideal world, we should return true as long as anyone has a or can
244 // get a handle to us and we have event listeners. This is order to handle
245 // user generated events properly.
246 return !m_finished || ActiveDOMObject::hasPendingActivity();
247 }
248
onBlocked()249 void IDBRequest::onBlocked()
250 {
251 ASSERT_NOT_REACHED();
252 }
253
scriptExecutionContext() const254 ScriptExecutionContext* IDBRequest::scriptExecutionContext() const
255 {
256 return ActiveDOMObject::scriptExecutionContext();
257 }
258
dispatchEvent(PassRefPtr<Event> event)259 bool IDBRequest::dispatchEvent(PassRefPtr<Event> event)
260 {
261 ASSERT(!m_finished);
262 ASSERT(m_enqueuedEvents.size());
263 ASSERT(scriptExecutionContext());
264 ASSERT(event->target() == this);
265 ASSERT(m_readyState < DONE);
266 if (event->type() != eventNames().blockedEvent)
267 m_readyState = DONE;
268
269 for (size_t i = 0; i < m_enqueuedEvents.size(); ++i) {
270 if (m_enqueuedEvents[i].get() == event.get())
271 m_enqueuedEvents.remove(i);
272 }
273
274 Vector<RefPtr<EventTarget> > targets;
275 targets.append(this);
276 if (m_transaction) {
277 targets.append(m_transaction);
278 // If there ever are events that are associated with a database but
279 // that do not have a transaction, then this will not work and we need
280 // this object to actually hold a reference to the database (to ensure
281 // it stays alive).
282 targets.append(m_transaction->db());
283 }
284
285 // FIXME: When we allow custom event dispatching, this will probably need to change.
286 ASSERT(event->type() == eventNames().successEvent || event->type() == eventNames().errorEvent || event->type() == eventNames().blockedEvent);
287 bool dontPreventDefault = IDBEventDispatcher::dispatch(event.get(), targets);
288
289 // If the result was of type IDBCursor, then we'll fire again.
290 if (m_result && m_result->type() != IDBAny::IDBCursorType && m_result->type() != IDBAny::IDBCursorWithValueType)
291 m_finished = true;
292
293 if (m_transaction) {
294 // If an error event and the default wasn't prevented...
295 if (dontPreventDefault && event->type() == eventNames().errorEvent)
296 m_transaction->backend()->abort();
297 m_transaction->backend()->didCompleteTaskEvents();
298 }
299 return dontPreventDefault;
300 }
301
uncaughtExceptionInEventHandler()302 void IDBRequest::uncaughtExceptionInEventHandler()
303 {
304 if (m_transaction)
305 m_transaction->backend()->abort();
306 }
307
enqueueEvent(PassRefPtr<Event> event)308 void IDBRequest::enqueueEvent(PassRefPtr<Event> event)
309 {
310 ASSERT(!m_finished);
311 ASSERT(m_readyState < DONE);
312 if (!scriptExecutionContext())
313 return;
314
315 ASSERT(scriptExecutionContext()->isDocument());
316 EventQueue* eventQueue = static_cast<Document*>(scriptExecutionContext())->eventQueue();
317 event->setTarget(this);
318 eventQueue->enqueueEvent(event.get());
319 m_enqueuedEvents.append(event);
320 }
321
eventTargetData()322 EventTargetData* IDBRequest::eventTargetData()
323 {
324 return &m_eventTargetData;
325 }
326
ensureEventTargetData()327 EventTargetData* IDBRequest::ensureEventTargetData()
328 {
329 return &m_eventTargetData;
330 }
331
332 } // namespace WebCore
333
334 #endif
335