diff options
Diffstat (limited to '')
-rw-r--r-- | dom/workers/loader/CacheLoadHandler.cpp | 646 |
1 files changed, 646 insertions, 0 deletions
diff --git a/dom/workers/loader/CacheLoadHandler.cpp b/dom/workers/loader/CacheLoadHandler.cpp new file mode 100644 index 0000000000..a3ad48fc98 --- /dev/null +++ b/dom/workers/loader/CacheLoadHandler.cpp @@ -0,0 +1,646 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "CacheLoadHandler.h" +#include "ScriptResponseHeaderProcessor.h" // ScriptResponseHeaderProcessor +#include "WorkerLoadContext.h" // WorkerLoadContext + +#include "nsIPrincipal.h" + +#include "nsIThreadRetargetableRequest.h" +#include "nsIXPConnect.h" + +#include "jsapi.h" +#include "nsNetUtil.h" + +#include "mozilla/Assertions.h" +#include "mozilla/Encoding.h" +#include "mozilla/dom/CacheBinding.h" +#include "mozilla/dom/cache/CacheTypes.h" +#include "mozilla/dom/Response.h" +#include "mozilla/dom/ServiceWorkerBinding.h" // ServiceWorkerState +#include "mozilla/Result.h" +#include "mozilla/UniquePtr.h" +#include "mozilla/dom/Document.h" +#include "mozilla/dom/WorkerScope.h" + +#include "mozilla/dom/workerinternals/ScriptLoader.h" // WorkerScriptLoader + +namespace mozilla { +namespace dom { + +namespace workerinternals::loader { + +NS_IMPL_ISUPPORTS0(CacheCreator) + +NS_IMPL_ISUPPORTS(CacheLoadHandler, nsIStreamLoaderObserver) + +NS_IMPL_ISUPPORTS0(CachePromiseHandler) + +CachePromiseHandler::CachePromiseHandler( + WorkerScriptLoader* aLoader, ThreadSafeRequestHandle* aRequestHandle) + : mLoader(aLoader), mRequestHandle(aRequestHandle) { + AssertIsOnMainThread(); + MOZ_ASSERT(mLoader); +} + +void CachePromiseHandler::ResolvedCallback(JSContext* aCx, + JS::Handle<JS::Value> aValue, + ErrorResult& aRv) { + AssertIsOnMainThread(); + if (mRequestHandle->IsEmpty()) { + return; + } + WorkerLoadContext* loadContext = mRequestHandle->GetContext(); + + // May already have been canceled by CacheLoadHandler::Fail from + // CancelMainThread. + MOZ_ASSERT(loadContext->mCacheStatus == WorkerLoadContext::WritingToCache || + loadContext->mCacheStatus == WorkerLoadContext::Cancel); + MOZ_ASSERT_IF(loadContext->mCacheStatus == WorkerLoadContext::Cancel, + !loadContext->mCachePromise); + + if (loadContext->mCachePromise) { + loadContext->mCacheStatus = WorkerLoadContext::Cached; + loadContext->mCachePromise = nullptr; + mRequestHandle->MaybeExecuteFinishedScripts(); + } +} + +void CachePromiseHandler::RejectedCallback(JSContext* aCx, + JS::Handle<JS::Value> aValue, + ErrorResult& aRv) { + AssertIsOnMainThread(); + if (mRequestHandle->IsEmpty()) { + return; + } + WorkerLoadContext* loadContext = mRequestHandle->GetContext(); + + // May already have been canceled by CacheLoadHandler::Fail from + // CancelMainThread. + MOZ_ASSERT(loadContext->mCacheStatus == WorkerLoadContext::WritingToCache || + loadContext->mCacheStatus == WorkerLoadContext::Cancel); + loadContext->mCacheStatus = WorkerLoadContext::Cancel; + + loadContext->mCachePromise = nullptr; + + // This will delete the cache object and will call LoadingFinished() with an + // error for each ongoing operation. + auto* cacheCreator = mRequestHandle->GetCacheCreator(); + if (cacheCreator) { + cacheCreator->DeleteCache(NS_ERROR_FAILURE); + } +} + +CacheCreator::CacheCreator(WorkerPrivate* aWorkerPrivate) + : mCacheName(aWorkerPrivate->ServiceWorkerCacheName()), + mOriginAttributes(aWorkerPrivate->GetOriginAttributes()) { + MOZ_ASSERT(aWorkerPrivate->IsServiceWorker()); +} + +nsresult CacheCreator::CreateCacheStorage(nsIPrincipal* aPrincipal) { + AssertIsOnMainThread(); + MOZ_ASSERT(!mCacheStorage); + MOZ_ASSERT(aPrincipal); + + nsIXPConnect* xpc = nsContentUtils::XPConnect(); + MOZ_ASSERT(xpc, "This should never be null!"); + + AutoJSAPI jsapi; + jsapi.Init(); + JSContext* cx = jsapi.cx(); + JS::Rooted<JSObject*> sandbox(cx); + nsresult rv = xpc->CreateSandbox(cx, aPrincipal, sandbox.address()); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + // The JSContext is not in a realm, so CreateSandbox returned an unwrapped + // global. + MOZ_ASSERT(JS_IsGlobalObject(sandbox)); + + mSandboxGlobalObject = xpc::NativeGlobal(sandbox); + if (NS_WARN_IF(!mSandboxGlobalObject)) { + return NS_ERROR_FAILURE; + } + + // If we're in private browsing mode, don't even try to create the + // CacheStorage. Instead, just fail immediately to terminate the + // ServiceWorker load. + if (NS_WARN_IF(mOriginAttributes.mPrivateBrowsingId > 0)) { + return NS_ERROR_DOM_SECURITY_ERR; + } + + // Create a CacheStorage bypassing its trusted origin checks. The + // ServiceWorker has already performed its own checks before getting + // to this point. + ErrorResult error; + mCacheStorage = CacheStorage::CreateOnMainThread( + mozilla::dom::cache::CHROME_ONLY_NAMESPACE, mSandboxGlobalObject, + aPrincipal, true /* force trusted origin */, error); + if (NS_WARN_IF(error.Failed())) { + return error.StealNSResult(); + } + + return NS_OK; +} + +nsresult CacheCreator::Load(nsIPrincipal* aPrincipal) { + AssertIsOnMainThread(); + MOZ_ASSERT(!mLoaders.IsEmpty()); + + nsresult rv = CreateCacheStorage(aPrincipal); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + ErrorResult error; + MOZ_ASSERT(!mCacheName.IsEmpty()); + RefPtr<Promise> promise = mCacheStorage->Open(mCacheName, error); + if (NS_WARN_IF(error.Failed())) { + return error.StealNSResult(); + } + + promise->AppendNativeHandler(this); + return NS_OK; +} + +void CacheCreator::FailLoaders(nsresult aRv) { + AssertIsOnMainThread(); + + // Fail() can call LoadingFinished() which may call ExecuteFinishedScripts() + // which sets mCacheCreator to null, so hold a ref. + RefPtr<CacheCreator> kungfuDeathGrip = this; + + for (uint32_t i = 0, len = mLoaders.Length(); i < len; ++i) { + mLoaders[i]->Fail(aRv); + } + + mLoaders.Clear(); +} + +void CacheCreator::RejectedCallback(JSContext* aCx, + JS::Handle<JS::Value> aValue, + ErrorResult& aRv) { + AssertIsOnMainThread(); + FailLoaders(NS_ERROR_FAILURE); +} + +void CacheCreator::ResolvedCallback(JSContext* aCx, + JS::Handle<JS::Value> aValue, + ErrorResult& aRv) { + AssertIsOnMainThread(); + if (!aValue.isObject()) { + FailLoaders(NS_ERROR_FAILURE); + return; + } + + JS::Rooted<JSObject*> obj(aCx, &aValue.toObject()); + Cache* cache = nullptr; + nsresult rv = UNWRAP_OBJECT(Cache, &obj, cache); + if (NS_WARN_IF(NS_FAILED(rv))) { + FailLoaders(NS_ERROR_FAILURE); + return; + } + + mCache = cache; + MOZ_DIAGNOSTIC_ASSERT(mCache); + + // If the worker is canceled, CancelMainThread() will have cleared the + // loaders via DeleteCache(). + for (uint32_t i = 0, len = mLoaders.Length(); i < len; ++i) { + mLoaders[i]->Load(cache); + } +} + +void CacheCreator::DeleteCache(nsresult aReason) { + AssertIsOnMainThread(); + + // This is called when the load is canceled which can occur before + // mCacheStorage is initialized. + if (mCacheStorage) { + // It's safe to do this while Cache::Match() and Cache::Put() calls are + // running. + RefPtr<Promise> promise = mCacheStorage->Delete(mCacheName, IgnoreErrors()); + + // We don't care to know the result of the promise object. + } + + // Always call this here to ensure the loaders array is cleared. + FailLoaders(NS_ERROR_FAILURE); +} + +CacheLoadHandler::CacheLoadHandler(ThreadSafeWorkerRef* aWorkerRef, + ThreadSafeRequestHandle* aRequestHandle, + bool aIsWorkerScript, + WorkerScriptLoader* aLoader) + : mRequestHandle(aRequestHandle), + mLoader(aLoader), + mWorkerRef(aWorkerRef), + mIsWorkerScript(aIsWorkerScript), + mFailed(false), + mState(aWorkerRef->Private()->GetServiceWorkerDescriptor().State()) { + MOZ_ASSERT(aWorkerRef); + MOZ_ASSERT(aWorkerRef->Private()->IsServiceWorker()); + mMainThreadEventTarget = aWorkerRef->Private()->MainThreadEventTarget(); + MOZ_ASSERT(mMainThreadEventTarget); + mBaseURI = mLoader->GetBaseURI(); + AssertIsOnMainThread(); + + // Worker scripts are always decoded as UTF-8 per spec. + mDecoder = MakeUnique<ScriptDecoder>(UTF_8_ENCODING, + ScriptDecoder::BOMHandling::Remove); +} + +void CacheLoadHandler::Fail(nsresult aRv) { + AssertIsOnMainThread(); + MOZ_ASSERT(NS_FAILED(aRv)); + + if (mFailed) { + return; + } + + mFailed = true; + + if (mPump) { + MOZ_ASSERT_IF(!mRequestHandle->IsEmpty(), + mRequestHandle->GetContext()->mCacheStatus == + WorkerLoadContext::ReadingFromCache); + mPump->Cancel(aRv); + mPump = nullptr; + } + if (mRequestHandle->IsEmpty()) { + return; + } + + WorkerLoadContext* loadContext = mRequestHandle->GetContext(); + + loadContext->mCacheStatus = WorkerLoadContext::Cancel; + + if (loadContext->mCachePromise) { + loadContext->mCachePromise->MaybeReject(aRv); + } + + loadContext->mCachePromise = nullptr; + + mRequestHandle->LoadingFinished(aRv); +} + +void CacheLoadHandler::Load(Cache* aCache) { + AssertIsOnMainThread(); + MOZ_ASSERT(aCache); + MOZ_ASSERT(!mRequestHandle->IsEmpty()); + WorkerLoadContext* loadContext = mRequestHandle->GetContext(); + + nsCOMPtr<nsIURI> uri; + nsresult rv = NS_NewURI(getter_AddRefs(uri), loadContext->mRequest->mURL, + nullptr, mBaseURI); + if (NS_WARN_IF(NS_FAILED(rv))) { + Fail(rv); + return; + } + + nsAutoCString spec; + rv = uri->GetSpec(spec); + if (NS_WARN_IF(NS_FAILED(rv))) { + Fail(rv); + return; + } + + MOZ_ASSERT(loadContext->mFullURL.IsEmpty()); + CopyUTF8toUTF16(spec, loadContext->mFullURL); + + mozilla::dom::RequestOrUSVString request; + request.SetAsUSVString().ShareOrDependUpon(loadContext->mFullURL); + + mozilla::dom::CacheQueryOptions params; + + // This JSContext will not end up executing JS code because here there are + // no ReadableStreams involved. + AutoJSAPI jsapi; + jsapi.Init(); + + ErrorResult error; + RefPtr<Promise> promise = aCache->Match(jsapi.cx(), request, params, error); + if (NS_WARN_IF(error.Failed())) { + Fail(error.StealNSResult()); + return; + } + + promise->AppendNativeHandler(this); +} + +void CacheLoadHandler::RejectedCallback(JSContext* aCx, + JS::Handle<JS::Value> aValue, + ErrorResult& aRv) { + AssertIsOnMainThread(); + MOZ_ASSERT(!mRequestHandle->IsEmpty()); + + MOZ_ASSERT(mRequestHandle->GetContext()->mCacheStatus == + WorkerLoadContext::Uncached); + Fail(NS_ERROR_FAILURE); +} + +void CacheLoadHandler::ResolvedCallback(JSContext* aCx, + JS::Handle<JS::Value> aValue, + ErrorResult& aRv) { + AssertIsOnMainThread(); + MOZ_ASSERT(!mRequestHandle->IsEmpty()); + WorkerLoadContext* loadContext = mRequestHandle->GetContext(); + + // If we have already called 'Fail', we should not proceed. If we cancelled, + // we should similarily not proceed. + if (mFailed) { + return; + } + + MOZ_ASSERT(loadContext->mCacheStatus == WorkerLoadContext::Uncached); + + nsresult rv; + + // The ServiceWorkerScriptCache will store data for any scripts it + // it knows about. This is always at least the top level script. + // Depending on if a previous version of the service worker has + // been installed or not it may also know about importScripts(). We + // must handle loading and offlining new importScripts() here, however. + if (aValue.isUndefined()) { + // If this is the main script or we're not loading a new service worker + // then this is an error. This can happen for internal reasons, like + // storage was probably wiped without removing the service worker + // registration. It can also happen for exposed reasons like the + // service worker script calling importScripts() after install. + if (NS_WARN_IF(mIsWorkerScript || + (mState != ServiceWorkerState::Parsed && + mState != ServiceWorkerState::Installing))) { + Fail(NS_ERROR_DOM_INVALID_STATE_ERR); + return; + } + + loadContext->mCacheStatus = WorkerLoadContext::ToBeCached; + rv = mLoader->LoadScript(mRequestHandle); + if (NS_WARN_IF(NS_FAILED(rv))) { + Fail(rv); + } + return; + } + + MOZ_ASSERT(aValue.isObject()); + + JS::Rooted<JSObject*> obj(aCx, &aValue.toObject()); + mozilla::dom::Response* response = nullptr; + rv = UNWRAP_OBJECT(Response, &obj, response); + if (NS_WARN_IF(NS_FAILED(rv))) { + Fail(rv); + return; + } + + InternalHeaders* headers = response->GetInternalHeaders(); + + headers->Get("content-security-policy"_ns, mCSPHeaderValue, IgnoreErrors()); + headers->Get("content-security-policy-report-only"_ns, + mCSPReportOnlyHeaderValue, IgnoreErrors()); + headers->Get("referrer-policy"_ns, mReferrerPolicyHeaderValue, + IgnoreErrors()); + + nsAutoCString coepHeader; + headers->Get("cross-origin-embedder-policy"_ns, coepHeader, IgnoreErrors()); + + nsILoadInfo::CrossOriginEmbedderPolicy coep = + NS_GetCrossOriginEmbedderPolicyFromHeader( + coepHeader, mWorkerRef->Private()->Trials().IsEnabled( + OriginTrial::CoepCredentialless)); + + rv = ScriptResponseHeaderProcessor::ProcessCrossOriginEmbedderPolicyHeader( + mWorkerRef->Private(), coep, loadContext->IsTopLevel()); + + if (NS_WARN_IF(NS_FAILED(rv))) { + Fail(rv); + return; + } + + nsCOMPtr<nsIInputStream> inputStream; + response->GetBody(getter_AddRefs(inputStream)); + mChannelInfo = response->GetChannelInfo(); + const UniquePtr<PrincipalInfo>& pInfo = response->GetPrincipalInfo(); + if (pInfo) { + mPrincipalInfo = mozilla::MakeUnique<PrincipalInfo>(*pInfo); + } + + if (!inputStream) { + loadContext->mCacheStatus = WorkerLoadContext::Cached; + + if (mRequestHandle->IsCancelled()) { + auto* cacheCreator = mRequestHandle->GetCacheCreator(); + if (cacheCreator) { + cacheCreator->DeleteCache(mRequestHandle->GetCancelResult()); + } + return; + } + + nsresult rv = DataReceivedFromCache( + (uint8_t*)"", 0, mChannelInfo, std::move(mPrincipalInfo), + mCSPHeaderValue, mCSPReportOnlyHeaderValue, mReferrerPolicyHeaderValue); + + mRequestHandle->OnStreamComplete(rv); + return; + } + + MOZ_ASSERT(!mPump); + rv = NS_NewInputStreamPump(getter_AddRefs(mPump), inputStream.forget(), + 0, /* default segsize */ + 0, /* default segcount */ + false, /* default closeWhenDone */ + mMainThreadEventTarget); + if (NS_WARN_IF(NS_FAILED(rv))) { + Fail(rv); + return; + } + + nsCOMPtr<nsIStreamLoader> loader; + rv = NS_NewStreamLoader(getter_AddRefs(loader), this); + if (NS_WARN_IF(NS_FAILED(rv))) { + Fail(rv); + return; + } + + rv = mPump->AsyncRead(loader); + if (NS_WARN_IF(NS_FAILED(rv))) { + mPump = nullptr; + Fail(rv); + return; + } + + nsCOMPtr<nsIThreadRetargetableRequest> rr = do_QueryInterface(mPump); + if (rr) { + nsCOMPtr<nsIEventTarget> sts = + do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID); + rv = rr->RetargetDeliveryTo(sts); + if (NS_FAILED(rv)) { + NS_WARNING("Failed to dispatch the nsIInputStreamPump to a IO thread."); + } + } + + loadContext->mCacheStatus = WorkerLoadContext::ReadingFromCache; +} + +NS_IMETHODIMP +CacheLoadHandler::OnStreamComplete(nsIStreamLoader* aLoader, + nsISupports* aContext, nsresult aStatus, + uint32_t aStringLen, + const uint8_t* aString) { + AssertIsOnMainThread(); + if (mRequestHandle->IsEmpty()) { + return NS_OK; + } + WorkerLoadContext* loadContext = mRequestHandle->GetContext(); + + mPump = nullptr; + + if (NS_FAILED(aStatus)) { + MOZ_ASSERT(loadContext->mCacheStatus == + WorkerLoadContext::ReadingFromCache || + loadContext->mCacheStatus == WorkerLoadContext::Cancel); + Fail(aStatus); + return NS_OK; + } + + MOZ_ASSERT(loadContext->mCacheStatus == WorkerLoadContext::ReadingFromCache); + loadContext->mCacheStatus = WorkerLoadContext::Cached; + + MOZ_ASSERT(mPrincipalInfo); + + nsresult rv = DataReceivedFromCache( + aString, aStringLen, mChannelInfo, std::move(mPrincipalInfo), + mCSPHeaderValue, mCSPReportOnlyHeaderValue, mReferrerPolicyHeaderValue); + return mRequestHandle->OnStreamComplete(rv); +} + +nsresult CacheLoadHandler::DataReceivedFromCache( + const uint8_t* aString, uint32_t aStringLen, + const mozilla::dom::ChannelInfo& aChannelInfo, + UniquePtr<PrincipalInfo> aPrincipalInfo, const nsACString& aCSPHeaderValue, + const nsACString& aCSPReportOnlyHeaderValue, + const nsACString& aReferrerPolicyHeaderValue) { + AssertIsOnMainThread(); + if (mRequestHandle->IsEmpty()) { + return NS_OK; + } + WorkerLoadContext* loadContext = mRequestHandle->GetContext(); + + MOZ_ASSERT(loadContext->mCacheStatus == WorkerLoadContext::Cached); + MOZ_ASSERT(loadContext->mRequest); + + auto responsePrincipalOrErr = PrincipalInfoToPrincipal(*aPrincipalInfo); + MOZ_DIAGNOSTIC_ASSERT(responsePrincipalOrErr.isOk()); + + nsIPrincipal* principal = mWorkerRef->Private()->GetPrincipal(); + if (!principal) { + WorkerPrivate* parentWorker = mWorkerRef->Private()->GetParent(); + MOZ_ASSERT(parentWorker, "Must have a parent!"); + principal = parentWorker->GetPrincipal(); + } + + nsCOMPtr<nsIPrincipal> responsePrincipal = responsePrincipalOrErr.unwrap(); + + loadContext->mMutedErrorFlag.emplace(!principal->Subsumes(responsePrincipal)); + + // May be null. + Document* parentDoc = mWorkerRef->Private()->GetDocument(); + + // Use the regular ScriptDecoder Decoder for this grunt work! Should be just + // fine because we're running on the main thread. + nsresult rv; + + // Set the Source type to "text" for decoding. + loadContext->mRequest->SetTextSource(); + + rv = mDecoder->DecodeRawData(loadContext->mRequest, aString, aStringLen, + /* aEndOfStream = */ true); + NS_ENSURE_SUCCESS(rv, rv); + + if (!loadContext->mRequest->ScriptTextLength()) { + nsContentUtils::ReportToConsole(nsIScriptError::warningFlag, "DOM"_ns, + parentDoc, nsContentUtils::eDOM_PROPERTIES, + "EmptyWorkerSourceWarning"); + } + + if (loadContext->IsTopLevel()) { + nsCOMPtr<nsIURI> finalURI; + rv = NS_NewURI(getter_AddRefs(finalURI), loadContext->mFullURL); + if (NS_SUCCEEDED(rv)) { + mWorkerRef->Private()->SetBaseURI(finalURI); + } + +#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED + nsIPrincipal* principal = mWorkerRef->Private()->GetPrincipal(); + MOZ_DIAGNOSTIC_ASSERT(principal); + + bool equal = false; + MOZ_ALWAYS_SUCCEEDS(responsePrincipal->Equals(principal, &equal)); + MOZ_DIAGNOSTIC_ASSERT(equal); + + nsCOMPtr<nsIContentSecurityPolicy> csp; + if (parentDoc) { + csp = parentDoc->GetCsp(); + } + MOZ_DIAGNOSTIC_ASSERT(!csp); +#endif + + mWorkerRef->Private()->InitChannelInfo(aChannelInfo); + + nsILoadGroup* loadGroup = mWorkerRef->Private()->GetLoadGroup(); + MOZ_DIAGNOSTIC_ASSERT(loadGroup); + + // Override the principal on the WorkerPrivate. This is only necessary + // in order to get a principal with exactly the correct URL. The fetch + // referrer logic depends on the WorkerPrivate principal having a URL + // that matches the worker script URL. If bug 1340694 is ever fixed + // this can be removed. + // XXX: force the partitionedPrincipal to be equal to the response one. + // This is OK for now because we don't want to expose partitionedPrincipal + // functionality in ServiceWorkers yet. + rv = mWorkerRef->Private()->SetPrincipalsAndCSPOnMainThread( + responsePrincipal, responsePrincipal, loadGroup, nullptr); + MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv)); + + rv = mWorkerRef->Private()->SetCSPFromHeaderValues( + aCSPHeaderValue, aCSPReportOnlyHeaderValue); + MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv)); + + mWorkerRef->Private()->UpdateReferrerInfoFromHeader( + aReferrerPolicyHeaderValue); + } + + if (NS_SUCCEEDED(rv)) { + DataReceived(); + } + + return rv; +} + +void CacheLoadHandler::DataReceived() { + MOZ_ASSERT(!mRequestHandle->IsEmpty()); + WorkerLoadContext* loadContext = mRequestHandle->GetContext(); + + if (loadContext->IsTopLevel()) { + WorkerPrivate* parent = mWorkerRef->Private()->GetParent(); + + if (parent) { + // XHR Params Allowed + mWorkerRef->Private()->SetXHRParamsAllowed(parent->XHRParamsAllowed()); + + // Set Eval and ContentSecurityPolicy + mWorkerRef->Private()->SetCsp(parent->GetCsp()); + mWorkerRef->Private()->SetEvalAllowed(parent->IsEvalAllowed()); + mWorkerRef->Private()->SetWasmEvalAllowed(parent->IsWasmEvalAllowed()); + } + } +} + +} // namespace workerinternals::loader + +} // namespace dom +} // namespace mozilla |