diff --git a/lib/internal/constants.js b/lib/internal/constants.js index f0ffec7a447529..c9a5bea833306f 100644 --- a/lib/internal/constants.js +++ b/lib/internal/constants.js @@ -8,9 +8,39 @@ module.exports = { CHAR_LOWERCASE_Z: 122, /*z*/ // Non-alphabetic chars. - CHAR_DOT: 46, /*.*/ - CHAR_FORWARD_SLASH: 47, /*/*/ - CHAR_BACKWARD_SLASH: 92, /*\*/ - CHAR_COLON: 58, /*:*/ - CHAR_QUESTION_MARK: 63, /*?*/ + CHAR_DOT: 46, /* . */ + CHAR_FORWARD_SLASH: 47, /* / */ + CHAR_BACKWARD_SLASH: 92, /* \ */ + CHAR_VERTICAL_LINE: 124, /* | */ + CHAR_COLON: 58, /* : */ + CHAR_QUESTION_MARK: 63, /* ? */ + CHAR_UNDERSCORE: 95, /* _ */ + CHAR_LINE_FEED: 10, /* \n */ + CHAR_CARRIAGE_RETURN: 13, /* \r */ + CHAR_TAB: 9, /* \t */ + CHAR_FORM_FEED: 12, /* \f */ + CHAR_EXCLAMATION_MARK: 33, /* ! */ + CHAR_HASH: 35, /* # */ + CHAR_SPACE: 32, /* */ + CHAR_NO_BREAK_SPACE: 160, /* \u00A0 */ + CHAR_ZERO_WIDTH_NOBREAK_SPACE: 65279, /* \uFEFF */ + CHAR_LEFT_SQUARE_BRACKET: 91, /* [ */ + CHAR_RIGHT_SQUARE_BRACKET: 93, /* ] */ + CHAR_LEFT_ANGLE_BRACKET: 60, /* < */ + CHAR_RIGHT_ANGLE_BRACKET: 62, /* > */ + CHAR_LEFT_CURLY_BRACKET: 123, /* { */ + CHAR_RIGHT_CURLY_BRACKET: 125, /* } */ + CHAR_HYPHEN_MINUS: 45, /* - */ + CHAR_PLUS: 43, /* + */ + CHAR_DOUBLE_QUOTE: 34, /* " */ + CHAR_SINGLE_QUOTE: 39, /* ' */ + CHAR_PERCENT: 37, /* % */ + CHAR_SEMICOLON: 59, /* ; */ + CHAR_CIRCUMFLEX_ACCENT: 94, /* ^ */ + CHAR_GRAVE_ACCENT: 96, /* ` */ + CHAR_AT: 64, /* @ */ + + // Digits + CHAR_0: 48, /* 0 */ + CHAR_9: 57, /* 9 */ }; diff --git a/lib/url.js b/lib/url.js index ab4b2b4647edd2..df9d917a479aba 100644 --- a/lib/url.js +++ b/lib/url.js @@ -92,6 +92,43 @@ const slashedProtocol = { 'file:': true }; const querystring = require('querystring'); +const { + CHAR_SPACE, + CHAR_TAB, + CHAR_CARRIAGE_RETURN, + CHAR_LINE_FEED, + CHAR_FORM_FEED, + CHAR_NO_BREAK_SPACE, + CHAR_ZERO_WIDTH_NOBREAK_SPACE, + CHAR_HASH, + CHAR_FORWARD_SLASH, + CHAR_LEFT_SQUARE_BRACKET, + CHAR_RIGHT_SQUARE_BRACKET, + CHAR_LEFT_ANGLE_BRACKET, + CHAR_RIGHT_ANGLE_BRACKET, + CHAR_LEFT_CURLY_BRACKET, + CHAR_RIGHT_CURLY_BRACKET, + CHAR_QUESTION_MARK, + CHAR_LOWERCASE_A, + CHAR_LOWERCASE_Z, + CHAR_UPPERCASE_A, + CHAR_UPPERCASE_Z, + CHAR_DOT, + CHAR_0, + CHAR_9, + CHAR_HYPHEN_MINUS, + CHAR_PLUS, + CHAR_UNDERSCORE, + CHAR_DOUBLE_QUOTE, + CHAR_SINGLE_QUOTE, + CHAR_PERCENT, + CHAR_SEMICOLON, + CHAR_BACKWARD_SLASH, + CHAR_CIRCUMFLEX_ACCENT, + CHAR_GRAVE_ACCENT, + CHAR_VERTICAL_LINE, + CHAR_AT, +} = require('internal/constants'); function urlParse(url, parseQueryString, slashesDenoteHost) { if (url instanceof Url) return url; @@ -119,13 +156,13 @@ Url.prototype.parse = function parse(url, parseQueryString, slashesDenoteHost) { const code = url.charCodeAt(i); // Find first and last non-whitespace characters for trimming - const isWs = code === 32/* */ || - code === 9/*\t*/ || - code === 13/*\r*/ || - code === 10/*\n*/ || - code === 12/*\f*/ || - code === 160/*\u00A0*/ || - code === 65279/*\uFEFF*/; + const isWs = code === CHAR_SPACE || + code === CHAR_TAB || + code === CHAR_CARRIAGE_RETURN || + code === CHAR_LINE_FEED || + code === CHAR_FORM_FEED || + code === CHAR_NO_BREAK_SPACE || + code === CHAR_ZERO_WIDTH_NOBREAK_SPACE; if (start === -1) { if (isWs) continue; @@ -143,20 +180,20 @@ Url.prototype.parse = function parse(url, parseQueryString, slashesDenoteHost) { // Only convert backslashes while we haven't seen a split character if (!split) { switch (code) { - case 35: // '#' + case CHAR_HASH: hasHash = true; // Fall through - case 63: // '?' + case CHAR_QUESTION_MARK: split = true; break; - case 92: // '\\' + case CHAR_BACKWARD_SLASH: if (i - lastPos > 0) rest += url.slice(lastPos, i); rest += '/'; lastPos = i + 1; break; } - } else if (!hasHash && code === 35/*#*/) { + } else if (!hasHash && code === CHAR_HASH) { hasHash = true; } } @@ -218,8 +255,8 @@ Url.prototype.parse = function parse(url, parseQueryString, slashesDenoteHost) { // resolution will treat //foo/bar as host=foo,path=bar because that's // how the browser resolves relative URLs. if (slashesDenoteHost || proto || hostPattern.test(rest)) { - var slashes = rest.charCodeAt(0) === 47/*/*/ && - rest.charCodeAt(1) === 47/*/*/; + var slashes = rest.charCodeAt(0) === CHAR_FORWARD_SLASH && + rest.charCodeAt(1) === CHAR_FORWARD_SLASH; if (slashes && !(proto && hostlessProtocol[proto])) { rest = rest.slice(2); this.slashes = true; @@ -249,35 +286,35 @@ Url.prototype.parse = function parse(url, parseQueryString, slashesDenoteHost) { var nonHost = -1; for (i = 0; i < rest.length; ++i) { switch (rest.charCodeAt(i)) { - case 9: // '\t' - case 10: // '\n' - case 13: // '\r' - case 32: // ' ' - case 34: // '"' - case 37: // '%' - case 39: // '\'' - case 59: // ';' - case 60: // '<' - case 62: // '>' - case 92: // '\\' - case 94: // '^' - case 96: // '`' - case 123: // '{' - case 124: // '|' - case 125: // '}' + case CHAR_TAB: + case CHAR_LINE_FEED: + case CHAR_CARRIAGE_RETURN: + case CHAR_SPACE: + case CHAR_DOUBLE_QUOTE: + case CHAR_PERCENT: + case CHAR_SINGLE_QUOTE: + case CHAR_SEMICOLON: + case CHAR_LEFT_ANGLE_BRACKET: + case CHAR_RIGHT_ANGLE_BRACKET: + case CHAR_BACKWARD_SLASH: + case CHAR_CIRCUMFLEX_ACCENT: + case CHAR_GRAVE_ACCENT: + case CHAR_LEFT_CURLY_BRACKET: + case CHAR_VERTICAL_LINE: + case CHAR_RIGHT_CURLY_BRACKET: // Characters that are never ever allowed in a hostname from RFC 2396 if (nonHost === -1) nonHost = i; break; - case 35: // '#' - case 47: // '/' - case 63: // '?' + case CHAR_HASH: + case CHAR_FORWARD_SLASH: + case CHAR_QUESTION_MARK: // Find the first instance of any host-ending characters if (nonHost === -1) nonHost = i; hostEnd = i; break; - case 64: // '@' + case CHAR_AT: // At this point, either we have an explicit point where the // auth portion cannot go past, or the last @ char is the decider. atSign = i; @@ -312,8 +349,8 @@ Url.prototype.parse = function parse(url, parseQueryString, slashesDenoteHost) { // if hostname begins with [ and ends with ] // assume that it's an IPv6 address. - var ipv6Hostname = hostname.charCodeAt(0) === 91/*[*/ && - hostname.charCodeAt(hostname.length - 1) === 93/*]*/; + var ipv6Hostname = hostname.charCodeAt(0) === CHAR_LEFT_SQUARE_BRACKET && + hostname.charCodeAt(hostname.length - 1) === CHAR_RIGHT_SQUARE_BRACKET; // validate a little. if (!ipv6Hostname) { @@ -367,11 +404,11 @@ Url.prototype.parse = function parse(url, parseQueryString, slashesDenoteHost) { var hashIdx = -1; for (i = 0; i < rest.length; ++i) { const code = rest.charCodeAt(i); - if (code === 35/*#*/) { + if (code === CHAR_HASH) { this.hash = rest.slice(i); hashIdx = i; break; - } else if (code === 63/*?*/ && questionIdx === -1) { + } else if (code === CHAR_QUESTION_MARK && questionIdx === -1) { questionIdx = i; } } @@ -422,13 +459,13 @@ Url.prototype.parse = function parse(url, parseQueryString, slashesDenoteHost) { function validateHostname(self, rest, hostname) { for (var i = 0; i < hostname.length; ++i) { const code = hostname.charCodeAt(i); - const isValid = (code >= 97/*a*/ && code <= 122/*z*/) || - code === 46/*.*/ || - (code >= 65/*A*/ && code <= 90/*Z*/) || - (code >= 48/*0*/ && code <= 57/*9*/) || - code === 45/*-*/ || - code === 43/*+*/ || - code === 95/*_*/ || + const isValid = (code >= CHAR_LOWERCASE_A && code <= CHAR_LOWERCASE_Z) || + code === CHAR_DOT || + (code >= CHAR_UPPERCASE_A && code <= CHAR_UPPERCASE_Z) || + (code >= CHAR_0 && code <= CHAR_9) || + code === CHAR_HYPHEN_MINUS || + code === CHAR_PLUS || + code === CHAR_UNDERSCORE || code > 127; // Invalid host character @@ -542,13 +579,13 @@ Url.prototype.format = function format() { var lastPos = 0; for (var i = 0; i < pathname.length; ++i) { switch (pathname.charCodeAt(i)) { - case 35: // '#' + case CHAR_HASH: if (i - lastPos > 0) newPathname += pathname.slice(lastPos, i); newPathname += '%23'; lastPos = i + 1; break; - case 63: // '?' + case CHAR_QUESTION_MARK: if (i - lastPos > 0) newPathname += pathname.slice(lastPos, i); newPathname += '%3F'; @@ -567,7 +604,7 @@ Url.prototype.format = function format() { // unless they had them to begin with. if (this.slashes || slashedProtocol[protocol]) { if (this.slashes || host) { - if (pathname && pathname.charCodeAt(0) !== 47/*/*/) + if (pathname && pathname.charCodeAt(0) !== CHAR_FORWARD_SLASH) pathname = '/' + pathname; host = '//' + host; } else if (protocol.length >= 4 && @@ -581,8 +618,10 @@ Url.prototype.format = function format() { search = search.replace(/#/g, '%23'); - if (hash && hash.charCodeAt(0) !== 35/*#*/) hash = '#' + hash; - if (search && search.charCodeAt(0) !== 63/*?*/) search = '?' + search; + if (hash && hash.charCodeAt(0) !== CHAR_HASH) + hash = '#' + hash; + if (search && search.charCodeAt(0) !== CHAR_QUESTION_MARK) + search = '?' + search; return protocol + host + pathname + search + hash; };