ohttp-relay 0.0.11

Relay Oblivious HTTP requests to protect IP metadata
Documentation
use std::time::Duration;

use http_body_util::combinators::BoxBody;
use http_body_util::BodyExt;
use hyper::body::Bytes;
use hyper::header::{HeaderValue, RETRY_AFTER};
use hyper::{Response, StatusCode};
use tracing::error;

use crate::{empty, full};

pub(crate) type BoxError = Box<dyn std::error::Error + Send + Sync>;

#[derive(Debug)]
#[allow(clippy::enum_variant_names)]
pub(crate) enum Error {
    BadGateway,
    MethodNotAllowed,
    UnsupportedMediaType,
    BadRequest(String),
    NotFound,
    InternalServerError(BoxError),
    Unavailable(Duration),
}

impl Error {
    pub fn to_response(&self) -> Response<BoxBody<Bytes, hyper::Error>> {
        let mut res = Response::new(empty());
        match self {
            Self::UnsupportedMediaType => *res.status_mut() = StatusCode::UNSUPPORTED_MEDIA_TYPE,
            Self::BadGateway => *res.status_mut() = StatusCode::BAD_GATEWAY,
            Self::MethodNotAllowed => *res.status_mut() = StatusCode::METHOD_NOT_ALLOWED,
            Self::BadRequest(e) => {
                *res.status_mut() = StatusCode::BAD_REQUEST;
                *res.body_mut() = full(e.to_string()).boxed();
            }
            Self::NotFound => *res.status_mut() = StatusCode::NOT_FOUND,
            Self::InternalServerError(internal_error) => {
                error!("Internal server error: {}", internal_error);
                *res.status_mut() = StatusCode::INTERNAL_SERVER_ERROR;
            }
            Self::Unavailable(max_age) => {
                *res.status_mut() = StatusCode::SERVICE_UNAVAILABLE;
                res.headers_mut().append(
                    RETRY_AFTER,
                    HeaderValue::from_str(&max_age.as_secs().to_string())
                        .expect("header value should always be valid"),
                );
            }
        };
        res
    }
}

impl std::fmt::Display for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        match self {
            Self::UnsupportedMediaType => write!(f, "Unsupported media type"),
            Self::BadGateway => write!(f, "Bad gateway"),
            Self::MethodNotAllowed => write!(f, "Method not allowed"),
            Self::BadRequest(e) => write!(f, "Bad request: {}", e),
            Self::NotFound => write!(f, "Not found"),
            Self::InternalServerError(e) => write!(f, "Internal server error: {}", e),
            Self::Unavailable(_) => write!(f, "Service unavailable"),
        }
    }
}

impl std::error::Error for Error {}