tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit fe57630b1dc0c45eb8f6ee8a868a91a07a3cbff0
parent 3ce6095849c00bed4a16f3ced9626541d814e0ba
Author: Randell Jesup <rjesup@mozilla.com>
Date:   Wed,  1 Oct 2025 18:45:56 +0000

Bug 1918013: Compression Dictionaries link rel= support r=smaug,necko-reviewers,kershaw

Differential Revision: https://phabricator.services.mozilla.com/D255234

Diffstat:
Mdom/base/LinkStyle.cpp | 2++
Mdom/base/LinkStyle.h | 3++-
Mdom/base/nsContentSink.cpp | 43+++++++++++++++++++++++++------------------
Mdom/base/nsContentSink.h | 9+++++----
Mdom/html/HTMLLinkElement.cpp | 19++++++++++++++++---
Mnetwerk/protocol/http/EarlyHintsService.cpp | 7+++++++
Muriloader/preload/PreloadService.cpp | 42+++++++++++++++++++++++++++++++-----------
Muriloader/preload/PreloadService.h | 19++++++++++---------
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;