tor-browser

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

CacheStorage.cpp (19939B)


      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 "mozilla/dom/cache/CacheStorage.h"
      8 
      9 #include "js/Object.h"              // JS::GetClass
     10 #include "js/PropertyAndElement.h"  // JS_DefineProperty
     11 #include "mozilla/Preferences.h"
     12 #include "mozilla/StaticPrefs_dom.h"
     13 #include "mozilla/StaticPrefs_extensions.h"
     14 #include "mozilla/dom/CacheBinding.h"
     15 #include "mozilla/dom/CacheStorageBinding.h"
     16 #include "mozilla/dom/Document.h"
     17 #include "mozilla/dom/InternalRequest.h"
     18 #include "mozilla/dom/Promise.h"
     19 #include "mozilla/dom/Response.h"
     20 #include "mozilla/dom/WorkerPrivate.h"
     21 #include "mozilla/dom/cache/AutoUtils.h"
     22 #include "mozilla/dom/cache/Cache.h"
     23 #include "mozilla/dom/cache/CacheChild.h"
     24 #include "mozilla/dom/cache/CacheCommon.h"
     25 #include "mozilla/dom/cache/CacheStorageChild.h"
     26 #include "mozilla/dom/cache/CacheWorkerRef.h"
     27 #include "mozilla/dom/cache/PCacheChild.h"
     28 #include "mozilla/dom/cache/ReadStream.h"
     29 #include "mozilla/dom/cache/TypeUtils.h"
     30 #include "mozilla/dom/quota/PrincipalUtils.h"
     31 #include "mozilla/dom/quota/ResultExtensions.h"
     32 #include "mozilla/ipc/BackgroundChild.h"
     33 #include "mozilla/ipc/BackgroundUtils.h"
     34 #include "mozilla/ipc/PBackgroundChild.h"
     35 #include "mozilla/ipc/PBackgroundSharedTypes.h"
     36 #include "nsContentUtils.h"
     37 #include "nsIGlobalObject.h"
     38 #include "nsMixedContentBlocker.h"
     39 #include "nsURLParsers.h"
     40 
     41 namespace mozilla::dom::cache {
     42 
     43 using mozilla::ErrorResult;
     44 using mozilla::ipc::BackgroundChild;
     45 using mozilla::ipc::PBackgroundChild;
     46 using mozilla::ipc::PrincipalInfo;
     47 using mozilla::ipc::PrincipalToPrincipalInfo;
     48 
     49 NS_IMPL_CYCLE_COLLECTING_ADDREF(mozilla::dom::cache::CacheStorage);
     50 NS_IMPL_CYCLE_COLLECTING_RELEASE(mozilla::dom::cache::CacheStorage);
     51 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(mozilla::dom::cache::CacheStorage,
     52                                      mGlobal);
     53 
     54 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CacheStorage)
     55  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
     56  NS_INTERFACE_MAP_ENTRY(nsISupports)
     57 NS_INTERFACE_MAP_END
     58 
     59 // We cannot reference IPC types in a webidl binding implementation header.  So
     60 // define this in the .cpp.
     61 struct CacheStorage::Entry final {
     62  RefPtr<Promise> mPromise;
     63  CacheOpArgs mArgs;
     64  // We cannot add the requests until after the actor is present.  So store
     65  // the request data separately for now.
     66  SafeRefPtr<InternalRequest> mRequest;
     67 };
     68 
     69 bool IsTrusted(const PrincipalInfo& aPrincipalInfo, bool aTestingPrefEnabled) {
     70  // Can happen on main thread or worker thread
     71 
     72  if (aPrincipalInfo.type() == PrincipalInfo::TSystemPrincipalInfo) {
     73    return true;
     74  }
     75 
     76  // Require a ContentPrincipal to avoid null principal, etc.
     77  QM_TRY(OkIf(aPrincipalInfo.type() == PrincipalInfo::TContentPrincipalInfo),
     78         false);
     79 
     80  // If we're in testing mode, then don't do any more work to determine if
     81  // the origin is trusted.  We have to run some tests as http.
     82  if (aTestingPrefEnabled) {
     83    return true;
     84  }
     85 
     86  // Now parse the scheme of the principal's origin.  This is a short term
     87  // method for determining "trust".  In the long term we need to implement
     88  // the full algorithm here:
     89  //
     90  // https://w3c.github.io/webappsec/specs/powerfulfeatures/#settings-secure
     91  //
     92  // TODO: Implement full secure setting algorithm. (bug 1177856)
     93 
     94  const nsCString& flatURL = aPrincipalInfo.get_ContentPrincipalInfo().spec();
     95  const char* const url = flatURL.get();
     96 
     97  // off the main thread URL parsing using nsStdURLParser.
     98  const nsCOMPtr<nsIURLParser> urlParser = new nsStdURLParser();
     99 
    100  uint32_t schemePos;
    101  int32_t schemeLen;
    102  uint32_t authPos;
    103  int32_t authLen;
    104  QM_TRY(MOZ_TO_RESULT(urlParser->ParseURL(url, flatURL.Length(), &schemePos,
    105                                           &schemeLen, &authPos, &authLen,
    106                                           nullptr, nullptr)),  // ignore path
    107         false);
    108 
    109  const nsAutoCString scheme(Substring(flatURL, schemePos, schemeLen));
    110  if (scheme.LowerCaseEqualsLiteral("https") ||
    111      scheme.LowerCaseEqualsLiteral("file") ||
    112      scheme.LowerCaseEqualsLiteral("moz-extension")) {
    113    return true;
    114  }
    115 
    116  uint32_t hostPos;
    117  int32_t hostLen;
    118  QM_TRY(MOZ_TO_RESULT(
    119             urlParser->ParseAuthority(url + authPos, authLen, nullptr,
    120                                       nullptr,           // ignore username
    121                                       nullptr, nullptr,  // ignore password
    122                                       &hostPos, &hostLen,
    123                                       nullptr)),  // ignore port
    124         false);
    125 
    126  return nsMixedContentBlocker::IsPotentiallyTrustworthyLoopbackHost(
    127      nsDependentCSubstring(url + authPos + hostPos, hostLen));
    128 }
    129 
    130 // static
    131 already_AddRefed<CacheStorage> CacheStorage::CreateOnMainThread(
    132    Namespace aNamespace, nsIGlobalObject* aGlobal, nsIPrincipal* aPrincipal,
    133    bool aForceTrustedOrigin, ErrorResult& aRv) {
    134  MOZ_DIAGNOSTIC_ASSERT(aGlobal);
    135  MOZ_DIAGNOSTIC_ASSERT(aPrincipal);
    136  MOZ_ASSERT(NS_IsMainThread());
    137 
    138  PrincipalInfo principalInfo;
    139  QM_TRY(MOZ_TO_RESULT(PrincipalToPrincipalInfo(aPrincipal, &principalInfo)),
    140         nullptr, [&aRv](const nsresult rv) { aRv.Throw(rv); });
    141 
    142  QM_TRY(OkIf(quota::IsPrincipalInfoValid(principalInfo)),
    143         RefPtr{new CacheStorage(NS_ERROR_DOM_SECURITY_ERR)}.forget(),
    144         [](const auto) {
    145           NS_WARNING("CacheStorage not supported on invalid origins.");
    146         });
    147 
    148  const bool testingEnabled =
    149      aForceTrustedOrigin ||
    150      Preferences::GetBool("dom.caches.testing.enabled", false) ||
    151      StaticPrefs::dom_serviceWorkers_testing_enabled();
    152 
    153  if (!IsTrusted(principalInfo, testingEnabled)) {
    154    NS_WARNING("CacheStorage not supported on untrusted origins.");
    155    RefPtr<CacheStorage> ref = new CacheStorage(NS_ERROR_DOM_SECURITY_ERR);
    156    return ref.forget();
    157  }
    158 
    159  RefPtr<CacheStorage> ref =
    160      new CacheStorage(aNamespace, aGlobal, principalInfo, nullptr);
    161  return ref.forget();
    162 }
    163 
    164 // static
    165 already_AddRefed<CacheStorage> CacheStorage::CreateOnWorker(
    166    Namespace aNamespace, nsIGlobalObject* aGlobal,
    167    WorkerPrivate* aWorkerPrivate, ErrorResult& aRv) {
    168  MOZ_DIAGNOSTIC_ASSERT(aGlobal);
    169  MOZ_DIAGNOSTIC_ASSERT(aWorkerPrivate);
    170  aWorkerPrivate->AssertIsOnWorkerThread();
    171 
    172  if (aWorkerPrivate->GetOriginAttributes().IsPrivateBrowsing() &&
    173      !StaticPrefs::dom_cache_privateBrowsing_enabled()) {
    174    NS_WARNING("CacheStorage not supported during private browsing.");
    175    RefPtr<CacheStorage> ref = new CacheStorage(NS_ERROR_DOM_SECURITY_ERR);
    176    return ref.forget();
    177  }
    178 
    179  SafeRefPtr<CacheWorkerRef> workerRef =
    180      CacheWorkerRef::Create(aWorkerPrivate, CacheWorkerRef::eIPCWorkerRef);
    181  if (!workerRef) {
    182    NS_WARNING("Worker thread is shutting down.");
    183    aRv.Throw(NS_ERROR_FAILURE);
    184    return nullptr;
    185  }
    186 
    187  const PrincipalInfo& principalInfo =
    188      aWorkerPrivate->GetEffectiveStoragePrincipalInfo();
    189 
    190  QM_TRY(OkIf(quota::IsPrincipalInfoValid(principalInfo)), nullptr,
    191         [&aRv](const auto) { aRv.Throw(NS_ERROR_FAILURE); });
    192 
    193  // We have a number of cases where we want to skip the https scheme
    194  // validation:
    195  //
    196  // 1) Any worker when dom.caches.testing.enabled pref is true.
    197  // 2) Any worker when dom.serviceWorkers.testing.enabled pref is true.  This
    198  //    is mainly because most sites using SWs will expect Cache to work if
    199  //    SWs are enabled.
    200  // 3) If the window that created this worker has the devtools SW testing
    201  //    option enabled.  Same reasoning as (2).
    202  // 4) If the worker itself is a ServiceWorker, then we always skip the
    203  //    origin checks.  The ServiceWorker has its own trusted origin checks
    204  //    that are better than ours.  In addition, we don't have information
    205  //    about the window any more, so we can't do our own checks.
    206  bool testingEnabled = StaticPrefs::dom_caches_testing_enabled() ||
    207                        StaticPrefs::dom_serviceWorkers_testing_enabled() ||
    208                        aWorkerPrivate->ServiceWorkersTestingInWindow() ||
    209                        aWorkerPrivate->IsServiceWorker();
    210 
    211  if (!IsTrusted(principalInfo, testingEnabled)) {
    212    NS_WARNING("CacheStorage not supported on untrusted origins.");
    213    RefPtr<CacheStorage> ref = new CacheStorage(NS_ERROR_DOM_SECURITY_ERR);
    214    return ref.forget();
    215  }
    216 
    217  RefPtr<CacheStorage> ref = new CacheStorage(
    218      aNamespace, aGlobal, principalInfo, std::move(workerRef));
    219  return ref.forget();
    220 }
    221 
    222 // static
    223 bool CacheStorage::DefineCachesForSandbox(JSContext* aCx,
    224                                          JS::Handle<JSObject*> aGlobal) {
    225  MOZ_ASSERT(NS_IsMainThread());
    226  MOZ_DIAGNOSTIC_ASSERT(JS::GetClass(aGlobal)->flags & JSCLASS_DOM_GLOBAL,
    227                        "Passed object is not a global object!");
    228  js::AssertSameCompartment(aCx, aGlobal);
    229 
    230  if (NS_WARN_IF(!CacheStorage_Binding::CreateAndDefineOnGlobal(aCx) ||
    231                 !Cache_Binding::CreateAndDefineOnGlobal(aCx))) {
    232    return false;
    233  }
    234 
    235  nsIPrincipal* principal = nsContentUtils::ObjectPrincipal(aGlobal);
    236  MOZ_DIAGNOSTIC_ASSERT(principal);
    237 
    238  ErrorResult rv;
    239  RefPtr<CacheStorage> storage =
    240      CreateOnMainThread(DEFAULT_NAMESPACE, xpc::NativeGlobal(aGlobal),
    241                         principal, true, /* force trusted */
    242                         rv);
    243  if (NS_WARN_IF(rv.MaybeSetPendingException(aCx))) {
    244    return false;
    245  }
    246 
    247  JS::Rooted<JS::Value> caches(aCx);
    248  if (NS_WARN_IF(!ToJSValue(aCx, storage, &caches))) {
    249    return false;
    250  }
    251 
    252  return JS_DefineProperty(aCx, aGlobal, "caches", caches, JSPROP_ENUMERATE);
    253 }
    254 
    255 // static
    256 bool CacheStorage::CachesEnabled(JSContext* aCx, JSObject* aObj) {
    257  return cache::Cache::CachesEnabled(aCx, aObj);
    258 }
    259 
    260 CacheStorage::CacheStorage(Namespace aNamespace, nsIGlobalObject* aGlobal,
    261                           const PrincipalInfo& aPrincipalInfo,
    262                           SafeRefPtr<CacheWorkerRef> aWorkerRef)
    263    : mNamespace(aNamespace),
    264      mGlobal(aGlobal),
    265      mPrincipalInfo(MakeUnique<PrincipalInfo>(aPrincipalInfo)),
    266      mActor(nullptr),
    267      mStatus(NS_OK) {
    268  MOZ_DIAGNOSTIC_ASSERT(mGlobal);
    269 
    270  // If the PBackground actor is already initialized then we can
    271  // immediately use it
    272  PBackgroundChild* actor = BackgroundChild::GetOrCreateForCurrentThread();
    273  if (NS_WARN_IF(!actor)) {
    274    mStatus = NS_ERROR_UNEXPECTED;
    275    return;
    276  }
    277 
    278  // WorkerRef ownership is passed to the CacheStorageChild actor and any
    279  // actors it may create.  The WorkerRef will keep the worker thread alive
    280  // until the actors can gracefully shutdown.
    281  CacheStorageChild* newActor =
    282      new CacheStorageChild(this, std::move(aWorkerRef));
    283  PCacheStorageChild* constructedActor = actor->SendPCacheStorageConstructor(
    284      newActor, mNamespace, *mPrincipalInfo);
    285 
    286  if (NS_WARN_IF(!constructedActor)) {
    287    mStatus = NS_ERROR_UNEXPECTED;
    288    return;
    289  }
    290 
    291  MOZ_DIAGNOSTIC_ASSERT(constructedActor == newActor);
    292  mActor = newActor;
    293 }
    294 
    295 CacheStorage::CacheStorage(nsresult aFailureResult)
    296    : mNamespace(INVALID_NAMESPACE), mActor(nullptr), mStatus(aFailureResult) {
    297  MOZ_DIAGNOSTIC_ASSERT(NS_FAILED(mStatus));
    298 }
    299 
    300 already_AddRefed<Promise> CacheStorage::Match(
    301    JSContext* aCx, const RequestOrUTF8String& aRequest,
    302    const MultiCacheQueryOptions& aOptions, ErrorResult& aRv) {
    303  NS_ASSERT_OWNINGTHREAD(CacheStorage);
    304 
    305  if (!HasStorageAccess(eUseCounter_custom_PrivateBrowsingCachesMatch,
    306                        UseCounterWorker::Custom_PrivateBrowsingCachesMatch)) {
    307    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
    308    return nullptr;
    309  }
    310 
    311  if (NS_WARN_IF(NS_FAILED(mStatus))) {
    312    aRv.Throw(mStatus);
    313    return nullptr;
    314  }
    315 
    316  SafeRefPtr<InternalRequest> request =
    317      ToInternalRequest(aCx, aRequest, IgnoreBody, aRv);
    318  if (NS_WARN_IF(aRv.Failed())) {
    319    return nullptr;
    320  }
    321 
    322  RefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
    323  if (NS_WARN_IF(!promise)) {
    324    return nullptr;
    325  }
    326 
    327  CacheQueryParams params;
    328  ToCacheQueryParams(params, aOptions);
    329 
    330  auto entry = MakeUnique<Entry>();
    331  entry->mPromise = promise;
    332  entry->mArgs = StorageMatchArgs(CacheRequest(), params, GetOpenMode());
    333  entry->mRequest = std::move(request);
    334 
    335  RunRequest(std::move(entry));
    336 
    337  return promise.forget();
    338 }
    339 
    340 already_AddRefed<Promise> CacheStorage::Has(const nsAString& aKey,
    341                                            ErrorResult& aRv) {
    342  NS_ASSERT_OWNINGTHREAD(CacheStorage);
    343 
    344  if (!HasStorageAccess(eUseCounter_custom_PrivateBrowsingCachesHas,
    345                        UseCounterWorker::Custom_PrivateBrowsingCachesHas)) {
    346    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
    347    return nullptr;
    348  }
    349 
    350  if (NS_WARN_IF(NS_FAILED(mStatus))) {
    351    aRv.Throw(mStatus);
    352    return nullptr;
    353  }
    354 
    355  RefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
    356  if (NS_WARN_IF(!promise)) {
    357    return nullptr;
    358  }
    359 
    360  auto entry = MakeUnique<Entry>();
    361  entry->mPromise = promise;
    362  entry->mArgs = StorageHasArgs(nsString(aKey));
    363 
    364  RunRequest(std::move(entry));
    365 
    366  return promise.forget();
    367 }
    368 
    369 already_AddRefed<Promise> CacheStorage::Open(const nsAString& aKey,
    370                                             ErrorResult& aRv) {
    371  NS_ASSERT_OWNINGTHREAD(CacheStorage);
    372 
    373  if (!HasStorageAccess(eUseCounter_custom_PrivateBrowsingCachesOpen,
    374                        UseCounterWorker::Custom_PrivateBrowsingCachesOpen)) {
    375    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
    376    return nullptr;
    377  }
    378 
    379  if (NS_WARN_IF(NS_FAILED(mStatus))) {
    380    aRv.Throw(mStatus);
    381    return nullptr;
    382  }
    383 
    384  RefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
    385  if (NS_WARN_IF(!promise)) {
    386    return nullptr;
    387  }
    388 
    389  auto entry = MakeUnique<Entry>();
    390  entry->mPromise = promise;
    391  entry->mArgs = StorageOpenArgs(nsString(aKey));
    392 
    393  RunRequest(std::move(entry));
    394 
    395  return promise.forget();
    396 }
    397 
    398 already_AddRefed<Promise> CacheStorage::Delete(const nsAString& aKey,
    399                                               ErrorResult& aRv) {
    400  NS_ASSERT_OWNINGTHREAD(CacheStorage);
    401 
    402  if (!HasStorageAccess(eUseCounter_custom_PrivateBrowsingCachesDelete,
    403                        UseCounterWorker::Custom_PrivateBrowsingCachesDelete)) {
    404    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
    405    return nullptr;
    406  }
    407 
    408  if (NS_WARN_IF(NS_FAILED(mStatus))) {
    409    aRv.Throw(mStatus);
    410    return nullptr;
    411  }
    412 
    413  RefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
    414  if (NS_WARN_IF(!promise)) {
    415    return nullptr;
    416  }
    417 
    418  auto entry = MakeUnique<Entry>();
    419  entry->mPromise = promise;
    420  entry->mArgs = StorageDeleteArgs(nsString(aKey));
    421 
    422  RunRequest(std::move(entry));
    423 
    424  return promise.forget();
    425 }
    426 
    427 already_AddRefed<Promise> CacheStorage::Keys(ErrorResult& aRv) {
    428  NS_ASSERT_OWNINGTHREAD(CacheStorage);
    429 
    430  if (!HasStorageAccess(eUseCounter_custom_PrivateBrowsingCachesKeys,
    431                        UseCounterWorker::Custom_PrivateBrowsingCachesKeys)) {
    432    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
    433    return nullptr;
    434  }
    435 
    436  if (NS_WARN_IF(NS_FAILED(mStatus))) {
    437    aRv.Throw(mStatus);
    438    return nullptr;
    439  }
    440 
    441  RefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
    442  if (NS_WARN_IF(!promise)) {
    443    return nullptr;
    444  }
    445 
    446  auto entry = MakeUnique<Entry>();
    447  entry->mPromise = promise;
    448  entry->mArgs = StorageKeysArgs();
    449 
    450  RunRequest(std::move(entry));
    451 
    452  return promise.forget();
    453 }
    454 
    455 // static
    456 already_AddRefed<CacheStorage> CacheStorage::Constructor(
    457    const GlobalObject& aGlobal, CacheStorageNamespace aNamespace,
    458    nsIPrincipal* aPrincipal, ErrorResult& aRv) {
    459  if (NS_WARN_IF(!NS_IsMainThread())) {
    460    aRv.Throw(NS_ERROR_FAILURE);
    461    return nullptr;
    462  }
    463 
    464  // TODO: remove Namespace in favor of CacheStorageNamespace
    465  static_assert(DEFAULT_NAMESPACE == (uint32_t)CacheStorageNamespace::Content,
    466                "Default namespace should match webidl Content enum");
    467  static_assert(
    468      CHROME_ONLY_NAMESPACE == (uint32_t)CacheStorageNamespace::Chrome,
    469      "Chrome namespace should match webidl Chrome enum");
    470  static_assert(
    471      NUMBER_OF_NAMESPACES == ContiguousEnumSize<CacheStorageNamespace>::value,
    472      "Number of namespace should match webidl count");
    473 
    474  Namespace ns = static_cast<Namespace>(aNamespace);
    475  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
    476 
    477  bool privateBrowsing = false;
    478  if (nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(global)) {
    479    RefPtr<Document> doc = window->GetExtantDoc();
    480    if (doc) {
    481      nsCOMPtr<nsILoadContext> loadContext = doc->GetLoadContext();
    482      privateBrowsing = loadContext && loadContext->UsePrivateBrowsing();
    483    }
    484  }
    485 
    486  if (privateBrowsing && !StaticPrefs::dom_cache_privateBrowsing_enabled()) {
    487    RefPtr<CacheStorage> ref = new CacheStorage(NS_ERROR_DOM_SECURITY_ERR);
    488    return ref.forget();
    489  }
    490 
    491  // Create a CacheStorage object bypassing the trusted origin checks
    492  // since this is a chrome-only constructor.
    493  return CreateOnMainThread(ns, global, aPrincipal,
    494                            true /* force trusted origin */, aRv);
    495 }
    496 
    497 nsISupports* CacheStorage::GetParentObject() const { return mGlobal; }
    498 
    499 JSObject* CacheStorage::WrapObject(JSContext* aContext,
    500                                   JS::Handle<JSObject*> aGivenProto) {
    501  return mozilla::dom::CacheStorage_Binding::Wrap(aContext, this, aGivenProto);
    502 }
    503 
    504 void CacheStorage::OnActorDestroy(CacheStorageChild* aActor) {
    505  NS_ASSERT_OWNINGTHREAD(CacheStorage);
    506  MOZ_DIAGNOSTIC_ASSERT(mActor);
    507  MOZ_DIAGNOSTIC_ASSERT(mActor == aActor);
    508  MOZ_DIAGNOSTIC_ASSERT(!NS_FAILED(mStatus));
    509  mActor->ClearListener();
    510  mActor = nullptr;
    511  mStatus = NS_ERROR_UNEXPECTED;
    512 
    513  // Note that we will never get an actor again in case another request is
    514  // made before this object is destructed.
    515 }
    516 
    517 nsIGlobalObject* CacheStorage::GetGlobalObject() const { return mGlobal; }
    518 
    519 #ifdef DEBUG
    520 void CacheStorage::AssertOwningThread() const {
    521  NS_ASSERT_OWNINGTHREAD(CacheStorage);
    522 }
    523 #endif
    524 
    525 CacheStorage::~CacheStorage() {
    526  NS_ASSERT_OWNINGTHREAD(CacheStorage);
    527  if (mActor) {
    528    mActor->StartDestroyFromListener();
    529    // OnActorDestroy() is called synchronously by StartDestroyFromListener().
    530    // So we should have already cleared the mActor.
    531    MOZ_DIAGNOSTIC_ASSERT(!mActor);
    532  }
    533 }
    534 
    535 void CacheStorage::RunRequest(UniquePtr<Entry> aEntry) {
    536  MOZ_ASSERT(mActor);
    537 
    538  AutoChildOpArgs args(this, aEntry->mArgs, 1);
    539 
    540  if (aEntry->mRequest) {
    541    ErrorResult rv;
    542    args.Add(*aEntry->mRequest, IgnoreBody, IgnoreInvalidScheme, rv);
    543    if (NS_WARN_IF(rv.Failed())) {
    544      aEntry->mPromise->MaybeReject(std::move(rv));
    545      return;
    546    }
    547  }
    548 
    549  mActor->ExecuteOp(mGlobal, aEntry->mPromise, this, args.SendAsOpArgs());
    550 }
    551 
    552 OpenMode CacheStorage::GetOpenMode() const {
    553  return mNamespace == CHROME_ONLY_NAMESPACE ? OpenMode::Eager : OpenMode::Lazy;
    554 }
    555 
    556 bool CacheStorage::HasStorageAccess(UseCounter aLabel,
    557                                    UseCounterWorker aLabelWorker) const {
    558  NS_ASSERT_OWNINGTHREAD(CacheStorage);
    559  if (NS_WARN_IF(!mGlobal)) {
    560    return false;
    561  }
    562 
    563  StorageAccess access = mGlobal->GetStorageAccess();
    564  if (access == StorageAccess::ePrivateBrowsing) {
    565    if (NS_IsMainThread()) {
    566      SetUseCounter(mGlobal->GetGlobalJSObject(), aLabel);
    567    } else {
    568      SetUseCounter(aLabelWorker);
    569    }
    570  }
    571 
    572  // Deny storage access for private browsing unless pref is toggled on.
    573  if (nsIPrincipal* principal = mGlobal->PrincipalOrNull()) {
    574    if (!principal->IsSystemPrincipal() &&
    575        principal->GetPrivateBrowsingId() !=
    576            nsIScriptSecurityManager::DEFAULT_PRIVATE_BROWSING_ID &&
    577        !StaticPrefs::dom_cache_privateBrowsing_enabled()) {
    578      return false;
    579    }
    580  }
    581 
    582  return access > StorageAccess::eDeny ||
    583         (StaticPrefs::
    584              privacy_partition_always_partition_third_party_non_cookie_storage() &&
    585          ShouldPartitionStorage(access));
    586 }
    587 
    588 }  // namespace mozilla::dom::cache