Bug 704320 - Parse and implement meta tag-based referrer policies for documents and nsHttpChannels. (r=bz,mcmanus)

This commit is contained in:
Owen Chu 2014-11-18 08:46:29 -05:00
parent 41b6632668
commit 290f6d6062
28 changed files with 409 additions and 38 deletions

View File

@ -187,8 +187,10 @@ let SessionHistoryInternal = {
// We will include the property only if it's truthy to save a couple of
// bytes when the resulting object is stringified and saved to disk.
if (shEntry.referrerURI)
if (shEntry.referrerURI) {
entry.referrer = shEntry.referrerURI.spec;
entry.referrerPolicy = shEntry.referrerPolicy;
}
if (shEntry.srcdocData)
entry.srcdocData = shEntry.srcdocData;
@ -340,8 +342,10 @@ let SessionHistoryInternal = {
shEntry.loadType = Ci.nsIDocShellLoadInfo.loadHistory;
if (entry.contentType)
shEntry.contentType = entry.contentType;
if (entry.referrer)
if (entry.referrer) {
shEntry.referrerURI = Utils.makeURI(entry.referrer);
shEntry.referrerPolicy = entry.referrerPolicy;
}
if (entry.isSrcdocEntry)
shEntry.srcdocData = entry.srcdocData;
if (entry.baseURI)

View File

@ -38,6 +38,7 @@
#include "nsDocShellCID.h"
#include "nsDOMCID.h"
#include "nsNetUtil.h"
#include "mozilla/net/ReferrerPolicy.h"
#include "nsRect.h"
#include "prenv.h"
#include "nsIDOMWindow.h"
@ -554,6 +555,7 @@ struct SendPingInfo {
bool requireSameHost;
nsIURI *target;
nsIURI *referrer;
uint32_t referrerPolicy;
};
static void
@ -633,7 +635,7 @@ SendPing(void *closure, nsIContent *content, nsIURI *uri, nsIIOService *ios)
// over an encrypted connection and its address does not have the same
// origin as "ping URL", send a referrer.
if (!sameOrigin && !referrerIsSecure)
httpChan->SetReferrer(info->referrer);
httpChan->SetReferrerWithPolicy(info->referrer, info->referrerPolicy);
}
nsCOMPtr<nsIUploadChannel2> uploadChan = do_QueryInterface(httpChan);
@ -691,7 +693,10 @@ SendPing(void *closure, nsIContent *content, nsIURI *uri, nsIIOService *ios)
// Spec: http://whatwg.org/specs/web-apps/current-work/#ping
static void
DispatchPings(nsIContent *content, nsIURI *target, nsIURI *referrer)
DispatchPings(nsIContent *content,
nsIURI *target,
nsIURI *referrer,
uint32_t referrerPolicy)
{
SendPingInfo info;
@ -703,6 +708,7 @@ DispatchPings(nsIContent *content, nsIURI *target, nsIURI *referrer)
info.numPings = 0;
info.target = target;
info.referrer = referrer;
info.referrerPolicy = referrerPolicy;
ForEachPing(content, SendPing, &info);
}
@ -1346,6 +1352,7 @@ nsDocShell::LoadURI(nsIURI * aURI,
bool inheritOwner = false;
bool ownerIsExplicit = false;
bool sendReferrer = true;
uint32_t referrerPolicy = mozilla::net::RP_Default;
bool isSrcdoc = false;
nsCOMPtr<nsISHEntry> shEntry;
nsXPIDLString target;
@ -1379,6 +1386,7 @@ nsDocShell::LoadURI(nsIURI * aURI,
aLoadInfo->GetPostDataStream(getter_AddRefs(postStream));
aLoadInfo->GetHeadersStream(getter_AddRefs(headersStream));
aLoadInfo->GetSendReferrer(&sendReferrer);
aLoadInfo->GetReferrerPolicy(&referrerPolicy);
aLoadInfo->GetIsSrcdocLoad(&isSrcdoc);
aLoadInfo->GetSrcdocData(srcdoc);
aLoadInfo->GetSourceDocShell(getter_AddRefs(sourceDocShell));
@ -1602,6 +1610,7 @@ nsDocShell::LoadURI(nsIURI * aURI,
return InternalLoad(aURI,
referrer,
referrerPolicy,
owner,
flags,
target.get(),
@ -5265,8 +5274,8 @@ nsDocShell::LoadErrorPage(nsIURI *aURI, const char16_t *aURL,
rv = NS_NewURI(getter_AddRefs(errorPageURI), errorPageUrl);
NS_ENSURE_SUCCESS(rv, rv);
return InternalLoad(errorPageURI, nullptr, nullptr,
INTERNAL_LOAD_FLAGS_INHERIT_OWNER, nullptr, nullptr,
return InternalLoad(errorPageURI, nullptr, mozilla::net::RP_Default,
nullptr, INTERNAL_LOAD_FLAGS_INHERIT_OWNER, nullptr, nullptr,
NullString(), nullptr, nullptr, LOAD_ERROR_PAGE,
nullptr, true, NullString(), this, nullptr, nullptr,
nullptr);
@ -5328,6 +5337,7 @@ nsDocShell::Reload(uint32_t aReloadFlags)
}
rv = InternalLoad(mCurrentURI,
mReferrerURI,
mReferrerPolicy,
principal,
flags,
nullptr, // No window target
@ -9230,7 +9240,8 @@ void CopyFavicon(nsIURI *aOldURI, nsIURI *aNewURI, bool inPrivateBrowsing)
class InternalLoadEvent : public nsRunnable
{
public:
InternalLoadEvent(nsDocShell* aDocShell, nsIURI * aURI, nsIURI * aReferrer,
InternalLoadEvent(nsDocShell* aDocShell, nsIURI * aURI,
nsIURI * aReferrer, uint32_t aReferrerPolicy,
nsISupports * aOwner, uint32_t aFlags,
const char* aTypeHint, nsIInputStream * aPostData,
nsIInputStream * aHeadersData, uint32_t aLoadType,
@ -9241,6 +9252,7 @@ public:
mDocShell(aDocShell),
mURI(aURI),
mReferrer(aReferrer),
mReferrerPolicy(aReferrerPolicy),
mOwner(aOwner),
mPostData(aPostData),
mHeadersData(aHeadersData),
@ -9258,7 +9270,9 @@ public:
}
NS_IMETHOD Run() {
return mDocShell->InternalLoad(mURI, mReferrer, mOwner, mFlags,
return mDocShell->InternalLoad(mURI, mReferrer,
mReferrerPolicy,
mOwner, mFlags,
nullptr, mTypeHint.get(),
NullString(), mPostData, mHeadersData,
mLoadType, mSHEntry, mFirstParty,
@ -9276,6 +9290,7 @@ private:
nsRefPtr<nsDocShell> mDocShell;
nsCOMPtr<nsIURI> mURI;
nsCOMPtr<nsIURI> mReferrer;
uint32_t mReferrerPolicy;
nsCOMPtr<nsISupports> mOwner;
nsCOMPtr<nsIInputStream> mPostData;
nsCOMPtr<nsIInputStream> mHeadersData;
@ -9330,6 +9345,7 @@ nsDocShell::CreatePrincipalFromReferrer(nsIURI* aReferrer,
NS_IMETHODIMP
nsDocShell::InternalLoad(nsIURI * aURI,
nsIURI * aReferrer,
uint32_t aReferrerPolicy,
nsISupports * aOwner,
uint32_t aFlags,
const char16_t *aWindowTarget,
@ -9586,6 +9602,7 @@ nsDocShell::InternalLoad(nsIURI * aURI,
if (NS_SUCCEEDED(rv) && targetDocShell) {
rv = targetDocShell->InternalLoad(aURI,
aReferrer,
aReferrerPolicy,
owner,
aFlags,
nullptr, // No window target
@ -9666,7 +9683,8 @@ nsDocShell::InternalLoad(nsIURI * aURI,
// Do this asynchronously
nsCOMPtr<nsIRunnable> ev =
new InternalLoadEvent(this, aURI, aReferrer, aOwner, aFlags,
new InternalLoadEvent(this, aURI, aReferrer,
aReferrerPolicy, aOwner, aFlags,
aTypeHint, aPostData, aHeadersData,
aLoadType, aSHEntry, aFirstParty, aSrcdoc,
aSourceDocShell, aBaseURI);
@ -10118,6 +10136,7 @@ nsDocShell::InternalLoad(nsIURI * aURI,
nsCOMPtr<nsIRequest> req;
rv = DoURILoad(aURI, aReferrer,
!(aFlags & INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER),
aReferrerPolicy,
owner, aTypeHint, aFileName, aPostData, aHeadersData,
aFirstParty, aDocShell, getter_AddRefs(req),
(aFlags & INTERNAL_LOAD_FLAGS_FIRST_LOAD) != 0,
@ -10191,6 +10210,7 @@ nsresult
nsDocShell::DoURILoad(nsIURI * aURI,
nsIURI * aReferrerURI,
bool aSendReferrer,
uint32_t aReferrerPolicy,
nsISupports * aOwner,
const char * aTypeHint,
const nsAString & aFileName,
@ -10520,7 +10540,7 @@ nsDocShell::DoURILoad(nsIURI * aURI,
// Set the referrer explicitly
if (aReferrerURI && aSendReferrer) {
// Referrer is currenly only set for link clicks here.
httpChannel->SetReferrer(aReferrerURI);
httpChannel->SetReferrerWithPolicy(aReferrerURI, aReferrerPolicy);
}
}
@ -10856,6 +10876,11 @@ nsDocShell::SetupReferrerFromChannel(nsIChannel * aChannel)
if (NS_SUCCEEDED(rv)) {
SetReferrerURI(referrer);
}
uint32_t referrerPolicy;
rv = httpChannel->GetReferrerPolicy(&referrerPolicy);
if (NS_SUCCEEDED(rv)) {
SetReferrerPolicy(referrerPolicy);
}
}
}
@ -11123,6 +11148,12 @@ nsDocShell::SetReferrerURI(nsIURI * aURI)
mReferrerURI = aURI; // This assigment addrefs
}
void
nsDocShell::SetReferrerPolicy(uint32_t referrerPolicy)
{
mReferrerPolicy = referrerPolicy;
}
//*****************************************************************************
// nsDocShell: Session History
//*****************************************************************************
@ -11552,6 +11583,7 @@ nsDocShell::AddToSessionHistory(nsIURI * aURI, nsIChannel * aChannel,
// Get the post data & referrer
nsCOMPtr<nsIInputStream> inputStream;
nsCOMPtr<nsIURI> referrerURI;
uint32_t referrerPolicy = mozilla::net::RP_Default;
nsCOMPtr<nsISupports> cacheKey;
nsCOMPtr<nsISupports> owner = aOwner;
bool expired = false;
@ -11578,6 +11610,7 @@ nsDocShell::AddToSessionHistory(nsIURI * aURI, nsIChannel * aChannel,
uploadChannel->GetUploadStream(getter_AddRefs(inputStream));
}
httpChannel->GetReferrer(getter_AddRefs(referrerURI));
httpChannel->GetReferrerPolicy(&referrerPolicy);
discardLayoutState = ShouldDiscardLayoutState(httpChannel);
}
@ -11608,6 +11641,7 @@ nsDocShell::AddToSessionHistory(nsIURI * aURI, nsIChannel * aChannel,
mHistoryID,
mDynamicallyCreated);
entry->SetReferrerURI(referrerURI);
entry->SetReferrerPolicy(referrerPolicy);
nsCOMPtr<nsIInputStreamChannel> inStrmChan = do_QueryInterface(aChannel);
if (inStrmChan) {
bool isSrcdocChannel;
@ -11707,6 +11741,7 @@ nsDocShell::LoadHistoryEntry(nsISHEntry * aEntry, uint32_t aLoadType)
nsCOMPtr<nsIURI> uri;
nsCOMPtr<nsIInputStream> postData;
nsCOMPtr<nsIURI> referrerURI;
uint32_t referrerPolicy;
nsAutoCString contentType;
nsCOMPtr<nsISupports> owner;
@ -11715,6 +11750,8 @@ nsDocShell::LoadHistoryEntry(nsISHEntry * aEntry, uint32_t aLoadType)
NS_ENSURE_SUCCESS(aEntry->GetURI(getter_AddRefs(uri)), NS_ERROR_FAILURE);
NS_ENSURE_SUCCESS(aEntry->GetReferrerURI(getter_AddRefs(referrerURI)),
NS_ERROR_FAILURE);
NS_ENSURE_SUCCESS(aEntry->GetReferrerPolicy(&referrerPolicy),
NS_ERROR_FAILURE);
NS_ENSURE_SUCCESS(aEntry->GetPostData(getter_AddRefs(postData)),
NS_ERROR_FAILURE);
NS_ENSURE_SUCCESS(aEntry->GetContentType(contentType), NS_ERROR_FAILURE);
@ -11791,6 +11828,7 @@ nsDocShell::LoadHistoryEntry(nsISHEntry * aEntry, uint32_t aLoadType)
// first created. bug 947716 has been created to address this issue.
rv = InternalLoad(uri,
referrerURI,
referrerPolicy,
owner,
flags,
nullptr, // No window target
@ -13192,6 +13230,7 @@ nsDocShell::OnLinkClickSync(nsIContent *aContent,
}
nsCOMPtr<nsIURI> referer = refererDoc->GetDocumentURI();
uint32_t refererPolicy = refererDoc->GetReferrerPolicy();
// 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.
@ -13220,6 +13259,7 @@ nsDocShell::OnLinkClickSync(nsIContent *aContent,
nsresult rv = InternalLoad(clonedURI, // New URI
referer, // Referer URI
refererPolicy, // Referer policy
aContent->NodePrincipal(), // Owner is our node's
// principal
flags,
@ -13237,7 +13277,7 @@ nsDocShell::OnLinkClickSync(nsIContent *aContent,
aDocShell, // DocShell out-param
aRequest); // Request out-param
if (NS_SUCCEEDED(rv)) {
DispatchPings(aContent, aURI, referer);
DispatchPings(aContent, aURI, referer, refererPolicy);
}
return rv;
}

View File

@ -310,6 +310,7 @@ protected:
virtual nsresult DoURILoad(nsIURI * aURI,
nsIURI * aReferrer,
bool aSendReferrer,
uint32_t aReferrerPolicy,
nsISupports * aOwner,
const char * aTypeHint,
const nsAString & aFileName,
@ -358,6 +359,7 @@ protected:
bool aCloneSHChildren);
virtual void SetReferrerURI(nsIURI * aURI);
virtual void SetReferrerPolicy(uint32_t referrerPolicy);
// Session History
virtual bool ShouldAddToSessionHistory(nsIURI * aURI);
@ -752,6 +754,7 @@ protected:
// mCurrentURI should be marked immutable on set if possible.
nsCOMPtr<nsIURI> mCurrentURI;
nsCOMPtr<nsIURI> mReferrerURI;
uint32_t mReferrerPolicy;
nsRefPtr<nsGlobalWindow> mScriptGlobal;
nsCOMPtr<nsISHistory> mSessionHistory;
nsCOMPtr<nsIGlobalHistory2> mGlobalHistory;

View File

@ -10,6 +10,7 @@
#include "nsIInputStream.h"
#include "nsIURI.h"
#include "nsIDocShell.h"
#include "mozilla/net/ReferrerPolicy.h"
//*****************************************************************************
//*** nsDocShellLoadInfo: Object Management
@ -19,6 +20,7 @@ nsDocShellLoadInfo::nsDocShellLoadInfo()
: mInheritOwner(false),
mOwnerIsExplicit(false),
mSendReferrer(true),
mReferrerPolicy(mozilla::net::RP_Default),
mLoadType(nsIDocShellLoadInfo::loadNormal),
mIsSrcdocLoad(false)
{
@ -192,6 +194,18 @@ NS_IMETHODIMP nsDocShellLoadInfo::SetSendReferrer(bool aSendReferrer)
return NS_OK;
}
NS_IMETHODIMP nsDocShellLoadInfo::GetReferrerPolicy(nsDocShellInfoReferrerPolicy* aReferrerPolicy)
{
*aReferrerPolicy = mReferrerPolicy;
return NS_OK;
}
NS_IMETHODIMP nsDocShellLoadInfo::SetReferrerPolicy(nsDocShellInfoReferrerPolicy aReferrerPolicy)
{
mReferrerPolicy = aReferrerPolicy;
return NS_OK;
}
NS_IMETHODIMP nsDocShellLoadInfo::GetIsSrcdocLoad(bool* aIsSrcdocLoad)
{
*aIsSrcdocLoad = mIsSrcdocLoad;

View File

@ -37,6 +37,7 @@ protected:
bool mInheritOwner;
bool mOwnerIsExplicit;
bool mSendReferrer;
nsDocShellInfoReferrerPolicy mReferrerPolicy;
nsDocShellInfoLoadType mLoadType;
nsCOMPtr<nsISHEntry> mSHEntry;
nsString mTarget;

View File

@ -54,7 +54,7 @@ interface nsITabParent;
typedef unsigned long nsLoadFlags;
[scriptable, builtinclass, uuid(4e3de242-0b2a-4cf0-81b5-a5fe8628431c)]
[scriptable, builtinclass, uuid(c2756385-bc54-417b-9ae4-c5a40053a2a3)]
interface nsIDocShell : nsIDocShellTreeItem
{
/**
@ -132,6 +132,7 @@ interface nsIDocShell : nsIDocShellTreeItem
*
* @param aURI - The URI to load.
* @param aReferrer - Referring URI
* @param aReferrerPolicy - Referrer policy
* @param aOwner - Owner (security principal)
* @param aInheritOwner - Flag indicating whether the owner of the current
* document should be inherited if aOwner is null.
@ -157,6 +158,7 @@ interface nsIDocShell : nsIDocShellTreeItem
*/
[noscript]void internalLoad(in nsIURI aURI,
in nsIURI aReferrer,
in unsigned long aReferrerPolicy,
in nsISupports aOwner,
in uint32_t aFlags,
in wstring aWindowTarget,

View File

@ -17,8 +17,9 @@ interface nsISHEntry;
interface nsIDocShell;
typedef long nsDocShellInfoLoadType;
typedef unsigned long nsDocShellInfoReferrerPolicy;
[scriptable, uuid(c8d3b1e1-565a-427e-9d68-b109910ce9b7)]
[scriptable, uuid(c63e9d64-490d-48bf-8013-b5d8ee4dbc25)]
interface nsIDocShellLoadInfo : nsISupports
{
/** This is the referrer for the load. */
@ -85,6 +86,11 @@ interface nsIDocShellLoadInfo : nsISupports
*/
attribute boolean sendReferrer;
/** Referrer policy for the load. This attribute holds one of
* the values (REFERRER_POLICY_*) defined in nsIHttpChannel.
*/
attribute nsDocShellInfoReferrerPolicy referrerPolicy;
/** True if the docshell has been created to load an iframe where the
* srcdoc attribute has been set. Set when srcdocData is specified.
*/

View File

@ -30,7 +30,7 @@ class nsSHEntryShared;
[ptr] native nsDocShellEditorDataPtr(nsDocShellEditorData);
[ptr] native nsSHEntryShared(nsSHEntryShared);
[scriptable, uuid(9eed7e92-1121-46f2-95e5-2f5c0dca46f0)]
[scriptable, uuid(d5fbeb10-f373-4677-b69a-2694aa706cac)]
interface nsISHEntry : nsISupports
{
/**
@ -64,6 +64,11 @@ interface nsISHEntry : nsISupports
/** Referrer URI */
attribute nsIURI referrerURI;
/** Referrer policy, holding one of the values (REFERRER_POLICY_*)
* defined in nsIHttpChannel.
*/
attribute unsigned long referrerPolicy;
/** Content viewer, for fast restoration of presentation */
attribute nsIContentViewer contentViewer;

View File

@ -15,6 +15,7 @@
#include "nsIStructuredCloneContainer.h"
#include "nsIInputStream.h"
#include "nsIURI.h"
#include "mozilla/net/ReferrerPolicy.h"
#include <algorithm>
namespace dom = mozilla::dom;
@ -27,7 +28,8 @@ static uint32_t gEntryID = 0;
nsSHEntry::nsSHEntry()
: mLoadType(0)
: mReferrerPolicy(mozilla::net::RP_Default)
, mLoadType(0)
, mID(gEntryID++)
, mScrollPositionX(0)
, mScrollPositionY(0)
@ -42,6 +44,7 @@ nsSHEntry::nsSHEntry(const nsSHEntry &other)
: mShared(other.mShared)
, mURI(other.mURI)
, mReferrerURI(other.mReferrerURI)
, mReferrerPolicy(other.mReferrerPolicy)
, mTitle(other.mTitle)
, mPostData(other.mPostData)
, mLoadType(0) // XXX why not copy?
@ -134,6 +137,18 @@ NS_IMETHODIMP nsSHEntry::SetReferrerURI(nsIURI *aReferrerURI)
return NS_OK;
}
NS_IMETHODIMP nsSHEntry::GetReferrerPolicy(uint32_t *aReferrerPolicy)
{
*aReferrerPolicy = mReferrerPolicy;
return NS_OK;
}
NS_IMETHODIMP nsSHEntry::SetReferrerPolicy(uint32_t aReferrerPolicy)
{
mReferrerPolicy = aReferrerPolicy;
return NS_OK;
}
NS_IMETHODIMP
nsSHEntry::SetContentViewer(nsIContentViewer *aViewer)
{

View File

@ -50,6 +50,7 @@ private:
// See nsSHEntry.idl for comments on these members.
nsCOMPtr<nsIURI> mURI;
nsCOMPtr<nsIURI> mReferrerURI;
uint32_t mReferrerPolicy;
nsString mTitle;
nsCOMPtr<nsIInputStream> mPostData;
uint32_t mLoadType;

View File

@ -1539,6 +1539,8 @@ static already_AddRefed<mozilla::dom::NodeInfo> nullNodeInfo;
// ==================================================================
nsIDocument::nsIDocument()
: nsINode(nullNodeInfo),
mReferrerPolicySet(false),
mReferrerPolicy(mozilla::net::RP_Default),
mCharacterSet(NS_LITERAL_CSTRING("ISO-8859-1")),
mNodeInfoManager(nullptr),
mCompatMode(eCompatibility_FullStandards),
@ -3701,6 +3703,20 @@ nsDocument::SetHeaderData(nsIAtom* aHeaderField, const nsAString& aData)
aHeaderField == nsGkAtoms::viewport_user_scalable) {
mViewportType = Unknown;
}
// Referrer policy spec says to ignore any empty referrer policies.
if (aHeaderField == nsGkAtoms::referrer && !aData.IsEmpty()) {
ReferrerPolicy policy = mozilla::net::ReferrerPolicyFromString(aData);
// Referrer policy spec (section 6.1) says that once the referrer policy
// is set, any future attempts to change it result in No-Referrer.
if (!mReferrerPolicySet) {
mReferrerPolicy = policy;
mReferrerPolicySet = true;
} else if (mReferrerPolicy != policy) {
mReferrerPolicy = mozilla::net::RP_No_Referrer;
}
}
}
void

View File

@ -120,6 +120,7 @@ class nsIdentifierMapEntry : public nsStringHashKey
{
public:
typedef mozilla::dom::Element Element;
typedef mozilla::net::ReferrerPolicy ReferrerPolicy;
explicit nsIdentifierMapEntry(const nsAString& aKey) :
nsStringHashKey(&aKey), mNameContentList(nullptr)

View File

@ -432,6 +432,8 @@ nsFrameLoader::ReallyStartLoadingInternal()
}
}
loadInfo->SetReferrerPolicy(mOwnerContent->OwnerDoc()->GetReferrerPolicy());
// Default flags:
int32_t flags = nsIWebNavigation::LOAD_FLAGS_NONE;

View File

@ -582,6 +582,7 @@ GK_ATOM(menupopup, "menupopup")
GK_ATOM(menuseparator, "menuseparator")
GK_ATOM(message, "message")
GK_ATOM(meta, "meta")
GK_ATOM(referrer, "referrer")
GK_ATOM(meter, "meter")
GK_ATOM(method, "method")
GK_ATOM(microdataProperties, "microdataProperties")

View File

@ -19,6 +19,7 @@
#include "nsPIDOMWindow.h" // for use in inline functions
#include "nsPropertyTable.h" // for member
#include "nsTHashtable.h" // for member
#include "mozilla/net/ReferrerPolicy.h" // for member
#include "nsWeakReference.h"
#include "mozilla/dom/DocumentBinding.h"
#include "mozilla/WeakPtr.h"
@ -169,6 +170,7 @@ class nsIDocument : public nsINode
{
typedef mozilla::dom::GlobalObject GlobalObject;
public:
typedef mozilla::net::ReferrerPolicy ReferrerPolicy;
typedef mozilla::dom::Element Element;
NS_DECLARE_STATIC_IID_ACCESSOR(NS_IDOCUMENT_IID)
@ -271,6 +273,15 @@ public:
*/
virtual void SetChromeXHRDocBaseURI(nsIURI* aURI) = 0;
/**
* Return the referrer policy of the document. Return "default" if there's no
* valid meta referrer tag found in the document.
*/
ReferrerPolicy GetReferrerPolicy() const
{
return mReferrerPolicy;
}
/**
* Set the principal responsible for this document.
*/
@ -2468,6 +2479,9 @@ protected:
nsWeakPtr mDocumentLoadGroup;
bool mReferrerPolicySet;
ReferrerPolicy mReferrerPolicy;
mozilla::WeakPtr<nsDocShell> mDocumentContainer;
nsCString mCharacterSet;

View File

@ -77,7 +77,21 @@ HTMLMetaElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
nsAutoString content;
rv = GetContent(content);
NS_ENSURE_SUCCESS(rv, rv);
nsContentUtils::ProcessViewportInfo(aDocument, content);
nsContentUtils::ProcessViewportInfo(aDocument, content);
}
if (aDocument &&
AttrValueIs(kNameSpaceID_None, nsGkAtoms::name, nsGkAtoms::referrer, eIgnoreCase)) {
nsAutoString content;
rv = GetContent(content);
NS_ENSURE_SUCCESS(rv, rv);
// Referrer Policy spec requires a <meta name="referrer" tag to be in the
// <head> element.
Element* headElt = aDocument->GetHeadElement();
if (headElt && nsContentUtils::ContentIsDescendantOf(this, headElt)) {
content = nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespace>(content);
aDocument->SetHeaderData(nsGkAtoms::referrer, content);
}
}
CreateAndDispatchEvent(aDocument, NS_LITERAL_STRING("DOMMetaAdded"));
return rv;

View File

@ -0,0 +1,61 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef ReferrerPolicy_h__
#define ReferrerPolicy_h__
#include "nsStringGlue.h"
#include "nsIHttpChannel.h"
namespace mozilla { namespace net {
enum ReferrerPolicy {
/* spec tokens: never no-referrer */
RP_No_Referrer = nsIHttpChannel::REFERRER_POLICY_NO_REFERRER,
/* spec tokens: origin */
RP_Origin = nsIHttpChannel::REFERRER_POLICY_ORIGIN,
/* spec tokens: default no-referrer-when-downgrade */
RP_No_Referrer_When_Downgrade = nsIHttpChannel::REFERRER_POLICY_NO_REFERRER_WHEN_DOWNGRADE,
RP_Default = nsIHttpChannel::REFERRER_POLICY_NO_REFERRER_WHEN_DOWNGRADE,
/* spec tokens: origin-when-crossorigin */
RP_Origin_When_Crossorigin = nsIHttpChannel::REFERRER_POLICY_ORIGIN_WHEN_XORIGIN,
/* spec tokens: always unsafe-url */
RP_Unsafe_URL = nsIHttpChannel::REFERRER_POLICY_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")) {
return RP_No_Referrer;
}
if (content.LowerCaseEqualsLiteral("origin")) {
return RP_Origin;
}
if (content.LowerCaseEqualsLiteral("default") ||
content.LowerCaseEqualsLiteral("no-referrer-when-downgrade")) {
return RP_No_Referrer_When_Downgrade;
}
if (content.LowerCaseEqualsLiteral("origin-when-crossorigin")) {
return RP_Origin_When_Crossorigin;
}
if (content.LowerCaseEqualsLiteral("always") ||
content.LowerCaseEqualsLiteral("unsafe-url")) {
return RP_Unsafe_URL;
}
// Spec says if none of the previous match, use No_Referrer.
return RP_No_Referrer;
}
} } //namespace mozilla::net
#endif

View File

@ -144,6 +144,10 @@ EXPORTS += [
'nsURIHashKey.h',
]
EXPORTS.mozilla.net += [
'ReferrerPolicy.h',
]
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
EXPORTS += [
'NetStatistics.h',

View File

@ -76,6 +76,7 @@ HttpBaseChannel::HttpBaseChannel()
, mProxyResolveFlags(0)
, mContentDispositionHint(UINT32_MAX)
, mHttpHandler(gHttpHandler)
, mReferrerPolicy(REFERRER_POLICY_NO_REFERRER_WHEN_DOWNGRADE)
, mRedirectCount(0)
, mForcePending(false)
{
@ -898,15 +899,38 @@ HttpBaseChannel::GetReferrer(nsIURI **referrer)
NS_IMETHODIMP
HttpBaseChannel::SetReferrer(nsIURI *referrer)
{
return SetReferrerWithPolicy(referrer, REFERRER_POLICY_NO_REFERRER_WHEN_DOWNGRADE);
}
NS_IMETHODIMP
HttpBaseChannel::GetReferrerPolicy(uint32_t *referrerPolicy)
{
NS_ENSURE_ARG_POINTER(referrerPolicy);
*referrerPolicy = mReferrerPolicy;
return NS_OK;
}
NS_IMETHODIMP
HttpBaseChannel::SetReferrerWithPolicy(nsIURI *referrer,
uint32_t referrerPolicy)
{
ENSURE_CALLED_BEFORE_CONNECT();
// clear existing referrer, if any
mReferrer = nullptr;
mRequestHead.ClearHeader(nsHttp::Referer);
mReferrerPolicy = REFERRER_POLICY_NO_REFERRER_WHEN_DOWNGRADE;
if (!referrer)
return NS_OK;
if (!referrer) {
return NS_OK;
}
// Don't send referrer at all when the meta referrer setting is "no-referrer"
if (referrerPolicy == REFERRER_POLICY_NO_REFERRER) {
mReferrerPolicy = REFERRER_POLICY_NO_REFERRER;
return NS_OK;
}
// 0: never send referer
// 1: send referer for direct user action
@ -929,12 +953,14 @@ HttpBaseChannel::SetReferrer(nsIURI *referrer)
// check referrer blocking pref
uint32_t referrerLevel;
if (mLoadFlags & LOAD_INITIAL_DOCUMENT_URI)
if (mLoadFlags & LOAD_INITIAL_DOCUMENT_URI) {
referrerLevel = 1; // user action
else
} else {
referrerLevel = 2; // inline content
if (userReferrerLevel < referrerLevel)
}
if (userReferrerLevel < referrerLevel) {
return NS_OK;
}
nsCOMPtr<nsIURI> referrerGrip;
nsresult rv;
@ -992,8 +1018,7 @@ HttpBaseChannel::SetReferrer(nsIURI *referrer)
rv = referrer->SchemeIs(*scheme, &match);
if (NS_FAILED(rv)) return rv;
}
if (!match)
return NS_OK; // kick out....
if (!match) return NS_OK; // kick out....
//
// Handle secure referrals.
@ -1003,28 +1028,52 @@ HttpBaseChannel::SetReferrer(nsIURI *referrer)
//
rv = referrer->SchemeIs("https", &match);
if (NS_FAILED(rv)) return rv;
if (match) {
rv = mURI->SchemeIs("https", &match);
if (NS_FAILED(rv)) return rv;
if (!match)
return NS_OK;
if (!gHttpHandler->SendSecureXSiteReferrer()) {
nsAutoCString referrerHost;
nsAutoCString host;
// It's ok to send referrer for https-to-http scenarios if the referrer
// policy is "unsafe-url" or "origin".
if (referrerPolicy != REFERRER_POLICY_UNSAFE_URL &&
referrerPolicy != REFERRER_POLICY_ORIGIN) {
rv = referrer->GetAsciiHost(referrerHost);
if (NS_FAILED(rv)) return rv;
// in other referrer policies, https->http is not allowed...
if (!match) return NS_OK;
rv = mURI->GetAsciiHost(host);
if (NS_FAILED(rv)) return rv;
// ...and https->https is possibly only allowed if the hosts match.
if (!gHttpHandler->SendSecureXSiteReferrer()) {
nsAutoCString referrerHost;
nsAutoCString host;
// GetAsciiHost returns lowercase hostname.
if (!referrerHost.Equals(host))
return NS_OK;
rv = referrer->GetAsciiHost(referrerHost);
if (NS_FAILED(rv)) return rv;
rv = mURI->GetAsciiHost(host);
if (NS_FAILED(rv)) return rv;
// GetAsciiHost returns lowercase hostname.
if (!referrerHost.Equals(host))
return NS_OK;
}
}
}
// for cross-origin-based referrer changes (not just host-based), figure out
// if the referrer is being sent cross-origin.
nsCOMPtr<nsIURI> loadingURI;
bool isCrossOrigin = true;
if (mLoadInfo) {
mLoadInfo->LoadingPrincipal()->GetURI(getter_AddRefs(loadingURI));
}
if (loadingURI) {
nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
rv = ssm->CheckSameOriginURI(loadingURI, mURI, false);
isCrossOrigin = NS_FAILED(rv);
} else {
NS_WARNING("no loading principal available via loadInfo, assumming load is cross-origin");
}
nsCOMPtr<nsIURI> clone;
//
// we need to clone the referrer, so we can:
@ -1032,6 +1081,7 @@ HttpBaseChannel::SetReferrer(nsIURI *referrer)
// (2) keep a reference to it after returning from this function
//
// Use CloneIgnoringRef to strip away any fragment per RFC 2616 section 14.36
// and Referrer Policy section 6.3.5.
rv = referrer->CloneIgnoringRef(getter_AddRefs(clone));
if (NS_FAILED(rv)) return rv;
@ -1077,11 +1127,22 @@ HttpBaseChannel::SetReferrer(nsIURI *referrer)
}
// strip away any userpass; we don't want to be giving out passwords ;-)
// This is required by Referrer Policy stripping algorithm.
rv = clone->SetUserPass(EmptyCString());
if (NS_FAILED(rv)) return rv;
nsAutoCString spec;
// site-specified referrer trimming may affect the trim level
// "unsafe-url" behaves like "origin" (send referrer in the same situations) but
// "unsafe-url" sends the whole referrer and origin removes the path.
// "origin-when-cross-origin" trims the referrer only when the request is
// cross-origin.
if (referrerPolicy == REFERRER_POLICY_ORIGIN ||
(isCrossOrigin && referrerPolicy == REFERRER_POLICY_ORIGIN_WHEN_XORIGIN)) {
userReferrerTrimmingPolicy = 2;
}
// check how much referer to send
switch (userReferrerTrimmingPolicy) {
@ -1117,8 +1178,11 @@ HttpBaseChannel::SetReferrer(nsIURI *referrer)
}
// finally, remember the referrer URI and set the Referer header.
rv = SetRequestHeader(NS_LITERAL_CSTRING("Referer"), spec, false);
if (NS_FAILED(rv)) return rv;
mReferrer = clone;
mRequestHead.SetHeader(nsHttp::Referer, spec);
mReferrerPolicy = referrerPolicy;
return NS_OK;
}
@ -2071,7 +2135,7 @@ HttpBaseChannel::SetupReplacementChannel(nsIURI *newURI,
}
// convey the referrer if one was used for this channel to the next one
if (mReferrer)
httpChannel->SetReferrer(mReferrer);
httpChannel->SetReferrerWithPolicy(mReferrer, mReferrerPolicy);
// convey the mAllowPipelining and mAllowSTS flags
httpChannel->SetAllowPipelining(mAllowPipelining);
httpChannel->SetAllowSTS(mAllowSTS);

View File

@ -133,6 +133,8 @@ public:
NS_IMETHOD SetRequestMethod(const nsACString& aMethod);
NS_IMETHOD GetReferrer(nsIURI **referrer);
NS_IMETHOD SetReferrer(nsIURI *referrer);
NS_IMETHOD GetReferrerPolicy(uint32_t *referrerPolicy);
NS_IMETHOD SetReferrerWithPolicy(nsIURI *referrer, uint32_t referrerPolicy);
NS_IMETHOD GetRequestHeader(const nsACString& aHeader, nsACString& aValue);
NS_IMETHOD SetRequestHeader(const nsACString& aHeader,
const nsACString& aValue, bool aMerge);
@ -383,6 +385,8 @@ protected:
nsRefPtr<nsHttpHandler> mHttpHandler; // keep gHttpHandler alive
uint32_t mReferrerPolicy;
// Performance tracking
// The initiator type (for this resource) - how was the resource referenced in
// the HTML file.

View File

@ -274,6 +274,7 @@ HttpChannelParent::DoAsyncOpen( const URIParams& aURI,
mChannel->SetDocumentURI(docUri);
if (referrerUri)
mChannel->SetReferrerInternal(referrerUri);
//TODO set referrer policy too (in patch 5)
if (apiRedirectToUri)
mChannel->RedirectTo(apiRedirectToUri);
if (topWindowUri)

View File

@ -14,7 +14,7 @@ interface nsIHttpHeaderVisitor;
* the inspection of the resulting HTTP response status and headers when they
* become available.
*/
[scriptable, uuid(1bc753ad-5b88-454d-b4c0-4fd34cce6d96)]
[scriptable, uuid(82083578-fb78-4f9a-953c-cecbae500697)]
interface nsIHttpChannel : nsIChannel
{
/**************************************************************************
@ -55,6 +55,33 @@ interface nsIHttpChannel : nsIChannel
*/
attribute nsIURI referrer;
/**
* Referrer policies. See ReferrerPolicy.h for more details.
*/
/* default state, doesn't send referrer from https->http */
const unsigned long REFERRER_POLICY_NO_REFERRER_WHEN_DOWNGRADE = 0;
/* sends no referrer */
const unsigned long REFERRER_POLICY_NO_REFERRER = 1;
/* only sends the origin of the referring URL */
const unsigned long REFERRER_POLICY_ORIGIN = 2;
/* same as default, but reduced to ORIGIN when cross-origin. */
const unsigned long REFERRER_POLICY_ORIGIN_WHEN_XORIGIN = 3;
/* always sends the referrer, even on downgrade. */
const unsigned long REFERRER_POLICY_UNSAFE_URL = 4;
/**
* Get the HTTP referrer policy. The policy is retrieved from the meta
* referrer tag, which can be one of many values (see ReferrerPolicy.h for
* more details).
*/
readonly attribute unsigned long referrerPolicy;
/**
* Set the HTTP referrer URI with a referrer policy.
*/
void setReferrerWithPolicy(in nsIURI referrer, in unsigned long referrerPolicy);
/**
* Get the value of a particular request header.
*

View File

@ -607,6 +607,21 @@ nsViewSourceChannel::SetReferrer(nsIURI * aReferrer)
mHttpChannel->SetReferrer(aReferrer);
}
NS_IMETHODIMP
nsViewSourceChannel::GetReferrerPolicy(uint32_t *aReferrerPolicy)
{
return !mHttpChannel ? NS_ERROR_NULL_POINTER :
mHttpChannel->GetReferrerPolicy(aReferrerPolicy);
}
NS_IMETHODIMP
nsViewSourceChannel::SetReferrerWithPolicy(nsIURI * aReferrer,
uint32_t aReferrerPolicy)
{
return !mHttpChannel ? NS_ERROR_NULL_POINTER :
mHttpChannel->SetReferrerWithPolicy(aReferrer, aReferrerPolicy);
}
NS_IMETHODIMP
nsViewSourceChannel::GetRequestHeader(const nsACString & aHeader,
nsACString & aValue)

View File

@ -27,6 +27,9 @@ nsHtml5SpeculativeLoad::Perform(nsHtml5TreeOpExecutor* aExecutor)
case eSpeculativeLoadBase:
aExecutor->SetSpeculationBase(mUrl);
break;
case eSpeculativeLoadMetaReferrer:
aExecutor->SetSpeculationReferrerPolicy(mMetaReferrerPolicy);
break;
case eSpeculativeLoadImage:
aExecutor->PreloadImage(mUrl, mCrossOrigin);
break;

View File

@ -6,6 +6,7 @@
#define nsHtml5SpeculativeLoad_h
#include "nsString.h"
#include "nsContentUtils.h"
class nsHtml5TreeOpExecutor;
@ -14,6 +15,7 @@ enum eHtml5SpeculativeLoad {
eSpeculativeLoadUninitialized,
#endif
eSpeculativeLoadBase,
eSpeculativeLoadMetaReferrer,
eSpeculativeLoadImage,
eSpeculativeLoadScript,
eSpeculativeLoadScriptFromHead,
@ -35,6 +37,14 @@ class nsHtml5SpeculativeLoad {
mUrl.Assign(aUrl);
}
inline void InitMetaReferrerPolicy(const nsAString& aReferrerPolicy) {
NS_PRECONDITION(mOpCode == eSpeculativeLoadUninitialized,
"Trying to reinitialize a speculative load!");
mOpCode = eSpeculativeLoadMetaReferrer;
mMetaReferrerPolicy.Assign(
nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespace>(aReferrerPolicy));
}
inline void InitImage(const nsAString& aUrl,
const nsAString& aCrossOrigin)
{
@ -116,6 +126,7 @@ class nsHtml5SpeculativeLoad {
private:
eHtml5SpeculativeLoad mOpCode;
nsString mUrl;
nsString mMetaReferrerPolicy;
/**
* If mOpCode is eSpeculativeLoadStyle or eSpeculativeLoadScript[FromHead]
* then this is the value of the "charset" attribute. For

View File

@ -189,6 +189,15 @@ nsHtml5TreeBuilder::createElement(int32_t aNamespace, nsIAtom* aName,
if (url) {
mSpeculativeLoadQueue.AppendElement()->InitBase(*url);
}
} else if (nsHtml5Atoms::meta == aName) {
if (nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString(
"referrer",
aAttributes->getValue(nsHtml5AttributeName::ATTR_NAME))) {
nsString* referrerPolicy = aAttributes->getValue(nsHtml5AttributeName::ATTR_CONTENT);
if (referrerPolicy) {
mSpeculativeLoadQueue.AppendElement()->InitMetaReferrerPolicy(*referrerPolicy);
}
}
}
break;
case kNameSpaceID_SVG:

View File

@ -63,6 +63,8 @@ static nsITimer* gFlushTimer = nullptr;
nsHtml5TreeOpExecutor::nsHtml5TreeOpExecutor()
: nsHtml5DocumentBuilder(false)
, mPreloadedURLs(23) // Mean # of preloadable resources per page on dmoz
, mSpeculationReferrerPolicyWasSet(false)
, mSpeculationReferrerPolicy(mozilla::net::RP_Default)
{
// zeroing operator new for everything else
}
@ -952,6 +954,27 @@ nsHtml5TreeOpExecutor::SetSpeculationBase(const nsAString& aURL)
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Failed to create a URI");
}
void
nsHtml5TreeOpExecutor::SetSpeculationReferrerPolicy(const nsAString& aReferrerPolicy)
{
ReferrerPolicy policy = mozilla::net::ReferrerPolicyFromString(aReferrerPolicy);
if (mSpeculationReferrerPolicyWasSet &&
policy != mSpeculationReferrerPolicy) {
// According to the Referrer Policy spec, if there's already been a policy
// set and another attempt is made to set a _different_ policy, the result
// is a "No Referrer" policy.
mSpeculationReferrerPolicy = mozilla::net::RP_No_Referrer;
}
else {
// Record "speculated" referrer policy locally and thread through the
// speculation phase. The actual referrer policy will be set by
// HTMLMetaElement::BindToTree().
mSpeculationReferrerPolicyWasSet = true;
mSpeculationReferrerPolicy = policy;
}
}
#ifdef DEBUG_NS_HTML5_TREE_OP_EXECUTOR_FLUSH
uint32_t nsHtml5TreeOpExecutor::sAppendBatchMaxSize = 0;
uint32_t nsHtml5TreeOpExecutor::sAppendBatchSlotsExamined = 0;

View File

@ -22,6 +22,7 @@
#include "nsHashKeys.h"
#include "mozilla/LinkedList.h"
#include "nsHtml5DocumentBuilder.h"
#include "mozilla/net/ReferrerPolicy.h"
class nsHtml5Parser;
class nsHtml5TreeBuilder;
@ -36,6 +37,7 @@ class nsHtml5TreeOpExecutor MOZ_FINAL : public nsHtml5DocumentBuilder,
public mozilla::LinkedListElement<nsHtml5TreeOpExecutor>
{
friend class nsHtml5FlushLoopGuard;
typedef mozilla::net::ReferrerPolicy ReferrerPolicy;
public:
NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW
@ -67,6 +69,12 @@ class nsHtml5TreeOpExecutor MOZ_FINAL : public nsHtml5DocumentBuilder,
nsCOMPtr<nsIURI> mSpeculationBaseURI;
/**
* Need to keep track of whether the referrer policy was already set.
*/
bool mSpeculationReferrerPolicyWasSet;
ReferrerPolicy mSpeculationReferrerPolicy;
nsCOMPtr<nsIURI> mViewSourceBaseURI;
/**
@ -257,6 +265,8 @@ class nsHtml5TreeOpExecutor MOZ_FINAL : public nsHtml5DocumentBuilder,
void PreloadImage(const nsAString& aURL, const nsAString& aCrossOrigin);
void SetSpeculationBase(const nsAString& aURL);
void SetSpeculationReferrerPolicy(const nsAString& aReferrerPolicy);
void AddBase(const nsAString& aURL);