Messages in server-sent events, Web
sockets, cross-document messaging, and
channel messaging use the message
event.
The following interface is defined for this event:
interface MessageEvent : Event { readonly attribute any data; readonly attribute DOMString origin; readonly attribute DOMString lastEventId; readonly attribute WindowProxy source; readonly attribute MessagePortArray ports; void initMessageEvent(in DOMString typeArg, in boolean canBubbleArg, in boolean cancelableArg, in any dataArg, in DOMString originArg, in DOMString lastEventIdArg, in WindowProxy sourceArg, in MessagePortArray portsArg); void initMessageEventNS(in DOMString namespaceURI, in DOMString typeArg, in boolean canBubbleArg, in boolean cancelableArg, in any dataArg, in DOMString originArg, in DOMString lastEventIdArg, in WindowProxy sourceArg, in MessagePortArray portsArg); };
data
Returns the data of the message.
origin
Returns the origin of the message, for server-sent events and cross-document messaging.
lastEventId
Returns the last event ID, for server-sent events.
source
Returns the WindowProxy
of the source window, for
cross-document messaging.
ports
Returns the MessagePortArray
sent with the
message, for cross-document messaging and
channel messaging.
The initMessageEvent()
and initMessageEventNS()
methods must initialize the event in a manner analogous to the
similarly-named methods in the DOM3 Events interfaces. [DOM3EVENTS]
The data
attribute represents the message being sent.
The origin
attribute
represents, in server-sent events and
cross-document messaging, the origin of
the document that sent the message (typically the scheme, hostname,
and port of the document, but not its path or fragment
identifier).
The lastEventId
attribute represents, in server-sent events, the
last event ID string of the event source.
The source
attribute
represents, in cross-document messaging, the
WindowProxy
of the browsing context of the
Window
object from which the message came.
The ports
attribute represents, in cross-document messaging and
channel messaging the MessagePortArray
being sent, if any.
Unless otherwise specified, when the user agent creates and
dispatches a message
event in the
algorithms described in the following sections, the lastEventId
attribute
must be the empty string, the origin
attribute must be the
empty string, the source
attribute must be
null, and the ports
attribute
must be null.
Web browsers, for security and privacy reasons, prevent documents in different domains from affecting each other; that is, cross-site scripting is disallowed.
While this is an important security feature, it prevents pages from different domains from communicating even when those pages are not hostile. This section introduces a messaging system that allows documents to communicate with each other regardless of their source domain, in a way designed to not enable cross-site scripting attacks.
The task source for the tasks in cross-document messaging is the posted message task source.
This section is non-normative.
For example, if document A contains an iframe
element that contains document B, and script in document A calls
postMessage()
on the
Window
object of document B, then a message event will
be fired on that object, marked as originating from the
Window
of document A. The script in document A might
look like:
var o = document.getElementsByTagName('iframe')[0]; o.contentWindow.postMessage('Hello world', 'http://b.example.org/');
To register an event handler for incoming events, the script
would use addEventListener()
(or similar
mechanisms). For example, the script in document B might look
like:
window.addEventListener('message', receiver, false); function receiver(e) { if (e.origin == 'http://example.com') { if (e.data == 'Hello world') { e.source.postMessage('Hello', e.origin); } else { alert(e.data); } } }
This script first checks the domain is the expected domain, and then looks at the message, which it either displays to the user, or responds to by sending a message back to the document which sent the message in the first place.
Use of this API requires extra care to protect users from hostile entities abusing a site for their own purposes.
Authors should check the origin
attribute to ensure
that messages are only accepted from domains that they expect to
receive messages from. Otherwise, bugs in the author's message
handling code could be exploited by hostile sites.
Authors should not use the wildcard keyword ("*") in the targetOrigin argument in messages that contain any confidential information, as otherwise there is no way to guarantee that the message is only delivered to the recipient to which it was intended.
The integrity of this API is based on the inability for scripts
of one origin to post arbitrary events (using dispatchEvent()
or otherwise) to objects in other
origins (those that are not the same).
Implementors are urged to take extra care in the implementation of this feature. It allows authors to transmit information from one domain to another domain, which is normally disallowed for security reasons. It also requires that UAs be careful to allow access to certain properties but not others.
postMessage
(message, [ ports, ] targetOrigin)Posts a message, optionally with an array of ports, to the given window.
If the origin of the target window doesn't match the given
origin, the message is discarded, to avoid information leakage. To
send the message to the target regardless of origin, set the
target origin to "*
".
Throws an INVALID_STATE_ERR
if the ports array is not null and it contains
either null entries, duplicate ports, or ports that are not
entangled.
When a script invokes the postMessage(message, targetOrigin)
method (with only two
arguments) on a Window
object, the user agent must
follow these steps:
If the value of the targetOrigin argument
is not a single U+002A ASTERISK character ("*"), and resolving it relative to the
first script's base
URL either fails or results in a URL with a
<host-specific>
component that is neither empty nor a single U+002F SOLIDUS
character (/), then throw a SYNTAX_ERR
exception and
abort the overall set of steps.
Let message clone be the result of obtaining a structured clone of the message argument. If this throws an exception, then throw that exception and abort these steps.
Return from the postMessage()
method, but
asynchronously continue running these steps.
If the targetOrigin argument has a value
other than a single literal U+002A ASTERISK character ("*"), and
the Document
of the Window
object on
which the method was invoked does not have the same
origin as targetOrigin, then abort
these steps silently.
Create an event that uses the MessageEvent
interface, with the event name message
, which does not bubble, is
cancelable, and has no default action. The data
attribute must be set to
the value of message clone, the origin
attribute must be
set to the Unicode serialization of the origin of
the script that invoked the method, and the source
attribute must be
set to the script's global object.
Queue a task to dispatch the event created in the
previous step at the Window
object on which the
method was invoked. The task source for this task is the posted message task
source.
When a script invokes the postMessage(message, ports, targetOrigin)
method (with three
arguments) on a Window
object, the user agent must
follow these steps:
If the value of the targetOrigin argument
is not a single U+002A ASTERISK character ("*"), and resolving it relative to the
first script's base
URL either fails or results in a URL with a
<host-specific>
component that is neither empty nor a single U+002F SOLIDUS
character (/), then throw a SYNTAX_ERR
exception and
abort the overall set of steps.
Let message clone be the result of obtaining a structured clone of the message argument. If this throws an exception, then throw that exception and abort these steps.
If the ports argument is null, then act as if the method had just been called with two arguments, message and targetOrigin.
If any of the entries in ports are
null, if any of the entries in ports
are not entangled MessagePort
objects, or if any
MessagePort
object is listed in ports more than once, then throw an
INVALID_STATE_ERR
exception.
Let new ports be an empty array.
For each port in ports in turn,
obtain a new port by cloning the
port with the Window
object on which the method was
invoked as the owner of the clone, and append the clone to the
new ports array.
If the original ports array was empty, then the new ports array will also be empty.
Return from the postMessage()
method, but
asynchronously continue running these steps.
If the targetOrigin argument has a value
other than a single literal U+002A ASTERISK character ("*"), and
the Document
of the Window
object on
which the method was invoked does not have the same
origin as targetOrigin, then abort
these steps silently.
Create an event that uses the MessageEvent
interface, with the event name message
, which does not bubble, is
cancelable, and has no default action. The data
attribute must be set to
the value of message clone, the origin
attribute must be
set to the Unicode serialization of the origin of
the script that invoked the method, and the source
attribute must be
set to the script's global object.
Let the ports
attribute
of the event be the new ports array.
Queue a task to dispatch the event created in the
previous step at the Window
object on which the
method was invoked. The task source for this task is the posted message task
source.
These steps, with the exception of the second and third steps and the penultimate step, are identical to those in the previous section.
This section is non-normative.
An introduction to the channel and port APIs.
[Constructor] interface MessageChannel { readonly attribute MessagePort port1; readonly attribute MessagePort port2; };
MessageChannel
()Returns a new MessageChannel
object with two new MessagePort
objects.
port1
Returns the first MessagePort
object.
port2
Returns the second MessagePort
object.
When the MessageChannel()
constructor is called, it must run the following algorithm:
Create a new MessagePort
object
owned by the script's global object, and let port1 be that object.
Create a new MessagePort
object
owned by the script's global object, and let port2 be that object.
Entangle the port1 and port2 objects.
Instantiate a new MessageChannel
object, and
let channel be that object.
Let the port1
attribute of the channel object be port1.
Let the port2
attribute of the channel object be port2.
Return channel.
The port1
and
port2
attributes
must return the values they were assigned when the
MessageChannel
object was created.
Each channel has two message ports. Data sent through one port is received by the other port, and vice versa.
typedef sequence<MessagePort> MessagePortArray; interface MessagePort { readonly attribute boolean active; void postMessage(in any message, [Optional] in MessagePortArray ports); void start(); void close(); // event handler attributes attribute Function onmessage; };
active
Returns true if the port is still active; otherwise, returns false.
postMessage
(message [, ports] )Posts a message through the channel, optionally with the given ports.
Throws an INVALID_STATE_ERR
if the ports array is not null and it contains
either null entries, duplicate ports, ports that are not
entangled, or the source or target port.
start
()Begins dispatching messages received on the port.
close
()Disconnects the port, so that it is no longer active.
Objects implementing the MessagePort
interface must
also implement the EventTarget
interface.
Each MessagePort
object can be entangled with
another (a symmetric relationship). Each MessagePort
object also has a task source called the port
message queue, initial empty. A port message
queue can be open or closed, and is initially closed.
When the user agent is to create a new
MessagePort
object owned by a script's
global object object owner, it must
instantiate a new MessagePort
object, and let its owner
be owner.
When the user agent is to entangle two
MessagePort
objects, it must run the following
steps:
If one of the ports is already entangled, then disentangle it and the port that it was entangled with.
If those two previously entangled ports were the
two ports of a MessageChannel
object, then that
MessageChannel
object no longer represents an actual
channel: the two ports in that object are no longer entangled.
Associate the two ports to be entangled, so that they form
the two parts of a new channel. (There is no
MessageChannel
object that represents this
channel.)
When the user agent is to clone a port original port, with the clone being owned by owner, it must run the following steps, which return
either a new MessagePort
object or an exception for the
caller to raise:
If the original port is not entangled
without another port, then return an INVALID_STATE_ERR
exception and abort all these steps.
Let the remote port be the port with which the original port is entangled.
Create a new MessagePort
object
owned by owner, and let new
port be that object.
Move all the events in the port message queue of original port to the port message queue of new port, if any, leaving the new port's port message queue in its initial closed state.
Entangle the remote port and new port objects. The original port object will be disentangled by this process.
Return new port. It is the clone.
The active
attribute must return true if the port is entangled, and false
otherwise.
The postMessage()
method, when called on a port source port, must
cause the user agent to run the following steps:
Let message be the method's first argument.
Let data port be the method's second argument, if any.
Let message clone be the result of obtaining a structured clone of the message argument. If this throws an exception, then throw that exception and abort these steps.
If the source port is not entangled with another port, then return and abort these steps.
Let target port be the port with which source port is entangled.
Create an event that uses the MessageEvent
interface, with the name message
, which does not bubble, is
cancelable, and has no default action.
Let the data
attribute of the event have the value of message
clone.
If the method was called with a second argument ports and that argument isn't null, then run the following substeps:
If any of the entries in ports are
null, if any of the entries in ports
are not entangled MessagePort
objects, or if any
MessagePort
object is listed in ports more than once, then throw an
INVALID_STATE_ERR
exception.
Let new ports be an empty array.
For each port in ports in turn, obtain a new port by cloning the port with the owner of the target port as the owner of the clone, and append the clone to the new ports array.
If the original ports array was empty, then the new ports array will also be empty.
Let the ports
attribute of the event be the new ports
array.
Return from the method, but continue with these steps.
Add the event to the port message queue of target port.
The start()
method must open its port's port message queue, if it
is not already open.
When a port's port message queue is open, the event loop must use it as one of its task sources.
If the Document
of the port's event
handlers' global object
is not fully active, then the messages are lost.
The close()
method, when called on a port local port that is
entangled with another port, must cause the user agents to
disentangle the two ports. If the method is called on a port that is
not entangled, then the method must do nothing.
The following are the event handler attributes (and their corresponding event handler event types)
that must be supported, as DOM attributes, by all objects
implementing the MessagePort
interface:
event handler attribute | Event handler event type |
---|---|
onmessage | message
|
The first time a MessagePort
object's onmessage
DOM attribute
is set, the port's port message queue must be opened,
as if the start()
method
had been called.
User agents must act as if MessagePort
objects have
a strong reference to their entangled MessagePort
object.
Thus, a message port can be received, given an event listener, and then forgotten, and so long as that event listener could receive a message, the channel will be maintained.
Of course, if this was to occur on both sides of the channel, then both ports would be garbage collected, since they would not be reachable from live code, despite having a strong reference to each other.
Furthermore, a MessagePort
object must not be
garbage collected while there exists a message in a task
queue that is to be dispatched on that
MessagePort
object, or while the
MessagePort
object's port message queue is
open and there exists a message
event in that queue.