LCOV - code coverage report
Current view: directory - dom/indexedDB - CheckQuotaHelper.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 121 0 0.0 %
Date: 2012-06-02 Functions: 10 0 0.0 %

       1                 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* vim: set ts=2 et sw=2 tw=80: */
       3                 : /* ***** BEGIN LICENSE BLOCK *****
       4                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       5                 :  *
       6                 :  * The contents of this file are subject to the Mozilla Public License Version
       7                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       8                 :  * the License. You may obtain a copy of the License at
       9                 :  * http://www.mozilla.org/MPL/
      10                 :  *
      11                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      12                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      13                 :  * for the specific language governing rights and limitations under the
      14                 :  * License.
      15                 :  *
      16                 :  * The Original Code is Indexed Database.
      17                 :  *
      18                 :  * The Initial Developer of the Original Code is
      19                 :  * The Mozilla Foundation.
      20                 :  * Portions created by the Initial Developer are Copyright (C) 2010
      21                 :  * the Initial Developer. All Rights Reserved.
      22                 :  *
      23                 :  * Contributor(s):
      24                 :  *   Ben Turner <bent.mozilla@gmail.com>
      25                 :  *
      26                 :  * Alternatively, the contents of this file may be used under the terms of
      27                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      28                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      29                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      30                 :  * of those above. If you wish to allow use of your version of this file only
      31                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      32                 :  * use your version of this file under the terms of the MPL, indicate your
      33                 :  * decision by deleting the provisions above and replace them with the notice
      34                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      35                 :  * the provisions above, a recipient may use your version of this file under
      36                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      37                 :  *
      38                 :  * ***** END LICENSE BLOCK ***** */
      39                 : 
      40                 : #include "CheckQuotaHelper.h"
      41                 : 
      42                 : #include "nsIDOMWindow.h"
      43                 : #include "nsIObserverService.h"
      44                 : #include "nsIPermissionManager.h"
      45                 : #include "nsIPrincipal.h"
      46                 : #include "nsIScriptObjectPrincipal.h"
      47                 : #include "nsIURI.h"
      48                 : #include "nsXULAppAPI.h"
      49                 : 
      50                 : #include "nsContentUtils.h"
      51                 : #include "nsNetUtil.h"
      52                 : #include "nsThreadUtils.h"
      53                 : #include "mozilla/Services.h"
      54                 : 
      55                 : #include "IndexedDatabaseManager.h"
      56                 : 
      57                 : #define PERMISSION_INDEXEDDB_UNLIMITED "indexedDB-unlimited"
      58                 : 
      59                 : #define TOPIC_QUOTA_PROMPT "indexedDB-quota-prompt"
      60                 : #define TOPIC_QUOTA_RESPONSE "indexedDB-quota-response"
      61                 : #define TOPIC_QUOTA_CANCEL "indexedDB-quota-cancel"
      62                 : 
      63                 : USING_INDEXEDDB_NAMESPACE
      64                 : using namespace mozilla::services;
      65                 : using mozilla::MutexAutoLock;
      66                 : 
      67                 : namespace {
      68                 : 
      69                 : inline
      70                 : PRUint32
      71               0 : GetQuotaPermissions(const nsACString& aASCIIOrigin,
      72                 :                     nsIDOMWindow* aWindow)
      73                 : {
      74               0 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
      75                 : 
      76               0 :   nsCOMPtr<nsIScriptObjectPrincipal> sop(do_QueryInterface(aWindow));
      77               0 :   NS_ENSURE_TRUE(sop, nsIPermissionManager::DENY_ACTION);
      78                 : 
      79               0 :   if (nsContentUtils::IsSystemPrincipal(sop->GetPrincipal())) {
      80               0 :     return nsIPermissionManager::ALLOW_ACTION;
      81                 :   }
      82                 : 
      83               0 :   nsCOMPtr<nsIURI> uri;
      84               0 :   nsresult rv = NS_NewURI(getter_AddRefs(uri), aASCIIOrigin);
      85               0 :   NS_ENSURE_SUCCESS(rv, nsIPermissionManager::DENY_ACTION);
      86                 : 
      87                 :   nsCOMPtr<nsIPermissionManager> permissionManager =
      88               0 :     do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
      89               0 :   NS_ENSURE_TRUE(permissionManager, nsIPermissionManager::DENY_ACTION);
      90                 : 
      91                 :   PRUint32 permission;
      92               0 :   rv = permissionManager->TestPermission(uri, PERMISSION_INDEXEDDB_UNLIMITED,
      93               0 :                                          &permission);
      94               0 :   NS_ENSURE_SUCCESS(rv, nsIPermissionManager::DENY_ACTION);
      95                 : 
      96               0 :   return permission;
      97                 : }
      98                 : 
      99                 : } // anonymous namespace
     100                 : 
     101               0 : CheckQuotaHelper::CheckQuotaHelper(nsPIDOMWindow* aWindow,
     102                 :                                    mozilla::Mutex& aMutex)
     103                 : : mWindow(aWindow),
     104                 :   mMutex(aMutex),
     105                 :   mCondVar(mMutex, "CheckQuotaHelper::mCondVar"),
     106                 :   mPromptResult(0),
     107                 :   mWaiting(true),
     108               0 :   mHasPrompted(false)
     109                 : {
     110               0 :   NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
     111               0 :   mMutex.AssertCurrentThreadOwns();
     112               0 : }
     113                 : 
     114                 : bool
     115               0 : CheckQuotaHelper::PromptAndReturnQuotaIsDisabled()
     116                 : {
     117               0 :   NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
     118               0 :   mMutex.AssertCurrentThreadOwns();
     119                 : 
     120               0 :   while (mWaiting) {
     121               0 :     mCondVar.Wait();
     122                 :   }
     123                 : 
     124               0 :   NS_ASSERTION(!mWindow, "This should always be null here!");
     125                 : 
     126               0 :   NS_ASSERTION(mPromptResult == nsIPermissionManager::ALLOW_ACTION ||
     127                 :                mPromptResult == nsIPermissionManager::DENY_ACTION ||
     128                 :                mPromptResult == nsIPermissionManager::UNKNOWN_ACTION,
     129                 :                "Unknown permission!");
     130                 : 
     131               0 :   return mPromptResult == nsIPermissionManager::ALLOW_ACTION;
     132                 : }
     133                 : 
     134                 : void
     135               0 : CheckQuotaHelper::Cancel()
     136                 : {
     137               0 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
     138               0 :   mMutex.AssertCurrentThreadOwns();
     139                 : 
     140               0 :   if (mWaiting && !mHasPrompted) {
     141               0 :     MutexAutoUnlock unlock(mMutex);
     142                 : 
     143                 :     // First close any prompts that are open for this window.
     144               0 :     nsCOMPtr<nsIObserverService> obs = GetObserverService();
     145               0 :     NS_WARN_IF_FALSE(obs, "Failed to get observer service!");
     146               0 :     if (obs && NS_FAILED(obs->NotifyObservers(static_cast<nsIRunnable*>(this),
     147                 :                                               TOPIC_QUOTA_CANCEL, nsnull))) {
     148               0 :       NS_WARNING("Failed to notify observers!");
     149                 :     }
     150                 : 
     151                 :     // If that didn't trigger an Observe callback (maybe the window had already
     152                 :     // died?) then go ahead and do it manually.
     153               0 :     if (!mHasPrompted) {
     154               0 :       nsAutoString response;
     155               0 :       response.AppendInt(nsIPermissionManager::UNKNOWN_ACTION);
     156                 : 
     157               0 :       if (NS_SUCCEEDED(Observe(nsnull, TOPIC_QUOTA_RESPONSE, response.get()))) {
     158               0 :         NS_ASSERTION(mHasPrompted, "Should have set this in Observe!");
     159                 :       }
     160                 :       else {
     161               0 :         NS_WARNING("Failed to notify!");
     162                 :       }
     163                 :     }
     164                 :   }
     165               0 : }
     166                 : 
     167               0 : NS_IMPL_THREADSAFE_ISUPPORTS3(CheckQuotaHelper, nsIRunnable,
     168                 :                                                 nsIInterfaceRequestor,
     169                 :                                                 nsIObserver)
     170                 : 
     171                 : NS_IMETHODIMP
     172               0 : CheckQuotaHelper::Run()
     173                 : {
     174               0 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
     175                 : 
     176               0 :   nsresult rv = NS_OK;
     177                 : 
     178               0 :   if (mASCIIOrigin.IsEmpty()) {
     179                 :     rv = IndexedDatabaseManager::GetASCIIOriginFromWindow(mWindow,
     180               0 :                                                           mASCIIOrigin);
     181                 :   }
     182                 : 
     183               0 :   if (NS_SUCCEEDED(rv)) {
     184               0 :     if (!mHasPrompted) {
     185               0 :       mPromptResult = GetQuotaPermissions(mASCIIOrigin, mWindow);
     186                 :     }
     187                 : 
     188               0 :     if (mHasPrompted) {
     189                 :       // Add permissions to the database, but only if we are in the parent
     190                 :       // process (if we are in the child process, we have already
     191                 :       // set the permission when the prompt was shown in the parent, as
     192                 :       // we cannot set the permission from the child).
     193               0 :       if (mPromptResult != nsIPermissionManager::UNKNOWN_ACTION &&
     194               0 :           XRE_GetProcessType() == GeckoProcessType_Default) {
     195               0 :         nsCOMPtr<nsIURI> uri;
     196               0 :         rv = NS_NewURI(getter_AddRefs(uri), mASCIIOrigin);
     197               0 :         NS_ENSURE_SUCCESS(rv, rv);
     198                 :     
     199                 :         nsCOMPtr<nsIPermissionManager> permissionManager =
     200               0 :           do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
     201               0 :         NS_ENSURE_STATE(permissionManager);
     202                 :     
     203               0 :         rv = permissionManager->Add(uri, PERMISSION_INDEXEDDB_UNLIMITED,
     204                 :                                     mPromptResult,
     205               0 :                                     nsIPermissionManager::EXPIRE_NEVER, 0);
     206               0 :         NS_ENSURE_SUCCESS(rv, rv);
     207                 :       }
     208                 :     }
     209               0 :     else if (mPromptResult == nsIPermissionManager::UNKNOWN_ACTION) {
     210               0 :       PRUint32 quota = IndexedDatabaseManager::GetIndexedDBQuotaMB();
     211                 : 
     212               0 :       nsString quotaString;
     213               0 :       quotaString.AppendInt(quota);
     214                 : 
     215               0 :       nsCOMPtr<nsIObserverService> obs = GetObserverService();
     216               0 :       NS_ENSURE_STATE(obs);
     217                 : 
     218                 :       // We have to watch to make sure that the window doesn't go away without
     219                 :       // responding to us. Otherwise our database threads will hang.
     220               0 :       rv = obs->AddObserver(this, DOM_WINDOW_DESTROYED_TOPIC, false);
     221               0 :       NS_ENSURE_SUCCESS(rv, rv);
     222                 : 
     223               0 :       rv = obs->NotifyObservers(static_cast<nsIRunnable*>(this),
     224               0 :                                 TOPIC_QUOTA_PROMPT, quotaString.get());
     225               0 :       NS_ENSURE_SUCCESS(rv, rv);
     226                 : 
     227               0 :       return NS_OK;
     228                 :     }
     229                 :   }
     230                 : 
     231               0 :   MutexAutoLock lock(mMutex);
     232                 : 
     233               0 :   NS_ASSERTION(mWaiting, "Huh?!");
     234                 : 
     235                 :     // This should never be used again.
     236               0 :   mWindow = nsnull;
     237                 : 
     238               0 :   mWaiting = false;
     239               0 :   mCondVar.NotifyAll();
     240                 : 
     241               0 :   return NS_OK;
     242                 : }
     243                 : 
     244                 : NS_IMETHODIMP
     245               0 : CheckQuotaHelper::GetInterface(const nsIID& aIID,
     246                 :                                void** aResult)
     247                 : {
     248               0 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
     249                 : 
     250               0 :   if (aIID.Equals(NS_GET_IID(nsIObserver))) {
     251               0 :     return QueryInterface(aIID, aResult);
     252                 :   }
     253                 : 
     254               0 :   if (aIID.Equals(NS_GET_IID(nsIDOMWindow))) {
     255               0 :     return mWindow->QueryInterface(aIID, aResult);
     256                 :   }
     257                 : 
     258               0 :   *aResult = nsnull;
     259               0 :   return NS_ERROR_NOT_AVAILABLE;
     260                 : }
     261                 : 
     262                 : NS_IMETHODIMP
     263               0 : CheckQuotaHelper::Observe(nsISupports* aSubject,
     264                 :                           const char* aTopic,
     265                 :                           const PRUnichar* aData)
     266                 : {
     267               0 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
     268                 : 
     269                 :   nsresult rv;
     270                 : 
     271               0 :   if (!strcmp(aTopic, TOPIC_QUOTA_RESPONSE)) {
     272               0 :     if (!mHasPrompted) {
     273               0 :       mHasPrompted = true;
     274                 : 
     275               0 :       mPromptResult = nsDependentString(aData).ToInteger(&rv);
     276               0 :       NS_ENSURE_SUCCESS(rv, rv);
     277                 : 
     278               0 :       rv = NS_DispatchToCurrentThread(this);
     279               0 :       NS_ENSURE_SUCCESS(rv, rv);
     280                 : 
     281                 :       // We no longer care about the window here.
     282               0 :       nsCOMPtr<nsIObserverService> obs = GetObserverService();
     283               0 :       NS_ENSURE_STATE(obs);
     284                 : 
     285               0 :       rv = obs->RemoveObserver(this, DOM_WINDOW_DESTROYED_TOPIC);
     286               0 :       NS_ENSURE_SUCCESS(rv, rv);
     287                 :     }
     288               0 :     return NS_OK;
     289                 :   }
     290                 : 
     291               0 :   if (!strcmp(aTopic, DOM_WINDOW_DESTROYED_TOPIC)) {
     292               0 :     NS_ASSERTION(!mHasPrompted, "Should have removed observer before now!");
     293               0 :     NS_ASSERTION(mWindow, "This should never be null!");
     294                 : 
     295               0 :     nsCOMPtr<nsPIDOMWindow> window(do_QueryInterface(aSubject));
     296               0 :     NS_ENSURE_STATE(window);
     297                 : 
     298               0 :     if (mWindow->GetSerial() == window->GetSerial()) {
     299                 :       // This is our window, dying, without responding to our prompt! Fake one.
     300               0 :       mHasPrompted = true;
     301               0 :       mPromptResult = nsIPermissionManager::UNKNOWN_ACTION;
     302                 : 
     303               0 :       rv = NS_DispatchToCurrentThread(this);
     304               0 :       NS_ENSURE_SUCCESS(rv, rv);
     305                 : 
     306                 :       // We no longer care about the window here.
     307               0 :       nsCOMPtr<nsIObserverService> obs = GetObserverService();
     308               0 :       NS_ENSURE_STATE(obs);
     309                 : 
     310               0 :       rv = obs->RemoveObserver(this, DOM_WINDOW_DESTROYED_TOPIC);
     311               0 :       NS_ENSURE_SUCCESS(rv, rv);
     312                 :     }
     313               0 :     return NS_OK;
     314                 :   }
     315                 : 
     316               0 :   NS_NOTREACHED("Unexpected topic!");
     317               0 :   return NS_ERROR_UNEXPECTED;
     318                 : }

Generated by: LCOV version 1.7