Bug 536978 - Cookies should write to the database asynchronously.

This makes cookie insertion, updates, and deletions happen asynchronously off of
the main thread.  The only I/O done on the main thread is the initial loading of
the database at each startup.
r=dwitte
This commit is contained in:
Shawn Wilsher 2010-03-12 07:18:38 -08:00
parent 6371523ca7
commit 5bdff598be
3 changed files with 361 additions and 122 deletions

View File

@ -69,10 +69,9 @@
#include "nsNetUtil.h"
#include "nsNetCID.h"
#include "nsAppDirectoryServiceDefs.h"
#include "mozIStorageService.h"
#include "mozStorageHelper.h"
#include "nsIPrivateBrowsingService.h"
#include "nsNetCID.h"
#include "mozilla/storage.h"
/******************************************************************************
* nsCookieService impl:
@ -342,6 +341,127 @@ LogSuccess(PRBool aSetCookie, nsIURI *aHostURI, const nsAFlatCString &aCookieStr
#define COOKIE_LOGSTRING(a, b) PR_BEGIN_MACRO /* nothing */ PR_END_MACRO
#endif
#ifdef DEBUG
#define NS_ASSERT_SUCCESS(res) \
PR_BEGIN_MACRO \
nsresult __rv = res; /* Do not evaluate |res| more than once! */ \
if (NS_FAILED(__rv)) { \
char *msg = PR_smprintf("NS_ASSERT_SUCCESS(%s) failed with result 0x%X", \
#res, __rv); \
NS_ASSERTION(NS_SUCCEEDED(__rv), msg); \
PR_smprintf_free(msg); \
} \
PR_END_MACRO
#else
#define NS_ASSERT_SUCCESS(res) PR_BEGIN_MACRO /* nothing */ PR_END_MACRO
#endif
namespace {
/******************************************************************************
* DBListenerErrorHandler imp:
* Parent class for our async storage listeners that handles the logging of
* errors.
******************************************************************************/
class DBListenerErrorHandler : public mozIStorageStatementCallback
{
protected:
virtual const char *GetOpType() = 0;
public:
NS_DECL_ISUPPORTS
NS_IMETHOD HandleError(mozIStorageError* aError)
{
#ifdef PR_LOGGING
PRInt32 result = -1;
aError->GetResult(&result);
nsCAutoString message;
aError->GetMessage(message);
COOKIE_LOGSTRING(PR_LOG_WARNING,
("Error %d occurred while performing a %s operation. Message: `%s`\n",
result, GetOpType(), message.get()));
#endif
return NS_OK;
}
};
NS_IMETHODIMP_(nsrefcnt) DBListenerErrorHandler::AddRef() { return 2; }
NS_IMETHODIMP_(nsrefcnt) DBListenerErrorHandler::Release() { return 1; }
NS_IMPL_QUERY_INTERFACE1(DBListenerErrorHandler, mozIStorageStatementCallback)
/******************************************************************************
* InsertCookieDBListener imp:
* Static mozIStorageStatementCallback used to track asynchronous insertion
* operations.
******************************************************************************/
class InsertCookieDBListener : public DBListenerErrorHandler
{
protected:
virtual const char *GetOpType() { return "INSERT"; }
public:
NS_IMETHOD HandleResult(mozIStorageResultSet*)
{
NS_NOTREACHED("Unexpected call to InsertCookieDBListener::HandleResult");
return NS_OK;
}
NS_IMETHOD HandleCompletion(PRUint16 aReason)
{
return NS_OK;
}
};
static InsertCookieDBListener sInsertCookieDBListener;
/******************************************************************************
* UpdateCookieDBListener imp:
* Static mozIStorageStatementCallback used to track asynchronous update
* operations.
******************************************************************************/
class UpdateCookieDBListener : public DBListenerErrorHandler
{
protected:
virtual const char *GetOpType() { return "UPDATE"; }
public:
NS_IMETHOD HandleResult(mozIStorageResultSet*)
{
NS_NOTREACHED("Unexpected call to UpdateCookieDBListener::HandleResult");
return NS_OK;
}
NS_IMETHOD HandleCompletion(PRUint16 aReason)
{
return NS_OK;
}
};
static UpdateCookieDBListener sUpdateCookieDBListener;
/******************************************************************************
* RemoveCookieDBListener imp:
* Static mozIStorageStatementCallback used to track asynchronous removal
* operations.
******************************************************************************/
class RemoveCookieDBListener : public DBListenerErrorHandler
{
protected:
virtual const char *GetOpType() { return "REMOVE"; }
public:
NS_IMETHOD HandleResult(mozIStorageResultSet*)
{
NS_NOTREACHED("Unexpected call to RemoveCookieDBListener::HandleResult");
return NS_OK;
}
NS_IMETHOD HandleCompletion(PRUint16 aReason)
{
return NS_OK;
}
};
static RemoveCookieDBListener sRemoveCookieDBListener;
} // anonymous namespace
/******************************************************************************
* nsCookieService impl:
* singleton instance ctor/dtor methods
@ -673,8 +793,11 @@ nsCookieService::CloseDB()
mDefaultDBState.stmtInsert = nsnull;
mDefaultDBState.stmtDelete = nsnull;
mDefaultDBState.stmtUpdate = nsnull;
if (mDefaultDBState.dbConn) {
mDefaultDBState.dbConn->AsyncClose(NULL);
mDefaultDBState.dbConn = nsnull;
}
}
nsCookieService::~nsCookieService()
{
@ -851,14 +974,33 @@ nsCookieService::SetCookieStringInternal(nsIURI *aHostURI,
serverTime = PR_Now() / PR_USEC_PER_SEC;
}
// start a transaction on the storage db, to optimize insertions.
// transaction will automically commit on completion
mozStorageTransaction transaction(mDBState->dbConn, PR_TRUE);
// We may be adding a bunch of cookies to the DB, so we use async batching
// with storage to make this super fast.
nsCOMPtr<mozIStorageBindingParamsArray> paramsArray;
if (mDBState->dbConn) {
mDBState->stmtInsert->NewBindingParamsArray(getter_AddRefs(paramsArray));
}
// switch to a nice string type now, and process each cookie in the header
nsDependentCString cookieHeader(aCookieHeader);
while (SetCookieInternal(aHostURI, aChannel, baseDomain, requireHostMatch,
cookieHeader, serverTime, aFromHttp));
cookieHeader, serverTime, aFromHttp, paramsArray));
// If we had a params array, go ahead and write it out to disk now.
if (paramsArray) {
// ...but only if we have sufficient length!
PRUint32 length;
paramsArray->GetLength(&length);
if (length == 0)
return NS_OK;
rv = mDBState->stmtInsert->BindParameters(paramsArray);
NS_ASSERT_SUCCESS(rv);
nsCOMPtr<mozIStoragePendingStatement> handle;
rv = mDBState->stmtInsert->ExecuteAsync(&sInsertCookieDBListener,
getter_AddRefs(handle));
NS_ASSERT_SUCCESS(rv);
}
return NS_OK;
}
@ -1137,7 +1279,7 @@ nsCookieService::Read()
if (!newCookie)
return NS_ERROR_OUT_OF_MEMORY;
if (!AddCookieToList(baseDomain, newCookie, PR_FALSE))
if (!AddCookieToList(baseDomain, newCookie, NULL, PR_FALSE))
// It is purpose that created us; purpose that connects us;
// purpose that pulls us; that guides us; that drives us.
// It is purpose that defines us; purpose that binds us.
@ -1164,10 +1306,6 @@ nsCookieService::ImportCookies(nsIFile *aCookieFile)
nsCOMPtr<nsILineInputStream> lineInputStream = do_QueryInterface(fileInputStream, &rv);
if (NS_FAILED(rv)) return rv;
// start a transaction on the storage db, to optimize insertions.
// transaction will automically commit on completion
mozStorageTransaction transaction(mDBState->dbConn, PR_TRUE);
static const char kTrue[] = "TRUE";
nsCAutoString buffer, baseDomain;
@ -1208,6 +1346,13 @@ nsCookieService::ImportCookies(nsIFile *aCookieFile)
*
*/
// We will likely be adding a bunch of cookies to the DB, so we use async
// batching with storage to make this super fast.
nsCOMPtr<mozIStorageBindingParamsArray> paramsArray;
if (mDBState->dbConn) {
mDBState->stmtInsert->NewBindingParamsArray(getter_AddRefs(paramsArray));
}
while (isMore && NS_SUCCEEDED(lineInputStream->ReadLine(buffer, &isMore))) {
if (StringBeginsWith(buffer, NS_LITERAL_CSTRING(kHttpOnlyPrefix))) {
isHttpOnly = PR_TRUE;
@ -1278,11 +1423,29 @@ nsCookieService::ImportCookies(nsIFile *aCookieFile)
// by successively decrementing the lastAccessed time
lastAccessedCounter--;
if (originalCookieCount == 0)
AddCookieToList(baseDomain, newCookie);
else
AddInternal(baseDomain, newCookie, currentTimeInUsec, nsnull, nsnull, PR_TRUE);
if (originalCookieCount == 0) {
AddCookieToList(baseDomain, newCookie, paramsArray);
}
else {
AddInternal(baseDomain, newCookie, currentTimeInUsec, NULL, NULL, PR_TRUE,
paramsArray);
}
}
// If we need to write to disk, do so now.
if (paramsArray) {
PRUint32 length;
paramsArray->GetLength(&length);
if (length) {
rv = mDBState->stmtInsert->BindParameters(paramsArray);
NS_ASSERT_SUCCESS(rv);
nsCOMPtr<mozIStoragePendingStatement> handle;
rv = mDBState->stmtInsert->ExecuteAsync(&sInsertCookieDBListener,
getter_AddRefs(handle));
NS_ASSERT_SUCCESS(rv);
}
}
COOKIE_LOGSTRING(PR_LOG_DEBUG, ("ImportCookies(): %ld cookies imported", mDBState->cookieCount));
@ -1447,15 +1610,31 @@ nsCookieService::GetCookieInternal(nsIURI *aHostURI,
// 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(mDBState->dbConn, PR_TRUE);
// Create an array of parameters to bind to our update statement.
nsCOMPtr<mozIStorageBindingParamsArray> paramsArray;
mozIStorageStatement* stmt = mDBState->stmtUpdate;
if (mDBState->dbConn) {
stmt->NewBindingParamsArray(getter_AddRefs(paramsArray));
}
for (PRInt32 i = 0; i < count; ++i) {
cookie = foundCookieList.ElementAt(i);
if (currentTimeInUsec - cookie->LastAccessed() > kCookieStaleThreshold)
UpdateCookieInList(cookie, currentTimeInUsec);
UpdateCookieInList(cookie, currentTimeInUsec, paramsArray);
}
// Update the database now if necessary.
if (paramsArray) {
PRUint32 length;
paramsArray->GetLength(&length);
if (length) {
nsresult rv = stmt->BindParameters(paramsArray);
NS_ASSERT_SUCCESS(rv);
nsCOMPtr<mozIStoragePendingStatement> handle;
rv = stmt->ExecuteAsync(&sUpdateCookieDBListener,
getter_AddRefs(handle));
NS_ASSERT_SUCCESS(rv);
}
}
}
@ -1503,7 +1682,8 @@ nsCookieService::SetCookieInternal(nsIURI *aHostURI,
PRBool aRequireHostMatch,
nsDependentCString &aCookieHeader,
PRInt64 aServerTime,
PRBool aFromHttp)
PRBool aFromHttp,
mozIStorageBindingParamsArray *aParamsArray)
{
// create a stack-based nsCookieAttributes, to store all the
// attributes parsed from the cookie
@ -1588,7 +1768,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(aBaseDomain, cookie, PR_Now(), aHostURI, savedCookieHeader.get(),
aFromHttp);
aFromHttp, aParamsArray);
return newCookie;
}
@ -1603,7 +1783,8 @@ nsCookieService::AddInternal(const nsCString &aBaseDomain,
PRInt64 aCurrentTimeInUsec,
nsIURI *aHostURI,
const char *aCookieHeader,
PRBool aFromHttp)
PRBool aFromHttp,
mozIStorageBindingParamsArray *aParamsArray)
{
PRInt64 currentTime = aCurrentTimeInUsec / PR_USEC_PER_SEC;
@ -1613,11 +1794,6 @@ nsCookieService::AddInternal(const nsCString &aBaseDomain,
return;
}
// 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(mDBState->dbConn, PR_TRUE);
nsListIter matchIter;
PRBool foundCookie = FindCookie(aBaseDomain, aCookie->Host(),
aCookie->Name(), aCookie->Path(), matchIter, currentTime);
@ -1678,7 +1854,7 @@ nsCookieService::AddInternal(const nsCString &aBaseDomain,
}
// add the cookie to head of list
AddCookieToList(aBaseDomain, aCookie);
AddCookieToList(aBaseDomain, aCookie, aParamsArray);
NotifyChanged(aCookie, foundCookie ? NS_LITERAL_STRING("changed").get()
: NS_LITERAL_STRING("added").get());
@ -2282,12 +2458,16 @@ struct nsPurgeData
nsPurgeData(PRInt64 aCurrentTime,
PRInt64 aPurgeTime,
ArrayType &aPurgeList,
nsIMutableArray *aRemovedList)
nsIMutableArray *aRemovedList,
mozIStorageBindingParamsArray *aParamsArray)
: currentTime(aCurrentTime)
, purgeTime(aPurgeTime)
, oldestTime(LL_MAXINT)
, purgeList(aPurgeList)
, removedList(aRemovedList) {}
, removedList(aRemovedList)
, paramsArray(aParamsArray)
{
}
// the current time, in seconds
PRInt64 currentTime;
@ -2303,6 +2483,9 @@ struct nsPurgeData
// list of all cookies we've removed, for notification
nsIMutableArray *removedList;
// The array of parameters to be bound to the statement for deletion later.
mozIStorageBindingParamsArray *paramsArray;
};
// comparator class for lastaccessed times of cookies.
@ -2350,6 +2533,7 @@ purgeCookiesCallback(nsCookieEntry *aEntry,
nsPurgeData &data = *static_cast<nsPurgeData*>(aArg);
const nsCookieEntry::ArrayType &cookies = aEntry->GetCookies();
mozIStorageBindingParamsArray *array = data.paramsArray;
for (nsCookieEntry::IndexType i = 0; i < cookies.Length(); ) {
nsListIter iter(aEntry, i);
nsCookie *cookie = cookies[i];
@ -2360,7 +2544,7 @@ purgeCookiesCallback(nsCookieEntry *aEntry,
COOKIE_LOGEVICTED(cookie);
// remove from list; do not increment our iterator
nsCookieService::gCookieService->RemoveCookieFromList(iter);
nsCookieService::gCookieService->RemoveCookieFromList(iter, array);
} else {
// check if the cookie is over the age limit
@ -2396,8 +2580,14 @@ nsCookieService::PurgeCookies(PRInt64 aCurrentTimeInUsec)
if (!removedList)
return;
mozIStorageStatement *stmt = mDBState->stmtDelete;
nsCOMPtr<mozIStorageBindingParamsArray> paramsArray;
if (mDBState->dbConn) {
stmt->NewBindingParamsArray(getter_AddRefs(paramsArray));
}
nsPurgeData data(aCurrentTimeInUsec / PR_USEC_PER_SEC,
aCurrentTimeInUsec - mCookiePurgeAge, purgeList, removedList);
aCurrentTimeInUsec - mCookiePurgeAge, purgeList, removedList, paramsArray);
mDBState->hostTable.EnumerateEntries(purgeCookiesCallback, &data);
#ifdef PR_LOGGING
@ -2426,7 +2616,20 @@ nsCookieService::PurgeCookies(PRInt64 aCurrentTimeInUsec)
removedList->AppendElement(cookie, PR_FALSE);
COOKIE_LOGEVICTED(cookie);
RemoveCookieFromList(purgeList[i]);
RemoveCookieFromList(purgeList[i], paramsArray);
}
// Update the database if we have entries to purge.
if (paramsArray) {
PRUint32 length;
paramsArray->GetLength(&length);
if (length) {
nsresult rv = stmt->BindParameters(paramsArray);
NS_ASSERT_SUCCESS(rv);
nsCOMPtr<mozIStoragePendingStatement> handle;
rv = stmt->ExecuteAsync(&sRemoveCookieDBListener, getter_AddRefs(handle));
NS_ASSERT_SUCCESS(rv);
}
}
// take all the cookies in the removed list, and notify about them in one batch
@ -2585,23 +2788,36 @@ nsCookieService::FindCookie(const nsCString &aBaseDomain,
// remove a cookie from the hashtable, and update the iterator state.
void
nsCookieService::RemoveCookieFromList(const nsListIter &aIter)
nsCookieService::RemoveCookieFromList(const nsListIter &aIter,
mozIStorageBindingParamsArray *aParamsArray)
{
// if it's a non-session cookie, remove it from the db
if (!aIter.Cookie()->IsSession() && mDBState->dbConn) {
// use our cached sqlite "delete" statement
mozStorageStatementScoper scoper(mDBState->stmtDelete);
PRInt64 creationID = aIter.Cookie()->CreationID();
nsresult rv = mDBState->stmtDelete->BindInt64Parameter(0, creationID);
if (NS_SUCCEEDED(rv)) {
PRBool hasResult;
rv = mDBState->stmtDelete->ExecuteStep(&hasResult);
// Use the asynchronous binding methods to ensure that we do not acquire
// the database lock.
mozIStorageStatement *stmt = mDBState->stmtDelete;
nsCOMPtr<mozIStorageBindingParamsArray> paramsArray(aParamsArray);
if (!paramsArray) {
stmt->NewBindingParamsArray(getter_AddRefs(paramsArray));
}
if (NS_FAILED(rv)) {
NS_WARNING("db remove failed!");
COOKIE_LOGSTRING(PR_LOG_WARNING, ("RemoveCookieFromList(): removing from db gave error %x", rv));
nsCOMPtr<mozIStorageBindingParams> params;
paramsArray->NewBindingParams(getter_AddRefs(params));
nsresult rv = params->BindInt64ByIndex(0, aIter.Cookie()->CreationID());
NS_ASSERT_SUCCESS(rv);
rv = paramsArray->AddParams(params);
NS_ASSERT_SUCCESS(rv);
// If we weren't given a params array, we'll need to remove it ourselves.
if (!aParamsArray) {
rv = stmt->BindParameters(paramsArray);
NS_ASSERT_SUCCESS(rv);
nsCOMPtr<mozIStoragePendingStatement> handle;
rv = stmt->ExecuteAsync(&sRemoveCookieDBListener,
getter_AddRefs(handle));
NS_ASSERT_SUCCESS(rv);
}
}
@ -2619,44 +2835,64 @@ nsCookieService::RemoveCookieFromList(const nsListIter &aIter)
--mDBState->cookieCount;
}
static nsresult
bindCookieParameters(mozIStorageStatement *aStmt, const nsCookie *aCookie)
static void
bindCookieParameters(mozIStorageBindingParamsArray *aParamsArray,
const nsCookie *aCookie)
{
NS_ASSERTION(aParamsArray, "Null params array passed to bindCookieParameters!");
NS_ASSERTION(aCookie, "Null cookie passed to bindCookieParameters!");
nsresult rv;
rv = aStmt->BindInt64Parameter(0, aCookie->CreationID());
if (NS_FAILED(rv)) return rv;
// Use the asynchronous binding methods to ensure that we do not acquire the
// database lock.
nsCOMPtr<mozIStorageBindingParams> params;
rv = aParamsArray->NewBindingParams(getter_AddRefs(params));
NS_ASSERT_SUCCESS(rv);
rv = aStmt->BindUTF8StringParameter(1, aCookie->Name());
if (NS_FAILED(rv)) return rv;
// Bind our values to params
rv = params->BindInt64ByIndex(0, aCookie->CreationID());
NS_ASSERT_SUCCESS(rv);
rv = aStmt->BindUTF8StringParameter(2, aCookie->Value());
if (NS_FAILED(rv)) return rv;
rv = params->BindUTF8StringByIndex(1, aCookie->Name());
NS_ASSERT_SUCCESS(rv);
rv = aStmt->BindUTF8StringParameter(3, aCookie->Host());
if (NS_FAILED(rv)) return rv;
rv = params->BindUTF8StringByIndex(2, aCookie->Value());
NS_ASSERT_SUCCESS(rv);
rv = aStmt->BindUTF8StringParameter(4, aCookie->Path());
if (NS_FAILED(rv)) return rv;
rv = params->BindUTF8StringByIndex(3, aCookie->Host());
NS_ASSERT_SUCCESS(rv);
rv = aStmt->BindInt64Parameter(5, aCookie->Expiry());
if (NS_FAILED(rv)) return rv;
rv = params->BindUTF8StringByIndex(4, aCookie->Path());
NS_ASSERT_SUCCESS(rv);
rv = aStmt->BindInt64Parameter(6, aCookie->LastAccessed());
if (NS_FAILED(rv)) return rv;
rv = params->BindInt64ByIndex(5, aCookie->Expiry());
NS_ASSERT_SUCCESS(rv);
rv = aStmt->BindInt32Parameter(7, aCookie->IsSecure());
if (NS_FAILED(rv)) return rv;
rv = params->BindInt64ByIndex(6, aCookie->LastAccessed());
NS_ASSERT_SUCCESS(rv);
rv = aStmt->BindInt32Parameter(8, aCookie->IsHttpOnly());
return rv;
rv = params->BindInt32ByIndex(7, aCookie->IsSecure());
NS_ASSERT_SUCCESS(rv);
rv = params->BindInt32ByIndex(8, aCookie->IsHttpOnly());
NS_ASSERT_SUCCESS(rv);
// Bind the params to the array.
rv = aParamsArray->AddParams(params);
NS_ASSERT_SUCCESS(rv);
}
PRBool
nsCookieService::AddCookieToList(const nsCString &aBaseDomain,
nsCookie *aCookie,
mozIStorageBindingParamsArray *aParamsArray,
PRBool aWriteToDB)
{
NS_ASSERTION(!(mDBState->dbConn && !aWriteToDB && aParamsArray),
"Not writing to the DB but have a params array?");
NS_ASSERTION(!(!mDBState->dbConn && aParamsArray),
"Do not have a DB connection but have a params array?");
nsCookieEntry *entry = mDBState->hostTable.PutEntry(aBaseDomain);
if (!entry) {
NS_ERROR("can't insert element into a null entry!");
@ -2672,18 +2908,19 @@ nsCookieService::AddCookieToList(const nsCString &aBaseDomain,
// if it's a non-session cookie and hasn't just been read from the db, write it out.
if (aWriteToDB && !aCookie->IsSession() && mDBState->dbConn) {
// use our cached sqlite "insert" statement
mozStorageStatementScoper scoper(mDBState->stmtInsert);
nsresult rv = bindCookieParameters(mDBState->stmtInsert, aCookie);
if (NS_SUCCEEDED(rv)) {
PRBool hasResult;
rv = mDBState->stmtInsert->ExecuteStep(&hasResult);
nsCOMPtr<mozIStorageBindingParamsArray> array(aParamsArray);
if (!array) {
mDBState->stmtInsert->NewBindingParamsArray(getter_AddRefs(array));
}
bindCookieParameters(array, aCookie);
if (NS_FAILED(rv)) {
NS_WARNING("db insert failed!");
COOKIE_LOGSTRING(PR_LOG_WARNING, ("AddCookieToList(): adding to db gave error %x", rv));
// If we were supplied an array to store parameters, we shouldn't call
// executeAsync - someone up the stack will do this for us.
if (!aParamsArray) {
nsCOMPtr<mozIStoragePendingStatement> handle;
nsresult rv = mDBState->stmtInsert->ExecuteAsync(&sInsertCookieDBListener,
getter_AddRefs(handle));
NS_ASSERT_SUCCESS(rv);
}
}
@ -2691,29 +2928,29 @@ nsCookieService::AddCookieToList(const nsCString &aBaseDomain,
}
void
nsCookieService::UpdateCookieInList(nsCookie *aCookie, PRInt64 aLastAccessed)
nsCookieService::UpdateCookieInList(nsCookie *aCookie,
PRInt64 aLastAccessed,
mozIStorageBindingParamsArray *aParamsArray)
{
// update the lastAccessed timestamp
NS_ASSERTION(aCookie, "Passing a null cookie to UpdateCookieInList!");
// udpate the lastAccessed timestamp
aCookie->SetLastAccessed(aLastAccessed);
// if it's a non-session cookie, update it in the db too
if (!aCookie->IsSession() && mDBState->dbConn) {
// use our cached sqlite "update" statement
mozStorageStatementScoper scoper(mDBState->stmtUpdate);
if (!aCookie->IsSession() && aParamsArray) {
// Create our params holder.
nsCOMPtr<mozIStorageBindingParams> params;
aParamsArray->NewBindingParams(getter_AddRefs(params));
nsresult rv = mDBState->stmtUpdate->BindInt64Parameter(0, aLastAccessed);
if (NS_SUCCEEDED(rv)) {
rv = mDBState->stmtUpdate->BindInt64Parameter(1, aCookie->CreationID());
if (NS_SUCCEEDED(rv)) {
PRBool hasResult;
rv = mDBState->stmtUpdate->ExecuteStep(&hasResult);
}
}
// Bind our parameters.
nsresult rv = params->BindInt64ByIndex(0, aLastAccessed);
NS_ASSERT_SUCCESS(rv);
rv = params->BindInt64ByIndex(1, aCookie->CreationID());
NS_ASSERT_SUCCESS(rv);
if (NS_FAILED(rv)) {
NS_WARNING("db update failed!");
COOKIE_LOGSTRING(PR_LOG_WARNING, ("UpdateCookieInList(): updating db gave error %x", rv));
// Add our bound parameters to the array.
rv = aParamsArray->AddParams(params);
NS_ASSERT_SUCCESS(rv);
}
}
}

View File

@ -174,11 +174,11 @@ class nsCookieService : public nsICookieService
nsresult GetBaseDomainFromHost(const nsACString &aHost, nsCString &aBaseDomain);
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, const nsCString& aBaseDomain, PRBool aRequireHostMatch, nsDependentCString &aCookieHeader, PRInt64 aServerTime, PRBool aFromHttp);
void AddInternal(const nsCString& aBaseDomain, nsCookie *aCookie, PRInt64 aCurrentTimeInUsec, nsIURI *aHostURI, const char *aCookieHeader, PRBool aFromHttp);
void RemoveCookieFromList(const nsListIter &aIter);
PRBool AddCookieToList(const nsCString& aBaseDomain, nsCookie *aCookie, PRBool aWriteToDB = PR_TRUE);
void UpdateCookieInList(nsCookie *aCookie, PRInt64 aLastAccessed);
PRBool SetCookieInternal(nsIURI *aHostURI, nsIChannel *aChannel, const nsCString& aBaseDomain, PRBool aRequireHostMatch, nsDependentCString &aCookieHeader, PRInt64 aServerTime, PRBool aFromHttp, mozIStorageBindingParamsArray *aParamsArray = NULL);
void AddInternal(const nsCString& aBaseDomain, nsCookie *aCookie, PRInt64 aCurrentTimeInUsec, nsIURI *aHostURI, const char *aCookieHeader, PRBool aFromHttp, mozIStorageBindingParamsArray *aParamsArray = NULL);
void RemoveCookieFromList(const nsListIter &aIter, mozIStorageBindingParamsArray *aParamsArray = NULL);
PRBool AddCookieToList(const nsCString& aBaseDomain, nsCookie *aCookie, mozIStorageBindingParamsArray *aParamsArray, PRBool aWriteToDB = PR_TRUE);
void UpdateCookieInList(nsCookie *aCookie, PRInt64 aLastAccessed, mozIStorageBindingParamsArray *aParamsArray);
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);
PRBool IsForeign(const nsCString &aBaseDomain, PRBool aRequireHostMatch, nsIURI *aFirstURI);

View File

@ -43,6 +43,7 @@
////////////////////////////////////////////////////////////////////////////////
//// Public Interfaces
#include "mozStorageCID.h"
#include "mozIStorageAggregateFunction.h"
#include "mozIStorageConnection.h"
#include "mozIStorageError.h"
@ -54,12 +55,13 @@
#include "mozIStorageService.h"
#include "mozIStorageStatement.h"
#include "mozIStorageStatementCallback.h"
#include "mozIStorageBindingParamsArray.h"
#include "mozIStorageBindingParams.h"
////////////////////////////////////////////////////////////////////////////////
//// Native Language Helpers
#include "mozStorageHelper.h"
#include "mozStorageCID.h"
#include "mozilla/storage/Variant.h"