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"
24 #include "nsThreadUtils.h"
25 #include "nsWrapperCacheInlines.h"
27 #include "AsyncConnectionHelper.h"
28 #include "IDBCursor.h"
29 #include "IDBEvents.h"
30 #include "IDBFactory.h"
32 #include "IDBObjectStore.h"
33 #include "IDBTransaction.h"
34 #include "ReportInternalError.h"
38 #ifdef MOZ_ENABLE_PROFILER_SPS
39 uint64_t gNextRequestSerialNumber
= 1;
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
++),
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
++),
72 mHaveResultOrErrorCode(false)
74 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
77 IDBRequest::~IDBRequest()
79 mResultVal
= JSVAL_VOID
;
80 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
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();
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();
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();
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
136 MOZ_ASSERT(!!mSourceAsObjectStore
+ !!mSourceAsIndex
+ !!mSourceAsCursor
<= 1);
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
;
161 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
162 mResultVal
= JSVAL_VOID
;
163 mHaveResultOrErrorCode
= false;
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.
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())) {
190 // Otherwise we need to get the result from the helper.
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.
197 ac
.emplace(jsapi
.cx(), GetScriptOwner());
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
;
207 JSContext
* cx
= jsapi
.cx();
211 JS::Rooted
<JS::Value
> value(cx
);
212 rv
= aHelper
->GetSuccessResult(cx
, &value
);
214 NS_WARNING("GetSuccessResult failed!");
217 if (NS_SUCCEEDED(rv
)) {
223 mResultVal
= JSVAL_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())) {
242 mHaveResultOrErrorCode
= true;
244 if (NS_FAILED(aRv
)) {
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
);
259 mResultVal
= JSVAL_VOID
;
264 IDBRequest::GetErrorCode() const
266 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
267 NS_ASSERTION(mHaveResultOrErrorCode
, "Don't call me yet!");
273 IDBRequest::CaptureCaller()
277 const char* filename
= nullptr;
279 if (!nsJSUtils::GetCallingLocation(cx
, &filename
, &lineNo
)) {
280 NS_WARNING("Failed to get caller.");
284 mFilename
.Assign(NS_ConvertUTF8toUTF16(filename
));
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!");
301 return IDBRequestReadyState::Pending
;
304 return IDBRequestReadyState::Done
;
308 IDBRequest::WrapObject(JSContext
* aCx
)
310 return IDBRequestBinding::Wrap(aCx
, this);
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
);
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
)
375 IDBRequest::PreHandleEvent(EventChainPreVisitor
& aVisitor
)
377 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
379 aVisitor
.mCanHandle
= true;
380 aVisitor
.mParentTarget
= mTransaction
;
384 IDBOpenDBRequest::IDBOpenDBRequest(nsPIDOMWindow
* aOwner
)
387 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
390 IDBOpenDBRequest::~IDBOpenDBRequest()
392 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
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();
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
,
431 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFactory
)
432 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
434 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(IDBOpenDBRequest
,
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
)
446 IDBOpenDBRequest::PostHandleEvent(EventChainPostVisitor
& aVisitor
)
448 return IndexedDatabaseManager::FireWindowOnError(GetOwner(), aVisitor
);
452 IDBOpenDBRequest::WrapObject(JSContext
* aCx
)
454 return IDBOpenDBRequestBinding::Wrap(aCx
, this);