Bug 1638358 - Cookie Schemeful Same-Site - part 6 - console messages, r=mayhemer
☠☠ backed out by 70bab29e077c ☠ ☠
authorAndrea Marchesini <amarchesini@mozilla.com>
Mon, 01 Jun 2020 15:17:31 +0000
changeset 597397 4e8fbe01aa38990c2c4348a42a6cf343f66080f7
parent 597396 532731e94bb23b01b5e7136bee829844a0f08bc2
child 597398 b4b25034dd83ae8e63fa2b60042280483803f3cd
push id13310
push userffxbld-merge
push dateMon, 29 Jun 2020 14:50:06 +0000
treeherdermozilla-beta@15a59a0afa5c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmayhemer
bugs1638358
milestone78.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 1638358 - Cookie Schemeful Same-Site - part 6 - console messages, r=mayhemer Differential Revision: https://phabricator.services.mozilla.com/D75800
netwerk/cookie/CookieCommons.cpp
netwerk/cookie/CookieCommons.h
netwerk/cookie/CookieLogging.cpp
netwerk/cookie/CookieLogging.h
netwerk/cookie/CookieService.cpp
netwerk/cookie/CookieService.h
netwerk/cookie/test/unit/test_schemeMap.js
netwerk/locales/en-US/necko.properties
--- a/netwerk/cookie/CookieCommons.cpp
+++ b/netwerk/cookie/CookieCommons.cpp
@@ -1,28 +1,32 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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/. */
 
 #include "Cookie.h"
 #include "CookieCommons.h"
+#include "CookieLogging.h"
 #include "CookieService.h"
 #include "mozilla/ContentBlocking.h"
 #include "mozilla/ConsoleReportCollector.h"
 #include "mozilla/ContentBlockingNotifier.h"
 #include "mozilla/dom/nsMixedContentBlocker.h"
 #include "mozilla/net/CookieJarSettings.h"
 #include "mozIThirdPartyUtil.h"
 #include "nsContentUtils.h"
 #include "nsICookiePermission.h"
 #include "nsICookieService.h"
 #include "nsIEffectiveTLDService.h"
 #include "nsScriptSecurityManager.h"
 
+constexpr auto CONSOLE_SCHEMEFUL_CATEGORY =
+    NS_LITERAL_CSTRING("cookieSchemeful");
+
 namespace mozilla {
 
 using dom::Document;
 
 namespace net {
 
 // static
 bool CookieCommons::DomainMatches(Cookie* aCookie, const nsACString& aHost) {
@@ -451,31 +455,78 @@ bool CookieCommons::ShouldIncludeCrossSi
   MOZ_ASSERT(aCookie);
 
   int32_t sameSiteAttr = 0;
   aCookie->GetSameSite(&sameSiteAttr);
 
   return sameSiteAttr == nsICookie::SAMESITE_NONE;
 }
 
-// static
-bool CookieCommons::MaybeCompareScheme(Cookie* aCookie,
-                                       nsICookie::schemeType aSchemeType) {
-  if (!StaticPrefs::network_cookie_sameSite_schemeful()) {
-    return true;
-  }
+namespace {
+
+bool MaybeCompareSchemeInternal(Cookie* aCookie,
+                                nsICookie::schemeType aSchemeType) {
+  MOZ_ASSERT(aCookie);
 
   // This is an old cookie without a scheme yet. Let's consider it valid.
   if (aCookie->SchemeMap() == nsICookie::SCHEME_UNSET) {
     return true;
   }
 
   return !!(aCookie->SchemeMap() & aSchemeType);
 }
 
+}  // namespace
+
+// static
+bool CookieCommons::MaybeCompareSchemeWithLogging(
+    nsIConsoleReportCollector* aCRC, nsIURI* aHostURI, Cookie* aCookie,
+    nsICookie::schemeType aSchemeType) {
+  MOZ_ASSERT(aCookie);
+  MOZ_ASSERT(aHostURI);
+
+  if (MaybeCompareSchemeInternal(aCookie, aSchemeType)) {
+    return true;
+  }
+
+  nsAutoCString uri;
+  nsresult rv = aHostURI->GetSpec(uri);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return !StaticPrefs::network_cookie_sameSite_schemeful();
+  }
+
+  if (!StaticPrefs::network_cookie_sameSite_schemeful()) {
+    CookieLogging::LogMessageToConsole(
+        aCRC, aHostURI, nsIScriptError::warningFlag, CONSOLE_SCHEMEFUL_CATEGORY,
+        NS_LITERAL_CSTRING("CookieSchemefulRejectForBeta"),
+        AutoTArray<nsString, 2>{NS_ConvertUTF8toUTF16(aCookie->Name()),
+                                NS_ConvertUTF8toUTF16(uri)});
+    return true;
+  }
+
+  CookieLogging::LogMessageToConsole(
+      aCRC, aHostURI, nsIScriptError::warningFlag, CONSOLE_SCHEMEFUL_CATEGORY,
+      NS_LITERAL_CSTRING("CookieSchemefulReject"),
+      AutoTArray<nsString, 2>{NS_ConvertUTF8toUTF16(aCookie->Name()),
+                              NS_ConvertUTF8toUTF16(uri)});
+  return false;
+}
+
+// static
+bool CookieCommons::MaybeCompareScheme(Cookie* aCookie,
+                                       nsICookie::schemeType aSchemeType) {
+  MOZ_ASSERT(aCookie);
+
+  if (!StaticPrefs::network_cookie_sameSite_schemeful()) {
+    return true;
+  }
+
+  return MaybeCompareSchemeInternal(aCookie, aSchemeType);
+}
+
 // static
 nsICookie::schemeType CookieCommons::URIToSchemeType(nsIURI* aURI) {
   MOZ_ASSERT(aURI);
 
   nsAutoCString scheme;
   nsresult rv = aURI->GetScheme(scheme);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return nsICookie::SCHEME_UNSET;
--- a/netwerk/cookie/CookieCommons.h
+++ b/netwerk/cookie/CookieCommons.h
@@ -104,16 +104,20 @@ class CookieCommons final {
           aHasExistingCookiesLambda,
       nsIURI** aDocumentURI, nsACString& aBaseDomain, OriginAttributes& aAttrs);
 
   static already_AddRefed<nsICookieJarSettings> GetCookieJarSettings(
       nsIChannel* aChannel);
 
   static bool ShouldIncludeCrossSiteCookieForDocument(Cookie* aCookie);
 
+  static bool MaybeCompareSchemeWithLogging(nsIConsoleReportCollector* aCRC,
+                                            nsIURI* aHostURI, Cookie* aCookie,
+                                            nsICookie::schemeType aSchemeType);
+
   static bool MaybeCompareScheme(Cookie* aCookie,
                                  nsICookie::schemeType aSchemeType);
 
   static nsICookie::schemeType URIToSchemeType(nsIURI* aURI);
 
   static nsICookie::schemeType PrincipalToSchemeType(nsIPrincipal* aPrincipal);
 
   static nsICookie::schemeType SchemeToSchemeType(const nsACString& aScheme);
--- a/netwerk/cookie/CookieLogging.cpp
+++ b/netwerk/cookie/CookieLogging.cpp
@@ -152,10 +152,33 @@ void CookieLogging::LogEvicted(Cookie* a
   MOZ_LOG(gCookieLog, LogLevel::Debug, ("===== COOKIE EVICTED =====\n"));
   MOZ_LOG(gCookieLog, LogLevel::Debug, ("%s\n", details));
 
   LogCookie(aCookie);
 
   MOZ_LOG(gCookieLog, LogLevel::Debug, ("\n"));
 }
 
+// static
+void CookieLogging::LogMessageToConsole(nsIConsoleReportCollector* aCRC,
+                                        nsIURI* aURI, uint32_t aErrorFlags,
+                                        const nsACString& aCategory,
+                                        const nsACString& aMsg,
+                                        const nsTArray<nsString>& aParams) {
+  MOZ_ASSERT(aURI);
+
+  if (!aCRC) {
+    return;
+  }
+
+  nsAutoCString uri;
+  nsresult rv = aURI->GetSpec(uri);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return;
+  }
+
+  aCRC->AddConsoleReport(aErrorFlags, aCategory,
+                         nsContentUtils::eNECKO_PROPERTIES, uri, 0, 0, aMsg,
+                         aParams);
+}
+
 }  // namespace net
 }  // namespace mozilla
--- a/netwerk/cookie/CookieLogging.h
+++ b/netwerk/cookie/CookieLogging.h
@@ -4,16 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_net_CookieLogging_h
 #define mozilla_net_CookieLogging_h
 
 #include "mozilla/Logging.h"
 #include "nsString.h"
 
+class nsIConsoleReportCollector;
 class nsIURI;
 
 namespace mozilla {
 namespace net {
 
 // define logging macros for convenience
 #define SET_COOKIE true
 #define GET_COOKIE false
@@ -45,14 +46,20 @@ class CookieLogging final {
                          bool aReplacing);
 
   static void LogFailure(bool aSetCookie, nsIURI* aHostURI,
                          const nsACString& aCookieString, const char* aReason);
 
   static void LogCookie(Cookie* aCookie);
 
   static void LogEvicted(Cookie* aCookie, const char* aDetails);
+
+  static void LogMessageToConsole(nsIConsoleReportCollector* aCRC, nsIURI* aURI,
+                                  uint32_t aErrorFlags,
+                                  const nsACString& aCategory,
+                                  const nsACString& aMsg,
+                                  const nsTArray<nsString>& aParams);
 };
 
 }  // namespace net
 }  // namespace mozilla
 
 #endif  // mozilla_net_CookieLogging_h
--- a/netwerk/cookie/CookieService.cpp
+++ b/netwerk/cookie/CookieService.cpp
@@ -905,30 +905,33 @@ void CookieService::GetCookiesForURI(
     return;
   }
 
   bool laxByDefault =
       StaticPrefs::network_cookie_sameSite_laxByDefault() &&
       !nsContentUtils::IsURIInPrefList(
           aHostURI, "network.cookie.sameSite.laxByDefault.disabledHosts");
 
+  nsCOMPtr<nsIConsoleReportCollector> crc = do_QueryInterface(aChannel);
+
   // iterate the cookies!
   for (Cookie* cookie : *cookies) {
     // check the host, since the base domain lookup is conservative.
     if (!CookieCommons::DomainMatches(cookie, hostFromURI)) {
       continue;
     }
 
     // if the cookie is secure and the host scheme isn't, we can't send it
     if (cookie->IsSecure() && !potentiallyTurstworthy) {
       continue;
     }
 
     // The scheme doesn't match.
-    if (!CookieCommons::MaybeCompareScheme(cookie, schemeType)) {
+    if (!CookieCommons::MaybeCompareSchemeWithLogging(crc, aHostURI, cookie,
+                                                      schemeType)) {
       continue;
     }
 
     if (aHttpBound && aIsSameSiteForeign &&
         !ProcessSameSiteCookieForForeignRequest(
             aChannel, cookie, aIsSafeTopLevelNav, laxByDefault)) {
       continue;
     }
@@ -1037,19 +1040,19 @@ bool CookieService::CanSetCookie(
 
     AutoTArray<nsString, 2> params = {
         NS_ConvertUTF8toUTF16(aCookieData.name())};
 
     nsString size;
     size.AppendInt(kMaxBytesPerCookie);
     params.AppendElement(size);
 
-    LogMessageToConsole(aCRC, aHostURI, nsIScriptError::warningFlag,
-                        CONSOLE_OVERSIZE_CATEGORY,
-                        NS_LITERAL_CSTRING("CookieOversize"), params);
+    CookieLogging::LogMessageToConsole(
+        aCRC, aHostURI, nsIScriptError::warningFlag, CONSOLE_OVERSIZE_CATEGORY,
+        NS_LITERAL_CSTRING("CookieOversize"), params);
     return newCookie;
   }
 
   if (!CookieCommons::CheckName(aCookieData)) {
     COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, savedCookieHeader,
                       "invalid name character");
     return newCookie;
   }
@@ -1361,17 +1364,17 @@ bool CookieService::ParseAttributes(nsIC
         aCookieData.sameSite() = nsICookie::SAMESITE_STRICT;
         aCookieData.rawSameSite() = nsICookie::SAMESITE_STRICT;
         sameSiteSet = true;
       } else if (tokenValue.LowerCaseEqualsLiteral(kSameSiteNone)) {
         aCookieData.sameSite() = nsICookie::SAMESITE_NONE;
         aCookieData.rawSameSite() = nsICookie::SAMESITE_NONE;
         sameSiteSet = true;
       } else {
-        LogMessageToConsole(
+        CookieLogging::LogMessageToConsole(
             aCRC, aHostURI, nsIScriptError::infoFlag, CONSOLE_SAMESITE_CATEGORY,
             NS_LITERAL_CSTRING("CookieSameSiteValueInvalid"),
             AutoTArray<nsString, 1>{NS_ConvertUTF8toUTF16(aCookieData.name())});
       }
     }
   }
 
   Telemetry::Accumulate(Telemetry::COOKIE_SAMESITE_SET_VS_UNSET,
@@ -1381,78 +1384,55 @@ bool CookieService::ParseAttributes(nsIC
   aCookieHeader.Assign(Substring(cookieStart, cookieEnd));
 
   // If same-site is set to 'none' but this is not a secure context, let's abort
   // the parsing.
   if (!aCookieData.isSecure() &&
       aCookieData.sameSite() == nsICookie::SAMESITE_NONE) {
     if (laxByDefault &&
         StaticPrefs::network_cookie_sameSite_noneRequiresSecure()) {
-      LogMessageToConsole(
+      CookieLogging::LogMessageToConsole(
           aCRC, aHostURI, nsIScriptError::infoFlag, CONSOLE_SAMESITE_CATEGORY,
           NS_LITERAL_CSTRING("CookieRejectedNonRequiresSecure"),
           AutoTArray<nsString, 1>{NS_ConvertUTF8toUTF16(aCookieData.name())});
       return newCookie;
     }
 
     // if sameSite=lax by default is disabled, we want to warn the user.
-    LogMessageToConsole(
+    CookieLogging::LogMessageToConsole(
         aCRC, aHostURI, nsIScriptError::warningFlag, CONSOLE_SAMESITE_CATEGORY,
         NS_LITERAL_CSTRING("CookieRejectedNonRequiresSecureForBeta"),
         AutoTArray<nsString, 2>{NS_ConvertUTF8toUTF16(aCookieData.name()),
                                 SAMESITE_MDN_URL});
   }
 
   if (aCookieData.rawSameSite() == nsICookie::SAMESITE_NONE &&
       aCookieData.sameSite() == nsICookie::SAMESITE_LAX) {
     if (laxByDefault) {
-      LogMessageToConsole(
+      CookieLogging::LogMessageToConsole(
           aCRC, aHostURI, nsIScriptError::infoFlag, CONSOLE_SAMESITE_CATEGORY,
           NS_LITERAL_CSTRING("CookieLaxForced"),
           AutoTArray<nsString, 1>{NS_ConvertUTF8toUTF16(aCookieData.name())});
     } else {
-      LogMessageToConsole(
+      CookieLogging::LogMessageToConsole(
           aCRC, aHostURI, nsIScriptError::warningFlag,
           CONSOLE_SAMESITE_CATEGORY,
           NS_LITERAL_CSTRING("CookieLaxForcedForBeta"),
           AutoTArray<nsString, 2>{NS_ConvertUTF8toUTF16(aCookieData.name()),
                                   SAMESITE_MDN_URL});
     }
   }
 
   // Cookie accepted.
   aAcceptedByParser = true;
 
   MOZ_ASSERT(Cookie::ValidateRawSame(aCookieData));
   return newCookie;
 }
 
-// static
-void CookieService::LogMessageToConsole(nsIConsoleReportCollector* aCRC,
-                                        nsIURI* aURI, uint32_t aErrorFlags,
-                                        const nsACString& aCategory,
-                                        const nsACString& aMsg,
-                                        const nsTArray<nsString>& aParams) {
-  MOZ_ASSERT(aURI);
-
-  if (!aCRC) {
-    return;
-  }
-
-  nsAutoCString uri;
-  nsresult rv = aURI->GetSpec(uri);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return;
-  }
-
-  aCRC->AddConsoleReport(aErrorFlags, aCategory,
-                         nsContentUtils::eNECKO_PROPERTIES, uri, 0, 0, aMsg,
-                         aParams);
-}
-
 /******************************************************************************
  * CookieService impl:
  * private domain & permission compliance enforcement functions
  ******************************************************************************/
 
 // Normalizes the given hostname, component by component. ASCII/ACE
 // components are lower-cased, and UTF-8 components are normalized per
 // RFC 3454 and converted to ACE.
@@ -1733,19 +1713,19 @@ bool CookieService::CheckPath(CookieStru
   if (!CookieCommons::CheckPathSize(aCookieData)) {
     AutoTArray<nsString, 2> params = {
         NS_ConvertUTF8toUTF16(aCookieData.name())};
 
     nsString size;
     size.AppendInt(kMaxBytesPerPath);
     params.AppendElement(size);
 
-    LogMessageToConsole(aCRC, aHostURI, nsIScriptError::warningFlag,
-                        CONSOLE_OVERSIZE_CATEGORY,
-                        NS_LITERAL_CSTRING("CookiePathOversize"), params);
+    CookieLogging::LogMessageToConsole(
+        aCRC, aHostURI, nsIScriptError::warningFlag, CONSOLE_OVERSIZE_CATEGORY,
+        NS_LITERAL_CSTRING("CookiePathOversize"), params);
     return false;
   }
 
   if (aCookieData.path().Contains('\t')) {
     return false;
   }
 
   return true;
--- a/netwerk/cookie/CookieService.h
+++ b/netwerk/cookie/CookieService.h
@@ -140,22 +140,16 @@ class CookieService final : public nsICo
 
  protected:
   CookieStorage* PickStorage(const OriginAttributes& aAttrs);
   CookieStorage* PickStorage(const OriginAttributesPattern& aAttrs);
 
   nsresult RemoveCookiesFromExactHost(const nsACString& aHost,
                                       const OriginAttributesPattern& aPattern);
 
-  static void LogMessageToConsole(nsIConsoleReportCollector* aCRC, nsIURI* aURI,
-                                  uint32_t aErrorFlags,
-                                  const nsACString& aCategory,
-                                  const nsACString& aMsg,
-                                  const nsTArray<nsString>& aParams);
-
   // cached members.
   nsCOMPtr<mozIThirdPartyUtil> mThirdPartyUtil;
   nsCOMPtr<nsIEffectiveTLDService> mTLDService;
   nsCOMPtr<nsIIDNService> mIDNService;
 
   // we have two separate Cookie Storages: one for normal browsing and one for
   // private browsing.
   RefPtr<CookiePersistentStorage> mPersistentStorage;
--- a/netwerk/cookie/test/unit/test_schemeMap.js
+++ b/netwerk/cookie/test/unit/test_schemeMap.js
@@ -11,16 +11,33 @@ XPCOMUtils.defineLazyServiceGetter(
   "@mozilla.org/cookiemanager;1",
   "nsICookieManager"
 );
 
 function inChildProcess() {
   return Services.appinfo.processType != Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
 }
 
+const { CookieXPCShellUtils } = ChromeUtils.import(
+  "resource://testing-common/CookieXPCShellUtils.jsm"
+);
+
+let cookieXPCShellUtilsInitialized = false;
+function maybeInitializeCookieXPCShellUtils() {
+  if (!cookieXPCShellUtilsInitialized) {
+    cookieXPCShellUtilsInitialized = true;
+    CookieXPCShellUtils.init(this);
+
+    CookieXPCShellUtils.createServer({ hosts: ["example.org"] });
+  }
+}
+
+// Don't pick up default permissions from profile.
+Services.prefs.setCharPref("permissions.manager.defaultsUrl", "");
+
 add_task(async _ => {
   do_get_profile();
 
   // Allow all cookies if the pref service is available in this process.
   if (!inChildProcess()) {
     Services.prefs.setIntPref("network.cookie.cookieBehavior", 0);
     Services.prefs.setBoolPref(
       "network.cookieJarSettings.unblocked_for_testing",
@@ -75,16 +92,18 @@ add_task(async _ => {
 
   Services.cookies.removeAll();
 });
 
 [true, false].forEach(schemefulComparison => {
   add_task(async () => {
     do_get_profile();
 
+    maybeInitializeCookieXPCShellUtils();
+
     // Allow all cookies if the pref service is available in this process.
     if (!inChildProcess()) {
       Services.prefs.setBoolPref(
         "network.cookie.sameSite.schemeful",
         schemefulComparison
       );
       Services.prefs.setIntPref("network.cookie.cookieBehavior", 0);
       Services.prefs.setBoolPref(
@@ -92,50 +111,50 @@ add_task(async _ => {
         true
       );
     }
 
     let cs = Cc["@mozilla.org/cookieService;1"].getService(Ci.nsICookieService);
 
     info("Let's set a cookie from HTTP example.org");
 
-    let uri = NetUtil.newURI("http://example.org/");
+    let uri = NetUtil.newURI("https://example.org/");
     let principal = Services.scriptSecurityManager.createContentPrincipal(
       uri,
       {}
     );
     let channel = NetUtil.newChannel({
       uri,
       loadingPrincipal: principal,
       securityFlags: Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
       contentPolicyType: Ci.nsIContentPolicy.TYPE_OTHER,
     });
 
     cs.setCookieStringFromHttp(uri, "a=b; sameSite=lax", channel);
 
     let cookies = Services.cookies.getCookieStringFromHttp(uri, channel);
     Assert.equal(cookies, "a=b", "Cookies match");
 
-    uri = NetUtil.newURI("https://example.org/");
+    uri = NetUtil.newURI("http://example.org/");
     principal = Services.scriptSecurityManager.createContentPrincipal(uri, {});
     channel = NetUtil.newChannel({
       uri,
       loadingPrincipal: principal,
       securityFlags: Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
       contentPolicyType: Ci.nsIContentPolicy.TYPE_OTHER,
     });
 
     cookies = Services.cookies.getCookieStringFromHttp(uri, channel);
     if (schemefulComparison) {
       Assert.equal(cookies, "", "No cookie for different scheme!");
     } else {
       Assert.equal(cookies, "a=b", "Cookie even for different scheme!");
     }
 
-    cookies = Services.cookies.getCookieStringForPrincipal(principal);
+    cookies = await CookieXPCShellUtils.getCookieStringFromDocument(uri.spec);
     if (schemefulComparison) {
       Assert.equal(cookies, "", "No cookie for different scheme!");
     } else {
       Assert.equal(cookies, "a=b", "Cookie even for different scheme!");
     }
 
     Services.cookies.removeAll();
   });
@@ -186,8 +205,83 @@ add_task(async _ => {
     });
 
     cookies = Services.cookies.getCookieStringFromHttp(uri, channel);
     Assert.equal(cookies, "a=b", "Cookie for unset scheme");
   });
 
   Services.cookies.removeAll();
 });
+
+[
+  {
+    prefValue: true,
+    consoleMessage: `Cookie “a” has been treated as cross-site against “http://example.org/” because the scheme does not match.`,
+  },
+  {
+    prefValue: false,
+    consoleMessage: `Cookie “a” will be soon treated as cross-site cookie against “http://example.org/” because the scheme does not match.`,
+  },
+].forEach(test => {
+  add_task(async () => {
+    do_get_profile();
+
+    maybeInitializeCookieXPCShellUtils();
+
+    // Allow all cookies if the pref service is available in this process.
+    if (!inChildProcess()) {
+      Services.prefs.setBoolPref(
+        "network.cookie.sameSite.schemeful",
+        test.prefValue
+      );
+      Services.prefs.setIntPref("network.cookie.cookieBehavior", 0);
+      Services.prefs.setBoolPref(
+        "network.cookieJarSettings.unblocked_for_testing",
+        true
+      );
+    }
+
+    let cs = Cc["@mozilla.org/cookieService;1"].getService(Ci.nsICookieService);
+
+    info("Let's set a cookie from HTTPS example.org");
+
+    let uri = NetUtil.newURI("https://example.org/");
+    let principal = Services.scriptSecurityManager.createContentPrincipal(
+      uri,
+      {}
+    );
+    let channel = NetUtil.newChannel({
+      uri,
+      loadingPrincipal: principal,
+      securityFlags: Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
+      contentPolicyType: Ci.nsIContentPolicy.TYPE_OTHER,
+    });
+
+    cs.setCookieStringFromHttp(uri, "a=b; sameSite=lax", channel);
+
+    // Create a console listener.
+    let consolePromise = new Promise(resolve => {
+      let listener = {
+        observe(message) {
+          // Ignore unexpected messages.
+          if (!(message instanceof Ci.nsIConsoleMessage)) {
+            return;
+          }
+
+          if (message.message.includes(test.consoleMessage)) {
+            Services.console.unregisterListener(listener);
+            resolve();
+          }
+        },
+      };
+
+      Services.console.registerListener(listener);
+    });
+
+    const contentPage = await CookieXPCShellUtils.loadContentPage(
+      "http://example.org/"
+    );
+    await contentPage.close();
+
+    await consolePromise;
+    Services.cookies.removeAll();
+  });
+});
--- a/netwerk/locales/en-US/necko.properties
+++ b/netwerk/locales/en-US/necko.properties
@@ -58,10 +58,14 @@ CookieRejectedNonRequiresSecureForBeta=Cookie “%1$S” will be soon rejected because it has the “sameSite” attribute set to “none” or an invalid value, without the “secure” attribute. To know more about the “sameSite“ attribute, read %2$S
 # LOCALIZATION NOTE(CookieLaxForced): %1$S is the cookie name. Do not localize "sameSite", "lax" and "sameSite=lax".
 CookieLaxForced=Cookie “%1$S” has “sameSite” policy set to “lax” because it is missing a “sameSite” attribute, and “sameSite=lax” is the default value for this attribute.
 # LOCALIZATION NOTE(CookieLaxForcedForBeta): %1$S is the cookie name. %2$S is a URL. Do not localize "sameSite", "lax" and "sameSite=lax", "sameSite=none".
 CookieLaxForcedForBeta=Cookie “%1$S” does not have a proper “sameSite” attribute value. Soon, cookies without the “sameSite” attribute or with an invalid value will be treated as “lax”. This means that the cookie will no longer be sent in third-party contexts. If your application depends on this cookie being available in such contexts, please add the “sameSite=none“ attribute to it. To know more about the “sameSite“ attribute, read %2$S
 # LOCALIZATION NOTE: %1$S is cookie name. Do not localize "sameSite", "lax", "strict" and "none"
 CookieSameSiteValueInvalid=Invalid “sameSite“ value for cookie “%1$S”. The supported values are: “lax“, “strict“, “none“.
 # LOCALIZATION NOTE (CookieOversize): %1$S is the cookie name. %2$S is the number of bytes. "B" means bytes.
 CookieOversize=Cookie “%1$S” is invalid because its size is too big. Max size is %2$S B.
-# LOCALIZATION NOTE (CookiePathOversiz): %1$S is the cookie name. %2$S is the number of bytes. "B" means bytes.
+# LOCALIZATION NOTE (CookiePathOversize): %1$S is the cookie name. %2$S is the number of bytes. "B" means bytes.
 CookiePathOversize=Cookie “%1$S” is invalid because its path size is too big. Max size is %2$S B.
+# LOCALIZATION NOTE (CookieSchemefulRejectForBeta): %1$S is the cookie name. %2$S is the hostname.
+CookieSchemefulRejectForBeta=Cookie “%1$S” will be soon treated as cross-site cookie against “%2$S” because the scheme does not match.
+# LOCALIZATION NOTE (CookieSchemefulReject): %1$S is the cookie name. %2$S is the hostname.
+CookieSchemefulReject=Cookie “%1$S” has been treated as cross-site against “%2$S” because the scheme does not match.