diff --git a/src/urlparser.js b/src/urlparser.js index 487e2ff..3f3631f 100644 --- a/src/urlparser.js +++ b/src/urlparser.js @@ -72,7 +72,7 @@ function Url$parse(str, parseQueryString, hostDenotesSlash) { if (start <= end) { var ch = str.charCodeAt(start); - if (ch === 0x2F /*'/'*/) { + if (ch === 0x2F /*'/'*/ || ch === 0x5C /*'\'*/) { this._parsePath(str, start, end); } else if (ch === 0x3F /*'?'*/) { @@ -484,8 +484,10 @@ Url.prototype._parsePort = function Url$_parsePort(str, start, end) { Url.prototype._parseHost = function Url$_parseHost(str, start, end, slashesDenoteHost) { var hostEndingCharacters = this._hostEndingCharacters; - if (str.charCodeAt(start) === 0x2F /*'/'*/ && - str.charCodeAt(start + 1) === 0x2F /*'/'*/) { + var first = str.charCodeAt(start); + var second = str.charCodeAt(start + 1); + if ((first === 0x2F /*'/'*/ || first === 0x5C /*'\'*/) && + (second === 0x2F /*'/'*/ || second === 0x5C /*'\'*/)) { this.slashes = true; //The string starts with // @@ -677,11 +679,12 @@ Url.prototype._clone = function Url$_clone() { }; Url.prototype._getComponentEscaped = -function Url$_getComponentEscaped(str, start, end) { +function Url$_getComponentEscaped(str, start, end, isAfterHash) { var cur = start; var i = start; var ret = ""; - var autoEscapeMap = this._autoEscapeMap; + var autoEscapeMap = isAfterHash + ? this._afterHashAutoEscapeMap : this._autoEscapeMap; for (; i <= end; ++i) { var ch = str.charCodeAt(i); var escaped = autoEscapeMap[ch]; @@ -727,7 +730,7 @@ function Url$_parsePath(str, start, end) { var path; if (escape) { - path = this._getComponentEscaped(str, pathStart, pathEnd); + path = this._getComponentEscaped(str, pathStart, pathEnd, false); } else { path = str.slice(pathStart, pathEnd + 1); @@ -761,7 +764,7 @@ Url.prototype._parseQuery = function Url$_parseQuery(str, start, end) { var query; if (escape) { - query = this._getComponentEscaped(str, queryStart, queryEnd); + query = this._getComponentEscaped(str, queryStart, queryEnd, false); } else { query = str.slice(queryStart, queryEnd + 1); @@ -774,7 +777,7 @@ Url.prototype._parseHash = function Url$_parseHash(str, start, end) { this.hash = ""; return; } - this.hash = this._getComponentEscaped(str, start, end); + this.hash = this._getComponentEscaped(str, start, end, true); }; Object.defineProperty(Url.prototype, "port", { @@ -979,7 +982,8 @@ for (var i = 0, len = autoEscape.length; i < len; ++i) { } autoEscapeMap[c.charCodeAt(0)] = esc; } - +var afterHashAutoEscapeMap = autoEscapeMap.slice(); +autoEscapeMap[0x5C /*'\'*/] = "/"; var slashProtocols = Url.prototype._slashProtocols = { http: true, @@ -1006,7 +1010,7 @@ Url.prototype._protocolCharacters = makeAsciiTable([ ]); Url.prototype._hostEndingCharacters = makeAsciiTable([ - 0x23 /*'#'*/, 0x3F /*'?'*/, 0x2F /*'/'*/ + 0x23 /*'#'*/, 0x3F /*'?'*/, 0x2F /*'/'*/, 0x5C /*'\'*/ ]); Url.prototype._autoEscapeCharacters = makeAsciiTable( @@ -1019,7 +1023,7 @@ Url.prototype._autoEscapeCharacters = makeAsciiTable( Url.prototype._noPrependSlashHostEnders = makeAsciiTable( [ "<", ">", "'", "`", " ", "\r", - "\n", "\t", "{", "}", "|", "\\", + "\n", "\t", "{", "}", "|", "^", "`", "\"", "%", ";" ].map(function(v) { return v.charCodeAt(0); @@ -1027,6 +1031,7 @@ Url.prototype._noPrependSlashHostEnders = makeAsciiTable( ); Url.prototype._autoEscapeMap = autoEscapeMap; +Url.prototype._afterHashAutoEscapeMap = afterHashAutoEscapeMap; module.exports = Url; diff --git a/test/node.js b/test/node.js index e6860d7..4776de0 100644 --- a/test/node.js +++ b/test/node.js @@ -25,6 +25,28 @@ var url = require('../src/urlparser.js'); // URLs to parse, and expected data // { url : parsed } var parseTests = { + 'http:\\\\evil-phisher\\foo.html#h\\a\\s\\h': { + protocol: 'http:', + slashes: true, + host: 'evil-phisher', + hostname: 'evil-phisher', + pathname: '/foo.html', + path: '/foo.html', + hash: '#h%5Ca%5Cs%5Ch', + href: 'http://evil-phisher/foo.html#h%5Ca%5Cs%5Ch' + }, + + + 'http:\\\\evil-phisher\\foo.html': { + protocol: 'http:', + slashes: true, + host: 'evil-phisher', + hostname: 'evil-phisher', + pathname: '/foo.html', + path: '/foo.html', + href: 'http://evil-phisher/foo.html' + }, + '//some_path' : { 'href': '//some_path', 'pathname': '//some_path', @@ -753,9 +775,9 @@ var parseTests = { 'host': 'x:1', 'port': '1', 'hostname': 'x', - 'pathname': '/%27%20%3C%3E%22%60/%7B%7D%7C%5C%5E~%60/', - 'path': '/%27%20%3C%3E%22%60/%7B%7D%7C%5C%5E~%60/', - 'href': 'http://x:1/%27%20%3C%3E%22%60/%7B%7D%7C%5C%5E~%60/' + 'pathname': '/%27%20%3C%3E%22%60/%7B%7D%7C/%5E~%60/', + 'path': '/%27%20%3C%3E%22%60/%7B%7D%7C/%5E~%60/', + 'href': 'http://x:1/%27%20%3C%3E%22%60/%7B%7D%7C/%5E~%60/' }, 'http://a@b@c/': {