Bug 1544131 - Part 1: Ensure that the referrer policy provided by JS/DOM will override the default referrer policy applied to third-party trackers; r=michal
authorEhsan Akhgari <ehsan@mozilla.com>
Mon, 15 Apr 2019 13:05:10 +0000
changeset 469664 2fcb6eeb5afd
parent 469663 4b227d4b3377
child 469665 272dbcb4bc39
push id35879
push usernerli@mozilla.com
push dateTue, 16 Apr 2019 22:01:48 +0000
treeherdermozilla-central@12a60898fdc1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmichal
bugs1544131
milestone68.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 1544131 - Part 1: Ensure that the referrer policy provided by JS/DOM will override the default referrer policy applied to third-party trackers; r=michal Differential Revision: https://phabricator.services.mozilla.com/D27393
netwerk/ipc/NeckoChannelParams.ipdlh
netwerk/protocol/http/HttpBaseChannel.cpp
netwerk/protocol/http/HttpBaseChannel.h
netwerk/protocol/http/HttpChannelChild.cpp
netwerk/protocol/http/HttpChannelParent.cpp
netwerk/protocol/http/HttpChannelParent.h
netwerk/protocol/http/nsHttpChannel.cpp
--- a/netwerk/ipc/NeckoChannelParams.ipdlh
+++ b/netwerk/ipc/NeckoChannelParams.ipdlh
@@ -212,16 +212,17 @@ struct HttpChannelOpenArgs
 {
   URIParams                   uri;
   // - TODO: bug 571161: unclear if any HTTP channel clients ever
   // set originalURI != uri (about:credits?); also not clear if
   // chrome channel would ever need to know.  Get rid of next arg?
   URIParams?                  original;
   URIParams?                  doc;
   URIParams?                  originalReferrer;
+  uint32_t                    originalReferrerPolicy;
   uint32_t                    referrerPolicy;
   URIParams?                  apiRedirectTo;
   URIParams?                  topWindowURI;
   uint32_t                    loadFlags;
   RequestHeaderTuples         requestHeaders;
   nsCString                   requestMethod;
   IPCStream?                  uploadStream;
   bool                        uploadStreamHasHeaders;
--- a/netwerk/protocol/http/HttpBaseChannel.cpp
+++ b/netwerk/protocol/http/HttpBaseChannel.cpp
@@ -206,17 +206,18 @@ HttpBaseChannel::HttpBaseChannel()
       mAddedAsNonTailRequest(false),
       mAsyncOpenWaitingForStreamLength(false),
       mUpgradableToSecure(true),
       mTlsFlags(0),
       mSuspendCount(0),
       mInitialRwin(0),
       mProxyResolveFlags(0),
       mContentDispositionHint(UINT32_MAX),
-      mReferrerPolicy(NS_GetDefaultReferrerPolicy()),
+      mOriginalReferrerPolicy(NS_GetDefaultReferrerPolicy()),
+      mReferrerPolicy(mOriginalReferrerPolicy),
       mCorsMode(nsIHttpChannelInternal::CORS_MODE_NO_CORS),
       mRedirectMode(nsIHttpChannelInternal::REDIRECT_MODE_FOLLOW),
       mLastRedirectFlags(0),
       mPriority(PRIORITY_NORMAL),
       mRedirectionLimit(gHttpHandler->RedirectionLimit()),
       mRedirectCount(0),
       mInternalRedirectCount(0),
       mAsyncOpenTimeOverriden(false),
@@ -1643,16 +1644,17 @@ bool HttpBaseChannel::IsCrossOriginWithR
 }
 
 NS_IMETHODIMP
 HttpBaseChannel::SetReferrerWithPolicy(nsIURI* referrer,
                                        uint32_t referrerPolicy) {
   ENSURE_CALLED_BEFORE_CONNECT();
 
   nsIURI* originalReferrer = referrer;
+  uint32_t originalReferrerPolicy = referrerPolicy;
 
   mReferrerPolicy = referrerPolicy;
 
   // clear existing referrer, if any
   mReferrer = nullptr;
   nsresult rv = mRequestHead.ClearHeader(nsHttp::Referer);
   if (NS_FAILED(rv)) {
     return rv;
@@ -1925,16 +1927,17 @@ HttpBaseChannel::SetReferrerWithPolicy(n
     rv = clone->GetAsciiSpec(spec);
     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;
 
+  mOriginalReferrerPolicy = originalReferrerPolicy;
   mOriginalReferrer = originalReferrer;
   mReferrer = clone;
   return NS_OK;
 }
 
 // Return the channel's proxy URI, or if it doesn't exist, the
 // channel's main URI.
 NS_IMETHODIMP
--- a/netwerk/protocol/http/HttpBaseChannel.h
+++ b/netwerk/protocol/http/HttpBaseChannel.h
@@ -439,25 +439,27 @@ class HttpBaseChannel : public nsHashPro
   void InternalSetUploadStreamLength(uint64_t aLength) {
     mReqContentLength = aLength;
   }
 
   void SetUploadStreamHasHeaders(bool hasHeaders) {
     mUploadStreamHasHeaders = hasHeaders;
   }
 
-  MOZ_MUST_USE nsresult SetReferrerWithPolicyInternal(nsIURI *referrer,
-                                                      uint32_t referrerPolicy) {
+  MOZ_MUST_USE nsresult SetReferrerWithPolicyInternal(
+      nsIURI *referrer, uint32_t originalReferrerPolicy,
+      uint32_t referrerPolicy) {
     nsAutoCString spec;
     nsresult rv = referrer->GetAsciiSpec(spec);
     if (NS_FAILED(rv)) {
       return rv;
     }
     mOriginalReferrer = referrer;
     mReferrer = referrer;
+    mOriginalReferrerPolicy = originalReferrerPolicy;
     mReferrerPolicy = referrerPolicy;
     rv = mRequestHead.SetHeader(nsHttp::Referer, spec);
     return rv;
   }
 
   MOZ_MUST_USE nsresult SetTopWindowURI(nsIURI *aTopWindowURI) {
     mTopWindowURI = aTopWindowURI;
     return NS_OK;
@@ -742,16 +744,17 @@ class HttpBaseChannel : public nsHashPro
   uint32_t mSuspendCount;
 
   // Per channel transport window override (0 means no override)
   uint32_t mInitialRwin;
 
   uint32_t mProxyResolveFlags;
 
   uint32_t mContentDispositionHint;
+  uint32_t mOriginalReferrerPolicy;
   uint32_t mReferrerPolicy;
 
   uint32_t mCorsMode;
   uint32_t mRedirectMode;
 
   // If this channel was created as the result of a redirect, then this value
   // will reflect the redirect flags passed to the SetupReplacementChannel()
   // method.
--- a/netwerk/protocol/http/HttpChannelChild.cpp
+++ b/netwerk/protocol/http/HttpChannelChild.cpp
@@ -2659,16 +2659,17 @@ nsresult HttpChannelChild::ContinueAsync
 
   HttpChannelOpenArgs openArgs;
   // No access to HttpChannelOpenArgs members, but they each have a
   // function with the struct name that returns a ref.
   SerializeURI(mURI, openArgs.uri());
   SerializeURI(mOriginalURI, openArgs.original());
   SerializeURI(mDocumentURI, openArgs.doc());
   SerializeURI(mOriginalReferrer, openArgs.originalReferrer());
+  openArgs.originalReferrerPolicy() = mOriginalReferrerPolicy;
   openArgs.referrerPolicy() = mReferrerPolicy;
   SerializeURI(mAPIRedirectToURI, openArgs.apiRedirectTo());
   openArgs.loadFlags() = mLoadFlags;
   openArgs.requestHeaders() = mClientSetRequestHeaders;
   mRequestHead.Method(openArgs.requestMethod());
   openArgs.preferredAlternativeTypes() = mPreferredCachedAltDataTypes;
 
   AutoIPCStream autoStream(openArgs.uploadStream());
--- a/netwerk/protocol/http/HttpChannelParent.cpp
+++ b/netwerk/protocol/http/HttpChannelParent.cpp
@@ -129,20 +129,20 @@ void HttpChannelParent::ActorDestroy(Act
 bool HttpChannelParent::Init(const HttpChannelCreationArgs& aArgs) {
   LOG(("HttpChannelParent::Init [this=%p]\n", this));
   AUTO_PROFILER_LABEL("HttpChannelParent::Init", NETWORK);
   switch (aArgs.type()) {
     case HttpChannelCreationArgs::THttpChannelOpenArgs: {
       const HttpChannelOpenArgs& a = aArgs.get_HttpChannelOpenArgs();
       return DoAsyncOpen(
           a.uri(), a.original(), a.doc(), a.originalReferrer(),
-          a.referrerPolicy(), a.apiRedirectTo(), a.topWindowURI(),
-          a.loadFlags(), a.requestHeaders(), a.requestMethod(),
-          a.uploadStream(), a.uploadStreamHasHeaders(), a.priority(),
-          a.classOfService(), a.redirectionLimit(), a.allowSTS(),
+          a.originalReferrerPolicy(), a.referrerPolicy(), a.apiRedirectTo(),
+          a.topWindowURI(), a.loadFlags(), a.requestHeaders(),
+          a.requestMethod(), a.uploadStream(), a.uploadStreamHasHeaders(),
+          a.priority(), a.classOfService(), a.redirectionLimit(), a.allowSTS(),
           a.thirdPartyFlags(), a.resumeAt(), a.startPos(), a.entityID(),
           a.chooseApplicationCache(), a.appCacheClientID(), a.allowSpdy(),
           a.allowAltSvc(), a.beConservative(), a.tlsFlags(), a.loadInfo(),
           a.synthesizedResponseHead(), a.synthesizedSecurityInfoSerialization(),
           a.cacheKey(), a.requestContextID(), a.preflightArgs(),
           a.initialRwin(), a.blockAuthPrompt(),
           a.suspendAfterSynthesizeResponse(), a.allowStaleCacheContent(),
           a.contentTypeHint(), a.corsMode(), a.redirectMode(), a.channelId(),
@@ -380,17 +380,18 @@ void HttpChannelParent::InvokeAsyncOpen(
     AsyncOpenFailed(rv);
   }
 }
 
 bool HttpChannelParent::DoAsyncOpen(
     const URIParams& aURI, const Maybe<URIParams>& aOriginalURI,
     const Maybe<URIParams>& aDocURI,
     const Maybe<URIParams>& aOriginalReferrerURI,
-    const uint32_t& aReferrerPolicy, const Maybe<URIParams>& aAPIRedirectToURI,
+    const uint32_t& aOriginalReferrerPolicy, const uint32_t& aReferrerPolicy,
+    const Maybe<URIParams>& aAPIRedirectToURI,
     const Maybe<URIParams>& aTopWindowURI, const uint32_t& aLoadFlags,
     const RequestHeaderTuples& requestHeaders, const nsCString& requestMethod,
     const Maybe<IPCStream>& uploadStream, const bool& uploadStreamHasHeaders,
     const int16_t& priority, const uint32_t& classOfService,
     const uint8_t& redirectionLimit, const bool& allowSTS,
     const uint32_t& thirdPartyFlags, const bool& doResumeAt,
     const uint64_t& startPos, const nsCString& entityID,
     const bool& chooseApplicationCache, const nsCString& appCacheClientID,
@@ -478,18 +479,18 @@ bool HttpChannelParent::DoAsyncOpen(
     httpChannel->SetPrivate(mPBOverride == kPBOverride_Private ? true : false);
   }
 
   if (doResumeAt) httpChannel->ResumeAt(startPos, entityID);
 
   if (originalUri) httpChannel->SetOriginalURI(originalUri);
   if (docUri) httpChannel->SetDocumentURI(docUri);
   if (referrerUri) {
-    rv = httpChannel->SetReferrerWithPolicyInternal(referrerUri,
-                                                    aReferrerPolicy);
+    rv = httpChannel->SetReferrerWithPolicyInternal(
+        referrerUri, aOriginalReferrerPolicy, aReferrerPolicy);
     MOZ_ASSERT(NS_SUCCEEDED(rv));
   }
   if (apiRedirectToUri) httpChannel->RedirectTo(apiRedirectToUri);
   if (topWindowUri) {
     rv = httpChannel->SetTopWindowURI(topWindowUri);
     MOZ_ASSERT(NS_SUCCEEDED(rv));
   }
 
--- a/netwerk/protocol/http/HttpChannelParent.h
+++ b/netwerk/protocol/http/HttpChannelParent.h
@@ -136,17 +136,17 @@ class HttpChannelParent final : public n
   // ChildChannel.  Used during redirects.
   MOZ_MUST_USE bool ConnectChannel(const uint32_t& channelId,
                                    const bool& shouldIntercept);
 
   MOZ_MUST_USE bool DoAsyncOpen(
       const URIParams& uri, const Maybe<URIParams>& originalUri,
       const Maybe<URIParams>& docUri,
       const Maybe<URIParams>& originalReferrerUri,
-      const uint32_t& referrerPolicy,
+      const uint32_t& originalReferrerPolicy, const uint32_t& referrerPolicy,
       const Maybe<URIParams>& internalRedirectUri,
       const Maybe<URIParams>& topWindowUri, const uint32_t& loadFlags,
       const RequestHeaderTuples& requestHeaders, const nsCString& requestMethod,
       const Maybe<IPCStream>& uploadStream, const bool& uploadStreamHasHeaders,
       const int16_t& priority, const uint32_t& classOfService,
       const uint8_t& redirectionLimit, const bool& allowSTS,
       const uint32_t& thirdPartyFlags, const bool& doResumeAt,
       const uint64_t& startPos, const nsCString& entityID,
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -10220,23 +10220,25 @@ nsresult nsHttpChannel::RedirectToInterc
   }
 
   return rv;
 }
 
 void nsHttpChannel::ReEvaluateReferrerAfterTrackingStatusIsKnown() {
   if (StaticPrefs::network_cookie_cookieBehavior() ==
       nsICookieService::BEHAVIOR_REJECT_TRACKER) {
-    // If our referrer has been set before, and our referrer policy is equal to
-    // the default policy if we thought the channel wasn't a third-party
-    // tracking channel, we may need to set our referrer with referrer policy
-    // once again to ensure our defaults properly take effect now.
+    // If our referrer has been set before, the JS/DOM caller did not
+    // previously provide us with an explicit referrer policy value and our
+    // current referrer policy is equal to the default policy if we thought the
+    // channel wasn't a third-party tracking channel, we may need to set our
+    // referrer with referrer policy once again to ensure our defaults properly
+    // take effect now.
     bool isPrivate =
         mLoadInfo && mLoadInfo->GetOriginAttributes().mPrivateBrowsingId > 0;
-    if (mOriginalReferrer &&
+    if (mOriginalReferrer && mOriginalReferrerPolicy == REFERRER_POLICY_UNSET &&
         mReferrerPolicy ==
             NS_GetDefaultReferrerPolicy(nullptr, nullptr, isPrivate)) {
       SetReferrer(mOriginalReferrer);
     }
   }
 }
 
 namespace {