diff --git a/.github/actions/spin-ci-dependencies/action.yml b/.github/actions/spin-ci-dependencies/action.yml index 3fae5c555f..ff0c5dfc3d 100644 --- a/.github/actions/spin-ci-dependencies/action.yml +++ b/.github/actions/spin-ci-dependencies/action.yml @@ -8,7 +8,7 @@ inputs: type: bool rust-version: description: 'Rust version to setup' - default: '1.86' + default: '1.87' required: false type: string diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b15164a190..de27a59a97 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -17,7 +17,7 @@ concurrency: env: CARGO_TERM_COLOR: always - RUST_VERSION: 1.86 + RUST_VERSION: 1.87 jobs: dependency-review: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c15d4d7e30..0da2363a82 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -11,7 +11,7 @@ on: concurrency: ${{ github.workflow }}-${{ github.ref }} env: - RUST_VERSION: 1.86 + RUST_VERSION: 1.87 jobs: build-and-sign: diff --git a/Cargo.lock b/Cargo.lock index c0b5762148..1897e8b49a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1887,36 +1887,36 @@ dependencies = [ [[package]] name = "cranelift-assembler-x64" -version = "0.123.2" +version = "0.124.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0920ef6863433fa28ece7e53925be4cd39a913adba2dc3738f4edd182f76d168" +checksum = "d3e8ca189363907c025c5debe2bfe56c8c18503d4575d750f87e4ccbbfbd8681" dependencies = [ "cranelift-assembler-x64-meta", ] [[package]] name = "cranelift-assembler-x64-meta" -version = "0.123.2" +version = "0.124.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8990a217e2529a378af1daf4f8afa889f928f07ebbde6ae2f058ae60e40e2c20" +checksum = "e169461bfd463df68b01b196522f263c905eadc852f6e57fd4ce4c5d76115ead" dependencies = [ "cranelift-srcgen", ] [[package]] name = "cranelift-bforest" -version = "0.123.2" +version = "0.124.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62225596b687f69a42c038485a28369badc186cb7c74bd9436eeec9f539011b1" +checksum = "2a98298338375075287834defe333d552847110f3a04db0ce19bd308b4c40fbb" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-bitset" -version = "0.123.2" +version = "0.124.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c23914fc4062558650a6f0d8c1846c97b541215a291fdeabc85f68bdc9bbcca3" +checksum = "edf5f49a2e2ae284db75437a49cc13220a7fb394983d5545af1209ab0bbadee3" dependencies = [ "serde", "serde_derive", @@ -1924,9 +1924,9 @@ dependencies = [ [[package]] name = "cranelift-codegen" -version = "0.123.2" +version = "0.124.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41a238b2f7e7ec077eb170145fa15fd8b3d0f36cc83d8e354e29ca550f339ca7" +checksum = "c354d6db9e344f647f38c88849c482c6014b79a295aca23fa82f73b62caeda2d" dependencies = [ "bumpalo", "cranelift-assembler-x64", @@ -1951,9 +1951,9 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.123.2" +version = "0.124.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9315ddcc2512513a9d66455ec89bb70ae5498cb472f5ed990230536f4cd5c011" +checksum = "9bb8008396957de750e26d0b40a76bea6e5623d970a5bfe4266ef0a79ccb8341" dependencies = [ "cranelift-assembler-x64-meta", "cranelift-codegen-shared", @@ -1964,24 +1964,24 @@ dependencies = [ [[package]] name = "cranelift-codegen-shared" -version = "0.123.2" +version = "0.124.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc6acea40ef860f28cb36eaad479e26556c1e538b0a66fc44598cf1b1689393d" +checksum = "98ecb53eafe1ad1f7d7f7d0585ae5d42b2050978fa812216b0420d4752eb41cb" [[package]] name = "cranelift-control" -version = "0.123.2" +version = "0.124.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b2af895da90761cfda4a4445960554fcec971e637882eda5a87337d993fe1b9" +checksum = "b9c43ac27fe178cadb17e7f4cf1320ba89b8875cc2bdee265cccfca49bc76c95" dependencies = [ "arbitrary", ] [[package]] name = "cranelift-entity" -version = "0.123.2" +version = "0.124.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e8c542c856feb50d504e4fc0526b3db3a514f882a9f68f956164531517828ab" +checksum = "15513ee4bf648d366654c6a9864fe870ca64f1eed4acabf9139056e68b3d44dc" dependencies = [ "cranelift-bitset", "serde", @@ -1990,9 +1990,9 @@ dependencies = [ [[package]] name = "cranelift-frontend" -version = "0.123.2" +version = "0.124.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9996dd9c20929c03360fe0c4edf3594c0cbb94525bdbfa04b6bb639ec14573c7" +checksum = "c5e4399d31f06b50fcb3fa0117ff4c393c22e521574eecf524cf932fc99cd78f" dependencies = [ "cranelift-codegen", "log", @@ -2002,15 +2002,15 @@ dependencies = [ [[package]] name = "cranelift-isle" -version = "0.123.2" +version = "0.124.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "928b8dccad51b9e0ffe54accbd617da900239439b13d48f0f122ab61105ca6ad" +checksum = "9a751ec2b7c2f281274a3798e37ba2344b55f60789e67aaa10d6bbea3f3f8a6b" [[package]] name = "cranelift-native" -version = "0.123.2" +version = "0.124.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f75ef0a6a2efed3a2a14812318e28dc82c214eab5399c13d70878e2f88947b5" +checksum = "546500d7cb424c423e118dfddc169aa61ed611c47fc1cf48783ed4e3f9800619" dependencies = [ "cranelift-codegen", "libc", @@ -2019,9 +2019,9 @@ dependencies = [ [[package]] name = "cranelift-srcgen" -version = "0.123.2" +version = "0.124.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "673bd6d1c83cb41d60afb140a1474ef6caf1a3e02f3820fc522aefbc93ac67d6" +checksum = "edeb6b718b23108a123ad1c8eecf6fa34d21a6b5518fc340dda80ce5bdf42377" [[package]] name = "crc32fast" @@ -6315,9 +6315,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] name = "pin-utils" @@ -6712,9 +6712,9 @@ dependencies = [ [[package]] name = "pulley-interpreter" -version = "36.0.2" +version = "37.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4e2d31146038fd9e62bfa331db057aca325d5ca10451a9fe341356cead7da53" +checksum = "4338089093bf5f2f50e77602a4b8bb938e16bead1419ed9cd6484c9ef7050b10" dependencies = [ "cranelift-bitset", "log", @@ -6724,9 +6724,9 @@ dependencies = [ [[package]] name = "pulley-macros" -version = "36.0.2" +version = "37.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efb9fdafaca625f9ea8cfa793364ea1bdd32d306cff18f166b00ddaa61ecbb27" +checksum = "23e93c268176831e893721022bb923f41b892b3c9e41875f276025fddb1a0ea8" dependencies = [ "proc-macro2", "quote", @@ -7072,9 +7072,9 @@ dependencies = [ [[package]] name = "regalloc2" -version = "0.12.2" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5216b1837de2149f8bc8e6d5f88a9326b63b8c836ed58ce4a0a29ec736a59734" +checksum = "68e18e1ef763167dc6718c28a5585e62f907590a21028b8e87be1318f19ef1cb" dependencies = [ "allocator-api2", "bumpalo", @@ -8337,14 +8337,14 @@ dependencies = [ "tokio", "toml", "tracing", - "wasm-encoder 0.236.1", - "wasm-metadata 0.236.1", - "wasmparser 0.236.1", + "wasm-encoder 0.239.0", + "wasm-metadata 0.239.0", + "wasmparser 0.239.0", "wasmtime", "wasmtime-wasi", "wat", - "wit-component 0.236.1", - "wit-parser 0.236.1", + "wit-component 0.239.0", + "wit-parser 0.239.0", ] [[package]] @@ -8431,10 +8431,10 @@ dependencies = [ "wac-graph", "wac-types", "wasm-pkg-client", - "wasmparser 0.236.1", - "wit-component 0.236.1", + "wasmparser 0.239.0", + "wit-component 0.239.0", "wit-encoder", - "wit-parser 0.236.1", + "wit-parser 0.239.0", ] [[package]] @@ -8499,9 +8499,11 @@ dependencies = [ "anyhow", "bytes", "http 1.1.0", + "http-body 1.0.1", "http-body-util", "hyper 1.5.0", "hyper-util", + "pin-project-lite", "reqwest 0.12.9", "rustls 0.23.18", "serde", @@ -8928,11 +8930,11 @@ dependencies = [ "tokio-util", "tracing", "walkdir", - "wasm-encoder 0.236.1", - "wasmparser 0.236.1", + "wasm-encoder 0.239.0", + "wasmparser 0.239.0", "wat", - "wit-component 0.236.1", - "wit-parser 0.236.1", + "wit-component 0.239.0", + "wit-parser 0.239.0", ] [[package]] @@ -9177,9 +9179,11 @@ dependencies = [ "clap 3.2.25", "futures", "http 1.1.0", + "http-body 1.0.1", "http-body-util", "hyper 1.5.0", "hyper-util", + "pin-project-lite", "rustls 0.23.18", "rustls-pki-types", "serde", @@ -9190,6 +9194,7 @@ dependencies = [ "spin-factor-outbound-networking", "spin-factor-wasi", "spin-factors", + "spin-factors-executor", "spin-http", "spin-telemetry", "spin-trigger", @@ -9638,7 +9643,7 @@ name = "test-components" version = "0.1.0" dependencies = [ "cargo_toml", - "wit-component 0.236.1", + "wit-component 0.239.0", ] [[package]] @@ -10846,12 +10851,12 @@ dependencies = [ [[package]] name = "wasm-encoder" -version = "0.236.1" +version = "0.239.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "724fccfd4f3c24b7e589d333fc0429c68042897a7e8a5f8694f31792471841e7" +checksum = "5be00faa2b4950c76fe618c409d2c3ea5a3c9422013e079482d78544bb2d184c" dependencies = [ "leb128fmt", - "wasmparser 0.236.1", + "wasmparser 0.239.0", ] [[package]] @@ -10892,9 +10897,9 @@ dependencies = [ [[package]] name = "wasm-metadata" -version = "0.236.1" +version = "0.239.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c909f94a49a8de3365f3c0344f064818f1e369ff1740c5b04f455f85d454768e" +checksum = "20b3ec880a9ac69ccd92fbdbcf46ee833071cf09f82bb005b2327c7ae6025ae2" dependencies = [ "anyhow", "auditable-serde", @@ -10905,8 +10910,8 @@ dependencies = [ "serde_json", "spdx", "url", - "wasm-encoder 0.236.1", - "wasmparser 0.236.1", + "wasm-encoder 0.239.0", + "wasmparser 0.239.0", ] [[package]] @@ -11015,9 +11020,9 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.236.1" +version = "0.239.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9b1e81f3eb254cf7404a82cee6926a4a3ccc5aad80cc3d43608a070c67aa1d7" +checksum = "8c9d90bb93e764f6beabf1d02028c70a2156a6583e63ac4218dd07ef733368b0" dependencies = [ "bitflags 2.6.0", "hashbrown 0.15.2", @@ -11038,29 +11043,31 @@ dependencies = [ [[package]] name = "wasmprinter" -version = "0.236.1" +version = "0.239.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2df225df06a6df15b46e3f73ca066ff92c2e023670969f7d50ce7d5e695abbb1" +checksum = "b3981f3d51f39f24f5fc90f93049a90f08dbbca8deba602cd46bb8ca67a94718" dependencies = [ "anyhow", "termcolor", - "wasmparser 0.236.1", + "wasmparser 0.239.0", ] [[package]] name = "wasmtime" -version = "36.0.2" +version = "37.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b3e1fab634681494213138ea3a18e958e5ea99da13a4a01a4b870d51a41680b" +checksum = "eae1ef7649330697f0374eca8af0a437cf349605afce261bb64ba66fa0663c80" dependencies = [ "addr2line 0.25.0", "anyhow", "async-trait", "bitflags 2.6.0", "bumpalo", + "bytes", "cc", "cfg-if", "encoding_rs", + "futures", "fxprof-processed-profile", "gimli 0.32.0", "hashbrown 0.15.2", @@ -11082,8 +11089,8 @@ dependencies = [ "serde_json", "smallvec", "target-lexicon", - "wasm-encoder 0.236.1", - "wasmparser 0.236.1", + "wasm-encoder 0.239.0", + "wasmparser 0.239.0", "wasmtime-environ", "wasmtime-internal-asm-macros", "wasmtime-internal-cache", @@ -11104,9 +11111,9 @@ dependencies = [ [[package]] name = "wasmtime-environ" -version = "36.0.2" +version = "37.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6750e519977953a018fe994aada7e02510aea4babb03310aa5f5b4145b6e6577" +checksum = "d6bf9ff7210fa31880e7cf3cfa1b83648c777090aa11ac1c448dff11e6c466a2" dependencies = [ "anyhow", "cpp_demangle", @@ -11123,26 +11130,26 @@ dependencies = [ "serde_derive", "smallvec", "target-lexicon", - "wasm-encoder 0.236.1", - "wasmparser 0.236.1", - "wasmprinter 0.236.1", + "wasm-encoder 0.239.0", + "wasmparser 0.239.0", + "wasmprinter 0.239.0", "wasmtime-internal-component-util", ] [[package]] name = "wasmtime-internal-asm-macros" -version = "36.0.2" +version = "37.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdbf38adac6e81d5c0326e8fd25f80450e3038f2fc103afd3c5cc8b83d5dd78b" +checksum = "761159dea98c5f585497f715d9d80b38baa7c6334cf9e033a76d01b291719416" dependencies = [ "cfg-if", ] [[package]] name = "wasmtime-internal-cache" -version = "36.0.2" +version = "37.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0c9085d8c04cc294612d743e2f355382b39250de4bd20bf4b0b0b7c0ae7067a" +checksum = "0ea7c17c1d771c923f63c08bd79d6714ca8bb503cf4ecb6f39d82043280020bd" dependencies = [ "anyhow", "base64 0.22.1", @@ -11160,9 +11167,9 @@ dependencies = [ [[package]] name = "wasmtime-internal-component-macro" -version = "36.0.2" +version = "37.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26a578a474e3b7ddce063cd169ced292b5185013341457522891b10e989aa42a" +checksum = "fd634b96656a0740f2b5fdb01e69bfc670bafbb292436826022a26153b33e818" dependencies = [ "anyhow", "proc-macro2", @@ -11170,20 +11177,20 @@ dependencies = [ "syn 2.0.87", "wasmtime-internal-component-util", "wasmtime-internal-wit-bindgen", - "wit-parser 0.236.1", + "wit-parser 0.239.0", ] [[package]] name = "wasmtime-internal-component-util" -version = "36.0.2" +version = "37.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edc23d46ec1b1cd42b6f73205eb80498ed94b47098ec53456c0b18299405b158" +checksum = "2a29a22837e16da7263e3622a7451917684971f65d21f4f9b97049babfacee37" [[package]] name = "wasmtime-internal-cranelift" -version = "36.0.2" +version = "37.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d85b8ba128525bff91b89ac8a97755136a4fb0fb59df5ffb7539dd646455d441" +checksum = "da2055ee07c1782ec3bb96bd7b91328e003de1a327eb02c48c2dfc937f490547" dependencies = [ "anyhow", "cfg-if", @@ -11200,17 +11207,18 @@ dependencies = [ "smallvec", "target-lexicon", "thiserror 2.0.12", - "wasmparser 0.236.1", + "wasmparser 0.239.0", "wasmtime-environ", "wasmtime-internal-math", + "wasmtime-internal-unwinder", "wasmtime-internal-versioned-export-macros", ] [[package]] name = "wasmtime-internal-fiber" -version = "36.0.2" +version = "37.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c566f5137de1f55339df8a236a5ec89698b466a3d33f9cc07823a58a3f85e16" +checksum = "781b52cb6e688a6a50b90051b20a87a841c35638a18e309e00fed9daca7e36aa" dependencies = [ "anyhow", "cc", @@ -11224,9 +11232,9 @@ dependencies = [ [[package]] name = "wasmtime-internal-jit-debug" -version = "36.0.2" +version = "37.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e03f0b11f8fe4d456feac11e7e9dc6f02ddb34d4f6a1912775dbc63c5bdd5670" +checksum = "b771527002767c3c84f7edee5255925c1dce5fd41e9de5b46aeaaee6e5242971" dependencies = [ "cc", "object 0.37.3", @@ -11236,9 +11244,9 @@ dependencies = [ [[package]] name = "wasmtime-internal-jit-icache-coherence" -version = "36.0.2" +version = "37.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71aeb74f9b3fd9225319c723e59832a77a674b0c899ba9795f9b2130a6d1b167" +checksum = "4aea2b284343796fbbe749c36db092b43809762f8b9e46626561a8be4003dd85" dependencies = [ "anyhow", "cfg-if", @@ -11248,24 +11256,24 @@ dependencies = [ [[package]] name = "wasmtime-internal-math" -version = "36.0.2" +version = "37.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31d5dad8a609c6cc47a5f265f13b52e347e893450a69641af082b8a276043fa7" +checksum = "5a058122e659373c3648a71de03436105f213037d8016bb68550c259d4b37931" dependencies = [ "libm", ] [[package]] name = "wasmtime-internal-slab" -version = "36.0.2" +version = "37.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d152a7b875d62e395bfe0ae7d12e7b47cd332eb380353cce3eb831f9843731d" +checksum = "65cafe64859a9df2b2391bb4cc1139eace115c02ba363e22cfd19eb675282f5a" [[package]] name = "wasmtime-internal-unwinder" -version = "36.0.2" +version = "37.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2aaacc0fea00293f7af7e6c25cef74b7d213ebbe7560c86305eec15fc318fab8" +checksum = "be561ffc6e3dcbd07b49d463af1a325412e58550d1514fbfb6c37e1bf4c80928" dependencies = [ "anyhow", "cfg-if", @@ -11276,9 +11284,9 @@ dependencies = [ [[package]] name = "wasmtime-internal-versioned-export-macros" -version = "36.0.2" +version = "37.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61c7f75326434944cc5f3b75409a063fa37e537f6247f00f0f733679f0be406" +checksum = "8d16a0ea81107fc7e269d504bb586296eaf9c4d79d99aaa4f4135d18bc6fbc86" dependencies = [ "proc-macro2", "quote", @@ -11287,16 +11295,17 @@ dependencies = [ [[package]] name = "wasmtime-internal-winch" -version = "36.0.2" +version = "37.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cfbaa87e1ac4972bb096c9cb1800fedc113e36332cc4bc2c96a2ef1d7c5e750" +checksum = "a99416e4805ffc48b718b5b967d3bda44aa8765c7bfcc6993f8b5819e8427cb6" dependencies = [ "anyhow", "cranelift-codegen", "gimli 0.32.0", + "log", "object 0.37.3", "target-lexicon", - "wasmparser 0.236.1", + "wasmparser 0.239.0", "wasmtime-environ", "wasmtime-internal-cranelift", "winch-codegen", @@ -11304,22 +11313,22 @@ dependencies = [ [[package]] name = "wasmtime-internal-wit-bindgen" -version = "36.0.2" +version = "37.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "169042d58002f16da149ab7d608b71164411abd1fc5140f48f4c200b44bb5565" +checksum = "d04509ae5bfb09b509e22ce83168add9b2a92dc7a902d68f31d391c9b23a36d6" dependencies = [ "anyhow", "bitflags 2.6.0", "heck 0.5.0", "indexmap 2.7.1", - "wit-parser 0.236.1", + "wit-parser 0.239.0", ] [[package]] name = "wasmtime-wasi" -version = "36.0.2" +version = "37.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9049a5fedcd24fa0f665ba7c17c4445c1a547536a9560d960e15bee2d8428d0" +checksum = "78179e5f067030bcc032cb4c149bbe92688e3fc9960b9d45eb06c38b817e6b8b" dependencies = [ "anyhow", "async-trait", @@ -11348,9 +11357,9 @@ dependencies = [ [[package]] name = "wasmtime-wasi-http" -version = "36.0.2" +version = "37.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1eea0b00539f0a3defce68bddb746736debea787e2f3a67cb562df977eb65a7" +checksum = "c1c3083c447bc7cbeb1128068d3fef0768ff6fb346409a574466aa3e4e458d1e" dependencies = [ "anyhow", "async-trait", @@ -11363,6 +11372,7 @@ dependencies = [ "rustls 0.22.4", "tokio", "tokio-rustls 0.25.0", + "tokio-util", "tracing", "wasmtime", "wasmtime-wasi", @@ -11372,9 +11382,9 @@ dependencies = [ [[package]] name = "wasmtime-wasi-io" -version = "36.0.2" +version = "37.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d62156d8695d80df8e85baeb56379b3ba6b6bf5996671594724c24d40b67825f" +checksum = "aa0974abaf5ec96584ed75928689a95e79b553182939337fa284779cb6b8a4e3" dependencies = [ "anyhow", "async-trait", @@ -11394,24 +11404,24 @@ dependencies = [ [[package]] name = "wast" -version = "236.0.1" +version = "239.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3bec4b4db9c6808d394632fd4b0cd4654c32c540bd3237f55ee6a40fff6e51f" +checksum = "9139176fe8a2590e0fb174cdcaf373b224cb93c3dde08e4297c1361d2ba1ea5d" dependencies = [ "bumpalo", "leb128fmt", "memchr", "unicode-width 0.2.0", - "wasm-encoder 0.236.1", + "wasm-encoder 0.239.0", ] [[package]] name = "wat" -version = "1.236.1" +version = "1.239.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64475e2f77d6071ce90624098fc236285ddafa8c3ea1fb386f2c4154b6c2bbdb" +checksum = "3e1c941927d34709f255558166f8901a2005f8ab4a9650432e9281b7cc6f3b75" dependencies = [ - "wast 236.0.1", + "wast 239.0.0", ] [[package]] @@ -11549,9 +11559,9 @@ dependencies = [ [[package]] name = "wiggle" -version = "36.0.2" +version = "37.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e233166bc0ef02371ebe2c630aba51dd3f015bcaf616d32b4171efab84d09137" +checksum = "b35aad501cfca310289a22bdc95c571c15047967b02295a4df56de391b4d90ef" dependencies = [ "anyhow", "async-trait", @@ -11564,9 +11574,9 @@ dependencies = [ [[package]] name = "wiggle-generate" -version = "36.0.2" +version = "37.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93048543902e61c65b75d8a9ea0e78d5a8723e5db6e11ff93870165807c4463d" +checksum = "66a1516334f2191ef393f754a8689f0c2193cf304828725b4708d377c6b0a185" dependencies = [ "anyhow", "heck 0.5.0", @@ -11578,9 +11588,9 @@ dependencies = [ [[package]] name = "wiggle-macro" -version = "36.0.2" +version = "37.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd7e511edbcaa045079dea564486c4ff7946ae491002227c41d74ea62a59d329" +checksum = "8c6a0b969afcee961240d696375f29e3c42e6a55e2fcf9a1798f500fe0fdd242" dependencies = [ "proc-macro2", "quote", @@ -11621,9 +11631,9 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "winch-codegen" -version = "36.0.2" +version = "37.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e615fe205d7d4c9aa62217862f2e0969d00b9b0843af0b1b8181adaea3cfef3" +checksum = "20581fd07c028fc1c151cd5c15719da62dfd852502c1751df8a93a0637a86791" dependencies = [ "anyhow", "cranelift-assembler-x64", @@ -11633,7 +11643,7 @@ dependencies = [ "smallvec", "target-lexicon", "thiserror 2.0.12", - "wasmparser 0.236.1", + "wasmparser 0.239.0", "wasmtime-environ", "wasmtime-internal-cranelift", "wasmtime-internal-math", @@ -12176,9 +12186,9 @@ dependencies = [ [[package]] name = "wit-component" -version = "0.236.1" +version = "0.239.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3622959ed7ed6341c38e5aa35af243632534b0a36226852faa802939ce11e00f" +checksum = "88a866b19dba2c94d706ec58c92a4c62ab63e482b4c935d2a085ac94caecb136" dependencies = [ "anyhow", "bitflags 2.6.0", @@ -12187,11 +12197,11 @@ dependencies = [ "serde", "serde_derive", "serde_json", - "wasm-encoder 0.236.1", - "wasm-metadata 0.236.1", - "wasmparser 0.236.1", + "wasm-encoder 0.239.0", + "wasm-metadata 0.239.0", + "wasmparser 0.239.0", "wat", - "wit-parser 0.236.1", + "wit-parser 0.239.0", ] [[package]] @@ -12245,9 +12255,9 @@ dependencies = [ [[package]] name = "wit-parser" -version = "0.236.1" +version = "0.239.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16e4833a20cd6e85d6abfea0e63a399472d6f88c6262957c17f546879a80ba15" +checksum = "55c92c939d667b7bf0c6bf2d1f67196529758f99a2a45a3355cc56964fd5315d" dependencies = [ "anyhow", "id-arena", @@ -12258,7 +12268,7 @@ dependencies = [ "serde_derive", "serde_json", "unicode-xid", - "wasmparser 0.236.1", + "wasmparser 0.239.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 0b43d5971b..82bfb77d2e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -136,6 +136,7 @@ futures-util = "0.3" glob = "0.3" heck = "0.5" http = "1" +http-body = "1" http-body-util = "0.1" hyper = { version = "1", features = ["full"] } hyper-util = { version = "0.1", features = ["tokio"] } @@ -143,6 +144,7 @@ indexmap = "2" itertools = "0.14" lazy_static = "1.5" path-absolutize = "3" +pin-project-lite = "0.2.16" quote = "1" rand = "0.9" redis = "0.32.5" @@ -170,16 +172,16 @@ tower-service = "0.3.3" tracing = { version = "0.1.41", features = ["log"] } url = "2" walkdir = "2" -wasm-encoder = "0.236.1" -wasm-metadata = "0.236.1" +wasm-encoder = "0.239.0" +wasm-metadata = "0.239.0" wasm-pkg-client = "0.11" wasm-pkg-common = "0.11" -wasmparser = "0.236.1" -wasmtime = "36.0.2" -wasmtime-wasi = "36.0.2" -wasmtime-wasi-http = "36.0.2" -wit-component = "0.236.1" -wit-parser = "0.236.1" +wasmparser = "0.239.0" +wasmtime = { version = "37.0.1", features = ["component-model-async"] } +wasmtime-wasi = { version = "37.0.1", features = ["p3"] } +wasmtime-wasi-http = { version = "37.0.1", features = ["p3"] } +wit-component = "0.239.0" +wit-parser = "0.239.0" spin-componentize = { path = "crates/componentize" } diff --git a/crates/core/src/lib.rs b/crates/core/src/lib.rs index 2866e0f244..760734c62b 100644 --- a/crates/core/src/lib.rs +++ b/crates/core/src/lib.rs @@ -75,6 +75,7 @@ impl Default for Config { inner.async_support(true); inner.epoch_interruption(true); inner.wasm_component_model(true); + inner.wasm_component_model_async(true); // If targeting musl, disable native unwind to address this issue: // https://github.com/spinframework/spin/issues/2889 // TODO: remove this when wasmtime is updated to >= v27.0.0 diff --git a/crates/core/tests/integration_test.rs b/crates/core/tests/integration_test.rs index 8f83b3ea98..392e54db29 100644 --- a/crates/core/tests/integration_test.rs +++ b/crates/core/tests/integration_test.rs @@ -9,7 +9,7 @@ use spin_core::{AsState, Component, Config, Engine, State, Store, StoreBuilder, use spin_factor_wasi::{DummyFilesMounter, WasiFactor}; use spin_factors::{App, AsInstanceState, RuntimeFactors}; use spin_locked_app::locked::LockedApp; -use tokio::{fs, io::AsyncWrite}; +use tokio::fs; use wasmtime_wasi::I32Exit; #[tokio::test(flavor = "multi_thread")] @@ -170,44 +170,3 @@ async fn run_test( .0 .map_err(|()| anyhow::anyhow!("command failed")) } - -// Write with `print!`, required for test output capture -struct TestWriter(tokio::io::Stdout); - -impl std::io::Write for TestWriter { - fn write(&mut self, buf: &[u8]) -> std::io::Result { - print!("{}", String::from_utf8_lossy(buf)); - Ok(buf.len()) - } - - fn flush(&mut self) -> std::io::Result<()> { - Ok(()) - } -} - -impl AsyncWrite for TestWriter { - fn poll_write( - self: std::pin::Pin<&mut Self>, - cx: &mut std::task::Context<'_>, - buf: &[u8], - ) -> std::task::Poll> { - let this = self.get_mut(); - std::pin::Pin::new(&mut this.0).poll_write(cx, buf) - } - - fn poll_flush( - self: std::pin::Pin<&mut Self>, - cx: &mut std::task::Context<'_>, - ) -> std::task::Poll> { - let this = self.get_mut(); - std::pin::Pin::new(&mut this.0).poll_flush(cx) - } - - fn poll_shutdown( - self: std::pin::Pin<&mut Self>, - cx: &mut std::task::Context<'_>, - ) -> std::task::Poll> { - let this = self.get_mut(); - std::pin::Pin::new(&mut this.0).poll_shutdown(cx) - } -} diff --git a/crates/environments/src/environment.rs b/crates/environments/src/environment.rs index 0b1bf21ac4..2ba48683a4 100644 --- a/crates/environments/src/environment.rs +++ b/crates/environments/src/environment.rs @@ -459,7 +459,7 @@ mod test { let mut resolve = wit_parser::Resolve::default(); let package_id = resolve.push_str("test", wit).expect("should parse WIT"); let world_id = resolve - .select_world(package_id, Some(world)) + .select_world(&[package_id], Some(world)) .expect("should select world"); let mut wasm = wit_component::dummy_module( diff --git a/crates/factor-outbound-http/Cargo.toml b/crates/factor-outbound-http/Cargo.toml index 03f5136296..6e6d14cf01 100644 --- a/crates/factor-outbound-http/Cargo.toml +++ b/crates/factor-outbound-http/Cargo.toml @@ -8,9 +8,11 @@ edition = { workspace = true } anyhow = { workspace = true } bytes = { workspace = true } http = { workspace = true } +http-body = { workspace = true } http-body-util = { workspace = true } hyper = { workspace = true } hyper-util = { workspace = true } +pin-project-lite = { workspace = true } reqwest = { workspace = true, features = ["gzip"] } rustls = { workspace = true } serde = { workspace = true } diff --git a/crates/factor-outbound-http/src/lib.rs b/crates/factor-outbound-http/src/lib.rs index 101075de75..ef0ef8f953 100644 --- a/crates/factor-outbound-http/src/lib.rs +++ b/crates/factor-outbound-http/src/lib.rs @@ -31,6 +31,8 @@ pub use wasmtime_wasi_http::{ HttpResult, }; +pub use wasi::{p2_to_p3_error_code, p3_to_p2_error_code}; + #[derive(Default)] pub struct OutboundHttpFactor { _priv: (), diff --git a/crates/factor-outbound-http/src/wasi.rs b/crates/factor-outbound-http/src/wasi.rs index 756799adf3..2e75bdb9e5 100644 --- a/crates/factor-outbound-http/src/wasi.rs +++ b/crates/factor-outbound-http/src/wasi.rs @@ -5,12 +5,14 @@ use std::{ net::SocketAddr, pin::Pin, sync::Arc, - task::{Context, Poll}, + task::{self, Context, Poll}, time::Duration, }; -use http::{header::HOST, Uri}; -use http_body_util::BodyExt; +use bytes::Bytes; +use http::{header::HOST, uri::Scheme, Uri}; +use http_body::{Body, Frame, SizeHint}; +use http_body_util::{combinators::BoxBody, BodyExt}; use hyper_util::{ client::legacy::{ connect::{Connected, Connection}, @@ -32,9 +34,11 @@ use tokio_rustls::client::TlsStream; use tower_service::Service; use tracing::{field::Empty, instrument, Instrument}; use wasmtime::component::HasData; +use wasmtime_wasi::TrappableError; use wasmtime_wasi_http::{ - bindings::http::types::ErrorCode, + bindings::http::types::{self as p2_types, ErrorCode}, body::HyperOutgoingBody, + p3::{self, bindings::http::types as p3_types}, types::{HostFutureIncomingResponse, IncomingResponse, OutgoingRequestConfig}, HttpError, WasiHttpCtx, WasiHttpImpl, WasiHttpView, }; @@ -44,16 +48,147 @@ use crate::{ wasi_2023_10_18, wasi_2023_11_10, InstanceState, OutboundHttpFactor, SelfRequestOrigin, }; +const DEFAULT_TIMEOUT: Duration = Duration::from_secs(600); + pub(crate) struct HasHttp; impl HasData for HasHttp { type Data<'a> = WasiHttpImpl>; } +impl p3::WasiHttpCtx for InstanceState { + fn send_request( + &mut self, + request: http::Request>, + options: Option, + fut: Box> + Send>, + ) -> Box< + dyn Future< + Output = Result< + ( + http::Response>, + Box> + Send>, + ), + TrappableError, + >, + > + Send, + > { + // If the caller (i.e. the guest) has trouble consuming the response + // (e.g. encountering a network error while forwarding it on to some + // other place), it can report that error to us via `fut`. However, + // there's nothing we'll be able to do with it here, so we ignore it. + // Presumably the guest will also drop the body stream and trailers + // future if it encounters such an error while those things are still + // arriving, which Hyper will deal with as appropriate (e.g. closing the + // connection). + _ = fut; + + let request_sender = RequestSender { + allowed_hosts: self.allowed_hosts.clone(), + component_tls_configs: self.component_tls_configs.clone(), + request_interceptor: self.request_interceptor.clone(), + self_request_origin: self.self_request_origin.clone(), + blocked_networks: self.blocked_networks.clone(), + http_clients: self.wasi_http_clients.clone(), + }; + let config = OutgoingRequestConfig { + use_tls: request.uri().scheme() == Some(&Scheme::HTTPS), + connect_timeout: options + .and_then(|v| v.connect_timeout) + .unwrap_or(DEFAULT_TIMEOUT), + first_byte_timeout: options + .and_then(|v| v.first_byte_timeout) + .unwrap_or(DEFAULT_TIMEOUT), + between_bytes_timeout: options + .and_then(|v| v.between_bytes_timeout) + .unwrap_or(DEFAULT_TIMEOUT), + }; + Box::new(async { + match request_sender + .send( + request.map(|body| body.map_err(p3_to_p2_error_code).boxed()), + config, + ) + .await + { + Ok(IncomingResponse { + resp, + between_bytes_timeout, + .. + }) => Ok(( + resp.map(|body| { + BetweenBytesTimeoutBody { + body, + sleep: None, + timeout: between_bytes_timeout, + } + .boxed() + }), + Box::new(async { + // TODO: Can we plumb connection errors through to here, or + // will `hyper_util::client::legacy::Client` pass them all + // via the response body? + Ok(()) + }) as Box + Send>, + )), + Err(http_error) => match http_error.downcast() { + Ok(error_code) => Err(TrappableError::from(p2_to_p3_error_code(error_code))), + Err(trap) => Err(TrappableError::trap(trap)), + }, + } + }) + } +} + +pin_project_lite::pin_project! { + struct BetweenBytesTimeoutBody { + #[pin] + body: B, + #[pin] + sleep: Option, + timeout: Duration, + } +} + +impl> Body for BetweenBytesTimeoutBody { + type Data = B::Data; + type Error = p3_types::ErrorCode; + + fn poll_frame( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll, Self::Error>>> { + let mut me = self.project(); + match me.body.poll_frame(cx) { + Poll::Ready(value) => { + me.sleep.as_mut().set(None); + Poll::Ready(value.map(|v| v.map_err(p2_to_p3_error_code))) + } + Poll::Pending => { + if me.sleep.is_none() { + me.sleep.as_mut().set(Some(tokio::time::sleep(*me.timeout))); + } + task::ready!(me.sleep.as_pin_mut().unwrap().poll(cx)); + Poll::Ready(Some(Err(p3_types::ErrorCode::ConnectionReadTimeout))) + } + } + } + + fn is_end_stream(&self) -> bool { + self.body.is_end_stream() + } + + fn size_hint(&self) -> SizeHint { + self.body.size_hint() + } +} + pub(crate) fn add_to_linker(ctx: &mut C) -> anyhow::Result<()> where C: spin_factors::InitContext, { + let linker = ctx.linker(); + fn get_http(store: &mut C::StoreData) -> WasiHttpImpl> where C: spin_factors::InitContext, @@ -61,8 +196,8 @@ where let (state, table) = C::get_data_with_table(store); WasiHttpImpl(WasiHttpImplInner { state, table }) } + let get_http = get_http:: as fn(&mut C::StoreData) -> WasiHttpImpl>; - let linker = ctx.linker(); wasmtime_wasi_http::bindings::http::outgoing_handler::add_to_linker::<_, HasHttp>( linker, get_http, )?; @@ -72,6 +207,18 @@ where get_http, )?; + fn get_http_p3(store: &mut C::StoreData) -> p3::WasiHttpCtxView<'_> + where + C: spin_factors::InitContext, + { + let (state, table) = C::get_data_with_table(store); + p3::WasiHttpCtxView { ctx: state, table } + } + + let get_http_p3 = get_http_p3:: as fn(&mut C::StoreData) -> p3::WasiHttpCtxView<'_>; + p3::bindings::http::handler::add_to_linker::<_, p3::WasiHttp>(linker, get_http_p3)?; + p3::bindings::http::types::add_to_linker::<_, p3::WasiHttp>(linker, get_http_p3)?; + wasi_2023_10_18::add_to_linker(linker, get_http)?; wasi_2023_11_10::add_to_linker(linker, get_http)?; @@ -85,6 +232,13 @@ impl OutboundHttpFactor { let (state, table) = runtime_instance_state.get_with_table::()?; Some(WasiHttpImpl(WasiHttpImplInner { state, table })) } + + pub fn get_wasi_p3_http_impl( + runtime_instance_state: &mut impl RuntimeFactorsInstanceState, + ) -> Option> { + let (state, table) = runtime_instance_state.get_with_table::()?; + Some(p3::WasiHttpCtxView { ctx: state, table }) + } } pub(crate) struct WasiHttpImplInner<'a> { @@ -590,3 +744,207 @@ fn dns_error(rcode: String, info_code: u16) -> ErrorCode { info_code: Some(info_code), }) } + +// TODO: Remove this (and uses of it) once +// https://github.com/spinframework/spin/issues/3274 has been addressed. +pub fn p2_to_p3_error_code(code: p2_types::ErrorCode) -> p3_types::ErrorCode { + match code { + p2_types::ErrorCode::DnsTimeout => p3_types::ErrorCode::DnsTimeout, + p2_types::ErrorCode::DnsError(payload) => { + p3_types::ErrorCode::DnsError(p3_types::DnsErrorPayload { + rcode: payload.rcode, + info_code: payload.info_code, + }) + } + p2_types::ErrorCode::DestinationNotFound => p3_types::ErrorCode::DestinationNotFound, + p2_types::ErrorCode::DestinationUnavailable => p3_types::ErrorCode::DestinationUnavailable, + p2_types::ErrorCode::DestinationIpProhibited => { + p3_types::ErrorCode::DestinationIpProhibited + } + p2_types::ErrorCode::DestinationIpUnroutable => { + p3_types::ErrorCode::DestinationIpUnroutable + } + p2_types::ErrorCode::ConnectionRefused => p3_types::ErrorCode::ConnectionRefused, + p2_types::ErrorCode::ConnectionTerminated => p3_types::ErrorCode::ConnectionTerminated, + p2_types::ErrorCode::ConnectionTimeout => p3_types::ErrorCode::ConnectionTimeout, + p2_types::ErrorCode::ConnectionReadTimeout => p3_types::ErrorCode::ConnectionReadTimeout, + p2_types::ErrorCode::ConnectionWriteTimeout => p3_types::ErrorCode::ConnectionWriteTimeout, + p2_types::ErrorCode::ConnectionLimitReached => p3_types::ErrorCode::ConnectionLimitReached, + p2_types::ErrorCode::TlsProtocolError => p3_types::ErrorCode::TlsProtocolError, + p2_types::ErrorCode::TlsCertificateError => p3_types::ErrorCode::TlsCertificateError, + p2_types::ErrorCode::TlsAlertReceived(payload) => { + p3_types::ErrorCode::TlsAlertReceived(p3_types::TlsAlertReceivedPayload { + alert_id: payload.alert_id, + alert_message: payload.alert_message, + }) + } + p2_types::ErrorCode::HttpRequestDenied => p3_types::ErrorCode::HttpRequestDenied, + p2_types::ErrorCode::HttpRequestLengthRequired => { + p3_types::ErrorCode::HttpRequestLengthRequired + } + p2_types::ErrorCode::HttpRequestBodySize(payload) => { + p3_types::ErrorCode::HttpRequestBodySize(payload) + } + p2_types::ErrorCode::HttpRequestMethodInvalid => { + p3_types::ErrorCode::HttpRequestMethodInvalid + } + p2_types::ErrorCode::HttpRequestUriInvalid => p3_types::ErrorCode::HttpRequestUriInvalid, + p2_types::ErrorCode::HttpRequestUriTooLong => p3_types::ErrorCode::HttpRequestUriTooLong, + p2_types::ErrorCode::HttpRequestHeaderSectionSize(payload) => { + p3_types::ErrorCode::HttpRequestHeaderSectionSize(payload) + } + p2_types::ErrorCode::HttpRequestHeaderSize(payload) => { + p3_types::ErrorCode::HttpRequestHeaderSize(payload.map(|payload| { + p3_types::FieldSizePayload { + field_name: payload.field_name, + field_size: payload.field_size, + } + })) + } + p2_types::ErrorCode::HttpRequestTrailerSectionSize(payload) => { + p3_types::ErrorCode::HttpRequestTrailerSectionSize(payload) + } + p2_types::ErrorCode::HttpRequestTrailerSize(payload) => { + p3_types::ErrorCode::HttpRequestTrailerSize(p3_types::FieldSizePayload { + field_name: payload.field_name, + field_size: payload.field_size, + }) + } + p2_types::ErrorCode::HttpResponseIncomplete => p3_types::ErrorCode::HttpResponseIncomplete, + p2_types::ErrorCode::HttpResponseHeaderSectionSize(payload) => { + p3_types::ErrorCode::HttpResponseHeaderSectionSize(payload) + } + p2_types::ErrorCode::HttpResponseHeaderSize(payload) => { + p3_types::ErrorCode::HttpResponseHeaderSize(p3_types::FieldSizePayload { + field_name: payload.field_name, + field_size: payload.field_size, + }) + } + p2_types::ErrorCode::HttpResponseBodySize(payload) => { + p3_types::ErrorCode::HttpResponseBodySize(payload) + } + p2_types::ErrorCode::HttpResponseTrailerSectionSize(payload) => { + p3_types::ErrorCode::HttpResponseTrailerSectionSize(payload) + } + p2_types::ErrorCode::HttpResponseTrailerSize(payload) => { + p3_types::ErrorCode::HttpResponseTrailerSize(p3_types::FieldSizePayload { + field_name: payload.field_name, + field_size: payload.field_size, + }) + } + p2_types::ErrorCode::HttpResponseTransferCoding(payload) => { + p3_types::ErrorCode::HttpResponseTransferCoding(payload) + } + p2_types::ErrorCode::HttpResponseContentCoding(payload) => { + p3_types::ErrorCode::HttpResponseContentCoding(payload) + } + p2_types::ErrorCode::HttpResponseTimeout => p3_types::ErrorCode::HttpResponseTimeout, + p2_types::ErrorCode::HttpUpgradeFailed => p3_types::ErrorCode::HttpUpgradeFailed, + p2_types::ErrorCode::HttpProtocolError => p3_types::ErrorCode::HttpProtocolError, + p2_types::ErrorCode::LoopDetected => p3_types::ErrorCode::LoopDetected, + p2_types::ErrorCode::ConfigurationError => p3_types::ErrorCode::ConfigurationError, + p2_types::ErrorCode::InternalError(payload) => p3_types::ErrorCode::InternalError(payload), + } +} + +// TODO: Remove this (and uses of it) once +// https://github.com/spinframework/spin/issues/3274 has been addressed. +pub fn p3_to_p2_error_code(code: p3_types::ErrorCode) -> p2_types::ErrorCode { + match code { + p3_types::ErrorCode::DnsTimeout => p2_types::ErrorCode::DnsTimeout, + p3_types::ErrorCode::DnsError(payload) => { + p2_types::ErrorCode::DnsError(p2_types::DnsErrorPayload { + rcode: payload.rcode, + info_code: payload.info_code, + }) + } + p3_types::ErrorCode::DestinationNotFound => p2_types::ErrorCode::DestinationNotFound, + p3_types::ErrorCode::DestinationUnavailable => p2_types::ErrorCode::DestinationUnavailable, + p3_types::ErrorCode::DestinationIpProhibited => { + p2_types::ErrorCode::DestinationIpProhibited + } + p3_types::ErrorCode::DestinationIpUnroutable => { + p2_types::ErrorCode::DestinationIpUnroutable + } + p3_types::ErrorCode::ConnectionRefused => p2_types::ErrorCode::ConnectionRefused, + p3_types::ErrorCode::ConnectionTerminated => p2_types::ErrorCode::ConnectionTerminated, + p3_types::ErrorCode::ConnectionTimeout => p2_types::ErrorCode::ConnectionTimeout, + p3_types::ErrorCode::ConnectionReadTimeout => p2_types::ErrorCode::ConnectionReadTimeout, + p3_types::ErrorCode::ConnectionWriteTimeout => p2_types::ErrorCode::ConnectionWriteTimeout, + p3_types::ErrorCode::ConnectionLimitReached => p2_types::ErrorCode::ConnectionLimitReached, + p3_types::ErrorCode::TlsProtocolError => p2_types::ErrorCode::TlsProtocolError, + p3_types::ErrorCode::TlsCertificateError => p2_types::ErrorCode::TlsCertificateError, + p3_types::ErrorCode::TlsAlertReceived(payload) => { + p2_types::ErrorCode::TlsAlertReceived(p2_types::TlsAlertReceivedPayload { + alert_id: payload.alert_id, + alert_message: payload.alert_message, + }) + } + p3_types::ErrorCode::HttpRequestDenied => p2_types::ErrorCode::HttpRequestDenied, + p3_types::ErrorCode::HttpRequestLengthRequired => { + p2_types::ErrorCode::HttpRequestLengthRequired + } + p3_types::ErrorCode::HttpRequestBodySize(payload) => { + p2_types::ErrorCode::HttpRequestBodySize(payload) + } + p3_types::ErrorCode::HttpRequestMethodInvalid => { + p2_types::ErrorCode::HttpRequestMethodInvalid + } + p3_types::ErrorCode::HttpRequestUriInvalid => p2_types::ErrorCode::HttpRequestUriInvalid, + p3_types::ErrorCode::HttpRequestUriTooLong => p2_types::ErrorCode::HttpRequestUriTooLong, + p3_types::ErrorCode::HttpRequestHeaderSectionSize(payload) => { + p2_types::ErrorCode::HttpRequestHeaderSectionSize(payload) + } + p3_types::ErrorCode::HttpRequestHeaderSize(payload) => { + p2_types::ErrorCode::HttpRequestHeaderSize(payload.map(|payload| { + p2_types::FieldSizePayload { + field_name: payload.field_name, + field_size: payload.field_size, + } + })) + } + p3_types::ErrorCode::HttpRequestTrailerSectionSize(payload) => { + p2_types::ErrorCode::HttpRequestTrailerSectionSize(payload) + } + p3_types::ErrorCode::HttpRequestTrailerSize(payload) => { + p2_types::ErrorCode::HttpRequestTrailerSize(p2_types::FieldSizePayload { + field_name: payload.field_name, + field_size: payload.field_size, + }) + } + p3_types::ErrorCode::HttpResponseIncomplete => p2_types::ErrorCode::HttpResponseIncomplete, + p3_types::ErrorCode::HttpResponseHeaderSectionSize(payload) => { + p2_types::ErrorCode::HttpResponseHeaderSectionSize(payload) + } + p3_types::ErrorCode::HttpResponseHeaderSize(payload) => { + p2_types::ErrorCode::HttpResponseHeaderSize(p2_types::FieldSizePayload { + field_name: payload.field_name, + field_size: payload.field_size, + }) + } + p3_types::ErrorCode::HttpResponseBodySize(payload) => { + p2_types::ErrorCode::HttpResponseBodySize(payload) + } + p3_types::ErrorCode::HttpResponseTrailerSectionSize(payload) => { + p2_types::ErrorCode::HttpResponseTrailerSectionSize(payload) + } + p3_types::ErrorCode::HttpResponseTrailerSize(payload) => { + p2_types::ErrorCode::HttpResponseTrailerSize(p2_types::FieldSizePayload { + field_name: payload.field_name, + field_size: payload.field_size, + }) + } + p3_types::ErrorCode::HttpResponseTransferCoding(payload) => { + p2_types::ErrorCode::HttpResponseTransferCoding(payload) + } + p3_types::ErrorCode::HttpResponseContentCoding(payload) => { + p2_types::ErrorCode::HttpResponseContentCoding(payload) + } + p3_types::ErrorCode::HttpResponseTimeout => p2_types::ErrorCode::HttpResponseTimeout, + p3_types::ErrorCode::HttpUpgradeFailed => p2_types::ErrorCode::HttpUpgradeFailed, + p3_types::ErrorCode::HttpProtocolError => p2_types::ErrorCode::HttpProtocolError, + p3_types::ErrorCode::LoopDetected => p2_types::ErrorCode::LoopDetected, + p3_types::ErrorCode::ConfigurationError => p2_types::ErrorCode::ConfigurationError, + p3_types::ErrorCode::InternalError(payload) => p2_types::ErrorCode::InternalError(payload), + } +} diff --git a/crates/factor-outbound-networking/tests/factor_test.rs b/crates/factor-outbound-networking/tests/factor_test.rs index 7c7120599b..4918d70ff4 100644 --- a/crates/factor-outbound-networking/tests/factor_test.rs +++ b/crates/factor-outbound-networking/tests/factor_test.rs @@ -5,7 +5,7 @@ use spin_factor_wasi::{DummyFilesMounter, WasiFactor}; use spin_factors::{anyhow, RuntimeFactors}; use spin_factors_test::{toml, TestEnvironment}; use wasmtime_wasi::p2::bindings::sockets::instance_network::Host; -use wasmtime_wasi::SocketAddrUse; +use wasmtime_wasi::sockets::SocketAddrUse; #[derive(RuntimeFactors)] struct TestFactors { @@ -35,10 +35,10 @@ async fn configures_wasi_socket_addr_check() -> anyhow::Result<()> { ..Default::default() })?; let mut state = env.build_instance_state().await?; - let mut wasi = WasiFactor::get_wasi_impl(&mut state).unwrap(); + let mut sockets = WasiFactor::get_sockets_impl(&mut state).unwrap(); - let network_resource = wasi.instance_network()?; - let network = wasi.table.get(&network_resource)?; + let network_resource = sockets.instance_network()?; + let network = sockets.table.get(&network_resource)?; network .check_socket_addr( diff --git a/crates/factor-wasi/src/lib.rs b/crates/factor-wasi/src/lib.rs index e4a5c3e62a..e67564c4f1 100644 --- a/crates/factor-wasi/src/lib.rs +++ b/crates/factor-wasi/src/lib.rs @@ -16,11 +16,14 @@ use spin_factors::{ RuntimeFactors, RuntimeFactorsInstanceState, }; use wasmtime::component::HasData; -use wasmtime_wasi::cli::{StdinStream, StdoutStream}; -use wasmtime_wasi::random::WasiRandomCtx; +use wasmtime_wasi::cli::{StdinStream, StdoutStream, WasiCli, WasiCliCtxView}; +use wasmtime_wasi::clocks::{WasiClocks, WasiClocksCtxView}; +use wasmtime_wasi::filesystem::{WasiFilesystem, WasiFilesystemCtxView}; +use wasmtime_wasi::random::{WasiRandom, WasiRandomCtx}; +use wasmtime_wasi::sockets::{WasiSockets, WasiSocketsCtxView}; use wasmtime_wasi::{DirPerms, FilePerms, ResourceTable, WasiCtx, WasiCtxBuilder, WasiCtxView}; -pub use wasmtime_wasi::SocketAddrUse; +pub use wasmtime_wasi::sockets::SocketAddrUse; pub struct WasiFactor { files_mounter: Box, @@ -42,6 +45,26 @@ impl WasiFactor { table, }) } + + pub fn get_cli_impl( + runtime_instance_state: &mut impl RuntimeFactorsInstanceState, + ) -> Option> { + let (state, table) = runtime_instance_state.get_with_table::()?; + Some(WasiCliCtxView { + ctx: state.ctx.cli(), + table, + }) + } + + pub fn get_sockets_impl( + runtime_instance_state: &mut impl RuntimeFactorsInstanceState, + ) -> Option> { + let (state, table) = runtime_instance_state.get_with_table::()?; + Some(WasiSocketsCtxView { + ctx: state.ctx.sockets(), + table, + }) + } } /// Helper trait to extend `InitContext` with some more `link_*_bindings` @@ -54,46 +77,113 @@ trait InitContextExt: InitContext { table } - fn link_io_bindings( + fn get_clocks(data: &mut Self::StoreData) -> WasiClocksCtxView<'_> { + let (state, table) = Self::get_data_with_table(data); + WasiClocksCtxView { + ctx: state.ctx.clocks(), + table, + } + } + + fn get_random(data: &mut Self::StoreData) -> &mut WasiRandomCtx { + let (state, _) = Self::get_data_with_table(data); + state.ctx.random() + } + + fn link_clocks_bindings( &mut self, add_to_linker: fn( &mut wasmtime::component::Linker, - fn(&mut Self::StoreData) -> &mut ResourceTable, + fn(&mut Self::StoreData) -> WasiClocksCtxView<'_>, ) -> anyhow::Result<()>, ) -> anyhow::Result<()> { - add_to_linker(self.linker(), Self::get_table) + add_to_linker(self.linker(), Self::get_clocks) } - fn get_wasi(data: &mut Self::StoreData) -> WasiCtxView<'_> { + fn get_cli(data: &mut Self::StoreData) -> WasiCliCtxView<'_> { let (state, table) = Self::get_data_with_table(data); - WasiCtxView { - ctx: &mut state.ctx, + WasiCliCtxView { + ctx: state.ctx.cli(), table, } } - fn link_wasi_bindings( + fn link_cli_bindings( &mut self, add_to_linker: fn( &mut wasmtime::component::Linker, - fn(&mut Self::StoreData) -> WasiCtxView<'_>, + fn(&mut Self::StoreData) -> WasiCliCtxView<'_>, ) -> anyhow::Result<()>, ) -> anyhow::Result<()> { - add_to_linker(self.linker(), Self::get_wasi) + add_to_linker(self.linker(), Self::get_cli) } - fn link_wasi_default_bindings( + fn link_cli_default_bindings( &mut self, add_to_linker: fn( &mut wasmtime::component::Linker, &O, - fn(&mut Self::StoreData) -> WasiCtxView<'_>, + fn(&mut Self::StoreData) -> WasiCliCtxView<'_>, ) -> anyhow::Result<()>, - ) -> anyhow::Result<()> - where - O: Default, - { - add_to_linker(self.linker(), &O::default(), Self::get_wasi) + ) -> anyhow::Result<()> { + add_to_linker(self.linker(), &O::default(), Self::get_cli) + } + + fn get_filesystem(data: &mut Self::StoreData) -> WasiFilesystemCtxView<'_> { + let (state, table) = Self::get_data_with_table(data); + WasiFilesystemCtxView { + ctx: state.ctx.filesystem(), + table, + } + } + + fn link_filesystem_bindings( + &mut self, + add_to_linker: fn( + &mut wasmtime::component::Linker, + fn(&mut Self::StoreData) -> WasiFilesystemCtxView<'_>, + ) -> anyhow::Result<()>, + ) -> anyhow::Result<()> { + add_to_linker(self.linker(), Self::get_filesystem) + } + + fn get_sockets(data: &mut Self::StoreData) -> WasiSocketsCtxView<'_> { + let (state, table) = Self::get_data_with_table(data); + WasiSocketsCtxView { + ctx: state.ctx.sockets(), + table, + } + } + + fn link_sockets_bindings( + &mut self, + add_to_linker: fn( + &mut wasmtime::component::Linker, + fn(&mut Self::StoreData) -> WasiSocketsCtxView<'_>, + ) -> anyhow::Result<()>, + ) -> anyhow::Result<()> { + add_to_linker(self.linker(), Self::get_sockets) + } + + fn link_sockets_default_bindings( + &mut self, + add_to_linker: fn( + &mut wasmtime::component::Linker, + &O, + fn(&mut Self::StoreData) -> WasiSocketsCtxView<'_>, + ) -> anyhow::Result<()>, + ) -> anyhow::Result<()> { + add_to_linker(self.linker(), &O::default(), Self::get_sockets) + } + + fn link_io_bindings( + &mut self, + add_to_linker: fn( + &mut wasmtime::component::Linker, + fn(&mut Self::StoreData) -> &mut ResourceTable, + ) -> anyhow::Result<()>, + ) -> anyhow::Result<()> { + add_to_linker(self.linker(), Self::get_table) } fn link_random_bindings( @@ -108,66 +198,124 @@ trait InitContextExt: InitContext { state.ctx.random() }) } + + fn link_all_bindings( + &mut self, + add_to_linker: fn( + &mut wasmtime::component::Linker, + fn(&mut Self::StoreData) -> &mut ResourceTable, + fn(&mut Self::StoreData) -> &mut WasiRandomCtx, + fn(&mut Self::StoreData) -> WasiClocksCtxView<'_>, + fn(&mut Self::StoreData) -> WasiCliCtxView<'_>, + fn(&mut Self::StoreData) -> WasiFilesystemCtxView<'_>, + fn(&mut Self::StoreData) -> WasiSocketsCtxView<'_>, + ) -> anyhow::Result<()>, + ) -> anyhow::Result<()> { + add_to_linker( + self.linker(), + Self::get_table, + Self::get_random, + Self::get_clocks, + Self::get_cli, + Self::get_filesystem, + Self::get_sockets, + ) + } } impl InitContextExt for T where T: InitContext {} -struct HasWasi; - -impl HasData for HasWasi { - type Data<'a> = WasiCtxView<'a>; -} - struct HasIo; impl HasData for HasIo { type Data<'a> = &'a mut ResourceTable; } -struct HasRandom; - -impl HasData for HasRandom { - type Data<'a> = &'a mut WasiRandomCtx; -} - impl Factor for WasiFactor { type RuntimeConfig = (); type AppState = (); type InstanceBuilder = InstanceBuilder; fn init(&mut self, ctx: &mut impl InitContext) -> anyhow::Result<()> { - use wasmtime_wasi::p2::bindings; - - ctx.link_wasi_bindings(bindings::clocks::wall_clock::add_to_linker::<_, HasWasi>)?; - ctx.link_wasi_bindings(bindings::clocks::monotonic_clock::add_to_linker::<_, HasWasi>)?; - ctx.link_wasi_bindings(bindings::filesystem::types::add_to_linker::<_, HasWasi>)?; - ctx.link_wasi_bindings(bindings::filesystem::preopens::add_to_linker::<_, HasWasi>)?; - ctx.link_io_bindings(bindings::io::error::add_to_linker::<_, HasIo>)?; - ctx.link_io_bindings(bindings::io::poll::add_to_linker::<_, HasIo>)?; - ctx.link_io_bindings(bindings::io::streams::add_to_linker::<_, HasIo>)?; - ctx.link_random_bindings(bindings::random::random::add_to_linker::<_, HasRandom>)?; - ctx.link_random_bindings(bindings::random::insecure::add_to_linker::<_, HasRandom>)?; - ctx.link_random_bindings(bindings::random::insecure_seed::add_to_linker::<_, HasRandom>)?; - ctx.link_wasi_default_bindings(bindings::cli::exit::add_to_linker::<_, HasWasi>)?; - ctx.link_wasi_bindings(bindings::cli::environment::add_to_linker::<_, HasWasi>)?; - ctx.link_wasi_bindings(bindings::cli::stdin::add_to_linker::<_, HasWasi>)?; - ctx.link_wasi_bindings(bindings::cli::stdout::add_to_linker::<_, HasWasi>)?; - ctx.link_wasi_bindings(bindings::cli::stderr::add_to_linker::<_, HasWasi>)?; - ctx.link_wasi_bindings(bindings::cli::terminal_input::add_to_linker::<_, HasWasi>)?; - ctx.link_wasi_bindings(bindings::cli::terminal_output::add_to_linker::<_, HasWasi>)?; - ctx.link_wasi_bindings(bindings::cli::terminal_stdin::add_to_linker::<_, HasWasi>)?; - ctx.link_wasi_bindings(bindings::cli::terminal_stdout::add_to_linker::<_, HasWasi>)?; - ctx.link_wasi_bindings(bindings::cli::terminal_stderr::add_to_linker::<_, HasWasi>)?; - ctx.link_wasi_bindings(bindings::sockets::tcp::add_to_linker::<_, HasWasi>)?; - ctx.link_wasi_bindings(bindings::sockets::tcp_create_socket::add_to_linker::<_, HasWasi>)?; - ctx.link_wasi_bindings(bindings::sockets::udp::add_to_linker::<_, HasWasi>)?; - ctx.link_wasi_bindings(bindings::sockets::udp_create_socket::add_to_linker::<_, HasWasi>)?; - ctx.link_wasi_bindings(bindings::sockets::instance_network::add_to_linker::<_, HasWasi>)?; - ctx.link_wasi_default_bindings(bindings::sockets::network::add_to_linker::<_, HasWasi>)?; - ctx.link_wasi_bindings(bindings::sockets::ip_name_lookup::add_to_linker::<_, HasWasi>)?; - - ctx.link_wasi_bindings(wasi_2023_10_18::add_to_linker)?; - ctx.link_wasi_bindings(wasi_2023_11_10::add_to_linker)?; + use wasmtime_wasi::{p2, p3}; + + ctx.link_clocks_bindings(p2::bindings::clocks::wall_clock::add_to_linker::<_, WasiClocks>)?; + ctx.link_clocks_bindings(p3::bindings::clocks::wall_clock::add_to_linker::<_, WasiClocks>)?; + ctx.link_clocks_bindings( + p2::bindings::clocks::monotonic_clock::add_to_linker::<_, WasiClocks>, + )?; + ctx.link_clocks_bindings( + p3::bindings::clocks::monotonic_clock::add_to_linker::<_, WasiClocks>, + )?; + ctx.link_filesystem_bindings( + p2::bindings::filesystem::types::add_to_linker::<_, WasiFilesystem>, + )?; + ctx.link_filesystem_bindings( + p3::bindings::filesystem::types::add_to_linker::<_, WasiFilesystem>, + )?; + ctx.link_filesystem_bindings( + p2::bindings::filesystem::preopens::add_to_linker::<_, WasiFilesystem>, + )?; + ctx.link_filesystem_bindings( + p3::bindings::filesystem::preopens::add_to_linker::<_, WasiFilesystem>, + )?; + ctx.link_io_bindings(p2::bindings::io::error::add_to_linker::<_, HasIo>)?; + ctx.link_io_bindings(p2::bindings::io::poll::add_to_linker::<_, HasIo>)?; + ctx.link_io_bindings(p2::bindings::io::streams::add_to_linker::<_, HasIo>)?; + ctx.link_random_bindings(p2::bindings::random::random::add_to_linker::<_, WasiRandom>)?; + ctx.link_random_bindings(p3::bindings::random::random::add_to_linker::<_, WasiRandom>)?; + ctx.link_random_bindings(p2::bindings::random::insecure::add_to_linker::<_, WasiRandom>)?; + ctx.link_random_bindings(p3::bindings::random::insecure::add_to_linker::<_, WasiRandom>)?; + ctx.link_random_bindings( + p2::bindings::random::insecure_seed::add_to_linker::<_, WasiRandom>, + )?; + ctx.link_random_bindings( + p3::bindings::random::insecure_seed::add_to_linker::<_, WasiRandom>, + )?; + ctx.link_cli_default_bindings(p2::bindings::cli::exit::add_to_linker::<_, WasiCli>)?; + ctx.link_cli_default_bindings(p3::bindings::cli::exit::add_to_linker::<_, WasiCli>)?; + ctx.link_cli_bindings(p2::bindings::cli::environment::add_to_linker::<_, WasiCli>)?; + ctx.link_cli_bindings(p3::bindings::cli::environment::add_to_linker::<_, WasiCli>)?; + ctx.link_cli_bindings(p2::bindings::cli::stdin::add_to_linker::<_, WasiCli>)?; + ctx.link_cli_bindings(p3::bindings::cli::stdin::add_to_linker::<_, WasiCli>)?; + ctx.link_cli_bindings(p2::bindings::cli::stdout::add_to_linker::<_, WasiCli>)?; + ctx.link_cli_bindings(p3::bindings::cli::stdout::add_to_linker::<_, WasiCli>)?; + ctx.link_cli_bindings(p2::bindings::cli::stderr::add_to_linker::<_, WasiCli>)?; + ctx.link_cli_bindings(p3::bindings::cli::stderr::add_to_linker::<_, WasiCli>)?; + ctx.link_cli_bindings(p2::bindings::cli::terminal_input::add_to_linker::<_, WasiCli>)?; + ctx.link_cli_bindings(p3::bindings::cli::terminal_input::add_to_linker::<_, WasiCli>)?; + ctx.link_cli_bindings(p2::bindings::cli::terminal_output::add_to_linker::<_, WasiCli>)?; + ctx.link_cli_bindings(p3::bindings::cli::terminal_output::add_to_linker::<_, WasiCli>)?; + ctx.link_cli_bindings(p2::bindings::cli::terminal_stdin::add_to_linker::<_, WasiCli>)?; + ctx.link_cli_bindings(p3::bindings::cli::terminal_stdin::add_to_linker::<_, WasiCli>)?; + ctx.link_cli_bindings(p2::bindings::cli::terminal_stdout::add_to_linker::<_, WasiCli>)?; + ctx.link_cli_bindings(p3::bindings::cli::terminal_stdout::add_to_linker::<_, WasiCli>)?; + ctx.link_cli_bindings(p2::bindings::cli::terminal_stderr::add_to_linker::<_, WasiCli>)?; + ctx.link_cli_bindings(p3::bindings::cli::terminal_stderr::add_to_linker::<_, WasiCli>)?; + ctx.link_sockets_bindings(p2::bindings::sockets::tcp::add_to_linker::<_, WasiSockets>)?; + ctx.link_sockets_bindings( + p2::bindings::sockets::tcp_create_socket::add_to_linker::<_, WasiSockets>, + )?; + ctx.link_sockets_bindings(p2::bindings::sockets::udp::add_to_linker::<_, WasiSockets>)?; + ctx.link_sockets_bindings( + p2::bindings::sockets::udp_create_socket::add_to_linker::<_, WasiSockets>, + )?; + ctx.link_sockets_bindings( + p2::bindings::sockets::instance_network::add_to_linker::<_, WasiSockets>, + )?; + ctx.link_sockets_default_bindings( + p2::bindings::sockets::network::add_to_linker::<_, WasiSockets>, + )?; + ctx.link_sockets_bindings( + p2::bindings::sockets::ip_name_lookup::add_to_linker::<_, WasiSockets>, + )?; + ctx.link_sockets_bindings( + p3::bindings::sockets::ip_name_lookup::add_to_linker::<_, WasiSockets>, + )?; + ctx.link_sockets_bindings(p3::bindings::sockets::types::add_to_linker::<_, WasiSockets>)?; + + ctx.link_all_bindings(wasi_2023_10_18::add_to_linker)?; + ctx.link_all_bindings(wasi_2023_11_10::add_to_linker)?; Ok(()) } @@ -333,13 +481,11 @@ impl InstanceBuilder { let check = check.clone(); Box::pin(async move { match addr_use { - wasmtime_wasi::SocketAddrUse::TcpBind => false, - wasmtime_wasi::SocketAddrUse::TcpConnect - | wasmtime_wasi::SocketAddrUse::UdpBind - | wasmtime_wasi::SocketAddrUse::UdpConnect - | wasmtime_wasi::SocketAddrUse::UdpOutgoingDatagram => { - check(addr, addr_use).await - } + SocketAddrUse::TcpBind => false, + SocketAddrUse::TcpConnect + | SocketAddrUse::UdpBind + | SocketAddrUse::UdpConnect + | SocketAddrUse::UdpOutgoingDatagram => check(addr, addr_use).await, } }) }); diff --git a/crates/factor-wasi/src/wasi_2023_10_18.rs b/crates/factor-wasi/src/wasi_2023_10_18.rs index cc3c338f51..d32032efdf 100644 --- a/crates/factor-wasi/src/wasi_2023_10_18.rs +++ b/crates/factor-wasi/src/wasi_2023_10_18.rs @@ -1,8 +1,13 @@ use spin_factors::anyhow::{self, Result}; use std::mem; -use wasmtime::component::{Linker, Resource}; +use wasmtime::component::{Linker, Resource, ResourceTable}; +use wasmtime_wasi::cli::{WasiCli, WasiCliCtxView}; +use wasmtime_wasi::clocks::{WasiClocks, WasiClocksCtxView}; +use wasmtime_wasi::filesystem::{WasiFilesystem, WasiFilesystemCtxView}; use wasmtime_wasi::p2::DynPollable; -use wasmtime_wasi::{TrappableError, WasiCtxView}; +use wasmtime_wasi::random::{WasiRandom, WasiRandomCtx}; +use wasmtime_wasi::sockets::{WasiSockets, WasiSocketsCtxView}; +use wasmtime_wasi::TrappableError; mod latest { pub use wasmtime_wasi::p2::bindings::*; @@ -112,45 +117,50 @@ use wasi::sockets::tcp::{ }; use wasi::sockets::udp::Datagram; -use crate::HasWasi; +use crate::HasIo; pub fn add_to_linker( linker: &mut Linker, - closure: fn(&mut T) -> WasiCtxView<'_>, + io_closure: fn(&mut T) -> &mut ResourceTable, + random_closure: fn(&mut T) -> &mut WasiRandomCtx, + clocks_closure: fn(&mut T) -> WasiClocksCtxView<'_>, + cli_closure: fn(&mut T) -> WasiCliCtxView<'_>, + filesystem_closure: fn(&mut T) -> WasiFilesystemCtxView<'_>, + sockets_closure: fn(&mut T) -> WasiSocketsCtxView<'_>, ) -> Result<()> where T: Send + 'static, { - wasi::clocks::monotonic_clock::add_to_linker::<_, HasWasi>(linker, closure)?; - wasi::clocks::wall_clock::add_to_linker::<_, HasWasi>(linker, closure)?; - wasi::filesystem::types::add_to_linker::<_, HasWasi>(linker, closure)?; - wasi::filesystem::preopens::add_to_linker::<_, HasWasi>(linker, closure)?; - wasi::io::poll::add_to_linker::<_, HasWasi>(linker, closure)?; - wasi::io::streams::add_to_linker::<_, HasWasi>(linker, closure)?; - wasi::random::random::add_to_linker::<_, HasWasi>(linker, closure)?; - wasi::random::insecure::add_to_linker::<_, HasWasi>(linker, closure)?; - wasi::random::insecure_seed::add_to_linker::<_, HasWasi>(linker, closure)?; - wasi::cli::exit::add_to_linker::<_, HasWasi>(linker, closure)?; - wasi::cli::environment::add_to_linker::<_, HasWasi>(linker, closure)?; - wasi::cli::stdin::add_to_linker::<_, HasWasi>(linker, closure)?; - wasi::cli::stdout::add_to_linker::<_, HasWasi>(linker, closure)?; - wasi::cli::stderr::add_to_linker::<_, HasWasi>(linker, closure)?; - wasi::cli::terminal_input::add_to_linker::<_, HasWasi>(linker, closure)?; - wasi::cli::terminal_output::add_to_linker::<_, HasWasi>(linker, closure)?; - wasi::cli::terminal_stdin::add_to_linker::<_, HasWasi>(linker, closure)?; - wasi::cli::terminal_stdout::add_to_linker::<_, HasWasi>(linker, closure)?; - wasi::cli::terminal_stderr::add_to_linker::<_, HasWasi>(linker, closure)?; - wasi::sockets::tcp::add_to_linker::<_, HasWasi>(linker, closure)?; - wasi::sockets::tcp_create_socket::add_to_linker::<_, HasWasi>(linker, closure)?; - wasi::sockets::udp::add_to_linker::<_, HasWasi>(linker, closure)?; - wasi::sockets::udp_create_socket::add_to_linker::<_, HasWasi>(linker, closure)?; - wasi::sockets::instance_network::add_to_linker::<_, HasWasi>(linker, closure)?; - wasi::sockets::network::add_to_linker::<_, HasWasi>(linker, closure)?; - wasi::sockets::ip_name_lookup::add_to_linker::<_, HasWasi>(linker, closure)?; + wasi::clocks::monotonic_clock::add_to_linker::<_, WasiClocks>(linker, clocks_closure)?; + wasi::clocks::wall_clock::add_to_linker::<_, WasiClocks>(linker, clocks_closure)?; + wasi::filesystem::types::add_to_linker::<_, WasiFilesystem>(linker, filesystem_closure)?; + wasi::filesystem::preopens::add_to_linker::<_, WasiFilesystem>(linker, filesystem_closure)?; + wasi::io::poll::add_to_linker::<_, HasIo>(linker, io_closure)?; + wasi::io::streams::add_to_linker::<_, HasIo>(linker, io_closure)?; + wasi::random::random::add_to_linker::<_, WasiRandom>(linker, random_closure)?; + wasi::random::insecure::add_to_linker::<_, WasiRandom>(linker, random_closure)?; + wasi::random::insecure_seed::add_to_linker::<_, WasiRandom>(linker, random_closure)?; + wasi::cli::exit::add_to_linker::<_, WasiCli>(linker, cli_closure)?; + wasi::cli::environment::add_to_linker::<_, WasiCli>(linker, cli_closure)?; + wasi::cli::stdin::add_to_linker::<_, WasiCli>(linker, cli_closure)?; + wasi::cli::stdout::add_to_linker::<_, WasiCli>(linker, cli_closure)?; + wasi::cli::stderr::add_to_linker::<_, WasiCli>(linker, cli_closure)?; + wasi::cli::terminal_input::add_to_linker::<_, WasiCli>(linker, cli_closure)?; + wasi::cli::terminal_output::add_to_linker::<_, WasiCli>(linker, cli_closure)?; + wasi::cli::terminal_stdin::add_to_linker::<_, WasiCli>(linker, cli_closure)?; + wasi::cli::terminal_stdout::add_to_linker::<_, WasiCli>(linker, cli_closure)?; + wasi::cli::terminal_stderr::add_to_linker::<_, WasiCli>(linker, cli_closure)?; + wasi::sockets::tcp::add_to_linker::<_, WasiSockets>(linker, sockets_closure)?; + wasi::sockets::tcp_create_socket::add_to_linker::<_, WasiSockets>(linker, sockets_closure)?; + wasi::sockets::udp::add_to_linker::<_, WasiSockets>(linker, sockets_closure)?; + wasi::sockets::udp_create_socket::add_to_linker::<_, WasiSockets>(linker, sockets_closure)?; + wasi::sockets::instance_network::add_to_linker::<_, WasiSockets>(linker, sockets_closure)?; + wasi::sockets::network::add_to_linker::<_, WasiSockets>(linker, sockets_closure)?; + wasi::sockets::ip_name_lookup::add_to_linker::<_, WasiSockets>(linker, sockets_closure)?; Ok(()) } -impl wasi::clocks::monotonic_clock::Host for WasiCtxView<'_> { +impl wasi::clocks::monotonic_clock::Host for WasiClocksCtxView<'_> { fn now(&mut self) -> wasmtime::Result { latest::clocks::monotonic_clock::Host::now(self) } @@ -172,7 +182,7 @@ impl wasi::clocks::monotonic_clock::Host for WasiCtxView<'_> { } } -impl wasi::clocks::wall_clock::Host for WasiCtxView<'_> { +impl wasi::clocks::wall_clock::Host for WasiClocksCtxView<'_> { fn now(&mut self) -> wasmtime::Result { Ok(latest::clocks::wall_clock::Host::now(self)?.into()) } @@ -182,7 +192,7 @@ impl wasi::clocks::wall_clock::Host for WasiCtxView<'_> { } } -impl wasi::filesystem::types::Host for WasiCtxView<'_> { +impl wasi::filesystem::types::Host for WasiFilesystemCtxView<'_> { fn filesystem_error_code( &mut self, err: Resource, @@ -191,7 +201,7 @@ impl wasi::filesystem::types::Host for WasiCtxView<'_> { } } -impl wasi::filesystem::types::HostDescriptor for WasiCtxView<'_> { +impl wasi::filesystem::types::HostDescriptor for WasiFilesystemCtxView<'_> { fn read_via_stream( &mut self, self_: Resource, @@ -585,7 +595,7 @@ impl wasi::filesystem::types::HostDescriptor for WasiCtxView<'_> { } } -impl wasi::filesystem::types::HostDirectoryEntryStream for WasiCtxView<'_> { +impl wasi::filesystem::types::HostDirectoryEntryStream for WasiFilesystemCtxView<'_> { async fn read_directory_entry( &mut self, self_: Resource, @@ -602,47 +612,47 @@ impl wasi::filesystem::types::HostDirectoryEntryStream for WasiCtxView<'_> { } } -impl wasi::filesystem::preopens::Host for WasiCtxView<'_> { +impl wasi::filesystem::preopens::Host for WasiFilesystemCtxView<'_> { fn get_directories(&mut self) -> wasmtime::Result, String)>> { latest::filesystem::preopens::Host::get_directories(self) } } -impl wasi::io::poll::Host for WasiCtxView<'_> { +impl wasi::io::poll::Host for ResourceTable { async fn poll_list(&mut self, list: Vec>) -> wasmtime::Result> { - latest::io::poll::Host::poll(self.table, list).await + latest::io::poll::Host::poll(self, list).await } async fn poll_one(&mut self, rep: Resource) -> wasmtime::Result<()> { - latest::io::poll::HostPollable::block(self.table, rep).await + latest::io::poll::HostPollable::block(self, rep).await } } -impl wasi::io::poll::HostPollable for WasiCtxView<'_> { +impl wasi::io::poll::HostPollable for ResourceTable { fn drop(&mut self, rep: Resource) -> wasmtime::Result<()> { - latest::io::poll::HostPollable::drop(self.table, rep) + latest::io::poll::HostPollable::drop(self, rep) } } -impl wasi::io::streams::Host for WasiCtxView<'_> {} +impl wasi::io::streams::Host for ResourceTable {} -impl wasi::io::streams::HostError for WasiCtxView<'_> { +impl wasi::io::streams::HostError for ResourceTable { fn to_debug_string(&mut self, self_: Resource) -> wasmtime::Result { - latest::io::error::HostError::to_debug_string(self.table, self_) + latest::io::error::HostError::to_debug_string(self, self_) } fn drop(&mut self, rep: Resource) -> wasmtime::Result<()> { - latest::io::error::HostError::drop(self.table, rep) + latest::io::error::HostError::drop(self, rep) } } -impl wasi::io::streams::HostInputStream for WasiCtxView<'_> { +impl wasi::io::streams::HostInputStream for ResourceTable { fn read( &mut self, self_: Resource, len: u64, ) -> wasmtime::Result, StreamError>> { - let result = latest::io::streams::HostInputStream::read(self.table, self_, len); + let result = latest::io::streams::HostInputStream::read(self, self_, len); convert_stream_result(self, result) } @@ -651,8 +661,7 @@ impl wasi::io::streams::HostInputStream for WasiCtxView<'_> { self_: Resource, len: u64, ) -> wasmtime::Result, StreamError>> { - let result = - latest::io::streams::HostInputStream::blocking_read(self.table, self_, len).await; + let result = latest::io::streams::HostInputStream::blocking_read(self, self_, len).await; convert_stream_result(self, result) } @@ -661,7 +670,7 @@ impl wasi::io::streams::HostInputStream for WasiCtxView<'_> { self_: Resource, len: u64, ) -> wasmtime::Result> { - let result = latest::io::streams::HostInputStream::skip(self.table, self_, len); + let result = latest::io::streams::HostInputStream::skip(self, self_, len); convert_stream_result(self, result) } @@ -670,8 +679,7 @@ impl wasi::io::streams::HostInputStream for WasiCtxView<'_> { self_: Resource, len: u64, ) -> wasmtime::Result> { - let result = - latest::io::streams::HostInputStream::blocking_skip(self.table, self_, len).await; + let result = latest::io::streams::HostInputStream::blocking_skip(self, self_, len).await; convert_stream_result(self, result) } @@ -679,20 +687,20 @@ impl wasi::io::streams::HostInputStream for WasiCtxView<'_> { &mut self, self_: Resource, ) -> wasmtime::Result> { - latest::io::streams::HostInputStream::subscribe(self.table, self_) + latest::io::streams::HostInputStream::subscribe(self, self_) } async fn drop(&mut self, rep: Resource) -> wasmtime::Result<()> { - latest::io::streams::HostInputStream::drop(self.table, rep).await + latest::io::streams::HostInputStream::drop(self, rep).await } } -impl wasi::io::streams::HostOutputStream for WasiCtxView<'_> { +impl wasi::io::streams::HostOutputStream for ResourceTable { fn check_write( &mut self, self_: Resource, ) -> wasmtime::Result> { - let result = latest::io::streams::HostOutputStream::check_write(self.table, self_); + let result = latest::io::streams::HostOutputStream::check_write(self, self_); convert_stream_result(self, result) } @@ -701,7 +709,7 @@ impl wasi::io::streams::HostOutputStream for WasiCtxView<'_> { self_: Resource, contents: Vec, ) -> wasmtime::Result> { - let result = latest::io::streams::HostOutputStream::write(self.table, self_, contents); + let result = latest::io::streams::HostOutputStream::write(self, self_, contents); convert_stream_result(self, result) } @@ -710,10 +718,9 @@ impl wasi::io::streams::HostOutputStream for WasiCtxView<'_> { self_: Resource, contents: Vec, ) -> wasmtime::Result> { - let result = latest::io::streams::HostOutputStream::blocking_write_and_flush( - self.table, self_, contents, - ) - .await; + let result = + latest::io::streams::HostOutputStream::blocking_write_and_flush(self, self_, contents) + .await; convert_stream_result(self, result) } @@ -721,7 +728,7 @@ impl wasi::io::streams::HostOutputStream for WasiCtxView<'_> { &mut self, self_: Resource, ) -> wasmtime::Result> { - let result = latest::io::streams::HostOutputStream::flush(self.table, self_); + let result = latest::io::streams::HostOutputStream::flush(self, self_); convert_stream_result(self, result) } @@ -729,7 +736,7 @@ impl wasi::io::streams::HostOutputStream for WasiCtxView<'_> { &mut self, self_: Resource, ) -> wasmtime::Result> { - let result = latest::io::streams::HostOutputStream::blocking_flush(self.table, self_).await; + let result = latest::io::streams::HostOutputStream::blocking_flush(self, self_).await; convert_stream_result(self, result) } @@ -737,7 +744,7 @@ impl wasi::io::streams::HostOutputStream for WasiCtxView<'_> { &mut self, self_: Resource, ) -> wasmtime::Result> { - latest::io::streams::HostOutputStream::subscribe(self.table, self_) + latest::io::streams::HostOutputStream::subscribe(self, self_) } fn write_zeroes( @@ -745,7 +752,7 @@ impl wasi::io::streams::HostOutputStream for WasiCtxView<'_> { self_: Resource, len: u64, ) -> wasmtime::Result> { - let result = latest::io::streams::HostOutputStream::write_zeroes(self.table, self_, len); + let result = latest::io::streams::HostOutputStream::write_zeroes(self, self_, len); convert_stream_result(self, result) } @@ -755,7 +762,7 @@ impl wasi::io::streams::HostOutputStream for WasiCtxView<'_> { len: u64, ) -> wasmtime::Result> { let result = latest::io::streams::HostOutputStream::blocking_write_zeroes_and_flush( - self.table, self_, len, + self, self_, len, ) .await; convert_stream_result(self, result) @@ -767,7 +774,7 @@ impl wasi::io::streams::HostOutputStream for WasiCtxView<'_> { src: Resource, len: u64, ) -> wasmtime::Result> { - let result = latest::io::streams::HostOutputStream::splice(self.table, self_, src, len); + let result = latest::io::streams::HostOutputStream::splice(self, self_, src, len); convert_stream_result(self, result) } @@ -778,8 +785,7 @@ impl wasi::io::streams::HostOutputStream for WasiCtxView<'_> { len: u64, ) -> wasmtime::Result> { let result = - latest::io::streams::HostOutputStream::blocking_splice(self.table, self_, src, len) - .await; + latest::io::streams::HostOutputStream::blocking_splice(self, self_, src, len).await; convert_stream_result(self, result) } @@ -792,43 +798,43 @@ impl wasi::io::streams::HostOutputStream for WasiCtxView<'_> { } async fn drop(&mut self, rep: Resource) -> wasmtime::Result<()> { - latest::io::streams::HostOutputStream::drop(self.table, rep).await + latest::io::streams::HostOutputStream::drop(self, rep).await } } -impl wasi::random::random::Host for WasiCtxView<'_> { +impl wasi::random::random::Host for WasiRandomCtx { fn get_random_bytes(&mut self, len: u64) -> wasmtime::Result> { - latest::random::random::Host::get_random_bytes(self.ctx.random(), len) + latest::random::random::Host::get_random_bytes(self, len) } fn get_random_u64(&mut self) -> wasmtime::Result { - latest::random::random::Host::get_random_u64(self.ctx.random()) + latest::random::random::Host::get_random_u64(self) } } -impl wasi::random::insecure::Host for WasiCtxView<'_> { +impl wasi::random::insecure::Host for WasiRandomCtx { fn get_insecure_random_bytes(&mut self, len: u64) -> wasmtime::Result> { - latest::random::insecure::Host::get_insecure_random_bytes(self.ctx.random(), len) + latest::random::insecure::Host::get_insecure_random_bytes(self, len) } fn get_insecure_random_u64(&mut self) -> wasmtime::Result { - latest::random::insecure::Host::get_insecure_random_u64(self.ctx.random()) + latest::random::insecure::Host::get_insecure_random_u64(self) } } -impl wasi::random::insecure_seed::Host for WasiCtxView<'_> { +impl wasi::random::insecure_seed::Host for WasiRandomCtx { fn insecure_seed(&mut self) -> wasmtime::Result<(u64, u64)> { - latest::random::insecure_seed::Host::insecure_seed(self.ctx.random()) + latest::random::insecure_seed::Host::insecure_seed(self) } } -impl wasi::cli::exit::Host for WasiCtxView<'_> { +impl wasi::cli::exit::Host for WasiCliCtxView<'_> { fn exit(&mut self, status: Result<(), ()>) -> wasmtime::Result<()> { latest::cli::exit::Host::exit(self, status) } } -impl wasi::cli::environment::Host for WasiCtxView<'_> { +impl wasi::cli::environment::Host for WasiCliCtxView<'_> { fn get_environment(&mut self) -> wasmtime::Result> { latest::cli::environment::Host::get_environment(self) } @@ -842,61 +848,61 @@ impl wasi::cli::environment::Host for WasiCtxView<'_> { } } -impl wasi::cli::stdin::Host for WasiCtxView<'_> { +impl wasi::cli::stdin::Host for WasiCliCtxView<'_> { fn get_stdin(&mut self) -> wasmtime::Result> { latest::cli::stdin::Host::get_stdin(self) } } -impl wasi::cli::stdout::Host for WasiCtxView<'_> { +impl wasi::cli::stdout::Host for WasiCliCtxView<'_> { fn get_stdout(&mut self) -> wasmtime::Result> { latest::cli::stdout::Host::get_stdout(self) } } -impl wasi::cli::stderr::Host for WasiCtxView<'_> { +impl wasi::cli::stderr::Host for WasiCliCtxView<'_> { fn get_stderr(&mut self) -> wasmtime::Result> { latest::cli::stderr::Host::get_stderr(self) } } -impl wasi::cli::terminal_stdin::Host for WasiCtxView<'_> { +impl wasi::cli::terminal_stdin::Host for WasiCliCtxView<'_> { fn get_terminal_stdin(&mut self) -> wasmtime::Result>> { latest::cli::terminal_stdin::Host::get_terminal_stdin(self) } } -impl wasi::cli::terminal_stdout::Host for WasiCtxView<'_> { +impl wasi::cli::terminal_stdout::Host for WasiCliCtxView<'_> { fn get_terminal_stdout(&mut self) -> wasmtime::Result>> { latest::cli::terminal_stdout::Host::get_terminal_stdout(self) } } -impl wasi::cli::terminal_stderr::Host for WasiCtxView<'_> { +impl wasi::cli::terminal_stderr::Host for WasiCliCtxView<'_> { fn get_terminal_stderr(&mut self) -> wasmtime::Result>> { latest::cli::terminal_stderr::Host::get_terminal_stderr(self) } } -impl wasi::cli::terminal_input::Host for WasiCtxView<'_> {} +impl wasi::cli::terminal_input::Host for WasiCliCtxView<'_> {} -impl wasi::cli::terminal_input::HostTerminalInput for WasiCtxView<'_> { +impl wasi::cli::terminal_input::HostTerminalInput for WasiCliCtxView<'_> { fn drop(&mut self, rep: Resource) -> wasmtime::Result<()> { latest::cli::terminal_input::HostTerminalInput::drop(self, rep) } } -impl wasi::cli::terminal_output::Host for WasiCtxView<'_> {} +impl wasi::cli::terminal_output::Host for WasiCliCtxView<'_> {} -impl wasi::cli::terminal_output::HostTerminalOutput for WasiCtxView<'_> { +impl wasi::cli::terminal_output::HostTerminalOutput for WasiCliCtxView<'_> { fn drop(&mut self, rep: Resource) -> wasmtime::Result<()> { latest::cli::terminal_output::HostTerminalOutput::drop(self, rep) } } -impl wasi::sockets::tcp::Host for WasiCtxView<'_> {} +impl wasi::sockets::tcp::Host for WasiSocketsCtxView<'_> {} -impl wasi::sockets::tcp::HostTcpSocket for WasiCtxView<'_> { +impl wasi::sockets::tcp::HostTcpSocket for WasiSocketsCtxView<'_> { async fn start_bind( &mut self, self_: Resource, @@ -1141,7 +1147,7 @@ impl wasi::sockets::tcp::HostTcpSocket for WasiCtxView<'_> { } } -impl wasi::sockets::tcp_create_socket::Host for WasiCtxView<'_> { +impl wasi::sockets::tcp_create_socket::Host for WasiSocketsCtxView<'_> { fn create_tcp_socket( &mut self, address_family: IpAddressFamily, @@ -1153,7 +1159,7 @@ impl wasi::sockets::tcp_create_socket::Host for WasiCtxView<'_> { } } -impl wasi::sockets::udp::Host for WasiCtxView<'_> {} +impl wasi::sockets::udp::Host for WasiSocketsCtxView<'_> {} /// Between the snapshot of WASI that this file is implementing and the current /// implementation of WASI UDP sockets were redesigned slightly to deal with @@ -1174,7 +1180,7 @@ pub enum UdpSocket { impl UdpSocket { async fn finish_connect( - table: &mut WasiCtxView<'_>, + table: &mut WasiSocketsCtxView<'_>, socket: &Resource, explicit: bool, ) -> wasmtime::Result> { @@ -1217,7 +1223,7 @@ impl UdpSocket { } } -impl wasi::sockets::udp::HostUdpSocket for WasiCtxView<'_> { +impl wasi::sockets::udp::HostUdpSocket for WasiSocketsCtxView<'_> { async fn start_bind( &mut self, self_: Resource, @@ -1474,7 +1480,7 @@ impl wasi::sockets::udp::HostUdpSocket for WasiCtxView<'_> { } } -impl wasi::sockets::udp_create_socket::Host for WasiCtxView<'_> { +impl wasi::sockets::udp_create_socket::Host for WasiSocketsCtxView<'_> { fn create_udp_socket( &mut self, address_family: IpAddressFamily, @@ -1492,21 +1498,21 @@ impl wasi::sockets::udp_create_socket::Host for WasiCtxView<'_> { } } -impl wasi::sockets::instance_network::Host for WasiCtxView<'_> { +impl wasi::sockets::instance_network::Host for WasiSocketsCtxView<'_> { fn instance_network(&mut self) -> wasmtime::Result> { latest::sockets::instance_network::Host::instance_network(self) } } -impl wasi::sockets::network::Host for WasiCtxView<'_> {} +impl wasi::sockets::network::Host for WasiSocketsCtxView<'_> {} -impl wasi::sockets::network::HostNetwork for WasiCtxView<'_> { +impl wasi::sockets::network::HostNetwork for WasiSocketsCtxView<'_> { fn drop(&mut self, rep: Resource) -> wasmtime::Result<()> { latest::sockets::network::HostNetwork::drop(self, rep) } } -impl wasi::sockets::ip_name_lookup::Host for WasiCtxView<'_> { +impl wasi::sockets::ip_name_lookup::Host for WasiSocketsCtxView<'_> { fn resolve_addresses( &mut self, network: Resource, @@ -1520,7 +1526,7 @@ impl wasi::sockets::ip_name_lookup::Host for WasiCtxView<'_> { } } -impl wasi::sockets::ip_name_lookup::HostResolveAddressStream for WasiCtxView<'_> { +impl wasi::sockets::ip_name_lookup::HostResolveAddressStream for WasiSocketsCtxView<'_> { fn resolve_next_address( &mut self, self_: Resource, @@ -1560,7 +1566,7 @@ where } fn convert_stream_result( - view: &mut WasiCtxView<'_>, + table: &mut ResourceTable, result: Result, ) -> wasmtime::Result> where @@ -1570,7 +1576,7 @@ where Ok(e) => Ok(Ok(e.into())), Err(wasmtime_wasi::p2::StreamError::Closed) => Ok(Err(StreamError::Closed)), Err(wasmtime_wasi::p2::StreamError::LastOperationFailed(e)) => { - let e = view.table.push(e)?; + let e = table.push(e)?; Ok(Err(StreamError::LastOperationFailed(e))) } Err(wasmtime_wasi::p2::StreamError::Trap(e)) => Err(e), diff --git a/crates/factor-wasi/src/wasi_2023_11_10.rs b/crates/factor-wasi/src/wasi_2023_11_10.rs index 50c59cddfa..6380427008 100644 --- a/crates/factor-wasi/src/wasi_2023_11_10.rs +++ b/crates/factor-wasi/src/wasi_2023_11_10.rs @@ -1,7 +1,11 @@ use super::wasi_2023_10_18::{convert, convert_result}; use spin_factors::anyhow::{self, Result}; -use wasmtime::component::{Linker, Resource}; -use wasmtime_wasi::WasiCtxView; +use wasmtime::component::{Linker, Resource, ResourceTable}; +use wasmtime_wasi::cli::{WasiCli, WasiCliCtxView}; +use wasmtime_wasi::clocks::{WasiClocks, WasiClocksCtxView}; +use wasmtime_wasi::filesystem::{WasiFilesystem, WasiFilesystemCtxView}; +use wasmtime_wasi::random::{WasiRandom, WasiRandomCtx}; +use wasmtime_wasi::sockets::{WasiSockets, WasiSocketsCtxView}; mod latest { pub use wasmtime_wasi::p2::bindings::*; @@ -106,46 +110,51 @@ use wasi::sockets::udp::{ IncomingDatagram, IncomingDatagramStream, OutgoingDatagram, OutgoingDatagramStream, UdpSocket, }; -use crate::HasWasi; +use crate::HasIo; pub fn add_to_linker( linker: &mut Linker, - closure: fn(&mut T) -> WasiCtxView<'_>, + io_closure: fn(&mut T) -> &mut ResourceTable, + random_closure: fn(&mut T) -> &mut WasiRandomCtx, + clocks_closure: fn(&mut T) -> WasiClocksCtxView<'_>, + cli_closure: fn(&mut T) -> WasiCliCtxView<'_>, + filesystem_closure: fn(&mut T) -> WasiFilesystemCtxView<'_>, + sockets_closure: fn(&mut T) -> WasiSocketsCtxView<'_>, ) -> Result<()> where T: Send + 'static, { - wasi::clocks::monotonic_clock::add_to_linker::<_, HasWasi>(linker, closure)?; - wasi::clocks::wall_clock::add_to_linker::<_, HasWasi>(linker, closure)?; - wasi::filesystem::types::add_to_linker::<_, HasWasi>(linker, closure)?; - wasi::filesystem::preopens::add_to_linker::<_, HasWasi>(linker, closure)?; - wasi::io::error::add_to_linker::<_, HasWasi>(linker, closure)?; - wasi::io::poll::add_to_linker::<_, HasWasi>(linker, closure)?; - wasi::io::streams::add_to_linker::<_, HasWasi>(linker, closure)?; - wasi::random::random::add_to_linker::<_, HasWasi>(linker, closure)?; - wasi::random::insecure::add_to_linker::<_, HasWasi>(linker, closure)?; - wasi::random::insecure_seed::add_to_linker::<_, HasWasi>(linker, closure)?; - wasi::cli::exit::add_to_linker::<_, HasWasi>(linker, closure)?; - wasi::cli::environment::add_to_linker::<_, HasWasi>(linker, closure)?; - wasi::cli::stdin::add_to_linker::<_, HasWasi>(linker, closure)?; - wasi::cli::stdout::add_to_linker::<_, HasWasi>(linker, closure)?; - wasi::cli::stderr::add_to_linker::<_, HasWasi>(linker, closure)?; - wasi::cli::terminal_input::add_to_linker::<_, HasWasi>(linker, closure)?; - wasi::cli::terminal_output::add_to_linker::<_, HasWasi>(linker, closure)?; - wasi::cli::terminal_stdin::add_to_linker::<_, HasWasi>(linker, closure)?; - wasi::cli::terminal_stdout::add_to_linker::<_, HasWasi>(linker, closure)?; - wasi::cli::terminal_stderr::add_to_linker::<_, HasWasi>(linker, closure)?; - wasi::sockets::tcp::add_to_linker::<_, HasWasi>(linker, closure)?; - wasi::sockets::tcp_create_socket::add_to_linker::<_, HasWasi>(linker, closure)?; - wasi::sockets::udp::add_to_linker::<_, HasWasi>(linker, closure)?; - wasi::sockets::udp_create_socket::add_to_linker::<_, HasWasi>(linker, closure)?; - wasi::sockets::instance_network::add_to_linker::<_, HasWasi>(linker, closure)?; - wasi::sockets::network::add_to_linker::<_, HasWasi>(linker, closure)?; - wasi::sockets::ip_name_lookup::add_to_linker::<_, HasWasi>(linker, closure)?; + wasi::clocks::monotonic_clock::add_to_linker::<_, WasiClocks>(linker, clocks_closure)?; + wasi::clocks::wall_clock::add_to_linker::<_, WasiClocks>(linker, clocks_closure)?; + wasi::filesystem::types::add_to_linker::<_, WasiFilesystem>(linker, filesystem_closure)?; + wasi::filesystem::preopens::add_to_linker::<_, WasiFilesystem>(linker, filesystem_closure)?; + wasi::io::error::add_to_linker::<_, HasIo>(linker, io_closure)?; + wasi::io::poll::add_to_linker::<_, HasIo>(linker, io_closure)?; + wasi::io::streams::add_to_linker::<_, HasIo>(linker, io_closure)?; + wasi::random::random::add_to_linker::<_, WasiRandom>(linker, random_closure)?; + wasi::random::insecure::add_to_linker::<_, WasiRandom>(linker, random_closure)?; + wasi::random::insecure_seed::add_to_linker::<_, WasiRandom>(linker, random_closure)?; + wasi::cli::exit::add_to_linker::<_, WasiCli>(linker, cli_closure)?; + wasi::cli::environment::add_to_linker::<_, WasiCli>(linker, cli_closure)?; + wasi::cli::stdin::add_to_linker::<_, WasiCli>(linker, cli_closure)?; + wasi::cli::stdout::add_to_linker::<_, WasiCli>(linker, cli_closure)?; + wasi::cli::stderr::add_to_linker::<_, WasiCli>(linker, cli_closure)?; + wasi::cli::terminal_input::add_to_linker::<_, WasiCli>(linker, cli_closure)?; + wasi::cli::terminal_output::add_to_linker::<_, WasiCli>(linker, cli_closure)?; + wasi::cli::terminal_stdin::add_to_linker::<_, WasiCli>(linker, cli_closure)?; + wasi::cli::terminal_stdout::add_to_linker::<_, WasiCli>(linker, cli_closure)?; + wasi::cli::terminal_stderr::add_to_linker::<_, WasiCli>(linker, cli_closure)?; + wasi::sockets::tcp::add_to_linker::<_, WasiSockets>(linker, sockets_closure)?; + wasi::sockets::tcp_create_socket::add_to_linker::<_, WasiSockets>(linker, sockets_closure)?; + wasi::sockets::udp::add_to_linker::<_, WasiSockets>(linker, sockets_closure)?; + wasi::sockets::udp_create_socket::add_to_linker::<_, WasiSockets>(linker, sockets_closure)?; + wasi::sockets::instance_network::add_to_linker::<_, WasiSockets>(linker, sockets_closure)?; + wasi::sockets::network::add_to_linker::<_, WasiSockets>(linker, sockets_closure)?; + wasi::sockets::ip_name_lookup::add_to_linker::<_, WasiSockets>(linker, sockets_closure)?; Ok(()) } -impl wasi::clocks::monotonic_clock::Host for WasiCtxView<'_> { +impl wasi::clocks::monotonic_clock::Host for WasiClocksCtxView<'_> { fn now(&mut self) -> wasmtime::Result { latest::clocks::monotonic_clock::Host::now(self) } @@ -163,7 +172,7 @@ impl wasi::clocks::monotonic_clock::Host for WasiCtxView<'_> { } } -impl wasi::clocks::wall_clock::Host for WasiCtxView<'_> { +impl wasi::clocks::wall_clock::Host for WasiClocksCtxView<'_> { fn now(&mut self) -> wasmtime::Result { Ok(latest::clocks::wall_clock::Host::now(self)?.into()) } @@ -173,7 +182,7 @@ impl wasi::clocks::wall_clock::Host for WasiCtxView<'_> { } } -impl wasi::filesystem::types::Host for WasiCtxView<'_> { +impl wasi::filesystem::types::Host for WasiFilesystemCtxView<'_> { fn filesystem_error_code( &mut self, err: Resource, @@ -182,7 +191,7 @@ impl wasi::filesystem::types::Host for WasiCtxView<'_> { } } -impl wasi::filesystem::types::HostDescriptor for WasiCtxView<'_> { +impl wasi::filesystem::types::HostDescriptor for WasiFilesystemCtxView<'_> { fn read_via_stream( &mut self, self_: Resource, @@ -506,7 +515,7 @@ impl wasi::filesystem::types::HostDescriptor for WasiCtxView<'_> { } } -impl wasi::filesystem::types::HostDirectoryEntryStream for WasiCtxView<'_> { +impl wasi::filesystem::types::HostDirectoryEntryStream for WasiFilesystemCtxView<'_> { async fn read_directory_entry( &mut self, self_: Resource, @@ -523,46 +532,46 @@ impl wasi::filesystem::types::HostDirectoryEntryStream for WasiCtxView<'_> { } } -impl wasi::filesystem::preopens::Host for WasiCtxView<'_> { +impl wasi::filesystem::preopens::Host for WasiFilesystemCtxView<'_> { fn get_directories(&mut self) -> wasmtime::Result, String)>> { latest::filesystem::preopens::Host::get_directories(self) } } -impl wasi::io::poll::Host for WasiCtxView<'_> { +impl wasi::io::poll::Host for ResourceTable { async fn poll(&mut self, list: Vec>) -> wasmtime::Result> { - latest::io::poll::Host::poll(self.table, list).await + latest::io::poll::Host::poll(self, list).await } } -impl wasi::io::poll::HostPollable for WasiCtxView<'_> { +impl wasi::io::poll::HostPollable for ResourceTable { async fn block(&mut self, rep: Resource) -> wasmtime::Result<()> { - latest::io::poll::HostPollable::block(self.table, rep).await + latest::io::poll::HostPollable::block(self, rep).await } async fn ready(&mut self, rep: Resource) -> wasmtime::Result { - latest::io::poll::HostPollable::ready(self.table, rep).await + latest::io::poll::HostPollable::ready(self, rep).await } fn drop(&mut self, rep: Resource) -> wasmtime::Result<()> { - latest::io::poll::HostPollable::drop(self.table, rep) + latest::io::poll::HostPollable::drop(self, rep) } } -impl wasi::io::error::Host for WasiCtxView<'_> {} +impl wasi::io::error::Host for ResourceTable {} -impl wasi::io::error::HostError for WasiCtxView<'_> { +impl wasi::io::error::HostError for ResourceTable { fn to_debug_string(&mut self, self_: Resource) -> wasmtime::Result { - latest::io::error::HostError::to_debug_string(self.table, self_) + latest::io::error::HostError::to_debug_string(self, self_) } fn drop(&mut self, rep: Resource) -> wasmtime::Result<()> { - latest::io::error::HostError::drop(self.table, rep) + latest::io::error::HostError::drop(self, rep) } } fn convert_stream_result( - view: &mut WasiCtxView<'_>, + table: &mut ResourceTable, result: Result, ) -> wasmtime::Result> where @@ -572,22 +581,22 @@ where Ok(e) => Ok(Ok(e.into())), Err(wasmtime_wasi::p2::StreamError::Closed) => Ok(Err(StreamError::Closed)), Err(wasmtime_wasi::p2::StreamError::LastOperationFailed(e)) => { - let e = view.table.push(e)?; + let e = table.push(e)?; Ok(Err(StreamError::LastOperationFailed(e))) } Err(wasmtime_wasi::p2::StreamError::Trap(e)) => Err(e), } } -impl wasi::io::streams::Host for WasiCtxView<'_> {} +impl wasi::io::streams::Host for ResourceTable {} -impl wasi::io::streams::HostInputStream for WasiCtxView<'_> { +impl wasi::io::streams::HostInputStream for ResourceTable { fn read( &mut self, self_: Resource, len: u64, ) -> wasmtime::Result, StreamError>> { - let result = latest::io::streams::HostInputStream::read(self.table, self_, len); + let result = latest::io::streams::HostInputStream::read(self, self_, len); convert_stream_result(self, result) } @@ -596,8 +605,7 @@ impl wasi::io::streams::HostInputStream for WasiCtxView<'_> { self_: Resource, len: u64, ) -> wasmtime::Result, StreamError>> { - let result = - latest::io::streams::HostInputStream::blocking_read(self.table, self_, len).await; + let result = latest::io::streams::HostInputStream::blocking_read(self, self_, len).await; convert_stream_result(self, result) } @@ -606,7 +614,7 @@ impl wasi::io::streams::HostInputStream for WasiCtxView<'_> { self_: Resource, len: u64, ) -> wasmtime::Result> { - let result = latest::io::streams::HostInputStream::skip(self.table, self_, len); + let result = latest::io::streams::HostInputStream::skip(self, self_, len); convert_stream_result(self, result) } @@ -615,26 +623,25 @@ impl wasi::io::streams::HostInputStream for WasiCtxView<'_> { self_: Resource, len: u64, ) -> wasmtime::Result> { - let result = - latest::io::streams::HostInputStream::blocking_skip(self.table, self_, len).await; + let result = latest::io::streams::HostInputStream::blocking_skip(self, self_, len).await; convert_stream_result(self, result) } fn subscribe(&mut self, self_: Resource) -> wasmtime::Result> { - latest::io::streams::HostInputStream::subscribe(self.table, self_) + latest::io::streams::HostInputStream::subscribe(self, self_) } async fn drop(&mut self, rep: Resource) -> wasmtime::Result<()> { - latest::io::streams::HostInputStream::drop(self.table, rep).await + latest::io::streams::HostInputStream::drop(self, rep).await } } -impl wasi::io::streams::HostOutputStream for WasiCtxView<'_> { +impl wasi::io::streams::HostOutputStream for ResourceTable { fn check_write( &mut self, self_: Resource, ) -> wasmtime::Result> { - let result = latest::io::streams::HostOutputStream::check_write(self.table, self_); + let result = latest::io::streams::HostOutputStream::check_write(self, self_); convert_stream_result(self, result) } @@ -643,7 +650,7 @@ impl wasi::io::streams::HostOutputStream for WasiCtxView<'_> { self_: Resource, contents: Vec, ) -> wasmtime::Result> { - let result = latest::io::streams::HostOutputStream::write(self.table, self_, contents); + let result = latest::io::streams::HostOutputStream::write(self, self_, contents); convert_stream_result(self, result) } @@ -652,10 +659,9 @@ impl wasi::io::streams::HostOutputStream for WasiCtxView<'_> { self_: Resource, contents: Vec, ) -> wasmtime::Result> { - let result = latest::io::streams::HostOutputStream::blocking_write_and_flush( - self.table, self_, contents, - ) - .await; + let result = + latest::io::streams::HostOutputStream::blocking_write_and_flush(self, self_, contents) + .await; convert_stream_result(self, result) } @@ -663,7 +669,7 @@ impl wasi::io::streams::HostOutputStream for WasiCtxView<'_> { &mut self, self_: Resource, ) -> wasmtime::Result> { - let result = latest::io::streams::HostOutputStream::flush(self.table, self_); + let result = latest::io::streams::HostOutputStream::flush(self, self_); convert_stream_result(self, result) } @@ -671,12 +677,12 @@ impl wasi::io::streams::HostOutputStream for WasiCtxView<'_> { &mut self, self_: Resource, ) -> wasmtime::Result> { - let result = latest::io::streams::HostOutputStream::blocking_flush(self.table, self_).await; + let result = latest::io::streams::HostOutputStream::blocking_flush(self, self_).await; convert_stream_result(self, result) } fn subscribe(&mut self, self_: Resource) -> wasmtime::Result> { - latest::io::streams::HostOutputStream::subscribe(self.table, self_) + latest::io::streams::HostOutputStream::subscribe(self, self_) } fn write_zeroes( @@ -684,7 +690,7 @@ impl wasi::io::streams::HostOutputStream for WasiCtxView<'_> { self_: Resource, len: u64, ) -> wasmtime::Result> { - let result = latest::io::streams::HostOutputStream::write_zeroes(self.table, self_, len); + let result = latest::io::streams::HostOutputStream::write_zeroes(self, self_, len); convert_stream_result(self, result) } @@ -694,7 +700,7 @@ impl wasi::io::streams::HostOutputStream for WasiCtxView<'_> { len: u64, ) -> wasmtime::Result> { let result = latest::io::streams::HostOutputStream::blocking_write_zeroes_and_flush( - self.table, self_, len, + self, self_, len, ) .await; convert_stream_result(self, result) @@ -706,7 +712,7 @@ impl wasi::io::streams::HostOutputStream for WasiCtxView<'_> { src: Resource, len: u64, ) -> wasmtime::Result> { - let result = latest::io::streams::HostOutputStream::splice(self.table, self_, src, len); + let result = latest::io::streams::HostOutputStream::splice(self, self_, src, len); convert_stream_result(self, result) } @@ -717,49 +723,48 @@ impl wasi::io::streams::HostOutputStream for WasiCtxView<'_> { len: u64, ) -> wasmtime::Result> { let result = - latest::io::streams::HostOutputStream::blocking_splice(self.table, self_, src, len) - .await; + latest::io::streams::HostOutputStream::blocking_splice(self, self_, src, len).await; convert_stream_result(self, result) } async fn drop(&mut self, rep: Resource) -> wasmtime::Result<()> { - latest::io::streams::HostOutputStream::drop(self.table, rep).await + latest::io::streams::HostOutputStream::drop(self, rep).await } } -impl wasi::random::random::Host for WasiCtxView<'_> { +impl wasi::random::random::Host for WasiRandomCtx { fn get_random_bytes(&mut self, len: u64) -> wasmtime::Result> { - latest::random::random::Host::get_random_bytes(self.ctx.random(), len) + latest::random::random::Host::get_random_bytes(self, len) } fn get_random_u64(&mut self) -> wasmtime::Result { - latest::random::random::Host::get_random_u64(self.ctx.random()) + latest::random::random::Host::get_random_u64(self) } } -impl wasi::random::insecure::Host for WasiCtxView<'_> { +impl wasi::random::insecure::Host for WasiRandomCtx { fn get_insecure_random_bytes(&mut self, len: u64) -> wasmtime::Result> { - latest::random::insecure::Host::get_insecure_random_bytes(self.ctx.random(), len) + latest::random::insecure::Host::get_insecure_random_bytes(self, len) } fn get_insecure_random_u64(&mut self) -> wasmtime::Result { - latest::random::insecure::Host::get_insecure_random_u64(self.ctx.random()) + latest::random::insecure::Host::get_insecure_random_u64(self) } } -impl wasi::random::insecure_seed::Host for WasiCtxView<'_> { +impl wasi::random::insecure_seed::Host for WasiRandomCtx { fn insecure_seed(&mut self) -> wasmtime::Result<(u64, u64)> { - latest::random::insecure_seed::Host::insecure_seed(self.ctx.random()) + latest::random::insecure_seed::Host::insecure_seed(self) } } -impl wasi::cli::exit::Host for WasiCtxView<'_> { +impl wasi::cli::exit::Host for WasiCliCtxView<'_> { fn exit(&mut self, status: Result<(), ()>) -> wasmtime::Result<()> { latest::cli::exit::Host::exit(self, status) } } -impl wasi::cli::environment::Host for WasiCtxView<'_> { +impl wasi::cli::environment::Host for WasiCliCtxView<'_> { fn get_environment(&mut self) -> wasmtime::Result> { latest::cli::environment::Host::get_environment(self) } @@ -773,61 +778,61 @@ impl wasi::cli::environment::Host for WasiCtxView<'_> { } } -impl wasi::cli::stdin::Host for WasiCtxView<'_> { +impl wasi::cli::stdin::Host for WasiCliCtxView<'_> { fn get_stdin(&mut self) -> wasmtime::Result> { latest::cli::stdin::Host::get_stdin(self) } } -impl wasi::cli::stdout::Host for WasiCtxView<'_> { +impl wasi::cli::stdout::Host for WasiCliCtxView<'_> { fn get_stdout(&mut self) -> wasmtime::Result> { latest::cli::stdout::Host::get_stdout(self) } } -impl wasi::cli::stderr::Host for WasiCtxView<'_> { +impl wasi::cli::stderr::Host for WasiCliCtxView<'_> { fn get_stderr(&mut self) -> wasmtime::Result> { latest::cli::stderr::Host::get_stderr(self) } } -impl wasi::cli::terminal_stdin::Host for WasiCtxView<'_> { +impl wasi::cli::terminal_stdin::Host for WasiCliCtxView<'_> { fn get_terminal_stdin(&mut self) -> wasmtime::Result>> { latest::cli::terminal_stdin::Host::get_terminal_stdin(self) } } -impl wasi::cli::terminal_stdout::Host for WasiCtxView<'_> { +impl wasi::cli::terminal_stdout::Host for WasiCliCtxView<'_> { fn get_terminal_stdout(&mut self) -> wasmtime::Result>> { latest::cli::terminal_stdout::Host::get_terminal_stdout(self) } } -impl wasi::cli::terminal_stderr::Host for WasiCtxView<'_> { +impl wasi::cli::terminal_stderr::Host for WasiCliCtxView<'_> { fn get_terminal_stderr(&mut self) -> wasmtime::Result>> { latest::cli::terminal_stderr::Host::get_terminal_stderr(self) } } -impl wasi::cli::terminal_input::Host for WasiCtxView<'_> {} +impl wasi::cli::terminal_input::Host for WasiCliCtxView<'_> {} -impl wasi::cli::terminal_input::HostTerminalInput for WasiCtxView<'_> { +impl wasi::cli::terminal_input::HostTerminalInput for WasiCliCtxView<'_> { fn drop(&mut self, rep: Resource) -> wasmtime::Result<()> { latest::cli::terminal_input::HostTerminalInput::drop(self, rep) } } -impl wasi::cli::terminal_output::Host for WasiCtxView<'_> {} +impl wasi::cli::terminal_output::Host for WasiCliCtxView<'_> {} -impl wasi::cli::terminal_output::HostTerminalOutput for WasiCtxView<'_> { +impl wasi::cli::terminal_output::HostTerminalOutput for WasiCliCtxView<'_> { fn drop(&mut self, rep: Resource) -> wasmtime::Result<()> { latest::cli::terminal_output::HostTerminalOutput::drop(self, rep) } } -impl wasi::sockets::tcp::Host for WasiCtxView<'_> {} +impl wasi::sockets::tcp::Host for WasiSocketsCtxView<'_> {} -impl wasi::sockets::tcp::HostTcpSocket for WasiCtxView<'_> { +impl wasi::sockets::tcp::HostTcpSocket for WasiSocketsCtxView<'_> { async fn start_bind( &mut self, self_: Resource, @@ -1118,7 +1123,7 @@ impl wasi::sockets::tcp::HostTcpSocket for WasiCtxView<'_> { } } -impl wasi::sockets::tcp_create_socket::Host for WasiCtxView<'_> { +impl wasi::sockets::tcp_create_socket::Host for WasiSocketsCtxView<'_> { fn create_tcp_socket( &mut self, address_family: IpAddressFamily, @@ -1130,9 +1135,9 @@ impl wasi::sockets::tcp_create_socket::Host for WasiCtxView<'_> { } } -impl wasi::sockets::udp::Host for WasiCtxView<'_> {} +impl wasi::sockets::udp::Host for WasiSocketsCtxView<'_> {} -impl wasi::sockets::udp::HostUdpSocket for WasiCtxView<'_> { +impl wasi::sockets::udp::HostUdpSocket for WasiSocketsCtxView<'_> { async fn start_bind( &mut self, self_: Resource, @@ -1285,7 +1290,7 @@ impl wasi::sockets::udp::HostUdpSocket for WasiCtxView<'_> { } } -impl wasi::sockets::udp::HostOutgoingDatagramStream for WasiCtxView<'_> { +impl wasi::sockets::udp::HostOutgoingDatagramStream for WasiSocketsCtxView<'_> { fn check_send( &mut self, self_: Resource, @@ -1320,7 +1325,7 @@ impl wasi::sockets::udp::HostOutgoingDatagramStream for WasiCtxView<'_> { } } -impl wasi::sockets::udp::HostIncomingDatagramStream for WasiCtxView<'_> { +impl wasi::sockets::udp::HostIncomingDatagramStream for WasiSocketsCtxView<'_> { fn receive( &mut self, self_: Resource, @@ -1346,7 +1351,7 @@ impl wasi::sockets::udp::HostIncomingDatagramStream for WasiCtxView<'_> { } } -impl wasi::sockets::udp_create_socket::Host for WasiCtxView<'_> { +impl wasi::sockets::udp_create_socket::Host for WasiSocketsCtxView<'_> { fn create_udp_socket( &mut self, address_family: IpAddressFamily, @@ -1358,21 +1363,21 @@ impl wasi::sockets::udp_create_socket::Host for WasiCtxView<'_> { } } -impl wasi::sockets::instance_network::Host for WasiCtxView<'_> { +impl wasi::sockets::instance_network::Host for WasiSocketsCtxView<'_> { fn instance_network(&mut self) -> wasmtime::Result> { latest::sockets::instance_network::Host::instance_network(self) } } -impl wasi::sockets::network::Host for WasiCtxView<'_> {} +impl wasi::sockets::network::Host for WasiSocketsCtxView<'_> {} -impl wasi::sockets::network::HostNetwork for WasiCtxView<'_> { +impl wasi::sockets::network::HostNetwork for WasiSocketsCtxView<'_> { fn drop(&mut self, rep: Resource) -> wasmtime::Result<()> { latest::sockets::network::HostNetwork::drop(self, rep) } } -impl wasi::sockets::ip_name_lookup::Host for WasiCtxView<'_> { +impl wasi::sockets::ip_name_lookup::Host for WasiSocketsCtxView<'_> { fn resolve_addresses( &mut self, network: Resource, @@ -1384,7 +1389,7 @@ impl wasi::sockets::ip_name_lookup::Host for WasiCtxView<'_> { } } -impl wasi::sockets::ip_name_lookup::HostResolveAddressStream for WasiCtxView<'_> { +impl wasi::sockets::ip_name_lookup::HostResolveAddressStream for WasiSocketsCtxView<'_> { fn resolve_next_address( &mut self, self_: Resource, diff --git a/crates/factor-wasi/tests/factor_test.rs b/crates/factor-wasi/tests/factor_test.rs index 34020c64ad..faf8f4a1b2 100644 --- a/crates/factor-wasi/tests/factor_test.rs +++ b/crates/factor-wasi/tests/factor_test.rs @@ -19,9 +19,9 @@ async fn environment_works() -> anyhow::Result<()> { environment = { FOO = "bar" } }); let mut state = env.build_instance_state().await?; - let mut wasi = WasiFactor::get_wasi_impl(&mut state).unwrap(); + let mut cli = WasiFactor::get_cli_impl(&mut state).unwrap(); - let val = wasi + let val = cli .get_environment()? .into_iter() .find_map(|(key, val)| (key == "FOO").then_some(val)); diff --git a/crates/http/src/trigger.rs b/crates/http/src/trigger.rs index f7946bd580..8cc91691cd 100644 --- a/crates/http/src/trigger.rs +++ b/crates/http/src/trigger.rs @@ -4,6 +4,7 @@ use spin_factor_outbound_http::wasi_2023_11_10::ProxyIndices as ProxyIndices2023 use wasmtime::component::InstancePre; use wasmtime_wasi::p2::bindings::CommandIndices; use wasmtime_wasi_http::bindings::ProxyIndices; +use wasmtime_wasi_http::p3::bindings::ProxyIndices as P3ProxyIndices; #[derive(Clone, Debug, Default, Deserialize, Serialize)] #[serde(deny_unknown_fields)] @@ -22,6 +23,7 @@ pub enum HandlerType { Spin, Wagi(CommandIndices), Wasi0_2(ProxyIndices), + Wasi0_3(P3ProxyIndices), Wasi2023_11_10(ProxyIndices2023_11_10), Wasi2023_10_18(ProxyIndices2023_10_18), } @@ -32,6 +34,8 @@ const WASI_HTTP_EXPORT_2023_10_18: &str = "wasi:http/incoming-handler@0.2.0-rc-2 const WASI_HTTP_EXPORT_2023_11_10: &str = "wasi:http/incoming-handler@0.2.0-rc-2023-11-10"; /// The `incoming-handler` export prefix for all `wasi:http` 0.2 versions const WASI_HTTP_EXPORT_0_2_PREFIX: &str = "wasi:http/incoming-handler@0.2"; +/// The `handler` export `wasi:http` version 0.3.0-rc-2025-08-15 +const WASI_HTTP_EXPORT_0_3_0_RC_2025_09_16: &str = "wasi:http/handler@0.3.0-rc-2025-09-16"; /// The `inbound-http` export for `fermyon:spin` const SPIN_HTTP_EXPORT: &str = "fermyon:spin/inbound-http"; @@ -42,6 +46,9 @@ impl HandlerType { if let Ok(indices) = ProxyIndices::new(pre) { candidates.push(HandlerType::Wasi0_2(indices)); } + if let Ok(indices) = P3ProxyIndices::new(pre) { + candidates.push(HandlerType::Wasi0_3(indices)); + } if let Ok(indices) = ProxyIndices2023_10_18::new(pre) { candidates.push(HandlerType::Wasi2023_10_18(indices)); } @@ -63,6 +70,7 @@ impl HandlerType { `{WASI_HTTP_EXPORT_2023_10_18}`, \ `{WASI_HTTP_EXPORT_2023_11_10}`, \ `{WASI_HTTP_EXPORT_0_2_PREFIX}.*`, \ + `{WASI_HTTP_EXPORT_0_3_0_RC_2025_09_16}`, \ or `{SPIN_HTTP_EXPORT}` but it exported none of those. \ This may mean the component handles a different trigger, or that its `wasi:http` export is newer then those supported by Spin. \ If you're sure this is an HTTP module, check if a Spin upgrade is available: this may handle the newer version." diff --git a/crates/oci/src/client.rs b/crates/oci/src/client.rs index 7ec254bf46..ba962f7d86 100644 --- a/crates/oci/src/client.rs +++ b/crates/oci/src/client.rs @@ -732,7 +732,10 @@ impl Client { Ok(c) => Ok(c), Err(_) => match docker_credential::get_credential(server) { Err(e) => { - tracing::trace!("Cannot retrieve credentials from Docker, attempting to use anonymous auth: {}", e); + tracing::trace!( + "Cannot retrieve credentials from Docker, attempting to use anonymous auth: {}", + e + ); Ok(RegistryAuth::Anonymous) } @@ -741,7 +744,9 @@ impl Client { Ok(RegistryAuth::Basic(username, password)) } Ok(DockerCredential::IdentityToken(_)) => { - tracing::trace!("Cannot use contents of Docker config, identity token not supported. Using anonymous auth"); + tracing::trace!( + "Cannot use contents of Docker config, identity token not supported. Using anonymous auth" + ); Ok(RegistryAuth::Anonymous) } }, @@ -1329,7 +1334,7 @@ mod test { let mut resolve = wit_parser::Resolve::default(); let package_id = resolve.push_str("test", wit).expect("should parse WIT"); let world_id = resolve - .select_world(package_id, Some(world)) + .select_world(&[package_id], Some(world)) .expect("should select world"); let mut wasm = wit_component::dummy_module( diff --git a/crates/runtime-config/src/lib.rs b/crates/runtime-config/src/lib.rs index d8bbc49a19..4c0d6f4b1f 100644 --- a/crates/runtime-config/src/lib.rs +++ b/crates/runtime-config/src/lib.rs @@ -478,6 +478,7 @@ mod tests { macro_rules! define_test_factor { ($field:ident : $factor:ty) => { #[derive(RuntimeFactors)] + #[allow(unused)] struct TestFactors { $field: $factor, } diff --git a/crates/trigger-http/Cargo.toml b/crates/trigger-http/Cargo.toml index 6374597910..40fe090b23 100644 --- a/crates/trigger-http/Cargo.toml +++ b/crates/trigger-http/Cargo.toml @@ -12,9 +12,11 @@ anyhow = { workspace = true } clap = { workspace = true } futures = { workspace = true } http = { workspace = true } +http-body = { workspace = true } http-body-util = { workspace = true } hyper = { workspace = true } hyper-util = { workspace = true } +pin-project-lite = { workspace = true } rustls = { workspace = true } rustls-pki-types = { workspace = true } serde = { workspace = true } @@ -25,6 +27,7 @@ spin-factor-outbound-http = { path = "../factor-outbound-http" } spin-factor-outbound-networking = { path = "../factor-outbound-networking" } spin-factor-wasi = { path = "../factor-wasi" } spin-factors = { path = "../factors" } +spin-factors-executor = { path = "../factors-executor" } spin-http = { path = "../http" } spin-telemetry = { path = "../telemetry" } spin-trigger = { path = "../trigger" } diff --git a/crates/trigger-http/src/lib.rs b/crates/trigger-http/src/lib.rs index 67a69d28ee..cc14d35f0c 100644 --- a/crates/trigger-http/src/lib.rs +++ b/crates/trigger-http/src/lib.rs @@ -8,6 +8,7 @@ mod spin; mod tls; mod wagi; mod wasi; +mod wasip3; use std::{ error::Error, @@ -153,9 +154,13 @@ impl HttpTrigger { } if let Some(TriggerMetadata { base: Some(base) }) = app.get_trigger_metadata("http")? { if base == "/" { - tracing::warn!("This application has the deprecated trigger 'base' set to the default value '/'. This may be an error in the future!"); + tracing::warn!( + "This application has the deprecated trigger 'base' set to the default value '/'. This may be an error in the future!" + ); } else { - bail!("This application is using the deprecated trigger 'base' field. The base must be prepended to each [[trigger.http]]'s 'route'.") + bail!( + "This application is using the deprecated trigger 'base' field. The base must be prepended to each [[trigger.http]]'s 'route'." + ) } } Ok(()) diff --git a/crates/trigger-http/src/server.rs b/crates/trigger-http/src/server.rs index e0b9f93501..8c002f8d66 100644 --- a/crates/trigger-http/src/server.rs +++ b/crates/trigger-http/src/server.rs @@ -46,6 +46,7 @@ use crate::{ spin::SpinHttpExecutor, wagi::WagiHttpExecutor, wasi::WasiHttpExecutor, + wasip3::Wasip3HttpExecutor, Body, NotFoundRouteKind, TlsConfig, TriggerApp, TriggerInstanceBuilder, }; @@ -372,6 +373,11 @@ impl HttpServer { .execute(instance_builder, &route_match, req, client_addr) .await } + HandlerType::Wasi0_3(indices) => { + Wasip3HttpExecutor(indices) + .execute(instance_builder, &route_match, req, client_addr) + .await + } HandlerType::Wasi0_2(_) | HandlerType::Wasi2023_11_10(_) | HandlerType::Wasi2023_10_18(_) => { @@ -464,7 +470,9 @@ impl HttpServer { if !SHOWN_GENERIC_404_WARNING.fetch_or(true, Ordering::Relaxed) && std::io::stderr().is_terminal() { - terminal::warn!("Request to {route} matched no pattern, and received a generic 404 response. To serve a more informative 404 page, add a catch-all (/...) route."); + terminal::warn!( + "Request to {route} matched no pattern, and received a generic 404 response. To serve a more informative 404 page, add a catch-all (/...) route." + ); } } Ok(Response::builder() diff --git a/crates/trigger-http/src/spin.rs b/crates/trigger-http/src/spin.rs index e22998c70a..2bbc401a6d 100644 --- a/crates/trigger-http/src/spin.rs +++ b/crates/trigger-http/src/spin.rs @@ -30,7 +30,7 @@ impl HttpExecutor for SpinHttpExecutor { ) -> Result> { let spin_http::routes::TriggerLookupKey::Component(component_id) = route_match.lookup_key() else { - anyhow::bail!("INCONCEIVABLE"); + unreachable!() }; tracing::trace!("Executing request using the Spin executor for component {component_id}"); diff --git a/crates/trigger-http/src/wagi.rs b/crates/trigger-http/src/wagi.rs index bca9442474..7b72a22c1e 100644 --- a/crates/trigger-http/src/wagi.rs +++ b/crates/trigger-http/src/wagi.rs @@ -29,7 +29,7 @@ impl HttpExecutor for WagiHttpExecutor<'_> { ) -> Result> { let spin_http::routes::TriggerLookupKey::Component(component) = route_match.lookup_key() else { - anyhow::bail!("INCONCEIVABLE"); + unreachable!() }; tracing::trace!( diff --git a/crates/trigger-http/src/wasi.rs b/crates/trigger-http/src/wasi.rs index af76f45293..f506f08591 100644 --- a/crates/trigger-http/src/wasi.rs +++ b/crates/trigger-http/src/wasi.rs @@ -17,6 +17,34 @@ use wasmtime_wasi_http::{bindings::Proxy, body::HyperIncomingBody as Body, WasiH use crate::{headers::prepare_request_headers, server::HttpExecutor, TriggerInstanceBuilder}; +pub(super) fn prepare_request( + route_match: &RouteMatch<'_, '_>, + req: &mut Request, + client_addr: SocketAddr, +) -> Result<()> { + let spin_http::routes::TriggerLookupKey::Component(component_id) = route_match.lookup_key() + else { + unreachable!() + }; + + tracing::trace!("Executing request using the Wasi executor for component {component_id}"); + + let headers = prepare_request_headers(req, route_match, client_addr)?; + req.headers_mut().clear(); + req.headers_mut() + .extend(headers.into_iter().filter_map(|(n, v)| { + let Ok(name) = n.parse::() else { + return None; + }; + let Ok(value) = HeaderValue::from_bytes(v.as_bytes()) else { + return None; + }; + Some((name, value)) + })); + + Ok(()) +} + /// An [`HttpExecutor`] that uses the `wasi:http/incoming-handler` interface. pub struct WasiHttpExecutor<'a> { pub handler_type: &'a HandlerType, @@ -31,28 +59,10 @@ impl HttpExecutor for WasiHttpExecutor<'_> { mut req: Request, client_addr: SocketAddr, ) -> Result> { - let spin_http::routes::TriggerLookupKey::Component(component_id) = route_match.lookup_key() - else { - anyhow::bail!("INCONCEIVABLE"); - }; - - tracing::trace!("Executing request using the Wasi executor for component {component_id}"); + prepare_request(route_match, &mut req, client_addr)?; let (instance, mut store) = instance_builder.instantiate(()).await?; - let headers = prepare_request_headers(&req, route_match, client_addr)?; - req.headers_mut().clear(); - req.headers_mut() - .extend(headers.into_iter().filter_map(|(n, v)| { - let Ok(name) = n.parse::() else { - return None; - }; - let Ok(value) = HeaderValue::from_bytes(v.as_bytes()) else { - return None; - }; - Some((name, value)) - })); - let mut wasi_http = spin_factor_outbound_http::OutboundHttpFactor::get_wasi_http_impl( store.data_mut().factors_instance_state_mut(), ) @@ -92,6 +102,7 @@ impl HttpExecutor for WasiHttpExecutor<'_> { Handler::Handler2023_11_10(guest) } HandlerType::Wasi0_2(indices) => Handler::Latest(indices.load(&mut store, &instance)?), + HandlerType::Wasi0_3(_) => unreachable!("should have used Wasip3HttpExecutor"), HandlerType::Spin => unreachable!("should have used SpinHttpExecutor"), HandlerType::Wagi(_) => unreachable!("should have used WagiExecutor instead"), }; diff --git a/crates/trigger-http/src/wasip3.rs b/crates/trigger-http/src/wasip3.rs new file mode 100644 index 0000000000..9c8aa5c347 --- /dev/null +++ b/crates/trigger-http/src/wasip3.rs @@ -0,0 +1,134 @@ +use crate::{server::HttpExecutor, TriggerInstanceBuilder}; +use anyhow::{Context as _, Result}; +use futures::{channel::oneshot, FutureExt}; +use http_body_util::BodyExt; +use spin_factors::RuntimeFactors; +use spin_factors_executor::InstanceState; +use spin_http::routes::RouteMatch; +use std::{ + net::SocketAddr, + pin::Pin, + task::{Context, Poll}, +}; +use tokio::task; +use tracing::{instrument, Instrument, Level}; +use wasmtime_wasi_http::{ + body::HyperIncomingBody as Body, + p3::{ + bindings::{http::types, ProxyIndices}, + WasiHttpCtxView, + }, +}; + +/// An [`HttpExecutor`] that uses the `wasi:http@0.3.*/handler` interface. +pub(super) struct Wasip3HttpExecutor<'a>(pub(super) &'a ProxyIndices); + +impl HttpExecutor for Wasip3HttpExecutor<'_> { + #[instrument(name = "spin_trigger_http.execute_wasm", skip_all, err(level = Level::INFO), fields(otel.name = format!("execute_wasm_component {}", route_match.lookup_key().to_string())))] + async fn execute( + &self, + instance_builder: TriggerInstanceBuilder<'_, F>, + route_match: &RouteMatch<'_, '_>, + mut req: http::Request, + client_addr: SocketAddr, + ) -> Result> { + super::wasi::prepare_request(route_match, &mut req, client_addr)?; + + let (instance, mut store) = instance_builder.instantiate(()).await?; + + let getter = (|data| wasi_http::(data).unwrap()) + as fn(&mut InstanceState) -> WasiHttpCtxView<'_>; + + let (request, body) = req.into_parts(); + let body = body.map_err(spin_factor_outbound_http::p2_to_p3_error_code); + let request = http::Request::from_parts(request, body); + let (request, request_io_result) = types::Request::from_http(request); + let request = wasi_http::(store.data_mut())?.table.push(request)?; + + let guest = self.0.load(&mut store, &instance)?; + + let (tx, rx) = oneshot::channel(); + task::spawn( + async move { + instance + .run_concurrent(&mut store, async move |store| { + let (response, task) = guest + .wasi_http_handler() + .call_handle(store, request) + .await?; + let response = store.with(|mut store| { + anyhow::Ok(wasi_http::(store.get())?.table.delete(response?)?) + })?; + let response = store.with(|mut store| { + response.into_http_with_getter(&mut store, request_io_result, getter) + })?; + + let (response_tx, response_rx) = oneshot::channel::<()>(); + _ = tx.send(response.map(|body| BodyWithAttachment { + body, + _attachment: response_tx, + })); + + task.block(store).await; + + // TODO: This is a temporary workaround for + // https://github.com/bytecodealliance/wasmtime/issues/11703. + // Remove this (and `BodyWithAttachment`) once that + // issue is addressed: + _ = response_rx.await; + + anyhow::Ok(()) + }) + .await? + } + .in_current_span() + .inspect(|result| { + if let Err(error) = result { + tracing::error!("Component error handling request: {error:?}"); + } + }), + ); + + Ok(rx.await?.map(|body| { + body.map_err(spin_factor_outbound_http::p3_to_p2_error_code) + .boxed() + })) + } +} + +pin_project_lite::pin_project! { + struct BodyWithAttachment { + #[pin] + body: B, + _attachment: A, + } +} + +impl http_body::Body for BodyWithAttachment { + type Data = B::Data; + type Error = B::Error; + + fn poll_frame( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll, Self::Error>>> { + self.project().body.poll_frame(cx) + } + + fn is_end_stream(&self) -> bool { + self.body.is_end_stream() + } + + fn size_hint(&self) -> http_body::SizeHint { + self.body.size_hint() + } +} + +fn wasi_http( + data: &mut InstanceState, +) -> Result> { + spin_factor_outbound_http::OutboundHttpFactor::get_wasi_p3_http_impl( + data.factors_instance_state_mut(), + ) + .context("missing OutboundHttpFactor") +} diff --git a/examples/spin-timer/Cargo.lock b/examples/spin-timer/Cargo.lock index fd0ca88a1c..546da757b2 100644 --- a/examples/spin-timer/Cargo.lock +++ b/examples/spin-timer/Cargo.lock @@ -780,9 +780,9 @@ dependencies = [ [[package]] name = "backon" -version = "1.5.0" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd0b50b1b78dbadd44ab18b3c794e496f3a139abb9fbc27d9c94c4eebbb96496" +checksum = "592277618714fbcecda9a02ba7a8781f319d26532a88553bbacc77ba5d2b3a8d" dependencies = [ "fastrand 2.3.0", ] @@ -1199,36 +1199,36 @@ dependencies = [ [[package]] name = "cranelift-assembler-x64" -version = "0.123.1" +version = "0.124.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3870e823d79cafc9c868fbea77e83fc12ec9c0e87f17ad392c71a55ec01f12a9" +checksum = "d3e8ca189363907c025c5debe2bfe56c8c18503d4575d750f87e4ccbbfbd8681" dependencies = [ "cranelift-assembler-x64-meta", ] [[package]] name = "cranelift-assembler-x64-meta" -version = "0.123.1" +version = "0.124.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a9fe971fab18724cbfc9a0579dd9cb6e370891991ccc8f85f3390d81392a3c0" +checksum = "e169461bfd463df68b01b196522f263c905eadc852f6e57fd4ce4c5d76115ead" dependencies = [ "cranelift-srcgen", ] [[package]] name = "cranelift-bforest" -version = "0.123.1" +version = "0.124.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac391df81890fc9f820461e76fb344bcebcbf72614ef99bdd03d9fb1a8cdcc5e" +checksum = "2a98298338375075287834defe333d552847110f3a04db0ce19bd308b4c40fbb" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-bitset" -version = "0.123.1" +version = "0.124.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712de3ed567438f3ca42d12547dbf30d92aef37d63ae45eabe32dd53c4ee5d00" +checksum = "edf5f49a2e2ae284db75437a49cc13220a7fb394983d5545af1209ab0bbadee3" dependencies = [ "serde", "serde_derive", @@ -1236,9 +1236,9 @@ dependencies = [ [[package]] name = "cranelift-codegen" -version = "0.123.1" +version = "0.124.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68e6fc48d06ef89c1ad3675fe093f2642d260eea8ceb96a9ee9ae94e51698277" +checksum = "c354d6db9e344f647f38c88849c482c6014b79a295aca23fa82f73b62caeda2d" dependencies = [ "bumpalo", "cranelift-assembler-x64", @@ -1263,9 +1263,9 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.123.1" +version = "0.124.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a45a98cfcd528bd06c6ef2fd1846cda3695d41bd4b2823ce965a82f4abec362f" +checksum = "9bb8008396957de750e26d0b40a76bea6e5623d970a5bfe4266ef0a79ccb8341" dependencies = [ "cranelift-assembler-x64-meta", "cranelift-codegen-shared", @@ -1276,24 +1276,24 @@ dependencies = [ [[package]] name = "cranelift-codegen-shared" -version = "0.123.1" +version = "0.124.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66b12b2fef743dffdb51a5cdb95f5f92ab263ed518a7ec73aa272a4a86ea17bf" +checksum = "98ecb53eafe1ad1f7d7f7d0585ae5d42b2050978fa812216b0420d4752eb41cb" [[package]] name = "cranelift-control" -version = "0.123.1" +version = "0.124.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dc203df5ac23968c8ded672b6c4b6dbc0639521e50b8d27ac67c2e221f3c98b" +checksum = "b9c43ac27fe178cadb17e7f4cf1320ba89b8875cc2bdee265cccfca49bc76c95" dependencies = [ "arbitrary", ] [[package]] name = "cranelift-entity" -version = "0.123.1" +version = "0.124.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d01c5dca220ed9c664a4c0cf2085aa0bebaddc306be365bdd2691d4a55dd2ae" +checksum = "15513ee4bf648d366654c6a9864fe870ca64f1eed4acabf9139056e68b3d44dc" dependencies = [ "cranelift-bitset", "serde", @@ -1302,9 +1302,9 @@ dependencies = [ [[package]] name = "cranelift-frontend" -version = "0.123.1" +version = "0.124.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecd02bd4641b10658668bf195ef92af0ecffa49a8a563de8e98f0c2d843a229d" +checksum = "c5e4399d31f06b50fcb3fa0117ff4c393c22e521574eecf524cf932fc99cd78f" dependencies = [ "cranelift-codegen", "log", @@ -1314,15 +1314,15 @@ dependencies = [ [[package]] name = "cranelift-isle" -version = "0.123.1" +version = "0.124.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51da2281ea3db0b1f6029b4321acf541ef856baafdf16e990d64953c9737bc3f" +checksum = "9a751ec2b7c2f281274a3798e37ba2344b55f60789e67aaa10d6bbea3f3f8a6b" [[package]] name = "cranelift-native" -version = "0.123.1" +version = "0.124.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff037ce35e9d513dcf64e9f613ec4816cb7b0b1b0b4e23788745f2200d278fec" +checksum = "546500d7cb424c423e118dfddc169aa61ed611c47fc1cf48783ed4e3f9800619" dependencies = [ "cranelift-codegen", "libc", @@ -1331,9 +1331,9 @@ dependencies = [ [[package]] name = "cranelift-srcgen" -version = "0.123.1" +version = "0.124.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d13dc01a8588b7f7733de0c31b766d85cac04aec078897cde706cebd891f8212" +checksum = "edeb6b718b23108a123ad1c8eecf6fa34d21a6b5518fc340dda80ce5bdf42377" [[package]] name = "crc32fast" @@ -2254,7 +2254,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2", + "socket2 0.5.9", "tokio", "tower-service", "tracing", @@ -2377,7 +2377,7 @@ dependencies = [ "hyper 1.6.0", "libc", "pin-project-lite", - "socket2", + "socket2 0.5.9", "tokio", "tower-service", "tracing", @@ -2731,9 +2731,9 @@ checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" [[package]] name = "libc" -version = "0.2.171" +version = "0.2.175" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" +checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" [[package]] name = "libm" @@ -2997,7 +2997,7 @@ dependencies = [ "rand 0.8.5", "serde", "serde_json", - "socket2", + "socket2 0.5.9", "thiserror 2.0.12", "tokio", "tokio-native-tls", @@ -3700,9 +3700,9 @@ dependencies = [ [[package]] name = "pulley-interpreter" -version = "36.0.1" +version = "37.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c53c41637e4052ec0010b923a3ffc99a124f2b6f19062147eae6458904d3e46" +checksum = "4338089093bf5f2f50e77602a4b8bb938e16bead1419ed9cd6484c9ef7050b10" dependencies = [ "cranelift-bitset", "log", @@ -3712,9 +3712,9 @@ dependencies = [ [[package]] name = "pulley-macros" -version = "36.0.1" +version = "37.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aed513b785fd6b142c6708c29990d92475971df8370b018c2c236dfd1c47b77d" +checksum = "23e93c268176831e893721022bb923f41b892b3c9e41875f276025fddb1a0ea8" dependencies = [ "proc-macro2", "quote", @@ -3734,7 +3734,7 @@ dependencies = [ "quinn-udp", "rustc-hash", "rustls 0.23.25", - "socket2", + "socket2 0.5.9", "thiserror 2.0.12", "tokio", "tracing", @@ -3770,7 +3770,7 @@ dependencies = [ "cfg_aliases", "libc", "once_cell", - "socket2", + "socket2 0.5.9", "tracing", "windows-sys 0.59.0", ] @@ -3919,36 +3919,14 @@ dependencies = [ [[package]] name = "redis" -version = "0.25.4" +version = "0.32.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0d7a6955c7511f60f3ba9e86c6d02b3c3f144f8c24b288d1f4e18074ab8bbec" -dependencies = [ - "async-trait", - "bytes", - "combine", - "futures-util", - "itoa", - "native-tls", - "percent-encoding", - "pin-project-lite", - "ryu", - "sha1_smol", - "socket2", - "tokio", - "tokio-native-tls", - "tokio-util", - "url", -] - -[[package]] -name = "redis" -version = "0.29.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bc42f3a12fd4408ce64d8efef67048a924e543bd35c6591c0447fda9054695f" +checksum = "7cd3650deebc68526b304898b192fa4102a4ef0b9ada24da096559cb60e0eef8" dependencies = [ "arc-swap", "backon", "bytes", + "cfg-if", "combine", "futures-channel", "futures-util", @@ -3959,7 +3937,7 @@ dependencies = [ "pin-project-lite", "ryu", "sha1_smol", - "socket2", + "socket2 0.6.0", "tokio", "tokio-native-tls", "tokio-util", @@ -4008,9 +3986,9 @@ dependencies = [ [[package]] name = "regalloc2" -version = "0.12.2" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5216b1837de2149f8bc8e6d5f88a9326b63b8c836ed58ce4a0a29ec736a59734" +checksum = "68e18e1ef763167dc6718c28a5585e62f907590a21028b8e87be1318f19ef1cb" dependencies = [ "allocator-api2", "bumpalo", @@ -4742,6 +4720,16 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "socket2" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + [[package]] name = "spdx" version = "0.10.8" @@ -4788,9 +4776,9 @@ version = "3.5.0-pre0" dependencies = [ "anyhow", "tracing", - "wasm-encoder 0.236.1", - "wasm-metadata 0.236.1", - "wasmparser 0.236.1", + "wasm-encoder 0.239.0", + "wasm-metadata 0.239.0", + "wasmparser 0.239.0", "wit-component", "wit-parser", ] @@ -4876,9 +4864,11 @@ dependencies = [ "anyhow", "bytes", "http 1.3.1", + "http-body 1.0.1", "http-body-util", "hyper 1.6.0", "hyper-util", + "pin-project-lite", "reqwest", "rustls 0.23.25", "serde", @@ -4979,7 +4969,7 @@ name = "spin-factor-outbound-redis" version = "3.5.0-pre0" dependencies = [ "anyhow", - "redis 0.25.4", + "redis", "spin-core", "spin-factor-outbound-networking", "spin-factors", @@ -5091,7 +5081,7 @@ name = "spin-key-value-redis" version = "3.5.0-pre0" dependencies = [ "anyhow", - "redis 0.29.5", + "redis", "serde", "spin-core", "spin-factor-key-value", @@ -5687,7 +5677,7 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2", + "socket2 0.5.9", "tokio-macros", "windows-sys 0.52.0", ] @@ -5733,7 +5723,7 @@ dependencies = [ "postgres-protocol", "postgres-types", "rand 0.8.5", - "socket2", + "socket2 0.5.9", "tokio", "tokio-util", "whoami", @@ -5860,7 +5850,7 @@ dependencies = [ "percent-encoding", "pin-project", "prost 0.13.5", - "socket2", + "socket2 0.5.9", "tokio", "tokio-stream", "tower 0.4.13", @@ -6351,12 +6341,12 @@ dependencies = [ [[package]] name = "wasm-encoder" -version = "0.236.1" +version = "0.239.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "724fccfd4f3c24b7e589d333fc0429c68042897a7e8a5f8694f31792471841e7" +checksum = "5be00faa2b4950c76fe618c409d2c3ea5a3c9422013e079482d78544bb2d184c" dependencies = [ "leb128fmt", - "wasmparser 0.236.1", + "wasmparser 0.239.0", ] [[package]] @@ -6380,9 +6370,9 @@ dependencies = [ [[package]] name = "wasm-metadata" -version = "0.236.1" +version = "0.239.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c909f94a49a8de3365f3c0344f064818f1e369ff1740c5b04f455f85d454768e" +checksum = "20b3ec880a9ac69ccd92fbdbcf46ee833071cf09f82bb005b2327c7ae6025ae2" dependencies = [ "anyhow", "auditable-serde", @@ -6393,8 +6383,8 @@ dependencies = [ "serde_json", "spdx", "url", - "wasm-encoder 0.236.1", - "wasmparser 0.236.1", + "wasm-encoder 0.239.0", + "wasmparser 0.239.0", ] [[package]] @@ -6442,9 +6432,9 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.236.1" +version = "0.239.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9b1e81f3eb254cf7404a82cee6926a4a3ccc5aad80cc3d43608a070c67aa1d7" +checksum = "8c9d90bb93e764f6beabf1d02028c70a2156a6583e63ac4218dd07ef733368b0" dependencies = [ "bitflags 2.9.0", "hashbrown 0.15.2", @@ -6455,29 +6445,31 @@ dependencies = [ [[package]] name = "wasmprinter" -version = "0.236.1" +version = "0.239.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2df225df06a6df15b46e3f73ca066ff92c2e023670969f7d50ce7d5e695abbb1" +checksum = "b3981f3d51f39f24f5fc90f93049a90f08dbbca8deba602cd46bb8ca67a94718" dependencies = [ "anyhow", "termcolor", - "wasmparser 0.236.1", + "wasmparser 0.239.0", ] [[package]] name = "wasmtime" -version = "36.0.1" +version = "37.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72eb410993c268be048b7745a49649e3390348b0fe9ee050253a74a79192574f" +checksum = "eae1ef7649330697f0374eca8af0a437cf349605afce261bb64ba66fa0663c80" dependencies = [ "addr2line 0.25.0", "anyhow", "async-trait", "bitflags 2.9.0", "bumpalo", + "bytes", "cc", "cfg-if", "encoding_rs", + "futures", "fxprof-processed-profile", "gimli 0.32.0", "hashbrown 0.15.2", @@ -6499,8 +6491,8 @@ dependencies = [ "serde_json", "smallvec", "target-lexicon", - "wasm-encoder 0.236.1", - "wasmparser 0.236.1", + "wasm-encoder 0.239.0", + "wasmparser 0.239.0", "wasmtime-environ", "wasmtime-internal-asm-macros", "wasmtime-internal-cache", @@ -6521,9 +6513,9 @@ dependencies = [ [[package]] name = "wasmtime-environ" -version = "36.0.1" +version = "37.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88d3047dfcd4c0eeb2dbd9d639dd4eef65cbe53f17211c549543f208466246ed" +checksum = "d6bf9ff7210fa31880e7cf3cfa1b83648c777090aa11ac1c448dff11e6c466a2" dependencies = [ "anyhow", "cpp_demangle", @@ -6540,26 +6532,26 @@ dependencies = [ "serde_derive", "smallvec", "target-lexicon", - "wasm-encoder 0.236.1", - "wasmparser 0.236.1", + "wasm-encoder 0.239.0", + "wasmparser 0.239.0", "wasmprinter", "wasmtime-internal-component-util", ] [[package]] name = "wasmtime-internal-asm-macros" -version = "36.0.1" +version = "37.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82c3ac22f7209c35a913b4423a9f83fc12b74239af3cb5ac6c39a5df34e1970b" +checksum = "761159dea98c5f585497f715d9d80b38baa7c6334cf9e033a76d01b291719416" dependencies = [ "cfg-if", ] [[package]] name = "wasmtime-internal-cache" -version = "36.0.1" +version = "37.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbd49572a149c84a28079a0fb06f2c67c6290e75405f71855e943e4bb4703ae0" +checksum = "0ea7c17c1d771c923f63c08bd79d6714ca8bb503cf4ecb6f39d82043280020bd" dependencies = [ "anyhow", "base64 0.22.1", @@ -6577,9 +6569,9 @@ dependencies = [ [[package]] name = "wasmtime-internal-component-macro" -version = "36.0.1" +version = "37.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0badcd2acaa2901910a2ec0815abd24b80ffeecb5683029082e26220be2b44c5" +checksum = "fd634b96656a0740f2b5fdb01e69bfc670bafbb292436826022a26153b33e818" dependencies = [ "anyhow", "proc-macro2", @@ -6592,15 +6584,15 @@ dependencies = [ [[package]] name = "wasmtime-internal-component-util" -version = "36.0.1" +version = "37.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "399a9f4d25c0dcf4829751cbb63de438f3b715abc49277c15c86460539f4a7e7" +checksum = "2a29a22837e16da7263e3622a7451917684971f65d21f4f9b97049babfacee37" [[package]] name = "wasmtime-internal-cranelift" -version = "36.0.1" +version = "37.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41370ede67231853b2f96a7f03b8e3db61802ad3ee0d7497b366f815e616f4fc" +checksum = "da2055ee07c1782ec3bb96bd7b91328e003de1a327eb02c48c2dfc937f490547" dependencies = [ "anyhow", "cfg-if", @@ -6617,17 +6609,18 @@ dependencies = [ "smallvec", "target-lexicon", "thiserror 2.0.12", - "wasmparser 0.236.1", + "wasmparser 0.239.0", "wasmtime-environ", "wasmtime-internal-math", + "wasmtime-internal-unwinder", "wasmtime-internal-versioned-export-macros", ] [[package]] name = "wasmtime-internal-fiber" -version = "36.0.1" +version = "37.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6baf30fe62eb18fdc83395011ebd32dd74af3e86cecffb74dec05d8af2243515" +checksum = "781b52cb6e688a6a50b90051b20a87a841c35638a18e309e00fed9daca7e36aa" dependencies = [ "anyhow", "cc", @@ -6641,9 +6634,9 @@ dependencies = [ [[package]] name = "wasmtime-internal-jit-debug" -version = "36.0.1" +version = "37.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "416e2d2193073fe65355315bd144a9a26cbdf1f0c27faa7fdd3266a09b2689d3" +checksum = "b771527002767c3c84f7edee5255925c1dce5fd41e9de5b46aeaaee6e5242971" dependencies = [ "cc", "object 0.37.3", @@ -6653,9 +6646,9 @@ dependencies = [ [[package]] name = "wasmtime-internal-jit-icache-coherence" -version = "36.0.1" +version = "37.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b787315e8acb988ce5da8439ce827f84a01b912d3b157aafe0ddd8779fef219e" +checksum = "4aea2b284343796fbbe749c36db092b43809762f8b9e46626561a8be4003dd85" dependencies = [ "anyhow", "cfg-if", @@ -6665,24 +6658,24 @@ dependencies = [ [[package]] name = "wasmtime-internal-math" -version = "36.0.1" +version = "37.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d8b81a4083aa76d3cd3ebf24f0564b6d17d4faffd47c42dd218798aa5894d4" +checksum = "5a058122e659373c3648a71de03436105f213037d8016bb68550c259d4b37931" dependencies = [ "libm", ] [[package]] name = "wasmtime-internal-slab" -version = "36.0.1" +version = "37.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e701cdea321a3c288990dcc1ed7b4c89d120e10bf50052e942243251e710c42" +checksum = "65cafe64859a9df2b2391bb4cc1139eace115c02ba363e22cfd19eb675282f5a" [[package]] name = "wasmtime-internal-unwinder" -version = "36.0.1" +version = "37.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60ddcc1b024ae8e16f043b0dbea676048f3b710efbaa63f2647bc287315b8704" +checksum = "be561ffc6e3dcbd07b49d463af1a325412e58550d1514fbfb6c37e1bf4c80928" dependencies = [ "anyhow", "cfg-if", @@ -6693,9 +6686,9 @@ dependencies = [ [[package]] name = "wasmtime-internal-versioned-export-macros" -version = "36.0.1" +version = "37.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4bd56c30d60d617935d1a68272223341b67c27fb3776fee025e481f3ac53cd0" +checksum = "8d16a0ea81107fc7e269d504bb586296eaf9c4d79d99aaa4f4135d18bc6fbc86" dependencies = [ "proc-macro2", "quote", @@ -6704,16 +6697,17 @@ dependencies = [ [[package]] name = "wasmtime-internal-winch" -version = "36.0.1" +version = "37.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9a56b31bc1c5b6a62cb400e996947944a3a0545dc8e11790964074269876137" +checksum = "a99416e4805ffc48b718b5b967d3bda44aa8765c7bfcc6993f8b5819e8427cb6" dependencies = [ "anyhow", "cranelift-codegen", "gimli 0.32.0", + "log", "object 0.37.3", "target-lexicon", - "wasmparser 0.236.1", + "wasmparser 0.239.0", "wasmtime-environ", "wasmtime-internal-cranelift", "winch-codegen", @@ -6721,9 +6715,9 @@ dependencies = [ [[package]] name = "wasmtime-internal-wit-bindgen" -version = "36.0.1" +version = "37.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c9816c753aaa5591c45f3ccfb9f2ecf9ea9bbffabc1ad628818803bd12e34ba" +checksum = "d04509ae5bfb09b509e22ce83168add9b2a92dc7a902d68f31d391c9b23a36d6" dependencies = [ "anyhow", "bitflags 2.9.0", @@ -6734,9 +6728,9 @@ dependencies = [ [[package]] name = "wasmtime-wasi" -version = "36.0.1" +version = "37.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c43f4163d631ecb72245b34aae03f5a0b07e58c2004692b4258caf8bf7aacca5" +checksum = "78179e5f067030bcc032cb4c149bbe92688e3fc9960b9d45eb06c38b817e6b8b" dependencies = [ "anyhow", "async-trait", @@ -6765,9 +6759,9 @@ dependencies = [ [[package]] name = "wasmtime-wasi-http" -version = "36.0.1" +version = "37.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a9730c0a3f24c25a8fa40fecbd4a1a3e77dff5bb730d98e16861c9dfcc2ca33" +checksum = "c1c3083c447bc7cbeb1128068d3fef0768ff6fb346409a574466aa3e4e458d1e" dependencies = [ "anyhow", "async-trait", @@ -6780,6 +6774,7 @@ dependencies = [ "rustls 0.22.4", "tokio", "tokio-rustls 0.25.0", + "tokio-util", "tracing", "wasmtime", "wasmtime-wasi", @@ -6789,9 +6784,9 @@ dependencies = [ [[package]] name = "wasmtime-wasi-io" -version = "36.0.1" +version = "37.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a1700b7b7a2b9b704ed9501745798e3791f575ee6973d7d821e2386a94adbf" +checksum = "aa0974abaf5ec96584ed75928689a95e79b553182939337fa284779cb6b8a4e3" dependencies = [ "anyhow", "async-trait", @@ -6811,24 +6806,24 @@ dependencies = [ [[package]] name = "wast" -version = "236.0.1" +version = "239.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3bec4b4db9c6808d394632fd4b0cd4654c32c540bd3237f55ee6a40fff6e51f" +checksum = "9139176fe8a2590e0fb174cdcaf373b224cb93c3dde08e4297c1361d2ba1ea5d" dependencies = [ "bumpalo", "leb128fmt", "memchr", "unicode-width", - "wasm-encoder 0.236.1", + "wasm-encoder 0.239.0", ] [[package]] name = "wat" -version = "1.236.1" +version = "1.239.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64475e2f77d6071ce90624098fc236285ddafa8c3ea1fb386f2c4154b6c2bbdb" +checksum = "3e1c941927d34709f255558166f8901a2005f8ab4a9650432e9281b7cc6f3b75" dependencies = [ - "wast 236.0.1", + "wast 239.0.0", ] [[package]] @@ -6873,9 +6868,9 @@ dependencies = [ [[package]] name = "wiggle" -version = "36.0.1" +version = "37.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0047009d1851c65dfeb197ff53a1d1bf94358d56604ac5e9419397ba381bfa17" +checksum = "b35aad501cfca310289a22bdc95c571c15047967b02295a4df56de391b4d90ef" dependencies = [ "anyhow", "async-trait", @@ -6888,9 +6883,9 @@ dependencies = [ [[package]] name = "wiggle-generate" -version = "36.0.1" +version = "37.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af67f0f2a0e2e7841e9a561aff21cec8f6125b5b8d2c43adecc974e36e9cbbd9" +checksum = "66a1516334f2191ef393f754a8689f0c2193cf304828725b4708d377c6b0a185" dependencies = [ "anyhow", "heck 0.5.0", @@ -6902,9 +6897,9 @@ dependencies = [ [[package]] name = "wiggle-macro" -version = "36.0.1" +version = "37.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6f1ed189ba5962988a017f86bc73b03cc69e1b8d3040922beab307855ce594d" +checksum = "8c6a0b969afcee961240d696375f29e3c42e6a55e2fcf9a1798f500fe0fdd242" dependencies = [ "proc-macro2", "quote", @@ -6945,9 +6940,9 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "winch-codegen" -version = "36.0.1" +version = "37.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ac81262abfb835f3f46f64715863fa2737c2928fab58db74ec98710e3e261a" +checksum = "20581fd07c028fc1c151cd5c15719da62dfd852502c1751df8a93a0637a86791" dependencies = [ "anyhow", "cranelift-assembler-x64", @@ -6957,7 +6952,7 @@ dependencies = [ "smallvec", "target-lexicon", "thiserror 2.0.12", - "wasmparser 0.236.1", + "wasmparser 0.239.0", "wasmtime-environ", "wasmtime-internal-cranelift", "wasmtime-internal-math", @@ -7270,9 +7265,9 @@ dependencies = [ [[package]] name = "wit-component" -version = "0.236.1" +version = "0.239.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3622959ed7ed6341c38e5aa35af243632534b0a36226852faa802939ce11e00f" +checksum = "88a866b19dba2c94d706ec58c92a4c62ab63e482b4c935d2a085ac94caecb136" dependencies = [ "anyhow", "bitflags 2.9.0", @@ -7281,17 +7276,17 @@ dependencies = [ "serde", "serde_derive", "serde_json", - "wasm-encoder 0.236.1", - "wasm-metadata 0.236.1", - "wasmparser 0.236.1", + "wasm-encoder 0.239.0", + "wasm-metadata 0.239.0", + "wasmparser 0.239.0", "wit-parser", ] [[package]] name = "wit-parser" -version = "0.236.1" +version = "0.239.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16e4833a20cd6e85d6abfea0e63a399472d6f88c6262957c17f546879a80ba15" +checksum = "55c92c939d667b7bf0c6bf2d1f67196529758f99a2a45a3355cc56964fd5315d" dependencies = [ "anyhow", "id-arena", @@ -7302,7 +7297,7 @@ dependencies = [ "serde_derive", "serde_json", "unicode-xid", - "wasmparser 0.236.1", + "wasmparser 0.239.0", ] [[package]] diff --git a/examples/spin-timer/Cargo.toml b/examples/spin-timer/Cargo.toml index a9aaa6873e..c4ad15819e 100644 --- a/examples/spin-timer/Cargo.toml +++ b/examples/spin-timer/Cargo.toml @@ -13,6 +13,6 @@ spin-runtime-factors = { path = "../../crates/runtime-factors" } spin-trigger = { path = "../../crates/trigger" } tokio = { version = "1", features = ["full"] } tokio-scoped = "0.2.0" -wasmtime = "36.0.2" +wasmtime = "37.0.1" [workspace] diff --git a/tests/integration.rs b/tests/integration.rs index 322ea92490..a7e5f0b91c 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -143,7 +143,7 @@ mod integration_tests { Err(e) => { return Err( anyhow::anyhow!("could not read stdout file: {e}").into() - ) + ); } } }, @@ -201,7 +201,7 @@ mod integration_tests { Err(e) => { return Err( anyhow::anyhow!("could not read stdout file: {e}").into() - ) + ); } } }, @@ -1195,16 +1195,38 @@ route = "/..." } #[test] - fn test_wasi_http_echo() -> anyhow::Result<()> { - wasi_http_echo("echo".into(), None) + fn test_wasi_http_p2_echo() -> anyhow::Result<()> { + wasi_http_echo("wasi-http-p2-streaming", "echo".into(), None) } #[test] - fn test_wasi_http_double_echo() -> anyhow::Result<()> { - wasi_http_echo("double-echo".into(), Some("echo".into())) + fn test_wasi_http_p3_echo() -> anyhow::Result<()> { + wasi_http_echo("wasi-http-p3-streaming", "echo".into(), None) } - fn wasi_http_echo(uri: String, url_header_uri: Option) -> anyhow::Result<()> { + #[test] + fn test_wasi_http_p2_double_echo() -> anyhow::Result<()> { + wasi_http_echo( + "wasi-http-p2-streaming", + "double-echo".into(), + Some("echo".into()), + ) + } + + #[test] + fn test_wasi_http_p3_double_echo() -> anyhow::Result<()> { + wasi_http_echo( + "wasi-http-p2-streaming", + "double-echo".into(), + Some("echo".into()), + ) + } + + fn wasi_http_echo( + test: &str, + uri: String, + url_header_uri: Option, + ) -> anyhow::Result<()> { let body_bytes = { // A sorta-random-ish megabyte let mut n = 0_u8; @@ -1227,7 +1249,7 @@ route = "/..." )); run_test( - "wasi-http-streaming", + test, SpinConfig { binary_path: spin_binary(), spin_up_args: Vec::new(), @@ -1267,7 +1289,16 @@ route = "/..." } #[test] - fn test_wasi_http_hash_all() -> anyhow::Result<()> { + fn test_wasi_http_p2_hash_all() -> anyhow::Result<()> { + wasi_http_hash_all("wasi-http-p2-streaming") + } + + #[test] + fn test_wasi_http_p3_hash_all() -> anyhow::Result<()> { + wasi_http_hash_all("wasi-http-p3-streaming") + } + + fn wasi_http_hash_all(test: &str) -> anyhow::Result<()> { let requests = [ ("/a", "’Twas brillig, and the slithy toves"), ("/b", "Did gyre and gimble in the wabe:"), @@ -1277,7 +1308,7 @@ route = "/..." .into_iter() .collect::>(); run_test( - "wasi-http-streaming", + test, SpinConfig { binary_path: spin_binary(), spin_up_args: Vec::new(), diff --git a/tests/test-components/components/Cargo.lock b/tests/test-components/components/Cargo.lock index db79baac4d..729367592d 100644 --- a/tests/test-components/components/Cargo.lock +++ b/tests/test-components/components/Cargo.lock @@ -2,31 +2,19 @@ # It is not intended for manual editing. version = 4 -[[package]] -name = "ahash" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" -dependencies = [ - "cfg-if", - "once_cell", - "version_check", - "zerocopy", -] - [[package]] name = "ai" version = "0.1.0" dependencies = [ "helper", - "wit-bindgen 0.34.0", + "wit-bindgen 0.46.0", ] [[package]] name = "anyhow" -version = "1.0.89" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" +checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100" [[package]] name = "async-trait" @@ -101,6 +89,17 @@ dependencies = [ "crypto-common", ] +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", +] + [[package]] name = "equivalent" version = "1.0.1" @@ -113,20 +112,26 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + [[package]] name = "form_urlencoded" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" dependencies = [ "percent-encoding", ] [[package]] name = "futures" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" dependencies = [ "futures-channel", "futures-core", @@ -139,9 +144,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", "futures-sink", @@ -149,15 +154,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-executor" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" dependencies = [ "futures-core", "futures-task", @@ -166,15 +171,15 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-macro" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", @@ -183,21 +188,21 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-util" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-channel", "futures-core", @@ -223,11 +228,11 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.14.3" +version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ - "ahash", + "foldhash", ] [[package]] @@ -276,7 +281,7 @@ dependencies = [ name = "helper" version = "0.1.0" dependencies = [ - "wit-bindgen 0.34.0", + "wit-bindgen 0.46.0", ] [[package]] @@ -316,6 +321,92 @@ dependencies = [ "spin-sdk 2.2.0", ] +[[package]] +name = "icu_collections" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" + +[[package]] +name = "icu_properties" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "potential_utf", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" + +[[package]] +name = "icu_provider" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +dependencies = [ + "displaydoc", + "icu_locale_core", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + [[package]] name = "id-arena" version = "2.2.1" @@ -324,23 +415,35 @@ checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005" [[package]] name = "idna" -version = "0.5.0" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "icu_normalizer", + "icu_properties", ] [[package]] name = "indexmap" -version = "2.1.0" +version = "2.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +checksum = "92119844f513ffa41556430369ab02c295a3578af21cf945caa3e9e0c2481ac3" dependencies = [ "equivalent", "hashbrown", "serde", + "serde_core", ] [[package]] @@ -357,11 +460,11 @@ name = "integration-spin-inbound-http" version = "0.1.0" dependencies = [ "miniserde", - "wit-bindgen 0.34.0", + "wit-bindgen 0.46.0", ] [[package]] -name = "integration-wasi-http-streaming" +name = "integration-wasi-http-p2-streaming" version = "0.1.0" dependencies = [ "anyhow", @@ -372,6 +475,17 @@ dependencies = [ "url", ] +[[package]] +name = "integration-wasi-http-p3-streaming" +version = "0.1.0" +dependencies = [ + "futures", + "hex", + "sha2", + "url", + "wit-bindgen 0.46.0", +] + [[package]] name = "integration_wagi" version = "0.1.0" @@ -438,7 +552,7 @@ name = "key-value" version = "0.1.0" dependencies = [ "helper", - "wit-bindgen 0.34.0", + "wit-bindgen 0.46.0", ] [[package]] @@ -456,12 +570,24 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + [[package]] name = "libc" version = "0.2.152" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" +[[package]] +name = "litemap" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" + [[package]] name = "log" version = "0.4.20" @@ -516,7 +642,7 @@ name = "outbound-mqtt-test-component" version = "0.1.0" dependencies = [ "helper", - "wit-bindgen 0.34.0", + "wit-bindgen 0.46.0", ] [[package]] @@ -524,7 +650,7 @@ name = "outbound-mysql-test-component" version = "0.1.0" dependencies = [ "helper", - "wit-bindgen 0.34.0", + "wit-bindgen 0.46.0", ] [[package]] @@ -532,7 +658,7 @@ name = "outbound-postgres-test-component" version = "0.1.0" dependencies = [ "helper", - "wit-bindgen 0.34.0", + "wit-bindgen 0.46.0", ] [[package]] @@ -540,14 +666,14 @@ name = "outbound-redis-test-component" version = "0.1.0" dependencies = [ "helper", - "wit-bindgen 0.34.0", + "wit-bindgen 0.46.0", ] [[package]] name = "percent-encoding" -version = "2.3.1" +version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "pin-project-lite" @@ -561,6 +687,15 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "potential_utf" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84df19adbe5b5a0782edcab45899906947ab039ccf4573713735ee7de1e6b08a" +dependencies = [ + "zerovec", +] + [[package]] name = "prettyplease" version = "0.2.29" @@ -613,18 +748,28 @@ checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" [[package]] name = "serde" -version = "1.0.193" +version = "1.0.225" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" +checksum = "fd6c24dee235d0da097043389623fb913daddf92c76e9f5a1db88607a0bcbd1d" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.225" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "659356f9a0cb1e529b24c01e43ad2bdf520ec4ceaf83047b83ddcc2251f96383" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.193" +version = "1.0.225" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" +checksum = "0ea936adf78b1f766949a4977b91d2f5595825bd6ec079aa9543ad2685fc4516" dependencies = [ "proc-macro2", "quote", @@ -655,9 +800,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.8" +version = "0.10.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", "cpufeatures", @@ -675,9 +820,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.11.2" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "smartcow" @@ -790,9 +935,15 @@ name = "sqlite-test-component" version = "0.1.0" dependencies = [ "helper", - "wit-bindgen 0.34.0", + "wit-bindgen 0.46.0", ] +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "static_assertions" version = "1.1.0" @@ -821,12 +972,23 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", +] + [[package]] name = "tcp-sockets-test-component" version = "0.1.0" dependencies = [ "helper", - "wit-bindgen 0.34.0", + "wit-bindgen 0.46.0", ] [[package]] @@ -850,47 +1012,27 @@ dependencies = [ ] [[package]] -name = "tinyvec" -version = "1.6.0" +name = "tinystr" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" dependencies = [ - "tinyvec_macros", + "displaydoc", + "zerovec", ] -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - [[package]] name = "typenum" version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" -[[package]] -name = "unicode-bidi" -version = "0.3.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416" - [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" -[[package]] -name = "unicode-normalization" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" -dependencies = [ - "tinyvec", -] - [[package]] name = "unicode-segmentation" version = "1.10.1" @@ -905,21 +1047,28 @@ checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" [[package]] name = "url" -version = "2.5.0" +version = "2.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" dependencies = [ "form_urlencoded", "idna", "percent-encoding", + "serde", ] +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + [[package]] name = "variables" version = "0.1.0" dependencies = [ "helper", - "wit-bindgen 0.34.0", + "wit-bindgen 0.46.0", ] [[package]] @@ -942,7 +1091,7 @@ name = "wasi-config" version = "0.1.0" dependencies = [ "helper", - "wit-bindgen 0.34.0", + "wit-bindgen 0.46.0", ] [[package]] @@ -951,7 +1100,7 @@ version = "0.1.0" dependencies = [ "helper", "url", - "wit-bindgen 0.34.0", + "wit-bindgen 0.46.0", ] [[package]] @@ -959,7 +1108,7 @@ name = "wasi-http-rust-0-2-0" version = "0.1.0" dependencies = [ "url", - "wit-bindgen 0.34.0", + "wit-bindgen 0.46.0", ] [[package]] @@ -967,7 +1116,7 @@ name = "wasi-http-rust-rc-2023-11-10" version = "0.1.0" dependencies = [ "url", - "wit-bindgen 0.34.0", + "wit-bindgen 0.46.0", ] [[package]] @@ -975,7 +1124,7 @@ name = "wasi-key-value" version = "0.1.0" dependencies = [ "helper", - "wit-bindgen 0.34.0", + "wit-bindgen 0.46.0", ] [[package]] @@ -1007,12 +1156,12 @@ dependencies = [ [[package]] name = "wasm-encoder" -version = "0.219.2" +version = "0.239.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8aa79bcd666a043b58f5fa62b221b0b914dd901e6f620e8ab7371057a797f3e1" +checksum = "5be00faa2b4950c76fe618c409d2c3ea5a3c9422013e079482d78544bb2d184c" dependencies = [ - "leb128", - "wasmparser 0.219.2", + "leb128fmt", + "wasmparser 0.239.0", ] [[package]] @@ -1033,18 +1182,14 @@ dependencies = [ [[package]] name = "wasm-metadata" -version = "0.219.2" +version = "0.239.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1ef51bd442042a2a7b562dddb6016ead52c4abab254c376dcffc83add2c9c34" +checksum = "20b3ec880a9ac69ccd92fbdbcf46ee833071cf09f82bb005b2327c7ae6025ae2" dependencies = [ "anyhow", "indexmap", - "serde", - "serde_derive", - "serde_json", - "spdx", - "wasm-encoder 0.219.2", - "wasmparser 0.219.2", + "wasm-encoder 0.239.0", + "wasmparser 0.239.0", ] [[package]] @@ -1080,11 +1225,10 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.219.2" +version = "0.239.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5220ee4c6ffcc0cb9d7c47398052203bc902c8ef3985b0c8134118440c0b2921" +checksum = "8c9d90bb93e764f6beabf1d02028c70a2156a6583e63ac4218dd07ef733368b0" dependencies = [ - "ahash", "bitflags", "hashbrown", "indexmap", @@ -1113,12 +1257,14 @@ dependencies = [ [[package]] name = "wit-bindgen" -version = "0.34.0" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e11ad55616555605a60a8b2d1d89e006c2076f46c465c892cc2c153b20d4b30" +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" dependencies = [ - "wit-bindgen-rt", - "wit-bindgen-rust-macro 0.34.0", + "bitflags", + "futures", + "once_cell", + "wit-bindgen-rust-macro 0.46.0", ] [[package]] @@ -1145,22 +1291,13 @@ dependencies = [ [[package]] name = "wit-bindgen-core" -version = "0.34.0" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "163cee59d3d5ceec0b256735f3ab0dccac434afb0ec38c406276de9c5a11e906" +checksum = "cabd629f94da277abc739c71353397046401518efb2c707669f805205f0b9890" dependencies = [ "anyhow", "heck 0.5.0", - "wit-parser 0.219.2", -] - -[[package]] -name = "wit-bindgen-rt" -version = "0.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "744845cde309b8fa32408d6fb67456449278c66ea4dcd96de29797b302721f02" -dependencies = [ - "bitflags", + "wit-parser 0.239.0", ] [[package]] @@ -1191,18 +1328,18 @@ dependencies = [ [[package]] name = "wit-bindgen-rust" -version = "0.34.0" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6919521fc7807f927a739181db93100ca7ed03c29509b84d5f96b27b2e49a9a" +checksum = "9a4232e841089fa5f3c4fc732a92e1c74e1a3958db3b12f1de5934da2027f1f4" dependencies = [ "anyhow", "heck 0.5.0", "indexmap", "prettyplease", "syn 2.0.98", - "wasm-metadata 0.219.2", - "wit-bindgen-core 0.34.0", - "wit-component 0.219.2", + "wasm-metadata 0.239.0", + "wit-bindgen-core 0.46.0", + "wit-component 0.239.0", ] [[package]] @@ -1237,17 +1374,17 @@ dependencies = [ [[package]] name = "wit-bindgen-rust-macro" -version = "0.34.0" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c967731fc5d50244d7241ecfc9302a8929db508eea3c601fbc5371b196ba38a5" +checksum = "1e0d4698c2913d8d9c2b220d116409c3f51a7aa8d7765151b886918367179ee9" dependencies = [ "anyhow", "prettyplease", "proc-macro2", "quote", "syn 2.0.98", - "wit-bindgen-core 0.34.0", - "wit-bindgen-rust 0.34.0", + "wit-bindgen-core 0.46.0", + "wit-bindgen-rust 0.46.0", ] [[package]] @@ -1290,9 +1427,9 @@ dependencies = [ [[package]] name = "wit-component" -version = "0.219.2" +version = "0.239.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b8479a29d81c063264c3ab89d496787ef78f8345317a2dcf6dece0f129e5fcd" +checksum = "88a866b19dba2c94d706ec58c92a4c62ab63e482b4c935d2a085ac94caecb136" dependencies = [ "anyhow", "bitflags", @@ -1301,10 +1438,10 @@ dependencies = [ "serde", "serde_derive", "serde_json", - "wasm-encoder 0.219.2", - "wasm-metadata 0.219.2", - "wasmparser 0.219.2", - "wit-parser 0.219.2", + "wasm-encoder 0.239.0", + "wasm-metadata 0.239.0", + "wasmparser 0.239.0", + "wit-parser 0.239.0", ] [[package]] @@ -1343,9 +1480,9 @@ dependencies = [ [[package]] name = "wit-parser" -version = "0.219.2" +version = "0.239.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca004bb251010fe956f4a5b9d4bf86b4e415064160dd6669569939e8cbf2504f" +checksum = "55c92c939d667b7bf0c6bf2d1f67196529758f99a2a45a3355cc56964fd5315d" dependencies = [ "anyhow", "id-arena", @@ -1356,23 +1493,87 @@ dependencies = [ "serde_derive", "serde_json", "unicode-xid", - "wasmparser 0.219.2", + "wasmparser 0.239.0", +] + +[[package]] +name = "writeable" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" + +[[package]] +name = "yoke" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", + "synstructure", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", + "synstructure", +] + +[[package]] +name = "zerotrie" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", ] [[package]] -name = "zerocopy" -version = "0.7.35" +name = "zerovec" +version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b" dependencies = [ - "zerocopy-derive", + "yoke", + "zerofrom", + "zerovec-derive", ] [[package]] -name = "zerocopy-derive" -version = "0.7.35" +name = "zerovec-derive" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" dependencies = [ "proc-macro2", "quote", diff --git a/tests/test-components/components/Cargo.toml b/tests/test-components/components/Cargo.toml index fe5e760594..b4f8bd744d 100644 --- a/tests/test-components/components/Cargo.toml +++ b/tests/test-components/components/Cargo.toml @@ -4,4 +4,4 @@ exclude = ["target"] resolver = "2" [workspace.dependencies] -wit-bindgen = "0.34.0" +wit-bindgen = { version = "0.46.0", features = ["async"] } diff --git a/tests/test-components/components/http-routing/src/lib.rs b/tests/test-components/components/http-routing/src/lib.rs index 59591bee94..0aa25bcb0f 100644 --- a/tests/test-components/components/http-routing/src/lib.rs +++ b/tests/test-components/components/http-routing/src/lib.rs @@ -1,6 +1,9 @@ use anyhow::{anyhow, Result}; use helper::ensure_some; -use spin_sdk::{http_component, http::{Request, Response}}; +use spin_sdk::{ + http::{Request, Response}, + http_component, +}; #[http_component] fn test_routing_headers(req: Request) -> Result { @@ -13,15 +16,10 @@ fn test_routing_headers_impl(req: Request) -> Result { .and_then(|v| v.as_str()); let header_userid = ensure_some!(header_userid); - let trailing = req - .header("spin-path-info") - .and_then(|v| v.as_str()); + let trailing = req.header("spin-path-info").and_then(|v| v.as_str()); let trailing = ensure_some!(trailing); let response = format!("{header_userid}:{trailing}"); - Ok(Response::builder() - .status(200) - .body(response) - .build()) + Ok(Response::builder().status(200).body(response).build()) } diff --git a/tests/test-components/components/integration-wasi-http-streaming/Cargo.toml b/tests/test-components/components/integration-wasi-http-p2-streaming/Cargo.toml similarity index 81% rename from tests/test-components/components/integration-wasi-http-streaming/Cargo.toml rename to tests/test-components/components/integration-wasi-http-p2-streaming/Cargo.toml index e4d0db3712..c3ec6079d0 100644 --- a/tests/test-components/components/integration-wasi-http-streaming/Cargo.toml +++ b/tests/test-components/components/integration-wasi-http-p2-streaming/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "integration-wasi-http-streaming" +name = "integration-wasi-http-p2-streaming" version = "0.1.0" edition = "2021" diff --git a/tests/test-components/components/integration-wasi-http-streaming/src/lib.rs b/tests/test-components/components/integration-wasi-http-p2-streaming/src/lib.rs similarity index 100% rename from tests/test-components/components/integration-wasi-http-streaming/src/lib.rs rename to tests/test-components/components/integration-wasi-http-p2-streaming/src/lib.rs diff --git a/tests/test-components/components/integration-wasi-http-p3-streaming/Cargo.toml b/tests/test-components/components/integration-wasi-http-p3-streaming/Cargo.toml new file mode 100644 index 0000000000..25fc0a2e4c --- /dev/null +++ b/tests/test-components/components/integration-wasi-http-p3-streaming/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "integration-wasi-http-p3-streaming" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +futures = "0.3.31" +hex = "0.4.3" +sha2 = "0.10.9" +url = "2.5.7" +wit-bindgen = { workspace = true } + diff --git a/tests/test-components/components/integration-wasi-http-p3-streaming/src/lib.rs b/tests/test-components/components/integration-wasi-http-p3-streaming/src/lib.rs new file mode 100644 index 0000000000..3174b00900 --- /dev/null +++ b/tests/test-components/components/integration-wasi-http-p3-streaming/src/lib.rs @@ -0,0 +1,191 @@ +#![deny(warnings)] + +wit_bindgen::generate!({ + path: "../../../../wit", + world: "wasi:http/proxy@0.3.0-rc-2025-09-16", + generate_all, + debug: true +}); + +use { + crate::{ + exports::wasi::http0_3_0_rc_2025_09_16::handler::Guest, + wasi::http0_3_0_rc_2025_09_16::{ + handler, + types::{ErrorCode, Fields, Method, Request, Response, Scheme}, + }, + }, + core::mem, + futures::{StreamExt, stream}, + url::Url, + wit_bindgen::{StreamResult, rt::async_support}, +}; + +const MAX_CONCURRENCY: usize = 16; + +struct Component; + +export!(Component); + +impl Guest for Component { + async fn handle(request: Request) -> Result { + let headers = request.get_headers().copy_all(); + + Ok( + match ( + request.get_method(), + request.get_path_with_query().as_deref(), + ) { + (Method::Get, Some("/hash-all")) => { + // Send outgoing GET requests to the specified URLs and stream + // the hashes of the response bodies as they arrive. + + let urls = headers.iter().filter_map(|(k, v)| { + (k == "url") + .then_some(v) + .and_then(|v| std::str::from_utf8(v).ok()) + .and_then(|v| Url::parse(v).ok()) + }); + + let results = urls + .map(|url| async move { + let result = hash(&url).await; + (url, result) + }) + .collect::>(); + + let mut results = stream::iter(results).buffer_unordered(MAX_CONCURRENCY); + let (mut tx, rx) = wit_stream::new(); + async_support::spawn(async move { + while let Some((url, result)) = results.next().await { + tx.write_all( + match result { + Ok(hash) => format!("{url}: {hash}\n"), + Err(e) => format!("{url}: {e:?}\n"), + } + .into_bytes(), + ) + .await; + } + }); + + Response::new( + Fields::from_list(&[("content-type".to_string(), b"text/plain".to_vec())]) + .unwrap(), + Some(rx), + wit_future::new(|| Ok(None)).1, + ) + .0 + } + + (Method::Post, Some("/echo")) => { + // Echo the request body without buffering it. + + let (rx, trailers) = + Request::consume_body(request, wit_future::new(|| Ok(())).1); + Response::new( + Fields::from_list( + &headers + .into_iter() + .filter_map(|(k, v)| (k == "content-type").then_some((k, v))) + .collect::>(), + ) + .unwrap(), + Some(rx), + trailers, + ) + .0 + } + + (Method::Post, Some("/double-echo")) => { + // Pipe the request body to an outgoing request and stream the response back to the client. + + if let Some(url) = headers.iter().find_map(|(k, v)| { + (k == "url") + .then_some(v) + .and_then(|v| std::str::from_utf8(v).ok()) + .and_then(|v| Url::parse(v).ok()) + }) { + let method = request.get_method(); + let (rx, trailers) = + Request::consume_body(request, wit_future::new(|| Ok(())).1); + let outgoing_request = + Request::new(Fields::new(), Some(rx), trailers, None).0; + outgoing_request.set_method(&method).unwrap(); + outgoing_request + .set_path_with_query(Some(url.path())) + .unwrap(); + outgoing_request + .set_scheme(Some(&match url.scheme() { + "http" => Scheme::Http, + "https" => Scheme::Https, + scheme => Scheme::Other(scheme.into()), + })) + .unwrap(); + outgoing_request + .set_authority(Some(url.authority())) + .unwrap(); + handler::handle(outgoing_request).await? + } else { + bad_request() + } + } + + _ => method_not_allowed(), + }, + ) + } +} + +fn bad_request() -> Response { + respond(400) +} + +fn method_not_allowed() -> Response { + respond(405) +} + +fn respond(status: u16) -> Response { + let response = Response::new(Fields::new(), None, wit_future::new(|| Ok(None)).1).0; + response.set_status_code(status).unwrap(); + response +} + +async fn hash(url: &Url) -> Result { + let request = Request::new(Fields::new(), None, wit_future::new(|| Ok(None)).1, None).0; + request.set_path_with_query(Some(url.path())).unwrap(); + request + .set_scheme(Some(&match url.scheme() { + "http" => Scheme::Http, + "https" => Scheme::Https, + scheme => Scheme::Other(scheme.into()), + })) + .unwrap(); + request.set_authority(Some(url.authority())).unwrap(); + + let response = handler::handle(request).await?; + + let status = response.get_status_code(); + + if !(200..300).contains(&status) { + return Err(ErrorCode::InternalError(Some(format!( + "unexpected status: {status}" + )))); + } + + let (mut rx, trailers) = Response::consume_body(response, wit_future::new(|| Ok(())).1); + + use sha2::Digest; + let mut hasher = sha2::Sha256::new(); + let mut buffer = Vec::with_capacity(16 * 1024); + let mut result = StreamResult::Complete(0); + while let StreamResult::Complete(_) = result { + (result, buffer) = rx.read(mem::take(&mut buffer)).await; + hasher.update(&buffer); + buffer.clear(); + } + + trailers.await?; + + Ok(hex::encode(hasher.finalize())) +} diff --git a/tests/test-components/components/integration-wasi-http-v0.2.0-rc-2023-11-10/src/lib.rs b/tests/test-components/components/integration-wasi-http-v0.2.0-rc-2023-11-10/src/lib.rs index ab4f7d0daf..b106ae2e4b 100644 --- a/tests/test-components/components/integration-wasi-http-v0.2.0-rc-2023-11-10/src/lib.rs +++ b/tests/test-components/components/integration-wasi-http-v0.2.0-rc-2023-11-10/src/lib.rs @@ -34,9 +34,7 @@ impl incoming_handler::Guest for Component { .and_then(|v| Url::parse(v).ok()) }) { let headers = Headers::new(); - headers - .append(&"Content-Length".into(), &"13".into()) - .unwrap(); + headers.append("Content-Length", b"13").unwrap(); let outgoing_request = OutgoingRequest::new(headers); outgoing_request.set_method(&Method::Post).unwrap(); outgoing_request diff --git a/tests/test-components/components/integration-wasi-http-v0.2.0/src/lib.rs b/tests/test-components/components/integration-wasi-http-v0.2.0/src/lib.rs index c45100b10d..8e6c2fbaf2 100644 --- a/tests/test-components/components/integration-wasi-http-v0.2.0/src/lib.rs +++ b/tests/test-components/components/integration-wasi-http-v0.2.0/src/lib.rs @@ -34,9 +34,7 @@ impl incoming_handler::Guest for Component { .and_then(|v| Url::parse(v).ok()) }) { let headers = Headers::new(); - headers - .append(&"Content-Length".into(), &"13".into()) - .unwrap(); + headers.append("Content-Length", b"13").unwrap(); let outgoing_request = OutgoingRequest::new(headers); outgoing_request.set_method(&Method::Post).unwrap(); outgoing_request diff --git a/tests/test-components/components/llm/src/lib.rs b/tests/test-components/components/llm/src/lib.rs index 21b3092c14..1a9a2be9eb 100644 --- a/tests/test-components/components/llm/src/lib.rs +++ b/tests/test-components/components/llm/src/lib.rs @@ -13,11 +13,7 @@ impl Component { top_k: 1, top_p: 1.0, }; - let inference = ensure_ok!(llm::infer( - &"llama2-chat".to_owned(), - "say hello", - Some(param) - )); + let inference = ensure_ok!(llm::infer("llama2-chat", "say hello", Some(param))); ensure!(!inference.text.is_empty()); ensure_eq!(inference.usage.generated_token_count, 1); diff --git a/tests/test-components/components/outbound-mqtt/src/lib.rs b/tests/test-components/components/outbound-mqtt/src/lib.rs index 923bad0e95..da06cdea04 100644 --- a/tests/test-components/components/outbound-mqtt/src/lib.rs +++ b/tests/test-components/components/outbound-mqtt/src/lib.rs @@ -24,7 +24,7 @@ impl Component { keep_alive_interval )); - ensure_ok!(connection.publish("telemetry-topic", &b"Eureka!".to_vec(), Qos::AtLeastOnce)); + ensure_ok!(connection.publish("telemetry-topic", b"Eureka!", Qos::AtLeastOnce)); Ok(()) } diff --git a/tests/test-components/components/outbound-postgres/src/lib.rs b/tests/test-components/components/outbound-postgres/src/lib.rs index 5528bd6199..9ad8642cd4 100644 --- a/tests/test-components/components/outbound-postgres/src/lib.rs +++ b/tests/test-components/components/outbound-postgres/src/lib.rs @@ -219,7 +219,11 @@ fn json_types(conn: &postgres::Connection) -> Result"] +description = "An application that makes concurrent outbound HTTP requests." +name = "spin-wasi-http-async" +version = "1.0.0" + +[[trigger.http]] +route = "/..." +component = "wasi-http-async" + +[component.wasi-http-async] +source = "%{source=integration-wasi-http-p3-streaming}" +allowed_outbound_hosts = ["http://*:*", "https://*:*"] +[component.wasi-http-async.build] +command = "cargo build --target wasm32-wasip1 --release" +watch = ["src/**/*.rs", "Cargo.toml"] diff --git a/wit/deps/cli-0.3.0-rc-2025-09-16/command.wit b/wit/deps/cli-0.3.0-rc-2025-09-16/command.wit new file mode 100644 index 0000000000..f2f613e552 --- /dev/null +++ b/wit/deps/cli-0.3.0-rc-2025-09-16/command.wit @@ -0,0 +1,10 @@ +package wasi:cli@0.3.0-rc-2025-09-16; + +@since(version = 0.3.0-rc-2025-09-16) +world command { + @since(version = 0.3.0-rc-2025-09-16) + include imports; + + @since(version = 0.3.0-rc-2025-09-16) + export run; +} diff --git a/wit/deps/cli-0.3.0-rc-2025-09-16/environment.wit b/wit/deps/cli-0.3.0-rc-2025-09-16/environment.wit new file mode 100644 index 0000000000..3763f2f6ce --- /dev/null +++ b/wit/deps/cli-0.3.0-rc-2025-09-16/environment.wit @@ -0,0 +1,22 @@ +@since(version = 0.3.0-rc-2025-09-16) +interface environment { + /// Get the POSIX-style environment variables. + /// + /// Each environment variable is provided as a pair of string variable names + /// and string value. + /// + /// Morally, these are a value import, but until value imports are available + /// in the component model, this import function should return the same + /// values each time it is called. + @since(version = 0.3.0-rc-2025-09-16) + get-environment: func() -> list>; + + /// Get the POSIX-style arguments to the program. + @since(version = 0.3.0-rc-2025-09-16) + get-arguments: func() -> list; + + /// Return a path that programs should use as their initial current working + /// directory, interpreting `.` as shorthand for this. + @since(version = 0.3.0-rc-2025-09-16) + get-initial-cwd: func() -> option; +} diff --git a/wit/deps/cli-0.3.0-rc-2025-09-16/exit.wit b/wit/deps/cli-0.3.0-rc-2025-09-16/exit.wit new file mode 100644 index 0000000000..1efba7d683 --- /dev/null +++ b/wit/deps/cli-0.3.0-rc-2025-09-16/exit.wit @@ -0,0 +1,17 @@ +@since(version = 0.3.0-rc-2025-09-16) +interface exit { + /// Exit the current instance and any linked instances. + @since(version = 0.3.0-rc-2025-09-16) + exit: func(status: result); + + /// Exit the current instance and any linked instances, reporting the + /// specified status code to the host. + /// + /// The meaning of the code depends on the context, with 0 usually meaning + /// "success", and other values indicating various types of failure. + /// + /// This function does not return; the effect is analogous to a trap, but + /// without the connotation that something bad has happened. + @unstable(feature = cli-exit-with-code) + exit-with-code: func(status-code: u8); +} diff --git a/wit/deps/cli-0.3.0-rc-2025-09-16/imports.wit b/wit/deps/cli-0.3.0-rc-2025-09-16/imports.wit new file mode 100644 index 0000000000..660a2dd95a --- /dev/null +++ b/wit/deps/cli-0.3.0-rc-2025-09-16/imports.wit @@ -0,0 +1,34 @@ +package wasi:cli@0.3.0-rc-2025-09-16; + +@since(version = 0.3.0-rc-2025-09-16) +world imports { + @since(version = 0.3.0-rc-2025-09-16) + include wasi:clocks/imports@0.3.0-rc-2025-09-16; + @since(version = 0.3.0-rc-2025-09-16) + include wasi:filesystem/imports@0.3.0-rc-2025-09-16; + @since(version = 0.3.0-rc-2025-09-16) + include wasi:sockets/imports@0.3.0-rc-2025-09-16; + @since(version = 0.3.0-rc-2025-09-16) + include wasi:random/imports@0.3.0-rc-2025-09-16; + + @since(version = 0.3.0-rc-2025-09-16) + import environment; + @since(version = 0.3.0-rc-2025-09-16) + import exit; + @since(version = 0.3.0-rc-2025-09-16) + import stdin; + @since(version = 0.3.0-rc-2025-09-16) + import stdout; + @since(version = 0.3.0-rc-2025-09-16) + import stderr; + @since(version = 0.3.0-rc-2025-09-16) + import terminal-input; + @since(version = 0.3.0-rc-2025-09-16) + import terminal-output; + @since(version = 0.3.0-rc-2025-09-16) + import terminal-stdin; + @since(version = 0.3.0-rc-2025-09-16) + import terminal-stdout; + @since(version = 0.3.0-rc-2025-09-16) + import terminal-stderr; +} diff --git a/wit/deps/cli-0.3.0-rc-2025-09-16/run.wit b/wit/deps/cli-0.3.0-rc-2025-09-16/run.wit new file mode 100644 index 0000000000..631441a3f2 --- /dev/null +++ b/wit/deps/cli-0.3.0-rc-2025-09-16/run.wit @@ -0,0 +1,6 @@ +@since(version = 0.3.0-rc-2025-09-16) +interface run { + /// Run the program. + @since(version = 0.3.0-rc-2025-09-16) + run: async func() -> result; +} diff --git a/wit/deps/cli-0.3.0-rc-2025-09-16/stdio.wit b/wit/deps/cli-0.3.0-rc-2025-09-16/stdio.wit new file mode 100644 index 0000000000..51e5ae4b40 --- /dev/null +++ b/wit/deps/cli-0.3.0-rc-2025-09-16/stdio.wit @@ -0,0 +1,65 @@ +@since(version = 0.3.0-rc-2025-09-16) +interface types { + @since(version = 0.3.0-rc-2025-09-16) + enum error-code { + /// Input/output error + io, + /// Invalid or incomplete multibyte or wide character + illegal-byte-sequence, + /// Broken pipe + pipe, + } +} + +@since(version = 0.3.0-rc-2025-09-16) +interface stdin { + use types.{error-code}; + + /// Return a stream for reading from stdin. + /// + /// This function returns a stream which provides data read from stdin, + /// and a future to signal read results. + /// + /// If the stream's readable end is dropped the future will resolve to success. + /// + /// If the stream's writable end is dropped the future will either resolve to + /// success if stdin was closed by the writer or to an error-code if reading + /// failed for some other reason. + /// + /// Multiple streams may be active at the same time. The behavior of concurrent + /// reads is implementation-specific. + @since(version = 0.3.0-rc-2025-09-16) + read-via-stream: func() -> tuple, future>>; +} + +@since(version = 0.3.0-rc-2025-09-16) +interface stdout { + use types.{error-code}; + + /// Write the given stream to stdout. + /// + /// If the stream's writable end is dropped this function will either return + /// success once the entire contents of the stream have been written or an + /// error-code representing a failure. + /// + /// Otherwise if there is an error the readable end of the stream will be + /// dropped and this function will return an error-code. + @since(version = 0.3.0-rc-2025-09-16) + write-via-stream: async func(data: stream) -> result<_, error-code>; +} + +@since(version = 0.3.0-rc-2025-09-16) +interface stderr { + use types.{error-code}; + + /// Write the given stream to stderr. + /// + /// If the stream's writable end is dropped this function will either return + /// success once the entire contents of the stream have been written or an + /// error-code representing a failure. + /// + /// Otherwise if there is an error the readable end of the stream will be + /// dropped and this function will return an error-code. + @since(version = 0.3.0-rc-2025-09-16) + write-via-stream: async func(data: stream) -> result<_, error-code>; +} diff --git a/wit/deps/cli-0.3.0-rc-2025-09-16/terminal.wit b/wit/deps/cli-0.3.0-rc-2025-09-16/terminal.wit new file mode 100644 index 0000000000..74c17694a4 --- /dev/null +++ b/wit/deps/cli-0.3.0-rc-2025-09-16/terminal.wit @@ -0,0 +1,62 @@ +/// Terminal input. +/// +/// In the future, this may include functions for disabling echoing, +/// disabling input buffering so that keyboard events are sent through +/// immediately, querying supported features, and so on. +@since(version = 0.3.0-rc-2025-09-16) +interface terminal-input { + /// The input side of a terminal. + @since(version = 0.3.0-rc-2025-09-16) + resource terminal-input; +} + +/// Terminal output. +/// +/// In the future, this may include functions for querying the terminal +/// size, being notified of terminal size changes, querying supported +/// features, and so on. +@since(version = 0.3.0-rc-2025-09-16) +interface terminal-output { + /// The output side of a terminal. + @since(version = 0.3.0-rc-2025-09-16) + resource terminal-output; +} + +/// An interface providing an optional `terminal-input` for stdin as a +/// link-time authority. +@since(version = 0.3.0-rc-2025-09-16) +interface terminal-stdin { + @since(version = 0.3.0-rc-2025-09-16) + use terminal-input.{terminal-input}; + + /// If stdin is connected to a terminal, return a `terminal-input` handle + /// allowing further interaction with it. + @since(version = 0.3.0-rc-2025-09-16) + get-terminal-stdin: func() -> option; +} + +/// An interface providing an optional `terminal-output` for stdout as a +/// link-time authority. +@since(version = 0.3.0-rc-2025-09-16) +interface terminal-stdout { + @since(version = 0.3.0-rc-2025-09-16) + use terminal-output.{terminal-output}; + + /// If stdout is connected to a terminal, return a `terminal-output` handle + /// allowing further interaction with it. + @since(version = 0.3.0-rc-2025-09-16) + get-terminal-stdout: func() -> option; +} + +/// An interface providing an optional `terminal-output` for stderr as a +/// link-time authority. +@since(version = 0.3.0-rc-2025-09-16) +interface terminal-stderr { + @since(version = 0.3.0-rc-2025-09-16) + use terminal-output.{terminal-output}; + + /// If stderr is connected to a terminal, return a `terminal-output` handle + /// allowing further interaction with it. + @since(version = 0.3.0-rc-2025-09-16) + get-terminal-stderr: func() -> option; +} diff --git a/wit/deps/clocks-0.3.0-rc-2025-09-16/monotonic-clock.wit b/wit/deps/clocks-0.3.0-rc-2025-09-16/monotonic-clock.wit new file mode 100644 index 0000000000..a91d495c6c --- /dev/null +++ b/wit/deps/clocks-0.3.0-rc-2025-09-16/monotonic-clock.wit @@ -0,0 +1,48 @@ +package wasi:clocks@0.3.0-rc-2025-09-16; +/// WASI Monotonic Clock is a clock API intended to let users measure elapsed +/// time. +/// +/// It is intended to be portable at least between Unix-family platforms and +/// Windows. +/// +/// A monotonic clock is a clock which has an unspecified initial value, and +/// successive reads of the clock will produce non-decreasing values. +@since(version = 0.3.0-rc-2025-09-16) +interface monotonic-clock { + use types.{duration}; + + /// An instant in time, in nanoseconds. An instant is relative to an + /// unspecified initial value, and can only be compared to instances from + /// the same monotonic-clock. + @since(version = 0.3.0-rc-2025-09-16) + type instant = u64; + + /// Read the current value of the clock. + /// + /// The clock is monotonic, therefore calling this function repeatedly will + /// produce a sequence of non-decreasing values. + /// + /// For completeness, this function traps if it's not possible to represent + /// the value of the clock in an `instant`. Consequently, implementations + /// should ensure that the starting time is low enough to avoid the + /// possibility of overflow in practice. + @since(version = 0.3.0-rc-2025-09-16) + now: func() -> instant; + + /// Query the resolution of the clock. Returns the duration of time + /// corresponding to a clock tick. + @since(version = 0.3.0-rc-2025-09-16) + get-resolution: func() -> duration; + + /// Wait until the specified instant has occurred. + @since(version = 0.3.0-rc-2025-09-16) + wait-until: async func( + when: instant, + ); + + /// Wait for the specified duration to elapse. + @since(version = 0.3.0-rc-2025-09-16) + wait-for: async func( + how-long: duration, + ); +} diff --git a/wit/deps/clocks-0.3.0-rc-2025-09-16/timezone.wit b/wit/deps/clocks-0.3.0-rc-2025-09-16/timezone.wit new file mode 100644 index 0000000000..ab8f5c0801 --- /dev/null +++ b/wit/deps/clocks-0.3.0-rc-2025-09-16/timezone.wit @@ -0,0 +1,55 @@ +package wasi:clocks@0.3.0-rc-2025-09-16; + +@unstable(feature = clocks-timezone) +interface timezone { + @unstable(feature = clocks-timezone) + use wall-clock.{datetime}; + + /// Return information needed to display the given `datetime`. This includes + /// the UTC offset, the time zone name, and a flag indicating whether + /// daylight saving time is active. + /// + /// If the timezone cannot be determined for the given `datetime`, return a + /// `timezone-display` for `UTC` with a `utc-offset` of 0 and no daylight + /// saving time. + @unstable(feature = clocks-timezone) + display: func(when: datetime) -> timezone-display; + + /// The same as `display`, but only return the UTC offset. + @unstable(feature = clocks-timezone) + utc-offset: func(when: datetime) -> s32; + + /// Information useful for displaying the timezone of a specific `datetime`. + /// + /// This information may vary within a single `timezone` to reflect daylight + /// saving time adjustments. + @unstable(feature = clocks-timezone) + record timezone-display { + /// The number of seconds difference between UTC time and the local + /// time of the timezone. + /// + /// The returned value will always be less than 86400 which is the + /// number of seconds in a day (24*60*60). + /// + /// In implementations that do not expose an actual time zone, this + /// should return 0. + utc-offset: s32, + + /// The abbreviated name of the timezone to display to a user. The name + /// `UTC` indicates Coordinated Universal Time. Otherwise, this should + /// reference local standards for the name of the time zone. + /// + /// In implementations that do not expose an actual time zone, this + /// should be the string `UTC`. + /// + /// In time zones that do not have an applicable name, a formatted + /// representation of the UTC offset may be returned, such as `-04:00`. + name: string, + + /// Whether daylight saving time is active. + /// + /// In implementations that do not expose an actual time zone, this + /// should return false. + in-daylight-saving-time: bool, + } +} diff --git a/wit/deps/clocks-0.3.0-rc-2025-09-16/types.wit b/wit/deps/clocks-0.3.0-rc-2025-09-16/types.wit new file mode 100644 index 0000000000..aff7c2a22a --- /dev/null +++ b/wit/deps/clocks-0.3.0-rc-2025-09-16/types.wit @@ -0,0 +1,8 @@ +package wasi:clocks@0.3.0-rc-2025-09-16; +/// This interface common types used throughout wasi:clocks. +@since(version = 0.3.0-rc-2025-09-16) +interface types { + /// A duration of time, in nanoseconds. + @since(version = 0.3.0-rc-2025-09-16) + type duration = u64; +} diff --git a/wit/deps/clocks-0.3.0-rc-2025-09-16/wall-clock.wit b/wit/deps/clocks-0.3.0-rc-2025-09-16/wall-clock.wit new file mode 100644 index 0000000000..ea940500fa --- /dev/null +++ b/wit/deps/clocks-0.3.0-rc-2025-09-16/wall-clock.wit @@ -0,0 +1,46 @@ +package wasi:clocks@0.3.0-rc-2025-09-16; +/// WASI Wall Clock is a clock API intended to let users query the current +/// time. The name "wall" makes an analogy to a "clock on the wall", which +/// is not necessarily monotonic as it may be reset. +/// +/// It is intended to be portable at least between Unix-family platforms and +/// Windows. +/// +/// A wall clock is a clock which measures the date and time according to +/// some external reference. +/// +/// External references may be reset, so this clock is not necessarily +/// monotonic, making it unsuitable for measuring elapsed time. +/// +/// It is intended for reporting the current date and time for humans. +@since(version = 0.3.0-rc-2025-09-16) +interface wall-clock { + /// A time and date in seconds plus nanoseconds. + @since(version = 0.3.0-rc-2025-09-16) + record datetime { + seconds: u64, + nanoseconds: u32, + } + + /// Read the current value of the clock. + /// + /// This clock is not monotonic, therefore calling this function repeatedly + /// will not necessarily produce a sequence of non-decreasing values. + /// + /// The returned timestamps represent the number of seconds since + /// 1970-01-01T00:00:00Z, also known as [POSIX's Seconds Since the Epoch], + /// also known as [Unix Time]. + /// + /// The nanoseconds field of the output is always less than 1000000000. + /// + /// [POSIX's Seconds Since the Epoch]: https://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xbd_chap04.html#tag_21_04_16 + /// [Unix Time]: https://en.wikipedia.org/wiki/Unix_time + @since(version = 0.3.0-rc-2025-09-16) + now: func() -> datetime; + + /// Query the resolution of the clock. + /// + /// The nanoseconds field of the output is always less than 1000000000. + @since(version = 0.3.0-rc-2025-09-16) + get-resolution: func() -> datetime; +} diff --git a/wit/deps/clocks-0.3.0-rc-2025-09-16/world.wit b/wit/deps/clocks-0.3.0-rc-2025-09-16/world.wit new file mode 100644 index 0000000000..a6b885f070 --- /dev/null +++ b/wit/deps/clocks-0.3.0-rc-2025-09-16/world.wit @@ -0,0 +1,11 @@ +package wasi:clocks@0.3.0-rc-2025-09-16; + +@since(version = 0.3.0-rc-2025-09-16) +world imports { + @since(version = 0.3.0-rc-2025-09-16) + import monotonic-clock; + @since(version = 0.3.0-rc-2025-09-16) + import wall-clock; + @unstable(feature = clocks-timezone) + import timezone; +} diff --git a/wit/deps/filesystem-0.3.0-rc-2025-09-16/preopens.wit b/wit/deps/filesystem-0.3.0-rc-2025-09-16/preopens.wit new file mode 100644 index 0000000000..9036e90e88 --- /dev/null +++ b/wit/deps/filesystem-0.3.0-rc-2025-09-16/preopens.wit @@ -0,0 +1,11 @@ +package wasi:filesystem@0.3.0-rc-2025-09-16; + +@since(version = 0.3.0-rc-2025-09-16) +interface preopens { + @since(version = 0.3.0-rc-2025-09-16) + use types.{descriptor}; + + /// Return the set of preopened directories, and their paths. + @since(version = 0.3.0-rc-2025-09-16) + get-directories: func() -> list>; +} diff --git a/wit/deps/filesystem-0.3.0-rc-2025-09-16/types.wit b/wit/deps/filesystem-0.3.0-rc-2025-09-16/types.wit new file mode 100644 index 0000000000..41d91beee5 --- /dev/null +++ b/wit/deps/filesystem-0.3.0-rc-2025-09-16/types.wit @@ -0,0 +1,636 @@ +package wasi:filesystem@0.3.0-rc-2025-09-16; +/// WASI filesystem is a filesystem API primarily intended to let users run WASI +/// programs that access their files on their existing filesystems, without +/// significant overhead. +/// +/// It is intended to be roughly portable between Unix-family platforms and +/// Windows, though it does not hide many of the major differences. +/// +/// Paths are passed as interface-type `string`s, meaning they must consist of +/// a sequence of Unicode Scalar Values (USVs). Some filesystems may contain +/// paths which are not accessible by this API. +/// +/// The directory separator in WASI is always the forward-slash (`/`). +/// +/// All paths in WASI are relative paths, and are interpreted relative to a +/// `descriptor` referring to a base directory. If a `path` argument to any WASI +/// function starts with `/`, or if any step of resolving a `path`, including +/// `..` and symbolic link steps, reaches a directory outside of the base +/// directory, or reaches a symlink to an absolute or rooted path in the +/// underlying filesystem, the function fails with `error-code::not-permitted`. +/// +/// For more information about WASI path resolution and sandboxing, see +/// [WASI filesystem path resolution]. +/// +/// [WASI filesystem path resolution]: https://github.com/WebAssembly/wasi-filesystem/blob/main/path-resolution.md +@since(version = 0.3.0-rc-2025-09-16) +interface types { + @since(version = 0.3.0-rc-2025-09-16) + use wasi:clocks/wall-clock@0.3.0-rc-2025-09-16.{datetime}; + + /// File size or length of a region within a file. + @since(version = 0.3.0-rc-2025-09-16) + type filesize = u64; + + /// The type of a filesystem object referenced by a descriptor. + /// + /// Note: This was called `filetype` in earlier versions of WASI. + @since(version = 0.3.0-rc-2025-09-16) + enum descriptor-type { + /// The type of the descriptor or file is unknown or is different from + /// any of the other types specified. + unknown, + /// The descriptor refers to a block device inode. + block-device, + /// The descriptor refers to a character device inode. + character-device, + /// The descriptor refers to a directory inode. + directory, + /// The descriptor refers to a named pipe. + fifo, + /// The file refers to a symbolic link inode. + symbolic-link, + /// The descriptor refers to a regular file inode. + regular-file, + /// The descriptor refers to a socket. + socket, + } + + /// Descriptor flags. + /// + /// Note: This was called `fdflags` in earlier versions of WASI. + @since(version = 0.3.0-rc-2025-09-16) + flags descriptor-flags { + /// Read mode: Data can be read. + read, + /// Write mode: Data can be written to. + write, + /// Request that writes be performed according to synchronized I/O file + /// integrity completion. The data stored in the file and the file's + /// metadata are synchronized. This is similar to `O_SYNC` in POSIX. + /// + /// The precise semantics of this operation have not yet been defined for + /// WASI. At this time, it should be interpreted as a request, and not a + /// requirement. + file-integrity-sync, + /// Request that writes be performed according to synchronized I/O data + /// integrity completion. Only the data stored in the file is + /// synchronized. This is similar to `O_DSYNC` in POSIX. + /// + /// The precise semantics of this operation have not yet been defined for + /// WASI. At this time, it should be interpreted as a request, and not a + /// requirement. + data-integrity-sync, + /// Requests that reads be performed at the same level of integrity + /// requested for writes. This is similar to `O_RSYNC` in POSIX. + /// + /// The precise semantics of this operation have not yet been defined for + /// WASI. At this time, it should be interpreted as a request, and not a + /// requirement. + requested-write-sync, + /// Mutating directories mode: Directory contents may be mutated. + /// + /// When this flag is unset on a descriptor, operations using the + /// descriptor which would create, rename, delete, modify the data or + /// metadata of filesystem objects, or obtain another handle which + /// would permit any of those, shall fail with `error-code::read-only` if + /// they would otherwise succeed. + /// + /// This may only be set on directories. + mutate-directory, + } + + /// File attributes. + /// + /// Note: This was called `filestat` in earlier versions of WASI. + @since(version = 0.3.0-rc-2025-09-16) + record descriptor-stat { + /// File type. + %type: descriptor-type, + /// Number of hard links to the file. + link-count: link-count, + /// For regular files, the file size in bytes. For symbolic links, the + /// length in bytes of the pathname contained in the symbolic link. + size: filesize, + /// Last data access timestamp. + /// + /// If the `option` is none, the platform doesn't maintain an access + /// timestamp for this file. + data-access-timestamp: option, + /// Last data modification timestamp. + /// + /// If the `option` is none, the platform doesn't maintain a + /// modification timestamp for this file. + data-modification-timestamp: option, + /// Last file status-change timestamp. + /// + /// If the `option` is none, the platform doesn't maintain a + /// status-change timestamp for this file. + status-change-timestamp: option, + } + + /// Flags determining the method of how paths are resolved. + @since(version = 0.3.0-rc-2025-09-16) + flags path-flags { + /// As long as the resolved path corresponds to a symbolic link, it is + /// expanded. + symlink-follow, + } + + /// Open flags used by `open-at`. + @since(version = 0.3.0-rc-2025-09-16) + flags open-flags { + /// Create file if it does not exist, similar to `O_CREAT` in POSIX. + create, + /// Fail if not a directory, similar to `O_DIRECTORY` in POSIX. + directory, + /// Fail if file already exists, similar to `O_EXCL` in POSIX. + exclusive, + /// Truncate file to size 0, similar to `O_TRUNC` in POSIX. + truncate, + } + + /// Number of hard links to an inode. + @since(version = 0.3.0-rc-2025-09-16) + type link-count = u64; + + /// When setting a timestamp, this gives the value to set it to. + @since(version = 0.3.0-rc-2025-09-16) + variant new-timestamp { + /// Leave the timestamp set to its previous value. + no-change, + /// Set the timestamp to the current time of the system clock associated + /// with the filesystem. + now, + /// Set the timestamp to the given value. + timestamp(datetime), + } + + /// A directory entry. + record directory-entry { + /// The type of the file referred to by this directory entry. + %type: descriptor-type, + + /// The name of the object. + name: string, + } + + /// Error codes returned by functions, similar to `errno` in POSIX. + /// Not all of these error codes are returned by the functions provided by this + /// API; some are used in higher-level library layers, and others are provided + /// merely for alignment with POSIX. + enum error-code { + /// Permission denied, similar to `EACCES` in POSIX. + access, + /// Connection already in progress, similar to `EALREADY` in POSIX. + already, + /// Bad descriptor, similar to `EBADF` in POSIX. + bad-descriptor, + /// Device or resource busy, similar to `EBUSY` in POSIX. + busy, + /// Resource deadlock would occur, similar to `EDEADLK` in POSIX. + deadlock, + /// Storage quota exceeded, similar to `EDQUOT` in POSIX. + quota, + /// File exists, similar to `EEXIST` in POSIX. + exist, + /// File too large, similar to `EFBIG` in POSIX. + file-too-large, + /// Illegal byte sequence, similar to `EILSEQ` in POSIX. + illegal-byte-sequence, + /// Operation in progress, similar to `EINPROGRESS` in POSIX. + in-progress, + /// Interrupted function, similar to `EINTR` in POSIX. + interrupted, + /// Invalid argument, similar to `EINVAL` in POSIX. + invalid, + /// I/O error, similar to `EIO` in POSIX. + io, + /// Is a directory, similar to `EISDIR` in POSIX. + is-directory, + /// Too many levels of symbolic links, similar to `ELOOP` in POSIX. + loop, + /// Too many links, similar to `EMLINK` in POSIX. + too-many-links, + /// Message too large, similar to `EMSGSIZE` in POSIX. + message-size, + /// Filename too long, similar to `ENAMETOOLONG` in POSIX. + name-too-long, + /// No such device, similar to `ENODEV` in POSIX. + no-device, + /// No such file or directory, similar to `ENOENT` in POSIX. + no-entry, + /// No locks available, similar to `ENOLCK` in POSIX. + no-lock, + /// Not enough space, similar to `ENOMEM` in POSIX. + insufficient-memory, + /// No space left on device, similar to `ENOSPC` in POSIX. + insufficient-space, + /// Not a directory or a symbolic link to a directory, similar to `ENOTDIR` in POSIX. + not-directory, + /// Directory not empty, similar to `ENOTEMPTY` in POSIX. + not-empty, + /// State not recoverable, similar to `ENOTRECOVERABLE` in POSIX. + not-recoverable, + /// Not supported, similar to `ENOTSUP` and `ENOSYS` in POSIX. + unsupported, + /// Inappropriate I/O control operation, similar to `ENOTTY` in POSIX. + no-tty, + /// No such device or address, similar to `ENXIO` in POSIX. + no-such-device, + /// Value too large to be stored in data type, similar to `EOVERFLOW` in POSIX. + overflow, + /// Operation not permitted, similar to `EPERM` in POSIX. + not-permitted, + /// Broken pipe, similar to `EPIPE` in POSIX. + pipe, + /// Read-only file system, similar to `EROFS` in POSIX. + read-only, + /// Invalid seek, similar to `ESPIPE` in POSIX. + invalid-seek, + /// Text file busy, similar to `ETXTBSY` in POSIX. + text-file-busy, + /// Cross-device link, similar to `EXDEV` in POSIX. + cross-device, + } + + /// File or memory access pattern advisory information. + @since(version = 0.3.0-rc-2025-09-16) + enum advice { + /// The application has no advice to give on its behavior with respect + /// to the specified data. + normal, + /// The application expects to access the specified data sequentially + /// from lower offsets to higher offsets. + sequential, + /// The application expects to access the specified data in a random + /// order. + random, + /// The application expects to access the specified data in the near + /// future. + will-need, + /// The application expects that it will not access the specified data + /// in the near future. + dont-need, + /// The application expects to access the specified data once and then + /// not reuse it thereafter. + no-reuse, + } + + /// A 128-bit hash value, split into parts because wasm doesn't have a + /// 128-bit integer type. + @since(version = 0.3.0-rc-2025-09-16) + record metadata-hash-value { + /// 64 bits of a 128-bit hash value. + lower: u64, + /// Another 64 bits of a 128-bit hash value. + upper: u64, + } + + /// A descriptor is a reference to a filesystem object, which may be a file, + /// directory, named pipe, special file, or other object on which filesystem + /// calls may be made. + @since(version = 0.3.0-rc-2025-09-16) + resource descriptor { + /// Return a stream for reading from a file. + /// + /// Multiple read, write, and append streams may be active on the same open + /// file and they do not interfere with each other. + /// + /// This function returns a `stream` which provides the data received from the + /// file, and a `future` providing additional error information in case an + /// error is encountered. + /// + /// If no error is encountered, `stream.read` on the `stream` will return + /// `read-status::closed` with no `error-context` and the future resolves to + /// the value `ok`. If an error is encountered, `stream.read` on the + /// `stream` returns `read-status::closed` with an `error-context` and the future + /// resolves to `err` with an `error-code`. + /// + /// Note: This is similar to `pread` in POSIX. + @since(version = 0.3.0-rc-2025-09-16) + read-via-stream: func( + /// The offset within the file at which to start reading. + offset: filesize, + ) -> tuple, future>>; + + /// Return a stream for writing to a file, if available. + /// + /// May fail with an error-code describing why the file cannot be written. + /// + /// It is valid to write past the end of a file; the file is extended to the + /// extent of the write, with bytes between the previous end and the start of + /// the write set to zero. + /// + /// This function returns once either full contents of the stream are + /// written or an error is encountered. + /// + /// Note: This is similar to `pwrite` in POSIX. + @since(version = 0.3.0-rc-2025-09-16) + write-via-stream: async func( + /// Data to write + data: stream, + /// The offset within the file at which to start writing. + offset: filesize, + ) -> result<_, error-code>; + + /// Return a stream for appending to a file, if available. + /// + /// May fail with an error-code describing why the file cannot be appended. + /// + /// This function returns once either full contents of the stream are + /// written or an error is encountered. + /// + /// Note: This is similar to `write` with `O_APPEND` in POSIX. + @since(version = 0.3.0-rc-2025-09-16) + append-via-stream: async func(data: stream) -> result<_, error-code>; + + /// Provide file advisory information on a descriptor. + /// + /// This is similar to `posix_fadvise` in POSIX. + @since(version = 0.3.0-rc-2025-09-16) + advise: async func( + /// The offset within the file to which the advisory applies. + offset: filesize, + /// The length of the region to which the advisory applies. + length: filesize, + /// The advice. + advice: advice + ) -> result<_, error-code>; + + /// Synchronize the data of a file to disk. + /// + /// This function succeeds with no effect if the file descriptor is not + /// opened for writing. + /// + /// Note: This is similar to `fdatasync` in POSIX. + @since(version = 0.3.0-rc-2025-09-16) + sync-data: async func() -> result<_, error-code>; + + /// Get flags associated with a descriptor. + /// + /// Note: This returns similar flags to `fcntl(fd, F_GETFL)` in POSIX. + /// + /// Note: This returns the value that was the `fs_flags` value returned + /// from `fdstat_get` in earlier versions of WASI. + @since(version = 0.3.0-rc-2025-09-16) + get-flags: async func() -> result; + + /// Get the dynamic type of a descriptor. + /// + /// Note: This returns the same value as the `type` field of the `fd-stat` + /// returned by `stat`, `stat-at` and similar. + /// + /// Note: This returns similar flags to the `st_mode & S_IFMT` value provided + /// by `fstat` in POSIX. + /// + /// Note: This returns the value that was the `fs_filetype` value returned + /// from `fdstat_get` in earlier versions of WASI. + @since(version = 0.3.0-rc-2025-09-16) + get-type: async func() -> result; + + /// Adjust the size of an open file. If this increases the file's size, the + /// extra bytes are filled with zeros. + /// + /// Note: This was called `fd_filestat_set_size` in earlier versions of WASI. + @since(version = 0.3.0-rc-2025-09-16) + set-size: async func(size: filesize) -> result<_, error-code>; + + /// Adjust the timestamps of an open file or directory. + /// + /// Note: This is similar to `futimens` in POSIX. + /// + /// Note: This was called `fd_filestat_set_times` in earlier versions of WASI. + @since(version = 0.3.0-rc-2025-09-16) + set-times: async func( + /// The desired values of the data access timestamp. + data-access-timestamp: new-timestamp, + /// The desired values of the data modification timestamp. + data-modification-timestamp: new-timestamp, + ) -> result<_, error-code>; + + /// Read directory entries from a directory. + /// + /// On filesystems where directories contain entries referring to themselves + /// and their parents, often named `.` and `..` respectively, these entries + /// are omitted. + /// + /// This always returns a new stream which starts at the beginning of the + /// directory. Multiple streams may be active on the same directory, and they + /// do not interfere with each other. + /// + /// This function returns a future, which will resolve to an error code if + /// reading full contents of the directory fails. + @since(version = 0.3.0-rc-2025-09-16) + read-directory: async func() -> tuple, future>>; + + /// Synchronize the data and metadata of a file to disk. + /// + /// This function succeeds with no effect if the file descriptor is not + /// opened for writing. + /// + /// Note: This is similar to `fsync` in POSIX. + @since(version = 0.3.0-rc-2025-09-16) + sync: async func() -> result<_, error-code>; + + /// Create a directory. + /// + /// Note: This is similar to `mkdirat` in POSIX. + @since(version = 0.3.0-rc-2025-09-16) + create-directory-at: async func( + /// The relative path at which to create the directory. + path: string, + ) -> result<_, error-code>; + + /// Return the attributes of an open file or directory. + /// + /// Note: This is similar to `fstat` in POSIX, except that it does not return + /// device and inode information. For testing whether two descriptors refer to + /// the same underlying filesystem object, use `is-same-object`. To obtain + /// additional data that can be used do determine whether a file has been + /// modified, use `metadata-hash`. + /// + /// Note: This was called `fd_filestat_get` in earlier versions of WASI. + @since(version = 0.3.0-rc-2025-09-16) + stat: async func() -> result; + + /// Return the attributes of a file or directory. + /// + /// Note: This is similar to `fstatat` in POSIX, except that it does not + /// return device and inode information. See the `stat` description for a + /// discussion of alternatives. + /// + /// Note: This was called `path_filestat_get` in earlier versions of WASI. + @since(version = 0.3.0-rc-2025-09-16) + stat-at: async func( + /// Flags determining the method of how the path is resolved. + path-flags: path-flags, + /// The relative path of the file or directory to inspect. + path: string, + ) -> result; + + /// Adjust the timestamps of a file or directory. + /// + /// Note: This is similar to `utimensat` in POSIX. + /// + /// Note: This was called `path_filestat_set_times` in earlier versions of + /// WASI. + @since(version = 0.3.0-rc-2025-09-16) + set-times-at: async func( + /// Flags determining the method of how the path is resolved. + path-flags: path-flags, + /// The relative path of the file or directory to operate on. + path: string, + /// The desired values of the data access timestamp. + data-access-timestamp: new-timestamp, + /// The desired values of the data modification timestamp. + data-modification-timestamp: new-timestamp, + ) -> result<_, error-code>; + + /// Create a hard link. + /// + /// Fails with `error-code::no-entry` if the old path does not exist, + /// with `error-code::exist` if the new path already exists, and + /// `error-code::not-permitted` if the old path is not a file. + /// + /// Note: This is similar to `linkat` in POSIX. + @since(version = 0.3.0-rc-2025-09-16) + link-at: async func( + /// Flags determining the method of how the path is resolved. + old-path-flags: path-flags, + /// The relative source path from which to link. + old-path: string, + /// The base directory for `new-path`. + new-descriptor: borrow, + /// The relative destination path at which to create the hard link. + new-path: string, + ) -> result<_, error-code>; + + /// Open a file or directory. + /// + /// If `flags` contains `descriptor-flags::mutate-directory`, and the base + /// descriptor doesn't have `descriptor-flags::mutate-directory` set, + /// `open-at` fails with `error-code::read-only`. + /// + /// If `flags` contains `write` or `mutate-directory`, or `open-flags` + /// contains `truncate` or `create`, and the base descriptor doesn't have + /// `descriptor-flags::mutate-directory` set, `open-at` fails with + /// `error-code::read-only`. + /// + /// Note: This is similar to `openat` in POSIX. + @since(version = 0.3.0-rc-2025-09-16) + open-at: async func( + /// Flags determining the method of how the path is resolved. + path-flags: path-flags, + /// The relative path of the object to open. + path: string, + /// The method by which to open the file. + open-flags: open-flags, + /// Flags to use for the resulting descriptor. + %flags: descriptor-flags, + ) -> result; + + /// Read the contents of a symbolic link. + /// + /// If the contents contain an absolute or rooted path in the underlying + /// filesystem, this function fails with `error-code::not-permitted`. + /// + /// Note: This is similar to `readlinkat` in POSIX. + @since(version = 0.3.0-rc-2025-09-16) + readlink-at: async func( + /// The relative path of the symbolic link from which to read. + path: string, + ) -> result; + + /// Remove a directory. + /// + /// Return `error-code::not-empty` if the directory is not empty. + /// + /// Note: This is similar to `unlinkat(fd, path, AT_REMOVEDIR)` in POSIX. + @since(version = 0.3.0-rc-2025-09-16) + remove-directory-at: async func( + /// The relative path to a directory to remove. + path: string, + ) -> result<_, error-code>; + + /// Rename a filesystem object. + /// + /// Note: This is similar to `renameat` in POSIX. + @since(version = 0.3.0-rc-2025-09-16) + rename-at: async func( + /// The relative source path of the file or directory to rename. + old-path: string, + /// The base directory for `new-path`. + new-descriptor: borrow, + /// The relative destination path to which to rename the file or directory. + new-path: string, + ) -> result<_, error-code>; + + /// Create a symbolic link (also known as a "symlink"). + /// + /// If `old-path` starts with `/`, the function fails with + /// `error-code::not-permitted`. + /// + /// Note: This is similar to `symlinkat` in POSIX. + @since(version = 0.3.0-rc-2025-09-16) + symlink-at: async func( + /// The contents of the symbolic link. + old-path: string, + /// The relative destination path at which to create the symbolic link. + new-path: string, + ) -> result<_, error-code>; + + /// Unlink a filesystem object that is not a directory. + /// + /// Return `error-code::is-directory` if the path refers to a directory. + /// Note: This is similar to `unlinkat(fd, path, 0)` in POSIX. + @since(version = 0.3.0-rc-2025-09-16) + unlink-file-at: async func( + /// The relative path to a file to unlink. + path: string, + ) -> result<_, error-code>; + + /// Test whether two descriptors refer to the same filesystem object. + /// + /// In POSIX, this corresponds to testing whether the two descriptors have the + /// same device (`st_dev`) and inode (`st_ino` or `d_ino`) numbers. + /// wasi-filesystem does not expose device and inode numbers, so this function + /// may be used instead. + @since(version = 0.3.0-rc-2025-09-16) + is-same-object: async func(other: borrow) -> bool; + + /// Return a hash of the metadata associated with a filesystem object referred + /// to by a descriptor. + /// + /// This returns a hash of the last-modification timestamp and file size, and + /// may also include the inode number, device number, birth timestamp, and + /// other metadata fields that may change when the file is modified or + /// replaced. It may also include a secret value chosen by the + /// implementation and not otherwise exposed. + /// + /// Implementations are encouraged to provide the following properties: + /// + /// - If the file is not modified or replaced, the computed hash value should + /// usually not change. + /// - If the object is modified or replaced, the computed hash value should + /// usually change. + /// - The inputs to the hash should not be easily computable from the + /// computed hash. + /// + /// However, none of these is required. + @since(version = 0.3.0-rc-2025-09-16) + metadata-hash: async func() -> result; + + /// Return a hash of the metadata associated with a filesystem object referred + /// to by a directory descriptor and a relative path. + /// + /// This performs the same hash computation as `metadata-hash`. + @since(version = 0.3.0-rc-2025-09-16) + metadata-hash-at: async func( + /// Flags determining the method of how the path is resolved. + path-flags: path-flags, + /// The relative path of the file or directory to inspect. + path: string, + ) -> result; + } +} diff --git a/wit/deps/filesystem-0.3.0-rc-2025-09-16/world.wit b/wit/deps/filesystem-0.3.0-rc-2025-09-16/world.wit new file mode 100644 index 0000000000..87fc727165 --- /dev/null +++ b/wit/deps/filesystem-0.3.0-rc-2025-09-16/world.wit @@ -0,0 +1,9 @@ +package wasi:filesystem@0.3.0-rc-2025-09-16; + +@since(version = 0.3.0-rc-2025-09-16) +world imports { + @since(version = 0.3.0-rc-2025-09-16) + import types; + @since(version = 0.3.0-rc-2025-09-16) + import preopens; +} diff --git a/wit/deps/http-0.3.0-rc-2025-09-16/handler.wit b/wit/deps/http-0.3.0-rc-2025-09-16/handler.wit new file mode 100644 index 0000000000..e4446cbecf --- /dev/null +++ b/wit/deps/http-0.3.0-rc-2025-09-16/handler.wit @@ -0,0 +1,17 @@ +/// This interface defines a handler of HTTP Requests. It may be imported by +/// components which wish to send HTTP Requests and also exported by components +/// which can respond to HTTP Requests. In addition, it may be used to pass +/// a request from one component to another without any use of a network. +interface handler { + use types.{request, response, error-code}; + + /// When exported, this function may be called with either an incoming + /// request read from the network or a request synthesized or forwarded by + /// another component. + /// + /// When imported, this function may be used to either send an outgoing + /// request over the network or pass it to another component. + handle: async func( + request: request, + ) -> result; +} diff --git a/wit/deps/http-0.3.0-rc-2025-09-16/proxy.wit b/wit/deps/http-0.3.0-rc-2025-09-16/proxy.wit new file mode 100644 index 0000000000..223083ea28 --- /dev/null +++ b/wit/deps/http-0.3.0-rc-2025-09-16/proxy.wit @@ -0,0 +1,44 @@ +package wasi:http@0.3.0-rc-2025-09-16; + +/// The `wasi:http/imports` world imports all the APIs for HTTP proxies. +/// It is intended to be `include`d in other worlds. +world imports { + /// HTTP proxies have access to time and randomness. + include wasi:clocks/imports@0.3.0-rc-2025-09-16; + import wasi:random/random@0.3.0-rc-2025-09-16; + + /// Proxies have standard output and error streams which are expected to + /// terminate in a developer-facing console provided by the host. + import wasi:cli/stdout@0.3.0-rc-2025-09-16; + import wasi:cli/stderr@0.3.0-rc-2025-09-16; + + /// TODO: this is a temporary workaround until component tooling is able to + /// gracefully handle the absence of stdin. Hosts must return an eof stream + /// for this import, which is what wasi-libc + tooling will do automatically + /// when this import is properly removed. + import wasi:cli/stdin@0.3.0-rc-2025-09-16; + + /// This is the default handler to use when user code simply wants to make an + /// HTTP request (e.g., via `fetch()`). + /// + /// This may also be used to pass synthesized or forwarded requests to another + /// component. + import handler; +} + +/// The `wasi:http/proxy` world captures a widely-implementable intersection of +/// hosts that includes HTTP forward and reverse proxies. Components targeting +/// this world may concurrently stream in and out any number of incoming and +/// outgoing HTTP requests. +world proxy { + include imports; + + /// The host delivers incoming HTTP requests to a component by calling the + /// `handle` function of this exported interface. A host may arbitrarily reuse + /// or not reuse component instance when delivering incoming HTTP requests and + /// thus a component must be able to handle 0..N calls to `handle`. + /// + /// This may also be used to receive synthesized or forwarded requests from + /// another component. + export handler; +} diff --git a/wit/deps/http-0.3.0-rc-2025-09-16/types.wit b/wit/deps/http-0.3.0-rc-2025-09-16/types.wit new file mode 100644 index 0000000000..8269eea202 --- /dev/null +++ b/wit/deps/http-0.3.0-rc-2025-09-16/types.wit @@ -0,0 +1,419 @@ +/// This interface defines all of the types and methods for implementing HTTP +/// Requests and Responses, as well as their headers, trailers, and bodies. +interface types { + use wasi:clocks/monotonic-clock@0.3.0-rc-2025-09-16.{duration}; + + /// This type corresponds to HTTP standard Methods. + variant method { + get, + head, + post, + put, + delete, + connect, + options, + trace, + patch, + other(string) + } + + /// This type corresponds to HTTP standard Related Schemes. + variant scheme { + HTTP, + HTTPS, + other(string) + } + + /// These cases are inspired by the IANA HTTP Proxy Error Types: + /// + variant error-code { + DNS-timeout, + DNS-error(DNS-error-payload), + destination-not-found, + destination-unavailable, + destination-IP-prohibited, + destination-IP-unroutable, + connection-refused, + connection-terminated, + connection-timeout, + connection-read-timeout, + connection-write-timeout, + connection-limit-reached, + TLS-protocol-error, + TLS-certificate-error, + TLS-alert-received(TLS-alert-received-payload), + HTTP-request-denied, + HTTP-request-length-required, + HTTP-request-body-size(option), + HTTP-request-method-invalid, + HTTP-request-URI-invalid, + HTTP-request-URI-too-long, + HTTP-request-header-section-size(option), + HTTP-request-header-size(option), + HTTP-request-trailer-section-size(option), + HTTP-request-trailer-size(field-size-payload), + HTTP-response-incomplete, + HTTP-response-header-section-size(option), + HTTP-response-header-size(field-size-payload), + HTTP-response-body-size(option), + HTTP-response-trailer-section-size(option), + HTTP-response-trailer-size(field-size-payload), + HTTP-response-transfer-coding(option), + HTTP-response-content-coding(option), + HTTP-response-timeout, + HTTP-upgrade-failed, + HTTP-protocol-error, + loop-detected, + configuration-error, + /// This is a catch-all error for anything that doesn't fit cleanly into a + /// more specific case. It also includes an optional string for an + /// unstructured description of the error. Users should not depend on the + /// string for diagnosing errors, as it's not required to be consistent + /// between implementations. + internal-error(option) + } + + /// Defines the case payload type for `DNS-error` above: + record DNS-error-payload { + rcode: option, + info-code: option + } + + /// Defines the case payload type for `TLS-alert-received` above: + record TLS-alert-received-payload { + alert-id: option, + alert-message: option + } + + /// Defines the case payload type for `HTTP-response-{header,trailer}-size` above: + record field-size-payload { + field-name: option, + field-size: option + } + + /// This type enumerates the different kinds of errors that may occur when + /// setting or appending to a `fields` resource. + variant header-error { + /// This error indicates that a `field-name` or `field-value` was + /// syntactically invalid when used with an operation that sets headers in a + /// `fields`. + invalid-syntax, + + /// This error indicates that a forbidden `field-name` was used when trying + /// to set a header in a `fields`. + forbidden, + + /// This error indicates that the operation on the `fields` was not + /// 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 { + /// Indicates the specified field is not supported by this implementation. + not-supported, + + /// Indicates that the operation on the `request-options` was not permitted + /// because it is immutable. + immutable, + } + + /// Field names are always strings. + /// + /// Field names should always be treated as case insensitive by the `fields` + /// resource for the purposes of equality checking. + type field-name = string; + + /// Field values should always be ASCII strings. However, in + /// reality, HTTP implementations often have to interpret malformed values, + /// so they are provided as a list of bytes. + type field-value = list; + + /// This following block defines the `fields` resource which corresponds to + /// HTTP standard Fields. Fields are a common representation used for both + /// Headers and Trailers. + /// + /// A `fields` may be mutable or immutable. A `fields` created using the + /// constructor, `from-list`, or `clone` will be mutable, but a `fields` + /// resource given by other means (including, but not limited to, + /// `request.headers`) might be be immutable. In an immutable fields, the + /// `set`, `append`, and `delete` operations will fail with + /// `header-error.immutable`. + /// + /// A `fields` resource should store `field-name`s and `field-value`s in their + /// original casing used to construct or mutate the `fields` resource. The `fields` + /// resource should use that original casing when serializing the fields for + /// transport or when returning them from a method. + resource fields { + + /// Construct an empty HTTP Fields. + /// + /// The resulting `fields` is mutable. + constructor(); + + /// Construct an HTTP Fields. + /// + /// The resulting `fields` is mutable. + /// + /// The list represents each name-value pair in the Fields. Names + /// which have multiple values are represented by multiple entries in this + /// list with the same name. + /// + /// The tuple is a pair of the field name, represented as a string, and + /// Value, represented as a list of bytes. In a valid Fields, all names + /// and values are valid UTF-8 strings. However, values are not always + /// well-formed, so they are represented as a raw list of bytes. + /// + /// An error result will be returned if any header or value was + /// syntactically invalid, or if a header was forbidden. + from-list: static func( + entries: list> + ) -> result; + + /// Get all of the values corresponding to a name. If the name is not present + /// in this `fields`, an empty list is returned. However, if the name is + /// present but empty, this is represented by a list with one or more + /// empty field-values present. + get: func(name: field-name) -> list; + + /// Returns `true` when the name is present in this `fields`. If the name is + /// syntactically invalid, `false` is returned. + has: func(name: field-name) -> bool; + + /// Set all of the values for a name. Clears any existing values for that + /// name, if they have been set. + /// + /// Fails with `header-error.immutable` if the `fields` are immutable. + set: func(name: field-name, value: list) -> result<_, header-error>; + + /// Delete all values for a name. Does nothing if no values for the name + /// exist. + /// + /// Fails with `header-error.immutable` if the `fields` are immutable. + delete: func(name: field-name) -> result<_, header-error>; + + /// Delete all values for a name. Does nothing if no values for the name + /// exist. + /// + /// Returns all values previously corresponding to the name, if any. + /// + /// Fails with `header-error.immutable` if the `fields` are immutable. + get-and-delete: func(name: field-name) -> result, header-error>; + + /// Append a value for a name. Does not change or delete any existing + /// values for that name. + /// + /// Fails with `header-error.immutable` if the `fields` are immutable. + append: func(name: field-name, value: field-value) -> result<_, header-error>; + + /// Retrieve the full set of names and values in the Fields. Like the + /// constructor, the list represents each name-value pair. + /// + /// The outer list represents each name-value pair in the Fields. Names + /// which have multiple values are represented by multiple entries in this + /// list with the same name. + /// + /// The names and values are always returned in the original casing and in + /// the order in which they will be serialized for transport. + copy-all: func() -> list>; + + /// Make a deep copy of the Fields. Equivalent in behavior to calling the + /// `fields` constructor on the return value of `copy-all`. The resulting + /// `fields` is mutable. + clone: func() -> fields; + } + + /// Headers is an alias for Fields. + type headers = fields; + + /// Trailers is an alias for Fields. + type trailers = fields; + + /// Represents an HTTP Request. + resource request { + + /// Construct a new `request` with a default `method` of `GET`, and + /// `none` values for `path-with-query`, `scheme`, and `authority`. + /// + /// `headers` is the HTTP Headers for the Request. + /// + /// `contents` is the optional body content stream with `none` + /// representing a zero-length content stream. + /// Once it is closed, `trailers` future must resolve to a result. + /// If `trailers` resolves to an error, underlying connection + /// will be closed immediately. + /// + /// `options` is optional `request-options` resource to be used + /// if the request is sent over a network connection. + /// + /// It is possible to construct, or manipulate with the accessor functions + /// below, a `request` with an invalid combination of `scheme` + /// and `authority`, or `headers` which are not permitted to be sent. + /// It is the obligation of the `handler.handle` implementation + /// to reject invalid constructions of `request`. + /// + /// The returned future resolves to result of transmission of this request. + new: static func( + headers: headers, + contents: option>, + trailers: future, error-code>>, + options: option + ) -> tuple>>; + + /// Get the Method for the Request. + get-method: func() -> method; + /// Set the Method for the Request. Fails if the string present in a + /// `method.other` argument is not a syntactically valid method. + set-method: func(method: method) -> result; + + /// Get the combination of the HTTP Path and Query for the Request. When + /// `none`, this represents an empty Path and empty Query. + get-path-with-query: func() -> option; + /// Set the combination of the HTTP Path and Query for the Request. When + /// `none`, this represents an empty Path and empty Query. Fails is the + /// string given is not a syntactically valid path and query uri component. + set-path-with-query: func(path-with-query: option) -> result; + + /// Get the HTTP Related Scheme for the Request. When `none`, the + /// implementation may choose an appropriate default scheme. + get-scheme: func() -> option; + /// Set the HTTP Related Scheme for the Request. When `none`, the + /// implementation may choose an appropriate default scheme. Fails if the + /// string given is not a syntactically valid uri scheme. + set-scheme: func(scheme: option) -> result; + + /// Get the authority of the Request's target URI. A value of `none` may be used + /// with Related Schemes which do not require an authority. The HTTP and + /// HTTPS schemes always require an authority. + get-authority: func() -> option; + /// Set the authority of the Request's target URI. A value of `none` may be used + /// with Related Schemes which do not require an authority. The HTTP and + /// HTTPS schemes always require an authority. Fails if the string given is + /// not a syntactically valid URI authority. + set-authority: func(authority: option) -> result; + + /// Get the `request-options` to be associated with this request + /// + /// The returned `request-options` resource is immutable: `set-*` operations + /// will fail if invoked. + /// + /// This `request-options` resource is a child: it must be dropped before + /// the parent `request` is dropped, or its ownership is transferred to + /// another component by e.g. `handler.handle`. + get-options: func() -> option; + + /// Get the headers associated with the Request. + /// + /// The returned `headers` resource is immutable: `set`, `append`, and + /// `delete` operations will fail with `header-error.immutable`. + get-headers: func() -> headers; + + /// Get body of the Request. + /// + /// Stream returned by this method represents the contents of the body. + /// Once the stream is reported as closed, callers should await the returned + /// future to determine whether the body was received successfully. + /// The future will only resolve after the stream is reported as closed. + /// + /// This function takes a `res` future as a parameter, which can be used to + /// communicate an error in handling of the request. + /// + /// Note that function will move the `request`, but references to headers or + /// request options acquired from it previously will remain valid. + consume-body: static func(this: request, res: future>) -> tuple, future, error-code>>>; + } + + /// Parameters for making an HTTP Request. Each of these parameters is + /// currently an optional timeout applicable to the transport layer of the + /// HTTP protocol. + /// + /// These timeouts are separate from any the user may use to bound an + /// asynchronous call. + resource request-options { + /// Construct a default `request-options` value. + constructor(); + + /// The timeout for the initial connect to the HTTP Server. + get-connect-timeout: func() -> option; + + /// Set the timeout for the initial connect to the HTTP Server. An error + /// return value indicates that this timeout is not supported or that this + /// handle is immutable. + set-connect-timeout: func(duration: option) -> result<_, request-options-error>; + + /// The timeout for receiving the first byte of the Response body. + get-first-byte-timeout: func() -> option; + + /// Set the timeout for receiving the first byte of the Response body. An + /// error return value indicates that this timeout is not supported or that + /// this handle is immutable. + set-first-byte-timeout: func(duration: option) -> result<_, request-options-error>; + + /// The timeout for receiving subsequent chunks of bytes in the Response + /// body stream. + get-between-bytes-timeout: func() -> option; + + /// 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 or that this handle is immutable. + set-between-bytes-timeout: func(duration: option) -> result<_, request-options-error>; + + /// Make a deep copy of the `request-options`. + /// The resulting `request-options` is mutable. + clone: func() -> request-options; + } + + /// This type corresponds to the HTTP standard Status Code. + type status-code = u16; + + /// Represents an HTTP Response. + resource response { + + /// Construct a new `response`, with a default `status-code` of `200`. + /// If a different `status-code` is needed, it must be set via the + /// `set-status-code` method. + /// + /// `headers` is the HTTP Headers for the Response. + /// + /// `contents` is the optional body content stream with `none` + /// representing a zero-length content stream. + /// Once it is closed, `trailers` future must resolve to a result. + /// If `trailers` resolves to an error, underlying connection + /// will be closed immediately. + /// + /// The returned future resolves to result of transmission of this response. + new: static func( + headers: headers, + contents: option>, + trailers: future, error-code>>, + ) -> tuple>>; + + /// Get the HTTP Status Code for the Response. + get-status-code: func() -> status-code; + + /// Set the HTTP Status Code for the Response. Fails if the status-code + /// given is not a valid http status code. + set-status-code: func(status-code: status-code) -> result; + + /// Get the headers associated with the Response. + /// + /// The returned `headers` resource is immutable: `set`, `append`, and + /// `delete` operations will fail with `header-error.immutable`. + get-headers: func() -> headers; + + /// Get body of the Response. + /// + /// Stream returned by this method represents the contents of the body. + /// Once the stream is reported as closed, callers should await the returned + /// future to determine whether the body was received successfully. + /// The future will only resolve after the stream is reported as closed. + /// + /// This function takes a `res` future as a parameter, which can be used to + /// communicate an error in handling of the response. + /// + /// Note that function will move the `response`, but references to headers + /// acquired from it previously will remain valid. + consume-body: static func(this: response, res: future>) -> tuple, future, error-code>>>; + } +} diff --git a/wit/deps/random-0.3.0-rc-2025-09-16/insecure-seed.wit b/wit/deps/random-0.3.0-rc-2025-09-16/insecure-seed.wit new file mode 100644 index 0000000000..302151ba65 --- /dev/null +++ b/wit/deps/random-0.3.0-rc-2025-09-16/insecure-seed.wit @@ -0,0 +1,27 @@ +package wasi:random@0.3.0-rc-2025-09-16; +/// The insecure-seed interface for seeding hash-map DoS resistance. +/// +/// It is intended to be portable at least between Unix-family platforms and +/// Windows. +@since(version = 0.3.0-rc-2025-09-16) +interface insecure-seed { + /// Return a 128-bit value that may contain a pseudo-random value. + /// + /// The returned value is not required to be computed from a CSPRNG, and may + /// even be entirely deterministic. Host implementations are encouraged to + /// provide pseudo-random values to any program exposed to + /// attacker-controlled content, to enable DoS protection built into many + /// languages' hash-map implementations. + /// + /// This function is intended to only be called once, by a source language + /// to initialize Denial Of Service (DoS) protection in its hash-map + /// implementation. + /// + /// # Expected future evolution + /// + /// This will likely be changed to a value import, to prevent it from being + /// called multiple times and potentially used for purposes other than DoS + /// protection. + @since(version = 0.3.0-rc-2025-09-16) + get-insecure-seed: func() -> tuple; +} diff --git a/wit/deps/random-0.3.0-rc-2025-09-16/insecure.wit b/wit/deps/random-0.3.0-rc-2025-09-16/insecure.wit new file mode 100644 index 0000000000..39146e3910 --- /dev/null +++ b/wit/deps/random-0.3.0-rc-2025-09-16/insecure.wit @@ -0,0 +1,25 @@ +package wasi:random@0.3.0-rc-2025-09-16; +/// The insecure interface for insecure pseudo-random numbers. +/// +/// It is intended to be portable at least between Unix-family platforms and +/// Windows. +@since(version = 0.3.0-rc-2025-09-16) +interface insecure { + /// Return `len` insecure pseudo-random bytes. + /// + /// This function is not cryptographically secure. Do not use it for + /// anything related to security. + /// + /// There are no requirements on the values of the returned bytes, however + /// implementations are encouraged to return evenly distributed values with + /// a long period. + @since(version = 0.3.0-rc-2025-09-16) + get-insecure-random-bytes: func(len: u64) -> list; + + /// Return an insecure pseudo-random `u64` value. + /// + /// This function returns the same type of pseudo-random data as + /// `get-insecure-random-bytes`, represented as a `u64`. + @since(version = 0.3.0-rc-2025-09-16) + get-insecure-random-u64: func() -> u64; +} diff --git a/wit/deps/random-0.3.0-rc-2025-09-16/random.wit b/wit/deps/random-0.3.0-rc-2025-09-16/random.wit new file mode 100644 index 0000000000..fa1f111dc7 --- /dev/null +++ b/wit/deps/random-0.3.0-rc-2025-09-16/random.wit @@ -0,0 +1,29 @@ +package wasi:random@0.3.0-rc-2025-09-16; +/// WASI Random is a random data API. +/// +/// It is intended to be portable at least between Unix-family platforms and +/// Windows. +@since(version = 0.3.0-rc-2025-09-16) +interface random { + /// Return `len` cryptographically-secure random or pseudo-random bytes. + /// + /// This function must produce data at least as cryptographically secure and + /// fast as an adequately seeded cryptographically-secure pseudo-random + /// number generator (CSPRNG). It must not block, from the perspective of + /// the calling program, under any circumstances, including on the first + /// request and on requests for numbers of bytes. The returned data must + /// always be unpredictable. + /// + /// This function must always return fresh data. Deterministic environments + /// must omit this function, rather than implementing it with deterministic + /// data. + @since(version = 0.3.0-rc-2025-09-16) + get-random-bytes: func(len: u64) -> list; + + /// Return a cryptographically-secure random or pseudo-random `u64` value. + /// + /// This function returns the same type of data as `get-random-bytes`, + /// represented as a `u64`. + @since(version = 0.3.0-rc-2025-09-16) + get-random-u64: func() -> u64; +} diff --git a/wit/deps/random-0.3.0-rc-2025-09-16/world.wit b/wit/deps/random-0.3.0-rc-2025-09-16/world.wit new file mode 100644 index 0000000000..08c5ed88b7 --- /dev/null +++ b/wit/deps/random-0.3.0-rc-2025-09-16/world.wit @@ -0,0 +1,13 @@ +package wasi:random@0.3.0-rc-2025-09-16; + +@since(version = 0.3.0-rc-2025-09-16) +world imports { + @since(version = 0.3.0-rc-2025-09-16) + import random; + + @since(version = 0.3.0-rc-2025-09-16) + import insecure; + + @since(version = 0.3.0-rc-2025-09-16) + import insecure-seed; +} diff --git a/wit/deps/sockets-0.3.0-rc-2025-09-16/ip-name-lookup.wit b/wit/deps/sockets-0.3.0-rc-2025-09-16/ip-name-lookup.wit new file mode 100644 index 0000000000..6a652ff232 --- /dev/null +++ b/wit/deps/sockets-0.3.0-rc-2025-09-16/ip-name-lookup.wit @@ -0,0 +1,62 @@ +@since(version = 0.3.0-rc-2025-09-16) +interface ip-name-lookup { + @since(version = 0.3.0-rc-2025-09-16) + use types.{ip-address}; + + /// Lookup error codes. + @since(version = 0.3.0-rc-2025-09-16) + enum error-code { + /// Unknown error + unknown, + + /// Access denied. + /// + /// POSIX equivalent: EACCES, EPERM + access-denied, + + /// `name` is a syntactically invalid domain name or IP address. + /// + /// POSIX equivalent: EINVAL + invalid-argument, + + /// Name does not exist or has no suitable associated IP addresses. + /// + /// POSIX equivalent: EAI_NONAME, EAI_NODATA, EAI_ADDRFAMILY + name-unresolvable, + + /// A temporary failure in name resolution occurred. + /// + /// POSIX equivalent: EAI_AGAIN + temporary-resolver-failure, + + /// A permanent failure in name resolution occurred. + /// + /// POSIX equivalent: EAI_FAIL + permanent-resolver-failure, + } + + /// Resolve an internet host name to a list of IP addresses. + /// + /// Unicode domain names are automatically converted to ASCII using IDNA encoding. + /// If the input is an IP address string, the address is parsed and returned + /// as-is without making any external requests. + /// + /// See the wasi-socket proposal README.md for a comparison with getaddrinfo. + /// + /// The results are returned in connection order preference. + /// + /// This function never succeeds with 0 results. It either fails or succeeds + /// with at least one address. Additionally, this function never returns + /// IPv4-mapped IPv6 addresses. + /// + /// The returned future will resolve to an error code in case of failure. + /// It will resolve to success once the returned stream is exhausted. + /// + /// # References: + /// - + /// - + /// - + /// - + @since(version = 0.3.0-rc-2025-09-16) + resolve-addresses: async func(name: string) -> result, error-code>; +} diff --git a/wit/deps/sockets-0.3.0-rc-2025-09-16/types.wit b/wit/deps/sockets-0.3.0-rc-2025-09-16/types.wit new file mode 100644 index 0000000000..2ed1912e48 --- /dev/null +++ b/wit/deps/sockets-0.3.0-rc-2025-09-16/types.wit @@ -0,0 +1,725 @@ +@since(version = 0.3.0-rc-2025-09-16) +interface types { + @since(version = 0.3.0-rc-2025-09-16) + use wasi:clocks/monotonic-clock@0.3.0-rc-2025-09-16.{duration}; + + /// Error codes. + /// + /// In theory, every API can return any error code. + /// In practice, API's typically only return the errors documented per API + /// combined with a couple of errors that are always possible: + /// - `unknown` + /// - `access-denied` + /// - `not-supported` + /// - `out-of-memory` + /// + /// See each individual API for what the POSIX equivalents are. They sometimes differ per API. + @since(version = 0.3.0-rc-2025-09-16) + enum error-code { + /// Unknown error + unknown, + + /// Access denied. + /// + /// POSIX equivalent: EACCES, EPERM + access-denied, + + /// The operation is not supported. + /// + /// POSIX equivalent: EOPNOTSUPP + not-supported, + + /// One of the arguments is invalid. + /// + /// POSIX equivalent: EINVAL + invalid-argument, + + /// Not enough memory to complete the operation. + /// + /// POSIX equivalent: ENOMEM, ENOBUFS, EAI_MEMORY + out-of-memory, + + /// The operation timed out before it could finish completely. + timeout, + + /// The operation is not valid in the socket's current state. + invalid-state, + + /// A bind operation failed because the provided address is not an address that the `network` can bind to. + address-not-bindable, + + /// A bind operation failed because the provided address is already in use or because there are no ephemeral ports available. + address-in-use, + + /// The remote address is not reachable + remote-unreachable, + + + /// The TCP connection was forcefully rejected + connection-refused, + + /// The TCP connection was reset. + connection-reset, + + /// A TCP connection was aborted. + connection-aborted, + + + /// The size of a datagram sent to a UDP socket exceeded the maximum + /// supported size. + datagram-too-large, + } + + @since(version = 0.3.0-rc-2025-09-16) + enum ip-address-family { + /// Similar to `AF_INET` in POSIX. + ipv4, + + /// Similar to `AF_INET6` in POSIX. + ipv6, + } + + @since(version = 0.3.0-rc-2025-09-16) + type ipv4-address = tuple; + @since(version = 0.3.0-rc-2025-09-16) + type ipv6-address = tuple; + + @since(version = 0.3.0-rc-2025-09-16) + variant ip-address { + ipv4(ipv4-address), + ipv6(ipv6-address), + } + + @since(version = 0.3.0-rc-2025-09-16) + record ipv4-socket-address { + /// sin_port + port: u16, + /// sin_addr + address: ipv4-address, + } + + @since(version = 0.3.0-rc-2025-09-16) + record ipv6-socket-address { + /// sin6_port + port: u16, + /// sin6_flowinfo + flow-info: u32, + /// sin6_addr + address: ipv6-address, + /// sin6_scope_id + scope-id: u32, + } + + @since(version = 0.3.0-rc-2025-09-16) + variant ip-socket-address { + ipv4(ipv4-socket-address), + ipv6(ipv6-socket-address), + } + + /// A TCP socket resource. + /// + /// The socket can be in one of the following states: + /// - `unbound` + /// - `bound` (See note below) + /// - `listening` + /// - `connecting` + /// - `connected` + /// - `closed` + /// See + /// for more information. + /// + /// Note: Except where explicitly mentioned, whenever this documentation uses + /// the term "bound" without backticks it actually means: in the `bound` state *or higher*. + /// (i.e. `bound`, `listening`, `connecting` or `connected`) + /// + /// In addition to the general error codes documented on the + /// `types::error-code` type, TCP socket methods may always return + /// `error(invalid-state)` when in the `closed` state. + @since(version = 0.3.0-rc-2025-09-16) + resource tcp-socket { + + /// Create a new TCP socket. + /// + /// Similar to `socket(AF_INET or AF_INET6, SOCK_STREAM, IPPROTO_TCP)` in POSIX. + /// On IPv6 sockets, IPV6_V6ONLY is enabled by default and can't be configured otherwise. + /// + /// Unlike POSIX, WASI sockets have no notion of a socket-level + /// `O_NONBLOCK` flag. Instead they fully rely on the Component Model's + /// async support. + /// + /// # References + /// - + /// - + /// - + /// - + @since(version = 0.3.0-rc-2025-09-16) + create: static func(address-family: ip-address-family) -> result; + + /// Bind the socket to the provided IP address and port. + /// + /// If the IP address is zero (`0.0.0.0` in IPv4, `::` in IPv6), it is left to the implementation to decide which + /// network interface(s) to bind to. + /// If the TCP/UDP port is zero, the socket will be bound to a random free port. + /// + /// Bind can be attempted multiple times on the same socket, even with + /// different arguments on each iteration. But never concurrently and + /// only as long as the previous bind failed. Once a bind succeeds, the + /// binding can't be changed anymore. + /// + /// # Typical errors + /// - `invalid-argument`: The `local-address` has the wrong address family. (EAFNOSUPPORT, EFAULT on Windows) + /// - `invalid-argument`: `local-address` is not a unicast address. (EINVAL) + /// - `invalid-argument`: `local-address` is an IPv4-mapped IPv6 address. (EINVAL) + /// - `invalid-state`: The socket is already bound. (EINVAL) + /// - `address-in-use`: No ephemeral ports available. (EADDRINUSE, ENOBUFS on Windows) + /// - `address-in-use`: Address is already in use. (EADDRINUSE) + /// - `address-not-bindable`: `local-address` is not an address that can be bound to. (EADDRNOTAVAIL) + /// + /// # Implementors note + /// When binding to a non-zero port, this bind operation shouldn't be affected by the TIME_WAIT + /// state of a recently closed socket on the same local address. In practice this means that the SO_REUSEADDR + /// socket option should be set implicitly on all platforms, except on Windows where this is the default behavior + /// and SO_REUSEADDR performs something different entirely. + /// + /// # References + /// - + /// - + /// - + /// - + @since(version = 0.3.0-rc-2025-09-16) + bind: func(local-address: ip-socket-address) -> result<_, error-code>; + + /// Connect to a remote endpoint. + /// + /// On success, the socket is transitioned into the `connected` state and this function returns a connection resource. + /// + /// After a failed connection attempt, the socket will be in the `closed` + /// state and the only valid action left is to `drop` the socket. A single + /// socket can not be used to connect more than once. + /// + /// # Typical errors + /// - `invalid-argument`: The `remote-address` has the wrong address family. (EAFNOSUPPORT) + /// - `invalid-argument`: `remote-address` is not a unicast address. (EINVAL, ENETUNREACH on Linux, EAFNOSUPPORT on MacOS) + /// - `invalid-argument`: `remote-address` is an IPv4-mapped IPv6 address. (EINVAL, EADDRNOTAVAIL on Illumos) + /// - `invalid-argument`: The IP address in `remote-address` is set to INADDR_ANY (`0.0.0.0` / `::`). (EADDRNOTAVAIL on Windows) + /// - `invalid-argument`: The port in `remote-address` is set to 0. (EADDRNOTAVAIL on Windows) + /// - `invalid-state`: The socket is already in the `connecting` state. (EALREADY) + /// - `invalid-state`: The socket is already in the `connected` state. (EISCONN) + /// - `invalid-state`: The socket is already in the `listening` state. (EOPNOTSUPP, EINVAL on Windows) + /// - `timeout`: Connection timed out. (ETIMEDOUT) + /// - `connection-refused`: The connection was forcefully rejected. (ECONNREFUSED) + /// - `connection-reset`: The connection was reset. (ECONNRESET) + /// - `connection-aborted`: The connection was aborted. (ECONNABORTED) + /// - `remote-unreachable`: The remote address is not reachable. (EHOSTUNREACH, EHOSTDOWN, ENETUNREACH, ENETDOWN, ENONET) + /// - `address-in-use`: Tried to perform an implicit bind, but there were no ephemeral ports available. (EADDRINUSE, EADDRNOTAVAIL on Linux, EAGAIN on BSD) + /// + /// # References + /// - + /// - + /// - + /// - + @since(version = 0.3.0-rc-2025-09-16) + connect: async func(remote-address: ip-socket-address) -> result<_, error-code>; + + /// Start listening and return a stream of new inbound connections. + /// + /// Transitions the socket into the `listening` state. This can be called + /// at most once per socket. + /// + /// If the socket is not already explicitly bound, this function will + /// implicitly bind the socket to a random free port. + /// + /// Normally, the returned sockets are bound, in the `connected` state + /// and immediately ready for I/O. Though, depending on exact timing and + /// circumstances, a newly accepted connection may already be `closed` + /// by the time the server attempts to perform its first I/O on it. This + /// is true regardless of whether the WASI implementation uses + /// "synthesized" sockets or not (see Implementors Notes below). + /// + /// The following properties are inherited from the listener socket: + /// - `address-family` + /// - `keep-alive-enabled` + /// - `keep-alive-idle-time` + /// - `keep-alive-interval` + /// - `keep-alive-count` + /// - `hop-limit` + /// - `receive-buffer-size` + /// - `send-buffer-size` + /// + /// # Typical errors + /// - `invalid-state`: The socket is already in the `connected` state. (EISCONN, EINVAL on BSD) + /// - `invalid-state`: The socket is already in the `listening` state. + /// - `address-in-use`: Tried to perform an implicit bind, but there were no ephemeral ports available. (EADDRINUSE) + /// + /// # Implementors note + /// This method returns a single perpetual stream that should only close + /// on fatal errors (if any). Yet, the POSIX' `accept` function may also + /// return transient errors (e.g. ECONNABORTED). The exact details differ + /// per operation system. For example, the Linux manual mentions: + /// + /// > Linux accept() passes already-pending network errors on the new + /// > socket as an error code from accept(). This behavior differs from + /// > other BSD socket implementations. For reliable operation the + /// > application should detect the network errors defined for the + /// > protocol after accept() and treat them like EAGAIN by retrying. + /// > In the case of TCP/IP, these are ENETDOWN, EPROTO, ENOPROTOOPT, + /// > EHOSTDOWN, ENONET, EHOSTUNREACH, EOPNOTSUPP, and ENETUNREACH. + /// Source: https://man7.org/linux/man-pages/man2/accept.2.html + /// + /// WASI implementations have two options to handle this: + /// - Optionally log it and then skip over non-fatal errors returned by + /// `accept`. Guest code never gets to see these failures. Or: + /// - Synthesize a `tcp-socket` resource that exposes the error when + /// attempting to send or receive on it. Guest code then sees these + /// failures as regular I/O errors. + /// + /// In either case, the stream returned by this `listen` method remains + /// operational. + /// + /// # References + /// - + /// - + /// - + /// - + /// - + /// - + /// - + /// - + @since(version = 0.3.0-rc-2025-09-16) + listen: func() -> result, error-code>; + + /// Transmit data to peer. + /// + /// The caller should close the stream when it has no more data to send + /// to the peer. Under normal circumstances this will cause a FIN packet + /// to be sent out. Closing the stream is equivalent to calling + /// `shutdown(SHUT_WR)` in POSIX. + /// + /// This function may be called at most once and returns once the full + /// contents of the stream are transmitted or an error is encountered. + /// + /// # Typical errors + /// - `invalid-state`: The socket is not in the `connected` state. (ENOTCONN) + /// - `connection-reset`: The connection was reset. (ECONNRESET) + /// - `remote-unreachable`: The remote address is not reachable. (EHOSTUNREACH, EHOSTDOWN, ENETUNREACH, ENETDOWN, ENONET) + /// + /// # References + /// - + /// - + /// - + /// - + @since(version = 0.3.0-rc-2025-09-16) + send: async func(data: stream) -> result<_, error-code>; + + /// Read data from peer. + /// + /// This function returns a `stream` which provides the data received from the + /// socket, and a `future` providing additional error information in case the + /// socket is closed abnormally. + /// + /// If the socket is closed normally, `stream.read` on the `stream` will return + /// `read-status::closed` with no `error-context` and the future resolves to + /// the value `ok`. If the socket is closed abnormally, `stream.read` on the + /// `stream` returns `read-status::closed` with an `error-context` and the future + /// resolves to `err` with an `error-code`. + /// + /// `receive` is meant to be called only once per socket. If it is called more + /// than once, the subsequent calls return a new `stream` that fails as if it + /// were closed abnormally. + /// + /// If the caller is not expecting to receive any data from the peer, + /// they may drop the stream. Any data still in the receive queue + /// will be discarded. This is equivalent to calling `shutdown(SHUT_RD)` + /// in POSIX. + /// + /// # Typical errors + /// - `invalid-state`: The socket is not in the `connected` state. (ENOTCONN) + /// - `connection-reset`: The connection was reset. (ECONNRESET) + /// - `remote-unreachable`: The remote address is not reachable. (EHOSTUNREACH, EHOSTDOWN, ENETUNREACH, ENETDOWN, ENONET) + /// + /// # References + /// - + /// - + /// - + /// - + @since(version = 0.3.0-rc-2025-09-16) + receive: func() -> tuple, future>>; + + /// Get the bound local address. + /// + /// POSIX mentions: + /// > If the socket has not been bound to a local name, the value + /// > stored in the object pointed to by `address` is unspecified. + /// + /// WASI is stricter and requires `get-local-address` to return `invalid-state` when the socket hasn't been bound yet. + /// + /// # Typical errors + /// - `invalid-state`: The socket is not bound to any local address. + /// + /// # References + /// - + /// - + /// - + /// - + @since(version = 0.3.0-rc-2025-09-16) + get-local-address: func() -> result; + + /// Get the remote address. + /// + /// # Typical errors + /// - `invalid-state`: The socket is not connected to a remote address. (ENOTCONN) + /// + /// # References + /// - + /// - + /// - + /// - + @since(version = 0.3.0-rc-2025-09-16) + get-remote-address: func() -> result; + + /// Whether the socket is in the `listening` state. + /// + /// Equivalent to the SO_ACCEPTCONN socket option. + @since(version = 0.3.0-rc-2025-09-16) + get-is-listening: func() -> bool; + + /// Whether this is a IPv4 or IPv6 socket. + /// + /// This is the value passed to the constructor. + /// + /// Equivalent to the SO_DOMAIN socket option. + @since(version = 0.3.0-rc-2025-09-16) + get-address-family: func() -> ip-address-family; + + /// Hints the desired listen queue size. Implementations are free to ignore this. + /// + /// If the provided value is 0, an `invalid-argument` error is returned. + /// Any other value will never cause an error, but it might be silently clamped and/or rounded. + /// + /// # Typical errors + /// - `not-supported`: (set) The platform does not support changing the backlog size after the initial listen. + /// - `invalid-argument`: (set) The provided value was 0. + /// - `invalid-state`: (set) The socket is in the `connecting` or `connected` state. + @since(version = 0.3.0-rc-2025-09-16) + set-listen-backlog-size: func(value: u64) -> result<_, error-code>; + + /// Enables or disables keepalive. + /// + /// The keepalive behavior can be adjusted using: + /// - `keep-alive-idle-time` + /// - `keep-alive-interval` + /// - `keep-alive-count` + /// These properties can be configured while `keep-alive-enabled` is false, but only come into effect when `keep-alive-enabled` is true. + /// + /// Equivalent to the SO_KEEPALIVE socket option. + @since(version = 0.3.0-rc-2025-09-16) + get-keep-alive-enabled: func() -> result; + @since(version = 0.3.0-rc-2025-09-16) + set-keep-alive-enabled: func(value: bool) -> result<_, error-code>; + + /// Amount of time the connection has to be idle before TCP starts sending keepalive packets. + /// + /// If the provided value is 0, an `invalid-argument` error is returned. + /// Any other value will never cause an error, but it might be silently clamped and/or rounded. + /// I.e. after setting a value, reading the same setting back may return a different value. + /// + /// Equivalent to the TCP_KEEPIDLE socket option. (TCP_KEEPALIVE on MacOS) + /// + /// # Typical errors + /// - `invalid-argument`: (set) The provided value was 0. + @since(version = 0.3.0-rc-2025-09-16) + get-keep-alive-idle-time: func() -> result; + @since(version = 0.3.0-rc-2025-09-16) + set-keep-alive-idle-time: func(value: duration) -> result<_, error-code>; + + /// The time between keepalive packets. + /// + /// If the provided value is 0, an `invalid-argument` error is returned. + /// Any other value will never cause an error, but it might be silently clamped and/or rounded. + /// I.e. after setting a value, reading the same setting back may return a different value. + /// + /// Equivalent to the TCP_KEEPINTVL socket option. + /// + /// # Typical errors + /// - `invalid-argument`: (set) The provided value was 0. + @since(version = 0.3.0-rc-2025-09-16) + get-keep-alive-interval: func() -> result; + @since(version = 0.3.0-rc-2025-09-16) + set-keep-alive-interval: func(value: duration) -> result<_, error-code>; + + /// The maximum amount of keepalive packets TCP should send before aborting the connection. + /// + /// If the provided value is 0, an `invalid-argument` error is returned. + /// Any other value will never cause an error, but it might be silently clamped and/or rounded. + /// I.e. after setting a value, reading the same setting back may return a different value. + /// + /// Equivalent to the TCP_KEEPCNT socket option. + /// + /// # Typical errors + /// - `invalid-argument`: (set) The provided value was 0. + @since(version = 0.3.0-rc-2025-09-16) + get-keep-alive-count: func() -> result; + @since(version = 0.3.0-rc-2025-09-16) + set-keep-alive-count: func(value: u32) -> result<_, error-code>; + + /// Equivalent to the IP_TTL & IPV6_UNICAST_HOPS socket options. + /// + /// If the provided value is 0, an `invalid-argument` error is returned. + /// + /// # Typical errors + /// - `invalid-argument`: (set) The TTL value must be 1 or higher. + @since(version = 0.3.0-rc-2025-09-16) + get-hop-limit: func() -> result; + @since(version = 0.3.0-rc-2025-09-16) + set-hop-limit: func(value: u8) -> result<_, error-code>; + + /// The kernel buffer space reserved for sends/receives on this socket. + /// + /// If the provided value is 0, an `invalid-argument` error is returned. + /// Any other value will never cause an error, but it might be silently clamped and/or rounded. + /// I.e. after setting a value, reading the same setting back may return a different value. + /// + /// Equivalent to the SO_RCVBUF and SO_SNDBUF socket options. + /// + /// # Typical errors + /// - `invalid-argument`: (set) The provided value was 0. + @since(version = 0.3.0-rc-2025-09-16) + get-receive-buffer-size: func() -> result; + @since(version = 0.3.0-rc-2025-09-16) + set-receive-buffer-size: func(value: u64) -> result<_, error-code>; + @since(version = 0.3.0-rc-2025-09-16) + get-send-buffer-size: func() -> result; + @since(version = 0.3.0-rc-2025-09-16) + set-send-buffer-size: func(value: u64) -> result<_, error-code>; + } + + /// A UDP socket handle. + @since(version = 0.3.0-rc-2025-09-16) + resource udp-socket { + + /// Create a new UDP socket. + /// + /// Similar to `socket(AF_INET or AF_INET6, SOCK_DGRAM, IPPROTO_UDP)` in POSIX. + /// On IPv6 sockets, IPV6_V6ONLY is enabled by default and can't be configured otherwise. + /// + /// Unlike POSIX, WASI sockets have no notion of a socket-level + /// `O_NONBLOCK` flag. Instead they fully rely on the Component Model's + /// async support. + /// + /// # References: + /// - + /// - + /// - + /// - + @since(version = 0.3.0-rc-2025-09-16) + create: static func(address-family: ip-address-family) -> result; + + /// Bind the socket to the provided IP address and port. + /// + /// If the IP address is zero (`0.0.0.0` in IPv4, `::` in IPv6), it is left to the implementation to decide which + /// network interface(s) to bind to. + /// If the port is zero, the socket will be bound to a random free port. + /// + /// # Typical errors + /// - `invalid-argument`: The `local-address` has the wrong address family. (EAFNOSUPPORT, EFAULT on Windows) + /// - `invalid-state`: The socket is already bound. (EINVAL) + /// - `address-in-use`: No ephemeral ports available. (EADDRINUSE, ENOBUFS on Windows) + /// - `address-in-use`: Address is already in use. (EADDRINUSE) + /// - `address-not-bindable`: `local-address` is not an address that can be bound to. (EADDRNOTAVAIL) + /// + /// # References + /// - + /// - + /// - + /// - + @since(version = 0.3.0-rc-2025-09-16) + bind: func(local-address: ip-socket-address) -> result<_, error-code>; + + /// Associate this socket with a specific peer address. + /// + /// On success, the `remote-address` of the socket is updated. + /// The `local-address` may be updated as well, based on the best network + /// path to `remote-address`. If the socket was not already explicitly + /// bound, this function will implicitly bind the socket to a random + /// free port. + /// + /// When a UDP socket is "connected", the `send` and `receive` methods + /// are limited to communicating with that peer only: + /// - `send` can only be used to send to this destination. + /// - `receive` will only return datagrams sent from the provided `remote-address`. + /// + /// The name "connect" was kept to align with the existing POSIX + /// terminology. Other than that, this function only changes the local + /// socket configuration and does not generate any network traffic. + /// The peer is not aware of this "connection". + /// + /// This method may be called multiple times on the same socket to change + /// its association, but only the most recent one will be effective. + /// + /// # Typical errors + /// - `invalid-argument`: The `remote-address` has the wrong address family. (EAFNOSUPPORT) + /// - `invalid-argument`: The IP address in `remote-address` is set to INADDR_ANY (`0.0.0.0` / `::`). (EDESTADDRREQ, EADDRNOTAVAIL) + /// - `invalid-argument`: The port in `remote-address` is set to 0. (EDESTADDRREQ, EADDRNOTAVAIL) + /// - `address-in-use`: Tried to perform an implicit bind, but there were no ephemeral ports available. (EADDRINUSE, EADDRNOTAVAIL on Linux, EAGAIN on BSD) + /// + /// # Implementors note + /// If the socket is already connected, some platforms (e.g. Linux) + /// require a disconnect before connecting to a different peer address. + /// + /// # References + /// - + /// - + /// - + /// - + @since(version = 0.3.0-rc-2025-09-16) + connect: func(remote-address: ip-socket-address) -> result<_, error-code>; + + /// Dissociate this socket from its peer address. + /// + /// After calling this method, `send` & `receive` are free to communicate + /// with any address again. + /// + /// The POSIX equivalent of this is calling `connect` with an `AF_UNSPEC` address. + /// + /// # Typical errors + /// - `invalid-state`: The socket is not connected. + /// + /// # References + /// - + /// - + /// - + /// - + @since(version = 0.3.0-rc-2025-09-16) + disconnect: func() -> result<_, error-code>; + + /// Send a message on the socket to a particular peer. + /// + /// If the socket is connected, the peer address may be left empty. In + /// that case this is equivalent to `send` in POSIX. Otherwise it is + /// equivalent to `sendto`. + /// + /// Additionally, if the socket is connected, a `remote-address` argument + /// _may_ be provided but then it must be identical to the address + /// passed to `connect`. + /// + /// Implementations may trap if the `data` length exceeds 64 KiB. + /// + /// # Typical errors + /// - `invalid-argument`: The `remote-address` has the wrong address family. (EAFNOSUPPORT) + /// - `invalid-argument`: The IP address in `remote-address` is set to INADDR_ANY (`0.0.0.0` / `::`). (EDESTADDRREQ, EADDRNOTAVAIL) + /// - `invalid-argument`: The port in `remote-address` is set to 0. (EDESTADDRREQ, EADDRNOTAVAIL) + /// - `invalid-argument`: The socket is in "connected" mode and `remote-address` is `some` value that does not match the address passed to `connect`. (EISCONN) + /// - `invalid-argument`: The socket is not "connected" and no value for `remote-address` was provided. (EDESTADDRREQ) + /// - `remote-unreachable`: The remote address is not reachable. (ECONNRESET, ENETRESET on Windows, EHOSTUNREACH, EHOSTDOWN, ENETUNREACH, ENETDOWN, ENONET) + /// - `connection-refused`: The connection was refused. (ECONNREFUSED) + /// - `datagram-too-large`: The datagram is too large. (EMSGSIZE) + /// + /// # References + /// - + /// - + /// - + /// - + /// - + /// - + /// - + /// - + @since(version = 0.3.0-rc-2025-09-16) + send: async func(data: list, remote-address: option) -> result<_, error-code>; + + /// Receive a message on the socket. + /// + /// On success, the return value contains a tuple of the received data + /// and the address of the sender. Theoretical maximum length of the + /// data is 64 KiB. Though in practice, it will typically be less than + /// 1500 bytes. + /// + /// If the socket is connected, the sender address is guaranteed to + /// match the remote address passed to `connect`. + /// + /// # Typical errors + /// - `invalid-state`: The socket has not been bound yet. + /// - `remote-unreachable`: The remote address is not reachable. (ECONNRESET, ENETRESET on Windows, EHOSTUNREACH, EHOSTDOWN, ENETUNREACH, ENETDOWN, ENONET) + /// - `connection-refused`: The connection was refused. (ECONNREFUSED) + /// + /// # References + /// - + /// - + /// - + /// - + /// - + /// - + /// - + @since(version = 0.3.0-rc-2025-09-16) + receive: async func() -> result, ip-socket-address>, error-code>; + + /// Get the current bound address. + /// + /// POSIX mentions: + /// > If the socket has not been bound to a local name, the value + /// > stored in the object pointed to by `address` is unspecified. + /// + /// WASI is stricter and requires `get-local-address` to return `invalid-state` when the socket hasn't been bound yet. + /// + /// # Typical errors + /// - `invalid-state`: The socket is not bound to any local address. + /// + /// # References + /// - + /// - + /// - + /// - + @since(version = 0.3.0-rc-2025-09-16) + get-local-address: func() -> result; + + /// Get the address the socket is currently "connected" to. + /// + /// # Typical errors + /// - `invalid-state`: The socket is not "connected" to a specific remote address. (ENOTCONN) + /// + /// # References + /// - + /// - + /// - + /// - + @since(version = 0.3.0-rc-2025-09-16) + get-remote-address: func() -> result; + + /// Whether this is a IPv4 or IPv6 socket. + /// + /// This is the value passed to the constructor. + /// + /// Equivalent to the SO_DOMAIN socket option. + @since(version = 0.3.0-rc-2025-09-16) + get-address-family: func() -> ip-address-family; + + /// Equivalent to the IP_TTL & IPV6_UNICAST_HOPS socket options. + /// + /// If the provided value is 0, an `invalid-argument` error is returned. + /// + /// # Typical errors + /// - `invalid-argument`: (set) The TTL value must be 1 or higher. + @since(version = 0.3.0-rc-2025-09-16) + get-unicast-hop-limit: func() -> result; + @since(version = 0.3.0-rc-2025-09-16) + set-unicast-hop-limit: func(value: u8) -> result<_, error-code>; + + /// The kernel buffer space reserved for sends/receives on this socket. + /// + /// If the provided value is 0, an `invalid-argument` error is returned. + /// Any other value will never cause an error, but it might be silently clamped and/or rounded. + /// I.e. after setting a value, reading the same setting back may return a different value. + /// + /// Equivalent to the SO_RCVBUF and SO_SNDBUF socket options. + /// + /// # Typical errors + /// - `invalid-argument`: (set) The provided value was 0. + @since(version = 0.3.0-rc-2025-09-16) + get-receive-buffer-size: func() -> result; + @since(version = 0.3.0-rc-2025-09-16) + set-receive-buffer-size: func(value: u64) -> result<_, error-code>; + @since(version = 0.3.0-rc-2025-09-16) + get-send-buffer-size: func() -> result; + @since(version = 0.3.0-rc-2025-09-16) + set-send-buffer-size: func(value: u64) -> result<_, error-code>; + } +} diff --git a/wit/deps/sockets-0.3.0-rc-2025-09-16/world.wit b/wit/deps/sockets-0.3.0-rc-2025-09-16/world.wit new file mode 100644 index 0000000000..44cc427ed1 --- /dev/null +++ b/wit/deps/sockets-0.3.0-rc-2025-09-16/world.wit @@ -0,0 +1,9 @@ +package wasi:sockets@0.3.0-rc-2025-09-16; + +@since(version = 0.3.0-rc-2025-09-16) +world imports { + @since(version = 0.3.0-rc-2025-09-16) + import types; + @since(version = 0.3.0-rc-2025-09-16) + import ip-name-lookup; +}