http_type/websocket_frame/
impl.rs1use crate::*;
2
3impl Default for WebSocketFrame {
4 fn default() -> Self {
5 Self {
6 fin: false,
7 opcode: WebSocketOpcode::Text,
8 mask: false,
9 payload_data: Vec::new(),
10 }
11 }
12}
13
14impl WebSocketOpcode {
15 pub fn from_u8(opcode: u8) -> Self {
23 match opcode {
24 0x0 => Self::Continuation,
25 0x1 => Self::Text,
26 0x2 => Self::Binary,
27 0x8 => Self::Close,
28 0x9 => Self::Ping,
29 0xA => Self::Pong,
30 _ => Self::Reserved(opcode),
31 }
32 }
33
34 pub fn to_u8(&self) -> u8 {
42 match self {
43 Self::Continuation => 0x0,
44 Self::Text => 0x1,
45 Self::Binary => 0x2,
46 Self::Close => 0x8,
47 Self::Ping => 0x9,
48 Self::Pong => 0xA,
49 Self::Reserved(code) => *code,
50 }
51 }
52
53 pub fn is_control(&self) -> bool {
61 matches!(self, Self::Close | Self::Ping | Self::Pong)
62 }
63
64 pub fn is_data(&self) -> bool {
72 matches!(self, Self::Text | Self::Binary | Self::Continuation)
73 }
74
75 pub fn is_continuation(&self) -> bool {
83 matches!(self, Self::Continuation)
84 }
85
86 pub fn is_text(&self) -> bool {
94 matches!(self, Self::Text)
95 }
96
97 pub fn is_binary(&self) -> bool {
105 matches!(self, Self::Binary)
106 }
107
108 pub fn is_close(&self) -> bool {
116 matches!(self, Self::Close)
117 }
118
119 pub fn is_ping(&self) -> bool {
127 matches!(self, Self::Ping)
128 }
129
130 pub fn is_pong(&self) -> bool {
138 matches!(self, Self::Pong)
139 }
140
141 pub fn is_reserved(&self) -> bool {
149 matches!(self, Self::Reserved(_))
150 }
151}
152
153impl WebSocketFrame {
154 pub fn decode_ws_frame(data: &[u8]) -> WebsocketFrameWithLengthOption {
162 if data.len() < 2 {
163 return None;
164 }
165 let mut index: usize = 0;
166 let fin: bool = (data[index] & 0b1000_0000) != 0;
167 let opcode: WebSocketOpcode = WebSocketOpcode::from_u8(data[index] & 0b0000_1111);
168 index += 1;
169 let mask: bool = (data[index] & 0b1000_0000) != 0;
170 let mut payload_len: usize = (data[index] & 0b0111_1111) as usize;
171 index += 1;
172 if payload_len == 126 {
173 if data.len() < index + 2 {
174 return None;
175 }
176 payload_len = u16::from_be_bytes(data[index..index + 2].try_into().ok()?) as usize;
177 index += 2;
178 } else if payload_len == 127 {
179 if data.len() < index + 8 {
180 return None;
181 }
182 payload_len = u64::from_be_bytes(data[index..index + 8].try_into().ok()?) as usize;
183 index += 8;
184 }
185 let mask_key: Option<[u8; 4]> = if mask {
186 if data.len() < index + 4 {
187 return None;
188 }
189 let key: [u8; 4] = data[index..index + 4].try_into().ok()?;
190 index += 4;
191 Some(key)
192 } else {
193 None
194 };
195 if data.len() < index + payload_len {
196 return None;
197 }
198 let mut payload: Vec<u8> = data[index..index + payload_len].to_vec();
199 if let Some(mask_key) = mask_key {
200 for (i, byte) in payload.iter_mut().enumerate() {
201 *byte ^= mask_key[i % 4];
202 }
203 }
204 index += payload_len;
205 let frame: WebSocketFrame = WebSocketFrame {
206 fin,
207 opcode,
208 mask,
209 payload_data: payload,
210 };
211 Some((frame, index))
212 }
213
214 pub fn create_response_frame_list(body: &ResponseBody) -> Vec<ResponseBody> {
222 let total_len: usize = body.len();
223 let mut offset: usize = 0;
224 let mut frames_list: Vec<ResponseBody> =
225 Vec::with_capacity((total_len / MAX_FRAME_SIZE) + 1);
226 let mut is_first_frame: bool = true;
227 let is_valid_utf8: bool = std::str::from_utf8(body).is_ok();
228 let base_opcode: WebSocketOpcode = if is_valid_utf8 {
229 WebSocketOpcode::Text
230 } else {
231 WebSocketOpcode::Binary
232 };
233 while offset < total_len {
234 let remaining: usize = total_len - offset;
235 let mut frame_size: usize = remaining.min(MAX_FRAME_SIZE);
236 if is_valid_utf8 && frame_size < remaining {
237 while frame_size > 0 && (body[offset + frame_size] & 0xC0) == 0x80 {
238 frame_size -= 1;
239 }
240 if frame_size == 0 {
241 frame_size = remaining.min(MAX_FRAME_SIZE);
242 }
243 }
244 let mut frame: ResponseBody = Vec::with_capacity(frame_size + 10);
245 let opcode: WebSocketOpcode = if is_first_frame {
246 base_opcode
247 } else {
248 WebSocketOpcode::Continuation
249 };
250 let fin: u8 = if remaining > frame_size { 0x00 } else { 0x80 };
251 let opcode_byte: u8 = opcode.to_u8() & 0x0F;
252 frame.push(fin | opcode_byte);
253 if frame_size < 126 {
254 frame.push(frame_size as u8);
255 } else if frame_size <= MAX_FRAME_SIZE {
256 frame.push(126);
257 frame.extend_from_slice(&(frame_size as u16).to_be_bytes());
258 } else {
259 frame.push(127);
260 frame.extend_from_slice(&(frame_size as u16).to_be_bytes());
261 }
262 let end: usize = offset + frame_size;
263 frame.extend_from_slice(&body[offset..end]);
264 frames_list.push(frame);
265 offset = end;
266 is_first_frame = false;
267 }
268 frames_list
269 }
270
271 pub fn sha1(data: &[u8]) -> [u8; 20] {
279 let mut hash_state: [u32; 5] = HASH_STATE;
280 let mut padded_data: Vec<u8> = Vec::from(data);
281 let original_length_bits: u64 = (padded_data.len() * 8) as u64;
282 padded_data.push(0x80);
283 while (padded_data.len() + 8) % 64 != 0 {
284 padded_data.push(0);
285 }
286 padded_data.extend_from_slice(&original_length_bits.to_be_bytes());
287 for block in padded_data.chunks_exact(64) {
288 let mut message_schedule: [u32; 80] = [0u32; 80];
289 for (i, block_chunk) in block.chunks_exact(4).enumerate().take(16) {
290 message_schedule[i] = u32::from_be_bytes([
291 block_chunk[0],
292 block_chunk[1],
293 block_chunk[2],
294 block_chunk[3],
295 ]);
296 }
297 for i in 16..80 {
298 message_schedule[i] = (message_schedule[i - 3]
299 ^ message_schedule[i - 8]
300 ^ message_schedule[i - 14]
301 ^ message_schedule[i - 16])
302 .rotate_left(1);
303 }
304 let [mut a, mut b, mut c, mut d, mut e] = hash_state;
305 for (i, &word) in message_schedule.iter().enumerate() {
306 let (f, k) = match i {
307 0..=19 => ((b & c) | (!b & d), 0x5A827999),
308 20..=39 => (b ^ c ^ d, 0x6ED9EBA1),
309 40..=59 => ((b & c) | (b & d) | (c & d), 0x8F1BBCDC),
310 _ => (b ^ c ^ d, 0xCA62C1D6),
311 };
312 let temp: u32 = a
313 .rotate_left(5)
314 .wrapping_add(f)
315 .wrapping_add(e)
316 .wrapping_add(k)
317 .wrapping_add(word);
318 e = d;
319 d = c;
320 c = b.rotate_left(30);
321 b = a;
322 a = temp;
323 }
324 hash_state[0] = hash_state[0].wrapping_add(a);
325 hash_state[1] = hash_state[1].wrapping_add(b);
326 hash_state[2] = hash_state[2].wrapping_add(c);
327 hash_state[3] = hash_state[3].wrapping_add(d);
328 hash_state[4] = hash_state[4].wrapping_add(e);
329 }
330 let mut result: [u8; 20] = [0u8; 20];
331 for (i, &val) in hash_state.iter().enumerate() {
332 result[i * 4..(i + 1) * 4].copy_from_slice(&val.to_be_bytes());
333 }
334 result
335 }
336
337 pub fn generate_accept_key(key: &str) -> String {
345 let mut data: [u8; 60] = [0u8; 60];
346 data[..24].copy_from_slice(&key.as_bytes()[..24.min(key.len())]);
347 data[24..].copy_from_slice(GUID);
348 let hash: [u8; 20] = Self::sha1(&data);
349 Self::base64_encode(&hash)
350 }
351
352 pub fn base64_encode(data: &[u8]) -> String {
360 let mut encoded_data: Vec<u8> = Vec::with_capacity((data.len() + 2) / 3 * 4);
361 for chunk in data.chunks(3) {
362 let mut buffer: [u8; 3] = [0u8; 3];
363 buffer[..chunk.len()].copy_from_slice(chunk);
364 let indices: [u8; 4] = [
365 buffer[0] >> 2,
366 ((buffer[0] & 0b11) << 4) | (buffer[1] >> 4),
367 ((buffer[1] & 0b1111) << 2) | (buffer[2] >> 6),
368 buffer[2] & 0b111111,
369 ];
370 for &idx in &indices[..chunk.len() + 1] {
371 encoded_data.push(BASE64_CHARSET_TABLE[idx as usize]);
372 }
373 while encoded_data.len() % 4 != 0 {
374 encoded_data.push(EQUAL_BYTES[0]);
375 }
376 }
377 String::from_utf8(encoded_data).unwrap()
378 }
379
380 pub fn is_continuation_opcode(&self) -> bool {
388 self.opcode.is_continuation()
389 }
390
391 pub fn is_text_opcode(&self) -> bool {
399 self.opcode.is_text()
400 }
401
402 pub fn is_binary_opcode(&self) -> bool {
410 self.opcode.is_binary()
411 }
412
413 pub fn is_close_opcode(&self) -> bool {
421 self.opcode.is_close()
422 }
423
424 pub fn is_ping_opcode(&self) -> bool {
432 self.opcode.is_ping()
433 }
434
435 pub fn is_pong_opcode(&self) -> bool {
443 self.opcode.is_pong()
444 }
445
446 pub fn is_reserved_opcode(&self) -> bool {
454 self.opcode.is_reserved()
455 }
456}