diff --git a/content/events/src/nsDOMMessageEvent.cpp b/content/events/src/nsDOMMessageEvent.cpp
index a9fb578b8c1..4956d6b393a 100644
--- a/content/events/src/nsDOMMessageEvent.cpp
+++ b/content/events/src/nsDOMMessageEvent.cpp
@@ -71,6 +71,13 @@ nsDOMMessageEvent::GetOrigin(nsAString& aOrigin)
return NS_OK;
}
+NS_IMETHODIMP
+nsDOMMessageEvent::GetLastEventId(nsAString& aLastEventId)
+{
+ aLastEventId = mLastEventId;
+ return NS_OK;
+}
+
NS_IMETHODIMP
nsDOMMessageEvent::GetSource(nsIDOMWindow** aSource)
{
@@ -84,6 +91,7 @@ nsDOMMessageEvent::InitMessageEvent(const nsAString& aType,
PRBool aCancelable,
const nsAString& aData,
const nsAString& aOrigin,
+ const nsAString& aLastEventId,
nsIDOMWindow* aSource)
{
nsresult rv = nsDOMEvent::InitEvent(aType, aCanBubble, aCancelable);
@@ -91,6 +99,7 @@ nsDOMMessageEvent::InitMessageEvent(const nsAString& aType,
mData = aData;
mOrigin = aOrigin;
+ mLastEventId = aLastEventId;
mSource = aSource;
return NS_OK;
@@ -103,6 +112,7 @@ nsDOMMessageEvent::InitMessageEventNS(const nsAString& aNamespaceURI,
PRBool aCancelable,
const nsAString& aData,
const nsAString& aOrigin,
+ const nsAString& aLastEventId,
nsIDOMWindow* aSource)
{
return NS_ERROR_NOT_IMPLEMENTED;
diff --git a/content/events/src/nsDOMMessageEvent.h b/content/events/src/nsDOMMessageEvent.h
index 45a5afb530a..00e68c28f79 100644
--- a/content/events/src/nsDOMMessageEvent.h
+++ b/content/events/src/nsDOMMessageEvent.h
@@ -44,7 +44,8 @@
#include "nsCycleCollectionParticipant.h"
/**
- * Implements the MessageEvent event, used for cross-document messaging.
+ * Implements the MessageEvent event, used for cross-document messaging and
+ * server-sent events.
*
* See http://www.whatwg.org/specs/web-apps/current-work/#messageevent for
* further details.
@@ -69,6 +70,7 @@ public:
private:
nsString mData;
nsString mOrigin;
+ nsString mLastEventId;
nsCOMPtr mSource;
};
diff --git a/dom/public/idl/base/nsIDOMWindowInternal.idl b/dom/public/idl/base/nsIDOMWindowInternal.idl
index a48c27148bd..90a4f51934d 100644
--- a/dom/public/idl/base/nsIDOMWindowInternal.idl
+++ b/dom/public/idl/base/nsIDOMWindowInternal.idl
@@ -44,7 +44,7 @@ interface nsIControllers;
interface nsIDOMLocation;
interface nsIVariant;
-[scriptable, uuid(89b9ff5a-78db-430b-b3b4-66469457435a)]
+[scriptable, uuid(3414EBC7-731F-4697-9F43-ACA6F5050875)]
interface nsIDOMWindowInternal : nsIDOMWindow2
{
readonly attribute nsIDOMWindowInternal window;
@@ -205,15 +205,19 @@ interface nsIDOMWindowInternal : nsIDOMWindow2
* 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.
+ * This method, when called, causes a MessageEvent to be asynchronously
+ * 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 an origin
+ * determined by the calling context's main document URI. The targetOrigin
+ * argument specifies a URI and is used to restrict the message to be sent
+ * only when the target window has the same origin as targetOrigin (since,
+ * when the sender and the target have different origins, neither can read the
+ * location of the other).
*
* See the WHATWG HTML5 specification, section 6.4, for more details.
*/
[binaryname(PostMessageMoz)] void postMessage(in DOMString message,
- [optional] in DOMString origin);
+ in DOMString targetOrigin);
};
diff --git a/dom/public/idl/events/nsIDOMMessageEvent.idl b/dom/public/idl/events/nsIDOMMessageEvent.idl
index 4dec2c3cdf1..bffa6b91c1a 100644
--- a/dom/public/idl/events/nsIDOMMessageEvent.idl
+++ b/dom/public/idl/events/nsIDOMMessageEvent.idl
@@ -43,9 +43,9 @@
* 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
+ * http://www.whatwg.org/specs/web-apps/current-work/#messageevent
*/
-[scriptable, uuid(ca081997-91f9-40c1-890c-3edf39b6c571)]
+[scriptable, uuid(98150805-6A15-4667-815A-1A8C87CB4BBC)]
interface nsIDOMMessageEvent : nsIDOMEvent
{
/**
@@ -60,6 +60,12 @@ interface nsIDOMMessageEvent : nsIDOMEvent
* ":" followed by that port. This value does not have a trailing slash.
*/
readonly attribute DOMString origin;
+
+ /**
+ * The last event ID string of the event source, for server-sent DOM events; this
+ * value is the empty string for cross-origin messaging.
+ */
+ readonly attribute DOMString lastEventId;
/**
* The window which originated this event.
@@ -69,19 +75,20 @@ interface nsIDOMMessageEvent : nsIDOMEvent
/**
* Initializes this event with the given data, in a manner analogous to
* the similarly-named method on the nsIDOMEvent interface, also setting the
- * data, origin, and source attributes of this appropriately.
+ * data, origin, source, and lastEventId attributes of this appropriately.
*/
void initMessageEvent(in DOMString aType,
in boolean aCanBubble,
in boolean aCancelable,
in DOMString aData,
in DOMString aOrigin,
+ in DOMString aLastEventId,
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,
- * origin, and source attributes of this appropriately.
+ * origin, source, and lastEventId attributes of this appropriately.
*/
void initMessageEventNS(in DOMString aNamespaceURI,
in DOMString aType,
@@ -89,5 +96,6 @@ interface nsIDOMMessageEvent : nsIDOMEvent
in boolean aCancelable,
in DOMString aData,
in DOMString aOrigin,
+ in DOMString aLastEventId,
in nsIDOMWindow aSource);
};
diff --git a/dom/src/base/nsGlobalWindow.cpp b/dom/src/base/nsGlobalWindow.cpp
index 18a104296c7..53a3329ccec 100644
--- a/dom/src/base/nsGlobalWindow.cpp
+++ b/dom/src/base/nsGlobalWindow.cpp
@@ -5186,10 +5186,155 @@ nsGlobalWindow::CallerInnerWindow()
return static_cast(win.get());
}
+
+/**
+ * Class used to represent events generated by calls to Window.postMessage,
+ * which asynchronously creates and dispatches events.
+ */
+class PostMessageEvent : public nsRunnable
+{
+ public:
+ NS_DECL_NSIRUNNABLE
+
+ PostMessageEvent(nsGlobalWindow* aSource,
+ const nsAString& aCallerOrigin,
+ const nsAString& aMessage,
+ nsGlobalWindow* aTargetWindow,
+ nsIURI* aProvidedOrigin,
+ PRBool aTrustedCaller)
+ : mSource(aSource),
+ mCallerOrigin(aCallerOrigin),
+ mMessage(aMessage),
+ mTargetWindow(aTargetWindow),
+ mProvidedOrigin(aProvidedOrigin),
+ mTrustedCaller(aTrustedCaller)
+ {
+ MOZ_COUNT_CTOR(PostMessageEvent);
+ }
+
+ ~PostMessageEvent()
+ {
+ MOZ_COUNT_DTOR(PostMessageEvent);
+ }
+
+ private:
+ nsRefPtr mSource;
+ nsString mCallerOrigin;
+ nsString mMessage;
+ nsRefPtr mTargetWindow;
+ nsCOMPtr mProvidedOrigin;
+ PRBool mTrustedCaller;
+};
+
+NS_IMETHODIMP
+PostMessageEvent::Run()
+{
+ NS_ABORT_IF_FALSE(mTargetWindow->IsOuterWindow(),
+ "should have been passed an outer window!");
+ NS_ABORT_IF_FALSE(!mSource || mSource->IsOuterWindow(),
+ "should have been passed an outer window!");
+
+ nsRefPtr targetWindow =
+ mTargetWindow->GetCurrentInnerWindowInternal();
+ NS_ABORT_IF_FALSE(targetWindow->IsInnerWindow(),
+ "we ordered an inner window!");
+
+ // Ensure that any origin which might have been provided is the origin of this
+ // window's document. Note that we do this *now* instead of when postMessage
+ // is called because the target window might have been navigated to a
+ // different location between then and now. If this check happened when
+ // postMessage was called, it would be fairly easy for a malicious webpage to
+ // intercept messages intended for another site by carefully timing navigation
+ // of the target window so it changed location after postMessage but before
+ // now.
+ if (mProvidedOrigin) {
+ // Get the target's origin either from its principal or, in the case the
+ // principal doesn't carry a URI (e.g. the system principal), the target's
+ // document.
+ nsIPrincipal* targetPrin = targetWindow->GetPrincipal();
+ if (!targetPrin)
+ return NS_OK;
+ nsCOMPtr targetURI;
+ if (NS_FAILED(targetPrin->GetURI(getter_AddRefs(targetURI))))
+ return NS_OK;
+ if (!targetURI) {
+ targetURI = targetWindow->mDoc->GetDocumentURI();
+ if (!targetURI)
+ return NS_OK;
+ }
+
+ // Note: This is contrary to the spec with respect to file: URLs, which
+ // the spec groups into a single origin, but given we intentionally
+ // don't do that in other places it seems better to hold the line for
+ // now. Long-term, we want HTML5 to address this so that we can
+ // be compliant while being safer.
+ nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
+ nsresult rv =
+ ssm->CheckSameOriginURI(mProvidedOrigin, targetURI, PR_TRUE);
+ if (NS_FAILED(rv))
+ return NS_OK;
+ }
+
+
+ // Create the event
+ nsCOMPtr docEvent =
+ do_QueryInterface(targetWindow->mDocument);
+ if (!docEvent)
+ return NS_OK;
+ nsCOMPtr event;
+ docEvent->CreateEvent(NS_LITERAL_STRING("MessageEvent"),
+ getter_AddRefs(event));
+ if (!event)
+ return NS_OK;
+
+ nsCOMPtr message = do_QueryInterface(event);
+ nsresult rv = message->InitMessageEvent(NS_LITERAL_STRING("message"),
+ PR_FALSE /* non-bubbling */,
+ PR_TRUE /* cancelable */,
+ mMessage,
+ mCallerOrigin,
+ EmptyString(),
+ mSource);
+ if (NS_FAILED(rv))
+ return NS_OK;
+
+
+ // We can't simply call dispatchEvent on the window because doing so ends
+ // up flipping the trusted bit on the event, and we don't want that to
+ // happen because then untrusted content can call postMessage on a chrome
+ // window if it can get a reference to it.
+
+ nsIPresShell *shell = targetWindow->mDoc->GetPrimaryShell();
+ nsRefPtr presContext;
+ if (shell)
+ presContext = shell->GetPresContext();
+
+ nsEvent* internalEvent;
+ nsCOMPtr privEvent = do_QueryInterface(message);
+ privEvent->SetTrusted(mTrustedCaller);
+ privEvent->GetInternalNSEvent(&internalEvent);
+
+ nsEventStatus status = nsEventStatus_eIgnore;
+ nsEventDispatcher::Dispatch(static_cast(mTargetWindow),
+ presContext,
+ internalEvent,
+ message,
+ &status);
+ return NS_OK;
+}
+
NS_IMETHODIMP
nsGlobalWindow::PostMessageMoz(const nsAString& aMessage, const nsAString& aOrigin)
{
- FORWARD_TO_INNER_CREATE(PostMessageMoz, (aMessage, aOrigin));
+ // NB: Since much of what this method does must happen at event dispatch time,
+ // this method does not forward to the inner window, unlike most other
+ // methods. We do this because the only time we need to refer to this
+ // window, we need a reference to the outer window (the PostMessageEvent
+ // ctor call), and we don't want to pay the price of forwarding to the
+ // inner window for no actual benefit. Furthermore, this function must
+ // only be called from script anyway, which should only have references to
+ // outer windows (and if script has an inner window we've already lost).
+ NS_ABORT_IF_FALSE(IsOuterWindow(), "only call this method on outer windows");
//
// Window.postMessage is an intentional subversion of the same-origin policy.
@@ -5199,30 +5344,36 @@ nsGlobalWindow::PostMessageMoz(const nsAString& aMessage, const nsAString& aOrig
// http://www.whatwg.org/specs/web-apps/current-work/multipage/section-crossDocumentMessages.html
//
-
// First, get the caller's window
nsRefPtr callerInnerWin = CallerInnerWindow();
if (!callerInnerWin)
return NS_OK;
- NS_ASSERTION(callerInnerWin->IsInnerWindow(), "should have gotten an inner window here");
+ NS_ABORT_IF_FALSE(callerInnerWin->IsInnerWindow(),
+ "should have gotten an inner window here");
// Compute the caller's origin either from its principal or, in the case the
// principal doesn't carry a URI (e.g. the system principal), the caller's
- // document.
+ // document. We must get this now instead of when the event is created and
+ // dispatched, because ultimately it is the identity of the calling window
+ // *now* that determines who sent the message (and not an identity which might
+ // have changed due to intervening navigations).
nsIPrincipal* callerPrin = callerInnerWin->GetPrincipal();
if (!callerPrin)
return NS_OK;
- nsCOMPtr callerURI;
- if (NS_FAILED(callerPrin->GetURI(getter_AddRefs(callerURI))))
+ nsCOMPtr callerOuterURI;
+ if (NS_FAILED(callerPrin->GetURI(getter_AddRefs(callerOuterURI))))
return NS_OK;
- if (!callerURI) {
+ if (!callerOuterURI) {
nsCOMPtr doc = do_QueryInterface(callerInnerWin->mDocument);
if (!doc)
return NS_OK;
- callerURI = doc->GetDocumentURI();
- if (!callerURI)
+ callerOuterURI = doc->GetDocumentURI();
+ if (!callerOuterURI)
return NS_OK;
}
+ nsCOMPtr callerURI = NS_GetInnermostURI(callerOuterURI);
+ if (!callerURI)
+ return NS_OK;
const nsCString& empty = EmptyCString();
nsCOMPtr callerOrigin;
if (NS_FAILED(callerURI->Clone(getter_AddRefs(callerOrigin))) ||
@@ -5230,97 +5381,33 @@ nsGlobalWindow::PostMessageMoz(const nsAString& aMessage, const nsAString& aOrig
return NS_OK;
- // Calling postMessage on a closed window does nothing.
- if (!mDocument)
- return NS_OK;
-
- nsCOMPtr targetDoc = do_QueryInterface(mDocument);
- nsCOMPtr docEvent = do_QueryInterface(mDocument);
-
-
- // Ensure that any origin which might have been provided is the origin of this
- // window's document.
- if (!aOrigin.IsVoid()) {
- nsCOMPtr providedOrigin;
+ // Convert the provided origin string into a URI for comparison purposes.
+ // "*" indicates no specific origin is required.
+ nsCOMPtr providedOrigin;
+ if (!aOrigin.EqualsASCII("*")) {
if (NS_FAILED(NS_NewURI(getter_AddRefs(providedOrigin), aOrigin)))
return NS_ERROR_DOM_SYNTAX_ERR;
if (NS_FAILED(providedOrigin->SetUserPass(empty)) ||
NS_FAILED(providedOrigin->SetPath(empty)))
return NS_OK;
-
- // Get the target's origin either from its principal or, in the case the
- // principal doesn't carry a URI (e.g. the system principal), the target's
- // document.
- nsIPrincipal* targetPrin = GetPrincipal();
- if (!targetPrin)
- return NS_OK;
- nsCOMPtr targetURI;
- if (NS_FAILED(targetPrin->GetURI(getter_AddRefs(targetURI))))
- return NS_OK;
- if (!targetURI) {
- nsCOMPtr targetDoc = do_QueryInterface(mDocument);
- if (!targetDoc)
- return NS_OK;
- targetURI = targetDoc->GetDocumentURI();
- if (!targetURI)
- return NS_OK;
- }
- nsCOMPtr targetOrigin;
- if (NS_FAILED(targetURI->Clone(getter_AddRefs(targetOrigin))) ||
- NS_FAILED(targetOrigin->SetUserPass(empty)) ||
- NS_FAILED(targetOrigin->SetPath(empty)))
- return NS_OK;
-
- PRBool equal = PR_FALSE;
- if (NS_FAILED(targetOrigin->Equals(providedOrigin, &equal)) || !equal)
- return NS_OK;
}
-
- // Create the event
- nsCOMPtr event;
- docEvent->CreateEvent(NS_LITERAL_STRING("MessageEvent"),
- getter_AddRefs(event));
- if (!event)
- return NS_OK;
-
nsCAutoString origin;
if (NS_FAILED(callerOrigin->GetPrePath(origin)))
return NS_OK;
- nsCOMPtr message = do_QueryInterface(event);
- nsresult rv = message->InitMessageEvent(NS_LITERAL_STRING("message"),
- PR_TRUE /* bubbling */,
- PR_TRUE /* cancelable */,
- aMessage,
- NS_ConvertUTF8toUTF16(origin),
- nsContentUtils::IsCallerChrome()
- ? nsnull
- : callerInnerWin->GetOuterWindowInternal());
- if (NS_FAILED(rv))
- return NS_OK;
-
-
- // Finally, dispatch the event, ignoring the result to prevent an exception
- // from revealing anything about the document for this window.
- PRBool dummy;
- 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;
+ // Create and asynchronously dispatch a runnable which will handle actual DOM
+ // event creation and dispatch.
+ nsRefPtr event =
+ new PostMessageEvent(nsContentUtils::IsCallerChrome()
+ ? nsnull
+ : callerInnerWin->GetOuterWindowInternal(),
+ NS_ConvertUTF8toUTF16(origin),
+ aMessage,
+ this,
+ providedOrigin,
+ nsContentUtils::IsCallerTrustedForWrite());
+ return NS_DispatchToCurrentThread(event);
}
class nsCloseEvent : public nsRunnable {
diff --git a/dom/src/base/nsGlobalWindow.h b/dom/src/base/nsGlobalWindow.h
index 15fbd896aed..e16e1bd097f 100644
--- a/dom/src/base/nsGlobalWindow.h
+++ b/dom/src/base/nsGlobalWindow.h
@@ -122,6 +122,7 @@ class nsGlobalWindow;
#ifdef OJI
class nsDummyJavaPluginOwner;
#endif
+class PostMessageEvent;
class nsDOMOfflineResourceList;
class nsDOMOfflineLoadStatusList;
@@ -743,6 +744,7 @@ protected:
friend class nsDOMScriptableHelper;
friend class nsDOMWindowUtils;
+ friend class PostMessageEvent;
static nsIFactory *sComputedDOMStyleFactory;
};
diff --git a/dom/tests/mochitest/bugs/iframe_bug407839-1.html b/dom/tests/mochitest/bugs/iframe_bug407839-1.html
index 72b6a6dc1ac..612596f1824 100644
--- a/dom/tests/mochitest/bugs/iframe_bug407839-1.html
+++ b/dom/tests/mochitest/bugs/iframe_bug407839-1.html
@@ -57,7 +57,7 @@ function run()
catch (ex) {
}
- window.parent.postMessage(message);
+ window.parent.postMessage(message, "http://localhost:8888");
}
window.addEventListener("load", run, false);
diff --git a/dom/tests/mochitest/bugs/iframe_bug407839-2.html b/dom/tests/mochitest/bugs/iframe_bug407839-2.html
index af6f3b3dcef..5889d161cef 100644
--- a/dom/tests/mochitest/bugs/iframe_bug407839-2.html
+++ b/dom/tests/mochitest/bugs/iframe_bug407839-2.html
@@ -23,7 +23,7 @@ function run()
message += "\n failed globalStorage[sub1.ält.example.org]";
}
- window.parent.postMessage(message);
+ window.parent.postMessage(message, "http://localhost:8888");
}
window.addEventListener("load", run, false);
diff --git a/dom/tests/mochitest/bugs/iframe_bug409349.html b/dom/tests/mochitest/bugs/iframe_bug409349.html
index 2aef169893f..ba9c2db904e 100644
--- a/dom/tests/mochitest/bugs/iframe_bug409349.html
+++ b/dom/tests/mochitest/bugs/iframe_bug409349.html
@@ -52,7 +52,7 @@ function run()
catch (ex) {
}
- window.parent.postMessage(message);
+ window.parent.postMessage(message, "http://localhost:8888");
}
window.addEventListener("load", run, false);
diff --git a/dom/tests/mochitest/bugs/iframe_bug424093.html b/dom/tests/mochitest/bugs/iframe_bug424093.html
index 2b4d304c406..cceda24b06b 100644
--- a/dom/tests/mochitest/bugs/iframe_bug424093.html
+++ b/dom/tests/mochitest/bugs/iframe_bug424093.html
@@ -31,7 +31,7 @@ function run()
message += "\n failed globalStorage[\"example.org\"]";
}
-window.parent.postMessage(message);
+ window.parent.postMessage(message, "http://localhost:8888");
}
window.addEventListener("load", run, false);
diff --git a/dom/tests/mochitest/bugs/test_bug407839.html b/dom/tests/mochitest/bugs/test_bug407839.html
index e2a1bddd616..cd020ea699b 100644
--- a/dom/tests/mochitest/bugs/test_bug407839.html
+++ b/dom/tests/mochitest/bugs/test_bug407839.html
@@ -36,7 +36,7 @@ function receiveMessage(evt)
}
}
-document.addEventListener("message", receiveMessage, false);
+window.addEventListener("message", receiveMessage, false);
diff --git a/dom/tests/mochitest/bugs/test_bug409349.html b/dom/tests/mochitest/bugs/test_bug409349.html
index a1c9fa9a6bc..5aee9be3c6a 100644
--- a/dom/tests/mochitest/bugs/test_bug409349.html
+++ b/dom/tests/mochitest/bugs/test_bug409349.html
@@ -29,7 +29,7 @@ function receiveMessage(evt)
SimpleTest.finish();
}
-document.addEventListener("message", receiveMessage, false);
+window.addEventListener("message", receiveMessage, false);
diff --git a/dom/tests/mochitest/whatwg/postMessage_closed_helper.html b/dom/tests/mochitest/whatwg/postMessage_closed_helper.html
index 10ea828d4fb..cb4d26b592f 100644
--- a/dom/tests/mochitest/whatwg/postMessage_closed_helper.html
+++ b/dom/tests/mochitest/whatwg/postMessage_closed_helper.html
@@ -5,17 +5,17 @@
diff --git a/dom/tests/mochitest/whatwg/postMessage_helper.html b/dom/tests/mochitest/whatwg/postMessage_helper.html
index 8cacfb6cd0b..d11f609789d 100644
--- a/dom/tests/mochitest/whatwg/postMessage_helper.html
+++ b/dom/tests/mochitest/whatwg/postMessage_helper.html
@@ -8,13 +8,17 @@
function setup()
{
- $("domain").textContent = location.hostname + ":" + (location.port || 80);
+ var target = $("domain");
+ target.textContent = location.hostname + ":" + (location.port || 80);
}
function receiveMessage(evt)
{
var response = evt.data + "-response";
+ if (evt.lastEventId !== "")
+ response += " wrong-lastEventId(" + evt.lastEventId + ")";
+
if (evt.source !== window.parent)
{
response += " unexpected-source(" + evt.source + ")";
@@ -22,8 +26,11 @@
response += " location(" + window.location.href + ")";
}
- if (isMozilla && evt.isTrusted)
- response += " unexpected-trusted";
+ if (isMozilla)
+ {
+ if (evt.isTrusted !== false)
+ response += " unexpected-trusted";
+ }
if (evt.type != "message")
response += " wrong-type(" + evt.type + ")";
@@ -40,7 +47,7 @@
else
{
response += " unexpected-message-to(" + window.location.href + ")";
- window.parent.postMessage(response);
+ window.parent.postMessage(response, "http://localhost:8888");
return;
}
}
@@ -68,7 +75,7 @@
}
finally
{
- source.postMessage(response);
+ source.postMessage(response, evt.origin);
}
}
@@ -90,11 +97,11 @@
if (!threw || privateVariable !== undefined)
response += " accessed-source!!!";
- source.postMessage(response);
+ source.postMessage(response, evt.origin);
}
window.addEventListener("load", setup, false);
- document.addEventListener("message", receiveMessage, false);
+ window.addEventListener("message", receiveMessage, false);
diff --git a/dom/tests/mochitest/whatwg/postMessage_idn_helper.html b/dom/tests/mochitest/whatwg/postMessage_idn_helper.html
index 9b637a6ffc1..e87e5ca545d 100644
--- a/dom/tests/mochitest/whatwg/postMessage_idn_helper.html
+++ b/dom/tests/mochitest/whatwg/postMessage_idn_helper.html
@@ -13,21 +13,23 @@
response += " wrong-sender-origin(" + evt.origin + ")";
if (evt.data !== "idn-message")
response += " wrong-data(" + evt.data + ")";
+ if (evt.lastEventId !== "")
+ response += " wrong-lastEventId(" + evt.lastEventId + ")";
if (evt.source !== window.parent)
response += " wrong-source";
- if (evt.target !== document)
+ if (evt.target !== window)
response += " wrong-target";
if (evt.type !== "message")
response += " wrong-type(" + evt.type + ")";
- evt.source.postMessage(response);
+ evt.source.postMessage(response, evt.origin);
}
- document.addEventListener("message", receiveMessage, false);
+ window.addEventListener("message", receiveMessage, false);
function setup()
{
var target = document.getElementById("location");
- target.textContent = document.domain;
+ target.textContent = location.hostname + ":" + (location.port || 80);
}
window.addEventListener("load", setup, false);
diff --git a/dom/tests/mochitest/whatwg/postMessage_joined_helper.html b/dom/tests/mochitest/whatwg/postMessage_joined_helper.html
index 228552c7614..1c88223e023 100644
--- a/dom/tests/mochitest/whatwg/postMessage_joined_helper.html
+++ b/dom/tests/mochitest/whatwg/postMessage_joined_helper.html
@@ -9,28 +9,34 @@ http://sub1.test1.example.org/tests/dom/tests/mochitest/whatwg/postMessage_joine
diff --git a/dom/tests/mochitest/whatwg/postMessage_origin_helper.xhtml b/dom/tests/mochitest/whatwg/postMessage_origin_helper.xhtml
index 39682849e16..0784980fb45 100644
--- a/dom/tests/mochitest/whatwg/postMessage_origin_helper.xhtml
+++ b/dom/tests/mochitest/whatwg/postMessage_origin_helper.xhtml
@@ -1,7 +1,7 @@
- postMessage throwing page
+ postMessage origin-testing helper page
diff --git a/dom/tests/mochitest/whatwg/postMessage_throw_helper.html b/dom/tests/mochitest/whatwg/postMessage_throw_helper.html
index 8d68aed509b..b3d22c65740 100644
--- a/dom/tests/mochitest/whatwg/postMessage_throw_helper.html
+++ b/dom/tests/mochitest/whatwg/postMessage_throw_helper.html
@@ -7,12 +7,12 @@
{
throw 17;
}
- document.addEventListener("message", receiveMessage, false);
+ window.addEventListener("message", receiveMessage, false);
function setup()
{
var target = document.getElementById("location");
- target.textContent = document.domain;
+ target.textContent = location.hostname + ":" + (location.port || 80);
}
window.addEventListener("load", setup, false);
diff --git a/dom/tests/mochitest/whatwg/postMessage_userpass_helper.html b/dom/tests/mochitest/whatwg/postMessage_userpass_helper.html
index 215007399d1..25309e6bcb0 100644
--- a/dom/tests/mochitest/whatwg/postMessage_userpass_helper.html
+++ b/dom/tests/mochitest/whatwg/postMessage_userpass_helper.html
@@ -11,6 +11,8 @@ function sendMessage(evt)
msg += " wrong-origin(" + evt.origin + ")";
if (evt.data !== "parent-message")
msg += " wrong-data(" + evt.data + ")";
+ if (evt.lastEventId !== "")
+ msg += " wrong-lastEventId(" + evt.lastEventId + ")";
if (evt.source !== window.parent)
msg += " wrong-source";
@@ -18,10 +20,10 @@ function sendMessage(evt)
// "bobhope:password", but Gecko elides that from the content-visible URL,
// and I can't find another way to actually detect this programmatically.
- window.parent.postMessage(msg);
+ window.parent.postMessage(msg, "http://localhost:8888");
}
-document.addEventListener("message", sendMessage, false);
+window.addEventListener("message", sendMessage, false);
diff --git a/dom/tests/mochitest/whatwg/test_MessageEvent.html b/dom/tests/mochitest/whatwg/test_MessageEvent.html
index 0db1aa4f809..3b065e14e72 100644
--- a/dom/tests/mochitest/whatwg/test_MessageEvent.html
+++ b/dom/tests/mochitest/whatwg/test_MessageEvent.html
@@ -28,6 +28,7 @@ SimpleTest.waitForExplicitFinish();
var data = "foobar";
var origin = "http://cool.example.com";
var bubbles = true, cancelable = true;
+var lastEventId = "lastEventId";
var target;
@@ -43,16 +44,21 @@ function sendMsg()
if (isMozilla)
{
is(evt.source, null,
- "not initialized yet, so null in our implementation");
+ "not initialized yet, so null in our implementation");
+ is(evt.lastEventId, "",
+ "not initialized yet, so empty string in our implementation");
}
- evt.initMessageEvent("message", bubbles, cancelable, data, origin, null);
+ evt.initMessageEvent("message", bubbles, cancelable, data, origin,
+ lastEventId, null);
ok(evt.source === null, "null source is fine for a MessageEvent");
- evt.initMessageEvent("message", bubbles, cancelable, data, origin, window);
+ evt.initMessageEvent("message", bubbles, cancelable, data, origin,
+ lastEventId, window);
is(evt.data, data, "unexpected data");
is(evt.origin, origin, "unexpected origin");
+ is(evt.lastEventId, lastEventId, "unexpected lastEventId");
is(evt.cancelable, cancelable, "wrong cancelable property");
is(evt.bubbles, bubbles, "wrong bubbling property");
@@ -71,6 +77,7 @@ function recvMsg(evt)
{
is(evt.data, data, "unexpected data");
is(evt.origin, origin, "unexpected origin");
+ is(evt.lastEventId, lastEventId, "unexpected lastEventId");
is(evt.cancelable, cancelable, "wrong cancelable property");
is(evt.bubbles, bubbles, "wrong bubbling property");
diff --git a/dom/tests/mochitest/whatwg/test_MessageEvent_dispatchToOther.html b/dom/tests/mochitest/whatwg/test_MessageEvent_dispatchToOther.html
index 327aa9fd25a..494d43d7dd9 100644
--- a/dom/tests/mochitest/whatwg/test_MessageEvent_dispatchToOther.html
+++ b/dom/tests/mochitest/whatwg/test_MessageEvent_dispatchToOther.html
@@ -28,7 +28,8 @@ function run()
{
var msg = document.createEvent("MessageEvent");
msg.initMessageEvent("message", true, true,
- "foo", "http://evil.com", window);
+ "foo", "http://evil.com", "",
+ window);
try
{
diff --git a/dom/tests/mochitest/whatwg/test_postMessage.html b/dom/tests/mochitest/whatwg/test_postMessage.html
index c905d4c3678..ccf19a6ce59 100644
--- a/dom/tests/mochitest/whatwg/test_postMessage.html
+++ b/dom/tests/mochitest/whatwg/test_postMessage.html
@@ -27,20 +27,30 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=postMessage
SimpleTest.waitForExplicitFinish();
-var testsCompletedCount = 0;
-
/** Variable for receivers to attempt to get. */
window.privateVariable = 17;
-/** For sentinel finish, if necessary in deficient browsers */
+/** For sentinel finish, if necessary in deficient browsers. */
var finished = false;
-/** Receives MessageEvents to this window. */
+/** Ends testing if it isn't already done. */
+function finish()
+{
+ if (!finished)
+ {
+ finished = true;
+ SimpleTest.finish();
+ }
+}
+
+/** Receives MessageEvents. */
function messageReceiver(evt)
{
try
{
ok(evt instanceof MessageEvent, "umm, how did we get this?");
+ is(evt.lastEventId, "",
+ "postMessage creates events with empty lastEventId");
is(evt.type, "message", "expected events of type 'message'");
if (isMozilla)
@@ -61,8 +71,6 @@ function messageReceiver(evt)
switch (evt.data)
{
- case "post-to-self":
-
case "post-to-self-response":
receiveSelf(evt);
break;
@@ -73,23 +81,21 @@ function messageReceiver(evt)
case "post-to-other-cross-domain-response":
receiveOtherCrossDomain(evt);
+
+ // All the tests have executed, so we're done.
+ finish();
break;
default:
ok(false, "unexpected message: " + evt.data);
+ finish();
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();
+ finish();
}
}
@@ -103,7 +109,7 @@ function respondToSelf(evt)
is(evt.origin, "http://localhost:8888", "event has wrong origin");
is(evt.source, window, "we posted this message!");
- evt.source.postMessage("post-to-self-response");
+ evt.source.postMessage("post-to-self-response", evt.origin);
}
@@ -115,6 +121,9 @@ function receiveSelf(evt)
{
is(evt.origin, "http://localhost:8888", "event has wrong origin");
is(evt.source, window, "we posted this message!");
+
+ window.frames.otherSameDomain.postMessage("post-to-other-same-domain",
+ "http://localhost:8888");
}
function receiveOtherSameDomain(evt)
@@ -123,6 +132,9 @@ function receiveOtherSameDomain(evt)
"same-domain response event has wrong origin");
is(evt.source, window.frames.otherSameDomain,
"wrong source for same-domain message!");
+
+ window.frames.otherCrossDomain.postMessage("post-to-other-cross-domain",
+ "http://example.org:8000");
}
function receiveOtherCrossDomain(evt)
@@ -141,55 +153,14 @@ function receiveOtherCrossDomain(evt)
* 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 start()
{
- function dispatcher()
- {
- try
- {
- destination.postMessage(message);
- }
- catch (e)
- {
- ok(false, "error while calling postMessage: " + e);
- }
- }
-
- return dispatcher;
+ window.postMessage("post-to-self", "http://localhost:8888");
}
-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),
- ];
+window.addEventListener("load", start, false);
+window.addEventListener("message", messageReceiver, false);
-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);
diff --git a/dom/tests/mochitest/whatwg/test_postMessage_basehref.html b/dom/tests/mochitest/whatwg/test_postMessage_basehref.html
index 06ed2862001..6da4992ae14 100644
--- a/dom/tests/mochitest/whatwg/test_postMessage_basehref.html
+++ b/dom/tests/mochitest/whatwg/test_postMessage_basehref.html
@@ -28,15 +28,16 @@ function receiveMessage(evt)
ok(evt.source === window, "wrong source");
is(evt.data, "generate-event", "wrong data");
+ is(evt.lastEventId, "", "wrong lastEventId");
SimpleTest.finish();
}
-document.addEventListener("message", receiveMessage, false);
+window.addEventListener("message", receiveMessage, false);
function run()
{
- window.postMessage("generate-event");
+ window.postMessage("generate-event", "http://localhost:8888");
}
window.addEventListener("load", run, false);
diff --git a/dom/tests/mochitest/whatwg/test_postMessage_chrome.html b/dom/tests/mochitest/whatwg/test_postMessage_chrome.html
index 275969fc1b3..75d6c4b629a 100644
--- a/dom/tests/mochitest/whatwg/test_postMessage_chrome.html
+++ b/dom/tests/mochitest/whatwg/test_postMessage_chrome.html
@@ -29,13 +29,22 @@ chrome://mochikit/content/chrome/dom/tests/mochitest/whatwg/test_postMessage_chr
SimpleTest.waitForExplicitFinish();
-var testsCompletedCount = 0;
+var finished = false;
+function finish()
+{
+ if (!finished)
+ {
+ finished = true;
+ SimpleTest.finish();
+ }
+}
/** 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'");
+ is(evt.lastEventId, "", "postMessage creates events with empty lastEventId");
switch (evt.data)
{
@@ -49,12 +58,9 @@ function messageReceiver(evt)
default:
ok(false, "unexpected message: " + evt.data);
+ finish();
break;
}
-
- // if all the tests have executed, we're done
- if (++testsCompletedCount == allTests.length)
- setTimeout(SimpleTest.finish, 0);
}
@@ -67,6 +73,9 @@ function checkSelf(evt)
is(evt.isTrusted, true, "should have sent a trusted event");
is(evt.origin, "chrome://mochikit", "wrong origin for chrome: URL");
is(evt.source, null, "chrome posters get a null source, for security");
+
+ window.frames.contentDomain.postMessage("post-to-content",
+ "http://example.org");
}
@@ -80,6 +89,8 @@ function receiveContent(evt)
is(evt.origin, "http://example.org", "content response event has wrong URI");
is(evt.source, window.frames.contentDomain,
"wrong source for same-domain message!");
+
+ finish();
}
@@ -87,25 +98,13 @@ function receiveContent(evt)
* 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 run()
{
- return function() { destination.postMessage(message); };
+ window.addEventListener("message", messageReceiver, false);
+ window.postMessage("post-to-self", "*");
}
-var allTests =
- [
- createMessageDispatcher("post-to-self", window),
- createMessageDispatcher("post-to-content",
- window.frames.contentDomain),
- ];
-
-allTests.forEach(addLoadEvent);
+window.addEventListener("load", run, false);
diff --git a/dom/tests/mochitest/whatwg/test_postMessage_closed.html b/dom/tests/mochitest/whatwg/test_postMessage_closed.html
index 5820bc3650b..3fc8d85e890 100644
--- a/dom/tests/mochitest/whatwg/test_postMessage_closed.html
+++ b/dom/tests/mochitest/whatwg/test_postMessage_closed.html
@@ -23,6 +23,7 @@ function receiveMessage(evt)
{
is(evt.origin, "http://localhost:8888", "wrong origin");
ok(evt.source === openedWindow, "wrong source");
+ is(evt.lastEventId, "", "postMessage creates events with empty lastEventId");
is(evt.data, "message", "wrong data");
if (evt.data !== "message")
@@ -33,7 +34,7 @@ function receiveMessage(evt)
function afterClose()
{
document.removeEventListener("message", receiveMessage, false);
- evt.source.postMessage("NOT-RECEIVED");
+ evt.source.postMessage("NOT-RECEIVED", "*");
var iframe = document.createElement("iframe");
iframe.id = "insertedIframe";
@@ -45,7 +46,7 @@ function receiveMessage(evt)
setTimeout(afterClose, 0);
}
-document.addEventListener("message", receiveMessage, false);
+window.addEventListener("message", receiveMessage, false);
function iframeLoaded(evt)
{
@@ -54,7 +55,7 @@ function iframeLoaded(evt)
var iframeWindow = iframe.contentWindow;
$("holder").removeChild($("insertedIframe"));
- iframeWindow.postMessage("NOT-RECEIVED");
+ iframeWindow.postMessage("NOT-RECEIVED", "*");
SimpleTest.finish();
}
diff --git a/dom/tests/mochitest/whatwg/test_postMessage_hash.html b/dom/tests/mochitest/whatwg/test_postMessage_hash.html
index 008892aa731..0645cbdf053 100644
--- a/dom/tests/mochitest/whatwg/test_postMessage_hash.html
+++ b/dom/tests/mochitest/whatwg/test_postMessage_hash.html
@@ -25,17 +25,18 @@ function receiveMessage(evt)
{
is(evt.origin, "http://localhost:8888", "wrong origin");
ok(evt.source === window.frames.kid, "wrong source");
+ is(evt.lastEventId, "", "postMessage creates events with empty lastEventId");
is(evt.data, "response-message", "wrong data");
SimpleTest.finish();
}
-document.addEventListener("message", receiveMessage, false);
+window.addEventListener("message", receiveMessage, false);
function run()
{
- window.frames.kid.postMessage("from-parent");
+ window.frames.kid.postMessage("from-parent", "http://localhost:8888");
}
window.addEventListener("load", run, false);
diff --git a/dom/tests/mochitest/whatwg/test_postMessage_idn.xhtml b/dom/tests/mochitest/whatwg/test_postMessage_idn.xhtml
index 0391b19332a..5bd486f4c01 100644
--- a/dom/tests/mochitest/whatwg/test_postMessage_idn.xhtml
+++ b/dom/tests/mochitest/whatwg/test_postMessage_idn.xhtml
@@ -41,30 +41,28 @@ function receiveMessage(evt)
"wrong origin -- IDN issue, perhaps?");
is(evt.data, "idn-response", "unexpected test result");
+ is(evt.lastEventId, "", "postMessage creates events with empty lastEventId");
ok(evt.source === idnWindow, "wrong source");
- responseReceived = true;
+ SimpleTest.finish();
}
-document.addEventListener("message", receiveMessage, false);
+window.addEventListener("message", receiveMessage, false);
var xhtmlns = "http://www.w3.org/1999/xhtml";
function setup()
{
+ var idnFrame = document.getElementsByTagNameNS(xhtmlns, "iframe")[0];
+ idnWindow = idnFrame.contentWindow;
try
{
- var idnFrame = document.getElementsByTagNameNS(xhtmlns, "iframe")[0];
- idnWindow = idnFrame.contentWindow;
- idnWindow.postMessage("idn-message");
-
- ok(responseReceived, "should have gotten a response before returning");
+ idnWindow.postMessage("idn-message", "http://sub1.ält.example.org:8000");
}
catch (e)
{
ok(false, "failed to post message: " + e);
+ SimpleTest.finish();
}
-
- SimpleTest.finish();
}
addLoadEvent(setup);
diff --git a/dom/tests/mochitest/whatwg/test_postMessage_jar.html b/dom/tests/mochitest/whatwg/test_postMessage_jar.html
new file mode 100644
index 00000000000..ef33ea61790
--- /dev/null
+++ b/dom/tests/mochitest/whatwg/test_postMessage_jar.html
@@ -0,0 +1,50 @@
+
+
+
+
+ postMessage's interaction with pages at jar: URIs
+
+
+
+
+
+
+
+Mozilla Bug 430251
+
+
+
+
+
+
+
+
+
+
diff --git a/dom/tests/mochitest/whatwg/test_postMessage_joined.html b/dom/tests/mochitest/whatwg/test_postMessage_joined.html
index 5e7d6daae13..9f294bdfa57 100644
--- a/dom/tests/mochitest/whatwg/test_postMessage_joined.html
+++ b/dom/tests/mochitest/whatwg/test_postMessage_joined.html
@@ -35,27 +35,20 @@ function receiveTestResult(evt)
ok(evt.isTrusted === false, "shouldn't have been a trusted event");
}
- var data = evt.data;
-
+ is(evt.lastEventId, "", "postMessage creates events with empty lastEventId");
+
// 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");
+ is(evt.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();
- }
+ window.addEventListener("message", receiveTestResult, false);
+ window.frames.container.postMessage("start-test",
+ "http://sub1.test1.example.org");
}
addLoadEvent(setup);
diff --git a/dom/tests/mochitest/whatwg/test_postMessage_onOther.html b/dom/tests/mochitest/whatwg/test_postMessage_onOther.html
index c4cba137898..8bf3063e754 100644
--- a/dom/tests/mochitest/whatwg/test_postMessage_onOther.html
+++ b/dom/tests/mochitest/whatwg/test_postMessage_onOther.html
@@ -14,10 +14,10 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=postMessage
-
-
+
+
@@ -26,50 +26,26 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=postMessage
SimpleTest.waitForExplicitFinish();
-var finished = false;
-
/** Receives MessageEvents to this window. */
function messageReceiver(evt)
{
ok(evt instanceof MessageEvent, "wrong event type");
- is(evt.origin, "http://example.org:8000", "unexpected origin");
- is(evt.data, "response-to-sibling-sent-message",
+ is(evt.origin, "http://test1.example.com", "unexpected origin");
+ is(evt.lastEventId, "", "postMessage creates events with empty lastEventId");
+ is(evt.data, "test-finished",
"unexpected data in message");
- // Handle buggy browsers that might somehow have received a message twice
- if (finished)
- return;
-
- finished = true;
SimpleTest.finish();
}
-function postToSecondFrameThroughFirstFrame()
+function run()
{
- try
- {
- window.frames.firstFrame.testSiblingPostMessage();
- }
- catch (e)
- {
- ok(false, "threw exception trying to post through firstFrame: " + e);
- }
+ window.frames.subDomainFrame.postMessage("start-test",
+ "http://test1.example.com");
}
-/** 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);
+window.addEventListener("message", messageReceiver, false);
+window.addEventListener("load", run, false);