diff --git a/Cargo.lock b/Cargo.lock index 7336d8b..cbe001f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2192,9 +2192,9 @@ dependencies = [ [[package]] name = "oci-wasm" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f147e207436277483c23cb8e55ccd039ee1657c6a8d19471a6de187da6973ef8" +checksum = "0609c917e8f4c44cd9d619a6e4741535d1cc199cfd995ad75580742bf6d624e8" dependencies = [ "anyhow", "chrono", @@ -2203,8 +2203,8 @@ dependencies = [ "serde_json", "sha2", "tokio", - "wit-component 0.219.1", - "wit-parser 0.219.1", + "wit-component", + "wit-parser", ] [[package]] @@ -4311,16 +4311,6 @@ dependencies = [ "wasmparser 0.121.2", ] -[[package]] -name = "wasm-encoder" -version = "0.219.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29cbbd772edcb8e7d524a82ee8cef8dd046fc14033796a754c3ad246d019fa54" -dependencies = [ - "leb128", - "wasmparser 0.219.1", -] - [[package]] name = "wasm-encoder" version = "0.221.2" @@ -4341,22 +4331,6 @@ dependencies = [ "wasmparser 0.224.0", ] -[[package]] -name = "wasm-metadata" -version = "0.219.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2af5a8e37a5e996861e1813f8de30911c47609c9ff51a7284f7dbd754dc3a9f3" -dependencies = [ - "anyhow", - "indexmap 2.7.0", - "serde", - "serde_derive", - "serde_json", - "spdx", - "wasm-encoder 0.219.1", - "wasmparser 0.219.1", -] - [[package]] name = "wasm-metadata" version = "0.224.0" @@ -4403,9 +4377,9 @@ dependencies = [ "warg-client", "warg-crypto", "warg-protocol", - "wasm-metadata 0.224.0", + "wasm-metadata", "wasm-pkg-common", - "wit-component 0.224.0", + "wit-component", ] [[package]] @@ -4445,12 +4419,12 @@ dependencies = [ "tokio-util", "toml", "tracing", - "wasm-metadata 0.224.0", + "wasm-metadata", "wasm-pkg-client", "wasm-pkg-common", "windows-sys 0.59.0", - "wit-component 0.224.0", - "wit-parser 0.224.0", + "wit-component", + "wit-parser", ] [[package]] @@ -4477,19 +4451,6 @@ dependencies = [ "semver", ] -[[package]] -name = "wasmparser" -version = "0.219.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c771866898879073c53b565a6c7b49953795159836714ac56a5befb581227c5" -dependencies = [ - "ahash", - "bitflags 2.6.0", - "hashbrown 0.14.5", - "indexmap 2.7.0", - "semver", -] - [[package]] name = "wasmparser" version = "0.221.2" @@ -4801,25 +4762,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "wit-component" -version = "0.219.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad1673163c0cb14a6a19ddbf44dd4efe6f015ec1ebb8156710ac32501f19fba2" -dependencies = [ - "anyhow", - "bitflags 2.6.0", - "indexmap 2.7.0", - "log", - "serde", - "serde_derive", - "serde_json", - "wasm-encoder 0.219.1", - "wasm-metadata 0.219.1", - "wasmparser 0.219.1", - "wit-parser 0.219.1", -] - [[package]] name = "wit-component" version = "0.224.0" @@ -4834,27 +4776,9 @@ dependencies = [ "serde_derive", "serde_json", "wasm-encoder 0.224.0", - "wasm-metadata 0.224.0", + "wasm-metadata", "wasmparser 0.224.0", - "wit-parser 0.224.0", -] - -[[package]] -name = "wit-parser" -version = "0.219.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a86f669283257e8e424b9a4fc3518e3ade0b95deb9fbc0f93a1876be3eda598" -dependencies = [ - "anyhow", - "id-arena", - "indexmap 2.7.0", - "log", - "semver", - "serde", - "serde_derive", - "serde_json", - "unicode-xid", - "wasmparser 0.219.1", + "wit-parser", ] [[package]] @@ -4895,7 +4819,7 @@ dependencies = [ "wasm-pkg-client", "wasm-pkg-common", "wasm-pkg-core", - "wit-component 0.224.0", + "wit-component", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 0bd2310..37994fb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,7 @@ futures-util = "0.3.30" oci-client = { version = "0.14", default-features = false, features = [ "rustls-tls", ] } -oci-wasm = { version = "0.2", default-features = false, features = [ +oci-wasm = { version = "0.2.1", default-features = false, features = [ "rustls-tls", ] } semver = "1.0.23" diff --git a/crates/wasm-pkg-core/src/resolver.rs b/crates/wasm-pkg-core/src/resolver.rs index ef6a605..14facc5 100644 --- a/crates/wasm-pkg-core/src/resolver.rs +++ b/crates/wasm-pkg-core/src/resolver.rs @@ -267,6 +267,7 @@ impl DecodedDependency<'_> { match self { Self::Wit { package, .. } => { let mut resolve = Resolve::new(); + resolve.all_features = true; let source_files = package .source_map .source_files() @@ -677,7 +678,11 @@ impl DependencyResolutionMap { /// Given a path to a component or a directory containing wit, use the given dependencies to /// generate a [`Resolve`] for the root package. pub async fn generate_resolve(&self, dir: impl AsRef) -> Result<(Resolve, PackageId)> { - let mut merged = Resolve::default(); + let mut merged = Resolve { + // Retain @unstable features; downstream tooling will process them further + all_features: true, + ..Resolve::default() + }; let deps = self.decode_dependencies().await?; diff --git a/crates/wasm-pkg-core/tests/build.rs b/crates/wasm-pkg-core/tests/build.rs index 2d9c910..c7f9745 100644 --- a/crates/wasm-pkg-core/tests/build.rs +++ b/crates/wasm-pkg-core/tests/build.rs @@ -1,5 +1,6 @@ use wasm_pkg_core::{config::Config as WkgConfig, lock::LockFile}; use wit_component::DecodedWasm; +use wit_parser::Stability; mod common; @@ -28,7 +29,7 @@ async fn test_build_wit() { ); assert_eq!( version.unwrap().to_string(), - "0.2.0", + "0.2.3", "Should have the correct version" ); @@ -53,18 +54,31 @@ async fn test_build_wit() { _ => panic!("Should be a package"), }; - let name = resolve - .package_names - .iter() - .find_map(|(name, id)| (pkg_id == *id).then_some(name)) - .expect("Should be able to find the package name"); + let package = resolve + .packages + .get(pkg_id) + .expect("Should contain decoded package"); assert_eq!( - name.to_string(), - "wasi:http@0.2.0", + package.name.to_string(), + "wasi:http@0.2.3", "Should have the correct package name" ); + // @unstable items are retained + let types_id = package + .interfaces + .get("types") + .expect("wasi:http should have a types interface"); + let send_informational = resolve.interfaces[*types_id] + .functions + .get("[method]response-outparam.send-informational") + .expect("Should have send-informational method"); + assert!( + matches!(send_informational.stability, Stability::Unstable { .. }), + "response-outparam.send-informational should be unstable" + ); + assert!( resolve.package_direct_deps(pkg_id).count() > 0, "Should have direct dependencies embedded" @@ -85,8 +99,8 @@ async fn test_bad_dep_failure() { .await .expect("Should be able to read the world file"); let str_world = str_world.replace( - "import wasi:cli/stdin@0.2.0;", - "import totally:not/real@0.2.0;", + "import wasi:cli/stdin@0.2.3;", + "import totally:not/real@0.2.3;", ); tokio::fs::write(world_file, str_world) .await diff --git a/crates/wasm-pkg-core/tests/fixtures/wasi-http/wit/handler.wit b/crates/wasm-pkg-core/tests/fixtures/wasi-http/wit/handler.wit index a34a064..6a6c629 100644 --- a/crates/wasm-pkg-core/tests/fixtures/wasi-http/wit/handler.wit +++ b/crates/wasm-pkg-core/tests/fixtures/wasi-http/wit/handler.wit @@ -1,6 +1,8 @@ /// This interface defines a handler of incoming HTTP Requests. It should /// be exported by components which can respond to HTTP Requests. +@since(version = 0.2.0) interface incoming-handler { + @since(version = 0.2.0) use types.{incoming-request, response-outparam}; /// This function is invoked with an incoming HTTP Request, and a resource @@ -13,6 +15,7 @@ interface incoming-handler { /// The implementor of this function must write a response to the /// `response-outparam` before returning, or else the caller will respond /// with an error on its behalf. + @since(version = 0.2.0) handle: func( request: incoming-request, response-out: response-outparam @@ -21,7 +24,9 @@ interface incoming-handler { /// This interface defines a handler of outgoing HTTP Requests. It should be /// imported by components which wish to make HTTP Requests. +@since(version = 0.2.0) interface outgoing-handler { + @since(version = 0.2.0) use types.{ outgoing-request, request-options, future-incoming-response, error-code }; @@ -36,6 +41,7 @@ interface outgoing-handler { /// This function may return an error if the `outgoing-request` is invalid /// or not allowed to be made. Otherwise, protocol errors are reported /// through the `future-incoming-response`. + @since(version = 0.2.0) handle: func( request: outgoing-request, options: option diff --git a/crates/wasm-pkg-core/tests/fixtures/wasi-http/wit/proxy.wit b/crates/wasm-pkg-core/tests/fixtures/wasi-http/wit/proxy.wit index 687c24d..de3bbe8 100644 --- a/crates/wasm-pkg-core/tests/fixtures/wasi-http/wit/proxy.wit +++ b/crates/wasm-pkg-core/tests/fixtures/wasi-http/wit/proxy.wit @@ -1,32 +1,50 @@ -package wasi:http@0.2.0; +package wasi:http@0.2.3; -/// The `wasi:http/proxy` world captures a widely-implementable intersection of -/// hosts that includes HTTP forward and reverse proxies. Components targeting -/// this world may concurrently stream in and out any number of incoming and -/// outgoing HTTP requests. -world proxy { +/// The `wasi:http/imports` world imports all the APIs for HTTP proxies. +/// It is intended to be `include`d in other worlds. +@since(version = 0.2.0) +world imports { /// HTTP proxies have access to time and randomness. - include wasi:clocks/imports@0.2.0; - import wasi:random/random@0.2.0; + @since(version = 0.2.0) + import wasi:clocks/monotonic-clock@0.2.3; + @since(version = 0.2.0) + import wasi:clocks/wall-clock@0.2.3; + @since(version = 0.2.0) + import wasi:random/random@0.2.3; /// Proxies have standard output and error streams which are expected to /// terminate in a developer-facing console provided by the host. - import wasi:cli/stdout@0.2.0; - import wasi:cli/stderr@0.2.0; + @since(version = 0.2.0) + import wasi:cli/stdout@0.2.3; + @since(version = 0.2.0) + import wasi:cli/stderr@0.2.3; /// TODO: this is a temporary workaround until component tooling is able to /// gracefully handle the absence of stdin. Hosts must return an eof stream /// for this import, which is what wasi-libc + tooling will do automatically /// when this import is properly removed. - import wasi:cli/stdin@0.2.0; + @since(version = 0.2.0) + import wasi:cli/stdin@0.2.3; /// This is the default handler to use when user code simply wants to make an /// HTTP request (e.g., via `fetch()`). + @since(version = 0.2.0) import outgoing-handler; +} + +/// The `wasi:http/proxy` world captures a widely-implementable intersection of +/// hosts that includes HTTP forward and reverse proxies. Components targeting +/// this world may concurrently stream in and out any number of incoming and +/// outgoing HTTP requests. +@since(version = 0.2.0) +world proxy { + @since(version = 0.2.0) + include imports; /// The host delivers incoming HTTP requests to a component by calling the /// `handle` function of this exported interface. A host may arbitrarily reuse /// or not reuse component instance when delivering incoming HTTP requests and /// thus a component must be able to handle 0..N calls to `handle`. + @since(version = 0.2.0) export incoming-handler; } diff --git a/crates/wasm-pkg-core/tests/fixtures/wasi-http/wit/types.wit b/crates/wasm-pkg-core/tests/fixtures/wasi-http/wit/types.wit index 755ac6a..9c0ce8b 100644 --- a/crates/wasm-pkg-core/tests/fixtures/wasi-http/wit/types.wit +++ b/crates/wasm-pkg-core/tests/fixtures/wasi-http/wit/types.wit @@ -1,13 +1,19 @@ /// This interface defines all of the types and methods for implementing /// HTTP Requests and Responses, both incoming and outgoing, as well as /// their headers, trailers, and bodies. +@since(version = 0.2.0) interface types { - use wasi:clocks/monotonic-clock@0.2.0.{duration}; - use wasi:io/streams@0.2.0.{input-stream, output-stream}; - use wasi:io/error@0.2.0.{error as io-error}; - use wasi:io/poll@0.2.0.{pollable}; + @since(version = 0.2.0) + use wasi:clocks/monotonic-clock@0.2.3.{duration}; + @since(version = 0.2.0) + use wasi:io/streams@0.2.3.{input-stream, output-stream}; + @since(version = 0.2.0) + use wasi:io/error@0.2.3.{error as io-error}; + @since(version = 0.2.0) + use wasi:io/poll@0.2.3.{pollable}; /// This type corresponds to HTTP standard Methods. + @since(version = 0.2.0) variant method { get, head, @@ -22,6 +28,7 @@ interface types { } /// This type corresponds to HTTP standard Related Schemes. + @since(version = 0.2.0) variant scheme { HTTP, HTTPS, @@ -29,7 +36,8 @@ interface types { } /// These cases are inspired by the IANA HTTP Proxy Error Types: - /// https://www.iana.org/assignments/http-proxy-status/http-proxy-status.xhtml#table-http-proxy-error-types + /// + @since(version = 0.2.0) variant error-code { DNS-timeout, DNS-error(DNS-error-payload), @@ -78,18 +86,21 @@ interface types { } /// Defines the case payload type for `DNS-error` above: + @since(version = 0.2.0) record DNS-error-payload { rcode: option, info-code: option } /// Defines the case payload type for `TLS-alert-received` above: + @since(version = 0.2.0) record TLS-alert-received-payload { alert-id: option, alert-message: option } /// Defines the case payload type for `HTTP-response-{header,trailer}-size` above: + @since(version = 0.2.0) record field-size-payload { field-name: option, field-size: option @@ -106,17 +117,19 @@ interface types { /// /// Note that this function is fallible because not all io-errors are /// http-related errors. + @since(version = 0.2.0) http-error-code: func(err: borrow) -> option; /// This type enumerates the different kinds of errors that may occur when /// setting or appending to a `fields` resource. + @since(version = 0.2.0) variant header-error { - /// This error indicates that a `field-key` or `field-value` was + /// This error indicates that a `field-name` or `field-value` was /// syntactically invalid when used with an operation that sets headers in a /// `fields`. invalid-syntax, - /// This error indicates that a forbidden `field-key` was used when trying + /// This error indicates that a forbidden `field-name` was used when trying /// to set a header in a `fields`. forbidden, @@ -125,12 +138,29 @@ interface types { immutable, } + /// Field names are always strings. + /// + /// Field names should always be treated as case insensitive by the `fields` + /// resource for the purposes of equality checking. + @since(version = 0.2.1) + type field-name = field-key; + /// Field keys are always strings. + /// + /// Field keys should always be treated as case insensitive by the `fields` + /// resource for the purposes of equality checking. + /// + /// # Deprecation + /// + /// This type has been deprecated in favor of the `field-name` type. + @since(version = 0.2.0) + @deprecated(version = 0.2.2) type field-key = string; /// Field values should always be ASCII strings. However, in /// reality, HTTP implementations often have to interpret malformed values, /// so they are provided as a list of bytes. + @since(version = 0.2.0) type field-value = list; /// This following block defines the `fields` resource which corresponds to @@ -140,96 +170,123 @@ interface types { /// A `fields` may be mutable or immutable. A `fields` created using the /// constructor, `from-list`, or `clone` will be mutable, but a `fields` /// resource given by other means (including, but not limited to, - /// `incoming-request.headers`, `outgoing-request.headers`) might be be + /// `incoming-request.headers`, `outgoing-request.headers`) might be /// immutable. In an immutable fields, the `set`, `append`, and `delete` /// operations will fail with `header-error.immutable`. + @since(version = 0.2.0) resource fields { /// Construct an empty HTTP Fields. /// /// The resulting `fields` is mutable. + @since(version = 0.2.0) constructor(); /// Construct an HTTP Fields. /// /// The resulting `fields` is mutable. /// - /// The list represents each key-value pair in the Fields. Keys + /// The list represents each name-value pair in the Fields. Names /// which have multiple values are represented by multiple entries in this - /// list with the same key. + /// list with the same name. /// - /// 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. + /// The tuple is a pair of the field name, represented as a string, and + /// Value, represented as a list of bytes. /// - /// An error result will be returned if any header or value was - /// syntactically invalid, or if a header was forbidden. + /// An error result will be returned if any `field-name` or `field-value` is + /// syntactically invalid, or if a field is forbidden. + @since(version = 0.2.0) from-list: static func( - entries: list> + entries: list> ) -> result; - /// 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. - get: func(name: field-key) -> list; + /// Get all of the values corresponding to a name. If the name is not present + /// in this `fields` or is syntactically invalid, an empty list is returned. + /// However, if the name is present but empty, this is represented by a list + /// with one or more empty field-values present. + @since(version = 0.2.0) + get: func(name: field-name) -> list; - /// Returns `true` when the key is present in this `fields`. If the key is + /// Returns `true` when the name is present in this `fields`. If the name is /// syntactically invalid, `false` is returned. - has: func(name: field-key) -> bool; + @since(version = 0.2.0) + has: func(name: field-name) -> bool; - /// Set all of the values for a key. Clears any existing values for that - /// key, if they have been set. + /// Set all of the values for a name. Clears any existing values for that + /// name, if they have been set. /// /// Fails with `header-error.immutable` if the `fields` are immutable. - set: func(name: field-key, value: list) -> result<_, header-error>; + /// + /// Fails with `header-error.invalid-syntax` if the `field-name` or any of + /// the `field-value`s are syntactically invalid. + @since(version = 0.2.0) + set: func(name: field-name, value: list) -> result<_, header-error>; - /// Delete all values for a key. Does nothing if no values for the key + /// Delete all values for a name. Does nothing if no values for the name /// exist. /// /// Fails with `header-error.immutable` if the `fields` are immutable. - delete: func(name: field-key) -> result<_, header-error>; + /// + /// Fails with `header-error.invalid-syntax` if the `field-name` is + /// syntactically invalid. + @since(version = 0.2.0) + delete: func(name: field-name) -> result<_, header-error>; - /// Append a value for a key. Does not change or delete any existing - /// values for that key. + /// Append a value for a name. Does not change or delete any existing + /// values for that name. /// /// Fails with `header-error.immutable` if the `fields` are immutable. - append: func(name: field-key, value: field-value) -> result<_, header-error>; + /// + /// Fails with `header-error.invalid-syntax` if the `field-name` or + /// `field-value` are syntactically invalid. + @since(version = 0.2.0) + append: func(name: field-name, value: field-value) -> result<_, header-error>; - /// Retrieve the full set of keys and values in the Fields. Like the - /// constructor, the list represents each key-value pair. + /// Retrieve the full set of names and values in the Fields. Like the + /// constructor, the list represents each name-value pair. /// - /// The outer list represents each key-value pair in the Fields. Keys + /// The outer list represents each name-value pair in the Fields. Names /// which have multiple values are represented by multiple entries in this - /// list with the same key. - entries: func() -> list>; + /// list with the same name. + /// + /// The names and values are always returned in the original casing and in + /// the order in which they will be serialized for transport. + @since(version = 0.2.0) + entries: func() -> list>; - /// Make a deep copy of the Fields. Equivelant in behavior to calling the + /// Make a deep copy of the Fields. Equivalent in behavior to calling the /// `fields` constructor on the return value of `entries`. The resulting /// `fields` is mutable. + @since(version = 0.2.0) clone: func() -> fields; } /// Headers is an alias for Fields. + @since(version = 0.2.0) type headers = fields; /// Trailers is an alias for Fields. + @since(version = 0.2.0) type trailers = fields; /// Represents an incoming HTTP Request. + @since(version = 0.2.0) resource incoming-request { /// Returns the method of the incoming request. + @since(version = 0.2.0) method: func() -> method; /// Returns the path with query parameters from the request, as a string. + @since(version = 0.2.0) path-with-query: func() -> option; /// Returns the protocol scheme from the request. + @since(version = 0.2.0) scheme: func() -> option; - /// Returns the authority from the request, if it was present. + /// Returns the authority of the Request's target URI, if present. + @since(version = 0.2.0) authority: func() -> option; /// Get the `headers` associated with the request. @@ -240,14 +297,17 @@ interface types { /// The `headers` returned are a child resource: it must be dropped before /// the parent `incoming-request` is dropped. Dropping this /// `incoming-request` before all children are dropped will trap. + @since(version = 0.2.0) headers: func() -> headers; /// Gives the `incoming-body` associated with this request. Will only /// return success at most once, and subsequent calls will return error. + @since(version = 0.2.0) consume: func() -> result; } /// Represents an outgoing HTTP Request. + @since(version = 0.2.0) resource outgoing-request { /// Construct a new `outgoing-request` with a default `method` of `GET`, and @@ -260,6 +320,7 @@ interface types { /// and `authority`, or `headers` which are not permitted to be sent. /// It is the obligation of the `outgoing-handler.handle` implementation /// to reject invalid constructions of `outgoing-request`. + @since(version = 0.2.0) constructor( headers: headers ); @@ -270,38 +331,47 @@ interface types { /// Returns success on the first call: the `outgoing-body` resource for /// this `outgoing-request` can be retrieved at most once. Subsequent /// calls will return error. + @since(version = 0.2.0) body: func() -> result; /// Get the Method for the Request. + @since(version = 0.2.0) method: func() -> method; /// Set the Method for the Request. Fails if the string present in a /// `method.other` argument is not a syntactically valid method. + @since(version = 0.2.0) set-method: func(method: method) -> result; /// Get the combination of the HTTP Path and Query for the Request. /// When `none`, this represents an empty Path and empty Query. + @since(version = 0.2.0) path-with-query: func() -> option; /// Set the combination of the HTTP Path and Query for the Request. /// When `none`, this represents an empty Path and empty Query. Fails is the /// string given is not a syntactically valid path and query uri component. + @since(version = 0.2.0) set-path-with-query: func(path-with-query: option) -> result; /// Get the HTTP Related Scheme for the Request. When `none`, the /// implementation may choose an appropriate default scheme. + @since(version = 0.2.0) scheme: func() -> option; /// Set the HTTP Related Scheme for the Request. When `none`, the /// implementation may choose an appropriate default scheme. Fails if the /// string given is not a syntactically valid uri scheme. + @since(version = 0.2.0) set-scheme: func(scheme: option) -> result; - /// Get the HTTP Authority for the Request. A value of `none` may be used - /// with Related Schemes which do not require an Authority. The HTTP and + /// Get the authority of the Request's target URI. A value of `none` may be used + /// with Related Schemes which do not require an authority. The HTTP and /// HTTPS schemes always require an authority. + @since(version = 0.2.0) authority: func() -> option; - /// Set the HTTP Authority for the Request. A value of `none` may be used - /// with Related Schemes which do not require an Authority. The HTTP and + /// Set the authority of the Request's target URI. A value of `none` may be used + /// with Related Schemes which do not require an authority. The HTTP and /// HTTPS schemes always require an authority. Fails if the string given is - /// not a syntactically valid uri authority. + /// not a syntactically valid URI authority. + @since(version = 0.2.0) set-authority: func(authority: option) -> result; /// Get the headers associated with the Request. @@ -310,8 +380,9 @@ interface types { /// `delete` operations will fail with `header-error.immutable`. /// /// This headers resource is a child: it must be dropped before the parent - /// `outgoing-request` is dropped, or its ownership is transfered to + /// `outgoing-request` is dropped, or its ownership is transferred to /// another component by e.g. `outgoing-handler.handle`. + @since(version = 0.2.0) headers: func() -> headers; } @@ -321,31 +392,39 @@ interface types { /// /// These timeouts are separate from any the user may use to bound a /// blocking call to `wasi:io/poll.poll`. + @since(version = 0.2.0) resource request-options { /// Construct a default `request-options` value. + @since(version = 0.2.0) constructor(); /// The timeout for the initial connect to the HTTP Server. + @since(version = 0.2.0) connect-timeout: func() -> option; /// Set the timeout for the initial connect to the HTTP Server. An error /// return value indicates that this timeout is not supported. + @since(version = 0.2.0) set-connect-timeout: func(duration: option) -> result; /// The timeout for receiving the first byte of the Response body. + @since(version = 0.2.0) first-byte-timeout: func() -> option; /// Set the timeout for receiving the first byte of the Response body. An /// error return value indicates that this timeout is not supported. + @since(version = 0.2.0) set-first-byte-timeout: func(duration: option) -> result; /// The timeout for receiving subsequent chunks of bytes in the Response /// body stream. + @since(version = 0.2.0) between-bytes-timeout: func() -> option; /// Set the timeout for receiving subsequent chunks of bytes in the Response /// body stream. An error return value indicates that this timeout is not /// supported. + @since(version = 0.2.0) set-between-bytes-timeout: func(duration: option) -> result; } @@ -354,7 +433,23 @@ interface types { /// This resource is used by the `wasi:http/incoming-handler` interface to /// allow a Response to be sent corresponding to the Request provided as the /// other argument to `incoming-handler.handle`. + @since(version = 0.2.0) resource response-outparam { + /// Send an HTTP 1xx response. + /// + /// Unlike `response-outparam.set`, this does not consume the + /// `response-outparam`, allowing the guest to send an arbitrary number of + /// informational responses before sending the final response using + /// `response-outparam.set`. + /// + /// This will return an `HTTP-protocol-error` if `status` is not in the + /// range [100-199], or an `internal-error` if the implementation does not + /// support informational responses. + @unstable(feature = informational-outbound-responses) + send-informational: func( + status: u16, + headers: headers + ) -> result<_, error-code>; /// Set the value of the `response-outparam` to either send a response, /// or indicate an error. @@ -365,6 +460,7 @@ interface types { /// /// The user may provide an `error` to `response` to allow the /// implementation determine how to respond with an HTTP error response. + @since(version = 0.2.0) set: static func( param: response-outparam, response: result, @@ -372,12 +468,15 @@ interface types { } /// This type corresponds to the HTTP standard Status Code. + @since(version = 0.2.0) type status-code = u16; /// Represents an incoming HTTP Response. + @since(version = 0.2.0) resource incoming-response { /// Returns the status code from the incoming response. + @since(version = 0.2.0) status: func() -> status-code; /// Returns the headers from the incoming response. @@ -387,10 +486,12 @@ interface types { /// /// This headers resource is a child: it must be dropped before the parent /// `incoming-response` is dropped. + @since(version = 0.2.0) headers: func() -> headers; /// Returns the incoming body. May be called at most once. Returns error /// if called additional times. + @since(version = 0.2.0) consume: func() -> result; } @@ -402,6 +503,7 @@ interface types { /// an `input-stream` and the delivery of trailers as a `future-trailers`, /// and ensures that the user of this interface may only be consuming either /// the body contents or waiting on trailers at any given time. + @since(version = 0.2.0) resource incoming-body { /// Returns the contents of the body, as a stream of bytes. @@ -419,26 +521,30 @@ interface types { /// backpressure is to be applied when the user is consuming the body, /// and for that backpressure to not inhibit delivery of the trailers if /// the user does not read the entire body. + @since(version = 0.2.0) %stream: func() -> result; /// Takes ownership of `incoming-body`, and returns a `future-trailers`. /// This function will trap if the `input-stream` child is still alive. + @since(version = 0.2.0) finish: static func(this: incoming-body) -> future-trailers; } - /// Represents a future which may eventaully return trailers, or an error. + /// Represents a future which may eventually return trailers, or an error. /// /// In the case that the incoming HTTP Request or Response did not have any /// trailers, this future will resolve to the empty set of trailers once the /// complete Request or Response body has been received. + @since(version = 0.2.0) resource future-trailers { /// Returns a pollable which becomes ready when either the trailers have - /// been received, or an error has occured. When this pollable is ready, + /// been received, or an error has occurred. When this pollable is ready, /// the `get` method will return `some`. + @since(version = 0.2.0) subscribe: func() -> pollable; - /// Returns the contents of the trailers, or an error which occured, + /// Returns the contents of the trailers, or an error which occurred, /// once the future is ready. /// /// The outer `option` represents future readiness. Users can wait on this @@ -450,17 +556,19 @@ interface types { /// /// The inner `result` represents that either the HTTP Request or Response /// body, as well as any trailers, were received successfully, or that an - /// error occured receiving them. The optional `trailers` indicates whether + /// error occurred receiving them. The optional `trailers` indicates whether /// or not trailers were present in the body. /// /// When some `trailers` are returned by this method, the `trailers` /// resource is immutable, and a child. Use of the `set`, `append`, or /// `delete` methods will return an error, and the resource must be /// dropped before the parent `future-trailers` is dropped. + @since(version = 0.2.0) get: func() -> option, error-code>>>; } /// Represents an outgoing HTTP Response. + @since(version = 0.2.0) resource outgoing-response { /// Construct an `outgoing-response`, with a default `status-code` of `200`. @@ -468,13 +576,16 @@ interface types { /// `set-status-code` method. /// /// * `headers` is the HTTP Headers for the Response. + @since(version = 0.2.0) constructor(headers: headers); /// Get the HTTP Status Code for the Response. + @since(version = 0.2.0) status-code: func() -> status-code; /// Set the HTTP Status Code for the Response. Fails if the status-code /// given is not a valid http status code. + @since(version = 0.2.0) set-status-code: func(status-code: status-code) -> result; /// Get the headers associated with the Request. @@ -483,8 +594,9 @@ interface types { /// `delete` operations will fail with `header-error.immutable`. /// /// This headers resource is a child: it must be dropped before the parent - /// `outgoing-request` is dropped, or its ownership is transfered to + /// `outgoing-request` is dropped, or its ownership is transferred to /// another component by e.g. `outgoing-handler.handle`. + @since(version = 0.2.0) headers: func() -> headers; /// Returns the resource corresponding to the outgoing Body for this Response. @@ -492,6 +604,7 @@ interface types { /// Returns success on the first call: the `outgoing-body` resource for /// this `outgoing-response` can be retrieved at most once. Subsequent /// calls will return error. + @since(version = 0.2.0) body: func() -> result; } @@ -507,10 +620,11 @@ interface types { /// /// If the user code drops this resource, as opposed to calling the static /// method `finish`, the implementation should treat the body as incomplete, - /// and that an error has occured. The implementation should propogate this + /// and that an error has occurred. The implementation should propagate this /// error to the HTTP protocol by whatever means it has available, /// including: corrupting the body on the wire, aborting the associated /// Request, or sending a late status code for the Response. + @since(version = 0.2.0) resource outgoing-body { /// Returns a stream for writing the body contents. @@ -522,6 +636,7 @@ interface types { /// Returns success on the first call: the `output-stream` resource for /// this `outgoing-body` may be retrieved at most once. Subsequent calls /// will return error. + @since(version = 0.2.0) write: func() -> result; /// Finalize an outgoing body, optionally providing trailers. This must be @@ -533,21 +648,24 @@ interface types { /// constructed with a Content-Length header, and the contents written /// to the body (via `write`) does not match the value given in the /// Content-Length. + @since(version = 0.2.0) finish: static func( this: outgoing-body, trailers: option ) -> result<_, error-code>; } - /// Represents a future which may eventaully return an incoming HTTP + /// Represents a future which may eventually return an incoming HTTP /// Response, or an error. /// /// This resource is returned by the `wasi:http/outgoing-handler` interface to /// provide the HTTP Response corresponding to the sent Request. + @since(version = 0.2.0) resource future-incoming-response { /// Returns a pollable which becomes ready when either the Response has - /// been received, or an error has occured. When this pollable is ready, + /// been received, or an error has occurred. When this pollable is ready, /// the `get` method will return `some`. + @since(version = 0.2.0) subscribe: func() -> pollable; /// Returns the incoming HTTP Response, or an error, once one is ready. @@ -560,11 +678,11 @@ interface types { /// is `some`, and error on subsequent calls. /// /// The inner `result` represents that either the incoming HTTP Response - /// status and headers have recieved successfully, or that an error - /// occured. Errors may also occur while consuming the response body, + /// status and headers have received successfully, or that an error + /// occurred. Errors may also occur while consuming the response body, /// but those will be reported by the `incoming-body` and its /// `output-stream` child. + @since(version = 0.2.0) get: func() -> option>>; - } }