From 6724c4061c186b7e69d3b40cf876042c5246f8af Mon Sep 17 00:00:00 2001
From: Pat Hickey
Date: Tue, 6 Oct 2026 13:47:12 -0700
Subject: [PATCH] Limit size of string fields in http request
This PR is motivated by string fields in wasip2 `outgoing-request` and waspi3 `request` resources - specifically, the `scheme` (via the `other` variant), `method` (`other` variant), `authority`, and `path_and_query`, being able to use a host allocation of up to `hostcall-fuel` (128M by default) size strings.
This PR limits the sum those by default to 16k per request, which I picked a reasonable limit given that many http implementations limit the sum of all of these strings plus the headers anywhere from 8k (akamai), 32k (nginx), to 128k (fastly, cloudflare). The limit is tunable in the construction of `WasiHttpCtx`, the C API, and the wasmtime cli (with `-Smax-http-request-strings-size=`).
The limits apply to all requests that come off the wire, as well as those manipulated by the guest, so that we keep the invariant that the guest can proxy (forward) any request it is given. Requests that come off the wire exceeding the limit get rejected with 400 BAD_REQUEST. Along the way, the validation of the host header was made stricter when the request doesn't already have an authority - it now must parse as an `http::uri::Authority`. These changes may end up causing embeddings to reject some requests they previously accepted, but they should be able to tweak the limit to continue accepting any valid requests.
New tests demonstrate this new limit on wasip2 and wasip3. There are some incidental changes to the crate's public api for wasip3, and wasip2's HostOutgoingRequest can no longer be constructed outside the crate through the struct fields, but that one didn't strike me as an intentional aspect of the public API. If there are embedder depending on that, we can make all of the new machinery validation machinery pub, but I chose to keep it as an internal implementation detail.
Also, this PR noticed that the http fields size limit wasn't settable in the C API, so that setting was added as well.
---
crates/c-api/include/wasmtime/_store_class.hh | 31 +++
crates/c-api/include/wasmtime/store.h | 33 +++
crates/c-api/src/store.rs | 34 +++
crates/c-api/tests/wasip2.cc | 23 ++
crates/cli-flags/src/lib.rs | 6 +
crates/test-programs/src/bin/p2_api_proxy.rs | 34 ++-
.../src/bin/p2_cli_http_request_strings.rs | 25 ++
.../src/bin/p3_cli_http_request_strings.rs | 36 +++
crates/wasi-http/src/ctx.rs | 16 ++
crates/wasi-http/src/handler.rs | 19 +-
crates/wasi-http/src/lib.rs | 2 +
crates/wasi-http/src/p2/types.rs | 65 ++++--
crates/wasi-http/src/p2/types_impl.rs | 49 ++--
crates/wasi-http/src/p3/host/types.rs | 57 +++--
crates/wasi-http/src/p3/request.rs | 93 +++++++-
crates/wasi-http/src/request_strings.rs | 215 ++++++++++++++++++
crates/wasi-http/tests/all/p2.rs | 142 ++++++++++++
crates/wasi-http/tests/all/p3/mod.rs | 3 +-
src/common.rs | 3 +
tests/all/cli_tests.rs | 187 +++++++++++++++
20 files changed, 999 insertions(+), 74 deletions(-)
create mode 100644 crates/test-programs/src/bin/p2_cli_http_request_strings.rs
create mode 100644 crates/test-programs/src/bin/p3_cli_http_request_strings.rs
create mode 100644 crates/wasi-http/src/request_strings.rs
diff --git a/crates/c-api/include/wasmtime/_store_class.hh b/crates/c-api/include/wasmtime/_store_class.hh
index 96029d106a2c..9cb97d0ce413 100644
--- a/crates/c-api/include/wasmtime/_store_class.hh
+++ b/crates/c-api/include/wasmtime/_store_class.hh
@@ -152,6 +152,37 @@ public:
}
#endif // WASMTIME_FEATURE_WASI
+#ifdef WASMTIME_FEATURE_WASI_HTTP
+ /// Initializes the WASI HTTP state used by this store.
+ void set_wasi_http() { wasmtime_context_set_wasi_http(ptr); }
+
+ /// Sets the maximum size, in bytes, of each WASI HTTP `fields` resource
+ /// (headers and trailers).
+ ///
+ /// Fails if `set_wasi_http` has not been called on this store.
+ Result set_wasi_http_field_size_limit(size_t limit) {
+ auto *error = wasmtime_context_set_wasi_http_field_size_limit(ptr, limit);
+ if (error != nullptr) {
+ return Error(error);
+ }
+ return std::monostate();
+ }
+
+ /// Sets the maximum combined size, in bytes, of a WASI HTTP request's
+ /// method, scheme, authority, and path-with-query strings.
+ ///
+ /// Fails if `set_wasi_http` has not been called on this store.
+ Result
+ set_wasi_http_request_strings_size_limit(size_t limit) {
+ auto *error =
+ wasmtime_context_set_wasi_http_request_strings_size_limit(ptr, limit);
+ if (error != nullptr) {
+ return Error(error);
+ }
+ return std::monostate();
+ }
+#endif // WASMTIME_FEATURE_WASI_HTTP
+
/// Configures this store's epoch deadline to be the specified number of
/// ticks beyond the engine's current epoch.
///
diff --git a/crates/c-api/include/wasmtime/store.h b/crates/c-api/include/wasmtime/store.h
index 668fe30bc86e..664bfff84d23 100644
--- a/crates/c-api/include/wasmtime/store.h
+++ b/crates/c-api/include/wasmtime/store.h
@@ -208,6 +208,39 @@ wasmtime_context_set_wasi(wasmtime_context_t *context, wasi_config_t *wasi);
WASM_API_EXTERN void
wasmtime_context_set_wasi_http(wasmtime_context_t *context);
+/**
+ * \brief Sets the maximum size, in bytes, of each WASI HTTP `fields` resource
+ * (headers and trailers).
+ *
+ * This is roughly a limit on the in-memory representation of the fields, so it
+ * needs to be larger than their size on the wire. Operations that would
+ * exceed it fail. Defaults to 128 KiB.
+ *
+ * Returns an error if #wasmtime_context_set_wasi_http has not been called on
+ * this store. Calling #wasmtime_context_set_wasi_http again resets the limit to
+ * the default.
+ */
+WASM_API_EXTERN wasmtime_error_t *
+wasmtime_context_set_wasi_http_field_size_limit(wasmtime_context_t *context,
+ size_t limit);
+
+/**
+ * \brief Sets the maximum combined size, in bytes, of a WASI HTTP request's
+ * method, scheme, authority, and path-with-query strings.
+ *
+ * Built-in methods (`GET`, `POST`, ...) and the `http`/`https` schemes don't
+ * count toward the limit. Guest setters that would exceed it return an error,
+ * and incoming requests that exceed it are rejected before reaching the guest.
+ * Defaults to 16 KiB.
+ *
+ * Returns an error if #wasmtime_context_set_wasi_http has not been called on
+ * this store. Calling #wasmtime_context_set_wasi_http again resets the limit to
+ * the default.
+ */
+WASM_API_EXTERN wasmtime_error_t *
+wasmtime_context_set_wasi_http_request_strings_size_limit(
+ wasmtime_context_t *context, size_t limit);
+
#endif // WASMTIME_FEATURE_WASI_HTTP
/**
diff --git a/crates/c-api/src/store.rs b/crates/c-api/src/store.rs
index 3b3c5140d0f8..955bc17e9acb 100644
--- a/crates/c-api/src/store.rs
+++ b/crates/c-api/src/store.rs
@@ -248,6 +248,40 @@ pub extern "C" fn wasmtime_context_set_wasi_http(mut context: WasmtimeStoreConte
context.data_mut().wasi_http = Some(wasmtime_wasi_http::WasiHttpCtx::new());
}
+#[cfg(feature = "wasi-http")]
+fn with_wasi_http(
+ mut context: WasmtimeStoreContextMut<'_>,
+ f: impl FnOnce(&mut wasmtime_wasi_http::WasiHttpCtx),
+) -> Option> {
+ match context.data_mut().wasi_http.as_mut() {
+ Some(http) => {
+ f(http);
+ None
+ }
+ None => Some(Box::new(wasmtime_error_t::from(wasmtime::format_err!(
+ "wasi-http context not set; call `wasmtime_context_set_wasi_http` first"
+ )))),
+ }
+}
+
+#[cfg(feature = "wasi-http")]
+#[unsafe(no_mangle)]
+pub extern "C" fn wasmtime_context_set_wasi_http_field_size_limit(
+ context: WasmtimeStoreContextMut<'_>,
+ limit: usize,
+) -> Option> {
+ with_wasi_http(context, |http| http.set_field_size_limit(limit))
+}
+
+#[cfg(feature = "wasi-http")]
+#[unsafe(no_mangle)]
+pub extern "C" fn wasmtime_context_set_wasi_http_request_strings_size_limit(
+ context: WasmtimeStoreContextMut<'_>,
+ limit: usize,
+) -> Option> {
+ with_wasi_http(context, |http| http.set_request_strings_size_limit(limit))
+}
+
#[unsafe(no_mangle)]
#[cfg(feature = "gc")]
pub extern "C" fn wasmtime_context_gc(
diff --git a/crates/c-api/tests/wasip2.cc b/crates/c-api/tests/wasip2.cc
index 0ab13fb5dc23..493a03d1998b 100644
--- a/crates/c-api/tests/wasip2.cc
+++ b/crates/c-api/tests/wasip2.cc
@@ -44,3 +44,26 @@ TEST(wasip2, smoke) {
linker.add_wasip2().unwrap();
linker.instantiate(context, component).unwrap();
}
+
+#ifdef WASMTIME_FEATURE_WASI_HTTP
+TEST(wasip2, http_limits) {
+ wasmtime::Engine engine;
+ wasmtime::Store store(engine);
+ auto context = store.context();
+
+ // Setting limits before the WASI HTTP context exists is an error.
+ auto err = context.set_wasi_http_field_size_limit(1024);
+ EXPECT_FALSE(err);
+ EXPECT_NE(err.err().message().find("wasmtime_context_set_wasi_http"),
+ std::string::npos);
+ err = context.set_wasi_http_request_strings_size_limit(1024);
+ EXPECT_FALSE(err);
+ EXPECT_NE(err.err().message().find("wasmtime_context_set_wasi_http"),
+ std::string::npos);
+
+ context.set_wasi(wasmtime::WasiConfig()).unwrap();
+ context.set_wasi_http();
+ context.set_wasi_http_field_size_limit(1024).unwrap();
+ context.set_wasi_http_request_strings_size_limit(1024).unwrap();
+}
+#endif // WASMTIME_FEATURE_WASI_HTTP
diff --git a/crates/cli-flags/src/lib.rs b/crates/cli-flags/src/lib.rs
index c551fc30b7a3..d3185cace10c 100644
--- a/crates/cli-flags/src/lib.rs
+++ b/crates/cli-flags/src/lib.rs
@@ -637,6 +637,12 @@ wasmtime_option_group! {
/// `fields` resource (aka `headers` and `trailers`). `fields` methods
/// which cause the contents to exceed this size limit will trap.
pub max_http_fields_size: Option,
+ /// Maximum combined size, in bytes, of a wasi-http request's method,
+ /// scheme, authority, and path-with-query strings. Built-in methods
+ /// and the `http`/`https` schemes don't count. Guest setters that
+ /// would exceed this return an error, and `wasmtime serve` answers
+ /// incoming requests that exceed it with `400 Bad Request`.
+ pub max_http_request_strings_size: Option,
}
enum Wasi {
diff --git a/crates/test-programs/src/bin/p2_api_proxy.rs b/crates/test-programs/src/bin/p2_api_proxy.rs
index 3e2706cdfb8b..e7c7761eb4c0 100644
--- a/crates/test-programs/src/bin/p2_api_proxy.rs
+++ b/crates/test-programs/src/bin/p2_api_proxy.rs
@@ -1,6 +1,7 @@
use anyhow::{Context, Result};
use test_programs::wasi::http::types::{
- Headers, IncomingRequest, Method, OutgoingBody, OutgoingResponse, ResponseOutparam,
+ Fields, Headers, IncomingRequest, Method, OutgoingBody, OutgoingRequest, OutgoingResponse,
+ ResponseOutparam, Scheme,
};
struct T;
@@ -40,6 +41,11 @@ impl test_programs::proxy::exports::wasi::http::incoming_handler::Guest for T {
response_for(r, outparam);
return;
}
+ (Method::Get, Some("/rs")) => {
+ let r = request_strings_handler(&request);
+ response_for(r, outparam);
+ return;
+ }
_ => {}
}
@@ -141,3 +147,29 @@ fn new_fields_handler(request: IncomingRequest) -> Result<()> {
Ok(())
}
+
+/// `/rs` with header `sets: =,...`: on a single fresh outgoing
+/// request, set each `field` in order to a valid string of exactly `len` bytes.
+///
+/// The path is kept short, and the sets are passed in a header, so that the
+/// incoming request itself stays well within a small request strings limit.
+fn request_strings_handler(request: &IncomingRequest) -> Result<()> {
+ let sets = request.headers().get("sets");
+ let sets = std::str::from_utf8(sets.first().context("expect a `sets` header")?)?;
+ let req = OutgoingRequest::new(Fields::new());
+ for set in sets.split(',') {
+ let (field, len) = set
+ .split_once('=')
+ .context("expect sets: =,...")?;
+ let len: usize = len.parse().context("expect len to parse as number")?;
+ let result = match field {
+ "method" => req.set_method(&Method::Other("X".repeat(len))),
+ "path" => req.set_path_with_query(Some(&format!("/{}", "a".repeat(len - 1)))),
+ "scheme" => req.set_scheme(Some(&Scheme::Other("x".repeat(len)))),
+ "authority" => req.set_authority(Some(&"a".repeat(len))),
+ other => anyhow::bail!("unknown field {other:?}"),
+ };
+ result.map_err(|()| anyhow::anyhow!("failed to set {field} of length {len}"))?;
+ }
+ Ok(())
+}
diff --git a/crates/test-programs/src/bin/p2_cli_http_request_strings.rs b/crates/test-programs/src/bin/p2_cli_http_request_strings.rs
new file mode 100644
index 000000000000..c1c08d2b6cf3
--- /dev/null
+++ b/crates/test-programs/src/bin/p2_cli_http_request_strings.rs
@@ -0,0 +1,25 @@
+use wasip2::http::types::{Fields, Method, OutgoingRequest, Scheme};
+
+/// Usage: `=...` where field is one of `method`, `path`, `scheme`,
+/// or `authority`.
+///
+/// Sets each field, in order, on a single request to a valid string of exactly
+/// `len` bytes, printing `ok` or `error received` for each.
+fn main() {
+ let req = OutgoingRequest::new(Fields::new());
+ for arg in std::env::args().skip(1) {
+ let (field, len) = arg.split_once('=').expect("expected =");
+ let len: usize = len.parse().expect("len must be a number");
+ let result = match field {
+ "method" => req.set_method(&Method::Other("X".repeat(len))),
+ "path" => req.set_path_with_query(Some(&format!("/{}", "a".repeat(len - 1)))),
+ "scheme" => req.set_scheme(Some(&Scheme::Other("x".repeat(len)))),
+ "authority" => req.set_authority(Some(&"a".repeat(len))),
+ other => panic!("unknown field {other:?}"),
+ };
+ match result {
+ Ok(()) => println!("ok"),
+ Err(()) => println!("error received"),
+ }
+ }
+}
diff --git a/crates/test-programs/src/bin/p3_cli_http_request_strings.rs b/crates/test-programs/src/bin/p3_cli_http_request_strings.rs
new file mode 100644
index 000000000000..91e6edd7b685
--- /dev/null
+++ b/crates/test-programs/src/bin/p3_cli_http_request_strings.rs
@@ -0,0 +1,36 @@
+use test_programs::p3::wasi::http::types::{Fields, Method, Request, Scheme};
+use test_programs::p3::wit_future;
+
+struct Component;
+
+test_programs::p3::export!(Component);
+
+/// Usage: `=...` where field is one of `method`, `path`, `scheme`,
+/// or `authority`.
+///
+/// Sets each field, in order, on a single request to a valid string of exactly
+/// `len` bytes, printing `ok` or `error received` for each.
+impl test_programs::p3::exports::wasi::cli::run::Guest for Component {
+ async fn run() -> Result<(), ()> {
+ let (_trailers_tx, trailers_rx) = wit_future::new(|| Ok(None));
+ let (req, _transmit) = Request::new(Fields::new(), None, trailers_rx, None);
+ for arg in std::env::args().skip(1) {
+ let (field, len) = arg.split_once('=').expect("expected =");
+ let len: usize = len.parse().expect("len must be a number");
+ let result = match field {
+ "method" => req.set_method(&Method::Other("X".repeat(len))),
+ "path" => req.set_path_with_query(Some(&format!("/{}", "a".repeat(len - 1)))),
+ "scheme" => req.set_scheme(Some(&Scheme::Other("x".repeat(len)))),
+ "authority" => req.set_authority(Some(&"a".repeat(len))),
+ other => panic!("unknown field {other:?}"),
+ };
+ match result {
+ Ok(()) => println!("ok"),
+ Err(()) => println!("error received"),
+ }
+ }
+ Ok(())
+ }
+}
+
+fn main() {}
diff --git a/crates/wasi-http/src/ctx.rs b/crates/wasi-http/src/ctx.rs
index 48bf04416088..076bef0394d0 100644
--- a/crates/wasi-http/src/ctx.rs
+++ b/crates/wasi-http/src/ctx.rs
@@ -120,11 +120,15 @@ pub struct WasiHttpCtxView<'a> {
/// completely full `HeaderMap` doesn't break the bank in terms of memory
/// consumption.
const DEFAULT_FIELD_SIZE_LIMIT: usize = 128 * 1024;
+/// Default limit on the combined size of a request's method, scheme,
+/// authority, and path-with-query strings, to limit host memory use.
+const DEFAULT_REQUEST_STRINGS_SIZE_LIMIT: usize = 16 * 1024;
/// Capture the state necessary for use in the wasi-http API implementation.
#[derive(Debug, Clone)]
pub struct WasiHttpCtx {
pub(crate) field_size_limit: usize,
+ pub(crate) request_strings_size_limit: usize,
}
impl WasiHttpCtx {
@@ -132,6 +136,7 @@ impl WasiHttpCtx {
pub fn new() -> Self {
Self {
field_size_limit: DEFAULT_FIELD_SIZE_LIMIT,
+ request_strings_size_limit: DEFAULT_REQUEST_STRINGS_SIZE_LIMIT,
}
}
@@ -145,6 +150,17 @@ impl WasiHttpCtx {
pub fn set_field_size_limit(&mut self, limit: usize) {
self.field_size_limit = limit;
}
+
+ /// Set the maximum combined size, in bytes, of a request's method,
+ /// scheme, authority, and path-with-query strings.
+ ///
+ /// Built-in methods (`GET`, `POST`, ...) and schemes (`http`, `https`)
+ /// don't count toward this limit. Guest setters which would exceed the
+ /// limit return an error, and incoming requests which exceed it are
+ /// rejected with a `400 Bad Request` before reaching the guest.
+ pub fn set_request_strings_size_limit(&mut self, limit: usize) {
+ self.request_strings_size_limit = limit;
+ }
}
impl Default for WasiHttpCtx {
diff --git a/crates/wasi-http/src/handler.rs b/crates/wasi-http/src/handler.rs
index 47990c2b7d53..f1dd32a5e476 100644
--- a/crates/wasi-http/src/handler.rs
+++ b/crates/wasi-http/src/handler.rs
@@ -1000,9 +1000,22 @@ impl<'a, T: Send> Prepared<'a, T> {
Proxy::P3(guest) => {
let (request, body) = request.into_parts();
let request = http::Request::from_parts(request, body);
- let hooks = view(store.data_mut()).hooks;
- let (request, request_io_result) = p3::Request::from_http(hooks, request);
- let request = view(store.data_mut()).table.push(request)?;
+ let cx = view(store.data_mut());
+ let (request, request_io_result) = match p3::Request::from_http(
+ cx.ctx, cx.hooks, request,
+ ) {
+ Ok(pair) => pair,
+ Err(e) => {
+ // As in the p2 case below, the request never
+ // reaches the guest, so report the failure through
+ // `tx`.
+ _ = tx.send(Err(e));
+ wasmtime::bail!(
+ "request was rejected before it could be turned into a guest request"
+ );
+ }
+ };
+ let request = cx.table.push(request)?;
Ok(Prepared::P3 {
tx,
diff --git a/crates/wasi-http/src/lib.rs b/crates/wasi-http/src/lib.rs
index 02b61743a6e5..06ad7ffe274a 100644
--- a/crates/wasi-http/src/lib.rs
+++ b/crates/wasi-http/src/lib.rs
@@ -29,6 +29,8 @@ pub mod p2;
#[cfg(feature = "p3")]
pub mod p3;
mod request_options;
+#[cfg(any(feature = "p2", feature = "p3"))]
+mod request_strings;
pub use ctx::*;
#[cfg(feature = "default-send-request")]
diff --git a/crates/wasi-http/src/p2/types.rs b/crates/wasi-http/src/p2/types.rs
index c6c13c179cab..e60d16d8c771 100644
--- a/crates/wasi-http/src/p2/types.rs
+++ b/crates/wasi-http/src/p2/types.rs
@@ -9,8 +9,8 @@ use crate::{Error, ErrorResponse, FieldMap, WasiHttpCtxView};
use bytes::Bytes;
use http_body_util::BodyExt;
use hyper::body::Body;
-use wasmtime::Result;
use wasmtime::component::Resource;
+use wasmtime::error::{Context, Result};
use wasmtime_wasi::p2::Pollable;
use wasmtime_wasi::runtime::AbortOnDropJoinHandle;
@@ -66,7 +66,6 @@ pub struct HostIncomingRequest {
pub(crate) uri: http::uri::Uri,
pub(crate) headers: FieldMap,
pub(crate) scheme: Scheme,
- pub(crate) authority: String,
/// The body of the incoming request.
pub body: Option,
}
@@ -83,28 +82,24 @@ impl WasiHttpCtxView<'_> {
B::Error: Into,
{
let (parts, body) = req.into_parts();
+ let parts = normalize_authority(parts, &scheme)
+ .with_context(|| ErrorResponse::new(http::StatusCode::BAD_REQUEST))?;
let body = body.map_err(Into::into).boxed_unsync();
let body = HostIncomingBody::new(body);
- let authority = match parts.uri.authority() {
- Some(authority) => authority.to_string(),
- None => match parts.headers.get(http::header::HOST) {
- Some(host) => host.to_str()?.to_string(),
- None => {
- return Err(wasmtime::Error::msg(
- "invalid HTTP request missing authority in URI and host header",
- )
- .context(ErrorResponse::new(http::StatusCode::BAD_REQUEST)));
- }
- },
- };
+ let mut validator = crate::request_strings::RequestStringsValidator::new(self.ctx);
+ validator.host_parts(
+ &parts.method,
+ parts.uri.scheme(),
+ parts.uri.authority(),
+ parts.uri.path_and_query(),
+ )?;
let headers = FieldMap::new_immutable(self.hooks, parts.headers);
let req = HostIncomingRequest {
method: parts.method,
uri: parts.uri,
headers,
- authority,
scheme,
body: Some(body),
};
@@ -112,6 +107,44 @@ impl WasiHttpCtxView<'_> {
}
}
+/// Ensure `parts.uri` has an authority, taking it from the `Host` header if
+/// necessary. A URI with an authority must also have a scheme, so `scheme`
+/// fills it in when the URI lacks one.
+///
+/// All failures in this function get propogated as a BAD_REQUEST error from the
+/// call site.
+fn normalize_authority(
+ parts: http::request::Parts,
+ scheme: &Scheme,
+) -> Result {
+ if parts.uri.authority().is_some() {
+ return Ok(parts);
+ }
+ if parts.headers.get(http::header::HOST).is_none() {
+ return Err(wasmtime::Error::msg(
+ "invalid HTTP request missing authority in URI and host header",
+ ));
+ }
+ let host: http::uri::Authority = parts
+ .headers
+ .get(http::header::HOST)
+ .unwrap()
+ .to_str()?
+ .parse()?;
+ let mut parts = parts;
+ let mut uri = parts.uri.into_parts();
+ uri.authority = Some(host);
+ if uri.scheme.is_none() {
+ uri.scheme = Some(match scheme {
+ Scheme::Http => http::uri::Scheme::HTTP,
+ Scheme::Https => http::uri::Scheme::HTTPS,
+ Scheme::Other(s) => s.parse()?,
+ });
+ }
+ parts.uri = http::uri::Uri::from_parts(uri)?;
+ Ok(parts)
+}
+
/// The concrete type behind a `wasi:http/types.response-outparam` resource.
pub struct HostResponseOutparam {
/// The callback sending a response.
@@ -202,6 +235,8 @@ pub struct HostOutgoingRequest {
pub headers: FieldMap,
/// The request body.
pub body: Option,
+ /// Accounting for the size of the method, scheme, authority, and path.
+ pub(crate) strings: crate::request_strings::RequestStringsValidator,
}
/// The concrete type behind a `wasi:http/types.incoming-response` resource.
diff --git a/crates/wasi-http/src/p2/types_impl.rs b/crates/wasi-http/src/p2/types_impl.rs
index 73689f37bc6a..cfeeaa2e6ac2 100644
--- a/crates/wasi-http/src/p2/types_impl.rs
+++ b/crates/wasi-http/src/p2/types_impl.rs
@@ -9,7 +9,6 @@ use crate::p2::types::{
use crate::p2::{HeaderError, HeaderResult, HttpError, HttpResult};
use crate::{FieldMap, WasiHttpCtxView, get_content_length};
use http::HeaderName;
-use std::str::FromStr;
use wasmtime::component::Resource;
use wasmtime::{error::Context as _, format_err};
use wasmtime_wasi::p2::{DynInputStream, DynOutputStream, DynPollable};
@@ -155,7 +154,12 @@ impl types::HostIncomingRequest for WasiHttpCtxView<'_> {
}
fn authority(&mut self, id: Resource) -> wasmtime::Result