diff --git a/browser/components/sessionstore/src/nsSessionStore.js b/browser/components/sessionstore/src/nsSessionStore.js index d13431a355b2..9b8650150f96 100644 --- a/browser/components/sessionstore/src/nsSessionStore.js +++ b/browser/components/sessionstore/src/nsSessionStore.js @@ -1397,7 +1397,7 @@ SessionStoreService.prototype = { // sessionStorage object for the page earlier than the page really // requires it. It was causing problems while accessing a storage when // a page later changed its domain. - storage = aDocShell.getSessionStorageForPrincipal(principal, false); + storage = aDocShell.getSessionStorageForPrincipal(principal, "", false); if (storage) storageItemCount = storage.length; } @@ -2254,7 +2254,7 @@ SessionStoreService.prototype = { _deserializeSessionStorage: function sss_deserializeSessionStorage(aStorageData, aDocShell) { for (let url in aStorageData) { let uri = IOSvc.newURI(url, null, null); - let storage = aDocShell.getSessionStorageForURI(uri); + let storage = aDocShell.getSessionStorageForURI(uri, ""); for (let key in aStorageData[url]) { try { storage.setItem(key, aStorageData[url][key]); diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index 3251571089f8..9c32e20b1966 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -51,6 +51,7 @@ #include "nsIContent.h" #include "nsIDocument.h" #include "nsIDOMDocument.h" +#include "nsIDOM3Document.h" #include "nsIDOMNSDocument.h" #include "nsIDOMElement.h" #include "nsIDOMStorageObsolete.h" @@ -2144,6 +2145,7 @@ GetPrincipalDomain(nsIPrincipal* aPrincipal, nsACString& aDomain) NS_IMETHODIMP nsDocShell::GetSessionStorageForPrincipal(nsIPrincipal* aPrincipal, + const nsAString& aDocumentURI, PRBool aCreate, nsIDOMStorage** aStorage) { @@ -2165,7 +2167,9 @@ nsDocShell::GetSessionStorageForPrincipal(nsIPrincipal* aPrincipal, nsDocShell* topDocShell = static_cast(topItem.get()); if (topDocShell != this) - return topDocShell->GetSessionStorageForPrincipal(aPrincipal, aCreate, + return topDocShell->GetSessionStorageForPrincipal(aPrincipal, + aDocumentURI, + aCreate, aStorage); nsCAutoString currentDomain; @@ -2185,7 +2189,7 @@ nsDocShell::GetSessionStorageForPrincipal(nsIPrincipal* aPrincipal, nsCOMPtr pistorage = do_QueryInterface(newstorage); if (!pistorage) return NS_ERROR_FAILURE; - rv = pistorage->InitAsSessionStorage(aPrincipal); + rv = pistorage->InitAsSessionStorage(aPrincipal, aDocumentURI); if (NS_FAILED(rv)) return rv; @@ -2193,19 +2197,58 @@ nsDocShell::GetSessionStorageForPrincipal(nsIPrincipal* aPrincipal, return NS_ERROR_OUT_OF_MEMORY; newstorage.swap(*aStorage); - return NS_OK; +#if defined(PR_LOGGING) && defined(DEBUG) + PR_LOG(gDocShellLog, PR_LOG_DEBUG, + ("nsDocShell[%p]: created a new sessionStorage %p", + this, *aStorage)); +#endif + } + else if (*aStorage) { + nsCOMPtr 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) { + NS_RELEASE(*aStorage); + return NS_ERROR_DOM_SECURITY_ERR; + } + } + +#if defined(PR_LOGGING) && defined(DEBUG) + PR_LOG(gDocShellLog, PR_LOG_DEBUG, + ("nsDocShell[%p]: returns existing sessionStorage %p", + this, *aStorage)); +#endif + return NS_OK; } - nsCOMPtr 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) { - NS_RELEASE(*aStorage); - return NS_ERROR_DOM_SECURITY_ERR; - } + if (aCreate) { + // We are asked to create a new storage object. This indicates + // that a new windows wants it. At this moment we "fork" the existing + // storage object (what it means is described in the paragraph bellow). + // We must create a single object per a single window to distinguish + // a window originating oparations on the storage object to succesfully + // prevent dispatch of a storage event to this same window that ivoked + // a change in its storage. We also do this to correctly fill + // documentURI property in the storage event. + // + // The difference between clone and fork is that clone creates + // a completelly new and independent storage, but fork only creates + // a new object wrapping the storage implementation and data and + // the forked storage then behaves completelly the same way as + // the storage it has been forked of, all such forked storage objects + // shares their state and data and change on one such object affects + // all others the same way. + nsCOMPtr piStorage = do_QueryInterface(*aStorage); + nsCOMPtr fork = piStorage->Fork(aDocumentURI); +#if defined(PR_LOGGING) && defined(DEBUG) + PR_LOG(gDocShellLog, PR_LOG_DEBUG, + ("nsDocShell[%p]: forked sessionStorage %p to %p", + this, *aStorage, fork.get())); +#endif + fork.swap(*aStorage); } return NS_OK; @@ -2213,13 +2256,15 @@ nsDocShell::GetSessionStorageForPrincipal(nsIPrincipal* aPrincipal, NS_IMETHODIMP nsDocShell::GetSessionStorageForURI(nsIURI* aURI, + const nsAString& aDocumentURI, nsIDOMStorage** aStorage) { - return GetSessionStorageForURI(aURI, PR_TRUE, aStorage); + return GetSessionStorageForURI(aURI, aDocumentURI, PR_TRUE, aStorage); } nsresult nsDocShell::GetSessionStorageForURI(nsIURI* aURI, + const nsSubstring& aDocumentURI, PRBool aCreate, nsIDOMStorage** aStorage) { @@ -2240,7 +2285,7 @@ nsDocShell::GetSessionStorageForURI(nsIURI* aURI, if (NS_FAILED(rv)) return rv; - return GetSessionStorageForPrincipal(principal, aCreate, aStorage); + return GetSessionStorageForPrincipal(principal, aDocumentURI, aCreate, aStorage); } nsresult @@ -2272,6 +2317,11 @@ nsDocShell::AddSessionStorage(nsIPrincipal* aPrincipal, if (mStorages.GetWeak(currentDomain)) return NS_ERROR_NOT_AVAILABLE; +#if defined(PR_LOGGING) && defined(DEBUG) + PR_LOG(gDocShellLog, PR_LOG_DEBUG, + ("nsDocShell[%p]: was added a sessionStorage %p", + this, aStorage)); +#endif if (!mStorages.Put(currentDomain, aStorage)) return NS_ERROR_OUT_OF_MEMORY; } diff --git a/docshell/base/nsDocShell.h b/docshell/base/nsDocShell.h index dcce9dd0be23..68b95ffe9449 100644 --- a/docshell/base/nsDocShell.h +++ b/docshell/base/nsDocShell.h @@ -605,6 +605,7 @@ protected: void ReattachEditorToWindow(nsISHEntry *aSHEntry); nsresult GetSessionStorageForURI(nsIURI* aURI, + const nsSubstring& aDocumentURI, PRBool create, nsIDOMStorage** aStorage); diff --git a/docshell/base/nsIDocShell.idl b/docshell/base/nsIDocShell.idl index 26634a9d603b..0e1b8aef4362 100644 --- a/docshell/base/nsIDocShell.idl +++ b/docshell/base/nsIDocShell.idl @@ -70,7 +70,7 @@ interface nsIDOMStorage; interface nsIPrincipal; interface nsIWebBrowserPrint; -[scriptable, uuid(1067ee1a-08e8-455d-9b12-19eeeee56b8e)] +[scriptable, uuid(c95eaff1-14e6-4db1-a806-46be97d5a9b6)] interface nsIDocShell : nsISupports { /** @@ -430,17 +430,23 @@ interface nsIDocShell : nsISupports * If it doesn't already exist, a new one will be created. * * @param uri the uri of the storage object to retrieve + * @param documentURI new storage will be created with reference to this + * document.documentURI that will appear in storage event */ - nsIDOMStorage getSessionStorageForURI(in nsIURI uri); + nsIDOMStorage getSessionStorageForURI(in nsIURI uri, + in DOMString documentURI); /* * Retrieves the WebApps session storage object for the supplied principal. * * @param principal returns a storage for this principal + * @param documentURI new storage will be created with reference to this + * document.documentURI that will appear in storage event * @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 DOMString documentURI, in boolean create); /* diff --git a/dom/base/nsDOMClassInfo.cpp b/dom/base/nsDOMClassInfo.cpp index 42fcbf65098f..160ed477f6f2 100644 --- a/dom/base/nsDOMClassInfo.cpp +++ b/dom/base/nsDOMClassInfo.cpp @@ -1202,6 +1202,8 @@ static nsDOMClassInfoData sClassInfoData[] = { DOM_DEFAULT_SCRIPTABLE_FLAGS) NS_DEFINE_CLASSINFO_DATA(StorageEvent, nsDOMGenericSH, DOM_DEFAULT_SCRIPTABLE_FLAGS) + NS_DEFINE_CLASSINFO_DATA(StorageEventObsolete, nsDOMGenericSH, + DOM_DEFAULT_SCRIPTABLE_FLAGS) NS_DEFINE_CLASSINFO_DATA(DOMParser, nsDOMGenericSH, DOM_DEFAULT_SCRIPTABLE_FLAGS) @@ -3487,6 +3489,10 @@ nsDOMClassInfo::Init() DOM_CLASSINFO_MAP_ENTRY(nsIDOMStorageEvent) DOM_CLASSINFO_MAP_END + DOM_CLASSINFO_MAP_BEGIN(StorageEventObsolete, nsIDOMStorageEventObsolete) + DOM_CLASSINFO_MAP_ENTRY(nsIDOMStorageEventObsolete) + DOM_CLASSINFO_MAP_END + DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(DOMParser, nsIDOMParser) DOM_CLASSINFO_MAP_ENTRY(nsIDOMParser) DOM_CLASSINFO_MAP_ENTRY(nsIDOMParserJS) diff --git a/dom/base/nsDOMClassInfoID.h b/dom/base/nsDOMClassInfoID.h index 124abebcabb0..f5b23f5baa2f 100644 --- a/dom/base/nsDOMClassInfoID.h +++ b/dom/base/nsDOMClassInfoID.h @@ -383,6 +383,7 @@ enum nsDOMClassInfoID { eDOMClassInfo_StorageList_id, eDOMClassInfo_StorageItem_id, eDOMClassInfo_StorageEvent_id, + eDOMClassInfo_StorageEventObsolete_id, // DOMParser, XMLSerializer eDOMClassInfo_DOMParser_id, diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index 8bfc3cbca9ae..492217806d92 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -101,6 +101,7 @@ #include "nsIDOMHTMLElement.h" #include "nsIDOMCrypto.h" #include "nsIDOMDocument.h" +#include "nsIDOM3Document.h" #include "nsIDOMNSDocument.h" #include "nsIDOMDocumentView.h" #include "nsIDOMElement.h" @@ -113,6 +114,7 @@ #include "nsIDOMPopupBlockedEvent.h" #include "nsIDOMOfflineResourceList.h" #include "nsIDOMGeoGeolocation.h" +#include "nsPIDOMStorage.h" #include "nsDOMString.h" #include "nsIEmbeddingSiteWindow2.h" #include "nsThreadUtils.h" @@ -653,9 +655,9 @@ nsGlobalWindow::nsGlobalWindow(nsGlobalWindow *aOuterWindow) mTimeoutPublicIdCounter(1), mTimeoutFiringDepth(0), mJSObject(nsnull), - mPendingStorageEvents(nsnull), mTimeoutsSuspendDepth(0), - mFocusMethod(0) + mFocusMethod(0), + mPendingStorageEventsObsolete(nsnull) #ifdef DEBUG , mSetOpenerWindowCalled(PR_FALSE) #endif @@ -687,6 +689,7 @@ nsGlobalWindow::nsGlobalWindow(nsGlobalWindow *aOuterWindow) // Watch for dom-storage-changed so we can fire storage // events. Use a strong reference. + os->AddObserver(mObserver, "dom-storage2-changed", PR_FALSE); os->AddObserver(mObserver, "dom-storage-changed", PR_FALSE); } } @@ -773,6 +776,7 @@ nsGlobalWindow::~nsGlobalWindow() do_GetService("@mozilla.org/observer-service;1"); if (os) { os->RemoveObserver(mObserver, NS_IOSERVICE_OFFLINE_STATUS_TOPIC); + os->RemoveObserver(mObserver, "dom-storage2-changed"); os->RemoveObserver(mObserver, "dom-storage-changed"); } @@ -826,7 +830,7 @@ nsGlobalWindow::~nsGlobalWindow() nsCycleCollector_DEBUG_wasFreed(static_cast(this)); #endif - delete mPendingStorageEvents; + delete mPendingStorageEventsObsolete; nsLayoutStatics::Release(); } @@ -1730,6 +1734,7 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument, mDocument = do_QueryInterface(aDocument); mDoc = aDocument; mLocalStorage = nsnull; + mSessionStorage = nsnull; #ifdef DEBUG mLastOpenedURI = aDocument->GetDocumentURI(); @@ -7082,8 +7087,6 @@ nsGlobalWindow::GetSessionStorage(nsIDOMStorage ** aSessionStorage) { FORWARD_TO_INNER(GetSessionStorage, (aSessionStorage), NS_ERROR_UNEXPECTED); - *aSessionStorage = nsnull; - nsIPrincipal *principal = GetPrincipal(); nsIDocShell* docShell = GetDocShell(); @@ -7091,15 +7094,56 @@ nsGlobalWindow::GetSessionStorage(nsIDOMStorage ** aSessionStorage) return NS_OK; } - nsresult rv = docShell->GetSessionStorageForPrincipal(principal, - PR_TRUE, - aSessionStorage); - NS_ENSURE_SUCCESS(rv, rv); - - if (!*aSessionStorage) { - return NS_ERROR_DOM_NOT_SUPPORTED_ERR; + if (mSessionStorage) { +#ifdef PR_LOGGING + if (PR_LOG_TEST(gDOMLeakPRLog, PR_LOG_DEBUG)) { + PR_LogPrint("nsGlobalWindow %p has %p sessionStorage", this, mSessionStorage.get()); + } +#endif + nsCOMPtr piStorage = do_QueryInterface(mSessionStorage); + if (piStorage) { + PRBool canAccess = piStorage->CanAccess(principal); + NS_ASSERTION(canAccess, + "window %x owned sessionStorage " + "that could not be accessed!"); + if (!canAccess) { + mSessionStorage = nsnull; + } + } } + if (!mSessionStorage) { + *aSessionStorage = nsnull; + + nsString documentURI; + nsCOMPtr document3 = do_QueryInterface(mDoc); + if (document3) + document3->GetDocumentURI(documentURI); + + nsresult rv = docShell->GetSessionStorageForPrincipal(principal, + documentURI, + PR_TRUE, + getter_AddRefs(mSessionStorage)); + NS_ENSURE_SUCCESS(rv, rv); + +#ifdef PR_LOGGING + if (PR_LOG_TEST(gDOMLeakPRLog, PR_LOG_DEBUG)) { + PR_LogPrint("nsGlobalWindow %p tried to get a new sessionStorage %p", this, mSessionStorage.get()); + } +#endif + + if (!mSessionStorage) { + return NS_ERROR_DOM_NOT_SUPPORTED_ERR; + } + } + +#ifdef PR_LOGGING + if (PR_LOG_TEST(gDOMLeakPRLog, PR_LOG_DEBUG)) { + PR_LogPrint("nsGlobalWindow %p returns %p sessionStorage", this, mSessionStorage.get()); + } +#endif + + NS_ADDREF(*aSessionStorage = mSessionStorage); return NS_OK; } @@ -7147,7 +7191,14 @@ nsGlobalWindow::GetLocalStorage(nsIDOMStorage ** aLocalStorage) do_GetService("@mozilla.org/dom/storagemanager;1", &rv); NS_ENSURE_SUCCESS(rv, rv); - rv = storageManager->GetLocalStorageForPrincipal(principal, getter_AddRefs(mLocalStorage)); + nsString documentURI; + nsCOMPtr document3 = do_QueryInterface(mDoc); + if (document3) + document3->GetDocumentURI(documentURI); + + rv = storageManager->GetLocalStorageForPrincipal(principal, + documentURI, + getter_AddRefs(mLocalStorage)); NS_ENSURE_SUCCESS(rv, rv); } @@ -7290,21 +7341,7 @@ nsGlobalWindow::Observe(nsISupports* aSubject, const char* aTopic, nsresult rv; principal = GetPrincipal(); - if (!aData) { - nsIDocShell* docShell = GetDocShell(); - if (principal && docShell) { - nsCOMPtr 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; - } - } - } else if (principal) { + if (principal) { // A global storage object changed, check to see if it's one // this window can access. @@ -7338,23 +7375,23 @@ nsGlobalWindow::Observe(nsISupports* aSubject, const char* aTopic, // store the domain in which the change happened and fire the // events if we're ever thawed. - if (!mPendingStorageEvents) { - mPendingStorageEvents = new nsDataHashtable; - NS_ENSURE_TRUE(mPendingStorageEvents, NS_ERROR_OUT_OF_MEMORY); + if (!mPendingStorageEventsObsolete) { + mPendingStorageEventsObsolete = new nsDataHashtable; + NS_ENSURE_TRUE(mPendingStorageEventsObsolete, NS_ERROR_OUT_OF_MEMORY); - rv = mPendingStorageEvents->Init(); + rv = mPendingStorageEventsObsolete->Init(); NS_ENSURE_SUCCESS(rv, rv); } - mPendingStorageEvents->Put(domain, PR_TRUE); + mPendingStorageEventsObsolete->Put(domain, PR_TRUE); return NS_OK; } - nsRefPtr event = new nsDOMStorageEvent(domain); + nsRefPtr event = new nsDOMStorageEventObsolete(); NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY); - rv = event->Init(); + rv = event->InitStorageEvent(NS_LITERAL_STRING("storage"), PR_FALSE, PR_FALSE, domain); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr htmlDoc(do_QueryInterface(mDocument)); @@ -7373,7 +7410,99 @@ nsGlobalWindow::Observe(nsISupports* aSubject, const char* aTopic, } PRBool defaultActionEnabled; - target->DispatchEvent((nsIDOMStorageEvent *)event, &defaultActionEnabled); + target->DispatchEvent((nsIDOMStorageEventObsolete *)event, &defaultActionEnabled); + + return NS_OK; + } + + if (IsInnerWindow() && !nsCRT::strcmp(aTopic, "dom-storage2-changed")) { + nsIPrincipal *principal; + nsresult rv; + + nsCOMPtr event = do_QueryInterface(aSubject, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr changingStorage; + rv = event->GetStorageArea(getter_AddRefs(changingStorage)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr pistorage = do_QueryInterface(changingStorage); + nsPIDOMStorage::nsDOMStorageType storageType = pistorage->StorageType(); + + principal = GetPrincipal(); + switch (storageType) + { + case nsPIDOMStorage::SessionStorage: + { + if (SameCOMIdentity(mSessionStorage, changingStorage)) { + // Do not fire any events for the same storage object, it's not shared + // among windows, see nsGlobalWindow::GetSessionStoarge() + return NS_OK; + } + + nsCOMPtr storage = mSessionStorage; + if (!storage) { + nsIDocShell* docShell = GetDocShell(); + if (principal && docShell) { + // No need to pass documentURI here, it's only needed when we want + // to create a new storage, the third paramater would be PR_TRUE + docShell->GetSessionStorageForPrincipal(principal, + EmptyString(), + PR_FALSE, + getter_AddRefs(storage)); + } + } + + if (!pistorage->IsForkOf(storage)) { + // This storage event is coming from a different doc shell, + // i.e. it is a clone, ignore this event. + return NS_OK; + } + +#ifdef PR_LOGGING + if (PR_LOG_TEST(gDOMLeakPRLog, PR_LOG_DEBUG)) { + PR_LogPrint("nsGlobalWindow %p with sessionStorage %p passing event from %p", this, mSessionStorage.get(), pistorage.get()); + } +#endif + + break; + } + case nsPIDOMStorage::LocalStorage: + { + if (SameCOMIdentity(mLocalStorage, changingStorage)) { + // Do not fire any events for the same storage object, it's not shared + // among windows, see nsGlobalWindow::GetLocalStoarge() + return NS_OK; + } + + // Allow event fire only for the same principal storages + // XXX We have to use EqualsIgnoreDomain after bug 495337 lands + nsIPrincipal *storagePrincipal = pistorage->Principal(); + PRBool equals; + + rv = storagePrincipal->Equals(principal, &equals); + NS_ENSURE_SUCCESS(rv, rv); + + if (!equals) + return NS_OK; + + break; + } + default: + return NS_OK; + } + + if (IsFrozen()) { + // This window is frozen, rather than firing the events here, + // store the domain in which the change happened and fire the + // events if we're ever thawed. + + mPendingStorageEvents.AppendElement(event); + return NS_OK; + } + + PRBool defaultActionEnabled; + DispatchEvent((nsIDOMStorageEvent *)event, &defaultActionEnabled); return NS_OK; } @@ -7403,12 +7532,16 @@ nsGlobalWindow::FireDelayedDOMEvents() { FORWARD_TO_INNER(FireDelayedDOMEvents, (), NS_ERROR_UNEXPECTED); - if (mPendingStorageEvents) { - // Fire pending storage events. - mPendingStorageEvents->EnumerateRead(FirePendingStorageEvents, this); + for (PRUint32 i = 0; i < mPendingStorageEvents.Length(); ++i) { + Observe(mPendingStorageEvents[i], "dom-storage2-changed", nsnull); + } - delete mPendingStorageEvents; - mPendingStorageEvents = nsnull; + if (mPendingStorageEventsObsolete) { + // Fire pending storage events. + mPendingStorageEventsObsolete->EnumerateRead(FirePendingStorageEvents, this); + + delete mPendingStorageEventsObsolete; + mPendingStorageEventsObsolete = nsnull; } if (mApplicationCache) { diff --git a/dom/base/nsGlobalWindow.h b/dom/base/nsGlobalWindow.h index b26241e63113..77d16e095cb6 100644 --- a/dom/base/nsGlobalWindow.h +++ b/dom/base/nsGlobalWindow.h @@ -96,6 +96,7 @@ #include "nsIDOMStorageObsolete.h" #include "nsIDOMStorageList.h" #include "nsIDOMStorageWindow.h" +#include "nsIDOMStorageEvent.h" #include "nsIDOMOfflineResourceList.h" #include "nsPIDOMEventTarget.h" #include "nsIArray.h" @@ -738,6 +739,7 @@ protected: nsCOMPtr mCrypto; nsCOMPtr mLocalStorage; + nsCOMPtr mSessionStorage; nsCOMPtr mInnerWindowHolders[NS_STID_ARRAY_UBOUND]; nsCOMPtr mOpenerScriptPrincipal; // strong; used to determine @@ -750,7 +752,6 @@ protected: nsTimeout* mTimeoutInsertionPoint; PRUint32 mTimeoutPublicIdCounter; PRUint32 mTimeoutFiringDepth; - nsCOMPtr mSessionStorage; // Holder of the dummy java plugin, used to expose window.java and // window.packages. @@ -761,7 +762,9 @@ protected: nsCOMPtr mDoc; // For fast access to principals JSObject* mJSObject; - nsDataHashtable *mPendingStorageEvents; + typedef nsTArray> nsDOMStorageEventArray; + nsDOMStorageEventArray mPendingStorageEvents; + nsDataHashtable *mPendingStorageEventsObsolete; PRUint32 mTimeoutsSuspendDepth; diff --git a/dom/interfaces/storage/Makefile.in b/dom/interfaces/storage/Makefile.in index ca9b3796afc0..4e8f55712f89 100644 --- a/dom/interfaces/storage/Makefile.in +++ b/dom/interfaces/storage/Makefile.in @@ -59,6 +59,7 @@ SDK_XPIDLSRCS = \ nsIDOMStorage.idl \ nsIDOMStorageObsolete.idl\ nsIDOMStorageEvent.idl \ + nsIDOMStorageEventObsolete.idl \ nsIDOMStorageItem.idl \ nsIDOMStorageList.idl \ nsIDOMStorageWindow.idl \ diff --git a/dom/interfaces/storage/nsIDOMStorageEvent.idl b/dom/interfaces/storage/nsIDOMStorageEvent.idl index e5a2fce0b9a6..25941ad5f532 100644 --- a/dom/interfaces/storage/nsIDOMStorageEvent.idl +++ b/dom/interfaces/storage/nsIDOMStorageEvent.idl @@ -40,26 +40,57 @@ /** * Interface for a client side storage. See - * http://www.whatwg.org/specs/web-apps/current-work/#scs-client-side + * http://dev.w3.org/html5/webstorage/#the-storage-event * for more information. * * Event sent to a window when a storage area changes. */ -[scriptable, uuid(8c021c75-f6b6-493c-914e-0b6c57ccc88d)] +interface nsIDOMStorage; + +[scriptable, uuid(AE0CB688-68B3-4fb3-9A11-2DA8E620E808)] interface nsIDOMStorageEvent : nsIDOMEvent { /** - * Domain of the storage area which changed, or #session for - * session storage. + * Attribute represents the key being changed. The key attribute is null + * when change has been invoked by the storage clear() method. */ - readonly attribute DOMString domain; + readonly attribute DOMString key; /** - * Initialize a storage event. + * The original value of the key. The oldValue is null when the change + * has been invoked by storage clear() method or the key has been newly + * added and therefor doesn't have any previous value. + */ + readonly attribute DOMString oldValue; + + /** + * The new value of the key. The newValue is null when the change + * has been invoked by storage clear() method or the key has been removed + * from the storage. + */ + readonly attribute DOMString newValue; + + /** + * Represents the address of the document whose key changed. + */ + readonly attribute DOMString url; + + /** + * Represents the Storage object that was affected. + */ + readonly attribute nsIDOMStorage storageArea; + + /** + * Initialize the event in a manner analogous to the similarly-named method + * in the DOM Events interfaces. */ void initStorageEvent(in DOMString typeArg, in boolean canBubbleArg, in boolean cancelableArg, - in DOMString domainArg); + in DOMString keyArg, + in DOMString oldValueArg, + in DOMString newValueArg, + in DOMString urlArg, + in nsIDOMStorage storageAreaArg); }; diff --git a/dom/interfaces/storage/nsIDOMStorageEventObsolete.idl b/dom/interfaces/storage/nsIDOMStorageEventObsolete.idl new file mode 100644 index 000000000000..4bf94e7c1a0f --- /dev/null +++ b/dom/interfaces/storage/nsIDOMStorageEventObsolete.idl @@ -0,0 +1,65 @@ +/* -*- Mode: IDL; 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 + * Neil Deakin + * Portions created by the Initial Developer are Copyright (C) 2006 + * 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 ***** */ + +#include "domstubs.idl" +#include "nsIDOMEvent.idl" + +/** + * Interface for a client side storage. See + * http://www.whatwg.org/specs/web-apps/current-work/#scs-client-side + * for more information. + * + * Event sent to a window when a storage area changes. + */ + +[scriptable, uuid(c0178907-847d-41c0-8a62-31301bb946fa)] +interface nsIDOMStorageEventObsolete : nsIDOMEvent +{ + /** + * Domain of the storage area which changed, or #session for + * session storage. + */ + readonly attribute DOMString domain; + + /** + * Initialize a storage event. + */ + void initStorageEvent(in DOMString typeArg, + in boolean canBubbleArg, + in boolean cancelableArg, + in DOMString domainArg); +}; diff --git a/dom/interfaces/storage/nsIDOMStorageManager.idl b/dom/interfaces/storage/nsIDOMStorageManager.idl index 2c6367d6f4c6..7df2efa34706 100644 --- a/dom/interfaces/storage/nsIDOMStorageManager.idl +++ b/dom/interfaces/storage/nsIDOMStorageManager.idl @@ -40,7 +40,7 @@ interface nsIDOMStorage; interface nsIPrincipal; -[scriptable, uuid(c8e54beb-48f3-4538-a0ce-d6229f4d8f45)] +[scriptable, uuid(fd91ec36-7da8-43bb-b8f2-4b57a862a467)] interface nsIDOMStorageManager : nsISupports { /** @@ -64,5 +64,6 @@ interface nsIDOMStorageManager : nsISupports * This method ensures there is always only a single instance * for a single origin. */ - nsIDOMStorage getLocalStorageForPrincipal(in nsIPrincipal aPrincipal); + nsIDOMStorage getLocalStorageForPrincipal(in nsIPrincipal aPrincipal, + in DOMString aDocumentURI); }; diff --git a/dom/interfaces/storage/nsPIDOMStorage.h b/dom/interfaces/storage/nsPIDOMStorage.h index 2ee17f0c7065..6ab8bea9f55d 100644 --- a/dom/interfaces/storage/nsPIDOMStorage.h +++ b/dom/interfaces/storage/nsPIDOMStorage.h @@ -47,25 +47,41 @@ class nsIDOMStorageObsolete; class nsIURI; class nsIPrincipal; +// {BAFFCEB1-FD40-4ea9-8378-3509DD79204A} #define NS_PIDOMSTORAGE_IID \ - { 0x5ffbee8d, 0x9a86, 0x4a57, \ - { 0x8c, 0x63, 0x76, 0x56, 0x18, 0x9c, 0xb2, 0xbc } } + { 0xbaffceb1, 0xfd40, 0x4ea9, \ + { 0x83, 0x78, 0x35, 0x9, 0xdd, 0x79, 0x20, 0x4a } }; 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; + typedef enum { + Unknown = 0, + GlobalStorage = 1, + LocalStorage = 2, + SessionStorage = 3 + } nsDOMStorageType; + + virtual nsresult InitAsSessionStorage(nsIPrincipal *aPrincipal, const nsSubstring &aDocumentURI) = 0; + virtual nsresult InitAsLocalStorage(nsIPrincipal *aPrincipal, const nsSubstring &aDocumentURI) = 0; virtual nsresult InitAsGlobalStorage(const nsACString &aDomainDemanded) = 0; virtual already_AddRefed Clone() = 0; + virtual already_AddRefed Fork(const nsSubstring &aDocumentURI) = 0; + virtual PRBool IsForkOf(nsIDOMStorage* aThat) = 0; virtual nsTArray *GetKeys() = 0; virtual nsIPrincipal* Principal() = 0; virtual PRBool CanAccess(nsIPrincipal *aPrincipal) = 0; + + virtual nsDOMStorageType StorageType() = 0; + + virtual void BroadcastChangeNotification(const nsSubstring &aKey, + const nsSubstring &aOldValue, + const nsSubstring &aNewValue) = 0; }; NS_DEFINE_STATIC_IID_ACCESSOR(nsPIDOMStorage, NS_PIDOMSTORAGE_IID) diff --git a/dom/src/storage/nsDOMStorage.cpp b/dom/src/storage/nsDOMStorage.cpp index b1be207efe9f..df35c0f41e1b 100644 --- a/dom/src/storage/nsDOMStorage.cpp +++ b/dom/src/storage/nsDOMStorage.cpp @@ -64,6 +64,7 @@ #include "nsIPrivateBrowsingService.h" #include "nsDOMString.h" #include "nsNetCID.h" +#include "nsIProxyObjectManager.h" static const PRUint32 ASK_BEFORE_ACCEPT = 1; static const PRUint32 ACCEPT_SESSION = 2; @@ -436,6 +437,7 @@ nsDOMStorageManager::ClearOfflineApps() NS_IMETHODIMP nsDOMStorageManager::GetLocalStorageForPrincipal(nsIPrincipal *aPrincipal, + const nsSubstring &aDocumentURI, nsIDOMStorage **aResult) { NS_ENSURE_ARG_POINTER(aPrincipal); @@ -447,7 +449,7 @@ nsDOMStorageManager::GetLocalStorageForPrincipal(nsIPrincipal *aPrincipal, if (!storage) return NS_ERROR_OUT_OF_MEMORY; - rv = storage->InitAsLocalStorage(aPrincipal); + rv = storage->InitAsLocalStorage(aPrincipal, aDocumentURI); if (NS_FAILED(rv)) return rv; @@ -548,8 +550,9 @@ NS_NewDOMStorage2(nsISupports* aOuter, REFNSIID aIID, void** aResult) nsDOMStorage::nsDOMStorage() : mUseDB(PR_FALSE) , mSessionOnly(PR_TRUE) - , mLocalStorage(PR_FALSE) , mItemsCached(PR_FALSE) + , mStorageType(nsPIDOMStorage::Unknown) + , mEventBroadcaster(nsnull) { mSecurityChecker = this; mItems.Init(8); @@ -560,12 +563,13 @@ nsDOMStorage::nsDOMStorage() 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) + , mStorageType(aThat.mStorageType) #ifdef MOZ_STORAGE , mScopeDBKey(aThat.mScopeDBKey) #endif + , mEventBroadcaster(nsnull) { mSecurityChecker = this; mItems.Init(8); @@ -610,7 +614,7 @@ GetDomainURI(nsIPrincipal *aPrincipal, PRBool aIncludeDomain, nsIURI **_domain) } nsresult -nsDOMStorage::InitAsSessionStorage(nsIPrincipal *aPrincipal) +nsDOMStorage::InitAsSessionStorage(nsIPrincipal *aPrincipal, const nsSubstring &aDocumentURI) { nsCOMPtr domainURI; nsresult rv = GetDomainURI(aPrincipal, PR_TRUE, getter_AddRefs(domainURI)); @@ -623,16 +627,20 @@ nsDOMStorage::InitAsSessionStorage(nsIPrincipal *aPrincipal) // won't get to InitAsSessionStorage. domainURI->GetAsciiHost(mDomain); + mDocumentURI = aDocumentURI; + #ifdef MOZ_STORAGE mUseDB = PR_FALSE; mScopeDBKey.Truncate(); mQuotaDomainDBKey.Truncate(); #endif + + mStorageType = SessionStorage; return NS_OK; } nsresult -nsDOMStorage::InitAsLocalStorage(nsIPrincipal *aPrincipal) +nsDOMStorage::InitAsLocalStorage(nsIPrincipal *aPrincipal, const nsSubstring &aDocumentURI) { nsCOMPtr domainURI; nsresult rv = GetDomainURI(aPrincipal, PR_FALSE, getter_AddRefs(domainURI)); @@ -646,6 +654,8 @@ nsDOMStorage::InitAsLocalStorage(nsIPrincipal *aPrincipal) // mPrincipal in bug 455070. It is not even used for localStorage. domainURI->GetAsciiHost(mDomain); + mDocumentURI = aDocumentURI; + #ifdef MOZ_STORAGE nsDOMStorageDBWrapper::CreateOriginScopeDBKey(domainURI, mScopeDBKey); @@ -661,7 +671,7 @@ nsDOMStorage::InitAsLocalStorage(nsIPrincipal *aPrincipal) PR_TRUE, PR_TRUE, mQuotaETLDplus1DomainDBKey); #endif - mLocalStorage = PR_TRUE; + mStorageType = LocalStorage; return NS_OK; } @@ -684,6 +694,9 @@ nsDOMStorage::InitAsGlobalStorage(const nsACString &aDomainDemanded) nsDOMStorageDBWrapper::CreateQuotaDomainDBKey(aDomainDemanded, PR_TRUE, PR_TRUE, mQuotaETLDplus1DomainDBKey); #endif + + mStorageType = GlobalStorage; + mEventBroadcaster = this; return NS_OK; } @@ -995,6 +1008,9 @@ nsDOMStorage::SetItem(const nsAString& aKey, const nsAString& aData) if (aKey.IsEmpty()) return NS_OK; + nsString oldValue; + SetDOMStringToNull(oldValue); + nsresult rv; nsRefPtr newitem = nsnull; nsSessionStorageEntry *entry = mItems.GetEntry(aKey); @@ -1002,9 +1018,8 @@ nsDOMStorage::SetItem(const nsAString& aKey, const nsAString& aData) if (entry->mItem->IsSecure() && !IsCallerSecure()) { return NS_ERROR_DOM_SECURITY_ERR; } - if (!UseDB()) { - entry->mItem->SetValueInternal(aData); - } + oldValue = entry->mItem->GetValueInternal(); + entry->mItem->SetValueInternal(aData); } else { newitem = new nsDOMStorageItem(this, aKey, aData, IsCallerSecure()); @@ -1023,9 +1038,8 @@ nsDOMStorage::SetItem(const nsAString& aKey, const nsAString& aData) entry->mItem = newitem; } - // SetDBValue already calls BroadcastChangeNotification so don't do it again - if (!UseDB()) - BroadcastChangeNotification(); + if ((oldValue != aData || mStorageType == GlobalStorage) && mEventBroadcaster) + mEventBroadcaster->BroadcastChangeNotification(aKey, oldValue, aData); return NS_OK; } @@ -1038,6 +1052,7 @@ NS_IMETHODIMP nsDOMStorage::RemoveItem(const nsAString& aKey) if (aKey.IsEmpty()) return NS_OK; + nsString oldValue; nsSessionStorageEntry *entry = mItems.GetEntry(aKey); if (entry && entry->mItem->IsSecure() && !IsCallerSecure()) { @@ -1056,26 +1071,31 @@ NS_IMETHODIMP nsDOMStorage::RemoveItem(const nsAString& aKey) return NS_OK; NS_ENSURE_SUCCESS(rv, rv); + oldValue = value; + rv = gStorageDB->RemoveKey(this, aKey, !IsOfflineAllowed(mDomain), aKey.Length() + value.Length()); NS_ENSURE_SUCCESS(rv, rv); mItemsCached = PR_FALSE; - - BroadcastChangeNotification(); #endif } else if (entry) { // clear string as StorageItems may be referencing this item + oldValue = entry->mItem->GetValueInternal(); entry->mItem->ClearValue(); - - BroadcastChangeNotification(); } if (entry) { mItems.RawRemoveEntry(entry); } + if ((!oldValue.IsEmpty() && mStorageType != GlobalStorage) && mEventBroadcaster) { + nsAutoString nullString; + SetDOMStringToNull(nullString); + mEventBroadcaster->BroadcastChangeNotification(aKey, oldValue, nullString); + } + return NS_OK; } @@ -1100,6 +1120,8 @@ nsDOMStorage::Clear() if (UseDB()) CacheKeysFromDB(); + PRInt32 oldCount = mItems.Count(); + PRBool foundSecureItem = PR_FALSE; mItems.EnumerateEntries(CheckSecure, &foundSecureItem); @@ -1118,7 +1140,12 @@ nsDOMStorage::Clear() #endif mItems.Clear(); - BroadcastChangeNotification(); + + if (oldCount && mEventBroadcaster) { + nsAutoString nullString; + SetDOMStringToNull(nullString); + mEventBroadcaster->BroadcastChangeNotification(nullString, nullString, nullString); + } return NS_OK; } @@ -1188,7 +1215,7 @@ nsDOMStorage::GetDBValue(const nsAString& aKey, nsAString& aValue, nsAutoString value; rv = gStorageDB->GetKeyValue(this, aKey, value, aSecure); - if (rv == NS_ERROR_DOM_NOT_FOUND_ERR && mLocalStorage) { + if (rv == NS_ERROR_DOM_NOT_FOUND_ERR && mStorageType != GlobalStorage) { SetDOMStringToNull(aValue); } @@ -1250,7 +1277,6 @@ nsDOMStorage::SetDBValue(const nsAString& aKey, NS_ConvertUTF8toUTF16(mDomain).get()); } - BroadcastChangeNotification(); #endif return NS_OK; @@ -1301,6 +1327,19 @@ nsDOMStorage::Clone() return nsnull; } +already_AddRefed +nsDOMStorage::Fork(const nsSubstring &aDocumentURI) +{ + NS_ASSERTION(PR_FALSE, "Old DOMStorage doesn't implement forking"); + return nsnull; +} + +PRBool nsDOMStorage::IsForkOf(nsIDOMStorage* aThat) +{ + NS_ASSERTION(PR_FALSE, "Old DOMStorage doesn't implement forking"); + return PR_FALSE; +} + struct KeysArrayBuilderStruct { PRBool callerIsSecure; @@ -1371,8 +1410,16 @@ nsDOMStorage::CanAccess(nsIPrincipal *aPrincipal) return domain.Equals(mDomain); } +nsPIDOMStorage::nsDOMStorageType +nsDOMStorage::StorageType() +{ + return mStorageType; +} + void -nsDOMStorage::BroadcastChangeNotification() +nsDOMStorage::BroadcastChangeNotification(const nsSubstring &aKey, + const nsSubstring &aOldValue, + const nsSubstring &aNewValue) { nsresult rv; nsCOMPtr observerService = @@ -1386,7 +1433,7 @@ nsDOMStorage::BroadcastChangeNotification() // domain, but if it's a global storage object we do. observerService->NotifyObservers((nsIDOMStorageObsolete *)this, "dom-storage-changed", - UseDB() ? NS_ConvertUTF8toUTF16(mDomain).get() : nsnull); + NS_ConvertUTF8toUTF16(mDomain).get()); } // @@ -1422,7 +1469,7 @@ nsDOMStorage2::nsDOMStorage2(nsDOMStorage2& aThat) } nsresult -nsDOMStorage2::InitAsSessionStorage(nsIPrincipal *aPrincipal) +nsDOMStorage2::InitAsSessionStorage(nsIPrincipal *aPrincipal, const nsSubstring &aDocumentURI) { mStorage = new nsDOMStorage(); if (!mStorage) @@ -1431,11 +1478,13 @@ nsDOMStorage2::InitAsSessionStorage(nsIPrincipal *aPrincipal) // Leave security checks only for domain (nsDOMStorage implementation) mStorage->mSecurityChecker = mStorage; mPrincipal = aPrincipal; - return mStorage->InitAsSessionStorage(aPrincipal); + mDocumentURI = aDocumentURI; + + return mStorage->InitAsSessionStorage(aPrincipal, aDocumentURI); } nsresult -nsDOMStorage2::InitAsLocalStorage(nsIPrincipal *aPrincipal) +nsDOMStorage2::InitAsLocalStorage(nsIPrincipal *aPrincipal, const nsSubstring &aDocumentURI) { mStorage = new nsDOMStorage(); if (!mStorage) @@ -1443,7 +1492,9 @@ nsDOMStorage2::InitAsLocalStorage(nsIPrincipal *aPrincipal) mStorage->mSecurityChecker = this; mPrincipal = aPrincipal; - return mStorage->InitAsLocalStorage(aPrincipal); + mDocumentURI = aDocumentURI; + + return mStorage->InitAsLocalStorage(aPrincipal, aDocumentURI); } nsresult @@ -1466,6 +1517,41 @@ nsDOMStorage2::Clone() return storage; } +already_AddRefed +nsDOMStorage2::Fork(const nsSubstring &aDocumentURI) +{ + nsRefPtr storage = new nsDOMStorage2(); + if (!storage) + return nsnull; + + nsresult rv = storage->InitAsSessionStorageFork(mPrincipal, aDocumentURI, mStorage); + if (NS_FAILED(rv)) + return nsnull; + + nsIDOMStorage* result = static_cast(storage.get()); + storage.forget(); + return result; +} + +PRBool nsDOMStorage2::IsForkOf(nsIDOMStorage* aThat) +{ + if (!aThat) + return PR_FALSE; + + nsDOMStorage2* storage = static_cast(aThat); + return mStorage == storage->mStorage; +} + +nsresult +nsDOMStorage2::InitAsSessionStorageFork(nsIPrincipal *aPrincipal, const nsSubstring &aDocumentURI, nsIDOMStorageObsolete* aStorage) +{ + mPrincipal = aPrincipal; + mDocumentURI = aDocumentURI; + mStorage = static_cast(aStorage); + + return NS_OK; +} + nsTArray * nsDOMStorage2::GetKeys() { @@ -1497,6 +1583,56 @@ nsDOMStorage2::CanAccess(nsIPrincipal *aPrincipal) return subsumes; } +nsPIDOMStorage::nsDOMStorageType +nsDOMStorage2::StorageType() +{ + if (mStorage) + return mStorage->StorageType(); + + return nsPIDOMStorage::Unknown; +} + +void +nsDOMStorage2::BroadcastChangeNotification(const nsSubstring &aKey, + const nsSubstring &aOldValue, + const nsSubstring &aNewValue) +{ + nsresult rv; + nsCOMPtr event = new nsDOMStorageEvent(); + rv = event->InitStorageEvent(NS_LITERAL_STRING("storage"), + PR_FALSE, + PR_FALSE, + aKey, + aOldValue, + aNewValue, + mDocumentURI, + static_cast(this)); + if (NS_FAILED(rv)) { + return; + } + + nsCOMPtr observerService = + do_GetService("@mozilla.org/observer-service;1", &rv); + if (NS_FAILED(rv)) { + return; + } + + nsCOMPtr observerServiceProxy; + rv = NS_GetProxyForObject(NS_PROXY_TO_MAIN_THREAD, + NS_GET_IID(nsIObserverService), + observerService, + NS_PROXY_ASYNC | NS_PROXY_ALWAYS, + getter_AddRefs(observerServiceProxy)); + if (NS_FAILED(rv)) { + return; + } + + // Fire off a notification that a storage object changed. + observerServiceProxy->NotifyObservers(event, + "dom-storage2-changed", + nsnull); +} + NS_IMETHODIMP nsDOMStorage2::GetLength(PRUint32 *aLength) { @@ -1518,18 +1654,21 @@ nsDOMStorage2::GetItem(const nsAString& aKey, nsAString &aData) NS_IMETHODIMP nsDOMStorage2::SetItem(const nsAString& aKey, const nsAString& aData) { + mStorage->mEventBroadcaster = this; return mStorage->SetItem(aKey, aData); } NS_IMETHODIMP nsDOMStorage2::RemoveItem(const nsAString& aKey) { + mStorage->mEventBroadcaster = this; return mStorage->RemoveItem(aKey); } NS_IMETHODIMP nsDOMStorage2::Clear() { + mStorage->mEventBroadcaster = this; return mStorage->Clear(); } @@ -1842,8 +1981,81 @@ NS_IMPL_ADDREF_INHERITED(nsDOMStorageEvent, nsDOMEvent) NS_IMPL_RELEASE_INHERITED(nsDOMStorageEvent, nsDOMEvent) +/* readonly attribute DOMString key; */ +NS_IMETHODIMP nsDOMStorageEvent::GetKey(nsAString & aKey) +{ + aKey = mKey; + return NS_OK; +} + +/* readonly attribute DOMString oldValue; */ +NS_IMETHODIMP nsDOMStorageEvent::GetOldValue(nsAString & aOldValue) +{ + aOldValue = mOldValue; + return NS_OK; +} + +/* readonly attribute DOMString newValue; */ +NS_IMETHODIMP nsDOMStorageEvent::GetNewValue(nsAString & aNewValue) +{ + aNewValue = mNewValue; + return NS_OK; +} + +/* readonly attribute DOMString url; */ +NS_IMETHODIMP nsDOMStorageEvent::GetUrl(nsAString & aUrl) +{ + aUrl = mUrl; + return NS_OK; +} + +/* readonly attribute nsIDOMStorage storageArea; */ +NS_IMETHODIMP nsDOMStorageEvent::GetStorageArea(nsIDOMStorage * *aStorageArea) +{ + NS_ENSURE_ARG_POINTER(aStorageArea); + + NS_ADDREF(*aStorageArea = mStorageArea); + return NS_OK; +} + +/* void initStorageEvent (in DOMString typeArg, in boolean canBubbleArg, in boolean cancelableArg, in DOMString keyArg, in DOMString oldValueArg, in DOMString newValueArg, in DOMString urlArg, in nsIDOMStorage storageAreaArg); */ +NS_IMETHODIMP nsDOMStorageEvent::InitStorageEvent(const nsAString & typeArg, + PRBool canBubbleArg, + PRBool cancelableArg, + const nsAString & keyArg, + const nsAString & oldValueArg, + const nsAString & newValueArg, + const nsAString & urlArg, + nsIDOMStorage *storageAreaArg) +{ + nsresult rv; + + rv = InitEvent(typeArg, canBubbleArg, cancelableArg); + NS_ENSURE_SUCCESS(rv, rv); + + mKey = keyArg; + mOldValue = oldValueArg; + mNewValue = newValueArg; + mUrl = urlArg; + mStorageArea = storageAreaArg; + + return NS_OK; +} + +// Obsolete globalStorage event + +// QueryInterface implementation for nsDOMStorageEventObsolete +NS_INTERFACE_MAP_BEGIN(nsDOMStorageEventObsolete) + NS_INTERFACE_MAP_ENTRY(nsIDOMStorageEventObsolete) + NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(StorageEventObsolete) +NS_INTERFACE_MAP_END_INHERITING(nsDOMEvent) + +NS_IMPL_ADDREF_INHERITED(nsDOMStorageEventObsolete, nsDOMEvent) +NS_IMPL_RELEASE_INHERITED(nsDOMStorageEventObsolete, nsDOMEvent) + + NS_IMETHODIMP -nsDOMStorageEvent::GetDomain(nsAString& aDomain) +nsDOMStorageEventObsolete::GetDomain(nsAString& aDomain) { // mDomain will be #session for session storage for events that fire // due to a change in a session storage object. @@ -1852,21 +2064,8 @@ nsDOMStorageEvent::GetDomain(nsAString& aDomain) return NS_OK; } -nsresult -nsDOMStorageEvent::Init() -{ - nsresult rv = InitEvent(NS_LITERAL_STRING("storage"), PR_TRUE, PR_FALSE); - NS_ENSURE_SUCCESS(rv, rv); - - // This init method is only called by native code, so set the - // trusted flag here. - SetTrusted(PR_TRUE); - - return NS_OK; -} - NS_IMETHODIMP -nsDOMStorageEvent::InitStorageEvent(const nsAString& aTypeArg, +nsDOMStorageEventObsolete::InitStorageEvent(const nsAString& aTypeArg, PRBool aCanBubbleArg, PRBool aCancelableArg, const nsAString& aDomainArg) diff --git a/dom/src/storage/nsDOMStorage.h b/dom/src/storage/nsDOMStorage.h index 7d3675228ca9..7ff1dae3d48d 100644 --- a/dom/src/storage/nsDOMStorage.h +++ b/dom/src/storage/nsDOMStorage.h @@ -55,6 +55,7 @@ #include "nsIDOMToString.h" #include "nsDOMEvent.h" #include "nsIDOMStorageEvent.h" +#include "nsIDOMStorageEventObsolete.h" #include "nsIDOMStorageManager.h" #include "nsCycleCollectionParticipant.h" @@ -145,13 +146,19 @@ public: nsresult Clear(); // nsPIDOMStorage - virtual nsresult InitAsSessionStorage(nsIPrincipal *aPrincipal); - virtual nsresult InitAsLocalStorage(nsIPrincipal *aPrincipal); + virtual nsresult InitAsSessionStorage(nsIPrincipal *aPrincipal, const nsSubstring &aDocumentURI); + virtual nsresult InitAsLocalStorage(nsIPrincipal *aPrincipal, const nsSubstring &aDocumentURI); virtual nsresult InitAsGlobalStorage(const nsACString &aDomainDemanded); virtual already_AddRefed Clone(); + virtual already_AddRefed Fork(const nsSubstring &aDocumentURI); + virtual PRBool IsForkOf(nsIDOMStorage* aThat); virtual nsTArray *GetKeys(); virtual nsIPrincipal* Principal(); virtual PRBool CanAccess(nsIPrincipal *aPrincipal); + virtual nsDOMStorageType StorageType(); + virtual void BroadcastChangeNotification(const nsSubstring &aKey, + const nsSubstring &aOldValue, + const nsSubstring &aNewValue); // If true, the contents of the storage should be stored in the // database, otherwise this storage should act like a session @@ -218,13 +225,17 @@ protected: // cache the keys from the database for faster lookup nsresult CacheKeysFromDB(); - void BroadcastChangeNotification(); - PRBool CanAccessSystem(nsIPrincipal *aPrincipal); // true if the storage database should be used for values PRPackedBool mUseDB; + // domain this store is associated with + nsCString mDomain; + + // document URI of the document this storage is bound to + nsString mDocumentURI; + // true if the preferences indicates that this storage should be // session only. This member is updated by // CacheStoragePermissions(), using the current principal. @@ -236,14 +247,11 @@ protected: // objects are scoped to scheme/host/port in the database, while globalStorage // objects are scoped just to host. this flag also tells the manager to map // this storage also in mLocalStorages hash table. - PRPackedBool mLocalStorage; + nsDOMStorageType mStorageType; // true if items from the database are cached PRPackedBool mItemsCached; - // domain this store is associated with - nsCString mDomain; - // the key->value item pairs nsTHashtable mItems; @@ -255,6 +263,7 @@ protected: friend class nsIDOMStorage2; nsPIDOMStorage* mSecurityChecker; + nsPIDOMStorage* mEventBroadcaster; public: // e.g. "moc.rab.oof.:" or "moc.rab.oof.:http:80" depending @@ -288,19 +297,34 @@ public: NS_DECL_NSIDOMSTORAGE // nsPIDOMStorage - virtual nsresult InitAsSessionStorage(nsIPrincipal *aPrincipal); - virtual nsresult InitAsLocalStorage(nsIPrincipal *aPrincipal); + virtual nsresult InitAsSessionStorage(nsIPrincipal *aPrincipal, const nsSubstring &aDocumentURI); + virtual nsresult InitAsLocalStorage(nsIPrincipal *aPrincipal, const nsSubstring &aDocumentURI); virtual nsresult InitAsGlobalStorage(const nsACString &aDomainDemanded); virtual already_AddRefed Clone(); + virtual already_AddRefed Fork(const nsSubstring &aDocumentURI); + virtual PRBool IsForkOf(nsIDOMStorage* aThat); virtual nsTArray *GetKeys(); virtual nsIPrincipal* Principal(); virtual PRBool CanAccess(nsIPrincipal *aPrincipal); + virtual nsDOMStorageType StorageType(); + virtual void BroadcastChangeNotification(const nsSubstring &aKey, + const nsSubstring &aOldValue, + const nsSubstring &aNewValue); + + nsresult InitAsSessionStorageFork(nsIPrincipal *aPrincipal, + const nsSubstring &aDocumentURI, + nsIDOMStorageObsolete* aStorage); private: // storages bound to an origin hold the principal to // make security checks against it nsCOMPtr mPrincipal; + // Needed for the storage event, this is address of the document this storage + // is bound to + nsString mDocumentURI; + + friend class nsDOMStorage2; nsRefPtr mStorage; }; @@ -422,15 +446,9 @@ class nsDOMStorageEvent : public nsDOMEvent, public nsIDOMStorageEvent { public: - nsDOMStorageEvent(const nsAString& aDomain) - : nsDOMEvent(nsnull, nsnull), mDomain(aDomain) + nsDOMStorageEvent() + : nsDOMEvent(nsnull, nsnull) { - if (aDomain.IsEmpty()) { - // An empty domain means this event is for a session sotrage - // object change. Store #session as the domain. - - mDomain = NS_LITERAL_STRING("#session"); - } } virtual ~nsDOMStorageEvent() @@ -443,6 +461,31 @@ public: NS_DECL_NSIDOMSTORAGEEVENT NS_FORWARD_NSIDOMEVENT(nsDOMEvent::) +protected: + nsString mKey; + nsString mOldValue; + nsString mNewValue; + nsString mUrl; + nsCOMPtr mStorageArea; +}; + +class nsDOMStorageEventObsolete : public nsDOMEvent, + public nsIDOMStorageEventObsolete +{ +public: + nsDOMStorageEventObsolete() + : nsDOMEvent(nsnull, nsnull) + { + } + + virtual ~nsDOMStorageEventObsolete() + { + } + + NS_DECL_ISUPPORTS + NS_DECL_NSIDOMSTORAGEEVENTOBSOLETE + NS_FORWARD_NSIDOMEVENT(nsDOMEvent::) + protected: nsString mDomain; }; diff --git a/dom/tests/mochitest/Makefile.in b/dom/tests/mochitest/Makefile.in index 9e3d220f6642..881c0fec4174 100644 --- a/dom/tests/mochitest/Makefile.in +++ b/dom/tests/mochitest/Makefile.in @@ -55,6 +55,7 @@ DIRS += \ geolocation \ localstorage \ sessionstorage \ + storageevent \ $(NULL) include $(topsrcdir)/config/rules.mk diff --git a/dom/tests/mochitest/localstorage/test_localStorageFromChrome.xhtml b/dom/tests/mochitest/localstorage/test_localStorageFromChrome.xhtml index 4b52449d1824..ec7b6ab3d965 100644 --- a/dom/tests/mochitest/localstorage/test_localStorageFromChrome.xhtml +++ b/dom/tests/mochitest/localstorage/test_localStorageFromChrome.xhtml @@ -20,7 +20,7 @@ function startTest() var uri = ios.newURI(url, "", null); var principal = ssm.getCodebasePrincipal(uri); - var storage = dsm.getLocalStorageForPrincipal(principal); + var storage = dsm.getLocalStorageForPrincipal(principal, ""); storage.setItem("chromekey", "chromevalue"); diff --git a/dom/tests/mochitest/storageevent/Makefile.in b/dom/tests/mochitest/storageevent/Makefile.in new file mode 100644 index 000000000000..2cd91eff3ab5 --- /dev/null +++ b/dom/tests/mochitest/storageevent/Makefile.in @@ -0,0 +1,71 @@ +# +# ***** 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) 2008 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Jan Bambas +# +# 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/storageevent + +include $(DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/rules.mk + +_TEST_FILES = \ + frameGlobalStorageMaster.html \ + frameGlobalStorageSlaveEqual.html \ + frameGlobalStorageSlaveNotEqual.html \ + frameLocalStorageMaster.html \ + frameLocalStorageSlaveEqual.html \ + frameLocalStorageSlaveNotEqual.html \ + frameSessionStorageMasterEqual.html \ + frameSessionStorageMasterNotEqual.html \ + frameSessionStorageSlaveEqual.html \ + frameSessionStorageSlaveNotEqual.html \ + test_storageGlobalStorageEventCheckNoPropagation.html \ + test_storageGlobalStorageEventCheckPropagation.html \ + test_storageLocalStorageEventCheckNoPropagation.html \ + test_storageLocalStorageEventCheckPropagation.html \ + test_storageSessionStorageEventCheckPropagation.html \ + test_storageSessionStorageEventCheckNoPropagation.html \ + interOriginFrame.js \ + interOriginTest2.js \ + $(NULL) + +libs:: $(_TEST_FILES) + $(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir) diff --git a/dom/tests/mochitest/storageevent/frameGlobalStorageMaster.html b/dom/tests/mochitest/storageevent/frameGlobalStorageMaster.html new file mode 100644 index 000000000000..deac8594c75b --- /dev/null +++ b/dom/tests/mochitest/storageevent/frameGlobalStorageMaster.html @@ -0,0 +1,53 @@ + + +master frame for event storage propagation + + + + + + + + + diff --git a/dom/tests/mochitest/storageevent/frameGlobalStorageSlaveEqual.html b/dom/tests/mochitest/storageevent/frameGlobalStorageSlaveEqual.html new file mode 100644 index 000000000000..9309148f9a99 --- /dev/null +++ b/dom/tests/mochitest/storageevent/frameGlobalStorageSlaveEqual.html @@ -0,0 +1,56 @@ + + +slave for storage event propagation + + + + + + + + + diff --git a/dom/tests/mochitest/storageevent/frameGlobalStorageSlaveNotEqual.html b/dom/tests/mochitest/storageevent/frameGlobalStorageSlaveNotEqual.html new file mode 100644 index 000000000000..219b94ef3b28 --- /dev/null +++ b/dom/tests/mochitest/storageevent/frameGlobalStorageSlaveNotEqual.html @@ -0,0 +1,42 @@ + + +slave for storage event propagation + + + + + + + + + diff --git a/dom/tests/mochitest/storageevent/frameLocalStorageMaster.html b/dom/tests/mochitest/storageevent/frameLocalStorageMaster.html new file mode 100644 index 000000000000..b4f372d6c7f5 --- /dev/null +++ b/dom/tests/mochitest/storageevent/frameLocalStorageMaster.html @@ -0,0 +1,63 @@ + + +master frame for event storage propagation + + + + + + + + + diff --git a/dom/tests/mochitest/storageevent/frameLocalStorageSlaveEqual.html b/dom/tests/mochitest/storageevent/frameLocalStorageSlaveEqual.html new file mode 100644 index 000000000000..3bde58c495dc --- /dev/null +++ b/dom/tests/mochitest/storageevent/frameLocalStorageSlaveEqual.html @@ -0,0 +1,55 @@ + + +slave for storage event propagation + + + + + + + + + diff --git a/dom/tests/mochitest/storageevent/frameLocalStorageSlaveNotEqual.html b/dom/tests/mochitest/storageevent/frameLocalStorageSlaveNotEqual.html new file mode 100644 index 000000000000..ba0e4ff98c76 --- /dev/null +++ b/dom/tests/mochitest/storageevent/frameLocalStorageSlaveNotEqual.html @@ -0,0 +1,39 @@ + + +slave for storage event propagation + + + + + + + + + diff --git a/dom/tests/mochitest/storageevent/frameSessionStorageMasterEqual.html b/dom/tests/mochitest/storageevent/frameSessionStorageMasterEqual.html new file mode 100644 index 000000000000..70e89f7e49a6 --- /dev/null +++ b/dom/tests/mochitest/storageevent/frameSessionStorageMasterEqual.html @@ -0,0 +1,67 @@ + + +master frame for event storage propagation + + + + + + + + + + diff --git a/dom/tests/mochitest/storageevent/frameSessionStorageMasterNotEqual.html b/dom/tests/mochitest/storageevent/frameSessionStorageMasterNotEqual.html new file mode 100644 index 000000000000..a101b88583ca --- /dev/null +++ b/dom/tests/mochitest/storageevent/frameSessionStorageMasterNotEqual.html @@ -0,0 +1,66 @@ + + +master frame for event storage propagation + + + + + + + + + + diff --git a/dom/tests/mochitest/storageevent/frameSessionStorageSlaveEqual.html b/dom/tests/mochitest/storageevent/frameSessionStorageSlaveEqual.html new file mode 100644 index 000000000000..287cb22f66ef --- /dev/null +++ b/dom/tests/mochitest/storageevent/frameSessionStorageSlaveEqual.html @@ -0,0 +1,59 @@ + + +slave for storage event propagation + + + + + + + + + diff --git a/dom/tests/mochitest/storageevent/frameSessionStorageSlaveNotEqual.html b/dom/tests/mochitest/storageevent/frameSessionStorageSlaveNotEqual.html new file mode 100644 index 000000000000..ba0e4ff98c76 --- /dev/null +++ b/dom/tests/mochitest/storageevent/frameSessionStorageSlaveNotEqual.html @@ -0,0 +1,39 @@ + + +slave for storage event propagation + + + + + + + + + diff --git a/dom/tests/mochitest/storageevent/interOriginFrame.js b/dom/tests/mochitest/storageevent/interOriginFrame.js new file mode 100644 index 000000000000..d3ff1bd00b3f --- /dev/null +++ b/dom/tests/mochitest/storageevent/interOriginFrame.js @@ -0,0 +1,57 @@ +function postMsg(message) +{ + netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead"); + var l = parent.window.location; + parent.postMessage(message, l.protocol + "//" + l.host); +} + +window.addEventListener("message", onMessageReceived, false); + +function onMessageReceived(event) +{ + if (event.data == "step") { + var performed = false; + try { + performed = doStep(); + } + catch (ex) { + postMsg("FAILURE: exception threw at "+ location +":\n" + ex); + finishTest(); + } + + if (performed) + postMsg("perf"); + + return; + } + + if (parent) + postMsg(event.data); +} + +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 todo(a, b, message) +{ + postMsg("TODO: " + message + ", expected "+b+" got "+a); +} + +function finishTest() +{ + postMsg("done"); + return false; +} diff --git a/dom/tests/mochitest/storageevent/interOriginTest2.js b/dom/tests/mochitest/storageevent/interOriginTest2.js new file mode 100644 index 000000000000..014d9c4d814f --- /dev/null +++ b/dom/tests/mochitest/storageevent/interOriginTest2.js @@ -0,0 +1,58 @@ +var frameLoadsPending = 2; + +var callMasterFrame = true; +var testDone = false; + +var masterFrameOrigin = ""; +var slaveFrameOrigin = ""; + +var failureRegExp = new RegExp("^FAILURE"); +var todoRegExp = new RegExp("^TODO"); + +const framePath = "/tests/dom/tests/mochitest/storageevent/"; + +window.addEventListener("message", onMessageReceived, false); + +function onMessageReceived(event) +{ + netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); + netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead"); + + switch (event.data) + { + // Indication of the frame onload event + case "frame loaded": + if (--frameLoadsPending) + break; + + // Just fall through... + + // Indication of successfully finished step of a test + case "perf": + if (callMasterFrame) + masterFrame.postMessage("step", masterFrameOrigin); + else if (slaveFrame) + slaveFrame.postMessage("step", slaveFrameOrigin); + else if (masterFrame.slaveFrame) + masterFrame.slaveFrame.postMessage("step", slaveFrameOrigin); + callMasterFrame = !callMasterFrame; + break; + + // Indication of all test parts finish (from any of the frames) + case "done": + if (testDone) + break; + + testDone = true; + SimpleTest.finish(); + break; + + // Any other message indicates error, succes or todo message of a test + default: + if (event.data.match(todoRegExp)) + SimpleTest.todo(false, event.data); + else + SimpleTest.ok(!event.data.match(failureRegExp), event.data); + break; + } +} diff --git a/dom/tests/mochitest/storageevent/test_storageGlobalStorageEventCheckNoPropagation.html b/dom/tests/mochitest/storageevent/test_storageGlobalStorageEventCheckNoPropagation.html new file mode 100644 index 000000000000..f87277017d3e --- /dev/null +++ b/dom/tests/mochitest/storageevent/test_storageGlobalStorageEventCheckNoPropagation.html @@ -0,0 +1,44 @@ + + +storage event propagation test + + + + + + + + + + + + + + + + + diff --git a/dom/tests/mochitest/storageevent/test_storageGlobalStorageEventCheckPropagation.html b/dom/tests/mochitest/storageevent/test_storageGlobalStorageEventCheckPropagation.html new file mode 100644 index 000000000000..542fd5b6249d --- /dev/null +++ b/dom/tests/mochitest/storageevent/test_storageGlobalStorageEventCheckPropagation.html @@ -0,0 +1,44 @@ + + +storage event propagation test + + + + + + + + + + + + + + + + + diff --git a/dom/tests/mochitest/storageevent/test_storageLocalStorageEventCheckNoPropagation.html b/dom/tests/mochitest/storageevent/test_storageLocalStorageEventCheckNoPropagation.html new file mode 100644 index 000000000000..57b7bdfd7eb3 --- /dev/null +++ b/dom/tests/mochitest/storageevent/test_storageLocalStorageEventCheckNoPropagation.html @@ -0,0 +1,44 @@ + + +storage event propagation test + + + + + + + + + + + + + + + + + diff --git a/dom/tests/mochitest/storageevent/test_storageLocalStorageEventCheckPropagation.html b/dom/tests/mochitest/storageevent/test_storageLocalStorageEventCheckPropagation.html new file mode 100644 index 000000000000..e1bb26d5720b --- /dev/null +++ b/dom/tests/mochitest/storageevent/test_storageLocalStorageEventCheckPropagation.html @@ -0,0 +1,44 @@ + + +storage event propagation test + + + + + + + + + + + + + + + + + diff --git a/dom/tests/mochitest/storageevent/test_storageSessionStorageEventCheckNoPropagation.html b/dom/tests/mochitest/storageevent/test_storageSessionStorageEventCheckNoPropagation.html new file mode 100644 index 000000000000..ecc496bc908d --- /dev/null +++ b/dom/tests/mochitest/storageevent/test_storageSessionStorageEventCheckNoPropagation.html @@ -0,0 +1,44 @@ + + +storage event propagation test + + + + + + + + + + + + + + + + diff --git a/dom/tests/mochitest/storageevent/test_storageSessionStorageEventCheckPropagation.html b/dom/tests/mochitest/storageevent/test_storageSessionStorageEventCheckPropagation.html new file mode 100644 index 000000000000..48343b9b573d --- /dev/null +++ b/dom/tests/mochitest/storageevent/test_storageSessionStorageEventCheckPropagation.html @@ -0,0 +1,44 @@ + + +storage event propagation test + + + + + + + + + + + + + + + + diff --git a/embedding/components/windowwatcher/src/nsWindowWatcher.cpp b/embedding/components/windowwatcher/src/nsWindowWatcher.cpp index 6ea021be037f..f7d889f07e97 100644 --- a/embedding/components/windowwatcher/src/nsWindowWatcher.cpp +++ b/embedding/components/windowwatcher/src/nsWindowWatcher.cpp @@ -950,7 +950,8 @@ nsWindowWatcher::OpenWindowJSInternal(nsIDOMWindow *aParent, if (subjectPrincipal && parentDocShell) { nsCOMPtr storage; - parentDocShell->GetSessionStorageForPrincipal(subjectPrincipal, PR_FALSE, + parentDocShell->GetSessionStorageForPrincipal(subjectPrincipal, + EmptyString(), PR_FALSE, getter_AddRefs(storage)); nsCOMPtr piStorage = do_QueryInterface(storage);