1
0
Fork 0
mirror of https://github.com/actix/actix-web.git synced 2024-05-20 01:08:10 +00:00
actix-web/actix-http/src/error.rs

489 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};
2023-07-17 01:38:12 +00:00
pub use http::Error as HttpError;
2021-06-17 16:57:58 +00:00
use http::{uri::InvalidUri, StatusCode};
2019-03-26 18:54:35 +00:00
2022-01-31 21:22:23 +00:00
use crate::{body::BoxBody, Response};
2021-02-13 15:08:43 +00:00
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-11-16 22:10:30 +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
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
}
2022-02-22 08:45:28 +00:00
#[allow(unused)] // available for future use
2021-06-17 16:57:58 +00:00
pub(crate) fn new_io() -> Self {
Self::new(Kind::Io)
2019-03-26 18:54:35 +00:00
}
2021-11-16 22:10:30 +00:00
#[allow(unused)] // used in encoder behind feature flag so ignore unused warning
2021-06-17 16:57:58 +00:00
pub(crate) fn new_encoder() -> Self {
Self::new(Kind::Encoder)
}
2022-01-31 21:22:23 +00:00
#[allow(unused)] // used with `ws` feature flag
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-12-04 19:40:47 +00:00
impl From<Error> for Response<BoxBody> {
2019-03-26 18:54:35 +00:00
fn from(err: Error) -> Self {
2021-12-04 19:40:47 +00:00
// TODO: more appropriate error status codes, usage assessment needed
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-12-04 19:40:47 +00:00
Response::new(status_code).set_body(BoxBody::new(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)]
2021-11-16 22:10:30 +00:00
pub(crate) enum Kind {
2021-06-17 16:57:58 +00:00
#[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 {
2022-02-22 07:04:23 +00:00
f.debug_struct("actix_http::Error")
.field("kind", &self.inner.kind)
.field("cause", &self.inner.cause)
.finish()
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<HttpError> for Error {
fn from(err: HttpError) -> Self {
Self::new_http().with_cause(err)
}
}
2022-01-31 21:22:23 +00:00
#[cfg(feature = "ws")]
impl From<crate::ws::HandshakeError> for Error {
fn from(err: crate::ws::HandshakeError) -> Self {
2021-06-17 16:57:58 +00:00
Self::new_ws().with_cause(err)
2019-03-26 18:54:35 +00:00
}
}
2022-01-31 21:22:23 +00:00
#[cfg(feature = "ws")]
impl From<crate::ws::ProtocolError> for Error {
fn from(err: crate::ws::ProtocolError) -> Self {
2021-12-04 19:40:47 +00:00
Self::new_ws().with_cause(err)
}
}
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")]
2019-03-26 18:54:35 +00:00
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)]
2019-03-26 18:54:35 +00:00
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")]
2019-03-26 18:54:35 +00:00
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")]
2019-03-26 18:54:35 +00:00
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")]
2019-03-26 18:54:35 +00:00
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")]
2019-03-26 18:54:35 +00:00
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")]
2019-03-26 18:54:35 +00:00
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")]
2019-03-26 18:54:35 +00:00
Timeout,
2021-04-14 05:07:59 +00:00
/// An I/O error that occurred while trying to read or write to a network stream.
#[display(fmt = "I/O error: {}", _0)]
2019-03-28 18:08:24 +00:00
Io(io::Error),
2021-04-14 05:07:59 +00:00
2021-08-12 19:18:09 +00:00
/// Parsing a field as string failed.
#[display(fmt = "UTF-8 error: {}", _0)]
2019-03-26 18:54:35 +00:00
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)
}
}
2021-12-04 19:40:47 +00:00
impl From<ParseError> for Response<BoxBody> {
2021-06-17 16:57:58 +00:00
fn from(err: ParseError) -> Self {
Error::from(err).into()
}
}
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.
#[display(fmt = "payload reached EOF before completing: {:?}", _0)]
2019-03-26 18:54:35 +00:00
Incomplete(Option<io::Error>),
/// Content encoding stream corruption.
#[display(fmt = "can not decode content-encoding")]
2019-03-26 18:54:35 +00:00
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.
2022-01-31 21:22:23 +00:00
#[cfg(feature = "http2")]
2019-03-26 18:54:35 +00:00
#[display(fmt = "{}", _0)]
2022-01-31 21:22:23 +00:00
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,
2022-02-22 08:45:28 +00:00
PayloadError::Incomplete(Some(err)) => Some(err),
PayloadError::EncodingCorrupted => None,
PayloadError::Overflow => None,
PayloadError::UnknownLength => None,
2022-01-31 21:22:23 +00:00
#[cfg(feature = "http2")]
2022-02-22 08:45:28 +00:00
PayloadError::Http2Payload(err) => Some(err),
PayloadError::Io(err) => Some(err),
}
}
}
2022-01-31 21:22:23 +00:00
#[cfg(feature = "http2")]
impl From<::h2::Error> for PayloadError {
fn from(err: ::h2::Error) -> Self {
2019-03-28 18:08:24 +00:00
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))
}
}
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, From)]
#[non_exhaustive]
2019-03-26 18:54:35 +00:00
pub enum DispatchError {
/// Service error.
#[display(fmt = "service error")]
Service(Response<BoxBody>),
2021-06-17 16:57:58 +00:00
/// Body streaming error.
#[display(fmt = "body error: {}", _0)]
Body(Box<dyn StdError>),
2019-03-26 18:54:35 +00:00
/// Upgrade service error.
#[display(fmt = "upgrade 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.
#[display(fmt = "I/O error: {}", _0)]
2019-03-26 18:54:35 +00:00
Io(io::Error),
/// Request parse error.
#[display(fmt = "request parse error: {}", _0)]
2019-03-26 18:54:35 +00:00
Parse(ParseError),
/// HTTP/2 error.
2019-03-26 18:54:35 +00:00
#[display(fmt = "{}", _0)]
2022-01-31 21:22:23 +00:00
#[cfg(feature = "http2")]
2019-03-26 18:54:35 +00:00
H2(h2::Error),
/// The first request did not complete within the specified timeout.
#[display(fmt = "request did not complete within the specified timeout")]
2019-03-26 18:54:35 +00:00
SlowRequestTimeout,
/// Disconnect timeout. Makes sense for TLS streams.
#[display(fmt = "connection shutdown timeout")]
2019-03-26 18:54:35 +00:00
DisconnectTimeout,
/// Handler dropped payload before reading EOF.
#[display(fmt = "handler dropped payload before reading EOF")]
HandlerDroppedPayload,
/// Internal error.
#[display(fmt = "internal error")]
2019-03-26 18:54:35 +00:00
InternalError,
}
2019-03-26 18:54:35 +00:00
impl StdError for DispatchError {
fn source(&self) -> Option<&(dyn StdError + 'static)> {
match self {
DispatchError::Service(_res) => None,
DispatchError::Body(err) => Some(&**err),
DispatchError::Io(err) => Some(err),
DispatchError::Parse(err) => Some(err),
2022-01-31 21:22:23 +00:00
#[cfg(feature = "http2")]
DispatchError::H2(err) => Some(err),
2022-01-31 21:22:23 +00:00
_ => None,
}
}
2019-03-26 18:54:35 +00:00
}
2021-04-14 05:07:59 +00:00
/// A set of error that can occur during parsing content type.
#[derive(Debug, Display, Error)]
#[cfg_attr(test, derive(PartialEq, Eq))]
2021-04-14 05:07:59 +00:00
#[non_exhaustive]
2019-03-26 18:54:35 +00:00
pub enum ContentTypeError {
/// Can not parse content type.
#[display(fmt = "could not parse content type")]
2019-03-26 18:54:35 +00:00
ParseError,
/// Unknown content encoding.
#[display(fmt = "unknown content encoding")]
2019-03-26 18:54:35 +00:00
UnknownEncoding,
}
2021-04-14 05:07:59 +00:00
#[cfg(test)]
mod tests {
use http::Error as HttpError;
2021-04-14 05:07:59 +00:00
2019-03-26 18:54:35 +00:00
use super::*;
#[test]
fn test_into_response() {
2021-12-04 19:40:47 +00:00
let resp: Response<BoxBody> = 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-12-04 19:40:47 +00:00
let resp: Response<BoxBody> = 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: I/O error: other"
2021-06-17 16:57:58 +00:00
);
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);
2021-12-04 19:40:47 +00:00
let resp: Response<BoxBody> = 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() {
2021-12-08 06:01:11 +00:00
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(),
"payload reached EOF before completing: 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!("I/O 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);
}
}