Prompt and context
A gateway and clients support HTTP/2, and a real-time service wants WebSocket streams multiplexed on one connection. Design an RFC 8441 migration: handshake, capability negotiation, proxy compatibility, stream versus connection closure, fallback, and acceptance metrics. This is a backend question about HTTP/2 extended-connect semantics.
What the interviewer evaluates
- Distinguish Extended CONNECT from HTTP/1.1 Upgrade.
- Use
:protocolandSETTINGS_ENABLE_CONNECT_PROTOCOLcorrectly. - Separate HTTP/2 stream closure from connection closure.
- Design fallback for unsupported proxies and clients.
- Measure handshake, stream errors, reuse, and latency.
Clarifying questions to ask
- Do the client, edge proxy, load balancer, gateway, and origin support RFC 8441?
- Can ordinary requests and WebSocket streams share one HTTP/2 connection?
- Does the load balancer preserve HTTP/2 end to end or terminate and rebuild it?
- Can old clients continue using HTTP/1.1 Upgrade?
- Is the client a browser, native SDK, or internal RPC implementation?
A 30-second answer
“I would verify SETTINGS_ENABLE_CONNECT_PROTOCOL at every hop. A capable client sends Extended CONNECT with :protocol = websocket; after success, that HTTP/2 stream carries WebSocket frames. An unsupported hop falls back to HTTP/1.1 Upgrade. Cancelling one stream must not close the whole connection. During canary, I would track handshake success, fallback, RST_STREAM, GOAWAY, reuse, and first-message latency.”
Deep-dive answer
Step 1: Negotiate extension support
Endpoints advertise Extended CONNECT through HTTP/2 SETTINGS. The client sends the :protocol pseudo-header only after receiving support; a proxy that strips the setting must trigger fallback rather than an invalid request.
SETTINGS_ENABLE_CONNECT_PROTOCOL = 1
:method = CONNECT
:protocol = websocket
:authority = chat.exampleThe snippet shows handshake fields; frame ordering still follows HTTP/2 and RFC 8441.
Step 2: Handle handshake and stream data
A successful Extended CONNECT creates an HTTP/2 stream carrying WebSocket frame semantics. It does not use HTTP/1.1 Connection, Upgrade, Sec-WebSocket-Key, or the 101 path. The server still authenticates, checks origin, and negotiates subprotocols and extensions.
Step 3: Separate lifecycles
RST_STREAM or normal stream closure affects one WebSocket, not other requests on the connection. GOAWAY prevents new streams; existing streams need a completion, migration, or reconnect policy. Reconnect logic must avoid replaying messages that were already acknowledged.
Step 4: Design proxy fallback
Build a capability matrix for clients, CDNs, load balancers, and gateways. If any hop lacks support, use HTTP/1.1 Upgrade or return a clear unsupported error; do not forward :protocol as an ordinary header. Preserve authentication, origin checks, subprotocols, and heartbeat behavior in both paths.
Step 5: Control flow and backpressure
HTTP/2 flow-control windows and the application queue both apply. Bound per-stream and per-connection buffers, observe window stalls, and ensure one slow stream cannot block ordinary requests sharing the connection.
Step 6: Canary and security checks
Start with internal clients and one region. Compare Extended CONNECT with HTTP/1.1 Upgrade for handshake success, first-message latency, reconnects, RST_STREAM, GOAWAY, and proxy errors. TLS, origin, authentication, subprotocol, and message-size limits remain unchanged.
Step 7: Define rollback and acceptance
Keep a client- or region-level switch to disable HTTP/2 WebSockets. Test missing SETTINGS, rejected protocols, stream cancellation, GOAWAY, network changes, and duplicate reconnects. Compare message ordering, p95 latency, connection count, and fallback ratio before expanding.
Model answer
“I would establish an end-to-end capability matrix and require SETTINGS_ENABLE_CONNECT_PROTOCOL at every hop. Supported clients send Extended CONNECT with :protocol = websocket; the successful HTTP/2 stream carries WebSocket frames, while unsupported paths use HTTP/1.1 Upgrade. Authentication, origin, subprotocol, heartbeat, and size limits stay the same.
RST_STREAM only affects one WebSocket; GOAWAY affects new streams and requires a completion or reconnect policy. The canary measures handshake, fallback, reconnects, first-message p95, reuse, and proxy errors, with injected missing SETTINGS, rejected protocols, slow streams, and network changes.”
Common mistakes
- Treating Extended CONNECT as a normal header → proxies may reject or misroute it → validate SETTINGS and pseudo-headers.
- Sending HTTP/1.1 Upgrade headers → HTTP/2 does not use that handshake → follow RFC 8441.
- Closing the connection on RST_STREAM → unrelated requests fail → separate stream and connection state.
- Ignoring GOAWAY → reconnect and completion become ambiguous → define lifecycle policy.
- Testing only direct connections → CDN and load-balancer differences break production → test every hop.
- Dropping authentication during migration → the extension does not change WebSocket security requirements → reuse the existing policy.
Follow-up questions and responses
Follow-up 1: Why not use HTTP/3 WebSockets directly?
RFC 9220 defines the HTTP/3 path. RFC 8441 is a practical step when the existing end-to-end path is HTTP/2; support and migration cost decide.
Follow-up 2: Can a client try Extended CONNECT without the setting?
No. Wait for the capability signal, then fall back or report unsupported rather than sending a protocol-invalid request.
Follow-up 3: How do you avoid duplicate messages after GOAWAY?
Use client sequence numbers or idempotency keys, persist acknowledged offsets, and resume from a defined point after reconnect.
Follow-up 4: How do you locate an incompatible proxy?
Capture SETTINGS, CONNECT responses, and error codes hop by hop, split by proxy, region, and client version.