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:
Jan Varga 2013-09-11 06:18:36 +02:00
Родитель 67b05683bd
Коммит e9492bcd36
83 изменённых файлов: 4592 добавлений и 831 удалений

Просмотреть файл

@ -61,7 +61,7 @@ let DomStorage = {
// Check if we're allowed to store sessionStorage data. // Check if we're allowed to store sessionStorage data.
let isHTTPS = principal.URI && principal.URI.schemeIs("https"); let isHTTPS = principal.URI && principal.URI.schemeIs("https");
if (aFullData || SessionStore.checkPrivacyLevel(isHTTPS, isPinned)) { if (aFullData || SessionStore.checkPrivacyLevel(isHTTPS, isPinned)) {
let origin = principal.extendedOrigin; let origin = principal.jarPrefix + principal.origin;
// Don't read a host twice. // Don't read a host twice.
if (!(origin in data)) { if (!(origin in data)) {

Просмотреть файл

@ -20,7 +20,7 @@ interface nsIContentSecurityPolicy;
[ptr] native JSPrincipals(JSPrincipals); [ptr] native JSPrincipals(JSPrincipals);
[ptr] native PrincipalArray(nsTArray<nsCOMPtr<nsIPrincipal> >); [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 interface nsIPrincipal : nsISerializable
{ {
/** /**
@ -162,19 +162,19 @@ interface nsIPrincipal : nsISerializable
[noscript] attribute nsIContentSecurityPolicy csp; [noscript] attribute nsIContentSecurityPolicy csp;
/** /**
* Returns the extended origin of the principal. * Returns the jar prefix of the principal.
* The extended origin is a string that has more information than the origin * The jar prefix is a string that can be used to isolate data or
* and can be used to isolate data or permissions between different * permissions between different principals while taking into account
* principals while taking into account parameters like the app id or the * parameters like the app id or the fact that the principal is embedded in
* fact that the principal is embedded in a mozbrowser. * a mozbrowser.
* Some principals will return the origin for extendedOrigin. * Some principals will return an empty string.
* Some principals will assert if you try to access the extendedOrigin. * Some principals will assert if you try to access the jarPrefix.
* *
* The extendedOrigin is intended to be an opaque identifier. It is * The jarPrefix is intended to be an opaque identifier. It is currently
* currently "human-readable" but no callers should assume it will stay * "human-readable" but no callers should assume it will stay as is and
* as is and it might be crypto-hashed at some point. * 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 * The base domain of the codebase URI to which this principal pertains

Просмотреть файл

@ -10,7 +10,7 @@ interface nsIURI;
interface nsIChannel; interface nsIChannel;
interface nsIDocShell; interface nsIDocShell;
[scriptable, uuid(ae486501-ec57-4ec8-a565-6880ca4ae6c4)] [scriptable, uuid(d6475e53-9ece-4dc0-940c-095ac3d85363)]
interface nsIScriptSecurityManager : nsIXPCSecurityManager interface nsIScriptSecurityManager : nsIXPCSecurityManager
{ {
///////////////// Security Checks ////////////////// ///////////////// Security Checks //////////////////
@ -229,13 +229,12 @@ interface nsIScriptSecurityManager : nsIXPCSecurityManager
const unsigned long UNKNOWN_APP_ID = 4294967295; // UINT32_MAX 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 * appId can be NO_APP_ID or a valid app id. appId should not be
* UNKNOWN_APP_ID. * 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, AUTF8String getJarPrefix(in unsigned long appId, in boolean inMozBrowser);
in boolean inMozBrowser);
}; };
%{C++ %{C++

Просмотреть файл

@ -65,7 +65,7 @@ public:
NS_IMETHOD Subsumes(nsIPrincipal* other, bool* _retval); NS_IMETHOD Subsumes(nsIPrincipal* other, bool* _retval);
NS_IMETHOD SubsumesIgnoringDomain(nsIPrincipal* other, bool* _retval); NS_IMETHOD SubsumesIgnoringDomain(nsIPrincipal* other, bool* _retval);
NS_IMETHOD CheckMayLoad(nsIURI* uri, bool report, bool allowIfInheritsPrincipal); 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 GetAppStatus(uint16_t* aAppStatus);
NS_IMETHOD GetAppId(uint32_t* aAppStatus); NS_IMETHOD GetAppId(uint32_t* aAppStatus);
NS_IMETHOD GetIsInBrowserElement(bool* aIsInBrowserElement); NS_IMETHOD GetIsInBrowserElement(bool* aIsInBrowserElement);
@ -148,7 +148,7 @@ public:
NS_IMETHOD Subsumes(nsIPrincipal* other, bool* _retval); NS_IMETHOD Subsumes(nsIPrincipal* other, bool* _retval);
NS_IMETHOD SubsumesIgnoringDomain(nsIPrincipal* other, bool* _retval); NS_IMETHOD SubsumesIgnoringDomain(nsIPrincipal* other, bool* _retval);
NS_IMETHOD CheckMayLoad(nsIURI* uri, bool report, bool allowIfInheritsPrincipal); 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 GetAppStatus(uint16_t* aAppStatus);
NS_IMETHOD GetAppId(uint32_t* aAppStatus); NS_IMETHOD GetAppId(uint32_t* aAppStatus);
NS_IMETHOD GetIsInBrowserElement(bool* aIsInBrowserElement); NS_IMETHOD GetIsInBrowserElement(bool* aIsInBrowserElement);

Просмотреть файл

@ -526,9 +526,9 @@ public:
namespace mozilla { namespace mozilla {
void void
GetExtendedOrigin(nsIURI* aURI, uint32_t aAppid, GetJarPrefix(uint32_t aAppid,
bool aInMozBrowser, bool aInMozBrowser,
nsACString& aExtendedOrigin); nsACString& aJarPrefix);
} // namespace mozilla } // namespace mozilla

Просмотреть файл

@ -259,9 +259,10 @@ nsNullPrincipal::CheckMayLoad(nsIURI* aURI, bool aReport, bool aAllowIfInheritsP
} }
NS_IMETHODIMP NS_IMETHODIMP
nsNullPrincipal::GetExtendedOrigin(nsACString& aExtendedOrigin) nsNullPrincipal::GetJarPrefix(nsACString& aJarPrefix)
{ {
return GetOrigin(getter_Copies(aExtendedOrigin)); aJarPrefix.Truncate();
return NS_OK;
} }
NS_IMETHODIMP NS_IMETHODIMP

Просмотреть файл

@ -424,11 +424,11 @@ nsPrincipal::SetDomain(nsIURI* aDomain)
} }
NS_IMETHODIMP NS_IMETHODIMP
nsPrincipal::GetExtendedOrigin(nsACString& aExtendedOrigin) nsPrincipal::GetJarPrefix(nsACString& aJarPrefix)
{ {
MOZ_ASSERT(mAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID); MOZ_ASSERT(mAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID);
mozilla::GetExtendedOrigin(mCodebase, mAppId, mInMozBrowser, aExtendedOrigin); mozilla::GetJarPrefix(mAppId, mInMozBrowser, aJarPrefix);
return NS_OK; return NS_OK;
} }
@ -773,9 +773,10 @@ nsExpandedPrincipal::GetWhiteList(nsTArray<nsCOMPtr<nsIPrincipal> >** aWhiteList
} }
NS_IMETHODIMP NS_IMETHODIMP
nsExpandedPrincipal::GetExtendedOrigin(nsACString& aExtendedOrigin) nsExpandedPrincipal::GetJarPrefix(nsACString& aJarPrefix)
{ {
return GetOrigin(getter_Copies(aExtendedOrigin)); aJarPrefix.Truncate();
return NS_OK;
} }
NS_IMETHODIMP NS_IMETHODIMP

Просмотреть файл

@ -2778,32 +2778,26 @@ nsScriptSecurityManager::InitPrefs()
namespace mozilla { namespace mozilla {
void void
GetExtendedOrigin(nsIURI* aURI, uint32_t aAppId, bool aInMozBrowser, GetJarPrefix(uint32_t aAppId, bool aInMozBrowser, nsACString& aJarPrefix)
nsACString& aExtendedOrigin)
{ {
MOZ_ASSERT(aURI);
MOZ_ASSERT(aAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID); MOZ_ASSERT(aAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID);
if (aAppId == nsIScriptSecurityManager::UNKNOWN_APP_ID) { if (aAppId == nsIScriptSecurityManager::UNKNOWN_APP_ID) {
aAppId = nsIScriptSecurityManager::NO_APP_ID; aAppId = nsIScriptSecurityManager::NO_APP_ID;
} }
nsAutoCString origin; aJarPrefix.Truncate();
nsPrincipal::GetOriginForURI(aURI, getter_Copies(origin));
// Fallback. // Fallback.
if (aAppId == nsIScriptSecurityManager::NO_APP_ID && !aInMozBrowser) { if (aAppId == nsIScriptSecurityManager::NO_APP_ID && !aInMozBrowser) {
aExtendedOrigin.Assign(origin);
return; return;
} }
// aExtendedOrigin = appId + "+" + { 't', 'f' } "+" + origin; // aJarPrefix = appId + "+" + { 't', 'f' } + "+";
aExtendedOrigin.Truncate(); aJarPrefix.AppendInt(aAppId);
aExtendedOrigin.AppendInt(aAppId); aJarPrefix.Append('+');
aExtendedOrigin.Append('+'); aJarPrefix.Append(aInMozBrowser ? 't' : 'f');
aExtendedOrigin.Append(aInMozBrowser ? 't' : 'f'); aJarPrefix.Append('+');
aExtendedOrigin.Append('+');
aExtendedOrigin.Append(origin);
return; return;
} }
@ -2811,13 +2805,12 @@ GetExtendedOrigin(nsIURI* aURI, uint32_t aAppId, bool aInMozBrowser,
} // namespace mozilla } // namespace mozilla
NS_IMETHODIMP NS_IMETHODIMP
nsScriptSecurityManager::GetExtendedOrigin(nsIURI* aURI, nsScriptSecurityManager::GetJarPrefix(uint32_t aAppId,
uint32_t aAppId, bool aInMozBrowser,
bool aInMozBrowser, nsACString& aJarPrefix)
nsACString& aExtendedOrigin)
{ {
MOZ_ASSERT(aAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID); MOZ_ASSERT(aAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID);
mozilla::GetExtendedOrigin(aURI, aAppId, aInMozBrowser, aExtendedOrigin); mozilla::GetJarPrefix(aAppId, aInMozBrowser, aJarPrefix);
return NS_OK; return NS_OK;
} }

Просмотреть файл

@ -166,9 +166,10 @@ nsSystemPrincipal::SetSecurityPolicy(void* aSecurityPolicy)
} }
NS_IMETHODIMP NS_IMETHODIMP
nsSystemPrincipal::GetExtendedOrigin(nsACString& aExtendedOrigin) nsSystemPrincipal::GetJarPrefix(nsACString& aJarPrefix)
{ {
return GetOrigin(getter_Copies(aExtendedOrigin)); aJarPrefix.Truncate();
return NS_OK;
} }
NS_IMETHODIMP NS_IMETHODIMP

Просмотреть файл

@ -11,8 +11,8 @@ MOCHITEST_FILES = test_bug423375.html \
test_app_principal_equality.html \ test_app_principal_equality.html \
$(NULL) $(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) ifneq ($(OS_ARCH),WINNT)
MOCHITEST_CHROME_FILES = test_principal_extendedorigin_appid_appstatus.html \ MOCHITEST_CHROME_FILES = test_principal_jarprefix_origin_appid_appstatus.html \
$(NULL) $(NULL)
endif endif

Просмотреть файл

@ -5,7 +5,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=758258
--> -->
<head> <head>
<meta charset="utf-8"> <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> <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"?> <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
</head> </head>
@ -294,20 +294,20 @@ function checkIFrame(aFrame, data) {
} }
if (!data.isapp && !data.browser) { if (!data.isapp && !data.browser) {
is(principal.extendedOrigin, principal.origin, is(principal.jarPrefix, "",
'extendedOrigin should return the origin for non-app and non-browsers principals'); 'jarPrefix should return an empty string for non-app and non-browsers principals');
} else { } else {
isnot(principal.extendedOrigin, principal.origin, isnot(principal.jarPrefix, "",
'extendedOrigin should not return the origin for apps or mozbrowsers'); 'jarPrefix should not return an empty string for apps or mozbrowsers');
} }
if (data.test.indexOf("eo-unique") != -1) { if (data.test.indexOf("eo-unique") != -1) {
is(eoList.indexOf(principal.extendedOrigin), -1, is(eoList.indexOf(principal.jarPrefix + principal.origin), -1,
"extendedOrigin should be unique"); "extended origin should be unique");
} }
if (data.test.indexOf("eo-as-last") != -1) { if (data.test.indexOf("eo-as-last") != -1) {
is(principal.extendedOrigin, eoList[eoList.length-1], is(principal.jarPrefix + principal.origin, eoList[eoList.length-1],
"extendedOrigin should be the same as the last inserted one"); "extended origin should be the same as the last inserted one");
} }
is(principal.isInBrowserElement, !!data.browser, is(principal.isInBrowserElement, !!data.browser,
@ -325,17 +325,19 @@ function checkIFrame(aFrame, data) {
"check childPrincipal.isInBrowserElement"); "check childPrincipal.isInBrowserElement");
if (data.test.indexOf("child-has-same-eo") != -1) { if (data.test.indexOf("child-has-same-eo") != -1) {
is(childPrincipal.extendedOrigin, principal.extendedOrigin, is(childPrincipal.jarPrefix + childPrincipal.origin,
"child should have the same extendedOrigin as parent"); principal.jarPrefix + principal.origin,
"child should have the same extended origin as parent");
is(childPrincipal.appStatus, principal.appStatus, 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, 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) { if (data.test.indexOf("child-has-different-eo") != -1) {
isnot(childPrincipal.extendedOrigin, principal.extendedOrigin, isnot(childPrincipal.jarPrefix + childPrincipal.origin,
"child should not have the same extendedOrigin as parent"); principal.jarPrefix + principal.origin,
"child should not have the same extended origin as parent");
} }
if (data.test.indexOf("child-has-same-appstatus") != -1) { 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++; checkedCount++;
if (checkedCount == checksTodo) { if (checkedCount == checksTodo) {
@ -373,8 +375,10 @@ function checkIFrame(aFrame, data) {
is('appStatus' in document.nodePrincipal, true, is('appStatus' in document.nodePrincipal, true,
'appStatus should be present in nsIPrincipal'); 'appStatus should be present in nsIPrincipal');
is('extendedOrigin' in document.nodePrincipal, true, is('jarPrefix' in document.nodePrincipal, true,
'extendedOrigin should be present in nsIPrincipal'); 'jarPrefix should be present in nsIPrincipal');
is('origin' in document.nodePrincipal, true,
'origin should be present in nsIPrincipal');
is('appId' in document.nodePrincipal, true, is('appId' in document.nodePrincipal, true,
'appId should be present in nsIPrincipal'); 'appId should be present in nsIPrincipal');

Просмотреть файл

@ -228,7 +228,8 @@ this.PermissionsTable = { geolocation: {
substitute: [ substitute: [
"indexedDB-unlimited", "indexedDB-unlimited",
"offline-app", "offline-app",
"pin-app" "pin-app",
"default-persistent-storage"
] ]
}, },
"background-sensors": { "background-sensors": {

Просмотреть файл

@ -459,7 +459,7 @@ this.DOMApplicationRegistry = {
debug("Fixing indexedDb folder names"); debug("Fixing indexedDb folder names");
let idbDir = FileUtils.getDir("indexedDBPDir", ["indexedDB"]); let idbDir = FileUtils.getDir("indexedDBPDir", ["indexedDB"]);
if (!idbDir.isDirectory()) { if (!idbDir.exists() || !idbDir.isDirectory()) {
return; return;
} }

Просмотреть файл

@ -59,7 +59,9 @@
#include "mozilla/layers/ShadowLayers.h" #include "mozilla/layers/ShadowLayers.h"
#include "mozilla/dom/Element.h" #include "mozilla/dom/Element.h"
#include "mozilla/dom/IDBFactoryBinding.h"
#include "mozilla/dom/indexedDB/IndexedDatabaseManager.h" #include "mozilla/dom/indexedDB/IndexedDatabaseManager.h"
#include "mozilla/dom/quota/PersistenceType.h"
#include "mozilla/dom/quota/QuotaManager.h" #include "mozilla/dom/quota/QuotaManager.h"
#include "nsDOMBlobBuilder.h" #include "nsDOMBlobBuilder.h"
#include "nsIDOMFileHandle.h" #include "nsIDOMFileHandle.h"
@ -2826,9 +2828,10 @@ nsDOMWindowUtils::GetFileId(const JS::Value& aFile, JSContext* aCx,
} }
NS_IMETHODIMP NS_IMETHODIMP
nsDOMWindowUtils::GetFileReferences(const nsAString& aDatabaseName, nsDOMWindowUtils::GetFileReferences(const nsAString& aDatabaseName, int64_t aId,
int64_t aId, int32_t* aRefCnt, const jsval& aOptions,
int32_t* aDBRefCnt, int32_t* aSliceRefCnt, int32_t* aRefCnt, int32_t* aDBRefCnt,
int32_t* aSliceRefCnt, JSContext* aCx,
bool* aResult) bool* aResult)
{ {
if (!nsContentUtils::IsCallerChrome()) { if (!nsContentUtils::IsCallerChrome()) {
@ -2839,15 +2842,28 @@ nsDOMWindowUtils::GetFileReferences(const nsAString& aDatabaseName,
NS_ENSURE_TRUE(window, NS_ERROR_FAILURE); NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
nsCString origin; 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); 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 = nsRefPtr<indexedDB::IndexedDatabaseManager> mgr =
indexedDB::IndexedDatabaseManager::Get(); indexedDB::IndexedDatabaseManager::Get();
if (mgr) { if (mgr) {
rv = mgr->BlockAndGetFileReferences(origin, aDatabaseName, aId, aRefCnt, rv = mgr->BlockAndGetFileReferences(persistenceType, origin, aDatabaseName,
aDBRefCnt, aSliceRefCnt, aResult); aId, aRefCnt, aDBRefCnt, aSliceRefCnt,
aResult);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
} }
else { else {

Просмотреть файл

@ -64,6 +64,28 @@ public:
return mIsNull; 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 // Make it possible to use a const Nullable of an array type with other
// array types. // array types.
template<typename U> template<typename U>

Просмотреть файл

@ -19,7 +19,6 @@
#include "nsContentUtils.h" #include "nsContentUtils.h"
#include "nsNetUtil.h" #include "nsNetUtil.h"
#include "nsThreadUtils.h" #include "nsThreadUtils.h"
#include "mozilla/dom/quota/QuotaManager.h"
#include "mozilla/Preferences.h" #include "mozilla/Preferences.h"
#include "mozilla/Services.h" #include "mozilla/Services.h"
@ -165,10 +164,7 @@ CheckPermissionsHelper::Run()
} }
} }
quota::QuotaManager* quotaManager = quota::QuotaManager::Get(); return helper->DispatchToIOThread();
NS_ASSERTION(quotaManager, "This should never be null!");
return helper->Dispatch(quotaManager->IOThread());
} }
NS_ASSERTION(permission == PERMISSION_PROMPT || NS_ASSERTION(permission == PERMISSION_PROMPT ||

Просмотреть файл

@ -30,17 +30,18 @@ public:
NS_DECL_NSIOBSERVER NS_DECL_NSIOBSERVER
CheckPermissionsHelper(OpenDatabaseHelper* aHelper, CheckPermissionsHelper(OpenDatabaseHelper* aHelper,
nsIDOMWindow* aWindow, nsIDOMWindow* aWindow)
bool aForDeletion)
: mHelper(aHelper), : mHelper(aHelper),
mWindow(aWindow), mWindow(aWindow),
// If we're trying to delete the database, we should never prompt the user. // If we're trying to delete the database, we should never prompt the user.
// Anything that would prompt is translated to denied. // Anything that would prompt is translated to denied.
mPromptAllowed(!aForDeletion), mPromptAllowed(!aHelper->mForDeletion),
mHasPrompted(false), mHasPrompted(false),
mPromptResult(0) mPromptResult(0)
{ {
NS_ASSERTION(aHelper, "Null pointer!"); NS_ASSERTION(aHelper, "Null pointer!");
NS_ASSERTION(aHelper->mPersistenceType == quota::PERSISTENCE_TYPE_PERSISTENT,
"Checking permission for non persistent databases?!");
} }
private: private:

Просмотреть файл

@ -7,7 +7,7 @@
#include "Client.h" #include "Client.h"
#include "mozilla/dom/quota/QuotaManager.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 "mozilla/dom/quota/Utilities.h"
#include "IDBDatabase.h" #include "IDBDatabase.h"
@ -45,12 +45,14 @@ NS_IMPL_ADDREF(mozilla::dom::indexedDB::Client)
NS_IMPL_RELEASE(mozilla::dom::indexedDB::Client) NS_IMPL_RELEASE(mozilla::dom::indexedDB::Client)
nsresult nsresult
Client::InitOrigin(const nsACString& aOrigin, UsageRunnable* aUsageRunnable) Client::InitOrigin(PersistenceType aPersistenceType, const nsACString& aGroup,
const nsACString& aOrigin, UsageInfo* aUsageInfo)
{ {
AssertIsOnIOThread(); AssertIsOnIOThread();
nsCOMPtr<nsIFile> directory; nsCOMPtr<nsIFile> directory;
nsresult rv = GetDirectory(aOrigin, getter_AddRefs(directory)); nsresult rv =
GetDirectory(aPersistenceType, aOrigin, getter_AddRefs(directory));
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
// We need to see if there are any files in the directory already. If they // 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; bool hasMore;
while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) && while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) &&
hasMore && (!aUsageRunnable || !aUsageRunnable->Canceled())) { hasMore && (!aUsageInfo || !aUsageInfo->Canceled())) {
nsCOMPtr<nsISupports> entry; nsCOMPtr<nsISupports> entry;
rv = entries->GetNext(getter_AddRefs(entry)); rv = entries->GetNext(getter_AddRefs(entry));
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
@ -83,11 +85,9 @@ Client::InitOrigin(const nsACString& aOrigin, UsageRunnable* aUsageRunnable)
continue; continue;
} }
#ifdef XP_MACOSX
if (leafName.EqualsLiteral(DSSTORE_FILE_NAME)) { if (leafName.EqualsLiteral(DSSTORE_FILE_NAME)) {
continue; continue;
} }
#endif
bool isDirectory; bool isDirectory;
rv = file->IsDirectory(&isDirectory); rv = file->IsDirectory(&isDirectory);
@ -113,21 +113,24 @@ Client::InitOrigin(const nsACString& aOrigin, UsageRunnable* aUsageRunnable)
rv = fmDirectory->Append(dbBaseFilename); rv = fmDirectory->Append(dbBaseFilename);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
rv = FileManager::InitDirectory(fmDirectory, file, aOrigin); rv = FileManager::InitDirectory(fmDirectory, file, aPersistenceType, aGroup,
aOrigin);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
if (aUsageRunnable) { if (aUsageInfo) {
int64_t fileSize; int64_t fileSize;
rv = file->GetFileSize(&fileSize); rv = file->GetFileSize(&fileSize);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
aUsageRunnable->AppendToDatabaseUsage(uint64_t(fileSize)); NS_ASSERTION(fileSize >= 0, "Negative size?!");
aUsageInfo->AppendToDatabaseUsage(uint64_t(fileSize));
uint64_t usage; uint64_t usage;
rv = FileManager::GetUsage(fmDirectory, &usage); rv = FileManager::GetUsage(fmDirectory, &usage);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
aUsageRunnable->AppendToFileUsage(usage); aUsageInfo->AppendToFileUsage(usage);
} }
validSubdirs.PutEntry(dbBaseFilename); validSubdirs.PutEntry(dbBaseFilename);
@ -167,30 +170,33 @@ Client::InitOrigin(const nsACString& aOrigin, UsageRunnable* aUsageRunnable)
} }
nsresult nsresult
Client::GetUsageForOrigin(const nsACString& aOrigin, Client::GetUsageForOrigin(PersistenceType aPersistenceType,
UsageRunnable* aUsageRunnable) const nsACString& aGroup, const nsACString& aOrigin,
UsageInfo* aUsageInfo)
{ {
AssertIsOnIOThread(); AssertIsOnIOThread();
NS_ASSERTION(aUsageRunnable, "Null pointer!"); NS_ASSERTION(aUsageInfo, "Null pointer!");
nsCOMPtr<nsIFile> directory; nsCOMPtr<nsIFile> directory;
nsresult rv = GetDirectory(aOrigin, getter_AddRefs(directory)); nsresult rv =
GetDirectory(aPersistenceType, aOrigin, getter_AddRefs(directory));
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
rv = GetUsageForDirectoryInternal(directory, aUsageRunnable, true); rv = GetUsageForDirectoryInternal(directory, aUsageInfo, true);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
return NS_OK; return NS_OK;
} }
void void
Client::OnOriginClearCompleted(const nsACString& aPattern) Client::OnOriginClearCompleted(PersistenceType aPersistenceType,
const OriginOrPatternString& aOriginOrPattern)
{ {
AssertIsOnIOThread(); AssertIsOnIOThread();
IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get(); IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
if (mgr) { if (mgr) {
mgr->InvalidateFileManagersForPattern(aPattern); mgr->InvalidateFileManagers(aPersistenceType, aOriginOrPattern);
} }
} }
@ -275,14 +281,15 @@ Client::ShutdownTransactionService()
} }
nsresult nsresult
Client::GetDirectory(const nsACString& aOrigin, nsIFile** aDirectory) Client::GetDirectory(PersistenceType aPersistenceType,
const nsACString& aOrigin, nsIFile** aDirectory)
{ {
QuotaManager* quotaManager = QuotaManager::Get(); QuotaManager* quotaManager = QuotaManager::Get();
NS_ASSERTION(quotaManager, "This should never fail!"); NS_ASSERTION(quotaManager, "This should never fail!");
nsCOMPtr<nsIFile> directory; nsCOMPtr<nsIFile> directory;
nsresult rv = nsresult rv = quotaManager->GetDirectoryForOrigin(aPersistenceType, aOrigin,
quotaManager->GetDirectoryForOrigin(aOrigin, getter_AddRefs(directory)); getter_AddRefs(directory));
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
NS_ASSERTION(directory, "What?"); NS_ASSERTION(directory, "What?");
@ -296,11 +303,11 @@ Client::GetDirectory(const nsACString& aOrigin, nsIFile** aDirectory)
nsresult nsresult
Client::GetUsageForDirectoryInternal(nsIFile* aDirectory, Client::GetUsageForDirectoryInternal(nsIFile* aDirectory,
UsageRunnable* aUsageRunnable, UsageInfo* aUsageInfo,
bool aDatabaseFiles) bool aDatabaseFiles)
{ {
NS_ASSERTION(aDirectory, "Null pointer!"); NS_ASSERTION(aDirectory, "Null pointer!");
NS_ASSERTION(aUsageRunnable, "Null pointer!"); NS_ASSERTION(aUsageInfo, "Null pointer!");
nsCOMPtr<nsISimpleEnumerator> entries; nsCOMPtr<nsISimpleEnumerator> entries;
nsresult rv = aDirectory->GetDirectoryEntries(getter_AddRefs(entries)); nsresult rv = aDirectory->GetDirectoryEntries(getter_AddRefs(entries));
@ -312,7 +319,7 @@ Client::GetUsageForDirectoryInternal(nsIFile* aDirectory,
bool hasMore; bool hasMore;
while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) && while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) &&
hasMore && !aUsageRunnable->Canceled()) { hasMore && !aUsageInfo->Canceled()) {
nsCOMPtr<nsISupports> entry; nsCOMPtr<nsISupports> entry;
rv = entries->GetNext(getter_AddRefs(entry)); rv = entries->GetNext(getter_AddRefs(entry));
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
@ -326,7 +333,7 @@ Client::GetUsageForDirectoryInternal(nsIFile* aDirectory,
if (isDirectory) { if (isDirectory) {
if (aDatabaseFiles) { if (aDatabaseFiles) {
rv = GetUsageForDirectoryInternal(file, aUsageRunnable, false); rv = GetUsageForDirectoryInternal(file, aUsageInfo, false);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
} }
else { else {
@ -349,10 +356,10 @@ Client::GetUsageForDirectoryInternal(nsIFile* aDirectory,
NS_ASSERTION(fileSize >= 0, "Negative size?!"); NS_ASSERTION(fileSize >= 0, "Negative size?!");
if (aDatabaseFiles) { if (aDatabaseFiles) {
aUsageRunnable->AppendToDatabaseUsage(uint64_t(fileSize)); aUsageInfo->AppendToDatabaseUsage(uint64_t(fileSize));
} }
else { else {
aUsageRunnable->AppendToFileUsage(uint64_t(fileSize)); aUsageInfo->AppendToFileUsage(uint64_t(fileSize));
} }
} }
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);

Просмотреть файл

@ -18,7 +18,9 @@ BEGIN_INDEXEDDB_NAMESPACE
class Client : public mozilla::dom::quota::Client 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: public:
NS_IMETHOD_(nsrefcnt) NS_IMETHOD_(nsrefcnt)
@ -34,15 +36,21 @@ public:
} }
virtual nsresult virtual nsresult
InitOrigin(const nsACString& aOrigin, InitOrigin(PersistenceType aPersistenceType,
UsageRunnable* aUsageRunnable) MOZ_OVERRIDE; const nsACString& aGroup,
const nsACString& aOrigin,
UsageInfo* aUsageInfo) MOZ_OVERRIDE;
virtual nsresult virtual nsresult
GetUsageForOrigin(const nsACString& aOrigin, GetUsageForOrigin(PersistenceType aPersistenceType,
UsageRunnable* aUsageRunnable) MOZ_OVERRIDE; const nsACString& aGroup,
const nsACString& aOrigin,
UsageInfo* aUsageInfo) MOZ_OVERRIDE;
virtual void virtual void
OnOriginClearCompleted(const nsACString& aPattern) MOZ_OVERRIDE; OnOriginClearCompleted(PersistenceType aPersistenceType,
const OriginOrPatternString& aOriginOrPattern)
MOZ_OVERRIDE;
virtual void virtual void
ReleaseIOThreadObjects() MOZ_OVERRIDE; ReleaseIOThreadObjects() MOZ_OVERRIDE;
@ -71,11 +79,12 @@ public:
private: private:
nsresult nsresult
GetDirectory(const nsACString& aOrigin, nsIFile** aDirectory); GetDirectory(PersistenceType aPersistenceType, const nsACString& aOrigin,
nsIFile** aDirectory);
nsresult nsresult
GetUsageForDirectoryInternal(nsIFile* aDirectory, GetUsageForDirectoryInternal(nsIFile* aDirectory,
UsageRunnable* aUsageRunnable, UsageInfo* aUsageInfo,
bool aDatabaseFiles); bool aDatabaseFiles);
nsAutoRefCnt mRefCnt; nsAutoRefCnt mRefCnt;

Просмотреть файл

@ -250,8 +250,10 @@ DatabaseInfo::Clone()
dbInfo->cloned = true; dbInfo->cloned = true;
dbInfo->name = name; dbInfo->name = name;
dbInfo->group = group;
dbInfo->origin = origin; dbInfo->origin = origin;
dbInfo->version = version; dbInfo->version = version;
dbInfo->persistenceType = persistenceType;
dbInfo->id = id; dbInfo->id = id;
dbInfo->filePath = filePath; dbInfo->filePath = filePath;
dbInfo->nextObjectStoreId = nextObjectStoreId; dbInfo->nextObjectStoreId = nextObjectStoreId;

Просмотреть файл

@ -9,13 +9,14 @@
#include "mozilla/dom/indexedDB/IndexedDatabase.h" #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/Key.h"
#include "mozilla/dom/indexedDB/KeyPath.h" #include "mozilla/dom/indexedDB/KeyPath.h"
#include "mozilla/dom/indexedDB/IDBObjectStore.h" #include "mozilla/dom/indexedDB/IDBObjectStore.h"
#include "nsRefPtrHashtable.h"
#include "nsHashKeys.h"
BEGIN_INDEXEDDB_NAMESPACE BEGIN_INDEXEDDB_NAMESPACE
class IndexedDBDatabaseChild; class IndexedDBDatabaseChild;
@ -26,6 +27,8 @@ typedef nsRefPtrHashtable<nsStringHashKey, ObjectStoreInfo>
struct DatabaseInfoGuts struct DatabaseInfoGuts
{ {
typedef mozilla::dom::quota::PersistenceType PersistenceType;
DatabaseInfoGuts() DatabaseInfoGuts()
: nextObjectStoreId(1), nextIndexId(1) : nextObjectStoreId(1), nextIndexId(1)
{ } { }
@ -33,16 +36,20 @@ struct DatabaseInfoGuts
bool operator==(const DatabaseInfoGuts& aOther) const bool operator==(const DatabaseInfoGuts& aOther) const
{ {
return this->name == aOther.name && return this->name == aOther.name &&
this->group == aOther.group &&
this->origin == aOther.origin && this->origin == aOther.origin &&
this->version == aOther.version && this->version == aOther.version &&
this->persistenceType == aOther.persistenceType &&
this->nextObjectStoreId == aOther.nextObjectStoreId && this->nextObjectStoreId == aOther.nextObjectStoreId &&
this->nextIndexId == aOther.nextIndexId; this->nextIndexId == aOther.nextIndexId;
}; };
// Make sure to update ipc/SerializationHelpers.h when changing members here! // Make sure to update ipc/SerializationHelpers.h when changing members here!
nsString name; nsString name;
nsCString group;
nsCString origin; nsCString origin;
uint64_t version; uint64_t version;
PersistenceType persistenceType;
int64_t nextObjectStoreId; int64_t nextObjectStoreId;
int64_t nextIndexId; int64_t nextIndexId;
}; };

Просмотреть файл

@ -266,6 +266,8 @@ FileManager::GetFileForId(nsIFile* aDirectory, int64_t aId)
nsresult nsresult
FileManager::InitDirectory(nsIFile* aDirectory, FileManager::InitDirectory(nsIFile* aDirectory,
nsIFile* aDatabaseFile, nsIFile* aDatabaseFile,
PersistenceType aPersistenceType,
const nsACString& aGroup,
const nsACString& aOrigin) const nsACString& aOrigin)
{ {
AssertIsOnIOThread(); AssertIsOnIOThread();
@ -311,7 +313,8 @@ FileManager::InitDirectory(nsIFile* aDirectory,
if (hasElements) { if (hasElements) {
nsCOMPtr<mozIStorageConnection> connection; nsCOMPtr<mozIStorageConnection> connection;
rv = OpenDatabaseHelper::CreateDatabaseConnection(aDatabaseFile, rv = OpenDatabaseHelper::CreateDatabaseConnection(aDatabaseFile,
aDirectory, NullString(), aOrigin, getter_AddRefs(connection)); aDirectory, NullString(), aPersistenceType, aGroup, aOrigin,
getter_AddRefs(connection));
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
mozStorageTransaction transaction(connection, false); mozStorageTransaction transaction(connection, false);

Просмотреть файл

@ -12,6 +12,7 @@
#include "nsIDOMFile.h" #include "nsIDOMFile.h"
#include "nsIFile.h" #include "nsIFile.h"
#include "mozilla/dom/quota/PersistenceType.h"
#include "mozilla/dom/quota/StoragePrivilege.h" #include "mozilla/dom/quota/StoragePrivilege.h"
#include "nsDataHashtable.h" #include "nsDataHashtable.h"
@ -25,13 +26,16 @@ class FileManager
{ {
friend class FileInfo; friend class FileInfo;
typedef mozilla::dom::quota::PersistenceType PersistenceType;
typedef mozilla::dom::quota::StoragePrivilege StoragePrivilege; typedef mozilla::dom::quota::StoragePrivilege StoragePrivilege;
public: public:
FileManager(const nsACString& aOrigin, StoragePrivilege aPrivilege, FileManager(PersistenceType aPersistenceType, const nsACString& aGroup,
const nsACString& aOrigin, StoragePrivilege aPrivilege,
const nsAString& aDatabaseName) const nsAString& aDatabaseName)
: mOrigin(aOrigin), mPrivilege(aPrivilege), mDatabaseName(aDatabaseName), : mPersistenceType(aPersistenceType), mGroup(aGroup), mOrigin(aOrigin),
mLastFileId(0), mInvalidated(false) mPrivilege(aPrivilege), mDatabaseName(aDatabaseName), mLastFileId(0),
mInvalidated(false)
{ } { }
~FileManager() ~FileManager()
@ -39,6 +43,16 @@ public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(FileManager) NS_INLINE_DECL_THREADSAFE_REFCOUNTING(FileManager)
PersistenceType Type()
{
return mPersistenceType;
}
const nsACString& Group() const
{
return mGroup;
}
const nsACString& Origin() const const nsACString& Origin() const
{ {
return mOrigin; return mOrigin;
@ -79,11 +93,15 @@ public:
static nsresult InitDirectory(nsIFile* aDirectory, static nsresult InitDirectory(nsIFile* aDirectory,
nsIFile* aDatabaseFile, nsIFile* aDatabaseFile,
PersistenceType aPersistenceType,
const nsACString& aGroup,
const nsACString& aOrigin); const nsACString& aOrigin);
static nsresult GetUsage(nsIFile* aDirectory, uint64_t* aUsage); static nsresult GetUsage(nsIFile* aDirectory, uint64_t* aUsage);
private: private:
PersistenceType mPersistenceType;
nsCString mGroup;
nsCString mOrigin; nsCString mOrigin;
StoragePrivilege mPrivilege; StoragePrivilege mPrivilege;
nsString mDatabaseName; nsString mDatabaseName;

Просмотреть файл

@ -197,6 +197,8 @@ IDBDatabase::Create(IDBWrapperCache* aOwnerCache,
db->mDatabaseId = databaseInfo->id; db->mDatabaseId = databaseInfo->id;
db->mName = databaseInfo->name; db->mName = databaseInfo->name;
db->mFilePath = databaseInfo->filePath; db->mFilePath = databaseInfo->filePath;
db->mPersistenceType = databaseInfo->persistenceType;
db->mGroup = databaseInfo->group;
databaseInfo.swap(db->mDatabaseInfo); databaseInfo.swap(db->mDatabaseInfo);
db->mASCIIOrigin = aASCIIOrigin; db->mASCIIOrigin = aASCIIOrigin;
db->mFileManager = aFileManager; db->mFileManager = aFileManager;
@ -227,8 +229,7 @@ IDBDatabase::FromStorage(nsIOfflineStorage* aStorage)
} }
IDBDatabase::IDBDatabase() IDBDatabase::IDBDatabase()
: mDatabaseId(0), : mActorChild(nullptr),
mActorChild(nullptr),
mActorParent(nullptr), mActorParent(nullptr),
mContentParent(nullptr), mContentParent(nullptr),
mInvalidated(false), mInvalidated(false),

Просмотреть файл

@ -16,6 +16,7 @@
#include "mozilla/Attributes.h" #include "mozilla/Attributes.h"
#include "mozilla/dom/IDBObjectStoreBinding.h" #include "mozilla/dom/IDBObjectStoreBinding.h"
#include "mozilla/dom/IDBTransactionBinding.h" #include "mozilla/dom/IDBTransactionBinding.h"
#include "mozilla/dom/quota/PersistenceType.h"
#include "nsDOMEventTargetHelper.h" #include "nsDOMEventTargetHelper.h"
#include "mozilla/dom/indexedDB/FileManager.h" #include "mozilla/dom/indexedDB/FileManager.h"
@ -210,6 +211,12 @@ public:
IMPL_EVENT_HANDLER(error) IMPL_EVENT_HANDLER(error)
IMPL_EVENT_HANDLER(versionchange) IMPL_EVENT_HANDLER(versionchange)
mozilla::dom::StorageType
Storage() const
{
return PersistenceTypeToStorage(mPersistenceType);
}
already_AddRefed<IDBRequest> already_AddRefed<IDBRequest>
MozCreateFileHandle(const nsAString& aName, const Optional<nsAString>& aType, MozCreateFileHandle(const nsAString& aName, const Optional<nsAString>& aType,
ErrorResult& aRv); ErrorResult& aRv);

Просмотреть файл

@ -9,6 +9,7 @@
#include "nsIFile.h" #include "nsIFile.h"
#include "nsIPrincipal.h" #include "nsIPrincipal.h"
#include "nsIScriptContext.h" #include "nsIScriptContext.h"
#include "nsIScriptSecurityManager.h"
#include "nsIXPConnect.h" #include "nsIXPConnect.h"
#include "nsIXPCScriptable.h" #include "nsIXPCScriptable.h"
@ -22,7 +23,6 @@
#include "mozilla/dom/TabChild.h" #include "mozilla/dom/TabChild.h"
#include "mozilla/storage.h" #include "mozilla/storage.h"
#include "nsComponentManagerUtils.h" #include "nsComponentManagerUtils.h"
#include "nsIScriptSecurityManager.h"
#include "nsCharSeparatedTokenizer.h" #include "nsCharSeparatedTokenizer.h"
#include "nsContentUtils.h" #include "nsContentUtils.h"
#include "nsCxPusher.h" #include "nsCxPusher.h"
@ -51,6 +51,7 @@ USING_QUOTA_NAMESPACE
using mozilla::dom::ContentChild; using mozilla::dom::ContentChild;
using mozilla::dom::ContentParent; using mozilla::dom::ContentParent;
using mozilla::dom::IDBOpenDBOptions;
using mozilla::dom::NonNull; using mozilla::dom::NonNull;
using mozilla::dom::Optional; using mozilla::dom::Optional;
using mozilla::dom::TabChild; using mozilla::dom::TabChild;
@ -70,7 +71,8 @@ struct ObjectStoreInfoMap
} // anonymous namespace } // anonymous namespace
IDBFactory::IDBFactory() IDBFactory::IDBFactory()
: mOwningObject(nullptr), mActorChild(nullptr), mActorParent(nullptr), : mPrivilege(Content), mDefaultPersistenceType(PERSISTENCE_TYPE_TEMPORARY),
mOwningObject(nullptr), mActorChild(nullptr), mActorParent(nullptr),
mContentParent(nullptr), mRootedOwningObject(false) mContentParent(nullptr), mRootedOwningObject(false)
{ {
SetIsDOMBinding(); SetIsDOMBinding();
@ -93,6 +95,7 @@ IDBFactory::~IDBFactory()
// static // static
nsresult nsresult
IDBFactory::Create(nsPIDOMWindow* aWindow, IDBFactory::Create(nsPIDOMWindow* aWindow,
const nsACString& aGroup,
const nsACString& aASCIIOrigin, const nsACString& aASCIIOrigin,
ContentParent* aContentParent, ContentParent* aContentParent,
IDBFactory** aFactory) IDBFactory** aFactory)
@ -116,18 +119,31 @@ IDBFactory::Create(nsPIDOMWindow* aWindow,
nsresult rv; nsresult rv;
nsCString group(aGroup);
nsCString origin(aASCIIOrigin); nsCString origin(aASCIIOrigin);
StoragePrivilege privilege;
PersistenceType defaultPersistenceType;
if (origin.IsEmpty()) { if (origin.IsEmpty()) {
rv = QuotaManager::GetASCIIOriginFromWindow(aWindow, origin); NS_ASSERTION(aGroup.IsEmpty(), "Should be empty too!");
if (NS_FAILED(rv)) {
// Not allowed. rv = QuotaManager::GetInfoFromWindow(aWindow, &group, &origin, &privilege,
*aFactory = nullptr; &defaultPersistenceType);
return NS_OK; }
} 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(); nsRefPtr<IDBFactory> factory = new IDBFactory();
factory->mGroup = group;
factory->mASCIIOrigin = origin; factory->mASCIIOrigin = origin;
factory->mPrivilege = privilege;
factory->mDefaultPersistenceType = defaultPersistenceType;
factory->mWindow = aWindow; factory->mWindow = aWindow;
factory->mContentParent = aContentParent; factory->mContentParent = aContentParent;
@ -138,7 +154,7 @@ IDBFactory::Create(nsPIDOMWindow* aWindow,
IndexedDBChild* actor = new IndexedDBChild(origin); IndexedDBChild* actor = new IndexedDBChild(origin);
bool allowed; bool allowed;
tabChild->SendPIndexedDBConstructor(actor, origin, &allowed); tabChild->SendPIndexedDBConstructor(actor, group, origin, &allowed);
if (!allowed) { if (!allowed) {
actor->Send__delete__(actor); actor->Send__delete__(actor);
@ -167,12 +183,20 @@ IDBFactory::Create(JSContext* aCx,
"Not a global object!"); "Not a global object!");
NS_ASSERTION(nsContentUtils::IsCallerChrome(), "Only for chrome!"); NS_ASSERTION(nsContentUtils::IsCallerChrome(), "Only for chrome!");
nsCString group;
nsCString origin; 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); NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
nsRefPtr<IDBFactory> factory = new IDBFactory(); nsRefPtr<IDBFactory> factory = new IDBFactory();
factory->mGroup = group;
factory->mASCIIOrigin = origin; factory->mASCIIOrigin = origin;
factory->mPrivilege = privilege;
factory->mDefaultPersistenceType = defaultPersistenceType;
factory->mOwningObject = aOwningObject; factory->mOwningObject = aOwningObject;
factory->mContentParent = aContentParent; factory->mContentParent = aContentParent;
@ -238,7 +262,10 @@ IDBFactory::Create(ContentParent* aContentParent,
// static // static
already_AddRefed<nsIFileURL> 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; nsCOMPtr<nsIURI> uri;
nsresult rv = NS_NewFileURI(getter_AddRefs(uri), aDatabaseFile); 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); nsCOMPtr<nsIFileURL> fileUrl = do_QueryInterface(uri);
NS_ASSERTION(fileUrl, "This should always succeed!"); 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); NS_ENSURE_SUCCESS(rv, nullptr);
return fileUrl.forget(); return fileUrl.forget();
@ -256,6 +288,8 @@ IDBFactory::GetDatabaseFileURL(nsIFile* aDatabaseFile, const nsACString& aOrigin
// static // static
already_AddRefed<mozIStorageConnection> already_AddRefed<mozIStorageConnection>
IDBFactory::GetConnection(const nsAString& aDatabaseFilePath, IDBFactory::GetConnection(const nsAString& aDatabaseFilePath,
PersistenceType aPersistenceType,
const nsACString& aGroup,
const nsACString& aOrigin) const nsACString& aOrigin)
{ {
NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
@ -273,7 +307,8 @@ IDBFactory::GetConnection(const nsAString& aDatabaseFilePath,
NS_ENSURE_SUCCESS(rv, nullptr); NS_ENSURE_SUCCESS(rv, nullptr);
NS_ENSURE_TRUE(exists, 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); NS_ENSURE_TRUE(dbFileUrl, nullptr);
nsCOMPtr<mozIStorageService> ss = nsCOMPtr<mozIStorageService> ss =
@ -524,7 +559,10 @@ DOMCI_DATA(IDBFactory, IDBFactory)
nsresult nsresult
IDBFactory::OpenInternal(const nsAString& aName, IDBFactory::OpenInternal(const nsAString& aName,
int64_t aVersion, int64_t aVersion,
PersistenceType aPersistenceType,
const nsACString& aGroup,
const nsACString& aASCIIOrigin, const nsACString& aASCIIOrigin,
StoragePrivilege aPrivilege,
bool aDeleting, bool aDeleting,
IDBOpenDBRequest** _retval) IDBOpenDBRequest** _retval)
{ {
@ -534,17 +572,19 @@ IDBFactory::OpenInternal(const nsAString& aName,
AutoJSContext cx; AutoJSContext cx;
nsCOMPtr<nsPIDOMWindow> window; nsCOMPtr<nsPIDOMWindow> window;
JS::Rooted<JSObject*> scriptOwner(cx); JS::Rooted<JSObject*> scriptOwner(cx);
StoragePrivilege privilege;
if (mWindow) { if (mWindow) {
window = mWindow; window = mWindow;
scriptOwner = scriptOwner =
static_cast<nsGlobalWindow*>(window.get())->FastGetGlobalJSObject(); static_cast<nsGlobalWindow*>(window.get())->FastGetGlobalJSObject();
privilege = Content;
} }
else { else {
scriptOwner = mOwningObject; scriptOwner = mOwningObject;
privilege = Chrome; }
if (aPrivilege == Chrome) {
// Chrome privilege, ignore the persistence type parameter.
aPersistenceType = PERSISTENCE_TYPE_PERSISTENT;
} }
nsRefPtr<IDBOpenDBRequest> request = nsRefPtr<IDBOpenDBRequest> request =
@ -555,40 +595,51 @@ IDBFactory::OpenInternal(const nsAString& aName,
if (IndexedDatabaseManager::IsMainProcess()) { if (IndexedDatabaseManager::IsMainProcess()) {
nsRefPtr<OpenDatabaseHelper> openHelper = nsRefPtr<OpenDatabaseHelper> openHelper =
new OpenDatabaseHelper(request, aName, aASCIIOrigin, aVersion, aDeleting, new OpenDatabaseHelper(request, aName, aGroup, aASCIIOrigin, aVersion,
mContentParent, privilege); aPersistenceType, aDeleting, mContentParent,
aPrivilege);
rv = openHelper->Init(); rv = openHelper->Init();
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
nsRefPtr<CheckPermissionsHelper> permissionHelper = if (aPersistenceType == PERSISTENCE_TYPE_PERSISTENT) {
new CheckPermissionsHelper(openHelper, window, aDeleting); nsRefPtr<CheckPermissionsHelper> permissionHelper =
new CheckPermissionsHelper(openHelper, window);
QuotaManager* quotaManager = QuotaManager::Get(); QuotaManager* quotaManager = QuotaManager::Get();
NS_ASSERTION(quotaManager, "This should never be null!"); NS_ASSERTION(quotaManager, "This should never be null!");
rv = quotaManager->WaitForOpenAllowed(OriginOrPatternString::FromOrigin( rv = quotaManager->
aASCIIOrigin), openHelper->Id(), WaitForOpenAllowed(OriginOrPatternString::FromOrigin(aASCIIOrigin),
permissionHelper); 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); NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
} }
else if (aDeleting) { else if (aDeleting) {
nsCOMPtr<nsIAtom> databaseId = nsCOMPtr<nsIAtom> databaseId =
QuotaManager::GetStorageId(aASCIIOrigin, aName); QuotaManager::GetStorageId(aPersistenceType, aASCIIOrigin, aName);
NS_ENSURE_TRUE(databaseId, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); NS_ENSURE_TRUE(databaseId, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
IndexedDBDeleteDatabaseRequestChild* actor = IndexedDBDeleteDatabaseRequestChild* actor =
new IndexedDBDeleteDatabaseRequestChild(this, request, databaseId); new IndexedDBDeleteDatabaseRequestChild(this, request, databaseId);
mActorChild->SendPIndexedDBDeleteDatabaseRequestConstructor( mActorChild->SendPIndexedDBDeleteDatabaseRequestConstructor(
actor, actor,
nsString(aName)); nsString(aName),
aPersistenceType);
} }
else { else {
IndexedDBDatabaseChild* dbActor = IndexedDBDatabaseChild* dbActor =
static_cast<IndexedDBDatabaseChild*>( static_cast<IndexedDBDatabaseChild*>(
mActorChild->SendPIndexedDBDatabaseConstructor(nsString(aName), mActorChild->SendPIndexedDBDatabaseConstructor(nsString(aName),
aVersion)); aVersion,
aPersistenceType));
dbActor->SetRequest(request); dbActor->SetRequest(request);
} }
@ -620,6 +671,22 @@ IDBFactory::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
return IDBFactoryBinding::Wrap(aCx, aScope, this); 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 int16_t
IDBFactory::Cmp(JSContext* aCx, JS::Handle<JS::Value> aFirst, IDBFactory::Cmp(JSContext* aCx, JS::Handle<JS::Value> aFirst,
JS::Handle<JS::Value> aSecond, ErrorResult& aRv) JS::Handle<JS::Value> aSecond, ErrorResult& aRv)
@ -646,22 +713,34 @@ IDBFactory::Cmp(JSContext* aCx, JS::Handle<JS::Value> aFirst,
} }
already_AddRefed<IDBOpenDBRequest> already_AddRefed<IDBOpenDBRequest>
IDBFactory::OpenForPrincipal(nsIPrincipal* aPrincipal, IDBFactory::OpenForPrincipal(nsIPrincipal* aPrincipal, const nsAString& aName,
const nsAString& aName, uint64_t aVersion, ErrorResult& aRv)
const Optional<uint64_t>& aVersion,
ErrorResult& aRv)
{ {
// Just to be on the extra-safe side // Just to be on the extra-safe side
if (!nsContentUtils::IsCallerChrome()) { if (!nsContentUtils::IsCallerChrome()) {
MOZ_CRASH(); 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> already_AddRefed<IDBOpenDBRequest>
IDBFactory::DeleteForPrincipal(nsIPrincipal* aPrincipal, IDBFactory::OpenForPrincipal(nsIPrincipal* aPrincipal, const nsAString& aName,
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) ErrorResult& aRv)
{ {
// Just to be on the extra-safe side // Just to be on the extra-safe side
@ -669,43 +748,53 @@ IDBFactory::DeleteForPrincipal(nsIPrincipal* aPrincipal,
MOZ_CRASH(); 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> already_AddRefed<IDBOpenDBRequest>
IDBFactory::Open(nsIPrincipal* aPrincipal, IDBFactory::Open(nsIPrincipal* aPrincipal, const nsAString& aName,
const nsAString& aName, const Optional<uint64_t>& aVersion, const Optional<uint64_t>& aVersion,
const Optional<mozilla::dom::StorageType>& aStorageType,
bool aDelete, ErrorResult& aRv) bool aDelete, ErrorResult& aRv)
{ {
nsresult rv; nsresult rv;
nsCString group;
nsCString origin; nsCString origin;
StoragePrivilege privilege;
PersistenceType defaultPersistenceType;
if (aPrincipal) { if (aPrincipal) {
rv = QuotaManager::GetASCIIOriginFromPrincipal(aPrincipal, origin); rv = QuotaManager::GetInfoFromPrincipal(aPrincipal, &group, &origin,
&privilege,
&defaultPersistenceType);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
aRv.Throw(rv); aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
return nullptr; return nullptr;
} }
} }
else { else {
group = mGroup;
origin = mASCIIOrigin; origin = mASCIIOrigin;
privilege = mPrivilege;
defaultPersistenceType = mDefaultPersistenceType;
} }
uint64_t version; uint64_t version = 0;
if (!aDelete && aVersion.WasPassed()) { if (!aDelete && aVersion.WasPassed()) {
version = aVersion.Value(); if (aVersion.Value() < 1) {
if (version < 1) {
aRv.ThrowTypeError(MSG_INVALID_VERSION); aRv.ThrowTypeError(MSG_INVALID_VERSION);
return nullptr; return nullptr;
} }
} version = aVersion.Value();
else {
version = 0;
} }
PersistenceType persistenceType =
PersistenceTypeFromStorage(aStorageType, defaultPersistenceType);
nsRefPtr<IDBOpenDBRequest> request; nsRefPtr<IDBOpenDBRequest> request;
rv = OpenInternal(aName, version, origin, aDelete, rv = OpenInternal(aName, version, persistenceType, group, origin, privilege,
getter_AddRefs(request)); aDelete, getter_AddRefs(request));
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
aRv.Throw(rv); aRv.Throw(rv);
return nullptr; return nullptr;

Просмотреть файл

@ -8,6 +8,9 @@
#define mozilla_dom_indexeddb_idbfactory_h__ #define mozilla_dom_indexeddb_idbfactory_h__
#include "mozilla/dom/BindingDeclarations.h" // for Optional #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 "nsCOMPtr.h"
#include "nsCycleCollectionParticipant.h" #include "nsCycleCollectionParticipant.h"
#include "nsWrapperCache.h" #include "nsWrapperCache.h"
@ -25,6 +28,7 @@ class ErrorResult;
namespace dom { namespace dom {
class ContentParent; class ContentParent;
class IDBOpenDBOptions;
namespace indexedDB { namespace indexedDB {
@ -40,7 +44,9 @@ class IDBFactory MOZ_FINAL : public nsISupports,
public nsWrapperCache public nsWrapperCache
{ {
typedef mozilla::dom::ContentParent ContentParent; typedef mozilla::dom::ContentParent ContentParent;
typedef mozilla::dom::quota::PersistenceType PersistenceType;
typedef nsTArray<nsRefPtr<ObjectStoreInfo> > ObjectStoreInfoArray; typedef nsTArray<nsRefPtr<ObjectStoreInfo> > ObjectStoreInfoArray;
typedef mozilla::dom::quota::StoragePrivilege StoragePrivilege;
public: public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTING_ISUPPORTS
@ -48,6 +54,7 @@ public:
// Called when using IndexedDB from a window in a different process. // Called when using IndexedDB from a window in a different process.
static nsresult Create(nsPIDOMWindow* aWindow, static nsresult Create(nsPIDOMWindow* aWindow,
const nsACString& aGroup,
const nsACString& aASCIIOrigin, const nsACString& aASCIIOrigin,
ContentParent* aContentParent, ContentParent* aContentParent,
IDBFactory** aFactory); IDBFactory** aFactory);
@ -57,7 +64,8 @@ public:
ContentParent* aContentParent, ContentParent* aContentParent,
IDBFactory** aFactory) 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 // Called when using IndexedDB from a JS component or a JSM in the current
@ -73,10 +81,15 @@ public:
IDBFactory** aFactory); IDBFactory** aFactory);
static already_AddRefed<nsIFileURL> 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> static already_AddRefed<mozIStorageConnection>
GetConnection(const nsAString& aDatabaseFilePath, GetConnection(const nsAString& aDatabaseFilePath,
PersistenceType aPersistenceType,
const nsACString& aGroup,
const nsACString& aOrigin); const nsACString& aOrigin);
static nsresult static nsresult
@ -96,17 +109,22 @@ public:
nsresult nsresult
OpenInternal(const nsAString& aName, OpenInternal(const nsAString& aName,
int64_t aVersion, int64_t aVersion,
PersistenceType aPersistenceType,
const nsACString& aGroup,
const nsACString& aASCIIOrigin, const nsACString& aASCIIOrigin,
StoragePrivilege aStoragePrivilege,
bool aDeleting, bool aDeleting,
IDBOpenDBRequest** _retval); IDBOpenDBRequest** _retval);
nsresult nsresult
OpenInternal(const nsAString& aName, OpenInternal(const nsAString& aName,
int64_t aVersion, int64_t aVersion,
PersistenceType aPersistenceType,
bool aDeleting, bool aDeleting,
IDBOpenDBRequest** _retval) IDBOpenDBRequest** _retval)
{ {
return OpenInternal(aName, aVersion, mASCIIOrigin, aDeleting, _retval); return OpenInternal(aName, aVersion, aPersistenceType, mGroup, mASCIIOrigin,
mPrivilege, aDeleting, _retval);
} }
void void
@ -129,28 +147,31 @@ public:
return mASCIIOrigin; return mASCIIOrigin;
} }
// WrapperCache // nsWrapperCache
nsPIDOMWindow* GetParentObject() const virtual JSObject*
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
// WebIDL
nsPIDOMWindow*
GetParentObject() const
{ {
return mWindow; return mWindow;
} }
virtual JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
// WebIDL
already_AddRefed<IDBOpenDBRequest> already_AddRefed<IDBOpenDBRequest>
Open(const nsAString& aName, const Optional<uint64_t>& aVersion, Open(const nsAString& aName, uint64_t aVersion, ErrorResult& aRv)
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> already_AddRefed<IDBOpenDBRequest>
DeleteDatabase(const nsAString& aName, ErrorResult& aRv) Open(const nsAString& aName, const IDBOpenDBOptions& aOptions,
{ ErrorResult& aRv);
return Open(nullptr, aName, Optional<uint64_t>(), true, aRv);
} already_AddRefed<IDBOpenDBRequest>
DeleteDatabase(const nsAString& aName, const IDBOpenDBOptions& aOptions,
ErrorResult& aRv);
int16_t int16_t
Cmp(JSContext* aCx, JS::Handle<JS::Value> aFirst, Cmp(JSContext* aCx, JS::Handle<JS::Value> aFirst,
@ -158,11 +179,15 @@ public:
already_AddRefed<IDBOpenDBRequest> already_AddRefed<IDBOpenDBRequest>
OpenForPrincipal(nsIPrincipal* aPrincipal, const nsAString& aName, 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> already_AddRefed<IDBOpenDBRequest>
DeleteForPrincipal(nsIPrincipal* aPrincipal, const nsAString& aName, DeleteForPrincipal(nsIPrincipal* aPrincipal, const nsAString& aName,
ErrorResult& aRv); const IDBOpenDBOptions& aOptions, ErrorResult& aRv);
private: private:
IDBFactory(); IDBFactory();
@ -170,9 +195,14 @@ private:
already_AddRefed<IDBOpenDBRequest> already_AddRefed<IDBOpenDBRequest>
Open(nsIPrincipal* aPrincipal, const nsAString& aName, 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; nsCString mASCIIOrigin;
StoragePrivilege mPrivilege;
PersistenceType mDefaultPersistenceType;
// If this factory lives on a window then mWindow must be non-null. Otherwise // If this factory lives on a window then mWindow must be non-null. Otherwise
// mOwningObject must be non-null. // mOwningObject must be non-null.

Просмотреть файл

@ -77,18 +77,22 @@ IDBFileHandle::CreateStream(nsIFile* aFile, bool aReadOnly)
nsCOMPtr<nsIOfflineStorage> storage = do_QueryInterface(mFileStorage); nsCOMPtr<nsIOfflineStorage> storage = do_QueryInterface(mFileStorage);
NS_ASSERTION(storage, "This should always succeed!"); NS_ASSERTION(storage, "This should always succeed!");
PersistenceType persistenceType = storage->Type();
const nsACString& group = storage->Group();
const nsACString& origin = storage->Origin(); const nsACString& origin = storage->Origin();
nsCOMPtr<nsISupports> result; nsCOMPtr<nsISupports> result;
if (aReadOnly) { if (aReadOnly) {
nsRefPtr<FileInputStream> stream = FileInputStream::Create( nsRefPtr<FileInputStream> stream =
origin, aFile, -1, -1, nsIFileInputStream::DEFER_OPEN); FileInputStream::Create(persistenceType, group, origin, aFile, -1, -1,
nsIFileInputStream::DEFER_OPEN);
result = NS_ISUPPORTS_CAST(nsIFileInputStream*, stream); result = NS_ISUPPORTS_CAST(nsIFileInputStream*, stream);
} }
else { else {
nsRefPtr<FileStream> stream = FileStream::Create( nsRefPtr<FileStream> stream =
origin, aFile, -1, -1, nsIFileStream::DEFER_OPEN); FileStream::Create(persistenceType, group, origin, aFile, -1, -1,
nsIFileStream::DEFER_OPEN);
result = NS_ISUPPORTS_CAST(nsIFileStream*, stream); result = NS_ISUPPORTS_CAST(nsIFileStream*, stream);
} }
NS_ENSURE_TRUE(result, nullptr); NS_ENSURE_TRUE(result, nullptr);

Просмотреть файл

@ -3015,8 +3015,10 @@ AddHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
nativeFile = fileManager->GetFileForId(directory, id); nativeFile = fileManager->GetFileForId(directory, id);
NS_ENSURE_TRUE(nativeFile, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); NS_ENSURE_TRUE(nativeFile, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
nsRefPtr<FileOutputStream> outputStream = FileOutputStream::Create( IDBDatabase* database = mObjectStore->Transaction()->Database();
mObjectStore->Transaction()->Database()->Origin(), nativeFile); nsRefPtr<FileOutputStream> outputStream =
FileOutputStream::Create(database->Type(), database->Group(),
database->Origin(), nativeFile);
NS_ENSURE_TRUE(outputStream, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); NS_ENSURE_TRUE(outputStream, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
rv = CopyData(inputStream, outputStream); rv = CopyData(inputStream, outputStream);

Просмотреть файл

@ -361,8 +361,8 @@ IDBTransaction::GetOrCreateConnection(mozIStorageConnection** aResult)
if (!mConnection) { if (!mConnection) {
nsCOMPtr<mozIStorageConnection> connection = nsCOMPtr<mozIStorageConnection> connection =
IDBFactory::GetConnection(mDatabase->FilePath(), IDBFactory::GetConnection(mDatabase->FilePath(), mDatabase->Type(),
mDatabase->Origin()); mDatabase->Group(), mDatabase->Origin());
NS_ENSURE_TRUE(connection, NS_ERROR_FAILURE); NS_ENSURE_TRUE(connection, NS_ERROR_FAILURE);
nsresult rv; nsresult rv;

Просмотреть файл

@ -16,6 +16,7 @@
#include "mozilla/ClearOnShutdown.h" #include "mozilla/ClearOnShutdown.h"
#include "mozilla/CondVar.h" #include "mozilla/CondVar.h"
#include "mozilla/dom/quota/OriginOrPatternString.h"
#include "mozilla/dom/quota/QuotaManager.h" #include "mozilla/dom/quota/QuotaManager.h"
#include "mozilla/dom/quota/Utilities.h" #include "mozilla/dom/quota/Utilities.h"
#include "mozilla/dom/TabContext.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); 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 { namespace {
mozilla::StaticRefPtr<IndexedDatabaseManager> gInstance; mozilla::StaticRefPtr<IndexedDatabaseManager> gInstance;
@ -67,10 +115,14 @@ public:
NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIRUNNABLE NS_DECL_NSIRUNNABLE
GetFileReferencesHelper(const nsACString& aOrigin, GetFileReferencesHelper(PersistenceType aPersistenceType,
const nsACString& aOrigin,
const nsAString& aDatabaseName, const nsAString& aDatabaseName,
int64_t aFileId) int64_t aFileId)
: mOrigin(aOrigin), mDatabaseName(aDatabaseName), mFileId(aFileId), : mPersistenceType(aPersistenceType),
mOrigin(aOrigin),
mDatabaseName(aDatabaseName),
mFileId(aFileId),
mMutex(IndexedDatabaseManager::FileMutex()), mMutex(IndexedDatabaseManager::FileMutex()),
mCondVar(mMutex, "GetFileReferencesHelper::mCondVar"), mCondVar(mMutex, "GetFileReferencesHelper::mCondVar"),
mMemRefCnt(-1), mMemRefCnt(-1),
@ -87,6 +139,7 @@ public:
bool* aResult); bool* aResult);
private: private:
PersistenceType mPersistenceType;
nsCString mOrigin; nsCString mOrigin;
nsString mDatabaseName; nsString mDatabaseName;
int64_t mFileId; int64_t mFileId;
@ -100,29 +153,15 @@ private:
bool mWaiting; bool mWaiting;
}; };
PLDHashOperator struct MOZ_STACK_CLASS InvalidateInfo
InvalidateAndRemoveFileManagers(
const nsACString& aKey,
nsAutoPtr<nsTArray<nsRefPtr<FileManager> > >& aValue,
void* aUserArg)
{ {
AssertIsOnIOThread(); InvalidateInfo(PersistenceType aPersistenceType, const nsACString& aPattern)
NS_ASSERTION(!aKey.IsEmpty(), "Empty key!"); : persistenceType(aPersistenceType), pattern(aPattern)
NS_ASSERTION(aValue, "Null pointer!"); { }
const nsACString* pattern = PersistenceType persistenceType;
static_cast<const nsACString*>(aUserArg); const nsACString& pattern;
};
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;
}
} // anonymous namespace } // anonymous namespace
@ -381,26 +420,21 @@ IndexedDatabaseManager::InLowDiskSpaceMode()
#endif #endif
already_AddRefed<FileManager> already_AddRefed<FileManager>
IndexedDatabaseManager::GetFileManager(const nsACString& aOrigin, IndexedDatabaseManager::GetFileManager(PersistenceType aPersistenceType,
const nsACString& aOrigin,
const nsAString& aDatabaseName) const nsAString& aDatabaseName)
{ {
AssertIsOnIOThread(); AssertIsOnIOThread();
nsTArray<nsRefPtr<FileManager> >* array; FileManagerInfo* info;
if (!mFileManagers.Get(aOrigin, &array)) { if (!mFileManagerInfos.Get(aOrigin, &info)) {
return nullptr; return nullptr;
} }
for (uint32_t i = 0; i < array->Length(); i++) { nsRefPtr<FileManager> fileManager =
nsRefPtr<FileManager>& fileManager = array->ElementAt(i); info->GetFileManager(aPersistenceType, aDatabaseName);
if (fileManager->DatabaseName().Equals(aDatabaseName)) { return fileManager.forget();
nsRefPtr<FileManager> result = fileManager;
return result.forget();
}
}
return nullptr;
} }
void void
@ -409,13 +443,42 @@ IndexedDatabaseManager::AddFileManager(FileManager* aFileManager)
AssertIsOnIOThread(); AssertIsOnIOThread();
NS_ASSERTION(aFileManager, "Null file manager!"); NS_ASSERTION(aFileManager, "Null file manager!");
nsTArray<nsRefPtr<FileManager> >* array; FileManagerInfo* info;
if (!mFileManagers.Get(aFileManager->Origin(), &array)) { if (!mFileManagerInfos.Get(aFileManager->Origin(), &info)) {
array = new nsTArray<nsRefPtr<FileManager> >(); info = new FileManagerInfo();
mFileManagers.Put(aFileManager->Origin(), array); 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 void
@ -423,43 +486,51 @@ IndexedDatabaseManager::InvalidateAllFileManagers()
{ {
AssertIsOnIOThread(); AssertIsOnIOThread();
mFileManagers.Enumerate(InvalidateAndRemoveFileManagers, nullptr); mFileManagerInfos.Enumerate(InvalidateAndRemoveFileManagers, nullptr);
} }
void void
IndexedDatabaseManager::InvalidateFileManagersForPattern( IndexedDatabaseManager::InvalidateFileManagers(
const nsACString& aPattern) PersistenceType aPersistenceType,
const OriginOrPatternString& aOriginOrPattern)
{ {
AssertIsOnIOThread(); AssertIsOnIOThread();
NS_ASSERTION(!aPattern.IsEmpty(), "Empty pattern!"); NS_ASSERTION(!aOriginOrPattern.IsEmpty(), "Empty pattern!");
mFileManagers.Enumerate(InvalidateAndRemoveFileManagers, if (aOriginOrPattern.IsOrigin()) {
const_cast<nsACString*>(&aPattern)); 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 void
IndexedDatabaseManager::InvalidateFileManager(const nsACString& aOrigin, IndexedDatabaseManager::InvalidateFileManager(PersistenceType aPersistenceType,
const nsACString& aOrigin,
const nsAString& aDatabaseName) const nsAString& aDatabaseName)
{ {
AssertIsOnIOThread(); AssertIsOnIOThread();
nsTArray<nsRefPtr<FileManager> >* array; FileManagerInfo* info;
if (!mFileManagers.Get(aOrigin, &array)) { if (!mFileManagerInfos.Get(aOrigin, &info)) {
return; return;
} }
for (uint32_t i = 0; i < array->Length(); i++) { info->InvalidateAndRemoveFileManager(aPersistenceType, aDatabaseName);
nsRefPtr<FileManager> fileManager = array->ElementAt(i);
if (fileManager->DatabaseName().Equals(aDatabaseName)) {
fileManager->Invalidate();
array->RemoveElementAt(i);
if (array->IsEmpty()) { if (!info->HasFileManagers()) {
mFileManagers.Remove(aOrigin); mFileManagerInfos.Remove(aOrigin);
}
break;
}
} }
} }
@ -492,16 +563,18 @@ IndexedDatabaseManager::AsyncDeleteFile(FileManager* aFileManager,
nsresult nsresult
IndexedDatabaseManager::BlockAndGetFileReferences( IndexedDatabaseManager::BlockAndGetFileReferences(
const nsACString& aOrigin, PersistenceType aPersistenceType,
const nsAString& aDatabaseName, const nsACString& aOrigin,
int64_t aFileId, const nsAString& aDatabaseName,
int32_t* aRefCnt, int64_t aFileId,
int32_t* aDBRefCnt, int32_t* aRefCnt,
int32_t* aSliceRefCnt, int32_t* aDBRefCnt,
bool* aResult) int32_t* aSliceRefCnt,
bool* aResult)
{ {
nsRefPtr<GetFileReferencesHelper> helper = nsRefPtr<GetFileReferencesHelper> helper =
new GetFileReferencesHelper(aOrigin, aDatabaseName, aFileId); new GetFileReferencesHelper(aPersistenceType, aOrigin, aDatabaseName,
aFileId);
nsresult rv = helper->DispatchAndReturnFileReferences(aRefCnt, aDBRefCnt, nsresult rv = helper->DispatchAndReturnFileReferences(aRefCnt, aDBRefCnt,
aSliceRefCnt, aResult); aSliceRefCnt, aResult);
@ -602,6 +675,105 @@ IndexedDatabaseManager::Observe(nsISupports* aSubject, const char* aTopic,
return NS_ERROR_UNEXPECTED; 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, AsyncDeleteFileRunnable::AsyncDeleteFileRunnable(FileManager* aFileManager,
int64_t aFileId) int64_t aFileId)
: mFileManager(aFileManager), mFileId(aFileId) : mFileManager(aFileManager), mFileId(aFileId)
@ -637,7 +809,9 @@ AsyncDeleteFileRunnable::Run()
QuotaManager* quotaManager = QuotaManager::Get(); QuotaManager* quotaManager = QuotaManager::Get();
NS_ASSERTION(quotaManager, "Shouldn't be null!"); NS_ASSERTION(quotaManager, "Shouldn't be null!");
quotaManager->DecreaseUsageForOrigin(mFileManager->Origin(), fileSize); quotaManager->DecreaseUsageForOrigin(mFileManager->Type(),
mFileManager->Group(),
mFileManager->Origin(), fileSize);
} }
directory = mFileManager->GetJournalDirectory(); directory = mFileManager->GetJournalDirectory();
@ -692,7 +866,7 @@ GetFileReferencesHelper::Run()
NS_ASSERTION(mgr, "This should never fail!"); NS_ASSERTION(mgr, "This should never fail!");
nsRefPtr<FileManager> fileManager = nsRefPtr<FileManager> fileManager =
mgr->GetFileManager(mOrigin, mDatabaseName); mgr->GetFileManager(mPersistenceType, mOrigin, mDatabaseName);
if (fileManager) { if (fileManager) {
nsRefPtr<FileInfo> fileInfo = fileManager->GetFileInfo(mFileId); nsRefPtr<FileInfo> fileInfo = fileManager->GetFileInfo(mFileId);

Просмотреть файл

@ -13,6 +13,7 @@
#include "nsIObserver.h" #include "nsIObserver.h"
#include "mozilla/Atomics.h" #include "mozilla/Atomics.h"
#include "mozilla/dom/quota/PersistenceType.h"
#include "mozilla/Mutex.h" #include "mozilla/Mutex.h"
#include "nsClassHashtable.h" #include "nsClassHashtable.h"
#include "nsHashKeys.h" #include "nsHashKeys.h"
@ -26,16 +27,23 @@ class nsEventChainPostVisitor;
namespace mozilla { namespace mozilla {
namespace dom { namespace dom {
class TabContext; class TabContext;
namespace quota {
class OriginOrPatternString;
}
} }
} }
BEGIN_INDEXEDDB_NAMESPACE BEGIN_INDEXEDDB_NAMESPACE
class FileManager; class FileManager;
class FileManagerInfo;
class IndexedDatabaseManager MOZ_FINAL : public nsIIndexedDatabaseManager, class IndexedDatabaseManager MOZ_FINAL : public nsIIndexedDatabaseManager,
public nsIObserver public nsIObserver
{ {
typedef mozilla::dom::quota::OriginOrPatternString OriginOrPatternString;
typedef mozilla::dom::quota::PersistenceType PersistenceType;
public: public:
NS_DECL_ISUPPORTS NS_DECL_ISUPPORTS
NS_DECL_NSIINDEXEDDATABASEMANAGER NS_DECL_NSIINDEXEDDATABASEMANAGER
@ -77,7 +85,8 @@ public:
#endif #endif
already_AddRefed<FileManager> already_AddRefed<FileManager>
GetFileManager(const nsACString& aOrigin, GetFileManager(PersistenceType aPersistenceType,
const nsACString& aOrigin,
const nsAString& aDatabaseName); const nsAString& aDatabaseName);
void void
@ -87,10 +96,12 @@ public:
InvalidateAllFileManagers(); InvalidateAllFileManagers();
void void
InvalidateFileManagersForPattern(const nsACString& aPattern); InvalidateFileManagers(PersistenceType aPersistenceType,
const OriginOrPatternString& aOriginOrPattern);
void void
InvalidateFileManager(const nsACString& aOrigin, InvalidateFileManager(PersistenceType aPersistenceType,
const nsACString& aOrigin,
const nsAString& aDatabaseName); const nsAString& aDatabaseName);
nsresult nsresult
@ -101,7 +112,8 @@ public:
// It is intended to be used by mochitests to test correctness of the special // It is intended to be used by mochitests to test correctness of the special
// reference counting of stored blobs/files. // reference counting of stored blobs/files.
nsresult nsresult
BlockAndGetFileReferences(const nsACString& aOrigin, BlockAndGetFileReferences(PersistenceType aPersistenceType,
const nsACString& aOrigin,
const nsAString& aDatabaseName, const nsAString& aDatabaseName,
int64_t aFileId, int64_t aFileId,
int32_t* aRefCnt, int32_t* aRefCnt,
@ -136,10 +148,14 @@ private:
void void
Destroy(); 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 // 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. // protected by any mutex but it is only ever touched on the IO thread.
nsClassHashtable<nsCStringHashKey, nsClassHashtable<nsCStringHashKey, FileManagerInfo> mFileManagerInfos;
nsTArray<nsRefPtr<FileManager> > > mFileManagers;
// Lock protecting FileManager.mFileInfos and nsDOMFileBase.mFileInfos // Lock protecting FileManager.mFileInfos and nsDOMFileBase.mFileInfos
// It's s also used to atomically update FileInfo.mRefCnt, FileInfo.mDBRefCnt // It's s also used to atomically update FileInfo.mRefCnt, FileInfo.mDBRefCnt

Просмотреть файл

@ -1504,11 +1504,14 @@ public:
OpenDatabaseHelper* aHelper, OpenDatabaseHelper* aHelper,
uint64_t aCurrentVersion, uint64_t aCurrentVersion,
const nsAString& aName, const nsAString& aName,
const nsACString& aASCIIOrigin) const nsACString& aGroup,
const nsACString& aASCIIOrigin,
PersistenceType aPersistenceType)
: AsyncConnectionHelper(static_cast<IDBDatabase*>(nullptr), aRequest), : AsyncConnectionHelper(static_cast<IDBDatabase*>(nullptr), aRequest),
mOpenHelper(aHelper), mOpenRequest(aRequest), mOpenHelper(aHelper), mOpenRequest(aRequest),
mCurrentVersion(aCurrentVersion), mName(aName), mCurrentVersion(aCurrentVersion), mName(aName),
mASCIIOrigin(aASCIIOrigin) mGroup(aGroup), mASCIIOrigin(aASCIIOrigin),
mPersistenceType(aPersistenceType)
{ } { }
NS_DECL_ISUPPORTS_INHERITED NS_DECL_ISUPPORTS_INHERITED
@ -1567,7 +1570,9 @@ private:
nsRefPtr<IDBOpenDBRequest> mOpenRequest; nsRefPtr<IDBOpenDBRequest> mOpenRequest;
uint64_t mCurrentVersion; uint64_t mCurrentVersion;
nsString mName; nsString mName;
nsCString mGroup;
nsCString mASCIIOrigin; nsCString mASCIIOrigin;
PersistenceType mPersistenceType;
}; };
// Responsible for firing "versionchange" events at all live and non-closed // Responsible for firing "versionchange" events at all live and non-closed
@ -1685,21 +1690,50 @@ NS_IMPL_ISUPPORTS1(OpenDatabaseHelper, nsIRunnable)
nsresult nsresult
OpenDatabaseHelper::Init() OpenDatabaseHelper::Init()
{ {
mDatabaseId = QuotaManager::GetStorageId(mASCIIOrigin, mName); mDatabaseId =
QuotaManager::GetStorageId(mPersistenceType, mASCIIOrigin, mName);
NS_ENSURE_TRUE(mDatabaseId, NS_ERROR_FAILURE); NS_ENSURE_TRUE(mDatabaseId, NS_ERROR_FAILURE);
return NS_OK; return NS_OK;
} }
nsresult nsresult
OpenDatabaseHelper::Dispatch(nsIEventTarget* aTarget) OpenDatabaseHelper::WaitForOpenAllowed()
{ {
NS_ASSERTION(mState == eCreated, "We've already been dispatched?"); 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; mState = eDBWork;
return aTarget->Dispatch(this, NS_DISPATCH_NORMAL); 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 nsresult
OpenDatabaseHelper::RunImmediately() OpenDatabaseHelper::RunImmediately()
{ {
@ -1709,6 +1743,7 @@ OpenDatabaseHelper::RunImmediately()
NS_ASSERTION(NS_IsMainThread(), "All hell is about to break lose!"); NS_ASSERTION(NS_IsMainThread(), "All hell is about to break lose!");
mState = eFiringEvents; mState = eFiringEvents;
return this->Run(); return this->Run();
} }
@ -1739,8 +1774,8 @@ OpenDatabaseHelper::DoDatabaseWork()
NS_ASSERTION(quotaManager, "This should never be null!"); NS_ASSERTION(quotaManager, "This should never be null!");
nsresult rv = nsresult rv =
quotaManager->EnsureOriginIsInitialized(mASCIIOrigin, quotaManager->EnsureOriginIsInitialized(mPersistenceType, mGroup,
mTrackingQuota, mASCIIOrigin, mTrackingQuota,
getter_AddRefs(dbDirectory)); getter_AddRefs(dbDirectory));
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 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); NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
nsCOMPtr<mozIStorageConnection> connection; nsCOMPtr<mozIStorageConnection> connection;
rv = CreateDatabaseConnection(dbFile, fmDirectory, mName, mASCIIOrigin, rv = CreateDatabaseConnection(dbFile, fmDirectory, mName, mPersistenceType,
mGroup, mASCIIOrigin,
getter_AddRefs(connection)); getter_AddRefs(connection));
if (NS_FAILED(rv) && if (NS_FAILED(rv) &&
NS_ERROR_GET_MODULE(rv) != NS_ERROR_MODULE_DOM_INDEXEDDB) { NS_ERROR_GET_MODULE(rv) != NS_ERROR_MODULE_DOM_INDEXEDDB) {
@ -1837,9 +1873,11 @@ OpenDatabaseHelper::DoDatabaseWork()
IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get(); IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
NS_ASSERTION(mgr, "This should never be null!"); 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) { if (!fileManager) {
fileManager = new FileManager(mASCIIOrigin, mPrivilege, mName); fileManager = new FileManager(mPersistenceType, mGroup, mASCIIOrigin,
mPrivilege, mName);
rv = fileManager->Init(fmDirectory, connection); rv = fileManager->Init(fmDirectory, connection);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
@ -1858,6 +1896,8 @@ OpenDatabaseHelper::CreateDatabaseConnection(
nsIFile* aDBFile, nsIFile* aDBFile,
nsIFile* aFMDirectory, nsIFile* aFMDirectory,
const nsAString& aName, const nsAString& aName,
PersistenceType aPersistenceType,
const nsACString& aGroup,
const nsACString& aOrigin, const nsACString& aOrigin,
mozIStorageConnection** aConnection) mozIStorageConnection** aConnection)
{ {
@ -1880,7 +1920,7 @@ OpenDatabaseHelper::CreateDatabaseConnection(
} }
nsCOMPtr<nsIFileURL> dbFileUrl = nsCOMPtr<nsIFileURL> dbFileUrl =
IDBFactory::GetDatabaseFileURL(aDBFile, aOrigin); IDBFactory::GetDatabaseFileURL(aDBFile, aPersistenceType, aGroup, aOrigin);
NS_ENSURE_TRUE(dbFileUrl, NS_ERROR_FAILURE); NS_ENSURE_TRUE(dbFileUrl, NS_ERROR_FAILURE);
nsCOMPtr<mozIStorageService> ss = nsCOMPtr<mozIStorageService> ss =
@ -1950,7 +1990,12 @@ OpenDatabaseHelper::CreateDatabaseConnection(
// Turn on auto_vacuum mode to reclaim disk space on mobile devices. // Turn on auto_vacuum mode to reclaim disk space on mobile devices.
"PRAGMA auto_vacuum = FULL; " "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 #endif
@ -2097,7 +2142,7 @@ OpenDatabaseHelper::StartDelete()
nsRefPtr<DeleteDatabaseHelper> helper = nsRefPtr<DeleteDatabaseHelper> helper =
new DeleteDatabaseHelper(mOpenDBRequest, this, mCurrentVersion, mName, new DeleteDatabaseHelper(mOpenDBRequest, this, mCurrentVersion, mName,
mASCIIOrigin); mGroup, mASCIIOrigin, mPersistenceType);
QuotaManager* quotaManager = QuotaManager::Get(); QuotaManager* quotaManager = QuotaManager::Get();
NS_ASSERTION(quotaManager, "This should never be null!"); NS_ASSERTION(quotaManager, "This should never be null!");
@ -2122,6 +2167,10 @@ OpenDatabaseHelper::Run()
if (NS_IsMainThread()) { if (NS_IsMainThread()) {
PROFILER_MAIN_THREAD_LABEL("IndexedDB", "OpenDatabaseHelper::Run"); PROFILER_MAIN_THREAD_LABEL("IndexedDB", "OpenDatabaseHelper::Run");
if (mState == eOpenPending) {
return DispatchToIOThread();
}
// If we need to queue up a SetVersionHelper, do that here. // If we need to queue up a SetVersionHelper, do that here.
if (mState == eSetVersionPending) { if (mState == eSetVersionPending) {
nsresult rv = StartSetVersion(); nsresult rv = StartSetVersion();
@ -2199,9 +2248,10 @@ OpenDatabaseHelper::Run()
QuotaManager* quotaManager = QuotaManager::Get(); QuotaManager* quotaManager = QuotaManager::Get();
NS_ASSERTION(quotaManager, "This should never be null!"); NS_ASSERTION(quotaManager, "This should never be null!");
quotaManager->AllowNextSynchronizedOp( quotaManager->
OriginOrPatternString::FromOrigin(mASCIIOrigin), AllowNextSynchronizedOp(OriginOrPatternString::FromOrigin(mASCIIOrigin),
mDatabaseId); Nullable<PersistenceType>(mPersistenceType),
mDatabaseId);
ReleaseMainThreadObjects(); ReleaseMainThreadObjects();
@ -2242,6 +2292,7 @@ OpenDatabaseHelper::EnsureSuccessResult()
{ {
NS_ASSERTION(dbInfo->name == mName && NS_ASSERTION(dbInfo->name == mName &&
dbInfo->version == mCurrentVersion && dbInfo->version == mCurrentVersion &&
dbInfo->persistenceType == mPersistenceType &&
dbInfo->id == mDatabaseId && dbInfo->id == mDatabaseId &&
dbInfo->filePath == mDatabaseFilePath, dbInfo->filePath == mDatabaseFilePath,
"Metadata mismatch!"); "Metadata mismatch!");
@ -2284,7 +2335,9 @@ OpenDatabaseHelper::EnsureSuccessResult()
nsRefPtr<DatabaseInfo> newInfo(new DatabaseInfo()); nsRefPtr<DatabaseInfo> newInfo(new DatabaseInfo());
newInfo->name = mName; newInfo->name = mName;
newInfo->group = mGroup;
newInfo->origin = mASCIIOrigin; newInfo->origin = mASCIIOrigin;
newInfo->persistenceType = mPersistenceType;
newInfo->id = mDatabaseId; newInfo->id = mDatabaseId;
newInfo->filePath = mDatabaseFilePath; newInfo->filePath = mDatabaseFilePath;
@ -2576,7 +2629,8 @@ DeleteDatabaseHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
NS_ASSERTION(quotaManager, "This should never fail!"); NS_ASSERTION(quotaManager, "This should never fail!");
nsCOMPtr<nsIFile> directory; nsCOMPtr<nsIFile> directory;
nsresult rv = quotaManager->GetDirectoryForOrigin(mASCIIOrigin, nsresult rv = quotaManager->GetDirectoryForOrigin(mPersistenceType,
mASCIIOrigin,
getter_AddRefs(directory)); getter_AddRefs(directory));
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
@ -2615,7 +2669,8 @@ DeleteDatabaseHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
QuotaManager* quotaManager = QuotaManager::Get(); QuotaManager* quotaManager = QuotaManager::Get();
NS_ASSERTION(quotaManager, "Shouldn't be null!"); 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(); QuotaManager* quotaManager = QuotaManager::Get();
NS_ASSERTION(quotaManager, "Shouldn't be null!"); NS_ASSERTION(quotaManager, "Shouldn't be null!");
quotaManager->DecreaseUsageForOrigin(mASCIIOrigin, usage); quotaManager->DecreaseUsageForOrigin(mPersistenceType, mGroup,
mASCIIOrigin, usage);
} }
} }
IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get(); IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
NS_ASSERTION(mgr, "This should never fail!"); NS_ASSERTION(mgr, "This should never fail!");
mgr->InvalidateFileManager(mASCIIOrigin, mName); mgr->InvalidateFileManager(mPersistenceType, mASCIIOrigin, mName);
return NS_OK; return NS_OK;
} }

Просмотреть файл

@ -31,18 +31,22 @@ class OpenDatabaseHelper : public HelperBase
{ {
friend class CheckPermissionsHelper; friend class CheckPermissionsHelper;
typedef mozilla::dom::quota::PersistenceType PersistenceType;
typedef mozilla::dom::quota::StoragePrivilege StoragePrivilege; typedef mozilla::dom::quota::StoragePrivilege StoragePrivilege;
public: public:
OpenDatabaseHelper(IDBOpenDBRequest* aRequest, OpenDatabaseHelper(IDBOpenDBRequest* aRequest,
const nsAString& aName, const nsAString& aName,
const nsACString& aGroup,
const nsACString& aASCIIOrigin, const nsACString& aASCIIOrigin,
uint64_t aRequestedVersion, uint64_t aRequestedVersion,
PersistenceType aPersistenceType,
bool aForDeletion, bool aForDeletion,
mozilla::dom::ContentParent* aContentParent, mozilla::dom::ContentParent* aContentParent,
StoragePrivilege aPrivilege) StoragePrivilege aPrivilege)
: HelperBase(aRequest), mOpenDBRequest(aRequest), mName(aName), : HelperBase(aRequest), mOpenDBRequest(aRequest), mName(aName),
mASCIIOrigin(aASCIIOrigin), mRequestedVersion(aRequestedVersion), mGroup(aGroup), mASCIIOrigin(aASCIIOrigin),
mRequestedVersion(aRequestedVersion), mPersistenceType(aPersistenceType),
mForDeletion(aForDeletion), mPrivilege(aPrivilege), mDatabaseId(nullptr), mForDeletion(aForDeletion), mPrivilege(aPrivilege), mDatabaseId(nullptr),
mContentParent(aContentParent), mCurrentVersion(0), mLastObjectStoreId(0), mContentParent(aContentParent), mCurrentVersion(0), mLastObjectStoreId(0),
mLastIndexId(0), mState(eCreated), mResultCode(NS_OK), mLastIndexId(0), mState(eCreated), mResultCode(NS_OK),
@ -58,7 +62,9 @@ public:
nsresult Init(); nsresult Init();
nsresult WaitForOpenAllowed();
nsresult Dispatch(nsIEventTarget* aDatabaseThread); nsresult Dispatch(nsIEventTarget* aDatabaseThread);
nsresult DispatchToIOThread();
nsresult RunImmediately(); nsresult RunImmediately();
void SetError(nsresult rv) void SetError(nsresult rv)
@ -96,6 +102,8 @@ public:
nsresult CreateDatabaseConnection(nsIFile* aDBFile, nsresult CreateDatabaseConnection(nsIFile* aDBFile,
nsIFile* aFMDirectory, nsIFile* aFMDirectory,
const nsAString& aName, const nsAString& aName,
PersistenceType aPersistenceType,
const nsACString& aGroup,
const nsACString& aOrigin, const nsACString& aOrigin,
mozIStorageConnection** aConnection); mozIStorageConnection** aConnection);
@ -122,8 +130,10 @@ protected:
// In-params. // In-params.
nsRefPtr<IDBOpenDBRequest> mOpenDBRequest; nsRefPtr<IDBOpenDBRequest> mOpenDBRequest;
nsString mName; nsString mName;
nsCString mGroup;
nsCString mASCIIOrigin; nsCString mASCIIOrigin;
uint64_t mRequestedVersion; uint64_t mRequestedVersion;
PersistenceType mPersistenceType;
bool mForDeletion; bool mForDeletion;
StoragePrivilege mPrivilege; StoragePrivilege mPrivilege;
nsCOMPtr<nsIAtom> mDatabaseId; nsCOMPtr<nsIAtom> mDatabaseId;
@ -140,6 +150,7 @@ protected:
// State variables // State variables
enum OpenDatabaseState { enum OpenDatabaseState {
eCreated = 0, // Not yet dispatched to the DB thread 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 eDBWork, // Waiting to do/doing work on the DB thread
eFiringEvents, // Waiting to fire/firing events on the main thread eFiringEvents, // Waiting to fire/firing events on the main thread
eSetVersionPending, // Waiting on a SetVersionHelper eSetVersionPending, // Waiting on a SetVersionHelper

Просмотреть файл

@ -210,8 +210,10 @@ IndexedDBChild::ActorDestroy(ActorDestroyReason aWhy)
} }
PIndexedDBDatabaseChild* PIndexedDBDatabaseChild*
IndexedDBChild::AllocPIndexedDBDatabaseChild(const nsString& aName, IndexedDBChild::AllocPIndexedDBDatabaseChild(
const uint64_t& aVersion) const nsString& aName,
const uint64_t& aVersion,
const PersistenceType& aPersistenceType)
{ {
return new IndexedDBDatabaseChild(aName, aVersion); return new IndexedDBDatabaseChild(aName, aVersion);
} }
@ -224,7 +226,9 @@ IndexedDBChild::DeallocPIndexedDBDatabaseChild(PIndexedDBDatabaseChild* aActor)
} }
PIndexedDBDeleteDatabaseRequestChild* PIndexedDBDeleteDatabaseRequestChild*
IndexedDBChild::AllocPIndexedDBDeleteDatabaseRequestChild(const nsString& aName) IndexedDBChild::AllocPIndexedDBDeleteDatabaseRequestChild(
const nsString& aName,
const PersistenceType& aPersistenceType)
{ {
MOZ_CRASH("Caller is supposed to manually construct a request!"); MOZ_CRASH("Caller is supposed to manually construct a request!");
} }
@ -285,7 +289,8 @@ IndexedDBDatabaseChild::EnsureDatabase(
databaseId = mDatabase->Id(); databaseId = mDatabase->Id();
} }
else { else {
databaseId = QuotaManager::GetStorageId(aDBInfo.origin, aDBInfo.name); databaseId = QuotaManager::GetStorageId(aDBInfo.persistenceType,
aDBInfo.origin, aDBInfo.name);
} }
NS_ENSURE_TRUE(databaseId, false); NS_ENSURE_TRUE(databaseId, false);

Просмотреть файл

@ -65,14 +65,18 @@ protected:
ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE; ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
virtual PIndexedDBDatabaseChild* virtual PIndexedDBDatabaseChild*
AllocPIndexedDBDatabaseChild(const nsString& aName, const uint64_t& aVersion) AllocPIndexedDBDatabaseChild(const nsString& aName, const uint64_t& aVersion,
const PersistenceType& aPersistenceType)
MOZ_OVERRIDE; MOZ_OVERRIDE;
virtual bool virtual bool
DeallocPIndexedDBDatabaseChild(PIndexedDBDatabaseChild* aActor) MOZ_OVERRIDE; DeallocPIndexedDBDatabaseChild(PIndexedDBDatabaseChild* aActor) MOZ_OVERRIDE;
virtual PIndexedDBDeleteDatabaseRequestChild* virtual PIndexedDBDeleteDatabaseRequestChild*
AllocPIndexedDBDeleteDatabaseRequestChild(const nsString& aName) MOZ_OVERRIDE; AllocPIndexedDBDeleteDatabaseRequestChild(
const nsString& aName,
const PersistenceType& aPersistenceType)
MOZ_OVERRIDE;
virtual bool virtual bool
DeallocPIndexedDBDeleteDatabaseRequestChild( DeallocPIndexedDBDeleteDatabaseRequestChild(

Просмотреть файл

@ -144,9 +144,10 @@ IndexedDBParent::ActorDestroy(ActorDestroyReason aWhy)
bool bool
IndexedDBParent::RecvPIndexedDBDatabaseConstructor( IndexedDBParent::RecvPIndexedDBDatabaseConstructor(
PIndexedDBDatabaseParent* aActor, PIndexedDBDatabaseParent* aActor,
const nsString& aName, const nsString& aName,
const uint64_t& aVersion) const uint64_t& aVersion,
const PersistenceType& aPersistenceType)
{ {
if (!CheckReadPermission(aName)) { if (!CheckReadPermission(aName)) {
return false; return false;
@ -162,8 +163,8 @@ IndexedDBParent::RecvPIndexedDBDatabaseConstructor(
} }
nsRefPtr<IDBOpenDBRequest> request; nsRefPtr<IDBOpenDBRequest> request;
nsresult rv = nsresult rv = mFactory->OpenInternal(aName, aVersion, aPersistenceType, false,
mFactory->OpenInternal(aName, aVersion, false, getter_AddRefs(request)); getter_AddRefs(request));
NS_ENSURE_SUCCESS(rv, false); NS_ENSURE_SUCCESS(rv, false);
IndexedDBDatabaseParent* actor = IndexedDBDatabaseParent* actor =
@ -178,7 +179,8 @@ IndexedDBParent::RecvPIndexedDBDatabaseConstructor(
bool bool
IndexedDBParent::RecvPIndexedDBDeleteDatabaseRequestConstructor( IndexedDBParent::RecvPIndexedDBDeleteDatabaseRequestConstructor(
PIndexedDBDeleteDatabaseRequestParent* aActor, PIndexedDBDeleteDatabaseRequestParent* aActor,
const nsString& aName) const nsString& aName,
const PersistenceType& aPersistenceType)
{ {
if (!CheckWritePermission(aName)) { if (!CheckWritePermission(aName)) {
return false; return false;
@ -198,8 +200,8 @@ IndexedDBParent::RecvPIndexedDBDeleteDatabaseRequestConstructor(
nsRefPtr<IDBOpenDBRequest> request; nsRefPtr<IDBOpenDBRequest> request;
nsresult rv = nsresult rv = mFactory->OpenInternal(aName, 0, aPersistenceType, true,
mFactory->OpenInternal(aName, 0, true, getter_AddRefs(request)); getter_AddRefs(request));
NS_ENSURE_SUCCESS(rv, false); NS_ENSURE_SUCCESS(rv, false);
rv = actor->SetOpenRequest(request); rv = actor->SetOpenRequest(request);
@ -209,8 +211,10 @@ IndexedDBParent::RecvPIndexedDBDeleteDatabaseRequestConstructor(
} }
PIndexedDBDatabaseParent* PIndexedDBDatabaseParent*
IndexedDBParent::AllocPIndexedDBDatabaseParent(const nsString& aName, IndexedDBParent::AllocPIndexedDBDatabaseParent(
const uint64_t& aVersion) const nsString& aName,
const uint64_t& aVersion,
const PersistenceType& aPersistenceType)
{ {
return new IndexedDBDatabaseParent(); return new IndexedDBDatabaseParent();
} }
@ -223,7 +227,9 @@ IndexedDBParent::DeallocPIndexedDBDatabaseParent(PIndexedDBDatabaseParent* aActo
} }
PIndexedDBDeleteDatabaseRequestParent* PIndexedDBDeleteDatabaseRequestParent*
IndexedDBParent::AllocPIndexedDBDeleteDatabaseRequestParent(const nsString& aName) IndexedDBParent::AllocPIndexedDBDeleteDatabaseRequestParent(
const nsString& aName,
const PersistenceType& aPersistenceType)
{ {
return new IndexedDBDeleteDatabaseRequestParent(mFactory); return new IndexedDBDeleteDatabaseRequestParent(mFactory);
} }

Просмотреть файл

@ -205,22 +205,30 @@ protected:
virtual bool virtual bool
RecvPIndexedDBDatabaseConstructor(PIndexedDBDatabaseParent* aActor, RecvPIndexedDBDatabaseConstructor(PIndexedDBDatabaseParent* aActor,
const nsString& aName, const nsString& aName,
const uint64_t& aVersion) MOZ_OVERRIDE; const uint64_t& aVersion,
const PersistenceType& aPersistenceType)
MOZ_OVERRIDE;
virtual bool virtual bool
RecvPIndexedDBDeleteDatabaseRequestConstructor( RecvPIndexedDBDeleteDatabaseRequestConstructor(
PIndexedDBDeleteDatabaseRequestParent* aActor, PIndexedDBDeleteDatabaseRequestParent* aActor,
const nsString& aName) MOZ_OVERRIDE; const nsString& aName,
const PersistenceType& aPersistenceType)
MOZ_OVERRIDE;
virtual PIndexedDBDatabaseParent* virtual PIndexedDBDatabaseParent*
AllocPIndexedDBDatabaseParent(const nsString& aName, const uint64_t& aVersion) AllocPIndexedDBDatabaseParent(const nsString& aName, const uint64_t& aVersion,
const PersistenceType& aPersistenceType)
MOZ_OVERRIDE; MOZ_OVERRIDE;
virtual bool virtual bool
DeallocPIndexedDBDatabaseParent(PIndexedDBDatabaseParent* aActor) MOZ_OVERRIDE; DeallocPIndexedDBDatabaseParent(PIndexedDBDatabaseParent* aActor) MOZ_OVERRIDE;
virtual PIndexedDBDeleteDatabaseRequestParent* virtual PIndexedDBDeleteDatabaseRequestParent*
AllocPIndexedDBDeleteDatabaseRequestParent(const nsString& aName) MOZ_OVERRIDE; AllocPIndexedDBDeleteDatabaseRequestParent(
const nsString& aName,
const PersistenceType& aPersistenceType)
MOZ_OVERRIDE;
virtual bool virtual bool
DeallocPIndexedDBDeleteDatabaseRequestParent( DeallocPIndexedDBDeleteDatabaseRequestParent(

Просмотреть файл

@ -7,6 +7,10 @@ include protocol PContent;
include protocol PIndexedDBDatabase; include protocol PIndexedDBDatabase;
include protocol PIndexedDBDeleteDatabaseRequest; include protocol PIndexedDBDeleteDatabaseRequest;
include "mozilla/dom/indexedDB/SerializationHelpers.h";
using mozilla::dom::quota::PersistenceType;
namespace mozilla { namespace mozilla {
namespace dom { namespace dom {
namespace indexedDB { namespace indexedDB {
@ -21,9 +25,11 @@ protocol PIndexedDB
parent: parent:
__delete__(); __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 } // namespace indexedDB

Просмотреть файл

@ -15,6 +15,13 @@
namespace IPC { 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 <> template <>
struct ParamTraits<mozilla::dom::indexedDB::Key> struct ParamTraits<mozilla::dom::indexedDB::Key>
{ {
@ -154,8 +161,10 @@ struct ParamTraits<mozilla::dom::indexedDB::DatabaseInfoGuts>
static void Write(Message* aMsg, const paramType& aParam) static void Write(Message* aMsg, const paramType& aParam)
{ {
WriteParam(aMsg, aParam.name); WriteParam(aMsg, aParam.name);
WriteParam(aMsg, aParam.group);
WriteParam(aMsg, aParam.origin); WriteParam(aMsg, aParam.origin);
WriteParam(aMsg, aParam.version); WriteParam(aMsg, aParam.version);
WriteParam(aMsg, aParam.persistenceType);
WriteParam(aMsg, aParam.nextObjectStoreId); WriteParam(aMsg, aParam.nextObjectStoreId);
WriteParam(aMsg, aParam.nextIndexId); WriteParam(aMsg, aParam.nextIndexId);
} }
@ -163,8 +172,10 @@ struct ParamTraits<mozilla::dom::indexedDB::DatabaseInfoGuts>
static bool Read(const Message* aMsg, void** aIter, paramType* aResult) static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
{ {
return ReadParam(aMsg, aIter, &aResult->name) && return ReadParam(aMsg, aIter, &aResult->name) &&
ReadParam(aMsg, aIter, &aResult->group) &&
ReadParam(aMsg, aIter, &aResult->origin) && ReadParam(aMsg, aIter, &aResult->origin) &&
ReadParam(aMsg, aIter, &aResult->version) && ReadParam(aMsg, aIter, &aResult->version) &&
ReadParam(aMsg, aIter, &aResult->persistenceType) &&
ReadParam(aMsg, aIter, &aResult->nextObjectStoreId) && ReadParam(aMsg, aIter, &aResult->nextObjectStoreId) &&
ReadParam(aMsg, aIter, &aResult->nextIndexId); ReadParam(aMsg, aIter, &aResult->nextIndexId);
} }
@ -172,6 +183,7 @@ struct ParamTraits<mozilla::dom::indexedDB::DatabaseInfoGuts>
static void Log(const paramType& aParam, std::wstring* aLog) static void Log(const paramType& aParam, std::wstring* aLog)
{ {
LogParam(aParam.name, aLog); LogParam(aParam.name, aLog);
LogParam(aParam.group, aLog);
LogParam(aParam.origin, aLog); LogParam(aParam.origin, aLog);
LogParam(aParam.version, aLog); LogParam(aParam.version, aLog);
LogParam(aParam.nextObjectStoreId, aLog); LogParam(aParam.nextObjectStoreId, aLog);

Просмотреть файл

@ -79,6 +79,7 @@ MOCHITEST_FILES = \
test_open_objectStore.html \ test_open_objectStore.html \
test_optionalArguments.html \ test_optionalArguments.html \
test_overlapping_transactions.html \ test_overlapping_transactions.html \
test_persistenceType.html \
test_put_get_values.html \ test_put_get_values.html \
test_put_get_values_autoIncrement.html \ test_put_get_values_autoIncrement.html \
test_readonly_transactions.html \ test_readonly_transactions.html \

Просмотреть файл

@ -190,11 +190,6 @@ function getUsage(usageHandler)
quotaManager.getUsageForURI(uri, cb); quotaManager.getUsageForURI(uri, cb);
} }
function scheduleGC()
{
SpecialPowers.exactGC(window, continueToNextStep);
}
function getFileId(file) function getFileId(file)
{ {
return utils.getFileId(file); return utils.getFileId(file);
@ -208,13 +203,13 @@ function hasFileInfo(name, id)
function getFileRefCount(name, id) function getFileRefCount(name, id)
{ {
let count = {}; let count = {};
utils.getFileReferences(name, id, count); utils.getFileReferences(name, id, null, count);
return count.value; return count.value;
} }
function getFileDBRefCount(name, id) function getFileDBRefCount(name, id)
{ {
let count = {}; let count = {};
utils.getFileReferences(name, id, {}, count); utils.getFileReferences(name, id, null, {}, count);
return count.value; return count.value;
} }

Просмотреть файл

@ -84,6 +84,7 @@ if (!window.runTest) {
allowUnlimitedQuota(); allowUnlimitedQuota();
} }
enableExperimental();
enableArchiveReader(); enableArchiveReader();
clearAllDatabases(function () { testGenerator.next(); }); clearAllDatabases(function () { testGenerator.next(); });
@ -93,6 +94,7 @@ if (!window.runTest) {
function finishTest() function finishTest()
{ {
resetUnlimitedQuota(); resetUnlimitedQuota();
resetExperimental();
resetArchiveReader(); resetArchiveReader();
SpecialPowers.notifyObserversInParentProcess(null, "disk-space-watcher", SpecialPowers.notifyObserversInParentProcess(null, "disk-space-watcher",
"free"); "free");
@ -253,8 +255,23 @@ function resetArchiveReader()
SpecialPowers.setBoolPref("dom.archivereader.enabled", archiveReaderEnabled); SpecialPowers.setBoolPref("dom.archivereader.enabled", archiveReaderEnabled);
} }
function enableExperimental()
{
SpecialPowers.setBoolPref("dom.indexedDB.experimental", true);
}
function resetExperimental()
{
SpecialPowers.clearUserPref("dom.indexedDB.experimental");
}
function gc() function gc()
{ {
SpecialPowers.forceGC(); SpecialPowers.forceGC();
SpecialPowers.forceCC(); SpecialPowers.forceCC();
} }
function scheduleGC()
{
SpecialPowers.exactGC(window, continueToNextStep);
}

Просмотреть файл

@ -46,7 +46,7 @@
for (let id = 1; id <= 100; id++) { for (let id = 1; id <= 100; id++) {
let refs = {}; let refs = {};
let dbRefs = {}; let dbRefs = {};
let hasFileInfo = utils.getFileReferences(name, id, refs, dbRefs); let hasFileInfo = utils.getFileReferences(name, id, null, refs, dbRefs);
ok(hasFileInfo, "Has file info"); ok(hasFileInfo, "Has file info");
is(refs.value, 1, "Correct ref count"); is(refs.value, 1, "Correct ref count");
is(dbRefs.value, id / 100 >> 0, "Correct db 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_open_objectStore.js \
test_optionalArguments.js \ test_optionalArguments.js \
test_overlapping_transactions.js \ test_overlapping_transactions.js \
test_persistenceType.js \
test_put_get_values.js \ test_put_get_values.js \
test_put_get_values_autoIncrement.js \ test_put_get_values_autoIncrement.js \
test_readonly_transactions.js \ test_readonly_transactions.js \
@ -57,6 +58,7 @@ MOCHITEST_FILES = \
test_setVersion_events.js \ test_setVersion_events.js \
test_setVersion_exclusion.js \ test_setVersion_exclusion.js \
test_success_events_after_abort.js \ test_success_events_after_abort.js \
test_temporary_storage.js \
test_traffic_jam.js \ test_traffic_jam.js \
test_transaction_abort.js \ test_transaction_abort.js \
test_transaction_abort_hang.js \ test_transaction_abort_hang.js \

Просмотреть файл

@ -47,16 +47,20 @@ function runTest()
getService(Ci.nsIIndexedDatabaseManager); getService(Ci.nsIIndexedDatabaseManager);
idbManager.initWindowless(this); idbManager.initWindowless(this);
enableExperimental();
do_test_pending(); do_test_pending();
testGenerator.next(); testGenerator.next();
} }
function finishTest() function finishTest()
{ {
resetExperimental();
SpecialPowers.notifyObserversInParentProcess(null, "disk-space-watcher",
"free");
do_execute_soon(function(){ do_execute_soon(function(){
testGenerator.close(); testGenerator.close();
SpecialPowers.notifyObserversInParentProcess(null, "disk-space-watcher",
"free");
do_test_finished(); do_test_finished();
}) })
} }
@ -179,12 +183,27 @@ function disallowUnlimitedQuota(url)
throw "disallowUnlimitedQuota"; throw "disallowUnlimitedQuota";
} }
function enableExperimental()
{
SpecialPowers.setBoolPref("dom.indexedDB.experimental", true);
}
function resetExperimental()
{
SpecialPowers.clearUserPref("dom.indexedDB.experimental");
}
function gc() function gc()
{ {
Components.utils.forceGC(); Components.utils.forceGC();
Components.utils.forceCC(); Components.utils.forceCC();
} }
function scheduleGC()
{
SpecialPowers.exactGC(null, continueToNextStep);
}
function setTimeout(fun, timeout) { function setTimeout(fun, timeout) {
let timer = Components.classes["@mozilla.org/timer;1"] let timer = Components.classes["@mozilla.org/timer;1"]
.createInstance(Components.interfaces.nsITimer); .createInstance(Components.interfaces.nsITimer);
@ -214,5 +233,43 @@ var SpecialPowers = {
throw new Error("Can't send subject to another process!"); throw new Error("Can't send subject to another process!");
} }
return this.notifyObservers(subject, topic, data); 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."); 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(); finishTest();
yield undefined; 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_open_objectStore.js]
[test_optionalArguments.js] [test_optionalArguments.js]
[test_overlapping_transactions.js] [test_overlapping_transactions.js]
[test_persistenceType.js]
[test_put_get_values.js] [test_put_get_values.js]
[test_put_get_values_autoIncrement.js] [test_put_get_values_autoIncrement.js]
[test_readonly_transactions.js] [test_readonly_transactions.js]
@ -58,6 +59,7 @@ tail =
[test_setVersion_events.js] [test_setVersion_events.js]
[test_setVersion_exclusion.js] [test_setVersion_exclusion.js]
[test_success_events_after_abort.js] [test_success_events_after_abort.js]
[test_temporary_storage.js]
[test_traffic_jam.js] [test_traffic_jam.js]
[test_transaction_abort.js] [test_transaction_abort.js]
[test_transaction_abort_hang.js] [test_transaction_abort_hang.js]

Просмотреть файл

@ -42,7 +42,7 @@ interface nsIURI;
interface nsIDOMEventTarget; interface nsIDOMEventTarget;
interface nsIRunnable; interface nsIRunnable;
[scriptable, uuid(d6e733ef-492b-4e67-b723-28571c2959f0)] [scriptable, uuid(d18a8d69-7609-4165-ae20-af8aead36833)]
interface nsIDOMWindowUtils : nsISupports { interface nsIDOMWindowUtils : nsISupports {
/** /**
@ -1229,7 +1229,9 @@ interface nsIDOMWindowUtils : nsISupports {
* Get file ref count info for given database and file id. * Get file ref count info for given database and file id.
* *
*/ */
[implicit_jscontext]
boolean getFileReferences(in AString aDatabaseName, in long long aId, boolean getFileReferences(in AString aDatabaseName, in long long aId,
[optional] in jsval aOptions,
[optional] out long aRefCnt, [optional] out long aRefCnt,
[optional] out long aDBRefCnt, [optional] out long aDBRefCnt,
[optional] out long aSliceRefCnt); [optional] out long aSliceRefCnt);

Просмотреть файл

@ -251,7 +251,7 @@ parent:
POfflineCacheUpdate(URIParams manifestURI, URIParams documentURI, POfflineCacheUpdate(URIParams manifestURI, URIParams documentURI,
bool stickDocument); bool stickDocument);
sync PIndexedDB(nsCString asciiOrigin) sync PIndexedDB(nsCString group, nsCString asciiOrigin)
returns (bool allowed); returns (bool allowed);
/** /**

Просмотреть файл

@ -2445,7 +2445,9 @@ TabChild::GetMessageManager(nsIContentFrameMessageManager** aResult)
} }
PIndexedDBChild* PIndexedDBChild*
TabChild::AllocPIndexedDBChild(const nsCString& aASCIIOrigin, bool* /* aAllowed */) TabChild::AllocPIndexedDBChild(
const nsCString& aGroup,
const nsCString& aASCIIOrigin, bool* /* aAllowed */)
{ {
NS_NOTREACHED("Should never get here!"); NS_NOTREACHED("Should never get here!");
return NULL; return NULL;

Просмотреть файл

@ -351,7 +351,8 @@ protected:
nsEventStatus DispatchWidgetEvent(nsGUIEvent& event); nsEventStatus DispatchWidgetEvent(nsGUIEvent& event);
virtual PIndexedDBChild* AllocPIndexedDBChild(const nsCString& aASCIIOrigin, virtual PIndexedDBChild* AllocPIndexedDBChild(const nsCString& aGroup,
const nsCString& aASCIIOrigin,
bool* /* aAllowed */); bool* /* aAllowed */);
virtual bool DeallocPIndexedDBChild(PIndexedDBChild* aActor); virtual bool DeallocPIndexedDBChild(PIndexedDBChild* aActor);

Просмотреть файл

@ -1195,7 +1195,9 @@ TabParent::ReceiveMessage(const nsString& aMessage,
} }
PIndexedDBParent* PIndexedDBParent*
TabParent::AllocPIndexedDBParent(const nsCString& aASCIIOrigin, bool* /* aAllowed */) TabParent::AllocPIndexedDBParent(
const nsCString& aGroup,
const nsCString& aASCIIOrigin, bool* /* aAllowed */)
{ {
return new IndexedDBParent(this); return new IndexedDBParent(this);
} }
@ -1209,6 +1211,7 @@ TabParent::DeallocPIndexedDBParent(PIndexedDBParent* aActor)
bool bool
TabParent::RecvPIndexedDBConstructor(PIndexedDBParent* aActor, TabParent::RecvPIndexedDBConstructor(PIndexedDBParent* aActor,
const nsCString& aGroup,
const nsCString& aASCIIOrigin, const nsCString& aASCIIOrigin,
bool* aAllowed) bool* aAllowed)
{ {
@ -1263,7 +1266,7 @@ TabParent::RecvPIndexedDBConstructor(PIndexedDBParent* aActor,
NS_ASSERTION(contentParent, "Null manager?!"); NS_ASSERTION(contentParent, "Null manager?!");
nsRefPtr<IDBFactory> factory; nsRefPtr<IDBFactory> factory;
rv = IDBFactory::Create(window, aASCIIOrigin, contentParent, rv = IDBFactory::Create(window, aGroup, aASCIIOrigin, contentParent,
getter_AddRefs(factory)); getter_AddRefs(factory));
NS_ENSURE_SUCCESS(rv, false); NS_ENSURE_SUCCESS(rv, false);

Просмотреть файл

@ -248,13 +248,16 @@ protected:
virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE; virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE;
virtual PIndexedDBParent* AllocPIndexedDBParent(const nsCString& aASCIIOrigin, virtual PIndexedDBParent* AllocPIndexedDBParent(
bool* /* aAllowed */); const nsCString& aGroup,
const nsCString& aASCIIOrigin,
bool* /* aAllowed */);
virtual bool DeallocPIndexedDBParent(PIndexedDBParent* aActor); virtual bool DeallocPIndexedDBParent(PIndexedDBParent* aActor);
virtual bool virtual bool
RecvPIndexedDBConstructor(PIndexedDBParent* aActor, RecvPIndexedDBConstructor(PIndexedDBParent* aActor,
const nsCString& aGroup,
const nsCString& aASCIIOrigin, const nsCString& aASCIIOrigin,
bool* aAllowed); bool* aAllowed);

Просмотреть файл

@ -21,7 +21,8 @@ var gData = [
// test substitute // test substitute
{ {
permission: "storage", permission: "storage",
expected: ["indexedDB-unlimited", "offline-app", "pin-app"] expected: ["indexedDB-unlimited", "offline-app", "pin-app",
"default-persistent-storage"]
}, },
// test unknown access // test unknown access
{ {

Просмотреть файл

@ -120,9 +120,8 @@ CheckQuotaHelper::GetQuotaPermission(nsIPrincipal* aPrincipal)
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(aPrincipal, "Null principal!"); NS_ASSERTION(aPrincipal, "Null principal!");
if (nsContentUtils::IsSystemPrincipal(aPrincipal)) { NS_ASSERTION(!nsContentUtils::IsSystemPrincipal(aPrincipal),
return nsIPermissionManager::ALLOW_ACTION; "Chrome windows shouldn't track quota!");
}
nsCOMPtr<nsIPermissionManager> pm = nsCOMPtr<nsIPermissionManager> pm =
do_GetService(NS_PERMISSIONMANAGER_CONTRACTID); do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
@ -200,7 +199,7 @@ CheckQuotaHelper::Run()
NS_ASSERTION(mWaiting, "Huh?!"); NS_ASSERTION(mWaiting, "Huh?!");
// This should never be used again. // This should never be used again.
mWindow = nullptr; mWindow = nullptr;
mWaiting = false; mWaiting = false;

Просмотреть файл

@ -13,8 +13,8 @@
#include "nsIObserver.h" #include "nsIObserver.h"
#include "nsIRunnable.h" #include "nsIRunnable.h"
#include "mozilla/Mutex.h"
#include "mozilla/CondVar.h" #include "mozilla/CondVar.h"
#include "mozilla/Mutex.h"
class nsIPrincipal; class nsIPrincipal;
class nsPIDOMWindow; class nsPIDOMWindow;
@ -34,11 +34,14 @@ public:
CheckQuotaHelper(nsPIDOMWindow* aWindow, CheckQuotaHelper(nsPIDOMWindow* aWindow,
mozilla::Mutex& aMutex); mozilla::Mutex& aMutex);
bool PromptAndReturnQuotaIsDisabled(); bool
PromptAndReturnQuotaIsDisabled();
void Cancel(); void
Cancel();
static uint32_t GetQuotaPermission(nsIPrincipal* aPrincipal); static uint32_t
GetQuotaPermission(nsIPrincipal* aPrincipal);
private: private:
nsPIDOMWindow* mWindow; nsPIDOMWindow* mWindow;

Просмотреть файл

@ -9,12 +9,15 @@
#include "mozilla/dom/quota/QuotaCommon.h" #include "mozilla/dom/quota/QuotaCommon.h"
#include "PersistenceType.h"
class nsIOfflineStorage; class nsIOfflineStorage;
class nsIRunnable; class nsIRunnable;
BEGIN_QUOTA_NAMESPACE BEGIN_QUOTA_NAMESPACE
class UsageRunnable; class OriginOrPatternString;
class UsageInfo;
// An abstract interface for quota manager clients. // An abstract interface for quota manager clients.
// Each storage API must provide an implementation of this interface in order // 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. // Methods which are called on the IO thred.
virtual nsresult virtual nsresult
InitOrigin(const nsACString& aOrigin, UsageRunnable* aUsageRunnable) = 0; InitOrigin(PersistenceType aPersistenceType,
const nsACString& aGroup,
const nsACString& aOrigin,
UsageInfo* aUsageInfo) = 0;
virtual nsresult virtual nsresult
GetUsageForOrigin(const nsACString& aOrigin, GetUsageForOrigin(PersistenceType aPersistenceType,
UsageRunnable* aUsageRunnable) = 0; const nsACString& aGroup,
const nsACString& aOrigin,
UsageInfo* aUsageInfo) = 0;
virtual void virtual void
OnOriginClearCompleted(const nsACString& aPattern) = 0; OnOriginClearCompleted(PersistenceType aPersistenceType,
const OriginOrPatternString& aOriginOrPattern) = 0;
virtual void virtual void
ReleaseIOThreadObjects() = 0; ReleaseIOThreadObjects() = 0;

Просмотреть файл

@ -48,7 +48,7 @@ FileQuotaStream<FileStreamBase>::DoOpen()
NS_ASSERTION(quotaManager, "Shouldn't be null!"); NS_ASSERTION(quotaManager, "Shouldn't be null!");
NS_ASSERTION(!mQuotaObject, "Creating quota object more than once?"); NS_ASSERTION(!mQuotaObject, "Creating quota object more than once?");
mQuotaObject = quotaManager->GetQuotaObject(mOrigin, mQuotaObject = quotaManager->GetQuotaObject(mPersistenceType, mGroup, mOrigin,
FileStreamBase::mOpenParams.localFile); FileStreamBase::mOpenParams.localFile);
nsresult rv = FileStreamBase::DoOpen(); nsresult rv = FileStreamBase::DoOpen();
@ -89,11 +89,13 @@ FileQuotaStreamWithWrite<FileStreamBase>::Write(const char* aBuf,
NS_IMPL_ISUPPORTS_INHERITED0(FileInputStream, nsFileInputStream) NS_IMPL_ISUPPORTS_INHERITED0(FileInputStream, nsFileInputStream)
already_AddRefed<FileInputStream> already_AddRefed<FileInputStream>
FileInputStream::Create(const nsACString& aOrigin, nsIFile* aFile, FileInputStream::Create(PersistenceType aPersistenceType,
int32_t aIOFlags, int32_t aPerm, const nsACString& aGroup, const nsACString& aOrigin,
nsIFile* aFile, int32_t aIOFlags, int32_t aPerm,
int32_t aBehaviorFlags) 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); nsresult rv = stream->Init(aFile, aIOFlags, aPerm, aBehaviorFlags);
NS_ENSURE_SUCCESS(rv, nullptr); NS_ENSURE_SUCCESS(rv, nullptr);
return stream.forget(); return stream.forget();
@ -102,11 +104,13 @@ FileInputStream::Create(const nsACString& aOrigin, nsIFile* aFile,
NS_IMPL_ISUPPORTS_INHERITED0(FileOutputStream, nsFileOutputStream) NS_IMPL_ISUPPORTS_INHERITED0(FileOutputStream, nsFileOutputStream)
already_AddRefed<FileOutputStream> already_AddRefed<FileOutputStream>
FileOutputStream::Create(const nsACString& aOrigin, nsIFile* aFile, FileOutputStream::Create(PersistenceType aPersistenceType,
int32_t aIOFlags, int32_t aPerm, const nsACString& aGroup, const nsACString& aOrigin,
nsIFile* aFile, int32_t aIOFlags, int32_t aPerm,
int32_t aBehaviorFlags) 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); nsresult rv = stream->Init(aFile, aIOFlags, aPerm, aBehaviorFlags);
NS_ENSURE_SUCCESS(rv, nullptr); NS_ENSURE_SUCCESS(rv, nullptr);
return stream.forget(); return stream.forget();
@ -115,10 +119,12 @@ FileOutputStream::Create(const nsACString& aOrigin, nsIFile* aFile,
NS_IMPL_ISUPPORTS_INHERITED0(FileStream, nsFileStream) NS_IMPL_ISUPPORTS_INHERITED0(FileStream, nsFileStream)
already_AddRefed<FileStream> 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) 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); nsresult rv = stream->Init(aFile, aIOFlags, aPerm, aBehaviorFlags);
NS_ENSURE_SUCCESS(rv, nullptr); NS_ENSURE_SUCCESS(rv, nullptr);
return stream.forget(); return stream.forget();

Просмотреть файл

@ -11,6 +11,7 @@
#include "nsFileStreams.h" #include "nsFileStreams.h"
#include "PersistenceType.h"
#include "QuotaObject.h" #include "QuotaObject.h"
BEGIN_QUOTA_NAMESPACE BEGIN_QUOTA_NAMESPACE
@ -27,14 +28,17 @@ public:
Close() MOZ_OVERRIDE; Close() MOZ_OVERRIDE;
protected: protected:
FileQuotaStream(const nsACString& aOrigin) FileQuotaStream(PersistenceType aPersistenceType, const nsACString& aGroup,
: mOrigin(aOrigin) const nsACString& aOrigin)
: mPersistenceType(aPersistenceType), mGroup(aGroup), mOrigin(aOrigin)
{ } { }
// nsFileStreamBase override // nsFileStreamBase override
virtual nsresult virtual nsresult
DoOpen() MOZ_OVERRIDE; DoOpen() MOZ_OVERRIDE;
PersistenceType mPersistenceType;
nsCString mGroup;
nsCString mOrigin; nsCString mOrigin;
nsRefPtr<QuotaObject> mQuotaObject; nsRefPtr<QuotaObject> mQuotaObject;
}; };
@ -48,8 +52,9 @@ public:
Write(const char* aBuf, uint32_t aCount, uint32_t* _retval) MOZ_OVERRIDE; Write(const char* aBuf, uint32_t aCount, uint32_t* _retval) MOZ_OVERRIDE;
protected: protected:
FileQuotaStreamWithWrite(const nsACString& aOrigin) FileQuotaStreamWithWrite(PersistenceType aPersistenceType,
: FileQuotaStream<FileStreamBase>(aOrigin) const nsACString& aGroup, const nsACString& aOrigin)
: FileQuotaStream<FileStreamBase>(aPersistenceType, aGroup, aOrigin)
{ } { }
}; };
@ -59,12 +64,14 @@ public:
NS_DECL_ISUPPORTS_INHERITED NS_DECL_ISUPPORTS_INHERITED
static already_AddRefed<FileInputStream> 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); int32_t aPerm = -1, int32_t aBehaviorFlags = 0);
private: private:
FileInputStream(const nsACString& aOrigin) FileInputStream(PersistenceType aPersistenceType, const nsACString& aGroup,
: FileQuotaStream<nsFileInputStream>(aOrigin) const nsACString& aOrigin)
: FileQuotaStream<nsFileInputStream>(aPersistenceType, aGroup, aOrigin)
{ } { }
virtual ~FileInputStream() { virtual ~FileInputStream() {
@ -78,12 +85,15 @@ public:
NS_DECL_ISUPPORTS_INHERITED NS_DECL_ISUPPORTS_INHERITED
static already_AddRefed<FileOutputStream> 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); int32_t aPerm = -1, int32_t aBehaviorFlags = 0);
private: private:
FileOutputStream(const nsACString& aOrigin) FileOutputStream(PersistenceType aPersistenceType, const nsACString& aGroup,
: FileQuotaStreamWithWrite<nsFileOutputStream>(aOrigin) const nsACString& aOrigin)
: FileQuotaStreamWithWrite<nsFileOutputStream>(aPersistenceType, aGroup,
aOrigin)
{ } { }
virtual ~FileOutputStream() { virtual ~FileOutputStream() {
@ -97,12 +107,14 @@ public:
NS_DECL_ISUPPORTS_INHERITED NS_DECL_ISUPPORTS_INHERITED
static already_AddRefed<FileStream> 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); int32_t aPerm = -1, int32_t aBehaviorFlags = 0);
private: private:
FileStream(const nsACString& aOrigin) FileStream(PersistenceType aPersistenceType, const nsACString& aGroup,
: FileQuotaStreamWithWrite<nsFileStream>(aOrigin) const nsACString& aOrigin)
: FileQuotaStreamWithWrite<nsFileStream>(aPersistenceType, aGroup, aOrigin)
{ } { }
virtual ~FileStream() { 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); return OriginOrPatternString(aPattern, false);
} }
static OriginOrPatternString
FromNull()
{
return OriginOrPatternString();
}
bool bool
IsOrigin() const IsOrigin() const
{ {
@ -35,18 +41,31 @@ public:
bool bool
IsPattern() const IsPattern() const
{ {
return !mIsOrigin; return mIsPattern;
}
bool
IsNull() const
{
return mIsNull;
} }
private: private:
OriginOrPatternString(const nsACString& aOriginOrPattern, bool aIsOrigin) 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 bool
operator==(const OriginOrPatternString& aOther) MOZ_DELETE; operator==(const OriginOrPatternString& aOther) MOZ_DELETE;
bool mIsOrigin; bool mIsOrigin;
bool mIsPattern;
bool mIsNull;
}; };
END_QUOTA_NAMESPACE 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 BEGIN_QUOTA_NAMESPACE
#ifdef DEBUG
void void
AssertIsOnIOThread(); AssertIsOnIOThread();
#else
inline void void
AssertIsOnIOThread() AssertCurrentThreadOwnsQuotaMutex();
{ }
#endif bool
IsOnIOThread();
END_QUOTA_NAMESPACE END_QUOTA_NAMESPACE

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -12,13 +12,16 @@
#include "nsIObserver.h" #include "nsIObserver.h"
#include "nsIQuotaManager.h" #include "nsIQuotaManager.h"
#include "mozilla/dom/Nullable.h"
#include "mozilla/Mutex.h" #include "mozilla/Mutex.h"
#include "nsClassHashtable.h" #include "nsClassHashtable.h"
#include "nsRefPtrHashtable.h" #include "nsRefPtrHashtable.h"
#include "nsThreadUtils.h" #include "nsThreadUtils.h"
#include "ArrayCluster.h" #include "ArrayCluster.h"
#include "Client.h" #include "Client.h"
#include "PersistenceType.h"
#include "StoragePrivilege.h" #include "StoragePrivilege.h"
#define QUOTA_MANAGER_CONTRACTID "@mozilla.org/dom/quota/manager;1" #define QUOTA_MANAGER_CONTRACTID "@mozilla.org/dom/quota/manager;1"
@ -36,19 +39,28 @@ BEGIN_QUOTA_NAMESPACE
class AcquireListener; class AcquireListener;
class AsyncUsageRunnable; class AsyncUsageRunnable;
class CheckQuotaHelper; class CheckQuotaHelper;
class CollectOriginsHelper;
class FinalizeOriginEvictionRunnable;
class GroupInfo;
class GroupInfoPair;
class OriginClearRunnable; class OriginClearRunnable;
class OriginInfo; class OriginInfo;
class OriginOrPatternString; class OriginOrPatternString;
class QuotaObject; class QuotaObject;
class ResetOrClearRunnable;
struct SynchronizedOp; struct SynchronizedOp;
class QuotaManager MOZ_FINAL : public nsIQuotaManager, class QuotaManager MOZ_FINAL : public nsIQuotaManager,
public nsIObserver public nsIObserver
{ {
friend class AsyncUsageRunnable; friend class AsyncUsageRunnable;
friend class CollectOriginsHelper;
friend class FinalizeOriginEvictionRunnable;
friend class GroupInfo;
friend class OriginClearRunnable; friend class OriginClearRunnable;
friend class OriginInfo; friend class OriginInfo;
friend class QuotaObject; friend class QuotaObject;
friend class ResetOrClearRunnable;
enum MozBrowserPatternFlag enum MozBrowserPatternFlag
{ {
@ -81,23 +93,53 @@ public:
static bool IsShuttingDown(); static bool IsShuttingDown();
void void
InitQuotaForOrigin(const nsACString& aOrigin, InitQuotaForOrigin(PersistenceType aPersistenceType,
int64_t aLimitBytes, const nsACString& aGroup,
int64_t aUsageBytes); const nsACString& aOrigin,
uint64_t aLimitBytes,
uint64_t aUsageBytes,
int64_t aAccessTime);
void void
DecreaseUsageForOrigin(const nsACString& aOrigin, DecreaseUsageForOrigin(PersistenceType aPersistenceType,
const nsACString& aGroup,
const nsACString& aOrigin,
int64_t aSize); int64_t aSize);
void 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> already_AddRefed<QuotaObject>
GetQuotaObject(const nsACString& aOrigin, GetQuotaObject(PersistenceType aPersistenceType,
const nsACString& aGroup,
const nsACString& aOrigin,
nsIFile* aFile); nsIFile* aFile);
already_AddRefed<QuotaObject> already_AddRefed<QuotaObject>
GetQuotaObject(const nsACString& aOrigin, GetQuotaObject(PersistenceType aPersistenceType,
const nsACString& aGroup,
const nsACString& aOrigin,
const nsAString& aPath); const nsAString& aPath);
// Set the Window that the current thread is doing operations for. // Set the Window that the current thread is doing operations for.
@ -148,6 +190,7 @@ public:
// complete before dispatching the given runnable. // complete before dispatching the given runnable.
nsresult nsresult
WaitForOpenAllowed(const OriginOrPatternString& aOriginOrPattern, WaitForOpenAllowed(const OriginOrPatternString& aOriginOrPattern,
Nullable<PersistenceType> aPersistenceType,
nsIAtom* aId, nsIAtom* aId,
nsIRunnable* aRunnable); nsIRunnable* aRunnable);
@ -178,25 +221,39 @@ public:
void void
AllowNextSynchronizedOp(const OriginOrPatternString& aOriginOrPattern, AllowNextSynchronizedOp(const OriginOrPatternString& aOriginOrPattern,
Nullable<PersistenceType> aPersistenceType,
nsIAtom* aId); nsIAtom* aId);
bool bool
IsClearOriginPending(const nsACString& aPattern) IsClearOriginPending(const nsACString& aPattern)
{ {
return !!FindSynchronizedOp(aPattern, nullptr); return !!FindSynchronizedOp(aPattern, Nullable<PersistenceType>(), nullptr);
} }
nsresult nsresult
GetDirectoryForOrigin(const nsACString& aASCIIOrigin, GetDirectoryForOrigin(PersistenceType aPersistenceType,
const nsACString& aASCIIOrigin,
nsIFile** aDirectory) const; nsIFile** aDirectory) const;
nsresult nsresult
EnsureOriginIsInitialized(const nsACString& aOrigin, EnsureOriginIsInitialized(PersistenceType aPersistenceType,
const nsACString& aGroup,
const nsACString& aOrigin,
bool aTrackQuota, bool aTrackQuota,
nsIFile** aDirectory); nsIFile** aDirectory);
void void
OriginClearCompleted(const nsACString& aPattern); OriginClearCompleted(PersistenceType aPersistenceType,
const OriginOrPatternString& aOriginOrPattern);
void
ResetOrClearCompleted();
void
AssertCurrentThreadOwnsQuotaMutex()
{
mQuotaMutex.AssertCurrentThreadOwns();
}
nsIThread* nsIThread*
IOThread() IOThread()
@ -209,31 +266,53 @@ public:
GetClient(Client::Type aClientType); GetClient(Client::Type aClientType);
const nsString& 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 static uint32_t
GetStorageQuotaMB(); GetStorageQuotaMB();
static already_AddRefed<nsIAtom> static already_AddRefed<nsIAtom>
GetStorageId(const nsACString& aOrigin, GetStorageId(PersistenceType aPersistenceType,
const nsACString& aOrigin,
const nsAString& aName); const nsAString& aName);
static nsresult static nsresult
GetASCIIOriginFromURI(nsIURI* aURI, GetInfoFromURI(nsIURI* aURI,
uint32_t aAppId, uint32_t aAppId,
bool aInMozBrowser, bool aInMozBrowser,
nsACString& aASCIIOrigin); nsACString* aGroup,
nsACString* aASCIIOrigin,
StoragePrivilege* aPrivilege,
PersistenceType* aDefaultPersistenceType);
static nsresult static nsresult
GetASCIIOriginFromPrincipal(nsIPrincipal* aPrincipal, GetInfoFromPrincipal(nsIPrincipal* aPrincipal,
nsACString& aASCIIOrigin); nsACString* aGroup,
nsACString* aASCIIOrigin,
StoragePrivilege* aPrivilege,
PersistenceType* aDefaultPersistenceType);
static nsresult static nsresult
GetASCIIOriginFromWindow(nsPIDOMWindow* aWindow, GetInfoFromWindow(nsPIDOMWindow* aWindow,
nsACString& aASCIIOrigin); nsACString* aGroup,
nsACString* aASCIIOrigin,
StoragePrivilege* aPrivilege,
PersistenceType* aDefaultPersistenceType);
static void static void
GetOriginPatternString(uint32_t aAppId, bool aBrowserOnly, GetOriginPatternString(uint32_t aAppId, bool aBrowserOnly,
@ -272,6 +351,15 @@ private:
bool bool
LockedQuotaIsLifted(); LockedQuotaIsLifted();
uint64_t
LockedCollectOriginsForEviction(uint64_t aMinSizeToBeFreed,
nsTArray<OriginInfo*>& aOriginInfos);
void
LockedRemoveQuotaForOrigin(PersistenceType aPersistenceType,
const nsACString& aGroup,
const nsACString& aOrigin);
nsresult nsresult
AcquireExclusiveAccess(const nsACString& aOrigin, AcquireExclusiveAccess(const nsACString& aOrigin,
nsIOfflineStorage* aStorage, nsIOfflineStorage* aStorage,
@ -279,19 +367,50 @@ private:
WaitingOnStoragesCallback aCallback, WaitingOnStoragesCallback aCallback,
void* aClosure); void* aClosure);
void
AddSynchronizedOp(const OriginOrPatternString& aOriginOrPattern,
Nullable<PersistenceType> aPersistenceType,
nsIAtom* aId);
nsresult nsresult
RunSynchronizedOp(nsIOfflineStorage* aStorage, RunSynchronizedOp(nsIOfflineStorage* aStorage,
SynchronizedOp* aOp); SynchronizedOp* aOp);
SynchronizedOp* SynchronizedOp*
FindSynchronizedOp(const nsACString& aPattern, FindSynchronizedOp(const nsACString& aPattern,
Nullable<PersistenceType> aPersistenceType,
nsISupports* aId); nsISupports* aId);
nsresult
MaybeUpgradeIndexedDBDirectory();
nsresult
InitializeOrigin(PersistenceType aPersistenceType,
const nsACString& aGroup,
const nsACString& aOrigin,
bool aTrackQuota,
int64_t aAccessTime,
nsIFile* aDirectory);
nsresult nsresult
ClearStoragesForApp(uint32_t aAppId, bool aBrowserOnly); ClearStoragesForApp(uint32_t aAppId, bool aBrowserOnly);
nsresult void
MaybeUpgradeOriginDirectory(nsIFile* aDirectory); 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 void
ReleaseIOThreadObjects() ReleaseIOThreadObjects()
@ -309,12 +428,47 @@ private:
const nsACString& aOrigin, const nsACString& aOrigin,
nsAutoCString& _retval); 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. // TLS storage index for the current thread's window.
unsigned int mCurrentWindowIndex; unsigned int mCurrentWindowIndex;
mozilla::Mutex mQuotaMutex; mozilla::Mutex mQuotaMutex;
nsRefPtrHashtable<nsCStringHashKey, OriginInfo> mOriginInfos; nsClassHashtable<nsCStringHashKey, GroupInfoPair> mGroupInfoPairs;
// A map of Windows to the corresponding quota helper. // A map of Windows to the corresponding quota helper.
nsRefPtrHashtable<nsPtrHashKey<nsPIDOMWindow>, nsRefPtrHashtable<nsPtrHashKey<nsPIDOMWindow>,
@ -339,7 +493,15 @@ private:
nsAutoTArray<nsRefPtr<Client>, Client::TYPE_MAX> mClients; 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 class AutoEnterWindow

Просмотреть файл

@ -7,6 +7,7 @@
#include "QuotaObject.h" #include "QuotaObject.h"
#include "QuotaManager.h" #include "QuotaManager.h"
#include "Utilities.h"
USING_QUOTA_NAMESPACE USING_QUOTA_NAMESPACE
@ -68,10 +69,24 @@ QuotaObject::UpdateSize(int64_t aSize)
MutexAutoLock lock(quotaManager->mQuotaMutex); MutexAutoLock lock(quotaManager->mQuotaMutex);
if (mOriginInfo) { if (!mOriginInfo) {
mOriginInfo->mUsage -= mSize; return;
mSize = aSize; }
mOriginInfo->mUsage += mSize;
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; return true;
} }
int64_t newUsage = mOriginInfo->mUsage - mSize + end; GroupInfo* groupInfo = mOriginInfo->mGroupInfo;
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 if (groupInfo->IsForPersistentStorage()) {
// thread. uint64_t newUsage = mOriginInfo->mUsage - mSize + end;
if (!mOriginInfo) {
// The other thread could allocate more space. if (newUsage > mOriginInfo->mLimit) {
if (end > mSize) { // This will block the thread, but it will also drop the mutex while
mSize = end; // 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; return true;
} }
nsCString origin = mOriginInfo->mOrigin; mOriginInfo->mUsage = newUsage;
mOriginInfo->LockedClearOriginInfos(); groupInfo->mUsage = groupInfo->mUsage - mSize + end;
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!");
mSize = end; mSize = end;
return true; 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; mOriginInfo->mUsage = newUsage;
groupInfo->mUsage = newGroupUsage;
quotaManager->mTemporaryStorageUsage = newTemporaryStorageUsage;
mSize = end; mSize = end;
return true; return true;
} }
#ifdef DEBUG
void void
OriginInfo::LockedClearOriginInfos() OriginInfo::LockedDecreaseUsage(int64_t aSize)
{ {
QuotaManager* quotaManager = QuotaManager::Get(); AssertCurrentThreadOwnsQuotaMutex();
NS_ASSERTION(quotaManager, "Shouldn't be null!");
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 // static
PLDHashOperator PLDHashOperator
@ -157,3 +306,118 @@ OriginInfo::ClearOriginInfoCallback(const nsAString& aKey,
return PL_DHASH_NEXT; 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 "nsDataHashtable.h"
#include "PersistenceType.h"
BEGIN_QUOTA_NAMESPACE BEGIN_QUOTA_NAMESPACE
class GroupInfo;
class GroupInfoPair;
class OriginInfo; class OriginInfo;
class QuotaManager; class QuotaManager;
@ -37,10 +41,14 @@ public:
private: private:
QuotaObject(OriginInfo* aOriginInfo, const nsAString& aPath, int64_t aSize) QuotaObject(OriginInfo* aOriginInfo, const nsAString& aPath, int64_t aSize)
: mOriginInfo(aOriginInfo), mPath(aPath), mSize(aSize) : mOriginInfo(aOriginInfo), mPath(aPath), mSize(aSize)
{ } {
MOZ_COUNT_CTOR(QuotaObject);
}
virtual ~QuotaObject() ~QuotaObject()
{ } {
MOZ_COUNT_DTOR(QuotaObject);
}
mozilla::ThreadSafeAutoRefCnt mRefCnt; mozilla::ThreadSafeAutoRefCnt mRefCnt;
@ -51,27 +59,51 @@ private:
class OriginInfo class OriginInfo
{ {
friend class GroupInfo;
friend class QuotaManager; friend class QuotaManager;
friend class QuotaObject; friend class QuotaObject;
public: public:
OriginInfo(const nsACString& aOrigin, int64_t aLimit, int64_t aUsage) OriginInfo(GroupInfo* aGroupInfo, const nsACString& aOrigin, uint64_t aLimit,
: mOrigin(aOrigin), mLimit(aLimit), mUsage(aUsage) 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) NS_INLINE_DECL_THREADSAFE_REFCOUNTING(OriginInfo)
int64_t
AccessTime() const
{
return mAccessTime;
}
private: private:
void void
#ifdef DEBUG LockedDecreaseUsage(int64_t aSize);
LockedClearOriginInfos();
#else void
LockedUpdateAccessTime(int64_t aAccessTime)
{
AssertCurrentThreadOwnsQuotaMutex();
mAccessTime = aAccessTime;
}
void
LockedClearOriginInfos() LockedClearOriginInfos()
{ {
AssertCurrentThreadOwnsQuotaMutex();
mQuotaObjects.EnumerateRead(ClearOriginInfoCallback, nullptr); mQuotaObjects.EnumerateRead(ClearOriginInfoCallback, nullptr);
} }
#endif
static PLDHashOperator static PLDHashOperator
ClearOriginInfoCallback(const nsAString& aKey, ClearOriginInfoCallback(const nsAString& aKey,
@ -79,9 +111,153 @@ private:
nsDataHashtable<nsStringHashKey, QuotaObject*> mQuotaObjects; nsDataHashtable<nsStringHashKey, QuotaObject*> mQuotaObjects;
GroupInfo* mGroupInfo;
nsCString mOrigin; nsCString mOrigin;
int64_t mLimit; uint64_t mLimit;
int64_t mUsage; 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 END_QUOTA_NAMESPACE

Просмотреть файл

@ -12,8 +12,13 @@
BEGIN_QUOTA_NAMESPACE BEGIN_QUOTA_NAMESPACE
enum StoragePrivilege { enum StoragePrivilege {
Content, // Quota not tracked, persistence type is always "persistent".
Chrome 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 END_QUOTA_NAMESPACE

Просмотреть файл

@ -4,8 +4,8 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this file, * 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/. */ * You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_quota_usagerunnable_h__ #ifndef mozilla_dom_quota_usageinfo_h__
#define mozilla_dom_quota_usagerunnable_h__ #define mozilla_dom_quota_usageinfo_h__
#include "mozilla/dom/quota/QuotaCommon.h" #include "mozilla/dom/quota/QuotaCommon.h"
@ -14,14 +14,14 @@
BEGIN_QUOTA_NAMESPACE BEGIN_QUOTA_NAMESPACE
class UsageRunnable class UsageInfo
{ {
public: public:
UsageRunnable() UsageInfo()
: mCanceled(0), mDatabaseUsage(0), mFileUsage(0) : mCanceled(0), mDatabaseUsage(0), mFileUsage(0)
{ } { }
virtual ~UsageRunnable() virtual ~UsageInfo()
{ } { }
bool bool
@ -79,4 +79,4 @@ private:
END_QUOTA_NAMESPACE 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', 'Client.h',
'FileStreams.h', 'FileStreams.h',
'OriginOrPatternString.h', 'OriginOrPatternString.h',
'PersistenceType.h',
'QuotaCommon.h', 'QuotaCommon.h',
'QuotaManager.h', 'QuotaManager.h',
'QuotaObject.h', 'QuotaObject.h',
'StoragePrivilege.h', 'StoragePrivilege.h',
'UsageRunnable.h', 'UsageInfo.h',
'Utilities.h', 'Utilities.h',
] ]

Просмотреть файл

@ -9,9 +9,13 @@
#include "nsIFileStorage.h" #include "nsIFileStorage.h"
#include "mozilla/dom/quota/PersistenceType.h"
#define NS_OFFLINESTORAGE_IID \ #define NS_OFFLINESTORAGE_IID \
{0xe531b6e0, 0x55b8, 0x4f39, \ {0xec7e878d, 0xc8c1, 0x402e, \
{ 0x95, 0xbb, 0x97, 0x21, 0x4c, 0xb0, 0xf6, 0x1a } } { 0xa2, 0xc4, 0xf6, 0x82, 0x29, 0x4e, 0x3c, 0xb1 } }
class nsPIDOMWindow;
namespace mozilla { namespace mozilla {
namespace dom { namespace dom {
@ -25,6 +29,7 @@ class nsIOfflineStorage : public nsIFileStorage
{ {
public: public:
typedef mozilla::dom::quota::Client Client; typedef mozilla::dom::quota::Client Client;
typedef mozilla::dom::quota::PersistenceType PersistenceType;
NS_DECLARE_STATIC_IID_ACCESSOR(NS_OFFLINESTORAGE_IID) NS_DECLARE_STATIC_IID_ACCESSOR(NS_OFFLINESTORAGE_IID)
@ -34,6 +39,18 @@ public:
NS_IMETHOD_(bool) NS_IMETHOD_(bool)
IsOwned(nsPIDOMWindow* aOwner) = 0; IsOwned(nsPIDOMWindow* aOwner) = 0;
NS_IMETHOD_(PersistenceType)
Type()
{
return mPersistenceType;
}
NS_IMETHOD_(const nsACString&)
Group()
{
return mGroup;
}
NS_IMETHOD_(const nsACString&) NS_IMETHOD_(const nsACString&)
Origin() = 0; Origin() = 0;
@ -50,6 +67,17 @@ public:
// operations should be aborted and pending operations should be discarded. // operations should be aborted and pending operations should be discarded.
NS_IMETHOD_(void) NS_IMETHOD_(void)
Invalidate() = 0; 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) NS_DEFINE_STATIC_IID_ACCESSOR(nsIOfflineStorage, NS_OFFLINESTORAGE_IID)

Просмотреть файл

@ -10,7 +10,7 @@ interface nsIQuotaRequest;
interface nsIURI; interface nsIURI;
interface nsIUsageCallback; interface nsIUsageCallback;
[scriptable, builtinclass, uuid(8d74e6f8-81c3-4045-9bb7-70bdb7b11b25)] [scriptable, builtinclass, uuid(f19a03ae-e97d-41e9-95dd-681b910c4093)]
interface nsIQuotaManager : nsISupports interface nsIQuotaManager : nsISupports
{ {
/** /**
@ -29,6 +29,17 @@ interface nsIQuotaManager : nsISupports
[optional] in unsigned long aAppId, [optional] in unsigned long aAppId,
[optional] in boolean aInMozBrowserOnly); [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 * Removes all storages stored for the given URI. The files may not be
* deleted immediately depending on prohibitive concurrent operations. * deleted immediately depending on prohibitive concurrent operations.
@ -41,4 +52,16 @@ interface nsIQuotaManager : nsISupports
clearStoragesForURI(in nsIURI aURI, clearStoragesForURI(in nsIURI aURI,
[optional] in unsigned long aAppId, [optional] in unsigned long aAppId,
[optional] in boolean aInMozBrowserOnly); [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 { partial interface IDBDatabase {
[Pref="dom.indexedDB.experimental"]
readonly attribute StorageType storage;
[Throws] [Throws]
IDBRequest mozCreateFileHandle (DOMString name, optional DOMString type); IDBRequest mozCreateFileHandle (DOMString name, optional DOMString type);
}; };

Просмотреть файл

@ -12,6 +12,12 @@
interface Principal; interface Principal;
dictionary IDBOpenDBOptions
{
[EnforceRange] unsigned long long version;
StorageType storage;
};
/** /**
* Interface that defines the indexedDB property on a window. See * Interface that defines the indexedDB property on a window. See
* http://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#idl-def-IDBFactory * http://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#idl-def-IDBFactory
@ -21,11 +27,17 @@ interface IDBFactory {
[Throws] [Throws]
IDBOpenDBRequest IDBOpenDBRequest
open(DOMString name, open(DOMString name,
[EnforceRange] optional unsigned long long version); [EnforceRange] unsigned long long version);
[Throws] [Throws]
IDBOpenDBRequest IDBOpenDBRequest
deleteDatabase(DOMString name); open(DOMString name,
optional IDBOpenDBOptions options);
[Throws]
IDBOpenDBRequest
deleteDatabase(DOMString name,
optional IDBOpenDBOptions options);
[Throws] [Throws]
short short
@ -36,10 +48,17 @@ interface IDBFactory {
IDBOpenDBRequest IDBOpenDBRequest
openForPrincipal(Principal principal, openForPrincipal(Principal principal,
DOMString name, 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] [Throws, ChromeOnly]
IDBOpenDBRequest IDBOpenDBRequest
deleteForPrincipal(Principal principal, 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', 'SimpleGestureEvent.webidl',
'SourceBuffer.webidl', 'SourceBuffer.webidl',
'SourceBufferList.webidl', 'SourceBufferList.webidl',
'StorageType.webidl',
'StyleSheet.webidl', 'StyleSheet.webidl',
'SVGAElement.webidl', 'SVGAElement.webidl',
'SVGAltGlyphElement.webidl', 'SVGAltGlyphElement.webidl',

Просмотреть файл

@ -78,10 +78,15 @@ pref("offline-apps.quota.warn", 51200);
// cache compression turned off for now - see bug #715198 // cache compression turned off for now - see bug #715198
pref("browser.cache.compression_level", 0); pref("browser.cache.compression_level", 0);
// Whether or not testing features are enabled.
pref("dom.quotaManager.testing", false);
// Whether or not indexedDB is enabled. // Whether or not indexedDB is enabled.
pref("dom.indexedDB.enabled", true); pref("dom.indexedDB.enabled", true);
// Space to allow indexedDB databases before prompting (in MB). // Space to allow indexedDB databases before prompting (in MB).
pref("dom.indexedDB.warningQuota", 50); 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. // Whether or not Web Workers are enabled.
pref("dom.workers.enabled", true); pref("dom.workers.enabled", true);

Просмотреть файл

@ -10,6 +10,7 @@
#include "sqlite3.h" #include "sqlite3.h"
#include "nsThreadUtils.h" #include "nsThreadUtils.h"
#include "mozilla/Util.h" #include "mozilla/Util.h"
#include "mozilla/dom/quota/PersistenceType.h"
#include "mozilla/dom/quota/QuotaManager.h" #include "mozilla/dom/quota/QuotaManager.h"
#include "mozilla/dom/quota/QuotaObject.h" #include "mozilla/dom/quota/QuotaObject.h"
#include "mozilla/SQLiteInterposer.h" #include "mozilla/SQLiteInterposer.h"
@ -349,15 +350,19 @@ xOpen(sqlite3_vfs* vfs, const char *zName, sqlite3_file* pFile,
} }
p->histograms = h; p->histograms = h;
const char* persistenceType;
const char* group;
const char* origin; const char* origin;
if ((flags & SQLITE_OPEN_URI) && if ((flags & SQLITE_OPEN_URI) &&
(persistenceType = sqlite3_uri_parameter(zName, "persistenceType")) &&
(group = sqlite3_uri_parameter(zName, "group")) &&
(origin = sqlite3_uri_parameter(zName, "origin"))) { (origin = sqlite3_uri_parameter(zName, "origin"))) {
QuotaManager* quotaManager = QuotaManager::Get(); QuotaManager* quotaManager = QuotaManager::Get();
MOZ_ASSERT(quotaManager); MOZ_ASSERT(quotaManager);
p->quotaObject = quotaManager->GetQuotaObject(nsDependentCString(origin), p->quotaObject = quotaManager->GetQuotaObject(PersistenceTypeFromText(
NS_ConvertUTF8toUTF16(zName)); nsDependentCString(persistenceType)), nsDependentCString(group),
nsDependentCString(origin), NS_ConvertUTF8toUTF16(zName));
} }
rc = orig_vfs->xOpen(orig_vfs, zName, p->pReal, flags, pOutFlags); rc = orig_vfs->xOpen(orig_vfs, zName, p->pReal, flags, pOutFlags);

Просмотреть файл

@ -1182,6 +1182,11 @@ SpecialPowersAPI.prototype = {
Cu.forceCC(); 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) { exactGC: function(win, callback) {
var self = this; var self = this;
let count = 0; let count = 0;