From 00f71d81bb85126c80a6e53302690fb32941ba2e Mon Sep 17 00:00:00 2001 From: IshitaSingh0822 Date: Mon, 16 Feb 2026 19:19:21 +0530 Subject: [PATCH 1/4] =?UTF-8?q?Ishita=F0=9F=8D=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/res.type.js | 68 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/test/res.type.js b/test/res.type.js index 09285af3914..2337c4e0ab6 100644 --- a/test/res.type.js +++ b/test/res.type.js @@ -42,5 +42,73 @@ describe('res', function(){ .get('/') .expect('Content-Type', 'application/vnd.amazon.ebook', done); }) + describe('edge cases', function(){ + it('should handle empty string gracefully', function(done){ + var app = express(); + + app.use(function(req, res){ + res.type('').end('test'); + }); + + request(app) + .get('/') + .expect('Content-Type', 'application/octet-stream') + .end(done); + }) + + it('should handle file extension with dots', function(done){ + var app = express(); + + app.use(function(req, res){ + res.type('.json').end('{"test": true}'); + }); + + request(app) + .get('/') + .expect('Content-Type', 'application/json; charset=utf-8') + .end(done); + }) + + it('should handle multiple file extensions', function(done){ + var app = express(); + + app.use(function(req, res){ + res.type('file.tar.gz').end('compressed'); + }); + + request(app) + .get('/') + .expect('Content-Type', 'application/gzip') + .end(done); + }) + + it('should handle uppercase extensions', function(done){ + var app = express(); + + app.use(function(req, res){ + res.type('FILE.JSON').end('{"test": true}'); + }); + + request(app) + .get('/') + .expect('Content-Type', 'application/json; charset=utf-8') + .end(done); + }) + + it('should handle extension with special characters', function(done){ + var app = express(); + + app.use(function(req, res){ + res.type('file@test.json').end('{"test": true}'); + }); + + request(app) + .get('/') + .expect('Content-Type', 'application/json; charset=utf-8') + .end(done); + }) + }) }) }) + + From f3b22bc59fe616c7cdc4e7071da4ef60d94b30d1 Mon Sep 17 00:00:00 2001 From: IshitaSingh0822 Date: Thu, 19 Feb 2026 16:05:32 +0530 Subject: [PATCH 2/4] test: add blank line for better code flow - Add extra spacing before edge cases describe block - Address maintainer feedback --- test/res.type.js | 1 + 1 file changed, 1 insertion(+) diff --git a/test/res.type.js b/test/res.type.js index 2337c4e0ab6..e438956313a 100644 --- a/test/res.type.js +++ b/test/res.type.js @@ -42,6 +42,7 @@ describe('res', function(){ .get('/') .expect('Content-Type', 'application/vnd.amazon.ebook', done); }) + describe('edge cases', function(){ it('should handle empty string gracefully', function(done){ var app = express(); From 0cf4efb236854026ea24fcc8e60ff3cab97641d8 Mon Sep 17 00:00:00 2001 From: IshitaSingh0822 Date: Sun, 19 Apr 2026 23:09:02 +0530 Subject: [PATCH 3/4] fix: req.query returns object instead of array for >20 repeated values --- lib/utils.js | 7 +++++- test/req.query.js | 60 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 1 deletion(-) diff --git a/lib/utils.js b/lib/utils.js index 4f21e7ef1e3..6cd7e7d58d3 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -266,6 +266,11 @@ function createETagGenerator (options) { function parseExtendedQueryString(str) { return qs.parse(str, { - allowPrototypes: true + allowPrototypes: true, + // fix(#7147): qs defaults arrayLimit to 20, causing arrays with more than + // 20 items to be returned as a plain object with numeric string keys instead + // of an array. Setting Infinity removes that cap while the existing + // parameterLimit (default: 1000) already bounds total query string size. + arrayLimit: Infinity }); } diff --git a/test/req.query.js b/test/req.query.js index c0d3c8376e9..19a2df117e3 100644 --- a/test/req.query.js +++ b/test/req.query.js @@ -104,3 +104,63 @@ function createApp(setting) { return app; } + +// regression test for issue #7147 +// req.query was returning a plain object (not an array) when a repeated +// query param had more than 20 values — caused by qs defaulting arrayLimit to 20 +describe('regression: issue #7147 — arrays with more than 20 values', function () { + it('should parse 21 repeated query params as an array, not an object', function (done) { + var app = createApp('extended'); + + // Build ?ids=0&ids=1&...&ids=20 (21 values) + var query = Array.from({ length: 21 }, function (_, i) { return 'ids=' + i; }).join('&'); + + request(app) + .get('/?' + query) + .expect(200) + .end(function (err, res) { + if (err) return done(err); + var parsed = JSON.parse(res.text); + assert.ok(Array.isArray(parsed.ids), + 'req.query.ids should be an Array, got: ' + JSON.stringify(parsed.ids)); + assert.strictEqual(parsed.ids.length, 21); + done(); + }); + }); + + it('should parse 100 repeated query params as an array', function (done) { + var app = createApp('extended'); + + var query = Array.from({ length: 100 }, function (_, i) { return 'ids=' + i; }).join('&'); + + request(app) + .get('/?' + query) + .expect(200) + .end(function (err, res) { + if (err) return done(err); + var parsed = JSON.parse(res.text); + assert.ok(Array.isArray(parsed.ids), + 'req.query.ids should be an Array, got: ' + typeof parsed.ids); + assert.strictEqual(parsed.ids.length, 100); + done(); + }); + }); + + it('should still parse 20 or fewer repeated params as an array', function (done) { + var app = createApp('extended'); + + var query = Array.from({ length: 20 }, function (_, i) { return 'ids=' + i; }).join('&'); + + request(app) + .get('/?' + query) + .expect(200) + .end(function (err, res) { + if (err) return done(err); + var parsed = JSON.parse(res.text); + assert.ok(Array.isArray(parsed.ids), + 'req.query.ids should be an Array for 20 items'); + assert.strictEqual(parsed.ids.length, 20); + done(); + }); + }); +}); \ No newline at end of file From e79dfa580d11750a5cac16d36e073653f10d4b0d Mon Sep 17 00:00:00 2001 From: IshitaSingh0822 Date: Sun, 19 Apr 2026 23:19:33 +0530 Subject: [PATCH 4/4] fix: add missing newline at end of req.query.js --- test/req.query.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/req.query.js b/test/req.query.js index 19a2df117e3..a388a412dce 100644 --- a/test/req.query.js +++ b/test/req.query.js @@ -163,4 +163,4 @@ describe('regression: issue #7147 — arrays with more than 20 values', function done(); }); }); -}); \ No newline at end of file +});