commit f45f89e18858f77d0679126017d425f8eb14897c
parent 00429283549a36638f5e7b7e5c222925b7970e34
Author: Randell Jesup <rjesup@mozilla.com>
Date: Tue, 7 Oct 2025 14:07:04 +0000
Bug 1918013: Compression Dictionaries link rel= support r=smaug,necko-reviewers,kershaw
Differential Revision: https://phabricator.services.mozilla.com/D255234
Diffstat:
8 files changed, 98 insertions(+), 46 deletions(-)
diff --git a/dom/base/LinkStyle.cpp b/dom/base/LinkStyle.cpp
@@ -149,6 +149,8 @@ static uint32_t ToLinkMask(const nsAString& aLink) {
mask = LinkStyle::ePRELOAD;
} else if (aLink.EqualsLiteral("modulepreload")) {
mask = LinkStyle::eMODULE_PRELOAD;
+ } else if (aLink.EqualsLiteral("compression-dictionary")) {
+ mask = LinkStyle::eCOMPRESSION_DICTIONARY;
}
return mask;
diff --git a/dom/base/LinkStyle.h b/dom/base/LinkStyle.h
@@ -117,7 +117,8 @@ class LinkStyle {
ePRECONNECT = 0x00000020,
// NOTE: 0x40 is unused
ePRELOAD = 0x00000080,
- eMODULE_PRELOAD = 0x00000100
+ eMODULE_PRELOAD = 0x00000100,
+ eCOMPRESSION_DICTIONARY = 0x00000200
};
// The return value is a bitwise or of 0 or more RelValues.
diff --git a/dom/base/nsContentSink.cpp b/dom/base/nsContentSink.cpp
@@ -316,10 +316,19 @@ nsresult nsContentSink::ProcessLinkFromHeader(const net::LinkHeader& aHeader,
}
if (linkTypes & LinkStyle::ePRELOAD) {
- PreloadHref(aHeader.mHref, aHeader.mAs, aHeader.mType, aHeader.mMedia,
- aHeader.mNonce, aHeader.mIntegrity, aHeader.mSrcset,
- aHeader.mSizes, aHeader.mCrossOrigin, aHeader.mReferrerPolicy,
- aEarlyHintPreloaderId, aHeader.mFetchPriority);
+ PreloadHref(aHeader.mHref, aHeader.mAs, aHeader.mRel, aHeader.mType,
+ aHeader.mMedia, aHeader.mNonce, aHeader.mIntegrity,
+ aHeader.mSrcset, aHeader.mSizes, aHeader.mCrossOrigin,
+ aHeader.mReferrerPolicy, aEarlyHintPreloaderId,
+ aHeader.mFetchPriority);
+ }
+
+ if (linkTypes & LinkStyle::eCOMPRESSION_DICTIONARY) {
+ PreloadHref(aHeader.mHref, u"fetch"_ns, aHeader.mRel, aHeader.mType,
+ aHeader.mMedia, aHeader.mNonce, aHeader.mIntegrity,
+ aHeader.mSrcset, aHeader.mSizes, aHeader.mCrossOrigin,
+ aHeader.mReferrerPolicy, aEarlyHintPreloaderId,
+ aHeader.mFetchPriority);
}
if ((linkTypes & LinkStyle::eMODULE_PRELOAD) &&
@@ -431,15 +440,13 @@ void nsContentSink::PrefetchHref(const nsAString& aHref, const nsAString& aAs,
}
}
-void nsContentSink::PreloadHref(const nsAString& aHref, const nsAString& aAs,
- const nsAString& aType, const nsAString& aMedia,
- const nsAString& aNonce,
- const nsAString& aIntegrity,
- const nsAString& aSrcset,
- const nsAString& aSizes, const nsAString& aCORS,
- const nsAString& aReferrerPolicy,
- uint64_t aEarlyHintPreloaderId,
- const nsAString& aFetchPriority) {
+void nsContentSink::PreloadHref(
+ const nsAString& aHref, const nsAString& aAs, const nsAString& aRel,
+ const nsAString& aType, const nsAString& aMedia, const nsAString& aNonce,
+ const nsAString& aIntegrity, const nsAString& aSrcset,
+ const nsAString& aSizes, const nsAString& aCORS,
+ const nsAString& aReferrerPolicy, uint64_t aEarlyHintPreloaderId,
+ const nsAString& aFetchPriority) {
auto encoding = mDocument->GetDocumentCharacterSet();
nsCOMPtr<nsIURI> uri;
NS_NewURI(getter_AddRefs(uri), aHref, encoding, mDocument->GetDocBaseURI());
@@ -464,8 +471,8 @@ void nsContentSink::PreloadHref(const nsAString& aHref, const nsAString& aAs,
}
mDocument->Preloads().PreloadLinkHeader(
- uri, aHref, policyType, aAs, aType, aNonce, aIntegrity, aSrcset, aSizes,
- aCORS, aReferrerPolicy, aEarlyHintPreloaderId, aFetchPriority);
+ uri, aHref, policyType, aAs, aRel, aType, aNonce, aIntegrity, aSrcset,
+ aSizes, aCORS, aReferrerPolicy, aEarlyHintPreloaderId, aFetchPriority);
}
void nsContentSink::PreloadModule(
@@ -506,9 +513,9 @@ void nsContentSink::PreloadModule(
moduleLoader->DisallowImportMaps();
mDocument->Preloads().PreloadLinkHeader(
- uri, aHref, nsIContentPolicy::TYPE_SCRIPT, u"script"_ns, u"module"_ns,
- aNonce, aIntegrity, u""_ns, u""_ns, aCORS, aReferrerPolicy,
- aEarlyHintPreloaderId, aFetchPriority);
+ uri, aHref, nsIContentPolicy::TYPE_SCRIPT, u"script"_ns,
+ u"modulepreload"_ns, u"module"_ns, aNonce, aIntegrity, u""_ns, u""_ns,
+ aCORS, aReferrerPolicy, aEarlyHintPreloaderId, aFetchPriority);
}
void nsContentSink::PrefetchDNS(const nsAString& aHref) {
diff --git a/dom/base/nsContentSink.h b/dom/base/nsContentSink.h
@@ -141,10 +141,11 @@ class nsContentSink : public nsICSSLoaderObserver,
void PrefetchHref(const nsAString& aHref, const nsAString& aAs,
const nsAString& aType, const nsAString& aMedia);
void PreloadHref(const nsAString& aHref, const nsAString& aAs,
- const nsAString& aType, const nsAString& aMedia,
- const nsAString& aNonce, const nsAString& aIntegrity,
- const nsAString& aSrcset, const nsAString& aSizes,
- const nsAString& aCORS, const nsAString& aReferrerPolicy,
+ const nsAString& aRel, const nsAString& aType,
+ const nsAString& aMedia, const nsAString& aNonce,
+ const nsAString& aIntegrity, const nsAString& aSrcset,
+ const nsAString& aSizes, const nsAString& aCORS,
+ const nsAString& aReferrerPolicy,
uint64_t aEarlyHintPreloaderId,
const nsAString& aFetchPriority);
diff --git a/dom/html/HTMLLinkElement.cpp b/dom/html/HTMLLinkElement.cpp
@@ -323,17 +323,23 @@ void HTMLLinkElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName,
"preload", "prefetch", "dns-prefetch", "stylesheet", "next", "alternate", \
"preconnect", "icon", "search", nullptr
-static const DOMTokenListSupportedToken sSupportedRelValueCombinations[][12] = {
+static const DOMTokenListSupportedToken sSupportedRelValueCombinations[][13] = {
{SUPPORTED_REL_VALUES_BASE},
{"manifest", SUPPORTED_REL_VALUES_BASE},
{"modulepreload", SUPPORTED_REL_VALUES_BASE},
- {"modulepreload", "manifest", SUPPORTED_REL_VALUES_BASE}};
+ {"modulepreload", "manifest", SUPPORTED_REL_VALUES_BASE},
+ {"compression-dictionary", SUPPORTED_REL_VALUES_BASE},
+ {"compression-dictionary", "manifest", SUPPORTED_REL_VALUES_BASE},
+ {"compression-dictionary", "modulepreload", SUPPORTED_REL_VALUES_BASE},
+ {"compression-dictionary", "modulepreload", "manifest",
+ SUPPORTED_REL_VALUES_BASE}};
#undef SUPPORTED_REL_VALUES_BASE
nsDOMTokenList* HTMLLinkElement::RelList() {
if (!mRelList) {
int index = (StaticPrefs::dom_manifest_enabled() ? 1 : 0) |
- (StaticPrefs::network_modulepreload() ? 2 : 0);
+ (StaticPrefs::network_modulepreload() ? 2 : 0) |
+ (StaticPrefs::network_http_dictionaries_enable() ? 4 : 0);
mRelList = new nsDOMTokenList(this, nsGkAtoms::rel,
sSupportedRelValueCombinations[index]);
@@ -465,6 +471,13 @@ void HTMLLinkElement::
}
}
+ if (linkTypes & eCOMPRESSION_DICTIONARY) {
+ if (nsCOMPtr<nsIURI> uri = GetURI()) {
+ StartPreload(nsIContentPolicy::TYPE_INTERNAL_FETCH_PRELOAD);
+ return;
+ }
+ }
+
if (linkTypes & ePRELOAD) {
if (nsCOMPtr<nsIURI> uri = GetURI()) {
nsContentPolicyType policyType;
diff --git a/netwerk/protocol/http/EarlyHintsService.cpp b/netwerk/protocol/http/EarlyHintsService.cpp
@@ -105,6 +105,13 @@ void EarlyHintsService::EarlyHint(
mOngoingEarlyHints, linkHeader, aBaseURI, principal,
cookieJarSettings, aReferrerPolicy, aCSPHeader,
loadInfo->GetBrowsingContextID(), aLoadingBrowsingContext, true);
+ } else if (linkHeader.mRel.LowerCaseEqualsLiteral(
+ "compression-dictionary")) {
+ mLinkType |= dom::LinkStyle::eCOMPRESSION_DICTIONARY;
+ EarlyHintPreloader::MaybeCreateAndInsertPreload(
+ mOngoingEarlyHints, linkHeader, aBaseURI, principal,
+ cookieJarSettings, aReferrerPolicy, aCSPHeader,
+ loadInfo->GetBrowsingContextID(), aLoadingBrowsingContext, true);
}
}
}
diff --git a/uriloader/preload/PreloadService.cpp b/uriloader/preload/PreloadService.cpp
@@ -93,6 +93,13 @@ already_AddRefed<PreloaderBase> PreloadService::PreloadLinkElement(
integrity =
aLinkElement->HasAttr(nsGkAtoms::integrity) ? integrity : VoidString();
+ // rel=compression-dictionary fetches default to "anonymous" if no
+ // crossorigin=foo parameter is given
+ if (rel.LowerCaseEqualsASCII("compression-dictionary") &&
+ crossOrigin.IsEmpty()) {
+ crossOrigin = u"anonymous"_ns;
+ }
+
nsAutoString nonce;
if (nsString* cspNonce =
static_cast<nsString*>(aLinkElement->GetProperty(nsGkAtoms::nonce))) {
@@ -107,7 +114,7 @@ already_AddRefed<PreloaderBase> PreloadService::PreloadLinkElement(
aLinkElement->GetType(type);
}
- auto result = PreloadOrCoalesce(uri, url, aPolicyType, as, type, charset,
+ auto result = PreloadOrCoalesce(uri, url, aPolicyType, as, rel, type, charset,
srcset, sizes, nonce, integrity, crossOrigin,
referrerPolicy, fetchPriority,
/* aFromHeader = */ false, 0);
@@ -123,9 +130,9 @@ already_AddRefed<PreloaderBase> PreloadService::PreloadLinkElement(
void PreloadService::PreloadLinkHeader(
nsIURI* aURI, const nsAString& aURL, nsContentPolicyType aPolicyType,
- const nsAString& aAs, const nsAString& aType, const nsAString& aNonce,
- const nsAString& aIntegrity, const nsAString& aSrcset,
- const nsAString& aSizes, const nsAString& aCORS,
+ const nsAString& aAs, const nsAString& aRel, const nsAString& aType,
+ const nsAString& aNonce, const nsAString& aIntegrity,
+ const nsAString& aSrcset, const nsAString& aSizes, const nsAString& aCORS,
const nsAString& aReferrerPolicy, uint64_t aEarlyHintPreloaderId,
const nsAString& aFetchPriority) {
if (aPolicyType == nsIContentPolicy::TYPE_INVALID) {
@@ -133,10 +140,17 @@ void PreloadService::PreloadLinkHeader(
return;
}
- PreloadOrCoalesce(aURI, aURL, aPolicyType, aAs, aType, u""_ns, aSrcset,
- aSizes, aNonce, aIntegrity, aCORS, aReferrerPolicy,
- aFetchPriority,
- /* aFromHeader = */ true, aEarlyHintPreloaderId);
+ // rel=compression-dictionary fetches default to "anonymous" if no
+ // crossorigin=foo parameter is given
+
+ PreloadOrCoalesce(
+ aURI, aURL, aPolicyType, aAs, aRel, aType, u""_ns, aSrcset, aSizes,
+ aNonce, aIntegrity,
+ aRel.LowerCaseEqualsASCII("compression-dictionary") && aCORS.IsEmpty()
+ ? u"anonymous"_ns
+ : aCORS,
+ aReferrerPolicy, aFetchPriority,
+ /* aFromHeader = */ true, aEarlyHintPreloaderId);
}
// The mapping is specified as implementation-defined, see step 15 of
@@ -167,8 +181,9 @@ class SupportsPriorityValueFor {
PreloadService::PreloadOrCoalesceResult PreloadService::PreloadOrCoalesce(
nsIURI* aURI, const nsAString& aURL, nsContentPolicyType aPolicyType,
- const nsAString& aAs, const nsAString& aType, const nsAString& aCharset,
- const nsAString& aSrcset, const nsAString& aSizes, const nsAString& aNonce,
+ const nsAString& aAs, const nsAString& aRel, const nsAString& aType,
+ const nsAString& aCharset, const nsAString& aSrcset,
+ const nsAString& aSizes, const nsAString& aNonce,
const nsAString& aIntegrity, const nsAString& aCORS,
const nsAString& aReferrerPolicy, const nsAString& aFetchPriority,
bool aFromHeader, uint64_t aEarlyHintPreloaderId) {
@@ -202,6 +217,10 @@ PreloadService::PreloadOrCoalesceResult PreloadService::PreloadOrCoalesce(
} else if (aAs.LowerCaseEqualsASCII("fetch")) {
preloadKey = PreloadHashKey::CreateAsFetch(
uri, dom::Element::StringToCORSMode(aCORS));
+ } else if (aRel.LowerCaseEqualsASCII("compression-dictionary")) {
+ // compression-dictionary doesn't specify an 'as=' value
+ preloadKey = PreloadHashKey::CreateAsFetch(
+ uri, dom::Element::StringToCORSMode(aCORS));
} else {
return {nullptr, false};
}
@@ -240,7 +259,8 @@ PreloadService::PreloadOrCoalesceResult PreloadService::PreloadOrCoalesce(
} else if (aAs.LowerCaseEqualsASCII("font")) {
PreloadFont(uri, aCORS, aReferrerPolicy, aEarlyHintPreloaderId,
aFetchPriority);
- } else if (aAs.LowerCaseEqualsASCII("fetch")) {
+ } else if (aAs.LowerCaseEqualsASCII("fetch") ||
+ aRel.LowerCaseEqualsASCII("compression-dictionary")) {
PreloadFetch(uri, aCORS, aReferrerPolicy, aEarlyHintPreloaderId,
aFetchPriority);
}
diff --git a/uriloader/preload/PreloadService.h b/uriloader/preload/PreloadService.h
@@ -74,9 +74,10 @@ class PreloadService {
// AsyncOpen.
void PreloadLinkHeader(nsIURI* aURI, const nsAString& aURL,
nsContentPolicyType aPolicyType, const nsAString& aAs,
- const nsAString& aType, const nsAString& aNonce,
- const nsAString& aIntegrity, const nsAString& aSrcset,
- const nsAString& aSizes, const nsAString& aCORS,
+ const nsAString& aRel, const nsAString& aType,
+ const nsAString& aNonce, const nsAString& aIntegrity,
+ const nsAString& aSrcset, const nsAString& aSizes,
+ const nsAString& aCORS,
const nsAString& aReferrerPolicy,
uint64_t aEarlyHintPreloaderId,
const nsAString& aFetchPriority);
@@ -119,12 +120,12 @@ class PreloadService {
PreloadOrCoalesceResult PreloadOrCoalesce(
nsIURI* aURI, const nsAString& aURL, nsContentPolicyType aPolicyType,
- const nsAString& aAs, const nsAString& aType, const nsAString& aCharset,
- const nsAString& aSrcset, const nsAString& aSizes,
- const nsAString& aNonce, const nsAString& aIntegrity,
- const nsAString& aCORS, const nsAString& aReferrerPolicy,
- const nsAString& aFetchPriority, bool aFromHeader,
- uint64_t aEarlyHintPreloaderId);
+ const nsAString& aAs, const nsAString& aRel, const nsAString& aType,
+ const nsAString& aCharset, const nsAString& aSrcset,
+ const nsAString& aSizes, const nsAString& aNonce,
+ const nsAString& aIntegrity, const nsAString& aCORS,
+ const nsAString& aReferrerPolicy, const nsAString& aFetchPriority,
+ bool aFromHeader, uint64_t aEarlyHintPreloaderId);
private:
nsRefPtrHashtable<PreloadHashKey, PreloaderBase> mPreloads;