Bug 1525245 - Stabilize cookiePolicy/cookiePermission for live documents - part 13 - Cookies, r=Ehsan
☠☠ backed out by 32412e6eb551 ☠ ☠
authorAndrea Marchesini <amarchesini@mozilla.com>
Wed, 06 Mar 2019 17:04:29 +0000
changeset 523528 362f5a8d033c44cbdc0b84d47774b908a2eac5dc
parent 523527 9da3ab33cf679f8a11cbfcd87e93fc5826fe95cd
child 523529 835e5f642a03df66f2240dd174a42fe203e4d372
push id2032
push userffxbld-merge
push dateMon, 13 May 2019 09:36:57 +0000
treeherdermozilla-release@455c1065dcbe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersEhsan
bugs1525245
milestone67.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 1525245 - Stabilize cookiePolicy/cookiePermission for live documents - part 13 - Cookies, r=Ehsan Differential Revision: https://phabricator.services.mozilla.com/D21696
netwerk/cookie/CookieServiceChild.cpp
netwerk/cookie/CookieServiceChild.h
netwerk/cookie/CookieServiceParent.cpp
netwerk/cookie/CookieServiceParent.h
netwerk/cookie/PCookieService.ipdl
netwerk/cookie/moz.build
netwerk/cookie/nsCookieService.cpp
netwerk/cookie/nsCookieService.h
--- a/netwerk/cookie/CookieServiceChild.cpp
+++ b/netwerk/cookie/CookieServiceChild.cpp
@@ -22,25 +22,25 @@
 #include "nsCookiePermission.h"
 #include "nsIEffectiveTLDService.h"
 #include "nsIURI.h"
 #include "nsIPrefService.h"
 #include "nsIPrefBranch.h"
 #include "nsServiceManagerUtils.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/TimeStamp.h"
+#include "ThirdPartyUtil.h"
 
 using namespace mozilla::ipc;
 using mozilla::OriginAttributes;
 
 namespace mozilla {
 namespace net {
 
 // Pref string constants
-static const char kPrefCookieBehavior[] = "network.cookie.cookieBehavior";
 static const char kPrefThirdPartySession[] =
     "network.cookie.thirdparty.sessionOnly";
 static const char kPrefThirdPartyNonsecureSession[] =
     "network.cookie.thirdparty.nonsecureSessionOnly";
 static const char kCookieMoveIntervalSecs[] =
     "network.cookie.move.interval_sec";
 
 static StaticRefPtr<CookieServiceChild> gCookieService;
@@ -54,18 +54,17 @@ already_AddRefed<CookieServiceChild> Coo
 
   return do_AddRef(gCookieService);
 }
 
 NS_IMPL_ISUPPORTS(CookieServiceChild, nsICookieService, nsIObserver,
                   nsITimerCallback, nsISupportsWeakReference)
 
 CookieServiceChild::CookieServiceChild()
-    : mCookieBehavior(nsICookieService::BEHAVIOR_ACCEPT),
-      mThirdPartySession(false),
+    : mThirdPartySession(false),
       mThirdPartyNonsecureSession(false),
       mIPCOpen(false) {
   NS_ASSERTION(IsNeckoChild(), "not a child process");
 
   mozilla::dom::ContentChild *cc =
       static_cast<mozilla::dom::ContentChild *>(gNeckoChild->Manager());
   if (cc->IsShuttingDown()) {
     return;
@@ -76,24 +75,26 @@ CookieServiceChild::CookieServiceChild()
 
   NeckoChild::InitNeckoChild();
 
   // Create a child PCookieService actor.
   gNeckoChild->SendPCookieServiceConstructor(this);
 
   mIPCOpen = true;
 
+  mThirdPartyUtil = ThirdPartyUtil::GetInstance();
+  NS_ASSERTION(mThirdPartyUtil, "couldn't get ThirdPartyUtil service");
+
   mTLDService = do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID);
   NS_ASSERTION(mTLDService, "couldn't get TLDService");
 
   // Init our prefs and observer.
   nsCOMPtr<nsIPrefBranch> prefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID);
   NS_WARNING_ASSERTION(prefBranch, "no prefservice");
   if (prefBranch) {
-    prefBranch->AddObserver(kPrefCookieBehavior, this, true);
     prefBranch->AddObserver(kPrefThirdPartySession, this, true);
     prefBranch->AddObserver(kPrefThirdPartyNonsecureSession, this, true);
     prefBranch->AddObserver(kCookieMoveIntervalSecs, this, true);
     PrefChanged(prefBranch);
   }
 
   nsCOMPtr<nsIObserverService> observerService =
       mozilla::services::GetObserverService();
@@ -143,17 +144,18 @@ void CookieServiceChild::TrackCookieLoad
     return;
   }
 
   bool isForeign = false;
   bool isTrackingResource = false;
   bool firstPartyStorageAccessGranted = false;
   nsCOMPtr<nsIURI> uri;
   aChannel->GetURI(getter_AddRefs(uri));
-  if (RequireThirdPartyCheck()) {
+  nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
+  if (RequireThirdPartyCheck(loadInfo)) {
     mThirdPartyUtil->IsThirdPartyChannel(aChannel, uri, &isForeign);
   }
   nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
   if (httpChannel) {
     isTrackingResource = httpChannel->GetIsTrackingResource();
     // Check first-party storage access even for non-tracking resources, since
     // we will need the result when computing the access rights for the reject
     // foreign cookie behavior mode.
@@ -167,17 +169,16 @@ void CookieServiceChild::TrackCookieLoad
     // since the parent process can't do it for us as it won't have a channel
     // object handy.
     if (!firstPartyStorageAccessGranted) {
       AntiTrackingCommon::NotifyBlockingDecision(
           aChannel, AntiTrackingCommon::BlockingDecision::eBlock,
           rejectedReason);
     }
   }
-  nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
   mozilla::OriginAttributes attrs = loadInfo->GetOriginAttributes();
   URIParams uriParams;
   SerializeURI(uri, uriParams);
   bool isSafeTopLevelNav = NS_IsSafeTopLevelNav(aChannel);
   bool isSameSiteForeign = NS_IsSameSiteForeign(aChannel, uri);
   SendPrepareCookieList(uriParams, isForeign, isTrackingResource,
                         firstPartyStorageAccessGranted, isSafeTopLevelNav,
                         isSameSiteForeign, attrs);
@@ -247,36 +248,25 @@ mozilla::ipc::IPCResult CookieServiceChi
         aCookiesList[i].sameSite());
     RecordDocumentCookie(cookie, aAttrs);
   }
 
   return IPC_OK();
 }
 
 void CookieServiceChild::PrefChanged(nsIPrefBranch *aPrefBranch) {
-  int32_t val;
-  if (NS_SUCCEEDED(aPrefBranch->GetIntPref(kPrefCookieBehavior, &val)))
-    mCookieBehavior = val >= nsICookieService::BEHAVIOR_ACCEPT &&
-                              val <= nsICookieService::BEHAVIOR_LAST
-                          ? val
-                          : nsICookieService::BEHAVIOR_ACCEPT;
-
   bool boolval;
   if (NS_SUCCEEDED(aPrefBranch->GetBoolPref(kPrefThirdPartySession, &boolval)))
     mThirdPartySession = !!boolval;
 
   if (NS_SUCCEEDED(
           aPrefBranch->GetBoolPref(kPrefThirdPartyNonsecureSession, &boolval)))
     mThirdPartyNonsecureSession = boolval;
 
-  if (!mThirdPartyUtil && RequireThirdPartyCheck()) {
-    mThirdPartyUtil = do_GetService(THIRDPARTYUTIL_CONTRACTID);
-    NS_ASSERTION(mThirdPartyUtil, "require ThirdPartyUtil service");
-  }
-
+  int32_t val;
   if (NS_SUCCEEDED(aPrefBranch->GetIntPref(kCookieMoveIntervalSecs, &val))) {
     gMoveCookiesIntervalSeconds = clamped<uint32_t>(val, 0, 3600);
     if (gMoveCookiesIntervalSeconds && !mCookieTimer) {
       NS_NewTimerWithCallback(getter_AddRefs(mCookieTimer), this,
                               gMoveCookiesIntervalSeconds * 1000,
                               nsITimer::TYPE_REPEATING_SLACK_LOW_PRIORITY);
     }
     if (!gMoveCookiesIntervalSeconds && mCookieTimer) {
@@ -287,49 +277,55 @@ void CookieServiceChild::PrefChanged(nsI
       mCookieTimer->SetDelay(gMoveCookiesIntervalSeconds * 1000);
     }
   }
 }
 
 void CookieServiceChild::GetCookieStringFromCookieHashTable(
     nsIURI *aHostURI, bool aIsForeign, bool aIsTrackingResource,
     bool aFirstPartyStorageAccessGranted, bool aIsSafeTopLevelNav,
-    bool aIsSameSiteForeign, const OriginAttributes &aOriginAttrs,
-    nsCString &aCookieString) {
+    bool aIsSameSiteForeign, nsIChannel *aChannel, nsCString &aCookieString) {
   nsCOMPtr<nsIEffectiveTLDService> TLDService =
       do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID);
   NS_ASSERTION(TLDService, "Can't get TLDService");
   bool requireHostMatch;
   nsAutoCString baseDomain;
+
+  nsCOMPtr<nsILoadInfo> loadInfo;
+  mozilla::OriginAttributes attrs;
+  if (aChannel) {
+    loadInfo = aChannel->LoadInfo();
+    attrs = loadInfo->GetOriginAttributes();
+  }
+
   nsCookieService::GetBaseDomain(TLDService, aHostURI, baseDomain,
                                  requireHostMatch);
-  nsCookieKey key(baseDomain, aOriginAttrs);
+  nsCookieKey key(baseDomain, attrs);
   CookiesList *cookiesList = nullptr;
   mCookiesMap.Get(key, &cookiesList);
 
   if (!cookiesList) {
     return;
   }
 
   nsAutoCString hostFromURI, pathFromURI;
   bool isSecure;
   aHostURI->GetAsciiHost(hostFromURI);
   aHostURI->GetPathQueryRef(pathFromURI);
   aHostURI->SchemeIs("https", &isSecure);
   int64_t currentTimeInUsec = PR_Now();
   int64_t currentTime = currentTimeInUsec / PR_USEC_PER_SEC;
 
-  nsCOMPtr<nsICookiePermission> permissionService =
-      nsCookiePermission::GetOrCreate();
+  nsCOMPtr<nsICookieSettings> cookieSettings =
+      nsCookieService::GetCookieSettings(aChannel);
+
   CookieStatus cookieStatus = nsCookieService::CheckPrefs(
-      permissionService, mCookieBehavior, mThirdPartySession,
-      mThirdPartyNonsecureSession, aHostURI, aIsForeign, aIsTrackingResource,
-      aFirstPartyStorageAccessGranted, nullptr,
-      CountCookiesFromHashTable(baseDomain, aOriginAttrs), aOriginAttrs,
-      nullptr);
+      cookieSettings, mThirdPartySession, mThirdPartyNonsecureSession, aHostURI,
+      aIsForeign, aIsTrackingResource, aFirstPartyStorageAccessGranted, nullptr,
+      CountCookiesFromHashTable(baseDomain, attrs), attrs, nullptr);
 
   if (cookieStatus != STATUS_ACCEPTED &&
       cookieStatus != STATUS_ACCEPT_SESSION) {
     return;
   }
 
   cookiesList->Sort(CompareCookiesForSending());
   for (uint32_t i = 0; i < cookiesList->Length(); i++) {
@@ -404,20 +400,27 @@ void CookieServiceChild::SetCookieIntern
       aCookieAttributes.path, aCookieAttributes.expiryTime, currentTimeInUsec,
       nsCookie::GenerateUniqueCreationTime(currentTimeInUsec),
       aCookieAttributes.isSession, aCookieAttributes.isSecure,
       aCookieAttributes.isHttpOnly, aAttrs, aCookieAttributes.sameSite);
 
   RecordDocumentCookie(cookie, aAttrs);
 }
 
-bool CookieServiceChild::RequireThirdPartyCheck() {
-  return mCookieBehavior == nsICookieService::BEHAVIOR_REJECT_FOREIGN ||
-         mCookieBehavior == nsICookieService::BEHAVIOR_LIMIT_FOREIGN ||
-         mCookieBehavior == nsICookieService::BEHAVIOR_REJECT_TRACKER ||
+bool CookieServiceChild::RequireThirdPartyCheck(nsILoadInfo *aLoadInfo) {
+  nsCOMPtr<nsICookieSettings> cookieSettings;
+  nsresult rv = aLoadInfo->GetCookieSettings(getter_AddRefs(cookieSettings));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return false;
+  }
+
+  uint32_t cookieBehavior = cookieSettings->GetCookieBehavior();
+  return cookieBehavior == nsICookieService::BEHAVIOR_REJECT_FOREIGN ||
+         cookieBehavior == nsICookieService::BEHAVIOR_LIMIT_FOREIGN ||
+         cookieBehavior == nsICookieService::BEHAVIOR_REJECT_TRACKER ||
          mThirdPartySession || mThirdPartyNonsecureSession;
 }
 
 void CookieServiceChild::RecordDocumentCookie(nsCookie *aCookie,
                                               const OriginAttributes &aAttrs) {
   nsAutoCString baseDomain;
   nsCookieService::GetBaseDomainFromHost(mTLDService, aCookie->Host(),
                                          baseDomain);
@@ -465,27 +468,22 @@ nsresult CookieServiceChild::GetCookieSt
   *aCookieString = nullptr;
 
   // Fast past: don't bother sending IPC messages about nullprincipal'd
   // documents.
   nsAutoCString scheme;
   aHostURI->GetScheme(scheme);
   if (scheme.EqualsLiteral("moz-nullprincipal")) return NS_OK;
 
-  nsCOMPtr<nsILoadInfo> loadInfo;
-  mozilla::OriginAttributes attrs;
-  if (aChannel) {
-    loadInfo = aChannel->LoadInfo();
-    attrs = loadInfo->GetOriginAttributes();
-  }
-
   // Asynchronously call the parent.
   bool isForeign = true;
-  if (RequireThirdPartyCheck())
+  nsCOMPtr<nsILoadInfo> loadInfo = aChannel ? aChannel->LoadInfo() : nullptr;
+  if (RequireThirdPartyCheck(loadInfo)) {
     mThirdPartyUtil->IsThirdPartyChannel(aChannel, aHostURI, &isForeign);
+  }
 
   bool isTrackingResource = false;
   bool firstPartyStorageAccessGranted = false;
   nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
   if (httpChannel) {
     isTrackingResource = httpChannel->GetIsTrackingResource();
     // Check first-party storage access even for non-tracking resources, since
     // we will need the result when computing the access rights for the reject
@@ -497,17 +495,17 @@ nsresult CookieServiceChild::GetCookieSt
   }
 
   bool isSafeTopLevelNav = NS_IsSafeTopLevelNav(aChannel);
   bool isSameSiteForeign = NS_IsSameSiteForeign(aChannel, aHostURI);
 
   nsAutoCString result;
   GetCookieStringFromCookieHashTable(
       aHostURI, isForeign, isTrackingResource, firstPartyStorageAccessGranted,
-      isSafeTopLevelNav, isSameSiteForeign, attrs, result);
+      isSafeTopLevelNav, isSameSiteForeign, aChannel, result);
 
   if (!result.IsEmpty()) *aCookieString = ToNewCString(result);
 
   return NS_OK;
 }
 
 nsresult CookieServiceChild::SetCookieStringInternal(nsIURI *aHostURI,
                                                      nsIChannel *aChannel,
@@ -520,18 +518,20 @@ nsresult CookieServiceChild::SetCookieSt
   // Fast past: don't bother sending IPC messages about nullprincipal'd
   // documents.
   nsAutoCString scheme;
   aHostURI->GetScheme(scheme);
   if (scheme.EqualsLiteral("moz-nullprincipal")) return NS_OK;
 
   // Determine whether the request is foreign. Failure is acceptable.
   bool isForeign = true;
-  if (RequireThirdPartyCheck())
+  nsCOMPtr<nsILoadInfo> loadInfo = aChannel ? aChannel->LoadInfo() : nullptr;
+  if (RequireThirdPartyCheck(loadInfo)) {
     mThirdPartyUtil->IsThirdPartyChannel(aChannel, aHostURI, &isForeign);
+  }
 
   bool isTrackingResource = false;
   bool firstPartyStorageAccessGranted = false;
   nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
   if (httpChannel) {
     isTrackingResource = httpChannel->GetIsTrackingResource();
     // Check first-party storage access even for non-tracking resources, since
     // we will need the result when computing the access rights for the reject
@@ -551,42 +551,46 @@ nsresult CookieServiceChild::SetCookieSt
 
   Maybe<URIParams> channelURIParams;
   mozilla::OriginAttributes attrs;
   if (aChannel) {
     nsCOMPtr<nsIURI> channelURI;
     aChannel->GetURI(getter_AddRefs(channelURI));
     SerializeURI(channelURI, channelURIParams);
 
-    nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
+    MOZ_ASSERT(loadInfo);
     attrs = loadInfo->GetOriginAttributes();
   } else {
     SerializeURI(nullptr, channelURIParams);
   }
 
+  Maybe<LoadInfoArgs> optionalLoadInfoArgs;
+  LoadInfoToLoadInfoArgs(loadInfo, &optionalLoadInfoArgs);
+
   // Asynchronously call the parent.
   if (mIPCOpen) {
-    SendSetCookieString(hostURIParams, channelURIParams, isForeign,
-                        isTrackingResource, firstPartyStorageAccessGranted,
-                        cookieString, stringServerTime, attrs, aFromHttp);
+    SendSetCookieString(hostURIParams, channelURIParams, optionalLoadInfoArgs,
+                        isForeign, isTrackingResource,
+                        firstPartyStorageAccessGranted, cookieString,
+                        stringServerTime, aFromHttp);
   }
 
   bool requireHostMatch;
   nsCString baseDomain;
   nsCookieService::GetBaseDomain(mTLDService, aHostURI, baseDomain,
                                  requireHostMatch);
 
-  nsCOMPtr<nsICookiePermission> permissionService =
-      nsCookiePermission::GetOrCreate();
+  nsCOMPtr<nsICookieSettings> cookieSettings =
+      nsCookieService::GetCookieSettings(aChannel);
 
   CookieStatus cookieStatus = nsCookieService::CheckPrefs(
-      permissionService, mCookieBehavior, mThirdPartySession,
-      mThirdPartyNonsecureSession, aHostURI, isForeign, isTrackingResource,
-      firstPartyStorageAccessGranted, aCookieString,
-      CountCookiesFromHashTable(baseDomain, attrs), attrs, nullptr);
+      cookieSettings, mThirdPartySession, mThirdPartyNonsecureSession, aHostURI,
+      isForeign, isTrackingResource, firstPartyStorageAccessGranted,
+      aCookieString, CountCookiesFromHashTable(baseDomain, attrs), attrs,
+      nullptr);
 
   if (cookieStatus != STATUS_ACCEPTED &&
       cookieStatus != STATUS_ACCEPT_SESSION) {
     return NS_OK;
   }
 
   nsCookieKey key(baseDomain, attrs);
   CookiesList *cookies = mCookiesMap.Get(key);
@@ -615,16 +619,18 @@ nsresult CookieServiceChild::SetCookieSt
             cookie->IsHttpOnly()) {
           // Can't overwrite an httponly cookie from a script context.
           canSetCookie = false;
         }
       }
     }
 
     if (canSetCookie) {
+      nsCOMPtr<nsICookiePermission> permissionService =
+          nsCookiePermission::GetOrCreate();
       SetCookieInternal(cookieAttributes, attrs, aChannel, aFromHttp,
                         permissionService);
     }
 
     // document.cookie can only set one cookie at a time.
     if (!aFromHttp) {
       break;
     }
--- a/netwerk/cookie/CookieServiceChild.h
+++ b/netwerk/cookie/CookieServiceChild.h
@@ -14,16 +14,17 @@
 #include "nsIPrefBranch.h"
 #include "mozIThirdPartyUtil.h"
 #include "nsWeakReference.h"
 #include "nsThreadUtils.h"
 
 class nsCookie;
 class nsICookiePermission;
 class nsIEffectiveTLDService;
+class nsILoadInfo;
 
 struct nsCookieAttributes;
 
 namespace mozilla {
 namespace net {
 class CookieStruct;
 
 class CookieServiceChild : public PCookieServiceChild,
@@ -55,23 +56,20 @@ class CookieServiceChild : public PCooki
   void SerializeURIs(nsIURI *aHostURI, nsIChannel *aChannel,
                      nsCString &aHostSpec, nsCString &aHostCharset,
                      nsCString &aOriginatingSpec,
                      nsCString &aOriginatingCharset);
 
   nsresult GetCookieStringInternal(nsIURI *aHostURI, nsIChannel *aChannel,
                                    char **aCookieString);
 
-  void GetCookieStringFromCookieHashTable(nsIURI *aHostURI, bool aIsForeign,
-                                          bool aIsTrackingResource,
-                                          bool aFirstPartyStorageAccessGranted,
-                                          bool aIsSafeTopLevelNav,
-                                          bool aIsSameSiteForeign,
-                                          const OriginAttributes &aAttrs,
-                                          nsCString &aCookieString);
+  void GetCookieStringFromCookieHashTable(
+      nsIURI *aHostURI, bool aIsForeign, bool aIsTrackingResource,
+      bool aFirstPartyStorageAccessGranted, bool aIsSafeTopLevelNav,
+      bool aIsSameSiteForeign, nsIChannel *aChannel, nsCString &aCookieString);
 
   nsresult SetCookieStringInternal(nsIURI *aHostURI, nsIChannel *aChannel,
                                    const char *aCookieString,
                                    const char *aServerTime, bool aFromHttp);
 
   void RecordDocumentCookie(nsCookie *aCookie, const OriginAttributes &aAttrs);
 
   void SetCookieInternal(nsCookieAttributes &aCookieAttributes,
@@ -79,17 +77,17 @@ class CookieServiceChild : public PCooki
                          nsIChannel *aChannel, bool aFromHttp,
                          nsICookiePermission *aPermissionService);
 
   uint32_t CountCookiesFromHashTable(const nsCString &aBaseDomain,
                                      const OriginAttributes &aOriginAttrs);
 
   void PrefChanged(nsIPrefBranch *aPrefBranch);
 
-  bool RequireThirdPartyCheck();
+  bool RequireThirdPartyCheck(nsILoadInfo *aLoadInfo);
 
   mozilla::ipc::IPCResult RecvTrackCookiesLoad(
       nsTArray<CookieStruct> &&aCookiesList, const OriginAttributes &aAttrs);
 
   mozilla::ipc::IPCResult RecvRemoveAll();
 
   mozilla::ipc::IPCResult RecvRemoveBatchDeletedCookies(
       nsTArray<CookieStruct> &&aCookiesList,
@@ -102,17 +100,16 @@ class CookieServiceChild : public PCooki
                                         const OriginAttributes &aAttrs);
 
   virtual void ActorDestroy(ActorDestroyReason aWhy) override;
 
   CookiesMap mCookiesMap;
   nsCOMPtr<nsITimer> mCookieTimer;
   nsCOMPtr<mozIThirdPartyUtil> mThirdPartyUtil;
   nsCOMPtr<nsIEffectiveTLDService> mTLDService;
-  uint8_t mCookieBehavior;
   bool mThirdPartySession;
   bool mThirdPartyNonsecureSession;
   bool mIPCOpen;
 };
 
 }  // namespace net
 }  // namespace mozilla
 
--- a/netwerk/cookie/CookieServiceParent.cpp
+++ b/netwerk/cookie/CookieServiceParent.cpp
@@ -23,38 +23,27 @@ using mozilla::BasePrincipal;
 using mozilla::OriginAttributes;
 using mozilla::dom::PContentParent;
 using mozilla::net::NeckoParent;
 
 namespace {
 
 // Ignore failures from this function, as they only affect whether we do or
 // don't show a dialog box in private browsing mode if the user sets a pref.
-void CreateDummyChannel(nsIURI *aHostURI, nsIURI *aChannelURI,
-                        OriginAttributes &aAttrs, nsIChannel **aChannel) {
-  nsCOMPtr<nsIPrincipal> principal =
-      BasePrincipal::CreateCodebasePrincipal(aHostURI, aAttrs);
-  if (!principal) {
-    return;
+nsresult CreateDummyChannel(nsIURI *aHostURI, nsILoadInfo *aLoadInfo,
+                            nsIChannel **aChannel) {
+  nsCOMPtr<nsIChannel> dummyChannel;
+  nsresult rv =
+      NS_NewChannelInternal(getter_AddRefs(dummyChannel), aHostURI, aLoadInfo);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
   }
 
-  // The following channel is never openend, so it does not matter what
-  // securityFlags we pass; let's follow the principle of least privilege.
-  nsCOMPtr<nsIChannel> dummyChannel;
-  NS_NewChannel(getter_AddRefs(dummyChannel), aChannelURI, principal,
-                nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_IS_BLOCKED,
-                nsIContentPolicy::TYPE_INVALID);
-  nsCOMPtr<nsIPrivateBrowsingChannel> pbChannel =
-      do_QueryInterface(dummyChannel);
-  if (!pbChannel) {
-    return;
-  }
-
-  pbChannel->SetPrivate(aAttrs.mPrivateBrowsingId > 0);
   dummyChannel.forget(aChannel);
+  return NS_OK;
 }
 
 }  // namespace
 
 namespace mozilla {
 namespace net {
 
 CookieServiceParent::CookieServiceParent() {
@@ -211,48 +200,60 @@ mozilla::ipc::IPCResult CookieServicePar
 
 void CookieServiceParent::ActorDestroy(ActorDestroyReason aWhy) {
   // Nothing needed here. Called right before destructor since this is a
   // non-refcounted class.
 }
 
 mozilla::ipc::IPCResult CookieServiceParent::RecvSetCookieString(
     const URIParams &aHost, const Maybe<URIParams> &aChannelURI,
-    const bool &aIsForeign, const bool &aIsTrackingResource,
+    const Maybe<LoadInfoArgs> &aLoadInfoArgs, const bool &aIsForeign,
+    const bool &aIsTrackingResource,
     const bool &aFirstPartyStorageAccessGranted, const nsCString &aCookieString,
-    const nsCString &aServerTime, const OriginAttributes &aAttrs,
-    const bool &aFromHttp) {
+    const nsCString &aServerTime, const bool &aFromHttp) {
   if (!mCookieService) return IPC_OK();
 
   // Deserialize URI. Having a host URI is mandatory and should always be
   // provided by the child; thus we consider failure fatal.
   nsCOMPtr<nsIURI> hostURI = DeserializeURI(aHost);
   if (!hostURI) return IPC_FAIL_NO_REASON(this);
 
   nsCOMPtr<nsIURI> channelURI = DeserializeURI(aChannelURI);
 
+  nsCOMPtr<nsILoadInfo> loadInfo;
+  Unused << NS_WARN_IF(NS_FAILED(
+      LoadInfoArgsToLoadInfo(aLoadInfoArgs, getter_AddRefs(loadInfo))));
+
   // This is a gross hack. We've already computed everything we need to know
   // for whether to set this cookie or not, but we need to communicate all of
   // this information through to nsICookiePermission, which indirectly
   // computes the information from the channel. We only care about the
   // aIsPrivate argument as nsCookieService::SetCookieStringInternal deals
   // with aIsForeign before we have to worry about nsCookiePermission trying
   // to use the channel to inspect it.
   nsCOMPtr<nsIChannel> dummyChannel;
-  CreateDummyChannel(hostURI, channelURI,
-                     const_cast<OriginAttributes &>(aAttrs),
-                     getter_AddRefs(dummyChannel));
+  nsresult rv =
+      CreateDummyChannel(channelURI, loadInfo, getter_AddRefs(dummyChannel));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    // No reason to kill the content process.
+    return IPC_OK();
+  }
 
   // NB: dummyChannel could be null if something failed in CreateDummyChannel.
   nsDependentCString cookieString(aCookieString, 0);
 
+  OriginAttributes attrs;
+  if (loadInfo) {
+    attrs = loadInfo->GetOriginAttributes();
+  }
+
   // We set this to true while processing this cookie update, to make sure
   // we don't send it back to the same content process.
   mProcessingCookie = true;
   mCookieService->SetCookieStringInternal(
       hostURI, aIsForeign, aIsTrackingResource, aFirstPartyStorageAccessGranted,
-      cookieString, aServerTime, aFromHttp, aAttrs, dummyChannel);
+      cookieString, aServerTime, aFromHttp, attrs, dummyChannel);
   mProcessingCookie = false;
   return IPC_OK();
 }
 
 }  // namespace net
 }  // namespace mozilla
--- a/netwerk/cookie/CookieServiceParent.h
+++ b/netwerk/cookie/CookieServiceParent.h
@@ -41,20 +41,22 @@ class CookieServiceParent : public PCook
   // processes, not the one they originated from.
   bool ProcessingCookie() { return mProcessingCookie; }
 
  protected:
   virtual void ActorDestroy(ActorDestroyReason aWhy) override;
 
   mozilla::ipc::IPCResult RecvSetCookieString(
       const URIParams &aHost, const Maybe<URIParams> &aChannelURI,
-      const bool &aIsForeign, const bool &aIsTrackingResource,
+      const Maybe<LoadInfoArgs> &aLoadInfoArgs, const bool &aIsForeign,
+      const bool &aIsTrackingResource,
       const bool &aFirstPartyStorageAccessGranted,
       const nsCString &aCookieString, const nsCString &aServerTime,
-      const OriginAttributes &aAttrs, const bool &aFromHttp);
+      const bool &aFromHttp);
+
   mozilla::ipc::IPCResult RecvPrepareCookieList(
       const URIParams &aHost, const bool &aIsForeign,
       const bool &aIsTackingResource,
       const bool &aFirstPartyStorageAccessGranted,
       const bool &aIsSafeTopLevelNav, const bool &aIsSameSiteForeign,
       const OriginAttributes &aAttrs);
 
   void SerialializeCookieList(const nsTArray<nsCookie *> &aFoundCookieList,
--- a/netwerk/cookie/PCookieService.ipdl
+++ b/netwerk/cookie/PCookieService.ipdl
@@ -35,16 +35,18 @@ parent:
 
   /*
    * Set a cookie string.
    *
    * @param host
    *        Same as the 'aURI' argument to nsICookieService.setCookieString.
    * @param channelURI
    *        The URI of the request.
+   * @param loadInfoArgs
+   *        The optional serialization of nsILoadInfo.
    * @param isForeign
    *        True if the the request is third party, for purposes of allowing
    *        access to cookies. This should be obtained from
    *        mozIThirdPartyUtil.isThirdPartyChannel. Third party requests may be
    *        rejected depending on user preferences; if those checks are
    *        disabled, this parameter is ignored.
    * @param isTrackingResource
    *        True if the request has been marked as tracking.
@@ -57,32 +59,29 @@ parent:
    * @param serverTime
    *        Same as the 'aServerTime' argument to
    *        nsICookieService.setCookieStringFromHttp. If the string is empty or
    *        null (e.g. for non-HTTP requests), the current local time is used.
    * @param fromHttp
    *        Whether the result is for an HTTP request header. This should be
    *        true for nsICookieService.setCookieStringFromHttp calls, false
    *        otherwise.
-   * @param attrs
-   *        The origin attributes from the HTTP channel or document that the
-   *        cookie is being set on.
    *
    * @see nsICookieService.setCookieString
    * @see nsICookieService.setCookieStringFromHttp
    * @see mozIThirdPartyUtil.isThirdPartyChannel
    */
   nested(inside_cpow) async SetCookieString(URIParams host,
                                             URIParams? channelURI,
+                                            LoadInfoArgs? loadInfoArgs,
                                             bool isForeign,
                                             bool isTrackingResource,
                                             bool firstPartyStorageAccessGranted,
                                             nsCString cookieString,
                                             nsCString serverTime,
-                                            OriginAttributes attrs,
                                             bool aFromHttp);
 
   async PrepareCookieList(URIParams host,
                           bool isForeign,
                           bool isTrackingResource,
                           bool firstPartyStorageAccessGranted,
                           bool isSafeTopLevelNav,
                           bool isSameSiteForeign,
--- a/netwerk/cookie/moz.build
+++ b/netwerk/cookie/moz.build
@@ -32,16 +32,17 @@ if CONFIG['NECKO_COOKIES']:
         'CookieSettings.cpp',
         'nsCookie.cpp',
     ]
     # nsCookieService.cpp can't be unified because of symbol conflicts
     SOURCES += [
         'nsCookieService.cpp',
     ]
     LOCAL_INCLUDES += [
+        '/dom/base',
         '/extensions/cookie',
         '/intl/uconv',
     ]
 
     XPCSHELL_TESTS_MANIFESTS += [
         'test/unit/xpcshell.ini',
     ]
 
--- a/netwerk/cookie/nsCookieService.cpp
+++ b/netwerk/cookie/nsCookieService.cpp
@@ -7,16 +7,17 @@
 #include "mozilla/AntiTrackingCommon.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/Likely.h"
 #include "mozilla/Printf.h"
 #include "mozilla/Unused.h"
 
+#include "mozilla/net/CookieSettings.h"
 #include "mozilla/net/CookieServiceChild.h"
 #include "mozilla/net/NeckoCommon.h"
 
 #include "nsCookieService.h"
 #include "nsContentUtils.h"
 #include "nsIServiceManager.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIWebProgressListener.h"
@@ -120,17 +121,16 @@ static const int64_t kCookiePurgeAge =
 // network.cookie.maxNumber and network.cookie.maxPerHost prefs respectively.
 static const uint32_t kMaxNumberOfCookies = 3000;
 static const uint32_t kMaxCookiesPerHost = 180;
 static const uint32_t kCookieQuotaPerHost = 150;
 static const uint32_t kMaxBytesPerCookie = 4096;
 static const uint32_t kMaxBytesPerPath = 1024;
 
 // pref string constants
-static const char kPrefCookieBehavior[] = "network.cookie.cookieBehavior";
 static const char kPrefMaxNumberOfCookies[] = "network.cookie.maxNumber";
 static const char kPrefMaxCookiesPerHost[] = "network.cookie.maxPerHost";
 static const char kPrefCookieQuotaPerHost[] = "network.cookie.quotaPerHost";
 static const char kPrefCookiePurgeAge[] = "network.cookie.purgeAge";
 static const char kPrefThirdPartySession[] =
     "network.cookie.thirdparty.sessionOnly";
 static const char kPrefThirdPartyNonsecureSession[] =
     "network.cookie.thirdparty.nonsecureSessionOnly";
@@ -581,17 +581,16 @@ void nsCookieService::AppClearDataObserv
  * public methods
  ******************************************************************************/
 
 NS_IMPL_ISUPPORTS(nsCookieService, nsICookieService, nsICookieManager,
                   nsIObserver, nsISupportsWeakReference, nsIMemoryReporter)
 
 nsCookieService::nsCookieService()
     : mDBState(nullptr),
-      mCookieBehavior(nsICookieService::BEHAVIOR_ACCEPT),
       mThirdPartySession(false),
       mThirdPartyNonsecureSession(false),
       mMaxNumberOfCookies(kMaxNumberOfCookies),
       mMaxCookiesPerHost(kMaxCookiesPerHost),
       mCookieQuotaPerHost(kCookieQuotaPerHost),
       mCookiePurgeAge(kCookiePurgeAge),
       mThread(nullptr),
       mMonitor("CookieThread"),
@@ -607,17 +606,16 @@ nsresult nsCookieService::Init() {
   NS_ENSURE_SUCCESS(rv, rv);
 
   mThirdPartyUtil = do_GetService(THIRDPARTYUTIL_CONTRACTID);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // init our pref and observer
   nsCOMPtr<nsIPrefBranch> prefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID);
   if (prefBranch) {
-    prefBranch->AddObserver(kPrefCookieBehavior, this, true);
     prefBranch->AddObserver(kPrefMaxNumberOfCookies, this, true);
     prefBranch->AddObserver(kPrefMaxCookiesPerHost, this, true);
     prefBranch->AddObserver(kPrefCookiePurgeAge, this, true);
     prefBranch->AddObserver(kPrefThirdPartySession, this, true);
     prefBranch->AddObserver(kPrefThirdPartyNonsecureSession, this, true);
     PrefChanged(prefBranch);
   }
 
@@ -2000,16 +1998,34 @@ nsresult nsCookieService::GetCookieStrin
   nsAutoCString result;
   GetCookieStringInternal(aHostURI, aChannel, isForeign, isTrackingResource,
                           firstPartyStorageAccessGranted, isSafeTopLevelNav,
                           isSameSiteForeign, aHttpBound, attrs, result);
   *aCookie = result.IsEmpty() ? nullptr : ToNewCString(result);
   return NS_OK;
 }
 
+// static
+already_AddRefed<nsICookieSettings> nsCookieService::GetCookieSettings(
+    nsIChannel *aChannel) {
+  nsCOMPtr<nsICookieSettings> cookieSettings;
+  if (aChannel) {
+    nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
+    nsresult rv = loadInfo->GetCookieSettings(getter_AddRefs(cookieSettings));
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      cookieSettings = CookieSettings::CreateBlockingAll();
+    }
+  } else {
+    cookieSettings = CookieSettings::Create();
+  }
+
+  MOZ_ASSERT(cookieSettings);
+  return cookieSettings.forget();
+}
+
 NS_IMETHODIMP
 nsCookieService::SetCookieString(nsIURI *aHostURI, nsIPrompt *aPrompt,
                                  const char *aCookieHeader,
                                  nsIChannel *aChannel) {
   // The aPrompt argument is deprecated and unused.  Avoid introducing new
   // code that uses this argument by warning if the value is non-null.
   MOZ_ASSERT(!aPrompt);
   if (aPrompt) {
@@ -2133,28 +2149,28 @@ void nsCookieService::SetCookieStringInt
       GetBaseDomain(mTLDService, aHostURI, baseDomain, requireHostMatch);
   if (NS_FAILED(rv)) {
     COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, aCookieHeader,
                       "couldn't get base domain from URI");
     return;
   }
 
   nsCookieKey key(baseDomain, aOriginAttrs);
+  nsCOMPtr<nsICookieSettings> cookieSettings = GetCookieSettings(aChannel);
 
   // check default prefs
   uint32_t priorCookieCount = 0;
   uint32_t rejectedReason = 0;
   nsAutoCString hostFromURI;
   aHostURI->GetHost(hostFromURI);
   CountCookiesFromHost(hostFromURI, &priorCookieCount);
   CookieStatus cookieStatus = CheckPrefs(
-      mPermissionService, mCookieBehavior, mThirdPartySession,
-      mThirdPartyNonsecureSession, aHostURI, aIsForeign, aIsTrackingResource,
-      aFirstPartyStorageAccessGranted, aCookieHeader.get(), priorCookieCount,
-      aOriginAttrs, &rejectedReason);
+      cookieSettings, mThirdPartySession, mThirdPartyNonsecureSession, aHostURI,
+      aIsForeign, aIsTrackingResource, aFirstPartyStorageAccessGranted,
+      aCookieHeader.get(), priorCookieCount, aOriginAttrs, &rejectedReason);
 
   MOZ_ASSERT_IF(rejectedReason, cookieStatus == STATUS_REJECTED);
 
   // fire a notification if third party or if cookie was rejected
   // (but not if there was an error)
   switch (cookieStatus) {
     case STATUS_REJECTED:
       NotifyRejected(aHostURI, aChannel, rejectedReason, OPERATION_WRITE);
@@ -2355,20 +2371,16 @@ nsCookieService::RunInTransaction(nsICoo
 
 /******************************************************************************
  * nsCookieService:
  * pref observer impl
  ******************************************************************************/
 
 void nsCookieService::PrefChanged(nsIPrefBranch *aPrefBranch) {
   int32_t val;
-  if (NS_SUCCEEDED(aPrefBranch->GetIntPref(kPrefCookieBehavior, &val)))
-    mCookieBehavior =
-        (uint8_t)LIMIT(val, 0, nsICookieService::BEHAVIOR_LAST, 0);
-
   if (NS_SUCCEEDED(aPrefBranch->GetIntPref(kPrefMaxNumberOfCookies, &val)))
     mMaxNumberOfCookies = (uint16_t)LIMIT(val, 1, 0xFFFF, kMaxNumberOfCookies);
 
   if (NS_SUCCEEDED(aPrefBranch->GetIntPref(kPrefCookieQuotaPerHost, &val))) {
     mCookieQuotaPerHost =
         (uint16_t)LIMIT(val, 1, mMaxCookiesPerHost - 1, kCookieQuotaPerHost);
   }
 
@@ -3033,25 +3045,26 @@ void nsCookieService::GetCookiesForURI(
   if (NS_SUCCEEDED(rv)) rv = aHostURI->GetAsciiHost(hostFromURI);
   if (NS_SUCCEEDED(rv)) rv = aHostURI->GetPathQueryRef(pathFromURI);
   if (NS_FAILED(rv)) {
     COOKIE_LOGFAILURE(GET_COOKIE, aHostURI, nullptr,
                       "invalid host/path from URI");
     return;
   }
 
+  nsCOMPtr<nsICookieSettings> cookieSettings = GetCookieSettings(aChannel);
+
   // check default prefs
   uint32_t rejectedReason = 0;
   uint32_t priorCookieCount = 0;
   CountCookiesFromHost(hostFromURI, &priorCookieCount);
-  CookieStatus cookieStatus =
-      CheckPrefs(mPermissionService, mCookieBehavior, mThirdPartySession,
-                 mThirdPartyNonsecureSession, aHostURI, aIsForeign,
-                 aIsTrackingResource, aFirstPartyStorageAccessGranted, nullptr,
-                 priorCookieCount, aOriginAttrs, &rejectedReason);
+  CookieStatus cookieStatus = CheckPrefs(
+      cookieSettings, mThirdPartySession, mThirdPartyNonsecureSession, aHostURI,
+      aIsForeign, aIsTrackingResource, aFirstPartyStorageAccessGranted, nullptr,
+      priorCookieCount, aOriginAttrs, &rejectedReason);
 
   MOZ_ASSERT_IF(rejectedReason, cookieStatus == STATUS_REJECTED);
 
   // for GetCookie(), we only fire acceptance/rejection notifications
   // (but not if there was an error)
   switch (cookieStatus) {
     case STATUS_REJECTED:
       NotifyRejected(aHostURI, aChannel, rejectedReason, OPERATION_READ);
@@ -3964,22 +3977,21 @@ nsresult nsCookieService::NormalizeHost(
 static inline bool IsSubdomainOf(const nsCString &a, const nsCString &b) {
   if (a == b) return true;
   if (a.Length() > b.Length())
     return a[a.Length() - b.Length() - 1] == '.' && StringEndsWith(a, b);
   return false;
 }
 
 CookieStatus nsCookieService::CheckPrefs(
-    nsICookiePermission *aPermissionService, uint8_t aCookieBehavior,
-    bool aThirdPartySession, bool aThirdPartyNonsecureSession, nsIURI *aHostURI,
-    bool aIsForeign, bool aIsTrackingResource,
-    bool aFirstPartyStorageAccessGranted, const char *aCookieHeader,
-    const int aNumOfCookies, const OriginAttributes &aOriginAttrs,
-    uint32_t *aRejectedReason) {
+    nsICookieSettings *aCookieSettings, bool aThirdPartySession,
+    bool aThirdPartyNonsecureSession, nsIURI *aHostURI, bool aIsForeign,
+    bool aIsTrackingResource, bool aFirstPartyStorageAccessGranted,
+    const char *aCookieHeader, const int aNumOfCookies,
+    const OriginAttributes &aOriginAttrs, uint32_t *aRejectedReason) {
   nsresult rv;
 
   // Let's use a internal value in order to avoid a null check on
   // aRejectedReason everywhere.
   uint32_t rejectedReason = 0;
   if (!aRejectedReason) {
     aRejectedReason = &rejectedReason;
   }
@@ -4001,72 +4013,70 @@ CookieStatus nsCookieService::CheckPrefs
     COOKIE_LOGFAILURE(aCookieHeader ? SET_COOKIE : GET_COOKIE, aHostURI,
                       aCookieHeader,
                       "non-codebase principals cannot get/set cookies");
     return STATUS_REJECTED_WITH_ERROR;
   }
 
   // check the permission list first; if we find an entry, it overrides
   // default prefs. see bug 184059.
-  if (aPermissionService) {
-    nsCookieAccess access;
-    // Not passing an nsIChannel here is probably OK; our implementation
-    // doesn't do anything with it anyway.
-    rv = aPermissionService->CanAccess(principal, &access);
-
-    // if we found an entry, use it
-    if (NS_SUCCEEDED(rv)) {
-      switch (access) {
-        case nsICookiePermission::ACCESS_DENY:
-          COOKIE_LOGFAILURE(aCookieHeader ? SET_COOKIE : GET_COOKIE, aHostURI,
-                            aCookieHeader, "cookies are blocked for this site");
-          *aRejectedReason =
-              nsIWebProgressListener::STATE_COOKIES_BLOCKED_BY_PERMISSION;
-          return STATUS_REJECTED;
-
-        case nsICookiePermission::ACCESS_ALLOW:
-          return STATUS_ACCEPTED;
-      }
+  uint32_t cookiePermission = nsICookiePermission::ACCESS_DEFAULT;
+  rv = aCookieSettings->CookiePermission(principal, &cookiePermission);
+  if (NS_SUCCEEDED(rv)) {
+    switch (cookiePermission) {
+      case nsICookiePermission::ACCESS_DENY:
+        COOKIE_LOGFAILURE(aCookieHeader ? SET_COOKIE : GET_COOKIE, aHostURI,
+                          aCookieHeader, "cookies are blocked for this site");
+        *aRejectedReason =
+            nsIWebProgressListener::STATE_COOKIES_BLOCKED_BY_PERMISSION;
+        return STATUS_REJECTED;
+
+      case nsICookiePermission::ACCESS_ALLOW:
+        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 &&
-      aCookieBehavior == nsICookieService::BEHAVIOR_REJECT_TRACKER) {
+      aCookieSettings->GetCookieBehavior() ==
+          nsICookieService::BEHAVIOR_REJECT_TRACKER) {
     COOKIE_LOGFAILURE(aCookieHeader ? SET_COOKIE : GET_COOKIE, aHostURI,
                       aCookieHeader, "cookies are disabled in trackers");
     *aRejectedReason = nsIWebProgressListener::STATE_COOKIES_BLOCKED_TRACKER;
     return STATUS_REJECTED;
   }
 
   // check default prefs.
   // Check aFirstPartyStorageAccessGranted when checking aCookieBehavior
   // so that we take things such as the content blocking allow list into
   // account.
-  if (aCookieBehavior == nsICookieService::BEHAVIOR_REJECT &&
+  if (aCookieSettings->GetCookieBehavior() ==
+          nsICookieService::BEHAVIOR_REJECT &&
       !aFirstPartyStorageAccessGranted) {
     COOKIE_LOGFAILURE(aCookieHeader ? SET_COOKIE : GET_COOKIE, aHostURI,
                       aCookieHeader, "cookies are disabled");
     *aRejectedReason = nsIWebProgressListener::STATE_COOKIES_BLOCKED_ALL;
     return STATUS_REJECTED;
   }
 
   // check if cookie is foreign
   if (aIsForeign) {
-    if (aCookieBehavior == nsICookieService::BEHAVIOR_REJECT_FOREIGN &&
+    if (aCookieSettings->GetCookieBehavior() ==
+            nsICookieService::BEHAVIOR_REJECT_FOREIGN &&
         !aFirstPartyStorageAccessGranted) {
       COOKIE_LOGFAILURE(aCookieHeader ? SET_COOKIE : GET_COOKIE, aHostURI,
                         aCookieHeader, "context is third party");
       *aRejectedReason = nsIWebProgressListener::STATE_COOKIES_BLOCKED_FOREIGN;
       return STATUS_REJECTED;
     }
 
-    if (aCookieBehavior == nsICookieService::BEHAVIOR_LIMIT_FOREIGN &&
+    if (aCookieSettings->GetCookieBehavior() ==
+            nsICookieService::BEHAVIOR_LIMIT_FOREIGN &&
         !aFirstPartyStorageAccessGranted && aNumOfCookies == 0) {
       COOKIE_LOGFAILURE(aCookieHeader ? SET_COOKIE : GET_COOKIE, aHostURI,
                         aCookieHeader, "context is third party");
       *aRejectedReason = nsIWebProgressListener::STATE_COOKIES_BLOCKED_FOREIGN;
       return STATUS_REJECTED;
     }
 
     if (aThirdPartySession) return STATUS_ACCEPT_SESSION;
--- a/netwerk/cookie/nsCookieService.h
+++ b/netwerk/cookie/nsCookieService.h
@@ -3,16 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsCookieService_h__
 #define nsCookieService_h__
 
 #include "nsICookieService.h"
 #include "nsICookieManager.h"
+#include "nsICookiePermission.h"
 #include "nsIObserver.h"
 #include "nsWeakReference.h"
 
 #include "nsCookie.h"
 #include "nsCookieKey.h"
 #include "nsString.h"
 #include "nsAutoPtr.h"
 #include "nsHashKeys.h"
@@ -33,16 +34,17 @@
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/Monitor.h"
 #include "mozilla/UniquePtr.h"
 
 using mozilla::OriginAttributes;
 
 class nsICookiePermission;
+class nsICookieSettings;
 class nsIEffectiveTLDService;
 class nsIIDNService;
 class nsIPrefBranch;
 class nsIObserverService;
 class nsIURI;
 class nsIChannel;
 class nsIArray;
 class nsIThread;
@@ -253,23 +255,26 @@ class nsCookieService final : public nsI
   static bool CanSetCookie(nsIURI *aHostURI, const nsCookieKey &aKey,
                            nsCookieAttributes &aCookieAttributes,
                            bool aRequireHostMatch, CookieStatus aStatus,
                            nsDependentCString &aCookieHeader,
                            int64_t aServerTime, bool aFromHttp,
                            nsIChannel *aChannel, bool &aSetCookie,
                            mozIThirdPartyUtil *aThirdPartyUtil);
   static CookieStatus CheckPrefs(
-      nsICookiePermission *aPermissionServices, uint8_t aCookieBehavior,
-      bool aThirdPartySession, bool aThirdPartyNonsecureSession,
-      nsIURI *aHostURI, bool aIsForeign, bool aIsTrackingResource,
-      bool aIsFirstPartyStorageAccessGranted, const char *aCookieHeader,
-      const int aNumOfCookies, const OriginAttributes &aOriginAttrs,
-      uint32_t *aRejectedReason);
+      nsICookieSettings *aCookieSettings, bool aThirdPartySession,
+      bool aThirdPartyNonsecureSession, nsIURI *aHostURI, bool aIsForeign,
+      bool aIsTrackingResource, bool aIsFirstPartyStorageAccessGranted,
+      const char *aCookieHeader, const int aNumOfCookies,
+      const OriginAttributes &aOriginAttrs, uint32_t *aRejectedReason);
   static int64_t ParseServerTime(const nsCString &aServerTime);
+
+  static already_AddRefed<nsICookieSettings> GetCookieSettings(
+      nsIChannel *aChannel);
+
   void GetCookiesForURI(nsIURI *aHostURI, nsIChannel *aChannel, bool aIsForeign,
                         bool aIsTrackingResource,
                         bool aFirstPartyStorageAccessGranted,
                         bool aIsSafeTopLevelNav, bool aIsSameSiteForeign,
                         bool aHttpBound, const OriginAttributes &aOriginAttrs,
                         nsTArray<nsCookie *> &aCookieList);
 
  protected:
@@ -393,19 +398,16 @@ class nsCookieService final : public nsI
   // private browsing, switching between them on a per-cookie-request basis.
   // this state encapsulates both the in-memory table and the on-disk DB.
   // note that the private states' dbConn should always be null - we never
   // want to be dealing with the on-disk DB when in private browsing.
   DBState *mDBState;
   RefPtr<DBState> mDefaultDBState;
   RefPtr<DBState> mPrivateDBState;
 
-  // cached prefs
-  uint8_t mCookieBehavior;  // BEHAVIOR_{ACCEPT, REJECTFOREIGN, REJECT,
-                            // LIMITFOREIGN}
   bool mThirdPartySession;
   bool mThirdPartyNonsecureSession;
   uint16_t mMaxNumberOfCookies;
   uint16_t mMaxCookiesPerHost;
   uint16_t mCookieQuotaPerHost;
   int64_t mCookiePurgeAge;
 
   // thread