1use std::convert::Infallible;
49use std::error::Error as StdError;
50use std::fmt::{self, Display, Formatter};
51use std::io::Error as IoError;
52
53use crate::http::{ParseError, StatusError};
54use crate::{Response, Scribe};
55
56pub type BoxedError = Box<dyn StdError + Send + Sync>;
61
62#[derive(Debug)]
97#[non_exhaustive]
98pub enum Error {
99 Hyper(hyper::Error),
103 HttpParse(ParseError),
107 HttpStatus(StatusError),
112 Io(IoError),
116 SerdeJson(serde_json::Error),
118 InvalidUri(http::uri::InvalidUri),
122 #[cfg(feature = "quinn")]
124 #[cfg_attr(docsrs, doc(cfg(feature = "quinn")))]
125 H3Connection(salvo_http3::error::ConnectionError),
126 #[cfg(feature = "quinn")]
128 #[cfg_attr(docsrs, doc(cfg(feature = "quinn")))]
129 H3Stream(salvo_http3::error::StreamError),
130 #[cfg(feature = "quinn")]
132 #[cfg_attr(docsrs, doc(cfg(feature = "quinn")))]
133 H3SendDatagram(h3_datagram::datagram_handler::SendDatagramError),
134 #[cfg(feature = "anyhow")]
136 #[cfg_attr(docsrs, doc(cfg(feature = "anyhow")))]
137 Anyhow(anyhow::Error),
138 #[cfg(feature = "eyre")]
140 #[cfg_attr(docsrs, doc(cfg(feature = "eyre")))]
141 Eyre(eyre::Report),
142 Other(BoxedError),
146}
147
148impl Error {
149 #[inline]
173 pub fn other(error: impl Into<BoxedError>) -> Self {
174 Self::Other(error.into())
175 }
176}
177impl Display for Error {
178 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
179 match self {
180 Self::Hyper(e) => Display::fmt(e, f),
181 Self::HttpParse(e) => Display::fmt(e, f),
182 Self::HttpStatus(e) => Display::fmt(e, f),
183 Self::Io(e) => Display::fmt(e, f),
184 Self::SerdeJson(e) => Display::fmt(e, f),
185 Self::InvalidUri(e) => Display::fmt(e, f),
186 #[cfg(feature = "quinn")]
187 Self::H3Connection(e) => Display::fmt(e, f),
188 #[cfg(feature = "quinn")]
189 Self::H3Stream(e) => Display::fmt(e, f),
190 #[cfg(feature = "quinn")]
191 Self::H3SendDatagram(e) => Display::fmt(e, f),
192 #[cfg(feature = "anyhow")]
193 Self::Anyhow(e) => Display::fmt(e, f),
194 #[cfg(feature = "eyre")]
195 Self::Eyre(e) => Display::fmt(e, f),
196 Self::Other(e) => Display::fmt(e, f),
197 }
198 }
199}
200
201impl StdError for Error {}
202
203impl From<Infallible> for Error {
204 #[inline]
205 fn from(infallible: Infallible) -> Self {
206 match infallible {}
207 }
208}
209impl From<hyper::Error> for Error {
210 #[inline]
211 fn from(e: hyper::Error) -> Self {
212 Self::Hyper(e)
213 }
214}
215impl From<ParseError> for Error {
216 #[inline]
217 fn from(d: ParseError) -> Self {
218 Self::HttpParse(d)
219 }
220}
221impl From<StatusError> for Error {
222 #[inline]
223 fn from(e: StatusError) -> Self {
224 Self::HttpStatus(e)
225 }
226}
227impl From<IoError> for Error {
228 #[inline]
229 fn from(e: IoError) -> Self {
230 Self::Io(e)
231 }
232}
233impl From<http::uri::InvalidUri> for Error {
234 #[inline]
235 fn from(e: http::uri::InvalidUri) -> Self {
236 Self::InvalidUri(e)
237 }
238}
239impl From<serde_json::Error> for Error {
240 #[inline]
241 fn from(e: serde_json::Error) -> Self {
242 Self::SerdeJson(e)
243 }
244}
245cfg_feature! {
246 #![feature = "quinn"]
247 impl From<salvo_http3::error::ConnectionError> for Error {
248 #[inline]
249 fn from(e: salvo_http3::error::ConnectionError) -> Self {
250 Self::H3Connection(e)
251 }
252 }
253 impl From<salvo_http3::error::StreamError> for Error {
254 #[inline]
255 fn from(e: salvo_http3::error::StreamError) -> Self {
256 Self::H3Stream(e)
257 }
258 }
259 impl From<h3_datagram::datagram_handler::SendDatagramError> for Error {
260 #[inline]
261 fn from(e: h3_datagram::datagram_handler::SendDatagramError) -> Self {
262 Self::H3SendDatagram(e)
263 }
264 }
265}
266cfg_feature! {
267 #![feature = "anyhow"]
268 impl From<anyhow::Error> for Error {
269 #[inline]
270 fn from(e: anyhow::Error) -> Self {
271 Self::Anyhow(e)
272 }
273 }
274}
275cfg_feature! {
276 #![feature = "eyre"]
277 impl From<eyre::Report> for Error {
278 #[inline]
279 fn from(e: eyre::Report) -> Self {
280 Self::Eyre(e)
281 }
282 }
283}
284
285impl From<BoxedError> for Error {
286 #[inline]
287 fn from(e: BoxedError) -> Self {
288 Self::Other(e)
289 }
290}
291
292impl Scribe for Error {
293 fn render(self, res: &mut Response) {
294 let status_error = match self {
295 Self::HttpStatus(e) => e,
296 _ => StatusError::internal_server_error().cause(self),
297 };
298 res.render(status_error);
299 }
300}
301cfg_feature! {
302 #![feature = "anyhow"]
303 impl Scribe for anyhow::Error {
304 #[inline]
305 fn render(self, res: &mut Response) {
306 tracing::error!(error = ?self, "anyhow error occurred");
307 res.render(StatusError::internal_server_error().origin(self));
308 }
309 }
310}
311cfg_feature! {
312 #![feature = "eyre"]
313 impl Scribe for eyre::Report {
314 #[inline]
315 fn render(self, res: &mut Response) {
316 tracing::error!(error = ?self, "eyre error occurred");
317 res.render(StatusError::internal_server_error().cause(self));
318 }
319 }
320}
321
322#[cfg(test)]
323mod tests {
324 use std::str::FromStr;
325
326 use super::*;
327 use crate::http::*;
328 use crate::{Depot, Writer};
329
330 #[tokio::test]
331 #[cfg(feature = "anyhow")]
332 async fn test_anyhow() {
333 let mut req = Request::default();
334 let mut res = Response::default();
335 let mut depot = Depot::new();
336 let e: anyhow::Error = anyhow::anyhow!("detail message");
337 e.write(&mut req, &mut depot, &mut res).await;
338 assert_eq!(res.status_code, Some(StatusCode::INTERNAL_SERVER_ERROR));
339 }
340
341 #[tokio::test]
342 #[cfg(feature = "eyre")]
343 async fn test_eyre() {
344 let mut req = Request::default();
345 let mut res = Response::default();
346 let mut depot = Depot::new();
347 let e: eyre::Report = eyre::Report::msg("detail message");
348 e.write(&mut req, &mut depot, &mut res).await;
349 assert_eq!(res.status_code, Some(StatusCode::INTERNAL_SERVER_ERROR));
350 }
351
352 #[tokio::test]
353 async fn test_error() {
354 let mut req = Request::default();
355 let mut res = Response::default();
356 let mut depot = Depot::new();
357
358 let e = Error::Other(Box::new(std::io::Error::new(
359 std::io::ErrorKind::Other,
360 "detail message",
361 )));
362 e.write(&mut req, &mut depot, &mut res).await;
363 assert_eq!(res.status_code, Some(StatusCode::INTERNAL_SERVER_ERROR));
364 }
365
366 #[test]
367 fn test_error_from() {
368 use std::io;
369
370 let err: Error = io::Error::new(io::ErrorKind::Other, "oh no!").into();
371 assert!(matches!(err, Error::Io(_)));
372
373 let err: Error = ParseError::ParseFromStr.into();
374 assert!(matches!(err, Error::HttpParse(_)));
375
376 let err: Error = StatusError::bad_request().into();
377 assert!(matches!(err, Error::HttpStatus(_)));
378
379 let err: Error = serde_json::from_str::<serde_json::Value>("{")
380 .unwrap_err()
381 .into();
382 assert!(matches!(err, Error::SerdeJson(_)));
383
384 let err: Error = http::Uri::from_str("ht tp://host.com").unwrap_err().into();
385 assert!(matches!(err, Error::InvalidUri(_)));
386
387 let err: Error = Error::other(Box::new(std::io::Error::new(
388 std::io::ErrorKind::Other,
389 "custom error",
390 )));
391 assert!(matches!(err, Error::Other(_)));
392 }
393
394 #[test]
395 fn test_error_display() {
396 use std::io;
397
398 let err: Error = io::Error::new(io::ErrorKind::Other, "io error").into();
399 assert_eq!(format!("{}", err), "io error");
400
401 let err: Error = ParseError::ParseFromStr.into();
402 assert_eq!(format!("{}", err), "Parse error when parse from str.");
403
404 let err: Error = StatusError::bad_request().brief("status error").into();
405 assert!(format!("{}", err).contains("status error"));
406 }
407
408 #[tokio::test]
409 async fn test_error_scribe() {
410 let mut req = Request::default();
411 let mut res = Response::default();
412 let mut depot = Depot::new();
413
414 let e = Error::from(StatusError::bad_request());
415 e.write(&mut req, &mut depot, &mut res).await;
416 assert_eq!(res.status_code, Some(StatusCode::BAD_REQUEST));
417
418 let mut res = Response::default();
419 let e = std::io::Error::new(std::io::ErrorKind::Other, "io error");
420 Error::from(e).write(&mut req, &mut depot, &mut res).await;
421 assert_eq!(res.status_code, Some(StatusCode::INTERNAL_SERVER_ERROR));
422 }
423}