Reading — step 1 of 5
Read
The Upgrade Handshake
A WebSocket connection begins life as a plain HTTP/1.1 GET request. This is deliberate: it lets WebSockets ride existing infrastructure — port 80/443, TLS termination, reverse proxies, cookies and auth headers — instead of fighting for a new port through every firewall on Earth.
Client request:
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13
Origin: http://example.com
Server response:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
After the 101, HTTP is over. The same TCP socket now carries WebSocket frames in both directions.
What Sec-WebSocket-Key really is
The client generates 16 random bytes and base64-encodes them — that's the 24-character Sec-WebSocket-Key. It is not a password and not secret. Its only job is to be unpredictable, so the server's answer proves something.
The server must respond with Sec-WebSocket-Accept, computed exactly as RFC 6455 §4.2.2 prescribes:
magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
accept = base64( SHA-1( key + magic ) )
In Python:
Why this dance exists
If the accept value is wrong, the browser refuses the connection. That protects against two things. First, protocol confusion: a generic HTTP server (or a cache replaying an old response) would never produce the right hash of a key it just received, so the client knows a real, WebSocket-aware endpoint processed this handshake. Second, it stops non-browser scripts from tricking a WS server into accepting a connection that was never a genuine WebSocket attempt. The magic GUID is hardcoded in the RFC precisely so nothing else on the internet would ever compute this value by accident.
Note the details that bite implementers:
- You hash the base64 string itself (the literal 24 characters), not the decoded 16 bytes.
- You base64 the raw 20-byte SHA-1 digest, not its 40-character hex spelling.
- SHA-1 is cryptographically broken for signatures — and that's fine here. Nothing secret is being protected; it's a fixed transform proving protocol awareness.
The RFC's own worked example: key dGhlIHNhbXBsZSBub25jZQ== must produce accept s3pPLMBiTxaQ9kYGzzhZRbK+xOo=.
Your exercise
Implement accept(key) per the formula. The two mistakes the grader catches: (1) using hashlib.sha1(...).hexdigest() and base64-encoding that — you'll print a 56-character string where the grader expects the 28-character s3pPLMBiTxaQ9kYGzzhZRbK+xOo= for the sample key; use .digest(). (2) base64-decoding the client key before hashing — concatenate the key as text with the magic GUID. Print one accept value per input line, nothing else.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…