implement CountCookiesFromHost() in cookie backend for perf reasons, and update consumers to use it.bug 379239, r=mvl, sr=biesi
authordwitte@stanford.edu
Sat, 05 May 2007 14:09:54 -0700
changeset 1128 acd173b99e3b9cc178afb14131b04b8a48dd2021
parent 1127 741aa5658c9874e66347d7474f4dd8267390c0fd
child 1129 bf74f5b51c0eb73ca8db94b9694b1a4956442041
push idunknown
push userunknown
push dateunknown
reviewersmvl, biesi
bugs379239
milestone1.9a5pre
implement CountCookiesFromHost() in cookie backend for perf reasons, and update consumers to use it.bug 379239, r=mvl, sr=biesi
browser/base/content/pageinfo/security.js
extensions/cookie/nsCookiePermission.cpp
netwerk/cookie/public/nsICookieManager2.idl
netwerk/cookie/src/nsCookieService.cpp
netwerk/cookie/src/nsCookieService.h
--- a/browser/base/content/pageinfo/security.js
+++ b/browser/base/content/pageinfo/security.js
@@ -294,33 +294,19 @@ function viewCertHelper(parent, cert)
 /**
  * Return true iff we have cookies for hostName
  */
 function hostHasCookies(hostName) {
   if (!hostName)
     return false;
   
   var cookieManager = Components.classes["@mozilla.org/cookiemanager;1"]
-                                .getService(Components.interfaces.nsICookieManager);
+                                .getService(Components.interfaces.nsICookieManager2);
 
-  var iter = cookieManager.enumerator;
-  while (iter.hasMoreElements()){
-    var cookie = iter.getNext().QueryInterface(Components.interfaces.nsICookie);
-    if (!cookie)
-      continue;
-    
-    // A direct match works whether it's a domain cookie or not
-    if (cookie.host == hostName)
-      return true;
-    
-    // Domain cookies just need to end with our target hostname
-    if (cookie.isDomain && endsWith(hostName, cookie.host))
-      return true;
-  }
-  return false;
+  return cookieManager.countCookiesFromHost(hostName) > 0;
 }
 
 /**
  * Return true iff realm (proto://host:port) (extracted from location) has
  * saved passwords
  */
 function realmHasPasswords(location) {
   if (!location) 
--- a/extensions/cookie/nsCookiePermission.cpp
+++ b/extensions/cookie/nsCookiePermission.cpp
@@ -356,21 +356,27 @@ nsCookiePermission::CanSetCookie(nsIURI 
       // try to get a nsIDOMWindow from the channel...
       nsCOMPtr<nsIDOMWindow> parent;
       if (aChannel)
         NS_QueryNotificationCallbacks(aChannel, parent);
 
       // get some useful information to present to the user:
       // whether a previous cookie already exists, and how many cookies this host
       // has set
-      PRBool foundCookie;
+      PRBool foundCookie = PR_FALSE;
       PRUint32 countFromHost;
       nsCOMPtr<nsICookieManager2> cookieManager = do_GetService(NS_COOKIEMANAGER_CONTRACTID, &rv);
-      if (NS_SUCCEEDED(rv))
-        rv = cookieManager->FindMatchingCookie(aCookie, &countFromHost, &foundCookie);
+      if (NS_SUCCEEDED(rv)) {
+        nsCAutoString rawHost;
+        aCookie->GetRawHost(rawHost);
+        rv = cookieManager->CountCookiesFromHost(rawHost, &countFromHost);
+
+        if (NS_SUCCEEDED(rv) && countFromHost > 0)
+          rv = cookieManager->CookieExists(aCookie, &foundCookie);
+      }
       if (NS_FAILED(rv)) return rv;
 
       // check if the cookie we're trying to set is already expired, and return;
       // but only if there's no previous cookie, because then we need to delete the previous
       // cookie. we need this check to avoid prompting the user for already-expired cookies.
       if (!foundCookie && !*aIsSession && delta <= nsInt64(0)) {
         // the cookie has already expired. accept it, and let the backend figure
         // out it's expired, so that we get correct logging & notifications.
--- a/netwerk/cookie/public/nsICookieManager2.idl
+++ b/netwerk/cookie/public/nsICookieManager2.idl
@@ -38,17 +38,17 @@
 #include "nsICookieManager.idl"
 
 interface nsICookie2;
 
 /** 
  * Additions to the frozen nsICookieManager
  */
 
-[scriptable, uuid(3E73FF5F-154E-494f-B640-3C654BA2CC2B)]
+[scriptable, uuid(9facbb48-c05d-470b-b4da-897c8d613e00)]
 interface nsICookieManager2 : nsICookieManager
 {
   /**
    * Add a cookie. nsICookieService is the normal way to do this. This
    * method is something of a backdoor.
    *
    * @param aDomain
    *        the host or domain for which the cookie is set. presence of a
@@ -72,24 +72,29 @@ interface nsICookieManager2 : nsICookieM
            in AUTF8String aPath,
            in ACString    aName,
            in ACString    aValue,
            in boolean     aSecure,
            in boolean     aIsSession,
            in PRInt64     aExpiry);
 
   /**
-   * Find whether a matching cookie already exists, and how many cookies
-   * a given host has already set. This is useful when e.g. prompting the
-   * user whether to accept a given cookie.
+   * Find whether a given cookie already exists.
    *
    * @param aCookie
    *        the cookie to look for
-   * @param aCountFromHost
-   *        the number of cookies found whose hosts are the same as, or
-   *        subdomains of, the host field of aCookie
    *
    * @return true if a cookie was found which matches the host, path, and name
    *         fields of aCookie
    */
-  boolean findMatchingCookie(in nsICookie2     aCookie,
-                             out unsigned long aCountFromHost);
+  boolean cookieExists(in nsICookie2 aCookie);
+
+  /**
+   * Count how many cookies a given host has already set.
+   *
+   * @param aHost
+   *        the raw host string to look for, e.g. "google.com"
+   *
+   * @return the number of cookies found whose hosts are the same as, or
+   *         subdomains of, aHost
+   */
+  unsigned long countCookiesFromHost(in ACString aHost);
 };
--- a/netwerk/cookie/src/nsCookieService.cpp
+++ b/netwerk/cookie/src/nsCookieService.cpp
@@ -1427,17 +1427,17 @@ nsCookieService::AddInternal(nsCookie   
     // check if cookie has already expired
     if (aCookie->Expiry() <= aCurrentTime) {
       COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, aCookieHeader, "cookie has already expired");
       return;
     }
 
     // check if we have to delete an old cookie.
     nsEnumerationData data(aCurrentTime, LL_MAXINT);
-    if (CountCookiesFromHost(aCookie, data) >= mMaxCookiesPerHost) {
+    if (CountCookiesFromHostInternal(aCookie->RawHost(), data) >= mMaxCookiesPerHost) {
       // remove the oldest cookie from host
       oldCookie = data.iter.current;
       RemoveCookieFromList(data.iter);
 
     } else if (mCookieCount >= mMaxNumberOfCookies) {
       // try to make room, by removing expired cookies
       RemoveExpiredCookies(aCurrentTime);
 
@@ -2142,44 +2142,41 @@ removeExpiredCallback(nsCookieEntry *aEn
 
 // removes any expired cookies from memory
 void
 nsCookieService::RemoveExpiredCookies(nsInt64 aCurrentTime)
 {
   mHostTable.EnumerateEntries(removeExpiredCallback, &aCurrentTime);
 }
 
-// find whether a previous cookie has been set, and count the number of cookies from
-// this host, for prompting purposes. this is provided by the nsICookieManager2
-// interface.
+// find whether a given cookie has been previously set. this is provided by the
+// nsICookieManager2 interface.
 NS_IMETHODIMP
-nsCookieService::FindMatchingCookie(nsICookie2 *aCookie,
-                                    PRUint32   *aCountFromHost,
-                                    PRBool     *aFoundCookie)
+nsCookieService::CookieExists(nsICookie2 *aCookie,
+                              PRBool     *aFoundCookie)
 {
   NS_ENSURE_ARG_POINTER(aCookie);
 
-  // we don't care about finding the oldest cookie here, so disable the search
+  // just a placeholder
   nsEnumerationData data(NOW_IN_SECONDS, LL_MININT);
   nsCookie *cookie = NS_STATIC_CAST(nsCookie*, aCookie);
 
-  *aCountFromHost = CountCookiesFromHost(cookie, data);
   *aFoundCookie = FindCookie(cookie->Host(), cookie->Name(), cookie->Path(), data.iter);
   return NS_OK;
 }
 
-// count the number of cookies from this host, and find the oldest cookie
-// from this host.
+// count the number of cookies from a given host, and simultaneously find the
+// oldest cookie from the host.
 PRUint32
-nsCookieService::CountCookiesFromHost(nsCookie          *aCookie,
-                                      nsEnumerationData &aData)
+nsCookieService::CountCookiesFromHostInternal(const nsACString  &aHost,
+                                              nsEnumerationData &aData)
 {
   PRUint32 countFromHost = 0;
 
-  nsCAutoString hostWithDot(NS_LITERAL_CSTRING(".") + aCookie->RawHost());
+  nsCAutoString hostWithDot(NS_LITERAL_CSTRING(".") + aHost);
 
   const char *currentDot = hostWithDot.get();
   const char *nextDot = currentDot + 1;
   do {
     nsCookieEntry *entry = mHostTable.GetEntry(currentDot);
     for (nsListIter iter(entry); iter.current; ++iter) {
       // only count non-expired cookies
       if (iter.current->Expiry() > aData.currentTime) {
@@ -2197,16 +2194,29 @@ nsCookieService::CountCookiesFromHost(ns
     if (currentDot)
       nextDot = strchr(currentDot + 1, '.');
 
   } while (currentDot);
 
   return countFromHost;
 }
 
+// count the number of cookies stored by a particular host. this is provided by the
+// nsICookieManager2 interface.
+NS_IMETHODIMP
+nsCookieService::CountCookiesFromHost(const nsACString &aHost,
+                                      PRUint32         *aCountFromHost)
+{
+  // we don't care about finding the oldest cookie here, so disable the search
+  nsEnumerationData data(NOW_IN_SECONDS, LL_MININT);
+  
+  *aCountFromHost = CountCookiesFromHostInternal(aHost, data);
+  return NS_OK;
+}
+
 // find an exact previous match.
 PRBool
 nsCookieService::FindCookie(const nsAFlatCString &aHost,
                             const nsAFlatCString &aName,
                             const nsAFlatCString &aPath,
                             nsListIter           &aIter)
 {
   nsCookieEntry *entry = mHostTable.GetEntry(aHost.get());
--- a/netwerk/cookie/src/nsCookieService.h
+++ b/netwerk/cookie/src/nsCookieService.h
@@ -185,17 +185,17 @@ class nsCookieService : public nsICookie
     nsCookieStatus                CheckPrefs(nsIURI *aHostURI, nsIURI *aFirstURI, nsIChannel *aChannel, const char *aCookieHeader, nsCookiePolicy &aPolicy);
     static PRBool                 CheckDomain(nsCookieAttributes &aCookie, nsIURI *aHostURI);
     static PRBool                 CheckPath(nsCookieAttributes &aCookie, nsIURI *aHostURI);
     static PRBool                 GetExpiry(nsCookieAttributes &aCookie, nsInt64 aServerTime, nsInt64 aCurrentTime, nsCookieStatus aStatus);
     void                          RemoveAllFromMemory();
     void                          RemoveExpiredCookies(nsInt64 aCurrentTime);
     PRBool                        FindCookie(const nsAFlatCString &aHost, const nsAFlatCString &aName, const nsAFlatCString &aPath, nsListIter &aIter);
     void                          FindOldestCookie(nsEnumerationData &aData);
-    PRUint32                      CountCookiesFromHost(nsCookie *aCookie, nsEnumerationData &aData);
+    PRUint32                      CountCookiesFromHostInternal(const nsACString &aHost, nsEnumerationData &aData);
     void                          NotifyRejected(nsIURI *aHostURI);
     void                          NotifyChanged(nsICookie2 *aCookie, const PRUnichar *aData);
 
     // Use LazyWrite to save the cookies file on a timer. It will write
     // the file only once if repeatedly hammered quickly.
     void                          LazyWrite();
     static void                   DoLazyWrite(nsITimer *aTimer, void *aClosure);