Skip to content

http2: enforce maxSessionMemory for client requests - #67361

Open
gabedemesa wants to merge 1 commit into
nodejs:mainfrom
gabedemesa:http2-client-request-session-memory
Open

gabedemesa wants to merge 1 commit into
nodejs:mainfrom
gabedemesa:http2-client-request-session-memory

Conversation

@gabedemesa

Copy link
Copy Markdown

The documentation for maxSessionMemory says new Http2Stream instances are rejected while the limit is exceeded. That was only enforced for streams opened by the peer (Http2Session::CanAddStream()). session.request() went straight to nghttp2_submit_request(), so a client whose socket stopped draining could keep submitting requests and queue frames in outgoing_buffers_ without bound.

This checks the session memory in Http2Session::Request() before submitting and fails only that request with ERR_HTTP2_STREAM_ERROR (NGHTTP2_ENHANCE_YOUR_CALM). The session stays usable. As with response headers (#67114), request bodies queued for flow control are not counted, so a large upload does not block unrelated requests on the same session. The outgoing_buffers_ descriptors (32 bytes per queued write) are now counted towards the session memory.

The rejection is signalled by returning false from the internal request() binding rather than a new constant, to avoid adding to the public http2.constants or the NGHTTP2_ERR_* set that test-http2-client-onconnect-errors iterates.

Verification

30,000 GETs submitted with maxSessionMemory: 1 to a peer that accepts the connection and then pauses its socket (repro from nodejs/undici#6181):

Build outboundQueueSize Requests rejected
v26.1.0 29,900 0
This branch 1,187 28,713 (ENHANCE_YOUR_CALM)

All test/parallel/test-http2-* and test/sequential/test-http2-* tests pass locally. The new test-http2-max-session-memory-client-request.js fails without the change. cpplint is clean; ESLint was not run locally.

Not covered

  • A single stream that ignores write() backpressure can still queue without bound on that stream (also described in the issue). That is application-level backpressure.
  • This does not establish the cause of the production OOM in the issue, which has no captured native trace. It only closes the unbounded client submission path the issue identified.

Refs: nodejs/undici#6181

🤖 Generated with Claude Code

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Review requested:

  • @nodejs/http2
  • @nodejs/net

@nodejs-github-bot nodejs-github-bot added c++ Issues and PRs that require attention from people who are familiar with C++. http2 Issues and PRs related to the http2 subsystem. needs-ci PRs that need a full CI run. labels Nov 9, 2026
@github-actions

github-actions Bot commented Nov 9, 2026

Copy link
Copy Markdown
Contributor

Welcome to Node.js, and thank you for your first contribution!

Before review, please take a moment to read:

Please make sure every commit is signed off. For a first pull request, GitHub Actions require collaborator approval and Jenkins CI must be started by a collaborator or triager, so an initial wait is normal.

The documentation for `maxSessionMemory` says new streams are rejected
while the limit is exceeded. That was only enforced for streams opened
by the peer (`Http2Session::CanAddStream()`); `session.request()` went
straight to `nghttp2_submit_request()`. A client whose socket stopped
draining could therefore keep submitting requests and queue frames in
`outgoing_buffers_` without bound.

Check the session memory before submitting a request and fail only that
request with `ERR_HTTP2_STREAM_ERROR` (`NGHTTP2_ENHANCE_YOUR_CALM`),
leaving the session usable. As with response headers, request bodies
queued for flow control are not counted, so large uploads do not block
unrelated requests on the same session.

Also count the `outgoing_buffers_` descriptors towards the session
memory; each queued write costs 32 bytes regardless of its length.

Refs: nodejs/undici#6181
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Signed-off-by: gdemesa <gdemesa@opengov.com>
@gabedemesa
gabedemesa force-pushed the http2-client-request-session-memory branch from 3cb04f3 to 9e2e2fa Compare November 9, 2026 21:52
@gabedemesa
gabedemesa marked this pull request as ready for review November 9, 2026 21:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

c++ Issues and PRs that require attention from people who are familiar with C++. http2 Issues and PRs related to the http2 subsystem. needs-ci PRs that need a full CI run.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants