use std::{error::Error, io};
use serde_json::error::Error as JsonError;
use thiserror::Error;
#[cfg(feature = "openssl")]
use crate::connect::openssl::{HandshakeError, SslError};
use crate::http::error::{DecodeError, EncodeError, HttpError, PayloadError};
use crate::util::Either;
#[derive(Error, Debug)]
pub enum JsonPayloadError {
#[error("Content type error")]
ContentType,
#[error("Json deserialize error: {0}")]
Deserialize(#[from] JsonError),
#[error("Error that occur during reading payload: {0}")]
Payload(#[from] PayloadError),
}
#[derive(Error, Debug)]
pub enum ConnectError {
#[error("SSL is not supported")]
SslIsNotSupported,
#[cfg(feature = "openssl")]
#[error("{0}")]
SslError(std::rc::Rc<SslError>),
#[cfg(feature = "openssl")]
#[error("{0}")]
SslHandshakeError(String),
#[error("Failed resolving hostname: {0}")]
Resolver(#[from] io::Error),
#[error("No dns records found for the input")]
NoRecords,
#[error("Timeout while establishing connection")]
Timeout,
#[error("Connector has been disconnected")]
Disconnected(Option<io::Error>),
#[error("Connector received `Connect` method with unresolved host")]
Unresolved,
}
impl Clone for ConnectError {
fn clone(&self) -> Self {
match self {
ConnectError::SslIsNotSupported => ConnectError::SslIsNotSupported,
#[cfg(feature = "openssl")]
ConnectError::SslError(e) => ConnectError::SslError(e.clone()),
#[cfg(feature = "openssl")]
ConnectError::SslHandshakeError(e) => {
ConnectError::SslHandshakeError(e.clone())
}
ConnectError::Resolver(e) => {
ConnectError::Resolver(io::Error::new(e.kind(), format!("{}", e)))
}
ConnectError::NoRecords => ConnectError::NoRecords,
ConnectError::Timeout => ConnectError::Timeout,
ConnectError::Disconnected(e) => {
if let Some(e) = e {
ConnectError::Disconnected(Some(io::Error::new(
e.kind(),
format!("{}", e),
)))
} else {
ConnectError::Disconnected(None)
}
}
ConnectError::Unresolved => ConnectError::Unresolved,
}
}
}
#[cfg(feature = "openssl")]
impl From<SslError> for ConnectError {
fn from(err: SslError) -> Self {
ConnectError::SslError(std::rc::Rc::new(err))
}
}
impl From<crate::connect::ConnectError> for ConnectError {
fn from(err: crate::connect::ConnectError) -> ConnectError {
match err {
crate::connect::ConnectError::Resolver(e) => ConnectError::Resolver(e),
crate::connect::ConnectError::NoRecords => ConnectError::NoRecords,
crate::connect::ConnectError::InvalidInput => panic!(),
crate::connect::ConnectError::Unresolved => ConnectError::Unresolved,
crate::connect::ConnectError::Io(e) => ConnectError::Disconnected(Some(e)),
}
}
}
#[cfg(feature = "openssl")]
impl<T: std::fmt::Debug> From<HandshakeError<T>> for ConnectError {
fn from(err: HandshakeError<T>) -> ConnectError {
ConnectError::SslHandshakeError(format!("{:?}", err))
}
}
#[derive(Error, Debug)]
pub enum InvalidUrl {
#[error("Missing url scheme")]
MissingScheme,
#[error("Unknown url scheme")]
UnknownScheme,
#[error("Missing host name")]
MissingHost,
#[error("Url parse error: {0}")]
Http(#[from] HttpError),
}
#[derive(Error, Debug)]
pub enum SendRequestError {
#[error("Invalid URL: {0}")]
Url(#[from] InvalidUrl),
#[error("Failed to connect to host: {0}")]
Connect(#[from] ConnectError),
#[error("Error sending request: {0}")]
Send(#[from] io::Error),
#[error("Error during request encoding: {0}")]
Request(#[from] EncodeError),
#[error("Error during response parsing: {0}")]
Response(#[from] DecodeError),
#[error("{0}")]
Http(#[from] HttpError),
#[error("Http2 error {0}")]
H2(#[from] ntex_h2::OperationError),
#[error("Timeout while waiting for response")]
Timeout,
#[error("Tunnels are not supported for http2 connection")]
TunnelNotSupported,
#[error("Error sending request body {0}")]
Error(#[from] Box<dyn Error>),
}
impl From<Either<EncodeError, io::Error>> for SendRequestError {
fn from(err: Either<EncodeError, io::Error>) -> Self {
match err {
Either::Left(err) => SendRequestError::Request(err),
Either::Right(err) => SendRequestError::Send(err),
}
}
}
impl From<Either<DecodeError, io::Error>> for SendRequestError {
fn from(err: Either<DecodeError, io::Error>) -> Self {
match err {
Either::Left(err) => SendRequestError::Response(err),
Either::Right(err) => SendRequestError::Send(err),
}
}
}
#[derive(Error, Debug)]
pub enum FreezeRequestError {
#[error("Invalid URL: {0}")]
Url(#[from] InvalidUrl),
#[error("{0}")]
Http(#[from] HttpError),
}
impl From<FreezeRequestError> for SendRequestError {
fn from(e: FreezeRequestError) -> Self {
match e {
FreezeRequestError::Url(e) => e.into(),
FreezeRequestError::Http(e) => e.into(),
}
}
}