1
0
Fork 0
mirror of https://github.com/actix/actix-web.git synced 2024-06-02 21:39:26 +00:00
actix-web/actix-http/src/error.rs

511 lines
13 KiB
Rust
Raw Normal View History

2019-03-26 18:54:35 +00:00
//! Error and Result module
2021-06-17 16:57:58 +00:00
use std::{error::Error as StdError, fmt, io, str::Utf8Error, string::FromUtf8Error};
2019-03-26 18:54:35 +00:00
use derive_more::{Display, Error, From};
2021-06-17 16:57:58 +00:00
use http::{uri::InvalidUri, StatusCode};
2019-03-26 18:54:35 +00:00
2021-06-17 16:57:58 +00:00
use crate::{
body::{AnyBody, Body},
ws, Response,
};
2021-02-13 15:08:43 +00:00
pub use http::Error as HttpError;
2019-03-26 18:54:35 +00:00
pub struct Error {
2021-06-17 16:57:58 +00:00
inner: Box<ErrorInner>,
}
pub(crate) struct ErrorInner {
#[allow(dead_code)]
kind: Kind,
cause: Option<Box<dyn StdError>>,
2019-03-26 18:54:35 +00:00
}
impl Error {
2021-06-17 16:57:58 +00:00
fn new(kind: Kind) -> Self {
Self {
inner: Box::new(ErrorInner { kind, cause: None }),
}
2019-03-26 18:54:35 +00:00
}
2021-06-17 16:57:58 +00:00
pub(crate) fn new_http() -> Self {
Self::new(Kind::Http)
}
2019-03-26 18:54:35 +00:00
2021-06-17 16:57:58 +00:00
pub(crate) fn new_parse() -> Self {
Self::new(Kind::Parse)
}
2021-06-17 16:57:58 +00:00
pub(crate) fn new_payload() -> Self {
Self::new(Kind::Payload)
}
2021-06-17 16:57:58 +00:00
pub(crate) fn new_body() -> Self {
Self::new(Kind::Body)
}
2019-03-26 18:54:35 +00:00
2021-06-17 16:57:58 +00:00
pub(crate) fn new_send_response() -> Self {
Self::new(Kind::SendResponse)
2019-03-26 18:54:35 +00:00
}
2021-06-17 16:57:58 +00:00
// TODO: remove allow
#[allow(dead_code)]
pub(crate) fn new_io() -> Self {
Self::new(Kind::Io)
2019-03-26 18:54:35 +00:00
}
2021-07-12 15:55:24 +00:00
// used in encoder behind feature flag so ignore unused warning
#[allow(unused)]
2021-06-17 16:57:58 +00:00
pub(crate) fn new_encoder() -> Self {
Self::new(Kind::Encoder)
}
2021-06-17 16:57:58 +00:00
pub(crate) fn new_ws() -> Self {
Self::new(Kind::Ws)
2019-12-05 17:35:43 +00:00
}
2021-06-17 16:57:58 +00:00
pub(crate) fn with_cause(mut self, cause: impl Into<Box<dyn StdError>>) -> Self {
self.inner.cause = Some(cause.into());
self
}
}
2021-06-17 16:57:58 +00:00
impl From<Error> for Response<AnyBody> {
2019-03-26 18:54:35 +00:00
fn from(err: Error) -> Self {
2021-06-17 16:57:58 +00:00
let status_code = match err.inner.kind {
Kind::Parse => StatusCode::BAD_REQUEST,
_ => StatusCode::INTERNAL_SERVER_ERROR,
};
2019-03-26 18:54:35 +00:00
2021-06-17 16:57:58 +00:00
Response::new(status_code).set_body(Body::from(err.to_string()))
2019-03-26 18:54:35 +00:00
}
}
2021-06-17 16:57:58 +00:00
#[derive(Debug, Clone, Copy, PartialEq, Eq, Display)]
pub enum Kind {
#[display(fmt = "error processing HTTP")]
Http,
2019-04-05 23:46:44 +00:00
2021-06-17 16:57:58 +00:00
#[display(fmt = "error parsing HTTP message")]
Parse,
2021-06-17 16:57:58 +00:00
#[display(fmt = "request payload read error")]
Payload,
2019-04-05 23:46:44 +00:00
2021-06-17 16:57:58 +00:00
#[display(fmt = "response body write error")]
Body,
2019-04-11 22:12:23 +00:00
2021-06-17 16:57:58 +00:00
#[display(fmt = "send response error")]
SendResponse,
#[display(fmt = "error in WebSocket process")]
Ws,
#[display(fmt = "connection error")]
Io,
#[display(fmt = "encoder error")]
Encoder,
2019-03-26 18:54:35 +00:00
}
2021-06-17 16:57:58 +00:00
impl fmt::Debug for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// TODO: more detail
f.write_str("actix_http::Error")
2019-03-26 18:54:35 +00:00
}
}
2021-06-17 16:57:58 +00:00
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.inner.cause.as_ref() {
Some(err) => write!(f, "{}: {}", &self.inner.kind, err),
None => write!(f, "{}", &self.inner.kind),
2019-03-26 18:54:35 +00:00
}
}
}
2021-06-17 16:57:58 +00:00
impl StdError for Error {
fn source(&self) -> Option<&(dyn StdError + 'static)> {
self.inner.cause.as_ref().map(Box::as_ref)
2021-06-17 16:57:58 +00:00
}
}
impl From<std::convert::Infallible> for Error {
fn from(err: std::convert::Infallible) -> Self {
match err {}
}
}
impl From<ws::ProtocolError> for Error {
fn from(err: ws::ProtocolError) -> Self {
Self::new_ws().with_cause(err)
}
}
impl From<HttpError> for Error {
fn from(err: HttpError) -> Self {
Self::new_http().with_cause(err)
}
}
impl From<ws::HandshakeError> for Error {
fn from(err: ws::HandshakeError) -> Self {
Self::new_ws().with_cause(err)
2019-03-26 18:54:35 +00:00
}
}
2021-04-14 05:07:59 +00:00
/// A set of errors that can occur during parsing HTTP streams.
#[derive(Debug, Display, Error)]
#[non_exhaustive]
2019-03-26 18:54:35 +00:00
pub enum ParseError {
/// An invalid `Method`, such as `GE.T`.
#[display(fmt = "Invalid Method specified")]
Method,
2021-04-14 05:07:59 +00:00
2019-03-26 18:54:35 +00:00
/// An invalid `Uri`, such as `exam ple.domain`.
#[display(fmt = "Uri error: {}", _0)]
Uri(InvalidUri),
2021-04-14 05:07:59 +00:00
2019-03-26 18:54:35 +00:00
/// An invalid `HttpVersion`, such as `HTP/1.1`
#[display(fmt = "Invalid HTTP version specified")]
Version,
2021-04-14 05:07:59 +00:00
2019-03-26 18:54:35 +00:00
/// An invalid `Header`.
#[display(fmt = "Invalid Header provided")]
Header,
2021-04-14 05:07:59 +00:00
2019-03-26 18:54:35 +00:00
/// A message head is too large to be reasonable.
#[display(fmt = "Message head is too large")]
TooLarge,
2021-04-14 05:07:59 +00:00
2019-03-26 18:54:35 +00:00
/// A message reached EOF, but is not complete.
#[display(fmt = "Message is incomplete")]
Incomplete,
2021-04-14 05:07:59 +00:00
2019-03-26 18:54:35 +00:00
/// An invalid `Status`, such as `1337 ELITE`.
#[display(fmt = "Invalid Status provided")]
Status,
2021-04-14 05:07:59 +00:00
2019-03-26 18:54:35 +00:00
/// A timeout occurred waiting for an IO event.
#[allow(dead_code)]
#[display(fmt = "Timeout")]
Timeout,
2021-04-14 05:07:59 +00:00
/// An `io::Error` that occurred while trying to read or write to a network stream.
2019-03-26 18:54:35 +00:00
#[display(fmt = "IO error: {}", _0)]
2019-03-28 18:08:24 +00:00
Io(io::Error),
2021-04-14 05:07:59 +00:00
2019-03-26 18:54:35 +00:00
/// Parsing a field as string failed
#[display(fmt = "UTF8 error: {}", _0)]
Utf8(Utf8Error),
}
2019-03-28 18:08:24 +00:00
impl From<io::Error> for ParseError {
fn from(err: io::Error) -> ParseError {
2019-03-26 18:54:35 +00:00
ParseError::Io(err)
}
}
impl From<InvalidUri> for ParseError {
fn from(err: InvalidUri) -> ParseError {
ParseError::Uri(err)
}
}
impl From<Utf8Error> for ParseError {
fn from(err: Utf8Error) -> ParseError {
ParseError::Utf8(err)
}
}
impl From<FromUtf8Error> for ParseError {
fn from(err: FromUtf8Error) -> ParseError {
ParseError::Utf8(err.utf8_error())
}
}
impl From<httparse::Error> for ParseError {
fn from(err: httparse::Error) -> ParseError {
match err {
httparse::Error::HeaderName
| httparse::Error::HeaderValue
| httparse::Error::NewLine
| httparse::Error::Token => ParseError::Header,
httparse::Error::Status => ParseError::Status,
httparse::Error::TooManyHeaders => ParseError::TooLarge,
httparse::Error::Version => ParseError::Version,
}
}
}
2021-06-17 16:57:58 +00:00
impl From<ParseError> for Error {
fn from(err: ParseError) -> Self {
Self::new_parse().with_cause(err)
}
}
impl From<ParseError> for Response<AnyBody> {
fn from(err: ParseError) -> Self {
Error::from(err).into()
}
}
/// A set of errors that can occur running blocking tasks in thread pool.
2021-04-14 05:07:59 +00:00
#[derive(Debug, Display, Error)]
#[display(fmt = "Blocking thread pool is gone")]
pub struct BlockingError;
2021-04-14 05:07:59 +00:00
/// A set of errors that can occur during payload parsing.
#[derive(Debug, Display)]
#[non_exhaustive]
2019-03-26 18:54:35 +00:00
pub enum PayloadError {
/// A payload reached EOF, but is not complete.
2019-03-28 12:34:33 +00:00
#[display(
fmt = "A payload reached EOF, but is not complete. Inner error: {:?}",
2019-03-28 12:34:33 +00:00
_0
)]
2019-03-26 18:54:35 +00:00
Incomplete(Option<io::Error>),
/// Content encoding stream corruption.
2019-03-26 18:54:35 +00:00
#[display(fmt = "Can not decode content-encoding.")]
EncodingCorrupted,
/// Payload reached size limit.
#[display(fmt = "Payload reached size limit.")]
2019-03-26 18:54:35 +00:00
Overflow,
/// Payload length is unknown.
#[display(fmt = "Payload length is unknown.")]
2019-03-26 18:54:35 +00:00
UnknownLength,
/// HTTP/2 payload error.
2019-03-26 18:54:35 +00:00
#[display(fmt = "{}", _0)]
Http2Payload(h2::Error),
/// Generic I/O error.
2019-03-28 18:08:24 +00:00
#[display(fmt = "{}", _0)]
Io(io::Error),
}
impl std::error::Error for PayloadError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
PayloadError::Incomplete(None) => None,
PayloadError::Incomplete(Some(err)) => Some(err as &dyn std::error::Error),
PayloadError::EncodingCorrupted => None,
PayloadError::Overflow => None,
PayloadError::UnknownLength => None,
PayloadError::Http2Payload(err) => Some(err as &dyn std::error::Error),
PayloadError::Io(err) => Some(err as &dyn std::error::Error),
}
}
}
2019-03-28 18:08:24 +00:00
impl From<h2::Error> for PayloadError {
fn from(err: h2::Error) -> Self {
PayloadError::Http2Payload(err)
}
}
impl From<Option<io::Error>> for PayloadError {
fn from(err: Option<io::Error>) -> Self {
PayloadError::Incomplete(err)
}
2019-03-26 18:54:35 +00:00
}
impl From<io::Error> for PayloadError {
fn from(err: io::Error) -> Self {
PayloadError::Incomplete(Some(err))
}
}
impl From<BlockingError> for PayloadError {
fn from(_: BlockingError) -> Self {
PayloadError::Io(io::Error::new(
io::ErrorKind::Other,
"Operation is canceled",
))
2019-03-28 18:08:24 +00:00
}
}
2021-06-17 16:57:58 +00:00
impl From<PayloadError> for Error {
fn from(err: PayloadError) -> Self {
Self::new_payload().with_cause(err)
2019-03-26 18:54:35 +00:00
}
}
2021-04-14 05:07:59 +00:00
/// A set of errors that can occur during dispatching HTTP requests.
#[derive(Debug, Display, Error, From)]
#[non_exhaustive]
2019-03-26 18:54:35 +00:00
pub enum DispatchError {
/// Service error
2021-06-17 16:57:58 +00:00
// FIXME: display and error type
#[display(fmt = "Service Error")]
Service(#[error(not(source))] Response<AnyBody>),
/// Body error
// FIXME: display and error type
#[display(fmt = "Body Error")]
Body(#[error(not(source))] Box<dyn StdError>),
2019-03-26 18:54:35 +00:00
/// Upgrade service error
Upgrade,
2021-06-17 16:57:58 +00:00
/// An `io::Error` that occurred while trying to read or write to a network stream.
2019-03-26 18:54:35 +00:00
#[display(fmt = "IO error: {}", _0)]
Io(io::Error),
/// Http request parse error.
#[display(fmt = "Parse error: {}", _0)]
Parse(ParseError),
/// Http/2 error
#[display(fmt = "{}", _0)]
H2(h2::Error),
/// The first request did not complete within the specified timeout.
#[display(fmt = "The first request did not complete within the specified timeout")]
SlowRequestTimeout,
/// Disconnect timeout. Makes sense for ssl streams.
#[display(fmt = "Connection shutdown timeout")]
DisconnectTimeout,
/// Payload is not consumed
#[display(fmt = "Task is completed but request's payload is not consumed")]
PayloadIsNotConsumed,
/// Malformed request
#[display(fmt = "Malformed request")]
MalformedRequest,
/// Internal error
#[display(fmt = "Internal error")]
InternalError,
/// Unknown error
#[display(fmt = "Unknown error")]
Unknown,
}
2021-04-14 05:07:59 +00:00
/// A set of error that can occur during parsing content type.
#[derive(Debug, Display, Error)]
#[non_exhaustive]
2019-03-26 18:54:35 +00:00
pub enum ContentTypeError {
/// Can not parse content type
#[display(fmt = "Can not parse content type")]
ParseError,
2019-03-26 18:54:35 +00:00
/// Unknown content encoding
#[display(fmt = "Unknown content encoding")]
UnknownEncoding,
}
2021-04-14 05:07:59 +00:00
#[cfg(test)]
mod content_type_test_impls {
use super::*;
impl std::cmp::PartialEq for ContentTypeError {
fn eq(&self, other: &Self) -> bool {
match self {
Self::ParseError => matches!(other, ContentTypeError::ParseError),
Self::UnknownEncoding => {
matches!(other, ContentTypeError::UnknownEncoding)
}
}
}
}
}
2019-03-26 18:54:35 +00:00
#[cfg(test)]
mod tests {
use super::*;
use http::{Error as HttpError, StatusCode};
use std::io;
#[test]
fn test_into_response() {
2021-06-17 16:57:58 +00:00
let resp: Response<AnyBody> = ParseError::Incomplete.into();
2019-03-26 18:54:35 +00:00
assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
let err: HttpError = StatusCode::from_u16(10000).err().unwrap().into();
2021-06-17 16:57:58 +00:00
let resp: Response<AnyBody> = Error::new_http().with_cause(err).into();
2019-03-26 18:54:35 +00:00
assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR);
}
#[test]
fn test_as_response() {
let orig = io::Error::new(io::ErrorKind::Other, "other");
2021-06-17 16:57:58 +00:00
let err: Error = ParseError::Io(orig).into();
assert_eq!(
format!("{}", err),
"error parsing HTTP message: IO error: other"
);
2019-03-26 18:54:35 +00:00
}
#[test]
fn test_error_display() {
let orig = io::Error::new(io::ErrorKind::Other, "other");
2021-06-17 16:57:58 +00:00
let err = Error::new_io().with_cause(orig);
assert_eq!("connection error: other", err.to_string());
2019-03-26 18:54:35 +00:00
}
#[test]
fn test_error_http_response() {
let orig = io::Error::new(io::ErrorKind::Other, "other");
2021-06-17 16:57:58 +00:00
let err = Error::new_io().with_cause(orig);
let resp: Response<AnyBody> = err.into();
2019-03-26 18:54:35 +00:00
assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR);
}
2019-03-28 12:04:39 +00:00
#[test]
fn test_payload_error() {
let err: PayloadError =
io::Error::new(io::ErrorKind::Other, "ParseError").into();
assert!(err.to_string().contains("ParseError"));
2019-03-28 12:04:39 +00:00
2019-03-28 12:34:33 +00:00
let err = PayloadError::Incomplete(None);
2019-03-28 12:04:39 +00:00
assert_eq!(
err.to_string(),
"A payload reached EOF, but is not complete. Inner error: None"
2019-03-28 12:04:39 +00:00
);
}
2019-03-26 18:54:35 +00:00
macro_rules! from {
($from:expr => $error:pat) => {
match ParseError::from($from) {
err @ $error => {
assert!(err.to_string().len() >= 5);
2019-03-26 18:54:35 +00:00
}
err => unreachable!("{:?}", err),
2019-03-26 18:54:35 +00:00
}
};
}
macro_rules! from_and_cause {
($from:expr => $error:pat) => {
match ParseError::from($from) {
e @ $error => {
let desc = format!("{}", e);
assert_eq!(desc, format!("IO error: {}", $from));
2019-03-26 18:54:35 +00:00
}
_ => unreachable!("{:?}", $from),
}
};
}
#[test]
fn test_from() {
from_and_cause!(io::Error::new(io::ErrorKind::Other, "other") => ParseError::Io(..));
from!(httparse::Error::HeaderName => ParseError::Header);
from!(httparse::Error::HeaderName => ParseError::Header);
from!(httparse::Error::HeaderValue => ParseError::Header);
from!(httparse::Error::NewLine => ParseError::Header);
from!(httparse::Error::Status => ParseError::Status);
from!(httparse::Error::Token => ParseError::Header);
from!(httparse::Error::TooManyHeaders => ParseError::TooLarge);
from!(httparse::Error::Version => ParseError::Version);
}
}