Skip to content

fix(ext/node): http2 improvements — constants, error codes, settings, validation#33332

Merged
bartlomieju merged 13 commits into
mainfrom
fix/http2-session-constructor-setuphandle
Apr 21, 2026
Merged

fix(ext/node): http2 improvements — constants, error codes, settings, validation#33332
bartlomieju merged 13 commits into
mainfrom
fix/http2-session-constructor-setuphandle

Conversation

@bartlomieju
Copy link
Copy Markdown
Member

@bartlomieju bartlomieju commented Apr 20, 2026

Summary

  • Inline HTTP/2 constants in JS — removed op_http2_constants Rust op (all values are compile-time constants, no need for serde/v8 serialization)
  • Fix missing error codes — register ERR_HTTP2_CONNECT_*, ERR_HTTP2_HEADER_SINGLE_VALUE, ERR_HTTP2_INVALID_CONNECTION_HEADERS, ERR_HTTP2_INVALID_PSEUDOHEADER, ERR_INVALID_HTTP_TOKEN in the codes object; add missing imports in http2.ts
  • Add HideStackFramesError — static self-reference on ERR_HTTP2_INVALID_HEADER_VALUE, ERR_HTTP2_PSEUDOHEADER_NOT_ALLOWED, ERR_INVALID_HTTP_TOKEN (needed by compat.js assertValidHeader)
  • Fix settings validation — use correct 2^31-1 upper bound for initialWindowSize (per RFC 7540); fix getUnpackedSettings to handle TypedArray inputs correctly; reject DataView
  • Implement strictSingleValueFields — session option to disable single-value header validation, wired through all buildNgHeaderString call sites
  • Fix compat.js — match Node's assertValidPseudoHeader usage and this.destroy() for invalid tokens

New compat tests enabled

  • test-http2-connect-method.js
  • test-http2-connect.js
  • test-http2-getpackedsettings.js
  • test-http2-info-headers.js
  • test-http2-invalidheaderfield.js
  • test-http2-invalidheaderfields-client.js
  • test-http2-misused-pseudoheaders.js
  • test-http2-single-headers-validation.js
  • test-http2-single-headers-validation-disabled.js
  • test-http2-trailers.js
  • test-http2-util-assert-valid-pseudoheader.js

Test plan

  • ./x test-compat for all newly enabled tests
  • ./x test-node http2 passes
  • ./x test-spec node/http2 passes
  • ./x lint and ./x fmt pass

🤖 Generated with Claude Code

bartlomieju and others added 12 commits April 20, 2026 17:06
- Implement sessionListenerAdded/sessionListenerRemoved to track
  remoteSettings and frameError listener counts in native fields bitfield
- Remove duplicate process.nextTick for buffered data in constructor
  (setupHandle already handles this, having both risks double-processing)
- Add maxOutstandingPings/maxOutstandingSettings validation and
  enforcement (defaults to 10, matching Node.js)
- Initialize originSet via initOriginSet() for TLS h2 sessions in
  setupHandle
- Define missing constants kSessionMaxInvalidFrames,
  kSessionMaxRejectedStreams, kSessionHasRemoteSettingsListeners

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…t op

All values in op_http2_constants were compile-time constants (nghttp2
C defines, literal strings, HTTP status codes). No reason to serialize
them through serde/v8 at runtime. Move them to a JS constants module
and import directly.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
ERR_HTTP2_CONNECT_AUTHORITY, ERR_HTTP2_CONNECT_PATH, and
ERR_HTTP2_CONNECT_SCHEME were defined as classes but never added to
the `codes` object, causing "is not a constructor" at runtime.

Also enables test-http2-connect-method.js and test-http2-connect.js
in the node compat test suite.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Use correct upper bound (2^31-1) for initialWindowSize validation
  per HTTP/2 spec (RFC 7540 Section 6.5.2)
- Fix getUnpackedSettings to correctly handle TypedArray inputs by
  using Buffer.from(buf) which copies element values as bytes
- Reject DataView in getUnpackedSettings (only Buffer/TypedArray valid)
- Enable test-http2-getpackedsettings.js in compat suite

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Import missing error classes in http2.ts (ERR_HTTP2_INVALID_INFO_STATUS,
  ERR_HTTP2_STATUS_101, ERR_HTTP2_NESTED_PUSH, ERR_HTTP2_PING_CANCEL,
  ERR_HTTP2_SETTINGS_CANCEL, ERR_HTTP2_MAX_PENDING_SETTINGS_ACK,
  ERR_HTTP2_TRAILERS_ALREADY_SENT, ERR_HTTP2_TRAILERS_NOT_READY)
- Register ERR_HTTP2_HEADER_SINGLE_VALUE, ERR_HTTP2_INVALID_CONNECTION_HEADERS,
  and ERR_HTTP2_INVALID_PSEUDOHEADER in the codes object
- Enable test-http2-info-headers.js in compat suite

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…VALID_HTTP_TOKEN

- Add static HideStackFramesError self-reference on ERR_HTTP2_INVALID_HEADER_VALUE,
  ERR_HTTP2_PSEUDOHEADER_NOT_ALLOWED, and ERR_INVALID_HTTP_TOKEN (needed by
  compat.js assertValidHeader which uses .HideStackFramesError pattern)
- Register ERR_INVALID_HTTP_TOKEN in codes object
- Fix compat.js to throw (not destroy) for invalid HTTP tokens in setHeader
- Enable test-http2-invalidheaderfield.js and
  test-http2-invalidheaderfields-client.js in compat suite

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Enable test-http2-trailers.js and
test-http2-util-assert-valid-pseudoheader.js in the compat suite.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…d tokens

Match Node.js behavior: use this.destroy() (not throw) for invalid HTTP
tokens in kSetHeader/kAppendHeader. The assertValidHeader function
already throws for names with spaces before this code path is reached.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add kStrictSingleValueFields symbol to Http2Session, defaulting to true
(matching Node.js behavior). When set to false via session options,
single-value header validation is skipped in buildNgHeaderString.

Pass the option through all buildNgHeaderString call sites:
sendTrailers, prepareResponseHeaders, processRespondWithFD, pushStream,
additionalHeaders, prepareRequestHeadersArray, prepareRequestHeadersObject.

Enables test-http2-single-headers-validation-disabled.js in compat suite.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@bartlomieju bartlomieju changed the title fix(ext/node): http2 session constructor and setupHandle improvements fix(ext/node): http2 improvements — constants, error codes, settings, validation Apr 20, 2026
Copy link
Copy Markdown

@miracatbot miracatbot left a comment

Choose a reason for hiding this comment

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

I think there is one behavioral issue to fix before this lands.

The new maxOutstandingPings check in Http2Session.ping() appears to reuse this[kState].pendingAck, but that same counter is also used by settings() / settingsCallback() for SETTINGS ACK tracking. That means a session with many outstanding SETTINGS ACKs can start rejecting ping() calls even when there are no outstanding PINGs.

In Node these limits are separate in effect: maxOutstandingSettings gates SETTINGS ACK pressure, while maxOutstandingPings applies to in-flight PINGs only. Reusing pendingAck here makes the ping throttling stricter than intended and couples two unrelated mechanisms.

Everything else I checked looked reasonable, but I’d fix that accounting before merging.

Node.js does not gate ping() calls with a pendingAck counter — that
counter is only used for SETTINGS ACK tracking. The shared pendingAck
counter meant outstanding SETTINGS ACKs could incorrectly reject
ping() calls.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@miracatbot miracatbot left a comment

Choose a reason for hiding this comment

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

Re-checked after the latest fix. The previously noted maxOutstandingPings / pendingAck coupling issue is resolved, and the remaining HTTP/2 compat changes look good to me.

Copy link
Copy Markdown
Member

@nathanwhit nathanwhit left a comment

Choose a reason for hiding this comment

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

LGTM

@bartlomieju bartlomieju merged commit 5254b88 into main Apr 21, 2026
112 checks passed
@bartlomieju bartlomieju deleted the fix/http2-session-constructor-setuphandle branch April 21, 2026 06:13
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.

3 participants