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    pub fn create_response_frame_list(body: &ResponseBody) -> Vec<ResponseBody> {
70        let total_len: usize = body.len();
71        let mut offset: usize = 0;
72        let mut frames_list: Vec<ResponseBody> = Vec::new();
73        let mut is_first_frame: bool = true;
74        let is_valid_utf8: bool = std::str::from_utf8(body).is_ok();
75        let base_opcode: u8 = if is_valid_utf8 { 0x01 } else { 0x02 };
76        while offset < total_len {
77            let remaining: usize = total_len - offset;
78            let mut frame_size: usize = remaining.min(MAX_FRAME_SIZE);
79            if is_valid_utf8 && frame_size < remaining {
80                while frame_size > 0 && (body[offset + frame_size] & 0xC0) == 0x80 {
81                    frame_size -= 1;
82                }
83                if frame_size == 0 {
84                    frame_size = remaining.min(MAX_FRAME_SIZE);
85                }
86            }
87            let mut frame: ResponseBody = Vec::with_capacity(frame_size + 10);
88            let opcode: u8 = if is_first_frame { base_opcode } else { 0x00 };
89            let fin_bit: u8 = if remaining > frame_size { 0x00 } else { 0x80 };
90            frame.push(fin_bit | opcode);
91            if frame_size < 126 {
92                frame.push(frame_size as u8);
93            } else if frame_size <= MAX_FRAME_SIZE {
94                frame.push(126);
95                frame.extend_from_slice(&(frame_size as u16).to_be_bytes());
96            } else {
97                frame.push(127);
98                frame.extend_from_slice(&(frame_size as u64).to_be_bytes());
99            }
100            frame.extend_from_slice(&body[offset..offset + frame_size]);
101            frames_list.push(frame);
102            offset += frame_size;
103            is_first_frame = false;
104        }
105        frames_list
106    }
107
108    /// sha1
109    ///
110    /// - `data`: A byte slice containing the input data to be hashed.
111    /// - Returns: A 20-byte array representing the SHA-1 hash of the input data.
112    pub fn sha1(data: &[u8]) -> [u8; 20] {
113        let mut hash_state: [u32; 5] = HASH_STATE;
114        let mut padded_data: Vec<u8> = Vec::from(data);
115        let original_length_bits: u64 = (padded_data.len() * 8) as u64;
116        padded_data.push(0x80);
117        while (padded_data.len() + 8) % 64 != 0 {
118            padded_data.push(0);
119        }
120        padded_data.extend_from_slice(&original_length_bits.to_be_bytes());
121        for block in padded_data.chunks_exact(64) {
122            let mut message_schedule: [u32; 80] = [0u32; 80];
123            for (i, block_chunk) in block.chunks_exact(4).enumerate().take(16) {
124                message_schedule[i] = u32::from_be_bytes([
125                    block_chunk[0],
126                    block_chunk[1],
127                    block_chunk[2],
128                    block_chunk[3],
129                ]);
130            }
131            for i in 16..80 {
132                message_schedule[i] = (message_schedule[i - 3]
133                    ^ message_schedule[i - 8]
134                    ^ message_schedule[i - 14]
135                    ^ message_schedule[i - 16])
136                    .rotate_left(1);
137            }
138            let [mut a, mut b, mut c, mut d, mut e] = hash_state;
139            for (i, &word) in message_schedule.iter().enumerate() {
140                let (f, k) = match i {
141                    0..=19 => ((b & c) | (!b & d), 0x5A827999),
142                    20..=39 => (b ^ c ^ d, 0x6ED9EBA1),
143                    40..=59 => ((b & c) | (b & d) | (c & d), 0x8F1BBCDC),
144                    _ => (b ^ c ^ d, 0xCA62C1D6),
145                };
146                let temp: u32 = a
147                    .rotate_left(5)
148                    .wrapping_add(f)
149                    .wrapping_add(e)
150                    .wrapping_add(k)
151                    .wrapping_add(word);
152                e = d;
153                d = c;
154                c = b.rotate_left(30);
155                b = a;
156                a = temp;
157            }
158            hash_state[0] = hash_state[0].wrapping_add(a);
159            hash_state[1] = hash_state[1].wrapping_add(b);
160            hash_state[2] = hash_state[2].wrapping_add(c);
161            hash_state[3] = hash_state[3].wrapping_add(d);
162            hash_state[4] = hash_state[4].wrapping_add(e);
163        }
164        let mut result: [u8; 20] = [0u8; 20];
165        for (i, &val) in hash_state.iter().enumerate() {
166            result[i * 4..(i + 1) * 4].copy_from_slice(&val.to_be_bytes());
167        }
168        result
169    }
170
171    /// generate_accept_key
172    ///
173    /// - `key`: A string slice containing the client-provided key.
174    /// - Returns: A string representing the generated WebSocket accept key.
175    pub fn generate_accept_key(key: &str) -> String {
176        let mut data: [u8; 60] = [0u8; 60];
177        data[..24].copy_from_slice(&key.as_bytes()[..24.min(key.len())]);
178        data[24..].copy_from_slice(GUID);
179        let hash: [u8; 20] = Self::sha1(&data);
180        Self::base64_encode(&hash)
181    }
182
183    /// base64_encode
184    ///
185    /// - `data`: A byte slice containing the data to encode in base64.
186    /// - Returns: A string with the base64 encoded representation of the input data.
187    pub fn base64_encode(data: &[u8]) -> String {
188        let mut encoded_data: Vec<u8> = Vec::with_capacity((data.len() + 2) / 3 * 4);
189        for chunk in data.chunks(3) {
190            let mut buffer: [u8; 3] = [0u8; 3];
191            buffer[..chunk.len()].copy_from_slice(chunk);
192            let indices: [u8; 4] = [
193                buffer[0] >> 2,
194                ((buffer[0] & 0b11) << 4) | (buffer[1] >> 4),
195                ((buffer[1] & 0b1111) << 2) | (buffer[2] >> 6),
196                buffer[2] & 0b111111,
197            ];
198            for &idx in &indices[..chunk.len() + 1] {
199                encoded_data.push(BASE64_CHARSET_TABLE[idx as usize]);
200            }
201            while encoded_data.len() % 4 != 0 {
202                encoded_data.push(EQUAL_BYTES[0]);
203            }
204        }
205        String::from_utf8(encoded_data).unwrap()
206    }
207}