Browse Source

wasi-http spec tweaks (#7589)

* Change `ms` to `duration`

* Make `future-trailers.get` only return the trailers once

* `duration` is in nanoseconds
pull/7607/head
Trevor Elliott 11 months ago
committed by GitHub
parent
commit
1d234f8885
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 5
      crates/wasi-http/src/body.rs
  2. 87
      crates/wasi-http/src/types_impl.rs
  3. 29
      crates/wasi-http/wit/deps/http/types.wit
  4. 29
      crates/wasi/wit/deps/http/types.wit

5
crates/wasi-http/src/body.rs

@ -300,6 +300,9 @@ pub enum HostFutureTrailers {
/// Note that `Ok(None)` means that there were no trailers for this request
/// while `Ok(Some(_))` means that trailers were found in the request.
Done(Result<Option<FieldMap>, types::ErrorCode>),
/// Trailers have been consumed by `future-trailers.get`.
Consumed,
}
#[async_trait::async_trait]
@ -308,6 +311,7 @@ impl Subscribe for HostFutureTrailers {
let body = match self {
HostFutureTrailers::Waiting(body) => body,
HostFutureTrailers::Done(_) => return,
HostFutureTrailers::Consumed => return,
};
// If the body is itself being read by a body stream then we need to
@ -337,6 +341,7 @@ impl Subscribe for HostFutureTrailers {
let body = match self {
HostFutureTrailers::Waiting(body) => body,
HostFutureTrailers::Done(_) => return,
HostFutureTrailers::Consumed => return,
};
let hyper_body = match &mut body.body {
IncomingBodyState::Start(body) => body,

87
crates/wasi-http/src/types_impl.rs

@ -637,32 +637,31 @@ impl<T: WasiHttpView> crate::bindings::http::types::HostFutureTrailers for T {
fn get(
&mut self,
id: Resource<HostFutureTrailers>,
) -> wasmtime::Result<Option<Result<Option<Resource<Trailers>>, types::ErrorCode>>> {
) -> wasmtime::Result<Option<Result<Result<Option<Resource<Trailers>>, types::ErrorCode>, ()>>>
{
let trailers = self.table().get_mut(&id)?;
match trailers {
HostFutureTrailers::Waiting(_) => return Ok(None),
HostFutureTrailers::Done(Err(e)) => return Ok(Some(Err(e.clone()))),
HostFutureTrailers::Done(Ok(None)) => return Ok(Some(Ok(None))),
HostFutureTrailers::Done(Ok(_)) => {}
}
HostFutureTrailers::Consumed => return Ok(Some(Err(()))),
HostFutureTrailers::Done(_) => {}
};
fn get_fields(elem: &mut dyn Any) -> &mut FieldMap {
let trailers = elem.downcast_mut::<HostFutureTrailers>().unwrap();
match trailers {
HostFutureTrailers::Done(Ok(Some(e))) => e,
_ => unreachable!(),
}
}
let res = match std::mem::replace(trailers, HostFutureTrailers::Consumed) {
HostFutureTrailers::Done(res) => res,
_ => unreachable!(),
};
let hdrs = self.table().push_child(
HostFields::Ref {
parent: id.rep(),
get_fields,
},
&id,
)?;
let mut fields = match res {
Ok(Some(fields)) => fields,
Ok(None) => return Ok(Some(Ok(Ok(None)))),
Err(e) => return Ok(Some(Ok(Err(e)))),
};
remove_forbidden_headers(self, &mut fields);
let ts = self.table().push(HostFields::Owned { fields })?;
Ok(Some(Ok(Some(hdrs))))
Ok(Some(Ok(Ok(Some(ts)))))
}
}
@ -886,84 +885,84 @@ impl<T: WasiHttpView> crate::bindings::http::types::HostRequestOptions for T {
Ok(id)
}
fn connect_timeout_ms(
fn connect_timeout(
&mut self,
opts: Resource<types::RequestOptions>,
) -> wasmtime::Result<Option<types::Duration>> {
let millis = self
let nanos = self
.table()
.get(&opts)?
.connect_timeout
.map(|d| d.as_millis());
.map(|d| d.as_nanos());
if let Some(millis) = millis {
Ok(Some(millis.try_into()?))
if let Some(nanos) = nanos {
Ok(Some(nanos.try_into()?))
} else {
Ok(None)
}
}
fn set_connect_timeout_ms(
fn set_connect_timeout(
&mut self,
opts: Resource<types::RequestOptions>,
ms: Option<types::Duration>,
duration: Option<types::Duration>,
) -> wasmtime::Result<Result<(), ()>> {
self.table().get_mut(&opts)?.connect_timeout =
ms.map(|ms| std::time::Duration::from_millis(ms));
duration.map(std::time::Duration::from_nanos);
Ok(Ok(()))
}
fn first_byte_timeout_ms(
fn first_byte_timeout(
&mut self,
opts: Resource<types::RequestOptions>,
) -> wasmtime::Result<Option<types::Duration>> {
let millis = self
let nanos = self
.table()
.get(&opts)?
.first_byte_timeout
.map(|d| d.as_millis());
.map(|d| d.as_nanos());
if let Some(millis) = millis {
Ok(Some(millis.try_into()?))
if let Some(nanos) = nanos {
Ok(Some(nanos.try_into()?))
} else {
Ok(None)
}
}
fn set_first_byte_timeout_ms(
fn set_first_byte_timeout(
&mut self,
opts: Resource<types::RequestOptions>,
ms: Option<types::Duration>,
duration: Option<types::Duration>,
) -> wasmtime::Result<Result<(), ()>> {
self.table().get_mut(&opts)?.first_byte_timeout =
ms.map(|ms| std::time::Duration::from_millis(ms));
duration.map(std::time::Duration::from_nanos);
Ok(Ok(()))
}
fn between_bytes_timeout_ms(
fn between_bytes_timeout(
&mut self,
opts: Resource<types::RequestOptions>,
) -> wasmtime::Result<Option<types::Duration>> {
let millis = self
let nanos = self
.table()
.get(&opts)?
.between_bytes_timeout
.map(|d| d.as_millis());
.map(|d| d.as_nanos());
if let Some(millis) = millis {
Ok(Some(millis.try_into()?))
if let Some(nanos) = nanos {
Ok(Some(nanos.try_into()?))
} else {
Ok(None)
}
}
fn set_between_bytes_timeout_ms(
fn set_between_bytes_timeout(
&mut self,
opts: Resource<types::RequestOptions>,
ms: Option<types::Duration>,
duration: Option<types::Duration>,
) -> wasmtime::Result<Result<(), ()>> {
self.table().get_mut(&opts)?.between_bytes_timeout =
ms.map(|ms| std::time::Duration::from_millis(ms));
duration.map(std::time::Duration::from_nanos);
Ok(Ok(()))
}

29
crates/wasi-http/wit/deps/http/types.wit

@ -309,8 +309,7 @@ interface types {
}
/// Parameters for making an HTTP Request. Each of these parameters is an
/// optional timeout, with the unit in milliseconds, applicable to the
/// transport layer of the HTTP protocol.
/// optional timeout, applicable to the transport layer of the HTTP protocol.
///
/// These timeouts are separate from any the user may use to bound a
/// blocking call to `wasi:io/poll.poll`.
@ -319,27 +318,27 @@ interface types {
constructor();
/// The timeout for the initial connect to the HTTP Server.
connect-timeout-ms: func() -> option<duration>;
connect-timeout: func() -> option<duration>;
/// Set the timeout for the initial connect to the HTTP Server. An error
/// return value indicates that this timeout is not supported.
set-connect-timeout-ms: func(ms: option<duration>) -> result;
set-connect-timeout: func(duration: option<duration>) -> result;
/// The timeout for receiving the first byte of the Response body.
first-byte-timeout-ms: func() -> option<duration>;
first-byte-timeout: func() -> option<duration>;
/// Set the timeout for receiving the first byte of the Response body. An
/// error return value indicates that this timeout is not supported.
set-first-byte-timeout-ms: func(ms: option<duration>) -> result;
set-first-byte-timeout: func(duration: option<duration>) -> result;
/// The timeout for receiving subsequent chunks of bytes in the Response
/// body stream.
between-bytes-timeout-ms: func() -> option<duration>;
between-bytes-timeout: func() -> option<duration>;
/// Set the timeout for receiving subsequent chunks of bytes in the Response
/// body stream. An error return value indicates that this timeout is not
/// supported.
set-between-bytes-timeout-ms: func(ms: option<duration>) -> result;
set-between-bytes-timeout: func(duration: option<duration>) -> result;
}
/// Represents the ability to send an HTTP Response.
@ -437,16 +436,20 @@ interface types {
/// The outer `option` represents future readiness. Users can wait on this
/// `option` to become `some` using the `subscribe` method.
///
/// The `result` represents that either the HTTP Request or Response body,
/// as well as any trailers, were received successfully, or that an error
/// occured receiving them. The optional `trailers` indicates whether or not
/// trailers were present in the body.
/// The outer `result` is used to retrieve the trailers or error at most
/// once. It will be success on the first call in which the outer option
/// is `some`, and error on subsequent calls.
///
/// The inner `result` represents that either the HTTP Request or Response
/// body, as well as any trailers, were received successfully, or that an
/// error occured receiving them. The optional `trailers` indicates whether
/// or not trailers were present in the body.
///
/// When some `trailers` are returned by this method, the `trailers`
/// resource is immutable, and a child. Use of the `set`, `append`, or
/// `delete` methods will return an error, and the resource must be
/// dropped before the parent `future-trailers` is dropped.
get: func() -> option<result<option<trailers>, error-code>>;
get: func() -> option<result<result<option<trailers>, error-code>>>;
}
/// Represents an outgoing HTTP Response.

29
crates/wasi/wit/deps/http/types.wit

@ -309,8 +309,7 @@ interface types {
}
/// Parameters for making an HTTP Request. Each of these parameters is an
/// optional timeout, with the unit in milliseconds, applicable to the
/// transport layer of the HTTP protocol.
/// optional timeout, applicable to the transport layer of the HTTP protocol.
///
/// These timeouts are separate from any the user may use to bound a
/// blocking call to `wasi:io/poll.poll`.
@ -319,27 +318,27 @@ interface types {
constructor();
/// The timeout for the initial connect to the HTTP Server.
connect-timeout-ms: func() -> option<duration>;
connect-timeout: func() -> option<duration>;
/// Set the timeout for the initial connect to the HTTP Server. An error
/// return value indicates that this timeout is not supported.
set-connect-timeout-ms: func(ms: option<duration>) -> result;
set-connect-timeout: func(duration: option<duration>) -> result;
/// The timeout for receiving the first byte of the Response body.
first-byte-timeout-ms: func() -> option<duration>;
first-byte-timeout: func() -> option<duration>;
/// Set the timeout for receiving the first byte of the Response body. An
/// error return value indicates that this timeout is not supported.
set-first-byte-timeout-ms: func(ms: option<duration>) -> result;
set-first-byte-timeout: func(duration: option<duration>) -> result;
/// The timeout for receiving subsequent chunks of bytes in the Response
/// body stream.
between-bytes-timeout-ms: func() -> option<duration>;
between-bytes-timeout: func() -> option<duration>;
/// Set the timeout for receiving subsequent chunks of bytes in the Response
/// body stream. An error return value indicates that this timeout is not
/// supported.
set-between-bytes-timeout-ms: func(ms: option<duration>) -> result;
set-between-bytes-timeout: func(duration: option<duration>) -> result;
}
/// Represents the ability to send an HTTP Response.
@ -437,16 +436,20 @@ interface types {
/// The outer `option` represents future readiness. Users can wait on this
/// `option` to become `some` using the `subscribe` method.
///
/// The `result` represents that either the HTTP Request or Response body,
/// as well as any trailers, were received successfully, or that an error
/// occured receiving them. The optional `trailers` indicates whether or not
/// trailers were present in the body.
/// The outer `result` is used to retrieve the trailers or error at most
/// once. It will be success on the first call in which the outer option
/// is `some`, and error on subsequent calls.
///
/// The inner `result` represents that either the HTTP Request or Response
/// body, as well as any trailers, were received successfully, or that an
/// error occured receiving them. The optional `trailers` indicates whether
/// or not trailers were present in the body.
///
/// When some `trailers` are returned by this method, the `trailers`
/// resource is immutable, and a child. Use of the `set`, `append`, or
/// `delete` methods will return an error, and the resource must be
/// dropped before the parent `future-trailers` is dropped.
get: func() -> option<result<option<trailers>, error-code>>;
get: func() -> option<result<result<option<trailers>, error-code>>>;
}
/// Represents an outgoing HTTP Response.

Loading…
Cancel
Save