skip to content

What must a WebSocket client do when a 101 response arrives whose Sec-WebSocket-Accept does not match the key it sent?

level: seniorimportance: should knowfreq 48%

answer

  1. a promise with a sharp edge
  2. validate before believing the status line
  3. absent and mismatched are treated alike
  4. unchecked bytes reach the frame parser
  5. no socket yet, so no close frame

basics

~20 s

It must fail the WebSocket connection: stop, close the underlying connection, and never read the following bytes as protocol data. A wrong or absent digest means whatever answered did not perform this handshake for this connection.

solid answer

~50 s

RFC 6455 makes this a **MUST**: if `Sec-WebSocket-Accept` is absent, or present with a value other than the digest the client computes from the key it sent, the client fails the WebSocket connection — it stops, tears down the underlying connection and reports failure. The same applies when the response omits `Upgrade: websocket` or a `Connection` field containing `Upgrade`, or names a subprotocol or extension the client never offered. The reason is that a 101 is a promise that **everything after the blank line is no longer HTTP**. A client that skips the check hands whatever bytes follow — an error page, a stale cached body, silence — to its frame parser, and the result is a socket that appears open and then behaves inexplicably. There is no close frame to send here, because no socket was ever established.

code

http · 4 lines
http
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: bm90IHRoZSBkaWdlc3QgeW91IHdhbnQ=

go deeper

for a junior

Remember that a 101 alone is not proof of success: the client compares the returned accept digest against the key it sent before treating the connection as a socket.

for a middle

Explain the mechanism behind the requirement - the 101 ends HTTP on that connection, so an unvalidated one feeds whatever follows to a frame parser instead of raising a clean error.

for a senior

Show the diagnosis: read the actual status line first, then the digest, and know that a 200 with a body and a 101 with a wrong digest are different findings with different owners.

for a principal

The judgment call is where strictness belongs: clients that fail loudly on a malformed handshake surface routing faults early, at the cost of being unforgiving of endpoints that half-implement the protocol.

## The rule The client validates the handshake response before it believes a word of it. If any of the following holds, it **fails the WebSocket connection**: - the status is not `101 Switching Protocols`; - the response has no `Upgrade` field, or its value is not `websocket` (matched case-insensitively); - the response has no `Connection` field containing the token `Upgrade`; - `Sec-WebSocket-Accept` is **absent**, or present with a value other than the digest computed from the key this client sent; - the response names a subprotocol or an extension the client never offered (what those names then mean is a separate subject). "Fail the WebSocket connection" at this stage means exactly one thing: close the underlying TCP connection and report the failure upward. There is no close frame to send, because a close frame is part of the protocol the two sides never started speaking. ## Why the rule is not pedantry A `101` is a promise with a sharp edge: after the blank line ending that header block, **the connection is no longer HTTP** and nothing will re-frame it. A client that accepts a 101 without validating hands the next bytes straight to its frame parser. Three concrete outcomes follow, and all three are miserable to diagnose: 1. **The parser reads an HTTP body as frames.** An error page or any ordinary body is interpreted as opcodes and lengths, producing either an immediate protocol error or, worse, a plausible-looking "message" of garbage. 2. **The client waits forever.** If the peer sends nothing more, the application shows a socket in an open state with no traffic, and the fault surfaces much later as a silent feature rather than a connection error. 3. **A stale response is accepted as a live socket.** Because the digest binds the answer to *this connection's* fresh random key, a response produced for some earlier exchange fails the comparison. Without the check, it does not. The cost of getting this wrong is paid by the wrong team: the symptom appears as corrupt application messages, not as a failed connection. ## When the status is not 101 at all A non-101 response is **an ordinary HTTP response and is handled by ordinary HTTP rules first**. It has a status line, usually a body, and it means the protocol switch did not happen. | Response | What it means here | What the client does | |---|---|---| | `200 OK` with a body | Something answered without switching protocols | No socket exists; the body is an HTTP body | | A redirect status | The target moved | Handled per HTTP; a client may or may not follow it | | A status demanding authentication | The endpoint wants credentials first | Handled per HTTP; credentials are a separate subject | | `426 Upgrade Required` | The protocol version was refused | A version refusal, answered differently | | `101` with a bad or missing digest | Something claimed a switch it cannot perform | **Fail the WebSocket connection** | The one line to keep straight is that a non-101 is not automatically a WebSocket failure the instant it arrives — the client may act on it as HTTP — but no socket exists unless and until a validated 101 arrives. ## Diagnosing it on the wire When a client reports "the connection failed" and the application team suspects the socket layer, look at the actual response bytes and ask two questions in order: - **What is the status line?** A `200` with a body means the request was answered by something that ignored the upgrade fields entirely, so the problem is upstream of the protocol. - **If it is a 101, does the digest match the key that was sent?** A mismatch is a far narrower finding: something answered that did not compute the digest from this request's key. That points at a responder that is not the endpoint you addressed, or at an answer that was not produced for this exchange. The distinction matters because the two findings have completely different owners, and a client that swallows the mismatch destroys the evidence for both. ## What a strong answer sounds like State the requirement as a requirement ("the client MUST fail the connection"), name what "fail" means at this stage (tear down the underlying connection; no close frame exists yet), and then give the mechanism for *why*: the 101 is the last HTTP byte, so an unvalidated 101 turns a wrong answer into corrupt protocol data rather than a clean error.

  • What if the 101 arrives with no Sec-WebSocket-Accept field at all?
    Same outcome: absent and mismatched are treated identically, and the client fails the WebSocket connection. A 101 without the digest is a peer claiming a protocol switch it has given no evidence of being able to perform.
  • Does 'fail the WebSocket connection' mean sending a close with a status code?
    Not at this point. Close frames belong to a socket that exists, and here none ever did, so the client simply tears down the underlying connection and reports the failure. Close semantics apply only after a validated 101.
  • Should a client retry immediately when the digest does not match?
    No. A mismatch is a deterministic fault in what answered, not a transient one, so an immediate retry loop reproduces the same response while hiding the evidence. Report it, and treat repeated occurrences as a routing or endpoint problem.

saying these in an interview costs you the question

  • Treats any 101 as success without comparing the accept value
  • Retries the same upgrade in a tight loop when the digest mismatches
  • Starts reading the response body as WebSocket data after a 200 OK
  • Thinks a bad digest makes the socket insecure rather than nonexistent
  • Expects a close frame to report a handshake that never completed
  • Assumes any non-101 status is automatically a transport error