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