From 486aa46547b4e878d6e87183de95dd26d46fb020 Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Mon, 10 Jan 2022 14:33:08 -0800 Subject: [PATCH] v6.4.1 --- CHANGELOG.md | 21 +++++++++++++++ component.json | 2 +- dist/qs.js | 70 ++++++++++++++++++++++++++++---------------------- package.json | 2 +- 4 files changed, 63 insertions(+), 32 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 85e69b0a..30f10c74 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,24 @@ +## **6.4.1** +- [Fix] `parse`: ignore `__proto__` keys (#428) +- [Fix] fix for an impossible situation: when the formatter is called with a non-string value +- [Fix] use `safer-buffer` instead of `Buffer` constructor +- [Fix] `utils.merge`: avoid a crash with a null target and an array source +- [Fix]` `utils.merge`: avoid a crash with a null target and a truthy non-array source +- [Fix] `stringify`: fix a crash with `strictNullHandling` and a custom `filter`/`serializeDate` (#279) +- [Fix] `utils`: `merge`: fix crash when `source` is a truthy primitive & no options are provided +- [Fix] when `parseArrays` is false, properly handle keys ending in `[]` +- [Robustness] `stringify`: avoid relying on a global `undefined` (#427) +- [Refactor] use cached `Array.isArray` +- [Refactor] `stringify`: Avoid arr = arr.concat(...), push to the existing instance (#269) +- [readme] remove travis badge; add github actions/codecov badges; update URLs +- [Docs] Clarify the need for "arrayLimit" option +- [meta] fix README.md (#399) +- [meta] Clean up license text so it’s properly detected as BSD-3-Clause +- [meta] add FUNDING.yml +- [actions] backport actions from main +- [Tests] remove nonexistent tape option +- [Dev Deps] backport from main + ## **6.4.0** - [New] `qs.stringify`: add `encodeValuesOnly` option - [Fix] follow `allowPrototypes` option during merge (#201, #201) diff --git a/component.json b/component.json index f15c2133..7867ed1c 100644 --- a/component.json +++ b/component.json @@ -2,7 +2,7 @@ "name": "qs", "repository": "hapijs/qs", "description": "query-string parser / stringifier with nesting support", - "version": "6.4.0", + "version": "6.4.1", "keywords": ["querystring", "query", "parser"], "main": "lib/index.js", "scripts": [ diff --git a/dist/qs.js b/dist/qs.js index 483714d8..b2393194 100644 --- a/dist/qs.js +++ b/dist/qs.js @@ -11,7 +11,7 @@ module.exports = { return replace.call(value, percentTwenties, '+'); }, RFC3986: function (value) { - return value; + return String(value); } }, RFC1738: 'RFC1738', @@ -102,7 +102,7 @@ var parseObject = function parseObjectRecursive(chain, val, options) { ) { obj = []; obj[index] = parseObject(chain, val, options); - } else { + } else if (cleanRoot !== '__proto__') { obj[cleanRoot] = parseObject(chain, val, options); } } @@ -132,8 +132,7 @@ var parseKeys = function parseQueryStringKeys(givenKey, val, options) { var keys = []; if (parent) { - // If we aren't using plain objects, optionally prefix keys - // that would overwrite object prototype properties + // If we aren't using plain objects, optionally prefix keys that would overwrite object prototype properties if (!options.plainObjects && has.call(Object.prototype, parent)) { if (!options.allowPrototypes) { return; @@ -209,17 +208,23 @@ var utils = require('./utils'); var formats = require('./formats'); var arrayPrefixGenerators = { - brackets: function brackets(prefix) { // eslint-disable-line func-name-matching + brackets: function brackets(prefix) { return prefix + '[]'; }, - indices: function indices(prefix, key) { // eslint-disable-line func-name-matching + indices: function indices(prefix, key) { return prefix + '[' + key + ']'; }, - repeat: function repeat(prefix) { // eslint-disable-line func-name-matching + repeat: function repeat(prefix) { return prefix; } }; +var isArray = Array.isArray; +var push = Array.prototype.push; +var pushToArray = function (arr, valueOrArray) { + push.apply(arr, isArray(valueOrArray) ? valueOrArray : [valueOrArray]); +}; + var toISO = Date.prototype.toISOString; var defaults = { @@ -227,14 +232,14 @@ var defaults = { encode: true, encoder: utils.encode, encodeValuesOnly: false, - serializeDate: function serializeDate(date) { // eslint-disable-line func-name-matching + serializeDate: function serializeDate(date) { return toISO.call(date); }, skipNulls: false, strictNullHandling: false }; -var stringify = function stringify( // eslint-disable-line func-name-matching +var stringify = function stringify( object, prefix, generateArrayPrefix, @@ -253,7 +258,9 @@ var stringify = function stringify( // eslint-disable-line func-name-matching obj = filter(prefix, obj); } else if (obj instanceof Date) { obj = serializeDate(obj); - } else if (obj === null) { + } + + if (obj === null) { if (strictNullHandling) { return encoder && !encodeValuesOnly ? encoder(prefix) : prefix; } @@ -276,7 +283,7 @@ var stringify = function stringify( // eslint-disable-line func-name-matching } var objKeys; - if (Array.isArray(filter)) { + if (isArray(filter)) { objKeys = filter; } else { var keys = Object.keys(obj); @@ -290,8 +297,8 @@ var stringify = function stringify( // eslint-disable-line func-name-matching continue; } - if (Array.isArray(obj)) { - values = values.concat(stringify( + if (isArray(obj)) { + pushToArray(values, stringify( obj[key], generateArrayPrefix(prefix, key), generateArrayPrefix, @@ -306,7 +313,7 @@ var stringify = function stringify( // eslint-disable-line func-name-matching encodeValuesOnly )); } else { - values = values.concat(stringify( + pushToArray(values, stringify( obj[key], prefix + (allowDots ? '.' + key : '[' + key + ']'), generateArrayPrefix, @@ -330,7 +337,7 @@ module.exports = function (object, opts) { var obj = object; var options = opts || {}; - if (options.encoder !== null && options.encoder !== undefined && typeof options.encoder !== 'function') { + if (options.encoder !== null && typeof options.encoder !== 'undefined' && typeof options.encoder !== 'function') { throw new TypeError('Encoder has to be a function.'); } @@ -344,7 +351,7 @@ module.exports = function (object, opts) { var serializeDate = typeof options.serializeDate === 'function' ? options.serializeDate : defaults.serializeDate; var encodeValuesOnly = typeof options.encodeValuesOnly === 'boolean' ? options.encodeValuesOnly : defaults.encodeValuesOnly; if (typeof options.format === 'undefined') { - options.format = formats.default; + options.format = formats['default']; } else if (!Object.prototype.hasOwnProperty.call(formats.formatters, options.format)) { throw new TypeError('Unknown format option provided.'); } @@ -355,7 +362,7 @@ module.exports = function (object, opts) { if (typeof options.filter === 'function') { filter = options.filter; obj = filter('', obj); - } else if (Array.isArray(options.filter)) { + } else if (isArray(options.filter)) { filter = options.filter; objKeys = filter; } @@ -391,8 +398,7 @@ module.exports = function (object, opts) { if (skipNulls && obj[key] === null) { continue; } - - keys = keys.concat(stringify( + pushToArray(keys, stringify( obj[key], key, generateArrayPrefix, @@ -444,8 +450,8 @@ exports.merge = function (target, source, options) { if (typeof source !== 'object') { if (Array.isArray(target)) { target.push(source); - } else if (typeof target === 'object') { - if (options.plainObjects || options.allowPrototypes || !has.call(Object.prototype, source)) { + } else if (target && typeof target === 'object') { + if ((options && (options.plainObjects || options.allowPrototypes)) || !has.call(Object.prototype, source)) { target[source] = true; } } else { @@ -455,7 +461,7 @@ exports.merge = function (target, source, options) { return target; } - if (typeof target !== 'object') { + if (!target || typeof target !== 'object') { return [target].concat(source); } @@ -513,13 +519,13 @@ exports.encode = function (str) { var c = string.charCodeAt(i); if ( - c === 0x2D || // - - c === 0x2E || // . - c === 0x5F || // _ - c === 0x7E || // ~ - (c >= 0x30 && c <= 0x39) || // 0-9 - (c >= 0x41 && c <= 0x5A) || // a-z - (c >= 0x61 && c <= 0x7A) // A-Z + c === 0x2D // - + || c === 0x2E // . + || c === 0x5F // _ + || c === 0x7E // ~ + || (c >= 0x30 && c <= 0x39) // 0-9 + || (c >= 0x41 && c <= 0x5A) // a-z + || (c >= 0x61 && c <= 0x7A) // A-Z ) { out += string.charAt(i); continue; @@ -542,7 +548,11 @@ exports.encode = function (str) { i += 1; c = 0x10000 + (((c & 0x3FF) << 10) | (string.charCodeAt(i) & 0x3FF)); - out += hexTable[0xF0 | (c >> 18)] + hexTable[0x80 | ((c >> 12) & 0x3F)] + hexTable[0x80 | ((c >> 6) & 0x3F)] + hexTable[0x80 | (c & 0x3F)]; // eslint-disable-line max-len + /* eslint operator-linebreak: [2, "before"] */ + out += hexTable[0xF0 | (c >> 18)] + + hexTable[0x80 | ((c >> 12) & 0x3F)] + + hexTable[0x80 | ((c >> 6) & 0x3F)] + + hexTable[0x80 | (c & 0x3F)]; } return out; diff --git a/package.json b/package.json index 1cb81e5d..422955cd 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "qs", "description": "A querystring parser that supports nesting and arrays, with a depth limit", "homepage": "https://github.com/ljharb/qs", - "version": "6.4.0", + "version": "6.4.1", "repository": { "type": "git", "url": "https://github.com/ljharb/qs.git"