--- a/browser/components/sessionstore/src/nsSessionStore.js
+++ b/browser/components/sessionstore/src/nsSessionStore.js
@@ -1266,17 +1266,17 @@ SessionStoreService.prototype = {
*/
_serializeSessionStorage:
function sss_serializeSessionStorage(aTabData, aHistory, aDocShell, aFullData) {
let storageData = {};
let hasContent = false;
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)
domain = uri.prePath;
}
catch (ex) { /* this throws for host-less URIs (such as about: or jar:) */ }
if (storageData[domain] || !(aFullData || this._checkPrivacyLevel(uri.schemeIs("https"))))
continue;
@@ -1290,19 +1290,17 @@ SessionStoreService.prototype = {
if (storageItemCount == 0)
continue;
let data = storageData[domain] = {};
for (let j = 0; j < storageItemCount; j++) {
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) */ }
}
hasContent = true;
}
if (hasContent)
aTabData.storage = storageData;
@@ -2103,19 +2101,17 @@ SessionStoreService.prototype = {
*/
_deserializeSessionStorage: function sss_deserializeSessionStorage(aStorageData, aDocShell) {
let ioService = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
for (let url in aStorageData) {
let uri = ioService.newURI(url, null, null);
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
}
}
},
/**
* Restore properties to a loaded document
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -49,16 +49,17 @@
#include "nsIBrowserDOMWindow.h"
#include "nsIComponentManager.h"
#include "nsIContent.h"
#include "nsIDocument.h"
#include "nsIDOMDocument.h"
#include "nsIDOMNSDocument.h"
#include "nsIDOMElement.h"
#include "nsIDOMStorageObsolete.h"
+#include "nsIDOMStorage.h"
#include "nsPIDOMStorage.h"
#include "nsIDocumentViewer.h"
#include "nsIDocumentLoaderFactory.h"
#include "nsCURILoader.h"
#include "nsURILoader.h"
#include "nsDocShellCID.h"
#include "nsLayoutCID.h"
#include "nsDOMCID.h"
@@ -848,17 +849,16 @@ NS_INTERFACE_MAP_BEGIN(nsDocShell)
NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener)
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
NS_INTERFACE_MAP_ENTRY(nsIContentViewerContainer)
NS_INTERFACE_MAP_ENTRY(nsIEditorDocShell)
NS_INTERFACE_MAP_ENTRY(nsIWebPageDescriptor)
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)
NS_INTERFACE_MAP_END_INHERITING(nsDocLoader)
///*****************************************************************************
// nsDocShell::nsIInterfaceRequestor
//*****************************************************************************
@@ -2138,37 +2138,64 @@ nsDocShell::HistoryPurged(PRInt32 aNumEn
}
return NS_OK;
}
NS_IMETHODIMP
nsDocShell::GetSessionStorageForPrincipal(nsIPrincipal* aPrincipal,
PRBool aCreate,
- nsIDOMStorageObsolete** aStorage)
+ nsIDOMStorage** aStorage)
{
NS_ENSURE_ARG_POINTER(aStorage);
*aStorage = nsnull;
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);
- }
-
- if (!codebaseURI)
+ nsresult rv;
+
+ 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) {
PRBool canAccess = piStorage->CanAccess(aPrincipal);
NS_ASSERTION(canAccess,
"GetSessionStorageForPrincipal got a storage "
"that could not be accessed!");
if (!canAccess) {
@@ -2177,101 +2204,80 @@ nsDocShell::GetSessionStorageForPrincipa
}
}
return NS_OK;
}
NS_IMETHODIMP
nsDocShell::GetSessionStorageForURI(nsIURI* aURI,
- nsIDOMStorageObsolete** aStorage)
+ nsIDOMStorage** aStorage)
{
return GetSessionStorageForURI(aURI, PR_TRUE, aStorage);
}
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;
-
- nsCOMPtr<nsIDocShellTreeItem> topItem;
- nsresult rv = GetSameTypeRootTreeItem(getter_AddRefs(topItem));
+ nsresult rv;
+
+ 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;
nsresult rv = GetSameTypeRootTreeItem(getter_AddRefs(topItem));
if (NS_FAILED(rv))
return rv;
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);
}
}
return NS_OK;
}
NS_IMETHODIMP
nsDocShell::GetCurrentDocumentChannel(nsIChannel** aResult)
--- a/docshell/base/nsDocShell.h
+++ b/docshell/base/nsDocShell.h
@@ -208,17 +208,16 @@ class nsDocShell : public nsDocLoader,
public nsIScriptGlobalObjectOwner,
public nsIRefreshURI,
public nsIWebProgressListener,
public nsIEditorDocShell,
public nsIWebPageDescriptor,
public nsIAuthPromptProvider,
public nsIObserver,
public nsILoadContext,
- public nsIDocShell_MOZILLA_1_9_1,
public nsIWebShellServices,
public nsILinkHandler,
public nsIClipboardCommands
{
friend class nsDSURIContentListener;
public:
// Object Management
@@ -243,17 +242,16 @@ public:
NS_DECL_NSIWEBPROGRESSLISTENER
NS_DECL_NSIREFRESHURI
NS_DECL_NSICONTENTVIEWERCONTAINER
NS_DECL_NSIEDITORDOCSHELL
NS_DECL_NSIWEBPAGEDESCRIPTOR
NS_DECL_NSIAUTHPROMPTPROVIDER
NS_DECL_NSIOBSERVER
NS_DECL_NSILOADCONTEXT
- NS_DECL_NSIDOCSHELL_MOZILLA_1_9_1
NS_DECL_NSICLIPBOARDCOMMANDS
NS_DECL_NSIWEBSHELLSERVICES
NS_IMETHOD Stop() {
// Need this here because otherwise nsIWebNavigation::Stop
// overrides the docloader's Stop()
return nsDocLoader::Stop();
}
@@ -601,17 +599,17 @@ protected:
// InternalLoad). This makes sure that we're not inside unload, or that if
// we are it's still OK to load this URI.
PRBool IsOKToLoadURI(nsIURI* aURI);
void ReattachEditorToWindow(nsISHEntry *aSHEntry);
nsresult GetSessionStorageForURI(nsIURI* aURI,
PRBool create,
- nsIDOMStorageObsolete** aStorage);
+ nsIDOMStorage** aStorage);
// helpers for executing commands
nsresult GetControllerForCommand(const char *inCommand,
nsIController** outController);
nsresult IsCommandEnabled(const char * inCommand, PRBool* outEnabled);
nsresult DoCommand(const char * inCommand);
nsresult EnsureCommandHandler();
@@ -625,20 +623,23 @@ protected:
NS_DECL_NSIRUNNABLE
RestorePresentationEvent(nsDocShell *ds) : mDocShell(ds) {}
void Revoke() { mDocShell = nsnull; }
private:
nsDocShell *mDocShell;
};
// 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.
*/
nsCString mContentTypeHint;
nsIntPoint mDefaultScrollbarPref; // persistent across doc loads
nsCOMPtr<nsISupportsArray> mRefreshURIList;
--- a/docshell/base/nsIDocShell.idl
+++ b/docshell/base/nsIDocShell.idl
@@ -61,20 +61,20 @@ interface nsIDocShellLoadInfo;
interface nsIDocumentCharsetInfo;
interface nsIWebNavigation;
interface nsISimpleEnumerator;
interface nsIInputStream;
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
{
/**
* Loads a given URI. This will give priority to loading the requested URI
* in the object implementing this interface. If it can't be loaded here
* however, the URL dispatcher will go through its normal process of content
* loading.
*
@@ -434,25 +434,35 @@ interface nsIDocShell : nsISupports
void historyPurged(in long numEntries);
/*
* Retrieves the WebApps session storage object for the supplied domain.
* If it doesn't already exist, a new one will be created.
*
* @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.
* For a new document load, this will be the channel of the previous document
* until after OnLocationChange fires.
*/
readonly attribute nsIChannel currentDocumentChannel;
@@ -484,22 +494,8 @@ interface nsIDocShell : nsISupports
/**
* If true, this browser is not visible in the traditional sense, but
* is actively being rendered to the screen (ex. painted on a canvas)
* and should be treated accordingly.
**/
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);
-};
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -6767,25 +6767,24 @@ nsGlobalWindow::GetDocument(nsIDOMDocume
return rv;
}
//*****************************************************************************
// nsGlobalWindow::nsIDOMStorageWindow
//*****************************************************************************
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;
}
nsresult rv = docShell->GetSessionStorageForPrincipal(principal,
PR_TRUE,
aSessionStorage);
@@ -6981,20 +6980,19 @@ nsGlobalWindow::Observe(nsISupports* aSu
}
if (IsInnerWindow() && !nsCRT::strcmp(aTopic, "dom-storage-changed")) {
nsIPrincipal *principal;
nsresult rv;
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));
if (!SameCOMIdentity(storage, aSubject)) {
// A sessionStorage object changed, but not our session storage
// object.
return NS_OK;
@@ -7078,17 +7076,17 @@ nsGlobalWindow::Observe(nsISupports* aSu
return NS_ERROR_FAILURE;
}
static PLDHashOperator
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) {
win->Observe(storage, "dom-storage-changed",
aKey.IsEmpty() ? nsnull : PromiseFlatString(aKey).get());
}
return PL_DHASH_NEXT;
--- a/dom/interfaces/storage/nsIDOMStorageWindow.idl
+++ b/dom/interfaces/storage/nsIDOMStorageWindow.idl
@@ -44,23 +44,23 @@
*
* Allows access to contextual storage areas.
*/
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.
*/
readonly attribute nsIDOMStorageList globalStorage;
/**
* Local storage for the current browsing context.
--- a/dom/interfaces/storage/nsPIDOMStorage.h
+++ b/dom/interfaces/storage/nsPIDOMStorage.h
@@ -43,31 +43,31 @@
#include "nsISupports.h"
#include "nsTArray.h"
class nsIDOMStorageObsolete;
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;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsPIDOMStorage, NS_PIDOMSTORAGE_IID)
#endif // __nsPIDOMStorage_h_
--- a/dom/src/storage/nsDOMStorage.cpp
+++ b/dom/src/storage/nsDOMStorage.cpp
@@ -511,55 +511,101 @@ NS_INTERFACE_MAP_END
NS_IMETHODIMP
NS_NewDOMStorage(nsISupports* aOuter, REFNSIID aIID, void** aResult)
{
nsDOMStorage* storage = new nsDOMStorage();
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()
: mUseDB(PR_FALSE)
, mSessionOnly(PR_TRUE)
, mLocalStorage(PR_FALSE)
, mItemsCached(PR_FALSE)
{
mItems.Init(8);
if (nsDOMStorageManager::gStorageManager)
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)
, mLocalStorage(PR_FALSE) // Any clone is not a localStorage
, mItemsCached(PR_FALSE)
, mDomain(aThat.mDomain)
#ifdef MOZ_STORAGE
, mScopeDBKey(aThat.mScopeDBKey)
#endif
{
mItems.Init(8);
+ aThat.mItems.EnumerateEntries(CopyStorageItems, this);
+
if (nsDOMStorageManager::gStorageManager)
nsDOMStorageManager::gStorageManager->AddToStoragesHash(this);
}
nsDOMStorage::~nsDOMStorage()
{
if (nsDOMStorageManager::gStorageManager)
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)
{
nsresult rv;
nsCOMPtr<nsIURI> uri;
rv = aPrincipal->GetURI(getter_AddRefs(uri));
NS_ENSURE_SUCCESS(rv, rv);
@@ -610,30 +656,16 @@ nsDOMStorage::InitAsGlobalStorage(const
if (!(mUseDB = !mScopeDBKey.IsEmpty()))
mScopeDBKey.AppendLiteral(":");
nsDOMStorageDBWrapper::CreateQuotaDomainDBKey(aDomainDemanded, PR_TRUE, mQuotaDomainDBKey);
#endif
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)
{
// check if the calling domain can use storage. Downgrade to session
// only if only session storage may be used.
NS_ASSERTION(aSessionOnly, "null session flag");
*aSessionOnly = PR_FALSE;
@@ -1235,51 +1267,21 @@ ClearStorageItem(nsSessionStorageEntry*
void
nsDOMStorage::ClearAll()
{
mItems.EnumerateEntries(ClearStorageItem, nsnull);
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
{
PRBool callerIsSecure;
nsTArray<nsString> *keys;
};
@@ -1304,20 +1306,20 @@ nsDOMStorage::GetKeys()
keystruct.callerIsSecure = IsCallerSecure();
keystruct.keys = new nsTArray<nsString>();
if (keystruct.keys)
mItems.EnumerateEntries(KeysArrayBuilder, &keystruct);
return keystruct.keys;
}
-const nsCString &
-nsDOMStorage::Domain()
+nsIPrincipal*
+nsDOMStorage::Principal()
{
- return mDomain;
+ return nsnull;
}
PRBool
nsDOMStorage::CanAccessSystem(nsIPrincipal *aPrincipal)
{
if (!aPrincipal)
return PR_TRUE;
@@ -1382,16 +1384,37 @@ NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOU
NS_IMPL_CYCLE_COLLECTING_RELEASE_AMBIGUOUS(nsDOMStorage2, nsIDOMStorage)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMStorage2)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMStorage)
NS_INTERFACE_MAP_ENTRY(nsIDOMStorage)
NS_INTERFACE_MAP_ENTRY(nsPIDOMStorage)
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)
{
mStorage = new nsDOMStorage();
if (!mStorage)
return NS_ERROR_OUT_OF_MEMORY;
mPrincipal = aPrincipal;
@@ -1400,45 +1423,38 @@ nsDOMStorage2::InitAsLocalStorage(nsIPri
nsresult
nsDOMStorage2::InitAsGlobalStorage(const nsACString &aDomainDemanded)
{
NS_ASSERTION(PR_FALSE, "Should not initialize nsDOMStorage2 as global storage.");
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> *
nsDOMStorage2::GetKeys()
{
return mStorage->GetKeys();
}
-const nsCString &
-nsDOMStorage2::Domain()
+nsIPrincipal*
+nsDOMStorage2::Principal()
{
- return mStorage->Domain();
+ return mPrincipal;
}
PRBool
nsDOMStorage2::CanAccess(nsIPrincipal *aPrincipal)
{
// Allow C++ callers to access the storage
if (!aPrincipal)
return PR_TRUE;
--- a/dom/src/storage/nsDOMStorage.h
+++ b/dom/src/storage/nsDOMStorage.h
@@ -135,22 +135,22 @@ public:
// nsIDOMStorageObsolete
NS_DECL_NSIDOMSTORAGEOBSOLETE
// Helpers for implementing nsIDOMStorage
nsresult GetItem(const nsAString& key, nsAString& aData);
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
// database, otherwise this storage should act like a session
// storage.
// This call relies on mSessionOnly, and should only be used
// after a CacheStoragePermissions() call. See the comments
// for mSessionOnly below.
@@ -262,25 +262,28 @@ public:
class nsDOMStorage2 : public nsIDOMStorage,
public nsPIDOMStorage
{
public:
// nsISupports
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:
// storages bound to an origin hold the principal to
// make security checks against it
nsCOMPtr<nsIPrincipal> mPrincipal;
nsRefPtr<nsDOMStorage> mStorage;
@@ -427,12 +430,15 @@ public:
protected:
nsString mDomain;
};
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);
#endif /* nsDOMStorage_h___ */
--- a/dom/tests/mochitest/Makefile.in
+++ b/dom/tests/mochitest/Makefile.in
@@ -49,12 +49,13 @@ DIRS += \
dom-level2-html \
ajax \
bugs \
chrome \
general \
whatwg \
geolocation \
localstorage \
+ sessionstorage \
$(NULL)
include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/sessionstorage/Makefile.in
@@ -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)
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/sessionstorage/frameEqual.html
@@ -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>
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/sessionstorage/frameNotEqual.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>
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/sessionstorage/frameReplace.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>
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/sessionstorage/interOriginSlave.js
@@ -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;
+}
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/sessionstorage/interOriginTest.js
@@ -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;
+ }
+}
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/sessionstorage/test_sessionStorageBase.html
@@ -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>
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/sessionstorage/test_sessionStorageClone.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>
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/sessionstorage/test_sessionStorageReplace.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>
--- a/embedding/components/windowwatcher/src/nsWindowWatcher.cpp
+++ b/embedding/components/windowwatcher/src/nsWindowWatcher.cpp
@@ -81,16 +81,17 @@
#include "nsIMarkupDocumentViewer.h"
#include "nsIContentViewer.h"
#include "nsIDocumentViewer.h"
#include "nsIWindowProvider.h"
#include "nsIMutableArray.h"
#include "nsISupportsArray.h"
#include "nsIDeviceContext.h"
#include "nsIDOMStorageObsolete.h"
+#include "nsIDOMStorage.h"
#include "nsPIDOMStorage.h"
#include "nsIWidget.h"
#include "nsIPrefBranch.h"
#include "nsIPrefService.h"
#include "jsinterp.h" // for js_AllocStack() and js_FreeStack()
@@ -926,30 +927,30 @@ nsWindowWatcher::OpenWindowJSInternal(ns
newDocShell->LoadURI(uriToLoad, loadInfo,
windowIsNew ? nsIWebNavigation::LOAD_FLAGS_FIRST_LOAD :
nsIWebNavigation::LOAD_FLAGS_NONE, PR_TRUE);
}
// 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 =
do_QueryInterface(storage);
if (piStorage){
storage = piStorage->Clone();
newDocShell->AddSessionStorage(
- piStorage->Domain(),
+ piStorage->Principal(),
storage);
}
}
if (isNewToplevelWindow)
SizeOpenedDocShellItem(newDocShellItem, aParent, sizeSpec);
// XXXbz isn't windowIsModal always true when windowIsModalContentDialog?
--- a/layout/build/nsLayoutCID.h
+++ b/layout/build/nsLayoutCID.h
@@ -213,16 +213,20 @@
// {a35d1cd4-c505-4d2d-a0f9-aef00b7ce5a5}
#define NS_CANVASRENDERINGCONTEXT2D_CID \
{ 0xa35d1cd4, 0xc505, 0x4d2d, { 0xa0, 0xf9, 0xae, 0xf0, 0x0b, 0x7c, 0xe5, 0xa5 } }
// {8b449142-1eab-4bfa-9830-fab6ebb09774}
#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 } }
// {14632191-AC21-4BDF-83E7-2363AD17E838}
#define NS_XULPOPUPMANAGER_CID \
{ 0x14632191, 0xac21, 0x4bdf, { 0x83, 0xe7, 0x23, 0x63, 0xad, 0x17, 0xe8, 0x38 } }
--- a/layout/build/nsLayoutModule.cpp
+++ b/layout/build/nsLayoutModule.cpp
@@ -1397,16 +1397,21 @@ static const nsModuleComponentInfo gComp
NS_DOMPARSER_CONTRACTID,
nsDOMParserConstructor },
{ "DOM Storage",
NS_DOMSTORAGE_CID,
"@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",
nsDOMStorageManagerConstructor },
{ "DOM JSON",
NS_DOMJSON_CID,
"@mozilla.org/dom/json;1",