diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index e2d136ea8fb..b6f25745b93 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -1671,16 +1671,13 @@ nsDocShell::HistoryPurged(PRInt32 aNumEntries) } NS_IMETHODIMP -nsDocShell::GetSessionStorageForDomain(const nsACString& aDomain, - nsIDOMStorage** aStorage) +nsDocShell::GetSessionStorageForURI(nsIURI* aURI, + nsIDOMStorage** aStorage) { NS_ENSURE_ARG_POINTER(aStorage); *aStorage = nsnull; - if (aDomain.IsEmpty()) - return NS_OK; - nsCOMPtr topItem; nsresult rv = GetSameTypeRootTreeItem(getter_AddRefs(topItem)); if (NS_FAILED(rv)) @@ -1691,9 +1688,16 @@ nsDocShell::GetSessionStorageForDomain(const nsACString& aDomain, nsCOMPtr topDocShell = do_QueryInterface(topItem); if (topDocShell != this) - return topDocShell->GetSessionStorageForDomain(aDomain, aStorage); - - if (!mStorages.Get(aDomain, aStorage)) { + return topDocShell->GetSessionStorageForURI(aURI, aStorage); + + nsCAutoString currentDomain; + rv = aURI->GetAsciiHost(currentDomain); + NS_ENSURE_SUCCESS(rv, rv); + + if (currentDomain.IsEmpty()) + return NS_OK; + + if (!mStorages.Get(currentDomain, aStorage)) { nsCOMPtr newstorage = do_CreateInstance("@mozilla.org/dom/storage;1"); if (!newstorage) @@ -1702,9 +1706,9 @@ nsDocShell::GetSessionStorageForDomain(const nsACString& aDomain, nsCOMPtr pistorage = do_QueryInterface(newstorage); if (!pistorage) return NS_ERROR_FAILURE; - pistorage->Init(NS_ConvertUTF8toUTF16(aDomain), PR_FALSE); + pistorage->Init(aURI, NS_ConvertUTF8toUTF16(currentDomain), PR_FALSE); - if (!mStorages.Put(aDomain, newstorage)) + if (!mStorages.Put(currentDomain, newstorage)) return NS_ERROR_OUT_OF_MEMORY; *aStorage = newstorage; @@ -6441,13 +6445,13 @@ nsDocShell::InternalLoad(nsIURI * aURI, gethostrv |= aURI->GetAsciiHost(newDomain); if (NS_SUCCEEDED(gethostrv) && thisDomain.Equals(newDomain)) { nsCOMPtr storage; - GetSessionStorageForDomain(thisDomain, - getter_AddRefs(storage)); + GetSessionStorageForURI(currentCodebase, + getter_AddRefs(storage)); nsCOMPtr piStorage = do_QueryInterface(storage); if (piStorage) { nsCOMPtr newstorage = - piStorage->Clone(); + piStorage->Clone(currentCodebase); targetDocShell->AddSessionStorage(thisDomain, newstorage); } diff --git a/docshell/base/nsIDocShell.idl b/docshell/base/nsIDocShell.idl index 3c9ce0a03d8..9f6f67630b6 100644 --- a/docshell/base/nsIDocShell.idl +++ b/docshell/base/nsIDocShell.idl @@ -68,7 +68,7 @@ interface nsILayoutHistoryState; interface nsISecureBrowserUI; interface nsIDOMStorage; -[scriptable, uuid(51241d7c-73c9-4b85-970c-bd4f91acfbcc)] +[scriptable, uuid(539355C0-F5C8-4929-A4AA-CB105E8F9997)] interface nsIDocShell : nsISupports { /** @@ -417,7 +417,7 @@ interface nsIDocShell : nsISupports * * @param domain the domain of the storage object to retrieve */ - nsIDOMStorage getSessionStorageForDomain(in ACString aDomain); + nsIDOMStorage getSessionStorageForURI(in nsIURI uri); /* * Add a WebApps session storage object to the docshell. diff --git a/dom/public/idl/storage/nsPIDOMStorage.h b/dom/public/idl/storage/nsPIDOMStorage.h index 38502a5d4ec..558095ccbf9 100644 --- a/dom/public/idl/storage/nsPIDOMStorage.h +++ b/dom/public/idl/storage/nsPIDOMStorage.h @@ -44,6 +44,7 @@ #include "nsTArray.h" class nsIDOMStorage; +class nsIURI; #define NS_PIDOMSTORAGE_IID \ { 0x2fdbb82e, 0x4b47, 0x406a, \ @@ -54,9 +55,9 @@ class nsPIDOMStorage : public nsISupports public: NS_DECLARE_STATIC_IID_ACCESSOR(NS_PIDOMSTORAGE_IID) - virtual void Init(const nsAString &aDomain, PRBool aUseDB) = 0; + virtual void Init(nsIURI* aURI, const nsAString &aDomain, PRBool aUseDB) = 0; - virtual already_AddRefed Clone() = 0; + virtual already_AddRefed Clone(nsIURI* aURI) = 0; virtual nsTArray *GetKeys() = 0; }; diff --git a/dom/src/base/nsGlobalWindow.cpp b/dom/src/base/nsGlobalWindow.cpp index d8a0024381c..3cc0cd1edbb 100644 --- a/dom/src/base/nsGlobalWindow.cpp +++ b/dom/src/base/nsGlobalWindow.cpp @@ -5621,11 +5621,7 @@ nsGlobalWindow::GetSessionStorage(nsIDOMStorage ** aSessionStorage) return NS_FAILED(rv) ? rv : NS_ERROR_DOM_NOT_SUPPORTED_ERR; } - nsCAutoString currentDomain; - rv = codebase->GetAsciiHost(currentDomain); - NS_ENSURE_SUCCESS(rv, rv); - - return docShell->GetSessionStorageForDomain(currentDomain, aSessionStorage); + return docShell->GetSessionStorageForURI(codebase, aSessionStorage); } NS_IMETHODIMP @@ -6139,11 +6135,11 @@ nsGlobalWindow::OpenInternal(const nsAString& aUrl, const nsAString& aName, if (NS_SUCCEEDED(gethostrv) && thisDomain.Equals(newDomain)) { nsCOMPtr storage; - mDocShell->GetSessionStorageForDomain(thisDomain, - getter_AddRefs(storage)); + mDocShell->GetSessionStorageForURI(currentCodebase, + getter_AddRefs(storage)); nsCOMPtr piStorage = do_QueryInterface(storage); if (piStorage) { - nsCOMPtr newstorage = piStorage->Clone(); + nsCOMPtr newstorage = piStorage->Clone(newURI); newDocShell->AddSessionStorage(thisDomain, newstorage); } } diff --git a/dom/src/storage/nsDOMStorage.cpp b/dom/src/storage/nsDOMStorage.cpp index 59af5bc4db5..69df8a20670 100644 --- a/dom/src/storage/nsDOMStorage.cpp +++ b/dom/src/storage/nsDOMStorage.cpp @@ -50,6 +50,18 @@ #include "nsReadableUtils.h" #include "nsIObserverService.h" #include "nsNetUtil.h" +#include "nsIPrefBranch.h" +#include "nsICookiePermission.h" +#include "nsIPermissionManager.h" + +static const PRUint32 ASK_BEFORE_ACCEPT = 1; +static const PRUint32 ACCEPT_SESSION = 2; +static const PRUint32 BEHAVIOR_REJECT = 2; + +static const char kPermissionType[] = "cookie"; +static const char kStorageEnabled[] = "dom.storage.enabled"; +static const char kCookiesBehavior[] = "network.cookie.cookieBehavior"; +static const char kCookiesLifetimePolicy[] = "network.cookie.lifetimePolicy"; // // Helper that tells us whether the caller is secure or not. @@ -135,13 +147,17 @@ NS_NewDOMStorage(nsISupports* aOuter, REFNSIID aIID, void** aResult) } nsDOMStorage::nsDOMStorage() - : mUseDB(PR_FALSE), mItemsCached(PR_FALSE) + : mUseDB(PR_FALSE), mSessionOnly(PR_TRUE), mItemsCached(PR_FALSE) { mItems.Init(8); } -nsDOMStorage::nsDOMStorage(const nsAString& aDomain, PRBool aUseDB) - : mUseDB(aUseDB), mItemsCached(PR_FALSE), mDomain(aDomain) +nsDOMStorage::nsDOMStorage(nsIURI* aURI, const nsAString& aDomain, PRBool aUseDB) + : mUseDB(aUseDB), + mSessionOnly(PR_TRUE), + mItemsCached(PR_FALSE), + mURI(aURI), + mDomain(aDomain) { #ifndef MOZ_STORAGE mUseDB = PR_FALSE; @@ -155,8 +171,9 @@ nsDOMStorage::~nsDOMStorage() } void -nsDOMStorage::Init(const nsAString& aDomain, PRBool aUseDB) +nsDOMStorage::Init(nsIURI* aURI, const nsAString& aDomain, PRBool aUseDB) { + mURI = aURI; mDomain.Assign(aDomain); #ifdef MOZ_STORAGE mUseDB = aUseDB; @@ -165,6 +182,48 @@ nsDOMStorage::Init(const nsAString& aDomain, PRBool aUseDB) #endif } +//static +PRBool +nsDOMStorage::CanUseStorage(nsIURI* aURI, PRPackedBool* aSessionOnly) +{ + // check if the domain can use storage. Downgrade to session only if only + // session storage may be used. + NS_ASSERTION(aURI && aSessionOnly, "null URI or session flag"); + + if (!nsContentUtils::GetBoolPref(kStorageEnabled)) + return PR_FALSE; + + nsCOMPtr permissionManager = + do_GetService(NS_PERMISSIONMANAGER_CONTRACTID); + if (!permissionManager) + return PR_FALSE; + + *aSessionOnly = PR_FALSE; + + PRUint32 perm; + permissionManager->TestPermission(aURI, kPermissionType, &perm); + + if (perm == nsIPermissionManager::DENY_ACTION) + return PR_FALSE; + + if (perm == nsICookiePermission::ACCESS_SESSION) { + *aSessionOnly = PR_TRUE; + } + else if (perm != nsIPermissionManager::ALLOW_ACTION) { + PRUint32 cookieBehavior = nsContentUtils::GetIntPref(kCookiesBehavior); + PRUint32 lifetimePolicy = nsContentUtils::GetIntPref(kCookiesLifetimePolicy); + + // treat ask as reject always + if (cookieBehavior == BEHAVIOR_REJECT || lifetimePolicy == ASK_BEFORE_ACCEPT) + return PR_FALSE; + + if (lifetimePolicy == ACCEPT_SESSION) + *aSessionOnly = PR_TRUE; + } + + return PR_TRUE; +} + class ItemCounterState { public: @@ -194,7 +253,10 @@ ItemCounter(nsSessionStorageEntry* aEntry, void* userArg) NS_IMETHODIMP nsDOMStorage::GetLength(PRUint32 *aLength) { - if (mUseDB) + if (!CacheStoragePermissions()) + return NS_ERROR_DOM_SECURITY_ERR; + + if (UseDB()) CacheKeysFromDB(); ItemCounterState state(IsCallerSecure()); @@ -253,7 +315,10 @@ nsDOMStorage::Key(PRUint32 aIndex, nsAString& aKey) // maybe we need to have a lazily populated key array here or // something? - if (mUseDB) + if (!CacheStoragePermissions()) + return NS_ERROR_DOM_SECURITY_ERR; + + if (UseDB()) CacheKeysFromDB(); IndexFinderData data(IsCallerSecure(), aIndex); @@ -274,6 +339,9 @@ nsDOMStorage::GetItem(const nsAString& aKey, nsIDOMStorageItem **aItem) { *aItem = nsnull; + if (!CacheStoragePermissions()) + return NS_ERROR_DOM_SECURITY_ERR; + if (aKey.IsEmpty()) return NS_OK; @@ -285,7 +353,7 @@ nsDOMStorage::GetItem(const nsAString& aKey, nsIDOMStorageItem **aItem) } NS_ADDREF(*aItem = entry->mItem); } - else if (mUseDB) { + else if (UseDB()) { PRBool secure; nsAutoString value; nsresult rv = GetDBValue(aKey, value, &secure); @@ -295,7 +363,7 @@ nsDOMStorage::GetItem(const nsAString& aKey, nsIDOMStorageItem **aItem) NS_ENSURE_SUCCESS(rv, rv); nsRefPtr newitem = - new nsDOMStorageItem(this, aKey, secure); + new nsDOMStorageItem(this, aKey, value, secure); if (!newitem) return NS_ERROR_OUT_OF_MEMORY; @@ -312,6 +380,9 @@ nsDOMStorage::GetItem(const nsAString& aKey, nsIDOMStorageItem **aItem) NS_IMETHODIMP nsDOMStorage::SetItem(const nsAString& aKey, const nsAString& aData) { + if (!CacheStoragePermissions()) + return NS_ERROR_DOM_SECURITY_ERR; + if (aKey.IsEmpty()) return NS_OK; @@ -322,21 +393,20 @@ nsDOMStorage::SetItem(const nsAString& aKey, const nsAString& aData) if (entry->mItem->IsSecure() && !IsCallerSecure()) { return NS_ERROR_DOM_SECURITY_ERR; } - if (!mUseDB) { - rv = entry->mItem->SetValue(aData); - NS_ENSURE_SUCCESS(rv, rv); + if (!UseDB()) { + entry->mItem->SetValueInternal(aData); } } else { - if (mUseDB) - newitem = new nsDOMStorageItem(this, aKey, PR_FALSE); + if (UseDB()) + newitem = new nsDOMStorageItem(this, aKey, aData, PR_FALSE); else - newitem = new nsDOMStorageItem(nsnull, aData, PR_FALSE); + newitem = new nsDOMStorageItem(this, aKey, aData, PR_FALSE); if (!newitem) return NS_ERROR_OUT_OF_MEMORY; } - if (mUseDB) { + if (UseDB()) { rv = SetDBValue(aKey, aData, IsCallerSecure()); NS_ENSURE_SUCCESS(rv, rv); } @@ -348,7 +418,7 @@ nsDOMStorage::SetItem(const nsAString& aKey, const nsAString& aData) } // SetDBValue already calls BroadcastChangeNotification so don't do it again - if (!mUseDB) + if (!UseDB()) BroadcastChangeNotification(); return NS_OK; @@ -356,6 +426,9 @@ nsDOMStorage::SetItem(const nsAString& aKey, const nsAString& aData) NS_IMETHODIMP nsDOMStorage::RemoveItem(const nsAString& aKey) { + if (!CacheStoragePermissions()) + return NS_ERROR_DOM_SECURITY_ERR; + if (aKey.IsEmpty()) return NS_OK; @@ -365,7 +438,7 @@ NS_IMETHODIMP nsDOMStorage::RemoveItem(const nsAString& aKey) return NS_ERROR_DOM_SECURITY_ERR; } - if (mUseDB) { + if (UseDB()) { #ifdef MOZ_STORAGE nsresult rv = InitDB(); NS_ENSURE_SUCCESS(rv, rv); @@ -453,8 +526,8 @@ nsDOMStorage::GetDBValue(const nsAString& aKey, nsAString& aValue, aValue.Truncate(); #ifdef MOZ_STORAGE - NS_ASSERTION(mUseDB, - "Uh, we should only get here if we're using the database!"); + if (!UseDB()) + return NS_OK; nsresult rv = InitDB(); NS_ENSURE_SUCCESS(rv, rv); @@ -480,8 +553,8 @@ nsDOMStorage::SetDBValue(const nsAString& aKey, PRBool aSecure) { #ifdef MOZ_STORAGE - NS_ASSERTION(mUseDB, - "Uh, we should only get here if we're using the database!"); + if (!UseDB()) + return NS_OK; nsresult rv = InitDB(); NS_ENSURE_SUCCESS(rv, rv); @@ -502,7 +575,7 @@ nsresult nsDOMStorage::SetSecure(const nsAString& aKey, PRBool aSecure) { #ifdef MOZ_STORAGE - if (mUseDB) { + if (UseDB()) { nsresult rv = InitDB(); NS_ENSURE_SUCCESS(rv, rv); @@ -537,15 +610,15 @@ CopyStorageItems(nsSessionStorageEntry* aEntry, void* userArg) } already_AddRefed -nsDOMStorage::Clone() +nsDOMStorage::Clone(nsIURI* aURI) { - if (mUseDB) { + if (UseDB()) { NS_ERROR("Uh, don't clone a global storage object."); return nsnull; } - nsDOMStorage* storage = new nsDOMStorage(mDomain, PR_FALSE); + nsDOMStorage* storage = new nsDOMStorage(aURI, mDomain, PR_FALSE); if (!storage) return nsnull; @@ -576,7 +649,7 @@ KeysArrayBuilder(nsSessionStorageEntry* aEntry, void* userArg) nsTArray * nsDOMStorage::GetKeys() { - if (mUseDB) + if (UseDB()) CacheKeysFromDB(); KeysArrayBuilderStruct keystruct; @@ -603,7 +676,7 @@ nsDOMStorage::BroadcastChangeNotification() // domain, but if it's a global storage object we do. observerService->NotifyObservers((nsIDOMStorage *)this, "dom-storage-changed", - mUseDB ? mDomain.get() : nsnull); + UseDB() ? mDomain.get() : nsnull); } // @@ -623,6 +696,8 @@ nsresult nsDOMStorageList::NamedItem(const nsAString& aDomain, nsIDOMStorage** aStorage) { + *aStorage = nsnull; + nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager(); if (!ssm) return NS_ERROR_FAILURE; @@ -631,23 +706,27 @@ nsDOMStorageList::NamedItem(const nsAString& aDomain, nsresult rv = ssm->GetSubjectPrincipal(getter_AddRefs(subjectPrincipal)); NS_ENSURE_SUCCESS(rv, rv); - nsCOMPtr systemPrincipal; - rv = ssm->GetSystemPrincipal(getter_AddRefs(systemPrincipal)); - NS_ENSURE_SUCCESS(rv, rv); - + nsCOMPtr uri; nsCAutoString currentDomain; if (subjectPrincipal) { - nsCOMPtr uri; rv = subjectPrincipal->GetURI(getter_AddRefs(uri)); if (NS_SUCCEEDED(rv) && uri) { + PRPackedBool sessionOnly; + if (!nsDOMStorage::CanUseStorage(uri, &sessionOnly)) + return NS_ERROR_DOM_SECURITY_ERR; + rv = uri->GetAsciiHost(currentDomain); NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_SECURITY_ERR); } } - - if (subjectPrincipal == systemPrincipal || !currentDomain.IsEmpty()) { - return GetStorageForDomain(aDomain, NS_ConvertUTF8toUTF16(currentDomain), - subjectPrincipal == systemPrincipal, aStorage); + + PRBool isSystem; + rv = ssm->SubjectPrincipalIsSystem(&isSystem); + NS_ENSURE_SUCCESS(rv, rv); + + if (isSystem || !currentDomain.IsEmpty()) { + return GetStorageForDomain(uri, aDomain, NS_ConvertUTF8toUTF16(currentDomain), + isSystem, aStorage); } return NS_ERROR_DOM_SECURITY_ERR; @@ -690,11 +769,20 @@ nsDOMStorageList::CanAccessDomain(const nsAString& aRequestedDomain, } nsresult -nsDOMStorageList::GetStorageForDomain(const nsAString& aRequestedDomain, +nsDOMStorageList::GetStorageForDomain(nsIURI* aURI, + const nsAString& aRequestedDomain, const nsAString& aCurrentDomain, PRBool aNoCurrentDomainCheck, nsIDOMStorage** aStorage) { + // fail if the domain contains no periods. + // XXXndeakin update this when bug 342314 is fixed so that we can check + // for top-level domain names properly + nsAutoString trimmedDomain(aRequestedDomain); + trimmedDomain.Trim("."); + if (trimmedDomain.FindChar('.') == kNotFound) + return NS_ERROR_DOM_SECURITY_ERR; + if (!aNoCurrentDomainCheck && !CanAccessDomain(aRequestedDomain, aCurrentDomain)) { return NS_ERROR_DOM_SECURITY_ERR; @@ -717,7 +805,7 @@ nsDOMStorageList::GetStorageForDomain(const nsAString& aRequestedDomain, // now have a valid domain, so look it up in the storage table if (!mStorages.Get(usedDomain, aStorage)) { - nsCOMPtr newstorage = new nsDOMStorage(usedDomain, PR_TRUE); + nsCOMPtr newstorage = new nsDOMStorage(aURI, usedDomain, PR_TRUE); if (!newstorage) return NS_ERROR_OUT_OF_MEMORY; @@ -788,9 +876,11 @@ NS_IMPL_RELEASE(nsDOMStorageItem) nsDOMStorageItem::nsDOMStorageItem(nsDOMStorage* aStorage, const nsAString& aKey, + const nsAString& aValue, PRBool aSecure) : mSecure(aSecure), - mKeyOrValue(aKey), + mKey(aKey), + mValue(aValue), mStorage(aStorage) { } @@ -802,13 +892,13 @@ nsDOMStorageItem::~nsDOMStorageItem() NS_IMETHODIMP nsDOMStorageItem::GetSecure(PRBool* aSecure) { - if (!IsCallerSecure()) { + if (!mStorage->CacheStoragePermissions() || !IsCallerSecure()) { return NS_ERROR_DOM_INVALID_ACCESS_ERR; } - if (mStorage) { + if (mStorage->UseDB()) { nsAutoString value; - return mStorage->GetDBValue(mKeyOrValue, value, aSecure); + return mStorage->GetDBValue(mKey, value, aSecure); } *aSecure = IsSecure(); @@ -818,12 +908,12 @@ nsDOMStorageItem::GetSecure(PRBool* aSecure) NS_IMETHODIMP nsDOMStorageItem::SetSecure(PRBool aSecure) { - if (!IsCallerSecure()) { + if (!mStorage->CacheStoragePermissions() || !IsCallerSecure()) { return NS_ERROR_DOM_INVALID_ACCESS_ERR; } - if (mStorage) { - nsresult rv = mStorage->SetSecure(mKeyOrValue, aSecure); + if (mStorage->UseDB()) { + nsresult rv = mStorage->SetSecure(mKey, aSecure); NS_ENSURE_SUCCESS(rv, rv); } @@ -834,10 +924,13 @@ nsDOMStorageItem::SetSecure(PRBool aSecure) NS_IMETHODIMP nsDOMStorageItem::GetValue(nsAString& aValue) { - if (mStorage) { + 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(mKeyOrValue, aValue, &secure); + nsresult rv = mStorage->GetDBValue(mKey, aValue, &secure); return (rv == NS_ERROR_DOM_NOT_FOUND_ERR) ? NS_OK : rv; } @@ -845,29 +938,31 @@ nsDOMStorageItem::GetValue(nsAString& aValue) return NS_ERROR_DOM_SECURITY_ERR; } - aValue = mKeyOrValue; + aValue = mValue; return NS_OK; } NS_IMETHODIMP nsDOMStorageItem::SetValue(const nsAString& aValue) { + if (!mStorage->CacheStoragePermissions()) + return NS_ERROR_DOM_INVALID_ACCESS_ERR; + PRBool secureCaller = IsCallerSecure(); - if (mStorage) { + if (mStorage->UseDB()) { // SetDBValue() does the security checks for us. - return mStorage->SetDBValue(mKeyOrValue, aValue, secureCaller); + return mStorage->SetDBValue(mKey, aValue, secureCaller); } PRBool secureItem = IsSecure(); if (!secureCaller && secureItem) { // The item is secure, but the caller isn't. Throw. - return NS_ERROR_DOM_SECURITY_ERR; } - mKeyOrValue = aValue; + mValue = aValue; mSecure = secureCaller; return NS_OK; } diff --git a/dom/src/storage/nsDOMStorage.h b/dom/src/storage/nsDOMStorage.h index 73825d6a144..b8089858768 100644 --- a/dom/src/storage/nsDOMStorage.h +++ b/dom/src/storage/nsDOMStorage.h @@ -73,7 +73,7 @@ class nsDOMStorage : public nsIDOMStorage, { public: nsDOMStorage(); - nsDOMStorage(const nsAString& aDomain, PRBool aUseDB); + nsDOMStorage(nsIURI* aURI, const nsAString& aDomain, PRBool aUseDB); virtual ~nsDOMStorage(); // nsISupports @@ -83,13 +83,23 @@ public: NS_DECL_NSIDOMSTORAGE // nsPIDOMStorage - virtual void Init(const nsAString& aDomain, PRBool aUseDB); - virtual already_AddRefed Clone(); + virtual void Init(nsIURI* aURI, const nsAString& aDomain, PRBool aUseDB); + virtual already_AddRefed Clone(nsIURI* aURI); virtual nsTArray *GetKeys(); - // cache the keys from the database for faster lookup - nsresult - CacheKeysFromDB(); + PRBool UseDB() { return mUseDB && !mSessionOnly; } + + // cache whether storage may be used by aURI, and whether it is session + // only. If aURI is null, the uri associated with this storage (mURI) + // is checked. Returns true if storage may be used. + static PRBool + CanUseStorage(nsIURI* aURI, PRPackedBool* aSessionOnly); + + PRBool + CacheStoragePermissions() + { + return CanUseStorage(mURI, &mSessionOnly); + } // retrieve the value and secure state corresponding to a key out of storage. nsresult @@ -111,13 +121,22 @@ protected: nsresult InitDB(); + // cache the keys from the database for faster lookup + nsresult CacheKeysFromDB(); + void BroadcastChangeNotification(); // true if the storage database should be used for values - PRBool mUseDB; + PRPackedBool mUseDB; + + // true if the preferences indicates that this storage should be session only + PRPackedBool mSessionOnly; // true if items from the database are cached - PRBool mItemsCached; + PRPackedBool mItemsCached; + + // the URI this store is associated with + nsCOMPtr mURI; // domain this store is associated with nsAutoString mDomain; @@ -146,6 +165,15 @@ public: // nsIDOMStorageList NS_DECL_NSIDOMSTORAGELIST + /** + * Check whether aCurrentDomain has access to aRequestedDomain + */ + static PRBool + CanAccessDomain(const nsAString& aRequestedDomain, + const nsAString& aCurrentDomain); + +protected: + /** * Return the global nsIDOMStorage for a particular domain. * aNoCurrentDomainCheck may be true to skip the domain comparison; @@ -157,7 +185,8 @@ public: * @param aNoCurrentDomainCheck true to skip domain comparison */ nsresult - GetStorageForDomain(const nsAString& aRequestedDomain, + GetStorageForDomain(nsIURI* aURI, + const nsAString& aRequestedDomain, const nsAString& aCurrentDomain, PRBool aNoCurrentDomainCheck, nsIDOMStorage** aStorage); @@ -169,15 +198,6 @@ public: ConvertDomainToArray(const nsAString& aDomain, nsStringArray* aArray); - /** - * Check whether aCurrentDomain has access to aRequestedDomain - */ - static PRBool - CanAccessDomain(const nsAString& aRequestedDomain, - const nsAString& aCurrentDomain); - -protected: - nsInterfaceHashtable mStorages; }; @@ -187,6 +207,7 @@ class nsDOMStorageItem : public nsIDOMStorageItem, public: nsDOMStorageItem(nsDOMStorage* aStorage, const nsAString& aKey, + const nsAString& aValue, PRBool aSecure); virtual ~nsDOMStorageItem(); @@ -211,16 +232,17 @@ public: const nsAString& GetValueInternal() { - NS_ASSERTION(!mStorage, "Don't call this on global storage items!"); + return mValue; + } - return mKeyOrValue; + const void SetValueInternal(const nsAString& aValue) + { + mValue = aValue; } void ClearValue() { - NS_ASSERTION(!mStorage, "Don't call this on global storage items!"); - - mKeyOrValue.Truncate(); + mValue.Truncate(); } protected: @@ -228,8 +250,11 @@ protected: // true if this value is for secure sites only PRBool mSecure; - // value of the item, or key for the item if it came from the db. - nsString mKeyOrValue; + // 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. diff --git a/dom/src/storage/nsDOMStorageDB.cpp b/dom/src/storage/nsDOMStorageDB.cpp index 8e74637fc51..d315142a736 100644 --- a/dom/src/storage/nsDOMStorageDB.cpp +++ b/dom/src/storage/nsDOMStorageDB.cpp @@ -159,7 +159,7 @@ nsDOMStorageDB::GetAllKeys(const nsAString& aDomain, nsSessionStorageEntry* entry = aKeys->PutEntry(key); NS_ENSURE_TRUE(entry, NS_ERROR_OUT_OF_MEMORY); - entry->mItem = new nsDOMStorageItem(aStorage, key, secureInt); + entry->mItem = new nsDOMStorageItem(aStorage, key, EmptyString(), secureInt); if (!entry->mItem) { aKeys->RawRemoveEntry(entry); return NS_ERROR_OUT_OF_MEMORY; diff --git a/modules/libpref/src/init/all.js b/modules/libpref/src/init/all.js index 972a640d21c..aa1a8b3fcc3 100644 --- a/modules/libpref/src/init/all.js +++ b/modules/libpref/src/init/all.js @@ -452,6 +452,8 @@ pref("dom.popup_maximum", 20); pref("dom.popup_allowed_events", "change click dblclick mouseup reset submit"); pref("dom.disable_open_click_delay", 1000); +pref("dom.storage.enabled", true); + // Disable popups from plugins by default // 0 = openAllowed // 1 = openControlled