Bug 1406278: Part 2c - Use subject principal as triggering principal in <img> "srcset" attribute. r=bz

MozReview-Commit-ID: 784EsgwBcS1

--HG--
extra : rebase_source : 01b701f84c425786b66cd9787d4e570dd9341ae5
This commit is contained in:
Kris Maglione 2017-10-02 21:30:34 -07:00
parent d72aa193c4
commit d038453393
6 changed files with 72 additions and 15 deletions

View File

@ -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
{

View File

@ -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<nsINode> mOwnerNode;
// The cached URL for default candidate.
nsString mDefaultSourceURL;
nsCOMPtr<nsIPrincipal> mDefaultSourceTriggeringPrincipal;
// If this array contains an eCandidateType_Default, it should be the last
// element, such that the Setters can preserve/replace it respectively.
nsTArray<ResponsiveImageCandidate> 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<nsIPrincipal> mTriggeringPrincipal;
eCandidateType mType;
union {
double mDensity;

View File

@ -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<nsIURI> url = mResponsiveSelector->GetSelectedImageURL();
nsCOMPtr<nsIPrincipal> 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<nsIPrincipal> 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<nsIPrincipal> principal;
// Skip if this is not a <source> 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 <img> 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<ResponsiveImageSelector> 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);
}
}

View File

@ -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<ImageLoadTask> mPendingImageLoadTask;
nsCOMPtr<nsIPrincipal> mSrcTriggeringPrincipal;
nsCOMPtr<nsIPrincipal> mSrcsetTriggeringPrincipal;
// Last URL that was attempted to load by this element.
nsCOMPtr<nsIURI> mLastSelectedSource;

View File

@ -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;

View File

@ -437,6 +437,11 @@ add_task(async function test_contentscript_triggeringPrincipals() {
element: ["img", {}],
src: "img.png",
},
{
element: ["img", {}],
src: "imgset.png",
srcAttr: "srcset",
},
];
/**