From 9c3860dacffc399c390881551d734ec7cbb107be Mon Sep 17 00:00:00 2001 From: Andreas Lind Date: Mon, 15 Dec 2014 11:46:31 +0100 Subject: [PATCH 01/20] urlencoded, in extended mode: Support iso-8859-1 encoded requests, and also accept iso-8859-1 as a default encoding. --- README.md | 7 +++++++ lib/types/urlencoded.js | 21 +++++++++++++++------ test/urlencoded.js | 17 +++++++++++++++++ 3 files changed, 39 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index d9138bc7..08ed036d 100644 --- a/README.md +++ b/README.md @@ -279,6 +279,13 @@ The `verify` option, if supplied, is called as `verify(req, res, buf, encoding)` where `buf` is a `Buffer` of the raw request body and `encoding` is the encoding of the request. The parsing can be aborted by throwing an error. +##### defaultCharset + +The default charset to parse as, if not specified in content-type. Must be +either `utf-8` or `iso-8859-1`. The latter is only supported in `extended` +mode. Defaults to `utf-8`. + + ## Errors The middlewares provided by this module create errors depending on the error diff --git a/lib/types/urlencoded.js b/lib/types/urlencoded.js index 5ccda218..02686b5f 100644 --- a/lib/types/urlencoded.js +++ b/lib/types/urlencoded.js @@ -60,6 +60,11 @@ function urlencoded (options) { throw new TypeError('option verify must be function') } + var defaultCharset = opts.defaultCharset || 'utf-8' + if (defaultCharset !== 'utf-8' && (!extended && defaultCharset !== 'iso-8859-1')) { + throw new TypeError('option defaultCharset must be either utf-8 or iso-8859-1 (only supported with extended is true)') + } + // create the appropriate query parser var queryparse = extended ? extendedparser(opts) @@ -102,8 +107,8 @@ function urlencoded (options) { } // assert charset - var charset = getCharset(req) || 'utf-8' - if (charset !== 'utf-8') { + var charset = getCharset(req) || defaultCharset + if (charset !== 'utf-8' && charset !== 'iso-8859-1') { debug('invalid charset') next(createError(415, 'unsupported charset "' + charset.toUpperCase() + '"', { charset: charset, @@ -113,8 +118,11 @@ function urlencoded (options) { } // read - read(req, res, next, parse, debug, { - debug: debug, + read(req, res, next, function parse(body) { + return body.length + ? queryparse(body, charset) + : {} + }, debug, { encoding: charset, inflate: inflate, limit: limit, @@ -143,7 +151,7 @@ function extendedparser (options) { parameterLimit = parameterLimit | 0 } - return function queryparse (body) { + return function queryparse (body, charset) { var paramCount = parameterCount(body, parameterLimit) if (paramCount === undefined) { @@ -160,7 +168,8 @@ function extendedparser (options) { allowPrototypes: true, arrayLimit: arrayLimit, depth: Infinity, - parameterLimit: parameterLimit + parameterLimit: parameterLimit, + charset: charset }) } } diff --git a/test/urlencoded.js b/test/urlencoded.js index 8b3702b4..88e3f663 100644 --- a/test/urlencoded.js +++ b/test/urlencoded.js @@ -42,6 +42,23 @@ describe('bodyParser.urlencoded()', function () { .expect(200, '{}', done) }) + it('should parse x-www-form-urlencoded with an explicit iso-8859-1 encoding', function(done){ + request(this.server) + .post('/') + .set('Content-Type', 'application/x-www-form-urlencoded; charset=iso-8859-1') + .send('%A2=%BD') + .expect(200, '{"¢":"½"}', done) + }) + + it('should parse x-www-form-urlencoded with unspecified iso-8859-1 encoding when the defaultCharset is set to iso-8859-1', function(done){ + var server = createServer({ defaultCharset: 'iso-8859-1' }) + request(server) + .post('/') + .set('Content-Type', 'application/x-www-form-urlencoded') + .send('%A2=%BD') + .expect(200, '{"¢":"½"}', done) + }) + it('should handle empty message-body', function (done) { request(createServer({ limit: '1kb' })) .post('/') From 6f5406cc1f3b4fa3c0c4e1282995ef5c054187cb Mon Sep 17 00:00:00 2001 From: Andreas Lind Date: Mon, 15 Dec 2014 14:02:41 +0100 Subject: [PATCH 02/20] urlencoded: Support an utf8 sentinel to detect the charset. --- README.md | 6 ++++++ lib/types/urlencoded.js | 4 +++- test/urlencoded.js | 18 ++++++++++++++++++ 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 08ed036d..3cfd2aa3 100644 --- a/README.md +++ b/README.md @@ -285,6 +285,12 @@ The default charset to parse as, if not specified in content-type. Must be either `utf-8` or `iso-8859-1`. The latter is only supported in `extended` mode. Defaults to `utf-8`. +##### utf8Sentinel + +Whether to let the value of the `utf8` parameter take precedence as the charset +selector. It requires the form to contain a parameter named `utf8` with a value +of `✓`. Only supported in `extended` mode. Defaults to `false`. + ## Errors diff --git a/lib/types/urlencoded.js b/lib/types/urlencoded.js index 02686b5f..d907ba8c 100644 --- a/lib/types/urlencoded.js +++ b/lib/types/urlencoded.js @@ -142,6 +142,7 @@ function extendedparser (options) { ? options.parameterLimit : 1000 var parse = parser('qs') + var utf8Sentinel = options.utf8Sentinel if (isNaN(parameterLimit) || parameterLimit < 1) { throw new TypeError('option parameterLimit must be a positive number') @@ -169,7 +170,8 @@ function extendedparser (options) { arrayLimit: arrayLimit, depth: Infinity, parameterLimit: parameterLimit, - charset: charset + charset: charset, + utf8Sentinel: utf8Sentinel }) } } diff --git a/test/urlencoded.js b/test/urlencoded.js index 88e3f663..741dfe98 100644 --- a/test/urlencoded.js +++ b/test/urlencoded.js @@ -59,6 +59,24 @@ describe('bodyParser.urlencoded()', function () { .expect(200, '{"¢":"½"}', done) }) + it('should parse x-www-form-urlencoded with an unspecified iso-8859-1 encoding when the utf-8 sentinel has a value of %26%2310003%3B', function(done){ + var server = createServer({ utf8Sentinel: true }) + request(server) + .post('/') + .set('Content-Type', 'application/x-www-form-urlencoded') + .send('utf8=%26%2310003%3B&user=%C3%B8') + .expect(200, '{"user":"ø"}', done) + }) + + it('should parse x-www-form-urlencoded with an unspecified utf-8 encoding when the utf-8 sentinel has a value of %E2%9C%93 and the defaultCharset is iso-8859-1', function(done){ + var server = createServer({ utf8Sentinel: true }) + request(server) + .post('/') + .set('Content-Type', 'application/x-www-form-urlencoded') + .send('utf8=%E2%9C%93&user=%C3%B8') + .expect(200, '{"user":"ø"}', done) + }) + it('should handle empty message-body', function (done) { request(createServer({ limit: '1kb' })) .post('/') From cf7807bc1df67015e459dd792c0a2d92ef7e3726 Mon Sep 17 00:00:00 2001 From: Andreas Lind Date: Fri, 9 Jan 2015 16:31:57 +0100 Subject: [PATCH 03/20] Pass the interpretNumericEntities option through to qs. --- README.md | 5 +++++ lib/types/urlencoded.js | 4 +++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 3cfd2aa3..d68be424 100644 --- a/README.md +++ b/README.md @@ -291,6 +291,11 @@ Whether to let the value of the `utf8` parameter take precedence as the charset selector. It requires the form to contain a parameter named `utf8` with a value of `✓`. Only supported in `extended` mode. Defaults to `false`. +##### interpretNumericEntities + +Whether to decode numeric entities such as `☺` when parsing an iso-8859-1 +form. Only supported in `extended` mode. Defaults to `false`. + ## Errors diff --git a/lib/types/urlencoded.js b/lib/types/urlencoded.js index d907ba8c..62e7b0bb 100644 --- a/lib/types/urlencoded.js +++ b/lib/types/urlencoded.js @@ -143,6 +143,7 @@ function extendedparser (options) { : 1000 var parse = parser('qs') var utf8Sentinel = options.utf8Sentinel + var interpretNumericEntities = options.interpretNumericEntities if (isNaN(parameterLimit) || parameterLimit < 1) { throw new TypeError('option parameterLimit must be a positive number') @@ -171,7 +172,8 @@ function extendedparser (options) { depth: Infinity, parameterLimit: parameterLimit, charset: charset, - utf8Sentinel: utf8Sentinel + utf8Sentinel: utf8Sentinel, + interpretNumericEntities: interpretNumericEntities }) } } From 22eb75a453f4bc78f705638f9bc0cd18e4924076 Mon Sep 17 00:00:00 2001 From: Andreas Lind Date: Tue, 31 Jul 2018 19:53:02 +0200 Subject: [PATCH 04/20] Fix lint --- lib/types/urlencoded.js | 8 +------- test/urlencoded.js | 8 ++++---- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/lib/types/urlencoded.js b/lib/types/urlencoded.js index 62e7b0bb..baeb4cef 100644 --- a/lib/types/urlencoded.js +++ b/lib/types/urlencoded.js @@ -75,12 +75,6 @@ function urlencoded (options) { ? typeChecker(type) : type - function parse (body) { - return body.length - ? queryparse(body) - : {} - } - return function urlencodedParser (req, res, next) { if (req._body) { debug('body already parsed') @@ -118,7 +112,7 @@ function urlencoded (options) { } // read - read(req, res, next, function parse(body) { + read(req, res, next, function parse (body) { return body.length ? queryparse(body, charset) : {} diff --git a/test/urlencoded.js b/test/urlencoded.js index 741dfe98..f5ae1544 100644 --- a/test/urlencoded.js +++ b/test/urlencoded.js @@ -42,7 +42,7 @@ describe('bodyParser.urlencoded()', function () { .expect(200, '{}', done) }) - it('should parse x-www-form-urlencoded with an explicit iso-8859-1 encoding', function(done){ + it('should parse x-www-form-urlencoded with an explicit iso-8859-1 encoding', function (done) { request(this.server) .post('/') .set('Content-Type', 'application/x-www-form-urlencoded; charset=iso-8859-1') @@ -50,7 +50,7 @@ describe('bodyParser.urlencoded()', function () { .expect(200, '{"¢":"½"}', done) }) - it('should parse x-www-form-urlencoded with unspecified iso-8859-1 encoding when the defaultCharset is set to iso-8859-1', function(done){ + it('should parse x-www-form-urlencoded with unspecified iso-8859-1 encoding when the defaultCharset is set to iso-8859-1', function (done) { var server = createServer({ defaultCharset: 'iso-8859-1' }) request(server) .post('/') @@ -59,7 +59,7 @@ describe('bodyParser.urlencoded()', function () { .expect(200, '{"¢":"½"}', done) }) - it('should parse x-www-form-urlencoded with an unspecified iso-8859-1 encoding when the utf-8 sentinel has a value of %26%2310003%3B', function(done){ + it('should parse x-www-form-urlencoded with an unspecified iso-8859-1 encoding when the utf-8 sentinel has a value of %26%2310003%3B', function (done) { var server = createServer({ utf8Sentinel: true }) request(server) .post('/') @@ -68,7 +68,7 @@ describe('bodyParser.urlencoded()', function () { .expect(200, '{"user":"ø"}', done) }) - it('should parse x-www-form-urlencoded with an unspecified utf-8 encoding when the utf-8 sentinel has a value of %E2%9C%93 and the defaultCharset is iso-8859-1', function(done){ + it('should parse x-www-form-urlencoded with an unspecified utf-8 encoding when the utf-8 sentinel has a value of %E2%9C%93 and the defaultCharset is iso-8859-1', function (done) { var server = createServer({ utf8Sentinel: true }) request(server) .post('/') From 5c25f5d129526959ab685c9bec5c4a1159201266 Mon Sep 17 00:00:00 2001 From: Andreas Lind Date: Tue, 31 Jul 2018 22:16:49 +0200 Subject: [PATCH 05/20] Support charsets, sentinels etc. via custom decoders Works in both extended and simple mode. --- README.md | 7 ++--- lib/types/urlencoded.js | 66 ++++++++++++++++++++++++++++++++++++----- 2 files changed, 61 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index d68be424..c2bd56d8 100644 --- a/README.md +++ b/README.md @@ -282,19 +282,18 @@ encoding of the request. The parsing can be aborted by throwing an error. ##### defaultCharset The default charset to parse as, if not specified in content-type. Must be -either `utf-8` or `iso-8859-1`. The latter is only supported in `extended` -mode. Defaults to `utf-8`. +either `utf-8` or `iso-8859-1`. ##### utf8Sentinel Whether to let the value of the `utf8` parameter take precedence as the charset selector. It requires the form to contain a parameter named `utf8` with a value -of `✓`. Only supported in `extended` mode. Defaults to `false`. +of `✓`. Defaults to `false`. ##### interpretNumericEntities Whether to decode numeric entities such as `☺` when parsing an iso-8859-1 -form. Only supported in `extended` mode. Defaults to `false`. +form. Defaults to `false`. ## Errors diff --git a/lib/types/urlencoded.js b/lib/types/urlencoded.js index baeb4cef..97e0146d 100644 --- a/lib/types/urlencoded.js +++ b/lib/types/urlencoded.js @@ -32,6 +32,45 @@ module.exports = urlencoded var parsers = Object.create(null) +var charsetBySentinel = { + // This is what browsers will submit when the ✓ character occurs in an + // application/x-www-form-urlencoded body and the encoding of the page containing + // the form is iso-8859-1, or when the submitted form has an accept-charset + // attribute of iso-8859-1. Presumably also with other charsets that do not contain + // the ✓ character, such as us-ascii. + '%26%2310003%3B': 'iso-8859-1', // encodeURIComponent('✓') + // These are the percent-encoded utf-8 octets representing a checkmark, indicating + // that the request actually is utf-8 encoded. + '%E2%9C%93': 'utf-8' // encodeURIComponent('✓') +} + +/** + * Helper for creating a decoder function that interprets percent-encoded octets + * in a certain charset + */ +function getDecoder (charset, interpretNumericEntities) { + return function decoder (str) { + var decodedStr = str.replace(/\+/g, ' '); + if (charset === 'iso-8859-1') { + // unescape never throws, no try...catch needed: + return decodedStr.replace(/%[0-9a-f]{2}/gi, unescape) + } else { + // utf-8 + try { + decodedStr = decodeURIComponent(decodedStr) + } catch (e) { + // URIError, keep encoded + } + } + if (interpretNumericEntities) { + decodedStr = decodedStr.replace(/&#(\d+);/g, function ($0, numberStr) { + return String.fromCharCode(parseInt(numberStr, 10)) + }) + } + return decodedStr + } +} + /** * Create a middleware to parse urlencoded bodies. * @@ -55,14 +94,16 @@ function urlencoded (options) { : opts.limit var type = opts.type || 'application/x-www-form-urlencoded' var verify = opts.verify || false + var utf8Sentinel = opts.utf8Sentinel + var interpretNumericEntities = opts.interpretNumericEntities if (verify !== false && typeof verify !== 'function') { throw new TypeError('option verify must be function') } var defaultCharset = opts.defaultCharset || 'utf-8' - if (defaultCharset !== 'utf-8' && (!extended && defaultCharset !== 'iso-8859-1')) { - throw new TypeError('option defaultCharset must be either utf-8 or iso-8859-1 (only supported with extended is true)') + if (defaultCharset !== 'utf-8' && defaultCharset !== 'iso-8859-1') { + throw new TypeError('option defaultCharset must be either utf-8 or iso-8859-1') } // create the appropriate query parser @@ -113,8 +154,17 @@ function urlencoded (options) { // read read(req, res, next, function parse (body) { - return body.length - ? queryparse(body, charset) + var b = body + if (utf8Sentinel) { + b = b.replace(/(?:^|&)utf8=([^&]+)/, function ($0, value) { + if (charsetBySentinel[value]) { + charset = charsetBySentinel[value] + } + return '' + }) + } + return b.length + ? queryparse(b, getDecoder(charset, interpretNumericEntities)) : {} }, debug, { encoding: charset, @@ -147,7 +197,7 @@ function extendedparser (options) { parameterLimit = parameterLimit | 0 } - return function queryparse (body, charset) { + return function queryparse (body, decoder) { var paramCount = parameterCount(body, parameterLimit) if (paramCount === undefined) { @@ -165,7 +215,7 @@ function extendedparser (options) { arrayLimit: arrayLimit, depth: Infinity, parameterLimit: parameterLimit, - charset: charset, + decoder: decoder, utf8Sentinel: utf8Sentinel, interpretNumericEntities: interpretNumericEntities }) @@ -262,7 +312,7 @@ function simpleparser (options) { parameterLimit = parameterLimit | 0 } - return function queryparse (body) { + return function queryparse (body, decoder) { var paramCount = parameterCount(body, parameterLimit) if (paramCount === undefined) { @@ -273,7 +323,7 @@ function simpleparser (options) { } debug('parse urlencoding') - return parse(body, undefined, undefined, {maxKeys: parameterLimit}) + return parse(body, undefined, undefined, {maxKeys: parameterLimit, decodeURIComponent: decoder}) } } From dab286a3e482158b352a486e939b7eb7e0ce4716 Mon Sep 17 00:00:00 2001 From: Andreas Lind Date: Tue, 31 Jul 2018 22:31:50 +0200 Subject: [PATCH 06/20] Simplify --- lib/types/urlencoded.js | 39 ++++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/lib/types/urlencoded.js b/lib/types/urlencoded.js index 97e0146d..e89d6ca6 100644 --- a/lib/types/urlencoded.js +++ b/lib/types/urlencoded.js @@ -50,7 +50,7 @@ var charsetBySentinel = { */ function getDecoder (charset, interpretNumericEntities) { return function decoder (str) { - var decodedStr = str.replace(/\+/g, ' '); + var decodedStr = str.replace(/\+/g, ' ') if (charset === 'iso-8859-1') { // unescape never throws, no try...catch needed: return decodedStr.replace(/%[0-9a-f]{2}/gi, unescape) @@ -71,6 +71,28 @@ function getDecoder (charset, interpretNumericEntities) { } } +/** + * Helper for creating a decoder for the application/x-www-url-encoded body given + * the parsing options + */ +function createBodyDecoder (queryparse, charset, utf8Sentinel, interpretNumericEntities) { + var correctedCharset = charset + return function bodyDecoder (body) { + var modifiedBody = body + if (utf8Sentinel) { + modifiedBody = modifiedBody.replace(/(?:^|&)utf8=([^&]+)/, function ($0, value) { + if (charsetBySentinel[value]) { + correctedCharset = charsetBySentinel[value] + } + return '' + }) + } + return modifiedBody.length + ? queryparse(modifiedBody, getDecoder(correctedCharset, interpretNumericEntities)) + : {} + } +} + /** * Create a middleware to parse urlencoded bodies. * @@ -153,20 +175,7 @@ function urlencoded (options) { } // read - read(req, res, next, function parse (body) { - var b = body - if (utf8Sentinel) { - b = b.replace(/(?:^|&)utf8=([^&]+)/, function ($0, value) { - if (charsetBySentinel[value]) { - charset = charsetBySentinel[value] - } - return '' - }) - } - return b.length - ? queryparse(b, getDecoder(charset, interpretNumericEntities)) - : {} - }, debug, { + read(req, res, next, createBodyDecoder(queryparse, charset, utf8Sentinel, interpretNumericEntities), debug, { encoding: charset, inflate: inflate, limit: limit, From e3fca5d5f96fb7aa5c6ac7689504827860860929 Mon Sep 17 00:00:00 2001 From: Andreas Lind Date: Tue, 31 Jul 2018 22:45:48 +0200 Subject: [PATCH 07/20] Fix empty parameter issue with utf8Sentinel in simple mode --- lib/types/urlencoded.js | 6 ++++-- test/urlencoded.js | 29 +++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/lib/types/urlencoded.js b/lib/types/urlencoded.js index e89d6ca6..a9aa2760 100644 --- a/lib/types/urlencoded.js +++ b/lib/types/urlencoded.js @@ -80,11 +80,13 @@ function createBodyDecoder (queryparse, charset, utf8Sentinel, interpretNumericE return function bodyDecoder (body) { var modifiedBody = body if (utf8Sentinel) { - modifiedBody = modifiedBody.replace(/(?:^|&)utf8=([^&]+)/, function ($0, value) { + modifiedBody = modifiedBody.replace(/(^|&)utf8=([^&]+)($|&)/, function ($0, ampBefore, value, ampAfter) { if (charsetBySentinel[value]) { correctedCharset = charsetBySentinel[value] } - return '' + // Make sure that we only leave an ampersand when replacing in the middle of the query string + // as the simple parser will add an empty string parameter if it gets && + return ampBefore && ampAfter ? '&' : '' }) } return modifiedBody.length diff --git a/test/urlencoded.js b/test/urlencoded.js index f5ae1544..e57468d2 100644 --- a/test/urlencoded.js +++ b/test/urlencoded.js @@ -77,6 +77,35 @@ describe('bodyParser.urlencoded()', function () { .expect(200, '{"user":"ø"}', done) }) + describe('in simple mode', function () { + it('should not leave an empty string parameter when removing the utf8 sentinel from the start of the string', function (done) { + var server = createServer({ utf8Sentinel: true, extended: false }) + request(server) + .post('/') + .set('Content-Type', 'application/x-www-form-urlencoded') + .send('utf8=%E2%9C%93&foo=bar') + .expect(200, '{"foo":"bar"}', done) + }) + + it('should not leave an empty string parameter when removing the utf8 sentinel from the middle of the string', function (done) { + var server = createServer({ utf8Sentinel: true, extended: false }) + request(server) + .post('/') + .set('Content-Type', 'application/x-www-form-urlencoded') + .send('foo=bar&utf8=%E2%9C%93&baz=quux') + .expect(200, '{"foo":"bar","baz":"quux"}', done) + }) + + it('should not leave an empty string parameter when removing the utf8 sentinel from the end of the string', function (done) { + var server = createServer({ utf8Sentinel: true, extended: false }) + request(server) + .post('/') + .set('Content-Type', 'application/x-www-form-urlencoded') + .send('foo=bar&baz=quux&utf8=%E2%9C%93') + .expect(200, '{"foo":"bar","baz":"quux"}', done) + }) + }) + it('should handle empty message-body', function (done) { request(createServer({ limit: '1kb' })) .post('/') From 5b39b86a79e16f56386349313cf65b7392a0b0ee Mon Sep 17 00:00:00 2001 From: Andreas Lind Date: Tue, 31 Jul 2018 22:53:54 +0200 Subject: [PATCH 08/20] Run all the charset/sentinel tests in both extended and simple modes --- test/urlencoded.js | 114 +++++++++++++++++++++++---------------------- 1 file changed, 59 insertions(+), 55 deletions(-) diff --git a/test/urlencoded.js b/test/urlencoded.js index e57468d2..a16a67f8 100644 --- a/test/urlencoded.js +++ b/test/urlencoded.js @@ -42,67 +42,71 @@ describe('bodyParser.urlencoded()', function () { .expect(200, '{}', done) }) - it('should parse x-www-form-urlencoded with an explicit iso-8859-1 encoding', function (done) { - request(this.server) - .post('/') - .set('Content-Type', 'application/x-www-form-urlencoded; charset=iso-8859-1') - .send('%A2=%BD') - .expect(200, '{"¢":"½"}', done) - }) + var extendedValues = [true, false] + extendedValues.forEach(function (extended) { + describe('in ' + (extended ? 'extended' : 'simple') + ' mode', function () { + it('should parse x-www-form-urlencoded with an explicit iso-8859-1 encoding', function (done) { + var server = createServer({ extended: extended }) + request(server) + .post('/') + .set('Content-Type', 'application/x-www-form-urlencoded; charset=iso-8859-1') + .send('%A2=%BD') + .expect(200, '{"¢":"½"}', done) + }) - it('should parse x-www-form-urlencoded with unspecified iso-8859-1 encoding when the defaultCharset is set to iso-8859-1', function (done) { - var server = createServer({ defaultCharset: 'iso-8859-1' }) - request(server) - .post('/') - .set('Content-Type', 'application/x-www-form-urlencoded') - .send('%A2=%BD') - .expect(200, '{"¢":"½"}', done) - }) + it('should parse x-www-form-urlencoded with unspecified iso-8859-1 encoding when the defaultCharset is set to iso-8859-1', function (done) { + var server = createServer({ defaultCharset: 'iso-8859-1', extended: extended }) + request(server) + .post('/') + .set('Content-Type', 'application/x-www-form-urlencoded') + .send('%A2=%BD') + .expect(200, '{"¢":"½"}', done) + }) - it('should parse x-www-form-urlencoded with an unspecified iso-8859-1 encoding when the utf-8 sentinel has a value of %26%2310003%3B', function (done) { - var server = createServer({ utf8Sentinel: true }) - request(server) - .post('/') - .set('Content-Type', 'application/x-www-form-urlencoded') - .send('utf8=%26%2310003%3B&user=%C3%B8') - .expect(200, '{"user":"ø"}', done) - }) + it('should parse x-www-form-urlencoded with an unspecified iso-8859-1 encoding when the utf-8 sentinel has a value of %26%2310003%3B', function (done) { + var server = createServer({ utf8Sentinel: true, extended: extended }) + request(server) + .post('/') + .set('Content-Type', 'application/x-www-form-urlencoded') + .send('utf8=%26%2310003%3B&user=%C3%B8') + .expect(200, '{"user":"ø"}', done) + }) - it('should parse x-www-form-urlencoded with an unspecified utf-8 encoding when the utf-8 sentinel has a value of %E2%9C%93 and the defaultCharset is iso-8859-1', function (done) { - var server = createServer({ utf8Sentinel: true }) - request(server) - .post('/') - .set('Content-Type', 'application/x-www-form-urlencoded') - .send('utf8=%E2%9C%93&user=%C3%B8') - .expect(200, '{"user":"ø"}', done) - }) + it('should parse x-www-form-urlencoded with an unspecified utf-8 encoding when the utf-8 sentinel has a value of %E2%9C%93 and the defaultCharset is iso-8859-1', function (done) { + var server = createServer({ utf8Sentinel: true, extended: extended }) + request(server) + .post('/') + .set('Content-Type', 'application/x-www-form-urlencoded') + .send('utf8=%E2%9C%93&user=%C3%B8') + .expect(200, '{"user":"ø"}', done) + }) - describe('in simple mode', function () { - it('should not leave an empty string parameter when removing the utf8 sentinel from the start of the string', function (done) { - var server = createServer({ utf8Sentinel: true, extended: false }) - request(server) - .post('/') - .set('Content-Type', 'application/x-www-form-urlencoded') - .send('utf8=%E2%9C%93&foo=bar') - .expect(200, '{"foo":"bar"}', done) - }) + it('should not leave an empty string parameter when removing the utf8 sentinel from the start of the string', function (done) { + var server = createServer({ utf8Sentinel: true, extended: extended }) + request(server) + .post('/') + .set('Content-Type', 'application/x-www-form-urlencoded') + .send('utf8=%E2%9C%93&foo=bar') + .expect(200, '{"foo":"bar"}', done) + }) - it('should not leave an empty string parameter when removing the utf8 sentinel from the middle of the string', function (done) { - var server = createServer({ utf8Sentinel: true, extended: false }) - request(server) - .post('/') - .set('Content-Type', 'application/x-www-form-urlencoded') - .send('foo=bar&utf8=%E2%9C%93&baz=quux') - .expect(200, '{"foo":"bar","baz":"quux"}', done) - }) + it('should not leave an empty string parameter when removing the utf8 sentinel from the middle of the string', function (done) { + var server = createServer({ utf8Sentinel: true, extended: extended }) + request(server) + .post('/') + .set('Content-Type', 'application/x-www-form-urlencoded') + .send('foo=bar&utf8=%E2%9C%93&baz=quux') + .expect(200, '{"foo":"bar","baz":"quux"}', done) + }) - it('should not leave an empty string parameter when removing the utf8 sentinel from the end of the string', function (done) { - var server = createServer({ utf8Sentinel: true, extended: false }) - request(server) - .post('/') - .set('Content-Type', 'application/x-www-form-urlencoded') - .send('foo=bar&baz=quux&utf8=%E2%9C%93') - .expect(200, '{"foo":"bar","baz":"quux"}', done) + it('should not leave an empty string parameter when removing the utf8 sentinel from the end of the string', function (done) { + var server = createServer({ utf8Sentinel: true, extended: extended }) + request(server) + .post('/') + .set('Content-Type', 'application/x-www-form-urlencoded') + .send('foo=bar&baz=quux&utf8=%E2%9C%93') + .expect(200, '{"foo":"bar","baz":"quux"}', done) + }) }) }) From 5daeca85bfde4fda7f3c6708ad598bffe14dc034 Mon Sep 17 00:00:00 2001 From: Andreas Lind Date: Thu, 2 Aug 2018 23:43:46 +0200 Subject: [PATCH 09/20] utf8Sentinel => charsetSentinel https://github.com/ljharb/qs/pull/268#discussion_r207115487 --- README.md | 2 +- lib/types/urlencoded.js | 12 ++++++------ test/urlencoded.js | 10 +++++----- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index c2bd56d8..f10dcd08 100644 --- a/README.md +++ b/README.md @@ -284,7 +284,7 @@ encoding of the request. The parsing can be aborted by throwing an error. The default charset to parse as, if not specified in content-type. Must be either `utf-8` or `iso-8859-1`. -##### utf8Sentinel +##### charsetSentinel Whether to let the value of the `utf8` parameter take precedence as the charset selector. It requires the form to contain a parameter named `utf8` with a value diff --git a/lib/types/urlencoded.js b/lib/types/urlencoded.js index a9aa2760..c6ee4ef8 100644 --- a/lib/types/urlencoded.js +++ b/lib/types/urlencoded.js @@ -75,11 +75,11 @@ function getDecoder (charset, interpretNumericEntities) { * Helper for creating a decoder for the application/x-www-url-encoded body given * the parsing options */ -function createBodyDecoder (queryparse, charset, utf8Sentinel, interpretNumericEntities) { +function createBodyDecoder (queryparse, charset, charsetSentinel, interpretNumericEntities) { var correctedCharset = charset return function bodyDecoder (body) { var modifiedBody = body - if (utf8Sentinel) { + if (charsetSentinel) { modifiedBody = modifiedBody.replace(/(^|&)utf8=([^&]+)($|&)/, function ($0, ampBefore, value, ampAfter) { if (charsetBySentinel[value]) { correctedCharset = charsetBySentinel[value] @@ -118,7 +118,7 @@ function urlencoded (options) { : opts.limit var type = opts.type || 'application/x-www-form-urlencoded' var verify = opts.verify || false - var utf8Sentinel = opts.utf8Sentinel + var charsetSentinel = opts.charsetSentinel var interpretNumericEntities = opts.interpretNumericEntities if (verify !== false && typeof verify !== 'function') { @@ -177,7 +177,7 @@ function urlencoded (options) { } // read - read(req, res, next, createBodyDecoder(queryparse, charset, utf8Sentinel, interpretNumericEntities), debug, { + read(req, res, next, createBodyDecoder(queryparse, charset, charsetSentinel, interpretNumericEntities), debug, { encoding: charset, inflate: inflate, limit: limit, @@ -197,7 +197,7 @@ function extendedparser (options) { ? options.parameterLimit : 1000 var parse = parser('qs') - var utf8Sentinel = options.utf8Sentinel + var charsetSentinel = options.charsetSentinel var interpretNumericEntities = options.interpretNumericEntities if (isNaN(parameterLimit) || parameterLimit < 1) { @@ -227,7 +227,7 @@ function extendedparser (options) { depth: Infinity, parameterLimit: parameterLimit, decoder: decoder, - utf8Sentinel: utf8Sentinel, + charsetSentinel: charsetSentinel, interpretNumericEntities: interpretNumericEntities }) } diff --git a/test/urlencoded.js b/test/urlencoded.js index a16a67f8..58fee1b4 100644 --- a/test/urlencoded.js +++ b/test/urlencoded.js @@ -64,7 +64,7 @@ describe('bodyParser.urlencoded()', function () { }) it('should parse x-www-form-urlencoded with an unspecified iso-8859-1 encoding when the utf-8 sentinel has a value of %26%2310003%3B', function (done) { - var server = createServer({ utf8Sentinel: true, extended: extended }) + var server = createServer({ charsetSentinel: true, extended: extended }) request(server) .post('/') .set('Content-Type', 'application/x-www-form-urlencoded') @@ -73,7 +73,7 @@ describe('bodyParser.urlencoded()', function () { }) it('should parse x-www-form-urlencoded with an unspecified utf-8 encoding when the utf-8 sentinel has a value of %E2%9C%93 and the defaultCharset is iso-8859-1', function (done) { - var server = createServer({ utf8Sentinel: true, extended: extended }) + var server = createServer({ charsetSentinel: true, extended: extended }) request(server) .post('/') .set('Content-Type', 'application/x-www-form-urlencoded') @@ -82,7 +82,7 @@ describe('bodyParser.urlencoded()', function () { }) it('should not leave an empty string parameter when removing the utf8 sentinel from the start of the string', function (done) { - var server = createServer({ utf8Sentinel: true, extended: extended }) + var server = createServer({ charsetSentinel: true, extended: extended }) request(server) .post('/') .set('Content-Type', 'application/x-www-form-urlencoded') @@ -91,7 +91,7 @@ describe('bodyParser.urlencoded()', function () { }) it('should not leave an empty string parameter when removing the utf8 sentinel from the middle of the string', function (done) { - var server = createServer({ utf8Sentinel: true, extended: extended }) + var server = createServer({ charsetSentinel: true, extended: extended }) request(server) .post('/') .set('Content-Type', 'application/x-www-form-urlencoded') @@ -100,7 +100,7 @@ describe('bodyParser.urlencoded()', function () { }) it('should not leave an empty string parameter when removing the utf8 sentinel from the end of the string', function (done) { - var server = createServer({ utf8Sentinel: true, extended: extended }) + var server = createServer({ charsetSentinel: true, extended: extended }) request(server) .post('/') .set('Content-Type', 'application/x-www-form-urlencoded') From 2ef109fa6176f354888eb66b92efa591acd9d00c Mon Sep 17 00:00:00 2001 From: Andreas Lind Date: Mon, 10 Feb 2020 21:52:01 +0100 Subject: [PATCH 10/20] Update qs to 6.9.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 454fc148..bb64de4a 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "http-errors": "1.7.2", "iconv-lite": "0.4.24", "on-finished": "~2.3.0", - "qs": "6.7.0", + "qs": "6.9.1", "raw-body": "2.4.0", "type-is": "~1.6.18" }, From d82fe9e528fd24db4bca918343f806f084c5cd3c Mon Sep 17 00:00:00 2001 From: Andreas Lind Date: Mon, 10 Feb 2020 21:55:36 +0100 Subject: [PATCH 11/20] Always use the qs module, even in simple mode https://github.com/expressjs/body-parser/pull/326#issuecomment-521823039 --- lib/types/urlencoded.js | 48 ++++++----------------------------------- 1 file changed, 7 insertions(+), 41 deletions(-) diff --git a/lib/types/urlencoded.js b/lib/types/urlencoded.js index b2ca8f16..a7e8b0bc 100644 --- a/lib/types/urlencoded.js +++ b/lib/types/urlencoded.js @@ -19,6 +19,7 @@ var debug = require('debug')('body-parser:urlencoded') var deprecate = require('depd')('body-parser') var read = require('../read') var typeis = require('type-is') +var qs = require('qs') /** * Module exports. @@ -26,12 +27,6 @@ var typeis = require('type-is') module.exports = urlencoded -/** - * Cache of parser modules. - */ - -var parsers = Object.create(null) - /** * Create a middleware to parse urlencoded bodies. * @@ -133,7 +128,6 @@ function extendedparser (options) { var parameterLimit = options.parameterLimit !== undefined ? options.parameterLimit : 1000 - var parse = parser('qs') if (isNaN(parameterLimit) || parameterLimit < 1) { throw new TypeError('option parameterLimit must be a positive number') @@ -156,7 +150,7 @@ function extendedparser (options) { var arrayLimit = Math.max(100, paramCount) debug('parse extended urlencoding') - return parse(body, { + return qs.parse(body, { allowPrototypes: true, arrayLimit: arrayLimit, depth: Infinity, @@ -204,37 +198,6 @@ function parameterCount (body, limit) { return count } -/** - * Get parser for module name dynamically. - * - * @param {string} name - * @return {function} - * @api private - */ - -function parser (name) { - var mod = parsers[name] - - if (mod !== undefined) { - return mod.parse - } - - // this uses a switch for static require analysis - switch (name) { - case 'qs': - mod = require('qs') - break - case 'querystring': - mod = require('querystring') - break - } - - // store to prevent invoking require() - parsers[name] = mod - - return mod.parse -} - /** * Get the simple query parser. * @@ -245,7 +208,6 @@ function simpleparser (options) { var parameterLimit = options.parameterLimit !== undefined ? options.parameterLimit : 1000 - var parse = parser('querystring') if (isNaN(parameterLimit) || parameterLimit < 1) { throw new TypeError('option parameterLimit must be a positive number') @@ -266,7 +228,11 @@ function simpleparser (options) { } debug('parse urlencoding') - return parse(body, undefined, undefined, { maxKeys: parameterLimit }) + return qs.parse(body, { + allowPrototypes: true, + depth: 0, + parameterLimit: parameterLimit + }) } } From a0b69dd500e9e324d5d3e3b9216ad63e61e90f2e Mon Sep 17 00:00:00 2001 From: Andreas Lind Date: Mon, 10 Feb 2020 22:15:09 +0100 Subject: [PATCH 12/20] Create the simple and extended parser with the same function, reducing duplication --- lib/types/urlencoded.js | 53 +++++++---------------------------------- 1 file changed, 8 insertions(+), 45 deletions(-) diff --git a/lib/types/urlencoded.js b/lib/types/urlencoded.js index a7e8b0bc..3cc0463e 100644 --- a/lib/types/urlencoded.js +++ b/lib/types/urlencoded.js @@ -56,9 +56,7 @@ function urlencoded (options) { } // create the appropriate query parser - var queryparse = extended - ? extendedparser(opts) - : simpleparser(opts) + var queryparse = createQueryParser(opts, extended); // create the appropriate type checking function var shouldParse = typeof type !== 'function' @@ -124,7 +122,7 @@ function urlencoded (options) { * @param {object} options */ -function extendedparser (options) { +function createQueryParser (options, extended) { var parameterLimit = options.parameterLimit !== undefined ? options.parameterLimit : 1000 @@ -137,6 +135,8 @@ function extendedparser (options) { parameterLimit = parameterLimit | 0 } + var depth = extended ? Infinity : 0; + return function queryparse (body) { var paramCount = parameterCount(body, parameterLimit) @@ -147,13 +147,14 @@ function extendedparser (options) { }) } - var arrayLimit = Math.max(100, paramCount) + var arrayLimit = extended ? Math.max(100, paramCount) : 0 + + debug('parse ' + (extended ? 'extended ' : '') + 'urlencoding') - debug('parse extended urlencoding') return qs.parse(body, { allowPrototypes: true, arrayLimit: arrayLimit, - depth: Infinity, + depth: depth, parameterLimit: parameterLimit }) } @@ -198,44 +199,6 @@ function parameterCount (body, limit) { return count } -/** - * Get the simple query parser. - * - * @param {object} options - */ - -function simpleparser (options) { - var parameterLimit = options.parameterLimit !== undefined - ? options.parameterLimit - : 1000 - - if (isNaN(parameterLimit) || parameterLimit < 1) { - throw new TypeError('option parameterLimit must be a positive number') - } - - if (isFinite(parameterLimit)) { - parameterLimit = parameterLimit | 0 - } - - return function queryparse (body) { - var paramCount = parameterCount(body, parameterLimit) - - if (paramCount === undefined) { - debug('too many parameters') - throw createError(413, 'too many parameters', { - type: 'parameters.too.many' - }) - } - - debug('parse urlencoding') - return qs.parse(body, { - allowPrototypes: true, - depth: 0, - parameterLimit: parameterLimit - }) - } -} - /** * Get the simple type checker. * From 97e574d75a9377643a374fdec075fe43234c2f1c Mon Sep 17 00:00:00 2001 From: Andreas Lind Date: Mon, 10 Feb 2020 22:18:43 +0100 Subject: [PATCH 13/20] Don't mention the querystring module in the README --- README.md | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index aba6297a..abf8debe 100644 --- a/README.md +++ b/README.md @@ -232,12 +232,10 @@ any of the following keys: ##### extended -The `extended` option allows to choose between parsing the URL-encoded data -with the `querystring` library (when `false`) or the `qs` library (when -`true`). The "extended" syntax allows for rich objects and arrays to be -encoded into the URL-encoded format, allowing for a JSON-like experience -with URL-encoded. For more information, please -[see the qs library](https://www.npmjs.org/package/qs#readme). +The "extended" syntax allows for rich objects and arrays to be encoded into the +URL-encoded format, allowing for a JSON-like experience with URL-encoded. For +more information, please [see the qs +library](https://www.npmjs.org/package/qs#readme). Defaults to `true`, but using the default has been deprecated. Please research into the difference between `qs` and `querystring` and choose the From 080ba72ae6447718e069efeb6cead1be7fee5e96 Mon Sep 17 00:00:00 2001 From: Andreas Lind Date: Mon, 10 Feb 2020 22:25:57 +0100 Subject: [PATCH 14/20] Fix lint --- lib/types/urlencoded.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/types/urlencoded.js b/lib/types/urlencoded.js index 3cc0463e..4bed607e 100644 --- a/lib/types/urlencoded.js +++ b/lib/types/urlencoded.js @@ -56,7 +56,7 @@ function urlencoded (options) { } // create the appropriate query parser - var queryparse = createQueryParser(opts, extended); + var queryparse = createQueryParser(opts, extended) // create the appropriate type checking function var shouldParse = typeof type !== 'function' @@ -135,7 +135,7 @@ function createQueryParser (options, extended) { parameterLimit = parameterLimit | 0 } - var depth = extended ? Infinity : 0; + var depth = extended ? Infinity : 0 return function queryparse (body) { var paramCount = parameterCount(body, parameterLimit) From b9645c4d84c13f4f06f60b7fae452ad4bb58ee8b Mon Sep 17 00:00:00 2001 From: Andreas Lind Date: Mon, 26 Oct 2020 20:52:34 +0100 Subject: [PATCH 15/20] Update qs to 6.9.4 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1ea75517..bbc0a046 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "http-errors": "1.7.3", "iconv-lite": "0.4.24", "on-finished": "~2.3.0", - "qs": "6.9.3", + "qs": "6.9.4", "raw-body": "2.4.1", "type-is": "~1.6.18" }, From 097fc97da08b6cd1a7a0d44d02871959f8e49858 Mon Sep 17 00:00:00 2001 From: Andreas Lind Date: Mon, 26 Oct 2020 21:11:42 +0100 Subject: [PATCH 16/20] Consistently call it "utf8 sentinel" --- test/urlencoded.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/urlencoded.js b/test/urlencoded.js index 8f4d0a29..c688941c 100644 --- a/test/urlencoded.js +++ b/test/urlencoded.js @@ -63,7 +63,7 @@ describe('bodyParser.urlencoded()', function () { .expect(200, '{"¢":"½"}', done) }) - it('should parse x-www-form-urlencoded with an unspecified iso-8859-1 encoding when the utf-8 sentinel has a value of %26%2310003%3B', function (done) { + it('should parse x-www-form-urlencoded with an unspecified iso-8859-1 encoding when the utf8 sentinel has a value of %26%2310003%3B', function (done) { var server = createServer({ charsetSentinel: true, extended: extended }) request(server) .post('/') @@ -72,7 +72,7 @@ describe('bodyParser.urlencoded()', function () { .expect(200, '{"user":"ø"}', done) }) - it('should parse x-www-form-urlencoded with an unspecified utf-8 encoding when the utf-8 sentinel has a value of %E2%9C%93 and the defaultCharset is iso-8859-1', function (done) { + it('should parse x-www-form-urlencoded with an unspecified utf-8 encoding when the utf8 sentinel has a value of %E2%9C%93 and the defaultCharset is iso-8859-1', function (done) { var server = createServer({ charsetSentinel: true, extended: extended }) request(server) .post('/') From cbf4cec5c601473c25226d205fcaa84c57706308 Mon Sep 17 00:00:00 2001 From: Andreas Lind Date: Sat, 27 Jul 2024 14:16:36 +0200 Subject: [PATCH 17/20] Simplify by relying on the qs module's support for detecting the charset https://github.com/expressjs/body-parser/pull/326#discussion_r1693684912 --- lib/read.js | 2 +- lib/types/urlencoded.js | 80 +++++++---------------------------------- 2 files changed, 14 insertions(+), 68 deletions(-) diff --git a/lib/read.js b/lib/read.js index 35688f99..20a18ac8 100644 --- a/lib/read.js +++ b/lib/read.js @@ -122,7 +122,7 @@ function read (req, res, next, parse, debug, options) { str = typeof body !== 'string' && encoding !== null ? iconv.decode(body, encoding) : body - req.body = parse(str) + req.body = parse(str, encoding) } catch (err) { next(createError(400, err, { body: str, diff --git a/lib/types/urlencoded.js b/lib/types/urlencoded.js index 66c4ae17..d5b1d2cd 100644 --- a/lib/types/urlencoded.js +++ b/lib/types/urlencoded.js @@ -27,69 +27,6 @@ var qs = require('qs') module.exports = urlencoded -var charsetBySentinel = { - // This is what browsers will submit when the ✓ character occurs in an - // application/x-www-form-urlencoded body and the encoding of the page containing - // the form is iso-8859-1, or when the submitted form has an accept-charset - // attribute of iso-8859-1. Presumably also with other charsets that do not contain - // the ✓ character, such as us-ascii. - '%26%2310003%3B': 'iso-8859-1', // encodeURIComponent('✓') - // These are the percent-encoded utf-8 octets representing a checkmark, indicating - // that the request actually is utf-8 encoded. - '%E2%9C%93': 'utf-8' // encodeURIComponent('✓') -} - -/** - * Helper for creating a decoder function that interprets percent-encoded octets - * in a certain charset - */ -function getDecoder (charset, interpretNumericEntities) { - return function decoder (str) { - var decodedStr = str.replace(/\+/g, ' ') - if (charset === 'iso-8859-1') { - // unescape never throws, no try...catch needed: - return decodedStr.replace(/%[0-9a-f]{2}/gi, unescape) - } else { - // utf-8 - try { - decodedStr = decodeURIComponent(decodedStr) - } catch (e) { - // URIError, keep encoded - } - } - if (interpretNumericEntities) { - decodedStr = decodedStr.replace(/&#(\d+);/g, function ($0, numberStr) { - return String.fromCharCode(parseInt(numberStr, 10)) - }) - } - return decodedStr - } -} - -/** - * Helper for creating a decoder for the application/x-www-url-encoded body given - * the parsing options - */ -function createBodyDecoder (queryparse, charset, charsetSentinel, interpretNumericEntities) { - var correctedCharset = charset - return function bodyDecoder (body) { - var modifiedBody = body - if (charsetSentinel) { - modifiedBody = modifiedBody.replace(/(^|&)utf8=([^&]+)($|&)/, function ($0, ampBefore, value, ampAfter) { - if (charsetBySentinel[value]) { - correctedCharset = charsetBySentinel[value] - } - // Make sure that we only leave an ampersand when replacing in the middle of the query string - // as the simple parser will add an empty string parameter if it gets && - return ampBefore && ampAfter ? '&' : '' - }) - } - return modifiedBody.length - ? queryparse(modifiedBody, getDecoder(correctedCharset, interpretNumericEntities)) - : {} - } -} - /** * Create a middleware to parse urlencoded bodies. * @@ -128,6 +65,12 @@ function urlencoded (options) { ? typeChecker(type) : type + function parse (body, encoding) { + return body.length + ? queryparse(body, undefined, encoding) + : {} + } + return function urlencodedParser (req, res, next) { if (isFinished(req)) { debug('body already parsed') @@ -167,11 +110,13 @@ function urlencoded (options) { } // read - read(req, res, next, createBodyDecoder(queryparse, charset, charsetSentinel, interpretNumericEntities), debug, { + read(req, res, next, parse, debug, { encoding: charset, inflate: inflate, limit: limit, - verify: verify + verify: verify, + charsetSentinel: charsetSentinel, + interpretNumericEntities: interpretNumericEntities }) } } @@ -199,7 +144,7 @@ function createQueryParser (options, extended) { var depth = extended ? Infinity : 0 - return function queryparse (body, decoder) { + return function queryparse (body, decoder, encoding) { var paramCount = parameterCount(body, parameterLimit) if (paramCount === undefined) { @@ -220,7 +165,8 @@ function createQueryParser (options, extended) { parameterLimit: parameterLimit, decoder: decoder, charsetSentinel: charsetSentinel, - interpretNumericEntities: interpretNumericEntities + interpretNumericEntities: interpretNumericEntities, + charset: encoding }) } } From 97d204413f3c36dbae47a522a5ebd981ffd66c45 Mon Sep 17 00:00:00 2001 From: Andreas Lind Date: Sat, 27 Jul 2024 14:19:09 +0200 Subject: [PATCH 18/20] Simplify further --- lib/types/urlencoded.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/types/urlencoded.js b/lib/types/urlencoded.js index d5b1d2cd..ccc091fa 100644 --- a/lib/types/urlencoded.js +++ b/lib/types/urlencoded.js @@ -67,7 +67,7 @@ function urlencoded (options) { function parse (body, encoding) { return body.length - ? queryparse(body, undefined, encoding) + ? queryparse(body, encoding) : {} } @@ -144,7 +144,7 @@ function createQueryParser (options, extended) { var depth = extended ? Infinity : 0 - return function queryparse (body, decoder, encoding) { + return function queryparse (body, encoding) { var paramCount = parameterCount(body, parameterLimit) if (paramCount === undefined) { @@ -163,7 +163,6 @@ function createQueryParser (options, extended) { arrayLimit: arrayLimit, depth: depth, parameterLimit: parameterLimit, - decoder: decoder, charsetSentinel: charsetSentinel, interpretNumericEntities: interpretNumericEntities, charset: encoding From 9d47455b2ce616304e9d3dfc13049e396cd0c513 Mon Sep 17 00:00:00 2001 From: Andreas Lind Date: Sat, 27 Jul 2024 14:20:23 +0200 Subject: [PATCH 19/20] Put back debug option --- lib/types/urlencoded.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/types/urlencoded.js b/lib/types/urlencoded.js index ccc091fa..1c1ff71d 100644 --- a/lib/types/urlencoded.js +++ b/lib/types/urlencoded.js @@ -111,6 +111,7 @@ function urlencoded (options) { // read read(req, res, next, parse, debug, { + debug: debug, encoding: charset, inflate: inflate, limit: limit, From 44a6aa944c05cd865cb2479e2e2d00c816c02c76 Mon Sep 17 00:00:00 2001 From: Andreas Lind Date: Sat, 27 Jul 2024 14:41:48 +0200 Subject: [PATCH 20/20] Document that defaultCharset defaults to utf-8 https://github.com/expressjs/body-parser/pull/326#discussion_r1693684214 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e9c26a9a..219d63c9 100644 --- a/README.md +++ b/README.md @@ -274,7 +274,7 @@ encoding of the request. The parsing can be aborted by throwing an error. ##### defaultCharset The default charset to parse as, if not specified in content-type. Must be -either `utf-8` or `iso-8859-1`. +either `utf-8` or `iso-8859-1`. Defaults to `utf-8`. ##### charsetSentinel