use derive_more::Display;
use hickory_resolver::{ResolveError, ResolveErrorKind};
use rustls_connector::HandshakeError;
use std::error::Error;
use std::io;
use std::net::TcpStream;
#[derive(Clone, Debug, Display)]
pub enum ResolveDnsError {
#[display("Can't find DNS entry for the given host.")]
NoResults,
#[display("Couldn't resolve DNS for given host because: {}", _0)]
Other(Box<ResolveError>),
}
impl Error for ResolveDnsError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
Self::Other(err) => Some(err),
Self::NoResults => None,
}
}
}
impl PartialEq for ResolveDnsError {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::NoResults, Self::NoResults) => true,
(Self::Other(e1), Self::Other(e2)) => match (e1.kind(), e2.kind()) {
(ResolveErrorKind::Msg(msg1), ResolveErrorKind::Msg(msg2)) => msg1.eq(msg2),
(ResolveErrorKind::Message(msg1), ResolveErrorKind::Message(msg2)) => msg1.eq(msg2),
(ResolveErrorKind::Proto(_e1), ResolveErrorKind::Proto(_e2)) => {
true
}
_ => false,
},
_ => false,
}
}
}
#[derive(Clone, Debug, Display, Ord, PartialOrd, Eq, PartialEq, Hash)]
pub enum InvalidUrlError {
#[display(
"No input was provided. Provide a URL, such as https://example.com or https://1.2.3.4:443"
)]
MissingInput,
#[display("The URL is illegal because: {}", _0)]
WrongFormat(String),
#[display("Wrong scheme '{}://': Only supports http and https.", _0)]
WrongScheme(String),
#[display("Other unknown error.")]
Other,
}
impl Error for InvalidUrlError {}
#[derive(Debug, Display)]
pub enum TtfbError {
#[display("Invalid URL: {}", _0)]
InvalidUrl(InvalidUrlError),
#[display("Can't resolve DNS because: {}", _0)]
CantResolveDns(ResolveDnsError),
#[display("Can't establish TCP-Connection because: {}", _0)]
CantConnectTcp(io::Error),
#[display("Can't establish TLS-Connection because: {}", _0)]
CantConnectTls(HandshakeError<TcpStream>),
#[display("Can't verify TLS-Connection because: {}", _0)]
CantVerifyTls(HandshakeError<TcpStream>),
#[display("Can't establish HTTP/1.1-Connection because: {}", _0)]
CantConnectHttp(io::Error),
#[display("Didn't receive any data. Is the host running a HTTP server?")]
NoHttpResponse,
#[display("There was a problem with the TCP stream because: {}", _0)]
OtherStreamError(io::Error),
#[display("Failed to configure DNS based on system or default settings: {_0}")]
CantConfigureDNSError(ResolveError),
}
impl Error for TtfbError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
TtfbError::InvalidUrl(err) => Some(err),
TtfbError::CantResolveDns(err) => Some(err),
TtfbError::CantConnectTls(err) => Some(err),
TtfbError::CantConnectTcp(err) => Some(err),
TtfbError::OtherStreamError(err) => Some(err),
TtfbError::CantConnectHttp(err) => Some(err),
TtfbError::NoHttpResponse => None,
TtfbError::CantConfigureDNSError(err) => Some(err),
TtfbError::CantVerifyTls(err) => Some(err),
}
}
}
impl PartialEq for TtfbError {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::InvalidUrl(e1), Self::InvalidUrl(e2)) => e1.eq(e2),
(Self::CantResolveDns(e1), Self::CantResolveDns(e2)) => e1.eq(e2),
(Self::CantConnectTcp(e1), Self::CantConnectTcp(e2)) => e1.kind().eq(&e2.kind()),
(Self::CantConnectTls(_e1), Self::CantConnectTls(_e2)) => {
true
}
(Self::CantVerifyTls(_e1), Self::CantVerifyTls(_e2)) => {
true
}
(Self::CantConnectHttp(e1), Self::OtherStreamError(e2)) => e1.kind().eq(&e2.kind()),
(Self::CantConfigureDNSError(_e1), Self::CantConfigureDNSError(_e2)) => {
true
}
(Self::NoHttpResponse, Self::NoHttpResponse) => true,
_ => false,
}
}
}