diff --git a/lib/cli/src/commands/run_unstable.rs b/lib/cli/src/commands/run_unstable.rs index 8ef2b98b813..419bc64fb0a 100644 --- a/lib/cli/src/commands/run_unstable.rs +++ b/lib/cli/src/commands/run_unstable.rs @@ -25,7 +25,7 @@ use wasmer::{ use wasmer_cache::Cache; use wasmer_compiler::ArtifactBuild; use wasmer_registry::Package; -use wasmer_wasix::runners::{MappedDirectory, Runner, WapmContainer}; +use wasmer_wasix::runners::{wcgi::AbortHandle, MappedDirectory, Runner, WapmContainer}; use webc::metadata::Manifest; use webc_v4::DirOrFile; @@ -158,7 +158,7 @@ impl RunUnstable { .addr(self.wcgi.addr) .envs(self.wasi.env_vars.clone()) .map_directories(self.wasi.mapped_dirs.clone()) - .callbacks(Callbacks::default()); + .callbacks(Callbacks::new(self.wcgi.addr)); if self.wasi.forward_host_env { runner.config().forward_host_env(); } @@ -594,17 +594,23 @@ impl Default for WcgiOptions { #[derive(Debug)] struct Callbacks { stderr: Mutex>, + addr: SocketAddr, } -impl Default for Callbacks { - fn default() -> Self { - Self { +impl Callbacks { + fn new(addr: SocketAddr) -> Self { + Callbacks { stderr: Mutex::new(LineWriter::new(std::io::stderr())), + addr, } } } impl wasmer_wasix::runners::wcgi::Callbacks for Callbacks { + fn started(&self, _abort: AbortHandle) { + println!("WCGI Server running at http://{}/", self.addr); + } + fn on_stderr(&self, raw_message: &[u8]) { if let Ok(mut stderr) = self.stderr.lock() { // If the WCGI runner printed any log messages we want to make sure diff --git a/lib/wasi/src/runners/wasi.rs b/lib/wasi/src/runners/wasi.rs index c4f1339cd06..23bff4cc87e 100644 --- a/lib/wasi/src/runners/wasi.rs +++ b/lib/wasi/src/runners/wasi.rs @@ -122,9 +122,9 @@ impl WasiRunner { program_name: &str, wasi: &Wasi, ) -> Result { - let mut builder = - self.wasi - .prepare_webc_env(container.container_fs(), program_name, wasi)?; + let mut builder = WasiEnvBuilder::new(program_name); + self.wasi + .prepare_webc_env(&mut builder, container.container_fs(), wasi)?; if let Some(tasks) = &self.tasks { let rt = PluggableRuntime::new(Arc::clone(tasks)); diff --git a/lib/wasi/src/runners/wasi_common.rs b/lib/wasi/src/runners/wasi_common.rs index 55ef2b74ff3..f1ec2d24f16 100644 --- a/lib/wasi/src/runners/wasi_common.rs +++ b/lib/wasi/src/runners/wasi_common.rs @@ -8,7 +8,7 @@ use anyhow::{Context, Error}; use virtual_fs::{FileSystem, OverlayFileSystem, RootFileSystemBuilder}; use webc::metadata::annotations::Wasi as WasiAnnotation; -use crate::{runners::MappedDirectory, WasiEnv, WasiEnvBuilder}; +use crate::{runners::MappedDirectory, WasiEnvBuilder}; #[derive(Debug, Default, Clone, serde::Serialize, serde::Deserialize)] pub(crate) struct CommonWasiOptions { @@ -21,11 +21,11 @@ pub(crate) struct CommonWasiOptions { impl CommonWasiOptions { pub(crate) fn prepare_webc_env( &self, + builder: &mut WasiEnvBuilder, container_fs: Arc, - program_name: &str, wasi: &WasiAnnotation, - ) -> Result { - let mut builder = WasiEnv::builder(program_name).args(&self.args); + ) -> Result<(), anyhow::Error> { + builder.add_args(&self.args); let fs = prepare_filesystem(&self.mapped_dirs, container_fs, |path| { builder.add_preopen_dir(path).map_err(Error::from) @@ -34,10 +34,10 @@ impl CommonWasiOptions { builder.add_preopen_dir("/")?; builder.add_preopen_dir(".")?; - self.populate_env(wasi, &mut builder); - self.populate_args(wasi, &mut builder); + self.populate_env(wasi, builder); + self.populate_args(wasi, builder); - Ok(builder) + Ok(()) } fn populate_env(&self, wasi: &WasiAnnotation, builder: &mut WasiEnvBuilder) { diff --git a/lib/wasi/src/runners/wcgi/handler.rs b/lib/wasi/src/runners/wcgi/handler.rs index 2c182a5343d..0957a086f9a 100644 --- a/lib/wasi/src/runners/wcgi/handler.rs +++ b/lib/wasi/src/runners/wcgi/handler.rs @@ -39,19 +39,21 @@ impl Handler { tracing::debug!("Creating the WebAssembly instance"); - let mut request_specific_env = HashMap::new(); + let mut builder = WasiEnvBuilder::new(&self.program_name); - if self.dialect == CgiDialect::Rfc3875 { - // HACK(Michael-F-Bryan): this belongs in the wcgi-host crate - request_specific_env.insert("SCRIPT_NAME".to_string(), parts.uri.to_string()); - } + (self.setup_builder)(&mut builder)?; + + // Note: We want to apply the CGI environment variables *after* + // anything specified by WASI annotations so users get a chance to + // override things like $DOCUMENT_ROOT and $SCRIPT_FILENAME. + let mut request_specific_env = HashMap::new(); self.dialect .prepare_environment_variables(parts, &mut request_specific_env); + builder.add_envs(request_specific_env); let rt = PluggableRuntime::new(Arc::clone(&self.task_manager)); - let builder = (self.setup_builder)()? - .envs(request_specific_env) + let builder = builder .stdin(Box::new(req_body_receiver)) .stdout(Box::new(res_body_sender)) .stderr(Box::new(stderr_sender)) @@ -205,13 +207,16 @@ async fn consume_stderr( } } +type SetupBuilder = Box Result<(), anyhow::Error> + Send + Sync>; + #[derive(derivative::Derivative)] #[derivative(Debug)] pub(crate) struct SharedState { pub(crate) module: Module, pub(crate) dialect: CgiDialect, + pub(crate) program_name: String, #[derivative(Debug = "ignore")] - pub(crate) setup_builder: Box Result + Send + Sync>, + pub(crate) setup_builder: SetupBuilder, #[derivative(Debug = "ignore")] pub(crate) callbacks: Arc, #[derivative(Debug = "ignore")] diff --git a/lib/wasi/src/runners/wcgi/mod.rs b/lib/wasi/src/runners/wcgi/mod.rs index ddfe6d783a2..e39e197f6af 100644 --- a/lib/wasi/src/runners/wcgi/mod.rs +++ b/lib/wasi/src/runners/wcgi/mod.rs @@ -2,3 +2,4 @@ mod handler; mod runner; pub use self::runner::{Callbacks, Config, WcgiRunner}; +pub use futures::future::AbortHandle; diff --git a/lib/wasi/src/runners/wcgi/runner.rs b/lib/wasi/src/runners/wcgi/runner.rs index 892a53b63dc..1b49c0d6269 100644 --- a/lib/wasi/src/runners/wcgi/runner.rs +++ b/lib/wasi/src/runners/wcgi/runner.rs @@ -138,15 +138,16 @@ impl WcgiRunner { }; let shared = SharedState { + module, + dialect, + program_name: self.program_name.clone(), + setup_builder: Box::new(self.setup_builder(ctx, wasi)), + callbacks: Arc::clone(&self.config.callbacks), task_manager: self .config .task_manager .clone() .unwrap_or_else(|| Arc::new(TokioTaskManager::default())), - module, - dialect, - callbacks: Arc::clone(&self.config.callbacks), - setup_builder: Box::new(self.setup_builder(ctx, wasi)), }; Ok(Handler::new(shared)) @@ -156,23 +157,21 @@ impl WcgiRunner { &self, ctx: &RunnerContext<'_>, wasi: &Wasi, - ) -> impl Fn() -> Result + Send + Sync { + ) -> impl Fn(&mut WasiEnvBuilder) -> Result<(), Error> + Send + Sync { let container_fs = ctx.container_fs(); let wasi_common = self.config.wasi.clone(); - let program_name = self.program_name.clone(); let wasi = wasi.clone(); let tasks = self.config.task_manager.clone(); - move || { - let mut builder = - wasi_common.prepare_webc_env(Arc::clone(&container_fs), &program_name, &wasi)?; + move |builder| { + wasi_common.prepare_webc_env(builder, Arc::clone(&container_fs), &wasi)?; if let Some(tasks) = &tasks { let rt = PluggableRuntime::new(Arc::clone(tasks)); builder.set_runtime(Arc::new(rt)); } - Ok(builder) + Ok(()) } } }