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