author | Josh Matthews <josh@joshmatthews.net> |
Thu, 18 Nov 2010 20:15:23 -0500 | |
changeset 58092 | 4973e2b9a905c183a573097f0bf369d7fbb8e50a |
parent 58091 | cbdf3ff3e88af95430416c0043e63ee6b0359643 |
child 58093 | 43a10e7fbef398cd9d629e7cb094f01a5eb175ab |
push id | 17151 |
push user | honzab.moz@firemni.cz |
push date | Tue, 23 Nov 2010 19:38:40 +0000 |
treeherder | mozilla-central@4973e2b9a905 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | honzab, blocking-fennec2.0b3 |
bugs | 584946 |
milestone | 2.0b8pre |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/dom/ipc/ContentChild.cpp +++ b/dom/ipc/ContentChild.cpp @@ -49,16 +49,17 @@ #include "TabChild.h" #include "AudioChild.h" #include "mozilla/ipc/TestShellChild.h" #include "mozilla/net/NeckoChild.h" #include "mozilla/ipc/XPCShellEnvironment.h" #include "mozilla/jsipc/PContextWrapperChild.h" #include "mozilla/dom/ExternalHelperAppChild.h" +#include "mozilla/dom/StorageChild.h" #include "nsAudioStream.h" #include "nsIObserverService.h" #include "nsTObserverArray.h" #include "nsIObserver.h" #include "nsIPrefService.h" #include "nsServiceManagerUtils.h" @@ -335,16 +336,31 @@ ContentChild::AllocPExternalHelperApp(co bool ContentChild::DeallocPExternalHelperApp(PExternalHelperAppChild* aService) { ExternalHelperAppChild *child = static_cast<ExternalHelperAppChild*>(aService); child->Release(); return true; } +PStorageChild* +ContentChild::AllocPStorage(const StorageConstructData& aData) +{ + NS_NOTREACHED("We should never be manually allocating PStorageChild actors"); + return nsnull; +} + +bool +ContentChild::DeallocPStorage(PStorageChild* aActor) +{ + StorageChild* child = static_cast<StorageChild*>(aActor); + child->ReleaseIPDLReference(); + return true; +} + bool ContentChild::RecvRegisterChrome(const InfallibleTArray<ChromePackage>& packages, const InfallibleTArray<ResourceMapping>& resources, const InfallibleTArray<OverrideMapping>& overrides) { nsCOMPtr<nsIChromeRegistry> registrySvc = nsChromeRegistry::GetService(); nsChromeRegistryContent* chromeRegistry = static_cast<nsChromeRegistryContent*>(registrySvc.get());
--- a/dom/ipc/ContentChild.h +++ b/dom/ipc/ContentChild.h @@ -51,16 +51,17 @@ struct ResourceMapping; struct OverrideMapping; namespace mozilla { namespace dom { class AlertObserver; class PrefObserver; class ConsoleListener; +class PStorageChild; class ContentChild : public PContentChild { public: ContentChild(); virtual ~ContentChild(); bool Init(MessageLoop* aIOLoop, @@ -95,16 +96,19 @@ public: const IPC::URI& uri, const nsCString& aMimeContentType, const nsCString& aContentDisposition, const bool& aForceSave, const PRInt64& aContentLength, const IPC::URI& aReferrer); virtual bool DeallocPExternalHelperApp(PExternalHelperAppChild *aService); + virtual PStorageChild* AllocPStorage(const StorageConstructData& aData); + virtual bool DeallocPStorage(PStorageChild* aActor); + virtual bool RecvRegisterChrome(const InfallibleTArray<ChromePackage>& packages, const InfallibleTArray<ResourceMapping>& resources, const InfallibleTArray<OverrideMapping>& overrides); virtual bool RecvSetOffline(const PRBool& offline); virtual bool RecvNotifyVisited(const IPC::URI& aURI); // auto remove when alertfinished is received.
--- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -68,16 +68,17 @@ #include "nsConsoleMessage.h" #include "AudioParent.h" #ifdef MOZ_PERMISSIONS #include "nsPermissionManager.h" #endif #include "mozilla/dom/ExternalHelperAppParent.h" +#include "mozilla/dom/StorageParent.h" #include "nsAccelerometer.h" using namespace mozilla::ipc; using namespace mozilla::net; using namespace mozilla::places; using mozilla::MonitorAutoEnter; namespace mozilla { @@ -411,16 +412,29 @@ ContentParent::AllocPExternalHelperApp(c bool ContentParent::DeallocPExternalHelperApp(PExternalHelperAppParent* aService) { ExternalHelperAppParent *parent = static_cast<ExternalHelperAppParent *>(aService); parent->Release(); return true; } +PStorageParent* +ContentParent::AllocPStorage(const StorageConstructData& aData) +{ + return new StorageParent(aData); +} + +bool +ContentParent::DeallocPStorage(PStorageParent* aActor) +{ + delete aActor; + return true; +} + void ContentParent::ReportChildAlreadyBlocked() { if (!mRunToCompletionDepth) { #ifdef DEBUG printf("Running to completion...\n"); #endif mRunToCompletionDepth = 1;
--- a/dom/ipc/ContentParent.h +++ b/dom/ipc/ContentParent.h @@ -57,16 +57,17 @@ namespace mozilla { namespace ipc { class TestShellParent; } namespace dom { class TabParent; +class PStorageParent; class ContentParent : public PContentParent , public nsIObserver , public nsIThreadObserver , public nsIDOMGeoPositionCallback , public nsIAccelerationListener { private: @@ -129,16 +130,19 @@ private: const IPC::URI& uri, const nsCString& aMimeContentType, const nsCString& aContentDisposition, const bool& aForceSave, const PRInt64& aContentLength, const IPC::URI& aReferrer); virtual bool DeallocPExternalHelperApp(PExternalHelperAppParent* aService); + virtual PStorageParent* AllocPStorage(const StorageConstructData& aData); + virtual bool DeallocPStorage(PStorageParent* aActor); + virtual bool RecvReadPrefsArray(InfallibleTArray<PrefTuple> *retValue); void EnsurePrefService(); virtual bool RecvReadPermissions(InfallibleTArray<IPC::Permission>* aPermissions); virtual bool RecvStartVisitedQuery(const IPC::URI& uri);
--- a/dom/ipc/Makefile.in +++ b/dom/ipc/Makefile.in @@ -79,16 +79,17 @@ include $(topsrcdir)/config/rules.mk LOCAL_INCLUDES += \ -I$(srcdir)/../../content/base/src \ -I$(srcdir)/../../content/events/src \ -I$(srcdir)/../../toolkit/components/places/src \ -I$(topsrcdir)/chrome/src \ -I$(topsrcdir)/uriloader/exthandler \ -I$(srcdir)/../../netwerk/base/src \ -I$(srcdir)/../src/base \ + -I$(srcdir)/../src/storage \ -I$(srcdir)/../../xpcom/base \ -I$(topsrcdir)/extensions/cookie \ $(NULL) DEFINES += -DBIN_SUFFIX='"$(BIN_SUFFIX)"' ifdef MOZ_PERMISSIONS DEFINES += -DMOZ_PERMISSIONS
--- a/dom/ipc/PContent.ipdl +++ b/dom/ipc/PContent.ipdl @@ -36,42 +36,62 @@ * * ***** END LICENSE BLOCK ***** */ include protocol PAudio; include protocol PBrowser; include protocol PTestShell; include protocol PNecko; include protocol PExternalHelperApp; +include protocol PStorage; include "mozilla/chrome/RegistryMessageUtils.h"; include "mozilla/net/NeckoMessageUtils.h"; include "nsGeoPositionIPCSerialiser.h"; include "PPrefTuple.h"; using GeoPosition; using PrefTuple; using ChromePackage; using ResourceMapping; using OverrideMapping; using IPC::URI; using IPC::Permission; +using mozilla::null_t; namespace mozilla { namespace dom { +// Data required to clone an existing DOMStorageImpl in the parent +struct StorageClone +{ + // Existing cross-process storage actor to clone + PStorage actor; + // Result of calling IsCallerSecure() in the child + bool callerSecure; +}; + +// When creating a new PStorage protocol, an existing one can be +// cloned (see nsDOMStorage2::Clone) +union StorageConstructData +{ + null_t; + StorageClone; +}; + rpc protocol PContent { manages PAudio; manages PBrowser; manages PTestShell; manages PNecko; manages PExternalHelperApp; + manages PStorage; child: PBrowser(PRUint32 chromeFlags); PTestShell(); RegisterChrome(ChromePackage[] packages, ResourceMapping[] resources, OverrideMapping[] overrides); @@ -88,16 +108,18 @@ child: // nsIPermissionManager messages AddPermission(Permission permission); AccelerationChanged(double x, double y, double z); parent: PNecko(); + + PStorage(StorageConstructData data); PAudio(PRInt32 aNumChannels, PRInt32 aRate, PRInt32 aFormat); // Services remoting async StartVisitedQuery(URI uri); async VisitURI(URI uri, URI referrer, PRUint32 flags); async SetURITitle(URI uri, nsString title);
--- a/dom/src/storage/Makefile.in +++ b/dom/src/storage/Makefile.in @@ -49,20 +49,29 @@ LIBXUL_LIBRARY = 1 CPPSRCS = \ nsDOMStorage.cpp \ $(NULL) ifdef MOZ_STORAGE CPPSRCS += nsDOMStorageDBWrapper.cpp nsDOMStoragePersistentDB.cpp nsDOMStorageMemoryDB.cpp + +ifdef MOZ_IPC +CPPSRCS += StorageChild.cpp StorageParent.cpp + +EXPORTS_NAMESPACES = mozilla/dom +EXPORTS_mozilla/dom = StorageChild.h StorageParent.h +endif endif # we don't want the shared lib, but we want to force the creation of a static lib. FORCE_STATIC_LIB = 1 LOCAL_INCLUDES = \ -I$(topsrcdir)/dom/base \ -I$(topsrcdir)/content/events/src DEFINES += -D_IMPL_NS_LAYOUT +include $(topsrcdir)/config/config.mk +include $(topsrcdir)/ipc/chromium/chromium-config.mk include $(topsrcdir)/config/rules.mk
new file mode 100644 --- /dev/null +++ b/dom/src/storage/PStorage.ipdl @@ -0,0 +1,99 @@ +/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */ +/* vim: set sw=4 ts=8 et tw=80 ft=cpp : */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Content App. + * + * The Initial Developer of the Original Code is + * The Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Josh Matthews <josh@joshmatthews.net> (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +include protocol PContent; + +using mozilla::null_t; + +namespace mozilla { +namespace dom { + +struct ItemData +{ + nsString value; + PRBool secure; +}; + +// A cross-process GetValue result -- either null, or containing the parameters +// with which to initialize an nsIDOMStorageItem. +union StorageItem +{ + null_t; + ItemData; +}; + +// This protocol is little more than a thin wrapper around the DOMStorageBase +// class in nsDOMStorage.h. The child implementation simply forwards the +// arguments for any given call to the parent, and returns the result. +sync protocol PStorage +{ + manager PContent; + +parent: + __delete__(); + + Init(bool useDB, bool canUseChromePersist, nsCString domain, + nsCString scopeDBKey, nsCString quotaDomainDBKey, + nsCString quotaETLDplus1DomainDBKey, PRUint32 storageType); + + sync GetKeys(bool callerSecure) + returns (nsString[] keys); + sync GetLength(bool callerSecure) + returns (PRUint32 length, nsresult rv); + sync GetKey(bool callerSecure, PRUint32 index) + returns (nsString key, nsresult rv); + sync GetValue(bool callerSecure, nsString key) + returns (StorageItem item, nsresult rv); + sync SetValue(bool callerSecure, nsString key, nsString data) + returns (nsString oldValue, nsresult rv); + sync RemoveValue(bool callerSecure, nsString key) + returns (nsString oldValue, nsresult rv); + sync Clear(bool callerSecure) + returns (PRInt32 oldCount, nsresult rv); + + sync GetDBValue(nsString key) + returns (nsString value, PRBool secure, nsresult rv); + sync SetDBValue(nsString key, nsString value, PRBool secure) + returns (nsresult rv); + sync SetSecure(nsString key, PRBool secure) + returns (nsresult rv); +}; + +} +}
new file mode 100644 --- /dev/null +++ b/dom/src/storage/StorageChild.cpp @@ -0,0 +1,282 @@ +/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */ +/* vim: set sw=4 ts=8 et tw=80 ft=cpp : */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla DOM Storage. + * + * The Initial Developer of the Original Code is + * The Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Josh Matthews <josh@joshmatthews.net> (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "StorageChild.h" +#include "mozilla/dom/ContentChild.h" +#include "nsDOMError.h" + +namespace mozilla { +namespace dom { + +NS_IMPL_CYCLE_COLLECTION_1(StorageChild, mStorage) + +NS_IMPL_CYCLE_COLLECTING_ADDREF(StorageChild) +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(StorageChild) + NS_INTERFACE_MAP_ENTRY(nsISupports) +NS_INTERFACE_MAP_END + +NS_IMETHODIMP_(nsrefcnt) StorageChild::Release(void) +{ + NS_PRECONDITION(0 != mRefCnt, "dup release"); + NS_ASSERT_OWNINGTHREAD(StorageChild); + nsISupports* base = NS_CYCLE_COLLECTION_CLASSNAME(StorageChild)::Upcast(this); + nsrefcnt count = mRefCnt.decr(base); + NS_LOG_RELEASE(this, count, "StorageChild"); + if (count == 1 && mIPCOpen) { + Send__delete__(this); + return 0; + } + if (count == 0) { + mRefCnt.stabilizeForDeletion(base); + delete this; + return 0; + } + return count; +} + +StorageChild::StorageChild(nsDOMStorage* aOwner) +: mStorage(aOwner) +, mIPCOpen(false) +{ +} + +StorageChild::StorageChild(nsDOMStorage* aOwner, StorageChild& aOther) +: DOMStorageBase(aOther) +, mStorage(aOwner) +, mIPCOpen(false) +{ +} + +void +StorageChild::AddIPDLReference() +{ + NS_ABORT_IF_FALSE(!mIPCOpen, "Attempting to retain multiple IPDL references"); + mIPCOpen = true; + AddRef(); +} + +void +StorageChild::ReleaseIPDLReference() +{ + NS_ABORT_IF_FALSE(mIPCOpen, "Attempting to release non-existent IPDL reference"); + mIPCOpen = false; + Release(); +} + +bool +StorageChild::CacheStoragePermissions() +{ + nsDOMStorage* storage = static_cast<nsDOMStorage*>(mStorage.get()); + return storage->CacheStoragePermissions(); +} + +void +StorageChild::InitRemote() +{ + ContentChild* child = ContentChild::GetSingleton(); + AddIPDLReference(); + child->SendPStorageConstructor(this, null_t()); + SendInit(mUseDB, mCanUseChromePersist, mDomain, mScopeDBKey, + mQuotaDomainDBKey, mQuotaETLDplus1DomainDBKey, mStorageType); +} + +void +StorageChild::InitAsSessionStorage(nsIURI* aDomainURI) +{ + DOMStorageBase::InitAsSessionStorage(aDomainURI); + InitRemote(); +} + +void +StorageChild::InitAsLocalStorage(nsIURI* aDomainURI, bool aCanUseChromePersist) +{ + DOMStorageBase::InitAsLocalStorage(aDomainURI, aCanUseChromePersist); + InitRemote(); +} + +void +StorageChild::InitAsGlobalStorage(const nsACString& aDomainDemanded) +{ + DOMStorageBase::InitAsGlobalStorage(aDomainDemanded); + InitRemote(); +} + +nsTArray<nsString>* +StorageChild::GetKeys(bool aCallerSecure) +{ + InfallibleTArray<nsString> remoteKeys; + SendGetKeys(aCallerSecure, &remoteKeys); + nsTArray<nsString>* keys = new nsTArray<nsString>; + *keys = remoteKeys; + return keys; +} + +nsresult +StorageChild::GetLength(bool aCallerSecure, PRUint32* aLength) +{ + nsresult rv; + SendGetLength(aCallerSecure, aLength, &rv); + return rv; +} + +nsresult +StorageChild::GetKey(bool aCallerSecure, PRUint32 aIndex, nsAString& aKey) +{ + nsresult rv; + nsString key; + SendGetKey(aCallerSecure, aIndex, &key, &rv); + if (NS_FAILED(rv)) + return rv; + aKey = key; + return NS_OK; +} + +// Unlike other cross-process forwarding methods, GetValue needs to replicate +// the following behaviour of DOMStorageImpl::GetValue: +// +// - if a security error occurs, or the item isn't found, return null without +// propogating the error. +// +// If DOMStorageImpl::GetValue ever changes its behaviour, this should be kept +// in sync. +nsIDOMStorageItem* +StorageChild::GetValue(bool aCallerSecure, const nsAString& aKey, nsresult* rv) +{ + nsresult rv2 = *rv = NS_OK; + StorageItem storageItem; + SendGetValue(aCallerSecure, nsString(aKey), &storageItem, &rv2); + if (rv2 == NS_ERROR_DOM_SECURITY_ERR || rv2 == NS_ERROR_DOM_NOT_FOUND_ERR) + return nsnull; + *rv = rv2; + if (NS_FAILED(*rv) || storageItem.type() == StorageItem::Tnull_t) + return nsnull; + const ItemData& data = storageItem.get_ItemData(); + nsIDOMStorageItem* item = new nsDOMStorageItem(this, aKey, data.value(), + data.secure()); + return item; +} + +nsresult +StorageChild::SetValue(bool aCallerSecure, const nsAString& aKey, + const nsAString& aData, nsAString& aOldData) +{ + nsresult rv; + nsString oldData; + SendSetValue(aCallerSecure, nsString(aKey), nsString(aData), &oldData, &rv); + if (NS_FAILED(rv)) + return rv; + aOldData = oldData; + return NS_OK; +} + +nsresult +StorageChild::RemoveValue(bool aCallerSecure, const nsAString& aKey, + nsAString& aOldData) +{ + nsresult rv; + nsString oldData; + SendRemoveValue(aCallerSecure, nsString(aKey), &oldData, &rv); + if (NS_FAILED(rv)) + return rv; + aOldData = oldData; + return NS_OK; +} + +nsresult +StorageChild::Clear(bool aCallerSecure, PRInt32* aOldCount) +{ + nsresult rv; + PRInt32 oldCount; + SendClear(aCallerSecure, &oldCount, &rv); + if (NS_FAILED(rv)) + return rv; + *aOldCount = oldCount; + return NS_OK; +} + +bool +StorageChild::CanUseChromePersist() +{ + return mCanUseChromePersist; +} + +nsresult +StorageChild::GetDBValue(const nsAString& aKey, nsAString& aValue, + PRBool* aSecure) +{ + nsresult rv; + nsString value; + SendGetDBValue(nsString(aKey), &value, aSecure, &rv); + aValue = value; + return rv; +} + +nsresult +StorageChild::SetDBValue(const nsAString& aKey, + const nsAString& aValue, + PRBool aSecure) +{ + nsresult rv; + SendSetDBValue(nsString(aKey), nsString(aValue), aSecure, &rv); + return rv; +} + +nsresult +StorageChild::SetSecure(const nsAString& aKey, PRBool aSecure) +{ + nsresult rv; + SendSetSecure(nsString(aKey), aSecure, &rv); + return rv; +} + +nsresult +StorageChild::CloneFrom(bool aCallerSecure, DOMStorageBase* aThat) +{ + StorageChild* other = static_cast<StorageChild*>(aThat); + ContentChild* child = ContentChild::GetSingleton(); + StorageClone clone(nsnull, other, aCallerSecure); + AddIPDLReference(); + child->SendPStorageConstructor(this, clone); + SendInit(mUseDB, mCanUseChromePersist, mDomain, mScopeDBKey, + mQuotaDomainDBKey, mQuotaETLDplus1DomainDBKey, mStorageType); + return NS_OK; +} + +} +}
new file mode 100644 --- /dev/null +++ b/dom/src/storage/StorageChild.h @@ -0,0 +1,105 @@ +/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */ +/* vim: set sw=4 ts=8 et tw=80 ft=cpp : */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla DOM Storage. + * + * The Initial Developer of the Original Code is + * The Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Josh Matthews <josh@joshmatthews.net> (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef mozilla_dom_StorageChild_h +#define mozilla_dom_StorageChild_h + +#include "mozilla/dom/PStorageChild.h" +#include "nsDOMStorage.h" +#include "nsCycleCollectionParticipant.h" + +namespace mozilla { +namespace dom { + +class StorageChild : public PStorageChild + , public DOMStorageBase +{ +public: + NS_DECL_CYCLE_COLLECTION_CLASS(StorageChild) + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + + StorageChild(nsDOMStorage* aOwner); + StorageChild(nsDOMStorage* aOwner, StorageChild& aOther); + + virtual void InitAsSessionStorage(nsIURI* aDomainURI); + virtual void InitAsLocalStorage(nsIURI* aDomainURI, bool aCanUseChromePersist); + virtual void InitAsGlobalStorage(const nsACString& aDomainDemanded); + + virtual bool CacheStoragePermissions(); + + virtual nsTArray<nsString>* GetKeys(bool aCallerSecure); + virtual nsresult GetLength(bool aCallerSecure, PRUint32* aLength); + virtual nsresult GetKey(bool aCallerSecure, PRUint32 aIndex, nsAString& aKey); + virtual nsIDOMStorageItem* GetValue(bool aCallerSecure, const nsAString& aKey, + nsresult* rv); + virtual nsresult SetValue(bool aCallerSecure, const nsAString& aKey, + const nsAString& aData, nsAString& aOldValue); + virtual nsresult RemoveValue(bool aCallerSecure, const nsAString& aKey, + nsAString& aOldValue); + virtual nsresult Clear(bool aCallerSecure, PRInt32* aOldCount); + + virtual bool CanUseChromePersist(); + + virtual nsresult GetDBValue(const nsAString& aKey, + nsAString& aValue, + PRBool* aSecure); + virtual nsresult SetDBValue(const nsAString& aKey, + const nsAString& aValue, + PRBool aSecure); + virtual nsresult SetSecure(const nsAString& aKey, PRBool aSecure); + + virtual nsresult CloneFrom(bool aCallerSecure, DOMStorageBase* aThat); + + void AddIPDLReference(); + void ReleaseIPDLReference(); + +private: + void InitRemote(); + + // Unimplemented + StorageChild(const StorageChild&); + + nsCOMPtr<nsIDOMStorageObsolete> mStorage; + bool mIPCOpen; +}; + +} +} + +#endif
new file mode 100644 --- /dev/null +++ b/dom/src/storage/StorageParent.cpp @@ -0,0 +1,175 @@ +/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */ +/* vim: set sw=4 ts=8 et tw=80 ft=cpp : */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla DOM Storage. + * + * The Initial Developer of the Original Code is + * The Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Josh Matthews <josh@joshmatthews.net> (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "StorageParent.h" +#include "mozilla/dom/PContentParent.h" +#include "mozilla/unused.h" +#include "nsDOMString.h" + +using mozilla::unused; + +namespace mozilla { +namespace dom { + +StorageParent::StorageParent(const StorageConstructData& aData) +{ + if (aData.type() == StorageConstructData::Tnull_t) { + mStorage = new DOMStorageImpl(nsnull); + } else { + const StorageClone& clone = aData.get_StorageClone(); + StorageParent* other = static_cast<StorageParent*>(clone.actorParent()); + mStorage = new DOMStorageImpl(nsnull, *other->mStorage.get()); + mStorage->CloneFrom(clone.callerSecure(), other->mStorage); + } +} + +bool +StorageParent::RecvInit(const bool& aUseDB, + const bool& aCanUseChromePersist, + const nsCString& aDomain, + const nsCString& aScopeDBKey, + const nsCString& aQuotaDomainDBKey, + const nsCString& aQuotaETLDplus1DomainDBKey, + const PRUint32& aStorageType) +{ + mStorage->InitFromChild(aUseDB, aCanUseChromePersist, aDomain, aScopeDBKey, + aQuotaDomainDBKey, aQuotaETLDplus1DomainDBKey, + aStorageType); + return true; +} + +bool +StorageParent::RecvGetKeys(const bool& aCallerSecure, InfallibleTArray<nsString>* aKeys) +{ + // Callers are responsible for deallocating the array returned by mStorage->GetKeys + nsAutoPtr<nsTArray<nsString> > keys(mStorage->GetKeys(aCallerSecure)); + aKeys->SwapElements(*keys); + return true; +} + +bool +StorageParent::RecvGetLength(const bool& aCallerSecure, PRUint32* aLength, + nsresult* rv) +{ + *rv = mStorage->GetLength(aCallerSecure, aLength); + return true; +} + +bool +StorageParent::RecvGetKey(const bool& aCallerSecure, const PRUint32& aIndex, + nsString* aKey, nsresult* rv) +{ + *rv = mStorage->GetKey(aCallerSecure, aIndex, *aKey); + return true; +} + +bool +StorageParent::RecvGetValue(const bool& aCallerSecure, const nsString& aKey, + StorageItem* aItem, nsresult* rv) +{ + // We need to ensure that a proper null representation is sent to the child + // if no item is found or an error occurs. + + *rv = NS_OK; + nsCOMPtr<nsIDOMStorageItem> item = mStorage->GetValue(aCallerSecure, aKey, rv); + if (NS_FAILED(*rv) || !item) { + *aItem = null_t(); + return true; + } + + ItemData data(EmptyString(), false); + nsDOMStorageItem* internalItem = static_cast<nsDOMStorageItem*>(item.get()); + data.value() = internalItem->GetValueInternal(); + if (aCallerSecure) + data.secure() = internalItem->IsSecure(); + *aItem = data; + return true; +} + +bool +StorageParent::RecvSetValue(const bool& aCallerSecure, const nsString& aKey, + const nsString& aData, nsString* aOldValue, + nsresult* rv) +{ + *rv = mStorage->SetValue(aCallerSecure, aKey, aData, *aOldValue); + return true; +} + +bool +StorageParent::RecvRemoveValue(const bool& aCallerSecure, const nsString& aKey, + nsString* aOldValue, nsresult* rv) +{ + *rv = mStorage->RemoveValue(aCallerSecure, aKey, *aOldValue); + return true; +} + +bool +StorageParent::RecvClear(const bool& aCallerSecure, PRInt32* aOldCount, + nsresult* rv) +{ + *rv = mStorage->Clear(aCallerSecure, aOldCount); + return true; +} + +bool +StorageParent::RecvGetDBValue(const nsString& aKey, nsString* aValue, + PRBool* aSecure, nsresult* rv) +{ + *rv = mStorage->GetDBValue(aKey, *aValue, aSecure); + return true; +} + +bool +StorageParent::RecvSetDBValue(const nsString& aKey, const nsString& aValue, + const PRBool& aSecure, nsresult* rv) +{ + *rv = mStorage->SetDBValue(aKey, aValue, aSecure); + return true; +} + +bool +StorageParent::RecvSetSecure(const nsString& aKey, const PRBool& aSecure, + nsresult* rv) +{ + *rv = mStorage->SetSecure(aKey, aSecure); + return true; +} + +} +}
new file mode 100644 --- /dev/null +++ b/dom/src/storage/StorageParent.h @@ -0,0 +1,90 @@ +/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */ +/* vim: set sw=4 ts=8 et tw=80 ft=cpp : */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla DOM Storage. + * + * The Initial Developer of the Original Code is + * The Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Josh Matthews <josh@joshmatthews.net> (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef mozilla_dom_StorageParent_h +#define mozilla_dom_StorageParent_h + +#include "mozilla/dom/PStorageParent.h" +#include "nsDOMStorage.h" + +namespace mozilla { +namespace dom { + +class StorageConstructData; + +class StorageParent : public PStorageParent +{ +public: + StorageParent(const StorageConstructData& aData); + +private: + bool RecvGetKeys(const bool& aCallerSecure, InfallibleTArray<nsString>* aKeys); + bool RecvGetLength(const bool& aCallerSecure, PRUint32* aLength, nsresult* rv); + bool RecvGetKey(const bool& aCallerSecure, const PRUint32& aIndex, + nsString* aKey, nsresult* rv); + bool RecvGetValue(const bool& aCallerSecure, const nsString& aKey, + StorageItem* aItem, nsresult* rv); + bool RecvSetValue(const bool& aCallerSecure, const nsString& aKey, + const nsString& aData, nsString* aOldValue, nsresult* rv); + bool RecvRemoveValue(const bool& aCallerSecure, const nsString& aKey, + nsString* aOldData, nsresult* rv); + bool RecvClear(const bool& aCallerSecure, PRInt32* aOldCount, nsresult* rv); + + bool RecvGetDBValue(const nsString& aKey, nsString* aValue, PRBool* aSecure, + nsresult* rv); + bool RecvSetDBValue(const nsString& aKey, const nsString& aValue, + const PRBool& aSecure, nsresult* rv); + bool RecvSetSecure(const nsString& aKey, const PRBool& aSecure, + nsresult* rv); + + bool RecvInit(const bool& aUseDB, + const bool& aCanUseChromePersist, + const nsCString& aDomain, + const nsCString& aScopeDBKey, + const nsCString& aQuotaDomainDBKey, + const nsCString& aQuotaETLDplus1DomainDBKey, + const PRUint32& aStorageType); + + nsRefPtr<DOMStorageImpl> mStorage; +}; + +} +} + +#endif
new file mode 100644 --- /dev/null +++ b/dom/src/storage/ipdl.mk @@ -0,0 +1,39 @@ +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla DOM Storage. +# +# The Initial Developer of the Original Code is +# The Mozilla Foundation. +# Portions created by the Initial Developer are Copyright (C) 2010 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +IPDLSRCS = \ + PStorage.ipdl \ + $(NULL)
--- a/dom/src/storage/nsDOMStorage.cpp +++ b/dom/src/storage/nsDOMStorage.cpp @@ -19,31 +19,39 @@ * Portions created by the Initial Developer are Copyright (C) 2006 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Neil Deakin <enndeakin@sympatico.ca> * Johnny Stenback <jst@mozilla.com> * Ehsan Akhgari <ehsan.akhgari@gmail.com> * Honza Bambas <honzab@firemni.cz> + * Josh Matthews <josh@joshmatthews.net> * * Alternatively, the contents of this file may be used under the terms of * either of the GNU General Public License Version 2 or later (the "GPL"), * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ +#ifdef MOZ_IPC +#include "StorageChild.h" +#include "StorageParent.h" +#include "nsXULAppAPI.h" +using mozilla::dom::StorageChild; +#endif + #include "prnetdb.h" #include "nsCOMPtr.h" #include "nsDOMError.h" #include "nsDOMClassInfo.h" #include "nsUnicharUtils.h" #include "nsIDocument.h" #include "nsDOMStorage.h" #include "nsEscape.h" @@ -289,18 +297,18 @@ nsDOMStorageManager::GetInstance() //static void nsDOMStorageManager::Shutdown() { NS_IF_RELEASE(gStorageManager); gStorageManager = nsnull; #ifdef MOZ_STORAGE - delete nsDOMStorage::gStorageDB; - nsDOMStorage::gStorageDB = nsnull; + delete DOMStorageImpl::gStorageDB; + DOMStorageImpl::gStorageDB = nsnull; #endif } static PLDHashOperator ClearStorage(nsDOMStorageEntry* aEntry, void* userArg) { aEntry->mStorage->ClearAll(); return PL_DHASH_REMOVE; @@ -355,46 +363,46 @@ nsDOMStorageManager::Observe(nsISupports if (!strcmp(aTopic, "profile-after-change")) { nsCOMPtr<nsIPrivateBrowsingService> pbs = do_GetService(NS_PRIVATE_BROWSING_SERVICE_CONTRACTID); if (pbs) pbs->GetPrivateBrowsingEnabled(&gStorageManager->mInPrivateBrowsing); } else if (!strcmp(aTopic, "offline-app-removed")) { #ifdef MOZ_STORAGE - nsresult rv = nsDOMStorage::InitDB(); + nsresult rv = DOMStorageImpl::InitDB(); NS_ENSURE_SUCCESS(rv, rv); - return nsDOMStorage::gStorageDB->RemoveOwner(NS_ConvertUTF16toUTF8(aData), - PR_TRUE); + return DOMStorageImpl::gStorageDB->RemoveOwner(NS_ConvertUTF16toUTF8(aData), + PR_TRUE); #endif } else if (!strcmp(aTopic, "cookie-changed") && !nsCRT::strcmp(aData, NS_LITERAL_STRING("cleared").get())) { mStorages.EnumerateEntries(ClearStorage, nsnull); #ifdef MOZ_STORAGE - nsresult rv = nsDOMStorage::InitDB(); + nsresult rv = DOMStorageImpl::InitDB(); NS_ENSURE_SUCCESS(rv, rv); // Remove global storage for domains that aren't marked for offline use. nsTArray<nsString> domains; rv = GetOfflineDomains(domains); NS_ENSURE_SUCCESS(rv, rv); - return nsDOMStorage::gStorageDB->RemoveOwners(domains, PR_TRUE, PR_FALSE); + return DOMStorageImpl::gStorageDB->RemoveOwners(domains, PR_TRUE, PR_FALSE); #endif } else if (!strcmp(aTopic, NS_PRIVATE_BROWSING_SWITCH_TOPIC)) { mStorages.EnumerateEntries(ClearStorage, nsnull); if (!nsCRT::strcmp(aData, NS_LITERAL_STRING(NS_PRIVATE_BROWSING_ENTER).get())) mInPrivateBrowsing = PR_TRUE; else if (!nsCRT::strcmp(aData, NS_LITERAL_STRING(NS_PRIVATE_BROWSING_LEAVE).get())) mInPrivateBrowsing = PR_FALSE; #ifdef MOZ_STORAGE - nsresult rv = nsDOMStorage::InitDB(); + nsresult rv = DOMStorageImpl::InitDB(); NS_ENSURE_SUCCESS(rv, rv); - return nsDOMStorage::gStorageDB->DropPrivateBrowsingStorages(); + return DOMStorageImpl::gStorageDB->DropPrivateBrowsingStorages(); #endif } else if (!strcmp(aTopic, "perm-changed")) { // Check for cookie permission change nsCOMPtr<nsIPermission> perm(do_QueryInterface(aSubject)); if (perm) { nsCAutoString type; perm->GetType(type); if (type != NS_LITERAL_CSTRING("cookie")) @@ -407,52 +415,52 @@ nsDOMStorageManager::Observe(nsISupports return NS_OK; nsCAutoString host; perm->GetHost(host); if (host.IsEmpty()) return NS_OK; #ifdef MOZ_STORAGE - nsresult rv = nsDOMStorage::InitDB(); + nsresult rv = DOMStorageImpl::InitDB(); NS_ENSURE_SUCCESS(rv, rv); - return nsDOMStorage::gStorageDB->DropSessionOnlyStoragesForHost(host); + return DOMStorageImpl::gStorageDB->DropSessionOnlyStoragesForHost(host); #endif } } else if (!strcmp(aTopic, "timer-callback")) { nsCOMPtr<nsIObserverService> obsserv = mozilla::services::GetObserverService(); if (obsserv) obsserv->NotifyObservers(nsnull, NS_DOMSTORAGE_FLUSH_TIMER_OBSERVER, nsnull); } return NS_OK; } NS_IMETHODIMP nsDOMStorageManager::GetUsage(const nsAString& aDomain, PRInt32 *aUsage) { - nsresult rv = nsDOMStorage::InitDB(); + nsresult rv = DOMStorageImpl::InitDB(); NS_ENSURE_SUCCESS(rv, rv); - return nsDOMStorage::gStorageDB->GetUsage(NS_ConvertUTF16toUTF8(aDomain), - PR_FALSE, aUsage); + return DOMStorageImpl::gStorageDB->GetUsage(NS_ConvertUTF16toUTF8(aDomain), + PR_FALSE, aUsage); } NS_IMETHODIMP nsDOMStorageManager::ClearOfflineApps() { - nsresult rv = nsDOMStorage::InitDB(); + nsresult rv = DOMStorageImpl::InitDB(); NS_ENSURE_SUCCESS(rv, rv); nsTArray<nsString> domains; rv = GetOfflineDomains(domains); NS_ENSURE_SUCCESS(rv, rv); - return nsDOMStorage::gStorageDB->RemoveOwners(domains, PR_TRUE, PR_TRUE); + return DOMStorageImpl::gStorageDB->RemoveOwners(domains, PR_TRUE, PR_TRUE); } NS_IMETHODIMP nsDOMStorageManager::GetLocalStorageForPrincipal(nsIPrincipal *aPrincipal, const nsSubstring &aDocumentURI, nsIDOMStorage **aResult) { NS_ENSURE_ARG_POINTER(aPrincipal); @@ -470,37 +478,37 @@ nsDOMStorageManager::GetLocalStorageForP *aResult = storage.get(); storage.forget(); return NS_OK; } void -nsDOMStorageManager::AddToStoragesHash(nsDOMStorage* aStorage) +nsDOMStorageManager::AddToStoragesHash(DOMStorageImpl* aStorage) { nsDOMStorageEntry* entry = mStorages.PutEntry(aStorage); if (entry) entry->mStorage = aStorage; } void -nsDOMStorageManager::RemoveFromStoragesHash(nsDOMStorage* aStorage) +nsDOMStorageManager::RemoveFromStoragesHash(DOMStorageImpl* aStorage) { nsDOMStorageEntry* entry = mStorages.GetEntry(aStorage); if (entry) mStorages.RemoveEntry(aStorage); } // // nsDOMStorage // #ifdef MOZ_STORAGE -nsDOMStorageDBWrapper* nsDOMStorage::gStorageDB = nsnull; +nsDOMStorageDBWrapper* DOMStorageImpl::gStorageDB = nsnull; #endif nsDOMStorageEntry::nsDOMStorageEntry(KeyTypePointer aStr) : nsVoidPtrHashKey(aStr), mStorage(nsnull) { } nsDOMStorageEntry::nsDOMStorageEntry(const nsDOMStorageEntry& aToCopy) @@ -508,46 +516,26 @@ nsDOMStorageEntry::nsDOMStorageEntry(con { NS_ERROR("DOMStorage horked."); } nsDOMStorageEntry::~nsDOMStorageEntry() { } -PLDHashOperator -SessionStorageTraverser(nsSessionStorageEntry* aEntry, void* userArg) { - nsCycleCollectionTraversalCallback *cb = - static_cast<nsCycleCollectionTraversalCallback*>(userArg); - - cb->NoteXPCOMChild((nsIDOMStorageItem *) aEntry->mItem); - - return PL_DHASH_NEXT; -} - -NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMStorage) -NS_IMPL_CYCLE_COLLECTION_UNLINK_0(nsDOMStorage) -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDOMStorage) - { - if (tmp->mItems.IsInitialized()) { - tmp->mItems.EnumerateEntries(SessionStorageTraverser, &cb); - } - } -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END +NS_IMPL_CYCLE_COLLECTION_1(nsDOMStorage, mStorageImpl) DOMCI_DATA(StorageObsolete, nsDOMStorage) NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(nsDOMStorage, nsIDOMStorageObsolete) NS_IMPL_CYCLE_COLLECTING_RELEASE_AMBIGUOUS(nsDOMStorage, nsIDOMStorageObsolete) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMStorage) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMStorageObsolete) NS_INTERFACE_MAP_ENTRY(nsIDOMStorageObsolete) NS_INTERFACE_MAP_ENTRY(nsPIDOMStorage) - NS_INTERFACE_MAP_ENTRY(nsIObserver) - NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(StorageObsolete) NS_INTERFACE_MAP_END nsresult NS_NewDOMStorage(nsISupports* aOuter, REFNSIID aIID, void** aResult) { nsDOMStorage* storage = new nsDOMStorage(); if (!storage) @@ -561,57 +549,866 @@ NS_NewDOMStorage2(nsISupports* aOuter, R { nsDOMStorage2* storage = new nsDOMStorage2(); if (!storage) return NS_ERROR_OUT_OF_MEMORY; return storage->QueryInterface(aIID, aResult); } -nsDOMStorage::nsDOMStorage() - : mUseDB(PR_FALSE) +DOMStorageBase::DOMStorageBase() + : mStorageType(nsPIDOMStorage::Unknown) + , mUseDB(PR_FALSE) + , mSessionOnly(PR_TRUE) + , mCanUseChromePersist(false) +{ +} + +DOMStorageBase::DOMStorageBase(DOMStorageBase& aThat) + : mStorageType(aThat.mStorageType) + , mUseDB(PR_FALSE) // Clones don't use the DB , mSessionOnly(PR_TRUE) - , mStorageType(nsPIDOMStorage::Unknown) - , mItemsCached(PR_FALSE) - , mEventBroadcaster(nsnull) - , mCanUseChromePersist(false) - , mLoadedTemporaryTable(false) + , mDomain(aThat.mDomain) + , mScopeDBKey(aThat.mScopeDBKey) + , mQuotaETLDplus1DomainDBKey(aThat.mQuotaETLDplus1DomainDBKey) + , mQuotaDomainDBKey(aThat.mQuotaDomainDBKey) + , mCanUseChromePersist(aThat.mCanUseChromePersist) +{ +} + +void +DOMStorageBase::InitAsSessionStorage(nsIURI* aDomainURI) +{ + // No need to check for a return value. If this would fail we would not get + // here as we call GetPrincipalURIAndHost (nsDOMStorage.cpp:88) from + // nsDOMStorage::CanUseStorage before we query the storage manager for a new + // sessionStorage. It calls GetAsciiHost on innermost URI. If it fails, we + // won't get to InitAsSessionStorage. + aDomainURI->GetAsciiHost(mDomain); + +#ifdef MOZ_STORAGE + mUseDB = PR_FALSE; + mScopeDBKey.Truncate(); + mQuotaDomainDBKey.Truncate(); +#endif + mStorageType = nsPIDOMStorage::SessionStorage; +} + +void +DOMStorageBase::InitAsLocalStorage(nsIURI* aDomainURI, + bool aCanUseChromePersist) { - mSecurityChecker = this; - mItems.Init(8); - if (nsDOMStorageManager::gStorageManager) - nsDOMStorageManager::gStorageManager->AddToStoragesHash(this); + // No need to check for a return value. If this would fail we would not get + // here as we call GetPrincipalURIAndHost (nsDOMStorage.cpp:88) from + // nsDOMStorage::CanUseStorage before we query the storage manager for a new + // localStorage. It calls GetAsciiHost on innermost URI. If it fails, we won't + // get to InitAsLocalStorage. Actually, mDomain will get replaced with + // mPrincipal in bug 455070. It is not even used for localStorage. + aDomainURI->GetAsciiHost(mDomain); + +#ifdef MOZ_STORAGE + nsDOMStorageDBWrapper::CreateOriginScopeDBKey(aDomainURI, mScopeDBKey); + + // XXX Bug 357323, we have to solve the issue how to define + // origin for file URLs. In that case CreateOriginScopeDBKey + // fails (the result is empty) and we must avoid database use + // in that case because it produces broken entries w/o owner. + mUseDB = !mScopeDBKey.IsEmpty(); + + nsDOMStorageDBWrapper::CreateQuotaDomainDBKey(mDomain, + PR_TRUE, PR_FALSE, mQuotaDomainDBKey); + nsDOMStorageDBWrapper::CreateQuotaDomainDBKey(mDomain, + PR_TRUE, PR_TRUE, mQuotaETLDplus1DomainDBKey); +#endif + mCanUseChromePersist = aCanUseChromePersist; + mStorageType = nsPIDOMStorage::LocalStorage; } -nsDOMStorage::nsDOMStorage(nsDOMStorage& aThat) - : mUseDB(PR_FALSE) // Any clone is not using the database - , mDomain(aThat.mDomain) - , mSessionOnly(PR_TRUE) - , mStorageType(aThat.mStorageType) - , mItemsCached(PR_FALSE) +void +DOMStorageBase::InitAsGlobalStorage(const nsACString& aDomainDemanded) +{ + mDomain = aDomainDemanded; + #ifdef MOZ_STORAGE - , mScopeDBKey(aThat.mScopeDBKey) + nsDOMStorageDBWrapper::CreateDomainScopeDBKey(aDomainDemanded, mScopeDBKey); + + // XXX Bug 357323, we have to solve the issue how to define + // origin for file URLs. In that case CreateOriginScopeDBKey + // fails (the result is empty) and we must avoid database use + // in that case because it produces broken entries w/o owner. + if (!(mUseDB = !mScopeDBKey.IsEmpty())) + mScopeDBKey.AppendLiteral(":"); + + nsDOMStorageDBWrapper::CreateQuotaDomainDBKey(aDomainDemanded, + PR_TRUE, PR_FALSE, mQuotaDomainDBKey); + nsDOMStorageDBWrapper::CreateQuotaDomainDBKey(aDomainDemanded, + PR_TRUE, PR_TRUE, mQuotaETLDplus1DomainDBKey); #endif - , mEventBroadcaster(nsnull) - , mCanUseChromePersist(aThat.mCanUseChromePersist) + mStorageType = nsPIDOMStorage::GlobalStorage; +} + +PLDHashOperator +SessionStorageTraverser(nsSessionStorageEntry* aEntry, void* userArg) { + nsCycleCollectionTraversalCallback *cb = + static_cast<nsCycleCollectionTraversalCallback*>(userArg); + + cb->NoteXPCOMChild((nsIDOMStorageItem *) aEntry->mItem); + + return PL_DHASH_NEXT; +} + +NS_IMPL_CYCLE_COLLECTION_CLASS(DOMStorageImpl) +NS_IMPL_CYCLE_COLLECTION_UNLINK_0(DOMStorageImpl) +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DOMStorageImpl) +{ + if (tmp->mItems.IsInitialized()) { + tmp->mItems.EnumerateEntries(SessionStorageTraverser, &cb); + } +} +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END + +NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(DOMStorageImpl, nsIObserver) +NS_IMPL_CYCLE_COLLECTING_RELEASE_AMBIGUOUS(DOMStorageImpl, nsIObserver) +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMStorageImpl) + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIObserver) + NS_INTERFACE_MAP_ENTRY(nsIObserver) + NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) +NS_INTERFACE_MAP_END + +DOMStorageImpl::DOMStorageImpl(nsDOMStorage* aStorage) + : mLoadedTemporaryTable(false) +{ + Init(aStorage); +} + +DOMStorageImpl::DOMStorageImpl(nsDOMStorage* aStorage, DOMStorageImpl& aThat) + : DOMStorageBase(aThat) , mLoadedTemporaryTable(aThat.mLoadedTemporaryTable) , mLastTemporaryTableAccessTime(aThat.mLastTemporaryTableAccessTime) , mTemporaryTableAge(aThat.mTemporaryTableAge) { - mSecurityChecker = this; + Init(aStorage); +} + +void +DOMStorageImpl::Init(nsDOMStorage* aStorage) +{ + mItemsCached = PR_FALSE; mItems.Init(8); - + mOwner = aStorage; if (nsDOMStorageManager::gStorageManager) nsDOMStorageManager::gStorageManager->AddToStoragesHash(this); } +DOMStorageImpl::~DOMStorageImpl() +{ + if (nsDOMStorageManager::gStorageManager) + nsDOMStorageManager::gStorageManager->RemoveFromStoragesHash(this); +} + +nsresult +DOMStorageImpl::InitDB() +{ +#ifdef MOZ_STORAGE + if (!gStorageDB) { + gStorageDB = new nsDOMStorageDBWrapper(); + if (!gStorageDB) + return NS_ERROR_OUT_OF_MEMORY; + + nsresult rv = gStorageDB->Init(); + if (NS_FAILED(rv)) { + // Failed to initialize the DB, delete it and null out the + // pointer so we don't end up attempting to use an + // un-initialized DB later on. + + delete gStorageDB; + gStorageDB = nsnull; + + return rv; + } + } +#endif + + return NS_OK; +} + +void +DOMStorageImpl::InitFromChild(bool aUseDB, bool aCanUseChromePersist, + const nsACString& aDomain, + const nsACString& aScopeDBKey, + const nsACString& aQuotaDomainDBKey, + const nsACString& aQuotaETLDplus1DomainDBKey, + PRUint32 aStorageType) +{ + mUseDB = aUseDB; + mCanUseChromePersist = aCanUseChromePersist; + mDomain = aDomain; + mScopeDBKey = aScopeDBKey; + mQuotaDomainDBKey = aQuotaDomainDBKey; + mQuotaETLDplus1DomainDBKey = aQuotaETLDplus1DomainDBKey; + mStorageType = static_cast<nsPIDOMStorage::nsDOMStorageType>(aStorageType); + if (mStorageType != nsPIDOMStorage::SessionStorage) + RegisterObservers(); + CacheStoragePermissions(); +} + +void +DOMStorageImpl::InitAsSessionStorage(nsIURI* aDomainURI) +{ + DOMStorageBase::InitAsSessionStorage(aDomainURI); +} + +void +DOMStorageImpl::InitAsLocalStorage(nsIURI* aDomainURI, + bool aCanUseChromePersist) +{ + DOMStorageBase::InitAsLocalStorage(aDomainURI, aCanUseChromePersist); + RegisterObservers(); +} + +void +DOMStorageImpl::InitAsGlobalStorage(const nsACString& aDomainDemanded) +{ + DOMStorageBase::InitAsGlobalStorage(aDomainDemanded); + RegisterObservers(); +} + +bool +DOMStorageImpl::CacheStoragePermissions() +{ + // If this is a cross-process situation, we don't have a real storage owner. + // All the correct checks have been done on the child, so we just need to + // make sure that our session-only status is correctly updated. + if (!mOwner) + return nsDOMStorage::CanUseStorage(&mSessionOnly); + + return mOwner->CacheStoragePermissions(); +} + +bool +DOMStorageImpl::CanUseChromePersist() +{ + return mCanUseChromePersist; +} + +nsresult +DOMStorageImpl::GetCachedValue(const nsAString& aKey, nsAString& aValue, + PRBool* aSecure) +{ + aValue.Truncate(); + *aSecure = PR_FALSE; + + nsSessionStorageEntry *entry = mItems.GetEntry(aKey); + if (!entry) + return NS_ERROR_NOT_AVAILABLE; + + aValue = entry->mItem->GetValueInternal(); + *aSecure = entry->mItem->IsSecure(); + + return NS_OK; +} + +nsresult +DOMStorageImpl::GetDBValue(const nsAString& aKey, nsAString& aValue, + PRBool* aSecure) +{ + aValue.Truncate(); + +#ifdef MOZ_STORAGE + if (!UseDB()) + return NS_OK; + + nsresult rv = InitDB(); + NS_ENSURE_SUCCESS(rv, rv); + + nsAutoString value; + rv = gStorageDB->GetKeyValue(this, aKey, value, aSecure); + + if (rv == NS_ERROR_DOM_NOT_FOUND_ERR && + mStorageType != nsPIDOMStorage::GlobalStorage) { + SetDOMStringToNull(aValue); + } + + if (NS_FAILED(rv)) + return rv; + + aValue.Assign(value); +#endif + + return NS_OK; +} + +nsresult +DOMStorageImpl::SetDBValue(const nsAString& aKey, + const nsAString& aValue, + PRBool aSecure) +{ +#ifdef MOZ_STORAGE + if (!UseDB()) + return NS_OK; + + nsresult rv = InitDB(); + NS_ENSURE_SUCCESS(rv, rv); + + PRInt32 offlineAppPermission; + PRInt32 quota; + PRInt32 warnQuota; + offlineAppPermission = GetQuota(mDomain, "a, &warnQuota, + CanUseChromePersist()); + + PRInt32 usage; + rv = gStorageDB->SetKey(this, aKey, aValue, aSecure, quota, + !IS_PERMISSION_ALLOWED(offlineAppPermission), + &usage); + NS_ENSURE_SUCCESS(rv, rv); + + // Before bug 536544 got fixed we were dropping mItemsCached flag here + + if (warnQuota >= 0 && usage > warnQuota) { + // try to include the window that exceeded the warn quota + nsCOMPtr<nsIDOMWindow> window; + JSContext *cx; + nsCOMPtr<nsIJSContextStack> stack = + do_GetService("@mozilla.org/js/xpc/ContextStack;1"); + if (stack && NS_SUCCEEDED(stack->Peek(&cx)) && cx) { + nsCOMPtr<nsIScriptContext> scriptContext; + scriptContext = GetScriptContextFromJSContext(cx); + if (scriptContext) { + window = do_QueryInterface(scriptContext->GetGlobalObject()); + } + } + + nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService(); + os->NotifyObservers(window, "dom-storage-warn-quota-exceeded", + NS_ConvertUTF8toUTF16(mDomain).get()); + } + +#endif + + return NS_OK; +} + +nsresult +DOMStorageImpl::SetSecure(const nsAString& aKey, PRBool aSecure) +{ +#ifdef MOZ_STORAGE + if (UseDB()) { + nsresult rv = InitDB(); + NS_ENSURE_SUCCESS(rv, rv); + + return gStorageDB->SetSecure(this, aKey, aSecure); + } +#else + return NS_ERROR_NOT_IMPLEMENTED; +#endif + + nsSessionStorageEntry *entry = mItems.GetEntry(aKey); + NS_ASSERTION(entry, "Don't use SetSecure() with nonexistent keys!"); + + if (entry) { + entry->mItem->SetSecureInternal(aSecure); + } + + return NS_OK; +} + +static PLDHashOperator +ClearStorageItem(nsSessionStorageEntry* aEntry, void* userArg) +{ + aEntry->mItem->SetValueInternal(EmptyString()); + return PL_DHASH_NEXT; +} + +void +DOMStorageImpl::ClearAll() +{ + mItems.EnumerateEntries(ClearStorageItem, nsnull); + mItemsCached = PR_FALSE; +} + +struct CopyArgs { + DOMStorageImpl* storage; + bool callerSecure; +}; + +static PLDHashOperator +CopyStorageItems(nsSessionStorageEntry* aEntry, void* userArg) +{ + // When copying items from one impl to another, we may not + // have an mOwner that we can call SetItem on. Therefore we need + // to replicate its behaviour. + + CopyArgs* args = static_cast<CopyArgs*>(userArg); + + nsAutoString unused; + nsresult rv = args->storage->SetValue(args->callerSecure, aEntry->GetKey(), + aEntry->mItem->GetValueInternal(), unused); + if (NS_FAILED(rv)) + return PL_DHASH_NEXT; + + if (aEntry->mItem->IsSecure()) { + args->storage->SetSecure(aEntry->GetKey(), PR_TRUE); + } + + return PL_DHASH_NEXT; +} + +nsresult +DOMStorageImpl::CloneFrom(bool aCallerSecure, DOMStorageBase* aThat) +{ + // For various reasons, we no longer call SetItem in CopyStorageItems, + // so we need to ensure that the storage permissions are correct. + if (!CacheStoragePermissions()) + return NS_ERROR_DOM_SECURITY_ERR; + + DOMStorageImpl* that = static_cast<DOMStorageImpl*>(aThat); + CopyArgs args = { this, aCallerSecure }; + that->mItems.EnumerateEntries(CopyStorageItems, &args); + return NS_OK; +} + +nsresult +DOMStorageImpl::RegisterObservers() +{ + nsCOMPtr<nsIObserverService> obsserv = mozilla::services::GetObserverService(); + if (obsserv) { + obsserv->AddObserver(this, "profile-before-change", PR_TRUE); + obsserv->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, PR_TRUE); + obsserv->AddObserver(this, NS_DOMSTORAGE_FLUSH_TIMER_OBSERVER, PR_TRUE); + } + return NS_OK; +} + +nsresult +DOMStorageImpl::MaybeCommitTemporaryTable(bool force) +{ +#ifdef MOZ_STORAGE + if (!UseDB()) + return NS_OK; + + if (!mLoadedTemporaryTable) + return NS_OK; + + // If we are not forced to flush (e.g. on shutdown) then don't flush if the + // last table access is less then 5 seconds ago or the table itself is not + // older then 30 secs + if (!force && + ((TimeStamp::Now() - mLastTemporaryTableAccessTime).ToSeconds() < + NS_DOMSTORAGE_MAXIMUM_TEMPTABLE_INACTIVITY_TIME) && + ((TimeStamp::Now() - mTemporaryTableAge).ToSeconds() < + NS_DOMSTORAGE_MAXIMUM_TEMPTABLE_AGE)) + return NS_OK; + + return gStorageDB->FlushAndDeleteTemporaryTableForStorage(this); +#endif + + return NS_OK; +} + +bool +DOMStorageImpl::WasTemporaryTableLoaded() +{ + return mLoadedTemporaryTable; +} + +void +DOMStorageImpl::SetTemporaryTableLoaded(bool loaded) +{ + if (loaded) { + mLastTemporaryTableAccessTime = TimeStamp::Now(); + if (!mLoadedTemporaryTable) + mTemporaryTableAge = mLastTemporaryTableAccessTime; + } + + mLoadedTemporaryTable = loaded; +} + +NS_IMETHODIMP +DOMStorageImpl::Observe(nsISupports *subject, + const char *topic, + const PRUnichar *data) +{ + bool isProfileBeforeChange = !strcmp(topic, "profile-before-change"); + bool isXPCOMShutdown = !strcmp(topic, NS_XPCOM_SHUTDOWN_OBSERVER_ID); + bool isFlushTimer = !strcmp(topic, NS_DOMSTORAGE_FLUSH_TIMER_OBSERVER); + + if (isXPCOMShutdown || isProfileBeforeChange || isFlushTimer) { + nsresult rv = MaybeCommitTemporaryTable(isXPCOMShutdown || isProfileBeforeChange); + if (NS_FAILED(rv)) { + NS_WARNING("DOMStorage: temporary table commit failed"); + } + + return NS_OK; + } + + NS_WARNING("Unrecognized topic in nsDOMStorage::Observe"); + return NS_OK; +} + +nsresult +DOMStorageImpl::CacheKeysFromDB() +{ +#ifdef MOZ_STORAGE + // cache all the keys in the hash. This is used by the Length and Key methods + // use this cache for better performance. The disadvantage is that the + // order may break if someone changes the keys in the database directly. + if (!mItemsCached) { + nsresult rv = InitDB(); + NS_ENSURE_SUCCESS(rv, rv); + + mItems.Clear(); + + rv = gStorageDB->GetAllKeys(this, &mItems); + NS_ENSURE_SUCCESS(rv, rv); + + mItemsCached = PR_TRUE; + } +#endif + + return NS_OK; +} + +struct KeysArrayBuilderStruct +{ + PRBool callerIsSecure; + nsTArray<nsString> *keys; +}; + +static PLDHashOperator +KeysArrayBuilder(nsSessionStorageEntry* aEntry, void* userArg) +{ + KeysArrayBuilderStruct *keystruct = (KeysArrayBuilderStruct *)userArg; + + if (keystruct->callerIsSecure || !aEntry->mItem->IsSecure()) + keystruct->keys->AppendElement(aEntry->GetKey()); + + return PL_DHASH_NEXT; +} + +nsTArray<nsString>* +DOMStorageImpl::GetKeys(bool aCallerSecure) +{ + if (UseDB()) + CacheKeysFromDB(); + + KeysArrayBuilderStruct keystruct; + keystruct.callerIsSecure = aCallerSecure; + keystruct.keys = new nsTArray<nsString>(); + if (keystruct.keys) + mItems.EnumerateEntries(KeysArrayBuilder, &keystruct); + + return keystruct.keys; +} + +class ItemCounterState +{ + public: + ItemCounterState(PRBool aIsCallerSecure) + : mIsCallerSecure(aIsCallerSecure), mCount(0) + { + } + + PRBool mIsCallerSecure; + PRBool mCount; + private: + ItemCounterState(); // Not to be implemented +}; + +static PLDHashOperator +ItemCounter(nsSessionStorageEntry* aEntry, void* userArg) +{ + ItemCounterState *state = (ItemCounterState *)userArg; + + if (state->mIsCallerSecure || !aEntry->mItem->IsSecure()) { + ++state->mCount; + } + + return PL_DHASH_NEXT; +} + +nsresult +DOMStorageImpl::GetLength(bool aCallerSecure, PRUint32* aLength) +{ + // Force reload of items from database. This ensures sync localStorages for + // same origins among different windows. + mItemsCached = PR_FALSE; + if (UseDB()) + CacheKeysFromDB(); + + ItemCounterState state(aCallerSecure); + + mItems.EnumerateEntries(ItemCounter, &state); + + *aLength = state.mCount; + return NS_OK; +} + +class IndexFinderData +{ + public: + IndexFinderData(PRBool aIsCallerSecure, PRUint32 aWantedIndex) + : mIsCallerSecure(aIsCallerSecure), mIndex(0), mWantedIndex(aWantedIndex), + mItem(nsnull) + { + } + + PRBool mIsCallerSecure; + PRUint32 mIndex; + PRUint32 mWantedIndex; + nsSessionStorageEntry *mItem; + + private: + IndexFinderData(); // Not to be implemented +}; + +static PLDHashOperator +IndexFinder(nsSessionStorageEntry* aEntry, void* userArg) +{ + IndexFinderData *data = (IndexFinderData *)userArg; + + if (data->mIndex == data->mWantedIndex && + (data->mIsCallerSecure || !aEntry->mItem->IsSecure())) { + data->mItem = aEntry; + + return PL_DHASH_STOP; + } + + ++data->mIndex; + + return PL_DHASH_NEXT; +} + +nsresult +DOMStorageImpl::GetKey(bool aCallerSecure, PRUint32 aIndex, nsAString& aKey) +{ + // XXXjst: This is as retarded as the DOM spec is, takes an unsigned + // int, but the spec talks about what to do if a negative value is + // passed in. + + // XXX: This does a linear search for the key at index, which would + // suck if there's a large numer of indexes. Do we care? If so, + // maybe we need to have a lazily populated key array here or + // something? + + if (UseDB()) + CacheKeysFromDB(); + + IndexFinderData data(aCallerSecure, aIndex); + mItems.EnumerateEntries(IndexFinder, &data); + + if (!data.mItem) { + // aIndex was larger than the number of accessible keys. Throw. + return NS_ERROR_DOM_INDEX_SIZE_ERR; + } + + aKey = data.mItem->GetKey(); + return NS_OK; +} + +// The behaviour of this function must be kept in sync with StorageChild::GetValue. +// See the explanatory comment there for more details. +nsIDOMStorageItem* +DOMStorageImpl::GetValue(bool aCallerSecure, const nsAString& aKey, + nsresult* aResult) +{ + nsSessionStorageEntry *entry = mItems.GetEntry(aKey); + nsIDOMStorageItem* item = nsnull; + if (entry) { + if (aCallerSecure || !entry->mItem->IsSecure()) { + item = entry->mItem; + } + } + else if (UseDB()) { + PRBool secure; + nsAutoString value; + nsresult rv = GetDBValue(aKey, value, &secure); + // return null if access isn't allowed or the key wasn't found + if (rv == NS_ERROR_DOM_SECURITY_ERR || rv == NS_ERROR_DOM_NOT_FOUND_ERR || + (!aCallerSecure && secure)) + return nsnull; + + *aResult = rv; + NS_ENSURE_SUCCESS(rv, nsnull); + + nsRefPtr<nsDOMStorageItem> newitem = + new nsDOMStorageItem(this, aKey, value, secure); + if (newitem && (entry = mItems.PutEntry(aKey))) { + item = entry->mItem = newitem; + } + else { + *aResult = NS_ERROR_OUT_OF_MEMORY; + } + } + return item; +} + +nsresult +DOMStorageImpl::SetValue(bool aIsCallerSecure, const nsAString& aKey, + const nsAString& aData, nsAString& aOldValue) +{ + if (aKey.IsEmpty()) + return NS_OK; + + nsresult rv; + nsString oldValue; + SetDOMStringToNull(oldValue); + + // First store the value to the database, we need to do this before we update + // the mItems cache. SetDBValue is using the old cached value to decide + // on quota checking. + if (UseDB()) { + rv = SetDBValue(aKey, aData, aIsCallerSecure); + NS_ENSURE_SUCCESS(rv, rv); + } + + nsSessionStorageEntry *entry = mItems.GetEntry(aKey); + if (entry) { + if (entry->mItem->IsSecure() && !aIsCallerSecure) { + return NS_ERROR_DOM_SECURITY_ERR; + } + oldValue = entry->mItem->GetValueInternal(); + entry->mItem->SetValueInternal(aData); + } + else { + nsRefPtr<nsDOMStorageItem> newitem = + new nsDOMStorageItem(this, aKey, aData, aIsCallerSecure); + if (!newitem) + return NS_ERROR_OUT_OF_MEMORY; + entry = mItems.PutEntry(aKey); + NS_ENSURE_TRUE(entry, NS_ERROR_OUT_OF_MEMORY); + entry->mItem = newitem; + } + aOldValue = oldValue; + return NS_OK; +} + +nsresult +DOMStorageImpl::RemoveValue(bool aCallerSecure, const nsAString& aKey, + nsAString& aOldValue) +{ + if (!CacheStoragePermissions()) + return NS_ERROR_DOM_SECURITY_ERR; + + nsString oldValue; + nsSessionStorageEntry *entry = mItems.GetEntry(aKey); + + if (entry && entry->mItem->IsSecure() && !aCallerSecure) { + return NS_ERROR_DOM_SECURITY_ERR; + } + + if (UseDB()) { +#ifdef MOZ_STORAGE + nsresult rv = InitDB(); + NS_ENSURE_SUCCESS(rv, rv); + + nsAutoString value; + PRBool secureItem; + rv = GetDBValue(aKey, value, &secureItem); + NS_ENSURE_SUCCESS(rv, rv); + if (!aCallerSecure && secureItem) + return NS_ERROR_DOM_SECURITY_ERR; + + oldValue = value; + + rv = gStorageDB->RemoveKey(this, aKey, !IsOfflineAllowed(mDomain), + aKey.Length() + value.Length()); + NS_ENSURE_SUCCESS(rv, rv); + + // Before bug 536544 got fixed we were dropping mItemsCached flag here +#endif + } + else if (entry) { + // clear string as StorageItems may be referencing this item + oldValue = entry->mItem->GetValueInternal(); + entry->mItem->ClearValue(); + } + + if (entry) { + mItems.RawRemoveEntry(entry); + } + aOldValue = oldValue; + return NS_OK; +} + +PR_STATIC_CALLBACK(PLDHashOperator) +CheckSecure(nsSessionStorageEntry* aEntry, void* userArg) +{ + PRBool* secure = (PRBool*)userArg; + if (aEntry->mItem->IsSecure()) { + *secure = PR_TRUE; + return PL_DHASH_STOP; + } + + return PL_DHASH_NEXT; +} + +nsresult +DOMStorageImpl::Clear(bool aCallerSecure, PRInt32* aOldCount) +{ + if (UseDB()) + CacheKeysFromDB(); + + PRInt32 oldCount = mItems.Count(); + + PRBool foundSecureItem = PR_FALSE; + mItems.EnumerateEntries(CheckSecure, &foundSecureItem); + + if (foundSecureItem && !aCallerSecure) { + return NS_ERROR_DOM_SECURITY_ERR; + } + +#ifdef MOZ_STORAGE + if (UseDB()) { + nsresult rv = InitDB(); + NS_ENSURE_SUCCESS(rv, rv); + + rv = gStorageDB->ClearStorage(this); + NS_ENSURE_SUCCESS(rv, rv); + } +#endif + + *aOldCount = oldCount; + mItems.Clear(); + return NS_OK; +} + +nsDOMStorage::nsDOMStorage() + : mStorageType(nsPIDOMStorage::Unknown) + , mEventBroadcaster(nsnull) +{ + mSecurityChecker = this; + +#ifdef MOZ_IPC + if (XRE_GetProcessType() != GeckoProcessType_Default) + mStorageImpl = new StorageChild(this); + else +#endif + mStorageImpl = new DOMStorageImpl(this); +} + +nsDOMStorage::nsDOMStorage(nsDOMStorage& aThat) + : mStorageType(aThat.mStorageType) + , mEventBroadcaster(nsnull) +{ + mSecurityChecker = this; + +#ifdef MOZ_IPC + if (XRE_GetProcessType() != GeckoProcessType_Default) { + StorageChild* other = static_cast<StorageChild*>(aThat.mStorageImpl.get()); + mStorageImpl = new StorageChild(this, *other); + } else +#endif + { + DOMStorageImpl* other = static_cast<DOMStorageImpl*>(aThat.mStorageImpl.get()); + mStorageImpl = new DOMStorageImpl(this, *other); + } +} + nsDOMStorage::~nsDOMStorage() { - if (nsDOMStorageManager::gStorageManager) - nsDOMStorageManager::gStorageManager->RemoveFromStoragesHash(this); } static nsresult GetDomainURI(nsIPrincipal *aPrincipal, PRBool aIncludeDomain, nsIURI **_domain) { nsCOMPtr<nsIURI> uri; @@ -640,125 +1437,51 @@ GetDomainURI(nsIPrincipal *aPrincipal, P nsresult nsDOMStorage::InitAsSessionStorage(nsIPrincipal *aPrincipal, const nsSubstring &aDocumentURI) { nsCOMPtr<nsIURI> domainURI; nsresult rv = GetDomainURI(aPrincipal, PR_TRUE, getter_AddRefs(domainURI)); NS_ENSURE_SUCCESS(rv, rv); - // No need to check for a return value. If this would fail we would not get - // here as we call GetPrincipalURIAndHost (nsDOMStorage.cpp:88) from - // nsDOMStorage::CanUseStorage before we query the storage manager for a new - // sessionStorage. It calls GetAsciiHost on innermost URI. If it fails, we - // won't get to InitAsSessionStorage. - domainURI->GetAsciiHost(mDomain); - mDocumentURI = aDocumentURI; -#ifdef MOZ_STORAGE - mUseDB = PR_FALSE; - mScopeDBKey.Truncate(); - mQuotaDomainDBKey.Truncate(); -#endif - mStorageType = SessionStorage; + + mStorageImpl->InitAsSessionStorage(domainURI); return NS_OK; } nsresult nsDOMStorage::InitAsLocalStorage(nsIPrincipal *aPrincipal, const nsSubstring &aDocumentURI) { nsCOMPtr<nsIURI> domainURI; nsresult rv = GetDomainURI(aPrincipal, PR_FALSE, getter_AddRefs(domainURI)); NS_ENSURE_SUCCESS(rv, rv); - // No need to check for a return value. If this would fail we would not get - // here as we call GetPrincipalURIAndHost (nsDOMStorage.cpp:88) from - // nsDOMStorage::CanUseStorage before we query the storage manager for a new - // localStorage. It calls GetAsciiHost on innermost URI. If it fails, we won't - // get to InitAsLocalStorage. Actually, mDomain will get replaced with - // mPrincipal in bug 455070. It is not even used for localStorage. - domainURI->GetAsciiHost(mDomain); - mDocumentURI = aDocumentURI; -#ifdef MOZ_STORAGE - nsDOMStorageDBWrapper::CreateOriginScopeDBKey(domainURI, mScopeDBKey); - - // XXX Bug 357323, we have to solve the issue how to define - // origin for file URLs. In that case CreateOriginScopeDBKey - // fails (the result is empty) and we must avoid database use - // in that case because it produces broken entries w/o owner. - mUseDB = !mScopeDBKey.IsEmpty(); - - nsDOMStorageDBWrapper::CreateQuotaDomainDBKey(mDomain, - PR_TRUE, PR_FALSE, mQuotaDomainDBKey); - nsDOMStorageDBWrapper::CreateQuotaDomainDBKey(mDomain, - PR_TRUE, PR_TRUE, mQuotaETLDplus1DomainDBKey); -#endif - mStorageType = LocalStorage; + bool canUseChromePersist = false; nsCOMPtr<nsIURI> URI; if (NS_SUCCEEDED(aPrincipal->GetURI(getter_AddRefs(URI))) && URI) { - mCanUseChromePersist = URICanUseChromePersist(URI); + canUseChromePersist = URICanUseChromePersist(URI); } - - RegisterObservers(); - + + mStorageImpl->InitAsLocalStorage(domainURI, canUseChromePersist); return NS_OK; } nsresult nsDOMStorage::InitAsGlobalStorage(const nsACString &aDomainDemanded) { - mDomain = aDomainDemanded; -#ifdef MOZ_STORAGE - nsDOMStorageDBWrapper::CreateDomainScopeDBKey(aDomainDemanded, mScopeDBKey); - - // XXX Bug 357323, we have to solve the issue how to define - // origin for file URLs. In that case CreateOriginScopeDBKey - // fails (the result is empty) and we must avoid database use - // in that case because it produces broken entries w/o owner. - if (!(mUseDB = !mScopeDBKey.IsEmpty())) - mScopeDBKey.AppendLiteral(":"); - - nsDOMStorageDBWrapper::CreateQuotaDomainDBKey(aDomainDemanded, - PR_TRUE, PR_FALSE, mQuotaDomainDBKey); - nsDOMStorageDBWrapper::CreateQuotaDomainDBKey(aDomainDemanded, - PR_TRUE, PR_TRUE, mQuotaETLDplus1DomainDBKey); -#endif - mStorageType = GlobalStorage; mEventBroadcaster = this; - - RegisterObservers(); - - return NS_OK; -} - -static PLDHashOperator -CopyStorageItems(nsSessionStorageEntry* aEntry, void* userArg) -{ - nsDOMStorage* newstorage = static_cast<nsDOMStorage*>(userArg); - - newstorage->SetItem(aEntry->GetKey(), aEntry->mItem->GetValueInternal()); - - if (aEntry->mItem->IsSecure()) { - newstorage->SetSecure(aEntry->GetKey(), PR_TRUE); - } - - return PL_DHASH_NEXT; -} - -nsresult -nsDOMStorage::CloneFrom(nsDOMStorage* aThat) -{ - aThat->mItems.EnumerateEntries(CopyStorageItems, this); + mStorageImpl->InitAsGlobalStorage(aDomainDemanded); return NS_OK; } //static PRBool nsDOMStorage::CanUseStorage(PRPackedBool* aSessionOnly) { // check if the calling domain can use storage. Downgrade to session @@ -824,17 +1547,17 @@ nsDOMStorage::CanUseStorage(PRPackedBool } PRBool nsDOMStorage::CacheStoragePermissions() { // Bug 488446, disallowing storage use when in session only mode. // This is temporary fix before we find complete solution for storage // behavior in private browsing mode or session-only cookies mode. - if (!CanUseStorage(&mSessionOnly)) + if (!CanUseStorage(&mStorageImpl->mSessionOnly)) return PR_FALSE; nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager(); if (!ssm) return PR_FALSE; nsCOMPtr<nsIPrincipal> subjectPrincipal; ssm->GetSubjectPrincipal(getter_AddRefs(subjectPrincipal)); @@ -847,176 +1570,47 @@ nsDOMStorage::CacheStoragePermissions() PRBool nsDOMStorage::URICanUseChromePersist(nsIURI* aURI) { PRBool isAbout; return (NS_SUCCEEDED(aURI->SchemeIs("moz-safe-about", &isAbout)) && isAbout) || (NS_SUCCEEDED(aURI->SchemeIs("about", &isAbout)) && isAbout); } -bool -nsDOMStorage::CanUseChromePersist() -{ - return mCanUseChromePersist; -} - -class ItemCounterState -{ -public: - ItemCounterState(PRBool aIsCallerSecure) - : mIsCallerSecure(aIsCallerSecure), mCount(0) - { - } - - PRBool mIsCallerSecure; - PRBool mCount; -private: - ItemCounterState(); // Not to be implemented -}; - -static PLDHashOperator -ItemCounter(nsSessionStorageEntry* aEntry, void* userArg) -{ - ItemCounterState *state = (ItemCounterState *)userArg; - - if (state->mIsCallerSecure || !aEntry->mItem->IsSecure()) { - ++state->mCount; - } - - return PL_DHASH_NEXT; -} - NS_IMETHODIMP nsDOMStorage::GetLength(PRUint32 *aLength) { if (!CacheStoragePermissions()) return NS_ERROR_DOM_SECURITY_ERR; - - // Force reload of items from database. This ensures sync localStorages for - // same origins among different windows. - mItemsCached = PR_FALSE; - if (UseDB()) - CacheKeysFromDB(); - - ItemCounterState state(IsCallerSecure()); - - mItems.EnumerateEntries(ItemCounter, &state); - - *aLength = state.mCount; - - return NS_OK; -} - -class IndexFinderData -{ -public: - IndexFinderData(PRBool aIsCallerSecure, PRUint32 aWantedIndex) - : mIsCallerSecure(aIsCallerSecure), mIndex(0), mWantedIndex(aWantedIndex), - mItem(nsnull) - { - } - - PRBool mIsCallerSecure; - PRUint32 mIndex; - PRUint32 mWantedIndex; - nsSessionStorageEntry *mItem; - -private: - IndexFinderData(); // Not to be implemented -}; - -static PLDHashOperator -IndexFinder(nsSessionStorageEntry* aEntry, void* userArg) -{ - IndexFinderData *data = (IndexFinderData *)userArg; - - if (data->mIndex == data->mWantedIndex && - (data->mIsCallerSecure || !aEntry->mItem->IsSecure())) { - data->mItem = aEntry; - - return PL_DHASH_STOP; - } - - ++data->mIndex; - - return PL_DHASH_NEXT; + + return mStorageImpl->GetLength(IsCallerSecure(), aLength); } NS_IMETHODIMP nsDOMStorage::Key(PRUint32 aIndex, nsAString& aKey) { - // XXXjst: This is as retarded as the DOM spec is, takes an unsigned - // int, but the spec talks about what to do if a negative value is - // passed in. - - // XXX: This does a linear search for the key at index, which would - // suck if there's a large numer of indexes. Do we care? If so, - // maybe we need to have a lazily populated key array here or - // something? - if (!CacheStoragePermissions()) return NS_ERROR_DOM_SECURITY_ERR; - if (UseDB()) - CacheKeysFromDB(); - - IndexFinderData data(IsCallerSecure(), aIndex); - mItems.EnumerateEntries(IndexFinder, &data); - - if (!data.mItem) { - // aIndex was larger than the number of accessible keys. Throw. - return NS_ERROR_DOM_INDEX_SIZE_ERR; - } - - aKey = data.mItem->GetKey(); - - return NS_OK; + return mStorageImpl->GetKey(IsCallerSecure(), aIndex, aKey); } nsIDOMStorageItem* nsDOMStorage::GetNamedItem(const nsAString& aKey, nsresult* aResult) { if (!CacheStoragePermissions()) { *aResult = NS_ERROR_DOM_SECURITY_ERR; return nsnull; } *aResult = NS_OK; if (aKey.IsEmpty()) return nsnull; - - nsSessionStorageEntry *entry = mItems.GetEntry(aKey); - nsIDOMStorageItem* item = nsnull; - if (entry) { - if (IsCallerSecure() || !entry->mItem->IsSecure()) { - item = entry->mItem; - } - } - else if (UseDB()) { - PRBool secure; - nsAutoString value; - nsresult rv = GetDBValue(aKey, value, &secure); - // return null if access isn't allowed or the key wasn't found - if (rv == NS_ERROR_DOM_SECURITY_ERR || rv == NS_ERROR_DOM_NOT_FOUND_ERR) - return nsnull; - - *aResult = rv; - NS_ENSURE_SUCCESS(rv, nsnull); - - nsRefPtr<nsDOMStorageItem> newitem = - new nsDOMStorageItem(this, aKey, value, secure); - if (newitem && (entry = mItems.PutEntry(aKey))) { - item = entry->mItem = newitem; - } - else { - *aResult = NS_ERROR_OUT_OF_MEMORY; - } - } - - return item; + + return mStorageImpl->GetValue(IsCallerSecure(), aKey, aResult); } nsresult nsDOMStorage::GetItem(const nsAString& aKey, nsAString &aData) { nsresult rv; // IMPORTANT: @@ -1052,349 +1646,71 @@ nsDOMStorage::GetItem(const nsAString& a } NS_IMETHODIMP nsDOMStorage::SetItem(const nsAString& aKey, const nsAString& aData) { if (!CacheStoragePermissions()) return NS_ERROR_DOM_SECURITY_ERR; - if (aKey.IsEmpty()) - return NS_OK; - - nsresult rv; nsString oldValue; - SetDOMStringToNull(oldValue); - - // First store the value to the database, we need to do this before we update - // the mItems cache. SetDBValue is using the old cached value to decide - // on quota checking. - bool isCallerSecure = IsCallerSecure(); - if (UseDB()) { - rv = SetDBValue(aKey, aData, isCallerSecure); - NS_ENSURE_SUCCESS(rv, rv); - } - - nsSessionStorageEntry *entry = mItems.GetEntry(aKey); - if (entry) { - if (entry->mItem->IsSecure() && !isCallerSecure) { - return NS_ERROR_DOM_SECURITY_ERR; - } - oldValue = entry->mItem->GetValueInternal(); - entry->mItem->SetValueInternal(aData); - } - else { - nsRefPtr<nsDOMStorageItem> newitem = - new nsDOMStorageItem(this, aKey, aData, isCallerSecure); - if (!newitem) - return NS_ERROR_OUT_OF_MEMORY; - entry = mItems.PutEntry(aKey); - NS_ENSURE_TRUE(entry, NS_ERROR_OUT_OF_MEMORY); - entry->mItem = newitem; - } + nsresult rv = mStorageImpl->SetValue(IsCallerSecure(), aKey, aData, oldValue); + if (NS_FAILED(rv)) + return rv; if ((oldValue != aData || mStorageType == GlobalStorage) && mEventBroadcaster) mEventBroadcaster->BroadcastChangeNotification(aKey, oldValue, aData); return NS_OK; } NS_IMETHODIMP nsDOMStorage::RemoveItem(const nsAString& aKey) { if (!CacheStoragePermissions()) return NS_ERROR_DOM_SECURITY_ERR; if (aKey.IsEmpty()) return NS_OK; nsString oldValue; - nsSessionStorageEntry *entry = mItems.GetEntry(aKey); - - if (entry && entry->mItem->IsSecure() && !IsCallerSecure()) { - return NS_ERROR_DOM_SECURITY_ERR; - } - - if (UseDB()) { -#ifdef MOZ_STORAGE - nsresult rv = InitDB(); - NS_ENSURE_SUCCESS(rv, rv); - - nsAutoString value; - PRBool secureItem; - rv = GetDBValue(aKey, value, &secureItem); - if (rv == NS_ERROR_DOM_NOT_FOUND_ERR) - return NS_OK; - NS_ENSURE_SUCCESS(rv, rv); - - oldValue = value; - - rv = gStorageDB->RemoveKey(this, aKey, !IsOfflineAllowed(mDomain), - aKey.Length() + value.Length()); - NS_ENSURE_SUCCESS(rv, rv); - - // Before bug 536544 got fixed we were dropping mItemsCached flag here -#endif - } - else if (entry) { - // clear string as StorageItems may be referencing this item - oldValue = entry->mItem->GetValueInternal(); - entry->mItem->ClearValue(); - } - - if (entry) { - mItems.RawRemoveEntry(entry); - } + nsresult rv = mStorageImpl->RemoveValue(IsCallerSecure(), aKey, oldValue); + if (rv == NS_ERROR_DOM_NOT_FOUND_ERR) + return NS_OK; + if (NS_FAILED(rv)) + return rv; if ((!oldValue.IsEmpty() && mStorageType != GlobalStorage) && mEventBroadcaster) { nsAutoString nullString; SetDOMStringToNull(nullString); mEventBroadcaster->BroadcastChangeNotification(aKey, oldValue, nullString); } return NS_OK; } -PR_STATIC_CALLBACK(PLDHashOperator) -CheckSecure(nsSessionStorageEntry* aEntry, void* userArg) -{ - PRBool* secure = (PRBool*)userArg; - if (aEntry->mItem->IsSecure()) { - *secure = PR_TRUE; - return PL_DHASH_STOP; - } - - return PL_DHASH_NEXT; -} - nsresult nsDOMStorage::Clear() { if (!CacheStoragePermissions()) return NS_ERROR_DOM_SECURITY_ERR; - if (UseDB()) - CacheKeysFromDB(); - - PRInt32 oldCount = mItems.Count(); - - PRBool foundSecureItem = PR_FALSE; - mItems.EnumerateEntries(CheckSecure, &foundSecureItem); - - if (foundSecureItem && !IsCallerSecure()) { - return NS_ERROR_DOM_SECURITY_ERR; - } - -#ifdef MOZ_STORAGE - if (UseDB()) { - nsresult rv = InitDB(); - NS_ENSURE_SUCCESS(rv, rv); - - rv = gStorageDB->ClearStorage(this); - NS_ENSURE_SUCCESS(rv, rv); - } -#endif - - mItems.Clear(); - + PRInt32 oldCount; + nsresult rv = mStorageImpl->Clear(IsCallerSecure(), &oldCount); + if (NS_FAILED(rv)) + return rv; + if (oldCount && mEventBroadcaster) { nsAutoString nullString; SetDOMStringToNull(nullString); mEventBroadcaster->BroadcastChangeNotification(nullString, nullString, nullString); } return NS_OK; } -nsresult -nsDOMStorage::InitDB() -{ -#ifdef MOZ_STORAGE - if (!gStorageDB) { - gStorageDB = new nsDOMStorageDBWrapper(); - if (!gStorageDB) - return NS_ERROR_OUT_OF_MEMORY; - - nsresult rv = gStorageDB->Init(); - if (NS_FAILED(rv)) { - // Failed to initialize the DB, delete it and null out the - // pointer so we don't end up attempting to use an - // un-initialized DB later on. - - delete gStorageDB; - gStorageDB = nsnull; - - return rv; - } - } -#endif - - return NS_OK; -} - -nsresult -nsDOMStorage::CacheKeysFromDB() -{ -#ifdef MOZ_STORAGE - // cache all the keys in the hash. This is used by the Length and Key methods - // use this cache for better performance. The disadvantage is that the - // order may break if someone changes the keys in the database directly. - if (!mItemsCached) { - nsresult rv = InitDB(); - NS_ENSURE_SUCCESS(rv, rv); - - mItems.Clear(); - - rv = gStorageDB->GetAllKeys(this, &mItems); - NS_ENSURE_SUCCESS(rv, rv); - - mItemsCached = PR_TRUE; - } -#endif - - return NS_OK; -} - -nsresult -nsDOMStorage::GetCachedValue(const nsAString& aKey, nsAString& aValue, - PRBool* aSecure) -{ - aValue.Truncate(); - *aSecure = PR_FALSE; - - nsSessionStorageEntry *entry = mItems.GetEntry(aKey); - if (!entry) - return NS_ERROR_NOT_AVAILABLE; - - aValue = entry->mItem->GetValueInternal(); - *aSecure = entry->mItem->IsSecure(); - - return NS_OK; -} - -nsresult -nsDOMStorage::GetDBValue(const nsAString& aKey, nsAString& aValue, - PRBool* aSecure) -{ - aValue.Truncate(); - -#ifdef MOZ_STORAGE - if (!UseDB()) - return NS_OK; - - nsresult rv = InitDB(); - NS_ENSURE_SUCCESS(rv, rv); - - nsAutoString value; - rv = gStorageDB->GetKeyValue(this, aKey, value, aSecure); - - if (rv == NS_ERROR_DOM_NOT_FOUND_ERR && mStorageType != GlobalStorage) { - SetDOMStringToNull(aValue); - } - - if (NS_FAILED(rv)) - return rv; - - if (!IsCallerSecure() && *aSecure) { - return NS_ERROR_DOM_SECURITY_ERR; - } - - aValue.Assign(value); -#endif - - return NS_OK; -} - -nsresult -nsDOMStorage::SetDBValue(const nsAString& aKey, - const nsAString& aValue, - PRBool aSecure) -{ -#ifdef MOZ_STORAGE - if (!UseDB()) - return NS_OK; - - nsresult rv = InitDB(); - NS_ENSURE_SUCCESS(rv, rv); - - PRInt32 offlineAppPermission; - PRInt32 quota; - PRInt32 warnQuota; - offlineAppPermission = GetQuota(mDomain, "a, &warnQuota, - CanUseChromePersist()); - - PRInt32 usage; - rv = gStorageDB->SetKey(this, aKey, aValue, aSecure, quota, - !IS_PERMISSION_ALLOWED(offlineAppPermission), - &usage); - NS_ENSURE_SUCCESS(rv, rv); - - // Before bug 536544 got fixed we were dropping mItemsCached flag here - - if (warnQuota >= 0 && usage > warnQuota) { - // try to include the window that exceeded the warn quota - nsCOMPtr<nsIDOMWindow> window; - JSContext *cx; - nsCOMPtr<nsIJSContextStack> stack = - do_GetService("@mozilla.org/js/xpc/ContextStack;1"); - if (stack && NS_SUCCEEDED(stack->Peek(&cx)) && cx) { - nsCOMPtr<nsIScriptContext> scriptContext; - scriptContext = GetScriptContextFromJSContext(cx); - if (scriptContext) { - window = do_QueryInterface(scriptContext->GetGlobalObject()); - } - } - - nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService(); - os->NotifyObservers(window, "dom-storage-warn-quota-exceeded", - NS_ConvertUTF8toUTF16(mDomain).get()); - } - -#endif - - return NS_OK; -} - -nsresult -nsDOMStorage::SetSecure(const nsAString& aKey, PRBool aSecure) -{ -#ifdef MOZ_STORAGE - if (UseDB()) { - nsresult rv = InitDB(); - NS_ENSURE_SUCCESS(rv, rv); - - return gStorageDB->SetSecure(this, aKey, aSecure); - } -#else - return NS_ERROR_NOT_IMPLEMENTED; -#endif - - nsSessionStorageEntry *entry = mItems.GetEntry(aKey); - NS_ASSERTION(entry, "Don't use SetSecure() with nonexistent keys!"); - - if (entry) { - entry->mItem->SetSecureInternal(aSecure); - } - - return NS_OK; -} - -static PLDHashOperator -ClearStorageItem(nsSessionStorageEntry* aEntry, void* userArg) -{ - aEntry->mItem->SetValueInternal(EmptyString()); - return PL_DHASH_NEXT; -} - -void -nsDOMStorage::ClearAll() -{ - mItems.EnumerateEntries(ClearStorageItem, nsnull); - mItemsCached = PR_FALSE; -} - already_AddRefed<nsIDOMStorage> nsDOMStorage::Clone() { NS_ASSERTION(PR_FALSE, "Old DOMStorage doesn't implement cloning"); return nsnull; } already_AddRefed<nsIDOMStorage> @@ -1405,46 +1721,26 @@ nsDOMStorage::Fork(const nsSubstring &aD } PRBool nsDOMStorage::IsForkOf(nsIDOMStorage* aThat) { NS_ASSERTION(PR_FALSE, "Old DOMStorage doesn't implement forking"); return PR_FALSE; } -struct KeysArrayBuilderStruct +nsresult +nsDOMStorage::CloneFrom(nsDOMStorage* aThat) { - PRBool callerIsSecure; - nsTArray<nsString> *keys; -}; - -static PLDHashOperator -KeysArrayBuilder(nsSessionStorageEntry* aEntry, void* userArg) -{ - KeysArrayBuilderStruct *keystruct = (KeysArrayBuilderStruct *)userArg; - - if (keystruct->callerIsSecure || !aEntry->mItem->IsSecure()) - keystruct->keys->AppendElement(aEntry->GetKey()); - - return PL_DHASH_NEXT; + return mStorageImpl->CloneFrom(IsCallerSecure(), aThat->mStorageImpl); } nsTArray<nsString> * nsDOMStorage::GetKeys() { - if (UseDB()) - CacheKeysFromDB(); - - KeysArrayBuilderStruct keystruct; - keystruct.callerIsSecure = IsCallerSecure(); - keystruct.keys = new nsTArray<nsString>(); - if (keystruct.keys) - mItems.EnumerateEntries(KeysArrayBuilder, &keystruct); - - return keystruct.keys; + return mStorageImpl->GetKeys(IsCallerSecure()); } nsIPrincipal* nsDOMStorage::Principal() { return nsnull; } @@ -1472,17 +1768,17 @@ nsDOMStorage::CanAccess(nsIPrincipal *aP return PR_TRUE; nsCAutoString domain; nsCOMPtr<nsIURI> unused; nsresult rv = GetPrincipalURIAndHost(aPrincipal, getter_AddRefs(unused), domain); NS_ENSURE_SUCCESS(rv, PR_FALSE); - return domain.Equals(mDomain); + return domain.Equals(mStorageImpl->mDomain); } nsPIDOMStorage::nsDOMStorageType nsDOMStorage::StorageType() { return mStorageType; } @@ -1497,95 +1793,17 @@ nsDOMStorage::BroadcastChangeNotificatio return; } // Fire off a notification that a storage object changed. If the // storage object is a session storage object, we don't pass a // domain, but if it's a global storage object we do. observerService->NotifyObservers((nsIDOMStorageObsolete *)this, "dom-storage-changed", - NS_ConvertUTF8toUTF16(mDomain).get()); -} - -nsresult -nsDOMStorage::MaybeCommitTemporaryTable(bool force) -{ -#ifdef MOZ_STORAGE - if (!UseDB()) - return NS_OK; - - if (!mLoadedTemporaryTable) - return NS_OK; - - // If we are not forced to flush (e.g. on shutdown) then don't flush if the - // last table access is less then 5 seconds ago or the table itself is not - // older then 30 secs - if (!force && - ((TimeStamp::Now() - mLastTemporaryTableAccessTime).ToSeconds() < - NS_DOMSTORAGE_MAXIMUM_TEMPTABLE_INACTIVITY_TIME) && - ((TimeStamp::Now() - mTemporaryTableAge).ToSeconds() < - NS_DOMSTORAGE_MAXIMUM_TEMPTABLE_AGE)) - return NS_OK; - - return gStorageDB->FlushAndDeleteTemporaryTableForStorage(this); -#endif - - return NS_OK; -} - -nsresult -nsDOMStorage::RegisterObservers() -{ - nsCOMPtr<nsIObserverService> obsserv = mozilla::services::GetObserverService(); - if (obsserv) { - obsserv->AddObserver(this, "profile-before-change", PR_TRUE); - obsserv->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, PR_TRUE); - obsserv->AddObserver(this, NS_DOMSTORAGE_FLUSH_TIMER_OBSERVER, PR_TRUE); - } - return NS_OK; -} - -bool -nsDOMStorage::WasTemporaryTableLoaded() -{ - return mLoadedTemporaryTable; -} - -void -nsDOMStorage::SetTemporaryTableLoaded(bool loaded) -{ - if (loaded) { - mLastTemporaryTableAccessTime = TimeStamp::Now(); - if (!mLoadedTemporaryTable) - mTemporaryTableAge = mLastTemporaryTableAccessTime; - } - - mLoadedTemporaryTable = loaded; -} - -NS_IMETHODIMP -nsDOMStorage::Observe(nsISupports *subject, - const char *topic, - const PRUnichar *data) -{ - bool isProfileBeforeChange = !strcmp(topic, "profile-before-change"); - bool isXPCOMShutdown = !strcmp(topic, NS_XPCOM_SHUTDOWN_OBSERVER_ID); - bool isFlushTimer = !strcmp(topic, NS_DOMSTORAGE_FLUSH_TIMER_OBSERVER); - - if (isXPCOMShutdown || isProfileBeforeChange || isFlushTimer) { - nsresult rv = MaybeCommitTemporaryTable(isXPCOMShutdown || isProfileBeforeChange); - if (NS_FAILED(rv)) { - NS_WARNING("DOMStorage: temporary table commit failed"); - } - - return NS_OK; - } - - NS_WARNING("Unrecognized topic in nsDOMStorage::Observe"); - return NS_OK; + NS_ConvertUTF8toUTF16(mStorageImpl->mDomain).get()); } // // nsDOMStorage2 // NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMStorage2) NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDOMStorage2) @@ -2003,33 +2221,33 @@ NS_NewDOMStorageList(nsIDOMStorageList** NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMStorageItem) NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDOMStorageItem) { tmp->mStorage = nsnull; } NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDOMStorageItem) { - cb.NoteXPCOMChild((nsIDOMStorageObsolete*) tmp->mStorage); + cb.NoteXPCOMChild((nsISupports*) tmp->mStorage); } NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(nsDOMStorageItem, nsIDOMStorageItem) NS_IMPL_CYCLE_COLLECTING_RELEASE_AMBIGUOUS(nsDOMStorageItem, nsIDOMStorageItem) DOMCI_DATA(StorageItem, nsDOMStorageItem) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMStorageItem) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMStorageItem) NS_INTERFACE_MAP_ENTRY(nsIDOMStorageItem) NS_INTERFACE_MAP_ENTRY(nsIDOMToString) NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(StorageItem) NS_INTERFACE_MAP_END -nsDOMStorageItem::nsDOMStorageItem(nsDOMStorage* aStorage, +nsDOMStorageItem::nsDOMStorageItem(DOMStorageBase* aStorage, const nsAString& aKey, const nsAString& aValue, PRBool aSecure) : mSecure(aSecure), mKey(aKey), mValue(aValue), mStorage(aStorage) { @@ -2073,21 +2291,22 @@ nsDOMStorageItem::SetSecure(PRBool aSecu NS_IMETHODIMP nsDOMStorageItem::GetValue(nsAString& aValue) { if (!mStorage->CacheStoragePermissions()) return NS_ERROR_DOM_INVALID_ACCESS_ERR; if (mStorage->UseDB()) { - // GetDBValue checks the secure state so no need to do it here PRBool secure; nsresult rv = mStorage->GetDBValue(mKey, aValue, &secure); if (rv == NS_ERROR_DOM_NOT_FOUND_ERR) return NS_OK; + if (NS_SUCCEEDED(rv) && !IsCallerSecure() && secure) + return NS_ERROR_DOM_SECURITY_ERR; return rv; } if (IsSecure() && !IsCallerSecure()) { return NS_ERROR_DOM_SECURITY_ERR; } aValue = mValue;
--- a/dom/src/storage/nsDOMStorage.h +++ b/dom/src/storage/nsDOMStorage.h @@ -75,25 +75,34 @@ class nsDOMStorage; class nsIDOMStorage; class nsDOMStorageItem; using mozilla::TimeStamp; using mozilla::TimeDuration; +namespace mozilla { +namespace dom { +class StorageParent; +} +} +using mozilla::dom::StorageParent; + +class DOMStorageImpl; + class nsDOMStorageEntry : public nsVoidPtrHashKey { public: nsDOMStorageEntry(KeyTypePointer aStr); nsDOMStorageEntry(const nsDOMStorageEntry& aToCopy); ~nsDOMStorageEntry(); // weak reference so that it can be deleted when no longer used - nsDOMStorage* mStorage; + DOMStorageImpl* mStorage; }; class nsSessionStorageEntry : public nsStringHashKey { public: nsSessionStorageEntry(KeyTypePointer aStr); nsSessionStorageEntry(const nsSessionStorageEntry& aToCopy); ~nsSessionStorageEntry(); @@ -111,18 +120,18 @@ public: // nsIDOMStorageManager NS_DECL_NSIDOMSTORAGEMANAGER // nsIObserver NS_DECL_NSIOBSERVER nsDOMStorageManager(); - void AddToStoragesHash(nsDOMStorage* aStorage); - void RemoveFromStoragesHash(nsDOMStorage* aStorage); + void AddToStoragesHash(DOMStorageImpl* aStorage); + void RemoveFromStoragesHash(DOMStorageImpl* aStorage); nsresult ClearAllStorages(); PRBool InPrivateBrowsingMode() { return mInPrivateBrowsing; } static nsresult Initialize(); static nsDOMStorageManager* GetInstance(); static void Shutdown(); @@ -130,31 +139,235 @@ public: static nsDOMStorageManager* gStorageManager; protected: nsTHashtable<nsDOMStorageEntry> mStorages; PRBool mInPrivateBrowsing; }; +class DOMStorageBase : public nsISupports +{ +public: + DOMStorageBase(); + DOMStorageBase(DOMStorageBase&); + + virtual void InitAsSessionStorage(nsIURI* aDomainURI); + virtual void InitAsLocalStorage(nsIURI* aDomainURI, bool aCanUseChromePersist); + virtual void InitAsGlobalStorage(const nsACString& aDomainDemanded); + + virtual nsTArray<nsString>* GetKeys(bool aCallerSecure) = 0; + virtual nsresult GetLength(bool aCallerSecure, PRUint32* aLength) = 0; + virtual nsresult GetKey(bool aCallerSecure, PRUint32 aIndex, nsAString& aKey) = 0; + virtual nsIDOMStorageItem* GetValue(bool aCallerSecure, const nsAString& aKey, + nsresult* rv) = 0; + virtual nsresult SetValue(bool aCallerSecure, const nsAString& aKey, + const nsAString& aData, nsAString& aOldValue) = 0; + virtual nsresult RemoveValue(bool aCallerSecure, const nsAString& aKey, + nsAString& aOldValue) = 0; + virtual nsresult Clear(bool aCallerSecure, PRInt32* aOldCount) = 0; + + // If true, the contents of the storage should be stored in the + // database, otherwise this storage should act like a session + // storage. + // This call relies on mSessionOnly, and should only be used + // after a CacheStoragePermissions() call. See the comments + // for mSessionOnly below. + PRBool UseDB() { + return mUseDB; + } + + // retrieve the value and secure state corresponding to a key out of storage. + virtual nsresult + GetDBValue(const nsAString& aKey, + nsAString& aValue, + PRBool* aSecure) = 0; + + // set the value corresponding to a key in the storage. If + // aSecure is false, then attempts to modify a secure value + // throw NS_ERROR_DOM_INVALID_ACCESS_ERR + virtual nsresult + SetDBValue(const nsAString& aKey, + const nsAString& aValue, + PRBool aSecure) = 0; + + // set the value corresponding to a key as secure. + virtual nsresult + SetSecure(const nsAString& aKey, PRBool aSecure) = 0; + + virtual nsresult + CloneFrom(bool aCallerSecure, DOMStorageBase* aThat) = 0; + + // e.g. "moc.rab.oof.:" or "moc.rab.oof.:http:80" depending + // on association with a domain (globalStorage) or + // an origin (localStorage). + nsCString& GetScopeDBKey() {return mScopeDBKey;} + + // e.g. "moc.rab.%" - reversed eTLD+1 subpart of the domain or + // reversed offline application allowed domain. + nsCString& GetQuotaDomainDBKey(PRBool aOfflineAllowed) + { + return aOfflineAllowed ? mQuotaDomainDBKey : mQuotaETLDplus1DomainDBKey; + } + + virtual bool CacheStoragePermissions() = 0; + +protected: + friend class nsDOMStorageManager; + friend class nsDOMStorage; + + nsPIDOMStorage::nsDOMStorageType mStorageType; + + // true if the storage database should be used for values + PRPackedBool mUseDB; + + // true if the preferences indicates that this storage should be + // session only. This member is updated by + // CacheStoragePermissions(), using the current principal. + // CacheStoragePermissions() must be called at each entry point to + // make sure this stays up to date. + PRPackedBool mSessionOnly; + + // domain this store is associated with + nsCString mDomain; + + // keys are used for database queries. + // see comments of the getters bellow. + nsCString mScopeDBKey; + nsCString mQuotaETLDplus1DomainDBKey; + nsCString mQuotaDomainDBKey; + + bool mCanUseChromePersist; +}; + +class DOMStorageImpl : public DOMStorageBase + , public nsIObserver + , public nsSupportsWeakReference + +{ +public: + NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(DOMStorageImpl, nsIObserver) + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_NSIOBSERVER + + DOMStorageImpl(nsDOMStorage*); + DOMStorageImpl(nsDOMStorage*, DOMStorageImpl&); + ~DOMStorageImpl(); + + // Cross-process storage implementations never have InitAs(Session|Local|Global)Storage + // called, so the appropriate initialization needs to happen from the child. + void InitFromChild(bool aUseDB, bool aCanUseChromePersist, + const nsACString& aDomain, + const nsACString& aScopeDBKey, + const nsACString& aQuotaDomainDBKey, + const nsACString& aQuotaETLDplus1DomainDBKey, + PRUint32 aStorageType); + + virtual void InitAsSessionStorage(nsIURI* aDomainURI); + virtual void InitAsLocalStorage(nsIURI* aDomainURI, bool aCanUseChromePersist); + virtual void InitAsGlobalStorage(const nsACString& aDomainDemanded); + + PRBool SessionOnly() { + return mSessionOnly; + } + + virtual nsTArray<nsString>* GetKeys(bool aCallerSecure); + virtual nsresult GetLength(bool aCallerSecure, PRUint32* aLength); + virtual nsresult GetKey(bool aCallerSecure, PRUint32 aIndex, nsAString& aKey); + virtual nsIDOMStorageItem* GetValue(bool aCallerSecure, const nsAString& aKey, + nsresult* rv); + virtual nsresult SetValue(bool aCallerSecure, const nsAString& aKey, + const nsAString& aData, nsAString& aOldValue); + virtual nsresult RemoveValue(bool aCallerSecure, const nsAString& aKey, + nsAString& aOldValue); + virtual nsresult Clear(bool aCallerSecure, PRInt32* aOldCount); + + // cache the keys from the database for faster lookup + nsresult CacheKeysFromDB(); + + // Some privileged internal pages can use a persistent storage even in + // session-only or private-browsing modes. + bool CanUseChromePersist(); + + // retrieve the value and secure state corresponding to a key out of storage + // that has been cached in mItems hash table. + nsresult + GetCachedValue(const nsAString& aKey, + nsAString& aValue, + PRBool* aSecure); + + // retrieve the value and secure state corresponding to a key out of storage. + virtual nsresult + GetDBValue(const nsAString& aKey, + nsAString& aValue, + PRBool* aSecure); + + // set the value corresponding to a key in the storage. If + // aSecure is false, then attempts to modify a secure value + // throw NS_ERROR_DOM_INVALID_ACCESS_ERR + virtual nsresult + SetDBValue(const nsAString& aKey, + const nsAString& aValue, + PRBool aSecure); + + // set the value corresponding to a key as secure. + virtual nsresult + SetSecure(const nsAString& aKey, PRBool aSecure); + + // clear all values from the store + void ClearAll(); + + virtual nsresult + CloneFrom(bool aCallerSecure, DOMStorageBase* aThat); + + nsresult RegisterObservers(); + nsresult MaybeCommitTemporaryTable(bool force); + + bool WasTemporaryTableLoaded(); + void SetTemporaryTableLoaded(bool loaded); + + virtual bool CacheStoragePermissions(); + +private: +#ifdef MOZ_STORAGE + static nsDOMStorageDBWrapper* gStorageDB; +#endif + friend class nsDOMStorageManager; + friend class StorageParent; + + void Init(nsDOMStorage*); + + static nsresult InitDB(); + + // true if items from the database are cached + PRPackedBool mItemsCached; + + // the key->value item pairs + nsTHashtable<nsSessionStorageEntry> mItems; + + // Weak reference to the owning storage instance + nsDOMStorage* mOwner; + + bool mLoadedTemporaryTable; + TimeStamp mLastTemporaryTableAccessTime; + TimeStamp mTemporaryTableAge; +}; + class nsDOMStorage : public nsIDOMStorageObsolete, - public nsPIDOMStorage, - public nsIObserver, - public nsSupportsWeakReference + public nsPIDOMStorage { public: nsDOMStorage(); nsDOMStorage(nsDOMStorage& aThat); virtual ~nsDOMStorage(); NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsDOMStorage, nsIDOMStorageObsolete) NS_DECL_NSIDOMSTORAGEOBSOLETE - NS_DECL_NSIOBSERVER // Helpers for implementing nsIDOMStorage nsresult GetItem(const nsAString& key, nsAString& aData); nsresult Clear(); // nsPIDOMStorage virtual nsresult InitAsSessionStorage(nsIPrincipal *aPrincipal, const nsSubstring &aDocumentURI); virtual nsresult InitAsLocalStorage(nsIPrincipal *aPrincipal, const nsSubstring &aDocumentURI); @@ -165,167 +378,66 @@ public: virtual nsTArray<nsString> *GetKeys(); virtual nsIPrincipal* Principal(); virtual PRBool CanAccess(nsIPrincipal *aPrincipal); virtual nsDOMStorageType StorageType(); virtual void BroadcastChangeNotification(const nsSubstring &aKey, const nsSubstring &aOldValue, const nsSubstring &aNewValue); - // If true, the contents of the storage should be stored in the - // database, otherwise this storage should act like a session - // storage. - // This call relies on mSessionOnly, and should only be used - // after a CacheStoragePermissions() call. See the comments - // for mSessionOnly below. - PRBool UseDB() { - return mUseDB; - } - - PRBool SessionOnly() { - return mSessionOnly; - } - - // Some privileged internal pages can use a persistent storage even in - // session-only or private-browsing modes. - bool CanUseChromePersist(); - // Check whether storage may be used by the caller, and whether it // is session only. Returns true if storage may be used. static PRBool CanUseStorage(PRPackedBool* aSessionOnly); // Check whether this URI can use chrome persist storage. This kind of // storage can bypass cookies limits, private browsing and uses the offline // apps quota. static PRBool URICanUseChromePersist(nsIURI* aURI); // Check whether storage may be used. Updates mSessionOnly based on // the result of CanUseStorage. PRBool CacheStoragePermissions(); - // retrieve the value and secure state corresponding to a key out of storage - // that has been cached in mItems hash table. - nsresult - GetCachedValue(const nsAString& aKey, - nsAString& aValue, - PRBool* aSecure); - - // retrieve the value and secure state corresponding to a key out of storage. - nsresult - GetDBValue(const nsAString& aKey, - nsAString& aValue, - PRBool* aSecure); - - // set the value corresponding to a key in the storage. If - // aSecure is false, then attempts to modify a secure value - // throw NS_ERROR_DOM_INVALID_ACCESS_ERR - nsresult - SetDBValue(const nsAString& aKey, - const nsAString& aValue, - PRBool aSecure); - - // set the value corresponding to a key as secure. - nsresult - SetSecure(const nsAString& aKey, PRBool aSecure); - - // clear all values from the store - void ClearAll(); - - nsresult - CloneFrom(nsDOMStorage* aThat); - nsIDOMStorageItem* GetNamedItem(const nsAString& aKey, nsresult* aResult); static nsDOMStorage* FromSupports(nsISupports* aSupports) { return static_cast<nsDOMStorage*>(static_cast<nsIDOMStorageObsolete*>(aSupports)); } - nsresult RegisterObservers(); - nsresult MaybeCommitTemporaryTable(bool force); + nsresult SetSecure(const nsAString& aKey, PRBool aSecure) + { + return mStorageImpl->SetSecure(aKey, aSecure); + } - bool WasTemporaryTableLoaded(); - void SetTemporaryTableLoaded(bool loaded); + nsresult CloneFrom(nsDOMStorage* aThat); -protected: - - friend class nsDOMStorageManager; + protected: friend class nsDOMStorage2; friend class nsDOMStoragePersistentDB; - static nsresult InitDB(); - - // cache the keys from the database for faster lookup - nsresult CacheKeysFromDB(); + nsRefPtr<DOMStorageBase> mStorageImpl; PRBool CanAccessSystem(nsIPrincipal *aPrincipal); - // true if the storage database should be used for values - PRPackedBool mUseDB; - - // domain this store is associated with - nsCString mDomain; - // document URI of the document this storage is bound to nsString mDocumentURI; - // true if the preferences indicates that this storage should be - // session only. This member is updated by - // CacheStoragePermissions(), using the current principal. - // CacheStoragePermissions() must be called at each entry point to - // make sure this stays up to date. - PRPackedBool mSessionOnly; - // true if this storage was initialized as a localStorage object. localStorage // objects are scoped to scheme/host/port in the database, while globalStorage // objects are scoped just to host. this flag also tells the manager to map // this storage also in mLocalStorages hash table. nsDOMStorageType mStorageType; - // true if items from the database are cached - PRPackedBool mItemsCached; - - // the key->value item pairs - nsTHashtable<nsSessionStorageEntry> mItems; - - // keys are used for database queries. - // see comments of the getters bellow. - nsCString mScopeDBKey; - nsCString mQuotaETLDplus1DomainDBKey; - nsCString mQuotaDomainDBKey; - friend class nsIDOMStorage2; nsPIDOMStorage* mSecurityChecker; nsPIDOMStorage* mEventBroadcaster; - - bool mCanUseChromePersist; - - bool mLoadedTemporaryTable; - TimeStamp mLastTemporaryTableAccessTime; - TimeStamp mTemporaryTableAge; - -public: - // e.g. "moc.rab.oof.:" or "moc.rab.oof.:http:80" depending - // on association with a domain (globalStorage) or - // an origin (localStorage). - nsCString& GetScopeDBKey() {return mScopeDBKey;} - - // e.g. "moc.rab.%" - reversed eTLD+1 subpart of the domain or - // reversed offline application allowed domain. - nsCString& GetQuotaDomainDBKey(PRBool aOfflineAllowed) - { - return aOfflineAllowed ? mQuotaDomainDBKey : mQuotaETLDplus1DomainDBKey; - } - - #ifdef MOZ_STORAGE - static nsDOMStorageDBWrapper* gStorageDB; - #endif }; class nsDOMStorage2 : public nsIDOMStorage, public nsPIDOMStorage { public: // nsISupports NS_DECL_CYCLE_COLLECTING_ISUPPORTS @@ -418,17 +530,17 @@ protected: nsInterfaceHashtable<nsCStringHashKey, nsIDOMStorageObsolete> mStorages; }; class nsDOMStorageItem : public nsIDOMStorageItem, public nsIDOMToString { public: - nsDOMStorageItem(nsDOMStorage* aStorage, + nsDOMStorageItem(DOMStorageBase* aStorage, const nsAString& aKey, const nsAString& aValue, PRBool aSecure); virtual ~nsDOMStorageItem(); // nsISupports NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsDOMStorageItem, nsIDOMStorageItem) @@ -472,17 +584,17 @@ protected: // key for the item nsString mKey; // value of the item nsString mValue; // If this item came from the db, mStorage points to the storage // object where this item came from. - nsRefPtr<nsDOMStorage> mStorage; + nsRefPtr<DOMStorageBase> mStorage; }; class nsDOMStorageEvent : public nsDOMEvent, public nsIDOMStorageEvent { public: nsDOMStorageEvent() : nsDOMEvent(nsnull, nsnull)
--- a/dom/src/storage/nsDOMStorageDBWrapper.cpp +++ b/dom/src/storage/nsDOMStorageDBWrapper.cpp @@ -103,73 +103,73 @@ nsDOMStorageDBWrapper::Init() rv = mFlushTimer->Init(nsDOMStorageManager::gStorageManager, 5000, nsITimer::TYPE_REPEATING_SLACK); NS_ENSURE_SUCCESS(rv, rv); return NS_OK; } nsresult -nsDOMStorageDBWrapper::EnsureLoadTemporaryTableForStorage(nsDOMStorage* aStorage) +nsDOMStorageDBWrapper::EnsureLoadTemporaryTableForStorage(DOMStorageImpl* aStorage) { if (aStorage->CanUseChromePersist()) return mChromePersistentDB.EnsureLoadTemporaryTableForStorage(aStorage); if (nsDOMStorageManager::gStorageManager->InPrivateBrowsingMode()) return NS_OK; if (aStorage->SessionOnly()) return NS_OK; return mPersistentDB.EnsureLoadTemporaryTableForStorage(aStorage); } nsresult -nsDOMStorageDBWrapper::FlushAndDeleteTemporaryTableForStorage(nsDOMStorage* aStorage) +nsDOMStorageDBWrapper::FlushAndDeleteTemporaryTableForStorage(DOMStorageImpl* aStorage) { if (aStorage->CanUseChromePersist()) return mChromePersistentDB.FlushAndDeleteTemporaryTableForStorage(aStorage); if (nsDOMStorageManager::gStorageManager->InPrivateBrowsingMode()) return NS_OK; if (aStorage->SessionOnly()) return NS_OK; return mPersistentDB.FlushAndDeleteTemporaryTableForStorage(aStorage); } nsresult -nsDOMStorageDBWrapper::GetAllKeys(nsDOMStorage* aStorage, +nsDOMStorageDBWrapper::GetAllKeys(DOMStorageImpl* aStorage, nsTHashtable<nsSessionStorageEntry>* aKeys) { if (aStorage->CanUseChromePersist()) return mChromePersistentDB.GetAllKeys(aStorage, aKeys); if (nsDOMStorageManager::gStorageManager->InPrivateBrowsingMode()) return mPrivateBrowsingDB.GetAllKeys(aStorage, aKeys); if (aStorage->SessionOnly()) return mSessionOnlyDB.GetAllKeys(aStorage, aKeys); return mPersistentDB.GetAllKeys(aStorage, aKeys); } nsresult -nsDOMStorageDBWrapper::GetKeyValue(nsDOMStorage* aStorage, +nsDOMStorageDBWrapper::GetKeyValue(DOMStorageImpl* aStorage, const nsAString& aKey, nsAString& aValue, PRBool* aSecure) { if (aStorage->CanUseChromePersist()) return mChromePersistentDB.GetKeyValue(aStorage, aKey, aValue, aSecure); if (nsDOMStorageManager::gStorageManager->InPrivateBrowsingMode()) return mPrivateBrowsingDB.GetKeyValue(aStorage, aKey, aValue, aSecure); if (aStorage->SessionOnly()) return mSessionOnlyDB.GetKeyValue(aStorage, aKey, aValue, aSecure); return mPersistentDB.GetKeyValue(aStorage, aKey, aValue, aSecure); } nsresult -nsDOMStorageDBWrapper::SetKey(nsDOMStorage* aStorage, +nsDOMStorageDBWrapper::SetKey(DOMStorageImpl* aStorage, const nsAString& aKey, const nsAString& aValue, PRBool aSecure, PRInt32 aQuota, PRBool aExcludeOfflineFromUsage, PRInt32 *aNewUsage) { if (aStorage->CanUseChromePersist()) @@ -182,48 +182,48 @@ nsDOMStorageDBWrapper::SetKey(nsDOMStora return mSessionOnlyDB.SetKey(aStorage, aKey, aValue, aSecure, aQuota, aExcludeOfflineFromUsage, aNewUsage); return mPersistentDB.SetKey(aStorage, aKey, aValue, aSecure, aQuota, aExcludeOfflineFromUsage, aNewUsage); } nsresult -nsDOMStorageDBWrapper::SetSecure(nsDOMStorage* aStorage, +nsDOMStorageDBWrapper::SetSecure(DOMStorageImpl* aStorage, const nsAString& aKey, const PRBool aSecure) { if (aStorage->CanUseChromePersist()) return mChromePersistentDB.SetSecure(aStorage, aKey, aSecure); if (nsDOMStorageManager::gStorageManager->InPrivateBrowsingMode()) return mPrivateBrowsingDB.SetSecure(aStorage, aKey, aSecure); if (aStorage->SessionOnly()) return mSessionOnlyDB.SetSecure(aStorage, aKey, aSecure); return mPersistentDB.SetSecure(aStorage, aKey, aSecure); } nsresult -nsDOMStorageDBWrapper::RemoveKey(nsDOMStorage* aStorage, +nsDOMStorageDBWrapper::RemoveKey(DOMStorageImpl* aStorage, const nsAString& aKey, PRBool aExcludeOfflineFromUsage, PRInt32 aKeyUsage) { if (aStorage->CanUseChromePersist()) return mChromePersistentDB.RemoveKey(aStorage, aKey, aExcludeOfflineFromUsage, aKeyUsage); if (nsDOMStorageManager::gStorageManager->InPrivateBrowsingMode()) return mPrivateBrowsingDB.RemoveKey(aStorage, aKey, aExcludeOfflineFromUsage, aKeyUsage); if (aStorage->SessionOnly()) return mSessionOnlyDB.RemoveKey(aStorage, aKey, aExcludeOfflineFromUsage, aKeyUsage); return mPersistentDB.RemoveKey(aStorage, aKey, aExcludeOfflineFromUsage, aKeyUsage); } nsresult -nsDOMStorageDBWrapper::ClearStorage(nsDOMStorage* aStorage) +nsDOMStorageDBWrapper::ClearStorage(DOMStorageImpl* aStorage) { if (aStorage->CanUseChromePersist()) return mChromePersistentDB.ClearStorage(aStorage); if (nsDOMStorageManager::gStorageManager->InPrivateBrowsingMode()) return mPrivateBrowsingDB.ClearStorage(aStorage); if (aStorage->SessionOnly()) return mSessionOnlyDB.ClearStorage(aStorage); @@ -301,17 +301,17 @@ nsDOMStorageDBWrapper::RemoveAll() rv = mPersistentDB.RemoveAll(); NS_ENSURE_SUCCESS(rv, rv); return rv; } nsresult -nsDOMStorageDBWrapper::GetUsage(nsDOMStorage* aStorage, +nsDOMStorageDBWrapper::GetUsage(DOMStorageImpl* aStorage, PRBool aExcludeOfflineFromUsage, PRInt32 *aUsage) { if (aStorage->CanUseChromePersist()) return mChromePersistentDB.GetUsage(aStorage, aExcludeOfflineFromUsage, aUsage); if (nsDOMStorageManager::gStorageManager->InPrivateBrowsingMode()) return mPrivateBrowsingDB.GetUsage(aStorage, aExcludeOfflineFromUsage, aUsage); if (aStorage->SessionOnly()) return mSessionOnlyDB.GetUsage(aStorage, aExcludeOfflineFromUsage, aUsage);
--- a/dom/src/storage/nsDOMStorageDBWrapper.h +++ b/dom/src/storage/nsDOMStorageDBWrapper.h @@ -88,73 +88,73 @@ class nsDOMStorageDBWrapper public: nsDOMStorageDBWrapper(); ~nsDOMStorageDBWrapper(); nsresult Init(); nsresult - EnsureLoadTemporaryTableForStorage(nsDOMStorage* aStorage); + EnsureLoadTemporaryTableForStorage(DOMStorageImpl* aStorage); nsresult - FlushAndDeleteTemporaryTableForStorage(nsDOMStorage* aStorage); + FlushAndDeleteTemporaryTableForStorage(DOMStorageImpl* aStorage); /** * Retrieve a list of all the keys associated with a particular domain. */ nsresult - GetAllKeys(nsDOMStorage* aStorage, + GetAllKeys(DOMStorageImpl* aStorage, nsTHashtable<nsSessionStorageEntry>* aKeys); /** * Retrieve a value and secure flag for a key from storage. * * @throws NS_ERROR_DOM_NOT_FOUND_ERR if key not found */ nsresult - GetKeyValue(nsDOMStorage* aStorage, + GetKeyValue(DOMStorageImpl* aStorage, const nsAString& aKey, nsAString& aValue, PRBool* aSecure); /** * Set the value and secure flag for a key in storage. */ nsresult - SetKey(nsDOMStorage* aStorage, + SetKey(DOMStorageImpl* aStorage, const nsAString& aKey, const nsAString& aValue, PRBool aSecure, PRInt32 aQuota, PRBool aExcludeOfflineFromUsage, PRInt32* aNewUsage); /** * Set the secure flag for a key in storage. Does nothing if the key was * not found. */ nsresult - SetSecure(nsDOMStorage* aStorage, + SetSecure(DOMStorageImpl* aStorage, const nsAString& aKey, const PRBool aSecure); /** * Removes a key from storage. */ nsresult - RemoveKey(nsDOMStorage* aStorage, + RemoveKey(DOMStorageImpl* aStorage, const nsAString& aKey, PRBool aExcludeOfflineFromUsage, PRInt32 aKeyUsage); /** * Remove all keys belonging to this storage. */ nsresult - ClearStorage(nsDOMStorage* aStorage); + ClearStorage(DOMStorageImpl* aStorage); /** * Drop session-only storage for a specific host and all it's subdomains */ nsresult DropSessionOnlyStoragesForHost(const nsACString& aHostName); /** @@ -182,17 +182,17 @@ public: */ nsresult RemoveAll(); /** * Returns usage for a storage using its GetQuotaDomainDBKey() as a key. */ nsresult - GetUsage(nsDOMStorage* aStorage, PRBool aExcludeOfflineFromUsage, PRInt32 *aUsage); + GetUsage(DOMStorageImpl* aStorage, PRBool aExcludeOfflineFromUsage, PRInt32 *aUsage); /** * Returns usage of the domain and optionaly by any subdomain. */ nsresult GetUsage(const nsACString& aDomain, PRBool aIncludeSubDomains, PRInt32 *aUsage); /**
--- a/dom/src/storage/nsDOMStorageMemoryDB.cpp +++ b/dom/src/storage/nsDOMStorageMemoryDB.cpp @@ -69,17 +69,17 @@ AllKeyEnum(nsSessionStorageEntry* aEntry if (NS_FAILED(rv)) item->mSecure = PR_FALSE; target->Put(aEntry->GetKey(), item); return PL_DHASH_NEXT; } nsresult -nsDOMStorageMemoryDB::GetItemsTable(nsDOMStorage* aStorage, +nsDOMStorageMemoryDB::GetItemsTable(DOMStorageImpl* aStorage, nsInMemoryStorage** aMemoryStorage) { if (mData.Get(aStorage->GetScopeDBKey(), aMemoryStorage)) return NS_OK; *aMemoryStorage = nsnull; nsInMemoryStorage* storageData = new nsInMemoryStorage(); @@ -109,17 +109,17 @@ nsDOMStorageMemoryDB::GetItemsTable(nsDO *aMemoryStorage = storageData; return NS_OK; } struct GetAllKeysEnumStruc { nsTHashtable<nsSessionStorageEntry>* mTarget; - nsDOMStorage* mStorage; + DOMStorageImpl* mStorage; }; static PLDHashOperator GetAllKeysEnum(const nsAString& keyname, nsDOMStorageMemoryDB::nsInMemoryItem* item, void *closure) { GetAllKeysEnumStruc* struc = (GetAllKeysEnumStruc*)closure; @@ -134,17 +134,17 @@ GetAllKeysEnum(const nsAString& keyname, item->mSecure); if (!entry->mItem) return PL_DHASH_STOP; return PL_DHASH_NEXT; } nsresult -nsDOMStorageMemoryDB::GetAllKeys(nsDOMStorage* aStorage, +nsDOMStorageMemoryDB::GetAllKeys(DOMStorageImpl* aStorage, nsTHashtable<nsSessionStorageEntry>* aKeys) { nsresult rv; nsInMemoryStorage* storage; rv = GetItemsTable(aStorage, &storage); NS_ENSURE_SUCCESS(rv, rv); @@ -152,17 +152,17 @@ nsDOMStorageMemoryDB::GetAllKeys(nsDOMSt struc.mTarget = aKeys; struc.mStorage = aStorage; storage->mTable.EnumerateRead(GetAllKeysEnum, &struc); return NS_OK; } nsresult -nsDOMStorageMemoryDB::GetKeyValue(nsDOMStorage* aStorage, +nsDOMStorageMemoryDB::GetKeyValue(DOMStorageImpl* aStorage, const nsAString& aKey, nsAString& aValue, PRBool* aSecure) { if (mPreloading) { NS_PRECONDITION(mPreloadDB, "Must have a preload DB set when preloading"); return mPreloadDB->GetKeyValue(aStorage, aKey, aValue, aSecure); } @@ -178,17 +178,17 @@ nsDOMStorageMemoryDB::GetKeyValue(nsDOMS return NS_ERROR_DOM_NOT_FOUND_ERR; aValue = item->mValue; *aSecure = item->mSecure; return NS_OK; } nsresult -nsDOMStorageMemoryDB::SetKey(nsDOMStorage* aStorage, +nsDOMStorageMemoryDB::SetKey(DOMStorageImpl* aStorage, const nsAString& aKey, const nsAString& aValue, PRBool aSecure, PRInt32 aQuota, PRBool aExcludeOfflineFromUsage, PRInt32 *aNewUsage) { nsresult rv; @@ -232,17 +232,17 @@ nsDOMStorageMemoryDB::SetKey(nsDOMStorag item->mSecure = aSecure; *aNewUsage = usage; return NS_OK; } nsresult -nsDOMStorageMemoryDB::SetSecure(nsDOMStorage* aStorage, +nsDOMStorageMemoryDB::SetSecure(DOMStorageImpl* aStorage, const nsAString& aKey, const PRBool aSecure) { nsresult rv; nsInMemoryStorage* storage; rv = GetItemsTable(aStorage, &storage); NS_ENSURE_SUCCESS(rv, rv); @@ -252,17 +252,17 @@ nsDOMStorageMemoryDB::SetSecure(nsDOMSto return NS_ERROR_DOM_NOT_FOUND_ERR; item->mSecure = aSecure; return NS_OK; } nsresult -nsDOMStorageMemoryDB::RemoveKey(nsDOMStorage* aStorage, +nsDOMStorageMemoryDB::RemoveKey(DOMStorageImpl* aStorage, const nsAString& aKey, PRBool aExcludeOfflineFromUsage, PRInt32 aKeyUsage) { nsresult rv; nsInMemoryStorage* storage; rv = GetItemsTable(aStorage, &storage); @@ -286,30 +286,30 @@ RemoveAllKeysEnum(const nsAString& keyna nsDOMStorageMemoryDB::nsInMemoryStorage* storage = (nsDOMStorageMemoryDB::nsInMemoryStorage*)closure; storage->mUsageDelta -= keyname.Length() + item->mValue.Length(); return PL_DHASH_REMOVE; } nsresult -nsDOMStorageMemoryDB::ClearStorage(nsDOMStorage* aStorage) +nsDOMStorageMemoryDB::ClearStorage(DOMStorageImpl* aStorage) { nsresult rv; nsInMemoryStorage* storage; rv = GetItemsTable(aStorage, &storage); NS_ENSURE_SUCCESS(rv, rv); storage->mTable.Enumerate(RemoveAllKeysEnum, storage); return NS_OK; } nsresult -nsDOMStorageMemoryDB::DropStorage(nsDOMStorage* aStorage) +nsDOMStorageMemoryDB::DropStorage(DOMStorageImpl* aStorage) { mData.Remove(aStorage->GetScopeDBKey()); return NS_OK; } struct RemoveOwnersStruc { nsCString* mSubDomain; @@ -382,17 +382,17 @@ nsDOMStorageMemoryDB::RemoveOwners(const nsresult nsDOMStorageMemoryDB::RemoveAll() { mData.Clear(); // XXX Check this releases all instances return NS_OK; } nsresult -nsDOMStorageMemoryDB::GetUsage(nsDOMStorage* aStorage, +nsDOMStorageMemoryDB::GetUsage(DOMStorageImpl* aStorage, PRBool aExcludeOfflineFromUsage, PRInt32 *aUsage) { return GetUsageInternal(aStorage->GetQuotaDomainDBKey(!aExcludeOfflineFromUsage), aExcludeOfflineFromUsage, aUsage); } nsresult nsDOMStorageMemoryDB::GetUsage(const nsACString& aDomain,
--- a/dom/src/storage/nsDOMStorageMemoryDB.h +++ b/dom/src/storage/nsDOMStorageMemoryDB.h @@ -77,78 +77,78 @@ public: */ nsresult Init(nsDOMStoragePersistentDB* aPreloadDB = nsnull); /** * */ nsresult - GetItemsTable(nsDOMStorage* aStorage, + GetItemsTable(DOMStorageImpl* aStorage, nsInMemoryStorage** aMemoryStorage); /** * Retrieve a list of all the keys associated with a particular domain. */ nsresult - GetAllKeys(nsDOMStorage* aStorage, + GetAllKeys(DOMStorageImpl* aStorage, nsTHashtable<nsSessionStorageEntry>* aKeys); /** * Retrieve a value and secure flag for a key from storage. * * @throws NS_ERROR_DOM_NOT_FOUND_ERR if key not found */ nsresult - GetKeyValue(nsDOMStorage* aStorage, + GetKeyValue(DOMStorageImpl* aStorage, const nsAString& aKey, nsAString& aValue, PRBool* aSecure); /** * Set the value and secure flag for a key in storage. */ nsresult - SetKey(nsDOMStorage* aStorage, + SetKey(DOMStorageImpl* aStorage, const nsAString& aKey, const nsAString& aValue, PRBool aSecure, PRInt32 aQuota, PRBool aExcludeOfflineFromUsage, PRInt32* aNewUsage); /** * Set the secure flag for a key in storage. Does nothing if the key was * not found. */ nsresult - SetSecure(nsDOMStorage* aStorage, + SetSecure(DOMStorageImpl* aStorage, const nsAString& aKey, const PRBool aSecure); /** * Removes a key from storage. */ nsresult - RemoveKey(nsDOMStorage* aStorage, + RemoveKey(DOMStorageImpl* aStorage, const nsAString& aKey, PRBool aExcludeOfflineFromUsage, PRInt32 aKeyUsage); /** * Remove all keys belonging to this storage. */ nsresult - ClearStorage(nsDOMStorage* aStorage); + ClearStorage(DOMStorageImpl* aStorage); /** * If we have changed the persistent storage, drop any potential session storages */ nsresult - DropStorage(nsDOMStorage* aStorage); + DropStorage(DOMStorageImpl* aStorage); /** * Removes all keys added by a given domain. */ nsresult RemoveOwner(const nsACString& aOwner, PRBool aIncludeSubDomains); /** @@ -164,17 +164,17 @@ public: */ nsresult RemoveAll(); /** * Returns usage for a storage using its GetQuotaDomainDBKey() as a key. */ nsresult - GetUsage(nsDOMStorage* aStorage, PRBool aExcludeOfflineFromUsage, PRInt32 *aUsage); + GetUsage(DOMStorageImpl* aStorage, PRBool aExcludeOfflineFromUsage, PRInt32 *aUsage); /** * Returns usage of the domain and optionaly by any subdomain. */ nsresult GetUsage(const nsACString& aDomain, PRBool aIncludeSubDomains, PRInt32 *aUsage); protected:
--- a/dom/src/storage/nsDOMStoragePersistentDB.cpp +++ b/dom/src/storage/nsDOMStoragePersistentDB.cpp @@ -439,17 +439,17 @@ nsDOMStoragePersistentDB::Init(const nsS rv = transaction.Commit(); NS_ENSURE_SUCCESS(rv, rv); return NS_OK; } nsresult -nsDOMStoragePersistentDB::EnsureLoadTemporaryTableForStorage(nsDOMStorage* aStorage) +nsDOMStoragePersistentDB::EnsureLoadTemporaryTableForStorage(DOMStorageImpl* aStorage) { if (!aStorage->WasTemporaryTableLoaded()) { nsresult rv; rv = MaybeCommitInsertTransaction(); NS_ENSURE_SUCCESS(rv, rv); mozStorageStatementScoper scope(mCopyToTempTableStatement); @@ -470,17 +470,17 @@ nsDOMStoragePersistentDB::EnsureLoadTemp // Always call this to update the last access time aStorage->SetTemporaryTableLoaded(true); return NS_OK; } nsresult -nsDOMStoragePersistentDB::FlushAndDeleteTemporaryTableForStorage(nsDOMStorage* aStorage) +nsDOMStoragePersistentDB::FlushAndDeleteTemporaryTableForStorage(DOMStorageImpl* aStorage) { if (!aStorage->WasTemporaryTableLoaded()) return NS_OK; mozStorageTransaction trans(mConnection, PR_FALSE); nsresult rv; @@ -525,17 +525,17 @@ nsDOMStoragePersistentDB::FlushAndDelete NS_ENSURE_SUCCESS(rv, rv); aStorage->SetTemporaryTableLoaded(false); return NS_OK; } nsresult -nsDOMStoragePersistentDB::GetAllKeys(nsDOMStorage* aStorage, +nsDOMStoragePersistentDB::GetAllKeys(DOMStorageImpl* aStorage, nsTHashtable<nsSessionStorageEntry>* aKeys) { nsresult rv; rv = MaybeCommitInsertTransaction(); NS_ENSURE_SUCCESS(rv, rv); rv = EnsureLoadTemporaryTableForStorage(aStorage); @@ -578,17 +578,17 @@ nsDOMStoragePersistentDB::GetAllKeys(nsD return NS_ERROR_OUT_OF_MEMORY; } } return NS_OK; } nsresult -nsDOMStoragePersistentDB::GetKeyValue(nsDOMStorage* aStorage, +nsDOMStoragePersistentDB::GetKeyValue(DOMStorageImpl* aStorage, const nsAString& aKey, nsAString& aValue, PRBool* aSecure) { nsresult rv; rv = MaybeCommitInsertTransaction(); NS_ENSURE_SUCCESS(rv, rv); @@ -628,17 +628,17 @@ nsDOMStoragePersistentDB::GetKeyValue(ns } *aSecure = !!secureInt; return rv; } nsresult -nsDOMStoragePersistentDB::SetKey(nsDOMStorage* aStorage, +nsDOMStoragePersistentDB::SetKey(DOMStorageImpl* aStorage, const nsAString& aKey, const nsAString& aValue, PRBool aSecure, PRInt32 aQuota, PRBool aExcludeOfflineFromUsage, PRInt32 *aNewUsage) { nsresult rv; @@ -702,17 +702,17 @@ nsDOMStoragePersistentDB::SetKey(nsDOMSt } *aNewUsage = usage; return NS_OK; } nsresult -nsDOMStoragePersistentDB::SetSecure(nsDOMStorage* aStorage, +nsDOMStoragePersistentDB::SetSecure(DOMStorageImpl* aStorage, const nsAString& aKey, const PRBool aSecure) { nsresult rv; rv = EnsureLoadTemporaryTableForStorage(aStorage); NS_ENSURE_SUCCESS(rv, rv); @@ -736,17 +736,17 @@ nsDOMStoragePersistentDB::SetSecure(nsDO rv = binder.Add(); NS_ENSURE_SUCCESS(rv, rv); return mSetSecureStatement->Execute(); } nsresult -nsDOMStoragePersistentDB::RemoveKey(nsDOMStorage* aStorage, +nsDOMStoragePersistentDB::RemoveKey(DOMStorageImpl* aStorage, const nsAString& aKey, PRBool aExcludeOfflineFromUsage, PRInt32 aKeyUsage) { nsresult rv; rv = MaybeCommitInsertTransaction(); NS_ENSURE_SUCCESS(rv, rv); @@ -772,17 +772,17 @@ nsDOMStoragePersistentDB::RemoveKey(nsDO rv = mRemoveKeyStatement->Execute(); NS_ENSURE_SUCCESS(rv, rv); return NS_OK; } nsresult -nsDOMStoragePersistentDB::ClearStorage(nsDOMStorage* aStorage) +nsDOMStoragePersistentDB::ClearStorage(DOMStorageImpl* aStorage) { nsresult rv; rv = MaybeCommitInsertTransaction(); NS_ENSURE_SUCCESS(rv, rv); mozStorageStatementScoper scope(mRemoveStorageStatement); @@ -933,17 +933,17 @@ nsDOMStoragePersistentDB::RemoveAll() rv = mRemoveAllStatement->Execute(); NS_ENSURE_SUCCESS(rv, rv); return NS_OK; } nsresult -nsDOMStoragePersistentDB::GetUsage(nsDOMStorage* aStorage, +nsDOMStoragePersistentDB::GetUsage(DOMStorageImpl* aStorage, PRBool aExcludeOfflineFromUsage, PRInt32 *aUsage) { return GetUsageInternal(aStorage->GetQuotaDomainDBKey(!aExcludeOfflineFromUsage), aExcludeOfflineFromUsage, aUsage); }
--- a/dom/src/storage/nsDOMStoragePersistentDB.h +++ b/dom/src/storage/nsDOMStoragePersistentDB.h @@ -39,85 +39,85 @@ #ifndef nsDOMStoragePersistentDB_h___ #define nsDOMStoragePersistentDB_h___ #include "nscore.h" #include "mozIStorageConnection.h" #include "mozIStorageStatement.h" #include "nsTHashtable.h" -class nsDOMStorage; +class DOMStorageImpl; class nsSessionStorageEntry; class nsDOMStoragePersistentDB { public: nsDOMStoragePersistentDB(); ~nsDOMStoragePersistentDB() {} nsresult Init(const nsString& aDatabaseName); nsresult - EnsureLoadTemporaryTableForStorage(nsDOMStorage* aStorage); + EnsureLoadTemporaryTableForStorage(DOMStorageImpl* aStorage); nsresult - FlushAndDeleteTemporaryTableForStorage(nsDOMStorage* aStorage); + FlushAndDeleteTemporaryTableForStorage(DOMStorageImpl* aStorage); /** * Retrieve a list of all the keys associated with a particular domain. */ nsresult - GetAllKeys(nsDOMStorage* aStorage, + GetAllKeys(DOMStorageImpl* aStorage, nsTHashtable<nsSessionStorageEntry>* aKeys); /** * Retrieve a value and secure flag for a key from storage. * * @throws NS_ERROR_DOM_NOT_FOUND_ERR if key not found */ nsresult - GetKeyValue(nsDOMStorage* aStorage, + GetKeyValue(DOMStorageImpl* aStorage, const nsAString& aKey, nsAString& aValue, PRBool* aSecure); /** * Set the value and secure flag for a key in storage. */ nsresult - SetKey(nsDOMStorage* aStorage, + SetKey(DOMStorageImpl* aStorage, const nsAString& aKey, const nsAString& aValue, PRBool aSecure, PRInt32 aQuota, PRBool aExcludeOfflineFromUsage, PRInt32* aNewUsage); /** * Set the secure flag for a key in storage. Does nothing if the key was * not found. */ nsresult - SetSecure(nsDOMStorage* aStorage, + SetSecure(DOMStorageImpl* aStorage, const nsAString& aKey, const PRBool aSecure); /** * Removes a key from storage. */ nsresult - RemoveKey(nsDOMStorage* aStorage, + RemoveKey(DOMStorageImpl* aStorage, const nsAString& aKey, PRBool aExcludeOfflineFromUsage, PRInt32 aKeyUsage); /** * Remove all keys belonging to this storage. */ - nsresult ClearStorage(nsDOMStorage* aStorage); + nsresult ClearStorage(DOMStorageImpl* aStorage); /** * Removes all keys added by a given domain. */ nsresult RemoveOwner(const nsACString& aOwner, PRBool aIncludeSubDomains); /** @@ -133,17 +133,17 @@ public: */ nsresult RemoveAll(); /** * Returns usage for a storage using its GetQuotaDomainDBKey() as a key. */ nsresult - GetUsage(nsDOMStorage* aStorage, PRBool aExcludeOfflineFromUsage, PRInt32 *aUsage); + GetUsage(DOMStorageImpl* aStorage, PRBool aExcludeOfflineFromUsage, PRInt32 *aUsage); /** * Returns usage of the domain and optionaly by any subdomain. */ nsresult GetUsage(const nsACString& aDomain, PRBool aIncludeSubDomains, PRInt32 *aUsage); /**
--- a/ipc/ipdl/Makefile.in +++ b/ipc/ipdl/Makefile.in @@ -52,16 +52,17 @@ EXPORT_LIBRARY = 1 ##----------------------------------------------------------------------------- ## When you add IPDL files to a source directory, list the directory here. ## IPDLDIRS = \ uriloader/exthandler \ dom/plugins \ dom/ipc \ + dom/src/storage \ gfx/layers/ipc \ ipc/ipdl/test/cxx \ ipc/testshell \ js/ipc \ js/jetpack \ layout/ipc \ netwerk/ipc \ netwerk/protocol/ftp \