mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-11 20:35:50 +00:00
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:
parent
b92cdd8365
commit
7c8df0e8e5
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
|
361
dom/src/storage/nsDOMStorageDBWrapper.cpp
Normal file
361
dom/src/storage/nsDOMStorageDBWrapper.cpp
Normal 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;
|
||||
}
|
@ -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___ */
|
448
dom/src/storage/nsDOMStorageMemoryDB.cpp
Normal file
448
dom/src/storage/nsDOMStorageMemoryDB.cpp
Normal 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 = "aKey;
|
||||
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;
|
||||
}
|
188
dom/src/storage/nsDOMStorageMemoryDB.h
Normal file
188
dom/src/storage/nsDOMStorageMemoryDB.h
Normal 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
|
@ -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;
|
||||
}
|
171
dom/src/storage/nsDOMStoragePersistentDB.h
Normal file
171
dom/src/storage/nsDOMStoragePersistentDB.h
Normal 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___ */
|
@ -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)
|
||||
|
||||
|
117
dom/tests/mochitest/localstorage/frameQuotaSessionOnly.html
Normal file
117
dom/tests/mochitest/localstorage/frameQuotaSessionOnly.html
Normal 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>
|
39
dom/tests/mochitest/localstorage/pbSwitch.js
Normal file
39
dom/tests/mochitest/localstorage/pbSwitch.js
Normal 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");
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
@ -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>
|
@ -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>
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
Loading…
Reference in New Issue
Block a user