wasmtime_wasi_http/p2/
types.rs1use crate::p2::{
5 bindings::http::types::{self, Method, Scheme},
6 body::{HostIncomingBody, HyperIncomingBody, HyperOutgoingBody},
7};
8use crate::{Error, FieldMap, WasiHttpCtxView};
9use bytes::Bytes;
10use http_body_util::BodyExt;
11use hyper::body::Body;
12use wasmtime::component::Resource;
13use wasmtime::{Result, bail};
14use wasmtime_wasi::p2::Pollable;
15use wasmtime_wasi::runtime::AbortOnDropJoinHandle;
16
17impl From<http::Method> for types::Method {
18 fn from(method: http::Method) -> Self {
19 if method == http::Method::GET {
20 types::Method::Get
21 } else if method == hyper::Method::HEAD {
22 types::Method::Head
23 } else if method == hyper::Method::POST {
24 types::Method::Post
25 } else if method == hyper::Method::PUT {
26 types::Method::Put
27 } else if method == hyper::Method::DELETE {
28 types::Method::Delete
29 } else if method == hyper::Method::CONNECT {
30 types::Method::Connect
31 } else if method == hyper::Method::OPTIONS {
32 types::Method::Options
33 } else if method == hyper::Method::TRACE {
34 types::Method::Trace
35 } else if method == hyper::Method::PATCH {
36 types::Method::Patch
37 } else {
38 types::Method::Other(method.to_string())
39 }
40 }
41}
42
43impl TryInto<http::Method> for types::Method {
44 type Error = http::method::InvalidMethod;
45
46 fn try_into(self) -> Result<http::Method, Self::Error> {
47 match self {
48 Method::Get => Ok(http::Method::GET),
49 Method::Head => Ok(http::Method::HEAD),
50 Method::Post => Ok(http::Method::POST),
51 Method::Put => Ok(http::Method::PUT),
52 Method::Delete => Ok(http::Method::DELETE),
53 Method::Connect => Ok(http::Method::CONNECT),
54 Method::Options => Ok(http::Method::OPTIONS),
55 Method::Trace => Ok(http::Method::TRACE),
56 Method::Patch => Ok(http::Method::PATCH),
57 Method::Other(s) => http::Method::from_bytes(s.as_bytes()),
58 }
59 }
60}
61
62#[derive(Debug)]
64pub struct HostIncomingRequest {
65 pub(crate) method: http::method::Method,
66 pub(crate) uri: http::uri::Uri,
67 pub(crate) headers: FieldMap,
68 pub(crate) scheme: Scheme,
69 pub(crate) authority: String,
70 pub body: Option<HostIncomingBody>,
72}
73
74impl WasiHttpCtxView<'_> {
75 pub fn new_incoming_request<B>(
77 &mut self,
78 scheme: Scheme,
79 req: hyper::Request<B>,
80 ) -> wasmtime::Result<Resource<HostIncomingRequest>>
81 where
82 B: Body<Data = Bytes> + Send + 'static,
83 B::Error: Into<Error>,
84 {
85 let (parts, body) = req.into_parts();
86 let body = body.map_err(Into::into).boxed_unsync();
87 let body = HostIncomingBody::new(body);
88 let authority = match parts.uri.authority() {
89 Some(authority) => authority.to_string(),
90 None => match parts.headers.get(http::header::HOST) {
91 Some(host) => host.to_str()?.to_string(),
92 None => bail!("invalid HTTP request missing authority in URI and host header"),
93 },
94 };
95
96 let headers = FieldMap::new_immutable(self.hooks, parts.headers);
97
98 let req = HostIncomingRequest {
99 method: parts.method,
100 uri: parts.uri,
101 headers,
102 authority,
103 scheme,
104 body: Some(body),
105 };
106 Ok(self.table.push(req)?)
107 }
108}
109
110pub struct HostResponseOutparam {
112 pub send:
114 Box<dyn FnOnce(Result<hyper::Response<HyperOutgoingBody>, types::ErrorCode>) + Send + Sync>,
115}
116
117impl WasiHttpCtxView<'_> {
118 pub fn new_response_outparam(
120 &mut self,
121 result: tokio::sync::oneshot::Sender<
122 Result<hyper::Response<HyperOutgoingBody>, types::ErrorCode>,
123 >,
124 ) -> wasmtime::Result<Resource<HostResponseOutparam>> {
125 let id = self.table.push(HostResponseOutparam {
126 send: Box::new(move |value| {
127 _ = result.send(value)
132 }),
133 })?;
134 Ok(id)
135 }
136
137 pub fn new_response_outparam_from_callback(
139 &mut self,
140 callback: impl FnOnce(Result<hyper::Response<HyperOutgoingBody>, types::ErrorCode>)
141 + Send
142 + Sync
143 + 'static,
144 ) -> wasmtime::Result<Resource<HostResponseOutparam>> {
145 let id = self.table.push(HostResponseOutparam {
146 send: Box::new(callback),
147 })?;
148 Ok(id)
149 }
150}
151
152pub struct HostOutgoingResponse {
154 pub status: http::StatusCode,
156 pub headers: FieldMap,
158 pub body: Option<HyperOutgoingBody>,
160}
161
162impl TryFrom<HostOutgoingResponse> for hyper::Response<HyperOutgoingBody> {
163 type Error = http::Error;
164
165 fn try_from(
166 resp: HostOutgoingResponse,
167 ) -> Result<hyper::Response<HyperOutgoingBody>, Self::Error> {
168 use http_body_util::Empty;
169
170 let mut builder = hyper::Response::builder().status(resp.status);
171
172 *builder.headers_mut().unwrap() = resp.headers.into();
173
174 match resp.body {
175 Some(body) => builder.body(body),
176 None => builder.body(
177 Empty::<bytes::Bytes>::new()
178 .map_err(|_| unreachable!("Infallible error"))
179 .boxed_unsync(),
180 ),
181 }
182 }
183}
184
185#[derive(Debug)]
187pub struct HostOutgoingRequest {
188 pub method: Method,
190 pub scheme: Option<Scheme>,
192 pub authority: Option<String>,
194 pub path_with_query: Option<String>,
196 pub headers: FieldMap,
198 pub body: Option<HyperOutgoingBody>,
200}
201
202#[derive(Debug)]
204pub struct HostIncomingResponse {
205 pub status: u16,
207 pub headers: FieldMap,
209 pub body: Option<HostIncomingBody>,
211}
212
213pub type FutureIncomingResponseHandle = AbortOnDropJoinHandle<SendRequestResult>;
215
216#[derive(Debug)]
218pub struct IncomingResponse {
219 pub resp: hyper::Response<HyperIncomingBody>,
221 pub worker: Option<AbortOnDropJoinHandle<()>>,
223}
224
225type SendRequestResult =
226 crate::Result<(http::Response<HyperIncomingBody>, AbortOnDropJoinHandle<()>)>;
227
228pub enum HostFutureIncomingResponse {
230 Pending(FutureIncomingResponseHandle),
232 Ready(SendRequestResult),
236 Consumed,
238}
239
240impl HostFutureIncomingResponse {
241 pub(crate) fn unwrap_ready(self) -> SendRequestResult {
243 match self {
244 Self::Ready(res) => res,
245 Self::Pending(_) | Self::Consumed => {
246 panic!("unwrap_ready called on a pending HostFutureIncomingResponse")
247 }
248 }
249 }
250}
251
252#[async_trait::async_trait]
253impl Pollable for HostFutureIncomingResponse {
254 async fn ready(&mut self) {
255 if let Self::Pending(handle) = self {
256 *self = Self::Ready(handle.await);
257 }
258 }
259}