diff --git a/src/vs/base/common/uri.ts b/src/vs/base/common/uri.ts index 55e43e6d1cb..d2fdb47ea2a 100644 --- a/src/vs/base/common/uri.ts +++ b/src/vs/base/common/uri.ts @@ -50,6 +50,27 @@ function _validateUri(ret: URI): void { } } +// implements a bit of https://tools.ietf.org/html/rfc3986#section-5 +function _referenceResolution(scheme: string, path: string): string { + + // the slash-character is our 'default base' as we don't + // support constructing URIs relative to other URIs. This + // also means that we alter and potentially break paths. + // see https://tools.ietf.org/html/rfc3986#section-5.1.4 + switch (scheme) { + case 'https': + case 'http': + case 'file': + if (!path) { + path = _slash; + } else if (path[0] !== _slash) { + path = _slash + path; + } + break; + } + return path; +} + const _empty = ''; const _slash = '/'; const _regexp = /^(([^:/?#]+?):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/; @@ -142,14 +163,10 @@ export default class URI implements UriComponents { } else { this.scheme = schemeOrData || _empty; this.authority = authority || _empty; - this.path = path || _empty; + this.path = _referenceResolution(this.scheme, path || _empty); this.query = query || _empty; this.fragment = fragment || _empty; - // if (this.path[0] !== _slash) { - // this.path = _slash + this.path; - // } - _validateUri(this); } } @@ -253,14 +270,6 @@ export default class URI implements UriComponents { } } - // the slash-character is our 'default base' as we don't - // support constructing URIs relative to other URIs. This - // also means that we alter and potentially break paths. - // see https://tools.ietf.org/html/rfc3986#section-5.1.4 - if (path[0] !== _slash) { - path = _slash + path; - } - return new _URI('file', authority, path, _empty, _empty); } @@ -377,7 +386,7 @@ class _URI extends URI { function _makeFsPath(uri: URI): string { let value: string; - if (uri.authority && uri.path && uri.scheme === 'file') { + if (uri.authority && uri.path.length > 1 && uri.scheme === 'file') { // unc path: file://shares/c$/far/boo value = `//${uri.authority}${uri.path}`; } else if (_driveLetterPath.test(uri.path)) { diff --git a/src/vs/base/test/common/network.test.ts b/src/vs/base/test/common/network.test.ts index cf77a0f56d9..7aba51f153b 100644 --- a/src/vs/base/test/common/network.test.ts +++ b/src/vs/base/test/common/network.test.ts @@ -36,7 +36,7 @@ suite('Network', () => { ); assertUrl('http://www.test.com:8000#hash', - 'http', 'www.test.com', '8000', '', '', 'hash' + 'http', 'www.test.com', '8000', '/', '', 'hash' ); assertUrl('http://www.test.com/#hash', @@ -44,7 +44,7 @@ suite('Network', () => { ); assertUrl('http://www.test.com#hash', - 'http', 'www.test.com', '', '', '', 'hash' + 'http', 'www.test.com', '', '/', '', 'hash' ); assertUrl('http://www.test.com:8000/this/that/theother.html', @@ -56,7 +56,7 @@ suite('Network', () => { ); assertUrl('http://www.test.com:8000', - 'http', 'www.test.com', '8000', '', '', '' + 'http', 'www.test.com', '8000', '/', '', '' ); assertUrl('http://www.test.com/', diff --git a/src/vs/base/test/common/uri.test.ts b/src/vs/base/test/common/uri.test.ts index 3341b0bcb6a..7d3e4ad0ddc 100644 --- a/src/vs/base/test/common/uri.test.ts +++ b/src/vs/base/test/common/uri.test.ts @@ -51,15 +51,15 @@ suite('URI', () => { test('URI#fsPath - no `fsPath` when no `path`', () => { const value = URI.parse('file://%2Fhome%2Fticino%2Fdesktop%2Fcpluscplus%2Ftest.cpp'); assert.equal(value.authority, '/home/ticino/desktop/cpluscplus/test.cpp'); - assert.equal(value.path, ''); - assert.equal(value.fsPath, ''); + assert.equal(value.path, '/'); + assert.equal(value.fsPath, '/'); }); test('http#toString', () => { assert.equal(URI.from({ scheme: 'http', authority: 'www.msft.com', path: '/my/path' }).toString(), 'http://www.msft.com/my/path'); assert.equal(URI.from({ scheme: 'http', authority: 'www.msft.com', path: '/my/path' }).toString(), 'http://www.msft.com/my/path'); assert.equal(URI.from({ scheme: 'http', authority: 'www.MSFT.com', path: '/my/path' }).toString(), 'http://www.msft.com/my/path'); - assert.equal(URI.from({ scheme: 'http', authority: '', path: 'my/path' }).toString(), 'http:my/path'); + assert.equal(URI.from({ scheme: 'http', authority: '', path: 'my/path' }).toString(), 'http:/my/path'); assert.equal(URI.from({ scheme: 'http', authority: '', path: '/my/path' }).toString(), 'http:/my/path'); assert.equal(URI.from({ scheme: '', authority: '', path: 'my/path' }).toString(), 'my/path'); assert.equal(URI.from({ scheme: '', authority: '', path: '/my/path' }).toString(), '/my/path'); @@ -213,7 +213,7 @@ suite('URI', () => { value = URI.parse('file:?q'); assert.equal(value.scheme, 'file'); assert.equal(value.authority, ''); - assert.equal(value.path, ''); + assert.equal(value.path, '/'); assert.equal(value.query, 'q'); assert.equal(value.fragment, ''); @@ -227,7 +227,7 @@ suite('URI', () => { value = URI.parse('file:#d'); assert.equal(value.scheme, 'file'); assert.equal(value.authority, ''); - assert.equal(value.path, ''); + assert.equal(value.path, '/'); assert.equal(value.query, ''); assert.equal(value.fragment, 'd');