Skip to content

Commit 4e259b2

Browse files
watildejasnell
authored andcommitted
querystring, url: handle repeated sep in search
* update state machine in parse * repeated sep should be adjusted * `&=&=` should be `{ '': [ '', '' ] }` * add test cases for querystring and URLSearchParams Fixes: #10454 PR-URL: #10967 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Timothy Gu <timothygu99@gmail.com>
1 parent 0d9ea4f commit 4e259b2

File tree

2 files changed

+31
-14
lines changed

2 files changed

+31
-14
lines changed

lib/querystring.js

+23-14
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,7 @@ function parse(qs, sep, eq, options) {
292292
const customDecode = (decode !== qsUnescape);
293293

294294
const keys = [];
295+
var posIdx = 0;
295296
var lastPos = 0;
296297
var sepIdx = 0;
297298
var eqIdx = 0;
@@ -319,26 +320,34 @@ function parse(qs, sep, eq, options) {
319320
key = decodeStr(key, decode);
320321
if (valEncoded)
321322
value = decodeStr(value, decode);
322-
// Use a key array lookup instead of using hasOwnProperty(), which is
323-
// slower
324-
if (keys.indexOf(key) === -1) {
325-
obj[key] = value;
326-
keys[keys.length] = key;
327-
} else {
328-
const curValue = obj[key];
329-
// A simple Array-specific property check is enough here to
330-
// distinguish from a string value and is faster and still safe since
331-
// we are generating all of the values being assigned.
332-
if (curValue.pop)
333-
curValue[curValue.length] = value;
334-
else
335-
obj[key] = [curValue, value];
323+
324+
if (key || value || lastPos - posIdx > sepLen || i === 0) {
325+
// Use a key array lookup instead of using hasOwnProperty(), which is
326+
// slower
327+
if (keys.indexOf(key) === -1) {
328+
obj[key] = value;
329+
keys[keys.length] = key;
330+
} else {
331+
const curValue = obj[key] || '';
332+
// A simple Array-specific property check is enough here to
333+
// distinguish from a string value and is faster and still safe
334+
// since we are generating all of the values being assigned.
335+
if (curValue.pop)
336+
curValue[curValue.length] = value;
337+
else if (curValue)
338+
obj[key] = [curValue, value];
339+
}
340+
} else if (i === 1) {
341+
// A pair with repeated sep could be added into obj in the first loop
342+
// and it should be deleted
343+
delete obj[key];
336344
}
337345
if (--pairs === 0)
338346
break;
339347
keyEncoded = valEncoded = customDecode;
340348
encodeCheck = 0;
341349
key = value = '';
350+
posIdx = lastPos;
342351
lastPos = i + 1;
343352
sepIdx = eqIdx = 0;
344353
}

test/parallel/test-querystring.js

+8
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,14 @@ const qsTestCases = [
5151
__defineGetter__: 'baz' }],
5252
// See: https://github.com/joyent/node/issues/3058
5353
['foo&bar=baz', 'foo=&bar=baz', { foo: '', bar: 'baz' }],
54+
['a=b&c&d=e', 'a=b&c=&d=e', { a: 'b', c: '', d: 'e' }],
55+
['a=b&c=&d=e', 'a=b&c=&d=e', { a: 'b', c: '', d: 'e' }],
56+
['a=b&=c&d=e', 'a=b&=c&d=e', { a: 'b', '': 'c', d: 'e' }],
57+
['a=b&=&c=d', 'a=b&=&c=d', { a: 'b', '': '', c: 'd' }],
58+
['&&foo=bar&&', 'foo=bar', { foo: 'bar' }],
59+
['&&&&', '', {}],
60+
['&=&', '=', { '': '' }],
61+
['&=&=', '=&=', { '': [ '', '' ]}],
5462
[null, '', {}],
5563
[undefined, '', {}]
5664
];

0 commit comments

Comments
 (0)