http: add native single-shot response builder
AN
19d ago+1839+1839+0123456789012345678901234567890123456789-135-135-012345678901234567890123456789
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():tryFastFlushEndflushes the prebuilt header + body without the fullwrite_()/ extra empty-write path (this is thebenchmark/http/simple.jscase).
- Server-side native headers stay as Buffers until write time (no latin1 string copy on the hot path). ClientRequest still materializes a string for
_headercompatibility. - 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.jsbefore/after (and after review + further speed-ups) - CI on this PR