From cee682b980ea5c6f5b871458a02f3b146233b5b4 Mon Sep 17 00:00:00 2001 From: Andy Date: Wed, 9 Oct 2024 12:08:46 -0700 Subject: [PATCH 1/5] PR #2643 - The border-radius Directive Should Apply to Outlines However, `-moz-outline-radius` should still override any `border-radius`. This is primarily done for backward compatibility with some themes. Additionally, it also allows for more advanced outline control than the CSS spec provides, without breaking spec. Finally, if the spec is ever updated to include `outline-radius`, we'll be ready to drop the `-moz-` prefix! Note: BZ 315209 has an inadvertent double-negative in nsDisplayList.cpp: HasRadius() essentially returns the opposite value it should. --- layout/base/nsCSSRendering.cpp | 57 ++++++++++++++++++---------------- layout/base/nsDisplayList.cpp | 19 +++++++----- layout/base/nsDisplayList.h | 3 ++ layout/style/nsStyleStruct.cpp | 2 ++ 4 files changed, 48 insertions(+), 33 deletions(-) diff --git a/layout/base/nsCSSRendering.cpp b/layout/base/nsCSSRendering.cpp index c683a19605..54f965e9d2 100644 --- a/layout/base/nsCSSRendering.cpp +++ b/layout/base/nsCSSRendering.cpp @@ -855,8 +855,6 @@ nsCSSRendering::PaintOutline(nsPresContext* aPresContext, const nsRect& aBorderArea, nsStyleContext* aStyleContext) { - nscoord twipsRadii[8]; - // Get our style context's color struct. const nsStyleOutline* ourOutline = aStyleContext->StyleOutline(); MOZ_ASSERT(ourOutline != NS_STYLE_BORDER_STYLE_NONE, @@ -898,24 +896,6 @@ nsCSSRendering::PaintOutline(nsPresContext* aPresContext, if (innerRect.Contains(aDirtyRect)) return; - nsRect outerRect = innerRect; - outerRect.Inflate(width, width); - - // get the radius for our outline - nsIFrame::ComputeBorderRadii(ourOutline->mOutlineRadius, aBorderArea.Size(), - outerRect.Size(), Sides(), twipsRadii); - - // Get our conversion values - nscoord twipsPerPixel = aPresContext->DevPixelsToAppUnits(1); - - // get the outer rectangles - Rect oRect(NSRectToRect(outerRect, twipsPerPixel)); - - // convert the radii - nsMargin outlineMargin(width, width, width, width); - RectCornerRadii outlineRadii; - ComputePixelRadii(twipsRadii, twipsPerPixel, &outlineRadii); - if (outlineStyle == NS_STYLE_BORDER_STYLE_AUTO) { if (nsLayoutUtils::IsOutlineStyleAutoEnabled()) { nsITheme* theme = aPresContext->GetTheme(); @@ -935,6 +915,36 @@ nsCSSRendering::PaintOutline(nsPresContext* aPresContext, outlineStyle = NS_STYLE_BORDER_STYLE_SOLID; } + RectCornerRadii outlineRadii; + nsRect outerRect = innerRect; + outerRect.Inflate(width, width); + + const nscoord oneDevPixel = aPresContext->AppUnitsPerDevPixel(); + Rect oRect(NSRectToRect(outerRect, oneDevPixel)); + + const Float outlineWidths[4] = { + Float(width) / oneDevPixel, Float(width) / oneDevPixel, + Float(width) / oneDevPixel, Float(width) / oneDevPixel}; + + // convert the radii + nscoord twipsRadii[8]; + + // get the radius for our outline + if (nsLayoutUtils::HasNonZeroCorner(ourOutline->mOutlineRadius)) { + nsIFrame::ComputeBorderRadii(ourOutline->mOutlineRadius, aBorderArea.Size(), + outerRect.Size(), Sides(), twipsRadii); + ComputePixelRadii(twipsRadii, oneDevPixel, &outlineRadii); + } else if (aForFrame->GetBorderRadii(twipsRadii)) { + RectCornerRadii innerRadii; + ComputePixelRadii(twipsRadii, oneDevPixel, &innerRadii); + + Float devPixelOffset = aPresContext->AppUnitsToFloatDevPixels(offset); + const Float widths[4] = { + outlineWidths[0] + devPixelOffset, outlineWidths[1] + devPixelOffset, + outlineWidths[2] + devPixelOffset, outlineWidths[3] + devPixelOffset}; + nsCSSBorderRenderer::ComputeOuterRadii(innerRadii, widths, &outlineRadii); + } + uint8_t outlineStyles[4] = { outlineStyle, outlineStyle, outlineStyle, outlineStyle }; @@ -947,12 +957,7 @@ nsCSSRendering::PaintOutline(nsPresContext* aPresContext, outlineColor, outlineColor }; - // convert the border widths - Float outlineWidths[4] = { Float(width / twipsPerPixel), - Float(width / twipsPerPixel), - Float(width / twipsPerPixel), - Float(width / twipsPerPixel) }; - Rect dirtyRect = NSRectToRect(aDirtyRect, twipsPerPixel); + Rect dirtyRect = NSRectToRect(aDirtyRect, oneDevPixel); nsIDocument* document = nullptr; nsIContent* content = aForFrame->GetContent(); diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp index fa28ea5f87..825c564211 100644 --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -3757,18 +3757,23 @@ nsDisplayOutline::Paint(nsDisplayListBuilder* aBuilder, mFrame->StyleContext()); } +bool nsDisplayOutline::HasRadius() const { + if (nsLayoutUtils::HasNonZeroCorner(mFrame->StyleOutline()->mOutlineRadius)) { + return true; + } + return nsLayoutUtils::HasNonZeroCorner(mFrame->StyleBorder()->mBorderRadius); +} + bool nsDisplayOutline::IsInvisibleInRect(const nsRect& aRect) { const nsStyleOutline* outline = mFrame->StyleOutline(); nsRect borderBox(ToReferenceFrame(), mFrame->GetSize()); - if (borderBox.Contains(aRect) && - !nsLayoutUtils::HasNonZeroCorner(outline->mOutlineRadius)) { - if (outline->mOutlineOffset >= 0) { - // aRect is entirely inside the border-rect, and the outline isn't - // rendered inside the border-rect, so the outline is not visible. - return true; - } + if (borderBox.Contains(aRect) && !HasRadius() && + outline->mOutlineOffset >= 0) { + // aRect is entirely inside the border-rect, and the outline isn't + // rendered inside the border-rect, so the outline is not visible. + return true; } return false; diff --git a/layout/base/nsDisplayList.h b/layout/base/nsDisplayList.h index 2b4efd86ef..2f3f53b7fc 100644 --- a/layout/base/nsDisplayList.h +++ b/layout/base/nsDisplayList.h @@ -3220,6 +3220,9 @@ public: virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) override; virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) override; NS_DISPLAY_DECL_NAME("Outline", TYPE_OUTLINE) + +private: + bool HasRadius() const; }; /** diff --git a/layout/style/nsStyleStruct.cpp b/layout/style/nsStyleStruct.cpp index 4f95ddaeb0..9de0f13c00 100644 --- a/layout/style/nsStyleStruct.cpp +++ b/layout/style/nsStyleStruct.cpp @@ -510,6 +510,8 @@ nsStyleBorder::CalcDifference(const nsStyleBorder& aNewData) const } } + // Note that border radius is used as a fallback for outline radius, if set. + // Any optimizations here should apply to both. if (mBorderRadius != aNewData.mBorderRadius || !mBorderColors != !aNewData.mBorderColors) { return nsChangeHint_RepaintFrame; From 19c4996881b2d5094bf2d38798d5fc29abd6bba3 Mon Sep 17 00:00:00 2001 From: Moonchild Date: Fri, 11 Oct 2024 22:02:44 +0200 Subject: [PATCH 2/5] Issue #2645 - Fix type confusion for `ResumeKind` It used a mix of uint8_t and uint16_t. Set it to uint16_t. Also don't allow non-typeset to simplify stubs used in compound opcodes. --- js/src/vm/Interpreter.cpp | 7 ++++++- js/src/vm/Opcodes.h | 2 +- js/src/vm/TypeInference.cpp | 4 +--- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index ad52234a31..db5e01803b 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -1960,8 +1960,13 @@ CASE(JSOP_RETRVAL) /* Resume execution in the calling frame. */ if (MOZ_LIKELY(interpReturnOK)) { - TypeScript::Monitor(cx, script, REGS.pc, REGS.sp[-1]); + + if (JSOp(*REGS.pc) == JSOP_RESUME) { + ADVANCE_AND_DISPATCH(JSOP_RESUME_LENGTH); + } + TypeScript::Monitor(cx, script, REGS.pc, REGS.sp[-1]); + MOZ_ASSERT(CodeSpec[*REGS.pc].length == JSOP_CALL_LENGTH); ADVANCE_AND_DISPATCH(JSOP_CALL_LENGTH); } diff --git a/js/src/vm/Opcodes.h b/js/src/vm/Opcodes.h index ad140ff7bc..c5be5f6bef 100644 --- a/js/src/vm/Opcodes.h +++ b/js/src/vm/Opcodes.h @@ -2106,7 +2106,7 @@ * Operands: resume kind (GeneratorObject::ResumeKind) * Stack: gen, val => rval */ \ - macro(JSOP_RESUME, 205,"resume", NULL, 3, 2, 1, JOF_UINT8|JOF_INVOKE) \ + macro(JSOP_RESUME, 205,"resume", NULL, 2, 2, 1, JOF_UINT16|JOF_INVOKE) \ /* * Pops the top two values on the stack as 'obj' and 'v', pushes 'v' to * 'obj'. diff --git a/js/src/vm/TypeInference.cpp b/js/src/vm/TypeInference.cpp index a36926eb94..8ed6e885f8 100644 --- a/js/src/vm/TypeInference.cpp +++ b/js/src/vm/TypeInference.cpp @@ -3335,9 +3335,7 @@ js::TypeMonitorResult(JSContext* cx, JSScript* script, jsbytecode* pc, TypeSet:: void js::TypeMonitorResult(JSContext* cx, JSScript* script, jsbytecode* pc, const js::Value& rval) { - /* Allow the non-TYPESET scenario to simplify stubs used in compound opcodes. */ - if (!(CodeSpec[*pc].format & JOF_TYPESET)) - return; + MOZ_ASSERT(CodeSpec[*pc].format & JOF_TYPESET); if (!script->hasBaselineScript()) return; From f6f046930dbd603819c4b5e96aa2462b569e8d6f Mon Sep 17 00:00:00 2001 From: Moonchild Date: Sun, 20 Oct 2024 09:35:39 +0200 Subject: [PATCH 3/5] Issue #2641 - Speculative load changes for referrerpolicy --- dom/base/nsContentSink.cpp | 28 +++- dom/base/nsContentSink.h | 4 +- dom/base/nsStyleLinkElement.cpp | 21 +-- dom/html/HTMLScriptElement.cpp | 6 + dom/html/HTMLScriptElement.h | 9 ++ dom/html/test/test_bug1260664.html | 2 +- dom/script/ScriptLoader.cpp | 19 ++- dom/script/ScriptLoader.h | 6 + dom/script/nsIScriptElement.h | 9 ++ dom/webidl/HTMLScriptElement.webidl | 2 + dom/xml/nsXMLContentSink.cpp | 9 +- dom/xml/nsXMLContentSink.h | 3 +- dom/xml/nsXMLFragmentContentSink.cpp | 7 +- layout/style/Loader.cpp | 6 +- layout/style/Loader.h | 2 + parser/html/nsHtml5SpeculativeLoad.cpp | 52 ++++--- parser/html/nsHtml5SpeculativeLoad.h | 130 ++++++++++-------- parser/html/nsHtml5TreeBuilderCppSupplement.h | 21 ++- parser/html/nsHtml5TreeOpExecutor.cpp | 50 ++++--- parser/html/nsHtml5TreeOpExecutor.h | 4 + 20 files changed, 262 insertions(+), 128 deletions(-) diff --git a/dom/base/nsContentSink.cpp b/dom/base/nsContentSink.cpp index 26e1ea5f89..066ec84466 100644 --- a/dom/base/nsContentSink.cpp +++ b/dom/base/nsContentSink.cpp @@ -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); diff --git a/dom/base/nsContentSink.h b/dom/base/nsContentSink.h index bed7392ca3..d6605af8d9 100644 --- a/dom/base/nsContentSink.h +++ b/dom/base/nsContentSink.h @@ -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, diff --git a/dom/base/nsStyleLinkElement.cpp b/dom/base/nsStyleLinkElement.cpp index 7a0a563350..971af21b4c 100644 --- a/dom/base/nsStyleLinkElement.cpp +++ b/dom/base/nsStyleLinkElement.cpp @@ -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 clonedURI; uri->Clone(getter_AddRefs(clonedURI)); diff --git a/dom/html/HTMLScriptElement.cpp b/dom/html/HTMLScriptElement.cpp index 48fa96ac90..a1a58e4fa2 100644 --- a/dom/html/HTMLScriptElement.cpp +++ b/dom/html/HTMLScriptElement.cpp @@ -324,6 +324,12 @@ HTMLScriptElement::GetCORSMode() const return AttrValueToCORSMode(GetParsedAttr(nsGkAtoms::crossorigin)); } +mozilla::net::ReferrerPolicy +HTMLScriptElement::GetReferrerPolicy() +{ + return GetReferrerPolicyAsEnum(); +} + bool HTMLScriptElement::HasScriptContent() { diff --git a/dom/html/HTMLScriptElement.h b/dom/html/HTMLScriptElement.h index a80f0262a1..b9affc49a1 100644 --- a/dom/html/HTMLScriptElement.h +++ b/dom/html/HTMLScriptElement.h @@ -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(); diff --git a/dom/html/test/test_bug1260664.html b/dom/html/test/test_bug1260664.html index f034328956..9bc43fdb3c 100644 --- a/dom/html/test/test_bug1260664.html +++ b/dom/html/test/test_bug1260664.html @@ -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({ diff --git a/dom/script/ScriptLoader.cpp b/dom/script/ScriptLoader.cpp index d7553b024e..01b03c3f27 100644 --- a/dom/script/ScriptLoader.cpp +++ b/dom/script/ScriptLoader.cpp @@ -1563,7 +1563,7 @@ ScriptLoader::ProcessScriptElement(nsIScriptElement *aElement) // Step 15. and later in the HTML5 spec nsresult rv = NS_OK; RefPtr request; - mozilla::net::ReferrerPolicy ourRefPolicy = mDocument->GetReferrerPolicy(); + mozilla::net::ReferrerPolicy referrerPolicy = GetReferrerPolicy(aElement); if (aElement->GetScriptExternal()) { // external script nsCOMPtr 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 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 diff --git a/dom/script/ScriptLoader.h b/dom/script/ScriptLoader.h index 6cf108e331..f66c9ede1d 100644 --- a/dom/script/ScriptLoader.h +++ b/dom/script/ScriptLoader.h @@ -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. */ diff --git a/dom/script/nsIScriptElement.h b/dom/script/nsIScriptElement.h index a654291aa0..6a6f985d33 100644 --- a/dom/script/nsIScriptElement.h +++ b/dom/script/nsIScriptElement.h @@ -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 */ diff --git a/dom/webidl/HTMLScriptElement.webidl b/dom/webidl/HTMLScriptElement.webidl index 6b48a52443..bb9618428a 100644 --- a/dom/webidl/HTMLScriptElement.webidl +++ b/dom/webidl/HTMLScriptElement.webidl @@ -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; diff --git a/dom/xml/nsXMLContentSink.cpp b/dom/xml/nsXMLContentSink.cpp index 7db1ea4a6a..2125416d73 100644 --- a/dom/xml/nsXMLContentSink.cpp +++ b/dom/xml/nsXMLContentSink.cpp @@ -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); + // 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; } diff --git a/dom/xml/nsXMLContentSink.h b/dom/xml/nsXMLContentSink.h index ea190954a2..d7399349e8 100644 --- a/dom/xml/nsXMLContentSink.h +++ b/dom/xml/nsXMLContentSink.h @@ -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); diff --git a/dom/xml/nsXMLFragmentContentSink.cpp b/dom/xml/nsXMLFragmentContentSink.cpp index a4bb406351..664fbbeb6a 100644 --- a/dom/xml/nsXMLFragmentContentSink.cpp +++ b/dom/xml/nsXMLFragmentContentSink.cpp @@ -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; diff --git a/layout/style/Loader.cpp b/layout/style/Loader.cpp index 4e1a1d6fe1..3b445eb567 100644 --- a/layout/style/Loader.cpp +++ b/layout/style/Loader.cpp @@ -1941,6 +1941,7 @@ Loader::LoadInlineStyle(nsIContent* aElement, uint32_t aLineNumber, const nsAString& aTitle, const nsAString& aMedia, + ReferrerPolicy aReferrerPolicy, Element* aScopeElement, nsICSSLoaderObserver* aObserver, bool* aCompleted, @@ -1964,11 +1965,12 @@ Loader::LoadInlineStyle(nsIContent* aElement, // Since we're not planning to load a URI, no need to hand a principal to the // load data or to CreateSheet(). Also, OK to use CORS_NONE for the CORS - // mode and mDocument's ReferrerPolicy. + // mode. + StyleSheetState state; RefPtr sheet; nsresult rv = CreateSheet(nullptr, aElement, nullptr, eAuthorSheetFeatures, - CORS_NONE, mDocument->GetReferrerPolicy(), + CORS_NONE, aReferrerPolicy, EmptyString(), // no inline integrity checks false, false, aTitle, state, aIsAlternate, &sheet); diff --git a/layout/style/Loader.h b/layout/style/Loader.h index c9af2f39e8..2319164a2f 100644 --- a/layout/style/Loader.h +++ b/layout/style/Loader.h @@ -224,6 +224,7 @@ public: * @param aLineNumber the line number at which the stylesheet data started. * @param aTitle the title of the sheet. * @param aMedia the media string for the sheet. + * @param aReferrerPolicy the referrer policy for loading the sheet. * @param aObserver the observer to notify when the load completes. * May be null. * @param [out] aCompleted whether parsing of the sheet completed. @@ -237,6 +238,7 @@ public: uint32_t aLineNumber, const nsAString& aTitle, const nsAString& aMedia, + ReferrerPolicy aReferrerPolicy, mozilla::dom::Element* aScopeElement, nsICSSLoaderObserver* aObserver, bool* aCompleted, diff --git a/parser/html/nsHtml5SpeculativeLoad.cpp b/parser/html/nsHtml5SpeculativeLoad.cpp index 35c11b739d..14e8f9ea9c 100644 --- a/parser/html/nsHtml5SpeculativeLoad.cpp +++ b/parser/html/nsHtml5SpeculativeLoad.cpp @@ -28,16 +28,18 @@ nsHtml5SpeculativeLoad::Perform(nsHtml5TreeOpExecutor* aExecutor) { switch (mOpCode) { case eSpeculativeLoadBase: - aExecutor->SetSpeculationBase(mUrl); + aExecutor->SetSpeculationBase(mUrlOrSizes); break; case eSpeculativeLoadCSP: - aExecutor->AddSpeculationCSP(mMetaCSP); + aExecutor->AddSpeculationCSP(mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity); break; case eSpeculativeLoadMetaReferrer: - aExecutor->SetSpeculationReferrerPolicy(mReferrerPolicy); + aExecutor->SetSpeculationReferrerPolicy(mReferrerPolicyOrIntegrity); break; case eSpeculativeLoadImage: - aExecutor->PreloadImage(mUrl, mCrossOrigin, mSrcset, mSizes, mReferrerPolicy); + aExecutor->PreloadImage(mUrlOrSizes, mCrossOriginOrMedia, mCharsetOrSrcset, + mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity, + mReferrerPolicyOrIntegrity); break; case eSpeculativeLoadOpenPicture: aExecutor->PreloadOpenPicture(); @@ -46,55 +48,61 @@ nsHtml5SpeculativeLoad::Perform(nsHtml5TreeOpExecutor* aExecutor) aExecutor->PreloadEndPicture(); break; case eSpeculativeLoadPictureSource: - aExecutor->PreloadPictureSource(mSrcset, mSizes, mTypeOrCharsetSourceOrDocumentMode, - mMedia); + aExecutor->PreloadPictureSource(mCharsetOrSrcset, mUrlOrSizes, + mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity, + mCrossOriginOrMedia); break; case eSpeculativeLoadScript: - aExecutor->PreloadScript(mUrl, mCharset, mTypeOrCharsetSourceOrDocumentMode, - mCrossOrigin, mIntegrity, false, + aExecutor->PreloadScript(mUrlOrSizes, mCharsetOrSrcset, + mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity, + mCrossOriginOrMedia, mReferrerPolicyOrIntegrity, mScriptReferrerPolicy, false, mIsAsync, mIsDefer, false); break; case eSpeculativeLoadScriptFromHead: - aExecutor->PreloadScript(mUrl, mCharset, mTypeOrCharsetSourceOrDocumentMode, - mCrossOrigin, mIntegrity, true, + aExecutor->PreloadScript(mUrlOrSizes, mCharsetOrSrcset, + mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity, + mCrossOriginOrMedia, mReferrerPolicyOrIntegrity, mScriptReferrerPolicy, true, mIsAsync, mIsDefer, false); break; case eSpeculativeLoadNoModuleScript: - aExecutor->PreloadScript(mUrl, mCharset, mTypeOrCharsetSourceOrDocumentMode, - mCrossOrigin, mIntegrity, false, + aExecutor->PreloadScript(mUrlOrSizes, mCharsetOrSrcset, + mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity, + mCrossOriginOrMedia, mReferrerPolicyOrIntegrity, mScriptReferrerPolicy, false, mIsAsync, mIsDefer, true); break; case eSpeculativeLoadNoModuleScriptFromHead: - aExecutor->PreloadScript(mUrl, mCharset, mTypeOrCharsetSourceOrDocumentMode, - mCrossOrigin, mIntegrity, true, + aExecutor->PreloadScript(mUrlOrSizes, mCharsetOrSrcset, + mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity, + mCrossOriginOrMedia, mReferrerPolicyOrIntegrity, mScriptReferrerPolicy, true, mIsAsync, mIsDefer, true); break; case eSpeculativeLoadStyle: - aExecutor->PreloadStyle(mUrl, mCharset, mCrossOrigin, mIntegrity); + aExecutor->PreloadStyle(mUrlOrSizes, mCharsetOrSrcset, mCrossOriginOrMedia, mReferrerPolicyOrIntegrity, + mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity); break; case eSpeculativeLoadManifest: - aExecutor->ProcessOfflineManifest(mUrl); + aExecutor->ProcessOfflineManifest(mUrlOrSizes); break; case eSpeculativeLoadSetDocumentCharset: { nsAutoCString narrowName; - CopyUTF16toUTF8(mCharset, narrowName); - NS_ASSERTION(mTypeOrCharsetSourceOrDocumentMode.Length() == 1, + CopyUTF16toUTF8(mCharsetOrSrcset, narrowName); + NS_ASSERTION(mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity.Length() == 1, "Unexpected charset source string"); - int32_t intSource = (int32_t)mTypeOrCharsetSourceOrDocumentMode.First(); + int32_t intSource = (int32_t)mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity.First(); aExecutor->SetDocumentCharsetAndSource(narrowName, intSource); } break; case eSpeculativeLoadSetDocumentMode: { - NS_ASSERTION(mTypeOrCharsetSourceOrDocumentMode.Length() == 1, + NS_ASSERTION(mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity.Length() == 1, "Unexpected document mode string"); nsHtml5DocumentMode mode = - (nsHtml5DocumentMode)mTypeOrCharsetSourceOrDocumentMode.First(); + (nsHtml5DocumentMode)mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity.First(); aExecutor->SetDocumentMode(mode); } break; case eSpeculativeLoadPreconnect: - aExecutor->Preconnect(mUrl, mCrossOrigin); + aExecutor->Preconnect(mUrlOrSizes, mCrossOriginOrMedia); break; default: NS_NOTREACHED("Bogus speculative load."); diff --git a/parser/html/nsHtml5SpeculativeLoad.h b/parser/html/nsHtml5SpeculativeLoad.h index 1f4a617416..d9467d3875 100644 --- a/parser/html/nsHtml5SpeculativeLoad.h +++ b/parser/html/nsHtml5SpeculativeLoad.h @@ -7,6 +7,7 @@ #include "nsString.h" #include "nsContentUtils.h" +#include "mozilla/net/ReferrerPolicy.h" class nsHtml5TreeOpExecutor; @@ -43,7 +44,7 @@ class nsHtml5SpeculativeLoad { NS_PRECONDITION(mOpCode == eSpeculativeLoadUninitialized, "Trying to reinitialize a speculative load!"); mOpCode = eSpeculativeLoadBase; - aUrl.ToString(mUrl); + aUrl.ToString(mUrlOrSizes); } inline void InitMetaCSP(nsHtml5String aCSP) @@ -53,7 +54,7 @@ class nsHtml5SpeculativeLoad { mOpCode = eSpeculativeLoadCSP; nsString csp; // Not Auto, because using it to hold nsStringBuffer* aCSP.ToString(csp); - mMetaCSP.Assign( + mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity.Assign( nsContentUtils::TrimWhitespace(csp)); } @@ -65,7 +66,7 @@ class nsHtml5SpeculativeLoad { nsString referrerPolicy; // Not Auto, because using it to hold nsStringBuffer* aReferrerPolicy.ToString(referrerPolicy); - mReferrerPolicy.Assign( + mReferrerPolicyOrIntegrity.Assign( nsContentUtils::TrimWhitespace( referrerPolicy)); } @@ -79,16 +80,16 @@ class nsHtml5SpeculativeLoad { NS_PRECONDITION(mOpCode == eSpeculativeLoadUninitialized, "Trying to reinitialize a speculative load!"); mOpCode = eSpeculativeLoadImage; - aUrl.ToString(mUrl); - aCrossOrigin.ToString(mCrossOrigin); + aUrl.ToString(mUrlOrSizes); + aCrossOrigin.ToString(mCrossOriginOrMedia); nsString referrerPolicy; // Not Auto, because using it to hold nsStringBuffer* aReferrerPolicy.ToString(referrerPolicy); - mReferrerPolicy.Assign( + mReferrerPolicyOrIntegrity.Assign( nsContentUtils::TrimWhitespace( referrerPolicy)); - aSrcset.ToString(mSrcset); - aSizes.ToString(mSizes); + aSrcset.ToString(mCharsetOrSrcset); + aSizes.ToString(mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity); } // elements have multiple nodes followed by an , @@ -120,10 +121,10 @@ class nsHtml5SpeculativeLoad { NS_PRECONDITION(mOpCode == eSpeculativeLoadUninitialized, "Trying to reinitialize a speculative load!"); mOpCode = eSpeculativeLoadPictureSource; - aSrcset.ToString(mSrcset); - aSizes.ToString(mSizes); - aType.ToString(mTypeOrCharsetSourceOrDocumentMode); - aMedia.ToString(mMedia); + aSrcset.ToString(mCharsetOrSrcset); + aSizes.ToString(mUrlOrSizes); + aType.ToString(mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity); + aMedia.ToString(mCrossOriginOrMedia); } inline void InitScript(nsHtml5String aUrl, @@ -131,6 +132,7 @@ class nsHtml5SpeculativeLoad { nsHtml5String aType, nsHtml5String aCrossOrigin, nsHtml5String aIntegrity, + nsHtml5String aReferrerPolicy, bool aParserInHead, bool aAsync, bool aDefer, @@ -145,11 +147,19 @@ class nsHtml5SpeculativeLoad { mOpCode = aParserInHead ? eSpeculativeLoadScriptFromHead : eSpeculativeLoadScript; } - aUrl.ToString(mUrl); - aCharset.ToString(mCharset); - aType.ToString(mTypeOrCharsetSourceOrDocumentMode); - aCrossOrigin.ToString(mCrossOrigin); - aIntegrity.ToString(mIntegrity); + aUrl.ToString(mUrlOrSizes); + aCharset.ToString(mCharsetOrSrcset); + aType.ToString(mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity); + aCrossOrigin.ToString(mCrossOriginOrMedia); + aIntegrity.ToString(mReferrerPolicyOrIntegrity); + nsAutoString referrerPolicy; + aReferrerPolicy.ToString(referrerPolicy); + referrerPolicy = + nsContentUtils::TrimWhitespace< + nsContentUtils::IsHTMLWhitespace>(referrerPolicy); + mScriptReferrerPolicy = + mozilla::net::AttributeReferrerPolicyFromString(referrerPolicy); + mIsAsync = aAsync; mIsDefer = aDefer; } @@ -157,15 +167,22 @@ class nsHtml5SpeculativeLoad { inline void InitStyle(nsHtml5String aUrl, nsHtml5String aCharset, nsHtml5String aCrossOrigin, + nsHtml5String aReferrerPolicy, nsHtml5String aIntegrity) { NS_PRECONDITION(mOpCode == eSpeculativeLoadUninitialized, "Trying to reinitialize a speculative load!"); mOpCode = eSpeculativeLoadStyle; - aUrl.ToString(mUrl); - aCharset.ToString(mCharset); - aCrossOrigin.ToString(mCrossOrigin); - aIntegrity.ToString(mIntegrity); + aUrl.ToString(mUrlOrSizes); + aCharset.ToString(mCharsetOrSrcset); + aCrossOrigin.ToString(mCrossOriginOrMedia); + nsString + referrerPolicy; // Not Auto, because using it to hold nsStringBuffer* + aReferrerPolicy.ToString(referrerPolicy); + mReferrerPolicyOrIntegrity.Assign( + nsContentUtils::TrimWhitespace( + referrerPolicy)); + aIntegrity.ToString(mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity); } /** @@ -184,7 +201,7 @@ class nsHtml5SpeculativeLoad { NS_PRECONDITION(mOpCode == eSpeculativeLoadUninitialized, "Trying to reinitialize a speculative load!"); mOpCode = eSpeculativeLoadManifest; - aUrl.ToString(mUrl); + aUrl.ToString(mUrlOrSizes); } /** @@ -203,8 +220,8 @@ class nsHtml5SpeculativeLoad { NS_PRECONDITION(mOpCode == eSpeculativeLoadUninitialized, "Trying to reinitialize a speculative load!"); mOpCode = eSpeculativeLoadSetDocumentCharset; - CopyUTF8toUTF16(aCharset, mCharset); - mTypeOrCharsetSourceOrDocumentMode.Assign((char16_t)aCharsetSource); + CopyUTF8toUTF16(aCharset, mCharsetOrSrcset); + mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity.Assign((char16_t)aCharsetSource); } /** @@ -218,7 +235,7 @@ class nsHtml5SpeculativeLoad { NS_PRECONDITION(mOpCode == eSpeculativeLoadUninitialized, "Trying to reinitialize a speculative load!"); mOpCode = eSpeculativeLoadSetDocumentMode; - mTypeOrCharsetSourceOrDocumentMode.Assign((char16_t)aMode); + mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity.Assign((char16_t)aMode); } inline void InitPreconnect(nsHtml5String aUrl, nsHtml5String aCrossOrigin) @@ -226,8 +243,8 @@ class nsHtml5SpeculativeLoad { NS_PRECONDITION(mOpCode == eSpeculativeLoadUninitialized, "Trying to reinitialize a speculative load!"); mOpCode = eSpeculativeLoadPreconnect; - aUrl.ToString(mUrl); - aCrossOrigin.ToString(mCrossOrigin); + aUrl.ToString(mUrlOrSizes); + aCrossOrigin.ToString(mCrossOriginOrMedia); } void Perform(nsHtml5TreeOpExecutor* aExecutor); @@ -241,55 +258,56 @@ class nsHtml5SpeculativeLoad { bool mIsAsync; bool mIsDefer; - nsString mUrl; - nsString mReferrerPolicy; - nsString mMetaCSP; + /* If mOpCode is eSpeculativeLoadPictureSource, this is the value of the + * "sizes" attribute. If the attribute is not set, this will be a void + * string. Otherwise it empty or the value of the url. + */ + nsString mUrlOrSizes; + /** + * If mOpCode is eSpeculativeLoadScript[FromHead], 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 referrer policy. + */ + nsString mReferrerPolicyOrIntegrity; /** * If mOpCode is eSpeculativeLoadStyle or eSpeculativeLoadScript[FromHead] * then this is the value of the "charset" attribute. For * eSpeculativeLoadSetDocumentCharset it is the charset that the - * document's charset is being set to. Otherwise it's empty. + * document's charset is being set to. If mOpCode is eSpeculativeLoadImage + * or eSpeculativeLoadPictureSource, this is the value of the "srcset" attribute. + * If the attribute is not set, this will be a void string. Otherwise it's empty. */ - nsString mCharset; + nsString mCharsetOrSrcset; /** * If mOpCode is eSpeculativeLoadSetDocumentCharset, this is a * one-character string whose single character's code point is to be * interpreted as a charset source integer. If mOpCode is * eSpeculativeLoadSetDocumentMode, this is a one-character string whose * single character's code point is to be interpreted as an - * nsHtml5DocumentMode. Otherwise, it is empty or the value of the type - * attribute. + * nsHtml5DocumentMode. If mOpCode is eSpeculativeLoadCSP, this is a meta + * element's CSP value. If mOpCode is eSpeculativeLoadImage, this is the + * 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 + * referrer policy. Otherwise, it is empty or the value of the type attribute. */ - nsString mTypeOrCharsetSourceOrDocumentMode; + nsString mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity; /** * If mOpCode is eSpeculativeLoadImage or eSpeculativeLoadScript[FromHead] * or eSpeculativeLoadPreconnect this is the value of the "crossorigin" * attribute. If the attribute is not set, this will be a void string. + * If mOpCode is eSpeculativeLoadPictureSource, this is the value of the + * "media" attribute. If the attribute is not set, this will be a void string. */ - nsString mCrossOrigin; + nsString mCrossOriginOrMedia; /** - * If mOpCode is eSpeculativeLoadImage or eSpeculativeLoadPictureSource, - * this is the value of "srcset" attribute. If the attribute is not set, - * this will be a void string. + * If mOpCode is eSpeculativeLoadScript[FromHead] this represents the value + * of the "referrerpolicy" attribute. This field holds one of the values + * (REFERRER_POLICY_*) defined in nsIHttpChannel. */ - nsString mSrcset; - /** - * If mOpCode is eSpeculativeLoadPictureSource, this is the value of "sizes" - * attribute. If the attribute is not set, this will be a void string. - */ - nsString mSizes; - /** - * If mOpCode is eSpeculativeLoadPictureSource, this is the value of "media" - * attribute. If the attribute is not set, this will be a void string. - */ - nsString mMedia; - /** - * If mOpCode is eSpeculativeLoadScript[FromHead], this is the value of the - * "integrity" attribute. If the attribute is not set, this will be a void - * string. - */ - nsString mIntegrity; + mozilla::net::ReferrerPolicy mScriptReferrerPolicy; }; #endif // nsHtml5SpeculativeLoad_h diff --git a/parser/html/nsHtml5TreeBuilderCppSupplement.h b/parser/html/nsHtml5TreeBuilderCppSupplement.h index a3a7e92155..d17216b758 100644 --- a/parser/html/nsHtml5TreeBuilderCppSupplement.h +++ b/parser/html/nsHtml5TreeBuilderCppSupplement.h @@ -184,6 +184,8 @@ nsHtml5TreeBuilder::createElement(int32_t aNamespace, aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN); nsHtml5String integrity = aAttributes->getValue(nsHtml5AttributeName::ATTR_INTEGRITY); + nsHtml5String referrerPolicy = + aAttributes->getValue(nsHtml5AttributeName::ATTR_REFERRERPOLICY); bool async = aAttributes->contains(nsHtml5AttributeName::ATTR_ASYNC); bool defer = @@ -196,6 +198,7 @@ nsHtml5TreeBuilder::createElement(int32_t aNamespace, type, crossOrigin, integrity, + referrerPolicy, mode == nsHtml5TreeBuilder::IN_HEAD, async, defer, @@ -218,8 +221,10 @@ nsHtml5TreeBuilder::createElement(int32_t aNamespace, aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN); nsHtml5String integrity = aAttributes->getValue(nsHtml5AttributeName::ATTR_INTEGRITY); + nsHtml5String referrerPolicy = + aAttributes->getValue(nsHtml5AttributeName::ATTR_REFERRERPOLICY); mSpeculativeLoadQueue.AppendElement()->InitStyle( - url, charset, crossOrigin, integrity); + url, charset, crossOrigin, referrerPolicy, integrity); } } else if (rel.LowerCaseEqualsASCII("preconnect")) { nsHtml5String url = @@ -245,12 +250,15 @@ nsHtml5TreeBuilder::createElement(int32_t aNamespace, aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN); nsHtml5String integrity = aAttributes->getValue(nsHtml5AttributeName::ATTR_INTEGRITY); + nsHtml5String referrerPolicy = + aAttributes->getValue(nsHtml5AttributeName::ATTR_REFERRERPOLICY); mSpeculativeLoadQueue.AppendElement()->InitScript( url, charset, type, crossOrigin, integrity, + referrerPolicy, mode == nsHtml5TreeBuilder::IN_HEAD, false, false, @@ -263,8 +271,10 @@ nsHtml5TreeBuilder::createElement(int32_t aNamespace, aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN); nsHtml5String integrity = aAttributes->getValue(nsHtml5AttributeName::ATTR_INTEGRITY); + nsHtml5String referrerPolicy = + aAttributes->getValue(nsHtml5AttributeName::ATTR_REFERRERPOLICY); mSpeculativeLoadQueue.AppendElement()->InitStyle( - url, charset, crossOrigin, integrity); + url, charset, crossOrigin, referrerPolicy, integrity); } else if (preloadAs.LowerCaseEqualsASCII("image")) { nsHtml5String srcset = aAttributes->getValue(nsHtml5AttributeName::ATTR_SRCSET); @@ -345,12 +355,15 @@ nsHtml5TreeBuilder::createElement(int32_t aNamespace, aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN); nsHtml5String integrity = aAttributes->getValue(nsHtml5AttributeName::ATTR_INTEGRITY); + nsHtml5String referrerPolicy = + aAttributes->getValue(nsHtml5AttributeName::ATTR_REFERRERPOLICY); mSpeculativeLoadQueue.AppendElement()->InitScript( url, nullptr, type, crossOrigin, integrity, + referrerPolicy, mode == nsHtml5TreeBuilder::IN_HEAD, false /* async */, false /* defer */, @@ -368,8 +381,10 @@ nsHtml5TreeBuilder::createElement(int32_t aNamespace, aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN); nsHtml5String integrity = aAttributes->getValue(nsHtml5AttributeName::ATTR_INTEGRITY); + nsHtml5String referrerPolicy = + aAttributes->getValue(nsHtml5AttributeName::ATTR_REFERRERPOLICY); mSpeculativeLoadQueue.AppendElement()->InitStyle( - url, nullptr, crossOrigin, integrity); + url, nullptr, crossOrigin, referrerPolicy, integrity); } } break; diff --git a/parser/html/nsHtml5TreeOpExecutor.cpp b/parser/html/nsHtml5TreeOpExecutor.cpp index 33fb3d0c7d..7fe1fdd39e 100644 --- a/parser/html/nsHtml5TreeOpExecutor.cpp +++ b/parser/html/nsHtml5TreeOpExecutor.cpp @@ -914,12 +914,23 @@ nsHtml5TreeOpExecutor::ShouldPreloadURI(nsIURI *aURI) return true; } +net::ReferrerPolicy +nsHtml5TreeOpExecutor::GetPreloadReferrerPolicy( + const nsAString& aReferrerPolicy) +{ + net::ReferrerPolicy referrerPolicy = + net::AttributeReferrerPolicyFromString(aReferrerPolicy); + return referrerPolicy != net::RP_Unset ? referrerPolicy : + mSpeculationReferrerPolicy; +} + void nsHtml5TreeOpExecutor::PreloadScript(const nsAString& aURL, const nsAString& aCharset, const nsAString& aType, const nsAString& aCrossOrigin, const nsAString& aIntegrity, + net::ReferrerPolicy aReferrerPolicy, bool aScriptFromHead, bool aAsync, bool aDefer, @@ -929,24 +940,35 @@ nsHtml5TreeOpExecutor::PreloadScript(const nsAString& aURL, if (!uri) { return; } - mDocument->ScriptLoader()->PreloadURI(uri, aCharset, aType, aCrossOrigin, - aIntegrity, aScriptFromHead, aAsync, - aDefer, aNoModule, - mSpeculationReferrerPolicy); + net::ReferrerPolicy referrerPolicy = aReferrerPolicy != net::RP_Unset ? + aReferrerPolicy : mSpeculationReferrerPolicy; + mDocument->ScriptLoader() + ->PreloadURI(uri, + aCharset, + aType, + aCrossOrigin, + aIntegrity, + aScriptFromHead, + aAsync, + aDefer, + aNoModule, + referrerPolicy); } void nsHtml5TreeOpExecutor::PreloadStyle(const nsAString& aURL, const nsAString& aCharset, const nsAString& aCrossOrigin, + const nsAString& aReferrerPolicy, const nsAString& aIntegrity) { nsCOMPtr uri = ConvertIfNotPreloadedYet(aURL); if (!uri) { return; } - mDocument->PreloadStyle(uri, aCharset, aCrossOrigin, - mSpeculationReferrerPolicy, aIntegrity); + + mDocument->PreloadStyle(uri, aCharset, aCrossOrigin, GetPreloadReferrerPolicy(aReferrerPolicy), + aIntegrity); } void @@ -962,18 +984,10 @@ nsHtml5TreeOpExecutor::PreloadImage(const nsAString& aURL, aSizes, &isImgSet); if (uri && ShouldPreloadURI(uri)) { // use document wide referrer policy - mozilla::net::ReferrerPolicy referrerPolicy = mSpeculationReferrerPolicy; - // if enabled in preferences, use the referrer attribute from the image, if provided - bool referrerAttributeEnabled = Preferences::GetBool("network.http.enablePerElementReferrer", true); - if (referrerAttributeEnabled) { - mozilla::net::ReferrerPolicy imageReferrerPolicy = - mozilla::net::AttributeReferrerPolicyFromString(aImageReferrerPolicy); - if (imageReferrerPolicy != mozilla::net::RP_Unset) { - referrerPolicy = imageReferrerPolicy; - } - } - - mDocument->MaybePreLoadImage(uri, aCrossOrigin, referrerPolicy, isImgSet); + mDocument->MaybePreLoadImage(uri, + aCrossOrigin, + GetPreloadReferrerPolicy(aImageReferrerPolicy), + isImgSet); } } diff --git a/parser/html/nsHtml5TreeOpExecutor.h b/parser/html/nsHtml5TreeOpExecutor.h index 878f359c55..6a1a9e674a 100644 --- a/parser/html/nsHtml5TreeOpExecutor.h +++ b/parser/html/nsHtml5TreeOpExecutor.h @@ -249,6 +249,7 @@ class nsHtml5TreeOpExecutor final : public nsHtml5DocumentBuilder, const nsAString& aType, const nsAString& aCrossOrigin, const nsAString& aIntegrity, + ReferrerPolicy aReferrerPolicy, bool aScriptFromHead, bool aAsync, bool aDefer, @@ -256,6 +257,7 @@ class nsHtml5TreeOpExecutor final : public nsHtml5DocumentBuilder, void PreloadStyle(const nsAString& aURL, const nsAString& aCharset, const nsAString& aCrossOrigin, + const nsAString& aReferrerPolicy, const nsAString& aIntegrity); void PreloadImage(const nsAString& aURL, @@ -304,6 +306,8 @@ class nsHtml5TreeOpExecutor final : public nsHtml5DocumentBuilder, * list of preloaded URIs */ bool ShouldPreloadURI(nsIURI *aURI); + + ReferrerPolicy GetPreloadReferrerPolicy(const nsAString& aReferrerPolicy); }; #endif // nsHtml5TreeOpExecutor_h From 7d978ccd713df4b7c02a8c06f81d2f965f9ce836 Mon Sep 17 00:00:00 2001 From: Moonchild Date: Sun, 20 Oct 2024 11:23:30 +0200 Subject: [PATCH 4/5] Issue #2641 - Update Fetch to adhere to the updated spec (pass refpolicy) Resolves #2641 --- dom/base/nsContentUtils.cpp | 6 +- dom/cache/DBSchema.cpp | 5 +- dom/fetch/FetchDriver.cpp | 105 ++++++-------------- dom/fetch/FetchUtil.cpp | 56 +++++++++++ dom/fetch/FetchUtil.h | 13 +++ dom/fetch/InternalRequest.h | 66 ++++++++++++ dom/webidl/Request.webidl | 6 +- dom/workers/ScriptLoader.cpp | 4 +- dom/workers/ServiceWorkerPrivate.cpp | 16 +++ dom/xhr/XMLHttpRequestMainThread.cpp | 5 +- netwerk/protocol/http/HttpBaseChannel.cpp | 4 +- netwerk/protocol/http/HttpChannelChild.cpp | 37 ++++++- netwerk/protocol/http/HttpChannelChild.h | 1 + netwerk/protocol/http/HttpChannelParent.cpp | 5 + netwerk/protocol/http/HttpChannelParent.h | 2 + netwerk/protocol/http/PHttpChannel.ipdl | 4 +- 16 files changed, 244 insertions(+), 91 deletions(-) diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index 624f9c502f..5d5edbd3b3 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -8868,10 +8868,8 @@ nsContentUtils::SetFetchReferrerURIWithPolicy(nsIPrincipal* aPrincipal, referrerURI = principalURI; } - net::ReferrerPolicy referrerPolicy = aReferrerPolicy; - if (referrerPolicy == net::RP_Default) { - referrerPolicy = aDoc->GetReferrerPolicy(); - } + net::ReferrerPolicy referrerPolicy = (aReferrerPolicy != net::RP_Unset) ? + aReferrerPolicy : net::RP_Default; return aChannel->SetReferrerWithPolicy(referrerURI, referrerPolicy); } diff --git a/dom/cache/DBSchema.cpp b/dom/cache/DBSchema.cpp index 953aacb14e..7b8c2af8b6 100644 --- a/dom/cache/DBSchema.cpp +++ b/dom/cache/DBSchema.cpp @@ -196,7 +196,10 @@ static_assert(int(ReferrerPolicy::_empty) == 0 && int(ReferrerPolicy::Origin) == 3 && int(ReferrerPolicy::Origin_when_cross_origin) == 4 && int(ReferrerPolicy::Unsafe_url) == 5 && - int(ReferrerPolicy::EndGuard_) == 6, + int(ReferrerPolicy::Same_origin) == 6 && + int(ReferrerPolicy::Strict_origin) == 7 && + int(ReferrerPolicy::Strict_origin_when_cross_origin) == 8 && + int(ReferrerPolicy::EndGuard_) == 9, "ReferrerPolicy values are as expected"); static_assert(int(RequestMode::Same_origin) == 0 && int(RequestMode::No_cors) == 1 && diff --git a/dom/fetch/FetchDriver.cpp b/dom/fetch/FetchDriver.cpp index 0198cc44aa..e0f369206d 100644 --- a/dom/fetch/FetchDriver.cpp +++ b/dom/fetch/FetchDriver.cpp @@ -33,6 +33,7 @@ #include "mozilla/Unused.h" #include "Fetch.h" +#include "FetchUtil.h" #include "InternalRequest.h" #include "InternalResponse.h" @@ -263,62 +264,30 @@ FetchDriver::HttpFetch() // Set the same headers. SetRequestHeaders(httpChan); - // Step 2. Set the referrer. - nsAutoString referrer; - mRequest->GetReferrer(referrer); - - // The Referrer Policy in Request can be used to override a referrer policy - // associated with an environment settings object. - // If there's no Referrer Policy in the request, it should be inherited - // from environment. - ReferrerPolicy referrerPolicy = mRequest->ReferrerPolicy_(); net::ReferrerPolicy net_referrerPolicy = mRequest->GetEnvironmentReferrerPolicy(); - switch (referrerPolicy) { - case ReferrerPolicy::_empty: - break; - case ReferrerPolicy::No_referrer: - net_referrerPolicy = net::RP_No_Referrer; - break; - case ReferrerPolicy::No_referrer_when_downgrade: - net_referrerPolicy = net::RP_No_Referrer_When_Downgrade; - break; - case ReferrerPolicy::Origin: - net_referrerPolicy = net::RP_Origin; - break; - case ReferrerPolicy::Origin_when_cross_origin: - net_referrerPolicy = net::RP_Origin_When_Crossorigin; - break; - case ReferrerPolicy::Unsafe_url: - net_referrerPolicy = net::RP_Unsafe_URL; - break; - default: - MOZ_ASSERT_UNREACHABLE("Invalid ReferrerPolicy enum value?"); - break; + // Step 6 of + // https://fetch.spec.whatwg.org/#main-fetch + // If request's referrer policy is the empty string and request's client is + // non-null, then set request's referrer policy to request's client's + // associated referrer policy. + // Basically, "client" is not in our implementation, we use + // EnvironmentReferrerPolicy of the worker or document context + if (mRequest->ReferrerPolicy_() == ReferrerPolicy::_empty) { + mRequest->SetReferrerPolicy(net_referrerPolicy); + } + // Step 7 of + // https://fetch.spec.whatwg.org/#main-fetch + // If request’s referrer policy is the empty string, + // then set request’s referrer policy to "no-referrer-when-downgrade". + if (mRequest->ReferrerPolicy_() == ReferrerPolicy::_empty) { + mRequest->SetReferrerPolicy(net::RP_No_Referrer_When_Downgrade); } - if (referrer.EqualsLiteral(kFETCH_CLIENT_REFERRER_STR)) { - rv = nsContentUtils::SetFetchReferrerURIWithPolicy(mPrincipal, - mDocument, - httpChan, - net_referrerPolicy); - NS_ENSURE_SUCCESS(rv, rv); - } else if (referrer.IsEmpty()) { - rv = httpChan->SetReferrerWithPolicy(nullptr, net::RP_No_Referrer); - NS_ENSURE_SUCCESS(rv, rv); - } else { - // From "Determine request's Referrer" step 3 - // "If request's referrer is a URL, let referrerSource be request's - // referrer." - nsCOMPtr referrerURI; - rv = NS_NewURI(getter_AddRefs(referrerURI), referrer, nullptr, nullptr); - NS_ENSURE_SUCCESS(rv, rv); - rv = - httpChan->SetReferrerWithPolicy(referrerURI, - referrerPolicy == ReferrerPolicy::_empty ? - mRequest->GetEnvironmentReferrerPolicy() : - net_referrerPolicy); - NS_ENSURE_SUCCESS(rv, rv); - } + rv = FetchUtil::SetRequestReferrer(mPrincipal, + mDocument, + httpChan, + mRequest); + NS_ENSURE_SUCCESS(rv, rv); // Bug 1120722 - Authorization will be handled later. // Auth may require prompting, we don't support it yet. @@ -865,29 +834,15 @@ FetchDriver::AsyncOnChannelRedirect(nsIChannel* aOldChannel, net::ReferrerPolicy net_referrerPolicy = nsContentUtils::GetReferrerPolicyFromHeader(tRPHeaderValue); if (net_referrerPolicy != net::RP_Unset) { - ReferrerPolicy referrerPolicy = mRequest->ReferrerPolicy_(); - switch (net_referrerPolicy) { - case net::RP_No_Referrer: - referrerPolicy = ReferrerPolicy::No_referrer; - break; - case net::RP_No_Referrer_When_Downgrade: - referrerPolicy = ReferrerPolicy::No_referrer_when_downgrade; - break; - case net::RP_Origin: - referrerPolicy = ReferrerPolicy::Origin; - break; - case net::RP_Origin_When_Crossorigin: - referrerPolicy = ReferrerPolicy::Origin_when_cross_origin; - break; - case net::RP_Unsafe_URL: - referrerPolicy = ReferrerPolicy::Unsafe_url; - break; - default: - MOZ_ASSERT_UNREACHABLE("Invalid ReferrerPolicy value"); - break; + mRequest->SetReferrerPolicy(net_referrerPolicy); + // Should update channel's referrer policy + if (httpChannel) { + rv = FetchUtil::SetRequestReferrer(mPrincipal, + mDocument, + httpChannel, + mRequest); + NS_ENSURE_SUCCESS(rv, rv); } - - mRequest->SetReferrerPolicy(referrerPolicy); } } diff --git a/dom/fetch/FetchUtil.cpp b/dom/fetch/FetchUtil.cpp index b384c4f810..320753a9f1 100644 --- a/dom/fetch/FetchUtil.cpp +++ b/dom/fetch/FetchUtil.cpp @@ -4,8 +4,10 @@ #include "nsIUnicodeDecoder.h" #include "nsNetUtil.h" #include "nsString.h" +#include "nsIDocument.h" #include "mozilla/dom/EncodingUtils.h" +#include "mozilla/dom/InternalRequest.h" namespace mozilla { namespace dom { @@ -111,5 +113,59 @@ FetchUtil::ExtractHeader(nsACString::const_iterator& aStart, return PushOverLine(aStart, aEnd); } +// static +nsresult +FetchUtil::SetRequestReferrer(nsIPrincipal* aPrincipal, + nsIDocument* aDoc, + nsIHttpChannel* aChannel, + InternalRequest* aRequest) { + MOZ_ASSERT(NS_IsMainThread()); + + nsAutoString referrer; + aRequest->GetReferrer(referrer); + net::ReferrerPolicy policy = aRequest->GetReferrerPolicy(); + + nsresult rv = NS_OK; + if (referrer.IsEmpty()) { + // This is the case request’s referrer is "no-referrer" + rv = aChannel->SetReferrerWithPolicy(nullptr, net::RP_No_Referrer); + NS_ENSURE_SUCCESS(rv, rv); + } else if (referrer.EqualsLiteral(kFETCH_CLIENT_REFERRER_STR)) { + rv = nsContentUtils::SetFetchReferrerURIWithPolicy(aPrincipal, + aDoc, + aChannel, + policy); + NS_ENSURE_SUCCESS(rv, rv); + } else { + // From "Determine request's Referrer" step 3 + // "If request's referrer is a URL, let referrerSource be request's + // referrer." + nsCOMPtr referrerURI; + rv = NS_NewURI(getter_AddRefs(referrerURI), referrer, nullptr, nullptr); + NS_ENSURE_SUCCESS(rv, rv); + + rv = aChannel->SetReferrerWithPolicy(referrerURI, policy); + NS_ENSURE_SUCCESS(rv, rv); + } + + nsCOMPtr referrerURI; + aChannel->GetReferrer(getter_AddRefs(referrerURI)); + + // Step 8 https://fetch.spec.whatwg.org/#main-fetch + // If request’s referrer is not "no-referrer", set request’s referrer to + // the result of invoking determine request’s referrer. + if (referrerURI) { + nsAutoCString spec; + rv = referrerURI->GetSpec(spec); + NS_ENSURE_SUCCESS(rv, rv); + + aRequest->SetReferrer(NS_ConvertUTF8toUTF16(spec)); + } else { + aRequest->SetReferrer(EmptyString()); + } + + return NS_OK; +} + } // namespace dom } // namespace mozilla diff --git a/dom/fetch/FetchUtil.h b/dom/fetch/FetchUtil.h index d99aa39b44..7bf946eafa 100644 --- a/dom/fetch/FetchUtil.h +++ b/dom/fetch/FetchUtil.h @@ -8,9 +8,15 @@ #include "mozilla/dom/File.h" #include "mozilla/dom/FormData.h" +class nsIPrincipal; +class nsIDocument; +class nsIHttpChannel; + namespace mozilla { namespace dom { +class InternalRequest; + class FetchUtil final { private: @@ -35,6 +41,13 @@ public: nsCString& aHeaderName, nsCString& aHeaderValue, bool* aWasEmptyHeader); + + static nsresult + SetRequestReferrer(nsIPrincipal* aPrincipal, + nsIDocument* aDoc, + nsIHttpChannel* aChannel, + InternalRequest* aRequest); + }; } // namespace dom diff --git a/dom/fetch/InternalRequest.h b/dom/fetch/InternalRequest.h index 786c71e00f..9ab115be0a 100644 --- a/dom/fetch/InternalRequest.h +++ b/dom/fetch/InternalRequest.h @@ -232,6 +232,72 @@ public: mReferrerPolicy = aReferrerPolicy; } + void + SetReferrerPolicy(net::ReferrerPolicy aReferrerPolicy) + { + switch (aReferrerPolicy) { + case net::RP_Unset: + mReferrerPolicy = ReferrerPolicy::_empty; + break; + case net::RP_No_Referrer: + mReferrerPolicy = ReferrerPolicy::No_referrer; + break; + case net::RP_No_Referrer_When_Downgrade: + mReferrerPolicy = ReferrerPolicy::No_referrer_when_downgrade; + break; + case net::RP_Origin: + mReferrerPolicy = ReferrerPolicy::Origin; + break; + case net::RP_Origin_When_Crossorigin: + mReferrerPolicy = ReferrerPolicy::Origin_when_cross_origin; + break; + case net::RP_Unsafe_URL: + mReferrerPolicy = ReferrerPolicy::Unsafe_url; + break; + case net::RP_Same_Origin: + mReferrerPolicy = ReferrerPolicy::Same_origin; + break; + case net::RP_Strict_Origin: + mReferrerPolicy = ReferrerPolicy::Strict_origin; + break; + case net::RP_Strict_Origin_When_Cross_Origin: + mReferrerPolicy = ReferrerPolicy::Strict_origin_when_cross_origin; + break; + default: + MOZ_ASSERT_UNREACHABLE("Invalid ReferrerPolicy value"); + break; + } + } + + net::ReferrerPolicy + GetReferrerPolicy() + { + switch (mReferrerPolicy) { + case ReferrerPolicy::_empty: + return net::RP_Unset; + case ReferrerPolicy::No_referrer: + return net::RP_No_Referrer; + case ReferrerPolicy::No_referrer_when_downgrade: + return net::RP_No_Referrer_When_Downgrade; + case ReferrerPolicy::Origin: + return net::RP_Origin; + case ReferrerPolicy::Origin_when_cross_origin: + return net::RP_Origin_When_Crossorigin; + case ReferrerPolicy::Unsafe_url: + return net::RP_Unsafe_URL; + case ReferrerPolicy::Strict_origin: + return net::RP_Strict_Origin; + case ReferrerPolicy::Same_origin: + return net::RP_Same_Origin; + case ReferrerPolicy::Strict_origin_when_cross_origin: + return net::RP_Strict_Origin_When_Cross_Origin; + default: + MOZ_ASSERT_UNREACHABLE("Invalid ReferrerPolicy enum value?"); + break; + } + return net::RP_Unset; + } + net::ReferrerPolicy GetEnvironmentReferrerPolicy() const { diff --git a/dom/webidl/Request.webidl b/dom/webidl/Request.webidl index 9140543e7b..1b9cb1e909 100644 --- a/dom/webidl/Request.webidl +++ b/dom/webidl/Request.webidl @@ -73,4 +73,8 @@ enum RequestMode { "same-origin", "no-cors", "cors", "navigate" }; enum RequestCredentials { "omit", "same-origin", "include" }; enum RequestCache { "default", "no-store", "reload", "no-cache", "force-cache", "only-if-cached" }; enum RequestRedirect { "follow", "error", "manual" }; -enum ReferrerPolicy { "", "no-referrer", "no-referrer-when-downgrade", "origin", "origin-when-cross-origin", "unsafe-url" }; +enum ReferrerPolicy { + "", "no-referrer", "no-referrer-when-downgrade", "origin", + "origin-when-cross-origin", "unsafe-url", "same-origin", "strict-origin", + "strict-origin-when-cross-origin" +}; diff --git a/dom/workers/ScriptLoader.cpp b/dom/workers/ScriptLoader.cpp index 80dec34ec7..c05309dd0a 100644 --- a/dom/workers/ScriptLoader.cpp +++ b/dom/workers/ScriptLoader.cpp @@ -209,8 +209,10 @@ ChannelFromScriptURL(nsIPrincipal* principal, NS_ENSURE_SUCCESS(rv, rv); if (nsCOMPtr httpChannel = do_QueryInterface(channel)) { + mozilla::net::ReferrerPolicy referrerPolicy = parentDoc ? + parentDoc->GetReferrerPolicy() : mozilla::net::RP_Default; rv = nsContentUtils::SetFetchReferrerURIWithPolicy(principal, parentDoc, - httpChannel, mozilla::net::RP_Default); + httpChannel, referrerPolicy); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } diff --git a/dom/workers/ServiceWorkerPrivate.cpp b/dom/workers/ServiceWorkerPrivate.cpp index f30ae67a19..9e7b855efc 100644 --- a/dom/workers/ServiceWorkerPrivate.cpp +++ b/dom/workers/ServiceWorkerPrivate.cpp @@ -1345,12 +1345,19 @@ public: httpChannel->GetRequestHeader(NS_LITERAL_CSTRING("Referer"), referrer); if (!referrer.IsEmpty()) { mReferrer = referrer; + } else { + // If there's no referrer Header, means the header was omitted for + // security/privacy reason. + mReferrer = EmptyCString(); } uint32_t referrerPolicy = 0; rv = httpChannel->GetReferrerPolicy(&referrerPolicy); NS_ENSURE_SUCCESS(rv, rv); switch (referrerPolicy) { + case nsIHttpChannel::REFERRER_POLICY_UNSET: + mReferrerPolicy = ReferrerPolicy::_empty; + break; case nsIHttpChannel::REFERRER_POLICY_NO_REFERRER: mReferrerPolicy = ReferrerPolicy::No_referrer; break; @@ -1366,6 +1373,15 @@ public: case nsIHttpChannel::REFERRER_POLICY_UNSAFE_URL: mReferrerPolicy = ReferrerPolicy::Unsafe_url; break; + case nsIHttpChannel::REFERRER_POLICY_SAME_ORIGIN: + mReferrerPolicy = ReferrerPolicy::Same_origin; + break; + case nsIHttpChannel::REFERRER_POLICY_STRICT_ORIGIN_WHEN_XORIGIN: + mReferrerPolicy = ReferrerPolicy::Strict_origin_when_cross_origin; + break; + case nsIHttpChannel::REFERRER_POLICY_STRICT_ORIGIN: + mReferrerPolicy = ReferrerPolicy::Strict_origin; + break; default: MOZ_ASSERT_UNREACHABLE("Invalid Referrer Policy enum value?"); break; diff --git a/dom/xhr/XMLHttpRequestMainThread.cpp b/dom/xhr/XMLHttpRequestMainThread.cpp index 48eb494747..101922ac3d 100644 --- a/dom/xhr/XMLHttpRequestMainThread.cpp +++ b/dom/xhr/XMLHttpRequestMainThread.cpp @@ -2434,9 +2434,10 @@ XMLHttpRequestMainThread::InitiateFetch(nsIInputStream* aUploadStream, if (!IsSystemXHR()) { nsCOMPtr owner = GetOwner(); nsCOMPtr doc = owner ? owner->GetExtantDoc() : nullptr; + mozilla::net::ReferrerPolicy referrerPolicy = doc ? + doc->GetReferrerPolicy() : mozilla::net::RP_Default; nsContentUtils::SetFetchReferrerURIWithPolicy(mPrincipal, doc, - httpChannel, - mozilla::net::RP_Default); + httpChannel, referrerPolicy); } // Some extensions override the http protocol handler and provide their own diff --git a/netwerk/protocol/http/HttpBaseChannel.cpp b/netwerk/protocol/http/HttpBaseChannel.cpp index 2544ad5866..e0ccbfb811 100644 --- a/netwerk/protocol/http/HttpBaseChannel.cpp +++ b/netwerk/protocol/http/HttpBaseChannel.cpp @@ -1316,7 +1316,7 @@ HttpBaseChannel::SetReferrerWithPolicy(nsIURI *referrer, if(NS_FAILED(rv)) { return rv; } - mReferrerPolicy = REFERRER_POLICY_NO_REFERRER_WHEN_DOWNGRADE; + mReferrerPolicy = referrerPolicy; if (!referrer) { return NS_OK; @@ -1324,7 +1324,6 @@ HttpBaseChannel::SetReferrerWithPolicy(nsIURI *referrer, // Don't send referrer at all when the meta referrer setting is "no-referrer" if (referrerPolicy == REFERRER_POLICY_NO_REFERRER) { - mReferrerPolicy = REFERRER_POLICY_NO_REFERRER; return NS_OK; } @@ -1597,7 +1596,6 @@ HttpBaseChannel::SetReferrerWithPolicy(nsIURI *referrer, if (NS_FAILED(rv)) return rv; mReferrer = clone; - mReferrerPolicy = referrerPolicy; return NS_OK; } diff --git a/netwerk/protocol/http/HttpChannelChild.cpp b/netwerk/protocol/http/HttpChannelChild.cpp index 8fcc0d203b..fa6ba396dc 100644 --- a/netwerk/protocol/http/HttpChannelChild.cpp +++ b/netwerk/protocol/http/HttpChannelChild.cpp @@ -1681,8 +1681,13 @@ NS_IMETHODIMP HttpChannelChild::OnRedirectVerifyCallback(nsresult result) { LOG(("HttpChannelChild::OnRedirectVerifyCallback [this=%p]\n", this)); - OptionalURIParams redirectURI; nsresult rv; + OptionalURIParams redirectURI; + + uint32_t referrerPolicy = REFERRER_POLICY_NO_REFERRER_WHEN_DOWNGRADE; + OptionalURIParams referrerURI; + SerializeURI(nullptr, referrerURI); + nsCOMPtr newHttpChannel = do_QueryInterface(mRedirectChannelChild); @@ -1700,6 +1705,12 @@ HttpChannelChild::OnRedirectVerifyCallback(nsresult result) if (newHttpChannel) { // Must not be called until after redirect observers called. newHttpChannel->SetOriginalURI(mOriginalURI); + + newHttpChannel->GetReferrerPolicy(&referrerPolicy); + nsCOMPtr newChannelReferrerURI; + newHttpChannel->GetReferrer(getter_AddRefs(newChannelReferrerURI)); + + SerializeURI(newChannelReferrerURI, referrerURI); } if (mRedirectingForSubsequentSynthesizedResponse) { @@ -1770,8 +1781,9 @@ HttpChannelChild::OnRedirectVerifyCallback(nsresult result) } if (mIPCOpen) - SendRedirect2Verify(result, *headerTuples, loadFlags, redirectURI, - corsPreflightArgs, chooseAppcache); + SendRedirect2Verify(result, *headerTuples, loadFlags, referrerPolicy, + referrerURI, redirectURI, corsPreflightArgs, + chooseAppcache); return NS_OK; } @@ -2147,6 +2159,25 @@ HttpChannelChild::ContinueAsyncOpen() // HttpChannelChild::nsIHttpChannel //----------------------------------------------------------------------------- +NS_IMETHODIMP +HttpChannelChild::SetReferrerWithPolicy(nsIURI *referrer, + uint32_t referrerPolicy) +{ + ENSURE_CALLED_BEFORE_CONNECT(); + + // remove old referrer if any, loop backwards + for (int i = mClientSetRequestHeaders.Length() - 1; i >= 0; --i) { + if (NS_LITERAL_CSTRING("Referer").Equals(mClientSetRequestHeaders[i].mHeader)) { + mClientSetRequestHeaders.RemoveElementAt(i); + } + } + + nsresult rv = HttpBaseChannel::SetReferrerWithPolicy(referrer, referrerPolicy); + if (NS_FAILED(rv)) + return rv; + return NS_OK; + +} NS_IMETHODIMP HttpChannelChild::SetRequestHeader(const nsACString& aHeader, const nsACString& aValue, diff --git a/netwerk/protocol/http/HttpChannelChild.h b/netwerk/protocol/http/HttpChannelChild.h index 983f35be75..c48ebcbb4e 100644 --- a/netwerk/protocol/http/HttpChannelChild.h +++ b/netwerk/protocol/http/HttpChannelChild.h @@ -77,6 +77,7 @@ public: NS_IMETHOD AsyncOpen2(nsIStreamListener *aListener) override; // HttpBaseChannel::nsIHttpChannel + NS_IMETHOD SetReferrerWithPolicy(nsIURI *referrer, uint32_t referrerPolicy) override; NS_IMETHOD SetRequestHeader(const nsACString& aHeader, const nsACString& aValue, bool aMerge) override; diff --git a/netwerk/protocol/http/HttpChannelParent.cpp b/netwerk/protocol/http/HttpChannelParent.cpp index b296478516..34113a6bfd 100644 --- a/netwerk/protocol/http/HttpChannelParent.cpp +++ b/netwerk/protocol/http/HttpChannelParent.cpp @@ -733,6 +733,8 @@ bool HttpChannelParent::RecvRedirect2Verify(const nsresult& result, const RequestHeaderTuples& changedHeaders, const uint32_t& loadFlags, + const uint32_t& referrerPolicy, + const OptionalURIParams& aReferrerURI, const OptionalURIParams& aAPIRedirectURI, const OptionalCorsPreflightArgs& aCorsPreflightArgs, const bool& aChooseAppcache) @@ -773,6 +775,9 @@ HttpChannelParent::RecvRedirect2Verify(const nsresult& result, newInternalChannel->SetCorsPreflightParameters(args.unsafeHeaders()); } + nsCOMPtr referrerUri = DeserializeURI(aReferrerURI); + newHttpChannel->SetReferrerWithPolicy(referrerUri, referrerPolicy); + nsCOMPtr appCacheChannel = do_QueryInterface(newHttpChannel); if (appCacheChannel) { diff --git a/netwerk/protocol/http/HttpChannelParent.h b/netwerk/protocol/http/HttpChannelParent.h index bb7077780e..32b2ef8b48 100644 --- a/netwerk/protocol/http/HttpChannelParent.h +++ b/netwerk/protocol/http/HttpChannelParent.h @@ -159,6 +159,8 @@ protected: virtual bool RecvRedirect2Verify(const nsresult& result, const RequestHeaderTuples& changedHeaders, const uint32_t& loadFlags, + const uint32_t& referrerPolicy, + const OptionalURIParams& aReferrerURI, const OptionalURIParams& apiRedirectUri, const OptionalCorsPreflightArgs& aCorsPreflightArgs, const bool& aChooseAppcache) override; diff --git a/netwerk/protocol/http/PHttpChannel.ipdl b/netwerk/protocol/http/PHttpChannel.ipdl index d43b27afcb..e797e1d2ec 100644 --- a/netwerk/protocol/http/PHttpChannel.ipdl +++ b/netwerk/protocol/http/PHttpChannel.ipdl @@ -44,7 +44,9 @@ parent: // Reports approval/veto of redirect by child process redirect observers async Redirect2Verify(nsresult result, RequestHeaderTuples changedHeaders, - uint32_t loadFlags, OptionalURIParams apiRedirectTo, + uint32_t loadFlags, uint32_t referrerPolicy, + OptionalURIParams referrerUri, + OptionalURIParams apiRedirectTo, OptionalCorsPreflightArgs corsPreflightArgs, bool chooseAppcache); From e665b30629df081722595450e9658ae5b9ad83a9 Mon Sep 17 00:00:00 2001 From: Moonchild Date: Mon, 21 Oct 2024 22:27:57 +0200 Subject: [PATCH 5/5] Issue #2645 - Return null if getName() PC is invalid. --- js/src/jsscript.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/js/src/jsscript.h b/js/src/jsscript.h index 68e9884321..41d8e18ee0 100644 --- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -1871,8 +1871,11 @@ class JSScript : public js::gc::TenuredCell } js::PropertyName* getName(jsbytecode* pc) const { - MOZ_ASSERT(containsPC(pc) && containsPC(pc + sizeof(uint32_t))); - return getAtom(GET_UINT32_INDEX(pc))->asPropertyName(); + if (containsPC(pc) && containsPC(pc + sizeof(uint32_t))) { + return getAtom(GET_UINT32_INDEX(pc))->asPropertyName(); + } else { + return nullptr; + } } JSObject* getObject(size_t index) {