Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Fix] proper comma parsing of URL-encoded comma #361

Merged
merged 1 commit into from Mar 25, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
40 changes: 23 additions & 17 deletions lib/parse.js
Expand Up @@ -37,6 +37,17 @@ var parseArrayValue = function (val, options) {
return val;
};

var maybeMap = function maybeMap(val, fn) {
if (isArray(val)) {
var mapped = [];
for (var i = 0; i < val.length; i += 1) {
mapped.push(fn(val[i]));
}
return mapped;
}
return fn(val);
};

// 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
Expand Down Expand Up @@ -85,23 +96,18 @@ var parseValues = function parseQueryStringValues(str, options) {
val = options.strictNullHandling ? null : '';
} else {
key = options.decoder(part.slice(0, pos), defaults.decoder, charset, 'key');
var encodedVal = part.slice(pos + 1);
if (options.comma && encodedVal.indexOf(',') !== -1) {
val = encodedVal.split(',')
.map(function (encodedFragment) {
return options.decoder(encodedFragment, defaults.decoder, charset, 'value');
});
} else {
val = options.decoder(encodedVal, defaults.decoder, charset, 'value');
}
val = maybeMap(
parseArrayValue(part.slice(pos + 1), options),
function (encodedVal) {
return options.decoder(encodedVal, defaults.decoder, charset, 'value');
}
);
}

if (val && options.interpretNumericEntities && charset === 'iso-8859-1') {
val = interpretNumericEntities(val);
}

val = parseArrayValue(val, options);

if (part.indexOf('[]=') > -1) {
val = isArray(val) ? [val] : val;
}
Expand All @@ -116,8 +122,8 @@ var parseValues = function parseQueryStringValues(str, options) {
return obj;
};

var parseObject = function (chain, val, options) {
var leaf = parseArrayValue(val, options);
var parseObject = function (chain, val, options, valuesParsed) {
var leaf = valuesParsed ? val : parseArrayValue(val, options);

for (var i = chain.length - 1; i >= 0; --i) {
var obj;
Expand Down Expand Up @@ -145,13 +151,13 @@ var parseObject = function (chain, val, options) {
}
}

leaf = obj;
leaf = obj; // eslint-disable-line no-param-reassign
}

return leaf;
};

var parseKeys = function parseQueryStringKeys(givenKey, val, options) {
var parseKeys = function parseQueryStringKeys(givenKey, val, options, valuesParsed) {
if (!givenKey) {
return;
}
Expand Down Expand Up @@ -202,7 +208,7 @@ var parseKeys = function parseQueryStringKeys(givenKey, val, options) {
keys.push('[' + key.slice(segment.index) + ']');
}

return parseObject(keys, val, options);
return parseObject(keys, val, options, valuesParsed);
};

var normalizeParseOptions = function normalizeParseOptions(opts) {
Expand Down Expand Up @@ -254,7 +260,7 @@ module.exports = function (str, opts) {
var keys = Object.keys(tempObj);
for (var i = 0; i < keys.length; ++i) {
var key = keys[i];
var newObj = parseKeys(key, tempObj[key], options);
var newObj = parseKeys(key, tempObj[key], options, typeof str === 'string');
obj = utils.merge(obj, newObj, options);
}

Expand Down
2 changes: 1 addition & 1 deletion test/parse.js
Expand Up @@ -430,7 +430,7 @@ test('parse()', function (t) {
});

t.test('parses comma delimited array while having percent-encoded comma treated as normal text', function (st) {
st.deepEqual(qs.parse('foo=a%2Cb', { comma: true }), { foo: ['a', 'b'] });
st.deepEqual(qs.parse('foo=a%2Cb', { comma: true }), { foo: 'a,b' });
st.deepEqual(qs.parse('foo=a%2C%20b,d', { comma: true }), { foo: ['a, b', 'd'] });
st.deepEqual(qs.parse('foo=a%2C%20b,c%2C%20d', { comma: true }), { foo: ['a, b', 'c, d'] });

Expand Down