Bug 1166910 - Referrer attribute for img tag. r=ckerschb, r=hsivonen, r=bz

--HG--
extra : rebase_source : ceb3a3d18acf7deb9d13cfae499b7e112db8ffce
This commit is contained in:
Franziskus Kiefer 2015-06-05 15:25:24 -07:00
Родитель 8e360c243e
Коммит 2ae91f6891
14 изменённых файлов: 114 добавлений и 10 удалений

Просмотреть файл

@ -46,6 +46,7 @@
#include "mozilla/EventStates.h" #include "mozilla/EventStates.h"
#include "mozilla/dom/Element.h" #include "mozilla/dom/Element.h"
#include "mozilla/dom/ScriptSettings.h" #include "mozilla/dom/ScriptSettings.h"
#include "mozilla/Preferences.h"
#ifdef LoadImage #ifdef LoadImage
// Undefine LoadImage to prevent naming conflict with Windows. // Undefine LoadImage to prevent naming conflict with Windows.
@ -930,15 +931,27 @@ nsImageLoadingContent::LoadImage(nsIURI* aNewURI,
loadFlags |= imgILoader::LOAD_CORS_USE_CREDENTIALS; loadFlags |= imgILoader::LOAD_CORS_USE_CREDENTIALS;
} }
// get document wide referrer policy
mozilla::net::ReferrerPolicy referrerPolicy = aDocument->GetReferrerPolicy();
bool referrerAttributeEnabled = Preferences::GetBool("network.http.enablePerElementReferrer", false);
// if referrer attributes are enabled in preferences, load img referrer attribute
nsresult rv;
if (referrerAttributeEnabled) {
mozilla::net::ReferrerPolicy imgReferrerPolicy = GetImageReferrerPolicy();
// if the image does not provide a referrer attribute, ignore this
if (imgReferrerPolicy != mozilla::net::RP_Unset) {
referrerPolicy = imgReferrerPolicy;
}
}
// Not blocked. Do the load. // Not blocked. Do the load.
nsRefPtr<imgRequestProxy>& req = PrepareNextRequest(aImageLoadType); nsRefPtr<imgRequestProxy>& req = PrepareNextRequest(aImageLoadType);
nsCOMPtr<nsIContent> content = nsCOMPtr<nsIContent> content =
do_QueryInterface(static_cast<nsIImageLoadingContent*>(this)); do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
nsresult rv;
rv = nsContentUtils::LoadImage(aNewURI, aDocument, rv = nsContentUtils::LoadImage(aNewURI, aDocument,
aDocument->NodePrincipal(), aDocument->NodePrincipal(),
aDocument->GetDocumentURI(), aDocument->GetDocumentURI(),
aDocument->GetReferrerPolicy(), referrerPolicy,
this, loadFlags, this, loadFlags,
content->LocalName(), content->LocalName(),
getter_AddRefs(req), getter_AddRefs(req),
@ -1566,3 +1579,11 @@ nsImageLoadingContent::ImageObserver::~ImageObserver()
MOZ_COUNT_DTOR(ImageObserver); MOZ_COUNT_DTOR(ImageObserver);
NS_CONTENT_DELETE_LIST_MEMBER(ImageObserver, this, mNext); NS_CONTENT_DELETE_LIST_MEMBER(ImageObserver, this, mNext);
} }
// Only HTMLInputElement.h overrides this for <img> tags
// all other subclasses use this one, i.e. ignore referrer attributes
mozilla::net::ReferrerPolicy
nsImageLoadingContent::GetImageReferrerPolicy()
{
return mozilla::net::RP_Unset;
};

Просмотреть файл

@ -24,6 +24,7 @@
#include "nsAutoPtr.h" #include "nsAutoPtr.h"
#include "nsIContentPolicy.h" #include "nsIContentPolicy.h"
#include "mozilla/dom/BindingDeclarations.h" #include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/net/ReferrerPolicy.h"
class nsIURI; class nsIURI;
class nsIDocument; class nsIDocument;
@ -198,6 +199,8 @@ protected:
*/ */
virtual mozilla::CORSMode GetCORSMode(); virtual mozilla::CORSMode GetCORSMode();
virtual mozilla::net::ReferrerPolicy GetImageReferrerPolicy();
// Subclasses are *required* to call BindToTree/UnbindFromTree. // Subclasses are *required* to call BindToTree/UnbindFromTree.
void BindToTree(nsIDocument* aDocument, nsIContent* aParent, void BindToTree(nsIDocument* aDocument, nsIContent* aParent,
nsIContent* aBindingParent, bool aCompileEventHandlers); nsIContent* aBindingParent, bool aCompileEventHandlers);

Просмотреть файл

@ -189,6 +189,20 @@ public:
{ {
SetHTMLAttr(nsGkAtoms::border, aBorder, aError); SetHTMLAttr(nsGkAtoms::border, aBorder, aError);
} }
void SetReferrer(const nsAString& aReferrer, ErrorResult& aError)
{
SetHTMLAttr(nsGkAtoms::referrer, aReferrer, aError);
}
void GetReferrer(nsAString& aReferrer)
{
GetEnumAttr(nsGkAtoms::referrer, nullptr, aReferrer);
}
mozilla::net::ReferrerPolicy
GetImageReferrerPolicy()
{
return GetReferrerPolicy();
}
int32_t X(); int32_t X();
int32_t Y(); int32_t Y();

Просмотреть файл

@ -106,6 +106,8 @@
#include "mozilla/dom/HTMLBodyElement.h" #include "mozilla/dom/HTMLBodyElement.h"
#include "imgIContainer.h" #include "imgIContainer.h"
#include "mozilla/net/ReferrerPolicy.h"
using namespace mozilla; using namespace mozilla;
using namespace mozilla::dom; using namespace mozilla::dom;
@ -995,6 +997,10 @@ nsGenericHTMLElement::ParseAttribute(int32_t aNamespaceID,
return aResult.ParseIntValue(aValue); return aResult.ParseIntValue(aValue);
} }
if (aAttribute == nsGkAtoms::referrer) {
return ParseReferrerAttribute(aValue, aResult);
}
if (aAttribute == nsGkAtoms::name) { if (aAttribute == nsGkAtoms::name) {
// Store name as an atom. name="" means that the element has no name, // Store name as an atom. name="" means that the element has no name,
// not that it has an emptystring as the name. // not that it has an emptystring as the name.
@ -1262,6 +1268,19 @@ nsGenericHTMLElement::ParseImageAttribute(nsIAtom* aAttribute,
return false; return false;
} }
bool
nsGenericHTMLElement::ParseReferrerAttribute(const nsAString& aString,
nsAttrValue& aResult)
{
static const nsAttrValue::EnumTable kReferrerTable[] = {
{ "no-referrer", net::RP_No_Referrer },
{ "origin", net::RP_Origin },
{ "unsafe-url", net::RP_Unsafe_URL },
{ 0 }
};
return aResult.ParseEnumValue(aString, kReferrerTable, false);
}
bool bool
nsGenericHTMLElement::ParseFrameborderValue(const nsAString& aString, nsGenericHTMLElement::ParseFrameborderValue(const nsAString& aString,
nsAttrValue& aResult) nsAttrValue& aResult)

Просмотреть файл

@ -233,6 +233,17 @@ public:
mScrollgrab = aValue; mScrollgrab = aValue;
} }
mozilla::net::ReferrerPolicy
GetReferrerPolicy()
{
nsAutoString aPolicyString;
GetEnumAttr(nsGkAtoms::referrer, nullptr, aPolicyString);
if (aPolicyString.IsEmpty()) {
return mozilla::net::RP_Unset;
}
return mozilla::net::ReferrerPolicyFromString(aPolicyString);
}
/** /**
* Determine whether an attribute is an event (onclick, etc.) * Determine whether an attribute is an event (onclick, etc.)
* @param aName the attribute * @param aName the attribute
@ -711,6 +722,10 @@ public:
static bool ParseImageAttribute(nsIAtom* aAttribute, static bool ParseImageAttribute(nsIAtom* aAttribute,
const nsAString& aString, const nsAString& aString,
nsAttrValue& aResult); nsAttrValue& aResult);
static bool ParseReferrerAttribute(const nsAString& aString,
nsAttrValue& aResult);
/** /**
* Convert a frameborder string to value (yes/no/1/0) * Convert a frameborder string to value (yes/no/1/0)
* *

Просмотреть файл

@ -30,6 +30,8 @@ interface HTMLImageElement : HTMLElement {
[SetterThrows] [SetterThrows]
attribute DOMString useMap; attribute DOMString useMap;
[SetterThrows] [SetterThrows]
attribute DOMString referrer;
[SetterThrows]
attribute boolean isMap; attribute boolean isMap;
[SetterThrows] [SetterThrows]
attribute unsigned long width; attribute unsigned long width;

Просмотреть файл

@ -670,6 +670,9 @@ ValidateSecurityInfo(imgRequest* request, bool forcePrincipalCheck,
nsISupports* aCX, ReferrerPolicy referrerPolicy) nsISupports* aCX, ReferrerPolicy referrerPolicy)
{ {
// If the entry's Referrer Policy doesn't match, we can't use this request. // If the entry's Referrer Policy doesn't match, we can't use this request.
// XXX: this will return false if an image has different referrer attributes,
// i.e. we currently don't use the cached image but reload the image with
// the new referrer policy bug 1174921
if (referrerPolicy != request->GetReferrerPolicy()) { if (referrerPolicy != request->GetReferrerPolicy()) {
return false; return false;
} }

Просмотреть файл

@ -1274,6 +1274,9 @@ pref("network.http.referer.XOriginPolicy", 0);
// By default this is enabled for compatibility (see bug 141641) // By default this is enabled for compatibility (see bug 141641)
pref("network.http.sendSecureXSiteReferrer", true); pref("network.http.sendSecureXSiteReferrer", true);
// Controls whether referrer attributes in <a>, <img>, <area>, and <iframe> are honoured
pref("network.http.enablePerElementReferrer", false);
// Maximum number of consecutive redirects before aborting. // Maximum number of consecutive redirects before aborting.
pref("network.http.redirection-limit", 20); pref("network.http.redirection-limit", 20);

Просмотреть файл

@ -25,7 +25,10 @@ enum ReferrerPolicy {
RP_Origin_When_Crossorigin = nsIHttpChannel::REFERRER_POLICY_ORIGIN_WHEN_XORIGIN, RP_Origin_When_Crossorigin = nsIHttpChannel::REFERRER_POLICY_ORIGIN_WHEN_XORIGIN,
/* spec tokens: always unsafe-url */ /* spec tokens: always unsafe-url */
RP_Unsafe_URL = nsIHttpChannel::REFERRER_POLICY_UNSAFE_URL RP_Unsafe_URL = nsIHttpChannel::REFERRER_POLICY_UNSAFE_URL,
/* referrer policy is not set */
RP_Unset = nsIHttpChannel::REFERRER_POLICY_NO_REFERRER_WHEN_DOWNGRADE
}; };
inline ReferrerPolicy inline ReferrerPolicy

Просмотреть файл

@ -28,10 +28,10 @@ nsHtml5SpeculativeLoad::Perform(nsHtml5TreeOpExecutor* aExecutor)
aExecutor->SetSpeculationBase(mUrl); aExecutor->SetSpeculationBase(mUrl);
break; break;
case eSpeculativeLoadMetaReferrer: case eSpeculativeLoadMetaReferrer:
aExecutor->SetSpeculationReferrerPolicy(mMetaReferrerPolicy); aExecutor->SetSpeculationReferrerPolicy(mReferrerPolicy);
break; break;
case eSpeculativeLoadImage: case eSpeculativeLoadImage:
aExecutor->PreloadImage(mUrl, mCrossOrigin, mSrcset, mSizes); aExecutor->PreloadImage(mUrl, mCrossOrigin, mSrcset, mSizes, mReferrerPolicy);
break; break;
case eSpeculativeLoadOpenPicture: case eSpeculativeLoadOpenPicture:
aExecutor->PreloadOpenPicture(); aExecutor->PreloadOpenPicture();

Просмотреть файл

@ -45,12 +45,13 @@ class nsHtml5SpeculativeLoad {
NS_PRECONDITION(mOpCode == eSpeculativeLoadUninitialized, NS_PRECONDITION(mOpCode == eSpeculativeLoadUninitialized,
"Trying to reinitialize a speculative load!"); "Trying to reinitialize a speculative load!");
mOpCode = eSpeculativeLoadMetaReferrer; mOpCode = eSpeculativeLoadMetaReferrer;
mMetaReferrerPolicy.Assign( mReferrerPolicy.Assign(
nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespace>(aReferrerPolicy)); nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespace>(aReferrerPolicy));
} }
inline void InitImage(const nsAString& aUrl, inline void InitImage(const nsAString& aUrl,
const nsAString& aCrossOrigin, const nsAString& aCrossOrigin,
const nsAString& aReferrerPolicy,
const nsAString& aSrcset, const nsAString& aSrcset,
const nsAString& aSizes) const nsAString& aSizes)
{ {
@ -59,6 +60,8 @@ class nsHtml5SpeculativeLoad {
mOpCode = eSpeculativeLoadImage; mOpCode = eSpeculativeLoadImage;
mUrl.Assign(aUrl); mUrl.Assign(aUrl);
mCrossOrigin.Assign(aCrossOrigin); mCrossOrigin.Assign(aCrossOrigin);
mReferrerPolicy.Assign(
nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespace>(aReferrerPolicy));
mSrcset.Assign(aSrcset); mSrcset.Assign(aSrcset);
mSizes.Assign(aSizes); mSizes.Assign(aSizes);
} }
@ -179,7 +182,7 @@ class nsHtml5SpeculativeLoad {
private: private:
eHtml5SpeculativeLoad mOpCode; eHtml5SpeculativeLoad mOpCode;
nsString mUrl; nsString mUrl;
nsString mMetaReferrerPolicy; nsString mReferrerPolicy;
/** /**
* If mOpCode is eSpeculativeLoadStyle or eSpeculativeLoadScript[FromHead] * If mOpCode is eSpeculativeLoadStyle or eSpeculativeLoadScript[FromHead]
* then this is the value of the "charset" attribute. For * then this is the value of the "charset" attribute. For

Просмотреть файл

@ -125,11 +125,14 @@ nsHtml5TreeBuilder::createElement(int32_t aNamespace, nsIAtom* aName,
aAttributes->getValue(nsHtml5AttributeName::ATTR_SRCSET); aAttributes->getValue(nsHtml5AttributeName::ATTR_SRCSET);
nsString* crossOrigin = nsString* crossOrigin =
aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN); aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN);
nsString* referrerPolicy =
aAttributes->getValue(nsHtml5AttributeName::ATTR_REFERRER);
nsString* sizes = nsString* sizes =
aAttributes->getValue(nsHtml5AttributeName::ATTR_SIZES); aAttributes->getValue(nsHtml5AttributeName::ATTR_SIZES);
mSpeculativeLoadQueue.AppendElement()-> mSpeculativeLoadQueue.AppendElement()->
InitImage(url ? *url : NullString(), InitImage(url ? *url : NullString(),
crossOrigin ? *crossOrigin : NullString(), crossOrigin ? *crossOrigin : NullString(),
referrerPolicy ? *referrerPolicy : NullString(),
srcset ? *srcset : NullString(), srcset ? *srcset : NullString(),
sizes ? *sizes : NullString()); sizes ? *sizes : NullString());
} else if (nsHtml5Atoms::source == aName) { } else if (nsHtml5Atoms::source == aName) {
@ -202,6 +205,7 @@ nsHtml5TreeBuilder::createElement(int32_t aNamespace, nsIAtom* aName,
nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_POSTER); nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_POSTER);
if (url) { if (url) {
mSpeculativeLoadQueue.AppendElement()->InitImage(*url, NullString(), mSpeculativeLoadQueue.AppendElement()->InitImage(*url, NullString(),
NullString(),
NullString(), NullString(),
NullString()); NullString());
} }
@ -238,6 +242,7 @@ nsHtml5TreeBuilder::createElement(int32_t aNamespace, nsIAtom* aName,
nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_XLINK_HREF); nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_XLINK_HREF);
if (url) { if (url) {
mSpeculativeLoadQueue.AppendElement()->InitImage(*url, NullString(), mSpeculativeLoadQueue.AppendElement()->InitImage(*url, NullString(),
NullString(),
NullString(), NullString(),
NullString()); NullString());
} }

Просмотреть файл

@ -943,13 +943,25 @@ void
nsHtml5TreeOpExecutor::PreloadImage(const nsAString& aURL, nsHtml5TreeOpExecutor::PreloadImage(const nsAString& aURL,
const nsAString& aCrossOrigin, const nsAString& aCrossOrigin,
const nsAString& aSrcset, const nsAString& aSrcset,
const nsAString& aSizes) const nsAString& aSizes,
const nsAString& aImageReferrerPolicy)
{ {
nsCOMPtr<nsIURI> baseURI = BaseURIForPreload(); nsCOMPtr<nsIURI> baseURI = BaseURIForPreload();
nsCOMPtr<nsIURI> uri = mDocument->ResolvePreloadImage(baseURI, aURL, aSrcset, nsCOMPtr<nsIURI> uri = mDocument->ResolvePreloadImage(baseURI, aURL, aSrcset,
aSizes); aSizes);
if (uri && ShouldPreloadURI(uri)) { if (uri && ShouldPreloadURI(uri)) {
mDocument->MaybePreLoadImage(uri, aCrossOrigin, mSpeculationReferrerPolicy); // 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", false);
if (referrerAttributeEnabled) {
mozilla::net::ReferrerPolicy imageReferrerPolicy = mozilla::net::ReferrerPolicyFromString(aImageReferrerPolicy);
if (imageReferrerPolicy != mozilla::net::RP_Unset) {
referrerPolicy = imageReferrerPolicy;
}
}
mDocument->MaybePreLoadImage(uri, aCrossOrigin, referrerPolicy);
} }
} }

Просмотреть файл

@ -256,7 +256,8 @@ class nsHtml5TreeOpExecutor final : public nsHtml5DocumentBuilder,
void PreloadImage(const nsAString& aURL, void PreloadImage(const nsAString& aURL,
const nsAString& aCrossOrigin, const nsAString& aCrossOrigin,
const nsAString& aSrcset, const nsAString& aSrcset,
const nsAString& aSizes); const nsAString& aSizes,
const nsAString& aImageReferrerPolicy);
void PreloadOpenPicture(); void PreloadOpenPicture();