mirror of
https://github.com/nodejs/node.git
synced 2026-10-28 10:15:07 +08:00
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:
1 parent
276fe2be45
commit
25c0c8e18a
42 files changed
+144
-44
No files matched your search
@@ -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
@@ -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);
|
||||
|
||||
|
||||
@@ -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') {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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');
|
||||
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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.');
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
});
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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');
|
||||
});
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in new issue
Block a user