Skip to content

feat(ext/node): select how OutgoingMessage#end() delivers finish per runtime - #36

Merged
jackspirou merged 1 commit into
nimbus/v2.9.7from
fix/http-end-final-chunk-finish
Sep 24, 2026
Merged

jackspirou merged 1 commit into
nimbus/v2.9.7from
fix/http-end-final-chunk-finish

Conversation

@jackspirou

Copy link
Copy Markdown
Contributor

Summary

Node.js 24.21 and 26.8 (nodejs/node#65466) changed how OutgoingMessage#end(data) delivers 'finish'. When the chunk can be the final write, 'finish' now rides on that write, and no separate empty write follows. Node.js 24.20, 26.7, and earlier send the chunk and then a separate empty write.

This change adds HttpOutgoingEndPolicy so that an embedder can select the contract of the Node.js version that it reports:

  • SeparateFinishWrite (the default): Node.js 24.20, 26.7, and earlier. The default matches the reported Node.js v26.5.1.
  • FinishWithFinalChunk: Node.js 24.21, 26.8, and later.

The policy follows the existing pattern (VtControlStripPolicy, BufferDetachedValidationPolicy): a deno_node option, an op that JS reads at each call (snapshot safe), and positional defaults in runtime/worker.rs, runtime/web_worker.rs, and runtime/snapshot_info.rs. maybePrepareFinalChunk() in _http_outgoing.ts mirrors the Node.js guard: no final-chunk finish for a destroyed message, for strictContentLength, for a chunked response, or for a non-string and non-Uint8Array chunk.

Tests

  • New unit test [node/http] end(data) sends a separate empty write for finish (default contract, two writes).
  • test-http-server-response-standalone.js passes under the default.
  • A temporary build with the FinishWithFinalChunk default passes the Node.js v24.21 fixture of the same test.
  • The test-http-* failure set (52 of 446, all not enabled in config.jsonc) is identical under both defaults.
  • cargo test -p deno_node --lib policy (8 passed), clippy with -D warnings, rustfmt, dprint, and tools/lint.js --js are clean.

…runtime

Node.js 24.21 and 26.8 (nodejs/node#65466) attach 'finish' to the final
chunk of end(data) when that chunk can be the last write. Earlier releases
write the chunk and then send a separate empty write that carries 'finish'.
The socket sees one write in the new contract and two in the old one.

Add HttpOutgoingEndPolicy so that an embedder can select the contract of the
Node.js release that it targets. The default stays SeparateFinishWrite,
which matches the Node.js release that Deno reports.
@jackspirou
jackspirou merged commit 5269ddd into nimbus/v2.9.7 Sep 24, 2026
1 check passed
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.

1 participant