From bc46704b07c17727218d7a99c65beb0559fe418b Mon Sep 17 00:00:00 2001 From: Kartik Puri Date: Wed, 3 Dec 2025 22:52:17 +0530 Subject: [PATCH 1/3] fix(res): throw error when res.redirect(undefined) is called --- lib/response.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/response.js b/lib/response.js index 7a2f0ecce56..54a8344b9ba 100644 --- a/lib/response.js +++ b/lib/response.js @@ -839,6 +839,10 @@ res.redirect = function redirect(url) { deprecate('Status must be a number'); } + if (!address || typeof address !== 'string') { + throw new TypeError('path argument is required to res.redirect'); + } + // Set location header address = this.location(address).get('Location'); From eb648f56f3b5a43f1e18a34fa8832599f6ed6758 Mon Sep 17 00:00:00 2001 From: Kartik Puri Date: Wed, 3 Dec 2025 23:38:15 +0530 Subject: [PATCH 2/3] test(res): improve redirect tests for res.redirect(undefined) (#6942) --- test/res.redirect.undefined.js | 64 ++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 test/res.redirect.undefined.js diff --git a/test/res.redirect.undefined.js b/test/res.redirect.undefined.js new file mode 100644 index 00000000000..da7b0f80af1 --- /dev/null +++ b/test/res.redirect.undefined.js @@ -0,0 +1,64 @@ +'use strict' + +var express = require('..') +var request = require('supertest') + +describe('res.redirect - Issue #6942', function () { + describe('when redirect argument is undefined', function () { + it('should throw a TypeError with correct message', function (done) { + var app = express() + + app.use(function (req, res) { + res.redirect(undefined) + }) + + app.use(function (err, req, res, next) { + res.status(500).json({ + error: err.message, + type: err.name, + stack: err.stack + }) + }) + + request(app) + .get('/') + .expect(500) + .expect(function (res) { + if (res.body.type !== 'TypeError') { + throw new Error('Expected TypeError, got ' + res.body.type) + } + if (res.body.error !== 'path argument is required to res.redirect') { + throw new Error( + 'Unexpected error message: ' + res.body.error + ) + } + if (!res.body.stack) { + throw new Error('Expected error stack to be present') + } + }) + .end(done) + }) + + it('should not send a Location header when redirect throws', function (done) { + var app = express() + + app.use(function (req, res) { + res.redirect(undefined) + }) + + app.use(function (err, req, res, next) { + res.status(500).send('error') + }) + + request(app) + .get('/') + .expect(500) + .expect(function (res) { + if ('location' in res.headers) { + throw new Error('Location header should not exist when redirect throws') + } + }) + .end(done) + }) + }) +}) From c3017cd53088252b2d6e88026b499fbc168fac2c Mon Sep 17 00:00:00 2001 From: Kartik Puri Date: Wed, 3 Dec 2025 23:47:09 +0530 Subject: [PATCH 3/3] test(res): remove invalid empty-string redirect case (#6942) --- test/res.redirect.undefined.js | 145 +++++++++++++++++++++++++++++---- 1 file changed, 131 insertions(+), 14 deletions(-) diff --git a/test/res.redirect.undefined.js b/test/res.redirect.undefined.js index da7b0f80af1..e16f1d683dd 100644 --- a/test/res.redirect.undefined.js +++ b/test/res.redirect.undefined.js @@ -3,22 +3,24 @@ var express = require('..') var request = require('supertest') -describe('res.redirect - Issue #6942', function () { - describe('when redirect argument is undefined', function () { - it('should throw a TypeError with correct message', function (done) { +describe('res.redirect - Issue #6941 / #6942', function () { + function jsonError(err, req, res, next) { + res.status(500).json({ + error: err.message, + type: err.name, + stack: Boolean(err.stack) + }) + } + + describe('when url is undefined', function () { + it('should throw a TypeError', function (done) { var app = express() app.use(function (req, res) { res.redirect(undefined) }) - app.use(function (err, req, res, next) { - res.status(500).json({ - error: err.message, - type: err.name, - stack: err.stack - }) - }) + app.use(jsonError) request(app) .get('/') @@ -28,9 +30,7 @@ describe('res.redirect - Issue #6942', function () { throw new Error('Expected TypeError, got ' + res.body.type) } if (res.body.error !== 'path argument is required to res.redirect') { - throw new Error( - 'Unexpected error message: ' + res.body.error - ) + throw new Error('Unexpected error message: ' + res.body.error) } if (!res.body.stack) { throw new Error('Expected error stack to be present') @@ -39,7 +39,7 @@ describe('res.redirect - Issue #6942', function () { .end(done) }) - it('should not send a Location header when redirect throws', function (done) { + it('should not send a Location header', function (done) { var app = express() app.use(function (req, res) { @@ -54,6 +54,7 @@ describe('res.redirect - Issue #6942', function () { .get('/') .expect(500) .expect(function (res) { + // stronger than checking "undefined" if ('location' in res.headers) { throw new Error('Location header should not exist when redirect throws') } @@ -61,4 +62,120 @@ describe('res.redirect - Issue #6942', function () { .end(done) }) }) + + describe('when url is not a string', function () { + it('should throw a TypeError for null', function (done) { + var app = express() + + app.use(function (req, res) { + res.redirect(null) + }) + + app.use(jsonError) + + request(app) + .get('/') + .expect(500) + .expect(function (res) { + if (res.body.type !== 'TypeError') { + throw new Error('Expected TypeError') + } + }) + .end(done) + }) + + it('should throw a TypeError for number (when single argument)', function (done) { + var app = express() + + app.use(function (req, res) { + res.redirect(123) + }) + + app.use(jsonError) + + request(app) + .get('/') + .expect(500) + .expect(function (res) { + if (res.body.type !== 'TypeError') { + throw new Error('Expected TypeError') + } + }) + .end(done) + }) + + it('should throw a TypeError for object', function (done) { + var app = express() + + app.use(function (req, res) { + res.redirect({ url: '/home' }) + }) + + app.use(jsonError) + + request(app) + .get('/') + .expect(500) + .expect(function (res) { + if (res.body.type !== 'TypeError') { + throw new Error('Expected TypeError') + } + }) + .end(done) + }) + }) + + describe('when status and url are provided', function () { + it('should throw a TypeError if url is undefined', function (done) { + var app = express() + + app.use(function (req, res) { + res.redirect(301, undefined) + }) + + app.use(jsonError) + + request(app) + .get('/') + .expect(500) + .expect(function (res) { + if (res.body.type !== 'TypeError') { + throw new Error('Expected TypeError') + } + if (res.body.error !== 'path argument is required to res.redirect') { + throw new Error('Unexpected error message: ' + res.body.error) + } + }) + .end(done) + }) + + it('should work correctly with valid status and url', function (done) { + var app = express() + + app.use(function (req, res) { + res.redirect(301, '/new-location') + }) + + request(app) + .get('/') + .expect('Location', '/new-location') + .expect(301, done) + }) + }) + + describe('valid redirects should still work', function () { + it('should redirect with a string url', function (done) { + var app = express() + + app.use(function (req, res) { + res.redirect('/home') + }) + + request(app) + .get('/') + .expect('Location', '/home') + .expect(302, done) + }) + }) }) +