diff --git a/src/URI.js b/src/URI.js index f63ad6c6..6f7fd572 100644 --- a/src/URI.js +++ b/src/URI.js @@ -240,16 +240,10 @@ ws: '80', wss: '443' }; - // list of protocols which always require a hostname - URI.hostProtocols = [ - 'http', - 'https' - ]; - // allowed hostname characters according to RFC 3986 // ALPHA DIGIT "-" "." "_" "~" "!" "$" "&" "'" "(" ")" "*" "+" "," ";" "=" %encoded // I've never seen a (non-IDN) hostname other than: ALPHA DIGIT . - - URI.invalid_hostname_characters = /[^a-zA-Z0-9\.\-:]/; + URI.invalid_hostname_characters = /[^a-zA-Z0-9\.-]/; // map DOM Elements to their URI attribute URI.domAttributes = { 'a': 'href', @@ -581,12 +575,6 @@ string = '/' + string; } - URI.ensureValidHostname(parts.hostname, parts.protocol); - - if (parts.port) { - URI.ensureValidPort(parts.port); - } - return string.substring(pos) || '/'; }; URI.parseAuthority = function(string, parts) { @@ -1027,44 +1015,22 @@ return string; }; - URI.ensureValidHostname = function(v, protocol) { + URI.ensureValidHostname = function(v) { // Theoretically URIs allow percent-encoding in Hostnames (according to RFC 3986) // they are not part of DNS and therefore ignored by URI.js - var hasHostname = !!v; // not null and not an empty string - var hasProtocol = !!protocol; - var rejectEmptyHostname = false; - - if (hasProtocol) { - rejectEmptyHostname = arrayContains(URI.hostProtocols, protocol); - } - - if (rejectEmptyHostname && !hasHostname) { - throw new TypeError('Hostname cannot be empty, if protocol is ' + protocol); - } else if (v && v.match(URI.invalid_hostname_characters)) { + if (v.match(URI.invalid_hostname_characters)) { // test punycode if (!punycode) { throw new TypeError('Hostname "' + v + '" contains characters other than [A-Z0-9.-] and Punycode.js is not available'); } + if (punycode.toASCII(v).match(URI.invalid_hostname_characters)) { - throw new TypeError('Hostname "' + v + '" contains characters other than [A-Z0-9.:-]'); + throw new TypeError('Hostname "' + v + '" contains characters other than [A-Z0-9.-]'); } } }; - URI.ensureValidPort = function (v) { - if (!v) { - return; - } - - var port = Number(v); - if (Number.isInteger(port) && (port > 0) && (port < 65536)) { - return; - } - - throw new TypeError('Port "' + v + '" is not a valid port'); - }; - // noConflict URI.noConflict = function(removeAll) { if (removeAll) { @@ -1322,7 +1288,9 @@ v = v.substring(1); } - URI.ensureValidPort(v); + if (v.match(/[^0-9]/)) { + throw new TypeError('Port "' + v + '" contains characters other than [0-9]'); + } } } return _port.call(this, v, build); @@ -1340,7 +1308,6 @@ } v = x.hostname; - URI.ensureValidHostname(v, this._parts.protocol); } return _hostname.call(this, v, build); }; @@ -1459,12 +1426,8 @@ v += '.'; } - if (v.indexOf(':') !== -1) { - throw new TypeError('Domains cannot contain colons'); - } - if (v) { - URI.ensureValidHostname(v, this._parts.protocol); + URI.ensureValidHostname(v); } this._parts.hostname = this._parts.hostname.replace(replace, v); @@ -1503,11 +1466,7 @@ throw new TypeError('cannot set domain empty'); } - if (v.indexOf(':') !== -1) { - throw new TypeError('Domains cannot contain colons'); - } - - URI.ensureValidHostname(v, this._parts.protocol); + URI.ensureValidHostname(v); if (!this._parts.hostname || this.is('IP')) { this._parts.hostname = v; diff --git a/test/test.js b/test/test.js index 8ebf8623..1cc2ce5d 100644 --- a/test/test.js +++ b/test/test.js @@ -124,26 +124,6 @@ ok(u instanceof URI, 'instanceof URI'); ok(u._parts.hostname !== undefined, 'host undefined'); }); - test('function URI(string) with invalid port "port" throws', function () { - raises(function () { - new URI('http://example.org:port'); - }, TypeError, "throws TypeError"); - }); - test('function URI(string) with invalid port "0" throws', function () { - raises(function () { - new URI('http://example.org:0'); - }, TypeError, "throws TypeError"); - }); - test('function URI(string) with invalid port "65536" throws', function () { - raises(function () { - new URI('http://example.org:65536'); - }, TypeError, "throws TypeError"); - }); - test('function URI(string) with protocol and without hostname should throw', function () { - raises(function () { - new URI('http://'); - }, TypeError, "throws TypeError"); - }); test('new URI(string, string)', function() { // see http://dvcs.w3.org/hg/url/raw-file/tip/Overview.html#constructor var u = new URI('../foobar.html', 'http://example.org/hello/world.html'); @@ -243,16 +223,13 @@ equal(u.hostname(), 'abc.foobar.lala', 'hostname changed'); equal(u+'', 'http://abc.foobar.lala/foo.html', 'hostname changed url'); + u.hostname(''); + equal(u.hostname(), '', 'hostname removed'); + equal(u+'', 'http:///foo.html', 'hostname removed url'); + raises(function() { u.hostname('foo\\bar.com'); }, TypeError, 'Failing backslash detection in hostname'); - - raises(function() { - u.hostname(''); - }, TypeError, "Trying to set an empty hostname with http(s) protocol throws a TypeError"); - raises(function() { - u.hostname(null); - }, TypeError, "Trying to set hostname to null with http(s) protocol throws a TypeError"); }); test('port', function() { var u = new URI('http://example.org/foo.html'); @@ -1361,6 +1338,11 @@ url: 'file:///C:/skyclan/snipkit', base: 'http://example.com/foo/bar', result: 'file:///C:/skyclan/snipkit' + }, { + name: 'absolute passthru - generic empty-hostname - urljoin (#328)', + url: 'http:///foo', + base: 'http://example.com/foo/bar', + result: 'http:///foo' }, { name: 'file paths - urljoin', url: 'anotherFile',