1use std::time::Duration;
2
3use http_body_util::combinators::BoxBody;
4use http_body_util::BodyExt;
5use hyper::body::Bytes;
6use hyper::header::{HeaderValue, RETRY_AFTER};
7use hyper::{Response, StatusCode};
8use tracing::error;
9
10use crate::{empty, full};
11
12pub(crate) type BoxError = Box<dyn std::error::Error + Send + Sync>;
13
14#[derive(Debug)]
15#[allow(clippy::enum_variant_names)]
16pub(crate) enum Error {
17 BadGateway,
18 MethodNotAllowed,
19 UnsupportedMediaType,
20 BadRequest(String),
21 NotFound,
22 InternalServerError(BoxError),
23 Unavailable(Duration),
24}
25
26impl Error {
27 pub fn to_response(&self) -> Response<BoxBody<Bytes, hyper::Error>> {
28 let mut res = Response::new(empty());
29 match self {
30 Self::UnsupportedMediaType => *res.status_mut() = StatusCode::UNSUPPORTED_MEDIA_TYPE,
31 Self::BadGateway => *res.status_mut() = StatusCode::BAD_GATEWAY,
32 Self::MethodNotAllowed => *res.status_mut() = StatusCode::METHOD_NOT_ALLOWED,
33 Self::BadRequest(e) => {
34 *res.status_mut() = StatusCode::BAD_REQUEST;
35 *res.body_mut() = full(e.to_string()).boxed();
36 }
37 Self::NotFound => *res.status_mut() = StatusCode::NOT_FOUND,
38 Self::InternalServerError(internal_error) => {
39 error!("Internal server error: {}", internal_error);
40 *res.status_mut() = StatusCode::INTERNAL_SERVER_ERROR;
41 }
42 Self::Unavailable(max_age) => {
43 *res.status_mut() = StatusCode::SERVICE_UNAVAILABLE;
44 res.headers_mut().append(
45 RETRY_AFTER,
46 HeaderValue::from_str(&max_age.as_secs().to_string())
47 .expect("header value should always be valid"),
48 );
49 }
50 };
51 res
52 }
53}
54
55impl std::fmt::Display for Error {
56 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
57 match self {
58 Self::UnsupportedMediaType => write!(f, "Unsupported media type"),
59 Self::BadGateway => write!(f, "Bad gateway"),
60 Self::MethodNotAllowed => write!(f, "Method not allowed"),
61 Self::BadRequest(e) => write!(f, "Bad request: {}", e),
62 Self::NotFound => write!(f, "Not found"),
63 Self::InternalServerError(e) => write!(f, "Internal server error: {}", e),
64 Self::Unavailable(_) => write!(f, "Service unavailable"),
65 }
66 }
67}
68
69impl std::error::Error for Error {}