1use std::{
4 convert::Infallible,
5 error::Error as StdError,
6 fmt::{self, Debug, Display, Formatter},
7 string::FromUtf8Error,
8};
9
10use headers::{ContentRange, HeaderMapExt};
11use http::{Extensions, Method};
12
13use crate::{http::StatusCode, IntoResponse, Response};
14
15macro_rules! define_http_error {
16 ($($(#[$docs:meta])* ($name:ident, $status:ident);)*) => {
17 $(
18 $(#[$docs])*
19 #[allow(non_snake_case)]
20 #[inline]
21 pub fn $name(err: impl StdError + Send + Sync + 'static) -> Error {
22 Error::new(err, StatusCode::$status)
23 }
24 )*
25 };
26}
27
28pub trait ResponseError {
30 fn status(&self) -> StatusCode;
32
33 fn as_response(&self) -> Response
35 where
36 Self: StdError + Send + Sync + 'static,
37 {
38 let mut resp = self.to_string().into_response();
39 resp.set_status(self.status());
40 resp
41 }
42}
43
44enum ErrorSource {
45 BoxedError(Box<dyn StdError + Send + Sync>),
46 #[cfg(feature = "anyhow")]
47 Anyhow(anyhow::Error),
48 #[cfg(feature = "eyre06")]
49 Eyre06(eyre06::Report),
50}
51
52impl Debug for ErrorSource {
53 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
54 match self {
55 ErrorSource::BoxedError(err) => Debug::fmt(err, f),
56 #[cfg(feature = "anyhow")]
57 ErrorSource::Anyhow(err) => Debug::fmt(err, f),
58 #[cfg(feature = "eyre06")]
59 ErrorSource::Eyre06(err) => Debug::fmt(err, f),
60 }
61 }
62}
63
64type AsResponseFn = fn(&Error) -> Response;
65type GetStatusFn = fn(&Error) -> StatusCode;
66
67enum AsResponse {
68 Status(StatusCode),
69 Fn(AsResponseFn, GetStatusFn),
70 Response(Response),
71}
72
73impl AsResponse {
74 #[inline]
75 fn from_status(status: StatusCode) -> Self {
76 AsResponse::Status(status)
77 }
78
79 fn from_type<T: ResponseError + StdError + Send + Sync + 'static>() -> Self {
80 AsResponse::Fn(
81 |err| {
82 let err = err.downcast_ref::<T>().expect("valid error");
83 err.as_response()
84 },
85 |err| {
86 let err = err.downcast_ref::<T>().expect("valid error");
87 err.status()
88 },
89 )
90 }
91}
92
93pub struct Error {
190 as_response: AsResponse,
191 source: Option<ErrorSource>,
192 extensions: Extensions,
193 msg: Option<String>,
194}
195
196impl Debug for Error {
197 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
198 f.debug_struct("Error")
199 .field("source", &self.source)
200 .finish()
201 }
202}
203
204impl Display for Error {
205 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
206 if let Some(msg) = &self.msg {
207 return write!(f, "{msg}");
208 }
209
210 match &self.source {
211 Some(ErrorSource::BoxedError(err)) => Display::fmt(err, f),
212 #[cfg(feature = "anyhow")]
213 Some(ErrorSource::Anyhow(err)) => write!(f, "{err:#}"),
214 #[cfg(feature = "eyre06")]
215 Some(ErrorSource::Eyre06(err)) => Display::fmt(err, f),
216 None => write!(f, "{}", self.status()),
217 }
218 }
219}
220
221impl StdError for Error {
222 fn source(&self) -> Option<&(dyn StdError + 'static)> {
223 match &self.source {
224 Some(ErrorSource::BoxedError(err)) => Some(err.as_ref()),
225 #[cfg(feature = "anyhow")]
226 Some(ErrorSource::Anyhow(err)) => Some(err.as_ref()),
227 #[cfg(feature = "eyre06")]
228 Some(ErrorSource::Eyre06(err)) => Some(err.as_ref()),
229 None => None,
230 }
231 }
232}
233
234impl From<Infallible> for Error {
235 fn from(_: Infallible) -> Self {
236 unreachable!()
237 }
238}
239
240impl<T: ResponseError + StdError + Send + Sync + 'static> From<T> for Error {
241 fn from(err: T) -> Self {
242 Error {
243 as_response: AsResponse::from_type::<T>(),
244 source: Some(ErrorSource::BoxedError(Box::new(err))),
245 extensions: Extensions::default(),
246 msg: None,
247 }
248 }
249}
250
251impl From<Box<dyn StdError + Send + Sync>> for Error {
252 fn from(err: Box<dyn StdError + Send + Sync>) -> Self {
253 (StatusCode::INTERNAL_SERVER_ERROR, err).into()
254 }
255}
256
257impl From<(StatusCode, Box<dyn StdError + Send + Sync>)> for Error {
258 fn from((status, err): (StatusCode, Box<dyn StdError + Send + Sync>)) -> Self {
259 Error {
260 as_response: AsResponse::from_status(status),
261 source: Some(ErrorSource::BoxedError(err)),
262 extensions: Extensions::default(),
263 msg: None,
264 }
265 }
266}
267
268#[cfg(feature = "anyhow")]
269impl From<anyhow::Error> for Error {
270 fn from(err: anyhow::Error) -> Self {
271 Error {
272 as_response: AsResponse::from_status(StatusCode::INTERNAL_SERVER_ERROR),
273 source: Some(ErrorSource::Anyhow(err)),
274 extensions: Extensions::default(),
275 msg: None,
276 }
277 }
278}
279
280#[cfg(feature = "eyre06")]
281impl From<eyre06::Error> for Error {
282 fn from(err: eyre06::Error) -> Self {
283 Error {
284 as_response: AsResponse::from_status(StatusCode::INTERNAL_SERVER_ERROR),
285 source: Some(ErrorSource::Eyre06(err)),
286 extensions: Extensions::default(),
287 msg: None,
288 }
289 }
290}
291
292#[cfg(feature = "anyhow")]
293impl From<(StatusCode, anyhow::Error)> for Error {
294 fn from((status, err): (StatusCode, anyhow::Error)) -> Self {
295 Error {
296 as_response: AsResponse::from_status(status),
297 source: Some(ErrorSource::Anyhow(err)),
298 extensions: Extensions::default(),
299 msg: None,
300 }
301 }
302}
303
304#[cfg(feature = "eyre06")]
305impl From<(StatusCode, eyre06::Report)> for Error {
306 fn from((status, err): (StatusCode, eyre06::Report)) -> Self {
307 Error {
308 as_response: AsResponse::from_status(status),
309 source: Some(ErrorSource::Eyre06(err)),
310 extensions: Extensions::default(),
311 msg: None,
312 }
313 }
314}
315
316impl From<StatusCode> for Error {
317 fn from(status: StatusCode) -> Self {
318 Error::from_status(status)
319 }
320}
321
322impl Error {
323 #[inline]
325 pub fn new<T: StdError + Send + Sync + 'static>(err: T, status: StatusCode) -> Self {
326 Self {
327 as_response: AsResponse::from_status(status),
328 source: Some(ErrorSource::BoxedError(Box::new(err))),
329 extensions: Extensions::default(),
330 msg: None,
331 }
332 }
333
334 pub fn from_response(resp: Response) -> Self {
336 Self {
337 as_response: AsResponse::Response(resp),
338 source: None,
339 extensions: Extensions::default(),
340 msg: None,
341 }
342 }
343
344 pub fn from_status(status: StatusCode) -> Self {
346 #[derive(Debug, thiserror::Error)]
347 #[error("{0}")]
348 struct StatusError(StatusCode);
349
350 impl ResponseError for StatusError {
351 fn status(&self) -> StatusCode {
352 self.0
353 }
354
355 fn as_response(&self) -> Response
356 where
357 Self: StdError + Send + Sync + 'static,
358 {
359 self.0.into_response()
360 }
361 }
362
363 StatusError(status).into()
364 }
365
366 pub fn from_string(msg: impl Into<String>, status: StatusCode) -> Self {
368 #[derive(Debug, thiserror::Error)]
369 #[error("{0}")]
370 struct StringError(String);
371
372 Self::new(StringError(msg.into()), status)
373 }
374
375 #[inline]
377 pub fn downcast_ref<T: StdError + Send + Sync + 'static>(&self) -> Option<&T> {
378 match &self.source {
379 Some(ErrorSource::BoxedError(err)) => err.downcast_ref::<T>(),
380 #[cfg(feature = "anyhow")]
381 Some(ErrorSource::Anyhow(err)) => err.downcast_ref::<T>(),
382 #[cfg(feature = "eyre06")]
383 Some(ErrorSource::Eyre06(err)) => err.downcast_ref::<T>(),
384 None => None,
385 }
386 }
387
388 #[inline]
390 pub fn downcast<T: StdError + Send + Sync + 'static>(self) -> Result<T, Error> {
391 let as_response = self.as_response;
392 let extensions = self.extensions;
393 let msg = self.msg;
394
395 match self.source {
396 Some(ErrorSource::BoxedError(err)) => match err.downcast::<T>() {
397 Ok(err) => Ok(*err),
398 Err(err) => Err(Error {
399 as_response,
400 source: Some(ErrorSource::BoxedError(err)),
401 extensions,
402 msg,
403 }),
404 },
405 #[cfg(feature = "anyhow")]
406 Some(ErrorSource::Anyhow(err)) => match err.downcast::<T>() {
407 Ok(err) => Ok(err),
408 Err(err) => Err(Error {
409 as_response,
410 source: Some(ErrorSource::Anyhow(err)),
411 extensions,
412 msg,
413 }),
414 },
415 #[cfg(feature = "eyre06")]
416 Some(ErrorSource::Eyre06(err)) => match err.downcast::<T>() {
417 Ok(err) => Ok(err),
418 Err(err) => Err(Error {
419 as_response,
420 source: Some(ErrorSource::Eyre06(err)),
421 extensions,
422 msg,
423 }),
424 },
425 None => Err(Error {
426 as_response,
427 source: None,
428 extensions,
429 msg,
430 }),
431 }
432 }
433
434 #[inline]
436 pub fn is<T: StdError + Debug + Send + Sync + 'static>(&self) -> bool {
437 match &self.source {
438 Some(ErrorSource::BoxedError(err)) => err.is::<T>(),
439 #[cfg(feature = "anyhow")]
440 Some(ErrorSource::Anyhow(err)) => err.is::<T>(),
441 #[cfg(feature = "eyre06")]
442 Some(ErrorSource::Eyre06(err)) => err.is::<T>(),
443 None => false,
444 }
445 }
446
447 pub fn into_response(self) -> Response {
449 let mut resp = match self.as_response {
450 AsResponse::Status(status) => Response::builder().status(status).body(self.to_string()),
451 AsResponse::Fn(ref f, _) => f(&self),
452 AsResponse::Response(resp) => resp,
453 };
454 *resp.extensions_mut() = self.extensions;
455 resp
456 }
457
458 pub fn has_source(&self) -> bool {
460 self.source.is_some()
461 }
462
463 #[inline]
479 pub fn set_data(&mut self, data: impl Clone + Send + Sync + 'static) {
480 self.extensions.insert(data);
481 }
482
483 pub fn data<T: Send + Sync + 'static>(&self) -> Option<&T> {
485 self.extensions.get()
486 }
487
488 pub fn status(&self) -> StatusCode {
490 match &self.as_response {
491 AsResponse::Status(status) => *status,
492 AsResponse::Fn(_, get_status) => (get_status)(self),
493 AsResponse::Response(resp) => resp.status(),
494 }
495 }
496
497 #[inline]
499 pub fn is_from_response(&self) -> bool {
500 matches!(&self.as_response, AsResponse::Response(_))
501 }
502
503 pub fn set_error_message(&mut self, msg: impl Into<String>) {
505 self.msg = Some(msg.into());
506 }
507}
508
509define_http_error!(
510 (BadRequest, BAD_REQUEST);
512 (Unauthorized, UNAUTHORIZED);
514 (PaymentRequired, PAYMENT_REQUIRED);
516 (Forbidden, FORBIDDEN);
518 (NotFound, NOT_FOUND);
520 (MethodNotAllowed, METHOD_NOT_ALLOWED);
522 (NotAcceptable, NOT_ACCEPTABLE);
524 (ProxyAuthenticationRequired, PROXY_AUTHENTICATION_REQUIRED);
526 (RequestTimeout, REQUEST_TIMEOUT);
528 (Conflict, CONFLICT);
530 (Gone, GONE);
532 (LengthRequired, LENGTH_REQUIRED);
534 (PayloadTooLarge, PAYLOAD_TOO_LARGE);
536 (UriTooLong, URI_TOO_LONG);
538 (UnsupportedMediaType, UNSUPPORTED_MEDIA_TYPE);
540 (RangeNotSatisfiable, RANGE_NOT_SATISFIABLE);
542 (ImATeapot, IM_A_TEAPOT);
544 (MisdirectedRequest, MISDIRECTED_REQUEST);
546 (UnprocessableEntity, UNPROCESSABLE_ENTITY);
548 (Locked, LOCKED);
550 (FailedDependency, FAILED_DEPENDENCY);
552 (UpgradeRequired, UPGRADE_REQUIRED);
554 (PreconditionFailed, PRECONDITION_FAILED);
556 (PreconditionRequired, PRECONDITION_REQUIRED);
558 (TooManyRequests, TOO_MANY_REQUESTS);
560 (RequestHeaderFieldsTooLarge, REQUEST_HEADER_FIELDS_TOO_LARGE);
562 (UnavailableForLegalReasons, UNAVAILABLE_FOR_LEGAL_REASONS);
564 (ExpectationFailed, EXPECTATION_FAILED);
566 (InternalServerError, INTERNAL_SERVER_ERROR);
568 (NotImplemented, NOT_IMPLEMENTED);
570 (BadGateway, BAD_GATEWAY);
572 (ServiceUnavailable, SERVICE_UNAVAILABLE);
574 (GatewayTimeout, GATEWAY_TIMEOUT);
576 (HttpVersionNotSupported, HTTP_VERSION_NOT_SUPPORTED);
578 (VariantAlsoNegotiates, VARIANT_ALSO_NEGOTIATES);
580 (InsufficientStorage, INSUFFICIENT_STORAGE);
582 (LoopDetected, LOOP_DETECTED);
584 (NotExtended, NOT_EXTENDED);
586 (NetworkAuthenticationRequired, NETWORK_AUTHENTICATION_REQUIRED);
588);
589
590pub type Result<T, E = Error> = ::std::result::Result<T, E>;
592
593pub trait IntoResult<T: IntoResponse> {
609 fn into_result(self) -> Result<T>;
611}
612
613impl<T, E> IntoResult<T> for Result<T, E>
614where
615 T: IntoResponse,
616 E: Into<Error> + Send + Sync + 'static,
617{
618 #[inline]
619 fn into_result(self) -> Result<T> {
620 self.map_err(Into::into)
621 }
622}
623
624impl<T: IntoResponse> IntoResult<T> for T {
625 #[inline]
626 fn into_result(self) -> Result<T> {
627 Ok(self)
628 }
629}
630
631macro_rules! define_simple_errors {
632 ($($(#[$docs:meta])* ($name:ident, $status:ident, $err_msg:literal);)*) => {
633 $(
634 $(#[$docs])*
635 #[derive(Debug, thiserror::Error, Copy, Clone, Eq, PartialEq)]
636 #[error($err_msg)]
637 pub struct $name;
638
639 impl ResponseError for $name {
640 fn status(&self) -> StatusCode {
641 StatusCode::$status
642 }
643 }
644 )*
645 };
646}
647
648define_simple_errors!(
649 (ParsePathError, BAD_REQUEST, "invalid path params");
651
652 (NotFoundError, NOT_FOUND, "not found");
654
655 (MethodNotAllowedError, METHOD_NOT_ALLOWED, "method not allowed");
657);
658
659#[derive(Debug, thiserror::Error)]
661pub enum ReadBodyError {
662 #[error("the body has been taken")]
664 BodyHasBeenTaken,
665
666 #[error("parse utf8: {0}")]
668 Utf8(#[from] FromUtf8Error),
669
670 #[error("payload too large")]
672 PayloadTooLarge,
673
674 #[error("io: {0}")]
676 Io(#[from] std::io::Error),
677}
678
679impl ResponseError for ReadBodyError {
680 fn status(&self) -> StatusCode {
681 match self {
682 ReadBodyError::BodyHasBeenTaken => StatusCode::INTERNAL_SERVER_ERROR,
683 ReadBodyError::Utf8(_) => StatusCode::BAD_REQUEST,
684 ReadBodyError::Io(_) => StatusCode::BAD_REQUEST,
685 ReadBodyError::PayloadTooLarge => StatusCode::PAYLOAD_TOO_LARGE,
686 }
687 }
688}
689
690#[cfg(feature = "cookie")]
692#[cfg_attr(docsrs, doc(cfg(feature = "cookie")))]
693#[derive(Debug, thiserror::Error)]
694pub enum ParseCookieError {
695 #[error("cookie is illegal")]
697 CookieIllegal,
698
699 #[error("`Cookie` header is required")]
701 CookieHeaderRequired,
702
703 #[error("cookie is illegal: {0}")]
705 #[cfg(not(feature = "sonic-rs"))]
706 ParseJsonValue(#[from] serde_json::Error),
707
708 #[error("cookie is illegal: {0}")]
710 #[cfg(feature = "sonic-rs")]
711 ParseJsonValue(#[from] sonic_rs::Error),
712}
713
714#[cfg(feature = "cookie")]
715impl ResponseError for ParseCookieError {
716 fn status(&self) -> StatusCode {
717 StatusCode::BAD_REQUEST
718 }
719}
720
721#[derive(Debug, thiserror::Error, Eq, PartialEq)]
723#[error("data of type `{0}` was not found.")]
724pub struct GetDataError(pub &'static str);
725
726impl ResponseError for GetDataError {
727 fn status(&self) -> StatusCode {
728 StatusCode::INTERNAL_SERVER_ERROR
729 }
730}
731
732#[derive(Debug, thiserror::Error)]
734pub enum ParseFormError {
735 #[error("invalid content type `{0}`, expect: `application/x-www-form-urlencoded`")]
737 InvalidContentType(String),
738
739 #[error("expect content type `application/x-www-form-urlencoded`")]
741 ContentTypeRequired,
742
743 #[error("url decode: {0}")]
745 UrlDecode(#[from] serde_urlencoded::de::Error),
746}
747
748impl ResponseError for ParseFormError {
749 fn status(&self) -> StatusCode {
750 match self {
751 ParseFormError::InvalidContentType(_) => StatusCode::UNSUPPORTED_MEDIA_TYPE,
752 ParseFormError::ContentTypeRequired => StatusCode::UNSUPPORTED_MEDIA_TYPE,
753 ParseFormError::UrlDecode(_) => StatusCode::BAD_REQUEST,
754 }
755 }
756}
757
758#[derive(Debug, thiserror::Error)]
760pub enum ParseJsonError {
761 #[error("invalid content type `{0}`, expect: `application/json`")]
763 InvalidContentType(String),
764
765 #[error("expect content type `application/json`")]
767 ContentTypeRequired,
768
769 #[error("parse error: {0}")]
771 #[cfg(not(feature = "sonic-rs"))]
772 Parse(#[from] serde_json::Error),
773
774 #[error("parse error: {0}")]
776 #[cfg(feature = "sonic-rs")]
777 Parse(#[from] sonic_rs::Error),
778}
779
780impl ResponseError for ParseJsonError {
781 fn status(&self) -> StatusCode {
782 match self {
783 ParseJsonError::InvalidContentType(_) => StatusCode::UNSUPPORTED_MEDIA_TYPE,
784 ParseJsonError::ContentTypeRequired => StatusCode::UNSUPPORTED_MEDIA_TYPE,
785 ParseJsonError::Parse(_) => StatusCode::BAD_REQUEST,
786 }
787 }
788}
789
790#[cfg(feature = "xml")]
792#[derive(Debug, thiserror::Error)]
793pub enum ParseXmlError {
794 #[error("invalid content type `{0}`, expect: `application/xml`")]
796 InvalidContentType(String),
797
798 #[error("expect content type `application/xml`")]
800 ContentTypeRequired,
801
802 #[error("parse error: {0}")]
804 Parse(#[from] quick_xml::de::DeError),
805}
806
807#[cfg(feature = "xml")]
808impl ResponseError for ParseXmlError {
809 fn status(&self) -> StatusCode {
810 match self {
811 ParseXmlError::InvalidContentType(_) => StatusCode::UNSUPPORTED_MEDIA_TYPE,
812 ParseXmlError::ContentTypeRequired => StatusCode::UNSUPPORTED_MEDIA_TYPE,
813 ParseXmlError::Parse(_) => StatusCode::BAD_REQUEST,
814 }
815 }
816}
817
818#[cfg(feature = "yaml")]
820#[derive(Debug, thiserror::Error)]
821pub enum ParseYamlError {
822 #[error("invalid content type `{0}`, expect: `application/yaml`")]
824 InvalidContentType(String),
825
826 #[error("expect content type `application/yaml`")]
828 ContentTypeRequired,
829
830 #[error("parse error: {0}")]
832 Parse(#[from] serde_yaml::Error),
833}
834
835#[cfg(feature = "yaml")]
836impl ResponseError for ParseYamlError {
837 fn status(&self) -> StatusCode {
838 match self {
839 ParseYamlError::InvalidContentType(_) => StatusCode::UNSUPPORTED_MEDIA_TYPE,
840 ParseYamlError::ContentTypeRequired => StatusCode::UNSUPPORTED_MEDIA_TYPE,
841 ParseYamlError::Parse(_) => StatusCode::BAD_REQUEST,
842 }
843 }
844}
845
846#[derive(Debug, thiserror::Error)]
848#[error(transparent)]
849pub struct ParseQueryError(#[from] pub serde_urlencoded::de::Error);
850
851impl ResponseError for ParseQueryError {
852 fn status(&self) -> StatusCode {
853 StatusCode::BAD_REQUEST
854 }
855}
856
857#[cfg(feature = "multipart")]
859#[cfg_attr(docsrs, doc(cfg(feature = "multipart")))]
860#[derive(Debug, thiserror::Error)]
861pub enum ParseMultipartError {
862 #[error("invalid content type `{0}`, expect: `multipart/form-data`")]
864 InvalidContentType(String),
865
866 #[error("expect content type `multipart/form-data`")]
868 ContentTypeRequired,
869
870 #[error("parse: {0}")]
872 Multipart(#[from] multer::Error),
873
874 #[error("parse utf8: {0}")]
876 Utf8(#[from] FromUtf8Error),
877
878 #[error("io: {0}")]
880 Io(#[from] std::io::Error),
881}
882
883#[cfg(feature = "multipart")]
884impl ResponseError for ParseMultipartError {
885 fn status(&self) -> StatusCode {
886 match self {
887 ParseMultipartError::InvalidContentType(_) => StatusCode::UNSUPPORTED_MEDIA_TYPE,
888 ParseMultipartError::ContentTypeRequired => StatusCode::UNSUPPORTED_MEDIA_TYPE,
889 ParseMultipartError::Multipart(_) => StatusCode::BAD_REQUEST,
890 ParseMultipartError::Utf8(_) => StatusCode::BAD_REQUEST,
891 ParseMultipartError::Io(_) => StatusCode::BAD_REQUEST,
892 }
893 }
894}
895
896#[derive(Debug, thiserror::Error)]
898pub enum ParseTypedHeaderError {
899 #[error("header `{0}` is required")]
901 HeaderRequired(String),
902
903 #[error("parse: {0}")]
905 TypedHeader(#[from] headers::Error),
906}
907
908impl ResponseError for ParseTypedHeaderError {
909 fn status(&self) -> StatusCode {
910 StatusCode::BAD_REQUEST
911 }
912}
913
914#[cfg(feature = "websocket")]
916#[cfg_attr(docsrs, doc(cfg(feature = "websocket")))]
917#[derive(Debug, thiserror::Error)]
918pub enum WebSocketError {
919 #[error("invalid protocol")]
921 InvalidProtocol,
922
923 #[error(transparent)]
925 UpgradeError(#[from] UpgradeError),
926}
927
928#[cfg(feature = "websocket")]
929impl ResponseError for WebSocketError {
930 fn status(&self) -> StatusCode {
931 match self {
932 WebSocketError::InvalidProtocol => StatusCode::BAD_REQUEST,
933 WebSocketError::UpgradeError(err) => err.status(),
934 }
935 }
936}
937
938#[derive(Debug, thiserror::Error)]
940pub enum UpgradeError {
941 #[error("no upgrade")]
943 NoUpgrade,
944
945 #[error("{0}")]
947 Other(String),
948}
949
950impl ResponseError for UpgradeError {
951 fn status(&self) -> StatusCode {
952 match self {
953 UpgradeError::NoUpgrade => StatusCode::INTERNAL_SERVER_ERROR,
954 UpgradeError::Other(_) => StatusCode::BAD_REQUEST,
955 }
956 }
957}
958
959#[derive(Debug, thiserror::Error)]
961pub enum StaticFileError {
962 #[error("method not found")]
964 MethodNotAllowed(Method),
965
966 #[error("invalid path")]
968 InvalidPath,
969
970 #[error("forbidden: {0}")]
972 Forbidden(String),
973
974 #[error("not found")]
976 NotFound,
977
978 #[error("precondition failed")]
980 PreconditionFailed,
981
982 #[error("range not satisfiable")]
984 RangeNotSatisfiable {
985 size: u64,
987 },
988
989 #[error("io: {0}")]
991 Io(#[from] std::io::Error),
992}
993
994impl ResponseError for StaticFileError {
995 fn status(&self) -> StatusCode {
996 match self {
997 StaticFileError::MethodNotAllowed(_) => StatusCode::METHOD_NOT_ALLOWED,
998 StaticFileError::InvalidPath => StatusCode::BAD_REQUEST,
999 StaticFileError::Forbidden(_) => StatusCode::FORBIDDEN,
1000 StaticFileError::NotFound => StatusCode::NOT_FOUND,
1001 StaticFileError::PreconditionFailed => StatusCode::PRECONDITION_FAILED,
1002 StaticFileError::RangeNotSatisfiable { .. } => StatusCode::RANGE_NOT_SATISFIABLE,
1003 StaticFileError::Io(_) => StatusCode::INTERNAL_SERVER_ERROR,
1004 }
1005 }
1006
1007 fn as_response(&self) -> Response {
1008 let mut resp = self.to_string().into_response();
1009 resp.set_status(self.status());
1010 if let StaticFileError::RangeNotSatisfiable { size } = self {
1011 resp.headers_mut()
1012 .typed_insert(ContentRange::unsatisfied_bytes(*size));
1013 }
1014 resp
1015 }
1016}
1017
1018#[derive(Debug, thiserror::Error, Eq, PartialEq)]
1020pub enum SizedLimitError {
1021 #[error("missing `Content-Length` header")]
1023 MissingContentLength,
1024
1025 #[error("payload too large")]
1027 PayloadTooLarge,
1028}
1029
1030impl ResponseError for SizedLimitError {
1031 fn status(&self) -> StatusCode {
1032 match self {
1033 SizedLimitError::MissingContentLength => StatusCode::LENGTH_REQUIRED,
1034 SizedLimitError::PayloadTooLarge => StatusCode::PAYLOAD_TOO_LARGE,
1035 }
1036 }
1037}
1038
1039#[derive(Debug, thiserror::Error, Eq, PartialEq)]
1041pub enum RouteError {
1042 #[error("invalid path: {0}")]
1044 InvalidPath(String),
1045
1046 #[error("duplicate path: {0}")]
1048 Duplicate(String),
1049
1050 #[error("invalid regex in path: {path}")]
1052 InvalidRegex {
1053 path: String,
1055
1056 regex: String,
1058 },
1059}
1060
1061impl ResponseError for RouteError {
1062 fn status(&self) -> StatusCode {
1063 StatusCode::INTERNAL_SERVER_ERROR
1064 }
1065}
1066
1067#[derive(Debug, thiserror::Error, Eq, PartialEq)]
1069pub enum CorsError {
1070 #[error("request-method not allowed")]
1072 MethodNotAllowed,
1073
1074 #[error("request-origin not allowed")]
1076 OriginNotAllowed,
1077
1078 #[error("request-headers not allowed")]
1080 HeadersNotAllowed,
1081}
1082
1083impl ResponseError for CorsError {
1084 fn status(&self) -> StatusCode {
1085 StatusCode::FORBIDDEN
1086 }
1087}
1088
1089#[cfg(feature = "i18n")]
1091#[derive(Debug, thiserror::Error)]
1092pub enum I18NError {
1093 #[error("fluent: {}", .0[0])]
1095 Fluent(Vec<fluent::FluentError>),
1096
1097 #[error("fluent parser: {}", .0[0])]
1099 FluentParser(Vec<fluent_syntax::parser::ParserError>),
1100
1101 #[error("no value")]
1103 FluentNoValue,
1104
1105 #[error("msg not found: `{id}`")]
1107 FluentMessageNotFound {
1108 id: String,
1110 },
1111
1112 #[error("invalid language id: {0}")]
1114 LanguageIdentifier(#[from] unic_langid::LanguageIdentifierError),
1115
1116 #[error("io: {0}")]
1118 Io(#[from] std::io::Error),
1119}
1120
1121#[cfg(feature = "i18n")]
1122impl ResponseError for I18NError {
1123 fn status(&self) -> StatusCode {
1124 StatusCode::INTERNAL_SERVER_ERROR
1125 }
1126}
1127
1128#[cfg(feature = "redis-session")]
1130#[derive(Debug, thiserror::Error)]
1131pub enum RedisSessionError {
1132 #[error("redis: {0}")]
1134 Redis(redis::RedisError),
1135}
1136
1137#[cfg(feature = "redis-session")]
1138impl ResponseError for RedisSessionError {
1139 fn status(&self) -> StatusCode {
1140 StatusCode::INTERNAL_SERVER_ERROR
1141 }
1142}
1143
1144#[cfg(test)]
1145mod tests {
1146 use std::io::{Error as IoError, ErrorKind};
1147
1148 use super::*;
1149
1150 #[test]
1151 fn test_into_result() {
1152 assert!(matches!("hello".into_result(), Ok("hello")));
1153 assert!(matches!(Ok::<_, Error>("hello").into_result(), Ok("hello")));
1154 assert!(matches!(
1155 Ok::<_, NotFoundError>("hello").into_result(),
1156 Ok("hello")
1157 ));
1158 assert!(Err::<String, _>(NotFoundError)
1159 .into_result()
1160 .unwrap_err()
1161 .is::<NotFoundError>());
1162 }
1163
1164 #[test]
1165 fn test_error() {
1166 let err = Error::new(
1167 IoError::new(ErrorKind::AlreadyExists, "aaa"),
1168 StatusCode::BAD_GATEWAY,
1169 );
1170 assert!(err.is::<IoError>());
1171 assert_eq!(
1172 err.downcast_ref::<IoError>().unwrap().kind(),
1173 ErrorKind::AlreadyExists
1174 );
1175 assert_eq!(err.into_response().status(), StatusCode::BAD_GATEWAY);
1176 }
1177
1178 #[test]
1179 fn test_box_error() {
1180 let boxed_err: Box<dyn StdError + Send + Sync> =
1181 Box::new(IoError::new(ErrorKind::AlreadyExists, "aaa"));
1182 let err: Error = Error::from((StatusCode::BAD_GATEWAY, boxed_err));
1183 assert!(err.is::<IoError>());
1184 assert_eq!(
1185 err.downcast_ref::<IoError>().unwrap().kind(),
1186 ErrorKind::AlreadyExists
1187 );
1188 assert_eq!(err.into_response().status(), StatusCode::BAD_GATEWAY);
1189 }
1190
1191 #[cfg(feature = "anyhow")]
1192 #[test]
1193 fn test_anyhow_error() {
1194 let anyhow_err: anyhow::Error = IoError::new(ErrorKind::AlreadyExists, "aaa").into();
1195 let err: Error = Error::from((StatusCode::BAD_GATEWAY, anyhow_err));
1196 assert!(err.is::<IoError>());
1197 assert_eq!(
1198 err.downcast_ref::<IoError>().unwrap().kind(),
1199 ErrorKind::AlreadyExists
1200 );
1201 assert_eq!(err.into_response().status(), StatusCode::BAD_GATEWAY);
1202 }
1203
1204 #[cfg(feature = "eyre06")]
1205 #[test]
1206 fn test_eyre06_error() {
1207 let eyre06_err: eyre06::Error = IoError::new(ErrorKind::AlreadyExists, "aaa").into();
1208 let err: Error = Error::from((StatusCode::BAD_GATEWAY, eyre06_err));
1209 assert!(err.is::<IoError>());
1210 assert_eq!(
1211 err.downcast_ref::<IoError>().unwrap().kind(),
1212 ErrorKind::AlreadyExists
1213 );
1214 assert_eq!(err.into_response().status(), StatusCode::BAD_GATEWAY);
1215 }
1216
1217 #[tokio::test]
1218 async fn test_custom_as_response() {
1219 #[derive(Debug, thiserror::Error)]
1220 #[error("my error")]
1221 struct MyError;
1222
1223 impl ResponseError for MyError {
1224 fn status(&self) -> StatusCode {
1225 StatusCode::BAD_GATEWAY
1226 }
1227
1228 fn as_response(&self) -> Response {
1229 Response::builder()
1230 .status(self.status())
1231 .body("my error message")
1232 }
1233 }
1234
1235 let err = Error::from(MyError);
1236 let resp = err.into_response();
1237
1238 assert_eq!(resp.status(), StatusCode::BAD_GATEWAY);
1239 assert_eq!(
1240 resp.into_body().into_string().await.unwrap(),
1241 "my error message"
1242 );
1243 }
1244}