use bytes::{Buf, BufMut, Bytes, BytesMut};
use rand::Rng;
use crate::parser::Parser;
struct Padding {
pub len: u16,
pub data: Bytes,
}
pub const MAX_PADDING_SIZE: u32 = 255;
impl Padding {
pub fn generate_padding() -> Padding {
let mut rng = rand::rng();
let random_u32: u32 = rng.next_u32();
let padding_len: u16 = (random_u32 % MAX_PADDING_SIZE) as u16;
let mut padding = vec![0u8; padding_len as usize];
rng.fill_bytes(&mut padding);
Padding {
len: padding_len,
data: Bytes::from(padding),
}
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub(crate) enum FrameType {
Connect = 0x00,
Data = 0x01,
Close = 0x02,
Heartbeat = 0x03,
UdpConnect = 0x04,
UdpData = 0x05,
Handshake = 0x06,
}
#[derive(Copy, Clone)]
pub(crate) struct FrameHeader {
pub(crate) _auth_tag: [u8; 16],
pub(crate) stream_id: u32,
pub(crate) frame_type: FrameType,
pub(crate) payload_len: u16,
pub(crate) padding_len: u16,
}
pub(crate) struct Frame {
pub(crate) header: FrameHeader,
pub(crate) payload: Bytes,
pub(crate) _padding: Bytes,
}
const AUTH_TAG_SIZE: u16 = 16;
const STREAM_ID_SIZE: u16 = 4;
const FRAME_TYPE_SIZE: u16 = 1;
const PAYLOAD_LEN_SIZE: u16 = 2;
const PADDING_LEN_SIZE: u16 = 2;
pub const FRAME_HEADER_SIZE: u16 =
AUTH_TAG_SIZE + STREAM_ID_SIZE + FRAME_TYPE_SIZE + PAYLOAD_LEN_SIZE + PADDING_LEN_SIZE;
impl Frame {
pub(crate) fn new(stream_id: u32, frame_type: FrameType, payload: Bytes) -> Self {
Self {
header: FrameHeader {
_auth_tag: [0u8; 16],
stream_id,
frame_type,
payload_len: payload.len() as u16,
padding_len: 0,
},
payload,
_padding: Bytes::new(),
}
}
pub(crate) fn into_bytes(mut self, auth_key: &[u8; 16]) -> BytesMut {
let generated_padding = Padding::generate_padding();
self.header.padding_len = generated_padding.len;
let total_size =
FRAME_HEADER_SIZE as usize + self.payload.len() + generated_padding.len as usize;
let mut buf = BytesMut::with_capacity(total_size);
buf.put_slice(auth_key);
buf.put_u32(self.header.stream_id);
buf.put_u8(self.header.frame_type as u8);
buf.put_u16(self.header.payload_len);
buf.put_u16(self.header.padding_len);
buf.put(self.payload);
buf.put(generated_padding.data);
buf
}
}
impl Parser for FrameHeader {
type Error = String;
fn can_parse(bytes: &BytesMut) -> bool {
bytes.len() >= FRAME_HEADER_SIZE as usize
}
fn parse(bytes: &mut BytesMut) -> Result