Bug 1547813 - Part 8: Introduce a CookieSettings API to query whether cookies from third-party trackers must be rejected and use it in Gecko; r=baku
☠☠ backed out by 8fea66166287 ☠ ☠
authorEhsan Akhgari <ehsan@mozilla.com>
Wed, 08 May 2019 20:22:18 +0000
changeset 532061 8cad4fd197b1bdbee9e36bc54a12c48dd8c8e269
parent 532060 807ce59e7e6eecbbb83b02d1ff45ecbda9896835
child 532062 c1288949de1cc38beee2a6cea0704f59c46f2551
push id11265
push userffxbld-merge
push dateMon, 13 May 2019 10:53:39 +0000
treeherdermozilla-beta@77e0fe8dbdd3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbaku
bugs1547813
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 1547813 - Part 8: Introduce a CookieSettings API to query whether cookies from third-party trackers must be rejected and use it in Gecko; r=baku Differential Revision: https://phabricator.services.mozilla.com/D30117
dom/base/Document.cpp
dom/base/nsGlobalWindowOuter.cpp
dom/security/ReferrerInfo.cpp
dom/workers/RuntimeService.cpp
netwerk/cookie/CookieSettings.cpp
netwerk/cookie/nsCookieService.cpp
netwerk/cookie/nsICookieSettings.idl
netwerk/protocol/http/nsHttpChannel.cpp
toolkit/components/antitracking/AntiTrackingCommon.cpp
--- a/dom/base/Document.cpp
+++ b/dom/base/Document.cpp
@@ -12191,18 +12191,17 @@ void Document::SetDocTreeHadPlayRevoked(
   }
 }
 
 DocumentAutoplayPolicy Document::AutoplayPolicy() const {
   return AutoplayPolicy::IsAllowedToPlay(*this);
 }
 
 void Document::MaybeAllowStorageForOpenerAfterUserInteraction() {
-  if (CookieSettings()->GetCookieBehavior() !=
-      nsICookieService::BEHAVIOR_REJECT_TRACKER) {
+  if (!CookieSettings()->GetRejectThirdPartyTrackers()) {
     return;
   }
 
   // This will probably change for project fission, but currently this document
   // and the opener are on the same process. In the future, we should make this
   // part async.
 
   nsPIDOMWindowInner* inner = GetInnerWindow();
@@ -12729,18 +12728,17 @@ already_AddRefed<mozilla::dom::Promise> 
 
   // Step 2. If the document has a null origin, reject.
   if (NodePrincipal()->GetIsNullPrincipal()) {
     promise->MaybeRejectWithUndefined();
     return promise.forget();
   }
 
   // Only enforce third-party checks when there is a reason to enforce them.
-  if (CookieSettings()->GetCookieBehavior() !=
-      nsICookieService::BEHAVIOR_REJECT_TRACKER) {
+  if (!CookieSettings()->GetRejectThirdPartyTrackers()) {
     // Step 3. If the document's frame is the main frame, resolve.
     if (IsTopLevelContentDocument()) {
       promise->MaybeResolveWithUndefined();
       return promise.forget();
     }
 
     // Step 4. If the sub frame's origin is equal to the main frame's, resolve.
     nsCOMPtr<Document> topLevelDoc = GetTopLevelContentDocument();
@@ -12782,19 +12780,17 @@ already_AddRefed<mozilla::dom::Promise> 
 
   if (nsContentUtils::IsInPrivateBrowsing(this)) {
     // If the document is in PB mode, it doesn't have access to its persistent
     // cookie jar, so reject the promise here.
     promise->MaybeRejectWithUndefined();
     return promise.forget();
   }
 
-  if (CookieSettings()->GetCookieBehavior() ==
-          nsICookieService::BEHAVIOR_REJECT_TRACKER &&
-      inner) {
+  if (CookieSettings()->GetRejectThirdPartyTrackers() && inner) {
     // Only do something special for third-party tracking content.
     if (nsContentUtils::StorageDisabledByAntiTracking(this, nullptr)) {
       // Note: If this has returned true, the top-level document is guaranteed
       // to not be on the Content Blocking allow list.
       DebugOnly<bool> isOnAllowList = false;
       // If we have a parent document, it has to be non-private since we
       // verified earlier that our own document is non-private and a private
       // document can never have a non-private document as its child.
--- a/dom/base/nsGlobalWindowOuter.cpp
+++ b/dom/base/nsGlobalWindowOuter.cpp
@@ -2288,18 +2288,17 @@ nsresult nsGlobalWindowOuter::SetNewDocu
   // If we have a recorded interesting Large-Allocation header status, report it
   // to the newly attached document.
   ReportLargeAllocStatus();
   mLargeAllocStatus = LargeAllocStatus::NONE;
 
   mHasStorageAccess = false;
   nsIURI* uri = aDocument->GetDocumentURI();
   if (newInnerWindow &&
-      aDocument->CookieSettings()->GetCookieBehavior() ==
-          nsICookieService::BEHAVIOR_REJECT_TRACKER &&
+      aDocument->CookieSettings()->GetRejectThirdPartyTrackers() &&
       nsContentUtils::IsThirdPartyWindowOrChannel(newInnerWindow, nullptr,
                                                   uri) &&
       nsContentUtils::IsTrackingResourceWindow(newInnerWindow)) {
     // Grant storage access by default if the first-party storage access
     // permission has been granted already.
     // Don't notify in this case, since we would be notifying the user
     // needlessly.
     mHasStorageAccess = AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(
--- a/dom/security/ReferrerInfo.cpp
+++ b/dom/security/ReferrerInfo.cpp
@@ -13,16 +13,17 @@
 #include "nsIURIFixup.h"
 #include "nsIURL.h"
 #include "nsIURIMutator.h"
 
 #include "nsAlgorithm.h"
 #include "ReferrerInfo.h"
 
 #include "mozilla/AntiTrackingCommon.h"
+#include "mozilla/net/CookieSettings.h"
 #include "mozilla/net/HttpBaseChannel.h"
 
 static mozilla::LazyLogModule gReferrerInfoLog("ReferrerInfo");
 #define LOG(msg) MOZ_LOG(gReferrerInfoLog, mozilla::LogLevel::Debug, msg)
 #define LOG_ENABLED() MOZ_LOG_TEST(gReferrerInfoLog, mozilla::LogLevel::Debug)
 
 using namespace mozilla::net;
 
@@ -115,19 +116,28 @@ bool ReferrerInfo::HideOnionReferrerSour
 }
 
 /* static */
 uint32_t ReferrerInfo::GetDefaultReferrerPolicy(nsIHttpChannel* aChannel,
                                                 nsIURI* aURI,
                                                 bool privateBrowsing) {
   CachePreferrenceValue();
   bool thirdPartyTrackerIsolated = false;
-  if (StaticPrefs::network_cookie_cookieBehavior() ==
-          nsICookieService::BEHAVIOR_REJECT_TRACKER &&
-      aChannel && aURI) {
+  nsCOMPtr<nsILoadInfo> loadInfo;
+  if (aChannel) {
+    loadInfo = aChannel->LoadInfo();
+  }
+  nsCOMPtr<nsICookieSettings> cs;
+  if (loadInfo) {
+    Unused << loadInfo->GetCookieSettings(getter_AddRefs(cs));
+  }
+  if (!cs) {
+    cs = net::CookieSettings::Create();
+  }
+  if (aChannel && aURI && cs->GetRejectThirdPartyTrackers()) {
     uint32_t rejectedReason = 0;
     thirdPartyTrackerIsolated =
         !AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(
             aChannel, aURI, &rejectedReason);
     // Here we intentionally do not notify about the rejection reason, if any
     // in order to avoid this check to have any visible side-effects (e.g. a
     // web console report.)
   }
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -2025,18 +2025,17 @@ void RuntimeService::ResumeWorkersForWin
 }
 
 void RuntimeService::PropagateFirstPartyStorageAccessGranted(
     nsPIDOMWindowInner* aWindow) {
   AssertIsOnMainThread();
   MOZ_ASSERT(aWindow);
   MOZ_ASSERT_IF(
       aWindow->GetExtantDoc(),
-      aWindow->GetExtantDoc()->CookieSettings()->GetCookieBehavior() ==
-          nsICookieService::BEHAVIOR_REJECT_TRACKER);
+      aWindow->GetExtantDoc()->CookieSettings()->GetRejectThirdPartyTrackers());
 
   nsTArray<WorkerPrivate*> workers;
   GetWorkersForWindow(aWindow, workers);
 
   for (uint32_t index = 0; index < workers.Length(); index++) {
     workers[index]->PropagateFirstPartyStorageAccessGranted();
   }
 }
@@ -2426,18 +2425,17 @@ void ResumeWorkersForWindow(nsPIDOMWindo
   }
 }
 
 void PropagateFirstPartyStorageAccessGrantedToWorkers(
     nsPIDOMWindowInner* aWindow) {
   AssertIsOnMainThread();
   MOZ_ASSERT_IF(
       aWindow->GetExtantDoc(),
-      aWindow->GetExtantDoc()->CookieSettings()->GetCookieBehavior() ==
-          nsICookieService::BEHAVIOR_REJECT_TRACKER);
+      aWindow->GetExtantDoc()->CookieSettings()->GetRejectThirdPartyTrackers());
 
   RuntimeService* runtime = RuntimeService::GetService();
   if (runtime) {
     runtime->PropagateFirstPartyStorageAccessGranted(aWindow);
   }
 }
 
 WorkerPrivate* GetWorkerPrivateFromContext(JSContext* aCx) {
--- a/netwerk/cookie/CookieSettings.cpp
+++ b/netwerk/cookie/CookieSettings.cpp
@@ -100,16 +100,25 @@ CookieSettings::~CookieSettings() {
 
 NS_IMETHODIMP
 CookieSettings::GetCookieBehavior(uint32_t* aCookieBehavior) {
   *aCookieBehavior = mCookieBehavior;
   return NS_OK;
 }
 
 NS_IMETHODIMP
+CookieSettings::GetRejectThirdPartyTrackers(bool* aRejectThirdPartyTrackers) {
+  *aRejectThirdPartyTrackers =
+      mCookieBehavior == nsICookieService::BEHAVIOR_REJECT_TRACKER ||
+      mCookieBehavior ==
+          nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 CookieSettings::CookiePermission(nsIPrincipal* aPrincipal,
                                  uint32_t* aCookiePermission) {
   MOZ_ASSERT(NS_IsMainThread());
   NS_ENSURE_ARG_POINTER(aPrincipal);
   NS_ENSURE_ARG_POINTER(aCookiePermission);
 
   *aCookiePermission = nsIPermissionManager::UNKNOWN_ACTION;
 
--- a/netwerk/cookie/nsCookieService.cpp
+++ b/netwerk/cookie/nsCookieService.cpp
@@ -4049,18 +4049,17 @@ CookieStatus nsCookieService::CheckPrefs
         return STATUS_ACCEPTED;
     }
   }
 
   // No cookies allowed if this request comes from a tracker, in a 3rd party
   // context, when anti-tracking protection is enabled and when we don't have
   // access to the first-party cookie jar.
   if (aIsForeign && aIsTrackingResource && !aFirstPartyStorageAccessGranted &&
-      aCookieSettings->GetCookieBehavior() ==
-          nsICookieService::BEHAVIOR_REJECT_TRACKER) {
+      aCookieSettings->GetRejectThirdPartyTrackers()) {
     if (StoragePartitioningEnabled(aInputRejectedReason, aCookieSettings)) {
       MOZ_ASSERT(!aOriginAttrs.mFirstPartyDomain.IsEmpty(),
                  "We must have a StoragePrincipal here!");
       return STATUS_ACCEPTED;
     }
 
     COOKIE_LOGFAILURE(aCookieHeader ? SET_COOKIE : GET_COOKIE, aHostURI,
                       aCookieHeader, "cookies are disabled in trackers");
--- a/netwerk/cookie/nsICookieSettings.idl
+++ b/netwerk/cookie/nsICookieSettings.idl
@@ -17,14 +17,19 @@ interface nsICookieSettings : nsISupport
   /**
    * CookieBehavior at the loading of the document. Any other loadInfo
    * inherits it from its document's loadInfo. If there is not a document
    * involved, cookieBehavior is reject.
    */
   [infallible] readonly attribute unsigned long cookieBehavior;
 
   /**
+   * Whether our cookie behavior mandates rejecting third-party trackers.
+   */
+  [infallible] readonly attribute boolean rejectThirdPartyTrackers;
+
+  /**
    * CookiePermission at the loading of the document for a particular
    * principal. It returns the same cookiePermission also in case it changes
    * during the life-time of the top document.
    */
   unsigned long cookiePermission(in nsIPrincipal aPrincipal);
 };
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -117,16 +117,17 @@
 #include "nsIMultiplexInputStream.h"
 #include "../../cache2/CacheFileUtils.h"
 #include "../../cache2/CacheHashUtils.h"
 #include "nsINetworkLinkService.h"
 #include "mozilla/dom/PromiseNativeHandler.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/ServiceWorkerUtils.h"
 #include "mozilla/net/AsyncUrlChannelClassifier.h"
+#include "mozilla/net/CookieSettings.h"
 #include "mozilla/net/NeckoChannelParams.h"
 #include "mozilla/net/UrlClassifierFeatureFactory.h"
 #include "nsIWebNavigation.h"
 #include "HttpTrafficAnalyzer.h"
 #include "mozilla/dom/CanonicalBrowsingContext.h"
 #include "mozilla/dom/WindowGlobalParent.h"
 
 #ifdef MOZ_TASK_TRACER
@@ -10218,18 +10219,24 @@ nsresult nsHttpChannel::RedirectToInterc
 
     PopRedirectAsyncFunc(&nsHttpChannel::ContinueAsyncRedirectChannelToURI);
   }
 
   return rv;
 }
 
 void nsHttpChannel::ReEvaluateReferrerAfterTrackingStatusIsKnown() {
-  if (StaticPrefs::network_cookie_cookieBehavior() ==
-      nsICookieService::BEHAVIOR_REJECT_TRACKER) {
+  nsCOMPtr<nsICookieSettings> cs;
+  if (mLoadInfo) {
+    Unused << mLoadInfo->GetCookieSettings(getter_AddRefs(cs));
+  }
+  if (!cs) {
+    cs = net::CookieSettings::Create();
+  }
+  if (cs->GetRejectThirdPartyTrackers()) {
     bool isPrivate =
         mLoadInfo && mLoadInfo->GetOriginAttributes().mPrivateBrowsingId > 0;
     // If our referrer has been set before, and our referrer policy is unset
     // (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 (mReferrerInfo) {
       dom::ReferrerInfo* referrerInfo =
--- a/toolkit/components/antitracking/AntiTrackingCommon.cpp
+++ b/toolkit/components/antitracking/AntiTrackingCommon.cpp
@@ -781,22 +781,21 @@ AntiTrackingCommon::AddFirstPartyStorage
   LOG(("Adding a first-party storage exception for %s...",
        PromiseFlatCString(origin).get()));
 
   Document* parentDoc = aParentWindow->GetExtantDoc();
   if (!parentDoc) {
     LOG(("Parent window has no doc"));
     return StorageAccessGrantPromise::CreateAndReject(false, __func__);
   }
-  auto cookieBehavior = parentDoc->CookieSettings()->GetCookieBehavior();
-  if (cookieBehavior != nsICookieService::BEHAVIOR_REJECT_TRACKER) {
+  if (!parentDoc->CookieSettings()->GetRejectThirdPartyTrackers()) {
     LOG(
         ("Disabled by network.cookie.cookieBehavior pref (%d), bailing out "
          "early",
-         cookieBehavior));
+         parentDoc->CookieSettings()->GetCookieBehavior()));
     return StorageAccessGrantPromise::CreateAndResolve(true, __func__);
   }
 
   if (CheckContentBlockingAllowList(aParentWindow)) {
     return StorageAccessGrantPromise::CreateAndResolve(true, __func__);
   }
 
   nsCOMPtr<nsIPrincipal> topLevelStoragePrincipal;
@@ -1612,21 +1611,19 @@ bool AntiTrackingCommon::MaybeIsFirstPar
 
   Document* parentDocument =
       nsGlobalWindowInner::Cast(aFirstPartyWindow)->GetExtantDoc();
   if (NS_WARN_IF(!parentDocument)) {
     LOG(("Failed to get the first party window's document"));
     return false;
   }
 
-  auto cookieBehavior = parentDocument->CookieSettings()->GetCookieBehavior();
-  // TODO: Perhaps we need to do something special for
-  // nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN here?
-  if (cookieBehavior != nsICookieService::BEHAVIOR_REJECT_TRACKER) {
-    LOG(("Disabled by the pref (%d), bail out early", cookieBehavior));
+  if (!parentDocument->CookieSettings()->GetRejectThirdPartyTrackers()) {
+    LOG(("Disabled by the pref (%d), bail out early",
+         parentDocument->CookieSettings()->GetCookieBehavior()));
     return true;
   }
 
   if (CheckContentBlockingAllowList(aFirstPartyWindow)) {
     return true;
   }
 
   if (!nsContentUtils::IsThirdPartyWindowOrChannel(aFirstPartyWindow, nullptr,