From 391f4fb27ef0d98578f32cfb639d54e5285ac119 Mon Sep 17 00:00:00 2001
From: Joel Dice
Date: Thu, 7 Mar 2024 16:42:51 -0700
Subject: [PATCH 1/2] add draft of wasi:http@0.3.0
This adds a `wit-0.3.0-draft` directory so we can iterate on the 0.3.0 design in
parallel with the 0.2.x work. It's currently an exact copy of the `wit`
directory except for the `handler.wit`, `proxy.wit`, and `types.wit` files,
which have been updated to assume Component Model async, `stream`s, and
`future`s are available.
High level description:
- The incoming-handler and outgoing-handler interfaces have been combined into a single handler interface.
- The incoming- and outgoing- variations of request, response, and body have been combined.
- I've added a option field to request since it would be awkward to leave it as a parameter of handler.handle (e.g. what would it mean to receive such a parameter for an incoming request or for a request passed from one component to the other without any use of the network?).
- I've added a request-options-error (analogous to header-error) to distinguish between unsupported fields and immutable handles.
- We use `stream` and `future` where appropriate.
You can find a working implementation of this API, plus several examples, in the
[isyswasfa](https://github.com/dicej/isyswasfa) repository.
Signed-off-by: Joel Dice
---
wit-0.3.0-draft/deps.lock | 29 +
wit-0.3.0-draft/deps.toml | 7 +
wit-0.3.0-draft/deps/cli/command.wit | 7 +
wit-0.3.0-draft/deps/cli/environment.wit | 18 +
wit-0.3.0-draft/deps/cli/exit.wit | 4 +
wit-0.3.0-draft/deps/cli/imports.wit | 20 +
wit-0.3.0-draft/deps/cli/run.wit | 4 +
wit-0.3.0-draft/deps/cli/stdio.wit | 17 +
wit-0.3.0-draft/deps/cli/terminal.wit | 49 ++
.../deps/clocks/monotonic-clock.wit | 45 ++
wit-0.3.0-draft/deps/clocks/wall-clock.wit | 42 ++
wit-0.3.0-draft/deps/clocks/world.wit | 6 +
wit-0.3.0-draft/deps/filesystem/preopens.wit | 8 +
wit-0.3.0-draft/deps/filesystem/types.wit | 634 ++++++++++++++++++
wit-0.3.0-draft/deps/filesystem/world.wit | 6 +
wit-0.3.0-draft/deps/io/error.wit | 34 +
wit-0.3.0-draft/deps/io/poll.wit | 41 ++
wit-0.3.0-draft/deps/io/streams.wit | 262 ++++++++
wit-0.3.0-draft/deps/io/world.wit | 6 +
wit-0.3.0-draft/deps/random/insecure-seed.wit | 25 +
wit-0.3.0-draft/deps/random/insecure.wit | 22 +
wit-0.3.0-draft/deps/random/random.wit | 26 +
wit-0.3.0-draft/deps/random/world.wit | 7 +
.../deps/sockets/instance-network.wit | 9 +
.../deps/sockets/ip-name-lookup.wit | 51 ++
wit-0.3.0-draft/deps/sockets/network.wit | 145 ++++
.../deps/sockets/tcp-create-socket.wit | 27 +
wit-0.3.0-draft/deps/sockets/tcp.wit | 353 ++++++++++
.../deps/sockets/udp-create-socket.wit | 27 +
wit-0.3.0-draft/deps/sockets/udp.wit | 266 ++++++++
wit-0.3.0-draft/deps/sockets/world.wit | 11 +
wit-0.3.0-draft/handler.wit | 17 +
wit-0.3.0-draft/proxy.wit | 44 ++
wit-0.3.0-draft/types.wit | 423 ++++++++++++
34 files changed, 2692 insertions(+)
create mode 100644 wit-0.3.0-draft/deps.lock
create mode 100644 wit-0.3.0-draft/deps.toml
create mode 100644 wit-0.3.0-draft/deps/cli/command.wit
create mode 100644 wit-0.3.0-draft/deps/cli/environment.wit
create mode 100644 wit-0.3.0-draft/deps/cli/exit.wit
create mode 100644 wit-0.3.0-draft/deps/cli/imports.wit
create mode 100644 wit-0.3.0-draft/deps/cli/run.wit
create mode 100644 wit-0.3.0-draft/deps/cli/stdio.wit
create mode 100644 wit-0.3.0-draft/deps/cli/terminal.wit
create mode 100644 wit-0.3.0-draft/deps/clocks/monotonic-clock.wit
create mode 100644 wit-0.3.0-draft/deps/clocks/wall-clock.wit
create mode 100644 wit-0.3.0-draft/deps/clocks/world.wit
create mode 100644 wit-0.3.0-draft/deps/filesystem/preopens.wit
create mode 100644 wit-0.3.0-draft/deps/filesystem/types.wit
create mode 100644 wit-0.3.0-draft/deps/filesystem/world.wit
create mode 100644 wit-0.3.0-draft/deps/io/error.wit
create mode 100644 wit-0.3.0-draft/deps/io/poll.wit
create mode 100644 wit-0.3.0-draft/deps/io/streams.wit
create mode 100644 wit-0.3.0-draft/deps/io/world.wit
create mode 100644 wit-0.3.0-draft/deps/random/insecure-seed.wit
create mode 100644 wit-0.3.0-draft/deps/random/insecure.wit
create mode 100644 wit-0.3.0-draft/deps/random/random.wit
create mode 100644 wit-0.3.0-draft/deps/random/world.wit
create mode 100644 wit-0.3.0-draft/deps/sockets/instance-network.wit
create mode 100644 wit-0.3.0-draft/deps/sockets/ip-name-lookup.wit
create mode 100644 wit-0.3.0-draft/deps/sockets/network.wit
create mode 100644 wit-0.3.0-draft/deps/sockets/tcp-create-socket.wit
create mode 100644 wit-0.3.0-draft/deps/sockets/tcp.wit
create mode 100644 wit-0.3.0-draft/deps/sockets/udp-create-socket.wit
create mode 100644 wit-0.3.0-draft/deps/sockets/udp.wit
create mode 100644 wit-0.3.0-draft/deps/sockets/world.wit
create mode 100644 wit-0.3.0-draft/handler.wit
create mode 100644 wit-0.3.0-draft/proxy.wit
create mode 100644 wit-0.3.0-draft/types.wit
diff --git a/wit-0.3.0-draft/deps.lock b/wit-0.3.0-draft/deps.lock
new file mode 100644
index 0000000..96be4b2
--- /dev/null
+++ b/wit-0.3.0-draft/deps.lock
@@ -0,0 +1,29 @@
+[cli]
+url = "https://github.com/WebAssembly/wasi-cli/archive/main.tar.gz"
+sha256 = "285865a31d777181b075f39e92bcfe59c89cd6bacce660be1b9a627646956258"
+sha512 = "da2622210a9e3eea82b99f1a5b8a44ce5443d009cb943f7bca0bf9cf4360829b289913d7ee727c011f0f72994ea7dc8e661ebcc0a6b34b587297d80cd9b3f7e8"
+
+[clocks]
+url = "https://github.com/WebAssembly/wasi-clocks/archive/main.tar.gz"
+sha256 = "468b4d12892fe926b8eb5d398dbf579d566c93231fa44f415440572c695b7613"
+sha512 = "e6b53a07221f1413953c9797c68f08b815fdaebf66419bbc1ea3e8b7dece73731062693634731f311a03957b268cf9cc509c518bd15e513c318aa04a8459b93a"
+
+[filesystem]
+url = "https://github.com/WebAssembly/wasi-filesystem/archive/main.tar.gz"
+sha256 = "498c465cfd04587db40f970fff2185daa597d074c20b68a8bcbae558f261499b"
+sha512 = "ead452f9b7bfb88593a502ec00d76d4228003d51c40fd0408aebc32d35c94673551b00230d730873361567cc209ec218c41fb4e95bad194268592c49e7964347"
+
+[io]
+url = "https://github.com/WebAssembly/wasi-io/archive/main.tar.gz"
+sha256 = "7210e5653539a15478f894d4da24cc69d61924cbcba21d2804d69314a88e5a4c"
+sha512 = "49184a1b0945a889abd52d25271172ed3dc2db6968fcdddb1bab7ee0081f4a3eeee0977ad2291126a37631c0d86eeea75d822fa8af224c422134500bf9f0f2bb"
+
+[random]
+url = "https://github.com/WebAssembly/wasi-random/archive/main.tar.gz"
+sha256 = "7371d03c037d924caba2587fb2e7c5773a0d3c5fcecbf7971e0e0ba57973c53d"
+sha512 = "964c4e8925a53078e4d94ba907b54f89a0b7e154f46823a505391471466c17f53c8692682e5c85771712acd88b348686173fc07c53a3cfe3d301b8cd8ddd0de4"
+
+[sockets]
+url = "https://github.com/WebAssembly/wasi-sockets/archive/main.tar.gz"
+sha256 = "622bd28bbeb43736375dc02bd003fd3a016ff8ee91e14bab488325c6b38bf966"
+sha512 = "5a63c1f36de0c4548e1d2297bdbededb28721cbad94ef7825c469eae29d7451c97e00b4c1d6730ee1ec0c4a5aac922961a2795762d4a0c3bb54e30a391a84bae"
diff --git a/wit-0.3.0-draft/deps.toml b/wit-0.3.0-draft/deps.toml
new file mode 100644
index 0000000..dd738ac
--- /dev/null
+++ b/wit-0.3.0-draft/deps.toml
@@ -0,0 +1,7 @@
+io = "https://github.com/WebAssembly/wasi-io/archive/main.tar.gz"
+cli = "https://github.com/WebAssembly/wasi-cli/archive/main.tar.gz"
+random = "https://github.com/WebAssembly/wasi-random/archive/main.tar.gz"
+clocks = "https://github.com/WebAssembly/wasi-clocks/archive/main.tar.gz"
+# not used by http/proxy, but included to allow full contents of wasi-cli to validate
+filesystem = "https://github.com/WebAssembly/wasi-filesystem/archive/main.tar.gz"
+sockets = "https://github.com/WebAssembly/wasi-sockets/archive/main.tar.gz"
diff --git a/wit-0.3.0-draft/deps/cli/command.wit b/wit-0.3.0-draft/deps/cli/command.wit
new file mode 100644
index 0000000..d8005bd
--- /dev/null
+++ b/wit-0.3.0-draft/deps/cli/command.wit
@@ -0,0 +1,7 @@
+package wasi:cli@0.2.0;
+
+world command {
+ include imports;
+
+ export run;
+}
diff --git a/wit-0.3.0-draft/deps/cli/environment.wit b/wit-0.3.0-draft/deps/cli/environment.wit
new file mode 100644
index 0000000..7006523
--- /dev/null
+++ b/wit-0.3.0-draft/deps/cli/environment.wit
@@ -0,0 +1,18 @@
+interface environment {
+ /// Get the POSIX-style environment variables.
+ ///
+ /// Each environment variable is provided as a pair of string variable names
+ /// and string value.
+ ///
+ /// Morally, these are a value import, but until value imports are available
+ /// in the component model, this import function should return the same
+ /// values each time it is called.
+ get-environment: func() -> list>;
+
+ /// Get the POSIX-style arguments to the program.
+ get-arguments: func() -> list;
+
+ /// Return a path that programs should use as their initial current working
+ /// directory, interpreting `.` as shorthand for this.
+ initial-cwd: func() -> option;
+}
diff --git a/wit-0.3.0-draft/deps/cli/exit.wit b/wit-0.3.0-draft/deps/cli/exit.wit
new file mode 100644
index 0000000..d0c2b82
--- /dev/null
+++ b/wit-0.3.0-draft/deps/cli/exit.wit
@@ -0,0 +1,4 @@
+interface exit {
+ /// Exit the current instance and any linked instances.
+ exit: func(status: result);
+}
diff --git a/wit-0.3.0-draft/deps/cli/imports.wit b/wit-0.3.0-draft/deps/cli/imports.wit
new file mode 100644
index 0000000..083b84a
--- /dev/null
+++ b/wit-0.3.0-draft/deps/cli/imports.wit
@@ -0,0 +1,20 @@
+package wasi:cli@0.2.0;
+
+world imports {
+ include wasi:clocks/imports@0.2.0;
+ include wasi:filesystem/imports@0.2.0;
+ include wasi:sockets/imports@0.2.0;
+ include wasi:random/imports@0.2.0;
+ include wasi:io/imports@0.2.0;
+
+ import environment;
+ import exit;
+ import stdin;
+ import stdout;
+ import stderr;
+ import terminal-input;
+ import terminal-output;
+ import terminal-stdin;
+ import terminal-stdout;
+ import terminal-stderr;
+}
diff --git a/wit-0.3.0-draft/deps/cli/run.wit b/wit-0.3.0-draft/deps/cli/run.wit
new file mode 100644
index 0000000..a70ee8c
--- /dev/null
+++ b/wit-0.3.0-draft/deps/cli/run.wit
@@ -0,0 +1,4 @@
+interface run {
+ /// Run the program.
+ run: func() -> result;
+}
diff --git a/wit-0.3.0-draft/deps/cli/stdio.wit b/wit-0.3.0-draft/deps/cli/stdio.wit
new file mode 100644
index 0000000..31ef35b
--- /dev/null
+++ b/wit-0.3.0-draft/deps/cli/stdio.wit
@@ -0,0 +1,17 @@
+interface stdin {
+ use wasi:io/streams@0.2.0.{input-stream};
+
+ get-stdin: func() -> input-stream;
+}
+
+interface stdout {
+ use wasi:io/streams@0.2.0.{output-stream};
+
+ get-stdout: func() -> output-stream;
+}
+
+interface stderr {
+ use wasi:io/streams@0.2.0.{output-stream};
+
+ get-stderr: func() -> output-stream;
+}
diff --git a/wit-0.3.0-draft/deps/cli/terminal.wit b/wit-0.3.0-draft/deps/cli/terminal.wit
new file mode 100644
index 0000000..38c724e
--- /dev/null
+++ b/wit-0.3.0-draft/deps/cli/terminal.wit
@@ -0,0 +1,49 @@
+/// Terminal input.
+///
+/// In the future, this may include functions for disabling echoing,
+/// disabling input buffering so that keyboard events are sent through
+/// immediately, querying supported features, and so on.
+interface terminal-input {
+ /// The input side of a terminal.
+ resource terminal-input;
+}
+
+/// Terminal output.
+///
+/// In the future, this may include functions for querying the terminal
+/// size, being notified of terminal size changes, querying supported
+/// features, and so on.
+interface terminal-output {
+ /// The output side of a terminal.
+ resource terminal-output;
+}
+
+/// An interface providing an optional `terminal-input` for stdin as a
+/// link-time authority.
+interface terminal-stdin {
+ use terminal-input.{terminal-input};
+
+ /// If stdin is connected to a terminal, return a `terminal-input` handle
+ /// allowing further interaction with it.
+ get-terminal-stdin: func() -> option;
+}
+
+/// An interface providing an optional `terminal-output` for stdout as a
+/// link-time authority.
+interface terminal-stdout {
+ use terminal-output.{terminal-output};
+
+ /// If stdout is connected to a terminal, return a `terminal-output` handle
+ /// allowing further interaction with it.
+ get-terminal-stdout: func() -> option;
+}
+
+/// An interface providing an optional `terminal-output` for stderr as a
+/// link-time authority.
+interface terminal-stderr {
+ use terminal-output.{terminal-output};
+
+ /// If stderr is connected to a terminal, return a `terminal-output` handle
+ /// allowing further interaction with it.
+ get-terminal-stderr: func() -> option;
+}
diff --git a/wit-0.3.0-draft/deps/clocks/monotonic-clock.wit b/wit-0.3.0-draft/deps/clocks/monotonic-clock.wit
new file mode 100644
index 0000000..4e4dc3a
--- /dev/null
+++ b/wit-0.3.0-draft/deps/clocks/monotonic-clock.wit
@@ -0,0 +1,45 @@
+package wasi:clocks@0.2.0;
+/// WASI Monotonic Clock is a clock API intended to let users measure elapsed
+/// time.
+///
+/// It is intended to be portable at least between Unix-family platforms and
+/// Windows.
+///
+/// A monotonic clock is a clock which has an unspecified initial value, and
+/// successive reads of the clock will produce non-decreasing values.
+///
+/// It is intended for measuring elapsed time.
+interface monotonic-clock {
+ use wasi:io/poll@0.2.0.{pollable};
+
+ /// An instant in time, in nanoseconds. An instant is relative to an
+ /// unspecified initial value, and can only be compared to instances from
+ /// the same monotonic-clock.
+ type instant = u64;
+
+ /// A duration of time, in nanoseconds.
+ type duration = u64;
+
+ /// Read the current value of the clock.
+ ///
+ /// The clock is monotonic, therefore calling this function repeatedly will
+ /// produce a sequence of non-decreasing values.
+ now: func() -> instant;
+
+ /// Query the resolution of the clock. Returns the duration of time
+ /// corresponding to a clock tick.
+ resolution: func() -> duration;
+
+ /// Create a `pollable` which will resolve once the specified instant
+ /// occured.
+ subscribe-instant: func(
+ when: instant,
+ ) -> pollable;
+
+ /// Create a `pollable` which will resolve once the given duration has
+ /// elapsed, starting at the time at which this function was called.
+ /// occured.
+ subscribe-duration: func(
+ when: duration,
+ ) -> pollable;
+}
diff --git a/wit-0.3.0-draft/deps/clocks/wall-clock.wit b/wit-0.3.0-draft/deps/clocks/wall-clock.wit
new file mode 100644
index 0000000..440ca0f
--- /dev/null
+++ b/wit-0.3.0-draft/deps/clocks/wall-clock.wit
@@ -0,0 +1,42 @@
+package wasi:clocks@0.2.0;
+/// WASI Wall Clock is a clock API intended to let users query the current
+/// time. The name "wall" makes an analogy to a "clock on the wall", which
+/// is not necessarily monotonic as it may be reset.
+///
+/// It is intended to be portable at least between Unix-family platforms and
+/// Windows.
+///
+/// A wall clock is a clock which measures the date and time according to
+/// some external reference.
+///
+/// External references may be reset, so this clock is not necessarily
+/// monotonic, making it unsuitable for measuring elapsed time.
+///
+/// It is intended for reporting the current date and time for humans.
+interface wall-clock {
+ /// A time and date in seconds plus nanoseconds.
+ record datetime {
+ seconds: u64,
+ nanoseconds: u32,
+ }
+
+ /// Read the current value of the clock.
+ ///
+ /// This clock is not monotonic, therefore calling this function repeatedly
+ /// will not necessarily produce a sequence of non-decreasing values.
+ ///
+ /// The returned timestamps represent the number of seconds since
+ /// 1970-01-01T00:00:00Z, also known as [POSIX's Seconds Since the Epoch],
+ /// also known as [Unix Time].
+ ///
+ /// The nanoseconds field of the output is always less than 1000000000.
+ ///
+ /// [POSIX's Seconds Since the Epoch]: https://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xbd_chap04.html#tag_21_04_16
+ /// [Unix Time]: https://en.wikipedia.org/wiki/Unix_time
+ now: func() -> datetime;
+
+ /// Query the resolution of the clock.
+ ///
+ /// The nanoseconds field of the output is always less than 1000000000.
+ resolution: func() -> datetime;
+}
diff --git a/wit-0.3.0-draft/deps/clocks/world.wit b/wit-0.3.0-draft/deps/clocks/world.wit
new file mode 100644
index 0000000..c022457
--- /dev/null
+++ b/wit-0.3.0-draft/deps/clocks/world.wit
@@ -0,0 +1,6 @@
+package wasi:clocks@0.2.0;
+
+world imports {
+ import monotonic-clock;
+ import wall-clock;
+}
diff --git a/wit-0.3.0-draft/deps/filesystem/preopens.wit b/wit-0.3.0-draft/deps/filesystem/preopens.wit
new file mode 100644
index 0000000..da801f6
--- /dev/null
+++ b/wit-0.3.0-draft/deps/filesystem/preopens.wit
@@ -0,0 +1,8 @@
+package wasi:filesystem@0.2.0;
+
+interface preopens {
+ use types.{descriptor};
+
+ /// Return the set of preopened directories, and their path.
+ get-directories: func() -> list>;
+}
diff --git a/wit-0.3.0-draft/deps/filesystem/types.wit b/wit-0.3.0-draft/deps/filesystem/types.wit
new file mode 100644
index 0000000..11108fc
--- /dev/null
+++ b/wit-0.3.0-draft/deps/filesystem/types.wit
@@ -0,0 +1,634 @@
+package wasi:filesystem@0.2.0;
+/// WASI filesystem is a filesystem API primarily intended to let users run WASI
+/// programs that access their files on their existing filesystems, without
+/// significant overhead.
+///
+/// It is intended to be roughly portable between Unix-family platforms and
+/// Windows, though it does not hide many of the major differences.
+///
+/// Paths are passed as interface-type `string`s, meaning they must consist of
+/// a sequence of Unicode Scalar Values (USVs). Some filesystems may contain
+/// paths which are not accessible by this API.
+///
+/// The directory separator in WASI is always the forward-slash (`/`).
+///
+/// All paths in WASI are relative paths, and are interpreted relative to a
+/// `descriptor` referring to a base directory. If a `path` argument to any WASI
+/// function starts with `/`, or if any step of resolving a `path`, including
+/// `..` and symbolic link steps, reaches a directory outside of the base
+/// directory, or reaches a symlink to an absolute or rooted path in the
+/// underlying filesystem, the function fails with `error-code::not-permitted`.
+///
+/// For more information about WASI path resolution and sandboxing, see
+/// [WASI filesystem path resolution].
+///
+/// [WASI filesystem path resolution]: https://github.com/WebAssembly/wasi-filesystem/blob/main/path-resolution.md
+interface types {
+ use wasi:io/streams@0.2.0.{input-stream, output-stream, error};
+ use wasi:clocks/wall-clock@0.2.0.{datetime};
+
+ /// File size or length of a region within a file.
+ type filesize = u64;
+
+ /// The type of a filesystem object referenced by a descriptor.
+ ///
+ /// Note: This was called `filetype` in earlier versions of WASI.
+ enum descriptor-type {
+ /// The type of the descriptor or file is unknown or is different from
+ /// any of the other types specified.
+ unknown,
+ /// The descriptor refers to a block device inode.
+ block-device,
+ /// The descriptor refers to a character device inode.
+ character-device,
+ /// The descriptor refers to a directory inode.
+ directory,
+ /// The descriptor refers to a named pipe.
+ fifo,
+ /// The file refers to a symbolic link inode.
+ symbolic-link,
+ /// The descriptor refers to a regular file inode.
+ regular-file,
+ /// The descriptor refers to a socket.
+ socket,
+ }
+
+ /// Descriptor flags.
+ ///
+ /// Note: This was called `fdflags` in earlier versions of WASI.
+ flags descriptor-flags {
+ /// Read mode: Data can be read.
+ read,
+ /// Write mode: Data can be written to.
+ write,
+ /// Request that writes be performed according to synchronized I/O file
+ /// integrity completion. The data stored in the file and the file's
+ /// metadata are synchronized. This is similar to `O_SYNC` in POSIX.
+ ///
+ /// The precise semantics of this operation have not yet been defined for
+ /// WASI. At this time, it should be interpreted as a request, and not a
+ /// requirement.
+ file-integrity-sync,
+ /// Request that writes be performed according to synchronized I/O data
+ /// integrity completion. Only the data stored in the file is
+ /// synchronized. This is similar to `O_DSYNC` in POSIX.
+ ///
+ /// The precise semantics of this operation have not yet been defined for
+ /// WASI. At this time, it should be interpreted as a request, and not a
+ /// requirement.
+ data-integrity-sync,
+ /// Requests that reads be performed at the same level of integrety
+ /// requested for writes. This is similar to `O_RSYNC` in POSIX.
+ ///
+ /// The precise semantics of this operation have not yet been defined for
+ /// WASI. At this time, it should be interpreted as a request, and not a
+ /// requirement.
+ requested-write-sync,
+ /// Mutating directories mode: Directory contents may be mutated.
+ ///
+ /// When this flag is unset on a descriptor, operations using the
+ /// descriptor which would create, rename, delete, modify the data or
+ /// metadata of filesystem objects, or obtain another handle which
+ /// would permit any of those, shall fail with `error-code::read-only` if
+ /// they would otherwise succeed.
+ ///
+ /// This may only be set on directories.
+ mutate-directory,
+ }
+
+ /// File attributes.
+ ///
+ /// Note: This was called `filestat` in earlier versions of WASI.
+ record descriptor-stat {
+ /// File type.
+ %type: descriptor-type,
+ /// Number of hard links to the file.
+ link-count: link-count,
+ /// For regular files, the file size in bytes. For symbolic links, the
+ /// length in bytes of the pathname contained in the symbolic link.
+ size: filesize,
+ /// Last data access timestamp.
+ ///
+ /// If the `option` is none, the platform doesn't maintain an access
+ /// timestamp for this file.
+ data-access-timestamp: option,
+ /// Last data modification timestamp.
+ ///
+ /// If the `option` is none, the platform doesn't maintain a
+ /// modification timestamp for this file.
+ data-modification-timestamp: option,
+ /// Last file status-change timestamp.
+ ///
+ /// If the `option` is none, the platform doesn't maintain a
+ /// status-change timestamp for this file.
+ status-change-timestamp: option,
+ }
+
+ /// Flags determining the method of how paths are resolved.
+ flags path-flags {
+ /// As long as the resolved path corresponds to a symbolic link, it is
+ /// expanded.
+ symlink-follow,
+ }
+
+ /// Open flags used by `open-at`.
+ flags open-flags {
+ /// Create file if it does not exist, similar to `O_CREAT` in POSIX.
+ create,
+ /// Fail if not a directory, similar to `O_DIRECTORY` in POSIX.
+ directory,
+ /// Fail if file already exists, similar to `O_EXCL` in POSIX.
+ exclusive,
+ /// Truncate file to size 0, similar to `O_TRUNC` in POSIX.
+ truncate,
+ }
+
+ /// Number of hard links to an inode.
+ type link-count = u64;
+
+ /// When setting a timestamp, this gives the value to set it to.
+ variant new-timestamp {
+ /// Leave the timestamp set to its previous value.
+ no-change,
+ /// Set the timestamp to the current time of the system clock associated
+ /// with the filesystem.
+ now,
+ /// Set the timestamp to the given value.
+ timestamp(datetime),
+ }
+
+ /// A directory entry.
+ record directory-entry {
+ /// The type of the file referred to by this directory entry.
+ %type: descriptor-type,
+
+ /// The name of the object.
+ name: string,
+ }
+
+ /// Error codes returned by functions, similar to `errno` in POSIX.
+ /// Not all of these error codes are returned by the functions provided by this
+ /// API; some are used in higher-level library layers, and others are provided
+ /// merely for alignment with POSIX.
+ enum error-code {
+ /// Permission denied, similar to `EACCES` in POSIX.
+ access,
+ /// Resource unavailable, or operation would block, similar to `EAGAIN` and `EWOULDBLOCK` in POSIX.
+ would-block,
+ /// Connection already in progress, similar to `EALREADY` in POSIX.
+ already,
+ /// Bad descriptor, similar to `EBADF` in POSIX.
+ bad-descriptor,
+ /// Device or resource busy, similar to `EBUSY` in POSIX.
+ busy,
+ /// Resource deadlock would occur, similar to `EDEADLK` in POSIX.
+ deadlock,
+ /// Storage quota exceeded, similar to `EDQUOT` in POSIX.
+ quota,
+ /// File exists, similar to `EEXIST` in POSIX.
+ exist,
+ /// File too large, similar to `EFBIG` in POSIX.
+ file-too-large,
+ /// Illegal byte sequence, similar to `EILSEQ` in POSIX.
+ illegal-byte-sequence,
+ /// Operation in progress, similar to `EINPROGRESS` in POSIX.
+ in-progress,
+ /// Interrupted function, similar to `EINTR` in POSIX.
+ interrupted,
+ /// Invalid argument, similar to `EINVAL` in POSIX.
+ invalid,
+ /// I/O error, similar to `EIO` in POSIX.
+ io,
+ /// Is a directory, similar to `EISDIR` in POSIX.
+ is-directory,
+ /// Too many levels of symbolic links, similar to `ELOOP` in POSIX.
+ loop,
+ /// Too many links, similar to `EMLINK` in POSIX.
+ too-many-links,
+ /// Message too large, similar to `EMSGSIZE` in POSIX.
+ message-size,
+ /// Filename too long, similar to `ENAMETOOLONG` in POSIX.
+ name-too-long,
+ /// No such device, similar to `ENODEV` in POSIX.
+ no-device,
+ /// No such file or directory, similar to `ENOENT` in POSIX.
+ no-entry,
+ /// No locks available, similar to `ENOLCK` in POSIX.
+ no-lock,
+ /// Not enough space, similar to `ENOMEM` in POSIX.
+ insufficient-memory,
+ /// No space left on device, similar to `ENOSPC` in POSIX.
+ insufficient-space,
+ /// Not a directory or a symbolic link to a directory, similar to `ENOTDIR` in POSIX.
+ not-directory,
+ /// Directory not empty, similar to `ENOTEMPTY` in POSIX.
+ not-empty,
+ /// State not recoverable, similar to `ENOTRECOVERABLE` in POSIX.
+ not-recoverable,
+ /// Not supported, similar to `ENOTSUP` and `ENOSYS` in POSIX.
+ unsupported,
+ /// Inappropriate I/O control operation, similar to `ENOTTY` in POSIX.
+ no-tty,
+ /// No such device or address, similar to `ENXIO` in POSIX.
+ no-such-device,
+ /// Value too large to be stored in data type, similar to `EOVERFLOW` in POSIX.
+ overflow,
+ /// Operation not permitted, similar to `EPERM` in POSIX.
+ not-permitted,
+ /// Broken pipe, similar to `EPIPE` in POSIX.
+ pipe,
+ /// Read-only file system, similar to `EROFS` in POSIX.
+ read-only,
+ /// Invalid seek, similar to `ESPIPE` in POSIX.
+ invalid-seek,
+ /// Text file busy, similar to `ETXTBSY` in POSIX.
+ text-file-busy,
+ /// Cross-device link, similar to `EXDEV` in POSIX.
+ cross-device,
+ }
+
+ /// File or memory access pattern advisory information.
+ enum advice {
+ /// The application has no advice to give on its behavior with respect
+ /// to the specified data.
+ normal,
+ /// The application expects to access the specified data sequentially
+ /// from lower offsets to higher offsets.
+ sequential,
+ /// The application expects to access the specified data in a random
+ /// order.
+ random,
+ /// The application expects to access the specified data in the near
+ /// future.
+ will-need,
+ /// The application expects that it will not access the specified data
+ /// in the near future.
+ dont-need,
+ /// The application expects to access the specified data once and then
+ /// not reuse it thereafter.
+ no-reuse,
+ }
+
+ /// A 128-bit hash value, split into parts because wasm doesn't have a
+ /// 128-bit integer type.
+ record metadata-hash-value {
+ /// 64 bits of a 128-bit hash value.
+ lower: u64,
+ /// Another 64 bits of a 128-bit hash value.
+ upper: u64,
+ }
+
+ /// A descriptor is a reference to a filesystem object, which may be a file,
+ /// directory, named pipe, special file, or other object on which filesystem
+ /// calls may be made.
+ resource descriptor {
+ /// Return a stream for reading from a file, if available.
+ ///
+ /// May fail with an error-code describing why the file cannot be read.
+ ///
+ /// Multiple read, write, and append streams may be active on the same open
+ /// file and they do not interfere with each other.
+ ///
+ /// Note: This allows using `read-stream`, which is similar to `read` in POSIX.
+ read-via-stream: func(
+ /// The offset within the file at which to start reading.
+ offset: filesize,
+ ) -> result;
+
+ /// Return a stream for writing to a file, if available.
+ ///
+ /// May fail with an error-code describing why the file cannot be written.
+ ///
+ /// Note: This allows using `write-stream`, which is similar to `write` in
+ /// POSIX.
+ write-via-stream: func(
+ /// The offset within the file at which to start writing.
+ offset: filesize,
+ ) -> result;
+
+ /// Return a stream for appending to a file, if available.
+ ///
+ /// May fail with an error-code describing why the file cannot be appended.
+ ///
+ /// Note: This allows using `write-stream`, which is similar to `write` with
+ /// `O_APPEND` in in POSIX.
+ append-via-stream: func() -> result;
+
+ /// Provide file advisory information on a descriptor.
+ ///
+ /// This is similar to `posix_fadvise` in POSIX.
+ advise: func(
+ /// The offset within the file to which the advisory applies.
+ offset: filesize,
+ /// The length of the region to which the advisory applies.
+ length: filesize,
+ /// The advice.
+ advice: advice
+ ) -> result<_, error-code>;
+
+ /// Synchronize the data of a file to disk.
+ ///
+ /// This function succeeds with no effect if the file descriptor is not
+ /// opened for writing.
+ ///
+ /// Note: This is similar to `fdatasync` in POSIX.
+ sync-data: func() -> result<_, error-code>;
+
+ /// Get flags associated with a descriptor.
+ ///
+ /// Note: This returns similar flags to `fcntl(fd, F_GETFL)` in POSIX.
+ ///
+ /// Note: This returns the value that was the `fs_flags` value returned
+ /// from `fdstat_get` in earlier versions of WASI.
+ get-flags: func() -> result;
+
+ /// Get the dynamic type of a descriptor.
+ ///
+ /// Note: This returns the same value as the `type` field of the `fd-stat`
+ /// returned by `stat`, `stat-at` and similar.
+ ///
+ /// Note: This returns similar flags to the `st_mode & S_IFMT` value provided
+ /// by `fstat` in POSIX.
+ ///
+ /// Note: This returns the value that was the `fs_filetype` value returned
+ /// from `fdstat_get` in earlier versions of WASI.
+ get-type: func() -> result;
+
+ /// Adjust the size of an open file. If this increases the file's size, the
+ /// extra bytes are filled with zeros.
+ ///
+ /// Note: This was called `fd_filestat_set_size` in earlier versions of WASI.
+ set-size: func(size: filesize) -> result<_, error-code>;
+
+ /// Adjust the timestamps of an open file or directory.
+ ///
+ /// Note: This is similar to `futimens` in POSIX.
+ ///
+ /// Note: This was called `fd_filestat_set_times` in earlier versions of WASI.
+ set-times: func(
+ /// The desired values of the data access timestamp.
+ data-access-timestamp: new-timestamp,
+ /// The desired values of the data modification timestamp.
+ data-modification-timestamp: new-timestamp,
+ ) -> result<_, error-code>;
+
+ /// Read from a descriptor, without using and updating the descriptor's offset.
+ ///
+ /// This function returns a list of bytes containing the data that was
+ /// read, along with a bool which, when true, indicates that the end of the
+ /// file was reached. The returned list will contain up to `length` bytes; it
+ /// may return fewer than requested, if the end of the file is reached or
+ /// if the I/O operation is interrupted.
+ ///
+ /// In the future, this may change to return a `stream`.
+ ///
+ /// Note: This is similar to `pread` in POSIX.
+ read: func(
+ /// The maximum number of bytes to read.
+ length: filesize,
+ /// The offset within the file at which to read.
+ offset: filesize,
+ ) -> result, bool>, error-code>;
+
+ /// Write to a descriptor, without using and updating the descriptor's offset.
+ ///
+ /// It is valid to write past the end of a file; the file is extended to the
+ /// extent of the write, with bytes between the previous end and the start of
+ /// the write set to zero.
+ ///
+ /// In the future, this may change to take a `stream`.
+ ///
+ /// Note: This is similar to `pwrite` in POSIX.
+ write: func(
+ /// Data to write
+ buffer: list,
+ /// The offset within the file at which to write.
+ offset: filesize,
+ ) -> result;
+
+ /// Read directory entries from a directory.
+ ///
+ /// On filesystems where directories contain entries referring to themselves
+ /// and their parents, often named `.` and `..` respectively, these entries
+ /// are omitted.
+ ///
+ /// This always returns a new stream which starts at the beginning of the
+ /// directory. Multiple streams may be active on the same directory, and they
+ /// do not interfere with each other.
+ read-directory: func() -> result;
+
+ /// Synchronize the data and metadata of a file to disk.
+ ///
+ /// This function succeeds with no effect if the file descriptor is not
+ /// opened for writing.
+ ///
+ /// Note: This is similar to `fsync` in POSIX.
+ sync: func() -> result<_, error-code>;
+
+ /// Create a directory.
+ ///
+ /// Note: This is similar to `mkdirat` in POSIX.
+ create-directory-at: func(
+ /// The relative path at which to create the directory.
+ path: string,
+ ) -> result<_, error-code>;
+
+ /// Return the attributes of an open file or directory.
+ ///
+ /// Note: This is similar to `fstat` in POSIX, except that it does not return
+ /// device and inode information. For testing whether two descriptors refer to
+ /// the same underlying filesystem object, use `is-same-object`. To obtain
+ /// additional data that can be used do determine whether a file has been
+ /// modified, use `metadata-hash`.
+ ///
+ /// Note: This was called `fd_filestat_get` in earlier versions of WASI.
+ stat: func() -> result;
+
+ /// Return the attributes of a file or directory.
+ ///
+ /// Note: This is similar to `fstatat` in POSIX, except that it does not
+ /// return device and inode information. See the `stat` description for a
+ /// discussion of alternatives.
+ ///
+ /// Note: This was called `path_filestat_get` in earlier versions of WASI.
+ stat-at: func(
+ /// Flags determining the method of how the path is resolved.
+ path-flags: path-flags,
+ /// The relative path of the file or directory to inspect.
+ path: string,
+ ) -> result;
+
+ /// Adjust the timestamps of a file or directory.
+ ///
+ /// Note: This is similar to `utimensat` in POSIX.
+ ///
+ /// Note: This was called `path_filestat_set_times` in earlier versions of
+ /// WASI.
+ set-times-at: func(
+ /// Flags determining the method of how the path is resolved.
+ path-flags: path-flags,
+ /// The relative path of the file or directory to operate on.
+ path: string,
+ /// The desired values of the data access timestamp.
+ data-access-timestamp: new-timestamp,
+ /// The desired values of the data modification timestamp.
+ data-modification-timestamp: new-timestamp,
+ ) -> result<_, error-code>;
+
+ /// Create a hard link.
+ ///
+ /// Note: This is similar to `linkat` in POSIX.
+ link-at: func(
+ /// Flags determining the method of how the path is resolved.
+ old-path-flags: path-flags,
+ /// The relative source path from which to link.
+ old-path: string,
+ /// The base directory for `new-path`.
+ new-descriptor: borrow,
+ /// The relative destination path at which to create the hard link.
+ new-path: string,
+ ) -> result<_, error-code>;
+
+ /// Open a file or directory.
+ ///
+ /// The returned descriptor is not guaranteed to be the lowest-numbered
+ /// descriptor not currently open/ it is randomized to prevent applications
+ /// from depending on making assumptions about indexes, since this is
+ /// error-prone in multi-threaded contexts. The returned descriptor is
+ /// guaranteed to be less than 2**31.
+ ///
+ /// If `flags` contains `descriptor-flags::mutate-directory`, and the base
+ /// descriptor doesn't have `descriptor-flags::mutate-directory` set,
+ /// `open-at` fails with `error-code::read-only`.
+ ///
+ /// If `flags` contains `write` or `mutate-directory`, or `open-flags`
+ /// contains `truncate` or `create`, and the base descriptor doesn't have
+ /// `descriptor-flags::mutate-directory` set, `open-at` fails with
+ /// `error-code::read-only`.
+ ///
+ /// Note: This is similar to `openat` in POSIX.
+ open-at: func(
+ /// Flags determining the method of how the path is resolved.
+ path-flags: path-flags,
+ /// The relative path of the object to open.
+ path: string,
+ /// The method by which to open the file.
+ open-flags: open-flags,
+ /// Flags to use for the resulting descriptor.
+ %flags: descriptor-flags,
+ ) -> result;
+
+ /// Read the contents of a symbolic link.
+ ///
+ /// If the contents contain an absolute or rooted path in the underlying
+ /// filesystem, this function fails with `error-code::not-permitted`.
+ ///
+ /// Note: This is similar to `readlinkat` in POSIX.
+ readlink-at: func(
+ /// The relative path of the symbolic link from which to read.
+ path: string,
+ ) -> result;
+
+ /// Remove a directory.
+ ///
+ /// Return `error-code::not-empty` if the directory is not empty.
+ ///
+ /// Note: This is similar to `unlinkat(fd, path, AT_REMOVEDIR)` in POSIX.
+ remove-directory-at: func(
+ /// The relative path to a directory to remove.
+ path: string,
+ ) -> result<_, error-code>;
+
+ /// Rename a filesystem object.
+ ///
+ /// Note: This is similar to `renameat` in POSIX.
+ rename-at: func(
+ /// The relative source path of the file or directory to rename.
+ old-path: string,
+ /// The base directory for `new-path`.
+ new-descriptor: borrow,
+ /// The relative destination path to which to rename the file or directory.
+ new-path: string,
+ ) -> result<_, error-code>;
+
+ /// Create a symbolic link (also known as a "symlink").
+ ///
+ /// If `old-path` starts with `/`, the function fails with
+ /// `error-code::not-permitted`.
+ ///
+ /// Note: This is similar to `symlinkat` in POSIX.
+ symlink-at: func(
+ /// The contents of the symbolic link.
+ old-path: string,
+ /// The relative destination path at which to create the symbolic link.
+ new-path: string,
+ ) -> result<_, error-code>;
+
+ /// Unlink a filesystem object that is not a directory.
+ ///
+ /// Return `error-code::is-directory` if the path refers to a directory.
+ /// Note: This is similar to `unlinkat(fd, path, 0)` in POSIX.
+ unlink-file-at: func(
+ /// The relative path to a file to unlink.
+ path: string,
+ ) -> result<_, error-code>;
+
+ /// Test whether two descriptors refer to the same filesystem object.
+ ///
+ /// In POSIX, this corresponds to testing whether the two descriptors have the
+ /// same device (`st_dev`) and inode (`st_ino` or `d_ino`) numbers.
+ /// wasi-filesystem does not expose device and inode numbers, so this function
+ /// may be used instead.
+ is-same-object: func(other: borrow) -> bool;
+
+ /// Return a hash of the metadata associated with a filesystem object referred
+ /// to by a descriptor.
+ ///
+ /// This returns a hash of the last-modification timestamp and file size, and
+ /// may also include the inode number, device number, birth timestamp, and
+ /// other metadata fields that may change when the file is modified or
+ /// replaced. It may also include a secret value chosen by the
+ /// implementation and not otherwise exposed.
+ ///
+ /// Implementations are encourated to provide the following properties:
+ ///
+ /// - If the file is not modified or replaced, the computed hash value should
+ /// usually not change.
+ /// - If the object is modified or replaced, the computed hash value should
+ /// usually change.
+ /// - The inputs to the hash should not be easily computable from the
+ /// computed hash.
+ ///
+ /// However, none of these is required.
+ metadata-hash: func() -> result;
+
+ /// Return a hash of the metadata associated with a filesystem object referred
+ /// to by a directory descriptor and a relative path.
+ ///
+ /// This performs the same hash computation as `metadata-hash`.
+ metadata-hash-at: func(
+ /// Flags determining the method of how the path is resolved.
+ path-flags: path-flags,
+ /// The relative path of the file or directory to inspect.
+ path: string,
+ ) -> result;
+ }
+
+ /// A stream of directory entries.
+ resource directory-entry-stream {
+ /// Read a single directory entry from a `directory-entry-stream`.
+ read-directory-entry: func() -> result
which have multiple values are represented by multiple entries in this
list with the same key.
The tuple is a pair of the field key, represented as a string, and
-Value, represented as a list of bytes. In a valid Fields, all keys
-and values are valid UTF-8 strings. However, values are not always
-well-formed, so they are represented as a raw list of bytes.
-
An error result will be returned if any header or value was
-syntactically invalid, or if a header was forbidden.
+Value, represented as a list of bytes.
+
An error result will be returned if any field-key or field-value is
+syntactically invalid, or if a field is forbidden.
@@ -825,9 +823,9 @@ syntactically invalid, or if a header was forbidden.
[method]fields.get: func
Get all of the values corresponding to a key. If the key is not present
-in this fields, an empty list is returned. However, if the key is
-present but empty, this is represented by a list with one or more
-empty field-values present.
+in this fields or is syntactically invalid, an empty list is returned.
+However, if the key is present but empty, this is represented by a list
+with one or more empty field-values present.