Backed out changeset b288a387f790 (bug 1425310) for causing Reflection related failures. CLOSED TREE

This commit is contained in:
Cristina Horotan 2023-04-21 18:37:11 +03:00
parent 69e2647814
commit 82a7ee4839
21 changed files with 130 additions and 408 deletions

View file

@ -311,30 +311,36 @@ void HTMLLinkElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName,
aNameSpaceID, aName, aValue, aOldValue, aSubjectPrincipal, aNotify);
}
// Keep this and the arrays below in sync with ToLinkMask in LinkStyle.cpp.
#define SUPPORTED_REL_VALUES_BASE \
"prefetch", "dns-prefetch", "stylesheet", "next", "alternate", "preconnect", \
"icon", "search", nullptr
static const DOMTokenListSupportedToken sSupportedRelValues[] = {
// Keep this and the one below in sync with ToLinkMask in
// LinkStyle.cpp.
// "preload" must come first because it can be disabled.
"preload", "prefetch", "dns-prefetch", "stylesheet",
"next", "alternate", "preconnect", "icon",
"search", "modulepreload", nullptr};
static const DOMTokenListSupportedToken sSupportedRelValueCombinations[][12] = {
{SUPPORTED_REL_VALUES_BASE},
{"manifest", SUPPORTED_REL_VALUES_BASE},
{"preload", SUPPORTED_REL_VALUES_BASE},
{"preload", "manifest", SUPPORTED_REL_VALUES_BASE},
{"modulepreload", SUPPORTED_REL_VALUES_BASE},
{"modulepreload", "manifest", SUPPORTED_REL_VALUES_BASE},
{"modulepreload", "preload", SUPPORTED_REL_VALUES_BASE},
{"modulepreload", "preload", "manifest", SUPPORTED_REL_VALUES_BASE}};
#undef SUPPORTED_REL_VALUES_BASE
static const DOMTokenListSupportedToken sSupportedRelValuesWithManifest[] = {
// Keep this in sync with ToLinkMask in LinkStyle.cpp.
// "preload" and "manifest" must come first because they can be disabled.
"preload", "manifest", "prefetch", "dns-prefetch", "stylesheet", "next",
"alternate", "preconnect", "icon", "search", nullptr};
nsDOMTokenList* HTMLLinkElement::RelList() {
if (!mRelList) {
int index = (StaticPrefs::dom_manifest_enabled() ? 1 : 0) |
(StaticPrefs::network_preload() ? 2 : 0) |
(StaticPrefs::network_modulepreload() ? 4 : 0);
mRelList = new nsDOMTokenList(this, nsGkAtoms::rel,
sSupportedRelValueCombinations[index]);
auto preload = StaticPrefs::network_preload();
auto manifest = StaticPrefs::dom_manifest_enabled();
if (manifest && preload) {
mRelList = new nsDOMTokenList(this, nsGkAtoms::rel,
sSupportedRelValuesWithManifest);
} else if (manifest && !preload) {
mRelList = new nsDOMTokenList(this, nsGkAtoms::rel,
&sSupportedRelValuesWithManifest[1]);
} else if (!manifest && preload) {
mRelList = new nsDOMTokenList(this, nsGkAtoms::rel, sSupportedRelValues);
} else { // both false...drop preload
mRelList =
new nsDOMTokenList(this, nsGkAtoms::rel, &sSupportedRelValues[1]);
}
}
return mRelList;
}
@ -484,10 +490,7 @@ void HTMLLinkElement::
}
if (linkTypes & eMODULE_PRELOAD) {
ScriptLoader* scriptLoader = OwnerDoc()->ScriptLoader();
ModuleLoader* moduleLoader = scriptLoader->GetModuleLoader();
if (!moduleLoader) {
if (!OwnerDoc()->ScriptLoader()->GetModuleLoader()) {
// For the print preview documents, at this moment it doesn't have module
// loader yet, as the (print preview) document is not attached to the
// nsIContentViewer yet, so it doesn't have the GlobalObject.
@ -497,52 +500,9 @@ void HTMLLinkElement::
return;
}
if (!StaticPrefs::network_modulepreload()) {
// Keep behavior from https://phabricator.services.mozilla.com/D149371,
// prior to main implementation of modulepreload
moduleLoader->DisallowImportMaps();
return;
}
// https://html.spec.whatwg.org/multipage/semantics.html#processing-the-media-attribute
// TODO: apply this check for all linkTypes
nsAutoString media;
if (GetAttr(nsGkAtoms::media, media)) {
RefPtr<mozilla::dom::MediaList> mediaList =
mozilla::dom::MediaList::Create(NS_ConvertUTF16toUTF8(media));
if (!mediaList->Matches(*OwnerDoc())) {
return;
}
}
// TODO: per spec, apply this check for ePREFETCH as well
if (!HasNonEmptyAttr(nsGkAtoms::href)) {
return;
}
nsAutoString as;
GetAttr(nsGkAtoms::as, as);
nsAttrValue asAttr;
net::ParseAsValue(as, asAttr);
if (!net::IsScriptLikeOrInvalid(asAttr)) {
RefPtr<AsyncEventDispatcher> asyncDispatcher = new AsyncEventDispatcher(
this, u"error"_ns, CanBubble::eNo, ChromeOnlyDispatch::eNo);
asyncDispatcher->PostDOMEvent();
return;
}
nsCOMPtr<nsIURI> uri = GetURI();
if (!uri) {
return;
}
// https://html.spec.whatwg.org/multipage/webappapis.html#fetch-a-modulepreload-module-script-graph
// Step 1. Disallow further import maps given settings object.
moduleLoader->DisallowImportMaps();
StartPreload(nsIContentPolicy::TYPE_SCRIPT);
OwnerDoc()->ScriptLoader()->GetModuleLoader()->DisallowImportMaps();
return;
}

View file

@ -62,10 +62,9 @@ class Element;
* the script does not need to be fetched first.
* * mIsXSLT
* Set if we are in an XSLT request.
* * mIsPreload
* * TODO: mIsPreload (will be moved from ScriptFetchOptions)
* Set for scripts that are preloaded in a
* <link rel="preload" as="script"> or <link rel="modulepreload">
* element.
* <link rel="preload" as="script"> element.
*
* In addition to describing how the ScriptLoadRequest will be loaded by the
* DOM ScriptLoader, the ScriptLoadContext contains fields that facilitate
@ -114,7 +113,7 @@ class ScriptLoadContext : public JS::loader::LoadContextBase,
eDeferred,
eAsync,
eLinkPreload // this is a load initiated by <link rel="preload"
// as="script"> or <link rel="modulepreload"> tag
// as="script"> tag
};
void SetScriptMode(bool aDeferAttr, bool aAsyncAttr, bool aLinkPreload);

View file

@ -675,12 +675,12 @@ nsresult ScriptLoader::StartLoadInternal(
aRequest->GetScriptLoadContext()->IsTracking()));
if (aRequest->GetScriptLoadContext()->IsLinkPreloadScript()) {
// This is <link rel="preload" as="script"> or <link rel="modulepreload">
// initiated speculative load, 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.
// This is <link rel="preload" as="script"> initiated speculative load,
// 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(channel);
ScriptLoadContext::AddLoadBackgroundFlag(channel);
} else if (nsCOMPtr<nsIClassOfService> cos = do_QueryInterface(channel)) {
@ -786,8 +786,7 @@ nsresult ScriptLoader::StartLoadInternal(
aRequest->mURI, aRequest->CORSMode(), aRequest->mKind);
aRequest->GetScriptLoadContext()->NotifyOpen(
key, channel, mDocument,
aRequest->GetScriptLoadContext()->IsLinkPreloadScript(),
aRequest->IsModuleRequest());
aRequest->GetScriptLoadContext()->IsLinkPreloadScript());
if (aEarlyHintPreloaderId) {
nsCOMPtr<nsIHttpChannelInternal> channelInternal =

View file

@ -11634,21 +11634,12 @@
value: false
mirror: always
# Enables `<link rel="preload">` tag and `Link: rel=preload` response header
# handling.
# Enables `<link rel="preload">` tag and `Link: rel=preload` response header handling.
- name: network.preload
type: RelaxedAtomicBool
value: true
mirror: always
# Enables `<link rel="modulepreload">` tag and `Link: rel=modulepreload`
# response header handling. The latter is not yet implemented, see:
# https://bugzilla.mozilla.org/show_bug.cgi?id=1773056.
- name: network.modulepreload
type: RelaxedAtomicBool
value: true
mirror: always
# Enable 103 Early Hint status code (RFC 8297)
- name: network.early-hints.enabled
type: RelaxedAtomicBool

View file

@ -3716,30 +3716,11 @@ bool IsFontMimeType(const nsAString& aType) {
}
static const nsAttrValue::EnumTable kAsAttributeTable[] = {
{"", DESTINATION_INVALID},
{"audio", DESTINATION_AUDIO},
{"audioworklet", DESTINATION_AUDIOWORKLET},
{"document", DESTINATION_DOCUMENT},
{"embed", DESTINATION_EMBED},
{"font", DESTINATION_FONT},
{"frame", DESTINATION_FRAME},
{"iframe", DESTINATION_IFRAME},
{"image", DESTINATION_IMAGE},
{"manifest", DESTINATION_MANIFEST},
{"object", DESTINATION_OBJECT},
{"paintworklet", DESTINATION_PAINTWORKLET},
{"report", DESTINATION_REPORT},
{"script", DESTINATION_SCRIPT},
{"serviceworker", DESTINATION_SERVICEWORKER},
{"sharedworker", DESTINATION_SHAREDWORKER},
{"style", DESTINATION_STYLE},
{"track", DESTINATION_TRACK},
{"video", DESTINATION_VIDEO},
{"webidentity", DESTINATION_WEBIDENTITY},
{"worker", DESTINATION_WORKER},
{"xslt", DESTINATION_XSLT},
{"fetch", DESTINATION_FETCH},
{nullptr, 0}};
{"", DESTINATION_INVALID}, {"audio", DESTINATION_AUDIO},
{"font", DESTINATION_FONT}, {"image", DESTINATION_IMAGE},
{"script", DESTINATION_SCRIPT}, {"style", DESTINATION_STYLE},
{"track", DESTINATION_TRACK}, {"video", DESTINATION_VIDEO},
{"fetch", DESTINATION_FETCH}, {nullptr, 0}};
void ParseAsValue(const nsAString& aValue, nsAttrValue& aResult) {
DebugOnly<bool> success =
@ -3775,16 +3756,6 @@ nsContentPolicyType AsValueToContentPolicy(const nsAttrValue& aValue) {
return nsIContentPolicy::TYPE_INVALID;
}
bool IsScriptLikeOrInvalid(const nsAttrValue& aValue) {
return aValue.GetEnumValue() == DESTINATION_INVALID ||
aValue.GetEnumValue() == DESTINATION_AUDIOWORKLET ||
aValue.GetEnumValue() == DESTINATION_PAINTWORKLET ||
aValue.GetEnumValue() == DESTINATION_SCRIPT ||
aValue.GetEnumValue() == DESTINATION_SERVICEWORKER ||
aValue.GetEnumValue() == DESTINATION_SHAREDWORKER ||
aValue.GetEnumValue() == DESTINATION_WORKER;
}
bool CheckPreloadAttrs(const nsAttrValue& aAs, const nsAString& aType,
const nsAString& aMedia,
mozilla::dom::Document* aDocument) {

View file

@ -1019,16 +1019,12 @@ nsTArray<LinkHeader> ParseLinkHeader(const nsAString& aLinkData);
enum ASDestination : uint8_t {
DESTINATION_INVALID,
DESTINATION_AUDIO,
DESTINATION_AUDIOWORKLET,
DESTINATION_DOCUMENT,
DESTINATION_EMBED,
DESTINATION_FONT,
DESTINATION_FRAME,
DESTINATION_IFRAME,
DESTINATION_IMAGE,
DESTINATION_MANIFEST,
DESTINATION_OBJECT,
DESTINATION_PAINTWORKLET,
DESTINATION_REPORT,
DESTINATION_SCRIPT,
DESTINATION_SERVICEWORKER,
@ -1036,7 +1032,6 @@ enum ASDestination : uint8_t {
DESTINATION_STYLE,
DESTINATION_TRACK,
DESTINATION_VIDEO,
DESTINATION_WEBIDENTITY,
DESTINATION_WORKER,
DESTINATION_XSLT,
DESTINATION_FETCH
@ -1044,7 +1039,6 @@ enum ASDestination : uint8_t {
void ParseAsValue(const nsAString& aValue, nsAttrValue& aResult);
nsContentPolicyType AsValueToContentPolicy(const nsAttrValue& aValue);
bool IsScriptLikeOrInvalid(const nsAttrValue& aValue);
bool CheckPreloadAttrs(const nsAttrValue& aAs, const nsAString& aType,
const nsAString& aMedia,

View file

@ -63,7 +63,7 @@ void nsHtml5SpeculativeLoad::Perform(nsHtml5TreeOpExecutor* aExecutor) {
aExecutor->PreloadScript(
mUrlOrSizes, mCharsetOrSrcset,
mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity,
mCrossOrigin, mMedia, mReferrerPolicyOrIntegrity, mAs,
mCrossOrigin, mMedia, mReferrerPolicyOrIntegrity,
mScriptReferrerPolicy, false, mIsAsync, mIsDefer, false,
mIsLinkPreload);
break;
@ -71,7 +71,7 @@ void nsHtml5SpeculativeLoad::Perform(nsHtml5TreeOpExecutor* aExecutor) {
aExecutor->PreloadScript(
mUrlOrSizes, mCharsetOrSrcset,
mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity,
mCrossOrigin, mMedia, mReferrerPolicyOrIntegrity, mAs,
mCrossOrigin, mMedia, mReferrerPolicyOrIntegrity,
mScriptReferrerPolicy, true, mIsAsync, mIsDefer, false,
mIsLinkPreload);
break;
@ -79,7 +79,7 @@ void nsHtml5SpeculativeLoad::Perform(nsHtml5TreeOpExecutor* aExecutor) {
aExecutor->PreloadScript(
mUrlOrSizes, mCharsetOrSrcset,
mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity,
mCrossOrigin, mMedia, mReferrerPolicyOrIntegrity, mAs,
mCrossOrigin, mMedia, mReferrerPolicyOrIntegrity,
mScriptReferrerPolicy, false, mIsAsync, mIsDefer, true,
mIsLinkPreload);
break;
@ -87,7 +87,7 @@ void nsHtml5SpeculativeLoad::Perform(nsHtml5TreeOpExecutor* aExecutor) {
aExecutor->PreloadScript(
mUrlOrSizes, mCharsetOrSrcset,
mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity,
mCrossOrigin, mMedia, mReferrerPolicyOrIntegrity, mAs,
mCrossOrigin, mMedia, mReferrerPolicyOrIntegrity,
mScriptReferrerPolicy, true, mIsAsync, mIsDefer, true,
mIsLinkPreload);
break;

View file

@ -169,9 +169,9 @@ class nsHtml5SpeculativeLoad {
inline void InitScript(nsHtml5String aUrl, nsHtml5String aCharset,
nsHtml5String aType, nsHtml5String aCrossOrigin,
nsHtml5String aMedia, nsHtml5String aIntegrity,
nsHtml5String aAs, nsHtml5String aReferrerPolicy,
bool aParserInHead, bool aAsync, bool aDefer,
bool aNoModule, bool aLinkPreload) {
nsHtml5String aReferrerPolicy, bool aParserInHead,
bool aAsync, bool aDefer, bool aNoModule,
bool aLinkPreload) {
MOZ_ASSERT(mOpCode == eSpeculativeLoadUninitialized,
"Trying to reinitialize a speculative load!");
if (aNoModule) {
@ -188,7 +188,6 @@ class nsHtml5SpeculativeLoad {
aCrossOrigin.ToString(mCrossOrigin);
aMedia.ToString(mMedia);
aIntegrity.ToString(mReferrerPolicyOrIntegrity);
aAs.ToString(mAs);
nsAutoString referrerPolicy;
aReferrerPolicy.ToString(referrerPolicy);
referrerPolicy =
@ -335,8 +334,8 @@ class nsHtml5SpeculativeLoad {
/**
* True if and only if this is a speculative load initiated by <link
* rel="preload"> or <link rel="modulepreload"> tag encounter. Passed to the
* handling loader as an indication to raise the priority.
* rel="preload"> tag encounter. Passed to the handling loader as an
* indication to raise the priority.
*/
bool mIsLinkPreload;
@ -388,8 +387,8 @@ class nsHtml5SpeculativeLoad {
* value of the "sizes" attribute. If the attribute is not set, this will
* be a void string. If mOpCode is eSpeculativeLoadStyle, this
* is the value of the "integrity" attribute. If the attribute is not set,
* this will be a void string. Otherwise, it is empty or the value of the type
* attribute.
* this will be a void string. Otherwise it is empty or the value of the
* referrer policy. Otherwise, it is empty or the value of the type attribute.
*/
nsString mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity;
/**
@ -407,12 +406,6 @@ class nsHtml5SpeculativeLoad {
* will be a void string.
*/
nsString mMedia;
/**
* If mOpCode is eSpeculativeLoadScript[FromHead] and the preload originated
* from <link rel="modulepreload">, this is the value of the "as" attribute.
* Otherwise, this will be a void string.
*/
nsString mAs;
/**
* If mOpCode is eSpeculativeLoadScript[FromHead] this represents the value
* of the "referrerpolicy" attribute. This field holds one of the values

View file

@ -246,9 +246,8 @@ nsIContentHandle* nsHtml5TreeBuilder::createElement(
aAttributes->contains(nsHtml5AttributeName::ATTR_NOMODULE);
mSpeculativeLoadQueue.AppendElement()->InitScript(
url, charset, type, crossOrigin, /* aMedia = */ nullptr,
integrity, nullptr, referrerPolicy,
mode == nsHtml5TreeBuilder::IN_HEAD, async, defer, noModule,
false);
integrity, referrerPolicy, mode == nsHtml5TreeBuilder::IN_HEAD,
async, defer, noModule, false);
mCurrentHtmlScriptIsAsyncOrDefer = async || defer;
}
} else if (nsGkAtoms::link == aName) {
@ -314,9 +313,8 @@ nsIContentHandle* nsHtml5TreeBuilder::createElement(
aAttributes->getValue(nsHtml5AttributeName::ATTR_TYPE);
mSpeculativeLoadQueue.AppendElement()->InitScript(
url, charset, type, crossOrigin, media, integrity,
nullptr, referrerPolicy,
mode == nsHtml5TreeBuilder::IN_HEAD, false, false, false,
true);
referrerPolicy, mode == nsHtml5TreeBuilder::IN_HEAD,
false, false, false, true);
} else if (as.LowerCaseEqualsASCII("style")) {
mSpeculativeLoadQueue.AppendElement()->InitStyle(
url, charset, crossOrigin, media, referrerPolicy,
@ -338,31 +336,6 @@ nsIContentHandle* nsHtml5TreeBuilder::createElement(
}
// Other "as" values will be supported later.
}
} else if (mozilla::StaticPrefs::network_modulepreload() &&
rel.LowerCaseEqualsASCII("modulepreload")) {
nsHtml5String url =
aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF);
if (url && url.Length() != 0) {
nsHtml5String as =
aAttributes->getValue(nsHtml5AttributeName::ATTR_AS);
nsHtml5String charset =
aAttributes->getValue(nsHtml5AttributeName::ATTR_CHARSET);
RefPtr<nsAtom> moduleType = nsGkAtoms::_module;
nsHtml5String type =
nsHtml5String::FromAtom(moduleType.forget());
nsHtml5String crossOrigin = aAttributes->getValue(
nsHtml5AttributeName::ATTR_CROSSORIGIN);
nsHtml5String media =
aAttributes->getValue(nsHtml5AttributeName::ATTR_MEDIA);
nsHtml5String integrity =
aAttributes->getValue(nsHtml5AttributeName::ATTR_INTEGRITY);
nsHtml5String referrerPolicy = aAttributes->getValue(
nsHtml5AttributeName::ATTR_REFERRERPOLICY);
mSpeculativeLoadQueue.AppendElement()->InitScript(
url, charset, type, crossOrigin, media, integrity, as,
referrerPolicy, mode == nsHtml5TreeBuilder::IN_HEAD, false,
false, false, true);
}
}
}
} else if (nsGkAtoms::video == aName) {
@ -457,9 +430,8 @@ nsIContentHandle* nsHtml5TreeBuilder::createElement(
nsHtml5AttributeName::ATTR_REFERRERPOLICY);
mSpeculativeLoadQueue.AppendElement()->InitScript(
url, nullptr, type, crossOrigin, /* aMedia = */ nullptr,
integrity, nullptr, referrerPolicy,
mode == nsHtml5TreeBuilder::IN_HEAD, false, false, false,
false);
integrity, referrerPolicy, mode == nsHtml5TreeBuilder::IN_HEAD,
false, false, false, false);
}
} else if (nsGkAtoms::style == aName) {
mImportScanner.Start();

View file

@ -1205,22 +1205,13 @@ dom::ReferrerPolicy nsHtml5TreeOpExecutor::GetPreloadReferrerPolicy(
void nsHtml5TreeOpExecutor::PreloadScript(
const nsAString& aURL, const nsAString& aCharset, const nsAString& aType,
const nsAString& aCrossOrigin, const nsAString& aMedia,
const nsAString& aIntegrity, const nsAString& aAs,
dom::ReferrerPolicy aReferrerPolicy, bool aScriptFromHead, bool aAsync,
bool aDefer, bool aNoModule, bool aLinkPreload) {
const nsAString& aIntegrity, dom::ReferrerPolicy aReferrerPolicy,
bool aScriptFromHead, bool aAsync, bool aDefer, bool aNoModule,
bool aLinkPreload) {
nsCOMPtr<nsIURI> uri = ConvertIfNotPreloadedYetAndMediaApplies(aURL, aMedia);
if (!uri) {
return;
}
if (!aAs.IsVoid()) {
MOZ_ASSERT(aType.LowerCaseEqualsASCII("module") && aLinkPreload,
"aAs should be void for non-modulepreloads");
nsAttrValue asAttr;
net::ParseAsValue(aAs, asAttr);
if (!net::IsScriptLikeOrInvalid(asAttr)) {
return;
}
}
auto key = PreloadHashKey::CreateAsScript(uri, aCrossOrigin, aType);
if (mDocument->Preloads().PreloadExists(key)) {
return;

View file

@ -246,9 +246,9 @@ class nsHtml5TreeOpExecutor final
void PreloadScript(const nsAString& aURL, const nsAString& aCharset,
const nsAString& aType, const nsAString& aCrossOrigin,
const nsAString& aMedia, const nsAString& aIntegrity,
const nsAString& aAs, ReferrerPolicy aReferrerPolicy,
bool aScriptFromHead, bool aAsync, bool aDefer,
bool aNoModule, bool aLinkPreload);
ReferrerPolicy aReferrerPolicy, bool aScriptFromHead,
bool aAsync, bool aDefer, bool aNoModule,
bool aLinkPreload);
void PreloadStyle(const nsAString& aURL, const nsAString& aCharset,
const nsAString& aCrossOrigin, const nsAString& aMedia,

View file

@ -0,0 +1,2 @@
[avoid-delaying-onload-link-modulepreload-exec.html]
expected: ERROR

View file

@ -0,0 +1,2 @@
[avoid-delaying-onload-link-modulepreload.html]
expected: ERROR

View file

@ -0,0 +1,47 @@
[modulepreload.html]
expected: TIMEOUT
[link rel=modulepreload]
expected: TIMEOUT
[link rel=modulepreload with submodules]
expected: NOTRUN
[link rel=modulepreload for a module with syntax error]
expected: NOTRUN
[link rel=modulepreload for a module with network error]
expected: NOTRUN
[link rel=modulepreload with bad href attribute]
expected: NOTRUN
[link rel=modulepreload as=script]
expected: NOTRUN
[link rel=modulepreload with invalid as= value]
expected: NOTRUN
[link rel=modulepreload with integrity match]
expected: NOTRUN
[link rel=modulepreload with integrity mismatch]
expected: NOTRUN
[cross-origin link rel=modulepreload]
expected: NOTRUN
[cross-origin link rel=modulepreload crossorigin=anonymous]
expected: NOTRUN
[same-origin link rel=modulepreload crossorigin=anonymous]
expected: NOTRUN
[same-origin link rel=modulepreload crossorigin=use-credentials]
expected: NOTRUN
[cross-origin link rel=modulepreload crossorigin=use-credentials]
expected: NOTRUN
[link rel=modulepreload with integrity match2]
expected: NOTRUN

View file

@ -1,67 +0,0 @@
<!doctype html>
<meta charset=utf-8>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<link rel="modulepreload" href="resources/module1.js?empty-string" as="">
<link rel="modulepreload" href="resources/module1.js?audio" as="audio">
<link rel="modulepreload" href="resources/module1.js?audioworklet" as="audioworklet">
<link rel="modulepreload" href="resources/module1.js?document" as="document">
<link rel="modulepreload" href="resources/module1.js?embed" as="embed">
<link rel="modulepreload" href="resources/module1.js?font" as="font">
<link rel="modulepreload" href="resources/module1.js?frame" as="frame">
<link rel="modulepreload" href="resources/module1.js?iframe" as="iframe">
<link rel="modulepreload" href="resources/module1.js?image" as="image">
<link rel="modulepreload" href="resources/module1.js?manifest" as="manifest">
<link rel="modulepreload" href="resources/module1.js?object" as="object">
<link rel="modulepreload" href="resources/module1.js?paintworklet" as="paintworklet">
<link rel="modulepreload" href="resources/module1.js?report" as="report">
<link rel="modulepreload" href="resources/module1.js?script" as="script">
<link rel="modulepreload" href="resources/module1.js?serviceworker" as="serviceworker">
<link rel="modulepreload" href="resources/module1.js?sharedworker" as="sharedworker">
<link rel="modulepreload" href="resources/module1.js?style" as="style">
<link rel="modulepreload" href="resources/module1.js?track" as="track">
<link rel="modulepreload" href="resources/module1.js?video" as="video">
<link rel="modulepreload" href="resources/module1.js?webidentity" as="webidentity">
<link rel="modulepreload" href="resources/module1.js?worker" as="worker">
<link rel="modulepreload" href="resources/module1.js?xslt" as="xslt">
<link rel="modulepreload" href="resources/module1.js?fetch" as="fetch">
<link rel="modulepreload" href="resources/module1.js?invalid-dest" as="invalid-dest" data-as="invalid-dest">
<link rel="modulepreload" href="resources/module1.js?iMaGe" as="iMaGe" data-as="iMaGe">
<link rel="modulepreload" href="resources/module1.js?sCrIpT" as="sCrIpT" data-as="sCrIpT">
<body>
<script>
// compared to modulepreload.html, this tests behavior when elements are
// initially on an HTML page instead of being added by JS
const scriptLikes = [
'audioworklet',
'paintworklet',
'script',
'serviceworker',
'sharedworker',
'worker',
];
const goodAsValues = ['', 'invalid-dest', 'sCrIpT', ...scriptLikes];
for (const link of document.querySelectorAll('link')) {
const asValue = link.dataset.as ?? link.as;
const good = goodAsValues.includes(asValue);
// promise tests are queued sequentially, so create the promise here to
// ensure we don't miss the error event
const promise = new Promise((resolve, reject) => {
link.onload = good ? resolve : reject;
link.onerror = good ? reject : resolve;
});
promise_test(() => promise.then(() => {
const downloads = performance
.getEntriesByName(new URL(link.href, location.href))
.filter(entry => entry.transferSize > 0)
.length;
assert_equals(downloads, good ? 1 : 0);
}), `Modulepreload with as="${asValue}"`);
}
</script>

View file

@ -1,18 +0,0 @@
<!doctype html>
<meta charset=utf-8>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<link rel="modulepreload" href="resources/module1.js" integrity="sha384-invalid">
<script type="module" src="resources/module1.js" id="myscript"></script>
<body>
<script>
// compared to modulepreload.html, this tests behavior when elements are
// initially on an HTML page instead of being added by JS
promise_test(() => {
return new Promise((resolve, reject) => {
let myscript = document.querySelector('#myscript');
myscript.onerror = resolve;
myscript.onload = reject;
});
}, "Script should not be loaded if modulepreload's integrity is invalid");
</script>

View file

@ -33,15 +33,6 @@ function attachAndWaitForError(element) {
});
}
function attachAndWaitForTimeout(element, t) {
return new Promise((resolve, reject) => {
element.onload = reject;
element.onerror = reject;
t.step_timeout(resolve, 1000);
document.body.appendChild(element);
});
}
promise_test(function(t) {
var link = document.createElement('link');
link.rel = 'modulepreload';
@ -223,21 +214,13 @@ promise_test(function(t) {
link.href = 'resources/module1.js?as-image';
link.as = 'image'
return attachAndWaitForError(link);
}, 'link rel=modulepreload with non-script-like as= value (image)');
promise_test(function(t) {
var link = document.createElement('link');
link.rel = 'modulepreload';
link.href = 'resources/module1.js?as-xslt';
link.as = 'xslt'
return attachAndWaitForError(link);
}, 'link rel=modulepreload with non-script-like as= value (xslt)');
}, 'link rel=modulepreload with invalid as= value');
promise_test(function(t) {
var link = document.createElement('link');
link.rel = 'modulepreload';
link.href = 'resources/module1.js?integrity-match';
link.integrity = 'sha256-+Ks3iNIiTq2ujlWhvB056cmXobrCFpU9hd60xZ1WCaA='
link.integrity = 'sha256-dOxReWMnMSPfUvxEbBqIrjNh8ZN8n05j7h3JmhF8gQc=%'
return attachAndWaitForLoad(link);
}, 'link rel=modulepreload with integrity match');
@ -245,7 +228,7 @@ promise_test(function(t) {
var link = document.createElement('link');
link.rel = 'modulepreload';
link.href = 'resources/module1.mjs?integrity-match';
link.integrity = 'sha256-+Ks3iNIiTq2ujlWhvB056cmXobrCFpU9hd60xZ1WCaA='
link.integrity = 'sha256-dOxReWMnMSPfUvxEbBqIrjNh8ZN8n05j7h3JmhF8gQc=%'
return attachAndWaitForLoad(link);
}, 'link rel=modulepreload with integrity match2');
@ -257,88 +240,5 @@ promise_test(function(t) {
return attachAndWaitForError(link);
}, 'link rel=modulepreload with integrity mismatch');
promise_test(function(t) {
var link = document.createElement('link');
link.rel = 'modulepreload';
link.href = 'resources/module1.mjs?integrity-doesnotmatch';
link.integrity = 'sha256-dOxReWMnMSPfUvxEbBqIrjNh8ZN8n05j7h3JmhF8gQc='
return attachAndWaitForError(link);
}, 'link rel=modulepreload with integrity mismatch2');
promise_test(function(t) {
var link = document.createElement('link');
link.rel = 'modulepreload';
link.href = 'resources/module1.mjs?integrity-invalid';
link.integrity = 'sha256-dOxReWMnMSPfUvxEbBqIrjNh8ZN8n05j7h3JmhF8gQc=%'
return attachAndWaitForError(link);
}, 'link rel=modulepreload with integrity mismatch3');
promise_test(function(t) {
var link1 = document.createElement('link');
var link2 = document.createElement('link');
link1.rel = 'modulepreload';
link2.rel = 'modulepreload';
link1.href = 'resources/module1.js?same-url';
link2.href = 'resources/module1.js?same-url';
return Promise.all([
attachAndWaitForLoad(link1),
attachAndWaitForLoad(link2),
]);
}, 'multiple link rel=modulepreload with same href');
promise_test(function(t) {
var link1 = document.createElement('link');
var link2 = document.createElement('link');
link1.rel = 'modulepreload';
link2.rel = 'modulepreload';
link1.href = 'resources/module2.js?child-before';
link2.href = 'resources/module1.js?child-before';
return attachAndWaitForLoad(link1)
.then(() => attachAndWaitForLoad(link2))
.then(() => new Promise(r => t.step_timeout(r, 1000)))
.then(() => {
verifyNumberOfDownloads('resources/module2.js?child-before', 1);
});
}, 'multiple link rel=modulepreload with child module before parent');
promise_test(function(t) {
var link = document.createElement('link');
link.rel = 'modulepreload';
link.href = 'resources/module1.mjs?matching-media';
link.media = 'all';
return attachAndWaitForLoad(link);
}, 'link rel=modulepreload with matching media');
promise_test(function(t) {
var link = document.createElement('link');
link.rel = 'modulepreload';
link.href = 'resources/module1.mjs?non-matching-media';
link.media = 'not all';
return attachAndWaitForTimeout(link, t);
}, 'link rel=modulepreload with non-matching media');
promise_test(function(t) {
var link = document.createElement('link');
link.rel = 'modulepreload';
link.href = 'resources/module1.mjs?empty-media';
link.media = '';
return attachAndWaitForLoad(link);
}, 'link rel=modulepreload with empty media');
promise_test(function(t) {
var link = document.createElement('link');
link.rel = 'modulepreload';
link.href = '';
return attachAndWaitForTimeout(link, t);
}, 'link rel=modulepreload with empty href');
promise_test(function(t) {
var link = document.createElement('link');
link.rel = 'modulepreload';
link.href = '';
link.as = 'fetch';
return attachAndWaitForTimeout(link, t);
}, 'link rel=modulepreload with empty href and invalid as= value');
</script>
</body>

View file

@ -72,10 +72,11 @@ already_AddRefed<PreloaderBase> PreloadService::PreloadLinkElement(
return nullptr;
}
nsAutoString as, charset, crossOrigin, integrity, referrerPolicy, rel, srcset,
nsAutoString as, charset, crossOrigin, integrity, referrerPolicy, srcset,
sizes, type, url;
nsCOMPtr<nsIURI> uri = aLinkElement->GetURI();
aLinkElement->GetAs(as);
aLinkElement->GetCharset(charset);
aLinkElement->GetImageSrcset(srcset);
aLinkElement->GetImageSizes(sizes);
@ -83,15 +84,7 @@ already_AddRefed<PreloaderBase> PreloadService::PreloadLinkElement(
aLinkElement->GetCrossOrigin(crossOrigin);
aLinkElement->GetIntegrity(integrity);
aLinkElement->GetReferrerPolicy(referrerPolicy);
aLinkElement->GetRel(rel);
if (rel.LowerCaseEqualsASCII("modulepreload")) {
as = u"script"_ns;
type = u"module"_ns;
} else {
aLinkElement->GetAs(as);
aLinkElement->GetType(type);
}
aLinkElement->GetType(type);
auto result = PreloadOrCoalesce(uri, url, aPolicyType, as, type, charset,
srcset, sizes, integrity, crossOrigin,

View file

@ -124,8 +124,7 @@ void PreloaderBase::AddLoadBackgroundFlag(nsIChannel* aChannel) {
}
void PreloaderBase::NotifyOpen(const PreloadHashKey& aKey,
dom::Document* aDocument, bool aIsPreload,
bool aIsModule) {
dom::Document* aDocument, bool aIsPreload) {
if (aDocument) {
DebugOnly<bool> alreadyRegistered =
aDocument->Preloads().RegisterPreload(aKey, this);
@ -138,10 +137,7 @@ void PreloaderBase::NotifyOpen(const PreloadHashKey& aKey,
mKey = aKey;
mIsUsed = !aIsPreload;
// Start usage timer for rel="preload", but not for rel="modulepreload"
// because modules may be loaded for functionality the user does not
// immediately interact with after page load (e.g. a docs search box)
if (!aIsModule && !mIsUsed && !mUsageTimer) {
if (!mIsUsed && !mUsageTimer) {
auto callback = MakeRefPtr<UsageTimer>(this, aDocument);
NS_NewTimerWithCallback(getter_AddRefs(mUsageTimer), callback, 10000,
nsITimer::TYPE_ONE_SHOT);
@ -151,9 +147,8 @@ void PreloaderBase::NotifyOpen(const PreloadHashKey& aKey,
}
void PreloaderBase::NotifyOpen(const PreloadHashKey& aKey, nsIChannel* aChannel,
dom::Document* aDocument, bool aIsPreload,
bool aIsModule) {
NotifyOpen(aKey, aDocument, aIsPreload, aIsModule);
dom::Document* aDocument, bool aIsPreload) {
NotifyOpen(aKey, aDocument, aIsPreload);
mChannel = aChannel;
nsCOMPtr<nsIInterfaceRequestor> callbacks;

View file

@ -45,10 +45,9 @@ class PreloaderBase : public SupportsWeakPtr, public nsISupports {
// preload service to provide coalescing, and access to the preload when it
// should be used for an actual load.
void NotifyOpen(const PreloadHashKey& aKey, dom::Document* aDocument,
bool aIsPreload, bool aIsModule = false);
bool aIsPreload);
void NotifyOpen(const PreloadHashKey& aKey, nsIChannel* aChannel,
dom::Document* aDocument, bool aIsPreload,
bool aIsModule = false);
dom::Document* aDocument, bool aIsPreload);
// Called when the load is about to be started all over again and thus this
// PreloaderBase will be registered again with the same key. This method

View file

@ -678,7 +678,6 @@ STATIC_ATOMS = [
Atom("mixed", "mixed"),
Atom("messagemanagergroup", "messagemanagergroup"),
Atom("mod", "mod"),
Atom("_module", "module"),
Atom("mode", "mode"),
Atom("modifiers", "modifiers"),
Atom("monochrome", "monochrome"),