DoxigAlpha

readSmallMessage

Reads the next message from the WebSocket stream, failing if the message does not fit into the input buffer. The returned memory points into the input buffer and is invalidated on the next read.

Function parameters

Parameters

#
ws:*WebSocket

Type definitions in this namespace

Types

#
WebSocket
See https://tools.ietf.org/html/rfc6455

Initialize an HTTP server that can respond to multiple requests on the same

Functions

#
init
Initialize an HTTP server that can respond to multiple requests on the same

Error sets in this namespace

Error Sets

#

Source

Implementation

#
pub fn readSmallMessage(ws: *WebSocket) ReadSmallTextMessageError!SmallMessage {
    const in = ws.input;
    while (true) {
        const header = try in.takeArray(2);
        const h0: Header0 = @bitCast(header[0]);
        const h1: Header1 = @bitCast(header[1]);

        switch (h0.opcode) {
            .text, .binary, .pong, .ping => {},
            .connection_close => return error.ConnectionClose,
            .continuation => return error.UnexpectedOpCode,
            _ => return error.UnexpectedOpCode,
        }

        if (!h0.fin) return error.MessageTooBig;
        if (!h1.mask) return error.MissingMaskBit;

        const len: usize = switch (h1.payload_len) {
            .len16 => try in.takeInt(u16, .big),
            .len64 => std.math.cast(usize, try in.takeInt(u64, .big)) orelse return error.MessageTooBig,
            else => @intFromEnum(h1.payload_len),
        };
        if (len > in.buffer.len) return error.MessageTooBig;
        const mask: u32 = @bitCast((try in.takeArray(4)).*);
        const payload = try in.take(len);

        // Skip pongs.
        if (h0.opcode == .pong) continue;

        // The last item may contain a partial word of unused data.
        const floored_len = (payload.len / 4) * 4;
        const u32_payload: []align(1) u32 = @ptrCast(payload[0..floored_len]);
        for (u32_payload) |*elem| elem.* ^= mask;
        const mask_bytes: []const u8 = @ptrCast(&mask);
        for (payload[floored_len..], mask_bytes[0 .. payload.len - floored_len]) |*leftover, m|
            leftover.* ^= m;

        return .{
            .opcode = h0.opcode,
            .data = payload,
        };
    }
}