How does a WebSocket carried in an extended CONNECT tunnel over HTTP/2 or HTTP/3 end, and what survives that ending?
answer
- the socket is a stream, not a connection
- ending one leaves the other
- two layers close, name both
- END_STREAM in HTTP/2
- a FIN on the HTTP/3 stream
basics
~20 sThe 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.
solid answer
~40 sA bootstrapped socket owns one stream, so ending the socket means ending that stream. Over HTTP/2 that is a `DATA` frame carrying `END_STREAM` from each side; over HTTP/3 it is a `FIN` on the stream carrying the tunnel. Either way the connection survives, and whatever else it was carrying keeps running — which is the opposite of the HTTP/1.1 case, where the socket consumed the connection for its whole life and closing one meant losing the other. The WebSocket protocol's own closing handshake still runs inside the tunnel first; what changes at this level is what happens underneath it. Practically this means a device can drop and reopen its socket repeatedly without re-establishing a connection, and without disturbing the requests sharing it.
code
pseudocode · 13 linesfunction close_bootstrapped_socket(stream):
# layer 1: the WebSocket closing handshake, inside the tunnel
send websocket_close_frame on stream
wait for peer close_frame, with a deadline
# layer 2: the stream underneath the tunnel
if transport is http2:
send empty DATA frame with END_STREAM on stream
else:
send FIN on stream
# the connection is untouched and keeps serving other streams
returngo deeper
Remember the unit: over HTTP/2 or HTTP/3 the socket lives on one stream, so ending it does not end the connection or anything else using it.
Name the mechanics per version - DATA with END_STREAM, or a FIN - and distinguish them from the closing handshake happening inside the tunnel.
Use the distinction in diagnosis: a dead socket on a live connection rules out every connection-wide cause, and a lost connection takes every socket and request with it.
Weigh the concentration this creates: one connection per device is cheap until it is the single event that takes out a whole device's traffic at once.
## One stream is the socket, so one stream is what ends Over HTTP/1.1 a WebSocket takes the connection. From the `101` onward, that TCP connection speaks WebSocket and nothing else; when the socket is finished, the connection goes with it, and anything else that wanted to talk to the same origin needed its own connection. The extended CONNECT bootstrap changes the unit. The socket is a converted **stream** on a connection that carries many. Its lifetime is the stream's lifetime: - **HTTP/2** — the tunnel ends when the stream ends: a `DATA` frame carrying `END_STREAM` from each side closes it in that direction, and once both directions are done the stream is closed. - **HTTP/3** — the same shape, expressed the way HTTP/3 expresses it: a `FIN` on the stream carrying the tunnel. In both cases the **connection is untouched**. Other exchanges on it continue. A subsequent socket can be bootstrapped on a new stream over the same connection, with no new handshake underneath. ## Two layers, two closings, and why the distinction matters There are two things called closing here, and they sit at different layers: 1. **Inside the tunnel**, the WebSocket protocol's own closing handshake runs exactly as it always has. That layer is unchanged by the bootstrap and is where an application's close semantics live. 2. **Underneath it**, the stream terminates in the transport's own terms — `END_STREAM` or a `FIN`. A clean shutdown does the first, then the second. A stream that simply ends underneath a socket takes the socket with it whether or not the layer above finished politely. When you describe a closure, say which of the two you mean: "the connection closed" is the least informative sentence available here, because on a bootstrapped socket the connection very likely did not. | | HTTP/1.1 socket | Bootstrapped socket (HTTP/2) | Bootstrapped socket (HTTP/3) | |---|---|---|---| | Unit the socket owns | the connection | one stream | one stream | | How it ends underneath | connection teardown | `DATA` + `END_STREAM` | `FIN` on the stream | | Survives the ending | nothing on that connection | the connection and its other streams | the connection and its other streams | | Cost of reopening | new connection, new security handshake | a new stream | a new stream | ## What this buys, and where it misleads For a console at the end of an expensive link, the practical gain is reconnection cost. A socket that drops and reopens ten times in a shift costs ten streams, not ten connections — no new transport setup, no new security handshake, and no disturbance to the other traffic the link is carrying. That is a large difference on a constrained link and almost invisible on a laptop. The place it misleads is diagnosis. Engineers reason about WebSocket failures with an HTTP/1.1 mental model in which "the socket died" and "the connection died" are the same event. On a bootstrapped socket they are not: - The socket can end while the connection stays healthy and busy — nothing in the connection's own health tells you a socket went away. - The connection can be lost, and then every socket riding it is gone at once, along with every ordinary request in flight. One event, many casualties. That second case is the one worth planning for. Consolidating a device's traffic onto one connection is exactly what makes the bootstrap attractive, and it is also what makes a single connection loss a fleet-visible event rather than one socket's problem. The reconnection design has to account for everything the connection was carrying, not just the socket you were thinking about. ## Saying it precisely When you answer this in an interview, name the layer in every sentence: the WebSocket closing handshake runs inside the tunnel; the tunnel ends when the stream ends; the stream ends with `END_STREAM` in HTTP/2 or a `FIN` in HTTP/3; the connection outlives all of it. Four claims, four different nouns, and a candidate who blurs them sounds like someone who has read about one HTTP version and assumed it generalises.
- A bootstrapped socket goes away but the connection stays healthy. What does that rule out?It rules out anything connection-wide: transport loss, a security-layer failure, or a hop tearing the link down. Whatever ended the socket acted on that one stream - the peer finished it, or the application above closed it. Connection-level health checks will show nothing, because nothing at that level happened.
- Why is reopening a bootstrapped socket cheaper than reopening an HTTP/1.1 one?It costs a new stream on a connection that already exists, so there is no transport setup and no security handshake to repeat. An HTTP/1.1 socket owned its connection, so reopening meant paying for a whole new connection before the handshake could even start.
- What is the risk of putting all of a device's traffic on one connection this way?Losing that connection loses everything at once - every socket riding it and every ordinary request in flight. The efficiency that makes the bootstrap attractive also concentrates the blast radius, so reconnection has to restore the whole set rather than one socket.
saying these in an interview costs you the question
- Says closing the socket closes the HTTP/2 connection.
- Assumes the connection dying is the only way a socket ends.
- Treats END_STREAM and a WebSocket close frame as the same thing.
- Thinks reopening a socket needs a new connection each time.
- Believes one socket blocks other requests on the connection.