Skip to content

Commit

Permalink
feat: update to independent trailer retrieval
Browse files Browse the repository at this point in the history
This commit updates `wasi:http/types#body.finish` to avoid resolving
optional trailers, but instead returning them for the caller to
resolve.

This may introduce some efficiency gains in the cases where trailers
can be safely ignored, and does avoid the work done in checking
whether they are present or not, at least.

Signed-off-by: Victor Adossi <[email protected]>
  • Loading branch information
vados-cosmonic committed Feb 19, 2025
1 parent ab30f13 commit 65c6e80
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 31 deletions.
25 changes: 5 additions & 20 deletions crates/misc/component-async-tests/http/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,8 @@ use {
anyhow::anyhow,
std::{fmt, future::Future, mem},
wasi::http::types::{ErrorCode, HeaderError, Method, RequestOptionsError, Scheme},
wasmtime::{
component::{
Accessor, ErrorContext, FutureReader, Linker, Resource, ResourceTable, StreamReader,
},
AsContextMut,
wasmtime::component::{
Accessor, ErrorContext, FutureReader, Linker, Resource, ResourceTable, StreamReader,
},
};

Expand Down Expand Up @@ -233,25 +230,13 @@ where
async fn finish(
accessor: &mut Accessor<Self::BodyData>,
this: Resource<Body>,
) -> wasmtime::Result<Result<Option<Resource<Fields>>, ErrorCode>> {
) -> wasmtime::Result<Option<FutureReader<Resource<Fields>>>> {
let trailers = accessor.with(|mut store| {
let trailers = store.data_mut().table().delete(this)?.trailers;
trailers
.map(|v| v.read(store.as_context_mut()).map(|v| v.into_future()))
.transpose()
Ok(trailers) as wasmtime::Result<_>
})?;

let maybe_trailers = if let Some(trailers) = trailers {
match trailers.await {
Some(Ok(trailers)) => Some(trailers),
Some(Err(_err_ctx)) => return Ok(Err(ErrorCode::InternalError(None))),
None => None,
}
} else {
None
};

Ok(Ok(maybe_trailers))
Ok(trailers)
}

fn drop(&mut self, this: Resource<Body>) -> wasmtime::Result<()> {
Expand Down
10 changes: 5 additions & 5 deletions crates/misc/component-async-tests/wit/deps/http/types.wit
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ interface types {
/// permitted because the fields are immutable.
immutable,
}

/// This type enumerates the different kinds of errors that may occur when
/// setting fields of a `request-options` resource.
variant request-options-error {
Expand Down Expand Up @@ -234,13 +234,13 @@ interface types {
/// interface may only be consuming either the body contents or waiting on
/// trailers at any given time.
resource body {

/// Construct a new `body` with the specified stream and trailers.
constructor(
%stream: stream<u8>,
trailers: option<future<trailers>>
);

/// Returns the contents of the body, as a stream of bytes.
///
/// This function may be called multiple times as long as any `stream`s
Expand All @@ -249,9 +249,9 @@ interface types {

/// Takes ownership of `body`, and returns a `trailers`. This function will
/// trap if a `stream` child is still alive.
finish: static func(this: body) -> result<option<trailers>, error-code>;
finish: static func(this: body) -> option<future<trailers>>;
}

/// Represents an HTTP Request.
resource request {

Expand Down
11 changes: 9 additions & 2 deletions crates/test-programs/src/bin/async_http_echo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,15 @@ impl Handler for Component {

drop(pipe_tx);

if let Some(trailers) = Body::finish(body).await.unwrap() {
trailers_tx.write(trailers).await;
if let Some(maybe_trailers) = Body::finish(body).await {
if let Some(trailers) = maybe_trailers.await {
trailers_tx
.write(
trailers
.expect("trailer does not resolve to an error when present"),
)
.await;
}
}
});

Expand Down
22 changes: 18 additions & 4 deletions crates/test-programs/src/bin/async_http_middleware.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,15 @@ impl Handler for Component {
drop(pipe_tx);
}

if let Some(trailers) = Body::finish(body).await.unwrap() {
trailers_tx.write(trailers).await
if let Some(maybe_trailers) = Body::finish(body).await {
if let Some(trailers) = maybe_trailers.await {
trailers_tx
.write(
trailers
.expect("trailer does not resolve to an error when present"),
)
.await;
}
}
});

Expand Down Expand Up @@ -138,8 +145,15 @@ impl Handler for Component {
drop(pipe_tx);
}

if let Some(trailers) = Body::finish(body).await.unwrap() {
trailers_tx.write(trailers).await;
if let Some(maybe_trailers) = Body::finish(body).await {
if let Some(trailers) = maybe_trailers.await {
trailers_tx
.write(
trailers
.expect("trailer does not resolve to an error when present"),
)
.await;
}
}
});

Expand Down

0 comments on commit 65c6e80

Please sign in to comment.