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