├── .gitattributes ├── .github └── workflows │ └── main.yml ├── .gitignore ├── .gitmodules ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-Apache-2.0_WITH_LLVM-exception ├── LICENSE-MIT ├── ORG_CODE_OF_CONDUCT.md ├── README.md ├── SECURITY.md ├── ci ├── regenerate.sh └── vendor-wit.sh ├── crates └── wasi-ext │ ├── Cargo.toml │ ├── examples │ └── rand.rs │ └── src │ ├── lib.rs │ └── rand.rs ├── examples ├── cli-command-no_std.rs ├── cli-command.rs ├── hello-world-no_std.rs ├── hello-world.rs ├── http-proxy-no_std.rs └── http-proxy.rs ├── src ├── bindings.rs ├── command.rs ├── ext │ ├── mod.rs │ └── std.rs ├── lib.rs └── proxy.rs └── wit ├── deps ├── cli │ ├── command.wit │ ├── environment.wit │ ├── exit.wit │ ├── imports.wit │ ├── run.wit │ ├── stdio.wit │ └── terminal.wit ├── clocks │ ├── monotonic-clock.wit │ ├── timezone.wit │ ├── wall-clock.wit │ └── world.wit ├── filesystem │ ├── preopens.wit │ ├── types.wit │ └── world.wit ├── http │ ├── handler.wit │ ├── proxy.wit │ └── types.wit ├── io │ ├── error.wit │ ├── poll.wit │ ├── streams.wit │ └── world.wit ├── random │ ├── insecure-seed.wit │ ├── insecure.wit │ ├── random.wit │ └── world.wit └── sockets │ ├── instance-network.wit │ ├── ip-name-lookup.wit │ ├── network.wit │ ├── tcp-create-socket.wit │ ├── tcp.wit │ ├── udp-create-socket.wit │ ├── udp.wit │ └── world.wit └── wasi-crate.wit /.gitattributes: -------------------------------------------------------------------------------- 1 | # These are generated by `wit-bindgen` 2 | src/bindings.rs linguist-generated=true 3 | src/proxy.rs linguist-generated=true 4 | src/command.rs linguist-generated=true 5 | 6 | # This is copied from other repos so diffs aren't super interesting by default 7 | wit/deps linguist-generated=true 8 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: [push, pull_request] 3 | 4 | jobs: 5 | test: 6 | name: Test 7 | runs-on: ubuntu-latest 8 | strategy: 9 | matrix: 10 | rust: [stable, beta, nightly] 11 | steps: 12 | - uses: actions/checkout@v4 13 | - name: Install Rust 14 | run: rustup update ${{ matrix.rust }} && rustup default ${{ matrix.rust }} && rustup component add rustfmt 15 | - run: rustup target add wasm32-wasip1 wasm32-unknown-unknown 16 | - run: cargo build --workspace 17 | - run: cargo build --workspace --no-default-features 18 | - run: cargo build --workspace --target wasm32-wasip1 19 | - run: cargo build --workspace --target wasm32-wasip1 --no-default-features 20 | - run: cargo test --workspace --doc 21 | - name: Install Wasmtime 22 | uses: bytecodealliance/actions/wasmtime/setup@v1 23 | with: 24 | version: "v30.0.2" 25 | - name: Install wasm-tools 26 | uses: bytecodealliance/actions/wasm-tools/setup@v1 27 | with: 28 | version: "1.224.0" 29 | - run: curl -LO https://github.com/bytecodealliance/wasmtime/releases/download/v30.0.2/wasi_snapshot_preview1.command.wasm 30 | 31 | - run: cargo build --examples --target wasm32-wasip1 --no-default-features 32 | 33 | - run: wasm-tools component new ./target/wasm32-wasip1/debug/examples/hello-world-no_std.wasm --adapt ./wasi_snapshot_preview1.command.wasm -o component.wasm 34 | - run: wasmtime run component.wasm 35 | 36 | - run: cargo build --examples --target wasm32-unknown-unknown --no-default-features 37 | 38 | - run: wasm-tools component new ./target/wasm32-unknown-unknown/debug/examples/cli_command_no_std.wasm -o component.wasm 39 | - run: wasmtime run component.wasm 40 | 41 | - run: wasm-tools component new ./target/wasm32-unknown-unknown/debug/examples/http_proxy_no_std.wasm -o component.wasm 42 | - run: wasm-tools component targets wit component.wasm -w wasi:http/proxy 43 | 44 | - run: cargo build --examples --target wasm32-wasip1 45 | 46 | - run: wasm-tools component new ./target/wasm32-wasip1/debug/examples/hello-world.wasm --adapt ./wasi_snapshot_preview1.command.wasm -o component.wasm 47 | - run: wasmtime run component.wasm 48 | 49 | - run: cargo build --examples --target wasm32-unknown-unknown 50 | 51 | - run: wasm-tools component new ./target/wasm32-unknown-unknown/debug/examples/cli_command.wasm -o component.wasm 52 | - run: wasmtime run component.wasm 53 | 54 | - run: wasm-tools component new ./target/wasm32-unknown-unknown/debug/examples/http_proxy.wasm -o component.wasm 55 | - run: wasm-tools component targets wit component.wasm -w wasi:http/proxy 56 | 57 | - run: cargo build --examples --workspace --target wasm32-wasip1 --features rand 58 | 59 | - run: wasm-tools component new ./target/wasm32-wasip1/debug/examples/rand.wasm --adapt ./wasi_snapshot_preview1.command.wasm -o component.wasm 60 | - run: wasmtime run component.wasm 61 | 62 | generate: 63 | name: Ensure generated code up-to-date 64 | runs-on: ubuntu-latest 65 | steps: 66 | - uses: actions/checkout@v4 67 | - name: Install Rust 68 | run: rustup update stable && rustup default stable 69 | # Re-vendor all WIT files and ensure that they're all up-to-date by ensuring 70 | # that there's no git changes. 71 | - name: Re-vendor WIT 72 | run: | 73 | ./ci/vendor-wit.sh 74 | git diff --exit-code 75 | - run: cargo install wit-bindgen-cli@0.39.0 --locked 76 | - run: ./ci/regenerate.sh 77 | - run: git diff --exit-code 78 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | Cargo.lock 4 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bytecodealliance/wasi-rs/039c272625c2ad09ca3b0b63c41b5f79657482d0/.gitmodules -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | *Note*: this Code of Conduct pertains to individuals' behavior. Please also see the [Organizational Code of Conduct][OCoC]. 4 | 5 | ## Our Pledge 6 | 7 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 8 | 9 | ## Our Standards 10 | 11 | Examples of behavior that contributes to creating a positive environment include: 12 | 13 | * Using welcoming and inclusive language 14 | * Being respectful of differing viewpoints and experiences 15 | * Gracefully accepting constructive criticism 16 | * Focusing on what is best for the community 17 | * Showing empathy towards other community members 18 | 19 | Examples of unacceptable behavior by participants include: 20 | 21 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 22 | * Trolling, insulting/derogatory comments, and personal or political attacks 23 | * Public or private harassment 24 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 25 | * Other conduct which could reasonably be considered inappropriate in a professional setting 26 | 27 | ## Our Responsibilities 28 | 29 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 30 | 31 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 32 | 33 | ## Scope 34 | 35 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 36 | 37 | ## Enforcement 38 | 39 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the Bytecode Alliance CoC team at [report@bytecodealliance.org](mailto:report@bytecodealliance.org). The CoC team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The CoC team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 40 | 41 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the Bytecode Alliance's leadership. 42 | 43 | ## Attribution 44 | 45 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 46 | 47 | [OCoC]: ORG_CODE_OF_CONDUCT.md 48 | [homepage]: https://www.contributor-covenant.org 49 | [version]: https://www.contributor-covenant.org/version/1/4/ 50 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to wasi-core 2 | 3 | wasi-core follows the same development style as Cranelift, so checkout 4 | [Cranelift's CONTRIBUTING.md]. Of course, for wasi-core-specific issues, please 5 | use the [wasi-core issue tracker]. 6 | 7 | [Cranelift's CONTRIBUTING.md]: https://github.com/CraneStation/cranelift/blob/master/CONTRIBUTING.md 8 | [wasi-core issue tracker]: https://github.com/CraneStation/wasi-core/issues/new 9 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wasi" 3 | version = "0.14.2+wasi-0.2.4" 4 | authors = ["The Cranelift Project Developers"] 5 | description = "WASI API bindings for Rust" 6 | categories = ["no-std", "wasm"] 7 | keywords = ["webassembly", "wasm"] 8 | readme = "README.md" 9 | documentation = "https://docs.rs/wasi" 10 | license.workspace = true 11 | edition.workspace = true 12 | repository.workspace = true 13 | 14 | [workspace.package] 15 | edition = "2021" 16 | license = "Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT" 17 | repository = "https://github.com/bytecodealliance/wasi-rs" 18 | 19 | [workspace.dependencies] 20 | rand = { version = "0.8.5", default-features = false } 21 | wasi = { version = "0.14", path = ".", default-features = false } 22 | 23 | [workspace] 24 | members = ["./crates/*"] 25 | 26 | [dependencies] 27 | wit-bindgen-rt = { version = "0.39.0", features = ["bitflags"] } 28 | 29 | # When built as part of libstd 30 | compiler_builtins = { version = "0.1", optional = true } 31 | core = { version = "1.0", optional = true, package = "rustc-std-workspace-core" } 32 | rustc-std-workspace-alloc = { version = "1.0", optional = true } 33 | 34 | [features] 35 | default = ["std"] 36 | std = [] 37 | # Unstable feature to support being a libstd dependency 38 | rustc-dep-of-std = ["compiler_builtins", "core", "rustc-std-workspace-alloc"] 39 | 40 | [[example]] 41 | name = "cli-command-no_std" 42 | crate-type = ["cdylib"] 43 | 44 | [[example]] 45 | name = "cli-command" 46 | crate-type = ["cdylib"] 47 | required-features = ["std"] 48 | 49 | [[example]] 50 | name = "hello-world" 51 | required-features = ["std"] 52 | 53 | [[example]] 54 | name = "http-proxy-no_std" 55 | crate-type = ["cdylib"] 56 | 57 | [[example]] 58 | name = "http-proxy" 59 | crate-type = ["cdylib"] 60 | required-features = ["std"] 61 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /LICENSE-Apache-2.0_WITH_LLVM-exception: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | 204 | 205 | --- LLVM Exceptions to the Apache 2.0 License ---- 206 | 207 | As an exception, if, as a result of your compiling your source code, portions 208 | of this Software are embedded into an Object form of such source code, you 209 | may redistribute such embedded portions in such Object form without complying 210 | with the conditions of Sections 4(a), 4(b) and 4(d) of the License. 211 | 212 | In addition, if you combine or link compiled forms of this Software with 213 | software that is licensed under the GPLv2 ("Combined Software") and if a 214 | court of competent jurisdiction determines that the patent provision (Section 215 | 3), the indemnity provision (Section 9) or other Section of the License 216 | conflicts with the conditions of the GPLv2, you may retroactively and 217 | prospectively choose to deem waived or otherwise exclude such Section(s) of 218 | the License, but only in their entirety and only with respect to the Combined 219 | Software. 220 | 221 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Permission is hereby granted, free of charge, to any 2 | person obtaining a copy of this software and associated 3 | documentation files (the "Software"), to deal in the 4 | Software without restriction, including without 5 | limitation the rights to use, copy, modify, merge, 6 | publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software 8 | is furnished to do so, subject to the following 9 | conditions: 10 | 11 | The above copyright notice and this permission notice 12 | shall be included in all copies or substantial portions 13 | of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 16 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 17 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 18 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 19 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 22 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /ORG_CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Bytecode Alliance Organizational Code of Conduct (OCoC) 2 | 3 | *Note*: this Code of Conduct pertains to organizations' behavior. Please also see the [Individual Code of Conduct](CODE_OF_CONDUCT.md). 4 | 5 | ## Preamble 6 | 7 | The Bytecode Alliance (BA) welcomes involvement from organizations, 8 | including commercial organizations. This document is an 9 | *organizational* code of conduct, intended particularly to provide 10 | guidance to commercial organizations. It is distinct from the 11 | [Individual Code of Conduct (ICoC)](CODE_OF_CONDUCT.md), and does not 12 | replace the ICoC. This OCoC applies to any group of people acting in 13 | concert as a BA member or as a participant in BA activities, whether 14 | or not that group is formally incorporated in some jurisdiction. 15 | 16 | The code of conduct described below is not a set of rigid rules, and 17 | we did not write it to encompass every conceivable scenario that might 18 | arise. For example, it is theoretically possible there would be times 19 | when asserting patents is in the best interest of the BA community as 20 | a whole. In such instances, consult with the BA, strive for 21 | consensus, and interpret these rules with an intent that is generous 22 | to the community the BA serves. 23 | 24 | While we may revise these guidelines from time to time based on 25 | real-world experience, overall they are based on a simple principle: 26 | 27 | *Bytecode Alliance members should observe the distinction between 28 | public community functions and private functions — especially 29 | commercial ones — and should ensure that the latter support, or at 30 | least do not harm, the former.* 31 | 32 | ## Guidelines 33 | 34 | * **Do not cause confusion about Wasm standards or interoperability.** 35 | 36 | Having an interoperable WebAssembly core is a high priority for 37 | the BA, and members should strive to preserve that core. It is fine 38 | to develop additional non-standard features or APIs, but they 39 | should always be clearly distinguished from the core interoperable 40 | Wasm. 41 | 42 | Treat the WebAssembly name and any BA-associated names with 43 | respect, and follow BA trademark and branding guidelines. If you 44 | distribute a customized version of software originally produced by 45 | the BA, or if you build a product or service using BA-derived 46 | software, use names that clearly distinguish your work from the 47 | original. (You should still provide proper attribution to the 48 | original, of course, wherever such attribution would normally be 49 | given.) 50 | 51 | Further, do not use the WebAssembly name or BA-associated names in 52 | other public namespaces in ways that could cause confusion, e.g., 53 | in company names, names of commercial service offerings, domain 54 | names, publicly-visible social media accounts or online service 55 | accounts, etc. It may sometimes be reasonable, however, to 56 | register such a name in a new namespace and then immediately donate 57 | control of that account to the BA, because that would help the project 58 | maintain its identity. 59 | 60 | For further guidance, see the BA Trademark and Branding Policy 61 | [TODO: create policy, then insert link]. 62 | 63 | * **Do not restrict contributors.** If your company requires 64 | employees or contractors to sign non-compete agreements, those 65 | agreements must not prevent people from participating in the BA or 66 | contributing to related projects. 67 | 68 | This does not mean that all non-compete agreements are incompatible 69 | with this code of conduct. For example, a company may restrict an 70 | employee's ability to solicit the company's customers. However, an 71 | agreement must not block any form of technical or social 72 | participation in BA activities, including but not limited to the 73 | implementation of particular features. 74 | 75 | The accumulation of experience and expertise in individual persons, 76 | who are ultimately free to direct their energy and attention as 77 | they decide, is one of the most important drivers of progress in 78 | open source projects. A company that limits this freedom may hinder 79 | the success of the BA's efforts. 80 | 81 | * **Do not use patents as offensive weapons.** If any BA participant 82 | prevents the adoption or development of BA technologies by 83 | asserting its patents, that undermines the purpose of the 84 | coalition. The collaboration fostered by the BA cannot include 85 | members who act to undermine its work. 86 | 87 | * **Practice responsible disclosure** for security vulnerabilities. 88 | Use designated, non-public reporting channels to disclose technical 89 | vulnerabilities, and give the project a reasonable period to 90 | respond, remediate, and patch. [TODO: optionally include the 91 | security vulnerability reporting URL here.] 92 | 93 | Vulnerability reporters may patch their company's own offerings, as 94 | long as that patching does not significantly delay the reporting of 95 | the vulnerability. Vulnerability information should never be used 96 | for unilateral commercial advantage. Vendors may legitimately 97 | compete on the speed and reliability with which they deploy 98 | security fixes, but withholding vulnerability information damages 99 | everyone in the long run by risking harm to the BA project's 100 | reputation and to the security of all users. 101 | 102 | * **Respect the letter and spirit of open source practice.** While 103 | there is not space to list here all possible aspects of standard 104 | open source practice, some examples will help show what we mean: 105 | 106 | * Abide by all applicable open source license terms. Do not engage 107 | in copyright violation or misattribution of any kind. 108 | 109 | * Do not claim others' ideas or designs as your own. 110 | 111 | * When others engage in publicly visible work (e.g., an upcoming 112 | demo that is coordinated in a public issue tracker), do not 113 | unilaterally announce early releases or early demonstrations of 114 | that work ahead of their schedule in order to secure private 115 | advantage (such as marketplace advantage) for yourself. 116 | 117 | The BA reserves the right to determine what constitutes good open 118 | source practices and to take action as it deems appropriate to 119 | encourage, and if necessary enforce, such practices. 120 | 121 | ## Enforcement 122 | 123 | Instances of organizational behavior in violation of the OCoC may 124 | be reported by contacting the Bytecode Alliance CoC team at 125 | [report@bytecodealliance.org](mailto:report@bytecodealliance.org). The 126 | CoC team will review and investigate all complaints, and will respond 127 | in a way that it deems appropriate to the circumstances. The CoC team 128 | is obligated to maintain confidentiality with regard to the reporter of 129 | an incident. Further details of specific enforcement policies may be 130 | posted separately. 131 | 132 | When the BA deems an organization in violation of this OCoC, the BA 133 | will, at its sole discretion, determine what action to take. The BA 134 | will decide what type, degree, and duration of corrective action is 135 | needed, if any, before a violating organization can be considered for 136 | membership (if it was not already a member) or can have its membership 137 | reinstated (if it was a member and the BA canceled its membership due 138 | to the violation). 139 | 140 | In practice, the BA's first approach will be to start a conversation, 141 | with punitive enforcement used only as a last resort. Violations 142 | often turn out to be unintentional and swiftly correctable with all 143 | parties acting in good faith. 144 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 |

wasi

3 | 4 | A Bytecode Alliance project 5 | 6 |

7 | WASI API Bindings for Rust 8 |

9 | 10 |

11 | Crates.io version 12 | Download 13 | docs.rs docs 14 |

15 |
16 | 17 | This crate contains bindings for [WASI](https://github.com/WebAssembly/WASI) 18 | APIs for the worlds: 19 | 20 | * [`wasi:cli/command`] 21 | * [`wasi:http/proxy`] 22 | 23 | This crate is procedurally generated from [WIT] files using [`wit-bindgen`]. 24 | 25 | [`wasi:cli/command`]: https://github.com/WebAssembly/wasi-cli 26 | [`wasi:http/proxy`]: https://github.com/WebAssembly/wasi-http 27 | [WIT]: https://component-model.bytecodealliance.org/design/wit.html 28 | [`wit-bindgen`]: https://github.com/bytecodealliance/wit-bindgen 29 | [components]: https://component-model.bytecodealliance.org/ 30 | [`wasm-tools`]: https://github.com/bytecodealliance/wasm-tools 31 | 32 | # Usage 33 | 34 | Depending on this crate can be done by adding it to your dependencies: 35 | 36 | ```sh 37 | $ cargo add wasi 38 | ``` 39 | 40 | Next you can use the APIs in the root of the module like so: 41 | 42 | ```rust 43 | fn main() { 44 | let stdout = wasi::cli::stdout::get_stdout(); 45 | stdout.blocking_write_and_flush(b"Hello, world!\n").unwrap(); 46 | } 47 | ``` 48 | 49 | This crate can currently be used in three main ways. 50 | 51 | - One is to use it and compile for the [`wasm32-wasip2` target] in Rust 1.82 and later. 52 | This is the simplest approach, as all the tools needed are included in the 53 | Rust tooling, however it doesn't yet support some of the features of the 54 | other approaches. 55 | 56 | - Another is to use it and compile using [`cargo component`]. This is essentially 57 | the same as the next option, except that `cargo component` handles most of the 58 | steps for you. `cargo component` also has a number of additional features for 59 | working with dependencies and custom WIT interfaces. 60 | 61 | - And the third is to compile for the `wasm32-wasip1` target, and then adapt 62 | the resulting modules into component using `wasm-tools component new`; see 63 | the next section here for details. 64 | 65 | [`wasm32-wasip2` target]: https://blog.rust-lang.org/2024/11/26/wasip2-tier-2.html 66 | [`cargo component`]: https://github.com/bytecodealliance/cargo-component 67 | 68 | ## Building with wasm32-wasip1 and `cargo component new`. 69 | 70 | The `wasm32-wasip2` target works with a simple `cargo build --target=wasm32-wasip2` 71 | and doesn't need a lot of documentation here, and `cargo component` has its own 72 | documentation, so here we have some documentation for the `wasm32-wasip1` way. 73 | 74 | ``` 75 | $ cargo build --target wasm32-wasip1 76 | ``` 77 | 78 | Next you'll want an "adapter" to convert the Rust standard library's usage of 79 | `wasi_snapshot_preview1` to the component model. An example adapter can be found 80 | from [Wasmtime's release page](https://github.com/bytecodealliance/wasmtime/releases/download/v17.0.0/wasi_snapshot_preview1.command.wasm). 81 | 82 | ``` 83 | $ curl -LO https://github.com/bytecodealliance/wasmtime/releases/download/v17.0.0/wasi_snapshot_preview1.command.wasm 84 | ``` 85 | 86 | Next to create a component you'll use the [`wasm-tools`] CLI to create a 87 | component: 88 | 89 | ``` 90 | $ cargo install wasm-tools 91 | $ wasm-tools component new target/wasm32-wasip1/debug/foo.wasm \ 92 | --adapt ./wasi_snapshot_preview1.command.wasm \ 93 | -o component.wasm 94 | ``` 95 | 96 | And finally the component can be run by a runtime that has Component Model 97 | support, such as [Wasmtime]: 98 | 99 | ``` 100 | $ wasmtime run component.wasm 101 | Hello, world! 102 | ``` 103 | 104 | [Wasmtime]: https://github.com/bytecodealliance/wasmtime 105 | 106 | # WASIp2 vs WASIp1 107 | 108 | In January 2024 the WASI subgroup published WASI 0.2.0, colloquially known as 109 | "WASIp2". Around the same time the subgroup additionally decided to name the 110 | previous iteration of WASI as "WASIp1", historically known as "WASI preview1". 111 | This now-historical snapshot of WASI was defined with an entirely different set 112 | of primitives and worked very differently. This crate now targets WASIp2 and no 113 | longer targets WASIp1. 114 | 115 | ## Support for WASIp1 116 | 117 | The last version of the `wasi` crate to support WASIp1 was the 118 | [0.11.0+wasi-snapshot-preview1 119 | version](https://crates.io/crates/wasi/0.11.0+wasi-snapshot-preview1). This 120 | version of the crate supported all WASIp1 APIs. WASIp1 was historically defined 121 | with `*.witx` files and used a bindings generator called `witx-bindgen`. 122 | 123 | ## Should I use WASIp1 or WASIp2? 124 | 125 | This is a bit of a nuanced question/answer but the short answer is to probably 126 | use the 0.11.0 release of `wasi` for now if you're unsure. 127 | 128 | The longer-form answer of this is that it depends on the Rust targets that you 129 | want to support. Rust WebAssembly targets include: 130 | 131 | * `wasm32-unknown-unknown` - do not use this crate because this target indicates 132 | that WASI is not desired. 133 | * `wasm32-wasip1` - this target has been present in Rust for quite some time and 134 | was previously known as `wasm32-wasi`. For this target you probably want the 135 | 0.11.0 track of this crate. 136 | * `wasm32-wasip2` - this target is a recent addition to rustc (as of the time of 137 | this writing it's not merged yet into rustc). This is what the 0.12.0 version 138 | of the crate is intended for. 139 | 140 | Note that if you use `wasm32-wasip1` it's not necessarily guaranteed you want 141 | 0.11.0 of this crate. If your users are producing components then you probably 142 | want 0.12.0 instead. If you don't know what your users are producing then you 143 | should probably stick with 0.11.0. 144 | 145 | Long story short, it's a bit complicated. We're in a transition period from 146 | WASIp1 to WASIp2 and things aren't going to be perfect every step of the way, so 147 | understanding is appreciated! 148 | 149 | # Development 150 | 151 | The bulk of the `wasi` crate is generated by the [`wit-bindgen`] tool. The 152 | `src/bindings.rs` file can be regenerated with: 153 | 154 | ``` 155 | $ ./ci/regenerate.sh 156 | ``` 157 | 158 | WASI definitions are located in the `wit` directory of this repository. 159 | Currently they're copied from upstream repositories but are hoped to be better 160 | managed in the future. 161 | 162 | # License 163 | 164 | This project is triple licenced under the Apache 2/ Apache 2 with LLVM exceptions/ MIT licences. The reasoning for this is: 165 | - Apache 2/ MIT is common in the rust ecosystem. 166 | - Apache 2/ MIT is used in the rust standard library, and some of this code may be migrated there. 167 | - Some of this code may be used in compiler output, and the Apache 2 with LLVM exceptions licence is useful for this. 168 | 169 | For more details see 170 | - [Apache 2 Licence](LICENSE-APACHE) 171 | - [Apache 2 Licence with LLVM exceptions](LICENSE-Apache-2.0_WITH_LLVM-exception) 172 | - [MIT Licence](LICENSE-MIT) 173 | 174 | ### Contribution 175 | 176 | Unless you explicitly state otherwise, any contribution intentionally submitted 177 | for inclusion in this project by you, as defined in the Apache 2/ Apache 2 with LLVM exceptions/ MIT licenses, 178 | shall be licensed as above, without any additional terms or conditions. 179 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | Building secure foundations for software development is at the core of what we do in the Bytecode Alliance. Contributions of external security researchers are a vital part of that. 4 | 5 | ## Scope 6 | 7 | If you believe you've found a security issue in any website, service, or software owned or operated by the Bytecode Alliance, we encourage you to notify us. 8 | 9 | ## How to Submit a Report 10 | 11 | To submit a vulnerability report to the Bytecode Alliance, please contact us at [security@bytecodealliance.org](mailto:security@bytecodealliance.org). Your submission will be reviewed and validated by a member of our security team. 12 | 13 | ## Safe Harbor 14 | 15 | The Bytecode Alliance supports safe harbor for security researchers who: 16 | 17 | * Make a good faith effort to avoid privacy violations, destruction of data, and interruption or degradation of our services. 18 | * Only interact with accounts you own or with explicit permission of the account holder. If you do encounter Personally Identifiable Information (PII) contact us immediately, do not proceed with access, and immediately purge any local information. 19 | * Provide us with a reasonable amount of time to resolve vulnerabilities prior to any disclosure to the public or a third-party. 20 | 21 | We will consider activities conducted consistent with this policy to constitute "authorized" conduct and will not pursue civil action or initiate a complaint to law enforcement. We will help to the extent we can if legal action is initiated by a third party against you. 22 | 23 | Please submit a report to us before engaging in conduct that may be inconsistent with or unaddressed by this policy. 24 | 25 | ## Preferences 26 | 27 | * Please provide detailed reports with reproducible steps and a clearly defined impact. 28 | * Submit one vulnerability per report. 29 | * Social engineering (e.g. phishing, vishing, smishing) is prohibited. 30 | -------------------------------------------------------------------------------- /ci/regenerate.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -ex 4 | 5 | generate() { 6 | file="$1" 7 | shift 8 | wit-bindgen rust wit --async none --out-dir src --std-feature "$@" --format \ 9 | --runtime-path wit_bindgen_rt 10 | } 11 | 12 | # Generate the main body of the bindings which includes all imports from the two 13 | # worlds below. 14 | generate src/bindings.rs --type-section-suffix rust-wasi-from-crates-io \ 15 | --generate-all 16 | 17 | # Generate bindings for the `wasi:cli/command` world specifically, namely the 18 | # macro `export_command`. 19 | # 20 | # Note that `--with` is used to point at the previously generated bindings. 21 | with="wasi:cli/environment@0.2.4=crate::cli::environment" 22 | with="$with,wasi:cli/exit@0.2.4=crate::cli::exit" 23 | with="$with,wasi:cli/stdin@0.2.4=crate::cli::stdin" 24 | with="$with,wasi:cli/stdout@0.2.4=crate::cli::stdout" 25 | with="$with,wasi:cli/stderr@0.2.4=crate::cli::stderr" 26 | with="$with,wasi:cli/terminal-input@0.2.4=crate::cli::terminal_input" 27 | with="$with,wasi:cli/terminal-output@0.2.4=crate::cli::terminal_output" 28 | with="$with,wasi:cli/terminal-stdin@0.2.4=crate::cli::terminal_stdin" 29 | with="$with,wasi:cli/terminal-stdout@0.2.4=crate::cli::terminal_stdout" 30 | with="$with,wasi:cli/terminal-stderr@0.2.4=crate::cli::terminal_stderr" 31 | with="$with,wasi:clocks/monotonic-clock@0.2.4=crate::clocks::monotonic_clock" 32 | with="$with,wasi:clocks/wall-clock@0.2.4=crate::clocks::wall_clock" 33 | with="$with,wasi:filesystem/types@0.2.4=crate::filesystem::types" 34 | with="$with,wasi:filesystem/preopens@0.2.4=crate::filesystem::preopens" 35 | with="$with,wasi:io/error@0.2.4=crate::io::error" 36 | with="$with,wasi:io/poll@0.2.4=crate::io::poll" 37 | with="$with,wasi:io/streams@0.2.4=crate::io::streams" 38 | with="$with,wasi:random/random@0.2.4=crate::random::random" 39 | with="$with,wasi:random/insecure@0.2.4=crate::random::insecure" 40 | with="$with,wasi:random/insecure-seed@0.2.4=crate::random::insecure_seed" 41 | with="$with,wasi:sockets/network@0.2.4=crate::sockets::network" 42 | with="$with,wasi:sockets/instance-network@0.2.4=crate::sockets::instance_network" 43 | with="$with,wasi:sockets/tcp@0.2.4=crate::sockets::tcp" 44 | with="$with,wasi:sockets/tcp-create-socket@0.2.4=crate::sockets::tcp_create_socket" 45 | with="$with,wasi:sockets/udp@0.2.4=crate::sockets::udp" 46 | with="$with,wasi:sockets/udp-create-socket@0.2.4=crate::sockets::udp_create_socket" 47 | with="$with,wasi:sockets/ip-name-lookup@0.2.4=crate::sockets::ip_name_lookup" 48 | generate src/command.rs \ 49 | --world wasi:cli/command \ 50 | --with "$with" \ 51 | --type-section-suffix rust-wasi-from-crates-io-command-world \ 52 | --default-bindings-module wasi \ 53 | --pub-export-macro \ 54 | --export-macro-name _export_command 55 | 56 | # Same as the `command` world, but for the proxy world. 57 | with="wasi:cli/stdin@0.2.4=crate::cli::stdin" 58 | with="$with,wasi:cli/stdout@0.2.4=crate::cli::stdout" 59 | with="$with,wasi:cli/stderr@0.2.4=crate::cli::stderr" 60 | with="$with,wasi:clocks/monotonic-clock@0.2.4=crate::clocks::monotonic_clock" 61 | with="$with,wasi:clocks/wall-clock@0.2.4=crate::clocks::wall_clock" 62 | with="$with,wasi:io/error@0.2.4=crate::io::error" 63 | with="$with,wasi:io/poll@0.2.4=crate::io::poll" 64 | with="$with,wasi:io/streams@0.2.4=crate::io::streams" 65 | with="$with,wasi:random/random@0.2.4=crate::random::random" 66 | with="$with,wasi:http/types@0.2.4=crate::http::types" 67 | with="$with,wasi:http/outgoing-handler@0.2.4=crate::http::outgoing_handler" 68 | generate src/proxy.rs \ 69 | --world wasi:http/proxy \ 70 | --with "$with" \ 71 | --type-section-suffix rust-wasi-from-crates-io-proxy-world \ 72 | --default-bindings-module wasi \ 73 | --pub-export-macro \ 74 | --export-macro-name _export_proxy 75 | -------------------------------------------------------------------------------- /ci/vendor-wit.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Script to re-vendor the WIT files that wasi-rs uses as defined by a 4 | # particular tag in upstream repositories. 5 | # 6 | # This script is executed on CI to ensure that everything is up-to-date. 7 | set -ex 8 | 9 | # Space-separated list of wasi proposals that are vendored here along with the 10 | # tag that they're all vendored at. 11 | # 12 | # This assumes that the repositories all have the pattern: 13 | # https://github.com/WebAssembly/wasi-$repo 14 | # and every repository has a tag `v$tag` here. That is currently done as part 15 | # of the WASI release process. 16 | repos="cli clocks filesystem http io random sockets" 17 | tag=0.2.4 18 | dst=wit/deps 19 | 20 | rm -rf $dst 21 | mkdir -p $dst 22 | 23 | for repo in $repos; do 24 | mkdir $dst/$repo 25 | curl -L https://github.com/WebAssembly/wasi-$repo/archive/refs/tags/v$tag.tar.gz | \ 26 | tar xzf - --strip-components=2 -C $dst/$repo wasi-$repo-$tag/wit 27 | rm -rf $dst/$repo/deps* 28 | done 29 | -------------------------------------------------------------------------------- /crates/wasi-ext/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wasi-ext" 3 | version = "0.1.0" 4 | authors = ["Roman Volosatovs "] 5 | description = "Third-party crate integrations for WASI" 6 | 7 | license.workspace = true 8 | edition.workspace = true 9 | repository.workspace = true 10 | 11 | [features] 12 | default = ["std"] 13 | std = ["wasi/std"] 14 | 15 | [dependencies] 16 | rand = { workspace = true, optional = true } 17 | wasi = { workspace = true } 18 | 19 | [[example]] 20 | name = "rand" 21 | required-features = ["rand", "std"] 22 | -------------------------------------------------------------------------------- /crates/wasi-ext/examples/rand.rs: -------------------------------------------------------------------------------- 1 | use std::io::Write as _; 2 | 3 | use wasi_ext::rand::rand::Rng as _; 4 | use wasi_ext::rand::{HostInsecureRng, HostRng}; 5 | 6 | fn main() { 7 | let mut stdout = wasi::cli::stdout::get_stdout(); 8 | 9 | let r: u64 = HostRng.gen(); 10 | writeln!(stdout, "Cryptographically-secure random u64 is {r}").unwrap(); 11 | 12 | let r: u64 = HostInsecureRng.gen(); 13 | writeln!(stdout, "Pseudo-random u64 is {r}").unwrap(); 14 | 15 | stdout.flush().unwrap(); 16 | } 17 | -------------------------------------------------------------------------------- /crates/wasi-ext/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "rand")] 2 | pub mod rand; 3 | -------------------------------------------------------------------------------- /crates/wasi-ext/src/rand.rs: -------------------------------------------------------------------------------- 1 | pub use rand; 2 | 3 | use rand::{CryptoRng, RngCore}; 4 | 5 | /// The secure interface for cryptographically-secure random numbers 6 | pub struct HostRng; 7 | 8 | impl CryptoRng for HostRng {} 9 | 10 | impl RngCore for HostRng { 11 | #[inline] 12 | fn next_u32(&mut self) -> u32 { 13 | wasi::random::random::get_random_u64() as _ 14 | } 15 | 16 | #[inline] 17 | fn next_u64(&mut self) -> u64 { 18 | wasi::random::random::get_random_u64() 19 | } 20 | 21 | fn fill_bytes(&mut self, dest: &mut [u8]) { 22 | let n = dest.len(); 23 | if usize::BITS <= u64::BITS || n <= u64::MAX as _ { 24 | dest.copy_from_slice(&wasi::random::random::get_random_bytes(n as _)); 25 | } else { 26 | let (head, tail) = dest.split_at_mut(u64::MAX as _); 27 | head.copy_from_slice(&wasi::random::random::get_random_bytes(u64::MAX)); 28 | self.fill_bytes(tail); 29 | } 30 | } 31 | 32 | #[inline] 33 | fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand::Error> { 34 | self.fill_bytes(dest); 35 | Ok(()) 36 | } 37 | } 38 | 39 | /// The insecure interface for insecure pseudo-random numbers 40 | pub struct HostInsecureRng; 41 | 42 | impl RngCore for HostInsecureRng { 43 | #[inline] 44 | fn next_u32(&mut self) -> u32 { 45 | wasi::random::insecure::get_insecure_random_u64() as _ 46 | } 47 | 48 | #[inline] 49 | fn next_u64(&mut self) -> u64 { 50 | wasi::random::insecure::get_insecure_random_u64() 51 | } 52 | 53 | fn fill_bytes(&mut self, dest: &mut [u8]) { 54 | let n = dest.len(); 55 | if usize::BITS <= u64::BITS || n <= u64::MAX as _ { 56 | dest.copy_from_slice(&wasi::random::insecure::get_insecure_random_bytes(n as _)); 57 | } else { 58 | let (head, tail) = dest.split_at_mut(u64::MAX as _); 59 | head.copy_from_slice(&wasi::random::insecure::get_insecure_random_bytes(u64::MAX)); 60 | self.fill_bytes(tail); 61 | } 62 | } 63 | 64 | #[inline] 65 | fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand::Error> { 66 | self.fill_bytes(dest); 67 | Ok(()) 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /examples/cli-command-no_std.rs: -------------------------------------------------------------------------------- 1 | wasi::cli::command::export!(Example); 2 | 3 | struct Example; 4 | 5 | impl wasi::exports::cli::run::Guest for Example { 6 | fn run() -> Result<(), ()> { 7 | let stdout = wasi::cli::stdout::get_stdout(); 8 | stdout.blocking_write_and_flush(b"Hello, WASI!").unwrap(); 9 | Ok(()) 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /examples/cli-command.rs: -------------------------------------------------------------------------------- 1 | use std::io::Write as _; 2 | 3 | wasi::cli::command::export!(Example); 4 | 5 | struct Example; 6 | 7 | impl wasi::exports::cli::run::Guest for Example { 8 | fn run() -> Result<(), ()> { 9 | let mut stdout = wasi::cli::stdout::get_stdout(); 10 | stdout.write_all(b"Hello, WASI!").unwrap(); 11 | stdout.flush().unwrap(); 12 | Ok(()) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /examples/hello-world-no_std.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let stdout = wasi::cli::stdout::get_stdout(); 3 | stdout.blocking_write_and_flush(b"Hello, world!\n").unwrap(); 4 | } 5 | -------------------------------------------------------------------------------- /examples/hello-world.rs: -------------------------------------------------------------------------------- 1 | use std::io::Write as _; 2 | 3 | fn main() { 4 | let mut stdout = wasi::cli::stdout::get_stdout(); 5 | stdout.write_all(b"Hello, world!\n").unwrap(); 6 | stdout.flush().unwrap(); 7 | } 8 | -------------------------------------------------------------------------------- /examples/http-proxy-no_std.rs: -------------------------------------------------------------------------------- 1 | use wasi::http::types::{ 2 | Fields, IncomingRequest, OutgoingBody, OutgoingResponse, ResponseOutparam, 3 | }; 4 | 5 | wasi::http::proxy::export!(Example); 6 | 7 | struct Example; 8 | 9 | impl wasi::exports::http::incoming_handler::Guest for Example { 10 | fn handle(_request: IncomingRequest, response_out: ResponseOutparam) { 11 | let resp = OutgoingResponse::new(Fields::new()); 12 | let body = resp.body().unwrap(); 13 | 14 | ResponseOutparam::set(response_out, Ok(resp)); 15 | 16 | let out = body.write().unwrap(); 17 | out.blocking_write_and_flush(b"Hello, WASI!").unwrap(); 18 | drop(out); 19 | 20 | OutgoingBody::finish(body, None).unwrap(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /examples/http-proxy.rs: -------------------------------------------------------------------------------- 1 | use std::io::Write as _; 2 | 3 | use wasi::http::types::{ 4 | Fields, IncomingRequest, OutgoingBody, OutgoingResponse, ResponseOutparam, 5 | }; 6 | 7 | wasi::http::proxy::export!(Example); 8 | 9 | struct Example; 10 | 11 | impl wasi::exports::http::incoming_handler::Guest for Example { 12 | fn handle(_request: IncomingRequest, response_out: ResponseOutparam) { 13 | let resp = OutgoingResponse::new(Fields::new()); 14 | let body = resp.body().unwrap(); 15 | 16 | ResponseOutparam::set(response_out, Ok(resp)); 17 | 18 | let mut out = body.write().unwrap(); 19 | out.write_all(b"Hello, WASI!").unwrap(); 20 | out.flush().unwrap(); 21 | drop(out); 22 | 23 | OutgoingBody::finish(body, None).unwrap(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/ext/mod.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "std")] 2 | mod std; 3 | 4 | impl core::fmt::Display for crate::io::error::Error { 5 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 6 | f.write_str(&self.to_debug_string()) 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/ext/std.rs: -------------------------------------------------------------------------------- 1 | use std::error::Error; 2 | use std::io; 3 | use std::num::NonZeroU64; 4 | 5 | use crate::io::streams::StreamError; 6 | 7 | impl Error for crate::io::error::Error {} 8 | 9 | impl io::Read for crate::io::streams::InputStream { 10 | fn read(&mut self, buf: &mut [u8]) -> io::Result { 11 | let n = buf 12 | .len() 13 | .try_into() 14 | .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?; 15 | match self.blocking_read(n) { 16 | Ok(chunk) => { 17 | let n = chunk.len(); 18 | if n > buf.len() { 19 | return Err(io::Error::new( 20 | io::ErrorKind::Other, 21 | "more bytes read than requested", 22 | )); 23 | } 24 | buf[..n].copy_from_slice(&chunk); 25 | Ok(n) 26 | } 27 | Err(StreamError::Closed) => Ok(0), 28 | Err(StreamError::LastOperationFailed(e)) => { 29 | Err(io::Error::new(io::ErrorKind::Other, e.to_debug_string())) 30 | } 31 | } 32 | } 33 | } 34 | 35 | impl io::Write for crate::io::streams::OutputStream { 36 | fn write(&mut self, buf: &[u8]) -> io::Result { 37 | let n = loop { 38 | match self.check_write().map(NonZeroU64::new) { 39 | Ok(Some(n)) => { 40 | break n; 41 | } 42 | Ok(None) => { 43 | self.subscribe().block(); 44 | } 45 | Err(StreamError::Closed) => return Ok(0), 46 | Err(StreamError::LastOperationFailed(e)) => { 47 | return Err(io::Error::new(io::ErrorKind::Other, e.to_debug_string())) 48 | } 49 | }; 50 | }; 51 | let n = n 52 | .get() 53 | .try_into() 54 | .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?; 55 | let n = buf.len().min(n); 56 | crate::io::streams::OutputStream::write(self, &buf[..n]).map_err(|e| match e { 57 | StreamError::Closed => io::ErrorKind::UnexpectedEof.into(), 58 | StreamError::LastOperationFailed(e) => { 59 | io::Error::new(io::ErrorKind::Other, e.to_debug_string()) 60 | } 61 | })?; 62 | Ok(n) 63 | } 64 | 65 | fn flush(&mut self) -> io::Result<()> { 66 | self.blocking_flush() 67 | .map_err(|e| io::Error::new(io::ErrorKind::Other, e)) 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Raw API bindings to the [WebAssembly System Interface (WASI)][WASI] 2 | //! 3 | //! [WASI]: https://github.com/WebAssembly/WASI 4 | //! 5 | //! This crate provides Rust API bindings to the imports of [WASI] [worlds] such 6 | //! as: 7 | //! 8 | //! * [`wasi:cli/command`] 9 | //! * [`wasi:http/proxy`] 10 | //! 11 | //! This crate is procedurally generated with the [`wit-bindgen`] bindings 12 | //! generator. Note that generated code is published to crates.io to slim this 13 | //! crate down in terms of build dependencies and resources. 14 | //! 15 | //! # What is WASI? 16 | //! 17 | //! [WASI] is a set of APIs defined for the WebAssembly [Component Model] to 18 | //! help components interact with the outside world. Core WebAssembly has no 19 | //! intrinsic ability to access the host, for example `println!` don't work, but 20 | //! [WASI] defines how to do so with the [`wasi:cli/stdio`] package. 21 | //! 22 | //! [WASI] is defined by an IDL called [WIT] using files that have the extension 23 | //! `*.wit`. [WASI] and [WIT] are themselves then both defined in terms of the 24 | //! [Component Model] in terms of types available and base semantics for APIs. 25 | //! 26 | //! [WASI] defines a number of standard "worlds" which are a description of a 27 | //! what a WebAssembly component can import from an embedding and must export to 28 | //! an embedding. An example world is [`wasi:cli/command`] which is a world for 29 | //! running CLI applications. This world provides basic system utilities such as 30 | //! clocks, a filesystem, CLI arguments, etc. The one required export is a main 31 | //! function. 32 | //! 33 | //! The purpose of this crate is to provide pregenerated bindings to access 34 | //! [WASI]-defined imports available to components. 35 | //! 36 | //! # What is a Component? 37 | //! 38 | //! An important aspect of [WASI] is that it is defined in terms of the 39 | //! [Component Model]. The [Component Model] is a proposal for WebAssembly which 40 | //! is a new format for wasm binaries, a component. A component contains "core" 41 | //! WebAssembly modules (which are [standard WebAssembly modules]) but also has 42 | //! the ability to do more: 43 | //! 44 | //! * A component can contain multiple core WebAssembly modules. 45 | //! * Types used with component imports and exports are more comprehensive than 46 | //! core WebAssembly. Core WebAssembly provides integers and floats, for 47 | //! example, and components build on this and add strings, records (aka a Rust 48 | //! `struct`), variants (aka a Rust `enum`), and resources (think a file 49 | //! descriptor on Unix). 50 | //! * A component provides procedural instructions of how to instantiate its 51 | //! internal core WebAssembly modules with the imports it has. 52 | //! 53 | //! The [Component Model] is a not considered an official WebAssembly standard 54 | //! at this time. It has been in development for 5 years (as of January 2024), 55 | //! however, and the WASI 0.2.0 milestone (more on versioning in a moment) in 56 | //! January 2024 represents a concrete target for ecosystems to use. Runtimes 57 | //! such as [Wasmtime] support the [Component Model] for out-of-browser usage 58 | //! and [jco] is an example of how components can be run in a browser. 59 | //! 60 | //! A full description of the component model is out of scope for this crate's 61 | //! documentation but it suffices to say that [WASI], and this crate, are 62 | //! intended to target components. Components use core WebAssembly modules as an 63 | //! important technical detail, but the final output of this crate is intended 64 | //! to be a component. 65 | //! 66 | //! # What are generated bindings? 67 | //! 68 | //! Above it was seen that [WASI] is defined with [WIT]. These programmatic 69 | //! descriptions of [WASI] APIs are not suitable for use directly in Rust, 70 | //! however these descriptions define how Rust can use them. Each [WIT] function 71 | //! has a defined meaning in core WebAssembly via the [Canonical ABI]. This is a 72 | //! lower level than most users want to operate at, however, so the generated 73 | //! bindings in this crate serve as the bridge. 74 | //! 75 | //! More specifically the generated functions in this crate take the [Canonical 76 | //! ABI] format of [WIT] functions and provide idiomatic Rust functions to call. 77 | //! For example the [`wasi:cli/environment`] definition includes: 78 | //! 79 | //! ```wit 80 | //! interface environment { 81 | //! // ... 82 | //! get-environment: func() -> list>; 83 | //! // ... 84 | //! } 85 | //! ``` 86 | //! 87 | //! This corresponds to 88 | //! [`wasi::cli::environment::get_environment`](crate::cli::environment::get_environment). 89 | //! 90 | //! Bindings are pre-generated in this crate with the [`wit-bindgen`] tool. You 91 | //! can also generate your own bindings with [`wit-bindgen`] and [WASI] [WIT] 92 | //! files too, but that's not covered by this crate. 93 | //! 94 | //! # WASI Today and `wasi_snapshot_preview1` 95 | //! 96 | //! This crate is based on the 0.2.0 version of [WASI] APIs. This version of 97 | //! [WASI] was declared "phase 3" (suitable for general use and testing) in 98 | //! January of 2024. Prior to this 0.2.0 "preview2" release of [WASI] there was 99 | //! `wasi_snapshot_preview1`. This previous "preview1" release of [WASI] was 100 | //! circa 2019 and was the initial vision for [WASI] as a standard. Development 101 | //! of [WASI] migrated to the [Component Model] in the meantime. 102 | //! 103 | //! This means that the old `wasi_snapshot_preview1` interfaces are no longer 104 | //! provided by this crate because [WASI] is no longer defined by those 105 | //! interfaces. This includes the historical `*.witx` format which has now been 106 | //! sueprseded. Note that the 0.11.x release series of this crate contains 107 | //! bindings to the historical `wasi_snapshot_preview1` APIs if you're 108 | //! interested in using them. 109 | //! 110 | //! # Crate Organization 111 | //! 112 | //! This crate is currently entirely generated by [`wit-bindgen`] which has the 113 | //! following structure: 114 | //! 115 | //! * Each [WIT] package with bindings corresponds to a top-level module. For 116 | //! example [`wasi:random`] can be found in the [`random`] module. 117 | //! * Each [WIT] interface then corresponds to a submodule of its package's 118 | //! module. For example [`wasi:random/insecure`] can be found in the 119 | //! [`random::insecure`] module. 120 | //! * Each [WIT] function has a Rust function with an idiomatic signature. 121 | //! module. For example [`random::insecure::get_insecure_random_u64`]. 122 | //! 123 | //! Note that [WIT] documentation is rendered as rustdoc documentation in these 124 | //! APIs as well. 125 | //! 126 | //! # Using this Crate 127 | //! 128 | //! This crate is intended to be easiest to use with a future 129 | //! `wasm32-wasip2` target added to the Rust compiler. In the meantime 130 | //! it's recommended to use the `wasm32-wasip1` target instead: 131 | //! 132 | //! ```sh 133 | //! $ cargo build --target wasm32-wasip1 134 | //! ``` 135 | //! 136 | //! Note that the output of the `wasm32-wasip1` target is a core wasm module, not 137 | //! a component, so to turn it into a component you can use the [`wasm-tools`] 138 | //! CLI in combination with an "adapter module" for the `wasi_snapshot_preview1` 139 | //! APIs that the Rust standard library uses (example adapters can be found on 140 | //! [Wasmtime's release page][adapters] as 141 | //! [`wasi_snapshot_preview1.command.wasm`] for example) 142 | //! 143 | //! ```sh 144 | //! $ wasm-tools component new ./target/wasm32-wasip1/debug/my-app.wasm \ 145 | //! --adapt ./wasi_snapshot_preview1.command.wasm \ 146 | //! -o my-component.wasm 147 | //! ``` 148 | //! 149 | //! ## Export Macros 150 | //! 151 | //! In addition to providing bindings for imports this crate also provides 152 | //! macros to export the `wasi:cli/run` and `wasi:http/proxy` worlds, see their 153 | //! respective documentation for more information: 154 | //! 155 | //! - [`wasi::cli::command::export!`](crate::cli::command::export) 156 | //! - [`wasi::http::proxy::export!`](crate::http::proxy::export) 157 | //! 158 | //! [worlds]: https://component-model.bytecodealliance.org/design/worlds.html 159 | //! [`wasi:cli/command`]: https://github.com/WebAssembly/wasi-cli/ 160 | //! [`wasi:http/proxy`]: https://github.com/WebAssembly/wasi-http 161 | //! [`wasi:cli/stdio`]: https://github.com/WebAssembly/wasi-cli/blob/main/wit/stdio.wit 162 | //! [`wit-bindgen`]: https://github.com/bytecodealliance/wit-bindgen/ 163 | //! [Component Model]: https://component-model.bytecodealliance.org/ 164 | //! [WIT]: https://component-model.bytecodealliance.org/design/wit.html 165 | //! [standard WebAssembly modules]: https://webassembly.github.io/spec/ 166 | //! [Wasmtime]: https://github.com/bytecodealliance/wasmtime 167 | //! [jco]: https://github.com/bytecodealliance/jco 168 | //! [Canonical ABI]: https://github.com/WebAssembly/component-model/blob/main/design/mvp/CanonicalABI.md 169 | //! [`wasi:cli/environment`]: https://github.com/WebAssembly/wasi-cli/blob/main/wit/environment.wit 170 | //! [`wasi:random`]: https://github.com/WebAssembly/wasi-random 171 | //! [`wasi:random/insecure`]: https://github.com/WebAssembly/wasi-random/blob/main/wit/insecure.wit 172 | //! [`wasm-tools`]: https://github.com/bytecodealliance/wasm-tools 173 | //! [adapters]: https://github.com/bytecodealliance/wasmtime/releases 174 | //! [`wasi_snapshot_preview1.command.wasm`]: https://github.com/bytecodealliance/wasmtime/releases/download/v17.0.0/wasi_snapshot_preview1.command.wasm 175 | 176 | #![no_std] 177 | 178 | #[cfg(feature = "std")] 179 | extern crate std; 180 | 181 | pub mod ext; 182 | 183 | // These modules are all auto-generated by `./ci/regenerate.sh` 184 | mod bindings; 185 | #[allow(unused_imports)] 186 | mod command; 187 | #[allow(unused_imports)] 188 | mod proxy; 189 | 190 | // generated bindings start with the package namespace, which in this case is 191 | // `wasi`, but the crate is already called wasi, so lift everything up one level 192 | // to the root of this crate. 193 | pub use bindings::wasi::*; 194 | 195 | // Expand the `cli` and `http` modules with `export!` macros for the 196 | // command/proxy worlds, but also retain all the contents defined in the 197 | // `bindings` module as well. 198 | pub mod cli { 199 | pub use super::bindings::wasi::cli::*; 200 | 201 | pub mod command { 202 | /// Generate an exported instance of the `wasi:cli/command` world. 203 | /// 204 | /// This macro generate the `#[no_mangle]` functions necessary to 205 | /// export this interface. It takes an argument which is a type that 206 | /// must implement the 207 | /// [`exports::cli::run::Guest`](crate::exports::cli::run::Guest) 208 | /// trait. 209 | /// 210 | /// ``` 211 | /// struct MyCliRunner; 212 | /// 213 | /// impl wasi::exports::cli::run::Guest for MyCliRunner { 214 | /// fn run() -> Result<(), ()> { 215 | /// // ... 216 | /// # panic!(); 217 | /// } 218 | /// } 219 | /// 220 | /// wasi::cli::command::export!(MyCliRunner); 221 | /// ``` 222 | /// 223 | /// ## Compatibility with `wasm32-wasip1` targets 224 | /// 225 | /// This macro is not compatible with `wasm32-wasip1` `bin` targets 226 | /// which instead use a `fn main()` with the 227 | /// `wasi_snapshot_preview1.command.wasm` adapter. This macro _can_ be 228 | /// used with the `reactor` or `proxy` adapters. 229 | /// 230 | /// 234 | #[doc(inline)] 235 | pub use crate::command::_export_command as export; 236 | } 237 | } 238 | 239 | pub mod http { 240 | pub use super::bindings::wasi::http::*; 241 | 242 | pub mod proxy { 243 | /// Generate an exported instance of the `wasi:http/proxy` world. 244 | /// 245 | /// This macro will generate `#[no_mangle]` functions as necessary to 246 | /// export an implementation of the 247 | /// [`exports::http::incoming_handler::Guest`](crate::exports::http::incoming_handler::Guest) 248 | /// trait. This macro takes 249 | /// an argument which is a type that implements this trait: 250 | /// 251 | /// ``` 252 | /// use wasi::http::types::{IncomingRequest, ResponseOutparam}; 253 | /// 254 | /// struct MyIncomingHandler; 255 | /// 256 | /// impl wasi::exports::http::incoming_handler::Guest for MyIncomingHandler { 257 | /// fn handle(request: IncomingRequest, response_out: ResponseOutparam) { 258 | /// // ... 259 | /// # panic!(); 260 | /// } 261 | /// } 262 | /// 263 | /// wasi::http::proxy::export!(MyIncomingHandler); 264 | /// ``` 265 | /// 266 | /// 270 | #[doc(inline)] 271 | pub use crate::proxy::_export_proxy as export; 272 | } 273 | } 274 | 275 | pub mod exports { 276 | // This is required by the `export!` macros of this crate which assume that 277 | // the types it's referring to show up as `exports::wasi::...`. 278 | // 279 | // This isn't part of the public interface, though, so hide this. 280 | #[doc(hidden)] 281 | pub mod wasi { 282 | pub use crate::command::exports::wasi::*; 283 | pub use crate::proxy::exports::wasi::*; 284 | } 285 | 286 | // These are the restructured public interface of this crate. 287 | pub use crate::command::exports::wasi::cli; 288 | pub use crate::proxy::exports::wasi::http; 289 | } 290 | 291 | // These macros are used by recursive invocations of the macro, but they're 292 | // `#[doc(hidden)]` as it's not part of the public interface. 293 | #[doc(hidden)] 294 | pub use crate::command::_export_command; 295 | #[doc(hidden)] 296 | pub use crate::proxy::_export_proxy; 297 | -------------------------------------------------------------------------------- /wit/deps/cli/command.wit: -------------------------------------------------------------------------------- 1 | package wasi:cli@0.2.4; 2 | 3 | @since(version = 0.2.0) 4 | world command { 5 | @since(version = 0.2.0) 6 | include imports; 7 | 8 | @since(version = 0.2.0) 9 | export run; 10 | } 11 | -------------------------------------------------------------------------------- /wit/deps/cli/environment.wit: -------------------------------------------------------------------------------- 1 | @since(version = 0.2.0) 2 | interface environment { 3 | /// Get the POSIX-style environment variables. 4 | /// 5 | /// Each environment variable is provided as a pair of string variable names 6 | /// and string value. 7 | /// 8 | /// Morally, these are a value import, but until value imports are available 9 | /// in the component model, this import function should return the same 10 | /// values each time it is called. 11 | @since(version = 0.2.0) 12 | get-environment: func() -> list>; 13 | 14 | /// Get the POSIX-style arguments to the program. 15 | @since(version = 0.2.0) 16 | get-arguments: func() -> list; 17 | 18 | /// Return a path that programs should use as their initial current working 19 | /// directory, interpreting `.` as shorthand for this. 20 | @since(version = 0.2.0) 21 | initial-cwd: func() -> option; 22 | } 23 | -------------------------------------------------------------------------------- /wit/deps/cli/exit.wit: -------------------------------------------------------------------------------- 1 | @since(version = 0.2.0) 2 | interface exit { 3 | /// Exit the current instance and any linked instances. 4 | @since(version = 0.2.0) 5 | exit: func(status: result); 6 | 7 | /// Exit the current instance and any linked instances, reporting the 8 | /// specified status code to the host. 9 | /// 10 | /// The meaning of the code depends on the context, with 0 usually meaning 11 | /// "success", and other values indicating various types of failure. 12 | /// 13 | /// This function does not return; the effect is analogous to a trap, but 14 | /// without the connotation that something bad has happened. 15 | @unstable(feature = cli-exit-with-code) 16 | exit-with-code: func(status-code: u8); 17 | } 18 | -------------------------------------------------------------------------------- /wit/deps/cli/imports.wit: -------------------------------------------------------------------------------- 1 | package wasi:cli@0.2.4; 2 | 3 | @since(version = 0.2.0) 4 | world imports { 5 | @since(version = 0.2.0) 6 | include wasi:clocks/imports@0.2.4; 7 | @since(version = 0.2.0) 8 | include wasi:filesystem/imports@0.2.4; 9 | @since(version = 0.2.0) 10 | include wasi:sockets/imports@0.2.4; 11 | @since(version = 0.2.0) 12 | include wasi:random/imports@0.2.4; 13 | @since(version = 0.2.0) 14 | include wasi:io/imports@0.2.4; 15 | 16 | @since(version = 0.2.0) 17 | import environment; 18 | @since(version = 0.2.0) 19 | import exit; 20 | @since(version = 0.2.0) 21 | import stdin; 22 | @since(version = 0.2.0) 23 | import stdout; 24 | @since(version = 0.2.0) 25 | import stderr; 26 | @since(version = 0.2.0) 27 | import terminal-input; 28 | @since(version = 0.2.0) 29 | import terminal-output; 30 | @since(version = 0.2.0) 31 | import terminal-stdin; 32 | @since(version = 0.2.0) 33 | import terminal-stdout; 34 | @since(version = 0.2.0) 35 | import terminal-stderr; 36 | } 37 | -------------------------------------------------------------------------------- /wit/deps/cli/run.wit: -------------------------------------------------------------------------------- 1 | @since(version = 0.2.0) 2 | interface run { 3 | /// Run the program. 4 | @since(version = 0.2.0) 5 | run: func() -> result; 6 | } 7 | -------------------------------------------------------------------------------- /wit/deps/cli/stdio.wit: -------------------------------------------------------------------------------- 1 | @since(version = 0.2.0) 2 | interface stdin { 3 | @since(version = 0.2.0) 4 | use wasi:io/streams@0.2.4.{input-stream}; 5 | 6 | @since(version = 0.2.0) 7 | get-stdin: func() -> input-stream; 8 | } 9 | 10 | @since(version = 0.2.0) 11 | interface stdout { 12 | @since(version = 0.2.0) 13 | use wasi:io/streams@0.2.4.{output-stream}; 14 | 15 | @since(version = 0.2.0) 16 | get-stdout: func() -> output-stream; 17 | } 18 | 19 | @since(version = 0.2.0) 20 | interface stderr { 21 | @since(version = 0.2.0) 22 | use wasi:io/streams@0.2.4.{output-stream}; 23 | 24 | @since(version = 0.2.0) 25 | get-stderr: func() -> output-stream; 26 | } 27 | -------------------------------------------------------------------------------- /wit/deps/cli/terminal.wit: -------------------------------------------------------------------------------- 1 | /// Terminal input. 2 | /// 3 | /// In the future, this may include functions for disabling echoing, 4 | /// disabling input buffering so that keyboard events are sent through 5 | /// immediately, querying supported features, and so on. 6 | @since(version = 0.2.0) 7 | interface terminal-input { 8 | /// The input side of a terminal. 9 | @since(version = 0.2.0) 10 | resource terminal-input; 11 | } 12 | 13 | /// Terminal output. 14 | /// 15 | /// In the future, this may include functions for querying the terminal 16 | /// size, being notified of terminal size changes, querying supported 17 | /// features, and so on. 18 | @since(version = 0.2.0) 19 | interface terminal-output { 20 | /// The output side of a terminal. 21 | @since(version = 0.2.0) 22 | resource terminal-output; 23 | } 24 | 25 | /// An interface providing an optional `terminal-input` for stdin as a 26 | /// link-time authority. 27 | @since(version = 0.2.0) 28 | interface terminal-stdin { 29 | @since(version = 0.2.0) 30 | use terminal-input.{terminal-input}; 31 | 32 | /// If stdin is connected to a terminal, return a `terminal-input` handle 33 | /// allowing further interaction with it. 34 | @since(version = 0.2.0) 35 | get-terminal-stdin: func() -> option; 36 | } 37 | 38 | /// An interface providing an optional `terminal-output` for stdout as a 39 | /// link-time authority. 40 | @since(version = 0.2.0) 41 | interface terminal-stdout { 42 | @since(version = 0.2.0) 43 | use terminal-output.{terminal-output}; 44 | 45 | /// If stdout is connected to a terminal, return a `terminal-output` handle 46 | /// allowing further interaction with it. 47 | @since(version = 0.2.0) 48 | get-terminal-stdout: func() -> option; 49 | } 50 | 51 | /// An interface providing an optional `terminal-output` for stderr as a 52 | /// link-time authority. 53 | @since(version = 0.2.0) 54 | interface terminal-stderr { 55 | @since(version = 0.2.0) 56 | use terminal-output.{terminal-output}; 57 | 58 | /// If stderr is connected to a terminal, return a `terminal-output` handle 59 | /// allowing further interaction with it. 60 | @since(version = 0.2.0) 61 | get-terminal-stderr: func() -> option; 62 | } 63 | -------------------------------------------------------------------------------- /wit/deps/clocks/monotonic-clock.wit: -------------------------------------------------------------------------------- 1 | package wasi:clocks@0.2.4; 2 | /// WASI Monotonic Clock is a clock API intended to let users measure elapsed 3 | /// time. 4 | /// 5 | /// It is intended to be portable at least between Unix-family platforms and 6 | /// Windows. 7 | /// 8 | /// A monotonic clock is a clock which has an unspecified initial value, and 9 | /// successive reads of the clock will produce non-decreasing values. 10 | @since(version = 0.2.0) 11 | interface monotonic-clock { 12 | @since(version = 0.2.0) 13 | use wasi:io/poll@0.2.4.{pollable}; 14 | 15 | /// An instant in time, in nanoseconds. An instant is relative to an 16 | /// unspecified initial value, and can only be compared to instances from 17 | /// the same monotonic-clock. 18 | @since(version = 0.2.0) 19 | type instant = u64; 20 | 21 | /// A duration of time, in nanoseconds. 22 | @since(version = 0.2.0) 23 | type duration = u64; 24 | 25 | /// Read the current value of the clock. 26 | /// 27 | /// The clock is monotonic, therefore calling this function repeatedly will 28 | /// produce a sequence of non-decreasing values. 29 | @since(version = 0.2.0) 30 | now: func() -> instant; 31 | 32 | /// Query the resolution of the clock. Returns the duration of time 33 | /// corresponding to a clock tick. 34 | @since(version = 0.2.0) 35 | resolution: func() -> duration; 36 | 37 | /// Create a `pollable` which will resolve once the specified instant 38 | /// has occurred. 39 | @since(version = 0.2.0) 40 | subscribe-instant: func( 41 | when: instant, 42 | ) -> pollable; 43 | 44 | /// Create a `pollable` that will resolve after the specified duration has 45 | /// elapsed from the time this function is invoked. 46 | @since(version = 0.2.0) 47 | subscribe-duration: func( 48 | when: duration, 49 | ) -> pollable; 50 | } 51 | -------------------------------------------------------------------------------- /wit/deps/clocks/timezone.wit: -------------------------------------------------------------------------------- 1 | package wasi:clocks@0.2.4; 2 | 3 | @unstable(feature = clocks-timezone) 4 | interface timezone { 5 | @unstable(feature = clocks-timezone) 6 | use wall-clock.{datetime}; 7 | 8 | /// Return information needed to display the given `datetime`. This includes 9 | /// the UTC offset, the time zone name, and a flag indicating whether 10 | /// daylight saving time is active. 11 | /// 12 | /// If the timezone cannot be determined for the given `datetime`, return a 13 | /// `timezone-display` for `UTC` with a `utc-offset` of 0 and no daylight 14 | /// saving time. 15 | @unstable(feature = clocks-timezone) 16 | display: func(when: datetime) -> timezone-display; 17 | 18 | /// The same as `display`, but only return the UTC offset. 19 | @unstable(feature = clocks-timezone) 20 | utc-offset: func(when: datetime) -> s32; 21 | 22 | /// Information useful for displaying the timezone of a specific `datetime`. 23 | /// 24 | /// This information may vary within a single `timezone` to reflect daylight 25 | /// saving time adjustments. 26 | @unstable(feature = clocks-timezone) 27 | record timezone-display { 28 | /// The number of seconds difference between UTC time and the local 29 | /// time of the timezone. 30 | /// 31 | /// The returned value will always be less than 86400 which is the 32 | /// number of seconds in a day (24*60*60). 33 | /// 34 | /// In implementations that do not expose an actual time zone, this 35 | /// should return 0. 36 | utc-offset: s32, 37 | 38 | /// The abbreviated name of the timezone to display to a user. The name 39 | /// `UTC` indicates Coordinated Universal Time. Otherwise, this should 40 | /// reference local standards for the name of the time zone. 41 | /// 42 | /// In implementations that do not expose an actual time zone, this 43 | /// should be the string `UTC`. 44 | /// 45 | /// In time zones that do not have an applicable name, a formatted 46 | /// representation of the UTC offset may be returned, such as `-04:00`. 47 | name: string, 48 | 49 | /// Whether daylight saving time is active. 50 | /// 51 | /// In implementations that do not expose an actual time zone, this 52 | /// should return false. 53 | in-daylight-saving-time: bool, 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /wit/deps/clocks/wall-clock.wit: -------------------------------------------------------------------------------- 1 | package wasi:clocks@0.2.4; 2 | /// WASI Wall Clock is a clock API intended to let users query the current 3 | /// time. The name "wall" makes an analogy to a "clock on the wall", which 4 | /// is not necessarily monotonic as it may be reset. 5 | /// 6 | /// It is intended to be portable at least between Unix-family platforms and 7 | /// Windows. 8 | /// 9 | /// A wall clock is a clock which measures the date and time according to 10 | /// some external reference. 11 | /// 12 | /// External references may be reset, so this clock is not necessarily 13 | /// monotonic, making it unsuitable for measuring elapsed time. 14 | /// 15 | /// It is intended for reporting the current date and time for humans. 16 | @since(version = 0.2.0) 17 | interface wall-clock { 18 | /// A time and date in seconds plus nanoseconds. 19 | @since(version = 0.2.0) 20 | record datetime { 21 | seconds: u64, 22 | nanoseconds: u32, 23 | } 24 | 25 | /// Read the current value of the clock. 26 | /// 27 | /// This clock is not monotonic, therefore calling this function repeatedly 28 | /// will not necessarily produce a sequence of non-decreasing values. 29 | /// 30 | /// The returned timestamps represent the number of seconds since 31 | /// 1970-01-01T00:00:00Z, also known as [POSIX's Seconds Since the Epoch], 32 | /// also known as [Unix Time]. 33 | /// 34 | /// The nanoseconds field of the output is always less than 1000000000. 35 | /// 36 | /// [POSIX's Seconds Since the Epoch]: https://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xbd_chap04.html#tag_21_04_16 37 | /// [Unix Time]: https://en.wikipedia.org/wiki/Unix_time 38 | @since(version = 0.2.0) 39 | now: func() -> datetime; 40 | 41 | /// Query the resolution of the clock. 42 | /// 43 | /// The nanoseconds field of the output is always less than 1000000000. 44 | @since(version = 0.2.0) 45 | resolution: func() -> datetime; 46 | } 47 | -------------------------------------------------------------------------------- /wit/deps/clocks/world.wit: -------------------------------------------------------------------------------- 1 | package wasi:clocks@0.2.4; 2 | 3 | @since(version = 0.2.0) 4 | world imports { 5 | @since(version = 0.2.0) 6 | import monotonic-clock; 7 | @since(version = 0.2.0) 8 | import wall-clock; 9 | @unstable(feature = clocks-timezone) 10 | import timezone; 11 | } 12 | -------------------------------------------------------------------------------- /wit/deps/filesystem/preopens.wit: -------------------------------------------------------------------------------- 1 | package wasi:filesystem@0.2.4; 2 | 3 | @since(version = 0.2.0) 4 | interface preopens { 5 | @since(version = 0.2.0) 6 | use types.{descriptor}; 7 | 8 | /// Return the set of preopened directories, and their paths. 9 | @since(version = 0.2.0) 10 | get-directories: func() -> list>; 11 | } 12 | -------------------------------------------------------------------------------- /wit/deps/filesystem/world.wit: -------------------------------------------------------------------------------- 1 | package wasi:filesystem@0.2.4; 2 | 3 | @since(version = 0.2.0) 4 | world imports { 5 | @since(version = 0.2.0) 6 | import types; 7 | @since(version = 0.2.0) 8 | import preopens; 9 | } 10 | -------------------------------------------------------------------------------- /wit/deps/http/handler.wit: -------------------------------------------------------------------------------- 1 | /// This interface defines a handler of incoming HTTP Requests. It should 2 | /// be exported by components which can respond to HTTP Requests. 3 | @since(version = 0.2.0) 4 | interface incoming-handler { 5 | @since(version = 0.2.0) 6 | use types.{incoming-request, response-outparam}; 7 | 8 | /// This function is invoked with an incoming HTTP Request, and a resource 9 | /// `response-outparam` which provides the capability to reply with an HTTP 10 | /// Response. The response is sent by calling the `response-outparam.set` 11 | /// method, which allows execution to continue after the response has been 12 | /// sent. This enables both streaming to the response body, and performing other 13 | /// work. 14 | /// 15 | /// The implementor of this function must write a response to the 16 | /// `response-outparam` before returning, or else the caller will respond 17 | /// with an error on its behalf. 18 | @since(version = 0.2.0) 19 | handle: func( 20 | request: incoming-request, 21 | response-out: response-outparam 22 | ); 23 | } 24 | 25 | /// This interface defines a handler of outgoing HTTP Requests. It should be 26 | /// imported by components which wish to make HTTP Requests. 27 | @since(version = 0.2.0) 28 | interface outgoing-handler { 29 | @since(version = 0.2.0) 30 | use types.{ 31 | outgoing-request, request-options, future-incoming-response, error-code 32 | }; 33 | 34 | /// This function is invoked with an outgoing HTTP Request, and it returns 35 | /// a resource `future-incoming-response` which represents an HTTP Response 36 | /// which may arrive in the future. 37 | /// 38 | /// The `options` argument accepts optional parameters for the HTTP 39 | /// protocol's transport layer. 40 | /// 41 | /// This function may return an error if the `outgoing-request` is invalid 42 | /// or not allowed to be made. Otherwise, protocol errors are reported 43 | /// through the `future-incoming-response`. 44 | @since(version = 0.2.0) 45 | handle: func( 46 | request: outgoing-request, 47 | options: option 48 | ) -> result; 49 | } 50 | -------------------------------------------------------------------------------- /wit/deps/http/proxy.wit: -------------------------------------------------------------------------------- 1 | package wasi:http@0.2.4; 2 | 3 | /// The `wasi:http/imports` world imports all the APIs for HTTP proxies. 4 | /// It is intended to be `include`d in other worlds. 5 | @since(version = 0.2.0) 6 | world imports { 7 | /// HTTP proxies have access to time and randomness. 8 | @since(version = 0.2.0) 9 | import wasi:clocks/monotonic-clock@0.2.4; 10 | @since(version = 0.2.0) 11 | import wasi:clocks/wall-clock@0.2.4; 12 | @since(version = 0.2.0) 13 | import wasi:random/random@0.2.4; 14 | 15 | /// Proxies have standard output and error streams which are expected to 16 | /// terminate in a developer-facing console provided by the host. 17 | @since(version = 0.2.0) 18 | import wasi:cli/stdout@0.2.4; 19 | @since(version = 0.2.0) 20 | import wasi:cli/stderr@0.2.4; 21 | 22 | /// TODO: this is a temporary workaround until component tooling is able to 23 | /// gracefully handle the absence of stdin. Hosts must return an eof stream 24 | /// for this import, which is what wasi-libc + tooling will do automatically 25 | /// when this import is properly removed. 26 | @since(version = 0.2.0) 27 | import wasi:cli/stdin@0.2.4; 28 | 29 | /// This is the default handler to use when user code simply wants to make an 30 | /// HTTP request (e.g., via `fetch()`). 31 | @since(version = 0.2.0) 32 | import outgoing-handler; 33 | } 34 | 35 | /// The `wasi:http/proxy` world captures a widely-implementable intersection of 36 | /// hosts that includes HTTP forward and reverse proxies. Components targeting 37 | /// this world may concurrently stream in and out any number of incoming and 38 | /// outgoing HTTP requests. 39 | @since(version = 0.2.0) 40 | world proxy { 41 | @since(version = 0.2.0) 42 | include imports; 43 | 44 | /// The host delivers incoming HTTP requests to a component by calling the 45 | /// `handle` function of this exported interface. A host may arbitrarily reuse 46 | /// or not reuse component instance when delivering incoming HTTP requests and 47 | /// thus a component must be able to handle 0..N calls to `handle`. 48 | @since(version = 0.2.0) 49 | export incoming-handler; 50 | } 51 | -------------------------------------------------------------------------------- /wit/deps/http/types.wit: -------------------------------------------------------------------------------- 1 | /// This interface defines all of the types and methods for implementing 2 | /// HTTP Requests and Responses, both incoming and outgoing, as well as 3 | /// their headers, trailers, and bodies. 4 | @since(version = 0.2.0) 5 | interface types { 6 | @since(version = 0.2.0) 7 | use wasi:clocks/monotonic-clock@0.2.4.{duration}; 8 | @since(version = 0.2.0) 9 | use wasi:io/streams@0.2.4.{input-stream, output-stream}; 10 | @since(version = 0.2.0) 11 | use wasi:io/error@0.2.4.{error as io-error}; 12 | @since(version = 0.2.0) 13 | use wasi:io/poll@0.2.4.{pollable}; 14 | 15 | /// This type corresponds to HTTP standard Methods. 16 | @since(version = 0.2.0) 17 | variant method { 18 | get, 19 | head, 20 | post, 21 | put, 22 | delete, 23 | connect, 24 | options, 25 | trace, 26 | patch, 27 | other(string) 28 | } 29 | 30 | /// This type corresponds to HTTP standard Related Schemes. 31 | @since(version = 0.2.0) 32 | variant scheme { 33 | HTTP, 34 | HTTPS, 35 | other(string) 36 | } 37 | 38 | /// These cases are inspired by the IANA HTTP Proxy Error Types: 39 | /// 40 | @since(version = 0.2.0) 41 | variant error-code { 42 | DNS-timeout, 43 | DNS-error(DNS-error-payload), 44 | destination-not-found, 45 | destination-unavailable, 46 | destination-IP-prohibited, 47 | destination-IP-unroutable, 48 | connection-refused, 49 | connection-terminated, 50 | connection-timeout, 51 | connection-read-timeout, 52 | connection-write-timeout, 53 | connection-limit-reached, 54 | TLS-protocol-error, 55 | TLS-certificate-error, 56 | TLS-alert-received(TLS-alert-received-payload), 57 | HTTP-request-denied, 58 | HTTP-request-length-required, 59 | HTTP-request-body-size(option), 60 | HTTP-request-method-invalid, 61 | HTTP-request-URI-invalid, 62 | HTTP-request-URI-too-long, 63 | HTTP-request-header-section-size(option), 64 | HTTP-request-header-size(option), 65 | HTTP-request-trailer-section-size(option), 66 | HTTP-request-trailer-size(field-size-payload), 67 | HTTP-response-incomplete, 68 | HTTP-response-header-section-size(option), 69 | HTTP-response-header-size(field-size-payload), 70 | HTTP-response-body-size(option), 71 | HTTP-response-trailer-section-size(option), 72 | HTTP-response-trailer-size(field-size-payload), 73 | HTTP-response-transfer-coding(option), 74 | HTTP-response-content-coding(option), 75 | HTTP-response-timeout, 76 | HTTP-upgrade-failed, 77 | HTTP-protocol-error, 78 | loop-detected, 79 | configuration-error, 80 | /// This is a catch-all error for anything that doesn't fit cleanly into a 81 | /// more specific case. It also includes an optional string for an 82 | /// unstructured description of the error. Users should not depend on the 83 | /// string for diagnosing errors, as it's not required to be consistent 84 | /// between implementations. 85 | internal-error(option) 86 | } 87 | 88 | /// Defines the case payload type for `DNS-error` above: 89 | @since(version = 0.2.0) 90 | record DNS-error-payload { 91 | rcode: option, 92 | info-code: option 93 | } 94 | 95 | /// Defines the case payload type for `TLS-alert-received` above: 96 | @since(version = 0.2.0) 97 | record TLS-alert-received-payload { 98 | alert-id: option, 99 | alert-message: option 100 | } 101 | 102 | /// Defines the case payload type for `HTTP-response-{header,trailer}-size` above: 103 | @since(version = 0.2.0) 104 | record field-size-payload { 105 | field-name: option, 106 | field-size: option 107 | } 108 | 109 | /// Attempts to extract a http-related `error` from the wasi:io `error` 110 | /// provided. 111 | /// 112 | /// Stream operations which return 113 | /// `wasi:io/stream/stream-error::last-operation-failed` have a payload of 114 | /// type `wasi:io/error/error` with more information about the operation 115 | /// that failed. This payload can be passed through to this function to see 116 | /// if there's http-related information about the error to return. 117 | /// 118 | /// Note that this function is fallible because not all io-errors are 119 | /// http-related errors. 120 | @since(version = 0.2.0) 121 | http-error-code: func(err: borrow) -> option; 122 | 123 | /// This type enumerates the different kinds of errors that may occur when 124 | /// setting or appending to a `fields` resource. 125 | @since(version = 0.2.0) 126 | variant header-error { 127 | /// This error indicates that a `field-name` or `field-value` was 128 | /// syntactically invalid when used with an operation that sets headers in a 129 | /// `fields`. 130 | invalid-syntax, 131 | 132 | /// This error indicates that a forbidden `field-name` was used when trying 133 | /// to set a header in a `fields`. 134 | forbidden, 135 | 136 | /// This error indicates that the operation on the `fields` was not 137 | /// permitted because the fields are immutable. 138 | immutable, 139 | } 140 | 141 | /// Field names are always strings. 142 | /// 143 | /// Field names should always be treated as case insensitive by the `fields` 144 | /// resource for the purposes of equality checking. 145 | @since(version = 0.2.1) 146 | type field-name = field-key; 147 | 148 | /// Field keys are always strings. 149 | /// 150 | /// Field keys should always be treated as case insensitive by the `fields` 151 | /// resource for the purposes of equality checking. 152 | /// 153 | /// # Deprecation 154 | /// 155 | /// This type has been deprecated in favor of the `field-name` type. 156 | @since(version = 0.2.0) 157 | @deprecated(version = 0.2.2) 158 | type field-key = string; 159 | 160 | /// Field values should always be ASCII strings. However, in 161 | /// reality, HTTP implementations often have to interpret malformed values, 162 | /// so they are provided as a list of bytes. 163 | @since(version = 0.2.0) 164 | type field-value = list; 165 | 166 | /// This following block defines the `fields` resource which corresponds to 167 | /// HTTP standard Fields. Fields are a common representation used for both 168 | /// Headers and Trailers. 169 | /// 170 | /// A `fields` may be mutable or immutable. A `fields` created using the 171 | /// constructor, `from-list`, or `clone` will be mutable, but a `fields` 172 | /// resource given by other means (including, but not limited to, 173 | /// `incoming-request.headers`, `outgoing-request.headers`) might be 174 | /// immutable. In an immutable fields, the `set`, `append`, and `delete` 175 | /// operations will fail with `header-error.immutable`. 176 | @since(version = 0.2.0) 177 | resource fields { 178 | 179 | /// Construct an empty HTTP Fields. 180 | /// 181 | /// The resulting `fields` is mutable. 182 | @since(version = 0.2.0) 183 | constructor(); 184 | 185 | /// Construct an HTTP Fields. 186 | /// 187 | /// The resulting `fields` is mutable. 188 | /// 189 | /// The list represents each name-value pair in the Fields. Names 190 | /// which have multiple values are represented by multiple entries in this 191 | /// list with the same name. 192 | /// 193 | /// The tuple is a pair of the field name, represented as a string, and 194 | /// Value, represented as a list of bytes. 195 | /// 196 | /// An error result will be returned if any `field-name` or `field-value` is 197 | /// syntactically invalid, or if a field is forbidden. 198 | @since(version = 0.2.0) 199 | from-list: static func( 200 | entries: list> 201 | ) -> result; 202 | 203 | /// Get all of the values corresponding to a name. If the name is not present 204 | /// in this `fields` or is syntactically invalid, an empty list is returned. 205 | /// However, if the name is present but empty, this is represented by a list 206 | /// with one or more empty field-values present. 207 | @since(version = 0.2.0) 208 | get: func(name: field-name) -> list; 209 | 210 | /// Returns `true` when the name is present in this `fields`. If the name is 211 | /// syntactically invalid, `false` is returned. 212 | @since(version = 0.2.0) 213 | has: func(name: field-name) -> bool; 214 | 215 | /// Set all of the values for a name. Clears any existing values for that 216 | /// name, if they have been set. 217 | /// 218 | /// Fails with `header-error.immutable` if the `fields` are immutable. 219 | /// 220 | /// Fails with `header-error.invalid-syntax` if the `field-name` or any of 221 | /// the `field-value`s are syntactically invalid. 222 | @since(version = 0.2.0) 223 | set: func(name: field-name, value: list) -> result<_, header-error>; 224 | 225 | /// Delete all values for a name. Does nothing if no values for the name 226 | /// exist. 227 | /// 228 | /// Fails with `header-error.immutable` if the `fields` are immutable. 229 | /// 230 | /// Fails with `header-error.invalid-syntax` if the `field-name` is 231 | /// syntactically invalid. 232 | @since(version = 0.2.0) 233 | delete: func(name: field-name) -> result<_, header-error>; 234 | 235 | /// Append a value for a name. Does not change or delete any existing 236 | /// values for that name. 237 | /// 238 | /// Fails with `header-error.immutable` if the `fields` are immutable. 239 | /// 240 | /// Fails with `header-error.invalid-syntax` if the `field-name` or 241 | /// `field-value` are syntactically invalid. 242 | @since(version = 0.2.0) 243 | append: func(name: field-name, value: field-value) -> result<_, header-error>; 244 | 245 | /// Retrieve the full set of names and values in the Fields. Like the 246 | /// constructor, the list represents each name-value pair. 247 | /// 248 | /// The outer list represents each name-value pair in the Fields. Names 249 | /// which have multiple values are represented by multiple entries in this 250 | /// list with the same name. 251 | /// 252 | /// The names and values are always returned in the original casing and in 253 | /// the order in which they will be serialized for transport. 254 | @since(version = 0.2.0) 255 | entries: func() -> list>; 256 | 257 | /// Make a deep copy of the Fields. Equivalent in behavior to calling the 258 | /// `fields` constructor on the return value of `entries`. The resulting 259 | /// `fields` is mutable. 260 | @since(version = 0.2.0) 261 | clone: func() -> fields; 262 | } 263 | 264 | /// Headers is an alias for Fields. 265 | @since(version = 0.2.0) 266 | type headers = fields; 267 | 268 | /// Trailers is an alias for Fields. 269 | @since(version = 0.2.0) 270 | type trailers = fields; 271 | 272 | /// Represents an incoming HTTP Request. 273 | @since(version = 0.2.0) 274 | resource incoming-request { 275 | 276 | /// Returns the method of the incoming request. 277 | @since(version = 0.2.0) 278 | method: func() -> method; 279 | 280 | /// Returns the path with query parameters from the request, as a string. 281 | @since(version = 0.2.0) 282 | path-with-query: func() -> option; 283 | 284 | /// Returns the protocol scheme from the request. 285 | @since(version = 0.2.0) 286 | scheme: func() -> option; 287 | 288 | /// Returns the authority of the Request's target URI, if present. 289 | @since(version = 0.2.0) 290 | authority: func() -> option; 291 | 292 | /// Get the `headers` associated with the request. 293 | /// 294 | /// The returned `headers` resource is immutable: `set`, `append`, and 295 | /// `delete` operations will fail with `header-error.immutable`. 296 | /// 297 | /// The `headers` returned are a child resource: it must be dropped before 298 | /// the parent `incoming-request` is dropped. Dropping this 299 | /// `incoming-request` before all children are dropped will trap. 300 | @since(version = 0.2.0) 301 | headers: func() -> headers; 302 | 303 | /// Gives the `incoming-body` associated with this request. Will only 304 | /// return success at most once, and subsequent calls will return error. 305 | @since(version = 0.2.0) 306 | consume: func() -> result; 307 | } 308 | 309 | /// Represents an outgoing HTTP Request. 310 | @since(version = 0.2.0) 311 | resource outgoing-request { 312 | 313 | /// Construct a new `outgoing-request` with a default `method` of `GET`, and 314 | /// `none` values for `path-with-query`, `scheme`, and `authority`. 315 | /// 316 | /// * `headers` is the HTTP Headers for the Request. 317 | /// 318 | /// It is possible to construct, or manipulate with the accessor functions 319 | /// below, an `outgoing-request` with an invalid combination of `scheme` 320 | /// and `authority`, or `headers` which are not permitted to be sent. 321 | /// It is the obligation of the `outgoing-handler.handle` implementation 322 | /// to reject invalid constructions of `outgoing-request`. 323 | @since(version = 0.2.0) 324 | constructor( 325 | headers: headers 326 | ); 327 | 328 | /// Returns the resource corresponding to the outgoing Body for this 329 | /// Request. 330 | /// 331 | /// Returns success on the first call: the `outgoing-body` resource for 332 | /// this `outgoing-request` can be retrieved at most once. Subsequent 333 | /// calls will return error. 334 | @since(version = 0.2.0) 335 | body: func() -> result; 336 | 337 | /// Get the Method for the Request. 338 | @since(version = 0.2.0) 339 | method: func() -> method; 340 | /// Set the Method for the Request. Fails if the string present in a 341 | /// `method.other` argument is not a syntactically valid method. 342 | @since(version = 0.2.0) 343 | set-method: func(method: method) -> result; 344 | 345 | /// Get the combination of the HTTP Path and Query for the Request. 346 | /// When `none`, this represents an empty Path and empty Query. 347 | @since(version = 0.2.0) 348 | path-with-query: func() -> option; 349 | /// Set the combination of the HTTP Path and Query for the Request. 350 | /// When `none`, this represents an empty Path and empty Query. Fails is the 351 | /// string given is not a syntactically valid path and query uri component. 352 | @since(version = 0.2.0) 353 | set-path-with-query: func(path-with-query: option) -> result; 354 | 355 | /// Get the HTTP Related Scheme for the Request. When `none`, the 356 | /// implementation may choose an appropriate default scheme. 357 | @since(version = 0.2.0) 358 | scheme: func() -> option; 359 | /// Set the HTTP Related Scheme for the Request. When `none`, the 360 | /// implementation may choose an appropriate default scheme. Fails if the 361 | /// string given is not a syntactically valid uri scheme. 362 | @since(version = 0.2.0) 363 | set-scheme: func(scheme: option) -> result; 364 | 365 | /// Get the authority of the Request's target URI. A value of `none` may be used 366 | /// with Related Schemes which do not require an authority. The HTTP and 367 | /// HTTPS schemes always require an authority. 368 | @since(version = 0.2.0) 369 | authority: func() -> option; 370 | /// Set the authority of the Request's target URI. A value of `none` may be used 371 | /// with Related Schemes which do not require an authority. The HTTP and 372 | /// HTTPS schemes always require an authority. Fails if the string given is 373 | /// not a syntactically valid URI authority. 374 | @since(version = 0.2.0) 375 | set-authority: func(authority: option) -> result; 376 | 377 | /// Get the headers associated with the Request. 378 | /// 379 | /// The returned `headers` resource is immutable: `set`, `append`, and 380 | /// `delete` operations will fail with `header-error.immutable`. 381 | /// 382 | /// This headers resource is a child: it must be dropped before the parent 383 | /// `outgoing-request` is dropped, or its ownership is transferred to 384 | /// another component by e.g. `outgoing-handler.handle`. 385 | @since(version = 0.2.0) 386 | headers: func() -> headers; 387 | } 388 | 389 | /// Parameters for making an HTTP Request. Each of these parameters is 390 | /// currently an optional timeout applicable to the transport layer of the 391 | /// HTTP protocol. 392 | /// 393 | /// These timeouts are separate from any the user may use to bound a 394 | /// blocking call to `wasi:io/poll.poll`. 395 | @since(version = 0.2.0) 396 | resource request-options { 397 | /// Construct a default `request-options` value. 398 | @since(version = 0.2.0) 399 | constructor(); 400 | 401 | /// The timeout for the initial connect to the HTTP Server. 402 | @since(version = 0.2.0) 403 | connect-timeout: func() -> option; 404 | 405 | /// Set the timeout for the initial connect to the HTTP Server. An error 406 | /// return value indicates that this timeout is not supported. 407 | @since(version = 0.2.0) 408 | set-connect-timeout: func(duration: option) -> result; 409 | 410 | /// The timeout for receiving the first byte of the Response body. 411 | @since(version = 0.2.0) 412 | first-byte-timeout: func() -> option; 413 | 414 | /// Set the timeout for receiving the first byte of the Response body. An 415 | /// error return value indicates that this timeout is not supported. 416 | @since(version = 0.2.0) 417 | set-first-byte-timeout: func(duration: option) -> result; 418 | 419 | /// The timeout for receiving subsequent chunks of bytes in the Response 420 | /// body stream. 421 | @since(version = 0.2.0) 422 | between-bytes-timeout: func() -> option; 423 | 424 | /// Set the timeout for receiving subsequent chunks of bytes in the Response 425 | /// body stream. An error return value indicates that this timeout is not 426 | /// supported. 427 | @since(version = 0.2.0) 428 | set-between-bytes-timeout: func(duration: option) -> result; 429 | } 430 | 431 | /// Represents the ability to send an HTTP Response. 432 | /// 433 | /// This resource is used by the `wasi:http/incoming-handler` interface to 434 | /// allow a Response to be sent corresponding to the Request provided as the 435 | /// other argument to `incoming-handler.handle`. 436 | @since(version = 0.2.0) 437 | resource response-outparam { 438 | /// Send an HTTP 1xx response. 439 | /// 440 | /// Unlike `response-outparam.set`, this does not consume the 441 | /// `response-outparam`, allowing the guest to send an arbitrary number of 442 | /// informational responses before sending the final response using 443 | /// `response-outparam.set`. 444 | /// 445 | /// This will return an `HTTP-protocol-error` if `status` is not in the 446 | /// range [100-199], or an `internal-error` if the implementation does not 447 | /// support informational responses. 448 | @unstable(feature = informational-outbound-responses) 449 | send-informational: func( 450 | status: u16, 451 | headers: headers 452 | ) -> result<_, error-code>; 453 | 454 | /// Set the value of the `response-outparam` to either send a response, 455 | /// or indicate an error. 456 | /// 457 | /// This method consumes the `response-outparam` to ensure that it is 458 | /// called at most once. If it is never called, the implementation 459 | /// will respond with an error. 460 | /// 461 | /// The user may provide an `error` to `response` to allow the 462 | /// implementation determine how to respond with an HTTP error response. 463 | @since(version = 0.2.0) 464 | set: static func( 465 | param: response-outparam, 466 | response: result, 467 | ); 468 | } 469 | 470 | /// This type corresponds to the HTTP standard Status Code. 471 | @since(version = 0.2.0) 472 | type status-code = u16; 473 | 474 | /// Represents an incoming HTTP Response. 475 | @since(version = 0.2.0) 476 | resource incoming-response { 477 | 478 | /// Returns the status code from the incoming response. 479 | @since(version = 0.2.0) 480 | status: func() -> status-code; 481 | 482 | /// Returns the headers from the incoming response. 483 | /// 484 | /// The returned `headers` resource is immutable: `set`, `append`, and 485 | /// `delete` operations will fail with `header-error.immutable`. 486 | /// 487 | /// This headers resource is a child: it must be dropped before the parent 488 | /// `incoming-response` is dropped. 489 | @since(version = 0.2.0) 490 | headers: func() -> headers; 491 | 492 | /// Returns the incoming body. May be called at most once. Returns error 493 | /// if called additional times. 494 | @since(version = 0.2.0) 495 | consume: func() -> result; 496 | } 497 | 498 | /// Represents an incoming HTTP Request or Response's Body. 499 | /// 500 | /// A body has both its contents - a stream of bytes - and a (possibly 501 | /// empty) set of trailers, indicating that the full contents of the 502 | /// body have been received. This resource represents the contents as 503 | /// an `input-stream` and the delivery of trailers as a `future-trailers`, 504 | /// and ensures that the user of this interface may only be consuming either 505 | /// the body contents or waiting on trailers at any given time. 506 | @since(version = 0.2.0) 507 | resource incoming-body { 508 | 509 | /// Returns the contents of the body, as a stream of bytes. 510 | /// 511 | /// Returns success on first call: the stream representing the contents 512 | /// can be retrieved at most once. Subsequent calls will return error. 513 | /// 514 | /// The returned `input-stream` resource is a child: it must be dropped 515 | /// before the parent `incoming-body` is dropped, or consumed by 516 | /// `incoming-body.finish`. 517 | /// 518 | /// This invariant ensures that the implementation can determine whether 519 | /// the user is consuming the contents of the body, waiting on the 520 | /// `future-trailers` to be ready, or neither. This allows for network 521 | /// backpressure is to be applied when the user is consuming the body, 522 | /// and for that backpressure to not inhibit delivery of the trailers if 523 | /// the user does not read the entire body. 524 | @since(version = 0.2.0) 525 | %stream: func() -> result; 526 | 527 | /// Takes ownership of `incoming-body`, and returns a `future-trailers`. 528 | /// This function will trap if the `input-stream` child is still alive. 529 | @since(version = 0.2.0) 530 | finish: static func(this: incoming-body) -> future-trailers; 531 | } 532 | 533 | /// Represents a future which may eventually return trailers, or an error. 534 | /// 535 | /// In the case that the incoming HTTP Request or Response did not have any 536 | /// trailers, this future will resolve to the empty set of trailers once the 537 | /// complete Request or Response body has been received. 538 | @since(version = 0.2.0) 539 | resource future-trailers { 540 | 541 | /// Returns a pollable which becomes ready when either the trailers have 542 | /// been received, or an error has occurred. When this pollable is ready, 543 | /// the `get` method will return `some`. 544 | @since(version = 0.2.0) 545 | subscribe: func() -> pollable; 546 | 547 | /// Returns the contents of the trailers, or an error which occurred, 548 | /// once the future is ready. 549 | /// 550 | /// The outer `option` represents future readiness. Users can wait on this 551 | /// `option` to become `some` using the `subscribe` method. 552 | /// 553 | /// The outer `result` is used to retrieve the trailers or error at most 554 | /// once. It will be success on the first call in which the outer option 555 | /// is `some`, and error on subsequent calls. 556 | /// 557 | /// The inner `result` represents that either the HTTP Request or Response 558 | /// body, as well as any trailers, were received successfully, or that an 559 | /// error occurred receiving them. The optional `trailers` indicates whether 560 | /// or not trailers were present in the body. 561 | /// 562 | /// When some `trailers` are returned by this method, the `trailers` 563 | /// resource is immutable, and a child. Use of the `set`, `append`, or 564 | /// `delete` methods will return an error, and the resource must be 565 | /// dropped before the parent `future-trailers` is dropped. 566 | @since(version = 0.2.0) 567 | get: func() -> option, error-code>>>; 568 | } 569 | 570 | /// Represents an outgoing HTTP Response. 571 | @since(version = 0.2.0) 572 | resource outgoing-response { 573 | 574 | /// Construct an `outgoing-response`, with a default `status-code` of `200`. 575 | /// If a different `status-code` is needed, it must be set via the 576 | /// `set-status-code` method. 577 | /// 578 | /// * `headers` is the HTTP Headers for the Response. 579 | @since(version = 0.2.0) 580 | constructor(headers: headers); 581 | 582 | /// Get the HTTP Status Code for the Response. 583 | @since(version = 0.2.0) 584 | status-code: func() -> status-code; 585 | 586 | /// Set the HTTP Status Code for the Response. Fails if the status-code 587 | /// given is not a valid http status code. 588 | @since(version = 0.2.0) 589 | set-status-code: func(status-code: status-code) -> result; 590 | 591 | /// Get the headers associated with the Request. 592 | /// 593 | /// The returned `headers` resource is immutable: `set`, `append`, and 594 | /// `delete` operations will fail with `header-error.immutable`. 595 | /// 596 | /// This headers resource is a child: it must be dropped before the parent 597 | /// `outgoing-request` is dropped, or its ownership is transferred to 598 | /// another component by e.g. `outgoing-handler.handle`. 599 | @since(version = 0.2.0) 600 | headers: func() -> headers; 601 | 602 | /// Returns the resource corresponding to the outgoing Body for this Response. 603 | /// 604 | /// Returns success on the first call: the `outgoing-body` resource for 605 | /// this `outgoing-response` can be retrieved at most once. Subsequent 606 | /// calls will return error. 607 | @since(version = 0.2.0) 608 | body: func() -> result; 609 | } 610 | 611 | /// Represents an outgoing HTTP Request or Response's Body. 612 | /// 613 | /// A body has both its contents - a stream of bytes - and a (possibly 614 | /// empty) set of trailers, inducating the full contents of the body 615 | /// have been sent. This resource represents the contents as an 616 | /// `output-stream` child resource, and the completion of the body (with 617 | /// optional trailers) with a static function that consumes the 618 | /// `outgoing-body` resource, and ensures that the user of this interface 619 | /// may not write to the body contents after the body has been finished. 620 | /// 621 | /// If the user code drops this resource, as opposed to calling the static 622 | /// method `finish`, the implementation should treat the body as incomplete, 623 | /// and that an error has occurred. The implementation should propagate this 624 | /// error to the HTTP protocol by whatever means it has available, 625 | /// including: corrupting the body on the wire, aborting the associated 626 | /// Request, or sending a late status code for the Response. 627 | @since(version = 0.2.0) 628 | resource outgoing-body { 629 | 630 | /// Returns a stream for writing the body contents. 631 | /// 632 | /// The returned `output-stream` is a child resource: it must be dropped 633 | /// before the parent `outgoing-body` resource is dropped (or finished), 634 | /// otherwise the `outgoing-body` drop or `finish` will trap. 635 | /// 636 | /// Returns success on the first call: the `output-stream` resource for 637 | /// this `outgoing-body` may be retrieved at most once. Subsequent calls 638 | /// will return error. 639 | @since(version = 0.2.0) 640 | write: func() -> result; 641 | 642 | /// Finalize an outgoing body, optionally providing trailers. This must be 643 | /// called to signal that the response is complete. If the `outgoing-body` 644 | /// is dropped without calling `outgoing-body.finalize`, the implementation 645 | /// should treat the body as corrupted. 646 | /// 647 | /// Fails if the body's `outgoing-request` or `outgoing-response` was 648 | /// constructed with a Content-Length header, and the contents written 649 | /// to the body (via `write`) does not match the value given in the 650 | /// Content-Length. 651 | @since(version = 0.2.0) 652 | finish: static func( 653 | this: outgoing-body, 654 | trailers: option 655 | ) -> result<_, error-code>; 656 | } 657 | 658 | /// Represents a future which may eventually return an incoming HTTP 659 | /// Response, or an error. 660 | /// 661 | /// This resource is returned by the `wasi:http/outgoing-handler` interface to 662 | /// provide the HTTP Response corresponding to the sent Request. 663 | @since(version = 0.2.0) 664 | resource future-incoming-response { 665 | /// Returns a pollable which becomes ready when either the Response has 666 | /// been received, or an error has occurred. When this pollable is ready, 667 | /// the `get` method will return `some`. 668 | @since(version = 0.2.0) 669 | subscribe: func() -> pollable; 670 | 671 | /// Returns the incoming HTTP Response, or an error, once one is ready. 672 | /// 673 | /// The outer `option` represents future readiness. Users can wait on this 674 | /// `option` to become `some` using the `subscribe` method. 675 | /// 676 | /// The outer `result` is used to retrieve the response or error at most 677 | /// once. It will be success on the first call in which the outer option 678 | /// is `some`, and error on subsequent calls. 679 | /// 680 | /// The inner `result` represents that either the incoming HTTP Response 681 | /// status and headers have received successfully, or that an error 682 | /// occurred. Errors may also occur while consuming the response body, 683 | /// but those will be reported by the `incoming-body` and its 684 | /// `output-stream` child. 685 | @since(version = 0.2.0) 686 | get: func() -> option>>; 687 | } 688 | } 689 | -------------------------------------------------------------------------------- /wit/deps/io/error.wit: -------------------------------------------------------------------------------- 1 | package wasi:io@0.2.4; 2 | 3 | @since(version = 0.2.0) 4 | interface error { 5 | /// A resource which represents some error information. 6 | /// 7 | /// The only method provided by this resource is `to-debug-string`, 8 | /// which provides some human-readable information about the error. 9 | /// 10 | /// In the `wasi:io` package, this resource is returned through the 11 | /// `wasi:io/streams/stream-error` type. 12 | /// 13 | /// To provide more specific error information, other interfaces may 14 | /// offer functions to "downcast" this error into more specific types. For example, 15 | /// errors returned from streams derived from filesystem types can be described using 16 | /// the filesystem's own error-code type. This is done using the function 17 | /// `wasi:filesystem/types/filesystem-error-code`, which takes a `borrow` 18 | /// parameter and returns an `option`. 19 | /// 20 | /// The set of functions which can "downcast" an `error` into a more 21 | /// concrete type is open. 22 | @since(version = 0.2.0) 23 | resource error { 24 | /// Returns a string that is suitable to assist humans in debugging 25 | /// this error. 26 | /// 27 | /// WARNING: The returned string should not be consumed mechanically! 28 | /// It may change across platforms, hosts, or other implementation 29 | /// details. Parsing this string is a major platform-compatibility 30 | /// hazard. 31 | @since(version = 0.2.0) 32 | to-debug-string: func() -> string; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /wit/deps/io/poll.wit: -------------------------------------------------------------------------------- 1 | package wasi:io@0.2.4; 2 | 3 | /// A poll API intended to let users wait for I/O events on multiple handles 4 | /// at once. 5 | @since(version = 0.2.0) 6 | interface poll { 7 | /// `pollable` represents a single I/O event which may be ready, or not. 8 | @since(version = 0.2.0) 9 | resource pollable { 10 | 11 | /// Return the readiness of a pollable. This function never blocks. 12 | /// 13 | /// Returns `true` when the pollable is ready, and `false` otherwise. 14 | @since(version = 0.2.0) 15 | ready: func() -> bool; 16 | 17 | /// `block` returns immediately if the pollable is ready, and otherwise 18 | /// blocks until ready. 19 | /// 20 | /// This function is equivalent to calling `poll.poll` on a list 21 | /// containing only this pollable. 22 | @since(version = 0.2.0) 23 | block: func(); 24 | } 25 | 26 | /// Poll for completion on a set of pollables. 27 | /// 28 | /// This function takes a list of pollables, which identify I/O sources of 29 | /// interest, and waits until one or more of the events is ready for I/O. 30 | /// 31 | /// The result `list` contains one or more indices of handles in the 32 | /// argument list that is ready for I/O. 33 | /// 34 | /// This function traps if either: 35 | /// - the list is empty, or: 36 | /// - the list contains more elements than can be indexed with a `u32` value. 37 | /// 38 | /// A timeout can be implemented by adding a pollable from the 39 | /// wasi-clocks API to the list. 40 | /// 41 | /// This function does not return a `result`; polling in itself does not 42 | /// do any I/O so it doesn't fail. If any of the I/O sources identified by 43 | /// the pollables has an error, it is indicated by marking the source as 44 | /// being ready for I/O. 45 | @since(version = 0.2.0) 46 | poll: func(in: list>) -> list; 47 | } 48 | -------------------------------------------------------------------------------- /wit/deps/io/streams.wit: -------------------------------------------------------------------------------- 1 | package wasi:io@0.2.4; 2 | 3 | /// WASI I/O is an I/O abstraction API which is currently focused on providing 4 | /// stream types. 5 | /// 6 | /// In the future, the component model is expected to add built-in stream types; 7 | /// when it does, they are expected to subsume this API. 8 | @since(version = 0.2.0) 9 | interface streams { 10 | @since(version = 0.2.0) 11 | use error.{error}; 12 | @since(version = 0.2.0) 13 | use poll.{pollable}; 14 | 15 | /// An error for input-stream and output-stream operations. 16 | @since(version = 0.2.0) 17 | variant stream-error { 18 | /// The last operation (a write or flush) failed before completion. 19 | /// 20 | /// More information is available in the `error` payload. 21 | /// 22 | /// After this, the stream will be closed. All future operations return 23 | /// `stream-error::closed`. 24 | last-operation-failed(error), 25 | /// The stream is closed: no more input will be accepted by the 26 | /// stream. A closed output-stream will return this error on all 27 | /// future operations. 28 | closed 29 | } 30 | 31 | /// An input bytestream. 32 | /// 33 | /// `input-stream`s are *non-blocking* to the extent practical on underlying 34 | /// platforms. I/O operations always return promptly; if fewer bytes are 35 | /// promptly available than requested, they return the number of bytes promptly 36 | /// available, which could even be zero. To wait for data to be available, 37 | /// use the `subscribe` function to obtain a `pollable` which can be polled 38 | /// for using `wasi:io/poll`. 39 | @since(version = 0.2.0) 40 | resource input-stream { 41 | /// Perform a non-blocking read from the stream. 42 | /// 43 | /// When the source of a `read` is binary data, the bytes from the source 44 | /// are returned verbatim. When the source of a `read` is known to the 45 | /// implementation to be text, bytes containing the UTF-8 encoding of the 46 | /// text are returned. 47 | /// 48 | /// This function returns a list of bytes containing the read data, 49 | /// when successful. The returned list will contain up to `len` bytes; 50 | /// it may return fewer than requested, but not more. The list is 51 | /// empty when no bytes are available for reading at this time. The 52 | /// pollable given by `subscribe` will be ready when more bytes are 53 | /// available. 54 | /// 55 | /// This function fails with a `stream-error` when the operation 56 | /// encounters an error, giving `last-operation-failed`, or when the 57 | /// stream is closed, giving `closed`. 58 | /// 59 | /// When the caller gives a `len` of 0, it represents a request to 60 | /// read 0 bytes. If the stream is still open, this call should 61 | /// succeed and return an empty list, or otherwise fail with `closed`. 62 | /// 63 | /// The `len` parameter is a `u64`, which could represent a list of u8 which 64 | /// is not possible to allocate in wasm32, or not desirable to allocate as 65 | /// as a return value by the callee. The callee may return a list of bytes 66 | /// less than `len` in size while more bytes are available for reading. 67 | @since(version = 0.2.0) 68 | read: func( 69 | /// The maximum number of bytes to read 70 | len: u64 71 | ) -> result, stream-error>; 72 | 73 | /// Read bytes from a stream, after blocking until at least one byte can 74 | /// be read. Except for blocking, behavior is identical to `read`. 75 | @since(version = 0.2.0) 76 | blocking-read: func( 77 | /// The maximum number of bytes to read 78 | len: u64 79 | ) -> result, stream-error>; 80 | 81 | /// Skip bytes from a stream. Returns number of bytes skipped. 82 | /// 83 | /// Behaves identical to `read`, except instead of returning a list 84 | /// of bytes, returns the number of bytes consumed from the stream. 85 | @since(version = 0.2.0) 86 | skip: func( 87 | /// The maximum number of bytes to skip. 88 | len: u64, 89 | ) -> result; 90 | 91 | /// Skip bytes from a stream, after blocking until at least one byte 92 | /// can be skipped. Except for blocking behavior, identical to `skip`. 93 | @since(version = 0.2.0) 94 | blocking-skip: func( 95 | /// The maximum number of bytes to skip. 96 | len: u64, 97 | ) -> result; 98 | 99 | /// Create a `pollable` which will resolve once either the specified stream 100 | /// has bytes available to read or the other end of the stream has been 101 | /// closed. 102 | /// The created `pollable` is a child resource of the `input-stream`. 103 | /// Implementations may trap if the `input-stream` is dropped before 104 | /// all derived `pollable`s created with this function are dropped. 105 | @since(version = 0.2.0) 106 | subscribe: func() -> pollable; 107 | } 108 | 109 | 110 | /// An output bytestream. 111 | /// 112 | /// `output-stream`s are *non-blocking* to the extent practical on 113 | /// underlying platforms. Except where specified otherwise, I/O operations also 114 | /// always return promptly, after the number of bytes that can be written 115 | /// promptly, which could even be zero. To wait for the stream to be ready to 116 | /// accept data, the `subscribe` function to obtain a `pollable` which can be 117 | /// polled for using `wasi:io/poll`. 118 | /// 119 | /// Dropping an `output-stream` while there's still an active write in 120 | /// progress may result in the data being lost. Before dropping the stream, 121 | /// be sure to fully flush your writes. 122 | @since(version = 0.2.0) 123 | resource output-stream { 124 | /// Check readiness for writing. This function never blocks. 125 | /// 126 | /// Returns the number of bytes permitted for the next call to `write`, 127 | /// or an error. Calling `write` with more bytes than this function has 128 | /// permitted will trap. 129 | /// 130 | /// When this function returns 0 bytes, the `subscribe` pollable will 131 | /// become ready when this function will report at least 1 byte, or an 132 | /// error. 133 | @since(version = 0.2.0) 134 | check-write: func() -> result; 135 | 136 | /// Perform a write. This function never blocks. 137 | /// 138 | /// When the destination of a `write` is binary data, the bytes from 139 | /// `contents` are written verbatim. When the destination of a `write` is 140 | /// known to the implementation to be text, the bytes of `contents` are 141 | /// transcoded from UTF-8 into the encoding of the destination and then 142 | /// written. 143 | /// 144 | /// Precondition: check-write gave permit of Ok(n) and contents has a 145 | /// length of less than or equal to n. Otherwise, this function will trap. 146 | /// 147 | /// returns Err(closed) without writing if the stream has closed since 148 | /// the last call to check-write provided a permit. 149 | @since(version = 0.2.0) 150 | write: func( 151 | contents: list 152 | ) -> result<_, stream-error>; 153 | 154 | /// Perform a write of up to 4096 bytes, and then flush the stream. Block 155 | /// until all of these operations are complete, or an error occurs. 156 | /// 157 | /// This is a convenience wrapper around the use of `check-write`, 158 | /// `subscribe`, `write`, and `flush`, and is implemented with the 159 | /// following pseudo-code: 160 | /// 161 | /// ```text 162 | /// let pollable = this.subscribe(); 163 | /// while !contents.is_empty() { 164 | /// // Wait for the stream to become writable 165 | /// pollable.block(); 166 | /// let Ok(n) = this.check-write(); // eliding error handling 167 | /// let len = min(n, contents.len()); 168 | /// let (chunk, rest) = contents.split_at(len); 169 | /// this.write(chunk ); // eliding error handling 170 | /// contents = rest; 171 | /// } 172 | /// this.flush(); 173 | /// // Wait for completion of `flush` 174 | /// pollable.block(); 175 | /// // Check for any errors that arose during `flush` 176 | /// let _ = this.check-write(); // eliding error handling 177 | /// ``` 178 | @since(version = 0.2.0) 179 | blocking-write-and-flush: func( 180 | contents: list 181 | ) -> result<_, stream-error>; 182 | 183 | /// Request to flush buffered output. This function never blocks. 184 | /// 185 | /// This tells the output-stream that the caller intends any buffered 186 | /// output to be flushed. the output which is expected to be flushed 187 | /// is all that has been passed to `write` prior to this call. 188 | /// 189 | /// Upon calling this function, the `output-stream` will not accept any 190 | /// writes (`check-write` will return `ok(0)`) until the flush has 191 | /// completed. The `subscribe` pollable will become ready when the 192 | /// flush has completed and the stream can accept more writes. 193 | @since(version = 0.2.0) 194 | flush: func() -> result<_, stream-error>; 195 | 196 | /// Request to flush buffered output, and block until flush completes 197 | /// and stream is ready for writing again. 198 | @since(version = 0.2.0) 199 | blocking-flush: func() -> result<_, stream-error>; 200 | 201 | /// Create a `pollable` which will resolve once the output-stream 202 | /// is ready for more writing, or an error has occurred. When this 203 | /// pollable is ready, `check-write` will return `ok(n)` with n>0, or an 204 | /// error. 205 | /// 206 | /// If the stream is closed, this pollable is always ready immediately. 207 | /// 208 | /// The created `pollable` is a child resource of the `output-stream`. 209 | /// Implementations may trap if the `output-stream` is dropped before 210 | /// all derived `pollable`s created with this function are dropped. 211 | @since(version = 0.2.0) 212 | subscribe: func() -> pollable; 213 | 214 | /// Write zeroes to a stream. 215 | /// 216 | /// This should be used precisely like `write` with the exact same 217 | /// preconditions (must use check-write first), but instead of 218 | /// passing a list of bytes, you simply pass the number of zero-bytes 219 | /// that should be written. 220 | @since(version = 0.2.0) 221 | write-zeroes: func( 222 | /// The number of zero-bytes to write 223 | len: u64 224 | ) -> result<_, stream-error>; 225 | 226 | /// Perform a write of up to 4096 zeroes, and then flush the stream. 227 | /// Block until all of these operations are complete, or an error 228 | /// occurs. 229 | /// 230 | /// This is a convenience wrapper around the use of `check-write`, 231 | /// `subscribe`, `write-zeroes`, and `flush`, and is implemented with 232 | /// the following pseudo-code: 233 | /// 234 | /// ```text 235 | /// let pollable = this.subscribe(); 236 | /// while num_zeroes != 0 { 237 | /// // Wait for the stream to become writable 238 | /// pollable.block(); 239 | /// let Ok(n) = this.check-write(); // eliding error handling 240 | /// let len = min(n, num_zeroes); 241 | /// this.write-zeroes(len); // eliding error handling 242 | /// num_zeroes -= len; 243 | /// } 244 | /// this.flush(); 245 | /// // Wait for completion of `flush` 246 | /// pollable.block(); 247 | /// // Check for any errors that arose during `flush` 248 | /// let _ = this.check-write(); // eliding error handling 249 | /// ``` 250 | @since(version = 0.2.0) 251 | blocking-write-zeroes-and-flush: func( 252 | /// The number of zero-bytes to write 253 | len: u64 254 | ) -> result<_, stream-error>; 255 | 256 | /// Read from one stream and write to another. 257 | /// 258 | /// The behavior of splice is equivalent to: 259 | /// 1. calling `check-write` on the `output-stream` 260 | /// 2. calling `read` on the `input-stream` with the smaller of the 261 | /// `check-write` permitted length and the `len` provided to `splice` 262 | /// 3. calling `write` on the `output-stream` with that read data. 263 | /// 264 | /// Any error reported by the call to `check-write`, `read`, or 265 | /// `write` ends the splice and reports that error. 266 | /// 267 | /// This function returns the number of bytes transferred; it may be less 268 | /// than `len`. 269 | @since(version = 0.2.0) 270 | splice: func( 271 | /// The stream to read from 272 | src: borrow, 273 | /// The number of bytes to splice 274 | len: u64, 275 | ) -> result; 276 | 277 | /// Read from one stream and write to another, with blocking. 278 | /// 279 | /// This is similar to `splice`, except that it blocks until the 280 | /// `output-stream` is ready for writing, and the `input-stream` 281 | /// is ready for reading, before performing the `splice`. 282 | @since(version = 0.2.0) 283 | blocking-splice: func( 284 | /// The stream to read from 285 | src: borrow, 286 | /// The number of bytes to splice 287 | len: u64, 288 | ) -> result; 289 | } 290 | } 291 | -------------------------------------------------------------------------------- /wit/deps/io/world.wit: -------------------------------------------------------------------------------- 1 | package wasi:io@0.2.4; 2 | 3 | @since(version = 0.2.0) 4 | world imports { 5 | @since(version = 0.2.0) 6 | import streams; 7 | 8 | @since(version = 0.2.0) 9 | import poll; 10 | } 11 | -------------------------------------------------------------------------------- /wit/deps/random/insecure-seed.wit: -------------------------------------------------------------------------------- 1 | package wasi:random@0.2.4; 2 | /// The insecure-seed interface for seeding hash-map DoS resistance. 3 | /// 4 | /// It is intended to be portable at least between Unix-family platforms and 5 | /// Windows. 6 | @since(version = 0.2.0) 7 | interface insecure-seed { 8 | /// Return a 128-bit value that may contain a pseudo-random value. 9 | /// 10 | /// The returned value is not required to be computed from a CSPRNG, and may 11 | /// even be entirely deterministic. Host implementations are encouraged to 12 | /// provide pseudo-random values to any program exposed to 13 | /// attacker-controlled content, to enable DoS protection built into many 14 | /// languages' hash-map implementations. 15 | /// 16 | /// This function is intended to only be called once, by a source language 17 | /// to initialize Denial Of Service (DoS) protection in its hash-map 18 | /// implementation. 19 | /// 20 | /// # Expected future evolution 21 | /// 22 | /// This will likely be changed to a value import, to prevent it from being 23 | /// called multiple times and potentially used for purposes other than DoS 24 | /// protection. 25 | @since(version = 0.2.0) 26 | insecure-seed: func() -> tuple; 27 | } 28 | -------------------------------------------------------------------------------- /wit/deps/random/insecure.wit: -------------------------------------------------------------------------------- 1 | package wasi:random@0.2.4; 2 | /// The insecure interface for insecure pseudo-random numbers. 3 | /// 4 | /// It is intended to be portable at least between Unix-family platforms and 5 | /// Windows. 6 | @since(version = 0.2.0) 7 | interface insecure { 8 | /// Return `len` insecure pseudo-random bytes. 9 | /// 10 | /// This function is not cryptographically secure. Do not use it for 11 | /// anything related to security. 12 | /// 13 | /// There are no requirements on the values of the returned bytes, however 14 | /// implementations are encouraged to return evenly distributed values with 15 | /// a long period. 16 | @since(version = 0.2.0) 17 | get-insecure-random-bytes: func(len: u64) -> list; 18 | 19 | /// Return an insecure pseudo-random `u64` value. 20 | /// 21 | /// This function returns the same type of pseudo-random data as 22 | /// `get-insecure-random-bytes`, represented as a `u64`. 23 | @since(version = 0.2.0) 24 | get-insecure-random-u64: func() -> u64; 25 | } 26 | -------------------------------------------------------------------------------- /wit/deps/random/random.wit: -------------------------------------------------------------------------------- 1 | package wasi:random@0.2.4; 2 | /// WASI Random is a random data API. 3 | /// 4 | /// It is intended to be portable at least between Unix-family platforms and 5 | /// Windows. 6 | @since(version = 0.2.0) 7 | interface random { 8 | /// Return `len` cryptographically-secure random or pseudo-random bytes. 9 | /// 10 | /// This function must produce data at least as cryptographically secure and 11 | /// fast as an adequately seeded cryptographically-secure pseudo-random 12 | /// number generator (CSPRNG). It must not block, from the perspective of 13 | /// the calling program, under any circumstances, including on the first 14 | /// request and on requests for numbers of bytes. The returned data must 15 | /// always be unpredictable. 16 | /// 17 | /// This function must always return fresh data. Deterministic environments 18 | /// must omit this function, rather than implementing it with deterministic 19 | /// data. 20 | @since(version = 0.2.0) 21 | get-random-bytes: func(len: u64) -> list; 22 | 23 | /// Return a cryptographically-secure random or pseudo-random `u64` value. 24 | /// 25 | /// This function returns the same type of data as `get-random-bytes`, 26 | /// represented as a `u64`. 27 | @since(version = 0.2.0) 28 | get-random-u64: func() -> u64; 29 | } 30 | -------------------------------------------------------------------------------- /wit/deps/random/world.wit: -------------------------------------------------------------------------------- 1 | package wasi:random@0.2.4; 2 | 3 | @since(version = 0.2.0) 4 | world imports { 5 | @since(version = 0.2.0) 6 | import random; 7 | 8 | @since(version = 0.2.0) 9 | import insecure; 10 | 11 | @since(version = 0.2.0) 12 | import insecure-seed; 13 | } 14 | -------------------------------------------------------------------------------- /wit/deps/sockets/instance-network.wit: -------------------------------------------------------------------------------- 1 | 2 | /// This interface provides a value-export of the default network handle.. 3 | @since(version = 0.2.0) 4 | interface instance-network { 5 | @since(version = 0.2.0) 6 | use network.{network}; 7 | 8 | /// Get a handle to the default network. 9 | @since(version = 0.2.0) 10 | instance-network: func() -> network; 11 | } 12 | -------------------------------------------------------------------------------- /wit/deps/sockets/ip-name-lookup.wit: -------------------------------------------------------------------------------- 1 | @since(version = 0.2.0) 2 | interface ip-name-lookup { 3 | @since(version = 0.2.0) 4 | use wasi:io/poll@0.2.4.{pollable}; 5 | @since(version = 0.2.0) 6 | use network.{network, error-code, ip-address}; 7 | 8 | /// Resolve an internet host name to a list of IP addresses. 9 | /// 10 | /// Unicode domain names are automatically converted to ASCII using IDNA encoding. 11 | /// If the input is an IP address string, the address is parsed and returned 12 | /// as-is without making any external requests. 13 | /// 14 | /// See the wasi-socket proposal README.md for a comparison with getaddrinfo. 15 | /// 16 | /// This function never blocks. It either immediately fails or immediately 17 | /// returns successfully with a `resolve-address-stream` that can be used 18 | /// to (asynchronously) fetch the results. 19 | /// 20 | /// # Typical errors 21 | /// - `invalid-argument`: `name` is a syntactically invalid domain name or IP address. 22 | /// 23 | /// # References: 24 | /// - 25 | /// - 26 | /// - 27 | /// - 28 | @since(version = 0.2.0) 29 | resolve-addresses: func(network: borrow, name: string) -> result; 30 | 31 | @since(version = 0.2.0) 32 | resource resolve-address-stream { 33 | /// Returns the next address from the resolver. 34 | /// 35 | /// This function should be called multiple times. On each call, it will 36 | /// return the next address in connection order preference. If all 37 | /// addresses have been exhausted, this function returns `none`. 38 | /// 39 | /// This function never returns IPv4-mapped IPv6 addresses. 40 | /// 41 | /// # Typical errors 42 | /// - `name-unresolvable`: Name does not exist or has no suitable associated IP addresses. (EAI_NONAME, EAI_NODATA, EAI_ADDRFAMILY) 43 | /// - `temporary-resolver-failure`: A temporary failure in name resolution occurred. (EAI_AGAIN) 44 | /// - `permanent-resolver-failure`: A permanent failure in name resolution occurred. (EAI_FAIL) 45 | /// - `would-block`: A result is not available yet. (EWOULDBLOCK, EAGAIN) 46 | @since(version = 0.2.0) 47 | resolve-next-address: func() -> result, error-code>; 48 | 49 | /// Create a `pollable` which will resolve once the stream is ready for I/O. 50 | /// 51 | /// Note: this function is here for WASI 0.2 only. 52 | /// It's planned to be removed when `future` is natively supported in Preview3. 53 | @since(version = 0.2.0) 54 | subscribe: func() -> pollable; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /wit/deps/sockets/network.wit: -------------------------------------------------------------------------------- 1 | @since(version = 0.2.0) 2 | interface network { 3 | @unstable(feature = network-error-code) 4 | use wasi:io/error@0.2.4.{error}; 5 | 6 | /// An opaque resource that represents access to (a subset of) the network. 7 | /// This enables context-based security for networking. 8 | /// There is no need for this to map 1:1 to a physical network interface. 9 | @since(version = 0.2.0) 10 | resource network; 11 | 12 | /// Error codes. 13 | /// 14 | /// In theory, every API can return any error code. 15 | /// In practice, API's typically only return the errors documented per API 16 | /// combined with a couple of errors that are always possible: 17 | /// - `unknown` 18 | /// - `access-denied` 19 | /// - `not-supported` 20 | /// - `out-of-memory` 21 | /// - `concurrency-conflict` 22 | /// 23 | /// See each individual API for what the POSIX equivalents are. They sometimes differ per API. 24 | @since(version = 0.2.0) 25 | enum error-code { 26 | /// Unknown error 27 | unknown, 28 | 29 | /// Access denied. 30 | /// 31 | /// POSIX equivalent: EACCES, EPERM 32 | access-denied, 33 | 34 | /// The operation is not supported. 35 | /// 36 | /// POSIX equivalent: EOPNOTSUPP 37 | not-supported, 38 | 39 | /// One of the arguments is invalid. 40 | /// 41 | /// POSIX equivalent: EINVAL 42 | invalid-argument, 43 | 44 | /// Not enough memory to complete the operation. 45 | /// 46 | /// POSIX equivalent: ENOMEM, ENOBUFS, EAI_MEMORY 47 | out-of-memory, 48 | 49 | /// The operation timed out before it could finish completely. 50 | timeout, 51 | 52 | /// This operation is incompatible with another asynchronous operation that is already in progress. 53 | /// 54 | /// POSIX equivalent: EALREADY 55 | concurrency-conflict, 56 | 57 | /// Trying to finish an asynchronous operation that: 58 | /// - has not been started yet, or: 59 | /// - was already finished by a previous `finish-*` call. 60 | /// 61 | /// Note: this is scheduled to be removed when `future`s are natively supported. 62 | not-in-progress, 63 | 64 | /// The operation has been aborted because it could not be completed immediately. 65 | /// 66 | /// Note: this is scheduled to be removed when `future`s are natively supported. 67 | would-block, 68 | 69 | 70 | /// The operation is not valid in the socket's current state. 71 | invalid-state, 72 | 73 | /// A new socket resource could not be created because of a system limit. 74 | new-socket-limit, 75 | 76 | /// A bind operation failed because the provided address is not an address that the `network` can bind to. 77 | address-not-bindable, 78 | 79 | /// A bind operation failed because the provided address is already in use or because there are no ephemeral ports available. 80 | address-in-use, 81 | 82 | /// The remote address is not reachable 83 | remote-unreachable, 84 | 85 | 86 | /// The TCP connection was forcefully rejected 87 | connection-refused, 88 | 89 | /// The TCP connection was reset. 90 | connection-reset, 91 | 92 | /// A TCP connection was aborted. 93 | connection-aborted, 94 | 95 | 96 | /// The size of a datagram sent to a UDP socket exceeded the maximum 97 | /// supported size. 98 | datagram-too-large, 99 | 100 | 101 | /// Name does not exist or has no suitable associated IP addresses. 102 | name-unresolvable, 103 | 104 | /// A temporary failure in name resolution occurred. 105 | temporary-resolver-failure, 106 | 107 | /// A permanent failure in name resolution occurred. 108 | permanent-resolver-failure, 109 | } 110 | 111 | /// Attempts to extract a network-related `error-code` from the stream 112 | /// `error` provided. 113 | /// 114 | /// Stream operations which return `stream-error::last-operation-failed` 115 | /// have a payload with more information about the operation that failed. 116 | /// This payload can be passed through to this function to see if there's 117 | /// network-related information about the error to return. 118 | /// 119 | /// Note that this function is fallible because not all stream-related 120 | /// errors are network-related errors. 121 | @unstable(feature = network-error-code) 122 | network-error-code: func(err: borrow) -> option; 123 | 124 | @since(version = 0.2.0) 125 | enum ip-address-family { 126 | /// Similar to `AF_INET` in POSIX. 127 | ipv4, 128 | 129 | /// Similar to `AF_INET6` in POSIX. 130 | ipv6, 131 | } 132 | 133 | @since(version = 0.2.0) 134 | type ipv4-address = tuple; 135 | @since(version = 0.2.0) 136 | type ipv6-address = tuple; 137 | 138 | @since(version = 0.2.0) 139 | variant ip-address { 140 | ipv4(ipv4-address), 141 | ipv6(ipv6-address), 142 | } 143 | 144 | @since(version = 0.2.0) 145 | record ipv4-socket-address { 146 | /// sin_port 147 | port: u16, 148 | /// sin_addr 149 | address: ipv4-address, 150 | } 151 | 152 | @since(version = 0.2.0) 153 | record ipv6-socket-address { 154 | /// sin6_port 155 | port: u16, 156 | /// sin6_flowinfo 157 | flow-info: u32, 158 | /// sin6_addr 159 | address: ipv6-address, 160 | /// sin6_scope_id 161 | scope-id: u32, 162 | } 163 | 164 | @since(version = 0.2.0) 165 | variant ip-socket-address { 166 | ipv4(ipv4-socket-address), 167 | ipv6(ipv6-socket-address), 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /wit/deps/sockets/tcp-create-socket.wit: -------------------------------------------------------------------------------- 1 | @since(version = 0.2.0) 2 | interface tcp-create-socket { 3 | @since(version = 0.2.0) 4 | use network.{network, error-code, ip-address-family}; 5 | @since(version = 0.2.0) 6 | use tcp.{tcp-socket}; 7 | 8 | /// Create a new TCP socket. 9 | /// 10 | /// Similar to `socket(AF_INET or AF_INET6, SOCK_STREAM, IPPROTO_TCP)` in POSIX. 11 | /// On IPv6 sockets, IPV6_V6ONLY is enabled by default and can't be configured otherwise. 12 | /// 13 | /// This function does not require a network capability handle. This is considered to be safe because 14 | /// at time of creation, the socket is not bound to any `network` yet. Up to the moment `bind`/`connect` 15 | /// is called, the socket is effectively an in-memory configuration object, unable to communicate with the outside world. 16 | /// 17 | /// All sockets are non-blocking. Use the wasi-poll interface to block on asynchronous operations. 18 | /// 19 | /// # Typical errors 20 | /// - `not-supported`: The specified `address-family` is not supported. (EAFNOSUPPORT) 21 | /// - `new-socket-limit`: The new socket resource could not be created because of a system limit. (EMFILE, ENFILE) 22 | /// 23 | /// # References 24 | /// - 25 | /// - 26 | /// - 27 | /// - 28 | @since(version = 0.2.0) 29 | create-tcp-socket: func(address-family: ip-address-family) -> result; 30 | } 31 | -------------------------------------------------------------------------------- /wit/deps/sockets/tcp.wit: -------------------------------------------------------------------------------- 1 | @since(version = 0.2.0) 2 | interface tcp { 3 | @since(version = 0.2.0) 4 | use wasi:io/streams@0.2.4.{input-stream, output-stream}; 5 | @since(version = 0.2.0) 6 | use wasi:io/poll@0.2.4.{pollable}; 7 | @since(version = 0.2.0) 8 | use wasi:clocks/monotonic-clock@0.2.4.{duration}; 9 | @since(version = 0.2.0) 10 | use network.{network, error-code, ip-socket-address, ip-address-family}; 11 | 12 | @since(version = 0.2.0) 13 | enum shutdown-type { 14 | /// Similar to `SHUT_RD` in POSIX. 15 | receive, 16 | 17 | /// Similar to `SHUT_WR` in POSIX. 18 | send, 19 | 20 | /// Similar to `SHUT_RDWR` in POSIX. 21 | both, 22 | } 23 | 24 | /// A TCP socket resource. 25 | /// 26 | /// The socket can be in one of the following states: 27 | /// - `unbound` 28 | /// - `bind-in-progress` 29 | /// - `bound` (See note below) 30 | /// - `listen-in-progress` 31 | /// - `listening` 32 | /// - `connect-in-progress` 33 | /// - `connected` 34 | /// - `closed` 35 | /// See 36 | /// for more information. 37 | /// 38 | /// Note: Except where explicitly mentioned, whenever this documentation uses 39 | /// the term "bound" without backticks it actually means: in the `bound` state *or higher*. 40 | /// (i.e. `bound`, `listen-in-progress`, `listening`, `connect-in-progress` or `connected`) 41 | /// 42 | /// In addition to the general error codes documented on the 43 | /// `network::error-code` type, TCP socket methods may always return 44 | /// `error(invalid-state)` when in the `closed` state. 45 | @since(version = 0.2.0) 46 | resource tcp-socket { 47 | /// Bind the socket to a specific network on the provided IP address and port. 48 | /// 49 | /// If the IP address is zero (`0.0.0.0` in IPv4, `::` in IPv6), it is left to the implementation to decide which 50 | /// network interface(s) to bind to. 51 | /// If the TCP/UDP port is zero, the socket will be bound to a random free port. 52 | /// 53 | /// Bind can be attempted multiple times on the same socket, even with 54 | /// different arguments on each iteration. But never concurrently and 55 | /// only as long as the previous bind failed. Once a bind succeeds, the 56 | /// binding can't be changed anymore. 57 | /// 58 | /// # Typical errors 59 | /// - `invalid-argument`: The `local-address` has the wrong address family. (EAFNOSUPPORT, EFAULT on Windows) 60 | /// - `invalid-argument`: `local-address` is not a unicast address. (EINVAL) 61 | /// - `invalid-argument`: `local-address` is an IPv4-mapped IPv6 address. (EINVAL) 62 | /// - `invalid-state`: The socket is already bound. (EINVAL) 63 | /// - `address-in-use`: No ephemeral ports available. (EADDRINUSE, ENOBUFS on Windows) 64 | /// - `address-in-use`: Address is already in use. (EADDRINUSE) 65 | /// - `address-not-bindable`: `local-address` is not an address that the `network` can bind to. (EADDRNOTAVAIL) 66 | /// - `not-in-progress`: A `bind` operation is not in progress. 67 | /// - `would-block`: Can't finish the operation, it is still in progress. (EWOULDBLOCK, EAGAIN) 68 | /// 69 | /// # Implementors note 70 | /// When binding to a non-zero port, this bind operation shouldn't be affected by the TIME_WAIT 71 | /// state of a recently closed socket on the same local address. In practice this means that the SO_REUSEADDR 72 | /// socket option should be set implicitly on all platforms, except on Windows where this is the default behavior 73 | /// and SO_REUSEADDR performs something different entirely. 74 | /// 75 | /// Unlike in POSIX, in WASI the bind operation is async. This enables 76 | /// interactive WASI hosts to inject permission prompts. Runtimes that 77 | /// don't want to make use of this ability can simply call the native 78 | /// `bind` as part of either `start-bind` or `finish-bind`. 79 | /// 80 | /// # References 81 | /// - 82 | /// - 83 | /// - 84 | /// - 85 | @since(version = 0.2.0) 86 | start-bind: func(network: borrow, local-address: ip-socket-address) -> result<_, error-code>; 87 | @since(version = 0.2.0) 88 | finish-bind: func() -> result<_, error-code>; 89 | 90 | /// Connect to a remote endpoint. 91 | /// 92 | /// On success: 93 | /// - the socket is transitioned into the `connected` state. 94 | /// - a pair of streams is returned that can be used to read & write to the connection 95 | /// 96 | /// After a failed connection attempt, the socket will be in the `closed` 97 | /// state and the only valid action left is to `drop` the socket. A single 98 | /// socket can not be used to connect more than once. 99 | /// 100 | /// # Typical errors 101 | /// - `invalid-argument`: The `remote-address` has the wrong address family. (EAFNOSUPPORT) 102 | /// - `invalid-argument`: `remote-address` is not a unicast address. (EINVAL, ENETUNREACH on Linux, EAFNOSUPPORT on MacOS) 103 | /// - `invalid-argument`: `remote-address` is an IPv4-mapped IPv6 address. (EINVAL, EADDRNOTAVAIL on Illumos) 104 | /// - `invalid-argument`: The IP address in `remote-address` is set to INADDR_ANY (`0.0.0.0` / `::`). (EADDRNOTAVAIL on Windows) 105 | /// - `invalid-argument`: The port in `remote-address` is set to 0. (EADDRNOTAVAIL on Windows) 106 | /// - `invalid-argument`: The socket is already attached to a different network. The `network` passed to `connect` must be identical to the one passed to `bind`. 107 | /// - `invalid-state`: The socket is already in the `connected` state. (EISCONN) 108 | /// - `invalid-state`: The socket is already in the `listening` state. (EOPNOTSUPP, EINVAL on Windows) 109 | /// - `timeout`: Connection timed out. (ETIMEDOUT) 110 | /// - `connection-refused`: The connection was forcefully rejected. (ECONNREFUSED) 111 | /// - `connection-reset`: The connection was reset. (ECONNRESET) 112 | /// - `connection-aborted`: The connection was aborted. (ECONNABORTED) 113 | /// - `remote-unreachable`: The remote address is not reachable. (EHOSTUNREACH, EHOSTDOWN, ENETUNREACH, ENETDOWN, ENONET) 114 | /// - `address-in-use`: Tried to perform an implicit bind, but there were no ephemeral ports available. (EADDRINUSE, EADDRNOTAVAIL on Linux, EAGAIN on BSD) 115 | /// - `not-in-progress`: A connect operation is not in progress. 116 | /// - `would-block`: Can't finish the operation, it is still in progress. (EWOULDBLOCK, EAGAIN) 117 | /// 118 | /// # Implementors note 119 | /// The POSIX equivalent of `start-connect` is the regular `connect` syscall. 120 | /// Because all WASI sockets are non-blocking this is expected to return 121 | /// EINPROGRESS, which should be translated to `ok()` in WASI. 122 | /// 123 | /// The POSIX equivalent of `finish-connect` is a `poll` for event `POLLOUT` 124 | /// with a timeout of 0 on the socket descriptor. Followed by a check for 125 | /// the `SO_ERROR` socket option, in case the poll signaled readiness. 126 | /// 127 | /// # References 128 | /// - 129 | /// - 130 | /// - 131 | /// - 132 | @since(version = 0.2.0) 133 | start-connect: func(network: borrow, remote-address: ip-socket-address) -> result<_, error-code>; 134 | @since(version = 0.2.0) 135 | finish-connect: func() -> result, error-code>; 136 | 137 | /// Start listening for new connections. 138 | /// 139 | /// Transitions the socket into the `listening` state. 140 | /// 141 | /// Unlike POSIX, the socket must already be explicitly bound. 142 | /// 143 | /// # Typical errors 144 | /// - `invalid-state`: The socket is not bound to any local address. (EDESTADDRREQ) 145 | /// - `invalid-state`: The socket is already in the `connected` state. (EISCONN, EINVAL on BSD) 146 | /// - `invalid-state`: The socket is already in the `listening` state. 147 | /// - `address-in-use`: Tried to perform an implicit bind, but there were no ephemeral ports available. (EADDRINUSE) 148 | /// - `not-in-progress`: A listen operation is not in progress. 149 | /// - `would-block`: Can't finish the operation, it is still in progress. (EWOULDBLOCK, EAGAIN) 150 | /// 151 | /// # Implementors note 152 | /// Unlike in POSIX, in WASI the listen operation is async. This enables 153 | /// interactive WASI hosts to inject permission prompts. Runtimes that 154 | /// don't want to make use of this ability can simply call the native 155 | /// `listen` as part of either `start-listen` or `finish-listen`. 156 | /// 157 | /// # References 158 | /// - 159 | /// - 160 | /// - 161 | /// - 162 | @since(version = 0.2.0) 163 | start-listen: func() -> result<_, error-code>; 164 | @since(version = 0.2.0) 165 | finish-listen: func() -> result<_, error-code>; 166 | 167 | /// Accept a new client socket. 168 | /// 169 | /// The returned socket is bound and in the `connected` state. The following properties are inherited from the listener socket: 170 | /// - `address-family` 171 | /// - `keep-alive-enabled` 172 | /// - `keep-alive-idle-time` 173 | /// - `keep-alive-interval` 174 | /// - `keep-alive-count` 175 | /// - `hop-limit` 176 | /// - `receive-buffer-size` 177 | /// - `send-buffer-size` 178 | /// 179 | /// On success, this function returns the newly accepted client socket along with 180 | /// a pair of streams that can be used to read & write to the connection. 181 | /// 182 | /// # Typical errors 183 | /// - `invalid-state`: Socket is not in the `listening` state. (EINVAL) 184 | /// - `would-block`: No pending connections at the moment. (EWOULDBLOCK, EAGAIN) 185 | /// - `connection-aborted`: An incoming connection was pending, but was terminated by the client before this listener could accept it. (ECONNABORTED) 186 | /// - `new-socket-limit`: The new socket resource could not be created because of a system limit. (EMFILE, ENFILE) 187 | /// 188 | /// # References 189 | /// - 190 | /// - 191 | /// - 192 | /// - 193 | @since(version = 0.2.0) 194 | accept: func() -> result, error-code>; 195 | 196 | /// Get the bound local address. 197 | /// 198 | /// POSIX mentions: 199 | /// > If the socket has not been bound to a local name, the value 200 | /// > stored in the object pointed to by `address` is unspecified. 201 | /// 202 | /// WASI is stricter and requires `local-address` to return `invalid-state` when the socket hasn't been bound yet. 203 | /// 204 | /// # Typical errors 205 | /// - `invalid-state`: The socket is not bound to any local address. 206 | /// 207 | /// # References 208 | /// - 209 | /// - 210 | /// - 211 | /// - 212 | @since(version = 0.2.0) 213 | local-address: func() -> result; 214 | 215 | /// Get the remote address. 216 | /// 217 | /// # Typical errors 218 | /// - `invalid-state`: The socket is not connected to a remote address. (ENOTCONN) 219 | /// 220 | /// # References 221 | /// - 222 | /// - 223 | /// - 224 | /// - 225 | @since(version = 0.2.0) 226 | remote-address: func() -> result; 227 | 228 | /// Whether the socket is in the `listening` state. 229 | /// 230 | /// Equivalent to the SO_ACCEPTCONN socket option. 231 | @since(version = 0.2.0) 232 | is-listening: func() -> bool; 233 | 234 | /// Whether this is a IPv4 or IPv6 socket. 235 | /// 236 | /// Equivalent to the SO_DOMAIN socket option. 237 | @since(version = 0.2.0) 238 | address-family: func() -> ip-address-family; 239 | 240 | /// Hints the desired listen queue size. Implementations are free to ignore this. 241 | /// 242 | /// If the provided value is 0, an `invalid-argument` error is returned. 243 | /// Any other value will never cause an error, but it might be silently clamped and/or rounded. 244 | /// 245 | /// # Typical errors 246 | /// - `not-supported`: (set) The platform does not support changing the backlog size after the initial listen. 247 | /// - `invalid-argument`: (set) The provided value was 0. 248 | /// - `invalid-state`: (set) The socket is in the `connect-in-progress` or `connected` state. 249 | @since(version = 0.2.0) 250 | set-listen-backlog-size: func(value: u64) -> result<_, error-code>; 251 | 252 | /// Enables or disables keepalive. 253 | /// 254 | /// The keepalive behavior can be adjusted using: 255 | /// - `keep-alive-idle-time` 256 | /// - `keep-alive-interval` 257 | /// - `keep-alive-count` 258 | /// These properties can be configured while `keep-alive-enabled` is false, but only come into effect when `keep-alive-enabled` is true. 259 | /// 260 | /// Equivalent to the SO_KEEPALIVE socket option. 261 | @since(version = 0.2.0) 262 | keep-alive-enabled: func() -> result; 263 | @since(version = 0.2.0) 264 | set-keep-alive-enabled: func(value: bool) -> result<_, error-code>; 265 | 266 | /// Amount of time the connection has to be idle before TCP starts sending keepalive packets. 267 | /// 268 | /// If the provided value is 0, an `invalid-argument` error is returned. 269 | /// Any other value will never cause an error, but it might be silently clamped and/or rounded. 270 | /// I.e. after setting a value, reading the same setting back may return a different value. 271 | /// 272 | /// Equivalent to the TCP_KEEPIDLE socket option. (TCP_KEEPALIVE on MacOS) 273 | /// 274 | /// # Typical errors 275 | /// - `invalid-argument`: (set) The provided value was 0. 276 | @since(version = 0.2.0) 277 | keep-alive-idle-time: func() -> result; 278 | @since(version = 0.2.0) 279 | set-keep-alive-idle-time: func(value: duration) -> result<_, error-code>; 280 | 281 | /// The time between keepalive packets. 282 | /// 283 | /// If the provided value is 0, an `invalid-argument` error is returned. 284 | /// Any other value will never cause an error, but it might be silently clamped and/or rounded. 285 | /// I.e. after setting a value, reading the same setting back may return a different value. 286 | /// 287 | /// Equivalent to the TCP_KEEPINTVL socket option. 288 | /// 289 | /// # Typical errors 290 | /// - `invalid-argument`: (set) The provided value was 0. 291 | @since(version = 0.2.0) 292 | keep-alive-interval: func() -> result; 293 | @since(version = 0.2.0) 294 | set-keep-alive-interval: func(value: duration) -> result<_, error-code>; 295 | 296 | /// The maximum amount of keepalive packets TCP should send before aborting the connection. 297 | /// 298 | /// If the provided value is 0, an `invalid-argument` error is returned. 299 | /// Any other value will never cause an error, but it might be silently clamped and/or rounded. 300 | /// I.e. after setting a value, reading the same setting back may return a different value. 301 | /// 302 | /// Equivalent to the TCP_KEEPCNT socket option. 303 | /// 304 | /// # Typical errors 305 | /// - `invalid-argument`: (set) The provided value was 0. 306 | @since(version = 0.2.0) 307 | keep-alive-count: func() -> result; 308 | @since(version = 0.2.0) 309 | set-keep-alive-count: func(value: u32) -> result<_, error-code>; 310 | 311 | /// Equivalent to the IP_TTL & IPV6_UNICAST_HOPS socket options. 312 | /// 313 | /// If the provided value is 0, an `invalid-argument` error is returned. 314 | /// 315 | /// # Typical errors 316 | /// - `invalid-argument`: (set) The TTL value must be 1 or higher. 317 | @since(version = 0.2.0) 318 | hop-limit: func() -> result; 319 | @since(version = 0.2.0) 320 | set-hop-limit: func(value: u8) -> result<_, error-code>; 321 | 322 | /// The kernel buffer space reserved for sends/receives on this socket. 323 | /// 324 | /// If the provided value is 0, an `invalid-argument` error is returned. 325 | /// Any other value will never cause an error, but it might be silently clamped and/or rounded. 326 | /// I.e. after setting a value, reading the same setting back may return a different value. 327 | /// 328 | /// Equivalent to the SO_RCVBUF and SO_SNDBUF socket options. 329 | /// 330 | /// # Typical errors 331 | /// - `invalid-argument`: (set) The provided value was 0. 332 | @since(version = 0.2.0) 333 | receive-buffer-size: func() -> result; 334 | @since(version = 0.2.0) 335 | set-receive-buffer-size: func(value: u64) -> result<_, error-code>; 336 | @since(version = 0.2.0) 337 | send-buffer-size: func() -> result; 338 | @since(version = 0.2.0) 339 | set-send-buffer-size: func(value: u64) -> result<_, error-code>; 340 | 341 | /// Create a `pollable` which can be used to poll for, or block on, 342 | /// completion of any of the asynchronous operations of this socket. 343 | /// 344 | /// When `finish-bind`, `finish-listen`, `finish-connect` or `accept` 345 | /// return `error(would-block)`, this pollable can be used to wait for 346 | /// their success or failure, after which the method can be retried. 347 | /// 348 | /// The pollable is not limited to the async operation that happens to be 349 | /// in progress at the time of calling `subscribe` (if any). Theoretically, 350 | /// `subscribe` only has to be called once per socket and can then be 351 | /// (re)used for the remainder of the socket's lifetime. 352 | /// 353 | /// See 354 | /// for more information. 355 | /// 356 | /// Note: this function is here for WASI 0.2 only. 357 | /// It's planned to be removed when `future` is natively supported in Preview3. 358 | @since(version = 0.2.0) 359 | subscribe: func() -> pollable; 360 | 361 | /// Initiate a graceful shutdown. 362 | /// 363 | /// - `receive`: The socket is not expecting to receive any data from 364 | /// the peer. The `input-stream` associated with this socket will be 365 | /// closed. Any data still in the receive queue at time of calling 366 | /// this method will be discarded. 367 | /// - `send`: The socket has no more data to send to the peer. The `output-stream` 368 | /// associated with this socket will be closed and a FIN packet will be sent. 369 | /// - `both`: Same effect as `receive` & `send` combined. 370 | /// 371 | /// This function is idempotent; shutting down a direction more than once 372 | /// has no effect and returns `ok`. 373 | /// 374 | /// The shutdown function does not close (drop) the socket. 375 | /// 376 | /// # Typical errors 377 | /// - `invalid-state`: The socket is not in the `connected` state. (ENOTCONN) 378 | /// 379 | /// # References 380 | /// - 381 | /// - 382 | /// - 383 | /// - 384 | @since(version = 0.2.0) 385 | shutdown: func(shutdown-type: shutdown-type) -> result<_, error-code>; 386 | } 387 | } 388 | -------------------------------------------------------------------------------- /wit/deps/sockets/udp-create-socket.wit: -------------------------------------------------------------------------------- 1 | @since(version = 0.2.0) 2 | interface udp-create-socket { 3 | @since(version = 0.2.0) 4 | use network.{network, error-code, ip-address-family}; 5 | @since(version = 0.2.0) 6 | use udp.{udp-socket}; 7 | 8 | /// Create a new UDP socket. 9 | /// 10 | /// Similar to `socket(AF_INET or AF_INET6, SOCK_DGRAM, IPPROTO_UDP)` in POSIX. 11 | /// On IPv6 sockets, IPV6_V6ONLY is enabled by default and can't be configured otherwise. 12 | /// 13 | /// This function does not require a network capability handle. This is considered to be safe because 14 | /// at time of creation, the socket is not bound to any `network` yet. Up to the moment `bind` is called, 15 | /// the socket is effectively an in-memory configuration object, unable to communicate with the outside world. 16 | /// 17 | /// All sockets are non-blocking. Use the wasi-poll interface to block on asynchronous operations. 18 | /// 19 | /// # Typical errors 20 | /// - `not-supported`: The specified `address-family` is not supported. (EAFNOSUPPORT) 21 | /// - `new-socket-limit`: The new socket resource could not be created because of a system limit. (EMFILE, ENFILE) 22 | /// 23 | /// # References: 24 | /// - 25 | /// - 26 | /// - 27 | /// - 28 | @since(version = 0.2.0) 29 | create-udp-socket: func(address-family: ip-address-family) -> result; 30 | } 31 | -------------------------------------------------------------------------------- /wit/deps/sockets/udp.wit: -------------------------------------------------------------------------------- 1 | @since(version = 0.2.0) 2 | interface udp { 3 | @since(version = 0.2.0) 4 | use wasi:io/poll@0.2.4.{pollable}; 5 | @since(version = 0.2.0) 6 | use network.{network, error-code, ip-socket-address, ip-address-family}; 7 | 8 | /// A received datagram. 9 | @since(version = 0.2.0) 10 | record incoming-datagram { 11 | /// The payload. 12 | /// 13 | /// Theoretical max size: ~64 KiB. In practice, typically less than 1500 bytes. 14 | data: list, 15 | 16 | /// The source address. 17 | /// 18 | /// This field is guaranteed to match the remote address the stream was initialized with, if any. 19 | /// 20 | /// Equivalent to the `src_addr` out parameter of `recvfrom`. 21 | remote-address: ip-socket-address, 22 | } 23 | 24 | /// A datagram to be sent out. 25 | @since(version = 0.2.0) 26 | record outgoing-datagram { 27 | /// The payload. 28 | data: list, 29 | 30 | /// The destination address. 31 | /// 32 | /// The requirements on this field depend on how the stream was initialized: 33 | /// - with a remote address: this field must be None or match the stream's remote address exactly. 34 | /// - without a remote address: this field is required. 35 | /// 36 | /// If this value is None, the send operation is equivalent to `send` in POSIX. Otherwise it is equivalent to `sendto`. 37 | remote-address: option, 38 | } 39 | 40 | /// A UDP socket handle. 41 | @since(version = 0.2.0) 42 | resource udp-socket { 43 | /// Bind the socket to a specific network on the provided IP address and port. 44 | /// 45 | /// If the IP address is zero (`0.0.0.0` in IPv4, `::` in IPv6), it is left to the implementation to decide which 46 | /// network interface(s) to bind to. 47 | /// If the port is zero, the socket will be bound to a random free port. 48 | /// 49 | /// # Typical errors 50 | /// - `invalid-argument`: The `local-address` has the wrong address family. (EAFNOSUPPORT, EFAULT on Windows) 51 | /// - `invalid-state`: The socket is already bound. (EINVAL) 52 | /// - `address-in-use`: No ephemeral ports available. (EADDRINUSE, ENOBUFS on Windows) 53 | /// - `address-in-use`: Address is already in use. (EADDRINUSE) 54 | /// - `address-not-bindable`: `local-address` is not an address that the `network` can bind to. (EADDRNOTAVAIL) 55 | /// - `not-in-progress`: A `bind` operation is not in progress. 56 | /// - `would-block`: Can't finish the operation, it is still in progress. (EWOULDBLOCK, EAGAIN) 57 | /// 58 | /// # Implementors note 59 | /// Unlike in POSIX, in WASI the bind operation is async. This enables 60 | /// interactive WASI hosts to inject permission prompts. Runtimes that 61 | /// don't want to make use of this ability can simply call the native 62 | /// `bind` as part of either `start-bind` or `finish-bind`. 63 | /// 64 | /// # References 65 | /// - 66 | /// - 67 | /// - 68 | /// - 69 | @since(version = 0.2.0) 70 | start-bind: func(network: borrow, local-address: ip-socket-address) -> result<_, error-code>; 71 | @since(version = 0.2.0) 72 | finish-bind: func() -> result<_, error-code>; 73 | 74 | /// Set up inbound & outbound communication channels, optionally to a specific peer. 75 | /// 76 | /// This function only changes the local socket configuration and does not generate any network traffic. 77 | /// On success, the `remote-address` of the socket is updated. The `local-address` may be updated as well, 78 | /// based on the best network path to `remote-address`. 79 | /// 80 | /// When a `remote-address` is provided, the returned streams are limited to communicating with that specific peer: 81 | /// - `send` can only be used to send to this destination. 82 | /// - `receive` will only return datagrams sent from the provided `remote-address`. 83 | /// 84 | /// This method may be called multiple times on the same socket to change its association, but 85 | /// only the most recently returned pair of streams will be operational. Implementations may trap if 86 | /// the streams returned by a previous invocation haven't been dropped yet before calling `stream` again. 87 | /// 88 | /// The POSIX equivalent in pseudo-code is: 89 | /// ```text 90 | /// if (was previously connected) { 91 | /// connect(s, AF_UNSPEC) 92 | /// } 93 | /// if (remote_address is Some) { 94 | /// connect(s, remote_address) 95 | /// } 96 | /// ``` 97 | /// 98 | /// Unlike in POSIX, the socket must already be explicitly bound. 99 | /// 100 | /// # Typical errors 101 | /// - `invalid-argument`: The `remote-address` has the wrong address family. (EAFNOSUPPORT) 102 | /// - `invalid-argument`: The IP address in `remote-address` is set to INADDR_ANY (`0.0.0.0` / `::`). (EDESTADDRREQ, EADDRNOTAVAIL) 103 | /// - `invalid-argument`: The port in `remote-address` is set to 0. (EDESTADDRREQ, EADDRNOTAVAIL) 104 | /// - `invalid-state`: The socket is not bound. 105 | /// - `address-in-use`: Tried to perform an implicit bind, but there were no ephemeral ports available. (EADDRINUSE, EADDRNOTAVAIL on Linux, EAGAIN on BSD) 106 | /// - `remote-unreachable`: The remote address is not reachable. (ECONNRESET, ENETRESET, EHOSTUNREACH, EHOSTDOWN, ENETUNREACH, ENETDOWN, ENONET) 107 | /// - `connection-refused`: The connection was refused. (ECONNREFUSED) 108 | /// 109 | /// # References 110 | /// - 111 | /// - 112 | /// - 113 | /// - 114 | @since(version = 0.2.0) 115 | %stream: func(remote-address: option) -> result, error-code>; 116 | 117 | /// Get the current bound address. 118 | /// 119 | /// POSIX mentions: 120 | /// > If the socket has not been bound to a local name, the value 121 | /// > stored in the object pointed to by `address` is unspecified. 122 | /// 123 | /// WASI is stricter and requires `local-address` to return `invalid-state` when the socket hasn't been bound yet. 124 | /// 125 | /// # Typical errors 126 | /// - `invalid-state`: The socket is not bound to any local address. 127 | /// 128 | /// # References 129 | /// - 130 | /// - 131 | /// - 132 | /// - 133 | @since(version = 0.2.0) 134 | local-address: func() -> result; 135 | 136 | /// Get the address the socket is currently streaming to. 137 | /// 138 | /// # Typical errors 139 | /// - `invalid-state`: The socket is not streaming to a specific remote address. (ENOTCONN) 140 | /// 141 | /// # References 142 | /// - 143 | /// - 144 | /// - 145 | /// - 146 | @since(version = 0.2.0) 147 | remote-address: func() -> result; 148 | 149 | /// Whether this is a IPv4 or IPv6 socket. 150 | /// 151 | /// Equivalent to the SO_DOMAIN socket option. 152 | @since(version = 0.2.0) 153 | address-family: func() -> ip-address-family; 154 | 155 | /// Equivalent to the IP_TTL & IPV6_UNICAST_HOPS socket options. 156 | /// 157 | /// If the provided value is 0, an `invalid-argument` error is returned. 158 | /// 159 | /// # Typical errors 160 | /// - `invalid-argument`: (set) The TTL value must be 1 or higher. 161 | @since(version = 0.2.0) 162 | unicast-hop-limit: func() -> result; 163 | @since(version = 0.2.0) 164 | set-unicast-hop-limit: func(value: u8) -> result<_, error-code>; 165 | 166 | /// The kernel buffer space reserved for sends/receives on this socket. 167 | /// 168 | /// If the provided value is 0, an `invalid-argument` error is returned. 169 | /// Any other value will never cause an error, but it might be silently clamped and/or rounded. 170 | /// I.e. after setting a value, reading the same setting back may return a different value. 171 | /// 172 | /// Equivalent to the SO_RCVBUF and SO_SNDBUF socket options. 173 | /// 174 | /// # Typical errors 175 | /// - `invalid-argument`: (set) The provided value was 0. 176 | @since(version = 0.2.0) 177 | receive-buffer-size: func() -> result; 178 | @since(version = 0.2.0) 179 | set-receive-buffer-size: func(value: u64) -> result<_, error-code>; 180 | @since(version = 0.2.0) 181 | send-buffer-size: func() -> result; 182 | @since(version = 0.2.0) 183 | set-send-buffer-size: func(value: u64) -> result<_, error-code>; 184 | 185 | /// Create a `pollable` which will resolve once the socket is ready for I/O. 186 | /// 187 | /// Note: this function is here for WASI 0.2 only. 188 | /// It's planned to be removed when `future` is natively supported in Preview3. 189 | @since(version = 0.2.0) 190 | subscribe: func() -> pollable; 191 | } 192 | 193 | @since(version = 0.2.0) 194 | resource incoming-datagram-stream { 195 | /// Receive messages on the socket. 196 | /// 197 | /// This function attempts to receive up to `max-results` datagrams on the socket without blocking. 198 | /// The returned list may contain fewer elements than requested, but never more. 199 | /// 200 | /// This function returns successfully with an empty list when either: 201 | /// - `max-results` is 0, or: 202 | /// - `max-results` is greater than 0, but no results are immediately available. 203 | /// This function never returns `error(would-block)`. 204 | /// 205 | /// # Typical errors 206 | /// - `remote-unreachable`: The remote address is not reachable. (ECONNRESET, ENETRESET on Windows, EHOSTUNREACH, EHOSTDOWN, ENETUNREACH, ENETDOWN, ENONET) 207 | /// - `connection-refused`: The connection was refused. (ECONNREFUSED) 208 | /// 209 | /// # References 210 | /// - 211 | /// - 212 | /// - 213 | /// - 214 | /// - 215 | /// - 216 | /// - 217 | /// - 218 | @since(version = 0.2.0) 219 | receive: func(max-results: u64) -> result, error-code>; 220 | 221 | /// Create a `pollable` which will resolve once the stream is ready to receive again. 222 | /// 223 | /// Note: this function is here for WASI 0.2 only. 224 | /// It's planned to be removed when `future` is natively supported in Preview3. 225 | @since(version = 0.2.0) 226 | subscribe: func() -> pollable; 227 | } 228 | 229 | @since(version = 0.2.0) 230 | resource outgoing-datagram-stream { 231 | /// Check readiness for sending. This function never blocks. 232 | /// 233 | /// Returns the number of datagrams permitted for the next call to `send`, 234 | /// or an error. Calling `send` with more datagrams than this function has 235 | /// permitted will trap. 236 | /// 237 | /// When this function returns ok(0), the `subscribe` pollable will 238 | /// become ready when this function will report at least ok(1), or an 239 | /// error. 240 | /// 241 | /// Never returns `would-block`. 242 | check-send: func() -> result; 243 | 244 | /// Send messages on the socket. 245 | /// 246 | /// This function attempts to send all provided `datagrams` on the socket without blocking and 247 | /// returns how many messages were actually sent (or queued for sending). This function never 248 | /// returns `error(would-block)`. If none of the datagrams were able to be sent, `ok(0)` is returned. 249 | /// 250 | /// This function semantically behaves the same as iterating the `datagrams` list and sequentially 251 | /// sending each individual datagram until either the end of the list has been reached or the first error occurred. 252 | /// If at least one datagram has been sent successfully, this function never returns an error. 253 | /// 254 | /// If the input list is empty, the function returns `ok(0)`. 255 | /// 256 | /// Each call to `send` must be permitted by a preceding `check-send`. Implementations must trap if 257 | /// either `check-send` was not called or `datagrams` contains more items than `check-send` permitted. 258 | /// 259 | /// # Typical errors 260 | /// - `invalid-argument`: The `remote-address` has the wrong address family. (EAFNOSUPPORT) 261 | /// - `invalid-argument`: The IP address in `remote-address` is set to INADDR_ANY (`0.0.0.0` / `::`). (EDESTADDRREQ, EADDRNOTAVAIL) 262 | /// - `invalid-argument`: The port in `remote-address` is set to 0. (EDESTADDRREQ, EADDRNOTAVAIL) 263 | /// - `invalid-argument`: The socket is in "connected" mode and `remote-address` is `some` value that does not match the address passed to `stream`. (EISCONN) 264 | /// - `invalid-argument`: The socket is not "connected" and no value for `remote-address` was provided. (EDESTADDRREQ) 265 | /// - `remote-unreachable`: The remote address is not reachable. (ECONNRESET, ENETRESET on Windows, EHOSTUNREACH, EHOSTDOWN, ENETUNREACH, ENETDOWN, ENONET) 266 | /// - `connection-refused`: The connection was refused. (ECONNREFUSED) 267 | /// - `datagram-too-large`: The datagram is too large. (EMSGSIZE) 268 | /// 269 | /// # References 270 | /// - 271 | /// - 272 | /// - 273 | /// - 274 | /// - 275 | /// - 276 | /// - 277 | /// - 278 | @since(version = 0.2.0) 279 | send: func(datagrams: list) -> result; 280 | 281 | /// Create a `pollable` which will resolve once the stream is ready to send again. 282 | /// 283 | /// Note: this function is here for WASI 0.2 only. 284 | /// It's planned to be removed when `future` is natively supported in Preview3. 285 | @since(version = 0.2.0) 286 | subscribe: func() -> pollable; 287 | } 288 | } 289 | -------------------------------------------------------------------------------- /wit/deps/sockets/world.wit: -------------------------------------------------------------------------------- 1 | package wasi:sockets@0.2.4; 2 | 3 | @since(version = 0.2.0) 4 | world imports { 5 | @since(version = 0.2.0) 6 | import instance-network; 7 | @since(version = 0.2.0) 8 | import network; 9 | @since(version = 0.2.0) 10 | import udp; 11 | @since(version = 0.2.0) 12 | import udp-create-socket; 13 | @since(version = 0.2.0) 14 | import tcp; 15 | @since(version = 0.2.0) 16 | import tcp-create-socket; 17 | @since(version = 0.2.0) 18 | import ip-name-lookup; 19 | } 20 | -------------------------------------------------------------------------------- /wit/wasi-crate.wit: -------------------------------------------------------------------------------- 1 | package rust:wasi; 2 | 3 | world bindings { 4 | include wasi:cli/imports@0.2.4; 5 | import wasi:http/outgoing-handler@0.2.4; 6 | } 7 | --------------------------------------------------------------------------------