Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/crates/wasi-http/src/http_impl.rs
1692 views
1
//! Implementation of the `wasi:http/outgoing-handler` interface.
2
3
use 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
};
13
use bytes::Bytes;
14
use http_body_util::{BodyExt, Empty};
15
use hyper::Method;
16
use wasmtime::component::Resource;
17
18
impl<T> outgoing_handler::Host for WasiHttpImpl<T>
19
where
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
// We can only support http/https
65
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
}
109
110