From ab1cd04184c8c5705db3622484220a68ab3b45aa Mon Sep 17 00:00:00 2001 From: karthik2804 Date: Mon, 17 Jun 2024 11:42:32 +0200 Subject: [PATCH 1/2] add option to retain fetchEvent handler Signed-off-by: karthik2804 --- .../src/bindgen.rs | 13 ++++++++- .../spidermonkey-embedding-splicer/src/lib.rs | 27 ++++++++++++++++--- .../src/splice.rs | 24 +++++++++++------ .../wit/spidermonkey-embedding-splicer.wit | 2 +- src/componentize.js | 4 ++- 5 files changed, 55 insertions(+), 15 deletions(-) diff --git a/crates/spidermonkey-embedding-splicer/src/bindgen.rs b/crates/spidermonkey-embedding-splicer/src/bindgen.rs index 11912fd..69799d5 100644 --- a/crates/spidermonkey-embedding-splicer/src/bindgen.rs +++ b/crates/spidermonkey-embedding-splicer/src/bindgen.rs @@ -124,7 +124,12 @@ pub struct Componentization { pub resource_imports: Vec<(String, String, u32)>, } -pub fn componentize_bindgen(resolve: &Resolve, id: WorldId, name: &str) -> Componentization { +pub fn componentize_bindgen( + resolve: &Resolve, + id: WorldId, + name: &str, + retain_fetch_event: bool, +) -> Componentization { let mut bindgen = JsBindgen { src: Source::default(), esm_bindgen: EsmBindgen::default(), @@ -342,6 +347,7 @@ pub fn componentize_bindgen(resolve: &Resolve, id: WorldId, name: &str) -> Compo "$source_mod", &mut bindgen.local_names, name, + retain_fetch_event, ); let js_intrinsics = render_intrinsics(&mut bindgen.all_intrinsics, false, true); @@ -1001,6 +1007,7 @@ impl EsmBindgen { imports_object: &str, _local_names: &mut LocalNames, source_name: &str, + retain_fetch_event: bool, ) { // TODO: bring back these validations of imports // including using the flattened bindings @@ -1043,6 +1050,10 @@ impl EsmBindgen { "); } for (export_name, binding) in &self.exports { + // If we are retaining the fetch event, then we should just let StarlingMonkey handle the event directly. + if retain_fetch_event && export_name == "wasi:http/incoming-handler@0.2.0" { + continue; + } match binding { Binding::Interface(bindings) => { uwrite!(output, "const "); diff --git a/crates/spidermonkey-embedding-splicer/src/lib.rs b/crates/spidermonkey-embedding-splicer/src/lib.rs index 390cc72..b9f4e93 100644 --- a/crates/spidermonkey-embedding-splicer/src/lib.rs +++ b/crates/spidermonkey-embedding-splicer/src/lib.rs @@ -1,6 +1,9 @@ use anyhow::{bail, Context, Result}; use bindgen::BindingItem; -use std::path::{Path, PathBuf}; +use std::{ + collections::HashSet, + path::{Path, PathBuf}, +}; mod bindgen; mod splice; @@ -111,6 +114,7 @@ impl Guest for SpidermonkeyEmbeddingSplicerComponent { wit_path: Option, world_name: Option, debug: bool, + mut retain_fetch_event: bool, ) -> Result { let source_name = source_name.unwrap_or("source.js".to_string()); @@ -131,7 +135,22 @@ impl Guest for SpidermonkeyEmbeddingSplicerComponent { .map_err(|e| e.to_string())?; let mut wasm_bytes = wit_component::dummy_module(&resolve, world); - let componentized = bindgen::componentize_bindgen(&resolve, world, &source_name); + let componentized = + bindgen::componentize_bindgen(&resolve, world, &source_name, retain_fetch_event); + + let target_world = &resolve.worlds[world]; + let mut target_world_exports = HashSet::new(); + + for (key, _) in &target_world.exports { + target_world_exports.insert(resolve.name_world_key(key)); + } + + // Do not retain fetch event if the target world does not export the + // incomingHandler Interface as that would make it incompatible with the + // target world + if !target_world_exports.contains("wasi:http/incoming-handler@0.2.0") { + retain_fetch_event = false; + } // merge the engine world with the target world, retaining the engine producers let producers = if let Ok(( @@ -330,8 +349,8 @@ impl Guest for SpidermonkeyEmbeddingSplicerComponent { // println!("{:?}", &imports); // println!("{:?}", &componentized.imports); // println!("{:?}", &exports); - let mut wasm = - splice::splice(engine, imports, exports, debug).map_err(|e| format!("{:?}", e))?; + let mut wasm = splice::splice(engine, imports, exports, debug, retain_fetch_event) + .map_err(|e| format!("{:?}", e))?; // add the world section to the spliced wasm wasm.push(section.id()); diff --git a/crates/spidermonkey-embedding-splicer/src/splice.rs b/crates/spidermonkey-embedding-splicer/src/splice.rs index fd7b354..23414b8 100644 --- a/crates/spidermonkey-embedding-splicer/src/splice.rs +++ b/crates/spidermonkey-embedding-splicer/src/splice.rs @@ -38,6 +38,7 @@ pub fn splice( imports: Vec<(String, String, CoreFn, Option)>, exports: Vec<(String, CoreFn)>, debug: bool, + retain_fetch_event: bool, ) -> Result> { let mut config = walrus::ModuleConfig::new(); if debug { @@ -53,13 +54,16 @@ pub fn splice( module.exports.delete(expt.id()); module.funcs.delete(run); } - if let Ok(serve) = module - .exports - .get_func("wasi:http/incoming-handler@0.2.0#handle") - { - let expt = module.exports.get_exported_func(serve).unwrap(); - module.exports.delete(expt.id()); - module.funcs.delete(serve); + + if !retain_fetch_event { + if let Ok(serve) = module + .exports + .get_func("wasi:http/incoming-handler@0.2.0#handle") + { + let expt = module.exports.get_exported_func(serve).unwrap(); + module.exports.delete(expt.id()); + module.funcs.delete(serve); + } } // we reencode the WASI world component data, so strip it out from the @@ -79,7 +83,7 @@ pub fn splice( synthesize_import_functions(&mut module, &imports)?; // create the exported functions as wrappers around the "cabi_call" function - synthesize_export_functions(&mut module, &exports)?; + synthesize_export_functions(&mut module, &exports, retain_fetch_event)?; Ok(module.emit_wasm()) } @@ -530,6 +534,7 @@ fn synthesize_import_functions( fn synthesize_export_functions( module: &mut walrus::Module, exports: &Vec<(String, CoreFn)>, + retain_fetch_event: bool, ) -> Result<()> { let cabi_realloc = get_export_fid( module, @@ -561,6 +566,9 @@ fn synthesize_export_functions( let arg_ptr = module.locals.add(ValType::I32); let ret_ptr = module.locals.add(ValType::I32); for (export_num, (expt_name, expt_sig)) in exports.iter().enumerate() { + if retain_fetch_event && expt_name == "wasi:http/incoming-handler@0.2.0#handle" { + continue; + } // Export function synthesis { // add the function type diff --git a/crates/spidermonkey-embedding-splicer/wit/spidermonkey-embedding-splicer.wit b/crates/spidermonkey-embedding-splicer/wit/spidermonkey-embedding-splicer.wit index 08aa15d..e3001ad 100644 --- a/crates/spidermonkey-embedding-splicer/wit/spidermonkey-embedding-splicer.wit +++ b/crates/spidermonkey-embedding-splicer/wit/spidermonkey-embedding-splicer.wit @@ -33,5 +33,5 @@ world spidermonkey-embedding-splicer { export stub-wasi: func(engine: list, features: list, wit-world: option, wit-path: option, world-name: option) -> result, string>; - export splice-bindings: func(source-name: option, spidermonkey-engine: list, wit-world: option, wit-path: option, world-name: option, debug: bool) -> result; + export splice-bindings: func(source-name: option, spidermonkey-engine: list, wit-world: option, wit-path: option, world-name: option, debug: bool, retain-fetch-event: bool ) -> result; } diff --git a/src/componentize.js b/src/componentize.js index 52cba5b..b22ff64 100644 --- a/src/componentize.js +++ b/src/componentize.js @@ -45,6 +45,7 @@ export async function componentize(jsSource, witWorld, opts) { worldName, disableFeatures = [], enableFeatures = [], + retainFetchEvent = false } = opts || {}; let { wasm, jsBindings, importWrappers, exports, imports } = spliceBindings( @@ -53,7 +54,8 @@ export async function componentize(jsSource, witWorld, opts) { witWorld, maybeWindowsPath(witPath), worldName, - false + false, + retainFetchEvent ); // we never disable a feature that is already in the target world usage From 94a9888724019265f45e8c5fb7d39b615c46cee0 Mon Sep 17 00:00:00 2001 From: karthik2804 Date: Tue, 18 Jun 2024 11:46:12 +0200 Subject: [PATCH 2/2] update readme and add fetch-event to features list Signed-off-by: karthik2804 --- README.md | 4 ++++ src/componentize.js | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 362fd75..54eb00d 100644 --- a/README.md +++ b/README.md @@ -130,6 +130,10 @@ Setting `disableFeatures: ['random', 'stdio', 'clocks']` will disable all featur Note that pure components **will not report errors and will instead trap**, so that this should only be enabled after very careful testing. +The features that are not included by default are: +* `'http'` - Support for sending and receiving HTTP requests, depends on `wasi:io` +* `'fetch-event'` - Enables using `fetchEvent` to respond to `wasi:http/incoming-handler@0.2.0#handle`. If the target world does note export `wasi:http/incoming-handler@0.2.0`, this will be ignored. + Note that features explicitly imported by the target world cannot be disabled - if you target a component to a world that imports `wasi:clocks`, then `disableFeatures: ['clocks']` will not be supported. diff --git a/src/componentize.js b/src/componentize.js index b22ff64..6924ab6 100644 --- a/src/componentize.js +++ b/src/componentize.js @@ -45,9 +45,10 @@ export async function componentize(jsSource, witWorld, opts) { worldName, disableFeatures = [], enableFeatures = [], - retainFetchEvent = false } = opts || {}; + const retainFetchEvent = enableFeatures.includes('fetch-event') + let { wasm, jsBindings, importWrappers, exports, imports } = spliceBindings( sourceName, await readFile(engine),