skip to content

Extended CONNECT Bootstrap

How a socket opens when there is no 101: a server SETTINGS flag, a CONNECT carrying :protocol websocket, and HTTP/3 too. Interviewers ask because the handshake everyone recites is the HTTP/1.1 one.

part ofWebSocketsoverview, primer and where to startread it →
on this pageshow

questions

5

Before a WebSocket can open over HTTP/2, what must the server have sent, and what request replaces the GET with `Upgrade: websocket`?

level: middleimportance: must knowfreq 58%

answer

  1. the server offers before the client asks
  2. a setting first, then a method
  3. one stream becomes the socket
  4. SETTINGS_ENABLE_CONNECT_PROTOCOL is the gate
  5. :protocol = websocket on a CONNECT

basics

~10 s

An HTTP/2 server must first advertise SETTINGS_ENABLE_CONNECT_PROTOCOL with the value 1; only then may a client send an extended CONNECT request carrying the :protocol pseudo-header set to websocket, alongside :scheme, :path and :authority.

solid answer

~40 s

HTTP/2 has no `Upgrade` mechanism — `Connection` and `Upgrade` are connection-specific fields that an HTTP/2 request may not carry — so `RFC 8441` replaces the upgrade with a tunnel on a single stream. The gate is a setting: the server advertises `SETTINGS_ENABLE_CONNECT_PROTOCOL` (code `0x8`) with the value `1`, and only a client that has seen it may attempt the bootstrap. The request is then an extended CONNECT: `:method` is `CONNECT`, `:protocol` is `websocket`, and — unlike a plain CONNECT — `:scheme` and `:path` are both present, with `:scheme` being `https` for a `wss` URI and `http` for a `ws` one. `:authority` carries what `Host` used to. Nothing on the connection is handed over; one stream becomes the socket.

code

http · 8 lines
http
:method = CONNECT
:protocol = websocket
:scheme = https
:path = /hoist/shaft-3/signals
:authority = hoist-control.example:443
origin = https://console.example
sec-websocket-version = 13
sec-websocket-protocol = hoist.signal.v1

go deeper

for a junior

Remember the shape: over HTTP/2 a WebSocket does not upgrade a connection, it opens on one stream, and the server has to say up front that it allows this.

for a middle

Be able to name the setting, say that the server sends it, and lay out the CONNECT request's pseudo-headers - including that :scheme and :path are present here and absent from a plain CONNECT.

for a senior

Show that you know the gate is a permission, not a negotiation: a request sent before the advertisement is a client-side error, and a fallback path has to exist for servers that never advertise.

for a principal

The tradeoff to weigh is one socket per stream on a connection you already pay for, against a bootstrap that only works where every hop on the path implements it.

## Why the handshake everyone recites does not run here The opening handshake in `RFC 6455` is an HTTP/1.1 `GET` that carries `Upgrade: websocket` and `Connection: Upgrade`, and asks the server to stop speaking HTTP on that connection and start speaking WebSocket, which it agrees to with `101 Switching Protocols`. Every part of that sentence is an HTTP/1.1 fact. Over HTTP/2, none of it is available: - **`Connection` and `Upgrade` are forbidden.** They are connection-specific fields, and an HTTP/2 endpoint must not generate them; a request that carries them is malformed. - **There is no `101`.** The interim-response mechanism the upgrade depended on has no equivalent in HTTP/2. - **The connection is not one request's to take.** An HTTP/2 connection carries many concurrent streams for many requests. "Hand the whole connection to another protocol" is not something a single request may ask for. `RFC 8441` solves this by moving the socket down one level: instead of converting a *connection*, it converts a **stream**. `RFC 9220` carries the same mechanism to HTTP/3. ## The gate: a setting only the server sends A client may not simply try. The server advertises `SETTINGS_ENABLE_CONNECT_PROTOCOL` — code `0x8` in HTTP/2, value `0x08` in HTTP/3 — with the value `1` in its settings, and that advertisement is what permits the bootstrap. 1. Only a server sends this usefully; a client offering it means nothing. 2. A client that has not received it must not send an extended CONNECT. 3. A server that has advertised `1` may not later revert to `0` on the same connection — support does not come and go mid-connection. 4. Until it arrives, a client that wants a socket has two honest options: the HTTP/1.1 handshake on a separate connection, or no socket. This is the part candidates miss. They know HTTP/2 does something different; they do not know the something different is **gated**, and that a perfectly correct request sent to a server that never advertised the setting is a protocol error on the client's part rather than a negotiation. ## The request: CONNECT, plus one pseudo-header A WebSocket bootstrap over HTTP/2 is a `CONNECT` request whose pseudo-header block includes `:protocol = websocket`. That pseudo-header is the whole signal — it is what distinguishes this request from any other use of the method, and a server that understands it treats the stream as a tunnel rather than as a request for a representation. ```http :method = CONNECT :protocol = websocket :scheme = https :path = /hoist/shaft-3/signals :authority = hoist-control.example:443 origin = https://console.example sec-websocket-version = 13 sec-websocket-protocol = hoist.signal.v1 ``` Two details in that block decide most interview answers: - **`:scheme` and `:path` are present.** A plain CONNECT omits both. The WebSocket bootstrap requires them, because the socket attaches to a resource — a path on an origin — not merely to a host. - **`:scheme` is `https` for a `wss` URI and `http` for a `ws` one.** There is no `wss` scheme on the wire; the security is the connection's, and the connection is already established. - **`:authority` carries the host and port** that `Host` carried in HTTP/1.1. It does *not* mean "open a tunnel to this host" the way it does on a plain CONNECT. | | HTTP/1.1 handshake | Extended CONNECT bootstrap | |---|---|---| | Request line / method | `GET` with `Upgrade: websocket` | `CONNECT` with `:protocol = websocket` | | `Connection` / `Upgrade` fields | required | forbidden | | Host information | `Host` field | `:authority` pseudo-header | | Permission needed first | none | server's `SETTINGS_ENABLE_CONNECT_PROTOCOL` = 1 | | Scope converted | the whole connection | one stream | ## What this buys the deployment A console that already holds an expensive connection to the far end gets its socket **inside** that connection, on one more stream, instead of paying to open and secure a second one. Everything else the connection was doing keeps running beside it. That is the reason the mechanism exists, and it is why a device on a constrained or metered link cares about it far more than a browser tab on a laptop does.

  • Who sends SETTINGS_ENABLE_CONNECT_PROTOCOL, and may a server that advertised it withdraw it later on the same connection?
    The server sends it; a client advertising it achieves nothing. Once a server has sent the value `1` on a connection it must not later send `0` on that same connection, so a client that saw the advertisement can keep relying on it for the connection's life rather than re-checking before each socket.
  • In a WebSocket extended CONNECT, what does `:authority` carry, and where did the `Host` field go?
    `:authority` carries the host and port of the WebSocket URI — the information HTTP/1.1 put in `Host`. HTTP/2 conveys it as a pseudo-header instead of an ordinary field. Note that it does not mean "tunnel to this host": the target resource is named by `:path`, which a plain CONNECT does not send at all.
  • What does a client do if it wants a socket and the server never advertises the setting?
    It must not send the extended CONNECT. Its options are to open the socket the RFC 6455 way — an HTTP/1.1 connection with `Upgrade: websocket` — or to do without one. Most clients keep the HTTP/1.1 path as a fallback precisely for this case.

The building is already open for the day's traffic. Extended CONNECT is asking the doorman for an inner corridor off the same hallway - and he only offers one if the notice board says the corridor exists.

saying these in an interview costs you the question

  • Thinks an HTTP/2 socket still sends Upgrade: websocket and gets a 101.
  • Assumes any HTTP/2 server will accept an extended CONNECT.
  • Sends a plain CONNECT with no :protocol pseudo-header.
  • Omits :scheme and :path the way a plain CONNECT does.
  • Believes the client advertises the setting to the server.
  • Says the socket takes over the whole HTTP/2 connection.
open as a page

A WebSocket bootstrapped over HTTP/2 sends no `Sec-WebSocket-Key` and gets no `101`, so which handshake fields survive and what signals success?

level: middleimportance: should knowfreq 46%

basics

~10 s

Origin, Sec-WebSocket-Version, Sec-WebSocket-Protocol and Sec-WebSocket-Extensions survive, lowercased as HTTP/2 requires. The Key/Accept digest is gone because the :protocol pseudo-header does its job, and success is a 2xx status - in practice 200.

open as a page

A WebSocket bootstrap over HTTP/2 is answered with `:status = 501`, so what has the server said and what should the client do next?

level: seniorimportance: should knowfreq 38%

basics

~20 s

The 501 says the server does not support the :protocol the extended CONNECT carried, so no tunnel opened and no WebSocket exists. A client should stop retrying that path and fall back to the RFC 6455 HTTP/1.1 handshake on a separate connection.

open as a page

Would you standardise a WebSocket fleet on extended CONNECT bootstrapping when each console holds one leased HTTP/2 link and some intermediaries refuse it?

level: principalimportance: should knowfreq 30%

basics

~20 s

Prefer it, but never as the only path. Extended CONNECT puts the socket on a link you already pay for, while support is decided by every hop between the console and the origin - so the fleet commits to both bootstraps and to measuring which one each site actually gets.

open as a page

How does a WebSocket carried in an extended CONNECT tunnel over HTTP/2 or HTTP/3 end, and what survives that ending?

level: seniorimportance: nice to knowfreq 29%

basics

~20 s

The stream ends, not the connection. In HTTP/2 each side finishes with a DATA frame carrying END_STREAM; in HTTP/3 with a FIN on that stream. The connection and every other exchange riding it continue untouched.

open as a page