1use std::fmt;
2use std::io;
3
4#[derive(Debug)]
9#[non_exhaustive]
10#[expect(missing_docs, reason = "too cluttered")]
11pub enum Error {
12 Hyper(hyper::Error),
13 Connect(io::Error),
14 Tls(io::Error),
15 #[cfg(feature = "default-send-request")]
16 InvalidDnsNameError(rustls::pki_types::InvalidDnsNameError),
17 HttpRequestBodySize(Option<u64>),
18
19 DnsTimeout,
20 DnsError {
21 rcode: Option<String>,
22 info_code: Option<u16>,
23 },
24 DestinationNotFound,
25 DestinationUnavailable,
26 DestinationIpProhibited,
27 DestinationIpUnroutable,
28 ConnectionRefused,
29 ConnectionTerminated,
30 ConnectionTimeout,
31 ConnectionReadTimeout,
32 ConnectionWriteTimeout,
33 ConnectionLimitReached,
34 TlsProtocolError,
35 TlsCertificateError,
36 TlsAlertReceived {
37 alert_id: Option<u8>,
38 alert_message: Option<String>,
39 },
40 HttpRequestDenied,
41 HttpRequestLengthRequired,
42 HttpRequestMethodInvalid,
43 HttpRequestUriInvalid,
44 HttpRequestUriTooLong,
45 HttpRequestHeaderSectionSize(Option<u32>),
46 HttpRequestHeaderSize {
47 field_name: Option<String>,
48 field_size: Option<u32>,
49 },
50 HttpRequestTrailerSectionSize(Option<u32>),
51 HttpRequestTrailerSize {
52 field_name: Option<String>,
53 field_size: Option<u32>,
54 },
55 HttpResponseIncomplete,
56 HttpResponseHeaderSectionSize(Option<u32>),
57 HttpResponseHeaderSize {
58 field_name: Option<String>,
59 field_size: Option<u32>,
60 },
61 HttpResponseBodySize(Option<u64>),
62 HttpResponseTrailerSectionSize(Option<u32>),
63 HttpResponseTrailerSize {
64 field_name: Option<String>,
65 field_size: Option<u32>,
66 },
67 HttpResponseTransferCoding(Option<String>),
68 HttpResponseContentCoding(Option<String>),
69 HttpResponseTimeout,
70 HttpUpgradeFailed,
71 HttpProtocolError,
72 LoopDetected,
73 ConfigurationError,
74 InternalError(Option<String>),
75}
76
77pub type Result<T, E = Error> = std::result::Result<T, E>;
79
80impl From<hyper::Error> for Error {
81 fn from(err: hyper::Error) -> Self {
82 Self::Hyper(err)
83 }
84}
85
86impl From<std::convert::Infallible> for Error {
87 fn from(e: std::convert::Infallible) -> Self {
88 match e {}
89 }
90}
91
92#[cfg(feature = "default-send-request")]
93impl From<rustls::pki_types::InvalidDnsNameError> for Error {
94 fn from(err: rustls::pki_types::InvalidDnsNameError) -> Self {
95 Self::InvalidDnsNameError(err)
96 }
97}
98
99impl fmt::Display for Error {
100 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
101 match self {
102 Self::Hyper(err) => write!(f, "hyper error: {err}"),
103 Self::Connect(err) => write!(f, "connection error: {err}"),
104 Self::Tls(err) => write!(f, "TLS error: {err}"),
105 #[cfg(feature = "default-send-request")]
106 Self::InvalidDnsNameError(err) => write!(f, "invalid DNS name: {err}"),
107 Self::HttpRequestBodySize(None) => {
108 write!(f, "HTTP request body size exceeds limit")
109 }
110 Self::HttpRequestBodySize(Some(size)) => {
111 write!(f, "HTTP request body size exceeds limit: {size} bytes")
112 }
113 Self::DnsTimeout => write!(f, "DNS lookup timed out"),
114 Self::DnsError { rcode, info_code } => {
115 write!(f, "DNS error")?;
116 if let Some(rcode) = rcode {
117 write!(f, ": rcode {rcode}")?;
118 }
119 if let Some(info_code) = info_code {
120 write!(f, " (info code {info_code})")?;
121 }
122 Ok(())
123 }
124 Self::DestinationNotFound => write!(f, "destination not found"),
125 Self::DestinationUnavailable => write!(f, "destination unavailable"),
126 Self::DestinationIpProhibited => write!(f, "destination IP address is prohibited"),
127 Self::DestinationIpUnroutable => write!(f, "destination IP address is unroutable"),
128 Self::ConnectionRefused => write!(f, "connection refused"),
129 Self::ConnectionTerminated => write!(f, "connection terminated"),
130 Self::ConnectionTimeout => write!(f, "connection timeout"),
131 Self::ConnectionReadTimeout => write!(f, "connection read timeout"),
132 Self::ConnectionWriteTimeout => write!(f, "connection write timeout"),
133 Self::ConnectionLimitReached => write!(f, "connection limit reached"),
134 Self::TlsProtocolError => write!(f, "TLS protocol error"),
135 Self::TlsCertificateError => write!(f, "TLS certificate error"),
136 Self::TlsAlertReceived {
137 alert_id,
138 alert_message,
139 } => {
140 write!(f, "TLS alert received")?;
141 if let Some(id) = alert_id {
142 write!(f, ": alert id {id}")?;
143 }
144 if let Some(msg) = alert_message {
145 write!(f, ": {msg}")?;
146 }
147 Ok(())
148 }
149 Self::HttpRequestDenied => write!(f, "HTTP request denied"),
150 Self::HttpRequestLengthRequired => write!(f, "HTTP request length required"),
151 Self::HttpRequestMethodInvalid => write!(f, "invalid HTTP request method"),
152 Self::HttpRequestUriInvalid => write!(f, "invalid HTTP request URI"),
153 Self::HttpRequestUriTooLong => write!(f, "HTTP request URI too long"),
154 Self::HttpRequestHeaderSectionSize(size) => {
155 write!(f, "HTTP request header section size exceeds limit")?;
156 if let Some(size) = size {
157 write!(f, ": {size} bytes")?;
158 }
159 Ok(())
160 }
161 Self::HttpRequestHeaderSize {
162 field_name,
163 field_size,
164 } => {
165 write!(f, "HTTP request header size exceeds limit")?;
166 if let Some(name) = field_name {
167 write!(f, ": field {name:?}")?;
168 }
169 if let Some(size) = field_size {
170 write!(f, " ({size} bytes)")?;
171 }
172 Ok(())
173 }
174 Self::HttpRequestTrailerSectionSize(size) => {
175 write!(f, "HTTP request trailer section size exceeds limit")?;
176 if let Some(size) = size {
177 write!(f, ": {size} bytes")?;
178 }
179 Ok(())
180 }
181 Self::HttpRequestTrailerSize {
182 field_name,
183 field_size,
184 } => {
185 write!(f, "HTTP request trailer size exceeds limit")?;
186 if let Some(name) = field_name {
187 write!(f, ": field {name:?}")?;
188 }
189 if let Some(size) = field_size {
190 write!(f, " ({size} bytes)")?;
191 }
192 Ok(())
193 }
194 Self::HttpResponseIncomplete => write!(f, "incomplete HTTP response"),
195 Self::HttpResponseHeaderSectionSize(size) => {
196 write!(f, "HTTP response header section size exceeds limit")?;
197 if let Some(size) = size {
198 write!(f, ": {size} bytes")?;
199 }
200 Ok(())
201 }
202 Self::HttpResponseHeaderSize {
203 field_name,
204 field_size,
205 } => {
206 write!(f, "HTTP response header size exceeds limit")?;
207 if let Some(name) = field_name {
208 write!(f, ": field {name:?}")?;
209 }
210 if let Some(size) = field_size {
211 write!(f, " ({size} bytes)")?;
212 }
213 Ok(())
214 }
215 Self::HttpResponseBodySize(size) => {
216 write!(f, "HTTP response body size exceeds limit")?;
217 if let Some(size) = size {
218 write!(f, ": {size} bytes")?;
219 }
220 Ok(())
221 }
222 Self::HttpResponseTrailerSectionSize(size) => {
223 write!(f, "HTTP response trailer section size exceeds limit")?;
224 if let Some(size) = size {
225 write!(f, ": {size} bytes")?;
226 }
227 Ok(())
228 }
229 Self::HttpResponseTrailerSize {
230 field_name,
231 field_size,
232 } => {
233 write!(f, "HTTP response trailer size exceeds limit")?;
234 if let Some(name) = field_name {
235 write!(f, ": field {name:?}")?;
236 }
237 if let Some(size) = field_size {
238 write!(f, " ({size} bytes)")?;
239 }
240 Ok(())
241 }
242 Self::HttpResponseTransferCoding(coding) => {
243 write!(f, "unsupported HTTP response transfer coding")?;
244 if let Some(coding) = coding {
245 write!(f, ": {coding:?}")?;
246 }
247 Ok(())
248 }
249 Self::HttpResponseContentCoding(coding) => {
250 write!(f, "unsupported HTTP response content coding")?;
251 if let Some(coding) = coding {
252 write!(f, ": {coding:?}")?;
253 }
254 Ok(())
255 }
256 Self::HttpResponseTimeout => write!(f, "HTTP response timeout"),
257 Self::HttpUpgradeFailed => write!(f, "HTTP upgrade failed"),
258 Self::HttpProtocolError => write!(f, "HTTP protocol error"),
259 Self::LoopDetected => write!(f, "request loop detected"),
260 Self::ConfigurationError => write!(f, "configuration error"),
261 Self::InternalError(None) => write!(f, "internal error"),
262 Self::InternalError(Some(msg)) => write!(f, "internal error: {msg}"),
263 }
264 }
265}
266
267impl std::error::Error for Error {}