base_http_content/
read_error.rs1use base_http::Status;
5use base_web_content::Rejection;
6use std::{error::Error, fmt};
7
8#[derive(Debug)]
12#[non_exhaustive]
13pub struct ReadError<B, S> {
14 pub kind: ReadErrorKind<B, S>,
16 pub cleanup: Vec<S>,
18}
19
20#[derive(Debug)]
22#[non_exhaustive]
23pub enum ReadErrorKind<B, S> {
24 InvalidMediaType,
26 ContentTooLarge {
28 length: u64,
30 limit: u64,
32 },
33 Rejected(Rejection),
35 Body(B),
37 Store(S),
39}
40
41impl<B, S> ReadError<B, S> {
42 pub(crate) fn new(kind: ReadErrorKind<B, S>) -> Self {
43 Self {
44 kind,
45 cleanup: Vec::new(),
46 }
47 }
48
49 pub fn status(&self) -> Status {
51 match &self.kind {
52 ReadErrorKind::InvalidMediaType | ReadErrorKind::Body(_) => Status::BAD_REQUEST,
53 ReadErrorKind::ContentTooLarge { .. } => Status::CONTENT_TOO_LARGE,
54 ReadErrorKind::Rejected(Rejection::Error(error)) => {
55 Status::new(error.status()).unwrap_or(Status::BAD_REQUEST)
56 }
57 ReadErrorKind::Rejected(Rejection::Violations(_)) => Status::UNPROCESSABLE_CONTENT,
58 ReadErrorKind::Store(_) => Status::INTERNAL_SERVER_ERROR,
59 }
60 }
61}
62
63impl<B, S> fmt::Display for ReadError<B, S> {
64 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
65 let described = match &self.kind {
66 ReadErrorKind::InvalidMediaType => {
67 formatter.write_str("request has an invalid Content-Type")
68 }
69 ReadErrorKind::ContentTooLarge { length, limit } => write!(
70 formatter,
71 "request length {length} exceeds the largest body its declaration accepts, {limit}"
72 ),
73 ReadErrorKind::Rejected(rejection) => rejection.fmt(formatter),
74 ReadErrorKind::Body(_) => formatter.write_str("failed to read the request body"),
75 ReadErrorKind::Store(_) => formatter.write_str("failed to store an upload"),
76 };
77 described.and_then(|()| match self.cleanup.len() {
78 0 => Ok(()),
79 1 => formatter.write_str(", and 1 failure to remove a stored upload"),
80 count => write!(formatter, ", and {count} failures to remove stored uploads"),
81 })
82 }
83}
84
85impl<B: Error + 'static, S: Error + 'static> Error for ReadError<B, S> {
87 fn source(&self) -> Option<&(dyn Error + 'static)> {
88 match &self.kind {
89 ReadErrorKind::Body(error) => Some(error),
90 ReadErrorKind::Store(error) => Some(error),
91 _ => None,
92 }
93 }
94}