Loading extensions/cookie/test/Makefile.in +0 −1 Original line number Diff line number Diff line Loading @@ -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 Loading extensions/cookie/test/test_eviction.htmldeleted 100644 → 0 +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> netwerk/cookie/public/nsICookieService.idl +9 −14 Original line number Diff line number Diff line Loading @@ -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" Loading netwerk/cookie/src/nsCookieService.cpp +67 −181 Original line number Diff line number Diff line Loading @@ -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" Loading Loading @@ -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; Loading @@ -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 Loading Loading @@ -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); \ Loading Loading @@ -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); Loading Loading @@ -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) { } Loading @@ -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); } Loading Loading @@ -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); } /****************************************************************************** Loading @@ -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 } /****************************************************************************** Loading Loading @@ -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; } Loading Loading @@ -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)); Loading Loading @@ -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; } Loading @@ -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"); Loading @@ -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) { Loading @@ -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; Loading @@ -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()); } } Loading Loading @@ -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 ¤tTime = *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 Loading Loading @@ -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 Loading Loading @@ -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); } netwerk/cookie/src/nsCookieService.h +5 −6 Original line number Diff line number Diff line Loading @@ -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); Loading @@ -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 Loading @@ -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
extensions/cookie/test/Makefile.in +0 −1 Original line number Diff line number Diff line Loading @@ -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 Loading
extensions/cookie/test/test_eviction.htmldeleted 100644 → 0 +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>
netwerk/cookie/public/nsICookieService.idl +9 −14 Original line number Diff line number Diff line Loading @@ -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" Loading
netwerk/cookie/src/nsCookieService.cpp +67 −181 Original line number Diff line number Diff line Loading @@ -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" Loading Loading @@ -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; Loading @@ -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 Loading Loading @@ -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); \ Loading Loading @@ -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); Loading Loading @@ -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) { } Loading @@ -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); } Loading Loading @@ -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); } /****************************************************************************** Loading @@ -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 } /****************************************************************************** Loading Loading @@ -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; } Loading Loading @@ -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)); Loading Loading @@ -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; } Loading @@ -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"); Loading @@ -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) { Loading @@ -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; Loading @@ -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()); } } Loading Loading @@ -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 ¤tTime = *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 Loading Loading @@ -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 Loading Loading @@ -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); }
netwerk/cookie/src/nsCookieService.h +5 −6 Original line number Diff line number Diff line Loading @@ -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); Loading @@ -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 Loading @@ -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__