Bug 1504085 - P2 Let Origin: honor ReferrerPolicy for non-CORS r=tnguyen,valentin
☠☠ backed out by b68317f66cc6 ☠ ☠
authorJunior Hsu <juhsu@mozilla.com>
Fri, 14 Jun 2019 20:15:27 +0000
changeset 478954 94e779e03d4f1834d8b8c487d9ec170730547fcf
parent 478953 ce739f305797831f0a0c2418b05e14705bb41671
child 478955 2433254cb8221fa7d3cb8cd90bcfc8c5cb8201bf
push id87997
push userjuhsu@mozilla.com
push dateFri, 14 Jun 2019 21:22:18 +0000
treeherderautoland@94e779e03d4f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstnguyen, valentin
bugs1504085
milestone69.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 1504085 - P2 Let Origin: honor ReferrerPolicy for non-CORS r=tnguyen,valentin Differential Revision: https://phabricator.services.mozilla.com/D34454
dom/security/ReferrerInfo.cpp
dom/security/ReferrerInfo.h
netwerk/protocol/http/nsHttpChannel.cpp
--- a/dom/security/ReferrerInfo.cpp
+++ b/dom/security/ReferrerInfo.cpp
@@ -329,16 +329,58 @@ nsresult ReferrerInfo::HandleUserXOrigin
     default:
       break;
   }
 
   aAllowed = true;
   return NS_OK;
 }
 
+/* static */
+bool ReferrerInfo::ShouldSetNullOriginHeader(net::HttpBaseChannel* aChannel,
+                                             nsIURI* aOriginURI) {
+  MOZ_ASSERT(aChannel);
+  MOZ_ASSERT(aOriginURI);
+
+  // When we're dealing with CORS (mode is "cors"), we shouldn't take the
+  // Referrer-Policy into account
+  uint32_t corsMode = CORS_NONE;
+  NS_ENSURE_SUCCESS(aChannel->GetCorsMode(&corsMode), false);
+  if (corsMode == CORS_USE_CREDENTIALS) {
+    return false;
+  }
+
+  nsCOMPtr<nsIReferrerInfo> referrerInfo;
+  NS_ENSURE_SUCCESS(aChannel->GetReferrerInfo(getter_AddRefs(referrerInfo)),
+                    false);
+  if (!referrerInfo) {
+    return false;
+  }
+  uint32_t policy = referrerInfo->GetReferrerPolicy();
+  if (policy == nsIHttpChannel::REFERRER_POLICY_NO_REFERRER) {
+    return true;
+  }
+
+  bool allowed = false;
+  nsCOMPtr<nsIURI> uri;
+  NS_ENSURE_SUCCESS(aChannel->GetURI(getter_AddRefs(uri)), false);
+
+  if (NS_SUCCEEDED(ReferrerInfo::HandleSecureToInsecureReferral(
+          aOriginURI, uri, policy, allowed)) &&
+      !allowed) {
+    return true;
+  }
+
+  if (policy == nsIHttpChannel::REFERRER_POLICY_SAME_ORIGIN) {
+    return ReferrerInfo::IsCrossOriginRequest(aChannel);
+  }
+
+  return false;
+}
+
 nsresult ReferrerInfo::HandleUserReferrerSendingPolicy(nsIHttpChannel* aChannel,
                                                        bool& aAllowed) const {
   aAllowed = false;
   uint32_t referrerSendingPolicy;
   uint32_t loadFlags;
   nsresult rv = aChannel->GetLoadFlags(&loadFlags);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
--- a/dom/security/ReferrerInfo.h
+++ b/dom/security/ReferrerInfo.h
@@ -98,16 +98,23 @@ class ReferrerInfo : public nsIReferrerI
 
   /*
    * Check whether we need to hide referrer when leaving a .onion domain.
    * Controlled by user pref: network.http.referer.hideOnionSource
    */
   static bool HideOnionReferrerSource();
 
   /**
+   * Returns true if the given channel is suppressed by Referrer-Policy header
+   * and should set "null" to Origin header.
+   */
+  static bool ShouldSetNullOriginHeader(net::HttpBaseChannel* aChannel,
+                                        nsIURI* aOriginURI);
+
+  /**
    * Return default referrer policy which is controlled by user
    * prefs:
    * network.http.referer.defaultPolicy for regular mode
    * network.http.referer.defaultPolicy.trackers for third-party trackers
    * in regular mode
    * network.http.referer.defaultPolicy.pbmode for private mode
    * network.http.referer.defaultPolicy.trackers.pbmode for third-party trackers
    * in private mode
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -9680,25 +9680,34 @@ void nsHttpChannel::SetLoadGroupUserAgen
   }
 }
 
 // Step 10 of HTTP-network-or-cache fetch
 void nsHttpChannel::SetOriginHeader() {
   if (mRequestHead.IsGet() || mRequestHead.IsHead()) {
     return;
   }
+  nsresult rv;
+
   nsAutoCString existingHeader;
   Unused << mRequestHead.GetHeader(nsHttp::Origin, existingHeader);
   if (!existingHeader.IsEmpty()) {
     LOG(("nsHttpChannel::SetOriginHeader Origin header already present"));
+    nsCOMPtr<nsIURI> uri;
+    rv = NS_NewURI(getter_AddRefs(uri), existingHeader);
+    if (NS_SUCCEEDED(rv) &&
+        ReferrerInfo::ShouldSetNullOriginHeader(this, uri)) {
+      LOG(("nsHttpChannel::SetOriginHeader null Origin by Referrer-Policy"));
+      rv = mRequestHead.SetHeader(nsHttp::Origin, NS_LITERAL_CSTRING("null"),
+                                  false /* merge */);
+      MOZ_ASSERT(NS_SUCCEEDED(rv));
+    }
     return;
   }
 
-  DebugOnly<nsresult> rv;
-
   // Instead of consulting Preferences::GetInt() all the time we
   // can cache the result to speed things up.
   static int32_t sSendOriginHeader = 0;
   static bool sIsInited = false;
   if (!sIsInited) {
     sIsInited = true;
     Preferences::AddIntVarCache(&sSendOriginHeader,
                                 "network.http.sendOriginHeader");
@@ -9733,16 +9742,20 @@ void nsHttpChannel::SetOriginHeader() {
       nsContentUtils::GetASCIIOrigin(mURI, currentOrigin);
       if (!origin.EqualsIgnoreCase(currentOrigin.get())) {
         // Origin header is suppressed by .onion
         return;
       }
     }
   }
 
+  if (referrer && ReferrerInfo::ShouldSetNullOriginHeader(this, referrer)) {
+    origin.AssignLiteral("null");
+  }
+
   rv = mRequestHead.SetHeader(nsHttp::Origin, origin, false /* merge */);
   MOZ_ASSERT(NS_SUCCEEDED(rv));
 }
 
 void nsHttpChannel::SetDoNotTrack() {
   /**
    * 'DoNotTrack' header should be added if 'privacy.donottrackheader.enabled'
    * is true or tracking protection is enabled. See bug 1258033.