NAME

Unblock::WebSocket - event-loop and platform neutral WebSocket protocol engine

SYNOPSIS

Use the Handshake helper to establish WebSocket over HTTP, then use Client or Server for messages. The example below assumes the HTTP handshake has already succeeded:

use Unblock::WebSocket::Server;

my $ws = Unblock::WebSocket::Server->new(
    on_message => sub {
        my ($ws, $message, $type) = @_;
        $ws->send_text("echo:$message");
    },
);

# Received WebSocket bytes, not HTTP bytes:
$ws->input($bytes);

# Manual output mode:
while ($ws->want_write) {
    $host->write($ws->output);
}

Or attach a host that implements the three transport methods:

my $ws = Unblock::WebSocket::Server->new(
    transport => $host,
    on_message => sub {
        my ($ws, $message, $type) = @_;
        $ws->send_text($message);
    },
);

In attached mode output is passed to the host automatically. See the runnable examples/handshake-memory.pl and examples/memory-attached.pl programs in the distribution.

DESCRIPTION

Unblock::WebSocket provides WebSocket protocol handling without owning sockets, TLS, DNS, timers, or an event loop.

Use Unblock::WebSocket::Handshake for the opening HTTP handshake.

Use Unblock::WebSocket::Client or Unblock::WebSocket::Server after the WebSocket stream has been established.

The opening HTTP handshake is separate from established WebSocket traffic. The caller carries Uniform::HTTP request and response objects using its own HTTP implementation, then passes only WebSocket bytes to Client or Server.

The distribution supports:

  • RFC 6455 framing, masking, fragmentation, Ping/Pong, Close, and UTF-8

  • HTTP/1.1 Upgrade handshakes

  • HTTP/2 and HTTP/3 Extended CONNECT handshakes

  • RFC 7692 permessage-deflate

  • a portable Perl protocol backend

  • a private native backend for faster framing and masking

The public protocol API remains bytes in and bytes out. Applications do not need to work with WebSocket frame objects. Output can be drained manually or handed to an optional attached transport automatically.

INSTALLATION

Install with cpanm Unblock::WebSocket. The distribution requires Perl 5.16 or newer and builds an XS extension, so a C compiler is needed for installation from source.

NATIVE BACKEND

native_available() reports whether the XS backend loaded.

When available, normal established connections use the native backend unless a portable-only option requires otherwise. This is an implementation detail; the public Client and Server APIs are the same.

ESTABLISHED CONNECTION API

Unblock::WebSocket::Client and Unblock::WebSocket::Server share the same established-connection API.

Common constructor options include:

max_message_size

Maximum decompressed application message size. The default is 16 MiB.

high_water

Output high-water mark. The default is 65536 bytes.

low_water

Output low-water mark. The default is 32768 bytes.

permessage_deflate

Negotiated RFC 7692 parameters. Normally this comes from "connection_options" in Unblock::WebSocket::Handshake.

transport

Optional host transport object implementing unblock_send($bytes), unblock_finish() and unblock_abort($reason). The host owns the socket, TLS, event loop and its ordered output queue. An attached engine holds a weak reference to the host. Without this option, the engine uses manual output.

backend

native or perl. Normal applications should let the module choose automatically. This option is mainly useful for differential testing and debugging.

Callbacks are supplied to the constructor:

on_message
on_message => sub {
    my ($ws, $payload, $type) = @_;
}

$type is text or binary.

on_ping

Called for received Ping payloads. The protocol engine also sends the required Pong automatically.

on_pong

Called for received Pong payloads.

on_close
on_close => sub {
    my ($ws, $code, $reason) = @_;
}

Called when a Close frame is received. A transport EOF without a Close frame reports an undefined code and transport EOF as the reason.

on_error

Called for protocol or callback errors.

on_drain

Called when a producer that saw a false send return can resume. In attached mode, this also waits for host congestion to clear via resume_output(). This is not a socket writable callback.

Common methods include:

input($bytes)

Feed bytes received from the ordered transport.

input_eof()

Report transport EOF.

output([$maximum])

Remove and return generated transport bytes in manual mode. An optional positive maximum limits the returned chunk size. Calling this with an attached transport is an error.

resume_output()

With an attached transport, clear a congestion indication after the host can accept more bytes. The host must call this after its unblock_send() returned false. Calling it in manual mode is an error.

transport_error($reason)

Report a broken transport or TLS connection. Aborts immediately, discards unaccepted protocol output and, in attached mode, calls unblock_abort(). This is distinct from a peer WebSocket Close frame.

want_write()

True while generated output is waiting to be drained.

want_read()

True while the protocol engine can still accept transport input.

output_size()

Number of generated bytes currently buffered.

send_text($text)

Queue one text message.

send_binary($bytes)

Queue one binary message.

ping([$payload])

Queue a Ping control frame. Payloads are limited to 125 bytes.

close(%options)

Begin a normal WebSocket Close handshake. code defaults to 1000 and reason is optional.

abort()

Stop the protocol engine immediately and discard buffered output.

is_open(), is_closing(), is_closed()

Inspect connection state.

close_sent(), close_received(), close_complete()

Inspect the Close handshake.

want_end()

True when the transport may be ended after pending output is drained.

backend()

Returns native or perl.

permessage_deflate()

Returns the negotiated compression parameters, or undef.

send_text(), send_binary(), and ping() accept their bytes even when the output high-water mark is reached. A false return means the producer should pause until on_drain runs. In attached mode, false may also mean that the host accepted an entire buffer but reported congestion. Host send methods must accept all bytes or throw, and must drain their own write queues before a graceful unblock_finish() shuts the connection.

close() queues a WebSocket Close frame; it does not immediately terminate the transport. The peer Close response, outstanding output and any host congestion are handled before graceful finish. Unexpected EOF or a transport error aborts an attached host. See docs/INTEGRATION.md in the repository.

LICENSE

MIT License.