Bug 1264164 - Update request'referrer policy when redirect. r?ehsan draft
authorThomas Nguyen <tnguyen@mozilla.com>
Wed, 31 Aug 2016 11:09:00 +0800
changeset 407840 791ba875174c48bc34c7367bd457256680c50ed1
parent 407818 506facea63169a29e04eb140663da1730052db64
child 407841 abddee6822c7821de697d95c6acc41f4c120ac9d
push id28055
push usertnguyen@mozilla.com
push dateWed, 31 Aug 2016 03:09:37 +0000
reviewersehsan
bugs1264164
milestone51.0a1
Bug 1264164 - Update request'referrer policy when redirect. r?ehsan MozReview-Commit-ID: 6MR9Wh4pEmi
dom/base/nsContentUtils.cpp
dom/fetch/FetchDriver.cpp
dom/fetch/FetchUtil.cpp
dom/fetch/FetchUtil.h
dom/workers/ScriptLoader.cpp
dom/xhr/XMLHttpRequestMainThread.cpp
netwerk/protocol/http/HttpBaseChannel.cpp
netwerk/protocol/http/HttpChannelChild.cpp
netwerk/protocol/http/HttpChannelChild.h
netwerk/protocol/http/HttpChannelParent.cpp
netwerk/protocol/http/HttpChannelParent.h
netwerk/protocol/http/PHttpChannel.ipdl
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -8364,20 +8364,18 @@ nsContentUtils::SetFetchReferrerURIWithP
       referrerURI = docCurURI;
     }
   }
 
   if (!referrerURI) {
     referrerURI = principalURI;
   }
 
-  net::ReferrerPolicy referrerPolicy = aReferrerPolicy;
-  if (referrerPolicy == net::RP_Default) {
-    referrerPolicy = aDoc->GetReferrerPolicy();
-  }
+  net::ReferrerPolicy referrerPolicy = (aReferrerPolicy != net::RP_Unset) ?
+                                       aReferrerPolicy : net::RP_Default;
   return aChannel->SetReferrerWithPolicy(referrerURI, referrerPolicy);
 }
 
 // static
 net::ReferrerPolicy
 nsContentUtils::GetReferrerPolicyFromHeader(const nsAString& aHeader)
 {
   // Multiple headers could be concatenated into one comma-separated
--- a/dom/fetch/FetchDriver.cpp
+++ b/dom/fetch/FetchDriver.cpp
@@ -29,16 +29,17 @@
 #include "nsStringStream.h"
 #include "nsHttpChannel.h"
 
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/workers/Workers.h"
 #include "mozilla/Unused.h"
 
 #include "Fetch.h"
+#include "FetchUtil.h"
 #include "InternalRequest.h"
 #include "InternalResponse.h"
 
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_ISUPPORTS(FetchDriver,
                   nsIStreamListener, nsIChannelEventSink, nsIInterfaceRequestor,
@@ -244,72 +245,55 @@ FetchDriver::HttpFetch()
     nsAutoCString method;
     mRequest->GetMethod(method);
     rv = httpChan->SetRequestMethod(method);
     NS_ENSURE_SUCCESS(rv, rv);
 
     // Set the same headers.
     SetRequestHeaders(httpChan);
 
-    // Step 2. Set the referrer.
-    nsAutoString referrer;
-    mRequest->GetReferrer(referrer);
-
-    // The Referrer Policy in Request can be used to override a referrer policy
-    // associated with an environment settings object.
-    // If there's no Referrer Policy in the request, it should be inherited
-    // from environment.
+    // If request's referrer policy is the empty string and request's client is
+    // non-null, then set request's referrer policy to request's client's
+    // associated referrer policy.
+    // If request's referrer policy is the empty string, then set request's
+    // referrer policy to "no-referrer-when-downgrade".
+    // If request's referrer is not "no-referrer", set request's referrer to the
+    // result of invoking determine request's referrer.
     ReferrerPolicy referrerPolicy = mRequest->ReferrerPolicy_();
     net::ReferrerPolicy net_referrerPolicy = mRequest->GetEnvironmentReferrerPolicy();
     switch (referrerPolicy) {
-    case ReferrerPolicy::_empty:
-      break;
-    case ReferrerPolicy::No_referrer:
-      net_referrerPolicy = net::RP_No_Referrer;
-      break;
-    case ReferrerPolicy::No_referrer_when_downgrade:
-      net_referrerPolicy = net::RP_No_Referrer_When_Downgrade;
-      break;
-    case ReferrerPolicy::Origin:
-      net_referrerPolicy = net::RP_Origin;
-      break;
-    case ReferrerPolicy::Origin_when_cross_origin:
-      net_referrerPolicy = net::RP_Origin_When_Crossorigin;
-      break;
-    case ReferrerPolicy::Unsafe_url:
-      net_referrerPolicy = net::RP_Unsafe_URL;
-      break;
-    default:
-      MOZ_ASSERT_UNREACHABLE("Invalid ReferrerPolicy enum value?");
-      break;
+      case ReferrerPolicy::_empty:
+        break;
+      case ReferrerPolicy::No_referrer:
+        net_referrerPolicy = net::RP_No_Referrer;
+        break;
+      case ReferrerPolicy::No_referrer_when_downgrade:
+        net_referrerPolicy = net::RP_No_Referrer_When_Downgrade;
+        break;
+      case ReferrerPolicy::Origin:
+        net_referrerPolicy = net::RP_Origin;
+        break;
+      case ReferrerPolicy::Origin_when_cross_origin:
+        net_referrerPolicy = net::RP_Origin_When_Crossorigin;
+        break;
+      case ReferrerPolicy::Unsafe_url:
+        net_referrerPolicy = net::RP_Unsafe_URL;
+        break;
+      default:
+        MOZ_ASSERT_UNREACHABLE("Invalid ReferrerPolicy enum value?");
+        break;
     }
-    if (referrer.EqualsLiteral(kFETCH_CLIENT_REFERRER_STR)) {
-      rv = nsContentUtils::SetFetchReferrerURIWithPolicy(mPrincipal,
-                                                         mDocument,
-                                                         httpChan,
-                                                         net_referrerPolicy);
-      NS_ENSURE_SUCCESS(rv, rv);
-    } else if (referrer.IsEmpty()) {
-      rv = httpChan->SetReferrerWithPolicy(nullptr, net::RP_No_Referrer);
-      NS_ENSURE_SUCCESS(rv, rv);
-    } else {
-      // From "Determine request's Referrer" step 3
-      // "If request's referrer is a URL, let referrerSource be request's
-      // referrer."
-      nsCOMPtr<nsIURI> referrerURI;
-      rv = NS_NewURI(getter_AddRefs(referrerURI), referrer, nullptr, nullptr);
-      NS_ENSURE_SUCCESS(rv, rv);
 
-      rv =
-        httpChan->SetReferrerWithPolicy(referrerURI,
-                                        referrerPolicy == ReferrerPolicy::_empty ?
-                                          mRequest->GetEnvironmentReferrerPolicy() :
-                                          net_referrerPolicy);
-      NS_ENSURE_SUCCESS(rv, rv);
-    }
+    // Set request's referrer
+    rv = FetchUtil::SetRequestReferrer(mPrincipal,
+                                       mDocument,
+                                       httpChan,
+                                       mRequest,
+                                       net_referrerPolicy);
+    NS_ENSURE_SUCCESS(rv, rv);
 
     // Bug 1120722 - Authorization will be handled later.
     // Auth may require prompting, we don't support it yet.
     // The next patch in this same bug prevents this from aborting the request.
     // Credentials checks for CORS are handled by nsCORSListenerProxy,
 
     nsCOMPtr<nsIHttpChannelInternal> internalChan = do_QueryInterface(httpChan);
 
@@ -725,20 +709,31 @@ FetchDriver::AsyncOnChannelRedirect(nsIC
           referrerPolicy = ReferrerPolicy::Unsafe_url;
           break;
         default:
           MOZ_ASSERT_UNREACHABLE("Invalid ReferrerPolicy value");
           break;
       }
 
       mRequest->SetReferrerPolicy(referrerPolicy);
+      // Should update channel's referrer policy
+      if (httpChannel) {
+        rv = FetchUtil::SetRequestReferrer(mPrincipal,
+                                           mDocument,
+                                           httpChannel,
+                                           mRequest,
+                                           net_referrerPolicy);
+        NS_ENSURE_SUCCESS(rv, rv);
+      }
     }
   }
 
-  aCallback->OnRedirectVerifyCallback(NS_OK);
+  if (NS_SUCCEEDED(rv)) {
+    aCallback->OnRedirectVerifyCallback(NS_OK);
+  }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 FetchDriver::CheckListenerChain()
 {
   return NS_OK;
 }
--- a/dom/fetch/FetchUtil.cpp
+++ b/dom/fetch/FetchUtil.cpp
@@ -1,15 +1,17 @@
 #include "FetchUtil.h"
 
 #include "nsError.h"
 #include "nsIUnicodeDecoder.h"
 #include "nsString.h"
+#include "nsIDocument.h"
 
 #include "mozilla/dom/EncodingUtils.h"
+#include "mozilla/dom/InternalRequest.h"
 
 namespace mozilla {
 namespace dom {
 
 // static
 nsresult
 FetchUtil::GetValidRequestMethod(const nsACString& aMethod, nsCString& outMethod)
 {
@@ -103,10 +105,62 @@ FetchUtil::ExtractHeader(nsACString::con
   if (!NS_IsReasonableHTTPHeaderValue(aHeaderValue)) {
     return false;
   }
   aHeaderValue.CompressWhitespace();
 
   return PushOverLine(aStart);
 }
 
+// static
+nsresult
+FetchUtil::SetRequestReferrer(nsIPrincipal* aPrincipal,
+                              nsIDocument* aDoc,
+                              nsIHttpChannel* aChannel,
+                              InternalRequest* aRequest,
+                              net::ReferrerPolicy aPolicy) {
+  nsAutoString referrer;
+  aRequest->GetReferrer(referrer);
+
+  nsresult rv = NS_OK;
+  if (referrer.EqualsLiteral(kFETCH_CLIENT_REFERRER_STR)) {
+    rv = nsContentUtils::SetFetchReferrerURIWithPolicy(aPrincipal,
+                                                       aDoc,
+                                                       aChannel,
+                                                       aPolicy);
+    NS_ENSURE_SUCCESS(rv, rv);
+  } else if (referrer.IsEmpty()) {
+    rv = aChannel->SetReferrerWithPolicy(nullptr, net::RP_No_Referrer);
+    NS_ENSURE_SUCCESS(rv, rv);
+  } else {
+    // From "Determine request's Referrer" step 3
+    // "If request's referrer is a URL, let referrerSource be request's
+    // referrer."
+    nsCOMPtr<nsIURI> referrerURI;
+    rv = NS_NewURI(getter_AddRefs(referrerURI), referrer, nullptr, nullptr);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    rv = aChannel->SetReferrerWithPolicy(referrerURI, aPolicy);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  nsCOMPtr<nsIURI> referrerURI;
+  aChannel->GetReferrer(getter_AddRefs(referrerURI));
+
+  // Step 2. Set the referrer.
+  if (referrerURI) {
+    nsAutoString referrerURL;
+    nsAutoCString spec;
+
+    rv = referrerURI->GetSpec(spec);
+    CopyUTF8toUTF16(spec, referrerURL);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    aRequest->SetReferrer(referrerURL);
+  } else {
+    aRequest->SetReferrer(EmptyString());
+  }
+
+  return NS_OK;
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/fetch/FetchUtil.h
+++ b/dom/fetch/FetchUtil.h
@@ -3,19 +3,25 @@
 
 #include "nsString.h"
 #include "nsError.h"
 
 #include "mozilla/ErrorResult.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/FormData.h"
 
+class nsIPrincipal;
+class nsIDocument;
+class nsIHttpChannel;
+
 namespace mozilla {
 namespace dom {
 
+class InternalRequest;
+
 class FetchUtil final
 {
 private:
   FetchUtil() = delete;
 
 public:
   /**
   * Sets outMethod to a valid HTTP request method string based on an input method.
@@ -30,13 +36,20 @@ public:
    * Extracts an HTTP header from a substring range.
    */
   static bool
   ExtractHeader(nsACString::const_iterator& aStart,
                 nsACString::const_iterator& aEnd,
                 nsCString& aHeaderName,
                 nsCString& aHeaderValue,
                 bool* aWasEmptyHeader);
+
+  static nsresult
+  SetRequestReferrer(nsIPrincipal* aPrincipal,
+                     nsIDocument* aDoc,
+                     nsIHttpChannel* aChannel,
+                     InternalRequest* aRequest,
+                     net::ReferrerPolicy aPolicy);
 };
 
 } // namespace dom
 } // namespace mozilla
 #endif
--- a/dom/workers/ScriptLoader.cpp
+++ b/dom/workers/ScriptLoader.cpp
@@ -199,18 +199,20 @@ ChannelFromScriptURL(nsIPrincipal* princ
                        nullptr, // aCallbacks
                        aLoadFlags,
                        ios);
   }
 
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(channel)) {
+    mozilla::net::ReferrerPolicy referrerPolicy = parentDoc ?
+      parentDoc->GetReferrerPolicy() : mozilla::net::RP_Default;
     rv = nsContentUtils::SetFetchReferrerURIWithPolicy(principal, parentDoc,
-                                                       httpChannel, mozilla::net::RP_Default);
+                                                       httpChannel, referrerPolicy);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
   }
 
   channel.forget(aChannel);
   return rv;
 }
--- a/dom/xhr/XMLHttpRequestMainThread.cpp
+++ b/dom/xhr/XMLHttpRequestMainThread.cpp
@@ -2467,19 +2467,20 @@ XMLHttpRequestMainThread::InitiateFetch(
       mAuthorRequestHeaders.Set("accept", NS_LITERAL_CSTRING("*/*"));
     }
 
     mAuthorRequestHeaders.ApplyToChannel(httpChannel);
 
     if (!IsSystemXHR()) {
       nsCOMPtr<nsPIDOMWindowInner> owner = GetOwner();
       nsCOMPtr<nsIDocument> doc = owner ? owner->GetExtantDoc() : nullptr;
+      mozilla::net::ReferrerPolicy referrerPolicy = doc ?
+        doc->GetReferrerPolicy() : mozilla::net::RP_Default;
       nsContentUtils::SetFetchReferrerURIWithPolicy(mPrincipal, doc,
-                                                    httpChannel,
-                                                    mozilla::net::RP_Default);
+                                                    httpChannel, referrerPolicy);
     }
 
     // Some extensions override the http protocol handler and provide their own
     // implementation. The channels returned from that implementation don't
     // always seem to implement the nsIUploadChannel2 interface, presumably
     // because it's a new interface. Eventually we should remove this and simply
     // require that http channels implement the new interface (see bug 529041).
     nsCOMPtr<nsIUploadChannel2> uploadChannel2 = do_QueryInterface(httpChannel);
--- a/netwerk/protocol/http/HttpBaseChannel.cpp
+++ b/netwerk/protocol/http/HttpBaseChannel.cpp
@@ -1276,25 +1276,24 @@ HttpBaseChannel::SetReferrerWithPolicy(n
   ENSURE_CALLED_BEFORE_CONNECT();
 
   // clear existing referrer, if any
   mReferrer = nullptr;
   nsresult rv = mRequestHead.ClearHeader(nsHttp::Referer);
   if(NS_FAILED(rv)) {
     return rv;
   }
-  mReferrerPolicy = REFERRER_POLICY_NO_REFERRER_WHEN_DOWNGRADE;
+  mReferrerPolicy = referrerPolicy;
 
   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();
 
@@ -1562,17 +1561,16 @@ HttpBaseChannel::SetReferrerWithPolicy(n
     if (NS_FAILED(rv)) return rv;
   }
 
   // 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;
-  mReferrerPolicy = referrerPolicy;
   return NS_OK;
 }
 
 // Return the channel's proxy URI, or if it doesn't exist, the
 // channel's main URI.
 NS_IMETHODIMP
 HttpBaseChannel::GetProxyURI(nsIURI **aOut)
 {
--- a/netwerk/protocol/http/HttpChannelChild.cpp
+++ b/netwerk/protocol/http/HttpChannelChild.cpp
@@ -1561,16 +1561,21 @@ public:
   }
 };
 
 NS_IMETHODIMP
 HttpChannelChild::OnRedirectVerifyCallback(nsresult result)
 {
   LOG(("HttpChannelChild::OnRedirectVerifyCallback [this=%p]\n", this));
   OptionalURIParams redirectURI;
+
+  uint32_t referrerPolicy;
+  OptionalURIParams referrerURI;
+  SerializeURI(nullptr, referrerURI);
+
   nsCOMPtr<nsIHttpChannel> newHttpChannel =
       do_QueryInterface(mRedirectChannelChild);
 
   if (NS_SUCCEEDED(result) && !mRedirectChannelChild) {
     // mRedirectChannelChild doesn't exist means we're redirecting to a protocol
     // that doesn't implement nsIChildChannel. The redirect result should be set
     // as failed by veto listeners and shouldn't enter this condition. As the
     // last resort, we synthesize the error result as NS_ERROR_DOM_BAD_URI here
@@ -1578,16 +1583,21 @@ HttpChannelChild::OnRedirectVerifyCallba
     // another protocol and throw an error.
     LOG(("  redirecting to a protocol that doesn't implement nsIChildChannel"));
     result = NS_ERROR_DOM_BAD_URI;
   }
 
   if (newHttpChannel) {
     // Must not be called until after redirect observers called.
     newHttpChannel->SetOriginalURI(mOriginalURI);
+    newHttpChannel->GetReferrerPolicy(&referrerPolicy);
+    nsCOMPtr<nsIURI> newChannelReferrerURI;
+    newHttpChannel->GetReferrer(getter_AddRefs(newChannelReferrerURI));
+
+    SerializeURI(newChannelReferrerURI, referrerURI);
   }
 
   if (mRedirectingForSubsequentSynthesizedResponse) {
     nsCOMPtr<nsIHttpChannelChild> httpChannelChild = do_QueryInterface(mRedirectChannelChild);
     MOZ_ASSERT(httpChannelChild);
     RefPtr<HttpChannelChild> redirectedChannel =
         static_cast<HttpChannelChild*>(httpChannelChild.get());
 
@@ -1640,18 +1650,18 @@ HttpChannelChild::OnRedirectVerifyCallba
 
     nsCOMPtr<nsIRequest> request = do_QueryInterface(mRedirectChannelChild);
     if (request) {
       request->GetLoadFlags(&loadFlags);
     }
   }
 
   if (mIPCOpen)
-    SendRedirect2Verify(result, *headerTuples, loadFlags, redirectURI,
-                        corsPreflightArgs);
+    SendRedirect2Verify(result, *headerTuples, loadFlags, referrerPolicy,
+                        referrerURI, redirectURI, corsPreflightArgs);
 
   return NS_OK;
 }
 
 //-----------------------------------------------------------------------------
 // HttpChannelChild::nsIRequest
 //-----------------------------------------------------------------------------
 
@@ -2021,16 +2031,41 @@ HttpChannelChild::ContinueAsyncOpen()
   return NS_OK;
 }
 
 //-----------------------------------------------------------------------------
 // HttpChannelChild::nsIHttpChannel
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
+HttpChannelChild::SetReferrer(nsIURI *referrer)
+{
+  return SetReferrerWithPolicy(referrer, REFERRER_POLICY_NO_REFERRER_WHEN_DOWNGRADE);
+}
+
+NS_IMETHODIMP
+HttpChannelChild::SetReferrerWithPolicy(nsIURI *referrer,
+                                       uint32_t referrerPolicy)
+{
+  ENSURE_CALLED_BEFORE_CONNECT();
+
+  // remove old referrer if any
+  for (uint32_t i = 0; i < mClientSetRequestHeaders.Length(); i++ ) {
+    if (NS_LITERAL_CSTRING("Referer").Equals(mClientSetRequestHeaders[i].mHeader)) {
+      mClientSetRequestHeaders.RemoveElementAt(i);
+    }
+  }
+
+  nsresult rv = HttpBaseChannel::SetReferrerWithPolicy(referrer, referrerPolicy);
+  if (NS_FAILED(rv))
+    return rv;
+  return NS_OK;
+
+}
+NS_IMETHODIMP
 HttpChannelChild::SetRequestHeader(const nsACString& aHeader,
                                    const nsACString& aValue,
                                    bool aMerge)
 {
   LOG(("HttpChannelChild::SetRequestHeader [this=%p]\n", this));
   nsresult rv = HttpBaseChannel::SetRequestHeader(aHeader, aValue, aMerge);
   if (NS_FAILED(rv))
     return rv;
--- a/netwerk/protocol/http/HttpChannelChild.h
+++ b/netwerk/protocol/http/HttpChannelChild.h
@@ -74,16 +74,18 @@ public:
   NS_IMETHOD Suspend() override;
   NS_IMETHOD Resume() override;
   // nsIChannel
   NS_IMETHOD GetSecurityInfo(nsISupports **aSecurityInfo) override;
   NS_IMETHOD AsyncOpen(nsIStreamListener *listener, nsISupports *aContext) override;
   NS_IMETHOD AsyncOpen2(nsIStreamListener *aListener) override;
 
   // HttpBaseChannel::nsIHttpChannel
+  NS_IMETHOD SetReferrer(nsIURI *referrer) override;
+  NS_IMETHOD SetReferrerWithPolicy(nsIURI *referrer, uint32_t referrerPolicy) override;
   NS_IMETHOD SetRequestHeader(const nsACString& aHeader,
                               const nsACString& aValue,
                               bool aMerge) override;
   NS_IMETHOD SetEmptyRequestHeader(const nsACString& aHeader) override;
   NS_IMETHOD RedirectTo(nsIURI *newURI) override;
   NS_IMETHOD GetProtocolVersion(nsACString& aProtocolVersion) override;
   // nsIHttpChannelInternal
   NS_IMETHOD SetupFallbackChannel(const char *aFallbackKey) override;
--- a/netwerk/protocol/http/HttpChannelParent.cpp
+++ b/netwerk/protocol/http/HttpChannelParent.cpp
@@ -625,16 +625,18 @@ HttpChannelParent::RecvUpdateAssociatedC
   }
   return true;
 }
 
 bool
 HttpChannelParent::RecvRedirect2Verify(const nsresult& result,
                                        const RequestHeaderTuples& changedHeaders,
                                        const uint32_t& loadFlags,
+                                       const uint32_t& referrerPolicy,
+                                       const OptionalURIParams& aReferrerURI,
                                        const OptionalURIParams& aAPIRedirectURI,
                                        const OptionalCorsPreflightArgs& aCorsPreflightArgs)
 {
   LOG(("HttpChannelParent::RecvRedirect2Verify [this=%p result=%x]\n",
        this, result));
   if (NS_SUCCEEDED(result)) {
     nsCOMPtr<nsIHttpChannel> newHttpChannel =
         do_QueryInterface(mRedirectChannel);
@@ -663,16 +665,19 @@ HttpChannelParent::RecvRedirect2Verify(c
 
       if (aCorsPreflightArgs.type() == OptionalCorsPreflightArgs::TCorsPreflightArgs) {
         nsCOMPtr<nsIHttpChannelInternal> newInternalChannel =
           do_QueryInterface(newHttpChannel);
         MOZ_RELEASE_ASSERT(newInternalChannel);
         const CorsPreflightArgs& args = aCorsPreflightArgs.get_CorsPreflightArgs();
         newInternalChannel->SetCorsPreflightParameters(args.unsafeHeaders());
       }
+
+      nsCOMPtr<nsIURI> referrerUri = DeserializeURI(aReferrerURI);
+      newHttpChannel->SetReferrerWithPolicy(referrerUri, referrerPolicy);
     }
   }
 
   if (!mRedirectCallback) {
     // This should according the logic never happen, log the situation.
     if (mReceivedRedirect2Verify)
       LOG(("RecvRedirect2Verify[%p]: Duplicate fire", this));
     if (mSentRedirect1BeginFailed)
--- a/netwerk/protocol/http/HttpChannelParent.h
+++ b/netwerk/protocol/http/HttpChannelParent.h
@@ -146,16 +146,18 @@ protected:
   virtual bool RecvSetClassOfService(const uint32_t& cos) override;
   virtual bool RecvSetCacheTokenCachedCharset(const nsCString& charset) override;
   virtual bool RecvSuspend() override;
   virtual bool RecvResume() override;
   virtual bool RecvCancel(const nsresult& status) override;
   virtual bool RecvRedirect2Verify(const nsresult& result,
                                    const RequestHeaderTuples& changedHeaders,
                                    const uint32_t& loadFlags,
+                                   const uint32_t& referrerPolicy,
+                                   const OptionalURIParams& aReferrerURI,
                                    const OptionalURIParams& apiRedirectUri,
                                    const OptionalCorsPreflightArgs& aCorsPreflightArgs) override;
   virtual bool RecvUpdateAssociatedContentSecurity(const int32_t& broken,
                                                    const int32_t& no) override;
   virtual bool RecvDocumentChannelCleanup() override;
   virtual bool RecvMarkOfflineCacheEntryAsForeign() override;
   virtual bool RecvDivertOnDataAvailable(const nsCString& data,
                                          const uint64_t& offset,
--- a/netwerk/protocol/http/PHttpChannel.ipdl
+++ b/netwerk/protocol/http/PHttpChannel.ipdl
@@ -40,17 +40,19 @@ parent:
                                         int32_t no);
   async Suspend();
   async Resume();
 
   async Cancel(nsresult status);
 
   // Reports approval/veto of redirect by child process redirect observers
   async Redirect2Verify(nsresult result, RequestHeaderTuples changedHeaders,
-                        uint32_t loadFlags, OptionalURIParams apiRedirectTo,
+                        uint32_t loadFlags, uint32_t referrerPolicy,
+                        OptionalURIParams referrerUri,
+                        OptionalURIParams apiRedirectTo,
                         OptionalCorsPreflightArgs corsPreflightArgs);
 
   // For document loads we keep this protocol open after child's
   // OnStopRequest, and send this msg (instead of __delete__) to allow
   // partial cleanup on parent.
   async DocumentChannelCleanup();
 
   // This might have to be sync. If this fails we must fail the document load