From aba4ece034d6e7fb042be1f659ce88faeed909d3 Mon Sep 17 00:00:00 2001 From: Roman Volosatovs Date: Thu, 13 Mar 2025 17:49:31 +0100 Subject: [PATCH 1/8] feat(p3): be less trappy Signed-off-by: Roman Volosatovs --- wit-0.3.0-draft/types.wit | 69 +++++++++++++++++++++++++++++++-------- 1 file changed, 56 insertions(+), 13 deletions(-) diff --git a/wit-0.3.0-draft/types.wit b/wit-0.3.0-draft/types.wit index deec70b..f8f1e8d 100644 --- a/wit-0.3.0-draft/types.wit +++ b/wit-0.3.0-draft/types.wit @@ -265,17 +265,26 @@ interface types { /// Returns the contents of the body, as a stream of bytes. /// - /// This function may be called multiple times as long as any `stream`s - /// returned by previous calls have been dropped first. - /// - /// On success, this function returns a stream and a future, which will resolve + /// This function returns a stream and a future, which will resolve /// to an error code if receiving data from stream fails. - /// The returned future resolves to success if body is closed. - %stream: func() -> result, future>>>; + /// The returned future resolves to success if data section of the + /// body is fully consumed. + /// + /// The handles returned by this function are considered to be child + /// handles. Dropping the resource on which this function is called + /// will close the handles with an error context, if they are still open. + /// + /// This function may be called multiple times. + /// If it is called while either a stream or future returned by a previous + /// call to this function is still open, those handles will be closed + /// with an error context. + %stream: func() -> tuple, future>>; /// Takes ownership of `body`, and returns an unresolved optional `trailers` result. /// - /// This function will trap if a `stream` child is still alive. + /// Developers are encouraged to close any open handles returned by previous + /// calls to `stream`, if any, before calling this function, + /// but calling `finish` will close them with an error context. finish: static func(this: body) -> future, error-code>>; } @@ -356,13 +365,30 @@ interface types { /// Get the body associated with the Request, if any. /// - /// This body resource is a child: it must be dropped before the parent - /// `request` is dropped, or its ownership is transferred to another - /// component by e.g. `handler.handle`. + /// This body resource is a child: it must be dropped or consumed before + /// the parent `request` is dropped, or its ownership is transferred + /// to another component by e.g. `handler.handle`. + /// + /// Only a single body resource can be active at a time. + /// If this function is called before the body resource returned by + /// a previous call to this function is dropped, the previously-returned + /// body will be transitioned into an "error state" and all operations + /// on it will fail. + /// + /// In case, that a `body.finish` was called on the body returned by a previous + /// call to this function, this function returns `none`. body: func() -> option; /// Takes ownership of the `request` and returns the `headers`, `body` /// and `request-options`, if any. + /// + /// The headers returned by this function are considered to be a clone of the headers + /// of the request. Changes to the `headers` returned by this function will not be reflected + /// in the immutable `headers` resources, that could have been acquired by calls to `headers` + /// prior to this function being called. + /// + /// In case, that a `body.finish` was called on the body returned by a previous + /// call to `body`, this function returns body as `none`. into-parts: static func(this: request) -> tuple, option>; } @@ -439,13 +465,30 @@ interface types { /// Get the body associated with the Response, if any. /// - /// This body resource is a child: it must be dropped before the parent - /// `response` is dropped, or its ownership is transferred to another - /// component by e.g. `handler.handle`. + /// This body resource is a child: it should be dropped or consumed before + /// the parent `response` is dropped, or its ownership is transferred + /// to another component by e.g. `handler.handle`. + /// + /// Only a single body resource can be active at a time. + /// If this function is called before the body resource returned by + /// a previous call to this function is dropped, the previously-returned + /// body will be transitioned into an "error state" and all operations + /// on it will fail. + /// + /// In case, that a `body.finish` was called on the body returned by a previous + /// call to this function, this function returns `none`. body: func() -> option; /// Takes ownership of the `response` and returns the `headers` and `body`, /// if any. + /// + /// The headers returned by this function are considered to be a clone of the headers + /// of the response. Changes to the `headers` returned by this function will not be reflected + /// in the immutable `headers` resources, that could have been acquired by calls to `headers` + /// prior to this function being called. + /// + /// In case, that a `body.finish` was called on the body returned by a previous + /// call to `body`, this function returns body as `none`. into-parts: static func(this: response) -> tuple>; } } From 1b2455f5e33d11b33e00a761ecb1a588c0bfadc5 Mon Sep 17 00:00:00 2001 From: Roman Volosatovs Date: Thu, 13 Mar 2025 17:55:12 +0100 Subject: [PATCH 2/8] chore(p3): orphan `headers` returned by `headers()` Signed-off-by: Roman Volosatovs --- wit-0.3.0-draft/types.wit | 8 -------- 1 file changed, 8 deletions(-) diff --git a/wit-0.3.0-draft/types.wit b/wit-0.3.0-draft/types.wit index f8f1e8d..9e8bd76 100644 --- a/wit-0.3.0-draft/types.wit +++ b/wit-0.3.0-draft/types.wit @@ -357,10 +357,6 @@ interface types { /// /// The returned `headers` resource is immutable: `set`, `append`, and /// `delete` operations will fail with `header-error.immutable`. - /// - /// This headers resource is a child: it must be dropped before the parent - /// `request` is dropped, or its ownership is transferred to another - /// component by e.g. `handler.handle`. headers: func() -> headers; /// Get the body associated with the Request, if any. @@ -457,10 +453,6 @@ interface types { /// /// The returned `headers` resource is immutable: `set`, `append`, and /// `delete` operations will fail with `header-error.immutable`. - /// - /// This headers resource is a child: it must be dropped before the parent - /// `response` is dropped, or its ownership is transferred to another - /// component by e.g. `handler.handle`. headers: func() -> headers; /// Get the body associated with the Response, if any. From 128af9415bbd4a0417d317e3c87583eea6dcafeb Mon Sep 17 00:00:00 2001 From: Roman Volosatovs Date: Wed, 19 Mar 2025 13:31:11 +0100 Subject: [PATCH 3/8] doc(p3): improve wording Signed-off-by: Roman Volosatovs --- wit-0.3.0-draft/types.wit | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/wit-0.3.0-draft/types.wit b/wit-0.3.0-draft/types.wit index 9e8bd76..cbd370f 100644 --- a/wit-0.3.0-draft/types.wit +++ b/wit-0.3.0-draft/types.wit @@ -277,7 +277,9 @@ interface types { /// This function may be called multiple times. /// If it is called while either a stream or future returned by a previous /// call to this function is still open, those handles will be closed - /// with an error context. + /// with an error context. Thus there will always be at most one readable stream + /// open for a given body. Each subsequent stream picks up where the last + /// stream left off, up until `finish` is called. %stream: func() -> tuple, future>>; /// Takes ownership of `body`, and returns an unresolved optional `trailers` result. @@ -371,8 +373,8 @@ interface types { /// body will be transitioned into an "error state" and all operations /// on it will fail. /// - /// In case, that a `body.finish` was called on the body returned by a previous - /// call to this function, this function returns `none`. + /// Once `body.finish` is called on a body returned by this method, + /// all subsequent calls to this method will return `none`. body: func() -> option; /// Takes ownership of the `request` and returns the `headers`, `body` @@ -381,10 +383,10 @@ interface types { /// The headers returned by this function are considered to be a clone of the headers /// of the request. Changes to the `headers` returned by this function will not be reflected /// in the immutable `headers` resources, that could have been acquired by calls to `headers` - /// prior to this function being called. + /// prior to this method being called. /// - /// In case, that a `body.finish` was called on the body returned by a previous - /// call to `body`, this function returns body as `none`. + /// Once `body.finish` is called on a body returned by a previous + /// call to `body` method, this method returns body as `none`. into-parts: static func(this: request) -> tuple, option>; } @@ -467,8 +469,8 @@ interface types { /// body will be transitioned into an "error state" and all operations /// on it will fail. /// - /// In case, that a `body.finish` was called on the body returned by a previous - /// call to this function, this function returns `none`. + /// Once `body.finish` is called on a body returned by this method, + /// all subsequent calls to this method will return `none`. body: func() -> option; /// Takes ownership of the `response` and returns the `headers` and `body`, @@ -477,10 +479,10 @@ interface types { /// The headers returned by this function are considered to be a clone of the headers /// of the response. Changes to the `headers` returned by this function will not be reflected /// in the immutable `headers` resources, that could have been acquired by calls to `headers` - /// prior to this function being called. + /// prior to this method being called. /// - /// In case, that a `body.finish` was called on the body returned by a previous - /// call to `body`, this function returns body as `none`. + /// Once `body.finish` is called on a body returned by a previous + /// call to `body` method, this method returns body as `none`. into-parts: static func(this: response) -> tuple>; } } From 55db2ff4cbf824e3bad4e4526e20fe9992e9aa28 Mon Sep 17 00:00:00 2001 From: Roman Volosatovs Date: Wed, 19 Mar 2025 18:39:31 +0100 Subject: [PATCH 4/8] feat(p3): avoid auto-close semantics Signed-off-by: Roman Volosatovs --- wit-0.3.0-draft/types.wit | 53 +++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/wit-0.3.0-draft/types.wit b/wit-0.3.0-draft/types.wit index cbd370f..e808f38 100644 --- a/wit-0.3.0-draft/types.wit +++ b/wit-0.3.0-draft/types.wit @@ -265,29 +265,28 @@ interface types { /// Returns the contents of the body, as a stream of bytes. /// - /// This function returns a stream and a future, which will resolve + /// This method returns a stream and a future, which will resolve /// to an error code if receiving data from stream fails. /// The returned future resolves to success if data section of the /// body is fully consumed. /// - /// The handles returned by this function are considered to be child - /// handles. Dropping the resource on which this function is called + /// The handles returned by this method are considered to be child + /// handles. Dropping the resource on which this method is called /// will close the handles with an error context, if they are still open. /// - /// This function may be called multiple times. - /// If it is called while either a stream or future returned by a previous - /// call to this function is still open, those handles will be closed - /// with an error context. Thus there will always be at most one readable stream - /// open for a given body. Each subsequent stream picks up where the last - /// stream left off, up until `finish` is called. - %stream: func() -> tuple, future>>; + /// This method may be called multiple times. + /// If it is called while either a stream or future returned by a previous + /// call to this method is still open, this method will return an error. + /// Thus there will always be at most one readable stream open for a given body. + /// Each subsequent stream picks up where the last stream left off, + /// up until `finish` is called. + %stream: func() -> result, future>>>; /// Takes ownership of `body`, and returns an unresolved optional `trailers` result. /// - /// Developers are encouraged to close any open handles returned by previous - /// calls to `stream`, if any, before calling this function, - /// but calling `finish` will close them with an error context. - finish: static func(this: body) -> future, error-code>>; + /// If this function is called while either a stream or future returned by a previous + /// call to `body.stream` is still open, this function will return an error. + finish: static func(this: body) -> result, error-code>>>; } /// Represents an HTTP Request. @@ -368,14 +367,12 @@ interface types { /// to another component by e.g. `handler.handle`. /// /// Only a single body resource can be active at a time. - /// If this function is called before the body resource returned by - /// a previous call to this function is dropped, the previously-returned - /// body will be transitioned into an "error state" and all operations - /// on it will fail. + /// If this method is called before the body resource returned by + /// a previous call to this method is dropped, error will be returned. /// /// Once `body.finish` is called on a body returned by this method, - /// all subsequent calls to this method will return `none`. - body: func() -> option; + /// all subsequent calls to this method will return `ok(none)`. + body: func() -> result>; /// Takes ownership of the `request` and returns the `headers`, `body` /// and `request-options`, if any. @@ -385,6 +382,8 @@ interface types { /// in the immutable `headers` resources, that could have been acquired by calls to `headers` /// prior to this method being called. /// + /// If a body child exists when this function is called, an error will be returned. + /// /// Once `body.finish` is called on a body returned by a previous /// call to `body` method, this method returns body as `none`. into-parts: static func(this: request) -> tuple, option>; @@ -464,14 +463,12 @@ interface types { /// to another component by e.g. `handler.handle`. /// /// Only a single body resource can be active at a time. - /// If this function is called before the body resource returned by - /// a previous call to this function is dropped, the previously-returned - /// body will be transitioned into an "error state" and all operations - /// on it will fail. + /// If this method is called before the body resource returned by + /// a previous call to this method is dropped, error will be returned. /// /// Once `body.finish` is called on a body returned by this method, - /// all subsequent calls to this method will return `none`. - body: func() -> option; + /// all subsequent calls to this method will return `ok(none)`. + body: func() -> result>; /// Takes ownership of the `response` and returns the `headers` and `body`, /// if any. @@ -481,8 +478,10 @@ interface types { /// in the immutable `headers` resources, that could have been acquired by calls to `headers` /// prior to this method being called. /// + /// If a body child exists when this function is called, an error will be returned. + /// /// Once `body.finish` is called on a body returned by a previous /// call to `body` method, this method returns body as `none`. - into-parts: static func(this: response) -> tuple>; + into-parts: static func(this: response) -> result>>; } } From 70ad39c6a2c28ba91399f202e032298a88ecb531 Mon Sep 17 00:00:00 2001 From: Roman Volosatovs Date: Thu, 20 Mar 2025 13:52:39 +0100 Subject: [PATCH 5/8] p3: allow multiple active body refs to exist, drop `into-parts` Signed-off-by: Roman Volosatovs --- wit-0.3.0-draft/types.wit | 56 ++++++++------------------------------- 1 file changed, 11 insertions(+), 45 deletions(-) diff --git a/wit-0.3.0-draft/types.wit b/wit-0.3.0-draft/types.wit index e808f38..3b3dfd6 100644 --- a/wit-0.3.0-draft/types.wit +++ b/wit-0.3.0-draft/types.wit @@ -275,17 +275,19 @@ interface types { /// will close the handles with an error context, if they are still open. /// /// This method may be called multiple times. - /// If it is called while either a stream or future returned by a previous - /// call to this method is still open, this method will return an error. + /// This method will return an error if it is called while either: + /// - a stream or future returned by a previous call to this method is still open + /// - `finish` was called on another instance of this `body` resource /// Thus there will always be at most one readable stream open for a given body. /// Each subsequent stream picks up where the last stream left off, - /// up until `finish` is called. + /// up until `finish` is called on any of the instances of this `body` resource %stream: func() -> result, future>>>; /// Takes ownership of `body`, and returns an unresolved optional `trailers` result. /// - /// If this function is called while either a stream or future returned by a previous - /// call to `body.stream` is still open, this function will return an error. + /// This function will return an error if it is called while either: + /// - a stream or future returned by a previous call to `body.stream` is still open + /// - `finish` was already called on another instance of this `body` resource finish: static func(this: body) -> result, error-code>>>; } @@ -366,27 +368,9 @@ interface types { /// the parent `request` is dropped, or its ownership is transferred /// to another component by e.g. `handler.handle`. /// - /// Only a single body resource can be active at a time. - /// If this method is called before the body resource returned by - /// a previous call to this method is dropped, error will be returned. - /// /// Once `body.finish` is called on a body returned by this method, - /// all subsequent calls to this method will return `ok(none)`. - body: func() -> result>; - - /// Takes ownership of the `request` and returns the `headers`, `body` - /// and `request-options`, if any. - /// - /// The headers returned by this function are considered to be a clone of the headers - /// of the request. Changes to the `headers` returned by this function will not be reflected - /// in the immutable `headers` resources, that could have been acquired by calls to `headers` - /// prior to this method being called. - /// - /// If a body child exists when this function is called, an error will be returned. - /// - /// Once `body.finish` is called on a body returned by a previous - /// call to `body` method, this method returns body as `none`. - into-parts: static func(this: request) -> tuple, option>; + /// all subsequent calls to this method will return `none`. + body: func() -> option; } /// Parameters for making an HTTP Request. Each of these parameters is @@ -462,26 +446,8 @@ interface types { /// the parent `response` is dropped, or its ownership is transferred /// to another component by e.g. `handler.handle`. /// - /// Only a single body resource can be active at a time. - /// If this method is called before the body resource returned by - /// a previous call to this method is dropped, error will be returned. - /// /// Once `body.finish` is called on a body returned by this method, - /// all subsequent calls to this method will return `ok(none)`. - body: func() -> result>; - - /// Takes ownership of the `response` and returns the `headers` and `body`, - /// if any. - /// - /// The headers returned by this function are considered to be a clone of the headers - /// of the response. Changes to the `headers` returned by this function will not be reflected - /// in the immutable `headers` resources, that could have been acquired by calls to `headers` - /// prior to this method being called. - /// - /// If a body child exists when this function is called, an error will be returned. - /// - /// Once `body.finish` is called on a body returned by a previous - /// call to `body` method, this method returns body as `none`. - into-parts: static func(this: response) -> result>>; + /// all subsequent calls to this method will return `none`. + body: func() -> option; } } From eac841641f35b68351542864ae4746b6fbdd760f Mon Sep 17 00:00:00 2001 From: Roman Volosatovs Date: Thu, 20 Mar 2025 13:53:13 +0100 Subject: [PATCH 6/8] p3: add `request-options#clone` Signed-off-by: Roman Volosatovs --- wit-0.3.0-draft/types.wit | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/wit-0.3.0-draft/types.wit b/wit-0.3.0-draft/types.wit index 3b3dfd6..5347016 100644 --- a/wit-0.3.0-draft/types.wit +++ b/wit-0.3.0-draft/types.wit @@ -407,6 +407,10 @@ interface types { /// body stream. An error return value indicates that this timeout is not /// supported or that this handle is immutable. set-between-bytes-timeout: func(duration: option) -> result<_, request-options-error>; + + /// Make a deep copy of the `request-options`. + /// The resulting `request-options` is mutable. + clone: func() -> request-options; } /// This type corresponds to the HTTP standard Status Code. From f927cf482f0a4953177b4a931ccbd14c361acec8 Mon Sep 17 00:00:00 2001 From: Roman Volosatovs Date: Wed, 19 Mar 2025 18:55:17 +0100 Subject: [PATCH 7/8] p3: model `body` after `stream` Signed-off-by: Roman Volosatovs --- wit-0.3.0-draft/types.wit | 35 ++++++++++++----------------------- 1 file changed, 12 insertions(+), 23 deletions(-) diff --git a/wit-0.3.0-draft/types.wit b/wit-0.3.0-draft/types.wit index 5347016..6a87842 100644 --- a/wit-0.3.0-draft/types.wit +++ b/wit-0.3.0-draft/types.wit @@ -240,27 +240,18 @@ interface types { /// trailers at any given time. resource body { - /// Construct a new `body` with the specified stream. + /// Construct a new `body` with the specified stream and `finish` future. /// - /// This function returns a future, which will resolve - /// to an error code if transmitting stream data fails. + /// The `finish` future must resolve to a result once `stream` has finished. /// - /// The returned future resolves to success once body stream - /// is fully transmitted. - new: static func( - %stream: stream, - ) -> tuple>>; - - /// Construct a new `body` with the specified stream and trailers. - /// - /// This function returns a future, which will resolve - /// to an error code if transmitting stream data or trailers fails. + /// This function returns a future, which will resolve to an error code if + /// transmitting of the request or response this body is a part of fails. /// - /// The returned future resolves to success once body stream and trailers - /// are fully transmitted. - new-with-trailers: static func( + /// The returned future resolves to success once request or response this + /// body is a part of is fully transmitted. + new: static func( %stream: stream, - trailers: future + finish: future, error-code>>, ) -> tuple>>; /// Returns the contents of the body, as a stream of bytes. @@ -298,8 +289,7 @@ interface types { /// `none` values for `path-with-query`, `scheme`, and `authority`. /// /// * `headers` is the HTTP Headers for the Response. - /// * `body` is the optional contents of the body, possibly including - /// trailers. + /// * `body` is the contents of the body, possibly including trailers. /// * `options` is optional `request-options` to be used if the request is /// sent over a network connection. /// @@ -310,7 +300,7 @@ interface types { /// to reject invalid constructions of `request`. constructor( headers: headers, - body: option, + body: body, options: option ); @@ -424,11 +414,10 @@ interface types { /// `set-status-code` method. /// /// * `headers` is the HTTP Headers for the Response. - /// * `body` is the optional contents of the body, possibly including - /// trailers. + /// * `body` is the contents of the body, possibly including trailers. constructor( headers: headers, - body: option, + body: body, ); /// Get the HTTP Status Code for the Response. From 865daa52084c3751c972a720912db7ca4a374302 Mon Sep 17 00:00:00 2001 From: Roman Volosatovs Date: Fri, 21 Mar 2025 15:33:40 +0100 Subject: [PATCH 8/8] p3: remove `body` resource Signed-off-by: Roman Volosatovs --- wit-0.3.0-draft/types.wit | 149 +++++++++++++++++--------------------- 1 file changed, 67 insertions(+), 82 deletions(-) diff --git a/wit-0.3.0-draft/types.wit b/wit-0.3.0-draft/types.wit index 6a87842..2112750 100644 --- a/wit-0.3.0-draft/types.wit +++ b/wit-0.3.0-draft/types.wit @@ -230,79 +230,35 @@ interface types { /// Trailers is an alias for Fields. type trailers = fields; - /// Represents an HTTP Request or Response's Body. - /// - /// A body has both its contents - a stream of bytes - and a (possibly empty) - /// set of trailers, indicating that the full contents of the body have been - /// received. This resource represents the contents as a `stream` and the - /// delivery of trailers as a `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. - resource body { - - /// Construct a new `body` with the specified stream and `finish` future. - /// - /// The `finish` future must resolve to a result once `stream` has finished. - /// - /// This function returns a future, which will resolve to an error code if - /// transmitting of the request or response this body is a part of fails. - /// - /// The returned future resolves to success once request or response this - /// body is a part of is fully transmitted. - new: static func( - %stream: stream, - finish: future, error-code>>, - ) -> tuple>>; - - /// Returns the contents of the body, as a stream of bytes. - /// - /// This method returns a stream and a future, which will resolve - /// to an error code if receiving data from stream fails. - /// The returned future resolves to success if data section of the - /// body is fully consumed. - /// - /// The handles returned by this method are considered to be child - /// handles. Dropping the resource on which this method is called - /// will close the handles with an error context, if they are still open. - /// - /// This method may be called multiple times. - /// This method will return an error if it is called while either: - /// - a stream or future returned by a previous call to this method is still open - /// - `finish` was called on another instance of this `body` resource - /// Thus there will always be at most one readable stream open for a given body. - /// Each subsequent stream picks up where the last stream left off, - /// up until `finish` is called on any of the instances of this `body` resource - %stream: func() -> result, future>>>; - - /// Takes ownership of `body`, and returns an unresolved optional `trailers` result. - /// - /// This function will return an error if it is called while either: - /// - a stream or future returned by a previous call to `body.stream` is still open - /// - `finish` was already called on another instance of this `body` resource - finish: static func(this: body) -> result, error-code>>>; - } - /// Represents an HTTP Request. resource request { /// Construct a new `request` with a default `method` of `GET`, and /// `none` values for `path-with-query`, `scheme`, and `authority`. /// - /// * `headers` is the HTTP Headers for the Response. - /// * `body` is the contents of the body, possibly including trailers. - /// * `options` is optional `request-options` to be used if the request is - /// sent over a network connection. + /// `headers` is the HTTP Headers for the Request. + /// + /// `contents` is the body content stream. Once it is closed, + /// `trailers` future must resolve to a result. + /// If `trailers` resolves to an error, underlying connection + /// will be closed immediately. + /// + /// `options` is optional `request-options` resource to be used + /// if the request is sent over a network connection. /// /// It is possible to construct, or manipulate with the accessor functions - /// below, an `request` with an invalid combination of `scheme` + /// below, a `request` with an invalid combination of `scheme` /// and `authority`, or `headers` which are not permitted to be sent. /// It is the obligation of the `handler.handle` implementation /// to reject invalid constructions of `request`. - constructor( + /// + /// The returned future resolves to result of transmission of this request. + new: static func( headers: headers, - body: body, + contents: stream, + trailers: future, error-code>>, options: option - ); + ) -> tuple>>; /// Get the Method for the Request. method: func() -> method; @@ -352,15 +308,26 @@ interface types { /// `delete` operations will fail with `header-error.immutable`. headers: func() -> headers; - /// Get the body associated with the Request, if any. + /// Get body of the Request. /// - /// This body resource is a child: it must be dropped or consumed before - /// the parent `request` is dropped, or its ownership is transferred - /// to another component by e.g. `handler.handle`. + /// Stream returned by this method represents the contents of the body. + /// Once the stream is reported as closed, callers should await the returned future + /// to determine whether the body was received successfully. + /// The future will only resolve after the stream is reported as closed. /// - /// Once `body.finish` is called on a body returned by this method, - /// all subsequent calls to this method will return `none`. - body: func() -> option; + /// The stream and future returned by this method are children: + /// they should be closed or consumed before the parent `response` + /// is dropped, or its ownership is transferred to another component + /// by e.g. `handler.handle`. + /// + /// This method may be called multiple times. + /// + /// This method will return `none` if it is called while either: + /// - a stream or future returned by a previous call to this method is still open + /// - a stream returned by a previous call to this method has reported itself as closed + /// Thus there will always be at most one readable stream open for a given body. + /// Each subsequent stream picks up where the last stream left off, up until it is finished. + body: func() -> option, future, error-code>>>>; } /// Parameters for making an HTTP Request. Each of these parameters is @@ -409,16 +376,23 @@ interface types { /// Represents an HTTP Response. resource response { - /// Construct an `response`, with a default `status-code` of `200`. If a - /// different `status-code` is needed, it must be set via the + /// Construct a new `response`, with a default `status-code` of `200`. + /// If a different `status-code` is needed, it must be set via the /// `set-status-code` method. /// - /// * `headers` is the HTTP Headers for the Response. - /// * `body` is the contents of the body, possibly including trailers. - constructor( + /// `headers` is the HTTP Headers for the Response. + /// + /// `contents` is the body content stream. Once it is closed, + /// `trailers` future must resolve to a result. + /// If `trailers` resolves to an error, underlying connection + /// will be closed immediately. + /// + /// The returned future resolves to result of transmission of this response. + new: static func( headers: headers, - body: body, - ); + contents: stream, + trailers: future, error-code>>, + ) -> tuple>>; /// Get the HTTP Status Code for the Response. status-code: func() -> status-code; @@ -427,20 +401,31 @@ interface types { /// given is not a valid http status code. set-status-code: func(status-code: status-code) -> result; - /// Get the headers associated with the Request. + /// Get the headers associated with the Response. /// /// The returned `headers` resource is immutable: `set`, `append`, and /// `delete` operations will fail with `header-error.immutable`. headers: func() -> headers; - /// Get the body associated with the Response, if any. + /// Get body of the Response. + /// + /// Stream returned by this method represents the contents of the body. + /// Once the stream is reported as closed, callers should await the returned future + /// to determine whether the body was received successfully. + /// The future will only resolve after the stream is reported as closed. /// - /// This body resource is a child: it should be dropped or consumed before - /// the parent `response` is dropped, or its ownership is transferred - /// to another component by e.g. `handler.handle`. + /// The stream and future returned by this method are children: + /// they should be closed or consumed before the parent `response` + /// is dropped, or its ownership is transferred to another component + /// by e.g. `handler.handle`. /// - /// Once `body.finish` is called on a body returned by this method, - /// all subsequent calls to this method will return `none`. - body: func() -> option; + /// This method may be called multiple times. + /// + /// This method will return `none` if it is called while either: + /// - a stream or future returned by a previous call to this method is still open + /// - a stream returned by a previous call to this method has reported itself as closed + /// Thus there will always be at most one readable stream open for a given body. + /// Each subsequent stream picks up where the last stream left off, up until it is finished. + body: func() -> option, future, error-code>>>>; } }