use super::response::{Metrics, ResponseInfo, ResponseParts};
use anyhow::Error as AnyError;
use http::uri::{Scheme, Uri};
use std::{
error::Error as StdError,
fmt::{self, Debug, Display},
net::IpAddr,
num::NonZeroU16,
};
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum ErrorKind {
ProtocolError,
InvalidRequestResponse,
InvalidUrl,
InvalidHeader,
ConnectError,
ProxyError,
DnsServerError,
UnknownHostError,
SendError,
ReceiveError,
LocalIoError,
TimeoutError,
ClientCertError,
ServerCertError,
SslError,
TooManyRedirect,
UnknownError,
CallbackError,
}
#[derive(Debug)]
pub struct Error {
kind: ErrorKind,
error: AnyError,
response_info: ResponseInfo,
}
impl Error {
#[inline]
pub fn builder(kind: ErrorKind, err: impl Into<AnyError>) -> ErrorBuilder {
ErrorBuilder::new(kind, err)
}
#[inline]
pub fn builder_with_msg(kind: ErrorKind, err: impl Display + Debug + Send + Sync + 'static) -> ErrorBuilder {
ErrorBuilder::new_with_msg(kind, err)
}
#[inline]
pub fn kind(&self) -> ErrorKind {
self.kind
}
#[inline]
pub fn into_inner(self) -> AnyError {
self.error
}
#[inline]
pub fn server_ip(&self) -> Option<IpAddr> {
self.response_info.server_ip()
}
#[inline]
pub fn server_port(&self) -> Option<NonZeroU16> {
self.response_info.server_port()
}
#[inline]
pub fn metrics(&self) -> Option<&Metrics> {
self.response_info.metrics()
}
#[inline]
pub fn server_ip_mut(&mut self) -> &mut Option<IpAddr> {
self.response_info.server_ip_mut()
}
#[inline]
pub fn server_port_mut(&mut self) -> &mut Option<NonZeroU16> {
self.response_info.server_port_mut()
}
#[inline]
pub fn metrics_mut(&mut self) -> &mut Option<Metrics> {
self.response_info.metrics_mut()
}
}
impl Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Display::fmt(&self.error, f)
}
}
impl StdError for Error {
#[inline]
fn source(&self) -> Option<&(dyn StdError + 'static)> {
Some(self.error.as_ref())
}
}
#[derive(Debug)]
pub struct ErrorBuilder {
inner: Error,
}
impl ErrorBuilder {
#[inline]
fn new(kind: ErrorKind, err: impl Into<AnyError>) -> Self {
Self {
inner: Error {
kind,
error: err.into(),
response_info: Default::default(),
},
}
}
#[inline]
fn new_with_msg(kind: ErrorKind, msg: impl Display + Debug + Send + Sync + 'static) -> Self {
Self {
inner: Error {
kind,
error: AnyError::msg(msg),
response_info: Default::default(),
},
}
}
#[inline]
pub fn build(self) -> Error {
self.inner
}
#[must_use]
pub fn uri(mut self, uri: &Uri) -> Self {
if let Some(host) = uri.host() {
if let Ok(ip_addr) = host.parse::<IpAddr>() {
*self.inner.server_ip_mut() = Some(ip_addr);
}
}
if let Some(port) = uri.port_u16() {
*self.inner.server_port_mut() = NonZeroU16::new(port);
} else if let Some(scheme) = uri.scheme() {
if scheme == &Scheme::HTTP {
*self.inner.server_port_mut() = NonZeroU16::new(80);
} else if scheme == &Scheme::HTTPS {
*self.inner.server_port_mut() = NonZeroU16::new(443);
}
}
self
}
#[inline]
#[must_use]
pub fn server_ip(mut self, server_ip: IpAddr) -> Self {
*self.inner.server_ip_mut() = Some(server_ip);
self
}
#[inline]
#[must_use]
pub fn server_port(mut self, server_port: NonZeroU16) -> Self {
*self.inner.server_port_mut() = Some(server_port);
self
}
#[inline]
#[must_use]
pub fn metrics(mut self, metrics: Metrics) -> Self {
*self.inner.metrics_mut() = Some(metrics);
self
}
}
#[derive(Debug)]
pub struct MapError<E> {
error: E,
parts: ResponseParts,
}
impl<E> MapError<E> {
pub(super) fn new(error: E, parts: ResponseParts) -> Self {
Self { error, parts }
}
#[inline]
pub fn into_inner(self) -> E {
self.error
}
}
impl<E: Into<AnyError>> MapError<E> {
pub fn into_response_error(self, kind: ErrorKind) -> Error {
Error {
kind,
error: self.error.into(),
response_info: self.parts.into_response_info(),
}
}
}