From c2fab212e648e9a59bd0153bb5059bb1d66e50ff Mon Sep 17 00:00:00 2001
From: Pat Hickey
Date: Fri, 17 Jul 2026 14:34:36 -0700
Subject: [PATCH 1/3] header map translation: do not set FORBIDDEN_HEADERS
the set of FORBIDDEN_HEADERS is derived from wasmtime, with the addition
of Content-Length, and Expect.
---
src/http/fields.rs | 23 +++++++++++++++++++----
1 file changed, 19 insertions(+), 4 deletions(-)
diff --git a/src/http/fields.rs b/src/http/fields.rs
index de6df16..d5a07ec 100644
--- a/src/http/fields.rs
+++ b/src/http/fields.rs
@@ -18,10 +18,25 @@ pub(crate) fn header_map_from_wasi(wasi_fields: Fields) -> Result Result {
let wasi_fields = Fields::new();
for (key, value) in header_map {
- // Unwrap because `HeaderMap` has already validated the headers.
- wasi_fields
- .append(key.as_str(), value.as_bytes())
- .with_context(|| format!("wasi rejected header `{key}: {value:?}`"))?
+ if !FORBIDDEN_HEADERS.contains(key) {
+ wasi_fields
+ .append(key.as_str(), value.as_bytes())
+ .with_context(|| format!("wasi rejected header `{key}: {value:?}`"))?
+ }
}
Ok(wasi_fields)
}
+
+const FORBIDDEN_HEADERS: [HeaderName; 11] = [
+ http::header::CONNECTION,
+ HeaderName::from_static("keep-alive"),
+ http::header::PROXY_AUTHENTICATE,
+ http::header::PROXY_AUTHORIZATION,
+ HeaderName::from_static("proxy-connection"),
+ http::header::TRANSFER_ENCODING,
+ http::header::UPGRADE,
+ http::header::HOST,
+ HeaderName::from_static("http2-settings"),
+ http::header::EXPECT,
+ http::header::CONTENT_LENGTH,
+];
From 0b0692c178c8005e06dd9aa31e49d8f1fd3a4924 Mon Sep 17 00:00:00 2001
From: Pat Hickey
Date: Fri, 17 Jul 2026 14:39:23 -0700
Subject: [PATCH 2/3] server: do not add a Content-Length header
---
src/http/server.rs | 9 ---------
1 file changed, 9 deletions(-)
diff --git a/src/http/server.rs b/src/http/server.rs
index 9fb6ff4..c9a396c 100644
--- a/src/http/server.rs
+++ b/src/http/server.rs
@@ -19,7 +19,6 @@
//! [`http_server`]: crate::http_server
use super::{Body, Error, Response, error::ErrorCode, fields::header_map_to_wasi};
-use http::header::CONTENT_LENGTH;
use wasip2::exports::http::incoming_handler::ResponseOutparam;
use wasip2::http::types::OutgoingResponse;
@@ -44,14 +43,6 @@ impl Responder {
// Consume the `response` and prepare to write the body.
let body = response.into_body().into();
- // Automatically add a Content-Length header.
- if let Some(len) = body.content_length() {
- let mut buffer = itoa::Buffer::new();
- wasi_headers
- .append(CONTENT_LENGTH.as_str(), buffer.format(len).as_bytes())
- .unwrap();
- }
-
let wasi_response = OutgoingResponse::new(wasi_headers);
// Unwrap because `StatusCode` has already validated the status.
From 35872be6bb4df3394a9f11d5a0ee5255879d4906 Mon Sep 17 00:00:00 2001
From: Pat Hickey
Date: Mon, 20 Jul 2026 15:01:42 -0700
Subject: [PATCH 3/3] lowercase search
---
src/http/fields.rs | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/src/http/fields.rs b/src/http/fields.rs
index d5a07ec..4845f9f 100644
--- a/src/http/fields.rs
+++ b/src/http/fields.rs
@@ -18,7 +18,12 @@ pub(crate) fn header_map_from_wasi(wasi_fields: Fields) -> Result Result {
let wasi_fields = Fields::new();
for (key, value) in header_map {
- if !FORBIDDEN_HEADERS.contains(key) {
+ let key = key.as_str().to_ascii_lowercase();
+ if FORBIDDEN_HEADERS
+ .iter()
+ .find(|k| k.as_str() == key)
+ .is_none()
+ {
wasi_fields
.append(key.as_str(), value.as_bytes())
.with_context(|| format!("wasi rejected header `{key}: {value:?}`"))?
@@ -27,6 +32,7 @@ pub(crate) fn header_map_to_wasi(header_map: &HeaderMap) -> Result