mod bad_request;
mod forbidden;
mod internal_server;
mod method_not_allowed;
mod not_found;
mod redirect;
mod unauthorized;
pub use bad_request::*;
pub use forbidden::*;
pub use internal_server::*;
pub use method_not_allowed::*;
pub use not_found::*;
pub use redirect::*;
pub use unauthorized::*;
use http::StatusCode;
use crate::{Body, IntoResponse, Response};
use topcoat_core::context::Cx;
use topcoat_core::error::{Error, Result};
pub(crate) fn respond(cx: &Cx, value: impl IntoResponse) -> Response {
value
.into_response(cx)
.unwrap_or_else(|error| error_into_response(cx, error))
}
fn error_into_response(cx: &Cx, error: Error) -> Response {
macro_rules! try_downcast {
($ident:ident as $ty:ty) => {
match $ident.downcast::<$ty>() {
Ok(error) => return into_response_or_500(cx, error),
Err(error) => error,
}
};
}
let error = try_downcast!(error as ForbiddenError);
let error = try_downcast!(error as BadRequestError);
let error = try_downcast!(error as InternalServerError);
let error = try_downcast!(error as NotFoundError);
let error = try_downcast!(error as MethodNotAllowedError);
let error = try_downcast!(error as RedirectError);
let error = try_downcast!(error as UnauthorizedError);
into_response_or_500(cx, internal_server_error(error))
}
fn into_response_or_500(cx: &Cx, value: impl IntoResponse) -> Response {
value.into_response(cx).unwrap_or_else(|_| {
let mut response = Response::new(Body::from("internal server error"));
*response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR;
response
})
}
impl<T> IntoResponse for Result<T>
where
T: IntoResponse,
{
fn into_response(self, cx: &Cx) -> Result<Response> {
match self {
Ok(value) => value.into_response(cx),
Err(error) => Ok(error_into_response(cx, error)),
}
}
}
impl IntoResponse for Error {
fn into_response(self, cx: &Cx) -> Result<Response> {
Ok(error_into_response(cx, self))
}
}
pub trait RouterErrorExt {
type T;
fn ok_or_redirect(self, uri: &str) -> Result<Self::T, RedirectError>;
fn ok_or_redirect_permanent(self, uri: &str) -> Result<Self::T, RedirectError>;
fn ok_or_not_found(self) -> Result<Self::T, NotFoundError>;
fn ok_or_unauthorized(self) -> Result<Self::T, UnauthorizedError>;
fn ok_or_forbidden(self) -> Result<Self::T, ForbiddenError>;
fn ok_or_bad_request(self, description: impl Into<String>) -> Result<Self::T, BadRequestError>;
}
impl<T> RouterErrorExt for Option<T> {
type T = T;
fn ok_or_redirect(self, uri: &str) -> Result<Self::T, RedirectError> {
match self {
Some(value) => Ok(value),
None => Err(redirect(uri)),
}
}
fn ok_or_redirect_permanent(self, uri: &str) -> Result<Self::T, RedirectError> {
match self {
Some(value) => Ok(value),
None => Err(redirect_permanent(uri)),
}
}
fn ok_or_not_found(self) -> Result<Self::T, NotFoundError> {
match self {
Some(value) => Ok(value),
None => Err(not_found()),
}
}
fn ok_or_unauthorized(self) -> Result<Self::T, UnauthorizedError> {
match self {
Some(value) => Ok(value),
None => Err(unauthorized()),
}
}
fn ok_or_forbidden(self) -> Result<Self::T, ForbiddenError> {
match self {
Some(value) => Ok(value),
None => Err(forbidden()),
}
}
fn ok_or_bad_request(self, description: impl Into<String>) -> Result<Self::T, BadRequestError> {
match self {
Some(value) => Ok(value),
None => Err(bad_request(description)),
}
}
}
impl<T, E> RouterErrorExt for Result<T, E> {
type T = T;
fn ok_or_redirect(self, uri: &str) -> Result<Self::T, RedirectError> {
match self {
Ok(value) => Ok(value),
Err(_) => Err(redirect(uri)),
}
}
fn ok_or_redirect_permanent(self, uri: &str) -> Result<Self::T, RedirectError> {
match self {
Ok(value) => Ok(value),
Err(_) => Err(redirect_permanent(uri)),
}
}
fn ok_or_not_found(self) -> Result<Self::T, NotFoundError> {
match self {
Ok(value) => Ok(value),
Err(_) => Err(not_found()),
}
}
fn ok_or_unauthorized(self) -> Result<Self::T, UnauthorizedError> {
match self {
Ok(value) => Ok(value),
Err(_) => Err(unauthorized()),
}
}
fn ok_or_forbidden(self) -> Result<Self::T, ForbiddenError> {
match self {
Ok(value) => Ok(value),
Err(_) => Err(forbidden()),
}
}
fn ok_or_bad_request(self, description: impl Into<String>) -> Result<Self::T, BadRequestError> {
match self {
Ok(value) => Ok(value),
Err(_) => Err(bad_request(description)),
}
}
}