Bumping gaia.json for 2 gaia revision(s) a=gaia-bump
[gecko.git] / dom / indexedDB / IDBRequest.cpp
blobe778a4bfdeec0ec6c42456393d12720df7ae8e42
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/. */
7 #include "IDBRequest.h"
9 #include "nsIScriptContext.h"
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/ScriptSettings.h"
16 #include "mozilla/dom/UnionTypes.h"
17 #include "nsComponentManagerUtils.h"
18 #include "nsDOMClassInfoID.h"
19 #include "nsDOMJSUtils.h"
20 #include "nsContentUtils.h"
21 #include "nsJSUtils.h"
22 #include "nsPIDOMWindow.h"
23 #include "nsString.h"
24 #include "nsThreadUtils.h"
25 #include "nsWrapperCacheInlines.h"
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"
36 namespace {
38 #ifdef MOZ_ENABLE_PROFILER_SPS
39 uint64_t gNextRequestSerialNumber = 1;
40 #endif
42 } // anonymous namespace
44 USING_INDEXEDDB_NAMESPACE
45 using mozilla::dom::OwningIDBObjectStoreOrIDBIndexOrIDBCursor;
46 using mozilla::dom::ErrorEventInit;
47 using namespace mozilla;
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)
60 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
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)
74 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
77 IDBRequest::~IDBRequest()
79 mResultVal = JSVAL_VOID;
80 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
83 // static
84 already_AddRefed<IDBRequest>
85 IDBRequest::Create(IDBDatabase* aDatabase,
86 IDBTransaction* aTransaction)
88 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
89 nsRefPtr<IDBRequest> request(new IDBRequest(aDatabase));
91 request->mTransaction = aTransaction;
92 request->SetScriptOwner(aDatabase->GetScriptOwner());
94 if (!aDatabase->Factory()->FromIPC()) {
95 request->CaptureCaller();
99 return request.forget();
102 // static
103 already_AddRefed<IDBRequest>
104 IDBRequest::Create(IDBObjectStore* aSourceAsObjectStore,
105 IDBDatabase* aDatabase,
106 IDBTransaction* aTransaction)
108 nsRefPtr<IDBRequest> request = Create(aDatabase, aTransaction);
110 request->mSourceAsObjectStore = aSourceAsObjectStore;
112 return request.forget();
115 // static
116 already_AddRefed<IDBRequest>
117 IDBRequest::Create(IDBIndex* aSourceAsIndex,
118 IDBDatabase* aDatabase,
119 IDBTransaction* aTransaction)
121 nsRefPtr<IDBRequest> request = Create(aDatabase, aTransaction);
123 request->mSourceAsIndex = aSourceAsIndex;
125 return request.forget();
128 #ifdef DEBUG
129 void
130 IDBRequest::AssertSourceIsCorrect() const
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.
136 MOZ_ASSERT(!!mSourceAsObjectStore + !!mSourceAsIndex + !!mSourceAsCursor <= 1);
138 #endif
140 void
141 IDBRequest::GetSource(Nullable<OwningIDBObjectStoreOrIDBIndexOrIDBCursor>& aSource) const
143 MOZ_ASSERT(NS_IsMainThread());
145 AssertSourceIsCorrect();
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();
158 void
159 IDBRequest::Reset()
161 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
162 mResultVal = JSVAL_VOID;
163 mHaveResultOrErrorCode = false;
164 mError = nullptr;
167 nsresult
168 IDBRequest::NotifyHelperCompleted(HelperBase* aHelper)
170 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
171 NS_ASSERTION(!mHaveResultOrErrorCode, "Already called!");
172 NS_ASSERTION(mResultVal.isUndefined(), "Should be undefined!");
174 mHaveResultOrErrorCode = true;
176 nsresult rv = aHelper->GetResultCode();
178 // If the request failed then set the error code and return.
179 if (NS_FAILED(rv)) {
180 SetError(rv);
181 return NS_OK;
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;
190 // Otherwise we need to get the result from the helper.
191 AutoJSAPI jsapi;
192 Maybe<JSAutoCompartment> ac;
193 if (GetScriptOwner()) {
194 // If we have a script owner we want the SafeJSContext and then to enter
195 // the script owner's compartment.
196 jsapi.Init();
197 ac.emplace(jsapi.cx(), GetScriptOwner());
198 } else {
199 // Otherwise our owner is a window and we use that to initialize.
200 if (!jsapi.InitWithLegacyErrorReporting(GetOwner())) {
201 IDB_WARNING("Failed to initialise AutoJSAPI!");
202 rv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
203 SetError(rv);
204 return rv;
207 JSContext* cx = jsapi.cx();
209 AssertIsRooted();
211 JS::Rooted<JS::Value> value(cx);
212 rv = aHelper->GetSuccessResult(cx, &value);
213 if (NS_FAILED(rv)) {
214 NS_WARNING("GetSuccessResult failed!");
217 if (NS_SUCCEEDED(rv)) {
218 mError = nullptr;
219 mResultVal = value;
221 else {
222 SetError(rv);
223 mResultVal = JSVAL_VOID;
226 return rv;
229 void
230 IDBRequest::NotifyHelperSentResultsToChildProcess(nsresult aRv)
232 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
233 NS_ASSERTION(!mHaveResultOrErrorCode, "Already called!");
234 NS_ASSERTION(mResultVal.isUndefined(), "Should be undefined!");
236 // See if our window is still valid. If not then we're going to pretend that
237 // we never completed.
238 if (NS_FAILED(CheckInnerWindowCorrectness())) {
239 return;
242 mHaveResultOrErrorCode = true;
244 if (NS_FAILED(aRv)) {
245 SetError(aRv);
249 void
250 IDBRequest::SetError(nsresult aRv)
252 NS_ASSERTION(NS_FAILED(aRv), "Er, what?");
253 NS_ASSERTION(!mError, "Already have an error?");
255 mHaveResultOrErrorCode = true;
256 mError = new mozilla::dom::DOMError(GetOwner(), aRv);
257 mErrorCode = aRv;
259 mResultVal = JSVAL_VOID;
262 #ifdef DEBUG
263 nsresult
264 IDBRequest::GetErrorCode() const
266 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
267 NS_ASSERTION(mHaveResultOrErrorCode, "Don't call me yet!");
268 return mErrorCode;
270 #endif
272 void
273 IDBRequest::CaptureCaller()
275 AutoJSContext cx;
277 const char* filename = nullptr;
278 uint32_t lineNo = 0;
279 if (!nsJSUtils::GetCallingLocation(cx, &filename, &lineNo)) {
280 NS_WARNING("Failed to get caller.");
281 return;
284 mFilename.Assign(NS_ConvertUTF8toUTF16(filename));
285 mLineNo = lineNo;
288 void
289 IDBRequest::FillScriptErrorEvent(ErrorEventInit& aEventInit) const
291 aEventInit.mLineno = mLineNo;
292 aEventInit.mFilename = mFilename;
295 mozilla::dom::IDBRequestReadyState
296 IDBRequest::ReadyState() const
298 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
300 if (IsPending()) {
301 return IDBRequestReadyState::Pending;
304 return IDBRequestReadyState::Done;
307 JSObject*
308 IDBRequest::WrapObject(JSContext* aCx)
310 return IDBRequestBinding::Wrap(aCx, this);
313 void
314 IDBRequest::GetResult(JS::MutableHandle<JS::Value> aResult,
315 ErrorResult& aRv) const
317 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
319 if (!mHaveResultOrErrorCode) {
320 // XXX Need a real error code here.
321 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
324 JS::ExposeValueToActiveJS(mResultVal);
325 aResult.set(mResultVal);
328 mozilla::dom::DOMError*
329 IDBRequest::GetError(mozilla::ErrorResult& aRv)
331 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
333 if (!mHaveResultOrErrorCode) {
334 aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
335 return nullptr;
338 return mError;
341 NS_IMPL_CYCLE_COLLECTION_CLASS(IDBRequest)
343 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(IDBRequest, IDBWrapperCache)
344 // Don't need NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS because
345 // DOMEventTargetHelper does it for us.
346 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSourceAsObjectStore)
347 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSourceAsIndex)
348 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSourceAsCursor)
349 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTransaction)
350 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mError)
351 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
353 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(IDBRequest, IDBWrapperCache)
354 tmp->mResultVal = JSVAL_VOID;
355 NS_IMPL_CYCLE_COLLECTION_UNLINK(mSourceAsObjectStore)
356 NS_IMPL_CYCLE_COLLECTION_UNLINK(mSourceAsIndex)
357 NS_IMPL_CYCLE_COLLECTION_UNLINK(mSourceAsCursor)
358 NS_IMPL_CYCLE_COLLECTION_UNLINK(mTransaction)
359 NS_IMPL_CYCLE_COLLECTION_UNLINK(mError)
360 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
362 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(IDBRequest, IDBWrapperCache)
363 // Don't need NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER because
364 // DOMEventTargetHelper does it for us.
365 NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mResultVal)
366 NS_IMPL_CYCLE_COLLECTION_TRACE_END
368 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(IDBRequest)
369 NS_INTERFACE_MAP_END_INHERITING(IDBWrapperCache)
371 NS_IMPL_ADDREF_INHERITED(IDBRequest, IDBWrapperCache)
372 NS_IMPL_RELEASE_INHERITED(IDBRequest, IDBWrapperCache)
374 nsresult
375 IDBRequest::PreHandleEvent(EventChainPreVisitor& aVisitor)
377 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
379 aVisitor.mCanHandle = true;
380 aVisitor.mParentTarget = mTransaction;
381 return NS_OK;
384 IDBOpenDBRequest::IDBOpenDBRequest(nsPIDOMWindow* aOwner)
385 : IDBRequest(aOwner)
387 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
390 IDBOpenDBRequest::~IDBOpenDBRequest()
392 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
395 // static
396 already_AddRefed<IDBOpenDBRequest>
397 IDBOpenDBRequest::Create(IDBFactory* aFactory,
398 nsPIDOMWindow* aOwner,
399 JS::Handle<JSObject*> aScriptOwner)
401 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
402 NS_ASSERTION(aFactory, "Null pointer!");
404 nsRefPtr<IDBOpenDBRequest> request = new IDBOpenDBRequest(aOwner);
406 request->SetScriptOwner(aScriptOwner);
407 request->mFactory = aFactory;
409 if (!aFactory->FromIPC()) {
410 request->CaptureCaller();
413 return request.forget();
416 void
417 IDBOpenDBRequest::SetTransaction(IDBTransaction* aTransaction)
419 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
421 NS_ASSERTION(!aTransaction || !mTransaction,
422 "Shouldn't have a transaction here!");
424 mTransaction = aTransaction;
427 NS_IMPL_CYCLE_COLLECTION_CLASS(IDBOpenDBRequest)
429 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(IDBOpenDBRequest,
430 IDBRequest)
431 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFactory)
432 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
434 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(IDBOpenDBRequest,
435 IDBRequest)
436 // Don't unlink mFactory!
437 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
439 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(IDBOpenDBRequest)
440 NS_INTERFACE_MAP_END_INHERITING(IDBRequest)
442 NS_IMPL_ADDREF_INHERITED(IDBOpenDBRequest, IDBRequest)
443 NS_IMPL_RELEASE_INHERITED(IDBOpenDBRequest, IDBRequest)
445 nsresult
446 IDBOpenDBRequest::PostHandleEvent(EventChainPostVisitor& aVisitor)
448 return IndexedDatabaseManager::FireWindowOnError(GetOwner(), aVisitor);
451 JSObject*
452 IDBOpenDBRequest::WrapObject(JSContext* aCx)
454 return IDBOpenDBRequestBinding::Wrap(aCx, this);