tor-browser

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

BoundStorageKeyCache.cpp (12286B)


      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 "BoundStorageKeyCache.h"
      8 
      9 #include "mozilla/dom/CacheBinding.h"
     10 #include "mozilla/dom/InternalResponse.h"
     11 #include "mozilla/dom/Request.h"
     12 #include "mozilla/dom/Response.h"
     13 #include "mozilla/dom/ServiceWorkerUtils.h"
     14 #include "mozilla/dom/cache/AutoUtils.h"
     15 #include "mozilla/dom/cache/Cache.h"
     16 #include "mozilla/dom/cache/CacheChild.h"
     17 #include "mozilla/dom/cache/CacheWorkerRef.h"
     18 // #include "mozilla/ErrorResult.h"
     19 #include "nsIGlobalObject.h"
     20 
     21 namespace mozilla::dom::cache {
     22 
     23 NS_IMPL_ISUPPORTS(BoundStorageKeyCache, nsISupports)
     24 
     25 using mozilla::ipc::PBackgroundChild;
     26 
     27 BoundStorageKeyCache::BoundStorageKeyCache(nsIGlobalObject* aGlobal,
     28                                           CacheChild* aActor,
     29                                           Namespace aNamespace)
     30    : mGlobal(aGlobal), mActor(aActor), mNamespace(aNamespace) {
     31  MOZ_DIAGNOSTIC_ASSERT(mGlobal);
     32  MOZ_DIAGNOSTIC_ASSERT(mActor);
     33  MOZ_DIAGNOSTIC_ASSERT(mNamespace != INVALID_NAMESPACE);
     34  mActor->SetListener(this);
     35 }
     36 
     37 // static
     38 bool BoundStorageKeyCache::CachesEnabled(JSContext* aCx, JSObject* aObj) {
     39  if (!IsSecureContextOrObjectIsFromSecureContext(aCx, aObj)) {
     40    return StaticPrefs::dom_caches_testing_enabled() ||
     41           ServiceWorkersEnabled(aCx, aObj);
     42  }
     43  return true;
     44 }
     45 
     46 auto BoundStorageKeyCache::Match(JSContext* aCx,
     47                                 const RequestOrUTF8String& aRequest,
     48                                 const CacheQueryOptions& aOptions,
     49                                 ErrorResult& aRv)
     50    -> already_AddRefed<CachePromise> {
     51  if (NS_WARN_IF(!mActor)) {
     52    aRv.Throw(NS_ERROR_UNEXPECTED);
     53    return nullptr;
     54  }
     55 
     56  CacheChild::AutoLock actorLock(*mActor);
     57 
     58  SafeRefPtr<InternalRequest> ir =
     59      ToInternalRequest(aCx, aRequest, IgnoreBody, aRv);
     60  if (NS_WARN_IF(aRv.Failed())) {
     61    return nullptr;
     62  }
     63 
     64  CacheQueryParams params;
     65  ToCacheQueryParams(params, aOptions);
     66 
     67  AutoChildOpArgs args(
     68      this, CacheMatchArgs(CacheRequest(), params, GetOpenMode()), 1);
     69 
     70  args.Add(*ir, IgnoreBody, IgnoreInvalidScheme, aRv);
     71  if (NS_WARN_IF(aRv.Failed())) {
     72    return nullptr;
     73  }
     74 
     75  RefPtr<CachePromise> promise = new MatchResultPromise::Private(__func__);
     76  ExecuteOp(args, promise, aRv);
     77  return promise.forget();
     78 }
     79 
     80 auto BoundStorageKeyCache::MatchAll(
     81    JSContext* aCx, const Optional<RequestOrUTF8String>& aRequest,
     82    const CacheQueryOptions& aOptions, ErrorResult& aRv)
     83    -> already_AddRefed<CachePromise> {
     84  if (NS_WARN_IF(!mActor)) {
     85    aRv.Throw(NS_ERROR_UNEXPECTED);
     86    return nullptr;
     87  }
     88 
     89  CacheChild::AutoLock actorLock(*mActor);
     90 
     91  CacheQueryParams params;
     92  ToCacheQueryParams(params, aOptions);
     93 
     94  AutoChildOpArgs args(this,
     95                       CacheMatchAllArgs(Nothing(), params, GetOpenMode()), 1);
     96 
     97  if (aRequest.WasPassed()) {
     98    SafeRefPtr<InternalRequest> ir =
     99        ToInternalRequest(aCx, aRequest.Value(), IgnoreBody, aRv);
    100    if (aRv.Failed()) {
    101      return nullptr;
    102    }
    103 
    104    args.Add(*ir, IgnoreBody, IgnoreInvalidScheme, aRv);
    105    if (aRv.Failed()) {
    106      return nullptr;
    107    }
    108  }
    109 
    110  RefPtr<CachePromise> promise{new MatchAllResultPromise::Private(__func__)};
    111  ExecuteOp(args, promise, aRv);
    112 
    113  return promise.forget();
    114 }
    115 
    116 auto BoundStorageKeyCache::Add(JSContext* aContext,
    117                               const RequestOrUTF8String& aRequest,
    118                               CallerType aCallerType, ErrorResult& aRv)
    119    -> already_AddRefed<CachePromise> {
    120  if (NS_WARN_IF(!mActor)) {
    121    aRv.Throw(NS_ERROR_UNEXPECTED);
    122    return nullptr;
    123  }
    124 
    125  CacheChild::AutoLock actorLock(*mActor);
    126 
    127  if (!IsValidPutRequestMethod(aRequest, aRv)) {
    128    return nullptr;
    129  }
    130 
    131  GlobalObject global(aContext, mGlobal->GetGlobalJSObject());
    132  MOZ_DIAGNOSTIC_ASSERT(!global.Failed());
    133 
    134  nsTArray<SafeRefPtr<Request>> requestList(1);
    135  RootedDictionary<RequestInit> requestInit(aContext);
    136  SafeRefPtr<Request> request =
    137      Request::Constructor(global, aRequest, requestInit, aRv);
    138  if (NS_WARN_IF(aRv.Failed())) {
    139    return nullptr;
    140  }
    141 
    142  nsAutoCString url;
    143  request->GetUrl(url);
    144  if (NS_WARN_IF(!IsValidPutRequestURL(url, aRv))) {
    145    return nullptr;
    146  }
    147 
    148  requestList.AppendElement(std::move(request));
    149  return AddAll(global, std::move(requestList), aCallerType, aRv);
    150 }
    151 
    152 auto BoundStorageKeyCache::AddAll(
    153    JSContext* aContext,
    154    const Sequence<OwningRequestOrUTF8String>& aRequestList,
    155    CallerType aCallerType, ErrorResult& aRv)
    156    -> already_AddRefed<CachePromise> {
    157  if (NS_WARN_IF(!mActor)) {
    158    aRv.Throw(NS_ERROR_UNEXPECTED);
    159    return nullptr;
    160  }
    161 
    162  CacheChild::AutoLock actorLock(*mActor);
    163 
    164  GlobalObject global(aContext, mGlobal->GetGlobalJSObject());
    165  MOZ_DIAGNOSTIC_ASSERT(!global.Failed());
    166 
    167  nsTArray<SafeRefPtr<Request>> requestList(aRequestList.Length());
    168  for (uint32_t i = 0; i < aRequestList.Length(); ++i) {
    169    RequestOrUTF8String requestOrString;
    170 
    171    if (aRequestList[i].IsRequest()) {
    172      requestOrString.SetAsRequest() = aRequestList[i].GetAsRequest();
    173      if (NS_WARN_IF(
    174              !IsValidPutRequestMethod(requestOrString.GetAsRequest(), aRv))) {
    175        return nullptr;
    176      }
    177    } else {
    178      requestOrString.SetAsUTF8String().ShareOrDependUpon(
    179          aRequestList[i].GetAsUTF8String());
    180    }
    181 
    182    RootedDictionary<RequestInit> requestInit(aContext);
    183    SafeRefPtr<Request> request =
    184        Request::Constructor(global, requestOrString, requestInit, aRv);
    185    if (NS_WARN_IF(aRv.Failed())) {
    186      return nullptr;
    187    }
    188 
    189    nsAutoCString url;
    190    request->GetUrl(url);
    191    if (NS_WARN_IF(!IsValidPutRequestURL(url, aRv))) {
    192      return nullptr;
    193    }
    194 
    195    requestList.AppendElement(std::move(request));
    196  }
    197 
    198  return AddAll(global, std::move(requestList), aCallerType, aRv);
    199 }
    200 
    201 auto BoundStorageKeyCache::Put(JSContext* aCx,
    202                               const RequestOrUTF8String& aRequest,
    203                               Response& aResponse, ErrorResult& aRv)
    204    -> already_AddRefed<CachePromise> {
    205  if (NS_WARN_IF(!mActor)) {
    206    aRv.Throw(NS_ERROR_UNEXPECTED);
    207    return nullptr;
    208  }
    209 
    210  CacheChild::AutoLock actorLock(*mActor);
    211 
    212  if (NS_WARN_IF(!IsValidPutRequestMethod(aRequest, aRv))) {
    213    return nullptr;
    214  }
    215 
    216  if (!IsValidPutResponseStatus(aResponse, PutStatusPolicy::Default, aRv)) {
    217    return nullptr;
    218  }
    219 
    220  if (NS_WARN_IF(aResponse.GetPrincipalInfo() &&
    221                 aResponse.GetPrincipalInfo()->type() ==
    222                     mozilla::ipc::PrincipalInfo::TExpandedPrincipalInfo)) {
    223    // WebExtensions Content Scripts can currently run fetch from their global
    224    // which will end up to have an expanded principal, but we require that the
    225    // contents of Cache storage for the content origin to be same-origin, and
    226    // never an expanded principal (See Bug 1753810).
    227    aRv.ThrowSecurityError("Disallowed on WebExtension ContentScript Request");
    228    return nullptr;
    229  }
    230 
    231  SafeRefPtr<InternalRequest> ir =
    232      ToInternalRequest(aCx, aRequest, ReadBody, aRv);
    233  if (NS_WARN_IF(aRv.Failed())) {
    234    return nullptr;
    235  }
    236 
    237  AutoChildOpArgs args(this, CachePutAllArgs(), 1);
    238 
    239  args.Add(aCx, *ir, ReadBody, TypeErrorOnInvalidScheme, aResponse, aRv);
    240  if (NS_WARN_IF(aRv.Failed())) {
    241    return nullptr;
    242  }
    243 
    244  RefPtr<CachePromise> promise{new PutResultPromise::Private(__func__)};
    245  ExecuteOp(args, promise, aRv);
    246 
    247  return promise.forget();
    248 }
    249 
    250 auto BoundStorageKeyCache::Delete(JSContext* aCx,
    251                                  const RequestOrUTF8String& aRequest,
    252                                  const CacheQueryOptions& aOptions,
    253                                  ErrorResult& aRv)
    254    -> already_AddRefed<CachePromise> {
    255  if (NS_WARN_IF(!mActor)) {
    256    aRv.Throw(NS_ERROR_UNEXPECTED);
    257    return nullptr;
    258  }
    259 
    260  CacheChild::AutoLock actorLock(*mActor);
    261 
    262  SafeRefPtr<InternalRequest> ir =
    263      ToInternalRequest(aCx, aRequest, IgnoreBody, aRv);
    264  if (NS_WARN_IF(aRv.Failed())) {
    265    return nullptr;
    266  }
    267 
    268  CacheQueryParams params;
    269  ToCacheQueryParams(params, aOptions);
    270 
    271  AutoChildOpArgs args(this, CacheDeleteArgs(CacheRequest(), params), 1);
    272 
    273  args.Add(*ir, IgnoreBody, IgnoreInvalidScheme, aRv);
    274  if (NS_WARN_IF(aRv.Failed())) {
    275    return nullptr;
    276  }
    277 
    278  RefPtr<CachePromise> promise{new DeleteResultPromise::Private(__func__)};
    279  ExecuteOp(args, promise, aRv);
    280 
    281  return promise.forget();
    282 }
    283 
    284 auto BoundStorageKeyCache::Keys(JSContext* aCx,
    285                                const Optional<RequestOrUTF8String>& aRequest,
    286                                const CacheQueryOptions& aOptions,
    287                                ErrorResult& aRv)
    288    -> already_AddRefed<CachePromise> {
    289  if (NS_WARN_IF(!mActor)) {
    290    aRv.Throw(NS_ERROR_UNEXPECTED);
    291    return nullptr;
    292  }
    293 
    294  CacheChild::AutoLock actorLock(*mActor);
    295 
    296  CacheQueryParams params;
    297  ToCacheQueryParams(params, aOptions);
    298 
    299  AutoChildOpArgs args(this, CacheKeysArgs(Nothing(), params, GetOpenMode()),
    300                       1);
    301 
    302  if (aRequest.WasPassed()) {
    303    SafeRefPtr<InternalRequest> ir =
    304        ToInternalRequest(aCx, aRequest.Value(), IgnoreBody, aRv);
    305    if (NS_WARN_IF(aRv.Failed())) {
    306      return nullptr;
    307    }
    308 
    309    args.Add(*ir, IgnoreBody, IgnoreInvalidScheme, aRv);
    310    if (NS_WARN_IF(aRv.Failed())) {
    311      return nullptr;
    312    }
    313  }
    314 
    315  RefPtr<CachePromise> promise{new KeysResultPromise::Private(__func__)};
    316  ExecuteOp(args, promise, aRv);
    317 
    318  return promise.forget();
    319 }
    320 
    321 void BoundStorageKeyCache::OnActorDestroy(CacheChild* aActor) {
    322  MOZ_DIAGNOSTIC_ASSERT(mActor);
    323  MOZ_DIAGNOSTIC_ASSERT(mActor == aActor);
    324 
    325  mActor->ClearListener();
    326  mActor = nullptr;
    327 }
    328 
    329 nsIGlobalObject* BoundStorageKeyCache::GetGlobalObject() const {
    330  return mGlobal;
    331 }
    332 
    333 #ifdef DEBUG
    334 void BoundStorageKeyCache::AssertOwningThread() const {
    335  NS_ASSERT_OWNINGTHREAD(Cache);
    336 }
    337 #endif
    338 
    339 BoundStorageKeyCache::~BoundStorageKeyCache() {
    340  NS_ASSERT_OWNINGTHREAD(BoundStorageKeyCache);
    341  if (mActor) {
    342    mActor->StartDestroyFromListener();
    343    // OnActorDestroy() is called synchronously by StartDestroyFromListener().
    344    // So we should have already cleared the mActor.
    345    MOZ_DIAGNOSTIC_ASSERT(!mActor);
    346  }
    347 }
    348 
    349 void BoundStorageKeyCache::ExecuteOp(AutoChildOpArgs& aOpArgs,
    350                                     RefPtr<CachePromise>& aPromise,
    351                                     ErrorResult& aRv) {
    352  MOZ_DIAGNOSTIC_ASSERT(mActor);
    353  mActor->ExecuteOp(mGlobal, aPromise, this, aOpArgs.SendAsOpArgs());
    354 }
    355 
    356 auto BoundStorageKeyCache::AddAll(const GlobalObject& aGlobal,
    357                                  nsTArray<SafeRefPtr<Request>>&& aRequestList,
    358                                  CallerType aCallerType, ErrorResult& aRv)
    359    -> already_AddRefed<CachePromise> {
    360  MOZ_DIAGNOSTIC_ASSERT(mActor);
    361 
    362  // Fetch doesn't work on non-main threads yet.
    363  RefPtr<CachePromise> promise = AddAllResultPromise::CreateAndReject(
    364      ErrorResult(NS_ERROR_FAILURE), __func__);
    365  return promise.forget();
    366 }
    367 
    368 auto BoundStorageKeyCache::PutAll(
    369    JSContext* aCx, const nsTArray<SafeRefPtr<Request>>& aRequestList,
    370    const nsTArray<RefPtr<Response>>& aResponseList, ErrorResult& aRv)
    371    -> already_AddRefed<CachePromise> {
    372  MOZ_DIAGNOSTIC_ASSERT(aRequestList.Length() == aResponseList.Length());
    373 
    374  if (NS_WARN_IF(!mActor)) {
    375    aRv.Throw(NS_ERROR_UNEXPECTED);
    376    return nullptr;
    377  }
    378 
    379  CacheChild::AutoLock actorLock(*mActor);
    380 
    381  AutoChildOpArgs args(this, CachePutAllArgs(), aRequestList.Length());
    382 
    383  for (uint32_t i = 0; i < aRequestList.Length(); ++i) {
    384    SafeRefPtr<InternalRequest> ir = aRequestList[i]->GetInternalRequest();
    385    args.Add(aCx, *ir, ReadBody, TypeErrorOnInvalidScheme, *aResponseList[i],
    386             aRv);
    387    if (NS_WARN_IF(aRv.Failed())) {
    388      return nullptr;
    389    }
    390  }
    391 
    392  RefPtr<CachePromise> promise{new PutResultPromise::Private(__func__)};
    393  ExecuteOp(args, promise, aRv);
    394 
    395  return promise.forget();
    396 }
    397 
    398 OpenMode BoundStorageKeyCache::GetOpenMode() const {
    399  return mNamespace == CHROME_ONLY_NAMESPACE ? OpenMode::Eager : OpenMode::Lazy;
    400 }
    401 
    402 }  // namespace mozilla::dom::cache