cheatah
Module

websocket

A from-scratch, low-latency WebSocket client (RFC 6455) over the cheatah tls 1.3 client and socket. wss:// only — the transport is always encrypted, like the rest of cheatah's network stack. No external libraries.

import io
import websocket

with websocket.open("echo.websocket.org", 443, "/", "echo.websocket.org") as ws {
    ws.send_text("hello")
    io.print(ws.recv())          # the echoed message
}                                # the connection (frame + TLS + socket) closes here

open_url("wss://host[:port]/path") is the convenience form. Both return an owning Client guard whose destructor sends a close frame and tears down the TLS session and socket — so, used with with, a connection cannot leak on any exit path.

Built for speed

The receive path is the hot path and is allocation-quiet:

  • one read buffer per session, reused across every frame — no per-frame heap;

  • server→client frames are unmasked by the protocol (§5.1), so recv does zero unmasking work — it slices the payload straight out of the buffer;

  • frame headers are parsed in place (no header object is built);

  • the TLS layer is drained in 64 KiB chunks, so many frames decode per read.

The send path masks (clients MUST, §5.3) with a 64-bit-word XOR (8 bytes per step) and a CSPRNG key from os.urandom; sends are rare (subscribe/control), off the hot path. Control frames are handled transparently — a ping is answered with a pong, a close ends the stream — none of which the caller sees.

API

The cheatah-facing API is the owning Client guard from open/open_url:

Call

What

open(host, port, path, server_name)

TCP + TLS 1.3 + the RFC 6455 upgrade; returns a Client guard

open_url(url)

same, from a wss://… URL

ws.send_text(msg)

send one masked text frame

ws.recv()

the next application message (reassembled; control frames handled); "" on close

ws.close()

send a close frame and tear down (the destructor does this too)

The flat, session-id handle API (connect/connect_url/send_text/recv/close, keyed by an integer that must be closed by hand to free its heap Session) is C++-only — it lives in websocket_lowlevel.hpp and is not reachable from cheatah, so a cheatah program cannot leak the session.

A client is single-owner — don't recv and send_text the same client from two threads at once; separate clients are independent.

Security

recv() treats every server frame as hostile: it enforces RFC 6455 framing before trusting a length — per-frame (64 MiB) and reassembled-message (64 MiB) size caps (so a huge or header + len-overflowing length cannot drive an out-of-bounds unmask or exhaust memory), control frames ≤125 bytes and never fragmented, reserved-bit / undefined-opcode rejection, and a validated fragmentation state machine. A malformed or oversized frame fails the connection instead of corrupting memory.

wss:// authenticates the server by default: the underlying tls client validates the certificate chain to a trusted CA, matches the hostname, and checks expiry — so a wss:// connection resists an active MITM. For a pinned/controlled peer, open/open_url take an insecure flag (skip validation) and a ca_file (trust a specific PEM CA) — see the tls README.

Built on tls (TLS 1.3, now verifying Ed25519 and ECDSA P-256 server certificates), socket, and os (urandom).

Classes

Functions

fn Client open(const std::string &host, long long port, const std::string &path, const std::string &server_name, bool insecure=false, const std::string &ca_file="", bool secure=true) source#

Open a secure WebSocket connection and return it as an owning Client (the RAII, with-friendly form of connect()).

The TLS server is AUTHENTICATED by default.

Parameters
host

the server host, e.g. "echo.websocket.org".

port

the TLS port, normally 443.

path

the request path, e.g. "/".

server_name

the TLS SNI / Host (usually == host); matched against the certificate SAN.

insecure

skip certificate validation (pinned/controlled peer only). Default false.

ca_file

a PEM CA bundle to trust instead of the system store (empty = system default).

secure

whether to run the connection over TLS. Default TRUE; false selects a PLAINTEXT WebSocket and is refused unless host is loopback.

Returns

an owning Client.

Parameters
std::runtime_error

on connect/TLS/validation/upgrade failure. TLS IS THE DEFAULT AND STAYS THE DEFAULT. secure = false selects a PLAINTEXT WebSocket, and connect() then refuses any host that is not loopback (127.0.0.1, ::1, localhost). It exists for a local control plane — Chrome's DevTools endpoint speaks ws:// on loopback and offers no TLS at all — so cleartext here can never reach the network. Every existing caller is unchanged: omit the parameter and you get TLS.

Warning

insecure = true drops the MITM protection: ANY peer that holds its own certificate's key is accepted. Pinned/controlled peers only.

Complexity

one TCP + one TLS handshake + one HTTP round trip.

Allocation

the session.

Concurrency

blocks for the TCP/TLS/upgrade round trips.

fn Client open_url(const std::string &url, bool insecure=false, const std::string &ca_file="") source#

Open a secure WebSocket connection from a wss://host[:port]/path URL and return it as an owning Client (the RAII, with-friendly form of connect_url()).

Server AUTHENTICATED by default.

Parameters
url

the wss URL.

insecure

skip certificate validation (pinned/controlled peer only). Default false.

ca_file

a PEM CA bundle to trust instead of the system store (empty = system default).

Returns

an owning Client.

Parameters
std::runtime_error

on a non-wss scheme or a connect/validation failure.

Warning

insecure = true drops the MITM protection (see open()).

Complexity

as open().

Allocation

the session.

Concurrency

blocks for the TCP/TLS/upgrade round trips.