Bug 1595934 - Make nsICookieManager cookie enumerators return Array<nsICookie> instead of nsISimpleEnumerator; r=baku
authorEhsan Akhgari <ehsan@mozilla.com>
Sun, 17 Nov 2019 07:21:14 +0000
changeset 502348 afe80b4ff889ef7e63982b70a267d37bb38393e1
parent 502347 54819ad7decc27ca094605fbab7b7792e0feb388
child 502349 d057aee5120ff2d216e33e4ebcfe6ea92a0d29f6
push id36814
push usermalexandru@mozilla.com
push dateMon, 18 Nov 2019 09:38:52 +0000
treeherdermozilla-central@f78494c785f1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbaku
bugs1595934
milestone72.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 1595934 - Make nsICookieManager cookie enumerators return Array<nsICookie> instead of nsISimpleEnumerator; r=baku Differential Revision: https://phabricator.services.mozilla.com/D52761
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.enumerator) {
+  for (let cookie of Services.cookies.cookies) {
     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.enumerator) {
+    for (const cookie of cookieMgr.cookies) {
       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.enumerator) {
+  for (let cookie of Services.cookies.cookies) {
     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.sessionEnumerator) {
+    for (let cookie of Services.cookies.sessionCookies) {
       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.enumerator) {
+  for (var cookie of Services.cookies.cookies) {
     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.enumerator) {
+  for (var cookie2 of Services.cookies.cookies) {
     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.enumerator);
+  let cookies = Array.from(Services.cookies.cookies);
   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 enumerator = Services.cookies.enumerator;
+    let cookies = Services.cookies.cookies;
     let hosts = new Set();
-    for (let cookie of enumerator) {
+    for (let cookie of cookies) {
       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.enumerator) {
+    for (let cookie of Services.cookies.cookies) {
       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.enumerator) {
+  for (let cookie of cm.cookies) {
     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.enumerator) {
+    for (let cookie of Services.cookies.cookies) {
       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.enumerator) {
+    for (let cookie of cookieMgr.cookies) {
       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,25 +41,22 @@
 #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"
@@ -2422,57 +2419,57 @@ nsCookieService::RemoveAll() {
     }
   }
 
   NotifyChanged(nullptr, u"cleared");
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsCookieService::GetEnumerator(nsISimpleEnumerator** aEnumerator) {
+nsCookieService::GetCookies(nsTArray<RefPtr<nsICookie>>& aCookies) {
   if (!mDBState) {
     NS_WARNING("No DBState! Profile already closed?");
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   EnsureReadComplete(true);
 
-  nsCOMArray<nsICookie> cookieList(mDBState->cookieCount);
+  aCookies.SetCapacity(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) {
-      cookieList.AppendObject(cookies[i]);
+      aCookies.AppendElement(cookies[i]);
     }
   }
 
-  return NS_NewArrayEnumerator(aEnumerator, cookieList, NS_GET_IID(nsICookie));
+  return NS_OK;
 }
 
 NS_IMETHODIMP
-nsCookieService::GetSessionEnumerator(nsISimpleEnumerator** aEnumerator) {
+nsCookieService::GetSessionCookies(nsTArray<RefPtr<nsICookie>>& aCookies) {
   if (!mDBState) {
     NS_WARNING("No DBState! Profile already closed?");
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   EnsureReadComplete(true);
 
-  nsCOMArray<nsICookie> cookieList(mDBState->cookieCount);
+  aCookies.SetCapacity(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()) {
-        cookieList.AppendObject(cookie);
+        aCookies.AppendElement(cookie);
       }
     }
   }
 
-  return NS_NewArrayEnumerator(aEnumerator, cookieList, NS_GET_IID(nsICookie));
+  return NS_OK;
 }
 
 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,17 +8,16 @@
 %{ 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
  */
 
@@ -27,30 +26,30 @@ interface nsICookieManager : nsISupports
 {
 
   /**
    * Called to remove all cookies from the cookie list
    */
   void removeAll();
 
   /**
-   * 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
+   * 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
    * getCookiesWithOriginAttributes.
    */
-  readonly attribute nsISimpleEnumerator enumerator;
+  readonly attribute Array<nsICookie> 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.
+   * 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.
    */
-  readonly attribute nsISimpleEnumerator sessionEnumerator;
+  readonly attribute Array<nsICookie> sessionCookies;
 
   /**
    * 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
@@ -173,29 +172,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 enumerator of cookies that exist within the base domain of
+   * Returns an array 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 nsISimpleEnumerator of nsICookie objects.
+   * @return an array 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 sessionEnumerator to wait for the initialization in cookie thread
-const enumerator = Services.cookies.sessionEnumerator;
+// Get sessionCookies to wait for the initialization in cookie thread
+const cookies = Services.cookies.sessionCookies;
 
 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,17 +10,16 @@
 #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"
 
@@ -878,38 +877,28 @@ 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
-  nsCOMPtr<nsISimpleEnumerator> enumerator;
-  EXPECT_TRUE(
-      NS_SUCCEEDED(cookieMgr->GetEnumerator(getter_AddRefs(enumerator))));
-  int32_t i = 0;
-  bool more;
+  nsTArray<RefPtr<nsICookie>> cookies;
+  EXPECT_TRUE(NS_SUCCEEDED(cookieMgr->GetCookies(cookies)));
   nsCOMPtr<nsICookie> expiredCookie, newDomainCookie;
-  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;
+  for (const auto& cookie : cookies) {
     nsAutoCString name;
-    cookie2->GetName(name);
+    cookie->GetName(name);
     if (name.EqualsLiteral("test2"))
-      expiredCookie = cookie2;
+      expiredCookie = cookie;
     else if (name.EqualsLiteral("test3"))
-      newDomainCookie = cookie2;
+      newDomainCookie = cookie;
   }
-  EXPECT_EQ(i, 3);
+  EXPECT_EQ(cookies.Length(), 3ul);
   // 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(
@@ -930,19 +919,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()));
-  EXPECT_TRUE(
-      NS_SUCCEEDED(cookieMgr->GetEnumerator(getter_AddRefs(enumerator))) &&
-      NS_SUCCEEDED(enumerator->HasMoreElements(&more)) && !more);
+  cookies.SetLength(0);
+  EXPECT_TRUE(NS_SUCCEEDED(cookieMgr->GetCookies(cookies)) &&
+              cookies.IsEmpty());
 
   // *** 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;
@@ -999,28 +988,20 @@ 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);
 
-  EXPECT_TRUE(
-      NS_SUCCEEDED(cookieMgr->GetEnumerator(getter_AddRefs(enumerator))));
-  i = 0;
+  cookies.SetLength(0);
+  EXPECT_TRUE(NS_SUCCEEDED(cookieMgr->GetCookies(cookies)));
 
-  // 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);
+  EXPECT_TRUE(cookies.IsEmpty());
 
   // 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);
@@ -1032,49 +1013,41 @@ 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);
 
-  EXPECT_TRUE(
-      NS_SUCCEEDED(cookieMgr->GetEnumerator(getter_AddRefs(enumerator))));
-  i = 0;
+  cookies.SetLength(0);
+  EXPECT_TRUE(NS_SUCCEEDED(cookieMgr->GetCookies(cookies)));
 
   // 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;
-
-    // keep tabs on the second and third cookies, so we can check them later
-    nsCOMPtr<nsICookie> cookie2(do_QueryInterface(cookie));
-    if (!cookie2) break;
+  for (const auto& cookie : cookies) {
     nsAutoCString name;
-    cookie2->GetName(name);
+    cookie->GetName(name);
     int32_t sameSiteAttr;
-    cookie2->GetSameSite(&sameSiteAttr);
+    cookie->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(i == 6);
+  EXPECT_TRUE(cookies.Length() == 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.enumerator) {
+  for (let cookie of cs.cookies) {
     ++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.enumerator) {
+  for (let cookie of cs.cookies) {
     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.enumerator) {
+  for (let cookie of cs.cookies) {
     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,27 +144,18 @@ 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 do_count_enumerator(Services.cookiemgr.enumerator);
+  return Services.cookiemgr.cookies.length;
 }
 
 // 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.enumerator) {
+    for (let cookie of cm.cookies) {
       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.enumerator) {
+  for (let cookie of cm.cookies) {
     ++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,20 +25,19 @@ 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 enumerator = Services.cookiemgr.enumerator;
-  Assert.ok(enumerator.hasMoreElements());
-  let cookie = enumerator.getNext().QueryInterface(Ci.nsICookie);
-  Assert.ok(!enumerator.hasMoreElements());
+  let cookies = Services.cookiemgr.cookies;
+  Assert.ok(cookies.length == 1);
+  let cookie = cookies[0];
 
   // 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);
@@ -52,17 +51,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.enumerator;
+    Services.cookiemgr.cookies;
   }, 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 sessionEnumerator to join the initialization in cookie thread
-  Services.cookiemgr.sessionEnumerator;
+  // Get the sessionCookies to join the initialization in cookie thread
+  Services.cookiemgr.sessionCookies;
 
   // 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.enumerator) {
+  for (let cookie of Services.cookiemgr.cookies) {
     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) 'enumerator', an enumerator of all cookies;
+// 1) 'cookies', an array of all cookies;
 // 2) 'countCookiesFromHost', which returns the number of cookies within the
 //    base domain of 'aHost',
-// 3) 'getCookiesFromHost', which returns an enumerator of 2).
+// 3) 'getCookiesFromHost', which returns an array of 2).
 function countCookies(aBaseDomain, aHost) {
-  // count how many cookies are within domain 'aBaseDomain' using the cookie
-  // enumerator.
+  // count how many cookies are within domain 'aBaseDomain' using the cookies
+  // array.
   let cookies = [];
-  for (let cookie of Services.cookiemgr.enumerator) {
+  for (let cookie of Services.cookiemgr.cookies) {
     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 enumerator");
+        do_throw("cookie " + cookie.name + " not found in master cookies");
       }
     } 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.enumerator) {
+  for (let cookie of Services.cookiemgr.cookies) {
     ++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 sessionEnumerator to join the initialization in cookie thread
-  Services.cookiemgr.sessionEnumerator;
+  // Get the sessionCookies to join the initialization in cookie thread
+  Services.cookiemgr.sessionCookies;
 
   // 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 sessionEnumerator to join the initialization in cookie thread
-  Services.cookiemgr.sessionEnumerator;
+  // Get the sessionCookies to join the initialization in cookie thread
+  Services.cookiemgr.sessionCookies;
 
   // 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 enumerator = Services.cookies.enumerator;
+    let cookies = Services.cookies.cookies;
     return this._deleteInternal(
-      enumerator,
+      cookies,
       aCookie => aCookie.creationTime > aFrom
     );
   },
 
   deleteAll() {
     return new Promise(aResolve => {
       Services.cookies.removeAll();
       aResolve();
     });
   },
 
-  _deleteInternal(aEnumerator, aCb) {
+  _deleteInternal(aCookies, 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 aEnumerator) {
+      for (let cookie of aCookies) {
         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(aEnumerator, aCb).then(aResolve, aReject);
+              this._deleteInternal(aCookies, 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.enumerator) {
+    for (let cookie of Services.cookies.cookies) {
       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.enumerator) {
+    for (let cookie of Services.cookies.cookies) {
       // 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 = Array.from(Services.cookies.enumerator).filter(
+  const cookies = Services.cookies.cookies.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 = Array.from(Services.cookies.enumerator);
+    let cookies = Services.cookies.cookies;
     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 enumerator = Services.cookies.enumerator;
+  let cookies = Services.cookies.cookies;
   let cookieCount = 0;
-  for (let cookie of enumerator) {
+  for (let cookie of cookies) {
     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 enumerator = Services.cookies.enumerator;
+      let cookies = Services.cookies.cookies;
       let hosts = new Set();
-      for (let cookie of enumerator) {
+      for (let cookie of cookies) {
         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.enumerator) {
+  for (let cookie of Services.cookies.cookies) {
     if (
       ChromeUtils.isOriginAttributesEqual(
         originAttributes,
         cookie.originAttributes
       ) &&
       cookie.host.includes(host)
     ) {
       return true;