Skip to content

http: cache parser callbacks - #66152

Open
mcollina wants to merge 1 commit into
nodejs:mainfrom
mcollina:http-parser-lookup-header-cache
Open

mcollina wants to merge 1 commit into
nodejs:mainfrom
mcollina:http-parser-lookup-header-cache

Conversation

@mcollina

@mcollina mcollina commented Sep 20, 2026 •

Copy link
Copy Markdown
Member

Cache the kOnHeadersComplete, kOnBody, and kOnMessageComplete lookups in internal fields on each parser’s JS object, rather than in strong v8::Global handles. This avoids an independent strong reference when a callback captures its parser.

The cache is cleared when the parser is initialized or freed. Callbacks replaced while a parser is active are picked up on its next initialization. Header names remain non-internalized because clients control them.

The new test covers repeated requests, callback replacement on reinitialization, and release of a cached callback on free(). The Release build, lint, formatting check, and focused tests passed. In the broader HTTP run, 500 tests passed and one timed out; the timed-out test passed when rerun alone.

@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_parser Issues and PRs related to the HTTP parser implementation or http_parser binding. needs-ci PRs that need a full CI run. labels Sep 20, 2026
@mcollina
mcollina force-pushed the http-parser-lookup-header-cache branch from d12ac94 to 2263e95 Compare September 20, 2026 07:45
@mcollina

Copy link
Copy Markdown
Member Author

@nodejs/diagnostics ptal. Not sure if anyone is monkeypatching those callbacks on the fly.

Comment thread src/node_http_parser.cc Outdated
@mcollina
mcollina force-pushed the http-parser-lookup-header-cache branch from 2263e95 to 781531a Compare September 20, 2026 07:58
@mcollina mcollina changed the title http: cache parser callbacks, intern header names http: cache parser callbacks Sep 20, 2026
@mcollina mcollina added the request-ci Add this label to start a Jenkins CI on a PR. Only starts once the PR has an approving review. label Sep 20, 2026
@github-actions github-actions Bot removed the request-ci Add this label to start a Jenkins CI on a PR. Only starts once the PR has an approving review. label Sep 20, 2026
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@codecov

codecov Bot commented Sep 20, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 90.37%. Comparing base (c0681e5) to head (2504fd1).
⚠️ Report is 12 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main   #66152   +/-   ##
=======================================
  Coverage   90.37%   90.37%           
=======================================
  Files         790      790           
  Lines      274514   274526   +12     
  Branches    52572    52576    +4     
=======================================
+ Hits       248102   248115   +13     
+ Misses      16889    16884    -5     
- Partials     9523     9527    +4     
Files with missing lines Coverage Δ
src/node_http_parser.cc 85.33% <100.00%> (+0.45%) ⬆️

... and 24 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.

@mcollina
mcollina force-pushed the http-parser-lookup-header-cache branch from 781531a to eea709d Compare September 21, 2026 05:37
@pimterry pimterry added request-ci Add this label to start a Jenkins CI on a PR. Only starts once the PR has an approving review. author ready PRs with CI started, the required approvals, and no outstanding review comments. labels Sep 23, 2026
@github-actions github-actions Bot removed the request-ci Add this label to start a Jenkins CI on a PR. Only starts once the PR has an approving review. label Sep 23, 2026
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Comment thread src/node_http_parser.cc Outdated
}

// Caches a set-once callback property; the cache is cleared in Init().
Local<Value> CachedCallback(uint32_t index, v8::Global<v8::Value>* cache) {

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.

Suggested change
Local<Value> CachedCallback(uint32_t index, v8::Global<v8::Value>* cache) {
Local<Value> CachedCallback(uint32_t index, v8::Global<v8::Value>& cache) {

maybe?
And change -> by . to access it.

Comment thread src/node_http_parser.cc Outdated
llhttp_init(&parser_, type, &settings);

on_headers_complete_cb_.Reset();
on_body_cb_.Reset();

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.

should this be done earlier, e.g. when parser is moved into freelist on managed side instead on next use?

Comment thread src/node_http_parser.cc Outdated

v8::Global<v8::Value> on_headers_complete_cb_;
v8::Global<v8::Value> on_body_cb_;
v8::Global<v8::Value> on_message_complete_cb_;

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.

Is there a reason why kOnHeaders callback is not cached?
Are the two complete callbacks called more then once per HTTP request? I assume caching for single use would be not helpful.

@panva panva added the resume-ci Add this label to resume the latest eligible Jenkins CI run on a PR with an approving review. label Sep 24, 2026
@github-actions github-actions Bot removed the resume-ci Add this label to resume the latest eligible Jenkins CI run on a PR with an approving review. label Sep 24, 2026
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@addaleax addaleax 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.

  1. v8::Global referring to callbacks is a memory leak footgun, as any reference from the callback back to the parser will create an indefinite memory leak
  2. If we do use v8::Globals, they need to be tracked in the Parser class's MemoryInfo method

If we do want to cache these methods, internal fields are likely a better choice (or, as a secondary option, weak v8::Globals, but I'd carefully evaluate the performance of that approach)

@github-actions github-actions Bot removed the author ready PRs with CI started, the required approvals, and no outstanding review comments. label Sep 26, 2026
@github-actions

Copy link
Copy Markdown
Contributor

This pull request has conflicts with its base branch, removing the author ready label.
Please rebase your branch onto the latest base branch, resolve the conflicts locally, and force-push.
Afterwards the pull request needs a fresh collaborator approval, and a collaborator will add the label back once it is author ready again.

Cache the per-message callback lookups on the parser's JS object instead
of retaining callback functions in strong v8::Global handles. A callback
that captures its parser can otherwise keep the parser alive.

Clear the cache when a parser is initialized or freed so reused parsers
can load replacement callbacks and idle parsers do not retain them.
Header field names remain non-internalized because they are supplied by
clients.

Assisted-by: pi
Signed-off-by: Matteo Collina <hello@matteocollina.com>
@mcollina
mcollina force-pushed the http-parser-lookup-header-cache branch from eea709d to 2504fd1 Compare September 26, 2026 15:19
@addaleax addaleax added author ready PRs with CI started, the required approvals, and no outstanding review comments. request-ci Add this label to start a Jenkins CI on a PR. Only starts once the PR has an approving review. labels Sep 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

author ready PRs with CI started, the required approvals, and no outstanding review comments. c++ Issues and PRs that require attention from people who are familiar with C++. http_parser Issues and PRs related to the HTTP parser implementation or http_parser binding. needs-ci PRs that need a full CI run. request-ci Add this label to start a Jenkins CI on a PR. Only starts once the PR has an approving review.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants