diff --git a/index.bs b/index.bs index 6b32a1c..9f4b8e7 100644 --- a/index.bs +++ b/index.bs @@ -281,7 +281,7 @@ It can have the following values: close code=] and |reason| as [=the WebSocket connection close reason=]. : |socket|.url - :: Returns the URL that was used to establish the WebSocket connection. + :: Returns the URL that was used to establish the WebSocket connection. : |socket|.readyState :: Returns the state of the WebSocket connection. It can have the values described above. @@ -321,14 +321,8 @@ It can have the following values: constructor steps are: 1. Let |baseURL| be [=this=]'s [=relevant settings object=]'s [=API base URL=]. - 1. Let |urlRecord| be the result of applying the [=URL parser=] to |url| with |baseURL|. - 1. If |urlRecord| is failure, then throw a "{{SyntaxError}}" {{DOMException}}. - 1. If |urlRecord|'s [=url/scheme=] is "`http`", then set |urlRecord|'s [=url/scheme=] to "`ws`". - 1. Otherwise, if |urlRecord|'s [=url/scheme=] is "`https`", set |urlRecord|'s [=url/scheme=] to - "`wss`". - 1. If |urlRecord|'s [=scheme=] is not "[=ws=]" or "[=wss=]", then throw a - "{{SyntaxError}}" {{DOMException}}. - 1. If |urlRecord|'s [=fragment=] is non-null, then throw a "{{SyntaxError}}" {{DOMException}}. + 1. Let |urlRecord| be the result of [=getting a URL record=] given |url| and + |baseURL|. 1. If |protocols| is a string, set |protocols| to a sequence consisting of just that string. 1. If any of the values in |protocols| occur more than once or otherwise fail to match the requirements for elements that comprise the value of @@ -364,58 +358,10 @@ string. After [=the WebSocket connection is established=], its value might chang
The close(|code|, |reason|) method steps are: - 1. If |code| is present, but is neither an integer equal to 1000 nor an integer in the range 3000 - to 4999, inclusive, throw an "{{InvalidAccessError}}" {{DOMException}}. - 1. If |reason| is present, then run these substeps: - 1. Let |reasonBytes| be the result of encoding |reason|. - 1. If |reasonBytes| is longer than 123 bytes, then throw a "{{SyntaxError}}" {{DOMException}}. - 1. Run the first matching steps from the following list: -
- : If [=this=]'s [=WebSocket/ready state=] is {{WebSocket/CLOSING}} (2) or {{WebSocket/CLOSED}} (3) - :: Do nothing. - -

The connection is already closing or is already closed. If it has not already, a - {{WebSocket/close}} event will eventually fire as described below. + 1. If |code| is the special value "missing", then set |code| to null. + 1. If |reason| is the special value "missing", then set |reason| to the empty string. + 1. [=Close the WebSocket=] with [=this=], |code|, and |reason|. - : If the WebSocket connection is not yet [=established=] [[!WSP]] - :: [=Fail the WebSocket connection=] and set [=this=]'s [=WebSocket/ready state=] to - {{WebSocket/CLOSING}} (2). [[!WSP]] - -

The [=fail the WebSocket connection=] algorithm invokes the [=close the - WebSocket connection=] algorithm, which then establishes that [=the WebSocket connection is - closed=], which fires the {{WebSocket/close}} event as described - below. - - : If the WebSocket closing handshake has not yet been started [[!WSP]] - :: [=Start the WebSocket closing handshake=] and set [=this=]'s [=WebSocket/ready state=] to - {{WebSocket/CLOSING}} (2). [[!WSP]] - - If neither |code| nor |reason| is present, the WebSocket Close message must not have a body. - -

The WebSocket Protocol erroneously states that the status code is required for the [=start the WebSocket closing handshake=] algorithm. - - - If |code| is present, then the status code to use in the WebSocket Close - message must be the integer given by |code|. [[!WSP]] - - If |reason| is also present, then |reasonBytes| must be provided in the Close message after the - status code. [[!WSP]] - -

The [=start the WebSocket closing handshake=] algorithm eventually invokes the - [=close the WebSocket connection=] algorithm, which then establishes that [=the WebSocket - connection is closed=], which fires the {{WebSocket/close}} event as - described below. - - : Otherwise - :: Set [=this=]'s [=WebSocket/ready state=] to {{WebSocket/CLOSING}} (2). - -

[=The WebSocket closing handshake is started=], and will eventually invoke the - [=close the WebSocket connection=] algorithm, which will establish that [=the WebSocket - connection is closed=], and thus the {{WebSocket/close}} event will fire, as described below. -

The {{WebSocket/close()}} method does not discard previously sent messages before @@ -547,7 +493,7 @@ that must be supported, as [=event handler IDL attributes=], by all objects impl -# Feedback from the protocol # {#feedback-from-the-protocol} +## Feedback from the protocol ## {#feedback-from-the-protocol} When [=the WebSocket connection is established=], the user agent must [=queue a task=] to run these steps: @@ -595,8 +541,8 @@ When [=a WebSocket message has been received=] with type |type| and data |data|, 1. [=Fire an event=] named message at the {{WebSocket}} object, using {{MessageEvent}}, with the {{MessageEvent/origin}} attribute initialized to the serialization of the {{WebSocket}} object's [=url=]'s [=origin=], and the - {{MessageEvent/data}} attribute initialized to |dataForEvent|. + serializer">serialization of the {{WebSocket}} object's [=internal-url|url=]'s [=origin=], + and the {{MessageEvent/data}} attribute initialized to |dataForEvent|.

User agents are encouraged to check if they can perform the above steps efficiently before they run the task, picking tasks from other [=task queues=] while they prepare the buffers @@ -688,23 +634,8 @@ The [=task source=] for all [=tasks=] queued in this se WebSocket task source. -# Ping and Pong frames # {#ping-and-pong-frames} - -The WebSocket protocol defines Ping and Pong frames that can be used for keep-alive, -heart-beats, network status probing, latency instrumentation, and so forth. These are not currently -exposed in the API. - -User agents may send ping and unsolicited pong frames as desired, for example in an attempt to -maintain local network NAT mappings, to detect failed connections, or to display latency metrics to -the user. User agents must not use pings or unsolicited pongs to aid the server; it is assumed that -servers will solicit pongs whenever appropriate for the server's needs. - - - -# The {{CloseEvent}} interface # {#the-closeevent-interface} +## The {{CloseEvent}} interface ## {#the-closeevent-interface} {{WebSocket}} objects use the {{CloseEvent}} interface for their {{WebSocket/close}} events: @@ -747,7 +678,7 @@ to. It represents the WebSocket connection close reason provided by the server. -# Garbage collection # {#garbage-collection} +## Garbage collection ## {#garbage-collection} A {{WebSocket}} object whose [=WebSocket/ready state=] was set to {{WebSocket/CONNECTING}} (0) as of the last time the [=event loop=] reached step 1 must not be garbage @@ -787,7 +718,7 @@ the following list: : If the WebSocket closing handshake has not yet been started [[!WSP]] :: [=Start the WebSocket closing handshake=], with the status code to use in the - WebSocket Close message being 1001. [[!WSP]] + WebSocket Close frame being 1001. [[!WSP]] : Otherwise :: Do nothing. @@ -795,6 +726,590 @@ the following list: + + +# The {{WebSocketStream}} interface # {#the-websocketstream-interface} + +The Web IDL definition for the {{WebSocketStream}} class is given as follows: + +

+dictionary WebSocketOpenInfo { + ReadableStream readable; + WritableStream writable; + DOMString extensions; + DOMString protocol; +}; + +dictionary WebSocketCloseInfo { + [EnforceRange] unsigned short closeCode; + USVString reason = ""; +}; + +dictionary WebSocketStreamOptions { + sequence<USVString> protocols; + AbortSignal signal; +}; + +[Exposed=(Window,Worker)] +interface WebSocketStream { + constructor(USVString url, optional WebSocketStreamOptions options = {}); + readonly attribute USVString url; + readonly attribute Promise<WebSocketOpenInfo> opened; + readonly attribute Promise<WebSocketCloseInfo> closed; + undefined close(optional WebSocketCloseInfo closeInfo = {}); +}; + + +Each {{WebSocketStream}} object has an associated url, which is a +[=URL record=]. + +Each {{WebSocketStream}} object has an associated opened promise, +which is a promise. + +Each {{WebSocketStream}} object has an associated closed promise, +which is a promise. + +Each {{WebSocketStream}} object has an associated readable stream, +which is a {{ReadableStream}}. + +Each {{WebSocketStream}} object has an associated writable stream, +which is a {{WritableStream}}. + +Each {{WebSocketStream}} object has an associated was ever +connected, which is a boolean, initially false. + +Each {{WebSocketStream}} object has an associated boolean handshake +aborted, which is initially false. + +Each {{WebSocketStream}} object has an associated ready state, +which is a number representing the state of the connection. Initially it must be +{{WebSocket/CONNECTING}} (0). It has the same semantics as {{WebSocket}}'s [=WebSocket/ready +state=], but is not exposed to JavaScript. + + +
+ : |socket| = new {{WebSocketStream/constructor(url, options)|WebSocketStream}}(|url|[, |options|]) + :: Creates a new {{WebSocketStream}} object, immediately establishing the associated WebSocket + connection. + + |url| is a string giving the URL over which the connection is established. + Only "`ws`", "`wss`", "`http`", and "`https`" schemes are allowed; others will cause a + "{{SyntaxError}}" {{DOMException}}. URLs with [=fragments=] will also cause such an exception. + + The |options| argument is an object whose properties can be set as follows: + + : {{WebSocketStreamOptions/protocols}} + :: An array of strings. If it is omitted, it is equivalent to an empty array. Each string in the + array is a subprotocol name. The connection will only be established if the server reports that + it has selected one of these subprotocols. The subprotocol names have to match the requirements + for elements that comprise the value of \``Sec-WebSocket-Protocol`\` fields as + defined by The WebSocket Protocol. [[!WSP]] + + : {{WebSocketStreamOptions/signal}} + :: An {{AbortSignal}} that can be used to abort the handshake. After the handshake is complete, + the signal does nothing. + + : |socket|.{{WebSocketStream/url}} + :: Returns the [=WebSocketStream/url|URL=] that was used to establish the WebSocket connection. + + : |socket|.{{WebSocketStream/opened}} + :: Returns a {{Promise}} which resolves when the handshake successfully completes, or rejects if + the handshake fails. On success, it resolves to an object with the following properties: + + : {{WebSocketOpenInfo/readable}} + :: A {{ReadableStream}} that can be used to read messages from the server. Each chunk read + corresponds to one message. Text messages will be read as strings; binary messages will be read + as {{Uint8Array}} objects. + +

The original {{WebSocket}} API supplied {{ArrayBuffer}} objects, but modern + practice is to prefer the {{Uint8Array}} type for binary data, particularly when using streams. + The underlying {{ArrayBuffer}} object can be recovered by accessing chunk.buffer. + + The stream can be closed by calling {{ReadableStream/cancel()}} on + {{WebSocketOpenInfo/readable}}. If the reason argument passed to {{ReadableStream/cancel()}} is a + {{WebSocketError}} object then {{WebSocketError/closeCode}} will be used as [=the WebSocket + connection close code=] and {{WebSocketError/reason}} will be used as [=the WebSocket connection + close reason=]. + + If no messages are read, or if messages are read slower than they are sent, then backpressure + will be applied and eventually the server will stop sending new messages. + + : {{WebSocketOpenInfo/writable}} + :: A {{WritableStream}} that can be used to send messages to the server. Each chunk written will + be converted to one message. Strings will be sent as text messages; {{BufferSource}} chunks will + be sent as binary messages. Backpressure due to the network or server being unable to process + data fast enough will automatically be observed by piping. When using a [=writable stream + writer=], waiting for the {{WritableStreamDefaultWriter/ready|writer.ready}} promise will ensure + that backpressure is obeyed. + + The WebSocket can be closed by calling {{WritableStream/close()}} on + {{WebSocketOpenInfo/writable}}. + + The stream can also be closed by calling {{WritableStream/abort()}} on + {{WebSocketOpenInfo/writable}}. If the reason passed to {{WritableStream/abort()}} is a + {{WebSocketError}}, then it will be used to set [=the WebSocket connection close code=] and + [=the WebSocket connection close reason=] as with {{ReadableStream/cancel()}} above. + + : {{WebSocketOpenInfo/extensions}} + :: The [=extensions in use=] for the connection. + + : {{WebSocketOpenInfo/protocol}} + :: The [=subprotocol in use=] for the connection. + + : |socket|.{{WebSocketStream/closed}} + :: A {{Promise}} which resolves when the connection is closed. If the connection did not close + [=cleanly=] then the promise is rejected with a {{WebSocketError}}. When the connection closes + [=cleanly=] the promise is fulfilled with an object with properties + {{WebSocketCloseInfo/closeCode}} and {{WebSocketCloseInfo/reason}}, giving [=the WebSocket + connection close code=] and [=the WebSocket connection close reason=] that were supplied by the + server. + + : |socket|.{{WebSocketStream/close()}} + : |socket|.{{WebSocketStream/close()|close}}({ {{WebSocketCloseInfo/closeCode}}, {{WebSocketCloseInfo/reason}} }) + :: Close the connection, optionally supplying an object with {{WebSocketCloseInfo/closeCode}} and + {{WebSocketCloseInfo/reason}} properties to indicate [=the WebSocket connection close code=] and + [=the WebSocket connection close reason=] that will be sent to the remote server. If the handshake + is still in progress, then it will be aborted and {{WebSocketCloseInfo/closeCode}} and + {{WebSocketCloseInfo/reason}} will be ignored. +

+ +
+ + The new + WebSocketStream(|url|, |options|) constructor steps are: + + 1. Let |baseURL| be [=this=]'s [=relevant settings object=]'s [=API base URL=]. + 1. Let |urlRecord| be the result of [=get a URL record|getting a URL record=] given |url| and + |baseURL|. + 1. Let |protocols| be |options|["{{WebSocketStreamOptions/protocols}}"] if it [=map/exists=], + otherwise an empty sequence. + 1. If any of the values in |protocols| occur more than once or otherwise fail to match the + requirements for elements that comprise the value of + \``Sec-WebSocket-Protocol`\` fields as defined by The WebSocket + Protocol, then throw a "{{SyntaxError}}" {{DOMException}}. [[!WSP]] + 1. Set [=this=]'s [=WebSocketStream/url=] to |urlRecord|. + 1. Set [=this=]'s [=WebSocketStream/opened promise=] and [=WebSocketStream/closed promise=] to new + promises. + 1. Apply backpressure to the WebSocket. + +

This means that messages won't be read until the application is ready for them. + + 1. If |options|["{{WebSocketStreamOptions/signal}}"] [=map/exists=], + 1. Let |signal| be |options|["{{WebSocketStreamOptions/signal}}"]. + 1. If |signal| is [=AbortSignal/aborted=], then reject [=this=]'s [=WebSocketStream/opened + promise=] and [=WebSocketStream/closed promise=] with |signal|'s [=abort reason=] and return. + 1. [=AbortSignal/add|Add the following abort steps=] to |signal|: + 1. If the WebSocket connection is not yet [=established=]: [[!WSP]] + 1. [=Fail the WebSocket connection=]. + 1. Set [=this=]'s [=WebSocketStream/ready state=] to {{WebSocket/CLOSING}}. + 1. [=Reject=] [=this=]'s [=WebSocketStream/opened promise=] and [=WebSocketStream/closed + promise=] with |signal|'s [=abort reason=]. + 1. Set [=this=]'s [=WebSocketStream/handshake aborted=] to true. + 1. Let |client| be [=this=]'s [=relevant settings object=]. + 1. Run this step [=in parallel=]: + 1. [=Establish a WebSocket connection=] given |urlRecord|, |protocols|, and |client|. [[!FETCH]] + +

If the [=establish a WebSocket connection=] algorithm fails, it triggers the + [=fail the WebSocket connection=] algorithm, which then invokes the [=close the WebSocket + connection=] algorithm. This establishes that [=the WebSocket connection is closed=], which + rejects the {{WebSocketStream/opened}} and {{WebSocketStream/closed}} promises. +

+ +
+ +The url getter steps are to return [=this=]'s +[=WebSocketStream/url=], [=URL serializer|serialized=]. + +The opened getter steps are to return [=this=]'s +[=WebSocketStream/opened promise=]. + +The closed getter steps are to return [=this=]'s +[=WebSocketStream/closed promise=]. + +
+ The close(|closeInfo|) method steps are: + + 1. Let |code| be |closeInfo|["{{WebSocketCloseInfo/closeCode}}"] if present, or null otherwise. + 1. Let |reason| be |closeInfo|["{{WebSocketCloseInfo/reason}}"]. + 1. [=Close the WebSocket=] with this, |code|, and |reason|. +
+ + +## Feedback to WebSocketStream from the protocol ## {#feedback-to-websocket-stream-from-the-protocol} + +When [=the WebSocket connection is established=] for a {{WebSocketStream}} |stream|, the user agent +must [=queue a global task=] on the [=WebSocket task source=] given |stream|'s [=relevant global +object=] to run these steps: + +
+ + 1. Change |stream|'s [=WebSocketStream/ready state=] to {{WebSocket/OPEN}} (1). + 1. Set |stream|'s [=WebSocketStream/was ever connected=] to true. + 1. Let |extensions| be the [=extensions in use=]. + 1. Let |protocol| be the [=subprotocol in use=]. + 1. Let |pullAlgorithm| be an action that [=pulls bytes=] from |stream|. + 1. Let |cancelAlgorithm| be an action that [=cancels=] |stream| with + |reason|, given |reason|. + 1. Let |readable| be a [=new=] {{ReadableStream}}. + 1. [=ReadableStream/Set up=] |readable| with |pullAlgorithm| and |cancelAlgorithm|. + 1. Let |writeAlgorithm| be an action that [=writes=] |chunk| to |stream|, given |chunk|. + 1. Let |closeAlgorithm| be an action that [=closes=] |stream|. + 1. Let |abortAlgorithm| be an action that [=aborts=] |stream| with |reason|, given |reason|. + 1. Let |writable| be a [=new=] {{WritableStream}}. + 1. [=WritableStream/Set up=] |writable| with |writeAlgorithm|, |closeAlgorithm|, and + |abortAlgorithm|. + 1. Set |stream|'s [=WebSocketStream/readable stream=] to |readable|. + 1. Set |stream|'s [=WebSocketStream/writable stream=] to |writable|. + 1. [=Resolve=] |stream|'s [=WebSocketStream/opened promise=] with {{WebSocketOpenInfo}} «[ + "{{WebSocketOpenInfo/extensions}}" → |extensions|, "{{WebSocketOpenInfo/protocol}}" → + |protocol|, "{{WebSocketOpenInfo/readable}}" → |readable|, "{{WebSocketOpenInfo/writable}}" → + |writable| ]». + +
+ +
+ +
+ +When [=a WebSocket message has been received=] for a {{WebSocketStream}} |stream| with type |type| +and data |data|, the user agent must [=queue a global task=] on the [=WebSocket task source=] given +|stream|'s [=relevant global object=] to follow these steps: [[!WSP]] + + 1. If |stream|'s [=WebSocketStream/ready state=] is not {{WebSocket/OPEN}} (1), then return. + 1. Let |chunk| be determined by switching on |type|: + +
+ : |type| indicates that the data is Text + :: a new {{DOMString}} containing |data| + + : |type| indicates that the data is Binary + :: a new {{Uint8Array}} object, created in the [=relevant Realm=] of the {{WebSocketStream}} + object, whose contents are |data| +
+ + 1. [=ReadableStream/Enqueue=] |chunk| into |stream|'s [=WebSocketStream/readable stream=]. + 1. Apply backpressure to the WebSocket. + +

Applying backpressure will result in no new WebSocket messages being handled until + the backpressure is released. After an implementation-defined amount of data is buffered, the + client will stop reading from the underlying network connection resulting in network-layer + backpressure being applied. +

+ +
+ +When [=the WebSocket closing handshake is started=] for a {{WebSocketStream}} +|stream|, the user agent must [=queue a global task=] on the [=WebSocket task source=] given +|stream|'s [=relevant global object=] to change |stream|'s [=WebSocketStream/ready state=] to +{{WebSocket/CLOSING}} [[!WSP]] + +
+ +
+ +When [=the WebSocket connection is closed=] for a {{WebSocketStream}} |stream|, possibly +[=cleanly=], the user agent must [=queue a global task=] on the [=WebSocket task source=] given +|stream|'s [=relevant global object=] to run the following substeps: + + 1. Change |stream|'s [=WebSocketStream/ready state=] to {{WebSocket/CLOSED}} (3). + 1. If |stream|'s [=WebSocketStream/handshake aborted=] is true, then return. + 1. If |stream|'s [=WebSocketStream/was ever connected=] is false, then [=reject=] |stream|'s + [=opened promise=] with a [=new=] {{WebSocketError}}. + 1. Let |code| be [=the WebSocket connection close code=]. + 1. Let |reason| be the result of applying [=UTF-8 decode without BOM=] to [=the WebSocket + connection close reason=]. + 1. If the connection was closed [=cleanly=], + 1. [=ReadableStream/Close=] |stream|'s [=WebSocketStream/readable stream=]. + 1. [=WritableStream/Error=] |stream|'s [=WebSocketStream/writable stream=] with an + "{{InvalidStateError}}" {{DOMException}} indicating that a closed {{WebSocketStream}} cannot be + written to. + 1. [=Resolve=] |stream|'s [=closed promise=] with {{WebSocketCloseInfo}} «[ + "{{WebSocketCloseInfo/closeCode}}" → |code|, "{{WebSocketCloseInfo/reason}}" → |reason| ]». + 1. Otherwise, + 1. Let |error| be a [=new=] + {{WebSocketError}} whose [=WebSocketError/closeCode=] is |code| and [=WebSocketError/reason=] + is |reason|. + 1. [=ReadableStream/Error=] |stream|'s [=WebSocketStream/readable stream=] with |error|. + 1. [=WritableStream/Error=] |stream|'s [=WebSocketStream/writable stream=] with |error|. + 1. [=Reject=] |stream|'s [=closed promise=] with |error|. +
+ + + +## Stream operations ## {#stream-operations} + +
+ +To pull bytes from a {{WebSocketStream}} |stream|, if |stream| is currently applying +backpressure, release backpressure. + +

If any messages are queued, one will be handled immediately as a result. +

+ +
+ +
+ +To cancel a {{WebSocketStream}} |stream| given |reason|, [=close using reason=] giving +|stream| and |reason|. +
+ +
+ +
+ +To write |chunk| to a {{WebSocketStream}} |stream|: + 1. Let |promise| be [=a new promise=] created in |stream|'s [=relevant realm=]. + 1. Let |data| be null. + 1. Let |opcode| be null. + 1. If |chunk| is a {{BufferSource}}, + 1. Set |data| to a [=get a copy of the buffer source|copy of the bytes=] given |chunk|. + 1. Set |opcode| to a binary frame opcode. + 1. Otherwise, + 1. Let |string| be the result of [=Converted to an IDL value|converting=] |chunk| to an IDL + {{USVString}}. If this throws an exception, return [=a promise rejected with=] the exception. + 1. Set |data| to the result of [=UTF-8 encoding=] |string|. + 1. Set |opcode| to a text frame opcode. + 1. In parallel, + 1. Wait until there is sufficient buffer space in |stream| to send the message. + +

This means that backpressure will be applied when the user agent's buffers are + full. + + 1. If [=the WebSocket closing handshake is started|the closing handshake has not yet started=], + [=Send a WebSocket Message=] to |stream| comprised of |data| using |opcode|. + 1. [=Queue a global task=] on the [=WebSocket task source=] given |stream|'s [=relevant global + object=] to resolve |promise| with undefined. + 1. Return |promise|. +

+ +
+ +
+ +To close a {{WebSocketStream}} |stream|, [=close the WebSocket=] with |stream| (code and reason are not set). +
+ +
+ +
+ +To abort a {{WebSocketStream}} |stream| given |reason|, [=close using reason=] giving +|stream| and |reason|. +
+ +
+ +
+ +To close using reason a {{WebSocketStream}} |stream| given |reason|: + + 1. Let |code| be null. + 1. Let |reasonString| be the empty string. + 1. If |reason| [=implements=] {{WebSocketError}}, + 1. Set |code| to |reason|'s [=WebSocketError/closeCode=]. + 1. Set |reasonString| to |reason|'s [=WebSocketError/reason=]. + 1. [=Close the WebSocket=] with |stream|, |code|, and |reasonString|. If this throws an exception, + discard |code| and |reasonString| and [=close the WebSocket=] with |stream|. + +

A {{WebSocketError}} object constructed from JavaScript will always have a + [=WebSocketError/closeCode=] and [=WebSocketError/reason=] that JavaScript is permitted to set. + However, the {{WebSocketStream/closed}} promise might be rejected with a {{WebSocketError}} whose + [=WebSocketError/closeCode=] has a value coming from the server that JavaScript is not permitted to + set itself, such as 1001 "Going Away". +

+ + + +## The {{WebSocketError}} interface ## {#the-websocketevent-interface} + +WebSocketError is a subclass of {{DOMException}} +that represents the information associated with closing a WebSocket. + + +[Exposed=(Window,Worker)] +interface WebSocketError : DOMException { + constructor(optional DOMString message = "", + optional WebSocketCloseInfo init = {}); + + readonly attribute unsigned short? closeCode; + readonly attribute USVString reason; +}; + + +Each {{WebSocketError}} object has an associated closeCode, which is +a number or null, and defaults to null. + +Each {{WebSocketError}} object has an associated reason, which is a +string, and defaults to the empty string. + +
+ : |error| = new {{WebSocketError/constructor(message, init)|WebSocketError}}([|message|[, + |init|]]) + :: Creates a new {{WebSocketError}} object. + + |message| is a string which will be used to initialize the {{DOMException/message}} attribute of + the base class. + + The |init| argument is an object whose properties can be set as follows: + + : {{WebSocketCloseInfo/closeCode}} + :: A number, either 1000 or any integer in the range 3000 to 4999, inclusive. Any other + number will result in an "{{InvalidAccessError}}" {{DOMException}}. If a non-empty + {{WebSocketCloseInfo/reason}} is set, defaults to 1000, since there is no way to send a non-empty + reason without a close code. + : {{WebSocketCloseInfo/reason}} + :: A string. Must be 123 bytes or less when converted to [=UTF-8=]. A longer string will result in + a "{{SyntaxError}}" {{DOMException}} being thrown. Defaults to the empty string. + + : |error|.{{WebSocketError/closeCode}} + :: Returns the [=the WebSocket connection close code=]. + + : |error|.{{WebSocketError/reason}} + :: Returns the [=the WebSocket connection close reason=]. +
+ +
+ +
+ +The new +WebSocketError(|message|, |init|) constructor steps are: + + 1. Set [=this=]'s [=DOMException/name=] to "WebSocketError". + 1. Set [=this=]'s [=DOMException/message=] to |message|. + 1. Let |code| be |init|["{{WebSocketCloseInfo/closeCode}}"] if it [=map/exists=], or null + otherwise. + 1. Let |reason| be |init|["{{WebSocketCloseInfo/reason}}"] if it [=map/exists=], or the empty + string otherwise. + 1. [=Validate close code and reason=] with |code| and |reason|. + 1. If |reason| is non-empty, but |code| is null, then set |code| to 1000 ("Normal Closure"). + 1. Set [=this=]'s [=WebSocketError/closeCode=] to |code|. + 1. Set [=this=]'s [=WebSocketError/reason=] to |reason|. +
+ +The closeCode getter steps are to return [=this=]'s +[=WebSocketError/closeCode=]. + +The reason getter steps are to return [=this=]'s +[=WebSocketError/reason=]. + +# Common algorithms # {#common-algorithms} + +These algorithms are shared between the {{WebSocket}} and {{WebSocketStream}} interfaces. + +
+ +To get a URL record given a |url| and |baseURL|: + + 1. Let |urlRecord| be the result of applying the [=URL parser=] to |url| with |baseURL|. + 1. If |urlRecord| is failure, then throw a "{{SyntaxError}}" {{DOMException}}. + 1. If |urlRecord|'s [=url/scheme=] is "`http`", then set |urlRecord|'s [=url/scheme=] to + "[=ws=]". + 1. Otherwise, if |urlRecord|'s [=url/scheme=] is "`https`", set |urlRecord|'s [=url/scheme=] to + "[=wss=]". + 1. If |urlRecord|'s [=scheme=] is not "[=ws=]" or "[=wss=]", then throw a + "{{SyntaxError}}" {{DOMException}}. + 1. If |urlRecord|'s [=fragment=] is non-null, then throw a "{{SyntaxError}}" {{DOMException}}. + 1. Return |urlRecord|. +
+ +
+ +
+ +To validate close code and reason given a |code| and |reason|: + + 1. If |code| is not null, but is neither an integer equal to 1000 nor an integer in the range 3000 + to 4999, inclusive, throw an "{{InvalidAccessError}}" {{DOMException}}. + 1. If |reason| is not null, then: + 1. Let |reasonBytes| be the result of [=UTF-8 encoding=] |reason|. + 1. If |reasonBytes| is longer than 123 bytes, then throw a "{{SyntaxError}}" {{DOMException}}. +
+ +
+ +
+ +To close the WebSocket for a {{WebSocket}} or {{WebSocketStream}} |object|, given +optional |code| and optional |reason|: + + 1. If |code| was not supplied, let |code| be null. + 1. If |reason| was not supplied, let |reason| be the empty string. + 1. [=Validate close code and reason=] with |code| and |reason|. + 1. Run the first matching steps from the following list: +
+ : If |object|'s [=WebSocket/ready state=] is {{WebSocket/CLOSING}} (2) or {{WebSocket/CLOSED}} (3) + :: Do nothing. + +

The connection is already closing or is already closed. If it has not already, a + {{WebSocket/close}} event will eventually fire if |object| is a {{WebSocket}}, or the + {{WebSocketStream/closed}} promise will become settled if |object| is a {{WebSocketStream}}. + + : If the WebSocket connection is not yet [=established=] [[!WSP]] + :: [=Fail the WebSocket connection=] and set |object|'s [=WebSocket/ready state=] to + {{WebSocket/CLOSING}} (2). [[!WSP]] + +

The [=fail the WebSocket connection=] algorithm invokes the [=close the + WebSocket connection=] algorithm, which then establishes that [=the WebSocket connection is + closed=], which fires the {{WebSocket/close}} event if |object| is a {{WebSocket}}, or settles + the {{WebSocketStream/closed}} promise if |object| is a {{WebSocketStream}}. + + : If the WebSocket closing handshake has not yet been started [[!WSP]] + :: [=Start the WebSocket closing handshake=] and set |object|'s [=WebSocket/ready state=] to + {{WebSocket/CLOSING}} (2). [[!WSP]] + + If |code| is null and |reason| is the empty string, the WebSocket Close frame must not have a + body. + +

The WebSocket Protocol erroneously states that the status code is + required for the [=start the WebSocket closing handshake=] + algorithm. + + if |reason| is non-empty but |code| is null, then set |code| to 1000 ("Normal Closure"). + + If |code| is set, then the status code to use in the WebSocket Close + frame must be the integer given by |code|. [[!WSP]] + + If |reason| is non-empty, then |reason|, encoded as UTF-8, must be + provided in the Close frame after the status code. [[!WSP]] + +

The [=start the WebSocket closing handshake=] algorithm eventually invokes the + [=close the WebSocket connection=] algorithm, which then establishes that [=the WebSocket + connection is closed=], which fires the {{WebSocket/close}} event if |object| is a + {{WebSocket}}, or settles the {{WebSocketStream/closed}} promise if |object| is a + {{WebSocketStream}}. + + : Otherwise + :: Set |object|'s [=WebSocket/ready state=] to {{WebSocket/CLOSING}} (2). + +

[=The WebSocket closing handshake is started=], and will eventually invoke the + [=close the WebSocket connection=] algorithm, which will establish that [=the WebSocket + connection is closed=], and thus the {{WebSocket/close}} event will fire or the + {{WebSocketStream/closed}} promise will resolve, depending on the type of |object|. +

+ + +# Ping and Pong frames # {#ping-and-pong-frames} + +The WebSocket Protocol defines Ping and Pong frames that can be used for keep-alive, +heart-beats, network status probing, latency instrumentation, and so forth. These are not currently +exposed in the API. + +User agents may send ping and unsolicited pong frames as desired, for example in an attempt to +maintain local network NAT mappings, to detect failed connections, or to display latency metrics to +the user. User agents must not use pings or unsolicited pongs to aid the server; it is assumed that +servers will solicit pongs whenever appropriate for the server's needs. + + + + +

Acknowledgments

Until the creation of this standard in 2021, the text here was maintained in the