/** * 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 };