mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-02 10:00:54 +00:00
Bug 591516 - 'IndexedDB: Add some UI to prompt for IndexedDB permissions'. r=sicking+gavin.
This commit is contained in:
parent
5158899107
commit
b88dc31fa2
@ -366,6 +366,7 @@ window[chromehidden~="toolbar"] toolbar:not(.toolbar-primary):not(.chromeclass-m
|
||||
}
|
||||
|
||||
#notification-popup-box[anchorid="geo-notification-icon"] > #geo-notification-icon,
|
||||
#notification-popup-box[anchorid="indexedDB-notification-icon"] > #indexedDB-notification-icon,
|
||||
#notification-popup-box[anchorid="addons-notification-icon"] > #addons-notification-icon {
|
||||
display: -moz-box;
|
||||
}
|
||||
|
@ -1321,6 +1321,7 @@ function delayedStartup(isLoadingBlank, mustLoadSidebar) {
|
||||
|
||||
BrowserOffline.init();
|
||||
OfflineApps.init();
|
||||
IndexedDBPromptHelper.init();
|
||||
|
||||
gBrowser.addEventListener("pageshow", function(evt) { setTimeout(pageShowEventHandlers, 0, evt); }, true);
|
||||
|
||||
@ -1580,6 +1581,7 @@ function BrowserShutdown()
|
||||
OfflineApps.uninit();
|
||||
DownloadMonitorPanel.uninit();
|
||||
gPrivateBrowsingUI.uninit();
|
||||
IndexedDBPromptHelper.uninit();
|
||||
|
||||
var enumerator = Services.wm.getEnumerator(null);
|
||||
enumerator.getNext();
|
||||
@ -5852,6 +5854,92 @@ var OfflineApps = {
|
||||
}
|
||||
};
|
||||
|
||||
var IndexedDBPromptHelper = {
|
||||
_permissionsPrompt: "indexedDB-permissions-prompt",
|
||||
_permissionsResponse: "indexedDB-permissions-response",
|
||||
|
||||
_quotaPrompt: "indexedDB-quota-prompt",
|
||||
_quotaResponse: "indexedDB-quota-response",
|
||||
|
||||
_notificationIcon: "indexedDB-notification-icon",
|
||||
|
||||
init:
|
||||
function IndexedDBPromptHelper_init() {
|
||||
Services.obs.addObserver(this, this._permissionsPrompt, false);
|
||||
Services.obs.addObserver(this, this._quotaPrompt, false);
|
||||
},
|
||||
|
||||
uninit:
|
||||
function IndexedDBPromptHelper_uninit() {
|
||||
Services.obs.removeObserver(this, this._permissionsPrompt, false);
|
||||
Services.obs.removeObserver(this, this._quotaPrompt, false);
|
||||
},
|
||||
|
||||
observe:
|
||||
function IndexedDBPromptHelper_observe(subject, topic, data) {
|
||||
if (topic != this._permissionsPrompt &&
|
||||
topic != this._quotaPrompt) {
|
||||
throw new Error("Unexpected topic!");
|
||||
}
|
||||
|
||||
var requestor = subject.QueryInterface(Ci.nsIInterfaceRequestor);
|
||||
|
||||
var contentWindow = requestor.getInterface(Ci.nsIDOMWindow);
|
||||
var contentDocument = contentWindow.document;
|
||||
var browserWindow =
|
||||
OfflineApps._getBrowserWindowForContentWindow(contentWindow);
|
||||
var browser =
|
||||
OfflineApps._getBrowserForContentWindow(browserWindow, contentWindow);
|
||||
|
||||
if (!browser) {
|
||||
// Must belong to some other window.
|
||||
return;
|
||||
}
|
||||
|
||||
var host = contentDocument.documentURIObject.asciiHost;
|
||||
|
||||
var message;
|
||||
var responseTopic;
|
||||
if (topic == this._permissionsPrompt) {
|
||||
message = gNavigatorBundle.getFormattedString("offlineApps.available",
|
||||
[ host ]);
|
||||
responseTopic = this._permissionsResponse;
|
||||
}
|
||||
else if (topic == this._quotaPrompt) {
|
||||
message = gNavigatorBundle.getFormattedString("indexedDB.usage",
|
||||
[ host, data ]);
|
||||
responseTopic = this._quotaResponse;
|
||||
}
|
||||
|
||||
var self = this;
|
||||
var observer = requestor.getInterface(Ci.nsIObserver);
|
||||
|
||||
var mainAction = {
|
||||
label: gNavigatorBundle.getString("offlineApps.allow"),
|
||||
accessKey: gNavigatorBundle.getString("offlineApps.allowAccessKey"),
|
||||
callback: function() {
|
||||
observer.observe(null, responseTopic,
|
||||
Ci.nsIPermissionManager.ALLOW_ACTION);
|
||||
}
|
||||
};
|
||||
|
||||
var secondaryActions = [
|
||||
{
|
||||
label: gNavigatorBundle.getString("offlineApps.never"),
|
||||
accessKey: gNavigatorBundle.getString("offlineApps.neverAccessKey"),
|
||||
callback: function() {
|
||||
observer.observe(null, responseTopic,
|
||||
Ci.nsIPermissionManager.DENY_ACTION);
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
PopupNotifications.show(browser, topic, message, this._notificationIcon,
|
||||
mainAction, secondaryActions);
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
function WindowIsClosing()
|
||||
{
|
||||
var reallyClose = closeWindow(false, warnAboutClosingWindow);
|
||||
|
@ -875,6 +875,7 @@
|
||||
<box id="notification-popup-box" hidden="true" align="center">
|
||||
<image id="geo-notification-icon" class="notification-anchor-icon" role="button"/>
|
||||
<image id="addons-notification-icon" class="notification-anchor-icon" role="button"/>
|
||||
<image id="indexedDB-notification-icon" class="notification-anchor-icon" role="button"/>
|
||||
</box>
|
||||
<!-- Use onclick instead of normal popup= syntax since the popup
|
||||
code fires onmousedown, and hence eats our favicon drag events.
|
||||
|
@ -185,6 +185,10 @@ offlineApps.usage=This website (%S) is now storing more than %SMB of data on you
|
||||
offlineApps.manageUsage=Show settings
|
||||
offlineApps.manageUsageAccessKey=S
|
||||
|
||||
# LOCALIZATION NOTE (indexedDB.usage): %1$S is the website host name
|
||||
# %2$S a number of megabytes.
|
||||
indexedDB.usage=This website (%1$S) is attempting to store more than %2$S MB of data on your computer for offline use.
|
||||
|
||||
identity.identified.verifier=Verified by: %S
|
||||
identity.identified.verified_by_you=You have added a security exception for this site.
|
||||
identity.identified.state_and_country=%S, %S
|
||||
|
@ -1034,6 +1034,11 @@ toolbar[iconsize="small"] #fullscreen-button {
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="indexedDB-permissions-prompt"],
|
||||
.popup-notification-icon[popupid="indexedDB-quota-prompt"] {
|
||||
list-style-image: url(chrome://global/skin/icons/question-64.png);
|
||||
}
|
||||
|
||||
/* Notification icon box */
|
||||
#notification-popup-box {
|
||||
margin: 0 3px;
|
||||
@ -1061,6 +1066,10 @@ toolbar[iconsize="small"] #fullscreen-button {
|
||||
list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric-16.png);
|
||||
}
|
||||
|
||||
#indexedDB-notification-icon {
|
||||
list-style-image: url(chrome://global/skin/icons/question-16.png);
|
||||
}
|
||||
|
||||
/* Feed icon */
|
||||
#feed-button,
|
||||
#feed-button > .button-box,
|
||||
|
@ -1962,6 +1962,15 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
#indexedDB-notification-icon {
|
||||
list-style-image: url(chrome://global/skin/icons/question-16.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="indexedDB-permissions-prompt"],
|
||||
.popup-notification-icon[popupid="indexedDB-quota-prompt"] {
|
||||
list-style-image: url(chrome://global/skin/icons/question-64.png);
|
||||
}
|
||||
|
||||
#identity-popup-container,
|
||||
#identity-popup-notification-container {
|
||||
margin: 4px 3px 2px -30px;
|
||||
|
@ -1885,6 +1885,11 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] {
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="indexedDB-permissions-prompt"],
|
||||
.popup-notification-icon[popupid="indexedDB-quota-prompt"] {
|
||||
list-style-image: url(chrome://global/skin/icons/question-64.png);
|
||||
}
|
||||
|
||||
/* Notification icon box */
|
||||
#notification-popup-box {
|
||||
margin: 0 3px;
|
||||
@ -1908,6 +1913,10 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] {
|
||||
list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric-16.png);
|
||||
}
|
||||
|
||||
#indexedDB-notification-icon {
|
||||
list-style-image: url(chrome://global/skin/icons/question-16.png);
|
||||
}
|
||||
|
||||
#identity-popup-container {
|
||||
min-width: 280px;
|
||||
padding: 9px;
|
||||
|
@ -243,10 +243,7 @@ static PRPackedBool gMouseDown = PR_FALSE;
|
||||
static PRPackedBool gDragServiceDisabled = PR_FALSE;
|
||||
static FILE *gDumpFile = nsnull;
|
||||
static PRUint64 gNextWindowID = 0;
|
||||
|
||||
#ifdef DEBUG
|
||||
static PRUint32 gSerialCounter = 0;
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_jst
|
||||
PRInt32 gTimeoutCnt = 0;
|
||||
@ -688,7 +685,8 @@ nsGlobalWindow::nsGlobalWindow(nsGlobalWindow *aOuterWindow)
|
||||
mJSObject(nsnull),
|
||||
mPendingStorageEventsObsolete(nsnull),
|
||||
mTimeoutsSuspendDepth(0),
|
||||
mFocusMethod(0)
|
||||
mFocusMethod(0),
|
||||
mSerial(0)
|
||||
#ifdef DEBUG
|
||||
, mSetOpenerWindowCalled(PR_FALSE)
|
||||
#endif
|
||||
@ -764,11 +762,12 @@ nsGlobalWindow::nsGlobalWindow(nsGlobalWindow *aOuterWindow)
|
||||
CallGetService(NS_ENTROPYCOLLECTOR_CONTRACTID, &gEntropyCollector);
|
||||
}
|
||||
|
||||
mSerial = ++gSerialCounter;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("++DOMWINDOW == %d (%p) [serial = %d] [outer = %p]\n", gRefCnt,
|
||||
static_cast<void*>(static_cast<nsIScriptGlobalObject*>(this)),
|
||||
++gSerialCounter, static_cast<void*>(aOuterWindow));
|
||||
mSerial = gSerialCounter;
|
||||
gSerialCounter, static_cast<void*>(aOuterWindow));
|
||||
#endif
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
|
@ -486,6 +486,10 @@ public:
|
||||
const nsAString &aPopupWindowName,
|
||||
const nsAString &aPopupWindowFeatures);
|
||||
|
||||
virtual PRUint32 GetSerial() {
|
||||
return mSerial;
|
||||
}
|
||||
|
||||
protected:
|
||||
// Object Management
|
||||
virtual ~nsGlobalWindow();
|
||||
@ -837,9 +841,10 @@ protected:
|
||||
// the method that was used to focus mFocusedNode
|
||||
PRUint32 mFocusMethod;
|
||||
|
||||
PRUint32 mSerial;
|
||||
|
||||
#ifdef DEBUG
|
||||
PRBool mSetOpenerWindowCalled;
|
||||
PRUint32 mSerial;
|
||||
nsCOMPtr<nsIURI> mLastOpenedURI;
|
||||
#endif
|
||||
|
||||
|
@ -546,6 +546,13 @@ public:
|
||||
*/
|
||||
virtual nsresult SetArguments(nsIArray *aArguments, nsIPrincipal *aOrigin) = 0;
|
||||
|
||||
/**
|
||||
* NOTE! This function *will* be called on multiple threads so the
|
||||
* implementation must not do any AddRef/Release or other actions that will
|
||||
* mutate internal state.
|
||||
*/
|
||||
virtual PRUint32 GetSerial() = 0;
|
||||
|
||||
protected:
|
||||
// The nsPIDOMWindow constructor. The aOuterWindow argument should
|
||||
// be null if and only if the created window itself is an outer
|
||||
|
@ -47,6 +47,7 @@
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
#include "IDBEvents.h"
|
||||
#include "IDBFactory.h"
|
||||
#include "IDBTransaction.h"
|
||||
#include "TransactionThreadPool.h"
|
||||
|
||||
@ -192,7 +193,13 @@ AsyncConnectionHelper::Run()
|
||||
}
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
if (mDatabase) {
|
||||
IDBFactory::SetCurrentDatabase(mDatabase);
|
||||
}
|
||||
mErrorCode = DoDatabaseWork(connection);
|
||||
if (mDatabase) {
|
||||
IDBFactory::SetCurrentDatabase(nsnull);
|
||||
}
|
||||
}
|
||||
else {
|
||||
mErrorCode = nsIIDBDatabaseException::UNKNOWN_ERR;
|
||||
|
@ -96,6 +96,12 @@ public:
|
||||
// Only for transactions!
|
||||
nsresult DispatchToTransactionPool();
|
||||
|
||||
void SetError(PRUint16 aErrorCode)
|
||||
{
|
||||
mError = true;
|
||||
mErrorCode = aErrorCode;
|
||||
}
|
||||
|
||||
protected:
|
||||
AsyncConnectionHelper(IDBDatabase* aDatabase,
|
||||
IDBRequest* aRequest);
|
||||
|
198
dom/indexedDB/CheckPermissionsHelper.cpp
Normal file
198
dom/indexedDB/CheckPermissionsHelper.cpp
Normal file
@ -0,0 +1,198 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Indexed Database.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* The Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Ben Turner <bent.mozilla@gmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "CheckPermissionsHelper.h"
|
||||
|
||||
#include "nsIDOMWindow.h"
|
||||
#include "nsIIDBDatabaseException.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsIPermissionManager.h"
|
||||
#include "nsIPrincipal.h"
|
||||
#include "nsIScriptObjectPrincipal.h"
|
||||
#include "nsIURI.h"
|
||||
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsDOMStorage.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "mozilla/Services.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"
|
||||
|
||||
USING_INDEXEDDB_NAMESPACE
|
||||
using namespace mozilla::services;
|
||||
|
||||
namespace {
|
||||
|
||||
inline
|
||||
PRUint32
|
||||
GetIndexedDBPermissions(const nsACString& aASCIIOrigin,
|
||||
nsIDOMWindow* aWindow)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
if (!nsContentUtils::GetBoolPref(PREF_INDEXEDDB_ENABLED)) {
|
||||
return nsIPermissionManager::DENY_ACTION;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIScriptObjectPrincipal> sop(do_QueryInterface(aWindow));
|
||||
NS_ENSURE_TRUE(sop, nsIPermissionManager::DENY_ACTION);
|
||||
|
||||
if (nsContentUtils::IsSystemPrincipal(sop->GetPrincipal())) {
|
||||
return nsIPermissionManager::ALLOW_ACTION;
|
||||
}
|
||||
|
||||
if (nsDOMStorageManager::gStorageManager->InPrivateBrowsingMode()) {
|
||||
// TODO Support private browsing indexedDB?
|
||||
return nsIPermissionManager::DENY_ACTION;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
nsresult rv = NS_NewURI(getter_AddRefs(uri), aASCIIOrigin);
|
||||
NS_ENSURE_SUCCESS(rv, nsIPermissionManager::DENY_ACTION);
|
||||
|
||||
nsCOMPtr<nsIPermissionManager> permissionManager =
|
||||
do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
|
||||
NS_ENSURE_TRUE(permissionManager, nsIPermissionManager::DENY_ACTION);
|
||||
|
||||
PRUint32 permission;
|
||||
rv = permissionManager->TestPermission(uri, PERMISSION_INDEXEDDB,
|
||||
&permission);
|
||||
NS_ENSURE_SUCCESS(rv, nsIPermissionManager::DENY_ACTION);
|
||||
|
||||
return permission;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS3(CheckPermissionsHelper, nsIRunnable,
|
||||
nsIInterfaceRequestor,
|
||||
nsIObserver)
|
||||
|
||||
NS_IMETHODIMP
|
||||
CheckPermissionsHelper::Run()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
PRUint32 permission = mHasPrompted ?
|
||||
mPromptResult :
|
||||
GetIndexedDBPermissions(mASCIIOrigin, mWindow);
|
||||
|
||||
nsresult rv;
|
||||
if (mHasPrompted) {
|
||||
if (permission != nsIPermissionManager::UNKNOWN_ACTION) {
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
rv = NS_NewURI(getter_AddRefs(uri), mASCIIOrigin);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIPermissionManager> permissionManager =
|
||||
do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
|
||||
NS_ENSURE_STATE(permissionManager);
|
||||
|
||||
rv = permissionManager->Add(uri, PERMISSION_INDEXEDDB, permission,
|
||||
nsIPermissionManager::EXPIRE_NEVER, 0);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
}
|
||||
else if (permission == nsIPermissionManager::UNKNOWN_ACTION) {
|
||||
nsCOMPtr<nsIObserverService> obs = GetObserverService();
|
||||
rv = obs->NotifyObservers(static_cast<nsIRunnable*>(this),
|
||||
TOPIC_PERMISSIONS_PROMPT, nsnull);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsRefPtr<AsyncConnectionHelper> helper;
|
||||
helper.swap(mHelper);
|
||||
|
||||
nsCOMPtr<nsIThread> thread;
|
||||
thread.swap(mThread);
|
||||
|
||||
nsCOMPtr<nsIDOMWindow> window;
|
||||
window.swap(mWindow);
|
||||
|
||||
if (permission == nsIPermissionManager::ALLOW_ACTION) {
|
||||
return helper->Dispatch(thread);
|
||||
}
|
||||
|
||||
NS_ASSERTION(permission == nsIPermissionManager::UNKNOWN_ACTION ||
|
||||
permission == nsIPermissionManager::DENY_ACTION,
|
||||
"Unknown permission!");
|
||||
|
||||
helper->SetError(nsIIDBDatabaseException::NOT_ALLOWED_ERR);
|
||||
return helper->Run();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
CheckPermissionsHelper::GetInterface(const nsIID& aIID,
|
||||
void** aResult)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
if (aIID.Equals(NS_GET_IID(nsIObserver))) {
|
||||
return QueryInterface(aIID, aResult);
|
||||
}
|
||||
|
||||
if (aIID.Equals(NS_GET_IID(nsIDOMWindow))) {
|
||||
return mWindow->QueryInterface(aIID, aResult);
|
||||
}
|
||||
|
||||
*aResult = nsnull;
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
CheckPermissionsHelper::Observe(nsISupports* aSubject,
|
||||
const char* aTopic,
|
||||
const PRUnichar* aData)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
NS_ASSERTION(!strcmp(aTopic, TOPIC_PERMISSIONS_RESPONSE), "Bad topic!");
|
||||
|
||||
mHasPrompted = PR_TRUE;
|
||||
|
||||
nsresult rv;
|
||||
mPromptResult = nsDependentString(aData).ToInteger(&rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_DispatchToCurrentThread(this);
|
||||
}
|
93
dom/indexedDB/CheckPermissionsHelper.h
Normal file
93
dom/indexedDB/CheckPermissionsHelper.h
Normal file
@ -0,0 +1,93 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Indexed Database.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* The Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Ben Turner <bent.mozilla@gmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef mozilla_dom_indexeddb_checkpermissionshelper_h__
|
||||
#define mozilla_dom_indexeddb_checkpermissionshelper_h__
|
||||
|
||||
// Only meant to be included in IndexedDB source files, not exported.
|
||||
#include "AsyncConnectionHelper.h"
|
||||
|
||||
#include "nsIInterfaceRequestor.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsIRunnable.h"
|
||||
|
||||
class nsIDOMWindow;
|
||||
class nsIThread;
|
||||
|
||||
BEGIN_INDEXEDDB_NAMESPACE
|
||||
|
||||
class CheckPermissionsHelper : public nsIRunnable,
|
||||
public nsIInterfaceRequestor,
|
||||
public nsIObserver
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIRUNNABLE
|
||||
NS_DECL_NSIINTERFACEREQUESTOR
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
CheckPermissionsHelper(AsyncConnectionHelper* aHelper,
|
||||
nsIThread* aThread,
|
||||
nsIDOMWindow* aWindow,
|
||||
const nsACString& aASCIIOrigin)
|
||||
: mHelper(aHelper),
|
||||
mThread(aThread),
|
||||
mWindow(aWindow),
|
||||
mASCIIOrigin(aASCIIOrigin),
|
||||
mHasPrompted(PR_FALSE),
|
||||
mPromptResult(0)
|
||||
{
|
||||
NS_ASSERTION(aHelper, "Null pointer!");
|
||||
NS_ASSERTION(aThread, "Null pointer!");
|
||||
NS_ASSERTION(aWindow, "Null pointer!");
|
||||
NS_ASSERTION(!aASCIIOrigin.IsEmpty(), "Empty host!");
|
||||
}
|
||||
|
||||
private:
|
||||
nsRefPtr<AsyncConnectionHelper> mHelper;
|
||||
nsCOMPtr<nsIThread> mThread;
|
||||
nsCOMPtr<nsIDOMWindow> mWindow;
|
||||
nsCString mASCIIOrigin;
|
||||
PRBool mHasPrompted;
|
||||
PRUint32 mPromptResult;
|
||||
};
|
||||
|
||||
END_INDEXEDDB_NAMESPACE
|
||||
|
||||
#endif // mozilla_dom_indexeddb_checkpermissionshelper_h__
|
226
dom/indexedDB/CheckQuotaHelper.cpp
Normal file
226
dom/indexedDB/CheckQuotaHelper.cpp
Normal file
@ -0,0 +1,226 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Indexed Database.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* The Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Ben Turner <bent.mozilla@gmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "CheckQuotaHelper.h"
|
||||
|
||||
#include "nsIDOMWindow.h"
|
||||
#include "nsIIDBDatabaseException.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsIPermissionManager.h"
|
||||
#include "nsIPrincipal.h"
|
||||
#include "nsIScriptObjectPrincipal.h"
|
||||
#include "nsIURI.h"
|
||||
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "mozilla/Services.h"
|
||||
|
||||
#include "IDBFactory.h"
|
||||
|
||||
#define PERMISSION_INDEXEDDB_UNLIMITED "indexedDB-unlimited"
|
||||
|
||||
#define TOPIC_QUOTA_PROMPT "indexedDB-quota-prompt"
|
||||
#define TOPIC_QUOTA_RESPONSE "indexedDB-quota-response"
|
||||
|
||||
USING_INDEXEDDB_NAMESPACE
|
||||
using namespace mozilla::services;
|
||||
using mozilla::MutexAutoLock;
|
||||
|
||||
namespace {
|
||||
|
||||
inline
|
||||
PRUint32
|
||||
GetQuotaPermissions(const nsACString& aASCIIOrigin,
|
||||
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<nsIURI> uri;
|
||||
nsresult rv = NS_NewURI(getter_AddRefs(uri), aASCIIOrigin);
|
||||
NS_ENSURE_SUCCESS(rv, nsIPermissionManager::DENY_ACTION);
|
||||
|
||||
nsCOMPtr<nsIPermissionManager> permissionManager =
|
||||
do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
|
||||
NS_ENSURE_TRUE(permissionManager, nsIPermissionManager::DENY_ACTION);
|
||||
|
||||
PRUint32 permission;
|
||||
rv = permissionManager->TestPermission(uri, PERMISSION_INDEXEDDB_UNLIMITED,
|
||||
&permission);
|
||||
NS_ENSURE_SUCCESS(rv, nsIPermissionManager::DENY_ACTION);
|
||||
|
||||
return permission;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
CheckQuotaHelper::CheckQuotaHelper(IDBDatabase* aDatabase,
|
||||
mozilla::Mutex& aMutex)
|
||||
: mWindow(aDatabase->Owner()),
|
||||
mWindowSerial(mWindow->GetSerial()),
|
||||
mOrigin(aDatabase->Origin()),
|
||||
mMutex(aMutex),
|
||||
mCondVar(mMutex, "CheckQuotaHelper::mCondVar"),
|
||||
mPromptResult(0),
|
||||
mWaiting(true),
|
||||
mHasPrompted(false)
|
||||
{
|
||||
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
|
||||
mMutex.AssertCurrentThreadOwns();
|
||||
}
|
||||
|
||||
bool
|
||||
CheckQuotaHelper::PromptAndReturnQuotaIsDisabled()
|
||||
{
|
||||
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
|
||||
mMutex.AssertCurrentThreadOwns();
|
||||
|
||||
while (mWaiting) {
|
||||
mCondVar.Wait();
|
||||
}
|
||||
|
||||
NS_ASSERTION(!mWindow, "This should always be null here!");
|
||||
|
||||
NS_ASSERTION(mPromptResult == nsIPermissionManager::ALLOW_ACTION ||
|
||||
mPromptResult == nsIPermissionManager::DENY_ACTION ||
|
||||
mPromptResult == nsIPermissionManager::UNKNOWN_ACTION,
|
||||
"Unknown permission!");
|
||||
|
||||
return mPromptResult == nsIPermissionManager::ALLOW_ACTION;
|
||||
}
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS3(CheckQuotaHelper, nsIRunnable,
|
||||
nsIInterfaceRequestor,
|
||||
nsIObserver)
|
||||
|
||||
NS_IMETHODIMP
|
||||
CheckQuotaHelper::Run()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
if (!mHasPrompted) {
|
||||
mPromptResult = GetQuotaPermissions(mOrigin, mWindow);
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
if (mHasPrompted) {
|
||||
if (mPromptResult != nsIPermissionManager::UNKNOWN_ACTION) {
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
rv = NS_NewURI(getter_AddRefs(uri), mOrigin);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIPermissionManager> permissionManager =
|
||||
do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
|
||||
NS_ENSURE_STATE(permissionManager);
|
||||
|
||||
rv = permissionManager->Add(uri, PERMISSION_INDEXEDDB_UNLIMITED,
|
||||
mPromptResult,
|
||||
nsIPermissionManager::EXPIRE_NEVER, 0);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
}
|
||||
else if (mPromptResult == nsIPermissionManager::UNKNOWN_ACTION) {
|
||||
PRUint32 quota = IDBFactory::GetIndexedDBQuota();
|
||||
NS_ASSERTION(quota, "Shouldn't get here if quota is disabled!");
|
||||
|
||||
nsString quotaString;
|
||||
quotaString.AppendInt(quota);
|
||||
|
||||
nsCOMPtr<nsIObserverService> obs = GetObserverService();
|
||||
rv = obs->NotifyObservers(static_cast<nsIRunnable*>(this),
|
||||
TOPIC_QUOTA_PROMPT, quotaString.get());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
MutexAutoLock lock(mMutex);
|
||||
|
||||
NS_ASSERTION(mWaiting, "Huh?!");
|
||||
|
||||
// This should never be used again.
|
||||
mWindow = nsnull;
|
||||
|
||||
mWaiting = false;
|
||||
mCondVar.NotifyAll();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
CheckQuotaHelper::GetInterface(const nsIID& aIID,
|
||||
void** aResult)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
if (aIID.Equals(NS_GET_IID(nsIObserver))) {
|
||||
return QueryInterface(aIID, aResult);
|
||||
}
|
||||
|
||||
if (aIID.Equals(NS_GET_IID(nsIDOMWindow))) {
|
||||
return mWindow->QueryInterface(aIID, aResult);
|
||||
}
|
||||
|
||||
*aResult = nsnull;
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
CheckQuotaHelper::Observe(nsISupports* aSubject,
|
||||
const char* aTopic,
|
||||
const PRUnichar* aData)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
NS_ASSERTION(!strcmp(aTopic, TOPIC_QUOTA_RESPONSE), "Bad topic!");
|
||||
|
||||
mHasPrompted = true;
|
||||
|
||||
nsresult rv;
|
||||
mPromptResult = nsDependentString(aData).ToInteger(&rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_DispatchToCurrentThread(this);
|
||||
}
|
92
dom/indexedDB/CheckQuotaHelper.h
Normal file
92
dom/indexedDB/CheckQuotaHelper.h
Normal file
@ -0,0 +1,92 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Indexed Database.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* The Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Ben Turner <bent.mozilla@gmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef mozilla_dom_indexeddb_checkquotahelper_h__
|
||||
#define mozilla_dom_indexeddb_checkquotahelper_h__
|
||||
|
||||
// Only meant to be included in IndexedDB source files, not exported.
|
||||
#include "IndexedDatabase.h"
|
||||
#include "IDBDatabase.h"
|
||||
|
||||
#include "nsIInterfaceRequestor.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsIRunnable.h"
|
||||
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "mozilla/CondVar.h"
|
||||
|
||||
class nsPIDOMWindow;
|
||||
|
||||
BEGIN_INDEXEDDB_NAMESPACE
|
||||
|
||||
class CheckQuotaHelper : public nsIRunnable,
|
||||
public nsIInterfaceRequestor,
|
||||
public nsIObserver
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIRUNNABLE
|
||||
NS_DECL_NSIINTERFACEREQUESTOR
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
CheckQuotaHelper(IDBDatabase* aDatabase,
|
||||
mozilla::Mutex& aMutex);
|
||||
|
||||
bool PromptAndReturnQuotaIsDisabled();
|
||||
|
||||
PRUint32 WindowSerial()
|
||||
{
|
||||
return mWindowSerial;
|
||||
}
|
||||
|
||||
private:
|
||||
nsPIDOMWindow* mWindow;
|
||||
PRUint32 mWindowSerial;
|
||||
nsCString mOrigin;
|
||||
|
||||
mozilla::Mutex& mMutex;
|
||||
mozilla::CondVar mCondVar;
|
||||
PRUint32 mPromptResult;
|
||||
bool mWaiting;
|
||||
bool mHasPrompted;
|
||||
};
|
||||
|
||||
END_INDEXEDDB_NAMESPACE
|
||||
|
||||
#endif // mozilla_dom_indexeddb_checkquotahelper_h__
|
@ -41,12 +41,14 @@
|
||||
|
||||
#include "nsIIDBDatabaseException.h"
|
||||
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "mozilla/storage.h"
|
||||
#include "nsDOMClassInfo.h"
|
||||
#include "nsProxyRelease.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
#include "AsyncConnectionHelper.h"
|
||||
#include "CheckQuotaHelper.h"
|
||||
#include "DatabaseInfo.h"
|
||||
#include "IDBEvents.h"
|
||||
#include "IDBObjectStore.h"
|
||||
@ -60,6 +62,12 @@ namespace {
|
||||
|
||||
const PRUint32 kDefaultDatabaseTimeoutSeconds = 30;
|
||||
|
||||
PRUint32 gDatabaseInstanceCount = 0;
|
||||
mozilla::Mutex* gPromptHelpersMutex = nsnull;
|
||||
|
||||
// Protected by gPromptHelpersMutex.
|
||||
nsTArray<nsRefPtr<CheckQuotaHelper> >* gPromptHelpers = nsnull;
|
||||
|
||||
class SetVersionHelper : public AsyncConnectionHelper
|
||||
{
|
||||
public:
|
||||
@ -246,7 +254,10 @@ IDBDatabase::Create(nsIScriptContext* aScriptContext,
|
||||
IDBDatabase::IDBDatabase()
|
||||
: mDatabaseId(0)
|
||||
{
|
||||
|
||||
if (!gDatabaseInstanceCount++) {
|
||||
NS_ASSERTION(!gPromptHelpersMutex, "Should be null!");
|
||||
gPromptHelpersMutex = new mozilla::Mutex("IDBDatabase gPromptHelpersMutex");
|
||||
}
|
||||
}
|
||||
|
||||
IDBDatabase::~IDBDatabase()
|
||||
@ -272,6 +283,16 @@ IDBDatabase::~IDBDatabase()
|
||||
if (mListenerManager) {
|
||||
mListenerManager->Disconnect();
|
||||
}
|
||||
|
||||
if (!--gDatabaseInstanceCount) {
|
||||
NS_ASSERTION(gPromptHelpersMutex, "Should not be null!");
|
||||
|
||||
delete gPromptHelpers;
|
||||
gPromptHelpers = nsnull;
|
||||
|
||||
delete gPromptHelpersMutex;
|
||||
gPromptHelpersMutex = nsnull;
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
@ -304,6 +325,50 @@ IDBDatabase::CloseConnection()
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
IDBDatabase::IsQuotaDisabled()
|
||||
{
|
||||
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
|
||||
NS_ASSERTION(gPromptHelpersMutex, "This should never be null!");
|
||||
|
||||
MutexAutoLock lock(*gPromptHelpersMutex);
|
||||
|
||||
if (!gPromptHelpers) {
|
||||
gPromptHelpers = new nsAutoTArray<nsRefPtr<CheckQuotaHelper>, 10>();
|
||||
}
|
||||
|
||||
CheckQuotaHelper* foundHelper = nsnull;
|
||||
|
||||
PRUint32 count = gPromptHelpers->Length();
|
||||
for (PRUint32 index = 0; index < count; index++) {
|
||||
nsRefPtr<CheckQuotaHelper>& helper = gPromptHelpers->ElementAt(index);
|
||||
if (helper->WindowSerial() == Owner()->GetSerial()) {
|
||||
foundHelper = helper;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundHelper) {
|
||||
nsRefPtr<CheckQuotaHelper>* newHelper = gPromptHelpers->AppendElement();
|
||||
if (!newHelper) {
|
||||
NS_WARNING("Out of memory!");
|
||||
return false;
|
||||
}
|
||||
*newHelper = new CheckQuotaHelper(this, *gPromptHelpersMutex);
|
||||
foundHelper = *newHelper;
|
||||
|
||||
{
|
||||
// Unlock before calling out to XPCOM.
|
||||
MutexAutoUnlock unlock(*gPromptHelpersMutex);
|
||||
|
||||
nsresult rv = NS_DispatchToMainThread(foundHelper, NS_DISPATCH_NORMAL);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
}
|
||||
}
|
||||
|
||||
return foundHelper->PromptAndReturnQuotaIsDisabled();
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(IDBDatabase)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(IDBDatabase,
|
||||
|
@ -111,6 +111,14 @@ public:
|
||||
return mOwner;
|
||||
}
|
||||
|
||||
bool
|
||||
IsQuotaDisabled();
|
||||
|
||||
nsCString& Origin()
|
||||
{
|
||||
return mASCIIOrigin;
|
||||
}
|
||||
|
||||
private:
|
||||
IDBDatabase();
|
||||
~IDBDatabase();
|
||||
|
@ -49,6 +49,7 @@
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsDirectoryServiceUtils.h"
|
||||
#include "nsDOMClassInfo.h"
|
||||
#include "nsEscape.h"
|
||||
#include "nsHashKeys.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
@ -56,17 +57,58 @@
|
||||
#include "nsXPCOMCID.h"
|
||||
|
||||
#include "AsyncConnectionHelper.h"
|
||||
#include "CheckPermissionsHelper.h"
|
||||
#include "DatabaseInfo.h"
|
||||
#include "IDBDatabase.h"
|
||||
#include "IDBKeyRange.h"
|
||||
#include "LazyIdleThread.h"
|
||||
|
||||
#define PREF_INDEXEDDB_QUOTA "dom.indexedDB.warningQuota"
|
||||
|
||||
// megabytes
|
||||
#define DEFAULT_QUOTA 50
|
||||
|
||||
#define BAD_TLS_INDEX (PRUintn)-1
|
||||
|
||||
#define DB_SCHEMA_VERSION 3
|
||||
|
||||
USING_INDEXEDDB_NAMESPACE
|
||||
|
||||
namespace {
|
||||
|
||||
PRUintn gCurrentDatabaseIndex = BAD_TLS_INDEX;
|
||||
|
||||
PRUint32 gIndexedDBQuota = DEFAULT_QUOTA;
|
||||
|
||||
class QuotaCallback : public mozIStorageQuotaCallback
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
NS_IMETHOD
|
||||
QuotaExceeded(const nsACString& aFilename,
|
||||
PRInt64 aCurrentSizeLimit,
|
||||
PRInt64 aCurrentTotalSize,
|
||||
nsISupports* aUserData,
|
||||
PRInt64* _retval)
|
||||
{
|
||||
NS_ASSERTION(gCurrentDatabaseIndex != BAD_TLS_INDEX,
|
||||
"This should be impossible!");
|
||||
|
||||
IDBDatabase* database =
|
||||
static_cast<IDBDatabase*>(PR_GetThreadPrivate(gCurrentDatabaseIndex));
|
||||
|
||||
if (database && database->IsQuotaDisabled()) {
|
||||
*_retval = 0;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
};
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS1(QuotaCallback, mozIStorageQuotaCallback)
|
||||
|
||||
const PRUint32 kDefaultThreadTimeoutMS = 30000;
|
||||
|
||||
struct ObjectStoreInfoMap
|
||||
@ -78,6 +120,7 @@ struct ObjectStoreInfoMap
|
||||
ObjectStoreInfo* info;
|
||||
};
|
||||
|
||||
|
||||
class OpenDatabaseHelper : public AsyncConnectionHelper
|
||||
{
|
||||
public:
|
||||
@ -318,51 +361,94 @@ CreateDatabaseConnection(const nsACString& aASCIIOrigin,
|
||||
|
||||
aDatabaseFilePath.Truncate();
|
||||
|
||||
nsCOMPtr<nsIFile> dbFile;
|
||||
nsCOMPtr<nsIFile> dbDirectory;
|
||||
nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
|
||||
getter_AddRefs(dbFile));
|
||||
getter_AddRefs(dbDirectory));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = dbFile->Append(NS_LITERAL_STRING("indexedDB"));
|
||||
rv = dbDirectory->Append(NS_LITERAL_STRING("indexedDB"));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
PRBool exists;
|
||||
rv = dbFile->Exists(&exists);
|
||||
rv = dbDirectory->Exists(&exists);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (exists) {
|
||||
PRBool isDirectory;
|
||||
rv = dbFile->IsDirectory(&isDirectory);
|
||||
rv = dbDirectory->IsDirectory(&isDirectory);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_TRUE(isDirectory, NS_ERROR_UNEXPECTED);
|
||||
}
|
||||
else {
|
||||
rv = dbFile->Create(nsIFile::DIRECTORY_TYPE, 0755);
|
||||
rv = dbDirectory->Create(nsIFile::DIRECTORY_TYPE, 0755);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
NS_ConvertASCIItoUTF16 originSanitized(aASCIIOrigin);
|
||||
originSanitized.ReplaceChar(":/", '+');
|
||||
|
||||
rv = dbDirectory->Append(originSanitized);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = dbDirectory->Exists(&exists);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (exists) {
|
||||
PRBool isDirectory;
|
||||
rv = dbDirectory->IsDirectory(&isDirectory);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_TRUE(isDirectory, NS_ERROR_UNEXPECTED);
|
||||
}
|
||||
else {
|
||||
rv = dbDirectory->Create(nsIFile::DIRECTORY_TYPE, 0755);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> dbFile;
|
||||
rv = dbDirectory->Clone(getter_AddRefs(dbFile));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<mozIStorageServiceQuotaManagement> ss =
|
||||
do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID);
|
||||
NS_ENSURE_TRUE(ss, NS_ERROR_FAILURE);
|
||||
|
||||
rv = dbDirectory->Append(NS_LITERAL_STRING("*"));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCString pattern;
|
||||
rv = dbDirectory->GetNativePath(pattern);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (gIndexedDBQuota) {
|
||||
PRUint64 quota = gIndexedDBQuota * 1024 * 1024;
|
||||
nsRefPtr<QuotaCallback> callback(new QuotaCallback());
|
||||
rv = ss->SetQuotaForFilenamePattern(pattern, quota, callback, nsnull);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
nsAutoString filename;
|
||||
filename.AppendInt(HashString(aASCIIOrigin));
|
||||
|
||||
rv = dbFile->Append(filename);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = dbFile->Exists(&exists);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (exists) {
|
||||
PRBool isDirectory;
|
||||
rv = dbFile->IsDirectory(&isDirectory);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_TRUE(isDirectory, NS_ERROR_UNEXPECTED);
|
||||
}
|
||||
else {
|
||||
rv = dbFile->Create(nsIFile::DIRECTORY_TYPE, 0755);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
filename.Truncate();
|
||||
filename.AppendInt(HashString(aName));
|
||||
|
||||
nsCString escapedName;
|
||||
if (!NS_Escape(NS_ConvertUTF16toUTF8(aName), escapedName, url_XPAlphas)) {
|
||||
NS_WARNING("Can't escape database name!");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
const char* forwardIter = escapedName.BeginReading();
|
||||
const char* backwardIter = escapedName.EndReading() - 1;
|
||||
|
||||
nsCString substring;
|
||||
while (forwardIter <= backwardIter && substring.Length() < 21) {
|
||||
if (substring.Length() % 2) {
|
||||
substring.Append(*backwardIter--);
|
||||
}
|
||||
else {
|
||||
substring.Append(*forwardIter++);
|
||||
}
|
||||
}
|
||||
|
||||
filename.Append(NS_ConvertASCIItoUTF16(substring));
|
||||
filename.AppendLiteral(".sqlite");
|
||||
|
||||
rv = dbFile->Append(filename);
|
||||
@ -371,12 +457,10 @@ CreateDatabaseConnection(const nsACString& aASCIIOrigin,
|
||||
rv = dbFile->Exists(&exists);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<mozIStorageService> ss =
|
||||
do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID);
|
||||
NS_ENSURE_TRUE(ss, NS_ERROR_FAILURE);
|
||||
NS_NAMED_LITERAL_CSTRING(quota, "quota");
|
||||
|
||||
nsCOMPtr<mozIStorageConnection> connection;
|
||||
rv = ss->OpenDatabase(dbFile, getter_AddRefs(connection));
|
||||
rv = ss->OpenDatabaseWithVFS(dbFile, quota, getter_AddRefs(connection));
|
||||
if (rv == NS_ERROR_FILE_CORRUPTED) {
|
||||
// Nuke the database file. The web services can recreate their data.
|
||||
rv = dbFile->Remove(PR_FALSE);
|
||||
@ -384,7 +468,7 @@ CreateDatabaseConnection(const nsACString& aASCIIOrigin,
|
||||
|
||||
exists = PR_FALSE;
|
||||
|
||||
rv = ss->OpenDatabase(dbFile, getter_AddRefs(connection));
|
||||
rv = ss->OpenDatabaseWithVFS(dbFile, quota, getter_AddRefs(connection));
|
||||
}
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
@ -399,7 +483,7 @@ CreateDatabaseConnection(const nsACString& aASCIIOrigin,
|
||||
rv = dbFile->Remove(PR_FALSE);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = ss->OpenDatabase(dbFile, getter_AddRefs(connection));
|
||||
rv = ss->OpenDatabaseWithVFS(dbFile, quota, getter_AddRefs(connection));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
@ -478,12 +562,13 @@ IDBFactory::GetConnection(const nsAString& aDatabaseFilePath)
|
||||
NS_ENSURE_SUCCESS(rv, nsnull);
|
||||
NS_ENSURE_TRUE(exists, nsnull);
|
||||
|
||||
nsCOMPtr<mozIStorageService> ss =
|
||||
nsCOMPtr<mozIStorageServiceQuotaManagement> ss =
|
||||
do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID);
|
||||
NS_ENSURE_TRUE(ss, nsnull);
|
||||
|
||||
nsCOMPtr<mozIStorageConnection> connection;
|
||||
rv = ss->OpenDatabase(dbFile, getter_AddRefs(connection));
|
||||
rv = ss->OpenDatabaseWithVFS(dbFile, NS_LITERAL_CSTRING("quota"),
|
||||
getter_AddRefs(connection));
|
||||
NS_ENSURE_SUCCESS(rv, nsnull);
|
||||
|
||||
#ifdef DEBUG
|
||||
@ -505,6 +590,39 @@ IDBFactory::GetConnection(const nsAString& aDatabaseFilePath)
|
||||
return connection.forget();
|
||||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
IDBFactory::SetCurrentDatabase(IDBDatabase* aDatabase)
|
||||
{
|
||||
NS_ASSERTION(gCurrentDatabaseIndex != BAD_TLS_INDEX,
|
||||
"This should have been set already!");
|
||||
|
||||
#ifdef DEBUG
|
||||
if (aDatabase) {
|
||||
NS_ASSERTION(!PR_GetThreadPrivate(gCurrentDatabaseIndex),
|
||||
"Someone forgot to unset gCurrentDatabaseIndex!");
|
||||
}
|
||||
else {
|
||||
NS_ASSERTION(PR_GetThreadPrivate(gCurrentDatabaseIndex),
|
||||
"Someone forgot to set gCurrentDatabaseIndex!");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (PR_SetThreadPrivate(gCurrentDatabaseIndex, aDatabase) != PR_SUCCESS) {
|
||||
NS_WARNING("Failed to set gCurrentDatabaseIndex!");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
PRUint32
|
||||
IDBFactory::GetIndexedDBQuota()
|
||||
{
|
||||
return gIndexedDBQuota;
|
||||
}
|
||||
|
||||
NS_IMPL_ADDREF(IDBFactory)
|
||||
NS_IMPL_RELEASE(IDBFactory)
|
||||
|
||||
@ -524,12 +642,27 @@ IDBFactory::Open(const nsAString& aName,
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
nsresult rv;
|
||||
|
||||
if (gCurrentDatabaseIndex == BAD_TLS_INDEX) {
|
||||
// First time we're creating a database.
|
||||
if (PR_NewThreadPrivateIndex(&gCurrentDatabaseIndex, NULL) != PR_SUCCESS) {
|
||||
NS_ERROR("PR_NewThreadPrivateIndex failed!");
|
||||
gCurrentDatabaseIndex = BAD_TLS_INDEX;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
PRInt32 quota = nsContentUtils::GetIntPref(PREF_INDEXEDDB_QUOTA,
|
||||
DEFAULT_QUOTA);
|
||||
gIndexedDBQuota = PRUint32(PR_MAX(quota, 0));
|
||||
}
|
||||
|
||||
if (aName.IsEmpty()) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
nsresult rv = nsContentUtils::GetSecurityManager()->
|
||||
rv = nsContentUtils::GetSecurityManager()->
|
||||
GetSubjectPrincipal(getter_AddRefs(principal));
|
||||
NS_ENSURE_SUCCESS(rv, nsnull);
|
||||
|
||||
@ -540,6 +673,11 @@ IDBFactory::Open(const nsAString& aName,
|
||||
else {
|
||||
rv = nsContentUtils::GetASCIIOrigin(principal, origin);
|
||||
NS_ENSURE_SUCCESS(rv, nsnull);
|
||||
|
||||
if (origin.EqualsLiteral("null")) {
|
||||
NS_WARNING("IndexedDB databases not allowed for this principal!");
|
||||
return nsnull;
|
||||
}
|
||||
}
|
||||
|
||||
nsIScriptContext* context = GetScriptContextFromJSContext(aCx);
|
||||
@ -560,10 +698,13 @@ IDBFactory::Open(const nsAString& aName,
|
||||
nsRefPtr<LazyIdleThread> thread(new LazyIdleThread(kDefaultThreadTimeoutMS,
|
||||
nsnull));
|
||||
|
||||
nsRefPtr<OpenDatabaseHelper> runnable =
|
||||
nsRefPtr<OpenDatabaseHelper> openHelper =
|
||||
new OpenDatabaseHelper(request, aName, aDescription, origin, thread);
|
||||
|
||||
rv = runnable->Dispatch(thread);
|
||||
nsRefPtr<CheckPermissionsHelper> permissionHelper =
|
||||
new CheckPermissionsHelper(openHelper, thread, innerWindow, origin);
|
||||
|
||||
rv = NS_DispatchToCurrentThread(permissionHelper);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
request.forget(_retval);
|
||||
|
@ -47,20 +47,25 @@
|
||||
|
||||
BEGIN_INDEXEDDB_NAMESPACE
|
||||
|
||||
class IDBDatabase;
|
||||
|
||||
class IDBFactory : public nsIIDBFactory
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIIDBFACTORY
|
||||
|
||||
static
|
||||
already_AddRefed<nsIIDBFactory>
|
||||
Create();
|
||||
static already_AddRefed<nsIIDBFactory> Create();
|
||||
|
||||
static
|
||||
already_AddRefed<mozIStorageConnection>
|
||||
static already_AddRefed<mozIStorageConnection>
|
||||
GetConnection(const nsAString& aDatabaseFilePath);
|
||||
|
||||
static bool
|
||||
SetCurrentDatabase(IDBDatabase* aDatabase);
|
||||
|
||||
static PRUint32
|
||||
GetIndexedDBQuota();
|
||||
|
||||
private:
|
||||
IDBFactory() { }
|
||||
~IDBFactory() { }
|
||||
|
@ -47,11 +47,11 @@
|
||||
#include "nsProxyRelease.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
#include "IDBEvents.h"
|
||||
#include "IDBCursor.h"
|
||||
#include "IDBObjectStore.h"
|
||||
#include "IDBFactory.h"
|
||||
#include "DatabaseInfo.h"
|
||||
#include "IDBCursor.h"
|
||||
#include "IDBEvents.h"
|
||||
#include "IDBFactory.h"
|
||||
#include "IDBObjectStore.h"
|
||||
#include "TransactionThreadPool.h"
|
||||
|
||||
#define SAVEPOINT_INITIAL "initial"
|
||||
@ -765,6 +765,8 @@ CommitHelper::Run()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
IDBFactory::SetCurrentDatabase(mTransaction->Database());
|
||||
|
||||
if (mAborted) {
|
||||
NS_ASSERTION(mConnection, "This had better not be null!");
|
||||
|
||||
@ -778,7 +780,7 @@ CommitHelper::Run()
|
||||
|
||||
NS_NAMED_LITERAL_CSTRING(release, "RELEASE " SAVEPOINT_INITIAL);
|
||||
if (NS_FAILED(mConnection->ExecuteSimpleSQL(release))) {
|
||||
NS_WARNING("Failed to release transaction!");
|
||||
mAborted = PR_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
@ -787,5 +789,7 @@ CommitHelper::Run()
|
||||
mConnection->Close();
|
||||
mConnection = nsnull;
|
||||
|
||||
IDBFactory::SetCurrentDatabase(nsnull);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -53,6 +53,8 @@ EXPORTS_NAMESPACES = mozilla/dom/indexedDB
|
||||
|
||||
CPPSRCS = \
|
||||
AsyncConnectionHelper.cpp \
|
||||
CheckPermissionsHelper.cpp \
|
||||
CheckQuotaHelper.cpp \
|
||||
DatabaseInfo.cpp \
|
||||
IDBCursor.cpp \
|
||||
IDBDatabase.cpp \
|
||||
@ -83,6 +85,7 @@ EXPORTS_mozilla/dom/indexedDB = \
|
||||
|
||||
LOCAL_INCLUDES = \
|
||||
-I$(topsrcdir)/dom/base \
|
||||
-I$(topsrcdir)/dom/src/storage \
|
||||
-I$(topsrcdir)/content/base/src \
|
||||
-I$(topsrcdir)/content/events/src \
|
||||
$(NULL)
|
||||
|
@ -6,6 +6,14 @@
|
||||
var testGenerator = testSteps();
|
||||
function runTest()
|
||||
{
|
||||
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||
|
||||
let uri = window.document.documentURIObject;
|
||||
Components.classes["@mozilla.org/permissionmanager;1"]
|
||||
.getService(Components.interfaces.nsIPermissionManager)
|
||||
.add(uri, "indexedDB",
|
||||
Components.interfaces.nsIPermissionManager.ALLOW_ACTION);
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
testGenerator.next();
|
||||
}
|
||||
|
@ -96,6 +96,11 @@ pref("offline-apps.quota.max", 7000);
|
||||
pref("offline-apps.quota.warn", 4000);
|
||||
#endif
|
||||
|
||||
// Whether or not indexedDB is enabled.
|
||||
pref("dom.indexedDB.enabled", true);
|
||||
// Space to allow indexedDB databases before prompting (in MB).
|
||||
pref("dom.indexedDB.warningQuota", 50);
|
||||
|
||||
// Fastback caching - if this pref is negative, then we calculate the number
|
||||
// of content viewers to cache based on the amount of available memory.
|
||||
pref("browser.sessionhistory.max_total_viewers", -1);
|
||||
|
Loading…
Reference in New Issue
Block a user