fire_http/
error.rs

1use crate::header::StatusCode;
2
3use std::error::Error as StdError;
4use std::{fmt, io};
5
6pub type Result<T> = std::result::Result<T, Error>;
7
8/// A universal error type which contains a source and a kind.
9///
10/// An error is either associated with the client or the server.
11#[derive(Debug)]
12pub struct Error {
13	kind: ErrorKind,
14	source: Option<Box<dyn StdError + Send + Sync>>,
15}
16
17impl Error {
18	/// Creates a new error.
19	pub fn new<K, E>(kind: K, error: E) -> Self
20	where
21		K: Into<ErrorKind>,
22		E: Into<Box<dyn StdError + Send + Sync>>,
23	{
24		Self {
25			kind: kind.into(),
26			source: Some(error.into()),
27		}
28	}
29
30	/// Creates a new error without a source.
31	pub fn empty<K>(kind: K) -> Self
32	where
33		K: Into<ErrorKind>,
34	{
35		Self {
36			kind: kind.into(),
37			source: None,
38		}
39	}
40
41	/// Returns the `StatusCode` corresponding to the `ErrorKind`.
42	pub fn status_code(&self) -> StatusCode {
43		match self.kind {
44			ErrorKind::Client(c) => c.into(),
45			ErrorKind::Server(s) => s.into(),
46		}
47	}
48
49	/// Returns a new error from an io::Error originating from the client.
50	pub fn from_client_io(error: io::Error) -> Self {
51		// try to detect if source is known to us
52		Self::new(ClientErrorKind::from_io(&error), error)
53	}
54
55	/// Returns a new error originating from the server.
56	pub fn from_server_error<E>(error: E) -> Self
57	where
58		E: Into<Box<dyn StdError + Send + Sync>>,
59	{
60		Self::new(ServerErrorKind::InternalServerError, error)
61	}
62}
63
64impl<T> From<T> for Error
65where
66	T: Into<ErrorKind>,
67{
68	fn from(e: T) -> Self {
69		Self::empty(e)
70	}
71}
72
73#[cfg(feature = "json")]
74mod deserialize_error {
75	use super::*;
76
77	use types::request::DeserializeError;
78
79	impl From<DeserializeError> for Error {
80		fn from(e: DeserializeError) -> Self {
81			Self::new(ClientErrorKind::BadRequest, e)
82		}
83	}
84}
85
86impl fmt::Display for Error {
87	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
88		fmt::Debug::fmt(self, f)
89	}
90}
91
92impl StdError for Error {
93	fn source(&self) -> Option<&(dyn StdError + 'static)> {
94		self.source.as_ref().map(|e| e.source()).flatten()
95	}
96}
97
98/// An error can either come from the client or the server.
99#[derive(Debug)]
100pub enum ErrorKind {
101	Client(ClientErrorKind),
102	Server(ServerErrorKind),
103}
104
105impl From<ClientErrorKind> for ErrorKind {
106	fn from(k: ClientErrorKind) -> Self {
107		Self::Client(k)
108	}
109}
110
111impl From<ServerErrorKind> for ErrorKind {
112	fn from(k: ServerErrorKind) -> Self {
113		Self::Server(k)
114	}
115}
116
117macro_rules! error_kind {
118	($name:ident, $($kind:ident => $status:ident),*) => (
119		#[derive(Debug, Clone, Copy, PartialEq, Eq)]
120		pub enum $name {
121			$($kind),*
122		}
123
124		impl From<$name> for StatusCode {
125			fn from(k: $name) -> Self {
126				match k {
127					$($name::$kind => Self::$status),*
128				}
129			}
130		}
131	)
132}
133
134// impl ClientErrorKind
135error_kind!( ClientErrorKind,
136	BadRequest => BAD_REQUEST,
137	Unauthorized => UNAUTHORIZED,
138	PaymentRequired => PAYMENT_REQUIRED,
139	Forbidden => FORBIDDEN,
140	NotFound => NOT_FOUND,
141	MethodNotAllowed => METHOD_NOT_ALLOWED,
142	NotAcceptable => NOT_ACCEPTABLE,
143	ProxyAuthenticationRequired => PROXY_AUTHENTICATION_REQUIRED,
144	RequestTimeout => REQUEST_TIMEOUT,
145	Conflict => CONFLICT,
146	Gone => GONE,
147	LengthRequired => LENGTH_REQUIRED,
148	PreconditionFailed => PRECONDITION_FAILED,
149	RequestEntityTooLarge => PAYLOAD_TOO_LARGE,
150	RequestURITooLarge => URI_TOO_LONG,
151	UnsupportedMediaType => UNSUPPORTED_MEDIA_TYPE,
152	RequestedRangeNotSatisfiable => RANGE_NOT_SATISFIABLE,
153	ExpectationFailed => EXPECTATION_FAILED
154);
155
156impl ClientErrorKind {
157	/// Converts an io::Error into the appropriate kind.
158	pub fn from_io(error: &io::Error) -> Self {
159		use io::ErrorKind::*;
160		match error.kind() {
161			NotFound => Self::NotFound,
162			PermissionDenied => Self::Unauthorized,
163			// this should probably not happen?
164			AlreadyExists => Self::Conflict,
165			UnexpectedEof => Self::RequestEntityTooLarge,
166			InvalidInput | InvalidData | Other => Self::BadRequest,
167			TimedOut => Self::RequestTimeout,
168			_ => Self::ExpectationFailed,
169		}
170	}
171}
172
173// Impl ServerErrorKind
174error_kind!( ServerErrorKind,
175	InternalServerError => INTERNAL_SERVER_ERROR,
176	NotImplemented => NOT_IMPLEMENTED,
177	BadGateway => BAD_GATEWAY,
178	ServiceUnavailable => SERVICE_UNAVAILABLE,
179	GatewayTimeout => GATEWAY_TIMEOUT
180);