qs 6.5.3 → 6.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.editorconfig +1 -14
- package/.eslintignore +1 -0
- package/.eslintrc +6 -22
- package/CHANGELOG.md +12 -20
- package/LICENSE +28 -0
- package/README.md +107 -56
- package/dist/qs.js +133 -44
- package/lib/formats.js +1 -1
- package/lib/parse.js +60 -9
- package/lib/stringify.js +42 -17
- package/lib/utils.js +30 -17
- package/package.json +15 -17
- package/test/.eslintrc +17 -0
- package/test/parse.js +80 -70
- package/test/stringify.js +32 -25
- package/test/utils.js +52 -28
- package/.github/FUNDING.yml +0 -12
- package/.nycrc +0 -13
- package/LICENSE.md +0 -29
- package/bower.json +0 -21
- package/component.json +0 -15
package/dist/qs.js
CHANGED
|
@@ -11,7 +11,7 @@ module.exports = {
|
|
|
11
11
|
return replace.call(value, percentTwenties, '+');
|
|
12
12
|
},
|
|
13
13
|
RFC3986: function (value) {
|
|
14
|
-
return
|
|
14
|
+
return value;
|
|
15
15
|
}
|
|
16
16
|
},
|
|
17
17
|
RFC1738: 'RFC1738',
|
|
@@ -42,21 +42,62 @@ var defaults = {
|
|
|
42
42
|
allowDots: false,
|
|
43
43
|
allowPrototypes: false,
|
|
44
44
|
arrayLimit: 20,
|
|
45
|
+
charset: 'utf-8',
|
|
46
|
+
charsetSentinel: false,
|
|
45
47
|
decoder: utils.decode,
|
|
46
48
|
delimiter: '&',
|
|
47
49
|
depth: 5,
|
|
50
|
+
ignoreQueryPrefix: false,
|
|
51
|
+
interpretNumericEntities: false,
|
|
48
52
|
parameterLimit: 1000,
|
|
53
|
+
parseArrays: true,
|
|
49
54
|
plainObjects: false,
|
|
50
55
|
strictNullHandling: false
|
|
51
56
|
};
|
|
52
57
|
|
|
58
|
+
var interpretNumericEntities = function (str) {
|
|
59
|
+
return str.replace(/&#(\d+);/g, function ($0, numberStr) {
|
|
60
|
+
return String.fromCharCode(parseInt(numberStr, 10));
|
|
61
|
+
});
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
// This is what browsers will submit when the ✓ character occurs in an
|
|
65
|
+
// application/x-www-form-urlencoded body and the encoding of the page containing
|
|
66
|
+
// the form is iso-8859-1, or when the submitted form has an accept-charset
|
|
67
|
+
// attribute of iso-8859-1. Presumably also with other charsets that do not contain
|
|
68
|
+
// the ✓ character, such as us-ascii.
|
|
69
|
+
var isoSentinel = 'utf8=%26%2310003%3B'; // encodeURIComponent('✓')
|
|
70
|
+
|
|
71
|
+
// These are the percent-encoded utf-8 octets representing a checkmark, indicating that the request actually is utf-8 encoded.
|
|
72
|
+
var charsetSentinel = 'utf8=%E2%9C%93'; // encodeURIComponent('✓')
|
|
73
|
+
|
|
53
74
|
var parseValues = function parseQueryStringValues(str, options) {
|
|
54
75
|
var obj = {};
|
|
55
76
|
var cleanStr = options.ignoreQueryPrefix ? str.replace(/^\?/, '') : str;
|
|
56
77
|
var limit = options.parameterLimit === Infinity ? undefined : options.parameterLimit;
|
|
57
78
|
var parts = cleanStr.split(options.delimiter, limit);
|
|
79
|
+
var skipIndex = -1; // Keep track of where the utf8 sentinel was found
|
|
80
|
+
var i;
|
|
81
|
+
|
|
82
|
+
var charset = options.charset;
|
|
83
|
+
if (options.charsetSentinel) {
|
|
84
|
+
for (i = 0; i < parts.length; ++i) {
|
|
85
|
+
if (parts[i].indexOf('utf8=') === 0) {
|
|
86
|
+
if (parts[i] === charsetSentinel) {
|
|
87
|
+
charset = 'utf-8';
|
|
88
|
+
} else if (parts[i] === isoSentinel) {
|
|
89
|
+
charset = 'iso-8859-1';
|
|
90
|
+
}
|
|
91
|
+
skipIndex = i;
|
|
92
|
+
i = parts.length; // The eslint settings do not allow break;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
58
96
|
|
|
59
|
-
for (
|
|
97
|
+
for (i = 0; i < parts.length; ++i) {
|
|
98
|
+
if (i === skipIndex) {
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
60
101
|
var part = parts[i];
|
|
61
102
|
|
|
62
103
|
var bracketEqualsPos = part.indexOf(']=');
|
|
@@ -64,14 +105,18 @@ var parseValues = function parseQueryStringValues(str, options) {
|
|
|
64
105
|
|
|
65
106
|
var key, val;
|
|
66
107
|
if (pos === -1) {
|
|
67
|
-
key = options.decoder(part, defaults.decoder);
|
|
108
|
+
key = options.decoder(part, defaults.decoder, charset);
|
|
68
109
|
val = options.strictNullHandling ? null : '';
|
|
69
110
|
} else {
|
|
70
|
-
key = options.decoder(part.slice(0, pos), defaults.decoder);
|
|
71
|
-
val = options.decoder(part.slice(pos + 1), defaults.decoder);
|
|
111
|
+
key = options.decoder(part.slice(0, pos), defaults.decoder, charset);
|
|
112
|
+
val = options.decoder(part.slice(pos + 1), defaults.decoder, charset);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (val && options.interpretNumericEntities && charset === 'iso-8859-1') {
|
|
116
|
+
val = interpretNumericEntities(val);
|
|
72
117
|
}
|
|
73
118
|
if (has.call(obj, key)) {
|
|
74
|
-
obj[key] =
|
|
119
|
+
obj[key] = utils.combine(obj[key], val);
|
|
75
120
|
} else {
|
|
76
121
|
obj[key] = val;
|
|
77
122
|
}
|
|
@@ -104,7 +149,7 @@ var parseObject = function (chain, val, options) {
|
|
|
104
149
|
) {
|
|
105
150
|
obj = [];
|
|
106
151
|
obj[index] = leaf;
|
|
107
|
-
} else
|
|
152
|
+
} else {
|
|
108
153
|
obj[cleanRoot] = leaf;
|
|
109
154
|
}
|
|
110
155
|
}
|
|
@@ -137,8 +182,7 @@ var parseKeys = function parseQueryStringKeys(givenKey, val, options) {
|
|
|
137
182
|
|
|
138
183
|
var keys = [];
|
|
139
184
|
if (parent) {
|
|
140
|
-
// If we aren't using plain objects, optionally prefix keys
|
|
141
|
-
// that would overwrite object prototype properties
|
|
185
|
+
// If we aren't using plain objects, optionally prefix keys that would overwrite object prototype properties
|
|
142
186
|
if (!options.plainObjects && has.call(Object.prototype, parent)) {
|
|
143
187
|
if (!options.allowPrototypes) {
|
|
144
188
|
return;
|
|
@@ -183,12 +227,19 @@ module.exports = function (str, opts) {
|
|
|
183
227
|
options.arrayLimit = typeof options.arrayLimit === 'number' ? options.arrayLimit : defaults.arrayLimit;
|
|
184
228
|
options.parseArrays = options.parseArrays !== false;
|
|
185
229
|
options.decoder = typeof options.decoder === 'function' ? options.decoder : defaults.decoder;
|
|
186
|
-
options.allowDots = typeof options.allowDots === '
|
|
230
|
+
options.allowDots = typeof options.allowDots === 'undefined' ? defaults.allowDots : !!options.allowDots;
|
|
187
231
|
options.plainObjects = typeof options.plainObjects === 'boolean' ? options.plainObjects : defaults.plainObjects;
|
|
188
232
|
options.allowPrototypes = typeof options.allowPrototypes === 'boolean' ? options.allowPrototypes : defaults.allowPrototypes;
|
|
189
233
|
options.parameterLimit = typeof options.parameterLimit === 'number' ? options.parameterLimit : defaults.parameterLimit;
|
|
190
234
|
options.strictNullHandling = typeof options.strictNullHandling === 'boolean' ? options.strictNullHandling : defaults.strictNullHandling;
|
|
191
235
|
|
|
236
|
+
if (typeof options.charset !== 'undefined' && options.charset !== 'utf-8' && options.charset !== 'iso-8859-1') {
|
|
237
|
+
throw new Error('The charset option must be either utf-8, iso-8859-1, or undefined');
|
|
238
|
+
}
|
|
239
|
+
if (typeof options.charset === 'undefined') {
|
|
240
|
+
options.charset = defaults.charset;
|
|
241
|
+
}
|
|
242
|
+
|
|
192
243
|
if (str === '' || str === null || typeof str === 'undefined') {
|
|
193
244
|
return options.plainObjects ? Object.create(null) : {};
|
|
194
245
|
}
|
|
@@ -215,13 +266,13 @@ var utils = require('./utils');
|
|
|
215
266
|
var formats = require('./formats');
|
|
216
267
|
|
|
217
268
|
var arrayPrefixGenerators = {
|
|
218
|
-
brackets: function brackets(prefix) {
|
|
269
|
+
brackets: function brackets(prefix) { // eslint-disable-line func-name-matching
|
|
219
270
|
return prefix + '[]';
|
|
220
271
|
},
|
|
221
|
-
indices: function indices(prefix, key) {
|
|
272
|
+
indices: function indices(prefix, key) { // eslint-disable-line func-name-matching
|
|
222
273
|
return prefix + '[' + key + ']';
|
|
223
274
|
},
|
|
224
|
-
repeat: function repeat(prefix) {
|
|
275
|
+
repeat: function repeat(prefix) { // eslint-disable-line func-name-matching
|
|
225
276
|
return prefix;
|
|
226
277
|
}
|
|
227
278
|
};
|
|
@@ -235,18 +286,24 @@ var pushToArray = function (arr, valueOrArray) {
|
|
|
235
286
|
var toISO = Date.prototype.toISOString;
|
|
236
287
|
|
|
237
288
|
var defaults = {
|
|
289
|
+
addQueryPrefix: false,
|
|
290
|
+
allowDots: false,
|
|
291
|
+
charset: 'utf-8',
|
|
292
|
+
charsetSentinel: false,
|
|
238
293
|
delimiter: '&',
|
|
239
294
|
encode: true,
|
|
240
295
|
encoder: utils.encode,
|
|
241
296
|
encodeValuesOnly: false,
|
|
242
|
-
|
|
297
|
+
// deprecated
|
|
298
|
+
indices: false,
|
|
299
|
+
serializeDate: function serializeDate(date) { // eslint-disable-line func-name-matching
|
|
243
300
|
return toISO.call(date);
|
|
244
301
|
},
|
|
245
302
|
skipNulls: false,
|
|
246
303
|
strictNullHandling: false
|
|
247
304
|
};
|
|
248
305
|
|
|
249
|
-
var stringify = function stringify(
|
|
306
|
+
var stringify = function stringify( // eslint-disable-line func-name-matching
|
|
250
307
|
object,
|
|
251
308
|
prefix,
|
|
252
309
|
generateArrayPrefix,
|
|
@@ -258,7 +315,8 @@ var stringify = function stringify(
|
|
|
258
315
|
allowDots,
|
|
259
316
|
serializeDate,
|
|
260
317
|
formatter,
|
|
261
|
-
encodeValuesOnly
|
|
318
|
+
encodeValuesOnly,
|
|
319
|
+
charset
|
|
262
320
|
) {
|
|
263
321
|
var obj = object;
|
|
264
322
|
if (typeof filter === 'function') {
|
|
@@ -269,7 +327,7 @@ var stringify = function stringify(
|
|
|
269
327
|
|
|
270
328
|
if (obj === null) {
|
|
271
329
|
if (strictNullHandling) {
|
|
272
|
-
return encoder && !encodeValuesOnly ? encoder(prefix, defaults.encoder) : prefix;
|
|
330
|
+
return encoder && !encodeValuesOnly ? encoder(prefix, defaults.encoder, charset) : prefix;
|
|
273
331
|
}
|
|
274
332
|
|
|
275
333
|
obj = '';
|
|
@@ -277,8 +335,8 @@ var stringify = function stringify(
|
|
|
277
335
|
|
|
278
336
|
if (typeof obj === 'string' || typeof obj === 'number' || typeof obj === 'boolean' || utils.isBuffer(obj)) {
|
|
279
337
|
if (encoder) {
|
|
280
|
-
var keyValue = encodeValuesOnly ? prefix : encoder(prefix, defaults.encoder);
|
|
281
|
-
return [formatter(keyValue) + '=' + formatter(encoder(obj, defaults.encoder))];
|
|
338
|
+
var keyValue = encodeValuesOnly ? prefix : encoder(prefix, defaults.encoder, charset);
|
|
339
|
+
return [formatter(keyValue) + '=' + formatter(encoder(obj, defaults.encoder, charset))];
|
|
282
340
|
}
|
|
283
341
|
return [formatter(prefix) + '=' + formatter(String(obj))];
|
|
284
342
|
}
|
|
@@ -290,7 +348,7 @@ var stringify = function stringify(
|
|
|
290
348
|
}
|
|
291
349
|
|
|
292
350
|
var objKeys;
|
|
293
|
-
if (isArray(filter)) {
|
|
351
|
+
if (Array.isArray(filter)) {
|
|
294
352
|
objKeys = filter;
|
|
295
353
|
} else {
|
|
296
354
|
var keys = Object.keys(obj);
|
|
@@ -304,7 +362,7 @@ var stringify = function stringify(
|
|
|
304
362
|
continue;
|
|
305
363
|
}
|
|
306
364
|
|
|
307
|
-
if (isArray(obj)) {
|
|
365
|
+
if (Array.isArray(obj)) {
|
|
308
366
|
pushToArray(values, stringify(
|
|
309
367
|
obj[key],
|
|
310
368
|
generateArrayPrefix(prefix, key),
|
|
@@ -317,7 +375,8 @@ var stringify = function stringify(
|
|
|
317
375
|
allowDots,
|
|
318
376
|
serializeDate,
|
|
319
377
|
formatter,
|
|
320
|
-
encodeValuesOnly
|
|
378
|
+
encodeValuesOnly,
|
|
379
|
+
charset
|
|
321
380
|
));
|
|
322
381
|
} else {
|
|
323
382
|
pushToArray(values, stringify(
|
|
@@ -332,7 +391,8 @@ var stringify = function stringify(
|
|
|
332
391
|
allowDots,
|
|
333
392
|
serializeDate,
|
|
334
393
|
formatter,
|
|
335
|
-
encodeValuesOnly
|
|
394
|
+
encodeValuesOnly,
|
|
395
|
+
charset
|
|
336
396
|
));
|
|
337
397
|
}
|
|
338
398
|
}
|
|
@@ -344,7 +404,7 @@ module.exports = function (object, opts) {
|
|
|
344
404
|
var obj = object;
|
|
345
405
|
var options = opts ? utils.assign({}, opts) : {};
|
|
346
406
|
|
|
347
|
-
if (options.encoder !== null &&
|
|
407
|
+
if (options.encoder !== null && options.encoder !== undefined && typeof options.encoder !== 'function') {
|
|
348
408
|
throw new TypeError('Encoder has to be a function.');
|
|
349
409
|
}
|
|
350
410
|
|
|
@@ -354,9 +414,14 @@ module.exports = function (object, opts) {
|
|
|
354
414
|
var encode = typeof options.encode === 'boolean' ? options.encode : defaults.encode;
|
|
355
415
|
var encoder = typeof options.encoder === 'function' ? options.encoder : defaults.encoder;
|
|
356
416
|
var sort = typeof options.sort === 'function' ? options.sort : null;
|
|
357
|
-
var allowDots = typeof options.allowDots === 'undefined' ?
|
|
417
|
+
var allowDots = typeof options.allowDots === 'undefined' ? defaults.allowDots : !!options.allowDots;
|
|
358
418
|
var serializeDate = typeof options.serializeDate === 'function' ? options.serializeDate : defaults.serializeDate;
|
|
359
419
|
var encodeValuesOnly = typeof options.encodeValuesOnly === 'boolean' ? options.encodeValuesOnly : defaults.encodeValuesOnly;
|
|
420
|
+
var charset = options.charset || defaults.charset;
|
|
421
|
+
if (typeof options.charset !== 'undefined' && options.charset !== 'utf-8' && options.charset !== 'iso-8859-1') {
|
|
422
|
+
throw new Error('The charset option must be either utf-8, iso-8859-1, or undefined');
|
|
423
|
+
}
|
|
424
|
+
|
|
360
425
|
if (typeof options.format === 'undefined') {
|
|
361
426
|
options.format = formats['default'];
|
|
362
427
|
} else if (!Object.prototype.hasOwnProperty.call(formats.formatters, options.format)) {
|
|
@@ -369,7 +434,7 @@ module.exports = function (object, opts) {
|
|
|
369
434
|
if (typeof options.filter === 'function') {
|
|
370
435
|
filter = options.filter;
|
|
371
436
|
obj = filter('', obj);
|
|
372
|
-
} else if (isArray(options.filter)) {
|
|
437
|
+
} else if (Array.isArray(options.filter)) {
|
|
373
438
|
filter = options.filter;
|
|
374
439
|
objKeys = filter;
|
|
375
440
|
}
|
|
@@ -417,13 +482,24 @@ module.exports = function (object, opts) {
|
|
|
417
482
|
allowDots,
|
|
418
483
|
serializeDate,
|
|
419
484
|
formatter,
|
|
420
|
-
encodeValuesOnly
|
|
485
|
+
encodeValuesOnly,
|
|
486
|
+
charset
|
|
421
487
|
));
|
|
422
488
|
}
|
|
423
489
|
|
|
424
490
|
var joined = keys.join(delimiter);
|
|
425
491
|
var prefix = options.addQueryPrefix === true ? '?' : '';
|
|
426
492
|
|
|
493
|
+
if (options.charsetSentinel) {
|
|
494
|
+
if (charset === 'iso-8859-1') {
|
|
495
|
+
// encodeURIComponent('✓'), the "numeric entity" representation of a checkmark
|
|
496
|
+
prefix += 'utf8=%26%2310003%3B&';
|
|
497
|
+
} else {
|
|
498
|
+
// encodeURIComponent('✓')
|
|
499
|
+
prefix += 'utf8=%E2%9C%93&';
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
|
|
427
503
|
return joined.length > 0 ? prefix + joined : '';
|
|
428
504
|
};
|
|
429
505
|
|
|
@@ -442,11 +518,9 @@ var hexTable = (function () {
|
|
|
442
518
|
}());
|
|
443
519
|
|
|
444
520
|
var compactQueue = function compactQueue(queue) {
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
while (queue.length) {
|
|
521
|
+
while (queue.length > 1) {
|
|
448
522
|
var item = queue.pop();
|
|
449
|
-
obj = item.obj[item.prop];
|
|
523
|
+
var obj = item.obj[item.prop];
|
|
450
524
|
|
|
451
525
|
if (Array.isArray(obj)) {
|
|
452
526
|
var compacted = [];
|
|
@@ -460,8 +534,6 @@ var compactQueue = function compactQueue(queue) {
|
|
|
460
534
|
item.obj[item.prop] = compacted;
|
|
461
535
|
}
|
|
462
536
|
}
|
|
463
|
-
|
|
464
|
-
return obj;
|
|
465
537
|
};
|
|
466
538
|
|
|
467
539
|
var arrayToObject = function arrayToObject(source, options) {
|
|
@@ -483,7 +555,7 @@ var merge = function merge(target, source, options) {
|
|
|
483
555
|
if (typeof source !== 'object') {
|
|
484
556
|
if (Array.isArray(target)) {
|
|
485
557
|
target.push(source);
|
|
486
|
-
} else if (
|
|
558
|
+
} else if (typeof target === 'object') {
|
|
487
559
|
if ((options && (options.plainObjects || options.allowPrototypes)) || !has.call(Object.prototype, source)) {
|
|
488
560
|
target[source] = true;
|
|
489
561
|
}
|
|
@@ -494,7 +566,7 @@ var merge = function merge(target, source, options) {
|
|
|
494
566
|
return target;
|
|
495
567
|
}
|
|
496
568
|
|
|
497
|
-
if (
|
|
569
|
+
if (typeof target !== 'object') {
|
|
498
570
|
return [target].concat(source);
|
|
499
571
|
}
|
|
500
572
|
|
|
@@ -506,9 +578,8 @@ var merge = function merge(target, source, options) {
|
|
|
506
578
|
if (Array.isArray(target) && Array.isArray(source)) {
|
|
507
579
|
source.forEach(function (item, i) {
|
|
508
580
|
if (has.call(target, i)) {
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
target[i] = merge(targetItem, item, options);
|
|
581
|
+
if (target[i] && typeof target[i] === 'object') {
|
|
582
|
+
target[i] = merge(target[i], item, options);
|
|
512
583
|
} else {
|
|
513
584
|
target.push(item);
|
|
514
585
|
}
|
|
@@ -538,15 +609,21 @@ var assign = function assignSingleSource(target, source) {
|
|
|
538
609
|
}, target);
|
|
539
610
|
};
|
|
540
611
|
|
|
541
|
-
var decode = function (str) {
|
|
612
|
+
var decode = function (str, decoder, charset) {
|
|
613
|
+
var strWithoutPlus = str.replace(/\+/g, ' ');
|
|
614
|
+
if (charset === 'iso-8859-1') {
|
|
615
|
+
// unescape never throws, no try...catch needed:
|
|
616
|
+
return strWithoutPlus.replace(/%[0-9a-f]{2}/gi, unescape);
|
|
617
|
+
}
|
|
618
|
+
// utf-8
|
|
542
619
|
try {
|
|
543
|
-
return decodeURIComponent(
|
|
620
|
+
return decodeURIComponent(strWithoutPlus);
|
|
544
621
|
} catch (e) {
|
|
545
|
-
return
|
|
622
|
+
return strWithoutPlus;
|
|
546
623
|
}
|
|
547
624
|
};
|
|
548
625
|
|
|
549
|
-
var encode = function encode(str) {
|
|
626
|
+
var encode = function encode(str, defaultEncoder, charset) {
|
|
550
627
|
// This code was originally written by Brian White (mscdex) for the io.js core querystring library.
|
|
551
628
|
// It has been adapted here for stricter adherence to RFC 3986
|
|
552
629
|
if (str.length === 0) {
|
|
@@ -555,6 +632,12 @@ var encode = function encode(str) {
|
|
|
555
632
|
|
|
556
633
|
var string = typeof str === 'string' ? str : String(str);
|
|
557
634
|
|
|
635
|
+
if (charset === 'iso-8859-1') {
|
|
636
|
+
return escape(string).replace(/%u[0-9a-f]{4}/gi, function ($0) {
|
|
637
|
+
return '%26%23' + parseInt($0.slice(2), 16) + '%3B';
|
|
638
|
+
});
|
|
639
|
+
}
|
|
640
|
+
|
|
558
641
|
var out = '';
|
|
559
642
|
for (var i = 0; i < string.length; ++i) {
|
|
560
643
|
var c = string.charCodeAt(i);
|
|
@@ -589,7 +672,6 @@ var encode = function encode(str) {
|
|
|
589
672
|
|
|
590
673
|
i += 1;
|
|
591
674
|
c = 0x10000 + (((c & 0x3FF) << 10) | (string.charCodeAt(i) & 0x3FF));
|
|
592
|
-
/* eslint operator-linebreak: [2, "before"] */
|
|
593
675
|
out += hexTable[0xF0 | (c >> 18)]
|
|
594
676
|
+ hexTable[0x80 | ((c >> 12) & 0x3F)]
|
|
595
677
|
+ hexTable[0x80 | ((c >> 6) & 0x3F)]
|
|
@@ -618,7 +700,9 @@ var compact = function compact(value) {
|
|
|
618
700
|
}
|
|
619
701
|
}
|
|
620
702
|
|
|
621
|
-
|
|
703
|
+
compactQueue(queue);
|
|
704
|
+
|
|
705
|
+
return value;
|
|
622
706
|
};
|
|
623
707
|
|
|
624
708
|
var isRegExp = function isRegExp(obj) {
|
|
@@ -633,9 +717,14 @@ var isBuffer = function isBuffer(obj) {
|
|
|
633
717
|
return !!(obj.constructor && obj.constructor.isBuffer && obj.constructor.isBuffer(obj));
|
|
634
718
|
};
|
|
635
719
|
|
|
720
|
+
var combine = function combine(a, b) {
|
|
721
|
+
return [].concat(a, b);
|
|
722
|
+
};
|
|
723
|
+
|
|
636
724
|
module.exports = {
|
|
637
725
|
arrayToObject: arrayToObject,
|
|
638
726
|
assign: assign,
|
|
727
|
+
combine: combine,
|
|
639
728
|
compact: compact,
|
|
640
729
|
decode: decode,
|
|
641
730
|
encode: encode,
|
package/lib/formats.js
CHANGED
package/lib/parse.js
CHANGED
|
@@ -8,21 +8,62 @@ var defaults = {
|
|
|
8
8
|
allowDots: false,
|
|
9
9
|
allowPrototypes: false,
|
|
10
10
|
arrayLimit: 20,
|
|
11
|
+
charset: 'utf-8',
|
|
12
|
+
charsetSentinel: false,
|
|
11
13
|
decoder: utils.decode,
|
|
12
14
|
delimiter: '&',
|
|
13
15
|
depth: 5,
|
|
16
|
+
ignoreQueryPrefix: false,
|
|
17
|
+
interpretNumericEntities: false,
|
|
14
18
|
parameterLimit: 1000,
|
|
19
|
+
parseArrays: true,
|
|
15
20
|
plainObjects: false,
|
|
16
21
|
strictNullHandling: false
|
|
17
22
|
};
|
|
18
23
|
|
|
24
|
+
var interpretNumericEntities = function (str) {
|
|
25
|
+
return str.replace(/&#(\d+);/g, function ($0, numberStr) {
|
|
26
|
+
return String.fromCharCode(parseInt(numberStr, 10));
|
|
27
|
+
});
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
// This is what browsers will submit when the ✓ character occurs in an
|
|
31
|
+
// application/x-www-form-urlencoded body and the encoding of the page containing
|
|
32
|
+
// the form is iso-8859-1, or when the submitted form has an accept-charset
|
|
33
|
+
// attribute of iso-8859-1. Presumably also with other charsets that do not contain
|
|
34
|
+
// the ✓ character, such as us-ascii.
|
|
35
|
+
var isoSentinel = 'utf8=%26%2310003%3B'; // encodeURIComponent('✓')
|
|
36
|
+
|
|
37
|
+
// These are the percent-encoded utf-8 octets representing a checkmark, indicating that the request actually is utf-8 encoded.
|
|
38
|
+
var charsetSentinel = 'utf8=%E2%9C%93'; // encodeURIComponent('✓')
|
|
39
|
+
|
|
19
40
|
var parseValues = function parseQueryStringValues(str, options) {
|
|
20
41
|
var obj = {};
|
|
21
42
|
var cleanStr = options.ignoreQueryPrefix ? str.replace(/^\?/, '') : str;
|
|
22
43
|
var limit = options.parameterLimit === Infinity ? undefined : options.parameterLimit;
|
|
23
44
|
var parts = cleanStr.split(options.delimiter, limit);
|
|
45
|
+
var skipIndex = -1; // Keep track of where the utf8 sentinel was found
|
|
46
|
+
var i;
|
|
47
|
+
|
|
48
|
+
var charset = options.charset;
|
|
49
|
+
if (options.charsetSentinel) {
|
|
50
|
+
for (i = 0; i < parts.length; ++i) {
|
|
51
|
+
if (parts[i].indexOf('utf8=') === 0) {
|
|
52
|
+
if (parts[i] === charsetSentinel) {
|
|
53
|
+
charset = 'utf-8';
|
|
54
|
+
} else if (parts[i] === isoSentinel) {
|
|
55
|
+
charset = 'iso-8859-1';
|
|
56
|
+
}
|
|
57
|
+
skipIndex = i;
|
|
58
|
+
i = parts.length; // The eslint settings do not allow break;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
24
62
|
|
|
25
|
-
for (
|
|
63
|
+
for (i = 0; i < parts.length; ++i) {
|
|
64
|
+
if (i === skipIndex) {
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
26
67
|
var part = parts[i];
|
|
27
68
|
|
|
28
69
|
var bracketEqualsPos = part.indexOf(']=');
|
|
@@ -30,14 +71,18 @@ var parseValues = function parseQueryStringValues(str, options) {
|
|
|
30
71
|
|
|
31
72
|
var key, val;
|
|
32
73
|
if (pos === -1) {
|
|
33
|
-
key = options.decoder(part, defaults.decoder);
|
|
74
|
+
key = options.decoder(part, defaults.decoder, charset);
|
|
34
75
|
val = options.strictNullHandling ? null : '';
|
|
35
76
|
} else {
|
|
36
|
-
key = options.decoder(part.slice(0, pos), defaults.decoder);
|
|
37
|
-
val = options.decoder(part.slice(pos + 1), defaults.decoder);
|
|
77
|
+
key = options.decoder(part.slice(0, pos), defaults.decoder, charset);
|
|
78
|
+
val = options.decoder(part.slice(pos + 1), defaults.decoder, charset);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (val && options.interpretNumericEntities && charset === 'iso-8859-1') {
|
|
82
|
+
val = interpretNumericEntities(val);
|
|
38
83
|
}
|
|
39
84
|
if (has.call(obj, key)) {
|
|
40
|
-
obj[key] =
|
|
85
|
+
obj[key] = utils.combine(obj[key], val);
|
|
41
86
|
} else {
|
|
42
87
|
obj[key] = val;
|
|
43
88
|
}
|
|
@@ -70,7 +115,7 @@ var parseObject = function (chain, val, options) {
|
|
|
70
115
|
) {
|
|
71
116
|
obj = [];
|
|
72
117
|
obj[index] = leaf;
|
|
73
|
-
} else
|
|
118
|
+
} else {
|
|
74
119
|
obj[cleanRoot] = leaf;
|
|
75
120
|
}
|
|
76
121
|
}
|
|
@@ -103,8 +148,7 @@ var parseKeys = function parseQueryStringKeys(givenKey, val, options) {
|
|
|
103
148
|
|
|
104
149
|
var keys = [];
|
|
105
150
|
if (parent) {
|
|
106
|
-
// If we aren't using plain objects, optionally prefix keys
|
|
107
|
-
// that would overwrite object prototype properties
|
|
151
|
+
// If we aren't using plain objects, optionally prefix keys that would overwrite object prototype properties
|
|
108
152
|
if (!options.plainObjects && has.call(Object.prototype, parent)) {
|
|
109
153
|
if (!options.allowPrototypes) {
|
|
110
154
|
return;
|
|
@@ -149,12 +193,19 @@ module.exports = function (str, opts) {
|
|
|
149
193
|
options.arrayLimit = typeof options.arrayLimit === 'number' ? options.arrayLimit : defaults.arrayLimit;
|
|
150
194
|
options.parseArrays = options.parseArrays !== false;
|
|
151
195
|
options.decoder = typeof options.decoder === 'function' ? options.decoder : defaults.decoder;
|
|
152
|
-
options.allowDots = typeof options.allowDots === '
|
|
196
|
+
options.allowDots = typeof options.allowDots === 'undefined' ? defaults.allowDots : !!options.allowDots;
|
|
153
197
|
options.plainObjects = typeof options.plainObjects === 'boolean' ? options.plainObjects : defaults.plainObjects;
|
|
154
198
|
options.allowPrototypes = typeof options.allowPrototypes === 'boolean' ? options.allowPrototypes : defaults.allowPrototypes;
|
|
155
199
|
options.parameterLimit = typeof options.parameterLimit === 'number' ? options.parameterLimit : defaults.parameterLimit;
|
|
156
200
|
options.strictNullHandling = typeof options.strictNullHandling === 'boolean' ? options.strictNullHandling : defaults.strictNullHandling;
|
|
157
201
|
|
|
202
|
+
if (typeof options.charset !== 'undefined' && options.charset !== 'utf-8' && options.charset !== 'iso-8859-1') {
|
|
203
|
+
throw new Error('The charset option must be either utf-8, iso-8859-1, or undefined');
|
|
204
|
+
}
|
|
205
|
+
if (typeof options.charset === 'undefined') {
|
|
206
|
+
options.charset = defaults.charset;
|
|
207
|
+
}
|
|
208
|
+
|
|
158
209
|
if (str === '' || str === null || typeof str === 'undefined') {
|
|
159
210
|
return options.plainObjects ? Object.create(null) : {};
|
|
160
211
|
}
|