ntex/ntex/src/web/error_default.rs
2021-06-25 22:42:25 +06:00

264 lines
8.2 KiB
Rust

//! Web error
use std::{fmt, io, io::Write, str::Utf8Error};
use serde::de::value::Error as DeError;
use serde_json::error::Error as JsonError;
use serde_urlencoded::ser::Error as FormError;
use crate::http::body::Body;
use crate::http::helpers::Writer;
use crate::http::ws::HandshakeError;
use crate::http::{self, header, StatusCode};
use crate::util::{timeout::TimeoutError, BytesMut};
use super::error::{self, ErrorContainer, ErrorRenderer, WebResponseError};
use super::{HttpRequest, HttpResponse};
/// Default error type
#[derive(Clone, Copy, Default)]
pub struct DefaultError;
impl ErrorRenderer for DefaultError {
type Container = Error;
}
/// Generic error container for errors that supports `DefaultError` renderer.
pub struct Error {
cause: Box<dyn WebResponseError<DefaultError>>,
}
impl Error {
pub fn new<T: WebResponseError<DefaultError> + 'static>(err: T) -> Error {
Error {
cause: Box::new(err),
}
}
/// Returns the reference to the underlying `WebResponseError`.
pub fn as_response_error(&self) -> &dyn WebResponseError<DefaultError> {
self.cause.as_ref()
}
}
/// `Error` for any error which implements `WebResponseError<DefaultError>`
impl<T: WebResponseError<DefaultError>> From<T> for Error {
fn from(err: T) -> Self {
Error {
cause: Box::new(err),
}
}
}
impl std::error::Error for Error {}
impl ErrorContainer for Error {
fn error_response(&self, req: &HttpRequest) -> HttpResponse {
self.cause.error_response(req)
}
}
impl crate::http::error::ResponseError for Error {
fn error_response(&self) -> HttpResponse {
let mut resp = HttpResponse::new(self.cause.status_code());
let mut buf = BytesMut::new();
let _ = write!(Writer(&mut buf), "{}", self.cause);
resp.headers_mut().insert(
header::CONTENT_TYPE,
header::HeaderValue::from_static("text/plain; charset=utf-8"),
);
resp.set_body(Body::from(buf))
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.cause, f)
}
}
impl fmt::Debug for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "web::Error({:?})", &self.cause)
}
}
/// Return `GATEWAY_TIMEOUT` for `TimeoutError`
impl<E: WebResponseError<DefaultError>> WebResponseError<DefaultError>
for TimeoutError<E>
{
fn status_code(&self) -> StatusCode {
match self {
TimeoutError::Service(e) => e.status_code(),
TimeoutError::Timeout => StatusCode::GATEWAY_TIMEOUT,
}
}
}
/// `InternalServerError` for `DataExtractorError`
impl WebResponseError<DefaultError> for error::DataExtractorError {}
/// `InternalServerError` for `JsonError`
impl WebResponseError<DefaultError> for JsonError {}
/// `InternalServerError` for `FormError`
impl WebResponseError<DefaultError> for FormError {}
#[cfg(feature = "openssl")]
/// `InternalServerError` for `openssl::ssl::Error`
impl WebResponseError<DefaultError> for crate::connect::openssl::SslError {}
#[cfg(feature = "openssl")]
/// `InternalServerError` for `openssl::ssl::HandshakeError`
impl<T: fmt::Debug + 'static> WebResponseError<DefaultError>
for open_ssl::ssl::HandshakeError<T>
{
}
/// Return `BAD_REQUEST` for `de::value::Error`
impl WebResponseError<DefaultError> for DeError {
fn status_code(&self) -> StatusCode {
StatusCode::BAD_REQUEST
}
}
/// `InternalServerError` for `Canceled`
impl WebResponseError<DefaultError> for crate::http::error::Canceled {}
/// `InternalServerError` for `BlockingError`
impl<E: fmt::Debug + 'static> WebResponseError<DefaultError>
for crate::http::error::BlockingError<E>
{
}
/// Return `BAD_REQUEST` for `Utf8Error`
impl WebResponseError<DefaultError> for Utf8Error {
fn status_code(&self) -> StatusCode {
StatusCode::BAD_REQUEST
}
}
/// Return `InternalServerError` for `HttpError`,
/// Response generation can return `HttpError`, so it is internal error
impl WebResponseError<DefaultError> for crate::http::error::HttpError {}
/// Return `InternalServerError` for `io::Error`
impl WebResponseError<DefaultError> for io::Error {
fn status_code(&self) -> StatusCode {
match self.kind() {
io::ErrorKind::NotFound => StatusCode::NOT_FOUND,
io::ErrorKind::PermissionDenied => StatusCode::FORBIDDEN,
_ => StatusCode::INTERNAL_SERVER_ERROR,
}
}
}
/// `InternalServerError` for `UrlGeneratorError`
impl WebResponseError<DefaultError> for error::UrlGenerationError {}
/// Response renderer for `UrlencodedError`
impl WebResponseError<DefaultError> for error::UrlencodedError {
fn status_code(&self) -> StatusCode {
match *self {
error::UrlencodedError::Overflow { .. } => StatusCode::PAYLOAD_TOO_LARGE,
error::UrlencodedError::UnknownLength => StatusCode::LENGTH_REQUIRED,
_ => StatusCode::BAD_REQUEST,
}
}
}
/// Return `BadRequest` for `JsonPayloadError`
impl WebResponseError<DefaultError> for error::JsonPayloadError {
fn status_code(&self) -> StatusCode {
match *self {
error::JsonPayloadError::Overflow => StatusCode::PAYLOAD_TOO_LARGE,
_ => StatusCode::BAD_REQUEST,
}
}
}
/// Error renderer for `PathError`
impl WebResponseError<DefaultError> for error::PathError {
fn status_code(&self) -> StatusCode {
StatusCode::NOT_FOUND
}
}
/// Error renderer `QueryPayloadError`
impl WebResponseError<DefaultError> for error::QueryPayloadError {
fn status_code(&self) -> StatusCode {
StatusCode::BAD_REQUEST
}
}
impl WebResponseError<DefaultError> for error::PayloadError {
fn status_code(&self) -> StatusCode {
StatusCode::BAD_REQUEST
}
}
/// `PayloadError` returns two possible results:
///
/// - `Overflow` returns `PayloadTooLarge`
/// - Other errors returns `BadRequest`
impl WebResponseError<DefaultError> for http::error::PayloadError {
fn status_code(&self) -> StatusCode {
match *self {
http::error::PayloadError::Overflow => StatusCode::PAYLOAD_TOO_LARGE,
_ => StatusCode::BAD_REQUEST,
}
}
}
#[cfg(feature = "cookie")]
/// Return `BadRequest` for `cookie::ParseError`
impl WebResponseError<DefaultError> for coo_kie::ParseError {
fn status_code(&self) -> StatusCode {
StatusCode::BAD_REQUEST
}
}
/// Return `BadRequest` for `ContentTypeError`
impl WebResponseError<DefaultError> for http::error::ContentTypeError {
fn status_code(&self) -> StatusCode {
StatusCode::BAD_REQUEST
}
}
/// Convert `SendRequestError` to a server `Response`
impl WebResponseError<DefaultError> for http::client::error::SendRequestError {
fn status_code(&self) -> StatusCode {
match *self {
http::client::error::SendRequestError::Connect(
http::client::error::ConnectError::Timeout,
) => StatusCode::GATEWAY_TIMEOUT,
http::client::error::SendRequestError::Connect(_) => StatusCode::BAD_REQUEST,
_ => StatusCode::INTERNAL_SERVER_ERROR,
}
}
}
/// Error renderer for ws::HandshakeError
impl WebResponseError<DefaultError> for HandshakeError {
fn error_response(&self, _: &HttpRequest) -> HttpResponse {
match *self {
HandshakeError::GetMethodRequired => HttpResponse::MethodNotAllowed()
.header(header::ALLOW, "GET")
.finish(),
HandshakeError::NoWebsocketUpgrade => HttpResponse::BadRequest()
.reason("No WebSocket UPGRADE header found")
.finish(),
HandshakeError::NoConnectionUpgrade => HttpResponse::BadRequest()
.reason("No CONNECTION upgrade")
.finish(),
HandshakeError::NoVersionHeader => HttpResponse::BadRequest()
.reason("Websocket version header is required")
.finish(),
HandshakeError::UnsupportedVersion => HttpResponse::BadRequest()
.reason("Unsupported version")
.finish(),
HandshakeError::BadWebsocketKey => HttpResponse::BadRequest()
.reason("Handshake error")
.finish(),
}
}
}