|
|
@ -35,159 +35,242 @@ impl<'t> fmt::Display for CloseFrame<'t> { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// A struct representing a WebSocket frame.
|
|
|
|
/// A struct representing a WebSocket frame header.
|
|
|
|
|
|
|
|
#[allow(missing_copy_implementations)] |
|
|
|
#[derive(Debug, Clone)] |
|
|
|
#[derive(Debug, Clone)] |
|
|
|
pub struct Frame { |
|
|
|
pub struct FrameHeader { |
|
|
|
finished: bool, |
|
|
|
/// Indicates that the frame is the last one of a possibly fragmented message.
|
|
|
|
rsv1: bool, |
|
|
|
pub is_final: bool, |
|
|
|
rsv2: bool, |
|
|
|
/// Reserved for protocol extensions.
|
|
|
|
rsv3: bool, |
|
|
|
pub rsv1: bool, |
|
|
|
opcode: OpCode, |
|
|
|
/// Reserved for protocol extensions.
|
|
|
|
|
|
|
|
pub rsv2: bool, |
|
|
|
|
|
|
|
/// Reserved for protocol extensions.
|
|
|
|
|
|
|
|
pub rsv3: bool, |
|
|
|
|
|
|
|
/// WebSocket protocol opcode.
|
|
|
|
|
|
|
|
pub opcode: OpCode, |
|
|
|
|
|
|
|
/// A frame mask, if any.
|
|
|
|
mask: Option<[u8; 4]>, |
|
|
|
mask: Option<[u8; 4]>, |
|
|
|
|
|
|
|
|
|
|
|
payload: Vec<u8>, |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
impl Frame { |
|
|
|
impl Default for FrameHeader { |
|
|
|
|
|
|
|
fn default() -> Self { |
|
|
|
|
|
|
|
FrameHeader { |
|
|
|
|
|
|
|
is_final: true, |
|
|
|
|
|
|
|
rsv1: false, |
|
|
|
|
|
|
|
rsv2: false, |
|
|
|
|
|
|
|
rsv3: false, |
|
|
|
|
|
|
|
opcode: OpCode::Control(Control::Close), |
|
|
|
|
|
|
|
mask: None, |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// Get the length of the frame.
|
|
|
|
impl FrameHeader { |
|
|
|
/// This is the length of the header + the length of the payload.
|
|
|
|
/// Parse a header from an input stream.
|
|
|
|
#[inline] |
|
|
|
/// Returns `None` if insufficient data and does not consume anything in this case.
|
|
|
|
pub fn len(&self) -> usize { |
|
|
|
/// Payload size is returned along with the header.
|
|
|
|
let mut header_length = 2; |
|
|
|
pub fn parse(cursor: &mut Cursor<impl AsRef<[u8]>>) -> Result<Option<(Self, u64)>> { |
|
|
|
let payload_len = self.payload().len(); |
|
|
|
let initial = cursor.position(); |
|
|
|
if payload_len > 125 { |
|
|
|
match Self::parse_internal(cursor) { |
|
|
|
if payload_len <= u16::max_value() as usize { |
|
|
|
ret @ Ok(None) => { |
|
|
|
header_length += 2; |
|
|
|
cursor.set_position(initial); |
|
|
|
} else { |
|
|
|
ret |
|
|
|
header_length += 8; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
ret => ret |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Get the size of the header formatted with given payload length.
|
|
|
|
|
|
|
|
pub fn len(&self, length: u64) -> usize { |
|
|
|
|
|
|
|
2 |
|
|
|
|
|
|
|
+ LengthFormat::for_length(length).extra_bytes() |
|
|
|
|
|
|
|
+ if self.mask.is_some() { 4 } else { 0 } |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if self.is_masked() { |
|
|
|
/// Format a header for given payload size.
|
|
|
|
header_length += 4; |
|
|
|
pub fn format(&self, length: u64, output: &mut impl Write) -> Result<()> { |
|
|
|
|
|
|
|
let code: u8 = self.opcode.into(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let one = { |
|
|
|
|
|
|
|
code |
|
|
|
|
|
|
|
| if self.is_final { 0x80 } else { 0 } |
|
|
|
|
|
|
|
| if self.rsv1 { 0x40 } else { 0 } |
|
|
|
|
|
|
|
| if self.rsv2 { 0x20 } else { 0 } |
|
|
|
|
|
|
|
| if self.rsv3 { 0x10 } else { 0 } |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let lenfmt = LengthFormat::for_length(length); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let two = { |
|
|
|
|
|
|
|
lenfmt.length_byte() |
|
|
|
|
|
|
|
| if self.mask.is_some() { 0x80 } else { 0 } |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
output.write_all(&[one, two])?; |
|
|
|
|
|
|
|
match lenfmt { |
|
|
|
|
|
|
|
LengthFormat::U8(_) => (), |
|
|
|
|
|
|
|
LengthFormat::U16 => output.write_u16::<NetworkEndian>(length as u16)?, |
|
|
|
|
|
|
|
LengthFormat::U64 => output.write_u64::<NetworkEndian>(length)?, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
header_length + payload_len |
|
|
|
if let Some(ref mask) = self.mask { |
|
|
|
} |
|
|
|
output.write_all(mask)? |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// Test whether the frame is a final frame.
|
|
|
|
Ok(()) |
|
|
|
#[inline] |
|
|
|
|
|
|
|
pub fn is_final(&self) -> bool { |
|
|
|
|
|
|
|
self.finished |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// Test whether the first reserved bit is set.
|
|
|
|
/// Generate a random frame mask and store this in the header.
|
|
|
|
#[inline] |
|
|
|
///
|
|
|
|
pub fn has_rsv1(&self) -> bool { |
|
|
|
/// Of course this does not change frame contents. It just generates a mask.
|
|
|
|
self.rsv1 |
|
|
|
pub(crate) fn set_random_mask(&mut self) { |
|
|
|
|
|
|
|
self.mask = Some(generate_mask()) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// Test whether the second reserved bit is set.
|
|
|
|
impl FrameHeader { |
|
|
|
#[inline] |
|
|
|
/// Internal parse engine.
|
|
|
|
pub fn has_rsv2(&self) -> bool { |
|
|
|
/// Returns `None` if insufficient data.
|
|
|
|
self.rsv2 |
|
|
|
/// Payload size is returned along with the header.
|
|
|
|
} |
|
|
|
fn parse_internal(cursor: &mut impl Read) -> Result<Option<(Self, u64)>> { |
|
|
|
|
|
|
|
let (first, second) = { |
|
|
|
|
|
|
|
let mut head = [0u8; 2]; |
|
|
|
|
|
|
|
if cursor.read(&mut head)? != 2 { |
|
|
|
|
|
|
|
return Ok(None) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
trace!("Parsed headers {:?}", head); |
|
|
|
|
|
|
|
(head[0], head[1]) |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
/// Test whether the third reserved bit is set.
|
|
|
|
trace!("First: {:b}", first); |
|
|
|
#[inline] |
|
|
|
trace!("Second: {:b}", second); |
|
|
|
pub fn has_rsv3(&self) -> bool { |
|
|
|
|
|
|
|
self.rsv3 |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Get the OpCode of the frame.
|
|
|
|
let is_final = first & 0x80 != 0; |
|
|
|
#[inline] |
|
|
|
|
|
|
|
pub fn opcode(&self) -> OpCode { |
|
|
|
|
|
|
|
self.opcode |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Get a reference to the frame's payload.
|
|
|
|
let rsv1 = first & 0x40 != 0; |
|
|
|
#[inline] |
|
|
|
let rsv2 = first & 0x20 != 0; |
|
|
|
pub fn payload(&self) -> &Vec<u8> { |
|
|
|
let rsv3 = first & 0x10 != 0; |
|
|
|
&self.payload |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Test whether the frame is masked.
|
|
|
|
let opcode = OpCode::from(first & 0x0F); |
|
|
|
#[doc(hidden)] |
|
|
|
trace!("Opcode: {:?}", opcode); |
|
|
|
#[inline] |
|
|
|
|
|
|
|
pub fn is_masked(&self) -> bool { |
|
|
|
|
|
|
|
self.mask.is_some() |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Get an optional reference to the frame's mask.
|
|
|
|
let masked = second & 0x80 != 0; |
|
|
|
#[doc(hidden)] |
|
|
|
trace!("Masked: {:?}", masked); |
|
|
|
#[allow(dead_code)] |
|
|
|
|
|
|
|
#[inline] |
|
|
|
|
|
|
|
pub fn mask(&self) -> Option<&[u8; 4]> { |
|
|
|
|
|
|
|
self.mask.as_ref() |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Make this frame a final frame.
|
|
|
|
let length = { |
|
|
|
#[allow(dead_code)] |
|
|
|
let length_byte = second & 0x7F; |
|
|
|
#[inline] |
|
|
|
let length_length = LengthFormat::for_byte(length_byte).extra_bytes(); |
|
|
|
pub fn set_final(&mut self, is_final: bool) -> &mut Frame { |
|
|
|
if length_length > 0 { |
|
|
|
self.finished = is_final; |
|
|
|
match cursor.read_uint::<NetworkEndian>(length_length) { |
|
|
|
self |
|
|
|
Err(ref err) if err.kind() == ErrorKind::UnexpectedEof => { |
|
|
|
|
|
|
|
return Ok(None); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
Err(err) => { |
|
|
|
|
|
|
|
return Err(err.into()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
Ok(read) => read |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
length_byte as u64 |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let mask = if masked { |
|
|
|
|
|
|
|
let mut mask_bytes = [0u8; 4]; |
|
|
|
|
|
|
|
if cursor.read(&mut mask_bytes)? != 4 { |
|
|
|
|
|
|
|
return Ok(None) |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
Some(mask_bytes) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
None |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Disallow bad opcode
|
|
|
|
|
|
|
|
match opcode { |
|
|
|
|
|
|
|
OpCode::Control(Control::Reserved(_)) | OpCode::Data(Data::Reserved(_)) => { |
|
|
|
|
|
|
|
return Err(Error::Protocol(format!("Encountered invalid opcode: {}", first & 0x0F).into())) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
_ => () |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let hdr = FrameHeader { |
|
|
|
|
|
|
|
is_final, |
|
|
|
|
|
|
|
rsv1, |
|
|
|
|
|
|
|
rsv2, |
|
|
|
|
|
|
|
rsv3, |
|
|
|
|
|
|
|
opcode, |
|
|
|
|
|
|
|
mask, |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Ok(Some((hdr, length))) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// A struct representing a WebSocket frame.
|
|
|
|
|
|
|
|
#[derive(Debug, Clone)] |
|
|
|
|
|
|
|
pub struct Frame { |
|
|
|
|
|
|
|
header: FrameHeader, |
|
|
|
|
|
|
|
payload: Vec<u8>, |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// Set the first reserved bit.
|
|
|
|
impl Frame { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Get the length of the frame.
|
|
|
|
|
|
|
|
/// This is the length of the header + the length of the payload.
|
|
|
|
#[inline] |
|
|
|
#[inline] |
|
|
|
pub fn set_rsv1(&mut self, has_rsv1: bool) -> &mut Frame { |
|
|
|
pub fn len(&self) -> usize { |
|
|
|
self.rsv1 = has_rsv1; |
|
|
|
let length = self.payload.len(); |
|
|
|
self |
|
|
|
self.header.len(length as u64) + length |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// Set the second reserved bit.
|
|
|
|
/// Get a reference to the frame's header.
|
|
|
|
#[inline] |
|
|
|
#[inline] |
|
|
|
pub fn set_rsv2(&mut self, has_rsv2: bool) -> &mut Frame { |
|
|
|
pub fn header(&self) -> &FrameHeader { |
|
|
|
self.rsv2 = has_rsv2; |
|
|
|
&self.header |
|
|
|
self |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// Set the third reserved bit.
|
|
|
|
/// Get a mutable reference to the frame's header.
|
|
|
|
#[inline] |
|
|
|
#[inline] |
|
|
|
pub fn set_rsv3(&mut self, has_rsv3: bool) -> &mut Frame { |
|
|
|
pub fn header_mut(&mut self) -> &mut FrameHeader { |
|
|
|
self.rsv3 = has_rsv3; |
|
|
|
&mut self.header |
|
|
|
self |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// Set the OpCode.
|
|
|
|
/// Get a reference to the frame's payload.
|
|
|
|
#[allow(dead_code)] |
|
|
|
|
|
|
|
#[inline] |
|
|
|
#[inline] |
|
|
|
pub fn set_opcode(&mut self, opcode: OpCode) -> &mut Frame { |
|
|
|
pub fn payload(&self) -> &Vec<u8> { |
|
|
|
self.opcode = opcode; |
|
|
|
&self.payload |
|
|
|
self |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// Edit the frame's payload.
|
|
|
|
/// Get a mutable reference to the frame's payload.
|
|
|
|
#[allow(dead_code)] |
|
|
|
|
|
|
|
#[inline] |
|
|
|
#[inline] |
|
|
|
pub fn payload_mut(&mut self) -> &mut Vec<u8> { |
|
|
|
pub fn payload_mut(&mut self) -> &mut Vec<u8> { |
|
|
|
&mut self.payload |
|
|
|
&mut self.payload |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Generate a new mask for this frame.
|
|
|
|
/// Test whether the frame is masked.
|
|
|
|
//
|
|
|
|
|
|
|
|
// This method simply generates and stores the mask. It does not change the payload data.
|
|
|
|
|
|
|
|
// Instead, the payload data will be masked with the generated mask when the frame is sent
|
|
|
|
|
|
|
|
// to the other endpoint.
|
|
|
|
|
|
|
|
#[doc(hidden)] |
|
|
|
|
|
|
|
#[inline] |
|
|
|
#[inline] |
|
|
|
pub fn set_mask(&mut self) -> &mut Frame { |
|
|
|
pub(crate) fn is_masked(&self) -> bool { |
|
|
|
self.mask = Some(generate_mask()); |
|
|
|
self.header.mask.is_some() |
|
|
|
self |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// This method unmasks the payload and should only be called on frames that are actually
|
|
|
|
/// Generate a random mask for the frame.
|
|
|
|
// masked. In other words, those frames that have just been received from a client endpoint.
|
|
|
|
///
|
|
|
|
#[doc(hidden)] |
|
|
|
/// This just generates a mask, payload is not changed. The actual masking is performed
|
|
|
|
|
|
|
|
/// either on `format()` or on `apply_mask()` call.
|
|
|
|
#[inline] |
|
|
|
#[inline] |
|
|
|
pub fn remove_mask(&mut self) { |
|
|
|
pub(crate) fn set_random_mask(&mut self) { |
|
|
|
self.mask.and_then(|mask| { |
|
|
|
self.header.set_random_mask() |
|
|
|
Some(apply_mask(&mut self.payload, &mask)) |
|
|
|
} |
|
|
|
}); |
|
|
|
|
|
|
|
self.mask = None; |
|
|
|
/// This method unmasks the payload and should only be called on frames that are actually
|
|
|
|
|
|
|
|
/// masked. In other words, those frames that have just been received from a client endpoint.
|
|
|
|
|
|
|
|
#[inline] |
|
|
|
|
|
|
|
pub(crate) fn apply_mask(&mut self) { |
|
|
|
|
|
|
|
if let Some(mask) = self.header.mask.take() { |
|
|
|
|
|
|
|
apply_mask(&mut self.payload, mask) |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// Consume the frame into its payload as binary.
|
|
|
|
/// Consume the frame into its payload as binary.
|
|
|
@ -204,7 +287,7 @@ impl Frame { |
|
|
|
|
|
|
|
|
|
|
|
/// Consume the frame into a closing frame.
|
|
|
|
/// Consume the frame into a closing frame.
|
|
|
|
#[inline] |
|
|
|
#[inline] |
|
|
|
pub fn into_close(self) -> Result<Option<CloseFrame<'static>>> { |
|
|
|
pub(crate) fn into_close(self) -> Result<Option<CloseFrame<'static>>> { |
|
|
|
match self.payload.len() { |
|
|
|
match self.payload.len() { |
|
|
|
0 => Ok(None), |
|
|
|
0 => Ok(None), |
|
|
|
1 => Err(Error::Protocol("Invalid close sequence".into())), |
|
|
|
1 => Err(Error::Protocol("Invalid close sequence".into())), |
|
|
@ -213,24 +296,26 @@ impl Frame { |
|
|
|
let code = NetworkEndian::read_u16(&data[0..2]).into(); |
|
|
|
let code = NetworkEndian::read_u16(&data[0..2]).into(); |
|
|
|
data.drain(0..2); |
|
|
|
data.drain(0..2); |
|
|
|
let text = String::from_utf8(data)?; |
|
|
|
let text = String::from_utf8(data)?; |
|
|
|
Ok(Some(CloseFrame { code: code, reason: text.into() })) |
|
|
|
Ok(Some(CloseFrame { code, reason: text.into() })) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// Create a new data frame.
|
|
|
|
/// Create a new data frame.
|
|
|
|
#[inline] |
|
|
|
#[inline] |
|
|
|
pub fn message(data: Vec<u8>, code: OpCode, finished: bool) -> Frame { |
|
|
|
pub fn message(data: Vec<u8>, opcode: OpCode, is_final: bool) -> Frame { |
|
|
|
debug_assert!(match code { |
|
|
|
debug_assert!(match opcode { |
|
|
|
OpCode::Data(_) => true, |
|
|
|
OpCode::Data(_) => true, |
|
|
|
_ => false, |
|
|
|
_ => false, |
|
|
|
}, "Invalid opcode for data frame."); |
|
|
|
}, "Invalid opcode for data frame."); |
|
|
|
|
|
|
|
|
|
|
|
Frame { |
|
|
|
Frame { |
|
|
|
finished: finished, |
|
|
|
header: FrameHeader { |
|
|
|
opcode: code, |
|
|
|
is_final, |
|
|
|
|
|
|
|
opcode, |
|
|
|
|
|
|
|
.. FrameHeader::default() |
|
|
|
|
|
|
|
}, |
|
|
|
payload: data, |
|
|
|
payload: data, |
|
|
|
.. Frame::default() |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -238,9 +323,11 @@ impl Frame { |
|
|
|
#[inline] |
|
|
|
#[inline] |
|
|
|
pub fn pong(data: Vec<u8>) -> Frame { |
|
|
|
pub fn pong(data: Vec<u8>) -> Frame { |
|
|
|
Frame { |
|
|
|
Frame { |
|
|
|
opcode: OpCode::Control(Control::Pong), |
|
|
|
header: FrameHeader { |
|
|
|
|
|
|
|
opcode: OpCode::Control(Control::Pong), |
|
|
|
|
|
|
|
.. FrameHeader::default() |
|
|
|
|
|
|
|
}, |
|
|
|
payload: data, |
|
|
|
payload: data, |
|
|
|
.. Frame::default() |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -248,9 +335,11 @@ impl Frame { |
|
|
|
#[inline] |
|
|
|
#[inline] |
|
|
|
pub fn ping(data: Vec<u8>) -> Frame { |
|
|
|
pub fn ping(data: Vec<u8>) -> Frame { |
|
|
|
Frame { |
|
|
|
Frame { |
|
|
|
opcode: OpCode::Control(Control::Ping), |
|
|
|
header: FrameHeader { |
|
|
|
|
|
|
|
opcode: OpCode::Control(Control::Ping), |
|
|
|
|
|
|
|
.. FrameHeader::default() |
|
|
|
|
|
|
|
}, |
|
|
|
payload: data, |
|
|
|
payload: data, |
|
|
|
.. Frame::default() |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -267,199 +356,28 @@ impl Frame { |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
Frame { |
|
|
|
Frame { |
|
|
|
payload: payload, |
|
|
|
header: FrameHeader::default(), |
|
|
|
.. Frame::default() |
|
|
|
payload, |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// Parse the input stream into a frame.
|
|
|
|
/// Create a frame from given header and data.
|
|
|
|
pub fn parse(cursor: &mut Cursor<Vec<u8>>) -> Result<Option<Frame>> { |
|
|
|
pub fn from_payload(header: FrameHeader, payload: Vec<u8>) -> Self { |
|
|
|
let size = cursor.get_ref().len() as u64 - cursor.position(); |
|
|
|
Frame { |
|
|
|
let initial = cursor.position(); |
|
|
|
header, |
|
|
|
trace!("Position in buffer {}", initial); |
|
|
|
payload, |
|
|
|
|
|
|
|
|
|
|
|
let mut head = [0u8; 2]; |
|
|
|
|
|
|
|
if try!(cursor.read(&mut head)) != 2 { |
|
|
|
|
|
|
|
cursor.set_position(initial); |
|
|
|
|
|
|
|
return Ok(None) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
trace!("Parsed headers {:?}", head); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let first = head[0]; |
|
|
|
|
|
|
|
let second = head[1]; |
|
|
|
|
|
|
|
trace!("First: {:b}", first); |
|
|
|
|
|
|
|
trace!("Second: {:b}", second); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let finished = first & 0x80 != 0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let rsv1 = first & 0x40 != 0; |
|
|
|
|
|
|
|
let rsv2 = first & 0x20 != 0; |
|
|
|
|
|
|
|
let rsv3 = first & 0x10 != 0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let opcode = OpCode::from(first & 0x0F); |
|
|
|
|
|
|
|
trace!("Opcode: {:?}", opcode); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let masked = second & 0x80 != 0; |
|
|
|
|
|
|
|
trace!("Masked: {:?}", masked); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let mut header_length = 2; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let mut length = (second & 0x7F) as u64; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if let Some(length_nbytes) = match length { |
|
|
|
|
|
|
|
126 => Some(2), |
|
|
|
|
|
|
|
127 => Some(8), |
|
|
|
|
|
|
|
_ => None, |
|
|
|
|
|
|
|
} { |
|
|
|
|
|
|
|
match cursor.read_uint::<NetworkEndian>(length_nbytes) { |
|
|
|
|
|
|
|
Err(ref err) if err.kind() == ErrorKind::UnexpectedEof => { |
|
|
|
|
|
|
|
cursor.set_position(initial); |
|
|
|
|
|
|
|
return Ok(None); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
Err(err) => { |
|
|
|
|
|
|
|
return Err(Error::from(err)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
Ok(read) => { |
|
|
|
|
|
|
|
length = read; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
header_length += length_nbytes as u64; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
trace!("Payload length: {}", length); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let mask = if masked { |
|
|
|
|
|
|
|
let mut mask_bytes = [0u8; 4]; |
|
|
|
|
|
|
|
if try!(cursor.read(&mut mask_bytes)) != 4 { |
|
|
|
|
|
|
|
cursor.set_position(initial); |
|
|
|
|
|
|
|
return Ok(None) |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
header_length += 4; |
|
|
|
|
|
|
|
Some(mask_bytes) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
None |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Disallow bad opcode
|
|
|
|
|
|
|
|
match opcode { |
|
|
|
|
|
|
|
OpCode::Control(Control::Reserved(_)) | OpCode::Data(Data::Reserved(_)) => { |
|
|
|
|
|
|
|
return Err(Error::Protocol(format!("Encountered invalid opcode: {}", first & 0x0F).into())) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
_ => () |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Make sure `length` is not too big (fits into `usize`).
|
|
|
|
|
|
|
|
if length > usize::max_value() as u64 { |
|
|
|
|
|
|
|
return Err(Error::Capacity(format!("Message length too big: {}", length).into())); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if size < header_length || size - header_length < length { |
|
|
|
|
|
|
|
cursor.set_position(initial); |
|
|
|
|
|
|
|
return Ok(None) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Size is checked above, so it won't be truncated here.
|
|
|
|
|
|
|
|
let mut data = Vec::with_capacity(length as usize); |
|
|
|
|
|
|
|
if length > 0 { |
|
|
|
|
|
|
|
try!(cursor.take(length).read_to_end(&mut data)); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
debug_assert_eq!(data.len() as u64, length); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let frame = Frame { |
|
|
|
|
|
|
|
finished: finished, |
|
|
|
|
|
|
|
rsv1: rsv1, |
|
|
|
|
|
|
|
rsv2: rsv2, |
|
|
|
|
|
|
|
rsv3: rsv3, |
|
|
|
|
|
|
|
opcode: opcode, |
|
|
|
|
|
|
|
mask: mask, |
|
|
|
|
|
|
|
payload: data, |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Ok(Some(frame)) |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// Write a frame out to a buffer
|
|
|
|
/// Write a frame out to a buffer
|
|
|
|
pub fn format<W>(mut self, w: &mut W) -> Result<()> |
|
|
|
pub fn format(mut self, output: &mut impl Write) -> Result<()> { |
|
|
|
where W: Write |
|
|
|
self.header.format(self.payload.len() as u64, output)?; |
|
|
|
{ |
|
|
|
self.apply_mask(); |
|
|
|
let mut one = 0u8; |
|
|
|
output.write_all(self.payload())?; |
|
|
|
let code: u8 = self.opcode.into(); |
|
|
|
|
|
|
|
if self.is_final() { |
|
|
|
|
|
|
|
one |= 0x80; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if self.has_rsv1() { |
|
|
|
|
|
|
|
one |= 0x40; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if self.has_rsv2() { |
|
|
|
|
|
|
|
one |= 0x20; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if self.has_rsv3() { |
|
|
|
|
|
|
|
one |= 0x10; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
one |= code; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let mut two = 0u8; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if self.is_masked() { |
|
|
|
|
|
|
|
two |= 0x80; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if self.payload.len() < 126 { |
|
|
|
|
|
|
|
two |= self.payload.len() as u8; |
|
|
|
|
|
|
|
let headers = [one, two]; |
|
|
|
|
|
|
|
try!(w.write(&headers)); |
|
|
|
|
|
|
|
} else if self.payload.len() <= 65535 { |
|
|
|
|
|
|
|
two |= 126; |
|
|
|
|
|
|
|
let mut length_bytes = [0u8; 2]; |
|
|
|
|
|
|
|
NetworkEndian::write_u16(&mut length_bytes, self.payload.len() as u16); |
|
|
|
|
|
|
|
let headers = [one, two, length_bytes[0], length_bytes[1]]; |
|
|
|
|
|
|
|
try!(w.write(&headers)); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
two |= 127; |
|
|
|
|
|
|
|
let mut length_bytes = [0u8; 8]; |
|
|
|
|
|
|
|
NetworkEndian::write_u64(&mut length_bytes, self.payload.len() as u64); |
|
|
|
|
|
|
|
let headers = [ |
|
|
|
|
|
|
|
one, |
|
|
|
|
|
|
|
two, |
|
|
|
|
|
|
|
length_bytes[0], |
|
|
|
|
|
|
|
length_bytes[1], |
|
|
|
|
|
|
|
length_bytes[2], |
|
|
|
|
|
|
|
length_bytes[3], |
|
|
|
|
|
|
|
length_bytes[4], |
|
|
|
|
|
|
|
length_bytes[5], |
|
|
|
|
|
|
|
length_bytes[6], |
|
|
|
|
|
|
|
length_bytes[7], |
|
|
|
|
|
|
|
]; |
|
|
|
|
|
|
|
try!(w.write(&headers)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if self.is_masked() { |
|
|
|
|
|
|
|
let mask = self.mask.take().unwrap(); |
|
|
|
|
|
|
|
apply_mask(&mut self.payload, &mask); |
|
|
|
|
|
|
|
try!(w.write(&mask)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
try!(w.write(&self.payload)); |
|
|
|
|
|
|
|
Ok(()) |
|
|
|
Ok(()) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
impl Default for Frame { |
|
|
|
|
|
|
|
fn default() -> Frame { |
|
|
|
|
|
|
|
Frame { |
|
|
|
|
|
|
|
finished: true, |
|
|
|
|
|
|
|
rsv1: false, |
|
|
|
|
|
|
|
rsv2: false, |
|
|
|
|
|
|
|
rsv3: false, |
|
|
|
|
|
|
|
opcode: OpCode::Control(Control::Close), |
|
|
|
|
|
|
|
mask: None, |
|
|
|
|
|
|
|
payload: Vec::new(), |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
impl fmt::Display for Frame { |
|
|
|
impl fmt::Display for Frame { |
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
|
|
|
write!(f, |
|
|
|
write!(f, |
|
|
@ -472,11 +390,11 @@ length: {} |
|
|
|
payload length: {} |
|
|
|
payload length: {} |
|
|
|
payload: 0x{} |
|
|
|
payload: 0x{} |
|
|
|
", |
|
|
|
", |
|
|
|
self.finished, |
|
|
|
self.header.is_final, |
|
|
|
self.rsv1, |
|
|
|
self.header.rsv1, |
|
|
|
self.rsv2, |
|
|
|
self.header.rsv2, |
|
|
|
self.rsv3, |
|
|
|
self.header.rsv3, |
|
|
|
self.opcode, |
|
|
|
self.header.opcode, |
|
|
|
// self.mask.map(|mask| format!("{:?}", mask)).unwrap_or("NONE".into()),
|
|
|
|
// self.mask.map(|mask| format!("{:?}", mask)).unwrap_or("NONE".into()),
|
|
|
|
self.len(), |
|
|
|
self.len(), |
|
|
|
self.payload.len(), |
|
|
|
self.payload.len(), |
|
|
@ -484,6 +402,57 @@ payload: 0x{} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Handling of the length format.
|
|
|
|
|
|
|
|
enum LengthFormat { |
|
|
|
|
|
|
|
U8(u8), |
|
|
|
|
|
|
|
U16, |
|
|
|
|
|
|
|
U64, |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
impl LengthFormat { |
|
|
|
|
|
|
|
/// Get length format for a given data size.
|
|
|
|
|
|
|
|
#[inline] |
|
|
|
|
|
|
|
fn for_length(length: u64) -> Self { |
|
|
|
|
|
|
|
if length < 126 { |
|
|
|
|
|
|
|
LengthFormat::U8(length as u8) |
|
|
|
|
|
|
|
} else if length < 65536 { |
|
|
|
|
|
|
|
LengthFormat::U16 |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
LengthFormat::U64 |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Get the size of length encoding.
|
|
|
|
|
|
|
|
#[inline] |
|
|
|
|
|
|
|
fn extra_bytes(&self) -> usize { |
|
|
|
|
|
|
|
match *self { |
|
|
|
|
|
|
|
LengthFormat::U8(_) => 0, |
|
|
|
|
|
|
|
LengthFormat::U16 => 2, |
|
|
|
|
|
|
|
LengthFormat::U64 => 8, |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Encode the givem length.
|
|
|
|
|
|
|
|
#[inline] |
|
|
|
|
|
|
|
fn length_byte(&self) -> u8 { |
|
|
|
|
|
|
|
match *self { |
|
|
|
|
|
|
|
LengthFormat::U8(b) => b, |
|
|
|
|
|
|
|
LengthFormat::U16 => 126, |
|
|
|
|
|
|
|
LengthFormat::U64 => 127, |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Get length format for a given length byte.
|
|
|
|
|
|
|
|
#[inline] |
|
|
|
|
|
|
|
fn for_byte(byte: u8) -> Self { |
|
|
|
|
|
|
|
match byte & 0x7F { |
|
|
|
|
|
|
|
126 => LengthFormat::U16, |
|
|
|
|
|
|
|
127 => LengthFormat::U64, |
|
|
|
|
|
|
|
b => LengthFormat::U8(b) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#[cfg(test)] |
|
|
|
#[cfg(test)] |
|
|
|
mod tests { |
|
|
|
mod tests { |
|
|
|
use super::*; |
|
|
|
use super::*; |
|
|
@ -496,7 +465,11 @@ mod tests { |
|
|
|
let mut raw: Cursor<Vec<u8>> = Cursor::new(vec![ |
|
|
|
let mut raw: Cursor<Vec<u8>> = Cursor::new(vec![ |
|
|
|
0x82, 0x07, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 |
|
|
|
0x82, 0x07, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 |
|
|
|
]); |
|
|
|
]); |
|
|
|
let frame = Frame::parse(&mut raw).unwrap().unwrap(); |
|
|
|
let (header, length) = FrameHeader::parse(&mut raw).unwrap().unwrap(); |
|
|
|
|
|
|
|
assert_eq!(length, 7); |
|
|
|
|
|
|
|
let mut payload = Vec::new(); |
|
|
|
|
|
|
|
raw.read_to_end(&mut payload).unwrap(); |
|
|
|
|
|
|
|
let frame = Frame::from_payload(header, payload); |
|
|
|
assert_eq!(frame.into_data(), vec![ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 ]); |
|
|
|
assert_eq!(frame.into_data(), vec![ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 ]); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -515,12 +488,4 @@ mod tests { |
|
|
|
assert!(view.contains("payload:")); |
|
|
|
assert!(view.contains("payload:")); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#[test] |
|
|
|
|
|
|
|
fn parse_overflow() { |
|
|
|
|
|
|
|
let mut raw: Cursor<Vec<u8>> = Cursor::new(vec![ |
|
|
|
|
|
|
|
0x83, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|
|
|
|
|
|
|
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, |
|
|
|
|
|
|
|
]); |
|
|
|
|
|
|
|
let _ = Frame::parse(&mut raw); // should not crash
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|