Commit ae24ecb7 authored by Dão Gottwald's avatar Dão Gottwald
Browse files

merge

parents 2aa59235 ae63a93e
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -71,7 +71,6 @@ _TEST_FILES = \
  test_same_base_domain_5.html \
  test_same_base_domain_6.html \
  file_loopback_inner.html \
  test_eviction.html \
	$(NULL)

# XXX see bug 454857
+0 −106
Original line number Diff line number Diff line
<!DOCTYPE HTML>
<html>
<head>
  <title>Test for cookie eviction</title>
  <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>        
  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body onload="setupTest()">
<p id="display"></p>
<pre id="test">
<script class="testbody" type="text/javascript">
  function setupTest() {
    SimpleTest.waitForExplicitFinish();

    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");

    // twiddle prefs to convenient values for this test
    var prefs = Components.classes["@mozilla.org/preferences-service;1"]
                          .getService(Components.interfaces.nsIPrefBranch);
    prefs.setIntPref("network.cookie.purgeAge", 1);
    prefs.setIntPref("network.cookie.maxNumber", 1000);

    var cm = Components.classes["@mozilla.org/cookiemanager;1"]
                       .getService(Components.interfaces.nsICookieManager2);

    // eviction is performed based on two limits: when the total number of cookies
    // exceeds maxNumber + 10% (1100), and when cookies are older than purgeAge
    // (1 second). purging is done when both conditions are satisfied, and only
    // those cookies are purged.

    // we test the following cases of eviction:
    // 1) excess and age are satisfied, but only some of the excess are old enough
    // to be purged.
    is(testEviction(cm, 1101, 2, 50, 1051), 1051, "incorrect number of cookies");

    // 2) excess and age are satisfied, and all of the excess are old enough
    // to be purged.
    is(testEviction(cm, 1101, 2, 100, 1001), 1001, "incorrect number of cookies");

    // 3) excess and age are satisfied, and more than the excess are old enough
    // to be purged.
    is(testEviction(cm, 1101, 2, 500, 1001), 1001, "incorrect number of cookies");

    // 4) excess but not age are satisfied.
    is(testEviction(cm, 2000, 0, 0, 2000), 2000, "incorrect number of cookies");

    // 5) age but not excess are satisfied.
    is(testEviction(cm, 1100, 2, 200, 1100), 1100, "incorrect number of cookies");

    cm.removeAll();

    // reset prefs to defaults
    prefs.setIntPref("network.cookie.purgeAge", 30 * 24 * 60 * 60 * 1000000);
    prefs.setIntPref("network.cookie.maxNumber", 2000);

    SimpleTest.finish();
  }

  // test that cookies are evicted by order of lastAccessed time, if both the limit
  // on total cookies (maxNumber + 10%) and the purge age are exceeded
  function
  testEviction(aCM, aNumberTotal, aSleepDuration, aNumberAfter, aNumberToExpect)
  {
      const Ci = Components.interfaces;

      aCM.removeAll();

      var i;
      for (i = 0; i < aNumberTotal; ++i) {
        var host = "eviction." + i + ".tests";
        aCM.add(host, "", "test", "eviction", false, false, false, Math.pow(2, 62));

        if ((i == aNumberAfter - 1) && aSleepDuration) {
          // sleep a while, to make sure the first batch of cookies is older than
          // the second (timer resolution varies on different platforms).
          sleep(aSleepDuration * 1000);
        }
      }

      var enumerator = aCM.enumerator;

      i = 0;
      while (enumerator.hasMoreElements()) {
        var cookie = enumerator.getNext().QueryInterface(Ci.nsICookie2);
        ++i;

        if (aNumberTotal != aNumberToExpect) {
          var hostNumber = new Number(cookie.rawHost.split(".")[1]);
          if (hostNumber < (aNumberTotal - aNumberToExpect)) break;
        }
      }

      return i;
  }

  // delay for a number of milliseconds
  function sleep(delay)
  {
      var start = new Date().getTime();
      while (new Date().getTime() < start + delay);
  }
</script>
</pre>
</body>
</html>
+9 −14
Original line number Diff line number Diff line
@@ -52,23 +52,18 @@ interface nsIChannel;
 * list is changed, or a cookie is rejected:
 *
 * topic  : "cookie-changed"
 *          broadcast whenever the cookie list changes in some way. see
 *          explanation of data strings below.
 * subject: see below.
 *          broadcast whenever the cookie list changes in some way. there
 *          are four possible data strings for this notification; one
 *          notification will be broadcast for each change, and will involve
 *          a single cookie.
 * subject: an nsICookie2 interface pointer representing the cookie object
 *          that changed.
 * data   : "deleted"
 *          a cookie was deleted. the subject is an nsICookie2 representing
 *          the deleted cookie.
 *          a cookie was deleted. the subject is the deleted cookie.
 *          "added"
 *          a cookie was added. the subject is an nsICookie2 representing
 *          the added cookie.
 *          a cookie was added. the subject is the added cookie.
 *          "changed"
 *          a cookie was changed. the subject is an nsICookie2 representing
 *          the new cookie. (note that host, path, and name are invariant
 *          for a given cookie; other parameters may change.)
 *          "batch-deleted"
 *          a batch of cookies was deleted (for instance, as part of a purging
 *          operation). the subject is an nsIArray of nsICookie2's representing
 *          the deleted cookies.
 *          a cookie was changed. the subject is the new cookie.
 *          "cleared"
 *          the entire cookie list was cleared. the subject is null.
 *          "reload"
+67 −181
Original line number Diff line number Diff line
@@ -55,9 +55,7 @@
#include "nsILineInputStream.h"
#include "nsIEffectiveTLDService.h"

#include "nsTArray.h"
#include "nsCOMArray.h"
#include "nsIMutableArray.h"
#include "nsArrayEnumerator.h"
#include "nsAutoPtr.h"
#include "nsReadableUtils.h"
@@ -88,16 +86,12 @@ static const char kCookieFileName[] = "cookies.sqlite";
#define COOKIES_SCHEMA_VERSION 2

static const PRInt64 kCookieStaleThreshold = 60 * PR_USEC_PER_SEC; // 1 minute in microseconds
static const PRInt64 kCookiePurgeAge = 30 * 24 * 60 * 60 * PR_USEC_PER_SEC; // 30 days in microseconds

static const char kOldCookieFileName[] = "cookies.txt";

#undef  LIMIT
#define LIMIT(x, low, high, default) ((x) >= (low) && (x) <= (high) ? (x) : (default))

#undef ROUND
#define ROUND(f, t) (t((f) + 0.5))

// default limits for the cookie list. these can be tuned by the
// network.cookie.maxNumber and network.cookie.maxPerHost prefs respectively.
static const PRUint32 kMaxNumberOfCookies = 3000;
@@ -123,7 +117,6 @@ static const PRUint32 BEHAVIOR_REJECT = 2;
static const char kPrefCookiesPermissions[] = "network.cookie.cookieBehavior";
static const char kPrefMaxNumberOfCookies[] = "network.cookie.maxNumber";
static const char kPrefMaxCookiesPerHost[]  = "network.cookie.maxPerHost";
static const char kPrefCookiePurgeAge[]     = "network.cookie.purgeAge";

// struct for temporarily storing cookie attributes during header parsing
struct nsCookieAttributes
@@ -214,13 +207,7 @@ static PRLogModuleInfo *sCookieLog = PR_NewLogModule("cookie");

#define COOKIE_LOGFAILURE(a, b, c, d)    LogFailure(a, b, c, d)
#define COOKIE_LOGSUCCESS(a, b, c, d, e) LogSuccess(a, b, c, d, e)

#define COOKIE_LOGEVICTED(a)                   \
  PR_BEGIN_MACRO                               \
    if (PR_LOG_TEST(sCookieLog, PR_LOG_DEBUG)) \
      LogEvicted(a);                           \
  PR_END_MACRO

#define COOKIE_LOGEVICTED(a)             LogEvicted(a)
#define COOKIE_LOGSTRING(lvl, fmt)   \
  PR_BEGIN_MACRO                     \
    PR_LOG(sCookieLog, lvl, fmt);    \
@@ -313,6 +300,11 @@ LogSuccess(PRBool aSetCookie, nsIURI *aHostURI, const char *aCookieString, nsCoo
static void
LogEvicted(nsCookie *aCookie)
{
  // if logging isn't enabled, return now to save cycles
  if (!PR_LOG_TEST(sCookieLog, PR_LOG_DEBUG)) {
    return;
  }

  PR_LOG(sCookieLog, PR_LOG_DEBUG,("===== COOKIE EVICTED =====\n"));

  LogCookie(aCookie);
@@ -386,12 +378,10 @@ NS_IMPL_ISUPPORTS5(nsCookieService,

nsCookieService::nsCookieService()
 : mHostTable(&mDefaultHostTable)
 , mCookieOldestTime(LL_MAXINT)
 , mCookieCount(0)
 , mCookiesPermissions(BEHAVIOR_ACCEPT)
 , mMaxNumberOfCookies(kMaxNumberOfCookies)
 , mMaxCookiesPerHost(kMaxCookiesPerHost)
 , mCookiePurgeAge(kCookiePurgeAge)
{
}

@@ -412,7 +402,6 @@ nsCookieService::Init()
    prefBranch->AddObserver(kPrefCookiesPermissions, this, PR_TRUE);
    prefBranch->AddObserver(kPrefMaxNumberOfCookies, this, PR_TRUE);
    prefBranch->AddObserver(kPrefMaxCookiesPerHost,  this, PR_TRUE);
    prefBranch->AddObserver(kPrefCookiePurgeAge,     this, PR_TRUE);
    PrefChanged(prefBranch);
  }

@@ -786,19 +775,18 @@ nsCookieService::NotifyRejected(nsIURI *aHostURI)
    mObserverService->NotifyObservers(aHostURI, "cookie-rejected", nsnull);
}

// notify observers that the cookie list changed. there are five possible
// notify observers that the cookie list changed. there are four possible
// values for aData:
// "deleted" means a cookie was deleted. aSubject is the deleted cookie.
// "added"   means a cookie was added. aSubject is the added cookie.
// "changed" means a cookie was altered. aSubject is the new cookie.
// "cleared" means the entire cookie list was cleared. aSubject is null.
// "batch-deleted" means multiple cookies were deleted. aSubject is the list of cookies.
// "deleted" means a cookie was deleted. aCookie is the deleted cookie.
// "added"   means a cookie was added. aCookie is the added cookie.
// "changed" means a cookie was altered. aCookie is the new cookie.
// "cleared" means the entire cookie list was cleared. aCookie is null.
void
nsCookieService::NotifyChanged(nsISupports     *aSubject,
nsCookieService::NotifyChanged(nsICookie2      *aCookie,
                               const PRUnichar *aData)
{
  if (mObserverService)
    mObserverService->NotifyObservers(aSubject, "cookie-changed", aData);
    mObserverService->NotifyObservers(aCookie, "cookie-changed", aData);
}

/******************************************************************************
@@ -818,9 +806,6 @@ nsCookieService::PrefChanged(nsIPrefBranch *aPrefBranch)

  if (NS_SUCCEEDED(aPrefBranch->GetIntPref(kPrefMaxCookiesPerHost, &val)))
    mMaxCookiesPerHost = (PRUint16) LIMIT(val, 0, 0xFFFF, 0xFFFF);

  if (NS_SUCCEEDED(aPrefBranch->GetIntPref(kPrefCookiePurgeAge, &val)))
    mCookiePurgeAge = LIMIT(val, 0, PR_INT32_MAX, PR_INT32_MAX) * PR_USEC_PER_SEC; // convert seconds to microseconds
}

/******************************************************************************
@@ -911,7 +896,7 @@ nsCookieService::Add(const nsACString &aDomain,
    return NS_ERROR_OUT_OF_MEMORY;
  }

  AddInternal(cookie, currentTimeInUsec, nsnull, nsnull, PR_TRUE);
  AddInternal(cookie, currentTimeInUsec / PR_USEC_PER_SEC, nsnull, nsnull, PR_TRUE);
  return NS_OK;
}

@@ -1151,7 +1136,7 @@ nsCookieService::ImportCookies(nsIFile *aCookieFile)
    if (originalCookieCount == 0)
      AddCookieToList(newCookie);
    else
      AddInternal(newCookie, currentTimeInUsec, nsnull, nsnull, PR_TRUE);
      AddInternal(newCookie, currentTime, nsnull, nsnull, PR_TRUE);
  }

  COOKIE_LOGSTRING(PR_LOG_DEBUG, ("ImportCookies(): %ld cookies imported", mCookieCount));
@@ -1446,7 +1431,7 @@ nsCookieService::SetCookieInternal(nsIURI *aHostURI,

  // add the cookie to the list. AddInternal() takes care of logging.
  // we get the current time again here, since it may have changed during prompting
  AddInternal(cookie, PR_Now(), aHostURI, savedCookieHeader.get(), aFromHttp);
  AddInternal(cookie, PR_Now() / PR_USEC_PER_SEC, aHostURI, savedCookieHeader.get(), aFromHttp);
  return newCookie;
}

@@ -1457,13 +1442,11 @@ nsCookieService::SetCookieInternal(nsIURI *aHostURI,
// reached). also performs list maintenance by removing expired cookies.
void
nsCookieService::AddInternal(nsCookie   *aCookie,
                             PRInt64     aCurrentTimeInUsec,
                             PRInt64     aCurrentTime,
                             nsIURI     *aHostURI,
                             const char *aCookieHeader,
                             PRBool      aFromHttp)
{
  PRInt64 currentTime = aCurrentTimeInUsec / PR_USEC_PER_SEC;

  // if the new cookie is httponly, make sure we're not coming from script
  if (!aFromHttp && aCookie->IsHttpOnly()) {
    COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, aCookieHeader, "cookie is httponly; coming from script");
@@ -1477,7 +1460,7 @@ nsCookieService::AddInternal(nsCookie *aCookie,

  nsListIter matchIter;
  PRBool foundCookie = FindCookie(aCookie->Host(), aCookie->Name(), aCookie->Path(),
                                  matchIter, currentTime);
                                  matchIter, aCurrentTime);

  nsRefPtr<nsCookie> oldCookie;
  if (foundCookie) {
@@ -1492,7 +1475,7 @@ nsCookieService::AddInternal(nsCookie *aCookie,
    RemoveCookieFromList(matchIter);

    // check if the cookie has expired
    if (aCookie->Expiry() <= currentTime) {
    if (aCookie->Expiry() <= aCurrentTime) {
      COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, aCookieHeader, "previously stored cookie was deleted");
      NotifyChanged(oldCookie, NS_LITERAL_STRING("deleted").get());
      return;
@@ -1504,30 +1487,36 @@ nsCookieService::AddInternal(nsCookie *aCookie,

  } else {
    // check if cookie has already expired
    if (aCookie->Expiry() <= currentTime) {
    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(currentTime, LL_MAXINT);
    nsEnumerationData data(aCurrentTime, LL_MAXINT);
    if (CountCookiesFromHostInternal(aCookie->RawHost(), data) >= mMaxCookiesPerHost) {
      // remove the oldest cookie from host
      oldCookie = data.iter.current;
      COOKIE_LOGEVICTED(oldCookie);
      RemoveCookieFromList(data.iter);

      NotifyChanged(oldCookie, NS_LITERAL_STRING("deleted").get());
    } else if (mCookieCount >= mMaxNumberOfCookies) {
      // try to make room, by removing expired cookies
      RemoveExpiredCookies(aCurrentTime);

    } else if (mCookieCount >= ROUND(double(1.1) * mMaxNumberOfCookies, PRUint32) &&
               aCurrentTimeInUsec - mCookieOldestTime >= ROUND(double(1.1) * mCookiePurgeAge, PRInt64)) {
      // we're over both size and age limits by 10%; time to purge the table!
      // do this by:
      // 1) removing expired cookies;
      // 2) evicting the balance of old cookies, until we reach the size limit.
      // note that the mCookieOldestTime indicator can be pessimistic - if it's
      // older than the actual oldest cookie, we'll just purge more eagerly.
      PurgeCookies(aCurrentTimeInUsec);
      // check if we still have to get rid of something
      if (mCookieCount >= mMaxNumberOfCookies) {
        // find the position of the oldest cookie, and remove it
        data.oldestTime = LL_MAXINT;
        FindOldestCookie(data);
        oldCookie = data.iter.current;
        RemoveCookieFromList(data.iter);
      }
    }

    // if we deleted an old cookie, notify consumers
    if (oldCookie) {
      COOKIE_LOGEVICTED(oldCookie);
      NotifyChanged(oldCookie, NS_LITERAL_STRING("deleted").get());
    }
  }

@@ -2081,151 +2070,32 @@ nsCookieService::RemoveAllFromMemory()
  // which releases all their respective children.
  mHostTable->Clear();
  mCookieCount = 0;
  mCookieOldestTime = LL_MAXINT;
}

// stores temporary data for enumerating over the hash entries,
// since enumeration is done using callback functions
struct nsPurgeData
{
  nsPurgeData(PRInt64 aCurrentTime,
              PRInt64 aPurgeTime,
              nsTArray<nsListIter> &aPurgeList,
              nsIMutableArray *aRemovedList)
   : currentTime(aCurrentTime)
   , purgeTime(aPurgeTime)
   , oldestTime(LL_MAXINT)
   , purgeList(aPurgeList)
   , removedList(aRemovedList) {}

  // the current time, in seconds
  PRInt64 currentTime;

  // lastAccessed time older than which cookies are eligible for purge
  PRInt64 purgeTime;

  // lastAccessed time of the oldest cookie found during purge, to update our indicator
  PRInt64 oldestTime;

  // list of cookies over the age limit, for purging
  nsTArray<nsListIter> &purgeList;

  // list of all cookies we've removed, for notification
  nsIMutableArray *removedList;
};

// comparator class for lastaccessed times of cookies.
class CompareCookiesByAge {
  public:
    // returns true if (a == b); false otherwise.
    PRBool Equals(const nsListIter &a, const nsListIter &b) const
    {
      return a.current->LastAccessed() == b.current->LastAccessed();
    }

    // returns true if (a < b); false otherwise.
    PRBool LessThan(const nsListIter &a, const nsListIter &b) const
    {
      return a.current->LastAccessed() < b.current->LastAccessed();
    }
};

PLDHashOperator
purgeCookiesCallback(nsCookieEntry *aEntry,
removeExpiredCallback(nsCookieEntry *aEntry,
                      void          *aArg)
{
  nsPurgeData &data = *static_cast<nsPurgeData*>(aArg);
  const PRInt64 &currentTime = *static_cast<PRInt64*>(aArg);
  for (nsListIter iter(aEntry, nsnull, aEntry->Head()); iter.current; ) {
    // check if the cookie has expired
    if (iter.current->Expiry() <= data.currentTime) {
      nsCookie *cookie = iter.current;
      data.removedList->AppendElement(cookie, PR_FALSE);
      COOKIE_LOGEVICTED(cookie);

    if (iter.current->Expiry() <= currentTime)
      // remove from list. this takes care of updating the iterator for us
      nsCookieService::gCookieService->RemoveCookieFromList(iter);

    } else {
      // check if the cookie is over the age limit
      if (iter.current->LastAccessed() <= data.purgeTime) {
        data.purgeList.AppendElement(iter);

      } else if (iter.current->LastAccessed() < data.oldestTime) {
        // reset our indicator
        data.oldestTime = iter.current->LastAccessed();
      }

    else
      ++iter;
  }
  }
  return PL_DHASH_NEXT;
}

// purges expired and old cookies in a batch operation.
// removes any expired cookies from memory
void
nsCookieService::PurgeCookies(PRInt64 aCurrentTimeInUsec)
nsCookieService::RemoveExpiredCookies(PRInt64 aCurrentTime)
{
#ifdef PR_LOGGING
  PRUint32 initialCookieCount = mCookieCount;
  COOKIE_LOGSTRING(PR_LOG_DEBUG, ("PurgeCookies(): beginning purge with %ld cookies and %lld age",
                                  mCookieCount, aCurrentTimeInUsec - mCookieOldestTime));
#endif

  nsAutoTArray<nsListIter, kMaxNumberOfCookies> purgeList;

  nsCOMPtr<nsIMutableArray> removedList = do_CreateInstance(NS_ARRAY_CONTRACTID);
  if (!removedList)
    return;

  nsPurgeData data(aCurrentTimeInUsec / PR_USEC_PER_SEC, aCurrentTimeInUsec - mCookiePurgeAge, purgeList, removedList);
  mHostTable->EnumerateEntries(purgeCookiesCallback, &data);

#ifdef PR_LOGGING
  PRUint32 postExpiryCookieCount = mCookieCount;
#endif

  // now we have a list of iterators for cookies over the age limit.
  // sort them by age, and then we'll see how many to remove...
  purgeList.Sort(CompareCookiesByAge());

  // only remove old cookies until we reach the max cookie limit, no more.
  PRUint32 excess = mCookieCount - mMaxNumberOfCookies;
  //printf("count %u, maxnum %u, listlen %u, excess %d\n", mCookieCount, mMaxNumberOfCookies, list.Length(), excess);
  if (purgeList.Length() > excess) {
    // we're not purging everything in the list, so update our indicator
    data.oldestTime = purgeList[excess].current->LastAccessed();

    purgeList.SetLength(excess);
  }

  // traverse the list and remove cookies. the iterators we've stored
  // in the list aren't stable under list mutation, so we need to do a
  // fresh linked list traversal from the hash entryclass for each cookie.
  for (PRUint32 i = 0; i < purgeList.Length(); ++i) {
    for (nsListIter iter(purgeList[i].entry, nsnull, purgeList[i].entry->Head()); iter.current; ++iter) {
      if (iter.current == purgeList[i].current) {
        // remove from list. this takes care of updating the iterator for us
        nsCookie *cookie = iter.current;
        removedList->AppendElement(cookie, PR_FALSE);
        COOKIE_LOGEVICTED(cookie);

        RemoveCookieFromList(iter);
        break;
      }
    }
  }

  // take all the cookies in the removed list, and notify about them in one batch
  NotifyChanged(removedList, NS_LITERAL_STRING("batch-deleted").get());

  // reset the oldest time indicator
  mCookieOldestTime = data.oldestTime;

  COOKIE_LOGSTRING(PR_LOG_DEBUG, ("PurgeCookies(): %ld expired; %ld purged; %ld remain; %lld oldest age",
                                  initialCookieCount - postExpiryCookieCount,
                                  mCookieCount - postExpiryCookieCount,
                                  mCookieCount,
                                  aCurrentTimeInUsec - mCookieOldestTime));
  mHostTable->EnumerateEntries(removeExpiredCallback, &aCurrentTime);
  COOKIE_LOGSTRING(PR_LOG_DEBUG, ("RemoveExpiredCookies(): %ld purged; %ld remain", initialCookieCount - mCookieCount, mCookieCount));
}

// find whether a given cookie has been previously set. this is provided by the
@@ -2442,10 +2312,6 @@ nsCookieService::AddCookieToList(nsCookie *aCookie, PRBool aWriteToDB)
  entry->Head() = aCookie;
  ++mCookieCount;

  // keep track of the oldest cookie, for when it comes time to purge
  if (aCookie->LastAccessed() < mCookieOldestTime)
    mCookieOldestTime = aCookie->LastAccessed();

  // if it's a non-session cookie and hasn't just been read from the db, write it out.
  if (aWriteToDB && !aCookie->IsSession() && mStmtInsert) {
    // use our cached sqlite "insert" statement
@@ -2493,3 +2359,23 @@ nsCookieService::UpdateCookieInList(nsCookie *aCookie, PRInt64 aLastAccessed)
  }
}

static PLDHashOperator
findOldestCallback(nsCookieEntry *aEntry,
                   void          *aArg)
{
  nsEnumerationData *data = static_cast<nsEnumerationData*>(aArg);
  for (nsListIter iter(aEntry, nsnull, aEntry->Head()); iter.current; ++iter) {
    // check if we've found the oldest cookie so far
    if (data->oldestTime > iter.current->LastAccessed()) {
      data->oldestTime = iter.current->LastAccessed();
      data->iter = iter;
    }
  }
  return PL_DHASH_NEXT;
}

void
nsCookieService::FindOldestCookie(nsEnumerationData &aData)
{
  mHostTable->EnumerateEntries(findOldestCallback, &aData);
}
+5 −6
Original line number Diff line number Diff line
@@ -172,7 +172,7 @@ class nsCookieService : public nsICookieService
    void                          GetCookieInternal(nsIURI *aHostURI, nsIChannel *aChannel, PRBool aHttpBound, char **aCookie);
    nsresult                      SetCookieStringInternal(nsIURI *aHostURI, nsIPrompt *aPrompt, const char *aCookieHeader, const char *aServerTime, nsIChannel *aChannel, PRBool aFromHttp);
    PRBool                        SetCookieInternal(nsIURI *aHostURI, nsIChannel *aChannel, nsDependentCString &aCookieHeader, PRInt64 aServerTime, PRBool aFromHttp);
    void                          AddInternal(nsCookie *aCookie, PRInt64 aCurrentTimeInUsec, nsIURI *aHostURI, const char *aCookieHeader, PRBool aFromHttp);
    void                          AddInternal(nsCookie *aCookie, PRInt64 aCurrentTime, nsIURI *aHostURI, const char *aCookieHeader, PRBool aFromHttp);
    void                          RemoveCookieFromList(nsListIter &aIter);
    PRBool                        AddCookieToList(nsCookie *aCookie, PRBool aWriteToDB = PR_TRUE);
    void                          UpdateCookieInList(nsCookie *aCookie, PRInt64 aLastAccessed);
@@ -184,11 +184,12 @@ class nsCookieService : public nsICookieService
    static PRBool                 CheckPath(nsCookieAttributes &aCookie, nsIURI *aHostURI);
    static PRBool                 GetExpiry(nsCookieAttributes &aCookie, PRInt64 aServerTime, PRInt64 aCurrentTime);
    void                          RemoveAllFromMemory();
    void                          PurgeCookies(PRInt64 aCurrentTimeInUsec);
    void                          RemoveExpiredCookies(PRInt64 aCurrentTime);
    PRBool                        FindCookie(const nsAFlatCString &aHost, const nsAFlatCString &aName, const nsAFlatCString &aPath, nsListIter &aIter, PRInt64 aCurrentTime);
    void                          FindOldestCookie(nsEnumerationData &aData);
    PRUint32                      CountCookiesFromHostInternal(const nsACString &aHost, nsEnumerationData &aData);
    void                          NotifyRejected(nsIURI *aHostURI);
    void                          NotifyChanged(nsISupports *aSubject, const PRUnichar *aData);
    void                          NotifyChanged(nsICookie2 *aCookie, const PRUnichar *aData);

  protected:
    // cached members
@@ -204,21 +205,19 @@ class nsCookieService : public nsICookieService
    nsTHashtable<nsCookieEntry>  *mHostTable;
    nsTHashtable<nsCookieEntry>   mDefaultHostTable;
    nsTHashtable<nsCookieEntry>   mPrivateHostTable;
    PRInt64                       mCookieOldestTime;
    PRUint32                      mCookieCount;

    // cached prefs
    PRUint8                       mCookiesPermissions;   // BEHAVIOR_{ACCEPT, REJECTFOREIGN, REJECT}
    PRUint16                      mMaxNumberOfCookies;
    PRUint16                      mMaxCookiesPerHost;
    PRUint64                      mCookiePurgeAge;

    // private static member, used to cache a ptr to nsCookieService,
    // so we can make nsCookieService a singleton xpcom object.
    static nsCookieService        *gCookieService;

    // this callback needs access to member functions
    friend PLDHashOperator purgeCookiesCallback(nsCookieEntry *aEntry, void *aArg);
    friend PLDHashOperator removeExpiredCallback(nsCookieEntry *aEntry, void *aArg);
};

#endif // nsCookieService_h__
Loading