curl/curl
WebSockets
Active contributors: Daniel Stenberg, Stefan Eissing
Purpose
curl supports the WebSocket protocol (RFC 6455) over ws:// and wss://. The implementation lives entirely in lib/ws.c (~62 KB) plus a small public API in include/curl/websockets.h. WebSockets graduated to "official" (no longer experimental) in November 2024.
Key abstractions
| Symbol | File | Description |
|---|---|---|
Curl_protocol_ws |
lib/ws.c |
Protocol handler for ws:// (and wss:// shares the same struct after upgrade) |
struct websocket |
lib/ws.h |
Per-handle WebSocket state: framing buffers, mask, fragment state |
Curl_ws_request() |
lib/ws.c |
Builds the HTTP Upgrade: websocket request |
Curl_ws_accept() |
lib/ws.c |
Validates the server's Sec-WebSocket-Accept reply |
Curl_ws_send / _recv |
lib/ws.c |
Frame send/recv used by the protocol handler |
curl_ws_send / curl_ws_recv |
include/curl/websockets.h |
Public API for application-side framed I/O |
curl_ws_meta() |
include/curl/websockets.h |
Per-frame metadata structure (flags, bytesleft) |
How it works
sequenceDiagram
participant App
participant Easy as easy.c
participant WS as Curl_protocol_ws
participant HTTP as http.c
App->>Easy: setopt URL=ws:// or wss://
Easy->>WS: do_it()
WS->>HTTP: send Upgrade: websocket request
HTTP-->>WS: 101 Switching Protocols
WS->>WS: validate Sec-WebSocket-Accept
WS-->>App: connection ready
loop messaging
App->>WS: curl_ws_send(...)
WS->>HTTP: framed bytes via Curl_conn_send
HTTP-->>WS: framed bytes via Curl_conn_recv
WS-->>App: curl_ws_recv(...)
endThe handshake is a regular HTTP request with Upgrade: websocket, Connection: Upgrade, and a base64-encoded random nonce. Once the server replies 101 Switching Protocols, the connection's role changes from "HTTP request/response" to "framed messaging". The cfilter chain underneath does not change — wss:// keeps the TLS filter but the bytes flowing through it are now WebSocket frames.
Frame structure
lib/ws.c implements RFC 6455 framing:
- 2-byte minimal header with FIN flag and 4-bit opcode
- Payload-length encoding (7-bit, 7+16-bit, 7+64-bit)
- 4-byte client-to-server mask
- Continuation, ping, pong, close opcodes
- Application messages may be split into multiple frames
The application sees logical messages via curl_ws_send / curl_ws_recv. Fragment metadata (FIN, partial size) is in the curl_ws_frame struct.
Two API styles
The public API supports two patterns:
- Push-style (
curl_easy_perform): the application receives bytes viaCURLOPT_WRITEFUNCTION, just like HTTP. Useful when the server only sends data. - Pull-style (
curl_ws_send/curl_ws_recv): requiresCURLOPT_CONNECT_ONLY = 2. The transfer is held open, and the application callscurl_ws_send/curl_ws_recvdirectly. This is the typical pattern.
Integration points
- HTTP handler: the upgrade handshake is a regular HTTP request, so
lib/http.chandles cookies, auth, and redirects up to the upgrade. - Connection filters:
wss://reuses the TLS filter; no WebSocket-specific cfilter is needed because framing is in the protocol handler, not the transport. - Connection cache: a WebSocket connection is single-use; once upgraded, it is not returned to the cache for reuse with other transfers.
Entry points for modification
- New extension support (e.g.
permessage-deflate) → would live inlib/ws.c. Note: not currently implemented. - New API helper →
include/curl/websockets.hpluslib/ws.c. Maintain ABI: only additive changes. - Frame parser fixes →
lib/ws.c::ws_handle_frame.
Related pages
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.