Skip to content

fix(http): server.ref()/unref() return this instead of a raw number (#5011)#5023

Merged
proggeramlug merged 3 commits into
mainfrom
fix/http-server-ref-unref-5011
Jun 12, 2026
Merged

fix(http): server.ref()/unref() return this instead of a raw number (#5011)#5023
proggeramlug merged 3 commits into
mainfrom
fix/http-server-ref-unref-5011

Conversation

@proggeramlug

Copy link
Copy Markdown
Contributor

Summary

Fixes #5011server.ref() and server.unref() on a node:http/node:https server returned the receiver handle as a raw number instead of the server object. Node returns this, so http.createServer(cb).unref().listen(...) broke under Perry with TypeError: (number).listen is not a function (test-http-request-method-delete-payload.js and friends).

const http = require('http');
const s = http.createServer(() => {});
console.log(typeof s.unref(), s.unref() === s);
// Node:  object true
// Perry (before): number false
// Perry (after):  object true

Root cause

crates/perry-codegen/src/lower_call/native_table/http_server.rs had entries for listen/close/closeAllConnections/… but none for ref/unref, so they fell through to a generic handler that returned the handle as a number — the exact shape listen had before #2129.

Fix

  • native table: added ref/unref NativeModSig rows (ret: NR_PTR) for both the HttpServer and HttpsServer class filters.
  • runtime: new js_node_http_server_ref/_unref and js_node_https_server_ref/_unref return the receiver handle (so s.ref() === s) and toggle a new refed flag on HttpServer. server_is_active now ignores a listening-but-unref()ed server, so the event loop can exit while the server is still bound (Node semantics) — pending listen callbacks and queued requests still keep the loop alive long enough to flush in-flight work.
  • dynamic dispatch: mirrored ref/unref in the server: any dispatcher (handle_dispatch.rs).
  • wiring: registered the externs in ext_registry.rs, runtime_decls/stdlib_ffi.rs, and the force_link_http_server anchor table; added ref/unref manifest rows and regenerated docs/src/api/reference.md.

Acceptance — verified locally

  • typeof s.unref()object, s.unref() === strue
  • s.ref() === strue
  • createServer(cb).unref().listen(...) works (listening on number)
  • A listening unref'd server lets the process exit (exit 0, no hang)
  • cargo test -p perry-api-manifest → 32 + 4 passed, 0 failed (manifest/docs drift clean)

Repro added at test-files/test_http_server_unref_5011.ts.

Not in scope

Separate (number).<method> cases tracked under #4975: new http.Agent().createConnection(...) returning a number (test-http-socket-encoding-error) and server.ALPNProtocols not being a Buffer (test-https-argument-of-creating).

Ralph Küpper added 2 commits June 12, 2026 13:10
…#5011)

`server.ref()`/`server.unref()` on a node:http/node:https server returned
the receiver handle as a raw number instead of the server object. Node
returns `this`, so `http.createServer(cb).unref().listen(...)` broke under
Perry with `TypeError: (number).listen is not a function`.

Root cause: native_table/http_server.rs had no ref/unref rows for the
HttpServer/HttpsServer class filters, so the calls fell through to a generic
handler that yielded the handle as a number — the same shape `listen` had
before #2129.

- Add ref/unref NativeModSig rows (ret: NR_PTR) for both server tables.
- New js_node_http(s)_server_ref/_unref runtime fns return the receiver
  handle and toggle a new `refed` flag on HttpServer; server_is_active now
  ignores a listening-but-unref'd server so the loop can exit (Node
  semantics), while pending listen callbacks / queued requests still keep
  it alive to flush in-flight work.
- Mirror the methods in the `server: any` dynamic dispatcher and register
  the externs in ext_registry, stdlib_ffi, and force_link_http_server.
- Add ref/unref manifest rows + regen docs.

Verified: typeof s.unref() === "object", s.unref() === s, s.ref() === s,
createServer(cb).unref().listen(...) works, and a listening unref'd server
exits cleanly (exit 0, no hang).
@proggeramlug proggeramlug force-pushed the fix/http-server-ref-unref-5011 branch from b5b746e to bdd7e95 Compare June 12, 2026 11:10
@proggeramlug proggeramlug merged commit 7cc7c91 into main Jun 12, 2026
13 checks passed
@proggeramlug proggeramlug deleted the fix/http-server-ref-unref-5011 branch June 12, 2026 11:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

node:http/https: server.ref()/unref() return a raw number instead of this (breaks createServer().unref() chaining)

1 participant