Skip to content
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

Fill in the 'error' variant #52

Merged
merged 6 commits into from
Nov 10, 2023
Merged

Fill in the 'error' variant #52

merged 6 commits into from
Nov 10, 2023

Conversation

lukewagner
Copy link
Member

As discussed in #49, this PR replaces the current placeholder error variant cases with the error types enumerated by RFC 9209 which are maintained in an IANA table. Note that these specs also specify payloads for some of these error cases which I also reflected in the error case payloads.

The one interesting bit of minutiae, where I'm going with Adam's suggestion, but I have no strong opinions about so happy to hear arguments to the contrary, is that there is no error case corresponding to http_request_error, as this seems like it would turn into an ok result with a 4xx status-code.

Copy link
Collaborator

@Mossaka Mossaka left a comment

Choose a reason for hiding this comment

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

lgtm!

wit/types.wit Outdated Show resolved Hide resolved
@pchickey
Copy link
Contributor

pchickey commented Oct 31, 2023

This PR should also add an http-error: func(stream-error) -> option<error> function for elaborating stream.error into one of these HTTP-specific error variants, see for example WebAssembly/wasi-filesystem#137

wit/types.wit Outdated Show resolved Hide resolved
HTTP-response-content-coding(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

@lukewagner
Copy link
Member Author

This all looks great to me; thanks for all the work @elliottt! (I'd approve, but I can't as the PR author :P)

@acfoltzer
Copy link
Contributor

@lukewagner can we please make sure this is addressed before committing? #52 (comment)

wit/types.wit Outdated Show resolved Hide resolved
@elliottt elliottt force-pushed the error-codes branch 2 times, most recently from 8d40487 to 0ba79a3 Compare November 9, 2023 00:59
wit/types.wit Outdated
TLS-alert-received(TLS-alert-received-payload),
HTTP-request-denied,
HTTP-request-length-required,
HTTP-request-content-too-large,
Copy link
Collaborator

Choose a reason for hiding this comment

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

The corresponding error for the response is HTTP-response-body-size(option<u32>), so this introduces inconsistency within the spec.

Comment on lines +52 to +55
HTTP-request-header-section-size(option<u32>),
HTTP-request-header-size(option<field-size-payload>),
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),

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

wit/types.wit Outdated
HTTP-response-timeout,
HTTP-upgrade-failed,
HTTP-protocol-error,
proxy-internal-response,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Note that this is used to indicate that the intermediate generated the response and didn't forward the request to the next hop. It's not an error condition.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, I think this variant probably doesn't belong, especially because returning an error means we don't get a response for this tag to apply to.

Suggested change
proxy-internal-response,

wit/types.wit Outdated
Comment on lines 66 to 67
proxy-internal-error,
proxy-configuration-error,
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm not sure if those are applicable here?

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 it's useful to have a catch-all "internal error" when implementing an embedder, and setting apart whether that error might have arisen from a bad configuration is helpful too. But we should probably not label them as being specific to a proxy; they could equally apply to incoming- or outgoing-only handler programs.

Suggested change
proxy-internal-error,
proxy-configuration-error,
internal-error,
configuration-error,

protocol-error(string),
unexpected-error(string)
/// The cases of this variant correspond to 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.

@pchickey
Copy link
Contributor

pchickey commented Nov 9, 2023

Thanks everyone for all of the discussion here - I've mentioned this in some other contexts that we are scheduled to cut a release candidate for WASI Preview 2 at the end of this week. I would like to get this PR resolved and merged by the end of Friday Nov 10, even if it means cutting off some discussion and deferring it to a later date. @elliottt and I are going to pair his afternoon to try to resolve these outstanding threads of discussion and get this PR ready to land, and bring the wasmtime implementation up-to-date with it. cc @lukewagner @acfoltzer @PiotrSikora

@elliottt elliottt merged commit 8db6763 into main Nov 10, 2023
1 check passed
@elliottt elliottt deleted the error-codes branch December 5, 2023 19:04
acfoltzer added a commit to acfoltzer/wasi-http that referenced this pull request Feb 21, 2024
I failed to notice this was missing in WebAssembly#52. Status codes outside the range of 100-599 are
[invalid](https://www.rfc-editor.org/rfc/rfc9110#section-15-6), though there is a nod to
implementation-defined behavior outside those valid ranges. In practice we have found it very useful
to return error codes specific to status problems to customers since our platform does not support
codes outside this range, and the next-best option in the RFC 9209 equivalents is the generic
`http-protocol-error` which doesn't help a user much with debugging.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants