1use crate::p3::bindings::http::types::{self, ErrorCode, Method, Scheme};
2use crate::{Error, WasiHttpCtxView};
3use core::convert::Infallible;
4use core::error::Error as _;
5use std::io::ErrorKind;
6
7impl From<Infallible> for ErrorCode {
8 fn from(x: Infallible) -> Self {
9 match x {}
10 }
11}
12
13impl From<ErrorCode> for Error {
14 fn from(e: ErrorCode) -> Self {
15 match e {
16 ErrorCode::DnsTimeout => Self::DnsTimeout,
17 ErrorCode::DnsError(payload) => Self::DnsError {
18 rcode: payload.rcode,
19 info_code: payload.info_code,
20 },
21 ErrorCode::DestinationNotFound => Self::DestinationNotFound,
22 ErrorCode::DestinationUnavailable => Self::DestinationUnavailable,
23 ErrorCode::DestinationIpProhibited => Self::DestinationIpProhibited,
24 ErrorCode::DestinationIpUnroutable => Self::DestinationIpUnroutable,
25 ErrorCode::ConnectionRefused => Self::ConnectionRefused,
26 ErrorCode::ConnectionTerminated => Self::ConnectionTerminated,
27 ErrorCode::ConnectionTimeout => Self::ConnectionTimeout,
28 ErrorCode::ConnectionReadTimeout => Self::ConnectionReadTimeout,
29 ErrorCode::ConnectionWriteTimeout => Self::ConnectionWriteTimeout,
30 ErrorCode::ConnectionLimitReached => Self::ConnectionLimitReached,
31 ErrorCode::TlsProtocolError => Self::TlsProtocolError,
32 ErrorCode::TlsCertificateError => Self::TlsCertificateError,
33 ErrorCode::TlsAlertReceived(payload) => Self::TlsAlertReceived {
34 alert_id: payload.alert_id,
35 alert_message: payload.alert_message,
36 },
37 ErrorCode::HttpRequestDenied => Self::HttpRequestDenied,
38 ErrorCode::HttpRequestLengthRequired => Self::HttpRequestLengthRequired,
39 ErrorCode::HttpRequestBodySize(payload) => Self::HttpRequestBodySize(payload),
40 ErrorCode::HttpRequestMethodInvalid => Self::HttpRequestMethodInvalid,
41 ErrorCode::HttpRequestUriInvalid => Self::HttpRequestUriInvalid,
42 ErrorCode::HttpRequestUriTooLong => Self::HttpRequestUriTooLong,
43 ErrorCode::HttpRequestHeaderSectionSize(payload) => {
44 Self::HttpRequestHeaderSectionSize(payload)
45 }
46 ErrorCode::HttpRequestHeaderSize(payload) => {
47 let (field_name, field_size) = match payload {
48 Some(p) => (p.field_name, p.field_size),
49 None => (None, None),
50 };
51 Self::HttpRequestHeaderSize {
52 field_name,
53 field_size,
54 }
55 }
56 ErrorCode::HttpRequestTrailerSectionSize(payload) => {
57 Self::HttpRequestTrailerSectionSize(payload)
58 }
59 ErrorCode::HttpRequestTrailerSize(payload) => Self::HttpRequestTrailerSize {
60 field_name: payload.field_name,
61 field_size: payload.field_size,
62 },
63 ErrorCode::HttpResponseIncomplete => Self::HttpResponseIncomplete,
64 ErrorCode::HttpResponseHeaderSectionSize(payload) => {
65 Self::HttpResponseHeaderSectionSize(payload)
66 }
67 ErrorCode::HttpResponseHeaderSize(payload) => Self::HttpRequestHeaderSize {
68 field_name: payload.field_name,
69 field_size: payload.field_size,
70 },
71 ErrorCode::HttpResponseBodySize(payload) => Self::HttpResponseBodySize(payload),
72 ErrorCode::HttpResponseTrailerSectionSize(payload) => {
73 Self::HttpResponseTrailerSectionSize(payload)
74 }
75 ErrorCode::HttpResponseTrailerSize(payload) => Self::HttpResponseTrailerSize {
76 field_name: payload.field_name,
77 field_size: payload.field_size,
78 },
79 ErrorCode::HttpResponseTransferCoding(payload) => {
80 Self::HttpResponseTransferCoding(payload)
81 }
82 ErrorCode::HttpResponseContentCoding(payload) => {
83 Self::HttpResponseContentCoding(payload)
84 }
85 ErrorCode::HttpResponseTimeout => Self::HttpResponseTimeout,
86 ErrorCode::HttpUpgradeFailed => Self::HttpUpgradeFailed,
87 ErrorCode::HttpProtocolError => Self::HttpProtocolError,
88 ErrorCode::LoopDetected => Self::LoopDetected,
89 ErrorCode::ConfigurationError => Self::ConfigurationError,
90 ErrorCode::InternalError(payload) => Self::InternalError(payload),
91 }
92 }
93}
94
95impl WasiHttpCtxView<'_> {
96 pub(crate) fn error_to_p3(&mut self, e: &Error) -> ErrorCode {
97 match e {
98 Error::Hyper(err) => {
99 if let Some(cause) = err.source() {
102 if let Some(err) = cause.downcast_ref::<ErrorCode>() {
103 return err.clone();
104 }
105 if let Some(err) = cause.downcast_ref::<Error>() {
106 return self.error_to_p3(err);
107 }
108 }
109
110 self.hooks.p3_error_from_hyper(err)
111 }
112 Error::Connect(err) => {
113 if err.kind() == ErrorKind::AddrNotAvailable {
114 return ErrorCode::DnsError(types::DnsErrorPayload {
115 rcode: Some("address not available".to_string()),
116 info_code: None,
117 });
118 }
119
120 if err
121 .to_string()
122 .starts_with("failed to lookup address information")
123 {
124 return ErrorCode::DnsError(types::DnsErrorPayload {
125 rcode: Some("address not available".to_string()),
126 info_code: None,
127 });
128 }
129
130 self.hooks.p3_error_from_connect(err)
131 }
132 Error::Tls(err) => self.hooks.p3_error_from_tls(err),
133 #[cfg(feature = "default-send-request")]
134 Error::InvalidDnsNameError(err) => self.hooks.p3_error_from_dns(err),
135 Error::DnsTimeout => ErrorCode::DnsTimeout,
136 Error::DnsError { rcode, info_code } => ErrorCode::DnsError(types::DnsErrorPayload {
137 rcode: rcode.clone(),
138 info_code: *info_code,
139 }),
140 Error::DestinationNotFound => ErrorCode::DestinationNotFound,
141 Error::DestinationUnavailable => ErrorCode::DestinationUnavailable,
142 Error::DestinationIpProhibited => ErrorCode::DestinationIpProhibited,
143 Error::DestinationIpUnroutable => ErrorCode::DestinationIpUnroutable,
144 Error::ConnectionRefused => ErrorCode::ConnectionRefused,
145 Error::ConnectionTerminated => ErrorCode::ConnectionTerminated,
146 Error::ConnectionTimeout => ErrorCode::ConnectionTimeout,
147 Error::ConnectionReadTimeout => ErrorCode::ConnectionReadTimeout,
148 Error::ConnectionWriteTimeout => ErrorCode::ConnectionWriteTimeout,
149 Error::ConnectionLimitReached => ErrorCode::ConnectionLimitReached,
150 Error::TlsProtocolError => ErrorCode::TlsProtocolError,
151 Error::TlsCertificateError => ErrorCode::TlsCertificateError,
152 Error::TlsAlertReceived {
153 alert_id,
154 alert_message,
155 } => ErrorCode::TlsAlertReceived(types::TlsAlertReceivedPayload {
156 alert_id: *alert_id,
157 alert_message: alert_message.clone(),
158 }),
159 Error::HttpRequestDenied => ErrorCode::HttpRequestDenied,
160 Error::HttpRequestLengthRequired => ErrorCode::HttpRequestLengthRequired,
161 Error::HttpRequestBodySize(payload) => ErrorCode::HttpRequestBodySize(*payload),
162 Error::HttpRequestMethodInvalid => ErrorCode::HttpRequestMethodInvalid,
163 Error::HttpRequestUriInvalid => ErrorCode::HttpRequestUriInvalid,
164 Error::HttpRequestUriTooLong => ErrorCode::HttpRequestUriTooLong,
165 Error::HttpRequestHeaderSectionSize(payload) => {
166 ErrorCode::HttpRequestHeaderSectionSize(*payload)
167 }
168 Error::HttpRequestHeaderSize {
169 field_name,
170 field_size,
171 } => ErrorCode::HttpRequestHeaderSize(Some(types::FieldSizePayload {
172 field_name: field_name.clone(),
173 field_size: *field_size,
174 })),
175 Error::HttpRequestTrailerSectionSize(payload) => {
176 ErrorCode::HttpRequestTrailerSectionSize(*payload)
177 }
178 Error::HttpRequestTrailerSize {
179 field_name,
180 field_size,
181 } => ErrorCode::HttpRequestTrailerSize(types::FieldSizePayload {
182 field_name: field_name.clone(),
183 field_size: *field_size,
184 }),
185 Error::HttpResponseIncomplete => ErrorCode::HttpResponseIncomplete,
186 Error::HttpResponseHeaderSectionSize(payload) => {
187 ErrorCode::HttpResponseHeaderSectionSize(*payload)
188 }
189 Error::HttpResponseHeaderSize {
190 field_name,
191 field_size,
192 } => ErrorCode::HttpResponseHeaderSize(types::FieldSizePayload {
193 field_name: field_name.clone(),
194 field_size: *field_size,
195 }),
196 Error::HttpResponseBodySize(payload) => ErrorCode::HttpResponseBodySize(*payload),
197 Error::HttpResponseTrailerSectionSize(payload) => {
198 ErrorCode::HttpResponseTrailerSectionSize(*payload)
199 }
200 Error::HttpResponseTrailerSize {
201 field_name,
202 field_size,
203 } => ErrorCode::HttpResponseTrailerSize(types::FieldSizePayload {
204 field_name: field_name.clone(),
205 field_size: *field_size,
206 }),
207 Error::HttpResponseTransferCoding(payload) => {
208 ErrorCode::HttpResponseTransferCoding(payload.clone())
209 }
210 Error::HttpResponseContentCoding(payload) => {
211 ErrorCode::HttpResponseContentCoding(payload.clone())
212 }
213 Error::HttpResponseTimeout => ErrorCode::HttpResponseTimeout,
214 Error::HttpUpgradeFailed => ErrorCode::HttpUpgradeFailed,
215 Error::HttpProtocolError => ErrorCode::HttpProtocolError,
216 Error::LoopDetected => ErrorCode::LoopDetected,
217 Error::ConfigurationError => ErrorCode::ConfigurationError,
218 Error::InternalError(payload) => ErrorCode::InternalError(payload.clone()),
219 }
220 }
221}
222
223impl From<http::Method> for Method {
224 fn from(method: http::Method) -> Self {
225 Self::from(&method)
226 }
227}
228
229impl From<&http::Method> for Method {
230 fn from(method: &http::Method) -> Self {
231 if method == http::Method::GET {
232 Self::Get
233 } else if method == http::Method::HEAD {
234 Self::Head
235 } else if method == http::Method::POST {
236 Self::Post
237 } else if method == http::Method::PUT {
238 Self::Put
239 } else if method == http::Method::DELETE {
240 Self::Delete
241 } else if method == http::Method::CONNECT {
242 Self::Connect
243 } else if method == http::Method::OPTIONS {
244 Self::Options
245 } else if method == http::Method::TRACE {
246 Self::Trace
247 } else if method == http::Method::PATCH {
248 Self::Patch
249 } else {
250 Self::Other(method.as_str().into())
251 }
252 }
253}
254
255impl TryFrom<Method> for http::Method {
256 type Error = http::method::InvalidMethod;
257
258 fn try_from(method: Method) -> Result<Self, Self::Error> {
259 Self::try_from(&method)
260 }
261}
262
263impl TryFrom<&Method> for http::Method {
264 type Error = http::method::InvalidMethod;
265
266 fn try_from(method: &Method) -> Result<Self, Self::Error> {
267 match method {
268 Method::Get => Ok(Self::GET),
269 Method::Head => Ok(Self::HEAD),
270 Method::Post => Ok(Self::POST),
271 Method::Put => Ok(Self::PUT),
272 Method::Delete => Ok(Self::DELETE),
273 Method::Connect => Ok(Self::CONNECT),
274 Method::Options => Ok(Self::OPTIONS),
275 Method::Trace => Ok(Self::TRACE),
276 Method::Patch => Ok(Self::PATCH),
277 Method::Other(s) => s.parse(),
278 }
279 }
280}
281
282impl From<http::uri::Scheme> for Scheme {
283 fn from(scheme: http::uri::Scheme) -> Self {
284 Self::from(&scheme)
285 }
286}
287
288impl From<&http::uri::Scheme> for Scheme {
289 fn from(scheme: &http::uri::Scheme) -> Self {
290 if *scheme == http::uri::Scheme::HTTP {
291 Self::Http
292 } else if *scheme == http::uri::Scheme::HTTPS {
293 Self::Https
294 } else {
295 Self::Other(scheme.as_str().into())
296 }
297 }
298}
299
300impl TryFrom<Scheme> for http::uri::Scheme {
301 type Error = http::uri::InvalidUri;
302
303 fn try_from(scheme: Scheme) -> Result<Self, Self::Error> {
304 Self::try_from(&scheme)
305 }
306}
307
308impl TryFrom<&Scheme> for http::uri::Scheme {
309 type Error = http::uri::InvalidUri;
310
311 fn try_from(scheme: &Scheme) -> Result<Self, Self::Error> {
312 match scheme {
313 Scheme::Http => Ok(Self::HTTP),
314 Scheme::Https => Ok(Self::HTTPS),
315 Scheme::Other(s) => s.parse(),
316 }
317 }
318}