tokio_gemini/
error.rs

1//! Library error structures and enums
2
3use tokio_rustls::rustls;
4
5#[cfg(feature = "hickory")]
6use hickory_client::{
7    error::ClientError as HickoryClientError, proto::error::ProtoError as HickoryProtoError,
8};
9
10/// Main error structure, also a wrapper for everything else
11#[derive(Debug)]
12pub enum LibError {
13    /// General I/O error
14    // TODO: separate somehow
15    IoError(std::io::Error),
16    /// URL parse or check error
17    InvalidUrlError(InvalidUrl),
18    /// DNS server has provided no suitable records
19    /// (e. g. domain does not exist)
20    HostLookupError,
21    /// TLS library error related to certificate/signature
22    /// verification failure or connection failure
23    RustlsError(rustls::Error),
24    /// Response status code is out of [10; 69] range
25    StatusOutOfRange(u8),
26    /// Response metadata or content cannot be parsed
27    /// as a UTF-8 string without errors
28    DataNotUtf8(std::string::FromUtf8Error),
29    /// Provided string is not a valid MIME type
30    InvalidMime(mime::FromStrError),
31    /// Hickory DNS client error
32    #[cfg(feature = "hickory")]
33    DnsClientError(HickoryClientError),
34}
35
36impl From<std::io::Error> for LibError {
37    #[inline]
38    fn from(err: std::io::Error) -> Self {
39        Self::IoError(err)
40    }
41}
42
43impl From<url::ParseError> for LibError {
44    #[inline]
45    fn from(err: url::ParseError) -> Self {
46        Self::InvalidUrlError(InvalidUrl::ParseError(err))
47    }
48}
49
50impl From<InvalidUrl> for LibError {
51    #[inline]
52    fn from(err: InvalidUrl) -> Self {
53        Self::InvalidUrlError(err)
54    }
55}
56
57impl From<rustls::Error> for LibError {
58    #[inline]
59    fn from(err: rustls::Error) -> Self {
60        Self::RustlsError(err)
61    }
62}
63
64impl From<rustls::CertificateError> for LibError {
65    #[inline]
66    fn from(err: rustls::CertificateError) -> Self {
67        Self::RustlsError(err.into())
68    }
69}
70
71impl LibError {
72    #[inline]
73    pub fn status_out_of_range(num: u8) -> Self {
74        Self::StatusOutOfRange(num)
75    }
76}
77
78impl From<std::string::FromUtf8Error> for LibError {
79    #[inline]
80    fn from(err: std::string::FromUtf8Error) -> Self {
81        Self::DataNotUtf8(err)
82    }
83}
84
85impl From<mime::FromStrError> for LibError {
86    #[inline]
87    fn from(err: mime::FromStrError) -> Self {
88        Self::InvalidMime(err)
89    }
90}
91
92#[cfg(feature = "hickory")]
93impl From<HickoryClientError> for LibError {
94    #[inline]
95    fn from(err: HickoryClientError) -> Self {
96        Self::DnsClientError(err)
97    }
98}
99
100#[cfg(feature = "hickory")]
101impl From<HickoryProtoError> for LibError {
102    #[inline]
103    fn from(err: HickoryProtoError) -> Self {
104        Self::DnsClientError(err.into())
105    }
106}
107
108/// URL parse or check error
109#[derive(Debug)]
110pub enum InvalidUrl {
111    /// Provided string cannot be parsed as a valid URL with [`url::Url`]
112    ParseError(url::ParseError),
113    /// URL scheme is not `gemini://`
114    SchemeNotGemini,
115    /// URL contains userinfo -- `user:pswd@` --
116    /// which is forbidden by Gemini spec
117    UserinfoPresent,
118    /// Could not extract host from the URL or convert host and port into
119    /// [`std::net::SocketAddr`] or [`crate::certs::ServerName`]
120    ConvertError,
121}