Skip to content

Fill in the 'error' variant #52

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Nov 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 94 additions & 14 deletions proxy.md
Original file line number Diff line number Diff line change
Expand Up @@ -644,6 +644,9 @@ their headers, trailers, and bodies.</p>
#### <a name="output_stream">`type output-stream`</a>
[`output-stream`](#output_stream)
<p>
#### <a name="stream_error">`type stream-error`</a>
[`error`](#error)
<p>
#### <a name="pollable">`type pollable`</a>
[`pollable`](#pollable)
<p>
Expand All @@ -670,16 +673,76 @@ their headers, trailers, and bodies.</p>
<li><a name="scheme.https"><code>HTTPS</code></a></li>
<li><a name="scheme.other"><code>other</code></a>: <code>string</code></li>
</ul>
<h4><a name="error"><code>variant error</code></a></h4>
<p>TODO: perhaps better align with HTTP semantics?
This type enumerates the different kinds of errors that may occur when
initially returning a response.</p>
<h4><a name="dns_error_payload"><code>record DNS-error-payload</code></a></h4>
<p>Defines the case payload type for <code>DNS-error</code> above:</p>
<h5>Record Fields</h5>
<ul>
<li><a name="dns_error_payload.rcode"><code>rcode</code></a>: option&lt;<code>string</code>&gt;</li>
<li><a name="dns_error_payload.info_code"><code>info-code</code></a>: option&lt;<code>u16</code>&gt;</li>
</ul>
<h4><a name="tls_alert_received_payload"><code>record TLS-alert-received-payload</code></a></h4>
<p>Defines the case payload type for <code>TLS-alert-received</code> above:</p>
<h5>Record Fields</h5>
<ul>
<li><a name="tls_alert_received_payload.alert_id"><code>alert-id</code></a>: option&lt;<code>u8</code>&gt;</li>
<li><a name="tls_alert_received_payload.alert_message"><code>alert-message</code></a>: option&lt;<code>string</code>&gt;</li>
</ul>
<h4><a name="field_size_payload"><code>record field-size-payload</code></a></h4>
<p>Defines the case payload type for <code>HTTP-response-{header,trailer}-size</code> above:</p>
<h5>Record Fields</h5>
<ul>
<li><a name="field_size_payload.field_name"><code>field-name</code></a>: option&lt;<code>string</code>&gt;</li>
<li><a name="field_size_payload.field_size"><code>field-size</code></a>: option&lt;<code>u32</code>&gt;</li>
</ul>
<h4><a name="error_code"><code>variant error-code</code></a></h4>
<p>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</p>
<h5>Variant Cases</h5>
<ul>
<li><a name="error.invalid_url"><code>invalid-url</code></a>: <code>string</code></li>
<li><a name="error.timeout_error"><code>timeout-error</code></a>: <code>string</code></li>
<li><a name="error.protocol_error"><code>protocol-error</code></a>: <code>string</code></li>
<li><a name="error.unexpected_error"><code>unexpected-error</code></a>: <code>string</code></li>
<li><a name="error_code.dns_timeout"><code>DNS-timeout</code></a></li>
<li><a name="error_code.dns_error"><code>DNS-error</code></a>: <a href="#dns_error_payload"><a href="#dns_error_payload"><code>DNS-error-payload</code></a></a></li>
<li><a name="error_code.destination_not_found"><code>destination-not-found</code></a></li>
<li><a name="error_code.destination_unavailable"><code>destination-unavailable</code></a></li>
<li><a name="error_code.destination_ip_prohibited"><code>destination-IP-prohibited</code></a></li>
<li><a name="error_code.destination_ip_unroutable"><code>destination-IP-unroutable</code></a></li>
<li><a name="error_code.connection_refused"><code>connection-refused</code></a></li>
<li><a name="error_code.connection_terminated"><code>connection-terminated</code></a></li>
<li><a name="error_code.connection_timeout"><code>connection-timeout</code></a></li>
<li><a name="error_code.connection_read_timeout"><code>connection-read-timeout</code></a></li>
<li><a name="error_code.connection_write_timeout"><code>connection-write-timeout</code></a></li>
<li><a name="error_code.connection_limit_reached"><code>connection-limit-reached</code></a></li>
<li><a name="error_code.tls_protocol_error"><code>TLS-protocol-error</code></a></li>
<li><a name="error_code.tls_certificate_error"><code>TLS-certificate-error</code></a></li>
<li><a name="error_code.tls_alert_received"><code>TLS-alert-received</code></a>: <a href="#tls_alert_received_payload"><a href="#tls_alert_received_payload"><code>TLS-alert-received-payload</code></a></a></li>
<li><a name="error_code.http_request_denied"><code>HTTP-request-denied</code></a></li>
<li><a name="error_code.http_request_length_required"><code>HTTP-request-length-required</code></a></li>
<li><a name="error_code.http_request_body_size"><code>HTTP-request-body-size</code></a>: option&lt;<code>u64</code>&gt;</li>
<li><a name="error_code.http_request_method_invalid"><code>HTTP-request-method-invalid</code></a></li>
<li><a name="error_code.http_request_uri_invalid"><code>HTTP-request-URI-invalid</code></a></li>
<li><a name="error_code.http_request_uri_too_long"><code>HTTP-request-URI-too-long</code></a></li>
<li><a name="error_code.http_request_header_section_size"><code>HTTP-request-header-section-size</code></a>: option&lt;<code>u32</code>&gt;</li>
<li><a name="error_code.http_request_header_size"><code>HTTP-request-header-size</code></a>: option&lt;<a href="#field_size_payload"><a href="#field_size_payload"><code>field-size-payload</code></a></a>&gt;</li>
<li><a name="error_code.http_request_trailer_section_size"><code>HTTP-request-trailer-section-size</code></a>: option&lt;<code>u32</code>&gt;</li>
<li><a name="error_code.http_request_trailer_size"><code>HTTP-request-trailer-size</code></a>: <a href="#field_size_payload"><a href="#field_size_payload"><code>field-size-payload</code></a></a></li>
<li><a name="error_code.http_response_incomplete"><code>HTTP-response-incomplete</code></a></li>
<li><a name="error_code.http_response_header_section_size"><code>HTTP-response-header-section-size</code></a>: option&lt;<code>u32</code>&gt;</li>
<li><a name="error_code.http_response_header_size"><code>HTTP-response-header-size</code></a>: <a href="#field_size_payload"><a href="#field_size_payload"><code>field-size-payload</code></a></a></li>
<li><a name="error_code.http_response_body_size"><code>HTTP-response-body-size</code></a>: option&lt;<code>u64</code>&gt;</li>
<li><a name="error_code.http_response_trailer_section_size"><code>HTTP-response-trailer-section-size</code></a>: option&lt;<code>u32</code>&gt;</li>
<li><a name="error_code.http_response_trailer_size"><code>HTTP-response-trailer-size</code></a>: <a href="#field_size_payload"><a href="#field_size_payload"><code>field-size-payload</code></a></a></li>
<li><a name="error_code.http_response_transfer_coding"><code>HTTP-response-transfer-coding</code></a>: option&lt;<code>string</code>&gt;</li>
<li><a name="error_code.http_response_content_coding"><code>HTTP-response-content-coding</code></a>: option&lt;<code>string</code>&gt;</li>
<li><a name="error_code.http_response_timeout"><code>HTTP-response-timeout</code></a></li>
<li><a name="error_code.http_upgrade_failed"><code>HTTP-upgrade-failed</code></a></li>
<li><a name="error_code.http_protocol_error"><code>HTTP-protocol-error</code></a></li>
<li><a name="error_code.loop_detected"><code>loop-detected</code></a></li>
<li><a name="error_code.configuration_error"><code>configuration-error</code></a></li>
<li><a name="error_code.internal_error"><code>internal-error</code></a>: option&lt;<code>string</code>&gt;<p>This is a catch-all error for anything that doesn't fit cleanly into a
more specific case. It also includes an optional string for an
unstructured description of the error. Users should not depend on the
string for diagnosing errors, as it's not required to be consistent
between implementations.
</li>
</ul>
<h4><a name="header_error"><code>variant header-error</code></a></h4>
<p>This type enumerates the different kinds of errors that may occur when
Expand Down Expand Up @@ -728,6 +791,23 @@ so they are provided as a list of bytes.
<h4><a name="future_incoming_response"><code>resource future-incoming-response</code></a></h4>
<hr />
<h3>Functions</h3>
<h4><a name="http_error_code"><code>http-error-code: func</code></a></h4>
<p>Attempts to extract a http-related <a href="#error"><code>error</code></a> from the stream <a href="#error"><code>error</code></a>
provided.</p>
<p>Stream operations which return <a href="#stream_error.last_operation_failed"><code>stream-error::last-operation-failed</code></a> have
a payload with more information about the operation that failed. This
payload can be passed through to this function to see if there's
http-related information about the error to return.</p>
<p>Note that this function is fallible because not all stream-related errors
are http-related errors.</p>
<h5>Params</h5>
<ul>
<li><a name="http_error_code.err"><code>err</code></a>: borrow&lt;<a href="#stream_error"><a href="#stream_error"><code>stream-error</code></a></a>&gt;</li>
</ul>
<h5>Return values</h5>
<ul>
<li><a name="http_error_code.0"></a> option&lt;<a href="#error_code"><a href="#error_code"><code>error-code</code></a></a>&gt;</li>
</ul>
<h4><a name="constructor_fields"><code>[constructor]fields: func</code></a></h4>
<p>Construct an empty HTTP Fields.</p>
<h5>Return values</h5>
Expand Down Expand Up @@ -1118,7 +1198,7 @@ implementation determine how to respond with an HTTP error response.</p>
<h5>Params</h5>
<ul>
<li><a name="static_response_outparam.set.param"><code>param</code></a>: own&lt;<a href="#response_outparam"><a href="#response_outparam"><code>response-outparam</code></a></a>&gt;</li>
<li><a name="static_response_outparam.set.response"><code>response</code></a>: result&lt;own&lt;<a href="#outgoing_response"><a href="#outgoing_response"><code>outgoing-response</code></a></a>&gt;, <a href="#error"><a href="#error"><code>error</code></a></a>&gt;</li>
<li><a name="static_response_outparam.set.response"><code>response</code></a>: result&lt;own&lt;<a href="#outgoing_response"><a href="#outgoing_response"><code>outgoing-response</code></a></a>&gt;, <a href="#error_code"><a href="#error_code"><code>error-code</code></a></a>&gt;</li>
</ul>
<h4><a name="method_incoming_response.status"><code>[method]incoming-response.status: func</code></a></h4>
<p>Returns the status code from the incoming response.</p>
Expand Down Expand Up @@ -1210,7 +1290,7 @@ trailers were present in the body.</p>
</ul>
<h5>Return values</h5>
<ul>
<li><a name="method_future_trailers.get.0"></a> option&lt;result&lt;option&lt;own&lt;<a href="#trailers"><a href="#trailers"><code>trailers</code></a></a>&gt;&gt;, <a href="#error"><a href="#error"><code>error</code></a></a>&gt;&gt;</li>
<li><a name="method_future_trailers.get.0"></a> option&lt;result&lt;option&lt;own&lt;<a href="#trailers"><a href="#trailers"><code>trailers</code></a></a>&gt;&gt;, <a href="#error_code"><a href="#error_code"><code>error-code</code></a></a>&gt;&gt;</li>
</ul>
<h4><a name="constructor_outgoing_response"><code>[constructor]outgoing-response: func</code></a></h4>
<p>Construct an <a href="#outgoing_response"><code>outgoing-response</code></a>, with a default <a href="#status_code"><code>status-code</code></a> of <code>200</code>.
Expand Down Expand Up @@ -1331,7 +1411,7 @@ but those will be reported by the <a href="#incoming_body"><code>incoming-body</
</ul>
<h5>Return values</h5>
<ul>
<li><a name="method_future_incoming_response.get.0"></a> option&lt;result&lt;result&lt;own&lt;<a href="#incoming_response"><a href="#incoming_response"><code>incoming-response</code></a></a>&gt;, <a href="#error"><a href="#error"><code>error</code></a></a>&gt;&gt;&gt;</li>
<li><a name="method_future_incoming_response.get.0"></a> option&lt;result&lt;result&lt;own&lt;<a href="#incoming_response"><a href="#incoming_response"><code>incoming-response</code></a></a>&gt;, <a href="#error_code"><a href="#error_code"><code>error-code</code></a></a>&gt;&gt;&gt;</li>
</ul>
<h2><a name="wasi:http_outgoing_handler">Import interface wasi:http/outgoing-handler</a></h2>
<p>This interface defines a handler of outgoing HTTP Requests. It should be
Expand All @@ -1347,8 +1427,8 @@ imported by components which wish to make HTTP Requests.</p>
#### <a name="future_incoming_response">`type future-incoming-response`</a>
[`future-incoming-response`](#future_incoming_response)
<p>
#### <a name="error">`type error`</a>
[`error`](#error)
#### <a name="error_code">`type error-code`</a>
[`error-code`](#error_code)
<p>
----
<h3>Functions</h3>
Expand All @@ -1368,7 +1448,7 @@ through the <a href="#future_incoming_response"><code>future-incoming-response</
</ul>
<h5>Return values</h5>
<ul>
<li><a name="handle.0"></a> result&lt;own&lt;<a href="#future_incoming_response"><a href="#future_incoming_response"><code>future-incoming-response</code></a></a>&gt;, <a href="#error"><a href="#error"><code>error</code></a></a>&gt;</li>
<li><a name="handle.0"></a> result&lt;own&lt;<a href="#future_incoming_response"><a href="#future_incoming_response"><code>future-incoming-response</code></a></a>&gt;, <a href="#error_code"><a href="#error_code"><code>error-code</code></a></a>&gt;</li>
</ul>
<h2><a name="wasi:http_incoming_handler">Export interface wasi:http/incoming-handler</a></h2>
<hr />
Expand Down
6 changes: 4 additions & 2 deletions wit/handler.wit
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,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.
interface outgoing-handler {
use types.{outgoing-request, request-options, future-incoming-response, error};
use types.{
outgoing-request, request-options, future-incoming-response, error-code
};

/// This function is invoked with an outgoing HTTP Request, and it returns
/// a resource `future-incoming-response` which represents an HTTP Response
Expand All @@ -37,5 +39,5 @@ interface outgoing-handler {
handle: func(
request: outgoing-request,
options: option<request-options>
) -> result<future-incoming-response, error>;
) -> result<future-incoming-response, error-code>;
}
93 changes: 81 additions & 12 deletions wit/types.wit
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
/// their headers, trailers, and bodies.
interface types {
use wasi:clocks/monotonic-clock.{duration};
use wasi:io/streams.{input-stream, output-stream};
use wasi:io/streams.{input-stream, output-stream, error as stream-error};
use wasi:io/poll.{pollable};

/// This type corresponds to HTTP standard Methods.
Expand All @@ -27,16 +27,85 @@ interface types {
other(string)
}

/// TODO: perhaps better align with HTTP semantics?
/// This type enumerates the different kinds of errors that may occur when
/// initially returning a response.
variant error {
invalid-url(string),
timeout-error(string),
protocol-error(string),
unexpected-error(string)
/// 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
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The list below already diverged from the IANA table.

variant error-code {
DNS-timeout,
DNS-error(DNS-error-payload),
destination-not-found,
destination-unavailable,
destination-IP-prohibited,
destination-IP-unroutable,
connection-refused,
connection-terminated,
connection-timeout,
connection-read-timeout,
connection-write-timeout,
connection-limit-reached,
TLS-protocol-error,
TLS-certificate-error,
TLS-alert-received(TLS-alert-received-payload),
HTTP-request-denied,
HTTP-request-length-required,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The generic HTTP-request-error would be still useful, since those listed here don't even cover the existing 4xx error space. Either that, or we should add HTTP-request-* errors covering existing 4xx error codes.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My rationale laid out here is that the remaining 4xx space would best be covered by returning an ok result with the next hop's 4xx response directly conveyed. Unlike the consumer of a proxy-status header, the perspective of the wasi-http client code makes it clear via the result whether the error arises from within the embedder, or from the next hop, so I don't think we need this case which primarily exists to disambiguate whether it was a proxy-generated status code or the next hop's.

Following the addition of the HTTP-request-* variants, are there further 4xx codes that you see being ambiguous? That's probably an indication that we're missing variants still.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The two cases from wasmtime-wasi-http that would be nice to cover are 400 and 405. We don't have anything that maps nicely to 400 right now, which is what was useful about the original HTTP-request-error. We were raising 405 for parse errors from hyper when trying to process the Other case for the Method variant.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@elliottt what errors are you wanting to map to 400?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When we receive an error from hyper that returns true only for is_parse, it's not entirely clear what we should map that to without having HTTP-request-error available. 400 seemed like a good use for that, but without HTTP-request-error I've switched back to HTTP-protocol-error.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that's the right choice. The is_parse() predicate is pretty broad within hyper, but in general indicates that a successful message was not received. But HTTP-request-error(400) would imply that the next hop successfully returned a 400, at least going by its definition in RFC 9209

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the specific case I'm thinking of, where the outgoing-handler needs to reject a Scheme::Other value during request validation. The request hasn't been sent upstream yet, but we still need to indicate that it was malformed. After the change to remove HTTP-request-error there's no longer a good place for that:

bytecodealliance/wasmtime@7af92d0#diff-5dc7fbb5c0f1d7e9bc2d07ee4d374589e46e4c2f054fd6d28b239da1aff426bdL55-L65

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gotcha, I don't think HTTP-request-error would be appropriate for that case regardless, I think we need a HTTP-request-URI-invalid instead

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My rationale laid out here is that the remaining 4xx space would best be covered by returning an ok result with the next hop's 4xx response directly conveyed

But returning ok and 4xx status code would imply that the error came from the peer and not the host environment, wouldn't it?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, the remaining 4xx codes are those that really can't be answered by the environment. If you notice a case we've missed, let's add it as new variants in a follow-up PR

HTTP-request-body-size(option<u64>),
HTTP-request-method-invalid,
HTTP-request-URI-invalid,
HTTP-request-URI-too-long,
HTTP-request-header-section-size(option<u32>),
HTTP-request-header-size(option<field-size-payload>),
Comment on lines +54 to +55
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should also add:

HTTP-request-trailer-section-size(option<u32>),
HTTP-request-trailer-size(field-size-payload),

HTTP-request-trailer-section-size(option<u32>),
HTTP-request-trailer-size(field-size-payload),
HTTP-response-incomplete,
HTTP-response-header-section-size(option<u32>),
HTTP-response-header-size(field-size-payload),
HTTP-response-body-size(option<u64>),
HTTP-response-trailer-section-size(option<u32>),
HTTP-response-trailer-size(field-size-payload),
HTTP-response-transfer-coding(option<string>),
HTTP-response-content-coding(option<string>),
HTTP-response-timeout,
HTTP-upgrade-failed,
HTTP-protocol-error,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This error should only be used when a more specific one is not defined. from https://www.iana.org/assignments/http-proxy-status/http-proxy-status.xhtml#table-http-proxy-error-types - this can represent whatwg fetch's network error concept https://fetch.spec.whatwg.org/#concept-network-error. Maybe this should have an (option<string>) payload so that an implementation can provide extra debugging information if it is available? and the docs should make it clear this is the catch-all case for when no other error could be determined.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe this should have an (option<string>) payload so that an implementation can provide extra debugging information if it is available?

I worry that if we expose this extra debugging information to clients, this will become load-bearing like the situation we have with 503s and custom HTTP/1 reason phrases. Perhaps we could instead encourage embedders to treat this as a cause for internal logging.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, we will not add this information now. We may find some way to provide more debugging or error context in the medium term, but not now.

Copy link
Contributor

@pchickey pchickey Nov 9, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, I think we really need to provide some option<string> here or else we will regret it. For the catch-all error case, we need to have some sort of way for the user to debug why an unexpected error occurred. Like the stream error to-debug-string, we will document that this information is unstable. If programmers ignore that and it breaks their code when it changes, I would prefer that situation to programmers whose code breaks when they move it to a different embedding, but they have no reasonable means to determine why, especially given that the purpose of this standard is to work on many different embedding which will have a variety of constraints which we can't yet imagine. Sending a user off to dig an error out of internal logging is always a much worse solution than just providing a string.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pchickey I think it comes down to who the "user" is that we want to empower to debug. If the user is a person who moves their code from one hosting provider to another and suddenly they start seeing protocol errors for requests to the same origin, that is very unlikely to be actionable by that user. It almost certainly indicates a problem with the embedder or the network between the embedder and the origin. In this situation, adding a free-form string at best gives that user something to paste into the support request with their new provider.

If you have other user profiles in mind that would benefit from the debugging info directly, I don't want to hold up progress on the spec. I would just recommend that any embedder who wants to avoid ossification not populate this field for production traffic.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@acfoltzer that is too narrow a definition of user. This spec already has implementations in progress that will be deployed beyond vendor-managed FaaS. For example the wasmtime-wasi-http implementation is intended to be run via runwasi in kubernetes environments, the jco implementation that could run in multiple different versions of node and node-like engines (deno, bun, etc), and there is interest in implementations that run on top of ServiceWorker, an implementation for nginx unit, and so on. In all of those cases, the user may also be managing major details of the embedding themselves, and the embeddings may encounter errors in ways that are difficult for us to anticipate here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're designating internal-error as the catch-all error case

loop-detected,
configuration-error,
/// This is a catch-all error for anything that doesn't fit cleanly into a
/// more specific case. It also includes an optional string for an
/// unstructured description of the error. Users should not depend on the
/// string for diagnosing errors, as it's not required to be consistent
/// between implementations.
internal-error(option<string>)
}

/// Defines the case payload type for `DNS-error` above:
record DNS-error-payload {
rcode: option<string>,
info-code: option<u16>
}

/// Defines the case payload type for `TLS-alert-received` above:
record TLS-alert-received-payload {
alert-id: option<u8>,
alert-message: option<string>
}

/// Defines the case payload type for `HTTP-response-{header,trailer}-size` above:
record field-size-payload {
field-name: option<string>,
field-size: option<u32>
}

/// Attempts to extract a http-related `error` from the stream `error`
/// provided.
///
/// Stream operations which return `stream-error::last-operation-failed` have
/// a payload with more information about the operation that failed. This
/// payload can be passed through to this function to see if there's
/// http-related information about the error to return.
///
/// Note that this function is fallible because not all stream-related errors
/// are http-related errors.
http-error-code: func(err: borrow<stream-error>) -> option<error-code>;

/// This type enumerates the different kinds of errors that may occur when
/// setting or appending to a `fields` resource.
variant header-error {
Expand Down Expand Up @@ -261,7 +330,7 @@ interface types {
/// implementation determine how to respond with an HTTP error response.
set: static func(
param: response-outparam,
response: result<outgoing-response, error>,
response: result<outgoing-response, error-code>,
);
}

Expand Down Expand Up @@ -336,7 +405,7 @@ interface types {
/// as well as any trailers, were received successfully, or that an error
/// occured receiving them. The optional `trailers` indicates whether or not
/// trailers were present in the body.
get: func() -> option<result<option<trailers>, error>>;
get: func() -> option<result<option<trailers>, error-code>>;
}

/// Represents an outgoing HTTP Response.
Expand Down Expand Up @@ -432,7 +501,7 @@ interface types {
/// occured. Errors may also occur while consuming the response body,
/// but those will be reported by the `incoming-body` and its
/// `output-stream` child.
get: func() -> option<result<result<incoming-response, error>>>;
get: func() -> option<result<result<incoming-response, error-code>>>;

}
}