зеркало из https://github.com/mozilla/gecko-dev.git
Bug 785884 - Implement support for temporary storage (aka shared pool). r=ehsan, r=bent
--HG-- rename : caps/tests/mochitest/test_principal_extendedorigin_appid_appstatus.html => caps/tests/mochitest/test_principal_jarprefix_origin_appid_appstatus.html rename : dom/quota/UsageRunnable.h => dom/quota/UsageInfo.h
This commit is contained in:
Родитель
67b05683bd
Коммит
e9492bcd36
|
@ -61,7 +61,7 @@ let DomStorage = {
|
|||
// Check if we're allowed to store sessionStorage data.
|
||||
let isHTTPS = principal.URI && principal.URI.schemeIs("https");
|
||||
if (aFullData || SessionStore.checkPrivacyLevel(isHTTPS, isPinned)) {
|
||||
let origin = principal.extendedOrigin;
|
||||
let origin = principal.jarPrefix + principal.origin;
|
||||
|
||||
// Don't read a host twice.
|
||||
if (!(origin in data)) {
|
||||
|
|
|
@ -20,7 +20,7 @@ interface nsIContentSecurityPolicy;
|
|||
[ptr] native JSPrincipals(JSPrincipals);
|
||||
[ptr] native PrincipalArray(nsTArray<nsCOMPtr<nsIPrincipal> >);
|
||||
|
||||
[scriptable, builtinclass, uuid(dbda8bb0-3023-4aec-ad98-8e9931a29d70)]
|
||||
[scriptable, builtinclass, uuid(551bf53d-203c-4ac4-8c0b-40aa7b5f1ad6)]
|
||||
interface nsIPrincipal : nsISerializable
|
||||
{
|
||||
/**
|
||||
|
@ -162,19 +162,19 @@ interface nsIPrincipal : nsISerializable
|
|||
[noscript] attribute nsIContentSecurityPolicy csp;
|
||||
|
||||
/**
|
||||
* Returns the extended origin of the principal.
|
||||
* The extended origin is a string that has more information than the origin
|
||||
* and can be used to isolate data or permissions between different
|
||||
* principals while taking into account parameters like the app id or the
|
||||
* fact that the principal is embedded in a mozbrowser.
|
||||
* Some principals will return the origin for extendedOrigin.
|
||||
* Some principals will assert if you try to access the extendedOrigin.
|
||||
* Returns the jar prefix of the principal.
|
||||
* The jar prefix is a string that can be used to isolate data or
|
||||
* permissions between different principals while taking into account
|
||||
* parameters like the app id or the fact that the principal is embedded in
|
||||
* a mozbrowser.
|
||||
* Some principals will return an empty string.
|
||||
* Some principals will assert if you try to access the jarPrefix.
|
||||
*
|
||||
* The extendedOrigin is intended to be an opaque identifier. It is
|
||||
* currently "human-readable" but no callers should assume it will stay
|
||||
* as is and it might be crypto-hashed at some point.
|
||||
* The jarPrefix is intended to be an opaque identifier. It is currently
|
||||
* "human-readable" but no callers should assume it will stay as is and
|
||||
* it might be crypto-hashed at some point.
|
||||
*/
|
||||
readonly attribute AUTF8String extendedOrigin;
|
||||
readonly attribute AUTF8String jarPrefix;
|
||||
|
||||
/**
|
||||
* The base domain of the codebase URI to which this principal pertains
|
||||
|
|
|
@ -10,7 +10,7 @@ interface nsIURI;
|
|||
interface nsIChannel;
|
||||
interface nsIDocShell;
|
||||
|
||||
[scriptable, uuid(ae486501-ec57-4ec8-a565-6880ca4ae6c4)]
|
||||
[scriptable, uuid(d6475e53-9ece-4dc0-940c-095ac3d85363)]
|
||||
interface nsIScriptSecurityManager : nsIXPCSecurityManager
|
||||
{
|
||||
///////////////// Security Checks //////////////////
|
||||
|
@ -229,13 +229,12 @@ interface nsIScriptSecurityManager : nsIXPCSecurityManager
|
|||
const unsigned long UNKNOWN_APP_ID = 4294967295; // UINT32_MAX
|
||||
|
||||
/**
|
||||
* Returns the extended origin for the uri.
|
||||
* Returns the jar prefix for the app.
|
||||
* appId can be NO_APP_ID or a valid app id. appId should not be
|
||||
* UNKNOWN_APP_ID.
|
||||
* inMozBrowser has to be true if the uri is inside a mozbrowser iframe.
|
||||
* inMozBrowser has to be true if the app is inside a mozbrowser iframe.
|
||||
*/
|
||||
AUTF8String getExtendedOrigin(in nsIURI uri, in unsigned long appId,
|
||||
in boolean inMozBrowser);
|
||||
AUTF8String getJarPrefix(in unsigned long appId, in boolean inMozBrowser);
|
||||
};
|
||||
|
||||
%{C++
|
||||
|
|
|
@ -65,7 +65,7 @@ public:
|
|||
NS_IMETHOD Subsumes(nsIPrincipal* other, bool* _retval);
|
||||
NS_IMETHOD SubsumesIgnoringDomain(nsIPrincipal* other, bool* _retval);
|
||||
NS_IMETHOD CheckMayLoad(nsIURI* uri, bool report, bool allowIfInheritsPrincipal);
|
||||
NS_IMETHOD GetExtendedOrigin(nsACString& aExtendedOrigin);
|
||||
NS_IMETHOD GetJarPrefix(nsACString& aJarPrefix);
|
||||
NS_IMETHOD GetAppStatus(uint16_t* aAppStatus);
|
||||
NS_IMETHOD GetAppId(uint32_t* aAppStatus);
|
||||
NS_IMETHOD GetIsInBrowserElement(bool* aIsInBrowserElement);
|
||||
|
@ -148,7 +148,7 @@ public:
|
|||
NS_IMETHOD Subsumes(nsIPrincipal* other, bool* _retval);
|
||||
NS_IMETHOD SubsumesIgnoringDomain(nsIPrincipal* other, bool* _retval);
|
||||
NS_IMETHOD CheckMayLoad(nsIURI* uri, bool report, bool allowIfInheritsPrincipal);
|
||||
NS_IMETHOD GetExtendedOrigin(nsACString& aExtendedOrigin);
|
||||
NS_IMETHOD GetJarPrefix(nsACString& aJarPrefix);
|
||||
NS_IMETHOD GetAppStatus(uint16_t* aAppStatus);
|
||||
NS_IMETHOD GetAppId(uint32_t* aAppStatus);
|
||||
NS_IMETHOD GetIsInBrowserElement(bool* aIsInBrowserElement);
|
||||
|
|
|
@ -526,9 +526,9 @@ public:
|
|||
namespace mozilla {
|
||||
|
||||
void
|
||||
GetExtendedOrigin(nsIURI* aURI, uint32_t aAppid,
|
||||
bool aInMozBrowser,
|
||||
nsACString& aExtendedOrigin);
|
||||
GetJarPrefix(uint32_t aAppid,
|
||||
bool aInMozBrowser,
|
||||
nsACString& aJarPrefix);
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
|
|
|
@ -259,9 +259,10 @@ nsNullPrincipal::CheckMayLoad(nsIURI* aURI, bool aReport, bool aAllowIfInheritsP
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNullPrincipal::GetExtendedOrigin(nsACString& aExtendedOrigin)
|
||||
nsNullPrincipal::GetJarPrefix(nsACString& aJarPrefix)
|
||||
{
|
||||
return GetOrigin(getter_Copies(aExtendedOrigin));
|
||||
aJarPrefix.Truncate();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
|
|
@ -424,11 +424,11 @@ nsPrincipal::SetDomain(nsIURI* aDomain)
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPrincipal::GetExtendedOrigin(nsACString& aExtendedOrigin)
|
||||
nsPrincipal::GetJarPrefix(nsACString& aJarPrefix)
|
||||
{
|
||||
MOZ_ASSERT(mAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID);
|
||||
|
||||
mozilla::GetExtendedOrigin(mCodebase, mAppId, mInMozBrowser, aExtendedOrigin);
|
||||
mozilla::GetJarPrefix(mAppId, mInMozBrowser, aJarPrefix);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -773,9 +773,10 @@ nsExpandedPrincipal::GetWhiteList(nsTArray<nsCOMPtr<nsIPrincipal> >** aWhiteList
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsExpandedPrincipal::GetExtendedOrigin(nsACString& aExtendedOrigin)
|
||||
nsExpandedPrincipal::GetJarPrefix(nsACString& aJarPrefix)
|
||||
{
|
||||
return GetOrigin(getter_Copies(aExtendedOrigin));
|
||||
aJarPrefix.Truncate();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
|
|
@ -2778,32 +2778,26 @@ nsScriptSecurityManager::InitPrefs()
|
|||
namespace mozilla {
|
||||
|
||||
void
|
||||
GetExtendedOrigin(nsIURI* aURI, uint32_t aAppId, bool aInMozBrowser,
|
||||
nsACString& aExtendedOrigin)
|
||||
GetJarPrefix(uint32_t aAppId, bool aInMozBrowser, nsACString& aJarPrefix)
|
||||
{
|
||||
MOZ_ASSERT(aURI);
|
||||
MOZ_ASSERT(aAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID);
|
||||
|
||||
if (aAppId == nsIScriptSecurityManager::UNKNOWN_APP_ID) {
|
||||
aAppId = nsIScriptSecurityManager::NO_APP_ID;
|
||||
}
|
||||
|
||||
nsAutoCString origin;
|
||||
nsPrincipal::GetOriginForURI(aURI, getter_Copies(origin));
|
||||
aJarPrefix.Truncate();
|
||||
|
||||
// Fallback.
|
||||
if (aAppId == nsIScriptSecurityManager::NO_APP_ID && !aInMozBrowser) {
|
||||
aExtendedOrigin.Assign(origin);
|
||||
return;
|
||||
}
|
||||
|
||||
// aExtendedOrigin = appId + "+" + { 't', 'f' } "+" + origin;
|
||||
aExtendedOrigin.Truncate();
|
||||
aExtendedOrigin.AppendInt(aAppId);
|
||||
aExtendedOrigin.Append('+');
|
||||
aExtendedOrigin.Append(aInMozBrowser ? 't' : 'f');
|
||||
aExtendedOrigin.Append('+');
|
||||
aExtendedOrigin.Append(origin);
|
||||
// aJarPrefix = appId + "+" + { 't', 'f' } + "+";
|
||||
aJarPrefix.AppendInt(aAppId);
|
||||
aJarPrefix.Append('+');
|
||||
aJarPrefix.Append(aInMozBrowser ? 't' : 'f');
|
||||
aJarPrefix.Append('+');
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -2811,13 +2805,12 @@ GetExtendedOrigin(nsIURI* aURI, uint32_t aAppId, bool aInMozBrowser,
|
|||
} // namespace mozilla
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsScriptSecurityManager::GetExtendedOrigin(nsIURI* aURI,
|
||||
uint32_t aAppId,
|
||||
bool aInMozBrowser,
|
||||
nsACString& aExtendedOrigin)
|
||||
nsScriptSecurityManager::GetJarPrefix(uint32_t aAppId,
|
||||
bool aInMozBrowser,
|
||||
nsACString& aJarPrefix)
|
||||
{
|
||||
MOZ_ASSERT(aAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID);
|
||||
|
||||
mozilla::GetExtendedOrigin(aURI, aAppId, aInMozBrowser, aExtendedOrigin);
|
||||
mozilla::GetJarPrefix(aAppId, aInMozBrowser, aJarPrefix);
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -166,9 +166,10 @@ nsSystemPrincipal::SetSecurityPolicy(void* aSecurityPolicy)
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSystemPrincipal::GetExtendedOrigin(nsACString& aExtendedOrigin)
|
||||
nsSystemPrincipal::GetJarPrefix(nsACString& aJarPrefix)
|
||||
{
|
||||
return GetOrigin(getter_Copies(aExtendedOrigin));
|
||||
aJarPrefix.Truncate();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
|
|
@ -11,8 +11,8 @@ MOCHITEST_FILES = test_bug423375.html \
|
|||
test_app_principal_equality.html \
|
||||
$(NULL)
|
||||
|
||||
# extendedOrigin test doesn't work on Windows, see bug 776296.
|
||||
# jarPrefix test doesn't work on Windows, see bug 776296.
|
||||
ifneq ($(OS_ARCH),WINNT)
|
||||
MOCHITEST_CHROME_FILES = test_principal_extendedorigin_appid_appstatus.html \
|
||||
MOCHITEST_CHROME_FILES = test_principal_jarprefix_origin_appid_appstatus.html \
|
||||
$(NULL)
|
||||
endif
|
||||
|
|
|
@ -5,7 +5,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=758258
|
|||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for nsIPrincipal extendedOrigin, appStatus and appId</title>
|
||||
<title>Test for nsIPrincipal jarPrefix, origin, appStatus and appId</title>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
|
||||
</head>
|
||||
|
@ -294,20 +294,20 @@ function checkIFrame(aFrame, data) {
|
|||
}
|
||||
|
||||
if (!data.isapp && !data.browser) {
|
||||
is(principal.extendedOrigin, principal.origin,
|
||||
'extendedOrigin should return the origin for non-app and non-browsers principals');
|
||||
is(principal.jarPrefix, "",
|
||||
'jarPrefix should return an empty string for non-app and non-browsers principals');
|
||||
} else {
|
||||
isnot(principal.extendedOrigin, principal.origin,
|
||||
'extendedOrigin should not return the origin for apps or mozbrowsers');
|
||||
isnot(principal.jarPrefix, "",
|
||||
'jarPrefix should not return an empty string for apps or mozbrowsers');
|
||||
}
|
||||
|
||||
if (data.test.indexOf("eo-unique") != -1) {
|
||||
is(eoList.indexOf(principal.extendedOrigin), -1,
|
||||
"extendedOrigin should be unique");
|
||||
is(eoList.indexOf(principal.jarPrefix + principal.origin), -1,
|
||||
"extended origin should be unique");
|
||||
}
|
||||
if (data.test.indexOf("eo-as-last") != -1) {
|
||||
is(principal.extendedOrigin, eoList[eoList.length-1],
|
||||
"extendedOrigin should be the same as the last inserted one");
|
||||
is(principal.jarPrefix + principal.origin, eoList[eoList.length-1],
|
||||
"extended origin should be the same as the last inserted one");
|
||||
}
|
||||
|
||||
is(principal.isInBrowserElement, !!data.browser,
|
||||
|
@ -325,17 +325,19 @@ function checkIFrame(aFrame, data) {
|
|||
"check childPrincipal.isInBrowserElement");
|
||||
|
||||
if (data.test.indexOf("child-has-same-eo") != -1) {
|
||||
is(childPrincipal.extendedOrigin, principal.extendedOrigin,
|
||||
"child should have the same extendedOrigin as parent");
|
||||
is(childPrincipal.jarPrefix + childPrincipal.origin,
|
||||
principal.jarPrefix + principal.origin,
|
||||
"child should have the same extended origin as parent");
|
||||
is(childPrincipal.appStatus, principal.appStatus,
|
||||
"child should have the same appStatus if it has the same extendedOrigin");
|
||||
"child should have the same appStatus if it has the same extended origin");
|
||||
is(childPrincipal.appId, principal.appId,
|
||||
"child should have the same appId if it has the same extendedOrigin");
|
||||
"child should have the same appId if it has the same extended origin");
|
||||
}
|
||||
|
||||
if (data.test.indexOf("child-has-different-eo") != -1) {
|
||||
isnot(childPrincipal.extendedOrigin, principal.extendedOrigin,
|
||||
"child should not have the same extendedOrigin as parent");
|
||||
isnot(childPrincipal.jarPrefix + childPrincipal.origin,
|
||||
principal.jarPrefix + principal.origin,
|
||||
"child should not have the same extended origin as parent");
|
||||
}
|
||||
|
||||
if (data.test.indexOf("child-has-same-appstatus") != -1) {
|
||||
|
@ -359,7 +361,7 @@ function checkIFrame(aFrame, data) {
|
|||
}
|
||||
}
|
||||
|
||||
eoList.push(principal.extendedOrigin);
|
||||
eoList.push(principal.jarPrefix + principal.origin);
|
||||
|
||||
checkedCount++;
|
||||
if (checkedCount == checksTodo) {
|
||||
|
@ -373,8 +375,10 @@ function checkIFrame(aFrame, data) {
|
|||
|
||||
is('appStatus' in document.nodePrincipal, true,
|
||||
'appStatus should be present in nsIPrincipal');
|
||||
is('extendedOrigin' in document.nodePrincipal, true,
|
||||
'extendedOrigin should be present in nsIPrincipal');
|
||||
is('jarPrefix' in document.nodePrincipal, true,
|
||||
'jarPrefix should be present in nsIPrincipal');
|
||||
is('origin' in document.nodePrincipal, true,
|
||||
'origin should be present in nsIPrincipal');
|
||||
is('appId' in document.nodePrincipal, true,
|
||||
'appId should be present in nsIPrincipal');
|
||||
|
|
@ -228,7 +228,8 @@ this.PermissionsTable = { geolocation: {
|
|||
substitute: [
|
||||
"indexedDB-unlimited",
|
||||
"offline-app",
|
||||
"pin-app"
|
||||
"pin-app",
|
||||
"default-persistent-storage"
|
||||
]
|
||||
},
|
||||
"background-sensors": {
|
||||
|
|
|
@ -459,7 +459,7 @@ this.DOMApplicationRegistry = {
|
|||
debug("Fixing indexedDb folder names");
|
||||
let idbDir = FileUtils.getDir("indexedDBPDir", ["indexedDB"]);
|
||||
|
||||
if (!idbDir.isDirectory()) {
|
||||
if (!idbDir.exists() || !idbDir.isDirectory()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -59,7 +59,9 @@
|
|||
#include "mozilla/layers/ShadowLayers.h"
|
||||
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/IDBFactoryBinding.h"
|
||||
#include "mozilla/dom/indexedDB/IndexedDatabaseManager.h"
|
||||
#include "mozilla/dom/quota/PersistenceType.h"
|
||||
#include "mozilla/dom/quota/QuotaManager.h"
|
||||
#include "nsDOMBlobBuilder.h"
|
||||
#include "nsIDOMFileHandle.h"
|
||||
|
@ -2826,9 +2828,10 @@ nsDOMWindowUtils::GetFileId(const JS::Value& aFile, JSContext* aCx,
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMWindowUtils::GetFileReferences(const nsAString& aDatabaseName,
|
||||
int64_t aId, int32_t* aRefCnt,
|
||||
int32_t* aDBRefCnt, int32_t* aSliceRefCnt,
|
||||
nsDOMWindowUtils::GetFileReferences(const nsAString& aDatabaseName, int64_t aId,
|
||||
const jsval& aOptions,
|
||||
int32_t* aRefCnt, int32_t* aDBRefCnt,
|
||||
int32_t* aSliceRefCnt, JSContext* aCx,
|
||||
bool* aResult)
|
||||
{
|
||||
if (!nsContentUtils::IsCallerChrome()) {
|
||||
|
@ -2839,15 +2842,28 @@ nsDOMWindowUtils::GetFileReferences(const nsAString& aDatabaseName,
|
|||
NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
|
||||
|
||||
nsCString origin;
|
||||
nsresult rv = quota::QuotaManager::GetASCIIOriginFromWindow(window, origin);
|
||||
quota::PersistenceType defaultPersistenceType;
|
||||
nsresult rv =
|
||||
quota::QuotaManager::GetInfoFromWindow(window, nullptr, &origin, nullptr,
|
||||
&defaultPersistenceType);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
IDBOpenDBOptions options;
|
||||
JS::Rooted<JS::Value> optionsVal(aCx, aOptions);
|
||||
if (!options.Init(aCx, optionsVal)) {
|
||||
return NS_ERROR_TYPE_ERR;
|
||||
}
|
||||
|
||||
quota::PersistenceType persistenceType =
|
||||
quota::PersistenceTypeFromStorage(options.mStorage, defaultPersistenceType);
|
||||
|
||||
nsRefPtr<indexedDB::IndexedDatabaseManager> mgr =
|
||||
indexedDB::IndexedDatabaseManager::Get();
|
||||
|
||||
if (mgr) {
|
||||
rv = mgr->BlockAndGetFileReferences(origin, aDatabaseName, aId, aRefCnt,
|
||||
aDBRefCnt, aSliceRefCnt, aResult);
|
||||
rv = mgr->BlockAndGetFileReferences(persistenceType, origin, aDatabaseName,
|
||||
aId, aRefCnt, aDBRefCnt, aSliceRefCnt,
|
||||
aResult);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -64,6 +64,28 @@ public:
|
|||
return mIsNull;
|
||||
}
|
||||
|
||||
bool Equals(const Nullable<T>& aOtherNullable) const
|
||||
{
|
||||
return (mIsNull && aOtherNullable.mIsNull) ||
|
||||
(!mIsNull && !aOtherNullable.mIsNull &&
|
||||
mValue == aOtherNullable.mValue);
|
||||
}
|
||||
|
||||
bool operator==(const Nullable<T>& aOtherNullable) const
|
||||
{
|
||||
return Equals(aOtherNullable);
|
||||
}
|
||||
|
||||
bool operator!=(const Nullable<T>& aOtherNullable) const
|
||||
{
|
||||
return !Equals(aOtherNullable);
|
||||
}
|
||||
|
||||
operator bool() const
|
||||
{
|
||||
return !mIsNull;
|
||||
}
|
||||
|
||||
// Make it possible to use a const Nullable of an array type with other
|
||||
// array types.
|
||||
template<typename U>
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
#include "nsContentUtils.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "mozilla/dom/quota/QuotaManager.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/Services.h"
|
||||
|
||||
|
@ -165,10 +164,7 @@ CheckPermissionsHelper::Run()
|
|||
}
|
||||
}
|
||||
|
||||
quota::QuotaManager* quotaManager = quota::QuotaManager::Get();
|
||||
NS_ASSERTION(quotaManager, "This should never be null!");
|
||||
|
||||
return helper->Dispatch(quotaManager->IOThread());
|
||||
return helper->DispatchToIOThread();
|
||||
}
|
||||
|
||||
NS_ASSERTION(permission == PERMISSION_PROMPT ||
|
||||
|
|
|
@ -30,17 +30,18 @@ public:
|
|||
NS_DECL_NSIOBSERVER
|
||||
|
||||
CheckPermissionsHelper(OpenDatabaseHelper* aHelper,
|
||||
nsIDOMWindow* aWindow,
|
||||
bool aForDeletion)
|
||||
nsIDOMWindow* aWindow)
|
||||
: mHelper(aHelper),
|
||||
mWindow(aWindow),
|
||||
// If we're trying to delete the database, we should never prompt the user.
|
||||
// Anything that would prompt is translated to denied.
|
||||
mPromptAllowed(!aForDeletion),
|
||||
mPromptAllowed(!aHelper->mForDeletion),
|
||||
mHasPrompted(false),
|
||||
mPromptResult(0)
|
||||
{
|
||||
NS_ASSERTION(aHelper, "Null pointer!");
|
||||
NS_ASSERTION(aHelper->mPersistenceType == quota::PERSISTENCE_TYPE_PERSISTENT,
|
||||
"Checking permission for non persistent databases?!");
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
#include "Client.h"
|
||||
|
||||
#include "mozilla/dom/quota/QuotaManager.h"
|
||||
#include "mozilla/dom/quota/UsageRunnable.h"
|
||||
#include "mozilla/dom/quota/UsageInfo.h"
|
||||
#include "mozilla/dom/quota/Utilities.h"
|
||||
|
||||
#include "IDBDatabase.h"
|
||||
|
@ -45,12 +45,14 @@ NS_IMPL_ADDREF(mozilla::dom::indexedDB::Client)
|
|||
NS_IMPL_RELEASE(mozilla::dom::indexedDB::Client)
|
||||
|
||||
nsresult
|
||||
Client::InitOrigin(const nsACString& aOrigin, UsageRunnable* aUsageRunnable)
|
||||
Client::InitOrigin(PersistenceType aPersistenceType, const nsACString& aGroup,
|
||||
const nsACString& aOrigin, UsageInfo* aUsageInfo)
|
||||
{
|
||||
AssertIsOnIOThread();
|
||||
|
||||
nsCOMPtr<nsIFile> directory;
|
||||
nsresult rv = GetDirectory(aOrigin, getter_AddRefs(directory));
|
||||
nsresult rv =
|
||||
GetDirectory(aPersistenceType, aOrigin, getter_AddRefs(directory));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// We need to see if there are any files in the directory already. If they
|
||||
|
@ -67,7 +69,7 @@ Client::InitOrigin(const nsACString& aOrigin, UsageRunnable* aUsageRunnable)
|
|||
|
||||
bool hasMore;
|
||||
while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) &&
|
||||
hasMore && (!aUsageRunnable || !aUsageRunnable->Canceled())) {
|
||||
hasMore && (!aUsageInfo || !aUsageInfo->Canceled())) {
|
||||
nsCOMPtr<nsISupports> entry;
|
||||
rv = entries->GetNext(getter_AddRefs(entry));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
@ -83,11 +85,9 @@ Client::InitOrigin(const nsACString& aOrigin, UsageRunnable* aUsageRunnable)
|
|||
continue;
|
||||
}
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
if (leafName.EqualsLiteral(DSSTORE_FILE_NAME)) {
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool isDirectory;
|
||||
rv = file->IsDirectory(&isDirectory);
|
||||
|
@ -113,21 +113,24 @@ Client::InitOrigin(const nsACString& aOrigin, UsageRunnable* aUsageRunnable)
|
|||
rv = fmDirectory->Append(dbBaseFilename);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = FileManager::InitDirectory(fmDirectory, file, aOrigin);
|
||||
rv = FileManager::InitDirectory(fmDirectory, file, aPersistenceType, aGroup,
|
||||
aOrigin);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (aUsageRunnable) {
|
||||
if (aUsageInfo) {
|
||||
int64_t fileSize;
|
||||
rv = file->GetFileSize(&fileSize);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
aUsageRunnable->AppendToDatabaseUsage(uint64_t(fileSize));
|
||||
NS_ASSERTION(fileSize >= 0, "Negative size?!");
|
||||
|
||||
aUsageInfo->AppendToDatabaseUsage(uint64_t(fileSize));
|
||||
|
||||
uint64_t usage;
|
||||
rv = FileManager::GetUsage(fmDirectory, &usage);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
aUsageRunnable->AppendToFileUsage(usage);
|
||||
aUsageInfo->AppendToFileUsage(usage);
|
||||
}
|
||||
|
||||
validSubdirs.PutEntry(dbBaseFilename);
|
||||
|
@ -167,30 +170,33 @@ Client::InitOrigin(const nsACString& aOrigin, UsageRunnable* aUsageRunnable)
|
|||
}
|
||||
|
||||
nsresult
|
||||
Client::GetUsageForOrigin(const nsACString& aOrigin,
|
||||
UsageRunnable* aUsageRunnable)
|
||||
Client::GetUsageForOrigin(PersistenceType aPersistenceType,
|
||||
const nsACString& aGroup, const nsACString& aOrigin,
|
||||
UsageInfo* aUsageInfo)
|
||||
{
|
||||
AssertIsOnIOThread();
|
||||
NS_ASSERTION(aUsageRunnable, "Null pointer!");
|
||||
NS_ASSERTION(aUsageInfo, "Null pointer!");
|
||||
|
||||
nsCOMPtr<nsIFile> directory;
|
||||
nsresult rv = GetDirectory(aOrigin, getter_AddRefs(directory));
|
||||
nsresult rv =
|
||||
GetDirectory(aPersistenceType, aOrigin, getter_AddRefs(directory));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = GetUsageForDirectoryInternal(directory, aUsageRunnable, true);
|
||||
rv = GetUsageForDirectoryInternal(directory, aUsageInfo, true);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
Client::OnOriginClearCompleted(const nsACString& aPattern)
|
||||
Client::OnOriginClearCompleted(PersistenceType aPersistenceType,
|
||||
const OriginOrPatternString& aOriginOrPattern)
|
||||
{
|
||||
AssertIsOnIOThread();
|
||||
|
||||
IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
|
||||
if (mgr) {
|
||||
mgr->InvalidateFileManagersForPattern(aPattern);
|
||||
mgr->InvalidateFileManagers(aPersistenceType, aOriginOrPattern);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -275,14 +281,15 @@ Client::ShutdownTransactionService()
|
|||
}
|
||||
|
||||
nsresult
|
||||
Client::GetDirectory(const nsACString& aOrigin, nsIFile** aDirectory)
|
||||
Client::GetDirectory(PersistenceType aPersistenceType,
|
||||
const nsACString& aOrigin, nsIFile** aDirectory)
|
||||
{
|
||||
QuotaManager* quotaManager = QuotaManager::Get();
|
||||
NS_ASSERTION(quotaManager, "This should never fail!");
|
||||
|
||||
nsCOMPtr<nsIFile> directory;
|
||||
nsresult rv =
|
||||
quotaManager->GetDirectoryForOrigin(aOrigin, getter_AddRefs(directory));
|
||||
nsresult rv = quotaManager->GetDirectoryForOrigin(aPersistenceType, aOrigin,
|
||||
getter_AddRefs(directory));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
NS_ASSERTION(directory, "What?");
|
||||
|
@ -296,11 +303,11 @@ Client::GetDirectory(const nsACString& aOrigin, nsIFile** aDirectory)
|
|||
|
||||
nsresult
|
||||
Client::GetUsageForDirectoryInternal(nsIFile* aDirectory,
|
||||
UsageRunnable* aUsageRunnable,
|
||||
UsageInfo* aUsageInfo,
|
||||
bool aDatabaseFiles)
|
||||
{
|
||||
NS_ASSERTION(aDirectory, "Null pointer!");
|
||||
NS_ASSERTION(aUsageRunnable, "Null pointer!");
|
||||
NS_ASSERTION(aUsageInfo, "Null pointer!");
|
||||
|
||||
nsCOMPtr<nsISimpleEnumerator> entries;
|
||||
nsresult rv = aDirectory->GetDirectoryEntries(getter_AddRefs(entries));
|
||||
|
@ -312,7 +319,7 @@ Client::GetUsageForDirectoryInternal(nsIFile* aDirectory,
|
|||
|
||||
bool hasMore;
|
||||
while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) &&
|
||||
hasMore && !aUsageRunnable->Canceled()) {
|
||||
hasMore && !aUsageInfo->Canceled()) {
|
||||
nsCOMPtr<nsISupports> entry;
|
||||
rv = entries->GetNext(getter_AddRefs(entry));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
@ -326,7 +333,7 @@ Client::GetUsageForDirectoryInternal(nsIFile* aDirectory,
|
|||
|
||||
if (isDirectory) {
|
||||
if (aDatabaseFiles) {
|
||||
rv = GetUsageForDirectoryInternal(file, aUsageRunnable, false);
|
||||
rv = GetUsageForDirectoryInternal(file, aUsageInfo, false);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
else {
|
||||
|
@ -349,10 +356,10 @@ Client::GetUsageForDirectoryInternal(nsIFile* aDirectory,
|
|||
NS_ASSERTION(fileSize >= 0, "Negative size?!");
|
||||
|
||||
if (aDatabaseFiles) {
|
||||
aUsageRunnable->AppendToDatabaseUsage(uint64_t(fileSize));
|
||||
aUsageInfo->AppendToDatabaseUsage(uint64_t(fileSize));
|
||||
}
|
||||
else {
|
||||
aUsageRunnable->AppendToFileUsage(uint64_t(fileSize));
|
||||
aUsageInfo->AppendToFileUsage(uint64_t(fileSize));
|
||||
}
|
||||
}
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
|
|
@ -18,7 +18,9 @@ BEGIN_INDEXEDDB_NAMESPACE
|
|||
|
||||
class Client : public mozilla::dom::quota::Client
|
||||
{
|
||||
typedef mozilla::dom::quota::UsageRunnable UsageRunnable;
|
||||
typedef mozilla::dom::quota::OriginOrPatternString OriginOrPatternString;
|
||||
typedef mozilla::dom::quota::PersistenceType PersistenceType;
|
||||
typedef mozilla::dom::quota::UsageInfo UsageInfo;
|
||||
|
||||
public:
|
||||
NS_IMETHOD_(nsrefcnt)
|
||||
|
@ -34,15 +36,21 @@ public:
|
|||
}
|
||||
|
||||
virtual nsresult
|
||||
InitOrigin(const nsACString& aOrigin,
|
||||
UsageRunnable* aUsageRunnable) MOZ_OVERRIDE;
|
||||
InitOrigin(PersistenceType aPersistenceType,
|
||||
const nsACString& aGroup,
|
||||
const nsACString& aOrigin,
|
||||
UsageInfo* aUsageInfo) MOZ_OVERRIDE;
|
||||
|
||||
virtual nsresult
|
||||
GetUsageForOrigin(const nsACString& aOrigin,
|
||||
UsageRunnable* aUsageRunnable) MOZ_OVERRIDE;
|
||||
GetUsageForOrigin(PersistenceType aPersistenceType,
|
||||
const nsACString& aGroup,
|
||||
const nsACString& aOrigin,
|
||||
UsageInfo* aUsageInfo) MOZ_OVERRIDE;
|
||||
|
||||
virtual void
|
||||
OnOriginClearCompleted(const nsACString& aPattern) MOZ_OVERRIDE;
|
||||
OnOriginClearCompleted(PersistenceType aPersistenceType,
|
||||
const OriginOrPatternString& aOriginOrPattern)
|
||||
MOZ_OVERRIDE;
|
||||
|
||||
virtual void
|
||||
ReleaseIOThreadObjects() MOZ_OVERRIDE;
|
||||
|
@ -71,11 +79,12 @@ public:
|
|||
|
||||
private:
|
||||
nsresult
|
||||
GetDirectory(const nsACString& aOrigin, nsIFile** aDirectory);
|
||||
GetDirectory(PersistenceType aPersistenceType, const nsACString& aOrigin,
|
||||
nsIFile** aDirectory);
|
||||
|
||||
nsresult
|
||||
GetUsageForDirectoryInternal(nsIFile* aDirectory,
|
||||
UsageRunnable* aUsageRunnable,
|
||||
UsageInfo* aUsageInfo,
|
||||
bool aDatabaseFiles);
|
||||
|
||||
nsAutoRefCnt mRefCnt;
|
||||
|
|
|
@ -250,8 +250,10 @@ DatabaseInfo::Clone()
|
|||
|
||||
dbInfo->cloned = true;
|
||||
dbInfo->name = name;
|
||||
dbInfo->group = group;
|
||||
dbInfo->origin = origin;
|
||||
dbInfo->version = version;
|
||||
dbInfo->persistenceType = persistenceType;
|
||||
dbInfo->id = id;
|
||||
dbInfo->filePath = filePath;
|
||||
dbInfo->nextObjectStoreId = nextObjectStoreId;
|
||||
|
|
|
@ -9,13 +9,14 @@
|
|||
|
||||
#include "mozilla/dom/indexedDB/IndexedDatabase.h"
|
||||
|
||||
#include "mozilla/dom/quota/PersistenceType.h"
|
||||
#include "nsRefPtrHashtable.h"
|
||||
#include "nsHashKeys.h"
|
||||
|
||||
#include "mozilla/dom/indexedDB/Key.h"
|
||||
#include "mozilla/dom/indexedDB/KeyPath.h"
|
||||
#include "mozilla/dom/indexedDB/IDBObjectStore.h"
|
||||
|
||||
#include "nsRefPtrHashtable.h"
|
||||
#include "nsHashKeys.h"
|
||||
|
||||
BEGIN_INDEXEDDB_NAMESPACE
|
||||
|
||||
class IndexedDBDatabaseChild;
|
||||
|
@ -26,6 +27,8 @@ typedef nsRefPtrHashtable<nsStringHashKey, ObjectStoreInfo>
|
|||
|
||||
struct DatabaseInfoGuts
|
||||
{
|
||||
typedef mozilla::dom::quota::PersistenceType PersistenceType;
|
||||
|
||||
DatabaseInfoGuts()
|
||||
: nextObjectStoreId(1), nextIndexId(1)
|
||||
{ }
|
||||
|
@ -33,16 +36,20 @@ struct DatabaseInfoGuts
|
|||
bool operator==(const DatabaseInfoGuts& aOther) const
|
||||
{
|
||||
return this->name == aOther.name &&
|
||||
this->group == aOther.group &&
|
||||
this->origin == aOther.origin &&
|
||||
this->version == aOther.version &&
|
||||
this->persistenceType == aOther.persistenceType &&
|
||||
this->nextObjectStoreId == aOther.nextObjectStoreId &&
|
||||
this->nextIndexId == aOther.nextIndexId;
|
||||
};
|
||||
|
||||
// Make sure to update ipc/SerializationHelpers.h when changing members here!
|
||||
nsString name;
|
||||
nsCString group;
|
||||
nsCString origin;
|
||||
uint64_t version;
|
||||
PersistenceType persistenceType;
|
||||
int64_t nextObjectStoreId;
|
||||
int64_t nextIndexId;
|
||||
};
|
||||
|
|
|
@ -266,6 +266,8 @@ FileManager::GetFileForId(nsIFile* aDirectory, int64_t aId)
|
|||
nsresult
|
||||
FileManager::InitDirectory(nsIFile* aDirectory,
|
||||
nsIFile* aDatabaseFile,
|
||||
PersistenceType aPersistenceType,
|
||||
const nsACString& aGroup,
|
||||
const nsACString& aOrigin)
|
||||
{
|
||||
AssertIsOnIOThread();
|
||||
|
@ -311,7 +313,8 @@ FileManager::InitDirectory(nsIFile* aDirectory,
|
|||
if (hasElements) {
|
||||
nsCOMPtr<mozIStorageConnection> connection;
|
||||
rv = OpenDatabaseHelper::CreateDatabaseConnection(aDatabaseFile,
|
||||
aDirectory, NullString(), aOrigin, getter_AddRefs(connection));
|
||||
aDirectory, NullString(), aPersistenceType, aGroup, aOrigin,
|
||||
getter_AddRefs(connection));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mozStorageTransaction transaction(connection, false);
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "nsIDOMFile.h"
|
||||
#include "nsIFile.h"
|
||||
|
||||
#include "mozilla/dom/quota/PersistenceType.h"
|
||||
#include "mozilla/dom/quota/StoragePrivilege.h"
|
||||
#include "nsDataHashtable.h"
|
||||
|
||||
|
@ -25,13 +26,16 @@ class FileManager
|
|||
{
|
||||
friend class FileInfo;
|
||||
|
||||
typedef mozilla::dom::quota::PersistenceType PersistenceType;
|
||||
typedef mozilla::dom::quota::StoragePrivilege StoragePrivilege;
|
||||
|
||||
public:
|
||||
FileManager(const nsACString& aOrigin, StoragePrivilege aPrivilege,
|
||||
FileManager(PersistenceType aPersistenceType, const nsACString& aGroup,
|
||||
const nsACString& aOrigin, StoragePrivilege aPrivilege,
|
||||
const nsAString& aDatabaseName)
|
||||
: mOrigin(aOrigin), mPrivilege(aPrivilege), mDatabaseName(aDatabaseName),
|
||||
mLastFileId(0), mInvalidated(false)
|
||||
: mPersistenceType(aPersistenceType), mGroup(aGroup), mOrigin(aOrigin),
|
||||
mPrivilege(aPrivilege), mDatabaseName(aDatabaseName), mLastFileId(0),
|
||||
mInvalidated(false)
|
||||
{ }
|
||||
|
||||
~FileManager()
|
||||
|
@ -39,6 +43,16 @@ public:
|
|||
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(FileManager)
|
||||
|
||||
PersistenceType Type()
|
||||
{
|
||||
return mPersistenceType;
|
||||
}
|
||||
|
||||
const nsACString& Group() const
|
||||
{
|
||||
return mGroup;
|
||||
}
|
||||
|
||||
const nsACString& Origin() const
|
||||
{
|
||||
return mOrigin;
|
||||
|
@ -79,11 +93,15 @@ public:
|
|||
|
||||
static nsresult InitDirectory(nsIFile* aDirectory,
|
||||
nsIFile* aDatabaseFile,
|
||||
PersistenceType aPersistenceType,
|
||||
const nsACString& aGroup,
|
||||
const nsACString& aOrigin);
|
||||
|
||||
static nsresult GetUsage(nsIFile* aDirectory, uint64_t* aUsage);
|
||||
|
||||
private:
|
||||
PersistenceType mPersistenceType;
|
||||
nsCString mGroup;
|
||||
nsCString mOrigin;
|
||||
StoragePrivilege mPrivilege;
|
||||
nsString mDatabaseName;
|
||||
|
|
|
@ -197,6 +197,8 @@ IDBDatabase::Create(IDBWrapperCache* aOwnerCache,
|
|||
db->mDatabaseId = databaseInfo->id;
|
||||
db->mName = databaseInfo->name;
|
||||
db->mFilePath = databaseInfo->filePath;
|
||||
db->mPersistenceType = databaseInfo->persistenceType;
|
||||
db->mGroup = databaseInfo->group;
|
||||
databaseInfo.swap(db->mDatabaseInfo);
|
||||
db->mASCIIOrigin = aASCIIOrigin;
|
||||
db->mFileManager = aFileManager;
|
||||
|
@ -227,8 +229,7 @@ IDBDatabase::FromStorage(nsIOfflineStorage* aStorage)
|
|||
}
|
||||
|
||||
IDBDatabase::IDBDatabase()
|
||||
: mDatabaseId(0),
|
||||
mActorChild(nullptr),
|
||||
: mActorChild(nullptr),
|
||||
mActorParent(nullptr),
|
||||
mContentParent(nullptr),
|
||||
mInvalidated(false),
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/dom/IDBObjectStoreBinding.h"
|
||||
#include "mozilla/dom/IDBTransactionBinding.h"
|
||||
#include "mozilla/dom/quota/PersistenceType.h"
|
||||
#include "nsDOMEventTargetHelper.h"
|
||||
|
||||
#include "mozilla/dom/indexedDB/FileManager.h"
|
||||
|
@ -210,6 +211,12 @@ public:
|
|||
IMPL_EVENT_HANDLER(error)
|
||||
IMPL_EVENT_HANDLER(versionchange)
|
||||
|
||||
mozilla::dom::StorageType
|
||||
Storage() const
|
||||
{
|
||||
return PersistenceTypeToStorage(mPersistenceType);
|
||||
}
|
||||
|
||||
already_AddRefed<IDBRequest>
|
||||
MozCreateFileHandle(const nsAString& aName, const Optional<nsAString>& aType,
|
||||
ErrorResult& aRv);
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "nsIFile.h"
|
||||
#include "nsIPrincipal.h"
|
||||
#include "nsIScriptContext.h"
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
#include "nsIXPConnect.h"
|
||||
#include "nsIXPCScriptable.h"
|
||||
|
||||
|
@ -22,7 +23,6 @@
|
|||
#include "mozilla/dom/TabChild.h"
|
||||
#include "mozilla/storage.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
#include "nsCharSeparatedTokenizer.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsCxPusher.h"
|
||||
|
@ -51,6 +51,7 @@ USING_QUOTA_NAMESPACE
|
|||
|
||||
using mozilla::dom::ContentChild;
|
||||
using mozilla::dom::ContentParent;
|
||||
using mozilla::dom::IDBOpenDBOptions;
|
||||
using mozilla::dom::NonNull;
|
||||
using mozilla::dom::Optional;
|
||||
using mozilla::dom::TabChild;
|
||||
|
@ -70,7 +71,8 @@ struct ObjectStoreInfoMap
|
|||
} // anonymous namespace
|
||||
|
||||
IDBFactory::IDBFactory()
|
||||
: mOwningObject(nullptr), mActorChild(nullptr), mActorParent(nullptr),
|
||||
: mPrivilege(Content), mDefaultPersistenceType(PERSISTENCE_TYPE_TEMPORARY),
|
||||
mOwningObject(nullptr), mActorChild(nullptr), mActorParent(nullptr),
|
||||
mContentParent(nullptr), mRootedOwningObject(false)
|
||||
{
|
||||
SetIsDOMBinding();
|
||||
|
@ -93,6 +95,7 @@ IDBFactory::~IDBFactory()
|
|||
// static
|
||||
nsresult
|
||||
IDBFactory::Create(nsPIDOMWindow* aWindow,
|
||||
const nsACString& aGroup,
|
||||
const nsACString& aASCIIOrigin,
|
||||
ContentParent* aContentParent,
|
||||
IDBFactory** aFactory)
|
||||
|
@ -116,18 +119,31 @@ IDBFactory::Create(nsPIDOMWindow* aWindow,
|
|||
|
||||
nsresult rv;
|
||||
|
||||
nsCString group(aGroup);
|
||||
nsCString origin(aASCIIOrigin);
|
||||
StoragePrivilege privilege;
|
||||
PersistenceType defaultPersistenceType;
|
||||
if (origin.IsEmpty()) {
|
||||
rv = QuotaManager::GetASCIIOriginFromWindow(aWindow, origin);
|
||||
if (NS_FAILED(rv)) {
|
||||
// Not allowed.
|
||||
*aFactory = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
NS_ASSERTION(aGroup.IsEmpty(), "Should be empty too!");
|
||||
|
||||
rv = QuotaManager::GetInfoFromWindow(aWindow, &group, &origin, &privilege,
|
||||
&defaultPersistenceType);
|
||||
}
|
||||
else {
|
||||
rv = QuotaManager::GetInfoFromWindow(aWindow, nullptr, nullptr, &privilege,
|
||||
&defaultPersistenceType);
|
||||
}
|
||||
if (NS_FAILED(rv)) {
|
||||
// Not allowed.
|
||||
*aFactory = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsRefPtr<IDBFactory> factory = new IDBFactory();
|
||||
factory->mGroup = group;
|
||||
factory->mASCIIOrigin = origin;
|
||||
factory->mPrivilege = privilege;
|
||||
factory->mDefaultPersistenceType = defaultPersistenceType;
|
||||
factory->mWindow = aWindow;
|
||||
factory->mContentParent = aContentParent;
|
||||
|
||||
|
@ -138,7 +154,7 @@ IDBFactory::Create(nsPIDOMWindow* aWindow,
|
|||
IndexedDBChild* actor = new IndexedDBChild(origin);
|
||||
|
||||
bool allowed;
|
||||
tabChild->SendPIndexedDBConstructor(actor, origin, &allowed);
|
||||
tabChild->SendPIndexedDBConstructor(actor, group, origin, &allowed);
|
||||
|
||||
if (!allowed) {
|
||||
actor->Send__delete__(actor);
|
||||
|
@ -167,12 +183,20 @@ IDBFactory::Create(JSContext* aCx,
|
|||
"Not a global object!");
|
||||
NS_ASSERTION(nsContentUtils::IsCallerChrome(), "Only for chrome!");
|
||||
|
||||
nsCString group;
|
||||
nsCString origin;
|
||||
nsresult rv = QuotaManager::GetASCIIOriginFromWindow(nullptr, origin);
|
||||
StoragePrivilege privilege;
|
||||
PersistenceType defaultPersistenceType;
|
||||
nsresult rv =
|
||||
QuotaManager::GetInfoFromWindow(nullptr, &group, &origin, &privilege,
|
||||
&defaultPersistenceType);
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
nsRefPtr<IDBFactory> factory = new IDBFactory();
|
||||
factory->mGroup = group;
|
||||
factory->mASCIIOrigin = origin;
|
||||
factory->mPrivilege = privilege;
|
||||
factory->mDefaultPersistenceType = defaultPersistenceType;
|
||||
factory->mOwningObject = aOwningObject;
|
||||
factory->mContentParent = aContentParent;
|
||||
|
||||
|
@ -238,7 +262,10 @@ IDBFactory::Create(ContentParent* aContentParent,
|
|||
|
||||
// static
|
||||
already_AddRefed<nsIFileURL>
|
||||
IDBFactory::GetDatabaseFileURL(nsIFile* aDatabaseFile, const nsACString& aOrigin)
|
||||
IDBFactory::GetDatabaseFileURL(nsIFile* aDatabaseFile,
|
||||
PersistenceType aPersistenceType,
|
||||
const nsACString& aGroup,
|
||||
const nsACString& aOrigin)
|
||||
{
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
nsresult rv = NS_NewFileURI(getter_AddRefs(uri), aDatabaseFile);
|
||||
|
@ -247,7 +274,12 @@ IDBFactory::GetDatabaseFileURL(nsIFile* aDatabaseFile, const nsACString& aOrigin
|
|||
nsCOMPtr<nsIFileURL> fileUrl = do_QueryInterface(uri);
|
||||
NS_ASSERTION(fileUrl, "This should always succeed!");
|
||||
|
||||
rv = fileUrl->SetQuery(NS_LITERAL_CSTRING("origin=") + aOrigin);
|
||||
nsAutoCString type;
|
||||
PersistenceTypeToText(aPersistenceType, type);
|
||||
|
||||
rv = fileUrl->SetQuery(NS_LITERAL_CSTRING("persistenceType=") + type +
|
||||
NS_LITERAL_CSTRING("&group=") + aGroup +
|
||||
NS_LITERAL_CSTRING("&origin=") + aOrigin);
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
|
||||
return fileUrl.forget();
|
||||
|
@ -256,6 +288,8 @@ IDBFactory::GetDatabaseFileURL(nsIFile* aDatabaseFile, const nsACString& aOrigin
|
|||
// static
|
||||
already_AddRefed<mozIStorageConnection>
|
||||
IDBFactory::GetConnection(const nsAString& aDatabaseFilePath,
|
||||
PersistenceType aPersistenceType,
|
||||
const nsACString& aGroup,
|
||||
const nsACString& aOrigin)
|
||||
{
|
||||
NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
|
||||
|
@ -273,7 +307,8 @@ IDBFactory::GetConnection(const nsAString& aDatabaseFilePath,
|
|||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
NS_ENSURE_TRUE(exists, nullptr);
|
||||
|
||||
nsCOMPtr<nsIFileURL> dbFileUrl = GetDatabaseFileURL(dbFile, aOrigin);
|
||||
nsCOMPtr<nsIFileURL> dbFileUrl =
|
||||
GetDatabaseFileURL(dbFile, aPersistenceType, aGroup, aOrigin);
|
||||
NS_ENSURE_TRUE(dbFileUrl, nullptr);
|
||||
|
||||
nsCOMPtr<mozIStorageService> ss =
|
||||
|
@ -524,7 +559,10 @@ DOMCI_DATA(IDBFactory, IDBFactory)
|
|||
nsresult
|
||||
IDBFactory::OpenInternal(const nsAString& aName,
|
||||
int64_t aVersion,
|
||||
PersistenceType aPersistenceType,
|
||||
const nsACString& aGroup,
|
||||
const nsACString& aASCIIOrigin,
|
||||
StoragePrivilege aPrivilege,
|
||||
bool aDeleting,
|
||||
IDBOpenDBRequest** _retval)
|
||||
{
|
||||
|
@ -534,17 +572,19 @@ IDBFactory::OpenInternal(const nsAString& aName,
|
|||
AutoJSContext cx;
|
||||
nsCOMPtr<nsPIDOMWindow> window;
|
||||
JS::Rooted<JSObject*> scriptOwner(cx);
|
||||
StoragePrivilege privilege;
|
||||
|
||||
if (mWindow) {
|
||||
window = mWindow;
|
||||
scriptOwner =
|
||||
static_cast<nsGlobalWindow*>(window.get())->FastGetGlobalJSObject();
|
||||
privilege = Content;
|
||||
}
|
||||
else {
|
||||
scriptOwner = mOwningObject;
|
||||
privilege = Chrome;
|
||||
}
|
||||
|
||||
if (aPrivilege == Chrome) {
|
||||
// Chrome privilege, ignore the persistence type parameter.
|
||||
aPersistenceType = PERSISTENCE_TYPE_PERSISTENT;
|
||||
}
|
||||
|
||||
nsRefPtr<IDBOpenDBRequest> request =
|
||||
|
@ -555,40 +595,51 @@ IDBFactory::OpenInternal(const nsAString& aName,
|
|||
|
||||
if (IndexedDatabaseManager::IsMainProcess()) {
|
||||
nsRefPtr<OpenDatabaseHelper> openHelper =
|
||||
new OpenDatabaseHelper(request, aName, aASCIIOrigin, aVersion, aDeleting,
|
||||
mContentParent, privilege);
|
||||
new OpenDatabaseHelper(request, aName, aGroup, aASCIIOrigin, aVersion,
|
||||
aPersistenceType, aDeleting, mContentParent,
|
||||
aPrivilege);
|
||||
|
||||
rv = openHelper->Init();
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
nsRefPtr<CheckPermissionsHelper> permissionHelper =
|
||||
new CheckPermissionsHelper(openHelper, window, aDeleting);
|
||||
if (aPersistenceType == PERSISTENCE_TYPE_PERSISTENT) {
|
||||
nsRefPtr<CheckPermissionsHelper> permissionHelper =
|
||||
new CheckPermissionsHelper(openHelper, window);
|
||||
|
||||
QuotaManager* quotaManager = QuotaManager::Get();
|
||||
NS_ASSERTION(quotaManager, "This should never be null!");
|
||||
QuotaManager* quotaManager = QuotaManager::Get();
|
||||
NS_ASSERTION(quotaManager, "This should never be null!");
|
||||
|
||||
rv = quotaManager->WaitForOpenAllowed(OriginOrPatternString::FromOrigin(
|
||||
aASCIIOrigin), openHelper->Id(),
|
||||
permissionHelper);
|
||||
rv = quotaManager->
|
||||
WaitForOpenAllowed(OriginOrPatternString::FromOrigin(aASCIIOrigin),
|
||||
Nullable<PersistenceType>(aPersistenceType),
|
||||
openHelper->Id(), permissionHelper);
|
||||
}
|
||||
else {
|
||||
NS_ASSERTION(aPersistenceType == PERSISTENCE_TYPE_TEMPORARY, "Huh?");
|
||||
|
||||
rv = openHelper->WaitForOpenAllowed();
|
||||
}
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
}
|
||||
else if (aDeleting) {
|
||||
nsCOMPtr<nsIAtom> databaseId =
|
||||
QuotaManager::GetStorageId(aASCIIOrigin, aName);
|
||||
QuotaManager::GetStorageId(aPersistenceType, aASCIIOrigin, aName);
|
||||
NS_ENSURE_TRUE(databaseId, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
IndexedDBDeleteDatabaseRequestChild* actor =
|
||||
new IndexedDBDeleteDatabaseRequestChild(this, request, databaseId);
|
||||
|
||||
mActorChild->SendPIndexedDBDeleteDatabaseRequestConstructor(
|
||||
actor,
|
||||
nsString(aName));
|
||||
actor,
|
||||
nsString(aName),
|
||||
aPersistenceType);
|
||||
}
|
||||
else {
|
||||
IndexedDBDatabaseChild* dbActor =
|
||||
static_cast<IndexedDBDatabaseChild*>(
|
||||
mActorChild->SendPIndexedDBDatabaseConstructor(nsString(aName),
|
||||
aVersion));
|
||||
aVersion,
|
||||
aPersistenceType));
|
||||
|
||||
dbActor->SetRequest(request);
|
||||
}
|
||||
|
@ -620,6 +671,22 @@ IDBFactory::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
|
|||
return IDBFactoryBinding::Wrap(aCx, aScope, this);
|
||||
}
|
||||
|
||||
already_AddRefed<IDBOpenDBRequest>
|
||||
IDBFactory::Open(const nsAString& aName, const IDBOpenDBOptions& aOptions,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
return Open(nullptr, aName, aOptions.mVersion, aOptions.mStorage, false, aRv);
|
||||
}
|
||||
|
||||
already_AddRefed<IDBOpenDBRequest>
|
||||
IDBFactory::DeleteDatabase(const nsAString& aName,
|
||||
const IDBOpenDBOptions& aOptions,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
return Open(nullptr, aName, Optional<uint64_t>(), aOptions.mStorage, true,
|
||||
aRv);
|
||||
}
|
||||
|
||||
int16_t
|
||||
IDBFactory::Cmp(JSContext* aCx, JS::Handle<JS::Value> aFirst,
|
||||
JS::Handle<JS::Value> aSecond, ErrorResult& aRv)
|
||||
|
@ -646,22 +713,34 @@ IDBFactory::Cmp(JSContext* aCx, JS::Handle<JS::Value> aFirst,
|
|||
}
|
||||
|
||||
already_AddRefed<IDBOpenDBRequest>
|
||||
IDBFactory::OpenForPrincipal(nsIPrincipal* aPrincipal,
|
||||
const nsAString& aName,
|
||||
const Optional<uint64_t>& aVersion,
|
||||
ErrorResult& aRv)
|
||||
IDBFactory::OpenForPrincipal(nsIPrincipal* aPrincipal, const nsAString& aName,
|
||||
uint64_t aVersion, ErrorResult& aRv)
|
||||
{
|
||||
// Just to be on the extra-safe side
|
||||
if (!nsContentUtils::IsCallerChrome()) {
|
||||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
return Open(aPrincipal, aName, aVersion, false, aRv);
|
||||
return Open(aPrincipal, aName, Optional<uint64_t>(aVersion),
|
||||
Optional<mozilla::dom::StorageType>(), false, aRv);
|
||||
}
|
||||
|
||||
already_AddRefed<IDBOpenDBRequest>
|
||||
IDBFactory::DeleteForPrincipal(nsIPrincipal* aPrincipal,
|
||||
const nsAString& aName,
|
||||
IDBFactory::OpenForPrincipal(nsIPrincipal* aPrincipal, const nsAString& aName,
|
||||
const IDBOpenDBOptions& aOptions, ErrorResult& aRv)
|
||||
{
|
||||
// Just to be on the extra-safe side
|
||||
if (!nsContentUtils::IsCallerChrome()) {
|
||||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
return Open(aPrincipal, aName, aOptions.mVersion, aOptions.mStorage, false,
|
||||
aRv);
|
||||
}
|
||||
|
||||
already_AddRefed<IDBOpenDBRequest>
|
||||
IDBFactory::DeleteForPrincipal(nsIPrincipal* aPrincipal, const nsAString& aName,
|
||||
const IDBOpenDBOptions& aOptions,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
// Just to be on the extra-safe side
|
||||
|
@ -669,43 +748,53 @@ IDBFactory::DeleteForPrincipal(nsIPrincipal* aPrincipal,
|
|||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
return Open(aPrincipal, aName, Optional<uint64_t>(), true, aRv);
|
||||
return Open(aPrincipal, aName, Optional<uint64_t>(), aOptions.mStorage, true,
|
||||
aRv);
|
||||
}
|
||||
|
||||
already_AddRefed<IDBOpenDBRequest>
|
||||
IDBFactory::Open(nsIPrincipal* aPrincipal,
|
||||
const nsAString& aName, const Optional<uint64_t>& aVersion,
|
||||
IDBFactory::Open(nsIPrincipal* aPrincipal, const nsAString& aName,
|
||||
const Optional<uint64_t>& aVersion,
|
||||
const Optional<mozilla::dom::StorageType>& aStorageType,
|
||||
bool aDelete, ErrorResult& aRv)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsCString group;
|
||||
nsCString origin;
|
||||
StoragePrivilege privilege;
|
||||
PersistenceType defaultPersistenceType;
|
||||
if (aPrincipal) {
|
||||
rv = QuotaManager::GetASCIIOriginFromPrincipal(aPrincipal, origin);
|
||||
rv = QuotaManager::GetInfoFromPrincipal(aPrincipal, &group, &origin,
|
||||
&privilege,
|
||||
&defaultPersistenceType);
|
||||
if (NS_FAILED(rv)) {
|
||||
aRv.Throw(rv);
|
||||
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
else {
|
||||
group = mGroup;
|
||||
origin = mASCIIOrigin;
|
||||
privilege = mPrivilege;
|
||||
defaultPersistenceType = mDefaultPersistenceType;
|
||||
}
|
||||
|
||||
uint64_t version;
|
||||
uint64_t version = 0;
|
||||
if (!aDelete && aVersion.WasPassed()) {
|
||||
version = aVersion.Value();
|
||||
if (version < 1) {
|
||||
if (aVersion.Value() < 1) {
|
||||
aRv.ThrowTypeError(MSG_INVALID_VERSION);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
else {
|
||||
version = 0;
|
||||
version = aVersion.Value();
|
||||
}
|
||||
|
||||
PersistenceType persistenceType =
|
||||
PersistenceTypeFromStorage(aStorageType, defaultPersistenceType);
|
||||
|
||||
nsRefPtr<IDBOpenDBRequest> request;
|
||||
rv = OpenInternal(aName, version, origin, aDelete,
|
||||
getter_AddRefs(request));
|
||||
rv = OpenInternal(aName, version, persistenceType, group, origin, privilege,
|
||||
aDelete, getter_AddRefs(request));
|
||||
if (NS_FAILED(rv)) {
|
||||
aRv.Throw(rv);
|
||||
return nullptr;
|
||||
|
|
|
@ -8,6 +8,9 @@
|
|||
#define mozilla_dom_indexeddb_idbfactory_h__
|
||||
|
||||
#include "mozilla/dom/BindingDeclarations.h" // for Optional
|
||||
#include "mozilla/dom/StorageTypeBinding.h"
|
||||
#include "mozilla/dom/quota/PersistenceType.h"
|
||||
#include "mozilla/dom/quota/StoragePrivilege.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsWrapperCache.h"
|
||||
|
@ -25,6 +28,7 @@ class ErrorResult;
|
|||
|
||||
namespace dom {
|
||||
class ContentParent;
|
||||
class IDBOpenDBOptions;
|
||||
|
||||
namespace indexedDB {
|
||||
|
||||
|
@ -40,7 +44,9 @@ class IDBFactory MOZ_FINAL : public nsISupports,
|
|||
public nsWrapperCache
|
||||
{
|
||||
typedef mozilla::dom::ContentParent ContentParent;
|
||||
typedef mozilla::dom::quota::PersistenceType PersistenceType;
|
||||
typedef nsTArray<nsRefPtr<ObjectStoreInfo> > ObjectStoreInfoArray;
|
||||
typedef mozilla::dom::quota::StoragePrivilege StoragePrivilege;
|
||||
|
||||
public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
|
@ -48,6 +54,7 @@ public:
|
|||
|
||||
// Called when using IndexedDB from a window in a different process.
|
||||
static nsresult Create(nsPIDOMWindow* aWindow,
|
||||
const nsACString& aGroup,
|
||||
const nsACString& aASCIIOrigin,
|
||||
ContentParent* aContentParent,
|
||||
IDBFactory** aFactory);
|
||||
|
@ -57,7 +64,8 @@ public:
|
|||
ContentParent* aContentParent,
|
||||
IDBFactory** aFactory)
|
||||
{
|
||||
return Create(aWindow, EmptyCString(), aContentParent, aFactory);
|
||||
return Create(aWindow, EmptyCString(), EmptyCString(), aContentParent,
|
||||
aFactory);
|
||||
}
|
||||
|
||||
// Called when using IndexedDB from a JS component or a JSM in the current
|
||||
|
@ -73,10 +81,15 @@ public:
|
|||
IDBFactory** aFactory);
|
||||
|
||||
static already_AddRefed<nsIFileURL>
|
||||
GetDatabaseFileURL(nsIFile* aDatabaseFile, const nsACString& aOrigin);
|
||||
GetDatabaseFileURL(nsIFile* aDatabaseFile,
|
||||
PersistenceType aPersistenceType,
|
||||
const nsACString& aGroup,
|
||||
const nsACString& aOrigin);
|
||||
|
||||
static already_AddRefed<mozIStorageConnection>
|
||||
GetConnection(const nsAString& aDatabaseFilePath,
|
||||
PersistenceType aPersistenceType,
|
||||
const nsACString& aGroup,
|
||||
const nsACString& aOrigin);
|
||||
|
||||
static nsresult
|
||||
|
@ -96,17 +109,22 @@ public:
|
|||
nsresult
|
||||
OpenInternal(const nsAString& aName,
|
||||
int64_t aVersion,
|
||||
PersistenceType aPersistenceType,
|
||||
const nsACString& aGroup,
|
||||
const nsACString& aASCIIOrigin,
|
||||
StoragePrivilege aStoragePrivilege,
|
||||
bool aDeleting,
|
||||
IDBOpenDBRequest** _retval);
|
||||
|
||||
nsresult
|
||||
OpenInternal(const nsAString& aName,
|
||||
int64_t aVersion,
|
||||
PersistenceType aPersistenceType,
|
||||
bool aDeleting,
|
||||
IDBOpenDBRequest** _retval)
|
||||
{
|
||||
return OpenInternal(aName, aVersion, mASCIIOrigin, aDeleting, _retval);
|
||||
return OpenInternal(aName, aVersion, aPersistenceType, mGroup, mASCIIOrigin,
|
||||
mPrivilege, aDeleting, _retval);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -129,28 +147,31 @@ public:
|
|||
return mASCIIOrigin;
|
||||
}
|
||||
|
||||
// WrapperCache
|
||||
nsPIDOMWindow* GetParentObject() const
|
||||
// nsWrapperCache
|
||||
virtual JSObject*
|
||||
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
|
||||
|
||||
// WebIDL
|
||||
nsPIDOMWindow*
|
||||
GetParentObject() const
|
||||
{
|
||||
return mWindow;
|
||||
}
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
|
||||
|
||||
// WebIDL
|
||||
already_AddRefed<IDBOpenDBRequest>
|
||||
Open(const nsAString& aName, const Optional<uint64_t>& aVersion,
|
||||
ErrorResult& aRv)
|
||||
Open(const nsAString& aName, uint64_t aVersion, ErrorResult& aRv)
|
||||
{
|
||||
return Open(nullptr, aName, aVersion, false, aRv);
|
||||
return Open(nullptr, aName, Optional<uint64_t>(aVersion),
|
||||
Optional<mozilla::dom::StorageType>(), false, aRv);
|
||||
}
|
||||
|
||||
already_AddRefed<IDBOpenDBRequest>
|
||||
DeleteDatabase(const nsAString& aName, ErrorResult& aRv)
|
||||
{
|
||||
return Open(nullptr, aName, Optional<uint64_t>(), true, aRv);
|
||||
}
|
||||
Open(const nsAString& aName, const IDBOpenDBOptions& aOptions,
|
||||
ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<IDBOpenDBRequest>
|
||||
DeleteDatabase(const nsAString& aName, const IDBOpenDBOptions& aOptions,
|
||||
ErrorResult& aRv);
|
||||
|
||||
int16_t
|
||||
Cmp(JSContext* aCx, JS::Handle<JS::Value> aFirst,
|
||||
|
@ -158,11 +179,15 @@ public:
|
|||
|
||||
already_AddRefed<IDBOpenDBRequest>
|
||||
OpenForPrincipal(nsIPrincipal* aPrincipal, const nsAString& aName,
|
||||
const Optional<uint64_t>& aVersion, ErrorResult& aRv);
|
||||
uint64_t aVersion, ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<IDBOpenDBRequest>
|
||||
OpenForPrincipal(nsIPrincipal* aPrincipal, const nsAString& aName,
|
||||
const IDBOpenDBOptions& aOptions, ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<IDBOpenDBRequest>
|
||||
DeleteForPrincipal(nsIPrincipal* aPrincipal, const nsAString& aName,
|
||||
ErrorResult& aRv);
|
||||
const IDBOpenDBOptions& aOptions, ErrorResult& aRv);
|
||||
|
||||
private:
|
||||
IDBFactory();
|
||||
|
@ -170,9 +195,14 @@ private:
|
|||
|
||||
already_AddRefed<IDBOpenDBRequest>
|
||||
Open(nsIPrincipal* aPrincipal, const nsAString& aName,
|
||||
const Optional<uint64_t>& aVersion, bool aDelete, ErrorResult& aRv);
|
||||
const Optional<uint64_t>& aVersion,
|
||||
const Optional<mozilla::dom::StorageType>& aStorageType, bool aDelete,
|
||||
ErrorResult& aRv);
|
||||
|
||||
nsCString mGroup;
|
||||
nsCString mASCIIOrigin;
|
||||
StoragePrivilege mPrivilege;
|
||||
PersistenceType mDefaultPersistenceType;
|
||||
|
||||
// If this factory lives on a window then mWindow must be non-null. Otherwise
|
||||
// mOwningObject must be non-null.
|
||||
|
|
|
@ -77,18 +77,22 @@ IDBFileHandle::CreateStream(nsIFile* aFile, bool aReadOnly)
|
|||
nsCOMPtr<nsIOfflineStorage> storage = do_QueryInterface(mFileStorage);
|
||||
NS_ASSERTION(storage, "This should always succeed!");
|
||||
|
||||
PersistenceType persistenceType = storage->Type();
|
||||
const nsACString& group = storage->Group();
|
||||
const nsACString& origin = storage->Origin();
|
||||
|
||||
nsCOMPtr<nsISupports> result;
|
||||
|
||||
if (aReadOnly) {
|
||||
nsRefPtr<FileInputStream> stream = FileInputStream::Create(
|
||||
origin, aFile, -1, -1, nsIFileInputStream::DEFER_OPEN);
|
||||
nsRefPtr<FileInputStream> stream =
|
||||
FileInputStream::Create(persistenceType, group, origin, aFile, -1, -1,
|
||||
nsIFileInputStream::DEFER_OPEN);
|
||||
result = NS_ISUPPORTS_CAST(nsIFileInputStream*, stream);
|
||||
}
|
||||
else {
|
||||
nsRefPtr<FileStream> stream = FileStream::Create(
|
||||
origin, aFile, -1, -1, nsIFileStream::DEFER_OPEN);
|
||||
nsRefPtr<FileStream> stream =
|
||||
FileStream::Create(persistenceType, group, origin, aFile, -1, -1,
|
||||
nsIFileStream::DEFER_OPEN);
|
||||
result = NS_ISUPPORTS_CAST(nsIFileStream*, stream);
|
||||
}
|
||||
NS_ENSURE_TRUE(result, nullptr);
|
||||
|
|
|
@ -3015,8 +3015,10 @@ AddHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
|
|||
nativeFile = fileManager->GetFileForId(directory, id);
|
||||
NS_ENSURE_TRUE(nativeFile, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
nsRefPtr<FileOutputStream> outputStream = FileOutputStream::Create(
|
||||
mObjectStore->Transaction()->Database()->Origin(), nativeFile);
|
||||
IDBDatabase* database = mObjectStore->Transaction()->Database();
|
||||
nsRefPtr<FileOutputStream> outputStream =
|
||||
FileOutputStream::Create(database->Type(), database->Group(),
|
||||
database->Origin(), nativeFile);
|
||||
NS_ENSURE_TRUE(outputStream, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
rv = CopyData(inputStream, outputStream);
|
||||
|
|
|
@ -361,8 +361,8 @@ IDBTransaction::GetOrCreateConnection(mozIStorageConnection** aResult)
|
|||
|
||||
if (!mConnection) {
|
||||
nsCOMPtr<mozIStorageConnection> connection =
|
||||
IDBFactory::GetConnection(mDatabase->FilePath(),
|
||||
mDatabase->Origin());
|
||||
IDBFactory::GetConnection(mDatabase->FilePath(), mDatabase->Type(),
|
||||
mDatabase->Group(), mDatabase->Origin());
|
||||
NS_ENSURE_TRUE(connection, NS_ERROR_FAILURE);
|
||||
|
||||
nsresult rv;
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
#include "mozilla/CondVar.h"
|
||||
#include "mozilla/dom/quota/OriginOrPatternString.h"
|
||||
#include "mozilla/dom/quota/QuotaManager.h"
|
||||
#include "mozilla/dom/quota/Utilities.h"
|
||||
#include "mozilla/dom/TabContext.h"
|
||||
|
@ -41,6 +42,53 @@ USING_QUOTA_NAMESPACE
|
|||
|
||||
static NS_DEFINE_CID(kDOMSOF_CID, NS_DOM_SCRIPT_OBJECT_FACTORY_CID);
|
||||
|
||||
BEGIN_INDEXEDDB_NAMESPACE
|
||||
|
||||
class FileManagerInfo
|
||||
{
|
||||
public:
|
||||
already_AddRefed<FileManager>
|
||||
GetFileManager(PersistenceType aPersistenceType,
|
||||
const nsAString& aName) const;
|
||||
|
||||
void
|
||||
AddFileManager(FileManager* aFileManager);
|
||||
|
||||
bool
|
||||
HasFileManagers() const
|
||||
{
|
||||
AssertIsOnIOThread();
|
||||
|
||||
return !mPersistentStorageFileManagers.IsEmpty() ||
|
||||
!mTemporaryStorageFileManagers.IsEmpty();
|
||||
}
|
||||
|
||||
void
|
||||
InvalidateAllFileManagers() const;
|
||||
|
||||
void
|
||||
InvalidateAndRemoveFileManagers(PersistenceType aPersistenceType);
|
||||
|
||||
void
|
||||
InvalidateAndRemoveFileManager(PersistenceType aPersistenceType,
|
||||
const nsAString& aName);
|
||||
|
||||
private:
|
||||
nsTArray<nsRefPtr<FileManager> >&
|
||||
GetArray(PersistenceType aPersistenceType);
|
||||
|
||||
const nsTArray<nsRefPtr<FileManager> >&
|
||||
GetImmutableArray(PersistenceType aPersistenceType) const
|
||||
{
|
||||
return const_cast<FileManagerInfo*>(this)->GetArray(aPersistenceType);
|
||||
}
|
||||
|
||||
nsTArray<nsRefPtr<FileManager> > mPersistentStorageFileManagers;
|
||||
nsTArray<nsRefPtr<FileManager> > mTemporaryStorageFileManagers;
|
||||
};
|
||||
|
||||
END_INDEXEDDB_NAMESPACE
|
||||
|
||||
namespace {
|
||||
|
||||
mozilla::StaticRefPtr<IndexedDatabaseManager> gInstance;
|
||||
|
@ -67,10 +115,14 @@ public:
|
|||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIRUNNABLE
|
||||
|
||||
GetFileReferencesHelper(const nsACString& aOrigin,
|
||||
GetFileReferencesHelper(PersistenceType aPersistenceType,
|
||||
const nsACString& aOrigin,
|
||||
const nsAString& aDatabaseName,
|
||||
int64_t aFileId)
|
||||
: mOrigin(aOrigin), mDatabaseName(aDatabaseName), mFileId(aFileId),
|
||||
: mPersistenceType(aPersistenceType),
|
||||
mOrigin(aOrigin),
|
||||
mDatabaseName(aDatabaseName),
|
||||
mFileId(aFileId),
|
||||
mMutex(IndexedDatabaseManager::FileMutex()),
|
||||
mCondVar(mMutex, "GetFileReferencesHelper::mCondVar"),
|
||||
mMemRefCnt(-1),
|
||||
|
@ -87,6 +139,7 @@ public:
|
|||
bool* aResult);
|
||||
|
||||
private:
|
||||
PersistenceType mPersistenceType;
|
||||
nsCString mOrigin;
|
||||
nsString mDatabaseName;
|
||||
int64_t mFileId;
|
||||
|
@ -100,29 +153,15 @@ private:
|
|||
bool mWaiting;
|
||||
};
|
||||
|
||||
PLDHashOperator
|
||||
InvalidateAndRemoveFileManagers(
|
||||
const nsACString& aKey,
|
||||
nsAutoPtr<nsTArray<nsRefPtr<FileManager> > >& aValue,
|
||||
void* aUserArg)
|
||||
struct MOZ_STACK_CLASS InvalidateInfo
|
||||
{
|
||||
AssertIsOnIOThread();
|
||||
NS_ASSERTION(!aKey.IsEmpty(), "Empty key!");
|
||||
NS_ASSERTION(aValue, "Null pointer!");
|
||||
InvalidateInfo(PersistenceType aPersistenceType, const nsACString& aPattern)
|
||||
: persistenceType(aPersistenceType), pattern(aPattern)
|
||||
{ }
|
||||
|
||||
const nsACString* pattern =
|
||||
static_cast<const nsACString*>(aUserArg);
|
||||
|
||||
if (!pattern || PatternMatchesOrigin(*pattern, aKey)) {
|
||||
for (uint32_t i = 0; i < aValue->Length(); i++) {
|
||||
nsRefPtr<FileManager>& fileManager = aValue->ElementAt(i);
|
||||
fileManager->Invalidate();
|
||||
}
|
||||
return PL_DHASH_REMOVE;
|
||||
}
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
PersistenceType persistenceType;
|
||||
const nsACString& pattern;
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
|
@ -381,26 +420,21 @@ IndexedDatabaseManager::InLowDiskSpaceMode()
|
|||
#endif
|
||||
|
||||
already_AddRefed<FileManager>
|
||||
IndexedDatabaseManager::GetFileManager(const nsACString& aOrigin,
|
||||
IndexedDatabaseManager::GetFileManager(PersistenceType aPersistenceType,
|
||||
const nsACString& aOrigin,
|
||||
const nsAString& aDatabaseName)
|
||||
{
|
||||
AssertIsOnIOThread();
|
||||
|
||||
nsTArray<nsRefPtr<FileManager> >* array;
|
||||
if (!mFileManagers.Get(aOrigin, &array)) {
|
||||
FileManagerInfo* info;
|
||||
if (!mFileManagerInfos.Get(aOrigin, &info)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < array->Length(); i++) {
|
||||
nsRefPtr<FileManager>& fileManager = array->ElementAt(i);
|
||||
nsRefPtr<FileManager> fileManager =
|
||||
info->GetFileManager(aPersistenceType, aDatabaseName);
|
||||
|
||||
if (fileManager->DatabaseName().Equals(aDatabaseName)) {
|
||||
nsRefPtr<FileManager> result = fileManager;
|
||||
return result.forget();
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
return fileManager.forget();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -409,13 +443,42 @@ IndexedDatabaseManager::AddFileManager(FileManager* aFileManager)
|
|||
AssertIsOnIOThread();
|
||||
NS_ASSERTION(aFileManager, "Null file manager!");
|
||||
|
||||
nsTArray<nsRefPtr<FileManager> >* array;
|
||||
if (!mFileManagers.Get(aFileManager->Origin(), &array)) {
|
||||
array = new nsTArray<nsRefPtr<FileManager> >();
|
||||
mFileManagers.Put(aFileManager->Origin(), array);
|
||||
FileManagerInfo* info;
|
||||
if (!mFileManagerInfos.Get(aFileManager->Origin(), &info)) {
|
||||
info = new FileManagerInfo();
|
||||
mFileManagerInfos.Put(aFileManager->Origin(), info);
|
||||
}
|
||||
|
||||
array->AppendElement(aFileManager);
|
||||
info->AddFileManager(aFileManager);
|
||||
}
|
||||
|
||||
// static
|
||||
PLDHashOperator
|
||||
IndexedDatabaseManager::InvalidateAndRemoveFileManagers(
|
||||
const nsACString& aKey,
|
||||
nsAutoPtr<FileManagerInfo>& aValue,
|
||||
void* aUserArg)
|
||||
{
|
||||
AssertIsOnIOThread();
|
||||
NS_ASSERTION(!aKey.IsEmpty(), "Empty key!");
|
||||
NS_ASSERTION(aValue, "Null pointer!");
|
||||
|
||||
if (!aUserArg) {
|
||||
aValue->InvalidateAllFileManagers();
|
||||
return PL_DHASH_REMOVE;
|
||||
}
|
||||
|
||||
InvalidateInfo* info = static_cast<InvalidateInfo*>(aUserArg);
|
||||
|
||||
if (PatternMatchesOrigin(info->pattern, aKey)) {
|
||||
aValue->InvalidateAndRemoveFileManagers(info->persistenceType);
|
||||
|
||||
if (!aValue->HasFileManagers()) {
|
||||
return PL_DHASH_REMOVE;
|
||||
}
|
||||
}
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -423,43 +486,51 @@ IndexedDatabaseManager::InvalidateAllFileManagers()
|
|||
{
|
||||
AssertIsOnIOThread();
|
||||
|
||||
mFileManagers.Enumerate(InvalidateAndRemoveFileManagers, nullptr);
|
||||
mFileManagerInfos.Enumerate(InvalidateAndRemoveFileManagers, nullptr);
|
||||
}
|
||||
|
||||
void
|
||||
IndexedDatabaseManager::InvalidateFileManagersForPattern(
|
||||
const nsACString& aPattern)
|
||||
IndexedDatabaseManager::InvalidateFileManagers(
|
||||
PersistenceType aPersistenceType,
|
||||
const OriginOrPatternString& aOriginOrPattern)
|
||||
{
|
||||
AssertIsOnIOThread();
|
||||
NS_ASSERTION(!aPattern.IsEmpty(), "Empty pattern!");
|
||||
NS_ASSERTION(!aOriginOrPattern.IsEmpty(), "Empty pattern!");
|
||||
|
||||
mFileManagers.Enumerate(InvalidateAndRemoveFileManagers,
|
||||
const_cast<nsACString*>(&aPattern));
|
||||
if (aOriginOrPattern.IsOrigin()) {
|
||||
FileManagerInfo* info;
|
||||
if (!mFileManagerInfos.Get(aOriginOrPattern, &info)) {
|
||||
return;
|
||||
}
|
||||
|
||||
info->InvalidateAndRemoveFileManagers(aPersistenceType);
|
||||
|
||||
if (!info->HasFileManagers()) {
|
||||
mFileManagerInfos.Remove(aOriginOrPattern);
|
||||
}
|
||||
}
|
||||
else {
|
||||
InvalidateInfo info(aPersistenceType, aOriginOrPattern);
|
||||
mFileManagerInfos.Enumerate(InvalidateAndRemoveFileManagers, &info);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
IndexedDatabaseManager::InvalidateFileManager(const nsACString& aOrigin,
|
||||
IndexedDatabaseManager::InvalidateFileManager(PersistenceType aPersistenceType,
|
||||
const nsACString& aOrigin,
|
||||
const nsAString& aDatabaseName)
|
||||
{
|
||||
AssertIsOnIOThread();
|
||||
|
||||
nsTArray<nsRefPtr<FileManager> >* array;
|
||||
if (!mFileManagers.Get(aOrigin, &array)) {
|
||||
FileManagerInfo* info;
|
||||
if (!mFileManagerInfos.Get(aOrigin, &info)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < array->Length(); i++) {
|
||||
nsRefPtr<FileManager> fileManager = array->ElementAt(i);
|
||||
if (fileManager->DatabaseName().Equals(aDatabaseName)) {
|
||||
fileManager->Invalidate();
|
||||
array->RemoveElementAt(i);
|
||||
info->InvalidateAndRemoveFileManager(aPersistenceType, aDatabaseName);
|
||||
|
||||
if (array->IsEmpty()) {
|
||||
mFileManagers.Remove(aOrigin);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
if (!info->HasFileManagers()) {
|
||||
mFileManagerInfos.Remove(aOrigin);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -492,16 +563,18 @@ IndexedDatabaseManager::AsyncDeleteFile(FileManager* aFileManager,
|
|||
|
||||
nsresult
|
||||
IndexedDatabaseManager::BlockAndGetFileReferences(
|
||||
const nsACString& aOrigin,
|
||||
const nsAString& aDatabaseName,
|
||||
int64_t aFileId,
|
||||
int32_t* aRefCnt,
|
||||
int32_t* aDBRefCnt,
|
||||
int32_t* aSliceRefCnt,
|
||||
bool* aResult)
|
||||
PersistenceType aPersistenceType,
|
||||
const nsACString& aOrigin,
|
||||
const nsAString& aDatabaseName,
|
||||
int64_t aFileId,
|
||||
int32_t* aRefCnt,
|
||||
int32_t* aDBRefCnt,
|
||||
int32_t* aSliceRefCnt,
|
||||
bool* aResult)
|
||||
{
|
||||
nsRefPtr<GetFileReferencesHelper> helper =
|
||||
new GetFileReferencesHelper(aOrigin, aDatabaseName, aFileId);
|
||||
new GetFileReferencesHelper(aPersistenceType, aOrigin, aDatabaseName,
|
||||
aFileId);
|
||||
|
||||
nsresult rv = helper->DispatchAndReturnFileReferences(aRefCnt, aDBRefCnt,
|
||||
aSliceRefCnt, aResult);
|
||||
|
@ -602,6 +675,105 @@ IndexedDatabaseManager::Observe(nsISupports* aSubject, const char* aTopic,
|
|||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
already_AddRefed<FileManager>
|
||||
FileManagerInfo::GetFileManager(PersistenceType aPersistenceType,
|
||||
const nsAString& aName) const
|
||||
{
|
||||
AssertIsOnIOThread();
|
||||
|
||||
const nsTArray<nsRefPtr<FileManager> >& managers =
|
||||
GetImmutableArray(aPersistenceType);
|
||||
|
||||
for (uint32_t i = 0; i < managers.Length(); i++) {
|
||||
const nsRefPtr<FileManager>& fileManager = managers[i];
|
||||
|
||||
if (fileManager->DatabaseName() == aName) {
|
||||
nsRefPtr<FileManager> result = fileManager;
|
||||
return result.forget();
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
FileManagerInfo::AddFileManager(FileManager* aFileManager)
|
||||
{
|
||||
AssertIsOnIOThread();
|
||||
|
||||
nsTArray<nsRefPtr<FileManager> >& managers = GetArray(aFileManager->Type());
|
||||
|
||||
NS_ASSERTION(!managers.Contains(aFileManager), "Adding more than once?!");
|
||||
|
||||
managers.AppendElement(aFileManager);
|
||||
}
|
||||
|
||||
void
|
||||
FileManagerInfo::InvalidateAllFileManagers() const
|
||||
{
|
||||
AssertIsOnIOThread();
|
||||
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0; i < mPersistentStorageFileManagers.Length(); i++) {
|
||||
mPersistentStorageFileManagers[i]->Invalidate();
|
||||
}
|
||||
|
||||
for (i = 0; i < mTemporaryStorageFileManagers.Length(); i++) {
|
||||
mTemporaryStorageFileManagers[i]->Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FileManagerInfo::InvalidateAndRemoveFileManagers(
|
||||
PersistenceType aPersistenceType)
|
||||
{
|
||||
AssertIsOnIOThread();
|
||||
|
||||
nsTArray<nsRefPtr<FileManager > >& managers = GetArray(aPersistenceType);
|
||||
|
||||
for (uint32_t i = 0; i < managers.Length(); i++) {
|
||||
managers[i]->Invalidate();
|
||||
}
|
||||
|
||||
managers.Clear();
|
||||
}
|
||||
|
||||
void
|
||||
FileManagerInfo::InvalidateAndRemoveFileManager(
|
||||
PersistenceType aPersistenceType,
|
||||
const nsAString& aName)
|
||||
{
|
||||
AssertIsOnIOThread();
|
||||
|
||||
nsTArray<nsRefPtr<FileManager > >& managers = GetArray(aPersistenceType);
|
||||
|
||||
for (uint32_t i = 0; i < managers.Length(); i++) {
|
||||
nsRefPtr<FileManager>& fileManager = managers[i];
|
||||
if (fileManager->DatabaseName() == aName) {
|
||||
fileManager->Invalidate();
|
||||
managers.RemoveElementAt(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsTArray<nsRefPtr<FileManager> >&
|
||||
FileManagerInfo::GetArray(PersistenceType aPersistenceType)
|
||||
{
|
||||
switch (aPersistenceType) {
|
||||
case PERSISTENCE_TYPE_PERSISTENT:
|
||||
return mPersistentStorageFileManagers;
|
||||
case PERSISTENCE_TYPE_TEMPORARY:
|
||||
return mTemporaryStorageFileManagers;
|
||||
|
||||
case PERSISTENCE_TYPE_INVALID:
|
||||
default:
|
||||
MOZ_CRASH("Bad storage type value!");
|
||||
return mPersistentStorageFileManagers;
|
||||
}
|
||||
}
|
||||
|
||||
AsyncDeleteFileRunnable::AsyncDeleteFileRunnable(FileManager* aFileManager,
|
||||
int64_t aFileId)
|
||||
: mFileManager(aFileManager), mFileId(aFileId)
|
||||
|
@ -637,7 +809,9 @@ AsyncDeleteFileRunnable::Run()
|
|||
QuotaManager* quotaManager = QuotaManager::Get();
|
||||
NS_ASSERTION(quotaManager, "Shouldn't be null!");
|
||||
|
||||
quotaManager->DecreaseUsageForOrigin(mFileManager->Origin(), fileSize);
|
||||
quotaManager->DecreaseUsageForOrigin(mFileManager->Type(),
|
||||
mFileManager->Group(),
|
||||
mFileManager->Origin(), fileSize);
|
||||
}
|
||||
|
||||
directory = mFileManager->GetJournalDirectory();
|
||||
|
@ -692,7 +866,7 @@ GetFileReferencesHelper::Run()
|
|||
NS_ASSERTION(mgr, "This should never fail!");
|
||||
|
||||
nsRefPtr<FileManager> fileManager =
|
||||
mgr->GetFileManager(mOrigin, mDatabaseName);
|
||||
mgr->GetFileManager(mPersistenceType, mOrigin, mDatabaseName);
|
||||
|
||||
if (fileManager) {
|
||||
nsRefPtr<FileInfo> fileInfo = fileManager->GetFileInfo(mFileId);
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "nsIObserver.h"
|
||||
|
||||
#include "mozilla/Atomics.h"
|
||||
#include "mozilla/dom/quota/PersistenceType.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "nsClassHashtable.h"
|
||||
#include "nsHashKeys.h"
|
||||
|
@ -26,16 +27,23 @@ class nsEventChainPostVisitor;
|
|||
namespace mozilla {
|
||||
namespace dom {
|
||||
class TabContext;
|
||||
namespace quota {
|
||||
class OriginOrPatternString;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BEGIN_INDEXEDDB_NAMESPACE
|
||||
|
||||
class FileManager;
|
||||
class FileManagerInfo;
|
||||
|
||||
class IndexedDatabaseManager MOZ_FINAL : public nsIIndexedDatabaseManager,
|
||||
public nsIObserver
|
||||
{
|
||||
typedef mozilla::dom::quota::OriginOrPatternString OriginOrPatternString;
|
||||
typedef mozilla::dom::quota::PersistenceType PersistenceType;
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIINDEXEDDATABASEMANAGER
|
||||
|
@ -77,7 +85,8 @@ public:
|
|||
#endif
|
||||
|
||||
already_AddRefed<FileManager>
|
||||
GetFileManager(const nsACString& aOrigin,
|
||||
GetFileManager(PersistenceType aPersistenceType,
|
||||
const nsACString& aOrigin,
|
||||
const nsAString& aDatabaseName);
|
||||
|
||||
void
|
||||
|
@ -87,10 +96,12 @@ public:
|
|||
InvalidateAllFileManagers();
|
||||
|
||||
void
|
||||
InvalidateFileManagersForPattern(const nsACString& aPattern);
|
||||
InvalidateFileManagers(PersistenceType aPersistenceType,
|
||||
const OriginOrPatternString& aOriginOrPattern);
|
||||
|
||||
void
|
||||
InvalidateFileManager(const nsACString& aOrigin,
|
||||
InvalidateFileManager(PersistenceType aPersistenceType,
|
||||
const nsACString& aOrigin,
|
||||
const nsAString& aDatabaseName);
|
||||
|
||||
nsresult
|
||||
|
@ -101,7 +112,8 @@ public:
|
|||
// It is intended to be used by mochitests to test correctness of the special
|
||||
// reference counting of stored blobs/files.
|
||||
nsresult
|
||||
BlockAndGetFileReferences(const nsACString& aOrigin,
|
||||
BlockAndGetFileReferences(PersistenceType aPersistenceType,
|
||||
const nsACString& aOrigin,
|
||||
const nsAString& aDatabaseName,
|
||||
int64_t aFileId,
|
||||
int32_t* aRefCnt,
|
||||
|
@ -136,10 +148,14 @@ private:
|
|||
void
|
||||
Destroy();
|
||||
|
||||
static PLDHashOperator
|
||||
InvalidateAndRemoveFileManagers(const nsACString& aKey,
|
||||
nsAutoPtr<FileManagerInfo>& aValue,
|
||||
void* aUserArg);
|
||||
|
||||
// Maintains a list of all file managers per origin. This list isn't
|
||||
// protected by any mutex but it is only ever touched on the IO thread.
|
||||
nsClassHashtable<nsCStringHashKey,
|
||||
nsTArray<nsRefPtr<FileManager> > > mFileManagers;
|
||||
nsClassHashtable<nsCStringHashKey, FileManagerInfo> mFileManagerInfos;
|
||||
|
||||
// Lock protecting FileManager.mFileInfos and nsDOMFileBase.mFileInfos
|
||||
// It's s also used to atomically update FileInfo.mRefCnt, FileInfo.mDBRefCnt
|
||||
|
|
|
@ -1504,11 +1504,14 @@ public:
|
|||
OpenDatabaseHelper* aHelper,
|
||||
uint64_t aCurrentVersion,
|
||||
const nsAString& aName,
|
||||
const nsACString& aASCIIOrigin)
|
||||
const nsACString& aGroup,
|
||||
const nsACString& aASCIIOrigin,
|
||||
PersistenceType aPersistenceType)
|
||||
: AsyncConnectionHelper(static_cast<IDBDatabase*>(nullptr), aRequest),
|
||||
mOpenHelper(aHelper), mOpenRequest(aRequest),
|
||||
mCurrentVersion(aCurrentVersion), mName(aName),
|
||||
mASCIIOrigin(aASCIIOrigin)
|
||||
mGroup(aGroup), mASCIIOrigin(aASCIIOrigin),
|
||||
mPersistenceType(aPersistenceType)
|
||||
{ }
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
@ -1567,7 +1570,9 @@ private:
|
|||
nsRefPtr<IDBOpenDBRequest> mOpenRequest;
|
||||
uint64_t mCurrentVersion;
|
||||
nsString mName;
|
||||
nsCString mGroup;
|
||||
nsCString mASCIIOrigin;
|
||||
PersistenceType mPersistenceType;
|
||||
};
|
||||
|
||||
// Responsible for firing "versionchange" events at all live and non-closed
|
||||
|
@ -1685,21 +1690,50 @@ NS_IMPL_ISUPPORTS1(OpenDatabaseHelper, nsIRunnable)
|
|||
nsresult
|
||||
OpenDatabaseHelper::Init()
|
||||
{
|
||||
mDatabaseId = QuotaManager::GetStorageId(mASCIIOrigin, mName);
|
||||
mDatabaseId =
|
||||
QuotaManager::GetStorageId(mPersistenceType, mASCIIOrigin, mName);
|
||||
NS_ENSURE_TRUE(mDatabaseId, NS_ERROR_FAILURE);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
OpenDatabaseHelper::Dispatch(nsIEventTarget* aTarget)
|
||||
OpenDatabaseHelper::WaitForOpenAllowed()
|
||||
{
|
||||
NS_ASSERTION(mState == eCreated, "We've already been dispatched?");
|
||||
NS_ASSERTION(NS_IsMainThread(), "All hell is about to break lose!");
|
||||
|
||||
mState = eOpenPending;
|
||||
|
||||
QuotaManager* quotaManager = QuotaManager::Get();
|
||||
NS_ASSERTION(quotaManager, "This should never be null!");
|
||||
|
||||
return quotaManager->
|
||||
WaitForOpenAllowed(OriginOrPatternString::FromOrigin(mASCIIOrigin),
|
||||
Nullable<PersistenceType>(mPersistenceType), mDatabaseId,
|
||||
this);
|
||||
}
|
||||
|
||||
nsresult
|
||||
OpenDatabaseHelper::Dispatch(nsIEventTarget* aTarget)
|
||||
{
|
||||
NS_ASSERTION(mState == eCreated || mState == eOpenPending,
|
||||
"We've already been dispatched?");
|
||||
|
||||
mState = eDBWork;
|
||||
|
||||
return aTarget->Dispatch(this, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
nsresult
|
||||
OpenDatabaseHelper::DispatchToIOThread()
|
||||
{
|
||||
QuotaManager* quotaManager = QuotaManager::Get();
|
||||
NS_ASSERTION(quotaManager, "This should never be null!");
|
||||
|
||||
return Dispatch(quotaManager->IOThread());
|
||||
}
|
||||
|
||||
nsresult
|
||||
OpenDatabaseHelper::RunImmediately()
|
||||
{
|
||||
|
@ -1709,6 +1743,7 @@ OpenDatabaseHelper::RunImmediately()
|
|||
NS_ASSERTION(NS_IsMainThread(), "All hell is about to break lose!");
|
||||
|
||||
mState = eFiringEvents;
|
||||
|
||||
return this->Run();
|
||||
}
|
||||
|
||||
|
@ -1739,8 +1774,8 @@ OpenDatabaseHelper::DoDatabaseWork()
|
|||
NS_ASSERTION(quotaManager, "This should never be null!");
|
||||
|
||||
nsresult rv =
|
||||
quotaManager->EnsureOriginIsInitialized(mASCIIOrigin,
|
||||
mTrackingQuota,
|
||||
quotaManager->EnsureOriginIsInitialized(mPersistenceType, mGroup,
|
||||
mASCIIOrigin, mTrackingQuota,
|
||||
getter_AddRefs(dbDirectory));
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
|
@ -1785,7 +1820,8 @@ OpenDatabaseHelper::DoDatabaseWork()
|
|||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
nsCOMPtr<mozIStorageConnection> connection;
|
||||
rv = CreateDatabaseConnection(dbFile, fmDirectory, mName, mASCIIOrigin,
|
||||
rv = CreateDatabaseConnection(dbFile, fmDirectory, mName, mPersistenceType,
|
||||
mGroup, mASCIIOrigin,
|
||||
getter_AddRefs(connection));
|
||||
if (NS_FAILED(rv) &&
|
||||
NS_ERROR_GET_MODULE(rv) != NS_ERROR_MODULE_DOM_INDEXEDDB) {
|
||||
|
@ -1837,9 +1873,11 @@ OpenDatabaseHelper::DoDatabaseWork()
|
|||
IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
|
||||
NS_ASSERTION(mgr, "This should never be null!");
|
||||
|
||||
nsRefPtr<FileManager> fileManager = mgr->GetFileManager(mASCIIOrigin, mName);
|
||||
nsRefPtr<FileManager> fileManager =
|
||||
mgr->GetFileManager(mPersistenceType, mASCIIOrigin, mName);
|
||||
if (!fileManager) {
|
||||
fileManager = new FileManager(mASCIIOrigin, mPrivilege, mName);
|
||||
fileManager = new FileManager(mPersistenceType, mGroup, mASCIIOrigin,
|
||||
mPrivilege, mName);
|
||||
|
||||
rv = fileManager->Init(fmDirectory, connection);
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
@ -1858,6 +1896,8 @@ OpenDatabaseHelper::CreateDatabaseConnection(
|
|||
nsIFile* aDBFile,
|
||||
nsIFile* aFMDirectory,
|
||||
const nsAString& aName,
|
||||
PersistenceType aPersistenceType,
|
||||
const nsACString& aGroup,
|
||||
const nsACString& aOrigin,
|
||||
mozIStorageConnection** aConnection)
|
||||
{
|
||||
|
@ -1880,7 +1920,7 @@ OpenDatabaseHelper::CreateDatabaseConnection(
|
|||
}
|
||||
|
||||
nsCOMPtr<nsIFileURL> dbFileUrl =
|
||||
IDBFactory::GetDatabaseFileURL(aDBFile, aOrigin);
|
||||
IDBFactory::GetDatabaseFileURL(aDBFile, aPersistenceType, aGroup, aOrigin);
|
||||
NS_ENSURE_TRUE(dbFileUrl, NS_ERROR_FAILURE);
|
||||
|
||||
nsCOMPtr<mozIStorageService> ss =
|
||||
|
@ -1950,7 +1990,12 @@ OpenDatabaseHelper::CreateDatabaseConnection(
|
|||
// Turn on auto_vacuum mode to reclaim disk space on mobile devices.
|
||||
"PRAGMA auto_vacuum = FULL; "
|
||||
));
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
if (rv == NS_ERROR_FILE_NO_DEVICE_SPACE) {
|
||||
// mozstorage translates SQLITE_FULL to NS_ERROR_FILE_NO_DEVICE_SPACE,
|
||||
// which we know better as NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR.
|
||||
rv = NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR;
|
||||
}
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -2097,7 +2142,7 @@ OpenDatabaseHelper::StartDelete()
|
|||
|
||||
nsRefPtr<DeleteDatabaseHelper> helper =
|
||||
new DeleteDatabaseHelper(mOpenDBRequest, this, mCurrentVersion, mName,
|
||||
mASCIIOrigin);
|
||||
mGroup, mASCIIOrigin, mPersistenceType);
|
||||
|
||||
QuotaManager* quotaManager = QuotaManager::Get();
|
||||
NS_ASSERTION(quotaManager, "This should never be null!");
|
||||
|
@ -2122,6 +2167,10 @@ OpenDatabaseHelper::Run()
|
|||
if (NS_IsMainThread()) {
|
||||
PROFILER_MAIN_THREAD_LABEL("IndexedDB", "OpenDatabaseHelper::Run");
|
||||
|
||||
if (mState == eOpenPending) {
|
||||
return DispatchToIOThread();
|
||||
}
|
||||
|
||||
// If we need to queue up a SetVersionHelper, do that here.
|
||||
if (mState == eSetVersionPending) {
|
||||
nsresult rv = StartSetVersion();
|
||||
|
@ -2199,9 +2248,10 @@ OpenDatabaseHelper::Run()
|
|||
QuotaManager* quotaManager = QuotaManager::Get();
|
||||
NS_ASSERTION(quotaManager, "This should never be null!");
|
||||
|
||||
quotaManager->AllowNextSynchronizedOp(
|
||||
OriginOrPatternString::FromOrigin(mASCIIOrigin),
|
||||
mDatabaseId);
|
||||
quotaManager->
|
||||
AllowNextSynchronizedOp(OriginOrPatternString::FromOrigin(mASCIIOrigin),
|
||||
Nullable<PersistenceType>(mPersistenceType),
|
||||
mDatabaseId);
|
||||
|
||||
ReleaseMainThreadObjects();
|
||||
|
||||
|
@ -2242,6 +2292,7 @@ OpenDatabaseHelper::EnsureSuccessResult()
|
|||
{
|
||||
NS_ASSERTION(dbInfo->name == mName &&
|
||||
dbInfo->version == mCurrentVersion &&
|
||||
dbInfo->persistenceType == mPersistenceType &&
|
||||
dbInfo->id == mDatabaseId &&
|
||||
dbInfo->filePath == mDatabaseFilePath,
|
||||
"Metadata mismatch!");
|
||||
|
@ -2284,7 +2335,9 @@ OpenDatabaseHelper::EnsureSuccessResult()
|
|||
nsRefPtr<DatabaseInfo> newInfo(new DatabaseInfo());
|
||||
|
||||
newInfo->name = mName;
|
||||
newInfo->group = mGroup;
|
||||
newInfo->origin = mASCIIOrigin;
|
||||
newInfo->persistenceType = mPersistenceType;
|
||||
newInfo->id = mDatabaseId;
|
||||
newInfo->filePath = mDatabaseFilePath;
|
||||
|
||||
|
@ -2576,7 +2629,8 @@ DeleteDatabaseHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
|
|||
NS_ASSERTION(quotaManager, "This should never fail!");
|
||||
|
||||
nsCOMPtr<nsIFile> directory;
|
||||
nsresult rv = quotaManager->GetDirectoryForOrigin(mASCIIOrigin,
|
||||
nsresult rv = quotaManager->GetDirectoryForOrigin(mPersistenceType,
|
||||
mASCIIOrigin,
|
||||
getter_AddRefs(directory));
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
|
@ -2615,7 +2669,8 @@ DeleteDatabaseHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
|
|||
QuotaManager* quotaManager = QuotaManager::Get();
|
||||
NS_ASSERTION(quotaManager, "Shouldn't be null!");
|
||||
|
||||
quotaManager->DecreaseUsageForOrigin(mASCIIOrigin, fileSize);
|
||||
quotaManager->DecreaseUsageForOrigin(mPersistenceType, mGroup,
|
||||
mASCIIOrigin, fileSize);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2664,14 +2719,15 @@ DeleteDatabaseHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
|
|||
QuotaManager* quotaManager = QuotaManager::Get();
|
||||
NS_ASSERTION(quotaManager, "Shouldn't be null!");
|
||||
|
||||
quotaManager->DecreaseUsageForOrigin(mASCIIOrigin, usage);
|
||||
quotaManager->DecreaseUsageForOrigin(mPersistenceType, mGroup,
|
||||
mASCIIOrigin, usage);
|
||||
}
|
||||
}
|
||||
|
||||
IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
|
||||
NS_ASSERTION(mgr, "This should never fail!");
|
||||
|
||||
mgr->InvalidateFileManager(mASCIIOrigin, mName);
|
||||
mgr->InvalidateFileManager(mPersistenceType, mASCIIOrigin, mName);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -31,18 +31,22 @@ class OpenDatabaseHelper : public HelperBase
|
|||
{
|
||||
friend class CheckPermissionsHelper;
|
||||
|
||||
typedef mozilla::dom::quota::PersistenceType PersistenceType;
|
||||
typedef mozilla::dom::quota::StoragePrivilege StoragePrivilege;
|
||||
|
||||
public:
|
||||
OpenDatabaseHelper(IDBOpenDBRequest* aRequest,
|
||||
const nsAString& aName,
|
||||
const nsACString& aGroup,
|
||||
const nsACString& aASCIIOrigin,
|
||||
uint64_t aRequestedVersion,
|
||||
PersistenceType aPersistenceType,
|
||||
bool aForDeletion,
|
||||
mozilla::dom::ContentParent* aContentParent,
|
||||
StoragePrivilege aPrivilege)
|
||||
: HelperBase(aRequest), mOpenDBRequest(aRequest), mName(aName),
|
||||
mASCIIOrigin(aASCIIOrigin), mRequestedVersion(aRequestedVersion),
|
||||
mGroup(aGroup), mASCIIOrigin(aASCIIOrigin),
|
||||
mRequestedVersion(aRequestedVersion), mPersistenceType(aPersistenceType),
|
||||
mForDeletion(aForDeletion), mPrivilege(aPrivilege), mDatabaseId(nullptr),
|
||||
mContentParent(aContentParent), mCurrentVersion(0), mLastObjectStoreId(0),
|
||||
mLastIndexId(0), mState(eCreated), mResultCode(NS_OK),
|
||||
|
@ -58,7 +62,9 @@ public:
|
|||
|
||||
nsresult Init();
|
||||
|
||||
nsresult WaitForOpenAllowed();
|
||||
nsresult Dispatch(nsIEventTarget* aDatabaseThread);
|
||||
nsresult DispatchToIOThread();
|
||||
nsresult RunImmediately();
|
||||
|
||||
void SetError(nsresult rv)
|
||||
|
@ -96,6 +102,8 @@ public:
|
|||
nsresult CreateDatabaseConnection(nsIFile* aDBFile,
|
||||
nsIFile* aFMDirectory,
|
||||
const nsAString& aName,
|
||||
PersistenceType aPersistenceType,
|
||||
const nsACString& aGroup,
|
||||
const nsACString& aOrigin,
|
||||
mozIStorageConnection** aConnection);
|
||||
|
||||
|
@ -122,8 +130,10 @@ protected:
|
|||
// In-params.
|
||||
nsRefPtr<IDBOpenDBRequest> mOpenDBRequest;
|
||||
nsString mName;
|
||||
nsCString mGroup;
|
||||
nsCString mASCIIOrigin;
|
||||
uint64_t mRequestedVersion;
|
||||
PersistenceType mPersistenceType;
|
||||
bool mForDeletion;
|
||||
StoragePrivilege mPrivilege;
|
||||
nsCOMPtr<nsIAtom> mDatabaseId;
|
||||
|
@ -140,6 +150,7 @@ protected:
|
|||
// State variables
|
||||
enum OpenDatabaseState {
|
||||
eCreated = 0, // Not yet dispatched to the DB thread
|
||||
eOpenPending, // Waiting for open allowed/open allowed
|
||||
eDBWork, // Waiting to do/doing work on the DB thread
|
||||
eFiringEvents, // Waiting to fire/firing events on the main thread
|
||||
eSetVersionPending, // Waiting on a SetVersionHelper
|
||||
|
|
|
@ -210,8 +210,10 @@ IndexedDBChild::ActorDestroy(ActorDestroyReason aWhy)
|
|||
}
|
||||
|
||||
PIndexedDBDatabaseChild*
|
||||
IndexedDBChild::AllocPIndexedDBDatabaseChild(const nsString& aName,
|
||||
const uint64_t& aVersion)
|
||||
IndexedDBChild::AllocPIndexedDBDatabaseChild(
|
||||
const nsString& aName,
|
||||
const uint64_t& aVersion,
|
||||
const PersistenceType& aPersistenceType)
|
||||
{
|
||||
return new IndexedDBDatabaseChild(aName, aVersion);
|
||||
}
|
||||
|
@ -224,7 +226,9 @@ IndexedDBChild::DeallocPIndexedDBDatabaseChild(PIndexedDBDatabaseChild* aActor)
|
|||
}
|
||||
|
||||
PIndexedDBDeleteDatabaseRequestChild*
|
||||
IndexedDBChild::AllocPIndexedDBDeleteDatabaseRequestChild(const nsString& aName)
|
||||
IndexedDBChild::AllocPIndexedDBDeleteDatabaseRequestChild(
|
||||
const nsString& aName,
|
||||
const PersistenceType& aPersistenceType)
|
||||
{
|
||||
MOZ_CRASH("Caller is supposed to manually construct a request!");
|
||||
}
|
||||
|
@ -285,7 +289,8 @@ IndexedDBDatabaseChild::EnsureDatabase(
|
|||
databaseId = mDatabase->Id();
|
||||
}
|
||||
else {
|
||||
databaseId = QuotaManager::GetStorageId(aDBInfo.origin, aDBInfo.name);
|
||||
databaseId = QuotaManager::GetStorageId(aDBInfo.persistenceType,
|
||||
aDBInfo.origin, aDBInfo.name);
|
||||
}
|
||||
NS_ENSURE_TRUE(databaseId, false);
|
||||
|
||||
|
|
|
@ -65,14 +65,18 @@ protected:
|
|||
ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
|
||||
|
||||
virtual PIndexedDBDatabaseChild*
|
||||
AllocPIndexedDBDatabaseChild(const nsString& aName, const uint64_t& aVersion)
|
||||
AllocPIndexedDBDatabaseChild(const nsString& aName, const uint64_t& aVersion,
|
||||
const PersistenceType& aPersistenceType)
|
||||
MOZ_OVERRIDE;
|
||||
|
||||
virtual bool
|
||||
DeallocPIndexedDBDatabaseChild(PIndexedDBDatabaseChild* aActor) MOZ_OVERRIDE;
|
||||
|
||||
virtual PIndexedDBDeleteDatabaseRequestChild*
|
||||
AllocPIndexedDBDeleteDatabaseRequestChild(const nsString& aName) MOZ_OVERRIDE;
|
||||
AllocPIndexedDBDeleteDatabaseRequestChild(
|
||||
const nsString& aName,
|
||||
const PersistenceType& aPersistenceType)
|
||||
MOZ_OVERRIDE;
|
||||
|
||||
virtual bool
|
||||
DeallocPIndexedDBDeleteDatabaseRequestChild(
|
||||
|
|
|
@ -144,9 +144,10 @@ IndexedDBParent::ActorDestroy(ActorDestroyReason aWhy)
|
|||
|
||||
bool
|
||||
IndexedDBParent::RecvPIndexedDBDatabaseConstructor(
|
||||
PIndexedDBDatabaseParent* aActor,
|
||||
const nsString& aName,
|
||||
const uint64_t& aVersion)
|
||||
PIndexedDBDatabaseParent* aActor,
|
||||
const nsString& aName,
|
||||
const uint64_t& aVersion,
|
||||
const PersistenceType& aPersistenceType)
|
||||
{
|
||||
if (!CheckReadPermission(aName)) {
|
||||
return false;
|
||||
|
@ -162,8 +163,8 @@ IndexedDBParent::RecvPIndexedDBDatabaseConstructor(
|
|||
}
|
||||
|
||||
nsRefPtr<IDBOpenDBRequest> request;
|
||||
nsresult rv =
|
||||
mFactory->OpenInternal(aName, aVersion, false, getter_AddRefs(request));
|
||||
nsresult rv = mFactory->OpenInternal(aName, aVersion, aPersistenceType, false,
|
||||
getter_AddRefs(request));
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
IndexedDBDatabaseParent* actor =
|
||||
|
@ -178,7 +179,8 @@ IndexedDBParent::RecvPIndexedDBDatabaseConstructor(
|
|||
bool
|
||||
IndexedDBParent::RecvPIndexedDBDeleteDatabaseRequestConstructor(
|
||||
PIndexedDBDeleteDatabaseRequestParent* aActor,
|
||||
const nsString& aName)
|
||||
const nsString& aName,
|
||||
const PersistenceType& aPersistenceType)
|
||||
{
|
||||
if (!CheckWritePermission(aName)) {
|
||||
return false;
|
||||
|
@ -198,8 +200,8 @@ IndexedDBParent::RecvPIndexedDBDeleteDatabaseRequestConstructor(
|
|||
|
||||
nsRefPtr<IDBOpenDBRequest> request;
|
||||
|
||||
nsresult rv =
|
||||
mFactory->OpenInternal(aName, 0, true, getter_AddRefs(request));
|
||||
nsresult rv = mFactory->OpenInternal(aName, 0, aPersistenceType, true,
|
||||
getter_AddRefs(request));
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
rv = actor->SetOpenRequest(request);
|
||||
|
@ -209,8 +211,10 @@ IndexedDBParent::RecvPIndexedDBDeleteDatabaseRequestConstructor(
|
|||
}
|
||||
|
||||
PIndexedDBDatabaseParent*
|
||||
IndexedDBParent::AllocPIndexedDBDatabaseParent(const nsString& aName,
|
||||
const uint64_t& aVersion)
|
||||
IndexedDBParent::AllocPIndexedDBDatabaseParent(
|
||||
const nsString& aName,
|
||||
const uint64_t& aVersion,
|
||||
const PersistenceType& aPersistenceType)
|
||||
{
|
||||
return new IndexedDBDatabaseParent();
|
||||
}
|
||||
|
@ -223,7 +227,9 @@ IndexedDBParent::DeallocPIndexedDBDatabaseParent(PIndexedDBDatabaseParent* aActo
|
|||
}
|
||||
|
||||
PIndexedDBDeleteDatabaseRequestParent*
|
||||
IndexedDBParent::AllocPIndexedDBDeleteDatabaseRequestParent(const nsString& aName)
|
||||
IndexedDBParent::AllocPIndexedDBDeleteDatabaseRequestParent(
|
||||
const nsString& aName,
|
||||
const PersistenceType& aPersistenceType)
|
||||
{
|
||||
return new IndexedDBDeleteDatabaseRequestParent(mFactory);
|
||||
}
|
||||
|
|
|
@ -205,22 +205,30 @@ protected:
|
|||
virtual bool
|
||||
RecvPIndexedDBDatabaseConstructor(PIndexedDBDatabaseParent* aActor,
|
||||
const nsString& aName,
|
||||
const uint64_t& aVersion) MOZ_OVERRIDE;
|
||||
const uint64_t& aVersion,
|
||||
const PersistenceType& aPersistenceType)
|
||||
MOZ_OVERRIDE;
|
||||
|
||||
virtual bool
|
||||
RecvPIndexedDBDeleteDatabaseRequestConstructor(
|
||||
PIndexedDBDeleteDatabaseRequestParent* aActor,
|
||||
const nsString& aName) MOZ_OVERRIDE;
|
||||
const nsString& aName,
|
||||
const PersistenceType& aPersistenceType)
|
||||
MOZ_OVERRIDE;
|
||||
|
||||
virtual PIndexedDBDatabaseParent*
|
||||
AllocPIndexedDBDatabaseParent(const nsString& aName, const uint64_t& aVersion)
|
||||
AllocPIndexedDBDatabaseParent(const nsString& aName, const uint64_t& aVersion,
|
||||
const PersistenceType& aPersistenceType)
|
||||
MOZ_OVERRIDE;
|
||||
|
||||
virtual bool
|
||||
DeallocPIndexedDBDatabaseParent(PIndexedDBDatabaseParent* aActor) MOZ_OVERRIDE;
|
||||
|
||||
virtual PIndexedDBDeleteDatabaseRequestParent*
|
||||
AllocPIndexedDBDeleteDatabaseRequestParent(const nsString& aName) MOZ_OVERRIDE;
|
||||
AllocPIndexedDBDeleteDatabaseRequestParent(
|
||||
const nsString& aName,
|
||||
const PersistenceType& aPersistenceType)
|
||||
MOZ_OVERRIDE;
|
||||
|
||||
virtual bool
|
||||
DeallocPIndexedDBDeleteDatabaseRequestParent(
|
||||
|
|
|
@ -7,6 +7,10 @@ include protocol PContent;
|
|||
include protocol PIndexedDBDatabase;
|
||||
include protocol PIndexedDBDeleteDatabaseRequest;
|
||||
|
||||
include "mozilla/dom/indexedDB/SerializationHelpers.h";
|
||||
|
||||
using mozilla::dom::quota::PersistenceType;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace indexedDB {
|
||||
|
@ -21,9 +25,11 @@ protocol PIndexedDB
|
|||
parent:
|
||||
__delete__();
|
||||
|
||||
PIndexedDBDatabase(nsString name, uint64_t version);
|
||||
PIndexedDBDatabase(nsString name, uint64_t version,
|
||||
PersistenceType persistenceType);
|
||||
|
||||
PIndexedDBDeleteDatabaseRequest(nsString name);
|
||||
PIndexedDBDeleteDatabaseRequest(nsString name,
|
||||
PersistenceType persistenceType);
|
||||
};
|
||||
|
||||
} // namespace indexedDB
|
||||
|
|
|
@ -15,6 +15,13 @@
|
|||
|
||||
namespace IPC {
|
||||
|
||||
template <>
|
||||
struct ParamTraits<mozilla::dom::quota::PersistenceType> :
|
||||
public EnumSerializer<mozilla::dom::quota::PersistenceType,
|
||||
mozilla::dom::quota::PERSISTENCE_TYPE_PERSISTENT,
|
||||
mozilla::dom::quota::PERSISTENCE_TYPE_INVALID>
|
||||
{ };
|
||||
|
||||
template <>
|
||||
struct ParamTraits<mozilla::dom::indexedDB::Key>
|
||||
{
|
||||
|
@ -154,8 +161,10 @@ struct ParamTraits<mozilla::dom::indexedDB::DatabaseInfoGuts>
|
|||
static void Write(Message* aMsg, const paramType& aParam)
|
||||
{
|
||||
WriteParam(aMsg, aParam.name);
|
||||
WriteParam(aMsg, aParam.group);
|
||||
WriteParam(aMsg, aParam.origin);
|
||||
WriteParam(aMsg, aParam.version);
|
||||
WriteParam(aMsg, aParam.persistenceType);
|
||||
WriteParam(aMsg, aParam.nextObjectStoreId);
|
||||
WriteParam(aMsg, aParam.nextIndexId);
|
||||
}
|
||||
|
@ -163,8 +172,10 @@ struct ParamTraits<mozilla::dom::indexedDB::DatabaseInfoGuts>
|
|||
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
|
||||
{
|
||||
return ReadParam(aMsg, aIter, &aResult->name) &&
|
||||
ReadParam(aMsg, aIter, &aResult->group) &&
|
||||
ReadParam(aMsg, aIter, &aResult->origin) &&
|
||||
ReadParam(aMsg, aIter, &aResult->version) &&
|
||||
ReadParam(aMsg, aIter, &aResult->persistenceType) &&
|
||||
ReadParam(aMsg, aIter, &aResult->nextObjectStoreId) &&
|
||||
ReadParam(aMsg, aIter, &aResult->nextIndexId);
|
||||
}
|
||||
|
@ -172,6 +183,7 @@ struct ParamTraits<mozilla::dom::indexedDB::DatabaseInfoGuts>
|
|||
static void Log(const paramType& aParam, std::wstring* aLog)
|
||||
{
|
||||
LogParam(aParam.name, aLog);
|
||||
LogParam(aParam.group, aLog);
|
||||
LogParam(aParam.origin, aLog);
|
||||
LogParam(aParam.version, aLog);
|
||||
LogParam(aParam.nextObjectStoreId, aLog);
|
||||
|
|
|
@ -79,6 +79,7 @@ MOCHITEST_FILES = \
|
|||
test_open_objectStore.html \
|
||||
test_optionalArguments.html \
|
||||
test_overlapping_transactions.html \
|
||||
test_persistenceType.html \
|
||||
test_put_get_values.html \
|
||||
test_put_get_values_autoIncrement.html \
|
||||
test_readonly_transactions.html \
|
||||
|
|
|
@ -190,11 +190,6 @@ function getUsage(usageHandler)
|
|||
quotaManager.getUsageForURI(uri, cb);
|
||||
}
|
||||
|
||||
function scheduleGC()
|
||||
{
|
||||
SpecialPowers.exactGC(window, continueToNextStep);
|
||||
}
|
||||
|
||||
function getFileId(file)
|
||||
{
|
||||
return utils.getFileId(file);
|
||||
|
@ -208,13 +203,13 @@ function hasFileInfo(name, id)
|
|||
function getFileRefCount(name, id)
|
||||
{
|
||||
let count = {};
|
||||
utils.getFileReferences(name, id, count);
|
||||
utils.getFileReferences(name, id, null, count);
|
||||
return count.value;
|
||||
}
|
||||
|
||||
function getFileDBRefCount(name, id)
|
||||
{
|
||||
let count = {};
|
||||
utils.getFileReferences(name, id, {}, count);
|
||||
utils.getFileReferences(name, id, null, {}, count);
|
||||
return count.value;
|
||||
}
|
||||
|
|
|
@ -84,6 +84,7 @@ if (!window.runTest) {
|
|||
allowUnlimitedQuota();
|
||||
}
|
||||
|
||||
enableExperimental();
|
||||
enableArchiveReader();
|
||||
|
||||
clearAllDatabases(function () { testGenerator.next(); });
|
||||
|
@ -93,6 +94,7 @@ if (!window.runTest) {
|
|||
function finishTest()
|
||||
{
|
||||
resetUnlimitedQuota();
|
||||
resetExperimental();
|
||||
resetArchiveReader();
|
||||
SpecialPowers.notifyObserversInParentProcess(null, "disk-space-watcher",
|
||||
"free");
|
||||
|
@ -253,8 +255,23 @@ function resetArchiveReader()
|
|||
SpecialPowers.setBoolPref("dom.archivereader.enabled", archiveReaderEnabled);
|
||||
}
|
||||
|
||||
function enableExperimental()
|
||||
{
|
||||
SpecialPowers.setBoolPref("dom.indexedDB.experimental", true);
|
||||
}
|
||||
|
||||
function resetExperimental()
|
||||
{
|
||||
SpecialPowers.clearUserPref("dom.indexedDB.experimental");
|
||||
}
|
||||
|
||||
function gc()
|
||||
{
|
||||
SpecialPowers.forceGC();
|
||||
SpecialPowers.forceCC();
|
||||
}
|
||||
|
||||
function scheduleGC()
|
||||
{
|
||||
SpecialPowers.exactGC(window, continueToNextStep);
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@
|
|||
for (let id = 1; id <= 100; id++) {
|
||||
let refs = {};
|
||||
let dbRefs = {};
|
||||
let hasFileInfo = utils.getFileReferences(name, id, refs, dbRefs);
|
||||
let hasFileInfo = utils.getFileReferences(name, id, null, refs, dbRefs);
|
||||
ok(hasFileInfo, "Has file info");
|
||||
is(refs.value, 1, "Correct ref count");
|
||||
is(dbRefs.value, id / 100 >> 0, "Correct db ref count");
|
||||
|
|
|
@ -0,0 +1,108 @@
|
|||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<title>Indexed Database Property Test</title>
|
||||
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
|
||||
<script type="text/javascript;version=1.7">
|
||||
function testSteps()
|
||||
{
|
||||
const name = window.location.pathname;
|
||||
const version = 1;
|
||||
|
||||
const objectStoreName = "Foo";
|
||||
const data = { key: 1, value: "bar" };
|
||||
|
||||
try {
|
||||
indexedDB.open(name, { version: version, storage: "unknown" });
|
||||
ok(false, "Should have thrown!");
|
||||
}
|
||||
catch (e) {
|
||||
ok(e instanceof TypeError, "Got TypeError.");
|
||||
is(e.name, "TypeError", "Good error name.");
|
||||
}
|
||||
|
||||
let request = indexedDB.open(name, { version: version,
|
||||
storage: "persistent" });
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = grabEventAndContinueHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
let event = yield undefined;
|
||||
|
||||
is(event.type, "upgradeneeded", "Got correct event type");
|
||||
|
||||
let db = event.target.result;
|
||||
db.onerror = errorHandler;
|
||||
|
||||
let objectStore = db.createObjectStore(objectStoreName, { });
|
||||
|
||||
event = yield undefined;
|
||||
|
||||
is(event.type, "success", "Got correct event type");
|
||||
|
||||
is(db.name, name, "Correct name");
|
||||
is(db.version, version, "Correct version");
|
||||
is(db.storage, "persistent", "Correct persistence type");
|
||||
|
||||
objectStore = db.transaction([objectStoreName], "readwrite")
|
||||
.objectStore(objectStoreName);
|
||||
|
||||
request = objectStore.get(data.key);
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
event = yield undefined;
|
||||
|
||||
is(event.target.result, null, "Got no data");
|
||||
|
||||
request = objectStore.add(data.value, data.key);
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
event = yield undefined;
|
||||
|
||||
is(event.target.result, data.key, "Got correct key");
|
||||
|
||||
request = indexedDB.open(name, { version: version,
|
||||
storage: "temporary" });
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = grabEventAndContinueHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
let event = yield undefined;
|
||||
|
||||
is(event.type, "upgradeneeded", "Got correct event type");
|
||||
|
||||
db = event.target.result;
|
||||
db.onerror = errorHandler;
|
||||
|
||||
objectStore = db.createObjectStore(objectStoreName, { });
|
||||
|
||||
event = yield undefined;
|
||||
|
||||
is(event.type, "success", "Got correct event type");
|
||||
|
||||
is(db.name, name, "Correct name");
|
||||
is(db.version, version, "Correct version");
|
||||
is(db.storage, "temporary", "Correct persistence type");
|
||||
|
||||
objectStore = db.transaction([objectStoreName])
|
||||
.objectStore(objectStoreName);
|
||||
|
||||
request = objectStore.get(data.key);
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
event = yield undefined;
|
||||
|
||||
is(event.target.result, null, "Got no data");
|
||||
|
||||
finishTest();
|
||||
yield undefined;
|
||||
}
|
||||
</script>
|
||||
<script type="text/javascript;version=1.7" src="helpers.js"></script>
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="runTest();"></body>
|
||||
|
||||
</html>
|
|
@ -46,6 +46,7 @@ MOCHITEST_FILES = \
|
|||
test_open_objectStore.js \
|
||||
test_optionalArguments.js \
|
||||
test_overlapping_transactions.js \
|
||||
test_persistenceType.js \
|
||||
test_put_get_values.js \
|
||||
test_put_get_values_autoIncrement.js \
|
||||
test_readonly_transactions.js \
|
||||
|
@ -57,6 +58,7 @@ MOCHITEST_FILES = \
|
|||
test_setVersion_events.js \
|
||||
test_setVersion_exclusion.js \
|
||||
test_success_events_after_abort.js \
|
||||
test_temporary_storage.js \
|
||||
test_traffic_jam.js \
|
||||
test_transaction_abort.js \
|
||||
test_transaction_abort_hang.js \
|
||||
|
|
|
@ -47,16 +47,20 @@ function runTest()
|
|||
getService(Ci.nsIIndexedDatabaseManager);
|
||||
idbManager.initWindowless(this);
|
||||
|
||||
enableExperimental();
|
||||
|
||||
do_test_pending();
|
||||
testGenerator.next();
|
||||
}
|
||||
|
||||
function finishTest()
|
||||
{
|
||||
resetExperimental();
|
||||
SpecialPowers.notifyObserversInParentProcess(null, "disk-space-watcher",
|
||||
"free");
|
||||
|
||||
do_execute_soon(function(){
|
||||
testGenerator.close();
|
||||
SpecialPowers.notifyObserversInParentProcess(null, "disk-space-watcher",
|
||||
"free");
|
||||
do_test_finished();
|
||||
})
|
||||
}
|
||||
|
@ -179,12 +183,27 @@ function disallowUnlimitedQuota(url)
|
|||
throw "disallowUnlimitedQuota";
|
||||
}
|
||||
|
||||
function enableExperimental()
|
||||
{
|
||||
SpecialPowers.setBoolPref("dom.indexedDB.experimental", true);
|
||||
}
|
||||
|
||||
function resetExperimental()
|
||||
{
|
||||
SpecialPowers.clearUserPref("dom.indexedDB.experimental");
|
||||
}
|
||||
|
||||
function gc()
|
||||
{
|
||||
Components.utils.forceGC();
|
||||
Components.utils.forceCC();
|
||||
}
|
||||
|
||||
function scheduleGC()
|
||||
{
|
||||
SpecialPowers.exactGC(null, continueToNextStep);
|
||||
}
|
||||
|
||||
function setTimeout(fun, timeout) {
|
||||
let timer = Components.classes["@mozilla.org/timer;1"]
|
||||
.createInstance(Components.interfaces.nsITimer);
|
||||
|
@ -214,5 +233,43 @@ var SpecialPowers = {
|
|||
throw new Error("Can't send subject to another process!");
|
||||
}
|
||||
return this.notifyObservers(subject, topic, data);
|
||||
},
|
||||
getBoolPref: function(prefName) {
|
||||
return this._getPrefs().getBoolPref(prefName);
|
||||
},
|
||||
setBoolPref: function(prefName, value) {
|
||||
this._getPrefs().setBoolPref(prefName, value);
|
||||
},
|
||||
setIntPref: function(prefName, value) {
|
||||
this._getPrefs().setIntPref(prefName, value);
|
||||
},
|
||||
clearUserPref: function(prefName) {
|
||||
this._getPrefs().clearUserPref(prefName);
|
||||
},
|
||||
// Copied (and slightly adjusted) from specialpowersAPI.js
|
||||
exactGC: function(win, callback) {
|
||||
let count = 0;
|
||||
|
||||
function doPreciseGCandCC() {
|
||||
function scheduledGCCallback() {
|
||||
Components.utils.forceCC();
|
||||
|
||||
if (++count < 2) {
|
||||
doPreciseGCandCC();
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
|
||||
Components.utils.schedulePreciseGC(scheduledGCCallback);
|
||||
}
|
||||
|
||||
doPreciseGCandCC();
|
||||
},
|
||||
|
||||
_getPrefs: function() {
|
||||
var prefService =
|
||||
Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefService);
|
||||
return prefService.getBranch(null);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -27,6 +27,24 @@ function testSteps()
|
|||
is(e.name, "TypeError", "Good error name.");
|
||||
}
|
||||
|
||||
try {
|
||||
indexedDB.open(name, { version: 0 });
|
||||
ok(false, "Should have thrown!");
|
||||
}
|
||||
catch (e) {
|
||||
ok(e instanceof TypeError, "Got TypeError.");
|
||||
is(e.name, "TypeError", "Good error name.");
|
||||
}
|
||||
|
||||
try {
|
||||
indexedDB.open(name, { version: -1 });
|
||||
ok(false, "Should have thrown!");
|
||||
}
|
||||
catch (e) {
|
||||
ok(e instanceof TypeError, "Got TypeError.");
|
||||
is(e.name, "TypeError", "Good error name.");
|
||||
}
|
||||
|
||||
finishTest();
|
||||
yield undefined;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
/**
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
var testGenerator = testSteps();
|
||||
|
||||
function testSteps()
|
||||
{
|
||||
const name = "Splendid Test";
|
||||
const version = 1;
|
||||
|
||||
const objectStoreName = "Foo";
|
||||
const data = { key: 1, value: "bar" };
|
||||
|
||||
try {
|
||||
indexedDB.open(name, { version: version, storage: "unknown" });
|
||||
ok(false, "Should have thrown!");
|
||||
}
|
||||
catch (e) {
|
||||
ok(e instanceof TypeError, "Got TypeError.");
|
||||
is(e.name, "TypeError", "Good error name.");
|
||||
}
|
||||
|
||||
let request = indexedDB.open(name, { version: version,
|
||||
storage: "persistent" });
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = grabEventAndContinueHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
let event = yield undefined;
|
||||
|
||||
is(event.type, "upgradeneeded", "Got correct event type");
|
||||
|
||||
let db = event.target.result;
|
||||
db.onerror = errorHandler;
|
||||
|
||||
let objectStore = db.createObjectStore(objectStoreName, { });
|
||||
|
||||
event = yield undefined;
|
||||
|
||||
is(event.type, "success", "Got correct event type");
|
||||
|
||||
is(db.name, name, "Correct name");
|
||||
is(db.version, version, "Correct version");
|
||||
is(db.storage, "persistent", "Correct persistence type");
|
||||
|
||||
objectStore = db.transaction([objectStoreName], "readwrite")
|
||||
.objectStore(objectStoreName);
|
||||
|
||||
request = objectStore.get(data.key);
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
event = yield undefined;
|
||||
|
||||
is(event.target.result, null, "Got no data");
|
||||
|
||||
request = objectStore.add(data.value, data.key);
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
event = yield undefined;
|
||||
|
||||
is(event.target.result, data.key, "Got correct key");
|
||||
|
||||
request = indexedDB.open(name, { version: version,
|
||||
storage: "temporary" });
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = grabEventAndContinueHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
let event = yield undefined;
|
||||
|
||||
is(event.type, "success", "Got correct event type");
|
||||
|
||||
is(db.name, name, "Correct name");
|
||||
is(db.version, version, "Correct version");
|
||||
is(db.storage, "persistent", "Correct persistence type");
|
||||
|
||||
objectStore = db.transaction([objectStoreName])
|
||||
.objectStore(objectStoreName);
|
||||
|
||||
request = objectStore.get(data.key);
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
event = yield undefined;
|
||||
|
||||
is(event.target.result, data.value, "Got correct data");
|
||||
|
||||
finishTest();
|
||||
yield undefined;
|
||||
}
|
|
@ -0,0 +1,225 @@
|
|||
/**
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
var testGenerator = testSteps();
|
||||
|
||||
function testSteps()
|
||||
{
|
||||
const name = this.window ? window.location.pathname : "Splendid Test";
|
||||
|
||||
const urls = [
|
||||
{ url: "http://www.alpha.com", flags: [true, true, false, false] },
|
||||
{ url: "http://www.beta.com", flags: [true, false, false, false] },
|
||||
{ url: "http://www.gamma.com", flags: [true, true, false, false] },
|
||||
{ url: "http://www.delta.com", flags: [true, true, false, false] },
|
||||
{ url: "http://www.epsilon.com", flags: [true, true, false, false] },
|
||||
{ url: "http://www2.alpha.com", flags: [true, true, false, false] },
|
||||
{ url: "http://www2.beta.com", flags: [true, true, false, false] },
|
||||
{ url: "http://www2.gamma.com", flags: [true, true, true, false] },
|
||||
{ url: "http://www2.delta.com", flags: [true, true, true, true] },
|
||||
{ url: "http://www2.epsilon.com", flags: [true, true, true, true] },
|
||||
{ url: "http://joe.blog.alpha.com", flags: [true, true, true, true] },
|
||||
{ url: "http://joe.blog.beta.com", flags: [true, true, true, true] },
|
||||
{ url: "http://joe.blog.gamma.com", flags: [true, true, true, true] },
|
||||
{ url: "http://joe.blog.delta.com", flags: [true, true, true, true] },
|
||||
{ url: "http://joe.blog.epsilon.com", flags: [true, true, true, true] },
|
||||
{ url: "http://www.rudolf.org", flags: [true, true, true, true] },
|
||||
{ url: "http://www.pauline.org", flags: [true, true, true, true] },
|
||||
{ url: "http://www.marie.org", flags: [true, true, true, true] },
|
||||
{ url: "http://www.john.org", flags: [true, true, true, true] },
|
||||
{ url: "http://www.ema.org", flags: [true, true, true, true] },
|
||||
{ url: "http://www.trigger.com", flags: [false, true, true, true] }
|
||||
];
|
||||
const lastIndex = urls.length - 1;
|
||||
const lastUrl = urls[lastIndex].url;
|
||||
|
||||
let quotaManager =
|
||||
Components.classes["@mozilla.org/dom/quota/manager;1"]
|
||||
.getService(Components.interfaces.nsIQuotaManager);
|
||||
|
||||
let ioService = Components.classes["@mozilla.org/network/io-service;1"]
|
||||
.getService(Components.interfaces.nsIIOService);
|
||||
|
||||
let dbSize = 0;
|
||||
|
||||
let databases = [];
|
||||
|
||||
function setLimit(limit) {
|
||||
if (limit) {
|
||||
SpecialPowers.setIntPref("dom.quotaManager.temporaryStorage.fixedLimit",
|
||||
limit);
|
||||
return;
|
||||
}
|
||||
SpecialPowers.clearUserPref("dom.quotaManager.temporaryStorage.fixedLimit");
|
||||
}
|
||||
|
||||
function getPrincipal(url) {
|
||||
let uri = ioService.newURI(url, null, null);
|
||||
return Components.classes["@mozilla.org/scriptsecuritymanager;1"]
|
||||
.getService(Components.interfaces.nsIScriptSecurityManager)
|
||||
.getNoAppCodebasePrincipal(uri);
|
||||
}
|
||||
|
||||
function getUsageForUrl(url, usageHandler) {
|
||||
let uri = ioService.newURI(url, null, null);
|
||||
function callback(uri, usage, fileUsage) {
|
||||
usageHandler(usage, fileUsage);
|
||||
}
|
||||
quotaManager.getUsageForURI(uri, callback);
|
||||
}
|
||||
|
||||
function grabUsageAndContinueHandler(usage, fileUsage) {
|
||||
testGenerator.send(usage);
|
||||
}
|
||||
|
||||
function checkUsage(stageIndex) {
|
||||
let handledIndex = 0;
|
||||
|
||||
function usageHandler(usage, fileUsage) {
|
||||
if (urls[handledIndex].flags[stageIndex - 1]) {
|
||||
ok(usage > 0, "Correct usage");
|
||||
}
|
||||
else {
|
||||
ok(usage == 0, "Correct usage");
|
||||
}
|
||||
if (++handledIndex == urls.length) {
|
||||
continueToNextStep();
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < urls.length; i++) {
|
||||
getUsageForUrl(urls[i].url, usageHandler);
|
||||
}
|
||||
}
|
||||
|
||||
// Enable clear() and test()
|
||||
let testingEnabled =
|
||||
SpecialPowers.getBoolPref("dom.quotaManager.testing");
|
||||
SpecialPowers.setBoolPref("dom.quotaManager.testing", true)
|
||||
|
||||
// Calibration
|
||||
let request = indexedDB.openForPrincipal(getPrincipal(lastUrl), name,
|
||||
{ storage: "temporary" });
|
||||
request.onerror = errorHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
let event = yield undefined;
|
||||
|
||||
getUsageForUrl(lastUrl, grabUsageAndContinueHandler);
|
||||
dbSize = yield undefined;
|
||||
|
||||
setLimit(lastIndex * dbSize / 1024);
|
||||
quotaManager.clear();
|
||||
|
||||
// Stage 1
|
||||
for (let i = 0; i < lastIndex; i++) {
|
||||
let data = urls[i];
|
||||
|
||||
request = indexedDB.openForPrincipal(getPrincipal(data.url), name,
|
||||
{ storage: "temporary" });
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = grabEventAndContinueHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
event = yield undefined;
|
||||
|
||||
is(event.type, "upgradeneeded", "Got correct event type");
|
||||
|
||||
let db = event.target.result;
|
||||
db.createObjectStore("foo", { });
|
||||
|
||||
event = yield undefined;
|
||||
|
||||
is(event.type, "success", "Got correct event type");
|
||||
|
||||
databases.push(event.target.result);
|
||||
}
|
||||
|
||||
request = indexedDB.openForPrincipal(getPrincipal(lastUrl), name,
|
||||
{ storage: "temporary" });
|
||||
request.addEventListener("error", new ExpectError("QuotaExceededError"));
|
||||
request.onsuccess = unexpectedSuccessHandler;
|
||||
event = yield undefined;
|
||||
|
||||
checkUsage(1);
|
||||
yield undefined;
|
||||
|
||||
// Stage 2
|
||||
for (let i = 1; i < urls.length; i++) {
|
||||
databases[i] = null;
|
||||
|
||||
scheduleGC();
|
||||
yield undefined;
|
||||
|
||||
// The origin access time is set to the current system time when the first
|
||||
// database for an origin is registered or the last one is unregistered.
|
||||
// The registration happens when the database object is being created and
|
||||
// the unregistration when it is unlinked/garbage collected.
|
||||
// Some older windows systems have the system time limited to a maximum
|
||||
// resolution of 10 or 15 milliseconds, so without a pause here we would
|
||||
// end up with origins with the same access time which would cause random
|
||||
// failures.
|
||||
setTimeout(function() { testGenerator.next(); }, 20);
|
||||
yield undefined;
|
||||
}
|
||||
|
||||
request = indexedDB.openForPrincipal(getPrincipal(lastUrl), name,
|
||||
{ storage: "temporary" });
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = grabEventAndContinueHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
event = yield undefined;
|
||||
|
||||
is(event.type, "upgradeneeded", "Got correct event type");
|
||||
|
||||
let db = event.target.result;
|
||||
db.createObjectStore("foo", { });
|
||||
|
||||
event = yield undefined;
|
||||
|
||||
is(event.type, "success", "Got correct event type");
|
||||
|
||||
checkUsage(2);
|
||||
yield undefined;
|
||||
|
||||
// Stage 3
|
||||
setLimit(14 * dbSize / 1024);
|
||||
quotaManager.reset();
|
||||
|
||||
request = indexedDB.openForPrincipal(getPrincipal(lastUrl), name,
|
||||
{ storage: "temporary" });
|
||||
request.onerror = errorHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
event = yield undefined;
|
||||
|
||||
is(event.type, "success", "Got correct event type");
|
||||
|
||||
let db = event.target.result;
|
||||
|
||||
checkUsage(3);
|
||||
yield undefined;
|
||||
|
||||
// Stage 4
|
||||
let trans = db.transaction(["foo"], "readwrite");
|
||||
|
||||
let blob = Blob(["bar"]);
|
||||
request = trans.objectStore("foo").add(blob, 42);
|
||||
request.onerror = errorHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
event = yield undefined;
|
||||
|
||||
trans.oncomplete = grabEventAndContinueHandler;
|
||||
event = yield undefined;
|
||||
|
||||
checkUsage(4);
|
||||
yield undefined;
|
||||
|
||||
// Cleanup
|
||||
setLimit();
|
||||
quotaManager.reset();
|
||||
|
||||
SpecialPowers.setBoolPref("dom.quotaManager.testing", testingEnabled);
|
||||
|
||||
finishTest();
|
||||
yield undefined;
|
||||
}
|
|
@ -47,6 +47,7 @@ tail =
|
|||
[test_open_objectStore.js]
|
||||
[test_optionalArguments.js]
|
||||
[test_overlapping_transactions.js]
|
||||
[test_persistenceType.js]
|
||||
[test_put_get_values.js]
|
||||
[test_put_get_values_autoIncrement.js]
|
||||
[test_readonly_transactions.js]
|
||||
|
@ -58,6 +59,7 @@ tail =
|
|||
[test_setVersion_events.js]
|
||||
[test_setVersion_exclusion.js]
|
||||
[test_success_events_after_abort.js]
|
||||
[test_temporary_storage.js]
|
||||
[test_traffic_jam.js]
|
||||
[test_transaction_abort.js]
|
||||
[test_transaction_abort_hang.js]
|
||||
|
|
|
@ -42,7 +42,7 @@ interface nsIURI;
|
|||
interface nsIDOMEventTarget;
|
||||
interface nsIRunnable;
|
||||
|
||||
[scriptable, uuid(d6e733ef-492b-4e67-b723-28571c2959f0)]
|
||||
[scriptable, uuid(d18a8d69-7609-4165-ae20-af8aead36833)]
|
||||
interface nsIDOMWindowUtils : nsISupports {
|
||||
|
||||
/**
|
||||
|
@ -1229,7 +1229,9 @@ interface nsIDOMWindowUtils : nsISupports {
|
|||
* Get file ref count info for given database and file id.
|
||||
*
|
||||
*/
|
||||
[implicit_jscontext]
|
||||
boolean getFileReferences(in AString aDatabaseName, in long long aId,
|
||||
[optional] in jsval aOptions,
|
||||
[optional] out long aRefCnt,
|
||||
[optional] out long aDBRefCnt,
|
||||
[optional] out long aSliceRefCnt);
|
||||
|
|
|
@ -251,7 +251,7 @@ parent:
|
|||
POfflineCacheUpdate(URIParams manifestURI, URIParams documentURI,
|
||||
bool stickDocument);
|
||||
|
||||
sync PIndexedDB(nsCString asciiOrigin)
|
||||
sync PIndexedDB(nsCString group, nsCString asciiOrigin)
|
||||
returns (bool allowed);
|
||||
|
||||
/**
|
||||
|
|
|
@ -2445,7 +2445,9 @@ TabChild::GetMessageManager(nsIContentFrameMessageManager** aResult)
|
|||
}
|
||||
|
||||
PIndexedDBChild*
|
||||
TabChild::AllocPIndexedDBChild(const nsCString& aASCIIOrigin, bool* /* aAllowed */)
|
||||
TabChild::AllocPIndexedDBChild(
|
||||
const nsCString& aGroup,
|
||||
const nsCString& aASCIIOrigin, bool* /* aAllowed */)
|
||||
{
|
||||
NS_NOTREACHED("Should never get here!");
|
||||
return NULL;
|
||||
|
|
|
@ -351,7 +351,8 @@ protected:
|
|||
|
||||
nsEventStatus DispatchWidgetEvent(nsGUIEvent& event);
|
||||
|
||||
virtual PIndexedDBChild* AllocPIndexedDBChild(const nsCString& aASCIIOrigin,
|
||||
virtual PIndexedDBChild* AllocPIndexedDBChild(const nsCString& aGroup,
|
||||
const nsCString& aASCIIOrigin,
|
||||
bool* /* aAllowed */);
|
||||
|
||||
virtual bool DeallocPIndexedDBChild(PIndexedDBChild* aActor);
|
||||
|
|
|
@ -1195,7 +1195,9 @@ TabParent::ReceiveMessage(const nsString& aMessage,
|
|||
}
|
||||
|
||||
PIndexedDBParent*
|
||||
TabParent::AllocPIndexedDBParent(const nsCString& aASCIIOrigin, bool* /* aAllowed */)
|
||||
TabParent::AllocPIndexedDBParent(
|
||||
const nsCString& aGroup,
|
||||
const nsCString& aASCIIOrigin, bool* /* aAllowed */)
|
||||
{
|
||||
return new IndexedDBParent(this);
|
||||
}
|
||||
|
@ -1209,6 +1211,7 @@ TabParent::DeallocPIndexedDBParent(PIndexedDBParent* aActor)
|
|||
|
||||
bool
|
||||
TabParent::RecvPIndexedDBConstructor(PIndexedDBParent* aActor,
|
||||
const nsCString& aGroup,
|
||||
const nsCString& aASCIIOrigin,
|
||||
bool* aAllowed)
|
||||
{
|
||||
|
@ -1263,7 +1266,7 @@ TabParent::RecvPIndexedDBConstructor(PIndexedDBParent* aActor,
|
|||
NS_ASSERTION(contentParent, "Null manager?!");
|
||||
|
||||
nsRefPtr<IDBFactory> factory;
|
||||
rv = IDBFactory::Create(window, aASCIIOrigin, contentParent,
|
||||
rv = IDBFactory::Create(window, aGroup, aASCIIOrigin, contentParent,
|
||||
getter_AddRefs(factory));
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
|
|
|
@ -248,13 +248,16 @@ protected:
|
|||
|
||||
virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE;
|
||||
|
||||
virtual PIndexedDBParent* AllocPIndexedDBParent(const nsCString& aASCIIOrigin,
|
||||
bool* /* aAllowed */);
|
||||
virtual PIndexedDBParent* AllocPIndexedDBParent(
|
||||
const nsCString& aGroup,
|
||||
const nsCString& aASCIIOrigin,
|
||||
bool* /* aAllowed */);
|
||||
|
||||
virtual bool DeallocPIndexedDBParent(PIndexedDBParent* aActor);
|
||||
|
||||
virtual bool
|
||||
RecvPIndexedDBConstructor(PIndexedDBParent* aActor,
|
||||
const nsCString& aGroup,
|
||||
const nsCString& aASCIIOrigin,
|
||||
bool* aAllowed);
|
||||
|
||||
|
|
|
@ -21,7 +21,8 @@ var gData = [
|
|||
// test substitute
|
||||
{
|
||||
permission: "storage",
|
||||
expected: ["indexedDB-unlimited", "offline-app", "pin-app"]
|
||||
expected: ["indexedDB-unlimited", "offline-app", "pin-app",
|
||||
"default-persistent-storage"]
|
||||
},
|
||||
// test unknown access
|
||||
{
|
||||
|
|
|
@ -120,9 +120,8 @@ CheckQuotaHelper::GetQuotaPermission(nsIPrincipal* aPrincipal)
|
|||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
NS_ASSERTION(aPrincipal, "Null principal!");
|
||||
|
||||
if (nsContentUtils::IsSystemPrincipal(aPrincipal)) {
|
||||
return nsIPermissionManager::ALLOW_ACTION;
|
||||
}
|
||||
NS_ASSERTION(!nsContentUtils::IsSystemPrincipal(aPrincipal),
|
||||
"Chrome windows shouldn't track quota!");
|
||||
|
||||
nsCOMPtr<nsIPermissionManager> pm =
|
||||
do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
|
||||
|
@ -200,7 +199,7 @@ CheckQuotaHelper::Run()
|
|||
|
||||
NS_ASSERTION(mWaiting, "Huh?!");
|
||||
|
||||
// This should never be used again.
|
||||
// This should never be used again.
|
||||
mWindow = nullptr;
|
||||
|
||||
mWaiting = false;
|
||||
|
|
|
@ -13,8 +13,8 @@
|
|||
#include "nsIObserver.h"
|
||||
#include "nsIRunnable.h"
|
||||
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "mozilla/CondVar.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
|
||||
class nsIPrincipal;
|
||||
class nsPIDOMWindow;
|
||||
|
@ -34,11 +34,14 @@ public:
|
|||
CheckQuotaHelper(nsPIDOMWindow* aWindow,
|
||||
mozilla::Mutex& aMutex);
|
||||
|
||||
bool PromptAndReturnQuotaIsDisabled();
|
||||
bool
|
||||
PromptAndReturnQuotaIsDisabled();
|
||||
|
||||
void Cancel();
|
||||
void
|
||||
Cancel();
|
||||
|
||||
static uint32_t GetQuotaPermission(nsIPrincipal* aPrincipal);
|
||||
static uint32_t
|
||||
GetQuotaPermission(nsIPrincipal* aPrincipal);
|
||||
|
||||
private:
|
||||
nsPIDOMWindow* mWindow;
|
||||
|
|
|
@ -9,12 +9,15 @@
|
|||
|
||||
#include "mozilla/dom/quota/QuotaCommon.h"
|
||||
|
||||
#include "PersistenceType.h"
|
||||
|
||||
class nsIOfflineStorage;
|
||||
class nsIRunnable;
|
||||
|
||||
BEGIN_QUOTA_NAMESPACE
|
||||
|
||||
class UsageRunnable;
|
||||
class OriginOrPatternString;
|
||||
class UsageInfo;
|
||||
|
||||
// An abstract interface for quota manager clients.
|
||||
// Each storage API must provide an implementation of this interface in order
|
||||
|
@ -70,14 +73,20 @@ public:
|
|||
|
||||
// Methods which are called on the IO thred.
|
||||
virtual nsresult
|
||||
InitOrigin(const nsACString& aOrigin, UsageRunnable* aUsageRunnable) = 0;
|
||||
InitOrigin(PersistenceType aPersistenceType,
|
||||
const nsACString& aGroup,
|
||||
const nsACString& aOrigin,
|
||||
UsageInfo* aUsageInfo) = 0;
|
||||
|
||||
virtual nsresult
|
||||
GetUsageForOrigin(const nsACString& aOrigin,
|
||||
UsageRunnable* aUsageRunnable) = 0;
|
||||
GetUsageForOrigin(PersistenceType aPersistenceType,
|
||||
const nsACString& aGroup,
|
||||
const nsACString& aOrigin,
|
||||
UsageInfo* aUsageInfo) = 0;
|
||||
|
||||
virtual void
|
||||
OnOriginClearCompleted(const nsACString& aPattern) = 0;
|
||||
OnOriginClearCompleted(PersistenceType aPersistenceType,
|
||||
const OriginOrPatternString& aOriginOrPattern) = 0;
|
||||
|
||||
virtual void
|
||||
ReleaseIOThreadObjects() = 0;
|
||||
|
|
|
@ -48,7 +48,7 @@ FileQuotaStream<FileStreamBase>::DoOpen()
|
|||
NS_ASSERTION(quotaManager, "Shouldn't be null!");
|
||||
|
||||
NS_ASSERTION(!mQuotaObject, "Creating quota object more than once?");
|
||||
mQuotaObject = quotaManager->GetQuotaObject(mOrigin,
|
||||
mQuotaObject = quotaManager->GetQuotaObject(mPersistenceType, mGroup, mOrigin,
|
||||
FileStreamBase::mOpenParams.localFile);
|
||||
|
||||
nsresult rv = FileStreamBase::DoOpen();
|
||||
|
@ -89,11 +89,13 @@ FileQuotaStreamWithWrite<FileStreamBase>::Write(const char* aBuf,
|
|||
NS_IMPL_ISUPPORTS_INHERITED0(FileInputStream, nsFileInputStream)
|
||||
|
||||
already_AddRefed<FileInputStream>
|
||||
FileInputStream::Create(const nsACString& aOrigin, nsIFile* aFile,
|
||||
int32_t aIOFlags, int32_t aPerm,
|
||||
FileInputStream::Create(PersistenceType aPersistenceType,
|
||||
const nsACString& aGroup, const nsACString& aOrigin,
|
||||
nsIFile* aFile, int32_t aIOFlags, int32_t aPerm,
|
||||
int32_t aBehaviorFlags)
|
||||
{
|
||||
nsRefPtr<FileInputStream> stream = new FileInputStream(aOrigin);
|
||||
nsRefPtr<FileInputStream> stream =
|
||||
new FileInputStream(aPersistenceType, aGroup, aOrigin);
|
||||
nsresult rv = stream->Init(aFile, aIOFlags, aPerm, aBehaviorFlags);
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
return stream.forget();
|
||||
|
@ -102,11 +104,13 @@ FileInputStream::Create(const nsACString& aOrigin, nsIFile* aFile,
|
|||
NS_IMPL_ISUPPORTS_INHERITED0(FileOutputStream, nsFileOutputStream)
|
||||
|
||||
already_AddRefed<FileOutputStream>
|
||||
FileOutputStream::Create(const nsACString& aOrigin, nsIFile* aFile,
|
||||
int32_t aIOFlags, int32_t aPerm,
|
||||
FileOutputStream::Create(PersistenceType aPersistenceType,
|
||||
const nsACString& aGroup, const nsACString& aOrigin,
|
||||
nsIFile* aFile, int32_t aIOFlags, int32_t aPerm,
|
||||
int32_t aBehaviorFlags)
|
||||
{
|
||||
nsRefPtr<FileOutputStream> stream = new FileOutputStream(aOrigin);
|
||||
nsRefPtr<FileOutputStream> stream =
|
||||
new FileOutputStream(aPersistenceType, aGroup, aOrigin);
|
||||
nsresult rv = stream->Init(aFile, aIOFlags, aPerm, aBehaviorFlags);
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
return stream.forget();
|
||||
|
@ -115,10 +119,12 @@ FileOutputStream::Create(const nsACString& aOrigin, nsIFile* aFile,
|
|||
NS_IMPL_ISUPPORTS_INHERITED0(FileStream, nsFileStream)
|
||||
|
||||
already_AddRefed<FileStream>
|
||||
FileStream::Create(const nsACString& aOrigin, nsIFile* aFile, int32_t aIOFlags,
|
||||
FileStream::Create(PersistenceType aPersistenceType, const nsACString& aGroup,
|
||||
const nsACString& aOrigin, nsIFile* aFile, int32_t aIOFlags,
|
||||
int32_t aPerm, int32_t aBehaviorFlags)
|
||||
{
|
||||
nsRefPtr<FileStream> stream = new FileStream(aOrigin);
|
||||
nsRefPtr<FileStream> stream =
|
||||
new FileStream(aPersistenceType, aGroup, aOrigin);
|
||||
nsresult rv = stream->Init(aFile, aIOFlags, aPerm, aBehaviorFlags);
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
return stream.forget();
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include "nsFileStreams.h"
|
||||
|
||||
#include "PersistenceType.h"
|
||||
#include "QuotaObject.h"
|
||||
|
||||
BEGIN_QUOTA_NAMESPACE
|
||||
|
@ -27,14 +28,17 @@ public:
|
|||
Close() MOZ_OVERRIDE;
|
||||
|
||||
protected:
|
||||
FileQuotaStream(const nsACString& aOrigin)
|
||||
: mOrigin(aOrigin)
|
||||
FileQuotaStream(PersistenceType aPersistenceType, const nsACString& aGroup,
|
||||
const nsACString& aOrigin)
|
||||
: mPersistenceType(aPersistenceType), mGroup(aGroup), mOrigin(aOrigin)
|
||||
{ }
|
||||
|
||||
// nsFileStreamBase override
|
||||
virtual nsresult
|
||||
DoOpen() MOZ_OVERRIDE;
|
||||
|
||||
PersistenceType mPersistenceType;
|
||||
nsCString mGroup;
|
||||
nsCString mOrigin;
|
||||
nsRefPtr<QuotaObject> mQuotaObject;
|
||||
};
|
||||
|
@ -48,8 +52,9 @@ public:
|
|||
Write(const char* aBuf, uint32_t aCount, uint32_t* _retval) MOZ_OVERRIDE;
|
||||
|
||||
protected:
|
||||
FileQuotaStreamWithWrite(const nsACString& aOrigin)
|
||||
: FileQuotaStream<FileStreamBase>(aOrigin)
|
||||
FileQuotaStreamWithWrite(PersistenceType aPersistenceType,
|
||||
const nsACString& aGroup, const nsACString& aOrigin)
|
||||
: FileQuotaStream<FileStreamBase>(aPersistenceType, aGroup, aOrigin)
|
||||
{ }
|
||||
};
|
||||
|
||||
|
@ -59,12 +64,14 @@ public:
|
|||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
static already_AddRefed<FileInputStream>
|
||||
Create(const nsACString& aOrigin, nsIFile* aFile, int32_t aIOFlags = -1,
|
||||
Create(PersistenceType aPersistenceType, const nsACString& aGroup,
|
||||
const nsACString& aOrigin, nsIFile* aFile, int32_t aIOFlags = -1,
|
||||
int32_t aPerm = -1, int32_t aBehaviorFlags = 0);
|
||||
|
||||
private:
|
||||
FileInputStream(const nsACString& aOrigin)
|
||||
: FileQuotaStream<nsFileInputStream>(aOrigin)
|
||||
FileInputStream(PersistenceType aPersistenceType, const nsACString& aGroup,
|
||||
const nsACString& aOrigin)
|
||||
: FileQuotaStream<nsFileInputStream>(aPersistenceType, aGroup, aOrigin)
|
||||
{ }
|
||||
|
||||
virtual ~FileInputStream() {
|
||||
|
@ -78,12 +85,15 @@ public:
|
|||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
static already_AddRefed<FileOutputStream>
|
||||
Create(const nsACString& aOrigin, nsIFile* aFile, int32_t aIOFlags = -1,
|
||||
Create(PersistenceType aPersistenceType, const nsACString& aGroup,
|
||||
const nsACString& aOrigin, nsIFile* aFile, int32_t aIOFlags = -1,
|
||||
int32_t aPerm = -1, int32_t aBehaviorFlags = 0);
|
||||
|
||||
private:
|
||||
FileOutputStream(const nsACString& aOrigin)
|
||||
: FileQuotaStreamWithWrite<nsFileOutputStream>(aOrigin)
|
||||
FileOutputStream(PersistenceType aPersistenceType, const nsACString& aGroup,
|
||||
const nsACString& aOrigin)
|
||||
: FileQuotaStreamWithWrite<nsFileOutputStream>(aPersistenceType, aGroup,
|
||||
aOrigin)
|
||||
{ }
|
||||
|
||||
virtual ~FileOutputStream() {
|
||||
|
@ -97,12 +107,14 @@ public:
|
|||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
static already_AddRefed<FileStream>
|
||||
Create(const nsACString& aOrigin, nsIFile* aFile, int32_t aIOFlags = -1,
|
||||
Create(PersistenceType aPersistenceType, const nsACString& aGroup,
|
||||
const nsACString& aOrigin, nsIFile* aFile, int32_t aIOFlags = -1,
|
||||
int32_t aPerm = -1, int32_t aBehaviorFlags = 0);
|
||||
|
||||
private:
|
||||
FileStream(const nsACString& aOrigin)
|
||||
: FileQuotaStreamWithWrite<nsFileStream>(aOrigin)
|
||||
FileStream(PersistenceType aPersistenceType, const nsACString& aGroup,
|
||||
const nsACString& aOrigin)
|
||||
: FileQuotaStreamWithWrite<nsFileStream>(aPersistenceType, aGroup, aOrigin)
|
||||
{ }
|
||||
|
||||
virtual ~FileStream() {
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_quota_origincollection_h__
|
||||
#define mozilla_dom_quota_origincollection_h__
|
||||
|
||||
#include "mozilla/dom/quota/QuotaCommon.h"
|
||||
|
||||
#include "nsHashKeys.h"
|
||||
#include "nsTHashtable.h"
|
||||
|
||||
#include "Utilities.h"
|
||||
|
||||
BEGIN_QUOTA_NAMESPACE
|
||||
|
||||
class OriginCollection
|
||||
{
|
||||
public:
|
||||
bool
|
||||
ContainsPattern(const nsACString& aPattern)
|
||||
{
|
||||
return mPatterns.Contains(aPattern);
|
||||
}
|
||||
|
||||
void
|
||||
AddPattern(const nsACString& aPattern)
|
||||
{
|
||||
MOZ_ASSERT(!mOrigins.Count());
|
||||
MOZ_ASSERT(!ContainsPattern(aPattern));
|
||||
mPatterns.AppendElement(aPattern);
|
||||
}
|
||||
|
||||
bool
|
||||
ContainsOrigin(const nsACString& aOrigin)
|
||||
{
|
||||
for (uint32_t index = 0; index < mPatterns.Length(); index++) {
|
||||
if (PatternMatchesOrigin(mPatterns[index], aOrigin)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return mOrigins.GetEntry(aOrigin);
|
||||
}
|
||||
|
||||
void
|
||||
AddOrigin(const nsACString& aOrigin)
|
||||
{
|
||||
MOZ_ASSERT(!ContainsOrigin(aOrigin));
|
||||
mOrigins.PutEntry(aOrigin);
|
||||
}
|
||||
|
||||
private:
|
||||
nsTArray<nsCString> mPatterns;
|
||||
nsTHashtable<nsCStringHashKey> mOrigins;
|
||||
};
|
||||
|
||||
END_QUOTA_NAMESPACE
|
||||
|
||||
#endif // mozilla_dom_quota_origincollection_h__
|
|
@ -26,6 +26,12 @@ public:
|
|||
return OriginOrPatternString(aPattern, false);
|
||||
}
|
||||
|
||||
static OriginOrPatternString
|
||||
FromNull()
|
||||
{
|
||||
return OriginOrPatternString();
|
||||
}
|
||||
|
||||
bool
|
||||
IsOrigin() const
|
||||
{
|
||||
|
@ -35,18 +41,31 @@ public:
|
|||
bool
|
||||
IsPattern() const
|
||||
{
|
||||
return !mIsOrigin;
|
||||
return mIsPattern;
|
||||
}
|
||||
|
||||
bool
|
||||
IsNull() const
|
||||
{
|
||||
return mIsNull;
|
||||
}
|
||||
|
||||
private:
|
||||
OriginOrPatternString(const nsACString& aOriginOrPattern, bool aIsOrigin)
|
||||
: nsCString(aOriginOrPattern), mIsOrigin(aIsOrigin)
|
||||
: nsCString(aOriginOrPattern),
|
||||
mIsOrigin(aIsOrigin), mIsPattern(!aIsOrigin), mIsNull(false)
|
||||
{ }
|
||||
|
||||
OriginOrPatternString()
|
||||
: mIsOrigin(false), mIsPattern(false), mIsNull(true)
|
||||
{ }
|
||||
|
||||
bool
|
||||
operator==(const OriginOrPatternString& aOther) MOZ_DELETE;
|
||||
|
||||
bool mIsOrigin;
|
||||
bool mIsPattern;
|
||||
bool mIsNull;
|
||||
};
|
||||
|
||||
END_QUOTA_NAMESPACE
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_quota_persistencetype_h__
|
||||
#define mozilla_dom_quota_persistencetype_h__
|
||||
|
||||
#include "mozilla/dom/quota/QuotaCommon.h"
|
||||
|
||||
#include "mozilla/dom/StorageTypeBinding.h"
|
||||
|
||||
BEGIN_QUOTA_NAMESPACE
|
||||
|
||||
enum PersistenceType
|
||||
{
|
||||
PERSISTENCE_TYPE_PERSISTENT = 0,
|
||||
PERSISTENCE_TYPE_TEMPORARY,
|
||||
|
||||
// Only needed for IPC serialization helper, should never be used in code.
|
||||
PERSISTENCE_TYPE_INVALID
|
||||
};
|
||||
|
||||
inline void
|
||||
PersistenceTypeToText(PersistenceType aPersistenceType, nsACString& aText)
|
||||
{
|
||||
switch (aPersistenceType) {
|
||||
case PERSISTENCE_TYPE_PERSISTENT:
|
||||
aText.AssignLiteral("persistent");
|
||||
return;
|
||||
case PERSISTENCE_TYPE_TEMPORARY:
|
||||
aText.AssignLiteral("temporary");
|
||||
return;
|
||||
|
||||
case PERSISTENCE_TYPE_INVALID:
|
||||
default:
|
||||
MOZ_CRASH("Bad persistence type value!");
|
||||
}
|
||||
|
||||
MOZ_ASSUME_UNREACHABLE("Should never get here!");
|
||||
}
|
||||
|
||||
inline PersistenceType
|
||||
PersistenceTypeFromText(const nsACString& aText)
|
||||
{
|
||||
if (aText.EqualsLiteral("persistent")) {
|
||||
return PERSISTENCE_TYPE_PERSISTENT;
|
||||
}
|
||||
|
||||
if (aText.EqualsLiteral("temporary")) {
|
||||
return PERSISTENCE_TYPE_TEMPORARY;
|
||||
}
|
||||
|
||||
MOZ_ASSUME_UNREACHABLE("Should never get here!");
|
||||
}
|
||||
|
||||
inline mozilla::dom::StorageType
|
||||
PersistenceTypeToStorage(PersistenceType aPersistenceType)
|
||||
{
|
||||
return mozilla::dom::StorageType(static_cast<int>(aPersistenceType));
|
||||
}
|
||||
|
||||
inline PersistenceType
|
||||
PersistenceTypeFromStorage(const Optional<mozilla::dom::StorageType>& aStorage,
|
||||
PersistenceType aDefaultPersistenceType)
|
||||
{
|
||||
if (aStorage.WasPassed()) {
|
||||
return PersistenceType(static_cast<int>(aStorage.Value()));
|
||||
}
|
||||
|
||||
return aDefaultPersistenceType;
|
||||
}
|
||||
|
||||
END_QUOTA_NAMESPACE
|
||||
|
||||
#endif // mozilla_dom_quota_persistencetype_h__
|
|
@ -24,14 +24,14 @@
|
|||
|
||||
BEGIN_QUOTA_NAMESPACE
|
||||
|
||||
#ifdef DEBUG
|
||||
void
|
||||
AssertIsOnIOThread();
|
||||
#else
|
||||
inline void
|
||||
AssertIsOnIOThread()
|
||||
{ }
|
||||
#endif
|
||||
|
||||
void
|
||||
AssertCurrentThreadOwnsQuotaMutex();
|
||||
|
||||
bool
|
||||
IsOnIOThread();
|
||||
|
||||
END_QUOTA_NAMESPACE
|
||||
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -12,13 +12,16 @@
|
|||
#include "nsIObserver.h"
|
||||
#include "nsIQuotaManager.h"
|
||||
|
||||
#include "mozilla/dom/Nullable.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
|
||||
#include "nsClassHashtable.h"
|
||||
#include "nsRefPtrHashtable.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
#include "ArrayCluster.h"
|
||||
#include "Client.h"
|
||||
#include "PersistenceType.h"
|
||||
#include "StoragePrivilege.h"
|
||||
|
||||
#define QUOTA_MANAGER_CONTRACTID "@mozilla.org/dom/quota/manager;1"
|
||||
|
@ -36,19 +39,28 @@ BEGIN_QUOTA_NAMESPACE
|
|||
class AcquireListener;
|
||||
class AsyncUsageRunnable;
|
||||
class CheckQuotaHelper;
|
||||
class CollectOriginsHelper;
|
||||
class FinalizeOriginEvictionRunnable;
|
||||
class GroupInfo;
|
||||
class GroupInfoPair;
|
||||
class OriginClearRunnable;
|
||||
class OriginInfo;
|
||||
class OriginOrPatternString;
|
||||
class QuotaObject;
|
||||
class ResetOrClearRunnable;
|
||||
struct SynchronizedOp;
|
||||
|
||||
class QuotaManager MOZ_FINAL : public nsIQuotaManager,
|
||||
public nsIObserver
|
||||
{
|
||||
friend class AsyncUsageRunnable;
|
||||
friend class CollectOriginsHelper;
|
||||
friend class FinalizeOriginEvictionRunnable;
|
||||
friend class GroupInfo;
|
||||
friend class OriginClearRunnable;
|
||||
friend class OriginInfo;
|
||||
friend class QuotaObject;
|
||||
friend class ResetOrClearRunnable;
|
||||
|
||||
enum MozBrowserPatternFlag
|
||||
{
|
||||
|
@ -81,23 +93,53 @@ public:
|
|||
static bool IsShuttingDown();
|
||||
|
||||
void
|
||||
InitQuotaForOrigin(const nsACString& aOrigin,
|
||||
int64_t aLimitBytes,
|
||||
int64_t aUsageBytes);
|
||||
InitQuotaForOrigin(PersistenceType aPersistenceType,
|
||||
const nsACString& aGroup,
|
||||
const nsACString& aOrigin,
|
||||
uint64_t aLimitBytes,
|
||||
uint64_t aUsageBytes,
|
||||
int64_t aAccessTime);
|
||||
|
||||
void
|
||||
DecreaseUsageForOrigin(const nsACString& aOrigin,
|
||||
DecreaseUsageForOrigin(PersistenceType aPersistenceType,
|
||||
const nsACString& aGroup,
|
||||
const nsACString& aOrigin,
|
||||
int64_t aSize);
|
||||
|
||||
void
|
||||
RemoveQuotaForPattern(const nsACString& aPattern);
|
||||
UpdateOriginAccessTime(PersistenceType aPersistenceType,
|
||||
const nsACString& aGroup,
|
||||
const nsACString& aOrigin);
|
||||
|
||||
void
|
||||
RemoveQuota();
|
||||
|
||||
void
|
||||
RemoveQuotaForPersistenceType(PersistenceType);
|
||||
|
||||
void
|
||||
RemoveQuotaForOrigin(PersistenceType aPersistenceType,
|
||||
const nsACString& aGroup,
|
||||
const nsACString& aOrigin)
|
||||
{
|
||||
MutexAutoLock lock(mQuotaMutex);
|
||||
LockedRemoveQuotaForOrigin(aPersistenceType, aGroup, aOrigin);
|
||||
}
|
||||
|
||||
void
|
||||
RemoveQuotaForPattern(PersistenceType aPersistenceType,
|
||||
const nsACString& aPattern);
|
||||
|
||||
already_AddRefed<QuotaObject>
|
||||
GetQuotaObject(const nsACString& aOrigin,
|
||||
GetQuotaObject(PersistenceType aPersistenceType,
|
||||
const nsACString& aGroup,
|
||||
const nsACString& aOrigin,
|
||||
nsIFile* aFile);
|
||||
|
||||
already_AddRefed<QuotaObject>
|
||||
GetQuotaObject(const nsACString& aOrigin,
|
||||
GetQuotaObject(PersistenceType aPersistenceType,
|
||||
const nsACString& aGroup,
|
||||
const nsACString& aOrigin,
|
||||
const nsAString& aPath);
|
||||
|
||||
// Set the Window that the current thread is doing operations for.
|
||||
|
@ -148,6 +190,7 @@ public:
|
|||
// complete before dispatching the given runnable.
|
||||
nsresult
|
||||
WaitForOpenAllowed(const OriginOrPatternString& aOriginOrPattern,
|
||||
Nullable<PersistenceType> aPersistenceType,
|
||||
nsIAtom* aId,
|
||||
nsIRunnable* aRunnable);
|
||||
|
||||
|
@ -178,25 +221,39 @@ public:
|
|||
|
||||
void
|
||||
AllowNextSynchronizedOp(const OriginOrPatternString& aOriginOrPattern,
|
||||
Nullable<PersistenceType> aPersistenceType,
|
||||
nsIAtom* aId);
|
||||
|
||||
bool
|
||||
IsClearOriginPending(const nsACString& aPattern)
|
||||
{
|
||||
return !!FindSynchronizedOp(aPattern, nullptr);
|
||||
return !!FindSynchronizedOp(aPattern, Nullable<PersistenceType>(), nullptr);
|
||||
}
|
||||
|
||||
nsresult
|
||||
GetDirectoryForOrigin(const nsACString& aASCIIOrigin,
|
||||
GetDirectoryForOrigin(PersistenceType aPersistenceType,
|
||||
const nsACString& aASCIIOrigin,
|
||||
nsIFile** aDirectory) const;
|
||||
|
||||
nsresult
|
||||
EnsureOriginIsInitialized(const nsACString& aOrigin,
|
||||
EnsureOriginIsInitialized(PersistenceType aPersistenceType,
|
||||
const nsACString& aGroup,
|
||||
const nsACString& aOrigin,
|
||||
bool aTrackQuota,
|
||||
nsIFile** aDirectory);
|
||||
|
||||
void
|
||||
OriginClearCompleted(const nsACString& aPattern);
|
||||
OriginClearCompleted(PersistenceType aPersistenceType,
|
||||
const OriginOrPatternString& aOriginOrPattern);
|
||||
|
||||
void
|
||||
ResetOrClearCompleted();
|
||||
|
||||
void
|
||||
AssertCurrentThreadOwnsQuotaMutex()
|
||||
{
|
||||
mQuotaMutex.AssertCurrentThreadOwns();
|
||||
}
|
||||
|
||||
nsIThread*
|
||||
IOThread()
|
||||
|
@ -209,31 +266,53 @@ public:
|
|||
GetClient(Client::Type aClientType);
|
||||
|
||||
const nsString&
|
||||
GetBaseDirectory() const
|
||||
GetStoragePath(PersistenceType aPersistenceType) const
|
||||
{
|
||||
return mStorageBasePath;
|
||||
if (aPersistenceType == PERSISTENCE_TYPE_PERSISTENT) {
|
||||
return mPersistentStoragePath;
|
||||
}
|
||||
|
||||
NS_ASSERTION(aPersistenceType == PERSISTENCE_TYPE_TEMPORARY, "Huh?");
|
||||
|
||||
return mTemporaryStoragePath;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
GetGroupLimit() const
|
||||
{
|
||||
return mTemporaryStorageLimit / 5;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
GetStorageQuotaMB();
|
||||
|
||||
static already_AddRefed<nsIAtom>
|
||||
GetStorageId(const nsACString& aOrigin,
|
||||
GetStorageId(PersistenceType aPersistenceType,
|
||||
const nsACString& aOrigin,
|
||||
const nsAString& aName);
|
||||
|
||||
static nsresult
|
||||
GetASCIIOriginFromURI(nsIURI* aURI,
|
||||
uint32_t aAppId,
|
||||
bool aInMozBrowser,
|
||||
nsACString& aASCIIOrigin);
|
||||
GetInfoFromURI(nsIURI* aURI,
|
||||
uint32_t aAppId,
|
||||
bool aInMozBrowser,
|
||||
nsACString* aGroup,
|
||||
nsACString* aASCIIOrigin,
|
||||
StoragePrivilege* aPrivilege,
|
||||
PersistenceType* aDefaultPersistenceType);
|
||||
|
||||
static nsresult
|
||||
GetASCIIOriginFromPrincipal(nsIPrincipal* aPrincipal,
|
||||
nsACString& aASCIIOrigin);
|
||||
GetInfoFromPrincipal(nsIPrincipal* aPrincipal,
|
||||
nsACString* aGroup,
|
||||
nsACString* aASCIIOrigin,
|
||||
StoragePrivilege* aPrivilege,
|
||||
PersistenceType* aDefaultPersistenceType);
|
||||
|
||||
static nsresult
|
||||
GetASCIIOriginFromWindow(nsPIDOMWindow* aWindow,
|
||||
nsACString& aASCIIOrigin);
|
||||
GetInfoFromWindow(nsPIDOMWindow* aWindow,
|
||||
nsACString* aGroup,
|
||||
nsACString* aASCIIOrigin,
|
||||
StoragePrivilege* aPrivilege,
|
||||
PersistenceType* aDefaultPersistenceType);
|
||||
|
||||
static void
|
||||
GetOriginPatternString(uint32_t aAppId, bool aBrowserOnly,
|
||||
|
@ -272,6 +351,15 @@ private:
|
|||
bool
|
||||
LockedQuotaIsLifted();
|
||||
|
||||
uint64_t
|
||||
LockedCollectOriginsForEviction(uint64_t aMinSizeToBeFreed,
|
||||
nsTArray<OriginInfo*>& aOriginInfos);
|
||||
|
||||
void
|
||||
LockedRemoveQuotaForOrigin(PersistenceType aPersistenceType,
|
||||
const nsACString& aGroup,
|
||||
const nsACString& aOrigin);
|
||||
|
||||
nsresult
|
||||
AcquireExclusiveAccess(const nsACString& aOrigin,
|
||||
nsIOfflineStorage* aStorage,
|
||||
|
@ -279,19 +367,50 @@ private:
|
|||
WaitingOnStoragesCallback aCallback,
|
||||
void* aClosure);
|
||||
|
||||
void
|
||||
AddSynchronizedOp(const OriginOrPatternString& aOriginOrPattern,
|
||||
Nullable<PersistenceType> aPersistenceType,
|
||||
nsIAtom* aId);
|
||||
|
||||
nsresult
|
||||
RunSynchronizedOp(nsIOfflineStorage* aStorage,
|
||||
SynchronizedOp* aOp);
|
||||
|
||||
SynchronizedOp*
|
||||
FindSynchronizedOp(const nsACString& aPattern,
|
||||
Nullable<PersistenceType> aPersistenceType,
|
||||
nsISupports* aId);
|
||||
|
||||
nsresult
|
||||
MaybeUpgradeIndexedDBDirectory();
|
||||
|
||||
nsresult
|
||||
InitializeOrigin(PersistenceType aPersistenceType,
|
||||
const nsACString& aGroup,
|
||||
const nsACString& aOrigin,
|
||||
bool aTrackQuota,
|
||||
int64_t aAccessTime,
|
||||
nsIFile* aDirectory);
|
||||
|
||||
nsresult
|
||||
ClearStoragesForApp(uint32_t aAppId, bool aBrowserOnly);
|
||||
|
||||
nsresult
|
||||
MaybeUpgradeOriginDirectory(nsIFile* aDirectory);
|
||||
void
|
||||
CheckTemporaryStorageLimits();
|
||||
|
||||
// Collect inactive and the least recently used origins.
|
||||
uint64_t
|
||||
CollectOriginsForEviction(uint64_t aMinSizeToBeFreed,
|
||||
nsTArray<OriginInfo*>& aOriginInfos);
|
||||
|
||||
void
|
||||
DeleteTemporaryFilesForOrigin(const nsACString& aOrigin);
|
||||
|
||||
void
|
||||
FinalizeOriginEviction(nsTArray<nsCString>& aOrigins);
|
||||
|
||||
void
|
||||
SaveOriginAccessTime(const nsACString& aOrigin, int64_t aTimestamp);
|
||||
|
||||
void
|
||||
ReleaseIOThreadObjects()
|
||||
|
@ -309,12 +428,47 @@ private:
|
|||
const nsACString& aOrigin,
|
||||
nsAutoCString& _retval);
|
||||
|
||||
static PLDHashOperator
|
||||
RemoveQuotaForPersistenceTypeCallback(const nsACString& aKey,
|
||||
nsAutoPtr<GroupInfoPair>& aValue,
|
||||
void* aUserArg);
|
||||
|
||||
static PLDHashOperator
|
||||
RemoveQuotaCallback(const nsACString& aKey,
|
||||
nsAutoPtr<GroupInfoPair>& aValue,
|
||||
void* aUserArg);
|
||||
|
||||
static PLDHashOperator
|
||||
RemoveQuotaForPatternCallback(const nsACString& aKey,
|
||||
nsAutoPtr<GroupInfoPair>& aValue,
|
||||
void* aUserArg);
|
||||
|
||||
static PLDHashOperator
|
||||
GetOriginsExceedingGroupLimit(const nsACString& aKey,
|
||||
GroupInfoPair* aValue,
|
||||
void* aUserArg);
|
||||
|
||||
static PLDHashOperator
|
||||
GetAllTemporaryStorageOrigins(const nsACString& aKey,
|
||||
GroupInfoPair* aValue,
|
||||
void* aUserArg);
|
||||
|
||||
static PLDHashOperator
|
||||
AddTemporaryStorageOrigins(const nsACString& aKey,
|
||||
ArrayCluster<nsIOfflineStorage*>* aValue,
|
||||
void* aUserArg);
|
||||
|
||||
static PLDHashOperator
|
||||
GetInactiveTemporaryStorageOrigins(const nsACString& aKey,
|
||||
GroupInfoPair* aValue,
|
||||
void* aUserArg);
|
||||
|
||||
// TLS storage index for the current thread's window.
|
||||
unsigned int mCurrentWindowIndex;
|
||||
|
||||
mozilla::Mutex mQuotaMutex;
|
||||
|
||||
nsRefPtrHashtable<nsCStringHashKey, OriginInfo> mOriginInfos;
|
||||
nsClassHashtable<nsCStringHashKey, GroupInfoPair> mGroupInfoPairs;
|
||||
|
||||
// A map of Windows to the corresponding quota helper.
|
||||
nsRefPtrHashtable<nsPtrHashKey<nsPIDOMWindow>,
|
||||
|
@ -339,7 +493,15 @@ private:
|
|||
|
||||
nsAutoTArray<nsRefPtr<Client>, Client::TYPE_MAX> mClients;
|
||||
|
||||
nsString mStorageBasePath;
|
||||
nsString mIndexedDBPath;
|
||||
nsString mPersistentStoragePath;
|
||||
nsString mTemporaryStoragePath;
|
||||
|
||||
uint64_t mTemporaryStorageLimit;
|
||||
uint64_t mTemporaryStorageUsage;
|
||||
bool mTemporaryStorageInitialized;
|
||||
|
||||
bool mStorageAreaInitialized;
|
||||
};
|
||||
|
||||
class AutoEnterWindow
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "QuotaObject.h"
|
||||
|
||||
#include "QuotaManager.h"
|
||||
#include "Utilities.h"
|
||||
|
||||
USING_QUOTA_NAMESPACE
|
||||
|
||||
|
@ -68,10 +69,24 @@ QuotaObject::UpdateSize(int64_t aSize)
|
|||
|
||||
MutexAutoLock lock(quotaManager->mQuotaMutex);
|
||||
|
||||
if (mOriginInfo) {
|
||||
mOriginInfo->mUsage -= mSize;
|
||||
mSize = aSize;
|
||||
mOriginInfo->mUsage += mSize;
|
||||
if (!mOriginInfo) {
|
||||
return;
|
||||
}
|
||||
|
||||
GroupInfo* groupInfo = mOriginInfo->mGroupInfo;
|
||||
|
||||
if (groupInfo->IsForTemporaryStorage()) {
|
||||
quotaManager->mTemporaryStorageUsage -= mSize;
|
||||
}
|
||||
groupInfo->mUsage -= mSize;
|
||||
mOriginInfo->mUsage -= mSize;
|
||||
|
||||
mSize = aSize;
|
||||
|
||||
mOriginInfo->mUsage += mSize;
|
||||
groupInfo->mUsage += mSize;
|
||||
if (groupInfo->IsForTemporaryStorage()) {
|
||||
quotaManager->mTemporaryStorageUsage += mSize;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -89,60 +104,194 @@ QuotaObject::MaybeAllocateMoreSpace(int64_t aOffset, int32_t aCount)
|
|||
return true;
|
||||
}
|
||||
|
||||
int64_t newUsage = mOriginInfo->mUsage - mSize + end;
|
||||
if (newUsage > mOriginInfo->mLimit) {
|
||||
// This will block the thread, but it will also drop the mutex while
|
||||
// waiting. The mutex will be reacquired again when the waiting is finished.
|
||||
if (!quotaManager->LockedQuotaIsLifted()) {
|
||||
return false;
|
||||
}
|
||||
GroupInfo* groupInfo = mOriginInfo->mGroupInfo;
|
||||
|
||||
// Threads raced, the origin info removal has been done by some other
|
||||
// thread.
|
||||
if (!mOriginInfo) {
|
||||
// The other thread could allocate more space.
|
||||
if (end > mSize) {
|
||||
mSize = end;
|
||||
if (groupInfo->IsForPersistentStorage()) {
|
||||
uint64_t newUsage = mOriginInfo->mUsage - mSize + end;
|
||||
|
||||
if (newUsage > mOriginInfo->mLimit) {
|
||||
// This will block the thread, but it will also drop the mutex while
|
||||
// waiting. The mutex will be reacquired again when the waiting is
|
||||
// finished.
|
||||
if (!quotaManager->LockedQuotaIsLifted()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Threads raced, the origin info removal has been done by some other
|
||||
// thread.
|
||||
if (!mOriginInfo) {
|
||||
// The other thread could allocate more space.
|
||||
if (end > mSize) {
|
||||
mSize = end;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
nsCString group = mOriginInfo->mGroupInfo->mGroup;
|
||||
nsCString origin = mOriginInfo->mOrigin;
|
||||
|
||||
mOriginInfo->LockedClearOriginInfos();
|
||||
NS_ASSERTION(!mOriginInfo,
|
||||
"Should have cleared in LockedClearOriginInfos!");
|
||||
|
||||
quotaManager->LockedRemoveQuotaForOrigin(PERSISTENCE_TYPE_PERSISTENT,
|
||||
group, origin);
|
||||
|
||||
// Some other thread could increase the size without blocking (increasing
|
||||
// the origin usage without hitting the limit), but no more than this one.
|
||||
NS_ASSERTION(mSize < end, "This shouldn't happen!");
|
||||
|
||||
mSize = end;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
nsCString origin = mOriginInfo->mOrigin;
|
||||
mOriginInfo->mUsage = newUsage;
|
||||
|
||||
mOriginInfo->LockedClearOriginInfos();
|
||||
NS_ASSERTION(!mOriginInfo,
|
||||
"Should have cleared in LockedClearOriginInfos!");
|
||||
|
||||
quotaManager->mOriginInfos.Remove(origin);
|
||||
|
||||
// Some other thread could increase the size without blocking (increasing
|
||||
// the origin usage without hitting the limit), but no more than this one.
|
||||
NS_ASSERTION(mSize < end, "This shouldn't happen!");
|
||||
groupInfo->mUsage = groupInfo->mUsage - mSize + end;
|
||||
|
||||
mSize = end;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
NS_ASSERTION(groupInfo->mPersistenceType == PERSISTENCE_TYPE_TEMPORARY,
|
||||
"Huh?");
|
||||
|
||||
uint64_t delta = end - mSize;
|
||||
|
||||
uint64_t newUsage = mOriginInfo->mUsage + delta;
|
||||
|
||||
// Temporary storage has no limit for origin usage (there's a group and the
|
||||
// global limit though).
|
||||
|
||||
uint64_t newGroupUsage = groupInfo->mUsage + delta;
|
||||
|
||||
// Temporary storage has a hard limit for group usage (20 % of the global
|
||||
// limit).
|
||||
if (newGroupUsage > quotaManager->GetGroupLimit()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint64_t newTemporaryStorageUsage = quotaManager->mTemporaryStorageUsage +
|
||||
delta;
|
||||
|
||||
if (newTemporaryStorageUsage > quotaManager->mTemporaryStorageLimit) {
|
||||
// This will block the thread without holding the lock while waitting.
|
||||
|
||||
nsAutoTArray<OriginInfo*, 10> originInfos;
|
||||
uint64_t sizeToBeFreed =
|
||||
quotaManager->LockedCollectOriginsForEviction(delta, originInfos);
|
||||
|
||||
if (!sizeToBeFreed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
NS_ASSERTION(sizeToBeFreed >= delta, "Huh?");
|
||||
|
||||
{
|
||||
MutexAutoUnlock autoUnlock(quotaManager->mQuotaMutex);
|
||||
|
||||
for (uint32_t i = 0; i < originInfos.Length(); i++) {
|
||||
quotaManager->DeleteTemporaryFilesForOrigin(originInfos[i]->mOrigin);
|
||||
}
|
||||
}
|
||||
|
||||
// Relocked.
|
||||
|
||||
NS_ASSERTION(mOriginInfo, "How come?!");
|
||||
|
||||
nsTArray<nsCString> origins;
|
||||
for (uint32_t i = 0; i < originInfos.Length(); i++) {
|
||||
OriginInfo* originInfo = originInfos[i];
|
||||
|
||||
NS_ASSERTION(originInfo != mOriginInfo, "Deleted itself!");
|
||||
|
||||
nsCString group = originInfo->mGroupInfo->mGroup;
|
||||
nsCString origin = originInfo->mOrigin;
|
||||
quotaManager->LockedRemoveQuotaForOrigin(PERSISTENCE_TYPE_TEMPORARY,
|
||||
group, origin);
|
||||
|
||||
#ifdef DEBUG
|
||||
originInfos[i] = nullptr;
|
||||
#endif
|
||||
|
||||
origins.AppendElement(origin);
|
||||
}
|
||||
|
||||
// We unlocked and relocked several times so we need to recompute all the
|
||||
// essential variables and recheck the group limit.
|
||||
|
||||
delta = end - mSize;
|
||||
|
||||
newUsage = mOriginInfo->mUsage + delta;
|
||||
|
||||
newGroupUsage = groupInfo->mUsage + delta;
|
||||
|
||||
if (newGroupUsage > quotaManager->GetGroupLimit()) {
|
||||
// Unfortunately some other thread increased the group usage in the
|
||||
// meantime and we are not below the group limit anymore.
|
||||
|
||||
// However, the origin eviction must be finalized in this case too.
|
||||
MutexAutoUnlock autoUnlock(quotaManager->mQuotaMutex);
|
||||
|
||||
quotaManager->FinalizeOriginEviction(origins);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
newTemporaryStorageUsage = quotaManager->mTemporaryStorageUsage + delta;
|
||||
|
||||
NS_ASSERTION(newTemporaryStorageUsage <=
|
||||
quotaManager->mTemporaryStorageLimit, "How come?!");
|
||||
|
||||
// Ok, we successfully freed enough space and the operation can continue
|
||||
// without throwing the quota error.
|
||||
|
||||
mOriginInfo->mUsage = newUsage;
|
||||
groupInfo->mUsage = newGroupUsage;
|
||||
quotaManager->mTemporaryStorageUsage = newTemporaryStorageUsage;;
|
||||
|
||||
// Some other thread could increase the size in the meantime, but no more
|
||||
// than this one.
|
||||
NS_ASSERTION(mSize < end, "This shouldn't happen!");
|
||||
mSize = end;
|
||||
|
||||
// Finally, release IO thread only objects and allow next synchronized
|
||||
// ops for the evicted origins.
|
||||
MutexAutoUnlock autoUnlock(quotaManager->mQuotaMutex);
|
||||
|
||||
quotaManager->FinalizeOriginEviction(origins);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
mOriginInfo->mUsage = newUsage;
|
||||
groupInfo->mUsage = newGroupUsage;
|
||||
quotaManager->mTemporaryStorageUsage = newTemporaryStorageUsage;
|
||||
|
||||
mSize = end;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
void
|
||||
OriginInfo::LockedClearOriginInfos()
|
||||
OriginInfo::LockedDecreaseUsage(int64_t aSize)
|
||||
{
|
||||
QuotaManager* quotaManager = QuotaManager::Get();
|
||||
NS_ASSERTION(quotaManager, "Shouldn't be null!");
|
||||
AssertCurrentThreadOwnsQuotaMutex();
|
||||
|
||||
quotaManager->mQuotaMutex.AssertCurrentThreadOwns();
|
||||
mUsage -= aSize;
|
||||
|
||||
mQuotaObjects.EnumerateRead(ClearOriginInfoCallback, nullptr);
|
||||
mGroupInfo->mUsage -= aSize;
|
||||
|
||||
if (mGroupInfo->IsForTemporaryStorage()) {
|
||||
QuotaManager* quotaManager = QuotaManager::Get();
|
||||
NS_ASSERTION(quotaManager, "Shouldn't be null!");
|
||||
|
||||
quotaManager->mTemporaryStorageUsage -= aSize;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// static
|
||||
PLDHashOperator
|
||||
|
@ -157,3 +306,118 @@ OriginInfo::ClearOriginInfoCallback(const nsAString& aKey,
|
|||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
already_AddRefed<OriginInfo>
|
||||
GroupInfo::LockedGetOriginInfo(const nsACString& aOrigin)
|
||||
{
|
||||
AssertCurrentThreadOwnsQuotaMutex();
|
||||
|
||||
for (uint32_t index = 0; index < mOriginInfos.Length(); index++) {
|
||||
nsRefPtr<OriginInfo>& originInfo = mOriginInfos[index];
|
||||
|
||||
if (originInfo->mOrigin == aOrigin) {
|
||||
nsRefPtr<OriginInfo> result = originInfo;
|
||||
return result.forget();
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
GroupInfo::LockedAddOriginInfo(OriginInfo* aOriginInfo)
|
||||
{
|
||||
AssertCurrentThreadOwnsQuotaMutex();
|
||||
|
||||
NS_ASSERTION(!mOriginInfos.Contains(aOriginInfo),
|
||||
"Replacing an existing entry!");
|
||||
mOriginInfos.AppendElement(aOriginInfo);
|
||||
|
||||
mUsage += aOriginInfo->mUsage;
|
||||
|
||||
if (IsForTemporaryStorage()) {
|
||||
QuotaManager* quotaManager = QuotaManager::Get();
|
||||
NS_ASSERTION(quotaManager, "Shouldn't be null!");
|
||||
|
||||
quotaManager->mTemporaryStorageUsage += aOriginInfo->mUsage;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GroupInfo::LockedRemoveOriginInfo(const nsACString& aOrigin)
|
||||
{
|
||||
AssertCurrentThreadOwnsQuotaMutex();
|
||||
|
||||
for (uint32_t index = 0; index < mOriginInfos.Length(); index++) {
|
||||
if (mOriginInfos[index]->mOrigin == aOrigin) {
|
||||
mUsage -= mOriginInfos[index]->mUsage;
|
||||
|
||||
if (IsForTemporaryStorage()) {
|
||||
QuotaManager* quotaManager = QuotaManager::Get();
|
||||
NS_ASSERTION(quotaManager, "Shouldn't be null!");
|
||||
|
||||
quotaManager->mTemporaryStorageUsage -= mOriginInfos[index]->mUsage;
|
||||
}
|
||||
|
||||
mOriginInfos.RemoveElementAt(index);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GroupInfo::LockedRemoveOriginInfos()
|
||||
{
|
||||
AssertCurrentThreadOwnsQuotaMutex();
|
||||
|
||||
for (uint32_t index = mOriginInfos.Length(); index > 0; index--) {
|
||||
mUsage -= mOriginInfos[index - 1]->mUsage;
|
||||
|
||||
if (IsForTemporaryStorage()) {
|
||||
QuotaManager* quotaManager = QuotaManager::Get();
|
||||
NS_ASSERTION(quotaManager, "Shouldn't be null!");
|
||||
|
||||
quotaManager->mTemporaryStorageUsage -= mOriginInfos[index - 1]->mUsage;
|
||||
}
|
||||
|
||||
mOriginInfos.RemoveElementAt(index - 1);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GroupInfo::LockedRemoveOriginInfosForPattern(const nsACString& aPattern)
|
||||
{
|
||||
AssertCurrentThreadOwnsQuotaMutex();
|
||||
|
||||
for (uint32_t index = mOriginInfos.Length(); index > 0; index--) {
|
||||
if (PatternMatchesOrigin(aPattern, mOriginInfos[index - 1]->mOrigin)) {
|
||||
mUsage -= mOriginInfos[index - 1]->mUsage;
|
||||
|
||||
if (IsForTemporaryStorage()) {
|
||||
QuotaManager* quotaManager = QuotaManager::Get();
|
||||
NS_ASSERTION(quotaManager, "Shouldn't be null!");
|
||||
|
||||
quotaManager->mTemporaryStorageUsage -= mOriginInfos[index - 1]->mUsage;
|
||||
}
|
||||
|
||||
mOriginInfos.RemoveElementAt(index - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsRefPtr<GroupInfo>&
|
||||
GroupInfoPair::GetGroupInfoForPersistenceType(PersistenceType aPersistenceType)
|
||||
{
|
||||
switch (aPersistenceType) {
|
||||
case PERSISTENCE_TYPE_PERSISTENT:
|
||||
return mPersistentStorageGroupInfo;
|
||||
case PERSISTENCE_TYPE_TEMPORARY:
|
||||
return mTemporaryStorageGroupInfo;
|
||||
|
||||
case PERSISTENCE_TYPE_INVALID:
|
||||
default:
|
||||
MOZ_CRASH("Bad persistence type value!");
|
||||
return mPersistentStorageGroupInfo;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,8 +11,12 @@
|
|||
|
||||
#include "nsDataHashtable.h"
|
||||
|
||||
#include "PersistenceType.h"
|
||||
|
||||
BEGIN_QUOTA_NAMESPACE
|
||||
|
||||
class GroupInfo;
|
||||
class GroupInfoPair;
|
||||
class OriginInfo;
|
||||
class QuotaManager;
|
||||
|
||||
|
@ -37,10 +41,14 @@ public:
|
|||
private:
|
||||
QuotaObject(OriginInfo* aOriginInfo, const nsAString& aPath, int64_t aSize)
|
||||
: mOriginInfo(aOriginInfo), mPath(aPath), mSize(aSize)
|
||||
{ }
|
||||
{
|
||||
MOZ_COUNT_CTOR(QuotaObject);
|
||||
}
|
||||
|
||||
virtual ~QuotaObject()
|
||||
{ }
|
||||
~QuotaObject()
|
||||
{
|
||||
MOZ_COUNT_DTOR(QuotaObject);
|
||||
}
|
||||
|
||||
mozilla::ThreadSafeAutoRefCnt mRefCnt;
|
||||
|
||||
|
@ -51,27 +59,51 @@ private:
|
|||
|
||||
class OriginInfo
|
||||
{
|
||||
friend class GroupInfo;
|
||||
friend class QuotaManager;
|
||||
friend class QuotaObject;
|
||||
|
||||
public:
|
||||
OriginInfo(const nsACString& aOrigin, int64_t aLimit, int64_t aUsage)
|
||||
: mOrigin(aOrigin), mLimit(aLimit), mUsage(aUsage)
|
||||
OriginInfo(GroupInfo* aGroupInfo, const nsACString& aOrigin, uint64_t aLimit,
|
||||
uint64_t aUsage, int64_t aAccessTime)
|
||||
: mGroupInfo(aGroupInfo), mOrigin(aOrigin), mLimit(aLimit), mUsage(aUsage),
|
||||
mAccessTime(aAccessTime)
|
||||
{
|
||||
MOZ_COUNT_CTOR(OriginInfo);
|
||||
}
|
||||
|
||||
~OriginInfo()
|
||||
{
|
||||
MOZ_COUNT_DTOR(OriginInfo);
|
||||
}
|
||||
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(OriginInfo)
|
||||
|
||||
int64_t
|
||||
AccessTime() const
|
||||
{
|
||||
return mAccessTime;
|
||||
}
|
||||
|
||||
private:
|
||||
void
|
||||
#ifdef DEBUG
|
||||
LockedClearOriginInfos();
|
||||
#else
|
||||
LockedDecreaseUsage(int64_t aSize);
|
||||
|
||||
void
|
||||
LockedUpdateAccessTime(int64_t aAccessTime)
|
||||
{
|
||||
AssertCurrentThreadOwnsQuotaMutex();
|
||||
|
||||
mAccessTime = aAccessTime;
|
||||
}
|
||||
|
||||
void
|
||||
LockedClearOriginInfos()
|
||||
{
|
||||
AssertCurrentThreadOwnsQuotaMutex();
|
||||
|
||||
mQuotaObjects.EnumerateRead(ClearOriginInfoCallback, nullptr);
|
||||
}
|
||||
#endif
|
||||
|
||||
static PLDHashOperator
|
||||
ClearOriginInfoCallback(const nsAString& aKey,
|
||||
|
@ -79,9 +111,153 @@ private:
|
|||
|
||||
nsDataHashtable<nsStringHashKey, QuotaObject*> mQuotaObjects;
|
||||
|
||||
GroupInfo* mGroupInfo;
|
||||
nsCString mOrigin;
|
||||
int64_t mLimit;
|
||||
int64_t mUsage;
|
||||
uint64_t mLimit;
|
||||
uint64_t mUsage;
|
||||
int64_t mAccessTime;
|
||||
};
|
||||
|
||||
class OriginInfoLRUComparator
|
||||
{
|
||||
public:
|
||||
bool
|
||||
Equals(const OriginInfo* a, const OriginInfo* b) const
|
||||
{
|
||||
return
|
||||
a && b ? a->AccessTime() == b->AccessTime() : !a && !b ? true : false;
|
||||
}
|
||||
|
||||
bool
|
||||
LessThan(const OriginInfo* a, const OriginInfo* b) const
|
||||
{
|
||||
return a && b ? a->AccessTime() < b->AccessTime() : b ? true : false;
|
||||
}
|
||||
};
|
||||
|
||||
class GroupInfo
|
||||
{
|
||||
friend class GroupInfoPair;
|
||||
friend class OriginInfo;
|
||||
friend class QuotaManager;
|
||||
friend class QuotaObject;
|
||||
|
||||
public:
|
||||
GroupInfo(PersistenceType aPersistenceType, const nsACString& aGroup)
|
||||
: mPersistenceType(aPersistenceType), mGroup(aGroup), mUsage(0)
|
||||
{
|
||||
MOZ_COUNT_CTOR(GroupInfo);
|
||||
}
|
||||
|
||||
~GroupInfo()
|
||||
{
|
||||
MOZ_COUNT_DTOR(GroupInfo);
|
||||
}
|
||||
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GroupInfo)
|
||||
|
||||
bool
|
||||
IsForPersistentStorage() const
|
||||
{
|
||||
return mPersistenceType == PERSISTENCE_TYPE_PERSISTENT;
|
||||
}
|
||||
|
||||
bool
|
||||
IsForTemporaryStorage() const
|
||||
{
|
||||
return mPersistenceType == PERSISTENCE_TYPE_TEMPORARY;
|
||||
}
|
||||
|
||||
private:
|
||||
already_AddRefed<OriginInfo>
|
||||
LockedGetOriginInfo(const nsACString& aOrigin);
|
||||
|
||||
void
|
||||
LockedAddOriginInfo(OriginInfo* aOriginInfo);
|
||||
|
||||
void
|
||||
LockedRemoveOriginInfo(const nsACString& aOrigin);
|
||||
|
||||
void
|
||||
LockedRemoveOriginInfos();
|
||||
|
||||
void
|
||||
LockedRemoveOriginInfosForPattern(const nsACString& aPattern);
|
||||
|
||||
bool
|
||||
LockedHasOriginInfos()
|
||||
{
|
||||
AssertCurrentThreadOwnsQuotaMutex();
|
||||
|
||||
return !mOriginInfos.IsEmpty();
|
||||
}
|
||||
|
||||
nsTArray<nsRefPtr<OriginInfo> > mOriginInfos;
|
||||
|
||||
PersistenceType mPersistenceType;
|
||||
nsCString mGroup;
|
||||
uint64_t mUsage;
|
||||
};
|
||||
|
||||
class GroupInfoPair
|
||||
{
|
||||
friend class QuotaManager;
|
||||
|
||||
public:
|
||||
GroupInfoPair()
|
||||
{
|
||||
MOZ_COUNT_CTOR(GroupInfoPair);
|
||||
}
|
||||
|
||||
~GroupInfoPair()
|
||||
{
|
||||
MOZ_COUNT_DTOR(GroupInfoPair);
|
||||
}
|
||||
|
||||
private:
|
||||
already_AddRefed<GroupInfo>
|
||||
LockedGetGroupInfo(PersistenceType aPersistenceType)
|
||||
{
|
||||
AssertCurrentThreadOwnsQuotaMutex();
|
||||
|
||||
nsRefPtr<GroupInfo> groupInfo =
|
||||
GetGroupInfoForPersistenceType(aPersistenceType);
|
||||
return groupInfo.forget();
|
||||
}
|
||||
|
||||
void
|
||||
LockedSetGroupInfo(GroupInfo* aGroupInfo)
|
||||
{
|
||||
AssertCurrentThreadOwnsQuotaMutex();
|
||||
|
||||
nsRefPtr<GroupInfo>& groupInfo =
|
||||
GetGroupInfoForPersistenceType(aGroupInfo->mPersistenceType);
|
||||
groupInfo = aGroupInfo;
|
||||
}
|
||||
|
||||
void
|
||||
LockedClearGroupInfo(PersistenceType aPersistenceType)
|
||||
{
|
||||
AssertCurrentThreadOwnsQuotaMutex();
|
||||
|
||||
nsRefPtr<GroupInfo>& groupInfo =
|
||||
GetGroupInfoForPersistenceType(aPersistenceType);
|
||||
groupInfo = nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
LockedHasGroupInfos()
|
||||
{
|
||||
AssertCurrentThreadOwnsQuotaMutex();
|
||||
|
||||
return mPersistentStorageGroupInfo || mTemporaryStorageGroupInfo;
|
||||
}
|
||||
|
||||
nsRefPtr<GroupInfo>&
|
||||
GetGroupInfoForPersistenceType(PersistenceType aPersistenceType);
|
||||
|
||||
nsRefPtr<GroupInfo> mPersistentStorageGroupInfo;
|
||||
nsRefPtr<GroupInfo> mTemporaryStorageGroupInfo;
|
||||
};
|
||||
|
||||
END_QUOTA_NAMESPACE
|
||||
|
|
|
@ -12,8 +12,13 @@
|
|||
BEGIN_QUOTA_NAMESPACE
|
||||
|
||||
enum StoragePrivilege {
|
||||
Content,
|
||||
Chrome
|
||||
// Quota not tracked, persistence type is always "persistent".
|
||||
Chrome,
|
||||
|
||||
// Quota tracked, persistence type can be either "persistent" or "temporary".
|
||||
// The permission "defaul-persistent-storage" is used to determine the
|
||||
// default persistence type.
|
||||
Content
|
||||
};
|
||||
|
||||
END_QUOTA_NAMESPACE
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_quota_usagerunnable_h__
|
||||
#define mozilla_dom_quota_usagerunnable_h__
|
||||
#ifndef mozilla_dom_quota_usageinfo_h__
|
||||
#define mozilla_dom_quota_usageinfo_h__
|
||||
|
||||
#include "mozilla/dom/quota/QuotaCommon.h"
|
||||
|
||||
|
@ -14,14 +14,14 @@
|
|||
|
||||
BEGIN_QUOTA_NAMESPACE
|
||||
|
||||
class UsageRunnable
|
||||
class UsageInfo
|
||||
{
|
||||
public:
|
||||
UsageRunnable()
|
||||
UsageInfo()
|
||||
: mCanceled(0), mDatabaseUsage(0), mFileUsage(0)
|
||||
{ }
|
||||
|
||||
virtual ~UsageRunnable()
|
||||
virtual ~UsageInfo()
|
||||
{ }
|
||||
|
||||
bool
|
||||
|
@ -79,4 +79,4 @@ private:
|
|||
|
||||
END_QUOTA_NAMESPACE
|
||||
|
||||
#endif // mozilla_dom_quota_usagerunnable_h__
|
||||
#endif // mozilla_dom_quota_usageinfo_h__
|
|
@ -24,11 +24,12 @@ EXPORTS.mozilla.dom.quota += [
|
|||
'Client.h',
|
||||
'FileStreams.h',
|
||||
'OriginOrPatternString.h',
|
||||
'PersistenceType.h',
|
||||
'QuotaCommon.h',
|
||||
'QuotaManager.h',
|
||||
'QuotaObject.h',
|
||||
'StoragePrivilege.h',
|
||||
'UsageRunnable.h',
|
||||
'UsageInfo.h',
|
||||
'Utilities.h',
|
||||
]
|
||||
|
||||
|
|
|
@ -9,9 +9,13 @@
|
|||
|
||||
#include "nsIFileStorage.h"
|
||||
|
||||
#include "mozilla/dom/quota/PersistenceType.h"
|
||||
|
||||
#define NS_OFFLINESTORAGE_IID \
|
||||
{0xe531b6e0, 0x55b8, 0x4f39, \
|
||||
{ 0x95, 0xbb, 0x97, 0x21, 0x4c, 0xb0, 0xf6, 0x1a } }
|
||||
{0xec7e878d, 0xc8c1, 0x402e, \
|
||||
{ 0xa2, 0xc4, 0xf6, 0x82, 0x29, 0x4e, 0x3c, 0xb1 } }
|
||||
|
||||
class nsPIDOMWindow;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
@ -25,6 +29,7 @@ class nsIOfflineStorage : public nsIFileStorage
|
|||
{
|
||||
public:
|
||||
typedef mozilla::dom::quota::Client Client;
|
||||
typedef mozilla::dom::quota::PersistenceType PersistenceType;
|
||||
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_OFFLINESTORAGE_IID)
|
||||
|
||||
|
@ -34,6 +39,18 @@ public:
|
|||
NS_IMETHOD_(bool)
|
||||
IsOwned(nsPIDOMWindow* aOwner) = 0;
|
||||
|
||||
NS_IMETHOD_(PersistenceType)
|
||||
Type()
|
||||
{
|
||||
return mPersistenceType;
|
||||
}
|
||||
|
||||
NS_IMETHOD_(const nsACString&)
|
||||
Group()
|
||||
{
|
||||
return mGroup;
|
||||
}
|
||||
|
||||
NS_IMETHOD_(const nsACString&)
|
||||
Origin() = 0;
|
||||
|
||||
|
@ -50,6 +67,17 @@ public:
|
|||
// operations should be aborted and pending operations should be discarded.
|
||||
NS_IMETHOD_(void)
|
||||
Invalidate() = 0;
|
||||
|
||||
protected:
|
||||
nsIOfflineStorage()
|
||||
: mPersistenceType(mozilla::dom::quota::PERSISTENCE_TYPE_INVALID)
|
||||
{ }
|
||||
|
||||
virtual ~nsIOfflineStorage()
|
||||
{ }
|
||||
|
||||
PersistenceType mPersistenceType;
|
||||
nsCString mGroup;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsIOfflineStorage, NS_OFFLINESTORAGE_IID)
|
||||
|
|
|
@ -10,7 +10,7 @@ interface nsIQuotaRequest;
|
|||
interface nsIURI;
|
||||
interface nsIUsageCallback;
|
||||
|
||||
[scriptable, builtinclass, uuid(8d74e6f8-81c3-4045-9bb7-70bdb7b11b25)]
|
||||
[scriptable, builtinclass, uuid(f19a03ae-e97d-41e9-95dd-681b910c4093)]
|
||||
interface nsIQuotaManager : nsISupports
|
||||
{
|
||||
/**
|
||||
|
@ -29,6 +29,17 @@ interface nsIQuotaManager : nsISupports
|
|||
[optional] in unsigned long aAppId,
|
||||
[optional] in boolean aInMozBrowserOnly);
|
||||
|
||||
/**
|
||||
* Removes all storages. The files may not be deleted immediately depending
|
||||
* on prohibitive concurrent operations.
|
||||
* Be careful, this removes *all* the data that has ever been stored!
|
||||
*
|
||||
* If the dom.quotaManager.testing preference is not true the call will be
|
||||
* a no-op.
|
||||
*/
|
||||
void
|
||||
clear();
|
||||
|
||||
/**
|
||||
* Removes all storages stored for the given URI. The files may not be
|
||||
* deleted immediately depending on prohibitive concurrent operations.
|
||||
|
@ -41,4 +52,16 @@ interface nsIQuotaManager : nsISupports
|
|||
clearStoragesForURI(in nsIURI aURI,
|
||||
[optional] in unsigned long aAppId,
|
||||
[optional] in boolean aInMozBrowserOnly);
|
||||
|
||||
/**
|
||||
* Resets quota and storage management. This can be used to force
|
||||
* reinitialization of the temp storage, for example when the pref for
|
||||
* overriding the temp storage limit has changed.
|
||||
* Be carefull, this invalidates all live storages!
|
||||
*
|
||||
* If the dom.quotaManager.testing preference is not true the call will be
|
||||
* a no-op.
|
||||
*/
|
||||
void
|
||||
reset();
|
||||
};
|
||||
|
|
|
@ -44,6 +44,9 @@ interface IDBDatabase : EventTarget {
|
|||
};
|
||||
|
||||
partial interface IDBDatabase {
|
||||
[Pref="dom.indexedDB.experimental"]
|
||||
readonly attribute StorageType storage;
|
||||
|
||||
[Throws]
|
||||
IDBRequest mozCreateFileHandle (DOMString name, optional DOMString type);
|
||||
};
|
||||
|
|
|
@ -12,6 +12,12 @@
|
|||
|
||||
interface Principal;
|
||||
|
||||
dictionary IDBOpenDBOptions
|
||||
{
|
||||
[EnforceRange] unsigned long long version;
|
||||
StorageType storage;
|
||||
};
|
||||
|
||||
/**
|
||||
* Interface that defines the indexedDB property on a window. See
|
||||
* http://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#idl-def-IDBFactory
|
||||
|
@ -21,11 +27,17 @@ interface IDBFactory {
|
|||
[Throws]
|
||||
IDBOpenDBRequest
|
||||
open(DOMString name,
|
||||
[EnforceRange] optional unsigned long long version);
|
||||
[EnforceRange] unsigned long long version);
|
||||
|
||||
[Throws]
|
||||
IDBOpenDBRequest
|
||||
deleteDatabase(DOMString name);
|
||||
open(DOMString name,
|
||||
optional IDBOpenDBOptions options);
|
||||
|
||||
[Throws]
|
||||
IDBOpenDBRequest
|
||||
deleteDatabase(DOMString name,
|
||||
optional IDBOpenDBOptions options);
|
||||
|
||||
[Throws]
|
||||
short
|
||||
|
@ -36,10 +48,17 @@ interface IDBFactory {
|
|||
IDBOpenDBRequest
|
||||
openForPrincipal(Principal principal,
|
||||
DOMString name,
|
||||
[EnforceRange] optional unsigned long long version);
|
||||
[EnforceRange] unsigned long long version);
|
||||
|
||||
[Throws, ChromeOnly]
|
||||
IDBOpenDBRequest
|
||||
openForPrincipal(Principal principal,
|
||||
DOMString name,
|
||||
optional IDBOpenDBOptions options);
|
||||
|
||||
[Throws, ChromeOnly]
|
||||
IDBOpenDBRequest
|
||||
deleteForPrincipal(Principal principal,
|
||||
DOMString name);
|
||||
DOMString name,
|
||||
optional IDBOpenDBOptions options);
|
||||
};
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
enum StorageType { "persistent", "temporary" };
|
|
@ -259,6 +259,7 @@ WEBIDL_FILES = [
|
|||
'SimpleGestureEvent.webidl',
|
||||
'SourceBuffer.webidl',
|
||||
'SourceBufferList.webidl',
|
||||
'StorageType.webidl',
|
||||
'StyleSheet.webidl',
|
||||
'SVGAElement.webidl',
|
||||
'SVGAltGlyphElement.webidl',
|
||||
|
|
|
@ -78,10 +78,15 @@ pref("offline-apps.quota.warn", 51200);
|
|||
// cache compression turned off for now - see bug #715198
|
||||
pref("browser.cache.compression_level", 0);
|
||||
|
||||
// Whether or not testing features are enabled.
|
||||
pref("dom.quotaManager.testing", false);
|
||||
|
||||
// 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);
|
||||
// Whether or not indexedDB experimental features are enabled.
|
||||
pref("dom.indexedDB.experimental", false);
|
||||
|
||||
// Whether or not Web Workers are enabled.
|
||||
pref("dom.workers.enabled", true);
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "sqlite3.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "mozilla/Util.h"
|
||||
#include "mozilla/dom/quota/PersistenceType.h"
|
||||
#include "mozilla/dom/quota/QuotaManager.h"
|
||||
#include "mozilla/dom/quota/QuotaObject.h"
|
||||
#include "mozilla/SQLiteInterposer.h"
|
||||
|
@ -349,15 +350,19 @@ xOpen(sqlite3_vfs* vfs, const char *zName, sqlite3_file* pFile,
|
|||
}
|
||||
p->histograms = h;
|
||||
|
||||
const char* persistenceType;
|
||||
const char* group;
|
||||
const char* origin;
|
||||
if ((flags & SQLITE_OPEN_URI) &&
|
||||
(persistenceType = sqlite3_uri_parameter(zName, "persistenceType")) &&
|
||||
(group = sqlite3_uri_parameter(zName, "group")) &&
|
||||
(origin = sqlite3_uri_parameter(zName, "origin"))) {
|
||||
QuotaManager* quotaManager = QuotaManager::Get();
|
||||
MOZ_ASSERT(quotaManager);
|
||||
|
||||
p->quotaObject = quotaManager->GetQuotaObject(nsDependentCString(origin),
|
||||
NS_ConvertUTF8toUTF16(zName));
|
||||
|
||||
p->quotaObject = quotaManager->GetQuotaObject(PersistenceTypeFromText(
|
||||
nsDependentCString(persistenceType)), nsDependentCString(group),
|
||||
nsDependentCString(origin), NS_ConvertUTF8toUTF16(zName));
|
||||
}
|
||||
|
||||
rc = orig_vfs->xOpen(orig_vfs, zName, p->pReal, flags, pOutFlags);
|
||||
|
|
|
@ -1182,6 +1182,11 @@ SpecialPowersAPI.prototype = {
|
|||
Cu.forceCC();
|
||||
},
|
||||
|
||||
// Due to various dependencies between JS objects and C++ objects, an ordinary
|
||||
// forceGC doesn't necessarily clear all unused objects, thus the GC and CC
|
||||
// needs to run several times and when no other JS is running.
|
||||
// The current number of iterations has been determined according to massive
|
||||
// cross platform testing.
|
||||
exactGC: function(win, callback) {
|
||||
var self = this;
|
||||
let count = 0;
|
||||
|
|
Загрузка…
Ссылка в новой задаче