http: runtime deprecate instantiating without new

Promote DEP0195 from documentation-only to a runtime deprecation.
Calling node:http constructors without `new` now emits DEP0195 via
deprecateInstantiation. This covers Agent, Server, OutgoingMessage,
IncomingMessage, ServerResponse, and ClientRequest.

Update in-tree tests that called Server/Agent without `new` to use
the keyword, and add a dedicated DEP0195 coverage test.

Refs: https://github.com/nodejs/node/pull/58518
Assisted-by: Grok
Signed-off-by: Yagiz Nizipli <yagiz@nizipli.com>
PR-URL: https://github.com/nodejs/node/pull/64853
Reviewed-By: Aviv Keller <me@aviv.sh>
Reviewed-By: Tim Perry <pimterry@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
This commit is contained in:
Yagiz Nizipli authored and GitHub committed 2026-08-01 21:42:59 +00:00
1 parent 276fe2be45
commit 25c0c8e18a
42 files changed
+144 -44

No files matched your search

+5 -2
View File
@@ -4341,6 +4341,9 @@ npx codemod@latest @nodejs/http2-priority-signaling
<!-- YAML
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/64853
description: Runtime deprecation.
- version:
- v24.2.0
- v22.17.0
@@ -4348,11 +4351,11 @@ changes:
description: Documentation-only deprecation.
-->
Type: Documentation-only
Type: Runtime
Instantiating classes without the `new` qualifier exported by the `node:http` module is deprecated.
It is recommended to use the `new` qualifier instead. This applies to all http classes, such as
`OutgoingMessage`, `IncomingMessage`, `ServerResponse` and `ClientRequest`.
`OutgoingMessage`, `IncomingMessage`, `ServerResponse`, `ClientRequest`, `Server`, and `Agent`.
An automated migration is available ([source](https://github.com/nodejs/userland-migrations/tree/main/recipes/http-classes-with-new)):
+4 -2
View File
@@ -48,6 +48,7 @@ const {
owner_symbol,
} = require('internal/async_hooks').symbols;
const {
deprecateInstantiation,
getLazy,
kEmptyObject,
once,
@@ -151,8 +152,9 @@ function removeFreeSocketDataGuard(socket) {
}
function Agent(options) {
if (!(this instanceof Agent))
return new Agent(options);
if (!(this instanceof Agent)) {
return deprecateInstantiation(Agent, 'DEP0195', options);
}
EventEmitter.call(this);
+5
View File
@@ -38,6 +38,7 @@ const {
const net = require('net');
const assert = require('internal/assert');
const {
deprecateInstantiation,
kEmptyObject,
once,
} = require('internal/util');
@@ -329,6 +330,10 @@ function rewriteForProxiedHttp(req, reqOptions, proxyAuthority, userHostHeader,
};
function ClientRequest(input, options, cb) {
if (!(this instanceof ClientRequest)) {
return deprecateInstantiation(ClientRequest, 'DEP0195', input, options, cb);
}
OutgoingMessage.call(this);
if (typeof input === 'string') {
+7
View File
@@ -28,6 +28,9 @@ const {
} = primordials;
const { Readable, finished } = require('stream');
const {
deprecateInstantiation,
} = require('internal/util');
const { AbortController } = require('internal/abort_controller');
@@ -56,6 +59,10 @@ function readStop(socket) {
/* Abstract base class for ServerRequest and ClientResponse. */
function IncomingMessage(socket) {
if (!(this instanceof IncomingMessage)) {
return deprecateInstantiation(IncomingMessage, 'DEP0195', socket);
}
let streamOptions;
if (socket) {
+8 -1
View File
@@ -71,7 +71,10 @@ const {
hideStackFrames,
} = require('internal/errors');
const { validateString } = require('internal/validators');
const { assignFunctionName } = require('internal/util');
const {
assignFunctionName,
deprecateInstantiation,
} = require('internal/util');
const { isUint8Array } = require('internal/util/types');
let debug = require('internal/util/debuglog').debuglog('http', (fn) => {
@@ -104,6 +107,10 @@ function isContentDispositionField(s) {
}
function OutgoingMessage(options) {
if (!(this instanceof OutgoingMessage)) {
return deprecateInstantiation(OutgoingMessage, 'DEP0195', options);
}
Stream.call(this);
// Queue that holds all currently pending data, until the response will be
+8 -1
View File
@@ -89,6 +89,7 @@ const {
} = require('internal/errors');
const {
assignFunctionName,
deprecateInstantiation,
kEmptyObject,
promisify,
} = require('internal/util');
@@ -205,6 +206,10 @@ class HTTPServerAsyncResource {
}
function ServerResponse(req, options) {
if (!(this instanceof ServerResponse)) {
return deprecateInstantiation(ServerResponse, 'DEP0195', req, options);
}
OutgoingMessage.call(this, options);
if (req.method === 'HEAD') this._hasBody = false;
@@ -630,7 +635,9 @@ function httpServerPreClose(server) {
}
function Server(options, requestListener) {
if (!(this instanceof Server)) return new Server(options, requestListener);
if (!(this instanceof Server)) {
return deprecateInstantiation(Server, 'DEP0195', options, requestListener);
}
if (typeof options === 'function') {
requestListener = options;
+2 -1
View File
@@ -50,7 +50,8 @@ function forEach(obj, fn) {
if (cluster.isWorker) {
require('http').Server(common.mustNotCall()).listen(0, '127.0.0.1');
const http = require('http');
new http.Server(common.mustNotCall()).listen(0, '127.0.0.1');
} else if (cluster.isPrimary) {
const checks = {
+1 -1
View File
@@ -29,7 +29,7 @@ const totalWorkers = 2;
// Cluster setup
if (cluster.isWorker) {
const http = require('http');
http.Server(() => {}).listen(0, '127.0.0.1');
new http.Server(() => {}).listen(0, '127.0.0.1');
} else if (process.argv[2] === 'cluster') {
// Send PID to testcase process
let forkNum = 0;
+1 -1
View File
@@ -28,7 +28,7 @@ if (cluster.isWorker) {
// Keep the worker alive
const http = require('http');
http.Server().listen(0, '127.0.0.1');
new http.Server().listen(0, '127.0.0.1');
} else if (process.argv[2] === 'cluster') {
@@ -32,7 +32,7 @@ if (cluster.isWorker) {
d.run(() => {});
const http = require('http');
http.Server(() => {}).listen(0, '127.0.0.1');
new http.Server(() => {}).listen(0, '127.0.0.1');
} else if (cluster.isPrimary) {
@@ -26,7 +26,7 @@ const cluster = require('cluster');
if (cluster.isWorker) {
const http = require('http');
http.Server(() => {
new http.Server(() => {
}).listen(0, '127.0.0.1');
+1 -1
View File
@@ -35,7 +35,7 @@ const EXIT_CODE = 42;
if (cluster.isWorker) {
const http = require('http');
const server = http.Server(() => { });
const server = new http.Server(() => { });
server.once('listening', common.mustCall(() => {
process.exit(EXIT_CODE);
@@ -11,7 +11,7 @@ const cluster = require('cluster');
if (cluster.isWorker) {
// Make the worker run something
const http = require('http');
const server = http.Server(() => { });
const server = new http.Server(() => { });
server.once('listening', common.mustCall());
server.listen(0, '127.0.0.1');
+1 -1
View File
@@ -33,7 +33,7 @@ const cluster = require('cluster');
if (cluster.isWorker) {
const http = require('http');
const server = http.Server(() => { });
const server = new http.Server(() => { });
server.once('listening', common.mustCall());
server.listen(0, '127.0.0.1');
+1 -1
View File
@@ -24,7 +24,7 @@ const common = require('../common');
const http = require('http');
let serverRes;
const server = http.Server(common.mustCall((req, res) => {
const server = new http.Server(common.mustCall((req, res) => {
serverRes = res;
res.writeHead(200);
res.write('Part of my res.');
+1 -1
View File
@@ -27,7 +27,7 @@ const http = require('http');
const N = 4;
const M = 4;
const server = http.Server(common.mustCall(function(req, res) {
const server = new http.Server(common.mustCall(function(req, res) {
res.writeHead(200);
res.end('hello world\n');
}, (N * M))); // N * M = good requests (the errors will not be counted)
+1 -1
View File
@@ -32,7 +32,7 @@ for (let i = 0; i < buffer.length; i++) {
buffer[i] = i % 256;
}
const server = http.Server(common.mustCallAtLeast(function(req, res) {
const server = new http.Server(common.mustCallAtLeast(function(req, res) {
server.close();
let i = 0;
+1 -1
View File
@@ -28,7 +28,7 @@ const N = 8;
const countdown = new Countdown(N, () => server.close());
const server = http.Server(common.mustCall((req, res) => {
const server = new http.Server(common.mustCall((req, res) => {
res.writeHead(200);
res.write('Working on it...');
req.on('aborted', common.mustCall(() => countdown.dec()));
@@ -4,7 +4,7 @@ const http = require('http');
{
let serverRes;
const server = http.Server(function(req, res) {
const server = new http.Server(function(req, res) {
res.write('Part of my res.');
serverRes = res;
});
@@ -27,7 +27,7 @@ const http = require('http');
{
// Don't crash of no 'error' handler.
let serverRes;
const server = http.Server(function(req, res) {
const server = new http.Server(function(req, res) {
res.write('Part of my res.');
serverRes = res;
});
+1 -1
View File
@@ -29,7 +29,7 @@ let name;
const max = 3;
const agent = new http.Agent();
const server = http.Server(common.mustCall((req, res) => {
const server = new http.Server(common.mustCall((req, res) => {
if (req.url === '/0') {
setTimeout(common.mustCall(() => {
res.writeHead(200);
@@ -3,7 +3,7 @@ const common = require('../common');
const assert = require('assert');
const http = require('http');
const server = http.Server(common.mustCall((req, res) => {
const server = new http.Server(common.mustCall((req, res) => {
res.writeHead(200);
res.end('Hello, World!');
}));
@@ -9,7 +9,7 @@ const Countdown = require('../common/countdown');
const N = 2;
let abortRequest = true;
const server = http.Server(common.mustCall((req, res) => {
const server = new http.Server(common.mustCall((req, res) => {
const headers = { 'Content-Type': 'text/plain', 'Connection': 'close' };
headers['Content-Length'] = 50;
const socket = res.socket;
+1 -1
View File
@@ -27,7 +27,7 @@ const http = require('http');
const expected = 'This is a unicode text: سلام';
let result = '';
const server = http.Server((req, res) => {
const server = new http.Server((req, res) => {
req.setEncoding('utf8');
req.on('data', (chunk) => {
result += chunk;
+68
View File
@@ -0,0 +1,68 @@
'use strict';
const common = require('../common');
const assert = require('assert');
const http = require('http');
// DEP0195: Instantiating node:http classes without `new` is runtime-deprecated.
// Deprecation codes warn once per process, so only the first call emits a warning.
common.expectWarning(
'DeprecationWarning',
"Instantiating Agent without the 'new' keyword has been deprecated.",
'DEP0195',
);
{
const agent = http.Agent();
assert.ok(agent instanceof http.Agent);
agent.destroy();
}
// Remaining classes still construct without `new` (same deprecation code; no
// additional warnings are emitted).
{
const server = http.Server();
assert.ok(server instanceof http.Server);
server.close();
}
{
const msg = http.OutgoingMessage();
assert.ok(msg instanceof http.OutgoingMessage);
}
{
const msg = http.IncomingMessage();
assert.ok(msg instanceof http.IncomingMessage);
}
{
const req = new http.IncomingMessage();
const res = http.ServerResponse(req);
assert.ok(res instanceof http.ServerResponse);
}
{
// ClientRequest begins a real request; provide a fake socket so nothing is
// dialed on the network.
const { Socket } = require('net');
const agent = new http.Agent();
agent.createConnection = common.mustCall((options, cb) => {
const socket = new Socket();
// Never connect; destroy immediately after construction completes.
process.nextTick(() => {
socket.destroy();
if (typeof cb === 'function') cb(new Error('stop'));
});
return socket;
});
const req = http.ClientRequest({
host: '127.0.0.1',
port: 1,
agent,
});
assert.ok(req instanceof http.ClientRequest);
req.on('error', common.mustCall());
req.destroy();
}
@@ -45,7 +45,7 @@ const responseCountdown = new Countdown(total, common.mustCall(() => {
server.close();
}));
const server = http.Server(function(req, res) {
const server = new http.Server(function(req, res) {
setTimeout(function() {
res.writeHead(200, {
'content-type': 'image/jpeg',
+1 -1
View File
@@ -41,7 +41,7 @@ server.listen(0, function() {
makeRequest(expectRequests);
});
const agent = http.Agent({ keepAlive: true });
const agent = new http.Agent({ keepAlive: true });
let clientSocket = null;
+1 -1
View File
@@ -10,7 +10,7 @@ for (const method of ['abort', 'destroy']) {
res.end(req.url);
}));
server.listen(0, common.mustCall(() => {
const agent = http.Agent({ keepAlive: true });
const agent = new http.Agent({ keepAlive: true });
const req = http
.request({
@@ -7,7 +7,7 @@ const http = require('http');
const server = http.createServer((req, res) => {
res.end('ok');
}).listen(0, common.mustCall(() => {
const agent = http.Agent({
const agent = new http.Agent({
keepAlive: true,
maxSockets: 5,
maxFreeSockets: 2
+1 -1
View File
@@ -41,7 +41,7 @@ server.listen(0, function() {
makeRequest(expectRequests);
});
const agent = http.Agent({ keepAlive: true });
const agent = new http.Agent({ keepAlive: true });
let clientSocket = null;
@@ -24,7 +24,7 @@ const common = require('../common');
const http = require('http');
const assert = require('assert');
const server = http.Server(function(req, res) {
const server = new http.Server(function(req, res) {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Hello World\n');
server.close();
+1 -1
View File
@@ -21,7 +21,7 @@ const makeRequest = common.mustCall((options) => {
});
}, 2);
const server = http.Server(common.mustCall((req, res) => {
const server = new http.Server(common.mustCall((req, res) => {
let result = '';
req.setEncoding('utf8');
+3 -3
View File
@@ -7,7 +7,7 @@ const assert = require('assert');
// When the response is ended immediately, `req` should emit `close`
// after `res`
{
const server = http.Server(common.mustCall((req, res) => {
const server = new http.Server(common.mustCall((req, res) => {
let resClosed = false;
let reqClosed = false;
@@ -47,7 +47,7 @@ const assert = require('assert');
// When there's no `data` handler attached to `req`,
// `req` should emit `close` after `res`.
{
const server = http.Server(common.mustCall((req, res) => {
const server = new http.Server(common.mustCall((req, res) => {
let resClosed = false;
let reqClosed = false;
@@ -91,7 +91,7 @@ const assert = require('assert');
// https://github.com/nodejs/node/pull/33035 introduced this change in behavior.
// See https://github.com/nodejs/node/pull/33035#issuecomment-751482764
{
const server = http.Server(common.mustCall((req, res) => {
const server = new http.Server(common.mustCall((req, res) => {
let resClosed = false;
let reqClosed = false;
+1 -1
View File
@@ -24,7 +24,7 @@ const common = require('../common');
const assert = require('assert');
const http = require('http');
const server = http.Server(function(req, res) {
const server = new http.Server(function(req, res) {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('hello world\n');
});
+1 -1
View File
@@ -27,7 +27,7 @@ const http = require('http');
const expected = 'Post Body For Test';
const expectedStatusCode = 200;
const server = http.Server(common.mustCallAtLeast(function(req, res) {
const server = new http.Server(common.mustCallAtLeast(function(req, res) {
let result = '';
req.setEncoding('utf8');
@@ -24,7 +24,7 @@ const common = require('../common');
const assert = require('assert');
const http = require('http');
const server = http.Server(common.mustCall(function(req, res) {
const server = new http.Server(common.mustCall(function(req, res) {
res.on('error', common.expectsError({
code: 'ERR_STREAM_WRITE_AFTER_END',
name: 'Error'
@@ -17,7 +17,7 @@ function test(res, header, code) {
});
}
const server = http.Server(common.mustCall(function(req, res) {
const server = new http.Server(common.mustCall(function(req, res) {
switch (reqNum) {
case 0:
test(res, -1, '-1');
@@ -16,7 +16,7 @@ class MyServerResponse extends http.ServerResponse {
}
}
const server = http.Server({
const server = new http.Server({
ServerResponse: MyServerResponse
}, common.mustCall(function(req, res) {
res.status(200);
+1 -1
View File
@@ -27,7 +27,7 @@ const url = require('url');
const expectedRequests = ['/hello', '/there', '/world'];
const server = http.Server(common.mustCall((req, res) => {
const server = new http.Server(common.mustCall((req, res) => {
assert.strictEqual(expectedRequests.shift(), req.url);
switch (req.url) {
+1 -1
View File
@@ -578,7 +578,7 @@ tmpdir.refresh();
}
{
const server = http.Server(function(req, res) {
const server = new http.Server(function(req, res) {
res.write('asd');
});
server.listen(0, common.mustCall(function() {
@@ -29,7 +29,7 @@ let responses = 0;
let requests = 0;
let connection;
const server = http.Server(common.mustCall((req, res) => {
const server = new http.Server(common.mustCall((req, res) => {
requests++;
assert.strictEqual(req.connection, connection);
res.writeHead(200);
@@ -34,7 +34,7 @@ const server = http.createServer(function(req, res) {
res.end(req.url);
});
server.listen(0, common.mustCall(() => {
const agent = http.Agent({
const agent = new http.Agent({
keepAlive: true,
maxSockets: 5,
maxFreeSockets: 2,
+1 -1
View File
@@ -41,7 +41,7 @@ for (let i = 0; i < buffer.length; i++) {
}
const web = http.Server(common.mustCall((req, res) => {
const web = new http.Server(common.mustCall((req, res) => {
web.close();
const socket = net.Stream();