RFC 6455

The WebSocket Protocol

๐Ÿ“… published December 2011, from ietf

RFC 6455: The WebSocket Protocol ๐Ÿฆ‹

Okay bestie, the title block first! ๐ŸŽ€ This one is from the Internet Engineering Task Force (IETF), dated December 2011. The authors are I. Fette (Google, Inc.) and A. Melnikov (Isode Ltd.). It's on the Standards Track and carries ISSN 2070-1721.

Abstract

okay so the WebSocket Protocol gives you two-way communication between a client running untrusted code in a controlled environment and a remote host that has opted in to hearing from that code ๐Ÿ’– The security model is the origin-based one that web browsers already use. The protocol is an opening handshake followed by basic message framing, layered over TCP. The goal is a way for browser apps that need two-way chatter with servers to do it without opening a pile of HTTP connections (like with XMLHttpRequest or <iframe>s and long polling) ๐Ÿ™ˆ

Status of This Memo

This is an Internet Standards Track document. โœจ

This document is a product of the Internet Engineering Task Force (IETF). It represents the consensus of the IETF community. It has had public review and has been approved for publication by the Internet Engineering Steering Group (IESG). More info on Internet Standards is in Section 2 of RFC 5741 ๐Ÿ“š

Info about the current status of this document, any errata, and how to send feedback on it lives at http://www.rfc-editor.org/info/rfc6455 ๐ŸŒธ

Copyright (c) 2011 IETF Trust and the persons identified as the document authors. All rights reserved. ๐Ÿ’œ

This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (http://trustee.ietf.org/license-info) in effect on the date of publication of this document. Please review these documents carefully, because they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Simplified BSD License text as described in Section 4.e of the Trust Legal Provisions, and they are provided without warranty as described in the Simplified BSD License. ๐Ÿซถ

Table of Contents ๐Ÿงš

1.  Introduction . . . . . . . . . . . . . . . . . . . . . . . . .  4
  1.1.  Background . . . . . . . . . . . . . . . . . . . . . . . .  4
  1.2.  Protocol Overview  . . . . . . . . . . . . . . . . . . . .  5
  1.3.  Opening Handshake  . . . . . . . . . . . . . . . . . . . .  6
  1.4.  Closing Handshake  . . . . . . . . . . . . . . . . . . . .  9
  1.5.  Design Philosophy  . . . . . . . . . . . . . . . . . . . .  9
  1.6.  Security Model . . . . . . . . . . . . . . . . . . . . . . 10
  1.7.  Relationship to TCP and HTTP . . . . . . . . . . . . . . . 11
  1.8.  Establishing a Connection  . . . . . . . . . . . . . . . . 11
  1.9.  Subprotocols Using the WebSocket Protocol  . . . . . . . . 12
2.  Conformance Requirements . . . . . . . . . . . . . . . . . . . 12
  2.1.  Terminology and Other Conventions  . . . . . . . . . . . . 13
3.  WebSocket URIs . . . . . . . . . . . . . . . . . . . . . . . . 14
4.  Opening Handshake  . . . . . . . . . . . . . . . . . . . . . . 14
  4.1.  Client Requirements  . . . . . . . . . . . . . . . . . . . 14
  4.2.  Server-Side Requirements . . . . . . . . . . . . . . . . . 20
    4.2.1.  Reading the Client's Opening Handshake . . . . . . . . 21
    4.2.2.  Sending the Server's Opening Handshake . . . . . . . . 22
  4.3.  Collected ABNF for New Header Fields Used in Handshake . . 25
  4.4.  Supporting Multiple Versions of WebSocket Protocol . . . . 26
5.  Data Framing . . . . . . . . . . . . . . . . . . . . . . . . . 27
  5.1.  Overview . . . . . . . . . . . . . . . . . . . . . . . . . 27
  5.2.  Base Framing Protocol  . . . . . . . . . . . . . . . . . . 28
  5.3.  Client-to-Server Masking . . . . . . . . . . . . . . . . . 32
  5.4.  Fragmentation  . . . . . . . . . . . . . . . . . . . . . . 33
  5.5.  Control Frames . . . . . . . . . . . . . . . . . . . . . . 36
    5.5.1.  Close  . . . . . . . . . . . . . . . . . . . . . . . . 36
    5.5.2.  Ping . . . . . . . . . . . . . . . . . . . . . . . . . 37
    5.5.3.  Pong . . . . . . . . . . . . . . . . . . . . . . . . . 37
  5.6.  Data Frames  . . . . . . . . . . . . . . . . . . . . . . . 38
  5.7.  Examples . . . . . . . . . . . . . . . . . . . . . . . . . 38
  5.8.  Extensibility  . . . . . . . . . . . . . . . . . . . . . . 39
6.  Sending and Receiving Data . . . . . . . . . . . . . . . . . . 39
  6.1.  Sending Data . . . . . . . . . . . . . . . . . . . . . . . 39
  6.2.  Receiving Data . . . . . . . . . . . . . . . . . . . . . . 40
7.  Closing the Connection . . . . . . . . . . . . . . . . . . . . 41
  7.1.  Definitions  . . . . . . . . . . . . . . . . . . . . . . . 41
    7.1.1.  Close the WebSocket Connection . . . . . . . . . . . . 41
    7.1.2.  Start the WebSocket Closing Handshake  . . . . . . . . 42
    7.1.3.  The WebSocket Closing Handshake is Started . . . . . . 42
    7.1.4.  The WebSocket Connection is Closed . . . . . . . . . . 42
    7.1.5.  The WebSocket Connection Close Code  . . . . . . . . . 42
    7.1.6.  The WebSocket Connection Close Reason  . . . . . . . . 43
    7.1.7.  Fail the WebSocket Connection  . . . . . . . . . . . . 43
  7.2.  Abnormal Closures  . . . . . . . . . . . . . . . . . . . . 44
    7.2.1.  Client-Initiated Closure . . . . . . . . . . . . . . . 44
    7.2.2.  Server-Initiated Closure . . . . . . . . . . . . . . . 44
    7.2.3.  Recovering from Abnormal Closure . . . . . . . . . . . 44
  7.3.  Normal Closure of Connections  . . . . . . . . . . . . . . 45
  7.4.  Status Codes . . . . . . . . . . . . . . . . . . . . . . . 45
    7.4.1.  Defined Status Codes . . . . . . . . . . . . . . . . . 45
    7.4.2.  Reserved Status Code Ranges  . . . . . . . . . . . . . 47
8.  Error Handling . . . . . . . . . . . . . . . . . . . . . . . . 48
  8.1.  Handling Errors in UTF-8-Encoded Data  . . . . . . . . . . 48
9.  Extensions . . . . . . . . . . . . . . . . . . . . . . . . . . 48
  9.1.  Negotiating Extensions . . . . . . . . . . . . . . . . . . 48
  9.2.  Known Extensions . . . . . . . . . . . . . . . . . . . . . 50
10. Security Considerations  . . . . . . . . . . . . . . . . . . . 50
  10.1. Non-Browser Clients  . . . . . . . . . . . . . . . . . . . 50
  10.2. Origin Considerations  . . . . . . . . . . . . . . . . . . 50
  10.3. Attacks On Infrastructure (Masking)  . . . . . . . . . . . 51
  10.4. Implementation-Specific Limits . . . . . . . . . . . . . . 52
  10.5. WebSocket Client Authentication  . . . . . . . . . . . . . 53
  10.6. Connection Confidentiality and Integrity . . . . . . . . . 53
  10.7. Handling of Invalid Data . . . . . . . . . . . . . . . . . 53
  10.8. Use of SHA-1 by the WebSocket Handshake  . . . . . . . . . 54
11. IANA Considerations  . . . . . . . . . . . . . . . . . . . . . 54
  11.1. Registration of New URI Schemes  . . . . . . . . . . . . . 54
    11.1.1. Registration of "ws" Scheme  . . . . . . . . . . . . . 54
    11.1.2. Registration of "wss" Scheme . . . . . . . . . . . . . 55
  11.2. Registration of the "WebSocket" HTTP Upgrade Keyword . . . 56
  11.3. Registration of New HTTP Header Fields . . . . . . . . . . 57
    11.3.1. Sec-WebSocket-Key  . . . . . . . . . . . . . . . . . . 57
    11.3.2. Sec-WebSocket-Extensions . . . . . . . . . . . . . . . 58
    11.3.3. Sec-WebSocket-Accept . . . . . . . . . . . . . . . . . 58
    11.3.4. Sec-WebSocket-Protocol . . . . . . . . . . . . . . . . 59
    11.3.5. Sec-WebSocket-Version  . . . . . . . . . . . . . . . . 60
  11.4. WebSocket Extension Name Registry  . . . . . . . . . . . . 61
  11.5. WebSocket Subprotocol Name Registry  . . . . . . . . . . . 61
  11.6. WebSocket Version Number Registry  . . . . . . . . . . . . 62
  11.7. WebSocket Close Code Number Registry . . . . . . . . . . . 64
  11.8. WebSocket Opcode Registry  . . . . . . . . . . . . . . . . 65
  11.9. WebSocket Framing Header Bits Registry . . . . . . . . . . 66
12. Using the WebSocket Protocol from Other Specifications . . . . 66
13. Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . 67
14. References . . . . . . . . . . . . . . . . . . . . . . . . . . 68
  14.1. Normative References . . . . . . . . . . . . . . . . . . . 68
  14.2. Informative References . . . . . . . . . . . . . . . . . . 69

1. Introduction โœจ

1.1. Background ๐Ÿ’…

This section is non-normative.

Historically, if you wanted a web app where the client and server could both talk whenever they wanted (think instant messaging and gaming apps), you had to basically abuse HTTP. You'd keep polling the server for updates, and send your upstream notifications as separate HTTP calls [RFC6202]. Iconic behaviour, not ๐Ÿ™ƒ

This gives you a bunch of problems:

  • The server is forced to use a number of different underlying TCP connections for each client: one for sending information to the client, and a new one for each incoming message.
  • The wire protocol has a high overhead, with each client-to-server message carrying an HTTP header.
  • The client-side script is forced to maintain a mapping from the outgoing connections to the incoming connection so it can track replies.

A simpler solution would be to use a single TCP connection for traffic in both directions ๐Ÿฆ‹ That's what the WebSocket Protocol gives you. Paired with the WebSocket API [WSAPI], it's an alternative to HTTP polling for two-way communication from a web page to a remote server. Literally the main character move ๐Ÿ‘‘

The same technique works for a whole bunch of web apps: games, stock tickers, multiuser apps with simultaneous editing, user interfaces that expose server-side services in real time, and so on. ๐ŸŒˆ

The WebSocket Protocol is designed to supersede existing bidirectional communication technologies that use HTTP as a transport layer. The point is to benefit from existing infrastructure (proxies, filtering, authentication). Those older technologies were trade-offs between efficiency and reliability, because HTTP was not originally meant for bidirectional communication (see [RFC6202] for more on that) ๐Ÿฅน WebSocket tries to hit the goals of those HTTP-based techniques while working inside the existing HTTP infrastructure. So it's designed to work over HTTP ports 80 and 443, and to support HTTP proxies and intermediaries, even if that means some complexity specific to today's environment. โœจ

However, the design doesn't limit WebSocket to HTTP. Future implementations could use a simpler handshake over a dedicated port without reinventing the entire protocol. This last point is a big deal, because the traffic patterns of interactive messaging don't closely match standard HTTP traffic, and they can induce unusual loads on some components ๐Ÿ’€

1.2. Protocol Overview โœจ

_This section is non-normative._ ๐ŸŽ€

Okay so the protocol has two parts: a handshake and then the data transfer. ๐Ÿ’–

The client's handshake looks like this:

GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: http://example.com
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13

And the server's handshake looks like this:

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Sec-WebSocket-Protocol: chat

The first line from the client follows the Request-Line format, and the first line from the server follows the Status-Line format. Both Request-Line and Status-Line are defined in [RFC2616], so you know where to look. ๐Ÿงš

After that first line, both sides send an unordered set of header fields. What those header fields mean is spelled out in Section 4 of this document. There can be extra header fields too, like cookies [RFC6265]. The format and parsing of headers is as defined in [RFC2616]. ๐Ÿ“

Once the client and server have both sent their handshakes, and the handshake worked out, the data transfer part kicks off. This is a two-way channel where each side can send data whenever it wants, totally independently of the other. Main character energy, literally. ๐Ÿ‘‘

After a successful handshake, clients and servers pass data back and forth in units this specification calls "messages". On the wire, a message is made of one or more frames. A WebSocket message doesn't have to line up with any particular network layer framing, because an intermediary is allowed to coalesce or split a fragmented message. ๐Ÿฆ‹

Every frame has a type, and every frame in the same message carries the same type of data. Broadly speaking, there are types for textual data (which gets interpreted as UTF-8 [RFC3629] text), types for binary data (what it means is up to the application), and types for control frames. Control frames aren't meant to carry data for the app. They're for protocol-level signaling, like telling the other side the connection should be closed. ๐Ÿ’… This version of the protocol defines six frame types and leaves ten reserved for future use. Iconic restraint, honestly. โœจ


1.3. Opening Handshake ๐ŸŒธ

_This section is non-normative._ ๐ŸŽ€

The opening handshake is designed to play nicely with HTTP-based server software and intermediaries. That way a single port can serve both regular HTTP clients and WebSocket clients talking to the same server. So the WebSocket client's handshake is an HTTP Upgrade request, like this:

GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: http://example.com
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13

Following [RFC2616], header fields in the handshake can be sent by the client in any order, so the order you receive them in doesn't matter. No cap, that's a relief. ๐Ÿ™ˆ

The Request-URI of the GET method [RFC2616] is used to identify the endpoint of the WebSocket connection. This lets multiple domains share one IP address, and it lets one server host multiple WebSocket endpoints. ๐ŸŒˆ

The client puts the hostname in the Host header field of its handshake as per [RFC2616]. That way both the client and the server can check that they agree on which host is in use. ๐Ÿซถ

Extra header fields are used to pick options in the WebSocket Protocol. The typical options in this version are the subprotocol selector (Sec-WebSocket-Protocol), the list of extensions the client supports (Sec-WebSocket-Extensions), the Origin header field, and so on. The Sec-WebSocket-Protocol request-header field says which subprotocols (application-level protocols layered over the WebSocket Protocol) the client finds acceptable. The server picks one of them, or none, and echoes that value back in its handshake to show which one it picked. ๐Ÿ’œ

Sec-WebSocket-Protocol: chat

The Origin header field [RFC6454] is there to protect against unauthorized cross-origin use of a WebSocket server by scripts running the WebSocket API in a web browser. The server gets told which script origin started the WebSocket connection request. If the server doesn't want to accept connections from that origin, it can reject the connection by sending an appropriate HTTP error code. Browsers send this header field. Non-browser clients can send it too, if it makes sense for them. ๐Ÿ”ฅ

Next up, the server has to prove to the client that it actually received the client's WebSocket handshake. That way it won't accept connections that aren't WebSocket connections in the first place. This stops an attacker from tricking a WebSocket server into doing something by sending it carefully crafted packets via XMLHttpRequest [XMLHttpRequest] or a form submission. Not on my watch. ๐Ÿ’€

To prove it got the handshake, the server takes two pieces of information and combines them into a response. The first piece comes from the Sec-WebSocket-Key header field in the client handshake:

Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==

For this header field, the server takes the value (as it appears in the header field, for example the base64-encoded [RFC4648] version, minus any leading and trailing whitespace) and concatenates it with the Globally Unique Identifier (GUID, [RFC4122]) "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" in string form. That GUID is unlikely to be used by network endpoints that don't understand the WebSocket Protocol. The server then takes a SHA-1 hash (160 bits) [FIPS.180-3] of that concatenation, base64-encodes it (see Section 4 of [RFC4648]), and sends the result back in its handshake. ๐Ÿง 

Let's make it concrete. In the example above, the Sec-WebSocket-Key header field had the value "dGhlIHNhbXBsZSBub25jZQ==". So the server concatenates the string "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" onto it, which gives "dGhlIHNhbXBsZSBub25jZQ==258EAFA5-E914-47DA-95CA-C5AB0DC85B11". Then it takes the SHA-1 hash of that, which comes out as 0xb3 0x7a 0x4f 0x2c 0xc0 0x62 0x4f 0x16 0x90 0xf6 0x46 0x06 0xcf 0x38 0x59 0x45 0xb2 0xbe 0xc4 0xea. That value gets base64-encoded (see Section 4 of [RFC4648]) to give "s3pPLMBiTxaQ9kYGzzhZRbK+xOo=". This value is what gets echoed back in the Sec-WebSocket-Accept header field. Math with a plot twist ๐Ÿค“โœจ

The server's handshake is way simpler than the client's. The first line is an HTTP Status-Line with status code 101:

HTTP/1.1 101 Switching Protocols

Any status code other than 101 means the WebSocket handshake hasn't completed, and the semantics of HTTP still apply. The headers come after the status code. ๐Ÿ™ƒ

The Connection and Upgrade header fields complete the HTTP Upgrade. The Sec-WebSocket-Accept header field shows whether the server is willing to accept the connection. If it's present, this header field must include a hash of the client's nonce sent in Sec-WebSocket-Key, along with the predefined GUID. Any other value must not be taken as the server accepting the connection. Be picky about it, bestie. ๐Ÿซ 

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=

For scripted pages, the WebSocket client checks these fields. If the Sec-WebSocket-Accept value doesn't match the expected value, if the header field is missing, or if the HTTP status code isn't 101, the connection won't be established, and no WebSocket frames get sent. Period. ๐Ÿšซ

There can also be option fields in the response. In this version the main one is Sec-WebSocket-Protocol, which tells the client which subprotocol the server picked. WebSocket clients verify that the server included one of the values the client specified in its handshake. A server that speaks more than one subprotocol has to pick one based on the client's handshake and then put it in its own handshake. ๐Ÿ’…

Sec-WebSocket-Protocol: chat

The server can also set cookie-related option fields to _set_ cookies, as described in [RFC6265]. ๐Ÿช


1.4. Closing Handshake ๐Ÿฆ‹

_This section is non-normative._ ๐ŸŽ€

The closing handshake is way simpler than the opening one. Lowkey a relief. ๐Ÿ˜ฎโ€๐Ÿ’จ

Either peer can send a control frame, with data containing a specified control sequence, to start the closing handshake (detailed in Section 5.5.1). When the other peer gets that frame, it sends a Close frame back in response, as long as it hasn't already sent one. When the first peer receives _that_ control frame, it closes the connection, safe in the knowledge that no more data is coming. Peak closure energy. ๐ŸŒธ

After a peer sends a control frame saying the connection should be closed, it doesn't send any more data. After a peer receives a control frame saying the connection should be closed, it throws away any further data it receives. ๐Ÿ—‘๏ธ

It's safe for both peers to start this handshake at the same time. ๐Ÿซถ

The closing handshake is meant to complement the TCP closing handshake (FIN/ACK), because the TCP closing handshake isn't always reliable end-to-end. That's especially true when there are intercepting proxies and other intermediaries in the way. ๐Ÿงš

By sending a Close frame and then waiting for a Close frame in response, certain cases are avoided where data could be lost for no reason. For instance, on some platforms, if a socket is closed while there's data in the receive queue, a RST packet is sent. That causes recv() to fail for the party that got the RST, even if there was data waiting to be read. Bestie, that's a whole trauma arc, and the closing handshake exists so we never have to live it. ๐Ÿ˜ญ๐Ÿ’œ

1.5. Design Philosophy โœจ

_This section is non-normative._

Okay so the WebSocket Protocol is built on one big principle: minimal framing ๐Ÿ’…. The only framing that exists is there to make the protocol frame-based instead of stream-based ๐ŸŽ€ and to tell Unicode text frames apart from binary frames. Anything fancier is supposed to be layered on top by the application layer, the same way metadata gets layered on top of TCP by the application layer (HTTP is the classic example) ๐Ÿงš.

Conceptually, WebSocket is really just a layer on top of TCP that does the following:

  • adds a web origin-based security model for browsers ๐Ÿ”
  • adds an addressing and protocol naming mechanism to support multiple services on one port and multiple host names on one IP address ๐ŸŒ
  • layers a framing mechanism on top of TCP to get back to the IP packet mechanism that TCP is built on, but without length limits ๐Ÿ“ฆ
  • includes an additional closing handshake in-band that is designed to work in the presence of proxies and other intermediaries ๐Ÿซถ

Other than that, WebSocket adds nothing. Lowkey that's the whole point: it's basically raw TCP exposed to script, as close as the Web allows ๐Ÿฆ‹. It's also designed so its servers can share a port with HTTP servers, because the handshake is a valid HTTP Upgrade request. Iconic, right? ๐Ÿ‘‘ You could conceptually use other protocols for client-server messaging, but WebSockets are meant to be a relatively simple protocol that coexists with HTTP and the HTTP infrastructure already out there (like proxies). It stays as close to TCP as is safe for that infrastructure, given the security considerations, and adds a few targeted things to keep simple things simple, like message semantics โœจ.

The protocol is meant to be extensible, and future versions will likely add stuff like multiplexing ๐ŸŒˆ.

1.6. Security Model

_This section is non-normative._

The WebSocket Protocol uses the same origin model that web browsers use, to control which web pages can contact a WebSocket server when the protocol is used from a web page ๐Ÿ•ธ๏ธ. But if a dedicated client uses the protocol directly (so not from a web page in a browser), the origin model isn't really useful, because that client can send any arbitrary origin string ๐Ÿ™ˆ.

This protocol is meant to fail to connect to servers of pre-existing protocols like SMTP [RFC5321] and HTTP, while still letting HTTP servers opt-in to supporting it if they want ๐Ÿง. The way it does this is with a strict and elaborate handshake, plus by limiting how much data can be stuffed into the connection before the handshake is finished (so the server can't be influenced too much) ๐Ÿ›ก๏ธ.

It's also meant to fail to connect when data from other protocols, especially HTTP, gets sent to a WebSocket server. For example, that could happen if an HTML "form" got submitted to one ๐Ÿ’€. This is mainly handled by requiring the server to prove it read the handshake, which it can only do if the handshake has the right parts, and only a WebSocket client can send those ๐Ÿ”‘. Also, at the time of writing this spec, fields starting with Sec- can't be set by an attacker from a web browser using only HTML and JavaScript APIs like XMLHttpRequest [XMLHttpRequest] ๐Ÿ™Œ.

1.7. Relationship to TCP and HTTP

_This section is non-normative._

The WebSocket Protocol is its own independent TCP-based protocol ๐Ÿงš. Its only relationship to HTTP is that HTTP servers interpret its handshake as an Upgrade request.

By default, WebSocket uses port 80 for regular connections and port 443 for connections tunneled over Transport Layer Security (TLS) [RFC2818] ๐Ÿ”’.

1.8. Establishing a Connection

_This section is non-normative._

When a connection is made to a port shared by an HTTP server (which is super likely on ports 80 and 443 ๐Ÿ˜ญ), the connection will look to the HTTP server like a regular GET request with an Upgrade offer. In simple setups with one IP address and one server handling all traffic for a single hostname, this might be a practical way to deploy WebSocket-based systems ๐Ÿ“. In more elaborate setups (think load balancers and multiple servers), it's probably easier to manage a dedicated set of hosts just for WebSocket connections, separate from the HTTP servers ๐Ÿ› ๏ธ.

At the time of writing this spec, it should be noted that connections on ports 80 and 443 have very different success rates. Connections on port 443 are significantly more likely to succeed, though that may change with time ๐Ÿ“ˆ. Not me noticing this as the main character of the internet ๐Ÿ’….

1.9. Subprotocols Using the WebSocket Protocol

_This section is non-normative._

The client can ask the server to use a specific subprotocol by including the Sec-WebSocket-Protocol field in its handshake ๐ŸŽ€. If one is specified, the server needs to include the same field, plus one of the selected subprotocol values, in its response for the connection to be established ๐Ÿค.

These subprotocol names should be registered as per Section 11.5. To avoid collisions, it is recommended to use names that contain the ASCII version of the domain name of the subprotocol's originator ๐Ÿชช. For example, if Example Corporation made a Chat subprotocol for lots of servers around the Web, they could name it "chat.example.com". If the Example Organization made a competing one called "chat.example.org", then both could be implemented by servers at the same time, and the server would pick which one to use based on what the client sent ๐Ÿ‘ฏโ€โ™€๏ธ. Ate and left no crumbs ๐Ÿ’….

Subprotocols can be versioned in backward-incompatible ways by changing the subprotocol name, e.g., going from "bookings.example.net" to "v2.bookings.example.net". WebSocket clients would treat those as completely separate subprotocols ๐Ÿฆ‹. Backward-compatible versioning is possible by reusing the same subprotocol string and carefully designing the subprotocol so it can stretch and extend ๐ŸŒธ.


2. Conformance Requirements โœจ

All diagrams, examples, and notes in this specification are non-normative, as are all sections explicitly marked non-normative. Everything else in this specification is normative ๐Ÿ“œ.

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC2119]. These are the official capital-letter power words, so read them carefully ๐Ÿ”ฅ.

Requirements written in the imperative as part of algorithms (like "strip any leading space characters" or "return false and abort these steps") are interpreted with the force of the key word ("MUST", "SHOULD", "MAY", etc.) used when introducing the algorithm ๐Ÿงฎ.

Conformance requirements phrased as algorithms or specific steps MAY be implemented in any manner, as long as the end result is equivalent. (The algorithms here are meant to be easy to follow, not fast ๐Ÿข.)

2.1. Terminology and Other Conventions

_ASCII_ shall mean the character-encoding scheme defined in [ANSI.X3-4.1986]. (Lowercase "shall," not the loud capital SHALL, so it's just a plain old word here ๐Ÿค“.)

This document references UTF-8 values and uses UTF-8 notational formats as defined in STD 63 [RFC3629] ๐Ÿ”ค.

Key terms like named algorithms or definitions are marked like _this_ โœจ.

Names of header fields or variables are marked like |this| ๐Ÿท๏ธ.

Variable values are marked like /this/ ๐ŸŽฏ.

This document references the procedure to _Fail the WebSocket Connection_. That procedure is defined in Section 7.1.7 ๐Ÿ’ฅ.

_Converting a string to ASCII lowercase_ means replacing every character in the range U+0041 to U+005A (so LATIN CAPITAL LETTER A to LATIN CAPITAL LETTER Z) with the matching character in the range U+0061 to U+007A (LATIN SMALL LETTER A to LATIN SMALL LETTER Z) ๐Ÿ”ก.

Comparing two strings in an _ASCII case-insensitive_ way means comparing them exactly, code point for code point, except that the characters in the range U+0041 to U+005A (LATIN CAPITAL LETTER A to LATIN CAPITAL LETTER Z) and the matching characters in the range U+0061 to U+007A (LATIN SMALL LETTER A to LATIN SMALL LETTER Z) are also considered to match ๐Ÿซ .

The term "URI" is used in this document as defined in [RFC3986] ๐ŸŒ.

When an implementation is required to _send_ data as part of the WebSocket Protocol, the implementation MAY delay the actual transmission for as long as it likes. For example, it can buffer data so it sends fewer IP packets ๐Ÿ“ฆโœจ.

Note that this document uses both [RFC5234] and [RFC2616] variants of ABNF in different sections ๐Ÿง .


3. WebSocket URIs ๐Ÿฆ‹

This specification defines two URI schemes, using the ABNF syntax defined in RFC 5234 [RFC5234], along with terminology and ABNF productions defined by the URI specification, RFC 3986 [RFC3986] ๐Ÿ“–.

          ws-URI = "ws:" "//" host [ ":" port ] path [ "?" query ]
          wss-URI = "wss:" "//" host [ ":" port ] path [ "?" query ]

          host = <host, defined in [RFC3986], Section 3.2.2>
          port = <port, defined in [RFC3986], Section 3.2.3>
          path = <path-abempty, defined in [RFC3986], Section 3.3>
          query = <query, defined in [RFC3986], Section 3.4>

The port component is OPTIONAL. The default for "ws" is port 80, and the default for "wss" is port 443 ๐Ÿ”Œ.

The URI is called "secure" (and it's said that "the secure flag is set") if the scheme component matches "wss" case-insensitively ๐Ÿ”.

The "resource-name" (also known as /resource name/ in Section 4.1) can be built by concatenating the following:

  • "/" if the path component is empty
  • the path component
  • "?" if the query component is non-empty
  • the query component

Fragment identifiers are meaningless in the context of WebSocket URIs and MUST NOT be used on these URIs. As with any URI scheme, the character "#", when it's not marking the start of a fragment, MUST be escaped as %23. Bestie, don't be the person who forgets the escape ๐Ÿ™ˆ๐Ÿ’€.


4. Opening Handshake ๐Ÿค

4.1. Client Requirements

To _Establish a WebSocket Connection_, a client opens a connection and sends a handshake as defined in this section. A connection is defined to start in a CONNECTING state ๐Ÿšช. A client needs to supply a /host/, /port/, /resource name/, and a /secure/ flag. Those are the components of a WebSocket URI from Section 3, along with a list of /protocols/ and /extensions/ to be used ๐Ÿงฉ. Also, if the client is a web browser, it supplies /origin/ ๐ŸŒ.

Clients running in controlled environments, like browsers on mobile handsets tied to specific carriers, MAY offload the management of the connection to another agent on the network. In that case, the client, for the purposes of this specification, is considered to include both the handset software and any such agents ๐Ÿ“ฑโœจ.

Okay so bestie, this is where the client actually does the thing ๐Ÿ’– When it's told to Establish a WebSocket Connection with a host, port, resource name, and secure flag, plus a list of protocols and extensions and an origin if it's a web browser, it MUST open a connection, send an opening handshake, and read the server's handshake back ๐Ÿฆ‹ The exact rules for opening the connection, what goes in the opening handshake, and how the server's reply gets read are below โœจ In the following text we'll use terms from Section 3, like "host" and "secure flag", which are defined there ๐ŸŽ€

  1. The components of the WebSocket URI passed into this algorithm (host, port, resource name, and secure flag) MUST be valid according to the specification of WebSocket URIs in Section 3. If any of the components are invalid, the client MUST Fail the WebSocket Connection and abort these steps. ๐Ÿ’€
  2. If the client already has a WebSocket connection to the remote host (IP address) identified by host and port port pair, even if the remote host is known by another name, the client MUST wait until that connection has been established or for that connection to have failed. There MUST be no more than one connection in a CONNECTING state. If multiple connections to the same IP address are attempted simultaneously, the client MUST serialize them so that there is no more than one connection at a time running through the following steps. ๐Ÿซถ

If the client cannot determine the IP address of the remote host (for example, because all communication is being done through a proxy server that performs DNS queries itself), then the client MUST assume for the purposes of this step that each host name refers to a distinct remote host, and instead the client SHOULD limit the total number of simultaneous pending connections to a reasonably low number (e.g., the client might allow simultaneous pending connections to a.example.com and b.example.com, but if thirty simultaneous connections to a single host are requested, that may not be allowed). For example, in a web browser context, the client needs to consider the number of tabs the user has open in setting a limit to the number of simultaneous pending connections. ๐ŸŒธ

NOTE: This makes it harder for a script to perform a denial-of-service attack by just opening a large number of WebSocket connections to a remote host. A server can further reduce the load on itself when attacked by pausing before closing the connection, as that will reduce the rate at which the client reconnects. ๐Ÿ™ˆ
NOTE: There is no limit to the number of established WebSocket connections a client can have with a single remote host. Servers can refuse to accept connections from hosts/IP addresses with an excessive number of existing connections or disconnect resource-hogging connections when suffering high load. ๐Ÿ‘‘
  1. Proxy Usage: If the client is configured to use a proxy when using the WebSocket Protocol to connect to host host and port port, then the client SHOULD connect to that proxy and ask it to open a TCP connection to the host given by host and the port given by port. ๐Ÿงš

EXAMPLE: For example, if the client uses an HTTP proxy for all traffic, 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:80 HTTP/1.1
Host: example.com

If there was a password, the connection might look like:

CONNECT example.com:80 HTTP/1.1
Host: example.com
Proxy-authorization: Basic ZWRuYW1vZGU6bm9jYXBlcyE=

If the client is not configured to use a proxy, then a direct TCP connection SHOULD be opened to the host given by host and the port given by port. ๐Ÿ“

NOTE: Implementations that do not expose explicit UI for selecting a proxy for WebSocket connections separate from other proxies are encouraged to use a SOCKS5 [RFC1928] proxy for WebSocket connections, if available, or failing that, to prefer the proxy configured for HTTPS connections over the proxy configured for HTTP connections. ๐Ÿ’…

For the purpose of proxy autoconfiguration scripts, the URI to pass the function MUST be constructed from host, port, resource name, and the secure flag using the definition of a WebSocket URI as given in Section 3. โœจ

NOTE: The WebSocket Protocol can be identified in proxy autoconfiguration scripts from the scheme ("ws" for unencrypted connections and "wss" for encrypted connections). ๐ŸŒˆ
  1. If the connection could not be opened, either because a direct connection failed or because any proxy used returned an error, then the client MUST Fail the WebSocket Connection and abort the connection attempt. ๐Ÿ˜ญ
  2. If secure is true, the client MUST perform a TLS handshake over the connection after opening the connection and before sending the handshake data [RFC2818]. If this fails (e.g., the server's certificate could not be verified), then the client MUST Fail the WebSocket Connection and abort the connection. Otherwise, all further communication on this channel MUST run through the encrypted tunnel [RFC5246]. ๐Ÿ”

Clients MUST use the Server Name Indication extension in the TLS handshake [RFC6066]. ๐ŸŽ€


Once a connection to the server has been established (including a connection via a proxy or over a TLS-encrypted tunnel), the client MUST send an opening handshake to the server. The handshake consists of an HTTP Upgrade request, along with a list of required and optional header fields. The requirements for this handshake are as follows. ๐Ÿฆ‹

  1. The handshake MUST be a valid HTTP request as specified by [RFC2616]. ๐Ÿ’–
  2. The method of the request MUST be GET, and the HTTP version MUST be at least 1.1.

For example, if the WebSocket URI is "ws://example.com/chat", the first line sent should be GET /chat HTTP/1.1. ๐ŸŒธ

  1. The "Request-URI" part of the request MUST match the resource name defined in Section 3 (a relative URI) or be an absolute http/https URI that, when parsed, has a resource name, host, and port that match the corresponding ws/wss URI. ๐Ÿงš
  2. The request MUST contain a Host header field whose value contains host plus optionally ":" followed by port (when not using the default port). ๐Ÿ“
  3. The request MUST contain an Upgrade header field whose value MUST include the "websocket" keyword. โญ
  4. The request MUST contain a Connection header field whose value MUST include the "Upgrade" token. ๐Ÿ’œ
  5. The request MUST include a header field with the name Sec-WebSocket-Key. The value of this header field MUST be a nonce consisting of a randomly selected 16-byte value that has been base64-encoded (see Section 4 of [RFC4648]). The nonce MUST be selected randomly for each connection. ๐Ÿ”ฅ

NOTE: As an example, if the randomly selected value was the sequence of bytes 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0a 0x0b 0x0c 0x0d 0x0e 0x0f 0x10, the value of the header field would be "AQIDBAUGBwgJCgsMDQ4PEC==" ๐Ÿง

  1. The request MUST include a header field with the name Origin [RFC6454] if the request is coming from a browser client. If the connection is from a non-browser client, the request MAY include this header field if the semantics of that client match the use-case described here for browser clients. The value of this header field is the ASCII serialization of origin of the context in which the code establishing the connection is running. See [RFC6454] for the details of how this header field value is constructed. ๐ŸŒ

As an example, if code downloaded from www.example.com attempts to establish a connection to ww2.example.com, the value of the header field would be "http://www.example.com". โœจ

  1. The request MUST include a header field with the name Sec-WebSocket-Version. The value of this header field MUST be 13. ๐ŸŽ€

NOTE: Although draft versions of this document (-09, -10, -11, and -12) were posted (they were mostly comprised of editorial changes and clarifications and not changes to the wire protocol), values 9, 10, 11, and 12 were not used as valid values for Sec-WebSocket-Version. These values were reserved in the IANA registry but were not and will not be used. ๐Ÿ“‹

  1. The request MAY include a header field with the name Sec-WebSocket-Protocol. If present, this value indicates one or more comma-separated subprotocol the client wishes to speak, ordered by preference. The elements that comprise this value MUST be non-empty strings with characters in the range U+0021 to U+007E not including separator characters as defined in [RFC2616] and MUST all be unique strings. The ABNF for the value of this header field is 1#token, where the definitions of constructs and rules are as given in [RFC2616]. ๐ŸŒŸ
  2. The request MAY include a header field with the name Sec-WebSocket-Extensions. If present, this value indicates the protocol-level extension(s) the client wishes to speak. The interpretation and format of this header field is described in Section 9.1. ๐Ÿงฉ
  3. The request MAY include any other header fields, for example, cookies [RFC6265] and/or authentication-related header fields such as the Authorization header field [RFC2616], which are processed according to documents that define them. ๐Ÿช

Once the client's opening handshake has been sent, the client MUST wait for a response from the server before sending any further data. The client MUST validate the server's response as follows: ๐Ÿ‘€

  1. If the status code received from the server is not 101, the client handles the response per HTTP [RFC2616] procedures. In particular, the client might perform authentication if it receives a 401 status code; the server might redirect the client using a 3xx status code (but clients are not required to follow them), etc. Otherwise, proceed as follows. ๐Ÿ”
  2. If the response lacks an Upgrade header field or the Upgrade header field contains a value that is not an ASCII case-insensitive match for the value "websocket", the client MUST Fail the WebSocket Connection. ๐Ÿšซ
  3. If the response lacks a Connection header field or the Connection header field doesn't contain a token that is an ASCII case-insensitive match for the value "Upgrade", the client MUST Fail the WebSocket Connection. ๐Ÿšซ
  4. If the response lacks a Sec-WebSocket-Accept header field or the Sec-WebSocket-Accept contains a value other than the base64-encoded SHA-1 of the concatenation of the Sec-WebSocket-Key (as a string, not base64-decoded) with the string "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" but ignoring any leading and trailing whitespace, the client MUST Fail the WebSocket Connection. ๐Ÿšซ

That's the whole client side of the handshake, bestie! ๐ŸŒˆ๐Ÿ‘‘

  1. Okay bestie, if the server's response has a Sec-WebSocket-Extensions header that says it's using an extension the client never asked for (the server crashed the party uninvited ๐Ÿ’€), the client MUST Fail the WebSocket Connection. (How to parse that header to figure out which extensions were requested is covered in Section 9.1 ๐Ÿฆ‹.)
  2. Same energy for Sec-WebSocket-Protocol. If the response includes that header and it says the server wants a subprotocol the client didn't request, the client MUST Fail the WebSocket Connection ๐Ÿšซ.

If the server's response doesn't meet the server's handshake requirements from this section and from Section 4.2.2, the client MUST Fail the WebSocket Connection ๐Ÿ’…. No exceptions, no drama ๐Ÿ™…โ€โ™€๏ธ.

Also, according to [RFC2616], all header field names in both HTTP requests and HTTP responses are case-insensitive. So Upgrade, upgrade, and UPGRADE are all the same field to us ๐ŸŒˆ.

If the server's response passes all the checks above, it is said that The WebSocket Connection is Established โœจ๐ŸŽ‰, and the WebSocket Connection is in the OPEN state. Two things get locked in at this point:

  • Extensions In Use is a string that can be empty. Its value is whatever the server sent in Sec-WebSocket-Extensions, or null if that header wasn't in the server's handshake ๐Ÿงฉ.
  • Subprotocol In Use is the value of Sec-WebSocket-Protocol from the server's handshake, or null if that header wasn't there ๐ŸŽ€.

And if any header fields in the server's handshake say that cookies should be set (as defined by [RFC6265]), those cookies are called Cookies Set During the Server's Opening Handshake ๐Ÿช. Iconic naming, honestly ๐Ÿ˜ญ.

4.2. Server-Side Requirements ๐Ÿงš

Servers MAY offload management of the connection to other agents on the network, like load balancers and reverse proxies ๐ŸŒธ. When that happens, the "server" for this spec means every piece of server-side infrastructure, from the first device that terminates the TCP connection all the way to the server that processes requests and sends responses. Main character behavior, all of it ๐Ÿ‘‘.

EXAMPLE: A data center might have one machine that answers WebSocket requests with the proper handshake, then hands the connection off to a different machine that actually handles the data frames. For this specification, the "server" is both computers together ๐Ÿ’œ.

4.2.1. Reading the Client's Opening Handshake ๐ŸŽ€

When a client starts a WebSocket connection, it sends its part of the opening handshake ๐Ÿค. The server must parse at least part of that handshake so it knows what it needs to build the server's part.

Here's what the client's opening handshake has to include. If the server, while reading it, finds that the client didn't send a handshake matching this description (remember, per [RFC2616], the order of header fields doesn't matter ๐Ÿ™ƒ), including but not limited to any violations of the ABNF grammar specified for the handshake components, the server MUST stop processing the client's handshake and return an HTTP response with an appropriate error code, such as 400 Bad Request ๐Ÿšจ. Rude, but necessary ๐Ÿ’€.

  1. An HTTP/1.1 or higher GET request, including a "Request-URI" [RFC2616] that should be interpreted as a resource name defined in Section 3 (or an absolute HTTP/HTTPS URI containing the resource name) ๐Ÿ”—.
  2. A Host header field containing the server's authority ๐Ÿ .
  3. An Upgrade header field containing the value "websocket", treated as an ASCII case-insensitive value ๐Ÿฆ‹.
  4. A Connection header field that includes the token "Upgrade", treated as an ASCII case-insensitive value ๐Ÿซถ.
  5. A Sec-WebSocket-Key header field with a base64-encoded value (see Section 4 of [RFC4648]) that, once decoded, is 16 bytes long ๐Ÿ”.
  6. A Sec-WebSocket-Version header field with a value of 13 ๐Ÿ”ข.
  7. Optionally, an Origin header field. Every browser client sends this one โœจ. A connection attempt that doesn't have this header SHOULD NOT be interpreted as coming from a browser client ๐Ÿ‘€.
  8. Optionally, a Sec-WebSocket-Protocol header field with a list of values showing which protocols the client would like to speak, ordered by preference ๐Ÿ’ฌ.
  9. Optionally, a Sec-WebSocket-Extensions header field with a list of values showing which extensions the client would like to speak. How this header gets interpreted is covered in Section 9.1 ๐Ÿงฉ.
  10. Optionally, other header fields, like the ones used to send cookies or request authentication from a server ๐Ÿ“. Unknown header fields are ignored, as per [RFC2616] ๐Ÿ™ˆ.

4.2.2. Sending the Server's Opening Handshake โœจ

Okay bestie, this is the part where the server finally says "yes, I'm in" ๐Ÿ’–. When a client establishes a WebSocket connection to a server, the server MUST complete the following steps to accept the connection and send the server's opening handshake.

  1. If the connection is happening on an HTTPS (HTTP-over-TLS) port, perform a TLS handshake over the connection. If this fails (e.g., the client indicated a host name in the extended client hello "server_name" extension that the server does not host), then close the connection; otherwise, all further communication for the connection (including the server's handshake) MUST run through the encrypted tunnel [RFC5246]. ๐Ÿ”
  2. The server can perform additional client authentication, for example, by returning a 401 status code with the corresponding WWW-Authenticate header field as described in [RFC2616]. ๐Ÿ™ˆ
  3. The server MAY redirect the client using a 3xx status code [RFC2616]. Note that this step can happen together with, before, or after the optional authentication step described above. ๐Ÿฆ‹
  4. Establish the following information: ๐Ÿงš
    • /origin/ The Origin header field in the client's handshake indicates the origin of the script establishing the connection. The origin is serialized to ASCII and converted to lowercase. The server MAY use this information as part of a determination of whether to accept the incoming connection. If the server does not validate the origin, it will accept connections from anywhere. If the server does not wish to accept this connection, it MUST return an appropriate HTTP error code (e.g., 403 Forbidden) and abort the WebSocket handshake described in this section. For more detail, refer to Section 10. ๐Ÿ’…
    • /key/ The Sec-WebSocket-Key header field in the client's handshake includes a base64-encoded value that, if decoded, is 16 bytes in length. This (encoded) value is used in the creation of the server's handshake to indicate an acceptance of the connection. It is not necessary for the server to base64-decode the Sec-WebSocket-Key value. ๐Ÿ”‘
    • /version/ The Sec-WebSocket-Version header field in the client's handshake includes the version of the WebSocket Protocol with which the client is attempting to communicate. If this version does not match a version understood by the server, the server MUST abort the WebSocket handshake described in this section and instead send an appropriate HTTP error code (such as 426 Upgrade Required) and a Sec-WebSocket-Version header field indicating the version(s) the server is capable of understanding. ๐ŸŒˆ
    • /resource name/ An identifier for the service provided by the server. If the server provides multiple services, then the value should be derived from the resource name given in the client's handshake in the "Request-URI" [RFC2616] of the GET method. If the requested service is not available, the server MUST send an appropriate HTTP error code (such as 404 Not Found) and abort the WebSocket handshake. ๐ŸŽ€
    • /subprotocol/ Either a single value representing the subprotocol the server is ready to use or null. The value chosen MUST be derived from the client's handshake, specifically by selecting one of the values from the Sec-WebSocket-Protocol field that the server is willing to use for this connection (if any). If the client's handshake did not contain such a header field or if the server does not agree to any of the client's requested subprotocols, the only acceptable value is null. The absence of such a field is equivalent to the null value (meaning that if the server does not wish to agree to one of the suggested subprotocols, it MUST NOT send back a Sec-WebSocket-Protocol header field in its response). The empty string is not the same as the null value for these purposes and is not a legal value for this field. The ABNF for the value of this header field is (token), where the definitions of constructs and rules are as given in [RFC2616]. ๐Ÿ“
    • /extensions/ A (possibly empty) list representing the protocol-level extensions the server is ready to use. If the server supports multiple extensions, then the value MUST be derived from the client's handshake, specifically by selecting one or more of the values from the Sec-WebSocket-Extensions field. The absence of such a field is equivalent to the null value. The empty string is not the same as the null value for these purposes. Extensions not listed by the client MUST NOT be listed. The method by which these values should be selected and interpreted is discussed in Section 9.1. โœจ
  5. If the server chooses to accept the incoming connection, it MUST reply with a valid HTTP response indicating the following. ๐Ÿ‘‘
    1. A Status-Line with a 101 response code as per RFC 2616 [RFC2616]. Such a response could look like "HTTP/1.1 101 Switching Protocols".
    2. An Upgrade header field with value "websocket" as per RFC 2616 [RFC2616].
    3. A Connection header field with value "Upgrade".
    4. A Sec-WebSocket-Accept header field. The value of this header field is constructed by concatenating /key/, defined above in step 4 in Section 4.2.2, with the string "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", taking the SHA-1 hash of this concatenated value to obtain a 20-byte value and base64-encoding (see Section 4 of [RFC4648]) this 20-byte hash. The ABNF [RFC2616] of this header field is defined as follows:
Sec-WebSocket-Accept     = base64-value-non-empty
base64-value-non-empty = (1*base64-data [ base64-padding ]) |
                         base64-padding
base64-data      = 4base64-character
base64-padding   = (2base64-character "==") |
                   (3base64-character "=")
base64-character = ALPHA | DIGIT | "+" | "/"
  1. Optionally, a Sec-WebSocket-Protocol header field, with a value /subprotocol/ as defined in step 4 in Section 4.2.2.
  2. Optionally, a Sec-WebSocket-Extensions header field, with a value /extensions/ as defined in step 4 in Section 4.2.2. If multiple extensions are to be used, they can all be listed in a single Sec-WebSocket-Extensions header field or split between multiple instances of the Sec-WebSocket-Extensions header field.
NOTE: As an example, if the value of the Sec-WebSocket-Key header field in the client's handshake were "dGhlIHNhbXBsZSBub25jZQ==", the server would append the string "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" to form the string "dGhlIHNhbXBsZSBub25jZQ==258EAFA5-E914-47DA-95CA-C5AB0DC85B11". The server would then take the SHA-1 hash of this string, giving the value 0xb3 0x7a 0x4f 0x2c 0xc0 0x62 0x4f 0x16 0x90 0xf6 0x46 0x06 0xcf 0x38 0x59 0x45 0xb2 0xbe 0xc4 0xea. This value is then base64-encoded, to give the value "s3pPLMBiTxaQ9kYGzzhZRbK+xOo=", which would be returned in the Sec-WebSocket-Accept header field. ๐Ÿง

This completes the server's handshake. If the server finishes these steps without aborting the WebSocket handshake, the server considers the WebSocket connection to be established and that the WebSocket connection is in the OPEN state. At this point, the server may begin sending (and receiving) data. Bestie, the handshake is DONE and the connection is live! ๐ŸŽ‰


4.3. Collected ABNF for New Header Fields Used in Handshake

This section is using ABNF syntax/rules from Section 2.1 of [RFC2616], including the "implied *LWS rule". ๐Ÿ“š

Note that the following ABNF conventions are used in this section. Some names of the rules correspond to names of the corresponding header fields. Such rules express values of the corresponding header fields, for example, the Sec-WebSocket-Key ABNF rule describes syntax of the Sec-WebSocket-Key header field value. ABNF rules with the "-Client" suffix in the name are only used in requests sent by the client to the server; ABNF rules with the "-Server" suffix in the name are only used in responses sent by the server to the client. For example, the ABNF rule Sec-WebSocket-Protocol-Client describes syntax of the Sec-WebSocket-Protocol header field value sent by the client to the server. ๐Ÿง 

The following new header fields can be sent during the handshake from the client to the server:

   Sec-WebSocket-Key = base64-value-non-empty
   Sec-WebSocket-Extensions = extension-list
   Sec-WebSocket-Protocol-Client = 1#token
   Sec-WebSocket-Version-Client = version

   base64-value-non-empty = (1*base64-data [ base64-padding ]) |
                             base64-padding
   base64-data      = 4base64-character
   base64-padding   = (2base64-character "==") |
                      (3base64-character "=")
   base64-character = ALPHA | DIGIT | "+" | "/"
   extension-list = 1#extension
   extension = extension-token *( ";" extension-param )
   extension-token = registered-token
   registered-token = token
   extension-param = token [ "=" (token | quoted-string) ]
        ; When using the quoted-string syntax variant, the value
        ; after quoted-string unescaping MUST conform to the
        ; 'token' ABNF.
   NZDIGIT       =  "1" | "2" | "3" | "4" | "5" | "6" |
                    "7" | "8" | "9"
   version = DIGIT | (NZDIGIT DIGIT) |
             ("1" DIGIT DIGIT) | ("2" DIGIT DIGIT)
             ; Limited to 0-255 range, with no leading zeros

The following new header fields can be sent during the handshake from the server to the client:

   Sec-WebSocket-Extensions = extension-list
   Sec-WebSocket-Accept     = base64-value-non-empty
   Sec-WebSocket-Protocol-Server = token
   Sec-WebSocket-Version-Server = 1#version

4.4. Supporting Multiple Versions of WebSocket Protocol ๐ŸŽ€

okay so this section is basically the guide for how clients and servers can handle more than one version of the WebSocket Protocol, and it's giving very "be flexible, bestie" ๐Ÿ’…

so the version advertisement thing (that's the Sec-WebSocket-Version header field) lets a client ask for whatever version it prefers first ๐Ÿฆ‹ and it doesn't have to be the newest one it knows. if the server supports that version and the handshake is otherwise valid, the server accepts it, easy. but if the server doesn't support the requested version, it MUST respond with a Sec-WebSocket-Version header field (or multiple Sec-WebSocket-Version header fields) listing every version it's willing to use. then if the client supports one of those, it can just redo the handshake with a new version value. iconic negotiation behaviour honestly ๐Ÿ‘‘

here's an example of that negotiation in action:

GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
...
Sec-WebSocket-Version: 25

and the server might reply like this:

HTTP/1.1 400 Bad Request
...
Sec-WebSocket-Version: 13, 8, 7

the last reply could also look like this, which is the same info just split across two header fields ๐ŸŒธ

HTTP/1.1 400 Bad Request
...
Sec-WebSocket-Version: 13
Sec-WebSocket-Version: 8, 7

and then the client repeats the handshake for version 13:

GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
...
Sec-WebSocket-Version: 13

5. Data Framing โœจ

5.1. Overview ๐Ÿ’–

okay bestie, this is where the actual data starts moving ๐Ÿš€ in the WebSocket Protocol, everything gets sent as a sequence of frames. and here's the lowkey important bit: to avoid confusing network intermediaries (like intercepting proxies) and for security reasons that get more detail in Section 10.3, a client MUST mask all frames that it sends to the server (see Section 5.3 for the deets). (fun fact, masking happens whether or not the WebSocket Protocol is running over TLS ๐Ÿ”)

the rules are strict on purpose: a server MUST close the connection if it gets a frame that isn't masked. in that case the server MAY send a Close frame with status code 1002 (protocol error), which is defined in Section 7.4.1. and a server MUST NOT mask any frames it sends to the client. a client MUST close the connection if it detects a masked frame, and in that case it MAY use status code 1002 (protocol error) as defined in Section 7.4.1. (these rules might get relaxed in a future specification, so keep an eye out ๐Ÿ‘€)

the base framing protocol defines a frame type with an opcode, a payload length, and designated spots for "Extension data" and "Application data". together those make up the "Payload data" ๐Ÿงš and some bits and opcodes are reserved for future expansion of the protocol, so they're just chilling for later โœจ

finally, a data frame MAY be sent by either the client or the server at any point after the opening handshake is complete, and before that endpoint has sent a Close frame (Section 5.5.1). periodt ๐Ÿ’…

5.2. Base Framing Protocol ๐ŸŽ€

okay so this section is the wire format for the data transfer part, and it's literally the blueprint for every single frame that goes across a WebSocket ๐Ÿ’– The ABNF [RFC5234] below spells it all out. Heads up: unlike the rest of the doc, this ABNF works on groups of bits, not characters. Each group's length is in a comment, and when it's on the wire the most significant bit is the leftmost one in the ABNF ๐Ÿงš

Here's the big-picture diagram. If the figure and the ABNF ever disagree, the figure wins, so trust the picture first โœจ

      0                   1                   2                   3
      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     +-+-+-+-+-------+-+-------------+-------------------------------+
     |F|R|R|R| opcode|M| Payload len |    Extended payload length    |
     |I|S|S|S|  (4)  |A|     (7)     |             (16/64)           |
     |N|V|V|V|       |S|             |   (if payload len==126/127)   |
     | |1|2|3|       |K|             |                               |
     +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
     |     Extended payload length continued, if payload len == 127  |
     + - - - - - - - - - - - - - - - +-------------------------------+
     |                               |Masking-key, if MASK set to 1  |
     +-------------------------------+-------------------------------+
     | Masking-key (continued)       |          Payload Data         |
     +-------------------------------- - - - - - - - - - - - - - - - +
     :                     Payload Data continued ...                :
     + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
     |                     Payload Data continued ...                |
     +---------------------------------------------------------------+

Now let's go through each field ๐Ÿ’…

FIN: 1 bit

this one tells you if this is the final fragment in a message ๐Ÿฆ‹ The first fragment MAY also be the final fragment, so a message can totally be just one frame, no cap.

RSV1, RSV2, RSV3: 1 bit each

these are reserved bits and they MUST be 0 unless an extension is negotiated that gives non-zero values a meaning ๐Ÿ™ˆ If you get a nonzero value and none of the negotiated extensions explains it, the receiving endpoint MUST Fail the WebSocket Connection. no vibes, just shutting it down ๐Ÿ’€

Opcode: 4 bits

the opcode tells you how to read the "Payload data" ๐ŸŒˆ If you receive an opcode nobody knows, the receiving endpoint MUST Fail the WebSocket Connection. Here's what the values mean:

  • %x0 denotes a continuation frame
  • %x1 denotes a text frame
  • %x2 denotes a binary frame
  • %x3-7 are reserved for further non-control frames
  • %x8 denotes a connection close
  • %x9 denotes a ping
  • %xA denotes a pong
  • %xB-F are reserved for further control frames

Mask: 1 bit

this is the bit that says whether the "Payload data" is masked ๐ŸŽ€ If it's set to 1, there's a masking key sitting in masking-key, and you use it to unmask the "Payload data" as per Section 5.3. Every frame going from client to server has this bit set to 1, so that part's basically iconic and consistent ๐Ÿ‘‘

Payload length: 7 bits, 7+16 bits, or 7+64 bits

this is the length of the "Payload data" in bytes, and it's a little choose-your-own-adventure ๐Ÿงš If it's 0-125, that number is the payload length. If it's 126, the next 2 bytes, read as a 16-bit unsigned integer, are the length. If it's 127, the next 8 bytes, read as a 64-bit unsigned integer, are the length (and the most significant bit MUST be 0). Multibyte lengths go in network byte order ๐ŸŒธ Also, in every case you MUST use the minimal number of bytes to encode the length. So a 124-byte string can't be sent as 126, 0, 124, because that's just extra and not it ๐Ÿ™…โ€โ™€๏ธ The payload length is the length of the "Extension data" plus the length of the "Application data". The "Extension data" can be zero length, and then the payload length is just the "Application data" length ๐Ÿ“

Masking-key: 0 or 4 bytes

every frame the client sends to the server gets masked with a 32-bit value sitting right inside the frame โœจ This field is there if the mask bit is 1 and gone if the mask bit is 0. Check out Section 5.3 for the deets on client-to-server masking ๐Ÿซถ

Payload data: (x+y) bytes

the "Payload data" is just "Extension data" glued together with "Application data" ๐Ÿง

Extension data: x bytes

this is 0 bytes unless an extension was negotiated. Any extension MUST specify the length of the "Extension data", or how that length gets calculated, and how the extension use MUST be negotiated during the opening handshake ๐Ÿ”ฅ When it's there, the "Extension data" counts toward the total payload length ๐Ÿ’œ

Application data: y bytes

this is the arbitrary stuff you actually care about, and it takes up whatever's left of the frame after the "Extension data". Its length is the payload length minus the length of the "Extension data" ๐ŸŒˆ

okay now the formal part ๐Ÿค“ The base framing protocol is defined by the ABNF [RFC5234] below. It's super important to remember this data is binary, NOT ASCII text. So a 1-bit field with values %x0 / %x1 is one single bit that's 0 or 1, not a whole byte standing in for the characters "0" or "1". Same deal for the 4-bit fields: they're 4 bits, not an ASCII character or a full byte ๐Ÿ’– [RFC5234] doesn't pick a character encoding, and it says: "Rules resolve into a string of terminal values, sometimes called characters. In ABNF, a character is merely a non-negative integer. In certain contexts, a specific mapping (encoding) of values into a character set (such as ASCII) will be specified." So here, the encoding is binary, where each terminal value gets encoded in however many bits its field needs, which changes from field to field ๐Ÿฆ‹

    ws-frame                = frame-fin           ; 1 bit in length
                              frame-rsv1          ; 1 bit in length
                              frame-rsv2          ; 1 bit in length
                              frame-rsv3          ; 1 bit in length
                              frame-opcode        ; 4 bits in length
                              frame-masked        ; 1 bit in length
                              frame-payload-length   ; either 7, 7+16,
                                                     ; or 7+64 bits in
                                                     ; length
                              [ frame-masking-key ]  ; 32 bits in length
                              frame-payload-data     ; n*8 bits in
                                                     ; length, where
                                                     ; n >= 0

    frame-fin               = %x0 ; more frames of this message follow
                            / %x1 ; final frame of this message
                                  ; 1 bit in length

    frame-rsv1              = %x0 / %x1
                              ; 1 bit in length, MUST be 0 unless
                              ; negotiated otherwise

    frame-rsv2              = %x0 / %x1
                              ; 1 bit in length, MUST be 0 unless
                              ; negotiated otherwise

    frame-rsv3              = %x0 / %x1
                              ; 1 bit in length, MUST be 0 unless
                              ; negotiated otherwise

    frame-opcode            = frame-opcode-non-control /
                              frame-opcode-control /
                              frame-opcode-cont

    frame-opcode-cont       = %x0 ; frame continuation

    frame-opcode-non-control= %x1 ; text frame
                            / %x2 ; binary frame
                            / %x3-7
                            ; 4 bits in length,
                            ; reserved for further non-control frames

    frame-opcode-control    = %x8 ; connection close
                            / %x9 ; ping
                            / %xA ; pong
                            / %xB-F ; reserved for further control
                                    ; frames
                                    ; 4 bits in length

    frame-masked            = %x0
                            ; frame is not masked, no frame-masking-key
                            / %x1
                            ; frame is masked, frame-masking-key present
                            ; 1 bit in length

    frame-payload-length    = ( %x00-7D )
                            / ( %x7E frame-payload-length-16 )
                            / ( %x7F frame-payload-length-63 )
                            ; 7, 7+16, or 7+64 bits in length,
                            ; respectively

    frame-payload-length-16 = %x0000-FFFF ; 16 bits in length

    frame-payload-length-63 = %x0000000000000000-7FFFFFFFFFFFFFFF
                            ; 64 bits in length

    frame-masking-key       = 4( %x00-FF )
                              ; present only if frame-masked is 1
                              ; 32 bits in length

    frame-payload-data      = (frame-masked-extension-data
                               frame-masked-application-data)
                            ; when frame-masked is 1
                              / (frame-unmasked-extension-data
                                frame-unmasked-application-data)
                            ; when frame-masked is 0

    frame-masked-extension-data     = *( %x00-FF )
                            ; reserved for future extensibility
                            ; n*8 bits in length, where n >= 0

    frame-masked-application-data   = *( %x00-FF )
                            ; n*8 bits in length, where n >= 0

    frame-unmasked-extension-data   = *( %x00-FF )
                            ; reserved for future extensibility
                            ; n*8 bits in length, where n >= 0

    frame-unmasked-application-data = *( %x00-FF )
                            ; n*8 bits in length, where n >= 0

5.3. Client-to-Server Masking ๐ŸŽ€

okay so a masked frame MUST have frame-masked set to 1 ๐Ÿ”’, as defined in Section 5.2. bestie, that bit is the whole "yes this frame is masked" flag. ๐Ÿ’œ

the masking key lives entirely inside the frame (it's frame-masking-key from Section 5.2) and it's used to mask the "Payload data" from that same section, which covers both "Extension data" and "Application data" ๐Ÿซถ

the client picks the masking key at random, a 32-bit value. when it prepares a masked frame it MUST pick a fresh masking key from the set of allowed 32-bit values ๐ŸŽฒ. and the key has to be unpredictable, so it MUST be derived from a strong source of entropy, and the key for a given frame MUST NOT make it simple for a server/proxy to predict the key for the next frame ๐Ÿ”ฎ. this matters SO much because if attackers could predict the bytes that show up on the wire, they could pick the exact bytes they want to appear ๐Ÿ˜ญ that's the whole reason. [RFC4086] is the place to read about what counts as a suitable entropy source for security-sensitive stuff ๐Ÿ“š

masking doesn't change the length of the "Payload data" at all ๐Ÿ“. to turn masked data into unmasked data (or the other way around) you run this algorithm, and it's the same no matter which direction you're going. like, the exact same steps mask it AND unmask it โœจ

each octet i of the transformed data (transformed-octet-i) is the XOR of octet i of the original data (original-octet-i) with the masking key octet at index i modulo 4 (masking-key-octet-j) ๐Ÿงฎ

  j                   = i MOD 4
  transformed-octet-i = original-octet-i XOR masking-key-octet-j

and the payload length in the framing (frame-payload-length) does not include the length of the masking key. it's just the length of the "Payload data", so the number of bytes that come after the masking key ๐ŸŒธ

5.4. Fragmentation ๐Ÿงฉ

okay the main reason fragmentation exists is so you can start sending a message when you don't know how big it's gonna be, without having to buffer the whole thing first ๐Ÿ“ฆ. if messages couldn't be fragmented, an endpoint would have to hold the entire message and count its length before sending the very first byte, which is so inconvenient ๐Ÿ˜ฉ with fragmentation, a server or intermediary can pick a reasonable buffer size and write out a fragment to the network whenever that buffer fills up ๐ŸŒŠ

there's a second use-case too, which is multiplexing ๐Ÿฆ‹. you don't want one big message on one logical channel hogging the whole output channel, so the multiplexing needs to be free to chop the message into smaller fragments and share the output nicely. (fyi the multiplexing extension isn't described in this document, so don't go looking for it here ๐Ÿ™ˆ)

unless an extension says otherwise, frames have no semantic meaning โœจ. an intermediary might coalesce and/or split frames if no extensions were negotiated by the client and the server. or if some were negotiated, but the intermediary understood all of them and knows how to coalesce and/or split frames with those extensions around ๐Ÿง . the big takeaway: without extensions, senders and receivers must not depend on the presence of specific frame boundaries ๐Ÿšซ

here are the fragmentation rules, bestie ๐Ÿ‘‘

  • an unfragmented message is a single frame with the FIN bit set (Section 5.2) and an opcode other than 0.
  • a fragmented message is a single frame with the FIN bit clear and an opcode other than 0, followed by zero or more frames with the FIN bit clear and the opcode set to 0, and then ended by a single frame with the FIN bit set and an opcode of 0. conceptually, a fragmented message is the same as one bigger message whose payload is the fragments' payloads glued together in order ๐Ÿงต. however, with extensions this might not hold, because the extension decides how the "Extension data" should be read. like, "Extension data" might only show up at the start of the first fragment and apply to all the rest, or each fragment might carry its own "Extension data" that only applies to that one fragment ๐Ÿ’…. without any "Extension data", here's how it works:

EXAMPLE: For a text message sent as three fragments, the first fragment would have an opcode of 0x1 and a FIN bit clear, the second fragment would have an opcode of 0x0 and a FIN bit clear, and the third fragment would have an opcode of 0x0 and a FIN bit that is set. ๐ŸŽ€

  • control frames (see Section 5.5) MAY be injected in the middle of a fragmented message ๐Ÿ’ซ. but control frames themselves MUST NOT be fragmented ๐Ÿšซ.
  • message fragments MUST be delivered to the recipient in the order the sender sent them ๐Ÿ“ฌ.
  • the fragments of one message MUST NOT be interleaved with the fragments of another message, unless an extension has been negotiated that can make sense of that interleaving ๐Ÿ™…โ€โ™€๏ธ.
  • an endpoint MUST be capable of handling control frames in the middle of a fragmented message ๐Ÿซถ.
  • a sender MAY create fragments of any size for non-control messages ๐Ÿ“.
  • clients and servers MUST support receiving both fragmented and unfragmented messages ๐Ÿ’–.
  • control frames can't be fragmented, so an intermediary MUST NOT attempt to change the fragmentation of a control frame ๐Ÿ™Œ.
  • an intermediary MUST NOT change the fragmentation of a message if any reserved bit values are used and the intermediary doesn't know what those values mean ๐Ÿ”.
  • an intermediary MUST NOT change the fragmentation of any message on a connection where extensions have been negotiated, if the intermediary doesn't understand those extensions' semantics. likewise, an intermediary that didn't see the WebSocket handshake (and wasn't told what was in it) that set up the WebSocket connection MUST NOT change the fragmentation of any message on that connection ๐Ÿ›‘.
  • because of all these rules, every fragment of a message is the same type, as set by the first fragment's opcode ๐Ÿ“. since control frames can't be fragmented, the type for all fragments in a message MUST be either text, binary, or one of the reserved opcodes โœจ.
NOTE: if control frames couldn't be interjected, the latency of a ping would be really long if it got stuck behind a large message ๐Ÿ˜ญ. that's why there's a requirement to handle control frames in the middle of a fragmented message ๐Ÿƒโ€โ™€๏ธ.
IMPLEMENTATION NOTE: without any extension, a receiver doesn't have to buffer the whole frame before processing it ๐ŸŒˆ. for example, if a streaming API is used, part of a frame can be handed to the application right away. BUT, heads up, this assumption might not hold for every future WebSocket extension ๐Ÿ‘€.

5.5. Control Frames ๐Ÿ’œ

control frames are identified by opcodes where the most significant bit of the opcode is 1 ๐Ÿ”‘. the control opcodes defined right now are 0x8 (Close), 0x9 (Ping), and 0xA (Pong) ๐Ÿ’…. opcodes 0xB-0xF are reserved for control frames that haven't been defined yet ๐ŸŒธ.

control frames are how the endpoints communicate state about the WebSocket ๐Ÿ“ก. and yes, they can be interjected in the middle of a fragmented message โญ.

all control frames MUST have a payload length of 125 bytes or less, and they MUST NOT be fragmented ๐Ÿ™…โ€โ™€๏ธ.

5.5.1. Close ๐Ÿšช

the Close frame has an opcode of 0x8 ๐Ÿ–ค.

the Close frame MAY contain a body (the "Application data" portion of the frame) that gives a reason for closing ๐Ÿ’Œ. examples are an endpoint shutting down, an endpoint receiving a frame that's too large, or an endpoint receiving a frame that doesn't match the format it expects ๐Ÿ˜ต. if there is a body, the first two bytes of the body MUST be a 2-byte unsigned integer (in network byte order) representing a status code with value /code/ defined in Section 7.4 ๐Ÿ”ข. after that 2-byte integer, the body MAY contain UTF-8-encoded data with value /reason/. the spec doesn't define how to interpret that part ๐Ÿคทโ€โ™€๏ธ. it's not necessarily human readable, but it can be handy for debugging or for passing info to the script that opened the connection ๐Ÿง‘โ€๐Ÿ’ป. since it's not guaranteed to be human readable, clients MUST NOT show it to end users ๐Ÿ™ˆ.

Close frames sent from client to server must be masked as per Section 5.3 ๐Ÿ”’.

the application MUST NOT send any more data frames after it sends a Close frame ๐Ÿ›‘.

if an endpoint receives a Close frame and didn't send one before, the endpoint MUST send a Close frame in response ๐Ÿ’ซ. (when it's responding, the endpoint typically echoes back the status code it got ๐Ÿชž.) it SHOULD do this as soon as practical โฐ. an endpoint MAY hold off sending its Close frame until its current message is finished sending. for example, if most of a fragmented message is already out, the endpoint MAY send the remaining fragments before the Close frame ๐Ÿงฉ. HOWEVER, there's no guarantee that an endpoint that already sent a Close frame will keep processing data ๐Ÿ˜ฌ.

after both sending and receiving a Close message, an endpoint considers the WebSocket connection closed and MUST close the underlying TCP connection ๐Ÿ”š. the server MUST close the underlying TCP connection immediately. the client SHOULD wait for the server to close the connection, but it MAY close the connection at any time after it has sent and received a Close message, for example if it hasn't gotten a TCP Close from the server within a reasonable amount of time โณ.

if a client and server both send a Close message at the same time, both endpoints will have sent and received one. they should consider the WebSocket connection closed and close the underlying TCP connection ๐Ÿค.

5.5.2. Ping ๐Ÿ“

the Ping frame has an opcode of 0x9 ๐ŸŒŸ.

a Ping frame MAY include "Application data" ๐Ÿ’ฌ.

when an endpoint receives a Ping frame, it MUST send a Pong frame in response, unless it already received a Close frame ๐Ÿ“. it SHOULD respond with a Pong frame as soon as is practical ๐Ÿƒโ€โ™€๏ธ. Pong frames are discussed in Section 5.5.3 ๐Ÿฆ‹.

an endpoint MAY send a Ping frame any time after the connection is established and before the connection is closed ๐Ÿ•ฐ๏ธ.

NOTE: a Ping frame can serve either as a keepalive or as a way to check that the remote endpoint is still responsive ๐Ÿ’“.

5.5.3. Pong ๐Ÿ’–

the Pong frame has an opcode of 0xA โœจ.

Section 5.5.2 details requirements that apply to both Ping and Pong frames ๐Ÿ“‹.

a Pong frame sent in response to a Ping frame MUST have identical "Application data" to what was in the message body of the Ping frame it's replying to ๐Ÿชž.

if an endpoint receives a Ping frame and has not yet sent Pong frame(s) in response to previous Ping frame(s), the endpoint MAY choose to send a Pong frame only for the most recently processed Ping frame ๐ŸŽฏ.

a Pong frame MAY be sent unsolicited ๐Ÿ“ฃ. this works as a one-way heartbeat ๐Ÿ’—. a response to an unsolicited Pong frame is not expected ๐Ÿ™.

5.6. Data Frames ๐ŸŽ€

okay so data frames are the non-control ones, and you can spot them because the most significant bit of their opcode is 0 ๐Ÿ’… Right now the defined ones are 0x1 (Text) and 0x2 (Binary). Opcodes 0x3-0x7 are saved for future non-control frames that haven't been defined yet ๐Ÿ”ฎ

Data frames carry application-layer and/or extension-layer data, and the opcode decides how that data should be read:

  • Text: the "Payload data" is text encoded as UTF-8. Heads up, one text frame might only hold part of a UTF-8 sequence, but the whole message MUST contain valid UTF-8 ๐Ÿ’– Invalid UTF-8 in reassembled messages gets handled the way Section 8.1 explains.
  • Binary: the "Payload data" is arbitrary binary data, and what it means is totally up to the application layer ๐Ÿคทโ€โ™€๏ธ

5.7. Examples โœจ

Here are some examples, because seeing the bytes is so much easier ๐Ÿฅน

A single-frame unmasked text message

0x81 0x05 0x48 0x65 0x6c 0x6c 0x6f (contains "Hello")

A single-frame masked text message

0x81 0x85 0x37 0xfa 0x21 0x3d 0x7f 0x9f 0x4d 0x51 0x58 (contains "Hello")

A fragmented unmasked text message

0x01 0x03 0x48 0x65 0x6c (contains "Hel")
0x80 0x02 0x6c 0x6f (contains "lo")

Unmasked Ping request and masked Ping response

0x89 0x05 0x48 0x65 0x6c 0x6c 0x6f (contains a body of "Hello",
but the contents of the body are arbitrary)
0x8a 0x85 0x37 0xfa 0x21 0x3d 0x7f 0x9f 0x4d 0x51 0x58
(contains a body of "Hello", matching the body of the ping)

256 bytes binary message in a single unmasked frame

0x82 0x7E 0x0100 [256 bytes of binary data]

64KiB binary message in a single unmasked frame

0x82 0x7F 0x0000000000010000 [65536 bytes of binary data]

5.8. Extensibility ๐Ÿงš

The protocol is built so extensions can bolt on new capabilities to the base protocol ๐ŸŒˆ The endpoints of a connection MUST negotiate the use of any extensions during the opening handshake. This spec also hands extensions a bunch of stuff to play with: opcodes 0x3 through 0x7 and 0xB through 0xF, the "Extension data" field, and the frame-rsv1, frame-rsv2, and frame-rsv3 bits of the frame header. Negotiation gets its own deep dive in Section 9.1. Here are some anticipated uses, and yes, this list is neither complete nor prescriptive ๐Ÿซถ

  • "Extension data" may be placed in the "Payload data" before the "Application data".
  • Reserved bits can be allocated for per-frame needs.
  • Reserved opcode values can be defined.
  • Reserved bits can be allocated to the opcode field if more opcode values are needed.
  • A reserved bit or an "extension" opcode can be defined that allocates additional bits out of the "Payload data" to define larger opcodes or more per-frame bits.

6. Sending and Receiving Data ๐Ÿฆ‹

6.1. Sending Data

To Send a WebSocket Message comprising of data over a WebSocket connection, an endpoint MUST go through the following steps ๐Ÿ“ฌ

  1. The endpoint MUST ensure the WebSocket connection is in the OPEN state (cf. Sections 4.1 and 4.2.2.) If at any point the state of the WebSocket connection changes, the endpoint MUST abort the following steps.
  2. An endpoint MUST encapsulate the data in a WebSocket frame as defined in Section 5.2. If the data to be sent is large, or if the data is not available in its entirety at the point the endpoint wants to start sending it, the endpoint MAY instead encapsulate the data in a series of frames as defined in Section 5.4.
  3. The opcode (frame-opcode) of the first frame containing the data MUST be set to the appropriate value from Section 5.2 for data that the recipient will interpret as text or binary data.
  4. The FIN bit (frame-fin) of the last frame containing the data MUST be set to 1 as defined in Section 5.2.
  5. If the data is being sent by the client, the frame(s) MUST be masked as defined in Section 5.3.
  6. If any extensions (Section 9) have been negotiated for the WebSocket connection, extra considerations may apply, based on how those extensions are defined.
  7. The frame(s) that have been formed MUST be transmitted over the underlying network connection.

6.2. Receiving Data

To receive WebSocket data, an endpoint listens on the underlying network connection. Incoming data MUST be parsed as WebSocket frames as defined in Section 5.2. If a control frame (Section 5.5) comes in, the frame MUST be handled as Section 5.5 defines. When a data frame (Section 5.6) arrives, the endpoint MUST note the type of the data, based on the opcode (frame-opcode) from Section 5.2. The "Application data" from that frame is the data of the message. If the frame is a complete, unfragmented message (Section 5.4), A WebSocket Message Has Been Received with type type and data data. If the frame is part of a fragmented message, the "Application data" from the later data frames gets concatenated to build the data. Once the last fragment arrives, flagged by the FIN bit (frame-fin), A WebSocket Message Has Been Received with data data (the concatenated "Application data" of the fragments) and type type (taken from the first frame of the fragmented message). Subsequent data frames MUST be interpreted as belonging to a new WebSocket message ๐ŸŽ‰

Extensions (Section 9) MAY change how data gets read, and that includes what counts as a message boundary ๐Ÿ‘€ On top of adding "Extension data" before the "Application data" in a payload, extensions MAY also modify the "Application data" (for example, by compressing it).

A server MUST remove masking for data frames received from a client, as described in Section 5.3 ๐Ÿ”“

7. Closing the Connection ๐Ÿ”’

7.1. Definitions

7.1.1. Close the WebSocket Connection

To Close the WebSocket Connection, an endpoint closes the underlying TCP connection. An endpoint SHOULD use a method that cleanly closes the TCP connection, plus the TLS session if there is one, and throws away any trailing bytes it might have received. An endpoint MAY close the connection by any means available when it's necessary, such as when it's under attack ๐Ÿšจ

Here's the lowkey important bit about who closes first ๐Ÿง In most normal cases, the server SHOULD be the one to close the underlying TCP connection first, so that the server ends up holding the TIME_WAIT state instead of the client. That matters because a client stuck in TIME_WAIT can't re-open the connection for 2 maximum segment lifetimes (2MSL). A server in TIME_WAIT doesn't get the same hit, since a TIME_WAIT connection gets reopened right away when a new SYN with a higher seq number shows up. In abnormal cases, like when the client hasn't received a TCP Close from the server after a reasonable amount of time, a client MAY initiate the TCP Close. So, when a server is told to Close the WebSocket Connection, it SHOULD start a TCP Close immediately, and when a client is told to do the same, it SHOULD wait for a TCP Close from the server โณ

For a clean closure in C with Berkeley sockets, the move is: call shutdown() with SHUT_WR on the socket, keep calling recv() until it returns 0 (which tells you the peer has also done an orderly shutdown), and then call close() on the socket ๐Ÿงผ

7.1.2. Start the WebSocket Closing Handshake

To Start the WebSocket Closing Handshake with a status code (Section 7.4) /code/ and an optional close reason (Section 7.1.6) /reason/, an endpoint MUST send a Close control frame, as described in Section 5.5.1, with its status code set to /code/ and its close reason set to /reason/. Once an endpoint has both sent and received a Close control frame, that endpoint SHOULD Close the WebSocket Connection as defined in Section 7.1.1 ๐Ÿ’Œ

7.1.3. The WebSocket Closing Handshake is Started

Once an endpoint either sends or receives a Close control frame, The WebSocket Closing Handshake is Started, and the WebSocket connection is in the CLOSING state ๐Ÿšฆ

7.1.4. The WebSocket Connection is Closed

When the underlying TCP connection is closed, The WebSocket Connection is Closed, and the WebSocket connection is in the CLOSED state ๐Ÿ If the TCP connection got closed after the WebSocket closing handshake was completed, the WebSocket connection is said to have been closed cleanly โœจ

If the WebSocket connection could never be established, The WebSocket Connection is Closed still applies, but it's not cleanly ๐Ÿ™ˆ

7.1.5. The WebSocket Connection Close Code

As defined in Sections 5.5.1 and 7.4, a Close control frame can carry a status code that gives a reason for the closure. Either endpoint can start closing the WebSocket connection, and they might do it at the same time ๐Ÿ‘ฏ The WebSocket Connection Close Code is the status code (Section 7.4) in the first Close control frame that the application implementing this protocol receives. If that Close control frame has no status code, The WebSocket Connection Close Code is considered to be 1005. If The WebSocket Connection is Closed and the endpoint never received a Close control frame (which could happen if the underlying transport connection drops), The WebSocket Connection Close Code is considered to be 1006 ๐Ÿ’€

NOTE: Two endpoints may not agree on the value of The WebSocket Connection Close Code. For example, say the remote endpoint sent a Close frame, but the local application hasn't read the data holding that Close frame out of its socket's receive buffer yet. If the local application then decides on its own to close the connection and sends a Close frame, both endpoints will have sent and received a Close frame, and neither will send another one. Each endpoint will see the status code the other one sent as The WebSocket Connection Close Code. So the two endpoints might end up disagreeing on it, if both Start the WebSocket Closing Handshake on their own at roughly the same time ๐Ÿซฃ

7.1.6. The WebSocket Connection Close Reason

As defined in Sections 5.5.1 and 7.4, a Close control frame can carry a status code that gives a reason for the closure, followed by UTF-8-encoded data. What that data means is left up to the endpoints, and this protocol doesn't define it ๐Ÿ“ Either endpoint can start closing, and that can happen at the same time too. The WebSocket Connection Close Reason is the UTF-8-encoded data after the status code (Section 7.4) in the first Close control frame the application implementing this protocol receives. If that Close control frame has no such data, The WebSocket Connection Close Reason is the empty string ๐ŸŒธ

NOTE: Same logic as Section 7.1.5 applies here, so two endpoints may not agree on The WebSocket Connection Close Reason either ๐Ÿง 

7.1.7. Fail the WebSocket Connection

Sometimes an algorithm or spec is like "nope, we're done here" and tells an endpoint to Fail the WebSocket Connection ๐Ÿ’€. To do that, the client MUST Close the WebSocket Connection, and it MAY tell the user about the problem in an appropriate way (which is especially helpful for developers ๐Ÿง‘โ€๐Ÿ’ปโœจ). The server does the same thing: it MUST Close the WebSocket Connection too, and it SHOULD log the problem ๐Ÿ“.

If The WebSocket Connection is Established before the endpoint hits the point where it has to Fail the WebSocket Connection, the endpoint SHOULD send a Close frame with an appropriate status code (Section 7.4) first, and only then Close the WebSocket Connection ๐ŸŽ€. An endpoint MAY skip the Close frame if it thinks the other side probably can't receive and process it, because of whatever error made the connection fail in the first place ๐Ÿ™ˆ. An endpoint MUST NOT keep trying to process data from the remote endpoint after it's been told to Fail the WebSocket Connection, and that includes a Close frame sent back in response ๐Ÿšซ.

Unless the stuff above says otherwise, or the application layer specifies it (like a script using the WebSocket API), clients SHOULD NOT close the connection ๐Ÿ™…โ€โ™€๏ธ.


7.2. Abnormal Closures

7.2.1. Client-Initiated Closure

Certain algorithms, especially during the opening handshake, require the client to Fail the WebSocket Connection ๐Ÿ˜ค. To do so, the client MUST Fail the WebSocket Connection as defined in Section 7.1.7.

If the underlying transport layer connection is unexpectedly lost at any point, the client MUST Fail the WebSocket Connection ๐Ÿ’”.

Unless the stuff above says otherwise, or the application layer specifies it (like a script using the WebSocket API), clients SHOULD NOT close the connection ๐Ÿ™…โ€โ™€๏ธ.

7.2.2. Server-Initiated Closure

Certain algorithms require or recommend that the server Abort the WebSocket Connection during the opening handshake ๐Ÿšช. To do so, the server MUST simply Close the WebSocket Connection (Section 7.1.1).

7.2.3. Recovering from Abnormal Closure

Abnormal closures can happen for lots of reasons ๐Ÿคทโ€โ™€๏ธ. Sometimes it's just a transient error, so reconnecting might give you a good connection and everything goes back to normal โœจ. But sometimes it's a nontransient problem. If every deployed client has an abnormal closure and immediately, nonstop tries to reconnect, the server can end up dealing with what's basically a denial-of-service attack from a huge crowd of clients all piling on ๐Ÿ˜ฑ. The end result could be that the service can't recover in a timely way, or that recovery gets way harder.

To prevent this, clients SHOULD use some form of backoff when trying to reconnect after abnormal closures, as described in this section ๐Ÿ›‘.

The first reconnect attempt SHOULD be delayed by a random amount of time โณ. The client gets to decide how that random delay is picked. A value chosen randomly between 0 and 5 seconds is a reasonable starting delay, though clients MAY choose a different interval to pick a delay length from, based on implementation experience and the particular application ๐Ÿง .

If the first reconnect attempt fails, the subsequent attempts SHOULD be delayed by increasingly longer amounts of time, using a method such as truncated binary exponential backoff ๐Ÿ“ˆ.


7.3. Normal Closure of Connections

Servers MAY close the WebSocket connection whenever they want ๐ŸŒค๏ธ. Clients SHOULD NOT close the WebSocket connection arbitrarily ๐Ÿ™…. Either way, an endpoint starts a closure by following the procedures to Start the WebSocket Closing Handshake (Section 7.1.2).

7.4. Status Codes

When closing an established connection (like when sending a Close frame after the opening handshake has completed), an endpoint MAY indicate a reason for the closure ๐Ÿ’Œ. What an endpoint makes of that reason, and what action it should take because of it, is left undefined by this spec ๐Ÿคทโ€โ™€๏ธ. This spec defines a set of predefined status codes and says which ranges extensions, frameworks, and end applications may use. The status code and any textual message are both optional parts of a Close frame ๐ŸŽ€.

7.4.1. Defined Status Codes

Endpoints MAY use the following predefined status codes when sending a Close frame ๐Ÿ’….

  • 1000: 1000 indicates a normal closure, meaning the purpose the connection was established for has been fulfilled ๐ŸŽ‰.
  • 1001: 1001 indicates that an endpoint is "going away", like a server going down or a browser navigating away from a page ๐Ÿ‘‹.
  • 1002: 1002 indicates that an endpoint is terminating the connection due to a protocol error ๐Ÿ’ฅ.
  • 1003: 1003 indicates that an endpoint is terminating the connection because it has received a type of data it cannot accept (e.g., an endpoint that understands only text data MAY send this if it receives a binary message) ๐Ÿ™…โ€โ™€๏ธ.
  • 1004: Reserved. The specific meaning might be defined in the future ๐Ÿ”ฎ.
  • 1005: 1005 is a reserved value and MUST NOT be set as a status code in a Close control frame by an endpoint. It is designated for use in applications expecting a status code to indicate that no status code was actually present ๐Ÿšซ.
  • 1006: 1006 is a reserved value and MUST NOT be set as a status code in a Close control frame by an endpoint. It is designated for use in applications expecting a status code to indicate that the connection was closed abnormally, e.g., without sending or receiving a Close control frame ๐Ÿ’€.
  • 1007: 1007 indicates that an endpoint is terminating the connection because it has received data within a message that was not consistent with the type of the message (e.g., non-UTF-8 [RFC3629] data within a text message) ๐Ÿ”ค.
  • 1008: 1008 indicates that an endpoint is terminating the connection because it has received a message that violates its policy. This is a generic status code that can be returned when there is no other more suitable status code (e.g., 1003 or 1009) or if there is a need to hide specific details about the policy ๐Ÿ“œ.
  • 1009: 1009 indicates that an endpoint is terminating the connection because it has received a message that is too big for it to process ๐Ÿ“ฆ.
  • 1010: 1010 indicates that an endpoint (client) is terminating the connection because it expected the server to negotiate one or more extensions, but the server didn't return them in the response message of the WebSocket handshake. The list of extensions that are needed SHOULD appear in the reason part of the Close frame. Note that this status code is not used by the server, because it can fail the WebSocket handshake instead ๐Ÿงฉ.
  • 1011: 1011 indicates that a server is terminating the connection because it encountered an unexpected condition that prevented it from fulfilling the request ๐Ÿซ .
  • 1015: 1015 is a reserved value and MUST NOT be set as a status code in a Close control frame by an endpoint. It is designated for use in applications expecting a status code to indicate that the connection was closed due to a failure to perform a TLS handshake (e.g., the server certificate can't be verified) ๐Ÿ”.

7.4.2. Reserved Status Code Ranges

  • 0-999: Status codes in the range 0-999 are not used. ๐Ÿซฅ
  • 1000-2999: Status codes in this range are reserved for definition by this protocol, its future revisions, and extensions specified in a permanent and readily available public specification ๐Ÿ“š.
  • 3000-3999: Status codes in this range are reserved for use by libraries, frameworks, and applications. These status codes are registered directly with IANA. The interpretation of these codes is undefined by this protocol ๐Ÿ—‚๏ธ.
  • 4000-4999: Status codes in this range are reserved for private use and thus can't be registered. Such codes can be used by prior agreements between WebSocket applications. The interpretation of these codes is undefined by this protocol ๐Ÿคซ.

8. Error Handling ๐Ÿšจ

8.1. Handling Errors in UTF-8-Encoded Data

When an endpoint is supposed to interpret a byte stream as UTF-8 but finds that the byte stream is not actually a valid UTF-8 stream, that endpoint MUST Fail the WebSocket Connection ๐Ÿ”ค. This rule applies both during the opening handshake and during subsequent data exchange ๐Ÿค.

9. Extensions โœจ

WebSocket clients MAY request extensions to this specification, and WebSocket servers MAY accept some or all of the extensions the client requested ๐ŸŒˆ. A server MUST NOT respond with any extension that the client did not request ๐Ÿ™…. If extension parameters are included in negotiations between the client and the server, those parameters MUST be chosen in accordance with the specification of the extension they apply to ๐Ÿ“‹.

9.1. Negotiating Extensions โœจ

okay bestie, so when a client wants extensions it sends a Sec-WebSocket-Extensions header field ๐Ÿ’…. It follows the normal HTTP header field rules (see [RFC2616], Section 4.2), and its value is spelled out in the ABNF below, which uses [RFC2616] ABNF, including the "implied *LWS rule". If either side gets a value during negotiation that doesn't match this ABNF, the recipient of that malformed data MUST immediately Fail the WebSocket Connection ๐Ÿ’€

      Sec-WebSocket-Extensions = extension-list
      extension-list = 1#extension
      extension = extension-token *( ";" extension-param )
      extension-token = registered-token
      registered-token = token
      extension-param = token [ "=" (token | quoted-string) ]
          ;When using the quoted-string syntax variant, the value
          ;after quoted-string unescaping MUST conform to the
          ;'token' ABNF.

Note that, like other HTTP header fields, this header field MAY be split or combined across multiple lines. Ergo, these two are equivalent ๐Ÿงš

      Sec-WebSocket-Extensions: foo
      Sec-WebSocket-Extensions: bar; baz=2

which is exactly the same as

      Sec-WebSocket-Extensions: foo, bar; baz=2

Any extension-token you use MUST be a registered token (see Section 11.4) ๐Ÿ”– The parameters for any given extension MUST be defined for that extension. Also, the client is only offering to use the advertised extensions, so it MUST NOT use them unless the server says it wants to use the extension. Not me waiting for a yes before I start ๐Ÿ˜ญ

Order matters here ๐ŸŒธ Any interactions between multiple extensions MAY be defined in the documents that define the extensions. If nobody defines that, the client's list counts as a preference order, with the first options being most preferable. The extensions the server lists in its response are the ones actually in use for the connection. If the extensions modify the data and/or framing, the order of operations should be assumed to be the same as the order the extensions are listed in the server's response in the opening handshake.

For example, say there are two extensions, "foo" and "bar", and the server sends Sec-WebSocket-Extensions with the value "foo, bar". Then the operations on the data happen as bar(foo(data)), whether those changes are to the data itself (like compression) or to the framing that may "stack" ๐Ÿฅž

Non-normative examples of acceptable extension header fields (long lines are folded so they're easier to read) ๐ŸŽ€

      Sec-WebSocket-Extensions: deflate-stream
      Sec-WebSocket-Extensions: mux; max-channels=4; flow-control,
       deflate-stream
      Sec-WebSocket-Extensions: private-extension

A server accepts one or more extensions by including a Sec-WebSocket-Extensions header field containing one or more of the extensions the client requested. What any extension parameter means, and what counts as a valid server response to a client's requested set of parameters, will be defined by each extension itself ๐Ÿฆ‹


9.2. Known Extensions ๐ŸŒˆ

Extensions are how implementations opt in to extra protocol features ๐Ÿ“ This document doesn't define any extension, but implementations MAY use extensions that are defined separately โœจ

10. Security Considerations ๐Ÿ›ก๏ธ

This section covers some security considerations for the WebSocket Protocol ๐Ÿ” The specific ones live in the subsections of this section, so let's get into it bestie ๐Ÿ’œ

10.1. Non-Browser Clients ๐Ÿค–

The WebSocket Protocol protects against malicious JavaScript running inside a trusted app like a web browser, for example by checking the Origin header field (more on that below). See Section 1.6 for extra details. Those assumptions don't hold up when the client is more capable than a browser ๐Ÿ˜ฌ

This protocol is meant to be used by scripts on web pages, but hosts can also use it directly. Those hosts are acting on their own behalf, so they can send fake Origin header fields and mislead the server ๐Ÿ™ˆ So servers should be careful about assuming they're talking directly to scripts from known origins, and they must consider that they might be accessed in unexpected ways. Most importantly, a server should not trust that any input is valid ๐Ÿšซ

EXAMPLE: If the server uses input as part of SQL queries, all input text should be escaped before it's passed to the SQL server, lest the server be susceptible to SQL injection ๐Ÿ’€ Not the vibe!

10.2. Origin Considerations ๐ŸŒธ

Servers that aren't meant to process input from every web page, but only from certain sites, SHOULD verify that the Origin field is an origin they expect. If the origin is unacceptable to the server, then it SHOULD respond to the WebSocket handshake with a reply containing the HTTP 403 Forbidden status code ๐Ÿšช

The Origin header field protects against attacks where the untrusted party is usually the author of a JavaScript application running inside a trusted client. The client itself can contact the server and, through the Origin header field, decide whether to give those communication privileges to the JavaScript app ๐Ÿ‘‘ The goal isn't to stop non-browsers from connecting. It's to make sure trusted browsers controlled by possibly malicious JavaScript can't fake a WebSocket handshake ๐Ÿซถ

10.3. Attacks On Infrastructure (Masking) ๐ŸŽญ

Endpoints aren't the only ones that get targeted via WebSockets. Other parts of web infrastructure, like proxies, can be attacked too ๐Ÿ˜ญ

While this protocol was being developed, an experiment showed a class of attacks on proxies that led to poisoning of caching proxies out in the wild [TALKING] ๐Ÿ’€ The general shape of the attack: connect to a server under the "attacker's" control, do an UPGRADE on the HTTP connection the way the WebSocket Protocol does to set up a connection, and then send data over that UPGRADEd connection that looks like a GET request for a specific known resource (in a real attack, probably something like a widely deployed hit-tracking script or a resource on an ad network). The remote server replies with something that looks like a response to that fake GET, and a nonzero percentage of deployed intermediaries cache that response, which poisons the cache. So if a user could be talked into visiting an attacker's website, the attacker could poison the cache for that user and for other users behind the same cache, run malicious script on other origins, and break the web security model ๐Ÿšจ

To avoid these attacks on deployed intermediaries, it isn't enough to put non-HTTP framing in front of application data, because you can't exhaustively find and test every nonconformant intermediary to check that it won't skip that framing and act wrongly on the payload. So the defense is to mask all data going from the client to the server. That way the remote script (the attacker) has no control over how the data looks on the wire, and can't build a message that an intermediary might misread as an HTTP request ๐Ÿ›ก๏ธ

Clients MUST choose a new masking key for each frame, using an algorithm that end applications providing the data can't predict. For example, each masking key could come from a cryptographically strong random number generator ๐ŸŽฒ If the same key gets reused, or there's a decipherable pattern for choosing the next key, the attacker can send a message that looks like an HTTP request once masked. (They take the message they want to appear on the wire, mask it with the next masking key, and then the masking key effectively unmasks the data when the client applies it. Galaxy brain attack, but still no thanks ๐Ÿ™…)

It's also necessary that once a frame's transmission from a client has begun, the frame's payload (the application-supplied data) must not be modifiable by the application. Otherwise, an attacker could send a long frame whose first data was a known value (like all zeros), work out the masking key from the first part they receive, and then change the rest of the frame's data so it looks like an HTTP request once masked. (This is basically the same problem as using a known or predictable masking key, just sneakier ๐Ÿฅท) If more data needs to be sent, or data that's already queued gets changed, that new or changed data must go in a new frame, and therefore with a new masking key. In short: once a frame starts transmitting, its contents must not be modifiable by the remote script (application) ๐Ÿ”’

The threat model we're protecting against is a client sending data that looks like an HTTP request. So the channel that needs masking is the data going from the client to the server. The server-to-client data can be made to look like a response, but to pull that off the client would also have to be able to forge a request. So it wasn't deemed necessary to mask data in both directions, and data from the server to the client is not masked ๐Ÿ’โ€โ™€๏ธ

Even with masking in place, non-compliant HTTP proxies are still vulnerable to this type of poisoning attack from clients and servers that don't apply masking ๐Ÿซ 

10.4. Implementation-Specific Limits ๐Ÿงฑ

Implementations that have their own implementation- and/or platform-specific limits on frame size, or on total message size after reassembly from multiple frames, MUST protect themselves against going over those limits. (For example, a malicious endpoint can try to exhaust its peer's memory or mount a denial-of-service attack, either by sending one giant frame, like one of size 2**60, or by sending a long stream of small frames that are part of a fragmented message ๐Ÿ’ฅ) An implementation like this SHOULD impose a limit on frame sizes and on total message size after reassembly from multiple frames ๐Ÿšง

10.5. WebSocket Client Authentication ๐Ÿชช

This protocol doesn't prescribe any particular way for servers to authenticate clients during the WebSocket handshake ๐Ÿ™Œ The WebSocket server can use any client authentication mechanism that's available to a generic HTTP server, like cookies, HTTP authentication, or TLS authentication ๐Ÿช

10.6. Connection Confidentiality and Integrity ๐Ÿ”

Okay bestie, so connection confidentiality and integrity come from running WebSocket over TLS, which is what the wss URIs are for โœจ. WebSocket implementations MUST support TLS and SHOULD employ it when they're talking to their peers ๐Ÿซถ.

With TLS connections, how much protection you actually get depends a LOT on how strong the algorithms are that get negotiated during the TLS handshake ๐Ÿ’…. Some TLS cipher mechanisms don't even provide connection confidentiality, which is so not it ๐Ÿ’€. So to get reasonable protection, clients should use only Strong TLS algorithms ๐ŸŽ€. "Web Security Context: User Interface Guidelines" [W3C.REC-wsc-ui-20100812] talks about what counts as Strong TLS algorithms ๐Ÿ“š. [RFC5246] gives extra guidance in Appendix A.5 and Appendix D.3 ๐ŸŒธ.

10.7. Handling of Invalid Data ๐Ÿ™…โ€โ™€๏ธ

Incoming data MUST always be validated by both clients and servers, no exceptions ๐Ÿšซ. If an endpoint ever gets data it doesn't understand, or data that breaks the criteria it uses to decide whether input is safe, or it sees an opening handshake that doesn't match what it was expecting (like a wrong path or origin in the client request), the endpoint MAY drop the TCP connection ๐Ÿ‘‹. If the invalid data showed up after a successful WebSocket handshake, the endpoint SHOULD send a Close frame with an appropriate status code (Section 7.4) before moving on to _Close the WebSocket Connection_ ๐Ÿ“ฆ. Using a Close frame with a good status code can really help with figuring out what went wrong ๐Ÿ•ต๏ธ. If the invalid data is sent during the WebSocket handshake, the server SHOULD return an appropriate HTTP [RFC2616] status code ๐Ÿงพ.

A super common class of security problems happens when text data gets sent in the wrong encoding ๐Ÿ˜ญ. This protocol says that messages with a Text data type (as opposed to Binary or other types) contain UTF-8-encoded data ๐Ÿ’œ. The length is still indicated, and applications using this protocol should use the length to figure out where the frame actually ends, but sending data in an improper encoding can still break the assumptions that apps built on top of this protocol make. That can lead to anything from misread data to lost data or potential security bugs ๐Ÿ™ˆ.

10.8. Use of SHA-1 by the WebSocket Handshake ๐Ÿง 

The WebSocket handshake described here doesn't depend on any security properties of SHA-1, like collision resistance or resistance to the second pre-image attack (as described in [RFC4270]) ๐Ÿฆ‹.

11. IANA Considerations ๐Ÿ“‹

11.1. Registration of New URI Schemes ๐Ÿ”—

11.1.1. Registration of "ws" Scheme

A ws URI identifies a WebSocket server and resource name ๐ŸŒˆ.

  • URI scheme name: ws
  • Status: Permanent
  • URI scheme syntax: Using the ABNF [RFC5234] syntax and ABNF terminals from the URI specification [RFC3986]:
"ws:" "//" authority path-abempty [ "?" query ]

The <path-abempty> and <query> [RFC3986] components form the resource name sent to the server to identify the kind of service desired. Other components have the meanings described in [RFC3986] โœจ.

  • URI scheme semantics: The only operation for this scheme is to open a connection using the WebSocket Protocol ๐Ÿ’–.
  • Encoding considerations: Characters in the host component that are excluded by the syntax defined above MUST be converted from Unicode to ASCII as specified in [RFC3987] or its replacement. For the purposes of scheme-based normalization, Internationalized Domain Name (IDN) forms of the host component and their conversions to punycode are considered equivalent (see Section 5.3.3 of [RFC3987]) ๐ŸŒ.

Characters in other components that are excluded by the syntax defined above MUST be converted from Unicode to ASCII by first encoding the characters as UTF-8 and then replacing the corresponding bytes using their percent-encoded form, as defined in the URI [RFC3986] and Internationalized Resource Identifier (IRI) [RFC3987] specifications ๐Ÿซง.

  • Applications/protocols that use this URI scheme name: WebSocket Protocol
  • Interoperability considerations: Use of WebSocket requires use of HTTP version 1.1 or higher ๐Ÿ“.
  • Security considerations: See "Security Considerations" section ๐Ÿ”ฅ.
  • Contact: HYBI WG <hybi@ietf.org>
  • Author/Change controller: IETF <iesg@ietf.org>
  • References: RFC 6455

11.1.2. Registration of "wss" Scheme

A wss URI identifies a WebSocket server and resource name, and it says that traffic over that connection is protected via TLS ๐Ÿ”’. That includes the usual TLS perks like data confidentiality and integrity and endpoint authentication ๐Ÿ‘‘.

  • URI scheme name: wss
  • Status: Permanent
  • URI scheme syntax: Using the ABNF [RFC5234] syntax and ABNF terminals from the URI specification [RFC3986]:
"wss:" "//" authority path-abempty [ "?" query ]

The <path-abempty> and <query> components form the resource name sent to the server to identify the kind of service desired. Other components have the meanings described in [RFC3986] ๐ŸŽ€.

  • URI scheme semantics: The only operation for this scheme is to open a connection using the WebSocket Protocol, encrypted using TLS ๐Ÿ”.
  • Encoding considerations: Characters in the host component that are excluded by the syntax defined above MUST be converted from Unicode to ASCII as specified in [RFC3987] or its replacement. For the purposes of scheme-based normalization, IDN forms of the host component and their conversions to punycode are considered equivalent (see Section 5.3.3 of [RFC3987]) ๐ŸŒธ.

Characters in other components that are excluded by the syntax defined above MUST be converted from Unicode to ASCII by first encoding the characters as UTF-8 and then replacing the corresponding bytes using their percent-encoded form, as defined in the URI [RFC3986] and IRI [RFC3987] specifications ๐Ÿ’….

  • Applications/protocols that use this URI scheme name: WebSocket Protocol over TLS
  • Interoperability considerations: Use of WebSocket requires use of HTTP version 1.1 or higher ๐Ÿฆ„.
  • Security considerations: See "Security Considerations" section ๐Ÿ’€.
  • Contact: HYBI WG <hybi@ietf.org>
  • Author/Change controller: IETF <iesg@ietf.org>
  • References: RFC 6455

11.2. Registration of the "WebSocket" HTTP Upgrade Keyword ๐Ÿ†™

This section defines a keyword registered in the HTTP Upgrade Tokens Registry as per RFC 2817 [RFC2817] โœจ.

  • Name of token: WebSocket
  • Author/Change controller: IETF <iesg@ietf.org>
  • Contact: HYBI <hybi@ietf.org>
  • References: RFC 6455

11.3. Registration of New HTTP Header Fields ๐ŸŽ€

11.3.1. Sec-WebSocket-Key

This section describes a header field registered in the Permanent Message Header Field Names registry [RFC3864] ๐Ÿ’–.

  • Header field name: Sec-WebSocket-Key
  • Applicable protocol: http
  • Status: standard
  • Author/Change controller: IETF
  • Specification document(s): RFC 6455
  • Related information: This header field is only used for WebSocket opening handshake.

The Sec-WebSocket-Key header field is used in the WebSocket opening handshake. It is sent from the client to the server to provide part of the information the server uses to prove that it received a valid WebSocket opening handshake. This helps make sure the server doesn't accept connections from non-WebSocket clients (like HTTP clients) that are being abused to send data to unsuspecting WebSocket servers ๐Ÿ›ก๏ธ.

The Sec-WebSocket-Key header field MUST NOT appear more than once in an HTTP request ๐Ÿ™…โ€โ™€๏ธ.

11.3.2. Sec-WebSocket-Extensions

This section describes a header field for registration in the Permanent Message Header Field Names registry [RFC3864] ๐Ÿงš.

  • Header field name: Sec-WebSocket-Extensions
  • Applicable protocol: http
  • Status: standard
  • Author/Change controller: IETF
  • Specification document(s): RFC 6455
  • Related information: This header field is only used for WebSocket opening handshake.

The Sec-WebSocket-Extensions header field is used in the WebSocket opening handshake. It is initially sent from the client to the server, and then subsequently sent from the server to the client, to agree on a set of protocol-level extensions to use for the duration of the connection ๐ŸŒˆ.

The Sec-WebSocket-Extensions header field MAY appear multiple times in an HTTP request (which is logically the same as a single Sec-WebSocket-Extensions header field that contains all values). However, the Sec-WebSocket-Extensions header field MUST NOT appear more than once in an HTTP response ๐Ÿฐ.

11.3.3. Sec-WebSocket-Accept

This section describes a header field registered in the Permanent Message Header Field Names registry [RFC3864] ๐Ÿ’œ.

  • Header field name: Sec-WebSocket-Accept
  • Applicable protocol: http
  • Status: standard
  • Author/Change controller: IETF
  • Specification document(s): RFC 6455
  • Related information: This header field is only used for the WebSocket opening handshake.

The Sec-WebSocket-Accept header field is used in the WebSocket opening handshake. It is sent from the server to the client to confirm that the server is willing to initiate the WebSocket connection ๐Ÿซถ.

The Sec-WebSocket-Accept header MUST NOT appear more than once in an HTTP response ๐Ÿ™ˆ.

11.3.4. Sec-WebSocket-Protocol

This section describes a header field registered in the Permanent Message Header Field Names registry [RFC3864] ๐Ÿ“.

  • Header field name: Sec-WebSocket-Protocol
  • Applicable protocol: http
  • Status: standard
  • Author/Change controller: IETF
  • Specification document(s): RFC 6455
  • Related information: This header field is only used for the WebSocket opening handshake.

The Sec-WebSocket-Protocol header field is used in the WebSocket opening handshake. It is sent from the client to the server and back from the server to the client to confirm the subprotocol of the connection. This lets scripts both select a subprotocol and be sure that the server agreed to serve that subprotocol โœจ.

The Sec-WebSocket-Protocol header field MAY appear multiple times in an HTTP request (which is logically the same as a single Sec-WebSocket-Protocol header field that contains all values). However, the Sec-WebSocket-Protocol header field MUST NOT appear more than once in an HTTP response ๐Ÿ‘‘.

11.3.5. Sec-WebSocket-Version ๐ŸŽ€

Okay so this header is registered in the Permanent Message Header Field Names registry [RFC3864], and it's giving very official vibes ๐Ÿ’…

  • Header field name: Sec-WebSocket-Version
  • Applicable protocol: http
  • Status: standard
  • Author/Change controller: IETF
  • Specification document(s): RFC 6455
  • Related information: This header field is only used for the WebSocket opening handshake.

Bestie, this is the header the client uses to say which WebSocket protocol version it's speaking ๐Ÿฆ‹ That way the server can read the opening handshake correctly and understand the data coming after it. If the server can't handle that data safely, it can close the connection โœจ The server also sends Sec-WebSocket-Version back to the client when the handshake fails because the version the client asked for isn't one the server knows. In that case, the header lists the version(s) the server does support. So it's like a little "here's what I speak" note ๐ŸŒธ

Also, higher version numbers are not guaranteed to be backward compatible with lower ones. Don't assume they'll get along just because the numbers go up ๐Ÿ™ˆ

The Sec-WebSocket-Version header field MAY appear multiple times in an HTTP response, and that's logically the same as one header carrying all the values together ๐Ÿ’œ But in an HTTP request, Sec-WebSocket-Version MUST NOT appear more than once. Keep it to one! ๐Ÿšซ


11.4. WebSocket Extension Name Registry โœจ

So this section creates a brand new IANA registry for WebSocket Extension names, to be used with the WebSocket Protocol. It follows the principles in RFC 5226 [RFC5226] ๐Ÿงš

IANA keeps track of the following info for each entry:

  • Extension Identifier: The identifier of the extension, as it will be used in the Sec-WebSocket-Extensions header field registered in Section 11.3.2 of this specification. The value must conform to the requirements for an extension-token, as defined in Section 9.1 of this specification.
  • Extension Common Name: The name of the extension, as people generally refer to it.
  • Extension Definition: A reference to the document where the extension being used with the WebSocket Protocol is defined.
  • Known Incompatible Extensions: A list of extension identifiers that this extension is known to be incompatible with. Yikes ๐Ÿ’€

WebSocket Extension names are subject to the "First Come First Served" IANA registration policy [RFC5226]. First come, first served, babe ๐Ÿ‘‘

There are no initial values in this registry. It's a clean slate ๐Ÿซง


11.5. WebSocket Subprotocol Name Registry ๐ŸŒˆ

This section creates a new IANA registry for WebSocket Subprotocol names, to be used with the WebSocket Protocol. It also follows the principles in RFC 5226 [RFC5226] ๐Ÿ’–

IANA keeps track of the following info:

  • Subprotocol Identifier: The identifier of the subprotocol, as it will be used in the Sec-WebSocket-Protocol header field registered in Section 11.3.4 of this specification. The value must conform to the requirements given in item 10 of Section 4.1 of this specification. In other words, the value must be a token, as defined by RFC 2616 [RFC2616] ๐Ÿ“
  • Subprotocol Common Name: The name of the subprotocol, as people generally refer to it.
  • Subprotocol Definition: A reference to the document where the subprotocol being used with the WebSocket Protocol is defined.

WebSocket Subprotocol names are subject to the "First Come First Served" IANA registration policy [RFC5226]. Same energy as the extension names, no notes ๐Ÿซถ


11.6. WebSocket Version Number Registry ๐Ÿฆ‹

This section creates a new IANA registry for WebSocket Version Numbers, to be used with the WebSocket Protocol. It follows the principles in RFC 5226 [RFC5226] ๐ŸŒธ

IANA keeps track of the following info:

  • Version Number: The version number to be used in Sec-WebSocket-Version is specified in Section 4.1 of this specification. The value must be a non-negative integer in the range between 0 and 255 (inclusive).
  • Reference: The RFC requesting a new version number, or a draft name with a version number (more on that below).
  • Status: Either "Interim" or "Standard." More on this below too ๐Ÿ’…

Every version number is designated as either "Interim" or "Standard," okay?

A "Standard" version number is documented in an RFC and identifies a major, stable version of the WebSocket protocol, like the one defined by this RFC ๐Ÿ‘‘ "Standard" version numbers are subject to the "IETF Review" IANA registration policy [RFC5226].

An "Interim" version number is documented in an Internet-Draft. Its job is to help implementers identify and interoperate with deployed versions of the WebSocket protocol, including versions that were developed before this RFC was published ๐Ÿซถ "Interim" version numbers are subject to the "Expert Review" IANA registration policy [RFC5226]. The initial Designated Experts are the chairs of the HYBI Working Group. If the working group closes, the Area Directors for the IETF Applications Area take over as the initial Designated Experts ๐Ÿงš

IANA has added initial values to the registry as follows:

+--------+-----------------------------------------+----------+
|Version |                Reference                |  Status  |
| Number |                                         |          |
+--------+-----------------------------------------+----------+
| 0      + draft-ietf-hybi-thewebsocketprotocol-00 | Interim  |
+--------+-----------------------------------------+----------+
| 1      + draft-ietf-hybi-thewebsocketprotocol-01 | Interim  |
+--------+-----------------------------------------+----------+
| 2      + draft-ietf-hybi-thewebsocketprotocol-02 | Interim  |
+--------+-----------------------------------------+----------+
| 3      + draft-ietf-hybi-thewebsocketprotocol-03 | Interim  |
+--------+-----------------------------------------+----------+
| 4      + draft-ietf-hybi-thewebsocketprotocol-04 | Interim  |
+--------+-----------------------------------------+----------+
| 5      + draft-ietf-hybi-thewebsocketprotocol-05 | Interim  |
+--------+-----------------------------------------+----------+
| 6      + draft-ietf-hybi-thewebsocketprotocol-06 | Interim  |
+--------+-----------------------------------------+----------+
| 7      + draft-ietf-hybi-thewebsocketprotocol-07 | Interim  |
+--------+-----------------------------------------+----------+
| 8      + draft-ietf-hybi-thewebsocketprotocol-08 | Interim  |
+--------+-----------------------------------------+----------+
| 9      +                Reserved                 |          |
+--------+-----------------------------------------+----------+
| 10     +                Reserved                 |          |
+--------+-----------------------------------------+----------+
| 11     +                Reserved                 |          |
+--------+-----------------------------------------+----------+
| 12     +                Reserved                 |          |
+--------+-----------------------------------------+----------+
| 13     +                RFC 6455                 | Standard |
+--------+-----------------------------------------+----------+

11.7. WebSocket Close Code Number Registry ๐Ÿ’€

This section creates a new IANA registry for WebSocket Connection Close Code Numbers, following the principles in RFC 5226 [RFC5226] ๐ŸŽ€

IANA keeps track of the following info:

  • Status Code: The Status Code denotes a reason for a WebSocket connection closure, as described in Section 7.4 of this document. It's an integer between 1000 and 4999 (inclusive) ๐Ÿ”ข
  • Meaning: What the status code means. Each status code has to have a unique meaning, no duplicates allowed ๐Ÿšซ
  • Contact: A contact for the entity reserving the status code.
  • Reference: The stable document that requests the status codes and defines what they mean. This is required for status codes in the range 1000-2999, and recommended for status codes in the range 3000-3999.

Close code numbers have different registration requirements depending on their range ๐ŸŒˆ Requests for status codes for use by this protocol and its future versions or extensions are subject to any one of these IANA registration policies: "Standards Action," "Specification Required" (which implies "Designated Expert"), or "IESG Review." These should be granted in the range 1000-2999.

Requests for status codes for use by libraries, frameworks, and applications are subject to the "First Come First Served" IANA registration policy. These should be granted in the range 3000-3999.

The range 4000-4999 is designated for Private Use ๐Ÿ”’

Requests should say whether they're asking for status codes for the WebSocket Protocol (or a future version of it), for extensions, or for libraries/frameworks/applications. Be clear about it, bestie ๐Ÿ’œ

IANA has added initial values to the registry as follows:

  |Status Code | Meaning         | Contact       | Reference |
 -+------------+-----------------+---------------+-----------|
  | 1000       | Normal Closure  | hybi@ietf.org | RFC 6455  |
 -+------------+-----------------+---------------+-----------|
  | 1001       | Going Away      | hybi@ietf.org | RFC 6455  |
 -+------------+-----------------+---------------+-----------|
  | 1002       | Protocol error  | hybi@ietf.org | RFC 6455  |
 -+------------+-----------------+---------------+-----------|
  | 1003       | Unsupported Data| hybi@ietf.org | RFC 6455  |
 -+------------+-----------------+---------------+-----------|
  | 1004       | ---Reserved---- | hybi@ietf.org | RFC 6455  |
 -+------------+-----------------+---------------+-----------|
  | 1005       | No Status Rcvd  | hybi@ietf.org | RFC 6455  |
 -+------------+-----------------+---------------+-----------|
  | 1006       | Abnormal Closure| hybi@ietf.org | RFC 6455  |
 -+------------+-----------------+---------------+-----------|
  | 1007       | Invalid frame   | hybi@ietf.org | RFC 6455  |
  |            | payload data    |               |           |
 -+------------+-----------------+---------------+-----------|
  | 1008       | Policy Violation| hybi@ietf.org | RFC 6455  |
 -+------------+-----------------+---------------+-----------|
  | 1009       | Message Too Big | hybi@ietf.org | RFC 6455  |
 -+------------+-----------------+---------------+-----------|
  | 1010       | Mandatory Ext.  | hybi@ietf.org | RFC 6455  |
 -+------------+-----------------+---------------+-----------|
  | 1011       | Internal Server | hybi@ietf.org | RFC 6455  |
  |            | Error           |               |           |
 -+------------+-----------------+---------------+-----------|
  | 1015       | TLS handshake   | hybi@ietf.org | RFC 6455  |
 -+------------+-----------------+---------------+-----------|

11.8. WebSocket Opcode Registry ๐ŸŽ€

This spec sets up a brand-new IANA registry for WebSocket Opcodes, following the principles in RFC 5226 [RFC5226]. โœจ

IANA keeps the following info for this registry:

  • Opcode: the frame type of a WebSocket frame, as defined in Section 5.2. It's an integer from 0 to 15, inclusive. ๐Ÿงš
  • Meaning: what the opcode value means. ๐Ÿ’œ
  • Reference: the spec that asked for the opcode. ๐Ÿ“š

WebSocket Opcode numbers are handled under the "Standards Action" IANA registration policy [RFC5226]. ๐Ÿ’…

IANA already added these initial values to the registry: ๐ŸŒˆ

  |Opcode  | Meaning                             | Reference |
 -+--------+-------------------------------------+-----------|
 | 0      | Continuation Frame                  | RFC 6455  |
 -+--------+-------------------------------------+-----------|
 | 1      | Text Frame                          | RFC 6455  |
 -+--------+-------------------------------------+-----------|
 | 2      | Binary Frame                        | RFC 6455  |
 -+--------+-------------------------------------+-----------|
 | 8      | Connection Close Frame              | RFC 6455  |
 -+--------+-------------------------------------+-----------|
 | 9      | Ping Frame                          | RFC 6455  |
 -+--------+-------------------------------------+-----------|
 | 10     | Pong Frame                          | RFC 6455  |
 -+--------+-------------------------------------+-----------|

11.9. WebSocket Framing Header Bits Registry ๐Ÿฆ‹

Same energy here: this spec creates another new IANA registry, for WebSocket Framing Header Bits, following the principles in RFC 5226 [RFC5226]. This one controls the assignment of the bits marked RSV1, RSV2, and RSV3 in Section 5.2. ๐Ÿ“

Those bits are reserved for future versions or extensions of this spec. ๐Ÿ”ฎ

WebSocket Framing Header Bits assignments are handled under the "Standards Action" IANA registration policy [RFC5226]. ๐Ÿซถ

12. Using the WebSocket Protocol from Other Specifications ๐Ÿงฉ

The WebSocket Protocol is meant to be used by other specs as a generic way to do dynamic, author-defined content, like in a spec that defines a scripted API. ๐Ÿ’–

So a spec like that first needs to Establish a WebSocket Connection, and it gives that algorithm:

  • The destination, made up of a host and a port. ๐Ÿ“
  • A resource name, which lets multiple services be identified at one host and port. ๐Ÿ—‚๏ธ
  • A secure flag, which is true if the connection is going to be encrypted and false otherwise. ๐Ÿ”
  • An ASCII serialization of an origin [RFC6454] that's being made responsible for the connection. ๐Ÿ™‹โ€โ™€๏ธ
  • Optionally, a string naming a protocol to be layered over the WebSocket connection. ๐Ÿฐ

The host, port, resource name, and secure flag are usually pulled out of a URI using the steps to parse a WebSocket URI's components. Those steps fail if the URI doesn't specify a WebSocket. ๐Ÿšซ

If the connection ever needs to close at any point, the spec has to use the Close the WebSocket Connection algorithm (Section 7.1.1). ๐Ÿ‘‹

Section 7.1.4 defines when The WebSocket Connection is Closed. ๐Ÿ

While a connection is open, the spec will need to handle the cases where A WebSocket Message Has Been Received (Section 6.2). ๐Ÿ“ฉ

To send some data data to an open connection, the spec needs to Send a WebSocket Message (Section 6.1). ๐Ÿš€

13. Acknowledgements ๐ŸŒธ

Huge shoutout to Ian Hickson, the original author and editor of this protocol, no notes. ๐Ÿ‘‘ The initial design of this spec benefited from lots of people in the WHATWG and the WHATWG mailing list. Contributions to that spec aren't tracked by section, but there's a list of everyone who contributed in the WHATWG HTML specification at http://whatwg.org/html5. ๐Ÿฅน

Special thanks also to John Tamplin, who wrote a significant amount of text for the "Data Framing" section. โœ๏ธ

Special thanks also to Adam Barth, who wrote a significant amount of text and did background research for the "Data Masking" section. ๐Ÿ”ฌ

Special thanks to Lisa Dusseault for the Apps Area review (and for helping start this work), Richard Barnes for the Gen-Art review, and Magnus Westerlund for the Transport Area Review. ๐Ÿ™Œ Special thanks to the HYBI WG chairs, past and present, who tirelessly worked behind the scenes to move this toward completion: Joe Hildebrand, Salvatore Loreto, and Gabriel Montenegro. And last but not least, special thank you to the responsible Area Director, Peter Saint-Andre. ๐Ÿ‘โœจ

Thank you to the following people who joined discussions on the HYBI WG mailing list and contributed ideas and/or gave detailed reviews (the list is likely incomplete): Greg Wilkins, John Tamplin, Willy Tarreau, Maciej Stachowiak, Jamie Lokier, Scott Ferguson, Bjoern Hoehrmann, Julian Reschke, Dave Cridland, Andy Green, Eric Rescorla, Inaki Baz Castillo, Martin Thomson, Roberto Peon, Patrick McManus, Zhong Yu, Bruce Atherton, Takeshi Yoshino, Martin J. Duerst, James Graham, Simon Pieters, Roy T. Fielding, Mykyta Yevstifeyev, Len Holgate, Paul Colomiets, Piotr Kulaga, Brian Raymor, Jan Koehler, Joonas Lehtolahti, Sylvain Hellegouarch, Stephen Farrell, Sean Turner, Pete Resnick, Peter Thorson, Joe Mason, John Fallows, and Alexander Philippou. ๐Ÿ’œ People listed above didn't necessarily endorse the end result of this work, so no pressure on them lol. ๐Ÿ™ˆ

14. References ๐Ÿ“–

14.1. Normative References ๐Ÿ”’

   [ANSI.X3-4.1986]
              American National Standards Institute, "Coded Character
              Set - 7-bit American Standard Code for Information
              Interchange", ANSI X3.4, 1986.

   [FIPS.180-3]
              National Institute of Standards and Technology, "Secure
              Hash Standard", FIPS PUB 180-3, October 2008,
              <http://csrc.nist.gov/publications/fips/fips180-3/
              fips180-3_final.pdf>.

   [RFC1928]  Leech, M., Ganis, M., Lee, Y., Kuris, R., Koblas, D., and
              L. Jones, "SOCKS Protocol Version 5", RFC 1928,
              March 1996.

   [RFC2119]  Bradner, S., "Key words for use in RFCs to Indicate
              Requirement Levels", BCP 14, RFC 2119, March 1997.

   [RFC2616]  Fielding, R., Gettys, J., Mogul, J., Frystyk, H.,
              Masinter, L., Leach, P., and T. Berners-Lee, "Hypertext
              Transfer Protocol -- HTTP/1.1", RFC 2616, June 1999.

   [RFC2817]  Khare, R. and S. Lawrence, "Upgrading to TLS Within
              HTTP/1.1", RFC 2817, May 2000.

   [RFC2818]  Rescorla, E., "HTTP Over TLS", RFC 2818, May 2000.

   [RFC3629]  Yergeau, F., "UTF-8, a transformation format of ISO
              10646", STD 63, RFC 3629, November 2003.

   [RFC3864]  Klyne, G., Nottingham, M., and J. Mogul, "Registration
              Procedures for Message Header Fields", BCP 90, RFC 3864,
              September 2004.

   [RFC3986]  Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform
              Resource Identifier (URI): Generic Syntax", STD 66,
              RFC 3986, January 2005.

   [RFC3987]  Duerst, M. and M. Suignard, "Internationalized Resource
              Identifiers (IRIs)", RFC 3987, January 2005.

   [RFC4086]  Eastlake, D., Schiller, J., and S. Crocker, "Randomness
              Requirements for Security", BCP 106, RFC 4086, June 2005.

   [RFC4648]  Josefsson, S., "The Base16, Base32, and Base64 Data
              Encodings", RFC 4648, October 2006.

   [RFC5226]  Narten, T. and H. Alvestrand, "Guidelines for Writing an
              IANA Considerations Section in RFCs", BCP 26, RFC 5226,
              May 2008.

   [RFC5234]  Crocker, D. and P. Overell, "Augmented BNF for Syntax
              Specifications: ABNF", STD 68, RFC 5234, January 2008.

   [RFC5246]  Dierks, T. and E. Rescorla, "The Transport Layer Security
              (TLS) Protocol Version 1.2", RFC 5246, August 2008.

   [RFC6066]  Eastlake, D., "Transport Layer Security (TLS) Extensions:
              Extension Definitions", RFC 6066, January 2011.

   [RFC6454]  Barth, A., "The Web Origin Concept", RFC 6454,
              December 2011.

14.2. Informative References ๐Ÿ’ก

   [RFC4122]  Leach, P., Mealling, M., and R. Salz, "A Universally
              Unique IDentifier (UUID) URN Namespace", RFC 4122,
              July 2005.

   [RFC4270]  Hoffman, P. and B. Schneier, "Attacks on Cryptographic
              Hashes in Internet Protocols", RFC 4270, November 2005.

   [RFC5321]  Klensin, J., "Simple Mail Transfer Protocol", RFC 5321,
              October 2008.

   [RFC6202]  Loreto, S., Saint-Andre, P., Salsano, S., and G. Wilkins,
              "Known Issues and Best Practices for the Use of Long
              Polling and Streaming in Bidirectional HTTP", RFC 6202,
              April 2011.

   [RFC6265]  Barth, A., "HTTP State Management Mechanism", RFC 6265,
              April 2011.

   [TALKING]  Huang, L-S., Chen, E., Barth, A., Rescorla, E., and C.
              Jackson, "Talking to Yourself for Fun and Profit", 2010,
              <http://w2spconf.com/2011/papers/websocket.pdf>.

   [W3C.REC-wsc-ui-20100812]
              Roessler, T. and A. Saldhana, "Web Security Context: User
              Interface Guidelines", World Wide Web Consortium
              Recommendation REC-wsc-ui-20100812, August 2010,
              <http://www.w3.org/TR/2010/REC-wsc-ui-20100812/>.

              Latest version available at
              <http://www.w3.org/TR/wsc-ui/>.

   [WSAPI]    Hickson, I., "The WebSocket API", W3C Working Draft WD-
              websockets-20110929, September 2011,
              <http://www.w3.org/TR/2011/WD-websockets-20110929/>.

              Latest version available at
              <http://www.w3.org/TR/websockets/>.

   [XMLHttpRequest]
              van Kesteren, A., Ed., "XMLHttpRequest", W3C Candidate
              Recommendation CR-XMLHttpRequest-20100803, August 2010,
              <http://www.w3.org/TR/2010/CR-XMLHttpRequest-20100803/>.

              Latest version available at
              <http://www.w3.org/TR/XMLHttpRequest/>.

Authors' Addresses ๐Ÿ’Œ

   Ian Fette
   Google, Inc.

   EMail: ifette+ietf@google.com
   URI:   http://www.ianfette.com/


   Alexey Melnikov
   Isode Ltd.
   5 Castle Business Village
   36 Station Road
   Hampton, Middlesex  TW12 2BX
   UK

   EMail: Alexey.Melnikov@isode.com

That's the whole protocol, bestie!! ๐ŸŒˆ๐Ÿงš๐Ÿ’–

๐Ÿ“ฆ where this page comes from