Skip to main content

wasmtime_wasi_http/p2/
error.rs

1use crate::FieldMapError;
2use crate::p2::bindings::http::types::{self, ErrorCode};
3use std::error::Error;
4use std::fmt;
5use wasmtime::component::ResourceTableError;
6
7/// A [`Result`] type where the error type defaults to [`HttpError`].
8pub type HttpResult<T, E = HttpError> = Result<T, E>;
9
10/// A `wasi:http`-specific error type used to represent either a trap or an
11/// [`ErrorCode`].
12///
13/// Modeled after [`TrappableError`](wasmtime_wasi::TrappableError).
14#[repr(transparent)]
15pub struct HttpError {
16    err: wasmtime::Error,
17}
18
19impl HttpError {
20    /// Create a new `HttpError` that represents a trap.
21    pub fn trap(err: impl Into<wasmtime::Error>) -> HttpError {
22        HttpError { err: err.into() }
23    }
24
25    /// Downcast this error to an [`ErrorCode`].
26    pub fn downcast(self) -> wasmtime::Result<ErrorCode> {
27        self.err.downcast()
28    }
29
30    /// Downcast this error to a reference to an [`ErrorCode`]
31    pub fn downcast_ref(&self) -> Option<&ErrorCode> {
32        self.err.downcast_ref()
33    }
34}
35
36impl From<ErrorCode> for HttpError {
37    fn from(error: ErrorCode) -> Self {
38        Self { err: error.into() }
39    }
40}
41
42impl From<ResourceTableError> for HttpError {
43    fn from(error: ResourceTableError) -> Self {
44        HttpError::trap(error)
45    }
46}
47
48impl fmt::Debug for HttpError {
49    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50        self.err.fmt(f)
51    }
52}
53
54impl fmt::Display for HttpError {
55    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
56        self.err.fmt(f)
57    }
58}
59
60impl Error for HttpError {}
61
62/// A [`Result`] type where the error type defaults to [`HeaderError`].
63pub type HeaderResult<T, E = HeaderError> = Result<T, E>;
64
65/// A `wasi:http`-specific error type used to represent either a trap or an
66/// [`types::HeaderError`].
67///
68/// Modeled after [`TrappableError`](wasmtime_wasi::TrappableError).
69#[repr(transparent)]
70pub struct HeaderError {
71    err: wasmtime::Error,
72}
73
74impl HeaderError {
75    /// Create a new `HeaderError` that represents a trap.
76    pub fn trap(err: impl Into<wasmtime::Error>) -> HeaderError {
77        HeaderError { err: err.into() }
78    }
79
80    /// Downcast this error to an [`ErrorCode`].
81    pub fn downcast(self) -> wasmtime::Result<types::HeaderError> {
82        self.err.downcast()
83    }
84
85    /// Downcast this error to a reference to an [`ErrorCode`]
86    pub fn downcast_ref(&self) -> Option<&types::HeaderError> {
87        self.err.downcast_ref()
88    }
89}
90
91impl From<types::HeaderError> for HeaderError {
92    fn from(error: types::HeaderError) -> Self {
93        Self { err: error.into() }
94    }
95}
96
97impl From<ResourceTableError> for HeaderError {
98    fn from(error: ResourceTableError) -> Self {
99        HeaderError::trap(error)
100    }
101}
102
103impl From<http::header::InvalidHeaderName> for HeaderError {
104    fn from(_: http::header::InvalidHeaderName) -> Self {
105        HeaderError::from(types::HeaderError::InvalidSyntax)
106    }
107}
108
109impl From<http::header::InvalidHeaderValue> for HeaderError {
110    fn from(_: http::header::InvalidHeaderValue) -> Self {
111        HeaderError::from(types::HeaderError::InvalidSyntax)
112    }
113}
114
115impl From<FieldMapError> for HeaderError {
116    fn from(err: FieldMapError) -> Self {
117        match err {
118            FieldMapError::Immutable => types::HeaderError::Immutable.into(),
119            FieldMapError::InvalidHeaderName => types::HeaderError::InvalidSyntax.into(),
120            FieldMapError::TooManyFields | FieldMapError::TotalSizeTooBig => HeaderError::trap(err),
121        }
122    }
123}
124
125impl fmt::Debug for HeaderError {
126    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
127        self.err.fmt(f)
128    }
129}
130
131impl fmt::Display for HeaderError {
132    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
133        self.err.fmt(f)
134    }
135}
136
137#[cfg(feature = "default-send-request")]
138pub(crate) fn dns_error(rcode: String, info_code: u16) -> ErrorCode {
139    ErrorCode::DnsError(crate::p2::bindings::http::types::DnsErrorPayload {
140        rcode: Some(rcode),
141        info_code: Some(info_code),
142    })
143}
144
145pub(crate) fn internal_error(msg: String) -> ErrorCode {
146    ErrorCode::InternalError(Some(msg))
147}
148
149/// Translate a [`http::Error`] to a wasi-http `ErrorCode` in the context of a request.
150pub fn http_request_error(err: http::Error) -> ErrorCode {
151    if err.is::<http::uri::InvalidUri>() {
152        return ErrorCode::HttpRequestUriInvalid;
153    }
154
155    tracing::warn!("http request error: {err:?}");
156
157    ErrorCode::HttpProtocolError
158}
159
160/// Translate a [`hyper::Error`] to a wasi-http `ErrorCode` in the context of a request.
161pub fn hyper_request_error(err: hyper::Error) -> ErrorCode {
162    // If there's a source, we might be able to extract a wasi-http error from it.
163    if let Some(cause) = err.source() {
164        if let Some(err) = cause.downcast_ref::<ErrorCode>() {
165            return err.clone();
166        }
167    }
168
169    tracing::warn!("hyper request error: {err:?}");
170
171    ErrorCode::HttpProtocolError
172}
173
174/// Translate a [`hyper::Error`] to a wasi-http `ErrorCode` in the context of a response.
175pub fn hyper_response_error(err: hyper::Error) -> ErrorCode {
176    if err.is_timeout() {
177        return ErrorCode::HttpResponseTimeout;
178    }
179
180    // If there's a source, we might be able to extract a wasi-http error from it.
181    if let Some(cause) = err.source() {
182        if let Some(err) = cause.downcast_ref::<ErrorCode>() {
183            return err.clone();
184        }
185    }
186
187    tracing::warn!("hyper response error: {err:?}");
188
189    ErrorCode::HttpProtocolError
190}
191
192impl From<hyper::Error> for ErrorCode {
193    fn from(err: hyper::Error) -> Self {
194        hyper_response_error(err)
195    }
196}