From a953a048394cf889981a35026dc5784e9639b23b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ralph=20K=C3=BCpper?= Date: Sun, 14 Jun 2026 22:29:12 +0200 Subject: [PATCH 1/2] fix(fastify): forward dynamic request/reply property reads in external-fastify variant builds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the well-known flip routes `import 'fastify'` to perry-ext-fastify (auto-optimize / `--no-default-features` builds), `bundled-fastify` and `http-server` are stripped, so the bundled FastifyContext property-dispatch arm in `js_handle_property_dispatch` is compiled out. A `request`/`reply` handle that escaped into a user helper function has its static type erased, so codegen emits a generic dynamic property read here rather than a `NativeMethodCall` — and with no external-fastify dispatch arm wired up, the read fell through to `undefined`. Inline reads in the handler still worked because codegen recognised the receiver and called `js_fastify_req_*` directly. The request handle lives in perry-ext-fastify's perry-ffi registry, so probe membership via the external `js_ext_fastify_is_context_handle` symbol (resolved at link time) and forward to the same `js_fastify_req_*` exports the bundled arm uses. Mirrors the existing external-zlib / external-net probe-and-forward arms and the `external-fastify-pump` pump in async_bridge.rs. Fixes #5037 --- crates/perry-stdlib/src/common/dispatch.rs | 69 ++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/crates/perry-stdlib/src/common/dispatch.rs b/crates/perry-stdlib/src/common/dispatch.rs index aa44766330..d3b8b784d5 100644 --- a/crates/perry-stdlib/src/common/dispatch.rs +++ b/crates/perry-stdlib/src/common/dispatch.rs @@ -2282,6 +2282,75 @@ pub unsafe extern "C" fn js_handle_property_dispatch( }; } + // #5037 — external-fastify variant of the request/reply property + // dispatch above. When the well-known flip routes `fastify` to + // perry-ext-fastify (auto-optimize / `--no-default-features`), + // `bundled-fastify`/`http-server` are stripped and the bundled + // arm above is compiled out. A `request`/`reply` handle that + // escaped into a user helper — its static type erased, so codegen + // emitted a generic dynamic property read here rather than a + // `NativeMethodCall` — then had no dispatch path and read + // `undefined` (inline reads in the handler still worked because + // codegen recognised the receiver and called `js_fastify_req_*` + // directly). The handle lives in perry-ext-fastify's perry-ffi + // registry, not perry-stdlib's, so probe membership via the + // external `js_ext_fastify_is_context_handle` symbol (resolved at + // link time) and forward to the same `js_fastify_req_*` exports + // the bundled arm uses. Mirrors the `external-fastify-pump` pump + // wiring in `async_bridge.rs`. + #[cfg(all(feature = "external-fastify-pump", not(feature = "http-server")))] + { + extern "C" { + fn js_ext_fastify_is_context_handle(handle: i64) -> i32; + fn js_fastify_req_query_object(handle: i64) -> f64; + fn js_fastify_req_params_object(handle: i64) -> f64; + fn js_fastify_req_json(handle: i64) -> f64; + fn js_fastify_req_body(handle: i64) -> *mut perry_runtime::StringHeader; + fn js_fastify_req_headers(handle: i64) -> i64; + fn js_fastify_req_method(handle: i64) -> *mut perry_runtime::StringHeader; + fn js_fastify_req_url(handle: i64) -> *mut perry_runtime::StringHeader; + fn js_fastify_req_get_user_data(handle: i64) -> f64; + } + if js_ext_fastify_is_context_handle(handle) != 0 { + return match property_name { + "query" => js_fastify_req_query_object(handle), + "params" => js_fastify_req_params_object(handle), + "body" => js_fastify_req_json(handle), + "rawBody" | "text" => { + let ptr = js_fastify_req_body(handle); + if ptr.is_null() { + f64::from_bits(0x7FFC_0000_0000_0001) + } else { + f64::from_bits(perry_runtime::JSValue::string_ptr(ptr).bits()) + } + } + "headers" => { + // Returns NaN-boxed JS object bits — use directly. + let bits = js_fastify_req_headers(handle); + f64::from_bits(bits as u64) + } + "method" => { + let ptr = js_fastify_req_method(handle); + if ptr.is_null() { + f64::from_bits(0x7FFC_0000_0000_0001) + } else { + f64::from_bits(perry_runtime::JSValue::string_ptr(ptr).bits()) + } + } + "url" => { + let ptr = js_fastify_req_url(handle); + if ptr.is_null() { + f64::from_bits(0x7FFC_0000_0000_0001) + } else { + f64::from_bits(perry_runtime::JSValue::string_ptr(ptr).bits()) + } + } + "user" => js_fastify_req_get_user_data(handle), + _ => f64::from_bits(0x7FFC_0000_0000_0001), // undefined + }; + } + } + // Issue #340: axios response — dispatch `r.status` / `r.data` / // `r.statusText` / `r.headers` to the AxiosResponseHandle accessor // shims. The handle id is registered in the common HANDLES From 4dd09109abc1cd78b4cf765b9d6203ed5f26cb42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ralph=20K=C3=BCpper?= Date: Mon, 15 Jun 2026 06:33:47 +0200 Subject: [PATCH 2/2] style: rustfmt the Android NDK clang `.cmd` cfg expr (unblock lint) `main` is currently red on the `Check formatting` lint step: the admin-merged #5154 left the `if cfg!(target_os = "windows") { ".cmd" } else { "" }` argument in `link/mod.rs` and `platform_cmd.rs` in a form rustfmt rejects. Apply `cargo fmt` so this PR's lint gate can pass; no behaviour change. --- crates/perry/src/commands/compile/link/mod.rs | 6 +++++- crates/perry/src/commands/compile/link/platform_cmd.rs | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/crates/perry/src/commands/compile/link/mod.rs b/crates/perry/src/commands/compile/link/mod.rs index b4d1279c6b..34ccb0e1ba 100644 --- a/crates/perry/src/commands/compile/link/mod.rs +++ b/crates/perry/src/commands/compile/link/mod.rs @@ -882,7 +882,11 @@ pub(super) fn build_and_run_link( "{}/toolchains/llvm/prebuilt/{}/bin/aarch64-linux-android24-clang{}", ndk_home, host_tag, - if cfg!(target_os = "windows") { ".cmd" } else { "" } + if cfg!(target_os = "windows") { + ".cmd" + } else { + "" + } ); let stub_ok = Command::new(&ndk_clang) .args(["-c", "-fPIC", "-target", "aarch64-linux-android24"]) diff --git a/crates/perry/src/commands/compile/link/platform_cmd.rs b/crates/perry/src/commands/compile/link/platform_cmd.rs index 05ca762936..5d86946e01 100644 --- a/crates/perry/src/commands/compile/link/platform_cmd.rs +++ b/crates/perry/src/commands/compile/link/platform_cmd.rs @@ -576,7 +576,11 @@ pub fn select_linker_command( "{}/toolchains/llvm/prebuilt/{}/bin/aarch64-linux-android24-clang{}", ndk_home, host_tag, - if cfg!(target_os = "windows") { ".cmd" } else { "" } + if cfg!(target_os = "windows") { + ".cmd" + } else { + "" + } ); if !PathBuf::from(&clang).exists() { return Err(anyhow!("Android NDK clang not found at: {}", clang));