use std::convert::Infallible;
use std::error::Error as StdError;
use std::fmt::{self, Display};
use std::io;
use std::result;
#[derive(Debug)]
pub enum InvalidResponseKind {
LocationHeader,
RedirectionUrl,
StatusLine,
StatusCode,
Header,
ChunkSize,
Chunk,
ContentLength,
}
impl Display for InvalidResponseKind {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use InvalidResponseKind::*;
match self {
LocationHeader => write!(f, "missing or invalid location header"),
RedirectionUrl => write!(f, "invalid redirection url"),
StatusLine => write!(f, "invalid status line"),
StatusCode => write!(f, "invalid status code"),
Header => write!(f, "invalid header"),
ChunkSize => write!(f, "invalid chunk size"),
Chunk => write!(f, "invalid chunk"),
ContentLength => write!(f, "invalid content length"),
}
}
}
#[derive(Debug)]
pub enum ErrorKind {
ConnectNotSupported,
ConnectError {
status_code: http::StatusCode,
body: Vec<u8>,
},
Http(http::Error),
Io(io::Error),
InvalidBaseUrl,
InvalidUrlHost,
InvalidUrlPort,
InvalidResponse(InvalidResponseKind),
TooManyRedirections,
StatusCode(http::StatusCode),
#[cfg(feature = "json")]
Json(serde_json::Error),
#[cfg(feature = "form")]
UrlEncoded(serde_urlencoded::ser::Error),
#[cfg(feature = "tls-native")]
Tls(native_tls::Error),
#[cfg(all(feature = "__rustls", not(feature = "tls-native")))]
Tls(rustls::Error),
#[cfg(feature = "__rustls")]
InvalidDNSName(String),
InvalidMimeType(String),
TlsDisabled,
#[cfg(feature = "__rustls")]
WebPKI(webpki::Error),
}
#[derive(Debug)]
pub struct Error(pub(crate) Box<ErrorKind>);
impl Error {
pub fn kind(&self) -> &ErrorKind {
&self.0
}
pub fn into_kind(self) -> ErrorKind {
*self.0
}
}
impl Display for Error {
fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
use ErrorKind::*;
match *self.0 {
ConnectNotSupported => write!(w, "CONNECT is not supported"),
ConnectError { status_code, .. } => write!(w, "Proxy CONNECT error: {status_code}"),
Http(ref e) => write!(w, "Http Error: {e}"),
Io(ref e) => write!(w, "Io Error: {e}"),
InvalidBaseUrl => write!(w, "Invalid base URL"),
InvalidUrlHost => write!(w, "URL is missing a host"),
InvalidUrlPort => write!(w, "URL is missing a port"),
InvalidResponse(ref k) => write!(w, "InvalidResponse: {k}"),
TooManyRedirections => write!(w, "Too many redirections"),
StatusCode(ref sc) => write!(w, "Status code {sc} indicates failure"),
#[cfg(feature = "json")]
Json(ref e) => write!(w, "Json Error: {e}"),
#[cfg(feature = "form")]
UrlEncoded(ref e) => write!(w, "URL Encoding Error: {e}"),
#[cfg(any(feature = "tls-native", feature = "__rustls"))]
Tls(ref e) => write!(w, "Tls Error: {e}"),
#[cfg(feature = "__rustls")]
InvalidDNSName(ref e) => write!(w, "Invalid DNS name: {e}"),
InvalidMimeType(ref e) => write!(w, "Invalid mime type: {e}"),
TlsDisabled => write!(w, "TLS is disabled, activate one of the tls- features"),
#[cfg(feature = "__rustls")]
WebPKI(ref e) => write!(w, "WebPKI error: {e}"),
}
}
}
impl StdError for Error {
fn cause(&self) -> Option<&dyn StdError> {
use ErrorKind::*;
match *self.0 {
Io(ref e) => Some(e),
Http(ref e) => Some(e),
#[cfg(feature = "json")]
Json(ref e) => Some(e),
#[cfg(any(feature = "tls-native", feature = "__rustls"))]
Tls(ref e) => Some(e),
#[cfg(feature = "__rustls")]
WebPKI(ref e) => Some(e),
_ => None,
}
}
}
impl From<Infallible> for Error {
fn from(_err: Infallible) -> Error {
unreachable!()
}
}
impl From<io::Error> for Error {
fn from(err: io::Error) -> Error {
Error(Box::new(ErrorKind::Io(err)))
}
}
impl From<http::Error> for Error {
fn from(err: http::Error) -> Error {
Error(Box::new(ErrorKind::Http(err)))
}
}
impl From<http::header::InvalidHeaderValue> for Error {
fn from(err: http::header::InvalidHeaderValue) -> Error {
Error(Box::new(ErrorKind::Http(http::Error::from(err))))
}
}
#[cfg(feature = "tls-native")]
impl From<native_tls::Error> for Error {
fn from(err: native_tls::Error) -> Error {
Error(Box::new(ErrorKind::Tls(err)))
}
}
#[cfg(all(feature = "__rustls", not(feature = "tls-native")))]
impl From<rustls::Error> for Error {
fn from(err: rustls::Error) -> Error {
Error(Box::new(ErrorKind::Tls(err)))
}
}
#[cfg(feature = "json")]
impl From<serde_json::Error> for Error {
fn from(err: serde_json::Error) -> Error {
Error(Box::new(ErrorKind::Json(err)))
}
}
#[cfg(feature = "form")]
impl From<serde_urlencoded::ser::Error> for Error {
fn from(err: serde_urlencoded::ser::Error) -> Error {
Error(Box::new(ErrorKind::UrlEncoded(err)))
}
}
impl From<ErrorKind> for Error {
fn from(err: ErrorKind) -> Error {
Error(Box::new(err))
}
}
impl From<InvalidResponseKind> for Error {
fn from(kind: InvalidResponseKind) -> Error {
ErrorKind::InvalidResponse(kind).into()
}
}
impl From<Error> for io::Error {
fn from(err: Error) -> io::Error {
io::Error::new(io::ErrorKind::Other, err)
}
}
impl From<InvalidResponseKind> for io::Error {
fn from(kind: InvalidResponseKind) -> io::Error {
io::Error::new(io::ErrorKind::Other, Error(Box::new(ErrorKind::InvalidResponse(kind))))
}
}
#[cfg(feature = "__rustls")]
impl From<webpki::Error> for Error {
fn from(err: webpki::Error) -> Error {
Error(Box::new(ErrorKind::WebPKI(err)))
}
}
pub type Result<T = ()> = result::Result<T, Error>;