Skip to content
Permalink
Browse files

[Fix] ensure that `allowPrototypes: false` does not ever shadow Objec…

…t.prototype properties.
  • Loading branch information
ljharb committed Feb 14, 2017
1 parent 8bd4c6c commit beade029171b8cef9cee0d03ebe577e2dd84976d
Showing with 33 additions and 8 deletions.
  1. +4 −4 lib/parse.js
  2. +29 −4 test/parse.js
@@ -55,7 +55,7 @@ var parseObject = function parseObjectRecursive(chain, val, options) {
obj = obj.concat(parseObject(chain, val, options));
} else {
obj = options.plainObjects ? Object.create(null) : {};
var cleanRoot = root[0] === '[' && root[root.length - 1] === ']' ? root.slice(1, root.length - 1) : root;
var cleanRoot = root.charAt(0) === '[' && root.charAt(root.length - 1) === ']' ? root.slice(1, -1) : root;
var index = parseInt(cleanRoot, 10);
if (
!isNaN(index) &&
@@ -84,7 +84,7 @@ var parseKeys = function parseQueryStringKeys(givenKey, val, options) {

// The regex chunks

var parent = /^([^[\]]*)/;
var parent = /^([^[]*)/;
var child = /(\[[^[\]]*])/g;

// Get the parent
@@ -111,9 +111,9 @@ var parseKeys = function parseQueryStringKeys(givenKey, val, options) {
var i = 0;
while ((segment = child.exec(key)) !== null && i < options.depth) {
i += 1;
if (!options.plainObjects && has.call(Object.prototype, segment[1].replace(/\[|]/g, ''))) {
if (!options.plainObjects && has.call(Object.prototype, segment[1].slice(1, -1))) {
if (!options.allowPrototypes) {
continue;
return;
}
}
keys.push(segment[1]);
@@ -131,9 +131,9 @@ test('parse()', function (t) {
st.deepEqual(qs.parse('foo[bad]=baz&foo[]=bar&foo[]=foo'), { foo: { bad: 'baz', 0: 'bar', 1: 'foo' } });
st.deepEqual(qs.parse('foo[0][a]=a&foo[0][b]=b&foo[1][a]=aa&foo[1][b]=bb'), { foo: [{ a: 'a', b: 'b' }, { a: 'aa', b: 'bb' }] });

st.deepEqual(qs.parse('a[]=b&a[t]=u&a[hasOwnProperty]=c', { allowPrototypes: false }), { a: { 0: 'b', c: true, t: 'u' } });
st.deepEqual(qs.parse('a[]=b&a[t]=u&a[hasOwnProperty]=c', { allowPrototypes: false }), { a: { 0: 'b', t: 'u' } });
st.deepEqual(qs.parse('a[]=b&a[t]=u&a[hasOwnProperty]=c', { allowPrototypes: true }), { a: { 0: 'b', t: 'u', hasOwnProperty: 'c' } });
st.deepEqual(qs.parse('a[]=b&a[hasOwnProperty]=c&a[x]=y', { allowPrototypes: false }), { a: { 0: 'b', 1: 'c', x: 'y' } });
st.deepEqual(qs.parse('a[]=b&a[hasOwnProperty]=c&a[x]=y', { allowPrototypes: false }), { a: { 0: 'b', x: 'y' } });
st.deepEqual(qs.parse('a[]=b&a[hasOwnProperty]=c&a[x]=y', { allowPrototypes: true }), { a: { 0: 'b', hasOwnProperty: 'c', x: 'y' } });
st.end();
});
@@ -413,9 +413,34 @@ test('parse()', function (t) {
st.end();
});

t.test('does not allow overwriting prototype properties', function (st) {
st.deepEqual(qs.parse('a[hasOwnProperty]=b', { allowPrototypes: false }), {});
st.deepEqual(qs.parse('hasOwnProperty=b', { allowPrototypes: false }), {});

st.deepEqual(
qs.parse('toString', { allowPrototypes: false }),
{},
'bare "toString" results in {}'
);

st.end();
});

t.test('can allow overwriting prototype properties', function (st) {
st.deepEqual(qs.parse('a[hasOwnProperty]=b', { allowPrototypes: true }), { a: { hasOwnProperty: 'b' } }, { prototype: false });
st.deepEqual(qs.parse('hasOwnProperty=b', { allowPrototypes: true }), { hasOwnProperty: 'b' }, { prototype: false });
st.deepEqual(qs.parse('a[hasOwnProperty]=b', { allowPrototypes: true }), { a: { hasOwnProperty: 'b' } });
st.deepEqual(qs.parse('hasOwnProperty=b', { allowPrototypes: true }), { hasOwnProperty: 'b' });

st.deepEqual(
qs.parse('toString', { allowPrototypes: true }),
{ toString: '' },
'bare "toString" results in { toString: "" }'
);

st.end();
});

t.test('params starting with a closing bracket', function (st) {
st.deepEqual(qs.parse(']=toString'), { ']': 'toString' });
st.end();
});

0 comments on commit beade02

Please sign in to comment.
You can’t perform that action at this time.