1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=2 et sw=2 tw=80: */
3 : /* ***** BEGIN LICENSE BLOCK *****
4 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 : *
6 : * The contents of this file are subject to the Mozilla Public License Version
7 : * 1.1 (the "License"); you may not use this file except in compliance with
8 : * the License. You may obtain a copy of the License at
9 : * http://www.mozilla.org/MPL/
10 : *
11 : * Software distributed under the License is distributed on an "AS IS" basis,
12 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 : * for the specific language governing rights and limitations under the
14 : * License.
15 : *
16 : * The Original Code is Indexed Database.
17 : *
18 : * The Initial Developer of the Original Code is
19 : * The Mozilla Foundation.
20 : * Portions created by the Initial Developer are Copyright (C) 2010
21 : * the Initial Developer. All Rights Reserved.
22 : *
23 : * Contributor(s):
24 : * Shawn Wilsher <me@shawnwilsher.com>
25 : * Ben Turner <bent.mozilla@gmail.com>
26 : *
27 : * Alternatively, the contents of this file may be used under the terms of
28 : * either the GNU General Public License Version 2 or later (the "GPL"), or
29 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 : * in which case the provisions of the GPL or the LGPL are applicable instead
31 : * of those above. If you wish to allow use of your version of this file only
32 : * under the terms of either the GPL or the LGPL, and not to allow others to
33 : * use your version of this file under the terms of the MPL, indicate your
34 : * decision by deleting the provisions above and replace them with the notice
35 : * and other provisions required by the GPL or the LGPL. If you do not delete
36 : * the provisions above, a recipient may use your version of this file under
37 : * the terms of any one of the MPL, the GPL or the LGPL.
38 : *
39 : * ***** END LICENSE BLOCK ***** */
40 :
41 : #include "IDBRequest.h"
42 :
43 : #include "nsIJSContextStack.h"
44 : #include "nsIScriptContext.h"
45 :
46 : #include "nsComponentManagerUtils.h"
47 : #include "nsDOMClassInfoID.h"
48 : #include "nsDOMJSUtils.h"
49 : #include "nsContentUtils.h"
50 : #include "nsEventDispatcher.h"
51 : #include "nsPIDOMWindow.h"
52 : #include "nsStringGlue.h"
53 : #include "nsThreadUtils.h"
54 : #include "nsWrapperCacheInlines.h"
55 :
56 : #include "AsyncConnectionHelper.h"
57 : #include "IDBEvents.h"
58 : #include "IDBTransaction.h"
59 :
60 : USING_INDEXEDDB_NAMESPACE
61 :
62 2464 : IDBRequest::IDBRequest()
63 : : mResultVal(JSVAL_VOID),
64 : mErrorCode(0),
65 : mHaveResultOrErrorCode(false),
66 2464 : mRooted(false)
67 : {
68 2464 : NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
69 2464 : }
70 :
71 7316 : IDBRequest::~IDBRequest()
72 : {
73 2464 : NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
74 :
75 2464 : UnrootResultVal();
76 9704 : }
77 :
78 : // static
79 : already_AddRefed<IDBRequest>
80 2388 : IDBRequest::Create(nsISupports* aSource,
81 : IDBWrapperCache* aOwnerCache,
82 : IDBTransaction* aTransaction)
83 : {
84 2388 : NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
85 4776 : nsRefPtr<IDBRequest> request(new IDBRequest());
86 :
87 2388 : request->mSource = aSource;
88 2388 : request->mTransaction = aTransaction;
89 2388 : request->BindToOwner(aOwnerCache);
90 2388 : if (!request->SetScriptOwner(aOwnerCache->GetScriptOwner())) {
91 0 : return nsnull;
92 : }
93 :
94 2388 : return request.forget();
95 : }
96 :
97 : void
98 1778 : IDBRequest::Reset()
99 : {
100 1778 : NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
101 1778 : mResultVal = JSVAL_VOID;
102 1778 : mHaveResultOrErrorCode = false;
103 1778 : mErrorCode = 0;
104 1778 : UnrootResultVal();
105 1778 : }
106 :
107 : nsresult
108 4242 : IDBRequest::NotifyHelperCompleted(HelperBase* aHelper)
109 : {
110 4242 : NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
111 4242 : NS_ASSERTION(!mHaveResultOrErrorCode, "Already called!");
112 4242 : NS_ASSERTION(!PreservingWrapper(), "Already rooted?!");
113 4242 : NS_ASSERTION(JSVAL_IS_VOID(mResultVal), "Should be undefined!");
114 :
115 : // See if our window is still valid. If not then we're going to pretend that
116 : // we never completed.
117 4242 : if (NS_FAILED(CheckInnerWindowCorrectness())) {
118 0 : return NS_OK;
119 : }
120 :
121 4242 : mHaveResultOrErrorCode = true;
122 :
123 4242 : nsresult rv = aHelper->GetResultCode();
124 :
125 : // If the request failed then set the error code and return.
126 4242 : if (NS_FAILED(rv)) {
127 31 : mErrorCode = NS_ERROR_GET_CODE(rv);
128 31 : return NS_OK;
129 : }
130 :
131 : // Otherwise we need to get the result from the helper.
132 : JSContext* cx;
133 4211 : if (GetScriptOwner()) {
134 4211 : nsIThreadJSContextStack* cxStack = nsContentUtils::ThreadJSContextStack();
135 4211 : NS_ASSERTION(cxStack, "Failed to get thread context stack!");
136 :
137 4211 : if (NS_FAILED(cxStack->GetSafeJSContext(&cx))) {
138 0 : NS_WARNING("Failed to get safe JSContext!");
139 0 : rv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
140 0 : mErrorCode = NS_ERROR_GET_CODE(rv);
141 0 : return rv;
142 : }
143 : }
144 : else {
145 0 : nsIScriptContext* sc = GetContextForEventHandlers(&rv);
146 0 : NS_ENSURE_STATE(sc);
147 0 : cx = sc->GetNativeContext();
148 0 : NS_ASSERTION(cx, "Failed to get a context!");
149 : }
150 :
151 4211 : JSObject* global = GetParentObject();
152 4211 : NS_ASSERTION(global, "This should never be null!");
153 :
154 8422 : JSAutoRequest ar(cx);
155 8422 : JSAutoEnterCompartment ac;
156 4211 : if (ac.enter(cx, global)) {
157 4211 : RootResultVal();
158 :
159 4211 : rv = aHelper->GetSuccessResult(cx, &mResultVal);
160 4211 : if (NS_FAILED(rv)) {
161 0 : NS_WARNING("GetSuccessResult failed!");
162 : }
163 : }
164 : else {
165 0 : NS_WARNING("Failed to enter correct compartment!");
166 0 : rv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
167 : }
168 :
169 4211 : if (NS_SUCCEEDED(rv)) {
170 4211 : mErrorCode = 0;
171 : }
172 : else {
173 0 : mErrorCode = NS_ERROR_GET_CODE(rv);
174 0 : mResultVal = JSVAL_VOID;
175 : }
176 :
177 4211 : return rv;
178 : }
179 :
180 : void
181 4136 : IDBRequest::RootResultValInternal()
182 : {
183 4136 : NS_HOLD_JS_OBJECTS(this, IDBRequest);
184 4136 : }
185 :
186 : void
187 4136 : IDBRequest::UnrootResultValInternal()
188 : {
189 4136 : NS_DROP_JS_OBJECTS(this, IDBRequest);
190 4136 : }
191 :
192 : NS_IMETHODIMP
193 1784 : IDBRequest::GetReadyState(nsAString& aReadyState)
194 : {
195 1784 : NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
196 :
197 1784 : if (mHaveResultOrErrorCode) {
198 1781 : aReadyState.AssignLiteral("done");
199 : }
200 : else {
201 3 : aReadyState.AssignLiteral("pending");
202 : }
203 :
204 1784 : return NS_OK;
205 : }
206 :
207 : NS_IMETHODIMP
208 4 : IDBRequest::GetSource(nsISupports** aSource)
209 : {
210 4 : NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
211 :
212 8 : nsCOMPtr<nsISupports> source(mSource);
213 4 : source.forget(aSource);
214 4 : return NS_OK;
215 : }
216 :
217 : NS_IMETHODIMP
218 588 : IDBRequest::GetTransaction(nsIIDBTransaction** aTransaction)
219 : {
220 588 : NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
221 :
222 1176 : nsCOMPtr<nsIIDBTransaction> transaction(mTransaction);
223 588 : transaction.forget(aTransaction);
224 588 : return NS_OK;
225 : }
226 :
227 : NS_IMETHODIMP
228 3099 : IDBRequest::GetResult(jsval* aResult)
229 : {
230 3099 : NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
231 :
232 3099 : if (!mHaveResultOrErrorCode) {
233 : // XXX Need a real error code here.
234 1 : return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
235 : }
236 :
237 3098 : *aResult = mResultVal;
238 3098 : return NS_OK;
239 : }
240 :
241 : NS_IMETHODIMP
242 21 : IDBRequest::GetErrorCode(PRUint16* aErrorCode)
243 : {
244 21 : NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
245 :
246 21 : if (!mHaveResultOrErrorCode) {
247 : // XXX Need a real error code here.
248 0 : return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
249 : }
250 :
251 21 : *aErrorCode = mErrorCode;
252 21 : return NS_OK;
253 : }
254 :
255 1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(IDBRequest)
256 :
257 31 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(IDBRequest, IDBWrapperCache)
258 : // Don't need NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS because
259 : // nsDOMEventTargetHelper does it for us.
260 31 : NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(success)
261 31 : NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(error)
262 31 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mSource)
263 31 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mTransaction,
264 : nsPIDOMEventTarget)
265 31 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
266 :
267 31 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(IDBRequest, IDBWrapperCache)
268 31 : tmp->mResultVal = JSVAL_VOID;
269 31 : tmp->UnrootResultVal();
270 31 : NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(success)
271 31 : NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(error)
272 31 : NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mSource)
273 31 : NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mTransaction)
274 31 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
275 :
276 2693 : NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(IDBRequest, IDBWrapperCache)
277 : // Don't need NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER because
278 : // nsDOMEventTargetHelper does it for us.
279 2693 : if (JSVAL_IS_GCTHING(tmp->mResultVal)) {
280 611 : void *gcThing = JSVAL_TO_GCTHING(tmp->mResultVal);
281 611 : NS_IMPL_CYCLE_COLLECTION_TRACE_JS_CALLBACK(gcThing, "mResultVal")
282 : }
283 2693 : NS_IMPL_CYCLE_COLLECTION_TRACE_END
284 :
285 146124 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(IDBRequest)
286 87413 : NS_INTERFACE_MAP_ENTRY(nsIIDBRequest)
287 75788 : NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(IDBRequest)
288 73400 : NS_INTERFACE_MAP_END_INHERITING(IDBWrapperCache)
289 :
290 102865 : NS_IMPL_ADDREF_INHERITED(IDBRequest, IDBWrapperCache)
291 102865 : NS_IMPL_RELEASE_INHERITED(IDBRequest, IDBWrapperCache)
292 :
293 : DOMCI_DATA(IDBRequest, IDBRequest)
294 :
295 1319 : NS_IMPL_EVENT_HANDLER(IDBRequest, success);
296 1814 : NS_IMPL_EVENT_HANDLER(IDBRequest, error);
297 :
298 : nsresult
299 4314 : IDBRequest::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
300 : {
301 4314 : NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
302 :
303 4314 : aVisitor.mCanHandle = true;
304 4314 : aVisitor.mParentTarget = mTransaction;
305 4314 : return NS_OK;
306 : }
307 :
308 228 : IDBOpenDBRequest::~IDBOpenDBRequest()
309 : {
310 76 : NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
311 :
312 76 : UnrootResultVal();
313 304 : }
314 :
315 : // static
316 : already_AddRefed<IDBOpenDBRequest>
317 76 : IDBOpenDBRequest::Create(nsPIDOMWindow* aOwner,
318 : JSObject* aScriptOwner)
319 : {
320 76 : NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
321 152 : nsRefPtr<IDBOpenDBRequest> request(new IDBOpenDBRequest());
322 :
323 76 : request->BindToOwner(aOwner);
324 76 : if (!request->SetScriptOwner(aScriptOwner)) {
325 0 : return nsnull;
326 : }
327 :
328 76 : return request.forget();
329 : }
330 :
331 : void
332 142 : IDBOpenDBRequest::SetTransaction(IDBTransaction* aTransaction)
333 : {
334 142 : mTransaction = aTransaction;
335 142 : }
336 :
337 : void
338 75 : IDBOpenDBRequest::RootResultValInternal()
339 : {
340 75 : NS_HOLD_JS_OBJECTS(this, IDBOpenDBRequest);
341 75 : }
342 :
343 : void
344 75 : IDBOpenDBRequest::UnrootResultValInternal()
345 : {
346 75 : NS_DROP_JS_OBJECTS(this, IDBOpenDBRequest);
347 75 : }
348 :
349 1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(IDBOpenDBRequest)
350 :
351 4 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(IDBOpenDBRequest,
352 : IDBRequest)
353 4 : NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(upgradeneeded)
354 4 : NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(blocked)
355 4 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
356 :
357 4 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(IDBOpenDBRequest,
358 : IDBRequest)
359 4 : NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(upgradeneeded)
360 4 : NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(blocked)
361 4 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
362 :
363 6606 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(IDBOpenDBRequest)
364 4122 : NS_INTERFACE_MAP_ENTRY(nsIIDBOpenDBRequest)
365 3893 : NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(IDBOpenDBRequest)
366 3817 : NS_INTERFACE_MAP_END_INHERITING(IDBRequest)
367 :
368 4416 : NS_IMPL_ADDREF_INHERITED(IDBOpenDBRequest, IDBRequest)
369 4416 : NS_IMPL_RELEASE_INHERITED(IDBOpenDBRequest, IDBRequest)
370 :
371 : DOMCI_DATA(IDBOpenDBRequest, IDBOpenDBRequest)
372 :
373 4 : NS_IMPL_EVENT_HANDLER(IDBOpenDBRequest, blocked);
374 4465 : NS_IMPL_EVENT_HANDLER(IDBOpenDBRequest, upgradeneeded);
|