Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

ws

WebSocket is a layer, like tls, and the first one that changes what an endpoint carries. TLS takes a byte stream and gives back a byte stream; WebSocket takes one and gives back messages, so a ws: endpoint is a datagram endpoint sitting on a TCP transport.

That is what makes it interesting beyond parity: it is the first message oriented network transport tocat has, so frame, unframe and the other boundary preserving stages become useful over a network rather than only over unix sockets.

The four schemes

SchemeWhat it is
wsDial, plain. TCP with a ws layer
ws-listenAccept, plain
wssDial, encrypted. TCP with tls then ws over it
wss-listenAccept, encrypted
$ tocat - ws:echo.example.com:80/socket
$ tocat 'wss-listen:8443,fork,cert=cert.pem,keyfile=key.pem' tcp:localhost:9000

The address is host:port as everywhere else in tocat, not a URL: write wss:echo.example.com:443, not wss://echo.example.com. The port is always required, since no scheme here defaults one.

OptionDescription
path=PATHThe resource. ws:host:9000/socket is sugar for this. Default /
textSend text frames instead of binary. See below

wss and wss-listen also take every tls option, and all four take the socket options of the TCP transport underneath.

The path is part of the endpoint

The same value on both sides: asked for when dialling, required when accepting. Unset is / either way, so ws-listen:9000 serves / and answers a client asking for anything else with a 404 rather than upgrading it. The query string is the client’s business and is not compared.

A path is not authentication. It stops a misdirected client from being served, not a determined one.

Messages, not bytes

One message in is one message out. A ws: endpoint is under the same datagram rules as udp: and unix-seqpacket:: a stage that cannot carry boundaries is refused at build time rather than quietly joining your messages together.

A message larger than the copy buffer is an error. The other message endpoints truncate, because a datagram sender cannot know what the receiver will accept. A WebSocket peer believes it sent a whole message, so delivering part of one is worse than failing. Raise -b if you meet this.

Text and binary

Received text frames are passed through as their bytes; nothing is lost either way. What is sent is binary, unless you set text.

$ tocat - 'ws:api.example.com:80/socket,text'

A text frame promises the peer that its payload is valid UTF-8, and tocat cannot know whether the bytes crossing it are text. text is you making that promise. If a message turns out not to be valid UTF-8 the run fails rather than sending something the peer is entitled to reject.

What is not here yet

Subprotocol negotiation and Origin checking, both of which belong in the same place as the path check. Compression is not offered.