Skip to main content

wasmtime_wasi_http/p3/
conv.rs

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 there's a source, we might be able to extract a wasi-http
100                // error from it.
101                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}