Bug 455070 - Make sessionStorage object conform the WHATWG spec, r+sr=jst

This commit is contained in:
Honza Bambas 2009-05-20 10:23:41 +02:00
Родитель d4e58eb985
Коммит 2b0d93ff16
22 изменённых файлов: 856 добавлений и 185 удалений

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

@ -1271,7 +1271,7 @@ SessionStoreService.prototype = {
for (let i = 0; i < aHistory.count; i++) {
let uri = aHistory.getEntryAtIndex(i, false).URI;
// sessionStorage is saved per domain (cf. nsDocShell::GetSessionStorageForURI)
// sessionStorage is saved per origin (cf. nsDocShell::GetSessionStorageForURI)
let domain = uri.spec;
try {
if (uri.host)
@ -1295,9 +1295,7 @@ SessionStoreService.prototype = {
try {
let key = storage.key(j);
let item = storage.getItem(key);
data[key] = { value: item.value };
if (uri.schemeIs("https") && item.secure)
data[key].secure = true;
data[key] = item;
}
catch (ex) { /* XXXzeniko this currently throws for secured items (cf. bug 442048) */ }
}
@ -2108,9 +2106,7 @@ SessionStoreService.prototype = {
let storage = aDocShell.getSessionStorageForURI(uri);
for (let key in aStorageData[url]) {
try {
storage.setItem(key, aStorageData[url][key].value);
if (uri.schemeIs("https"))
storage.getItem(key).secure = aStorageData[url][key].secure || false;
storage.setItem(key, aStorageData[url][key]);
}
catch (ex) { Cu.reportError(ex); } // throws e.g. for URIs that can't have sessionStorage
}

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

@ -54,6 +54,7 @@
#include "nsIDOMNSDocument.h"
#include "nsIDOMElement.h"
#include "nsIDOMStorageObsolete.h"
#include "nsIDOMStorage.h"
#include "nsPIDOMStorage.h"
#include "nsIDocumentViewer.h"
#include "nsIDocumentLoaderFactory.h"
@ -853,7 +854,6 @@ NS_INTERFACE_MAP_BEGIN(nsDocShell)
NS_INTERFACE_MAP_ENTRY(nsIAuthPromptProvider)
NS_INTERFACE_MAP_ENTRY(nsIObserver)
NS_INTERFACE_MAP_ENTRY(nsILoadContext)
NS_INTERFACE_MAP_ENTRY(nsIDocShell_MOZILLA_1_9_1)
NS_INTERFACE_MAP_ENTRY(nsIWebShellServices)
NS_INTERFACE_MAP_ENTRY(nsILinkHandler)
NS_INTERFACE_MAP_ENTRY(nsIClipboardCommands)
@ -2143,7 +2143,7 @@ nsDocShell::HistoryPurged(PRInt32 aNumEntries)
NS_IMETHODIMP
nsDocShell::GetSessionStorageForPrincipal(nsIPrincipal* aPrincipal,
PRBool aCreate,
nsIDOMStorageObsolete** aStorage)
nsIDOMStorage** aStorage)
{
NS_ENSURE_ARG_POINTER(aStorage);
*aStorage = nsnull;
@ -2151,19 +2151,46 @@ nsDocShell::GetSessionStorageForPrincipal(nsIPrincipal* aPrincipal,
if (!aPrincipal)
return NS_OK;
nsCOMPtr<nsIURI> codebaseURI;
nsresult rv = aPrincipal->GetDomain(getter_AddRefs(codebaseURI));
NS_ENSURE_SUCCESS(rv, rv);
if (!codebaseURI) {
rv = aPrincipal->GetURI(getter_AddRefs(codebaseURI));
NS_ENSURE_SUCCESS(rv, rv);
}
nsresult rv;
if (!codebaseURI)
nsCOMPtr<nsIDocShellTreeItem> topItem;
rv = GetSameTypeRootTreeItem(getter_AddRefs(topItem));
if (NS_FAILED(rv))
return rv;
if (!topItem)
return NS_ERROR_FAILURE;
nsDocShell* topDocShell = static_cast<nsDocShell*>(topItem.get());
if (topDocShell != this)
return topDocShell->GetSessionStorageForPrincipal(aPrincipal, aCreate,
aStorage);
nsXPIDLCString origin;
rv = aPrincipal->GetOrigin(getter_Copies(origin));
if (NS_FAILED(rv))
return rv;
if (origin.IsEmpty())
return NS_ERROR_FAILURE;
if (!mStorages.Get(origin, aStorage) && aCreate) {
nsCOMPtr<nsIDOMStorage> newstorage =
do_CreateInstance("@mozilla.org/dom/storage;2");
if (!newstorage)
return NS_ERROR_OUT_OF_MEMORY;
nsCOMPtr<nsPIDOMStorage> pistorage = do_QueryInterface(newstorage);
if (!pistorage)
return NS_ERROR_FAILURE;
pistorage->InitAsSessionStorage(aPrincipal);
if (!mStorages.Put(origin, newstorage))
return NS_ERROR_OUT_OF_MEMORY;
newstorage.swap(*aStorage);
return NS_OK;
rv = GetSessionStorageForURI(codebaseURI, aCreate, aStorage);
NS_ENSURE_SUCCESS(rv, rv);
}
nsCOMPtr<nsPIDOMStorage> piStorage = do_QueryInterface(*aStorage);
if (piStorage) {
@ -2182,7 +2209,7 @@ nsDocShell::GetSessionStorageForPrincipal(nsIPrincipal* aPrincipal,
NS_IMETHODIMP
nsDocShell::GetSessionStorageForURI(nsIURI* aURI,
nsIDOMStorageObsolete** aStorage)
nsIDOMStorage** aStorage)
{
return GetSessionStorageForURI(aURI, PR_TRUE, aStorage);
}
@ -2190,64 +2217,35 @@ nsDocShell::GetSessionStorageForURI(nsIURI* aURI,
nsresult
nsDocShell::GetSessionStorageForURI(nsIURI* aURI,
PRBool aCreate,
nsIDOMStorageObsolete** aStorage)
nsIDOMStorage** aStorage)
{
NS_ENSURE_ARG(aURI);
NS_ENSURE_ARG_POINTER(aStorage);
*aStorage = nsnull;
nsCOMPtr<nsIURI> innerURI = NS_GetInnermostURI(aURI);
NS_ASSERTION(innerURI, "Failed to get innermost URI");
if (!innerURI)
return NS_ERROR_FAILURE;
nsresult rv;
nsCOMPtr<nsIDocShellTreeItem> topItem;
nsresult rv = GetSameTypeRootTreeItem(getter_AddRefs(topItem));
nsCOMPtr<nsIScriptSecurityManager> securityManager =
do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
// This is terrible hack and should go away along with this whole method.
nsCOMPtr<nsIPrincipal> principal;
rv = securityManager->GetCodebasePrincipal(aURI, getter_AddRefs(principal));
if (NS_FAILED(rv))
return rv;
if (!topItem)
return NS_ERROR_FAILURE;
nsDocShell* topDocShell = static_cast<nsDocShell*>(topItem.get());
if (topDocShell != this)
return topDocShell->GetSessionStorageForURI(aURI, aCreate, aStorage);
nsCAutoString currentDomain;
rv = innerURI->GetAsciiHost(currentDomain);
NS_ENSURE_SUCCESS(rv, rv);
if (currentDomain.IsEmpty())
return NS_OK;
if (!mStorages.Get(currentDomain, aStorage) && aCreate) {
nsCOMPtr<nsIDOMStorageObsolete> newstorage =
do_CreateInstance("@mozilla.org/dom/storage;1");
if (!newstorage)
return NS_ERROR_OUT_OF_MEMORY;
nsCOMPtr<nsPIDOMStorage> pistorage = do_QueryInterface(newstorage);
if (!pistorage)
return NS_ERROR_FAILURE;
pistorage->InitAsSessionStorage(aURI);
if (!mStorages.Put(currentDomain, newstorage))
return NS_ERROR_OUT_OF_MEMORY;
newstorage.swap(*aStorage);
}
return NS_OK;
return GetSessionStorageForPrincipal(principal, aCreate, aStorage);
}
nsresult
nsDocShell::AddSessionStorage(const nsACString& aDomain,
nsIDOMStorageObsolete* aStorage)
nsDocShell::AddSessionStorage(nsIPrincipal* aPrincipal,
nsIDOMStorage* aStorage)
{
NS_ENSURE_ARG_POINTER(aStorage);
if (aDomain.IsEmpty())
if (!aPrincipal)
return NS_OK;
nsCOMPtr<nsIDocShellTreeItem> topItem;
@ -2258,15 +2256,23 @@ nsDocShell::AddSessionStorage(const nsACString& aDomain,
if (topItem) {
nsCOMPtr<nsIDocShell> topDocShell = do_QueryInterface(topItem);
if (topDocShell == this) {
nsXPIDLCString origin;
rv = aPrincipal->GetOrigin(getter_Copies(origin));
if (NS_FAILED(rv))
return rv;
if (origin.IsEmpty())
return NS_ERROR_FAILURE;
// Do not replace an existing session storage.
if (mStorages.GetWeak(aDomain))
if (mStorages.GetWeak(origin))
return NS_ERROR_NOT_AVAILABLE;
if (!mStorages.Put(aDomain, aStorage))
if (!mStorages.Put(origin, aStorage))
return NS_ERROR_OUT_OF_MEMORY;
}
else {
return topDocShell->AddSessionStorage(aDomain, aStorage);
return topDocShell->AddSessionStorage(aPrincipal, aStorage);
}
}

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

@ -213,7 +213,6 @@ class nsDocShell : public nsDocLoader,
public nsIAuthPromptProvider,
public nsIObserver,
public nsILoadContext,
public nsIDocShell_MOZILLA_1_9_1,
public nsIWebShellServices,
public nsILinkHandler,
public nsIClipboardCommands
@ -248,7 +247,6 @@ public:
NS_DECL_NSIAUTHPROMPTPROVIDER
NS_DECL_NSIOBSERVER
NS_DECL_NSILOADCONTEXT
NS_DECL_NSIDOCSHELL_MOZILLA_1_9_1
NS_DECL_NSICLIPBOARDCOMMANDS
NS_DECL_NSIWEBSHELLSERVICES
@ -606,7 +604,7 @@ protected:
nsresult GetSessionStorageForURI(nsIURI* aURI,
PRBool create,
nsIDOMStorageObsolete** aStorage);
nsIDOMStorage** aStorage);
// helpers for executing commands
nsresult GetControllerForCommand(const char *inCommand,
@ -630,10 +628,13 @@ protected:
};
// hash of session storages, keyed by domain
nsInterfaceHashtable<nsCStringHashKey, nsIDOMStorageObsolete> mStorages;
nsIntRect mBounds; // Dimensions of the docshell
nsInterfaceHashtable<nsCStringHashKey, nsIDOMStorage> mStorages;
// Dimensions of the docshell
nsIntRect mBounds;
nsString mName;
nsString mTitle;
/**
* Content-Type Hint of the most-recently initiated load. Used for
* session history entries.

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

@ -66,10 +66,10 @@ interface nsIRequest;
interface nsISHEntry;
interface nsILayoutHistoryState;
interface nsISecureBrowserUI;
interface nsIDOMStorageObsolete;
interface nsIDOMStorage;
interface nsIPrincipal;
[scriptable, uuid(f100ede8-fa36-4ed2-99b2-71a3b94f9a70)]
[scriptable, uuid(3156f677-f444-4c3e-a47f-b47e568eafd6)]
interface nsIDocShell : nsISupports
{
/**
@ -439,15 +439,25 @@ interface nsIDocShell : nsISupports
*
* @param uri the uri of the storage object to retrieve
*/
nsIDOMStorageObsolete getSessionStorageForURI(in nsIURI uri);
nsIDOMStorage getSessionStorageForURI(in nsIURI uri);
/*
* Retrieves the WebApps session storage object for the supplied principal.
*
* @param principal returns a storage for this principal
* @param create If true and a session storage object doesn't
* already exist, a new one will be created.
*/
nsIDOMStorage getSessionStorageForPrincipal(in nsIPrincipal principal,
in boolean create);
/*
* Add a WebApps session storage object to the docshell.
*
* @param domain the domain the storage object is associated with
* @param principal the principal the storage object is associated with
* @param storage the storage object to add
*/
void addSessionStorage(in ACString aDomain, in nsIDOMStorageObsolete storage);
void addSessionStorage(in nsIPrincipal principal, in nsIDOMStorage storage);
/**
* Gets the channel for the currently loaded document, if any.
@ -489,17 +499,3 @@ interface nsIDocShell : nsISupports
**/
attribute boolean isOffScreenBrowser;
};
[scriptable, uuid(460ba822-e664-4c38-9b08-98d2736473d7)]
interface nsIDocShell_MOZILLA_1_9_1 : nsISupports
{
/*
* Retrieves the WebApps session storage object for the supplied principal.
*
* @param principal returns a storage for this principal
* @param create If true and a session storage object doesn't
* already exist, a new one will be created.
*/
nsIDOMStorageObsolete getSessionStorageForPrincipal(in nsIPrincipal principal,
in boolean create);
};

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

@ -6772,15 +6772,14 @@ nsGlobalWindow::GetDocument(nsIDOMDocumentView ** aDocumentView)
//*****************************************************************************
NS_IMETHODIMP
nsGlobalWindow::GetSessionStorage(nsIDOMStorageObsolete ** aSessionStorage)
nsGlobalWindow::GetSessionStorage(nsIDOMStorage ** aSessionStorage)
{
FORWARD_TO_INNER(GetSessionStorage, (aSessionStorage), NS_ERROR_UNEXPECTED);
*aSessionStorage = nsnull;
nsIPrincipal *principal = GetPrincipal();
nsCOMPtr<nsIDocShell_MOZILLA_1_9_1> docShell =
do_QueryInterface(GetDocShell());
nsIDocShell* docShell = GetDocShell();
if (!principal || !docShell) {
return NS_OK;
@ -6986,10 +6985,9 @@ nsGlobalWindow::Observe(nsISupports* aSubject, const char* aTopic,
principal = GetPrincipal();
if (!aData) {
nsCOMPtr<nsIDocShell_MOZILLA_1_9_1> docShell =
do_QueryInterface(GetDocShell());
nsIDocShell* docShell = GetDocShell();
if (principal && docShell) {
nsCOMPtr<nsIDOMStorageObsolete> storage;
nsCOMPtr<nsIDOMStorage> storage;
docShell->GetSessionStorageForPrincipal(principal,
PR_FALSE,
getter_AddRefs(storage));
@ -7083,7 +7081,7 @@ FirePendingStorageEvents(const nsAString& aKey, PRBool aData, void *userArg)
{
nsGlobalWindow *win = static_cast<nsGlobalWindow *>(userArg);
nsCOMPtr<nsIDOMStorageObsolete> storage;
nsCOMPtr<nsIDOMStorage> storage;
win->GetSessionStorage(getter_AddRefs(storage));
if (storage) {

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

@ -49,13 +49,13 @@ interface nsIDOMStorageObsolete;
interface nsIDOMStorage;
interface nsIDOMStorageList;
[scriptable, uuid(390FBF21-36F5-4516-B3F2-9D1232718C69)]
[scriptable, uuid(A44581FE-DD9B-4fd7-9893-00C4AB43F12E)]
interface nsIDOMStorageWindow : nsISupports
{
/**
* Session storage for the current browsing context.
*/
readonly attribute nsIDOMStorageObsolete sessionStorage;
readonly attribute nsIDOMStorage sessionStorage;
/**
* Global storage, accessible by domain.

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

@ -48,23 +48,23 @@ class nsIURI;
class nsIPrincipal;
#define NS_PIDOMSTORAGE_IID \
{ 0x3231d539, 0xdd51, 0x4451, \
{ 0xba, 0xdc, 0xf7, 0x72, 0xf5, 0xda, 0x1c, 0x8a } }
{ 0x5ffbee8d, 0x9a86, 0x4a57, \
{ 0x8c, 0x63, 0x76, 0x56, 0x18, 0x9c, 0xb2, 0xbc } }
class nsPIDOMStorage : public nsISupports
{
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_PIDOMSTORAGE_IID)
virtual nsresult InitAsSessionStorage(nsIPrincipal *aPrincipal) = 0;
virtual nsresult InitAsLocalStorage(nsIPrincipal *aPrincipal) = 0;
virtual nsresult InitAsGlobalStorage(const nsACString &aDomainDemanded) = 0;
virtual nsresult InitAsSessionStorage(nsIURI* aURI) = 0;
virtual already_AddRefed<nsIDOMStorageObsolete> Clone() = 0;
virtual already_AddRefed<nsIDOMStorage> Clone() = 0;
virtual nsTArray<nsString> *GetKeys() = 0;
virtual const nsCString &Domain() = 0;
virtual nsIPrincipal* Principal() = 0;
virtual PRBool CanAccess(nsIPrincipal *aPrincipal) = 0;
};

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

@ -516,10 +516,17 @@ NS_NewDOMStorage(nsISupports* aOuter, REFNSIID aIID, void** aResult)
if (!storage)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(storage);
*aResult = storage;
return storage->QueryInterface(aIID, aResult);
}
return NS_OK;
NS_IMETHODIMP
NS_NewDOMStorage2(nsISupports* aOuter, REFNSIID aIID, void** aResult)
{
nsDOMStorage2* storage = new nsDOMStorage2();
if (!storage)
return NS_ERROR_OUT_OF_MEMORY;
return storage->QueryInterface(aIID, aResult);
}
nsDOMStorage::nsDOMStorage()
@ -533,6 +540,20 @@ nsDOMStorage::nsDOMStorage()
nsDOMStorageManager::gStorageManager->AddToStoragesHash(this);
}
static PLDHashOperator
CopyStorageItems(nsSessionStorageEntry* aEntry, void* userArg)
{
nsDOMStorage* newstorage = static_cast<nsDOMStorage*>(userArg);
newstorage->SetItem(aEntry->GetKey(), aEntry->mItem->GetValueInternal());
if (aEntry->mItem->IsSecure()) {
newstorage->SetSecure(aEntry->GetKey(), PR_TRUE);
}
return PL_DHASH_NEXT;
}
nsDOMStorage::nsDOMStorage(nsDOMStorage& aThat)
: mUseDB(PR_FALSE) // Any clone is not using the database
, mSessionOnly(PR_TRUE)
@ -544,6 +565,8 @@ nsDOMStorage::nsDOMStorage(nsDOMStorage& aThat)
#endif
{
mItems.Init(8);
aThat.mItems.EnumerateEntries(CopyStorageItems, this);
if (nsDOMStorageManager::gStorageManager)
nsDOMStorageManager::gStorageManager->AddToStoragesHash(this);
}
@ -554,6 +577,29 @@ nsDOMStorage::~nsDOMStorage()
nsDOMStorageManager::gStorageManager->RemoveFromStoragesHash(this);
}
nsresult
nsDOMStorage::InitAsSessionStorage(nsIPrincipal *aPrincipal)
{
nsresult rv;
nsCOMPtr<nsIURI> uri;
rv = aPrincipal->GetURI(getter_AddRefs(uri));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIURI> innerUri = NS_GetInnermostURI(uri);
if (!innerUri)
return NS_ERROR_UNEXPECTED;
innerUri->GetAsciiHost(mDomain);
#ifdef MOZ_STORAGE
mUseDB = PR_FALSE;
mScopeDBKey.Truncate();
mQuotaDomainDBKey.Truncate();
#endif
return NS_OK;
}
nsresult
nsDOMStorage::InitAsLocalStorage(nsIPrincipal *aPrincipal)
{
@ -615,20 +661,6 @@ nsDOMStorage::InitAsGlobalStorage(const nsACString &aDomainDemanded)
return NS_OK;
}
nsresult
nsDOMStorage::InitAsSessionStorage(nsIURI* aURI)
{
nsCAutoString domain;
aURI->GetAsciiHost(domain);
mDomain = domain;
#ifdef MOZ_STORAGE
mUseDB = PR_FALSE;
mScopeDBKey.Truncate();
mQuotaDomainDBKey.Truncate();
#endif
return NS_OK;
}
//static
PRBool
nsDOMStorage::CanUseStorage(PRPackedBool* aSessionOnly)
@ -1240,41 +1272,11 @@ nsDOMStorage::ClearAll()
mItemsCached = PR_FALSE;
}
static PLDHashOperator
CopyStorageItems(nsSessionStorageEntry* aEntry, void* userArg)
{
nsDOMStorage* newstorage = static_cast<nsDOMStorage*>(userArg);
newstorage->SetItem(aEntry->GetKey(), aEntry->mItem->GetValueInternal());
if (aEntry->mItem->IsSecure()) {
newstorage->SetSecure(aEntry->GetKey(), PR_TRUE);
}
return PL_DHASH_NEXT;
}
already_AddRefed<nsIDOMStorageObsolete>
already_AddRefed<nsIDOMStorage>
nsDOMStorage::Clone()
{
if (UseDB()) {
NS_ERROR("Uh, don't clone a global or local storage object.");
return nsnull;
}
nsDOMStorage* storage = new nsDOMStorage(*this);
if (!storage)
return nsnull;
mItems.EnumerateEntries(CopyStorageItems, storage);
NS_ADDREF(storage);
if (nsDOMStorageManager::gStorageManager)
nsDOMStorageManager::gStorageManager->AddToStoragesHash(storage);
return storage;
NS_ASSERTION(PR_FALSE, "Old DOMStorage doesn't implement cloning");
return nsnull;
}
struct KeysArrayBuilderStruct
@ -1309,10 +1311,10 @@ nsDOMStorage::GetKeys()
return keystruct.keys;
}
const nsCString &
nsDOMStorage::Domain()
nsIPrincipal*
nsDOMStorage::Principal()
{
return mDomain;
return nsnull;
}
PRBool
@ -1387,6 +1389,27 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMStorage2)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(Storage)
NS_INTERFACE_MAP_END
nsDOMStorage2::nsDOMStorage2()
{
}
nsDOMStorage2::nsDOMStorage2(nsDOMStorage2& aThat)
{
mStorage = new nsDOMStorage(*aThat.mStorage.get());
mPrincipal = aThat.mPrincipal;
}
nsresult
nsDOMStorage2::InitAsSessionStorage(nsIPrincipal *aPrincipal)
{
mStorage = new nsDOMStorage();
if (!mStorage)
return NS_ERROR_OUT_OF_MEMORY;
mPrincipal = aPrincipal;
return mStorage->InitAsSessionStorage(aPrincipal);
}
nsresult
nsDOMStorage2::InitAsLocalStorage(nsIPrincipal *aPrincipal)
{
@ -1405,23 +1428,16 @@ nsDOMStorage2::InitAsGlobalStorage(const nsACString &aDomainDemanded)
return NS_ERROR_NOT_IMPLEMENTED;
}
nsresult
nsDOMStorage2::InitAsSessionStorage(nsIURI* aURI)
{
mStorage = new nsDOMStorage();
if (!mStorage)
return NS_ERROR_OUT_OF_MEMORY;
return mStorage->InitAsSessionStorage(aURI);
}
already_AddRefed<nsIDOMStorageObsolete>
already_AddRefed<nsIDOMStorage>
nsDOMStorage2::Clone()
{
// XXX: this will need to be fixed before sessionStorage is moved
// to nsIDOMStorage.
NS_ASSERTION(PR_FALSE, "Cannot clone nsDOMStorage2");
return nsnull;
nsDOMStorage2* storage = new nsDOMStorage2(*this);
if (!storage)
return nsnull;
NS_ADDREF(storage);
return storage;
}
nsTArray<nsString> *
@ -1430,10 +1446,10 @@ nsDOMStorage2::GetKeys()
return mStorage->GetKeys();
}
const nsCString &
nsDOMStorage2::Domain()
nsIPrincipal*
nsDOMStorage2::Principal()
{
return mStorage->Domain();
return mPrincipal;
}
PRBool

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

@ -140,12 +140,12 @@ public:
nsresult Clear();
// nsPIDOMStorage
virtual nsresult InitAsSessionStorage(nsIPrincipal *aPrincipal);
virtual nsresult InitAsLocalStorage(nsIPrincipal *aPrincipal);
virtual nsresult InitAsGlobalStorage(const nsACString &aDomainDemanded);
virtual nsresult InitAsSessionStorage(nsIURI* aURI);
virtual already_AddRefed<nsIDOMStorageObsolete> Clone();
virtual already_AddRefed<nsIDOMStorage> Clone();
virtual nsTArray<nsString> *GetKeys();
virtual const nsCString &Domain();
virtual nsIPrincipal* Principal();
virtual PRBool CanAccess(nsIPrincipal *aPrincipal);
// If true, the contents of the storage should be stored in the
@ -267,15 +267,18 @@ public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsDOMStorage2, nsIDOMStorage)
nsDOMStorage2(nsDOMStorage2& aThat);
nsDOMStorage2();
NS_DECL_NSIDOMSTORAGE
// nsPIDOMStorage
virtual nsresult InitAsSessionStorage(nsIPrincipal *aPrincipal);
virtual nsresult InitAsLocalStorage(nsIPrincipal *aPrincipal);
virtual nsresult InitAsGlobalStorage(const nsACString &aDomainDemanded);
virtual nsresult InitAsSessionStorage(nsIURI* aURI);
virtual already_AddRefed<nsIDOMStorageObsolete> Clone();
virtual already_AddRefed<nsIDOMStorage> Clone();
virtual nsTArray<nsString> *GetKeys();
virtual const nsCString &Domain();
virtual nsIPrincipal* Principal();
virtual PRBool CanAccess(nsIPrincipal *aPrincipal);
private:
@ -432,6 +435,9 @@ protected:
NS_IMETHODIMP
NS_NewDOMStorage(nsISupports* aOuter, REFNSIID aIID, void** aResult);
NS_IMETHODIMP
NS_NewDOMStorage2(nsISupports* aOuter, REFNSIID aIID, void** aResult);
nsresult
NS_NewDOMStorageList(nsIDOMStorageList** aResult);

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

@ -54,6 +54,7 @@ DIRS += \
whatwg \
geolocation \
localstorage \
sessionstorage \
$(NULL)
include $(topsrcdir)/config/rules.mk

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

@ -0,0 +1,60 @@
#
# ***** 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 Foundation.
# Portions created by the Initial Developer are Copyright (C) 2007
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
#
# 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 *****
DEPTH = ../../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
relativesrcdir = dom/tests/mochitest/sessionstorage
include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/rules.mk
_TEST_FILES = \
frameReplace.html \
frameEqual.html \
frameNotEqual.html \
test_sessionStorageBase.html \
test_sessionStorageClone.html \
test_sessionStorageReplace.html \
interOriginSlave.js \
interOriginTest.js \
$(NULL)
libs:: $(_TEST_FILES)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)

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

@ -0,0 +1,47 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>slave for sessionStorage test</title>
<script type="text/javascript" src="interOriginSlave.js"></script>
<script type="text/javascript">
var currentStep = 2;
function doStep()
{
switch (currentStep)
{
case 2:
is(sessionStorage.getItem("A"), "1", "A is 1 in the slave");
is(sessionStorage.getItem("B"), "2", "B is 2 in the slave");
is(sessionStorage.length, 2, "Num of items is 2");
sessionStorage.setItem("C", "3");
is(sessionStorage.getItem("C"), "3", "C is 3 in the slave");
is(sessionStorage.length, 3, "Num of items is 3");
break;
case 4:
is(sessionStorage.getItem("A"), "1", "A is 1 in the slave");
is(sessionStorage.getItem("B"), "2", "B is 2 in the slave");
is(sessionStorage.getItem("C"), "3", "C is 3 in the slave");
is(sessionStorage.length, 3, "Num of items is 3");
break;
case 6:
return finishTest();
}
++currentStep;
++currentStep;
return true;
}
</script>
</head>
<body onload="postMsg('frame loaded');">
</body>
</html>

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

@ -0,0 +1,43 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>slave for sessionStorage test</title>
<script type="text/javascript" src="interOriginSlave.js"></script>
<script type="text/javascript">
var currentStep = 2;
function doStep()
{
switch (currentStep)
{
case 2:
is(sessionStorage.length, 0, "Num of items is 0");
sessionStorage.setItem("C", "3");
is(sessionStorage.getItem("C"), "3", "C is 3 in the slave");
is(sessionStorage.length, 1, "Num of items is 1");
break;
case 4:
is(sessionStorage.getItem("C"), "3", "C is 3 in the slave");
is(sessionStorage.length, 1, "Num of items is 1");
break;
case 6:
return finishTest();
}
++currentStep;
++currentStep;
return true;
}
</script>
</head>
<body onload="postMsg('frame loaded');">
</body>
</html>

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

@ -0,0 +1,75 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>sessionStorage replace frame</title>
<script type="text/javascript">
var shell;
function ok(a, message)
{
if (!a)
shell.postMessage("FAILURE: " + message, "http://localhost:8888");
else
shell.postMessage(message, "http://localhost:8888");
}
function is(a, b, message)
{
if (a != b)
shell.postMessage("FAILURE: " + message + ", expected "+b+" got "+a, "http://localhost:8888");
else
shell.postMessage(message + ", expected "+b+" got "+a, "http://localhost:8888");
}
function doTest()
{
var query = location.search.substring(1);
var queries = query.split("&");
var action = queries[0];
shell = queries[1];
switch (shell)
{
case "frame":
shell = parent;
break;
case "window":
shell = opener;
break;
}
switch (action)
{
case "init":
sessionStorage.setItem("A", "1");
sessionStorage.setItem("B", "2");
sessionStorage.setItem("C", "3");
is(sessionStorage.getItem("A"), "1", "'A' is '1'");
is(sessionStorage.getItem("B"), "2", "'A' is '2'");
is(sessionStorage.getItem("C"), "3", "'A' is '3'");
break;
case "check":
is(sessionStorage.getItem("A"), null, "'A' is null");
is(sessionStorage.getItem("B"), null, "'A' is null");
is(sessionStorage.getItem("C"), null, "'A' is null");
break;
case "clean":
is(sessionStorage.getItem("A"), "1", "'A' is '1'");
is(sessionStorage.getItem("B"), "2", "'A' is '2'");
is(sessionStorage.getItem("C"), "3", "'A' is '3'");
sessionStorage.clear();
break;
}
shell.postMessage(action + "_done", "http://localhost:8888");
}
</script>
</head>
<body onload="doTest();">
</body>
</html>

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

@ -0,0 +1,42 @@
function postMsg(message)
{
opener.postMessage(message, "http://localhost:8888");
}
window.addEventListener("message", onMessageReceived, false);
function onMessageReceived(event)
{
//alert("slave got event: "+event.data);
if (event.data == "step") {
if (doStep())
postMsg("perf");
return;
}
postMsg("Invalid message");
}
function ok(a, message)
{
if (!a)
postMsg("FAILURE: " + message);
else
postMsg(message);
}
function is(a, b, message)
{
if (a != b)
postMsg("FAILURE: " + message + ", expected "+b+" got "+a);
else
postMsg(message + ", expected "+b+" got "+a);
}
function finishTest()
{
sessionStorage.clear();
postMsg("done");
return false;
}

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

@ -0,0 +1,44 @@
var slaveLoadsPending = 1;
var slaveOrigin = "";
var slave = null;
var failureRegExp = new RegExp("^FAILURE");
const slavePath = "/tests/dom/tests/mochitest/sessionstorage/";
window.addEventListener("message", onMessageReceived, false);
function onMessageReceived(event)
{
//alert("master got event: "+event.data);
switch (event.data)
{
// Indication of the frame onload event
case "frame loaded":
if (--slaveLoadsPending)
break;
// Just fall through...
// Indication of successfully finished step of a test
case "perf":
// We called doStep before the frame was load
if (event.data == "perf")
doStep();
slave.postMessage("step", slaveOrigin);
break;
// Indication of all test parts finish (from any of the frames)
case "done":
sessionStorage.clear();
slaveLoadsPending = 1;
doNextTest();
break;
// Any other message indicates error or succes message of a test
default:
SimpleTest.ok(!event.data.match(failureRegExp), event.data);
break;
}
}

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

@ -0,0 +1,156 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>sessionStorage basic 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">
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()
{
// Initially check the sessionStorage is empty
is(sessionStorage.length, 0, "The storage is empty [1]");
checkException(function() {sessionStorage.key(0);}, INDEX_SIZE_ERR);
checkException(function() {sessionStorage.key(-1);}, INDEX_SIZE_ERR);
checkException(function() {sessionStorage.key(1);}, INDEX_SIZE_ERR);
is(sessionStorage.getItem("nonexisting"), null, "Nonexisting item is null (getItem())");
is(sessionStorage["nonexisting"], null, "Nonexisting item is null (array access)");
is(sessionStorage.nonexisting, null, "Nonexisting item is null (property access)");
sessionStorage.removeItem("nonexisting"); // Just check there is no exception
is(typeof sessionStorage.getItem("nonexisting"), "object", "getItem('nonexisting') is object");
is(typeof sessionStorage["nonexisting"], "object", "['nonexisting'] is object");
is(typeof sessionStorage.nonexisting, "object", "nonexisting is object");
is(typeof sessionStorage.getItem("nonexisting2"), "object", "getItem('nonexisting2') is object");
is(typeof sessionStorage["nonexisting2"], "object", "['nonexisting2'] is object");
is(typeof sessionStorage.nonexisting2, "object", "nonexisting2 is object");
// add an empty-value key
sessionStorage.setItem("empty", "");
is(sessionStorage.getItem("empty"), "", "Empty value (getItem())");
is(sessionStorage["empty"], "", "Empty value (array access)");
is(sessionStorage.empty, "", "Empty value (property access)");
is(typeof sessionStorage.getItem("empty"), "string", "getItem('empty') is string");
is(typeof sessionStorage["empty"], "string", "['empty'] is string");
is(typeof sessionStorage.empty, "string", "empty is string");
sessionStorage.removeItem("empty");
is(sessionStorage.length, 0, "The storage has no keys");
is(sessionStorage.getItem("empty"), null, "empty item is null (getItem())");
is(sessionStorage["empty"], null, "empty item is null (array access)");
is(sessionStorage.empty, null, "empty item is null (property access)");
is(typeof sessionStorage.getItem("empty"), "object", "getItem('empty') is object");
is(typeof sessionStorage["empty"], "object", "['empty'] is object");
is(typeof sessionStorage.empty, "object", "empty is object");
// add one key, check it is there
sessionStorage.setItem("key1", "value1");
is(sessionStorage.length, 1, "The storage has one key-value pair");
is(sessionStorage.key(0), "key1");
checkException(function() {sessionStorage.key(-1);}, INDEX_SIZE_ERR);
checkException(function() {sessionStorage.key(1);}, INDEX_SIZE_ERR);
// check all access method give the correct result
// and are of the correct type
is(sessionStorage.getItem("key1"), "value1", "getItem('key1') == value1");
is(sessionStorage["key1"], "value1", "['key1'] == value1");
is(sessionStorage.key1, "value1", "key1 == value1");
is(typeof sessionStorage.getItem("key1"), "string", "getItem('key1') is string");
is(typeof sessionStorage["key1"], "string", "['key1'] is string");
is(typeof sessionStorage.key1, "string", "key1 is string");
// remove the previously added key and check the storage is empty
sessionStorage.removeItem("key1");
is(sessionStorage.length, 0, "The storage is empty [2]");
checkException(function() {sessionStorage.key(0);}, INDEX_SIZE_ERR);
is(sessionStorage.getItem("key1"), null, "\'key1\' removed");
is(typeof sessionStorage.getItem("key1"), "object", "getItem('key1') is object");
is(typeof sessionStorage["key1"], "object", "['key1'] is object");
is(typeof sessionStorage.key1, "object", "key1 is object");
// add one key, check it is there
sessionStorage.setItem("key1", "value1");
is(sessionStorage.length, 1, "The storage has one key-value pair");
is(sessionStorage.key(0), "key1");
is(sessionStorage.getItem("key1"), "value1");
// add a second key
sessionStorage.setItem("key2", "value2");
is(sessionStorage.length, 2, "The storage has two key-value pairs");
is(sessionStorage.key(1), "key1"); // This test might not be accurate because order is not preserved
is(sessionStorage.key(0), "key2");
is(sessionStorage.getItem("key1"), "value1");
is(sessionStorage.getItem("key2"), "value2");
// change the second key
sessionStorage.setItem("key2", "value2-2");
is(sessionStorage.length, 2, "The storage has two key-value pairs");
is(sessionStorage.key(1), "key1"); // After key value changes the order must be preserved
is(sessionStorage.key(0), "key2");
checkException(function() {sessionStorage.key(-1);}, INDEX_SIZE_ERR);
checkException(function() {sessionStorage.key(2);}, INDEX_SIZE_ERR);
is(sessionStorage.getItem("key1"), "value1");
is(sessionStorage.getItem("key2"), "value2-2");
// change the first key
sessionStorage.setItem("key1", "value1-2");
is(sessionStorage.length, 2, "The storage has two key-value pairs");
is(sessionStorage.key(1), "key1"); // After key value changes the order must be preserved
is(sessionStorage.key(0), "key2");
checkException(function() {sessionStorage.key(-1);}, INDEX_SIZE_ERR);
checkException(function() {sessionStorage.key(2);}, INDEX_SIZE_ERR);
is(sessionStorage.getItem("key1"), "value1-2");
is(sessionStorage.getItem("key2"), "value2-2");
// remove the second key
sessionStorage.removeItem("key2");
is(sessionStorage.length, 1, "The storage has one key-value pair");
is(sessionStorage.key(0), "key1");
checkException(function() {sessionStorage.key(-1);}, INDEX_SIZE_ERR);
checkException(function() {sessionStorage.key(1);}, INDEX_SIZE_ERR);
is(sessionStorage.getItem("key1"), "value1-2");
// Clear the storage
sessionStorage.clear();
is(sessionStorage.length, 0, "The storage is empty [3]");
checkException(function() {sessionStorage.key(0);}, INDEX_SIZE_ERR); // this is unspecified!
checkException(function() {sessionStorage.key(-1);}, INDEX_SIZE_ERR);
checkException(function() {sessionStorage.key(1);}, INDEX_SIZE_ERR);
is(sessionStorage.getItem("nonexisting"), null, "Nonexisting item is null");
is(sessionStorage.getItem("key1"), null, "key1 removed");
is(sessionStorage.getItem("key2"), null, "key2 removed");
sessionStorage.removeItem("nonexisting"); // Just check there is no exception
sessionStorage.removeItem("key1"); // Just check there is no exception
sessionStorage.removeItem("key2"); // Just check there is no exception
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
</script>
</head>
<body onload="startTest();">
</body>
</html>

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

@ -0,0 +1,95 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>sessionStorage clone equal origins</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">
var currentTest = 1;
var currentStep = 1;
/*
window.addEventListener("storage", onStorageEvent, false);
function onStorageEvent(event)
{
}
*/
function doNextTest()
{
// We must perform the first step of the test
// to prepare the land.
currentStep = 1;
doStep();
switch (currentTest)
{
case 1:
// Open a window from the same origin and check data
// are copied but not further modified on our side
slaveOrigin = "http://localhost:8888";
slave = window.open(slaveOrigin + slavePath + "frameEqual.html");
break;
case 2:
slave.close();
// Open a window from a different origin and check data
// are NOT copied and not modified on our side
slaveOrigin = "http://example.com";
slave = window.open(slaveOrigin + slavePath + "frameNotEqual.html");
break;
case 3:
slave.close();
sessionStorage.clear();
SimpleTest.finish();
break;
}
++currentTest;
}
function doStep()
{
switch (currentStep)
{
case 1:
sessionStorage.setItem("A", "1");
sessionStorage.setItem("B", "2");
is(sessionStorage.getItem("A"), "1", "A is 1 in the master");
is(sessionStorage.getItem("B"), "2", "B is 2 in the master");
is(sessionStorage.length, 2, "Num of items is 2");
break;
case 3:
is(sessionStorage.getItem("A"), "1", "A is 1 in the master");
is(sessionStorage.getItem("B"), "2", "B is 2 in the master");
is(sessionStorage.getItem("C"), null, "C is null in the master");
is(sessionStorage.length, 2, "Num of items is 2");
sessionStorage.setItem("C", "4");
is(sessionStorage.getItem("C"), "4", "C is 4 in the master");
is(sessionStorage.length, 3, "Num of items is 3");
break;
}
++currentStep;
++currentStep;
return true;
}
SimpleTest.waitForExplicitFinish();
</script>
</head>
<body onload="doNextTest();">
</body>
</html>

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

@ -0,0 +1,79 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>sessionStorage replace test</title>
<!--
This test checks that sessionStorage object doesn't leak
in a window that changes its location. We do this by switching
frame location inside of this window and then by changing location
of a top level window.
-->
<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 shell;
var shellType;
var failureRegExp = new RegExp("^FAILURE");
window.addEventListener("message", onMessageReceived, false);
function onMessageReceived(event)
{
//alert("onMessageReceived "+event.data);
switch (event.data)
{
case "init_done":
// This is frame with different origin in the same browsing context
// as the first frame adding data to sessionStorage of the first origin.
shell.location = "http://example.com/tests/dom/tests/mochitest/sessionStorage/frameReplace.html?check&" + shellType;
break;
case "check_done":
// Recheck and clean the sessionStorage of the first origin.
shell.location = "http://example.org:80/tests/dom/tests/mochitest/sessionStorage/frameReplace.html?clean&" + shellType;
break;
case "clean_done":
switch (shellType)
{
case "frame":
// We finished testing in a frame
// proceed with test in a separate window
shellType = "window";
shell = window.open("http://example.org/tests/dom/tests/mochitest/sessionStorage/frameReplace.html?init&" + shellType);
break;
case "window":
shell.close();
window.setTimeout(function() {SimpleTest.finish();}, 0);
break;
}
break;
default:
SimpleTest.ok(!event.data.match(failureRegExp), event.data);
break;
}
}
function startTest()
{
shellType = "frame";
shell = frame;
shell.location = "http://example.org/tests/dom/tests/mochitest/sessionStorage/frameReplace.html?init&" + shellType;
}
SimpleTest.waitForExplicitFinish();
</script>
</head>
<body onload="startTest();">
<iframe src="" name="frame"></iframe>
</body>
</html>

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

@ -86,6 +86,7 @@
#include "nsISupportsArray.h"
#include "nsIDeviceContext.h"
#include "nsIDOMStorageObsolete.h"
#include "nsIDOMStorage.h"
#include "nsPIDOMStorage.h"
#include "nsIWidget.h"
@ -931,12 +932,12 @@ nsWindowWatcher::OpenWindowJSInternal(nsIDOMWindow *aParent,
// Copy the current session storage for the current domain.
nsCOMPtr<nsPIDOMWindow> piWindow = do_QueryInterface(aParent);
nsCOMPtr<nsIDocShell_MOZILLA_1_9_1> parentDocShell;
nsIDocShell* parentDocShell = nsnull;
if (piWindow)
parentDocShell = do_QueryInterface(piWindow->GetDocShell());
parentDocShell = piWindow->GetDocShell();
if (subjectPrincipal && parentDocShell) {
nsCOMPtr<nsIDOMStorageObsolete> storage;
nsCOMPtr<nsIDOMStorage> storage;
parentDocShell->GetSessionStorageForPrincipal(subjectPrincipal, PR_FALSE,
getter_AddRefs(storage));
nsCOMPtr<nsPIDOMStorage> piStorage =
@ -944,7 +945,7 @@ nsWindowWatcher::OpenWindowJSInternal(nsIDOMWindow *aParent,
if (piStorage){
storage = piStorage->Clone();
newDocShell->AddSessionStorage(
piStorage->Domain(),
piStorage->Principal(),
storage);
}
}

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

@ -218,6 +218,10 @@
#define NS_DOMSTORAGE_CID \
{ 0x8b449142, 0x1eab, 0x4bfa, { 0x98, 0x30, 0xfa, 0xb6, 0xeb, 0xb0, 0x97, 0x74 } }
// {27AECC62-7777-428e-B34C-5973A47B8298}
#define NS_DOMSTORAGE2_CID \
{ 0x27aecc62, 0x7777, 0x428e, { 0xb3, 0x4c, 0x59, 0x73, 0xa4, 0x7b, 0x82, 0x98 } }
// {b88a4712-eb52-4c10-9b85-bf5894b510f0}
#define NS_DOMSTORAGEMANAGER_CID \
{ 0xb88a4712, 0xeb52, 0x4c10, { 0x9b, 0x85, 0xbf, 0x58, 0x94, 0xb5, 0x10, 0xf0 } }

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

@ -1402,6 +1402,11 @@ static const nsModuleComponentInfo gComponents[] = {
"@mozilla.org/dom/storage;1",
NS_NewDOMStorage },
{ "DOM Storage 2",
NS_DOMSTORAGE2_CID,
"@mozilla.org/dom/storage;2",
NS_NewDOMStorage2 },
{ "DOM Storage Manager",
NS_DOMSTORAGEMANAGER_CID,
"@mozilla.org/dom/storagemanager;1",