Module lightws::stream

source ·
Expand description

Websocket stream.

Stream is a simple wrapper of the underlying IO source, with small stack buffers to save states.

It is transparent to call Read or Write on Stream:

{
    // establish connection, handshake
    let stream = ...
    // read some data
    stream.read(&mut buf)?;
    // write some data
    stream.write(&buf)?;
}

A new established Stream is in Direct (default) mode, where a Read or Write leads to at most one syscall, and an Ok(0) will be returned if frame head is not completely read or written. It can be converted to Guarded mode with Stream::guard, which wraps Read or Write in a loop, where Ok(0) is handled internally.

Stream itself does not buffer any payload data during a Read or Write, so there is no extra heap allocation.

Masking payload

Data read from stream are automatically unmasked. However, data written to stream are NOT automatically masked, since a Write call requires an immutable &[u8].

A standard client(e.g. StandardClient) should mask the payload before sending it; A non-standard client (e.g. Client) which holds an empty mask key can simply skip this step.

The mask key is prepared by ClientRole, which can be set or fetched via Stream::set_mask_key and Stream::mask_key.

Example:

use std::io::{Read, Write};
use std::net::TcpStream;
use lightws::role::StandardClient;
use lightws::endpoint::Endpoint;
use lightws::frame::{new_mask_key, apply_mask4};
fn write_data() -> std::io::Result<()> {  
    let mut buf = [0u8; 256];
    let mut tcp = TcpStream::connect("example.com:80")?;
    let mut ws = Endpoint::<TcpStream, StandardClient>::connect(tcp, &mut buf, "example.com", "/ws")?;

    // mask data
    let key = new_mask_key();
    apply_mask4(key, &mut buf);

    // set mask key for next write
    ws.set_mask_key(key)?;

    // write some data
    ws.write_all(&buf)?;
    Ok(())
}

Automatic masking

It is annoying to mask the payload each time before a write, and it will block us from using convenient functions like std::io::copy.

With unsafe_auto_mask_write fearure enabled, the provided immutable &[u8] will be casted to a mutable &mut [u8] then payload data can be automatically masked.

This feature only has effects on AutoMaskClientRole, where its inner mask key may be updated (depends on AutoMaskClientRole::UPDATE_MASK_KEY) and used to mask the payload before each write. Other ClientRole and ServerRole are not affected. Related code lies in src/stream/detail/write#L118.

Structs