use std::error::Error as StdError;
use crate::*;
#[derive(Debug)]
pub enum Kind
{
ResolveProxy,
ResolveHost,
Connect,
Http2,
BodyStreamFailure,
InterfaceFailure,
TooManyRedirects,
NothingFromServer,
SendError,
RecvError,
SslConnect,
SslLocalCertificate,
SslCipher,
SslCertificate,
SslShutdownFailed,
Curl(String),
PartialFile,
Timeout,
NotUtf8(std::string::FromUtf8Error),
}
#[derive(Debug)]
pub struct Error
{
kind: Kind,
url: Option<String>,
}
impl Error
{
pub fn new(kind: Kind, url: Option<String>)
-> Error
{
Error
{
kind,
url,
}
}
pub fn kind(&self) -> &Kind
{
&self.kind
}
pub fn is_network(&self) -> bool
{
use Kind::*;
matches!(
self.kind(),
ResolveProxy
| ResolveHost
| Connect
| SendError
| RecvError
| PartialFile
)
}
}
impl std::fmt::Display for Error
{
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result
{
if let Some(ref url) = self.url
{
std::fmt::Display::fmt(url, f)?;
f.write_str(": ")?;
}
let msg =
match &self.kind
{
Kind::ResolveProxy => "failure resolving proxy",
Kind::ResolveHost => "failure resolving host",
Kind::Connect => "failed connecting to host",
Kind::Http2 => "HTTP2 framing error",
Kind::BodyStreamFailure => "failure reading from the specified Body",
Kind::InterfaceFailure => "outgoing interface could not be used",
Kind::TooManyRedirects => "Redirect loop or too many redirects",
Kind::NothingFromServer => "The server sent nothing",
Kind::SendError => "Failed to send on socket",
Kind::RecvError => "Failed to receive from socket",
Kind::SslConnect => "failure performing SSL handshake",
Kind::SslLocalCertificate => "local client certificate problem",
Kind::SslCipher => "The SSL cipher is invalid",
Kind::SslCertificate => "Remote server's SSL certificate is invalid",
Kind::SslShutdownFailed => "The remote server did not securely close its socket over SSL",
Kind::Curl(a) => &a,
Kind::PartialFile => "The expected was not the reported size",
Kind::Timeout => "The specified timeout was exceeded",
Kind::NotUtf8(_) => "The contents were not UTF-8",
};
std::fmt::Display::fmt(msg, f)
}
}
impl StdError for Error
{
fn source(&self) -> Option<&(dyn StdError + 'static)>
{
None
}
}
pub(crate) fn kind_from_curl(c: sys::CURLcode) -> Kind
{
match c
{
sys::CURLE_COULDNT_RESOLVE_PROXY => Kind::ResolveProxy,
sys::CURLE_COULDNT_RESOLVE_HOST => Kind::ResolveHost,
sys::CURLE_COULDNT_CONNECT => Kind::Connect,
sys::CURLE_HTTP2 | sys::CURLE_HTTP2_STREAM => Kind::Http2,
sys::CURLE_ABORTED_BY_CALLBACK => Kind::BodyStreamFailure,
sys::CURLE_PARTIAL_FILE => Kind::PartialFile,
sys::CURLE_SSL_CONNECT_ERROR => Kind::SslConnect,
sys::CURLE_TOO_MANY_REDIRECTS => Kind::TooManyRedirects,
sys::CURLE_INTERFACE_FAILED => Kind::InterfaceFailure,
sys::CURLE_GOT_NOTHING => Kind::NothingFromServer,
sys::CURLE_SEND_ERROR => Kind::SendError,
sys::CURLE_RECV_ERROR => Kind::RecvError,
sys::CURLE_SSL_CERTPROBLEM => Kind::SslLocalCertificate,
sys::CURLE_SSL_CIPHER => Kind::SslCipher,
sys::CURLE_SSL_CACERT => Kind::SslCertificate,
sys::CURLE_SSL_SHUTDOWN_FAILED => Kind::SslShutdownFailed,
sys::CURLE_OPERATION_TIMEDOUT => Kind::Timeout,
a => Kind::Curl(format!("curl error {}", a)),
}
}