diff --git a/dom/base/ResponsiveImageSelector.cpp b/dom/base/ResponsiveImageSelector.cpp index 43a5138faa45..5ebb5b202006 100644 --- a/dom/base/ResponsiveImageSelector.cpp +++ b/dom/base/ResponsiveImageSelector.cpp @@ -116,7 +116,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(); @@ -168,6 +169,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); } } @@ -208,7 +211,8 @@ ResponsiveImageSelector::Document() } void -ResponsiveImageSelector::SetDefaultSource(const nsAString& aURLString) +ResponsiveImageSelector::SetDefaultSource(const nsAString& aURLString, + nsIPrincipal* aPrincipal) { ClearSelectedCandidate(); @@ -220,6 +224,7 @@ ResponsiveImageSelector::SetDefaultSource(const nsAString& aURLString) } mDefaultSourceURL = aURLString; + mDefaultSourceTriggeringPrincipal = aPrincipal; // Add new default to end of list MaybeAppendDefaultCandidate(); @@ -292,6 +297,7 @@ 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. mCandidates.AppendElement(defaultCandidate); @@ -330,6 +336,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) { @@ -458,8 +475,10 @@ ResponsiveImageCandidate::ResponsiveImageCandidate() } ResponsiveImageCandidate::ResponsiveImageCandidate(const nsAString& aURLString, - double aDensity) + double aDensity, + nsIPrincipal* aTriggeringPrincipal) : mURLString(aURLString) + , mTriggeringPrincipal(aTriggeringPrincipal) { mType = eCandidateType_Density; mValue.mDensity = aDensity; @@ -472,6 +491,12 @@ ResponsiveImageCandidate::SetURLSpec(const nsAString& aURLString) mURLString = aURLString; } +void +ResponsiveImageCandidate::SetTriggeringPrincipal(nsIPrincipal* aPrincipal) +{ + mTriggeringPrincipal = aPrincipal; +} + void ResponsiveImageCandidate::SetParameterAsComputedWidth(int32_t aWidth) { @@ -718,6 +743,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 c722e8784c72..210338babeac 100644 --- a/dom/base/ResponsiveImageSelector.h +++ b/dom/base/ResponsiveImageSelector.h @@ -45,14 +45,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); @@ -70,6 +72,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. @@ -108,6 +111,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; @@ -123,9 +127,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. @@ -148,6 +154,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; @@ -172,6 +179,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 1ee0dee139f8..1a09458f150e 100644 --- a/dom/html/HTMLImageElement.cpp +++ b/dom/html/HTMLImageElement.cpp @@ -368,6 +368,8 @@ HTMLImageElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName, // initaiated by a user interaction. mUseUrgentStartForChannel = EventStateManager::IsHandlingUserInput(); + mSrcsetTriggeringPrincipal = aMaybeScriptedPrincipal; + PictureSourceSrcsetChanged(this, attrVal.String(), aNotify); } else if (aName == nsGkAtoms::sizes && aNameSpaceID == kNameSpaceID_None) { @@ -426,7 +428,8 @@ HTMLImageElement::AfterMaybeChangeAttr(int32_t aNamespaceID, nsAtom* aName, if (InResponsiveMode()) { if (mResponsiveSelector && mResponsiveSelector->Content() == this) { - mResponsiveSelector->SetDefaultSource(aValue.String()); + mResponsiveSelector->SetDefaultSource(aValue.String(), + mSrcTriggeringPrincipal); } QueueImageLoadTask(true); } else if (aNotify && OwnerDoc()->IsCurrentActiveDocument()) { @@ -981,13 +984,15 @@ 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; @@ -1036,7 +1041,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()) { @@ -1221,6 +1230,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) { @@ -1230,6 +1241,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 @@ -1245,7 +1257,7 @@ HTMLImageElement::TryCreateResponsiveSelector(nsIContent *aSourceNode) // Try to parse RefPtr sel = new ResponsiveImageSelector(aSourceNode); - if (!sel->SetCandidatesFromSourceSet(srcset)) { + if (!sel->SetCandidatesFromSourceSet(srcset, principal)) { // No possible candidates, don't need to bother parsing sizes return false; } @@ -1259,7 +1271,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 8917be7bb9e3..952cb7bfb02a 100644 --- a/dom/html/HTMLImageElement.h +++ b/dom/html/HTMLImageElement.h @@ -150,13 +150,13 @@ public: { SetHTMLAttr(nsGkAtoms::src, aSrc, aTriggeringPrincipal, aError); } - void GetSrcset(nsAString& aSrcset) + void GetSrcset(nsAString& aSrcset, nsIPrincipal&) { GetHTMLAttr(nsGkAtoms::srcset, aSrcset); } - void SetSrcset(const nsAString& aSrcset, ErrorResult& aError) + void SetSrcset(const nsAString& aSrcset, nsIPrincipal& aTriggeringPrincipal, ErrorResult& aError) { - SetHTMLAttr(nsGkAtoms::srcset, aSrcset, aError); + SetHTMLAttr(nsGkAtoms::srcset, aSrcset, aTriggeringPrincipal, aError); } void GetCrossOrigin(nsAString& aResult) { @@ -427,6 +427,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 098c31cb6a04..d0cf708caddc 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; diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_contentscript_triggeringPrincipal.js b/toolkit/components/extensions/test/xpcshell/test_ext_contentscript_triggeringPrincipal.js index 1c9cdd619fed..01264aba0ff6 100644 --- a/toolkit/components/extensions/test/xpcshell/test_ext_contentscript_triggeringPrincipal.js +++ b/toolkit/components/extensions/test/xpcshell/test_ext_contentscript_triggeringPrincipal.js @@ -437,6 +437,11 @@ add_task(async function test_contentscript_triggeringPrincipals() { element: ["img", {}], src: "img.png", }, + { + element: ["img", {}], + src: "imgset.png", + srcAttr: "srcset", + }, ]; /**