

# [`std::websocket`](/silk/docs/std/websocket/)

[`std::websocket`](/silk/docs/std/websocket/) provides an RFC 6455
WebSocket implementation on top of [`std::net::TCPStream`](/silk/docs/std/networking/) (client + server
handshake, framing, ping/pong, close, fragmentation).

See also:

- [networking](/silk/docs/std/networking/) ([`std::net`](/silk/docs/std/networking/) sockets)
- RFC 6455: The WebSocket Protocol (wire format + handshake)

## Overview

[`std::websocket`](/silk/docs/std/websocket/) is a protocol layer that upgrades an HTTP/1.1 connection to a
WebSocket and then sends/receives WebSocket frames.

Design goals:

- Work for hosted POSIX builds using [`std::net`](/silk/docs/std/networking/).
- Be fully interoperable with other WebSocket implementations (browsers,
 Node.js, etc.) for the supported feature set:
 - version 13 handshake,
 - masked client→server frames,
 - unmasked server→client frames,
 - fragmentation and continuation frames,
 - ping/pong, close.
- Provide a small, blocking server that accepts one connection at a time.

Non-goals (for now):

- HTTP server integration beyond the upgrade handshake (no HTTP routing layer).
- TLS (`wss://`) integration (use [`std::tls`](/silk/docs/std/tls/) + a future adapter layer).
- Per-message compression (RSV1 / `permessage-deflate`).

## Exported API

```silk
module std::websocket;

import std::net;
import std::arrays;
import std::result;
import std::strings;

// Message opcodes (subset).
export let OPCODE_TEXT: int = 1;
export let OPCODE_BINARY: int = 2;

// Handshake errors.
export let ERR_HANDSHAKE_IO: int = 1;
export let ERR_HANDSHAKE_TOO_LARGE: int = 2;
export let ERR_HANDSHAKE_BAD_REQUEST: int = 3;
export let ERR_HANDSHAKE_MISSING_KEY: int = 4;
export let ERR_HANDSHAKE_BAD_VERSION: int = 5;
export let ERR_HANDSHAKE_BAD_ACCEPT: int = 6;
export let ERR_HANDSHAKE_OUT_OF_MEMORY: int = 7;

export error HandshakeError {
  kind: int,
}

export type WebSocketResult = std::result::Result(WebSocket, HandshakeError);
export type WebSocketServerResult = std::result::Result(WebSocketServer, HandshakeError);

// Protocol/runtime errors during frame processing.
export let ERR_PROTOCOL_IO: int = 1;
export let ERR_PROTOCOL_CLOSED: int = 2;
export let ERR_PROTOCOL_BAD_FRAME: int = 3;
export let ERR_PROTOCOL_TOO_LARGE: int = 4;
export let ERR_PROTOCOL_OUT_OF_MEMORY: int = 5;

export error ProtocolError {
  kind: int,
}

export type MessageResult = std::result::Result(Message, ProtocolError);

struct Message {
  opcode: int,              // OPCODE_TEXT or OPCODE_BINARY
  data: std::strings::String, // owned bytes (UTF-8 for text)
}

struct WebSocket {
  // opaque handle
}

impl WebSocket {
  // Server-side: perform the HTTP upgrade handshake on an accepted TCP stream.
  public fn accept (stream: std::net::TCPStream) -> WebSocketResult;

  // Client-side: connect and perform the HTTP upgrade handshake.
  public fn connect (addr: SocketAddrV4, host: string, path: string) -> WebSocketResult;

  public fn is_valid (self: &WebSocket) -> bool;
  public fn close (mut self: &WebSocket) -> ProtocolError?;

  // Read the next complete application message (text or binary).
  // Ping frames are answered automatically and do not surface as messages.
  public fn read_message (mut self: &WebSocket) -> MessageResult;

  // Send a single unfragmented message.
  public fn write_text (self: &WebSocket, text: string) -> ProtocolError?;
  public fn write_bytes (self: &WebSocket, bytes: std::arrays::ByteSlice) -> ProtocolError?;
}

struct WebSocketServer {
  // opaque handle
}

impl WebSocketServer {
  public fn listen (addr: SocketAddrV4, backlog: int) -> WebSocketServerResult;
  public fn is_valid (self: &WebSocketServer) -> bool;
  public fn local_port (self: &WebSocketServer) -> std::net::NetIntResult;
  public fn accept (mut self: &WebSocketServer) -> WebSocketResult;
  public fn close (mut self: &WebSocketServer) -> HandshakeError?;
}
```

Notes:

- This API is currently **blocking**.
- `accept` consumes its `TCPStream`, and a successful `WebSocket` owns that
 stream until `close` or `Drop` invalidates it.
- Handshake computation and writes borrow the stream retained inside the
 `WebSocket`; they do not create a second owning stream handle. Consequently,
 every handshake error path can close the original owner exactly once.
- `WebSocket` and `WebSocketServer` are ownership-tracked handles. Moving one
 transfers its wrapped OS resources, and copying an owning handle is rejected.

## Protocol Rules Enforced

The implementation enforces the following RFC 6455 requirements:

- Client→server frames **must** be masked; server→client frames **must not** be masked.
- Reserved bits (RSV1/2/3) must be zero (compression/extensions are not supported).
- Control frames (ping/pong/close):
 - are not allowed to be fragmented (`FIN = 1`),
 - must have payload length ≤ 125.
- Close frames trigger an attempted close reply and then the connection is
 treated as closed from the API’s perspective.
