/* -*- 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/. */
// Alternate Data MIME type used by the ScriptLoader to register that we want to // store bytecode without reading it. static constexpr auto kNullMimeType = "javascript/null"_ns;
// Unblock the kids, in case any of them moved to a different document // subtree in the meantime and therefore aren't actually going away. for (uint32_t j = 0; j < mPendingChildLoaders.Length(); ++j) {
mPendingChildLoaders[j]->RemoveParserBlockingScriptExecutionBlocker();
}
if (mShutdownObserver) {
mShutdownObserver->Unregister();
mShutdownObserver = nullptr;
}
mModuleLoader = nullptr;
if (mProcessPendingRequestsAsyncBypassParserBlocking) {
mProcessPendingRequestsAsyncBypassParserBlocking->Cancel();
}
}
void ScriptLoader::SetGlobalObject(nsIGlobalObject* aGlobalObject) { if (!aGlobalObject) { // The document is being detached.
CancelAndClearScriptLoadRequests(); return;
}
MOZ_ASSERT(!HasPendingRequests());
if (!mModuleLoader) { // The module loader is associated with a global object, so don't create it // until we have a global set.
mModuleLoader = new ModuleLoader(this, aGlobalObject, ModuleLoader::Normal);
}
// Collect telemtry data about the cache information, and the kind of source // which are being loaded, and where it is being loaded from. staticvoid CollectScriptTelemetry(ScriptLoadRequest* aRequest) { usingnamespace mozilla::Telemetry;
MOZ_ASSERT(aRequest->IsFetching());
// Skip this function if we are not running telemetry. if (!CanRecordExtended()) { return;
}
// Report the type of source. This is used to monitor the status of the // JavaScript Start-up Bytecode Cache, with the expectation of an almost zero // source-fallback and alternate-data being roughtly equal to source loads. if (aRequest->mFetchSourceOnly) { if (aRequest->GetScriptLoadContext()->mIsInline) {
AccumulateCategorical(LABELS_DOM_SCRIPT_LOADING_SOURCE::Inline);
} elseif (aRequest->IsTextSource()) {
AccumulateCategorical(LABELS_DOM_SCRIPT_LOADING_SOURCE::SourceFallback);
}
} else { if (aRequest->IsTextSource()) {
AccumulateCategorical(LABELS_DOM_SCRIPT_LOADING_SOURCE::Source);
} elseif (aRequest->IsBytecode()) {
AccumulateCategorical(LABELS_DOM_SCRIPT_LOADING_SOURCE::AltData);
}
}
}
// Helper method for checking if the script element is an event-handler // This means that it has both a for-attribute and a event-attribute. // Also, if the for-attribute has a value that matches "\s*window\s*", // and the event-attribute matches "\s*onload([ \(].*)?" then it isn't an // eventhandler. (both matches are case insensitive). // This is how IE seems to filter out a window's onload handler from a // <script for=... event=...> element.
const nsAString& for_str =
nsContentUtils::TrimWhitespace<nsCRT::IsAsciiSpace>(forAttr); if (!for_str.LowerCaseEqualsLiteral("window")) { returntrue;
}
// We found for="window", now check for event="onload". const nsAString& event_str =
nsContentUtils::TrimWhitespace<nsCRT::IsAsciiSpace>(eventAttr, false); if (!StringBeginsWith(event_str, u"onload"_ns,
nsCaseInsensitiveStringComparator)) { // It ain't "onload.*".
nsCOMPtr<nsINode> requestingNode = do_QueryInterface(aElement);
nsCOMPtr<nsILoadInfo> secCheckLoadInfo = new net::LoadInfo(
aDocument->NodePrincipal(), // loading principal
aDocument->NodePrincipal(), // triggering principal
requestingNode, nsILoadInfo::SEC_ONLY_FOR_EXPLICIT_CONTENTSEC_CHECK,
contentPolicyType);
secCheckLoadInfo->SetParserCreatedScript(aElement->GetParserCreated() !=
mozilla::dom::NOT_FROM_PARSER); // Use nonce of the current element, instead of the preload, because those // are allowed to differ.
secCheckLoadInfo->SetCspNonce(aNonce); if (aRequest->mIntegrity.IsValid()) {
MOZ_ASSERT(!aRequest->mIntegrity.IsEmpty());
secCheckLoadInfo->SetIntegrityMetadata(
aRequest->mIntegrity.GetIntegrityString());
}
/* static */ bool ScriptLoader::IsAboutPageLoadingChromeURI(ScriptLoadRequest* aRequest,
Document* aDocument) { // if the uri to be loaded is not of scheme chrome:, there is nothing to do. if (!aRequest->mURI->SchemeIs("chrome")) { returnfalse;
}
// we can either get here with a regular contentPrincipal or with a // NullPrincipal in case we are showing an error page in a sandboxed iframe. // In either case if the about: page is linkable from content, there is // nothing to do.
uint32_t aboutModuleFlags = 0;
nsresult rv = NS_OK;
nsCOMPtr<nsIPrincipal> triggeringPrincipal = aRequest->TriggeringPrincipal(); if (triggeringPrincipal->GetIsContentPrincipal()) { if (!triggeringPrincipal->SchemeIs("about")) { returnfalse;
}
rv = triggeringPrincipal->GetAboutModuleFlags(&aboutModuleFlags);
NS_ENSURE_SUCCESS(rv, false);
} elseif (triggeringPrincipal->GetIsNullPrincipal()) {
nsCOMPtr<nsIURI> docURI = aDocument->GetDocumentURI(); if (!docURI->SchemeIs("about")) { returnfalse;
}
// Notify preload restart so that we can register this preload request again.
aRequest->GetScriptLoadContext()->NotifyRestart(mDocument);
// Start a new channel from which we explicitly request to stream the source // instead of the bytecode.
aRequest->mFetchSourceOnly = true;
nsresult rv; if (aRequest->IsModuleRequest()) {
rv = aRequest->AsModuleRequest()->RestartModuleLoad();
} else {
rv = StartLoad(aRequest, Nothing());
} if (NS_FAILED(rv)) { return rv;
}
// Close the current channel and this ScriptLoadHandler as we created a new // one for the same request. return NS_BINDING_RETARGETED;
}
// static void ScriptLoader::PrepareCacheInfoChannel(nsIChannel* aChannel,
ScriptLoadRequest* aRequest) { // To avoid decoding issues, the build-id is part of the bytecode MIME type // constant.
aRequest->mCacheInfo = nullptr;
nsCOMPtr<nsICacheInfoChannel> cic(do_QueryInterface(aChannel)); if (cic && StaticPrefs::dom_script_loader_bytecode_cache_enabled()) {
MOZ_ASSERT(!IsWebExtensionRequest(aRequest), "Can not bytecode cache WebExt code"); if (!aRequest->mFetchSourceOnly) { // Inform the HTTP cache that we prefer to have information coming from // the bytecode cache instead of the sources, if such entry is already // registered.
LOG(("ScriptLoadRequest (%p): Maybe request bytecode", aRequest));
cic->PreferAlternativeDataType(
ScriptLoader::BytecodeMimeTypeFor(aRequest), ""_ns,
nsICacheInfoChannel::PreferredAlternativeDataDeliveryType::ASYNC);
} else { // If we are explicitly loading from the sources, such as after a // restarted request, we might still want to save the bytecode after. // // The following tell the cache to look for an alternative data type which // does not exist, such that we can later save the bytecode with a // different alternative data type.
LOG(("ScriptLoadRequest (%p): Request saving bytecode later", aRequest));
cic->PreferAlternativeDataType(
kNullMimeType, ""_ns,
nsICacheInfoChannel::PreferredAlternativeDataDeliveryType::ASYNC);
}
}
}
// Put it to the group that is not blocked by leaders and doesn't block // follower at the same time. // Giving it a much higher priority will make this request be processed // ahead of other Unblocked requests, but with the same weight as // Leaders. This will make us behave similar way for both http2 and http1.
ScriptLoadContext::PrioritizeAsPreload(aChannel);
if (!StaticPrefs::network_fetchpriority_enabled()) { return;
}
// The spec defines the priority to be set in an implementation defined // manner (<https://fetch.spec.whatwg.org/#concept-fetch>, step 15 and // <https://html.spec.whatwg.org/#concept-script-fetch-options-fetch-priority>). // See corresponding preferences in StaticPrefList.yaml for more context. const int32_t supportsPriorityDelta =
FETCH_PRIORITY_ADJUSTMENT_FOR(link_preload_script, fetchPriority);
supportsPriority->AdjustPriority(supportsPriorityDelta); #ifdef DEBUG
int32_t adjustedPriority;
supportsPriority->GetPriority(&adjustedPriority);
LogPriorityMapping(ScriptLoader::gScriptLoaderLog, fetchPriority,
adjustedPriority); #endif
}
if (nsCOMPtr<nsIClassOfService> cos = do_QueryInterface(aChannel)) {
cos->SetFetchPriorityDOM(fetchPriority);
}
}
if (!StaticPrefs::network_fetchpriority_enabled()) { return;
}
constauto fetchPriority = ToFetchPriority(aRequest->FetchPriority()); if (nsCOMPtr<nsISupportsPriority> supportsPriority =
do_QueryInterface(aChannel)) {
LOG(("Is not ));
// The spec defines the priority to be set in an implementation defined // manner (<https://fetch.spec.whatwg.org/#concept-fetch>, step 15 and // <https://html.spec.whatwg.org/#concept-script-fetch-options-fetch-priority>). // See corresponding preferences in StaticPrefList.yaml for more context. const int32_t supportsPriorityDelta = [&]() { const ScriptLoadContext* scriptLoadContext =
aRequest->GetScriptLoadContext(); if (aRequest->IsModuleRequest()) { return FETCH_PRIORITY_ADJUSTMENT_FOR(module_script, fetchPriority);
}
if (scriptLoadContext->IsAsyncScript() ||
scriptLoadContext->IsDeferredScript()) { return FETCH_PRIORITY_ADJUSTMENT_FOR(async_or_defer_script,
fetchPriority);
}
if (scriptLoadContext->mScriptFromHead) { return FETCH_PRIORITY_ADJUSTMENT_FOR(script_in_head, fetchPriority);
}
if (supportsPriorityDelta) {
supportsPriority->AdjustPriority(supportsPriorityDelta); #ifdef DEBUG
int32_t adjustedPriority;
supportsPriority->GetPriority(&adjustedPriority);
LogPriorityMapping(ScriptLoader::gScriptLoaderLog, fetchPriority,
adjustedPriority); #endif
}
} if (nsCOMPtr<nsIClassOfService> cos = do_QueryInterface(aChannel)) {
cos->SetFetchPriorityDOM(fetchPriority);
}
}
// static void ScriptLoader::PrepareRequestPriorityAndRequestDependencies(
nsIChannel* aChannel, ScriptLoadRequest* aRequest) { if (aRequest->GetScriptLoadContext()->IsLinkPreloadScript()) { // This is <link rel="preload" as="script"> or <link rel="modulepreload"> // initiated speculative load // (https://developer.mozilla.org/en-US/docs/Web/Performance/Speculative_loading).
AdjustPriorityAndClassOfServiceForLinkPreloadScripts(aChannel, aRequest);
ScriptLoadContext::AddLoadBackgroundFlag(aChannel);
} elseif (nsCOMPtr<nsIClassOfService> cos = do_QueryInterface(aChannel)) {
AdjustPriorityForNonLinkPreloadScripts(aChannel, aRequest);
if (aRequest->GetScriptLoadContext()->mScriptFromHead &&
aRequest->GetScriptLoadContext()->IsBlockingScript()) { // synchronous head scripts block loading of most other non js/css // content such as images, Leader implicitely disallows tailing
cos->AddClassFlags(nsIClassOfService::Leader);
} elseif (aRequest->GetScriptLoadContext()->IsDeferredScript() &&
!StaticPrefs::network_http_tailing_enabled()) { // Bug 1395525 and the !StaticPrefs::network_http_tailing_enabled() bit: // We want to make sure that turing tailing off by the pref makes the // browser behave exactly the same way as before landing the tailing // patch.
// head/body deferred scripts are blocked by leaders but are not // allowed tailing because they block DOMContentLoaded
cos->AddClassFlags(nsIClassOfService::TailForbidden);
} else { // other scripts (=body sync or head/body async) are neither blocked // nor prioritized
cos->AddClassFlags(nsIClassOfService::Unblocked);
if (aRequest->GetScriptLoadContext()->IsAsyncScript()) { // async scripts are allowed tailing, since those and only those // don't block DOMContentLoaded; this flag doesn't enforce tailing, // just overweights the Unblocked flag when the channel is found // to be a thrird-party tracker and thus set the Tail flag to engage // tailing.
cos->AddClassFlags(nsIClassOfService::TailAllowed);
}
}
}
}
if (httpChannel) { // HTTP content negotation has little value in this context.
nsAutoCString acceptTypes("*/*");
rv = httpChannel->SetRequestHeader("Accept"_ns, acceptTypes, false);
MOZ_ASSERT(NS_SUCCEEDED(rv));
nsCOMPtr<nsIReferrerInfo> referrerInfo = new ReferrerInfo(aRequest->mReferrer, aRequest->ReferrerPolicy());
rv = httpChannel->SetReferrerInfoWithoutClone(referrerInfo);
MOZ_ASSERT(NS_SUCCEEDED(rv));
// Set the initiator type
nsCOMPtr<nsITimedChannel> timedChannel(do_QueryInterface(httpChannel)); if (timedChannel) {
timedChannel->SetInitiatorType(GetInitiatorType(aRequest));
}
if (NS_FAILED(rv)) { // Make sure to inform any <link preload> tags about failure to load the // resource.
aRequest->GetScriptLoadContext()->NotifyStart(channel);
aRequest->GetScriptLoadContext()->NotifyStop(rv);
}
// Step 13. Check that the script is not an eventhandler if (IsScriptEventHandler(scriptKind, scriptContent)) { returnfalse;
}
// "In modern user agents that support module scripts, the script element with // the nomodule attribute will be ignored". // "The nomodule attribute must not be specified on module scripts (and will // be ignored if it is)." if (scriptKind == ScriptKind::eClassic && scriptContent->IsHTMLElement() &&
scriptContent->AsElement()->HasAttr(nsGkAtoms::nomodule)) { returnfalse;
}
// Step 15. and later in the HTML5 spec if (aElement->GetScriptExternal()) { return ProcessExternalScript(aElement, scriptKind, scriptContent);
}
bool ScriptLoader::ProcessExternalScript(nsIScriptElement* aElement,
ScriptKind aScriptKind,
nsIContent* aScriptContent) {
LOG(("ScriptLoader (%p): Process external script for element %p", this,
aElement));
// https://html.spec.whatwg.org/multipage/scripting.html#prepare-the-script-element // Step 30.1. If el's type is "importmap", then queue an element task on the // DOM manipulation task source given el to fire an event named error at el, // and return. if (aScriptKind == ScriptKind::eImportMap) {
NS_DispatchToCurrentThread(
NewRunnableMethod("nsIScriptElement::FireErrorEvent", aElement,
&nsIScriptElement::FireErrorEvent));
nsContentUtils::ReportToConsole(
nsIScriptError::warningFlag, "Script Loader"_ns, mDocument,
nsContentUtils::eDOM_PROPERTIES, "ImportMapExternalNotSupported"); returnfalse;
}
nsCOMPtr<nsIURI> scriptURI = aElement->GetScriptURI(); if (!scriptURI) { // Asynchronously report the failure to create a URI object
NS_DispatchToCurrentThread(
NewRunnableMethod("nsIScriptElement::FireErrorEvent", aElement,
&nsIScriptElement::FireErrorEvent)); returnfalse;
}
RefPtr<ScriptLoadRequest> request =
LookupPreloadRequest(aElement, aScriptKind, sriMetadata); if (request) { if (NS_FAILED(CheckContentPolicy(mDocument, aElement, nonce, request))) {
LOG(("ScriptLoader (%p): content policy check failed for preload", this));
// Probably plans have changed; even though the preload was allowed seems // like the actual load is not; let's cancel the preload request.
request->Cancel(); returnfalse;
}
// Use the preload request.
LOG(("ScriptLoadRequest (%p): Using preload request", request.get()));
// It's possible these attributes changed since we started the preload so // update them here.
request->GetScriptLoadContext()->SetScriptMode(
aElement->GetScriptDeferred(), aElement->GetScriptAsync(), false);
// The request will be added to another list or set as // mParserBlockingRequest below. if (request->GetScriptLoadContext()->mInCompilingList) {
mOffThreadCompilingRequests.Remove(request);
request->GetScriptLoadContext()->mInCompilingList = false;
}
} else { // No usable preload found.
nsCOMPtr<nsIPrincipal> principal =
aElement->GetScriptURITriggeringPrincipal(); if (!principal) {
principal = aScriptContent->NodePrincipal();
}
// We should still be in loading stage of script unless we're loading a // module or speculatively off-main-thread parsing a script.
NS_ASSERTION(SpeculativeOMTParsingEnabled() ||
!request->GetScriptLoadContext()->CompileStarted() ||
request->IsModuleRequest(), "Request should not yet be in compiling stage.");
if (request->GetScriptLoadContext()->IsAsyncScript()) {
AddAsyncRequest(request); if (request->IsFinished()) { // The script is available already. Run it ASAP when the event // loop gets a chance to spin.
// KVKV TODO: Instead of processing immediately, try off-thread-parsing // it and only schedule a pending ProcessRequest if that fails.
ProcessPendingRequestsAsync();
} returnfalse;
} if (!aElement->GetParserCreated()) { // Violate the HTML5 spec in order to make LABjs and the "order" plug-in // for RequireJS work with their Gecko-sniffed code path. See // http://lists.w3.org/Archives/Public/public-html/2010Oct/0088.html
request->GetScriptLoadContext()->mIsNonAsyncScriptInserted = true;
mNonAsyncExternalScriptInsertedRequests.AppendElement(request); if (request->IsFinished()) { // The script is available already. Run it ASAP when the event // loop gets a chance to spin.
ProcessPendingRequestsAsync();
} returnfalse;
} // we now have a parser-inserted request that may or may not be still // loading if (request->GetScriptLoadContext()->IsDeferredScript()) { // We don't want to run this yet. // If we come here, the script is a parser-created script and it has // the defer attribute but not the async attribute OR it is a module // script without the async attribute. Since a // a parser-inserted script is being run, we came here by the parser // running the script, which means the parser is still alive and the // parse is ongoing.
NS_ASSERTION(mDocument->GetCurrentContentSink() ||
aElement->GetParserCreated() == FROM_PARSER_XSLT, "Non-XSLT Defer script on a document without an active " "parser; bug 592366.");
AddDeferRequest(request); returnfalse;
}
if (aElement->GetParserCreated() == FROM_PARSER_XSLT) { // Need to maintain order for XSLT-inserted scripts
NS_ASSERTION(!mParserBlockingRequest, "Parser-blocking scripts and XSLT scripts in the same doc!");
request->GetScriptLoadContext()->mIsXSLT = true;
mXSLTRequests.AppendElement(request); if (request->IsFinished()) { // The script is available already. Run it ASAP when the event // loop gets a chance to spin.
ProcessPendingRequestsAsync();
} returntrue;
}
if (request->IsFinished() && ReadyToExecuteParserBlockingScripts()) { // The request has already been loaded and there are no pending style // sheets. If the script comes from the network stream, cheat for // performance reasons and avoid a trip through the event loop. if (aElement->GetParserCreated() == FROM_PARSER_NETWORK) { return ProcessRequest(request) == NS_ERROR_HTMLPARSER_BLOCK;
} // Otherwise, we've got a document.written script, make a trip through // the event loop to hide the preload effects from the scripts on the // Web page.
NS_ASSERTION(!mParserBlockingRequest, "There can be only one parser-blocking script at a time");
NS_ASSERTION(mXSLTRequests.isEmpty(), "Parser-blocking scripts and XSLT scripts in the same doc!");
mParserBlockingRequest = request;
ProcessPendingRequestsAsync(); returntrue;
}
// The script hasn't loaded yet or there's a style sheet blocking it. // The script will be run when it loads or the style sheet loads.
NS_ASSERTION(!mParserBlockingRequest, "There can be only one parser-blocking script at a time");
NS_ASSERTION(mXSLTRequests.isEmpty(), "Parser-blocking scripts and XSLT scripts in the same doc!");
mParserBlockingRequest = request; returntrue;
}
bool ScriptLoader::ProcessInlineScript(nsIScriptElement* aElement,
ScriptKind aScriptKind) { // Is this document sandboxed without 'allow-scripts'? if (mDocument->HasScriptsBlockedBySandbox()) { returnfalse;
}
nsCOMPtr<Element> element = do_QueryInterface(aElement);
nsString nonce = nsContentSecurityUtils::GetIsElementNonceableNonce(*element);
// Does CSP allow this inline script to run? if (!CSPAllowsInlineScript(aElement, nonce, mDocument)) { returnfalse;
}
// Check if adding an import map script is allowed. If not, we bail out // early to prevent creating a load request. if (aScriptKind == ScriptKind::eImportMap) { // https://html.spec.whatwg.org/multipage/scripting.html#prepare-the-script-element // Step 31.2 type is "importmap": // Step 1. If el's relevant global object's import maps allowed is false, // then queue an element task on the DOM manipulation task source given el // to fire an event named error at el, and return. if (!mModuleLoader->IsImportMapAllowed()) {
NS_WARNING("ScriptLoader: import maps allowed is false."); constchar* msg = mModuleLoader->HasImportMapRegistered()
? "ImportMapNotAllowedMultiple"
: "ImportMapNotAllowedAfterModuleLoad";
nsContentUtils::ReportToConsole(nsIScriptError::warningFlag, "Script Loader"_ns, mDocument,
nsContentUtils::eDOM_PROPERTIES, msg);
NS_DispatchToCurrentThread(
NewRunnableMethod("nsIScriptElement::FireErrorEvent", aElement,
&nsIScriptElement::FireErrorEvent)); returnfalse;
}
}
// Inline classic scripts ignore their CORS mode and are always CORS_NONE.
CORSMode corsMode = CORS_NONE; if (aScriptKind == ScriptKind::eModule) {
corsMode = aElement->GetCORSMode();
} // <https://html.spec.whatwg.org/multipage/scripting.html#prepare-the-script-element> // step 29 specifies to use the fetch priority. Presumably it has no effect // for inline scripts. constauto fetchPriority = aElement->GetFetchPriority();
// NOTE: The `nonce` as specified here is significant, because it's inherited // by other scripts (e.g. modules created via dynamic imports).
RefPtr<ScriptLoadRequest> request =
CreateLoadRequest(aScriptKind, mDocument->GetDocumentURI(), aElement,
mDocument->NodePrincipal(), corsMode, nonce,
FetchPriorityToRequestPriority(fetchPriority),
SRIMetadata(), // SRI doesn't apply
referrerPolicy, parserMetadata, RequestType::Inline);
request->GetScriptLoadContext()->mIsInline = true;
request->GetScriptLoadContext()->mLineNo = aElement->GetScriptLineNumber();
request->GetScriptLoadContext()->mColumnNo =
aElement->GetScriptColumnNumber();
request->mFetchSourceOnly = true;
request->SetTextSource(request->mLoadContext.get());
TRACE_FOR_TEST_BOOL(request, "scriptloader_load_source");
CollectScriptTelemetry(request);
// Only the 'async' attribute is heeded on an inline module script and // inline classic scripts ignore both these attributes.
MOZ_ASSERT(!aElement->GetScriptDeferred());
MOZ_ASSERT_IF(!request->IsModuleRequest(), !aElement->GetScriptAsync());
request->GetScriptLoadContext()->SetScriptMode( false, aElement->GetScriptAsync(), false);
LOG(("ScriptLoadRequest (%p): Created request for inline script",
request.get()));
ModuleLoadRequest* modReq = request->AsModuleRequest(); if (aElement->GetParserCreated() != NOT_FROM_PARSER) { if (aElement->GetScriptAsync()) {
AddAsyncRequest(modReq);
} else {
AddDeferRequest(modReq);
}
}
// This calls OnFetchComplete directly since there's no need to start // fetching an inline script.
nsresult rv = modReq->OnFetchComplete(NS_OK); if (NS_FAILED(rv)) {
ReportErrorToConsole(modReq, rv);
HandleLoadError(modReq, rv);
}
// Step 2. Set el's relevant global object's import maps allowed to false.
mModuleLoader->DisallowImportMaps();
// Step 3. Let result be the result of creating an import map parse result // given source text and base URL.
UniquePtr<ImportMap> importMap = mModuleLoader->ParseImportMap(request); if (!importMap) { // If parsing import maps fails, the exception will be reported in // ModuleLoaderBase::ParseImportMap, and the registration of the import // map will bail out early. returnfalse;
}
// Remove any module preloads. Module specifier resolution is invalidated by // adding an import map, and incorrect dependencies may have been loaded.
mPreloads.RemoveElementsBy([](const PreloadInfo& info) { if (info.mRequest->IsModuleRequest()) {
info.mRequest->Cancel(); returntrue;
} returnfalse;
});
// TODO: Bug 1781758: Move RegisterImportMap into EvaluateScriptElement. // // https://html.spec.whatwg.org/multipage/scripting.html#execute-the-script-element // The spec defines 'register an import map' should be done in // 'execute the script element', because inside 'execute the script element' // it will perform a 'preparation-time document check'. // However, as import maps could be only inline scripts by now, the // 'preparation-time document check' will never fail for import maps. // So we simply call 'register an import map' here.
mModuleLoader->RegisterImportMap(std::move(importMap)); returnfalse;
}
request->mState = ScriptLoadRequest::State::Ready; if (aElement->GetParserCreated() == FROM_PARSER_XSLT &&
(!ReadyToExecuteParserBlockingScripts() || !mXSLTRequests.isEmpty())) { // Need to maintain order for XSLT-inserted scripts
NS_ASSERTION(!mParserBlockingRequest, "Parser-blocking scripts and XSLT scripts in the same doc!");
mXSLTRequests.AppendElement(request); returntrue;
} if (aElement->GetParserCreated() == NOT_FROM_PARSER) {
NS_ASSERTION(
!nsContentUtils::IsSafeToRunScript(), "A script-inserted script is inserted without an update batch?");
RunScriptWhenSafe(request); returnfalse;
} if (aElement->GetParserCreated() == FROM_PARSER_NETWORK &&
!ReadyToExecuteParserBlockingScripts()) {
NS_ASSERTION(!mParserBlockingRequest, "There can be only one parser-blocking script at a time");
mParserBlockingRequest = request;
NS_ASSERTION(mXSLTRequests.isEmpty(), "Parser-blocking scripts and XSLT scripts in the same doc!"); returntrue;
} // We now have a document.written inline script or we have an inline script // from the network but there is no style sheet that is blocking scripts. // Don't check for style sheets blocking scripts in the document.write // case to avoid style sheet network activity affecting when // document.write returns. It's not really necessary to do this if // there's no document.write currently on the call stack. However, // this way matches IE more closely than checking if document.write // is on the call stack.
NS_ASSERTION(nsContentUtils::IsSafeToRunScript(), "Not safe to run a parser-inserted script?"); return ProcessRequest(request) == NS_ERROR_HTMLPARSER_BLOCK;
}
// Double-check that the charset the preload used is the same as the charset // we have now.
nsAutoString elementCharset;
aElement->GetScriptCharset(elementCharset);
// Bug 1832361: charset and crossorigin attributes shouldn't affect matching // of module scripts and modulepreload if (!request->IsModuleRequest() &&
(!elementCharset.Equals(preloadCharset) ||
aElement->GetCORSMode() != request->CORSMode())) { // Drop the preload.
request->Cancel(); return nullptr;
}
if (!aSRIMetadata.CanTrustBeDelegatedTo(request->mIntegrity)) { // Don't cancel link preload requests, we want to deliver onload according // the result of the load, cancellation would unexpectedly lead to error // notification. if (!request->GetScriptLoadContext()->IsLinkPreloadScript()) {
request->Cancel();
} return nullptr;
}
// Report any errors that we skipped while preloading.
ReportPreloadErrorsToConsole(request);
// This makes sure the pending preload (if exists) for this resource is // properly marked as used and thus not notified in the console as unused.
request->GetScriptLoadContext()->NotifyUsage(mDocument); // A used preload must no longer be found in the Document's hash table. Any // <link preload> tag after the <script> tag will start a new request, that // can be satisfied from a different cache, but not from the preload cache.
request->GetScriptLoadContext()->RemoveSelf(mDocument);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.