frame decoding

This commit is contained in:
core 2023-08-10 03:24:09 -04:00
parent 4f3a570ab4
commit bdeb371b1a
Signed by: core
GPG Key ID: FDBF740DADDCEECF
2 changed files with 140 additions and 1 deletions

View File

@ -2,11 +2,14 @@
pub mod wire;
/// Contains the implementation of FrameWritable
pub mod write;
/// Contains the implementation of FrameReadable
pub mod read;
/// Contains functions useful for encoding and decoding wire lengths
pub mod length;
/// Contains functions for frame masking
pub mod mask;
#[derive(PartialEq, Eq, Clone, Debug)]
pub struct Frame {
pub fin: bool, // 1 bit
pub rsv1: bool, // 1 bit
@ -22,7 +25,7 @@ pub struct Frame {
pub payload_data: Vec<u8>
}
#[derive(Clone)]
#[derive(Clone, PartialEq, Eq, Debug)]
#[repr(u8)]
pub enum Opcode {
Continuation = 0x0,

136
hornbeam/src/frame/read.rs Normal file
View File

@ -0,0 +1,136 @@
use std::error::Error;
use std::fmt::{Display, Formatter};
use std::io;
use std::io::Read;
use crate::frame::{Frame, Opcode};
use crate::frame::length::{LengthReadable, WireLength};
use crate::frame::mask::mask;
use crate::frame::wire::FrameReadable;
#[derive(Debug)]
pub enum FrameReadError {
IoError(io::Error),
InvalidOpcode
}
impl Display for FrameReadError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::IoError(e) => write!(f, "io error: {}", e),
Self::InvalidOpcode => write!(f, "invalid opcode")
}
}
}
impl Error for FrameReadError {}
impl From<io::Error> for FrameReadError {
fn from(value: io::Error) -> Self {
Self::IoError(value)
}
}
impl<R: Read> FrameReadable for R {
type Error = FrameReadError;
fn read_frame(&mut self) -> Result<Frame, Self::Error> {
// read the first two bytes
let mut first_two = [0u8; 2];
self.read_exact(&mut first_two)?;
let fin = (first_two[0] & 0b1000_0000) >> 7;
let rsv1 = (first_two[0] & 0b0100_0000) >> 6;
let rsv2 = (first_two[0] & 0b0010_0000) >> 5;
let rsv3 = (first_two[0] & 0b0001_0000) >> 4;
let opcode = first_two[0] & 0b0000_1111;
let do_mask = (first_two[1] & 0b1000_0000) >> 7;
let length_without_mask = first_two[1] & 0b0111_1111;
let length: u64 = WireLength::read_length(length_without_mask, self)?.into();
let mut mask_key = None;
if do_mask == 1 {
let mut buf = [0u8; 4];
self.read_exact(&mut buf)?;
mask_key = Some(buf);
}
let mut payload = vec![0u8; length as usize];
self.read_exact(&mut payload)?;
if let Some(key) = mask_key {
mask(&mut payload, key);
}
let opcode = match opcode {
0 => Opcode::Continuation,
1 => Opcode::Text,
2 => Opcode::Binary,
8 => Opcode::ConnectionClose,
9 => Opcode::Ping,
10 => Opcode::Pong,
_ => return Err(FrameReadError::InvalidOpcode)
};
Ok(Frame {
fin: fin == 1,
rsv1: rsv1 == 1,
rsv2: rsv2 == 1,
rsv3: rsv3 == 1,
opcode,
mask: do_mask == 1,
payload_len: length,
masking_key: mask_key,
payload_data: payload,
})
}
}
#[cfg(test)]
mod tests {
use std::io::{Cursor, Write};
use crate::frame::{Frame, Opcode};
use crate::frame::wire::{FrameReadable, FrameWritable};
#[test]
fn decoding_6455_5_7_a() {
let mut buf: Cursor<Vec<u8>> = Cursor::new(vec![0x81, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f]);
let frame = buf.read_frame().unwrap();
assert_eq!(frame, Frame {
fin: true,
rsv1: false,
rsv2: false,
rsv3: false,
opcode: Opcode::Text,
mask: false,
payload_len: 5,
masking_key: None,
payload_data: "Hello".to_string().as_bytes().to_vec(),
});
}
#[test]
fn decoding_6455_5_7_b() {
let mut buf: Cursor<Vec<u8>> = Cursor::new(vec![0x81, 0x85, 0x37, 0xfa, 0x21, 0x3d, 0x7f, 0x9f, 0x4d, 0x51, 0x58]);
assert_eq!(buf.read_frame().unwrap(), Frame {
fin: true,
rsv1: false,
rsv2: false,
rsv3: false,
opcode: Opcode::Text,
mask: true,
payload_len: 5,
masking_key: Some([0x37, 0xfa, 0x21, 0x3d]),
payload_data: "Hello".to_string().as_bytes().to_vec(),
});
}
// 5.7(e) and 5.7(f) are skipped because they are impractical to write
}