1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=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 "IDBFactory.h"
9 #include "BackgroundChildImpl.h"
10 #include "IDBRequest.h"
11 #include "IndexedDatabaseManager.h"
12 #include "mozilla/BasePrincipal.h"
13 #include "mozilla/ErrorResult.h"
14 #include "mozilla/Preferences.h"
15 #include "mozilla/dom/BindingDeclarations.h"
16 #include "mozilla/dom/Document.h"
17 #include "mozilla/dom/IDBFactoryBinding.h"
18 #include "mozilla/dom/Promise.h"
19 #include "mozilla/dom/quota/QuotaManager.h"
20 #include "mozilla/dom/quota/ResultExtensions.h"
21 #include "mozilla/dom/BrowserChild.h"
22 #include "mozilla/dom/WorkerPrivate.h"
23 #include "mozilla/ipc/BackgroundChild.h"
24 #include "mozilla/ipc/BackgroundUtils.h"
25 #include "mozilla/ipc/PBackground.h"
26 #include "mozilla/ipc/PBackgroundChild.h"
27 #include "mozilla/StaticPrefs_dom.h"
28 #include "mozilla/StorageAccess.h"
29 #include "mozilla/Telemetry.h"
30 #include "nsAboutProtocolUtils.h"
31 #include "nsContentUtils.h"
32 #include "nsGlobalWindowInner.h"
33 #include "nsIAboutModule.h"
34 #include "nsILoadContext.h"
36 #include "nsIUUIDGenerator.h"
37 #include "nsIWebNavigation.h"
38 #include "nsNetUtil.h"
39 #include "nsSandboxFlags.h"
40 #include "nsServiceManagerUtils.h"
41 #include "ProfilerHelpers.h"
42 #include "ReportInternalError.h"
43 #include "ThreadLocal.h"
45 // Include this last to avoid path problems on Windows.
46 #include "ActorsChild.h"
48 namespace mozilla::dom
{
50 using namespace mozilla::dom::indexedDB
;
51 using namespace mozilla::dom::quota
;
52 using namespace mozilla::ipc
;
56 Telemetry::LABELS_IDB_CUSTOM_OPEN_WITH_OPTIONS_COUNT
IdentifyPrincipalType(
57 const mozilla::ipc::PrincipalInfo
& aPrincipalInfo
) {
58 switch (aPrincipalInfo
.type()) {
59 case PrincipalInfo::TSystemPrincipalInfo
:
60 return Telemetry::LABELS_IDB_CUSTOM_OPEN_WITH_OPTIONS_COUNT::system
;
61 case PrincipalInfo::TContentPrincipalInfo
: {
62 const ContentPrincipalInfo
& info
=
63 aPrincipalInfo
.get_ContentPrincipalInfo();
67 if (NS_WARN_IF(NS_FAILED(NS_NewURI(getter_AddRefs(uri
), info
.spec())))) {
68 // This could be discriminated as an extra error value, but this is
69 // extremely unlikely to fail, so we just misuse ContentOther
70 return Telemetry::LABELS_IDB_CUSTOM_OPEN_WITH_OPTIONS_COUNT::
74 // TODO Are there constants defined for the schemes somewhere?
75 if (uri
->SchemeIs("file")) {
76 return Telemetry::LABELS_IDB_CUSTOM_OPEN_WITH_OPTIONS_COUNT::
79 if (uri
->SchemeIs("http") || uri
->SchemeIs("https")) {
80 return Telemetry::LABELS_IDB_CUSTOM_OPEN_WITH_OPTIONS_COUNT::
83 if (uri
->SchemeIs("moz-extension")) {
84 return Telemetry::LABELS_IDB_CUSTOM_OPEN_WITH_OPTIONS_COUNT::
87 if (uri
->SchemeIs("about")) {
88 return Telemetry::LABELS_IDB_CUSTOM_OPEN_WITH_OPTIONS_COUNT::
91 return Telemetry::LABELS_IDB_CUSTOM_OPEN_WITH_OPTIONS_COUNT::
94 case PrincipalInfo::TExpandedPrincipalInfo
:
95 return Telemetry::LABELS_IDB_CUSTOM_OPEN_WITH_OPTIONS_COUNT::expanded
;
97 return Telemetry::LABELS_IDB_CUSTOM_OPEN_WITH_OPTIONS_COUNT::other
;
103 struct IDBFactory::PendingRequestInfo
{
104 RefPtr
<IDBOpenDBRequest
> mRequest
;
105 FactoryRequestParams mParams
;
107 PendingRequestInfo(IDBOpenDBRequest
* aRequest
,
108 const FactoryRequestParams
& aParams
)
109 : mRequest(aRequest
), mParams(aParams
) {
110 MOZ_ASSERT(aRequest
);
111 MOZ_ASSERT(aParams
.type() != FactoryRequestParams::T__None
);
115 IDBFactory::IDBFactory(const IDBFactoryGuard
&)
116 : mBackgroundActor(nullptr),
118 mActiveTransactionCount(0),
119 mActiveDatabaseCount(0),
120 mBackgroundActorFailed(false),
121 mPrivateBrowsingMode(false) {
122 AssertIsOnOwningThread();
125 IDBFactory::~IDBFactory() {
126 MOZ_ASSERT_IF(mBackgroundActorFailed
, !mBackgroundActor
);
128 if (mBackgroundActor
) {
129 mBackgroundActor
->SendDeleteMeInternal();
130 MOZ_ASSERT(!mBackgroundActor
, "SendDeleteMeInternal should have cleared!");
135 Result
<RefPtr
<IDBFactory
>, nsresult
> IDBFactory::CreateForWindow(
136 nsPIDOMWindowInner
* aWindow
) {
137 MOZ_ASSERT(NS_IsMainThread());
140 nsCOMPtr
<nsIPrincipal
> principal
;
141 nsresult rv
= AllowedForWindowInternal(aWindow
, &principal
);
143 if (rv
== NS_ERROR_DOM_NOT_SUPPORTED_ERR
) {
144 NS_WARNING("IndexedDB is not permitted in a third-party window.");
145 return RefPtr
<IDBFactory
>{};
148 if (NS_WARN_IF(NS_FAILED(rv
))) {
149 if (rv
== NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
) {
150 IDB_REPORT_INTERNAL_ERR();
155 MOZ_ASSERT(principal
);
157 auto principalInfo
= MakeUnique
<PrincipalInfo
>();
158 rv
= PrincipalToPrincipalInfo(principal
, principalInfo
.get());
159 if (NS_WARN_IF(NS_FAILED(rv
))) {
160 IDB_REPORT_INTERNAL_ERR();
161 return Err(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
164 MOZ_ASSERT(principalInfo
->type() == PrincipalInfo::TContentPrincipalInfo
||
165 principalInfo
->type() == PrincipalInfo::TSystemPrincipalInfo
);
167 if (NS_WARN_IF(!QuotaManager::IsPrincipalInfoValid(*principalInfo
))) {
168 IDB_REPORT_INTERNAL_ERR();
169 return Err(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
172 nsCOMPtr
<nsIWebNavigation
> webNav
= do_GetInterface(aWindow
);
173 nsCOMPtr
<nsILoadContext
> loadContext
= do_QueryInterface(webNav
);
175 auto factory
= MakeRefPtr
<IDBFactory
>(IDBFactoryGuard
{});
176 factory
->mPrincipalInfo
= std::move(principalInfo
);
178 factory
->BindToOwner(aWindow
->AsGlobal());
180 factory
->mBrowserChild
= BrowserChild::GetFrom(aWindow
);
181 factory
->mEventTarget
=
182 nsGlobalWindowInner::Cast(aWindow
)->SerialEventTarget();
183 factory
->mInnerWindowID
= aWindow
->WindowID();
184 factory
->mPrivateBrowsingMode
=
185 loadContext
&& loadContext
->UsePrivateBrowsing();
191 Result
<RefPtr
<IDBFactory
>, nsresult
> IDBFactory::CreateForMainThreadJS(
192 nsIGlobalObject
* aGlobal
) {
193 MOZ_ASSERT(NS_IsMainThread());
196 nsCOMPtr
<nsIScriptObjectPrincipal
> sop
= do_QueryInterface(aGlobal
);
197 if (NS_WARN_IF(!sop
)) {
198 return Err(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
201 auto principalInfo
= MakeUnique
<PrincipalInfo
>();
202 nsIPrincipal
* principal
= sop
->GetEffectiveStoragePrincipal();
203 MOZ_ASSERT(principal
);
205 if (!AllowedForPrincipal(principal
, &isSystem
)) {
206 return Err(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
209 nsresult rv
= PrincipalToPrincipalInfo(principal
, principalInfo
.get());
210 if (NS_WARN_IF(NS_FAILED(rv
))) {
214 if (NS_WARN_IF(!QuotaManager::IsPrincipalInfoValid(*principalInfo
))) {
215 return Err(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
218 return CreateForMainThreadJSInternal(aGlobal
, std::move(principalInfo
));
222 Result
<RefPtr
<IDBFactory
>, nsresult
> IDBFactory::CreateForWorker(
223 nsIGlobalObject
* aGlobal
, const PrincipalInfo
& aPrincipalInfo
,
224 uint64_t aInnerWindowID
) {
225 MOZ_ASSERT(!NS_IsMainThread());
227 MOZ_ASSERT(aPrincipalInfo
.type() != PrincipalInfo::T__None
);
229 return CreateInternal(aGlobal
, MakeUnique
<PrincipalInfo
>(aPrincipalInfo
),
234 Result
<RefPtr
<IDBFactory
>, nsresult
> IDBFactory::CreateForMainThreadJSInternal(
235 nsIGlobalObject
* aGlobal
, UniquePtr
<PrincipalInfo
> aPrincipalInfo
) {
236 MOZ_ASSERT(NS_IsMainThread());
238 MOZ_ASSERT(aPrincipalInfo
);
240 IndexedDatabaseManager
* mgr
= IndexedDatabaseManager::GetOrCreate();
241 if (NS_WARN_IF(!mgr
)) {
242 IDB_REPORT_INTERNAL_ERR();
243 return Err(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
246 nsresult rv
= mgr
->EnsureLocale();
247 if (NS_WARN_IF(NS_FAILED(rv
))) {
248 IDB_REPORT_INTERNAL_ERR();
249 return Err(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
252 return CreateInternal(aGlobal
, std::move(aPrincipalInfo
),
253 /* aInnerWindowID */ 0);
257 Result
<RefPtr
<IDBFactory
>, nsresult
> IDBFactory::CreateInternal(
258 nsIGlobalObject
* aGlobal
, UniquePtr
<PrincipalInfo
> aPrincipalInfo
,
259 uint64_t aInnerWindowID
) {
261 MOZ_ASSERT(aPrincipalInfo
);
262 MOZ_ASSERT(aPrincipalInfo
->type() != PrincipalInfo::T__None
);
264 if (aPrincipalInfo
->type() != PrincipalInfo::TContentPrincipalInfo
&&
265 aPrincipalInfo
->type() != PrincipalInfo::TSystemPrincipalInfo
) {
266 NS_WARNING("IndexedDB not allowed for this principal!");
267 return RefPtr
<IDBFactory
>{};
270 auto factory
= MakeRefPtr
<IDBFactory
>(IDBFactoryGuard
{});
271 factory
->mPrincipalInfo
= std::move(aPrincipalInfo
);
272 factory
->BindToOwner(aGlobal
);
273 factory
->mEventTarget
= GetCurrentSerialEventTarget();
274 factory
->mInnerWindowID
= aInnerWindowID
;
280 bool IDBFactory::AllowedForWindow(nsPIDOMWindowInner
* aWindow
) {
281 MOZ_ASSERT(NS_IsMainThread());
284 return !NS_WARN_IF(NS_FAILED(AllowedForWindowInternal(aWindow
, nullptr)));
288 nsresult
IDBFactory::AllowedForWindowInternal(
289 nsPIDOMWindowInner
* aWindow
, nsCOMPtr
<nsIPrincipal
>* aPrincipal
) {
290 MOZ_ASSERT(NS_IsMainThread());
293 IndexedDatabaseManager
* mgr
= IndexedDatabaseManager::GetOrCreate();
294 if (NS_WARN_IF(!mgr
)) {
295 return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
;
298 nsresult rv
= mgr
->EnsureLocale();
299 if (NS_WARN_IF(NS_FAILED(rv
))) {
300 IDB_REPORT_INTERNAL_ERR();
301 return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
;
304 StorageAccess access
= StorageAllowedForWindow(aWindow
);
306 // the factory callsite records whether the browser is in private browsing.
307 // and thus we don't have to respect that setting here. IndexedDB has no
308 // concept of session-local storage, and thus ignores it.
309 if (access
== StorageAccess::eDeny
) {
310 return NS_ERROR_DOM_SECURITY_ERR
;
313 if (ShouldPartitionStorage(access
) &&
314 !StoragePartitioningEnabled(
315 access
, aWindow
->GetExtantDoc()->CookieJarSettings())) {
316 return NS_ERROR_DOM_SECURITY_ERR
;
319 nsCOMPtr
<nsIScriptObjectPrincipal
> sop
= do_QueryInterface(aWindow
);
322 nsCOMPtr
<nsIPrincipal
> principal
= sop
->GetEffectiveStoragePrincipal();
323 if (NS_WARN_IF(!principal
)) {
324 return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
;
327 if (principal
->IsSystemPrincipal()) {
328 *aPrincipal
= std::move(principal
);
332 // About URIs shouldn't be able to access IndexedDB unless they have the
333 // nsIAboutModule::ENABLE_INDEXED_DB flag set on them.
335 if (principal
->SchemeIs("about")) {
337 if (NS_SUCCEEDED(principal
->GetAboutModuleFlags(&flags
))) {
338 if (!(flags
& nsIAboutModule::ENABLE_INDEXED_DB
)) {
339 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
342 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
347 *aPrincipal
= std::move(principal
);
353 bool IDBFactory::AllowedForPrincipal(nsIPrincipal
* aPrincipal
,
354 bool* aIsSystemPrincipal
) {
355 MOZ_ASSERT(NS_IsMainThread());
356 MOZ_ASSERT(aPrincipal
);
358 IndexedDatabaseManager
* mgr
= IndexedDatabaseManager::GetOrCreate();
359 if (NS_WARN_IF(!mgr
)) {
363 nsresult rv
= mgr
->EnsureLocale();
364 if (NS_WARN_IF(NS_FAILED(rv
))) {
368 if (aPrincipal
->IsSystemPrincipal()) {
369 if (aIsSystemPrincipal
) {
370 *aIsSystemPrincipal
= true;
375 if (aIsSystemPrincipal
) {
376 *aIsSystemPrincipal
= false;
379 return !aPrincipal
->GetIsNullPrincipal();
383 PersistenceType
IDBFactory::GetPersistenceType(
384 const PrincipalInfo
& aPrincipalInfo
) {
385 if (aPrincipalInfo
.type() == PrincipalInfo::TSystemPrincipalInfo
) {
386 // Chrome privilege always gets persistent storage.
387 return PERSISTENCE_TYPE_PERSISTENT
;
390 if (aPrincipalInfo
.type() == PrincipalInfo::TContentPrincipalInfo
) {
392 aPrincipalInfo
.get_ContentPrincipalInfo().originNoSuffix();
394 if (QuotaManager::IsOriginInternal(origin
)) {
395 // Internal origins always get persistent storage.
396 return PERSISTENCE_TYPE_PERSISTENT
;
399 if (aPrincipalInfo
.get_ContentPrincipalInfo().attrs().mPrivateBrowsingId
>
401 return PERSISTENCE_TYPE_PRIVATE
;
405 return PERSISTENCE_TYPE_DEFAULT
;
408 void IDBFactory::UpdateActiveTransactionCount(int32_t aDelta
) {
409 AssertIsOnOwningThread();
410 MOZ_DIAGNOSTIC_ASSERT(aDelta
> 0 || (mActiveTransactionCount
+ aDelta
) <
411 mActiveTransactionCount
);
412 mActiveTransactionCount
+= aDelta
;
415 void IDBFactory::UpdateActiveDatabaseCount(int32_t aDelta
) {
416 AssertIsOnOwningThread();
417 MOZ_DIAGNOSTIC_ASSERT(aDelta
> 0 ||
418 (mActiveDatabaseCount
+ aDelta
) < mActiveDatabaseCount
);
419 mActiveDatabaseCount
+= aDelta
;
422 GetOwner()->UpdateActiveIndexedDBDatabaseCount(aDelta
);
426 bool IDBFactory::IsChrome() const {
427 AssertIsOnOwningThread();
428 MOZ_ASSERT(mPrincipalInfo
);
430 return mPrincipalInfo
->type() == PrincipalInfo::TSystemPrincipalInfo
;
433 RefPtr
<IDBOpenDBRequest
> IDBFactory::Open(JSContext
* aCx
,
434 const nsAString
& aName
,
436 CallerType aCallerType
,
438 return OpenInternal(aCx
,
439 /* aPrincipal */ nullptr, aName
,
440 Optional
<uint64_t>(aVersion
),
441 /* aDeleting */ false, aCallerType
, aRv
);
444 RefPtr
<IDBOpenDBRequest
> IDBFactory::Open(JSContext
* aCx
,
445 const nsAString
& aName
,
446 const IDBOpenDBOptions
& aOptions
,
447 CallerType aCallerType
,
449 // This overload is nonstandard, see bug 1275496.
450 // Ignore calls with empty options for telemetry of usage count.
451 // Unfortunately, we cannot distinguish between the use of the method with
452 // only a single argument (which actually is a standard overload we don't want
453 // to count) an empty dictionary passed explicitly (which is the custom
454 // overload we would like to count). However, we assume that the latter is so
455 // rare that it can be neglected.
456 if (aOptions
.IsAnyMemberPresent()) {
457 Telemetry::AccumulateCategorical(IdentifyPrincipalType(*mPrincipalInfo
));
460 return OpenInternal(aCx
,
461 /* aPrincipal */ nullptr, aName
, aOptions
.mVersion
,
462 /* aDeleting */ false, aCallerType
, aRv
);
465 RefPtr
<IDBOpenDBRequest
> IDBFactory::DeleteDatabase(
466 JSContext
* aCx
, const nsAString
& aName
, const IDBOpenDBOptions
& aOptions
,
467 CallerType aCallerType
, ErrorResult
& aRv
) {
468 return OpenInternal(aCx
,
469 /* aPrincipal */ nullptr, aName
, Optional
<uint64_t>(),
470 /* aDeleting */ true, aCallerType
, aRv
);
473 already_AddRefed
<Promise
> IDBFactory::Databases(JSContext
* const aCx
) {
474 RefPtr
<Promise
> promise
= Promise::CreateInfallible(GetOwnerGlobal());
476 // Nothing can be done here if we have previously failed to create a
478 if (mBackgroundActorFailed
) {
479 promise
->MaybeReject(NS_ERROR_FAILURE
);
480 return promise
.forget();
483 PersistenceType persistenceType
= GetPersistenceType(*mPrincipalInfo
);
485 QM_TRY(MOZ_TO_RESULT(EnsureBackgroundActor()), [&promise
](const nsresult rv
) {
486 promise
->MaybeReject(rv
);
487 return promise
.forget();
490 mBackgroundActor
->SendGetDatabases(persistenceType
, *mPrincipalInfo
)
492 GetCurrentSerialEventTarget(), __func__
,
493 [promise
](const PBackgroundIDBFactoryChild::GetDatabasesPromise::
494 ResolveOrRejectValue
& aValue
) {
495 if (aValue
.IsReject()) {
496 promise
->MaybeReject(NS_ERROR_FAILURE
);
500 const GetDatabasesResponse
& response
= aValue
.ResolveValue();
502 switch (response
.type()) {
503 case GetDatabasesResponse::Tnsresult
:
504 promise
->MaybeReject(response
.get_nsresult());
508 case GetDatabasesResponse::TArrayOfDatabaseMetadata
: {
509 const auto& array
= response
.get_ArrayOfDatabaseMetadata();
511 Sequence
<IDBDatabaseInfo
> databaseInfos
;
513 for (const auto& databaseMetadata
: array
) {
514 IDBDatabaseInfo databaseInfo
;
516 databaseInfo
.mName
.Construct(databaseMetadata
.name());
517 databaseInfo
.mVersion
.Construct(databaseMetadata
.version());
519 if (!databaseInfos
.AppendElement(std::move(databaseInfo
),
521 promise
->MaybeRejectWithTypeError("Out of memory");
526 promise
->MaybeResolve(databaseInfos
);
531 MOZ_CRASH("Unknown response type!");
535 return promise
.forget();
538 int16_t IDBFactory::Cmp(JSContext
* aCx
, JS::Handle
<JS::Value
> aFirst
,
539 JS::Handle
<JS::Value
> aSecond
, ErrorResult
& aRv
) {
541 auto result
= first
.SetFromJSVal(aCx
, aFirst
);
542 if (result
.isErr()) {
543 aRv
= result
.unwrapErr().ExtractErrorResult(
544 InvalidMapsTo
<NS_ERROR_DOM_INDEXEDDB_DATA_ERR
>);
548 result
= second
.SetFromJSVal(aCx
, aSecond
);
549 if (result
.isErr()) {
550 aRv
= result
.unwrapErr().ExtractErrorResult(
551 InvalidMapsTo
<NS_ERROR_DOM_INDEXEDDB_DATA_ERR
>);
555 if (first
.IsUnset() || second
.IsUnset()) {
556 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR
);
560 return Key::CompareKeys(first
, second
);
563 RefPtr
<IDBOpenDBRequest
> IDBFactory::OpenForPrincipal(
564 JSContext
* aCx
, nsIPrincipal
* aPrincipal
, const nsAString
& aName
,
565 uint64_t aVersion
, SystemCallerGuarantee aGuarantee
, ErrorResult
& aRv
) {
566 MOZ_ASSERT(aPrincipal
);
567 if (!NS_IsMainThread()) {
569 "Figure out security checks for workers! What's this aPrincipal "
570 "we have on a worker thread?");
573 return OpenInternal(aCx
, aPrincipal
, aName
, Optional
<uint64_t>(aVersion
),
574 /* aDeleting */ false, aGuarantee
, aRv
);
577 RefPtr
<IDBOpenDBRequest
> IDBFactory::OpenForPrincipal(
578 JSContext
* aCx
, nsIPrincipal
* aPrincipal
, const nsAString
& aName
,
579 const IDBOpenDBOptions
& aOptions
, SystemCallerGuarantee aGuarantee
,
581 MOZ_ASSERT(aPrincipal
);
582 if (!NS_IsMainThread()) {
584 "Figure out security checks for workers! What's this aPrincipal "
585 "we have on a worker thread?");
588 return OpenInternal(aCx
, aPrincipal
, aName
, aOptions
.mVersion
,
589 /* aDeleting */ false, aGuarantee
, aRv
);
592 RefPtr
<IDBOpenDBRequest
> IDBFactory::DeleteForPrincipal(
593 JSContext
* aCx
, nsIPrincipal
* aPrincipal
, const nsAString
& aName
,
594 const IDBOpenDBOptions
& aOptions
, SystemCallerGuarantee aGuarantee
,
596 MOZ_ASSERT(aPrincipal
);
597 if (!NS_IsMainThread()) {
599 "Figure out security checks for workers! What's this aPrincipal "
600 "we have on a worker thread?");
603 return OpenInternal(aCx
, aPrincipal
, aName
, Optional
<uint64_t>(),
604 /* aDeleting */ true, aGuarantee
, aRv
);
607 nsresult
IDBFactory::EnsureBackgroundActor() {
608 if (mBackgroundActor
) {
612 BackgroundChildImpl::ThreadLocal
* threadLocal
=
613 BackgroundChildImpl::GetThreadLocalForCurrentThread();
615 UniquePtr
<ThreadLocal
> newIDBThreadLocal
;
616 ThreadLocal
* idbThreadLocal
;
618 if (threadLocal
&& threadLocal
->mIndexedDBThreadLocal
) {
619 idbThreadLocal
= threadLocal
->mIndexedDBThreadLocal
.get();
621 nsCOMPtr
<nsIUUIDGenerator
> uuidGen
=
622 do_GetService("@mozilla.org/uuid-generator;1");
626 MOZ_ALWAYS_SUCCEEDS(uuidGen
->GenerateUUIDInPlace(&id
));
628 newIDBThreadLocal
= WrapUnique(new ThreadLocal(id
));
629 idbThreadLocal
= newIDBThreadLocal
.get();
632 PBackgroundChild
* backgroundActor
=
633 BackgroundChild::GetOrCreateForCurrentThread();
634 if (NS_WARN_IF(!backgroundActor
)) {
635 return NS_ERROR_FAILURE
;
639 BackgroundFactoryChild
* actor
= new BackgroundFactoryChild(*this);
641 mBackgroundActor
= static_cast<BackgroundFactoryChild
*>(
642 backgroundActor
->SendPBackgroundIDBFactoryConstructor(
643 actor
, idbThreadLocal
->GetLoggingInfo(),
644 IndexedDatabaseManager::GetLocale()));
646 if (NS_WARN_IF(!mBackgroundActor
)) {
647 return NS_ERROR_FAILURE
;
651 if (newIDBThreadLocal
) {
653 threadLocal
= BackgroundChildImpl::GetThreadLocalForCurrentThread();
655 MOZ_ASSERT(threadLocal
);
656 MOZ_ASSERT(!threadLocal
->mIndexedDBThreadLocal
);
658 threadLocal
->mIndexedDBThreadLocal
= std::move(newIDBThreadLocal
);
664 RefPtr
<IDBOpenDBRequest
> IDBFactory::OpenInternal(
665 JSContext
* aCx
, nsIPrincipal
* aPrincipal
, const nsAString
& aName
,
666 const Optional
<uint64_t>& aVersion
, bool aDeleting
, CallerType aCallerType
,
668 if (NS_WARN_IF(!GetOwnerGlobal())) {
669 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
673 CommonFactoryRequestParams commonParams
;
675 PrincipalInfo
& principalInfo
= commonParams
.principalInfo();
678 if (!NS_IsMainThread()) {
680 "Figure out security checks for workers! What's this "
681 "aPrincipal we have on a worker thread?");
683 MOZ_ASSERT(aCallerType
== CallerType::System
);
684 MOZ_DIAGNOSTIC_ASSERT(mPrivateBrowsingMode
==
685 (aPrincipal
->GetPrivateBrowsingId() > 0));
688 NS_FAILED(PrincipalToPrincipalInfo(aPrincipal
, &principalInfo
)))) {
689 IDB_REPORT_INTERNAL_ERR();
690 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
694 if (principalInfo
.type() != PrincipalInfo::TContentPrincipalInfo
&&
695 principalInfo
.type() != PrincipalInfo::TSystemPrincipalInfo
) {
696 IDB_REPORT_INTERNAL_ERR();
697 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
701 if (NS_WARN_IF(!QuotaManager::IsPrincipalInfoValid(principalInfo
))) {
702 IDB_REPORT_INTERNAL_ERR();
703 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
707 if (GetOwnerGlobal()->GetStorageAccess() ==
708 StorageAccess::ePrivateBrowsing
) {
709 if (NS_IsMainThread()) {
711 GetOwnerGlobal()->GetGlobalJSObject(),
713 ? eUseCounter_custom_PrivateBrowsingIDBFactoryOpen
714 : eUseCounter_custom_PrivateBrowsingIDBFactoryDeleteDatabase
);
717 aDeleting
? UseCounterWorker::Custom_PrivateBrowsingIDBFactoryOpen
719 Custom_PrivateBrowsingIDBFactoryDeleteDatabase
);
722 principalInfo
= *mPrincipalInfo
;
725 uint64_t version
= 0;
726 if (!aDeleting
&& aVersion
.WasPassed()) {
727 if (aVersion
.Value() < 1) {
728 aRv
.ThrowTypeError("0 (Zero) is not a valid database version.");
731 version
= aVersion
.Value();
734 // Nothing can be done here if we have previously failed to create a
736 if (mBackgroundActorFailed
) {
737 IDB_REPORT_INTERNAL_ERR();
738 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
742 PersistenceType persistenceType
= GetPersistenceType(principalInfo
);
744 DatabaseMetadata
& metadata
= commonParams
.metadata();
745 metadata
.name() = aName
;
746 metadata
.persistenceType() = persistenceType
;
748 FactoryRequestParams params
;
750 metadata
.version() = 0;
751 params
= DeleteDatabaseRequestParams(commonParams
);
753 metadata
.version() = version
;
754 params
= OpenDatabaseRequestParams(commonParams
);
757 nsresult rv
= EnsureBackgroundActor();
758 if (NS_WARN_IF(NS_FAILED(rv
))) {
759 IDB_REPORT_INTERNAL_ERR();
760 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
764 RefPtr
<IDBOpenDBRequest
> request
= IDBOpenDBRequest::Create(
765 aCx
, SafeRefPtr
{this, AcquireStrongRefFromRawPtr
{}}, GetOwnerGlobal());
767 MOZ_ASSERT(!NS_IsMainThread());
768 aRv
.ThrowUncatchableException();
775 IDB_LOG_MARK_CHILD_REQUEST(
776 "indexedDB.deleteDatabase(\"%s\")", "IDBFactory.deleteDatabase(%.0s)",
777 request
->LoggingSerialNumber(), NS_ConvertUTF16toUTF8(aName
).get());
779 IDB_LOG_MARK_CHILD_REQUEST(
780 "indexedDB.open(\"%s\", %s)", "IDBFactory.open(%.0s%.0s)",
781 request
->LoggingSerialNumber(), NS_ConvertUTF16toUTF8(aName
).get(),
782 IDB_LOG_STRINGIFY(aVersion
));
785 rv
= InitiateRequest(WrapNotNull(request
), params
);
786 if (NS_WARN_IF(NS_FAILED(rv
))) {
787 IDB_REPORT_INTERNAL_ERR();
788 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
795 nsresult
IDBFactory::InitiateRequest(
796 const NotNull
<RefPtr
<IDBOpenDBRequest
>>& aRequest
,
797 const FactoryRequestParams
& aParams
) {
798 MOZ_ASSERT(mBackgroundActor
);
799 MOZ_ASSERT(!mBackgroundActorFailed
);
802 uint64_t requestedVersion
;
804 switch (aParams
.type()) {
805 case FactoryRequestParams::TDeleteDatabaseRequestParams
: {
806 const DatabaseMetadata
& metadata
=
807 aParams
.get_DeleteDatabaseRequestParams().commonParams().metadata();
809 requestedVersion
= metadata
.version();
813 case FactoryRequestParams::TOpenDatabaseRequestParams
: {
814 const DatabaseMetadata
& metadata
=
815 aParams
.get_OpenDatabaseRequestParams().commonParams().metadata();
817 requestedVersion
= metadata
.version();
822 MOZ_CRASH("Should never get here!");
825 auto actor
= new BackgroundFactoryRequestChild(
826 SafeRefPtr
{this, AcquireStrongRefFromRawPtr
{}}, aRequest
, deleting
,
829 if (!mBackgroundActor
->SendPBackgroundIDBFactoryRequestConstructor(actor
,
831 aRequest
->DispatchNonTransactionError(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
832 return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
;
838 NS_IMPL_CYCLE_COLLECTING_ADDREF(IDBFactory
)
839 NS_IMPL_CYCLE_COLLECTING_RELEASE(IDBFactory
)
841 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IDBFactory
)
842 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
843 NS_INTERFACE_MAP_ENTRY(nsISupports
)
846 NS_IMPL_CYCLE_COLLECTION_CLASS(IDBFactory
)
848 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBFactory
)
849 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBrowserChild
)
850 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEventTarget
)
851 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
853 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IDBFactory
)
854 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
855 NS_IMPL_CYCLE_COLLECTION_UNLINK(mBrowserChild
)
856 NS_IMPL_CYCLE_COLLECTION_UNLINK(mEventTarget
)
857 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
859 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDBFactory
)
860 NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
861 NS_IMPL_CYCLE_COLLECTION_TRACE_END
863 JSObject
* IDBFactory::WrapObject(JSContext
* aCx
,
864 JS::Handle
<JSObject
*> aGivenProto
) {
865 return IDBFactory_Binding::Wrap(aCx
, this, aGivenProto
);
868 } // namespace mozilla::dom