http_type/websocket_frame/
impl.rs

1use crate::*;
2
3impl WebSocketFrame {
4    /// decode_websocket_frame_with_length
5    ///
6    /// # Parameters
7    /// - `data`: The raw data slice from the WebSocket stream.
8    ///
9    /// # Returns
10    /// - An Option containing a tuple (WebSocketFrame, usize), where the WebSocketFrame is the decoded frame and usize is the number of bytes consumed.
11    ///   Returns None if the frame is incomplete.
12    #[inline]
13    pub fn decode_websocket_frame_with_length(data: &[u8]) -> WebsocketFrameWithLengthOption {
14        if data.len() < 2 {
15            return None;
16        }
17        let mut index: usize = 0;
18        let fin: bool = (data[index] & 0b1000_0000) != 0;
19        let opcode: u8 = data[index] & 0b0000_1111;
20        index += 1;
21        let mask: bool = (data[index] & 0b1000_0000) != 0;
22        let mut payload_len: usize = (data[index] & 0b0111_1111) as usize;
23        index += 1;
24        if payload_len == 126 {
25            if data.len() < index + 2 {
26                return None;
27            }
28            payload_len = u16::from_be_bytes(data[index..index + 2].try_into().ok()?) as usize;
29            index += 2;
30        } else if payload_len == 127 {
31            if data.len() < index + 8 {
32                return None;
33            }
34            payload_len = u64::from_be_bytes(data[index..index + 8].try_into().ok()?) as usize;
35            index += 8;
36        }
37        let mask_key: Option<[u8; 4]> = if mask {
38            if data.len() < index + 4 {
39                return None;
40            }
41            let key: [u8; 4] = data[index..index + 4].try_into().ok()?;
42            index += 4;
43            Some(key)
44        } else {
45            None
46        };
47        if data.len() < index + payload_len {
48            return None;
49        }
50        let mut payload: Vec<u8> = data[index..index + payload_len].to_vec();
51        if let Some(mask_key) = mask_key {
52            for (i, byte) in payload.iter_mut().enumerate() {
53                *byte ^= mask_key[i % 4];
54            }
55        }
56        index += payload_len;
57        let frame: WebSocketFrame = WebSocketFrame {
58            fin,
59            opcode,
60            mask,
61            payload_data: payload,
62        };
63        Some((frame, index))
64    }
65
66    /// create_response_frame_list
67    ///
68    /// - `body`: A reference to a response body (payload) as a byte slice.
69    /// - Returns: A vector of response bodies (frames) representing the framed data.
70    #[inline]
71    pub fn create_response_frame_list(body: &ResponseBody) -> Vec<ResponseBody> {
72        let total_len: usize = body.len();
73        let mut offset: usize = 0;
74        let mut frames_list: Vec<ResponseBody> = Vec::new();
75        let mut is_first_frame: bool = true;
76        let is_valid_utf8: bool = std::str::from_utf8(body).is_ok();
77        let base_opcode: u8 = if is_valid_utf8 { 0x01 } else { 0x02 };
78        while offset < total_len {
79            let remaining: usize = total_len - offset;
80            let mut frame_size: usize = remaining.min(MAX_FRAME_SIZE);
81            if is_valid_utf8 && frame_size < remaining {
82                while frame_size > 0 && (body[offset + frame_size] & 0xC0) == 0x80 {
83                    frame_size -= 1;
84                }
85                if frame_size == 0 {
86                    frame_size = remaining.min(MAX_FRAME_SIZE);
87                }
88            }
89            let mut frame: ResponseBody = Vec::with_capacity(frame_size + 10);
90            let opcode: u8 = if is_first_frame { base_opcode } else { 0x00 };
91            let fin_bit: u8 = if remaining > frame_size { 0x00 } else { 0x80 };
92            frame.push(fin_bit | opcode);
93            if frame_size < 126 {
94                frame.push(frame_size as u8);
95            } else if frame_size <= MAX_FRAME_SIZE {
96                frame.push(126);
97                frame.extend_from_slice(&(frame_size as u16).to_be_bytes());
98            } else {
99                frame.push(127);
100                frame.extend_from_slice(&(frame_size as u64).to_be_bytes());
101            }
102            frame.extend_from_slice(&body[offset..offset + frame_size]);
103            frames_list.push(frame);
104            offset += frame_size;
105            is_first_frame = false;
106        }
107        frames_list
108    }
109
110    /// sha1
111    ///
112    /// - `data`: A byte slice containing the input data to be hashed.
113    /// - Returns: A 20-byte array representing the SHA-1 hash of the input data.
114    #[inline]
115    pub fn sha1(data: &[u8]) -> [u8; 20] {
116        let mut hash_state: [u32; 5] = HASH_STATE;
117        let mut padded_data: Vec<u8> = Vec::from(data);
118        let original_length_bits: u64 = (padded_data.len() * 8) as u64;
119        padded_data.push(0x80);
120        while (padded_data.len() + 8) % 64 != 0 {
121            padded_data.push(0);
122        }
123        padded_data.extend_from_slice(&original_length_bits.to_be_bytes());
124        for block in padded_data.chunks_exact(64) {
125            let mut message_schedule: [u32; 80] = [0u32; 80];
126            for (i, block_chunk) in block.chunks_exact(4).enumerate().take(16) {
127                message_schedule[i] = u32::from_be_bytes([
128                    block_chunk[0],
129                    block_chunk[1],
130                    block_chunk[2],
131                    block_chunk[3],
132                ]);
133            }
134            for i in 16..80 {
135                message_schedule[i] = (message_schedule[i - 3]
136                    ^ message_schedule[i - 8]
137                    ^ message_schedule[i - 14]
138                    ^ message_schedule[i - 16])
139                    .rotate_left(1);
140            }
141            let [mut a, mut b, mut c, mut d, mut e] = hash_state;
142            for (i, &word) in message_schedule.iter().enumerate() {
143                let (f, k) = match i {
144                    0..=19 => ((b & c) | (!b & d), 0x5A827999),
145                    20..=39 => (b ^ c ^ d, 0x6ED9EBA1),
146                    40..=59 => ((b & c) | (b & d) | (c & d), 0x8F1BBCDC),
147                    _ => (b ^ c ^ d, 0xCA62C1D6),
148                };
149                let temp: u32 = a
150                    .rotate_left(5)
151                    .wrapping_add(f)
152                    .wrapping_add(e)
153                    .wrapping_add(k)
154                    .wrapping_add(word);
155                e = d;
156                d = c;
157                c = b.rotate_left(30);
158                b = a;
159                a = temp;
160            }
161            hash_state[0] = hash_state[0].wrapping_add(a);
162            hash_state[1] = hash_state[1].wrapping_add(b);
163            hash_state[2] = hash_state[2].wrapping_add(c);
164            hash_state[3] = hash_state[3].wrapping_add(d);
165            hash_state[4] = hash_state[4].wrapping_add(e);
166        }
167        let mut result: [u8; 20] = [0u8; 20];
168        for (i, &val) in hash_state.iter().enumerate() {
169            result[i * 4..(i + 1) * 4].copy_from_slice(&val.to_be_bytes());
170        }
171        result
172    }
173
174    /// generate_accept_key
175    ///
176    /// - `key`: A string slice containing the client-provided key.
177    /// - Returns: A string representing the generated WebSocket accept key.
178    #[inline]
179    pub fn generate_accept_key(key: &str) -> String {
180        let mut data: [u8; 60] = [0u8; 60];
181        data[..24].copy_from_slice(&key.as_bytes()[..24.min(key.len())]);
182        data[24..].copy_from_slice(GUID);
183        let hash: [u8; 20] = Self::sha1(&data);
184        Self::base64_encode(&hash)
185    }
186
187    /// base64_encode
188    ///
189    /// - `data`: A byte slice containing the data to encode in base64.
190    /// - Returns: A string with the base64 encoded representation of the input data.
191    #[inline]
192    pub fn base64_encode(data: &[u8]) -> String {
193        let mut encoded_data: Vec<u8> = Vec::with_capacity((data.len() + 2) / 3 * 4);
194        for chunk in data.chunks(3) {
195            let mut buffer: [u8; 3] = [0u8; 3];
196            buffer[..chunk.len()].copy_from_slice(chunk);
197            let indices: [u8; 4] = [
198                buffer[0] >> 2,
199                ((buffer[0] & 0b11) << 4) | (buffer[1] >> 4),
200                ((buffer[1] & 0b1111) << 2) | (buffer[2] >> 6),
201                buffer[2] & 0b111111,
202            ];
203            for &idx in &indices[..chunk.len() + 1] {
204                encoded_data.push(BASE64_CHARSET_TABLE[idx as usize]);
205            }
206            while encoded_data.len() % 4 != 0 {
207                encoded_data.push(EQUAL_BYTES[0]);
208            }
209        }
210        String::from_utf8(encoded_data).unwrap()
211    }
212}