hickory_proto/http/
error.rs

1// Copyright 2015-2020 Benjamin Fry <benjaminfry@me.com>
2//
3// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
4// https://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5// https://opensource.org/licenses/MIT>, at your option. This file may not be
6// copied, modified, or distributed except according to those terms.
7
8use std::num::ParseIntError;
9use std::{fmt, io};
10
11use crate::error::ProtoError;
12use http::header::ToStrError;
13use thiserror::Error;
14
15#[cfg(feature = "backtrace")]
16use crate::{trace, ExtBacktrace};
17
18/// An alias for results returned by functions of this crate
19pub type Result<T> = ::std::result::Result<T, Error>;
20
21// TODO: remove this and put in ProtoError
22#[derive(Debug, Error)]
23#[non_exhaustive]
24pub enum ErrorKind {
25    /// Unable to decode header value to string
26    #[error("header decode error: {0}")]
27    Decode(#[from] ToStrError),
28
29    /// An error with an arbitrary message, referenced as &'static str
30    #[error("{0}")]
31    Message(&'static str),
32
33    /// An error with an arbitrary message, stored as String
34    #[error("{0}")]
35    Msg(String),
36
37    /// Unable to parse header value as number
38    #[error("unable to parse number: {0}")]
39    ParseInt(#[from] ParseIntError),
40
41    #[error("proto error: {0}")]
42    ProtoError(#[from] ProtoError),
43
44    #[error("h2: {0}")]
45    #[cfg(feature = "dns-over-https")]
46    H2(#[from] h2::Error),
47
48    #[error("h3: {0}")]
49    #[cfg(feature = "dns-over-h3")]
50    H3(#[from] h3::Error),
51}
52
53/// The error type for errors that get returned in the crate
54#[derive(Debug)]
55pub struct Error {
56    kind: ErrorKind,
57    #[cfg(feature = "backtrace")]
58    backtrack: Option<ExtBacktrace>,
59}
60
61impl Error {
62    /// Get the kind of the error
63    pub fn kind(&self) -> &ErrorKind {
64        &self.kind
65    }
66}
67
68impl fmt::Display for Error {
69    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
70        cfg_if::cfg_if! {
71            if #[cfg(feature = "backtrace")] {
72                if let Some(ref backtrace) = self.backtrack {
73                    fmt::Display::fmt(&self.kind, f)?;
74                    fmt::Debug::fmt(backtrace, f)
75                } else {
76                    fmt::Display::fmt(&self.kind, f)
77                }
78            } else {
79                fmt::Display::fmt(&self.kind, f)
80            }
81        }
82    }
83}
84
85impl From<ErrorKind> for Error {
86    fn from(kind: ErrorKind) -> Self {
87        Self {
88            kind,
89            #[cfg(feature = "backtrace")]
90            backtrack: trace!(),
91        }
92    }
93}
94
95impl From<&'static str> for Error {
96    fn from(msg: &'static str) -> Self {
97        ErrorKind::Message(msg).into()
98    }
99}
100
101impl From<String> for Error {
102    fn from(msg: String) -> Self {
103        ErrorKind::Msg(msg).into()
104    }
105}
106
107impl From<ParseIntError> for Error {
108    fn from(err: ParseIntError) -> Self {
109        ErrorKind::from(err).into()
110    }
111}
112
113impl From<ToStrError> for Error {
114    fn from(err: ToStrError) -> Self {
115        ErrorKind::from(err).into()
116    }
117}
118
119impl From<ProtoError> for Error {
120    fn from(msg: ProtoError) -> Self {
121        ErrorKind::ProtoError(msg).into()
122    }
123}
124
125#[cfg(feature = "dns-over-https")]
126impl From<h2::Error> for Error {
127    fn from(msg: h2::Error) -> Self {
128        ErrorKind::H2(msg).into()
129    }
130}
131
132#[cfg(feature = "dns-over-h3")]
133impl From<h3::Error> for Error {
134    fn from(msg: h3::Error) -> Self {
135        ErrorKind::H3(msg).into()
136    }
137}
138
139impl From<Error> for io::Error {
140    fn from(err: Error) -> Self {
141        Self::new(io::ErrorKind::Other, format!("https: {err}"))
142    }
143}