websocket_sans_io

Struct WebsocketFrameEncoder

Source
pub struct WebsocketFrameEncoder { /* private fields */ }
Expand description

A low-level WebSocket frames decoder.

It lets to prepare frame headers and transform (mask) frame payloads when needed.

It does not validate that you supplied correct amount of payload bytes after headers or that headers make sense.

Example usage:

use std::io::Write;

use tungstenite::{protocol::Role, Message};
use websocket_sans_io::{FrameInfo, Opcode};

fn main() {
    let (tunstenite_end, mut sansio_end) = pipe::bipipe();
    std::thread::spawn(move || {
        let mut frame_encoder = websocket_sans_io::WebsocketFrameEncoder::new();
        let mut hello = *b"Hello, world\n";
        let header = frame_encoder.start_frame(&FrameInfo {
            opcode: Opcode::Text,
            payload_length: hello.len() as websocket_sans_io::PayloadLength,
            mask: Some(1234u32.to_be_bytes()),
            fin: true,
            reserved: 0,
        });
        sansio_end.write_all(&header[..]).unwrap();

        frame_encoder.transform_frame_payload(&mut hello[..]);
        sansio_end.write_all(&hello[..]).unwrap();
    });

    let mut tunstenite =
        tungstenite::protocol::WebSocket::from_raw_socket(tunstenite_end, Role::Server, None);
    let msg = tunstenite.read().unwrap();

    assert_eq!(msg, Message::Text("Hello, world\n".to_owned()));
}

Implementations§

Source§

impl WebsocketFrameEncoder

Source

pub const fn new() -> WebsocketFrameEncoder

Create new instance of WebsocketFrameEncoder

Source

pub fn start_frame(&mut self, frame_info: &FrameInfo) -> ArrayVec<[u8; 14]>

Serialize given frame header as bytes. You should write all those bytes to the socket before starting to write payload contant (if any).

You can repeat the calls to start_frame to re-serialize the header of the same frame if you haven’t yet called transform_frame_payload for that frame.

It does not validate the frame in any way and can allow you to do nonsensial things such as starting conversation with Continuation frame or getting next frame header when current frame’s payload is not completely written.

Use masked frames when you are client and unmasked frames when you are server.

Writing frame header with nonzero frame_info.payload_length means you are obligated to write this number of bytes before writing any new frame.

If you have large or unknown size of a WebSocket message, use frames with fin=false and crate::Opcode::Continuation frames with smaller payload lengths each. This also allows to interrupt the data transmissing to send a crate::Opcode::Ping or reply with a crate::Opcode::Pong.

Source

pub fn transform_frame_payload(&mut self, data: &mut [u8])

Prepare this memory chunk to be transfitted to the socket as a part of WebSocket frame payload.

Call this after start_frame.

Chunks transformed by this method should be written to the socket in the same order as they are supplied to transform_frame_payload.

If you do not want to transmit the tranformed chunk or some of its trailing part, you can rollback the encoder state with WebsocketFrameEncoder::rollback_payload_transform.

Source

pub fn rollback_payload_transform(&mut self, n_bytes: usize)

Undo transformation of this number of bytes.

Example:

use std::io::Write;

use tungstenite::{protocol::Role, Message};
use websocket_sans_io::{FrameInfo, Opcode};

fn main() {
    let (tunstenite_end, mut sansio_end) = pipe::bipipe();
    std::thread::spawn(move || {
        let mut frame_encoder = websocket_sans_io::WebsocketFrameEncoder::new();
        let mut hello = *b"Hello, world\n";
        let header = frame_encoder.start_frame(&FrameInfo {
            opcode: Opcode::Text,
            payload_length: hello.len() as websocket_sans_io::PayloadLength,
            mask: Some(1234567890u32.to_be_bytes()),
            fin: true,
            reserved: 0,
        });
        sansio_end.write_all(&header[..]).unwrap();

        frame_encoder.transform_frame_payload(&mut hello[..]);

        // Let's pretend we only can write 7 bytes here, then 
        // we need to forget the buffer and reconstruct it later.

        sansio_end.write_all(&hello[0..7]).unwrap();

        frame_encoder.rollback_payload_transform(hello.len() - 7);

        #[allow(dropping_copy_types)]
        drop(hello);

        // Now we returned and want to finish the writing.

        let mut hello_remembered = *b"Hello, world\n";
        let remaining_part = &mut hello_remembered[7..];

        frame_encoder.transform_frame_payload(remaining_part);
        sansio_end.write_all(&remaining_part[..]).unwrap();
    });

    let mut tunstenite =
        tungstenite::protocol::WebSocket::from_raw_socket(tunstenite_end, Role::Server, None);
    let msg = tunstenite.read().unwrap();

    assert_eq!(msg, Message::Text("Hello, world\n".to_owned()));
}
Source

pub const fn transform_needed(&self) -> bool

Check if you can skip transform_frame_payload and just transfer payload as is.

Trait Implementations§

Source§

impl Clone for WebsocketFrameEncoder

Source§

fn clone(&self) -> WebsocketFrameEncoder

Returns a copy of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for WebsocketFrameEncoder

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for WebsocketFrameEncoder

Source§

fn default() -> WebsocketFrameEncoder

Returns the “default value” for a type. Read more
Source§

impl PartialEq for WebsocketFrameEncoder

Source§

fn eq(&self, other: &WebsocketFrameEncoder) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl Copy for WebsocketFrameEncoder

Source§

impl Eq for WebsocketFrameEncoder

Source§

impl StructuralPartialEq for WebsocketFrameEncoder

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dst: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dst. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.