use base_http::Status;
use base_web_content::Rejection;
use std::{error::Error, fmt};
#[derive(Debug)]
#[non_exhaustive]
pub struct ReadError<B, S> {
pub kind: ReadErrorKind<B, S>,
pub cleanup: Vec<S>,
}
#[derive(Debug)]
#[non_exhaustive]
pub enum ReadErrorKind<B, S> {
InvalidMediaType,
ContentTooLarge {
length: u64,
limit: u64,
},
Rejected(Rejection),
Body(B),
Store(S),
}
impl<B, S> ReadError<B, S> {
pub(crate) fn new(kind: ReadErrorKind<B, S>) -> Self {
Self {
kind,
cleanup: Vec::new(),
}
}
pub fn status(&self) -> Status {
match &self.kind {
ReadErrorKind::InvalidMediaType | ReadErrorKind::Body(_) => Status::BAD_REQUEST,
ReadErrorKind::ContentTooLarge { .. } => Status::CONTENT_TOO_LARGE,
ReadErrorKind::Rejected(Rejection::Error(error)) => {
Status::new(error.status()).unwrap_or(Status::BAD_REQUEST)
}
ReadErrorKind::Rejected(Rejection::Violations(_)) => Status::UNPROCESSABLE_CONTENT,
ReadErrorKind::Store(_) => Status::INTERNAL_SERVER_ERROR,
}
}
}
impl<B, S> fmt::Display for ReadError<B, S> {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
let described = match &self.kind {
ReadErrorKind::InvalidMediaType => {
formatter.write_str("request has an invalid Content-Type")
}
ReadErrorKind::ContentTooLarge { length, limit } => write!(
formatter,
"request length {length} exceeds the largest body its declaration accepts, {limit}"
),
ReadErrorKind::Rejected(rejection) => rejection.fmt(formatter),
ReadErrorKind::Body(_) => formatter.write_str("failed to read the request body"),
ReadErrorKind::Store(_) => formatter.write_str("failed to store an upload"),
};
described.and_then(|()| match self.cleanup.len() {
0 => Ok(()),
1 => formatter.write_str(", and 1 failure to remove a stored upload"),
count => write!(formatter, ", and {count} failures to remove stored uploads"),
})
}
}
impl<B: Error + 'static, S: Error + 'static> Error for ReadError<B, S> {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match &self.kind {
ReadErrorKind::Body(error) => Some(error),
ReadErrorKind::Store(error) => Some(error),
_ => None,
}
}
}