Skip to content

Commit cfc108f

Browse files
committed
[Fix] arrayLimit means max count, not max index, in combine/merge/parseArrayValue
1 parent febb644 commit cfc108f

File tree

4 files changed

+48
-47
lines changed

4 files changed

+48
-47
lines changed

lib/parse.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ var parseArrayValue = function (val, options, currentArrayLength) {
4040
return val.split(',');
4141
}
4242

43-
if (options.throwOnLimitExceeded && currentArrayLength > options.arrayLimit) {
44-
throw new RangeError('Array limit exceeded. Only ' + (options.arrayLimit + 1) + ' element' + (options.arrayLimit === 0 ? '' : 's') + ' allowed in an array.');
43+
if (options.throwOnLimitExceeded && currentArrayLength >= options.arrayLimit) {
44+
throw new RangeError('Array limit exceeded. Only ' + options.arrayLimit + ' element' + (options.arrayLimit === 1 ? '' : 's') + ' allowed in an array.');
4545
}
4646

4747
return val;
@@ -194,7 +194,7 @@ var parseObject = function (chain, val, options, valuesParsed) {
194194
&& options.parseArrays;
195195
if (!options.parseArrays && decodedRoot === '') {
196196
obj = { 0: leaf };
197-
} else if (isValidArrayIndex && index <= options.arrayLimit) {
197+
} else if (isValidArrayIndex && index < options.arrayLimit) {
198198
obj = [];
199199
obj[index] = leaf;
200200
} else if (isValidArrayIndex && options.throwOnLimitExceeded) {

lib/utils.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ var merge = function merge(target, source, options) {
112112
return markOverflow(result, getMaxIndex(source) + 1);
113113
}
114114
var combined = [target].concat(source);
115-
if (options && typeof options.arrayLimit === 'number' && combined.length - 1 > options.arrayLimit) {
115+
if (options && typeof options.arrayLimit === 'number' && combined.length > options.arrayLimit) {
116116
return markOverflow(arrayToObject(combined, options), combined.length - 1);
117117
}
118118
return combined;
@@ -296,7 +296,7 @@ var combine = function combine(a, b, arrayLimit, plainObjects) {
296296
}
297297

298298
var result = [].concat(a, b);
299-
if (result.length - 1 > arrayLimit) {
299+
if (result.length > arrayLimit) {
300300
return markOverflow(arrayToObject(result, { plainObjects: plainObjects }), result.length - 1);
301301
}
302302
return result;

test/parse.js

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -261,11 +261,11 @@ test('parse()', function (t) {
261261
});
262262

263263
t.test('limits specific array indices to arrayLimit', function (st) {
264-
st.deepEqual(qs.parse('a[20]=a', { arrayLimit: 20 }), { a: ['a'] });
265-
st.deepEqual(qs.parse('a[21]=a', { arrayLimit: 20 }), { a: { 21: 'a' } });
264+
st.deepEqual(qs.parse('a[19]=a', { arrayLimit: 20 }), { a: ['a'] });
265+
st.deepEqual(qs.parse('a[20]=a', { arrayLimit: 20 }), { a: { 20: 'a' } });
266266

267-
st.deepEqual(qs.parse('a[20]=a'), { a: ['a'] });
268-
st.deepEqual(qs.parse('a[21]=a'), { a: { 21: 'a' } });
267+
st.deepEqual(qs.parse('a[19]=a'), { a: ['a'] });
268+
st.deepEqual(qs.parse('a[20]=a'), { a: { 20: 'a' } });
269269
st.end();
270270
});
271271

@@ -483,7 +483,7 @@ test('parse()', function (t) {
483483

484484
t.test('allows overriding array limit', function (st) {
485485
st.deepEqual(qs.parse('a[0]=b', { arrayLimit: -1 }), { a: { 0: 'b' } });
486-
st.deepEqual(qs.parse('a[0]=b', { arrayLimit: 0 }), { a: ['b'] });
486+
st.deepEqual(qs.parse('a[0]=b', { arrayLimit: 0 }), { a: { 0: 'b' } });
487487

488488
st.deepEqual(qs.parse('a[-1]=b', { arrayLimit: -1 }), { a: { '-1': 'b' } });
489489
st.deepEqual(qs.parse('a[-1]=b', { arrayLimit: 0 }), { a: { '-1': 'b' } });
@@ -1118,22 +1118,22 @@ test('parse()', function (t) {
11181118
});
11191119

11201120
st.test('throws error when array limit exceeded', function (sst) {
1121-
// 5 elements (indices 0-4), max index 4 > limit 3
1121+
// 4 elements exceeds limit of 3
11221122
sst['throws'](
11231123
function () {
1124-
qs.parse('a[]=1&a[]=2&a[]=3&a[]=4&a[]=5', { arrayLimit: 3, throwOnLimitExceeded: true });
1124+
qs.parse('a[]=1&a[]=2&a[]=3&a[]=4', { arrayLimit: 3, throwOnLimitExceeded: true });
11251125
},
1126-
new RangeError('Array limit exceeded. Only 4 elements allowed in an array.'),
1126+
new RangeError('Array limit exceeded. Only 3 elements allowed in an array.'),
11271127
'throws error when array limit is exceeded'
11281128
);
11291129
sst.end();
11301130
});
11311131

11321132
st.test('does not throw when at limit', function (sst) {
1133-
// 4 elements (indices 0-3), max index 3 = limit 3, should not throw
1134-
var result = qs.parse('a[]=1&a[]=2&a[]=3&a[]=4', { arrayLimit: 3, throwOnLimitExceeded: true });
1133+
// 3 elements = limit of 3, should not throw
1134+
var result = qs.parse('a[]=1&a[]=2&a[]=3', { arrayLimit: 3, throwOnLimitExceeded: true });
11351135
sst.ok(Array.isArray(result.a), 'result is an array');
1136-
sst.deepEqual(result.a, ['1', '2', '3', '4'], 'all values present');
1136+
sst.deepEqual(result.a, ['1', '2', '3'], 'all values present');
11371137
sst.end();
11381138
});
11391139

@@ -1347,36 +1347,36 @@ test('DOS', function (t) {
13471347
});
13481348

13491349
test('arrayLimit boundary conditions', function (t) {
1350-
// arrayLimit is about max index, not length. With arrayLimit: 3, indices 0-3 are allowed (4 elements)
1350+
// arrayLimit is the max number of elements allowed in an array
13511351
t.test('exactly at the limit stays as array', function (st) {
1352-
// 4 elements (indices 0-3), max index 3 = limit 3
1353-
var result = qs.parse('a[]=1&a[]=2&a[]=3&a[]=4', { arrayLimit: 3 });
1354-
st.ok(Array.isArray(result.a), 'result is an array when max index equals limit');
1355-
st.deepEqual(result.a, ['1', '2', '3', '4'], 'all values present');
1352+
// 3 elements = limit of 3
1353+
var result = qs.parse('a[]=1&a[]=2&a[]=3', { arrayLimit: 3 });
1354+
st.ok(Array.isArray(result.a), 'result is an array when count equals limit');
1355+
st.deepEqual(result.a, ['1', '2', '3'], 'all values present');
13561356
st.end();
13571357
});
13581358

13591359
t.test('one over the limit converts to object', function (st) {
1360-
// 5 elements (indices 0-4), max index 4 > limit 3
1361-
var result = qs.parse('a[]=1&a[]=2&a[]=3&a[]=4&a[]=5', { arrayLimit: 3 });
1360+
// 4 elements exceeds limit of 3
1361+
var result = qs.parse('a[]=1&a[]=2&a[]=3&a[]=4', { arrayLimit: 3 });
13621362
st.notOk(Array.isArray(result.a), 'result is not an array when over limit');
1363-
st.deepEqual(result.a, { 0: '1', 1: '2', 2: '3', 3: '4', 4: '5' }, 'all values preserved as object');
1363+
st.deepEqual(result.a, { 0: '1', 1: '2', 2: '3', 3: '4' }, 'all values preserved as object');
13641364
st.end();
13651365
});
13661366

1367-
t.test('arrayLimit 1 with two values', function (st) {
1368-
// 2 elements (indices 0-1), max index 1 = limit 1, should be array
1369-
var result = qs.parse('a[]=1&a[]=2', { arrayLimit: 1 });
1370-
st.ok(Array.isArray(result.a), 'result is an array when max index equals limit');
1371-
st.deepEqual(result.a, ['1', '2'], 'both values preserved as array');
1367+
t.test('arrayLimit 1 with one value', function (st) {
1368+
// 1 element = limit of 1
1369+
var result = qs.parse('a[]=1', { arrayLimit: 1 });
1370+
st.ok(Array.isArray(result.a), 'result is an array when count equals limit');
1371+
st.deepEqual(result.a, ['1'], 'value preserved as array');
13721372
st.end();
13731373
});
13741374

1375-
t.test('arrayLimit 1 with three values converts to object', function (st) {
1376-
// 3 elements (indices 0-2), max index 2 > limit 1
1377-
var result = qs.parse('a[]=1&a[]=2&a[]=3', { arrayLimit: 1 });
1375+
t.test('arrayLimit 1 with two values converts to object', function (st) {
1376+
// 2 elements exceeds limit of 1
1377+
var result = qs.parse('a[]=1&a[]=2', { arrayLimit: 1 });
13781378
st.notOk(Array.isArray(result.a), 'result is not an array');
1379-
st.deepEqual(result.a, { 0: '1', 1: '2', 2: '3' }, 'all values preserved as object');
1379+
st.deepEqual(result.a, { 0: '1', 1: '2' }, 'all values preserved as object');
13801380
st.end();
13811381
});
13821382

test/utils.js

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -196,41 +196,42 @@ test('combine()', function (t) {
196196
s2t.end();
197197
});
198198

199-
// arrayLimit is max index allowed, so with limit 3, indices 0-3 (4 elements) are allowed
200199
st.test('exactly at the limit stays as array', function (s2t) {
201-
// 4 elements (indices 0-3), max index 3 = limit 3
202-
var combined = utils.combine(['a', 'b', 'c'], 'd', 3, false);
203-
s2t.deepEqual(combined, ['a', 'b', 'c', 'd'], 'stays as array when max index equals limit');
200+
var combined = utils.combine(['a', 'b'], 'c', 3, false);
201+
s2t.deepEqual(combined, ['a', 'b', 'c'], 'stays as array when count equals limit');
204202
s2t.ok(Array.isArray(combined), 'result is an array');
205203
s2t.end();
206204
});
207205

208206
st.test('over the limit', function (s2t) {
209-
// 5 elements (indices 0-4), max index 4 > limit 3
210-
var combined = utils.combine(['a', 'b', 'c', 'd'], 'e', 3, false);
211-
s2t.deepEqual(combined, { 0: 'a', 1: 'b', 2: 'c', 3: 'd', 4: 'e' }, 'converts to object when over limit');
207+
var combined = utils.combine(['a', 'b', 'c'], 'd', 3, false);
208+
s2t.deepEqual(combined, { 0: 'a', 1: 'b', 2: 'c', 3: 'd' }, 'converts to object when over limit');
212209
s2t.notOk(Array.isArray(combined), 'result is not an array');
213210
s2t.end();
214211
});
215212

216-
st.test('with arrayLimit 0', function (s2t) {
217-
// 1 element (index 0), max index 0 = limit 0, should stay as array
218-
var combined = utils.combine([], 'a', 0, false);
219-
s2t.deepEqual(combined, ['a'], 'stays as array with arrayLimit 0 and single element');
213+
st.test('with arrayLimit 1', function (s2t) {
214+
var combined = utils.combine([], 'a', 1, false);
215+
s2t.deepEqual(combined, ['a'], 'stays as array when count equals limit');
220216
s2t.ok(Array.isArray(combined), 'result is an array');
221217
s2t.end();
222218
});
223219

220+
st.test('with arrayLimit 0 converts single element to object', function (s2t) {
221+
var combined = utils.combine([], 'a', 0, false);
222+
s2t.deepEqual(combined, { 0: 'a' }, 'converts to object when count exceeds limit');
223+
s2t.notOk(Array.isArray(combined), 'result is not an array');
224+
s2t.end();
225+
});
226+
224227
st.test('with arrayLimit 0 and two elements converts to object', function (s2t) {
225-
// 2 elements (indices 0-1), max index 1 > limit 0
226228
var combined = utils.combine(['a'], 'b', 0, false);
227-
s2t.deepEqual(combined, { 0: 'a', 1: 'b' }, 'converts to object when max index exceeds limit');
229+
s2t.deepEqual(combined, { 0: 'a', 1: 'b' }, 'converts to object when count exceeds limit');
228230
s2t.notOk(Array.isArray(combined), 'result is not an array');
229231
s2t.end();
230232
});
231233

232234
st.test('with plainObjects option', function (s2t) {
233-
// 3 elements (indices 0-2), max index 2 > limit 1
234235
var combined = utils.combine(['a', 'b'], 'c', 1, true);
235236
var expected = { __proto__: null, 0: 'a', 1: 'b', 2: 'c' };
236237
s2t.deepEqual(combined, expected, 'converts to object with null prototype');

0 commit comments

Comments
 (0)