Before a WebSocket can open over HTTP/2, what must the server have sent, and what request replaces the GET with `Upgrade: websocket`?
answer
- the server offers before the client asks
- a setting first, then a method
- one stream becomes the socket
- SETTINGS_ENABLE_CONNECT_PROTOCOL is the gate
- :protocol = websocket on a CONNECT
basics
~10 sAn 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 sHTTP/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: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.v1go deeper
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.
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.
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.
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.