dom/indexedDB/IDBRequest.cpp

branch
TOR_BUG_9701
changeset 15
b8a032363ba2
equal deleted inserted replaced
-1:000000000000 0:9cf88cffe213
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 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 #include "IDBRequest.h"
8
9 #include "nsIScriptContext.h"
10
11 #include "mozilla/ContentEvents.h"
12 #include "mozilla/EventDispatcher.h"
13 #include "mozilla/dom/ErrorEventBinding.h"
14 #include "mozilla/dom/IDBOpenDBRequestBinding.h"
15 #include "mozilla/dom/UnionTypes.h"
16 #include "nsComponentManagerUtils.h"
17 #include "nsDOMClassInfoID.h"
18 #include "nsDOMJSUtils.h"
19 #include "nsContentUtils.h"
20 #include "nsCxPusher.h"
21 #include "nsJSUtils.h"
22 #include "nsPIDOMWindow.h"
23 #include "nsString.h"
24 #include "nsThreadUtils.h"
25 #include "nsWrapperCacheInlines.h"
26
27 #include "AsyncConnectionHelper.h"
28 #include "IDBCursor.h"
29 #include "IDBEvents.h"
30 #include "IDBFactory.h"
31 #include "IDBIndex.h"
32 #include "IDBObjectStore.h"
33 #include "IDBTransaction.h"
34 #include "ReportInternalError.h"
35
36 namespace {
37
38 #ifdef MOZ_ENABLE_PROFILER_SPS
39 uint64_t gNextRequestSerialNumber = 1;
40 #endif
41
42 } // anonymous namespace
43
44 USING_INDEXEDDB_NAMESPACE
45 using mozilla::dom::OwningIDBObjectStoreOrIDBIndexOrIDBCursor;
46 using mozilla::dom::ErrorEventInit;
47 using namespace mozilla;
48
49 IDBRequest::IDBRequest(IDBDatabase* aDatabase)
50 : IDBWrapperCache(aDatabase),
51 mResultVal(JSVAL_VOID),
52 mActorParent(nullptr),
53 #ifdef MOZ_ENABLE_PROFILER_SPS
54 mSerialNumber(gNextRequestSerialNumber++),
55 #endif
56 mErrorCode(NS_OK),
57 mLineNo(0),
58 mHaveResultOrErrorCode(false)
59 {
60 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
61 }
62
63 IDBRequest::IDBRequest(nsPIDOMWindow* aOwner)
64 : IDBWrapperCache(aOwner),
65 mResultVal(JSVAL_VOID),
66 mActorParent(nullptr),
67 #ifdef MOZ_ENABLE_PROFILER_SPS
68 mSerialNumber(gNextRequestSerialNumber++),
69 #endif
70 mErrorCode(NS_OK),
71 mLineNo(0),
72 mHaveResultOrErrorCode(false)
73 {
74 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
75 }
76
77 IDBRequest::~IDBRequest()
78 {
79 mResultVal = JSVAL_VOID;
80 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
81 }
82
83 // static
84 already_AddRefed<IDBRequest>
85 IDBRequest::Create(IDBDatabase* aDatabase,
86 IDBTransaction* aTransaction)
87 {
88 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
89 nsRefPtr<IDBRequest> request(new IDBRequest(aDatabase));
90
91 request->mTransaction = aTransaction;
92 request->SetScriptOwner(aDatabase->GetScriptOwner());
93
94 if (!aDatabase->Factory()->FromIPC()) {
95 request->CaptureCaller();
96 }
97
98
99 return request.forget();
100 }
101
102 // static
103 already_AddRefed<IDBRequest>
104 IDBRequest::Create(IDBObjectStore* aSourceAsObjectStore,
105 IDBDatabase* aDatabase,
106 IDBTransaction* aTransaction)
107 {
108 nsRefPtr<IDBRequest> request = Create(aDatabase, aTransaction);
109
110 request->mSourceAsObjectStore = aSourceAsObjectStore;
111
112 return request.forget();
113 }
114
115 // static
116 already_AddRefed<IDBRequest>
117 IDBRequest::Create(IDBIndex* aSourceAsIndex,
118 IDBDatabase* aDatabase,
119 IDBTransaction* aTransaction)
120 {
121 nsRefPtr<IDBRequest> request = Create(aDatabase, aTransaction);
122
123 request->mSourceAsIndex = aSourceAsIndex;
124
125 return request.forget();
126 }
127
128 #ifdef DEBUG
129 void
130 IDBRequest::AssertSourceIsCorrect() const
131 {
132 // At most one of mSourceAs* is allowed to be non-null. Check that by
133 // summing the double negation of each one and asserting the sum is at most
134 // 1.
135
136 MOZ_ASSERT(!!mSourceAsObjectStore + !!mSourceAsIndex + !!mSourceAsCursor <= 1);
137 }
138 #endif
139
140 void
141 IDBRequest::GetSource(Nullable<OwningIDBObjectStoreOrIDBIndexOrIDBCursor>& aSource) const
142 {
143 MOZ_ASSERT(NS_IsMainThread());
144
145 AssertSourceIsCorrect();
146
147 if (mSourceAsObjectStore) {
148 aSource.SetValue().SetAsIDBObjectStore() = mSourceAsObjectStore;
149 } else if (mSourceAsIndex) {
150 aSource.SetValue().SetAsIDBIndex() = mSourceAsIndex;
151 } else if (mSourceAsCursor) {
152 aSource.SetValue().SetAsIDBCursor() = mSourceAsCursor;
153 } else {
154 aSource.SetNull();
155 }
156 }
157
158 void
159 IDBRequest::Reset()
160 {
161 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
162 mResultVal = JSVAL_VOID;
163 mHaveResultOrErrorCode = false;
164 mError = nullptr;
165 }
166
167 nsresult
168 IDBRequest::NotifyHelperCompleted(HelperBase* aHelper)
169 {
170 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
171 NS_ASSERTION(!mHaveResultOrErrorCode, "Already called!");
172 NS_ASSERTION(JSVAL_IS_VOID(mResultVal), "Should be undefined!");
173
174 mHaveResultOrErrorCode = true;
175
176 nsresult rv = aHelper->GetResultCode();
177
178 // If the request failed then set the error code and return.
179 if (NS_FAILED(rv)) {
180 SetError(rv);
181 return NS_OK;
182 }
183
184 // See if our window is still valid. If not then we're going to pretend that
185 // we never completed.
186 if (NS_FAILED(CheckInnerWindowCorrectness())) {
187 return NS_OK;
188 }
189
190 // Otherwise we need to get the result from the helper.
191 AutoPushJSContext cx(GetJSContext());
192 if (!cx) {
193 IDB_WARNING("Failed to get safe JSContext!");
194 rv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
195 SetError(rv);
196 return rv;
197 }
198
199 JS::Rooted<JSObject*> global(cx, IDBWrapperCache::GetParentObject());
200 NS_ASSERTION(global, "This should never be null!");
201
202 JSAutoCompartment ac(cx, global);
203 AssertIsRooted();
204
205 JS::Rooted<JS::Value> value(cx);
206 rv = aHelper->GetSuccessResult(cx, &value);
207 if (NS_FAILED(rv)) {
208 NS_WARNING("GetSuccessResult failed!");
209 }
210
211 if (NS_SUCCEEDED(rv)) {
212 mError = nullptr;
213 mResultVal = value;
214 }
215 else {
216 SetError(rv);
217 mResultVal = JSVAL_VOID;
218 }
219
220 return rv;
221 }
222
223 void
224 IDBRequest::NotifyHelperSentResultsToChildProcess(nsresult aRv)
225 {
226 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
227 NS_ASSERTION(!mHaveResultOrErrorCode, "Already called!");
228 NS_ASSERTION(JSVAL_IS_VOID(mResultVal), "Should be undefined!");
229
230 // See if our window is still valid. If not then we're going to pretend that
231 // we never completed.
232 if (NS_FAILED(CheckInnerWindowCorrectness())) {
233 return;
234 }
235
236 mHaveResultOrErrorCode = true;
237
238 if (NS_FAILED(aRv)) {
239 SetError(aRv);
240 }
241 }
242
243 void
244 IDBRequest::SetError(nsresult aRv)
245 {
246 NS_ASSERTION(NS_FAILED(aRv), "Er, what?");
247 NS_ASSERTION(!mError, "Already have an error?");
248
249 mHaveResultOrErrorCode = true;
250 mError = new mozilla::dom::DOMError(GetOwner(), aRv);
251 mErrorCode = aRv;
252
253 mResultVal = JSVAL_VOID;
254 }
255
256 #ifdef DEBUG
257 nsresult
258 IDBRequest::GetErrorCode() const
259 {
260 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
261 NS_ASSERTION(mHaveResultOrErrorCode, "Don't call me yet!");
262 return mErrorCode;
263 }
264 #endif
265
266 JSContext*
267 IDBRequest::GetJSContext()
268 {
269 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
270
271 JSContext* cx;
272
273 if (GetScriptOwner()) {
274 return nsContentUtils::GetSafeJSContext();
275 }
276
277 nsresult rv;
278 nsIScriptContext* sc = GetContextForEventHandlers(&rv);
279 NS_ENSURE_SUCCESS(rv, nullptr);
280 NS_ENSURE_TRUE(sc, nullptr);
281
282 cx = sc->GetNativeContext();
283 NS_ASSERTION(cx, "Failed to get a context!");
284
285 return cx;
286 }
287
288 void
289 IDBRequest::CaptureCaller()
290 {
291 AutoJSContext cx;
292
293 const char* filename = nullptr;
294 uint32_t lineNo = 0;
295 if (!nsJSUtils::GetCallingLocation(cx, &filename, &lineNo)) {
296 NS_WARNING("Failed to get caller.");
297 return;
298 }
299
300 mFilename.Assign(NS_ConvertUTF8toUTF16(filename));
301 mLineNo = lineNo;
302 }
303
304 void
305 IDBRequest::FillScriptErrorEvent(ErrorEventInit& aEventInit) const
306 {
307 aEventInit.mLineno = mLineNo;
308 aEventInit.mFilename = mFilename;
309 }
310
311 mozilla::dom::IDBRequestReadyState
312 IDBRequest::ReadyState() const
313 {
314 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
315
316 if (IsPending()) {
317 return IDBRequestReadyState::Pending;
318 }
319
320 return IDBRequestReadyState::Done;
321 }
322
323 JSObject*
324 IDBRequest::WrapObject(JSContext* aCx)
325 {
326 return IDBRequestBinding::Wrap(aCx, this);
327 }
328
329 void
330 IDBRequest::GetResult(JSContext* aCx, JS::MutableHandle<JS::Value> aResult,
331 ErrorResult& aRv) const
332 {
333 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
334
335 if (!mHaveResultOrErrorCode) {
336 // XXX Need a real error code here.
337 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
338 }
339
340 JS::ExposeValueToActiveJS(mResultVal);
341 aResult.set(mResultVal);
342 }
343
344 mozilla::dom::DOMError*
345 IDBRequest::GetError(mozilla::ErrorResult& aRv)
346 {
347 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
348
349 if (!mHaveResultOrErrorCode) {
350 aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
351 return nullptr;
352 }
353
354 return mError;
355 }
356
357 NS_IMPL_CYCLE_COLLECTION_CLASS(IDBRequest)
358
359 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(IDBRequest, IDBWrapperCache)
360 // Don't need NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS because
361 // DOMEventTargetHelper does it for us.
362 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSourceAsObjectStore)
363 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSourceAsIndex)
364 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSourceAsCursor)
365 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTransaction)
366 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mError)
367 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
368
369 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(IDBRequest, IDBWrapperCache)
370 tmp->mResultVal = JSVAL_VOID;
371 NS_IMPL_CYCLE_COLLECTION_UNLINK(mSourceAsObjectStore)
372 NS_IMPL_CYCLE_COLLECTION_UNLINK(mSourceAsIndex)
373 NS_IMPL_CYCLE_COLLECTION_UNLINK(mSourceAsCursor)
374 NS_IMPL_CYCLE_COLLECTION_UNLINK(mTransaction)
375 NS_IMPL_CYCLE_COLLECTION_UNLINK(mError)
376 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
377
378 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(IDBRequest, IDBWrapperCache)
379 // Don't need NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER because
380 // DOMEventTargetHelper does it for us.
381 NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mResultVal)
382 NS_IMPL_CYCLE_COLLECTION_TRACE_END
383
384 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(IDBRequest)
385 NS_INTERFACE_MAP_END_INHERITING(IDBWrapperCache)
386
387 NS_IMPL_ADDREF_INHERITED(IDBRequest, IDBWrapperCache)
388 NS_IMPL_RELEASE_INHERITED(IDBRequest, IDBWrapperCache)
389
390 nsresult
391 IDBRequest::PreHandleEvent(EventChainPreVisitor& aVisitor)
392 {
393 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
394
395 aVisitor.mCanHandle = true;
396 aVisitor.mParentTarget = mTransaction;
397 return NS_OK;
398 }
399
400 IDBOpenDBRequest::IDBOpenDBRequest(nsPIDOMWindow* aOwner)
401 : IDBRequest(aOwner)
402 {
403 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
404 }
405
406 IDBOpenDBRequest::~IDBOpenDBRequest()
407 {
408 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
409 }
410
411 // static
412 already_AddRefed<IDBOpenDBRequest>
413 IDBOpenDBRequest::Create(IDBFactory* aFactory,
414 nsPIDOMWindow* aOwner,
415 JS::Handle<JSObject*> aScriptOwner)
416 {
417 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
418 NS_ASSERTION(aFactory, "Null pointer!");
419
420 nsRefPtr<IDBOpenDBRequest> request = new IDBOpenDBRequest(aOwner);
421
422 request->SetScriptOwner(aScriptOwner);
423 request->mFactory = aFactory;
424
425 if (!aFactory->FromIPC()) {
426 request->CaptureCaller();
427 }
428
429 return request.forget();
430 }
431
432 void
433 IDBOpenDBRequest::SetTransaction(IDBTransaction* aTransaction)
434 {
435 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
436
437 NS_ASSERTION(!aTransaction || !mTransaction,
438 "Shouldn't have a transaction here!");
439
440 mTransaction = aTransaction;
441 }
442
443 NS_IMPL_CYCLE_COLLECTION_CLASS(IDBOpenDBRequest)
444
445 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(IDBOpenDBRequest,
446 IDBRequest)
447 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFactory)
448 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
449
450 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(IDBOpenDBRequest,
451 IDBRequest)
452 // Don't unlink mFactory!
453 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
454
455 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(IDBOpenDBRequest)
456 NS_INTERFACE_MAP_END_INHERITING(IDBRequest)
457
458 NS_IMPL_ADDREF_INHERITED(IDBOpenDBRequest, IDBRequest)
459 NS_IMPL_RELEASE_INHERITED(IDBOpenDBRequest, IDBRequest)
460
461 nsresult
462 IDBOpenDBRequest::PostHandleEvent(EventChainPostVisitor& aVisitor)
463 {
464 return IndexedDatabaseManager::FireWindowOnError(GetOwner(), aVisitor);
465 }
466
467 JSObject*
468 IDBOpenDBRequest::WrapObject(JSContext* aCx)
469 {
470 return IDBOpenDBRequestBinding::Wrap(aCx, this);
471 }

mercurial