wasmtime_wasi_http/p2/
http_impl.rs1use crate::WasiHttpCtxView;
4use crate::p2::{
5 HttpResult,
6 bindings::http::{
7 outgoing_handler,
8 types::{self, Scheme},
9 },
10 error::internal_error,
11 http_request_error,
12 types::{HostFutureIncomingResponse, HostOutgoingRequest},
13};
14use bytes::Bytes;
15use http_body_util::{BodyExt, Empty};
16use hyper::Method;
17use std::pin::Pin;
18use wasmtime::component::Resource;
19
20impl outgoing_handler::Host for WasiHttpCtxView<'_> {
21 fn handle(
22 &mut self,
23 request_id: Resource<HostOutgoingRequest>,
24 options: Option<Resource<types::RequestOptions>>,
25 ) -> HttpResult<Resource<HostFutureIncomingResponse>> {
26 let opts = options.and_then(|opts| self.table.get(&opts).ok()).cloned();
27
28 let req = self.table.delete(request_id)?;
29 let mut builder = hyper::Request::builder();
30
31 builder = builder.method(match req.method {
32 types::Method::Get => Method::GET,
33 types::Method::Head => Method::HEAD,
34 types::Method::Post => Method::POST,
35 types::Method::Put => Method::PUT,
36 types::Method::Delete => Method::DELETE,
37 types::Method::Connect => Method::CONNECT,
38 types::Method::Options => Method::OPTIONS,
39 types::Method::Trace => Method::TRACE,
40 types::Method::Patch => Method::PATCH,
41 types::Method::Other(m) => match hyper::Method::from_bytes(m.as_bytes()) {
42 Ok(method) => method,
43 Err(_) => return Err(types::ErrorCode::HttpRequestMethodInvalid.into()),
44 },
45 });
46
47 let scheme = match req.scheme.unwrap_or(Scheme::Https) {
48 Scheme::Http => http::uri::Scheme::HTTP,
49 Scheme::Https => http::uri::Scheme::HTTPS,
50
51 Scheme::Other(_) => return Err(types::ErrorCode::HttpProtocolError.into()),
53 };
54
55 let authority = req.authority.unwrap_or_else(String::new);
56
57 let mut uri = http::Uri::builder()
58 .scheme(scheme)
59 .authority(authority.clone());
60
61 if let Some(path) = req.path_with_query {
62 uri = uri.path_and_query(path);
63 }
64
65 builder = builder.uri(uri.build().map_err(http_request_error)?);
66
67 for (k, v) in req.headers.iter() {
68 builder = builder.header(k, v);
69 }
70
71 let body = req.body.unwrap_or_else(|| {
72 Empty::<Bytes>::new()
73 .map_err(|_| unreachable!("Infallible error"))
74 .boxed_unsync()
75 });
76 let body = body.map_err(Into::into).boxed_unsync();
77
78 let request = builder
79 .body(body)
80 .map_err(|err| internal_error(err.to_string()))?;
81
82 let future = self
83 .hooks
84 .send_request(request, opts, Box::new(async { Ok(()) }));
85 let future = wasmtime_wasi::runtime::spawn(async move {
86 let (res, io) = Pin::from(future).await?;
87 let io = wasmtime_wasi::runtime::spawn(async move {
88 match Pin::from(io).await {
89 Ok(()) => {}
90 Err(e) => tracing::warn!("dropping error {e}"),
93 }
94 });
95 let res = res.map(|b| b.boxed_unsync());
96 Ok((res, io))
97 });
98
99 Ok(self
100 .table
101 .push(HostFutureIncomingResponse::Pending(future))?)
102 }
103}