xia-chao opened PR #14432 from xia-chao:serve-host-400 to bytecodealliance:main:
wasmtime servereturns 500 when an HTTP/1.1 request has noHostheader.
RFC 9112 section 3.2 says it should be a 400, so this changes it to that.
Only the status code changes; whether such a request should be refused at all
was settled in #8923 and is left alone.
xia-chao requested pchickey for a review on PR #14432.
xia-chao requested wasmtime-core-reviewers for a review on PR #14432.
xia-chao edited PR #14432:
wasmtime servereturns 500 when an HTTP/1.1 request has noHostheader.
RFC 9112 section 3.2 says it should be a 400, so this changes it to that.
Only the status code changes; whether such a request should be refused at all
was settled in #8923
xia-chao updated PR #14432.
:repeat: pchickey submitted PR review:
I think this comes down to an architectural decision for whether the guest or host code is responsible for enforcing the RFC invariant. De facto in this implementation, if hyper didn't enforce an RFC invariant, then it would be up to the guest to enforce it. That's not a principled decision, it was just the way things shook out, and other hosts very likely end up handling broken RFC invariants differently than the exact way hyper handles them.
So, we could enforce this particular RFC invariant here, but then the questions are:
- why, exactly, do we not enforce it for p3? The comment here doesn't make sense to me, because in p2 the guest is also capable of observing whether authority is none.
- what other RFC invariants is our implementation not enforcing in the host? Do we add them all here?
- What from this do we need to feed into specification of the wasi-http implementation?
Want to call this out to other maintainers here, cc @lann
If
new_incoming_requestis going to validate host/authority presence then by spec it should be returning a 400. Pragmatically I'm not sure where that would make a difference.
xia-chao commented on PR #14432:
Fair — the comment was wrong. I tested both worlds: the proxy path already fails on a Host-less request, we just turned the 500 into a 400. The service path doesn't fail, it just never gets the host. Happy to look into that instead if you'd rather.
xia-chao edited a comment on PR #14432:
Fair — the comment was wrong. I tested both worlds: the proxy path already fails on a Host-less request, we just turned the 500 into a 400. The service path doesn't fail, it just never gets the host.
xia-chao commented on PR #14432:
though it also can't see the host at all. Should I drop this, or dig into that?
xia-chao edited a comment on PR #14432:
Should I drop this, or dig into that?
Could you say more about your motivation for this change?
xia-chao commented on PR #14432:
RFC 9112 §3.2 says an HTTP/1.1 request without Host must get 400, and §3.3 lets the server reject an empty authority, so rejecting is fine — ours just surfaces as a 500 with "worker trapped or panicked", which reads as our bug. Only the status code changes.
pchickey commented on PR #14432:
@xia-chao Its possible to modify your guest code to give the correct status, correct?
@xia-chao Its possible to modify your guest code to give the correct status, correct?
No, that's the whole problem.
wasmtime-wasi-httpbails before it gets to the guest: https://github.com/bytecodealliance/wasmtime/blob/1bc343e789c52f09e8a511605e6adc1559bc09d2/crates/wasi-http/src/p2/types.rs#L92
xia-chao commented on PR #14432:
No — the host rejects it before the guest runs: "invalid HTTP request missing authority in URI and host header". A duplicate or invalid Host does reach the guest.
xia-chao deleted a comment on PR #14432:
Should I drop this, or dig into that?
lann edited a comment on PR #14432:
@xia-chao Its possible to modify your guest code to give the correct status, correct?
No, that's the whole problem;
wasmtime-wasi-httpbails before it gets to the guest: https://github.com/bytecodealliance/wasmtime/blob/1bc343e789c52f09e8a511605e6adc1559bc09d2/crates/wasi-http/src/p2/types.rs#L92
xia-chao commented on PR #14432:
It's a bug, not a preference.
pchickey commented on PR #14432:
OK, I apologize, I missed that, now I understand what both of you are saying.
We don't want to duplicate the logic of detecting this 400 Bad Request. Instead, we should change the place the bad request is detected to also include what status code Wasmtime serve should respond with. So, instead of this patch, the architecture I'd like to see is:
- add a
pub struct ErrorResponse { status: StatusCode } impl ErrorResponse { pub fn new(status: HttpStatusCode) -> Self {...} pub fn status(&self) -> StatusCode {...} }to wasmtime-wasi-http, with derive Debug, impls Display ("error response: {}"), and impl std::error::Error. This struct has opaque fields so that we can extend it in the future with more, if applicable.- change the
baillinked to have, additionally,.context(ErrorResponse::new(StatusCode::BAD_REQUEST))- in the Err case handler in wasmtime-cli's serve.rs, try to downcast the error to an ErrorResponse and get the status, with a default to 500 if the downcast fails. Put that status that into the status code of the response, as well as the html response body. The current hard-coded 500 response body should become a template. Use https://docs.rs/http/latest/http/status/struct.StatusCode.html#method.canonical_reason for the non-numeric description.
pchickey edited a comment on PR #14432:
OK, I apologize, I missed that, now I understand what both of you are saying.
We don't want to duplicate the logic of detecting this 400 Bad Request. Instead, we should change the place the bad request is detected to also include what status code Wasmtime serve should respond with. So, instead of this patch, the architecture I'd like to see is:
- add a
pub struct ErrorResponse { status: StatusCode } impl ErrorResponse { pub fn new(status: StatusCode) -> Self {...} pub fn status(&self) -> StatusCode {...} }to wasmtime-wasi-http, with derive Debug, impls Display ("error response: {}"), and impl std::error::Error. This struct has opaque fields so that we can extend it in the future with more, if applicable.- change the
baillinked to have, additionally,.context(ErrorResponse::new(StatusCode::BAD_REQUEST))- in the Err case handler in wasmtime-cli's serve.rs, try to downcast the error to an ErrorResponse and get the status, with a default to 500 if the downcast fails. Put that status that into the status code of the response, as well as the html response body. The current hard-coded 500 response body should become a template. Use https://docs.rs/http/latest/http/status/struct.StatusCode.html#method.canonical_reason for the non-numeric description.
Last updated: Oct 11 2026 at 04:10 UTC