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 DOMString data;
readonly attribute DOMString origin;
readonly attribute DOMString lastEventId;
readonly attribute Window source;
readonly attribute MessagePort messagePort;
void initMessageEvent(in DOMString typeArg, in boolean canBubbleArg, in boolean cancelableArg, in DOMString dataArg, in DOMString originArg, in DOMString lastEventIdArg, in Window sourceArg, in MessagePort messagePortArg);
void initMessageEventNS(in DOMString namespaceURI, in DOMString typeArg, in boolean canBubbleArg, in boolean cancelableArg, in DOMString dataArg, in DOMString originArg, in DOMString lastEventIdArg, in Window sourceArg, in MessagePort messagePortArg);
};
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
Window from which the message came.
The messagePort
attribute represents, in cross-document messaging and
channel messaging the MessagePort 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 messagePort
attribute must be null.
Tasks in server-sent events and Web Sockets use their own task sources, but the task source for the tasks in cross-document messaging and channel messaging is the posted message task source.
This section describes a mechanism for allowing servers to
dispatch DOM events into documents that expect it. The
eventsource element provides a simple interface to
this mechanism.
RemoteEventTarget interfaceAny object that implements the EventTarget interface
must also implement the RemoteEventTarget
interface.
interface RemoteEventTarget {
void addEventSource(in DOMString src);
void removeEventSource(in DOMString src);
};
When the addEventSource(src) method is invoked, the user agent
must resolve the URL
specified in src, and if that succeeds, add the resulting absolute URL
to the list of event
sources for that object. The same URL can be registered
multiple times. If the URL fails to resolve, then the user agent
must raise a SYNTAX_ERR exception.
When the removeEventSource(src) method is invoked, the user agent
must resolve the URL
specified in src, and if that succeeds, remove
the resulting absolute URL from the list of event sources for
that object. If the same URL has been registered multiple times,
removing it must remove only one instance of that URL for each
invocation of the removeEventSource() method. If the
URL fails to resolve, the user agent does nothing.
Each object implementing the EventTarget and
RemoteEventTarget interfaces has a list of event sources that
are registered for that object.
When a new absolute URL is added to this list, the user agent should queue a task to run the following steps with the new absolute URL:
If the entry for the new absolute URL has been removed from the list, then abort these steps.
Fetch the resource identified by that absolute URL.
As data is received, the tasks queued by the networking task source to handle the data must consist of following the rules given in the following sections.
When an event source is removed from the list of event sources for an object, if that resource is still being fetched, then the relevant connection must be closed.
Since connections established to remote servers for such resources are expected to be long-lived, UAs should ensure that appropriate buffering is used. In particular, while line buffering may be safe if lines are defined to end with a single U+000A LINE FEED character, block buffering or line buffering with different expected line endings can cause delays in event dispatch.
Each event source in the list must have associated with it the following:
In general, the semantics of the transport protocol specified by the URLs for the event sources must be followed, including HTTP caching rules.
For HTTP connections, the Accept header may
be included; if included, it must contain only formats of event
framing that are supported by the user agent (one of which must be
text/event-stream, as described below).
Other formats of event framing may also be supported in addition
to text/event-stream, but this specification does not
define how they are to be parsed or processed.
Such formats could include systems like SMS-push;
for example servers could use Accept headers
and HTTP redirects to an SMS-push mechanism as a kind of protocol
negotiation to reduce network load in GSM environments.
User agents should use the Cache-Control: no-cache
header in requests to bypass any caches for requests of event
sources.
If the event source's last event ID string is not the empty
string, then a Last-Event-ID HTTP header must
be included with the request, whose value is the value of the event
source's last event ID string.
For connections to domains other than the document's domain, the semantics of the Access-Control HTTP header must be followed. [ACCESSCONTROL]
HTTP 200 OK responses with a Content-Type header
specifying the type text/event-stream that are either
from the document's domain or explicitly allowed by the
Access-Control HTTP headers must be processed line by line as described below.
For the purposes of such successfully opened event streams only, user agents should ignore HTTP cache headers, and instead assume that the resource indicates that it does not wish to be cached.
If such a resource (with the correct MIME type) completes loading (i.e. the entire HTTP response body is received or the connection itself closes), the user agent should request the event source resource again after a delay equal to the reconnection time of the event source. This doesn't apply for the error cases that are listed below.
HTTP 200 OK responses that have a Content-Type other
than text/event-stream (or some other supported type),
and HTTP responses whose Access-Control headers indicate that the
resource are not to be used, must be ignored.
HTTP 204 No Content, and 205 Reset Content responses must be treated as if they were 200 OK responses with the right MIME type but no content, and should therefore cause the user agent to refetch the resource after a delay equal to the reconnection time of the event source.
Other HTTP response codes in the 2xx range must be treated like HTTP 200 OK responses for the purposes of reopening event source resources. They are, however, likely to indicate an error has occurred somewhere and may cause the user agent to emit a warning.
HTTP 300 Multiple Choices responses should be handled automatically if possible (treating the responses as if they were 302 Found responses pointing to the appropriate resource), and otherwise must be treated as HTTP 404 responses.
HTTP 301 Moved Permanently responses must cause the user agent to reconnect using the new server specified URL instead of the previously specified URL for all subsequent requests for this event source. (It doesn't affect other event sources with the same URL unless they also receive 301 responses, and it doesn't affect future sessions, e.g. if the page is reloaded.)
HTTP 302 Found, 303 See Other, and 307 Temporary Redirect responses must cause the user agent to connect to the new server-specified URL, but if the user agent needs to again request the resource at a later point, it must return to the previously specified URL for this event source.
HTTP 304 Not Modified responses should be handled like HTTP 200 OK responses, with the content coming from the user agent cache. A new request should then be made after a delay equal to the reconnection time of the event source.
HTTP 305 Use Proxy, HTTP 401 Unauthorized, and 407 Proxy Authentication Required should be treated transparently as for any other subresource.
Any other HTTP response code not listed here or network error (e.g. DNS errors) must be ignored.
For non-HTTP protocols, UAs should act in equivalent ways.
This event stream format's MIME type is
text/event-stream.
The event stream format is (in pseudo-BNF):
<stream> ::= <bom>? <event>*
<event> ::= [ <comment> | <field> ]* <newline>
<comment> ::= <colon> <any-char>* <newline>
<field> ::= <name-char>+ [ <colon> <space>? <any-char>* ]? <newline>
# characters:
<bom> ::= a single U+FEFF BYTE ORDER MARK character
<space> ::= a single U+0020 SPACE character (' ')
<newline> ::= a U+000D CARRIAGE RETURN character
followed by a U+000A LINE FEED character
| a single U+000D CARRIAGE RETURN character
| a single U+000A LINE FEED character
| the end of the file
<colon> ::= a single U+003A COLON character (':')
<name-char> ::= a single Unicode character other than
U+003A COLON, U+000D CARRIAGE RETURN and U+000A LINE FEED
<any-char> ::= a single Unicode character other than
U+000D CARRIAGE RETURN and U+000A LINE FEED
Event streams in this format must always be encoded as UTF-8.
Lines must be separated by either a U+000D CARRIAGE RETURN U+000A LINE FEED (CRLF) character pair, a single U+000A LINE FEED (LF) character, or a single U+000D CARRIAGE RETURN (CR) character.
Bytes or sequences of bytes that are not valid UTF-8 sequences must be interpreted as the U+FFFD REPLACEMENT CHARACTER.
One leading U+FEFF BYTE ORDER MARK character must be ignored if any are present.
The stream must then be parsed by reading everything line by line, with a U+000D CARRIAGE RETURN U+000A LINE FEED (CRLF) character pair, a single U+000A LINE FEED (LF) character, a single U+000D CARRIAGE RETURN (CR) character, and the end of the file being the four ways in which a line can end.
When a stream is parsed, a data buffer and an event name buffer must be associated with it. They must be initialized to the empty string
Lines must be processed, in the order they are received, as follows:
Dispatch the event, as defined below.
Ignore the line.
Collect the characters on the line before the first U+003A COLON character (':'), and let field be that string.
Collect the characters on the line after the first U+003A COLON character (':'), and let value be that string. If value starts with a single U+0020 SPACE character, remove it from value.
Process the field using the steps described below, using field as the field name and value as the field value.
Process the field using the steps described below, using the whole line as the field name, and the empty string as the field value.
Once the end of the file is reached, the user agent must dispatch the event one final time, as defined below.
The steps to process the field given a field name and a field value depend on the field name, as given in the following list. Field names must be compared literally, with no case folding performed.
Set the event name buffer the to field value.
If the data buffer is not the empty string, then append a single U+000A LINE FEED character to the data buffer. Append the field value to the data buffer.
Set the event stream's last event ID to the field value.
If the field value consists of only characters in the range U+0030 DIGIT ZERO ('0') U+0039 DIGIT NINE ('9'), then interpret the field value as an integer in base ten, and set the event stream's reconnection time to that integer. Otherwise, ignore the field.
The field is ignored.
When the user agent is required to dispatch the event, then the user agent must act as follows:
If the data buffer is an empty string, set the data buffer and the event name buffer to the empty string and abort these steps.
If the event name buffer is not the empty string but is also not a valid NCName, set the data buffer and the event name buffer to the empty string and abort these steps.
Otherwise, 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 the data buffer, the origin attribute must be set
to the Unicode
serialization of the origin of the event
stream's URL, and the lastEventId attribute
must be set to the last event ID string of the event
source.
If the event name buffer has a value other than the empty string, change the type of the newly created event to equal the value of the event name buffer.
Set the data buffer and the event name buffer to the empty string.
Queue a task to dispatch the newly created
event at the RemoteEventTarget object to which the
event stream is registered. The task source for this
task is the remote event
task source.
If an event doesn't have an "id" field, but an
earlier event did set the event source's last event ID
string, then the event's lastEventId field will
be set to the value of whatever the last seen "id" field was.
The following event stream, once followed by a blank line:
data: YHOO data: -2 data: 10
...would cause an event message with the interface
MessageEvent to be dispatched on the
eventsource element, whose data attribute would contain
the string YHOO\n-2\n10 (where \n
represents a newline).
This could be used as follows:
<eventsource src="http://stocks.example.com/ticker.php"
onmessage="var data = event.data.split('\n'); updateStocks(data[0], data[1], data[2]);">
...where updateStocks() is a function defined as:
function updateStocks(symbol, delta, value) { ... }
...or some such.
The following stream contains four blocks. The first block has
just a comment, and will fire nothing. The second block has two
fields with names "data" and "id" respectively; an event will be
fired for this block, with the data "first event", and will then
set the last event ID to "1" so that if the connection died between
this block and the next, the server would be sent a Last-Event-ID header with the value "1". The third
block fires an event with data "second event", and also has an "id"
field, this time with no value, which resets the last event ID to
the empty string (meaning no Last-Event-ID
header will now be sent in the event of a reconnection being
attempted). Finally the last block just fires an event with the
data "third event". Note that the last block doesn't have to end
with a blank line, the end of the stream is enough to trigger the
dispatch of the last event.
: test stream data: first event id: 1 data: second event id data: third event
The following stream fires just one event:
data data data data:
The first and last blocks do nothing, since they do not contain any actual data (the data buffer remains at the empty string, and so nothing gets dispatched). The middle block fires an event with the data set to a single newline character.
The following stream fires two identical events:
data:test data: test
This is because the space after the colon is ignored if present.
Legacy proxy servers are known to, in certain cases, drop HTTP connections after a short timeout. To protect against such proxy servers, authors can include a comment line (one starting with a ':' character) every 15 seconds or so.
Authors wishing to relate event source connections to each other
or to specific documents previously served might find that relying
on IP addresses doesn't work, as individual clients can have
multiple IP addresses (due to having multiple proxy servers) and
individual IP addresses can have multiple clients (due to sharing a
proxy server). It is better to include a unique identifier in the
document when it is served and then pass that identifier as part of
the URL in the src
attribute of the eventsource element.
Implementations that support HTTP's per-server connection
limitation might run into trouble when opening multiple pages from a
site if each page has an eventsource to the same
domain. Authors can avoid this using the relatively complex
mechanism of using unique domain names per connection, or by
allowing the user to enable or disable the eventsource
functionality on a per-page basis.
To enable Web applications to maintain bidirectional
communications with server-side processes, this specification
introduces the WebSocket interface.
This interface does not allow for raw access to the underlying network. For example, this interface could not be used to implement an IRC client without proxying messages through a custom server.
This section is non-normative.
An introduction to the client-side and server-side of using the direct connection APIs.
WebSocket interface
[Constructor(in DOMString url)]
interface WebSocket {
readonly attribute DOMString URL;
// ready state
const unsigned short CONNECTING = 0;
const unsigned short OPEN = 1;
const unsigned short CLOSED = 2;
readonly attribute long readyState;
// networking
attribute EventListener onopen;
attribute EventListener onmessage;
attribute EventListener onclosed;
void postMessage(in DOMString data);
void disconnect();
};
WebSocket objects must also implement the
EventTarget interface. [DOM3EVENTS]
The WebSocket(url) constructor takes one argument,
url, which specifies the URL to
which to connect. When a WebSocket object is created,
the UA must parse this argument and
verify that the URL parses without failure and has a <scheme> component whose value is
either "ws" or "wss",
when compared in an ASCII case-insensitive manner. If
it does, it has, and it is, then the user agent must asynchronously
establish a Web Socket connection to url. Otherwise, the constructor must raise a
SYNTAX_ERR exception.
The URL
attribute must return the value that was passed to the
constructor.
The readyState
attribute represents the state of the connection. It can have the
following values:
CONNECTING (numeric value 0)OPEN (numeric value 1)CLOSED (numeric value 2)When the object is created its readyState must be set to
CONNECTING (0).
The postMessage(data) method transmits data using the
connection. If the connection is not established (readyState is not OPEN), it must raise an
INVALID_STATE_ERR exception. If the connection
is established, then the user agent must send data using the Web Socket.
The disconnect()
method must close the Web Socket connection or
connection attempt, if any. If the connection is already closed, it
must do nothing. Closing the connection causes a close event to be fired and
the readyState
attribute's value to change, as described
below.
The open
event is fired when the Web Socket connection is
established.
The close
event is fired when the connection is closed (whether by the author,
calling the disconnect() method, or by
the server, or by a network error).
No information regarding why the connection was closed is passed to the application in this version of this specification.
The message event is fired
when when data is received for a connection.
The following are the event handler DOM attributes
that must be supported by objects implementing the
WebSocket interface:
onopenMust be invoked whenever an open event is targeted at or
bubbles through the WebSocket object.
onmessageMust be invoked whenever a message event is targeted at or
bubbles through the WebSocket object.
onclosedMust be invoked whenever an closed event is targeted at or
bubbles through the WebSocket object.
The task source for all tasks queued by algorithms in this section and its subsections is the Web Socket task source.
This section only applies to user agents.
This specification doesn't currently define a limit to the number of simultaneous connections that a client can establish to a server.
When the user agent is to establish a Web Socket connection to url, it must run the following steps, in the background (without blocking scripts or anything like that):
If the <scheme>
component of the resulting absolute URL is "ws", set secure to false;
otherwise, the <scheme>
component is "wss", set secure to true.
Let host be the value of the <host> component in the resulting absolute URL.
If the resulting absolute URL has a <port> component, then let port be that component's value; otherwise, if secure is false, let port be 81, otherwise let port be 815.
Let resource name be the value of the <path> component (which might be empty) in the resulting absolute URL.
If resource name is the empty string, set it to a single character U+002F SOLIDUS (/).
If the resulting absolute URL has a <query> component, then append a single 003F QUESTION MARK (?) character to resource name, followed by the value of the <query> component.
If the user agent is configured to use a proxy to connect to port port, then connect to that proxy and ask it to open a TCP/IP connection to the host given by host and the port given by port.
For example, if the user agent uses an HTTP proxy, then if it was to try to connect to port 80 on server example.com, it might send the following lines to the proxy server:
CONNECT example.com HTTP/1.1
If there was a password, the connection might look like:
CONNECT example.com HTTP/1.1 Proxy-authorization: Basic ZWRuYW1vZGU6bm9jYXBlcyE=
Otherwise, if the user agent is not configured to use a proxy, then open a TCP/IP connection to the host given by host and the port given by port.
If the connection could not be opened, then fail the Web Socket connection and abort these steps.
If secure is true, perform a TLS handshake over the connection. If this fails (e.g. the server's certificate could not be verified), then fail the Web Socket connection and abort these steps. Otherwise, all further communication on this channel must run through the encrypted tunnel. [RFC2246]
Send the following bytes to the remote side (the server):
47 45 54 20
Send the resource name value, encoded as US-ASCII.
Send the following bytes:
20 48 54 54 50 2f 31 2e 31 0d 0a 55 70 67 72 61 64 65 3a 20 57 65 62 53 6f 63 6b 65 74 0d 0a 43 6f 6e 6e 65 63 74 69 6f 6e 3a 20 55 70 67 72 61 64 65 0d 0a
The string "GET ", the path, " HTTP/1.1", CRLF, the string "Upgrade: WebSocket", CRLF, and the string "Connection: Upgrade", CRLF.
Send the following bytes:
48 6f 73 74 3a 20
Send the host value, encoded as US-ASCII, if it represents a host name (and not an IP address).
Send the following bytes:
0d 0a
The string "Host: ", the host, and CRLF.
Send the following bytes:
4f 72 69 67 69 6e 3a 20
Send the ASCII
serialization of the origin of the script that
invoked the WebSocket()
constructor.
Send the following bytes:
0d 0a
The string "Origin: ", the origin, and CRLF.
If the client has any authentication information or cookies
that would be relevant to a resource with a URL that
has a scheme of http if secure is false and https if
secure is true and is otherwise identical to
url, then HTTP headers that would be
appropriate for that information should be sent at this point. [RFC2616] [RFC2109] [RFC2965]
Each header must be on a line of its own (each ending with a CR LF sequence). For the purposes of this step, each header must not be split into multiple lines (despite HTTP otherwise allowing this with continuation lines).
For example, if the server had a username and password that applied to that URL, it could send:
Authorization: Basic d2FsbGU6ZXZl
Send the following bytes:
0d 0a
Just a CRLF (a blank line).
Read the first 85 bytes from the server. If the connection closes before 85 bytes are received, or if the first 85 bytes aren't exactly equal to the following bytes, then fail the Web Socket connection and abort these steps.
48 54 54 50 2f 31 2e 31 20 31 30 31 20 57 65 62 20 53 6f 63 6b 65 74 20 50 72 6f 74 6f 63 6f 6c 20 48 61 6e 64 73 68 61 6b 65 0d 0a 55 70 67 72 61 64 65 3a 20 57 65 62 53 6f 63 6b 65 74 0d 0a 43 6f 6e 6e 65 63 74 69 6f 6e 3a 20 55 70 67 72 61 64 65 0d 0a
The string "HTTP/1.1 101 Web Socket Protocol Handshake", CRLF, the string "Upgrade: WebSocket", CRLF, the string "Connection: Upgrade", CRLF.
What if the response is a 401 asking for credentials?
Let headers be a list of name-value pairs, initially empty.
Header: Let name and value be empty byte arrays.
Read a byte from the server.
If the connection closes before this byte is received, then fail the Web Socket connection and abort these steps.
Otherwise, handle the byte as described in the appropriate entry below:
This reads a header name, terminated by a colon, converting upper-case ASCII letters to lowercase, and aborting if a stray CR or LF is found.
Read a byte from the server.
If the connection closes before this byte is received, then fail the Web Socket connection and abort these steps.
Otherwise, handle the byte as described in the appropriate entry below:
This skips past a space character after the colon, if necessary.
Read a byte from the server.
If the connection closes before this byte is received, then fail the Web Socket connection and abort these steps.
Otherwise, handle the byte as described in the appropriate entry below:
This reads a header value, terminated by a CRLF.
Read a byte from the server.
If the connection closes before this byte is received, or if the byte is not a 0x0a byte (ASCII LF), then fail the Web Socket connection and abort these steps.
This skips past the LF byte of the CRLF after the header.
Append an entry to the headers list that has the name given by the string obtained by interpreting the name byte array as a UTF-8 byte stream and the value given by the string obtained by interpreting the value byte array as a UTF-8 byte stream.
Return to the header step above.
Headers processing: If there is not exactly one entry
in the headers list whose name is "websocket-origin", or if there is not exactly one
entry in the headers list whose name is "websocket-location", or if there are any entries
in the headers list whose names are the empty
string, then fail the Web Socket connection and abort
these steps.
Handle each entry in the headers list as follows:
websocket-origin"WebSocket() constructor, then
fail the Web Socket connection and abort these
steps.websocket-location"set-cookie" or
"set-cookie2" or another cookie-related
header namehttp if secure is false and https if
secure is true and is otherwise identical to
url. [RFC2109] [RFC2965]Change the readyState attribute's value
to OPEN (1).
Queue a task to fire a simple event
named open at the
WebSocket object.
The Web Socket connection is established. Now the user agent must send and receive to and from the connection as described in the next section.
To fail the Web Socket connection, the user agent must close the Web Socket connection, and may report the problem to the user (which would be especially useful for developers). However, user agents must not convey the failure information to the script in a way distinguishable from the Web Socket being closed normally.
Once a Web Socket connection is established, the user agent must run through the following state machine for the bytes sent by the server.
Try to read a byte from the server. Let frame type be that byte.
If no byte could be read because the Web Socket connection is closed, then abort.
Handle the frame type byte as follows:
Run these steps. If at any point during these steps a read is attempted but fails because the Web Socket connection is closed, then abort.
Let length be zero.
Length: Read a byte, let b be that byte.
Let bv be integer corresponding to the low 7 bits of b (the value you would get by anding b with 0x7f).
Multiply length by 128, add bv to that result, and store the final result in length.
If the high-order bit of b is set (i.e. if b anded with 0x80 returns 0x80), then return to the step above labeled length.
Read length bytes.
Discard the read bytes.
Run these steps. If at any point during these steps a read is attempted but fails because the Web Socket connection is closed, then abort.
Let raw data be an empty byte array.
Data: Read a byte, let b be that byte.
If b is not 0xff, then append b to raw data and return to the previous step (labeled data).
Interpret raw data as a UTF-8 string, and store that string in data.
If frame type is 0x00, create an
event that uses the MessageEvent interface, with
the event name message,
which does not bubble, is cancelable, has no default action,
and whose data
attribute is set to data, and queue a
task to dispatch it at the WebSocket
object. Otherwise, discard the data.
Return to the first step to read the next byte.
If the user agent is faced with content that is too large to be handled appropriately, then it must fail the Web Socket connection.
Once a Web Socket connection is established, the user agent must use the following steps to send data using the Web Socket:
Send a 0x00 byte to the server.
Encode data using UTF-8 and send the resulting byte stream to the server.
Send a 0xff byte to the server.
People often request the ability to send binary blobs over this API; also, once the other postMessage() methods support it, we should look into allowing name/value pairs, arrays, and numbers using postMessage() instead of just strings and binary data.
This section only applies to servers.
This section describes the minimal requirements for a server-side implementation of Web Sockets.
Listen on a port for TCP/IP. Upon receiving a connection request, open a connection and send the following bytes back to the client:
48 54 54 50 2f 31 2e 31 20 31 30 31 20 57 65 62 20 53 6f 63 6b 65 74 20 50 72 6f 74 6f 63 6f 6c 20 48 61 6e 64 73 68 61 6b 65 0d 0a 55 70 67 72 61 64 65 3a 20 57 65 62 53 6f 63 6b 65 74 0d 0a 43 6f 6e 6e 65 63 74 69 6f 6e 3a 20 55 70 67 72 61 64 65 0d 0a
Send the string "WebSocket-Origin" followed
by a U+003A COLON (":") followed by the ASCII serialization of the origin
from which the server is willing to accept connections, followed by
a CRLF pair (0x0d 0x0a).
For instance:
WebSocket-Origin: http://example.com
Send the string "WebSocket-Location"
followed by a U+003A COLON (":") followed by the URL of
the Web Socket script, followed by a CRLF pair (0x0d 0x0a).
For instance:
WebSocket-Location: ws://example.com:80/demo
Send another CRLF pair (0x0d 0x0a).
Read (and discard) data from the client until four bytes 0x0d 0x0a 0x0d 0x0a are read.
If the connection isn't dropped at this point, go to the data framing section.
The previous section ignores the data that is transmitted by the client during the handshake.
The data sent by the client consists of a number of fields separated by CR LF pairs (bytes 0x0d 0x0a).
The first field consists of three tokens separated by space
characters (byte 0x20). The middle token is the path being
opened. If the server supports multiple paths, then the server
should echo the value of this field in the initial handshake, as
part of the URL given on the WebSocket-Location line (after the appropriate
scheme and host).
The remaining fields consist of name-value pairs, with the name part separated from the value part by a colon and a space (bytes 0x3a 0x20). Of these, several are interesting:
The value gives the hostname that the client intended to use when opening the Web Socket. It would be of interest in particular to virtual hosting environments, where one server might serve multiple hosts, and might therefore want to return different data.
The right host has to be output as part of the URL
given on the WebSocket-Location line of the
handshake described above, to verify that the server knows that it
is really representing that host.
The value gives the scheme, hostname, and port (if it's not the default port for the given scheme) of the page that asked the client to open the Web Socket. It would be interesting if the server's operator had deals with operators of other sites, since the server could then decide how to respond (or indeed, whether to respond) based on which site was requesting a connection.
If the server supports connections from more than one origin,
then the server should echo the value of this field in the initial
handshake, on the WebSocket-Origin line.
Other fields can be used, such as "Cookie" or "Authorization", for
authentication purposes.
This section only describes how to handle content that this specification allows user agents to send (text). It doesn't handle any arbitrary content in the same way that the requirements on user agents defined earlier handle any content including possible future extensions to the protocols.
The server should run through the following steps to process the bytes sent by the client:
Read a byte from the client. Assuming everything is going according to plan, it will be a 0x00 byte. Behaviour for the server is undefined if the byte is not 0x00.
Let raw data be an empty byte array.
Data: Read a byte, let b be that byte.
If b is not 0xff, then append b to raw data and return to the previous step (labeled data).
Interpret raw data as a UTF-8 string, and apply whatever server-specific processing should occur for the resulting string.
Return to the first step to read the next byte.
The server should run through the followin steps to send strings to the client:
Send a 0x00 byte to the client to indicate the start of a string.
Encode data using UTF-8 and send the resulting byte stream to the client.
Send a 0xff byte to the client to indicate the end of the message.
To close the Web Socket connection, either the user agent or the server closes the TCP/IP connection. There is no closing handshake. Whether the user agent or the server closes the connection, it is said that the Web Socket connection is closed.
Servers may close the Web Socket connection whenever desired.
User agents should not close the Web Socket connection arbitrarily.
When the Web Socket connection is
closed, the readyState attribute's value
must be changed to CLOSED
(2), and the user agent must queue a task to fire
a simple event named close at the
WebSocket object.
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.
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.
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 either parsing it as a URL fails,
or resolving it 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.
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 active document of the browsing
context 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 passed as the message argument to
the postMessage()
method, 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 Window object of the default
view of the browsing context for which the
Document object with which the script is associated
is the active document.
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, messagePort, 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 either parsing it as a URL fails,
or resolving it 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.
If the messagePort argument is null, then act as if the method had just been called with two arguments, message and targetOrigin.
Try to obtain a new port by cloning the messagePort argument with the Window
object on which the method was invoked as the owner of the
clone. If this returns 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 active document of the browsing
context 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 passed as the message argument to
the postMessage()
method, 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 Window object of the default
view of the browsing context for which the
Document object with which the script is associated
is the active document.
Let the messagePort attribute
of the event be the new port.
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.
People often request the ability to send name/value pairs, arrays, and numbers using postMessage() instead of just strings.
This section is non-normative.
An introduction to the channel and port APIs.
[Constructor]
interface MessageChannel {
readonly attribute MessagePort port1;
readonly attribute MessagePort port2;
};
When the MessageChannel()
constructor is called, it must run the following algorithm:
Create a new MessagePort object
owned by the script execution context, and let port1 be that object.
Create a new MessagePort object
owned by the script execution context, 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.
interface MessagePort {
readonly attribute boolean active;
void postMessage(in DOMString message);
void postMessage(in DOMString message, in MessagePort messagePort);
void start();
void close();
// event handler attributes
attribute EventListener onmessage;
attribute EventListener onclose;
};
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 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
execution context 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 unentangle 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 unentangled 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.
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, the method's first argument.
If the method was called with a second argument data port and that argument isn't null, then run the following substeps:
If the data port is the source port or the target
port, then throw an INVALID_ACCESS_ERR
exception and abort all these steps.
Try to obtain a new data port by cloning the data port with the owner of the target port as the owner of the clone. If this returns an exception, then throw that exception and abort these steps.
Let the messagePort attribute
of the event be the new data port.
Return from the method, but continue with these steps.
Add the event to the port message queue of target port.
People often request the ability to send name/value pairs, arrays, and numbers using postMessage() instead of just strings.
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, contains
an event, and its owner is available, the user agent must queue a
task in the event loop to dispatch the first
event in the queue on the MessagePort object, and
remove the event from the queue. The task source for
this task is the posted
message task source.
A MessagePort's owner is available if the MessagePort is owned
by an object other than a Window object, or if it is
owned by a Window object and the Document
that was the active document in that browsing
context when the MessagePort was created is
fully active. If that Document is
discarded before the port's owner becomes available, then the events
are lost.
The close()
method, when called on a port local port that is
entangled with another port, must cause the user agents to run the
following steps:
Unentangle the two ports.
Queue a task to fire a simple
event called close at the
port on which the method was called.
Queue a task to fire a simple
event called close at the
other port.
The task source for the two tasks above is the posted message task source.
If the method is called on a port that is not entangled, then the method must do nothing.
The following are the event handler DOM attributes
that must be supported by objects implementing the
MessagePort interface:
onmessageMust be invoked whenever a message event is targeted
at or bubbles through the MessagePort object.
The first time a MessagePort object's onmessage attribute
is set, the port's port message queue must be opened,
as if the start()
method had been called.
oncloseMust be invoked whenever an close event is targeted at or bubbles
through the MessagePort object.
When a Document is discarded, if there are any
MessagePort objects that:
Document, andDocument was the active document of that browsing context, andDocument was the active document of that browsing context,...then the user agent must run the following steps for each such port:
Let surviving port be the port with
which the MessagePort object in question is
entangled.
Unentangle the two ports.
Queue a task to fire a simple
event called close at
surviving port. The task source
for this task is the posted
message task source.
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.