Bug 856032 - Quota management enabled even for origins with unlimited permission granted. r=janv, a=tef+
authorBen Turner <bent.mozilla@gmail.com>
Mon, 01 Apr 2013 14:48:40 -0400
changeset 118662 ccec751a468e42b070f6f2fbeda3ca7da4790ab1
parent 118661 b28463f2e718f823eef637b107fe7f2a3aa89107
child 118663 a0c63f84ab56094cc3bd62967440236824ef5019
push id74
push userryanvm@gmail.com
push dateMon, 01 Apr 2013 18:48:50 +0000
reviewersjanv, tef
bugs856032
milestone18.0
Bug 856032 - Quota management enabled even for origins with unlimited permission granted. r=janv, a=tef+
db/sqlite3/src/test_quota.c
dom/indexedDB/CheckPermissionsHelper.cpp
dom/indexedDB/CheckQuotaHelper.cpp
dom/indexedDB/CheckQuotaHelper.h
dom/indexedDB/FileManager.cpp
dom/indexedDB/FileManager.h
dom/indexedDB/IDBObjectStore.cpp
dom/indexedDB/IndexedDatabaseManager.cpp
dom/indexedDB/IndexedDatabaseManager.h
dom/indexedDB/OpenDatabaseHelper.cpp
dom/indexedDB/OpenDatabaseHelper.h
--- a/db/sqlite3/src/test_quota.c
+++ b/db/sqlite3/src/test_quota.c
@@ -662,28 +662,39 @@ static int quotaSync(sqlite3_file *pConn
 /* Pass xFileSize requests through to the original VFS but then
 ** update the quotaGroup with the new size before returning.
 */
 static int quotaFileSize(sqlite3_file *pConn, sqlite3_int64 *pSize){
   quotaConn *p = (quotaConn*)pConn;
   sqlite3_file *pSubOpen = quotaSubOpen(pConn);
   quotaFile *pFile = p->pFile;
   quotaGroup *pGroup;
-  sqlite3_int64 sz;
+  sqlite3_int64 szFile, szGroup;
   int rc;
 
-  rc = pSubOpen->pMethods->xFileSize(pSubOpen, &sz);
+  rc = pSubOpen->pMethods->xFileSize(pSubOpen, &szFile);
   if( rc==SQLITE_OK ){
     quotaEnter();
     pGroup = pFile->pGroup;
-    pGroup->iSize -= pFile->iSize;
-    pFile->iSize = sz;
-    pGroup->iSize += sz;
+    szGroup =  pGroup->iSize - pFile->iSize + szFile;
+    if( szGroup>pGroup->iLimit && pGroup->iLimit>0 ){
+      if( pGroup->xCallback ){
+        pGroup->xCallback(pFile->zFilename, &pGroup->iLimit, szGroup,
+                          pGroup->pArg);
+      }
+      if( szGroup>pGroup->iLimit && pGroup->iLimit>0 ){
+        rc = SQLITE_FULL;
+      }
+    }
+    if( rc==SQLITE_OK ){
+      pGroup->iSize = szGroup;
+      pFile->iSize = szFile;
+      *pSize = szFile;
+    }
     quotaLeave();
-    *pSize = sz;
   }
   return rc;
 }
 
 /* Pass xLock requests through to the original VFS unchanged.
 */
 static int quotaLock(sqlite3_file *pConn, int lock){
   sqlite3_file *pSubOpen = quotaSubOpen(pConn);
--- a/dom/indexedDB/CheckPermissionsHelper.cpp
+++ b/dom/indexedDB/CheckPermissionsHelper.cpp
@@ -17,16 +17,17 @@
 
 #include "nsContentUtils.h"
 #include "nsDOMStorage.h"
 #include "nsNetUtil.h"
 #include "nsThreadUtils.h"
 #include "mozilla/Services.h"
 #include "mozilla/Preferences.h"
 
+#include "CheckQuotaHelper.h"
 #include "IndexedDatabaseManager.h"
 
 #define PERMISSION_INDEXEDDB "indexedDB"
 #define PREF_INDEXEDDB_ENABLED "dom.indexedDB.enabled"
 #define TOPIC_PERMISSIONS_PROMPT "indexedDB-permissions-prompt"
 #define TOPIC_PERMISSIONS_RESPONSE "indexedDB-permissions-response"
 
 // This is a little confusing, but our default behavior (UNKNOWN_ACTION) is to
@@ -105,23 +106,25 @@ CheckPermissionsHelper::Run()
   nsresult rv;
   if (mHasPrompted) {
     // Add permissions to the database, but only if we are in the parent
     // process (if we are in the child process, we have already
     // set the permission when the prompt was shown in the parent, as
     // we cannot set the permission from the child).
     if (permission != PERMISSION_PROMPT &&
         IndexedDatabaseManager::IsMainProcess()) {
+      NS_ASSERTION(mWindow, "Null window!");
+
+      nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(mWindow);
+      NS_ASSERTION(sop, "Window didn't QI to nsIScriptObjectPrincipal!");
+
       nsCOMPtr<nsIPermissionManager> permissionManager =
         do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
       NS_ENSURE_STATE(permissionManager);
 
-      nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(mWindow);
-      NS_ENSURE_TRUE(sop, NS_ERROR_FAILURE);
-
       rv = permissionManager->AddFromPrincipal(sop->GetPrincipal(),
                                                PERMISSION_INDEXEDDB, permission,
                                                nsIPermissionManager::EXPIRE_NEVER,
                                                0);
       NS_ENSURE_SUCCESS(rv, rv);
     }
   }
   else if (permission == PERMISSION_PROMPT && mPromptAllowed) {
@@ -135,16 +138,31 @@ CheckPermissionsHelper::Run()
 
   nsRefPtr<OpenDatabaseHelper> helper;
   helper.swap(mHelper);
 
   nsCOMPtr<nsIDOMWindow> window;
   window.swap(mWindow);
 
   if (permission == PERMISSION_ALLOWED) {
+    // If we're running from a window then we should check the quota permission
+    // as well. If we don't have a window then we're opening a chrome database
+    // and the quota will be unlimited already.
+    if (window) {
+      nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(window);
+      NS_ASSERTION(sop, "Window didn't QI to nsIScriptObjectPrincipal!");
+
+      uint32_t quotaPermission =
+        CheckQuotaHelper::GetQuotaPermission(sop->GetPrincipal());
+
+      if (quotaPermission == nsIPermissionManager::ALLOW_ACTION) {
+        helper->SetUnlimitedQuotaAllowed();
+      }
+    }
+
     IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
     NS_ASSERTION(mgr, "This should never be null!");
 
     return helper->Dispatch(mgr->IOThread());
   }
 
   NS_ASSERTION(permission == PERMISSION_PROMPT ||
                permission == PERMISSION_DENIED,
--- a/dom/indexedDB/CheckQuotaHelper.cpp
+++ b/dom/indexedDB/CheckQuotaHelper.cpp
@@ -30,39 +30,24 @@
 USING_INDEXEDDB_NAMESPACE
 using namespace mozilla::services;
 using mozilla::MutexAutoLock;
 
 namespace {
 
 inline
 uint32_t
-GetQuotaPermissions(nsIDOMWindow* aWindow)
+GetQuotaPermissionFromWindow(nsIDOMWindow* aWindow)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   nsCOMPtr<nsIScriptObjectPrincipal> sop(do_QueryInterface(aWindow));
   NS_ENSURE_TRUE(sop, nsIPermissionManager::DENY_ACTION);
 
-  if (nsContentUtils::IsSystemPrincipal(sop->GetPrincipal())) {
-    return nsIPermissionManager::ALLOW_ACTION;
-  }
-
-  nsCOMPtr<nsIPermissionManager> permissionManager =
-    do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
-  NS_ENSURE_TRUE(permissionManager, nsIPermissionManager::DENY_ACTION);
-
-  uint32_t permission;
-  nsresult rv =
-    permissionManager->TestPermissionFromPrincipal(sop->GetPrincipal(),
-                                                   PERMISSION_INDEXEDDB_UNLIMITED,
-                                                   &permission);
-  NS_ENSURE_SUCCESS(rv, nsIPermissionManager::DENY_ACTION);
-
-  return permission;
+  return CheckQuotaHelper::GetQuotaPermission(sop->GetPrincipal());
 }
 
 } // anonymous namespace
 
 CheckQuotaHelper::CheckQuotaHelper(nsPIDOMWindow* aWindow,
                                    mozilla::Mutex& aMutex)
 : mWindow(aWindow),
   mMutex(aMutex),
@@ -123,30 +108,54 @@ CheckQuotaHelper::Cancel()
       }
       else {
         NS_WARNING("Failed to notify!");
       }
     }
   }
 }
 
+// static
+uint32_t
+CheckQuotaHelper::GetQuotaPermission(nsIPrincipal* aPrincipal)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(aPrincipal, "Null principal!");
+
+  if (nsContentUtils::IsSystemPrincipal(aPrincipal)) {
+    return nsIPermissionManager::ALLOW_ACTION;
+  }
+
+  nsCOMPtr<nsIPermissionManager> pm =
+    do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
+  NS_ENSURE_TRUE(pm, nsIPermissionManager::DENY_ACTION);
+
+  uint32_t permission;
+  nsresult rv = pm->TestPermissionFromPrincipal(aPrincipal,
+                                                PERMISSION_INDEXEDDB_UNLIMITED,
+                                                &permission);
+  NS_ENSURE_SUCCESS(rv, nsIPermissionManager::DENY_ACTION);
+
+  return permission;
+}
+
 NS_IMPL_THREADSAFE_ISUPPORTS3(CheckQuotaHelper, nsIRunnable,
                                                 nsIInterfaceRequestor,
                                                 nsIObserver)
 
 NS_IMETHODIMP
 CheckQuotaHelper::Run()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   nsresult rv = NS_OK;
 
   if (NS_SUCCEEDED(rv)) {
     if (!mHasPrompted) {
-      mPromptResult = GetQuotaPermissions(mWindow);
+      mPromptResult = GetQuotaPermissionFromWindow(mWindow);
     }
 
     if (mHasPrompted) {
       // Add permissions to the database, but only if we are in the parent
       // process (if we are in the child process, we have already
       // set the permission when the prompt was shown in the parent, as
       // we cannot set the permission from the child).
       if (mPromptResult != nsIPermissionManager::UNKNOWN_ACTION &&
--- a/dom/indexedDB/CheckQuotaHelper.h
+++ b/dom/indexedDB/CheckQuotaHelper.h
@@ -13,16 +13,17 @@
 
 #include "nsIInterfaceRequestor.h"
 #include "nsIObserver.h"
 #include "nsIRunnable.h"
 
 #include "mozilla/Mutex.h"
 #include "mozilla/CondVar.h"
 
+class nsIPrincipal;
 class nsPIDOMWindow;
 
 BEGIN_INDEXEDDB_NAMESPACE
 
 class CheckQuotaHelper MOZ_FINAL : public nsIRunnable,
                                    public nsIInterfaceRequestor,
                                    public nsIObserver
 {
@@ -34,16 +35,18 @@ public:
 
   CheckQuotaHelper(nsPIDOMWindow* aWindow,
                    mozilla::Mutex& aMutex);
 
   bool PromptAndReturnQuotaIsDisabled();
 
   void Cancel();
 
+  static uint32_t GetQuotaPermission(nsIPrincipal* aPrincipal);
+
 private:
   nsPIDOMWindow* mWindow;
 
   mozilla::Mutex& mMutex;
   mozilla::CondVar mCondVar;
   uint32_t mPromptResult;
   bool mWaiting;
   bool mHasPrompted;
--- a/dom/indexedDB/FileManager.cpp
+++ b/dom/indexedDB/FileManager.cpp
@@ -257,23 +257,21 @@ FileManager::GetFileForId(nsIFile* aDire
   rv = file->Append(id);
   NS_ENSURE_SUCCESS(rv, nullptr);
 
   return file.forget();
 }
 
 // static
 nsresult
-FileManager::InitDirectory(mozIStorageServiceQuotaManagement* aService,
-                           nsIFile* aDirectory,
+FileManager::InitDirectory(nsIFile* aDirectory,
                            nsIFile* aDatabaseFile,
-                           FactoryPrivilege aPrivilege)
+                           mozIStorageServiceQuotaManagement* aService)
 {
   NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
-  NS_ASSERTION(aService, "Null service!");
   NS_ASSERTION(aDirectory, "Null directory!");
   NS_ASSERTION(aDatabaseFile, "Null database file!");
 
   bool exists;
   nsresult rv = aDirectory->Exists(&exists);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (!exists) {
@@ -372,17 +370,19 @@ FileManager::InitDirectory(mozIStorageSe
         "DROP TABLE fs;"
       ));
       NS_ENSURE_SUCCESS(rv, rv);
 
       transaction.Commit();
     }
   }
 
-  if (aPrivilege == Chrome) {
+  // If no quota service was passed to us then there is no need to update quota
+  // information for files in our directory.
+  if (!aService) {
     return NS_OK;
   }
 
   nsCOMPtr<nsISimpleEnumerator> entries;
   rv = aDirectory->GetDirectoryEntries(getter_AddRefs(entries));
   NS_ENSURE_SUCCESS(rv, rv);
 
   bool hasMore;
--- a/dom/indexedDB/FileManager.h
+++ b/dom/indexedDB/FileManager.h
@@ -63,19 +63,18 @@ public:
 
   already_AddRefed<FileInfo> GetFileInfo(int64_t aId);
 
   already_AddRefed<FileInfo> GetNewFileInfo();
 
   static already_AddRefed<nsIFile> GetFileForId(nsIFile* aDirectory,
                                                 int64_t aId);
 
-  static nsresult InitDirectory(mozIStorageServiceQuotaManagement* aService,
-                                nsIFile* aDirectory, nsIFile* aDatabaseFile,
-                                FactoryPrivilege aPrivilege);
+  static nsresult InitDirectory(nsIFile* aDirectory, nsIFile* aDatabaseFile,
+                                mozIStorageServiceQuotaManagement* aService);
 
 private:
   nsCString mOrigin;
   nsString mDatabaseName;
 
   nsString mDirectoryPath;
   nsString mJournalDirectoryPath;
 
--- a/dom/indexedDB/IDBObjectStore.cpp
+++ b/dom/indexedDB/IDBObjectStore.cpp
@@ -2699,28 +2699,31 @@ inline nsresult
 CopyData(nsIInputStream* aInputStream, nsIOutputStream* aOutputStream)
 {
   nsresult rv;
 
   do {
     char copyBuffer[FILE_COPY_BUFFER_SIZE];
 
     uint32_t numRead;
-    rv = aInputStream->Read(copyBuffer, FILE_COPY_BUFFER_SIZE, &numRead);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    if (numRead <= 0) {
+    rv = aInputStream->Read(copyBuffer, sizeof(copyBuffer), &numRead);
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+    if (!numRead) {
       break;
     }
 
     uint32_t numWrite;
     rv = aOutputStream->Write(copyBuffer, numRead, &numWrite);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    NS_ENSURE_TRUE(numWrite == numRead, NS_ERROR_FAILURE);
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+    if (numWrite < numRead) {
+      // Must have hit the quota limit.
+      return NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR;
+    }
   } while (true);
 
   rv = aOutputStream->Flush();
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
@@ -2922,17 +2925,17 @@ AddHelper::DoDatabaseWork(mozIStorageCon
         nativeFile = fileManager->GetFileForId(directory, id);
         NS_ENSURE_TRUE(nativeFile, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
         nsRefPtr<FileStream> outputStream = new FileStream();
         rv = outputStream->Init(nativeFile, NS_LITERAL_STRING("wb"), 0);
         NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
         rv = CopyData(inputStream, outputStream);
-        NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+        NS_ENSURE_SUCCESS(rv, rv);
 
         cloneFile.mFile->AddFileInfo(fileInfo);
       }
 
       if (index) {
         fileIds.Append(NS_LITERAL_STRING(" "));
       }
       fileIds.AppendInt(id);
--- a/dom/indexedDB/IndexedDatabaseManager.cpp
+++ b/dom/indexedDB/IndexedDatabaseManager.cpp
@@ -110,17 +110,20 @@ public:
 
   NS_IMETHOD
   QuotaExceeded(const nsACString& aFilename,
                 int64_t aCurrentSizeLimit,
                 int64_t aCurrentTotalSize,
                 nsISupports* aUserData,
                 int64_t* _retval)
   {
-    if (IndexedDatabaseManager::QuotaIsLifted()) {
+    IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
+    NS_ASSERTION(mgr, "Must have a manager here!");
+
+    if (mgr->QuotaIsLifted()) {
       *_retval = 0;
       return NS_OK;
     }
 
     return NS_ERROR_FAILURE;
   }
 };
 
@@ -955,17 +958,17 @@ IndexedDatabaseManager::SetCurrentWindow
 uint32_t
 IndexedDatabaseManager::GetIndexedDBQuotaMB()
 {
   return uint32_t(NS_MAX(gIndexedDBQuotaMB, 0));
 }
 
 nsresult
 IndexedDatabaseManager::EnsureOriginIsInitialized(const nsACString& aOrigin,
-                                                  FactoryPrivilege aPrivilege,
+                                                  bool aTrackQuota,
                                                   nsIFile** aDirectory)
 {
 #ifdef DEBUG
   {
     bool correctThread;
     NS_ASSERTION(NS_SUCCEEDED(mIOThread->IsOnCurrentThread(&correctThread)) &&
                  correctThread,
                  "Running on the wrong thread!");
@@ -1008,17 +1011,17 @@ IndexedDatabaseManager::EnsureOriginIsIn
   rv = patternFile->GetPath(pattern);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Now tell SQLite to start tracking this pattern for content.
   nsCOMPtr<mozIStorageServiceQuotaManagement> ss =
     do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID);
   NS_ENSURE_TRUE(ss, NS_ERROR_FAILURE);
 
-  if (aPrivilege != Chrome) {
+  if (aTrackQuota) {
     rv = ss->SetQuotaForFilenamePattern(NS_ConvertUTF16toUTF8(pattern),
                                         GetIndexedDBQuotaMB() * 1024 * 1024,
                                         mQuotaCallbackSingleton, nullptr);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   // We need to see if there are any files in the directory already. If they
   // are database files then we need to cleanup stored files (if it's needed)
@@ -1070,21 +1073,21 @@ IndexedDatabaseManager::EnsureOriginIsIn
 
     nsCOMPtr<nsIFile> fileManagerDirectory;
     rv = directory->Clone(getter_AddRefs(fileManagerDirectory));
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = fileManagerDirectory->Append(dbBaseFilename);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    rv = FileManager::InitDirectory(ss, fileManagerDirectory, file,
-                                    aPrivilege);
+    rv = FileManager::InitDirectory(fileManagerDirectory, file,
+                                    aTrackQuota ? ss : nullptr);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    if (aPrivilege != Chrome) {
+    if (aTrackQuota) {
       rv = ss->UpdateQuotaInformationForFile(file);
       NS_ENSURE_SUCCESS(rv, rv);
     }
 
     validSubdirs.PutEntry(dbBaseFilename);
   }
   NS_ENSURE_SUCCESS(rv, rv);
 
@@ -1119,17 +1122,17 @@ IndexedDatabaseManager::EnsureOriginIsIn
 
   mInitializedOrigins.AppendElement(aOrigin);
 
   NS_ADDREF(*aDirectory = directory);
   return NS_OK;
 }
 
 bool
-IndexedDatabaseManager::QuotaIsLiftedInternal()
+IndexedDatabaseManager::QuotaIsLifted()
 {
   nsPIDOMWindow* window = nullptr;
   nsRefPtr<CheckQuotaHelper> helper = nullptr;
   bool createdHelper = false;
 
   window =
     static_cast<nsPIDOMWindow*>(PR_GetThreadPrivate(mCurrentWindowIndex));
 
--- a/dom/indexedDB/IndexedDatabaseManager.h
+++ b/dom/indexedDB/IndexedDatabaseManager.h
@@ -126,29 +126,23 @@ public:
 
     return mgr->SetCurrentWindowInternal(aWindow);
   }
 
   static uint32_t
   GetIndexedDBQuotaMB();
 
   nsresult EnsureOriginIsInitialized(const nsACString& aOrigin,
-                                     FactoryPrivilege aPrivilege,
+                                     bool aTrackQuota,
                                      nsIFile** aDirectory);
 
   // Determine if the quota is lifted for the Window the current thread is
   // using.
-  static inline bool
-  QuotaIsLifted()
-  {
-    IndexedDatabaseManager* mgr = Get();
-    NS_ASSERTION(mgr, "Must have a manager here!");
-
-    return mgr->QuotaIsLiftedInternal();
-  }
+  bool
+  QuotaIsLifted();
 
   static inline void
   CancelPromptsForWindow(nsPIDOMWindow* aWindow)
   {
     IndexedDatabaseManager* mgr = Get();
     NS_ASSERTION(mgr, "Must have a manager here!");
 
     mgr->CancelPromptsForWindowInternal(aWindow);
@@ -221,17 +215,16 @@ private:
   nsresult AcquireExclusiveAccess(const nsACString& aOrigin,
                                   IDBDatabase* aDatabase,
                                   AsyncConnectionHelper* aHelper,
                                   nsIRunnable* aRunnable,
                                   WaitingOnDatabasesCallback aCallback,
                                   void* aClosure);
 
   void SetCurrentWindowInternal(nsPIDOMWindow* aWindow);
-  bool QuotaIsLiftedInternal();
   void CancelPromptsForWindowInternal(nsPIDOMWindow* aWindow);
 
   // Called when a database is created.
   bool RegisterDatabase(IDBDatabase* aDatabase);
 
   // Called when a database is being unlinked or destroyed.
   void UnregisterDatabase(IDBDatabase* aDatabase);
 
--- a/dom/indexedDB/OpenDatabaseHelper.cpp
+++ b/dom/indexedDB/OpenDatabaseHelper.cpp
@@ -1607,17 +1607,17 @@ OpenDatabaseHelper::DoDatabaseWork()
   AutoEnterWindow autoWindow(window);
 
   nsCOMPtr<nsIFile> dbDirectory;
 
   IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
   NS_ASSERTION(mgr, "This should never be null!");
 
   nsresult rv = mgr->EnsureOriginIsInitialized(mASCIIOrigin,
-                                               mPrivilege,
+                                               mTrackingQuota,
                                                getter_AddRefs(dbDirectory));
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   nsAutoString filename;
   rv = GetDatabaseFilename(mName, filename);
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   nsCOMPtr<nsIFile> dbFile;
--- a/dom/indexedDB/OpenDatabaseHelper.h
+++ b/dom/indexedDB/OpenDatabaseHelper.h
@@ -17,32 +17,37 @@ class mozIStorageConnection;
 namespace mozilla {
 namespace dom {
 class ContentParent;
 }
 }
 
 BEGIN_INDEXEDDB_NAMESPACE
 
+class CheckPermissionsHelper;
+
 class OpenDatabaseHelper : public HelperBase
 {
+  friend class CheckPermissionsHelper;
+
 public:
   OpenDatabaseHelper(IDBOpenDBRequest* aRequest,
                      const nsAString& aName,
                      const nsACString& aASCIIOrigin,
                      uint64_t aRequestedVersion,
                      bool aForDeletion,
                      mozilla::dom::ContentParent* aContentParent,
                      FactoryPrivilege aPrivilege)
     : HelperBase(aRequest), mOpenDBRequest(aRequest), mName(aName),
       mASCIIOrigin(aASCIIOrigin), mRequestedVersion(aRequestedVersion),
       mForDeletion(aForDeletion), mPrivilege(aPrivilege), mDatabaseId(nullptr),
       mContentParent(aContentParent), mCurrentVersion(0), mLastObjectStoreId(0),
       mLastIndexId(0), mState(eCreated), mResultCode(NS_OK),
-      mLoadDBMetadata(false)
+      mLoadDBMetadata(false),
+      mTrackingQuota(aPrivilege == Chrome ? false : true)
   {
     NS_ASSERTION(!aForDeletion || !aRequestedVersion,
                  "Can't be for deletion and request a version!");
   }
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSIRUNNABLE
 
@@ -89,16 +94,22 @@ protected:
   nsresult StartSetVersion();
   nsresult StartDelete();
   virtual nsresult GetSuccessResult(JSContext* aCx,
                                     jsval* aVal) MOZ_OVERRIDE;
   void DispatchSuccessEvent();
   void DispatchErrorEvent();
   virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE;
 
+  // Called by CheckPermissionsHelper on the main thread before dispatch.
+  void SetUnlimitedQuotaAllowed()
+  {
+    mTrackingQuota = false;
+  }
+
   // Methods only called on the DB thread
   nsresult DoDatabaseWork();
 
   // In-params.
   nsRefPtr<IDBOpenDBRequest> mOpenDBRequest;
   nsString mName;
   nsCString mASCIIOrigin;
   uint64_t mRequestedVersion;
@@ -127,13 +138,14 @@ protected:
   };
   OpenDatabaseState mState;
   nsresult mResultCode;
 
   nsRefPtr<FileManager> mFileManager;
 
   nsRefPtr<DatabaseInfo> mDBInfo;
   bool mLoadDBMetadata;
+  bool mTrackingQuota;
 };
 
 END_INDEXEDDB_NAMESPACE
 
 #endif // mozilla_dom_indexeddb_opendatabasehelper_h__
\ No newline at end of file