--- a/content/events/public/nsIPrivateDOMEvent.h
+++ b/content/events/public/nsIPrivateDOMEvent.h
@@ -97,10 +97,12 @@ nsresult
NS_NewDOMSVGEvent(nsIDOMEvent** aResult, nsPresContext* aPresContext, class nsEvent* aEvent);
nsresult
NS_NewDOMSVGZoomEvent(nsIDOMEvent** aResult, nsPresContext* aPresContext, class nsGUIEvent* aEvent);
#endif // MOZ_SVG
nsresult
NS_NewDOMXULCommandEvent(nsIDOMEvent** aResult, nsPresContext* aPresContext, class nsXULCommandEvent* aEvent);
nsresult
NS_NewDOMCommandEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, nsCommandEvent* aEvent);
+nsresult
+NS_NewDOMMessageEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, class nsEvent* aEvent);
#endif // nsIPrivateDOMEvent_h__
--- a/content/events/src/Makefile.in
+++ b/content/events/src/Makefile.in
@@ -75,16 +75,17 @@ CPPSRCS = \
nsDOMTextEvent.cpp \
nsDOMMouseEvent.cpp \
nsDOMMutationEvent.cpp \
nsDOMPopupBlockedEvent.cpp \
nsDOMBeforeUnloadEvent.cpp \
nsDOMPageTransitionEvent.cpp \
nsDOMXULCommandEvent.cpp \
nsDOMCommandEvent.cpp \
+ nsDOMMessageEvent.cpp \
nsPrivateTextRange.cpp \
nsDOMEventGroup.cpp \
nsXMLEventsManager.cpp \
nsXMLEventsElement.cpp \
nsPLDOMEvent.cpp \
nsEventDispatcher.cpp \
nsIMEStateManager.cpp \
$(NULL)
new file mode 100644
--- /dev/null
+++ b/content/events/src/nsDOMMessageEvent.cpp
@@ -0,0 +1,131 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Jeff Walden <jwalden+code@mit.edu> (original author)
+ *
+ * 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 "nsDOMMessageEvent.h"
+#include "nsContentUtils.h"
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMMessageEvent)
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsDOMMessageEvent, nsDOMEvent)
+ NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mSource)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsDOMMessageEvent, nsDOMEvent)
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mSource)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsDOMMessageEvent)
+ NS_INTERFACE_MAP_ENTRY(nsIDOMMessageEvent)
+ NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(MessageEvent)
+NS_INTERFACE_MAP_END_INHERITING(nsDOMEvent)
+
+NS_IMPL_ADDREF_INHERITED(nsDOMMessageEvent, nsDOMEvent)
+NS_IMPL_RELEASE_INHERITED(nsDOMMessageEvent, nsDOMEvent)
+
+NS_IMETHODIMP
+nsDOMMessageEvent::GetData(nsAString& aData)
+{
+ aData = mData;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDOMMessageEvent::GetDomain(nsAString& aDomain)
+{
+ aDomain = mDomain;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDOMMessageEvent::GetUri(nsAString& aURI)
+{
+ aURI = mURI;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDOMMessageEvent::GetSource(nsIDOMWindow** aSource)
+{
+ NS_IF_ADDREF(*aSource = mSource);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDOMMessageEvent::InitMessageEvent(const nsAString& aType,
+ PRBool aCanBubble,
+ PRBool aCancelable,
+ const nsAString& aData,
+ const nsAString& aDomain,
+ const nsAString& aURI,
+ nsIDOMWindow* aSource)
+{
+ nsresult rv = nsDOMEvent::InitEvent(aType, aCanBubble, aCancelable);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ mData = aData;
+ mDomain = aDomain;
+ mURI = aURI;
+ mSource = aSource;
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDOMMessageEvent::InitMessageEventNS(const nsAString& aNamespaceURI,
+ const nsAString& aType,
+ PRBool aCanBubble,
+ PRBool aCancelable,
+ const nsAString& aData,
+ const nsAString& aDomain,
+ const nsAString& aURI,
+ nsIDOMWindow* aSource)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+nsresult
+NS_NewDOMMessageEvent(nsIDOMEvent** aInstancePtrResult,
+ nsPresContext* aPresContext,
+ nsEvent* aEvent)
+{
+ nsDOMMessageEvent* it = new nsDOMMessageEvent(aPresContext, aEvent);
+ if (nsnull == it)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ return CallQueryInterface(it, aInstancePtrResult);
+}
new file mode 100644
--- /dev/null
+++ b/content/events/src/nsDOMMessageEvent.h
@@ -0,0 +1,76 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Jeff Walden <jwalden+code@mit.edu> (original author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef nsDOMMessageEvent_h__
+#define nsDOMMessageEvent_h__
+
+#include "nsIDOMMessageEvent.h"
+#include "nsDOMEvent.h"
+#include "nsCycleCollectionParticipant.h"
+
+/**
+ * Implements the MessageEvent event, used for cross-document messaging.
+ *
+ * See http://www.whatwg.org/specs/web-apps/current-work/#messageevent for
+ * further details.
+ */
+class nsDOMMessageEvent : public nsIDOMMessageEvent,
+ public nsDOMEvent
+{
+public:
+ nsDOMMessageEvent(nsPresContext* aPresContext, nsEvent* aEvent)
+ : nsDOMEvent(aPresContext, aEvent)
+ {
+ }
+
+ NS_DECL_ISUPPORTS_INHERITED
+ NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsDOMMessageEvent, nsDOMEvent)
+
+ NS_DECL_NSIDOMMESSAGEEVENT
+
+ // Forward to base class
+ NS_FORWARD_TO_NSDOMEVENT
+
+private:
+ nsString mData;
+ nsString mDomain;
+ nsString mURI;
+ nsCOMPtr<nsIDOMWindow> mSource;
+};
+
+#endif // nsDOMMessageEvent_h__
--- a/content/events/src/nsEventDispatcher.cpp
+++ b/content/events/src/nsEventDispatcher.cpp
@@ -646,11 +646,13 @@ nsEventDispatcher::CreateEvent(nsPresCon
aEventType.LowerCaseEqualsLiteral("xulcommandevents"))
return NS_NewDOMXULCommandEvent(aDOMEvent, aPresContext, nsnull);
if (aEventType.LowerCaseEqualsLiteral("commandevent") ||
aEventType.LowerCaseEqualsLiteral("commandevents"))
return NS_NewDOMCommandEvent(aDOMEvent, aPresContext, nsnull);
if (aEventType.LowerCaseEqualsLiteral("datacontainerevent") ||
aEventType.LowerCaseEqualsLiteral("datacontainerevents"))
return NS_NewDOMDataContainerEvent(aDOMEvent, aPresContext, nsnull);
+ if (aEventType.LowerCaseEqualsLiteral("messageevent"))
+ return NS_NewDOMMessageEvent(aDOMEvent, aPresContext, nsnull);
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
}
--- a/dom/public/idl/base/nsIDOMWindowInternal.idl
+++ b/dom/public/idl/base/nsIDOMWindowInternal.idl
@@ -39,17 +39,24 @@
#include "nsIDOMWindow2.idl"
interface nsIPrompt;
interface nsIControllers;
interface nsIDOMLocation;
interface nsIVariant;
-[scriptable, uuid(0d12a345-3fe2-491e-af0d-bcfd5c4baa03)]
+%{C++
+/* I hate you, Windows. */
+#ifdef PostMessage
+#undef PostMessage
+#endif
+%}
+
+[scriptable, uuid(86f7b733-aff9-469a-9e8c-2996f7db2720)]
interface nsIDOMWindowInternal : nsIDOMWindow2
{
readonly attribute nsIDOMWindowInternal window;
/* [replaceable] self */
readonly attribute nsIDOMWindowInternal self;
readonly attribute nsIDOMNavigator navigator;
@@ -195,9 +202,24 @@ interface nsIDOMWindowInternal : nsIDOMW
DOMString atob(in DOMString aAsciiString);
DOMString btoa(in DOMString aBase64Data);
readonly attribute nsIDOMElement frameElement;
nsIVariant showModalDialog(in DOMString aURI,
[optional] in nsIVariant aArgs,
[optional] in DOMString aOptions);
+
+ /**
+ * Implements a safe message-passing system which can cross same-origin
+ * boundaries.
+ *
+ * This method, when called, causes a MessageEvent to be dispatched at the
+ * primary document for the window upon which this method is called. (Note
+ * that the postMessage property on windows is allAccess and thus is readable
+ * cross-origin.) The dispatched event will have message as its data, the
+ * calling context's window as its source, and a domain and URI determined by
+ * the calling context's main document URI.
+ *
+ * See the WHATWG HTML5 specification, section 6.4, for more details.
+ */
+ void postMessage(in DOMString message);
};
--- a/dom/public/idl/events/Makefile.in
+++ b/dom/public/idl/events/Makefile.in
@@ -66,11 +66,12 @@ XPIDLSRCS = \
nsIDOMMutationEvent.idl \
nsIDOMNSUIEvent.idl \
nsIDOMPopupBlockedEvent.idl \
nsIDOMBeforeUnloadEvent.idl \
nsIDOMNSEventTarget.idl \
nsIDOMSmartCardEvent.idl \
nsIDOMPageTransitionEvent.idl \
nsIDOMCommandEvent.idl \
+ nsIDOMMessageEvent.idl \
$(NULL)
include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/dom/public/idl/events/nsIDOMMessageEvent.idl
@@ -0,0 +1,97 @@
+/* -*- 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
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Jeff Walden <jwalden+code@mit.edu> (original author)
+ *
+ * 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 "nsIDOMEvent.idl"
+
+/**
+ * The nsIDOMMessageEvent interface is used for server-sent events and for
+ * cross-domain messaging.
+ *
+ * For more information on this interface, please see
+ * http://www.whatwg.org/specs/web-apps/current-work/multipage/section-event0.html#event0
+ */
+[scriptable, uuid(3CF6163E-0227-49D9-B52B-F061828FB9B8)]
+interface nsIDOMMessageEvent : nsIDOMEvent
+{
+ /**
+ * Custom string data associated with this event.
+ */
+ readonly attribute DOMString data;
+
+ /**
+ * The domain of the site from which this event originated.
+ */
+ readonly attribute DOMString domain;
+
+ /**
+ * The URI of the site from which this event was created.
+ */
+ readonly attribute DOMString uri;
+
+ /**
+ * The window which originated this event.
+ */
+ readonly attribute nsIDOMWindow source;
+
+ /**
+ * Initializes this event with the given data, in a manner analogous to
+ * the similarly-named method on the nsIDOMEvent interface, also setting the
+ * data, domain, uri, and source attributes of this appropriately.
+ */
+ void initMessageEvent(in DOMString aType,
+ in boolean aCanBubble,
+ in boolean aCancelable,
+ in DOMString aData,
+ in DOMString aDomain,
+ in DOMString aURI,
+ in nsIDOMWindow aSource);
+
+ /**
+ * Initializes this event with the given data, in a manner analogous to
+ * the similarly-named method on the Event interface, also setting the data,
+ * domain, uri, and source attributes of this appropriately.
+ */
+ void initMessageEventNS(in DOMString aNamespaceURI,
+ in DOMString aType,
+ in boolean aCanBubble,
+ in boolean aCancelable,
+ in DOMString aData,
+ in DOMString aDomain,
+ in DOMString aURI,
+ in nsIDOMWindow aSource);
+};
--- a/dom/public/nsDOMClassInfoID.h
+++ b/dom/public/nsDOMClassInfoID.h
@@ -415,16 +415,20 @@ enum nsDOMClassInfoID {
eDOMClassInfo_FileException_id,
// DOM modal content window class, almost identical to Window
eDOMClassInfo_ModalContentWindow_id,
// Data Events
eDOMClassInfo_DataContainerEvent_id,
+ // event used for cross-domain message-passing and for server-sent events in
+ // HTML5
+ eDOMClassInfo_MessageEvent_id,
+
// This one better be the last one in this list
eDOMClassInfoIDCount
};
/**
* nsIClassInfo helper macros
*/
--- a/dom/src/base/nsDOMClassInfo.cpp
+++ b/dom/src/base/nsDOMClassInfo.cpp
@@ -231,16 +231,17 @@
#include "nsIDOMMouseEvent.h"
#include "nsIDOMCommandEvent.h"
#include "nsIDOMPopupBlockedEvent.h"
#include "nsIDOMBeforeUnloadEvent.h"
#include "nsIDOMMutationEvent.h"
#include "nsIDOMSmartCardEvent.h"
#include "nsIDOMXULCommandEvent.h"
#include "nsIDOMPageTransitionEvent.h"
+#include "nsIDOMMessageEvent.h"
#include "nsIDOMNSDocumentStyle.h"
#include "nsIDOMDocumentRange.h"
#include "nsIDOMDocumentTraversal.h"
#include "nsIDOMDocumentXBL.h"
#include "nsIDOMDocumentView.h"
#include "nsIDOMElementCSSInlineStyle.h"
#include "nsIDOMLinkStyle.h"
#include "nsIDOMHTMLDocument.h"
@@ -1222,16 +1223,19 @@ static nsDOMClassInfoData sClassInfoData
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(ModalContentWindow, nsWindowSH,
DEFAULT_SCRIPTABLE_FLAGS |
WINDOW_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(DataContainerEvent, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
+
+ NS_DEFINE_CLASSINFO_DATA(MessageEvent, nsDOMGenericSH,
+ DOM_DEFAULT_SCRIPTABLE_FLAGS)
};
// Objects that shuld be constructable through |new Name();|
struct nsContractIDMapData
{
PRInt32 mDOMClassInfoID;
const char *mContractID;
};
@@ -3361,16 +3365,21 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_MAP_ENTRY(nsIDOMStorageWindow)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMModalContentWindow)
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(DataContainerEvent, nsIDOMDataContainerEvent)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMDataContainerEvent)
DOM_CLASSINFO_MAP_END
+ DOM_CLASSINFO_MAP_BEGIN(MessageEvent, nsIDOMMessageEvent)
+ DOM_CLASSINFO_MAP_ENTRY(nsIDOMMessageEvent)
+ DOM_CLASSINFO_EVENT_MAP_ENTRIES
+ DOM_CLASSINFO_MAP_END
+
#ifdef NS_DEBUG
{
PRUint32 i = NS_ARRAY_LENGTH(sClassInfoData);
if (i != eDOMClassInfoIDCount) {
NS_ERROR("The number of items in sClassInfoData doesn't match the "
"number of nsIDOMClassInfo ID's, this is bad! Fix it!");
--- a/dom/src/base/nsGlobalWindow.cpp
+++ b/dom/src/base/nsGlobalWindow.cpp
@@ -24,16 +24,17 @@
* Travis Bogard <travis@netscape.com>
* Brendan Eich <brendan@mozilla.org>
* David Hyatt (hyatt@netscape.com)
* Dan Rosen <dr@netscape.com>
* Vidur Apparao <vidur@netscape.com>
* Johnny Stenback <jst@netscape.com>
* Mark Hammond <mhammond@skippinet.com.au>
* Ryan Jones <sciguyryan@gmail.com>
+ * Jeff Walden <jwalden+code@mit.edu>
*
* 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
@@ -101,16 +102,17 @@
#include "nsIDOMNSDocument.h"
#include "nsIDOMDocumentView.h"
#include "nsIDOMElement.h"
#include "nsIDOMDocumentEvent.h"
#include "nsIDOMEvent.h"
#include "nsIDOMHTMLDocument.h"
#include "nsIDOMHTMLElement.h"
#include "nsIDOMKeyEvent.h"
+#include "nsIDOMMessageEvent.h"
#include "nsIDOMPopupBlockedEvent.h"
#include "nsIDOMPkcs11.h"
#include "nsIDOMOfflineResourceList.h"
#include "nsDOMString.h"
#include "nsIEmbeddingSiteWindow2.h"
#include "nsThreadUtils.h"
#include "nsIEventStateManager.h"
#include "nsIHttpProtocolHandler.h"
@@ -4965,16 +4967,157 @@ nsGlobalWindow::GetFrames(nsIDOMWindow**
*aFrames = this;
NS_ADDREF(*aFrames);
FlushPendingNotifications(Flush_ContentAndNotify);
return NS_OK;
}
+static nsGlobalWindow*
+CallerInnerWindow()
+{
+ nsAXPCNativeCallContext *ncc;
+ nsresult rv = nsContentUtils::XPConnect()->GetCurrentNativeCallContext(&ncc);
+ if (NS_FAILED(rv) || !ncc) {
+ NS_ASSERTION(ncc, "Please don't call this method from C++!");
+ return nsnull;
+ }
+
+ JSContext *cx = nsnull;
+ if (NS_FAILED(ncc->GetJSContext(&cx))) {
+ NS_WARNING("couldn't get JS context from native context");
+ return nsnull;
+ }
+
+ JSObject *scope = ::JS_GetScopeChain(cx);
+ if (!scope)
+ return nsnull;
+
+ nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
+ nsContentUtils::XPConnect()->
+ GetWrappedNativeOfJSObject(cx, ::JS_GetGlobalForObject(cx, scope),
+ getter_AddRefs(wrapper));
+ if (!wrapper)
+ return nsnull;
+
+ // The calling window must be holding a reference, so we can just return a
+ // raw pointer here and let the QI's addref be balanced by the nsCOMPtr
+ // destructor's release.
+ nsCOMPtr<nsPIDOMWindow> win = do_QueryWrappedNative(wrapper);
+ return static_cast<nsGlobalWindow*>(win.get());
+}
+
+/* I hate you, Windows. */
+#ifdef PostMessage
+#undef PostMessage
+#endif
+
+NS_IMETHODIMP
+nsGlobalWindow::PostMessage(const nsAString& aMessage)
+{
+ FORWARD_TO_INNER_CREATE(PostMessage, (aMessage));
+
+ //
+ // Window.postMessage is an intentional subversion of the same-origin policy.
+ // As such, this code must be particularly careful in the information it
+ // exposes to calling code.
+ //
+ // http://www.whatwg.org/specs/web-apps/current-work/multipage/section-crossDocumentMessages.html
+ //
+
+
+ // First, get the caller's window
+ nsRefPtr<nsGlobalWindow> callerInnerWin = CallerInnerWindow();
+ if (!callerInnerWin)
+ return NS_OK;
+ NS_ASSERTION(callerInnerWin->IsInnerWindow(), "should have gotten an inner window here");
+
+ // Obtain the caller's principal, from which we can usually extract a URI
+ // and domain for the event.
+ nsIPrincipal* callerPrin = callerInnerWin->GetPrincipal();
+ if (!callerPrin)
+ return NS_OK;
+ nsCOMPtr<nsIURI> docURI;
+ if (NS_FAILED(callerPrin->GetURI(getter_AddRefs(docURI))))
+ return NS_OK;
+
+ // If we hit this, we're probably in chrome context and have the URI-less
+ // system principal, so get the URI off the caller's document.
+ if (!docURI) {
+ nsCOMPtr<nsIDocument> doc = do_QueryInterface(callerInnerWin->mDocument);
+ if (!doc)
+ return NS_OK;
+
+ docURI = doc->GetDocumentURI();
+ if (!docURI)
+ return NS_OK;
+ }
+
+ nsCAutoString domain, uri;
+ nsresult rv = docURI->GetSpec(uri);
+ if (NS_FAILED(rv))
+ return NS_OK;
+
+ // This really shouldn't be necessary -- URLs which don't have a host should
+ // return the empty string -- but nsSimpleURI just errors instead of
+ // truncating domain. We could just ignore the returned error, but in the
+ // interests of playing it safe in a sensitive API, we check and truncate if
+ // GetHost fails. Empty hosts are valid for some URI schemes, and any code
+ // which expects a non-empty host should ignore the message we'll dispatch.
+ if (NS_FAILED(docURI->GetHost(domain)))
+ domain.Truncate();
+
+ // Create the event
+ nsCOMPtr<nsIDOMDocumentEvent> docEvent = do_QueryInterface(mDocument);
+ if (!docEvent)
+ return NS_OK;
+ nsCOMPtr<nsIDOMEvent> event;
+ docEvent->CreateEvent(NS_LITERAL_STRING("MessageEvent"),
+ getter_AddRefs(event));
+ if (!event)
+ return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIDOMMessageEvent> message = do_QueryInterface(event);
+ rv = message->InitMessageEvent(NS_LITERAL_STRING("message"),
+ PR_TRUE /* bubbling */,
+ PR_TRUE /* cancelable */,
+ aMessage,
+ NS_ConvertUTF8toUTF16(domain),
+ NS_ConvertUTF8toUTF16(uri),
+ nsContentUtils::IsCallerChrome()
+ ? nsnull
+ : callerInnerWin->GetOuterWindowInternal());
+ if (NS_FAILED(rv))
+ return rv;
+
+
+ // Finally, dispatch the event, ignoring the result to prevent an exception
+ // from revealing anything about the document for this window.
+ PRBool dummy;
+ nsCOMPtr<nsIDOMEventTarget> targetDoc = do_QueryInterface(mDocument);
+ targetDoc->DispatchEvent(message, &dummy);
+
+ // Cancel exceptions that might somehow be pending. XPConnect swallows these
+ // exceptions across JS contexts, but there can be concerns if the caller
+ // and the thrower are same-context but different-origin -- see bug 387706
+ // comment 26, waring the typo in it. Consequently, we play it safe and always
+ // cancel exceptions.
+ nsAXPCNativeCallContext *ncc;
+ rv = nsContentUtils::XPConnect()->GetCurrentNativeCallContext(&ncc);
+ if (NS_FAILED(rv) || !ncc)
+ return NS_OK;
+
+ JSContext *cx = nsnull;
+ if (NS_SUCCEEDED(ncc->GetJSContext(&cx)))
+ ::JS_ClearPendingException(cx);
+
+ return NS_OK;
+}
+
class nsCloseEvent : public nsRunnable {
public:
nsCloseEvent (nsGlobalWindow *aWindow)
: mWindow(aWindow)
{
}
NS_IMETHOD Run() {
@@ -7187,43 +7330,17 @@ nsGlobalWindow::SetTimeoutOrInterval(PRB
// This needs to forward to the inner window, but since the current
// inner may not be the inner in the calling scope, we need to treat
// this specially here as we don't want timeouts registered in a
// dying inner window to get registered and run on the current inner
// window. To get this right, we need to forward this call to the
// inner window that's calling window.setTimeout().
if (IsOuterWindow()) {
- nsAXPCNativeCallContext *ncc = nsnull;
- nsresult rv = nsContentUtils::XPConnect()->
- GetCurrentNativeCallContext(&ncc);
- NS_ENSURE_SUCCESS(rv, rv);
-
- if (!ncc) {
- return NS_ERROR_NOT_AVAILABLE;
- }
-
- JSContext *cx = nsnull;
-
- rv = ncc->GetJSContext(&cx);
- NS_ENSURE_SUCCESS(rv, rv);
-
- JSObject *scope = ::JS_GetScopeChain(cx);
-
- if (!scope) {
- return NS_ERROR_NOT_AVAILABLE;
- }
-
- nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
- nsContentUtils::XPConnect()->
- GetWrappedNativeOfJSObject(cx, ::JS_GetGlobalForObject(cx, scope),
- getter_AddRefs(wrapper));
- NS_ENSURE_TRUE(wrapper, NS_ERROR_NOT_AVAILABLE);
-
- nsGlobalWindow *callerInner = FromWrapper(wrapper);
+ nsGlobalWindow* callerInner = CallerInnerWindow();
NS_ENSURE_TRUE(callerInner, NS_ERROR_NOT_AVAILABLE);
// If the caller and the callee share the same outer window,
// forward to the callee inner. Else, we forward to the current
// inner (e.g. someone is calling setTimeout() on a reference to
// some other window).
if (callerInner->GetOuterWindow() == this &&
--- a/dom/src/base/nsGlobalWindow.h
+++ b/dom/src/base/nsGlobalWindow.h
@@ -93,16 +93,21 @@
#include "prclist.h"
#include "nsIDOMStorage.h"
#include "nsIDOMStorageList.h"
#include "nsIDOMStorageWindow.h"
#include "nsIDOMOfflineResourceList.h"
#include "nsPIDOMEventTarget.h"
#include "nsIArray.h"
+/* I hate you, Windows. */
+#ifdef PostMessage
+#undef PostMessage
+#endif
+
#define DEFAULT_HOME_PAGE "www.mozilla.org"
#define PREF_BROWSER_STARTUP_HOMEPAGE "browser.startup.homepage"
class nsIDOMBarProp;
class nsIDocument;
class nsIContent;
class nsPresContext;
class nsIDOMEvent;
@@ -206,17 +211,17 @@ private:
//*****************************************************************************
// Beware that all scriptable interfaces implemented by
// nsGlobalWindow will be reachable from JS, if you make this class
// implement new interfaces you better know what you're
// doing. Security wise this is very sensitive code. --
// jst@netscape.com
// nsGlobalWindow inherits PRCList for maintaining a list of all inner
-// widows still in memory for any given outer window. This list is
+// windows still in memory for any given outer window. This list is
// needed to ensure that mOuterWindow doesn't end up dangling. The
// nature of PRCList means that the window itself is always in the
// list, and an outer window's list will also contain all inner window
// objects that are still in memory (and in reality all inner window
// object's lists also contain its outer and all other inner windows
// belonging to the same outer window, but that's an unimportant
// side effect of inheriting PRCList).
--- a/dom/tests/mochitest/Makefile.in
+++ b/dom/tests/mochitest/Makefile.in
@@ -44,12 +44,13 @@ include $(DEPTH)/config/autoconf.mk
DIRS += \
dom-level0 \
dom-level1-core \
dom-level2-core \
ajax \
bugs \
chrome \
+ whatwg \
$(NULL)
include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/whatwg/Makefile.in
@@ -0,0 +1,77 @@
+#
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is mozilla.org code.
+#
+# The Initial Developer of the Original Code is
+# Mozilla Foundation.
+# Portions created by the Initial Developer are Copyright (C) 2007
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+# Jeff Walden <jwalden+code@mit.edu>
+#
+# 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/whatwg
+
+include $(DEPTH)/config/autoconf.mk
+include $(topsrcdir)/config/rules.mk
+
+_TEST_FILES = \
+ browserFu.js \
+ test_MessageEvent.html \
+ test_postMessage.html \
+ postMessage_helper.html \
+ test_postMessage_joined.html \
+ postMessage_joined_helper.html \
+ postMessage_joined_helper2.html \
+ test_postMessage_onOther.html \
+ postMessage_onOther.html \
+ test_MessageEvent_dispatchToOther.html \
+ test_postMessage_override.html \
+ postMessage_override_helper.html \
+ test_postMessage_throw.html \
+ postMessage_throw_helper.html \
+ postMessage_chrome_helper.html \
+ test_postMessage_special.xhtml \
+ test_postMessage_idn.xhtml \
+ postMessage_idn_helper.html \
+ $(NULL)
+
+_CHROME_FILES = \
+ test_postMessage_chrome.html \
+ $(NULL)
+
+libs:: $(_TEST_FILES)
+ $(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
+
+libs:: $(_CHROME_FILES)
+ $(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/chrome/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/whatwg/browserFu.js
@@ -0,0 +1,6 @@
+/**
+ * File which includes stuff for Mozilla-specific checks which shouldn't happen
+ * in other browsers but which we wish to test.
+ */
+
+var isMozilla = navigator.product === "Gecko" && "buildID" in navigator;
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/whatwg/postMessage_chrome_helper.html
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>postMessage chrome message receiver</title>
+ <script type="application/javascript">
+ var sourcePath = "chrome://mochikit/content/chrome/" +
+ "dom/tests/mochitest/whatwg/test_postMessage_chrome.html";
+
+ function receiveMessage(evt)
+ {
+ // Content cannot post to chrome without privileges
+ window.parent.postMessage("SHOULD NOT GET THIS!");
+
+ var msg = "post-to-content-response";
+
+ if (evt.source !== null)
+ msg += " wrong-source(" + evt.source + ")";
+ if (!evt.isTrusted)
+ msg += " unexpected-untrusted-event";
+ if (evt.type !== "message")
+ msg += " wrong-type(" + evt.type + ")";
+ if (evt.uri !== sourcePath)
+ msg += " wrong-uri(" + evt.uri + ")";
+ if (evt.domain !== "mochikit")
+ msg += " wrong-domain(" + evt.domain + ")";
+ if (evt.data !== "post-to-content")
+ msg += " wrong-message(" + evt.data + ")";
+
+ respond(msg);
+ }
+
+ function respond(msg)
+ {
+ // ...so get privileges and test that this works with privileges
+ netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+ window.parent.postMessage(msg);
+ }
+
+ document.addEventListener("message", receiveMessage, false);
+ </script>
+</head>
+<body>
+<h1 id="domain">example.org</h1>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/whatwg/postMessage_helper.html
@@ -0,0 +1,109 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>postMessage message receiver</title>
+ <script type="application/javascript" src="browserFu.js"></script>
+ <script type="application/javascript">
+ function $(id) { return document.getElementById(id); }
+
+ function setup()
+ {
+ $("domain").textContent = location.hostname + ":" + (location.port || 80);
+ }
+
+ var otherPath = "/tests/dom/tests/mochitest/whatwg/test_postMessage.html";
+
+ function receiveMessage(evt)
+ {
+ var response = evt.data + "-response";
+
+ if (evt.source !== window.parent)
+ {
+ response += " unexpected-source(" + evt.source + ")";
+ response += " window-parent-is(" + window.parent + ")";
+ response += " location(" + window.location.href + ")";
+ }
+
+ if (isMozilla && evt.isTrusted)
+ response += " unexpected-trusted";
+
+ if (evt.type != "message")
+ response += " wrong-type(" + evt.type + ")";
+
+ var data = evt.data;
+ if (data == "post-to-other-same-domain")
+ {
+ receiveSame(evt, response);
+ }
+ else if (data == "post-to-other-cross-domain")
+ {
+ receiveCross(evt, response);
+ }
+ else
+ {
+ response += " unexpected-message-to(" + window.location.href + ")";
+ window.parent.postMessage(response);
+ return;
+ }
+ }
+
+ function receiveSame(evt, response)
+ {
+ var source = evt.source;
+ try
+ {
+ if (evt.domain != "localhost")
+ response += " unexpected-domain(" + evt.domain + ")";
+ if (evt.uri != "http://localhost:8888" + otherPath)
+ response += " unexpected-uri(" + evt.uri + ")";
+
+ try
+ {
+ var threw = false;
+ var privateVariable = source.privateVariable;
+ }
+ catch (e)
+ {
+ threw = true;
+ }
+ if (threw || privateVariable !== window.parent.privateVariable)
+ response += " accessed-source!!!";
+
+ }
+ finally
+ {
+ source.postMessage(response);
+ }
+ }
+
+ function receiveCross(evt, response)
+ {
+ var source = evt.source;
+ if (evt.domain != "localhost")
+ response += " unexpected-domain(" + evt.domain + ")";
+ if (evt.uri != "http://localhost:8888" + otherPath)
+ response += " unexpected-uri(" + evt.uri + ")";
+
+ try
+ {
+ var threw = false;
+ var privateVariable = source.privateVariable;
+ }
+ catch (e)
+ {
+ threw = true;
+ }
+ if (!threw || privateVariable !== undefined)
+ response += " accessed-source!!!";
+
+ source.postMessage(response);
+ }
+
+ window.addEventListener("load", setup, false);
+ document.addEventListener("message", receiveMessage, false);
+ </script>
+</head>
+<body>
+<h1 id="domain"></h1>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/whatwg/postMessage_idn_helper.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>postMessage IDN test page</title>
+ <script type="application/javascript">
+ function receiveMessage(evt)
+ {
+ var response = "idn-response";
+
+ if (!(evt instanceof MessageEvent))
+ response += " not-a-MessageEvent";
+ if (evt.uri !== "http://localhost:8888/tests/dom/tests/mochitest/whatwg/test_postMessage_idn.xhtml")
+ response += " wrong-sender-uri(" + evt.uri + ")";
+ if (evt.domain !== "localhost")
+ response += " wrong-sender-domain(" + evt.domain + ")";
+ if (evt.data !== "idn-message")
+ response += " wrong-data(" + evt.data + ")";
+ if (evt.source !== window.parent)
+ response += " wrong-source";
+ if (evt.target !== document)
+ response += " wrong-target";
+ if (evt.type !== "message")
+ response += " wrong-type(" + evt.type + ")";
+
+ evt.source.postMessage(response);
+ }
+ document.addEventListener("message", receiveMessage, false);
+
+ function setup()
+ {
+ var target = document.getElementById("location");
+ target.textContent = document.domain;
+ }
+
+ window.addEventListener("load", setup, false);
+ </script>
+</head>
+<body>
+<h1 id="location">No location!</h1>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/whatwg/postMessage_joined_helper.html
@@ -0,0 +1,100 @@
+<!DOCTYPE html>
+<html>
+<!--
+http://sub1.test1.example.org/tests/dom/tests/mochitest/whatwg/postMessage_joined_helper.html
+-->
+<head>
+ <title>postMessage joined domains, inner frame</title>
+ <script type="application/javascript" src="browserFu.js"></script>
+ <script type="application/javascript">
+ function receiveMessage(evt)
+ {
+ var response, target;
+ var data = evt.data;
+ if (data === "subframe-test-finished")
+ {
+ target = window.parent;
+ response = "test-passed";
+ }
+ else if (data === "start-test")
+ {
+ target = window.frames.innermost;
+ response = "start-test";
+ }
+ else
+ {
+ target = window.parent;
+ response = "not reached";
+ }
+
+ if (evt.type !== "message")
+ response += " wrong-type(" + evt.type + ")";
+
+ if (evt.target !== document)
+ {
+ response += " wrong-target(" + evt.target + ")";
+ response += " location(" + window.location.href + ")";
+ }
+
+ if (isMozilla && evt.isTrusted === true)
+ {
+ response += " unexpected-trusted-event";
+ }
+
+ var uri, domain;
+ if (data == "subframe-test-finished")
+ {
+ uri = "http://example.org/tests/dom/tests/mochitest/whatwg/postMessage_joined_helper2.html";
+ domain = "example.org";
+ }
+ else if (data === "start-test")
+ {
+ uri = "http://localhost:8888/tests/dom/tests/mochitest/whatwg/test_postMessage_joined.html";
+ domain = "localhost";
+ }
+ else
+ {
+ uri = "unreached";
+ domain = "unreached";
+ }
+
+ if (evt.uri !== uri)
+ {
+ response += " wrong-uri(" + evt.uri + ")";
+ response += " location(" + window.location.href + ")";
+ }
+
+ if (evt.domain !== domain)
+ {
+ response += " wrong-domain(" + evt.domain + ")";
+ response += " location(" + window.location.href + ")";
+ }
+
+ target.postMessage(response);
+ }
+
+ function setup()
+ {
+ var oldDomain = document.domain;
+ var newDomain = "example.org";
+
+ document.domain = newDomain;
+
+ var target = document.getElementById("location");
+ target.textContent = "Location: " + oldDomain +
+ ", effective domain: " + newDomain;
+
+ document.addEventListener("message", receiveMessage, false);
+ }
+
+ window.addEventListener("load", setup, false);
+ </script>
+</head>
+<body>
+<p id="location">No location!</p>
+
+<iframe src="http://example.org/tests/dom/tests/mochitest/whatwg/postMessage_joined_helper2.html"
+ name="innermost"></iframe>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/whatwg/postMessage_joined_helper2.html
@@ -0,0 +1,83 @@
+<!DOCTYPE html>
+<html>
+<!--
+http://example.org/tests/dom/tests/mochitest/whatwg/postMessage_joined_helper2.html
+-->
+<head>
+ <title>postMessage joined domains, innermost frame</title>
+ <script type="application/javascript" src="browserFu.js"></script>
+ <script type="application/javascript">
+ function receiveMessage(evt)
+ {
+ var response = "subframe-test-finished";
+
+ if (evt.data !== "start-test")
+ response += " incorrect-subframe-data(" + evt.data + ")";
+ if (evt.type !== "message")
+ response += " wrong-type(" + evt.type + ")";
+ if (evt.target !== document)
+ {
+ response += " wrong-target(" + evt.target + ")";
+ response += " location(" + window.location.href + ")";
+ }
+
+ if (isMozilla && evt.isTrusted)
+ {
+ response += " unexpected-trusted-event";
+ }
+
+ if (evt.source !== window.parent)
+ {
+ response += " unexpected-source(" + evt.source + ")";
+ response += " window-parent-is(" + window.parent + ")";
+ response += " location(" + window.location.href + ")";
+ }
+
+ // verify that document.domain was actually joined with this domain
+ try
+ {
+ var passed = evt.source.document.domain === document.domain;
+ }
+ catch (e)
+ {
+ }
+
+ if (!passed)
+ response += " expected-joined-domains";
+
+ if (evt.uri !== "http://sub1.test1.example.org/tests/dom/tests/mochitest/whatwg/postMessage_joined_helper.html")
+ {
+ response += " wrong-uri(" + evt.uri + ")";
+ response += " location(" + window.location.href + ")";
+ }
+
+ if (evt.domain !== "sub1.test1.example.org")
+ {
+ response += " wrong-domain(" + evt.domain + ")";
+ response += " location(" + window.location.href + ")";
+ }
+
+ window.parent.postMessage(response);
+ }
+
+ function setup()
+ {
+ var oldDomain = document.domain;
+ var newDomain = "example.org"; // join with parent
+
+ document.domain = newDomain;
+
+ var target = document.getElementById("location");
+ target.textContent = "Location: " + oldDomain +
+ ", effective domain: " + newDomain;
+
+ document.addEventListener("message", receiveMessage, false);
+ }
+
+ window.addEventListener("load", setup, false);
+ </script>
+</head>
+<body>
+<p id="location">No location!</p>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/whatwg/postMessage_onOther.html
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>postMessage called through another frame</title>
+ <script type="application/javascript">
+ function receiveMessage(evt)
+ {
+ var response = "response-to-sibling-sent-message";
+
+ // Our parent frame called testSiblingPostMessage (below) on a frame
+ // containing this page on localhost:8888. testSiblingPostMessage then
+ // called postMessage on this page on example.org:8000. We thus expect
+ // to see an event whose source is the window of our sibling frame on
+ // localhost:8888. In other words, the event we receive should have:
+ //
+ // http://localhost:8888/tests/dom/tests/mochitest/whatwg/postMessage_onOther.html
+ //
+ // and not
+ //
+ // http://localhost:8888/tests/dom/tests/mochitest/whatwg/test_postMessage_onOther.html
+ //
+ // as its source.
+
+ if (evt.data !== "message-from-sibling")
+ response += " wrong-data(" + evt.data + ")";
+ if (evt.uri !== "http://localhost:8888/tests/dom/tests/mochitest/whatwg/postMessage_onOther.html")
+ response += " failed-wrong-uri(" + evt.uri + ")";
+ if (evt.domain !== "localhost")
+ response += " failed-wrong-domain(" + evt.domain + ")";
+ if (evt.source !== window.parent.firstFrame)
+ response += " failed-wrong-source";
+
+ window.parent.postMessage(response);
+ }
+
+ function testSiblingPostMessage()
+ {
+ window.parent.secondFrame.postMessage("message-from-sibling");
+ }
+
+ function setup()
+ {
+ var target = document.getElementById("location");
+ target.textContent = document.domain;
+ }
+
+ document.addEventListener("message", receiveMessage, false);
+ window.addEventListener("load", setup, false);
+ </script>
+</head>
+<body>
+<h1 id="location">No location!</h1>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/whatwg/postMessage_override_helper.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Overriding postMessage and dispatchEvent bindings</title>
+ <script type="application/javascript">
+ window.postMessage = function (evt)
+ {
+ window.parent.postMessage("FAIL overridden postMessage called");
+ };
+
+ var count = 0;
+
+ function receiveMessage(evt)
+ {
+ count++;
+ if (count == 1)
+ {
+ window.dispatchEvent = function(evt)
+ {
+ window.parent.postMessage("FAIL");
+ throw "dispatchEvent threw";
+ };
+ }
+
+ window.parent.postMessage(evt.data);
+ }
+
+ function setup()
+ {
+ var target = document.getElementById("location");
+ target.textContent = document.domain;
+ }
+
+ document.addEventListener("message", receiveMessage, false);
+
+ window.addEventListener("load", setup, false);
+ </script>
+</head>
+<body>
+<h1 id="location">No location!</h1>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/whatwg/postMessage_throw_helper.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>postMessage throwing page</title>
+ <script type="application/javascript">
+ function receiveMessage(evt)
+ {
+ throw 17;
+ }
+ document.addEventListener("message", receiveMessage, false);
+
+ function setup()
+ {
+ var target = document.getElementById("location");
+ target.textContent = document.domain;
+ }
+
+ window.addEventListener("load", setup, false);
+ </script>
+</head>
+<body>
+<h1 id="location">No location!</h1>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/whatwg/test_MessageEvent.html
@@ -0,0 +1,113 @@
+<!DOCTYPE html>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=postMessage
+-->
+<head>
+ <title>MessageEvent tests</title>
+ <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="browserFu.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=postMessage">Mozilla Bug 387706</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+
+<button id="target">target</button>
+
+<pre id="test">
+<script class="testbody" type="application/javascript">
+/** Test for Bug 387706 **/
+
+SimpleTest.waitForExplicitFinish();
+
+var data = "foobar";
+var domain = "cool.example.com";
+var uri = "http://cool.example.com/bar";
+var bubbles = true, cancelable = true;
+
+var target;
+
+var count = 0;
+
+function sendMsg()
+{
+ try
+ {
+ var evt = document.createEvent("MessageEvent");
+ ok(evt instanceof MessageEvent, "I ordered a MessageEvent!");
+
+ if (isMozilla)
+ {
+ is(evt.source, null,
+ "not initialized yet, so null in our implementation");
+ }
+
+ evt.initMessageEvent("message", bubbles, cancelable, data, domain, uri, null);
+ ok(evt.source === null, "null source is fine for a MessageEvent");
+
+ evt.initMessageEvent("message", bubbles, cancelable, data, domain, uri, window);
+
+ is(evt.data, data, "unexpected data");
+ is(evt.domain, domain, "unexpected domain");
+ is(evt.uri, uri, "unexpected uri");
+
+ is(evt.cancelable, cancelable, "wrong cancelable property");
+ is(evt.bubbles, bubbles, "wrong bubbling property");
+ is(evt.source, window, "wrong source");
+
+ return target.dispatchEvent(evt);
+ }
+ catch (e)
+ {
+ ok(false, "exception thrown: " + e);
+ return false;
+ }
+}
+
+function recvMsg(evt)
+{
+ is(evt.data, data, "unexpected data");
+ is(evt.domain, domain, "unexpected domain");
+ is(evt.uri, uri, "unexpected uri");
+
+ is(evt.cancelable, cancelable, "wrong cancelable property");
+ is(evt.bubbles, bubbles, "wrong bubbling property");
+ is(evt.source, window, "wrong source");
+
+ is(evt.target, target, "wrong target");
+
+ if (target == evt.currentTarget)
+ {
+ is(Event.AT_TARGET, evt.eventPhase, "this listener was on the target");
+ }
+ else
+ {
+ is(evt.currentTarget, document, "should have gotten this at the window");
+ is(Event.BUBBLING_PHASE, evt.eventPhase, "wrong phase");
+ }
+
+ count++;
+}
+
+function setup()
+{
+ target = $("target");
+ target.addEventListener("message", recvMsg, false);
+ document.addEventListener("message", recvMsg, false);
+ var res = sendMsg();
+ ok(res === true, "nothing canceled this");
+ is(count, 2, "listener not called twice");
+ SimpleTest.finish();
+}
+
+addLoadEvent(setup);
+
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/whatwg/test_MessageEvent_dispatchToOther.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=postMessage
+-->
+<head>
+ <title>Dispatching MessageEvent across origins</title>
+ <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=postMessage">Mozilla Bug 387706</a>
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+
+<iframe src="http://example.com/" name="otherDomain"></iframe>
+
+<pre id="test">
+<script class="testbody" type="application/javascript">
+/** Test for Bug 387706 **/
+
+SimpleTest.waitForExplicitFinish();
+
+function run()
+{
+ try
+ {
+ var msg = document.createEvent("MessageEvent");
+ msg.initMessageEvent("message", true, true,
+ "foo", "evil.com", "http://evil.com/", window);
+
+ try
+ {
+ var ex;
+ window.frames.otherDomain.dispatchEvent(msg);
+ ok(false, "should have thrown a security exception per HTML5");
+ }
+ catch (e)
+ {
+ ok(true, "correctly threw an exception (security exception, but " +
+ "what that entails isn't yet defined in the spec)");
+ }
+ }
+ catch (e)
+ {
+ ok(false, "threw exception during execution: " + e);
+ }
+ finally
+ {
+ SimpleTest.finish();
+ }
+}
+
+addLoadEvent(run);
+
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/whatwg/test_postMessage.html
@@ -0,0 +1,203 @@
+<!DOCTYPE html>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=postMessage
+-->
+<head>
+ <title>Basic postMessage tests</title>
+ <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="browserFu.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=postMessage">Mozilla Bug 387706</a>
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+
+<iframe src="http://localhost:8888/tests/dom/tests/mochitest/whatwg/postMessage_helper.html"
+ name="otherSameDomain"></iframe>
+<iframe src="http://example.org:8000/tests/dom/tests/mochitest/whatwg/postMessage_helper.html"
+ name="otherCrossDomain"></iframe>
+
+
+<pre id="test">
+<script class="testbody" type="application/javascript">
+/** Test for Bug 387706 **/
+
+SimpleTest.waitForExplicitFinish();
+
+var otherPath = "/tests/dom/tests/mochitest/whatwg/postMessage_helper.html";
+var path = "/tests/dom/tests/mochitest/whatwg/test_postMessage.html";
+
+var testsCompletedCount = 0;
+
+/** Variable for receivers to attempt to get. */
+window.privateVariable = 17;
+
+/** For sentinel finish, if necessary in deficient browsers */
+var finished = false;
+
+/** Receives MessageEvents to this window. */
+function messageReceiver(evt)
+{
+ try
+ {
+ ok(evt instanceof MessageEvent, "umm, how did we get this?");
+ is(evt.type, "message", "expected events of type 'message'");
+
+ if (isMozilla)
+ {
+ ok(evt.isTrusted === false, "shouldn't have been a trusted event");
+ }
+
+ var data = evt.data;
+
+ // Check for the message we send to ourselves; it can't be
+ // counted as a test, and it's conceptually distinct from
+ // the other cases, so just return after handling it.
+ if (data === "post-to-self")
+ {
+ respondToSelf(evt);
+ return;
+ }
+
+ switch (evt.data)
+ {
+ case "post-to-self":
+
+ case "post-to-self-response":
+ receiveSelf(evt);
+ break;
+
+ case "post-to-other-same-domain-response":
+ receiveOtherSameDomain(evt);
+ break;
+
+ case "post-to-other-cross-domain-response":
+ receiveOtherCrossDomain(evt);
+ break;
+
+ default:
+ ok(false, "unexpected message: " + evt.data);
+ break;
+ }
+ }
+ catch (e)
+ {
+ ok(false, "error processing event with data '" + evt.data + "': " + e);
+ }
+
+ // if all the tests have executed, we're done
+ if (++testsCompletedCount == allTests.length)
+ {
+ finished = true;
+ SimpleTest.finish();
+ }
+}
+
+
+/******************
+ * SELF-RESPONDER *
+ ******************/
+
+function respondToSelf(evt)
+{
+ is(evt.domain, "localhost", "what domain are we on again?");
+ is(evt.uri, "http://localhost:8888" + path, "event has wrong URI");
+ is(evt.source, window, "we posted this message!");
+
+ evt.source.postMessage("post-to-self-response");
+}
+
+
+/*************
+ * RECEIVERS *
+ *************/
+
+function receiveSelf(evt)
+{
+ is(evt.domain, "localhost", "what domain are we on again?");
+ is(evt.uri, "http://localhost:8888" + path, "event has wrong URI");
+ is(evt.source, window, "we posted this message!");
+}
+
+function receiveOtherSameDomain(evt)
+{
+ is(evt.domain, "localhost", "we should be same domain");
+ is(evt.uri, "http://localhost:8888" + otherPath,
+ "same-domain response event has wrong URI");
+ is(evt.source, window.frames.otherSameDomain,
+ "wrong source for same-domain message!");
+}
+
+function receiveOtherCrossDomain(evt)
+{
+ is(evt.domain, "example.org", "we should be same domain");
+ is(evt.uri, "http://example.org:8000" + otherPath,
+ "same-domain response event has wrong URI");
+
+ // can't use |is| here, because ok tries to get properties on its arguments
+ // for creating a formatted logging message
+ ok(evt.source === window.frames.otherCrossDomain,
+ "wrong source for cross-domain message!");
+}
+
+
+/**************
+ * TEST SETUP *
+ **************/
+
+document.addEventListener("message", messageReceiver, false);
+
+/**
+ * Returns a nullary function which posts the given message to the given
+ * destination.
+ */
+function createMessageDispatcher(message, destination)
+{
+ function dispatcher()
+ {
+ try
+ {
+ destination.postMessage(message);
+ }
+ catch (e)
+ {
+ ok(false, "error while calling postMessage: " + e);
+ }
+ }
+
+ return dispatcher;
+}
+
+var allTests =
+ [
+ createMessageDispatcher("post-to-self", window),
+ createMessageDispatcher("post-to-other-same-domain",
+ window.frames.otherSameDomain),
+ createMessageDispatcher("post-to-other-cross-domain",
+ window.frames.otherCrossDomain),
+ ];
+
+for (var i = 0, sz = allTests.length; i != sz; i++)
+ addLoadEvent(allTests[i]);
+
+/**
+ * Browsers which fail to send a response to a postMessage need this to
+ * finish the test.
+ */
+function sentinel()
+{
+ if (!finished)
+ {
+ ok(false, "shouldn't be necessary (finished in last of allTests)");
+ SimpleTest.finish();
+ }
+}
+
+addLoadEvent(sentinel);
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/whatwg/test_postMessage_chrome.html
@@ -0,0 +1,119 @@
+<!DOCTYPE html>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=postMessage
+-->
+<head>
+ <title>postMessage chrome tests</title>
+ <script type="application/javascript" src="chrome://mochikit/content/MochiKit/packed.js"></script>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+</head>
+<body>
+<!--
+This test runs at the following URL:
+chrome://mochikit/content/chrome/dom/tests/mochitest/whatwg/test_postMessage_chrome.html
+-->
+
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=postMessage">Mozilla Bug 387706</a>
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+
+<iframe src="http://example.org/tests/dom/tests/mochitest/whatwg/postMessage_chrome_helper.html"
+ name="contentDomain"></iframe>
+
+
+<pre id="test">
+<script class="testbody" type="application/javascript">
+/** Test for Bug 387706 **/
+
+SimpleTest.waitForExplicitFinish();
+
+var pathHead = "chrome://mochikit/content/chrome";
+var path = "/dom/tests/mochitest/whatwg/test_postMessage_chrome.html";
+var otherPath = "/tests/dom/tests/mochitest/whatwg/postMessage_chrome_helper.html";
+
+var testsCompletedCount = 0;
+
+/** Receives MessageEvents to this window. */
+function messageReceiver(evt)
+{
+ ok(evt instanceof MessageEvent, "umm, how did we get this?");
+ is(evt.type, "message", "expected events of type 'message'");
+
+ switch (evt.data)
+ {
+ case "post-to-self":
+ checkSelf(evt);
+ break;
+
+ case "post-to-content-response":
+ receiveContent(evt);
+ break;
+
+ default:
+ ok(false, "unexpected message: " + evt.data);
+ break;
+ }
+
+ // if all the tests have executed, we're done
+ if (++testsCompletedCount == allTests.length)
+ setTimeout(SimpleTest.finish, 0);
+}
+
+
+/******************
+ * SELF-RESPONDER *
+ ******************/
+
+function checkSelf(evt)
+{
+ is(evt.isTrusted, true, "should have sent a trusted event");
+ is(evt.domain, "mochikit", "chrome: protocol's domain is the package");
+ is(evt.uri, pathHead + path, "event has wrong URI");
+ is(evt.source, null, "chrome posters get a null source, for security");
+}
+
+
+/*************
+ * RECEIVERS *
+ *************/
+
+function receiveContent(evt)
+{
+ is(evt.isTrusted, true, "should have sent a trusted event");
+ is(evt.domain, "example.org", "wrong domain for content page");
+ is(evt.uri, "http://example.org" + otherPath,
+ "content response event has wrong URI");
+ is(evt.source, window.frames.contentDomain,
+ "wrong source for same-domain message!");
+}
+
+
+/**************
+ * TEST SETUP *
+ **************/
+
+document.addEventListener("message", messageReceiver, false);
+
+/**
+ * Returns a nullary function which posts the given message to the given
+ * destination.
+ */
+function createMessageDispatcher(message, destination)
+{
+ return function() { destination.postMessage(message); };
+}
+
+var allTests =
+ [
+ createMessageDispatcher("post-to-self", window),
+ createMessageDispatcher("post-to-content",
+ window.frames.contentDomain),
+ ];
+
+allTests.forEach(addLoadEvent);
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/whatwg/test_postMessage_idn.xhtml
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=postMessage
+-->
+<head>
+ <title>postMessage uri/domain values and IDN encoding</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="browserFu.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=postMessage">Mozilla Bug 387706</a>
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+
+<iframe src="http://sub1.ält.example.org:8000/tests/dom/tests/mochitest/whatwg/postMessage_idn_helper.html"></iframe>
+
+<pre id="test">
+<script class="testbody" type="application/javascript">
+/** Test for Bug 387706 **/
+
+SimpleTest.waitForExplicitFinish();
+
+var responseReceived = false;
+var idnWindow = null;
+
+function receiveMessage(evt)
+{
+ ok(evt instanceof MessageEvent, "umm, how did we get this?");
+ is(evt.type, "message", "expected events of type 'message'");
+
+ if (isMozilla)
+ {
+ ok(evt.isTrusted === false, "shouldn't have been a trusted event");
+ }
+
+ is(evt.uri, "http://sub1.ält.example.org:8000/tests/dom/tests/mochitest/whatwg/postMessage_idn_helper.html",
+ "wrong URI -- IDN issue, perhaps?");
+ is(evt.domain, "sub1.ält.example.org",
+ "wrong domain -- IDN issue, perhaps?");
+
+ is(evt.data, "idn-response", "unexpected test result");
+ ok(evt.source === idnWindow, "wrong source");
+
+ responseReceived = true;
+}
+document.addEventListener("message", receiveMessage, false);
+
+var xhtmlns = "http://www.w3.org/1999/xhtml";
+
+function setup()
+{
+ try
+ {
+ var idnFrame = document.getElementsByTagNameNS(xhtmlns, "iframe")[0];
+ idnWindow = idnFrame.contentWindow;
+ idnWindow.postMessage("idn-message");
+
+ ok(responseReceived, "should have gotten a response before returning");
+ }
+ catch (e)
+ {
+ ok(false, "failed to post message: " + e);
+ }
+
+ SimpleTest.finish();
+}
+
+addLoadEvent(setup);
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/whatwg/test_postMessage_joined.html
@@ -0,0 +1,66 @@
+<!DOCTYPE html>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=postMessage
+-->
+<head>
+ <title>postMessage with document.domain setting to join origins</title>
+ <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="browserFu.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=postMessage">Mozilla Bug 387706</a>
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+
+<iframe src="http://sub1.test1.example.org/tests/dom/tests/mochitest/whatwg/postMessage_joined_helper.html"
+ name="container"></iframe>
+
+
+<pre id="test">
+<script class="testbody" type="application/javascript">
+/** Test for Bug 387706 **/
+
+SimpleTest.waitForExplicitFinish();
+
+function receiveTestResult(evt)
+{
+ ok(evt instanceof MessageEvent, "umm, how did we get this?");
+ is(evt.type, "message", "expected events of type 'message'");
+
+ if (isMozilla)
+ {
+ ok(evt.isTrusted === false, "shouldn't have been a trusted event");
+ }
+
+ var data = evt.data;
+
+ // Either we passed the test or we failed it. The message's
+ // contents should help to diagnose the failure. Either way,
+ // consider this the end of the test.
+ is(data, "test-passed", "unexpected test result");
+ SimpleTest.finish();
+}
+
+function setup()
+{
+ document.addEventListener("message", receiveTestResult, false);
+ try
+ {
+ window.frames.container.postMessage("start-test");
+ }
+ catch (e)
+ {
+ ok(false, "failed to post message");
+ SimpleTest.finish();
+ }
+}
+
+addLoadEvent(setup);
+
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/whatwg/test_postMessage_onOther.html
@@ -0,0 +1,78 @@
+<!DOCTYPE html>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=postMessage
+-->
+<head>
+ <title>postMessage called through a different same-origin page</title>
+ <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=postMessage">Mozilla Bug 387706</a>
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+
+<iframe src="http://localhost:8888/tests/dom/tests/mochitest/whatwg/postMessage_onOther.html"
+ name="firstFrame"></iframe>
+<iframe src="http://example.org:8000/tests/dom/tests/mochitest/whatwg/postMessage_onOther.html"
+ name="secondFrame"></iframe>
+
+
+<pre id="test">
+<script class="testbody" type="application/javascript">
+/** Test for Bug 387706 **/
+
+SimpleTest.waitForExplicitFinish();
+
+var finished = false;
+
+/** Receives MessageEvents to this window. */
+function messageReceiver(evt)
+{
+ var fromURI = "http://example.org:8000/tests/dom/tests/mochitest/whatwg/postMessage_onOther.html";
+ ok(evt instanceof MessageEvent, "wrong event type");
+ is(evt.uri, fromURI, "unexpected URI");
+ is(evt.domain, "example.org", "unexpected domain");
+ is(evt.data, "response-to-sibling-sent-message",
+ "unexpected data in message");
+
+ // Handle buggy browsers that might somehow have received a message twice
+ if (finished)
+ return;
+
+ finished = true;
+ SimpleTest.finish();
+}
+
+function postToSecondFrameThroughFirstFrame()
+{
+ try
+ {
+ window.frames.firstFrame.testSiblingPostMessage();
+ }
+ catch (e)
+ {
+ ok(false, "threw exception trying to post through firstFrame: " + e);
+ }
+}
+
+/** For buggy browsers that didn't send a response. */
+function sentinel()
+{
+ if (!finished)
+ {
+ ok(false, "should have been finished by now -- didn't receive response?");
+ SimpleTest.finish();
+ }
+}
+
+document.addEventListener("message", messageReceiver, false);
+
+addLoadEvent(postToSecondFrameThroughFirstFrame);
+addLoadEvent(sentinel);
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/whatwg/test_postMessage_override.html
@@ -0,0 +1,83 @@
+<!DOCTYPE html>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=postMessage
+-->
+<head>
+ <title>postMessage override test</title>
+ <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=postMessage">Mozilla Bug 387706</a>
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+
+<iframe src="http://example.org:8000/tests/dom/tests/mochitest/whatwg/postMessage_override_helper.html"></iframe>
+
+
+<pre id="test">
+<script class="testbody" type="application/javascript">
+/** Test for Bug 387706 **/
+
+SimpleTest.waitForExplicitFinish();
+
+var count = 0;
+
+function test()
+{
+ try
+ {
+ count++;
+ switch (count)
+ {
+ case 1:
+ window.frames[0].postMessage("PASS 1");
+ break;
+
+ case 2:
+ window.frames[0].postMessage("PASS 2");
+ break;
+
+ default:
+ ok(false, "unexpected");
+ }
+ }
+ catch (e)
+ {
+ ok(false, "error running test " + count + ": " + e);
+ }
+}
+
+function messageReceiver(evt)
+{
+ var expect;
+
+ switch (count)
+ {
+ case 1:
+ expect = "PASS 1";
+ break;
+
+ case 2:
+ expect = "PASS 2";
+ break;
+
+ default:
+ expect = "unexpected";
+ break;
+ }
+
+ is(evt.data, expect, "uh-oh, we didn't get the right postMessage!");
+}
+
+document.addEventListener("message", messageReceiver, false);
+
+addLoadEvent(test);
+addLoadEvent(test);
+addLoadEvent(SimpleTest.finish);
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/whatwg/test_postMessage_special.xhtml
@@ -0,0 +1,397 @@
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=postMessage
+-->
+<head>
+ <title>postMessage from about:blank, data URLs</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="browserFu.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=postMessage">Mozilla Bug 387706</a>
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+
+<pre id="test">
+<script class="testbody" type="application/javascript"><![CDATA[
+/** Test for Bug 387706 **/
+
+SimpleTest.waitForExplicitFinish();
+
+var B64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+/**
+ * Encodes an array of bytes into a string using the base 64 encoding scheme.
+ *
+ * @param bytes
+ * An array of bytes to encode.
+ */
+function b64(str) {
+ var byteArray = new Array(str.length);
+ for (var i = 0, sz = str.length; i < sz; i++)
+ byteArray[i] = str.charCodeAt(i);
+
+ var index = 0;
+ function get3Bytes()
+ {
+ if (byteArray.length - index < 3)
+ return null; // Less than three bytes remaining
+
+ // Return the next three bytes in the array, and increment index for our
+ // next invocation
+ return byteArray.slice(index, index += 3);
+ }
+
+ var out = "";
+ var bytes = null;
+ while ((bytes = get3Bytes()))
+ {
+ var bits = 0;
+ for (var i = 0; i < 3; i++)
+ bits = (bits << 8) | bytes[i];
+ for (var j = 18; j >= 0; j -= 6)
+ out += B64_CHARS[(bits>>j) & 0x3F];
+ }
+
+ // Get the remaining bytes
+ bytes = byteArray.slice(index);
+
+ switch (bytes.length)
+ {
+ case 2:
+ out += B64_CHARS[(bytes[0]>>2) & 0x3F] +
+ B64_CHARS[((bytes[0] & 0x03) << 4) | ((bytes[1] >> 4) & 0x0F)] +
+ B64_CHARS[((bytes[1] & 0x0F) << 2)] +
+ "=";
+ break;
+ case 1:
+ out += B64_CHARS[(bytes[0]>>2) & 0x3F] +
+ B64_CHARS[(bytes[0] & 0x03) << 4] +
+ "==";
+ break;
+ }
+
+ return out;
+}
+
+
+var aboutBlankWindow = null;
+var aboutBlank2Window = null;
+var dataWindow = null;
+
+var aboutBlankResponseReceived = false;
+var aboutBlank2ResponseReceived = false;
+var dataResponseReceived = false;
+
+var finished = false;
+
+/** Convert a nullable string to a pretty representation */
+function sourceify(v)
+{
+ if (typeof v == "string")
+ return "'" + v + "'";
+ return String(v);
+}
+
+/** Receives MessageEvents to this window. */
+function messageReceiver(evt)
+{
+ // It's not clear what the security model is for data: URLs and whether they
+ // can access their parents; WebKit denies access, while Gecko currently
+ // allows it. We work around this problem by using postMessage (surprise!)
+ // to start the round of tests when each iframe loads.
+ if (evt.data === "next-test")
+ {
+ setTimeout(nextTest, 0);
+ return;
+ }
+
+
+ try
+ {
+ ok(evt instanceof MessageEvent, "umm, how did we get this?");
+ is(evt.type, "message", "expected events of type 'message'");
+
+ if (isMozilla)
+ {
+ ok(evt.isTrusted === false, "shouldn't have been a trusted event");
+ }
+
+ if (evt.data === "about:blank-response")
+ {
+ // This isn't clarified in HTML5 yet, but the origin for a document which
+ // has been open()ed is the origin of the calling code, somewhat loosely
+ // speaking. For the specific case of about:blank it's also possible
+ // that the origin is determined by the code that opens the window. It's
+ // not codified yet which of these two causes the identifier tokens on
+ // the event generated by the new window to be those of this window, but
+ // in either case this is what they should be.
+ is(evt.uri, "http://localhost:8888/tests/dom/tests/mochitest/whatwg/test_postMessage_special.xhtml",
+ "wrong uri for event from about:blank");
+ ok(evt.domain === "localhost",
+ "wrong domain for event from about:blank; " +
+ "got " + sourceify(evt.domain) + ", " +
+ "expected 'localhost'");
+ is(evt.source, aboutBlankWindow, "wrong source");
+ aboutBlankResponseReceived = true;
+ }
+ else if (evt.data === "about:blank2-response")
+ {
+ is(evt.uri, "http://localhost:8888/tests/dom/tests/mochitest/whatwg/test_postMessage_special.xhtml",
+ "wrong uri for event from about:blank #2");
+ ok(evt.domain === "localhost",
+ "wrong domain for event from about:blank; " +
+ "got " + sourceify(evt.domain) + ", expected 'localhost'");
+ is(evt.source, aboutBlank2Window, "wrong source");
+ aboutBlank2ResponseReceived = true;
+ }
+ else if (evt.data === "data-response")
+ {
+ // Again, HTML5 hasn't yet defined this, but we're going to do the same
+ // thing as with about:blank -- for a data: URL opened from page A, the
+ // uri and domain properties correspond to those of page A. This happens
+ // to fall out naturally from using the window's security principal to
+ // determine these two properties.
+ //
+ // Mozilla currently gives data: URLs the principal of the opener/parent
+ // window, and at least for now we'll test for that behavior. If we ever
+ // change how data: URLs are given principals, we can update this test
+ // then.
+ if (isMozilla)
+ {
+ is(evt.uri, "http://localhost:8888/tests/dom/tests/mochitest/whatwg/test_postMessage_special.xhtml",
+ "wrong uri for event from data URL (but note that this URI is " +
+ "the result of Mozilla's current policy that data: URLs inherit " +
+ "the principal of their opener/parent, a policy not currently " +
+ "specified by any standards)");
+ ok(evt.domain === "localhost",
+ "wrong domain for event from data URL; " +
+ "got " + sourceify(evt.domain) + ", expected ''");
+ }
+
+ is(evt.source, dataWindow, "wrong source");
+ dataResponseReceived = true;
+ }
+ else
+ {
+ ok(false, "unexpected message: " + evt.data);
+ }
+ }
+ catch (e)
+ {
+ ok(false, "error processing event with data '" + evt.data + "': " + e);
+ }
+}
+
+function getContents(description, responseText)
+{
+ var contents =
+ "<!DOCTYPE html>\n" +
+ "<html>\n" +
+ "<head>\n" +
+ " <title>about:blank</title>\n" +
+ " <script type='application/javascript'>\n" +
+ "function receive(evt)\n" +
+ "{\n" +
+ " var response = '" + responseText + "';\n" +
+ "\n" +
+ " if (evt.source !== window.parent)\n" +
+ " response += ' wrong-source';\n" +
+ " if (evt.uri !== 'http://localhost:8888/tests/dom/tests/mochitest/whatwg/test_postMessage_special.xhtml')\n" +
+ " response += ' wrong-uri(' + evt.uri + ')';\n" +
+ " if (evt.domain !== 'localhost')\n" +
+ " response += ' wrong-domain(' + evt.domain + ')';\n" +
+ " if (evt.data !== 'from-opener')\n" +
+ " response += ' wrong-data(' + evt.data + ')';\n" +
+ "\n" +
+ " window.parent.postMessage(response);\n" +
+ "}\n" +
+ "\n" +
+ "function ready()\n" +
+ "{\n" +
+ " window.parent.postMessage('next-test');\n" +
+ "}\n" +
+ "\n" +
+ "window.addEventListener('load', ready, false);\n" +
+ "document.addEventListener('message', receive, false);\n" +
+ " </script>\n" +
+ "</head>\n" +
+ "<body><p>" + description + "</p></body>\n" +
+ "</html>";
+
+ return contents;
+}
+
+var xhtmlns = "http://www.w3.org/1999/xhtml";
+
+function insert(el)
+{
+ var content = $("content");
+ content.parentNode.insertBefore(el, content);
+}
+
+var LOAD_TIMEOUT = 5000;
+
+function setupBlank()
+{
+ var aboutBlankFrame = document.createElementNS(xhtmlns, "iframe");
+ aboutBlankFrame.setAttribute("src", "about:blank");
+ insert(aboutBlankFrame);
+
+ aboutBlankWindow = aboutBlankFrame.contentWindow;
+ var doc = aboutBlankWindow.document;
+ doc.open();
+ doc.write(getContents("This was about:blank #1", "about:blank-response"));
+ doc.close();
+
+ // I don't believe anything guarantees sync parsing, so we have to wait for
+ // the new window to poke us to actually do the test. :-\
+
+ // Catch recalcitrant browsers that fail inside the iframe document code.
+ setTimeout(blankFailed, LOAD_TIMEOUT);
+}
+
+function blankFailed()
+{
+ if (!aboutBlankResponseReceived && !finished)
+ {
+ ok(false,
+ "test timed out (postMessage not accessible on window.parent in " +
+ "the first about:blank iframe?)");
+ finished = true;
+ SimpleTest.finish();
+ }
+}
+
+function setupBlank2()
+{
+ var aboutBlank2Frame = document.createElementNS(xhtmlns, "iframe");
+ aboutBlank2Frame.addEventListener("load", nextTest, false);
+ aboutBlank2Frame.setAttribute("src", "about:blank");
+
+ insert(aboutBlank2Frame);
+}
+
+// Could use window.btoa here, but that's not standardized, and we want to be
+// able to run these tests against browsers that don't support it.
+var dataURI = "data:text/html;base64," +
+ b64(getContents("A data: URL", "data-response"));
+
+function setupData()
+{
+ var dataFrame = document.createElementNS(xhtmlns, "iframe");
+ dataFrame.setAttribute("src", dataURI);
+ insert(dataFrame);
+
+ dataWindow = dataFrame.contentWindow;
+
+ // ...and wait again for the window to load...
+
+ // Catch recalcitrant browsers that fail inside the iframe document code.
+ setTimeout(dataFailed, LOAD_TIMEOUT);
+}
+
+function dataFailed()
+{
+ if (!dataResponseReceived && !finished)
+ {
+ ok(false,
+ "test timed out (postMessage not accessible on window.parent in " +
+ "the data: iframe?)");
+ finished = true;
+ SimpleTest.finish();
+ }
+}
+
+var count = 0;
+function nextTest()
+{
+ switch (count++)
+ {
+ case 0:
+ testBlank();
+ break;
+
+ case 1:
+ testBlank2();
+ break;
+
+ case 2:
+ testData();
+ break;
+
+ default:
+ ok(false, "unreached");
+ break;
+ }
+}
+
+function testBlank()
+{
+ try
+ {
+ aboutBlankWindow.postMessage("from-opener");
+ }
+ catch (e)
+ {
+ ok(false, "exception thrown trying to post message #1 to about:blank");
+ }
+
+ ok(aboutBlankResponseReceived, "about:blank never got a response!");
+
+ setTimeout(setupBlank2, 0);
+}
+
+function testBlank2()
+{
+ // For some reason we can't access this across browsers prior to the iframe
+ // loading, so set its value here.
+ aboutBlank2Window = window.frames[1];
+
+ var doc = aboutBlank2Window.document;
+
+ doc.body.textContent = "This was about:blank #2";
+
+ var script = doc.createElement("script");
+ script.textContent = "window.parent.postMessage('about:blank2-response');";
+ doc.body.appendChild(script);
+
+ // Note that this script gets run synchronously, so we're done with the
+ // test here.
+ ok(aboutBlank2ResponseReceived, "postMessage from about:blank #2 failed");
+
+ setTimeout(setupData, 0);
+}
+
+function testData()
+{
+ try
+ {
+ dataWindow.postMessage("from-opener");
+ }
+ catch (e)
+ {
+ ok(false, "exception thrown trying to post message to data: URL window");
+ }
+
+ ok(dataResponseReceived, "we never got a response!");
+
+ // Don't re-report -- we must have already failed, and this can
+ // screw up the displayed results.
+ if (finished)
+ return;
+
+ finished = true;
+ SimpleTest.finish();
+}
+
+document.addEventListener("message", messageReceiver, false);
+
+addLoadEvent(setupBlank);
+]]></script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/whatwg/test_postMessage_throw.html
@@ -0,0 +1,75 @@
+<!DOCTYPE html>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=postMessage
+-->
+<head>
+ <title>postMessage with a thrown exception</title>
+ <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=postMessage">Mozilla Bug 387706</a>
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+
+<iframe src="http://localhost:8888/tests/dom/tests/mochitest/whatwg/postMessage_throw_helper.html"
+ name="sameDomain"></iframe>
+<iframe src="http://example.org:8000/tests/dom/tests/mochitest/whatwg/postMessage_throw_helper.html"
+ name="crossDomain"></iframe>
+
+
+<pre id="test">
+<script class="testbody" type="application/javascript">
+/** Test for Bug 387706 **/
+
+SimpleTest.waitForExplicitFinish();
+
+function atLoad()
+{
+ try
+ {
+ sameDomain.postMessage("foo");
+ ok(true, "should not have thrown for same-domain exception");
+ }
+ catch (e)
+ {
+ ok(false, "uh-oh, threw a same-domain exception: " + e);
+ }
+
+ setTimeout(next, 0);
+}
+
+function next()
+{
+ ok(true, "no pending-exception wackiness for same-domain");
+ setTimeout(next2, 0);
+}
+
+function next2()
+{
+ try
+ {
+ crossDomain.postMessage("foo");
+ ok(true, "should not have thrown for cross-domain exception");
+ }
+ catch (e)
+ {
+ ok(false, "uh-oh, threw a cross-domain exception: " + e);
+ }
+
+ setTimeout(next3, 0);
+}
+
+function next3()
+{
+ ok(true, "no pending-exception wackiness for cross-domain");
+ SimpleTest.finish();
+}
+
+addLoadEvent(atLoad);
+</script>
+</pre>
+</body>
+</html>
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -304,16 +304,17 @@ pref("capability.policy.default.Window.c
pref("capability.policy.default.Window.closed.get", "allAccess");
pref("capability.policy.default.Window.focus.get", "allAccess");
pref("capability.policy.default.Window.frames.get", "allAccess");
pref("capability.policy.default.Window.history.get", "allAccess");
pref("capability.policy.default.Window.length.get", "allAccess");
pref("capability.policy.default.Window.location", "allAccess");
pref("capability.policy.default.Window.opener.get", "allAccess");
pref("capability.policy.default.Window.parent.get", "allAccess");
+pref("capability.policy.default.Window.postMessage.get", "allAccess");
pref("capability.policy.default.Window.self.get", "allAccess");
pref("capability.policy.default.Window.top.get", "allAccess");
pref("capability.policy.default.Window.window.get", "allAccess");
pref("capability.policy.default.Selection.addSelectionListener", "UniversalXPConnect");
pref("capability.policy.default.Selection.removeSelectionListener", "UniversalXPConnect");
// Restrictions on the DOM for mail/news - see bugs 66938 and 84545
--- a/testing/mochitest/harness.xul
+++ b/testing/mochitest/harness.xul
@@ -40,18 +40,18 @@
/** generate our test list **/
srvScope.makeTags();
var [links, count] = srvScope.list("chrome://mochikit/content/chrome/",
chromeDir, true);
var listContent = srvScope.linksToListItems(links);
var tableContent = srvScope.linksToTableRows(links);
function populate() {
$("list-holder").setAttribute("rowspan", 1 + count);
- $("test-list").innerHTML += listContent.toLowerCase();
- $("test-table").innerHTML += tableContent.toLowerCase();
+ $("test-list").innerHTML += listContent;
+ $("test-table").innerHTML += tableContent;
$("wrapper").innerHTML += " "; // redraw the table
}
gTestList = eval(srvScope.jsonArrayOfTestFiles(links));
connect(window, 'onload', populate);
connect(window, 'onload', hookup);
]]>
</script>
<vbox>
--- a/testing/mochitest/runtests.pl.in
+++ b/testing/mochitest/runtests.pl.in
@@ -100,17 +100,18 @@ use constant CHROMETESTS_URL => "http://
use constant SERVER_STARTUP_TIMEOUT => 45;
# Since some tests require cross-domain support in Mochitest, across ports,
# domains, subdomains, etc. we use a proxy autoconfig hack to map a bunch of
# servers onto localhost:8888. We have to grant them the same privileges as
# localhost:8888 here, since the browser only knows them as the URLs they're
# pretending to be.
-my @servers = ("localhost:8888", # MUST be first -- see PAC pref-setting code
+my @servers = (
+ "localhost:8888", # MUST be first -- see PAC pref-setting code
"example.org:80",
"test1.example.org:80",
"test2.example.org:80",
"sub1.test1.example.org:80",
"sub1.test2.example.org:80",
"sub2.test1.example.org:80",
"sub2.test2.example.org:80",
"example.org:8000",
@@ -123,17 +124,20 @@ my @servers = ("localhost:8888", # MUST
"example.com:80",
"test1.example.com:80",
"test2.example.com:80",
"sub1.test1.example.com:80",
"sub1.test2.example.com:80",
"sub2.test1.example.com:80",
"sub2.test2.example.com:80",
"sectest1.example.org:80",
- "sub.sectest2.example.org:80");
+ "sub.sectest2.example.org:80",
+ "sub1.xn--lt-uia.example.org:8000", # U+00E4 U+006C U+0074
+ "sub2.xn--lt-uia.example.org:80", # U+00E4 U+006C U+0074
+ );
my $profile = "mochitesttestingprofile";
my $profile_dir = "$FindBin::Bin/$profile";
# These are generated in mozilla/testing/mochitest/Makefile.in
#expand my $app = "$FindBin::Bin/" . __BROWSER_PATH__;
#expand my $dist_bin = "$FindBin::Bin/" . __XPC_BIN_PATH__;