├── .github └── workflows │ ├── main.yml │ ├── publish.yml │ └── update.yml ├── LICENSE.md ├── README.md ├── imports.md ├── proxy.md ├── wit-0.3.0-draft ├── deps.lock ├── deps.toml ├── 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 │ ├── random │ │ ├── insecure-seed.wit │ │ ├── insecure.wit │ │ ├── random.wit │ │ └── world.wit │ └── sockets │ │ ├── ip-name-lookup.wit │ │ ├── types.wit │ │ └── world.wit ├── handler.wit ├── proxy.wit └── types.wit └── wit ├── deps.lock ├── deps.toml ├── 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 ├── 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 ├── handler.wit ├── proxy.wit └── types.wit /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | push: 4 | branches: [main] 5 | pull_request: 6 | branches: [main] 7 | 8 | jobs: 9 | abi-up-to-date: 10 | name: Check ABI files are up-to-date 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v4 14 | - name: ensure `./wit/deps` are in sync 15 | run: | 16 | curl -Lo 'wit-deps' https://github.com/bytecodealliance/wit-deps/releases/download/v0.5.0/wit-deps-x86_64-unknown-linux-musl 17 | chmod +x ./wit-deps 18 | ./wit-deps lock --check 19 | ./wit-deps -m wit-0.3.0-draft/deps.toml -l wit-0.3.0-draft/deps.lock -d wit-0.3.0-draft/deps lock --check 20 | - uses: WebAssembly/wit-abi-up-to-date@v23 21 | with: 22 | wasm-tools: '1.223.0' 23 | wit-bindgen: '0.37.0' 24 | worlds: 'imports proxy' 25 | all-features: 'true' 26 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish a Wasm Component package to GitHub Artifacts 2 | 3 | # Run this action whenever a new release is tagged 4 | on: 5 | push: 6 | tags: 7 | - v* 8 | workflow_dispatch: 9 | 10 | env: 11 | IMAGE_NAME: ${{ github.repository }} 12 | 13 | jobs: 14 | publish: 15 | runs-on: ubuntu-latest 16 | permissions: 17 | id-token: write 18 | packages: write 19 | contents: write 20 | 21 | steps: 22 | # Checkout the repo and install dependencies 23 | - name: Checkout repository 24 | uses: actions/checkout@v2 25 | - name: Install cargo-binstall 26 | uses: cargo-bins/cargo-binstall@v1.10.15 27 | - name: Install wkg 28 | shell: bash 29 | run: cargo binstall wkg 30 | - name: Install cosign 31 | uses: sigstore/cosign-installer@v3.7.0 32 | 33 | # To version our image we want to obtain the version from the tag 34 | - name: Get version 35 | id: meta 36 | uses: docker/metadata-action@v5 37 | with: 38 | images: ghcr.io/webassembly/wasi/http 39 | tags: | 40 | type=semver,pattern={{version}} 41 | 42 | # To upload our image to the GitHub registry, we first have to login 43 | - name: Login to the GitHub registry 44 | uses: docker/login-action@v3 45 | with: 46 | registry: ghcr.io 47 | username: ${{ github.actor }} 48 | password: ${{ secrets.ORG_PAT }} 49 | 50 | # Build our `.wit` files into a Wasm binary 51 | - name: Build 52 | shell: bash 53 | run: wkg wit build -o wasi-http.wasm 54 | 55 | # Upload the Wasm binary to the GitHub registry 56 | - name: Publish to GitHub Container Registry 57 | id: publish 58 | uses: bytecodealliance/wkg-github-action@v5 59 | with: 60 | oci-reference-without-tag: 'ghcr.io/webassembly/wasi/http' 61 | file: 'wasi-http.wasm' 62 | description: 'A WASI API for sending and receiving HTTP requests and responses.' 63 | source: 'https://github.com/webassembly/wasi' 64 | homepage: 'https://wasi.dev' 65 | version: ${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.version'] }} 66 | licenses: 'Apache-2.0 WITH LLVM-exception' 67 | 68 | # Sign the output component 69 | - name: Sign the wasm component 70 | run: cosign sign --yes ghcr.io/webassembly/wasi/http@${{ steps.publish.outputs.digest }} 71 | -------------------------------------------------------------------------------- /.github/workflows/update.yml: -------------------------------------------------------------------------------- 1 | name: Create a PR to upgrade WIT to a new version 2 | 3 | # Manually dispatch this action from the Actions page 4 | on: 5 | workflow_dispatch: 6 | inputs: 7 | prev_version: 8 | description: 'Upgrading from version (without the v)' 9 | required: true 10 | type: string 11 | next_version: 12 | description: 'Upgrading to version (without the v)' 13 | required: true 14 | type: string 15 | 16 | permissions: 17 | pull-requests: write 18 | contents: write 19 | 20 | jobs: 21 | update-versions: 22 | runs-on: ubuntu-latest 23 | steps: 24 | # Checkout the repo and install dependencies 25 | - name: Checkout repository 26 | uses: actions/checkout@v4 27 | - name: Install cargo-binstall 28 | uses: cargo-bins/cargo-binstall@v1.10.15 29 | - name: Install wit-bindgen 30 | shell: bash 31 | run: cargo binstall wit-bindgen-cli 32 | - name: Install wit-deps 33 | shell: bash 34 | run: cargo binstall wit-deps-cli 35 | 36 | # echo input 37 | - name: Print the versions 38 | run: echo Upgrading from ${{ inputs.prev_version }} to ${{ inputs.next_version }} 39 | 40 | # upgrade 41 | - name: Upgrade tag 42 | run: find . -type f -name "*.wit" -exec sed -i "s/${{ inputs.prev_version }}/${{ inputs.next_version }}/g" {} + 43 | - name: Upgrade deps tags 44 | run: find . -type f -name "deps.toml" -exec sed -i "s/${{ inputs.prev_version }}/${{ inputs.next_version }}/g" {} + 45 | - name: Upgrade wit deps 46 | run: wit-deps update 47 | - name: Generate markdown for the proxy world 48 | run: wit-bindgen markdown wit -w proxy --html-in-md --features=informational-outbound-responses 49 | - name: Generate markdown for the imports world 50 | run: wit-bindgen markdown wit -w imports --html-in-md --features=informational-outbound-responses 51 | 52 | # file PR 53 | - name: Create feature branch 54 | env: 55 | FEATURE_BRANCH: release-v${{ inputs.next_version }} 56 | run: | 57 | git config user.name "github-actions[bot]" 58 | git config user.email "41898282+github-actions[bot]@users.noreply.github.com" 59 | git add . 60 | git checkout -b $FEATURE_BRANCH 61 | git push -u origin $FEATURE_BRANCH 62 | git commit -m "Update to v${{ inputs.next_version }}" 63 | git push 64 | 65 | - name: Create pull request 66 | run: gh pr create -B main -H release-v${{ inputs.next_version }} --title 'Release v${{ inputs.next_version }}' --body 'Updates the package version to v${{ inputs.next_version }}. Thanks!' 67 | env: 68 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 69 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright © 2019-2024 the Contributors to the WASI Specification, published 2 | by the [WebAssembly Community Group][cg] under the 3 | [W3C Community Contributor License Agreement (CLA)][cla]. A human-readable 4 | [summary][summary] is available. 5 | 6 | [cg]: https://www.w3.org/community/webassembly/ 7 | [cla]: https://www.w3.org/community/about/agreements/cla/ 8 | [summary]: https://www.w3.org/community/about/agreements/cla-deed/ 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WASI HTTP 2 | 3 | A proposed [WebAssembly System Interface](https://github.com/WebAssembly/WASI) API. 4 | 5 | ### Current Phase 6 | 7 | wasi-http is currently in [Phase 3](https://github.com/WebAssembly/WASI/blob/main/Proposals.md#phase-3---implementation-phase-cg--wg) 8 | 9 | ### Champions 10 | 11 | * Piotr Sikora 12 | * Jiaxiao Zhou 13 | * Dan Chiarlone 14 | * David Justice 15 | * Luke Wagner 16 | 17 | ### Portability Criteria 18 | 19 | WASI-http must have at least two complete independent implementations 20 | demonstrating embeddability in a production HTTP server context. 21 | 22 | ### Introduction 23 | 24 | The WASI-http proposal defines a collection of [interfaces] for sending and 25 | receiving HTTP requests and responses. WASI-http additionally defines a 26 | [world], `wasi:http/proxy`, that circumscribes a minimal execution environment 27 | for wasm HTTP [proxies]. 28 | 29 | [Interfaces]: https://github.com/WebAssembly/component-model/blob/main/design/mvp/WIT.md#wit-interfaces 30 | [World]: https://github.com/WebAssembly/component-model/blob/main/design/mvp/WIT.md#wit-worlds 31 | [Proxies]: https://httpwg.org/http-core/draft-ietf-httpbis-semantics-latest.html#intermediaries 32 | 33 | ### Goals 34 | 35 | The proposal intends to abstract over HTTP version and transport protocol 36 | choices (such as HTTP/1.1, HTTP/2 or HTTP/3) by mapping directly to the 37 | abstract [HTTP Semantics], allowing hosts to (mostly) transparently use any of 38 | these. 39 | 40 | The `wasi:http/proxy` world is meant to be implementable by a wide variety of 41 | hosts including Web [service workers], forward- and reverse-[proxies] and 42 | [origin servers] by requiring a minimal set of additional runtime support. 43 | 44 | The `wasi:http/proxy` world is meant to support flexible auto-scaling 45 | ("serverless") execution by moving the core `accept()` loop into the host and 46 | allowing the host to dynamically spin up wasm instances in response to arriving 47 | requests. 48 | 49 | The `wasi:http/proxy` world is meant to allow the chaining of HTTP 50 | intermediaries to be implemented directly in terms of [Component Model] linking. 51 | (Fully realizing this goal will require additional features only available in 52 | the [Preview 3] timeframe.) 53 | 54 | [HTTP Semantics]: https://httpwg.org/http-core/draft-ietf-httpbis-semantics-latest.html 55 | [Service Workers]: https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API 56 | [Origin Servers]: https://httpwg.org/http-core/draft-ietf-httpbis-semantics-latest.html#origin.server 57 | [Component Model]: https://github.com/WebAssembly/component-model/ 58 | [Preview 3]: https://github.com/WebAssembly/WASI/blob/main/docs/WitInWasi.md#streams 59 | 60 | ### Non-goals 61 | 62 | WASI-http does not intend to define a more fully-featured cloud execution 63 | environment (for this, see the [wasi-cloud-core] proposal). 64 | 65 | [wasi-cloud-core]: https://github.com/WebAssembly/wasi-cloud-core 66 | 67 | ### API walk-through 68 | 69 | The proposal can be understood by first reading the comments of [`proxy.wit`], 70 | then [`handler.wit`] and finally [`types.wit`]. 71 | 72 | [`proxy.wit`]: ./wit/proxy.wit 73 | [`handler.wit`]: ./wit/handler.wit 74 | [`types.wit`]: ./wit/types.wit 75 | 76 | ### Working with the WIT 77 | 78 | Bindings can be generated from the `wit` directory via: 79 | ``` 80 | wit-bindgen c wit/ --world proxy 81 | ``` 82 | and can be validated and otherwise manipulated via: 83 | ``` 84 | wasm-tools component wit wit/ ... 85 | ``` 86 | 87 | The `wit/deps` directory contains a live snapshot of the contents of several 88 | other WASI proposals upon which this proposal depends. It is automatically 89 | updated by running [`wit-deps update`](https://crates.io/crates/wit-deps-cli) 90 | in the root directory, which fetches the live contents of the `main` branch of 91 | each proposal. As things stabilize, `wit/deps.toml` will be updated to refer to 92 | versioned releases. 93 | 94 | ### References & acknowledgements 95 | 96 | * This proposal was seeded by and developed in consultation with 97 | [proxy-wasm](https://github.com/proxy-wasm/spec). 98 | 99 | -------------------------------------------------------------------------------- /wit-0.3.0-draft/deps.lock: -------------------------------------------------------------------------------- 1 | [cli] 2 | url = "https://github.com/WebAssembly/wasi-cli/archive/main.tar.gz" 3 | subdir = "wit-0.3.0-draft" 4 | sha256 = "9a94018c67baf2ab4475f23c164514724ca08795195184adb4b38cb8dc5d6f9c" 5 | sha512 = "8d2f3076eb94118c5321fd18dda60c0078087dbcbed57c6b973b8fc2225670045d94a6f70f4f19c0fb0e13bbb0344325d4dce3a48417b97434344d2a2c1371fd" 6 | deps = ["clocks", "filesystem", "random", "sockets"] 7 | 8 | [clocks] 9 | sha256 = "26e315db0d371495f8834edfc0e479042f94152ce677d96d54d3623d0e4ffb1e" 10 | sha512 = "e1c76f499435841316f9287b88d8173558e64f277c321ff390556de8707a0b18dd6c1749bbb17bbbba8d523da246ef6eb05c990ceddb762e03efb2ae30cacc76" 11 | 12 | [filesystem] 13 | sha256 = "f8a82b21e18cad3498b53475666a3f00c4c1b5f030b7ed47c79262e3dbe97461" 14 | sha512 = "0e62fe9ff3ba0572d890a2edd969e88a5c2327279cec681d3f2688ed8442820333f6041b0f0956b44941f971a6afb785bd2f5248ca0c99b51f13521496cadbcc" 15 | 16 | [random] 17 | sha256 = "7a483077cc23fc9dc7a3f067d62795663cceee7dbbd23f205934282b1164a83e" 18 | sha512 = "b99280fd60699f781f20209659e94c0058ce6b9e973ddbd0b8865d752f88c74633485d486d5a86b709385b6e60357470d1c6fbcb3a2769af210c0b1f52417506" 19 | 20 | [sockets] 21 | sha256 = "48fa617cdf64b66adc7136e4f0c14886061e6d5134072bf8e1698b84e2579669" 22 | sha512 = "786b8a03c14d3f529500275762a37c497ea1e6479e71028e8173aa07594beb77226904d77970a7c356ff3f59aa4a5c10f2e68537cc96b9916ff03a317b05a229" 23 | -------------------------------------------------------------------------------- /wit-0.3.0-draft/deps.toml: -------------------------------------------------------------------------------- 1 | cli = { url = "https://github.com/WebAssembly/wasi-cli/archive/main.tar.gz", subdir = "wit-0.3.0-draft" } 2 | -------------------------------------------------------------------------------- /wit-0.3.0-draft/deps/cli/command.wit: -------------------------------------------------------------------------------- 1 | package wasi:cli@0.3.0; 2 | 3 | @since(version = 0.3.0) 4 | world command { 5 | @since(version = 0.3.0) 6 | include imports; 7 | 8 | @since(version = 0.3.0) 9 | export run; 10 | } 11 | -------------------------------------------------------------------------------- /wit-0.3.0-draft/deps/cli/environment.wit: -------------------------------------------------------------------------------- 1 | @since(version = 0.3.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.3.0) 12 | get-environment: func() -> list>; 13 | 14 | /// Get the POSIX-style arguments to the program. 15 | @since(version = 0.3.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.3.0) 21 | initial-cwd: func() -> option; 22 | } 23 | -------------------------------------------------------------------------------- /wit-0.3.0-draft/deps/cli/exit.wit: -------------------------------------------------------------------------------- 1 | @since(version = 0.3.0) 2 | interface exit { 3 | /// Exit the current instance and any linked instances. 4 | @since(version = 0.3.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-0.3.0-draft/deps/cli/imports.wit: -------------------------------------------------------------------------------- 1 | package wasi:cli@0.3.0; 2 | 3 | @since(version = 0.3.0) 4 | world imports { 5 | @since(version = 0.3.0) 6 | include wasi:clocks/imports@0.3.0; 7 | @since(version = 0.3.0) 8 | include wasi:filesystem/imports@0.3.0; 9 | @since(version = 0.3.0) 10 | include wasi:sockets/imports@0.3.0; 11 | @since(version = 0.3.0) 12 | include wasi:random/imports@0.3.0; 13 | 14 | @since(version = 0.3.0) 15 | import environment; 16 | @since(version = 0.3.0) 17 | import exit; 18 | @since(version = 0.3.0) 19 | import stdin; 20 | @since(version = 0.3.0) 21 | import stdout; 22 | @since(version = 0.3.0) 23 | import stderr; 24 | @since(version = 0.3.0) 25 | import terminal-input; 26 | @since(version = 0.3.0) 27 | import terminal-output; 28 | @since(version = 0.3.0) 29 | import terminal-stdin; 30 | @since(version = 0.3.0) 31 | import terminal-stdout; 32 | @since(version = 0.3.0) 33 | import terminal-stderr; 34 | } 35 | -------------------------------------------------------------------------------- /wit-0.3.0-draft/deps/cli/run.wit: -------------------------------------------------------------------------------- 1 | @since(version = 0.3.0) 2 | interface run { 3 | /// Run the program. 4 | @since(version = 0.3.0) 5 | run: func() -> result; 6 | } 7 | -------------------------------------------------------------------------------- /wit-0.3.0-draft/deps/cli/stdio.wit: -------------------------------------------------------------------------------- 1 | @since(version = 0.3.0) 2 | interface stdin { 3 | @since(version = 0.3.0) 4 | get-stdin: func() -> stream; 5 | } 6 | 7 | @since(version = 0.3.0) 8 | interface stdout { 9 | @since(version = 0.3.0) 10 | set-stdout: func(data: stream); 11 | } 12 | 13 | @since(version = 0.3.0) 14 | interface stderr { 15 | @since(version = 0.3.0) 16 | set-stderr: func(data: stream); 17 | } 18 | -------------------------------------------------------------------------------- /wit-0.3.0-draft/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.3.0) 7 | interface terminal-input { 8 | /// The input side of a terminal. 9 | @since(version = 0.3.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.3.0) 19 | interface terminal-output { 20 | /// The output side of a terminal. 21 | @since(version = 0.3.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.3.0) 28 | interface terminal-stdin { 29 | @since(version = 0.3.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.3.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.3.0) 41 | interface terminal-stdout { 42 | @since(version = 0.3.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.3.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.3.0) 54 | interface terminal-stderr { 55 | @since(version = 0.3.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.3.0) 61 | get-terminal-stderr: func() -> option; 62 | } 63 | -------------------------------------------------------------------------------- /wit-0.3.0-draft/deps/clocks/monotonic-clock.wit: -------------------------------------------------------------------------------- 1 | package wasi:clocks@0.3.0; 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.3.0) 11 | interface monotonic-clock { 12 | /// An instant in time, in nanoseconds. An instant is relative to an 13 | /// unspecified initial value, and can only be compared to instances from 14 | /// the same monotonic-clock. 15 | @since(version = 0.3.0) 16 | type instant = u64; 17 | 18 | /// A duration of time, in nanoseconds. 19 | @since(version = 0.3.0) 20 | type duration = u64; 21 | 22 | /// Read the current value of the clock. 23 | /// 24 | /// The clock is monotonic, therefore calling this function repeatedly will 25 | /// produce a sequence of non-decreasing values. 26 | @since(version = 0.3.0) 27 | now: func() -> instant; 28 | 29 | /// Query the resolution of the clock. Returns the duration of time 30 | /// corresponding to a clock tick. 31 | @since(version = 0.3.0) 32 | resolution: func() -> duration; 33 | 34 | /// Wait until the specified instant has occurred. 35 | @since(version = 0.3.0) 36 | wait-until: func( 37 | when: instant, 38 | ); 39 | 40 | /// Wait for the specified duration has elapsed. 41 | @since(version = 0.3.0) 42 | wait-for: func( 43 | how-long: duration, 44 | ); 45 | } 46 | -------------------------------------------------------------------------------- /wit-0.3.0-draft/deps/clocks/timezone.wit: -------------------------------------------------------------------------------- 1 | package wasi:clocks@0.3.0; 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-0.3.0-draft/deps/clocks/wall-clock.wit: -------------------------------------------------------------------------------- 1 | package wasi:clocks@0.3.0; 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.3.0) 17 | interface wall-clock { 18 | /// A time and date in seconds plus nanoseconds. 19 | @since(version = 0.3.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.3.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.3.0) 45 | resolution: func() -> datetime; 46 | } 47 | -------------------------------------------------------------------------------- /wit-0.3.0-draft/deps/clocks/world.wit: -------------------------------------------------------------------------------- 1 | package wasi:clocks@0.3.0; 2 | 3 | @since(version = 0.3.0) 4 | world imports { 5 | @since(version = 0.3.0) 6 | import monotonic-clock; 7 | @since(version = 0.3.0) 8 | import wall-clock; 9 | @unstable(feature = clocks-timezone) 10 | import timezone; 11 | } 12 | -------------------------------------------------------------------------------- /wit-0.3.0-draft/deps/filesystem/preopens.wit: -------------------------------------------------------------------------------- 1 | package wasi:filesystem@0.3.0; 2 | 3 | @since(version = 0.3.0) 4 | interface preopens { 5 | @since(version = 0.3.0) 6 | use types.{descriptor}; 7 | 8 | /// Return the set of preopened directories, and their paths. 9 | @since(version = 0.3.0) 10 | get-directories: func() -> list>; 11 | } 12 | -------------------------------------------------------------------------------- /wit-0.3.0-draft/deps/filesystem/types.wit: -------------------------------------------------------------------------------- 1 | package wasi:filesystem@0.3.0; 2 | /// WASI filesystem is a filesystem API primarily intended to let users run WASI 3 | /// programs that access their files on their existing filesystems, without 4 | /// significant overhead. 5 | /// 6 | /// It is intended to be roughly portable between Unix-family platforms and 7 | /// Windows, though it does not hide many of the major differences. 8 | /// 9 | /// Paths are passed as interface-type `string`s, meaning they must consist of 10 | /// a sequence of Unicode Scalar Values (USVs). Some filesystems may contain 11 | /// paths which are not accessible by this API. 12 | /// 13 | /// The directory separator in WASI is always the forward-slash (`/`). 14 | /// 15 | /// All paths in WASI are relative paths, and are interpreted relative to a 16 | /// `descriptor` referring to a base directory. If a `path` argument to any WASI 17 | /// function starts with `/`, or if any step of resolving a `path`, including 18 | /// `..` and symbolic link steps, reaches a directory outside of the base 19 | /// directory, or reaches a symlink to an absolute or rooted path in the 20 | /// underlying filesystem, the function fails with `error-code::not-permitted`. 21 | /// 22 | /// For more information about WASI path resolution and sandboxing, see 23 | /// [WASI filesystem path resolution]. 24 | /// 25 | /// [WASI filesystem path resolution]: https://github.com/WebAssembly/wasi-filesystem/blob/main/path-resolution.md 26 | @since(version = 0.3.0) 27 | interface types { 28 | @since(version = 0.3.0) 29 | use wasi:clocks/wall-clock@0.3.0.{datetime}; 30 | 31 | /// File size or length of a region within a file. 32 | @since(version = 0.3.0) 33 | type filesize = u64; 34 | 35 | /// The type of a filesystem object referenced by a descriptor. 36 | /// 37 | /// Note: This was called `filetype` in earlier versions of WASI. 38 | @since(version = 0.3.0) 39 | enum descriptor-type { 40 | /// The type of the descriptor or file is unknown or is different from 41 | /// any of the other types specified. 42 | unknown, 43 | /// The descriptor refers to a block device inode. 44 | block-device, 45 | /// The descriptor refers to a character device inode. 46 | character-device, 47 | /// The descriptor refers to a directory inode. 48 | directory, 49 | /// The descriptor refers to a named pipe. 50 | fifo, 51 | /// The file refers to a symbolic link inode. 52 | symbolic-link, 53 | /// The descriptor refers to a regular file inode. 54 | regular-file, 55 | /// The descriptor refers to a socket. 56 | socket, 57 | } 58 | 59 | /// Descriptor flags. 60 | /// 61 | /// Note: This was called `fdflags` in earlier versions of WASI. 62 | @since(version = 0.3.0) 63 | flags descriptor-flags { 64 | /// Read mode: Data can be read. 65 | read, 66 | /// Write mode: Data can be written to. 67 | write, 68 | /// Request that writes be performed according to synchronized I/O file 69 | /// integrity completion. The data stored in the file and the file's 70 | /// metadata are synchronized. This is similar to `O_SYNC` in POSIX. 71 | /// 72 | /// The precise semantics of this operation have not yet been defined for 73 | /// WASI. At this time, it should be interpreted as a request, and not a 74 | /// requirement. 75 | file-integrity-sync, 76 | /// Request that writes be performed according to synchronized I/O data 77 | /// integrity completion. Only the data stored in the file is 78 | /// synchronized. This is similar to `O_DSYNC` in POSIX. 79 | /// 80 | /// The precise semantics of this operation have not yet been defined for 81 | /// WASI. At this time, it should be interpreted as a request, and not a 82 | /// requirement. 83 | data-integrity-sync, 84 | /// Requests that reads be performed at the same level of integrity 85 | /// requested for writes. This is similar to `O_RSYNC` in POSIX. 86 | /// 87 | /// The precise semantics of this operation have not yet been defined for 88 | /// WASI. At this time, it should be interpreted as a request, and not a 89 | /// requirement. 90 | requested-write-sync, 91 | /// Mutating directories mode: Directory contents may be mutated. 92 | /// 93 | /// When this flag is unset on a descriptor, operations using the 94 | /// descriptor which would create, rename, delete, modify the data or 95 | /// metadata of filesystem objects, or obtain another handle which 96 | /// would permit any of those, shall fail with `error-code::read-only` if 97 | /// they would otherwise succeed. 98 | /// 99 | /// This may only be set on directories. 100 | mutate-directory, 101 | } 102 | 103 | /// File attributes. 104 | /// 105 | /// Note: This was called `filestat` in earlier versions of WASI. 106 | @since(version = 0.3.0) 107 | record descriptor-stat { 108 | /// File type. 109 | %type: descriptor-type, 110 | /// Number of hard links to the file. 111 | link-count: link-count, 112 | /// For regular files, the file size in bytes. For symbolic links, the 113 | /// length in bytes of the pathname contained in the symbolic link. 114 | size: filesize, 115 | /// Last data access timestamp. 116 | /// 117 | /// If the `option` is none, the platform doesn't maintain an access 118 | /// timestamp for this file. 119 | data-access-timestamp: option, 120 | /// Last data modification timestamp. 121 | /// 122 | /// If the `option` is none, the platform doesn't maintain a 123 | /// modification timestamp for this file. 124 | data-modification-timestamp: option, 125 | /// Last file status-change timestamp. 126 | /// 127 | /// If the `option` is none, the platform doesn't maintain a 128 | /// status-change timestamp for this file. 129 | status-change-timestamp: option, 130 | } 131 | 132 | /// Flags determining the method of how paths are resolved. 133 | @since(version = 0.3.0) 134 | flags path-flags { 135 | /// As long as the resolved path corresponds to a symbolic link, it is 136 | /// expanded. 137 | symlink-follow, 138 | } 139 | 140 | /// Open flags used by `open-at`. 141 | @since(version = 0.3.0) 142 | flags open-flags { 143 | /// Create file if it does not exist, similar to `O_CREAT` in POSIX. 144 | create, 145 | /// Fail if not a directory, similar to `O_DIRECTORY` in POSIX. 146 | directory, 147 | /// Fail if file already exists, similar to `O_EXCL` in POSIX. 148 | exclusive, 149 | /// Truncate file to size 0, similar to `O_TRUNC` in POSIX. 150 | truncate, 151 | } 152 | 153 | /// Number of hard links to an inode. 154 | @since(version = 0.3.0) 155 | type link-count = u64; 156 | 157 | /// When setting a timestamp, this gives the value to set it to. 158 | @since(version = 0.3.0) 159 | variant new-timestamp { 160 | /// Leave the timestamp set to its previous value. 161 | no-change, 162 | /// Set the timestamp to the current time of the system clock associated 163 | /// with the filesystem. 164 | now, 165 | /// Set the timestamp to the given value. 166 | timestamp(datetime), 167 | } 168 | 169 | /// A directory entry. 170 | record directory-entry { 171 | /// The type of the file referred to by this directory entry. 172 | %type: descriptor-type, 173 | 174 | /// The name of the object. 175 | name: string, 176 | } 177 | 178 | /// Error codes returned by functions, similar to `errno` in POSIX. 179 | /// Not all of these error codes are returned by the functions provided by this 180 | /// API; some are used in higher-level library layers, and others are provided 181 | /// merely for alignment with POSIX. 182 | enum error-code { 183 | /// Permission denied, similar to `EACCES` in POSIX. 184 | access, 185 | /// Connection already in progress, similar to `EALREADY` in POSIX. 186 | already, 187 | /// Bad descriptor, similar to `EBADF` in POSIX. 188 | bad-descriptor, 189 | /// Device or resource busy, similar to `EBUSY` in POSIX. 190 | busy, 191 | /// Resource deadlock would occur, similar to `EDEADLK` in POSIX. 192 | deadlock, 193 | /// Storage quota exceeded, similar to `EDQUOT` in POSIX. 194 | quota, 195 | /// File exists, similar to `EEXIST` in POSIX. 196 | exist, 197 | /// File too large, similar to `EFBIG` in POSIX. 198 | file-too-large, 199 | /// Illegal byte sequence, similar to `EILSEQ` in POSIX. 200 | illegal-byte-sequence, 201 | /// Operation in progress, similar to `EINPROGRESS` in POSIX. 202 | in-progress, 203 | /// Interrupted function, similar to `EINTR` in POSIX. 204 | interrupted, 205 | /// Invalid argument, similar to `EINVAL` in POSIX. 206 | invalid, 207 | /// I/O error, similar to `EIO` in POSIX. 208 | io, 209 | /// Is a directory, similar to `EISDIR` in POSIX. 210 | is-directory, 211 | /// Too many levels of symbolic links, similar to `ELOOP` in POSIX. 212 | loop, 213 | /// Too many links, similar to `EMLINK` in POSIX. 214 | too-many-links, 215 | /// Message too large, similar to `EMSGSIZE` in POSIX. 216 | message-size, 217 | /// Filename too long, similar to `ENAMETOOLONG` in POSIX. 218 | name-too-long, 219 | /// No such device, similar to `ENODEV` in POSIX. 220 | no-device, 221 | /// No such file or directory, similar to `ENOENT` in POSIX. 222 | no-entry, 223 | /// No locks available, similar to `ENOLCK` in POSIX. 224 | no-lock, 225 | /// Not enough space, similar to `ENOMEM` in POSIX. 226 | insufficient-memory, 227 | /// No space left on device, similar to `ENOSPC` in POSIX. 228 | insufficient-space, 229 | /// Not a directory or a symbolic link to a directory, similar to `ENOTDIR` in POSIX. 230 | not-directory, 231 | /// Directory not empty, similar to `ENOTEMPTY` in POSIX. 232 | not-empty, 233 | /// State not recoverable, similar to `ENOTRECOVERABLE` in POSIX. 234 | not-recoverable, 235 | /// Not supported, similar to `ENOTSUP` and `ENOSYS` in POSIX. 236 | unsupported, 237 | /// Inappropriate I/O control operation, similar to `ENOTTY` in POSIX. 238 | no-tty, 239 | /// No such device or address, similar to `ENXIO` in POSIX. 240 | no-such-device, 241 | /// Value too large to be stored in data type, similar to `EOVERFLOW` in POSIX. 242 | overflow, 243 | /// Operation not permitted, similar to `EPERM` in POSIX. 244 | not-permitted, 245 | /// Broken pipe, similar to `EPIPE` in POSIX. 246 | pipe, 247 | /// Read-only file system, similar to `EROFS` in POSIX. 248 | read-only, 249 | /// Invalid seek, similar to `ESPIPE` in POSIX. 250 | invalid-seek, 251 | /// Text file busy, similar to `ETXTBSY` in POSIX. 252 | text-file-busy, 253 | /// Cross-device link, similar to `EXDEV` in POSIX. 254 | cross-device, 255 | } 256 | 257 | /// File or memory access pattern advisory information. 258 | @since(version = 0.3.0) 259 | enum advice { 260 | /// The application has no advice to give on its behavior with respect 261 | /// to the specified data. 262 | normal, 263 | /// The application expects to access the specified data sequentially 264 | /// from lower offsets to higher offsets. 265 | sequential, 266 | /// The application expects to access the specified data in a random 267 | /// order. 268 | random, 269 | /// The application expects to access the specified data in the near 270 | /// future. 271 | will-need, 272 | /// The application expects that it will not access the specified data 273 | /// in the near future. 274 | dont-need, 275 | /// The application expects to access the specified data once and then 276 | /// not reuse it thereafter. 277 | no-reuse, 278 | } 279 | 280 | /// A 128-bit hash value, split into parts because wasm doesn't have a 281 | /// 128-bit integer type. 282 | @since(version = 0.3.0) 283 | record metadata-hash-value { 284 | /// 64 bits of a 128-bit hash value. 285 | lower: u64, 286 | /// Another 64 bits of a 128-bit hash value. 287 | upper: u64, 288 | } 289 | 290 | /// A descriptor is a reference to a filesystem object, which may be a file, 291 | /// directory, named pipe, special file, or other object on which filesystem 292 | /// calls may be made. 293 | @since(version = 0.3.0) 294 | resource descriptor { 295 | /// Return a stream for reading from a file. 296 | /// 297 | /// Multiple read, write, and append streams may be active on the same open 298 | /// file and they do not interfere with each other. 299 | /// 300 | /// This function returns a future, which will resolve to an error code if 301 | /// reading full contents of the file fails. 302 | /// 303 | /// Note: This is similar to `pread` in POSIX. 304 | @since(version = 0.3.0) 305 | read-via-stream: func( 306 | /// The offset within the file at which to start reading. 307 | offset: filesize, 308 | ) -> tuple, future>>; 309 | 310 | /// Return a stream for writing to a file, if available. 311 | /// 312 | /// May fail with an error-code describing why the file cannot be written. 313 | /// 314 | /// It is valid to write past the end of a file; the file is extended to the 315 | /// extent of the write, with bytes between the previous end and the start of 316 | /// the write set to zero. 317 | /// 318 | /// This function returns once either full contents of the stream are 319 | /// written or an error is encountered. 320 | /// 321 | /// Note: This is similar to `pwrite` in POSIX. 322 | @since(version = 0.3.0) 323 | write-via-stream: func( 324 | /// Data to write 325 | data: stream, 326 | /// The offset within the file at which to start writing. 327 | offset: filesize, 328 | ) -> result<_, error-code>; 329 | 330 | /// Return a stream for appending to a file, if available. 331 | /// 332 | /// May fail with an error-code describing why the file cannot be appended. 333 | /// 334 | /// This function returns once either full contents of the stream are 335 | /// written or an error is encountered. 336 | /// 337 | /// Note: This is similar to `write` with `O_APPEND` in POSIX. 338 | @since(version = 0.3.0) 339 | append-via-stream: func(data: stream) -> result<_, error-code>; 340 | 341 | /// Provide file advisory information on a descriptor. 342 | /// 343 | /// This is similar to `posix_fadvise` in POSIX. 344 | @since(version = 0.3.0) 345 | advise: func( 346 | /// The offset within the file to which the advisory applies. 347 | offset: filesize, 348 | /// The length of the region to which the advisory applies. 349 | length: filesize, 350 | /// The advice. 351 | advice: advice 352 | ) -> result<_, error-code>; 353 | 354 | /// Synchronize the data of a file to disk. 355 | /// 356 | /// This function succeeds with no effect if the file descriptor is not 357 | /// opened for writing. 358 | /// 359 | /// Note: This is similar to `fdatasync` in POSIX. 360 | @since(version = 0.3.0) 361 | sync-data: func() -> result<_, error-code>; 362 | 363 | /// Get flags associated with a descriptor. 364 | /// 365 | /// Note: This returns similar flags to `fcntl(fd, F_GETFL)` in POSIX. 366 | /// 367 | /// Note: This returns the value that was the `fs_flags` value returned 368 | /// from `fdstat_get` in earlier versions of WASI. 369 | @since(version = 0.3.0) 370 | get-flags: func() -> result; 371 | 372 | /// Get the dynamic type of a descriptor. 373 | /// 374 | /// Note: This returns the same value as the `type` field of the `fd-stat` 375 | /// returned by `stat`, `stat-at` and similar. 376 | /// 377 | /// Note: This returns similar flags to the `st_mode & S_IFMT` value provided 378 | /// by `fstat` in POSIX. 379 | /// 380 | /// Note: This returns the value that was the `fs_filetype` value returned 381 | /// from `fdstat_get` in earlier versions of WASI. 382 | @since(version = 0.3.0) 383 | get-type: func() -> result; 384 | 385 | /// Adjust the size of an open file. If this increases the file's size, the 386 | /// extra bytes are filled with zeros. 387 | /// 388 | /// Note: This was called `fd_filestat_set_size` in earlier versions of WASI. 389 | @since(version = 0.3.0) 390 | set-size: func(size: filesize) -> result<_, error-code>; 391 | 392 | /// Adjust the timestamps of an open file or directory. 393 | /// 394 | /// Note: This is similar to `futimens` in POSIX. 395 | /// 396 | /// Note: This was called `fd_filestat_set_times` in earlier versions of WASI. 397 | @since(version = 0.3.0) 398 | set-times: func( 399 | /// The desired values of the data access timestamp. 400 | data-access-timestamp: new-timestamp, 401 | /// The desired values of the data modification timestamp. 402 | data-modification-timestamp: new-timestamp, 403 | ) -> result<_, error-code>; 404 | 405 | /// Read directory entries from a directory. 406 | /// 407 | /// On filesystems where directories contain entries referring to themselves 408 | /// and their parents, often named `.` and `..` respectively, these entries 409 | /// are omitted. 410 | /// 411 | /// This always returns a new stream which starts at the beginning of the 412 | /// directory. Multiple streams may be active on the same directory, and they 413 | /// do not interfere with each other. 414 | /// 415 | /// This function returns a future, which will resolve to an error code if 416 | /// reading full contents of the directory fails. 417 | @since(version = 0.3.0) 418 | read-directory: func() -> tuple, future>>; 419 | 420 | /// Synchronize the data and metadata of a file to disk. 421 | /// 422 | /// This function succeeds with no effect if the file descriptor is not 423 | /// opened for writing. 424 | /// 425 | /// Note: This is similar to `fsync` in POSIX. 426 | @since(version = 0.3.0) 427 | sync: func() -> result<_, error-code>; 428 | 429 | /// Create a directory. 430 | /// 431 | /// Note: This is similar to `mkdirat` in POSIX. 432 | @since(version = 0.3.0) 433 | create-directory-at: func( 434 | /// The relative path at which to create the directory. 435 | path: string, 436 | ) -> result<_, error-code>; 437 | 438 | /// Return the attributes of an open file or directory. 439 | /// 440 | /// Note: This is similar to `fstat` in POSIX, except that it does not return 441 | /// device and inode information. For testing whether two descriptors refer to 442 | /// the same underlying filesystem object, use `is-same-object`. To obtain 443 | /// additional data that can be used do determine whether a file has been 444 | /// modified, use `metadata-hash`. 445 | /// 446 | /// Note: This was called `fd_filestat_get` in earlier versions of WASI. 447 | @since(version = 0.3.0) 448 | stat: func() -> result; 449 | 450 | /// Return the attributes of a file or directory. 451 | /// 452 | /// Note: This is similar to `fstatat` in POSIX, except that it does not 453 | /// return device and inode information. See the `stat` description for a 454 | /// discussion of alternatives. 455 | /// 456 | /// Note: This was called `path_filestat_get` in earlier versions of WASI. 457 | @since(version = 0.3.0) 458 | stat-at: func( 459 | /// Flags determining the method of how the path is resolved. 460 | path-flags: path-flags, 461 | /// The relative path of the file or directory to inspect. 462 | path: string, 463 | ) -> result; 464 | 465 | /// Adjust the timestamps of a file or directory. 466 | /// 467 | /// Note: This is similar to `utimensat` in POSIX. 468 | /// 469 | /// Note: This was called `path_filestat_set_times` in earlier versions of 470 | /// WASI. 471 | @since(version = 0.3.0) 472 | set-times-at: func( 473 | /// Flags determining the method of how the path is resolved. 474 | path-flags: path-flags, 475 | /// The relative path of the file or directory to operate on. 476 | path: string, 477 | /// The desired values of the data access timestamp. 478 | data-access-timestamp: new-timestamp, 479 | /// The desired values of the data modification timestamp. 480 | data-modification-timestamp: new-timestamp, 481 | ) -> result<_, error-code>; 482 | 483 | /// Create a hard link. 484 | /// 485 | /// Fails with `error-code::no-entry` if the old path does not exist, 486 | /// with `error-code::exist` if the new path already exists, and 487 | /// `error-code::not-permitted` if the old path is not a file. 488 | /// 489 | /// Note: This is similar to `linkat` in POSIX. 490 | @since(version = 0.3.0) 491 | link-at: func( 492 | /// Flags determining the method of how the path is resolved. 493 | old-path-flags: path-flags, 494 | /// The relative source path from which to link. 495 | old-path: string, 496 | /// The base directory for `new-path`. 497 | new-descriptor: borrow, 498 | /// The relative destination path at which to create the hard link. 499 | new-path: string, 500 | ) -> result<_, error-code>; 501 | 502 | /// Open a file or directory. 503 | /// 504 | /// If `flags` contains `descriptor-flags::mutate-directory`, and the base 505 | /// descriptor doesn't have `descriptor-flags::mutate-directory` set, 506 | /// `open-at` fails with `error-code::read-only`. 507 | /// 508 | /// If `flags` contains `write` or `mutate-directory`, or `open-flags` 509 | /// contains `truncate` or `create`, and the base descriptor doesn't have 510 | /// `descriptor-flags::mutate-directory` set, `open-at` fails with 511 | /// `error-code::read-only`. 512 | /// 513 | /// Note: This is similar to `openat` in POSIX. 514 | @since(version = 0.3.0) 515 | open-at: func( 516 | /// Flags determining the method of how the path is resolved. 517 | path-flags: path-flags, 518 | /// The relative path of the object to open. 519 | path: string, 520 | /// The method by which to open the file. 521 | open-flags: open-flags, 522 | /// Flags to use for the resulting descriptor. 523 | %flags: descriptor-flags, 524 | ) -> result; 525 | 526 | /// Read the contents of a symbolic link. 527 | /// 528 | /// If the contents contain an absolute or rooted path in the underlying 529 | /// filesystem, this function fails with `error-code::not-permitted`. 530 | /// 531 | /// Note: This is similar to `readlinkat` in POSIX. 532 | @since(version = 0.3.0) 533 | readlink-at: func( 534 | /// The relative path of the symbolic link from which to read. 535 | path: string, 536 | ) -> result; 537 | 538 | /// Remove a directory. 539 | /// 540 | /// Return `error-code::not-empty` if the directory is not empty. 541 | /// 542 | /// Note: This is similar to `unlinkat(fd, path, AT_REMOVEDIR)` in POSIX. 543 | @since(version = 0.3.0) 544 | remove-directory-at: func( 545 | /// The relative path to a directory to remove. 546 | path: string, 547 | ) -> result<_, error-code>; 548 | 549 | /// Rename a filesystem object. 550 | /// 551 | /// Note: This is similar to `renameat` in POSIX. 552 | @since(version = 0.3.0) 553 | rename-at: func( 554 | /// The relative source path of the file or directory to rename. 555 | old-path: string, 556 | /// The base directory for `new-path`. 557 | new-descriptor: borrow, 558 | /// The relative destination path to which to rename the file or directory. 559 | new-path: string, 560 | ) -> result<_, error-code>; 561 | 562 | /// Create a symbolic link (also known as a "symlink"). 563 | /// 564 | /// If `old-path` starts with `/`, the function fails with 565 | /// `error-code::not-permitted`. 566 | /// 567 | /// Note: This is similar to `symlinkat` in POSIX. 568 | @since(version = 0.3.0) 569 | symlink-at: func( 570 | /// The contents of the symbolic link. 571 | old-path: string, 572 | /// The relative destination path at which to create the symbolic link. 573 | new-path: string, 574 | ) -> result<_, error-code>; 575 | 576 | /// Unlink a filesystem object that is not a directory. 577 | /// 578 | /// Return `error-code::is-directory` if the path refers to a directory. 579 | /// Note: This is similar to `unlinkat(fd, path, 0)` in POSIX. 580 | @since(version = 0.3.0) 581 | unlink-file-at: func( 582 | /// The relative path to a file to unlink. 583 | path: string, 584 | ) -> result<_, error-code>; 585 | 586 | /// Test whether two descriptors refer to the same filesystem object. 587 | /// 588 | /// In POSIX, this corresponds to testing whether the two descriptors have the 589 | /// same device (`st_dev`) and inode (`st_ino` or `d_ino`) numbers. 590 | /// wasi-filesystem does not expose device and inode numbers, so this function 591 | /// may be used instead. 592 | @since(version = 0.3.0) 593 | is-same-object: func(other: borrow) -> bool; 594 | 595 | /// Return a hash of the metadata associated with a filesystem object referred 596 | /// to by a descriptor. 597 | /// 598 | /// This returns a hash of the last-modification timestamp and file size, and 599 | /// may also include the inode number, device number, birth timestamp, and 600 | /// other metadata fields that may change when the file is modified or 601 | /// replaced. It may also include a secret value chosen by the 602 | /// implementation and not otherwise exposed. 603 | /// 604 | /// Implementations are encouraged to provide the following properties: 605 | /// 606 | /// - If the file is not modified or replaced, the computed hash value should 607 | /// usually not change. 608 | /// - If the object is modified or replaced, the computed hash value should 609 | /// usually change. 610 | /// - The inputs to the hash should not be easily computable from the 611 | /// computed hash. 612 | /// 613 | /// However, none of these is required. 614 | @since(version = 0.3.0) 615 | metadata-hash: func() -> result; 616 | 617 | /// Return a hash of the metadata associated with a filesystem object referred 618 | /// to by a directory descriptor and a relative path. 619 | /// 620 | /// This performs the same hash computation as `metadata-hash`. 621 | @since(version = 0.3.0) 622 | metadata-hash-at: func( 623 | /// Flags determining the method of how the path is resolved. 624 | path-flags: path-flags, 625 | /// The relative path of the file or directory to inspect. 626 | path: string, 627 | ) -> result; 628 | } 629 | } 630 | -------------------------------------------------------------------------------- /wit-0.3.0-draft/deps/filesystem/world.wit: -------------------------------------------------------------------------------- 1 | package wasi:filesystem@0.3.0; 2 | 3 | @since(version = 0.3.0) 4 | world imports { 5 | @since(version = 0.3.0) 6 | import types; 7 | @since(version = 0.3.0) 8 | import preopens; 9 | } 10 | -------------------------------------------------------------------------------- /wit-0.3.0-draft/deps/random/insecure-seed.wit: -------------------------------------------------------------------------------- 1 | package wasi:random@0.3.0; 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.3.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.3.0) 26 | insecure-seed: func() -> tuple; 27 | } 28 | -------------------------------------------------------------------------------- /wit-0.3.0-draft/deps/random/insecure.wit: -------------------------------------------------------------------------------- 1 | package wasi:random@0.3.0; 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.3.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.3.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.3.0) 24 | get-insecure-random-u64: func() -> u64; 25 | } 26 | -------------------------------------------------------------------------------- /wit-0.3.0-draft/deps/random/random.wit: -------------------------------------------------------------------------------- 1 | package wasi:random@0.3.0; 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.3.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.3.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.3.0) 28 | get-random-u64: func() -> u64; 29 | } 30 | -------------------------------------------------------------------------------- /wit-0.3.0-draft/deps/random/world.wit: -------------------------------------------------------------------------------- 1 | package wasi:random@0.3.0; 2 | 3 | @since(version = 0.3.0) 4 | world imports { 5 | @since(version = 0.3.0) 6 | import random; 7 | 8 | @since(version = 0.3.0) 9 | import insecure; 10 | 11 | @since(version = 0.3.0) 12 | import insecure-seed; 13 | } 14 | -------------------------------------------------------------------------------- /wit-0.3.0-draft/deps/sockets/ip-name-lookup.wit: -------------------------------------------------------------------------------- 1 | @since(version = 0.3.0) 2 | interface ip-name-lookup { 3 | @since(version = 0.3.0) 4 | use types.{ip-address}; 5 | 6 | /// Lookup error codes. 7 | @since(version = 0.3.0) 8 | enum error-code { 9 | /// Unknown error 10 | unknown, 11 | 12 | /// Access denied. 13 | /// 14 | /// POSIX equivalent: EACCES, EPERM 15 | access-denied, 16 | 17 | /// `name` is a syntactically invalid domain name or IP address. 18 | /// 19 | /// POSIX equivalent: EINVAL 20 | invalid-argument, 21 | 22 | /// Name does not exist or has no suitable associated IP addresses. 23 | /// 24 | /// POSIX equivalent: EAI_NONAME, EAI_NODATA, EAI_ADDRFAMILY 25 | name-unresolvable, 26 | 27 | /// A temporary failure in name resolution occurred. 28 | /// 29 | /// POSIX equivalent: EAI_AGAIN 30 | temporary-resolver-failure, 31 | 32 | /// A permanent failure in name resolution occurred. 33 | /// 34 | /// POSIX equivalent: EAI_FAIL 35 | permanent-resolver-failure, 36 | } 37 | 38 | /// Resolve an internet host name to a list of IP addresses. 39 | /// 40 | /// Unicode domain names are automatically converted to ASCII using IDNA encoding. 41 | /// If the input is an IP address string, the address is parsed and returned 42 | /// as-is without making any external requests. 43 | /// 44 | /// See the wasi-socket proposal README.md for a comparison with getaddrinfo. 45 | /// 46 | /// The results are returned in connection order preference. 47 | /// 48 | /// This function never succeeds with 0 results. It either fails or succeeds 49 | /// with at least one address. Additionally, this function never returns 50 | /// IPv4-mapped IPv6 addresses. 51 | /// 52 | /// The returned future will resolve to an error code in case of failure. 53 | /// It will resolve to success once the returned stream is exhausted. 54 | /// 55 | /// # References: 56 | /// - 57 | /// - 58 | /// - 59 | /// - 60 | @since(version = 0.3.0) 61 | resolve-addresses: func(name: string) -> result, error-code>; 62 | } 63 | -------------------------------------------------------------------------------- /wit-0.3.0-draft/deps/sockets/world.wit: -------------------------------------------------------------------------------- 1 | package wasi:sockets@0.3.0; 2 | 3 | @since(version = 0.3.0) 4 | world imports { 5 | @since(version = 0.3.0) 6 | import types; 7 | @since(version = 0.3.0) 8 | import ip-name-lookup; 9 | } 10 | -------------------------------------------------------------------------------- /wit-0.3.0-draft/handler.wit: -------------------------------------------------------------------------------- 1 | /// This interface defines a handler of HTTP Requests. It may be imported by 2 | /// components which wish to send HTTP Requests and also exported by components 3 | /// which can respond to HTTP Requests. In addition, it may be used to pass 4 | /// a request from one component to another without any use of a network. 5 | interface handler { 6 | use types.{request, response, error-code}; 7 | 8 | /// When exported, this function may be called with either an incoming 9 | /// request read from the network or a request synthesized or forwarded by 10 | /// another component. 11 | /// 12 | /// When imported, this function may be used to either send an outgoing 13 | /// request over the network or pass it to another component. 14 | handle: func( 15 | request: request, 16 | ) -> result; 17 | } 18 | -------------------------------------------------------------------------------- /wit-0.3.0-draft/proxy.wit: -------------------------------------------------------------------------------- 1 | package wasi:http@0.3.0-draft; 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 | world imports { 6 | /// HTTP proxies have access to time and randomness. 7 | include wasi:clocks/imports@0.3.0; 8 | import wasi:random/random@0.3.0; 9 | 10 | /// Proxies have standard output and error streams which are expected to 11 | /// terminate in a developer-facing console provided by the host. 12 | import wasi:cli/stdout@0.3.0; 13 | import wasi:cli/stderr@0.3.0; 14 | 15 | /// TODO: this is a temporary workaround until component tooling is able to 16 | /// gracefully handle the absence of stdin. Hosts must return an eof stream 17 | /// for this import, which is what wasi-libc + tooling will do automatically 18 | /// when this import is properly removed. 19 | import wasi:cli/stdin@0.3.0; 20 | 21 | /// This is the default handler to use when user code simply wants to make an 22 | /// HTTP request (e.g., via `fetch()`). 23 | /// 24 | /// This may also be used to pass synthesized or forwarded requests to another 25 | /// component. 26 | import handler; 27 | } 28 | 29 | /// The `wasi:http/proxy` world captures a widely-implementable intersection of 30 | /// hosts that includes HTTP forward and reverse proxies. Components targeting 31 | /// this world may concurrently stream in and out any number of incoming and 32 | /// outgoing HTTP requests. 33 | world proxy { 34 | include imports; 35 | 36 | /// The host delivers incoming HTTP requests to a component by calling the 37 | /// `handle` function of this exported interface. A host may arbitrarily reuse 38 | /// or not reuse component instance when delivering incoming HTTP requests and 39 | /// thus a component must be able to handle 0..N calls to `handle`. 40 | /// 41 | /// This may also be used to receive synthesized or forwarded requests from 42 | /// another component. 43 | export handler; 44 | } 45 | -------------------------------------------------------------------------------- /wit-0.3.0-draft/types.wit: -------------------------------------------------------------------------------- 1 | /// This interface defines all of the types and methods for implementing HTTP 2 | /// Requests and Responses, as well as their headers, trailers, and bodies. 3 | interface types { 4 | use wasi:clocks/monotonic-clock@0.3.0.{duration}; 5 | 6 | /// This type corresponds to HTTP standard Methods. 7 | variant method { 8 | get, 9 | head, 10 | post, 11 | put, 12 | delete, 13 | connect, 14 | options, 15 | trace, 16 | patch, 17 | other(string) 18 | } 19 | 20 | /// This type corresponds to HTTP standard Related Schemes. 21 | variant scheme { 22 | HTTP, 23 | HTTPS, 24 | other(string) 25 | } 26 | 27 | /// These cases are inspired by the IANA HTTP Proxy Error Types: 28 | /// 29 | variant error-code { 30 | DNS-timeout, 31 | DNS-error(DNS-error-payload), 32 | destination-not-found, 33 | destination-unavailable, 34 | destination-IP-prohibited, 35 | destination-IP-unroutable, 36 | connection-refused, 37 | connection-terminated, 38 | connection-timeout, 39 | connection-read-timeout, 40 | connection-write-timeout, 41 | connection-limit-reached, 42 | TLS-protocol-error, 43 | TLS-certificate-error, 44 | TLS-alert-received(TLS-alert-received-payload), 45 | HTTP-request-denied, 46 | HTTP-request-length-required, 47 | HTTP-request-body-size(option), 48 | HTTP-request-method-invalid, 49 | HTTP-request-URI-invalid, 50 | HTTP-request-URI-too-long, 51 | HTTP-request-header-section-size(option), 52 | HTTP-request-header-size(option), 53 | HTTP-request-trailer-section-size(option), 54 | HTTP-request-trailer-size(field-size-payload), 55 | HTTP-response-incomplete, 56 | HTTP-response-header-section-size(option), 57 | HTTP-response-header-size(field-size-payload), 58 | HTTP-response-body-size(option), 59 | HTTP-response-trailer-section-size(option), 60 | HTTP-response-trailer-size(field-size-payload), 61 | HTTP-response-transfer-coding(option), 62 | HTTP-response-content-coding(option), 63 | HTTP-response-timeout, 64 | HTTP-upgrade-failed, 65 | HTTP-protocol-error, 66 | loop-detected, 67 | configuration-error, 68 | /// This is a catch-all error for anything that doesn't fit cleanly into a 69 | /// more specific case. It also includes an optional string for an 70 | /// unstructured description of the error. Users should not depend on the 71 | /// string for diagnosing errors, as it's not required to be consistent 72 | /// between implementations. 73 | internal-error(option) 74 | } 75 | 76 | /// Defines the case payload type for `DNS-error` above: 77 | record DNS-error-payload { 78 | rcode: option, 79 | info-code: option 80 | } 81 | 82 | /// Defines the case payload type for `TLS-alert-received` above: 83 | record TLS-alert-received-payload { 84 | alert-id: option, 85 | alert-message: option 86 | } 87 | 88 | /// Defines the case payload type for `HTTP-response-{header,trailer}-size` above: 89 | record field-size-payload { 90 | field-name: option, 91 | field-size: option 92 | } 93 | 94 | /// This type enumerates the different kinds of errors that may occur when 95 | /// setting or appending to a `fields` resource. 96 | variant header-error { 97 | /// This error indicates that a `field-name` or `field-value` was 98 | /// syntactically invalid when used with an operation that sets headers in a 99 | /// `fields`. 100 | invalid-syntax, 101 | 102 | /// This error indicates that a forbidden `field-name` was used when trying 103 | /// to set a header in a `fields`. 104 | forbidden, 105 | 106 | /// This error indicates that the operation on the `fields` was not 107 | /// permitted because the fields are immutable. 108 | immutable, 109 | } 110 | 111 | /// This type enumerates the different kinds of errors that may occur when 112 | /// setting fields of a `request-options` resource. 113 | variant request-options-error { 114 | /// Indicates the specified field is not supported by this implementation. 115 | not-supported, 116 | 117 | /// Indicates that the operation on the `request-options` was not permitted 118 | /// because it is immutable. 119 | immutable, 120 | } 121 | 122 | /// Field names are always strings. 123 | /// 124 | /// Field names should always be treated as case insensitive by the `fields` 125 | /// resource for the purposes of equality checking. 126 | type field-name = string; 127 | 128 | /// Field values should always be ASCII strings. However, in 129 | /// reality, HTTP implementations often have to interpret malformed values, 130 | /// so they are provided as a list of bytes. 131 | type field-value = list; 132 | 133 | /// This following block defines the `fields` resource which corresponds to 134 | /// HTTP standard Fields. Fields are a common representation used for both 135 | /// Headers and Trailers. 136 | /// 137 | /// A `fields` may be mutable or immutable. A `fields` created using the 138 | /// constructor, `from-list`, or `clone` will be mutable, but a `fields` 139 | /// resource given by other means (including, but not limited to, 140 | /// `request.headers`) might be be immutable. In an immutable fields, the 141 | /// `set`, `append`, and `delete` operations will fail with 142 | /// `header-error.immutable`. 143 | /// 144 | /// A `fields` resource should store `field-name`s and `field-value`s in their 145 | /// original casing used to construct or mutate the `fields` resource. The `fields` 146 | /// resource should use that original casing when serializing the fields for 147 | /// transport or when returning them from a method. 148 | resource fields { 149 | 150 | /// Construct an empty HTTP Fields. 151 | /// 152 | /// The resulting `fields` is mutable. 153 | constructor(); 154 | 155 | /// Construct an HTTP Fields. 156 | /// 157 | /// The resulting `fields` is mutable. 158 | /// 159 | /// The list represents each name-value pair in the Fields. Names 160 | /// which have multiple values are represented by multiple entries in this 161 | /// list with the same name. 162 | /// 163 | /// The tuple is a pair of the field name, represented as a string, and 164 | /// Value, represented as a list of bytes. In a valid Fields, all names 165 | /// and values are valid UTF-8 strings. However, values are not always 166 | /// well-formed, so they are represented as a raw list of bytes. 167 | /// 168 | /// An error result will be returned if any header or value was 169 | /// syntactically invalid, or if a header was forbidden. 170 | from-list: static func( 171 | entries: list> 172 | ) -> result; 173 | 174 | /// Get all of the values corresponding to a name. If the name is not present 175 | /// in this `fields`, an empty list is returned. However, if the name is 176 | /// present but empty, this is represented by a list with one or more 177 | /// empty field-values present. 178 | get: func(name: field-name) -> list; 179 | 180 | /// Returns `true` when the name is present in this `fields`. If the name is 181 | /// syntactically invalid, `false` is returned. 182 | has: func(name: field-name) -> bool; 183 | 184 | /// Set all of the values for a name. Clears any existing values for that 185 | /// name, if they have been set. 186 | /// 187 | /// Fails with `header-error.immutable` if the `fields` are immutable. 188 | set: func(name: field-name, value: list) -> result<_, header-error>; 189 | 190 | /// Delete all values for a name. Does nothing if no values for the name 191 | /// exist. 192 | /// 193 | /// Fails with `header-error.immutable` if the `fields` are immutable. 194 | delete: func(name: field-name) -> result<_, header-error>; 195 | 196 | /// Delete all values for a name. Does nothing if no values for the name 197 | /// exist. 198 | /// 199 | /// Returns all values previously corresponding to the name, if any. 200 | /// 201 | /// Fails with `header-error.immutable` if the `fields` are immutable. 202 | get-and-delete: func(name: field-name) -> result, header-error>; 203 | 204 | /// Append a value for a name. Does not change or delete any existing 205 | /// values for that name. 206 | /// 207 | /// Fails with `header-error.immutable` if the `fields` are immutable. 208 | append: func(name: field-name, value: field-value) -> result<_, header-error>; 209 | 210 | /// Retrieve the full set of names and values in the Fields. Like the 211 | /// constructor, the list represents each name-value pair. 212 | /// 213 | /// The outer list represents each name-value pair in the Fields. Names 214 | /// which have multiple values are represented by multiple entries in this 215 | /// list with the same name. 216 | /// 217 | /// The names and values are always returned in the original casing and in 218 | /// the order in which they will be serialized for transport. 219 | entries: func() -> list>; 220 | 221 | /// Make a deep copy of the Fields. Equivalent in behavior to calling the 222 | /// `fields` constructor on the return value of `entries`. The resulting 223 | /// `fields` is mutable. 224 | clone: func() -> fields; 225 | } 226 | 227 | /// Headers is an alias for Fields. 228 | type headers = fields; 229 | 230 | /// Trailers is an alias for Fields. 231 | type trailers = fields; 232 | 233 | /// Represents an HTTP Request. 234 | resource request { 235 | 236 | /// Construct a new `request` with a default `method` of `GET`, and 237 | /// `none` values for `path-with-query`, `scheme`, and `authority`. 238 | /// 239 | /// `headers` is the HTTP Headers for the Request. 240 | /// 241 | /// `contents` is the optional body content stream with `none` 242 | /// representing a zero-length content stream. 243 | /// Once it is closed, `trailers` future must resolve to a result. 244 | /// If `trailers` resolves to an error, underlying connection 245 | /// will be closed immediately. 246 | /// 247 | /// `options` is optional `request-options` resource to be used 248 | /// if the request is sent over a network connection. 249 | /// 250 | /// It is possible to construct, or manipulate with the accessor functions 251 | /// below, a `request` with an invalid combination of `scheme` 252 | /// and `authority`, or `headers` which are not permitted to be sent. 253 | /// It is the obligation of the `handler.handle` implementation 254 | /// to reject invalid constructions of `request`. 255 | /// 256 | /// The returned future resolves to result of transmission of this request. 257 | new: static func( 258 | headers: headers, 259 | contents: option>, 260 | trailers: future, error-code>>, 261 | options: option 262 | ) -> tuple>>; 263 | 264 | /// Get the Method for the Request. 265 | method: func() -> method; 266 | /// Set the Method for the Request. Fails if the string present in a 267 | /// `method.other` argument is not a syntactically valid method. 268 | set-method: func(method: method) -> result; 269 | 270 | /// Get the combination of the HTTP Path and Query for the Request. When 271 | /// `none`, this represents an empty Path and empty Query. 272 | path-with-query: func() -> option; 273 | /// Set the combination of the HTTP Path and Query for the Request. When 274 | /// `none`, this represents an empty Path and empty Query. Fails is the 275 | /// string given is not a syntactically valid path and query uri component. 276 | set-path-with-query: func(path-with-query: option) -> result; 277 | 278 | /// Get the HTTP Related Scheme for the Request. When `none`, the 279 | /// implementation may choose an appropriate default scheme. 280 | scheme: func() -> option; 281 | /// Set the HTTP Related Scheme for the Request. When `none`, the 282 | /// implementation may choose an appropriate default scheme. Fails if the 283 | /// string given is not a syntactically valid uri scheme. 284 | set-scheme: func(scheme: option) -> result; 285 | 286 | /// Get the authority of the Request's target URI. A value of `none` may be used 287 | /// with Related Schemes which do not require an authority. The HTTP and 288 | /// HTTPS schemes always require an authority. 289 | authority: func() -> option; 290 | /// Set the authority of the Request's target URI. A value of `none` may be used 291 | /// with Related Schemes which do not require an authority. The HTTP and 292 | /// HTTPS schemes always require an authority. Fails if the string given is 293 | /// not a syntactically valid URI authority. 294 | set-authority: func(authority: option) -> result; 295 | 296 | /// Get the `request-options` to be associated with this request 297 | /// 298 | /// The returned `request-options` resource is immutable: `set-*` operations 299 | /// will fail if invoked. 300 | /// 301 | /// This `request-options` resource is a child: it must be dropped before 302 | /// the parent `request` is dropped, or its ownership is transferred to 303 | /// another component by e.g. `handler.handle`. 304 | options: func() -> option; 305 | 306 | /// Get the headers associated with the Request. 307 | /// 308 | /// The returned `headers` resource is immutable: `set`, `append`, and 309 | /// `delete` operations will fail with `header-error.immutable`. 310 | headers: func() -> headers; 311 | 312 | /// Get body of the Request. 313 | /// 314 | /// Stream returned by this method represents the contents of the body. 315 | /// Once the stream is reported as closed, callers should await the returned future 316 | /// to determine whether the body was received successfully. 317 | /// The future will only resolve after the stream is reported as closed. 318 | /// 319 | /// The stream and future returned by this method are children: 320 | /// they should be closed or consumed before the parent `response` 321 | /// is dropped, or its ownership is transferred to another component 322 | /// by e.g. `handler.handle`. 323 | /// 324 | /// This method may be called multiple times. 325 | /// 326 | /// This method will return an error if it is called while either: 327 | /// - a stream or future returned by a previous call to this method is still open 328 | /// - a stream returned by a previous call to this method has reported itself as closed 329 | /// Thus there will always be at most one readable stream open for a given body. 330 | /// Each subsequent stream picks up where the last stream left off, up until it is finished. 331 | body: func() -> result, future, error-code>>>>; 332 | } 333 | 334 | /// Parameters for making an HTTP Request. Each of these parameters is 335 | /// currently an optional timeout applicable to the transport layer of the 336 | /// HTTP protocol. 337 | /// 338 | /// These timeouts are separate from any the user may use to bound an 339 | /// asynchronous call. 340 | resource request-options { 341 | /// Construct a default `request-options` value. 342 | constructor(); 343 | 344 | /// The timeout for the initial connect to the HTTP Server. 345 | connect-timeout: func() -> option; 346 | 347 | /// Set the timeout for the initial connect to the HTTP Server. An error 348 | /// return value indicates that this timeout is not supported or that this 349 | /// handle is immutable. 350 | set-connect-timeout: func(duration: option) -> result<_, request-options-error>; 351 | 352 | /// The timeout for receiving the first byte of the Response body. 353 | first-byte-timeout: func() -> option; 354 | 355 | /// Set the timeout for receiving the first byte of the Response body. An 356 | /// error return value indicates that this timeout is not supported or that 357 | /// this handle is immutable. 358 | set-first-byte-timeout: func(duration: option) -> result<_, request-options-error>; 359 | 360 | /// The timeout for receiving subsequent chunks of bytes in the Response 361 | /// body stream. 362 | between-bytes-timeout: func() -> option; 363 | 364 | /// Set the timeout for receiving subsequent chunks of bytes in the Response 365 | /// body stream. An error return value indicates that this timeout is not 366 | /// supported or that this handle is immutable. 367 | set-between-bytes-timeout: func(duration: option) -> result<_, request-options-error>; 368 | 369 | /// Make a deep copy of the `request-options`. 370 | /// The resulting `request-options` is mutable. 371 | clone: func() -> request-options; 372 | } 373 | 374 | /// This type corresponds to the HTTP standard Status Code. 375 | type status-code = u16; 376 | 377 | /// Represents an HTTP Response. 378 | resource response { 379 | 380 | /// Construct a new `response`, with a default `status-code` of `200`. 381 | /// If a different `status-code` is needed, it must be set via the 382 | /// `set-status-code` method. 383 | /// 384 | /// `headers` is the HTTP Headers for the Response. 385 | /// 386 | /// `contents` is the optional body content stream with `none` 387 | /// representing a zero-length content stream. 388 | /// Once it is closed, `trailers` future must resolve to a result. 389 | /// If `trailers` resolves to an error, underlying connection 390 | /// will be closed immediately. 391 | /// 392 | /// The returned future resolves to result of transmission of this response. 393 | new: static func( 394 | headers: headers, 395 | contents: option>, 396 | trailers: future, error-code>>, 397 | ) -> tuple>>; 398 | 399 | /// Get the HTTP Status Code for the Response. 400 | status-code: func() -> status-code; 401 | 402 | /// Set the HTTP Status Code for the Response. Fails if the status-code 403 | /// given is not a valid http status code. 404 | set-status-code: func(status-code: status-code) -> result; 405 | 406 | /// Get the headers associated with the Response. 407 | /// 408 | /// The returned `headers` resource is immutable: `set`, `append`, and 409 | /// `delete` operations will fail with `header-error.immutable`. 410 | headers: func() -> headers; 411 | 412 | /// Get body of the Response. 413 | /// 414 | /// Stream returned by this method represents the contents of the body. 415 | /// Once the stream is reported as closed, callers should await the returned future 416 | /// to determine whether the body was received successfully. 417 | /// The future will only resolve after the stream is reported as closed. 418 | /// 419 | /// The stream and future returned by this method are children: 420 | /// they should be closed or consumed before the parent `response` 421 | /// is dropped, or its ownership is transferred to another component 422 | /// by e.g. `handler.handle`. 423 | /// 424 | /// This method may be called multiple times. 425 | /// 426 | /// This method will return an error if it is called while either: 427 | /// - a stream or future returned by a previous call to this method is still open 428 | /// - a stream returned by a previous call to this method has reported itself as closed 429 | /// Thus there will always be at most one readable stream open for a given body. 430 | /// Each subsequent stream picks up where the last stream left off, up until it is finished. 431 | body: func() -> result, future, error-code>>>>; 432 | } 433 | } 434 | -------------------------------------------------------------------------------- /wit/deps.lock: -------------------------------------------------------------------------------- 1 | [cli] 2 | url = "https://github.com/WebAssembly/wasi-cli/archive/v0.2.5.tar.gz" 3 | sha256 = "b65ce8f20c1cfcb874a0083a589c77408188b641a1dfa12cd76158195844f5bd" 4 | sha512 = "f6ce6a3416aa359111f2bf187d23459eef128c623e492f5c56da81099b8fd4bbd6db7274d0093fd70ae9077c812e58e5b221e55e68cd1e815b63b69334789ed8" 5 | deps = ["clocks", "filesystem", "io", "random", "sockets"] 6 | 7 | [clocks] 8 | sha256 = "f1c53079469e20167e2cd4300651f13f34a6fd508b5c7331bb7c8c95fb8857fb" 9 | sha512 = "2a9281d0edcabad3bfef0dcfa7a9712d6beb6d6bb07b29fbf24235706d149672901ffc32192404a1ac511c512eb775daf9716ad3a0514bdf6a5c93a5fed19450" 10 | 11 | [filesystem] 12 | sha256 = "9122d926d1e9c8c3c1aca0b54fcc6a64fe3b52b701d266af5ecbb7f83124a647" 13 | sha512 = "a8e81ca42f4ff9d58dca945cabbcdf04b7a9870b7acd3bb95c95e40bb656e74c7e190f73cf0b3189b6b01a78f3aaa2e247c215541a7a0f67fb86ed3e0b3f9e35" 14 | 15 | [io] 16 | sha256 = "749de54c05f7118dc118999ad69c5b63890ea1dd86f1be69270062195c7b79c2" 17 | sha512 = "b5096d518a7931c100594b9216bb4a98cd64533166bc7fdbb7465b48effc345863bd3ce2ec84fef59b273bae507edab08ec08975d56240ccef68f2494964e80a" 18 | 19 | [random] 20 | sha256 = "c59984d9385d1ef7af6dd817b3d7a0a7f4084baa66c92026d6f9bf1eaf29169a" 21 | sha512 = "7414a1a0616e42ff134ad15b65d9e10bc3b567b34f7f696356e20bc71bcb85ea16188d26d1997ba7e6964df9493f9f748304acaf1169e16ee21a035d8a8b4a89" 22 | 23 | [sockets] 24 | sha256 = "1e55b9b6aa43e02cc0a674e7e6250f5145d48ffbc60c0f200b5ea192dce61640" 25 | sha512 = "019224bb6fead5b6b687aeba7505ed05ebf20b9a60d045a4ab4fc323d0044af729b983b44efbe7ac8e0efda727f5c779fb0ad817c7802b2d7677196cf2cc0652" 26 | -------------------------------------------------------------------------------- /wit/deps.toml: -------------------------------------------------------------------------------- 1 | cli = "https://github.com/WebAssembly/wasi-cli/archive/v0.2.5.tar.gz" 2 | -------------------------------------------------------------------------------- /wit/deps/cli/command.wit: -------------------------------------------------------------------------------- 1 | package wasi:cli@0.2.5; 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.5; 2 | 3 | @since(version = 0.2.0) 4 | world imports { 5 | @since(version = 0.2.0) 6 | include wasi:clocks/imports@0.2.5; 7 | @since(version = 0.2.0) 8 | include wasi:filesystem/imports@0.2.5; 9 | @since(version = 0.2.0) 10 | include wasi:sockets/imports@0.2.5; 11 | @since(version = 0.2.0) 12 | include wasi:random/imports@0.2.5; 13 | @since(version = 0.2.0) 14 | include wasi:io/imports@0.2.5; 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.5.{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.5.{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.5.{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.5; 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.5.{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.5; 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.5; 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.5; 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.5; 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.5; 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/io/error.wit: -------------------------------------------------------------------------------- 1 | package wasi:io@0.2.5; 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.5; 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.5; 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.5; 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.5; 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.5; 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.5; 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.5; 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.5.{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.5.{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.5.{input-stream, output-stream}; 5 | @since(version = 0.2.0) 6 | use wasi:io/poll@0.2.5.{pollable}; 7 | @since(version = 0.2.0) 8 | use wasi:clocks/monotonic-clock@0.2.5.{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.5.{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.5; 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/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/proxy.wit: -------------------------------------------------------------------------------- 1 | package wasi:http@0.2.5; 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.5; 10 | @since(version = 0.2.0) 11 | import wasi:clocks/wall-clock@0.2.5; 12 | @since(version = 0.2.0) 13 | import wasi:random/random@0.2.5; 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.5; 19 | @since(version = 0.2.0) 20 | import wasi:cli/stderr@0.2.5; 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.5; 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/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.5.{duration}; 8 | @since(version = 0.2.0) 9 | use wasi:io/streams@0.2.5.{input-stream, output-stream}; 10 | @since(version = 0.2.0) 11 | use wasi:io/error@0.2.5.{error as io-error}; 12 | @since(version = 0.2.0) 13 | use wasi:io/poll@0.2.5.{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 | --------------------------------------------------------------------------------