diff --git a/doc/api/deprecations.md b/doc/api/deprecations.md index 18574f5e0a6227..b41ec032904f4f 100644 --- a/doc/api/deprecations.md +++ b/doc/api/deprecations.md @@ -1347,6 +1347,7 @@ The `http` module `OutgoingMessage.prototype._headers` and the public methods (e.g. `OutgoingMessage.prototype.getHeader()`, `OutgoingMessage.prototype.getHeaders()`, `OutgoingMessage.prototype.getHeaderNames()`, +`OutgoingMessage.prototype.getRawHeaderNames()`, `OutgoingMessage.prototype.hasHeader()`, `OutgoingMessage.prototype.removeHeader()`, `OutgoingMessage.prototype.setHeader()`) for working with outgoing headers. diff --git a/doc/api/http.md b/doc/api/http.md index 791b607f6b8388..505a8827755ad6 100644 --- a/doc/api/http.md +++ b/doc/api/http.md @@ -777,6 +777,24 @@ const cookie = request.getHeader('Cookie'); // 'cookie' is of type string[] ``` +### `request.getRawHeaderNames()` + + +* Returns: {string[]} + +Returns an array containing the unique names of the current outgoing raw +headers. Header names are returned with their exact casing being set. + +```js +request.setHeader('Foo', 'bar'); +request.setHeader('Set-Cookie', ['foo=bar', 'bar=baz']); + +const headerNames = request.getRawHeaderNames(); +// headerNames === ['Foo', 'Set-Cookie'] +``` + ### `request.maxHeadersCount` * {number} **Default:** `2000` diff --git a/lib/_http_outgoing.js b/lib/_http_outgoing.js index 59ef07e33e5aa4..78e6fdd15e9a68 100644 --- a/lib/_http_outgoing.js +++ b/lib/_http_outgoing.js @@ -22,6 +22,7 @@ 'use strict'; const { + Array, ArrayIsArray, ArrayPrototypeForEach, ArrayPrototypeJoin, @@ -36,6 +37,7 @@ const { ObjectCreate, ObjectDefineProperty, ObjectKeys, + ObjectValues, ObjectPrototypeHasOwnProperty, ObjectSetPrototypeOf, RegExpPrototypeTest, @@ -656,6 +658,23 @@ OutgoingMessage.prototype.getHeaderNames = function getHeaderNames() { }; +// Returns an array of the names of the current outgoing raw headers. +OutgoingMessage.prototype.getRawHeaderNames = function getRawHeaderNames() { + const headersMap = this[kOutHeaders]; + if (headersMap === null) return []; + + const values = ObjectValues(headersMap); + const headers = Array(values.length); + // 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]; + } + + return headers; +}; + + // Returns a shallow copy of the current outgoing headers. OutgoingMessage.prototype.getHeaders = function getHeaders() { const headers = this[kOutHeaders]; diff --git a/test/parallel/test-http-mutable-headers.js b/test/parallel/test-http-mutable-headers.js index c9f63acf4433f4..755a4dd66159e8 100644 --- a/test/parallel/test-http-mutable-headers.js +++ b/test/parallel/test-http-mutable-headers.js @@ -108,6 +108,10 @@ const s = http.createServer(common.mustCall((req, res) => { ['x-test-header', 'x-test-header2', 'set-cookie', 'x-test-array-header']); + assert.deepStrictEqual(res.getRawHeaderNames(), + ['x-test-header', 'X-TEST-HEADER2', + 'set-cookie', 'x-test-array-header']); + assert.strictEqual(res.hasHeader('x-test-header2'), true); assert.strictEqual(res.hasHeader('X-TEST-HEADER2'), true); assert.strictEqual(res.hasHeader('X-Test-Header2'), true); @@ -171,7 +175,10 @@ function nextTest() { let bufferedResponse = ''; - http.get({ port: s.address().port }, common.mustCall((response) => { + const req = http.get({ + port: s.address().port, + headers: { 'X-foo': 'bar' } + }, common.mustCall((response) => { switch (test) { case 'headers': assert.strictEqual(response.statusCode, 201); @@ -214,4 +221,10 @@ function nextTest() { common.mustCall(nextTest)(); })); })); + + assert.deepStrictEqual(req.getHeaderNames(), + ['x-foo', 'host']); + + assert.deepStrictEqual(req.getRawHeaderNames(), + ['X-foo', 'Host']); }