diff --git a/netwerk/cookie/src/nsCookie.cpp b/netwerk/cookie/src/nsCookie.cpp index 010f4b4eecc..83b8b6e76c4 100644 --- a/netwerk/cookie/src/nsCookie.cpp +++ b/netwerk/cookie/src/nsCookie.cpp @@ -89,7 +89,6 @@ nsCookie::Create(const nsACString &aName, const nsACString &aHost, const nsACString &aPath, PRInt64 aExpiry, - PRInt64 aLastAccessed, PRInt64 aCreationID, PRBool aIsSession, PRBool aIsSecure, @@ -120,7 +119,7 @@ nsCookie::Create(const nsACString &aName, // construct the cookie. placement new, oh yeah! return new (place) nsCookie(name, value, host, path, end, - aExpiry, aLastAccessed, aCreationID, + aExpiry, aCreationID, aIsSession, aIsSecure, aIsHttpOnly); } diff --git a/netwerk/cookie/src/nsCookie.h b/netwerk/cookie/src/nsCookie.h index 4902b5ac549..957897fa7d7 100644 --- a/netwerk/cookie/src/nsCookie.h +++ b/netwerk/cookie/src/nsCookie.h @@ -70,7 +70,6 @@ class nsCookie : public nsICookie2 const char *aPath, const char *aEnd, PRInt64 aExpiry, - PRInt64 aLastAccessed, PRInt64 aCreationID, PRBool aIsSession, PRBool aIsSecure, @@ -82,7 +81,6 @@ class nsCookie : public nsICookie2 , mPath(aPath) , mEnd(aEnd) , mExpiry(aExpiry) - , mLastAccessed(aLastAccessed) , mCreationID(aCreationID) , mIsSession(aIsSession != PR_FALSE) , mIsSecure(aIsSecure != PR_FALSE) @@ -98,7 +96,6 @@ class nsCookie : public nsICookie2 const nsACString &aHost, const nsACString &aPath, PRInt64 aExpiry, - PRInt64 aLastAccessed, PRInt64 aCreationID, PRBool aIsSession, PRBool aIsSecure, @@ -113,7 +110,6 @@ class nsCookie : public nsICookie2 inline const nsDependentCString RawHost() const { return nsDependentCString(IsDomain() ? mHost + 1 : mHost, mPath - 1); } inline const nsDependentCString Path() const { return nsDependentCString(mPath, mEnd); } inline PRInt64 Expiry() const { return mExpiry; } - inline PRInt64 LastAccessed() const { return mLastAccessed; } inline PRInt64 CreationID() const { return mCreationID; } // cookie creation time, in seconds inline PRInt64 CreationTime() const { return mCreationID / PR_USEC_PER_SEC; } @@ -124,7 +120,6 @@ class nsCookie : public nsICookie2 // setters inline void SetExpiry(PRInt64 aExpiry) { mExpiry = aExpiry; } - inline void SetLastAccessed(PRInt64 aTime) { mLastAccessed = aTime; } inline void SetIsSession(PRBool aIsSession) { mIsSession = aIsSession; } // set the creation id manually, overriding the monotonicity checks in Create(). // use with caution! @@ -147,7 +142,6 @@ class nsCookie : public nsICookie2 const char *mPath; const char *mEnd; PRInt64 mExpiry; - PRInt64 mLastAccessed; // creation id is unique for each cookie and approximately represents the cookie // creation time, in microseconds. PRInt64 mCreationID; diff --git a/netwerk/cookie/src/nsCookieService.cpp b/netwerk/cookie/src/nsCookieService.cpp index 52a743da2f4..2d1fa73e7ee 100644 --- a/netwerk/cookie/src/nsCookieService.cpp +++ b/netwerk/cookie/src/nsCookieService.cpp @@ -1,4 +1,5 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +// vim:ts=2:sw=2:et: +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * @@ -82,9 +83,7 @@ static const char kHttpOnlyPrefix[] = "#HttpOnly_"; static const char kCookieFileName[] = "cookies.sqlite"; -#define COOKIES_SCHEMA_VERSION 2 - -static const PRUint32 kCookieStaleThreshold = 60; // 1 minute in seconds +#define COOKIES_SCHEMA_VERSION 1 static const char kOldCookieFileName[] = "cookies.txt"; @@ -127,6 +126,7 @@ struct nsCookieAttributes nsCAutoString expires; nsCAutoString maxage; PRInt64 expiryTime; + PRInt64 creationID; PRBool isSession; PRBool isSecure; PRBool isHttpOnly; @@ -162,17 +162,17 @@ struct nsListIter struct nsEnumerationData { nsEnumerationData(PRInt64 aCurrentTime, - PRInt64 aOldestTime) + PRInt64 aOldestID) : currentTime(aCurrentTime) - , oldestTime(aOldestTime) + , oldestID(aOldestID) , iter(nsnull, nsnull, nsnull) {} // the current time PRInt64 currentTime; - // oldest lastAccessed time in the cookie list. use aOldestTime = LL_MAXINT + // oldest creation id in the cookie list. use aOldestID = LL_MAXINT // to enable this search, LL_MININT to disable it. - PRInt64 oldestTime; + PRInt64 oldestID; // an iterator object that points to the desired cookie nsListIter iter; @@ -482,65 +482,59 @@ nsCookieService::InitDB() PRInt32 dbSchemaVersion; rv = mDBConn->GetSchemaVersion(&dbSchemaVersion); NS_ENSURE_SUCCESS(rv, rv); + + if (dbSchemaVersion == 0) { + NS_WARNING("couldn't get schema version!"); + + // the table may be usable; someone might've just clobbered the schema + // version. we can treat this case like a downgrade using the codepath + // below, by verifying the columns we care about are all there. for now, + // re-set the schema version in the db, in case the checks succeed (if + // they don't, we're dropping the table anyway). + rv = mDBConn->SetSchemaVersion(COOKIES_SCHEMA_VERSION); + NS_ENSURE_SUCCESS(rv, rv); - switch (dbSchemaVersion) { - // upgrading. - // every time you increment the database schema, you need to implement - // the upgrading code from the previous version to the new one. - case 1: - { - // add the lastAccessed column to the table - rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING( - "ALTER TABLE moz_cookies ADD lastAccessed INTEGER")); - NS_ENSURE_SUCCESS(rv, rv); + // set this to a large number, to force the downgrade codepath + dbSchemaVersion = PR_INT32_MAX; + } - // update the schema version - rv = mDBConn->SetSchemaVersion(COOKIES_SCHEMA_VERSION); - NS_ENSURE_SUCCESS(rv, rv); - } - // fall through to the next upgrade + if (dbSchemaVersion != COOKIES_SCHEMA_VERSION) { + // migration how-to: + // + // 1. increment COOKIES_SCHEMA_VERSION. + // 2. implement a method that performs up/sidegrade to your version + // from the current version. - case COOKIES_SCHEMA_VERSION: - break; - - case 0: - { - NS_WARNING("couldn't get schema version!"); - - // the table may be usable; someone might've just clobbered the schema - // version. we can treat this case like a downgrade using the codepath - // below, by verifying the columns we care about are all there. for now, - // re-set the schema version in the db, in case the checks succeed (if - // they don't, we're dropping the table anyway). - rv = mDBConn->SetSchemaVersion(COOKIES_SCHEMA_VERSION); - NS_ENSURE_SUCCESS(rv, rv); - } - // fall through to downgrade check - - // downgrading. - // if columns have been added to the table, we can still use the ones we - // understand safely. if columns have been deleted or altered, just - // blow away the table and start from scratch! if you change the way - // a column is interpreted, make sure you also change its name so this - // check will catch it. - default: - { + if (dbSchemaVersion > COOKIES_SCHEMA_VERSION) { + // downgrading. + // if columns have been added to the table, we can still use the ones we + // understand safely. if columns have been deleted or altered, just + // blow away the table and start from scratch! if you change the way + // a column is interpreted, make sure you also change its name so this + // check will catch it. + + // NOTE: if you change the code below, make sure the db schema version + // getter above still falls through to this codepath on failure! + // check if all the expected columns exist nsCOMPtr stmt; rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING( "SELECT id, name, value, host, path, expiry, isSecure, isHttpOnly " "FROM moz_cookies"), getter_AddRefs(stmt)); - if (NS_SUCCEEDED(rv)) - break; + if (NS_SUCCEEDED(rv)) { + PRBool hasResult; + rv = stmt->ExecuteStep(&hasResult); + } + + if (NS_FAILED(rv)) { + // our columns aren't there - drop the table! + rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING("DROP TABLE moz_cookies")); + NS_ENSURE_SUCCESS(rv, rv); - // our columns aren't there - drop the table! - rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING("DROP TABLE moz_cookies")); - NS_ENSURE_SUCCESS(rv, rv); - - rv = CreateTable(); - NS_ENSURE_SUCCESS(rv, rv); + rv = CreateTable(); + NS_ENSURE_SUCCESS(rv, rv); + } } - break; } } @@ -550,18 +544,14 @@ nsCookieService::InitDB() // cache frequently used statements (for insertion, deletion, and updating) rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING( "INSERT INTO moz_cookies " - "(id, name, value, host, path, expiry, lastAccessed, isSecure, isHttpOnly) " - "VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9)"), getter_AddRefs(mStmtInsert)); + "(id, name, value, host, path, expiry, isSecure, isHttpOnly) " + "VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8)"), getter_AddRefs(mStmtInsert)); NS_ENSURE_SUCCESS(rv, rv); rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING( "DELETE FROM moz_cookies WHERE id = ?1"), getter_AddRefs(mStmtDelete)); NS_ENSURE_SUCCESS(rv, rv); - rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING( - "UPDATE moz_cookies SET lastAccessed = ?1 WHERE id = ?2"), getter_AddRefs(mStmtUpdate)); - NS_ENSURE_SUCCESS(rv, rv); - // check whether to import or just read in the db if (tableExists) return Read(); @@ -590,7 +580,7 @@ nsCookieService::CreateTable() return mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING( "CREATE TABLE moz_cookies (" "id INTEGER PRIMARY KEY, name TEXT, value TEXT, host TEXT, path TEXT," - "expiry INTEGER, lastAccessed INTEGER, isSecure INTEGER, isHttpOnly INTEGER)")); + "expiry INTEGER, isSecure INTEGER, isHttpOnly INTEGER)")); } nsCookieService::~nsCookieService() @@ -609,14 +599,13 @@ nsCookieService::Observe(nsISupports *aSubject, // or is going away because the application is shutting down. RemoveAllFromMemory(); - if (!nsCRT::strcmp(aData, NS_LITERAL_STRING("shutdown-cleanse").get()) && mDBConn) { + if (!nsCRT::strcmp(aData, NS_LITERAL_STRING("shutdown-cleanse").get()) && mDBConn) // clear the cookie file if (mDBConn) { nsresult rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING("DELETE FROM moz_cookies")); if (NS_FAILED(rv)) NS_WARNING("db delete failed"); } - } } else if (!strcmp(aTopic, "profile-do-change")) { // the profile has already changed; init the db from the new location @@ -835,7 +824,6 @@ nsCookieService::Add(const nsACString &aDomain, nsRefPtr cookie = nsCookie::Create(aName, aValue, aDomain, aPath, aExpiry, - currentTimeInUsec / PR_USEC_PER_SEC, currentTimeInUsec, aIsSession, aIsSecure, @@ -905,7 +893,7 @@ nsCookieService::Read() // let the reading begin! nsCOMPtr stmt; rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING( - "SELECT id, name, value, host, path, expiry, lastAccessed, isSecure, isHttpOnly " + "SELECT id, name, value, host, path, expiry, isSecure, isHttpOnly " "FROM moz_cookies"), getter_AddRefs(stmt)); NS_ENSURE_SUCCESS(rv, rv); @@ -920,15 +908,13 @@ nsCookieService::Read() stmt->GetUTF8String(4, path); PRInt64 expiry = stmt->AsInt64(5); - PRInt64 lastAccessed = stmt->AsInt64(6); - PRBool isSecure = stmt->AsInt32(7); - PRBool isHttpOnly = stmt->AsInt32(8); + PRBool isSecure = stmt->AsInt32(6); + PRBool isHttpOnly = stmt->AsInt32(7); // create a new nsCookie and assign the data. nsCookie* newCookie = nsCookie::Create(name, value, host, path, expiry, - lastAccessed, creationID, PR_FALSE, isSecure, @@ -978,11 +964,12 @@ nsCookieService::ImportCookies(nsIFile *aCookieFile) PRBool isDomain, isHttpOnly = PR_FALSE; PRUint32 originalCookieCount = mCookieCount; - PRInt64 currentTimeInUsec = PR_Now(); - PRInt64 currentTime = currentTimeInUsec / PR_USEC_PER_SEC; - // we use lastAccessedCounter to keep cookies in recently-used order, - // so we start by initializing to currentTime (somewhat arbitrary) - PRInt64 lastAccessedCounter = currentTime; + // generate a creation id for all the cookies we're going to read in, by + // using the current time and successively decrementing it, to keep + // the most-recently-used cookie ordering. the actual creation time is + // unknown, so this is the best we can do. + PRInt64 creationIDCounter = PR_Now(); + PRInt64 currentTime = creationIDCounter / PR_USEC_PER_SEC; /* file format is: * @@ -992,9 +979,7 @@ nsCookieService::ImportCookies(nsIFile *aCookieFile) * isDomain is "TRUE" or "FALSE" (default to "FALSE") * isSecure is "TRUE" or "FALSE" (default to "TRUE") * expires is a PRInt64 integer - * note 1: cookie can contain tabs. - * note 2: cookies will be stored in order of lastAccessed time: - * most-recently used come first; least-recently-used come last. + * note: cookie can contain tabs. */ /* @@ -1050,17 +1035,13 @@ nsCookieService::ImportCookies(nsIFile *aCookieFile) } // create a new nsCookie and assign the data. - // we don't know the cookie creation time, so just use the current time; - // this is okay, since nsCookie::Create() will make sure the creation id - // ends up monotonically increasing. nsRefPtr newCookie = nsCookie::Create(Substring(buffer, nameIndex, cookieIndex - nameIndex - 1), Substring(buffer, cookieIndex, buffer.Length() - cookieIndex), host, Substring(buffer, pathIndex, secureIndex - pathIndex - 1), expires, - lastAccessedCounter, - currentTimeInUsec, + creationIDCounter, PR_FALSE, Substring(buffer, secureIndex, expiresIndex - secureIndex - 1).EqualsLiteral(kTrue), isHttpOnly); @@ -1068,9 +1049,10 @@ nsCookieService::ImportCookies(nsIFile *aCookieFile) return NS_ERROR_OUT_OF_MEMORY; } - // trick: preserve the most-recently-used cookie ordering, - // by successively decrementing the lastAccessed time - lastAccessedCounter--; + // manually set the creation id. this is okay, since nsCookie::Create() will keep + // track of the largest id we've used, and we're setting it to a smaller + // known unique one here. + newCookie->SetCreationID(--creationIDCounter); if (originalCookieCount == 0) AddCookieToList(newCookie); @@ -1143,7 +1125,6 @@ nsCookieService::GetCookieInternal(nsIURI *aHostURI, PRInt64 currentTime = PR_Now() / PR_USEC_PER_SEC; const char *currentDot = hostFromURI.get(); const char *nextDot = currentDot + 1; - PRBool stale = PR_FALSE; // begin hash lookup, walking up the subdomain levels. // we use nextDot to force a lookup of the original host (without leading dot). @@ -1191,10 +1172,8 @@ nsCookieService::GetCookieInternal(nsIURI *aHostURI, continue; } - // all checks passed - add to list and check if lastAccessed stamp needs updating + // all checks passed - add to list foundCookieList.AppendElement(cookie); - if (currentTime - cookie->LastAccessed() > kCookieStaleThreshold) - stale = PR_TRUE; } currentDot = nextDot; @@ -1203,31 +1182,13 @@ nsCookieService::GetCookieInternal(nsIURI *aHostURI, } while (currentDot); - PRInt32 count = foundCookieList.Count(); - if (count == 0) - return; - - // update lastAccessed timestamps. we only do this if the timestamp is stale - // by a certain amount, to avoid thrashing the db during pageload. - if (stale) { - // start a transaction on the storage db, to optimize updates. - // transaction will automically commit on completion. - mozStorageTransaction transaction(mDBConn, PR_TRUE); - - for (PRInt32 i = 0; i < count; ++i) { - cookie = static_cast(foundCookieList.ElementAt(i)); - - if (currentTime - cookie->LastAccessed() > kCookieStaleThreshold) - UpdateCookieInList(cookie, currentTime); - } - } - // return cookies in order of path length; longest to shortest. // this is required per RFC2109. if cookies match in length, // then sort by creation time (see bug 236772). foundCookieList.Sort(compareCookiesForSending, nsnull); nsCAutoString cookieData; + PRInt32 count = foundCookieList.Count(); for (PRInt32 i = 0; i < count; ++i) { cookie = static_cast(foundCookieList.ElementAt(i)); @@ -1281,7 +1242,9 @@ nsCookieService::SetCookieInternal(nsIURI *aHostURI, // so we can handle them separately. PRBool newCookie = ParseAttributes(aCookieHeader, cookieAttributes); + // generate a creation id for the cookie PRInt64 currentTimeInUsec = PR_Now(); + cookieAttributes.creationID = currentTimeInUsec; // calculate expiry time of cookie. cookieAttributes.isSession = GetExpiry(cookieAttributes, aServerTime, @@ -1315,8 +1278,7 @@ nsCookieService::SetCookieInternal(nsIURI *aHostURI, cookieAttributes.host, cookieAttributes.path, cookieAttributes.expiryTime, - currentTimeInUsec / PR_USEC_PER_SEC, - currentTimeInUsec, + cookieAttributes.creationID, cookieAttributes.isSession, cookieAttributes.isSecure, cookieAttributes.isHttpOnly); @@ -1398,10 +1360,6 @@ nsCookieService::AddInternal(nsCookie *aCookie, return; } - // preserve creation time of cookie - if (oldCookie) - aCookie->SetCreationID(oldCookie->CreationID()); - } else { // check if cookie has already expired if (aCookie->Expiry() <= aCurrentTime) { @@ -1423,7 +1381,7 @@ nsCookieService::AddInternal(nsCookie *aCookie, // 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; + data.oldestID = LL_MAXINT; FindOldestCookie(data); oldCookie = data.iter.current; RemoveCookieFromList(data.iter); @@ -2133,8 +2091,8 @@ nsCookieService::CountCookiesFromHostInternal(const nsACString &aHost, ++countFromHost; // check if we've found the oldest cookie so far - if (aData.oldestTime > iter.current->LastAccessed()) { - aData.oldestTime = iter.current->LastAccessed(); + if (aData.oldestID > iter.current->CreationID()) { + aData.oldestID = iter.current->CreationID(); aData.iter = iter; } } @@ -2247,13 +2205,10 @@ bindCookieParameters(mozIStorageStatement* aStmt, const nsCookie* aCookie) rv = aStmt->BindInt64Parameter(5, aCookie->Expiry()); if (NS_FAILED(rv)) return rv; - rv = aStmt->BindInt64Parameter(6, aCookie->LastAccessed()); + rv = aStmt->BindInt32Parameter(6, aCookie->IsSecure()); if (NS_FAILED(rv)) return rv; - rv = aStmt->BindInt32Parameter(7, aCookie->IsSecure()); - if (NS_FAILED(rv)) return rv; - - rv = aStmt->BindInt32Parameter(8, aCookie->IsHttpOnly()); + rv = aStmt->BindInt32Parameter(7, aCookie->IsHttpOnly()); return rv; } @@ -2293,33 +2248,6 @@ nsCookieService::AddCookieToList(nsCookie *aCookie, PRBool aWriteToDB) return PR_TRUE; } -void -nsCookieService::UpdateCookieInList(nsCookie *aCookie, PRInt64 aLastAccessed) -{ - // update the lastAccessed timestamp - aCookie->SetLastAccessed(aLastAccessed); - - // if it's a non-session cookie, update it in the db too - if (!aCookie->IsSession() && mStmtUpdate) { - // use our cached sqlite "update" statement - mozStorageStatementScoper scoper(mStmtUpdate); - - nsresult rv = mStmtUpdate->BindInt64Parameter(0, aLastAccessed); - if (NS_SUCCEEDED(rv)) { - rv = mStmtUpdate->BindInt64Parameter(1, aCookie->CreationID()); - if (NS_SUCCEEDED(rv)) { - PRBool hasResult; - rv = mStmtUpdate->ExecuteStep(&hasResult); - } - } - - if (NS_FAILED(rv)) { - NS_WARNING("db update failed!"); - COOKIE_LOGSTRING(PR_LOG_WARNING, ("UpdateCookieInList(): updating db gave error %x", rv)); - } - } -} - PR_STATIC_CALLBACK(PLDHashOperator) findOldestCallback(nsCookieEntry *aEntry, void *aArg) @@ -2327,8 +2255,8 @@ findOldestCallback(nsCookieEntry *aEntry, nsEnumerationData *data = static_cast(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(); + if (data->oldestID > iter.current->CreationID()) { + data->oldestID = iter.current->CreationID(); data->iter = iter; } } @@ -2340,4 +2268,3 @@ nsCookieService::FindOldestCookie(nsEnumerationData &aData) { mHostTable.EnumerateEntries(findOldestCallback, &aData); } - diff --git a/netwerk/cookie/src/nsCookieService.h b/netwerk/cookie/src/nsCookieService.h index 6fec4b4788a..69b33ef7988 100644 --- a/netwerk/cookie/src/nsCookieService.h +++ b/netwerk/cookie/src/nsCookieService.h @@ -173,7 +173,6 @@ class nsCookieService : public nsICookieService 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); static PRBool GetTokenValue(nsASingleFragmentCString::const_char_iterator &aIter, nsASingleFragmentCString::const_char_iterator &aEndIter, nsDependentCSubstring &aTokenString, nsDependentCSubstring &aTokenValue, PRBool &aEqualsFound); static PRBool ParseAttributes(nsDependentCString &aCookieHeader, nsCookieAttributes &aCookie); static PRBool IsIPAddress(const nsAFlatCString &aHost); @@ -196,7 +195,6 @@ class nsCookieService : public nsICookieService nsCOMPtr mDBConn; nsCOMPtr mStmtInsert; nsCOMPtr mStmtDelete; - nsCOMPtr mStmtUpdate; nsCOMPtr mObserverService; nsCOMPtr mPermissionService;