Bug 704320 - Parse and implement meta tag-based referrer policies for documents and nsHttpChannels. (r=bz,mcmanus)
authorOwen Chu <owenchu@gmail.com>
Tue, 18 Nov 2014 08:46:29 -0500
changeset 242703 4c2d59fd05fb757fa64d113c6ddc497d091e810d
parent 242702 bf73bf22dfba714bc4de5e9a5e5095f07ef21bd3
child 242704 a35d5482084117afe7005794de8627327683627b
push id660
push userraliiev@mozilla.com
push dateWed, 18 Feb 2015 20:30:48 +0000
treeherdermozilla-release@49e493494178 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz, mcmanus
bugs704320
milestone36.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 704320 - Parse and implement meta tag-based referrer policies for documents and nsHttpChannels. (r=bz,mcmanus)
browser/components/sessionstore/SessionHistory.jsm
docshell/base/nsDocShell.cpp
docshell/base/nsDocShell.h
docshell/base/nsDocShellLoadInfo.cpp
docshell/base/nsDocShellLoadInfo.h
docshell/base/nsIDocShell.idl
docshell/base/nsIDocShellLoadInfo.idl
docshell/shistory/public/nsISHEntry.idl
docshell/shistory/src/nsSHEntry.cpp
docshell/shistory/src/nsSHEntry.h
dom/base/nsDocument.cpp
dom/base/nsDocument.h
dom/base/nsFrameLoader.cpp
dom/base/nsGkAtomList.h
dom/base/nsIDocument.h
dom/html/HTMLMetaElement.cpp
netwerk/base/public/ReferrerPolicy.h
netwerk/base/public/moz.build
netwerk/protocol/http/HttpBaseChannel.cpp
netwerk/protocol/http/HttpBaseChannel.h
netwerk/protocol/http/HttpChannelParent.cpp
netwerk/protocol/http/nsIHttpChannel.idl
netwerk/protocol/viewsource/nsViewSourceChannel.cpp
parser/html/nsHtml5SpeculativeLoad.cpp
parser/html/nsHtml5SpeculativeLoad.h
parser/html/nsHtml5TreeBuilderCppSupplement.h
parser/html/nsHtml5TreeOpExecutor.cpp
parser/html/nsHtml5TreeOpExecutor.h
--- a/browser/components/sessionstore/SessionHistory.jsm
+++ b/browser/components/sessionstore/SessionHistory.jsm
@@ -182,18 +182,20 @@ let SessionHistoryInternal = {
       // nsISerializable or something.
       entry.cacheKey = cacheKey.data;
     }
     entry.ID = shEntry.ID;
     entry.docshellID = shEntry.docshellID;
 
     // 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;
 
     if (shEntry.isSrcdocEntry)
       entry.isSrcdocEntry = shEntry.isSrcdocEntry;
 
     if (shEntry.baseURI)
@@ -335,18 +337,20 @@ let SessionHistoryInternal = {
 
     shEntry.setURI(Utils.makeURI(entry.url));
     shEntry.setTitle(entry.title || entry.url);
     if (entry.subframe)
       shEntry.setIsSubFrame(entry.subframe || false);
     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)
       shEntry.baseURI = Utils.makeURI(entry.baseURI);
 
     if (entry.cacheKey) {
       var cacheKey = Cc["@mozilla.org/supports-PRUint32;1"].
                      createInstance(Ci.nsISupportsPRUint32);
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -33,16 +33,17 @@
 #include "nsIDOMElement.h"
 #include "nsIDOMStorage.h"
 #include "nsIContentViewer.h"
 #include "nsIDocumentLoaderFactory.h"
 #include "nsCURILoader.h"
 #include "nsDocShellCID.h"
 #include "nsDOMCID.h"
 #include "nsNetUtil.h"
+#include "mozilla/net/ReferrerPolicy.h"
 #include "nsRect.h"
 #include "prenv.h"
 #include "nsIDOMWindow.h"
 #include "nsIGlobalObject.h"
 #include "nsIWebBrowserChrome.h"
 #include "nsPoint.h"
 #include "nsIObserverService.h"
 #include "nsIPrompt.h"
@@ -549,16 +550,17 @@ nsPingListener::AsyncOnChannelRedirect(n
 }
 
 struct SendPingInfo {
   int32_t numPings;
   int32_t maxPings;
   bool    requireSameHost;
   nsIURI *target;
   nsIURI *referrer;
+  uint32_t referrerPolicy;
 };
 
 static void
 SendPing(void *closure, nsIContent *content, nsIURI *uri, nsIIOService *ios)
 {
   SendPingInfo *info = static_cast<SendPingInfo *>(closure);
   if (info->maxPings > -1 && info->numPings >= info->maxPings)
     return;
@@ -628,17 +630,17 @@ SendPing(void *closure, nsIContent *cont
       if (NS_SUCCEEDED(info->referrer->GetSpec(pingFrom)))
         httpChan->SetRequestHeader(NS_LITERAL_CSTRING("Ping-From"), pingFrom, false);
     }
 
     // If the document containing the hyperlink being audited was not retrieved
     // 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);
   if (!uploadChan)
     return;
 
   NS_NAMED_LITERAL_CSTRING(uploadData, "PING");
 
@@ -686,28 +688,32 @@ SendPing(void *closure, nsIContent *cont
     // If we failed to setup the timer, then we should just cancel the channel
     // because we won't be able to ensure that it goes away in a timely manner.
     chan->Cancel(NS_ERROR_ABORT);
   }
 }
 
 // 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;
 
   if (!PingsEnabled(&info.maxPings, &info.requireSameHost))
     return;
   if (info.maxPings == 0)
     return;
 
   info.numPings = 0;
   info.target = target;
   info.referrer = referrer;
+  info.referrerPolicy = referrerPolicy;
 
   ForEachPing(content, SendPing, &info);
 }
 
 static nsDOMPerformanceNavigationType
 ConvertLoadTypeToNavigationType(uint32_t aLoadType)
 {
   // Not initialized, assume it's normal load.
@@ -1341,16 +1347,17 @@ nsDocShell::LoadURI(nsIURI * aURI,
     }
     nsCOMPtr<nsIURI> referrer;
     nsCOMPtr<nsIInputStream> postStream;
     nsCOMPtr<nsIInputStream> headersStream;
     nsCOMPtr<nsISupports> owner;
     bool inheritOwner = false;
     bool ownerIsExplicit = false;
     bool sendReferrer = true;
+    uint32_t referrerPolicy = mozilla::net::RP_Default;
     bool isSrcdoc = false;
     nsCOMPtr<nsISHEntry> shEntry;
     nsXPIDLString target;
     nsAutoString srcdoc;
     nsCOMPtr<nsIDocShell> sourceDocShell;
     nsCOMPtr<nsIURI> baseURI;
 
     uint32_t loadType = MAKE_LOAD_TYPE(LOAD_NORMAL, aLoadFlags);    
@@ -1374,16 +1381,17 @@ nsDocShell::LoadURI(nsIURI * aURI,
         aLoadInfo->GetOwner(getter_AddRefs(owner));
         aLoadInfo->GetInheritOwner(&inheritOwner);
         aLoadInfo->GetOwnerIsExplicit(&ownerIsExplicit);
         aLoadInfo->GetSHEntry(getter_AddRefs(shEntry));
         aLoadInfo->GetTarget(getter_Copies(target));
         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));
         aLoadInfo->GetBaseURI(getter_AddRefs(baseURI));
     }
 
 #if defined(PR_LOGGING) && defined(DEBUG)
     if (PR_LOG_TEST(gDocShellLog, PR_LOG_DEBUG)) {
@@ -1597,16 +1605,17 @@ nsDocShell::LoadURI(nsIURI * aURI,
     if (aLoadFlags & LOAD_FLAGS_FORCE_ALLOW_COOKIES)
         flags |= INTERNAL_LOAD_FLAGS_FORCE_ALLOW_COOKIES;
 
     if (isSrcdoc)
         flags |= INTERNAL_LOAD_FLAGS_IS_SRCDOC;
 
     return InternalLoad(aURI,
                         referrer,
+                        referrerPolicy,
                         owner,
                         flags,
                         target.get(),
                         nullptr,         // No type hint
                         NullString(),    // No forced download
                         postStream,
                         headersStream,
                         loadType,
@@ -5260,18 +5269,18 @@ nsDocShell::LoadErrorPage(nsIURI *aURI, 
     // end of the URL, so append it last.
     errorPageUrl.AppendLiteral("&d=");
     errorPageUrl.AppendASCII(escapedDescription.get());
 
     nsCOMPtr<nsIURI> errorPageURI;
     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);
 }
 
 
 NS_IMETHODIMP
 nsDocShell::Reload(uint32_t aReloadFlags)
@@ -5323,16 +5332,17 @@ nsDocShell::Reload(uint32_t aReloadFlags
             if (doc->IsSrcdocDocument()) {
                 doc->GetSrcdocData(srcdoc);
                 flags |= INTERNAL_LOAD_FLAGS_IS_SRCDOC;
                 baseURI = doc->GetBaseURI();
             }
         }
         rv = InternalLoad(mCurrentURI,
                           mReferrerURI,
+                          mReferrerPolicy,
                           principal,
                           flags,
                           nullptr,         // No window target
                           NS_LossyConvertUTF16toASCII(contentTypeHint).get(),
                           NullString(),    // No forced download
                           nullptr,         // No post data
                           nullptr,         // No headers data
                           loadType,        // Load type
@@ -9225,27 +9235,29 @@ void CopyFavicon(nsIURI *aOldURI, nsIURI
 #endif
 }
 
 } // anonymous namespace
 
 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,
                       nsISHEntry * aSHEntry, bool aFirstParty,
                       const nsAString &aSrcdoc, nsIDocShell* aSourceDocShell,
                       nsIURI * aBaseURI) :
         mSrcdoc(aSrcdoc),
         mDocShell(aDocShell),
         mURI(aURI),
         mReferrer(aReferrer),
+        mReferrerPolicy(aReferrerPolicy),
         mOwner(aOwner),
         mPostData(aPostData),
         mHeadersData(aHeadersData),
         mSHEntry(aSHEntry),
         mFlags(aFlags),
         mLoadType(aLoadType),
         mFirstParty(aFirstParty),
         mSourceDocShell(aSourceDocShell),
@@ -9253,17 +9265,19 @@ public:
     {
         // Make sure to keep null things null as needed
         if (aTypeHint) {
             mTypeHint = aTypeHint;
         }
     }
 
     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,
                                        mSrcdoc, mSourceDocShell, mBaseURI,
                                        nullptr, nullptr);
     }
 
 private:
@@ -9271,16 +9285,17 @@ private:
     // Use IDL strings so .get() returns null by default
     nsXPIDLString mWindowTarget;
     nsXPIDLCString mTypeHint;
     nsString mSrcdoc;
 
     nsRefPtr<nsDocShell> mDocShell;
     nsCOMPtr<nsIURI> mURI;
     nsCOMPtr<nsIURI> mReferrer;
+    uint32_t mReferrerPolicy;
     nsCOMPtr<nsISupports> mOwner;
     nsCOMPtr<nsIInputStream> mPostData;
     nsCOMPtr<nsIInputStream> mHeadersData;
     nsCOMPtr<nsISHEntry> mSHEntry;
     uint32_t mFlags;
     uint32_t mLoadType;
     bool mFirstParty;
     nsCOMPtr<nsIDocShell> mSourceDocShell;
@@ -9325,16 +9340,17 @@ nsDocShell::CreatePrincipalFromReferrer(
                                        outPrincipal);
   NS_ENSURE_SUCCESS(rv, rv);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocShell::InternalLoad(nsIURI * aURI,
                          nsIURI * aReferrer,
+                         uint32_t aReferrerPolicy,
                          nsISupports * aOwner,
                          uint32_t aFlags,
                          const char16_t *aWindowTarget,
                          const char* aTypeHint,
                          const nsAString& aFileName,
                          nsIInputStream * aPostData,
                          nsIInputStream * aHeadersData,
                          uint32_t aLoadType,
@@ -9581,16 +9597,17 @@ nsDocShell::InternalLoad(nsIURI * aURI,
 
         //
         // Transfer the load to the target DocShell...  Pass nullptr as the
         // window target name from to prevent recursive retargeting!
         //
         if (NS_SUCCEEDED(rv) && targetDocShell) {
             rv = targetDocShell->InternalLoad(aURI,
                                               aReferrer,
+                                              aReferrerPolicy,
                                               owner,
                                               aFlags,
                                               nullptr,         // No window target
                                               aTypeHint,
                                               NullString(),    // No forced download
                                               aPostData,
                                               aHeadersData,
                                               aLoadType,
@@ -9661,17 +9678,18 @@ nsDocShell::InternalLoad(nsIURI * aURI,
             // the unload event also a replace load, so we don't
             // create extra history entries.
             if (LOAD_TYPE_HAS_FLAGS(aLoadType, LOAD_FLAGS_REPLACE_HISTORY)) {
                 mLoadType = LOAD_NORMAL_REPLACE;
             }
             
             // 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);
             return NS_DispatchToCurrentThread(ev);
         }
 
         // Just ignore this load attempt
         return NS_OK;
@@ -10113,16 +10131,17 @@ nsDocShell::InternalLoad(nsIURI * aURI,
 
     mozilla::net::PredictorPredict(aURI, nullptr,
                                    nsINetworkPredictor::PREDICT_LOAD,
                                    this, nullptr);
 
     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,
                    (aFlags & INTERNAL_LOAD_FLAGS_BYPASS_CLASSIFIER) != 0,
                    (aFlags & INTERNAL_LOAD_FLAGS_FORCE_ALLOW_COOKIES) != 0,
                    srcdoc, aBaseURI, contentType);
     if (req && aRequest)
         NS_ADDREF(*aRequest = req);
@@ -10186,16 +10205,17 @@ nsDocShell::GetInheritedPrincipal(bool a
 
     return nullptr;
 }
 
 nsresult
 nsDocShell::DoURILoad(nsIURI * aURI,
                       nsIURI * aReferrerURI,
                       bool aSendReferrer,
+                      uint32_t aReferrerPolicy,
                       nsISupports * aOwner,
                       const char * aTypeHint,
                       const nsAString & aFileName,
                       nsIInputStream * aPostData,
                       nsIInputStream * aHeadersData,
                       bool aFirstParty,
                       nsIDocShell ** aDocShell,
                       nsIRequest ** aRequest,
@@ -10515,17 +10535,17 @@ nsDocShell::DoURILoad(nsIURI * aURI,
             }
         }
         if (aHeadersData) {
             rv = AddHeadersToChannel(aHeadersData, httpChannel);
         }
         // Set the referrer explicitly
         if (aReferrerURI && aSendReferrer) {
             // Referrer is currenly only set for link clicks here.
-            httpChannel->SetReferrer(aReferrerURI);
+            httpChannel->SetReferrerWithPolicy(aReferrerURI, aReferrerPolicy);
         }
     }
 
     nsCOMPtr<nsIScriptChannel> scriptChannel = do_QueryInterface(channel);
     if (scriptChannel) {
         // Allow execution against our context if the principals match
         scriptChannel->
             SetExecutionPolicy(nsIScriptChannel::EXECUTE_NORMAL);
@@ -10851,16 +10871,21 @@ nsDocShell::SetupReferrerFromChannel(nsI
 {
     nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
     if (httpChannel) {
         nsCOMPtr<nsIURI> referrer;
         nsresult rv = httpChannel->GetReferrer(getter_AddRefs(referrer));
         if (NS_SUCCEEDED(rv)) {
             SetReferrerURI(referrer);
         }
+        uint32_t referrerPolicy;
+        rv = httpChannel->GetReferrerPolicy(&referrerPolicy);
+        if (NS_SUCCEEDED(rv)) {
+            SetReferrerPolicy(referrerPolicy);
+        }
     }
 }
 
 bool
 nsDocShell::OnNewURI(nsIURI * aURI, nsIChannel * aChannel, nsISupports* aOwner,
                      uint32_t aLoadType, bool aFireOnLocationChange,
                      bool aAddToGlobalHistory, bool aCloneSHChildren)
 {
@@ -11118,16 +11143,22 @@ nsDocShell::OnLoadingSite(nsIChannel * a
 }
 
 void
 nsDocShell::SetReferrerURI(nsIURI * aURI)
 {
     mReferrerURI = aURI;        // This assigment addrefs
 }
 
+void
+nsDocShell::SetReferrerPolicy(uint32_t referrerPolicy)
+{
+    mReferrerPolicy = referrerPolicy;
+}
+
 //*****************************************************************************
 // nsDocShell: Session History
 //*****************************************************************************
 
 NS_IMETHODIMP
 nsDocShell::AddState(JS::Handle<JS::Value> aData, const nsAString& aTitle,
                      const nsAString& aURL, bool aReplace, JSContext* aCx)
 {
@@ -11547,16 +11578,17 @@ nsDocShell::AddToSessionHistory(nsIURI *
         if (!entry) {
             return NS_ERROR_OUT_OF_MEMORY;
         }
     }
 
     // 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;
     bool discardLayoutState = false;
     nsCOMPtr<nsICachingChannel> cacheChannel;
     if (aChannel) {
         cacheChannel = do_QueryInterface(aChannel);
 
@@ -11573,16 +11605,17 @@ nsDocShell::AddToSessionHistory(nsIURI *
             GetHttpChannel(aChannel, getter_AddRefs(httpChannel));
         }
         if (httpChannel) {
             nsCOMPtr<nsIUploadChannel> uploadChannel(do_QueryInterface(httpChannel));
             if (uploadChannel) {
                 uploadChannel->GetUploadStream(getter_AddRefs(inputStream));
             }
             httpChannel->GetReferrer(getter_AddRefs(referrerURI));
+            httpChannel->GetReferrerPolicy(&referrerPolicy);
 
             discardLayoutState = ShouldDiscardLayoutState(httpChannel);
         }
         aChannel->GetOwner(getter_AddRefs(owner));
         if (!owner) {
             nsCOMPtr<nsILoadInfo> loadInfo;
             aChannel->GetLoadInfo(getter_AddRefs(loadInfo));
             if (loadInfo) {
@@ -11603,16 +11636,17 @@ nsDocShell::AddToSessionHistory(nsIURI *
                   inputStream,       // Post data stream
                   nullptr,            // LayoutHistory state
                   cacheKey,          // CacheKey
                   mContentTypeHint,  // Content-type
                   owner,             // Channel or provided owner
                   mHistoryID,
                   mDynamicallyCreated);
     entry->SetReferrerURI(referrerURI);
+    entry->SetReferrerPolicy(referrerPolicy);
     nsCOMPtr<nsIInputStreamChannel> inStrmChan = do_QueryInterface(aChannel);
     if (inStrmChan) {
         bool isSrcdocChannel;
         inStrmChan->GetIsSrcdocChannel(&isSrcdocChannel);
         if (isSrcdocChannel) {
             nsAutoString srcdoc;
             inStrmChan->GetSrcdocData(srcdoc);
             entry->SetSrcdocData(srcdoc);
@@ -11702,24 +11736,27 @@ nsDocShell::LoadHistoryEntry(nsISHEntry 
 {
     if (!IsNavigationAllowed()) {
         return NS_OK;
     }
     
     nsCOMPtr<nsIURI> uri;
     nsCOMPtr<nsIInputStream> postData;
     nsCOMPtr<nsIURI> referrerURI;
+    uint32_t referrerPolicy;
     nsAutoCString contentType;
     nsCOMPtr<nsISupports> owner;
 
     NS_ENSURE_TRUE(aEntry, NS_ERROR_FAILURE);
 
     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);
     NS_ENSURE_SUCCESS(aEntry->GetOwner(getter_AddRefs(owner)),
                       NS_ERROR_FAILURE);
 
     // Calling CreateAboutBlankContentViewer can set mOSHE to null, and if
     // that's the only thing holding a ref to aEntry that will cause aEntry to
@@ -11786,16 +11823,17 @@ nsDocShell::LoadHistoryEntry(nsISHEntry 
     }
 
     // Passing nullptr as aSourceDocShell gives the same behaviour as before
     // aSourceDocShell was introduced. According to spec we should be passing
     // the source browsing context that was used when the history entry was
     // first created. bug 947716 has been created to address this issue.
     rv = InternalLoad(uri,
                       referrerURI,
+                      referrerPolicy,
                       owner,
                       flags,
                       nullptr,            // No window target
                       contentType.get(),  // Type hint
                       NullString(),       // No forced file download
                       postData,           // Post data stream
                       nullptr,            // No headers stream
                       aLoadType,          // Load type
@@ -13187,16 +13225,17 @@ nsDocShell::OnLinkClickSync(nsIContent *
   NS_ENSURE_TRUE(refererInner, NS_ERROR_UNEXPECTED);
   if (!mScriptGlobal ||
       mScriptGlobal->GetCurrentInnerWindow() != refererInner) {
       // We're no longer the current inner window
       return NS_OK;
   }
 
   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.
 
   nsAutoString target(aTargetSpec);
 
   // If this is an anchor element, grab its type property to use as a hint
   nsAutoString typeHint;
@@ -13215,16 +13254,17 @@ nsDocShell::OnLinkClickSync(nsIContent *
   nsCOMPtr<nsIURI> clonedURI;
   aURI->Clone(getter_AddRefs(clonedURI));
   if (!clonedURI) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   nsresult rv = InternalLoad(clonedURI,                 // New URI
                              referer,                   // Referer URI
+                             refererPolicy,             // Referer policy
                              aContent->NodePrincipal(), // Owner is our node's
                                                         // principal
                              flags,
                              target.get(),              // Window target
                              NS_LossyConvertUTF16toASCII(typeHint).get(),
                              aFileName,                 // Download as file
                              aPostDataStream,           // Post data stream
                              aHeadersDataStream,        // Headers stream
@@ -13232,17 +13272,17 @@ nsDocShell::OnLinkClickSync(nsIContent *
                              nullptr,                   // No SHEntry
                              true,                      // first party site
                              NullString(),              // No srcdoc
                              this,                      // We are the source
                              nullptr,                   // baseURI not needed
                              aDocShell,                 // DocShell out-param
                              aRequest);                 // Request out-param
   if (NS_SUCCEEDED(rv)) {
-    DispatchPings(aContent, aURI, referer);
+    DispatchPings(aContent, aURI, referer, refererPolicy);
   }
   return rv;
 }
 
 NS_IMETHODIMP
 nsDocShell::OnOverLink(nsIContent* aContent,
                        nsIURI* aURI,
                        const char16_t* aTargetSpec)
--- a/docshell/base/nsDocShell.h
+++ b/docshell/base/nsDocShell.h
@@ -305,16 +305,17 @@ protected:
     // Actually open a channel and perform a URI load.  Note: whatever owner is
     // passed to this function will be set on the channel.  Callers who wish to
     // not have an owner on the channel should just pass null.
     // If aSrcdoc is not void, the load will be considered as a srcdoc load,
     // and the contents of aSrcdoc will be loaded instead of aURI.
     virtual nsresult DoURILoad(nsIURI * aURI,
                                nsIURI * aReferrer,
                                bool aSendReferrer,
+                               uint32_t aReferrerPolicy,
                                nsISupports * aOwner,
                                const char * aTypeHint,
                                const nsAString & aFileName,
                                nsIInputStream * aPostData,
                                nsIInputStream * aHeadersData,
                                bool firstParty,
                                nsIDocShell ** aDocShell,
                                nsIRequest ** aRequest,
@@ -353,16 +354,17 @@ protected:
     // aCloneSHChildren argument as aCloneChildren.
     bool OnNewURI(nsIURI * aURI, nsIChannel * aChannel, nsISupports* aOwner,
                     uint32_t aLoadType,
                     bool aFireOnLocationChange,
                     bool aAddToGlobalHistory,
                     bool aCloneSHChildren);
 
     virtual void SetReferrerURI(nsIURI * aURI);
+    virtual void SetReferrerPolicy(uint32_t referrerPolicy);
 
     // Session History
     virtual bool ShouldAddToSessionHistory(nsIURI * aURI);
     // Either aChannel or aOwner must be null.  If aChannel is
     // present, the owner should be gotten from it.
     // If aCloneChildren is true, then our current session history's
     // children will be cloned onto the new entry.  This should be
     // used when we aren't actually changing the document while adding
@@ -747,16 +749,17 @@ protected:
     nsCOMPtr<nsISupportsArray> mSavedRefreshURIList;
     nsRefPtr<nsDSURIContentListener> mContentListener;
     nsCOMPtr<nsIContentViewer> mContentViewer;
     nsCOMPtr<nsIWidget>        mParentWidget;
 
     // 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;
     nsCOMPtr<nsIWebBrowserFind> mFind;
     nsCOMPtr<nsICommandManager> mCommandManager;
     // Reference to the SHEntry for this docshell until the page is destroyed.
     // Somebody give me better name
     nsCOMPtr<nsISHEntry>       mOSHE;
--- a/docshell/base/nsDocShellLoadInfo.cpp
+++ b/docshell/base/nsDocShellLoadInfo.cpp
@@ -5,25 +5,27 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // Local Includes
 #include "nsDocShellLoadInfo.h"
 #include "nsISHEntry.h"
 #include "nsIInputStream.h"
 #include "nsIURI.h"
 #include "nsIDocShell.h"
+#include "mozilla/net/ReferrerPolicy.h"
 
 //*****************************************************************************
 //***    nsDocShellLoadInfo: Object Management
 //*****************************************************************************
 
 nsDocShellLoadInfo::nsDocShellLoadInfo()
   : mInheritOwner(false),
     mOwnerIsExplicit(false),
     mSendReferrer(true),
+    mReferrerPolicy(mozilla::net::RP_Default),
     mLoadType(nsIDocShellLoadInfo::loadNormal),
     mIsSrcdocLoad(false)
 {
 }
 
 nsDocShellLoadInfo::~nsDocShellLoadInfo()
 {
 }
@@ -187,16 +189,28 @@ NS_IMETHODIMP nsDocShellLoadInfo::GetSen
 }
 
 NS_IMETHODIMP nsDocShellLoadInfo::SetSendReferrer(bool aSendReferrer)
 {
    mSendReferrer = 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;
    return NS_OK;
 }
 
 NS_IMETHODIMP nsDocShellLoadInfo::GetSrcdocData(nsAString &aSrcdocData)
 {
--- a/docshell/base/nsDocShellLoadInfo.h
+++ b/docshell/base/nsDocShellLoadInfo.h
@@ -32,16 +32,17 @@ protected:
   virtual ~nsDocShellLoadInfo();
 
 protected:
   nsCOMPtr<nsIURI>                 mReferrer;
   nsCOMPtr<nsISupports>            mOwner;
   bool                             mInheritOwner;
   bool                             mOwnerIsExplicit;
   bool                             mSendReferrer;
+  nsDocShellInfoReferrerPolicy     mReferrerPolicy;
   nsDocShellInfoLoadType           mLoadType;
   nsCOMPtr<nsISHEntry>             mSHEntry;
   nsString                         mTarget;
   nsCOMPtr<nsIInputStream>         mPostDataStream;
   nsCOMPtr<nsIInputStream>         mHeadersStream;
   bool                             mIsSrcdocLoad;
   nsString                         mSrcdocData;
   nsCOMPtr<nsIDocShell>            mSourceDocShell;
--- a/docshell/base/nsIDocShell.idl
+++ b/docshell/base/nsIDocShell.idl
@@ -49,17 +49,17 @@ interface nsIWebBrowserPrint;
 interface nsIVariant;
 interface nsIPrivacyTransitionObserver;
 interface nsIReflowObserver;
 interface nsIScrollObserver;
 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
 {
   /**
    * Loads a given URI.  This will give priority to loading the requested URI
    * in the object implementing	this interface.  If it can't be loaded here
    * however, the URL dispatcher will go through its normal process of content
    * loading.
    *
@@ -127,16 +127,17 @@ interface nsIDocShell : nsIDocShellTreeI
 
   /**
    * Loads the given URI.  This method is identical to loadURI(...) except
    * that its parameter list is broken out instead of being packaged inside
    * of an nsIDocShellLoadInfo object...
    *
    * @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.
    * @param aStopActiveDoc  - Flag indicating whether loading the current
    *                          document should be stopped.
    * @param aWindowTarget   - Window target for the load.
    * @param aTypeHint       - A hint as to the content-type of the resulting
    *                          data.  May be null or empty if no hint.
@@ -152,16 +153,17 @@ interface nsIDocShell : nsIDocShellTreeI
    *                          of aURI.
    * @param aSourceDocShell - The source browsing context for the navigation.
    * @param aBaseURI        - The base URI to be used for the load.  Set in
    *                          srcdoc loads as it cannot otherwise be inferred
    *                          in certain situations such as view-source.
    */
   [noscript]void internalLoad(in nsIURI aURI,
                               in nsIURI aReferrer,
+                              in unsigned long aReferrerPolicy,
                               in nsISupports aOwner,
                               in uint32_t aFlags,
                               in wstring aWindowTarget,
                               in string aTypeHint,
                               in AString aFileName,
                               in nsIInputStream aPostDataStream,
                               in nsIInputStream aHeadersStream,
                               in unsigned long aLoadFlags,
--- a/docshell/base/nsIDocShellLoadInfo.idl
+++ b/docshell/base/nsIDocShellLoadInfo.idl
@@ -12,18 +12,19 @@
  */
  
 interface nsIURI;
 interface nsIInputStream;
 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. */
     attribute nsIURI referrer;
 
     /** The owner of the load, that is, the entity responsible for 
      *  causing the load to occur. This should be a nsIPrincipal typically.
      */
@@ -80,16 +81,21 @@ interface nsIDocShellLoadInfo : nsISuppo
     /** Additional headers */
     attribute nsIInputStream headersStream;
 
     /** True if the referrer should be sent, false if it shouldn't be
      *  sent, even if it's available. This attribute defaults to true.
      */
     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.
      */
     readonly attribute boolean isSrcdocLoad;
 
     /** When set, the load will be interpreted as a srcdoc load, where contents
      * of this string will be loaded instead of the URI.  Setting srcdocData
      * sets isSrcdocLoad to true
--- a/docshell/shistory/public/nsISHEntry.idl
+++ b/docshell/shistory/public/nsISHEntry.idl
@@ -25,17 +25,17 @@ interface nsIBFCacheEntry;
 struct nsIntRect;
 class nsDocShellEditorData;
 class nsSHEntryShared;
 %}
 [ref] native nsIntRect(nsIntRect);
 [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
 {
     /**
      * A readonly property that returns the URI
      * of the current entry. The object returned is
      * of type nsIURI
      */
     readonly attribute nsIURI URI;
@@ -59,16 +59,21 @@ interface nsISHEntry : nsISupports
     readonly attribute boolean isSubFrame;
 
     /** URI for the document */
     void setURI(in nsIURI aURI);
 
     /** 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;
 
     /** Whether the content viewer is marked "sticky" */
     attribute boolean sticky;
 
     /** Saved state of the global window object */
     attribute nsISupports windowState;
--- a/docshell/shistory/src/nsSHEntry.cpp
+++ b/docshell/shistory/src/nsSHEntry.cpp
@@ -10,43 +10,46 @@
 #include "nsDocShellEditorData.h"
 #include "nsSHEntryShared.h"
 #include "nsILayoutHistoryState.h"
 #include "nsIContentViewer.h"
 #include "nsISupportsArray.h"
 #include "nsIStructuredCloneContainer.h"
 #include "nsIInputStream.h"
 #include "nsIURI.h"
+#include "mozilla/net/ReferrerPolicy.h"
 #include <algorithm>
 
 namespace dom = mozilla::dom;
 
 static uint32_t gEntryID = 0;
 
 //*****************************************************************************
 //***    nsSHEntry: Object Management
 //*****************************************************************************
 
 
 nsSHEntry::nsSHEntry()
-  : mLoadType(0)
+  : mReferrerPolicy(mozilla::net::RP_Default)
+  , mLoadType(0)
   , mID(gEntryID++)
   , mScrollPositionX(0)
   , mScrollPositionY(0)
   , mParent(nullptr)
   , mURIWasModified(false)
   , mIsSrcdocEntry(false)
 {
   mShared = new nsSHEntryShared();
 }
 
 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?
   , mID(other.mID)
   , mScrollPositionX(0)  // XXX why not copy?
   , mScrollPositionY(0)  // XXX why not copy?
   , mParent(other.mParent)
   , mURIWasModified(other.mURIWasModified)
@@ -129,16 +132,28 @@ NS_IMETHODIMP nsSHEntry::GetReferrerURI(
 }
 
 NS_IMETHODIMP nsSHEntry::SetReferrerURI(nsIURI *aReferrerURI)
 {
   mReferrerURI = 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)
 {
   return mShared->SetContentViewer(aViewer);
 }
 
 NS_IMETHODIMP
 nsSHEntry::GetContentViewer(nsIContentViewer **aResult)
--- a/docshell/shistory/src/nsSHEntry.h
+++ b/docshell/shistory/src/nsSHEntry.h
@@ -45,16 +45,17 @@ private:
 
   // We share the state in here with other SHEntries which correspond to the
   // same document.
   nsRefPtr<nsSHEntryShared> mShared;
 
   // 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;
   uint32_t                 mID;
   int32_t                  mScrollPositionX;
   int32_t                  mScrollPositionY;
   nsISHEntry*              mParent;
   nsCOMArray<nsISHEntry>   mChildren;
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -1534,16 +1534,18 @@ struct nsIDocument::FrameRequest
 
 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),
     mVisibilityState(dom::VisibilityState::Hidden),
     mIsInitialDocumentInWindow(false),
     mMayStartLayout(true),
     mVisible(true),
     mRemovedFromDocShell(false),
@@ -3696,16 +3698,30 @@ nsDocument::SetHeaderData(nsIAtom* aHead
       aHeaderField == nsGkAtoms::viewport_minimum_scale ||
       aHeaderField == nsGkAtoms::viewport_maximum_scale ||
       aHeaderField == nsGkAtoms::viewport_initial_scale ||
       aHeaderField == nsGkAtoms::viewport_height ||
       aHeaderField == nsGkAtoms::viewport_width ||
       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
 nsDocument::TryChannelCharset(nsIChannel *aChannel,
                               int32_t& aCharsetSource,
                               nsACString& aCharset,
                               nsHtml5TreeOpExecutor* aExecutor)
 {
--- a/dom/base/nsDocument.h
+++ b/dom/base/nsDocument.h
@@ -115,16 +115,17 @@ class CallbackFunction;
  * the ID's nsIdentifierMapEntry, the document.all result is released too.
  * Perhaps the document.all results should have their own hashtable
  * in nsHTMLDocument.
  */
 class nsIdentifierMapEntry : public nsStringHashKey
 {
 public:
   typedef mozilla::dom::Element Element;
+  typedef mozilla::net::ReferrerPolicy ReferrerPolicy;
 
   explicit nsIdentifierMapEntry(const nsAString& aKey) :
     nsStringHashKey(&aKey), mNameContentList(nullptr)
   {
   }
   explicit nsIdentifierMapEntry(const nsAString* aKey) :
     nsStringHashKey(aKey), mNameContentList(nullptr)
   {
--- a/dom/base/nsFrameLoader.cpp
+++ b/dom/base/nsFrameLoader.cpp
@@ -427,16 +427,18 @@ nsFrameLoader::ReallyStartLoadingInterna
   if (referrer) {
     bool isNullPrincipalScheme;
     rv = referrer->SchemeIs(NS_NULLPRINCIPAL_SCHEME, &isNullPrincipalScheme);
     if (NS_SUCCEEDED(rv) && !isNullPrincipalScheme) {
       loadInfo->SetReferrer(referrer);
     }
   }
 
+  loadInfo->SetReferrerPolicy(mOwnerContent->OwnerDoc()->GetReferrerPolicy());
+
   // Default flags:
   int32_t flags = nsIWebNavigation::LOAD_FLAGS_NONE;
 
   // Flags for browser frame:
   if (OwnerIsBrowserFrame()) {
     flags = nsIWebNavigation::LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP |
             nsIWebNavigation::LOAD_FLAGS_DISALLOW_INHERIT_OWNER;
   }
--- a/dom/base/nsGkAtomList.h
+++ b/dom/base/nsGkAtomList.h
@@ -577,16 +577,17 @@ GK_ATOM(menubutton, "menubutton")
 GK_ATOM(menuButton, "menu-button")
 GK_ATOM(menugroup, "menugroup")
 GK_ATOM(menuitem, "menuitem")
 GK_ATOM(menulist, "menulist")
 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")
 GK_ATOM(middle, "middle")
 GK_ATOM(min, "min")
 GK_ATOM(minheight, "minheight")
 GK_ATOM(minimum_scale, "minimum-scale")
 GK_ATOM(minpos, "minpos")
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -14,16 +14,17 @@
 #include "nsGkAtoms.h"                   // for static class members
 #include "nsIDocumentObserver.h"         // for typedef (nsUpdateType)
 #include "nsILoadGroup.h"                // for member (in nsCOMPtr)
 #include "nsINode.h"                     // for base class
 #include "nsIScriptGlobalObject.h"       // for member (in nsCOMPtr)
 #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"
 #include "Units.h"
 #include "nsExpirationTracker.h"
 #include "nsClassHashtable.h"
 
 class imgIRequest;
@@ -164,16 +165,17 @@ NS_GetContentList(nsINode* aRootNode,
 //----------------------------------------------------------------------
 
 // Document interface.  This is implemented by all document objects in
 // Gecko.
 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)
   NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW
 
 #ifdef MOZILLA_INTERNAL_API
   nsIDocument();
 #endif
@@ -267,16 +269,25 @@ public:
 
   /**
    * Set the base URI for the document loaded via XHR, when accessed from
    * chrome privileged script.
    */
   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.
    */
   virtual void SetPrincipal(nsIPrincipal *aPrincipal) = 0;
 
   /**
    * Return the LoadGroup for the document. May return null.
    */
   already_AddRefed<nsILoadGroup> GetDocumentLoadGroup() const
@@ -2463,16 +2474,19 @@ protected:
   nsCOMPtr<nsIURI> mDocumentURI;
   nsCOMPtr<nsIURI> mOriginalURI;
   nsCOMPtr<nsIURI> mChromeXHRDocURI;
   nsCOMPtr<nsIURI> mDocumentBaseURI;
   nsCOMPtr<nsIURI> mChromeXHRDocBaseURI;
 
   nsWeakPtr mDocumentLoadGroup;
 
+  bool mReferrerPolicySet;
+  ReferrerPolicy mReferrerPolicy;
+
   mozilla::WeakPtr<nsDocShell> mDocumentContainer;
 
   nsCString mCharacterSet;
   int32_t mCharacterSetSource;
 
   // This is just a weak pointer; the parent document owns its children.
   nsIDocument* mParentDocument;
 
--- a/dom/html/HTMLMetaElement.cpp
+++ b/dom/html/HTMLMetaElement.cpp
@@ -72,17 +72,31 @@ HTMLMetaElement::BindToTree(nsIDocument*
                                                  aBindingParent,
                                                  aCompileEventHandlers);
   NS_ENSURE_SUCCESS(rv, rv);
   if (aDocument &&
       AttrValueIs(kNameSpaceID_None, nsGkAtoms::name, nsGkAtoms::viewport, eIgnoreCase)) {
     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;
 }
 
 void
 HTMLMetaElement::UnbindFromTree(bool aDeep, bool aNullParent)
 {
new file mode 100644
--- /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
--- a/netwerk/base/public/moz.build
+++ b/netwerk/base/public/moz.build
@@ -139,15 +139,19 @@ EXPORTS += [
     'nsASocketHandler.h',
     'nsAsyncRedirectVerifyHelper.h',
     'nsNetUtil.h',
     'nsReadLine.h',
     'nsStreamListenerWrapper.h',
     'nsURIHashKey.h',
 ]
 
+EXPORTS.mozilla.net += [
+    'ReferrerPolicy.h',
+]
+
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
     EXPORTS += [
         'NetStatistics.h',
     ]
 
 FAIL_ON_WARNINGS = True
 
--- a/netwerk/protocol/http/HttpBaseChannel.cpp
+++ b/netwerk/protocol/http/HttpBaseChannel.cpp
@@ -71,16 +71,17 @@ HttpBaseChannel::HttpBaseChannel()
   , mResponseTimeoutEnabled(true)
   , mAllRedirectsSameOrigin(true)
   , mAllRedirectsPassTimingAllowCheck(true)
   , mForceNoIntercept(false)
   , mSuspendCount(0)
   , mProxyResolveFlags(0)
   , mContentDispositionHint(UINT32_MAX)
   , mHttpHandler(gHttpHandler)
+  , mReferrerPolicy(REFERRER_POLICY_NO_REFERRER_WHEN_DOWNGRADE)
   , mRedirectCount(0)
   , mForcePending(false)
 {
   LOG(("Creating HttpBaseChannel @%x\n", this));
 
   // Subfields of unions cannot be targeted in an initializer list
   mSelfAddr.raw.family = PR_AF_UNSPEC;
   mPeerAddr.raw.family = PR_AF_UNSPEC;
@@ -894,24 +895,47 @@ HttpBaseChannel::GetReferrer(nsIURI **re
   *referrer = mReferrer;
   NS_IF_ADDREF(*referrer);
   return NS_OK;
 }
 
 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);
-
-  if (!referrer)
-      return NS_OK;
+  mReferrerPolicy = REFERRER_POLICY_NO_REFERRER_WHEN_DOWNGRADE;
+
+  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
   // 2: always send referer
   uint32_t userReferrerLevel = gHttpHandler->ReferrerLevel();
 
   // false: use real referrer
   // true: spoof with URI of the current request
@@ -924,22 +948,24 @@ HttpBaseChannel::SetReferrer(nsIURI *ref
 
   // 0: send referer no matter what
   // 1: send referer ONLY when base domains match
   // 2: send referer ONLY when hosts match
   int userReferrerXOriginPolicy = gHttpHandler->ReferrerXOriginPolicy();
 
   // 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;
   bool match;
 
   //
   // Strip off "wyciwyg://123/" from wyciwyg referrers.
   //
@@ -987,56 +1013,80 @@ HttpBaseChannel::SetReferrer(nsIURI *ref
     nullptr
   };
   match = false;
   const char *const *scheme = referrerWhiteList;
   for (; *scheme && !match; ++scheme) {
     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.
   //
   // Support referrals from a secure server if this is a secure site
   // and (optionally) if the host names are the same.
   //
   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;
-
-      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;
+
+    // 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) {
+
+      // in other referrer policies, https->http is not allowed...
+      if (!match) return NS_OK;
+
+      // ...and https->https is possibly only allowed if the hosts match.
+      if (!gHttpHandler->SendSecureXSiteReferrer()) {
+        nsAutoCString referrerHost;
+        nsAutoCString host;
+
+        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:
   //  (1) modify it
   //  (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;
 
   nsAutoCString currentHost;
   nsAutoCString referrerHost;
 
   rv = mURI->GetAsciiHost(currentHost);
   if (NS_FAILED(rv)) return rv;
@@ -1072,21 +1122,32 @@ HttpBaseChannel::SetReferrer(nsIURI *ref
     nsCOMPtr<nsIURI> mURIclone;
     rv = mURI->CloneIgnoringRef(getter_AddRefs(mURIclone));
     if (NS_FAILED(rv)) return rv;
     clone = mURIclone;
     currentHost = referrerHost;
   }
 
   // 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) {
 
   case 1: {
     // scheme+host+port+path
     nsAutoCString prepath, path;
     rv = clone->GetPrePath(prepath);
     if (NS_FAILED(rv)) return rv;
@@ -1112,18 +1173,21 @@ HttpBaseChannel::SetReferrer(nsIURI *ref
   default:
     // full URI
     rv = clone->GetAsciiSpec(spec);
     if (NS_FAILED(rv)) return rv;
     break;
   }
 
   // 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;
 }
 
 NS_IMETHODIMP
 HttpBaseChannel::GetRequestHeader(const nsACString& aHeader,
                                   nsACString& aValue)
 {
   // XXX might be better to search the header list directly instead of
@@ -2066,17 +2130,17 @@ HttpBaseChannel::SetupReplacementChannel
     // request method gets set on the channel, regardless of whether or not
     // we set the upload stream above. This means SetRequestMethod() will
     // be called twice if ExplicitSetUploadStream() gets called above.
 
     httpChannel->SetRequestMethod(mRequestHead.Method());
   }
   // 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);
   // convey the new redirection limit
   httpChannel->SetRedirectionLimit(mRedirectionLimit - 1);
 
   // convey the Accept header value
   {
--- a/netwerk/protocol/http/HttpBaseChannel.h
+++ b/netwerk/protocol/http/HttpBaseChannel.h
@@ -128,16 +128,18 @@ public:
                                        nsIStreamListener **aNewNextListener,
                                        nsISupports *aCtxt);
 
   // HttpBaseChannel::nsIHttpChannel
   NS_IMETHOD GetRequestMethod(nsACString& aMethod);
   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);
   NS_IMETHOD VisitRequestHeaders(nsIHttpHeaderVisitor *visitor);
   NS_IMETHOD GetResponseHeader(const nsACString &header, nsACString &value);
   NS_IMETHOD SetResponseHeader(const nsACString& header,
                                const nsACString& value, bool merge);
   NS_IMETHOD VisitResponseHeaders(nsIHttpHeaderVisitor *visitor);
@@ -378,16 +380,18 @@ protected:
   uint32_t                          mProxyResolveFlags;
   nsCOMPtr<nsIURI>                  mProxyURI;
 
   uint32_t                          mContentDispositionHint;
   nsAutoPtr<nsString>               mContentDispositionFilename;
 
   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.
   nsString                          mInitiatorType;
   // Number of redirects that has occurred.
   int16_t                           mRedirectCount;
   // A time value equal to the starting time of the fetch that initiates the
   // redirect.
--- a/netwerk/protocol/http/HttpChannelParent.cpp
+++ b/netwerk/protocol/http/HttpChannelParent.cpp
@@ -269,16 +269,17 @@ HttpChannelParent::DoAsyncOpen(  const U
     mChannel->ResumeAt(startPos, entityID);
 
   if (originalUri)
     mChannel->SetOriginalURI(originalUri);
   if (docUri)
     mChannel->SetDocumentURI(docUri);
   if (referrerUri)
     mChannel->SetReferrerInternal(referrerUri);
+    //TODO set referrer policy too (in patch 5)
   if (apiRedirectToUri)
     mChannel->RedirectTo(apiRedirectToUri);
   if (topWindowUri)
     mChannel->SetTopWindowURI(topWindowUri);
   if (loadFlags != nsIRequest::LOAD_NORMAL)
     mChannel->SetLoadFlags(loadFlags);
 
   for (uint32_t i = 0; i < requestHeaders.Length(); i++) {
--- a/netwerk/protocol/http/nsIHttpChannel.idl
+++ b/netwerk/protocol/http/nsIHttpChannel.idl
@@ -9,17 +9,17 @@ interface nsIHttpHeaderVisitor;
 
 /**
  * nsIHttpChannel
  *
  * This interface allows for the modification of HTTP request parameters and
  * 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
 {
     /**************************************************************************
      * REQUEST CONFIGURATION
      *
      * Modifying request parameters after asyncOpen has been called is an error.
      */
 
@@ -51,16 +51,43 @@ interface nsIHttpChannel : nsIChannel
      * implementation is not required to throw an exception when the referrer
      * URI is rejected.
      *
      * @throws NS_ERROR_IN_PROGRESS if set after the channel has been opened.
      */
     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.
      *
      * @param aHeader
      *        The case-insensitive name of the request header to query (e.g.,
      *        "Cache-Control").
      *
      * @return the value of the request header.
      * @throws NS_ERROR_NOT_AVAILABLE if the header is not set.
--- a/netwerk/protocol/viewsource/nsViewSourceChannel.cpp
+++ b/netwerk/protocol/viewsource/nsViewSourceChannel.cpp
@@ -603,16 +603,31 @@ nsViewSourceChannel::GetReferrer(nsIURI 
 NS_IMETHODIMP
 nsViewSourceChannel::SetReferrer(nsIURI * aReferrer)
 {
     return !mHttpChannel ? NS_ERROR_NULL_POINTER :
         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)
 {
     return !mHttpChannel ? NS_ERROR_NULL_POINTER :
         mHttpChannel->GetRequestHeader(aHeader, aValue);
 }
 
 NS_IMETHODIMP
--- a/parser/html/nsHtml5SpeculativeLoad.cpp
+++ b/parser/html/nsHtml5SpeculativeLoad.cpp
@@ -22,16 +22,19 @@ nsHtml5SpeculativeLoad::~nsHtml5Speculat
 
 void
 nsHtml5SpeculativeLoad::Perform(nsHtml5TreeOpExecutor* aExecutor)
 {
   switch (mOpCode) {
     case eSpeculativeLoadBase:
       aExecutor->SetSpeculationBase(mUrl);
       break;
+    case eSpeculativeLoadMetaReferrer:
+      aExecutor->SetSpeculationReferrerPolicy(mMetaReferrerPolicy);
+      break;
     case eSpeculativeLoadImage:
       aExecutor->PreloadImage(mUrl, mCrossOrigin);
       break;
     case eSpeculativeLoadScript:
       aExecutor->PreloadScript(mUrl, mCharset, mTypeOrCharsetSource,
                                mCrossOrigin, false);
       break;
     case eSpeculativeLoadScriptFromHead:
--- a/parser/html/nsHtml5SpeculativeLoad.h
+++ b/parser/html/nsHtml5SpeculativeLoad.h
@@ -1,24 +1,26 @@
 /* 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 nsHtml5SpeculativeLoad_h
 #define nsHtml5SpeculativeLoad_h
 
 #include "nsString.h"
+#include "nsContentUtils.h"
 
 class nsHtml5TreeOpExecutor;
 
 enum eHtml5SpeculativeLoad {
 #ifdef DEBUG
   eSpeculativeLoadUninitialized,
 #endif
   eSpeculativeLoadBase,
+  eSpeculativeLoadMetaReferrer,
   eSpeculativeLoadImage,
   eSpeculativeLoadScript,
   eSpeculativeLoadScriptFromHead,
   eSpeculativeLoadStyle,
   eSpeculativeLoadManifest,
   eSpeculativeLoadSetDocumentCharset
 };
 
@@ -30,16 +32,24 @@ class nsHtml5SpeculativeLoad {
     inline void InitBase(const nsAString& aUrl)
     {
       NS_PRECONDITION(mOpCode == eSpeculativeLoadUninitialized,
                       "Trying to reinitialize a speculative load!");
       mOpCode = eSpeculativeLoadBase;
       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)
     {
       NS_PRECONDITION(mOpCode == eSpeculativeLoadUninitialized,
                       "Trying to reinitialize a speculative load!");
       mOpCode = eSpeculativeLoadImage;
       mUrl.Assign(aUrl);
       mCrossOrigin.Assign(aCrossOrigin);
@@ -111,16 +121,17 @@ class nsHtml5SpeculativeLoad {
       mTypeOrCharsetSource.Assign((char16_t)aCharsetSource);
     }
 
     void Perform(nsHtml5TreeOpExecutor* aExecutor);
     
   private:
     eHtml5SpeculativeLoad mOpCode;
     nsString mUrl;
+    nsString mMetaReferrerPolicy;
     /**
      * If mOpCode is eSpeculativeLoadStyle or eSpeculativeLoadScript[FromHead]
      * then this is the value of the "charset" attribute. For
      * eSpeculativeLoadSetDocumentCharset it is the charset that the
      * document's charset is being set to. Otherwise it's empty.
      */
     nsString mCharset;
     /**
--- a/parser/html/nsHtml5TreeBuilderCppSupplement.h
+++ b/parser/html/nsHtml5TreeBuilderCppSupplement.h
@@ -184,16 +184,25 @@ nsHtml5TreeBuilder::createElement(int32_
             mSpeculativeLoadQueue.AppendElement()->InitManifest(EmptyString());
           }
         } else if (nsHtml5Atoms::base == aName) {
           nsString* url =
               aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF);
           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:
         if (nsHtml5Atoms::image == aName) {
           nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_XLINK_HREF);
           if (url) {
             mSpeculativeLoadQueue.AppendElement()->InitImage(*url, NullString());
           }
--- a/parser/html/nsHtml5TreeOpExecutor.cpp
+++ b/parser/html/nsHtml5TreeOpExecutor.cpp
@@ -58,16 +58,18 @@ class nsHtml5ExecutorReflusher : public 
 };
 
 static mozilla::LinkedList<nsHtml5TreeOpExecutor>* gBackgroundFlushList = nullptr;
 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
 }
 
 nsHtml5TreeOpExecutor::~nsHtml5TreeOpExecutor()
 {
   if (gBackgroundFlushList && isInList()) {
     mOpQueue.Clear();
@@ -947,16 +949,37 @@ nsHtml5TreeOpExecutor::SetSpeculationBas
     return;
   }
   const nsCString& charset = mDocument->GetDocumentCharacterSet();
   DebugOnly<nsresult> rv = NS_NewURI(getter_AddRefs(mSpeculationBaseURI), aURL,
                                      charset.get(), mDocument->GetDocumentURI());
   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;
 uint32_t nsHtml5TreeOpExecutor::sAppendBatchExaminations = 0;
 uint32_t nsHtml5TreeOpExecutor::sLongestTimeOffTheEventLoop = 0;
 uint32_t nsHtml5TreeOpExecutor::sTimesFlushLoopInterrupted = 0;
 #endif
 bool nsHtml5TreeOpExecutor::sExternalViewSource = false;
--- a/parser/html/nsHtml5TreeOpExecutor.h
+++ b/parser/html/nsHtml5TreeOpExecutor.h
@@ -17,30 +17,32 @@
 #include "nsIParser.h"
 #include "nsAHtml5TreeOpSink.h"
 #include "nsHtml5TreeOpStage.h"
 #include "nsIURI.h"
 #include "nsTHashtable.h"
 #include "nsHashKeys.h"
 #include "mozilla/LinkedList.h"
 #include "nsHtml5DocumentBuilder.h"
+#include "mozilla/net/ReferrerPolicy.h"
 
 class nsHtml5Parser;
 class nsHtml5TreeBuilder;
 class nsHtml5Tokenizer;
 class nsHtml5StreamParser;
 class nsIContent;
 class nsIDocument;
 
 class nsHtml5TreeOpExecutor MOZ_FINAL : public nsHtml5DocumentBuilder,
                                         public nsIContentSink,
                                         public nsAHtml5TreeOpSink,
                                         public mozilla::LinkedListElement<nsHtml5TreeOpExecutor>
 {
   friend class nsHtml5FlushLoopGuard;
+  typedef mozilla::net::ReferrerPolicy ReferrerPolicy;
 
   public:
     NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW
     NS_DECL_ISUPPORTS_INHERITED
 
   private:
     static bool        sExternalViewSource;
 #ifdef DEBUG_NS_HTML5_TREE_OP_EXECUTOR_FLUSH
@@ -62,16 +64,22 @@ class nsHtml5TreeOpExecutor MOZ_FINAL : 
     
     /**
      * URLs already preloaded/preloading.
      */
     nsTHashtable<nsCStringHashKey> mPreloadedURLs;
 
     nsCOMPtr<nsIURI> mSpeculationBaseURI;
 
+    /**
+     * Need to keep track of whether the referrer policy was already set.
+     */
+    bool             mSpeculationReferrerPolicyWasSet;
+    ReferrerPolicy   mSpeculationReferrerPolicy;
+
     nsCOMPtr<nsIURI> mViewSourceBaseURI;
 
     /**
      * Whether the parser has started
      */
     bool                          mStarted;
 
     nsHtml5TreeOpStage            mStage;
@@ -252,16 +260,18 @@ class nsHtml5TreeOpExecutor MOZ_FINAL : 
                        bool aScriptFromHead);
 
     void PreloadStyle(const nsAString& aURL, const nsAString& aCharset,
 		      const nsAString& aCrossOrigin);
 
     void PreloadImage(const nsAString& aURL, const nsAString& aCrossOrigin);
 
     void SetSpeculationBase(const nsAString& aURL);
+
+    void SetSpeculationReferrerPolicy(const nsAString& aReferrerPolicy);
     
     void AddBase(const nsAString& aURL);
 
     static void InitializeStatics();
 
   private:
     nsHtml5Parser* GetParser();