diff --git a/crates/cli-flags/src/lib.rs b/crates/cli-flags/src/lib.rs index 938928560a6b..f819f8d544ca 100644 --- a/crates/cli-flags/src/lib.rs +++ b/crates/cli-flags/src/lib.rs @@ -375,6 +375,13 @@ wasmtime_option_group! { pub threads: Option, /// Enable support for WASI HTTP imports pub http: Option, + /// Number of distinct write calls to the outgoing body's output-stream + /// that the implementation will buffer. + /// Default: 1. + pub http_outgoing_body_buffer_chunks: Option, + /// Maximum size allowed in a write call to the outgoing body's output-stream. + /// Default: 1024 * 1024. + pub http_outgoing_body_chunk_size: Option, /// Enable support for WASI config imports (experimental) pub config: Option, /// Enable support for WASI key-value imports (experimental) diff --git a/crates/wasi-http/src/lib.rs b/crates/wasi-http/src/lib.rs index 1d5c5391105d..baf4bd6ba98d 100644 --- a/crates/wasi-http/src/lib.rs +++ b/crates/wasi-http/src/lib.rs @@ -232,7 +232,10 @@ pub use crate::error::{ http_request_error, hyper_request_error, hyper_response_error, HttpError, HttpResult, }; #[doc(inline)] -pub use crate::types::{WasiHttpCtx, WasiHttpImpl, WasiHttpView}; +pub use crate::types::{ + WasiHttpCtx, WasiHttpImpl, WasiHttpView, DEFAULT_OUTGOING_BODY_BUFFER_CHUNKS, + DEFAULT_OUTGOING_BODY_CHUNK_SIZE, +}; /// Add all of the `wasi:http/proxy` world's interfaces to a [`wasmtime::component::Linker`]. /// diff --git a/crates/wasi-http/src/types.rs b/crates/wasi-http/src/types.rs index 912c72513b0e..bb2935f0b820 100644 --- a/crates/wasi-http/src/types.rs +++ b/crates/wasi-http/src/types.rs @@ -130,16 +130,21 @@ pub trait WasiHttpView: Send { /// that the implementation will buffer. /// Default: 1. fn outgoing_body_buffer_chunks(&mut self) -> usize { - 1 + DEFAULT_OUTGOING_BODY_BUFFER_CHUNKS } /// Maximum size allowed in a write call to the outgoing body's output-stream. /// Default: 1024 * 1024. fn outgoing_body_chunk_size(&mut self) -> usize { - 1024 * 1024 + DEFAULT_OUTGOING_BODY_CHUNK_SIZE } } +/// The default value configured for [`WasiHttpView::outgoing_body_buffer_chunks`] in [`WasiHttpView`]. +pub const DEFAULT_OUTGOING_BODY_BUFFER_CHUNKS: usize = 1; +/// The default value configured for [`WasiHttpView::outgoing_body_chunk_size`] in [`WasiHttpView`]. +pub const DEFAULT_OUTGOING_BODY_CHUNK_SIZE: usize = 1024 * 1024; + impl WasiHttpView for &mut T { fn ctx(&mut self) -> &mut WasiHttpCtx { T::ctx(self) diff --git a/src/commands/run.rs b/src/commands/run.rs index 46021a6529b0..e154ad50542c 100644 --- a/src/commands/run.rs +++ b/src/commands/run.rs @@ -26,7 +26,9 @@ use wasmtime_wasi_threads::WasiThreadsCtx; #[cfg(feature = "wasi-config")] use wasmtime_wasi_config::{WasiConfig, WasiConfigVariables}; #[cfg(feature = "wasi-http")] -use wasmtime_wasi_http::WasiHttpCtx; +use wasmtime_wasi_http::{ + WasiHttpCtx, DEFAULT_OUTGOING_BODY_BUFFER_CHUNKS, DEFAULT_OUTGOING_BODY_CHUNK_SIZE, +}; #[cfg(feature = "wasi-keyvalue")] use wasmtime_wasi_keyvalue::{WasiKeyValue, WasiKeyValueCtx, WasiKeyValueCtxBuilder}; @@ -137,7 +139,18 @@ impl RunCommand { } } - let host = Host::default(); + let host = Host { + #[cfg(feature = "wasi-http")] + wasi_http_outgoing_body_buffer_chunks: self + .run + .common + .wasi + .http_outgoing_body_buffer_chunks, + #[cfg(feature = "wasi-http")] + wasi_http_outgoing_body_chunk_size: self.run.common.wasi.http_outgoing_body_chunk_size, + ..Default::default() + }; + let mut store = Store::new(&engine, host); self.populate_with_wasi(&mut linker, &mut store, &main)?; @@ -905,6 +918,10 @@ struct Host { wasi_threads: Option>>, #[cfg(feature = "wasi-http")] wasi_http: Option>, + #[cfg(feature = "wasi-http")] + wasi_http_outgoing_body_buffer_chunks: Option, + #[cfg(feature = "wasi-http")] + wasi_http_outgoing_body_chunk_size: Option, limits: StoreLimits, #[cfg(feature = "profiling")] guest_profiler: Option>, @@ -948,6 +965,16 @@ impl wasmtime_wasi_http::types::WasiHttpView for Host { fn table(&mut self) -> &mut wasmtime::component::ResourceTable { self.preview2_ctx().table() } + + fn outgoing_body_buffer_chunks(&mut self) -> usize { + self.wasi_http_outgoing_body_buffer_chunks + .unwrap_or_else(|| DEFAULT_OUTGOING_BODY_BUFFER_CHUNKS) + } + + fn outgoing_body_chunk_size(&mut self) -> usize { + self.wasi_http_outgoing_body_chunk_size + .unwrap_or_else(|| DEFAULT_OUTGOING_BODY_CHUNK_SIZE) + } } #[cfg(not(unix))] diff --git a/src/commands/serve.rs b/src/commands/serve.rs index f51f67e719a5..6551ba8a5713 100644 --- a/src/commands/serve.rs +++ b/src/commands/serve.rs @@ -15,7 +15,10 @@ use wasmtime_wasi::{StreamError, StreamResult, WasiCtx, WasiCtxBuilder, WasiView use wasmtime_wasi_http::bindings::http::types::Scheme; use wasmtime_wasi_http::bindings::ProxyPre; use wasmtime_wasi_http::io::TokioIo; -use wasmtime_wasi_http::{body::HyperOutgoingBody, WasiHttpCtx, WasiHttpView}; +use wasmtime_wasi_http::{ + body::HyperOutgoingBody, WasiHttpCtx, WasiHttpView, DEFAULT_OUTGOING_BODY_BUFFER_CHUNKS, + DEFAULT_OUTGOING_BODY_CHUNK_SIZE, +}; #[cfg(feature = "wasi-config")] use wasmtime_wasi_config::{WasiConfig, WasiConfigVariables}; @@ -28,6 +31,8 @@ struct Host { table: wasmtime::component::ResourceTable, ctx: WasiCtx, http: WasiHttpCtx, + http_outgoing_body_buffer_chunks: Option, + http_outgoing_body_chunk_size: Option, limits: StoreLimits, @@ -59,6 +64,16 @@ impl WasiHttpView for Host { fn ctx(&mut self) -> &mut WasiHttpCtx { &mut self.http } + + fn outgoing_body_buffer_chunks(&mut self) -> usize { + self.http_outgoing_body_buffer_chunks + .unwrap_or_else(|| DEFAULT_OUTGOING_BODY_BUFFER_CHUNKS) + } + + fn outgoing_body_chunk_size(&mut self) -> usize { + self.http_outgoing_body_chunk_size + .unwrap_or_else(|| DEFAULT_OUTGOING_BODY_CHUNK_SIZE) + } } const DEFAULT_ADDR: std::net::SocketAddr = std::net::SocketAddr::new( @@ -152,6 +167,8 @@ impl ServeCommand { table: wasmtime::component::ResourceTable::new(), ctx: builder.build(), http: WasiHttpCtx::new(), + http_outgoing_body_buffer_chunks: self.run.common.wasi.http_outgoing_body_buffer_chunks, + http_outgoing_body_chunk_size: self.run.common.wasi.http_outgoing_body_chunk_size, limits: StoreLimits::default(), diff --git a/tests/all/cli_tests.rs b/tests/all/cli_tests.rs index 75fda56b7b96..564542b16fcc 100644 --- a/tests/all/cli_tests.rs +++ b/tests/all/cli_tests.rs @@ -1713,6 +1713,30 @@ mod test_programs { Ok(()) } + #[tokio::test] + async fn cli_serve_outgoing_body_config() -> Result<()> { + let server = WasmtimeServe::new(CLI_SERVE_ECHO_ENV_COMPONENT, |cmd| { + cmd.arg("-Scli"); + cmd.arg("-Shttp-outgoing-body-buffer-chunks=2"); + cmd.arg("-Shttp-outgoing-body-chunk-size=1024"); + })?; + + let resp = server + .send_request( + hyper::Request::builder() + .uri("http://localhost/") + .header("env", "FOO") + .body(String::new()) + .context("failed to make request")?, + ) + .await?; + + assert!(resp.status().is_success()); + + server.finish()?; + Ok(()) + } + #[tokio::test] #[ignore] // TODO: printing stderr in the child and killing the child at the // end of this test race so the stderr may be present or not. Need