tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

IDBFactory.cpp (26988B)


      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/. */
      6 
      7 #include "IDBFactory.h"
      8 
      9 #include "BackgroundChildImpl.h"
     10 #include "IDBRequest.h"
     11 #include "IndexedDatabaseManager.h"
     12 #include "ProfilerHelpers.h"
     13 #include "ReportInternalError.h"
     14 #include "ThreadLocal.h"
     15 #include "mozilla/BasePrincipal.h"
     16 #include "mozilla/ErrorResult.h"
     17 #include "mozilla/Preferences.h"
     18 #include "mozilla/StaticPrefs_dom.h"
     19 #include "mozilla/StorageAccess.h"
     20 #include "mozilla/dom/BindingDeclarations.h"
     21 #include "mozilla/dom/BrowserChild.h"
     22 #include "mozilla/dom/Document.h"
     23 #include "mozilla/dom/IDBFactoryBinding.h"
     24 #include "mozilla/dom/Promise.h"
     25 #include "mozilla/dom/WorkerPrivate.h"
     26 #include "mozilla/dom/quota/PrincipalUtils.h"
     27 #include "mozilla/dom/quota/QuotaManager.h"
     28 #include "mozilla/dom/quota/ResultExtensions.h"
     29 #include "mozilla/ipc/BackgroundChild.h"
     30 #include "mozilla/ipc/BackgroundUtils.h"
     31 #include "mozilla/ipc/PBackground.h"
     32 #include "mozilla/ipc/PBackgroundChild.h"
     33 #include "nsAboutProtocolUtils.h"
     34 #include "nsContentUtils.h"
     35 #include "nsGlobalWindowInner.h"
     36 #include "nsIAboutModule.h"
     37 #include "nsILoadContext.h"
     38 #include "nsIURI.h"
     39 #include "nsIUUIDGenerator.h"
     40 #include "nsIWebNavigation.h"
     41 #include "nsLiteralString.h"
     42 #include "nsNetUtil.h"
     43 #include "nsSandboxFlags.h"
     44 #include "nsServiceManagerUtils.h"
     45 #include "nsStringFwd.h"
     46 
     47 // Include this last to avoid path problems on Windows.
     48 #include "ActorsChild.h"
     49 
     50 namespace mozilla::dom {
     51 
     52 using namespace mozilla::dom::indexedDB;
     53 using namespace mozilla::dom::quota;
     54 using namespace mozilla::ipc;
     55 
     56 namespace {
     57 
     58 constexpr nsLiteralCString kAccessError("The operation is insecure");
     59 
     60 }  // namespace
     61 
     62 struct IDBFactory::PendingRequestInfo {
     63  RefPtr<IDBOpenDBRequest> mRequest;
     64  FactoryRequestParams mParams;
     65 
     66  PendingRequestInfo(IDBOpenDBRequest* aRequest,
     67                     const FactoryRequestParams& aParams)
     68      : mRequest(aRequest), mParams(aParams) {
     69    MOZ_ASSERT(aRequest);
     70    MOZ_ASSERT(aParams.type() != FactoryRequestParams::T__None);
     71  }
     72 };
     73 
     74 IDBFactory::IDBFactory(const IDBFactoryGuard&, bool aAllowed)
     75    : mBackgroundActor(nullptr),
     76      mInnerWindowID(0),
     77      mActiveTransactionCount(0),
     78      mActiveDatabaseCount(0),
     79      mAllowed(aAllowed),
     80      mBackgroundActorFailed(false),
     81      mPrivateBrowsingMode(false) {
     82  AssertIsOnOwningThread();
     83 }
     84 
     85 IDBFactory::~IDBFactory() {
     86  MOZ_ASSERT_IF(mBackgroundActorFailed, !mBackgroundActor);
     87 
     88  if (mBackgroundActor) {
     89    mBackgroundActor->SendDeleteMeInternal();
     90    MOZ_ASSERT(!mBackgroundActor, "SendDeleteMeInternal should have cleared!");
     91  }
     92 }
     93 
     94 // static
     95 Result<RefPtr<IDBFactory>, nsresult> IDBFactory::CreateForWindow(
     96    nsPIDOMWindowInner* aWindow) {
     97  MOZ_ASSERT(NS_IsMainThread());
     98  MOZ_ASSERT(aWindow);
     99 
    100  nsCOMPtr<nsIPrincipal> principal;
    101  nsresult rv = AllowedForWindowInternal(aWindow, &principal);
    102 
    103  if (NS_WARN_IF(NS_FAILED(rv))) {
    104    if (rv == NS_ERROR_DOM_NOT_SUPPORTED_ERR) {
    105      NS_WARNING("IndexedDB is not permitted in a third-party window.");
    106    }
    107 
    108    if (rv == NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR) {
    109      IDB_REPORT_INTERNAL_ERR();
    110    }
    111 
    112    auto factory =
    113        MakeRefPtr<IDBFactory>(IDBFactoryGuard{}, /* aAllowed */ false);
    114    factory->BindToOwner(aWindow->AsGlobal());
    115    factory->mInnerWindowID = aWindow->WindowID();
    116 
    117    return factory;
    118  }
    119 
    120  MOZ_ASSERT(principal);
    121 
    122  auto principalInfo = MakeUnique<PrincipalInfo>();
    123  rv = PrincipalToPrincipalInfo(principal, principalInfo.get());
    124  if (NS_WARN_IF(NS_FAILED(rv))) {
    125    IDB_REPORT_INTERNAL_ERR();
    126    return Err(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    127  }
    128 
    129  MOZ_ASSERT(principalInfo->type() == PrincipalInfo::TContentPrincipalInfo ||
    130             principalInfo->type() == PrincipalInfo::TSystemPrincipalInfo);
    131 
    132  if (NS_WARN_IF(!quota::IsPrincipalInfoValid(*principalInfo))) {
    133    IDB_REPORT_INTERNAL_ERR();
    134    return Err(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    135  }
    136 
    137  nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(aWindow);
    138  nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(webNav);
    139 
    140  auto factory = MakeRefPtr<IDBFactory>(IDBFactoryGuard{}, /* aAllowed */ true);
    141  factory->mPrincipalInfo = std::move(principalInfo);
    142 
    143  factory->BindToOwner(aWindow->AsGlobal());
    144 
    145  factory->mBrowserChild = BrowserChild::GetFrom(aWindow);
    146  factory->mEventTarget =
    147      nsGlobalWindowInner::Cast(aWindow)->SerialEventTarget();
    148  factory->mInnerWindowID = aWindow->WindowID();
    149  factory->mPrivateBrowsingMode =
    150      loadContext && loadContext->UsePrivateBrowsing();
    151 
    152  return factory;
    153 }
    154 
    155 // static
    156 Result<RefPtr<IDBFactory>, nsresult> IDBFactory::CreateForMainThreadJS(
    157    nsIGlobalObject* aGlobal) {
    158  MOZ_ASSERT(NS_IsMainThread());
    159  MOZ_ASSERT(aGlobal);
    160 
    161  nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(aGlobal);
    162  if (NS_WARN_IF(!sop)) {
    163    return Err(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    164  }
    165 
    166  auto principalInfo = MakeUnique<PrincipalInfo>();
    167  nsIPrincipal* principal = sop->GetEffectiveStoragePrincipal();
    168  MOZ_ASSERT(principal);
    169  bool isSystem;
    170  if (!AllowedForPrincipal(principal, &isSystem)) {
    171    auto factory =
    172        MakeRefPtr<IDBFactory>(IDBFactoryGuard{}, /* aAllowed */ false);
    173    factory->BindToOwner(aGlobal);
    174 
    175    return factory;
    176  }
    177 
    178  nsresult rv = PrincipalToPrincipalInfo(principal, principalInfo.get());
    179  if (NS_WARN_IF(NS_FAILED(rv))) {
    180    return Err(rv);
    181  }
    182 
    183  if (NS_WARN_IF(!quota::IsPrincipalInfoValid(*principalInfo))) {
    184    return Err(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    185  }
    186 
    187  return CreateForMainThreadJSInternal(aGlobal, std::move(principalInfo));
    188 }
    189 
    190 // static
    191 Result<RefPtr<IDBFactory>, nsresult> IDBFactory::CreateForWorker(
    192    nsIGlobalObject* aGlobal, UniquePtr<PrincipalInfo>&& aPrincipalInfo,
    193    uint64_t aInnerWindowID) {
    194  MOZ_ASSERT(!NS_IsMainThread());
    195  MOZ_ASSERT(aGlobal);
    196 
    197  if (!aPrincipalInfo) {
    198    auto factory =
    199        MakeRefPtr<IDBFactory>(IDBFactoryGuard{}, /* aAllowed */ false);
    200    factory->BindToOwner(aGlobal);
    201    factory->mInnerWindowID = aInnerWindowID;
    202 
    203    return factory;
    204  }
    205 
    206  MOZ_ASSERT(aPrincipalInfo->type() != PrincipalInfo::T__None);
    207 
    208  return CreateInternal(aGlobal, std::move(aPrincipalInfo), aInnerWindowID);
    209 }
    210 
    211 // static
    212 Result<RefPtr<IDBFactory>, nsresult> IDBFactory::CreateForMainThreadJSInternal(
    213    nsIGlobalObject* aGlobal, UniquePtr<PrincipalInfo> aPrincipalInfo) {
    214  MOZ_ASSERT(NS_IsMainThread());
    215  MOZ_ASSERT(aGlobal);
    216  MOZ_ASSERT(aPrincipalInfo);
    217 
    218  IndexedDatabaseManager* mgr = IndexedDatabaseManager::GetOrCreate();
    219  if (NS_WARN_IF(!mgr)) {
    220    IDB_REPORT_INTERNAL_ERR();
    221    return Err(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    222  }
    223 
    224  nsresult rv = mgr->EnsureLocale();
    225  if (NS_WARN_IF(NS_FAILED(rv))) {
    226    IDB_REPORT_INTERNAL_ERR();
    227    return Err(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    228  };
    229 
    230  return CreateInternal(aGlobal, std::move(aPrincipalInfo),
    231                        /* aInnerWindowID */ 0);
    232 }
    233 
    234 // static
    235 Result<RefPtr<IDBFactory>, nsresult> IDBFactory::CreateInternal(
    236    nsIGlobalObject* aGlobal, UniquePtr<PrincipalInfo> aPrincipalInfo,
    237    uint64_t aInnerWindowID) {
    238  MOZ_ASSERT(aGlobal);
    239  MOZ_ASSERT(aPrincipalInfo);
    240  MOZ_ASSERT(aPrincipalInfo->type() != PrincipalInfo::T__None);
    241 
    242  if (aPrincipalInfo->type() != PrincipalInfo::TContentPrincipalInfo &&
    243      aPrincipalInfo->type() != PrincipalInfo::TSystemPrincipalInfo) {
    244    NS_WARNING("IndexedDB not allowed for this principal!");
    245 
    246    auto factory =
    247        MakeRefPtr<IDBFactory>(IDBFactoryGuard{}, /* aAllowed */ false);
    248    factory->BindToOwner(aGlobal);
    249    factory->mInnerWindowID = aInnerWindowID;
    250 
    251    return factory;
    252  }
    253 
    254  auto factory = MakeRefPtr<IDBFactory>(IDBFactoryGuard{}, /* aAllowed */ true);
    255  factory->mPrincipalInfo = std::move(aPrincipalInfo);
    256  factory->BindToOwner(aGlobal);
    257  factory->mEventTarget = GetCurrentSerialEventTarget();
    258  factory->mInnerWindowID = aInnerWindowID;
    259 
    260  return factory;
    261 }
    262 
    263 // static
    264 bool IDBFactory::AllowedForWindow(nsPIDOMWindowInner* aWindow) {
    265  MOZ_ASSERT(NS_IsMainThread());
    266  MOZ_ASSERT(aWindow);
    267 
    268  return !NS_WARN_IF(NS_FAILED(AllowedForWindowInternal(aWindow, nullptr)));
    269 }
    270 
    271 // static
    272 nsresult IDBFactory::AllowedForWindowInternal(
    273    nsPIDOMWindowInner* aWindow, nsCOMPtr<nsIPrincipal>* aPrincipal) {
    274  MOZ_ASSERT(NS_IsMainThread());
    275  MOZ_ASSERT(aWindow);
    276 
    277  IndexedDatabaseManager* mgr = IndexedDatabaseManager::GetOrCreate();
    278  if (NS_WARN_IF(!mgr)) {
    279    return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
    280  }
    281 
    282  nsresult rv = mgr->EnsureLocale();
    283  if (NS_WARN_IF(NS_FAILED(rv))) {
    284    IDB_REPORT_INTERNAL_ERR();
    285    return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
    286  };
    287 
    288  StorageAccess access = StorageAllowedForWindow(aWindow);
    289 
    290  // the factory callsite records whether the browser is in private browsing.
    291  // and thus we don't have to respect that setting here. IndexedDB has no
    292  // concept of session-local storage, and thus ignores it.
    293  if (access == StorageAccess::eDeny) {
    294    return NS_ERROR_DOM_SECURITY_ERR;
    295  }
    296 
    297  if (ShouldPartitionStorage(access) &&
    298      !StoragePartitioningEnabled(
    299          access, aWindow->GetExtantDoc()->CookieJarSettings())) {
    300    return NS_ERROR_DOM_SECURITY_ERR;
    301  }
    302 
    303  nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(aWindow);
    304  MOZ_ASSERT(sop);
    305 
    306  nsCOMPtr<nsIPrincipal> principal = sop->GetEffectiveStoragePrincipal();
    307  if (NS_WARN_IF(!principal)) {
    308    return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
    309  }
    310 
    311  if (principal->IsSystemPrincipal()) {
    312    *aPrincipal = std::move(principal);
    313    return NS_OK;
    314  }
    315 
    316  // About URIs shouldn't be able to access IndexedDB unless they have the
    317  // nsIAboutModule::ENABLE_INDEXED_DB flag set on them.
    318 
    319  if (principal->SchemeIs("about")) {
    320    uint32_t flags;
    321    if (NS_SUCCEEDED(principal->GetAboutModuleFlags(&flags))) {
    322      if (!(flags & nsIAboutModule::ENABLE_INDEXED_DB)) {
    323        return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
    324      }
    325    } else {
    326      return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
    327    }
    328  }
    329 
    330  if (aPrincipal) {
    331    *aPrincipal = std::move(principal);
    332  }
    333  return NS_OK;
    334 }
    335 
    336 // static
    337 bool IDBFactory::AllowedForPrincipal(nsIPrincipal* aPrincipal,
    338                                     bool* aIsSystemPrincipal) {
    339  MOZ_ASSERT(NS_IsMainThread());
    340  MOZ_ASSERT(aPrincipal);
    341 
    342  IndexedDatabaseManager* mgr = IndexedDatabaseManager::GetOrCreate();
    343  if (NS_WARN_IF(!mgr)) {
    344    return false;
    345  }
    346 
    347  nsresult rv = mgr->EnsureLocale();
    348  if (NS_WARN_IF(NS_FAILED(rv))) {
    349    return false;
    350  };
    351 
    352  if (aPrincipal->IsSystemPrincipal()) {
    353    if (aIsSystemPrincipal) {
    354      *aIsSystemPrincipal = true;
    355    }
    356    return true;
    357  }
    358 
    359  if (aIsSystemPrincipal) {
    360    *aIsSystemPrincipal = false;
    361  }
    362 
    363  return !aPrincipal->GetIsNullPrincipal();
    364 }
    365 
    366 // static
    367 PersistenceType IDBFactory::GetPersistenceType(
    368    const PrincipalInfo& aPrincipalInfo) {
    369  if (aPrincipalInfo.type() == PrincipalInfo::TSystemPrincipalInfo) {
    370    // Chrome privilege always gets persistent storage.
    371    return PERSISTENCE_TYPE_PERSISTENT;
    372  }
    373 
    374  if (aPrincipalInfo.type() == PrincipalInfo::TContentPrincipalInfo) {
    375    nsCString origin =
    376        aPrincipalInfo.get_ContentPrincipalInfo().originNoSuffix();
    377 
    378    if (QuotaManager::IsOriginInternal(origin)) {
    379      // Internal origins always get persistent storage.
    380      return PERSISTENCE_TYPE_PERSISTENT;
    381    }
    382 
    383    if (aPrincipalInfo.get_ContentPrincipalInfo().attrs().IsPrivateBrowsing()) {
    384      return PERSISTENCE_TYPE_PRIVATE;
    385    }
    386  }
    387 
    388  return PERSISTENCE_TYPE_DEFAULT;
    389 }
    390 
    391 void IDBFactory::UpdateActiveTransactionCount(int32_t aDelta) {
    392  AssertIsOnOwningThread();
    393  MOZ_ASSERT(mAllowed);
    394  MOZ_DIAGNOSTIC_ASSERT(aDelta > 0 || (mActiveTransactionCount + aDelta) <
    395                                          mActiveTransactionCount);
    396  mActiveTransactionCount += aDelta;
    397 }
    398 
    399 void IDBFactory::UpdateActiveDatabaseCount(int32_t aDelta) {
    400  AssertIsOnOwningThread();
    401  MOZ_ASSERT(mAllowed);
    402  MOZ_DIAGNOSTIC_ASSERT(aDelta > 0 ||
    403                        (mActiveDatabaseCount + aDelta) < mActiveDatabaseCount);
    404  mActiveDatabaseCount += aDelta;
    405 
    406  if (nsIGlobalObject* global = GetOwnerGlobal()) {
    407    global->UpdateActiveIndexedDBDatabaseCount(aDelta);
    408  }
    409 }
    410 
    411 bool IDBFactory::IsChrome() const {
    412  if (!mAllowed) {
    413    return false;  // Minimal privileges
    414  }
    415 
    416  AssertIsOnOwningThread();
    417  MOZ_ASSERT(mPrincipalInfo);
    418 
    419  return mPrincipalInfo->type() == PrincipalInfo::TSystemPrincipalInfo;
    420 }
    421 
    422 RefPtr<IDBOpenDBRequest> IDBFactory::Open(JSContext* aCx,
    423                                          const nsAString& aName,
    424                                          const Optional<uint64_t>& aVersion,
    425                                          CallerType aCallerType,
    426                                          ErrorResult& aRv) {
    427  if (!mAllowed) {
    428    aRv.ThrowSecurityError(kAccessError);
    429    return nullptr;
    430  }
    431 
    432  return OpenInternal(aCx,
    433                      /* aPrincipal */ nullptr, aName, aVersion,
    434                      /* aDeleting */ false, aCallerType, aRv);
    435 }
    436 
    437 RefPtr<IDBOpenDBRequest> IDBFactory::DeleteDatabase(JSContext* aCx,
    438                                                    const nsAString& aName,
    439                                                    CallerType aCallerType,
    440                                                    ErrorResult& aRv) {
    441  if (!mAllowed) {
    442    aRv.ThrowSecurityError(kAccessError);
    443    return nullptr;
    444  }
    445 
    446  return OpenInternal(aCx,
    447                      /* aPrincipal */ nullptr, aName, Optional<uint64_t>(),
    448                      /* aDeleting */ true, aCallerType, aRv);
    449 }
    450 
    451 already_AddRefed<Promise> IDBFactory::Databases(JSContext* const aCx,
    452                                                ErrorResult& aRv) {
    453  if (NS_WARN_IF(!GetOwnerGlobal())) {
    454    aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    455    return nullptr;
    456  }
    457 
    458  RefPtr<Promise> promise = Promise::CreateInfallible(GetOwnerGlobal());
    459  if (!mAllowed) {
    460    promise->MaybeRejectWithSecurityError(kAccessError);
    461    return promise.forget();
    462  }
    463 
    464  // Nothing can be done here if we have previously failed to create a
    465  // background actor.
    466  if (mBackgroundActorFailed) {
    467    promise->MaybeReject(NS_ERROR_FAILURE);
    468    return promise.forget();
    469  }
    470 
    471  PersistenceType persistenceType = GetPersistenceType(*mPrincipalInfo);
    472 
    473  QM_TRY(MOZ_TO_RESULT(EnsureBackgroundActor()), [&promise](const nsresult rv) {
    474    promise->MaybeReject(rv);
    475    return promise.forget();
    476  });
    477 
    478  mBackgroundActor->SendGetDatabases(persistenceType, *mPrincipalInfo)
    479      ->Then(
    480          GetCurrentSerialEventTarget(), __func__,
    481          [promise](const PBackgroundIDBFactoryChild::GetDatabasesPromise::
    482                        ResolveOrRejectValue& aValue) {
    483            if (aValue.IsReject()) {
    484              promise->MaybeReject(NS_ERROR_FAILURE);
    485              return;
    486            }
    487 
    488            const GetDatabasesResponse& response = aValue.ResolveValue();
    489 
    490            switch (response.type()) {
    491              case GetDatabasesResponse::Tnsresult:
    492                promise->MaybeReject(response.get_nsresult());
    493 
    494                break;
    495 
    496              case GetDatabasesResponse::TArrayOfDatabaseMetadata: {
    497                const auto& array = response.get_ArrayOfDatabaseMetadata();
    498 
    499                Sequence<IDBDatabaseInfo> databaseInfos;
    500 
    501                for (const auto& databaseMetadata : array) {
    502                  IDBDatabaseInfo databaseInfo;
    503 
    504                  databaseInfo.mName.Construct(databaseMetadata.name());
    505                  databaseInfo.mVersion.Construct(databaseMetadata.version());
    506 
    507                  if (!databaseInfos.AppendElement(std::move(databaseInfo),
    508                                                   fallible)) {
    509                    promise->MaybeRejectWithTypeError("Out of memory");
    510                    return;
    511                  }
    512                }
    513 
    514                promise->MaybeResolve(databaseInfos);
    515 
    516                break;
    517              }
    518              default:
    519                MOZ_CRASH("Unknown response type!");
    520            }
    521          });
    522 
    523  return promise.forget();
    524 }
    525 
    526 int16_t IDBFactory::Cmp(JSContext* aCx, JS::Handle<JS::Value> aFirst,
    527                        JS::Handle<JS::Value> aSecond, ErrorResult& aRv) {
    528  Key first, second;
    529  auto result = first.SetFromJSVal(aCx, aFirst);
    530  if (result.isErr()) {
    531    aRv = result.unwrapErr().ExtractErrorResult(
    532        InvalidMapsTo<NS_ERROR_DOM_INDEXEDDB_DATA_ERR>);
    533    return 0;
    534  }
    535 
    536  result = second.SetFromJSVal(aCx, aSecond);
    537  if (result.isErr()) {
    538    aRv = result.unwrapErr().ExtractErrorResult(
    539        InvalidMapsTo<NS_ERROR_DOM_INDEXEDDB_DATA_ERR>);
    540    return 0;
    541  }
    542 
    543  if (first.IsUnset() || second.IsUnset()) {
    544    aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
    545    return 0;
    546  }
    547 
    548  return Key::CompareKeys(first, second);
    549 }
    550 
    551 RefPtr<IDBOpenDBRequest> IDBFactory::OpenForPrincipal(
    552    JSContext* aCx, nsIPrincipal* aPrincipal, const nsAString& aName,
    553    uint64_t aVersion, SystemCallerGuarantee aGuarantee, ErrorResult& aRv) {
    554  if (!mAllowed) {
    555    aRv.ThrowSecurityError(kAccessError);
    556    return nullptr;
    557  }
    558 
    559  MOZ_ASSERT(aPrincipal);
    560  if (!NS_IsMainThread()) {
    561    MOZ_CRASH(
    562        "Figure out security checks for workers!  What's this aPrincipal "
    563        "we have on a worker thread?");
    564  }
    565 
    566  return OpenInternal(aCx, aPrincipal, aName, Optional<uint64_t>(aVersion),
    567                      /* aDeleting */ false, aGuarantee, aRv);
    568 }
    569 
    570 RefPtr<IDBOpenDBRequest> IDBFactory::OpenForPrincipal(
    571    JSContext* aCx, nsIPrincipal* aPrincipal, const nsAString& aName,
    572    const IDBOpenDBOptions& aOptions, SystemCallerGuarantee aGuarantee,
    573    ErrorResult& aRv) {
    574  if (!mAllowed) {
    575    aRv.ThrowSecurityError(kAccessError);
    576    return nullptr;
    577  }
    578 
    579  MOZ_ASSERT(aPrincipal);
    580  if (!NS_IsMainThread()) {
    581    MOZ_CRASH(
    582        "Figure out security checks for workers!  What's this aPrincipal "
    583        "we have on a worker thread?");
    584  }
    585 
    586  return OpenInternal(aCx, aPrincipal, aName, aOptions.mVersion,
    587                      /* aDeleting */ false, aGuarantee, aRv);
    588 }
    589 
    590 RefPtr<IDBOpenDBRequest> IDBFactory::DeleteForPrincipal(
    591    JSContext* aCx, nsIPrincipal* aPrincipal, const nsAString& aName,
    592    const IDBOpenDBOptions& aOptions, SystemCallerGuarantee aGuarantee,
    593    ErrorResult& aRv) {
    594  if (!mAllowed) {
    595    aRv.ThrowSecurityError(kAccessError);
    596    return nullptr;
    597  }
    598 
    599  MOZ_ASSERT(aPrincipal);
    600  if (!NS_IsMainThread()) {
    601    MOZ_CRASH(
    602        "Figure out security checks for workers!  What's this aPrincipal "
    603        "we have on a worker thread?");
    604  }
    605 
    606  return OpenInternal(aCx, aPrincipal, aName, Optional<uint64_t>(),
    607                      /* aDeleting */ true, aGuarantee, aRv);
    608 }
    609 
    610 nsresult IDBFactory::EnsureBackgroundActor() {
    611  MOZ_ASSERT(mAllowed);
    612 
    613  if (mBackgroundActor) {
    614    return NS_OK;
    615  }
    616 
    617  BackgroundChildImpl::ThreadLocal* threadLocal =
    618      BackgroundChildImpl::GetThreadLocalForCurrentThread();
    619 
    620  UniquePtr<ThreadLocal> newIDBThreadLocal;
    621  ThreadLocal* idbThreadLocal;
    622 
    623  if (threadLocal && threadLocal->mIndexedDBThreadLocal) {
    624    idbThreadLocal = threadLocal->mIndexedDBThreadLocal.get();
    625  } else {
    626    nsCOMPtr<nsIUUIDGenerator> uuidGen =
    627        do_GetService("@mozilla.org/uuid-generator;1");
    628    MOZ_ASSERT(uuidGen);
    629 
    630    nsID id{};
    631    MOZ_ALWAYS_SUCCEEDS(uuidGen->GenerateUUIDInPlace(&id));
    632 
    633    newIDBThreadLocal = WrapUnique(new ThreadLocal(id));
    634    idbThreadLocal = newIDBThreadLocal.get();
    635  }
    636 
    637  PBackgroundChild* backgroundActor =
    638      BackgroundChild::GetOrCreateForCurrentThread();
    639  if (NS_WARN_IF(!backgroundActor)) {
    640    return NS_ERROR_FAILURE;
    641  }
    642 
    643  {
    644    BackgroundFactoryChild* actor = new BackgroundFactoryChild(*this);
    645 
    646    mBackgroundActor = static_cast<BackgroundFactoryChild*>(
    647        backgroundActor->SendPBackgroundIDBFactoryConstructor(
    648            actor, idbThreadLocal->GetLoggingInfo(),
    649            IndexedDatabaseManager::GetLocale()));
    650 
    651    if (NS_WARN_IF(!mBackgroundActor)) {
    652      return NS_ERROR_FAILURE;
    653    }
    654  }
    655 
    656  if (newIDBThreadLocal) {
    657    if (!threadLocal) {
    658      threadLocal = BackgroundChildImpl::GetThreadLocalForCurrentThread();
    659    }
    660    MOZ_ASSERT(threadLocal);
    661    MOZ_ASSERT(!threadLocal->mIndexedDBThreadLocal);
    662 
    663    threadLocal->mIndexedDBThreadLocal = std::move(newIDBThreadLocal);
    664  }
    665 
    666  return NS_OK;
    667 }
    668 
    669 RefPtr<IDBOpenDBRequest> IDBFactory::OpenInternal(
    670    JSContext* aCx, nsIPrincipal* aPrincipal, const nsAString& aName,
    671    const Optional<uint64_t>& aVersion, bool aDeleting, CallerType aCallerType,
    672    ErrorResult& aRv) {
    673  MOZ_ASSERT(mAllowed);
    674 
    675  if (NS_WARN_IF(!GetOwnerGlobal())) {
    676    aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    677    return nullptr;
    678  }
    679 
    680  CommonFactoryRequestParams commonParams;
    681 
    682  PrincipalInfo& principalInfo = commonParams.principalInfo();
    683 
    684  if (aPrincipal) {
    685    if (!NS_IsMainThread()) {
    686      MOZ_CRASH(
    687          "Figure out security checks for workers!  What's this "
    688          "aPrincipal we have on a worker thread?");
    689    }
    690    MOZ_ASSERT(aCallerType == CallerType::System);
    691    MOZ_DIAGNOSTIC_ASSERT(mPrivateBrowsingMode ==
    692                          aPrincipal->GetIsInPrivateBrowsing());
    693 
    694    if (NS_WARN_IF(
    695            NS_FAILED(PrincipalToPrincipalInfo(aPrincipal, &principalInfo)))) {
    696      IDB_REPORT_INTERNAL_ERR();
    697      aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    698      return nullptr;
    699    }
    700 
    701    if (principalInfo.type() != PrincipalInfo::TContentPrincipalInfo &&
    702        principalInfo.type() != PrincipalInfo::TSystemPrincipalInfo) {
    703      IDB_REPORT_INTERNAL_ERR();
    704      aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    705      return nullptr;
    706    }
    707 
    708    if (NS_WARN_IF(!quota::IsPrincipalInfoValid(principalInfo))) {
    709      IDB_REPORT_INTERNAL_ERR();
    710      aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    711      return nullptr;
    712    }
    713  } else {
    714    if (GetOwnerGlobal()->GetStorageAccess() ==
    715        StorageAccess::ePrivateBrowsing) {
    716      if (NS_IsMainThread()) {
    717        SetUseCounter(
    718            GetOwnerGlobal()->GetGlobalJSObject(),
    719            aDeleting
    720                ? eUseCounter_custom_PrivateBrowsingIDBFactoryOpen
    721                : eUseCounter_custom_PrivateBrowsingIDBFactoryDeleteDatabase);
    722      } else {
    723        SetUseCounter(
    724            aDeleting ? UseCounterWorker::Custom_PrivateBrowsingIDBFactoryOpen
    725                      : UseCounterWorker::
    726                            Custom_PrivateBrowsingIDBFactoryDeleteDatabase);
    727      }
    728    }
    729    principalInfo = *mPrincipalInfo;
    730  }
    731 
    732  uint64_t version = 0;
    733  if (!aDeleting && aVersion.WasPassed()) {
    734    if (aVersion.Value() < 1) {
    735      aRv.ThrowTypeError("0 (Zero) is not a valid database version.");
    736      return nullptr;
    737    }
    738    version = aVersion.Value();
    739  }
    740 
    741  // Nothing can be done here if we have previously failed to create a
    742  // background actor.
    743  if (mBackgroundActorFailed) {
    744    IDB_REPORT_INTERNAL_ERR();
    745    aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    746    return nullptr;
    747  }
    748 
    749  PersistenceType persistenceType = GetPersistenceType(principalInfo);
    750 
    751  DatabaseMetadata& metadata = commonParams.metadata();
    752  metadata.name() = aName;
    753  metadata.persistenceType() = persistenceType;
    754 
    755  FactoryRequestParams params;
    756  if (aDeleting) {
    757    metadata.version() = 0;
    758    params = DeleteDatabaseRequestParams(commonParams);
    759  } else {
    760    metadata.version() = version;
    761    params = OpenDatabaseRequestParams(commonParams);
    762  }
    763 
    764  nsresult rv = EnsureBackgroundActor();
    765  if (NS_WARN_IF(NS_FAILED(rv))) {
    766    IDB_REPORT_INTERNAL_ERR();
    767    aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    768    return nullptr;
    769  }
    770 
    771  RefPtr<IDBOpenDBRequest> request = IDBOpenDBRequest::Create(
    772      aCx, SafeRefPtr{this, AcquireStrongRefFromRawPtr{}}, GetOwnerGlobal());
    773  if (!request) {
    774    MOZ_ASSERT(!NS_IsMainThread());
    775    aRv.ThrowUncatchableException();
    776    return nullptr;
    777  }
    778 
    779  MOZ_ASSERT(request);
    780 
    781  if (aDeleting) {
    782    IDB_LOG_MARK_CHILD_REQUEST(
    783        "indexedDB.deleteDatabase(\"%s\")", "IDBFactory.deleteDatabase(%.0s)",
    784        request->LoggingSerialNumber(), NS_ConvertUTF16toUTF8(aName).get());
    785  } else {
    786    IDB_LOG_MARK_CHILD_REQUEST(
    787        "indexedDB.open(\"%s\", %s)", "IDBFactory.open(%.0s%.0s)",
    788        request->LoggingSerialNumber(), NS_ConvertUTF16toUTF8(aName).get(),
    789        IDB_LOG_STRINGIFY(aVersion));
    790  }
    791 
    792  rv = InitiateRequest(WrapNotNull(request), params);
    793  if (NS_WARN_IF(NS_FAILED(rv))) {
    794    IDB_REPORT_INTERNAL_ERR();
    795    aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    796    return nullptr;
    797  }
    798 
    799  return request;
    800 }
    801 
    802 nsresult IDBFactory::InitiateRequest(
    803    const NotNull<RefPtr<IDBOpenDBRequest>>& aRequest,
    804    const FactoryRequestParams& aParams) {
    805  MOZ_ASSERT(mAllowed);
    806  MOZ_ASSERT(mBackgroundActor);
    807  MOZ_ASSERT(!mBackgroundActorFailed);
    808 
    809  bool deleting;
    810  uint64_t requestedVersion;
    811 
    812  switch (aParams.type()) {
    813    case FactoryRequestParams::TDeleteDatabaseRequestParams: {
    814      const DatabaseMetadata& metadata =
    815          aParams.get_DeleteDatabaseRequestParams().commonParams().metadata();
    816      deleting = true;
    817      requestedVersion = metadata.version();
    818      break;
    819    }
    820 
    821    case FactoryRequestParams::TOpenDatabaseRequestParams: {
    822      const DatabaseMetadata& metadata =
    823          aParams.get_OpenDatabaseRequestParams().commonParams().metadata();
    824      deleting = false;
    825      requestedVersion = metadata.version();
    826      break;
    827    }
    828 
    829    default:
    830      MOZ_CRASH("Should never get here!");
    831  }
    832 
    833  auto actor = new BackgroundFactoryRequestChild(
    834      SafeRefPtr{this, AcquireStrongRefFromRawPtr{}}, aRequest, deleting,
    835      requestedVersion);
    836 
    837  if (!mBackgroundActor->SendPBackgroundIDBFactoryRequestConstructor(actor,
    838                                                                     aParams)) {
    839    aRequest->DispatchNonTransactionError(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    840    return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
    841  }
    842 
    843  return NS_OK;
    844 }
    845 
    846 NS_IMPL_CYCLE_COLLECTING_ADDREF(IDBFactory)
    847 NS_IMPL_CYCLE_COLLECTING_RELEASE(IDBFactory)
    848 
    849 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IDBFactory)
    850  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
    851  NS_INTERFACE_MAP_ENTRY(nsISupports)
    852 NS_INTERFACE_MAP_END
    853 
    854 NS_IMPL_CYCLE_COLLECTION_CLASS(IDBFactory)
    855 
    856 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBFactory)
    857  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBrowserChild)
    858  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEventTarget)
    859 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
    860 
    861 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IDBFactory)
    862  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
    863  NS_IMPL_CYCLE_COLLECTION_UNLINK(mBrowserChild)
    864  NS_IMPL_CYCLE_COLLECTION_UNLINK(mEventTarget)
    865 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
    866 
    867 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDBFactory)
    868  NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
    869 NS_IMPL_CYCLE_COLLECTION_TRACE_END
    870 
    871 JSObject* IDBFactory::WrapObject(JSContext* aCx,
    872                                 JS::Handle<JSObject*> aGivenProto) {
    873  return IDBFactory_Binding::Wrap(aCx, this, aGivenProto);
    874 }
    875 
    876 }  // namespace mozilla::dom