reqrio 0.3.0-rc1

A lightweight, high-performance, fingerprint-based HTTP request library.
Documentation
use reqtls::WriteExt;
pub use payload::WsPayload;
pub use typ::{WsFrameType, WsOpcode};


mod payload;
mod typ;

use crate::error::HlsResult;
use crate::{Buffer, HlsError};

///```text
///     0    1   2   3   4   5   6   7
/// +------+---+---+---+---+---+---+---+
/// | mask |        len/code           |
/// +------+---------------------------+
/// ```
pub struct Marker {
    mask: bool,
    len_code: u8,
}

impl Marker {
    pub fn new() -> Marker {
        Marker {
            mask: false,
            len_code: 0,
        }
    }

    pub fn from_u8(value: u8) -> Marker {
        let mut res = Marker::new();
        res.mask = value & 0x80 == 0x80;
        res.len_code = value & 0x7f;
        res
    }

    pub fn into_inner(self, len: usize) -> u8 {
        let mut res = 0u8;
        if self.mask { res |= 0x80 }
        match len {
            ..126 => res |= len as u8,
            126..0xFFFF => res |= 126,
            0xFFFF.. => res |= 127,
        }
        res
    }
}


pub struct WsFrame {
    typ: WsFrameType,
    masker: Marker,
    payload: WsPayload,
}

impl Default for WsFrame {
    fn default() -> Self {
        WsFrame {
            typ: WsFrameType::new(),
            masker: Marker::new(),
            payload: WsPayload::new(),
        }
    }
}

impl WsFrame {
    pub fn new_frame(opcode: WsOpcode, mask: bool, payload: &[u8]) -> WsFrame {
        let mut res = WsFrame::default();
        res.typ.set_opcode(opcode);
        res.typ.set_fin(true);
        res.masker.mask = mask;
        res.payload.copy_payload(payload, &res.masker);
        res
    }

    pub fn new_pong(mask: bool, payload: &[u8]) -> WsFrame {
        let mut res = WsFrame::default();
        res.typ.set_opcode(WsOpcode::PONG);
        res.typ.set_fin(true);
        res.masker.mask = mask;
        res.payload.copy_payload(payload, &res.masker);
        res
    }

    pub fn new_binary(mask: bool, payload: &[u8]) -> WsFrame {
        let mut res = WsFrame::default();
        res.typ.set_opcode(WsOpcode::BINARY);
        res.typ.set_fin(true);
        res.masker.mask = mask;
        res.payload.copy_payload(payload, &res.masker);
        res
    }

    pub fn new_text(mask: bool, payload: impl AsRef<str>) -> WsFrame {
        let mut res = WsFrame::default();
        res.typ.set_opcode(WsOpcode::TEXT);
        res.typ.set_fin(true);
        res.masker.mask = mask;
        res.payload.copy_payload(payload.as_ref().as_bytes(), &res.masker);
        res
    }

    pub fn is_empty(&self) -> bool { self.len() == 0 }

    pub fn len(&self) -> usize {
        let mut len = 2;
        if self.masker.mask {
            len += 4;
        }
        len += match self.masker.len_code {
            127 => 8,
            126 => 2,
            _ => 0
        };
        len += self.payload.len();
        len
    }

    pub fn from_buffer(buffer: &mut Buffer) -> HlsResult<WsFrame> {
        if buffer.len() < 2 { return Err(HlsError::InvalidHeadSize); }
        let mut res = WsFrame::default();
        res.typ = WsFrameType::from_u8(buffer.filled()[0])?;
        res.masker = Marker::from_u8(buffer.filled()[1]);
        res.payload = WsPayload::from_bytes(&res.masker, &buffer.filled()[2..])?;
        buffer.move_to(res.len()..buffer.len(), 0)?;
        Ok(res)
    }

    pub fn payload(&self) -> &WsPayload {
        &self.payload
    }

    pub fn frame_type(&self) -> &WsFrameType {
        &self.typ
    }

    pub fn to_bytes(self) -> Vec<u8> {
        let payload_len = self.payload.len();
        let payload = self.payload.to_bytes(&self.masker);
        let mut res = vec![self.typ.to_u8(), self.masker.into_inner(payload_len)];
        match payload.len() {
            126..0xFFFF => res.extend((payload_len as u16).to_be_bytes()),
            0xFFFF.. => res.extend((payload_len as u64).to_be_bytes()),
            _ => {}
        }
        res.extend(payload);
        res
    }
}