use std::io;
use crate::{
body::SizeHint,
http::header::{CONTENT_LENGTH, HeaderMap},
};
use super::frame::headers;
pub(crate) trait BodySize {
fn from_header(headers: &HeaderMap, is_end_stream: bool) -> Result<Self, ()>
where
Self: Sized;
fn dec(&mut self, len: usize) -> io::Result<()>;
fn ensure_zero(&self) -> io::Result<()>;
}
impl BodySize for SizeHint {
fn from_header(headers: &HeaderMap, is_end_stream: bool) -> Result<Self, ()> {
if is_end_stream {
Ok(Self::None)
} else {
match headers.get(CONTENT_LENGTH) {
Some(v) => {
let s = v.to_str().map_err(|_| ())?;
let len = headers::parse_u64(s.as_bytes())?;
Ok(Self::Exact(len))
}
None => Ok(Self::Unknown),
}
}
}
fn dec(&mut self, len: usize) -> io::Result<()> {
match self {
Self::Unknown => Ok(()),
Self::None => Err(io::Error::new(io::ErrorKind::InvalidData, "content-length exceeded")),
Self::Exact(rem) => {
*rem = rem
.checked_sub(len as u64)
.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "content-length exceeded"))?;
Ok(())
}
}
}
fn ensure_zero(&self) -> io::Result<()> {
match self {
Self::Unknown | Self::None | Self::Exact(0) => Ok(()),
Self::Exact(_) => Err(io::Error::new(io::ErrorKind::InvalidData, "content-length underflow")),
}
}
}