diff --git a/index.js b/index.js index f424acc..73b53f6 100644 --- a/index.js +++ b/index.js @@ -2,8 +2,8 @@ var required = require('requires-port') , qs = require('querystringify') - , slashes = /^[A-Za-z][A-Za-z0-9+-.]*:[\\/]+/ - , protocolre = /^([a-z][a-z0-9.+-]*:)?([\\/]{1,})?([\S\s]*)/i + , slashes = /^[A-Za-z][A-Za-z0-9+-.]*:\/\// + , protocolre = /^([a-z][a-z0-9.+-]*:)?(\/\/)?([\\/]+)?([\S\s]*)/i , whitespace = '[\\x09\\x0A\\x0B\\x0C\\x0D\\x20\\xA0\\u1680\\u180E\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200A\\u202F\\u205F\\u3000\\u2028\\u2029\\uFEFF]' , left = new RegExp('^'+ whitespace +'+'); @@ -138,26 +138,46 @@ function extractProtocol(address, location) { var match = protocolre.exec(address); var protocol = match[1] ? match[1].toLowerCase() : ''; - var rest = match[2] ? match[2] + match[3] : match[3]; - var slashes = !!(match[2] && match[2].length >= 2); + var forwardSlashes = !!match[2]; + var otherSlashes = !!match[3]; + var slashesCount = 0; + var rest; + + if (forwardSlashes) { + if (otherSlashes) { + rest = match[2] + match[3] + match[4]; + slashesCount = match[2].length + match[3].length; + } else { + rest = match[2] + match[4]; + slashesCount = match[2].length; + } + } else { + if (otherSlashes) { + rest = match[3] + match[4]; + slashesCount = match[3].length; + } else { + rest = match[4] + } + } if (protocol === 'file:') { - if (slashes) { + if (slashesCount >= 2) { rest = rest.slice(2); } } else if (isSpecial(protocol)) { - rest = match[3]; + rest = match[4]; } else if (protocol) { - if (rest.indexOf('//') === 0) { + if (forwardSlashes) { rest = rest.slice(2); } - } else if (slashes && location.hostname) { - rest = match[3]; + } else if (slashesCount >= 2 && location.hostname) { + rest = match[4]; } return { protocol: protocol, - slashes: slashes, + slashes: forwardSlashes || isSpecial(protocol), + slashesCount: slashesCount, rest: rest }; } @@ -260,7 +280,7 @@ function Url(address, location, parser) { // if ( url.protocol === 'file:' || - (!extracted.slashes && !isSpecial(extracted.protocol)) + (extracted.slashesCount < 2 && !isSpecial(extracted.protocol)) ) { instructions[3] = [/(.*)/, 'pathname']; } @@ -472,7 +492,7 @@ function toString(stringify) { if (protocol && protocol.charAt(protocol.length - 1) !== ':') protocol += ':'; - var result = protocol + (url.slashes || url.protocol === 'file:' ? '//' : ''); + var result = protocol + (url.slashes || isSpecial(url.protocol) ? '//' : ''); if (url.username) { result += url.username; diff --git a/test/test.js b/test/test.js index 9a84fba..71cc473 100644 --- a/test/test.js +++ b/test/test.js @@ -71,7 +71,8 @@ describe('url-parse', function () { assume(parse.extractProtocol('http://example.com')).eql({ slashes: true, protocol: 'http:', - rest: 'example.com' + rest: 'example.com', + slashesCount: 2 }); }); @@ -79,7 +80,8 @@ describe('url-parse', function () { assume(parse.extractProtocol('')).eql({ slashes: false, protocol: '', - rest: '' + rest: '', + slashesCount: 0 }); }); @@ -87,13 +89,15 @@ describe('url-parse', function () { assume(parse.extractProtocol('/foo')).eql({ slashes: false, protocol: '', - rest: '/foo' + rest: '/foo', + slashesCount: 1 }); assume(parse.extractProtocol('//foo/bar')).eql({ slashes: true, protocol: '', - rest: '//foo/bar' + rest: '//foo/bar', + slashesCount: 2 }); }); @@ -103,7 +107,8 @@ describe('url-parse', function () { assume(parse.extractProtocol(input)).eql({ slashes: false, protocol: '', - rest: input + rest: input, + slashesCount: 0 }); }); @@ -111,7 +116,8 @@ describe('url-parse', function () { assume(parse.extractProtocol(' javascript://foo')).eql({ slashes: true, protocol: 'javascript:', - rest: 'foo' + rest: 'foo', + slashesCount: 2 }); }); }); @@ -281,6 +287,12 @@ describe('url-parse', function () { assume(parsed.host).equals('what-is-up.com'); assume(parsed.href).equals('http://what-is-up.com/'); + + url = '\\\\\\\\what-is-up.com' + parsed = parse(url, parse('http://google.com')); + + assume(parsed.host).equals('what-is-up.com'); + assume(parsed.href).equals('http://what-is-up.com/'); }); it('ignores slashes after the protocol for special URLs', function () { @@ -290,32 +302,44 @@ describe('url-parse', function () { assume(parsed.host).equals('github.com'); assume(parsed.hostname).equals('github.com'); assume(parsed.pathname).equals('/foo/bar'); + assume(parsed.slashes).is.true(); + assume(parsed.href).equals('https://github.com/foo/bar'); url = 'https:/\\/\\/\\github.com/foo/bar'; parsed = parse(url); assume(parsed.host).equals('github.com'); assume(parsed.hostname).equals('github.com'); assume(parsed.pathname).equals('/foo/bar'); + assume(parsed.slashes).is.true(); + assume(parsed.href).equals('https://github.com/foo/bar'); url = 'https:/github.com/foo/bar'; parsed = parse(url); assume(parsed.host).equals('github.com'); assume(parsed.pathname).equals('/foo/bar'); + assume(parsed.slashes).is.true(); + assume(parsed.href).equals('https://github.com/foo/bar'); url = 'https:\\github.com/foo/bar'; parsed = parse(url); assume(parsed.host).equals('github.com'); assume(parsed.pathname).equals('/foo/bar'); + assume(parsed.slashes).is.true(); + assume(parsed.href).equals('https://github.com/foo/bar'); url = 'https:github.com/foo/bar'; parsed = parse(url); assume(parsed.host).equals('github.com'); assume(parsed.pathname).equals('/foo/bar'); + assume(parsed.slashes).is.true(); + assume(parsed.href).equals('https://github.com/foo/bar'); url = 'https:github.com/foo/bar'; parsed = parse(url); assume(parsed.host).equals('github.com'); assume(parsed.pathname).equals('/foo/bar'); + assume(parsed.slashes).is.true(); + assume(parsed.href).equals('https://github.com/foo/bar'); }); it('handles slashes after the protocol for non special URLs', function () { @@ -325,24 +349,28 @@ describe('url-parse', function () { assume(parsed.hostname).equals(''); assume(parsed.pathname).equals('example.com'); assume(parsed.href).equals('foo:example.com'); + assume(parsed.slashes).is.false(); url = 'foo:/example.com'; parsed = parse(url); assume(parsed.hostname).equals(''); assume(parsed.pathname).equals('/example.com'); assume(parsed.href).equals('foo:/example.com'); + assume(parsed.slashes).is.false(); url = 'foo://example.com'; parsed = parse(url); assume(parsed.hostname).equals('example.com'); assume(parsed.pathname).equals('/'); assume(parsed.href).equals('foo://example.com/'); + assume(parsed.slashes).is.true(); url = 'foo:///example.com'; parsed = parse(url); assume(parsed.hostname).equals(''); assume(parsed.pathname).equals('/example.com'); assume(parsed.href).equals('foo:///example.com'); + assume(parsed.slashes).is.true(); }) describe('origin', function () {