Bug 501423 - StorageEvent implementation does not match the spec, r=jst
This commit is contained in:
Родитель
740d3d8e2f
Коммит
450d622843
|
@ -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]);
|
||||
|
|
|
@ -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<nsDocShell*>(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<nsPIDOMStorage> 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,57 @@ 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<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) {
|
||||
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
|
||||
}
|
||||
|
||||
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) {
|
||||
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<nsPIDOMStorage> piStorage = do_QueryInterface(*aStorage);
|
||||
nsCOMPtr<nsIDOMStorage> 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 +2255,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 +2284,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 +2316,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;
|
||||
}
|
||||
|
|
|
@ -605,6 +605,7 @@ protected:
|
|||
void ReattachEditorToWindow(nsISHEntry *aSHEntry);
|
||||
|
||||
nsresult GetSessionStorageForURI(nsIURI* aURI,
|
||||
const nsSubstring& aDocumentURI,
|
||||
PRBool create,
|
||||
nsIDOMStorage** aStorage);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
/*
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -383,6 +383,7 @@ enum nsDOMClassInfoID {
|
|||
eDOMClassInfo_StorageList_id,
|
||||
eDOMClassInfo_StorageItem_id,
|
||||
eDOMClassInfo_StorageEvent_id,
|
||||
eDOMClassInfo_StorageEventObsolete_id,
|
||||
|
||||
// DOMParser, XMLSerializer
|
||||
eDOMClassInfo_DOMParser_id,
|
||||
|
|
|
@ -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<nsIScriptGlobalObject*>(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<nsPIDOMStorage> 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<nsIDOM3Document> 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<nsIDOM3Document> 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<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;
|
||||
}
|
||||
}
|
||||
} 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<nsStringHashKey, PRBool>;
|
||||
NS_ENSURE_TRUE(mPendingStorageEvents, NS_ERROR_OUT_OF_MEMORY);
|
||||
if (!mPendingStorageEventsObsolete) {
|
||||
mPendingStorageEventsObsolete = new nsDataHashtable<nsStringHashKey, PRBool>;
|
||||
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<nsDOMStorageEvent> event = new nsDOMStorageEvent(domain);
|
||||
nsRefPtr<nsDOMStorageEventObsolete> 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<nsIDOMHTMLDocument> 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<nsIDOMStorageEvent> event = do_QueryInterface(aSubject, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIDOMStorage> changingStorage;
|
||||
rv = event->GetStorageArea(getter_AddRefs(changingStorage));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsPIDOMStorage> 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<nsIDOMStorage> 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) {
|
||||
|
|
|
@ -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<nsIDOMCrypto> mCrypto;
|
||||
|
||||
nsCOMPtr<nsIDOMStorage> mLocalStorage;
|
||||
nsCOMPtr<nsIDOMStorage> mSessionStorage;
|
||||
|
||||
nsCOMPtr<nsISupports> mInnerWindowHolders[NS_STID_ARRAY_UBOUND];
|
||||
nsCOMPtr<nsIPrincipal> mOpenerScriptPrincipal; // strong; used to determine
|
||||
|
@ -750,7 +752,6 @@ protected:
|
|||
nsTimeout* mTimeoutInsertionPoint;
|
||||
PRUint32 mTimeoutPublicIdCounter;
|
||||
PRUint32 mTimeoutFiringDepth;
|
||||
nsCOMPtr<nsIDOMStorageObsolete> mSessionStorage;
|
||||
|
||||
// Holder of the dummy java plugin, used to expose window.java and
|
||||
// window.packages.
|
||||
|
@ -761,7 +762,9 @@ protected:
|
|||
nsCOMPtr<nsIDocument> mDoc; // For fast access to principals
|
||||
JSObject* mJSObject;
|
||||
|
||||
nsDataHashtable<nsStringHashKey, PRBool> *mPendingStorageEvents;
|
||||
typedef nsTArray<nsCOMPtr<nsIDOMStorageEvent> > nsDOMStorageEventArray;
|
||||
nsDOMStorageEventArray mPendingStorageEvents;
|
||||
nsDataHashtable<nsStringHashKey, PRBool> *mPendingStorageEventsObsolete;
|
||||
|
||||
PRUint32 mTimeoutsSuspendDepth;
|
||||
|
||||
|
|
|
@ -59,6 +59,7 @@ SDK_XPIDLSRCS = \
|
|||
nsIDOMStorage.idl \
|
||||
nsIDOMStorageObsolete.idl\
|
||||
nsIDOMStorageEvent.idl \
|
||||
nsIDOMStorageEventObsolete.idl \
|
||||
nsIDOMStorageItem.idl \
|
||||
nsIDOMStorageList.idl \
|
||||
nsIDOMStorageWindow.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);
|
||||
};
|
||||
|
|
|
@ -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 <enndeakin@sympatico.ca>
|
||||
* 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);
|
||||
};
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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<nsIDOMStorage> Clone() = 0;
|
||||
virtual already_AddRefed<nsIDOMStorage> Fork(const nsSubstring &aDocumentURI) = 0;
|
||||
virtual PRBool IsForkOf(nsIDOMStorage* aThat) = 0;
|
||||
|
||||
virtual nsTArray<nsString> *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)
|
||||
|
|
|
@ -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<nsIURI> 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<nsIURI> 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<nsDOMStorageItem> 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<nsIDOMStorage>
|
||||
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<nsIObserverService> 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<nsIDOMStorage>
|
||||
nsDOMStorage2::Fork(const nsSubstring &aDocumentURI)
|
||||
{
|
||||
nsRefPtr<nsDOMStorage2> storage = new nsDOMStorage2();
|
||||
if (!storage)
|
||||
return nsnull;
|
||||
|
||||
nsresult rv = storage->InitAsSessionStorageFork(mPrincipal, aDocumentURI, mStorage);
|
||||
if (NS_FAILED(rv))
|
||||
return nsnull;
|
||||
|
||||
nsIDOMStorage* result = static_cast<nsIDOMStorage*>(storage.get());
|
||||
storage.forget();
|
||||
return result;
|
||||
}
|
||||
|
||||
PRBool nsDOMStorage2::IsForkOf(nsIDOMStorage* aThat)
|
||||
{
|
||||
if (!aThat)
|
||||
return PR_FALSE;
|
||||
|
||||
nsDOMStorage2* storage = static_cast<nsDOMStorage2*>(aThat);
|
||||
return mStorage == storage->mStorage;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDOMStorage2::InitAsSessionStorageFork(nsIPrincipal *aPrincipal, const nsSubstring &aDocumentURI, nsIDOMStorageObsolete* aStorage)
|
||||
{
|
||||
mPrincipal = aPrincipal;
|
||||
mDocumentURI = aDocumentURI;
|
||||
mStorage = static_cast<nsDOMStorage*>(aStorage);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsTArray<nsString> *
|
||||
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<nsIDOMStorageEvent> event = new nsDOMStorageEvent();
|
||||
rv = event->InitStorageEvent(NS_LITERAL_STRING("storage"),
|
||||
PR_FALSE,
|
||||
PR_FALSE,
|
||||
aKey,
|
||||
aOldValue,
|
||||
aNewValue,
|
||||
mDocumentURI,
|
||||
static_cast<nsIDOMStorage*>(this));
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIObserverService> observerService =
|
||||
do_GetService("@mozilla.org/observer-service;1", &rv);
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIObserverService> 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)
|
||||
|
|
|
@ -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<nsIDOMStorage> Clone();
|
||||
virtual already_AddRefed<nsIDOMStorage> Fork(const nsSubstring &aDocumentURI);
|
||||
virtual PRBool IsForkOf(nsIDOMStorage* aThat);
|
||||
virtual nsTArray<nsString> *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<nsSessionStorageEntry> 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,32 @@ 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<nsIDOMStorage> Clone();
|
||||
virtual already_AddRefed<nsIDOMStorage> Fork(const nsSubstring &aDocumentURI);
|
||||
virtual PRBool IsForkOf(nsIDOMStorage* aThat);
|
||||
virtual nsTArray<nsString> *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<nsIPrincipal> mPrincipal;
|
||||
|
||||
// Needed for the storage event, this is address of the document this storage
|
||||
// is bound to
|
||||
nsString mDocumentURI;
|
||||
nsRefPtr<nsDOMStorage> mStorage;
|
||||
};
|
||||
|
||||
|
@ -422,15 +444,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 +459,31 @@ public:
|
|||
NS_DECL_NSIDOMSTORAGEEVENT
|
||||
NS_FORWARD_NSIDOMEVENT(nsDOMEvent::)
|
||||
|
||||
protected:
|
||||
nsString mKey;
|
||||
nsString mOldValue;
|
||||
nsString mNewValue;
|
||||
nsString mUrl;
|
||||
nsCOMPtr<nsIDOMStorage> 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;
|
||||
};
|
||||
|
|
|
@ -55,6 +55,7 @@ DIRS += \
|
|||
geolocation \
|
||||
localstorage \
|
||||
sessionstorage \
|
||||
storageevent \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
|
|
@ -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");
|
||||
|
||||
|
|
|
@ -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 <honzab@firemni.cz>
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
# of those above. If you wish to allow use of your version of this file only
|
||||
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
# use your version of this file under the terms of the MPL, indicate your
|
||||
# decision by deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this file under
|
||||
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
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)
|
|
@ -0,0 +1,53 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>master frame for event storage propagation</title>
|
||||
|
||||
<script type="text/javascript" src="interOriginFrame.js"></script>
|
||||
<script type="text/javascript">
|
||||
|
||||
var currentStep = 1;
|
||||
var gotEvent = false;
|
||||
|
||||
function bind()
|
||||
{
|
||||
document.body.addEventListener("storage", function(event)
|
||||
{
|
||||
gotEvent = true;
|
||||
}, false);
|
||||
}
|
||||
|
||||
function doStep()
|
||||
{
|
||||
switch (currentStep)
|
||||
{
|
||||
case 1:
|
||||
var storage = globalStorage[location.host];
|
||||
storage.setItem("X", "1");
|
||||
storage.setItem("X", "2");
|
||||
storage.setItem("X", "2");
|
||||
storage.removeItem("X");
|
||||
storage.removeItem("X");
|
||||
storage.removeItem("Y");
|
||||
storage.setItem("X", "2");
|
||||
break;
|
||||
|
||||
case 3:
|
||||
todo(gotEvent, false, "Expected no events");
|
||||
return finishTest();
|
||||
}
|
||||
|
||||
// Increase by two to distinguish each test step order
|
||||
// in both master doStep and slave doStep functions.
|
||||
++currentStep;
|
||||
++currentStep;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="bind(); postMsg('frame loaded');">
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,56 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>slave for storage event propagation</title>
|
||||
|
||||
<script type="text/javascript" src="interOriginFrame.js"></script>
|
||||
<script type="text/javascript">
|
||||
|
||||
var currentStep = 2;
|
||||
|
||||
var events = [];
|
||||
|
||||
function bind()
|
||||
{
|
||||
document.body.addEventListener("storage", function(event)
|
||||
{
|
||||
events.push(event);
|
||||
}, false);
|
||||
}
|
||||
|
||||
function doStep()
|
||||
{
|
||||
function checkEvent()
|
||||
{
|
||||
var event = events.shift();
|
||||
ok(event);
|
||||
if (!event)
|
||||
return;
|
||||
is(event.domain, "example.com");
|
||||
}
|
||||
|
||||
switch (currentStep)
|
||||
{
|
||||
case 2:
|
||||
is(events.length, 4, "Expected 5 events");
|
||||
checkEvent();
|
||||
checkEvent();
|
||||
checkEvent();
|
||||
checkEvent();
|
||||
break;
|
||||
}
|
||||
|
||||
// Increase by two to distinguish each test step order
|
||||
// in both master doStep and slave doStep functions.
|
||||
++currentStep;
|
||||
++currentStep;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="bind(); postMsg('frame loaded');">
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,42 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>slave for storage event propagation</title>
|
||||
|
||||
<script type="text/javascript" src="interOriginFrame.js"></script>
|
||||
<script type="text/javascript">
|
||||
|
||||
var currentStep = 2;
|
||||
var gotEvent = false;
|
||||
|
||||
function bind()
|
||||
{
|
||||
document.body.addEventListener("storage", function(event)
|
||||
{
|
||||
gotEvent = true;
|
||||
}, false);
|
||||
}
|
||||
|
||||
function doStep()
|
||||
{
|
||||
switch (currentStep)
|
||||
{
|
||||
case 2:
|
||||
is(gotEvent, false, "Expected no events");
|
||||
break;
|
||||
}
|
||||
|
||||
// Increase by two to distinguish each test step order
|
||||
// in both master doStep and slave doStep functions.
|
||||
++currentStep;
|
||||
++currentStep;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="bind(); postMsg('frame loaded');">
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,63 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>master frame for event storage propagation</title>
|
||||
|
||||
<script type="text/javascript" src="interOriginFrame.js"></script>
|
||||
<script type="text/javascript">
|
||||
|
||||
var currentStep = 1;
|
||||
var gotEvent = false;
|
||||
|
||||
window.addEventListener("storage", function(event)
|
||||
{
|
||||
gotEvent = true;
|
||||
}, false);
|
||||
|
||||
function doStep()
|
||||
{
|
||||
switch (currentStep)
|
||||
{
|
||||
case 1:
|
||||
// Must not fire (storage must be clear!)
|
||||
localStorage.clear();
|
||||
// Must fire X:null->'1'
|
||||
localStorage.setItem("X", "1");
|
||||
// Must fire X:'1'->'2'
|
||||
localStorage.setItem("X", "2");
|
||||
// Must not fire
|
||||
localStorage.setItem("X", "2");
|
||||
// Must fire X:'2'->null
|
||||
localStorage.removeItem("X");
|
||||
// Must not fire
|
||||
localStorage.removeItem("X");
|
||||
// Must not fire
|
||||
localStorage.removeItem("Y");
|
||||
// Must fire X:null->'2' (we need something in the storage)
|
||||
localStorage.setItem("X", "2");
|
||||
// Must fire null:null->null (one item has been erased)
|
||||
localStorage.clear();
|
||||
// Must not fire
|
||||
localStorage.clear();
|
||||
break;
|
||||
|
||||
// Wait some time to let the async event be propagated
|
||||
case 11:
|
||||
is(gotEvent, false, "Expected no events");
|
||||
return finishTest();
|
||||
}
|
||||
|
||||
// Increase by two to distinguish each test step order
|
||||
// in both master doStep and slave doStep functions.
|
||||
++currentStep;
|
||||
++currentStep;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="postMsg('frame loaded');">
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,55 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>slave for storage event propagation</title>
|
||||
|
||||
<script type="text/javascript" src="interOriginFrame.js"></script>
|
||||
<script type="text/javascript">
|
||||
|
||||
var currentStep = 2;
|
||||
|
||||
var events = [];
|
||||
|
||||
window.addEventListener("storage", function(event)
|
||||
{
|
||||
events.push(event);
|
||||
}, false);
|
||||
|
||||
function doStep()
|
||||
{
|
||||
function checkEvent(expectedKey, expectedOldValue, expectedNewValue)
|
||||
{
|
||||
var event = events.shift();
|
||||
is(event.key, expectedKey, "key name check");
|
||||
is(event.oldValue, expectedOldValue, "old value check");
|
||||
is(event.newValue, expectedNewValue, "new value check");
|
||||
is(event.url, "http://example.com/tests/dom/tests/mochitest/storageevent/frameLocalStorageMaster.html");
|
||||
ok(event.storageArea);
|
||||
}
|
||||
|
||||
switch (currentStep)
|
||||
{
|
||||
case 10:
|
||||
is(events.length, 5, "Expected 5 events");
|
||||
checkEvent("X", null, "1");
|
||||
checkEvent("X", "1", "2");
|
||||
checkEvent("X", "2", null);
|
||||
checkEvent("X", null, "2");
|
||||
checkEvent(null, null, null);
|
||||
break;
|
||||
}
|
||||
|
||||
// Increase by two to distinguish each test step order
|
||||
// in both master doStep and slave doStep functions.
|
||||
++currentStep;
|
||||
++currentStep;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="postMsg('frame loaded');">
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,39 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>slave for storage event propagation</title>
|
||||
|
||||
<script type="text/javascript" src="interOriginFrame.js"></script>
|
||||
<script type="text/javascript">
|
||||
|
||||
var currentStep = 2;
|
||||
var gotEvent = false;
|
||||
|
||||
window.addEventListener("storage", function(event)
|
||||
{
|
||||
gotEvent = true;
|
||||
}, false);
|
||||
|
||||
function doStep()
|
||||
{
|
||||
switch (currentStep)
|
||||
{
|
||||
case 10:
|
||||
is(gotEvent, false, "Expected no events");
|
||||
break;
|
||||
}
|
||||
|
||||
// Increase by two to distinguish each test step order
|
||||
// in both master doStep and slave doStep functions.
|
||||
++currentStep;
|
||||
++currentStep;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="postMsg('frame loaded');">
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,67 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>master frame for event storage propagation</title>
|
||||
|
||||
<script type="text/javascript" src="interOriginFrame.js"></script>
|
||||
<script type="text/javascript">
|
||||
|
||||
var currentStep = 1;
|
||||
var gotEvent = false;
|
||||
|
||||
window.addEventListener("storage", function(event)
|
||||
{
|
||||
gotEvent = true;
|
||||
}, false);
|
||||
|
||||
function doStep()
|
||||
{
|
||||
switch (currentStep)
|
||||
{
|
||||
// In step 2 we instantiate sessionStorage in the other frame
|
||||
case 1:
|
||||
// Must not fire (storage must be clear!)
|
||||
sessionStorage.clear();
|
||||
// Must fire X:null->'1'
|
||||
sessionStorage.setItem("X", "1");
|
||||
// Must fire X:'1'->'2'
|
||||
sessionStorage.setItem("X", "2");
|
||||
// Must not fire
|
||||
sessionStorage.setItem("X", "2");
|
||||
// Must fire X:'2'->null
|
||||
sessionStorage.removeItem("X");
|
||||
// Must not fire
|
||||
sessionStorage.removeItem("X");
|
||||
// Must not fire
|
||||
sessionStorage.removeItem("Y");
|
||||
// Must fire X:null->'2' (we need something in the storage)
|
||||
sessionStorage.setItem("X", "2");
|
||||
// Must fire null:null->null (one item has been erased)
|
||||
sessionStorage.clear();
|
||||
// Must not fire
|
||||
sessionStorage.clear();
|
||||
break;
|
||||
|
||||
// Wait some time to let the async event be propagated
|
||||
case 11:
|
||||
is(gotEvent, false, "Expected no events");
|
||||
return finishTest();
|
||||
}
|
||||
|
||||
// Increase by two to distinguish each test step order
|
||||
// in both master doStep and slave doStep functions.
|
||||
++currentStep;
|
||||
++currentStep;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="postMsg('frame loaded');">
|
||||
<iframe src="http://example.com:80/tests/dom/tests/mochitest/storageevent/frameSessionStorageSlaveEqual.html"
|
||||
name="slaveFrame">
|
||||
</iframe>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,66 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>master frame for event storage propagation</title>
|
||||
|
||||
<script type="text/javascript" src="interOriginFrame.js"></script>
|
||||
<script type="text/javascript">
|
||||
|
||||
var currentStep = 1;
|
||||
var gotEvent = false;
|
||||
|
||||
window.addEventListener("storage", function(event)
|
||||
{
|
||||
gotEvent = true;
|
||||
}, false);
|
||||
|
||||
function doStep()
|
||||
{
|
||||
switch (currentStep)
|
||||
{
|
||||
case 1:
|
||||
// Must not fire (storage must be clear!)
|
||||
sessionStorage.clear();
|
||||
// Must fire X:null->'1'
|
||||
sessionStorage.setItem("X", "1");
|
||||
// Must fire X:'1'->'2'
|
||||
sessionStorage.setItem("X", "2");
|
||||
// Must not fire
|
||||
sessionStorage.setItem("X", "2");
|
||||
// Must fire X:'2'->null
|
||||
sessionStorage.removeItem("X");
|
||||
// Must not fire
|
||||
sessionStorage.removeItem("X");
|
||||
// Must not fire
|
||||
sessionStorage.removeItem("Y");
|
||||
// Must fire X:null->'2' (we need something in the storage)
|
||||
sessionStorage.setItem("X", "2");
|
||||
// Must fire null:null->null (one item has been erased)
|
||||
sessionStorage.clear();
|
||||
// Must not fire
|
||||
sessionStorage.clear();
|
||||
break;
|
||||
|
||||
// Wait some time to let the async event be propagated
|
||||
case 11:
|
||||
is(gotEvent, false, "Expected no events");
|
||||
return finishTest();
|
||||
}
|
||||
|
||||
// Increase by two to distinguish each test step order
|
||||
// in both master doStep and slave doStep functions.
|
||||
++currentStep;
|
||||
++currentStep;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="postMsg('frame loaded');">
|
||||
<iframe src="http://example.com:80/tests/dom/tests/mochitest/storageevent/frameSessionStorageSlaveNotEqual.html"
|
||||
name="slaveFrame">
|
||||
</iframe>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,59 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>slave for storage event propagation</title>
|
||||
|
||||
<script type="text/javascript" src="interOriginFrame.js"></script>
|
||||
<script type="text/javascript">
|
||||
|
||||
var currentStep = 2;
|
||||
|
||||
var events = [];
|
||||
|
||||
window.addEventListener("storage", function(event)
|
||||
{
|
||||
events.push(event);
|
||||
}, false);
|
||||
|
||||
function doStep()
|
||||
{
|
||||
function checkEvent(expectedKey, expectedOldValue, expectedNewValue)
|
||||
{
|
||||
var event = events.shift();
|
||||
ok(event, "Event is present");
|
||||
if (!event)
|
||||
return;
|
||||
|
||||
is(event.key, expectedKey, "key name check");
|
||||
is(event.oldValue, expectedOldValue, "old value check");
|
||||
is(event.newValue, expectedNewValue, "new value check");
|
||||
is(event.url, "http://example.com/tests/dom/tests/mochitest/storageevent/frameSessionStorageMasterEqual.html");
|
||||
ok(event.storageArea);
|
||||
}
|
||||
|
||||
switch (currentStep)
|
||||
{
|
||||
case 10:
|
||||
is(events.length, 5, "Expected 5 events");
|
||||
checkEvent("X", null, "1");
|
||||
checkEvent("X", "1", "2");
|
||||
checkEvent("X", "2", null);
|
||||
checkEvent("X", null, "2");
|
||||
checkEvent(null, null, null);
|
||||
break;
|
||||
}
|
||||
|
||||
// Increase by two to distinguish each test step order
|
||||
// in both master doStep and slave doStep functions.
|
||||
++currentStep;
|
||||
++currentStep;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="postMsg('frame loaded');">
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,39 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>slave for storage event propagation</title>
|
||||
|
||||
<script type="text/javascript" src="interOriginFrame.js"></script>
|
||||
<script type="text/javascript">
|
||||
|
||||
var currentStep = 2;
|
||||
var gotEvent = false;
|
||||
|
||||
window.addEventListener("storage", function(event)
|
||||
{
|
||||
gotEvent = true;
|
||||
}, false);
|
||||
|
||||
function doStep()
|
||||
{
|
||||
switch (currentStep)
|
||||
{
|
||||
case 10:
|
||||
is(gotEvent, false, "Expected no events");
|
||||
break;
|
||||
}
|
||||
|
||||
// Increase by two to distinguish each test step order
|
||||
// in both master doStep and slave doStep functions.
|
||||
++currentStep;
|
||||
++currentStep;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="postMsg('frame loaded');">
|
||||
</body>
|
||||
</html>
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>storage event propagation test</title>
|
||||
|
||||
<script type="text/javascript" src="/MochiKit/packed.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="interOriginTest2.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
|
||||
<!--
|
||||
This test loads two frames from different
|
||||
origins and checks that entries of localStorage
|
||||
objects don't leak each between other.
|
||||
|
||||
The subsystem is based on postMessage and addEventListener
|
||||
to send messages among different origins. The subsystem waits
|
||||
for both frames be loaded and then alternately calls each frames'
|
||||
doStep() function that on each call proceeds with a single step
|
||||
of the test on its side. This way the subsystem alternate between
|
||||
both frames until both sequences completely finish.
|
||||
-->
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
function startTest()
|
||||
{
|
||||
masterFrameOrigin = "http://example.com:80";
|
||||
slaveFrameOrigin = "http://example.org:80";
|
||||
|
||||
masterFrame.location = masterFrameOrigin + framePath + "frameGlobalStorageMaster.html";
|
||||
slaveFrame.location = slaveFrameOrigin + framePath + "frameGlobalStorageSlaveNotEqual.html";
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="startTest();">
|
||||
<iframe src="" name="masterFrame"></iframe>
|
||||
<iframe src="" name="slaveFrame"></iframe>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,44 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>storage event propagation test</title>
|
||||
|
||||
<script type="text/javascript" src="/MochiKit/packed.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="interOriginTest2.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
|
||||
<!--
|
||||
This test loads two frames from different
|
||||
origins and checks that entries of localStorage
|
||||
objects don't leak each between other.
|
||||
|
||||
The subsystem is based on postMessage and addEventListener
|
||||
to send messages among different origins. The subsystem waits
|
||||
for both frames be loaded and then alternately calls each frames'
|
||||
doStep() function that on each call proceeds with a single step
|
||||
of the test on its side. This way the subsystem alternate between
|
||||
both frames until both sequences completely finish.
|
||||
-->
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
function startTest()
|
||||
{
|
||||
masterFrameOrigin = "http://example.com:80";
|
||||
slaveFrameOrigin = "http://example.com:80";
|
||||
|
||||
masterFrame.location = masterFrameOrigin + framePath + "frameGlobalStorageMaster.html";
|
||||
slaveFrame.location = slaveFrameOrigin + framePath + "frameGlobalStorageSlaveEqual.html";
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="startTest();">
|
||||
<iframe src="" name="masterFrame"></iframe>
|
||||
<iframe src="" name="slaveFrame"></iframe>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,44 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>storage event propagation test</title>
|
||||
|
||||
<script type="text/javascript" src="/MochiKit/packed.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="interOriginTest2.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
|
||||
<!--
|
||||
This test loads two frames from different
|
||||
origins and checks that entries of localStorage
|
||||
objects don't leak each between other.
|
||||
|
||||
The subsystem is based on postMessage and addEventListener
|
||||
to send messages among different origins. The subsystem waits
|
||||
for both frames be loaded and then alternately calls each frames'
|
||||
doStep() function that on each call proceeds with a single step
|
||||
of the test on its side. This way the subsystem alternate between
|
||||
both frames until both sequences completely finish.
|
||||
-->
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
function startTest()
|
||||
{
|
||||
masterFrameOrigin = "http://example.com:80";
|
||||
slaveFrameOrigin = "http://example.org:80";
|
||||
|
||||
masterFrame.location = masterFrameOrigin + framePath + "frameLocalStorageMaster.html";
|
||||
slaveFrame.location = slaveFrameOrigin + framePath + "frameLocalStorageSlaveNotEqual.html";
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="startTest();">
|
||||
<iframe src="" name="masterFrame"></iframe>
|
||||
<iframe src="" name="slaveFrame"></iframe>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,44 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>storage event propagation test</title>
|
||||
|
||||
<script type="text/javascript" src="/MochiKit/packed.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="interOriginTest2.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
|
||||
<!--
|
||||
This test loads two frames from different
|
||||
origins and checks that entries of localStorage
|
||||
objects don't leak each between other.
|
||||
|
||||
The subsystem is based on postMessage and addEventListener
|
||||
to send messages among different origins. The subsystem waits
|
||||
for both frames be loaded and then alternately calls each frames'
|
||||
doStep() function that on each call proceeds with a single step
|
||||
of the test on its side. This way the subsystem alternate between
|
||||
both frames until both sequences completely finish.
|
||||
-->
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
function startTest()
|
||||
{
|
||||
masterFrameOrigin = "http://example.com:80";
|
||||
slaveFrameOrigin = "http://example.com:80";
|
||||
|
||||
masterFrame.location = masterFrameOrigin + framePath + "frameLocalStorageMaster.html";
|
||||
slaveFrame.location = slaveFrameOrigin + framePath + "frameLocalStorageSlaveEqual.html";
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="startTest();">
|
||||
<iframe src="" name="masterFrame"></iframe>
|
||||
<iframe src="" name="slaveFrame"></iframe>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,44 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>storage event propagation test</title>
|
||||
|
||||
<script type="text/javascript" src="/MochiKit/packed.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="interOriginTest2.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
|
||||
<!--
|
||||
This test loads two frames from different
|
||||
origins and checks that entries of localStorage
|
||||
objects don't leak each between other.
|
||||
|
||||
The subsystem is based on postMessage and addEventListener
|
||||
to send messages among different origins. The subsystem waits
|
||||
for both frames be loaded and then alternately calls each frames'
|
||||
doStep() function that on each call proceeds with a single step
|
||||
of the test on its side. This way the subsystem alternate between
|
||||
both frames until both sequences completely finish.
|
||||
-->
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
var slaveFrame = null;
|
||||
|
||||
function startTest()
|
||||
{
|
||||
masterFrameOrigin = "http://example.org:80";
|
||||
slaveFrameOrigin = "http://example.com:80";
|
||||
|
||||
masterFrame.location = masterFrameOrigin + framePath + "frameSessionStorageMasterNotEqual.html";
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="startTest();">
|
||||
<iframe src="" name="masterFrame"></iframe>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,44 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>storage event propagation test</title>
|
||||
|
||||
<script type="text/javascript" src="/MochiKit/packed.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="interOriginTest2.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
|
||||
<!--
|
||||
This test loads two frames from different
|
||||
origins and checks that entries of localStorage
|
||||
objects don't leak each between other.
|
||||
|
||||
The subsystem is based on postMessage and addEventListener
|
||||
to send messages among different origins. The subsystem waits
|
||||
for both frames be loaded and then alternately calls each frames'
|
||||
doStep() function that on each call proceeds with a single step
|
||||
of the test on its side. This way the subsystem alternate between
|
||||
both frames until both sequences completely finish.
|
||||
-->
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
var slaveFrame = null;
|
||||
|
||||
function startTest()
|
||||
{
|
||||
masterFrameOrigin = "http://example.com:80";
|
||||
slaveFrameOrigin = "http://example.com:80";
|
||||
|
||||
masterFrame.location = masterFrameOrigin + framePath + "frameSessionStorageMasterEqual.html";
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="startTest();">
|
||||
<iframe src="" name="masterFrame"></iframe>
|
||||
</body>
|
||||
</html>
|
|
@ -950,7 +950,8 @@ nsWindowWatcher::OpenWindowJSInternal(nsIDOMWindow *aParent,
|
|||
|
||||
if (subjectPrincipal && parentDocShell) {
|
||||
nsCOMPtr<nsIDOMStorage> storage;
|
||||
parentDocShell->GetSessionStorageForPrincipal(subjectPrincipal, PR_FALSE,
|
||||
parentDocShell->GetSessionStorageForPrincipal(subjectPrincipal,
|
||||
EmptyString(), PR_FALSE,
|
||||
getter_AddRefs(storage));
|
||||
nsCOMPtr<nsPIDOMStorage> piStorage =
|
||||
do_QueryInterface(storage);
|
||||
|
|
Загрузка…
Ссылка в новой задаче