http: reduce raw header name allocations

Reuse the values array instead of allocating a second result array.

Signed-off-by: Roberto Bianchi <roberto.bianchi@spendesk.com>
PR-URL: https://github.com/nodejs/node/pull/66488
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
Reviewed-By: Tim Perry <pimterry@gmail.com>
This commit is contained in:
Roberto Bianchi authored and GitHub committed 2026-10-12 09:13:52 +00:00
1 parent 712f7a83f5
commit e2bc15692e
3 files changed
+79 -5

No files matched your search

+33
View File
@@ -0,0 +1,33 @@
'use strict';
const common = require('../common.js');
const assert = require('node:assert');
const { OutgoingMessage } = require('node:http');
const bench = common.createBenchmark(main, {
n: [1e6],
headers: [0, 1, 4, 16, 64],
});
function main({ n, headers }) {
const message = new OutgoingMessage();
const expected = [];
for (let index = 0; index < headers; index++) {
const name = `X-Header-${index}`;
message.setHeader(name, 'value');
expected.push(name);
}
for (let index = 0; index < 1e4; index++) {
message.getRawHeaderNames();
}
let result;
bench.start();
for (let index = 0; index < n; index++) {
result = message.getRawHeaderNames();
}
bench.end(n);
assert.deepStrictEqual(result, expected);
}
+3 -5
View File
@@ -22,7 +22,6 @@
'use strict';
const {
Array,
ArrayIsArray,
MathFloor,
ObjectDefineProperty,
@@ -935,12 +934,11 @@ OutgoingMessage.prototype.getRawHeaderNames = function getRawHeaderNames() {
const headersMap = this[kOutHeaders];
if (headersMap === null) return [];
const values = ObjectValues(headersMap);
const headers = Array(values.length);
const headers = ObjectValues(headersMap);
// Retain for(;;) loop for performance reasons
// Refs: https://github.com/nodejs/node/pull/30958
for (let i = 0, l = values.length; i < l; i++) {
headers[i] = values[i][0];
for (let i = 0; i < headers.length; i++) {
headers[i] = headers[i][0];
}
return headers;
@@ -0,0 +1,43 @@
'use strict';
require('../common');
const assert = require('node:assert');
const { OutgoingMessage } = require('node:http');
const message = new OutgoingMessage();
assert.deepStrictEqual(message.getRawHeaderNames(), []);
assert.notStrictEqual(message.getRawHeaderNames(), message.getRawHeaderNames());
message.setHeader('X-First', 'first');
message.setHeader('10', 'ten');
message.setHeader('2', 'two');
message.setHeader('__proto__', 'proto');
message.setHeader('Constructor', 'constructor');
message.setHeader('X-Last', 'last');
const expected = ['2', '10', 'X-First', '__proto__', 'Constructor', 'X-Last'];
const names = message.getRawHeaderNames();
assert.deepStrictEqual(names, expected);
names[0] = 'changed';
names.push('extra');
assert.deepStrictEqual(message.getRawHeaderNames(), expected);
assert.strictEqual(message.getHeader('2'), 'two');
message.setHeader('x-FIRST', 'updated');
expected[2] = 'x-FIRST';
assert.deepStrictEqual(message.getRawHeaderNames(), expected);
message.removeHeader('X-FIRST');
message.setHeader('X-First', 'reinserted');
assert.deepStrictEqual(message.getRawHeaderNames(), [
'2', '10', '__proto__', 'Constructor', 'X-Last', 'X-First',
]);
for (const name of message.getHeaderNames()) {
message.removeHeader(name);
}
assert.deepStrictEqual(message.getRawHeaderNames(), []);
assert.notStrictEqual(message.getRawHeaderNames(), message.getRawHeaderNames());
message.setHeader('X-New', 'new');
assert.deepStrictEqual(message.getRawHeaderNames(), ['X-New']);