tor-browser

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

CacheLoadHandler.cpp (20886B)


      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 "CacheLoadHandler.h"
      8 
      9 #include "ScriptResponseHeaderProcessor.h"  // ScriptResponseHeaderProcessor
     10 #include "WorkerLoadContext.h"              // WorkerLoadContext
     11 #include "jsapi.h"
     12 #include "mozilla/Assertions.h"
     13 #include "mozilla/Encoding.h"
     14 #include "mozilla/TaskQueue.h"
     15 #include "mozilla/UniquePtr.h"
     16 #include "mozilla/dom/CacheBinding.h"
     17 #include "mozilla/dom/Document.h"
     18 #include "mozilla/dom/PolicyContainer.h"
     19 #include "mozilla/dom/Response.h"
     20 #include "mozilla/dom/ServiceWorkerBinding.h"  // ServiceWorkerState
     21 #include "mozilla/dom/WorkerScope.h"
     22 #include "mozilla/dom/cache/CacheTypes.h"
     23 #include "mozilla/dom/workerinternals/ScriptLoader.h"  // WorkerScriptLoader
     24 #include "nsIPrincipal.h"
     25 #include "nsIThreadRetargetableRequest.h"
     26 #include "nsIXPConnect.h"
     27 #include "nsNetUtil.h"
     28 
     29 namespace mozilla {
     30 namespace dom {
     31 
     32 namespace workerinternals::loader {
     33 
     34 NS_IMPL_ISUPPORTS0(CacheCreator)
     35 
     36 NS_IMPL_ISUPPORTS(CacheLoadHandler, nsIStreamLoaderObserver)
     37 
     38 NS_IMPL_ISUPPORTS0(CachePromiseHandler)
     39 
     40 CachePromiseHandler::CachePromiseHandler(
     41    WorkerScriptLoader* aLoader, ThreadSafeRequestHandle* aRequestHandle)
     42    : mLoader(aLoader), mRequestHandle(aRequestHandle) {
     43  AssertIsOnMainThread();
     44  MOZ_ASSERT(mLoader);
     45 }
     46 
     47 void CachePromiseHandler::ResolvedCallback(JSContext* aCx,
     48                                           JS::Handle<JS::Value> aValue,
     49                                           ErrorResult& aRv) {
     50  AssertIsOnMainThread();
     51  if (mRequestHandle->IsEmpty()) {
     52    return;
     53  }
     54  WorkerLoadContext* loadContext = mRequestHandle->GetContext();
     55 
     56  // May already have been canceled by CacheLoadHandler::Fail from
     57  // CancelMainThread.
     58  MOZ_ASSERT(loadContext->mCacheStatus == WorkerLoadContext::WritingToCache ||
     59             loadContext->mCacheStatus == WorkerLoadContext::Cancel);
     60  MOZ_ASSERT_IF(loadContext->mCacheStatus == WorkerLoadContext::Cancel,
     61                !loadContext->mCachePromise);
     62 
     63  if (loadContext->mCachePromise) {
     64    loadContext->mCacheStatus = WorkerLoadContext::Cached;
     65    loadContext->mCachePromise = nullptr;
     66    mRequestHandle->MaybeExecuteFinishedScripts();
     67  }
     68 }
     69 
     70 void CachePromiseHandler::RejectedCallback(JSContext* aCx,
     71                                           JS::Handle<JS::Value> aValue,
     72                                           ErrorResult& aRv) {
     73  AssertIsOnMainThread();
     74  if (mRequestHandle->IsEmpty()) {
     75    return;
     76  }
     77  WorkerLoadContext* loadContext = mRequestHandle->GetContext();
     78 
     79  // May already have been canceled by CacheLoadHandler::Fail from
     80  // CancelMainThread.
     81  MOZ_ASSERT(loadContext->mCacheStatus == WorkerLoadContext::WritingToCache ||
     82             loadContext->mCacheStatus == WorkerLoadContext::Cancel);
     83  loadContext->mCacheStatus = WorkerLoadContext::Cancel;
     84 
     85  loadContext->mCachePromise = nullptr;
     86 
     87  // This will delete the cache object and will call LoadingFinished() with an
     88  // error for each ongoing operation.
     89  auto* cacheCreator = mRequestHandle->GetCacheCreator();
     90  if (cacheCreator) {
     91    cacheCreator->DeleteCache(NS_ERROR_FAILURE);
     92  }
     93 }
     94 
     95 CacheCreator::CacheCreator(WorkerPrivate* aWorkerPrivate)
     96    : mCacheName(aWorkerPrivate->ServiceWorkerCacheName()),
     97      mOriginAttributes(aWorkerPrivate->GetOriginAttributes()) {
     98  MOZ_ASSERT(aWorkerPrivate->IsServiceWorker());
     99 }
    100 
    101 nsresult CacheCreator::CreateCacheStorage(nsIPrincipal* aPrincipal) {
    102  AssertIsOnMainThread();
    103  MOZ_ASSERT(!mCacheStorage);
    104  MOZ_ASSERT(aPrincipal);
    105 
    106  nsIXPConnect* xpc = nsContentUtils::XPConnect();
    107  MOZ_ASSERT(xpc, "This should never be null!");
    108 
    109  AutoJSAPI jsapi;
    110  jsapi.Init();
    111  JSContext* cx = jsapi.cx();
    112  JS::Rooted<JSObject*> sandbox(cx);
    113  nsresult rv = xpc->CreateSandbox(cx, aPrincipal, sandbox.address());
    114  if (NS_WARN_IF(NS_FAILED(rv))) {
    115    return rv;
    116  }
    117 
    118  // The JSContext is not in a realm, so CreateSandbox returned an unwrapped
    119  // global.
    120  MOZ_ASSERT(JS_IsGlobalObject(sandbox));
    121 
    122  mSandboxGlobalObject = xpc::NativeGlobal(sandbox);
    123  if (NS_WARN_IF(!mSandboxGlobalObject)) {
    124    return NS_ERROR_FAILURE;
    125  }
    126 
    127  // Create a CacheStorage bypassing its trusted origin checks.  The
    128  // ServiceWorker has already performed its own checks before getting
    129  // to this point.
    130  ErrorResult error;
    131  mCacheStorage = CacheStorage::CreateOnMainThread(
    132      mozilla::dom::cache::CHROME_ONLY_NAMESPACE, mSandboxGlobalObject,
    133      aPrincipal, true /* force trusted origin */, error);
    134  if (NS_WARN_IF(error.Failed())) {
    135    return error.StealNSResult();
    136  }
    137 
    138  return NS_OK;
    139 }
    140 
    141 nsresult CacheCreator::Load(nsIPrincipal* aPrincipal) {
    142  AssertIsOnMainThread();
    143  MOZ_ASSERT(!mLoaders.IsEmpty());
    144 
    145  nsresult rv = CreateCacheStorage(aPrincipal);
    146  if (NS_WARN_IF(NS_FAILED(rv))) {
    147    return rv;
    148  }
    149 
    150  ErrorResult error;
    151  MOZ_ASSERT(!mCacheName.IsEmpty());
    152  RefPtr<Promise> promise = mCacheStorage->Open(mCacheName, error);
    153  if (NS_WARN_IF(error.Failed())) {
    154    return error.StealNSResult();
    155  }
    156 
    157  promise->AppendNativeHandler(this);
    158  return NS_OK;
    159 }
    160 
    161 void CacheCreator::FailLoaders(nsresult aRv) {
    162  AssertIsOnMainThread();
    163 
    164  // Fail() can call LoadingFinished() which may call ExecuteFinishedScripts()
    165  // which sets mCacheCreator to null, so hold a ref.
    166  RefPtr<CacheCreator> kungfuDeathGrip = this;
    167 
    168  for (uint32_t i = 0, len = mLoaders.Length(); i < len; ++i) {
    169    mLoaders[i]->Fail(aRv);
    170  }
    171 
    172  mLoaders.Clear();
    173 }
    174 
    175 void CacheCreator::RejectedCallback(JSContext* aCx,
    176                                    JS::Handle<JS::Value> aValue,
    177                                    ErrorResult& aRv) {
    178  AssertIsOnMainThread();
    179  FailLoaders(NS_ERROR_FAILURE);
    180 }
    181 
    182 void CacheCreator::ResolvedCallback(JSContext* aCx,
    183                                    JS::Handle<JS::Value> aValue,
    184                                    ErrorResult& aRv) {
    185  AssertIsOnMainThread();
    186  if (!aValue.isObject()) {
    187    FailLoaders(NS_ERROR_FAILURE);
    188    return;
    189  }
    190 
    191  JS::Rooted<JSObject*> obj(aCx, &aValue.toObject());
    192  Cache* cache = nullptr;
    193  nsresult rv = UNWRAP_OBJECT(Cache, &obj, cache);
    194  if (NS_WARN_IF(NS_FAILED(rv))) {
    195    FailLoaders(NS_ERROR_FAILURE);
    196    return;
    197  }
    198 
    199  mCache = cache;
    200  MOZ_DIAGNOSTIC_ASSERT(mCache);
    201 
    202  // If the worker is canceled, CancelMainThread() will have cleared the
    203  // loaders via DeleteCache().
    204  for (uint32_t i = 0, len = mLoaders.Length(); i < len; ++i) {
    205    mLoaders[i]->Load(cache);
    206  }
    207 }
    208 
    209 void CacheCreator::DeleteCache(nsresult aReason) {
    210  AssertIsOnMainThread();
    211 
    212  // This is called when the load is canceled which can occur before
    213  // mCacheStorage is initialized.
    214  if (mCacheStorage) {
    215    // It's safe to do this while Cache::Match() and Cache::Put() calls are
    216    // running.
    217    RefPtr<Promise> promise = mCacheStorage->Delete(mCacheName, IgnoreErrors());
    218 
    219    // We don't care to know the result of the promise object.
    220  }
    221 
    222  // Always call this here to ensure the loaders array is cleared.
    223  FailLoaders(NS_ERROR_FAILURE);
    224 }
    225 
    226 CacheLoadHandler::CacheLoadHandler(ThreadSafeWorkerRef* aWorkerRef,
    227                                   ThreadSafeRequestHandle* aRequestHandle,
    228                                   bool aIsWorkerScript,
    229                                   bool aOnlyExistingCachedResourcesAllowed,
    230                                   WorkerScriptLoader* aLoader)
    231    : mRequestHandle(aRequestHandle),
    232      mLoader(aLoader),
    233      mWorkerRef(aWorkerRef),
    234      mIsWorkerScript(aIsWorkerScript),
    235      mFailed(false),
    236      mOnlyExistingCachedResourcesAllowed(aOnlyExistingCachedResourcesAllowed) {
    237  MOZ_ASSERT(aWorkerRef);
    238  MOZ_ASSERT(aWorkerRef->Private()->IsServiceWorker());
    239  mMainThreadEventTarget = aWorkerRef->Private()->MainThreadEventTarget();
    240  MOZ_ASSERT(mMainThreadEventTarget);
    241  mBaseURI = mLoader->GetBaseURI();
    242  AssertIsOnMainThread();
    243 
    244  // Worker scripts are always decoded as UTF-8 per spec.
    245  mDecoder = MakeUnique<ScriptDecoder>(UTF_8_ENCODING,
    246                                       ScriptDecoder::BOMHandling::Remove);
    247 }
    248 
    249 void CacheLoadHandler::Fail(nsresult aRv) {
    250  AssertIsOnMainThread();
    251  MOZ_ASSERT(NS_FAILED(aRv));
    252 
    253  if (mFailed) {
    254    return;
    255  }
    256 
    257  mFailed = true;
    258 
    259  if (mPump) {
    260    MOZ_ASSERT_IF(!mRequestHandle->IsEmpty(),
    261                  mRequestHandle->GetContext()->mCacheStatus ==
    262                      WorkerLoadContext::ReadingFromCache);
    263    mPump->Cancel(aRv);
    264    mPump = nullptr;
    265  }
    266  if (mRequestHandle->IsEmpty()) {
    267    return;
    268  }
    269 
    270  WorkerLoadContext* loadContext = mRequestHandle->GetContext();
    271 
    272  loadContext->mCacheStatus = WorkerLoadContext::Cancel;
    273 
    274  if (loadContext->mCachePromise) {
    275    loadContext->mCachePromise->MaybeReject(aRv);
    276  }
    277 
    278  loadContext->mCachePromise = nullptr;
    279 
    280  mRequestHandle->LoadingFinished(aRv);
    281 }
    282 
    283 void CacheLoadHandler::Load(Cache* aCache) {
    284  AssertIsOnMainThread();
    285  MOZ_ASSERT(aCache);
    286  MOZ_ASSERT(!mRequestHandle->IsEmpty());
    287  WorkerLoadContext* loadContext = mRequestHandle->GetContext();
    288 
    289  nsCOMPtr<nsIURI> uri;
    290  nsresult rv = NS_NewURI(getter_AddRefs(uri), loadContext->mRequest->mURL,
    291                          nullptr, mBaseURI);
    292  if (NS_WARN_IF(NS_FAILED(rv))) {
    293    Fail(rv);
    294    return;
    295  }
    296 
    297  MOZ_ASSERT(loadContext->mFullURL.IsEmpty());
    298  rv = uri->GetSpec(loadContext->mFullURL);
    299  if (NS_WARN_IF(NS_FAILED(rv))) {
    300    Fail(rv);
    301    return;
    302  }
    303 
    304  mozilla::dom::RequestOrUTF8String request;
    305  request.SetAsUTF8String().ShareOrDependUpon(loadContext->mFullURL);
    306 
    307  mozilla::dom::CacheQueryOptions params;
    308 
    309  // This JSContext will not end up executing JS code because here there are
    310  // no ReadableStreams involved.
    311  AutoJSAPI jsapi;
    312  jsapi.Init();
    313 
    314  ErrorResult error;
    315  RefPtr<Promise> promise = aCache->Match(jsapi.cx(), request, params, error);
    316  if (NS_WARN_IF(error.Failed())) {
    317    Fail(error.StealNSResult());
    318    return;
    319  }
    320 
    321  promise->AppendNativeHandler(this);
    322 }
    323 
    324 void CacheLoadHandler::RejectedCallback(JSContext* aCx,
    325                                        JS::Handle<JS::Value> aValue,
    326                                        ErrorResult& aRv) {
    327  AssertIsOnMainThread();
    328  MOZ_ASSERT(!mRequestHandle->IsEmpty());
    329 
    330  MOZ_ASSERT(mRequestHandle->GetContext()->mCacheStatus ==
    331             WorkerLoadContext::Uncached);
    332  Fail(NS_ERROR_FAILURE);
    333 }
    334 
    335 void CacheLoadHandler::ResolvedCallback(JSContext* aCx,
    336                                        JS::Handle<JS::Value> aValue,
    337                                        ErrorResult& aRv) {
    338  AssertIsOnMainThread();
    339  MOZ_ASSERT(!mRequestHandle->IsEmpty());
    340  WorkerLoadContext* loadContext = mRequestHandle->GetContext();
    341 
    342  // If we have already called 'Fail', we should not proceed. If we cancelled,
    343  // we should similarily not proceed.
    344  if (mFailed) {
    345    return;
    346  }
    347 
    348  MOZ_ASSERT(loadContext->mCacheStatus == WorkerLoadContext::Uncached);
    349 
    350  nsresult rv;
    351 
    352  // The ServiceWorkerScriptCache will store data for any scripts it
    353  // it knows about.  This is always at least the top level script.
    354  // Depending on if a previous version of the service worker has
    355  // been installed or not it may also know about importScripts().  We
    356  // must handle loading and offlining new importScripts() here, however.
    357  if (aValue.isUndefined()) {
    358    // If this is the main script or we're not loading a new service worker
    359    // then this is an error.  This can happen for internal reasons, like
    360    // storage was probably wiped without removing the service worker
    361    // registration.  It can also happen for exposed reasons like the
    362    // service worker script calling importScripts() after install.
    363    if (NS_WARN_IF(mIsWorkerScript || mOnlyExistingCachedResourcesAllowed)) {
    364      Fail(NS_ERROR_DOM_INVALID_STATE_ERR);
    365      return;
    366    }
    367 
    368    loadContext->mCacheStatus = WorkerLoadContext::ToBeCached;
    369    rv = mLoader->LoadScript(mRequestHandle);
    370    if (NS_WARN_IF(NS_FAILED(rv))) {
    371      Fail(rv);
    372    }
    373    return;
    374  }
    375 
    376  MOZ_ASSERT(aValue.isObject());
    377 
    378  JS::Rooted<JSObject*> obj(aCx, &aValue.toObject());
    379  mozilla::dom::Response* response = nullptr;
    380  rv = UNWRAP_OBJECT(Response, &obj, response);
    381  if (NS_WARN_IF(NS_FAILED(rv))) {
    382    Fail(rv);
    383    return;
    384  }
    385 
    386  InternalHeaders* headers = response->GetInternalHeaders();
    387 
    388  headers->Get("content-security-policy"_ns, mCSPHeaderValue, IgnoreErrors());
    389  headers->Get("content-security-policy-report-only"_ns,
    390               mCSPReportOnlyHeaderValue, IgnoreErrors());
    391  headers->Get("referrer-policy"_ns, mReferrerPolicyHeaderValue,
    392               IgnoreErrors());
    393 
    394  nsAutoCString coepHeader;
    395  headers->Get("cross-origin-embedder-policy"_ns, coepHeader, IgnoreErrors());
    396 
    397  nsILoadInfo::CrossOriginEmbedderPolicy coep =
    398      NS_GetCrossOriginEmbedderPolicyFromHeader(
    399          coepHeader, mWorkerRef->Private()->Trials().IsEnabled(
    400                          OriginTrial::CoepCredentialless));
    401 
    402  rv = ScriptResponseHeaderProcessor::ProcessCrossOriginEmbedderPolicyHeader(
    403      mWorkerRef->Private(), coep, loadContext->IsTopLevel());
    404 
    405  if (NS_WARN_IF(NS_FAILED(rv))) {
    406    Fail(rv);
    407    return;
    408  }
    409 
    410  nsCOMPtr<nsIInputStream> inputStream;
    411  response->GetBody(getter_AddRefs(inputStream));
    412  mChannelInfo = response->GetChannelInfo();
    413  const UniquePtr<PrincipalInfo>& pInfo = response->GetPrincipalInfo();
    414  if (pInfo) {
    415    mPrincipalInfo = mozilla::MakeUnique<PrincipalInfo>(*pInfo);
    416  }
    417 
    418  if (!inputStream) {
    419    loadContext->mCacheStatus = WorkerLoadContext::Cached;
    420 
    421    if (mRequestHandle->IsCancelled()) {
    422      auto* cacheCreator = mRequestHandle->GetCacheCreator();
    423      if (cacheCreator) {
    424        cacheCreator->DeleteCache(mRequestHandle->GetCancelResult());
    425      }
    426      return;
    427    }
    428 
    429    nsresult rv = DataReceivedFromCache(
    430        (uint8_t*)"", 0, mChannelInfo, std::move(mPrincipalInfo),
    431        mCSPHeaderValue, mCSPReportOnlyHeaderValue, mReferrerPolicyHeaderValue);
    432 
    433    mRequestHandle->OnStreamComplete(rv);
    434    return;
    435  }
    436 
    437  MOZ_ASSERT(!mPump);
    438  rv = NS_NewInputStreamPump(getter_AddRefs(mPump), inputStream.forget(),
    439                             0,     /* default segsize */
    440                             0,     /* default segcount */
    441                             false, /* default closeWhenDone */
    442                             mMainThreadEventTarget);
    443  if (NS_WARN_IF(NS_FAILED(rv))) {
    444    Fail(rv);
    445    return;
    446  }
    447 
    448  nsCOMPtr<nsIStreamLoader> loader;
    449  rv = NS_NewStreamLoader(getter_AddRefs(loader), this);
    450  if (NS_WARN_IF(NS_FAILED(rv))) {
    451    Fail(rv);
    452    return;
    453  }
    454 
    455  rv = mPump->AsyncRead(loader);
    456  if (NS_WARN_IF(NS_FAILED(rv))) {
    457    mPump = nullptr;
    458    Fail(rv);
    459    return;
    460  }
    461 
    462  nsCOMPtr<nsIThreadRetargetableRequest> rr = do_QueryInterface(mPump);
    463  if (rr) {
    464    nsCOMPtr<nsIEventTarget> sts =
    465        do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
    466    RefPtr<TaskQueue> queue =
    467        TaskQueue::Create(sts.forget(), "CacheLoadHandler STS Delivery Queue");
    468    rv = rr->RetargetDeliveryTo(queue);
    469    if (NS_FAILED(rv)) {
    470      NS_WARNING("Failed to dispatch the nsIInputStreamPump to a IO thread.");
    471    }
    472  }
    473 
    474  loadContext->mCacheStatus = WorkerLoadContext::ReadingFromCache;
    475 }
    476 
    477 NS_IMETHODIMP
    478 CacheLoadHandler::OnStreamComplete(nsIStreamLoader* aLoader,
    479                                   nsISupports* aContext, nsresult aStatus,
    480                                   uint32_t aStringLen,
    481                                   const uint8_t* aString) {
    482  AssertIsOnMainThread();
    483  if (mRequestHandle->IsEmpty()) {
    484    return NS_OK;
    485  }
    486  WorkerLoadContext* loadContext = mRequestHandle->GetContext();
    487 
    488  mPump = nullptr;
    489 
    490  if (NS_FAILED(aStatus)) {
    491    MOZ_ASSERT(loadContext->mCacheStatus ==
    492                   WorkerLoadContext::ReadingFromCache ||
    493               loadContext->mCacheStatus == WorkerLoadContext::Cancel);
    494    Fail(aStatus);
    495    return NS_OK;
    496  }
    497 
    498  MOZ_ASSERT(loadContext->mCacheStatus == WorkerLoadContext::ReadingFromCache);
    499  loadContext->mCacheStatus = WorkerLoadContext::Cached;
    500 
    501  MOZ_ASSERT(mPrincipalInfo);
    502 
    503  nsresult rv = DataReceivedFromCache(
    504      aString, aStringLen, mChannelInfo, std::move(mPrincipalInfo),
    505      mCSPHeaderValue, mCSPReportOnlyHeaderValue, mReferrerPolicyHeaderValue);
    506  return mRequestHandle->OnStreamComplete(rv);
    507 }
    508 
    509 nsresult CacheLoadHandler::DataReceivedFromCache(
    510    const uint8_t* aString, uint32_t aStringLen,
    511    const mozilla::dom::ChannelInfo& aChannelInfo,
    512    UniquePtr<PrincipalInfo> aPrincipalInfo, const nsACString& aCSPHeaderValue,
    513    const nsACString& aCSPReportOnlyHeaderValue,
    514    const nsACString& aReferrerPolicyHeaderValue) {
    515  AssertIsOnMainThread();
    516  if (mRequestHandle->IsEmpty()) {
    517    return NS_OK;
    518  }
    519  WorkerLoadContext* loadContext = mRequestHandle->GetContext();
    520 
    521  MOZ_ASSERT(loadContext->mCacheStatus == WorkerLoadContext::Cached);
    522  MOZ_ASSERT(loadContext->mRequest);
    523 
    524  auto responsePrincipalOrErr = PrincipalInfoToPrincipal(*aPrincipalInfo);
    525  MOZ_DIAGNOSTIC_ASSERT(responsePrincipalOrErr.isOk());
    526 
    527  nsIPrincipal* principal = mWorkerRef->Private()->GetPrincipal();
    528  if (!principal) {
    529    WorkerPrivate* parentWorker = mWorkerRef->Private()->GetParent();
    530    MOZ_ASSERT(parentWorker, "Must have a parent!");
    531    principal = parentWorker->GetPrincipal();
    532  }
    533 
    534  nsCOMPtr<nsIPrincipal> responsePrincipal = responsePrincipalOrErr.unwrap();
    535 
    536  loadContext->mMutedErrorFlag.emplace(!principal->Subsumes(responsePrincipal));
    537 
    538  // May be null.
    539  Document* parentDoc = mWorkerRef->Private()->GetDocument();
    540 
    541  // Use the regular ScriptDecoder Decoder for this grunt work! Should be just
    542  // fine because we're running on the main thread.
    543  nsresult rv;
    544 
    545  // Set the Source type to "text" for decoding.
    546  loadContext->mRequest->SetTextSource(loadContext);
    547 
    548  rv = mDecoder->DecodeRawData(loadContext->mRequest, aString, aStringLen,
    549                               /* aEndOfStream = */ true);
    550  NS_ENSURE_SUCCESS(rv, rv);
    551 
    552  if (!loadContext->mRequest->ScriptTextLength()) {
    553    nsContentUtils::ReportToConsole(nsIScriptError::warningFlag, "DOM"_ns,
    554                                    parentDoc, nsContentUtils::eDOM_PROPERTIES,
    555                                    "EmptyWorkerSourceWarning");
    556  }
    557 
    558  nsCOMPtr<nsIURI> finalURI;
    559  rv = NS_NewURI(getter_AddRefs(finalURI), loadContext->mFullURL);
    560  if (!loadContext->mRequest->BaseURL()) {
    561    loadContext->mRequest->SetBaseURL(finalURI);
    562  }
    563  if (loadContext->IsTopLevel()) {
    564    if (NS_SUCCEEDED(rv)) {
    565      mWorkerRef->Private()->SetBaseURI(finalURI);
    566    }
    567 
    568 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
    569    nsIPrincipal* principal = mWorkerRef->Private()->GetPrincipal();
    570    MOZ_DIAGNOSTIC_ASSERT(principal);
    571 
    572    bool equal = false;
    573    MOZ_ALWAYS_SUCCEEDS(responsePrincipal->Equals(principal, &equal));
    574    MOZ_DIAGNOSTIC_ASSERT(equal);
    575 
    576    nsCOMPtr<nsIContentSecurityPolicy> csp;
    577    if (parentDoc) {
    578      csp = PolicyContainer::GetCSP(parentDoc->GetPolicyContainer());
    579    }
    580    MOZ_DIAGNOSTIC_ASSERT(!csp);
    581 #endif
    582 
    583    mWorkerRef->Private()->InitChannelInfo(aChannelInfo);
    584 
    585    nsILoadGroup* loadGroup = mWorkerRef->Private()->GetLoadGroup();
    586    MOZ_DIAGNOSTIC_ASSERT(loadGroup);
    587 
    588    // Override the principal on the WorkerPrivate.  This is only necessary
    589    // in order to get a principal with exactly the correct URL.  The fetch
    590    // referrer logic depends on the WorkerPrivate principal having a URL
    591    // that matches the worker script URL.  If bug 1340694 is ever fixed
    592    // this can be removed.
    593    // XXX: force the partitionedPrincipal to be equal to the response one.
    594    // This is OK for now because we don't want to expose partitionedPrincipal
    595    // functionality in ServiceWorkers yet.
    596    rv = mWorkerRef->Private()->SetPrincipalsAndCSPOnMainThread(
    597        responsePrincipal, responsePrincipal, loadGroup, nullptr);
    598    MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
    599 
    600    rv = mWorkerRef->Private()->SetCSPFromHeaderValues(
    601        aCSPHeaderValue, aCSPReportOnlyHeaderValue);
    602    MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
    603 
    604    mWorkerRef->Private()->UpdateReferrerInfoFromHeader(
    605        aReferrerPolicyHeaderValue);
    606  }
    607 
    608  if (NS_SUCCEEDED(rv)) {
    609    return DataReceived();
    610  }
    611 
    612  return rv;
    613 }
    614 
    615 nsresult CacheLoadHandler::DataReceived() {
    616  MOZ_ASSERT(!mRequestHandle->IsEmpty());
    617  WorkerLoadContext* loadContext = mRequestHandle->GetContext();
    618 
    619  if (loadContext->IsTopLevel()) {
    620    WorkerPrivate* parent = mWorkerRef->Private()->GetParent();
    621 
    622    if (parent) {
    623      // XHR Params Allowed
    624      mWorkerRef->Private()->SetXHRParamsAllowed(parent->XHRParamsAllowed());
    625 
    626      // Set ContentSecurityPolicy
    627      nsresult rv = mWorkerRef->Private()->SetCsp(parent->GetCsp());
    628      NS_ENSURE_SUCCESS(rv, rv);
    629    }
    630  }
    631 
    632  return NS_OK;
    633 }
    634 
    635 }  // namespace workerinternals::loader
    636 
    637 }  // namespace dom
    638 }  // namespace mozilla