Skip to content

Commit 81ab967

Browse files
committed
[fix] Ignore slashes after the protocol for special URLs
Fixes #205 Fixes #206
1 parent ee22050 commit 81ab967

File tree

2 files changed

+107
-10
lines changed

2 files changed

+107
-10
lines changed

index.js

+44-7
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,24 @@ function lolcation(loc) {
9898
return finaldestination;
9999
}
100100

101+
/**
102+
* Check whether a protocol scheme is special.
103+
*
104+
* @param {String} The protocol scheme of the URL
105+
* @return {Boolean} `true` if the protocol scheme is special, else `false`
106+
* @private
107+
*/
108+
function isSpecial(scheme) {
109+
return (
110+
scheme === 'file:' ||
111+
scheme === 'ftp:' ||
112+
scheme === 'http:' ||
113+
scheme === 'https:' ||
114+
scheme === 'ws:' ||
115+
scheme === 'wss:'
116+
);
117+
}
118+
101119
/**
102120
* @typedef ProtocolExtract
103121
* @type Object
@@ -110,16 +128,32 @@ function lolcation(loc) {
110128
* Extract protocol information from a URL with/without double slash ("//").
111129
*
112130
* @param {String} address URL we want to extract from.
131+
* @param {Object} location
113132
* @return {ProtocolExtract} Extracted information.
114133
* @private
115134
*/
116-
function extractProtocol(address) {
135+
function extractProtocol(address, location) {
117136
address = trimLeft(address);
137+
location = location || {};
118138

119-
var match = protocolre.exec(address)
120-
, protocol = match[1] ? match[1].toLowerCase() : ''
121-
, slashes = !!(match[2] && match[2].length >= 2)
122-
, rest = match[2] && match[2].length === 1 ? '/' + match[3] : match[3];
139+
var match = protocolre.exec(address);
140+
var protocol = match[1] ? match[1].toLowerCase() : '';
141+
var rest = match[2] ? match[2] + match[3] : match[3];
142+
var slashes = !!(match[2] && match[2].length >= 2);
143+
144+
if (protocol === 'file:') {
145+
if (slashes) {
146+
rest = rest.slice(2);
147+
}
148+
} else if (isSpecial(protocol)) {
149+
rest = match[3];
150+
} else if (protocol) {
151+
if (rest.indexOf('//') === 0) {
152+
rest = rest.slice(2);
153+
}
154+
} else if (slashes && location.hostname) {
155+
rest = match[3];
156+
}
123157

124158
return {
125159
protocol: protocol,
@@ -214,7 +248,7 @@ function Url(address, location, parser) {
214248
//
215249
// Extract protocol information before running the instructions.
216250
//
217-
extracted = extractProtocol(address || '');
251+
extracted = extractProtocol(address || '', location);
218252
relative = !extracted.protocol && !extracted.slashes;
219253
url.slashes = extracted.slashes || relative && location.slashes;
220254
url.protocol = extracted.protocol || location.protocol || '';
@@ -224,7 +258,10 @@ function Url(address, location, parser) {
224258
// When the authority component is absent the URL starts with a path
225259
// component.
226260
//
227-
if (!extracted.slashes || url.protocol === 'file:') {
261+
if (
262+
url.protocol === 'file:' ||
263+
(!extracted.slashes && !isSpecial(extracted.protocol))
264+
) {
228265
instructions[3] = [/(.*)/, 'pathname'];
229266
}
230267

test/test.js

+63-3
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ describe('url-parse', function () {
9393
assume(parse.extractProtocol('//foo/bar')).eql({
9494
slashes: true,
9595
protocol: '',
96-
rest: 'foo/bar'
96+
rest: '//foo/bar'
9797
});
9898
});
9999

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

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

@@ -292,11 +292,59 @@ describe('url-parse', function () {
292292
assume(parsed.pathname).equals('/foo/bar');
293293

294294
url = 'https:/\\/\\/\\github.com/foo/bar';
295+
parsed = parse(url);
295296
assume(parsed.host).equals('github.com');
296297
assume(parsed.hostname).equals('github.com');
297298
assume(parsed.pathname).equals('/foo/bar');
299+
300+
url = 'https:/github.com/foo/bar';
301+
parsed = parse(url);
302+
assume(parsed.host).equals('github.com');
303+
assume(parsed.pathname).equals('/foo/bar');
304+
305+
url = 'https:\\github.com/foo/bar';
306+
parsed = parse(url);
307+
assume(parsed.host).equals('github.com');
308+
assume(parsed.pathname).equals('/foo/bar');
309+
310+
url = 'https:github.com/foo/bar';
311+
parsed = parse(url);
312+
assume(parsed.host).equals('github.com');
313+
assume(parsed.pathname).equals('/foo/bar');
314+
315+
url = 'https:github.com/foo/bar';
316+
parsed = parse(url);
317+
assume(parsed.host).equals('github.com');
318+
assume(parsed.pathname).equals('/foo/bar');
298319
});
299320

321+
it('handles slashes after the protocol for non special URLs', function () {
322+
var url = 'foo:example.com'
323+
, parsed = parse(url);
324+
325+
assume(parsed.hostname).equals('');
326+
assume(parsed.pathname).equals('example.com');
327+
assume(parsed.href).equals('foo:example.com');
328+
329+
url = 'foo:/example.com';
330+
parsed = parse(url);
331+
assume(parsed.hostname).equals('');
332+
assume(parsed.pathname).equals('/example.com');
333+
assume(parsed.href).equals('foo:/example.com');
334+
335+
url = 'foo://example.com';
336+
parsed = parse(url);
337+
assume(parsed.hostname).equals('example.com');
338+
assume(parsed.pathname).equals('/');
339+
assume(parsed.href).equals('foo://example.com/');
340+
341+
url = 'foo:///example.com';
342+
parsed = parse(url);
343+
assume(parsed.hostname).equals('');
344+
assume(parsed.pathname).equals('/example.com');
345+
assume(parsed.href).equals('foo:///example.com');
346+
})
347+
300348
describe('origin', function () {
301349
it('generates an origin property', function () {
302350
var url = 'http://google.com:80/pathname'
@@ -440,7 +488,7 @@ describe('url-parse', function () {
440488
});
441489

442490
it('handles the file: protocol', function () {
443-
var slashes = ['', '/', '//', '///', '////', '/////'];
491+
var slashes = ['', '/', '//', '///'];
444492
var data;
445493
var url;
446494

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

502+
url = 'file:////';
503+
data = parse(url);
504+
assume(data.protocol).equals('file:');
505+
assume(data.pathname).equals('//');
506+
assume(data.href).equals(url);
507+
508+
url = 'file://///';
509+
data = parse(url);
510+
assume(data.protocol).equals('file:');
511+
assume(data.pathname).equals('///');
512+
assume(data.href).equals(url);
513+
454514
url = 'file:///Users/foo/BAR/baz.pdf';
455515
data = parse(url);
456516
assume(data.protocol).equals('file:');

0 commit comments

Comments
 (0)