Networking

Networking

import std::sockets;

Covers TCP, HTTP and HTTPS, server-sent events, file downloads, WebSocket clients, and TCP, HTTP, and WebSocket servers.

Making a request

Request is a builder, and each method returns it so calls chain:

let response: sockets::HttpResponse? = new sockets::Request()
    .method("POST")
    .path("/api/thing")
    .header("Content-Type", "application/json")
    .body(payload)
    .send_http(host, 443)

if !response.is_value() {
    return None
}
let body: string = response.unwrap().body()

send_http returns a parsed HttpResponse with status_code(), body(), and header_value(name). send returns a plain Response. Both give None on a transport failure. The default port is 443 with TLS and 80 without.

A Request with no method is sent as a raw TCP payload; with a method it is serialized as HTTP/1.1 with Host, Content-Length, Connection: close, and a user agent filled in.

Streaming

stream and stream_sse take callbacks for the headers and each chunk or event, returning false from either to stop. open_stream gives a RequestWriter for a request body written incrementally; a writer dropped without finish() or abort() leaks its socket.

WebSocket client

let connected: sockets::WsClient? = sockets::ws_connect(url)
if connected.is_value() {
    let client: sockets::WsClient = connected.unwrap()
    client.send(`{"t":"hello"}`)
    let incoming: string? = client.recv()
    client.close()
}

recv() blocks until a message arrives or the connection closes, returning None for the latter.

Servers

Socket handles raw TCP, HttpSocket adds exact-URI routing, and WebSocket serves WebSocket connections.

let server: sockets::WebSocket = new sockets::WebSocket()
server.set_callback(closure(connection: sockets::WsConnection,
                           request: sockets::Request) => void {
    connection.send("ack")
})
server.listen()

listen() runs on a new thread; listen_attached() blocks the caller. A port of zero binds an ephemeral one, readable with get_port() afterwards. stop() sets a flag, so the loop exits on its next pass rather than immediately.

Two things to be explicit about

The TLS layer encrypts but does not authenticate the server. There is no certificate verification. Treat it as protection against passive observation, not against an active attacker.

Three functions signal failure with a magic string. send_request, send_request_tls, and send_raw return a string that begins with Error: when the exchange failed. The Request methods wrap this and return optionals, which is the better surface.