WebSocket

WebSocket is a communications protocol that supports bidirectional communication over a single TCP connection. It is designed to work over HTTP ports 80 and 443, making it compatible with infrastructure including HTTP proxies and intermediaries.

Usage

WebSocket and HTTP are distinct protocols that operate over the same infrastructure. The WebSocket protocol was designed to create a mechanism for bidirectional communication between a client and a server that does not suffer from problems inherent with stateless HTTP data transmission.

For example, a web-based instant messaging system using HTTP requires the client to continuously poll the server for new messages. Each message sent from client to server uses a new HTTP request, in some cases using new connections. WebSocket maintains the connection as long as the session is open, avoiding the overhead associated with dropping and reestablishing the connection many times. With WebSocket compatible at the infrastructure level, it means that technologies such as proxies and Authentication schemes can be utilized without significant changes.

Importantly, WebSocket does not depend on HTTP. It can be implemented such that it operates over a specific port, independent of HTTP or HTTPS. This gives developers greater flexibility over network communications.

Browser and server support

Most modern browsers support the WebSocket protocol, although due to security concerns, some versions in certain operating systems have been disabled. Similarly, popular servers such as the Apache HTTP Server, Nginx, and Microsoft IIS all support WebSockets.

URI

The WebSocket protocol introduces two new URI schemes. These are ws:// (WebSocket) and wss:// (WebSocket Secure).

ws : [// authority] path [? query]

Note

WebSocket does not support fragments but otherwise, it follows the same format as a standard URI.

Well-Known URIs

There are well-known URIs that support the WebSocket protocol and the list can be viewed at IANA Well-Known URIs.

Establishing WebSocket via HTTP/1.1

The HTTP/1.1 protocol includes a facility for converting an existing connection into a WebSocket connection. Specifically, the HTTP Upgrade request header is used to change protocols. It is not allowed in HTTP/2 and in fact, is not guaranteed in HTTP/1.1 because it is optional. A server is not obligated to change protocols, even if it supports the one that the client intends to upgrade to. The most common use of HTTP Upgrade header is to initiate a WebSocket connection.

The HTTP Upgrade header is a hop-by-hop header, which means that it has to be listed in the HTTP Connection header. Additional WebSocket-specific headers can also be used for enhancing the security of the connection.

HTTP/1.1 Upgrade example

In this example, the client sends an HTTP request that includes the HTTP Upgrade header. This HTTP header further requests that the server upgrade the connection to the WebSocket protocol, and the server responds with the 101 Switching Protocols HTTP status code to acknowledge that the Protocol Upgrade request was completed.

The client will verify the base64-encoded string in Sec-Websocket-Accept and from that point, subsequent messages are assumed to be WebSocket.

Request

GET / HTTP/1.1
Host: www.example.re
Connection: Upgrade
Sec-WebSocket-Key: IS0tZXhhbXBsZS5haS0tIQ==
Origin: http://example.re

Response

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: upgrade
Sec-WebSocket-Accept: OWQ4NjdjMDFhN2FiOGUwYzA4ZjYxNDc5MWFlMDQ2ZTViZDA1OWIzOA==

WebSocket headers

Several WebSocket-specific headers are used to set different parameters for the connection.

Sec-WebSocket-Key

The Sec-WebSocket-Key header is part of the WebSocket handshake. The key is calculated by base64 encoding a random string of 16 characters, each with an ASCII value between 32 and 127. A different key must be randomly generated for each connection.

This key will be read by the server and a corresponding response will be returned to the client.

Sec-WebSocket-Accept

The Sec-Websocket-Accept header is included with the initial response from the server. It is used only as part of the opening handshake and will only be included once within it.

The server reads the Sec-WebSocket-Key, appends UUID 258EAFA5-E914-47DA-95CA- to it, re-encodes it using base64, and returns it in the response as the parameter for Sec-Websocket-Accept. This is not intended to add a layer of security to the protocol. Rather, it allows the client to verify that the server does indeed understand WebSockets. Also, if an intermediary caches the response and returns it as part of a new request, the client will be able to recognize that the response is no longer valid. This is the case only because a new random key is used for each connection. This mechanism is not intended to provide Authentication or enhance privacy.

Sec-WebSocket-Extensions

The Sec-WebSocket-Extensions header is part of the WebSocket handshake. It is sent by the client to ask the server to use a specific set of extensions. This header can be included more than one time or a common-delimited list of extensions can be included on a single line. The extensions must be chosen from the IANA WebSocket Extension Name Registry. If an extension requires a parameter then it can be included by preceding the parameter with a semicolon.

The server will respond with the Sec-WebSocket-Extensions header to confirm what protocol-level extensions will be used for the remainder of the connection. The server will not include more than one instance of this header in the response.

Sec-WebSocket-Extensions example

In this example, the extensions being requested are colormode and background. The latter with the theme parameter set to light.

Sec-WebSocket-Extensions: colormode, background; theme=light

Sec-WebSocket-Protocol

The Sec-WebSocket-Protocol header is part of the WebSocket handshake. It is sent by the client to ask the server to use a specific subprotocol. This header can appear multiple times within the request, or instead, multiple subprotocols can be listed in a comma-delimited format. Subprotocols are chosen from the IANA WebSocket Subprotocol Name Registry. If multiple subprotocols are listed then do so in order of preference.

The server will respond using the Sec-WebSocket-Protocol header to confirm which subprotocol will be used. This server will include this header only once in the response.

Sec-WebSocket-Protocol example

In this example, a home automation network is communicating with various IoT and home automation devices. The first choice of protocol is SHIP (Smart Home IP), and the fallback choice is the done (done.best IoT protocol).

Sec-WebSocket-Protocol: ship, done

Sec-WebSocket-Version

The Sec-WebSocket-Version header is part of the WebSocket handshake. It is sent by the client to ask the server to use a specific version of the WebSocket protocol. It must be a non-negative number between 0 and 255, and the current set of versions can be found at the IANA WebSocket Version Number Registry. This header can appear multiple times within the request, or multiple choices listed in order of preference can be listed in a comma-delimited format.

If the server does not support any of the versions requested by the clients then it will return with an error that includes the Sec-WebSocket-Version header listing all of the versions that it supports.

Sec-WebSocket-Version example

In this example, the client is requesting that the server use the most recent version available when it was implemented, which is version 13 (standard version listed in RFC 8307), or version 8 as a fallback.

Sec-WebSocket-Version: 13, 8

If the server had not been willing to use either of these versions then it might return a response like:

Response

HTTP/1.1 400 Bad Request
Sec-WebSocket-Version: 7, 6

This response from the server indicates that it is only willing to use protocol version 7 or 6.

Alternatively, the server can reasonably return HTTP status code 426 Upgrade Required. Regardless of which HTTP status code is returned, a valid list of versions must be specified in the Sec-WebSocket-Version header.

Accessing WebSocket programmatically

WebSockets can be created by upgrading HTTP or HTTPS connections but they can also be created directly using other methods. For example, the following line of JavaScript code will create a WebSocket.

const connection = new WebSocket(‘ws://files.example.re/’);

Libraries and example code for using WebSocket with different programming languages such as Java, C#, C++, Rust, Ruby, and others are available from a variety of online resources. Examples for creating connections, as well as functions for event and error handling, are readily available.

Takeaway

The WebSocket protocol was designed to accommodate bidirectional communication over a single TCP connection while maintaining compatibility with infrastructure for HTTP. It is not dependent on HTTP and can work independently, directly connecting to a port. A WebSocket connection can be established by upgrading an existing HTTP/1.1 connection or programmatically.

See also

Last updated: August 2, 2023