diff --git a/browser/components/sessionstore/SessionHistory.jsm b/browser/components/sessionstore/SessionHistory.jsm index f8c929ee938f..4c895869135b 100644 --- a/browser/components/sessionstore/SessionHistory.jsm +++ b/browser/components/sessionstore/SessionHistory.jsm @@ -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) diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index 6728004debfa..1700702c2d37 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -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 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 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 mDocShell; nsCOMPtr mURI; nsCOMPtr mReferrer; + uint32_t mReferrerPolicy; nsCOMPtr mOwner; nsCOMPtr mPostData; nsCOMPtr 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 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 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 inputStream; nsCOMPtr referrerURI; + uint32_t referrerPolicy = mozilla::net::RP_Default; nsCOMPtr cacheKey; nsCOMPtr 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 inStrmChan = do_QueryInterface(aChannel); if (inStrmChan) { bool isSrcdocChannel; @@ -11707,6 +11741,7 @@ nsDocShell::LoadHistoryEntry(nsISHEntry * aEntry, uint32_t aLoadType) nsCOMPtr uri; nsCOMPtr postData; nsCOMPtr referrerURI; + uint32_t referrerPolicy; nsAutoCString contentType; nsCOMPtr 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 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; } diff --git a/docshell/base/nsDocShell.h b/docshell/base/nsDocShell.h index 8ce9b1fec820..df9ab86af394 100644 --- a/docshell/base/nsDocShell.h +++ b/docshell/base/nsDocShell.h @@ -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 mCurrentURI; nsCOMPtr mReferrerURI; + uint32_t mReferrerPolicy; nsRefPtr mScriptGlobal; nsCOMPtr mSessionHistory; nsCOMPtr mGlobalHistory; diff --git a/docshell/base/nsDocShellLoadInfo.cpp b/docshell/base/nsDocShellLoadInfo.cpp index 01dd301ebb22..2e02ea892c40 100644 --- a/docshell/base/nsDocShellLoadInfo.cpp +++ b/docshell/base/nsDocShellLoadInfo.cpp @@ -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; diff --git a/docshell/base/nsDocShellLoadInfo.h b/docshell/base/nsDocShellLoadInfo.h index 6a15235b7161..815ac6f00d2f 100644 --- a/docshell/base/nsDocShellLoadInfo.h +++ b/docshell/base/nsDocShellLoadInfo.h @@ -37,6 +37,7 @@ protected: bool mInheritOwner; bool mOwnerIsExplicit; bool mSendReferrer; + nsDocShellInfoReferrerPolicy mReferrerPolicy; nsDocShellInfoLoadType mLoadType; nsCOMPtr mSHEntry; nsString mTarget; diff --git a/docshell/base/nsIDocShell.idl b/docshell/base/nsIDocShell.idl index 23cd7096512e..c50c98378d8e 100644 --- a/docshell/base/nsIDocShell.idl +++ b/docshell/base/nsIDocShell.idl @@ -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, diff --git a/docshell/base/nsIDocShellLoadInfo.idl b/docshell/base/nsIDocShellLoadInfo.idl index 1e1c679338c8..735b837efece 100644 --- a/docshell/base/nsIDocShellLoadInfo.idl +++ b/docshell/base/nsIDocShellLoadInfo.idl @@ -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. */ diff --git a/docshell/shistory/public/nsISHEntry.idl b/docshell/shistory/public/nsISHEntry.idl index 7597839949ed..e36c7b6cf361 100644 --- a/docshell/shistory/public/nsISHEntry.idl +++ b/docshell/shistory/public/nsISHEntry.idl @@ -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; diff --git a/docshell/shistory/src/nsSHEntry.cpp b/docshell/shistory/src/nsSHEntry.cpp index b3bedb1c666b..065d8898be21 100644 --- a/docshell/shistory/src/nsSHEntry.cpp +++ b/docshell/shistory/src/nsSHEntry.cpp @@ -15,6 +15,7 @@ #include "nsIStructuredCloneContainer.h" #include "nsIInputStream.h" #include "nsIURI.h" +#include "mozilla/net/ReferrerPolicy.h" #include 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) { diff --git a/docshell/shistory/src/nsSHEntry.h b/docshell/shistory/src/nsSHEntry.h index 2267bac177c9..5a681a5fa2cc 100644 --- a/docshell/shistory/src/nsSHEntry.h +++ b/docshell/shistory/src/nsSHEntry.h @@ -50,6 +50,7 @@ private: // See nsSHEntry.idl for comments on these members. nsCOMPtr mURI; nsCOMPtr mReferrerURI; + uint32_t mReferrerPolicy; nsString mTitle; nsCOMPtr mPostData; uint32_t mLoadType; diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp index f3fa76ea447f..c6bb97ce458c 100644 --- a/dom/base/nsDocument.cpp +++ b/dom/base/nsDocument.cpp @@ -1539,6 +1539,8 @@ static already_AddRefed 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 diff --git a/dom/base/nsDocument.h b/dom/base/nsDocument.h index 0029e3111b78..1c88d4497bd8 100644 --- a/dom/base/nsDocument.h +++ b/dom/base/nsDocument.h @@ -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) diff --git a/dom/base/nsFrameLoader.cpp b/dom/base/nsFrameLoader.cpp index 0e195b12c6c0..e5f142f8279d 100644 --- a/dom/base/nsFrameLoader.cpp +++ b/dom/base/nsFrameLoader.cpp @@ -432,6 +432,8 @@ nsFrameLoader::ReallyStartLoadingInternal() } } + loadInfo->SetReferrerPolicy(mOwnerContent->OwnerDoc()->GetReferrerPolicy()); + // Default flags: int32_t flags = nsIWebNavigation::LOAD_FLAGS_NONE; diff --git a/dom/base/nsGkAtomList.h b/dom/base/nsGkAtomList.h index b6e5c40dfdaf..6aad7284115b 100644 --- a/dom/base/nsGkAtomList.h +++ b/dom/base/nsGkAtomList.h @@ -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") diff --git a/dom/base/nsIDocument.h b/dom/base/nsIDocument.h index e6f5d2b5f693..05b703f038d3 100644 --- a/dom/base/nsIDocument.h +++ b/dom/base/nsIDocument.h @@ -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 mDocumentContainer; nsCString mCharacterSet; diff --git a/dom/html/HTMLMetaElement.cpp b/dom/html/HTMLMetaElement.cpp index f6017274f0c4..93f1c82459d1 100644 --- a/dom/html/HTMLMetaElement.cpp +++ b/dom/html/HTMLMetaElement.cpp @@ -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 element. + Element* headElt = aDocument->GetHeadElement(); + if (headElt && nsContentUtils::ContentIsDescendantOf(this, headElt)) { + content = nsContentUtils::TrimWhitespace(content); + aDocument->SetHeaderData(nsGkAtoms::referrer, content); + } } CreateAndDispatchEvent(aDocument, NS_LITERAL_STRING("DOMMetaAdded")); return rv; diff --git a/netwerk/base/public/ReferrerPolicy.h b/netwerk/base/public/ReferrerPolicy.h new file mode 100644 index 000000000000..e8c6a2f9c7d6 --- /dev/null +++ b/netwerk/base/public/ReferrerPolicy.h @@ -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 diff --git a/netwerk/base/public/moz.build b/netwerk/base/public/moz.build index 6f37f583b106..cbe42a47b622 100644 --- a/netwerk/base/public/moz.build +++ b/netwerk/base/public/moz.build @@ -144,6 +144,10 @@ EXPORTS += [ 'nsURIHashKey.h', ] +EXPORTS.mozilla.net += [ + 'ReferrerPolicy.h', +] + if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk': EXPORTS += [ 'NetStatistics.h', diff --git a/netwerk/protocol/http/HttpBaseChannel.cpp b/netwerk/protocol/http/HttpBaseChannel.cpp index b8dc4be7c50f..a0f28afc8e2b 100644 --- a/netwerk/protocol/http/HttpBaseChannel.cpp +++ b/netwerk/protocol/http/HttpBaseChannel.cpp @@ -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 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 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 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); diff --git a/netwerk/protocol/http/HttpBaseChannel.h b/netwerk/protocol/http/HttpBaseChannel.h index 6938e2a17997..c9f6b6e6eed6 100644 --- a/netwerk/protocol/http/HttpBaseChannel.h +++ b/netwerk/protocol/http/HttpBaseChannel.h @@ -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 mHttpHandler; // keep gHttpHandler alive + uint32_t mReferrerPolicy; + // Performance tracking // The initiator type (for this resource) - how was the resource referenced in // the HTML file. diff --git a/netwerk/protocol/http/HttpChannelParent.cpp b/netwerk/protocol/http/HttpChannelParent.cpp index d0ae23c391a0..4eb2a39808da 100644 --- a/netwerk/protocol/http/HttpChannelParent.cpp +++ b/netwerk/protocol/http/HttpChannelParent.cpp @@ -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) diff --git a/netwerk/protocol/http/nsIHttpChannel.idl b/netwerk/protocol/http/nsIHttpChannel.idl index f6fa57f3cba8..03d39e85fec3 100644 --- a/netwerk/protocol/http/nsIHttpChannel.idl +++ b/netwerk/protocol/http/nsIHttpChannel.idl @@ -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. * diff --git a/netwerk/protocol/viewsource/nsViewSourceChannel.cpp b/netwerk/protocol/viewsource/nsViewSourceChannel.cpp index f57ca8d440d5..0d933118ace0 100644 --- a/netwerk/protocol/viewsource/nsViewSourceChannel.cpp +++ b/netwerk/protocol/viewsource/nsViewSourceChannel.cpp @@ -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) diff --git a/parser/html/nsHtml5SpeculativeLoad.cpp b/parser/html/nsHtml5SpeculativeLoad.cpp index 7ac26963be06..4ee9fd90df54 100644 --- a/parser/html/nsHtml5SpeculativeLoad.cpp +++ b/parser/html/nsHtml5SpeculativeLoad.cpp @@ -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; diff --git a/parser/html/nsHtml5SpeculativeLoad.h b/parser/html/nsHtml5SpeculativeLoad.h index a370543c8c2c..2f985425a5ac 100644 --- a/parser/html/nsHtml5SpeculativeLoad.h +++ b/parser/html/nsHtml5SpeculativeLoad.h @@ -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(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 diff --git a/parser/html/nsHtml5TreeBuilderCppSupplement.h b/parser/html/nsHtml5TreeBuilderCppSupplement.h index 6110bc0d731c..f0cf1110ec80 100644 --- a/parser/html/nsHtml5TreeBuilderCppSupplement.h +++ b/parser/html/nsHtml5TreeBuilderCppSupplement.h @@ -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: diff --git a/parser/html/nsHtml5TreeOpExecutor.cpp b/parser/html/nsHtml5TreeOpExecutor.cpp index 007b69042163..8fb074cab4ba 100644 --- a/parser/html/nsHtml5TreeOpExecutor.cpp +++ b/parser/html/nsHtml5TreeOpExecutor.cpp @@ -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; diff --git a/parser/html/nsHtml5TreeOpExecutor.h b/parser/html/nsHtml5TreeOpExecutor.h index eecba61469d1..8098a87b6816 100644 --- a/parser/html/nsHtml5TreeOpExecutor.h +++ b/parser/html/nsHtml5TreeOpExecutor.h @@ -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 { 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 mSpeculationBaseURI; + /** + * Need to keep track of whether the referrer policy was already set. + */ + bool mSpeculationReferrerPolicyWasSet; + ReferrerPolicy mSpeculationReferrerPolicy; + nsCOMPtr 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);