Skip to content

http: add native single-shot response builder#64393

Open
anonrig wants to merge 3 commits into
nodejs:mainfrom
anonrig:http-native-single-shot-response
Open

http: add native single-shot response builder#64393
anonrig wants to merge 3 commits into
nodejs:mainfrom
anonrig:http-native-single-shot-response

Conversation

@anonrig

@anonrig anonrig commented Jul 9, 2026

Copy link
Copy Markdown
Member

Summary

Add a C++ buildHttpMessage helper used by the HTTP/1.1 outgoing path so the common cases avoid repeated JavaScript string concatenation and multi-write overhead:

  • _storeHeader: builds the status/request line + header block natively (with JS fallback for special cases such as content-disposition latin1 / unique cookie joining).
  • ServerResponse.end() fast paths:
    • Headers not yet rendered: full message (headers + body) built in C++ and written once.
    • After writeHead(): tryFastFlushEnd flushes the prebuilt header + body without the full write_() / extra empty-write path (this is the benchmark/http/simple.js case).
  • Server-side native headers stay as Buffers until write time (no latin1 string copy on the hot path). ClientRequest still materializes a string for _header compatibility.
  • Complex encodings (hex, utf16le, ...), trailers, and fake/standalone sockets keep the existing JS path.

Public API and on-the-wire format are unchanged.

Benchmarks

Machine-local out/Release on the same host. Baseline measured before this change.

benchmark/http/simple.js (primary)

type=bytes len=4 chunks=1 c=50 chunkedEnc=0 duration=5
RPS
Baseline ~80,236
This PR (5 runs, latest tip) 120,087 / 122,461 / 116,360 / 122,196 / 123,654
Delta ~+45% to +54% (typical ~+50% around 120–123k)

Other simple.js variants (same tip):

Config RPS (3 runs)
chunkedEnc=1 (TE: chunked) 121k / 120k / 116k
len=1024 content-length 103k / 106k / 96k

Other microbenches

Workload RPS
end-vs-write-end method=end asc/64 c=50 duration=5 ~104–129k (run-to-run variance)
end-vs-write-end method=write asc/64 c=50 duration=5 ~106k
Custom keep-alive res.end('ok') only (50 clients, 3s) ~47–49k

Review feedback (document flags, no incidental C++ reformat, no Buffer.concat) is included; the common ASCII path still shows the large win vs baseline.

Tests

Full test/parallel/test-http* suite: 751/751 passed (pre-push on an earlier tip); targeted suite re-run after the latest speed-ups.

Test plan

  • tools/test.py test/parallel/test-http* --mode=release (751 passed)
  • Targeted cases: write-head, non-utf8 content-disposition, chunked 204/304, CONNECT, client default headers, outgoing-end-types, hex/utf16le first-chunk encodings, standalone ServerResponse
  • benchmark/http/simple.js before/after (and after review + further speed-ups)
  • CI on this PR

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Review requested:

  • @nodejs/http
  • @nodejs/net

@nodejs-github-bot nodejs-github-bot added c++ Issues and PRs that require attention from people who are familiar with C++. http Issues or PRs related to the http subsystem. http_parser Issues and PRs related to the HTTP Parser dependency or the http_parser binding. needs-ci PRs that need a full CI run. labels Jul 9, 2026
@anonrig anonrig requested review from Qard, mcollina, panva and ronag July 9, 2026 15:10
Serialize the common HTTP/1.1 header block (and optional body) in C++ so
_storeHeader and ServerResponse.end avoid repeated JS string
concatenation and multi-write path overhead. The public API and wire
format are unchanged; complex cases fall back to the existing JS path.

On benchmark/http/simple.js (bytes/4/1, 50 connections, 5s) this raised
throughput from ~80k to ~118-126k req/s (~+48% to +58%) on the same
machine.

Signed-off-by: Yagiz Nizipli <yagiz@nizipli.com>
@anonrig anonrig force-pushed the http-native-single-shot-response branch from 6e25748 to 8a0057a Compare July 9, 2026 15:37

@mcollina mcollina left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Amazing results!

Comment thread src/node_http_parser.cc Outdated
Comment thread lib/_http_outgoing.js
Comment thread lib/_http_outgoing.js Outdated
Comment thread lib/_http_outgoing.js Outdated
Revert incidental ConnectionsList reformatting in node_http_parser.cc,
document the buildHttpMessage flag and out-param slots in JS, and avoid
Buffer.concat when pairing headers with a body by queueing a separate
latin1 header write instead.

Signed-off-by: Yagiz Nizipli <yagiz@nizipli.com>
@anonrig anonrig requested a review from mcollina July 9, 2026 16:15
Hot writeHead()+end() now flushes via tryFastFlushEnd instead of the
full write_()/extra empty write path. Server-side native headers stay as
Buffers (no latin1 string copy) until write time; the C++ builder writes
into a single malloc transferred to Buffer (no std::string + Copy).
Reuse a scratch flat-header array and a prebuilt 200 status line.

Signed-off-by: Yagiz Nizipli <yagiz@nizipli.com>

@mcollina mcollina left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

This needs a CITGM run and some validation it doesn't break express, fastify, koa, etc before shipping.

@mcollina mcollina added the notable-change PRs with changes that should be highlighted in changelogs. label Jul 9, 2026
@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

The notable-change PRs with changes that should be highlighted in changelogs. label has been added by @mcollina.

Please suggest a text for the release notes if you'd like to include a more detailed summary, then proceed to update the PR description with the text or a link to the notable change suggested text comment. Otherwise, the commit will be placed in the Other Notable Changes section.

@mcollina mcollina added the request-ci Add this label to start a Jenkins CI on a PR. label Jul 9, 2026
@mcollina

mcollina commented Jul 9, 2026

Copy link
Copy Markdown
Member

Also a benchmark CI run would be interesting.

@anonrig

anonrig commented Jul 9, 2026

Copy link
Copy Markdown
Member Author

@anonrig

anonrig commented Jul 9, 2026

Copy link
Copy Markdown
Member Author

@mcollina mcollina added the baking-for-lts PRs that need to wait before landing in a LTS release. label Jul 9, 2026
@github-actions github-actions Bot removed the request-ci Add this label to start a Jenkins CI on a PR. label Jul 9, 2026
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@codecov

codecov Bot commented Jul 9, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 83.34901% with 177 lines in your changes missing coverage. Please review.
✅ Project coverage is 90.19%. Comparing base (8fec65d) to head (1dd52f6).

Files with missing lines Patch % Lines
lib/_http_outgoing.js 85.45% 86 Missing and 20 partials ⚠️
src/node_http_parser.cc 78.74% 30 Missing and 41 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #64393      +/-   ##
==========================================
- Coverage   90.25%   90.19%   -0.06%     
==========================================
  Files         741      741              
  Lines      241207   242197     +990     
  Branches    45430    45719     +289     
==========================================
+ Hits       217698   218456     +758     
- Misses      15084    15239     +155     
- Partials     8425     8502      +77     
Files with missing lines Coverage Δ
src/node_http_parser.cc 83.05% <78.74%> (-1.82%) ⬇️
lib/_http_outgoing.js 90.30% <85.45%> (-7.32%) ⬇️

... and 34 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

baking-for-lts PRs that need to wait before landing in a LTS release. c++ Issues and PRs that require attention from people who are familiar with C++. http_parser Issues and PRs related to the HTTP Parser dependency or the http_parser binding. http Issues or PRs related to the http subsystem. needs-ci PRs that need a full CI run. notable-change PRs with changes that should be highlighted in changelogs.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants