http: Convert from `derive_more` to `thiserror`

The `thiserror` has the advantage of implementing `std::error::Error`
and it integrates better with the Rust ecosystem.

Signed-off-by: Otavio Salvador <otavio@ossystems.com.br>
This commit is contained in:
Otavio Salvador 2020-03-11 23:00:55 -03:00
parent 9f196fe5a5
commit d2259b57dc
4 changed files with 112 additions and 171 deletions

View File

@ -56,7 +56,6 @@ base64 = "0.11"
bitflags = "1.2"
bytes = "0.5.3"
copyless = "0.1.4"
derive_more = "0.99.2"
either = "1.5.3"
encoding_rs = "0.8"
futures-core = "0.3.1"
@ -80,6 +79,7 @@ serde_json = "1.0"
sha-1 = "0.8"
slab = "0.4"
serde_urlencoded = "0.6.1"
thiserror = "1.0.11"
time = { version = "0.2.7", default-features = false, features = ["std"] }
# for secure cookie

View File

@ -1,7 +1,7 @@
use std::io;
use actix_connect::resolver::ResolveError;
use derive_more::{Display, From};
use thiserror::Error;
#[cfg(feature = "openssl")]
use actix_connect::ssl::openssl::{HandshakeError, SslError};
@ -10,49 +10,49 @@ use crate::error::{Error, ParseError, ResponseError};
use crate::http::{Error as HttpError, StatusCode};
/// A set of errors that can occur while connecting to an HTTP host
#[derive(Debug, Display, From)]
#[derive(Debug, Error)]
pub enum ConnectError {
/// SSL feature is not enabled
#[display(fmt = "SSL is not supported")]
#[error("SSL is not supported")]
SslIsNotSupported,
/// SSL error
#[cfg(feature = "openssl")]
#[display(fmt = "{}", _0)]
SslError(SslError),
#[error(transparent)]
SslError(#[from] SslError),
/// SSL Handshake error
#[cfg(feature = "openssl")]
#[display(fmt = "{}", _0)]
#[error("SSL handshake error: {0}")]
SslHandshakeError(String),
/// Failed to resolve the hostname
#[display(fmt = "Failed resolving hostname: {}", _0)]
Resolver(ResolveError),
#[error("Failed resolving hostname: {0}")]
Resolver(#[from] ResolveError),
/// No dns records
#[display(fmt = "No dns records found for the input")]
#[error("No dns records found for the input")]
NoRecords,
/// Http2 error
#[display(fmt = "{}", _0)]
H2(h2::Error),
#[error(transparent)]
H2(#[from] h2::Error),
/// Connecting took too long
#[display(fmt = "Timeout out while establishing connection")]
#[error("Timeout out while establishing connection")]
Timeout,
/// Connector has been disconnected
#[display(fmt = "Internal error: connector has been disconnected")]
#[error("Internal error: connector has been disconnected")]
Disconnected,
/// Unresolved host name
#[display(fmt = "Connector received `Connect` method with unresolved host")]
#[error("Connector received `Connect` method with unresolved host")]
Unresolverd,
/// Connection io error
#[display(fmt = "{}", _0)]
Io(io::Error),
#[error(transparent)]
Io(#[from] io::Error),
}
impl From<actix_connect::ConnectError> for ConnectError {
@ -74,45 +74,48 @@ impl<T: std::fmt::Debug> From<HandshakeError<T>> for ConnectError {
}
}
#[derive(Debug, Display, From)]
#[derive(Debug, Error)]
pub enum InvalidUrl {
#[display(fmt = "Missing url scheme")]
#[error("Missing url scheme")]
MissingScheme,
#[display(fmt = "Unknown url scheme")]
#[error("Unknown url scheme")]
UnknownScheme,
#[display(fmt = "Missing host name")]
#[error("Missing host name")]
MissingHost,
#[display(fmt = "Url parse error: {}", _0)]
HttpError(http::Error),
#[error("Url parse error: {0}")]
HttpError(#[from] http::Error),
}
/// A set of errors that can occur during request sending and response reading
#[derive(Debug, Display, From)]
#[derive(Debug, Error)]
pub enum SendRequestError {
/// Invalid URL
#[display(fmt = "Invalid URL: {}", _0)]
Url(InvalidUrl),
#[error("Invalid URL: {0}")]
Url(#[from] InvalidUrl),
/// Failed to connect to host
#[display(fmt = "Failed to connect to host: {}", _0)]
Connect(ConnectError),
#[error("Failed to connect to host: {0}")]
Connect(#[from] ConnectError),
/// Error sending request
Send(io::Error),
#[error(transparent)]
Send(#[from] io::Error),
/// Error parsing response
Response(ParseError),
#[error(transparent)]
Response(#[from] ParseError),
/// Http error
#[display(fmt = "{}", _0)]
Http(HttpError),
#[error(transparent)]
Http(#[from] HttpError),
/// Http2 error
#[display(fmt = "{}", _0)]
H2(h2::Error),
#[error(transparent)]
H2(#[from] h2::Error),
/// Response took too long
#[display(fmt = "Timeout out while waiting for response")]
#[error("Timeout out while waiting for response")]
Timeout,
/// Tunnels are not supported for http2 connection
#[display(fmt = "Tunnels are not supported for http2 connection")]
#[error("Tunnels are not supported for http2 connection")]
TunnelNotSupported,
/// Error sending request body
Body(Error),
#[error(transparent)]
Body(#[from] Error),
}
/// Convert `SendRequestError` to a server `Response`
@ -129,21 +132,12 @@ impl ResponseError for SendRequestError {
}
/// A set of errors that can occur during freezing a request
#[derive(Debug, Display, From)]
#[derive(Debug, Error)]
pub enum FreezeRequestError {
/// Invalid URL
#[display(fmt = "Invalid URL: {}", _0)]
Url(InvalidUrl),
#[error("Invalid URL: {0}")]
Url(#[from] InvalidUrl),
/// Http error
#[display(fmt = "{}", _0)]
Http(HttpError),
}
impl From<FreezeRequestError> for SendRequestError {
fn from(e: FreezeRequestError) -> Self {
match e {
FreezeRequestError::Url(e) => e.into(),
FreezeRequestError::Http(e) => e.into(),
}
}
#[error(transparent)]
Http(#[from] HttpError),
}

View File

@ -2,7 +2,6 @@
use std::cell::RefCell;
use std::io::Write;
use std::str::Utf8Error;
use std::string::FromUtf8Error;
use std::{fmt, io, result};
use actix_codec::{Decoder, Encoder};
@ -10,13 +9,13 @@ pub use actix_threadpool::BlockingError;
use actix_utils::framed::DispatcherError as FramedDispatcherError;
use actix_utils::timeout::TimeoutError;
use bytes::BytesMut;
use derive_more::{Display, From};
pub use futures_channel::oneshot::Canceled;
use http::uri::InvalidUri;
use http::{header, Error as HttpError, StatusCode};
use serde::de::value::Error as DeError;
use serde_json::error::Error as JsonError;
use serde_urlencoded::ser::Error as FormError;
use thiserror::Error;
// re-export for convinience
use crate::body::Body;
@ -42,6 +41,7 @@ pub type Result<T, E = Error> = result::Result<T, E>;
/// for it that can be used to create an http response from it this means that
/// if you have access to an actix `Error` you can always get a
/// `ResponseError` reference from it.
#[derive(Error)]
pub struct Error {
cause: Box<dyn ResponseError>,
}
@ -98,16 +98,6 @@ impl fmt::Debug for Error {
}
}
impl std::error::Error for Error {
fn cause(&self) -> Option<&dyn std::error::Error> {
None
}
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
None
}
}
impl From<()> for Error {
fn from(_: ()) -> Self {
Error::from(UnitError)
@ -162,8 +152,8 @@ impl<E: ResponseError> ResponseError for TimeoutError<E> {
}
}
#[derive(Debug, Display)]
#[display(fmt = "UnknownError")]
#[derive(Debug, Error)]
#[error("UnknownError")]
struct UnitError;
/// `InternalServerError` for `UnitError`
@ -226,40 +216,40 @@ impl ResponseError for header::InvalidHeaderValue {
}
/// A set of errors that can occur during parsing HTTP streams
#[derive(Debug, Display)]
#[derive(Debug, Error)]
pub enum ParseError {
/// An invalid `Method`, such as `GE.T`.
#[display(fmt = "Invalid Method specified")]
#[error("Invalid Method specified")]
Method,
/// An invalid `Uri`, such as `exam ple.domain`.
#[display(fmt = "Uri error: {}", _0)]
Uri(InvalidUri),
#[error("Uri error: {0}")]
Uri(#[from] InvalidUri),
/// An invalid `HttpVersion`, such as `HTP/1.1`
#[display(fmt = "Invalid HTTP version specified")]
#[error("Invalid HTTP version specified")]
Version,
/// An invalid `Header`.
#[display(fmt = "Invalid Header provided")]
#[error("Invalid Header provided")]
Header,
/// A message head is too large to be reasonable.
#[display(fmt = "Message head is too large")]
#[error("Message head is too large")]
TooLarge,
/// A message reached EOF, but is not complete.
#[display(fmt = "Message is incomplete")]
#[error("Message is incomplete")]
Incomplete,
/// An invalid `Status`, such as `1337 ELITE`.
#[display(fmt = "Invalid Status provided")]
#[error("Invalid Status provided")]
Status,
/// A timeout occurred waiting for an IO event.
#[allow(dead_code)]
#[display(fmt = "Timeout")]
#[error("Timeout")]
Timeout,
/// An `io::Error` that occurred while trying to read or write to a network
/// stream.
#[display(fmt = "IO error: {}", _0)]
Io(io::Error),
#[error("IO error: {0}")]
Io(#[from] io::Error),
/// Parsing a field as string failed
#[display(fmt = "UTF8 error: {}", _0)]
Utf8(Utf8Error),
#[error("UTF8 error: {0}")]
Utf8(#[from] Utf8Error),
}
/// Return `BadRequest` for `ParseError`
@ -269,30 +259,6 @@ impl ResponseError for ParseError {
}
}
impl From<io::Error> for ParseError {
fn from(err: io::Error) -> ParseError {
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 {
@ -307,48 +273,27 @@ impl From<httparse::Error> for ParseError {
}
}
#[derive(Display, Debug)]
#[derive(Error, Debug)]
/// A set of errors that can occur during payload parsing
pub enum PayloadError {
/// A payload reached EOF, but is not complete.
#[display(
fmt = "A payload reached EOF, but is not complete. With error: {:?}",
_0
)]
Incomplete(Option<io::Error>),
#[error("A payload reached EOF, but is not complete. With error: {0:?}")]
Incomplete(#[from] Option<io::Error>),
/// Content encoding stream corruption
#[display(fmt = "Can not decode content-encoding.")]
#[error("Can not decode content-encoding.")]
EncodingCorrupted,
/// A payload reached size limit.
#[display(fmt = "A payload reached size limit.")]
#[error("A payload reached size limit.")]
Overflow,
/// A payload length is unknown.
#[display(fmt = "A payload length is unknown.")]
#[error("A payload length is unknown.")]
UnknownLength,
/// Http2 payload error
#[display(fmt = "{}", _0)]
Http2Payload(h2::Error),
#[error(transparent)]
Http2Payload(#[from] h2::Error),
/// Io error
#[display(fmt = "{}", _0)]
Io(io::Error),
}
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)
}
}
impl From<io::Error> for PayloadError {
fn from(err: io::Error) -> Self {
PayloadError::Incomplete(Some(err))
}
#[error(transparent)]
Io(#[from] io::Error),
}
impl From<BlockingError<io::Error>> for PayloadError {
@ -383,61 +328,63 @@ impl ResponseError for crate::cookie::ParseError {
}
}
#[derive(Debug, Display, From)]
#[derive(Debug, Error)]
/// A set of errors that can occur during dispatching http requests
pub enum DispatchError {
/// Service error
Service(Error),
#[error(transparent)]
Service(#[from] Error),
/// Upgrade service error
#[error("Upgrade service error")]
Upgrade,
/// An `io::Error` that occurred while trying to read or write to a network
/// stream.
#[display(fmt = "IO error: {}", _0)]
Io(io::Error),
#[error("IO error: {0}")]
Io(#[from] io::Error),
/// Http request parse error.
#[display(fmt = "Parse error: {}", _0)]
Parse(ParseError),
#[error("Parse error: {0}")]
Parse(#[from] ParseError),
/// Http/2 error
#[display(fmt = "{}", _0)]
H2(h2::Error),
#[error(transparent)]
H2(#[from] h2::Error),
/// The first request did not complete within the specified timeout.
#[display(fmt = "The first request did not complete within the specified timeout")]
#[error("The first request did not complete within the specified timeout")]
SlowRequestTimeout,
/// Disconnect timeout. Makes sense for ssl streams.
#[display(fmt = "Connection shutdown timeout")]
#[error("Connection shutdown timeout")]
DisconnectTimeout,
/// Payload is not consumed
#[display(fmt = "Task is completed but request's payload is not consumed")]
#[error("Task is completed but request's payload is not consumed")]
PayloadIsNotConsumed,
/// Malformed request
#[display(fmt = "Malformed request")]
#[error("Malformed request")]
MalformedRequest,
/// Internal error
#[display(fmt = "Internal error")]
#[error("Internal error")]
InternalError,
/// Unknown error
#[display(fmt = "Unknown error")]
#[error("Unknown error")]
Unknown,
}
/// A set of error that can occure during parsing content type
#[derive(PartialEq, Debug, Display)]
#[derive(Error, PartialEq, Debug)]
pub enum ContentTypeError {
/// Can not parse content type
#[display(fmt = "Can not parse content type")]
#[error("Can not parse content type")]
ParseError,
/// Unknown content encoding
#[display(fmt = "Unknown content encoding")]
#[error("Unknown content encoding")]
UnknownEncoding,
}

View File

@ -5,8 +5,8 @@
//! communicate with the peer.
use std::io;
use derive_more::{Display, From};
use http::{header, Method, StatusCode};
use thiserror::Error;
use crate::error::ResponseError;
use crate::message::RequestHead;
@ -24,62 +24,62 @@ pub use self::frame::Parser;
pub use self::proto::{hash_key, CloseCode, CloseReason, OpCode};
/// Websocket protocol errors
#[derive(Debug, Display, From)]
#[derive(Debug, Error)]
pub enum ProtocolError {
/// Received an unmasked frame from client
#[display(fmt = "Received an unmasked frame from client")]
#[error("Received an unmasked frame from client")]
UnmaskedFrame,
/// Received a masked frame from server
#[display(fmt = "Received a masked frame from server")]
#[error("Received a masked frame from server")]
MaskedFrame,
/// Encountered invalid opcode
#[display(fmt = "Invalid opcode: {}", _0)]
#[error("Invalid opcode: {0}")]
InvalidOpcode(u8),
/// Invalid control frame length
#[display(fmt = "Invalid control frame length: {}", _0)]
#[error("Invalid control frame length: {0}")]
InvalidLength(usize),
/// Bad web socket op code
#[display(fmt = "Bad web socket op code")]
#[error("Bad web socket op code")]
BadOpCode,
/// A payload reached size limit.
#[display(fmt = "A payload reached size limit.")]
#[error("A payload reached size limit.")]
Overflow,
/// Continuation is not started
#[display(fmt = "Continuation is not started.")]
#[error("Continuation is not started.")]
ContinuationNotStarted,
/// Received new continuation but it is already started
#[display(fmt = "Received new continuation but it is already started")]
#[error("Received new continuation but it is already started")]
ContinuationStarted,
/// Unknown continuation fragment
#[display(fmt = "Unknown continuation fragment.")]
#[error("Unknown continuation fragment.")]
ContinuationFragment(OpCode),
/// Io error
#[display(fmt = "io error: {}", _0)]
Io(io::Error),
#[error("io error: {0}")]
Io(#[from] io::Error),
}
impl ResponseError for ProtocolError {}
/// Websocket handshake errors
#[derive(PartialEq, Debug, Display)]
#[derive(PartialEq, Debug, Error)]
pub enum HandshakeError {
/// Only get method is allowed
#[display(fmt = "Method not allowed")]
#[error("Method not allowed")]
GetMethodRequired,
/// Upgrade header if not set to websocket
#[display(fmt = "Websocket upgrade is expected")]
#[error("Websocket upgrade is expected")]
NoWebsocketUpgrade,
/// Connection header is not set to upgrade
#[display(fmt = "Connection upgrade is expected")]
#[error("Connection upgrade is expected")]
NoConnectionUpgrade,
/// Websocket version header is not set
#[display(fmt = "Websocket version header is required")]
#[error("Websocket version header is required")]
NoVersionHeader,
/// Unsupported websocket version
#[display(fmt = "Unsupported version")]
#[error("Unsupported version")]
UnsupportedVersion,
/// Websocket key is not set or wrong
#[display(fmt = "Unknown websocket key")]
#[error("Unknown websocket key")]
BadWebsocketKey,
}