Revert bug 572223 to fix creation of duplicate cookies.
authorDan Witte <dwitte@mozilla.com>
Sun, 01 Aug 2010 12:24:38 -0700
changeset 48670 f53433d38b84aac9c62bd27e4ffd7cb1a71b2b53
parent 48669 ff1ecd74f8272ac9565d37add02cfa85040a5472
child 48671 618a186a433e7655070c2e04718264b4f88088e8
push idunknown
push userunknown
push dateunknown
bugs572223
milestone2.0b3pre
Revert bug 572223 to fix creation of duplicate cookies.
extensions/cookie/test/unit/head_cookies.js
extensions/cookie/test/unit/test_cookies_persistence.js
extensions/cookie/test/unit/test_cookies_read.js
extensions/cookie/test/unit/test_cookies_thirdparty_session.js
netwerk/cookie/nsCookieService.cpp
netwerk/cookie/nsCookieService.h
storage/src/mozStorageStatement.cpp
--- a/extensions/cookie/test/unit/head_cookies.js
+++ b/extensions/cookie/test/unit/head_cookies.js
@@ -12,62 +12,54 @@ const Cr = Components.results;
 
 XPCOMUtils.defineLazyServiceGetter(Services, "cookies",
                                    "@mozilla.org/cookieService;1",
                                    "nsICookieService");
 XPCOMUtils.defineLazyServiceGetter(Services, "cookiemgr",
                                    "@mozilla.org/cookiemanager;1",
                                    "nsICookieManager2");
 
-function _observer(generator, service, topic) {
-  Services.obs.addObserver(this, topic, false);
+// Close and reload the cookie database.
+function do_reload_profile(generator, profile, cleanse) {
+  function _observer(generator, service, topic) {
+    Services.obs.addObserver(this, topic, false);
 
-  this.service = service;
-  this.generator = generator;
-  this.topic = topic;
-}
+    this.service = service;
+    this.generator = generator;
+    this.topic = topic;
+  }
 
-_observer.prototype = {
-  observe: function (subject, topic, data) {
-    do_check_eq(this.topic, topic);
+  _observer.prototype = {
+    observe: function (subject, topic, data) {
+      do_check_eq(this.topic, topic);
 
-    Services.obs.removeObserver(this, this.topic);
+      Services.obs.removeObserver(this, this.topic);
 
-    // Continue executing the generator function.
-    if (this.generator)
+      // Fire the notification to reload the database, and continue executing
+      // the generator function.
+      this.service.observe(null, "profile-do-change", "");
       this.generator.next();
 
-    this.generator = null;
-    this.service = null;
-    this.topic = null;
+      this.generator = null;
+      this.service = null;
+      this.topic = null;
+    }
   }
-}
 
-// Close the cookie database. If a generator is supplied, it will be invoked
-// once the close is complete.
-function do_close_profile(generator, cleanse) {
+  let dbfile = profile.QueryInterface(Ci.nsILocalFile).clone();
+  dbfile.append("cookies.sqlite");
+
   // Register an observer for db close.
   let service = Services.cookies.QueryInterface(Ci.nsIObserver);
   let obs = new _observer(generator, service, "cookie-db-closed");
 
   // Close the db.
   service.observe(null, "profile-before-change", cleanse ? cleanse : "");
 }
 
-// Load the cookie database. If a generator is supplied, it will be invoked
-// once the load is complete.
-function do_load_profile(generator) {
-  // Register an observer for read completion.
-  let service = Services.cookies.QueryInterface(Ci.nsIObserver);
-  let obs = new _observer(generator, service, "cookie-db-read");
-
-  // Load the profile.
-  service.observe(null, "profile-do-change", "");
-}
-
 // Set four cookies; with & without channel, http and non-http; and test
 // the cookie count against 'expected' after each set.
 function do_set_cookies(uri, channel, session, expected) {
   let suffix = session ? "" : "; max-age=1000";
 
   // without channel
   Services.cookies.setCookieString(uri, null, "oh=hai" + suffix, null);
   do_check_eq(Services.cookiemgr.countCookiesFromHost(uri.host), expected[0]);
@@ -76,22 +68,8 @@ function do_set_cookies(uri, channel, se
   do_check_eq(Services.cookiemgr.countCookiesFromHost(uri.host), expected[1]);
   // without channel, from http
   Services.cookies.setCookieStringFromHttp(uri, null, null, "cheez=burger" + suffix, null, null);
   do_check_eq(Services.cookiemgr.countCookiesFromHost(uri.host), expected[2]);
   // with channel, from http
   Services.cookies.setCookieStringFromHttp(uri, null, null, "hot=dog" + suffix, null, channel);
   do_check_eq(Services.cookiemgr.countCookiesFromHost(uri.host), expected[3]);
 }
-
-function do_count_enumerator(enumerator) {
-  let i = 0;
-  while (enumerator.hasMoreElements()) {
-    enumerator.getNext();
-    ++i;
-  }
-  return i;
-}
-
-function do_count_cookies() {
-  return do_count_enumerator(Services.cookiemgr.enumerator);
-}
-
--- a/extensions/cookie/test/unit/test_cookies_persistence.js
+++ b/extensions/cookie/test/unit/test_cookies_persistence.js
@@ -42,44 +42,33 @@ function do_run_test() {
 
   // test with cookies enabled, and third party cookies persistent.
   Services.prefs.setIntPref("network.cookie.cookieBehavior", 0);
   Services.prefs.setBoolPref("network.cookie.thirdparty.sessionOnly", false);
   do_set_cookies(uri1, channel1, false, [1, 2, 3, 4]);
   do_set_cookies(uri2, channel2, true, [1, 2, 3, 4]);
 
   // fake a profile change
-  do_close_profile(test_generator);
+  do_reload_profile(test_generator, profile);
   yield;
-  do_load_profile();
-  do_check_eq(Services.cookies.countCookiesFromHost(uri1.host), 4);
-  do_check_eq(Services.cookies.countCookiesFromHost(uri2.host), 0);
-
-  // Again, but don't wait for the async close to complete. This should always
-  // work, since we blocked on close above and haven't kicked off any writes
-  // since then.
-  do_close_profile();
-  do_load_profile();
   do_check_eq(Services.cookies.countCookiesFromHost(uri1.host), 4);
   do_check_eq(Services.cookies.countCookiesFromHost(uri2.host), 0);
 
   // cleanse them
-  do_close_profile(test_generator, "shutdown-cleanse");
+  do_reload_profile(test_generator, profile, "shutdown-cleanse");
   yield;
-  do_load_profile();
   do_check_eq(Services.cookies.countCookiesFromHost(uri1.host), 0);
   do_check_eq(Services.cookies.countCookiesFromHost(uri2.host), 0);
 
   // test with cookies set to session-only
   Services.prefs.setIntPref("network.cookie.lifetimePolicy", 2);
   do_set_cookies(uri1, channel1, false, [1, 2, 3, 4]);
   do_set_cookies(uri2, channel2, true, [1, 2, 3, 4]);
 
   // fake a profile change
-  do_close_profile(test_generator);
+  do_reload_profile(test_generator, profile);
   yield;
-  do_load_profile();
   do_check_eq(Services.cookies.countCookiesFromHost(uri1.host), 0);
   do_check_eq(Services.cookies.countCookiesFromHost(uri2.host), 0);
 
   finish_test();
 }
 
deleted file mode 100644
--- a/extensions/cookie/test/unit/test_cookies_read.js
+++ /dev/null
@@ -1,67 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/
- */
-
-// test cookie database asynchronous read operation.
-
-let test_generator = do_run_test();
-
-function run_test() {
-  do_test_pending();
-  test_generator.next();
-}
-
-function finish_test() {
-  do_execute_soon(function() {
-    test_generator.close();
-    do_test_finished();
-  });
-}
-
-function do_run_test() {
-  // Set up a profile.
-  let profile = do_get_profile();
-
-  for (let i = 0; i < 3000; ++i) {
-    let uri = NetUtil.newURI("http://" + i + ".com/");
-    Services.cookies.setCookieString(uri, null, "oh=hai; max-age=1000", null);
-  }
-
-  do_check_eq(do_count_cookies(), 3000);
-
-  // fake a profile change
-  do_close_profile(test_generator);
-  yield;
-  do_load_profile();
-
-  // test a few random cookies
-  do_check_eq(Services.cookiemgr.countCookiesFromHost("2000.com"), 1);
-  do_check_eq(Services.cookiemgr.countCookiesFromHost("abc.com"), 0);
-  do_check_eq(Services.cookiemgr.countCookiesFromHost("100.com"), 1);
-  do_check_eq(Services.cookiemgr.countCookiesFromHost("1400.com"), 1);
-  do_check_eq(Services.cookiemgr.countCookiesFromHost("xyz.com"), 0);
-
-  // force synchronous load of everything
-  do_check_eq(do_count_cookies(), 3000);
-
-  // check that everything's precisely correct
-  for (let i = 0; i < 3000; ++i) {
-    let host = i.toString() + ".com";
-    do_check_eq(Services.cookiemgr.countCookiesFromHost(host), 1);
-  }
-
-  // reload again, but wait for async read completion
-  do_close_profile(test_generator);
-  yield;
-  do_load_profile(test_generator);
-  yield;
-
-  // check that everything's precisely correct
-  for (let i = 0; i < 3000; ++i) {
-    let host = i.toString() + ".com";
-    do_check_eq(Services.cookiemgr.countCookiesFromHost(host), 1);
-  }
-
-  finish_test();
-}
-
--- a/extensions/cookie/test/unit/test_cookies_thirdparty_session.js
+++ b/extensions/cookie/test/unit/test_cookies_thirdparty_session.js
@@ -42,36 +42,33 @@ function do_run_test() {
 
   // test with cookies enabled, and third party cookies persistent.
   Services.prefs.setIntPref("network.cookie.cookieBehavior", 0);
   Services.prefs.setBoolPref("network.cookie.thirdparty.sessionOnly", false);
   do_set_cookies(uri1, channel2, false, [1, 2, 3, 4]);
   do_set_cookies(uri2, channel1, true, [1, 2, 3, 4]);
 
   // fake a profile change
-  do_close_profile(test_generator);
+  do_reload_profile(test_generator, profile);
   yield;
-  do_load_profile();
   do_check_eq(Services.cookies.countCookiesFromHost(uri1.host), 4);
   do_check_eq(Services.cookies.countCookiesFromHost(uri2.host), 0);
 
   // cleanse them
-  do_close_profile(test_generator, "shutdown-cleanse");
+  do_reload_profile(test_generator, profile, "shutdown-cleanse");
   yield;
-  do_load_profile();
   do_check_eq(Services.cookies.countCookiesFromHost(uri1.host), 0);
   do_check_eq(Services.cookies.countCookiesFromHost(uri2.host), 0);
 
   // test with third party cookies for session only.
   Services.prefs.setBoolPref("network.cookie.thirdparty.sessionOnly", true);
   do_set_cookies(uri1, channel2, false, [1, 2, 3, 4]);
   do_set_cookies(uri2, channel1, true, [1, 2, 3, 4]);
 
   // fake a profile change
-  do_close_profile(test_generator);
+  do_reload_profile(test_generator, profile);
   yield;
-  do_load_profile();
   do_check_eq(Services.cookies.countCookiesFromHost(uri1.host), 0);
   do_check_eq(Services.cookies.countCookiesFromHost(uri2.host), 0);
 
   finish_test();
 }
 
--- a/netwerk/cookie/nsCookieService.cpp
+++ b/netwerk/cookie/nsCookieService.cpp
@@ -82,18 +82,16 @@
 
 using namespace mozilla::net;
 
 /******************************************************************************
  * nsCookieService impl:
  * useful types & constants
  ******************************************************************************/
 
-static nsCookieService *gCookieService;
-
 // XXX_hack. See bug 178993.
 // This is a hack to hide HttpOnly cookies from older browsers
 static const char kHttpOnlyPrefix[] = "#HttpOnly_";
 
 static const char kCookieFileName[] = "cookies.sqlite";
 #define COOKIES_SCHEMA_VERSION 3
 
 static const PRInt64 kCookieStaleThreshold = 60 * PR_USEC_PER_SEC; // 1 minute in microseconds
@@ -354,50 +352,51 @@ LogSuccess(PRBool aSetCookie, nsIURI *aH
     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 impl:
+ * 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)
   {
-    // XXX Ignore corruption handling for now. See bug 547031.
 #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_IMPL_ISUPPORTS1(DBListenerErrorHandler, mozIStorageStatementCallback)
 
 /******************************************************************************
- * InsertCookieDBListener impl:
- * mozIStorageStatementCallback used to track asynchronous insertion operations.
+ * 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*)
@@ -407,18 +406,19 @@ public:
   }
   NS_IMETHOD HandleCompletion(PRUint16 aReason)
   {
     return NS_OK;
   }
 };
 
 /******************************************************************************
- * UpdateCookieDBListener impl:
- * mozIStorageStatementCallback used to track asynchronous update operations.
+ * 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*)
@@ -428,18 +428,19 @@ public:
   }
   NS_IMETHOD HandleCompletion(PRUint16 aReason)
   {
     return NS_OK;
   }
 };
 
 /******************************************************************************
- * RemoveCookieDBListener impl:
- * mozIStorageStatementCallback used to track asynchronous removal operations.
+ * 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*)
@@ -449,88 +450,16 @@ public:
   }
   NS_IMETHOD HandleCompletion(PRUint16 aReason)
   {
     return NS_OK;
   }
 };
 
 /******************************************************************************
- * ReadCookieDBListener impl:
- * mozIStorageStatementCallback used to track asynchronous removal operations.
- ******************************************************************************/
-class ReadCookieDBListener :  public DBListenerErrorHandler
-{
-protected:
-  virtual const char *GetOpType() { return "READ"; }
-  bool mCanceled;
-
-public:
-  ReadCookieDBListener() : mCanceled(false) { }
-
-  void Cancel() { mCanceled = true; }
-
-  NS_IMETHOD HandleResult(mozIStorageResultSet *aResult)
-  {
-    nsresult rv;
-    nsCOMPtr<mozIStorageRow> row;
-    nsTArray<CookieDomainTuple> &cookieArray =
-      gCookieService->mDefaultDBState.hostArray;
-
-    while (1) {
-      rv = aResult->GetNextRow(getter_AddRefs(row));
-      NS_ASSERT_SUCCESS(rv);
-
-      if (!row)
-        break;
-
-      CookieDomainTuple *tuple = cookieArray.AppendElement();
-      row->GetUTF8String(9, tuple->baseDomain);
-      tuple->cookie = gCookieService->GetCookieFromRow(row);
-    }
-
-    return NS_OK;
-  }
-  NS_IMETHOD HandleCompletion(PRUint16 aReason)
-  {
-    // Process the completion of the read operation. If we have been canceled,
-    // we cannot assume that the cookieservice still has an open connection
-    // or that it even refers to the same database, so we must return early.
-    // Conversely, the cookieservice guarantees that if we have not been
-    // canceled, the database connection is still alive and we can safely
-    // operate on it.
-
-    if (mCanceled) {
-      // We may receive a REASON_FINISHED after being canceled;
-      // tweak the reason accordingly.
-      aReason = mozIStorageStatementCallback::REASON_CANCELED;
-    }
-
-    switch (aReason) {
-    case mozIStorageStatementCallback::REASON_FINISHED:
-      gCookieService->AsyncReadComplete();
-      break;
-    case mozIStorageStatementCallback::REASON_CANCELED:
-      // Nothing more to do here. The partially read data has already been
-      // thrown away.
-      COOKIE_LOGSTRING(PR_LOG_DEBUG, ("Read canceled"));
-      break;
-    case mozIStorageStatementCallback::REASON_ERROR:
-      // Nothing more to do here. DBListenerErrorHandler::HandleError()
-      // can take handle it.
-      COOKIE_LOGSTRING(PR_LOG_DEBUG, ("Read error"));
-      break;
-    default:
-      NS_NOTREACHED("invalid reason");
-    }
-    return NS_OK;
-  }
-};
-
-/******************************************************************************
  * CloseCookieDBListener imp:
  * Static mozIStorageCompletionCallback used to notify when the database is
  * successfully closed.
  ******************************************************************************/
 class CloseCookieDBListener :  public mozIStorageCompletionCallback
 {
 public:
   NS_DECL_ISUPPORTS
@@ -544,21 +473,25 @@ public:
       obs->NotifyObservers(nsnull, "cookie-db-closed", nsnull);
 
     return NS_OK;
   }
 };
 
 NS_IMPL_ISUPPORTS1(CloseCookieDBListener, mozIStorageCompletionCallback)
 
+} // anonymous namespace
+
 /******************************************************************************
  * nsCookieService impl:
  * singleton instance ctor/dtor methods
  ******************************************************************************/
 
+static nsCookieService *gCookieService;
+
 nsICookieService*
 nsCookieService::GetXPCOMSingleton()
 {
 #ifdef MOZ_IPC
   if (IsNeckoChild())
     return CookieServiceChild::GetSingleton();
 #endif
 
@@ -638,19 +571,16 @@ nsCookieService::Init()
     prefBranch->AddObserver(kPrefCookieBehavior,     this, PR_TRUE);
     prefBranch->AddObserver(kPrefMaxNumberOfCookies, this, PR_TRUE);
     prefBranch->AddObserver(kPrefMaxCookiesPerHost,  this, PR_TRUE);
     prefBranch->AddObserver(kPrefCookiePurgeAge,     this, PR_TRUE);
     prefBranch->AddObserver(kPrefThirdPartySession,  this, PR_TRUE);
     PrefChanged(prefBranch);
   }
 
-  mStorageService = do_GetService("@mozilla.org/storage/service;1", &rv);
-  NS_ENSURE_SUCCESS(rv, rv);
-
   // failure here is non-fatal (we can run fine without
   // persistent storage - e.g. if there's no profile)
   rv = InitDB();
   if (NS_FAILED(rv))
     COOKIE_LOGSTRING(PR_LOG_WARNING, ("Init(): InitDB() gave error %x", rv));
 
   mObserverService = mozilla::services::GetObserverService();
   if (mObserverService) {
@@ -719,20 +649,23 @@ nsCookieService::TryInitDB(PRBool aDelet
   cookieFile->AppendNative(NS_LITERAL_CSTRING(kCookieFileName));
 
   // remove an existing db, if we've been told to (i.e. it's corrupt)
   if (aDeleteExistingDB) {
     rv = cookieFile->Remove(PR_FALSE);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
+  nsCOMPtr<mozIStorageService> storage = do_GetService("@mozilla.org/storage/service;1");
+  if (!storage)
+    return NS_ERROR_UNEXPECTED;
+
   // open a connection to the cookie database, and only cache our connection
-  // and statements upon success. The connection is opened shared such that
-  // the main and background threads can operate on the db concurrently.
-  rv = mStorageService->OpenDatabase(cookieFile, getter_AddRefs(mDBState->dbConn));
+  // and statements upon success.
+  rv = storage->OpenUnsharedDatabase(cookieFile, getter_AddRefs(mDBState->dbConn));
   NS_ENSURE_SUCCESS(rv, rv);
 
   PRBool tableExists = PR_FALSE;
   mDBState->dbConn->TableExists(NS_LITERAL_CSTRING("moz_cookies"), &tableExists);
   if (!tableExists) {
       rv = CreateTable();
       NS_ENSURE_SUCCESS(rv, rv);
 
@@ -963,23 +896,16 @@ nsCookieService::CloseDB()
   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.
   mDefaultDBState.stmtInsert = nsnull;
   mDefaultDBState.stmtDelete = nsnull;
   mDefaultDBState.stmtUpdate = nsnull;
   if (mDefaultDBState.dbConn) {
-    // Cancel any pending read. No further results will be received by our
-    // read listener.
-    if (mDefaultDBState.pendingRead) {
-      CancelAsyncRead(PR_TRUE);
-      mDefaultDBState.syncConn = nsnull;
-    }
-
     mDefaultDBState.dbConn->AsyncClose(mCloseListener);
     mDefaultDBState.dbConn = nsnull;
   }
 }
 
 nsCookieService::~nsCookieService()
 {
   CloseDB();
@@ -996,17 +922,19 @@ nsCookieService::Observe(nsISupports    
   if (!strcmp(aTopic, "profile-before-change")) {
     // The profile is about to change,
     // or is going away because the application is shutting down.
     RemoveAllFromMemory();
 
     if (mDBState->dbConn) {
       if (!nsCRT::strcmp(aData, NS_LITERAL_STRING("shutdown-cleanse").get())) {
         // clear the cookie file
-        RemoveAll();
+        nsresult rv = mDBState->dbConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING("DELETE FROM moz_cookies"));
+        if (NS_FAILED(rv))
+          NS_WARNING("db delete failed");
       }
 
       // Close the DB connection before changing
       CloseDB();
     }
 
   } else if (!strcmp(aTopic, "profile-do-change")) {
     // the profile has already changed; init the db from the new location.
@@ -1249,25 +1177,26 @@ NS_IMETHODIMP
 nsCookieService::RemoveAll()
 {
   RemoveAllFromMemory();
 
   // clear the cookie file
   if (mDBState->dbConn) {
     NS_ASSERTION(mDBState == &mDefaultDBState, "not in default DB state");
 
-    // XXX Ignore corruption for now. See bug 547031.
-    nsCOMPtr<mozIStorageStatement> stmt;
-    nsresult rv = mDefaultDBState.dbConn->CreateStatement(NS_LITERAL_CSTRING(
-      "DELETE FROM moz_cookies"), getter_AddRefs(stmt));
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    nsCOMPtr<mozIStoragePendingStatement> handle;
-    rv = stmt->ExecuteAsync(mRemoveListener, getter_AddRefs(handle));
-    NS_ASSERT_SUCCESS(rv);
+    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;
+      mDBState->dbConn->GetDatabaseFile(getter_AddRefs(dbFile));
+      CloseDB();
+      dbFile->Remove(PR_FALSE);
+
+      InitDB();
+    }
   }
 
   NotifyChanged(nsnull, NS_LITERAL_STRING("cleared").get());
   return NS_OK;
 }
 
 // helper struct for passing arguments into hash enumeration callback.
 struct nsGetEnumeratorData
@@ -1298,18 +1227,16 @@ COMArrayCallback(nsCookieEntry *aEntry,
 }
 
 NS_IMETHODIMP
 nsCookieService::GetEnumerator(nsISimpleEnumerator **aEnumerator)
 {
   nsCOMArray<nsICookie> cookieList(mDBState->cookieCount);
   nsGetEnumeratorData data(&cookieList, PR_Now() / PR_USEC_PER_SEC);
 
-  EnsureReadComplete();
-
   mDBState->hostTable.EnumerateEntries(COMArrayCallback, &data);
 
   return NS_NewArrayEnumerator(aEnumerator, cookieList);
 }
 
 NS_IMETHODIMP
 nsCookieService::Add(const nsACString &aHost,
                      const nsACString &aPath,
@@ -1397,288 +1324,95 @@ nsCookieService::Remove(const nsACString
 /******************************************************************************
  * nsCookieService impl:
  * private file I/O functions
  ******************************************************************************/
 
 nsresult
 nsCookieService::Read()
 {
-  // Let the reading begin!
+  nsresult rv;
+
+  // delete expired cookies, before we read in the db
+  {
+    // scope the deletion, so the write lock is released when finished
+    nsCOMPtr<mozIStorageStatement> 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->BindInt64ByIndex(0, PR_Now() / PR_USEC_PER_SEC);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    PRBool hasResult;
+    rv = stmtDeleteExpired->ExecuteStep(&hasResult);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  // let the reading begin!
   nsCOMPtr<mozIStorageStatement> stmt;
-  nsresult rv = mDefaultDBState.dbConn->CreateStatement(NS_LITERAL_CSTRING(
+  rv = mDBState->dbConn->CreateStatement(NS_LITERAL_CSTRING(
     "SELECT "
       "id, "
       "name, "
       "value, "
       "host, "
       "path, "
       "expiry, "
       "lastAccessed, "
       "isSecure, "
       "isHttpOnly, "
       "baseDomain "
     "FROM moz_cookies"), getter_AddRefs(stmt));
   NS_ENSURE_SUCCESS(rv, rv);
 
-  nsRefPtr<ReadCookieDBListener> readListener = new ReadCookieDBListener;
-  rv = stmt->ExecuteAsync(readListener,
-                          getter_AddRefs(mDefaultDBState.pendingRead));
-  NS_ASSERT_SUCCESS(rv);
-
-  mDefaultDBState.readListener = readListener;
-  if (!mDefaultDBState.readSet.IsInitialized())
-    mDefaultDBState.readSet.Init();
-
-  return NS_OK;
-}
-
-// Extract data from a single result row and create an nsCookie.
-// This is templated since 'T' is different for sync vs async results.
-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);
-  NS_ASSERT_SUCCESS(rv);
-  rv = aRow->GetUTF8String(2, value);
-  NS_ASSERT_SUCCESS(rv);
-  rv = aRow->GetUTF8String(3, host);
-  NS_ASSERT_SUCCESS(rv);
-  rv = aRow->GetUTF8String(4, path);
-  NS_ASSERT_SUCCESS(rv);
-
-  PRInt64 expiry = aRow->AsInt64(5);
-  PRInt64 lastAccessed = aRow->AsInt64(6);
-  PRBool isSecure = 0 != aRow->AsInt32(7);
-  PRBool isHttpOnly = 0 != aRow->AsInt32(8);
-
-  // create a new nsCookie and assign the data.
-  return nsCookie::Create(name, value, host, path,
-                          expiry,
-                          lastAccessed,
-                          creationID,
-                          PR_FALSE,
-                          isSecure,
-                          isHttpOnly);
-}
-
-void
-nsCookieService::AsyncReadComplete()
-{
-  NS_ASSERTION(mDBState == &mDefaultDBState, "not in default db state");
-  NS_ASSERTION(mDBState->pendingRead, "no pending read");
-  NS_ASSERTION(mDBState->readListener, "no read listener");
-
-  // Merge the data read on the background thread with the data synchronously
-  // read on the main thread. Note that transactions on the cookie table may
-  // have occurred on the main thread since, making the background data stale.
-  for (PRUint32 i = 0; i < mDefaultDBState.hostArray.Length(); ++i) {
-    const CookieDomainTuple &tuple = mDefaultDBState.hostArray[i];
-
-    // Tiebreak: if the given base domain has already been read in, ignore
-    // the background data. Note that readSet may contain domains that were
-    // queried but found not to be in the db -- that's harmless.
-    if (mDefaultDBState.readSet.GetEntry(tuple.baseDomain))
-      continue;
-
-    AddCookieToList(tuple.baseDomain, tuple.cookie, NULL, PR_FALSE);
+  nsCAutoString baseDomain, name, value, host, path;
+  PRBool hasResult;
+  while (NS_SUCCEEDED(rv = stmt->ExecuteStep(&hasResult)) && hasResult) {
+    PRInt64 creationID = stmt->AsInt64(0);
+
+    stmt->GetUTF8String(1, name);
+    stmt->GetUTF8String(2, value);
+    stmt->GetUTF8String(3, host);
+    stmt->GetUTF8String(4, path);
+
+    PRInt64 expiry = stmt->AsInt64(5);
+    PRInt64 lastAccessed = stmt->AsInt64(6);
+    PRBool isSecure = 0 != stmt->AsInt32(7);
+    PRBool isHttpOnly = 0 != stmt->AsInt32(8);
+
+    stmt->GetUTF8String(9, baseDomain);
+
+    // create a new nsCookie and assign the data.
+    nsCookie* newCookie =
+      nsCookie::Create(name, value, host, path,
+                       expiry,
+                       lastAccessed,
+                       creationID,
+                       PR_FALSE,
+                       isSecure,
+                       isHttpOnly);
+    if (!newCookie)
+      return NS_ERROR_OUT_OF_MEMORY;
+
+    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.
+      // When a cookie no longer has purpose, it has a choice:
+      // it can return to the source to be deleted, or it can go
+      // into exile, and stay hidden inside the Matrix.
+      // Let's choose deletion.
+      delete newCookie;
   }
 
-  mDefaultDBState.stmtReadDomain = nsnull;
-  mDefaultDBState.pendingRead = nsnull;
-  mDefaultDBState.readListener = nsnull;
-  mDefaultDBState.syncConn = nsnull;
-  mDefaultDBState.hostArray.Clear();
-  mDefaultDBState.readSet.Clear();
-
-  mObserverService->NotifyObservers(nsnull, "cookie-db-read", nsnull);
-
-  COOKIE_LOGSTRING(PR_LOG_DEBUG, ("Read(): %ld cookies read",
-                                  mDefaultDBState.cookieCount));
-}
-
-void
-nsCookieService::CancelAsyncRead(PRBool aPurgeReadSet)
-{
-  NS_ASSERTION(mDBState == &mDefaultDBState, "not in default db state");
-  NS_ASSERTION(mDBState->pendingRead, "no pending read");
-  NS_ASSERTION(mDBState->readListener, "no read listener");
-
-  // Cancel the pending read, kill the read listener, and empty the array
-  // of data already read in on the background thread.
-  mDefaultDBState.readListener->Cancel();
-  nsresult rv = mDefaultDBState.pendingRead->Cancel();
-  NS_ASSERT_SUCCESS(rv);
-
-  mDefaultDBState.stmtReadDomain = nsnull;
-  mDefaultDBState.pendingRead = nsnull;
-  mDefaultDBState.readListener = nsnull;
-  mDefaultDBState.hostArray.Clear();
-
-  // Only clear the 'readSet' table if we no longer need to know what set of
-  // data is already accounted for.
-  if (aPurgeReadSet)
-    mDefaultDBState.readSet.Clear();
-}
-
-mozIStorageConnection*
-nsCookieService::GetSyncDBConn()
-{
-  NS_ASSERTION(!mDefaultDBState.syncConn, "already have sync db connection");
-
-  // Start a new connection for sync reads to reduce contention with the
-  // background thread.
-  nsCOMPtr<nsIFile> cookieFile;
-  mDefaultDBState.dbConn->GetDatabaseFile(getter_AddRefs(cookieFile));
-  NS_ASSERTION(cookieFile, "no cookie file on connection");
-
-  mStorageService->OpenDatabase(cookieFile,
-    getter_AddRefs(mDefaultDBState.syncConn));
-  NS_ASSERTION(mDefaultDBState.syncConn, "can't open sync db connection");
-  return mDefaultDBState.syncConn;
-}
-
-void
-nsCookieService::EnsureReadDomain(const nsCString &aBaseDomain)
-{
-  NS_ASSERTION(!mDBState->dbConn || mDBState == &mDefaultDBState,
-    "not in default db state");
-
-  // Fast path 1: nothing to read, or we've already finished reading.
-  if (NS_LIKELY(!mDBState->dbConn || !mDefaultDBState.pendingRead))
-    return;
-
-  // Fast path 2: already read in this particular domain.
-  if (NS_LIKELY(mDefaultDBState.readSet.GetEntry(aBaseDomain)))
-    return;
-
-  // Read in the data synchronously.
-  nsresult rv;
-  if (!mDefaultDBState.stmtReadDomain) {
-    if (!GetSyncDBConn())
-      return;
-
-    // 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, "
-        "isSecure, "
-        "isHttpOnly "
-      "FROM moz_cookies "
-      "WHERE baseDomain = ?1"),
-      getter_AddRefs(mDefaultDBState.stmtReadDomain));
-
-    // XXX Ignore corruption for now. See bug 547031.
-    if (NS_FAILED(rv)) return;
-  }
-
-  NS_ASSERTION(mDefaultDBState.syncConn, "should have a sync db connection");
-
-  mozStorageStatementScoper scoper(mDefaultDBState.stmtReadDomain);
-
-  rv = mDefaultDBState.stmtReadDomain->BindUTF8StringByIndex(0, aBaseDomain);
-  NS_ASSERT_SUCCESS(rv);
-
-  PRBool hasResult;
-  PRUint32 readCount = 0;
-  nsCString name, value, host, path;
-  while (1) {
-    rv = mDefaultDBState.stmtReadDomain->ExecuteStep(&hasResult);
-    // XXX Ignore corruption for now. See bug 547031.
-    if (NS_FAILED(rv)) return;
-
-    if (!hasResult)
-      break;
-
-    nsCookie* newCookie = GetCookieFromRow(mDefaultDBState.stmtReadDomain);
-    AddCookieToList(aBaseDomain, newCookie, NULL, PR_FALSE);
-    ++readCount;
-  }
-
-  // Add it to the hashset of read entries, so we don't read it again.
-  mDefaultDBState.readSet.PutEntry(aBaseDomain);
-
-  COOKIE_LOGSTRING(PR_LOG_DEBUG,
-    ("EnsureReadDomain(): %ld cookies read for base domain %s",
-     readCount, aBaseDomain.get()));
-}
-
-void
-nsCookieService::EnsureReadComplete()
-{
-  NS_ASSERTION(!mDBState->dbConn || mDBState == &mDefaultDBState,
-    "not in default db state");
-
-  // Fast path 1: nothing to read, or we've already finished reading.
-  if (NS_LIKELY(!mDBState->dbConn || !mDefaultDBState.pendingRead))
-    return;
-
-  // Cancel the pending read, so we don't get any more results.
-  CancelAsyncRead(PR_FALSE);
-
-  if (!mDefaultDBState.syncConn && !GetSyncDBConn())
-    return;
-
-  // Read in the data synchronously.
-  nsCOMPtr<mozIStorageStatement> stmt;
-  nsresult rv = mDefaultDBState.syncConn->CreateStatement(NS_LITERAL_CSTRING(
-    "SELECT "
-      "id, "
-      "name, "
-      "value, "
-      "host, "
-      "path, "
-      "expiry, "
-      "lastAccessed, "
-      "isSecure, "
-      "isHttpOnly, "
-      "baseDomain "
-    "FROM moz_cookies"), getter_AddRefs(stmt));
-
-  // XXX Ignore corruption for now. See bug 547031.
-  if (NS_FAILED(rv)) return;
-
-  nsCString baseDomain, name, value, host, path;
-  PRBool hasResult;
-  PRUint32 readCount = 0;
-  while (1) {
-    rv = stmt->ExecuteStep(&hasResult);
-    // XXX Ignore corruption for now. See bug 547031.
-    if (NS_FAILED(rv)) return;
-
-    if (!hasResult)
-      break;
-
-    // Make sure we haven't already read the data.
-    stmt->GetUTF8String(9, baseDomain);
-    if (mDefaultDBState.readSet.GetEntry(baseDomain))
-      continue;
-
-    nsCookie* newCookie = GetCookieFromRow(stmt);
-    AddCookieToList(baseDomain, newCookie, NULL, PR_FALSE);
-    ++readCount;
-  }
-
-  mDefaultDBState.syncConn = nsnull;
-  mDefaultDBState.readSet.Clear();
-
-  mObserverService->NotifyObservers(nsnull, "cookie-db-read", nsnull);
-
-  COOKIE_LOGSTRING(PR_LOG_DEBUG,
-    ("EnsureReadComplete(): %ld cookies read", readCount));
+  COOKIE_LOGSTRING(PR_LOG_DEBUG, ("Read(): %ld cookies read", mDBState->cookieCount));
+
+  return rv;
 }
 
 NS_IMETHODIMP
 nsCookieService::ImportCookies(nsIFile *aCookieFile)
 {
   nsresult rv;
   nsCOMPtr<nsIInputStream> fileInputStream;
   rv = NS_NewLocalFileInputStream(getter_AddRefs(fileInputStream), aCookieFile);
@@ -1722,19 +1456,16 @@ nsCookieService::ImportCookies(nsIFile *
    * in a comment, so they don't expose HttpOnly cookies to JS.
    *
    * The format for HttpOnly cookies is
    *
    * #HttpOnly_host \t isDomain \t path \t secure \t expires \t name \t cookie
    *
    */
 
-  // First, ensure we've read in everything from the database, if we have one.
-  EnsureReadComplete();
-
   // 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 (originalCookieCount == 0 && mDBState->dbConn) {
     mDBState->stmtInsert->NewBindingParamsArray(getter_AddRefs(paramsArray));
   }
 
   while (isMore && NS_SUCCEEDED(lineInputStream->ReadLine(buffer, &isMore))) {
@@ -1921,18 +1652,16 @@ nsCookieService::GetCookieInternal(nsIUR
   }
 
   nsCookie *cookie;
   nsAutoTArray<nsCookie*, 8> foundCookieList;
   PRInt64 currentTimeInUsec = PR_Now();
   PRInt64 currentTime = currentTimeInUsec / PR_USEC_PER_SEC;
   PRBool stale = PR_FALSE;
 
-  EnsureReadDomain(baseDomain);
-
   // perform the hash lookup
   nsCookieEntry *entry = mDBState->hostTable.GetEntry(baseDomain);
   if (!entry)
     return;
 
   // iterate the cookies!
   const nsCookieEntry::ArrayType &cookies = entry->GetCookies();
   for (nsCookieEntry::IndexType i = 0; i < cookies.Length(); ++i) {
@@ -2982,18 +2711,16 @@ nsCookieService::PurgeCookies(PRInt64 aC
   // Create a params array to batch the removals. This is OK here because
   // all the removals are in order, and there are no interleaved additions.
   mozIStorageStatement *stmt = mDBState->stmtDelete;
   nsCOMPtr<mozIStorageBindingParamsArray> paramsArray;
   if (mDBState->dbConn) {
     stmt->NewBindingParamsArray(getter_AddRefs(paramsArray));
   }
 
-  EnsureReadComplete();
-
   nsPurgeData data(aCurrentTimeInUsec / PR_USEC_PER_SEC,
     aCurrentTimeInUsec - mCookiePurgeAge, purgeList, removedList, paramsArray);
   mDBState->hostTable.EnumerateEntries(purgeCookiesCallback, &data);
 
 #ifdef PR_LOGGING
   PRUint32 postExpiryCookieCount = mDBState->cookieCount;
 #endif
 
@@ -3076,18 +2803,16 @@ nsCookieService::CookieExists(nsICookie2
 }
 
 // count the number of cookies in a base domain, and simultaneously find the
 // oldest cookie in that domain.
 PRUint32
 nsCookieService::CountCookiesFromHostInternal(const nsCString   &aBaseDomain,
                                               nsEnumerationData &aData)
 {
-  EnsureReadDomain(aBaseDomain);
-
   nsCookieEntry *entry = mDBState->hostTable.GetEntry(aBaseDomain);
   if (!entry)
     return 0;
 
   PRUint32 countFromHost = 0;
   const nsCookieEntry::ArrayType &cookies = entry->GetCookies();
   for (nsCookieEntry::IndexType i = 0; i < cookies.Length(); ++i) {
     nsCookie *cookie = cookies[i];
@@ -3141,18 +2866,16 @@ nsCookieService::GetCookiesFromHost(cons
 
   nsCAutoString baseDomain;
   rv = GetBaseDomainFromHost(host, baseDomain);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMArray<nsICookie> cookieList(mMaxCookiesPerHost);
   PRInt64 currentTime = PR_Now() / PR_USEC_PER_SEC;
 
-  EnsureReadDomain(baseDomain);
-
   nsCookieEntry *entry = mDBState->hostTable.GetEntry(baseDomain);
   if (!entry)
     return NS_NewEmptyEnumerator(aEnumerator);
 
   const nsCookieEntry::ArrayType &cookies = entry->GetCookies();
   for (nsCookieEntry::IndexType i = 0; i < cookies.Length(); ++i) {
     nsCookie *cookie = cookies[i];
 
@@ -3168,18 +2891,16 @@ nsCookieService::GetCookiesFromHost(cons
 PRBool
 nsCookieService::FindCookie(const nsCString      &aBaseDomain,
                             const nsAFlatCString &aHost,
                             const nsAFlatCString &aName,
                             const nsAFlatCString &aPath,
                             nsListIter           &aIter,
                             PRInt64               aCurrentTime)
 {
-  EnsureReadDomain(aBaseDomain);
-
   nsCookieEntry *entry = mDBState->hostTable.GetEntry(aBaseDomain);
   if (!entry)
     return PR_FALSE;
 
   const nsCookieEntry::ArrayType &cookies = entry->GetCookies();
   for (nsCookieEntry::IndexType i = 0; i < cookies.Length(); ++i) {
     nsCookie *cookie = cookies[i];
 
@@ -3289,29 +3010,32 @@ bindCookieParameters(mozIStorageBindingP
   rv = params->BindInt32ByIndex(9, aCookie->IsHttpOnly());
   NS_ASSERT_SUCCESS(rv);
 
   // Bind the params to the array.
   rv = aParamsArray->AddParams(params);
   NS_ASSERT_SUCCESS(rv);
 }
 
-void
+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);
-  NS_ASSERTION(entry, "can't insert element into a null entry!");
+  if (!entry) {
+    NS_ERROR("can't insert element into a null entry!");
+    return PR_FALSE;
+  }
 
   entry->GetCookies().AppendElement(aCookie);
   ++mDBState->cookieCount;
 
   // keep track of the oldest cookie, for when it comes time to purge
   if (aCookie->LastAccessed() < mDBState->cookieOldestTime)
     mDBState->cookieOldestTime = aCookie->LastAccessed();
 
@@ -3329,16 +3053,18 @@ nsCookieService::AddCookieToList(const n
     if (!aParamsArray) {
       nsresult rv = stmt->BindParameters(paramsArray);
       NS_ASSERT_SUCCESS(rv);
       nsCOMPtr<mozIStoragePendingStatement> handle;
       rv = stmt->ExecuteAsync(mInsertListener, getter_AddRefs(handle));
       NS_ASSERT_SUCCESS(rv);
     }
   }
+
+  return PR_TRUE;
 }
 
 void
 nsCookieService::UpdateCookieInList(nsCookie                      *aCookie,
                                     PRInt64                        aLastAccessed,
                                     mozIStorageBindingParamsArray *aParamsArray)
 {
   NS_ASSERTION(aCookie, "Passing a null cookie to UpdateCookieInList!");
--- a/netwerk/cookie/nsCookieService.h
+++ b/netwerk/cookie/nsCookieService.h
@@ -49,31 +49,28 @@
 #include "nsWeakReference.h"
 
 #include "nsCookie.h"
 #include "nsString.h"
 #include "nsAutoPtr.h"
 #include "nsHashKeys.h"
 #include "nsTHashtable.h"
 #include "mozIStorageStatement.h"
-#include "mozIStoragePendingStatement.h"
 #include "mozIStorageConnection.h"
-#include "mozIStorageRow.h"
 
 class nsICookiePermission;
 class nsIEffectiveTLDService;
 class nsIIDNService;
 class nsIPrefBranch;
 class nsIObserverService;
 class nsIURI;
 class nsIChannel;
-class mozIStorageService;
+class DBListenerErrorHandler;
 class mozIStorageStatementCallback;
 class mozIStorageCompletionCallback;
-class ReadCookieDBListener;
 
 struct nsCookieAttributes;
 struct nsListIter;
 struct nsEnumerationData;
 
 namespace mozilla {
 namespace net {
 #ifdef MOZ_IPC
@@ -133,52 +130,29 @@ class nsCookieEntry : public PLDHashEntr
 
     inline ArrayType& GetCookies() { return mCookies; }
 
   private:
     nsCString mBaseDomain;
     ArrayType mCookies;
 };
 
-// encapsulates a (baseDomain, nsCookie) tuple for temporary storage purposes.
-struct CookieDomainTuple
-{
-  nsCString baseDomain;
-  nsRefPtr<nsCookie> cookie;
-};
-
 // 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), cookieOldestTime(LL_MAXINT) { }
 
   nsTHashtable<nsCookieEntry>     hostTable;
   PRUint32                        cookieCount;
   PRInt64                         cookieOldestTime;
   nsCOMPtr<mozIStorageConnection> dbConn;
   nsCOMPtr<mozIStorageStatement>  stmtInsert;
   nsCOMPtr<mozIStorageStatement>  stmtDelete;
   nsCOMPtr<mozIStorageStatement>  stmtUpdate;
-
-  // Various parts representing asynchronous read state. These are useful
-  // while the background read is taking place.
-  nsCOMPtr<mozIStorageConnection>       syncConn;
-  nsCOMPtr<mozIStorageStatement>        stmtReadDomain;
-  nsCOMPtr<mozIStoragePendingStatement> pendingRead;
-  // The asynchronous read listener. This is a weak ref (storage has ownership)
-  // since it may need to outlive the DBState's database connection.
-  ReadCookieDBListener*                 readListener;
-  // An array of (baseDomain, cookie) tuples representing data read in
-  // asynchronously. This is merged into hostTable once read is complete.
-  nsTArray<CookieDomainTuple>           hostArray;
-  // A hashset of baseDomains read in synchronously, while the async read is
-  // in flight. This is used to keep track of which data in hostArray is stale
-  // when the time comes to merge.
-  nsTHashtable<nsCStringHashKey>        readSet;
 };
 
 // these constants represent a decision about a cookie based on user prefs.
 enum CookieStatus
 {
   STATUS_ACCEPTED,
   STATUS_ACCEPT_SESSION,
   STATUS_REJECTED,
@@ -214,31 +188,25 @@ class nsCookieService : public nsICookie
 
   protected:
     void                          PrefChanged(nsIPrefBranch *aPrefBranch);
     nsresult                      InitDB();
     nsresult                      TryInitDB(PRBool aDeleteExistingDB);
     nsresult                      CreateTable();
     void                          CloseDB();
     nsresult                      Read();
-    template<class T> nsCookie*   GetCookieFromRow(T &aRow);
-    void                          AsyncReadComplete();
-    void                          CancelAsyncRead(PRBool aPurgeReadSet);
-    mozIStorageConnection*        GetSyncDBConn();
-    void                          EnsureReadDomain(const nsCString &aBaseDomain);
-    void                          EnsureReadComplete();
     nsresult                      NormalizeHost(nsCString &aHost);
     nsresult                      GetBaseDomain(nsIURI *aHostURI, nsCString &aBaseDomain, PRBool &aRequireHostMatch);
     nsresult                      GetBaseDomainFromHost(const nsACString &aHost, nsCString &aBaseDomain);
     void                          GetCookieInternal(nsIURI *aHostURI, nsIURI *aOriginatingURI, PRBool aHttpBound, nsCString &aCookie);
     void                          SetCookieStringInternal(nsIURI *aHostURI, nsIURI *aOriginatingURI, const nsCString &aCookieHeader, const nsCString &aServerTime, PRBool aFromHttp);
     PRBool                        SetCookieInternal(nsIURI *aHostURI, const nsCString& aBaseDomain, PRBool aRequireHostMatch, CookieStatus aStatus, 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, mozIStorageBindingParamsArray *aParamsArray = NULL);
-    void                          AddCookieToList(const nsCString& aBaseDomain, nsCookie *aCookie, mozIStorageBindingParamsArray *aParamsArray, PRBool aWriteToDB = PR_TRUE);
+    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);
     void                          GetOriginatingURI(nsIChannel *aChannel, nsIURI **aURI);
     CookieStatus                  CheckPrefs(nsIURI *aHostURI, nsIURI *aOriginatingURI, const nsCString &aBaseDomain, PRBool aRequireHostMatch, const char *aCookieHeader);
     PRBool                        CheckDomain(nsCookieAttributes &aCookie, nsIURI *aHostURI, const nsCString &aBaseDomain, PRBool aRequireHostMatch);
     static PRBool                 CheckPath(nsCookieAttributes &aCookie, nsIURI *aHostURI);
@@ -251,17 +219,16 @@ class nsCookieService : public nsICookie
     void                          NotifyChanged(nsISupports *aSubject, const PRUnichar *aData);
 
   protected:
     // cached members.
     nsCOMPtr<nsIObserverService>     mObserverService;
     nsCOMPtr<nsICookiePermission>    mPermissionService;
     nsCOMPtr<nsIEffectiveTLDService> mTLDService;
     nsCOMPtr<nsIIDNService>          mIDNService;
-    nsCOMPtr<mozIStorageService>     mStorageService;
 
     // 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;
@@ -275,19 +242,18 @@ class nsCookieService : public nsICookie
 
     // cached prefs
     PRUint8                       mCookieBehavior; // BEHAVIOR_{ACCEPT, REJECTFOREIGN, REJECT}
     PRBool                        mThirdPartySession;
     PRUint16                      mMaxNumberOfCookies;
     PRUint16                      mMaxCookiesPerHost;
     PRInt64                       mCookiePurgeAge;
 
-    // friends!
+    // this callback needs access to member functions
     friend PLDHashOperator purgeCookiesCallback(nsCookieEntry *aEntry, void *aArg);
-    friend class ReadCookieDBListener;
 
     static nsCookieService*       GetSingleton();
 #ifdef MOZ_IPC
     friend class mozilla::net::CookieServiceParent;
 #endif
 };
 
 #endif // nsCookieService_h__
--- a/storage/src/mozStorageStatement.cpp
+++ b/storage/src/mozStorageStatement.cpp
@@ -778,17 +778,17 @@ NS_IMETHODIMP
 Statement::GetUTF8String(PRUint32 aIndex,
                          nsACString &_value)
 {
   // Get type of Index will check aIndex for us, so we don't have to.
   PRInt32 type;
   nsresult rv = GetTypeOfIndex(aIndex, &type);
   NS_ENSURE_SUCCESS(rv, rv);
   if (type == mozIStorageStatement::VALUE_TYPE_NULL) {
-    // NULL columns should have IsVoid set to distinguish them from the empty
+    // NULL columns should have IsVod set to distinguis them from an empty
     // string.
     _value.Truncate(0);
     _value.SetIsVoid(PR_TRUE);
   }
   else {
     const char *value =
       reinterpret_cast<const char *>(::sqlite3_column_text(mDBStatement,
                                                            aIndex));
@@ -801,17 +801,17 @@ NS_IMETHODIMP
 Statement::GetString(PRUint32 aIndex,
                      nsAString &_value)
 {
   // Get type of Index will check aIndex for us, so we don't have to.
   PRInt32 type;
   nsresult rv = GetTypeOfIndex(aIndex, &type);
   NS_ENSURE_SUCCESS(rv, rv);
   if (type == mozIStorageStatement::VALUE_TYPE_NULL) {
-    // NULL columns should have IsVoid set to distinguish them from the empty
+    // NULL columns should have IsVod set to distinguis them from an empty
     // string.
     _value.Truncate(0);
     _value.SetIsVoid(PR_TRUE);
   } else {
     const PRUnichar *value =
       static_cast<const PRUnichar *>(::sqlite3_column_text16(mDBStatement,
                                                              aIndex));
     _value.Assign(value, ::sqlite3_column_bytes16(mDBStatement, aIndex) / 2);