/* 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 "ModuleLoader.h" #include #include "GeckoProfiler.h" #include "ScriptLoader.h" #include "ScriptTrace.h" // TRACE_FOR_TEST #include "js/CompileOptions.h" // JS::CompileOptions, JS::InstantiateOptions #include "js/ContextOptions.h" // JS::ContextOptionsRef #include "js/MemoryFunctions.h" #include "js/Modules.h" // JS::FinishDynamicModuleImport, JS::{G,S}etModuleResolveHook, JS::Get{ModulePrivate,ModuleScript,RequestedModule{s,Specifier,SourcePos}}, JS::SetModule{DynamicImport,Metadata}Hook #include "js/PropertyAndElement.h" // JS_DefineProperty #include "js/Realm.h" #include "js/SourceText.h" #include "js/experimental/JSStencil.h" // JS::Stencil, JS::CompileModuleScriptToStencil, JS::InstantiateModuleStencil #include "js/friend/ErrorMessages.h" // js::GetErrorMessage, JSMSG_* #include "js/loader/LoadedScript.h" #include "js/loader/ModuleLoadRequest.h" #include "js/loader/ModuleLoaderBase.h" #include "js/loader/ScriptLoadRequest.h" #include "jsapi.h" #include "mozilla/Assertions.h" #include "mozilla/CycleCollectedJSContext.h" #include "mozilla/LoadInfo.h" #include "mozilla/Maybe.h" #include "mozilla/StaticPrefs_dom.h" #include "mozilla/StyleSheet.h" #include "mozilla/StyleSheetInlines.h" #include "mozilla/dom/AutoEntryScript.h" #include "mozilla/dom/Document.h" #include "mozilla/dom/Element.h" #include "mozilla/dom/RequestBinding.h" #include "nsContentSecurityManager.h" #include "nsContentSecurityUtils.h" #include "nsError.h" #include "nsIContent.h" #include "nsIPrincipal.h" #include "nsJSUtils.h" #include "xpcpublic.h" using JS::SourceText; using namespace JS::loader; namespace mozilla::dom { #undef LOG #define LOG(args) \ MOZ_LOG(ScriptLoader::gScriptLoaderLog, mozilla::LogLevel::Debug, args) #define LOG_ENABLED() \ MOZ_LOG_TEST(ScriptLoader::gScriptLoaderLog, mozilla::LogLevel::Debug) ////////////////////////////////////////////////////////////// // DOM module loader ////////////////////////////////////////////////////////////// ModuleLoader::ModuleLoader(ScriptLoader* aLoader, nsIGlobalObject* aGlobalObject, Kind aKind) : ModuleLoaderBase(aLoader, aGlobalObject), mKind(aKind) {} ScriptLoader* ModuleLoader::GetScriptLoader() { return static_cast(mLoader.get()); } bool ModuleLoader::CanStartLoad(ModuleLoadRequest* aRequest, nsresult* aRvOut) { if (!GetScriptLoader()->GetDocument()) { *aRvOut = NS_ERROR_NULL_POINTER; return false; } nsCOMPtr principal = aRequest->TriggeringPrincipal(); if (BasePrincipal::Cast(principal)->ContentScriptAddonPolicy()) { // To prevent dynamic code execution, content scripts can only // load moz-extension URLs. if (!aRequest->URI()->SchemeIs("moz-extension")) { *aRvOut = NS_ERROR_DOM_WEBEXT_CONTENT_SCRIPT_URI; return false; } } else { // If this document is sandboxed without 'allow-scripts', abort. if (GetScriptLoader()->GetDocument()->HasScriptsBlockedBySandbox()) { *aRvOut = NS_ERROR_CONTENT_BLOCKED; return false; } } if (LOG_ENABLED()) { nsAutoCString url; aRequest->URI()->GetAsciiSpec(url); LOG(("ScriptLoadRequest (%p): Start Module Load (url = %s)", aRequest, url.get())); } return true; } void ModuleLoader::DisallowImportMapsForModuleFetch( ModuleLoadRequest* aRequest) { if (!aRequest->GetScriptLoadContext()->IsPreload() && !StaticPrefs::dom_multiple_import_maps_enabled()) { LOG(("ScriptLoadRequest (%p): Disallow further import maps.", aRequest)); DisallowImportMaps(); } } // Skip module CORS checks for resource: principals loading trusted schemes. // Other URI security checks still apply. static bool IsResourceDocumentLoadingTrustedURI(ModuleLoadRequest* aRequest) { nsIPrincipal* triggeringPrincipal = aRequest->TriggeringPrincipal(); if (!triggeringPrincipal->GetIsContentPrincipal() || !triggeringPrincipal->SchemeIs("resource")) { return false; } return nsContentSecurityUtils::IsTrustedScheme(aRequest->URI()); } nsresult ModuleLoader::StartFetch(ModuleLoadRequest* aRequest) { if (aRequest->IsRetrievedFromMemoryCache()) { DisallowImportMapsForModuleFetch(aRequest); GetScriptLoader()->EmulateNetworkEvents(aRequest, Nothing()); SetModuleFetchStarted(aRequest); aRequest->OnFetchComplete(NS_OK); return NS_OK; } // Module scripts normally require CORS. Disable it for non-linkable about: // pages loading chrome: URLs and resource: principals loading trusted // schemes. bool skipCORSChecks = ScriptLoader::IsAboutPageLoadingChromeURI( aRequest, GetScriptLoader()->GetDocument()) || IsResourceDocumentLoadingTrustedURI(aRequest); nsContentSecurityManager::CORSSecurityMapping corsMapping = skipCORSChecks ? nsContentSecurityManager::CORSSecurityMapping::DISABLE_CORS_CHECKS : nsContentSecurityManager::CORSSecurityMapping::REQUIRE_CORS_CHECKS; nsSecurityFlags securityFlags = nsContentSecurityManager::ComputeSecurityFlags(aRequest->CORSMode(), corsMapping); securityFlags |= nsILoadInfo::SEC_ALLOW_CHROME; // Delegate Shared Behavior to base ScriptLoader // // aCharsetForPreload is passed as Nothing() because this is not a preload // and `StartLoadInternal` is able to find the charset by using `aRequest` // for this case. nsresult rv = GetScriptLoader()->StartLoadInternal( aRequest, securityFlags, Nothing() /* aCharsetForPreload */); NS_ENSURE_SUCCESS(rv, rv); DisallowImportMapsForModuleFetch(aRequest); LOG(("ScriptLoadRequest (%p): Start fetching module", aRequest)); return NS_OK; } void ModuleLoader::AsyncExecuteInlineModule(ModuleLoadRequest* aRequest) { MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread( mozilla::NewRunnableMethod>( "ModuleLoader::ExecuteInlineModule", this, &ModuleLoader::ExecuteInlineModule, aRequest))); } void ModuleLoader::ExecuteInlineModule(ModuleLoadRequest* aRequest) { MOZ_ASSERT(aRequest->IsFinished()); MOZ_ASSERT(aRequest->IsTopLevel()); MOZ_ASSERT(aRequest->GetScriptLoadContext()->mIsInline); if (aRequest->GetScriptLoadContext()->GetParserCreated() == NOT_FROM_PARSER) { GetScriptLoader()->RunScriptWhenSafe(aRequest); } else { const RefPtr scriptLoader = GetScriptLoader(); scriptLoader->MaybeMoveToLoadedList(aRequest); scriptLoader->ProcessPendingRequests(); } aRequest->GetScriptLoadContext()->MaybeUnblockOnload(); } void ModuleLoader::OnModuleLoadComplete(ModuleLoadRequest* aRequest) { MOZ_ASSERT(aRequest->IsFinished()); if (aRequest->IsTopLevel() || aRequest->IsDynamicImport()) { if (aRequest->GetScriptLoadContext()->mIsInline && aRequest->GetScriptLoadContext()->GetParserCreated() == NOT_FROM_PARSER) { // https://html.spec.whatwg.org/#prepare-the-script-element // Step 32.2. // type: "module": // 3.1. Queue an element task on the networking task source given // el to perform the following steps: // 1. Mark as ready el given result. // // Step 33. If ... el's type is "module": // ... // 3. Otherwise, if el is not parser-inserted: // 3. Set el's steps to run when the result is ready to the // following: // ... // 2.1. Execute the script element scripts[0]. AsyncExecuteInlineModule(aRequest); return; } else if (aRequest->GetScriptLoadContext()->mIsInline && aRequest->GetScriptLoadContext()->GetParserCreated() != NOT_FROM_PARSER && !nsContentUtils::IsSafeToRunScript()) { // Avoid giving inline async module scripts that don't have // external dependencies a guaranteed execution time relative // to the HTML parse. That is, deliberately avoid guaranteeing // that the script would always observe a DOM shape where the // parser has not added further elements to the DOM. // (If `nsContentUtils::IsSafeToRunScript()` returns `true`, // we come here synchronously from the parser. If it returns // `false` we come here from an external dependency completing // its fetch, in which case we already are at an unspecific // point relative to the parse.) AsyncExecuteInlineModule(aRequest); return; } else { GetScriptLoader()->MaybeMoveToLoadedList(aRequest); GetScriptLoader()->ProcessPendingRequestsAsync(); } } aRequest->GetScriptLoadContext()->MaybeUnblockOnload(); } nsresult ModuleLoader::CompileFetchedModule( JSContext* aCx, JS::Handle aGlobal, JS::CompileOptions& aOptions, ModuleLoadRequest* aRequest, JS::MutableHandle aModuleOut) { switch (aRequest->mModuleType) { case JS::ModuleType::Unknown: MOZ_CRASH("Unexpected module type"); case JS::ModuleType::JavaScriptOrWasm: return CompileJavaScriptOrWasmModule(aCx, aGlobal, aOptions, aRequest, aModuleOut); case JS::ModuleType::JSON: return CompileJsonModule(aCx, aOptions, aRequest, aModuleOut); case JS::ModuleType::CSS: return CompileCssModule(aCx, aOptions, aRequest, aModuleOut); case JS::ModuleType::Text: return CreateTextModule(aCx, aOptions, aRequest, aModuleOut); case JS::ModuleType::Bytes: MOZ_CRASH("Unexpected module type"); } MOZ_CRASH("Unhandled module type"); } // https://html.spec.whatwg.org/#creating-a-javascript-module-script // Step 1: If scripting is disabled, set source to empty string nsresult ModuleLoader::CompileEmptyJavaScriptModule( JSContext* aCx, JS::CompileOptions& aOptions, ModuleLoadRequest* aRequest, JS::MutableHandle aModuleOut) { JS::SourceText srcBuf; if (!srcBuf.init(aCx, u"", 0, JS::SourceOwnership::Borrowed)) { return NS_ERROR_OUT_OF_MEMORY; } RefPtr stencil = JS::CompileModuleScriptToStencil(aCx, aOptions, srcBuf); if (!stencil) { return NS_ERROR_FAILURE; } aRequest->SetStencil(stencil); JS::InstantiateOptions instantiateOptions(aOptions); aModuleOut.set( JS::InstantiateModuleStencil(aCx, instantiateOptions, stencil)); return aModuleOut ? NS_OK : NS_ERROR_FAILURE; } #ifdef NIGHTLY_BUILD nsresult ModuleLoader::CompileWasmModuleBytes( JSContext* aCx, JS::CompileOptions& aOptions, ModuleLoadRequest* aRequest, WasmBytesBuffer& aBytes, JS::MutableHandle aModuleOut) { JSObject* wasmModule; if (aRequest->IsSourcePhaseRequest(aCx)) { wasmModule = JS::CompileWasmModuleAsSource(aCx, aOptions, aBytes); } else { wasmModule = JS::CompileWasmModule(aCx, aOptions, aBytes); } if (!wasmModule) { return NS_ERROR_FAILURE; } aModuleOut.set(wasmModule); return NS_OK; } // https://html.spec.whatwg.org/#creating-a-webassembly-module-script nsresult ModuleLoader::CompileEmptyWasmModule( JSContext* aCx, JS::CompileOptions& aOptions, ModuleLoadRequest* aRequest, JS::MutableHandle aModuleOut) { TRACE_FOR_TEST(aRequest, "compile:wasm empty"); // Step 1: If scripting is disabled, set bodyBytes to the byte sequence // 0x00 0x61 0x73 0x6D 0x01 0x00 0x00 0x00 static constexpr uint8_t kEmptyWasmModule[] = {0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00}; WasmBytesBuffer bytes; if (!bytes.append(kEmptyWasmModule, sizeof(kEmptyWasmModule))) { return NS_ERROR_OUT_OF_MEMORY; } return CompileWasmModuleBytes(aCx, aOptions, aRequest, bytes, aModuleOut); } #endif nsresult ModuleLoader::CompileJavaScriptOrWasmModule( JSContext* aCx, JS::Handle aGlobal, JS::CompileOptions& aOptions, ModuleLoadRequest* aRequest, JS::MutableHandle aModuleOut) { GetScriptLoader()->CalculateCacheFlag(aRequest); if (!nsJSUtils::IsScriptable(aGlobal)) { aRequest->GetScriptLoadContext()->MaybeCancelOffThreadScript(); #ifdef NIGHTLY_BUILD if (aRequest->HasWasmMimeTypeEssence()) { MOZ_ASSERT(aRequest->IsWasmBytes()); return CompileEmptyWasmModule(aCx, aOptions, aRequest, aModuleOut); } #endif return CompileEmptyJavaScriptModule(aCx, aOptions, aRequest, aModuleOut); } #ifdef NIGHTLY_BUILD if (aRequest->HasWasmMimeTypeEssence()) { MOZ_ASSERT(aRequest->IsWasmBytes()); // Only source phase requests are compiled off-thread, and the request's // bytes were moved into the WasmCompileTask, so the result has to be taken // from the task rather than recompiled. if (aRequest->GetScriptLoadContext()->mWasCompiledOMT) { MOZ_ASSERT(aRequest->IsSourcePhaseRequest(aCx)); if (!aRequest->GetScriptLoadContext()->StealOffThreadWasmResult( aCx, aModuleOut)) { return NS_ERROR_FAILURE; } return NS_OK; } return CompileWasmModuleBytes(aCx, aOptions, aRequest, aRequest->WasmBytes(), aModuleOut); } #endif MOZ_ASSERT(!aRequest->IsWasmBytes()); if (aRequest->IsRetrievedFromMemoryCache()) { JS::InstantiateOptions instantiateOptions(aOptions); RefPtr stencil = aRequest->GetStencil(); aModuleOut.set( JS::InstantiateModuleStencil(aCx, instantiateOptions, stencil)); if (!aModuleOut) { return NS_ERROR_FAILURE; } if (!GetScriptLoader()->StartCollectingDelazifications(aCx, aModuleOut, stencil)) { return NS_ERROR_FAILURE; } return NS_OK; } if (aRequest->GetScriptLoadContext()->mWasCompiledOMT) { JS::InstantiationStorage storage; RefPtr stencil = aRequest->GetScriptLoadContext()->StealOffThreadResult(aCx, &storage); if (!stencil) { return NS_ERROR_FAILURE; } aRequest->SetStencil(stencil); JS::InstantiateOptions instantiateOptions(aOptions); aModuleOut.set(JS::InstantiateModuleStencil(aCx, instantiateOptions, stencil, &storage)); if (!aModuleOut) { return NS_ERROR_FAILURE; } if (aRequest->PassedConditionForEitherCache()) { if (!GetScriptLoader()->StartCollectingDelazifications(aCx, aModuleOut, stencil)) { return NS_ERROR_FAILURE; } } GetScriptLoader()->TryCacheRequest(aRequest); return NS_OK; } RefPtr stencil; if (aRequest->IsFetchedAsTextSource()) { MaybeSourceText maybeSource; nsresult rv = aRequest->GetScriptSource(aCx, &maybeSource, aRequest->mLoadContext.get()); NS_ENSURE_SUCCESS(rv, rv); auto compile = [&](auto& source) { return JS::CompileModuleScriptToStencil(aCx, aOptions, source); }; stencil = maybeSource.mapNonEmpty(compile); } else { MOZ_ASSERT(aRequest->IsRetrievedAsSerializedStencil()); JS::DecodeOptions decodeOptions(aOptions); if (!GetScriptLoader()->UsesMemoryCache()) { decodeOptions.borrowBuffer = true; } JS::TranscodeRange range = aRequest->SerializedStencil(); JS::TranscodeResult tr = JS::DecodeStencil(aCx, decodeOptions, range, getter_AddRefs(stencil)); if (tr != JS::TranscodeResult::Ok) { return NS_ERROR_DOM_JS_DECODING_ERROR; } } if (!stencil) { return NS_ERROR_FAILURE; } aRequest->SetStencil(stencil); JS::InstantiateOptions instantiateOptions(aOptions); aModuleOut.set( JS::InstantiateModuleStencil(aCx, instantiateOptions, stencil)); if (!aModuleOut) { return NS_ERROR_FAILURE; } if (aRequest->PassedConditionForEitherCache()) { if (!GetScriptLoader()->StartCollectingDelazifications(aCx, aModuleOut, stencil)) { return NS_ERROR_FAILURE; } } GetScriptLoader()->TryCacheRequest(aRequest); return NS_OK; } nsresult ModuleLoader::CompileJsonModule( JSContext* aCx, JS::CompileOptions& aOptions, ModuleLoadRequest* aRequest, JS::MutableHandle aModuleOut) { MOZ_ASSERT(!aRequest->GetScriptLoadContext()->mWasCompiledOMT); MOZ_ASSERT(aRequest->IsFetchedAsTextSource()); ModuleLoader::MaybeSourceText maybeSource; nsresult rv = aRequest->GetScriptSource(aCx, &maybeSource, aRequest->mLoadContext.get()); NS_ENSURE_SUCCESS(rv, rv); auto compile = [&](auto& source) { return JS::CompileJsonModule(aCx, aOptions, source); }; auto* jsonModule = maybeSource.mapNonEmpty(compile); if (!jsonModule) { return NS_ERROR_FAILURE; } aModuleOut.set(jsonModule); return NS_OK; } nsresult CreateCssModule(JSContext* aCx, nsIGlobalObject* aGlobal, const nsACString& aSource, nsIURI* aBaseURI, JS::MutableHandle aModuleOut) { // https://html.spec.whatwg.org/#creating-a-css-module-script nsCOMPtr window = do_QueryInterface(aGlobal); if (!window) { JS_ReportErrorASCII(aCx, "CSS module scripts not supported when there is no " "window"); return NS_ERROR_FAILURE; } Document* constructorDocument = window->GetExtantDoc(); if (!constructorDocument) { JS_ReportErrorASCII(aCx, "CSS module scripts not supported when there is no " "document"); return NS_ERROR_FAILURE; } // 5. Let sheet be the result of running the steps to create a constructed // CSSStyleSheet with an empty dictionary as the argument. // Note that according to the specification, the baseURL should be the // baseURL of the document, but that doesn't seem correct (see // https://github.com/whatwg/html/issues/11629). ErrorResult error; CSSStyleSheetInit options; RefPtr sheet = StyleSheet::CreateConstructedSheet( *constructorDocument, aBaseURI, options, error); if (error.Failed()) { MOZ_ALWAYS_TRUE(error.MaybeSetPendingException(aCx)); return NS_ERROR_FAILURE; } // 6. Run the steps to synchronously replace the rules of a CSSStyleSheet on // sheet given source. Ideally we wouldn't run this on the main thread for // large scripts, see https://bugzilla.mozilla.org/show_bug.cgi?id=1987143. sheet->ReplaceSync(aSource, error); if (error.Failed()) { MOZ_ALWAYS_TRUE(error.MaybeSetPendingException(aCx)); return NS_ERROR_FAILURE; } JS::Rooted val(aCx, JS::NullValue()); if (!GetOrCreateDOMReflector(aCx, sheet, &val) || !val.isObject()) { if (!JS_IsExceptionPending(aCx)) { JS_ReportErrorASCII(aCx, "Internal error"); } return NS_ERROR_FAILURE; } // Steps 1 - 4 (re-ordered), 7, 8 JSObject* cssModule = JS::CreateDefaultExportSyntheticModule(aCx, val); if (!cssModule) { return NS_ERROR_FAILURE; } aModuleOut.set(cssModule); return NS_OK; } nsresult ModuleLoader::CompileCssModule( JSContext* aCx, JS::CompileOptions& aOptions, ModuleLoadRequest* aRequest, JS::MutableHandle aModuleOut) { MOZ_ASSERT(!aRequest->GetScriptLoadContext()->mWasCompiledOMT); MOZ_ASSERT(mozilla::StaticPrefs::layout_css_module_scripts_enabled()); MOZ_ASSERT(aRequest->IsFetchedAsTextSource()); ModuleLoader::MaybeSourceText maybeSource; nsresult rv = aRequest->GetScriptSource(aCx, &maybeSource, aRequest->mLoadContext.get()); NS_ENSURE_SUCCESS(rv, rv); JS::Rooted cssModule(aCx, nullptr); ErrorResult error; auto compile = [&](auto& source) { using T = decltype(source); static_assert(std::is_same_v&> || std::is_same_v&>); nsCString text; if constexpr (std::is_same_v&>) { text.Assign(source.get(), source.length()); } else { CopyUTF16toUTF8(nsDependentSubstring(source.get(), source.length()), text); } nsresult rv2 = CreateCssModule(aCx, aRequest->GetGlobalObject(), text, aRequest->BaseURL(), &cssModule); if (NS_FAILED(rv2) && !JS_IsExceptionPending(aCx)) { error.ThrowUnknownError("Internal error"); } }; maybeSource.mapNonEmpty(compile); if (!cssModule) { if (error.Failed()) { MOZ_ALWAYS_TRUE(error.MaybeSetPendingException(aCx)); } return NS_ERROR_FAILURE; } aModuleOut.set(cssModule); return NS_OK; } nsresult ModuleLoader::CreateTextModule( JSContext* aCx, JS::CompileOptions& aOptions, ModuleLoadRequest* aRequest, JS::MutableHandle aModuleOut) { MOZ_ASSERT(!aRequest->GetScriptLoadContext()->mWasCompiledOMT); MOZ_ASSERT(aRequest->IsFetchedAsTextSource()); ModuleLoader::MaybeSourceText maybeSource; nsresult rv = aRequest->GetScriptSource(aCx, &maybeSource, aRequest->mLoadContext.get()); NS_ENSURE_SUCCESS(rv, rv); auto compile = [&](auto& source) -> JSObject* { using T = decltype(source); static_assert(std::is_same_v&> || std::is_same_v&>); JSString* str; if constexpr (std::is_same_v&>) { str = JS_NewStringCopyUTF8N(aCx, JS::UTF8Chars(source.get(), source.length())); } else { str = JS_NewUCStringCopyN(aCx, source.get(), source.length()); } if (!str) { return nullptr; } JS::Rooted defaultExport(aCx, JS::StringValue(str)); return JS::CreateDefaultExportSyntheticModule(aCx, defaultExport); }; auto* textModule = maybeSource.mapNonEmpty(compile); if (!textModule) { return NS_ERROR_FAILURE; } aModuleOut.set(textModule); return NS_OK; } already_AddRefed ModuleLoader::CreateTopLevel( nsIURI* aURI, nsIScriptElement* aElement, ReferrerPolicy aReferrerPolicy, ScriptFetchOptions* aFetchOptions, const SRIMetadata& aIntegrity, nsIURI* aReferrer, ScriptLoadContext* aContext, ScriptLoadRequestType aRequestType) { RefPtr request = new ModuleLoadRequest( JS::ModuleType::JavaScript, aIntegrity, aReferrer, aContext, ModuleLoadRequest::Kind::TopLevel, this, nullptr); GetScriptLoader()->TryUseCache(aReferrerPolicy, aFetchOptions, aURI, request, aElement, aFetchOptions->mNonce, aRequestType); return request.forget(); } already_AddRefed ModuleLoader::CreateRequest( JSContext* aCx, nsIURI* aURI, JS::Handle aModuleRequest, JS::Handle aHostDefined, JS::Handle aPayload, bool aIsDynamicImport, ScriptFetchOptions* aOptions, ReferrerPolicy aReferrerPolicy, nsIURI* aBaseURL, const SRIMetadata& aSriMetadata) { RefPtr context = new ScriptLoadContext(); context->mIsInline = false; ModuleLoadRequest::Kind kind; ModuleLoadRequest* root = nullptr; if (aIsDynamicImport) { context->mScriptMode = ScriptLoadContext::ScriptMode::eAsync; kind = ModuleLoadRequest::Kind::DynamicImport; } else { MOZ_ASSERT(!aHostDefined.isUndefined()); root = static_cast(aHostDefined.toPrivate()); MOZ_ASSERT(root); LoadContextBase* loadContext = root->mLoadContext; context->mScriptMode = loadContext->AsWindowContext()->mScriptMode; if (loadContext->AsWindowContext()->mIsPreload) { context->mIsPreload = true; } kind = ModuleLoadRequest::Kind::StaticImport; } JS::ModuleType moduleType = GetModuleRequestType(aCx, aModuleRequest); RefPtr request = new ModuleLoadRequest( moduleType, aSriMetadata, aBaseURL, context, kind, this, root); GetScriptLoader()->TryUseCache(aReferrerPolicy, aOptions, aURI, request); return request.forget(); } already_AddRefed ModuleLoader::CreateDefaultScriptFetchOptions() { RefPtr options = ScriptFetchOptions::CreateDefault(); nsCOMPtr principal = GetGlobalObject()->PrincipalOrNull(); options->SetTriggeringPrincipal(principal); return options.forget(); } nsIURI* ModuleLoader::GetClientReferrerURI() { Document* document = GetScriptLoader()->GetDocument(); #ifdef DEBUG nsCOMPtr principal = GetGlobalObject()->PrincipalOrNull(); #endif // DEBUG MOZ_ASSERT_IF(GetKind() == WebExtension, BasePrincipal::Cast(principal)->ContentScriptAddonPolicy()); MOZ_ASSERT_IF(GetKind() == Normal, principal == document->NodePrincipal()); return document->GetDocBaseURI(); } ModuleLoader::~ModuleLoader() { LOG(("ModuleLoader::~ModuleLoader %p", this)); mLoader = nullptr; } #undef LOG #undef LOG_ENABLED } // namespace mozilla::dom