1use std::{cmp::min, io, str};
2
3use bytes::{Buf, BufMut, BytesMut};
4
5use super::{
6 mask::apply_mask,
7 proto::{CloseCode, CloseReason, OpCode},
8 ProtocolError,
9};
10
11#[derive(Debug)]
13pub struct Parser;
14
15const FIN_MASK: u8 = 0x80;
17
18const RSV_MASK: u8 = 0b0111_0000;
20
21const OPCODE_MASK: u8 = 0x0F;
23
24const MASK_BIT: u8 = 0x80;
26
27const PAYLOAD_LEN_MASK: u8 = 0x7F;
29
30const EXT_LEN_U16: u8 = 126;
32
33const EXT_LEN_U64: u8 = 127;
35
36const MAX_CONTROL_FRAME_PAYLOAD: usize = 125;
38
39const U16_PAYLOAD_MAX: usize = u16::MAX as usize;
41
42const MASK_LEN: usize = 4;
44
45impl Parser {
46 fn parse_metadata(
47 src: &[u8],
48 server: bool,
49 ) -> Result<Option<(usize, bool, OpCode, usize, Option<[u8; 4]>)>, ProtocolError> {
50 let chunk_len = src.len();
51
52 let mut idx = 2;
53 if chunk_len < 2 {
54 return Ok(None);
55 }
56
57 let first = src[0];
58 let second = src[1];
59 let finished = first & FIN_MASK != 0;
60
61 if first & RSV_MASK != 0 {
63 return Err(ProtocolError::Io(io::Error::new(
65 io::ErrorKind::InvalidData,
66 "Received a frame with non-zero reserved bits",
67 )));
68 }
69
70 let masked = second & MASK_BIT != 0;
72 if !masked && server {
73 return Err(ProtocolError::UnmaskedFrame);
74 } else if masked && !server {
75 return Err(ProtocolError::MaskedFrame);
76 }
77
78 let opcode = OpCode::from(first & OPCODE_MASK);
80
81 if let OpCode::Bad = opcode {
82 return Err(ProtocolError::InvalidOpcode(first & OPCODE_MASK));
83 }
84
85 let len = second & PAYLOAD_LEN_MASK;
86 let length = if len == EXT_LEN_U16 {
87 if chunk_len < 4 {
88 return Ok(None);
89 }
90 let len = usize::from(u16::from_be_bytes(
91 TryFrom::try_from(&src[idx..idx + 2]).unwrap(),
92 ));
93 idx += 2;
94 len
95 } else if len == EXT_LEN_U64 {
96 if chunk_len < 10 {
97 return Ok(None);
98 }
99 let len = u64::from_be_bytes(TryFrom::try_from(&src[idx..idx + 8]).unwrap());
100 idx += 8;
101 len as usize
102 } else {
103 len as usize
104 };
105
106 let mask = if server {
107 if chunk_len < idx + MASK_LEN {
108 return Ok(None);
109 }
110
111 let mask = TryFrom::try_from(&src[idx..idx + MASK_LEN]).unwrap();
112
113 idx += MASK_LEN;
114
115 Some(mask)
116 } else {
117 None
118 };
119
120 Ok(Some((idx, finished, opcode, length, mask)))
121 }
122
123 pub fn parse(
125 src: &mut BytesMut,
126 server: bool,
127 max_size: usize,
128 ) -> Result<Option<(bool, OpCode, Option<BytesMut>)>, ProtocolError> {
129 let (idx, finished, opcode, length, mask) = match Parser::parse_metadata(src, server)? {
131 None => return Ok(None),
132 Some(res) => res,
133 };
134
135 let frame_len = match idx.checked_add(length) {
136 Some(len) => len,
137 None => return Err(ProtocolError::Overflow),
138 };
139
140 if src.len() < frame_len {
142 let min_length = min(length, max_size);
143 let required_cap = match idx.checked_add(min_length) {
144 Some(cap) => cap,
145 None => return Err(ProtocolError::Overflow),
146 };
147
148 if src.capacity() < required_cap {
149 src.reserve(required_cap - src.capacity());
150 }
151 return Ok(None);
152 }
153
154 src.advance(idx);
156
157 if length > max_size {
159 src.advance(length);
161 return Err(ProtocolError::Overflow);
162 }
163
164 if length == 0 {
166 return Ok(Some((finished, opcode, None)));
167 }
168
169 let mut data = src.split_to(length);
170
171 match opcode {
173 OpCode::Ping | OpCode::Pong | OpCode::Close if length > MAX_CONTROL_FRAME_PAYLOAD => {
174 return Err(ProtocolError::InvalidLength(length));
175 }
176 _ => {}
177 }
178
179 if let Some(mask) = mask {
181 apply_mask(&mut data, mask);
182 }
183
184 Ok(Some((finished, opcode, Some(data))))
185 }
186
187 #[deprecated(
193 since = "3.13.5",
194 note = "Use `Parser::try_parse_close_payload` instead."
195 )]
196 pub fn parse_close_payload(payload: &[u8]) -> Option<CloseReason> {
197 if payload.len() >= 2 {
198 let raw_code = u16::from_be_bytes(TryFrom::try_from(&payload[..2]).unwrap());
199 let code = CloseCode::from(raw_code);
200 let description = if payload.len() > 2 {
201 Some(String::from_utf8_lossy(&payload[2..]).into())
202 } else {
203 None
204 };
205 Some(CloseReason { code, description })
206 } else {
207 None
208 }
209 }
210
211 pub fn try_parse_close_payload(payload: &[u8]) -> Result<Option<CloseReason>, ProtocolError> {
223 if payload.len() == 1 {
225 return Err(ProtocolError::InvalidLength(payload.len()));
226 }
227
228 if payload.len() >= 2 {
229 let raw_code = u16::from_be_bytes(
230 payload[..2]
231 .try_into()
232 .expect("Payload length should be checked before parsing"),
233 );
234
235 if !matches!(raw_code, 1000..=1003 | 1007..=1014 | 3000..=4999) {
239 return Err(ProtocolError::BadOpCode);
242 }
243
244 if payload.len() > 2 {
245 str::from_utf8(&payload[2..]).map_err(|_| {
248 ProtocolError::BadOpCode
251 })?;
252 }
253 }
254
255 #[expect(deprecated)]
256 Ok(Self::parse_close_payload(payload))
257 }
258
259 pub fn write_message<B: AsRef<[u8]>>(
261 dst: &mut BytesMut,
262 pl: B,
263 op: OpCode,
264 fin: bool,
265 mask: bool,
266 ) {
267 let payload = pl.as_ref();
268 let one = if fin {
269 FIN_MASK | u8::from(op)
270 } else {
271 u8::from(op)
272 };
273 let payload_len = payload.len();
274 let (two, p_len) = if mask {
275 (MASK_BIT, payload_len + MASK_LEN)
276 } else {
277 (0, payload_len)
278 };
279
280 if payload_len < EXT_LEN_U16 as usize {
281 dst.reserve(p_len + 2);
282 dst.put_slice(&[one, two | payload_len as u8]);
283 } else if payload_len <= U16_PAYLOAD_MAX {
284 dst.reserve(p_len + 4);
285 dst.put_slice(&[one, two | EXT_LEN_U16]);
286 dst.put_u16(payload_len as u16);
287 } else {
288 dst.reserve(p_len + 10);
289 dst.put_slice(&[one, two | EXT_LEN_U64]);
290 dst.put_u64(payload_len as u64);
291 };
292
293 if mask {
294 let mask = rand::random::<[u8; 4]>();
295 dst.put_slice(mask.as_ref());
296 dst.put_slice(payload.as_ref());
297 let pos = dst.len() - payload_len;
298 apply_mask(&mut dst[pos..], mask);
299 } else {
300 dst.put_slice(payload.as_ref());
301 }
302 }
303
304 #[inline]
306 pub fn write_close(dst: &mut BytesMut, reason: Option<CloseReason>, mask: bool) {
307 let payload = match reason {
308 None => Vec::new(),
309 Some(reason) => {
310 let mut payload = Into::<u16>::into(reason.code).to_be_bytes().to_vec();
311 if let Some(description) = reason.description {
312 payload.extend(description.as_bytes());
313 }
314 payload
315 }
316 };
317
318 Parser::write_message(dst, payload, OpCode::Close, true, mask)
319 }
320}
321
322#[cfg(test)]
323mod tests {
324 use bytes::Bytes;
325
326 use super::*;
327
328 struct F {
329 finished: bool,
330 opcode: OpCode,
331 payload: Bytes,
332 }
333
334 fn is_none(frm: &Result<Option<(bool, OpCode, Option<BytesMut>)>, ProtocolError>) -> bool {
335 matches!(*frm, Ok(None))
336 }
337
338 fn extract(frm: Result<Option<(bool, OpCode, Option<BytesMut>)>, ProtocolError>) -> F {
339 match frm {
340 Ok(Some((finished, opcode, payload))) => F {
341 finished,
342 opcode,
343 payload: payload
344 .map(|b| b.freeze())
345 .unwrap_or_else(|| Bytes::from("")),
346 },
347 _ => unreachable!("error"),
348 }
349 }
350
351 #[test]
352 fn test_parse() {
353 let mut buf = BytesMut::from(&[0b0000_0001u8, 0b0000_0001u8][..]);
354 assert!(is_none(&Parser::parse(&mut buf, false, 1024)));
355
356 let mut buf = BytesMut::from(&[0b0000_0001u8, 0b0000_0001u8][..]);
357 buf.extend(b"1");
358
359 let frame = extract(Parser::parse(&mut buf, false, 1024));
360 assert!(!frame.finished);
361 assert_eq!(frame.opcode, OpCode::Text);
362 assert_eq!(frame.payload.as_ref(), &b"1"[..]);
363 }
364
365 #[test]
366 fn test_parse_length0() {
367 let mut buf = BytesMut::from(&[0b0000_0001u8, 0b0000_0000u8][..]);
368 let frame = extract(Parser::parse(&mut buf, false, 1024));
369 assert!(!frame.finished);
370 assert_eq!(frame.opcode, OpCode::Text);
371 assert!(frame.payload.is_empty());
372 }
373
374 #[test]
375 fn test_parse_length2() {
376 let mut buf = BytesMut::from(&[0b0000_0001u8, 126u8][..]);
377 assert!(is_none(&Parser::parse(&mut buf, false, 1024)));
378
379 let mut buf = BytesMut::from(&[0b0000_0001u8, 126u8][..]);
380 buf.extend(&[0u8, 4u8][..]);
381 buf.extend(b"1234");
382
383 let frame = extract(Parser::parse(&mut buf, false, 1024));
384 assert!(!frame.finished);
385 assert_eq!(frame.opcode, OpCode::Text);
386 assert_eq!(frame.payload.as_ref(), &b"1234"[..]);
387 }
388
389 #[test]
390 fn test_parse_length4() {
391 let mut buf = BytesMut::from(&[0b0000_0001u8, 127u8][..]);
392 assert!(is_none(&Parser::parse(&mut buf, false, 1024)));
393
394 let mut buf = BytesMut::from(&[0b0000_0001u8, 127u8][..]);
395 buf.extend(&[0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 4u8][..]);
396 buf.extend(b"1234");
397
398 let frame = extract(Parser::parse(&mut buf, false, 1024));
399 assert!(!frame.finished);
400 assert_eq!(frame.opcode, OpCode::Text);
401 assert_eq!(frame.payload.as_ref(), &b"1234"[..]);
402 }
403
404 #[test]
405 fn test_parse_frame_mask() {
406 let mut buf = BytesMut::from(&[0b0000_0001u8, 0b1000_0001u8][..]);
407 buf.extend(b"0001");
408 buf.extend(b"1");
409
410 assert!(Parser::parse(&mut buf, false, 1024).is_err());
411
412 let frame = extract(Parser::parse(&mut buf, true, 1024));
413 assert!(!frame.finished);
414 assert_eq!(frame.opcode, OpCode::Text);
415 assert_eq!(frame.payload, Bytes::from(vec![1u8]));
416 }
417
418 #[test]
419 fn test_parse_frame_no_mask() {
420 let mut buf = BytesMut::from(&[0b0000_0001u8, 0b0000_0001u8][..]);
421 buf.extend([1u8]);
422
423 assert!(Parser::parse(&mut buf, true, 1024).is_err());
424
425 let frame = extract(Parser::parse(&mut buf, false, 1024));
426 assert!(!frame.finished);
427 assert_eq!(frame.opcode, OpCode::Text);
428 assert_eq!(frame.payload, Bytes::from(vec![1u8]));
429 }
430
431 #[test]
432 fn test_parse_frame_with_rsv1_set() {
433 let mut buf = BytesMut::from(
437 &[
438 0b1100_0001u8, 0b1000_0001u8, 0, 0, 0, 0, b'a', ][..],
446 );
447
448 Parser::parse(&mut buf, true, 1024)
449 .expect_err("Should reject set RSV1 bit when no extension is negotiated");
450 }
451
452 #[test]
453 fn test_parse_frame_max_size() {
454 let mut buf = BytesMut::from(&[0b0000_0001u8, 0b0000_0010u8][..]);
455 buf.extend([1u8, 1u8]);
456
457 assert!(Parser::parse(&mut buf, true, 1).is_err());
458
459 if let Err(ProtocolError::Overflow) = Parser::parse(&mut buf, false, 0) {
460 } else {
461 unreachable!("error");
462 }
463 }
464
465 #[test]
466 fn test_parse_frame_max_size_recoverability() {
467 let mut buf = BytesMut::new();
468 buf.extend([0b0000_0001u8, 0b0000_0010u8, 0b0000_0000u8, 0b0000_0000u8]);
470 buf.extend([0b0000_0010u8, 0b0000_0010u8, 0b1111_1111u8, 0b1111_1111u8]);
472
473 assert_eq!(buf.len(), 8);
474 assert!(matches!(
475 Parser::parse(&mut buf, false, 1),
476 Err(ProtocolError::Overflow)
477 ));
478 assert_eq!(buf.len(), 4);
479 let frame = extract(Parser::parse(&mut buf, false, 2));
480 assert!(!frame.finished);
481 assert_eq!(frame.opcode, OpCode::Binary);
482 assert_eq!(
483 frame.payload,
484 Bytes::from(vec![0b1111_1111u8, 0b1111_1111u8])
485 );
486 assert_eq!(buf.len(), 0);
487 }
488
489 #[test]
490 fn test_ping_frame() {
491 let mut buf = BytesMut::new();
492 Parser::write_message(&mut buf, Vec::from("data"), OpCode::Ping, true, false);
493
494 let mut v = vec![137u8, 4u8];
495 v.extend(b"data");
496 assert_eq!(&buf[..], &v[..]);
497 }
498
499 #[test]
500 fn test_pong_frame() {
501 let mut buf = BytesMut::new();
502 Parser::write_message(&mut buf, Vec::from("data"), OpCode::Pong, true, false);
503
504 let mut v = vec![138u8, 4u8];
505 v.extend(b"data");
506 assert_eq!(&buf[..], &v[..]);
507 }
508
509 #[test]
510 fn test_close_frame() {
511 let mut buf = BytesMut::new();
512 let reason = (CloseCode::Normal, "data");
513 Parser::write_close(&mut buf, Some(reason.into()), false);
514
515 let mut v = vec![136u8, 6u8, 3u8, 232u8];
516 v.extend(b"data");
517 assert_eq!(&buf[..], &v[..]);
518 }
519
520 #[test]
521 fn test_empty_close_frame() {
522 let mut buf = BytesMut::new();
523 Parser::write_close(&mut buf, None, false);
524 assert_eq!(&buf[..], &vec![0x88, 0x00][..]);
525 }
526
527 #[test]
528 fn try_parse_close_payload_validates_payload() {
529 assert!(matches!(
530 Parser::try_parse_close_payload(&[0x03, 0xe8, 0xff]).unwrap_err(),
531 ProtocolError::BadOpCode
532 ));
533 assert!(matches!(
534 Parser::try_parse_close_payload(&[0, 0]).unwrap_err(),
535 ProtocolError::BadOpCode
536 ));
537 }
538
539 #[test]
540 fn test_oversized_control_frames() {
541 let mut buf = BytesMut::from(&[0x89u8, 126u8, 0x00, 126][..]);
543 buf.extend(vec![0u8; 126]);
544 assert!(matches!(
545 Parser::parse(&mut buf, false, 65536),
546 Err(ProtocolError::InvalidLength(126))
547 ));
548
549 let mut buf = BytesMut::from(&[0x88u8, 126u8, 0x00, 126][..]);
551 buf.extend(vec![0u8; 126]);
552 assert!(matches!(
553 Parser::parse(&mut buf, false, 65536),
554 Err(ProtocolError::InvalidLength(126))
555 ));
556 }
557
558 #[test]
559 fn test_parse_length_overflow() {
560 let buf: [u8; 14] = [
561 0x0a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xeb, 0x0e, 0x8f,
562 ];
563 let mut buf = BytesMut::from(&buf[..]);
564 let result = Parser::parse(&mut buf, true, 65536);
565 assert!(matches!(result, Err(ProtocolError::Overflow)));
566 }
567}