From 2bdb9f3d853c7bb89a86fae73cd1e02cd2800576 Mon Sep 17 00:00:00 2001 From: Moonchild Date: Mon, 28 Apr 2025 19:15:02 +0200 Subject: [PATCH] Issue #2736 - Part 5: Re-work img `` attribute. Use subject principal as triggering principal in "srcset" attribute. --- dom/base/ResponsiveImageSelector.cpp | 39 +++++++++++++++++++++++++--- dom/base/ResponsiveImageSelector.h | 14 +++++++--- dom/html/HTMLImageElement.cpp | 21 ++++++++++----- dom/html/HTMLImageElement.h | 9 +++++-- dom/webidl/HTMLImageElement.webidl | 2 +- 5 files changed, 69 insertions(+), 16 deletions(-) diff --git a/dom/base/ResponsiveImageSelector.cpp b/dom/base/ResponsiveImageSelector.cpp index 0a64fc7430..8a224bf459 100644 --- a/dom/base/ResponsiveImageSelector.cpp +++ b/dom/base/ResponsiveImageSelector.cpp @@ -115,7 +115,8 @@ ResponsiveImageSelector::~ResponsiveImageSelector() // http://www.whatwg.org/specs/web-apps/current-work/#processing-the-image-candidates bool -ResponsiveImageSelector::SetCandidatesFromSourceSet(const nsAString & aSrcSet) +ResponsiveImageSelector::SetCandidatesFromSourceSet(const nsAString & aSrcSet, + nsIPrincipal* aTriggeringPrincipal) { ClearSelectedCandidate(); @@ -167,6 +168,8 @@ ResponsiveImageSelector::SetCandidatesFromSourceSet(const nsAString & aSrcSet) ResponsiveImageCandidate candidate; if (candidate.ConsumeDescriptors(iter, end)) { candidate.SetURLSpec(urlStr); + candidate.SetTriggeringPrincipal(nsContentUtils::GetAttrTriggeringPrincipal( + Content(), urlStr, aTriggeringPrincipal)); AppendCandidateIfUnique(candidate); } } @@ -207,7 +210,8 @@ ResponsiveImageSelector::Document() } void -ResponsiveImageSelector::SetDefaultSource(const nsAString& aURLString) +ResponsiveImageSelector::SetDefaultSource(const nsAString& aURLString, + nsIPrincipal* aPrincipal) { ClearSelectedCandidate(); @@ -219,6 +223,7 @@ ResponsiveImageSelector::SetDefaultSource(const nsAString& aURLString) } mDefaultSourceURL = aURLString; + mDefaultSourceTriggeringPrincipal = aPrincipal; // Add new default to end of list MaybeAppendDefaultCandidate(); @@ -291,8 +296,9 @@ ResponsiveImageSelector::MaybeAppendDefaultCandidate() ResponsiveImageCandidate defaultCandidate; defaultCandidate.SetParameterDefault(); defaultCandidate.SetURLSpec(mDefaultSourceURL); + defaultCandidate.SetTriggeringPrincipal(mDefaultSourceTriggeringPrincipal); // We don't use MaybeAppend since we want to keep this even if it can never - // match, as it may if the source set changes. + // match, because as it may match if the source set changes dynamically. mCandidates.AppendElement(defaultCandidate); } @@ -329,6 +335,17 @@ ResponsiveImageSelector::GetSelectedImageDensity() return mCandidates[bestIndex].Density(this); } +nsIPrincipal* +ResponsiveImageSelector::GetSelectedImageTriggeringPrincipal() +{ + int bestIndex = GetSelectedCandidateIndex(); + if (bestIndex < 0) { + return nullptr; + } + + return mCandidates[bestIndex].TriggeringPrincipal(); +} + bool ResponsiveImageSelector::SelectImage(bool aReselect) { @@ -457,8 +474,10 @@ ResponsiveImageCandidate::ResponsiveImageCandidate() } ResponsiveImageCandidate::ResponsiveImageCandidate(const nsAString& aURLString, - double aDensity) + double aDensity, + nsIPrincipal* aTriggeringPrincipal) : mURLString(aURLString) + , mTriggeringPrincipal(aTriggeringPrincipal) { mType = eCandidateType_Density; mValue.mDensity = aDensity; @@ -471,6 +490,12 @@ ResponsiveImageCandidate::SetURLSpec(const nsAString& aURLString) mURLString = aURLString; } +void +ResponsiveImageCandidate::SetTriggeringPrincipal(nsIPrincipal* aPrincipal) +{ + mTriggeringPrincipal = aPrincipal; +} + void ResponsiveImageCandidate::SetParameterAsComputedWidth(int32_t aWidth) { @@ -717,6 +742,12 @@ ResponsiveImageCandidate::URLString() const return mURLString; } +nsIPrincipal* +ResponsiveImageCandidate::TriggeringPrincipal() const +{ + return mTriggeringPrincipal; +} + double ResponsiveImageCandidate::Density(ResponsiveImageSelector *aSelector) const { diff --git a/dom/base/ResponsiveImageSelector.h b/dom/base/ResponsiveImageSelector.h index b4314b8bf7..2f1245f594 100644 --- a/dom/base/ResponsiveImageSelector.h +++ b/dom/base/ResponsiveImageSelector.h @@ -44,14 +44,16 @@ public: // Given a srcset string, parse and replace current candidates (does not // replace default source) - bool SetCandidatesFromSourceSet(const nsAString & aSrcSet); + bool SetCandidatesFromSourceSet(const nsAString & aSrcSet, + nsIPrincipal* aTriggeringPrincipal = nullptr); // Fill the source sizes from a valid sizes descriptor. Returns false if // descriptor is invalid. bool SetSizesFromDescriptor(const nsAString & aSizesDescriptor); // Set the default source, treated as the least-precedence 1.0 density source. - void SetDefaultSource(const nsAString& aURLString); + void SetDefaultSource(const nsAString& aURLString, + nsIPrincipal* aPrincipal = nullptr); uint32_t NumCandidates(bool aIncludeDefault = true); @@ -69,6 +71,7 @@ public: // Returns false if there is no selected image bool GetSelectedImageURLSpec(nsAString& aResult); double GetSelectedImageDensity(); + nsIPrincipal* GetSelectedImageTriggeringPrincipal(); // Runs image selection now if necessary. If an image has already // been choosen, takes no action unless aReselect is true. @@ -107,6 +110,7 @@ private: nsCOMPtr mOwnerNode; // The cached URL for default candidate. nsString mDefaultSourceURL; + nsCOMPtr mDefaultSourceTriggeringPrincipal; // If this array contains an eCandidateType_Default, it should be the last // element, such that the Setters can preserve/replace it respectively. nsTArray mCandidates; @@ -122,9 +126,11 @@ private: class ResponsiveImageCandidate { public: ResponsiveImageCandidate(); - ResponsiveImageCandidate(const nsAString& aURLString, double aDensity); + ResponsiveImageCandidate(const nsAString& aURLString, double aDensity, + nsIPrincipal* aTriggeringPrincipal = nullptr); void SetURLSpec(const nsAString& aURLString); + void SetTriggeringPrincipal(nsIPrincipal* aPrincipal); // Set this as a default-candidate. This behaves the same as density 1.0, but // has a differing type such that it can be replaced by subsequent // SetDefaultSource calls. @@ -147,6 +153,7 @@ public: bool HasSameParameter(const ResponsiveImageCandidate & aOther) const; const nsAString& URLString() const; + nsIPrincipal* TriggeringPrincipal() const; // Compute and return the density relative to a selector. double Density(ResponsiveImageSelector *aSelector) const; @@ -171,6 +178,7 @@ public: private: nsString mURLString; + nsCOMPtr mTriggeringPrincipal; eCandidateType mType; union { double mDensity; diff --git a/dom/html/HTMLImageElement.cpp b/dom/html/HTMLImageElement.cpp index 2124aab8c1..6945174954 100644 --- a/dom/html/HTMLImageElement.cpp +++ b/dom/html/HTMLImageElement.cpp @@ -430,6 +430,7 @@ HTMLImageElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName, } } else if (aName == nsGkAtoms::srcset && aNameSpaceID == kNameSpaceID_None) { + mSrcsetTriggeringPrincipal = aMaybeScriptedPrincipal; PictureSourceSrcsetChanged(this, attrVal.String(), aNotify); } else if (aName == nsGkAtoms::sizes && aNameSpaceID == kNameSpaceID_None) { @@ -481,7 +482,7 @@ HTMLImageElement::AfterMaybeChangeAttr(int32_t aNamespaceID, nsIAtom* aName, if (InResponsiveMode()) { if (mResponsiveSelector && mResponsiveSelector->Content() == this) { - mResponsiveSelector->SetDefaultSource(aValue.String()); + mResponsiveSelector->SetDefaultSource(aValue.String(), mSrcTriggeringPrincipal); } QueueImageLoadTask(true); } else if (aNotify && OwnerDoc()->IsCurrentActiveDocument()) { @@ -1000,13 +1001,14 @@ HTMLImageElement::LoadSelectedImage(bool aForce, bool aNotify, bool aAlwaysLoad) double currentDensity = 1.0; // default to 1.0 for the src attribute case if (mResponsiveSelector) { nsCOMPtr url = mResponsiveSelector->GetSelectedImageURL(); + nsCOMPtr triggeringPrincipal = mResponsiveSelector->GetSelectedImageTriggeringPrincipal(); selectedSource = url; currentDensity = mResponsiveSelector->GetSelectedImageDensity(); if (!aAlwaysLoad && SelectedSourceMatchesLast(selectedSource, currentDensity)) { return NS_OK; } if (url) { - rv = LoadImage(url, aForce, aNotify, eImageLoadType_Imageset); + rv = LoadImage(url, aForce, aNotify, eImageLoadType_Imageset, triggeringPrincipal); } } else { nsAutoString src; @@ -1055,7 +1057,11 @@ HTMLImageElement::PictureSourceSrcsetChanged(nsIContent *aSourceNode, if (aSourceNode == currentSrc) { // We're currently using this node as our responsive selector // source. - mResponsiveSelector->SetCandidatesFromSourceSet(aNewValue); + nsCOMPtr principal; + if (aSourceNode == this) { + principal = mSrcsetTriggeringPrincipal; + } + mResponsiveSelector->SetCandidatesFromSourceSet(aNewValue, principal); } if (!mInDocResponsiveContent && IsInComposedDoc()) { @@ -1240,6 +1246,8 @@ HTMLImageElement::SourceElementMatches(nsIContent* aSourceNode) bool HTMLImageElement::TryCreateResponsiveSelector(nsIContent *aSourceNode) { + nsCOMPtr principal; + // Skip if this is not a with matching media query bool isSourceTag = aSourceNode->IsHTMLElement(nsGkAtoms::source); if (isSourceTag) { @@ -1249,6 +1257,7 @@ HTMLImageElement::TryCreateResponsiveSelector(nsIContent *aSourceNode) } else if (aSourceNode->IsHTMLElement(nsGkAtoms::img)) { // Otherwise this is the tag itself MOZ_ASSERT(aSourceNode == this); + principal = mSrcsetTriggeringPrincipal; } // Skip if has no srcset or an empty srcset @@ -1264,8 +1273,8 @@ HTMLImageElement::TryCreateResponsiveSelector(nsIContent *aSourceNode) // Try to parse RefPtr sel = new ResponsiveImageSelector(aSourceNode); - if (!sel->SetCandidatesFromSourceSet(srcset)) { - // No possible candidates, don't need to bother parsing sizes + if (!sel->SetCandidatesFromSourceSet(srcset, principal)) { + // No possible candidates; no need to bother parsing sizes return false; } @@ -1278,7 +1287,7 @@ HTMLImageElement::TryCreateResponsiveSelector(nsIContent *aSourceNode) MOZ_ASSERT(aSourceNode == this); nsAutoString src; if (GetAttr(kNameSpaceID_None, nsGkAtoms::src, src) && !src.IsEmpty()) { - sel->SetDefaultSource(src); + sel->SetDefaultSource(src, mSrcTriggeringPrincipal); } } diff --git a/dom/html/HTMLImageElement.h b/dom/html/HTMLImageElement.h index ad32dcc1bf..2c184d26d9 100644 --- a/dom/html/HTMLImageElement.h +++ b/dom/html/HTMLImageElement.h @@ -145,9 +145,13 @@ public: { SetHTMLAttr(nsGkAtoms::src, aSrc, aTriggeringPrincipal, aError); } - void SetSrcset(const nsAString& aSrcset, ErrorResult& aError) + void GetSrcset(nsAString& aSrcset, nsIPrincipal&) { - SetHTMLAttr(nsGkAtoms::srcset, aSrcset, aError); + GetHTMLAttr(nsGkAtoms::srcset, aSrcset); + } + void SetSrcset(const nsAString& aSrcset, nsIPrincipal& aTriggeringPrincipal, ErrorResult& aError) + { + SetHTMLAttr(nsGkAtoms::srcset, aSrcset, aTriggeringPrincipal, aError); } void GetCrossOrigin(nsAString& aResult) { @@ -387,6 +391,7 @@ private: bool mInDocResponsiveContent; RefPtr mPendingImageLoadTask; nsCOMPtr mSrcTriggeringPrincipal; + nsCOMPtr mSrcsetTriggeringPrincipal; // Last URL that was attempted to load by this element. nsCOMPtr mLastSelectedSource; diff --git a/dom/webidl/HTMLImageElement.webidl b/dom/webidl/HTMLImageElement.webidl index 4df2f1fac3..8696b89d2e 100644 --- a/dom/webidl/HTMLImageElement.webidl +++ b/dom/webidl/HTMLImageElement.webidl @@ -23,7 +23,7 @@ interface HTMLImageElement : HTMLElement { attribute DOMString alt; [CEReactions, NeedsSubjectPrincipal, SetterThrows] attribute DOMString src; - [CEReactions, SetterThrows] + [CEReactions, NeedsSubjectPrincipal, SetterThrows] attribute DOMString srcset; [CEReactions, SetterThrows] attribute DOMString? crossOrigin;