use bytes::{Buf, BufMut};
use thiserror::Error as ThisError;
mod builder;
mod parser;
pub use builder::*;
pub use parser::*;
const CONTENT_TERMINATOR: u8 = 0x00;
#[derive(ThisError, Debug, PartialEq, Eq, Clone, Copy)]
pub enum Error {
#[error("Provided buffer is too short")]
ShortBuf,
#[error("Input data is invalid")]
InvalidInput,
#[error("Unexpected state in message builder")]
UnexpectedBuildState,
#[error("Unexpected framing")]
UnexpectedFraming,
}
type Result<T> = std::result::Result<T, Error>;
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[repr(u8)]
pub enum Framing {
KnownLenReq = 0,
KnownLenRes = 1,
IndLenReq = 2,
IndLenRes = 3,
}
impl Framing {
pub fn known_len(&self) -> bool {
*self == Self::KnownLenReq || *self == Self::KnownLenRes
}
pub fn is_request(&self) -> bool {
*self == Self::KnownLenReq || *self == Self::IndLenReq
}
}
impl TryFrom<u8> for Framing {
type Error = Error;
fn try_from(n: u8) -> Result<Self> {
match n {
0 => Ok(Self::KnownLenReq),
1 => Ok(Self::KnownLenRes),
2 => Ok(Self::IndLenReq),
3 => Ok(Self::IndLenRes),
_ => Err(Error::InvalidInput),
}
}
}
fn is_final_ctrl(status: usize) -> bool {
status >= 200
}
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
struct VarInt(u64);
impl VarInt {
const MAX: u64 = (1 << 62) - 1;
fn as_usize(&self) -> usize {
self.0 as usize
}
fn size(&self) -> usize {
match self.0 {
0..=0x3f => 1,
0x40..=0x3fff => 2,
0x4000..=0x3fff_ffff => 3,
0x4000_0000.. => 4,
}
}
}
impl From<VarInt> for u64 {
fn from(v: VarInt) -> Self {
v.0
}
}
impl TryFrom<u64> for VarInt {
type Error = Error;
fn try_from(n: u64) -> Result<Self> {
if n > Self::MAX {
Err(Error::InvalidInput)
} else {
Ok(Self(n))
}
}
}
impl TryFrom<usize> for VarInt {
type Error = Error;
fn try_from(n: usize) -> Result<Self> {
let n = u64::try_from(n).map_err(|_| Error::InvalidInput)?;
Self::try_from(n)
}
}
impl VarInt {
fn parse<B: Buf>(buf: &mut B) -> Result<Self> {
if !buf.has_remaining() {
return Err(Error::InvalidInput);
}
let b = buf.chunk()[0];
let n = 1 << (b >> 6);
if buf.remaining() < n {
return Err(Error::InvalidInput);
}
Ok(Self(match n {
1 => (buf.get_u8() & ((1 << 6) - 1)).into(),
2 => (buf.get_u16() & ((1 << 14) - 1)).into(),
4 => (buf.get_u32() & ((1 << 30) - 1)).into(),
8 => buf.get_u64() & ((1 << 62) - 1),
_ => unreachable!(),
}))
}
fn compose<B: BufMut>(&self, buf: &mut B) -> Result<()> {
let len = buf.remaining_mut();
match self.0 {
0..=0x3f if len > 0 => buf.put_u8(self.0 as u8),
0x40..=0x3fff if len > 1 => buf.put_u16((self.0 | (0b01 << 14)) as u16),
0x4000..=0x3fff_ffff if len > 3 => buf.put_u32((self.0 | (0b10 << 30)) as u32),
0x4000_0000..=0x3fff_ffff_ffff_ffff if len >= 8 => buf.put_u64(self.0 | (0b11 << 62)),
Self::MAX.. => return Err(Error::InvalidInput),
_ => return Err(Error::ShortBuf),
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use hex_literal::hex;
use rstest::*;
use std::str::from_utf8;
pub(crate) fn unwrap_fieldline<'a>(
f: Option<Result<(&'a [u8], &'a [u8])>>,
) -> (&'a str, &'a str) {
let (k, v) = f.unwrap().unwrap();
(from_utf8(k).unwrap(), from_utf8(v).unwrap())
}
pub(crate) const EXAMPLE_KNOWN_LEN_REQ1: &[u8] = hex!(
"
00034745 54056874 7470730b 6578616d
706c652e 636f6d01 2f
"
)
.as_slice();
pub(crate) const EXAMPLE_KNOWN_LEN_REQ2: &[u8] = hex!(
"
00034745 54056874 74707300 0a2f6865
6c6c6f2e 74787440 6c0a7573 65722d61
67656e74 34637572 6c2f372e 31362e33
206c6962 6375726c 2f372e31 362e3320
4f70656e 53534c2f 302e392e 376c207a
6c69622f 312e322e 3304686f 73740f77
77772e65 78616d70 6c652e63 6f6d0f61
63636570 742d6c61 6e677561 67650665
6e2c206d 690000
"
)
.as_slice();
pub(crate) const EXAMPLE_IND_LEN_REQ1: &[u8] = hex!(
"
02034745 54056874 74707300 0a2f6865
6c6c6f2e 7478740a 75736572 2d616765
6e743463 75726c2f 372e3136 2e33206c
69626375 726c2f37 2e31362e 33204f70
656e5353 4c2f302e 392e376c 207a6c69
622f312e 322e3304 686f7374 0f777777
2e657861 6d706c65 2e636f6d 0f616363
6570742d 6c616e67 75616765 06656e2c
206d6900 00000000 00000000 00000000
"
)
.as_slice();
pub(crate) const EXAMPLE_IND_LEN_REQ2: &[u8] = hex!(
"
02034745 54056874 74707300 0a2f6865
6c6c6f2e 7478740a 75736572 2d616765
6e743463 75726c2f 372e3136 2e33206c
69626375 726c2f37 2e31362e 33204f70
656e5353 4c2f302e 392e376c 207a6c69
622f312e 322e3304 686f7374 0f777777
2e657861 6d706c65 2e636f6d 0f616363
6570742d 6c616e67 75616765 06656e2c
206d6900
"
)
.as_slice();
pub(crate) const EXAMPLE_KNOWN_LEN_RES1: &[u8] = hex!(
"
0140c800 1d546869 7320636f 6e74656e
7420636f 6e746169 6e732043 524c462e
0d0a0d07 74726169 6c657204 74657874
"
)
.as_slice();
pub(crate) const EXAMPLE_IND_LEN_RES1: &[u8] = hex!(
"
03406607 72756e6e 696e670a 22736c65
65702031 35220040 67046c69 6e6b233c
2f737479 6c652e63 73733e3b 2072656c
3d707265 6c6f6164 3b206173 3d737479
6c65046c 696e6b24 3c2f7363 72697074
2e6a733e 3b207265 6c3d7072 656c6f61
643b2061 733d7363 72697074 0040c804
64617465 1d4d6f6e 2c203237 204a756c
20323030 39203132 3a32383a 35332047
4d540673 65727665 72064170 61636865
0d6c6173 742d6d6f 64696669 65641d57
65642c20 3232204a 756c2032 30303920
31393a31 353a3536 20474d54 04657461
67142233 34616133 38372d64 2d313536
38656230 30220d61 63636570 742d7261
6e676573 05627974 65730e63 6f6e7465
6e742d6c 656e6774 68023531 04766172
790f4163 63657074 2d456e63 6f64696e
670c636f 6e74656e 742d7479 70650a74
6578742f 706c6169 6e003348 656c6c6f
20576f72 6c642120 4d792063 6f6e7465
6e742069 6e636c75 64657320 61207472
61696c69 6e672043 524c462e 0d0a0000
"
)
.as_slice();
#[rstest]
#[case(&[0x00], Ok(0x00))]
#[case(&[0x01, 0x02, 0x03], Ok(0x01))]
#[case(&[0x40, 0xff], Ok(0xff))]
#[case(&[0x80, 0xad, 0xbe, 0xef], Ok(0x00adbeef))]
#[case(&[0xc0], Err(Error::InvalidInput))]
fn varint_parse(#[case] slice: &[u8], #[case] exp: Result<u64>) {
let mut buf = slice;
assert_eq!(exp, VarInt::parse(&mut buf).map(|v| v.into()))
}
#[rstest]
#[case(0x00, 1, Ok(&hex!("00")[..]))]
#[case(0x3f, 1, Ok(&hex!("3f")[..]))]
#[case(1 << 8, 2, Ok(&hex!("4100")[..]))]
#[case(1 << 16, 4, Ok(&hex!("80010000")[..]))]
#[case(1 << 32, 8, Ok(&hex!("c000000100000000")[..]))]
#[case(1 << 16, 1, Err(Error::ShortBuf))]
fn varint_compose(#[case] num: u64, #[case] buf_len: usize, #[case] exp_hex: Result<&[u8]>) {
let mut buf = vec![0xff; buf_len];
let mut slice_mut = buf.as_mut_slice();
let len = slice_mut.len();
let r = VarInt::try_from(num).unwrap().compose(&mut slice_mut);
let new_len = slice_mut.len();
assert_eq!(exp_hex, r.map(|_| &buf[..len - new_len]));
}
}