119 lines
3.3 KiB
JavaScript
119 lines
3.3 KiB
JavaScript
/**
|
|
* This modules provides simple percent (URI) encoding.
|
|
*
|
|
* @note Safety check for input types is not done intentionally as these
|
|
* functions are invoked in the hot code path.
|
|
*
|
|
* @private
|
|
* @module postman-url-encoder/encoder/percent-encode
|
|
*/
|
|
|
|
/**
|
|
* @fileoverview
|
|
* A percent-encoding mechanism is used to represent a data octet in a component
|
|
* when that octet's corresponding character is outside the allowed set or is
|
|
* being used as a delimiter of, or within, the component.
|
|
* A percent-encoded octet is encoded as a character triplet, consisting of the
|
|
* percent character "%" followed by the two hexadecimal digits representing
|
|
* that octet's numeric value.
|
|
*
|
|
* For example, "%20" is the percent-encoding for the binary octet "00100000"
|
|
* (ABNF: %x20), which in US-ASCII corresponds to the space character (SP).
|
|
*
|
|
* @see {@link https://en.wikipedia.org/wiki/Percent-encoding}
|
|
* @see {@link https://tools.ietf.org/html/rfc3986#section-2.1}
|
|
*/
|
|
|
|
const E = '',
|
|
ZERO = '0',
|
|
PERCENT = '%';
|
|
|
|
/**
|
|
* Checks if character with given code is valid hexadecimal digit or not.
|
|
*
|
|
* @private
|
|
* @param {Number} byte Byte
|
|
* @returns {Boolean}
|
|
*/
|
|
function isPreEncodedCharacter (byte) {
|
|
return (byte >= 0x30 && byte <= 0x39) || // 0-9
|
|
(byte >= 0x41 && byte <= 0x46) || // A-F
|
|
(byte >= 0x61 && byte <= 0x66); // a-f
|
|
}
|
|
|
|
/**
|
|
* Checks if character at given index in the buffer is already percent encoded or not.
|
|
*
|
|
* @private
|
|
* @param {Buffer} buffer Buffer to check the character from
|
|
* @param {Number} i Index of the character to check
|
|
* @returns {Boolean} true if the character is encoded, false otherwise
|
|
*/
|
|
function isPreEncoded (buffer, i) {
|
|
// if it is % check next two bytes for percent encode characters
|
|
// looking for pattern %00 - %FF
|
|
return buffer[i] === 0x25 && // %
|
|
isPreEncodedCharacter(buffer[i + 1]) &&
|
|
isPreEncodedCharacter(buffer[i + 2]);
|
|
}
|
|
|
|
/**
|
|
* Percent encode a character with given code.
|
|
*
|
|
* @example
|
|
* // returns '%20'
|
|
* encodeCharCode(32)
|
|
*
|
|
* @param {Number} code Character code
|
|
* @returns {String} Percent-encoded character
|
|
*/
|
|
function encodeCharCode (code) {
|
|
let hex = code.toString(16).toUpperCase();
|
|
|
|
(hex.length === 1) && (hex = ZERO + hex);
|
|
|
|
return PERCENT + hex;
|
|
}
|
|
|
|
/**
|
|
* Percent-encode the given string with the given {@link EncodeSet}.
|
|
*
|
|
* @example
|
|
* // returns 'foo%40bar'
|
|
* encode('foo@bar', new EncodeSet(['@']))
|
|
*
|
|
* @param {String} value String to percent-encode
|
|
* @param {EncodeSet} encodeSet EncodeSet to use for encoding
|
|
* @returns {String} Percent-encoded string
|
|
*/
|
|
function encode (value, encodeSet) {
|
|
let i,
|
|
ii,
|
|
charCode,
|
|
encoded = E,
|
|
buffer = Buffer.from(value);
|
|
|
|
for (i = 0, ii = buffer.length; i < ii; ++i) {
|
|
// avoid double encoding
|
|
if (i < ii - 2 && isPreEncoded(buffer, i)) {
|
|
encoded += PERCENT + String.fromCharCode(buffer[++i], buffer[++i]);
|
|
continue;
|
|
}
|
|
|
|
charCode = buffer[i];
|
|
|
|
encoded += encodeSet.has(charCode) ?
|
|
// encode if char code present in encodeSet
|
|
encodeCharCode(charCode) :
|
|
// or, append string from char code
|
|
String.fromCharCode(charCode);
|
|
}
|
|
|
|
return encoded;
|
|
}
|
|
|
|
module.exports = {
|
|
encode,
|
|
encodeCharCode
|
|
};
|