Skip to content

Commit

Permalink
[fix] Ignore slashes after the protocol for special URLs
Browse files Browse the repository at this point in the history
Fixes #205
Fixes #206
  • Loading branch information
lpinca committed Jul 24, 2021
1 parent ee22050 commit 81ab967
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 10 deletions.
51 changes: 44 additions & 7 deletions index.js
Expand Up @@ -98,6 +98,24 @@ function lolcation(loc) {
return finaldestination;
}

/**
* Check whether a protocol scheme is special.
*
* @param {String} The protocol scheme of the URL
* @return {Boolean} `true` if the protocol scheme is special, else `false`
* @private
*/
function isSpecial(scheme) {
return (
scheme === 'file:' ||
scheme === 'ftp:' ||
scheme === 'http:' ||
scheme === 'https:' ||
scheme === 'ws:' ||
scheme === 'wss:'
);
}

/**
* @typedef ProtocolExtract
* @type Object
Expand All @@ -110,16 +128,32 @@ function lolcation(loc) {
* Extract protocol information from a URL with/without double slash ("//").
*
* @param {String} address URL we want to extract from.
* @param {Object} location
* @return {ProtocolExtract} Extracted information.
* @private
*/
function extractProtocol(address) {
function extractProtocol(address, location) {
address = trimLeft(address);
location = location || {};

var match = protocolre.exec(address)
, protocol = match[1] ? match[1].toLowerCase() : ''
, slashes = !!(match[2] && match[2].length >= 2)
, rest = match[2] && match[2].length === 1 ? '/' + match[3] : match[3];
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);

if (protocol === 'file:') {
if (slashes) {
rest = rest.slice(2);
}
} else if (isSpecial(protocol)) {
rest = match[3];
} else if (protocol) {
if (rest.indexOf('//') === 0) {
rest = rest.slice(2);
}
} else if (slashes && location.hostname) {
rest = match[3];
}

return {
protocol: protocol,
Expand Down Expand Up @@ -214,7 +248,7 @@ function Url(address, location, parser) {
//
// Extract protocol information before running the instructions.
//
extracted = extractProtocol(address || '');
extracted = extractProtocol(address || '', location);
relative = !extracted.protocol && !extracted.slashes;
url.slashes = extracted.slashes || relative && location.slashes;
url.protocol = extracted.protocol || location.protocol || '';
Expand All @@ -224,7 +258,10 @@ function Url(address, location, parser) {
// When the authority component is absent the URL starts with a path
// component.
//
if (!extracted.slashes || url.protocol === 'file:') {
if (
url.protocol === 'file:' ||
(!extracted.slashes && !isSpecial(extracted.protocol))
) {
instructions[3] = [/(.*)/, 'pathname'];
}

Expand Down
66 changes: 63 additions & 3 deletions test/test.js
Expand Up @@ -93,7 +93,7 @@ describe('url-parse', function () {
assume(parse.extractProtocol('//foo/bar')).eql({
slashes: true,
protocol: '',
rest: 'foo/bar'
rest: '//foo/bar'
});
});

Expand Down Expand Up @@ -283,7 +283,7 @@ describe('url-parse', function () {
assume(parsed.href).equals('http://what-is-up.com/');
});

it('does not see a slash after the protocol as path', function () {
it('ignores slashes after the protocol for special URLs', function () {
var url = 'https:\\/github.com/foo/bar'
, parsed = parse(url);

Expand All @@ -292,11 +292,59 @@ describe('url-parse', function () {
assume(parsed.pathname).equals('/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');

url = 'https:/github.com/foo/bar';
parsed = parse(url);
assume(parsed.host).equals('github.com');
assume(parsed.pathname).equals('/foo/bar');

url = 'https:\\github.com/foo/bar';
parsed = parse(url);
assume(parsed.host).equals('github.com');
assume(parsed.pathname).equals('/foo/bar');

url = 'https:github.com/foo/bar';
parsed = parse(url);
assume(parsed.host).equals('github.com');
assume(parsed.pathname).equals('/foo/bar');

url = 'https:github.com/foo/bar';
parsed = parse(url);
assume(parsed.host).equals('github.com');
assume(parsed.pathname).equals('/foo/bar');
});

it('handles slashes after the protocol for non special URLs', function () {
var url = 'foo:example.com'
, parsed = parse(url);

assume(parsed.hostname).equals('');
assume(parsed.pathname).equals('example.com');
assume(parsed.href).equals('foo:example.com');

url = 'foo:/example.com';
parsed = parse(url);
assume(parsed.hostname).equals('');
assume(parsed.pathname).equals('/example.com');
assume(parsed.href).equals('foo:/example.com');

url = 'foo://example.com';
parsed = parse(url);
assume(parsed.hostname).equals('example.com');
assume(parsed.pathname).equals('/');
assume(parsed.href).equals('foo://example.com/');

url = 'foo:///example.com';
parsed = parse(url);
assume(parsed.hostname).equals('');
assume(parsed.pathname).equals('/example.com');
assume(parsed.href).equals('foo:///example.com');
})

describe('origin', function () {
it('generates an origin property', function () {
var url = 'http://google.com:80/pathname'
Expand Down Expand Up @@ -440,7 +488,7 @@ describe('url-parse', function () {
});

it('handles the file: protocol', function () {
var slashes = ['', '/', '//', '///', '////', '/////'];
var slashes = ['', '/', '//', '///'];
var data;
var url;

Expand All @@ -451,6 +499,18 @@ describe('url-parse', function () {
assume(data.href).equals('file:///');
}

url = 'file:////';
data = parse(url);
assume(data.protocol).equals('file:');
assume(data.pathname).equals('//');
assume(data.href).equals(url);

url = 'file://///';
data = parse(url);
assume(data.protocol).equals('file:');
assume(data.pathname).equals('///');
assume(data.href).equals(url);

url = 'file:///Users/foo/BAR/baz.pdf';
data = parse(url);
assume(data.protocol).equals('file:');
Expand Down

0 comments on commit 81ab967

Please sign in to comment.