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.
let isHTTPS = principal.URI && principal.URI.schemeIs("https");
if (aFullData || SessionStore.checkPrivacyLevel(isHTTPS, isPinned)) {
let origin = principal.extendedOrigin;
let origin = principal.jarPrefix + principal.origin;
// Don't read a host twice.
if (!(origin in data)) {

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

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

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

@ -10,7 +10,7 @@ interface nsIURI;
interface nsIChannel;
interface nsIDocShell;
[scriptable, uuid(ae486501-ec57-4ec8-a565-6880ca4ae6c4)]
[scriptable, uuid(d6475e53-9ece-4dc0-940c-095ac3d85363)]
interface nsIScriptSecurityManager : nsIXPCSecurityManager
{
///////////////// Security Checks //////////////////
@ -229,13 +229,12 @@ interface nsIScriptSecurityManager : nsIXPCSecurityManager
const unsigned long UNKNOWN_APP_ID = 4294967295; // UINT32_MAX
/**
* Returns the extended origin for the uri.
* Returns the jar prefix for the app.
* appId can be NO_APP_ID or a valid app id. appId should not be
* UNKNOWN_APP_ID.
* inMozBrowser has to be true if the uri is inside a mozbrowser iframe.
* inMozBrowser has to be true if the app is inside a mozbrowser iframe.
*/
AUTF8String getExtendedOrigin(in nsIURI uri, in unsigned long appId,
in boolean inMozBrowser);
AUTF8String getJarPrefix(in unsigned long appId, in boolean inMozBrowser);
};
%{C++

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

@ -65,7 +65,7 @@ public:
NS_IMETHOD Subsumes(nsIPrincipal* other, bool* _retval);
NS_IMETHOD SubsumesIgnoringDomain(nsIPrincipal* other, bool* _retval);
NS_IMETHOD CheckMayLoad(nsIURI* uri, bool report, bool allowIfInheritsPrincipal);
NS_IMETHOD GetExtendedOrigin(nsACString& aExtendedOrigin);
NS_IMETHOD GetJarPrefix(nsACString& aJarPrefix);
NS_IMETHOD GetAppStatus(uint16_t* aAppStatus);
NS_IMETHOD GetAppId(uint32_t* aAppStatus);
NS_IMETHOD GetIsInBrowserElement(bool* aIsInBrowserElement);
@ -148,7 +148,7 @@ public:
NS_IMETHOD Subsumes(nsIPrincipal* other, bool* _retval);
NS_IMETHOD SubsumesIgnoringDomain(nsIPrincipal* other, bool* _retval);
NS_IMETHOD CheckMayLoad(nsIURI* uri, bool report, bool allowIfInheritsPrincipal);
NS_IMETHOD GetExtendedOrigin(nsACString& aExtendedOrigin);
NS_IMETHOD GetJarPrefix(nsACString& aJarPrefix);
NS_IMETHOD GetAppStatus(uint16_t* aAppStatus);
NS_IMETHOD GetAppId(uint32_t* aAppStatus);
NS_IMETHOD GetIsInBrowserElement(bool* aIsInBrowserElement);

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

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

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

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

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

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

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

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

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

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

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

@ -11,8 +11,8 @@ MOCHITEST_FILES = test_bug423375.html \
test_app_principal_equality.html \
$(NULL)
# extendedOrigin test doesn't work on Windows, see bug 776296.
# jarPrefix test doesn't work on Windows, see bug 776296.
ifneq ($(OS_ARCH),WINNT)
MOCHITEST_CHROME_FILES = test_principal_extendedorigin_appid_appstatus.html \
MOCHITEST_CHROME_FILES = test_principal_jarprefix_origin_appid_appstatus.html \
$(NULL)
endif

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

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

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

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

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

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

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

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

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

@ -64,6 +64,28 @@ public:
return mIsNull;
}
bool Equals(const Nullable<T>& aOtherNullable) const
{
return (mIsNull && aOtherNullable.mIsNull) ||
(!mIsNull && !aOtherNullable.mIsNull &&
mValue == aOtherNullable.mValue);
}
bool operator==(const Nullable<T>& aOtherNullable) const
{
return Equals(aOtherNullable);
}
bool operator!=(const Nullable<T>& aOtherNullable) const
{
return !Equals(aOtherNullable);
}
operator bool() const
{
return !mIsNull;
}
// Make it possible to use a const Nullable of an array type with other
// array types.
template<typename U>

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

@ -7,6 +7,10 @@ include protocol PContent;
include protocol PIndexedDBDatabase;
include protocol PIndexedDBDeleteDatabaseRequest;
include "mozilla/dom/indexedDB/SerializationHelpers.h";
using mozilla::dom::quota::PersistenceType;
namespace mozilla {
namespace dom {
namespace indexedDB {
@ -21,9 +25,11 @@ protocol PIndexedDB
parent:
__delete__();
PIndexedDBDatabase(nsString name, uint64_t version);
PIndexedDBDatabase(nsString name, uint64_t version,
PersistenceType persistenceType);
PIndexedDBDeleteDatabaseRequest(nsString name);
PIndexedDBDeleteDatabaseRequest(nsString name,
PersistenceType persistenceType);
};
} // namespace indexedDB

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

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

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

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

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

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

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

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

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

@ -46,7 +46,7 @@
for (let id = 1; id <= 100; id++) {
let refs = {};
let dbRefs = {};
let hasFileInfo = utils.getFileReferences(name, id, refs, dbRefs);
let hasFileInfo = utils.getFileReferences(name, id, null, refs, dbRefs);
ok(hasFileInfo, "Has file info");
is(refs.value, 1, "Correct ref count");
is(dbRefs.value, id / 100 >> 0, "Correct db ref count");

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

@ -0,0 +1,108 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html>
<head>
<title>Indexed Database Property Test</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="text/javascript;version=1.7">
function testSteps()
{
const name = window.location.pathname;
const version = 1;
const objectStoreName = "Foo";
const data = { key: 1, value: "bar" };
try {
indexedDB.open(name, { version: version, storage: "unknown" });
ok(false, "Should have thrown!");
}
catch (e) {
ok(e instanceof TypeError, "Got TypeError.");
is(e.name, "TypeError", "Good error name.");
}
let request = indexedDB.open(name, { version: version,
storage: "persistent" });
request.onerror = errorHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
request.onsuccess = grabEventAndContinueHandler;
let event = yield undefined;
is(event.type, "upgradeneeded", "Got correct event type");
let db = event.target.result;
db.onerror = errorHandler;
let objectStore = db.createObjectStore(objectStoreName, { });
event = yield undefined;
is(event.type, "success", "Got correct event type");
is(db.name, name, "Correct name");
is(db.version, version, "Correct version");
is(db.storage, "persistent", "Correct persistence type");
objectStore = db.transaction([objectStoreName], "readwrite")
.objectStore(objectStoreName);
request = objectStore.get(data.key);
request.onsuccess = grabEventAndContinueHandler;
event = yield undefined;
is(event.target.result, null, "Got no data");
request = objectStore.add(data.value, data.key);
request.onsuccess = grabEventAndContinueHandler;
event = yield undefined;
is(event.target.result, data.key, "Got correct key");
request = indexedDB.open(name, { version: version,
storage: "temporary" });
request.onerror = errorHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
request.onsuccess = grabEventAndContinueHandler;
let event = yield undefined;
is(event.type, "upgradeneeded", "Got correct event type");
db = event.target.result;
db.onerror = errorHandler;
objectStore = db.createObjectStore(objectStoreName, { });
event = yield undefined;
is(event.type, "success", "Got correct event type");
is(db.name, name, "Correct name");
is(db.version, version, "Correct version");
is(db.storage, "temporary", "Correct persistence type");
objectStore = db.transaction([objectStoreName])
.objectStore(objectStoreName);
request = objectStore.get(data.key);
request.onsuccess = grabEventAndContinueHandler;
event = yield undefined;
is(event.target.result, null, "Got no data");
finishTest();
yield undefined;
}
</script>
<script type="text/javascript;version=1.7" src="helpers.js"></script>
</head>
<body onload="runTest();"></body>
</html>

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

@ -46,6 +46,7 @@ MOCHITEST_FILES = \
test_open_objectStore.js \
test_optionalArguments.js \
test_overlapping_transactions.js \
test_persistenceType.js \
test_put_get_values.js \
test_put_get_values_autoIncrement.js \
test_readonly_transactions.js \
@ -57,6 +58,7 @@ MOCHITEST_FILES = \
test_setVersion_events.js \
test_setVersion_exclusion.js \
test_success_events_after_abort.js \
test_temporary_storage.js \
test_traffic_jam.js \
test_transaction_abort.js \
test_transaction_abort_hang.js \

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

@ -47,16 +47,20 @@ function runTest()
getService(Ci.nsIIndexedDatabaseManager);
idbManager.initWindowless(this);
enableExperimental();
do_test_pending();
testGenerator.next();
}
function finishTest()
{
do_execute_soon(function(){
testGenerator.close();
resetExperimental();
SpecialPowers.notifyObserversInParentProcess(null, "disk-space-watcher",
"free");
do_execute_soon(function(){
testGenerator.close();
do_test_finished();
})
}
@ -179,12 +183,27 @@ function disallowUnlimitedQuota(url)
throw "disallowUnlimitedQuota";
}
function enableExperimental()
{
SpecialPowers.setBoolPref("dom.indexedDB.experimental", true);
}
function resetExperimental()
{
SpecialPowers.clearUserPref("dom.indexedDB.experimental");
}
function gc()
{
Components.utils.forceGC();
Components.utils.forceCC();
}
function scheduleGC()
{
SpecialPowers.exactGC(null, continueToNextStep);
}
function setTimeout(fun, timeout) {
let timer = Components.classes["@mozilla.org/timer;1"]
.createInstance(Components.interfaces.nsITimer);
@ -214,5 +233,43 @@ var SpecialPowers = {
throw new Error("Can't send subject to another process!");
}
return this.notifyObservers(subject, topic, data);
},
getBoolPref: function(prefName) {
return this._getPrefs().getBoolPref(prefName);
},
setBoolPref: function(prefName, value) {
this._getPrefs().setBoolPref(prefName, value);
},
setIntPref: function(prefName, value) {
this._getPrefs().setIntPref(prefName, value);
},
clearUserPref: function(prefName) {
this._getPrefs().clearUserPref(prefName);
},
// Copied (and slightly adjusted) from specialpowersAPI.js
exactGC: function(win, callback) {
let count = 0;
function doPreciseGCandCC() {
function scheduledGCCallback() {
Components.utils.forceCC();
if (++count < 2) {
doPreciseGCandCC();
} else {
callback();
}
}
Components.utils.schedulePreciseGC(scheduledGCCallback);
}
doPreciseGCandCC();
},
_getPrefs: function() {
var prefService =
Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefService);
return prefService.getBranch(null);
}
};

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

@ -27,6 +27,24 @@ function testSteps()
is(e.name, "TypeError", "Good error name.");
}
try {
indexedDB.open(name, { version: 0 });
ok(false, "Should have thrown!");
}
catch (e) {
ok(e instanceof TypeError, "Got TypeError.");
is(e.name, "TypeError", "Good error name.");
}
try {
indexedDB.open(name, { version: -1 });
ok(false, "Should have thrown!");
}
catch (e) {
ok(e instanceof TypeError, "Got TypeError.");
is(e.name, "TypeError", "Good error name.");
}
finishTest();
yield undefined;
}

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

@ -0,0 +1,86 @@
/**
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
var testGenerator = testSteps();
function testSteps()
{
const name = "Splendid Test";
const version = 1;
const objectStoreName = "Foo";
const data = { key: 1, value: "bar" };
try {
indexedDB.open(name, { version: version, storage: "unknown" });
ok(false, "Should have thrown!");
}
catch (e) {
ok(e instanceof TypeError, "Got TypeError.");
is(e.name, "TypeError", "Good error name.");
}
let request = indexedDB.open(name, { version: version,
storage: "persistent" });
request.onerror = errorHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
request.onsuccess = grabEventAndContinueHandler;
let event = yield undefined;
is(event.type, "upgradeneeded", "Got correct event type");
let db = event.target.result;
db.onerror = errorHandler;
let objectStore = db.createObjectStore(objectStoreName, { });
event = yield undefined;
is(event.type, "success", "Got correct event type");
is(db.name, name, "Correct name");
is(db.version, version, "Correct version");
is(db.storage, "persistent", "Correct persistence type");
objectStore = db.transaction([objectStoreName], "readwrite")
.objectStore(objectStoreName);
request = objectStore.get(data.key);
request.onsuccess = grabEventAndContinueHandler;
event = yield undefined;
is(event.target.result, null, "Got no data");
request = objectStore.add(data.value, data.key);
request.onsuccess = grabEventAndContinueHandler;
event = yield undefined;
is(event.target.result, data.key, "Got correct key");
request = indexedDB.open(name, { version: version,
storage: "temporary" });
request.onerror = errorHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
request.onsuccess = grabEventAndContinueHandler;
let event = yield undefined;
is(event.type, "success", "Got correct event type");
is(db.name, name, "Correct name");
is(db.version, version, "Correct version");
is(db.storage, "persistent", "Correct persistence type");
objectStore = db.transaction([objectStoreName])
.objectStore(objectStoreName);
request = objectStore.get(data.key);
request.onsuccess = grabEventAndContinueHandler;
event = yield undefined;
is(event.target.result, data.value, "Got correct data");
finishTest();
yield undefined;
}

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

@ -0,0 +1,225 @@
/**
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
var testGenerator = testSteps();
function testSteps()
{
const name = this.window ? window.location.pathname : "Splendid Test";
const urls = [
{ url: "http://www.alpha.com", flags: [true, true, false, false] },
{ url: "http://www.beta.com", flags: [true, false, false, false] },
{ url: "http://www.gamma.com", flags: [true, true, false, false] },
{ url: "http://www.delta.com", flags: [true, true, false, false] },
{ url: "http://www.epsilon.com", flags: [true, true, false, false] },
{ url: "http://www2.alpha.com", flags: [true, true, false, false] },
{ url: "http://www2.beta.com", flags: [true, true, false, false] },
{ url: "http://www2.gamma.com", flags: [true, true, true, false] },
{ url: "http://www2.delta.com", flags: [true, true, true, true] },
{ url: "http://www2.epsilon.com", flags: [true, true, true, true] },
{ url: "http://joe.blog.alpha.com", flags: [true, true, true, true] },
{ url: "http://joe.blog.beta.com", flags: [true, true, true, true] },
{ url: "http://joe.blog.gamma.com", flags: [true, true, true, true] },
{ url: "http://joe.blog.delta.com", flags: [true, true, true, true] },
{ url: "http://joe.blog.epsilon.com", flags: [true, true, true, true] },
{ url: "http://www.rudolf.org", flags: [true, true, true, true] },
{ url: "http://www.pauline.org", flags: [true, true, true, true] },
{ url: "http://www.marie.org", flags: [true, true, true, true] },
{ url: "http://www.john.org", flags: [true, true, true, true] },
{ url: "http://www.ema.org", flags: [true, true, true, true] },
{ url: "http://www.trigger.com", flags: [false, true, true, true] }
];
const lastIndex = urls.length - 1;
const lastUrl = urls[lastIndex].url;
let quotaManager =
Components.classes["@mozilla.org/dom/quota/manager;1"]
.getService(Components.interfaces.nsIQuotaManager);
let ioService = Components.classes["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService);
let dbSize = 0;
let databases = [];
function setLimit(limit) {
if (limit) {
SpecialPowers.setIntPref("dom.quotaManager.temporaryStorage.fixedLimit",
limit);
return;
}
SpecialPowers.clearUserPref("dom.quotaManager.temporaryStorage.fixedLimit");
}
function getPrincipal(url) {
let uri = ioService.newURI(url, null, null);
return Components.classes["@mozilla.org/scriptsecuritymanager;1"]
.getService(Components.interfaces.nsIScriptSecurityManager)
.getNoAppCodebasePrincipal(uri);
}
function getUsageForUrl(url, usageHandler) {
let uri = ioService.newURI(url, null, null);
function callback(uri, usage, fileUsage) {
usageHandler(usage, fileUsage);
}
quotaManager.getUsageForURI(uri, callback);
}
function grabUsageAndContinueHandler(usage, fileUsage) {
testGenerator.send(usage);
}
function checkUsage(stageIndex) {
let handledIndex = 0;
function usageHandler(usage, fileUsage) {
if (urls[handledIndex].flags[stageIndex - 1]) {
ok(usage > 0, "Correct usage");
}
else {
ok(usage == 0, "Correct usage");
}
if (++handledIndex == urls.length) {
continueToNextStep();
}
}
for (let i = 0; i < urls.length; i++) {
getUsageForUrl(urls[i].url, usageHandler);
}
}
// Enable clear() and test()
let testingEnabled =
SpecialPowers.getBoolPref("dom.quotaManager.testing");
SpecialPowers.setBoolPref("dom.quotaManager.testing", true)
// Calibration
let request = indexedDB.openForPrincipal(getPrincipal(lastUrl), name,
{ storage: "temporary" });
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
let event = yield undefined;
getUsageForUrl(lastUrl, grabUsageAndContinueHandler);
dbSize = yield undefined;
setLimit(lastIndex * dbSize / 1024);
quotaManager.clear();
// Stage 1
for (let i = 0; i < lastIndex; i++) {
let data = urls[i];
request = indexedDB.openForPrincipal(getPrincipal(data.url), name,
{ storage: "temporary" });
request.onerror = errorHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield undefined;
is(event.type, "upgradeneeded", "Got correct event type");
let db = event.target.result;
db.createObjectStore("foo", { });
event = yield undefined;
is(event.type, "success", "Got correct event type");
databases.push(event.target.result);
}
request = indexedDB.openForPrincipal(getPrincipal(lastUrl), name,
{ storage: "temporary" });
request.addEventListener("error", new ExpectError("QuotaExceededError"));
request.onsuccess = unexpectedSuccessHandler;
event = yield undefined;
checkUsage(1);
yield undefined;
// Stage 2
for (let i = 1; i < urls.length; i++) {
databases[i] = null;
scheduleGC();
yield undefined;
// The origin access time is set to the current system time when the first
// database for an origin is registered or the last one is unregistered.
// The registration happens when the database object is being created and
// the unregistration when it is unlinked/garbage collected.
// Some older windows systems have the system time limited to a maximum
// resolution of 10 or 15 milliseconds, so without a pause here we would
// end up with origins with the same access time which would cause random
// failures.
setTimeout(function() { testGenerator.next(); }, 20);
yield undefined;
}
request = indexedDB.openForPrincipal(getPrincipal(lastUrl), name,
{ storage: "temporary" });
request.onerror = errorHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield undefined;
is(event.type, "upgradeneeded", "Got correct event type");
let db = event.target.result;
db.createObjectStore("foo", { });
event = yield undefined;
is(event.type, "success", "Got correct event type");
checkUsage(2);
yield undefined;
// Stage 3
setLimit(14 * dbSize / 1024);
quotaManager.reset();
request = indexedDB.openForPrincipal(getPrincipal(lastUrl), name,
{ storage: "temporary" });
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield undefined;
is(event.type, "success", "Got correct event type");
let db = event.target.result;
checkUsage(3);
yield undefined;
// Stage 4
let trans = db.transaction(["foo"], "readwrite");
let blob = Blob(["bar"]);
request = trans.objectStore("foo").add(blob, 42);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield undefined;
trans.oncomplete = grabEventAndContinueHandler;
event = yield undefined;
checkUsage(4);
yield undefined;
// Cleanup
setLimit();
quotaManager.reset();
SpecialPowers.setBoolPref("dom.quotaManager.testing", testingEnabled);
finishTest();
yield undefined;
}

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

@ -47,6 +47,7 @@ tail =
[test_open_objectStore.js]
[test_optionalArguments.js]
[test_overlapping_transactions.js]
[test_persistenceType.js]
[test_put_get_values.js]
[test_put_get_values_autoIncrement.js]
[test_readonly_transactions.js]
@ -58,6 +59,7 @@ tail =
[test_setVersion_events.js]
[test_setVersion_exclusion.js]
[test_success_events_after_abort.js]
[test_temporary_storage.js]
[test_traffic_jam.js]
[test_transaction_abort.js]
[test_transaction_abort_hang.js]

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

@ -120,9 +120,8 @@ CheckQuotaHelper::GetQuotaPermission(nsIPrincipal* aPrincipal)
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(aPrincipal, "Null principal!");
if (nsContentUtils::IsSystemPrincipal(aPrincipal)) {
return nsIPermissionManager::ALLOW_ACTION;
}
NS_ASSERTION(!nsContentUtils::IsSystemPrincipal(aPrincipal),
"Chrome windows shouldn't track quota!");
nsCOMPtr<nsIPermissionManager> pm =
do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);

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

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

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

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

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

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

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

@ -11,6 +11,7 @@
#include "nsFileStreams.h"
#include "PersistenceType.h"
#include "QuotaObject.h"
BEGIN_QUOTA_NAMESPACE
@ -27,14 +28,17 @@ public:
Close() MOZ_OVERRIDE;
protected:
FileQuotaStream(const nsACString& aOrigin)
: mOrigin(aOrigin)
FileQuotaStream(PersistenceType aPersistenceType, const nsACString& aGroup,
const nsACString& aOrigin)
: mPersistenceType(aPersistenceType), mGroup(aGroup), mOrigin(aOrigin)
{ }
// nsFileStreamBase override
virtual nsresult
DoOpen() MOZ_OVERRIDE;
PersistenceType mPersistenceType;
nsCString mGroup;
nsCString mOrigin;
nsRefPtr<QuotaObject> mQuotaObject;
};
@ -48,8 +52,9 @@ public:
Write(const char* aBuf, uint32_t aCount, uint32_t* _retval) MOZ_OVERRIDE;
protected:
FileQuotaStreamWithWrite(const nsACString& aOrigin)
: FileQuotaStream<FileStreamBase>(aOrigin)
FileQuotaStreamWithWrite(PersistenceType aPersistenceType,
const nsACString& aGroup, const nsACString& aOrigin)
: FileQuotaStream<FileStreamBase>(aPersistenceType, aGroup, aOrigin)
{ }
};
@ -59,12 +64,14 @@ public:
NS_DECL_ISUPPORTS_INHERITED
static already_AddRefed<FileInputStream>
Create(const nsACString& aOrigin, nsIFile* aFile, int32_t aIOFlags = -1,
Create(PersistenceType aPersistenceType, const nsACString& aGroup,
const nsACString& aOrigin, nsIFile* aFile, int32_t aIOFlags = -1,
int32_t aPerm = -1, int32_t aBehaviorFlags = 0);
private:
FileInputStream(const nsACString& aOrigin)
: FileQuotaStream<nsFileInputStream>(aOrigin)
FileInputStream(PersistenceType aPersistenceType, const nsACString& aGroup,
const nsACString& aOrigin)
: FileQuotaStream<nsFileInputStream>(aPersistenceType, aGroup, aOrigin)
{ }
virtual ~FileInputStream() {
@ -78,12 +85,15 @@ public:
NS_DECL_ISUPPORTS_INHERITED
static already_AddRefed<FileOutputStream>
Create(const nsACString& aOrigin, nsIFile* aFile, int32_t aIOFlags = -1,
Create(PersistenceType aPersistenceType, const nsACString& aGroup,
const nsACString& aOrigin, nsIFile* aFile, int32_t aIOFlags = -1,
int32_t aPerm = -1, int32_t aBehaviorFlags = 0);
private:
FileOutputStream(const nsACString& aOrigin)
: FileQuotaStreamWithWrite<nsFileOutputStream>(aOrigin)
FileOutputStream(PersistenceType aPersistenceType, const nsACString& aGroup,
const nsACString& aOrigin)
: FileQuotaStreamWithWrite<nsFileOutputStream>(aPersistenceType, aGroup,
aOrigin)
{ }
virtual ~FileOutputStream() {
@ -97,12 +107,14 @@ public:
NS_DECL_ISUPPORTS_INHERITED
static already_AddRefed<FileStream>
Create(const nsACString& aOrigin, nsIFile* aFile, int32_t aIOFlags = -1,
Create(PersistenceType aPersistenceType, const nsACString& aGroup,
const nsACString& aOrigin, nsIFile* aFile, int32_t aIOFlags = -1,
int32_t aPerm = -1, int32_t aBehaviorFlags = 0);
private:
FileStream(const nsACString& aOrigin)
: FileQuotaStreamWithWrite<nsFileStream>(aOrigin)
FileStream(PersistenceType aPersistenceType, const nsACString& aGroup,
const nsACString& aOrigin)
: FileQuotaStreamWithWrite<nsFileStream>(aPersistenceType, aGroup, aOrigin)
{ }
virtual ~FileStream() {

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

@ -0,0 +1,62 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_quota_origincollection_h__
#define mozilla_dom_quota_origincollection_h__
#include "mozilla/dom/quota/QuotaCommon.h"
#include "nsHashKeys.h"
#include "nsTHashtable.h"
#include "Utilities.h"
BEGIN_QUOTA_NAMESPACE
class OriginCollection
{
public:
bool
ContainsPattern(const nsACString& aPattern)
{
return mPatterns.Contains(aPattern);
}
void
AddPattern(const nsACString& aPattern)
{
MOZ_ASSERT(!mOrigins.Count());
MOZ_ASSERT(!ContainsPattern(aPattern));
mPatterns.AppendElement(aPattern);
}
bool
ContainsOrigin(const nsACString& aOrigin)
{
for (uint32_t index = 0; index < mPatterns.Length(); index++) {
if (PatternMatchesOrigin(mPatterns[index], aOrigin)) {
return true;
}
}
return mOrigins.GetEntry(aOrigin);
}
void
AddOrigin(const nsACString& aOrigin)
{
MOZ_ASSERT(!ContainsOrigin(aOrigin));
mOrigins.PutEntry(aOrigin);
}
private:
nsTArray<nsCString> mPatterns;
nsTHashtable<nsCStringHashKey> mOrigins;
};
END_QUOTA_NAMESPACE
#endif // mozilla_dom_quota_origincollection_h__

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

@ -26,6 +26,12 @@ public:
return OriginOrPatternString(aPattern, false);
}
static OriginOrPatternString
FromNull()
{
return OriginOrPatternString();
}
bool
IsOrigin() const
{
@ -35,18 +41,31 @@ public:
bool
IsPattern() const
{
return !mIsOrigin;
return mIsPattern;
}
bool
IsNull() const
{
return mIsNull;
}
private:
OriginOrPatternString(const nsACString& aOriginOrPattern, bool aIsOrigin)
: nsCString(aOriginOrPattern), mIsOrigin(aIsOrigin)
: nsCString(aOriginOrPattern),
mIsOrigin(aIsOrigin), mIsPattern(!aIsOrigin), mIsNull(false)
{ }
OriginOrPatternString()
: mIsOrigin(false), mIsPattern(false), mIsNull(true)
{ }
bool
operator==(const OriginOrPatternString& aOther) MOZ_DELETE;
bool mIsOrigin;
bool mIsPattern;
bool mIsNull;
};
END_QUOTA_NAMESPACE

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

@ -0,0 +1,77 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_quota_persistencetype_h__
#define mozilla_dom_quota_persistencetype_h__
#include "mozilla/dom/quota/QuotaCommon.h"
#include "mozilla/dom/StorageTypeBinding.h"
BEGIN_QUOTA_NAMESPACE
enum PersistenceType
{
PERSISTENCE_TYPE_PERSISTENT = 0,
PERSISTENCE_TYPE_TEMPORARY,
// Only needed for IPC serialization helper, should never be used in code.
PERSISTENCE_TYPE_INVALID
};
inline void
PersistenceTypeToText(PersistenceType aPersistenceType, nsACString& aText)
{
switch (aPersistenceType) {
case PERSISTENCE_TYPE_PERSISTENT:
aText.AssignLiteral("persistent");
return;
case PERSISTENCE_TYPE_TEMPORARY:
aText.AssignLiteral("temporary");
return;
case PERSISTENCE_TYPE_INVALID:
default:
MOZ_CRASH("Bad persistence type value!");
}
MOZ_ASSUME_UNREACHABLE("Should never get here!");
}
inline PersistenceType
PersistenceTypeFromText(const nsACString& aText)
{
if (aText.EqualsLiteral("persistent")) {
return PERSISTENCE_TYPE_PERSISTENT;
}
if (aText.EqualsLiteral("temporary")) {
return PERSISTENCE_TYPE_TEMPORARY;
}
MOZ_ASSUME_UNREACHABLE("Should never get here!");
}
inline mozilla::dom::StorageType
PersistenceTypeToStorage(PersistenceType aPersistenceType)
{
return mozilla::dom::StorageType(static_cast<int>(aPersistenceType));
}
inline PersistenceType
PersistenceTypeFromStorage(const Optional<mozilla::dom::StorageType>& aStorage,
PersistenceType aDefaultPersistenceType)
{
if (aStorage.WasPassed()) {
return PersistenceType(static_cast<int>(aStorage.Value()));
}
return aDefaultPersistenceType;
}
END_QUOTA_NAMESPACE
#endif // mozilla_dom_quota_persistencetype_h__

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

@ -24,14 +24,14 @@
BEGIN_QUOTA_NAMESPACE
#ifdef DEBUG
void
AssertIsOnIOThread();
#else
inline void
AssertIsOnIOThread()
{ }
#endif
void
AssertCurrentThreadOwnsQuotaMutex();
bool
IsOnIOThread();
END_QUOTA_NAMESPACE

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

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

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

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

@ -7,6 +7,7 @@
#include "QuotaObject.h"
#include "QuotaManager.h"
#include "Utilities.h"
USING_QUOTA_NAMESPACE
@ -68,10 +69,24 @@ QuotaObject::UpdateSize(int64_t aSize)
MutexAutoLock lock(quotaManager->mQuotaMutex);
if (mOriginInfo) {
if (!mOriginInfo) {
return;
}
GroupInfo* groupInfo = mOriginInfo->mGroupInfo;
if (groupInfo->IsForTemporaryStorage()) {
quotaManager->mTemporaryStorageUsage -= mSize;
}
groupInfo->mUsage -= mSize;
mOriginInfo->mUsage -= mSize;
mSize = aSize;
mOriginInfo->mUsage += mSize;
groupInfo->mUsage += mSize;
if (groupInfo->IsForTemporaryStorage()) {
quotaManager->mTemporaryStorageUsage += mSize;
}
}
@ -89,10 +104,15 @@ QuotaObject::MaybeAllocateMoreSpace(int64_t aOffset, int32_t aCount)
return true;
}
int64_t newUsage = mOriginInfo->mUsage - mSize + end;
GroupInfo* groupInfo = mOriginInfo->mGroupInfo;
if (groupInfo->IsForPersistentStorage()) {
uint64_t newUsage = mOriginInfo->mUsage - mSize + end;
if (newUsage > mOriginInfo->mLimit) {
// This will block the thread, but it will also drop the mutex while
// waiting. The mutex will be reacquired again when the waiting is finished.
// waiting. The mutex will be reacquired again when the waiting is
// finished.
if (!quotaManager->LockedQuotaIsLifted()) {
return false;
}
@ -108,13 +128,15 @@ QuotaObject::MaybeAllocateMoreSpace(int64_t aOffset, int32_t aCount)
return true;
}
nsCString group = mOriginInfo->mGroupInfo->mGroup;
nsCString origin = mOriginInfo->mOrigin;
mOriginInfo->LockedClearOriginInfos();
NS_ASSERTION(!mOriginInfo,
"Should have cleared in LockedClearOriginInfos!");
quotaManager->mOriginInfos.Remove(origin);
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.
@ -126,23 +148,150 @@ QuotaObject::MaybeAllocateMoreSpace(int64_t aOffset, int32_t aCount)
}
mOriginInfo->mUsage = newUsage;
groupInfo->mUsage = groupInfo->mUsage - mSize + end;
mSize = end;
return true;
}
NS_ASSERTION(groupInfo->mPersistenceType == PERSISTENCE_TYPE_TEMPORARY,
"Huh?");
uint64_t delta = end - mSize;
uint64_t newUsage = mOriginInfo->mUsage + delta;
// Temporary storage has no limit for origin usage (there's a group and the
// global limit though).
uint64_t newGroupUsage = groupInfo->mUsage + delta;
// Temporary storage has a hard limit for group usage (20 % of the global
// limit).
if (newGroupUsage > quotaManager->GetGroupLimit()) {
return false;
}
uint64_t newTemporaryStorageUsage = quotaManager->mTemporaryStorageUsage +
delta;
if (newTemporaryStorageUsage > quotaManager->mTemporaryStorageLimit) {
// This will block the thread without holding the lock while waitting.
nsAutoTArray<OriginInfo*, 10> originInfos;
uint64_t sizeToBeFreed =
quotaManager->LockedCollectOriginsForEviction(delta, originInfos);
if (!sizeToBeFreed) {
return false;
}
NS_ASSERTION(sizeToBeFreed >= delta, "Huh?");
{
MutexAutoUnlock autoUnlock(quotaManager->mQuotaMutex);
for (uint32_t i = 0; i < originInfos.Length(); i++) {
quotaManager->DeleteTemporaryFilesForOrigin(originInfos[i]->mOrigin);
}
}
// Relocked.
NS_ASSERTION(mOriginInfo, "How come?!");
nsTArray<nsCString> origins;
for (uint32_t i = 0; i < originInfos.Length(); i++) {
OriginInfo* originInfo = originInfos[i];
NS_ASSERTION(originInfo != mOriginInfo, "Deleted itself!");
nsCString group = originInfo->mGroupInfo->mGroup;
nsCString origin = originInfo->mOrigin;
quotaManager->LockedRemoveQuotaForOrigin(PERSISTENCE_TYPE_TEMPORARY,
group, origin);
#ifdef DEBUG
originInfos[i] = nullptr;
#endif
origins.AppendElement(origin);
}
// We unlocked and relocked several times so we need to recompute all the
// essential variables and recheck the group limit.
delta = end - mSize;
newUsage = mOriginInfo->mUsage + delta;
newGroupUsage = groupInfo->mUsage + delta;
if (newGroupUsage > quotaManager->GetGroupLimit()) {
// Unfortunately some other thread increased the group usage in the
// meantime and we are not below the group limit anymore.
// However, the origin eviction must be finalized in this case too.
MutexAutoUnlock autoUnlock(quotaManager->mQuotaMutex);
quotaManager->FinalizeOriginEviction(origins);
return false;
}
newTemporaryStorageUsage = quotaManager->mTemporaryStorageUsage + delta;
NS_ASSERTION(newTemporaryStorageUsage <=
quotaManager->mTemporaryStorageLimit, "How come?!");
// Ok, we successfully freed enough space and the operation can continue
// without throwing the quota error.
mOriginInfo->mUsage = newUsage;
groupInfo->mUsage = newGroupUsage;
quotaManager->mTemporaryStorageUsage = newTemporaryStorageUsage;;
// Some other thread could increase the size in the meantime, but no more
// than this one.
NS_ASSERTION(mSize < end, "This shouldn't happen!");
mSize = end;
// Finally, release IO thread only objects and allow next synchronized
// ops for the evicted origins.
MutexAutoUnlock autoUnlock(quotaManager->mQuotaMutex);
quotaManager->FinalizeOriginEviction(origins);
return true;
}
mOriginInfo->mUsage = newUsage;
groupInfo->mUsage = newGroupUsage;
quotaManager->mTemporaryStorageUsage = newTemporaryStorageUsage;
mSize = end;
return true;
}
#ifdef DEBUG
void
OriginInfo::LockedClearOriginInfos()
OriginInfo::LockedDecreaseUsage(int64_t aSize)
{
AssertCurrentThreadOwnsQuotaMutex();
mUsage -= aSize;
mGroupInfo->mUsage -= aSize;
if (mGroupInfo->IsForTemporaryStorage()) {
QuotaManager* quotaManager = QuotaManager::Get();
NS_ASSERTION(quotaManager, "Shouldn't be null!");
quotaManager->mQuotaMutex.AssertCurrentThreadOwns();
mQuotaObjects.EnumerateRead(ClearOriginInfoCallback, nullptr);
quotaManager->mTemporaryStorageUsage -= aSize;
}
}
#endif
// static
PLDHashOperator
@ -157,3 +306,118 @@ OriginInfo::ClearOriginInfoCallback(const nsAString& aKey,
return PL_DHASH_NEXT;
}
already_AddRefed<OriginInfo>
GroupInfo::LockedGetOriginInfo(const nsACString& aOrigin)
{
AssertCurrentThreadOwnsQuotaMutex();
for (uint32_t index = 0; index < mOriginInfos.Length(); index++) {
nsRefPtr<OriginInfo>& originInfo = mOriginInfos[index];
if (originInfo->mOrigin == aOrigin) {
nsRefPtr<OriginInfo> result = originInfo;
return result.forget();
}
}
return nullptr;
}
void
GroupInfo::LockedAddOriginInfo(OriginInfo* aOriginInfo)
{
AssertCurrentThreadOwnsQuotaMutex();
NS_ASSERTION(!mOriginInfos.Contains(aOriginInfo),
"Replacing an existing entry!");
mOriginInfos.AppendElement(aOriginInfo);
mUsage += aOriginInfo->mUsage;
if (IsForTemporaryStorage()) {
QuotaManager* quotaManager = QuotaManager::Get();
NS_ASSERTION(quotaManager, "Shouldn't be null!");
quotaManager->mTemporaryStorageUsage += aOriginInfo->mUsage;
}
}
void
GroupInfo::LockedRemoveOriginInfo(const nsACString& aOrigin)
{
AssertCurrentThreadOwnsQuotaMutex();
for (uint32_t index = 0; index < mOriginInfos.Length(); index++) {
if (mOriginInfos[index]->mOrigin == aOrigin) {
mUsage -= mOriginInfos[index]->mUsage;
if (IsForTemporaryStorage()) {
QuotaManager* quotaManager = QuotaManager::Get();
NS_ASSERTION(quotaManager, "Shouldn't be null!");
quotaManager->mTemporaryStorageUsage -= mOriginInfos[index]->mUsage;
}
mOriginInfos.RemoveElementAt(index);
return;
}
}
}
void
GroupInfo::LockedRemoveOriginInfos()
{
AssertCurrentThreadOwnsQuotaMutex();
for (uint32_t index = mOriginInfos.Length(); index > 0; index--) {
mUsage -= mOriginInfos[index - 1]->mUsage;
if (IsForTemporaryStorage()) {
QuotaManager* quotaManager = QuotaManager::Get();
NS_ASSERTION(quotaManager, "Shouldn't be null!");
quotaManager->mTemporaryStorageUsage -= mOriginInfos[index - 1]->mUsage;
}
mOriginInfos.RemoveElementAt(index - 1);
}
}
void
GroupInfo::LockedRemoveOriginInfosForPattern(const nsACString& aPattern)
{
AssertCurrentThreadOwnsQuotaMutex();
for (uint32_t index = mOriginInfos.Length(); index > 0; index--) {
if (PatternMatchesOrigin(aPattern, mOriginInfos[index - 1]->mOrigin)) {
mUsage -= mOriginInfos[index - 1]->mUsage;
if (IsForTemporaryStorage()) {
QuotaManager* quotaManager = QuotaManager::Get();
NS_ASSERTION(quotaManager, "Shouldn't be null!");
quotaManager->mTemporaryStorageUsage -= mOriginInfos[index - 1]->mUsage;
}
mOriginInfos.RemoveElementAt(index - 1);
}
}
}
nsRefPtr<GroupInfo>&
GroupInfoPair::GetGroupInfoForPersistenceType(PersistenceType aPersistenceType)
{
switch (aPersistenceType) {
case PERSISTENCE_TYPE_PERSISTENT:
return mPersistentStorageGroupInfo;
case PERSISTENCE_TYPE_TEMPORARY:
return mTemporaryStorageGroupInfo;
case PERSISTENCE_TYPE_INVALID:
default:
MOZ_CRASH("Bad persistence type value!");
return mPersistentStorageGroupInfo;
}
}

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

@ -11,8 +11,12 @@
#include "nsDataHashtable.h"
#include "PersistenceType.h"
BEGIN_QUOTA_NAMESPACE
class GroupInfo;
class GroupInfoPair;
class OriginInfo;
class QuotaManager;
@ -37,10 +41,14 @@ public:
private:
QuotaObject(OriginInfo* aOriginInfo, const nsAString& aPath, int64_t aSize)
: mOriginInfo(aOriginInfo), mPath(aPath), mSize(aSize)
{ }
{
MOZ_COUNT_CTOR(QuotaObject);
}
virtual ~QuotaObject()
{ }
~QuotaObject()
{
MOZ_COUNT_DTOR(QuotaObject);
}
mozilla::ThreadSafeAutoRefCnt mRefCnt;
@ -51,27 +59,51 @@ private:
class OriginInfo
{
friend class GroupInfo;
friend class QuotaManager;
friend class QuotaObject;
public:
OriginInfo(const nsACString& aOrigin, int64_t aLimit, int64_t aUsage)
: mOrigin(aOrigin), mLimit(aLimit), mUsage(aUsage)
OriginInfo(GroupInfo* aGroupInfo, const nsACString& aOrigin, uint64_t aLimit,
uint64_t aUsage, int64_t aAccessTime)
: mGroupInfo(aGroupInfo), mOrigin(aOrigin), mLimit(aLimit), mUsage(aUsage),
mAccessTime(aAccessTime)
{
MOZ_COUNT_CTOR(OriginInfo);
}
~OriginInfo()
{
MOZ_COUNT_DTOR(OriginInfo);
}
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(OriginInfo)
int64_t
AccessTime() const
{
return mAccessTime;
}
private:
void
#ifdef DEBUG
LockedClearOriginInfos();
#else
LockedDecreaseUsage(int64_t aSize);
void
LockedUpdateAccessTime(int64_t aAccessTime)
{
AssertCurrentThreadOwnsQuotaMutex();
mAccessTime = aAccessTime;
}
void
LockedClearOriginInfos()
{
AssertCurrentThreadOwnsQuotaMutex();
mQuotaObjects.EnumerateRead(ClearOriginInfoCallback, nullptr);
}
#endif
static PLDHashOperator
ClearOriginInfoCallback(const nsAString& aKey,
@ -79,9 +111,153 @@ private:
nsDataHashtable<nsStringHashKey, QuotaObject*> mQuotaObjects;
GroupInfo* mGroupInfo;
nsCString mOrigin;
int64_t mLimit;
int64_t mUsage;
uint64_t mLimit;
uint64_t mUsage;
int64_t mAccessTime;
};
class OriginInfoLRUComparator
{
public:
bool
Equals(const OriginInfo* a, const OriginInfo* b) const
{
return
a && b ? a->AccessTime() == b->AccessTime() : !a && !b ? true : false;
}
bool
LessThan(const OriginInfo* a, const OriginInfo* b) const
{
return a && b ? a->AccessTime() < b->AccessTime() : b ? true : false;
}
};
class GroupInfo
{
friend class GroupInfoPair;
friend class OriginInfo;
friend class QuotaManager;
friend class QuotaObject;
public:
GroupInfo(PersistenceType aPersistenceType, const nsACString& aGroup)
: mPersistenceType(aPersistenceType), mGroup(aGroup), mUsage(0)
{
MOZ_COUNT_CTOR(GroupInfo);
}
~GroupInfo()
{
MOZ_COUNT_DTOR(GroupInfo);
}
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GroupInfo)
bool
IsForPersistentStorage() const
{
return mPersistenceType == PERSISTENCE_TYPE_PERSISTENT;
}
bool
IsForTemporaryStorage() const
{
return mPersistenceType == PERSISTENCE_TYPE_TEMPORARY;
}
private:
already_AddRefed<OriginInfo>
LockedGetOriginInfo(const nsACString& aOrigin);
void
LockedAddOriginInfo(OriginInfo* aOriginInfo);
void
LockedRemoveOriginInfo(const nsACString& aOrigin);
void
LockedRemoveOriginInfos();
void
LockedRemoveOriginInfosForPattern(const nsACString& aPattern);
bool
LockedHasOriginInfos()
{
AssertCurrentThreadOwnsQuotaMutex();
return !mOriginInfos.IsEmpty();
}
nsTArray<nsRefPtr<OriginInfo> > mOriginInfos;
PersistenceType mPersistenceType;
nsCString mGroup;
uint64_t mUsage;
};
class GroupInfoPair
{
friend class QuotaManager;
public:
GroupInfoPair()
{
MOZ_COUNT_CTOR(GroupInfoPair);
}
~GroupInfoPair()
{
MOZ_COUNT_DTOR(GroupInfoPair);
}
private:
already_AddRefed<GroupInfo>
LockedGetGroupInfo(PersistenceType aPersistenceType)
{
AssertCurrentThreadOwnsQuotaMutex();
nsRefPtr<GroupInfo> groupInfo =
GetGroupInfoForPersistenceType(aPersistenceType);
return groupInfo.forget();
}
void
LockedSetGroupInfo(GroupInfo* aGroupInfo)
{
AssertCurrentThreadOwnsQuotaMutex();
nsRefPtr<GroupInfo>& groupInfo =
GetGroupInfoForPersistenceType(aGroupInfo->mPersistenceType);
groupInfo = aGroupInfo;
}
void
LockedClearGroupInfo(PersistenceType aPersistenceType)
{
AssertCurrentThreadOwnsQuotaMutex();
nsRefPtr<GroupInfo>& groupInfo =
GetGroupInfoForPersistenceType(aPersistenceType);
groupInfo = nullptr;
}
bool
LockedHasGroupInfos()
{
AssertCurrentThreadOwnsQuotaMutex();
return mPersistentStorageGroupInfo || mTemporaryStorageGroupInfo;
}
nsRefPtr<GroupInfo>&
GetGroupInfoForPersistenceType(PersistenceType aPersistenceType);
nsRefPtr<GroupInfo> mPersistentStorageGroupInfo;
nsRefPtr<GroupInfo> mTemporaryStorageGroupInfo;
};
END_QUOTA_NAMESPACE

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

@ -12,8 +12,13 @@
BEGIN_QUOTA_NAMESPACE
enum StoragePrivilege {
Content,
Chrome
// Quota not tracked, persistence type is always "persistent".
Chrome,
// Quota tracked, persistence type can be either "persistent" or "temporary".
// The permission "defaul-persistent-storage" is used to determine the
// default persistence type.
Content
};
END_QUOTA_NAMESPACE

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

@ -4,8 +4,8 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_quota_usagerunnable_h__
#define mozilla_dom_quota_usagerunnable_h__
#ifndef mozilla_dom_quota_usageinfo_h__
#define mozilla_dom_quota_usageinfo_h__
#include "mozilla/dom/quota/QuotaCommon.h"
@ -14,14 +14,14 @@
BEGIN_QUOTA_NAMESPACE
class UsageRunnable
class UsageInfo
{
public:
UsageRunnable()
UsageInfo()
: mCanceled(0), mDatabaseUsage(0), mFileUsage(0)
{ }
virtual ~UsageRunnable()
virtual ~UsageInfo()
{ }
bool
@ -79,4 +79,4 @@ private:
END_QUOTA_NAMESPACE
#endif // mozilla_dom_quota_usagerunnable_h__
#endif // mozilla_dom_quota_usageinfo_h__

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

@ -24,11 +24,12 @@ EXPORTS.mozilla.dom.quota += [
'Client.h',
'FileStreams.h',
'OriginOrPatternString.h',
'PersistenceType.h',
'QuotaCommon.h',
'QuotaManager.h',
'QuotaObject.h',
'StoragePrivilege.h',
'UsageRunnable.h',
'UsageInfo.h',
'Utilities.h',
]

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

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

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

@ -10,7 +10,7 @@ interface nsIQuotaRequest;
interface nsIURI;
interface nsIUsageCallback;
[scriptable, builtinclass, uuid(8d74e6f8-81c3-4045-9bb7-70bdb7b11b25)]
[scriptable, builtinclass, uuid(f19a03ae-e97d-41e9-95dd-681b910c4093)]
interface nsIQuotaManager : nsISupports
{
/**
@ -29,6 +29,17 @@ interface nsIQuotaManager : nsISupports
[optional] in unsigned long aAppId,
[optional] in boolean aInMozBrowserOnly);
/**
* Removes all storages. The files may not be deleted immediately depending
* on prohibitive concurrent operations.
* Be careful, this removes *all* the data that has ever been stored!
*
* If the dom.quotaManager.testing preference is not true the call will be
* a no-op.
*/
void
clear();
/**
* Removes all storages stored for the given URI. The files may not be
* deleted immediately depending on prohibitive concurrent operations.
@ -41,4 +52,16 @@ interface nsIQuotaManager : nsISupports
clearStoragesForURI(in nsIURI aURI,
[optional] in unsigned long aAppId,
[optional] in boolean aInMozBrowserOnly);
/**
* Resets quota and storage management. This can be used to force
* reinitialization of the temp storage, for example when the pref for
* overriding the temp storage limit has changed.
* Be carefull, this invalidates all live storages!
*
* If the dom.quotaManager.testing preference is not true the call will be
* a no-op.
*/
void
reset();
};

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

@ -44,6 +44,9 @@ interface IDBDatabase : EventTarget {
};
partial interface IDBDatabase {
[Pref="dom.indexedDB.experimental"]
readonly attribute StorageType storage;
[Throws]
IDBRequest mozCreateFileHandle (DOMString name, optional DOMString type);
};

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

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

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

@ -0,0 +1,7 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
enum StorageType { "persistent", "temporary" };

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

@ -259,6 +259,7 @@ WEBIDL_FILES = [
'SimpleGestureEvent.webidl',
'SourceBuffer.webidl',
'SourceBufferList.webidl',
'StorageType.webidl',
'StyleSheet.webidl',
'SVGAElement.webidl',
'SVGAltGlyphElement.webidl',

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

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

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

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

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

@ -1182,6 +1182,11 @@ SpecialPowersAPI.prototype = {
Cu.forceCC();
},
// Due to various dependencies between JS objects and C++ objects, an ordinary
// forceGC doesn't necessarily clear all unused objects, thus the GC and CC
// needs to run several times and when no other JS is running.
// The current number of iterations has been determined according to massive
// cross platform testing.
exactGC: function(win, callback) {
var self = this;
let count = 0;