зеркало из https://github.com/mozilla/gecko-dev.git
Bug 481775 - Crash in [@ nsCookieService::RemoveCookieFromList(nsListIter&)]. r=sdwilsh
This commit is contained in:
Родитель
0e1cce64fa
Коммит
5abb9677f6
|
@ -377,8 +377,7 @@ NS_IMPL_ISUPPORTS5(nsCookieService,
|
|||
nsISupportsWeakReference)
|
||||
|
||||
nsCookieService::nsCookieService()
|
||||
: mHostTable(&mDefaultHostTable)
|
||||
, mCookieCount(0)
|
||||
: mDBState(&mDefaultDBState)
|
||||
, mCookiesPermissions(BEHAVIOR_ACCEPT)
|
||||
, mMaxNumberOfCookies(kMaxNumberOfCookies)
|
||||
, mMaxCookiesPerHost(kMaxCookiesPerHost)
|
||||
|
@ -388,7 +387,7 @@ nsCookieService::nsCookieService()
|
|||
nsresult
|
||||
nsCookieService::Init()
|
||||
{
|
||||
if (!mHostTable->Init()) {
|
||||
if (!mDBState->hostTable.Init()) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
|
@ -408,11 +407,6 @@ nsCookieService::Init()
|
|||
// failure here is non-fatal (we can run fine without
|
||||
// persistent storage - e.g. if there's no profile)
|
||||
rv = InitDB();
|
||||
if (rv == NS_ERROR_FILE_CORRUPTED) {
|
||||
// database is corrupt - delete and try again
|
||||
COOKIE_LOGSTRING(PR_LOG_WARNING, ("Init(): db corrupt, trying again", rv));
|
||||
rv = InitDB(PR_TRUE);
|
||||
}
|
||||
if (NS_FAILED(rv))
|
||||
COOKIE_LOGSTRING(PR_LOG_WARNING, ("Init(): InitDB() gave error %x", rv));
|
||||
|
||||
|
@ -428,7 +422,8 @@ nsCookieService::Init()
|
|||
PRBool inPrivateBrowsing = PR_FALSE;
|
||||
pbs->GetPrivateBrowsingEnabled(&inPrivateBrowsing);
|
||||
if (inPrivateBrowsing) {
|
||||
Observe(nsnull, NS_PRIVATE_BROWSING_SWITCH_TOPIC, NS_LITERAL_STRING(NS_PRIVATE_BROWSING_ENTER).get());
|
||||
Observe(nsnull, NS_PRIVATE_BROWSING_SWITCH_TOPIC,
|
||||
NS_LITERAL_STRING(NS_PRIVATE_BROWSING_ENTER).get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -443,10 +438,32 @@ nsCookieService::Init()
|
|||
}
|
||||
|
||||
nsresult
|
||||
nsCookieService::InitDB(PRBool aDeleteExistingDB)
|
||||
nsCookieService::InitDB()
|
||||
{
|
||||
// null out any existing connection
|
||||
NS_ASSERTION(mDBState == &mDefaultDBState, "not in default DB state");
|
||||
|
||||
// attempt to open and read the database
|
||||
nsresult rv = TryInitDB(PR_FALSE);
|
||||
if (rv == NS_ERROR_FILE_CORRUPTED) {
|
||||
// database is corrupt - delete and try again
|
||||
COOKIE_LOGSTRING(PR_LOG_WARNING, ("InitDB(): db corrupt, trying again", rv));
|
||||
|
||||
rv = TryInitDB(PR_TRUE);
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
// reset our DB connection and statements
|
||||
CloseDB();
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsCookieService::TryInitDB(PRBool aDeleteExistingDB)
|
||||
{
|
||||
// null out any existing connection, and clear the cookie table
|
||||
CloseDB();
|
||||
RemoveAllFromMemory();
|
||||
|
||||
nsCOMPtr<nsIFile> cookieFile;
|
||||
nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(cookieFile));
|
||||
|
@ -464,12 +481,13 @@ nsCookieService::InitDB(PRBool aDeleteExistingDB)
|
|||
if (!storage)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
// cache a connection to the cookie database
|
||||
rv = storage->OpenUnsharedDatabase(cookieFile, getter_AddRefs(mDBConn));
|
||||
// open a connection to the cookie database, and only cache our connection
|
||||
// and statements upon success.
|
||||
rv = storage->OpenUnsharedDatabase(cookieFile, getter_AddRefs(mDBState->dbConn));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
PRBool tableExists = PR_FALSE;
|
||||
mDBConn->TableExists(NS_LITERAL_CSTRING("moz_cookies"), &tableExists);
|
||||
mDBState->dbConn->TableExists(NS_LITERAL_CSTRING("moz_cookies"), &tableExists);
|
||||
if (!tableExists) {
|
||||
rv = CreateTable();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
@ -477,7 +495,7 @@ nsCookieService::InitDB(PRBool aDeleteExistingDB)
|
|||
} else {
|
||||
// table already exists; check the schema version before reading
|
||||
PRInt32 dbSchemaVersion;
|
||||
rv = mDBConn->GetSchemaVersion(&dbSchemaVersion);
|
||||
rv = mDBState->dbConn->GetSchemaVersion(&dbSchemaVersion);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
switch (dbSchemaVersion) {
|
||||
|
@ -487,12 +505,12 @@ nsCookieService::InitDB(PRBool aDeleteExistingDB)
|
|||
case 1:
|
||||
{
|
||||
// add the lastAccessed column to the table
|
||||
rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||
rv = mDBState->dbConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||
"ALTER TABLE moz_cookies ADD lastAccessed INTEGER"));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// update the schema version
|
||||
rv = mDBConn->SetSchemaVersion(COOKIES_SCHEMA_VERSION);
|
||||
rv = mDBState->dbConn->SetSchemaVersion(COOKIES_SCHEMA_VERSION);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
// fall through to the next upgrade
|
||||
|
@ -509,7 +527,7 @@ nsCookieService::InitDB(PRBool aDeleteExistingDB)
|
|||
// 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);
|
||||
rv = mDBState->dbConn->SetSchemaVersion(COOKIES_SCHEMA_VERSION);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
// fall through to downgrade check
|
||||
|
@ -524,14 +542,14 @@ nsCookieService::InitDB(PRBool aDeleteExistingDB)
|
|||
{
|
||||
// check if all the expected columns exist
|
||||
nsCOMPtr<mozIStorageStatement> stmt;
|
||||
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
|
||||
rv = mDBState->dbConn->CreateStatement(NS_LITERAL_CSTRING(
|
||||
"SELECT id, name, value, host, path, expiry, isSecure, isHttpOnly "
|
||||
"FROM moz_cookies"), getter_AddRefs(stmt));
|
||||
if (NS_SUCCEEDED(rv))
|
||||
break;
|
||||
|
||||
// our columns aren't there - drop the table!
|
||||
rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING("DROP TABLE moz_cookies"));
|
||||
rv = mDBState->dbConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING("DROP TABLE moz_cookies"));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = CreateTable();
|
||||
|
@ -542,24 +560,27 @@ nsCookieService::InitDB(PRBool aDeleteExistingDB)
|
|||
}
|
||||
|
||||
// make operations on the table asynchronous, for performance
|
||||
mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING("PRAGMA synchronous = OFF"));
|
||||
mDBState->dbConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING("PRAGMA synchronous = OFF"));
|
||||
|
||||
// open in exclusive mode for performance
|
||||
mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING("PRAGMA locking_mode = EXCLUSIVE"));
|
||||
mDBState->dbConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING("PRAGMA locking_mode = EXCLUSIVE"));
|
||||
|
||||
// cache frequently used statements (for insertion, deletion, and updating)
|
||||
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
|
||||
rv = mDBState->dbConn->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));
|
||||
"VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9)"),
|
||||
getter_AddRefs(mDBState->stmtInsert));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
|
||||
"DELETE FROM moz_cookies WHERE id = ?1"), getter_AddRefs(mStmtDelete));
|
||||
rv = mDBState->dbConn->CreateStatement(NS_LITERAL_CSTRING(
|
||||
"DELETE FROM moz_cookies WHERE id = ?1"),
|
||||
getter_AddRefs(mDBState->stmtDelete));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
|
||||
"UPDATE moz_cookies SET lastAccessed = ?1 WHERE id = ?2"), getter_AddRefs(mStmtUpdate));
|
||||
rv = mDBState->dbConn->CreateStatement(NS_LITERAL_CSTRING(
|
||||
"UPDATE moz_cookies SET lastAccessed = ?1 WHERE id = ?2"),
|
||||
getter_AddRefs(mDBState->stmtUpdate));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// if we deleted a corrupt db, don't attempt to import - return now
|
||||
|
@ -593,11 +614,11 @@ nsresult
|
|||
nsCookieService::CreateTable()
|
||||
{
|
||||
// set the schema version, before creating the table
|
||||
nsresult rv = mDBConn->SetSchemaVersion(COOKIES_SCHEMA_VERSION);
|
||||
nsresult rv = mDBState->dbConn->SetSchemaVersion(COOKIES_SCHEMA_VERSION);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// create the table
|
||||
return mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||
return mDBState->dbConn->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)"));
|
||||
|
@ -606,12 +627,14 @@ nsCookieService::CreateTable()
|
|||
void
|
||||
nsCookieService::CloseDB()
|
||||
{
|
||||
// finalize our statements and close the db connection.
|
||||
NS_ASSERTION(!mPrivateDBState.dbConn, "private DB connection should always be null");
|
||||
|
||||
// finalize our statements and close the db connection for the default state.
|
||||
// since we own these objects, nulling the pointers is sufficient here.
|
||||
mStmtInsert = nsnull;
|
||||
mStmtDelete = nsnull;
|
||||
mStmtUpdate = nsnull;
|
||||
mDBConn = nsnull;
|
||||
mDefaultDBState.stmtInsert = nsnull;
|
||||
mDefaultDBState.stmtDelete = nsnull;
|
||||
mDefaultDBState.stmtUpdate = nsnull;
|
||||
mDefaultDBState.dbConn = nsnull;
|
||||
}
|
||||
|
||||
nsCookieService::~nsCookieService()
|
||||
|
@ -632,10 +655,10 @@ nsCookieService::Observe(nsISupports *aSubject,
|
|||
// or is going away because the application is shutting down.
|
||||
RemoveAllFromMemory();
|
||||
|
||||
if (mDBConn) {
|
||||
if (mDBState->dbConn) {
|
||||
if (!nsCRT::strcmp(aData, NS_LITERAL_STRING("shutdown-cleanse").get())) {
|
||||
// clear the cookie file
|
||||
nsresult rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING("DELETE FROM moz_cookies"));
|
||||
nsresult rv = mDBState->dbConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING("DELETE FROM moz_cookies"));
|
||||
if (NS_FAILED(rv))
|
||||
NS_WARNING("db delete failed");
|
||||
}
|
||||
|
@ -645,8 +668,17 @@ nsCookieService::Observe(nsISupports *aSubject,
|
|||
}
|
||||
|
||||
} else if (!strcmp(aTopic, "profile-do-change")) {
|
||||
// the profile has already changed; init the db from the new location
|
||||
InitDB();
|
||||
// the profile has already changed; init the db from the new location.
|
||||
// if we are in the private browsing state, however, we do not want to read
|
||||
// data into it - we should instead put it into the default state, so it's
|
||||
// ready for us if and when we switch back to it.
|
||||
if (mDBState == &mPrivateDBState) {
|
||||
mDBState = &mDefaultDBState;
|
||||
InitDB();
|
||||
mDBState = &mPrivateDBState;
|
||||
} else {
|
||||
InitDB();
|
||||
}
|
||||
|
||||
} else if (!strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) {
|
||||
nsCOMPtr<nsIPrefBranch> prefBranch = do_QueryInterface(aSubject);
|
||||
|
@ -654,25 +686,31 @@ nsCookieService::Observe(nsISupports *aSubject,
|
|||
PrefChanged(prefBranch);
|
||||
} else if (!strcmp(aTopic, NS_PRIVATE_BROWSING_SWITCH_TOPIC)) {
|
||||
if (NS_LITERAL_STRING(NS_PRIVATE_BROWSING_ENTER).Equals(aData)) {
|
||||
// backup the existing in-memory DB
|
||||
if (mPrivateHostTable.IsInitialized() || mPrivateHostTable.Init()) {
|
||||
mHostTable = &mPrivateHostTable;
|
||||
mCookieCount = mHostTable->Count();
|
||||
NotifyChanged(nsnull, NS_LITERAL_STRING("reload").get());
|
||||
}
|
||||
// close the connection to the on-disk DB
|
||||
CloseDB();
|
||||
// continue to use the in-memory DB
|
||||
} else if (NS_LITERAL_STRING(NS_PRIVATE_BROWSING_LEAVE).Equals(aData)) {
|
||||
// open the connection to the on-disk DB
|
||||
InitDB();
|
||||
// restore the in-memory DB as it was prior to private browsing
|
||||
if (mPrivateHostTable.IsInitialized())
|
||||
mPrivateHostTable.Clear();
|
||||
mHostTable = &mDefaultHostTable;
|
||||
mCookieCount = mHostTable->Count();
|
||||
if (!mPrivateDBState.hostTable.IsInitialized() &&
|
||||
!mPrivateDBState.hostTable.Init())
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
NS_ASSERTION(mDBState == &mPrivateDBState, "already in private state");
|
||||
NS_ASSERTION(mPrivateDBState.cookieCount == 0, "private count not 0");
|
||||
NS_ASSERTION(mPrivateDBState.hostTable.Count() == 0, "private table not empty");
|
||||
NS_ASSERTION(!mPrivateDBState.dbConn, "private DB connection not null");
|
||||
|
||||
// swap the private and default states
|
||||
mDBState = &mPrivateDBState;
|
||||
|
||||
NotifyChanged(nsnull, NS_LITERAL_STRING("reload").get());
|
||||
|
||||
} else if (NS_LITERAL_STRING(NS_PRIVATE_BROWSING_LEAVE).Equals(aData)) {
|
||||
// restore the default state, and clear the private one
|
||||
mDBState = &mDefaultDBState;
|
||||
|
||||
NS_ASSERTION(!mPrivateDBState.dbConn, "private DB connection not null");
|
||||
|
||||
mPrivateDBState.cookieCount = 0;
|
||||
if (mPrivateDBState.hostTable.IsInitialized())
|
||||
mPrivateDBState.hostTable.Clear();
|
||||
|
||||
NotifyChanged(nsnull, NS_LITERAL_STRING("reload").get());
|
||||
// continue to use both on-disk and in-memory DB
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -758,7 +796,7 @@ nsCookieService::SetCookieStringInternal(nsIURI *aHostURI,
|
|||
|
||||
// start a transaction on the storage db, to optimize insertions.
|
||||
// transaction will automically commit on completion
|
||||
mozStorageTransaction transaction(mDBConn, PR_TRUE);
|
||||
mozStorageTransaction transaction(mDBState->dbConn, PR_TRUE);
|
||||
|
||||
// switch to a nice string type now, and process each cookie in the header
|
||||
nsDependentCString cookieHeader(aCookieHeader);
|
||||
|
@ -819,12 +857,14 @@ nsCookieService::RemoveAll()
|
|||
RemoveAllFromMemory();
|
||||
|
||||
// clear the cookie file
|
||||
if (mDBConn) {
|
||||
nsresult rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING("DELETE FROM moz_cookies"));
|
||||
if (mDBState->dbConn) {
|
||||
NS_ASSERTION(mDBState == &mDefaultDBState, "not in default DB state");
|
||||
|
||||
nsresult rv = mDBState->dbConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING("DELETE FROM moz_cookies"));
|
||||
if (NS_FAILED(rv)) {
|
||||
// Database must be corrupted, so remove it completely.
|
||||
nsCOMPtr<nsIFile> dbFile;
|
||||
mDBConn->GetDatabaseFile(getter_AddRefs(dbFile));
|
||||
mDBState->dbConn->GetDatabaseFile(getter_AddRefs(dbFile));
|
||||
CloseDB();
|
||||
dbFile->Remove(PR_FALSE);
|
||||
|
||||
|
@ -864,10 +904,10 @@ COMArrayCallback(nsCookieEntry *aEntry,
|
|||
NS_IMETHODIMP
|
||||
nsCookieService::GetEnumerator(nsISimpleEnumerator **aEnumerator)
|
||||
{
|
||||
nsCOMArray<nsICookie> cookieList(mCookieCount);
|
||||
nsCOMArray<nsICookie> cookieList(mDBState->cookieCount);
|
||||
nsGetEnumeratorData data(&cookieList, PR_Now() / PR_USEC_PER_SEC);
|
||||
|
||||
mHostTable->EnumerateEntries(COMArrayCallback, &data);
|
||||
mDBState->hostTable.EnumerateEntries(COMArrayCallback, &data);
|
||||
|
||||
return NS_NewArrayEnumerator(aEnumerator, cookieList);
|
||||
}
|
||||
|
@ -951,8 +991,9 @@ nsCookieService::Read()
|
|||
{
|
||||
// scope the deletion, so the write lock is released when finished
|
||||
nsCOMPtr<mozIStorageStatement> stmtDeleteExpired;
|
||||
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING("DELETE FROM moz_cookies WHERE expiry <= ?1"),
|
||||
getter_AddRefs(stmtDeleteExpired));
|
||||
rv = mDBState->dbConn->CreateStatement(NS_LITERAL_CSTRING(
|
||||
"DELETE FROM moz_cookies WHERE expiry <= ?1"),
|
||||
getter_AddRefs(stmtDeleteExpired));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = stmtDeleteExpired->BindInt64Parameter(0, PR_Now() / PR_USEC_PER_SEC);
|
||||
|
@ -965,7 +1006,7 @@ nsCookieService::Read()
|
|||
|
||||
// let the reading begin!
|
||||
nsCOMPtr<mozIStorageStatement> stmt;
|
||||
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
|
||||
rv = mDBState->dbConn->CreateStatement(NS_LITERAL_CSTRING(
|
||||
"SELECT id, name, value, host, path, expiry, lastAccessed, isSecure, isHttpOnly "
|
||||
"FROM moz_cookies"), getter_AddRefs(stmt));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
@ -1008,7 +1049,7 @@ nsCookieService::Read()
|
|||
delete newCookie;
|
||||
}
|
||||
|
||||
COOKIE_LOGSTRING(PR_LOG_DEBUG, ("Read(): %ld cookies read", mCookieCount));
|
||||
COOKIE_LOGSTRING(PR_LOG_DEBUG, ("Read(): %ld cookies read", mDBState->cookieCount));
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
@ -1026,7 +1067,7 @@ nsCookieService::ImportCookies(nsIFile *aCookieFile)
|
|||
|
||||
// start a transaction on the storage db, to optimize insertions.
|
||||
// transaction will automically commit on completion
|
||||
mozStorageTransaction transaction(mDBConn, PR_TRUE);
|
||||
mozStorageTransaction transaction(mDBState->dbConn, PR_TRUE);
|
||||
|
||||
static const char kTrue[] = "TRUE";
|
||||
|
||||
|
@ -1037,7 +1078,7 @@ nsCookieService::ImportCookies(nsIFile *aCookieFile)
|
|||
PRInt32 numInts;
|
||||
PRInt64 expires;
|
||||
PRBool isDomain, isHttpOnly = PR_FALSE;
|
||||
PRUint32 originalCookieCount = mCookieCount;
|
||||
PRUint32 originalCookieCount = mDBState->cookieCount;
|
||||
|
||||
PRInt64 currentTimeInUsec = PR_Now();
|
||||
PRInt64 currentTime = currentTimeInUsec / PR_USEC_PER_SEC;
|
||||
|
@ -1139,7 +1180,7 @@ nsCookieService::ImportCookies(nsIFile *aCookieFile)
|
|||
AddInternal(newCookie, currentTime, nsnull, nsnull, PR_TRUE);
|
||||
}
|
||||
|
||||
COOKIE_LOGSTRING(PR_LOG_DEBUG, ("ImportCookies(): %ld cookies imported", mCookieCount));
|
||||
COOKIE_LOGSTRING(PR_LOG_DEBUG, ("ImportCookies(): %ld cookies imported", mDBState->cookieCount));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -1231,7 +1272,7 @@ nsCookieService::GetCookieInternal(nsIURI *aHostURI,
|
|||
// begin hash lookup, walking up the subdomain levels.
|
||||
// we use nextDot to force a lookup of the original host (without leading dot).
|
||||
do {
|
||||
nsCookieEntry *entry = mHostTable->GetEntry(currentDot);
|
||||
nsCookieEntry *entry = mDBState->hostTable.GetEntry(currentDot);
|
||||
cookie = entry ? entry->Head() : nsnull;
|
||||
for (; cookie; cookie = cookie->Next()) {
|
||||
// if the cookie is secure and the host scheme isn't, we can't send it
|
||||
|
@ -1295,7 +1336,7 @@ nsCookieService::GetCookieInternal(nsIURI *aHostURI,
|
|||
if (stale) {
|
||||
// start a transaction on the storage db, to optimize updates.
|
||||
// transaction will automically commit on completion.
|
||||
mozStorageTransaction transaction(mDBConn, PR_TRUE);
|
||||
mozStorageTransaction transaction(mDBState->dbConn, PR_TRUE);
|
||||
|
||||
for (PRInt32 i = 0; i < count; ++i) {
|
||||
cookie = foundCookieList.ElementAt(i);
|
||||
|
@ -1456,7 +1497,7 @@ nsCookieService::AddInternal(nsCookie *aCookie,
|
|||
// start a transaction on the storage db, to optimize deletions/insertions.
|
||||
// transaction will automically commit on completion. if we already have a
|
||||
// transaction (e.g. from SetCookie*()), this will have no effect.
|
||||
mozStorageTransaction transaction(mDBConn, PR_TRUE);
|
||||
mozStorageTransaction transaction(mDBState->dbConn, PR_TRUE);
|
||||
|
||||
nsListIter matchIter;
|
||||
PRBool foundCookie = FindCookie(aCookie->Host(), aCookie->Name(), aCookie->Path(),
|
||||
|
@ -1499,12 +1540,12 @@ nsCookieService::AddInternal(nsCookie *aCookie,
|
|||
oldCookie = data.iter.current;
|
||||
RemoveCookieFromList(data.iter);
|
||||
|
||||
} else if (mCookieCount >= mMaxNumberOfCookies) {
|
||||
} else if (mDBState->cookieCount >= mMaxNumberOfCookies) {
|
||||
// try to make room, by removing expired cookies
|
||||
RemoveExpiredCookies(aCurrentTime);
|
||||
|
||||
// check if we still have to get rid of something
|
||||
if (mCookieCount >= mMaxNumberOfCookies) {
|
||||
if (mDBState->cookieCount >= mMaxNumberOfCookies) {
|
||||
// find the position of the oldest cookie, and remove it
|
||||
data.oldestTime = LL_MAXINT;
|
||||
FindOldestCookie(data);
|
||||
|
@ -2068,8 +2109,8 @@ nsCookieService::RemoveAllFromMemory()
|
|||
{
|
||||
// clearing the hashtable will call each nsCookieEntry's dtor,
|
||||
// which releases all their respective children.
|
||||
mHostTable->Clear();
|
||||
mCookieCount = 0;
|
||||
mDBState->hostTable.Clear();
|
||||
mDBState->cookieCount = 0;
|
||||
}
|
||||
|
||||
PLDHashOperator
|
||||
|
@ -2092,10 +2133,12 @@ void
|
|||
nsCookieService::RemoveExpiredCookies(PRInt64 aCurrentTime)
|
||||
{
|
||||
#ifdef PR_LOGGING
|
||||
PRUint32 initialCookieCount = mCookieCount;
|
||||
PRUint32 initialCookieCount = mDBState->cookieCount;
|
||||
#endif
|
||||
mHostTable->EnumerateEntries(removeExpiredCallback, &aCurrentTime);
|
||||
COOKIE_LOGSTRING(PR_LOG_DEBUG, ("RemoveExpiredCookies(): %ld purged; %ld remain", initialCookieCount - mCookieCount, mCookieCount));
|
||||
mDBState->hostTable.EnumerateEntries(removeExpiredCallback, &aCurrentTime);
|
||||
COOKIE_LOGSTRING(PR_LOG_DEBUG,
|
||||
("RemoveExpiredCookies(): %ld purged; %ld remain",
|
||||
initialCookieCount - mDBState->cookieCount, mDBState->cookieCount));
|
||||
}
|
||||
|
||||
// find whether a given cookie has been previously set. this is provided by the
|
||||
|
@ -2134,7 +2177,7 @@ nsCookieService::CountCookiesFromHostInternal(const nsACString &aHost,
|
|||
const char *currentDot = hostWithDot.get();
|
||||
const char *nextDot = currentDot + 1;
|
||||
do {
|
||||
nsCookieEntry *entry = mHostTable->GetEntry(currentDot);
|
||||
nsCookieEntry *entry = mDBState->hostTable.GetEntry(currentDot);
|
||||
for (nsListIter iter(entry); iter.current; ++iter) {
|
||||
// only count non-expired cookies
|
||||
if (iter.current->Expiry() > aData.currentTime) {
|
||||
|
@ -2183,7 +2226,7 @@ nsCookieService::GetCookiesFromHost(const nsACString &aHost,
|
|||
const char *currentDot = hostWithDot.get();
|
||||
const char *nextDot = currentDot + 1;
|
||||
do {
|
||||
nsCookieEntry *entry = mHostTable->GetEntry(currentDot);
|
||||
nsCookieEntry *entry = mDBState->hostTable.GetEntry(currentDot);
|
||||
for (nsListIter iter(entry); iter.current; ++iter) {
|
||||
// only append non-expired cookies
|
||||
if (iter.current->Expiry() > currentTime)
|
||||
|
@ -2207,7 +2250,7 @@ nsCookieService::FindCookie(const nsAFlatCString &aHost,
|
|||
nsListIter &aIter,
|
||||
PRInt64 aCurrentTime)
|
||||
{
|
||||
nsCookieEntry *entry = mHostTable->GetEntry(aHost.get());
|
||||
nsCookieEntry *entry = mDBState->hostTable.GetEntry(aHost.get());
|
||||
for (aIter = nsListIter(entry); aIter.current; ++aIter) {
|
||||
if (aIter.current->Expiry() > aCurrentTime &&
|
||||
aPath.Equals(aIter.current->Path()) &&
|
||||
|
@ -2224,14 +2267,14 @@ void
|
|||
nsCookieService::RemoveCookieFromList(nsListIter &aIter)
|
||||
{
|
||||
// if it's a non-session cookie, remove it from the db
|
||||
if (!aIter.current->IsSession() && mStmtDelete) {
|
||||
if (!aIter.current->IsSession() && mDBState->dbConn) {
|
||||
// use our cached sqlite "delete" statement
|
||||
mozStorageStatementScoper scoper(mStmtDelete);
|
||||
mozStorageStatementScoper scoper(mDBState->stmtDelete);
|
||||
|
||||
nsresult rv = mStmtDelete->BindInt64Parameter(0, aIter.current->CreationID());
|
||||
nsresult rv = mDBState->stmtDelete->BindInt64Parameter(0, aIter.current->CreationID());
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
PRBool hasResult;
|
||||
rv = mStmtDelete->ExecuteStep(&hasResult);
|
||||
rv = mDBState->stmtDelete->ExecuteStep(&hasResult);
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
|
@ -2244,7 +2287,7 @@ nsCookieService::RemoveCookieFromList(nsListIter &aIter)
|
|||
// we're removing the last element in the list - so just remove the entry
|
||||
// from the hash. note that the entryclass' dtor will take care of
|
||||
// releasing this last element for us!
|
||||
mHostTable->RawRemoveEntry(aIter.entry);
|
||||
mDBState->hostTable.RawRemoveEntry(aIter.entry);
|
||||
aIter.current = nsnull;
|
||||
|
||||
} else {
|
||||
|
@ -2260,7 +2303,7 @@ nsCookieService::RemoveCookieFromList(nsListIter &aIter)
|
|||
}
|
||||
}
|
||||
|
||||
--mCookieCount;
|
||||
--mDBState->cookieCount;
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -2299,7 +2342,7 @@ bindCookieParameters(mozIStorageStatement* aStmt, const nsCookie* aCookie)
|
|||
PRBool
|
||||
nsCookieService::AddCookieToList(nsCookie *aCookie, PRBool aWriteToDB)
|
||||
{
|
||||
nsCookieEntry *entry = mHostTable->PutEntry(aCookie->Host().get());
|
||||
nsCookieEntry *entry = mDBState->hostTable.PutEntry(aCookie->Host().get());
|
||||
|
||||
if (!entry) {
|
||||
NS_ERROR("can't insert element into a null entry!");
|
||||
|
@ -2310,17 +2353,17 @@ nsCookieService::AddCookieToList(nsCookie *aCookie, PRBool aWriteToDB)
|
|||
|
||||
aCookie->Next() = entry->Head();
|
||||
entry->Head() = aCookie;
|
||||
++mCookieCount;
|
||||
++mDBState->cookieCount;
|
||||
|
||||
// if it's a non-session cookie and hasn't just been read from the db, write it out.
|
||||
if (aWriteToDB && !aCookie->IsSession() && mStmtInsert) {
|
||||
if (aWriteToDB && !aCookie->IsSession() && mDBState->dbConn) {
|
||||
// use our cached sqlite "insert" statement
|
||||
mozStorageStatementScoper scoper(mStmtInsert);
|
||||
mozStorageStatementScoper scoper(mDBState->stmtInsert);
|
||||
|
||||
nsresult rv = bindCookieParameters(mStmtInsert, aCookie);
|
||||
nsresult rv = bindCookieParameters(mDBState->stmtInsert, aCookie);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
PRBool hasResult;
|
||||
rv = mStmtInsert->ExecuteStep(&hasResult);
|
||||
rv = mDBState->stmtInsert->ExecuteStep(&hasResult);
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
|
@ -2339,16 +2382,16 @@ nsCookieService::UpdateCookieInList(nsCookie *aCookie, PRInt64 aLastAccessed)
|
|||
aCookie->SetLastAccessed(aLastAccessed);
|
||||
|
||||
// if it's a non-session cookie, update it in the db too
|
||||
if (!aCookie->IsSession() && mStmtUpdate) {
|
||||
if (!aCookie->IsSession() && mDBState->dbConn) {
|
||||
// use our cached sqlite "update" statement
|
||||
mozStorageStatementScoper scoper(mStmtUpdate);
|
||||
mozStorageStatementScoper scoper(mDBState->stmtUpdate);
|
||||
|
||||
nsresult rv = mStmtUpdate->BindInt64Parameter(0, aLastAccessed);
|
||||
nsresult rv = mDBState->stmtUpdate->BindInt64Parameter(0, aLastAccessed);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
rv = mStmtUpdate->BindInt64Parameter(1, aCookie->CreationID());
|
||||
rv = mDBState->stmtUpdate->BindInt64Parameter(1, aCookie->CreationID());
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
PRBool hasResult;
|
||||
rv = mStmtUpdate->ExecuteStep(&hasResult);
|
||||
rv = mDBState->stmtUpdate->ExecuteStep(&hasResult);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2377,5 +2420,5 @@ findOldestCallback(nsCookieEntry *aEntry,
|
|||
void
|
||||
nsCookieService::FindOldestCookie(nsEnumerationData &aData)
|
||||
{
|
||||
mHostTable->EnumerateEntries(findOldestCallback, &aData);
|
||||
mDBState->hostTable.EnumerateEntries(findOldestCallback, &aData);
|
||||
}
|
||||
|
|
|
@ -140,6 +140,20 @@ class nsCookieEntry : public PLDHashEntryHdr
|
|||
nsCookie *mHead;
|
||||
};
|
||||
|
||||
// encapsulates in-memory and on-disk DB states, so we can
|
||||
// conveniently switch state when entering or exiting private browsing.
|
||||
struct DBState
|
||||
{
|
||||
DBState() : cookieCount(0) { }
|
||||
|
||||
nsTHashtable<nsCookieEntry> hostTable;
|
||||
PRUint32 cookieCount;
|
||||
nsCOMPtr<mozIStorageConnection> dbConn;
|
||||
nsCOMPtr<mozIStorageStatement> stmtInsert;
|
||||
nsCOMPtr<mozIStorageStatement> stmtDelete;
|
||||
nsCOMPtr<mozIStorageStatement> stmtUpdate;
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
* nsCookieService:
|
||||
* class declaration
|
||||
|
@ -165,7 +179,8 @@ class nsCookieService : public nsICookieService
|
|||
|
||||
protected:
|
||||
void PrefChanged(nsIPrefBranch *aPrefBranch);
|
||||
nsresult InitDB(PRBool aDeleteExistingDB = PR_FALSE);
|
||||
nsresult InitDB();
|
||||
nsresult TryInitDB(PRBool aDeleteExistingDB);
|
||||
nsresult CreateTable();
|
||||
void CloseDB();
|
||||
nsresult Read();
|
||||
|
@ -192,20 +207,19 @@ class nsCookieService : public nsICookieService
|
|||
void NotifyChanged(nsICookie2 *aCookie, const PRUnichar *aData);
|
||||
|
||||
protected:
|
||||
// cached members
|
||||
nsCOMPtr<mozIStorageConnection> mDBConn;
|
||||
nsCOMPtr<mozIStorageStatement> mStmtInsert;
|
||||
nsCOMPtr<mozIStorageStatement> mStmtDelete;
|
||||
nsCOMPtr<mozIStorageStatement> mStmtUpdate;
|
||||
// cached members.
|
||||
nsCOMPtr<nsIObserverService> mObserverService;
|
||||
nsCOMPtr<nsICookiePermission> mPermissionService;
|
||||
nsCOMPtr<nsIEffectiveTLDService> mTLDService;
|
||||
|
||||
// impl members
|
||||
nsTHashtable<nsCookieEntry> *mHostTable;
|
||||
nsTHashtable<nsCookieEntry> mDefaultHostTable;
|
||||
nsTHashtable<nsCookieEntry> mPrivateHostTable;
|
||||
PRUint32 mCookieCount;
|
||||
// we have two separate DB states: one for normal browsing and one for
|
||||
// private browsing, switching between them as appropriate. this state
|
||||
// encapsulates both the in-memory table and the on-disk DB.
|
||||
// note that the private states' dbConn should always be null - we never
|
||||
// want to be dealing with the on-disk DB when in private browsing.
|
||||
DBState *mDBState;
|
||||
DBState mDefaultDBState;
|
||||
DBState mPrivateDBState;
|
||||
|
||||
// cached prefs
|
||||
PRUint8 mCookiesPermissions; // BEHAVIOR_{ACCEPT, REJECTFOREIGN, REJECT}
|
||||
|
|
Загрузка…
Ссылка в новой задаче