Open-Source Wikis

/

curl

/

Features

/

WebSockets

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(...)
    end

The 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:

  1. Push-style (curl_easy_perform): the application receives bytes via CURLOPT_WRITEFUNCTION, just like HTTP. Useful when the server only sends data.
  2. Pull-style (curl_ws_send/curl_ws_recv): requires CURLOPT_CONNECT_ONLY = 2. The transfer is held open, and the application calls curl_ws_send/curl_ws_recv directly. This is the typical pattern.

Integration points

  • HTTP handler: the upgrade handshake is a regular HTTP request, so lib/http.c handles 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 in lib/ws.c. Note: not currently implemented.
  • New API helper → include/curl/websockets.h plus lib/ws.c. Maintain ABI: only additive changes.
  • Frame parser fixes → lib/ws.c::ws_handle_frame.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

WebSockets – curl wiki | Factory