use crate::pb::Trailer;
use bytes::{Buf, BufMut, Bytes, BytesMut};
use prost::Message;
pub const LEN_PREFIX: usize = 4;
#[derive(Debug, thiserror::Error)]
pub enum FetchError {
#[error("response body exceeds configured size limit ({limit} bytes)")]
TooLarge { limit: usize },
#[error("response body truncated: expected {expected} more bytes, had {had}")]
Truncated { expected: usize, had: usize },
#[error("failed to decode Trailer: {0}")]
Decode(#[from] prost::DecodeError),
}
pub fn encode_response_body(message: &[u8], trailer: &Trailer) -> Bytes {
let trailer_len = trailer.encoded_len();
let mut buf = BytesMut::with_capacity(LEN_PREFIX + message.len() + LEN_PREFIX + trailer_len);
buf.put_u32(message.len() as u32);
buf.put_slice(message);
buf.put_u32(trailer_len as u32);
trailer.encode(&mut buf).expect("BytesMut has capacity");
buf.freeze()
}
pub const EMPTY_MESSAGE_BLOCK: [u8; LEN_PREFIX] = [0; LEN_PREFIX];
pub fn encode_request_body(message: &[u8]) -> Bytes {
let mut buf = BytesMut::with_capacity(LEN_PREFIX + message.len());
buf.put_u32(message.len() as u32);
buf.put_slice(message);
buf.freeze()
}
pub fn encode_trailer_block(trailer: &Trailer) -> Bytes {
let trailer_len = trailer.encoded_len();
let mut buf = BytesMut::with_capacity(LEN_PREFIX + trailer_len);
buf.put_u32(trailer_len as u32);
trailer.encode(&mut buf).expect("BytesMut has capacity");
buf.freeze()
}
pub fn decode_response_body(mut body: Bytes, limit: usize) -> Result<(Bytes, Trailer), FetchError> {
if body.len() > limit {
return Err(FetchError::TooLarge { limit });
}
let message = take_block(&mut body)?;
let trailer_bytes = take_block(&mut body)?;
let trailer = Trailer::decode(trailer_bytes)?;
Ok((message, trailer))
}
fn take_block(body: &mut Bytes) -> Result<Bytes, FetchError> {
if body.remaining() < LEN_PREFIX {
return Err(FetchError::Truncated {
expected: LEN_PREFIX,
had: body.remaining(),
});
}
let len = body.get_u32() as usize;
if body.remaining() < len {
return Err(FetchError::Truncated {
expected: len,
had: body.remaining(),
});
}
Ok(body.split_to(len))
}