Bug 487695 - Decide on localStorage behavior in session-only cookies or private-browsing mode, r+sr=jst

--HG--
rename : dom/src/storage/nsDOMStorageDB.cpp => dom/src/storage/nsDOMStoragePersistentDB.cpp
rename : dom/src/storage/nsDOMStorageDB.h => dom/src/storage/nsDOMStoragePersistentDB.h
This commit is contained in:
Honza Bambas 2009-05-18 10:12:14 +02:00
parent b92cdd8365
commit 7c8df0e8e5
22 changed files with 2442 additions and 222 deletions

View File

@ -6825,26 +6825,19 @@ nsGlobalWindow::GetLocalStorage(nsIDOMStorage ** aLocalStorage)
NS_ENSURE_ARG(aLocalStorage);
if (nsDOMStorageManager::gStorageManager &&
nsDOMStorageManager::gStorageManager->InPrivateBrowsingMode())
return NS_ERROR_DOM_SECURITY_ERR;
if (!mLocalStorage) {
*aLocalStorage = nsnull;
nsresult rv;
PRPackedBool unused;
if (!nsDOMStorage::CanUseStorage(&unused))
return NS_ERROR_DOM_SECURITY_ERR;
nsIPrincipal *principal = GetPrincipal();
if (!principal)
return NS_OK;
PRPackedBool sessionOnly;
if (!nsDOMStorage::CanUseStorage(&sessionOnly))
return NS_ERROR_DOM_SECURITY_ERR;
if (sessionOnly)
return NS_ERROR_DOM_SECURITY_ERR;
nsCOMPtr<nsIDOMStorageManager> storageManager =
do_GetService("@mozilla.org/dom/storagemanager;1", &rv);
NS_ENSURE_SUCCESS(rv, rv);

View File

@ -72,7 +72,7 @@ CPPSRCS = \
$(NULL)
ifdef MOZ_STORAGE
CPPSRCS += nsDOMStorageDB.cpp
CPPSRCS += nsDOMStorageDBWrapper.cpp nsDOMStoragePersistentDB.cpp nsDOMStorageMemoryDB.cpp
endif
# we don't want the shared lib, but we want to force the creation of a static lib.

View File

@ -23,6 +23,7 @@
* Neil Deakin <enndeakin@sympatico.ca>
* Johnny Stenback <jst@mozilla.com>
* Ehsan Akhgari <ehsan.akhgari@gmail.com>
* Honza Bambas <honzab@firemni.cz>
*
* 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"),
@ -242,6 +243,7 @@ nsDOMStorageManager::Initialize()
os->AddObserver(gStorageManager, "cookie-changed", PR_FALSE);
os->AddObserver(gStorageManager, "offline-app-removed", PR_FALSE);
os->AddObserver(gStorageManager, NS_PRIVATE_BROWSING_SWITCH_TOPIC, PR_FALSE);
os->AddObserver(gStorageManager, "perm-changed", PR_FALSE);
nsCOMPtr<nsIPrivateBrowsingService> pbs =
do_GetService(NS_PRIVATE_BROWSING_SERVICE_CONTRACTID);
@ -355,6 +357,39 @@ nsDOMStorageManager::Observe(nsISupports *aSubject,
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();
NS_ENSURE_SUCCESS(rv, rv);
return nsDOMStorage::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"))
return NS_OK;
PRUint32 cap = 0;
perm->GetCapability(&cap);
if (!(cap & nsICookiePermission::ACCESS_SESSION) ||
nsDependentString(aData) != NS_LITERAL_STRING("deleted"))
return NS_OK;
nsCAutoString host;
perm->GetHost(host);
if (host.IsEmpty())
return NS_OK;
#ifdef MOZ_STORAGE
nsresult rv = nsDOMStorage::InitDB();
NS_ENSURE_SUCCESS(rv, rv);
return nsDOMStorage::gStorageDB->DropSessionOnlyStoragesForHost(host);
#endif
}
}
return NS_OK;
@ -427,7 +462,7 @@ nsDOMStorageManager::RemoveFromStoragesHash(nsDOMStorage* aStorage)
//
#ifdef MOZ_STORAGE
nsDOMStorageDB* nsDOMStorage::gStorageDB = nsnull;
nsDOMStorageDBWrapper* nsDOMStorage::gStorageDB = nsnull;
#endif
nsDOMStorageEntry::nsDOMStorageEntry(KeyTypePointer aStr)
@ -546,7 +581,7 @@ nsDOMStorage::InitAsLocalStorage(nsIPrincipal *aPrincipal)
innerUri->GetAsciiHost(mDomain);
#ifdef MOZ_STORAGE
nsDOMStorageDB::CreateOriginScopeDBKey(innerUri, mScopeDBKey);
nsDOMStorageDBWrapper::CreateOriginScopeDBKey(innerUri, mScopeDBKey);
// XXX Bug 357323, we have to solve the issue how to define
// origin for file URLs. In that case CreateOriginScopeDBKey
@ -554,7 +589,7 @@ nsDOMStorage::InitAsLocalStorage(nsIPrincipal *aPrincipal)
// in that case because it produces broken entries w/o owner.
mUseDB = !mScopeDBKey.IsEmpty();
nsDOMStorageDB::CreateQuotaDomainDBKey(mDomain, PR_TRUE, mQuotaDomainDBKey);
nsDOMStorageDBWrapper::CreateQuotaDomainDBKey(mDomain, PR_TRUE, mQuotaDomainDBKey);
#endif
mLocalStorage = PR_TRUE;
@ -566,7 +601,7 @@ nsDOMStorage::InitAsGlobalStorage(const nsACString &aDomainDemanded)
{
mDomain = aDomainDemanded;
#ifdef MOZ_STORAGE
nsDOMStorageDB::CreateDomainScopeDBKey(aDomainDemanded, 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
@ -575,7 +610,7 @@ nsDOMStorage::InitAsGlobalStorage(const nsACString &aDomainDemanded)
if (!(mUseDB = !mScopeDBKey.IsEmpty()))
mScopeDBKey.AppendLiteral(":");
nsDOMStorageDB::CreateQuotaDomainDBKey(aDomainDemanded, PR_TRUE, mQuotaDomainDBKey);
nsDOMStorageDBWrapper::CreateQuotaDomainDBKey(aDomainDemanded, PR_TRUE, mQuotaDomainDBKey);
#endif
return NS_OK;
}
@ -636,7 +671,11 @@ nsDOMStorage::CanUseStorage(PRPackedBool* aSessionOnly)
if (perm == nsIPermissionManager::DENY_ACTION)
return PR_FALSE;
if (perm == nsICookiePermission::ACCESS_SESSION) {
// In private browsing mode we ougth to behave as in session-only cookies
// mode to prevent detection of being in private browsing mode and ensuring
// that there will be no traces left.
if (perm == nsICookiePermission::ACCESS_SESSION ||
nsDOMStorageManager::gStorageManager->InPrivateBrowsingMode()) {
*aSessionOnly = PR_TRUE;
}
else if (perm != nsIPermissionManager::ALLOW_ACTION) {
@ -657,6 +696,9 @@ nsDOMStorage::CanUseStorage(PRPackedBool* aSessionOnly)
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))
return PR_FALSE;
@ -1003,7 +1045,7 @@ nsDOMStorage::InitDB()
{
#ifdef MOZ_STORAGE
if (!gStorageDB) {
gStorageDB = new nsDOMStorageDB();
gStorageDB = new nsDOMStorageDBWrapper();
if (!gStorageDB)
return NS_ERROR_OUT_OF_MEMORY;

View File

@ -58,7 +58,7 @@
#include "nsCycleCollectionParticipant.h"
#ifdef MOZ_STORAGE
#include "nsDOMStorageDB.h"
#include "nsDOMStorageDBWrapper.h"
#endif
class nsDOMStorage;
@ -155,8 +155,11 @@ public:
// after a CacheStoragePermissions() call. See the comments
// for mSessionOnly below.
PRBool UseDB() {
return mUseDB && !mSessionOnly &&
!nsDOMStorageManager::gStorageManager->InPrivateBrowsingMode();
return mUseDB;
}
PRBool SessionOnly() {
return mSessionOnly;
}
// Check whether storage may be used by the caller, and whether it
@ -252,7 +255,7 @@ public:
nsCString& GetQuotaDomainDBKey() {return mQuotaDomainDBKey;}
#ifdef MOZ_STORAGE
static nsDOMStorageDB* gStorageDB;
static nsDOMStorageDBWrapper* gStorageDB;
#endif
};

View File

@ -0,0 +1,361 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** 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.org code.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Neil Deakin <enndeakin@sympatico.ca>
* Honza Bambas <honzab@firemni.cz>
*
* 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 ***** */
#include "nsCOMPtr.h"
#include "nsDOMError.h"
#include "nsDOMStorage.h"
#include "nsDOMStorageDBWrapper.h"
#include "nsIFile.h"
#include "nsIVariant.h"
#include "nsIEffectiveTLDService.h"
#include "nsAppDirectoryServiceDefs.h"
#include "mozStorageCID.h"
#include "mozStorageHelper.h"
#include "mozIStorageService.h"
#include "mozIStorageValueArray.h"
#include "mozIStorageFunction.h"
#include "nsPrintfCString.h"
#include "nsNetUtil.h"
void ReverseString(const nsCSubstring& source, nsCSubstring& result)
{
nsACString::const_iterator sourceBegin, sourceEnd;
source.BeginReading(sourceBegin);
source.EndReading(sourceEnd);
result.SetLength(source.Length());
nsACString::iterator destEnd;
result.EndWriting(destEnd);
while (sourceBegin != sourceEnd) {
*(--destEnd) = *sourceBegin;
++sourceBegin;
}
}
nsresult
nsDOMStorageDBWrapper::Init()
{
nsresult rv;
rv = mPersistentDB.Init();
NS_ENSURE_SUCCESS(rv, rv);
rv = mSessionOnlyDB.Init(&mPersistentDB);
NS_ENSURE_SUCCESS(rv, rv);
rv = mPrivateBrowsingDB.Init();
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
nsresult
nsDOMStorageDBWrapper::GetAllKeys(nsDOMStorage* aStorage,
nsTHashtable<nsSessionStorageEntry>* 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,
const nsAString& aKey,
nsAString& aValue,
PRBool* 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,
const nsAString& aKey,
const nsAString& aValue,
PRBool aSecure,
PRInt32 aQuota,
PRInt32 *aNewUsage)
{
if (nsDOMStorageManager::gStorageManager->InPrivateBrowsingMode())
return mPrivateBrowsingDB.SetKey(aStorage, aKey, aValue, aSecure,
aQuota, aNewUsage);
if (aStorage->SessionOnly())
return mSessionOnlyDB.SetKey(aStorage, aKey, aValue, aSecure,
aQuota, aNewUsage);
return mPersistentDB.SetKey(aStorage, aKey, aValue, aSecure,
aQuota, aNewUsage);
}
nsresult
nsDOMStorageDBWrapper::SetSecure(nsDOMStorage* aStorage,
const nsAString& aKey,
const PRBool 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,
const nsAString& aKey,
PRInt32 aKeyUsage)
{
if (nsDOMStorageManager::gStorageManager->InPrivateBrowsingMode())
return mPrivateBrowsingDB.RemoveKey(aStorage, aKey, aKeyUsage);
if (aStorage->SessionOnly())
return mSessionOnlyDB.RemoveKey(aStorage, aKey, aKeyUsage);
return mPersistentDB.RemoveKey(aStorage, aKey, aKeyUsage);
}
nsresult
nsDOMStorageDBWrapper::ClearStorage(nsDOMStorage* aStorage)
{
if (nsDOMStorageManager::gStorageManager->InPrivateBrowsingMode())
return mPrivateBrowsingDB.ClearStorage(aStorage);
if (aStorage->SessionOnly())
return mSessionOnlyDB.ClearStorage(aStorage);
return mPersistentDB.ClearStorage(aStorage);
}
nsresult
nsDOMStorageDBWrapper::DropSessionOnlyStoragesForHost(const nsACString& aHostName)
{
return mSessionOnlyDB.RemoveOwner(aHostName, PR_TRUE);
}
nsresult
nsDOMStorageDBWrapper::DropPrivateBrowsingStorages()
{
return mPrivateBrowsingDB.RemoveAll();
}
nsresult
nsDOMStorageDBWrapper::RemoveOwner(const nsACString& aOwner,
PRBool aIncludeSubDomains)
{
nsresult rv;
rv = mPrivateBrowsingDB.RemoveOwner(aOwner, aIncludeSubDomains);
NS_ENSURE_SUCCESS(rv, rv);
if (nsDOMStorageManager::gStorageManager->InPrivateBrowsingMode())
return NS_OK;
rv = mSessionOnlyDB.RemoveOwner(aOwner, aIncludeSubDomains);
NS_ENSURE_SUCCESS(rv, rv);
rv = mPersistentDB.RemoveOwner(aOwner, aIncludeSubDomains);
NS_ENSURE_SUCCESS(rv, rv);
return rv;
}
nsresult
nsDOMStorageDBWrapper::RemoveOwners(const nsTArray<nsString> &aOwners,
PRBool aIncludeSubDomains, PRBool aMatch)
{
nsresult rv;
rv = mPrivateBrowsingDB.RemoveOwners(aOwners, aIncludeSubDomains, aMatch);
NS_ENSURE_SUCCESS(rv, rv);
if (nsDOMStorageManager::gStorageManager->InPrivateBrowsingMode())
return NS_OK;
rv = mSessionOnlyDB.RemoveOwners(aOwners, aIncludeSubDomains, aMatch);
NS_ENSURE_SUCCESS(rv, rv);
rv = mPersistentDB.RemoveOwners(aOwners, aIncludeSubDomains, aMatch);
NS_ENSURE_SUCCESS(rv, rv);
return rv;
}
nsresult
nsDOMStorageDBWrapper::RemoveAll()
{
nsresult rv;
rv = mPrivateBrowsingDB.RemoveAll();
NS_ENSURE_SUCCESS(rv, rv);
if (nsDOMStorageManager::gStorageManager->InPrivateBrowsingMode())
return NS_OK;
rv = mSessionOnlyDB.RemoveAll();
NS_ENSURE_SUCCESS(rv, rv);
rv = mPersistentDB.RemoveAll();
NS_ENSURE_SUCCESS(rv, rv);
return rv;
}
nsresult
nsDOMStorageDBWrapper::GetUsage(nsDOMStorage* aStorage, PRInt32 *aUsage)
{
if (nsDOMStorageManager::gStorageManager->InPrivateBrowsingMode())
return mPrivateBrowsingDB.GetUsage(aStorage, aUsage);
if (aStorage->SessionOnly())
return mSessionOnlyDB.GetUsage(aStorage, aUsage);
return mPersistentDB.GetUsage(aStorage, aUsage);
}
nsresult
nsDOMStorageDBWrapper::GetUsage(const nsACString& aDomain,
PRBool aIncludeSubDomains, PRInt32 *aUsage)
{
if (nsDOMStorageManager::gStorageManager->InPrivateBrowsingMode())
return mPrivateBrowsingDB.GetUsage(aDomain, aIncludeSubDomains, aUsage);
#if 0
// XXX Check where from all this method gets called, not sure this should
// include any potential session-only data
nsresult rv;
rv = mSessionOnlyDB.GetUsage(aDomain, aIncludeSubDomains, aUsage);
if (NS_SUECEEDED(rv))
return rv;
#endif
return mPersistentDB.GetUsage(aDomain, aIncludeSubDomains, aUsage);
}
nsresult
nsDOMStorageDBWrapper::CreateOriginScopeDBKey(nsIURI* aUri, nsACString& aKey)
{
nsresult rv;
rv = CreateDomainScopeDBKey(aUri, aKey);
if (NS_FAILED(rv))
return rv;
nsCAutoString scheme;
rv = aUri->GetScheme(scheme);
NS_ENSURE_SUCCESS(rv, rv);
aKey.AppendLiteral(":");
aKey.Append(scheme);
PRInt32 port = NS_GetRealPort(aUri);
if (port != -1) {
aKey.AppendLiteral(":");
aKey.Append(nsPrintfCString(32, "%d", port));
}
return NS_OK;
}
nsresult
nsDOMStorageDBWrapper::CreateDomainScopeDBKey(nsIURI* aUri, nsACString& aKey)
{
nsresult rv;
nsCAutoString host;
rv = aUri->GetAsciiHost(host);
NS_ENSURE_SUCCESS(rv, rv);
rv = CreateDomainScopeDBKey(host, aKey);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
nsresult
nsDOMStorageDBWrapper::CreateDomainScopeDBKey(const nsACString& aAsciiDomain,
nsACString& aKey)
{
if (aAsciiDomain.IsEmpty())
return NS_ERROR_NOT_AVAILABLE;
ReverseString(aAsciiDomain, aKey);
aKey.AppendLiteral(".");
return NS_OK;
}
nsresult
nsDOMStorageDBWrapper::CreateQuotaDomainDBKey(const nsACString& aAsciiDomain,
PRBool aIncludeSubDomains,
nsACString& aKey)
{
nsresult rv;
nsCOMPtr<nsIEffectiveTLDService> eTLDService(do_GetService(
NS_EFFECTIVETLDSERVICE_CONTRACTID, &rv));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIURI> uri;
rv = NS_NewURI(getter_AddRefs(uri), NS_LITERAL_CSTRING("http://") + aAsciiDomain);
NS_ENSURE_SUCCESS(rv, rv);
nsCAutoString eTLDplusOne;
rv = eTLDService->GetBaseDomain(uri, 0, eTLDplusOne);
if (NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS == rv) {
// XXX bug 357323 - what to do for localhost/file exactly?
eTLDplusOne = aAsciiDomain;
rv = NS_OK;
}
NS_ENSURE_SUCCESS(rv, rv);
nsCAutoString subdomainsDBKey;
CreateDomainScopeDBKey(eTLDplusOne, subdomainsDBKey);
if (!aIncludeSubDomains)
subdomainsDBKey.AppendLiteral(":");
aKey.Assign(subdomainsDBKey);
return NS_OK;
}

View File

@ -16,11 +16,11 @@
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2006
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Neil Deakin <enndeakin@sympatico.ca>
* Honza Bambas <honzab@firemni.cz>
*
* 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"),
@ -40,10 +40,13 @@
#define nsDOMStorageDB_h___
#include "nscore.h"
#include "mozIStorageConnection.h"
#include "mozIStorageStatement.h"
#include "nsTHashtable.h"
#include "nsDOMStoragePersistentDB.h"
#include "nsDOMStorageMemoryDB.h"
extern void ReverseString(const nsCSubstring& source, nsCSubstring& result);
class nsDOMStorage;
class nsSessionStorageEntry;
@ -80,11 +83,11 @@ class nsSessionStorageEntry;
* So we use a "quota key" during lookups to calculate the quota. So the
* quota key for localStorage at http://foo.bar.com is "moc.rab.". */
class nsDOMStorageDB
class nsDOMStorageDBWrapper
{
public:
nsDOMStorageDB() {}
~nsDOMStorageDB() {}
nsDOMStorageDBWrapper() {}
~nsDOMStorageDBWrapper() {}
nsresult
Init();
@ -138,7 +141,20 @@ public:
/**
* Remove all keys belonging to this storage.
*/
nsresult ClearStorage(nsDOMStorage* aStorage);
nsresult
ClearStorage(nsDOMStorage* aStorage);
/**
* Drop session-only storage for a specific host and all it's subdomains
*/
nsresult
DropSessionOnlyStoragesForHost(const nsACString& aHostName);
/**
* Drop everything we gathered to private browsing in-memory database
*/
nsresult
DropPrivateBrowsingStorages();
/**
* Removes all keys added by a given domain.
@ -195,25 +211,9 @@ public:
PRBool aIncludeSubDomains, nsACString& aKey);
protected:
nsCOMPtr<mozIStorageConnection> mConnection;
nsCOMPtr<mozIStorageStatement> mGetAllKeysStatement;
nsCOMPtr<mozIStorageStatement> mGetKeyValueStatement;
nsCOMPtr<mozIStorageStatement> mInsertKeyStatement;
nsCOMPtr<mozIStorageStatement> mUpdateKeyStatement;
nsCOMPtr<mozIStorageStatement> mSetSecureStatement;
nsCOMPtr<mozIStorageStatement> mRemoveKeyStatement;
nsCOMPtr<mozIStorageStatement> mRemoveOwnerStatement;
nsCOMPtr<mozIStorageStatement> mRemoveStorageStatement;
nsCOMPtr<mozIStorageStatement> mRemoveAllStatement;
nsCOMPtr<mozIStorageStatement> mGetUsageStatement;
nsCString mCachedOwner;
PRInt32 mCachedUsage;
nsresult
GetUsageInternal(const nsACString& aQuotaDomainDBKey, PRInt32 *aUsage);
nsDOMStoragePersistentDB mPersistentDB;
nsDOMStorageMemoryDB mSessionOnlyDB;
nsDOMStorageMemoryDB mPrivateBrowsingDB;
};
#endif /* nsDOMStorageDB_h___ */

View File

@ -0,0 +1,448 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** 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.org code.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Neil Deakin <enndeakin@sympatico.ca>
* Honza Bambas <honzab@firemni.cz>
*
* 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 ***** */
#include "nsCOMPtr.h"
#include "nsDOMError.h"
#include "nsDOMStorage.h"
#include "nsDOMStorageMemoryDB.h"
#include "nsNetUtil.h"
nsresult
nsDOMStorageMemoryDB::Init(nsDOMStoragePersistentDB* aPreloadDB)
{
if (!mData.Init(20))
return NS_ERROR_OUT_OF_MEMORY;
mPreloadDB = aPreloadDB;
return NS_OK;
}
static PLDHashOperator
AllKeyEnum(nsSessionStorageEntry* aEntry, void* userArg)
{
nsDOMStorageMemoryDB::nsStorageItemsTable *target =
(nsDOMStorageMemoryDB::nsStorageItemsTable *)userArg;
nsDOMStorageMemoryDB::nsInMemoryItem* item =
new nsDOMStorageMemoryDB::nsInMemoryItem();
if (!item)
return PL_DHASH_STOP;
aEntry->mItem->GetValue(item->mValue);
nsresult rv = aEntry->mItem->GetSecure(&item->mSecure);
if (NS_FAILED(rv))
item->mSecure = PR_FALSE;
target->Put(aEntry->GetKey(), item);
return PL_DHASH_NEXT;
}
nsresult
nsDOMStorageMemoryDB::GetItemsTable(nsDOMStorage* aStorage,
nsInMemoryStorage** aMemoryStorage)
{
if (mData.Get(aStorage->GetScopeDBKey(), aMemoryStorage))
return NS_OK;
*aMemoryStorage = nsnull;
nsInMemoryStorage* storageData = new nsInMemoryStorage();
if (!storageData)
return NS_ERROR_OUT_OF_MEMORY;
storageData->mUsageDelta = 0;
if (!storageData->mTable.Init()) {
delete storageData;
return NS_ERROR_OUT_OF_MEMORY;
}
if (mPreloadDB) {
nsresult rv;
nsTHashtable<nsSessionStorageEntry> keys;
keys.Init();
rv = mPreloadDB->GetAllKeys(aStorage, &keys);
NS_ENSURE_SUCCESS(rv, rv);
mPreloading = PR_TRUE;
keys.EnumerateEntries(AllKeyEnum, &storageData->mTable);
mPreloading = PR_FALSE;
}
mData.Put(aStorage->GetScopeDBKey(), storageData);
*aMemoryStorage = storageData;
return NS_OK;
}
struct GetAllKeysEnumStruc
{
nsTHashtable<nsSessionStorageEntry>* mTarget;
nsDOMStorage* mStorage;
};
static PLDHashOperator
GetAllKeysEnum(const nsAString& keyname,
nsDOMStorageMemoryDB::nsInMemoryItem* item,
void *closure)
{
GetAllKeysEnumStruc* struc = (GetAllKeysEnumStruc*)closure;
nsSessionStorageEntry* entry = struc->mTarget->PutEntry(keyname);
if (!entry)
return PL_DHASH_STOP;
entry->mItem = new nsDOMStorageItem(struc->mStorage,
keyname,
EmptyString(),
item->mSecure);
if (!entry->mItem)
return PL_DHASH_STOP;
return PL_DHASH_NEXT;
}
nsresult
nsDOMStorageMemoryDB::GetAllKeys(nsDOMStorage* aStorage,
nsTHashtable<nsSessionStorageEntry>* aKeys)
{
nsresult rv;
nsInMemoryStorage* storage;
rv = GetItemsTable(aStorage, &storage);
NS_ENSURE_SUCCESS(rv, rv);
GetAllKeysEnumStruc struc;
struc.mTarget = aKeys;
struc.mStorage = aStorage;
storage->mTable.EnumerateRead(GetAllKeysEnum, &struc);
return NS_OK;
}
nsresult
nsDOMStorageMemoryDB::GetKeyValue(nsDOMStorage* 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);
}
nsresult rv;
nsInMemoryStorage* storage;
rv = GetItemsTable(aStorage, &storage);
NS_ENSURE_SUCCESS(rv, rv);
nsInMemoryItem* item;
if (!storage->mTable.Get(aKey, &item))
return NS_ERROR_DOM_NOT_FOUND_ERR;
aValue = item->mValue;
*aSecure = item->mSecure;
return NS_OK;
}
nsresult
nsDOMStorageMemoryDB::SetKey(nsDOMStorage* aStorage,
const nsAString& aKey,
const nsAString& aValue,
PRBool aSecure,
PRInt32 aQuota,
PRInt32 *aNewUsage)
{
nsresult rv;
nsInMemoryStorage* storage;
rv = GetItemsTable(aStorage, &storage);
NS_ENSURE_SUCCESS(rv, rv);
PRInt32 usage = 0;
if (!aStorage->GetQuotaDomainDBKey().IsEmpty()) {
rv = GetUsage(aStorage, &usage);
NS_ENSURE_SUCCESS(rv, rv);
}
usage += aKey.Length() + aValue.Length();
nsInMemoryItem* item;
if (!storage->mTable.Get(aKey, &item)) {
if (usage > aQuota) {
return NS_ERROR_DOM_QUOTA_REACHED;
}
item = new nsInMemoryItem();
if (!item)
return NS_ERROR_OUT_OF_MEMORY;
storage->mTable.Put(aKey, item);
storage->mUsageDelta += aKey.Length();
}
else
{
usage -= aKey.Length() + item->mValue.Length();
if (usage > aQuota) {
return NS_ERROR_DOM_QUOTA_REACHED;
}
}
storage->mUsageDelta += aValue.Length() - item->mValue.Length();
item->mValue = aValue;
item->mSecure = aSecure;
*aNewUsage = usage;
return NS_OK;
}
nsresult
nsDOMStorageMemoryDB::SetSecure(nsDOMStorage* aStorage,
const nsAString& aKey,
const PRBool aSecure)
{
nsresult rv;
nsInMemoryStorage* storage;
rv = GetItemsTable(aStorage, &storage);
NS_ENSURE_SUCCESS(rv, rv);
nsInMemoryItem* item;
if (!storage->mTable.Get(aKey, &item))
return NS_ERROR_DOM_NOT_FOUND_ERR;
item->mSecure = aSecure;
return NS_OK;
}
nsresult
nsDOMStorageMemoryDB::RemoveKey(nsDOMStorage* aStorage,
const nsAString& aKey,
PRInt32 aKeyUsage)
{
nsresult rv;
nsInMemoryStorage* storage;
rv = GetItemsTable(aStorage, &storage);
NS_ENSURE_SUCCESS(rv, rv);
nsInMemoryItem* item;
if (!storage->mTable.Get(aKey, &item))
return NS_ERROR_DOM_NOT_FOUND_ERR;
storage->mUsageDelta -= aKey.Length() + item->mValue.Length();
storage->mTable.Remove(aKey);
return NS_OK;
}
static PLDHashOperator
RemoveAllKeysEnum(const nsAString& keyname,
nsAutoPtr<nsDOMStorageMemoryDB::nsInMemoryItem>& item,
void *closure)
{
nsDOMStorageMemoryDB::nsInMemoryStorage* storage =
(nsDOMStorageMemoryDB::nsInMemoryStorage*)closure;
storage->mUsageDelta -= keyname.Length() + item->mValue.Length();
return PL_DHASH_REMOVE;
}
nsresult
nsDOMStorageMemoryDB::ClearStorage(nsDOMStorage* 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)
{
mData.Remove(aStorage->GetScopeDBKey());
return NS_OK;
}
struct RemoveOwnersStruc
{
nsCString* mSubDomain;
PRBool mMatch;
};
static PLDHashOperator
RemoveOwnersEnum(const nsACString& key,
nsAutoPtr<nsDOMStorageMemoryDB::nsInMemoryStorage>& storage,
void *closure)
{
RemoveOwnersStruc* struc = (RemoveOwnersStruc*)closure;
if (StringBeginsWith(key, *(struc->mSubDomain)) == struc->mMatch)
return PL_DHASH_REMOVE;
return PL_DHASH_NEXT;
}
nsresult
nsDOMStorageMemoryDB::RemoveOwner(const nsACString& aOwner,
PRBool aIncludeSubDomains)
{
nsCAutoString subdomainsDBKey;
nsDOMStorageDBWrapper::CreateDomainScopeDBKey(aOwner, subdomainsDBKey);
if (!aIncludeSubDomains)
subdomainsDBKey.AppendLiteral(":");
RemoveOwnersStruc struc;
struc.mSubDomain = &subdomainsDBKey;
struc.mMatch = PR_TRUE;
mData.Enumerate(RemoveOwnersEnum, &struc);
return NS_OK;
}
nsresult
nsDOMStorageMemoryDB::RemoveOwners(const nsTArray<nsString> &aOwners,
PRBool aIncludeSubDomains,
PRBool aMatch)
{
if (aOwners.Length() == 0) {
if (aMatch) {
return NS_OK;
}
return RemoveAll();
}
for (PRUint32 i = 0; i < aOwners.Length(); i++) {
nsCAutoString quotaKey;
nsresult rv;
rv = nsDOMStorageDBWrapper::CreateDomainScopeDBKey(
NS_ConvertUTF16toUTF8(aOwners[i]), quotaKey);
if (!aIncludeSubDomains)
quotaKey.AppendLiteral(":");
RemoveOwnersStruc struc;
struc.mSubDomain = &quotaKey;
struc.mMatch = aMatch;
mData.Enumerate(RemoveOwnersEnum, &struc);
}
return NS_OK;
}
nsresult
nsDOMStorageMemoryDB::RemoveAll()
{
mData.Clear(); // XXX Check this releases all instances
return NS_OK;
}
nsresult
nsDOMStorageMemoryDB::GetUsage(nsDOMStorage* aStorage, PRInt32 *aUsage)
{
return GetUsageInternal(aStorage->GetQuotaDomainDBKey(), aUsage);
}
nsresult
nsDOMStorageMemoryDB::GetUsage(const nsACString& aDomain,
PRBool aIncludeSubDomains,
PRInt32 *aUsage)
{
nsresult rv;
nsCAutoString quotadomainDBKey;
rv = nsDOMStorageDBWrapper::CreateQuotaDomainDBKey(aDomain,
aIncludeSubDomains,
quotadomainDBKey);
NS_ENSURE_SUCCESS(rv, rv);
return GetUsageInternal(quotadomainDBKey, aUsage);
}
struct GetUsageEnumStruc
{
PRInt32 mUsage;
nsCString mSubdomain;
};
static PLDHashOperator
GetUsageEnum(const nsACString& key,
nsDOMStorageMemoryDB::nsInMemoryStorage* storageData,
void *closure)
{
GetUsageEnumStruc* struc = (GetUsageEnumStruc*)closure;
if (StringBeginsWith(key, struc->mSubdomain))
struc->mUsage += storageData->mUsageDelta;
return PL_DHASH_NEXT;
}
nsresult
nsDOMStorageMemoryDB::GetUsageInternal(const nsACString& aQuotaDomainDBKey,
PRInt32 *aUsage)
{
GetUsageEnumStruc struc;
struc.mUsage = 0;
struc.mSubdomain = aQuotaDomainDBKey;
if (mPreloadDB) {
nsresult rv;
rv = mPreloadDB->GetUsageInternal(aQuotaDomainDBKey, &struc.mUsage);
NS_ENSURE_SUCCESS(rv, rv);
}
mData.EnumerateRead(GetUsageEnum, &struc);
*aUsage = struc.mUsage;
return NS_OK;
}

View File

@ -0,0 +1,188 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** 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.org code.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Honza Bambas <honzab@firemni.cz>
*
* 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 ***** */
#ifndef nsDOMStorageMemoryDB_h___
#define nsDOMStorageMemoryDB_h___
#include "nscore.h"
#include "nsClassHashtable.h"
#include "nsDataHashtable.h"
class nsDOMStoragePersistentDB;
class nsDOMStorageMemoryDB
{
public:
nsDOMStorageMemoryDB() : mPreloading(PR_FALSE) {}
~nsDOMStorageMemoryDB() {}
class nsInMemoryItem
{
public:
PRBool mSecure;
nsString mValue;
};
typedef nsClassHashtable<nsStringHashKey, nsInMemoryItem> nsStorageItemsTable;
class nsInMemoryStorage
{
public:
nsStorageItemsTable mTable;
PRInt32 mUsageDelta;
nsInMemoryStorage() { mTable.Init(20); }
};
/**
* @param aPreloadDB
* If non-null, data for a domain/origin will be preloaded from
* the provided database. Used for session-only cookies mode to
* provide existing data from the persistent database.
*/
nsresult
Init(nsDOMStoragePersistentDB* aPreloadDB = nsnull);
/**
*
*/
nsresult
GetItemsTable(nsDOMStorage* aStorage,
nsInMemoryStorage** aMemoryStorage);
/**
* Retrieve a list of all the keys associated with a particular domain.
*/
nsresult
GetAllKeys(nsDOMStorage* 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,
const nsAString& aKey,
nsAString& aValue,
PRBool* aSecure);
/**
* Set the value and secure flag for a key in storage.
*/
nsresult
SetKey(nsDOMStorage* aStorage,
const nsAString& aKey,
const nsAString& aValue,
PRBool aSecure,
PRInt32 aQuota,
PRInt32* aNewUsage);
/**
* Set the secure flag for a key in storage. Does nothing if the key was
* not found.
*/
nsresult
SetSecure(nsDOMStorage* aStorage,
const nsAString& aKey,
const PRBool aSecure);
/**
* Removes a key from storage.
*/
nsresult
RemoveKey(nsDOMStorage* aStorage,
const nsAString& aKey,
PRInt32 aKeyUsage);
/**
* Remove all keys belonging to this storage.
*/
nsresult
ClearStorage(nsDOMStorage* aStorage);
/**
* If we have changed the persistent storage, drop any potential session storages
*/
nsresult
DropStorage(nsDOMStorage* aStorage);
/**
* Removes all keys added by a given domain.
*/
nsresult
RemoveOwner(const nsACString& aOwner, PRBool aIncludeSubDomains);
/**
* Removes keys owned by domains that either match or don't match the
* list.
*/
nsresult
RemoveOwners(const nsTArray<nsString>& aOwners,
PRBool aIncludeSubDomains, PRBool aMatch);
/**
* Removes all keys from storage. Used when clearing storage.
*/
nsresult
RemoveAll();
/**
* Returns usage for a storage using its GetQuotaDomainDBKey() as a key.
*/
nsresult
GetUsage(nsDOMStorage* aStorage, PRInt32 *aUsage);
/**
* Returns usage of the domain and optionaly by any subdomain.
*/
nsresult
GetUsage(const nsACString& aDomain, PRBool aIncludeSubDomains, PRInt32 *aUsage);
protected:
nsClassHashtable<nsCStringHashKey, nsInMemoryStorage> mData;
nsDOMStoragePersistentDB* mPreloadDB;
PRBool mPreloading;
nsresult
GetUsageInternal(const nsACString& aQuotaDomainDBKey, PRInt32 *aUsage);
};
#endif

View File

@ -39,7 +39,8 @@
#include "nsCOMPtr.h"
#include "nsDOMError.h"
#include "nsDOMStorage.h"
#include "nsDOMStorageDB.h"
#include "nsDOMStorageDBWrapper.h"
#include "nsDOMStoragePersistentDB.h"
#include "nsIFile.h"
#include "nsIVariant.h"
#include "nsIEffectiveTLDService.h"
@ -52,23 +53,6 @@
#include "nsPrintfCString.h"
#include "nsNetUtil.h"
static
void ReverseString(const nsCSubstring& source, nsCSubstring& result)
{
nsACString::const_iterator sourceBegin, sourceEnd;
source.BeginReading(sourceBegin);
source.EndReading(sourceEnd);
result.SetLength(source.Length());
nsACString::iterator destEnd;
result.EndWriting(destEnd);
while (sourceBegin != sourceEnd) {
*(--destEnd) = *sourceBegin;
++sourceBegin;
}
}
class nsReverseStringSQLFunction : public mozIStorageFunction
{
NS_DECL_ISUPPORTS
@ -103,7 +87,7 @@ nsReverseStringSQLFunction::OnFunctionCall(
}
nsresult
nsDOMStorageDB::Init()
nsDOMStoragePersistentDB::Init()
{
nsresult rv;
@ -170,7 +154,7 @@ nsDOMStorageDB::Init()
NS_LITERAL_CSTRING("DROP TABLE webappsstore"));
NS_ENSURE_SUCCESS(rv, rv);
}
// Check if there is storage of Gecko 1.8 and if so, upgrade that storage
// to actual webappsstore2 table and drop the obsolete table. Potential
// duplicates will be ignored.
@ -190,7 +174,7 @@ nsDOMStorageDB::Init()
NS_LITERAL_CSTRING("DROP TABLE moz_webappsstore"));
NS_ENSURE_SUCCESS(rv, rv);
}
// retrieve all keys associated with a domain
rv = mConnection->CreateStatement(
NS_LITERAL_CSTRING("SELECT key, secure FROM webappsstore2 "
@ -259,20 +243,21 @@ nsDOMStorageDB::Init()
NS_LITERAL_CSTRING("DELETE FROM webappsstore2"),
getter_AddRefs(mRemoveAllStatement));
NS_ENSURE_SUCCESS(rv, rv);
// check the usage for a given owner
rv = mConnection->CreateStatement(
NS_LITERAL_CSTRING("SELECT SUM(LENGTH(key) + LENGTH(value)) "
"FROM webappsstore2 "
"WHERE scope GLOB ?1"),
getter_AddRefs(mGetUsageStatement));
NS_ENSURE_SUCCESS(rv, rv);
return rv;
return NS_OK;
}
nsresult
nsDOMStorageDB::GetAllKeys(nsDOMStorage* aStorage,
nsTHashtable<nsSessionStorageEntry>* aKeys)
nsDOMStoragePersistentDB::GetAllKeys(nsDOMStorage* aStorage,
nsTHashtable<nsSessionStorageEntry>* aKeys)
{
mozStorageStatementScoper scope(mGetAllKeysStatement);
@ -293,7 +278,7 @@ nsDOMStorageDB::GetAllKeys(nsDOMStorage* aStorage,
nsSessionStorageEntry* entry = aKeys->PutEntry(key);
NS_ENSURE_TRUE(entry, NS_ERROR_OUT_OF_MEMORY);
entry->mItem = new nsDOMStorageItem(aStorage, key, EmptyString(), secureInt);
if (!entry->mItem) {
aKeys->RawRemoveEntry(entry);
@ -305,10 +290,10 @@ nsDOMStorageDB::GetAllKeys(nsDOMStorage* aStorage,
}
nsresult
nsDOMStorageDB::GetKeyValue(nsDOMStorage* aStorage,
const nsAString& aKey,
nsAString& aValue,
PRBool* aSecure)
nsDOMStoragePersistentDB::GetKeyValue(nsDOMStorage* aStorage,
const nsAString& aKey,
nsAString& aValue,
PRBool* aSecure)
{
mozStorageStatementScoper scope(mGetKeyValueStatement);
@ -340,15 +325,15 @@ nsDOMStorageDB::GetKeyValue(nsDOMStorage* aStorage,
}
nsresult
nsDOMStorageDB::SetKey(nsDOMStorage* aStorage,
const nsAString& aKey,
const nsAString& aValue,
PRBool aSecure,
PRInt32 aQuota,
PRInt32 *aNewUsage)
nsDOMStoragePersistentDB::SetKey(nsDOMStorage* aStorage,
const nsAString& aKey,
const nsAString& aValue,
PRBool aSecure,
PRInt32 aQuota,
PRInt32 *aNewUsage)
{
mozStorageStatementScoper scope(mGetKeyValueStatement);
PRInt32 usage = 0;
nsresult rv;
if (!aStorage->GetQuotaDomainDBKey().IsEmpty()) {
@ -380,7 +365,7 @@ nsDOMStorageDB::SetKey(nsDOMStorage* aStorage,
nsAutoString previousValue;
rv = mGetKeyValueStatement->GetString(0, previousValue);
NS_ENSURE_SUCCESS(rv, rv);
usage -= aKey.Length() + previousValue.Length();
mGetKeyValueStatement->Reset();
@ -408,9 +393,9 @@ nsDOMStorageDB::SetKey(nsDOMStorage* aStorage,
if (usage > aQuota) {
return NS_ERROR_DOM_QUOTA_REACHED;
}
mozStorageStatementScoper scopeinsert(mInsertKeyStatement);
rv = mInsertKeyStatement->BindUTF8StringParameter(0,
aStorage->GetScopeDBKey());
NS_ENSURE_SUCCESS(rv, rv);
@ -436,9 +421,9 @@ nsDOMStorageDB::SetKey(nsDOMStorage* aStorage,
}
nsresult
nsDOMStorageDB::SetSecure(nsDOMStorage* aStorage,
const nsAString& aKey,
const PRBool aSecure)
nsDOMStoragePersistentDB::SetSecure(nsDOMStorage* aStorage,
const nsAString& aKey,
const PRBool aSecure)
{
nsresult rv;
@ -455,9 +440,9 @@ nsDOMStorageDB::SetSecure(nsDOMStorage* aStorage,
}
nsresult
nsDOMStorageDB::RemoveKey(nsDOMStorage* aStorage,
const nsAString& aKey,
PRInt32 aKeyUsage)
nsDOMStoragePersistentDB::RemoveKey(nsDOMStorage* aStorage,
const nsAString& aKey,
PRInt32 aKeyUsage)
{
mozStorageStatementScoper scope(mRemoveKeyStatement);
@ -475,7 +460,7 @@ nsDOMStorageDB::RemoveKey(nsDOMStorage* aStorage,
}
nsresult
nsDOMStorageDB::ClearStorage(nsDOMStorage* aStorage)
nsDOMStoragePersistentDB::ClearStorage(nsDOMStorage* aStorage)
{
mozStorageStatementScoper scope(mRemoveStorageStatement);
@ -492,12 +477,13 @@ nsDOMStorageDB::ClearStorage(nsDOMStorage* aStorage)
}
nsresult
nsDOMStorageDB::RemoveOwner(const nsACString& aOwner, PRBool aIncludeSubDomains)
nsDOMStoragePersistentDB::RemoveOwner(const nsACString& aOwner,
PRBool aIncludeSubDomains)
{
mozStorageStatementScoper scope(mRemoveOwnerStatement);
nsCAutoString subdomainsDBKey;
nsDOMStorageDB::CreateDomainScopeDBKey(aOwner, subdomainsDBKey);
nsDOMStorageDBWrapper::CreateDomainScopeDBKey(aOwner, subdomainsDBKey);
if (!aIncludeSubDomains)
subdomainsDBKey.AppendLiteral(":");
@ -518,8 +504,9 @@ nsDOMStorageDB::RemoveOwner(const nsACString& aOwner, PRBool aIncludeSubDomains)
nsresult
nsDOMStorageDB::RemoveOwners(const nsTArray<nsString> &aOwners,
PRBool aIncludeSubDomains, PRBool aMatch)
nsDOMStoragePersistentDB::RemoveOwners(const nsTArray<nsString> &aOwners,
PRBool aIncludeSubDomains,
PRBool aMatch)
{
if (aOwners.Length() == 0) {
if (aMatch) {
@ -555,7 +542,8 @@ nsDOMStorageDB::RemoveOwners(const nsTArray<nsString> &aOwners,
for (PRUint32 i = 0; i < aOwners.Length(); i++) {
nsCAutoString quotaKey;
rv = nsDOMStorageDB::CreateDomainScopeDBKey(NS_ConvertUTF16toUTF8(aOwners[i]), quotaKey);
rv = nsDOMStorageDBWrapper::CreateDomainScopeDBKey(
NS_ConvertUTF16toUTF8(aOwners[i]), quotaKey);
if (!aIncludeSubDomains)
quotaKey.AppendLiteral(":");
@ -572,36 +560,37 @@ nsDOMStorageDB::RemoveOwners(const nsTArray<nsString> &aOwners,
}
nsresult
nsDOMStorageDB::RemoveAll()
nsDOMStoragePersistentDB::RemoveAll()
{
mozStorageStatementScoper scope(mRemoveAllStatement);
return mRemoveAllStatement->Execute();
}
nsresult
nsDOMStorageDB::GetUsage(nsDOMStorage* aStorage, PRInt32 *aUsage)
nsDOMStoragePersistentDB::GetUsage(nsDOMStorage* aStorage, PRInt32 *aUsage)
{
return GetUsageInternal(aStorage->GetQuotaDomainDBKey(), aUsage);
}
nsresult
nsDOMStorageDB::GetUsage(const nsACString& aDomain,
PRBool aIncludeSubDomains, PRInt32 *aUsage)
nsDOMStoragePersistentDB::GetUsage(const nsACString& aDomain,
PRBool aIncludeSubDomains,
PRInt32 *aUsage)
{
nsresult rv;
nsCAutoString quotadomainDBKey;
rv = nsDOMStorageDB::CreateQuotaDomainDBKey(aDomain,
aIncludeSubDomains,
quotadomainDBKey);
rv = nsDOMStorageDBWrapper::CreateQuotaDomainDBKey(aDomain,
aIncludeSubDomains,
quotadomainDBKey);
NS_ENSURE_SUCCESS(rv, rv);
return GetUsageInternal(quotadomainDBKey, aUsage);
}
nsresult
nsDOMStorageDB::GetUsageInternal(const nsACString& aQuotaDomainDBKey,
PRInt32 *aUsage)
nsDOMStoragePersistentDB::GetUsageInternal(const nsACString& aQuotaDomainDBKey,
PRInt32 *aUsage)
{
if (aQuotaDomainDBKey == mCachedOwner) {
*aUsage = mCachedUsage;
@ -612,9 +601,10 @@ nsDOMStorageDB::GetUsageInternal(const nsACString& aQuotaDomainDBKey,
nsresult rv;
rv = mGetUsageStatement->BindUTF8StringParameter(0, aQuotaDomainDBKey);
rv = mGetUsageStatement->BindUTF8StringParameter(0, aQuotaDomainDBKey +
NS_LITERAL_CSTRING("*"));
NS_ENSURE_SUCCESS(rv, rv);
PRBool exists;
rv = mGetUsageStatement->ExecuteStep(&exists);
NS_ENSURE_SUCCESS(rv, rv);
@ -623,7 +613,7 @@ nsDOMStorageDB::GetUsageInternal(const nsACString& aQuotaDomainDBKey,
*aUsage = 0;
return NS_OK;
}
rv = mGetUsageStatement->GetInt32(0, aUsage);
NS_ENSURE_SUCCESS(rv, rv);
@ -634,89 +624,3 @@ nsDOMStorageDB::GetUsageInternal(const nsACString& aQuotaDomainDBKey,
return NS_OK;
}
nsresult
nsDOMStorageDB::CreateOriginScopeDBKey(nsIURI* aUri, nsACString& aKey)
{
nsresult rv;
rv = CreateDomainScopeDBKey(aUri, aKey);
if (NS_FAILED(rv))
return rv;
nsCAutoString scheme;
rv = aUri->GetScheme(scheme);
NS_ENSURE_SUCCESS(rv, rv);
aKey.AppendLiteral(":");
aKey.Append(scheme);
PRInt32 port = NS_GetRealPort(aUri);
if (port != -1) {
aKey.AppendLiteral(":");
aKey.Append(nsPrintfCString(32, "%d", port));
}
return NS_OK;
}
nsresult
nsDOMStorageDB::CreateDomainScopeDBKey(nsIURI* aUri, nsACString& aKey)
{
nsresult rv;
nsCAutoString host;
rv = aUri->GetAsciiHost(host);
NS_ENSURE_SUCCESS(rv, rv);
rv = CreateDomainScopeDBKey(host, aKey);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
nsresult
nsDOMStorageDB::CreateDomainScopeDBKey(const nsACString& aAsciiDomain, nsACString& aKey)
{
if (aAsciiDomain.IsEmpty())
return NS_ERROR_NOT_AVAILABLE;
ReverseString(aAsciiDomain, aKey);
aKey.AppendLiteral(".");
return NS_OK;
}
nsresult
nsDOMStorageDB::CreateQuotaDomainDBKey(const nsACString& aAsciiDomain,
PRBool aIncludeSubDomains, nsACString& aKey)
{
nsresult rv;
nsCOMPtr<nsIEffectiveTLDService> eTLDService(do_GetService(
NS_EFFECTIVETLDSERVICE_CONTRACTID, &rv));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIURI> uri;
rv = NS_NewURI(getter_AddRefs(uri), NS_LITERAL_CSTRING("http://") + aAsciiDomain);
NS_ENSURE_SUCCESS(rv, rv);
nsCAutoString eTLDplusOne;
rv = eTLDService->GetBaseDomain(uri, 0, eTLDplusOne);
if (NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS == rv) {
// XXX bug 357323 - what to do for localhost/file exactly?
eTLDplusOne = aAsciiDomain;
rv = NS_OK;
}
NS_ENSURE_SUCCESS(rv, rv);
nsCAutoString subdomainsDBKey;
nsDOMStorageDB::CreateDomainScopeDBKey(eTLDplusOne, subdomainsDBKey);
if (!aIncludeSubDomains)
subdomainsDBKey.AppendLiteral(":");
subdomainsDBKey.AppendLiteral("*");
aKey.Assign(subdomainsDBKey);
return NS_OK;
}

View File

@ -0,0 +1,171 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** 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.org code.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2006
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Neil Deakin <enndeakin@sympatico.ca>
*
* 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 ***** */
#ifndef nsDOMStoragePersistentDB_h___
#define nsDOMStoragePersistentDB_h___
#include "nscore.h"
#include "mozIStorageConnection.h"
#include "mozIStorageStatement.h"
#include "nsTHashtable.h"
class nsDOMStorage;
class nsSessionStorageEntry;
class nsDOMStoragePersistentDB
{
public:
nsDOMStoragePersistentDB() {}
~nsDOMStoragePersistentDB() {}
nsresult
Init();
/**
* Retrieve a list of all the keys associated with a particular domain.
*/
nsresult
GetAllKeys(nsDOMStorage* 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,
const nsAString& aKey,
nsAString& aValue,
PRBool* aSecure);
/**
* Set the value and secure flag for a key in storage.
*/
nsresult
SetKey(nsDOMStorage* aStorage,
const nsAString& aKey,
const nsAString& aValue,
PRBool aSecure,
PRInt32 aQuota,
PRInt32* aNewUsage);
/**
* Set the secure flag for a key in storage. Does nothing if the key was
* not found.
*/
nsresult
SetSecure(nsDOMStorage* aStorage,
const nsAString& aKey,
const PRBool aSecure);
/**
* Removes a key from storage.
*/
nsresult
RemoveKey(nsDOMStorage* aStorage,
const nsAString& aKey,
PRInt32 aKeyUsage);
/**
* Remove all keys belonging to this storage.
*/
nsresult ClearStorage(nsDOMStorage* aStorage);
/**
* Removes all keys added by a given domain.
*/
nsresult
RemoveOwner(const nsACString& aOwner, PRBool aIncludeSubDomains);
/**
* Removes keys owned by domains that either match or don't match the
* list.
*/
nsresult
RemoveOwners(const nsTArray<nsString>& aOwners,
PRBool aIncludeSubDomains, PRBool aMatch);
/**
* Removes all keys from storage. Used when clearing storage.
*/
nsresult
RemoveAll();
/**
* Returns usage for a storage using its GetQuotaDomainDBKey() as a key.
*/
nsresult
GetUsage(nsDOMStorage* aStorage, PRInt32 *aUsage);
/**
* Returns usage of the domain and optionaly by any subdomain.
*/
nsresult
GetUsage(const nsACString& aDomain, PRBool aIncludeSubDomains, PRInt32 *aUsage);
/**
* Clears all in-memory data from private browsing mode
*/
nsresult ClearAllPrivateBrowsingData();
protected:
nsCOMPtr<mozIStorageConnection> mConnection;
nsCOMPtr<mozIStorageStatement> mGetAllKeysStatement;
nsCOMPtr<mozIStorageStatement> mGetKeyValueStatement;
nsCOMPtr<mozIStorageStatement> mInsertKeyStatement;
nsCOMPtr<mozIStorageStatement> mUpdateKeyStatement;
nsCOMPtr<mozIStorageStatement> mSetSecureStatement;
nsCOMPtr<mozIStorageStatement> mRemoveKeyStatement;
nsCOMPtr<mozIStorageStatement> mRemoveOwnerStatement;
nsCOMPtr<mozIStorageStatement> mRemoveStorageStatement;
nsCOMPtr<mozIStorageStatement> mRemoveAllStatement;
nsCOMPtr<mozIStorageStatement> mGetUsageStatement;
nsCString mCachedOwner;
PRInt32 mCachedUsage;
friend class nsDOMStorageDBWrapper;
friend class nsDOMStorageMemoryDB;
nsresult
GetUsageInternal(const nsACString& aQuotaDomainDBKey, PRInt32 *aUsage);
};
#endif /* nsDOMStorageDB_h___ */

View File

@ -54,14 +54,20 @@ _TEST_FILES = \
frameSlaveNotEqual.html \
frameReplace.html \
frameQuota.html \
frameQuotaSessionOnly.html \
frameOrder.html \
interOriginFrame.js \
interOriginTest.js \
interOriginTest2.js \
pbSwitch.js \
test_brokenUTF-16.html \
test_cookieBlock.html \
test_cookieSession-phase1.html \
test_cookieSession-phase2.html \
test_embededNulls.html \
test_localStorageBase.html \
test_localStorageBasePrivateBrowsing.html \
test_localStorageBaseSessionOnly.html \
test_localStorageOriginsEquals.html \
test_localStorageOriginsDiff.html \
test_localStorageOriginsPortDiffs.html \
@ -69,8 +75,11 @@ _TEST_FILES = \
test_localStorageOriginsSchemaDiffs.html \
test_localStorageReplace.html \
test_localStorageQuota.html \
test_localStorageQuotaPrivateBrowsing.html \
test_localStorageQuotaSessionOnly.html \
test_localStorageKeyOrder.html \
test_removeOwnersAPI.html \
test_removeOwnersAPISessionOnly.html \
test_storageConstructor.html \
$(NULL)

View File

@ -0,0 +1,117 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>slave for sessionStorage test</title>
<script type="text/javascript" src="interOriginFrame.js"></script>
<script type="text/javascript">
const DOM_QUOTA_REACHED = 2152924150;
function checkException(func, exc)
{
var exceptionThrew = false;
try {
func();
}
catch (ex) {
exceptionThrew = true;
is(ex.result, exc, "Expected "+exc+" exception");
}
ok(exceptionThrew, "Exception "+exc+" threw at "+location);
}
function doStep()
{
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var io = Components.classes["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService);
var uri = io.newURI(window.location, "", null);
var cp = Components.classes["@mozilla.org/cookie/permission;1"]
.getService(Components.interfaces.nsICookiePermission);
cp.setAccess(uri, Components.interfaces.nsICookiePermission.ACCESS_SESSION);
var query = location.search.substring(1);
var queries = query.split("&");
var operation = queries[0];
var keyName = queries[1];
var result = queries[2];
switch (result)
{
case "success":
switch (operation)
{
case "add":
// Store 500 bytes long string must succeed
localStorage.setItem(keyName, "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890");
is(localStorage.getItem(keyName), "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", "500 bytes key "+keyName+" stored");
break;
case "remove":
localStorage.removeItem(keyName);
is(localStorage.getItem(keyName), null, "Key "+keyName+" removed");
break;
case "checkclean":
is(localStorage.getItem(keyName), null, "Key "+keyName+" not present");
break;
case "checknotclean":
is(localStorage.getItem(keyName), "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", "Key "+keyName+" is present");
break;
}
break;
case "failure":
switch (operation)
{
case "add":
// Attempt to store 500 bytes long string that doens't
// fit the quota, have to throw DOM_QUOTA_REACHED exception
checkException(function() {
localStorage.setItem(keyName, "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890");
}, DOM_QUOTA_REACHED);
is(localStorage.getItem(keyName), null, "500 bytes key "+keyName+" is NOT stored");
break;
case "add2":
// Attempt to change a key value to reach the DOM quota and
// check it fails and the old key value is still present.
checkException(function() {
localStorage.setItem(keyName, "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890");
}, DOM_QUOTA_REACHED);
is(localStorage.getItem(keyName), "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", "Key "+keyName+" left unchanged");
break;
}
break;
case "":
switch (operation)
{
case "clear":
localStorage.clear();
cp.setAccess(uri, Components.interfaces.nsICookiePermission.ACCESS_DEFAULT);
break;
}
break;
}
// Just inform the master we are finished now
postMsg("done");
return false;
}
</script>
</head>
<body onload="postMsg('frame loaded');">
</body>
</html>

View File

@ -0,0 +1,39 @@
var _PBSvc = null;
function get_PBSvc()
{
if (_PBSvc)
return _PBSvc;
try {
_PBSvc = Components.classes["@mozilla.org/privatebrowsing;1"].
getService(Components.interfaces.nsIPrivateBrowsingService);
return _PBSvc;
}
catch (ex) {
}
return null;
}
function enterPrivateBrowsing()
{
if (get_PBSvc()) {
var prefBranch = Components.classes["@mozilla.org/preferences-service;1"].
getService(Components.interfaces.nsIPrefBranch);
prefBranch.setBoolPref("browser.privatebrowsing.keep_current_session", true);
get_PBSvc().privateBrowsingEnabled = true;
}
}
function leavePrivateBrowsing()
{
if (get_PBSvc()) {
get_PBSvc().privateBrowsingEnabled = false;
var prefBranch = Components.classes["@mozilla.org/preferences-service;1"].
getService(Components.interfaces.nsIPrefBranch);
prefBranch.clearUserPref("browser.privatebrowsing.keep_current_session");
}
}

View File

@ -17,40 +17,23 @@ function startTest()
var uri = io.newURI(window.location, "", null);
var cp = Components.classes["@mozilla.org/cookie/permission;1"]
.getService(Components.interfaces.nsICookiePermission);
cp.setAccess(uri, Components.interfaces.nsICookiePermission.ACCESS_DENY);
try {
localStorage.setItem("blocked", "blockedvalue");
ok(false, "Exception while accessing localStorage");
ok(false, "Exception for localStorage.setItem, ACCESS_DENY");
}
catch (ex) {
ok(true, "Exception while accessing localStorage");
ok(true, "Exception for localStorage.setItem, ACCESS_DENY");
}
try {
localStorage.getItem("blocked");
ok(false, "Exception while accessing localStorage");
ok(false, "Exception for localStorage.getItem, ACCESS_DENY");
}
catch (ex) {
ok(true, "Exception while accessing localStorage");
}
cp.setAccess(uri, Components.interfaces.nsICookiePermission.ACCESS_SESSION);
try {
localStorage.setItem("blocked", "blockedvalue");
ok(false, "Exception while accessing localStorage");
}
catch (ex) {
ok(true, "Exception while accessing localStorage");
}
try {
localStorage.getItem("blocked");
ok(false, "Exception while accessing localStorage");
}
catch (ex) {
ok(true, "Exception while accessing localStorage");
ok(true, "Exception for localStorage.getItem, ACCESS_DENY");
}
cp.setAccess(uri, Components.interfaces.nsICookiePermission.ACCESS_DEFAULT);

View File

@ -0,0 +1,49 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>cookie per-session only test</title>
<script type="text/javascript" src="/MochiKit/packed.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<script type="text/javascript">
/*
Set cookie access to be just per session and store to the localStorage.
Content stored must prevail only for session of the browser, so it must
be accessible in another window we try to access that key in the same
storage.
*/
function startTest()
{
localStorage.setItem("persistent1", "persistent value 1");
localStorage.setItem("persistent2", "persistent value 2");
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var io = Components.classes["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService);
var uri = io.newURI(window.location, "", null);
var cp = Components.classes["@mozilla.org/cookie/permission;1"]
.getService(Components.interfaces.nsICookiePermission);
cp.setAccess(uri, Components.interfaces.nsICookiePermission.ACCESS_SESSION);
localStorage.setItem("session only", "session value");
is(localStorage.getItem("session only"), "session value");
is(localStorage.getItem("persistent1"), "persistent value 1");
is(localStorage.getItem("persistent2"), "persistent value 2");
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
</script>
</head>
<body onload="startTest();">
</body>
</html>

View File

@ -0,0 +1,84 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>cookie per-session only test</title>
<script type="text/javascript" src="/MochiKit/packed.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<script type="text/javascript">
function startTest()
{
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var io = Components.classes["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService);
var uri = io.newURI(window.location, "", null);
var cp = Components.classes["@mozilla.org/cookie/permission;1"]
.getService(Components.interfaces.nsICookiePermission);
is(localStorage.getItem("session only"), "session value", "Value present when cookies in session-only mode");
is(localStorage.getItem("persistent1"), "persistent value 1", "Persistent value present");
is(localStorage.getItem("persistent2"), "persistent value 2", "Persistent value present");
localStorage.setItem("persistent1", "changed persistent value 1");
localStorage.removeItem("persistent2");
is(localStorage.getItem("session only"), "session value", "Value present when cookies in session-only mode");
is(localStorage.getItem("persistent1"), "changed persistent value 1", "Persistent value present");
is(localStorage.getItem("persistent2"), null, "Persistent value removed");
// This clear has to delete only changes made in session only mode
localStorage.clear();
is(localStorage.getItem("session only"), null, "Value not present when cookies in session-only mode after delete");
is(localStorage.getItem("persistent1"), null, "Persistent value not present in session only after delete");
is(localStorage.getItem("persistent2"), null, "Persistent value not present in session only after delete");
localStorage.setItem("session only 2", "must be deleted on drop of session-only cookies permissions");
cp.setAccess(uri, Components.interfaces.nsICookiePermission.ACCESS_DEFAULT);
is(localStorage.getItem("session only"), null, "No value when cookies are in default mode");
is(localStorage.getItem("session only 2"), null, "No value when cookies are in default mode");
is(localStorage.getItem("persistent1"), "persistent value 1", "Persistent value present");
is(localStorage.getItem("persistent2"), "persistent value 2", "Persistent value present");
cp.setAccess(uri, Components.interfaces.nsICookiePermission.ACCESS_SESSION);
is(localStorage.getItem("session only"), null, "Value not present when cookies in session-only mode after delete");
is(localStorage.getItem("session only 2"), null, "Value not present when cookies in session-only mode after delete");
is(localStorage.getItem("persistent1"), "persistent value 1", "Persistent value present again");
is(localStorage.getItem("persistent2"), "persistent value 2", "Persistent value present again");
cp.setAccess(uri, Components.interfaces.nsICookiePermission.ACCESS_DEFAULT);
localStorage.clear();
is(localStorage.getItem("session only"), null, "No value when cookies are in default mode");
is(localStorage.getItem("persistent1"), null, "Persistent value not present after delete");
is(localStorage.getItem("persistent2"), null, "Persistent value not present after delete");
cp.setAccess(uri, Components.interfaces.nsICookiePermission.ACCESS_SESSION);
is(localStorage.getItem("session only"), null, "Value not present when cookies in session-only mode after delete");
is(localStorage.getItem("session only 2"), null, "No value when cookies are in default mode");
is(localStorage.getItem("persistent1"), null, "Persistent value not present in session only after delete");
is(localStorage.getItem("persistent2"), null, "Persistent value not present in session only after delete");
cp.setAccess(uri, Components.interfaces.nsICookiePermission.ACCESS_DEFAULT);
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
</script>
</head>
<body onload="startTest();">
</body>
</html>

View File

@ -172,6 +172,7 @@ function startTest()
localStorage.removeItem("key1"); // Just check there is no exception
localStorage.removeItem("key2"); // Just check there is no exception
localStorage.clear();
SimpleTest.finish();
}

View File

@ -0,0 +1,218 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>localStorage basic test, while in sesison only mode</title>
<script type="text/javascript" src="/MochiKit/packed.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="pbSwitch.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<script type="text/javascript">
var INDEX_SIZE_ERR = 1;
function checkException(func, exc)
{
var exceptionThrew = false;
try {
func();
}
catch (ex) {
exceptionThrew = true;
is(ex.code, exc, "Expected "+exc+" exception");
}
ok(exceptionThrew, "Exception "+exc+" threw");
}
function startTest()
{
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
if (get_PBSvc())
doTest();
else
ok(true, "No private browsing service, test could not be performed");
SimpleTest.finish();
}
function doTest()
{
localStorage.setItem("persistent", "persistent1");
enterPrivateBrowsing();
is(localStorage.getItem("persistent"), null, "previous values are inaccessible");
// Initially check the localStorage is empty
is(localStorage.length, 0, "The storage is empty [1]");
checkException(function() {localStorage.key(0);}, INDEX_SIZE_ERR);
checkException(function() {localStorage.key(-1);}, INDEX_SIZE_ERR);
checkException(function() {localStorage.key(1);}, INDEX_SIZE_ERR);
is(localStorage.getItem("nonexisting"), null, "Nonexisting item is null (getItem())");
is(localStorage["nonexisting"], null, "Nonexisting item is null (array access)");
is(localStorage.nonexisting, null, "Nonexisting item is null (property access)");
localStorage.removeItem("nonexisting"); // Just check there is no exception
is(typeof localStorage.getItem("nonexisting"), "object", "getItem('nonexisting') is object");
is(typeof localStorage["nonexisting"], "object", "['nonexisting'] is object");
is(typeof localStorage.nonexisting, "object", "nonexisting is object");
is(typeof localStorage.getItem("nonexisting2"), "object", "getItem('nonexisting2') is object");
is(typeof localStorage["nonexisting2"], "object", "['nonexisting2'] is object");
is(typeof localStorage.nonexisting2, "object", "nonexisting2 is object");
// add an empty-value key
localStorage.setItem("empty", "");
is(localStorage.getItem("empty"), "", "Empty value (getItem())");
is(localStorage["empty"], "", "Empty value (array access)");
is(localStorage.empty, "", "Empty value (property access)");
is(typeof localStorage.getItem("empty"), "string", "getItem('empty') is string");
is(typeof localStorage["empty"], "string", "['empty'] is string");
is(typeof localStorage.empty, "string", "empty is string");
localStorage.removeItem("empty");
is(localStorage.length, 0, "The storage has no keys");
is(localStorage.getItem("empty"), null, "empty item is null (getItem())");
is(localStorage["empty"], null, "empty item is null (array access)");
is(localStorage.empty, null, "empty item is null (property access)");
is(typeof localStorage.getItem("empty"), "object", "getItem('empty') is object");
is(typeof localStorage["empty"], "object", "['empty'] is object");
is(typeof localStorage.empty, "object", "empty is object");
// add one key, check it is there
localStorage.setItem("key1", "value1");
is(localStorage.length, 1, "The storage has one key-value pair");
is(localStorage.key(0), "key1");
checkException(function() {localStorage.key(-1);}, INDEX_SIZE_ERR);
checkException(function() {localStorage.key(1);}, INDEX_SIZE_ERR);
// check all access method give the correct result
// and are of the correct type
is(localStorage.getItem("key1"), "value1", "getItem('key1') == value1");
is(localStorage["key1"], "value1", "['key1'] == value1");
is(localStorage.key1, "value1", "key1 == value1");
is(typeof localStorage.getItem("key1"), "string", "getItem('key1') is string");
is(typeof localStorage["key1"], "string", "['key1'] is string");
is(typeof localStorage.key1, "string", "key1 is string");
// remove the previously added key and check the storage is empty
localStorage.removeItem("key1");
is(localStorage.length, 0, "The storage is empty [2]");
checkException(function() {localStorage.key(0);}, INDEX_SIZE_ERR);
is(localStorage.getItem("key1"), null, "\'key1\' removed");
is(typeof localStorage.getItem("key1"), "object", "getItem('key1') is object");
is(typeof localStorage["key1"], "object", "['key1'] is object");
is(typeof localStorage.key1, "object", "key1 is object");
// add one key, check it is there
localStorage.setItem("key1", "value1");
is(localStorage.length, 1, "The storage has one key-value pair");
is(localStorage.key(0), "key1");
is(localStorage.getItem("key1"), "value1");
// add a second key
localStorage.setItem("key2", "value2");
is(localStorage.length, 2, "The storage has two key-value pairs");
is(localStorage.key(1), "key1"); // This test might not be accurate because order is not preserved
is(localStorage.key(0), "key2");
is(localStorage.getItem("key1"), "value1");
is(localStorage.getItem("key2"), "value2");
// change the second key
localStorage.setItem("key2", "value2-2");
is(localStorage.length, 2, "The storage has two key-value pairs");
is(localStorage.key(1), "key1"); // After key value changes the order must be preserved
is(localStorage.key(0), "key2");
checkException(function() {localStorage.key(-1);}, INDEX_SIZE_ERR);
checkException(function() {localStorage.key(2);}, INDEX_SIZE_ERR);
is(localStorage.getItem("key1"), "value1");
is(localStorage.getItem("key2"), "value2-2");
// change the first key
localStorage.setItem("key1", "value1-2");
is(localStorage.length, 2, "The storage has two key-value pairs");
is(localStorage.key(1), "key1"); // After key value changes the order must be preserved
is(localStorage.key(0), "key2");
checkException(function() {localStorage.key(-1);}, INDEX_SIZE_ERR);
checkException(function() {localStorage.key(2);}, INDEX_SIZE_ERR);
is(localStorage.getItem("key1"), "value1-2");
is(localStorage.getItem("key2"), "value2-2");
// remove the second key
localStorage.removeItem("key2");
is(localStorage.length, 1, "The storage has one key-value pair");
is(localStorage.key(0), "key1");
checkException(function() {localStorage.key(-1);}, INDEX_SIZE_ERR);
checkException(function() {localStorage.key(1);}, INDEX_SIZE_ERR);
is(localStorage.getItem("key1"), "value1-2");
// JS property test
localStorage.testA = "valueA";
is(localStorage.testA, "valueA");
is(localStorage["testA"], "valueA");
is(localStorage.getItem("testA"), "valueA");
localStorage.testA = "valueA2";
is(localStorage.testA, "valueA2");
is(localStorage["testA"], "valueA2");
is(localStorage.getItem("testA"), "valueA2");
localStorage["testB"] = "valueB";
is(localStorage.testB, "valueB");
is(localStorage["testB"], "valueB");
is(localStorage.getItem("testB"), "valueB");
localStorage["testB"] = "valueB2";
is(localStorage.testB, "valueB2");
is(localStorage["testB"], "valueB2");
is(localStorage.getItem("testB"), "valueB2");
localStorage.setItem("testC", "valueC");
is(localStorage.testC, "valueC");
is(localStorage["testC"], "valueC");
is(localStorage.getItem("testC"), "valueC");
localStorage.setItem("testC", "valueC2");
is(localStorage.testC, "valueC2");
is(localStorage["testC"], "valueC2");
is(localStorage.getItem("testC"), "valueC2");
// Clear the storage
localStorage.clear();
is(localStorage.length, 0, "The storage is empty [3]");
checkException(function() {localStorage.key(0);}, INDEX_SIZE_ERR); // this is unspecified!
checkException(function() {localStorage.key(-1);}, INDEX_SIZE_ERR);
checkException(function() {localStorage.key(1);}, INDEX_SIZE_ERR);
is(localStorage.getItem("nonexisting"), null, "Nonexisting item is null");
is(localStorage.getItem("key1"), null, "key1 removed");
is(localStorage.getItem("key2"), null, "key2 removed");
localStorage.removeItem("nonexisting"); // Just check there is no exception
localStorage.removeItem("key1"); // Just check there is no exception
localStorage.removeItem("key2"); // Just check there is no exception
localStorage.setItem("must disappear", "private browsing value");
leavePrivateBrowsing();
enterPrivateBrowsing();
is(localStorage.getItem("must disappear"), null, "private browsing values threw away");
is(localStorage.length, 0, "No items");
leavePrivateBrowsing();
is(localStorage.getItem("persistent"), "persistent1", "back in normal mode");
localStorage.clear();
}
SimpleTest.waitForExplicitFinish();
</script>
</head>
<body onload="startTest();">
</body>
</html>

View File

@ -0,0 +1,201 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>localStorage basic test, while in sesison only mode</title>
<script type="text/javascript" src="/MochiKit/packed.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<script type="text/javascript">
var INDEX_SIZE_ERR = 1;
function checkException(func, exc)
{
var exceptionThrew = false;
try {
func();
}
catch (ex) {
exceptionThrew = true;
is(ex.code, exc, "Expected "+exc+" exception");
}
ok(exceptionThrew, "Exception "+exc+" threw");
}
function startTest()
{
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var io = Components.classes["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService);
var uri = io.newURI(window.location, "", null);
var cp = Components.classes["@mozilla.org/cookie/permission;1"]
.getService(Components.interfaces.nsICookiePermission);
cp.setAccess(uri, Components.interfaces.nsICookiePermission.ACCESS_SESSION);
// Initially check the localStorage is empty
is(localStorage.length, 0, "The storage is empty [1]");
checkException(function() {localStorage.key(0);}, INDEX_SIZE_ERR);
checkException(function() {localStorage.key(-1);}, INDEX_SIZE_ERR);
checkException(function() {localStorage.key(1);}, INDEX_SIZE_ERR);
is(localStorage.getItem("nonexisting"), null, "Nonexisting item is null (getItem())");
is(localStorage["nonexisting"], null, "Nonexisting item is null (array access)");
is(localStorage.nonexisting, null, "Nonexisting item is null (property access)");
localStorage.removeItem("nonexisting"); // Just check there is no exception
is(typeof localStorage.getItem("nonexisting"), "object", "getItem('nonexisting') is object");
is(typeof localStorage["nonexisting"], "object", "['nonexisting'] is object");
is(typeof localStorage.nonexisting, "object", "nonexisting is object");
is(typeof localStorage.getItem("nonexisting2"), "object", "getItem('nonexisting2') is object");
is(typeof localStorage["nonexisting2"], "object", "['nonexisting2'] is object");
is(typeof localStorage.nonexisting2, "object", "nonexisting2 is object");
// add an empty-value key
localStorage.setItem("empty", "");
is(localStorage.getItem("empty"), "", "Empty value (getItem())");
is(localStorage["empty"], "", "Empty value (array access)");
is(localStorage.empty, "", "Empty value (property access)");
is(typeof localStorage.getItem("empty"), "string", "getItem('empty') is string");
is(typeof localStorage["empty"], "string", "['empty'] is string");
is(typeof localStorage.empty, "string", "empty is string");
localStorage.removeItem("empty");
is(localStorage.length, 0, "The storage has no keys");
is(localStorage.getItem("empty"), null, "empty item is null (getItem())");
is(localStorage["empty"], null, "empty item is null (array access)");
is(localStorage.empty, null, "empty item is null (property access)");
is(typeof localStorage.getItem("empty"), "object", "getItem('empty') is object");
is(typeof localStorage["empty"], "object", "['empty'] is object");
is(typeof localStorage.empty, "object", "empty is object");
// add one key, check it is there
localStorage.setItem("key1", "value1");
is(localStorage.length, 1, "The storage has one key-value pair");
is(localStorage.key(0), "key1");
checkException(function() {localStorage.key(-1);}, INDEX_SIZE_ERR);
checkException(function() {localStorage.key(1);}, INDEX_SIZE_ERR);
// check all access method give the correct result
// and are of the correct type
is(localStorage.getItem("key1"), "value1", "getItem('key1') == value1");
is(localStorage["key1"], "value1", "['key1'] == value1");
is(localStorage.key1, "value1", "key1 == value1");
is(typeof localStorage.getItem("key1"), "string", "getItem('key1') is string");
is(typeof localStorage["key1"], "string", "['key1'] is string");
is(typeof localStorage.key1, "string", "key1 is string");
// remove the previously added key and check the storage is empty
localStorage.removeItem("key1");
is(localStorage.length, 0, "The storage is empty [2]");
checkException(function() {localStorage.key(0);}, INDEX_SIZE_ERR);
is(localStorage.getItem("key1"), null, "\'key1\' removed");
is(typeof localStorage.getItem("key1"), "object", "getItem('key1') is object");
is(typeof localStorage["key1"], "object", "['key1'] is object");
is(typeof localStorage.key1, "object", "key1 is object");
// add one key, check it is there
localStorage.setItem("key1", "value1");
is(localStorage.length, 1, "The storage has one key-value pair");
is(localStorage.key(0), "key1");
is(localStorage.getItem("key1"), "value1");
// add a second key
localStorage.setItem("key2", "value2");
is(localStorage.length, 2, "The storage has two key-value pairs");
is(localStorage.key(1), "key1"); // This test might not be accurate because order is not preserved
is(localStorage.key(0), "key2");
is(localStorage.getItem("key1"), "value1");
is(localStorage.getItem("key2"), "value2");
// change the second key
localStorage.setItem("key2", "value2-2");
is(localStorage.length, 2, "The storage has two key-value pairs");
is(localStorage.key(1), "key1"); // After key value changes the order must be preserved
is(localStorage.key(0), "key2");
checkException(function() {localStorage.key(-1);}, INDEX_SIZE_ERR);
checkException(function() {localStorage.key(2);}, INDEX_SIZE_ERR);
is(localStorage.getItem("key1"), "value1");
is(localStorage.getItem("key2"), "value2-2");
// change the first key
localStorage.setItem("key1", "value1-2");
is(localStorage.length, 2, "The storage has two key-value pairs");
is(localStorage.key(1), "key1"); // After key value changes the order must be preserved
is(localStorage.key(0), "key2");
checkException(function() {localStorage.key(-1);}, INDEX_SIZE_ERR);
checkException(function() {localStorage.key(2);}, INDEX_SIZE_ERR);
is(localStorage.getItem("key1"), "value1-2");
is(localStorage.getItem("key2"), "value2-2");
// remove the second key
localStorage.removeItem("key2");
is(localStorage.length, 1, "The storage has one key-value pair");
is(localStorage.key(0), "key1");
checkException(function() {localStorage.key(-1);}, INDEX_SIZE_ERR);
checkException(function() {localStorage.key(1);}, INDEX_SIZE_ERR);
is(localStorage.getItem("key1"), "value1-2");
// JS property test
localStorage.testA = "valueA";
is(localStorage.testA, "valueA");
is(localStorage["testA"], "valueA");
is(localStorage.getItem("testA"), "valueA");
localStorage.testA = "valueA2";
is(localStorage.testA, "valueA2");
is(localStorage["testA"], "valueA2");
is(localStorage.getItem("testA"), "valueA2");
localStorage["testB"] = "valueB";
is(localStorage.testB, "valueB");
is(localStorage["testB"], "valueB");
is(localStorage.getItem("testB"), "valueB");
localStorage["testB"] = "valueB2";
is(localStorage.testB, "valueB2");
is(localStorage["testB"], "valueB2");
is(localStorage.getItem("testB"), "valueB2");
localStorage.setItem("testC", "valueC");
is(localStorage.testC, "valueC");
is(localStorage["testC"], "valueC");
is(localStorage.getItem("testC"), "valueC");
localStorage.setItem("testC", "valueC2");
is(localStorage.testC, "valueC2");
is(localStorage["testC"], "valueC2");
is(localStorage.getItem("testC"), "valueC2");
// Clear the storage
localStorage.clear();
is(localStorage.length, 0, "The storage is empty [3]");
checkException(function() {localStorage.key(0);}, INDEX_SIZE_ERR); // this is unspecified!
checkException(function() {localStorage.key(-1);}, INDEX_SIZE_ERR);
checkException(function() {localStorage.key(1);}, INDEX_SIZE_ERR);
is(localStorage.getItem("nonexisting"), null, "Nonexisting item is null");
is(localStorage.getItem("key1"), null, "key1 removed");
is(localStorage.getItem("key2"), null, "key2 removed");
localStorage.removeItem("nonexisting"); // Just check there is no exception
localStorage.removeItem("key1"); // Just check there is no exception
localStorage.removeItem("key2"); // Just check there is no exception
cp.setAccess(uri, Components.interfaces.nsICookiePermission.ACCESS_DEFAULT);
localStorage.clear();
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
</script>
</head>
<body onload="startTest();">
</body>
</html>

View File

@ -0,0 +1,138 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>localStorage and DOM quota test</title>
<script type="text/javascript" src="/MochiKit/packed.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="pbSwitch.js"></script>
<script type="text/javascript" src="interOriginTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<script type="text/javascript">
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var currentTest = 1;
var prefs = Components.classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefBranch);
var quota;
try {
quota = prefs.getIntPref("dom.storage.default_quota");
} catch (ex) {
quota = 5*1024;
}
prefs.setIntPref("dom.storage.default_quota", 1);
enterPrivateBrowsing();
function doNextTest()
{
if (!get_PBSvc()) {
// There is no PB service, skip all tests
currentTest = 999;
ok(true, "No private browsing service, test could not be performed");
}
slave = frame;
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
switch (currentTest)
{
// Initialy setup the quota to testing value of 1024B and
// set a 500 bytes key with name length 1 (allocate 501 bytes)
case 1:
slaveOrigin = "http://example.com";
slave.location = slaveOrigin + slavePath + "frameQuota.html?add&A&success";
break;
// In subdomain now set another key with length 500 bytes, i.e.
// allocate 501 bytes
case 2:
slaveOrigin = "http://test1.example.com";
slave.location = slaveOrigin + slavePath + "frameQuota.html?add&B&success";
break;
// Try to set the same key value again to check we don't fail
// even 1002 bytes has already been exhausted from the quota
// We just change the value of an existing key.
case 3:
slaveOrigin = "http://test1.example.com";
slave.location = slaveOrigin + slavePath + "frameQuota.html?add&B&success";
break;
// Try to set the same key to a larger value that would lead to
// quota reach and check that the value is still the old one
case 4:
slaveOrigin = "http://test1.example.com";
slave.location = slaveOrigin + slavePath + "frameQuota.html?add2&B&failure";
break;
// In a different subdomain try to set a new 500 bytes key
// and check we fail because we are over the quota
case 5:
slaveOrigin = "https://test2.example.com";
slave.location = slaveOrigin + slavePath + "frameQuota.html?add&C&failure";
break;
// Remove from the second subdomain the second key, it must not fail
// This should release the allocated space of the quota assigned to
// example.com.
case 6:
slaveOrigin = "http://test1.example.com";
slave.location = slaveOrigin + slavePath + "frameQuota.html?remove&B&success";
break;
// Now try again to set 500 bytes key, it must succeed.
case 7:
slaveOrigin = "https://test2.example.com";
slave.location = slaveOrigin + slavePath + "frameQuota.html?add&C&success";
break;
case 8:
// Do a clean up...
// TODO Bug 455070, use just ?clear what invokes call
// of clear() in the target frame. W/o clear method we must
// call clear implemented as removeItem for each item in
// the localStorage.
slaveOrigin = "http://example.com";
slave.location = slaveOrigin + slavePath + "frameQuota.html?clear&A&";
break;
case 9:
// Do a clean up...
slaveOrigin = "http://test1.example.com";
slave.location = slaveOrigin + slavePath + "frameQuota.html?clear&B&";
break;
case 10:
// Do a clean up...
slaveOrigin = "https://test2.example.com";
slave.location = slaveOrigin + slavePath + "frameQuota.html?clear&C&";
break;
default:
prefs.setIntPref("dom.storage.default_quota", quota);
leavePrivateBrowsing();
SimpleTest.finish();
}
++currentTest;
}
function doStep()
{
}
SimpleTest.waitForExplicitFinish();
</script>
</head>
<body onload="doNextTest();">
<iframe src="" name="frame"></iframe>
</body>
</html>

View File

@ -0,0 +1,136 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>localStorage and DOM quota test</title>
<script type="text/javascript" src="/MochiKit/packed.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="interOriginTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<script type="text/javascript">
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var currentTest = 1;
var prefs = Components.classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefBranch);
var io = Components.classes["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService);
var uri = io.newURI(window.location, "", null);
var cp = Components.classes["@mozilla.org/cookie/permission;1"]
.getService(Components.interfaces.nsICookiePermission);
cp.setAccess(uri, Components.interfaces.nsICookiePermission.ACCESS_SESSION);
var quota;
function doNextTest()
{
slave = frame;
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
switch (currentTest)
{
// Initialy setup the quota to testing value of 1024B and
// set a 500 bytes key with name length 1 (allocate 501 bytes)
case 1:
try {
quota = prefs.getIntPref("dom.storage.default_quota");
} catch (ex) {
quota = 5*1024;
}
prefs.setIntPref("dom.storage.default_quota", 1);
slaveOrigin = "http://example.com";
slave.location = slaveOrigin + slavePath + "frameQuotaSessionOnly.html?add&A&success";
break;
// In subdomain now set another key with length 500 bytes, i.e.
// allocate 501 bytes
case 2:
slaveOrigin = "http://test1.example.com";
slave.location = slaveOrigin + slavePath + "frameQuotaSessionOnly.html?add&B&success";
break;
// Try to set the same key value again to check we don't fail
// even 1002 bytes has already been exhausted from the quota
// We just change the value of an existing key.
case 3:
slaveOrigin = "http://test1.example.com";
slave.location = slaveOrigin + slavePath + "frameQuotaSessionOnly.html?add&B&success";
break;
// Try to set the same key to a larger value that would lead to
// quota reach and check that the value is still the old one
case 4:
slaveOrigin = "http://test1.example.com";
slave.location = slaveOrigin + slavePath + "frameQuotaSessionOnly.html?add2&B&failure";
break;
// In a different subdomain try to set a new 500 bytes key
// and check we fail because we are over the quota
case 5:
slaveOrigin = "https://test2.example.com";
slave.location = slaveOrigin + slavePath + "frameQuotaSessionOnly.html?add&C&failure";
break;
// Remove from the second subdomain the second key, it must not fail
// This should release the allocated space of the quota assigned to
// example.com.
case 6:
slaveOrigin = "http://test1.example.com";
slave.location = slaveOrigin + slavePath + "frameQuotaSessionOnly.html?remove&B&success";
break;
// Now try again to set 500 bytes key, it must succeed.
case 7:
slaveOrigin = "https://test2.example.com";
slave.location = slaveOrigin + slavePath + "frameQuotaSessionOnly.html?add&C&success";
break;
case 8:
// Do a clean up...
// TODO Bug 455070, use just ?clear what invokes call
// of clear() in the target frame. W/o clear method we must
// call clear implemented as removeItem for each item in
// the localStorage.
slaveOrigin = "http://example.com";
slave.location = slaveOrigin + slavePath + "frameQuotaSessionOnly.html?clear&A&";
break;
case 9:
// Do a clean up...
slaveOrigin = "http://test1.example.com";
slave.location = slaveOrigin + slavePath + "frameQuotaSessionOnly.html?clear&B&";
break;
case 10:
// Do a clean up...
slaveOrigin = "https://test2.example.com";
slave.location = slaveOrigin + slavePath + "frameQuotaSessionOnly.html?clear&C&";
break;
case 11:
prefs.setIntPref("dom.storage.default_quota", quota);
cp.setAccess(uri, Components.interfaces.nsICookiePermission.ACCESS_DEFAULT);
SimpleTest.finish();
}
++currentTest;
}
function doStep()
{
}
SimpleTest.waitForExplicitFinish();
</script>
</head>
<body onload="doNextTest();">
<iframe src="" name="frame"></iframe>
</body>
</html>

View File

@ -0,0 +1,135 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>localStorage and DOM quota test</title>
<script type="text/javascript" src="/MochiKit/packed.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="interOriginTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<script type="text/javascript">
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var currentTest = 1;
var currentStep = 1;
function addOfflineApp(url)
{
var permissionManager = Components.classes["@mozilla.org/permissionmanager;1"]
.getService(Components.interfaces.nsIPermissionManager);
var uri = Components.classes["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService)
.newURI(url, null, null);
permissionManager.add(uri, "offline-app",
Components.interfaces.nsIPermissionManager.ALLOW_ACTION);
}
function removeOfflineApp(url)
{
var permissionManager = Components.classes["@mozilla.org/permissionmanager;1"]
.getService(Components.interfaces.nsIPermissionManager);
var uri = Components.classes["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService)
.newURI(url, null, null);
permissionManager.remove(uri.host, "offline-app");
}
function doNextTest()
{
slave = frame;
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
currentStep = 1;
switch (currentTest)
{
// Add something to storage of example.com
case 1:
slaveOrigin = "http://example.com";
slave.location = slaveOrigin + slavePath + "frameQuotaSessionOnly.html?add&A&success";
break;
// Add something to storage of test1.example.com, secure schema
case 2:
slaveOrigin = "https://test1.example.com";
slave.location = slaveOrigin + slavePath + "frameQuotaSessionOnly.html?add&B&success";
break;
// Add something to storage of http://sub1.xn--hxajbheg2az3al.xn--jxalpdlp, secure schema
case 3:
slaveOrigin = "http://sub1.xn--hxajbheg2az3al.xn--jxalpdlp";
slave.location = slaveOrigin + slavePath + "frameQuotaSessionOnly.html?add&C&success";
break;
// Call RemoveOwners API through storage manager.
// Classify the sites above as offline-app using
// the permission manager to let the storage manager
// know about them.
case 4:
addOfflineApp("http://example.com");
addOfflineApp("http://sub1.xn--hxajbheg2az3al.xn--jxalpdlp");
var manager = Components.classes["@mozilla.org/dom/storagemanager;1"]
.getService(Components.interfaces.nsIDOMStorageManager);
try {
manager.clearOfflineApps();
}
catch (ex) {
ok(false, "Exception not thrown during clearOfflineApps()");
}
removeOfflineApp("http://example.com");
removeOfflineApp("http://sub1.xn--hxajbheg2az3al.xn--jxalpdlp");
// Now check that those two sites' data disappeared
slaveOrigin = "http://example.com";
slave.location = slaveOrigin + slavePath + "frameQuotaSessionOnly.html?checkclean&A&success";
break;
case 5:
slaveOrigin = "http://sub1.xn--hxajbheg2az3al.xn--jxalpdlp";
slave.location = slaveOrigin + slavePath + "frameQuotaSessionOnly.html?checkclean&C&success";
break;
case 6:
slaveOrigin = "https://test1.example.com";
slave.location = slaveOrigin + slavePath + "frameQuotaSessionOnly.html?checknotclean&B&success";
break;
case 7:
addOfflineApp("https://test1.example.com");
var manager = Components.classes["@mozilla.org/dom/storagemanager;1"]
.getService(Components.interfaces.nsIDOMStorageManager);
try {
manager.clearOfflineApps();
}
catch (ex) {
ok(false, "Exception not thrown during clearOfflineApps()");
}
removeOfflineApp("https://test1.example.com");
// Now check that those site's data disappeared
slaveOrigin = "https://test1.example.com";
slave.location = slaveOrigin + slavePath + "frameQuotaSessionOnly.html?checkclean&B&success";
break;
case 8:
SimpleTest.finish();
}
++currentTest;
}
function doStep()
{
}
SimpleTest.waitForExplicitFinish();
</script>
</head>
<body onload="doNextTest();">
<iframe src="" name="frame"></iframe>
</body>
</html>