Skip to content

Commit

Permalink
Resourcify the wasi-http interface (bytecodealliance#7135)
Browse files Browse the repository at this point in the history
  • Loading branch information
elliottt authored and alexcrichton committed Oct 4, 2023
1 parent 56f9381 commit 3c3ea44
Show file tree
Hide file tree
Showing 8 changed files with 554 additions and 745 deletions.
13 changes: 6 additions & 7 deletions crates/test-programs/wasi-http-proxy-tests/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,17 @@ struct T;

impl bindings::exports::wasi::http::incoming_handler::Guest for T {
fn handle(_request: IncomingRequest, outparam: ResponseOutparam) {
let hdrs = bindings::wasi::http::types::new_fields(&[]);
let resp = bindings::wasi::http::types::new_outgoing_response(200, hdrs);
let body =
bindings::wasi::http::types::outgoing_response_write(resp).expect("outgoing response");
let hdrs = bindings::wasi::http::types::Headers::new(&[]);
let resp = bindings::wasi::http::types::OutgoingResponse::new(200, hdrs);
let body = resp.write().expect("outgoing response");

bindings::wasi::http::types::set_response_outparam(outparam, Ok(resp));
bindings::wasi::http::types::ResponseOutparam::set(outparam, Ok(resp));

let out = bindings::wasi::http::types::outgoing_body_write(body).expect("outgoing stream");
let out = body.write().expect("outgoing stream");
out.blocking_write_and_flush(b"hello, world!")
.expect("writing response");

drop(out);
bindings::wasi::http::types::outgoing_body_finish(body, None);
bindings::wasi::http::types::OutgoingBody::finish(body, None);
}
}
37 changes: 19 additions & 18 deletions crates/test-programs/wasi-http-tests/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ pub fn request(
fn header_val(v: &str) -> Vec<u8> {
v.to_string().into_bytes()
}
let headers = http_types::new_fields(
let headers = http_types::Headers::new(
&[
&[
("User-agent".to_string(), header_val("WASI-HTTP/0.0.1")),
Expand All @@ -62,19 +62,21 @@ pub fn request(
.concat(),
);

let request = http_types::new_outgoing_request(
let request = http_types::OutgoingRequest::new(
&method,
Some(path_with_query),
Some(&scheme),
Some(authority),
headers,
);

let outgoing_body = http_types::outgoing_request_write(request)
let outgoing_body = request
.write()
.map_err(|_| anyhow!("outgoing request write failed"))?;

if let Some(mut buf) = body {
let request_body = http_types::outgoing_body_write(outgoing_body)
let request_body = outgoing_body
.write()
.map_err(|_| anyhow!("outgoing request write failed"))?;

let pollable = request_body.subscribe();
Expand Down Expand Up @@ -111,17 +113,15 @@ pub fn request(

let future_response = outgoing_handler::handle(request, None)?;

// TODO: The current implementation requires this drop after the request is sent.
// The ownership semantics are unclear in wasi-http we should clarify exactly what is
// supposed to happen here.
http_types::outgoing_body_finish(outgoing_body, None);
http_types::OutgoingBody::finish(outgoing_body, None);

let incoming_response = match http_types::future_incoming_response_get(future_response) {
let incoming_response = match future_response.get() {
Some(result) => result.map_err(|_| anyhow!("incoming response errored"))?,
None => {
let pollable = http_types::listen_to_future_incoming_response(future_response);
let pollable = future_response.subscribe();
let _ = poll::poll_list(&[&pollable]);
http_types::future_incoming_response_get(future_response)
future_response
.get()
.expect("incoming response available")
.map_err(|_| anyhow!("incoming response errored"))?
}
Expand All @@ -130,18 +130,19 @@ pub fn request(
// Error? anyway, just use its Debug here:
.map_err(|e| anyhow!("{e:?}"))?;

http_types::drop_future_incoming_response(future_response);
drop(future_response);

let status = http_types::incoming_response_status(incoming_response);
let status = incoming_response.status();

let headers_handle = http_types::incoming_response_headers(incoming_response);
let headers = http_types::fields_entries(headers_handle);
http_types::drop_fields(headers_handle);
let headers_handle = incoming_response.headers();
let headers = headers_handle.entries();
drop(headers_handle);

let incoming_body = http_types::incoming_response_consume(incoming_response)
let incoming_body = incoming_response
.consume()
.map_err(|()| anyhow!("incoming response has no body stream"))?;

http_types::drop_incoming_response(incoming_response);
drop(incoming_response);

let input_stream = incoming_body.stream().unwrap();
let input_stream_pollable = input_stream.subscribe();
Expand Down
15 changes: 9 additions & 6 deletions crates/wasi-http/src/http_impl.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use crate::bindings::http::{
outgoing_handler,
types::{FutureIncomingResponse, OutgoingRequest, RequestOptions, Scheme},
types::{RequestOptions, Scheme},
};
use crate::types::{self, HostFutureIncomingResponse, IncomingResponseInternal, TableHttpExt};
use crate::types::{self, HostFutureIncomingResponse, IncomingResponseInternal};
use crate::WasiHttpView;
use anyhow::Context;
use bytes::Bytes;
Expand All @@ -11,14 +11,17 @@ use hyper::Method;
use std::time::Duration;
use tokio::net::TcpStream;
use tokio::time::timeout;
use types::HostOutgoingRequest;
use wasmtime::component::Resource;
use wasmtime_wasi::preview2;

impl<T: WasiHttpView> outgoing_handler::Host for T {
fn handle(
&mut self,
request_id: OutgoingRequest,
request_id: Resource<HostOutgoingRequest>,
options: Option<RequestOptions>,
) -> wasmtime::Result<Result<FutureIncomingResponse, outgoing_handler::Error>> {
) -> wasmtime::Result<Result<Resource<HostFutureIncomingResponse>, outgoing_handler::Error>>
{
let connect_timeout = Duration::from_millis(
options
.and_then(|opts| opts.connect_timeout_ms)
Expand All @@ -37,7 +40,7 @@ impl<T: WasiHttpView> outgoing_handler::Host for T {
.unwrap_or(600 * 1000) as u64,
);

let req = types::OutgoingRequestLens::from(request_id).delete(self.table())?;
let req = self.table().delete_resource(request_id)?;

let method = match req.method {
crate::bindings::http::types::Method::Get => Method::GET,
Expand Down Expand Up @@ -175,7 +178,7 @@ impl<T: WasiHttpView> outgoing_handler::Host for T {

let fut = self
.table()
.push_future_incoming_response(HostFutureIncomingResponse::new(handle))?;
.push_resource(HostFutureIncomingResponse::new(handle))?;

Ok(Ok(fut))
}
Expand Down
11 changes: 11 additions & 0 deletions crates/wasi-http/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,17 @@ pub mod bindings {
with: {
"wasi:io/streams": wasmtime_wasi::preview2::bindings::io::streams,
"wasi:io/poll": wasmtime_wasi::preview2::bindings::io::poll,

"wasi:http/types/outgoing-body": super::body::HostOutgoingBody,
"wasi:http/types/future-incoming-response": super::types::HostFutureIncomingResponse,
"wasi:http/types/outgoing-response": super::types::HostOutgoingResponse,
"wasi:http/types/future-trailers": super::body::HostFutureTrailers,
"wasi:http/types/incoming-body": super::body::HostIncomingBody,
"wasi:http/types/incoming-response": super::types::HostIncomingResponse,
"wasi:http/types/response-outparam": super::types::HostResponseOutparam,
"wasi:http/types/outgoing-request": super::types::HostOutgoingRequest,
"wasi:http/types/incoming-request": super::types::HostIncomingRequest,
"wasi:http/types/fields": super::types::HostFields,
}
});

Expand Down
Loading

0 comments on commit 3c3ea44

Please sign in to comment.