diff --git a/lib/types/urlencoded.js b/lib/types/urlencoded.js index 92409373..3567ace6 100644 --- a/lib/types/urlencoded.js +++ b/lib/types/urlencoded.js @@ -131,12 +131,19 @@ function createQueryParser (options) { * @api private */ function parameterCount (body, limit) { - let count = 0 + if (body.length === 0) { + return 0 + } + + let ampersandCount = 0 let index = -1 - do { - count++ - if (count > limit) return undefined // Early exit if limit exceeded - index = body.indexOf('&', index + 1) - } while (index !== -1) - return count + + while ((index = body.indexOf('&', index + 1)) !== -1) { + ampersandCount++ + if (ampersandCount >= limit) { + return undefined + } + } + + return ampersandCount + 1 } diff --git a/test/urlencoded.js b/test/urlencoded.js index 49730659..a61e5a5f 100644 --- a/test/urlencoded.js +++ b/test/urlencoded.js @@ -575,6 +575,60 @@ describe('bodyParser.urlencoded()', function () { .expect(200, done) }) }) + + describe('parameterCount', function () { + it('should handle empty string correctly', function (done) { + request(createServer({ extended: true, parameterLimit: 10 })) + .post('/') + .set('Content-Type', 'application/x-www-form-urlencoded') + .send('') + .expect(200, '{}', done) + }) + + it('should handle leading ampersand correctly', function (done) { + request(createServer({ parameterLimit: 10 })) + .post('/') + .set('Content-Type', 'application/x-www-form-urlencoded') + .send('&a=1&b=2&c=3') + .expect(function (res) { + var body = JSON.parse(res.text) + assert.strictEqual(Object.keys(body).length, 3) + }) + .expect(200, done) + }) + + it('should handle trailing ampersand correctly', function (done) { + request(createServer({ parameterLimit: 10 })) + .post('/') + .set('Content-Type', 'application/x-www-form-urlencoded') + .send('a=1&b=2&c=3&') + .expect(function (res) { + var body = JSON.parse(res.text) + assert.strictEqual(Object.keys(body).length, 3) + }) + .expect(200, done) + }) + + it('should handle consecutive ampersands correctly', function (done) { + request(createServer({ parameterLimit: 10 })) + .post('/') + .set('Content-Type', 'application/x-www-form-urlencoded') + .send('a=1&&b=2') + .expect(function (res) { + var body = JSON.parse(res.text) + assert.strictEqual(Object.keys(body).length, 2) + }) + .expect(200, done) + }) + + it('should enforce limit correctly with trailing ampersand', function (done) { + request(createServer({ parameterLimit: 2 })) + .post('/') + .set('Content-Type', 'application/x-www-form-urlencoded') + .send('a=1&b=2&') + .expect(413, '[parameters.too.many] too many parameters', done) + }) + }) }) describe('with type option', function () {