diff --git a/ci/vendor-wit.sh b/ci/vendor-wit.sh index 55ffdf2a4072..c4888671494a 100755 --- a/ci/vendor-wit.sh +++ b/ci/vendor-wit.sh @@ -42,7 +42,7 @@ make_vendor "wasi" " filesystem@v0.2.1 io@v0.2.1 random@v0.2.1 - sockets@v0.2.1 + sockets@2e9982e " make_vendor "wasi-http" " @@ -51,7 +51,7 @@ make_vendor "wasi-http" " filesystem@v0.2.1 io@v0.2.1 random@v0.2.1 - sockets@v0.2.1 + sockets@2e9982e http@v0.2.1 " diff --git a/crates/wasi-http/src/bindings.rs b/crates/wasi-http/src/bindings.rs index 00054e5a644b..40b6dde0d719 100644 --- a/crates/wasi-http/src/bindings.rs +++ b/crates/wasi-http/src/bindings.rs @@ -8,6 +8,7 @@ mod generated { wasmtime::component::bindgen!({ path: "wit", world: "wasi:http/proxy", + features: ["network-error-code"], tracing: true, // Flag this as "possibly async" which will cause the exports to be // generated as async, but none of the imports here are async since @@ -56,6 +57,7 @@ pub mod sync { #![allow(missing_docs)] wasmtime::component::bindgen!({ world: "wasi:http/proxy", + features: ["network-error-code"], tracing: true, async: false, with: { diff --git a/crates/wasi-http/wit/deps/sockets/network.wit b/crates/wasi-http/wit/deps/sockets/network.wit index 8c13b348e534..993c4ce61393 100644 --- a/crates/wasi-http/wit/deps/sockets/network.wit +++ b/crates/wasi-http/wit/deps/sockets/network.wit @@ -1,5 +1,8 @@ @since(version = 0.2.0) interface network { + @unstable(feature = network-error-code) + use wasi:io/error@0.2.1.{error}; + /// An opaque resource that represents access to (a subset of) the network. /// This enables context-based security for networking. /// There is no need for this to map 1:1 to a physical network interface. @@ -105,6 +108,19 @@ interface network { permanent-resolver-failure, } + /// Attempts to extract a network-related `error-code` from the stream + /// `error` provided. + /// + /// Stream operations which return `stream-error::last-operation-failed` + /// have a payload with more information about the operation that failed. + /// This payload can be passed through to this function to see if there's + /// network-related information about the error to return. + /// + /// Note that this function is fallible because not all stream-related + /// errors are network-related errors. + @unstable(feature = network-error-code) + network-error-code: func(err: borrow) -> option; + @since(version = 0.2.0) enum ip-address-family { /// Similar to `AF_INET` in POSIX. diff --git a/crates/wasi/src/bindings.rs b/crates/wasi/src/bindings.rs index 74392b1831b3..0b06294ae76c 100644 --- a/crates/wasi/src/bindings.rs +++ b/crates/wasi/src/bindings.rs @@ -148,6 +148,7 @@ pub mod sync { wasmtime::component::bindgen!({ path: "wit", world: "wasi:cli/command", + features: ["network-error-code"], tracing: true, trappable_error_type: { "wasi:io/streams/stream-error" => StreamError, @@ -326,6 +327,7 @@ mod async_io { wasmtime::component::bindgen!({ path: "wit", world: "wasi:cli/command", + features: ["network-error-code"], tracing: true, trappable_imports: true, async: { diff --git a/crates/wasi/src/host/network.rs b/crates/wasi/src/host/network.rs index 6772db788ace..b44d281c4bec 100644 --- a/crates/wasi/src/host/network.rs +++ b/crates/wasi/src/host/network.rs @@ -15,6 +15,19 @@ where fn convert_error_code(&mut self, error: SocketError) -> anyhow::Result { error.downcast() } + + fn network_error_code( + &mut self, + err: Resource, + ) -> anyhow::Result> { + let err = self.table().get(&err)?; + + if let Some(err) = err.downcast_ref::() { + return Ok(Some(ErrorCode::from(err))); + } + + Ok(None) + } } impl crate::bindings::sockets::network::HostNetwork for WasiImpl @@ -32,8 +45,14 @@ where impl From for ErrorCode { fn from(value: io::Error) -> Self { + (&value).into() + } +} + +impl From<&io::Error> for ErrorCode { + fn from(value: &io::Error) -> Self { // Attempt the more detailed native error code first: - if let Some(errno) = Errno::from_io_error(&value) { + if let Some(errno) = Errno::from_io_error(value) { return errno.into(); } @@ -62,7 +81,13 @@ impl From for ErrorCode { impl From for ErrorCode { fn from(value: Errno) -> Self { - match value { + (&value).into() + } +} + +impl From<&Errno> for ErrorCode { + fn from(value: &Errno) -> Self { + match *value { Errno::WOULDBLOCK => ErrorCode::WouldBlock, #[allow(unreachable_patterns)] // EWOULDBLOCK and EAGAIN can have the same value. Errno::AGAIN => ErrorCode::WouldBlock, diff --git a/crates/wasi/wit/deps/sockets/network.wit b/crates/wasi/wit/deps/sockets/network.wit index 8c13b348e534..993c4ce61393 100644 --- a/crates/wasi/wit/deps/sockets/network.wit +++ b/crates/wasi/wit/deps/sockets/network.wit @@ -1,5 +1,8 @@ @since(version = 0.2.0) interface network { + @unstable(feature = network-error-code) + use wasi:io/error@0.2.1.{error}; + /// An opaque resource that represents access to (a subset of) the network. /// This enables context-based security for networking. /// There is no need for this to map 1:1 to a physical network interface. @@ -105,6 +108,19 @@ interface network { permanent-resolver-failure, } + /// Attempts to extract a network-related `error-code` from the stream + /// `error` provided. + /// + /// Stream operations which return `stream-error::last-operation-failed` + /// have a payload with more information about the operation that failed. + /// This payload can be passed through to this function to see if there's + /// network-related information about the error to return. + /// + /// Note that this function is fallible because not all stream-related + /// errors are network-related errors. + @unstable(feature = network-error-code) + network-error-code: func(err: borrow) -> option; + @since(version = 0.2.0) enum ip-address-family { /// Similar to `AF_INET` in POSIX.