Bug 786295 - 'Delete IndexedDB related to an app when uninstalled'. r=bz+khuey+sicking.

This commit is contained in:
Ben Turner 2012-10-23 09:31:19 -07:00
Родитель 993f960b0d
Коммит 5e8d8d57f2
35 изменённых файлов: 1188 добавлений и 249 удалений

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

@ -21,7 +21,7 @@ interface nsIContentSecurityPolicy;
[ptr] native JSPrincipals(JSPrincipals);
[ptr] native PrincipalArray(nsTArray<nsCOMPtr<nsIPrincipal> >);
[scriptable, uuid(96a92f0c-adcb-44ac-a034-37627647ec97)]
[scriptable, uuid(3a283dc9-f733-4618-a36f-e2b68c280ab7)]
interface nsIPrincipal : nsISerializable
{
/**
@ -195,6 +195,12 @@ interface nsIPrincipal : nsISerializable
* appId everywhere where we construct principals.
*/
readonly attribute boolean unknownAppId;
/**
* Returns true iff this principal is a null principal (corresponding to an
* unknown, hence assumed minimally privileged, security context).
*/
readonly attribute boolean isNullPrincipal;
};
/**
@ -217,4 +223,4 @@ interface nsIExpandedPrincipal : nsISupports
* should not be changed and should only be used ephemerally.
*/
[noscript] readonly attribute PrincipalArray whiteList;
};
};

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

@ -71,6 +71,7 @@ public:
NS_IMETHOD GetAppId(uint32_t* aAppStatus);
NS_IMETHOD GetIsInBrowserElement(bool* aIsInBrowserElement);
NS_IMETHOD GetUnknownAppId(bool* aUnknownAppId);
NS_IMETHOD GetIsNullPrincipal(bool* aIsNullPrincipal);
#ifdef DEBUG
virtual void dumpImpl();
#endif
@ -152,6 +153,7 @@ public:
NS_IMETHOD GetAppId(uint32_t* aAppStatus);
NS_IMETHOD GetIsInBrowserElement(bool* aIsInBrowserElement);
NS_IMETHOD GetUnknownAppId(bool* aUnknownAppId);
NS_IMETHOD GetIsNullPrincipal(bool* aIsNullPrincipal);
#ifdef DEBUG
virtual void dumpImpl();
#endif

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

@ -291,6 +291,13 @@ nsNullPrincipal::GetUnknownAppId(bool* aUnknownAppId)
return NS_OK;
}
NS_IMETHODIMP
nsNullPrincipal::GetIsNullPrincipal(bool* aIsNullPrincipal)
{
*aIsNullPrincipal = true;
return NS_OK;
}
/**
* nsISerializable implementation
*/

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

@ -541,6 +541,13 @@ nsPrincipal::GetUnknownAppId(bool* aUnknownAppId)
return NS_OK;
}
NS_IMETHODIMP
nsPrincipal::GetIsNullPrincipal(bool* aIsNullPrincipal)
{
*aIsNullPrincipal = false;
return NS_OK;
}
NS_IMETHODIMP
nsPrincipal::Read(nsIObjectInputStream* aStream)
{
@ -852,6 +859,13 @@ nsExpandedPrincipal::GetUnknownAppId(bool* aUnknownAppId)
return NS_OK;
}
NS_IMETHODIMP
nsExpandedPrincipal::GetIsNullPrincipal(bool* aIsNullPrincipal)
{
*aIsNullPrincipal = false;
return NS_OK;
}
void
nsExpandedPrincipal::GetScriptLocation(nsACString& aStr)
{

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

@ -2992,11 +2992,13 @@ GetExtendedOrigin(nsIURI* aURI, uint32_t aAppId, bool aInMozBrowser,
return;
}
// aExtendedOrigin = appId + "+" + origin + "+" + { 't', 'f' }
// aExtendedOrigin = appId + "+" + { 't', 'f' } "+" + origin;
aExtendedOrigin.Truncate();
aExtendedOrigin.AppendInt(aAppId);
aExtendedOrigin.Append(NS_LITERAL_CSTRING("+") + origin + NS_LITERAL_CSTRING("+"));
aExtendedOrigin.Append('+');
aExtendedOrigin.Append(aInMozBrowser ? 't' : 'f');
aExtendedOrigin.Append('+');
aExtendedOrigin.Append(origin);
return;
}

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

@ -198,6 +198,13 @@ nsSystemPrincipal::GetUnknownAppId(bool* aUnknownAppId)
return NS_OK;
}
NS_IMETHODIMP
nsSystemPrincipal::GetIsNullPrincipal(bool* aIsNullPrincipal)
{
*aIsNullPrincipal = false;
return NS_OK;
}
//////////////////////////////////////////
// Methods implementing nsISerializable //
//////////////////////////////////////////

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

@ -1725,6 +1725,10 @@ let DOMApplicationRegistry = {
switch (message.name) {
case "Webapps:ClearBrowserData":
this._clearPrivateData(appId, true);
// XXXbent This is a hack until bug 802366 is fixed. Currently all data
// loaded in mozbrowser frames within an app believe that their
// appId is 0.
this._clearPrivateData(0, true);
break;
}
},

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

@ -181,31 +181,6 @@ DatabaseInfo::Remove(nsIAtom* aId)
}
}
PLDHashOperator
EnumerateDatabasesRemoveOrigin(nsISupports* aId,
DatabaseInfo*& aDatabaseInfo,
void* aUserArg)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
const nsACString* origin = static_cast<const nsACString*>(aUserArg);
return aDatabaseInfo->origin.Equals(*origin) ?
PL_DHASH_REMOVE :
PL_DHASH_NEXT;
}
// static
void
DatabaseInfo::RemoveAllForOrigin(const nsACString& aOrigin)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
if (gDatabaseHash) {
gDatabaseHash->Enumerate(EnumerateDatabasesRemoveOrigin,
const_cast<nsACString*>(&aOrigin));
}
}
bool
DatabaseInfo::GetObjectStoreNames(nsTArray<nsString>& aNames)
{

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

@ -62,8 +62,6 @@ struct DatabaseInfo : public DatabaseInfoGuts
static void Remove(nsIAtom* aId);
static void RemoveAllForOrigin(const nsACString& aOrigin);
bool GetObjectStoreNames(nsTArray<nsString>& aNames);
bool ContainsStoreName(const nsAString& aName);

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

@ -10,6 +10,7 @@
#include "mozilla/Mutex.h"
#include "mozilla/storage.h"
#include "mozilla/unused.h"
#include "mozilla/dom/ContentParent.h"
#include "nsDOMClassInfo.h"
#include "nsDOMLists.h"
@ -33,6 +34,7 @@
#include "nsContentUtils.h"
#include "ipc/IndexedDBChild.h"
#include "ipc/IndexedDBParent.h"
USING_INDEXEDDB_NAMESPACE
using mozilla::dom::ContentParent;
@ -269,12 +271,14 @@ IDBDatabase::Invalidate()
if (owner) {
IndexedDatabaseManager::CancelPromptsForWindow(owner);
}
}
bool
IDBDatabase::IsInvalidated()
{
return mInvalidated;
DatabaseInfo::Remove(mDatabaseId);
// And let the child process know as well.
if (mActorParent) {
NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
mozilla::unused << mActorParent->SendInvalidate();
}
}
void
@ -299,8 +303,9 @@ IDBDatabase::DisconnectFromActor()
}
bool
IDBDatabase::IsDisconnectedFromActor()
IDBDatabase::IsDisconnectedFromActor() const
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
return mDisconnected;
}
@ -330,7 +335,7 @@ IDBDatabase::CloseInternal(bool aIsDead)
}
// And let the parent process know as well.
if (mActorChild) {
if (mActorChild && !IsInvalidated()) {
NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
mActorChild->SendClose(aIsDead);
}
@ -338,7 +343,7 @@ IDBDatabase::CloseInternal(bool aIsDead)
}
bool
IDBDatabase::IsClosed()
IDBDatabase::IsClosed() const
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
return mClosed;

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

@ -74,12 +74,12 @@ public:
return mDatabaseInfo;
}
const nsString& Name()
const nsString& Name() const
{
return mName;
}
const nsString& FilePath()
const nsString& FilePath() const
{
return mFilePath;
}
@ -95,7 +95,7 @@ public:
return doc.forget();
}
nsCString& Origin()
const nsCString& Origin() const
{
return mASCIIOrigin;
}
@ -103,20 +103,24 @@ public:
void Invalidate();
// Whether or not the database has been invalidated. If it has then no further
// transactions for this database will be allowed to run.
bool IsInvalidated();
// transactions for this database will be allowed to run. This function may be
// called on any thread.
bool IsInvalidated() const
{
return mInvalidated;
}
void DisconnectFromActor();
// Whether or not the database has been disconnected from its actor. If true
// it is not safe to send any IPC messages to the actor representing this db
// or any of its subactors.
bool IsDisconnectedFromActor();
bool IsDisconnectedFromActor() const;
void CloseInternal(bool aIsDead);
// Whether or not the database has had Close called on it.
bool IsClosed();
bool IsClosed() const;
void EnterSetVersionTransaction();
void ExitSetVersionTransaction();

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

@ -541,8 +541,9 @@ IDBFactory::OpenCommon(const nsAString& aName,
IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
NS_ASSERTION(mgr, "This should never be null!");
rv =
mgr->WaitForOpenAllowed(mASCIIOrigin, openHelper->Id(), permissionHelper);
rv =
mgr->WaitForOpenAllowed(OriginOrPatternString::FromOrigin(mASCIIOrigin),
openHelper->Id(), permissionHelper);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
}
else if (aDeleting) {

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

@ -175,6 +175,44 @@ struct SerializedStructuredCloneWriteInfo
uint64_t offsetToKeyProp;
};
class OriginOrPatternString : public nsCString
{
public:
static OriginOrPatternString
FromOrigin(const nsACString& aOrigin)
{
return OriginOrPatternString(aOrigin, true);
}
static OriginOrPatternString
FromPattern(const nsACString& aPattern)
{
return OriginOrPatternString(aPattern, false);
}
bool
IsOrigin() const
{
return mIsOrigin;
}
bool
IsPattern() const
{
return !mIsOrigin;
}
private:
OriginOrPatternString(const nsACString& aOriginOrPattern, bool aIsOrigin)
: nsCString(aOriginOrPattern), mIsOrigin(aIsOrigin)
{ }
bool
operator==(const OriginOrPatternString& aOther) MOZ_DELETE;
bool mIsOrigin;
};
END_INDEXEDDB_NAMESPACE
#endif // mozilla_dom_indexeddb_indexeddatabase_h__

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

@ -5,14 +5,15 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "IndexedDatabaseManager.h"
#include "DatabaseInfo.h"
#include "mozIApplicationClearPrivateDataParams.h"
#include "nsIAtom.h"
#include "nsIConsoleService.h"
#include "nsIDOMScriptObjectFactory.h"
#include "nsIFile.h"
#include "nsIFileStorage.h"
#include "nsIObserverService.h"
#include "nsIPrincipal.h"
#include "nsIScriptError.h"
#include "nsIScriptObjectPrincipal.h"
#include "nsIScriptSecurityManager.h"
@ -27,8 +28,10 @@
#include "mozilla/storage.h"
#include "nsAppDirectoryServiceDefs.h"
#include "nsContentUtils.h"
#include "nsCRTGlue.h"
#include "nsDirectoryServiceUtils.h"
#include "nsEventDispatcher.h"
#include "nsScriptSecurityManager.h"
#include "nsThreadUtils.h"
#include "nsXPCOM.h"
#include "nsXPCOMPrivate.h"
@ -133,34 +136,247 @@ EnumerateToTArray(const nsACString& aKey,
NS_ASSERTION(aValue, "Null pointer!");
NS_ASSERTION(aUserArg, "Null pointer!");
nsTArray<T>* array =
static_cast<nsTArray<T>*>(aUserArg);
if (!array->AppendElements(*aValue)) {
NS_WARNING("Out of memory!");
return PL_DHASH_STOP;
}
static_cast<nsTArray<T>*>(aUserArg)->AppendElements(*aValue);
return PL_DHASH_NEXT;
}
bool
PatternMatchesOrigin(const nsACString& aPatternString, const nsACString& aOrigin)
{
// Aren't we smart!
return StringBeginsWith(aOrigin, aPatternString);
}
enum MozBrowserPatternFlag
{
MozBrowser = 0,
NotMozBrowser,
IgnoreMozBrowser
};
// Use one of the friendly overloads below.
void
GetOriginPatternString(uint32_t aAppId, MozBrowserPatternFlag aBrowserFlag,
const nsACString& aOrigin, nsAutoCString& _retval)
{
NS_ASSERTION(aAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID,
"Bad appId!");
NS_ASSERTION(aOrigin.IsEmpty() || aBrowserFlag != IgnoreMozBrowser,
"Bad args!");
if (aOrigin.IsEmpty()) {
_retval.Truncate();
_retval.AppendInt(aAppId);
_retval.Append('+');
if (aBrowserFlag != IgnoreMozBrowser) {
if (aBrowserFlag == MozBrowser) {
_retval.Append('t');
}
else {
_retval.Append('f');
}
_retval.Append('+');
}
return;
}
#ifdef DEBUG
if (aAppId != nsIScriptSecurityManager::NO_APP_ID ||
aBrowserFlag == MozBrowser) {
nsAutoCString pattern;
GetOriginPatternString(aAppId, aBrowserFlag, EmptyCString(), pattern);
NS_ASSERTION(PatternMatchesOrigin(pattern, aOrigin),
"Origin doesn't match parameters!");
}
#endif
_retval = aOrigin;
}
void
GetOriginPatternString(uint32_t aAppId, nsAutoCString& _retval)
{
return GetOriginPatternString(aAppId, IgnoreMozBrowser, EmptyCString(),
_retval);
}
void
GetOriginPatternString(uint32_t aAppId, bool aBrowserOnly,
nsAutoCString& _retval)
{
return GetOriginPatternString(aAppId,
aBrowserOnly ? MozBrowser : NotMozBrowser,
EmptyCString(), _retval);
}
void
GetOriginPatternString(uint32_t aAppId, bool aBrowserOnly,
const nsACString& aOrigin, nsAutoCString& _retval)
{
return GetOriginPatternString(aAppId,
aBrowserOnly ? MozBrowser : NotMozBrowser,
aOrigin, _retval);
}
void
GetOriginPatternStringMaybeIgnoreBrowser(uint32_t aAppId, bool aBrowserOnly,
nsAutoCString& _retval)
{
return GetOriginPatternString(aAppId,
aBrowserOnly ? MozBrowser : IgnoreMozBrowser,
EmptyCString(), _retval);
}
template <class ValueType>
class PatternMatchArray : public nsAutoTArray<ValueType, 20>
{
typedef PatternMatchArray<ValueType> SelfType;
struct Closure
{
Closure(SelfType& aSelf, const nsACString& aPattern)
: mSelf(aSelf), mPattern(aPattern)
{ }
SelfType& mSelf;
const nsACString& mPattern;
};
public:
template <class T>
void
Find(const T& aHashtable,
const nsACString& aPattern)
{
SelfType::Clear();
Closure closure(*this, aPattern);
aHashtable.EnumerateRead(SelfType::Enumerate, &closure);
}
private:
static PLDHashOperator
Enumerate(const nsACString& aKey,
nsTArray<ValueType>* aValue,
void* aUserArg)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(!aKey.IsEmpty(), "Empty key!");
NS_ASSERTION(aValue, "Null pointer!");
NS_ASSERTION(aUserArg, "Null pointer!");
Closure* closure = static_cast<Closure*>(aUserArg);
if (PatternMatchesOrigin(closure->mPattern, aKey)) {
closure->mSelf.AppendElements(*aValue);
}
return PL_DHASH_NEXT;
}
};
typedef PatternMatchArray<IDBDatabase*> DatabasePatternMatchArray;
PLDHashOperator
InvalidateAllFileManagers(const nsACString& aKey,
nsTArray<nsRefPtr<FileManager> >* aValue,
void* aUserArg)
InvalidateAndRemoveFileManagers(
const nsACString& aKey,
nsAutoPtr<nsTArray<nsRefPtr<FileManager> > >& aValue,
void* aUserArg)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(!aKey.IsEmpty(), "Empty key!");
NS_ASSERTION(aValue, "Null pointer!");
for (uint32_t i = 0; i < aValue->Length(); i++) {
nsRefPtr<FileManager> fileManager = aValue->ElementAt(i);
fileManager->Invalidate();
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;
}
void
SanitizeOriginString(nsCString& aOrigin)
{
// We want profiles to be platform-independent so we always need to replace
// the same characters on every platform. Windows has the most extensive set
// of illegal characters so we use its FILE_ILLEGAL_CHARACTERS and
// FILE_PATH_SEPARATOR.
static const char kReplaceChars[] = CONTROL_CHARACTERS "/:*?\"<>|\\";
#ifdef XP_WIN
NS_ASSERTION(!strcmp(kReplaceChars,
FILE_ILLEGAL_CHARACTERS FILE_PATH_SEPARATOR),
"Illegal file characters have changed!");
#endif
aOrigin.ReplaceChar(kReplaceChars, '+');
}
nsresult
GetASCIIOriginFromURI(nsIURI* aURI,
uint32_t aAppId,
bool aInMozBrowser,
nsACString& aOrigin)
{
NS_ASSERTION(aURI, "Null uri!");
nsCString origin;
mozilla::GetExtendedOrigin(aURI, aAppId, aInMozBrowser, origin);
if (origin.IsEmpty()) {
NS_WARNING("GetExtendedOrigin returned empty string!");
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
aOrigin.Assign(origin);
return NS_OK;
}
nsresult
GetASCIIOriginFromPrincipal(nsIPrincipal* aPrincipal,
nsACString& aOrigin)
{
NS_ASSERTION(aPrincipal, "Don't hand me a null principal!");
static const char kChromeOrigin[] = "chrome";
nsCString origin;
if (nsContentUtils::IsSystemPrincipal(aPrincipal)) {
origin.AssignLiteral(kChromeOrigin);
}
else {
bool isNullPrincipal;
nsresult rv = aPrincipal->GetIsNullPrincipal(&isNullPrincipal);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
if (isNullPrincipal) {
NS_WARNING("IndexedDB not supported from this principal!");
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
rv = aPrincipal->GetExtendedOrigin(origin);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
if (origin.EqualsLiteral(kChromeOrigin)) {
NS_WARNING("Non-chrome principal can't use chrome origin!");
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
}
aOrigin.Assign(origin);
return NS_OK;
}
} // anonymous namespace
IndexedDatabaseManager::IndexedDatabaseManager()
@ -297,10 +513,10 @@ IndexedDatabaseManager::GetDirectoryForOrigin(const nsACString& aASCIIOrigin,
rv = directory->InitWithPath(GetBaseDirectory());
NS_ENSURE_SUCCESS(rv, rv);
NS_ConvertASCIItoUTF16 originSanitized(aASCIIOrigin);
originSanitized.ReplaceChar(":/", '+');
nsAutoCString originSanitized(aASCIIOrigin);
SanitizeOriginString(originSanitized);
rv = directory->Append(originSanitized);
rv = directory->Append(NS_ConvertASCIItoUTF16(originSanitized));
NS_ENSURE_SUCCESS(rv, rv);
directory.forget(aDirectory);
@ -406,6 +622,37 @@ IndexedDatabaseManager::FireWindowOnError(nsPIDOMWindow* aOwner,
return consoleService->LogMessage(scriptError);
}
// static
bool
IndexedDatabaseManager::OriginMatchesApp(const nsACString& aOrigin,
uint32_t aAppId)
{
NS_ASSERTION(!aOrigin.IsEmpty(), "Empty origin!");
NS_ASSERTION(aAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID,
"Bad appId!");
nsAutoCString pattern;
GetOriginPatternString(aAppId, pattern);
return PatternMatchesOrigin(pattern, aOrigin);
}
// static
bool
IndexedDatabaseManager::OriginMatchesApp(const nsACString& aOrigin,
uint32_t aAppId,
bool aInMozBrowser)
{
NS_ASSERTION(!aOrigin.IsEmpty(), "Empty origin!");
NS_ASSERTION(aAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID,
"Bad appId!");
nsAutoCString pattern;
GetOriginPatternString(aAppId, aInMozBrowser, pattern);
return PatternMatchesOrigin(pattern, aOrigin);
}
bool
IndexedDatabaseManager::RegisterDatabase(IDBDatabase* aDatabase)
{
@ -466,15 +713,16 @@ IndexedDatabaseManager::OnUsageCheckComplete(AsyncUsageRunnable* aRunnable)
}
nsresult
IndexedDatabaseManager::WaitForOpenAllowed(const nsACString& aOrigin,
nsIAtom* aId,
nsIRunnable* aRunnable)
IndexedDatabaseManager::WaitForOpenAllowed(
const OriginOrPatternString& aOriginOrPattern,
nsIAtom* aId,
nsIRunnable* aRunnable)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(!aOrigin.IsEmpty(), "Empty origin!");
NS_ASSERTION(!aOriginOrPattern.IsEmpty(), "Empty pattern!");
NS_ASSERTION(aRunnable, "Null pointer!");
nsAutoPtr<SynchronizedOp> op(new SynchronizedOp(aOrigin, aId));
nsAutoPtr<SynchronizedOp> op(new SynchronizedOp(aOriginOrPattern, aId));
// See if this runnable needs to wait.
bool delayed = false;
@ -501,16 +749,18 @@ IndexedDatabaseManager::WaitForOpenAllowed(const nsACString& aOrigin,
}
void
IndexedDatabaseManager::AllowNextSynchronizedOp(const nsACString& aOrigin,
nsIAtom* aId)
IndexedDatabaseManager::AllowNextSynchronizedOp(
const OriginOrPatternString& aOriginOrPattern,
nsIAtom* aId)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(!aOrigin.IsEmpty(), "Empty origin!");
NS_ASSERTION(!aOriginOrPattern.IsEmpty(), "Empty origin/pattern!");
uint32_t count = mSynchronizedOps.Length();
for (uint32_t index = 0; index < count; index++) {
nsAutoPtr<SynchronizedOp>& op = mSynchronizedOps[index];
if (op->mOrigin.Equals(aOrigin)) {
if (op->mOriginOrPattern.IsOrigin() == aOriginOrPattern.IsOrigin() &&
op->mOriginOrPattern == aOriginOrPattern) {
if (op->mId == aId) {
NS_ASSERTION(op->mDatabases.IsEmpty(), "How did this happen?");
@ -531,7 +781,7 @@ IndexedDatabaseManager::AllowNextSynchronizedOp(const nsACString& aOrigin,
nsresult
IndexedDatabaseManager::AcquireExclusiveAccess(
const nsACString& aOrigin,
const nsACString& aPattern,
IDBDatabase* aDatabase,
AsyncConnectionHelper* aHelper,
nsIRunnable* aRunnable,
@ -544,26 +794,26 @@ IndexedDatabaseManager::AcquireExclusiveAccess(
// Find the right SynchronizedOp.
SynchronizedOp* op =
FindSynchronizedOp(aOrigin, aDatabase ? aDatabase->Id() : nullptr);
FindSynchronizedOp(aPattern, aDatabase ? aDatabase->Id() : nullptr);
NS_ASSERTION(op, "We didn't find a SynchronizedOp?");
NS_ASSERTION(!op->mHelper, "SynchronizedOp already has a helper?!?");
NS_ASSERTION(!op->mRunnable, "SynchronizedOp already has a runnable?!?");
nsTArray<IDBDatabase*>* array;
mLiveDatabases.Get(aOrigin, &array);
DatabasePatternMatchArray matches;
matches.Find(mLiveDatabases, aPattern);
// We need to wait for the databases to go away.
// Hold on to all database objects that represent the same database file
// (except the one that is requesting this version change).
nsTArray<nsRefPtr<IDBDatabase> > liveDatabases;
if (array) {
if (!matches.IsEmpty()) {
if (aDatabase) {
// Grab all databases that are not yet closed but whose database id match
// the one we're looking for.
for (uint32_t index = 0; index < array->Length(); index++) {
IDBDatabase*& database = array->ElementAt(index);
for (uint32_t index = 0; index < matches.Length(); index++) {
IDBDatabase*& database = matches[index];
if (!database->IsClosed() &&
database != aDatabase &&
database->Id() == aDatabase->Id()) {
@ -574,7 +824,7 @@ IndexedDatabaseManager::AcquireExclusiveAccess(
else {
// We want *all* databases, even those that are closed, if we're going to
// clear the origin.
liveDatabases.AppendElements(*array);
liveDatabases.AppendElements(matches);
}
}
@ -986,18 +1236,8 @@ IndexedDatabaseManager::GetASCIIOriginFromWindow(nsPIDOMWindow* aWindow,
nsCOMPtr<nsIPrincipal> principal = sop->GetPrincipal();
NS_ENSURE_TRUE(principal, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
if (nsContentUtils::IsSystemPrincipal(principal)) {
aASCIIOrigin.AssignLiteral("chrome");
}
else {
nsresult rv = principal->GetExtendedOrigin(aASCIIOrigin);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
if (aASCIIOrigin.EqualsLiteral("null")) {
NS_WARNING("IndexedDB databases not allowed for this principal!");
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
}
nsresult rv = GetASCIIOriginFromPrincipal(principal, aASCIIOrigin);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
@ -1053,17 +1293,12 @@ IndexedDatabaseManager::AddFileManager(const nsACString& aOrigin,
}
void
IndexedDatabaseManager::InvalidateFileManagersForOrigin(
const nsACString& aOrigin)
IndexedDatabaseManager::InvalidateFileManagersForPattern(
const nsACString& aPattern)
{
nsTArray<nsRefPtr<FileManager> >* array;
if (mFileManagers.Get(aOrigin, &array)) {
for (uint32_t i = 0; i < array->Length(); i++) {
nsRefPtr<FileManager> fileManager = array->ElementAt(i);
fileManager->Invalidate();
}
mFileManagers.Remove(aOrigin);
}
NS_ASSERTION(!aPattern.IsEmpty(), "Empty pattern!");
mFileManagers.Enumerate(InvalidateAndRemoveFileManagers,
const_cast<nsACString*>(&aPattern));
}
void
@ -1173,39 +1408,103 @@ IndexedDatabaseManager::RunSynchronizedOp(IDBDatabase* aDatabase,
return NS_OK;
}
IndexedDatabaseManager::SynchronizedOp*
IndexedDatabaseManager::FindSynchronizedOp(const nsACString& aPattern,
nsIAtom* aId)
{
for (uint32_t index = 0; index < mSynchronizedOps.Length(); index++) {
const nsAutoPtr<SynchronizedOp>& currentOp = mSynchronizedOps[index];
if (PatternMatchesOrigin(aPattern, currentOp->mOriginOrPattern) &&
(!currentOp->mId || currentOp->mId == aId)) {
return currentOp;
}
}
return nullptr;
}
nsresult
IndexedDatabaseManager::ClearDatabasesForApp(uint32_t aAppId, bool aBrowserOnly)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(aAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID,
"Bad appId!");
// This only works from the main process.
NS_ENSURE_TRUE(IsMainProcess(), NS_ERROR_NOT_AVAILABLE);
nsAutoCString pattern;
GetOriginPatternStringMaybeIgnoreBrowser(aAppId, aBrowserOnly, pattern);
// If there is a pending or running clear operation for this app, return
// immediately.
if (IsClearOriginPending(pattern)) {
return NS_OK;
}
OriginOrPatternString oops = OriginOrPatternString::FromPattern(pattern);
// Queue up the origin clear runnable.
nsRefPtr<OriginClearRunnable> runnable = new OriginClearRunnable(oops);
nsresult rv = WaitForOpenAllowed(oops, nullptr, runnable);
NS_ENSURE_SUCCESS(rv, rv);
runnable->AdvanceState();
// Give the runnable some help by invalidating any databases in the way.
DatabasePatternMatchArray matches;
matches.Find(mLiveDatabases, pattern);
for (uint32_t index = 0; index < matches.Length(); index++) {
// We need to grab references here to prevent the database from dying while
// we invalidate it.
nsRefPtr<IDBDatabase> database = matches[index];
database->Invalidate();
}
return NS_OK;
}
NS_IMPL_ISUPPORTS2(IndexedDatabaseManager, nsIIndexedDatabaseManager,
nsIObserver)
NS_IMETHODIMP
IndexedDatabaseManager::GetUsageForURI(
nsIURI* aURI,
nsIIndexedDatabaseUsageCallback* aCallback)
nsIIndexedDatabaseUsageCallback* aCallback,
uint32_t aAppId,
bool aInMozBrowserOnly,
uint8_t aOptionalArgCount)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ENSURE_ARG_POINTER(aURI);
NS_ENSURE_ARG_POINTER(aCallback);
// This only works from the main process.
NS_ENSURE_TRUE(IsMainProcess(), NS_ERROR_NOT_AVAILABLE);
if (!aOptionalArgCount) {
aAppId = nsIScriptSecurityManager::NO_APP_ID;
}
// Figure out which origin we're dealing with.
nsCString origin;
nsresult rv = nsContentUtils::GetASCIIOrigin(aURI, origin);
nsresult rv = GetASCIIOriginFromURI(aURI, aAppId, aInMozBrowserOnly, origin);
NS_ENSURE_SUCCESS(rv, rv);
OriginOrPatternString oops = OriginOrPatternString::FromOrigin(origin);
nsRefPtr<AsyncUsageRunnable> runnable =
new AsyncUsageRunnable(aURI, origin, aCallback);
new AsyncUsageRunnable(aAppId, aInMozBrowserOnly, oops, aURI, aCallback);
nsRefPtr<AsyncUsageRunnable>* newRunnable =
mUsageRunnables.AppendElement(runnable);
NS_ENSURE_TRUE(newRunnable, NS_ERROR_OUT_OF_MEMORY);
// Non-standard URIs can't create databases anyway so fire the callback
// immediately.
if (origin.EqualsLiteral("null")) {
return runnable->TakeShortcut();
}
// Otherwise put the computation runnable in the queue.
rv = WaitForOpenAllowed(origin, nullptr, runnable);
rv = WaitForOpenAllowed(oops, nullptr, runnable);
NS_ENSURE_SUCCESS(rv, rv);
runnable->AdvanceState();
@ -1216,77 +1515,95 @@ IndexedDatabaseManager::GetUsageForURI(
NS_IMETHODIMP
IndexedDatabaseManager::CancelGetUsageForURI(
nsIURI* aURI,
nsIIndexedDatabaseUsageCallback* aCallback)
nsIIndexedDatabaseUsageCallback* aCallback,
uint32_t aAppId,
bool aInMozBrowserOnly,
uint8_t aOptionalArgCount)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ENSURE_ARG_POINTER(aURI);
NS_ENSURE_ARG_POINTER(aCallback);
// This only works from the main process.
NS_ENSURE_TRUE(IsMainProcess(), NS_ERROR_NOT_AVAILABLE);
if (!aOptionalArgCount) {
aAppId = nsIScriptSecurityManager::NO_APP_ID;
}
// See if one of our pending callbacks matches both the URI and the callback
// given. Cancel an remove it if so.
for (uint32_t index = 0; index < mUsageRunnables.Length(); index++) {
nsRefPtr<AsyncUsageRunnable>& runnable = mUsageRunnables[index];
bool equals;
nsresult rv = runnable->mURI->Equals(aURI, &equals);
NS_ENSURE_SUCCESS(rv, rv);
if (runnable->mAppId == aAppId &&
runnable->mInMozBrowserOnly == aInMozBrowserOnly) {
bool equals;
nsresult rv = runnable->mURI->Equals(aURI, &equals);
NS_ENSURE_SUCCESS(rv, rv);
if (equals && SameCOMIdentity(aCallback, runnable->mCallback)) {
runnable->Cancel();
break;
if (equals && SameCOMIdentity(aCallback, runnable->mCallback)) {
runnable->Cancel();
break;
}
}
}
return NS_OK;
}
NS_IMETHODIMP
IndexedDatabaseManager::ClearDatabasesForURI(nsIURI* aURI)
IndexedDatabaseManager::ClearDatabasesForURI(nsIURI* aURI,
uint32_t aAppId,
bool aInMozBrowserOnly,
uint8_t aOptionalArgCount)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ENSURE_ARG_POINTER(aURI);
// This only works from the main process.
NS_ENSURE_TRUE(IsMainProcess(), NS_ERROR_NOT_AVAILABLE);
if (!aOptionalArgCount) {
aAppId = nsIScriptSecurityManager::NO_APP_ID;
}
// Figure out which origin we're dealing with.
nsCString origin;
nsresult rv = nsContentUtils::GetASCIIOrigin(aURI, origin);
nsresult rv = GetASCIIOriginFromURI(aURI, aAppId, aInMozBrowserOnly, origin);
NS_ENSURE_SUCCESS(rv, rv);
// Non-standard URIs can't create databases anyway, so return immediately.
if (origin.EqualsLiteral("null")) {
return NS_OK;
}
nsAutoCString pattern;
GetOriginPatternString(aAppId, aInMozBrowserOnly, origin, pattern);
// If there is a pending or running clear operation for this origin, return
// immediately.
if (IsClearOriginPending(origin)) {
if (IsClearOriginPending(pattern)) {
return NS_OK;
}
// Queue up the origin clear runnable.
nsRefPtr<OriginClearRunnable> runnable = new OriginClearRunnable(origin);
OriginOrPatternString oops = OriginOrPatternString::FromPattern(pattern);
rv = WaitForOpenAllowed(origin, nullptr, runnable);
// Queue up the origin clear runnable.
nsRefPtr<OriginClearRunnable> runnable = new OriginClearRunnable(oops);
rv = WaitForOpenAllowed(oops, nullptr, runnable);
NS_ENSURE_SUCCESS(rv, rv);
runnable->AdvanceState();
// Give the runnable some help by invalidating any databases in the way. We
// need to grab references to any live databases here to prevent them from
// dying while we invalidate them.
nsTArray<nsRefPtr<IDBDatabase> > liveDatabases;
// Give the runnable some help by invalidating any databases in the way.
DatabasePatternMatchArray matches;
matches.Find(mLiveDatabases, pattern);
nsTArray<IDBDatabase*>* array;
if (mLiveDatabases.Get(origin, &array)) {
liveDatabases.AppendElements(*array);
for (uint32_t index = 0; index < matches.Length(); index++) {
// We need to grab references to any live databases here to prevent them
// from dying while we invalidate them.
nsRefPtr<IDBDatabase> database = matches[index];
database->Invalidate();
}
for (uint32_t index = 0; index < liveDatabases.Length(); index++) {
liveDatabases[index]->Invalidate();
}
DatabaseInfo::RemoveAllForOrigin(origin);
// After everything has been invalidated the helper should be dispatched to
// the end of the event queue.
return NS_OK;
@ -1361,7 +1678,7 @@ IndexedDatabaseManager::Observe(nsISupports* aSubject,
}
}
mFileManagers.EnumerateRead(InvalidateAllFileManagers, nullptr);
mFileManagers.Enumerate(InvalidateAndRemoveFileManagers, nullptr);
if (PR_ATOMIC_SET(&gClosed, 1)) {
NS_ERROR("Close more than once?!");
@ -1392,6 +1709,25 @@ IndexedDatabaseManager::Observe(nsISupports* aSubject,
return NS_OK;
}
if (!strcmp(aTopic, TOPIC_WEB_APP_CLEAR_DATA)) {
nsCOMPtr<mozIApplicationClearPrivateDataParams> params =
do_QueryInterface(aSubject);
NS_ENSURE_TRUE(params, NS_ERROR_UNEXPECTED);
uint32_t appId;
nsresult rv = params->GetAppId(&appId);
NS_ENSURE_SUCCESS(rv, rv);
bool browserOnly;
rv = params->GetBrowserOnly(&browserOnly);
NS_ENSURE_SUCCESS(rv, rv);
rv = ClearDatabasesForApp(appId, browserOnly);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_NOTREACHED("Unknown topic!");
return NS_ERROR_UNEXPECTED;
}
@ -1408,16 +1744,75 @@ OriginClearRunnable::InvalidateOpenedDatabases(
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
OriginClearRunnable* self = static_cast<OriginClearRunnable*>(aClosure);
nsTArray<nsRefPtr<IDBDatabase> > databases;
databases.SwapElements(aDatabases);
for (uint32_t index = 0; index < databases.Length(); index++) {
databases[index]->Invalidate();
}
}
DatabaseInfo::RemoveAllForOrigin(self->mOrigin);
void
IndexedDatabaseManager::
OriginClearRunnable::DeleteFiles(IndexedDatabaseManager* aManager)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(aManager, "Don't pass me null!");
nsresult rv;
nsCOMPtr<nsIFile> directory =
do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
NS_ENSURE_SUCCESS_VOID(rv);
rv = directory->InitWithPath(aManager->GetBaseDirectory());
NS_ENSURE_SUCCESS_VOID(rv);
nsCOMPtr<nsISimpleEnumerator> entries;
rv = directory->GetDirectoryEntries(getter_AddRefs(entries));
NS_ENSURE_SUCCESS_VOID(rv);
if (!entries) {
return;
}
nsCString originSanitized(mOriginOrPattern);
SanitizeOriginString(originSanitized);
bool hasMore;
while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) && hasMore) {
nsCOMPtr<nsISupports> entry;
rv = entries->GetNext(getter_AddRefs(entry));
NS_ENSURE_SUCCESS_VOID(rv);
nsCOMPtr<nsIFile> file = do_QueryInterface(entry);
NS_ASSERTION(file, "Don't know what this is!");
bool isDirectory;
rv = file->IsDirectory(&isDirectory);
NS_ENSURE_SUCCESS_VOID(rv);
if (!isDirectory) {
NS_WARNING("Something in the IndexedDB directory that doesn't belong!");
continue;
}
nsString leafName;
rv = file->GetLeafName(leafName);
NS_ENSURE_SUCCESS_VOID(rv);
// Skip databases for other apps.
if (!PatternMatchesOrigin(originSanitized,
NS_ConvertUTF16toUTF8(leafName))) {
continue;
}
if (NS_FAILED(file->Remove(true))) {
// This should never fail if we've closed all database connections
// correctly...
NS_ERROR("Failed to remove directory!");
}
}
}
NS_IMETHODIMP
@ -1439,9 +1834,9 @@ IndexedDatabaseManager::OriginClearRunnable::Run()
// Now we have to wait until the thread pool is done with all of the
// databases we care about.
nsresult rv =
mgr->AcquireExclusiveAccess(mOrigin, this, InvalidateOpenedDatabases,
this);
nsresult rv = mgr->AcquireExclusiveAccess(mOriginOrPattern, this,
InvalidateOpenedDatabases,
nullptr);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
@ -1452,24 +1847,7 @@ IndexedDatabaseManager::OriginClearRunnable::Run()
AdvanceState();
// Remove the directory that contains all our databases.
nsCOMPtr<nsIFile> directory;
nsresult rv =
mgr->GetDirectoryForOrigin(mOrigin, getter_AddRefs(directory));
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Failed to get directory to remove!");
if (NS_SUCCEEDED(rv)) {
bool exists;
rv = directory->Exists(&exists);
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
"Failed to check that the directory exists!");
if (NS_SUCCEEDED(rv) && exists && NS_FAILED(directory->Remove(true))) {
// This should never fail if we've closed all database connections
// correctly...
NS_ERROR("Failed to remove directory!");
}
}
DeleteFiles(mgr);
// Now dispatch back to the main thread.
if (NS_FAILED(NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL))) {
@ -1483,10 +1861,10 @@ IndexedDatabaseManager::OriginClearRunnable::Run()
case Complete: {
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
mgr->InvalidateFileManagersForOrigin(mOrigin);
mgr->InvalidateFileManagersForPattern(mOriginOrPattern);
// Tell the IndexedDatabaseManager that we're done.
mgr->AllowNextSynchronizedOp(mOrigin, nullptr);
mgr->AllowNextSynchronizedOp(mOriginOrPattern, nullptr);
return NS_OK;
}
@ -1501,19 +1879,24 @@ IndexedDatabaseManager::OriginClearRunnable::Run()
}
IndexedDatabaseManager::AsyncUsageRunnable::AsyncUsageRunnable(
uint32_t aAppId,
bool aInMozBrowserOnly,
const OriginOrPatternString& aOrigin,
nsIURI* aURI,
const nsACString& aOrigin,
nsIIndexedDatabaseUsageCallback* aCallback)
: mURI(aURI),
mOrigin(aOrigin),
mCallback(aCallback),
mUsage(0),
mFileUsage(0),
mAppId(aAppId),
mCanceled(0),
mCallbackState(Pending)
mOrigin(aOrigin),
mCallbackState(Pending),
mInMozBrowserOnly(aInMozBrowserOnly)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(aURI, "Null pointer!");
NS_ASSERTION(aOrigin.IsOrigin(), "Expect origin only here!");
NS_ASSERTION(!aOrigin.IsEmpty(), "Empty origin!");
NS_ASSERTION(aCallback, "Null pointer!");
}
@ -1612,7 +1995,8 @@ IndexedDatabaseManager::AsyncUsageRunnable::RunInternal()
if (!mCanceled) {
uint64_t usage = mUsage;
IncrementUsage(&usage, mFileUsage);
mCallback->OnUsageResult(mURI, usage, mFileUsage);
mCallback->OnUsageResult(mURI, usage, mFileUsage, mAppId,
mInMozBrowserOnly);
}
// Clean up.
@ -1779,9 +2163,9 @@ IndexedDatabaseManager::WaitForLockedFilesToFinishRunnable::Run()
}
IndexedDatabaseManager::
SynchronizedOp::SynchronizedOp(const nsACString& aOrigin,
SynchronizedOp::SynchronizedOp(const OriginOrPatternString& aOriginOrPattern,
nsIAtom* aId)
: mOrigin(aOrigin), mId(aId)
: mOriginOrPattern(aOriginOrPattern), mId(aId)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
MOZ_COUNT_CTOR(IndexedDatabaseManager::SynchronizedOp);
@ -1794,24 +2178,42 @@ IndexedDatabaseManager::SynchronizedOp::~SynchronizedOp()
}
bool
IndexedDatabaseManager::SynchronizedOp::MustWaitFor(const SynchronizedOp& aRhs)
const
IndexedDatabaseManager::
SynchronizedOp::MustWaitFor(const SynchronizedOp& aExistingOp)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
bool match;
if (aExistingOp.mOriginOrPattern.IsOrigin()) {
if (mOriginOrPattern.IsOrigin()) {
match = aExistingOp.mOriginOrPattern.Equals(mOriginOrPattern);
}
else {
match = PatternMatchesOrigin(mOriginOrPattern, aExistingOp.mOriginOrPattern);
}
}
else if (mOriginOrPattern.IsOrigin()) {
match = PatternMatchesOrigin(aExistingOp.mOriginOrPattern, mOriginOrPattern);
}
else {
match = PatternMatchesOrigin(mOriginOrPattern, aExistingOp.mOriginOrPattern) ||
PatternMatchesOrigin(aExistingOp.mOriginOrPattern, mOriginOrPattern);
}
// If the origins don't match, the second can proceed.
if (!aRhs.mOrigin.Equals(mOrigin)) {
if (!match) {
return false;
}
// If the origins and the ids match, the second must wait.
if (aRhs.mId == mId) {
if (aExistingOp.mId == mId) {
return true;
}
// Waiting is required if either one corresponds to an origin clearing
// (a null Id).
if (!aRhs.mId || !mId) {
if (!aExistingOp.mId || !mId) {
return true;
}

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

@ -57,11 +57,11 @@ public:
// Waits for databases to be cleared and for version change transactions to
// complete before dispatching the given runnable.
nsresult WaitForOpenAllowed(const nsACString& aOrigin,
nsresult WaitForOpenAllowed(const OriginOrPatternString& aOriginOrPattern,
nsIAtom* aId,
nsIRunnable* aRunnable);
void AllowNextSynchronizedOp(const nsACString& aOrigin,
void AllowNextSynchronizedOp(const OriginOrPatternString& aOriginOrPattern,
nsIAtom* aId);
nsIThread* IOThread()
@ -169,7 +169,7 @@ public:
const nsAString& aDatabaseName,
FileManager* aFileManager);
void InvalidateFileManagersForOrigin(const nsACString& aOrigin);
void InvalidateFileManagersForPattern(const nsACString& aPattern);
void InvalidateFileManager(const nsACString& aOrigin,
const nsAString& aDatabaseName);
@ -200,7 +200,18 @@ public:
const nsAString& aName);
static nsresult
FireWindowOnError(nsPIDOMWindow* aOwner, nsEventChainPostVisitor& aVisitor);
FireWindowOnError(nsPIDOMWindow* aOwner,
nsEventChainPostVisitor& aVisitor);
static bool
OriginMatchesApp(const nsACString& aOrigin,
uint32_t aAppId);
static bool
OriginMatchesApp(const nsACString& aOrigin,
uint32_t aAppId,
bool aInMozBrowser);
private:
IndexedDatabaseManager();
~IndexedDatabaseManager();
@ -225,6 +236,8 @@ private:
// Called when a database has been closed.
void OnDatabaseClosed(IDBDatabase* aDatabase);
nsresult ClearDatabasesForApp(uint32_t aAppId, bool aBrowserOnly);
// Responsible for clearing the database files for a particular origin on the
// IO thread. Created when nsIIDBIndexedDatabaseManager::ClearDatabasesForURI
// is called. Runs three times, first on the main thread, next on the IO
@ -253,8 +266,8 @@ private:
NS_DECL_ISUPPORTS
NS_DECL_NSIRUNNABLE
OriginClearRunnable(const nsACString& aOrigin)
: mOrigin(aOrigin),
OriginClearRunnable(const OriginOrPatternString& aOriginOrPattern)
: mOriginOrPattern(aOriginOrPattern),
mCallbackState(Pending)
{ }
@ -279,8 +292,10 @@ private:
nsTArray<nsRefPtr<IDBDatabase> >& aDatabases,
void* aClosure);
void DeleteFiles(IndexedDatabaseManager* aManager);
private:
nsCString mOrigin;
OriginOrPatternString mOriginOrPattern;
CallbackState mCallbackState;
};
@ -311,12 +326,15 @@ private:
// Running on the main thread after skipping the work
Shortcut
};
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIRUNNABLE
AsyncUsageRunnable(nsIURI* aURI,
const nsACString& aOrigin,
AsyncUsageRunnable(uint32_t aAppId,
bool aInMozBrowserOnly,
const OriginOrPatternString& aOrigin,
nsIURI* aURI,
nsIIndexedDatabaseUsageCallback* aCallback);
// Sets the canceled flag so that the callback is never called.
@ -349,13 +367,14 @@ private:
uint64_t* aUsage);
nsCOMPtr<nsIURI> mURI;
nsCString mOrigin;
nsCOMPtr<nsIIndexedDatabaseUsageCallback> mCallback;
uint64_t mUsage;
uint64_t mFileUsage;
uint32_t mAppId;
int32_t mCanceled;
OriginOrPatternString mOrigin;
CallbackState mCallbackState;
bool mInMozBrowserOnly;
};
// Called when AsyncUsageRunnable has finished its Run() method.
@ -366,16 +385,17 @@ private:
// clearing dbs for an origin, etc).
struct SynchronizedOp
{
SynchronizedOp(const nsACString& aOrigin, nsIAtom* aId);
SynchronizedOp(const OriginOrPatternString& aOriginOrPattern,
nsIAtom* aId);
~SynchronizedOp();
// Test whether the second SynchronizedOp needs to get behind this one.
bool MustWaitFor(const SynchronizedOp& aRhs) const;
// Test whether this SynchronizedOp needs to wait for the given op.
bool MustWaitFor(const SynchronizedOp& aOp);
void DelayRunnable(nsIRunnable* aRunnable);
void DispatchDelayedRunnables();
const nsCString mOrigin;
const OriginOrPatternString mOriginOrPattern;
nsCOMPtr<nsIAtom> mId;
nsRefPtr<AsyncConnectionHelper> mHelper;
nsCOMPtr<nsIRunnable> mRunnable;
@ -442,22 +462,12 @@ private:
static nsresult RunSynchronizedOp(IDBDatabase* aDatabase,
SynchronizedOp* aOp);
SynchronizedOp* FindSynchronizedOp(const nsACString& aOrigin,
nsIAtom* aId)
{
for (uint32_t index = 0; index < mSynchronizedOps.Length(); index++) {
const nsAutoPtr<SynchronizedOp>& currentOp = mSynchronizedOps[index];
if (currentOp->mOrigin == aOrigin &&
(!currentOp->mId || currentOp->mId == aId)) {
return currentOp;
}
}
return nullptr;
}
SynchronizedOp* FindSynchronizedOp(const nsACString& aPattern,
nsIAtom* aId);
bool IsClearOriginPending(const nsACString& aOrigin)
bool IsClearOriginPending(const nsACString& aPattern)
{
return !!FindSynchronizedOp(aOrigin, nullptr);
return !!FindSynchronizedOp(aPattern, nullptr);
}
// Maintains a list of live databases per origin.

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

@ -66,12 +66,13 @@ EXPORTS_mozilla/dom/indexedDB = \
$(NULL)
LOCAL_INCLUDES = \
-I$(topsrcdir)/db/sqlite3/src \
-I$(topsrcdir)/xpcom/build \
-I$(topsrcdir)/dom/base \
-I$(topsrcdir)/dom/src/storage \
-I$(topsrcdir)/caps/include \
-I$(topsrcdir)/content/base/src \
-I$(topsrcdir)/content/events/src \
-I$(topsrcdir)/db/sqlite3/src \
-I$(topsrcdir)/dom/base \
-I$(topsrcdir)/dom/src/storage \
-I$(topsrcdir)/xpcom/build \
$(NULL)
DEFINES += -D_IMPL_NS_LAYOUT

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

@ -2018,7 +2018,9 @@ OpenDatabaseHelper::Run()
IndexedDatabaseManager* manager = IndexedDatabaseManager::Get();
NS_ASSERTION(manager, "This should never be null!");
manager->AllowNextSynchronizedOp(mASCIIOrigin, mDatabaseId);
manager->AllowNextSynchronizedOp(
OriginOrPatternString::FromOrigin(mASCIIOrigin),
mDatabaseId);
ReleaseMainThreadObjects();

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

@ -434,6 +434,15 @@ IndexedDBDatabaseChild::RecvVersionChange(const uint64_t& aOldVersion,
return true;
}
bool
IndexedDBDatabaseChild::RecvInvalidate()
{
if (mDatabase) {
mDatabase->Invalidate();
}
return true;
}
bool
IndexedDBDatabaseChild::RecvPIndexedDBTransactionConstructor(
PIndexedDBTransactionChild* aActor,
@ -584,9 +593,30 @@ IndexedDBTransactionChild::ActorDestroy(ActorDestroyReason aWhy)
}
bool
IndexedDBTransactionChild::RecvComplete(const nsresult& aRv)
IndexedDBTransactionChild::RecvComplete(const CompleteParams& aParams)
{
FireCompleteEvent(aRv);
MOZ_ASSERT(mTransaction);
MOZ_ASSERT(mStrongTransaction);
nsresult resultCode;
switch (aParams.type()) {
case CompleteParams::TCompleteResult:
resultCode = NS_OK;
break;
case CompleteParams::TAbortResult:
resultCode = aParams.get_AbortResult().errorCode();
if (NS_SUCCEEDED(resultCode)) {
resultCode = NS_ERROR_DOM_INDEXEDDB_ABORT_ERR;
}
break;
default:
MOZ_NOT_REACHED("Unknown union type!");
return false;
}
FireCompleteEvent(resultCode);
return true;
}

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

@ -119,6 +119,9 @@ protected:
RecvVersionChange(const uint64_t& aOldVersion, const uint64_t& aNewVersion)
MOZ_OVERRIDE;
virtual bool
RecvInvalidate() MOZ_OVERRIDE;
virtual bool
RecvPIndexedDBTransactionConstructor(PIndexedDBTransactionChild* aActor,
const TransactionParams& aParams)
@ -163,7 +166,7 @@ protected:
ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
virtual bool
RecvComplete(const nsresult& aRv) MOZ_OVERRIDE;
RecvComplete(const CompleteParams& aParams) MOZ_OVERRIDE;
virtual PIndexedDBObjectStoreChild*
AllocPIndexedDBObjectStore(const ObjectStoreConstructorParams& aParams)

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

@ -355,7 +355,11 @@ IndexedDBDatabaseParent::HandleRequestEvent(nsIDOMEvent* aEvent,
}
MOZ_ASSERT(!mDatabase || mDatabase == databaseConcrete);
mDatabase = databaseConcrete;
if (!mDatabase) {
databaseConcrete->SetActor(this);
mDatabase = databaseConcrete;
}
return NS_OK;
}
@ -390,6 +394,7 @@ IndexedDBDatabaseParent::HandleRequestEvent(nsIDOMEvent* aEvent,
return NS_ERROR_FAILURE;
}
databaseConcrete->SetActor(this);
mDatabase = databaseConcrete;
return NS_OK;
@ -555,10 +560,10 @@ IndexedDBTransactionParent::HandleEvent(nsIDOMEvent* aEvent)
nsresult rv = aEvent->GetType(type);
NS_ENSURE_SUCCESS(rv, rv);
nsresult transactionResult;
CompleteParams params;
if (type.EqualsLiteral(COMPLETE_EVT_STR)) {
transactionResult = NS_OK;
params = CompleteResult();
}
else if (type.EqualsLiteral(ABORT_EVT_STR)) {
#ifdef DEBUG
@ -573,15 +578,14 @@ IndexedDBTransactionParent::HandleEvent(nsIDOMEvent* aEvent)
}
}
#endif
MOZ_ASSERT(NS_FAILED(mTransaction->GetAbortCode()));
transactionResult = mTransaction->GetAbortCode();
params = AbortResult(mTransaction->GetAbortCode());
}
else {
NS_WARNING("Unknown message type!");
return NS_ERROR_UNEXPECTED;
}
if (!SendComplete(transactionResult)) {
if (!SendComplete(params)) {
return NS_ERROR_FAILURE;
}

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

@ -58,6 +58,8 @@ child:
VersionChange(uint64_t oldVersion, uint64_t newVersion);
Invalidate();
both:
PIndexedDBTransaction(TransactionParams params);
};

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

@ -31,6 +31,20 @@ union ObjectStoreConstructorParams
GetObjectStoreParams;
};
struct CompleteResult
{ };
struct AbortResult
{
nsresult errorCode;
};
union CompleteParams
{
CompleteResult;
AbortResult;
};
} // namespace ipc
protocol PIndexedDBTransaction
@ -51,7 +65,7 @@ parent:
DeleteObjectStore(nsString name);
child:
Complete(nsresult rv);
Complete(CompleteParams params);
};
} // namespace indexedDB

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

@ -8,18 +8,17 @@
interface nsIURI;
[scriptable, function, uuid(ef1795ec-7050-4658-b80f-0e48cbe1d64b)]
[scriptable, function, uuid(38f15cc7-2df0-4a90-8b7f-1606b2243522)]
interface nsIIndexedDatabaseUsageCallback : nsISupports
{
/**
*
*/
void onUsageResult(in nsIURI aURI,
in unsigned long long aUsage,
in unsigned long long aFileUsage);
in unsigned long long aFileUsage,
in unsigned long aAppId,
in boolean aInMozBrowserOnly);
};
[scriptable, builtinclass, uuid(02256aa7-70d8-473f-bf3b-8cb35d28fd75)]
[scriptable, builtinclass, uuid(e5168115-baff-4559-887e-7c0405cc9e63)]
interface nsIIndexedDatabaseManager : nsISupports
{
/**
@ -31,8 +30,11 @@ interface nsIIndexedDatabaseManager : nsISupports
* @param aCallback
* The callback that will be called when the usage is available.
*/
[optional_argc]
void getUsageForURI(in nsIURI aURI,
in nsIIndexedDatabaseUsageCallback aCallback);
in nsIIndexedDatabaseUsageCallback aCallback,
[optional] in unsigned long aAppId,
[optional] in boolean aInMozBrowserOnly);
/**
* Cancels an asynchronous usage check initiated by a previous call to
@ -43,9 +45,11 @@ interface nsIIndexedDatabaseManager : nsISupports
* @param aCallback
* The callback that will be called when the usage is available.
*/
[optional_argc]
void cancelGetUsageForURI(in nsIURI aURI,
in nsIIndexedDatabaseUsageCallback aCallback);
in nsIIndexedDatabaseUsageCallback aCallback,
[optional] in unsigned long aAppId,
[optional] in boolean aInMozBrowserOnly);
/**
* Removes all databases stored for the given URI. The files may not be
@ -54,7 +58,10 @@ interface nsIIndexedDatabaseManager : nsISupports
* @param aURI
* The URI whose databases are to be cleared.
*/
void clearDatabasesForURI(in nsIURI aURI);
[optional_argc]
void clearDatabasesForURI(in nsIURI aURI,
[optional] in unsigned long aAppId,
[optional] in boolean aInMozBrowserOnly);
/**
* Defines indexedDB and IDBKeyrange with its static functions on

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

@ -21,6 +21,8 @@ MOCHITEST_FILES = \
event_propagation_iframe.html \
exceptions_in_events_iframe.html \
file.js \
file_app_isolation.html \
file_app_isolation.js \
helpers.js \
leaving_page_iframe.html \
test_add_put.html \
@ -100,12 +102,13 @@ MOCHITEST_FILES = \
test_setVersion_events.html \
test_setVersion_exclusion.html \
test_unique_index_update.html \
test_webapp_clearBrowserData.html \
third_party_iframe1.html \
third_party_iframe2.html \
test_app_isolation_inproc.html \
test_app_isolation_oop.html \
file_app_isolation.html \
file_app_isolation.js \
webapp_clearBrowserData_appFrame.html \
webapp_clearBrowserData_browserFrame.html \
$(NULL)
# test_writer_starvation.html disabled for infinite loops, bug 595368

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

@ -0,0 +1,137 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html>
<head>
<title>Indexed Database Clear Browser Data 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">
"use strict";
const appDomain = "example.org";
const manifestURL =
location.protocol + "//" + appDomain + "/manifest.webapp";
function testSteps()
{
const objectStoreName = "foo";
const testKey = 1;
const testValue = objectStoreName;
let request = indexedDB.open(window.location.pathname, 1);
request.onerror = errorHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
request.onsuccess = unexpectedSuccessHandler;
let event = yield;
let db = event.target.result;
db.onerror = errorHandler;
db.onversionchange = function(event) {
event.target.close();
}
let objectStore = db.createObjectStore(objectStoreName);
objectStore.add(testValue, testKey);
request.onsuccess = grabEventAndContinueHandler;
event = yield;
let srcURL =
location.protocol + "//" + appDomain +
location.pathname.replace("test_webapp_clearBrowserData.html",
"webapp_clearBrowserData_appFrame.html");
let iframe = document.createElement("iframe");
iframe.setAttribute("mozbrowser", "");
iframe.setAttribute("mozapp", manifestURL);
iframe.setAttribute("src", srcURL);
iframe.setAttribute("remote", "true");
iframe.addEventListener("mozbrowsershowmodalprompt", function(event) {
let message = JSON.parse(event.detail.message);
switch (message.type) {
case "info":
case "ok":
window[message.type].apply(window, message.args);
break;
case "done":
continueToNextStepSync();
break;
default:
throw "unknown message";
}
});
info("loading app frame");
document.body.appendChild(iframe);
yield;
request = indexedDB.open(window.location.pathname, 1);
request.onerror = errorHandler;
request.onupgradeneeded = unexpectedSuccessHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
db = event.target.result;
db.onerror = errorHandler;
objectStore =
db.transaction(objectStoreName).objectStore(objectStoreName);
objectStore.get(testKey).onsuccess = grabEventAndContinueHandler;
event = yield;
ok(testValue == event.target.result, "data still exists");
finishTest();
yield;
}
function start()
{
if (!SpecialPowers.isMainProcess()) {
todo(false, "Test disabled in child processes, for now");
SimpleTest.finish();
return;
}
SpecialPowers.addPermission("browser", true, document);
SpecialPowers.addPermission("browser", true, { manifestURL: manifestURL,
isInBrowserElement: false });
SpecialPowers.addPermission("embed-apps", true, document);
let Webapps = {};
SpecialPowers.wrap(Components)
.utils.import("resource://gre/modules/Webapps.jsm", Webapps);
let appRegistry = SpecialPowers.wrap(Webapps.DOMApplicationRegistry);
let originalAllAppsLaunchable = appRegistry.allAppsLaunchable;
appRegistry.allAppsLaunchable = true;
window.addEventListener("unload", function cleanup(event) {
if (event.target == document) {
window.removeEventListener("unload", cleanup, false);
SpecialPowers.removePermission("browser", location.href);
SpecialPowers.removePermission("browser",
location.protocol + "//" + appDomain);
SpecialPowers.removePermission("embed-apps", location.href);
appRegistry.allAppsLaunchable = originalAllAppsLaunchable;
}
}, false);
SpecialPowers.pushPrefEnv({
"set": [["dom.mozBrowserFramesEnabled", true]]
}, runTest);
}
</script>
<script type="text/javascript;version=1.7" src="helpers.js"></script>
</head>
<body onload="start();"></body>
</html>

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

@ -0,0 +1,126 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html>
<head>
<title>Indexed Database Clear Browser Data Test</title>
<script type="text/javascript;version=1.7">
"use strict";
function ok(cond, message)
{
alert(JSON.stringify({ type: "ok",
args: [!!cond, "appFrame: " + message] }));
}
function info(message)
{
alert(JSON.stringify({ type: "info",
args: ["appFrame: " + message] }));
}
function finish()
{
alert(JSON.stringify({ type: "done" }));
}
window.onerror = ok.bind(window, false);
function testSteps()
{
const objectStoreName = "foo";
const testKey = 1;
const testValue = objectStoreName;
let request = indexedDB.open(window.location.pathname, 1);
request.onerror = errorHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
request.onsuccess = unexpectedSuccessHandler;
let event = yield;
let db = event.target.result;
db.onerror = errorHandler;
db.onversionchange = function(event) {
event.target.close();
}
let objectStore = db.createObjectStore(objectStoreName);
objectStore.add(testValue, testKey);
request.onsuccess = grabEventAndContinueHandler;
event = yield;
ok(db === event.target.result, "created database");
objectStore =
db.transaction(objectStoreName).objectStore(objectStoreName);
objectStore.get(testKey).onsuccess = grabEventAndContinueHandler;
event = yield;
ok(testValue == event.target.result, "data exists");
let iframe = document.createElement("iframe");
iframe.setAttribute("mozbrowser", "");
iframe.setAttribute("src", "webapp_clearBrowserData_browserFrame.html");
iframe.addEventListener("mozbrowsershowmodalprompt", function(event) {
let message = JSON.parse(event.detail.message);
switch (message.type) {
case "block":
info("blocking browserFrame");
event.preventDefault();
let request = navigator.mozApps.getSelf();
request.onsuccess = function() {
let app = request.result;
ok(app, "got app");
info("clearing browser data");
app.clearBrowserData();
info("unblocking browserFrame");
event.detail.unblock();
}
break;
case "done":
continueToNextStepSync();
break;
default:
alert(event.detail.message);
}
});
info("loading browser frame");
document.body.appendChild(iframe);
yield;
request = indexedDB.open(window.location.pathname, 1);
request.onerror = errorHandler;
request.onupgradeneeded = unexpectedSuccessHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
db = event.target.result;
db.onerror = errorHandler;
objectStore =
db.transaction(objectStoreName).objectStore(objectStoreName);
objectStore.get(testKey).onsuccess = grabEventAndContinueHandler;
event = yield;
ok(testValue == event.target.result, "data still exists");
finish();
yield;
}
</script>
<script type="text/javascript;version=1.7" src="helpers.js"></script>
</head>
<body onload="testGenerator.next();"></body>
</html>

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

@ -0,0 +1,103 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html>
<head>
<title>Indexed Database Clear Browser Data Test</title>
<script type="text/javascript;version=1.7">
"use strict";
function ok(cond, message)
{
alert(JSON.stringify({ type: "ok",
args: [!!cond, "browserFrame: " + message] }));
}
function info(message)
{
alert(JSON.stringify({ type: "info",
args: ["browserFrame: " + message] }));
}
function block()
{
info("about to block");
// This will block until the parent has cleared our database.
alert(JSON.stringify({ type: "block" }));
info("unblocked");
}
function finish()
{
alert(JSON.stringify({ type: "done" }));
}
window.onerror = ok.bind(window, false);
function testSteps()
{
const objectStoreName = "foo";
const testKey = 1;
const testValue = objectStoreName;
let request = indexedDB.open(window.location.pathname, 1);
request.onerror = errorHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
request.onsuccess = unexpectedSuccessHandler;
let event = yield;
let db = event.target.result;
db.onerror = errorHandler;
db.onversionchange = function(event) {
event.target.close();
}
let objectStore = db.createObjectStore(objectStoreName);
objectStore.add(testValue, testKey);
request.onsuccess = grabEventAndContinueHandler;
event = yield;
ok(db === event.target.result, "created database");
objectStore =
db.transaction(objectStoreName).objectStore(objectStoreName);
objectStore.get(testKey).onsuccess = grabEventAndContinueHandler;
event = yield;
ok(testValue == event.target.result, "data exists");
block();
request = indexedDB.open(window.location.pathname, 1);
request.onerror = errorHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
request.onsuccess = unexpectedSuccessHandler;
event = yield;
ok(event.type == "upgradeneeded", "db doesn't exist");
request.onsuccess = grabEventAndContinueHandler;
event = yield;
db = event.target.result;
info(db.objectStoreNames.length);
ok(!db.objectStoreNames.length, "no object stores");
finish();
yield;
}
</script>
<script type="text/javascript;version=1.7" src="helpers.js"></script>
</head>
<body onload="testGenerator.next();"></body>
</html>

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

@ -13,3 +13,7 @@ interface mozIApplicationClearPrivateDataParams : nsISupports
readonly attribute unsigned long appId;
readonly attribute boolean browserOnly;
};
%{C++
#define TOPIC_WEB_APP_CLEAR_DATA "webapps-clear-data"
%}

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

@ -884,6 +884,23 @@ TabParent::RecvPIndexedDBConstructor(PIndexedDBParent* aActor,
NS_RUNTIMEABORT("Not supported yet!");
}
nsresult rv;
// XXXbent Need to make sure we have a whitelist for chrome databases!
// Verify the appID in the origin first.
if (mApp && !aASCIIOrigin.EqualsLiteral("chrome")) {
uint32_t appId;
rv = mApp->GetLocalId(&appId);
NS_ENSURE_SUCCESS(rv, false);
if (!IndexedDatabaseManager::OriginMatchesApp(aASCIIOrigin, appId)) {
NS_WARNING("App attempted to open databases that it does not have "
"permission to access!");
return false;
}
}
nsCOMPtr<nsINode> node = do_QueryInterface(GetOwnerElement());
NS_ENSURE_TRUE(node, false);
@ -897,9 +914,8 @@ TabParent::RecvPIndexedDBConstructor(PIndexedDBParent* aActor,
NS_ASSERTION(contentParent, "Null manager?!");
nsRefPtr<IDBFactory> factory;
nsresult rv =
IDBFactory::Create(window, aASCIIOrigin, contentParent,
getter_AddRefs(factory));
rv = IDBFactory::Create(window, aASCIIOrigin, contentParent,
getter_AddRefs(factory));
NS_ENSURE_SUCCESS(rv, false);
if (!factory) {

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

@ -331,7 +331,7 @@ nsDOMStorageManager::Observe(nsISupports *aSubject,
rv = params->GetBrowserOnly(&browserOnly);
NS_ENSURE_SUCCESS(rv, rv);
MOZ_ASSERT(appId != nsIScriptSecurityManager::NO_APP_ID);
MOZ_ASSERT(appId != nsIScriptSecurityManager::UNKNOWN_APP_ID);
return DOMStorageImpl::gStorageDB->RemoveAllForApp(appId, browserOnly);
}

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

@ -91,6 +91,7 @@
#include "nsDOMStorage.h"
#include "nsJSON.h"
#include "mozilla/dom/indexedDB/IndexedDatabaseManager.h"
#include "mozIApplicationClearPrivateDataParams.h"
#include "mozilla/dom/DOMRequest.h"
#include "mozilla/OSFileConstants.h"
#include "mozilla/dom/Activity.h"
@ -1296,6 +1297,7 @@ static const mozilla::Module::CategoryEntry kLayoutCategories[] = {
{ "net-channel-event-sinks", "CSPService", CSPSERVICE_CONTRACTID },
{ JAVASCRIPT_GLOBAL_STATIC_NAMESET_CATEGORY, "PrivilegeManager", NS_SECURITYNAMESET_CONTRACTID },
{ "app-startup", "Script Security Manager", "service," NS_SCRIPTSECURITYMANAGER_CONTRACTID },
{ TOPIC_WEB_APP_CLEAR_DATA, "IndexedDatabaseManager", "service," INDEXEDDB_MANAGER_CONTRACTID },
#ifdef MOZ_WIDGET_GONK
{ "app-startup", "Volume Service", "service," NS_VOLUMESERVICE_CONTRACTID },
#endif

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

@ -1336,8 +1336,6 @@ NS_GetAppInfo(nsIChannel *aChannel, uint32_t *aAppID, bool *aIsInBrowserElement)
return true;
}
#define TOPIC_WEB_APP_CLEAR_DATA "webapps-clear-data"
/**
* Gets appId and browserOnly parameters from the TOPIC_WEB_APP_CLEAR_DATA
* nsIObserverService notification. Used when clearing user data or
@ -1359,10 +1357,9 @@ NS_GetAppInfoFromClearDataNotification(nsISupports *aSubject,
uint32_t appId;
rv = clearParams->GetAppId(&appId);
MOZ_ASSERT(NS_SUCCEEDED(rv));
MOZ_ASSERT(appId != NECKO_NO_APP_ID);
MOZ_ASSERT(appId != NECKO_UNKNOWN_APP_ID);
NS_ENSURE_SUCCESS(rv, rv);
if (appId == NECKO_NO_APP_ID || appId == NECKO_UNKNOWN_APP_ID) {
if (appId == NECKO_UNKNOWN_APP_ID) {
return NS_ERROR_UNEXPECTED;
}

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

@ -3816,8 +3816,7 @@ nsCookieService::GetCookiesForApp(uint32_t aAppId, bool aOnlyBrowserElement,
return NS_ERROR_NOT_AVAILABLE;
}
NS_ENSURE_TRUE(aAppId != NECKO_NO_APP_ID && aAppId != NECKO_UNKNOWN_APP_ID,
NS_ERROR_INVALID_ARG);
NS_ENSURE_TRUE(aAppId != NECKO_UNKNOWN_APP_ID, NS_ERROR_INVALID_ARG);
GetCookiesForAppStruct data(aAppId, aOnlyBrowserElement);
mDBState->hostTable.EnumerateEntries(GetCookiesForApp, &data);

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

@ -152,6 +152,7 @@
"dom/indexedDB/test/test_event_propagation.html": "TIMED_OUT, bug 780855",
"dom/indexedDB/test/test_app_isolation_inproc.html": "TIMED_OUT",
"dom/indexedDB/test/test_app_isolation_oop.html": "TIMED_OUT",
"dom/indexedDB/test/test_webapp_clearBrowserData.html": "No test app installed",
"dom/network/tests/test_network_basics.html": "",
"dom/permission/tests/test_permission_basics.html": "",
"dom/sms/tests/test_sms_basics.html": "",

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

@ -1194,6 +1194,19 @@ SpecialPowersAPI.prototype = {
.getService(Ci.nsIIOService)
.newURI(arg, null, null)
.spec;
} else if (arg.manifestURL) {
// It's a thing representing an app.
let tmp = {};
Components.utils.import("resource://gre/modules/Webapps.jsm", tmp);
let app = tmp.DOMApplicationRegistry.getAppByManifestURL(arg.manifestURL);
if (!app) {
throw "No app for this manifest!";
}
appId = app.localId;
url = app.origin;
isInBrowserElement = arg.isInBrowserElement || false;
} else if (arg.nodePrincipal) {
// It's a document.
url = arg.nodePrincipal.URI.spec;