Bug 1276836 - Implement same-origin, strict-origin, strict-origin-when-cross-origin referrer policy. r=mcmanus,jdm
authorThomas Nguyen <tnguyen@mozilla.com>
Thu, 22 Sep 2016 16:27:42 -0700
changeset 315219 890c2d9417c5b695ef1697c786126c8fff27f38d
parent 315218 566cc2b60a8ca27bff5a4737b1fb8598869730bd
child 315220 3500d2927d5208a87316982d0d4de4b6a53fa8a4
push id32563
push userihsiao@mozilla.com
push dateMon, 26 Sep 2016 11:18:33 +0000
treeherderautoland@eb840c87b5fd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmcmanus, jdm
bugs1276836
milestone52.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 1276836 - Implement same-origin, strict-origin, strict-origin-when-cross-origin referrer policy. r=mcmanus,jdm MozReview-Commit-ID: 39AFT4RgHpl
dom/html/nsGenericHTMLElement.cpp
netwerk/base/ReferrerPolicy.h
netwerk/protocol/http/HttpBaseChannel.cpp
netwerk/protocol/http/nsIHttpChannel.idl
--- a/dom/html/nsGenericHTMLElement.cpp
+++ b/dom/html/nsGenericHTMLElement.cpp
@@ -1190,16 +1190,19 @@ nsGenericHTMLElement::ParseReferrerAttri
                                              nsAttrValue& aResult)
 {
   static const nsAttrValue::EnumTable kReferrerTable[] = {
     { net::kRPS_No_Referrer, static_cast<int16_t>(net::RP_No_Referrer) },
     { net::kRPS_Origin, static_cast<int16_t>(net::RP_Origin) },
     { net::kRPS_Origin_When_Cross_Origin, static_cast<int16_t>(net::RP_Origin_When_Crossorigin) },
     { net::kRPS_No_Referrer_When_Downgrade, static_cast<int16_t>(net::RP_No_Referrer_When_Downgrade) },
     { net::kRPS_Unsafe_URL, static_cast<int16_t>(net::RP_Unsafe_URL) },
+    { net::kRPS_Strict_Origin, static_cast<int16_t>(net::RP_Strict_Origin) },
+    { net::kRPS_Same_Origin, static_cast<int16_t>(net::RP_Same_Origin) },
+    { net::kRPS_Strict_Origin_When_Cross_Origin, static_cast<int16_t>(net::RP_Strict_Origin_When_Cross_Origin) },
     { nullptr, 0 }
   };
   return aResult.ParseEnumValue(aString, kReferrerTable, false);
 }
 
 bool
 nsGenericHTMLElement::ParseFrameborderValue(const nsAString& aString,
                                             nsAttrValue& aResult)
--- a/netwerk/base/ReferrerPolicy.h
+++ b/netwerk/base/ReferrerPolicy.h
@@ -23,16 +23,25 @@ enum ReferrerPolicy {
   RP_Default                     = nsIHttpChannel::REFERRER_POLICY_DEFAULT,
 
   /* spec tokens: origin-when-cross-origin */
   RP_Origin_When_Crossorigin     = nsIHttpChannel::REFERRER_POLICY_ORIGIN_WHEN_XORIGIN,
 
   /* spec tokens: always unsafe-url */
   RP_Unsafe_URL                  = nsIHttpChannel::REFERRER_POLICY_UNSAFE_URL,
 
+  /* spec tokens: same-origin */
+  RP_Same_Origin                = nsIHttpChannel::REFERRER_POLICY_SAME_ORIGIN,
+
+  /* spec tokens: strict-origin */
+  RP_Strict_Origin               = nsIHttpChannel::REFERRER_POLICY_STRICT_ORIGIN,
+
+  /* spec tokens: strict-origin-when-cross-origin */
+  RP_Strict_Origin_When_Cross_Origin = nsIHttpChannel::REFERRER_POLICY_STRICT_ORIGIN_WHEN_XORIGIN,
+
   /* spec tokens: empty string */
   /* The empty string "" corresponds to no referrer policy, or unset policy */
   RP_Unset                       = nsIHttpChannel::REFERRER_POLICY_UNSET,
 };
 
 /* spec tokens: never no-referrer */
 const char kRPS_Never[]                       = "never";
 const char kRPS_No_Referrer[]                 = "no-referrer";
@@ -43,16 +52,25 @@ const char kRPS_Origin[]                
 /* spec tokens: default no-referrer-when-downgrade */
 const char kRPS_Default[]                     = "default";
 const char kRPS_No_Referrer_When_Downgrade[]  = "no-referrer-when-downgrade";
 
 /* spec tokens: origin-when-cross-origin */
 const char kRPS_Origin_When_Cross_Origin[]    = "origin-when-cross-origin";
 const char kRPS_Origin_When_Crossorigin[]     = "origin-when-crossorigin";
 
+/* spec tokens: same-origin */
+const char kRPS_Same_Origin[]                 = "same-origin";
+
+/* spec tokens: strict-origin */
+const char kRPS_Strict_Origin[]               = "strict-origin";
+
+/* spec tokens: strict-origin-when-cross-origin */
+const char kRPS_Strict_Origin_When_Cross_Origin[] = "strict-origin-when-cross-origin";
+
 /* spec tokens: always unsafe-url */
 const char kRPS_Always[]                      = "always";
 const char kRPS_Unsafe_URL[]                  = "unsafe-url";
 
 inline ReferrerPolicy
 ReferrerPolicyFromString(const nsAString& content)
 {
   if (content.IsEmpty()) {
@@ -73,16 +91,25 @@ ReferrerPolicyFromString(const nsAString
   if (lowerContent.EqualsLiteral(kRPS_Default) ||
       lowerContent.EqualsLiteral(kRPS_No_Referrer_When_Downgrade)) {
     return RP_No_Referrer_When_Downgrade;
   }
   if (lowerContent.EqualsLiteral(kRPS_Origin_When_Cross_Origin) ||
       lowerContent.EqualsLiteral(kRPS_Origin_When_Crossorigin)) {
     return RP_Origin_When_Crossorigin;
   }
+  if (lowerContent.EqualsLiteral(kRPS_Same_Origin)) {
+    return RP_Same_Origin;
+  }
+  if (lowerContent.EqualsLiteral(kRPS_Strict_Origin)) {
+    return RP_Strict_Origin;
+  }
+  if (lowerContent.EqualsLiteral(kRPS_Strict_Origin_When_Cross_Origin)) {
+    return RP_Strict_Origin_When_Cross_Origin;
+  }
   if (lowerContent.EqualsLiteral(kRPS_Always) ||
       lowerContent.EqualsLiteral(kRPS_Unsafe_URL)) {
     return RP_Unsafe_URL;
   }
   // Spec says if none of the previous match, use empty string.
   return RP_Unset;
 
 }
@@ -99,16 +126,19 @@ IsValidReferrerPolicy(const nsAString& c
 
   return lowerContent.EqualsLiteral(kRPS_Never)
       || lowerContent.EqualsLiteral(kRPS_No_Referrer)
       || lowerContent.EqualsLiteral(kRPS_Origin)
       || lowerContent.EqualsLiteral(kRPS_Default)
       || lowerContent.EqualsLiteral(kRPS_No_Referrer_When_Downgrade)
       || lowerContent.EqualsLiteral(kRPS_Origin_When_Cross_Origin)
       || lowerContent.EqualsLiteral(kRPS_Origin_When_Crossorigin)
+      || lowerContent.EqualsLiteral(kRPS_Same_Origin)
+      || lowerContent.EqualsLiteral(kRPS_Strict_Origin)
+      || lowerContent.EqualsLiteral(kRPS_Strict_Origin_When_Cross_Origin)
       || lowerContent.EqualsLiteral(kRPS_Always)
       || lowerContent.EqualsLiteral(kRPS_Unsafe_URL);
 }
 
 inline ReferrerPolicy
 AttributeReferrerPolicyFromString(const nsAString& content)
 {
   // Specs : https://html.spec.whatwg.org/multipage/infrastructure.html#referrer-policy-attribute
@@ -130,16 +160,26 @@ AttributeReferrerPolicyFromString(const 
     return RP_No_Referrer_When_Downgrade;
   }
   if (lowerContent.EqualsLiteral(kRPS_Origin_When_Cross_Origin)) {
     return RP_Origin_When_Crossorigin;
   }
   if (lowerContent.EqualsLiteral(kRPS_Unsafe_URL)) {
     return RP_Unsafe_URL;
   }
+  if (lowerContent.EqualsLiteral(kRPS_Strict_Origin)) {
+    return RP_Strict_Origin;
+  }
+  if (lowerContent.EqualsLiteral(kRPS_Same_Origin)) {
+    return RP_Same_Origin;
+  }
+  if (lowerContent.EqualsLiteral(kRPS_Strict_Origin_When_Cross_Origin)) {
+    return RP_Strict_Origin_When_Cross_Origin;
+  }
+
   // Spec says invalid value default is empty string state
   // So, return RP_Unset if none of the previous match, return RP_Unset
   return RP_Unset;
 }
 
 } // namespace net
 } // namespace mozilla
 
--- a/netwerk/protocol/http/HttpBaseChannel.cpp
+++ b/netwerk/protocol/http/HttpBaseChannel.cpp
@@ -1440,16 +1440,22 @@ HttpBaseChannel::SetReferrerWithPolicy(n
     }
     nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
     rv = ssm->CheckSameOriginURI(triggeringURI, mURI, false);
     isCrossOrigin = NS_FAILED(rv);
   } else {
     LOG(("no triggering principal available via loadInfo, assuming load is cross-origin"));
   }
 
+  // Don't send referrer when the request is cross-origin and policy is "same-origin".
+  if (isCrossOrigin && referrerPolicy == REFERRER_POLICY_SAME_ORIGIN) {
+    mReferrerPolicy = REFERRER_POLICY_SAME_ORIGIN;
+    return NS_OK;
+  }
+
   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.
@@ -1504,18 +1510,23 @@ HttpBaseChannel::SetReferrerWithPolicy(n
 
   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.
+  // "Strict" request from https->http case was bailed out, so here:
+  // "strict-origin" behaves the same as "origin".
+  // "strict-origin-when-cross-origin" behaves the same as "origin-when-cross-origin"
   if (referrerPolicy == REFERRER_POLICY_ORIGIN ||
-      (isCrossOrigin && referrerPolicy == REFERRER_POLICY_ORIGIN_WHEN_XORIGIN)) {
+      referrerPolicy == REFERRER_POLICY_STRICT_ORIGIN ||
+      (isCrossOrigin && (referrerPolicy == REFERRER_POLICY_ORIGIN_WHEN_XORIGIN ||
+                         referrerPolicy == REFERRER_POLICY_STRICT_ORIGIN_WHEN_XORIGIN))) {
     userReferrerTrimmingPolicy = 2;
   }
 
   // check how much referer to send
   if (userReferrerTrimmingPolicy) {
     // All output strings start with: scheme+host+port
     // We want the IDN-normalized PrePath.  That's not something currently
     // available and there doesn't yet seem to be justification for adding it to
--- a/netwerk/protocol/http/nsIHttpChannel.idl
+++ b/netwerk/protocol/http/nsIHttpChannel.idl
@@ -73,16 +73,25 @@ interface nsIHttpChannel : nsIChannel
     /*   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;
+    /*   send referrer when same-origin, no referrer when cross-origin  */
+    const unsigned long REFERRER_POLICY_SAME_ORIGIN                = 5;
+    /*   send origin when request from https->https or http->http(s)
+         No referrer when request from https->http. */
+    const unsigned long REFERRER_POLICY_STRICT_ORIGIN              = 6;
+    /*   send referrer when same-origin,
+         Send origin when cross-origin from https->https or http->http(s)
+         No referrer when request from https->http. */
+    const unsigned long REFERRER_POLICY_STRICT_ORIGIN_WHEN_XORIGIN = 7;
 
     /**
      * 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;