tungstenite/protocol/frame/
frame.rs1use log::*;
2use std::{
3 default::Default,
4 fmt,
5 io::{Cursor, ErrorKind, Read, Write},
6 mem,
7 result::Result as StdResult,
8 str::Utf8Error,
9 string::String,
10};
11
12use super::{
13 coding::{CloseCode, Control, Data, OpCode},
14 mask::{apply_mask, generate_mask},
15};
16use crate::{
17 error::{Error, ProtocolError, Result},
18 protocol::frame::Utf8Bytes,
19};
20use bytes::{Bytes, BytesMut};
21
22#[derive(Debug, Clone, Eq, PartialEq)]
24pub struct CloseFrame {
25 pub code: CloseCode,
27 pub reason: Utf8Bytes,
29}
30
31impl fmt::Display for CloseFrame {
32 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
33 write!(f, "{} ({})", self.reason, self.code)
34 }
35}
36
37#[allow(missing_copy_implementations)]
39#[derive(Debug, Clone, Eq, PartialEq)]
40pub struct FrameHeader {
41 pub is_final: bool,
43 pub rsv1: bool,
45 pub rsv2: bool,
47 pub rsv3: bool,
49 pub opcode: OpCode,
51 pub mask: Option<[u8; 4]>,
53}
54
55impl Default for FrameHeader {
56 fn default() -> Self {
57 FrameHeader {
58 is_final: true,
59 rsv1: false,
60 rsv2: false,
61 rsv3: false,
62 opcode: OpCode::Control(Control::Close),
63 mask: None,
64 }
65 }
66}
67
68impl FrameHeader {
69 pub(crate) const MAX_SIZE: usize = 14;
72
73 pub fn parse(cursor: &mut Cursor<impl AsRef<[u8]>>) -> Result<Option<(Self, u64)>> {
77 let initial = cursor.position();
78 match Self::parse_internal(cursor) {
79 ret @ Ok(None) => {
80 cursor.set_position(initial);
81 ret
82 }
83 ret => ret,
84 }
85 }
86
87 #[allow(clippy::len_without_is_empty)]
89 pub fn len(&self, length: u64) -> usize {
90 2 + LengthFormat::for_length(length).extra_bytes() + if self.mask.is_some() { 4 } else { 0 }
91 }
92
93 pub fn format(&self, length: u64, output: &mut impl Write) -> Result<()> {
95 let code: u8 = self.opcode.into();
96
97 let one = {
98 code | if self.is_final { 0x80 } else { 0 }
99 | if self.rsv1 { 0x40 } else { 0 }
100 | if self.rsv2 { 0x20 } else { 0 }
101 | if self.rsv3 { 0x10 } else { 0 }
102 };
103
104 let lenfmt = LengthFormat::for_length(length);
105
106 let two = { lenfmt.length_byte() | if self.mask.is_some() { 0x80 } else { 0 } };
107
108 output.write_all(&[one, two])?;
109 match lenfmt {
110 LengthFormat::U8(_) => (),
111 LengthFormat::U16 => {
112 output.write_all(&(length as u16).to_be_bytes())?;
113 }
114 LengthFormat::U64 => {
115 output.write_all(&length.to_be_bytes())?;
116 }
117 }
118
119 if let Some(ref mask) = self.mask {
120 output.write_all(mask)?;
121 }
122
123 Ok(())
124 }
125
126 pub(crate) fn set_random_mask(&mut self) {
130 self.mask = Some(generate_mask());
131 }
132}
133
134impl FrameHeader {
135 fn parse_internal(cursor: &mut impl Read) -> Result<Option<(Self, u64)>> {
139 let (first, second) = {
140 let mut head = [0u8; 2];
141 if cursor.read(&mut head)? != 2 {
142 return Ok(None);
143 }
144 trace!("Parsed headers {head:?}");
145 (head[0], head[1])
146 };
147
148 trace!("First: {first:b}");
149 trace!("Second: {second:b}");
150
151 let is_final = first & 0x80 != 0;
152
153 let rsv1 = first & 0x40 != 0;
154 let rsv2 = first & 0x20 != 0;
155 let rsv3 = first & 0x10 != 0;
156
157 let opcode = OpCode::from(first & 0x0F);
158 trace!("Opcode: {opcode:?}");
159
160 let masked = second & 0x80 != 0;
161 trace!("Masked: {masked:?}");
162
163 let length = {
164 let length_byte = second & 0x7F;
165 let length_length = LengthFormat::for_byte(length_byte).extra_bytes();
166 if length_length > 0 {
167 const SIZE: usize = mem::size_of::<u64>();
168 assert!(length_length <= SIZE, "length exceeded size of u64");
169 let start = SIZE - length_length;
170 let mut buffer = [0; SIZE];
171 match cursor.read_exact(&mut buffer[start..]) {
172 Err(ref err) if err.kind() == ErrorKind::UnexpectedEof => return Ok(None),
173 Err(err) => return Err(err.into()),
174 Ok(()) => u64::from_be_bytes(buffer),
175 }
176 } else {
177 u64::from(length_byte)
178 }
179 };
180
181 let mask = if masked {
182 let mut mask_bytes = [0u8; 4];
183 if cursor.read(&mut mask_bytes)? != 4 {
184 return Ok(None);
185 } else {
186 Some(mask_bytes)
187 }
188 } else {
189 None
190 };
191
192 match opcode {
194 OpCode::Control(Control::Reserved(_)) | OpCode::Data(Data::Reserved(_)) => {
195 return Err(Error::Protocol(ProtocolError::InvalidOpcode(first & 0x0F)))
196 }
197 _ => (),
198 }
199
200 let hdr = FrameHeader { is_final, rsv1, rsv2, rsv3, opcode, mask };
201
202 Ok(Some((hdr, length)))
203 }
204}
205
206#[derive(Debug, Clone, Eq, PartialEq)]
208pub struct Frame {
209 header: FrameHeader,
210 payload: Bytes,
211}
212
213impl Frame {
214 #[inline]
217 pub fn len(&self) -> usize {
218 let length = self.payload.len();
219 self.header.len(length as u64) + length
220 }
221
222 #[inline]
224 pub fn is_empty(&self) -> bool {
225 self.len() == 0
226 }
227
228 #[inline]
230 pub fn header(&self) -> &FrameHeader {
231 &self.header
232 }
233
234 #[inline]
236 pub fn header_mut(&mut self) -> &mut FrameHeader {
237 &mut self.header
238 }
239
240 #[inline]
242 pub fn payload(&self) -> &[u8] {
243 &self.payload
244 }
245
246 #[inline]
248 pub(crate) fn is_masked(&self) -> bool {
249 self.header.mask.is_some()
250 }
251
252 #[inline]
257 pub(crate) fn set_random_mask(&mut self) {
258 self.header.set_random_mask();
259 }
260
261 #[inline]
263 pub fn into_text(self) -> StdResult<Utf8Bytes, Utf8Error> {
264 self.payload.try_into()
265 }
266
267 #[inline]
269 pub fn into_payload(self) -> Bytes {
270 self.payload
271 }
272
273 #[inline]
275 pub fn to_text(&self) -> Result<&str, Utf8Error> {
276 std::str::from_utf8(&self.payload)
277 }
278
279 #[inline]
281 pub(crate) fn into_close(self) -> Result<Option<CloseFrame>> {
282 match self.payload.len() {
283 0 => Ok(None),
284 1 => Err(Error::Protocol(ProtocolError::InvalidCloseSequence)),
285 _ => {
286 let code = u16::from_be_bytes([self.payload[0], self.payload[1]]).into();
287 let reason = Utf8Bytes::try_from(self.payload.slice(2..))?;
288 Ok(Some(CloseFrame { code, reason }))
289 }
290 }
291 }
292
293 #[inline]
295 pub fn message(data: impl Into<Bytes>, opcode: OpCode, is_final: bool) -> Frame {
296 debug_assert!(matches!(opcode, OpCode::Data(_)), "Invalid opcode for data frame.");
297 Frame {
298 header: FrameHeader { is_final, opcode, ..FrameHeader::default() },
299 payload: data.into(),
300 }
301 }
302
303 #[inline]
310 pub(crate) fn compressed_message(data: Bytes, opcode: Data, is_final: bool) -> Frame {
311 Frame {
312 header: FrameHeader {
313 is_final,
314 opcode: OpCode::Data(opcode),
315 rsv1: true,
323 ..FrameHeader::default()
324 },
325 payload: data,
326 }
327 }
328
329 #[inline]
331 pub fn pong(data: impl Into<Bytes>) -> Frame {
332 Frame {
333 header: FrameHeader {
334 opcode: OpCode::Control(Control::Pong),
335 ..FrameHeader::default()
336 },
337 payload: data.into(),
338 }
339 }
340
341 #[inline]
343 pub fn ping(data: impl Into<Bytes>) -> Frame {
344 Frame {
345 header: FrameHeader {
346 opcode: OpCode::Control(Control::Ping),
347 ..FrameHeader::default()
348 },
349 payload: data.into(),
350 }
351 }
352
353 #[inline]
355 pub fn close(msg: Option<CloseFrame>) -> Frame {
356 let payload = if let Some(CloseFrame { code, reason }) = msg {
357 let mut p = BytesMut::with_capacity(reason.len() + 2);
358 p.extend(u16::from(code).to_be_bytes());
359 p.extend_from_slice(reason.as_bytes());
360 p
361 } else {
362 <_>::default()
363 };
364
365 Frame { header: FrameHeader::default(), payload: payload.into() }
366 }
367
368 pub fn from_payload(header: FrameHeader, payload: Bytes) -> Self {
370 Frame { header, payload }
371 }
372
373 pub fn format(mut self, output: &mut impl Write) -> Result<()> {
375 self.header.format(self.payload.len() as u64, output)?;
376
377 if let Some(mask) = self.header.mask.take() {
378 let mut data = Vec::from(mem::take(&mut self.payload));
379 apply_mask(&mut data, mask);
380 output.write_all(&data)?;
381 } else {
382 output.write_all(&self.payload)?;
383 }
384
385 Ok(())
386 }
387
388 pub(crate) fn format_into_buf(mut self, buf: &mut Vec<u8>) -> Result<()> {
389 self.header.format(self.payload.len() as u64, buf)?;
390
391 let len = buf.len();
392 buf.extend_from_slice(&self.payload);
393
394 if let Some(mask) = self.header.mask.take() {
395 apply_mask(&mut buf[len..], mask);
396 }
397
398 Ok(())
399 }
400}
401
402impl fmt::Display for Frame {
403 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
404 use std::fmt::Write;
405
406 write!(
407 f,
408 "
409<FRAME>
410final: {}
411reserved: {} {} {}
412opcode: {}
413length: {}
414payload length: {}
415payload: 0x{}
416 ",
417 self.header.is_final,
418 self.header.rsv1,
419 self.header.rsv2,
420 self.header.rsv3,
421 self.header.opcode,
422 self.len(),
424 self.payload.len(),
425 self.payload.iter().fold(String::new(), |mut output, byte| {
426 _ = write!(output, "{byte:02x}");
427 output
428 })
429 )
430 }
431}
432
433enum LengthFormat {
435 U8(u8),
436 U16,
437 U64,
438}
439
440impl LengthFormat {
441 #[inline]
443 fn for_length(length: u64) -> Self {
444 if length < 126 {
445 LengthFormat::U8(length as u8)
446 } else if length < 65536 {
447 LengthFormat::U16
448 } else {
449 LengthFormat::U64
450 }
451 }
452
453 #[inline]
455 fn extra_bytes(&self) -> usize {
456 match *self {
457 LengthFormat::U8(_) => 0,
458 LengthFormat::U16 => 2,
459 LengthFormat::U64 => 8,
460 }
461 }
462
463 #[inline]
465 fn length_byte(&self) -> u8 {
466 match *self {
467 LengthFormat::U8(b) => b,
468 LengthFormat::U16 => 126,
469 LengthFormat::U64 => 127,
470 }
471 }
472
473 #[inline]
475 fn for_byte(byte: u8) -> Self {
476 match byte & 0x7F {
477 126 => LengthFormat::U16,
478 127 => LengthFormat::U64,
479 b => LengthFormat::U8(b),
480 }
481 }
482}
483
484#[cfg(test)]
485mod tests {
486 use super::*;
487
488 use super::super::coding::{Data, OpCode};
489 use std::io::Cursor;
490
491 #[test]
492 fn parse() {
493 let mut raw: Cursor<Vec<u8>> =
494 Cursor::new(vec![0x82, 0x07, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07]);
495 let (header, length) = FrameHeader::parse(&mut raw).unwrap().unwrap();
496 assert_eq!(length, 7);
497 let mut payload = Vec::new();
498 raw.read_to_end(&mut payload).unwrap();
499 let frame = Frame::from_payload(header, payload.into());
500 assert_eq!(frame.into_payload(), &[0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07][..]);
501 }
502
503 #[test]
504 fn format() {
505 let frame = Frame::ping(vec![0x01, 0x02]);
506 let mut buf = Vec::with_capacity(frame.len());
507 frame.format(&mut buf).unwrap();
508 assert_eq!(buf, vec![0x89, 0x02, 0x01, 0x02]);
509 }
510
511 #[test]
512 fn format_into_buf() {
513 let frame = Frame::ping(vec![0x01, 0x02]);
514 let mut buf = Vec::with_capacity(frame.len());
515 frame.format_into_buf(&mut buf).unwrap();
516 assert_eq!(buf, vec![0x89, 0x02, 0x01, 0x02]);
517 }
518
519 #[test]
520 fn display() {
521 let f = Frame::message(Bytes::from_static(b"hi there"), OpCode::Data(Data::Text), true);
522 let view = format!("{f}");
523 assert!(view.contains("payload:"));
524 }
525}