Issue #2641 - Speculative load changes for referrerpolicy

This commit is contained in:
Moonchild 2024-10-20 09:35:39 +02:00 • committed by roytam1
commit f6f046930d
20 changed files with 262 additions and 128 deletions

View file

@ -472,6 +472,7 @@ nsContentSink::ProcessLinkHeader(const nsAString& aLinkData)
nsAutoString media;
nsAutoString anchor;
nsAutoString crossOrigin;
nsAutoString referrerPolicy;
nsAutoString destination;
crossOrigin.SetIsVoid(true);
@ -660,6 +661,15 @@ nsContentSink::ProcessLinkHeader(const nsAString& aLinkData)
destination = value;
destination.StripWhitespace();
}
} else if (attr.LowerCaseEqualsLiteral("referrerpolicy")) {
// https://html.spec.whatwg.org/multipage/urls-and-fetching.html#referrer-policy-attribute
// The spec says that the referrer policy attribute is an enumerated attribute,
// case insensitive and includes the empty string.
// We will parse the value with AttributeReferrerPolicyFromString
// later, which will handle parsing it as an enumerated attribute.
if (referrerPolicy.IsEmpty()) {
referrerPolicy = value;
}
}
}
}
@ -673,7 +683,7 @@ nsContentSink::ProcessLinkHeader(const nsAString& aLinkData)
rv = ProcessLink(anchor, href, rel,
// prefer RFC 5987 variant over non-I18zed version
titleStar.IsEmpty() ? title : titleStar,
type, media, crossOrigin, destination);
type, media, crossOrigin, referrerPolicy, destination);
}
href.Truncate();
@ -682,6 +692,7 @@ nsContentSink::ProcessLinkHeader(const nsAString& aLinkData)
type.Truncate();
media.Truncate();
anchor.Truncate();
referrerPolicy.Truncate();
crossOrigin.SetIsVoid(true);
destination.Truncate();
@ -696,7 +707,7 @@ nsContentSink::ProcessLinkHeader(const nsAString& aLinkData)
rv = ProcessLink(anchor, href, rel,
// prefer RFC 5987 variant over non-I18zed version
titleStar.IsEmpty() ? title : titleStar,
type, media, crossOrigin, destination);
type, media, crossOrigin, referrerPolicy, destination);
}
return rv;
@ -708,6 +719,7 @@ nsContentSink::ProcessLink(const nsSubstring& aAnchor, const nsSubstring& aHref,
const nsSubstring& aRel, const nsSubstring& aTitle,
const nsSubstring& aType, const nsSubstring& aMedia,
const nsSubstring& aCrossOrigin,
const nsAString& aReferrerPolicy,
const nsSubstring& aDestination)
{
uint32_t linkTypes =
@ -749,7 +761,7 @@ nsContentSink::ProcessLink(const nsSubstring& aAnchor, const nsSubstring& aHref,
bool isAlternate = linkTypes & nsStyleLinkElement::eALTERNATE;
return ProcessStyleLink(nullptr, aHref, isAlternate, aTitle, aType,
aMedia);
aMedia, aReferrerPolicy);
}
nsresult
@ -758,7 +770,8 @@ nsContentSink::ProcessStyleLink(nsIContent* aElement,
bool aAlternate,
const nsSubstring& aTitle,
const nsSubstring& aType,
const nsSubstring& aMedia)
const nsSubstring& aMedia,
const nsSubstring& aReferrerPolicy)
{
if (aAlternate && aTitle.IsEmpty()) {
// alternates must have title return without error, for now
@ -797,13 +810,18 @@ nsContentSink::ProcessStyleLink(nsIContent* aElement,
("nsContentSink::ProcessStyleLink, integrity=%s",
NS_ConvertUTF16toUTF8(integrity).get()));
}
mozilla::net::ReferrerPolicy referrerPolicy =
mozilla::net::AttributeReferrerPolicyFromString(aReferrerPolicy);
if (referrerPolicy == net::RP_Unset) {
referrerPolicy = mDocument->GetReferrerPolicy();
}
// If this is a fragment parser, we don't want to observe.
// We don't support CORS for processing instructions
bool isAlternate;
bool isExplicitlyEnabled;
rv = mCSSLoader->LoadStyleLink(aElement, url, aTitle, aMedia, aAlternate,
CORS_NONE, mDocument->GetReferrerPolicy(),
CORS_NONE, referrerPolicy,
integrity, mRunsToCompletion ? nullptr : this,
&isAlternate, &isExplicitlyEnabled);
NS_ENSURE_SUCCESS(rv, rv);

View file

@ -154,6 +154,7 @@ protected:
const nsSubstring& aHref, const nsSubstring& aRel,
const nsSubstring& aTitle, const nsSubstring& aType,
const nsSubstring& aMedia, const nsSubstring& aCrossOrigin,
const nsSubstring& aReferrerPolicy,
const nsSubstring& aDestination);
virtual nsresult ProcessStyleLink(nsIContent* aElement,
@ -161,7 +162,8 @@ protected:
bool aAlternate,
const nsSubstring& aTitle,
const nsSubstring& aType,
const nsSubstring& aMedia);
const nsSubstring& aMedia,
const nsSubstring& aReferrerPolicy);
void PrefetchOrPreloadHref(const nsAString &aHref,
nsINode *aSource,

View file

@ -411,6 +411,16 @@ nsStyleLinkElement::DoUpdateStyleSheet(nsIDocument* aOldDocument,
bool doneLoading = false;
nsresult rv = NS_OK;
// Load the link's referrerpolicy attribute. If the link does not provide a
// referrerpolicy attribute, ignore this and use the document's referrer
// policy
net::ReferrerPolicy referrerPolicy = GetLinkReferrerPolicy();
if (referrerPolicy == net::RP_Unset) {
referrerPolicy = doc->GetReferrerPolicy();
}
if (isInline) {
nsAutoString text;
if (!nsContentUtils::GetNodeTextContent(thisContent, false, text, fallible)) {
@ -429,7 +439,7 @@ nsStyleLinkElement::DoUpdateStyleSheet(nsIDocument* aOldDocument,
// Parse the style sheet.
rv = doc->CSSLoader()->
LoadInlineStyle(thisContent, text, mLineNumber, title, media,
LoadInlineStyle(thisContent, text, mLineNumber, title, media, referrerPolicy,
scopeElement, aObserver, &doneLoading, &isAlternate, &isExplicitlyEnabled);
} else {
nsAutoString integrity;
@ -440,15 +450,6 @@ nsStyleLinkElement::DoUpdateStyleSheet(nsIDocument* aOldDocument,
NS_ConvertUTF16toUTF8(integrity).get()));
}
// if referrer attributes are enabled in preferences, load the link's referrer
// attribute. If the link does not provide a referrer attribute, ignore this
// and use the document's referrer policy
net::ReferrerPolicy referrerPolicy = GetLinkReferrerPolicy();
if (referrerPolicy == net::RP_Unset) {
referrerPolicy = doc->GetReferrerPolicy();
}
// XXXbz clone the URI here to work around content policies modifying URIs.
nsCOMPtr<nsIURI> clonedURI;
uri->Clone(getter_AddRefs(clonedURI));

View file

@ -324,6 +324,12 @@ HTMLScriptElement::GetCORSMode() const
return AttrValueToCORSMode(GetParsedAttr(nsGkAtoms::crossorigin));
}
mozilla::net::ReferrerPolicy
HTMLScriptElement::GetReferrerPolicy()
{
return GetReferrerPolicyAsEnum();
}
bool
HTMLScriptElement::HasScriptContent()
{

View file

@ -42,6 +42,7 @@ public:
virtual void GetScriptCharset(nsAString& charset) override;
virtual void FreezeExecutionAttrs(nsIDocument* aOwnerDoc) override;
virtual CORSMode GetCORSMode() const override;
virtual mozilla::net::ReferrerPolicy GetReferrerPolicy() override;
// nsIContent
virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
@ -96,6 +97,14 @@ public:
{
SetHTMLAttr(nsGkAtoms::integrity, aIntegrity, rv);
}
void SetReferrerPolicy(const nsAString& aReferrerPolicy, ErrorResult& aError)
{
SetHTMLAttr(nsGkAtoms::referrerpolicy, aReferrerPolicy, aError);
}
void GetReferrerPolicy(nsAString& aReferrerPolicy)
{
GetEnumAttr(nsGkAtoms::referrerpolicy, EmptyCString().get(), aReferrerPolicy);
}
bool Async();
void SetAsync(bool aValue, ErrorResult& rv);
bool NoModule();

View file

@ -24,7 +24,7 @@ SimpleTest.waitForExplicitFinish();
SimpleTest.waitForFocus(runTests);
function runTests() {
var elements = [ "iframe", "img", "a", "area", "link" ];
var elements = [ "iframe", "img", "a", "area", "link", "script"];
for (var i = 0; i < elements.length; ++i) {
reflectLimitedEnumerated({

View file

@ -1563,7 +1563,7 @@ ScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
// Step 15. and later in the HTML5 spec
nsresult rv = NS_OK;
RefPtr<ScriptLoadRequest> request;
mozilla::net::ReferrerPolicy ourRefPolicy = mDocument->GetReferrerPolicy();
mozilla::net::ReferrerPolicy referrerPolicy = GetReferrerPolicy(aElement);
if (aElement->GetScriptExternal()) {
// external script
nsCOMPtr<nsIURI> scriptURI = aElement->GetScriptURI();
@ -1593,7 +1593,7 @@ ScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
aElement->GetScriptCharset(elementCharset);
if (elementCharset.Equals(preloadCharset) &&
ourCORSMode == request->CORSMode() &&
ourRefPolicy == request->ReferrerPolicy() &&
referrerPolicy == request->ReferrerPolicy() &&
scriptKind == request->mKind) {
rv = CheckContentPolicy(mDocument, aElement, request->mURI, type, false);
if (NS_FAILED(rv)) {
@ -1639,7 +1639,7 @@ ScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
nsCOMPtr<nsIPrincipal> principal = scriptContent->NodePrincipal();
request = CreateLoadRequest(scriptKind, scriptURI, aElement, principal,
ourCORSMode, sriMetadata, ourRefPolicy);
ourCORSMode, sriMetadata, referrerPolicy);
request->mIsInline = false;
request->SetScriptMode(aElement->GetScriptDeferred(),
aElement->GetScriptAsync());
@ -1760,7 +1760,7 @@ ScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
mDocument->NodePrincipal(),
CORS_NONE,
SRIMetadata(), // SRI doesn't apply
ourRefPolicy);
referrerPolicy);
request->mIsInline = true;
request->mLineNo = aElement->GetScriptLineNumber();
@ -1826,6 +1826,17 @@ ScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
return ProcessRequest(request) == NS_ERROR_HTMLPARSER_BLOCK;
}
mozilla::net::ReferrerPolicy
ScriptLoader::GetReferrerPolicy(nsIScriptElement* aElement)
{
mozilla::net::ReferrerPolicy scriptReferrerPolicy =
aElement->GetReferrerPolicy();
if (scriptReferrerPolicy != mozilla::net::RP_Unset) {
return scriptReferrerPolicy;
}
return mDocument->GetReferrerPolicy();
}
namespace {
class NotifyOffThreadScriptLoadCompletedRunnable : public Runnable

View file

@ -619,6 +619,12 @@ private:
void ContinueParserAsync(ScriptLoadRequest* aParserBlockingRequest);
/**
* Given a script element, get the referrer policy that should be applied to
* load requests.
*/
mozilla::net::ReferrerPolicy GetReferrerPolicy(nsIScriptElement* aElement);
/**
* Helper function to check the content policy for a given request.
*/

View file

@ -16,6 +16,7 @@
#include "nsContentCreatorFunctions.h"
#include "nsIDOMHTMLScriptElement.h"
#include "mozilla/CORSMode.h"
#include "mozilla/net/ReferrerPolicy.h"
#define NS_ISCRIPTELEMENT_IID \
{ 0xe60fca9b, 0x1b96, 0x4e4e, \
@ -263,6 +264,14 @@ public:
return mozilla::CORS_NONE;
}
/**
* Get referrer policy of the script element
*/
virtual mozilla::net::ReferrerPolicy GetReferrerPolicy()
{
return mozilla::net::RP_Unset;
}
/**
* Fire an error event
*/

View file

@ -25,6 +25,8 @@ interface HTMLScriptElement : HTMLElement {
[CEReactions, SetterThrows]
attribute DOMString? crossOrigin;
[CEReactions, SetterThrows]
attribute DOMString referrerPolicy;
[CEReactions, SetterThrows]
attribute DOMString text;
[CEReactions, SetterThrows, Pure]
attribute DOMString nonce;

View file

@ -655,7 +655,8 @@ nsXMLContentSink::ProcessStyleLink(nsIContent* aElement,
bool aAlternate,
const nsSubstring& aTitle,
const nsSubstring& aType,
const nsSubstring& aMedia)
const nsSubstring& aMedia,
const nsSubstring& aReferrerPolicy)
{
nsresult rv = NS_OK;
mPrettyPrintXML = false;
@ -714,7 +715,7 @@ nsXMLContentSink::ProcessStyleLink(nsIContent* aElement,
// Let nsContentSink deal with css.
rv = nsContentSink::ProcessStyleLink(aElement, aHref, aAlternate,
aTitle, aType, aMedia);
aTitle, aType, aMedia, aReferrerPolicy);
// nsContentSink::ProcessStyleLink handles the bookkeeping here wrt
// pending sheets.
@ -1261,7 +1262,9 @@ nsXMLContentSink::HandleProcessingInstruction(const char16_t *aTarget,
return DidProcessATokenImpl();
}
rv = ProcessStyleLink(node, href, isAlternate, title, type, media);
// <?xml-stylesheet?> processing instructions don't have a referrerpolicy
// pseudo-attribute, so we pass in an empty string
rv = ProcessStyleLink(node, href, isAlternate, title, type, media, EmptyString());
return NS_SUCCEEDED(rv) ? DidProcessATokenImpl() : rv;
}

View file

@ -150,7 +150,8 @@ protected:
bool aAlternate,
const nsSubstring& aTitle,
const nsSubstring& aType,
const nsSubstring& aMedia) override;
const nsSubstring& aMedia,
const nsSubstring& aReferrerPolicy) override;
nsresult LoadXSLStyleSheet(nsIURI* aUrl);

View file

@ -97,7 +97,9 @@ protected:
bool aAlternate,
const nsSubstring& aTitle,
const nsSubstring& aType,
const nsSubstring& aMedia) override;
const nsSubstring& aMedia,
const nsSubstring& aReferrerPolicy) override;
nsresult LoadXSLStyleSheet(nsIURI* aUrl);
void StartLayout();
@ -332,7 +334,8 @@ nsXMLFragmentContentSink::ProcessStyleLink(nsIContent* aElement,
bool aAlternate,
const nsSubstring& aTitle,
const nsSubstring& aType,
const nsSubstring& aMedia)
const nsSubstring& aMedia,
const nsSubstring& aReferrerPolicy)
{
// don't process until moved to document
return NS_OK;