ws_framer/
lib.rs

1#![no_std]
2
3pub use crypto::process_sec_websocket_key;
4pub use framer::{WsRxFramer, WsTxFramer};
5pub use url::WsUrl;
6
7#[cfg(feature = "alloc")]
8pub use url::WsUrlOwned;
9
10#[cfg(feature = "alloc")]
11extern crate alloc;
12
13mod consts;
14mod crypto;
15mod framer;
16mod url;
17
18#[derive(Debug, Clone)]
19/// Websocket frame header
20pub struct WsFrameHeader {
21    pub fin: bool,
22    pub rsv1: bool,
23    pub rsv2: bool,
24    pub rsv3: bool,
25    pub opcode: u8,
26    pub mask: bool,
27    pub masking_key: [u8; 4],
28    pub payload_len: usize,
29    offset: usize,
30}
31
32#[allow(dead_code)]
33#[derive(Debug, Clone)]
34/// Websocket frame (packet)
35/// Stores reference to inner framer buffer
36pub enum WsFrame<'a> {
37    Text(&'a str),
38    Binary(&'a [u8]),
39    Close(u16, &'a str),
40    Ping(&'a [u8]),
41    Pong(&'a [u8]),
42    Unknown,
43}
44
45#[cfg(feature = "alloc")]
46#[allow(dead_code)]
47#[derive(Debug, Clone)]
48/// Websocket frame (packet)
49/// Owned version of WsFrame
50pub enum WsFrameOwned {
51    Text(alloc::string::String),
52    Binary(alloc::vec::Vec<u8>),
53    Close(u16, alloc::string::String),
54    Ping(alloc::vec::Vec<u8>),
55    Pong(alloc::vec::Vec<u8>),
56    Unknown,
57}
58
59impl<'a> WsFrame<'a> {
60    /// Return opcode for frame
61    pub fn opcode(&self) -> u8 {
62        match self {
63            WsFrame::Text(_) => 1,
64            WsFrame::Binary(_) => 2,
65            WsFrame::Close(..) => 8,
66            WsFrame::Ping(_) => 9,
67            WsFrame::Pong(_) => 10,
68            WsFrame::Unknown => 0,
69        }
70    }
71
72    /// Internal function to parse frame from header and buffer data
73    pub(crate) fn from_data(header: &WsFrameHeader, buf: &'a mut [u8]) -> Self {
74        if header.mask {
75            for (i, x) in buf.iter_mut().enumerate() {
76                let key = header.masking_key[i % 4];
77                *x ^= key;
78            }
79        }
80
81        match header.opcode {
82            1 => Self::Text(unsafe { core::str::from_utf8_unchecked(buf) }),
83            2 => Self::Binary(buf),
84            8 => Self::Close(u16::from_be_bytes([buf[0], buf[1]]), unsafe {
85                core::str::from_utf8_unchecked(&buf[2..])
86            }),
87            9 => Self::Ping(buf),
88            10 => Self::Pong(buf),
89            _ => Self::Unknown,
90        }
91    }
92
93    /// Helper to return data bytes from frame (if you dont care about frame type)
94    pub fn data(&self) -> &'a [u8] {
95        match self {
96            WsFrame::Text(str) => str.as_bytes(),
97            WsFrame::Binary(byt) => byt,
98            WsFrame::Close(_, reason) => reason.as_bytes(),
99            WsFrame::Ping(byt) => byt,
100            WsFrame::Pong(byt) => byt,
101            WsFrame::Unknown => &[],
102        }
103    }
104}
105
106#[cfg(feature = "alloc")]
107impl<'a> WsFrameOwned {
108    pub fn into_ref(&'a self) -> WsFrame<'a> {
109        match self {
110            WsFrameOwned::Text(string) => WsFrame::Text(&string),
111            WsFrameOwned::Binary(vec) => WsFrame::Binary(&vec),
112            WsFrameOwned::Close(code, reason) => WsFrame::Close(*code, &reason),
113            WsFrameOwned::Ping(vec) => WsFrame::Ping(&vec),
114            WsFrameOwned::Pong(vec) => WsFrame::Pong(&vec),
115            WsFrameOwned::Unknown => WsFrame::Unknown,
116        }
117    }
118}
119
120pub(crate) fn rng_fill(buf: &mut [u8]) {
121    #[cfg(feature = "getrandom02")]
122    {
123        _ = getrandom02::getrandom(buf);
124    }
125
126    #[cfg(feature = "getrandom03")]
127    {
128        _ = getrandom03::fill(buf);
129    }
130}