Repository: nodejs/node
Pull request: http: fix rawHeaders exceeding maxHeadersCount limit

Fixes: https://github.com/nodejs/node/issues/61284

<!--
Before submitting a pull request, please read:

- the CONTRIBUTING guide at https://github.com/nodejs/node/blob/HEAD/CONTRIBUTING.md
- the commit message formatting guidelines at
  https://github.com/nodejs/node/blob/HEAD/doc/contributing/pull-requests.md#commit-message-guidelines

For code changes:
1. Include tests for any bug fixes or new features.
2. Update documentation if relevant.
3. Ensure that `make -j4 test` (UNIX), or `vcbuild test` (Windows) passes.

If you believe this PR should be highlighted in the Node.js CHANGELOG
please add the `notable-change` label.

Developer's Certificate of Origin 1.1

By making a contribution to this project, I certify that:

(a) The contribution was created in whole or in part by me and I
    have the right to submit it under the open source license
    indicated in the file; or

(b) The contribution is based upon previous work that, to the best
    of my knowledge, is covered under an appropriate open source
    license and I have the right under that license to submit that
    work with modifications, whether created in whole or in part
    by me, under the same open source license (unless I am
    permitted to submit under a different license), as indicated
    in the file; or

(c) The contribution was provided directly to me by some other
    person who certified (a), (b) or (c) and I have not modified
    it.

(d) I understand and agree that this project and the contribution
    are public and that a record of the contribution (including all
    personal information I submit with it, including my sign-off) is
    maintained indefinitely and may be redistributed consistent with
    this project or the open source license(s) involved.
-->


Changed files:
filename: lib/_http_common.js
patch: @@ -59,9 +59,11 @@ const MAX_HEADER_PAIRS = 2000;
 // called to process trailing HTTP headers.
 function parserOnHeaders(headers, url) {
   // Once we exceeded headers limit - stop collecting them
-  if (this.maxHeaderPairs <= 0 ||
-      this._headers.length < this.maxHeaderPairs) {
+  const capacity = this.maxHeaderPairs - this._headers.length;
+  if (this.maxHeaderPairs <= 0 || capacity >= headers.length) {
     this._headers.push(...headers);
+  } else if (capacity > 0) {
+    this._headers.push(...headers.slice(0, capacity));
   }
   this._url += url;
 }

filename: test/parallel/test-http-rawheaders-limit.js
patch: @@ -0,0 +1,26 @@
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const http = require('http');
+const net = require('net');
+
+const server = http.createServer(common.mustCall((req, res) => {
+  const limit = server.maxHeadersCount * 2;
+  assert.ok(req.rawHeaders.length <= limit,
+            `rawHeaders.length (${req.rawHeaders.length}) exceeds limit (${limit})`);
+  res.end();
+  server.close();
+}));
+
+server.maxHeadersCount = 50;
+
+server.listen(0, common.mustCall(() => {
+  const port = server.address().port;
+  const headers = Array.from({ length: 65 }, (_, i) => `X-${i}:v`).join('\r\n');
+  const req = `GET / HTTP/1.1\r\nHost: localhost\r\n${headers}\r\n\r\n`;
+
+  net.createConnection(port, 'localhost', function() {
+    this.write(req);
+    this.once('data', () => this.end());
+  });
+}));