mirror of
https://github.com/nodejs/node.git
synced 2025-05-06 21:35:34 +00:00

Many of the util.is*() methods used to check data types simply compare against a single value or the result of typeof. This commit replaces calls to these methods with equivalent checks. This commit does not touch calls to the more complex methods (isRegExp(), isDate(), etc.). Fixes: https://github.com/iojs/io.js/issues/607 PR-URL: https://github.com/iojs/io.js/pull/647 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
204 lines
4.7 KiB
JavaScript
204 lines
4.7 KiB
JavaScript
// Query String Utilities
|
|
|
|
'use strict';
|
|
|
|
const QueryString = exports;
|
|
|
|
// If obj.hasOwnProperty has been overridden, then calling
|
|
// obj.hasOwnProperty(prop) will break.
|
|
// See: https://github.com/joyent/node/issues/1707
|
|
function hasOwnProperty(obj, prop) {
|
|
return Object.prototype.hasOwnProperty.call(obj, prop);
|
|
}
|
|
|
|
|
|
function charCode(c) {
|
|
return c.charCodeAt(0);
|
|
}
|
|
|
|
|
|
// a safe fast alternative to decodeURIComponent
|
|
QueryString.unescapeBuffer = function(s, decodeSpaces) {
|
|
var out = new Buffer(s.length);
|
|
var state = 'CHAR'; // states: CHAR, HEX0, HEX1
|
|
var n, m, hexchar;
|
|
|
|
for (var inIndex = 0, outIndex = 0; inIndex <= s.length; inIndex++) {
|
|
var c = s.charCodeAt(inIndex);
|
|
switch (state) {
|
|
case 'CHAR':
|
|
switch (c) {
|
|
case charCode('%'):
|
|
n = 0;
|
|
m = 0;
|
|
state = 'HEX0';
|
|
break;
|
|
case charCode('+'):
|
|
if (decodeSpaces) c = charCode(' ');
|
|
// pass thru
|
|
default:
|
|
out[outIndex++] = c;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case 'HEX0':
|
|
state = 'HEX1';
|
|
hexchar = c;
|
|
if (charCode('0') <= c && c <= charCode('9')) {
|
|
n = c - charCode('0');
|
|
} else if (charCode('a') <= c && c <= charCode('f')) {
|
|
n = c - charCode('a') + 10;
|
|
} else if (charCode('A') <= c && c <= charCode('F')) {
|
|
n = c - charCode('A') + 10;
|
|
} else {
|
|
out[outIndex++] = charCode('%');
|
|
out[outIndex++] = c;
|
|
state = 'CHAR';
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case 'HEX1':
|
|
state = 'CHAR';
|
|
if (charCode('0') <= c && c <= charCode('9')) {
|
|
m = c - charCode('0');
|
|
} else if (charCode('a') <= c && c <= charCode('f')) {
|
|
m = c - charCode('a') + 10;
|
|
} else if (charCode('A') <= c && c <= charCode('F')) {
|
|
m = c - charCode('A') + 10;
|
|
} else {
|
|
out[outIndex++] = charCode('%');
|
|
out[outIndex++] = hexchar;
|
|
out[outIndex++] = c;
|
|
break;
|
|
}
|
|
out[outIndex++] = 16 * n + m;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// TODO support returning arbitrary buffers.
|
|
|
|
return out.slice(0, outIndex - 1);
|
|
};
|
|
|
|
|
|
QueryString.unescape = function(s, decodeSpaces) {
|
|
try {
|
|
return decodeURIComponent(s);
|
|
} catch (e) {
|
|
return QueryString.unescapeBuffer(s, decodeSpaces).toString();
|
|
}
|
|
};
|
|
|
|
|
|
QueryString.escape = function(str) {
|
|
return encodeURIComponent(str);
|
|
};
|
|
|
|
var stringifyPrimitive = function(v) {
|
|
let type = typeof v;
|
|
|
|
if (type === 'string')
|
|
return v;
|
|
if (type === 'boolean')
|
|
return v ? 'true' : 'false';
|
|
if (type === 'number')
|
|
return isFinite(v) ? v : '';
|
|
return '';
|
|
};
|
|
|
|
|
|
QueryString.stringify = QueryString.encode = function(obj, sep, eq, options) {
|
|
sep = sep || '&';
|
|
eq = eq || '=';
|
|
|
|
var encode = QueryString.escape;
|
|
if (options && typeof options.encodeURIComponent === 'function') {
|
|
encode = options.encodeURIComponent;
|
|
}
|
|
|
|
if (obj !== null && typeof obj === 'object') {
|
|
var keys = Object.keys(obj);
|
|
var fields = [];
|
|
|
|
for (var i = 0; i < keys.length; i++) {
|
|
var k = keys[i];
|
|
var v = obj[k];
|
|
var ks = encode(stringifyPrimitive(k)) + eq;
|
|
|
|
if (Array.isArray(v)) {
|
|
for (var j = 0; j < v.length; j++)
|
|
fields.push(ks + encode(stringifyPrimitive(v[j])));
|
|
} else {
|
|
fields.push(ks + encode(stringifyPrimitive(v)));
|
|
}
|
|
}
|
|
return fields.join(sep);
|
|
}
|
|
return '';
|
|
};
|
|
|
|
// Parse a key=val string.
|
|
QueryString.parse = QueryString.decode = function(qs, sep, eq, options) {
|
|
sep = sep || '&';
|
|
eq = eq || '=';
|
|
var obj = {};
|
|
|
|
if (typeof qs !== 'string' || qs.length === 0) {
|
|
return obj;
|
|
}
|
|
|
|
var regexp = /\+/g;
|
|
qs = qs.split(sep);
|
|
|
|
var maxKeys = 1000;
|
|
if (options && typeof options.maxKeys === 'number') {
|
|
maxKeys = options.maxKeys;
|
|
}
|
|
|
|
var len = qs.length;
|
|
// maxKeys <= 0 means that we should not limit keys count
|
|
if (maxKeys > 0 && len > maxKeys) {
|
|
len = maxKeys;
|
|
}
|
|
|
|
var decode = QueryString.unescape;
|
|
if (options && typeof options.decodeURIComponent === 'function') {
|
|
decode = options.decodeURIComponent;
|
|
}
|
|
|
|
for (var i = 0; i < len; ++i) {
|
|
var x = qs[i].replace(regexp, '%20'),
|
|
idx = x.indexOf(eq),
|
|
kstr, vstr, k, v;
|
|
|
|
if (idx >= 0) {
|
|
kstr = x.substr(0, idx);
|
|
vstr = x.substr(idx + 1);
|
|
} else {
|
|
kstr = x;
|
|
vstr = '';
|
|
}
|
|
|
|
try {
|
|
k = decode(kstr);
|
|
v = decode(vstr);
|
|
} catch (e) {
|
|
k = QueryString.unescape(kstr, true);
|
|
v = QueryString.unescape(vstr, true);
|
|
}
|
|
|
|
if (!hasOwnProperty(obj, k)) {
|
|
obj[k] = v;
|
|
} else if (Array.isArray(obj[k])) {
|
|
obj[k].push(v);
|
|
} else {
|
|
obj[k] = [obj[k], v];
|
|
}
|
|
}
|
|
|
|
return obj;
|
|
};
|