Skip to content

feat(http): add --max-http-header-count CLI flag - #26122

Closed
robobun wants to merge 2 commits into
mainfrom
claude/add-max-http-header-count
Closed

robobun wants to merge 2 commits into
mainfrom
claude/add-max-http-header-count

Conversation

@robobun

@robobun robobun commented Jan 15, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Adds --max-http-header-count CLI flag to configure the maximum number of HTTP headers allowed per request (default: 100)
  • Adds http.maxHeadersCount getter/setter for Node.js compatibility
  • Uses dynamic allocation when limit > 100, with stack allocation fast path for default case

Test plan

  • bun bd test test/regression/issue/6982.test.ts passes
  • Verified tests fail with USE_SYSTEM_BUN=1 (feature doesn't exist in current release)
  • Tested CLI flag: bun --max-http-header-count=200 -e "console.log(require('http').maxHeadersCount)" outputs 200
  • Tested server accepts 150 headers with --max-http-header-count=200
  • Tested server rejects 60 headers with --max-http-header-count=50 (returns 431)

Fixes #6982

🤖 Generated with Claude Code

Adds a configurable maximum HTTP header count limit, similar to
--max-http-header-size. This allows servers to accept requests with
more than the default 100 headers.

Features:
- CLI flag: --max-http-header-count <INT> (default: 100)
- Node.js API: http.maxHeadersCount getter/setter
- Dynamic header allocation when limit > 100 (fast path for default)
- Returns HTTP 431 when header count exceeds limit

Fixes #6982

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jan 15, 2026 •

Copy link
Copy Markdown
Contributor

Walkthrough

This PR makes the HTTP header count limit configurable throughout Bun's stack. It replaces a hard-coded limit with a default of 100 and adds APIs at multiple layers (C++, C, Zig, TypeScript, CLI) to allow customization per application or globally via command-line flags.

Changes

Cohort / File(s) Summary
uWS C++ HTTP Parser Layer
packages/bun-uws/src/App.h, packages/bun-uws/src/HttpContext.h, packages/bun-uws/src/HttpContextData.h, packages/bun-uws/src/HttpParser.h
Core HTTP parsing infrastructure updated to support dynamic header count limits. Added setMaxHTTPHeadersCount() method, extended HttpContextData with new field, updated parser signatures to accept maxHeadersCount parameter, and introduced stack-allocated and dynamic vector-backed header storage strategies.
C/FFI Binding Layer
src/deps/libuwsockets.cpp, src/deps/uws/App.zig
Exported new C function uws_app_set_max_http_headers_count() and corresponding Zig wrapper binding to bridge C++ implementation to Zig/JavaScript layers.
Zig Runtime Configuration
src/http.zig, src/bun.js/node/node_http_binding.zig
Added global max_http_headers_count variable (default 100) exported as BUN_DEFAULT_MAX_HTTP_HEADERS_COUNT, and implemented getter/setter bindings for JavaScript API with input validation.
TypeScript/JavaScript API Layer
src/js/internal/http.ts, src/js/node/http.ts
Exposed new getMaxHTTPHeadersCount() and setMaxHTTPHeadersCount() functions, and added maxHeadersCount property accessor to HTTP exports for user-facing configuration.
CLI and Testing
src/cli/Arguments.zig, test/regression/issue/6982.test.ts
Added --max-http-header-count <INT> command-line parameter with default 100, and comprehensive regression test suite validating header count enforcement across getter/setter, CLI flags, and server request handling scenarios.

Suggested reviewers

  • Jarred-Sumner
  • pfgithub
  • alii
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The PR title directly describes the main feature added: a new CLI flag for configuring maximum HTTP headers, which is the primary change throughout the codebase.
Description check ✅ Passed The PR description covers both required sections: 'What does this PR do?' is addressed in the Summary section, and 'How did you verify your code works?' is covered by the Test plan with specific test cases and verification steps.
Linked Issues check ✅ Passed All requirements from issue #6982 are met: the MAX_HEADERS limit is now configurable via the --max-http-header-count CLI flag and http.maxHeadersCount property, allowing users to increase the limit from the default 100 as needed.
Out of Scope Changes check ✅ Passed All changes are directly related to making HTTP header counts configurable. No extraneous modifications detected; the implementation consistently threads the maxHeadersCount parameter through the codebase and adds necessary bindings and exports.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

@robobun

robobun commented Jan 15, 2026 •

Copy link
Copy Markdown
Collaborator Author
Updated 5:26 PM PT - Jan 14th, 2026

❌ Your commit 66b96948 has 1 failures in Build #34886 (All Failures):


🧪   To try this PR locally:

bunx bun-pr 26122

That installs a local version of the PR into your bun-26122 executable, so you can run:

bun-26122 --bun

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In `@packages/bun-uws/src/HttpParser.h`:
- Line 757: The loop for parsing headers (for (unsigned int i = 1; i <
maxHeadersCount - 1; i++)), combined with headers[0] being used for the request
line, means the effective capacity is maxHeadersCount - 2; update either the
parsing logic or the CLI description: either change the loop bound to i <
maxHeadersCount (and adjust any sentinel/terminator handling and the comment
"This cann take the very last header space") so that setting
--max-http-header-count = N allows N headers, or keep the loop but change the
user-facing --max-http-header-count help text to explicitly state the value
reserves two slots (request line + terminator) and thus supports N-2 actual
headers; locate and modify the loop in HttpParser.h, the headers[0] usage, and
the CLI flag description accordingly.

In `@src/bun.js/node/node_http_binding.zig`:
- Around line 49-65: The setMaxHTTPHeadersCount function can panic when num
exceeds u32 max; add an upper-bound check after coercing num to ensure num <=
std.math.maxInt(u32) and return globalThis.throwInvalidArgumentTypeValue (or a
similar JS error) if it’s larger, otherwise safely assign
bun.http.max_http_headers_count using `@intCast`; reference the symbols
setMaxHTTPHeadersCount, num, std.math.maxInt(u32), `@intCast`, and
bun.http.max_http_headers_count when implementing the validation and error
return.

In `@test/regression/issue/6982.test.ts`:
- Around line 81-85: The current logic reads a single chunk from
proc.stdout.getReader() and decodes value into url, which can break if the URL
is split across chunks; change to a loop that repeatedly reads from
reader.read(), appends decoded chunks into a buffer, and stops when a newline is
encountered (or EOF), then trim to produce url; apply the same fix to the second
occurrence that also reads stdout (lines referenced around the second block).
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 6104705 and 785976d.

📒 Files selected for processing (12)
  • packages/bun-uws/src/App.h
  • packages/bun-uws/src/HttpContext.h
  • packages/bun-uws/src/HttpContextData.h
  • packages/bun-uws/src/HttpParser.h
  • src/bun.js/node/node_http_binding.zig
  • src/cli/Arguments.zig
  • src/deps/libuwsockets.cpp
  • src/deps/uws/App.zig
  • src/http.zig
  • src/js/internal/http.ts
  • src/js/node/http.ts
  • test/regression/issue/6982.test.ts
🧰 Additional context used
📓 Path-based instructions (8)
**/*.zig

📄 CodeRabbit inference engine (CLAUDE.md)

In Zig code, be careful with allocators and use defer for cleanup

Files:

  • src/bun.js/node/node_http_binding.zig
  • src/deps/uws/App.zig
  • src/http.zig
  • src/cli/Arguments.zig
src/**/*.zig

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/*.zig: Use the # prefix for private fields in Zig structs, e.g., struct { #foo: u32 };
Use Decl literals in Zig, e.g., const decl: Decl = .{ .binding = 0, .value = 0 };
Place @import statements at the bottom of the file in Zig (auto formatter will handle positioning)
Never use @import() inline inside functions in Zig; always place imports at the bottom of the file or containing struct

Files:

  • src/bun.js/node/node_http_binding.zig
  • src/deps/uws/App.zig
  • src/http.zig
  • src/cli/Arguments.zig
src/js/{builtins,node,bun,thirdparty,internal}/**/*.{ts,js}

📄 CodeRabbit inference engine (src/js/CLAUDE.md)

src/js/{builtins,node,bun,thirdparty,internal}/**/*.{ts,js}: Use .$call() and .$apply() instead of .call() and .apply() to prevent user tampering with function invocation
Use string literal require() statements only; dynamic requires are not permitted
Export modules using export default { ... } syntax; modules are NOT ES modules
Use JSC intrinsics (prefixed with $) such as $Array.from(), $isCallable(), and $newArrayWithSize() for performance-critical operations
Use private globals and methods with $ prefix (e.g., $Array, map.$set()) instead of public JavaScript globals
Use $debug() for debug logging and $assert() for assertions; both are stripped in release builds
Validate function arguments using validators from internal/validators and throw $ERR_* error codes for invalid arguments
Use process.platform and process.arch for platform detection; these values are inlined and dead-code eliminated at build time

Files:

  • src/js/node/http.ts
  • src/js/internal/http.ts
src/js/{builtins,node,bun,thirdparty,internal}/**/*.ts

📄 CodeRabbit inference engine (src/js/CLAUDE.md)

Builtin functions must include this parameter typing in TypeScript to enable direct method binding in C++

Files:

  • src/js/node/http.ts
  • src/js/internal/http.ts
**/*.test.ts?(x)

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.test.ts?(x): Never use bun test directly - always use bun bd test to run tests with debug build changes
For single-file tests, prefer -e flag over tempDir
For multi-file tests, prefer tempDir and Bun.spawn over single-file tests
Use normalizeBunSnapshot to normalize snapshot output of tests
Never write tests that check for 'panic', 'uncaught exception', or similar strings in test output
Use tempDir from harness to create temporary directories - do not use tmpdirSync or fs.mkdtempSync
When spawning processes in tests, expect stdout before expecting exit code for more useful error messages on test failure
Do not write flaky tests - do not use setTimeout in tests; instead await the condition to be met
Verify tests fail with USE_SYSTEM_BUN=1 bun test <file> and pass with bun bd test <file> - tests are invalid if they pass with USE_SYSTEM_BUN=1
Test files must end with .test.ts or .test.tsx
Avoid shell commands like find or grep in tests - use Bun's Glob and built-in tools instead

Files:

  • test/regression/issue/6982.test.ts
test/regression/issue/*.test.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Place regression tests for specific GitHub issues in test/regression/issue/${issueNumber}.test.ts with real issue numbers only

Files:

  • test/regression/issue/6982.test.ts
test/**/*.test.ts?(x)

📄 CodeRabbit inference engine (CLAUDE.md)

Always use port: 0 in tests - do not hardcode ports or use custom random port number functions

Files:

  • test/regression/issue/6982.test.ts
test/**/*.test.{ts,js,jsx,tsx,mjs,cjs}

📄 CodeRabbit inference engine (test/CLAUDE.md)

test/**/*.test.{ts,js,jsx,tsx,mjs,cjs}: Use bun bd test <...test file> to run tests with compiled code changes. Do not use bun test as it will not include your changes.
Use bun:test for files ending in *.test.{ts,js,jsx,tsx,mjs,cjs}. For test files without .test extension in test/js/node/test/{parallel,sequential}/*.js, use bun bd <file> instead of bun bd test <file> since they expect exit code 0.
Do not set a timeout on tests. Bun already has timeouts built-in.

Files:

  • test/regression/issue/6982.test.ts
🧠 Learnings (35)
📓 Common learnings
Learnt from: RiskyMH
Repo: oven-sh/bun PR: 24719
File: docs/bundler/executables.mdx:527-560
Timestamp: 2025-11-14T16:07:01.064Z
Learning: In the Bun repository, certain bundler features like compile with code splitting (--compile --splitting) are CLI-only and not supported in the Bun.build() JavaScript API. Tests for CLI-only features use backend: "cli" flag (e.g., test/bundler/bundler_compile_splitting.test.ts). The CompileBuildConfig interface correctly restricts these with splitting?: never;. When documenting CLI-only bundler features, add a note clarifying they're not available via the programmatic API.
Learnt from: franciscop
Repo: oven-sh/bun PR: 24514
File: src/bun.js/api/crypto/PasswordObject.zig:86-101
Timestamp: 2025-11-10T00:57:09.173Z
Learning: In Bun's Zig codebase (PasswordObject.zig), when validating the parallelism parameter for Argon2, the upper limit is set to 65535 (2^16 - 1) rather than using `std.math.maxInt(u24)` because the latter triggers Zig's truncation limit checks. The value 65535 is a practical upper bound that avoids compiler issues while being sufficient for thread parallelism use cases.
Learnt from: Jarred-Sumner
Repo: oven-sh/bun PR: 24086
File: src/bun.js/api/server.zig:2534-2535
Timestamp: 2025-10-26T04:50:17.892Z
Learning: In src/bun.js/api/server.zig, u32 is acceptable for route indices and websocket_context_index fields, as the practical limit of 4 billion contexts will never be reached.
📚 Learning: 2025-10-19T04:55:33.099Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 23798
File: test/js/bun/http/node-telemetry.test.ts:27-203
Timestamp: 2025-10-19T04:55:33.099Z
Learning: In test/js/bun/http/node-telemetry.test.ts and the Bun.telemetry._node_binding API, after the architecture refactor, the _node_binding interface only contains two methods: handleIncomingRequest(req, res) and handleWriteHead(res, statusCode). The handleRequestFinish hook and other lifecycle hooks were removed during simplification. Both current methods are fully tested.

Applied to files:

  • src/bun.js/node/node_http_binding.zig
  • test/regression/issue/6982.test.ts
  • src/js/internal/http.ts
📚 Learning: 2025-10-17T20:50:58.644Z
Learnt from: taylordotfish
Repo: oven-sh/bun PR: 23755
File: src/bun.js/api/bun/socket/Handlers.zig:154-159
Timestamp: 2025-10-17T20:50:58.644Z
Learning: In Bun socket configuration error messages (src/bun.js/api/bun/socket/Handlers.zig), use the user-facing JavaScript names "data" and "drain" instead of internal field names "onData" and "onWritable", as these are the names users see in the API according to SocketConfig.bindv2.ts.

Applied to files:

  • src/bun.js/node/node_http_binding.zig
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/src/napi/napi.zig : For each new V8 C++ method, add both GCC/Clang and MSVC mangled symbol names to the V8API struct in src/napi/napi.zig using extern fn declarations

Applied to files:

  • src/bun.js/node/node_http_binding.zig
  • src/deps/uws/App.zig
📚 Learning: 2025-11-24T18:37:47.899Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/AGENTS.md:0-0
Timestamp: 2025-11-24T18:37:47.899Z
Learning: Applies to src/bun.js/bindings/v8/**/<UNKNOWN> : <UNKNOWN>

Applied to files:

  • src/bun.js/node/node_http_binding.zig
📚 Learning: 2025-10-26T04:50:17.892Z
Learnt from: Jarred-Sumner
Repo: oven-sh/bun PR: 24086
File: src/bun.js/api/server.zig:2534-2535
Timestamp: 2025-10-26T04:50:17.892Z
Learning: In src/bun.js/api/server.zig, u32 is acceptable for route indices and websocket_context_index fields, as the practical limit of 4 billion contexts will never be reached.

Applied to files:

  • src/bun.js/node/node_http_binding.zig
  • src/deps/uws/App.zig
  • src/http.zig
  • packages/bun-uws/src/HttpParser.h
  • src/js/internal/http.ts
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/src/symbols.txt : Add symbol names without leading underscore to src/symbols.txt for each new V8 API method

Applied to files:

  • src/bun.js/node/node_http_binding.zig
📚 Learning: 2025-10-01T21:59:54.571Z
Learnt from: taylordotfish
Repo: oven-sh/bun PR: 23169
File: src/bun.js/bindings/webcore/JSDOMConvertEnumeration.h:47-74
Timestamp: 2025-10-01T21:59:54.571Z
Learning: In the new bindings generator (bindgenv2) for `src/bun.js/bindings/webcore/JSDOMConvertEnumeration.h`, the context-aware enumeration conversion overloads intentionally use stricter validation (requiring `value.isString()` without ToString coercion), diverging from Web IDL semantics. This is a design decision documented in comments.

Applied to files:

  • src/bun.js/node/node_http_binding.zig
📚 Learning: 2025-12-16T00:21:32.179Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T00:21:32.179Z
Learning: Applies to src/bun.js/bindings/**/*.cpp : Cache structures in ZigGlobalObject for JavaScript class bindings

Applied to files:

  • src/bun.js/node/node_http_binding.zig
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/test/v8/v8-module/main.cpp : Register new V8 API test functions in the Init method using NODE_SET_METHOD with exports object

Applied to files:

  • src/bun.js/node/node_http_binding.zig
📚 Learning: 2025-10-18T20:50:47.750Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 23798
File: src/bun.js/telemetry.zig:366-373
Timestamp: 2025-10-18T20:50:47.750Z
Learning: In Bun's Zig codebase (src/bun.js/bindings/JSValue.zig), the JSValue enum uses `.null` (not `.js_null`) for JavaScript's null value. Only `js_undefined` has the `js_` prefix to avoid collision with Zig's built-in `undefined` keyword. The correct enum fields are: `js_undefined`, `null`, `true`, `false`, and `zero`.

Applied to files:

  • src/bun.js/node/node_http_binding.zig
📚 Learning: 2025-09-05T18:44:43.223Z
Learnt from: markovejnovic
Repo: oven-sh/bun PR: 21728
File: src/bun.js/bindings/bindings.cpp:6429-6432
Timestamp: 2025-09-05T18:44:43.223Z
Learning: The JSC::JSMap::size() method in JavaScriptCore returns a value that can be represented as uint32_t, and the binding functions in src/bun.js/bindings/bindings.cpp correctly use uint32_t as the return type for JSC__JSMap__size. JavaScript Maps are practically limited to 2^32 - 1 elements.

Applied to files:

  • src/bun.js/node/node_http_binding.zig
📚 Learning: 2026-01-05T16:32:07.551Z
Learnt from: alii
Repo: oven-sh/bun PR: 25474
File: src/bun.js/event_loop/Sigusr1Handler.zig:0-0
Timestamp: 2026-01-05T16:32:07.551Z
Learning: In Zig codebases (e.g., Bun), treat std.posix.sigaction as returning void and do not perform runtime error handling for its failure. The Zig standard library views sigaction failures as programmer errors (unreachable) because they only occur with invalid signals like SIGKILL/SIGSTOP. Apply this pattern across Zig files that call sigaction (e.g., crash_handler.zig, main.zig, filter_run.zig, process.zig) and ensure failures are not handled as recoverable errors; prefer reaching an explicit unreachable/compile-time assumption when such failures are detected.

Applied to files:

  • src/bun.js/node/node_http_binding.zig
  • src/deps/uws/App.zig
  • src/http.zig
  • src/cli/Arguments.zig
📚 Learning: 2026-01-10T00:28:26.694Z
Learnt from: cirospaciari
Repo: oven-sh/bun PR: 25938
File: packages/bun-uws/src/HttpParser.h:0-0
Timestamp: 2026-01-10T00:28:26.694Z
Learning: In packages/bun-uws/src/HttpParser.h, the headData and headLength fields on HttpRequest are intentionally left populated for all request types (not just CONNECT/upgrade), as they will be used in the future for parse errors and other Node.js compatibility features. They should not be cleared after the requestHandler call.

Applied to files:

  • packages/bun-uws/src/HttpContextData.h
  • packages/bun-uws/src/HttpContext.h
  • packages/bun-uws/src/HttpParser.h
📚 Learning: 2025-11-12T04:11:52.293Z
Learnt from: cirospaciari
Repo: oven-sh/bun PR: 24622
File: src/deps/uws/us_socket_t.zig:112-113
Timestamp: 2025-11-12T04:11:52.293Z
Learning: In Bun's Zig codebase, when passing u32 values to C FFI functions that expect c_uint parameters, no explicit intCast is needed because c_uint is equivalent to u32 on Bun's target platforms and Zig allows implicit coercion between equivalent types. This pattern is used consistently throughout src/deps/uws/us_socket_t.zig in functions like setTimeout, setLongTimeout, and setKeepalive.

Applied to files:

  • src/deps/uws/App.zig
  • packages/bun-uws/src/HttpParser.h
  • src/js/internal/http.ts
📚 Learning: 2025-10-19T04:55:27.213Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 23798
File: test/js/bun/http/node-telemetry.test.ts:27-88
Timestamp: 2025-10-19T04:55:27.213Z
Learning: In the Bun.telemetry._node_binding API for Node.js http.createServer compatibility, there are exactly two hooks: handleIncomingRequest(req, res) called once per request (returns a request ID), and handleWriteHead(res, statusCode) called once when headers are sent (explicit or implicit). The old handleRequestFinish hook no longer exists after architectural refactoring. Both hooks are tested in test/js/bun/http/node-telemetry.test.ts.

Applied to files:

  • src/js/node/http.ts
📚 Learning: 2025-11-10T00:57:09.173Z
Learnt from: franciscop
Repo: oven-sh/bun PR: 24514
File: src/bun.js/api/crypto/PasswordObject.zig:86-101
Timestamp: 2025-11-10T00:57:09.173Z
Learning: In Bun's Zig codebase (PasswordObject.zig), when validating the parallelism parameter for Argon2, the upper limit is set to 65535 (2^16 - 1) rather than using `std.math.maxInt(u24)` because the latter triggers Zig's truncation limit checks. The value 65535 is a practical upper bound that avoids compiler issues while being sufficient for thread parallelism use cases.

Applied to files:

  • src/http.zig
  • src/cli/Arguments.zig
📚 Learning: 2025-09-03T05:09:24.272Z
Learnt from: Jarred-Sumner
Repo: oven-sh/bun PR: 22335
File: src/http.zig:1376-1393
Timestamp: 2025-09-03T05:09:24.272Z
Learning: In bun's HTTP module, `bun.http.default_allocator` is the correct allocator to use for internal HTTP buffers like MutableString initialization for response_message_buffer and compressed_body. This allocator is initialized in HTTPThread.zig as `bun.http.default_arena.allocator()` and is used consistently across the HTTP module, separate from any local `default_allocator` variables.

Applied to files:

  • src/http.zig
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/test/v8/v8.test.ts : Add corresponding test cases to test/v8/v8.test.ts using checkSameOutput() function to compare Node.js and Bun output

Applied to files:

  • test/regression/issue/6982.test.ts
📚 Learning: 2025-10-18T05:23:24.403Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 23798
File: test/js/bun/telemetry-server.test.ts:91-100
Timestamp: 2025-10-18T05:23:24.403Z
Learning: In the Bun codebase, telemetry tests (test/js/bun/telemetry-*.test.ts) should focus on telemetry API behavior: configure/disable/isEnabled, callback signatures and invocation, request ID correlation, and error handling. HTTP protocol behaviors like status code normalization (e.g., 200 with empty body → 204) should be tested in HTTP server tests (test/js/bun/http/), not in telemetry tests. Keep separation of concerns: telemetry tests verify the telemetry API contract; HTTP tests verify HTTP semantics.

Applied to files:

  • test/regression/issue/6982.test.ts
📚 Learning: 2025-12-16T00:21:32.179Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T00:21:32.179Z
Learning: Applies to test/regression/issue/*.test.ts : Place regression tests for specific GitHub issues in `test/regression/issue/${issueNumber}.test.ts` with real issue numbers only

Applied to files:

  • test/regression/issue/6982.test.ts
📚 Learning: 2025-11-14T16:07:01.064Z
Learnt from: RiskyMH
Repo: oven-sh/bun PR: 24719
File: docs/bundler/executables.mdx:527-560
Timestamp: 2025-11-14T16:07:01.064Z
Learning: In the Bun repository, certain bundler features like compile with code splitting (--compile --splitting) are CLI-only and not supported in the Bun.build() JavaScript API. Tests for CLI-only features use backend: "cli" flag (e.g., test/bundler/bundler_compile_splitting.test.ts). The CompileBuildConfig interface correctly restricts these with splitting?: never;. When documenting CLI-only bundler features, add a note clarifying they're not available via the programmatic API.

Applied to files:

  • test/regression/issue/6982.test.ts
📚 Learning: 2026-01-05T23:04:01.518Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: test/CLAUDE.md:0-0
Timestamp: 2026-01-05T23:04:01.518Z
Learning: Applies to test/**/*-fixture.ts : Test files that spawn Bun processes should end in `*-fixture.ts` to identify them as test fixtures rather than tests themselves.

Applied to files:

  • test/regression/issue/6982.test.ts
📚 Learning: 2025-10-26T01:32:04.844Z
Learnt from: Jarred-Sumner
Repo: oven-sh/bun PR: 24082
File: test/cli/test/coverage.test.ts:60-112
Timestamp: 2025-10-26T01:32:04.844Z
Learning: In the Bun repository test files (test/cli/test/*.test.ts), when spawning Bun CLI commands with Bun.spawnSync for testing, prefer using stdio: ["inherit", "inherit", "inherit"] to inherit stdio streams rather than piping them.

Applied to files:

  • test/regression/issue/6982.test.ts
📚 Learning: 2025-12-16T00:21:32.179Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T00:21:32.179Z
Learning: Applies to **/*.test.ts?(x) : Verify tests fail with `USE_SYSTEM_BUN=1 bun test <file>` and pass with `bun bd test <file>` - tests are invalid if they pass with USE_SYSTEM_BUN=1

Applied to files:

  • test/regression/issue/6982.test.ts
📚 Learning: 2026-01-05T23:04:01.518Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: test/CLAUDE.md:0-0
Timestamp: 2026-01-05T23:04:01.518Z
Learning: Applies to test/**/*.test.{ts,js,jsx,tsx,mjs,cjs} : Use `bun bd test <...test file>` to run tests with compiled code changes. Do not use `bun test` as it will not include your changes.

Applied to files:

  • test/regression/issue/6982.test.ts
📚 Learning: 2026-01-05T23:04:01.518Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: test/CLAUDE.md:0-0
Timestamp: 2026-01-05T23:04:01.518Z
Learning: Organize regression tests for specific issues in `/test/regression/issue/${issueNumber}.test.ts`. Do not place regression tests in the regression directory if there is no associated issue number.

Applied to files:

  • test/regression/issue/6982.test.ts
📚 Learning: 2026-01-05T23:04:01.518Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: test/CLAUDE.md:0-0
Timestamp: 2026-01-05T23:04:01.518Z
Learning: Applies to test/**/*.test.{ts,js,jsx,tsx,mjs,cjs} : Use `bun:test` for files ending in `*.test.{ts,js,jsx,tsx,mjs,cjs}`. For test files without .test extension in test/js/node/test/{parallel,sequential}/*.js, use `bun bd <file>` instead of `bun bd test <file>` since they expect exit code 0.

Applied to files:

  • test/regression/issue/6982.test.ts
📚 Learning: 2026-01-14T21:08:10.406Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: test/js/node/test/parallel/CLAUDE.md:0-0
Timestamp: 2026-01-14T21:08:10.406Z
Learning: These are Node.js compatibility tests not written by Bun and cannot be modified

Applied to files:

  • test/regression/issue/6982.test.ts
📚 Learning: 2025-10-19T02:44:46.354Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 23798
File: packages/bun-otel/context-propagation.test.ts:1-1
Timestamp: 2025-10-19T02:44:46.354Z
Learning: In the Bun repository, standalone packages under packages/ (e.g., bun-vscode, bun-inspector-protocol, bun-plugin-yaml, bun-plugin-svelte, bun-debug-adapter-protocol, bun-otel) co-locate their tests with package source code using *.test.ts files. This follows standard npm/monorepo patterns. The test/ directory hierarchy (test/js/bun/, test/cli/, test/js/node/) is reserved for testing Bun's core runtime APIs and built-in functionality, not standalone packages.

Applied to files:

  • test/regression/issue/6982.test.ts
📚 Learning: 2026-01-05T23:04:01.518Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: test/CLAUDE.md:0-0
Timestamp: 2026-01-05T23:04:01.518Z
Learning: Applies to test/**/*.test.{ts,js,jsx,tsx,mjs,cjs} : Do not set a timeout on tests. Bun already has timeouts built-in.

Applied to files:

  • test/regression/issue/6982.test.ts
📚 Learning: 2025-09-20T05:35:57.318Z
Learnt from: pfgithub
Repo: oven-sh/bun PR: 22534
File: src/bun.js/bindings/headers.h:729-731
Timestamp: 2025-09-20T05:35:57.318Z
Learning: symbols.txt in the Bun codebase is specifically for V8 API mangled symbols (without leading underscore), not for general Bun host functions declared with BUN_DECLARE_HOST_FUNCTION. Host functions are handled through different build mechanisms.

Applied to files:

  • packages/bun-uws/src/HttpParser.h
📚 Learning: 2025-10-15T20:19:38.580Z
Learnt from: markovejnovic
Repo: oven-sh/bun PR: 23680
File: cmake/targets/BuildBun.cmake:822-822
Timestamp: 2025-10-15T20:19:38.580Z
Learning: In the Bun codebase, FFI is compiled with tcc (TinyCC), which barely supports C99. The headers `src/bun.js/api/FFI.h` and `src/bun.js/api/ffi-stdbool.h` are only used for FFI compilation with tcc, not for the main Bun target. Therefore, C23 compatibility concerns (such as bool/true/false keyword conflicts) do not apply to these FFI headers.

Applied to files:

  • packages/bun-uws/src/HttpParser.h
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/V8*.h : Add BUN_EXPORT visibility attribute to all public V8 API functions to ensure proper symbol export across platforms

Applied to files:

  • packages/bun-uws/src/HttpParser.h
📚 Learning: 2025-10-01T21:48:38.278Z
Learnt from: taylordotfish
Repo: oven-sh/bun PR: 23169
File: src/bun.js/bindings/Bindgen/IDLTypes.h:1-3
Timestamp: 2025-10-01T21:48:38.278Z
Learning: In the Bun codebase, for `BunIDL*` and `Bindgen*` headers (e.g., BunIDLTypes.h, Bindgen/IDLTypes.h), it's acceptable to rely on transitive includes for standard library headers like <type_traits> and <utility> rather than including them explicitly.

Applied to files:

  • packages/bun-uws/src/HttpParser.h
🧬 Code graph analysis (5)
packages/bun-uws/src/HttpContextData.h (1)
src/js/node/http.ts (2)
  • maxHeadersCount (64-66)
  • maxHeadersCount (67-69)
src/js/node/http.ts (1)
src/js/internal/http.ts (2)
  • getMaxHTTPHeadersCount (507-507)
  • setMaxHTTPHeadersCount (557-557)
test/regression/issue/6982.test.ts (1)
test/harness.ts (1)
  • tempDir (277-284)
packages/bun-uws/src/HttpParser.h (2)
src/js/node/http.ts (4)
  • maxHeadersCount (64-66)
  • maxHeadersCount (67-69)
  • maxHeaderSize (58-60)
  • maxHeaderSize (61-63)
packages/bun-uws/src/HttpContextData.h (1)
  • `` (40-85)
packages/bun-uws/src/App.h (2)
src/js/internal/http.ts (1)
  • setMaxHTTPHeadersCount (557-557)
src/js/node/http.ts (2)
  • maxHeadersCount (64-66)
  • maxHeadersCount (67-69)
🔇 Additional comments (23)
src/deps/libuwsockets.cpp (1)

534-542: LGTM!

The implementation correctly follows the established pattern used by uws_app_set_max_http_header_size and other similar functions in this file. The SSL/non-SSL dispatch logic is consistent with the rest of the codebase.

packages/bun-uws/src/HttpContextData.h (1)

73-73: LGTM!

The new maxHeadersCount field is appropriately typed as uint32_t, has a sensible default value with clear documentation of the sentinel semantics (0 = use default), and follows the same pattern as the existing maxHeaderSize field.

src/deps/uws/App.zig (1)

66-68: LGTM!

The new setMaxHTTPHeadersCount method correctly follows the established pattern used by setMaxHTTPHeaderSize. The extern declaration at line 411 properly matches the C++ function signature.

packages/bun-uws/src/App.h (1)

669-672: LGTM!

The setMaxHTTPHeadersCount method correctly mirrors the pattern established by setMaxHTTPHeaderSize, maintaining API consistency and supporting the fluent builder pattern via std::move(*this).

src/http.zig (1)

18-21: LGTM!

The global configuration variable is correctly defined with an appropriate default value of 100 and follows the established pattern used by max_http_header_size. The export with BUN_DEFAULT_MAX_HTTP_HEADERS_COUNT enables access from other parts of the codebase.

packages/bun-uws/src/HttpContext.h (1)

246-246: LGTM!

The maxHeadersCount parameter is correctly passed to consumePostPadded, following the same pattern as maxHeaderSize. The placement and ordering are consistent with the function signature.

src/cli/Arguments.zig (2)

106-106: LGTM!

The parameter declaration follows the established pattern used by --max-http-header-size and provides a clear description.


739-749: LGTM!

The parsing logic correctly mirrors the existing --max-http-header-size pattern. Using u32 is appropriate and matches the underlying C++ type in HttpContextData. The "0 means unlimited" behavior provides a consistent user experience.

src/js/node/http.ts (2)

9-16: LGTM!

The imports are correctly structured alongside the existing setMaxHTTPHeaderSize and getMaxHTTPHeaderSize bindings.


64-69: LGTM!

The getter/setter pair for maxHeadersCount follows the exact same pattern as maxHeaderSize, maintaining API consistency.

src/js/internal/http.ts (2)

355-356: LGTM!

The Zig function bindings are correctly defined with appropriate arities (1 for setter, 0 for getter), following the established pattern for setMaxHTTPHeaderSize/getMaxHTTPHeaderSize.


507-507: LGTM!

The exports are correctly added and maintain alphabetical ordering within the export block.

Also applies to: 557-557

test/regression/issue/6982.test.ts (5)

1-17: LGTM!

The test correctly validates the default getter value. Good use of await using for process cleanup and proper sequencing of stdout before exitCode.


19-42: LGTM!

The setter test properly validates both the initial default value and the updated value after assignment.


44-56: LGTM!

The CLI flag test correctly verifies that --max-http-header-count=200 sets the value accessible via http.maxHeadersCount.


58-100: LGTM!

The test correctly validates that a server with an increased header limit accepts requests with 150 headers. Good use of port: 0 and proper cleanup with proc.kill().


102-143: LGTM!

The test correctly validates that the server returns HTTP 431 when header count exceeds the configured limit. This verifies the core functionality requested in issue #6982.

src/bun.js/node/node_http_binding.zig (1)

43-47: LGTM!

The getter follows the established pattern from getMaxHTTPHeaderSize and correctly returns the current value.

packages/bun-uws/src/HttpParser.h (5)

48-48: LGTM!

The extern declaration follows the established pattern and uses appropriate type.


152-167: Good design with stack/heap hybrid allocation.

The implementation provides a fast path with stack-allocated storage for the default case while supporting larger limits via dynamic allocation. The RAII-managed vector handles cleanup correctly.


176-192: LGTM!

The dynamic allocation logic correctly switches between stack and heap storage based on the configured limit. The fallback to BUN_DEFAULT_MAX_HTTP_HEADERS_COUNT when count is 0 ensures consistent default behavior.


859-860: LGTM!

The per-request header limit is correctly threaded through to the getHeaders call.


992-997: LGTM!

The public API correctly accepts the maxHeadersCount parameter and configures the HttpRequest before parsing begins, enabling the dynamic allocation path when the limit exceeds the default.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

headers++;

for (unsigned int i = 1; i < UWS_HTTP_MAX_HEADERS_COUNT - 1; i++) {
for (unsigned int i = 1; i < maxHeadersCount - 1; i++) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

rg -n "max-http-header-count" --type=ts --type=md -C2

Repository: oven-sh/bun

Length of output: 1748


🏁 Script executed:

# Also search for related config/flag documentation
rg -n "maxHeadersCount\|max.*header.*count" --type=ts --type=md --type=js -C2 | head -50

Repository: oven-sh/bun

Length of output: 37


🏁 Script executed:

# Examine the HttpParser.h file to understand the context around line 757
sed -n '700,850p' packages/bun-uws/src/HttpParser.h | cat -n

Repository: oven-sh/bun

Length of output: 10011


🏁 Script executed:

cat test/regression/issue/6982.test.ts

Repository: oven-sh/bun

Length of output: 4296


🏁 Script executed:

# Search for CLI flag documentation or help text
rg -n "max.*header.*count" packages/bun-uws/ -C3 --type=h --type=cpp

Repository: oven-sh/bun

Length of output: 1887


🏁 Script executed:

# Look for where maxHeadersCount is set/initialized
rg -n "maxHeadersCount\s*=" packages/bun-uws/src/ --type=h --type=cpp -C2

Repository: oven-sh/bun

Length of output: 1542


🏁 Script executed:

# Check for documentation about the flag in CLI help text
rg -n "max-http-header-count\|maxHeadersCount" packages/bun/src --type=cpp --type=ts -B2 -A2 | head -100

Repository: oven-sh/bun

Length of output: 111


🏁 Script executed:

# Look for the default constant definition
rg -n "UWS_HTTP_MAX_HEADERS_COUNT\|BUN_DEFAULT_MAX_HTTP_HEADERS_COUNT" packages/bun-uws/ -C2 --type=h --type=cpp

Repository: oven-sh/bun

Length of output: 37


🏁 Script executed:

# Check if there's any comment explaining why the loop is i < maxHeadersCount - 1
sed -n '750,760p' packages/bun-uws/src/HttpParser.h

Repository: oven-sh/bun

Length of output: 573


🏁 Script executed:

# Search for the constant definitions more broadly
rg -n "UWS_HTTP_MAX_HEADERS_COUNT\|BUN_DEFAULT_MAX_HTTP_HEADERS_COUNT" --type=h --type=cpp -C2

Repository: oven-sh/bun

Length of output: 37


🏁 Script executed:

# Look for CLI flag handling in the main bun code
fd -n "main.cpp\|cli.cpp\|*.cpp" packages/bun | head -20

Repository: oven-sh/bun

Length of output: 285


🏁 Script executed:

# Search for where maxHeadersCount is passed to the parser
rg -n "setMaxHeadersCount\|max.*header.*count" --type=cpp --type=ts -B3 -A3 | head -80

Repository: oven-sh/bun

Length of output: 37


🏁 Script executed:

# Search for the constant definitions
rg "UWS_HTTP_MAX_HEADERS_COUNT|BUN_DEFAULT_MAX_HTTP_HEADERS_COUNT" --type=h --type=cpp -C2

Repository: oven-sh/bun

Length of output: 3040


🏁 Script executed:

# Check the entire HttpParser.h to understand the flow
wc -l packages/bun-uws/src/HttpParser.h

Repository: oven-sh/bun

Length of output: 93


🏁 Script executed:

# Look at where the loop counter is actually used and what happens at the boundary
sed -n '756,830p' packages/bun-uws/src/HttpParser.h | cat -n

Repository: oven-sh/bun

Length of output: 5301


🏁 Script executed:

# Check if the test actually validates the boundary behavior
sed -n '100,130p' test/regression/issue/6982.test.ts

Repository: oven-sh/bun

Length of output: 912


🏁 Script executed:

# Look for any comments explaining the off-by-one logic in the loop
sed -n '740,760p' packages/bun-uws/src/HttpParser.h | cat -n

Repository: oven-sh/bun

Length of output: 1164


🏁 Script executed:

# See where the terminator is used and if it's counted in the limit
rg -n "string_view(nullptr" packages/bun-uws/src/HttpParser.h -B2 -A2

Repository: oven-sh/bun

Length of output: 136


🏁 Script executed:

# Search for the terminator initialization - escape properly
rg -n "string_view.*nullptr.*0" packages/bun-uws/src/HttpParser.h -B2 -A2

Repository: oven-sh/bun

Length of output: 672


🏁 Script executed:

# Let's trace through what happens when we parse a request with maxHeadersCount=50
# Check if there's validation that accounts for the off-by-two
python3 <<'EOF'
# Simulate the loop logic
maxHeadersCount = 50

# Array indices:
# [0] = request line (headers[0])
# [1..48] = actual headers (loop runs for i=1 to i<49, so i=1 to 48)
# [49] = terminator slot (headers->key = string_view(nullptr, 0))

loop_iterations = 0
for i in range(1, maxHeadersCount - 1):
    loop_iterations += 1

print(f"maxHeadersCount: {maxHeadersCount}")
print(f"Loop range: i from 1 to {maxHeadersCount - 2} (inclusive)")
print(f"Loop iterations: {loop_iterations}")
print(f"Array layout:")
print(f"  [0] = request line")
print(f"  [1..{maxHeadersCount - 2}] = actual headers ({loop_iterations} slots)")
print(f"  [{maxHeadersCount - 1}] = terminator")
print(f"\nEffective user-facing limit: {maxHeadersCount - 2} headers")
print(f"If user sets --max-http-header-count=50, they get 48 actual headers")
EOF

Repository: oven-sh/bun

Length of output: 141


🏁 Script executed:

# Check the test to see what it actually validates - the rejection test
sed -n '110,140p' test/regression/issue/6982.test.ts

Repository: oven-sh/bun

Length of output: 907


The effective header limit is maxHeadersCount - 2 due to reserved slots for the request line and terminator.

The loop for (unsigned int i = 1; i < maxHeadersCount - 1; i++) combined with headers[0] storing the request line means users can parse only maxHeadersCount - 2 actual headers. With the default of 100, only 98 headers are supported; setting --max-http-header-count=50 allows only 48 headers, not 50.

This appears intentional (per the comment "This cann take the very last header space" at line 823), but the user-facing CLI flag description should clarify this discrepancy, or consider adjusting the internal logic to make the advertised limit match the actual parsing capacity.

🤖 Prompt for AI Agents
In `@packages/bun-uws/src/HttpParser.h` at line 757, The loop for parsing headers
(for (unsigned int i = 1; i < maxHeadersCount - 1; i++)), combined with
headers[0] being used for the request line, means the effective capacity is
maxHeadersCount - 2; update either the parsing logic or the CLI description:
either change the loop bound to i < maxHeadersCount (and adjust any
sentinel/terminator handling and the comment "This cann take the very last
header space") so that setting --max-http-header-count = N allows N headers, or
keep the loop but change the user-facing --max-http-header-count help text to
explicitly state the value reserves two slots (request line + terminator) and
thus supports N-2 actual headers; locate and modify the loop in HttpParser.h,
the headers[0] usage, and the CLI flag description accordingly.

Comment on lines +49 to +65
pub fn setMaxHTTPHeadersCount(globalThis: *jsc.JSGlobalObject, callframe: *jsc.CallFrame) bun.JSError!jsc.JSValue {
const arguments = callframe.arguments_old(1).slice();
if (arguments.len < 1) {
return globalThis.throwNotEnoughArguments("setMaxHTTPHeadersCount", 1, arguments.len);
}
const value = arguments[0];
const num = try value.coerceToInt64(globalThis);
if (num < 0) {
return globalThis.throwInvalidArgumentTypeValue("maxHeadersCount", "non-negative integer", value);
}
if (num == 0) {
bun.http.max_http_headers_count = std.math.maxInt(u32);
} else {
bun.http.max_http_headers_count = @intCast(num);
}
return jsc.JSValue.jsNumber(bun.http.max_http_headers_count);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Potential integer overflow on large input values.

If num exceeds std.math.maxInt(u32) (4,294,967,295), the @intCast at line 62 will cause a runtime panic. JavaScript can pass values up to Number.MAX_SAFE_INTEGER which is much larger than u32 max.

🔧 Suggested fix: Add upper bound validation
 pub fn setMaxHTTPHeadersCount(globalThis: *jsc.JSGlobalObject, callframe: *jsc.CallFrame) bun.JSError!jsc.JSValue {
     const arguments = callframe.arguments_old(1).slice();
     if (arguments.len < 1) {
         return globalThis.throwNotEnoughArguments("setMaxHTTPHeadersCount", 1, arguments.len);
     }
     const value = arguments[0];
     const num = try value.coerceToInt64(globalThis);
     if (num < 0) {
         return globalThis.throwInvalidArgumentTypeValue("maxHeadersCount", "non-negative integer", value);
     }
     if (num == 0) {
         bun.http.max_http_headers_count = std.math.maxInt(u32);
+    } else if (num > std.math.maxInt(u32)) {
+        bun.http.max_http_headers_count = std.math.maxInt(u32);
     } else {
         bun.http.max_http_headers_count = `@intCast`(num);
     }
     return jsc.JSValue.jsNumber(bun.http.max_http_headers_count);
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
pub fn setMaxHTTPHeadersCount(globalThis: *jsc.JSGlobalObject, callframe: *jsc.CallFrame) bun.JSError!jsc.JSValue {
const arguments = callframe.arguments_old(1).slice();
if (arguments.len < 1) {
return globalThis.throwNotEnoughArguments("setMaxHTTPHeadersCount", 1, arguments.len);
}
const value = arguments[0];
const num = try value.coerceToInt64(globalThis);
if (num < 0) {
return globalThis.throwInvalidArgumentTypeValue("maxHeadersCount", "non-negative integer", value);
}
if (num == 0) {
bun.http.max_http_headers_count = std.math.maxInt(u32);
} else {
bun.http.max_http_headers_count = @intCast(num);
}
return jsc.JSValue.jsNumber(bun.http.max_http_headers_count);
}
pub fn setMaxHTTPHeadersCount(globalThis: *jsc.JSGlobalObject, callframe: *jsc.CallFrame) bun.JSError!jsc.JSValue {
const arguments = callframe.arguments_old(1).slice();
if (arguments.len < 1) {
return globalThis.throwNotEnoughArguments("setMaxHTTPHeadersCount", 1, arguments.len);
}
const value = arguments[0];
const num = try value.coerceToInt64(globalThis);
if (num < 0) {
return globalThis.throwInvalidArgumentTypeValue("maxHeadersCount", "non-negative integer", value);
}
if (num == 0) {
bun.http.max_http_headers_count = std.math.maxInt(u32);
} else if (num > std.math.maxInt(u32)) {
bun.http.max_http_headers_count = std.math.maxInt(u32);
} else {
bun.http.max_http_headers_count = `@intCast`(num);
}
return jsc.JSValue.jsNumber(bun.http.max_http_headers_count);
}
🤖 Prompt for AI Agents
In `@src/bun.js/node/node_http_binding.zig` around lines 49 - 65, The
setMaxHTTPHeadersCount function can panic when num exceeds u32 max; add an
upper-bound check after coercing num to ensure num <= std.math.maxInt(u32) and
return globalThis.throwInvalidArgumentTypeValue (or a similar JS error) if it’s
larger, otherwise safely assign bun.http.max_http_headers_count using `@intCast`;
reference the symbols setMaxHTTPHeadersCount, num, std.math.maxInt(u32),
`@intCast`, and bun.http.max_http_headers_count when implementing the validation
and error return.

Comment on lines +81 to +85
// Read server URL from stdout
const reader = proc.stdout.getReader();
const { value } = await reader.read();
reader.releaseLock();
const url = new TextDecoder().decode(value).trim();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Consider using a more robust approach to read the server URL.

Reading a single chunk from the stream may be fragile if the URL happens to be split across buffer boundaries. Consider using a line-based approach or reading until a newline is found.

♻️ Suggested improvement
-    // Read server URL from stdout
-    const reader = proc.stdout.getReader();
-    const { value } = await reader.read();
-    reader.releaseLock();
-    const url = new TextDecoder().decode(value).trim();
+    // Read server URL from stdout (read until newline)
+    let urlData = "";
+    const reader = proc.stdout.getReader();
+    const decoder = new TextDecoder();
+    while (!urlData.includes("\n")) {
+      const { value, done } = await reader.read();
+      if (done) break;
+      urlData += decoder.decode(value, { stream: true });
+    }
+    reader.releaseLock();
+    const url = urlData.trim();

Also applies to: 125-129

🤖 Prompt for AI Agents
In `@test/regression/issue/6982.test.ts` around lines 81 - 85, The current logic
reads a single chunk from proc.stdout.getReader() and decodes value into url,
which can break if the URL is split across chunks; change to a loop that
repeatedly reads from reader.read(), appends decoded chunks into a buffer, and
stops when a newline is encountered (or EOF), then trim to produce url; apply
the same fix to the second occurrence that also reads stdout (lines referenced
around the second block).

@alii alii closed this Jan 15, 2026
@alii
alii deleted the claude/add-max-http-header-count branch January 15, 2026 03:27
@alii
alii restored the claude/add-max-http-header-count branch January 15, 2026 03:27
@alii

alii commented Jan 15, 2026

Copy link
Copy Markdown
Member

Superseded by #26130

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Allow MAX_HEADERS to be configurable.

2 participants