Backed out changeset afe80b4ff889 (bug 1595934) Requested by ehsan to see if it fixex bug 1597915. On a CLOSED TREE
authorDaniel Varga <dvarga@mozilla.com>
Fri, 22 Nov 2019 02:01:51 +0200
changeset 503229 adf7d49a44f8e4d91e687140aedd06721e6e45b0
parent 503228 e01020298260b1bb17bce5537baf72410aed44a5
child 503230 3f190001b25628d142ac504d4588db4f49c2acb8
child 503408 2a76c7273dd288badf6297583860a36df99cb31f
push id101201
push userdvarga@mozilla.com
push dateFri, 22 Nov 2019 00:02:54 +0000
treeherderautoland@adf7d49a44f8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1595934, 1597915
milestone72.0a1
backs outafe80b4ff889ef7e63982b70a267d37bb38393e1
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
Backed out changeset afe80b4ff889 (bug 1595934) Requested by ehsan to see if it fixex bug 1597915. On a CLOSED TREE
browser/base/content/test/sanitize/head.js
browser/components/extensions/parent/ext-browsingData.js
browser/components/originattributes/test/browser/browser_firstPartyIsolation.js
browser/components/sessionstore/SessionCookies.jsm
browser/components/sessionstore/test/browser_423132.js
browser/components/sessionstore/test/browser_cookies_sameSite.js
browser/modules/Sanitizer.jsm
browser/modules/SiteDataManager.jsm
dom/html/test/file_cookiemanager.js
dom/security/test/general/test_same_site_cookies_laxByDefault.html
mobile/android/components/extensions/ext-browsingData.js
netwerk/cookie/nsCookieService.cpp
netwerk/cookie/nsICookieManager.idl
netwerk/cookie/test/unit/test_bug1321912.js
netwerk/test/TestCookie.cpp
netwerk/test/mochitests/file_chromecommon.js
netwerk/test/mochitests/file_documentcookie_maxage_chromescript.js
netwerk/test/mochitests/file_testloadflags_chromescript.js
netwerk/test/unit/head_cookies.js
netwerk/test/unit/test_bug411952.js
netwerk/test/unit/test_bug526789.js
netwerk/test/unit/test_cookies_profile_close.js
netwerk/test/unit/test_cookies_read.js
netwerk/test/unit/test_domain_eviction.js
netwerk/test/unit/test_eviction.js
netwerk/test/unit/test_schema_2_migration.js
netwerk/test/unit/test_schema_3_migration.js
toolkit/components/cleardata/ClearDataService.jsm
toolkit/components/cleardata/SiteDataTestUtils.jsm
toolkit/components/contextualidentity/ContextualIdentityService.jsm
toolkit/components/extensions/test/xpcshell/test_ext_cookieBehaviors.js
toolkit/components/search/tests/xpcshell/test_searchSuggest_cookies.js
toolkit/forgetaboutsite/ForgetAboutSite.jsm
toolkit/forgetaboutsite/test/browser/browser_cookieDomain.js
--- a/browser/base/content/test/sanitize/head.js
+++ b/browser/base/content/test/sanitize/head.js
@@ -64,17 +64,17 @@ function createDomainCookie(host, origin
     false,
     Date.now() + 24000 * 60 * 60,
     originAttributes,
     Ci.nsICookie.SAMESITE_NONE
   );
 }
 
 function checkCookie(host, originAttributes) {
-  for (let cookie of Services.cookies.cookies) {
+  for (let cookie of Services.cookies.enumerator) {
     if (
       ChromeUtils.isOriginAttributesEqual(
         originAttributes,
         cookie.originAttributes
       ) &&
       cookie.host.includes(host)
     ) {
       return true;
--- a/browser/components/extensions/parent/ext-browsingData.js
+++ b/browser/components/extensions/parent/ext-browsingData.js
@@ -62,17 +62,17 @@ const clearCache = () => {
 
 const clearCookies = async function(options) {
   let cookieMgr = Services.cookies;
   // This code has been borrowed from Sanitizer.jsm.
   let yieldCounter = 0;
 
   if (options.since || options.hostnames) {
     // Iterate through the cookies and delete any created after our cutoff.
-    for (const cookie of cookieMgr.cookies) {
+    for (const cookie of cookieMgr.enumerator) {
       if (
         (!options.since ||
           cookie.creationTime >= PlacesUtils.toPRTime(options.since)) &&
         (!options.hostnames ||
           options.hostnames.includes(cookie.host.replace(/^\./, "")))
       ) {
         // This cookie was created after our cutoff, clear it.
         cookieMgr.remove(
--- a/browser/components/originattributes/test/browser/browser_firstPartyIsolation.js
+++ b/browser/components/originattributes/test/browser/browser_firstPartyIsolation.js
@@ -80,17 +80,17 @@ add_task(async function principal_test()
 add_task(async function cookie_test() {
   let tab = BrowserTestUtils.addTab(
     gBrowser,
     BASE_URL + "test_firstParty_cookie.html"
   );
   await BrowserTestUtils.browserLoaded(tab.linkedBrowser, true);
 
   let count = 0;
-  for (let cookie of Services.cookies.cookies) {
+  for (let cookie of Services.cookies.enumerator) {
     count++;
     Assert.equal(cookie.value, "foo", "Cookie value should be foo");
     Assert.equal(
       cookie.originAttributes.firstPartyDomain,
       BASE_DOMAIN,
       "Cookie's origin attributes should be " + BASE_DOMAIN
     );
   }
--- a/browser/components/sessionstore/SessionCookies.jsm
+++ b/browser/components/sessionstore/SessionCookies.jsm
@@ -189,17 +189,17 @@ var SessionCookiesInternal = {
   _reloadCookies() {
     CookieStore.clear();
 
     // Bail out if we're not supposed to store cookies at all.
     if (!PrivacyLevel.canSave(false)) {
       return;
     }
 
-    for (let cookie of Services.cookies.sessionCookies) {
+    for (let cookie of Services.cookies.sessionEnumerator) {
       this._addCookie(cookie);
     }
   },
 };
 
 /**
  * The internal storage that keeps track of session cookies.
  */
--- a/browser/components/sessionstore/test/browser_423132.js
+++ b/browser/components/sessionstore/test/browser_423132.js
@@ -20,29 +20,29 @@ add_task(async function() {
   await BrowserTestUtils.browserLoaded(tab.linkedBrowser);
   await TabStateFlusher.flush(tab.linkedBrowser);
 
   // get the sessionstore state for the window
   let state = ss.getBrowserState();
 
   // verify our cookie got set during pageload
   let i = 0;
-  for (var cookie of Services.cookies.cookies) {
+  for (var cookie of Services.cookies.enumerator) {
     i++;
   }
   Assert.equal(i, 1, "expected one cookie");
 
   // remove the cookie
   Services.cookies.removeAll();
 
   // restore the window state
   await setBrowserState(state);
 
   // at this point, the cookie should be restored...
-  for (var cookie2 of Services.cookies.cookies) {
+  for (var cookie2 of Services.cookies.enumerator) {
     if (cookie.name == cookie2.name) {
       break;
     }
   }
   is(cookie.name, cookie2.name, "cookie name successfully restored");
   is(cookie.value, cookie2.value, "cookie value successfully restored");
   is(cookie.path, cookie2.path, "cookie path successfully restored");
 
--- a/browser/components/sessionstore/test/browser_cookies_sameSite.js
+++ b/browser/components/sessionstore/test/browser_cookies_sameSite.js
@@ -1,15 +1,15 @@
 "use strict";
 
 const TEST_URL = "http://example.com";
 const MAX_EXPIRY = Math.pow(2, 62);
 
 function getSingleCookie() {
-  let cookies = Array.from(Services.cookies.cookies);
+  let cookies = Array.from(Services.cookies.enumerator);
   Assert.equal(cookies.length, 1, "expected one cookie");
   return cookies[0];
 }
 
 async function verifyRestore(sameSiteSetting) {
   Services.cookies.removeAll();
 
   // Make sure that sessionstore.js can be forced to be created by setting
--- a/browser/modules/Sanitizer.jsm
+++ b/browser/modules/Sanitizer.jsm
@@ -805,19 +805,19 @@ class PrincipalsCollector {
         Ci.nsIServiceWorkerRegistrationInfo
       );
       // We don't need to check the scheme. SW are just exposed to http/https URLs.
       principals.push(sw.principal);
     }
 
     // Let's take the list of unique hosts+OA from cookies.
     progress.step = "principals-cookies";
-    let cookies = Services.cookies.cookies;
+    let enumerator = Services.cookies.enumerator;
     let hosts = new Set();
-    for (let cookie of cookies) {
+    for (let cookie of enumerator) {
       hosts.add(
         cookie.rawHost +
           ChromeUtils.originAttributesToSuffix(cookie.originAttributes)
       );
     }
 
     progress.step = "principals-host-cookie";
     hosts.forEach(host => {
--- a/browser/modules/SiteDataManager.jsm
+++ b/browser/modules/SiteDataManager.jsm
@@ -173,17 +173,17 @@ var SiteDataManager = {
       //      After the bug 742822 and 1286798 landed, localStorage usage will be included.
       //      So currently only get indexedDB usage.
       this._quotaUsageRequest = Services.qms.getUsage(onUsageResult);
     });
     return this._getQuotaUsagePromise;
   },
 
   _getAllCookies() {
-    for (let cookie of Services.cookies.cookies) {
+    for (let cookie of Services.cookies.enumerator) {
       let site = this._getOrInsertSite(cookie.rawHost);
       site.cookies.push(cookie);
       if (site.lastAccessed < cookie.lastAccessed) {
         site.lastAccessed = cookie.lastAccessed;
       }
     }
   },
 
--- a/dom/html/test/file_cookiemanager.js
+++ b/dom/html/test/file_cookiemanager.js
@@ -1,13 +1,13 @@
 addMessageListener("getCookieFromManager", ({ host, path }) => {
   let cm = Cc["@mozilla.org/cookiemanager;1"].getService(Ci.nsICookieManager);
   let values = [];
   path = path.substring(0, path.lastIndexOf("/"));
-  for (let cookie of cm.cookies) {
+  for (let cookie of cm.enumerator) {
     if (!cookie) {
       break;
     }
     if (host != cookie.host || path != cookie.path) {
       continue;
     }
     values.push(cookie.name + "=" + cookie.value);
   }
--- a/dom/security/test/general/test_same_site_cookies_laxByDefault.html
+++ b/dom/security/test/general/test_same_site_cookies_laxByDefault.html
@@ -25,17 +25,17 @@ async function realTest(noneRequiresSecu
 
   info("Check cookies");
   let chromeScript = SpecialPowers.loadChromeScript(() => {
     const {sendAsyncMessage} = this;
     const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
 
     let cookies = { test: null, test2: null, test3: null };
 
-    for (let cookie of Services.cookies.cookies) {
+    for (let cookie of Services.cookies.enumerator) {
       if (cookie.host != "example.com") continue;
 
       if (cookie.name == "test" && cookie.value == "wow") {
         cookies.test = cookie.sameSite == Ci.nsICookie.SAMESITE_LAX ? 'lax' : 'none';
       }
 
       if (cookie.name == "test2" && cookie.value == "wow2") {
         cookies.test2 = cookie.sameSite == Ci.nsICookie.SAMESITE_LAX ? 'lax' : 'none';
--- a/mobile/android/components/extensions/ext-browsingData.js
+++ b/mobile/android/components/extensions/ext-browsingData.js
@@ -27,17 +27,17 @@ const clearCookies = async function(opti
   let cookieMgr = Services.cookies;
   let yieldCounter = 0;
   const YIELD_PERIOD = 10;
 
   if (options.since) {
     // Convert it to microseconds
     let since = options.since * 1000;
     // Iterate through the cookies and delete any created after our cutoff.
-    for (let cookie of cookieMgr.cookies) {
+    for (let cookie of cookieMgr.enumerator) {
       if (cookie.creationTime >= since) {
         // This cookie was created after our cutoff, clear it.
         cookieMgr.remove(
           cookie.host,
           cookie.name,
           cookie.path,
           cookie.originAttributes
         );
--- a/netwerk/cookie/nsCookieService.cpp
+++ b/netwerk/cookie/nsCookieService.cpp
@@ -41,22 +41,25 @@
 #include "nsIEffectiveTLDService.h"
 #include "nsIIDNService.h"
 #include "nsIThread.h"
 #include "mozIThirdPartyUtil.h"
 
 #include "nsTArray.h"
 #include "nsCOMArray.h"
 #include "nsIMutableArray.h"
+#include "nsArrayEnumerator.h"
+#include "nsEnumeratorUtils.h"
 #include "nsAutoPtr.h"
 #include "nsReadableUtils.h"
 #include "nsCRT.h"
 #include "prprf.h"
 #include "nsNetUtil.h"
 #include "nsNetCID.h"
+#include "nsISimpleEnumerator.h"
 #include "nsIInputStream.h"
 #include "nsAppDirectoryServiceDefs.h"
 #include "nsNetCID.h"
 #include "mozilla/storage.h"
 #include "mozilla/AutoRestore.h"
 #include "mozilla/FileUtils.h"
 #include "mozilla/ScopeExit.h"
 #include "mozilla/StaticPrefs_network.h"
@@ -2419,57 +2422,57 @@ nsCookieService::RemoveAll() {
     }
   }
 
   NotifyChanged(nullptr, u"cleared");
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsCookieService::GetCookies(nsTArray<RefPtr<nsICookie>>& aCookies) {
+nsCookieService::GetEnumerator(nsISimpleEnumerator** aEnumerator) {
   if (!mDBState) {
     NS_WARNING("No DBState! Profile already closed?");
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   EnsureReadComplete(true);
 
-  aCookies.SetCapacity(mDBState->cookieCount);
+  nsCOMArray<nsICookie> cookieList(mDBState->cookieCount);
   for (auto iter = mDBState->hostTable.Iter(); !iter.Done(); iter.Next()) {
     const nsCookieEntry::ArrayType& cookies = iter.Get()->GetCookies();
     for (nsCookieEntry::IndexType i = 0; i < cookies.Length(); ++i) {
-      aCookies.AppendElement(cookies[i]);
+      cookieList.AppendObject(cookies[i]);
     }
   }
 
-  return NS_OK;
+  return NS_NewArrayEnumerator(aEnumerator, cookieList, NS_GET_IID(nsICookie));
 }
 
 NS_IMETHODIMP
-nsCookieService::GetSessionCookies(nsTArray<RefPtr<nsICookie>>& aCookies) {
+nsCookieService::GetSessionEnumerator(nsISimpleEnumerator** aEnumerator) {
   if (!mDBState) {
     NS_WARNING("No DBState! Profile already closed?");
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   EnsureReadComplete(true);
 
-  aCookies.SetCapacity(mDBState->cookieCount);
+  nsCOMArray<nsICookie> cookieList(mDBState->cookieCount);
   for (auto iter = mDBState->hostTable.Iter(); !iter.Done(); iter.Next()) {
     const nsCookieEntry::ArrayType& cookies = iter.Get()->GetCookies();
     for (nsCookieEntry::IndexType i = 0; i < cookies.Length(); ++i) {
       nsCookie* cookie = cookies[i];
       // Filter out non-session cookies.
       if (cookie->IsSession()) {
-        aCookies.AppendElement(cookie);
+        cookieList.AppendObject(cookie);
       }
     }
   }
 
-  return NS_OK;
+  return NS_NewArrayEnumerator(aEnumerator, cookieList, NS_GET_IID(nsICookie));
 }
 
 NS_IMETHODIMP
 nsCookieService::Add(const nsACString& aHost, const nsACString& aPath,
                      const nsACString& aName, const nsACString& aValue,
                      bool aIsSecure, bool aIsHttpOnly, bool aIsSession,
                      int64_t aExpiry, JS::HandleValue aOriginAttributes,
                      int32_t aSameSite, JSContext* aCx) {
--- a/netwerk/cookie/nsICookieManager.idl
+++ b/netwerk/cookie/nsICookieManager.idl
@@ -8,16 +8,17 @@
 %{ C++
 namespace mozilla {
 class OriginAttributes;
 } // mozilla namespace
 %}
 
 [ptr] native OriginAttributesPtr(mozilla::OriginAttributes);
 
+interface nsISimpleEnumerator;
 interface nsICookie;
 interface nsIFile;
 
 /**
  * An optional interface for accessing or removing the cookies
  * that are in the cookie list
  */
 
@@ -26,30 +27,30 @@ interface nsICookieManager : nsISupports
 {
 
   /**
    * Called to remove all cookies from the cookie list
    */
   void removeAll();
 
   /**
-   * Returns an array of cookies in the cookie list.
-   * The objects in the array are of type nsICookie
-   * This array only contains non-private browsing cookies.
-   * To retrieve an array of private browsing cookies, use
+   * Called to enumerate through each cookie in the cookie list.
+   * The objects enumerated over are of type nsICookie
+   * This enumerator should only be used for non-private browsing cookies.
+   * To retrieve an enumerator for private browsing cookies, use
    * getCookiesWithOriginAttributes.
    */
-  readonly attribute Array<nsICookie> cookies;
+  readonly attribute nsISimpleEnumerator enumerator;
 
   /**
-   * Returns an array of session cookies in the cookie list.
-   * The objects in the array are of type nsICookie
-   * This array only contains non-private browsing cookies.
+   * Called to enumerate through each session cookie in the cookie list.
+   * The objects enumerated over are of type nsICookie
+   * This enumerator should only be used for non-private browsing cookies.
    */
-  readonly attribute Array<nsICookie> sessionCookies;
+  readonly attribute nsISimpleEnumerator sessionEnumerator;
 
   /**
    * Called to remove an individual cookie from the cookie list, specified
    * by host, name, and path. If the cookie cannot be found, no exception
    * is thrown. Typically, the arguments to this method will be obtained
    * directly from the desired nsICookie object.
    *
    * @param aHost The host or domain for which the cookie was set. @see
@@ -172,29 +173,29 @@ interface nsICookieManager : nsISupports
    *        of only the host portion of a URI. see @add for a description of
    *        acceptable host strings.
    *
    * @return the number of cookies found.
    */
   unsigned long countCookiesFromHost(in AUTF8String aHost);
 
   /**
-   * Returns an array of cookies that exist within the base domain of
+   * Returns an enumerator of cookies that exist within the base domain of
    * 'aHost'. Thus, for a host "weather.yahoo.com", the base domain would be
    * "yahoo.com", and any host or domain cookies for "yahoo.com" and its
    * subdomains would be returned.
    *
    * @param aHost
    *        the host string to search for, e.g. "google.com". this should consist
    *        of only the host portion of a URI. see @add for a description of
    *        acceptable host strings.
    * @param aOriginAttributes The originAttributes of cookies that would be
    *                          retrived.
    *
-   * @return an array of nsICookie objects.
+   * @return an nsISimpleEnumerator of nsICookie objects.
    *
    * @see countCookiesFromHost
    */
   [implicit_jscontext]
   Array<nsICookie> getCookiesFromHost(in AUTF8String aHost,
                                       in jsval aOriginAttributes);
 
   /**
--- a/netwerk/cookie/test/unit/test_bug1321912.js
+++ b/netwerk/cookie/test/unit/test_bug1321912.js
@@ -53,18 +53,18 @@ conn.executeSimpleSQL(
     ", " +
     now +
     ", " +
     now +
     ", 1, 1)"
 );
 
 // Now start the cookie service, and then check the fields in the table.
-// Get sessionCookies to wait for the initialization in cookie thread
-const cookies = Services.cookies.sessionCookies;
+// Get sessionEnumerator to wait for the initialization in cookie thread
+const enumerator = Services.cookies.sessionEnumerator;
 
 Assert.equal(conn.schemaVersion, 10);
 let stmt = conn.createStatement(
   "SELECT sql FROM sqlite_master " +
     "WHERE type = 'table' AND " +
     "      name = 'moz_cookies'"
 );
 try {
--- a/netwerk/test/TestCookie.cpp
+++ b/netwerk/test/TestCookie.cpp
@@ -10,16 +10,17 @@
 #include "nsICookieManager.h"
 #include "nsICookie.h"
 #include <stdio.h>
 #include "plstr.h"
 #include "nsNetUtil.h"
 #include "nsIChannel.h"
 #include "nsIPrincipal.h"
 #include "nsIScriptSecurityManager.h"
+#include "nsISimpleEnumerator.h"
 #include "nsServiceManagerUtils.h"
 #include "nsNetCID.h"
 #include "nsIPrefBranch.h"
 #include "nsIPrefService.h"
 #include "mozilla/Unused.h"
 #include "mozilla/net/CookieSettings.h"
 #include "nsIURI.h"
 
@@ -877,28 +878,38 @@ TEST(TestCookie, TestCookieMain)
                             NS_LITERAL_CSTRING("yes"),         // value
                             false,                             // is secure
                             false,                             // is httponly
                             true,                              // is session
                             INT64_MAX,                         // expiry time
                             &attrs,  // originAttributes
                             nsICookie::SAMESITE_NONE)));
   // confirm using enumerator
-  nsTArray<RefPtr<nsICookie>> cookies;
-  EXPECT_TRUE(NS_SUCCEEDED(cookieMgr->GetCookies(cookies)));
+  nsCOMPtr<nsISimpleEnumerator> enumerator;
+  EXPECT_TRUE(
+      NS_SUCCEEDED(cookieMgr->GetEnumerator(getter_AddRefs(enumerator))));
+  int32_t i = 0;
+  bool more;
   nsCOMPtr<nsICookie> expiredCookie, newDomainCookie;
-  for (const auto& cookie : cookies) {
+  while (NS_SUCCEEDED(enumerator->HasMoreElements(&more)) && more) {
+    nsCOMPtr<nsISupports> cookie;
+    if (NS_FAILED(enumerator->GetNext(getter_AddRefs(cookie)))) break;
+    ++i;
+
+    // keep tabs on the second and third cookies, so we can check them later
+    nsCOMPtr<nsICookie> cookie2(do_QueryInterface(cookie));
+    if (!cookie2) break;
     nsAutoCString name;
-    cookie->GetName(name);
+    cookie2->GetName(name);
     if (name.EqualsLiteral("test2"))
-      expiredCookie = cookie;
+      expiredCookie = cookie2;
     else if (name.EqualsLiteral("test3"))
-      newDomainCookie = cookie;
+      newDomainCookie = cookie2;
   }
-  EXPECT_EQ(cookies.Length(), 3ul);
+  EXPECT_EQ(i, 3);
   // check the httpOnly attribute of the second cookie is honored
   GetACookie(cookieService, "http://cookiemgr.test/foo/", nullptr, cookie);
   EXPECT_TRUE(CheckResult(cookie.get(), MUST_CONTAIN, "test2=yes"));
   GetACookieNoHttp(cookieService, "http://cookiemgr.test/foo/", cookie);
   EXPECT_TRUE(CheckResult(cookie.get(), MUST_NOT_CONTAIN, "test2=yes"));
   // check CountCookiesFromHost()
   uint32_t hostCookies = 0;
   EXPECT_TRUE(NS_SUCCEEDED(cookieMgr2->CountCookiesFromHost(
@@ -919,19 +930,19 @@ TEST(TestCookie, TestCookieMain)
       NS_LITERAL_CSTRING("cookiemgr.test"), &hostCookies)));
   EXPECT_EQ(hostCookies, 2u);
   EXPECT_TRUE(NS_SUCCEEDED(cookieMgr2->CookieExistsNative(
       NS_LITERAL_CSTRING("cookiemgr.test"), NS_LITERAL_CSTRING("/foo"),
       NS_LITERAL_CSTRING("test2"), &attrs, &found)));
   EXPECT_TRUE(found);
   // double-check RemoveAll() using the enumerator
   EXPECT_TRUE(NS_SUCCEEDED(cookieMgr->RemoveAll()));
-  cookies.SetLength(0);
-  EXPECT_TRUE(NS_SUCCEEDED(cookieMgr->GetCookies(cookies)) &&
-              cookies.IsEmpty());
+  EXPECT_TRUE(
+      NS_SUCCEEDED(cookieMgr->GetEnumerator(getter_AddRefs(enumerator))) &&
+      NS_SUCCEEDED(enumerator->HasMoreElements(&more)) && !more);
 
   // *** eviction and creation ordering tests
 
   // test that cookies are
   // a) returned by order of creation time (oldest first, newest last)
   // b) evicted by order of lastAccessed time, if the limit on cookies per host
   // (50) is reached
   nsAutoCString name;
@@ -988,20 +999,28 @@ TEST(TestCookie, TestCookieMain)
                      "empty=yes; samesite=", nullptr, false);
   SetASameSiteCookie(cookieService, "http://samesite.test", nullptr,
                      "bogus=yes; samesite=bogus", nullptr, false);
   SetASameSiteCookie(cookieService, "http://samesite.test", nullptr,
                      "strict=yes; samesite=strict", nullptr, false);
   SetASameSiteCookie(cookieService, "http://samesite.test", nullptr,
                      "lax=yes; samesite=lax", nullptr, false);
 
-  cookies.SetLength(0);
-  EXPECT_TRUE(NS_SUCCEEDED(cookieMgr->GetCookies(cookies)));
+  EXPECT_TRUE(
+      NS_SUCCEEDED(cookieMgr->GetEnumerator(getter_AddRefs(enumerator))));
+  i = 0;
 
-  EXPECT_TRUE(cookies.IsEmpty());
+  // check the cookies for the required samesite value
+  while (NS_SUCCEEDED(enumerator->HasMoreElements(&more)) && more) {
+    nsCOMPtr<nsISupports> cookie;
+    if (NS_FAILED(enumerator->GetNext(getter_AddRefs(cookie)))) break;
+    ++i;
+  }
+
+  EXPECT_TRUE(i == 0);
 
   // Set cookies with various incantations of the samesite attribute:
   // No same site attribute present
   SetASameSiteCookie(cookieService, "http://samesite.test", nullptr,
                      "unset=yes", nullptr, true);
   // samesite attribute present but with no value
   SetASameSiteCookie(cookieService, "http://samesite.test", nullptr,
                      "unspecified=yes; samesite", nullptr, true);
@@ -1013,41 +1032,49 @@ TEST(TestCookie, TestCookieMain)
                      "bogus=yes; samesite=bogus", nullptr, true);
   // samesite=strict
   SetASameSiteCookie(cookieService, "http://samesite.test", nullptr,
                      "strict=yes; samesite=strict", nullptr, true);
   // samesite=lax
   SetASameSiteCookie(cookieService, "http://samesite.test", nullptr,
                      "lax=yes; samesite=lax", nullptr, true);
 
-  cookies.SetLength(0);
-  EXPECT_TRUE(NS_SUCCEEDED(cookieMgr->GetCookies(cookies)));
+  EXPECT_TRUE(
+      NS_SUCCEEDED(cookieMgr->GetEnumerator(getter_AddRefs(enumerator))));
+  i = 0;
 
   // check the cookies for the required samesite value
-  for (const auto& cookie : cookies) {
+  while (NS_SUCCEEDED(enumerator->HasMoreElements(&more)) && more) {
+    nsCOMPtr<nsISupports> cookie;
+    if (NS_FAILED(enumerator->GetNext(getter_AddRefs(cookie)))) break;
+    ++i;
+
+    // keep tabs on the second and third cookies, so we can check them later
+    nsCOMPtr<nsICookie> cookie2(do_QueryInterface(cookie));
+    if (!cookie2) break;
     nsAutoCString name;
-    cookie->GetName(name);
+    cookie2->GetName(name);
     int32_t sameSiteAttr;
-    cookie->GetSameSite(&sameSiteAttr);
+    cookie2->GetSameSite(&sameSiteAttr);
     if (name.EqualsLiteral("unset")) {
       EXPECT_TRUE(sameSiteAttr == nsICookie::SAMESITE_NONE);
     } else if (name.EqualsLiteral("unspecified")) {
       EXPECT_TRUE(sameSiteAttr == nsICookie::SAMESITE_NONE);
     } else if (name.EqualsLiteral("empty")) {
       EXPECT_TRUE(sameSiteAttr == nsICookie::SAMESITE_NONE);
     } else if (name.EqualsLiteral("bogus")) {
       EXPECT_TRUE(sameSiteAttr == nsICookie::SAMESITE_NONE);
     } else if (name.EqualsLiteral("strict")) {
       EXPECT_TRUE(sameSiteAttr == nsICookie::SAMESITE_STRICT);
     } else if (name.EqualsLiteral("lax")) {
       EXPECT_TRUE(sameSiteAttr == nsICookie::SAMESITE_LAX);
     }
   }
 
-  EXPECT_TRUE(cookies.Length() == 6);
+  EXPECT_TRUE(i == 6);
 
   // *** SameSite attribute
   // Clear the cookies
   EXPECT_TRUE(NS_SUCCEEDED(cookieMgr->RemoveAll()));
 
   // please note that the flag aForeign is always set to true using this test
   // setup because no nsIChannel is passed to SetCookieString(). therefore we
   // can only test that no cookies are sent for cross origin requests using
--- a/netwerk/test/mochitests/file_chromecommon.js
+++ b/netwerk/test/mochitests/file_chromecommon.js
@@ -1,13 +1,13 @@
 let cs = Cc["@mozilla.org/cookiemanager;1"].getService(Ci.nsICookieManager);
 
 addMessageListener("getCookieCountAndClear", () => {
   let count = 0;
-  for (let cookie of cs.cookies) {
+  for (let cookie of cs.enumerator) {
     ++count;
   }
   cs.removeAll();
 
   sendAsyncMessage("getCookieCountAndClear:return", { count });
 });
 
 cs.removeAll();
--- a/netwerk/test/mochitests/file_documentcookie_maxage_chromescript.js
+++ b/netwerk/test/mochitests/file_documentcookie_maxage_chromescript.js
@@ -1,15 +1,15 @@
 function getCookieService() {
   return Cc["@mozilla.org/cookiemanager;1"].getService(Ci.nsICookieManager);
 }
 
 function getCookies(cs) {
   let cookies = [];
-  for (let cookie of cs.cookies) {
+  for (let cookie of cs.enumerator) {
     cookies.push({
       host: cookie.host,
       path: cookie.path,
       name: cookie.name,
       value: cookie.value,
       expires: cookie.expires,
     });
   }
--- a/netwerk/test/mochitests/file_testloadflags_chromescript.js
+++ b/netwerk/test/mochitests/file_testloadflags_chromescript.js
@@ -63,17 +63,17 @@ obs.prototype = {
 
     this.os.removeObserver(this, "http-on-modify-request");
     this.os = null;
   },
 };
 
 function getCookieCount(cs) {
   let count = 0;
-  for (let cookie of cs.cookies) {
+  for (let cookie of cs.enumerator) {
     info("cookie: " + cookie);
     info(
       "cookie host " +
         cookie.host +
         " path " +
         cookie.path +
         " name " +
         cookie.name +
--- a/netwerk/test/unit/head_cookies.js
+++ b/netwerk/test/unit/head_cookies.js
@@ -144,18 +144,27 @@ function do_set_cookies(uri, channel, se
     null,
     "hot=dog" + suffix,
     null,
     channel
   );
   Assert.equal(Services.cookiemgr.countCookiesFromHost(uri.host), expected[3]);
 }
 
+function do_count_enumerator(enumerator) {
+  let i = 0;
+  for (let cookie of enumerator) {
+    void cookie;
+    ++i;
+  }
+  return i;
+}
+
 function do_count_cookies() {
-  return Services.cookiemgr.cookies.length;
+  return do_count_enumerator(Services.cookiemgr.enumerator);
 }
 
 // Helper object to store cookie data.
 function Cookie(
   name,
   value,
   host,
   path,
--- a/netwerk/test/unit/test_bug411952.js
+++ b/netwerk/test/unit/test_bug411952.js
@@ -14,17 +14,17 @@ function run_test() {
       false,
       time,
       {},
       Ci.nsICookie.SAMESITE_NONE
     );
     const now = Math.floor(new Date().getTime() / 1000);
 
     var found = false;
-    for (let cookie of cm.cookies) {
+    for (let cookie of cm.enumerator) {
       if (
         cookie.host == "example.com" &&
         cookie.path == "/" &&
         cookie.name == "C"
       ) {
         Assert.ok(
           "creationTime" in cookie,
           "creationTime attribute is not accessible on the cookie"
--- a/netwerk/test/unit/test_bug526789.js
+++ b/netwerk/test/unit/test_bug526789.js
@@ -252,17 +252,17 @@ function run_test() {
   testTrailingDotCookie("http://foo.com", "foo.com");
 
   cm.removeAll();
 }
 
 function getCookieCount() {
   var count = 0;
   var cm = Cc["@mozilla.org/cookiemanager;1"].getService(Ci.nsICookieManager);
-  for (let cookie of cm.cookies) {
+  for (let cookie of cm.enumerator) {
     ++count;
   }
   return count;
 }
 
 function testDomainCookie(uriString, domain) {
   var cs = Cc["@mozilla.org/cookieService;1"].getService(Ci.nsICookieService);
   var cm = Cc["@mozilla.org/cookiemanager;1"].getService(Ci.nsICookieManager);
--- a/netwerk/test/unit/test_cookies_profile_close.js
+++ b/netwerk/test/unit/test_cookies_profile_close.js
@@ -25,19 +25,20 @@ function* do_run_test() {
   Services.prefs.setIntPref("network.cookie.cookieBehavior", 0);
 
   // Start the cookieservice.
   Services.cookies;
 
   // Set a cookie.
   let uri = NetUtil.newURI("http://foo.com");
   Services.cookies.setCookieString(uri, null, "oh=hai; max-age=1000", null);
-  let cookies = Services.cookiemgr.cookies;
-  Assert.ok(cookies.length == 1);
-  let cookie = cookies[0];
+  let enumerator = Services.cookiemgr.enumerator;
+  Assert.ok(enumerator.hasMoreElements());
+  let cookie = enumerator.getNext().QueryInterface(Ci.nsICookie);
+  Assert.ok(!enumerator.hasMoreElements());
 
   // Fire 'profile-before-change'.
   do_close_profile();
 
   // Check that the APIs behave appropriately.
   Assert.equal(Services.cookies.getCookieString(uri, null), "");
   Assert.equal(Services.cookies.getCookieStringFromHttp(uri, null, null), "");
   Services.cookies.setCookieString(uri, null, "oh2=hai", null);
@@ -51,17 +52,17 @@ function* do_run_test() {
   );
   Assert.equal(Services.cookies.getCookieString(uri, null), "");
 
   do_check_throws(function() {
     Services.cookiemgr.removeAll();
   }, Cr.NS_ERROR_NOT_AVAILABLE);
 
   do_check_throws(function() {
-    Services.cookiemgr.cookies;
+    Services.cookiemgr.enumerator;
   }, Cr.NS_ERROR_NOT_AVAILABLE);
 
   do_check_throws(function() {
     Services.cookiemgr.add(
       "foo.com",
       "",
       "oh4",
       "hai",
--- a/netwerk/test/unit/test_cookies_read.js
+++ b/netwerk/test/unit/test_cookies_read.js
@@ -22,18 +22,18 @@ function finish_test() {
 function* do_run_test() {
   // Set up a profile.
   let profile = do_get_profile();
 
   // Allow all cookies.
   Services.prefs.setIntPref("network.cookie.cookieBehavior", 0);
 
   // Start the cookieservice, to force creation of a database.
-  // Get the sessionCookies to join the initialization in cookie thread
-  Services.cookiemgr.sessionCookies;
+  // Get the sessionEnumerator to join the initialization in cookie thread
+  Services.cookiemgr.sessionEnumerator;
 
   // Open a database connection now, after synchronous initialization has
   // completed. We may not be able to open one later once asynchronous writing
   // begins.
   Assert.ok(do_get_cookie_file(profile).exists());
   let db = new CookieDatabaseConnection(do_get_cookie_file(profile), 4);
 
   for (let i = 0; i < CMAX; ++i) {
--- a/netwerk/test/unit/test_domain_eviction.js
+++ b/netwerk/test/unit/test_domain_eviction.js
@@ -51,17 +51,17 @@ function* do_run_test() {
   // Wait a while, to make sure the first batch of cookies is older than
   // the second (timer resolution varies on different platforms).
   do_timeout(100, continue_test);
   yield;
 
   setCookies("tasty.horse.radish", 50, futureExpiry);
   Assert.equal(countCookies("horse.radish", "horse.radish"), 50);
 
-  for (let cookie of Services.cookiemgr.cookies) {
+  for (let cookie of Services.cookiemgr.enumerator) {
     if (cookie.host == "horse.radish") {
       do_throw("cookies not evicted by lastAccessed order");
     }
   }
 
   // Test that expired cookies for a domain are evicted before live ones.
   let shortExpiry = Math.floor(Date.now() / 1000 + 2);
   setCookies("captchart.com", 49, futureExpiry);
@@ -120,25 +120,25 @@ function setCookies(aHost, aNumber, aExp
       {},
       Ci.nsICookie.SAMESITE_NONE
     );
   }
 }
 
 // count how many cookies are within domain 'aBaseDomain', using three
 // independent interface methods on nsICookieManager:
-// 1) 'cookies', an array of all cookies;
+// 1) 'enumerator', an enumerator of all cookies;
 // 2) 'countCookiesFromHost', which returns the number of cookies within the
 //    base domain of 'aHost',
-// 3) 'getCookiesFromHost', which returns an array of 2).
+// 3) 'getCookiesFromHost', which returns an enumerator of 2).
 function countCookies(aBaseDomain, aHost) {
-  // count how many cookies are within domain 'aBaseDomain' using the cookies
-  // array.
+  // count how many cookies are within domain 'aBaseDomain' using the cookie
+  // enumerator.
   let cookies = [];
-  for (let cookie of Services.cookiemgr.cookies) {
+  for (let cookie of Services.cookiemgr.enumerator) {
     if (
       cookie.host.length >= aBaseDomain.length &&
       cookie.host.slice(cookie.host.length - aBaseDomain.length) == aBaseDomain
     ) {
       cookies.push(cookie);
     }
   }
 
@@ -160,17 +160,17 @@ function countCookies(aBaseDomain, aHost
         if (cookies[i].host == cookie.host && cookies[i].name == cookie.name) {
           found = true;
           cookies.splice(i, 1);
           break;
         }
       }
 
       if (!found) {
-        do_throw("cookie " + cookie.name + " not found in master cookies");
+        do_throw("cookie " + cookie.name + " not found in master enumerator");
       }
     } else {
       do_throw(
         "cookie host " + cookie.host + " not within domain " + aBaseDomain
       );
     }
   }
 
--- a/netwerk/test/unit/test_eviction.js
+++ b/netwerk/test/unit/test_eviction.js
@@ -230,17 +230,17 @@ function get_creationTime(i) {
 
 // Test that 'aNumberToExpect' cookies remain after purging is complete, and
 // that the cookies that remain consist of the set expected given the number of
 // of older and newer cookies -- eviction should occur by order of lastAccessed
 // time, if both the limit on total cookies (maxNumber + 10%) and the purge age
 // + 10% are exceeded.
 function check_remaining_cookies(aNumberTotal, aNumberOld, aNumberToExpect) {
   let i = 0;
-  for (let cookie of Services.cookiemgr.cookies) {
+  for (let cookie of Services.cookiemgr.enumerator) {
     ++i;
 
     if (aNumberTotal != aNumberToExpect) {
       // make sure the cookie is one of the batch we expect was purged.
       var hostNumber = new Number(cookie.rawHost.split(".")[1]);
       if (hostNumber < aNumberOld - aNumberToExpect) {
         break;
       }
--- a/netwerk/test/unit/test_schema_2_migration.js
+++ b/netwerk/test/unit/test_schema_2_migration.js
@@ -18,18 +18,18 @@ function finish_test() {
   });
 }
 
 function* do_run_test() {
   // Set up a profile.
   let profile = do_get_profile();
 
   // Start the cookieservice, to force creation of a database.
-  // Get the sessionCookies to join the initialization in cookie thread
-  Services.cookiemgr.sessionCookies;
+  // Get the sessionEnumerator to join the initialization in cookie thread
+  Services.cookiemgr.sessionEnumerator;
 
   // Close the profile.
   do_close_profile(test_generator);
   yield;
 
   // Remove the cookie file in order to create another database file.
   do_get_cookie_file(profile).remove(false);
 
--- a/netwerk/test/unit/test_schema_3_migration.js
+++ b/netwerk/test/unit/test_schema_3_migration.js
@@ -18,18 +18,18 @@ function finish_test() {
   });
 }
 
 function* do_run_test() {
   // Set up a profile.
   let profile = do_get_profile();
 
   // Start the cookieservice, to force creation of a database.
-  // Get the sessionCookies to join the initialization in cookie thread
-  Services.cookiemgr.sessionCookies;
+  // Get the sessionEnumerator to join the initialization in cookie thread
+  Services.cookiemgr.sessionEnumerator;
 
   // Close the profile.
   do_close_profile(test_generator);
   yield;
 
   // Remove the cookie file in order to create another database file.
   do_get_cookie_file(profile).remove(false);
 
--- a/toolkit/components/cleardata/ClearDataService.jsm
+++ b/toolkit/components/cleardata/ClearDataService.jsm
@@ -68,48 +68,48 @@ const CookieCleaner = {
         aHost,
         JSON.stringify(aOriginAttributes)
       );
       aResolve();
     });
   },
 
   deleteByRange(aFrom, aTo) {
-    let cookies = Services.cookies.cookies;
+    let enumerator = Services.cookies.enumerator;
     return this._deleteInternal(
-      cookies,
+      enumerator,
       aCookie => aCookie.creationTime > aFrom
     );
   },
 
   deleteAll() {
     return new Promise(aResolve => {
       Services.cookies.removeAll();
       aResolve();
     });
   },
 
-  _deleteInternal(aCookies, aCb) {
+  _deleteInternal(aEnumerator, aCb) {
     // A number of iterations after which to yield time back to the system.
     const YIELD_PERIOD = 10;
 
     return new Promise((aResolve, aReject) => {
       let count = 0;
-      for (let cookie of aCookies) {
+      for (let cookie of aEnumerator) {
         if (aCb(cookie)) {
           Services.cookies.remove(
             cookie.host,
             cookie.name,
             cookie.path,
             cookie.originAttributes
           );
           // We don't want to block the main-thread.
           if (++count % YIELD_PERIOD == 0) {
             setTimeout(() => {
-              this._deleteInternal(aCookies, aCb).then(aResolve, aReject);
+              this._deleteInternal(aEnumerator, aCb).then(aResolve, aReject);
             }, 0);
             return;
           }
         }
       }
 
       aResolve();
     });
--- a/toolkit/components/cleardata/SiteDataTestUtils.jsm
+++ b/toolkit/components/cleardata/SiteDataTestUtils.jsm
@@ -137,17 +137,17 @@ var SiteDataTestUtils = {
       });
     });
   },
 
   hasCookies(origin) {
     let principal = Services.scriptSecurityManager.createContentPrincipalFromOrigin(
       origin
     );
-    for (let cookie of Services.cookies.cookies) {
+    for (let cookie of Services.cookies.enumerator) {
       if (
         ChromeUtils.isOriginAttributesEqual(
           principal.originAttributes,
           cookie.originAttributes
         ) &&
         cookie.host.includes(principal.URI.host)
       ) {
         return true;
--- a/toolkit/components/contextualidentity/ContextualIdentityService.jsm
+++ b/toolkit/components/contextualidentity/ContextualIdentityService.jsm
@@ -601,17 +601,17 @@ function _ContextualIdentityService(path
 
     // Collect the userContextId related to the identities that should not be cleared
     // (the ones marked as `public = false`).
     const keepDataContextIds = this.getPrivateUserContextIds();
 
     // Collect the userContextIds currently used by any stored cookie.
     let cookiesUserContextIds = new Set();
 
-    for (let cookie of Services.cookies.cookies) {
+    for (let cookie of Services.cookies.enumerator) {
       // Skip any userContextIds that should not be cleared.
       if (
         cookie.originAttributes.userContextId >= minUserContextId &&
         !keepDataContextIds.includes(cookie.originAttributes.userContextId)
       ) {
         cookiesUserContextIds.add(cookie.originAttributes.userContextId);
       }
     }
--- a/toolkit/components/extensions/test/xpcshell/test_ext_cookieBehaviors.js
+++ b/toolkit/components/extensions/test/xpcshell/test_ext_cookieBehaviors.js
@@ -49,17 +49,17 @@ server.registerPathHandler("/page-with-t
 });
 server.registerPathHandler("/sw.js", (request, response) => {
   response.setHeader("Content-Type", "text/javascript", false);
   response.write("");
 });
 
 function assertCookiesForHost(url, cookiesCount, message) {
   const { host } = new URL(url);
-  const cookies = Services.cookies.cookies.filter(
+  const cookies = Array.from(Services.cookies.enumerator).filter(
     cookie => cookie.host === host
   );
   equal(cookies.length, cookiesCount, message);
   return cookies;
 }
 
 // Test that the indexedDB and localStorage are allowed in an extension page
 // and that the indexedDB is allowed in a extension worker.
@@ -274,17 +274,17 @@ add_task(async function test_ext_page_3r
     { behavior: "BEHAVIOR_REJECT_FOREIGN", cookiesCount: 0 },
     { behavior: "BEHAVIOR_REJECT", cookiesCount: 0 },
     { behavior: "BEHAVIOR_LIMIT_FOREIGN", cookiesCount: 0 },
     { behavior: "BEHAVIOR_REJECT_TRACKER", cookiesCount: 1 },
   ];
 
   function clearAllCookies() {
     Services.cookies.removeAll();
-    let cookies = Services.cookies.cookies;
+    let cookies = Array.from(Services.cookies.enumerator);
     equal(cookies.length, 0, "There shouldn't be any cookies after clearing");
   }
 
   async function runTestRequests(extension, cookiesCount, msg) {
     for (const testRequest of testRequests) {
       clearAllCookies();
       extension.sendMessage(testRequest, testUrl);
       await extension.awaitMessage(`${testRequest}:done`);
--- a/toolkit/components/search/tests/xpcshell/test_searchSuggest_cookies.js
+++ b/toolkit/components/search/tests/xpcshell/test_searchSuggest_cookies.js
@@ -41,19 +41,19 @@ function countCacheEntries() {
       },
       true /* Do walk entries */
     );
   });
 }
 
 function countCookieEntries() {
   info("Enumerating cookies");
-  let cookies = Services.cookies.cookies;
+  let enumerator = Services.cookies.enumerator;
   let cookieCount = 0;
-  for (let cookie of cookies) {
+  for (let cookie of enumerator) {
     info(
       "Cookie:" + cookie.rawHost + " " + JSON.stringify(cookie.originAttributes)
     );
     cookieCount++;
     break;
   }
   return cookieCount;
 }
--- a/toolkit/forgetaboutsite/ForgetAboutSite.jsm
+++ b/toolkit/forgetaboutsite/ForgetAboutSite.jsm
@@ -19,19 +19,19 @@ var ForgetAboutSite = {
           errorCode => resolve(bitCounting(errorCode))
         )
       ),
     ];
 
     try {
       let baseDomain = Services.eTLD.getBaseDomainFromHost(aDomain);
 
-      let cookies = Services.cookies.cookies;
+      let enumerator = Services.cookies.enumerator;
       let hosts = new Set();
-      for (let cookie of cookies) {
+      for (let cookie of enumerator) {
         if (Services.eTLD.hasRootDomain(cookie.rawHost, baseDomain)) {
           hosts.add(cookie.rawHost);
         }
       }
 
       for (let host of hosts) {
         promises.push(
           new Promise(resolve =>
--- a/toolkit/forgetaboutsite/test/browser/browser_cookieDomain.js
+++ b/toolkit/forgetaboutsite/test/browser/browser_cookieDomain.js
@@ -1,17 +1,17 @@
 const { ForgetAboutSite } = ChromeUtils.import(
   "resource://gre/modules/ForgetAboutSite.jsm"
 );
 const { SiteDataTestUtils } = ChromeUtils.import(
   "resource://testing-common/SiteDataTestUtils.jsm"
 );
 
 function checkCookie(host, originAttributes) {
-  for (let cookie of Services.cookies.cookies) {
+  for (let cookie of Services.cookies.enumerator) {
     if (
       ChromeUtils.isOriginAttributesEqual(
         originAttributes,
         cookie.originAttributes
       ) &&
       cookie.host.includes(host)
     ) {
       return true;