http: add setDefaultHeaders option to http.request

This makes it possible to disable the various default headers directly
from the constructor. While this is possible for many use cases by
manually calling removeHeader on the request object instead, when
passing a raw header array to the request constructor the headers are
serialized and prepared to send immediately, and removeHeader cannot
subsequently be used.

With this change, it's now possible to 100% control sent request
headers by passing 'setDefaultHeaders: false' and a raw headers array to
http.request.

PR-URL: https://github.com/nodejs/node/pull/56112
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Yongsheng Zhang <zyszys98@gmail.com>
Reviewed-By: Marco Ippolito <marcoippolito54@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
Tim Perry 2024-12-12 16:43:10 +00:00 committed by GitHub
parent 131c33efa5
commit 7a40aa75a5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 100 additions and 2 deletions

View File

@ -3848,8 +3848,13 @@ changes:
* `port` {number} Port of remote server. **Default:** `defaultPort` if set,
else `80`.
* `protocol` {string} Protocol to use. **Default:** `'http:'`.
* `setDefaultHeaders` {boolean}: Specifies whether or not to automatically add
default headers such as `Connection`, `Content-Length`, `Transfer-Encoding`,
and `Host`. If set to `false` then all necessary headers must be added
manually. Defaults to `true`.
* `setHost` {boolean}: Specifies whether or not to automatically add the
`Host` header. Defaults to `true`.
`Host` header. If provided, this overrides `setDefaultHeaders`. Defaults to
`true`.
* `signal` {AbortSignal}: An AbortSignal that may be used to abort an ongoing
request.
* `socketPath` {string} Unix domain socket. Cannot be used if one of `host`

View File

@ -199,7 +199,13 @@ function ClientRequest(input, options, cb) {
const host = optsWithoutSignal.host = validateHost(options.hostname, 'hostname') ||
validateHost(options.host, 'host') || 'localhost';
const setHost = (options.setHost === undefined || Boolean(options.setHost));
const setHost = options.setHost !== undefined ?
Boolean(options.setHost) :
options.setDefaultHeaders !== false;
this._removedConnection = options.setDefaultHeaders === false;
this._removedContLen = options.setDefaultHeaders === false;
this._removedTE = options.setDefaultHeaders === false;
this.socketPath = options.socketPath;

View File

@ -0,0 +1,33 @@
'use strict';
const common = require('../common');
const assert = require('assert');
const http = require('http');
const server = http.createServer(common.mustCall(function(req, res) {
assert.deepStrictEqual(req.rawHeaders, [
'test', 'value',
'HOST', `127.0.0.1:${server.address().port}`,
'foo', 'bar',
'foo', 'baz',
'connection', 'close',
]);
res.end('ok');
server.close();
}));
server.listen(0, common.localhostIPv4, function() {
const req = http.request({
method: 'POST',
host: common.localhostIPv4,
port: this.address().port,
setDefaultHeaders: false,
});
req.setHeader('test', 'value');
req.setHeader('HOST', `${common.localhostIPv4}:${server.address().port}`);
req.setHeader('foo', ['bar', 'baz']);
req.setHeader('connection', 'close');
req.end();
});

View File

@ -0,0 +1,23 @@
'use strict';
const common = require('../common');
const assert = require('assert');
const http = require('http');
const server = http.createServer(common.mustCall(function(req, res) {
assert.deepStrictEqual(req.rawHeaders, [
'Host', `${common.localhostIPv4}:${server.address().port}`,
]);
res.end('ok');
server.close();
}));
server.listen(0, common.localhostIPv4, function() {
http.request({
method: 'POST',
host: common.localhostIPv4,
port: this.address().port,
setDefaultHeaders: false,
setHost: true
}).end();
});

View File

@ -0,0 +1,31 @@
'use strict';
const common = require('../common');
const assert = require('assert');
const http = require('http');
const server = http.createServer(common.mustCall(function(req, res) {
assert.deepStrictEqual(req.rawHeaders, [
'host', `${common.localhostIPv4}:${server.address().port}`,
'foo', 'bar',
'test', 'value',
'foo', 'baz',
]);
res.end('ok');
server.close();
}));
server.listen(0, common.localhostIPv4, function() {
http.request({
method: 'POST',
host: common.localhostIPv4,
port: this.address().port,
setDefaultHeaders: false,
headers: [
'host', `${common.localhostIPv4}:${server.address().port}`,
'foo', 'bar',
'test', 'value',
'foo', 'baz',
]
}).end();
});