Skip to main content

ohttp_relay/
error.rs

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 {}