зеркало из https://github.com/mozilla/gecko-dev.git
Bug 591447 - Cookie rowids may collide if PR_Now() winds backward. Part 2: add triple index. r=sdwilsh, a=beta8+
This commit is contained in:
Родитель
7ff653a67a
Коммит
aef2818ff7
|
@ -75,26 +75,27 @@ StrBlockCopy(const nsACString &aSource1,
|
|||
* creation helper
|
||||
******************************************************************************/
|
||||
|
||||
// This is a counter that keeps track of the last used creation id, each time we
|
||||
// create a new nsCookie. The creation id is nominally the time (in microseconds)
|
||||
// the cookie was created. This id also corresponds to the row id used in the
|
||||
// sqlite database, which must be unique. However, since it's possible two cookies
|
||||
// may be created at the same time, or the system clock isn't monotonic, we must
|
||||
// check each id to enforce monotonicity.
|
||||
static PRInt64 gLastCreationID;
|
||||
// This is a counter that keeps track of the last used creation time, each time
|
||||
// we create a new nsCookie. This is nominally the time (in microseconds) the
|
||||
// cookie was created, but is guaranteed to be monotonically increasing for
|
||||
// cookies added at runtime after the database has been read in. This is
|
||||
// necessary to enforce ordering among cookies whose creation times would
|
||||
// otherwise overlap, since it's possible two cookies may be created at the same
|
||||
// time, or that the system clock isn't monotonic.
|
||||
static PRInt64 gLastCreationTime;
|
||||
|
||||
PRInt64
|
||||
nsCookie::GenerateCreationID(PRInt64 aCreationTime)
|
||||
nsCookie::GenerateUniqueCreationTime(PRInt64 aCreationTime)
|
||||
{
|
||||
// Check if the creation time given to us is greater than the running maximum
|
||||
// (it should always be monotonically increasing).
|
||||
if (aCreationTime > gLastCreationID) {
|
||||
gLastCreationID = aCreationTime;
|
||||
if (aCreationTime > gLastCreationTime) {
|
||||
gLastCreationTime = aCreationTime;
|
||||
return aCreationTime;
|
||||
}
|
||||
|
||||
// Make up our own.
|
||||
return ++gLastCreationID;
|
||||
return ++gLastCreationTime;
|
||||
}
|
||||
|
||||
nsCookie *
|
||||
|
@ -104,7 +105,7 @@ nsCookie::Create(const nsACString &aName,
|
|||
const nsACString &aPath,
|
||||
PRInt64 aExpiry,
|
||||
PRInt64 aLastAccessed,
|
||||
PRInt64 aCreationID,
|
||||
PRInt64 aCreationTime,
|
||||
PRBool aIsSession,
|
||||
PRBool aIsSecure,
|
||||
PRBool aIsHttpOnly)
|
||||
|
@ -125,13 +126,14 @@ nsCookie::Create(const nsACString &aName,
|
|||
StrBlockCopy(aName, aValue, aHost, aPath,
|
||||
name, value, host, path, end);
|
||||
|
||||
// If the creationID given to us is higher than the running maximum, update it.
|
||||
if (aCreationID > gLastCreationID)
|
||||
gLastCreationID = aCreationID;
|
||||
// If the creationTime given to us is higher than the running maximum, update
|
||||
// our maximum.
|
||||
if (aCreationTime > gLastCreationTime)
|
||||
gLastCreationTime = aCreationTime;
|
||||
|
||||
// construct the cookie. placement new, oh yeah!
|
||||
return new (place) nsCookie(name, value, host, path, end,
|
||||
aExpiry, aLastAccessed, aCreationID,
|
||||
aExpiry, aLastAccessed, aCreationTime,
|
||||
aIsSession, aIsSecure, aIsHttpOnly);
|
||||
}
|
||||
|
||||
|
@ -153,7 +155,7 @@ NS_IMETHODIMP nsCookie::GetIsSecure(PRBool *aIsSecure) { *aIsSecure = IsSecu
|
|||
NS_IMETHODIMP nsCookie::GetIsHttpOnly(PRBool *aHttpOnly) { *aHttpOnly = IsHttpOnly(); return NS_OK; }
|
||||
NS_IMETHODIMP nsCookie::GetStatus(nsCookieStatus *aStatus) { *aStatus = 0; return NS_OK; }
|
||||
NS_IMETHODIMP nsCookie::GetPolicy(nsCookiePolicy *aPolicy) { *aPolicy = 0; return NS_OK; }
|
||||
NS_IMETHODIMP nsCookie::GetCreationTime(PRInt64 *aCreation){ *aCreation = CreationID(); return NS_OK; }
|
||||
NS_IMETHODIMP nsCookie::GetCreationTime(PRInt64 *aCreation){ *aCreation = CreationTime(); return NS_OK; }
|
||||
NS_IMETHODIMP nsCookie::GetLastAccessed(PRInt64 *aTime) { *aTime = LastAccessed(); return NS_OK; }
|
||||
|
||||
// compatibility method, for use with the legacy nsICookie interface.
|
||||
|
|
|
@ -71,7 +71,7 @@ class nsCookie : public nsICookie2
|
|||
const char *aEnd,
|
||||
PRInt64 aExpiry,
|
||||
PRInt64 aLastAccessed,
|
||||
PRInt64 aCreationID,
|
||||
PRInt64 aCreationTime,
|
||||
PRBool aIsSession,
|
||||
PRBool aIsSecure,
|
||||
PRBool aIsHttpOnly)
|
||||
|
@ -82,7 +82,7 @@ class nsCookie : public nsICookie2
|
|||
, mEnd(aEnd)
|
||||
, mExpiry(aExpiry)
|
||||
, mLastAccessed(aLastAccessed)
|
||||
, mCreationID(aCreationID)
|
||||
, mCreationTime(aCreationTime)
|
||||
, mIsSession(aIsSession != PR_FALSE)
|
||||
, mIsSecure(aIsSecure != PR_FALSE)
|
||||
, mIsHttpOnly(aIsHttpOnly != PR_FALSE)
|
||||
|
@ -90,10 +90,9 @@ class nsCookie : public nsICookie2
|
|||
}
|
||||
|
||||
public:
|
||||
// Generate a unique creationID. This will usually be the same as the
|
||||
// creation time, but with a guarantee of monotonicity such that it can
|
||||
// be used as a sqlite rowid.
|
||||
static PRInt64 GenerateCreationID(PRInt64 aCreationTime);
|
||||
// Generate a unique and monotonically increasing creation time. See comment
|
||||
// in nsCookie.cpp.
|
||||
static PRInt64 GenerateUniqueCreationTime(PRInt64 aCreationTime);
|
||||
|
||||
// public helper to create an nsCookie object. use |operator delete|
|
||||
// to destroy an object created by this method.
|
||||
|
@ -103,7 +102,7 @@ class nsCookie : public nsICookie2
|
|||
const nsACString &aPath,
|
||||
PRInt64 aExpiry,
|
||||
PRInt64 aLastAccessed,
|
||||
PRInt64 aCreationID,
|
||||
PRInt64 aCreationTime,
|
||||
PRBool aIsSession,
|
||||
PRBool aIsSecure,
|
||||
PRBool aIsHttpOnly);
|
||||
|
@ -118,7 +117,7 @@ class nsCookie : public nsICookie2
|
|||
inline const nsDependentCString Path() const { return nsDependentCString(mPath, mEnd); }
|
||||
inline PRInt64 Expiry() const { return mExpiry; } // in seconds
|
||||
inline PRInt64 LastAccessed() const { return mLastAccessed; } // in microseconds
|
||||
inline PRInt64 CreationID() const { return mCreationID; } // in microseconds
|
||||
inline PRInt64 CreationTime() const { return mCreationTime; } // in microseconds
|
||||
inline PRBool IsSession() const { return mIsSession; }
|
||||
inline PRBool IsDomain() const { return *mHost == '.'; }
|
||||
inline PRBool IsSecure() const { return mIsSecure; }
|
||||
|
@ -128,9 +127,9 @@ class nsCookie : public nsICookie2
|
|||
inline void SetExpiry(PRInt64 aExpiry) { mExpiry = aExpiry; }
|
||||
inline void SetLastAccessed(PRInt64 aTime) { mLastAccessed = aTime; }
|
||||
inline void SetIsSession(PRBool aIsSession) { mIsSession = (PRPackedBool) aIsSession; }
|
||||
// set the creation id manually, overriding the monotonicity checks in Create().
|
||||
// use with caution!
|
||||
inline void SetCreationID(PRInt64 aID) { mCreationID = aID; }
|
||||
// Set the creation time manually, overriding the monotonicity checks in
|
||||
// Create(). Use with caution!
|
||||
inline void SetCreationTime(PRInt64 aTime) { mCreationTime = aTime; }
|
||||
|
||||
protected:
|
||||
// member variables
|
||||
|
@ -145,9 +144,7 @@ class nsCookie : public nsICookie2
|
|||
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;
|
||||
PRInt64 mCreationTime;
|
||||
PRPackedBool mIsSession;
|
||||
PRPackedBool mIsSecure;
|
||||
PRPackedBool mIsHttpOnly;
|
||||
|
|
|
@ -100,7 +100,7 @@ static nsCookieService *gCookieService;
|
|||
static const char kHttpOnlyPrefix[] = "#HttpOnly_";
|
||||
|
||||
static const char kCookieFileName[] = "cookies.sqlite";
|
||||
#define COOKIES_SCHEMA_VERSION 3
|
||||
#define COOKIES_SCHEMA_VERSION 4
|
||||
|
||||
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
|
||||
|
@ -284,10 +284,9 @@ LogCookie(nsCookie *aCookie)
|
|||
PR_LOG(sCookieLog, PR_LOG_DEBUG,
|
||||
("expires: %s%s", timeString, aCookie->IsSession() ? " (at end of session)" : ""));
|
||||
|
||||
PR_ExplodeTime(aCookie->CreationID(), PR_GMTParameters, &explodedTime);
|
||||
PR_ExplodeTime(aCookie->CreationTime(), PR_GMTParameters, &explodedTime);
|
||||
PR_FormatTimeUSEnglish(timeString, 40, "%c GMT", &explodedTime);
|
||||
PR_LOG(sCookieLog, PR_LOG_DEBUG,
|
||||
("created: %s (id %lld)", timeString, aCookie->CreationID()));
|
||||
PR_LOG(sCookieLog, PR_LOG_DEBUG,("created: %s", timeString));
|
||||
|
||||
PR_LOG(sCookieLog, PR_LOG_DEBUG,("is secure: %s\n", aCookie->IsSecure() ? "true" : "false"));
|
||||
PR_LOG(sCookieLog, PR_LOG_DEBUG,("is httpOnly: %s\n", aCookie->IsHttpOnly() ? "true" : "false"));
|
||||
|
@ -751,6 +750,9 @@ nsCookieService::TryInitDB(PRBool aDeleteExistingDB)
|
|||
rv = mDBState->dbConn->GetSchemaVersion(&dbSchemaVersion);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Start a transaction for the whole migration block.
|
||||
mozStorageTransaction transaction(mDBState->dbConn, PR_TRUE);
|
||||
|
||||
switch (dbSchemaVersion) {
|
||||
// upgrading.
|
||||
// every time you increment the database schema, you need to implement
|
||||
|
@ -766,8 +768,6 @@ nsCookieService::TryInitDB(PRBool aDeleteExistingDB)
|
|||
|
||||
case 2:
|
||||
{
|
||||
mozStorageTransaction transaction(mDBState->dbConn, PR_TRUE);
|
||||
|
||||
// Add the baseDomain column and index to the table.
|
||||
rv = mDBState->dbConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||
"ALTER TABLE moz_cookies ADD baseDomain TEXT"));
|
||||
|
@ -783,7 +783,7 @@ nsCookieService::TryInitDB(PRBool aDeleteExistingDB)
|
|||
|
||||
nsCOMPtr<mozIStorageStatement> update;
|
||||
rv = mDBState->dbConn->CreateStatement(NS_LITERAL_CSTRING(
|
||||
"UPDATE moz_cookies SET baseDomain = ?1 WHERE id = ?2"),
|
||||
"UPDATE moz_cookies SET baseDomain = :baseDomain WHERE id = :id"),
|
||||
getter_AddRefs(update));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
|
@ -805,9 +805,11 @@ nsCookieService::TryInitDB(PRBool aDeleteExistingDB)
|
|||
|
||||
mozStorageStatementScoper scoper(update);
|
||||
|
||||
rv = update->BindUTF8StringByIndex(0, baseDomain);
|
||||
rv = update->BindUTF8StringByName(NS_LITERAL_CSTRING("baseDomain"),
|
||||
baseDomain);
|
||||
NS_ASSERT_SUCCESS(rv);
|
||||
rv = update->BindInt64ByIndex(1, id);
|
||||
rv = update->BindInt64ByName(NS_LITERAL_CSTRING("id"),
|
||||
id);
|
||||
NS_ASSERT_SUCCESS(rv);
|
||||
|
||||
rv = update->ExecuteStep(&hasResult);
|
||||
|
@ -818,13 +820,59 @@ nsCookieService::TryInitDB(PRBool aDeleteExistingDB)
|
|||
rv = mDBState->dbConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||
"CREATE INDEX moz_basedomain ON moz_cookies (baseDomain)"));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
// Fall through to the next upgrade.
|
||||
|
||||
// Update the schema version.
|
||||
rv = mDBState->dbConn->SetSchemaVersion(COOKIES_SCHEMA_VERSION);
|
||||
case 3:
|
||||
{
|
||||
// Add the creationTime column to the table.
|
||||
rv = mDBState->dbConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||
"ALTER TABLE moz_cookies ADD creationTime INTEGER"));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Read in the rowids from the database...
|
||||
nsCOMPtr<mozIStorageStatement> select;
|
||||
rv = mDBState->dbConn->CreateStatement(NS_LITERAL_CSTRING(
|
||||
"SELECT id FROM moz_cookies"), getter_AddRefs(select));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// ... and use them to generate the creationTime.
|
||||
nsCOMPtr<mozIStorageStatement> update;
|
||||
rv = mDBState->dbConn->CreateStatement(NS_LITERAL_CSTRING(
|
||||
"UPDATE moz_cookies SET creationTime = :id WHERE id = :id"),
|
||||
getter_AddRefs(update));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
PRBool hasResult;
|
||||
while (1) {
|
||||
rv = select->ExecuteStep(&hasResult);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!hasResult)
|
||||
break;
|
||||
|
||||
mozStorageStatementScoper scoper(update);
|
||||
|
||||
PRInt64 id = select->AsInt64(0);
|
||||
rv = update->BindInt64ByName(NS_LITERAL_CSTRING("id"), id);
|
||||
NS_ASSERT_SUCCESS(rv);
|
||||
|
||||
rv = update->ExecuteStep(&hasResult);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
// Create a unique index on (name, host, path) to allow fast lookup.
|
||||
rv = mDBState->dbConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||
"CREATE UNIQUE INDEX moz_uniqueid "
|
||||
"ON moz_cookies (name, host, path)"));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
// Fall through to the next upgrade.
|
||||
|
||||
// No more upgrades. Update the schema version.
|
||||
rv = mDBState->dbConn->SetSchemaVersion(COOKIES_SCHEMA_VERSION);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
case COOKIES_SCHEMA_VERSION:
|
||||
break;
|
||||
|
||||
|
@ -862,6 +910,7 @@ nsCookieService::TryInitDB(PRBool aDeleteExistingDB)
|
|||
"path, "
|
||||
"expiry, "
|
||||
"lastAccessed, "
|
||||
"creationTime, "
|
||||
"isSecure, "
|
||||
"isHttpOnly "
|
||||
"FROM moz_cookies"), getter_AddRefs(stmt));
|
||||
|
@ -885,7 +934,6 @@ nsCookieService::TryInitDB(PRBool aDeleteExistingDB)
|
|||
// cache frequently used statements (for insertion, deletion, and updating)
|
||||
rv = mDBState->dbConn->CreateStatement(NS_LITERAL_CSTRING(
|
||||
"INSERT INTO moz_cookies ("
|
||||
"id, "
|
||||
"baseDomain, "
|
||||
"name, "
|
||||
"value, "
|
||||
|
@ -893,19 +941,33 @@ nsCookieService::TryInitDB(PRBool aDeleteExistingDB)
|
|||
"path, "
|
||||
"expiry, "
|
||||
"lastAccessed, "
|
||||
"creationTime, "
|
||||
"isSecure, "
|
||||
"isHttpOnly"
|
||||
") VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10)"),
|
||||
") VALUES ("
|
||||
":baseDomain, "
|
||||
":name, "
|
||||
":value, "
|
||||
":host, "
|
||||
":path, "
|
||||
":expiry, "
|
||||
":lastAccessed, "
|
||||
":creationTime, "
|
||||
":isSecure, "
|
||||
":isHttpOnly"
|
||||
")"),
|
||||
getter_AddRefs(mDBState->stmtInsert));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = mDBState->dbConn->CreateStatement(NS_LITERAL_CSTRING(
|
||||
"DELETE FROM moz_cookies WHERE id = ?1"),
|
||||
"DELETE FROM moz_cookies "
|
||||
"WHERE name = :name AND host = :host AND path = :path"),
|
||||
getter_AddRefs(mDBState->stmtDelete));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = mDBState->dbConn->CreateStatement(NS_LITERAL_CSTRING(
|
||||
"UPDATE moz_cookies SET lastAccessed = ?1 WHERE id = ?2"),
|
||||
"UPDATE moz_cookies SET lastAccessed = :lastAccessed "
|
||||
"WHERE name = :name AND host = :host AND path = :path"),
|
||||
getter_AddRefs(mDBState->stmtUpdate));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
|
@ -954,8 +1016,10 @@ nsCookieService::CreateTable()
|
|||
"path TEXT, "
|
||||
"expiry INTEGER, "
|
||||
"lastAccessed INTEGER, "
|
||||
"creationTime INTEGER, "
|
||||
"isSecure INTEGER, "
|
||||
"isHttpOnly INTEGER"
|
||||
"isHttpOnly INTEGER, "
|
||||
"CONSTRAINT moz_uniqueid UNIQUE (name, host, path)"
|
||||
")"));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
|
@ -1348,7 +1412,7 @@ nsCookieService::Add(const nsACString &aHost,
|
|||
nsCookie::Create(aName, aValue, host, aPath,
|
||||
aExpiry,
|
||||
currentTimeInUsec,
|
||||
nsCookie::GenerateCreationID(currentTimeInUsec),
|
||||
nsCookie::GenerateUniqueCreationTime(currentTimeInUsec),
|
||||
aIsSession,
|
||||
aIsSecure,
|
||||
aIsHttpOnly);
|
||||
|
@ -1380,8 +1444,7 @@ nsCookieService::Remove(const nsACString &aHost,
|
|||
host,
|
||||
PromiseFlatCString(aName),
|
||||
PromiseFlatCString(aPath),
|
||||
matchIter,
|
||||
PR_Now() / PR_USEC_PER_SEC)) {
|
||||
matchIter)) {
|
||||
nsRefPtr<nsCookie> cookie = matchIter.Cookie();
|
||||
RemoveCookieFromList(matchIter);
|
||||
NotifyChanged(cookie, NS_LITERAL_STRING("deleted").get());
|
||||
|
@ -1417,13 +1480,13 @@ nsCookieService::Read()
|
|||
nsCOMPtr<mozIStorageStatement> stmt;
|
||||
nsresult rv = mDefaultDBState.dbConn->CreateStatement(NS_LITERAL_CSTRING(
|
||||
"SELECT "
|
||||
"id, "
|
||||
"name, "
|
||||
"value, "
|
||||
"host, "
|
||||
"path, "
|
||||
"expiry, "
|
||||
"lastAccessed, "
|
||||
"creationTime, "
|
||||
"isSecure, "
|
||||
"isHttpOnly, "
|
||||
"baseDomain "
|
||||
|
@ -1448,29 +1511,27 @@ template<class T> nsCookie*
|
|||
nsCookieService::GetCookieFromRow(T &aRow)
|
||||
{
|
||||
// Skip reading 'baseDomain' -- up to the caller.
|
||||
PRInt64 creationID = aRow->AsInt64(0);
|
||||
|
||||
nsCString name, value, host, path;
|
||||
nsresult rv = aRow->GetUTF8String(1, name);
|
||||
nsresult rv = aRow->GetUTF8String(0, name);
|
||||
NS_ASSERT_SUCCESS(rv);
|
||||
rv = aRow->GetUTF8String(2, value);
|
||||
rv = aRow->GetUTF8String(1, value);
|
||||
NS_ASSERT_SUCCESS(rv);
|
||||
rv = aRow->GetUTF8String(3, host);
|
||||
rv = aRow->GetUTF8String(2, host);
|
||||
NS_ASSERT_SUCCESS(rv);
|
||||
rv = aRow->GetUTF8String(4, path);
|
||||
rv = aRow->GetUTF8String(3, path);
|
||||
NS_ASSERT_SUCCESS(rv);
|
||||
|
||||
PRInt64 expiry = aRow->AsInt64(5);
|
||||
PRInt64 lastAccessed = aRow->AsInt64(6);
|
||||
PRInt64 expiry = aRow->AsInt64(4);
|
||||
PRInt64 lastAccessed = aRow->AsInt64(5);
|
||||
PRInt64 creationTime = aRow->AsInt64(6);
|
||||
PRBool isSecure = 0 != aRow->AsInt32(7);
|
||||
PRBool isHttpOnly = 0 != aRow->AsInt32(8);
|
||||
|
||||
// Create a new nsCookie and assign the data. We are guaranteed that the
|
||||
// creationID is unique, since we're reading it from the db itself.
|
||||
// Create a new nsCookie and assign the data.
|
||||
return nsCookie::Create(name, value, host, path,
|
||||
expiry,
|
||||
lastAccessed,
|
||||
creationID,
|
||||
creationTime,
|
||||
PR_FALSE,
|
||||
isSecure,
|
||||
isHttpOnly);
|
||||
|
@ -1580,13 +1641,13 @@ nsCookieService::EnsureReadDomain(const nsCString &aBaseDomain)
|
|||
// Cache the statement, since it's likely to be used again.
|
||||
rv = mDefaultDBState.syncConn->CreateStatement(NS_LITERAL_CSTRING(
|
||||
"SELECT "
|
||||
"id, "
|
||||
"name, "
|
||||
"value, "
|
||||
"host, "
|
||||
"path, "
|
||||
"expiry, "
|
||||
"lastAccessed, "
|
||||
"creationTime, "
|
||||
"isSecure, "
|
||||
"isHttpOnly "
|
||||
"FROM moz_cookies "
|
||||
|
@ -1648,13 +1709,13 @@ nsCookieService::EnsureReadComplete()
|
|||
nsCOMPtr<mozIStorageStatement> stmt;
|
||||
nsresult rv = mDefaultDBState.syncConn->CreateStatement(NS_LITERAL_CSTRING(
|
||||
"SELECT "
|
||||
"id, "
|
||||
"name, "
|
||||
"value, "
|
||||
"host, "
|
||||
"path, "
|
||||
"expiry, "
|
||||
"lastAccessed, "
|
||||
"creationTime, "
|
||||
"isSecure, "
|
||||
"isHttpOnly, "
|
||||
"baseDomain "
|
||||
|
@ -1808,9 +1869,8 @@ nsCookieService::ImportCookies(nsIFile *aCookieFile)
|
|||
if (NS_FAILED(rv))
|
||||
continue;
|
||||
|
||||
// Create a new nsCookie and assign the data.
|
||||
// We don't know the cookie creation time, so just use the current time
|
||||
// to generate a unique creationID.
|
||||
// Create a new nsCookie and assign the data. We don't know the cookie
|
||||
// creation time, so just use the current time to generate a unique one.
|
||||
nsRefPtr<nsCookie> newCookie =
|
||||
nsCookie::Create(Substring(buffer, nameIndex, cookieIndex - nameIndex - 1),
|
||||
Substring(buffer, cookieIndex, buffer.Length() - cookieIndex),
|
||||
|
@ -1818,7 +1878,7 @@ nsCookieService::ImportCookies(nsIFile *aCookieFile)
|
|||
Substring(buffer, pathIndex, secureIndex - pathIndex - 1),
|
||||
expires,
|
||||
lastAccessedCounter,
|
||||
nsCookie::GenerateCreationID(currentTimeInUsec),
|
||||
nsCookie::GenerateUniqueCreationTime(currentTimeInUsec),
|
||||
PR_FALSE,
|
||||
Substring(buffer, secureIndex, expiresIndex - secureIndex - 1).EqualsLiteral(kTrue),
|
||||
isHttpOnly);
|
||||
|
@ -1873,8 +1933,8 @@ class CompareCookiesForSending
|
|||
public:
|
||||
PRBool Equals(const nsCookie* aCookie1, const nsCookie* aCookie2) const
|
||||
{
|
||||
// CreationID is unique, so two id's can never be equal.
|
||||
return PR_FALSE;
|
||||
return aCookie1->CreationTime() == aCookie2->CreationTime() &&
|
||||
aCookie2->Path().Length() == aCookie1->Path().Length();
|
||||
}
|
||||
|
||||
PRBool LessThan(const nsCookie* aCookie1, const nsCookie* aCookie2) const
|
||||
|
@ -1888,8 +1948,7 @@ public:
|
|||
// required for backwards compatibility since some websites erroneously
|
||||
// depend on receiving cookies in the order in which they were sent to the
|
||||
// browser! see bug 236772.
|
||||
// note: CreationID is unique, so two id's can never be equal.
|
||||
return aCookie1->CreationID() < aCookie2->CreationID();
|
||||
return aCookie1->CreationTime() < aCookie2->CreationTime();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -2142,7 +2201,7 @@ nsCookieService::SetCookieInternal(nsIURI *aHostURI,
|
|||
cookieAttributes.path,
|
||||
cookieAttributes.expiryTime,
|
||||
currentTimeInUsec,
|
||||
nsCookie::GenerateCreationID(currentTimeInUsec),
|
||||
nsCookie::GenerateUniqueCreationTime(currentTimeInUsec),
|
||||
cookieAttributes.isSession,
|
||||
cookieAttributes.isSecure,
|
||||
cookieAttributes.isHttpOnly);
|
||||
|
@ -2203,30 +2262,35 @@ nsCookieService::AddInternal(const nsCString &aBaseDomain,
|
|||
|
||||
nsListIter matchIter;
|
||||
PRBool foundCookie = FindCookie(aBaseDomain, aCookie->Host(),
|
||||
aCookie->Name(), aCookie->Path(), matchIter, currentTime);
|
||||
aCookie->Name(), aCookie->Path(), matchIter);
|
||||
|
||||
nsRefPtr<nsCookie> oldCookie;
|
||||
if (foundCookie) {
|
||||
oldCookie = matchIter.Cookie();
|
||||
|
||||
// if the old cookie is httponly, make sure we're not coming from script
|
||||
if (!aFromHttp && oldCookie->IsHttpOnly()) {
|
||||
// If the old cookie is httponly, make sure we're not coming from script --
|
||||
// but, if the old cookie has already expired, pretend like it didn't exist.
|
||||
if (!aFromHttp && oldCookie->IsHttpOnly() &&
|
||||
oldCookie->Expiry() > currentTime) {
|
||||
COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, aCookieHeader, "previously stored cookie is httponly; coming from script");
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove the old cookie, regardless of whether it's expired or not, and
|
||||
// notify.
|
||||
RemoveCookieFromList(matchIter);
|
||||
|
||||
// check if the cookie has expired
|
||||
if (aCookie->Expiry() <= currentTime) {
|
||||
COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, aCookieHeader, "previously stored cookie was deleted");
|
||||
NotifyChanged(oldCookie, NS_LITERAL_STRING("deleted").get());
|
||||
return;
|
||||
}
|
||||
COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, aCookieHeader, "previously stored cookie was deleted");
|
||||
NotifyChanged(oldCookie, NS_LITERAL_STRING("deleted").get());
|
||||
|
||||
// preserve creation time of cookie
|
||||
// If the new cookie has expired -- i.e. the intent was simply to delete
|
||||
// the old cookie -- then we're done.
|
||||
if (aCookie->Expiry() <= currentTime)
|
||||
return;
|
||||
|
||||
// Preserve creation time of cookie for ordering purposes.
|
||||
if (oldCookie)
|
||||
aCookie->SetCreationID(oldCookie->CreationID());
|
||||
aCookie->SetCreationTime(oldCookie->CreationTime());
|
||||
|
||||
} else {
|
||||
// check if cookie has already expired
|
||||
|
@ -2916,18 +2980,18 @@ class CompareCookiesByAge {
|
|||
public:
|
||||
PRBool Equals(const nsListIter &a, const nsListIter &b) const
|
||||
{
|
||||
// CreationID is unique, so two id's can never be equal.
|
||||
return PR_FALSE;
|
||||
return a.Cookie()->LastAccessed() == b.Cookie()->LastAccessed() &&
|
||||
a.Cookie()->CreationTime() == b.Cookie()->CreationTime();
|
||||
}
|
||||
|
||||
PRBool LessThan(const nsListIter &a, const nsListIter &b) const
|
||||
{
|
||||
// compare by LastAccessed time, and tiebreak by CreationID.
|
||||
// compare by lastAccessed time, and tiebreak by creationTime.
|
||||
PRInt64 result = a.Cookie()->LastAccessed() - b.Cookie()->LastAccessed();
|
||||
if (result != 0)
|
||||
return result < 0;
|
||||
|
||||
return a.Cookie()->CreationID() < b.Cookie()->CreationID();
|
||||
return a.Cookie()->CreationTime() < b.Cookie()->CreationTime();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -3094,8 +3158,7 @@ nsCookieService::CookieExists(nsICookie2 *aCookie,
|
|||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsListIter iter;
|
||||
*aFoundCookie = FindCookie(baseDomain, host, name, path, iter,
|
||||
PR_Now() / PR_USEC_PER_SEC);
|
||||
*aFoundCookie = FindCookie(baseDomain, host, name, path, iter);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -3194,8 +3257,7 @@ nsCookieService::FindCookie(const nsCString &aBaseDomain,
|
|||
const nsAFlatCString &aHost,
|
||||
const nsAFlatCString &aName,
|
||||
const nsAFlatCString &aPath,
|
||||
nsListIter &aIter,
|
||||
PRInt64 aCurrentTime)
|
||||
nsListIter &aIter)
|
||||
{
|
||||
EnsureReadDomain(aBaseDomain);
|
||||
|
||||
|
@ -3207,8 +3269,7 @@ nsCookieService::FindCookie(const nsCString &aBaseDomain,
|
|||
for (nsCookieEntry::IndexType i = 0; i < cookies.Length(); ++i) {
|
||||
nsCookie *cookie = cookies[i];
|
||||
|
||||
if (cookie->Expiry() > aCurrentTime &&
|
||||
aHost.Equals(cookie->Host()) &&
|
||||
if (aHost.Equals(cookie->Host()) &&
|
||||
aPath.Equals(cookie->Path()) &&
|
||||
aName.Equals(cookie->Name())) {
|
||||
aIter = nsListIter(entry, i);
|
||||
|
@ -3237,7 +3298,16 @@ nsCookieService::RemoveCookieFromList(const nsListIter &aIter,
|
|||
nsCOMPtr<mozIStorageBindingParams> params;
|
||||
paramsArray->NewBindingParams(getter_AddRefs(params));
|
||||
|
||||
nsresult rv = params->BindInt64ByIndex(0, aIter.Cookie()->CreationID());
|
||||
nsresult rv = params->BindUTF8StringByName(NS_LITERAL_CSTRING("name"),
|
||||
aIter.Cookie()->Name());
|
||||
NS_ASSERT_SUCCESS(rv);
|
||||
|
||||
rv = params->BindUTF8StringByName(NS_LITERAL_CSTRING("host"),
|
||||
aIter.Cookie()->Host());
|
||||
NS_ASSERT_SUCCESS(rv);
|
||||
|
||||
rv = params->BindUTF8StringByName(NS_LITERAL_CSTRING("path"),
|
||||
aIter.Cookie()->Path());
|
||||
NS_ASSERT_SUCCESS(rv);
|
||||
|
||||
rv = paramsArray->AddParams(params);
|
||||
|
@ -3283,34 +3353,44 @@ bindCookieParameters(mozIStorageBindingParamsArray *aParamsArray,
|
|||
NS_ASSERT_SUCCESS(rv);
|
||||
|
||||
// Bind our values to params
|
||||
rv = params->BindInt64ByIndex(0, aCookie->CreationID());
|
||||
rv = params->BindUTF8StringByName(NS_LITERAL_CSTRING("baseDomain"),
|
||||
aBaseDomain);
|
||||
NS_ASSERT_SUCCESS(rv);
|
||||
|
||||
rv = params->BindUTF8StringByIndex(1, aBaseDomain);
|
||||
rv = params->BindUTF8StringByName(NS_LITERAL_CSTRING("name"),
|
||||
aCookie->Name());
|
||||
NS_ASSERT_SUCCESS(rv);
|
||||
|
||||
rv = params->BindUTF8StringByIndex(2, aCookie->Name());
|
||||
rv = params->BindUTF8StringByName(NS_LITERAL_CSTRING("value"),
|
||||
aCookie->Value());
|
||||
NS_ASSERT_SUCCESS(rv);
|
||||
|
||||
rv = params->BindUTF8StringByIndex(3, aCookie->Value());
|
||||
rv = params->BindUTF8StringByName(NS_LITERAL_CSTRING("host"),
|
||||
aCookie->Host());
|
||||
NS_ASSERT_SUCCESS(rv);
|
||||
|
||||
rv = params->BindUTF8StringByIndex(4, aCookie->Host());
|
||||
rv = params->BindUTF8StringByName(NS_LITERAL_CSTRING("path"),
|
||||
aCookie->Path());
|
||||
NS_ASSERT_SUCCESS(rv);
|
||||
|
||||
rv = params->BindUTF8StringByIndex(5, aCookie->Path());
|
||||
rv = params->BindInt64ByName(NS_LITERAL_CSTRING("expiry"),
|
||||
aCookie->Expiry());
|
||||
NS_ASSERT_SUCCESS(rv);
|
||||
|
||||
rv = params->BindInt64ByIndex(6, aCookie->Expiry());
|
||||
rv = params->BindInt64ByName(NS_LITERAL_CSTRING("lastAccessed"),
|
||||
aCookie->LastAccessed());
|
||||
NS_ASSERT_SUCCESS(rv);
|
||||
|
||||
rv = params->BindInt64ByIndex(7, aCookie->LastAccessed());
|
||||
rv = params->BindInt64ByName(NS_LITERAL_CSTRING("creationTime"),
|
||||
aCookie->CreationTime());
|
||||
NS_ASSERT_SUCCESS(rv);
|
||||
|
||||
rv = params->BindInt32ByIndex(8, aCookie->IsSecure());
|
||||
rv = params->BindInt32ByName(NS_LITERAL_CSTRING("isSecure"),
|
||||
aCookie->IsSecure());
|
||||
NS_ASSERT_SUCCESS(rv);
|
||||
|
||||
rv = params->BindInt32ByIndex(9, aCookie->IsHttpOnly());
|
||||
rv = params->BindInt32ByName(NS_LITERAL_CSTRING("isHttpOnly"),
|
||||
aCookie->IsHttpOnly());
|
||||
NS_ASSERT_SUCCESS(rv);
|
||||
|
||||
// Bind the params to the array.
|
||||
|
@ -3378,9 +3458,20 @@ nsCookieService::UpdateCookieInList(nsCookie *aCookie,
|
|||
aParamsArray->NewBindingParams(getter_AddRefs(params));
|
||||
|
||||
// Bind our parameters.
|
||||
nsresult rv = params->BindInt64ByIndex(0, aLastAccessed);
|
||||
nsresult rv = params->BindInt64ByName(NS_LITERAL_CSTRING("lastAccessed"),
|
||||
aLastAccessed);
|
||||
NS_ASSERT_SUCCESS(rv);
|
||||
rv = params->BindInt64ByIndex(1, aCookie->CreationID());
|
||||
|
||||
rv = params->BindUTF8StringByName(NS_LITERAL_CSTRING("name"),
|
||||
aCookie->Name());
|
||||
NS_ASSERT_SUCCESS(rv);
|
||||
|
||||
rv = params->BindUTF8StringByName(NS_LITERAL_CSTRING("host"),
|
||||
aCookie->Host());
|
||||
NS_ASSERT_SUCCESS(rv);
|
||||
|
||||
rv = params->BindUTF8StringByName(NS_LITERAL_CSTRING("path"),
|
||||
aCookie->Path());
|
||||
NS_ASSERT_SUCCESS(rv);
|
||||
|
||||
// Add our bound parameters to the array.
|
||||
|
|
|
@ -247,7 +247,7 @@ class nsCookieService : public nsICookieService
|
|||
static PRBool GetExpiry(nsCookieAttributes &aCookie, PRInt64 aServerTime, PRInt64 aCurrentTime);
|
||||
void RemoveAllFromMemory();
|
||||
void PurgeCookies(PRInt64 aCurrentTimeInUsec);
|
||||
PRBool FindCookie(const nsCString& aBaseDomain, const nsAFlatCString &aHost, const nsAFlatCString &aName, const nsAFlatCString &aPath, nsListIter &aIter, PRInt64 aCurrentTime);
|
||||
PRBool FindCookie(const nsCString& aBaseDomain, const nsAFlatCString &aHost, const nsAFlatCString &aName, const nsAFlatCString &aPath, nsListIter &aIter);
|
||||
PRUint32 CountCookiesFromHostInternal(const nsCString &aBaseDomain, nsEnumerationData &aData);
|
||||
void NotifyRejected(nsIURI *aHostURI);
|
||||
void NotifyChanged(nsISupports *aSubject, const PRUnichar *aData);
|
||||
|
|
|
@ -738,10 +738,11 @@ main(PRInt32 argc, char *argv[])
|
|||
rv[13] = NS_SUCCEEDED(cookieMgr2->CookieExists(newDomainCookie, &found)) && !found;
|
||||
// sleep four seconds, to make sure the second cookie has expired
|
||||
PR_Sleep(4 * PR_TicksPerSecond());
|
||||
// check CountCookiesFromHost() and CookieExists() don't count the expired cookie
|
||||
// check CountCookiesFromHost() doesn't count the expired cookie...
|
||||
rv[14] = NS_SUCCEEDED(cookieMgr2->CountCookiesFromHost(NS_LITERAL_CSTRING("cookiemgr.test"), &hostCookies)) &&
|
||||
hostCookies == 1;
|
||||
rv[15] = NS_SUCCEEDED(cookieMgr2->CookieExists(expiredCookie, &found)) && !found;
|
||||
// ... but that it's still there using CookieExists()
|
||||
rv[15] = NS_SUCCEEDED(cookieMgr2->CookieExists(expiredCookie, &found)) && found;
|
||||
// double-check RemoveAll() using the enumerator
|
||||
rv[16] = NS_SUCCEEDED(cookieMgr->RemoveAll());
|
||||
rv[17] = NS_SUCCEEDED(cookieMgr->GetEnumerator(getter_AddRefs(enumerator))) &&
|
||||
|
|
Загрузка…
Ссылка в новой задаче