Bug 1174913 - anchor and area referrer attributes. r=ckerschb, r=bz

This commit is contained in:
Franziskus Kiefer 2015-06-05 15:25:24 -07:00
Родитель 95250b2dbf
Коммит e97220a88e
11 изменённых файлов: 165 добавлений и 21 удалений

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

@ -5610,11 +5610,24 @@ function handleLinkClick(event, href, linkNode) {
catch (e) { }
}
// first get document wide referrer policy, then
// get referrer attribute from clicked link and parse it and
// allow per element referrer to overrule the document wide referrer if enabled
let referrerPolicy = doc.referrerPolicy;
if (Services.prefs.getBoolPref("network.http.enablePerElementReferrer") &&
linkNode) {
let referrerAttrValue = Services.netUtils.parseAttributePolicyString(linkNode.
getAttribute("referrer"));
if (referrerAttrValue != Ci.nsIHttpChannel.REFERRER_POLICY_DEFAULT) {
referrerPolicy = referrerAttrValue;
}
}
urlSecurityCheck(href, doc.nodePrincipal);
let params = { charset: doc.characterSet,
allowMixedContent: persistAllowMixedContentInChildTab,
referrerURI: referrerURI,
referrerPolicy: doc.referrerPolicy,
referrerPolicy: referrerPolicy,
noReferrer: BrowserUtils.linkHasNoReferrer(linkNode) };
openLinkIn(href, where, params);
event.preventDefault();

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

@ -105,6 +105,17 @@ let handleContentContextMenu = function (event) {
.getInterface(Ci.nsIDOMWindowUtils)
.outerWindowID;
// get referrer attribute from clicked link and parse it
// if per element referrer is enabled, the element referrer overrules
// the document wide referrer
if (Services.prefs.getBoolPref("network.http.enablePerElementReferrer")) {
let referrerAttrValue = Services.netUtils.parseAttributePolicyString(event.target.
getAttribute("referrer"));
if (referrerAttrValue !== Ci.nsIHttpChannel.REFERRER_POLICY_DEFAULT) {
referrerPolicy = referrerAttrValue;
}
}
let disableSetDesktopBg = null;
// Media related cache info parent needs for saving
let contentType = null;
@ -351,10 +362,23 @@ let ClickEventHandler = {
let [href, node] = this._hrefAndLinkNodeForClickEvent(event);
// get referrer attribute from clicked link and parse it
// if per element referrer is enabled, the element referrer overrules
// the document wide referrer
let referrerPolicy = ownerDoc.referrerPolicy;
if (Services.prefs.getBoolPref("network.http.enablePerElementReferrer") &&
node) {
let referrerAttrValue = Services.netUtils.parseAttributePolicyString(node.
getAttribute("referrer"));
if (referrerAttrValue !== Ci.nsIHttpChannel.REFERRER_POLICY_DEFAULT) {
referrerPolicy = referrerAttrValue;
}
}
let json = { button: event.button, shiftKey: event.shiftKey,
ctrlKey: event.ctrlKey, metaKey: event.metaKey,
altKey: event.altKey, href: null, title: null,
bookmark: false, referrerPolicy: ownerDoc.referrerPolicy };
bookmark: false, referrerPolicy: referrerPolicy };
if (href) {
try {

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

@ -13515,6 +13515,22 @@ nsDocShell::OnLinkClickSync(nsIContent* aContent,
nsCOMPtr<nsIURI> referer = refererDoc->GetDocumentURI();
uint32_t refererPolicy = refererDoc->GetReferrerPolicy();
// get referrer attribute from clicked link and parse it
// if per element referrer is enabled, the element referrer overrules
// the document wide referrer
if (IsElementAnchor(aContent)) {
MOZ_ASSERT(aContent->IsHTMLElement());
if (Preferences::GetBool("network.http.enablePerElementReferrer", false)) {
nsAutoString referrerPolicy;
if (aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::referrer, referrerPolicy)) {
uint32_t refPolEnum = mozilla::net::ReferrerPolicyFromString(referrerPolicy);
if (refPolEnum != mozilla::net::RP_Unset) {
refererPolicy = refPolEnum;
}
}
}
}
// referer could be null here in some odd cases, but that's ok,
// we'll just load the link w/o sending a referer in those cases.

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

@ -123,6 +123,14 @@ public:
{
SetHTMLAttr(nsGkAtoms::rel, aValue, rv);
}
void SetReferrer(const nsAString& aValue, mozilla::ErrorResult& rv)
{
SetHTMLAttr(nsGkAtoms::referrer, aValue, rv);
}
void GetReferrer(nsAString& aReferrer)
{
GetHTMLAttr(nsGkAtoms::referrer, aReferrer);
}
nsDOMTokenList* RelList();
void GetHreflang(DOMString& aValue)
{

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

@ -128,6 +128,15 @@ public:
}
nsDOMTokenList* RelList();
void SetReferrer(const nsAString& aValue, mozilla::ErrorResult& rv)
{
SetHTMLAttr(nsGkAtoms::referrer, aValue, rv);
}
void GetReferrer(nsAString& aReferrer)
{
GetHTMLAttr(nsGkAtoms::referrer, aReferrer);
}
// The Link::GetOrigin is OK for us
using Link::GetProtocol;

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

@ -21,6 +21,8 @@ interface HTMLAnchorElement : HTMLElement {
attribute DOMString ping;
[SetterThrows]
attribute DOMString rel;
[SetterThrows, Pref="network.http.enablePerElementReferrer"]
attribute DOMString referrer;
readonly attribute DOMTokenList relList;
[SetterThrows]
attribute DOMString hreflang;

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

@ -28,6 +28,8 @@ interface HTMLAreaElement : HTMLElement {
attribute DOMString ping;
[SetterThrows]
attribute DOMString rel;
[SetterThrows, Pref="network.http.enablePerElementReferrer"]
attribute DOMString referrer;
readonly attribute DOMTokenList relList;
// not implemented.

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

@ -31,28 +31,47 @@ enum ReferrerPolicy {
RP_Unset = nsIHttpChannel::REFERRER_POLICY_NO_REFERRER_WHEN_DOWNGRADE
};
/* spec tokens: never no-referrer */
const char kRPS_Never[] = "never";
const char kRPS_No_Referrer[] = "no-referrer";
/* spec tokens: origin */
const char kRPS_Origin[] = "origin";
/* spec tokens: default no-referrer-when-downgrade */
const char kRPS_Default[] = "default";
const char kRPS_No_Referrer_When_Downgrade[] = "no-referrer-when-downgrade";
/* spec tokens: origin-when-cross-origin */
const char kRPS_Origin_When_Cross_Origin[] = "origin-when-cross-origin";
const char kRPS_Origin_When_Crossorigin[] = "origin-when-crossorigin";
/* spec tokens: always unsafe-url */
const char kRPS_Always[] = "always";
const char kRPS_Unsafe_URL[] = "unsafe-url";
inline ReferrerPolicy
ReferrerPolicyFromString(const nsAString& content)
{
// This is implemented step by step as described in the Referrer Policy
// specification, section 6.4 "Determine token's Policy".
if (content.LowerCaseEqualsLiteral("never") ||
content.LowerCaseEqualsLiteral("no-referrer")) {
if (content.LowerCaseEqualsLiteral(kRPS_Never) ||
content.LowerCaseEqualsLiteral(kRPS_No_Referrer)) {
return RP_No_Referrer;
}
if (content.LowerCaseEqualsLiteral("origin")) {
if (content.LowerCaseEqualsLiteral(kRPS_Origin)) {
return RP_Origin;
}
if (content.LowerCaseEqualsLiteral("default") ||
content.LowerCaseEqualsLiteral("no-referrer-when-downgrade")) {
if (content.LowerCaseEqualsLiteral(kRPS_Default) ||
content.LowerCaseEqualsLiteral(kRPS_No_Referrer_When_Downgrade)) {
return RP_No_Referrer_When_Downgrade;
}
if (content.LowerCaseEqualsLiteral("origin-when-cross-origin") ||
content.LowerCaseEqualsLiteral("origin-when-crossorigin")) {
if (content.LowerCaseEqualsLiteral(kRPS_Origin_When_Cross_Origin) ||
content.LowerCaseEqualsLiteral(kRPS_Origin_When_Crossorigin)) {
return RP_Origin_When_Crossorigin;
}
if (content.LowerCaseEqualsLiteral("always") ||
content.LowerCaseEqualsLiteral("unsafe-url")) {
if (content.LowerCaseEqualsLiteral(kRPS_Always) ||
content.LowerCaseEqualsLiteral(kRPS_Unsafe_URL)) {
return RP_Unsafe_URL;
}
// Spec says if none of the previous match, use No_Referrer.
@ -63,15 +82,42 @@ ReferrerPolicyFromString(const nsAString& content)
inline bool
IsValidReferrerPolicy(const nsAString& content)
{
return content.LowerCaseEqualsLiteral("never")
|| content.LowerCaseEqualsLiteral("no-referrer")
|| content.LowerCaseEqualsLiteral("origin")
|| content.LowerCaseEqualsLiteral("default")
|| content.LowerCaseEqualsLiteral("no-referrer-when-downgrade")
|| content.LowerCaseEqualsLiteral("origin-when-cross-origin")
|| content.LowerCaseEqualsLiteral("origin-when-crossorigin")
|| content.LowerCaseEqualsLiteral("always")
|| content.LowerCaseEqualsLiteral("unsafe-url");
return content.LowerCaseEqualsLiteral(kRPS_Never)
|| content.LowerCaseEqualsLiteral(kRPS_No_Referrer)
|| content.LowerCaseEqualsLiteral(kRPS_Origin)
|| content.LowerCaseEqualsLiteral(kRPS_Default)
|| content.LowerCaseEqualsLiteral(kRPS_No_Referrer_When_Downgrade)
|| content.LowerCaseEqualsLiteral(kRPS_Origin_When_Cross_Origin)
|| content.LowerCaseEqualsLiteral(kRPS_Origin_When_Crossorigin)
|| content.LowerCaseEqualsLiteral(kRPS_Always)
|| content.LowerCaseEqualsLiteral(kRPS_Unsafe_URL);
}
inline bool
IsValidAttributeReferrerPolicy(const nsAString& aContent)
{
// Spec allows only these three policies at the moment
// See bug 1178337
return aContent.LowerCaseEqualsLiteral(kRPS_No_Referrer)
|| aContent.LowerCaseEqualsLiteral(kRPS_Origin)
|| aContent.LowerCaseEqualsLiteral(kRPS_Unsafe_URL);
}
inline ReferrerPolicy
AttributeReferrerPolicyFromString(const nsAString& aContent)
{
// if the referrer attribute string is empty, return RP_Unset
if (aContent.IsEmpty()) {
return RP_Unset;
}
// if the referrer attribute string is not empty and contains a valid
// referrer policy, return the according enum value
if (IsValidAttributeReferrerPolicy(aContent)) {
return ReferrerPolicyFromString(aContent);
}
// in any other case the referrer attribute contains an invalid
// policy value, we thus return RP_No_Referrer
return RP_No_Referrer;
}
} // namespace net

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

@ -11,7 +11,7 @@ interface nsIPrefBranch;
/**
* nsINetUtil provides various network-related utility methods.
*/
[scriptable, uuid(ca68c485-9db3-4c12-82a6-4fab7948e2d5)]
[scriptable, uuid(885d6940-1001-46e7-92ec-d494a78d7784)]
interface nsINetUtil : nsISupports
{
/**
@ -192,4 +192,16 @@ interface nsINetUtil : nsISupports
out AUTF8String aCharset,
out long aCharsetStart,
out long aCharsetEnd);
/**
* Parse an attribute referrer policy string (no-referrer, origin, unsafe-url)
* and return the according integer code (defined in nsIHttpChannel.idl)
*
* @param aPolicyString
* the policy string given as attribute
* @return aPolicyEnum
* referrer policy code from nsIHttpChannel.idl, (see parser in
* ReferrerPolicy.h for details)
*/
unsigned long parseAttributePolicyString(in AString aPolicyString);
};

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

@ -45,6 +45,7 @@
#include "mozilla/Telemetry.h"
#include "mozilla/net/DNS.h"
#include "CaptivePortalService.h"
#include "ReferrerPolicy.h"
#ifdef MOZ_WIDGET_GONK
#include "nsINetworkManager.h"
@ -1690,6 +1691,16 @@ nsIOService::ExtractCharsetFromContentType(const nsACString &aTypeHeader,
return NS_OK;
}
// parse policyString to policy enum value (see ReferrerPolicy.h)
NS_IMETHODIMP
nsIOService::ParseAttributePolicyString(const nsAString& policyString,
uint32_t *outPolicyEnum)
{
NS_ENSURE_ARG(outPolicyEnum);
*outPolicyEnum = (uint32_t)mozilla::net::AttributeReferrerPolicyFromString(policyString);
return NS_OK;
}
// nsISpeculativeConnect
class IOServiceProxyCallback final : public nsIProtocolProxyCallback
{

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

@ -100,6 +100,7 @@ let initTable = [
["focus", "@mozilla.org/focus-manager;1", "nsIFocusManager"],
["uriFixup", "@mozilla.org/docshell/urifixup;1", "nsIURIFixup"],
["blocklist", "@mozilla.org/extensions/blocklist;1", "nsIBlocklistService"],
["netUtils", "@mozilla.org/network/util;1", "nsINetUtil"],
];
initTable.forEach(([name, contract, intf, enabled = true]) => {