Skip to content

Commit 06eebb8

Browse files
committed
ensure path-component of file, http, and https-uris is absolute, microsoft#34449
1 parent 950d4bf commit 06eebb8

3 files changed

Lines changed: 31 additions & 22 deletions

File tree

src/vs/base/common/uri.ts

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,27 @@ function _validateUri(ret: URI): void {
5050
}
5151
}
5252

53+
// implements a bit of https://tools.ietf.org/html/rfc3986#section-5
54+
function _referenceResolution(scheme: string, path: string): string {
55+
56+
// the slash-character is our 'default base' as we don't
57+
// support constructing URIs relative to other URIs. This
58+
// also means that we alter and potentially break paths.
59+
// see https://tools.ietf.org/html/rfc3986#section-5.1.4
60+
switch (scheme) {
61+
case 'https':
62+
case 'http':
63+
case 'file':
64+
if (!path) {
65+
path = _slash;
66+
} else if (path[0] !== _slash) {
67+
path = _slash + path;
68+
}
69+
break;
70+
}
71+
return path;
72+
}
73+
5374
const _empty = '';
5475
const _slash = '/';
5576
const _regexp = /^(([^:/?#]+?):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/;
@@ -142,14 +163,10 @@ export default class URI implements UriComponents {
142163
} else {
143164
this.scheme = schemeOrData || _empty;
144165
this.authority = authority || _empty;
145-
this.path = path || _empty;
166+
this.path = _referenceResolution(this.scheme, path || _empty);
146167
this.query = query || _empty;
147168
this.fragment = fragment || _empty;
148169

149-
// if (this.path[0] !== _slash) {
150-
// this.path = _slash + this.path;
151-
// }
152-
153170
_validateUri(this);
154171
}
155172
}
@@ -253,14 +270,6 @@ export default class URI implements UriComponents {
253270
}
254271
}
255272

256-
// the slash-character is our 'default base' as we don't
257-
// support constructing URIs relative to other URIs. This
258-
// also means that we alter and potentially break paths.
259-
// see https://tools.ietf.org/html/rfc3986#section-5.1.4
260-
if (path[0] !== _slash) {
261-
path = _slash + path;
262-
}
263-
264273
return new _URI('file', authority, path, _empty, _empty);
265274
}
266275

@@ -377,7 +386,7 @@ class _URI extends URI {
377386
function _makeFsPath(uri: URI): string {
378387

379388
let value: string;
380-
if (uri.authority && uri.path && uri.scheme === 'file') {
389+
if (uri.authority && uri.path.length > 1 && uri.scheme === 'file') {
381390
// unc path: file://shares/c$/far/boo
382391
value = `//${uri.authority}${uri.path}`;
383392
} else if (_driveLetterPath.test(uri.path)) {

src/vs/base/test/common/network.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,15 +36,15 @@ suite('Network', () => {
3636
);
3737

3838
assertUrl('http://www.test.com:8000#hash',
39-
'http', 'www.test.com', '8000', '', '', 'hash'
39+
'http', 'www.test.com', '8000', '/', '', 'hash'
4040
);
4141

4242
assertUrl('http://www.test.com/#hash',
4343
'http', 'www.test.com', '', '/', '', 'hash'
4444
);
4545

4646
assertUrl('http://www.test.com#hash',
47-
'http', 'www.test.com', '', '', '', 'hash'
47+
'http', 'www.test.com', '', '/', '', 'hash'
4848
);
4949

5050
assertUrl('http://www.test.com:8000/this/that/theother.html',
@@ -56,7 +56,7 @@ suite('Network', () => {
5656
);
5757

5858
assertUrl('http://www.test.com:8000',
59-
'http', 'www.test.com', '8000', '', '', ''
59+
'http', 'www.test.com', '8000', '/', '', ''
6060
);
6161

6262
assertUrl('http://www.test.com/',

src/vs/base/test/common/uri.test.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,15 +51,15 @@ suite('URI', () => {
5151
test('URI#fsPath - no `fsPath` when no `path`', () => {
5252
const value = URI.parse('file://%2Fhome%2Fticino%2Fdesktop%2Fcpluscplus%2Ftest.cpp');
5353
assert.equal(value.authority, '/home/ticino/desktop/cpluscplus/test.cpp');
54-
assert.equal(value.path, '');
55-
assert.equal(value.fsPath, '');
54+
assert.equal(value.path, '/');
55+
assert.equal(value.fsPath, '/');
5656
});
5757

5858
test('http#toString', () => {
5959
assert.equal(URI.from({ scheme: 'http', authority: 'www.msft.com', path: '/my/path' }).toString(), 'http://www.msft.com/my/path');
6060
assert.equal(URI.from({ scheme: 'http', authority: 'www.msft.com', path: '/my/path' }).toString(), 'http://www.msft.com/my/path');
6161
assert.equal(URI.from({ scheme: 'http', authority: 'www.MSFT.com', path: '/my/path' }).toString(), 'http://www.msft.com/my/path');
62-
assert.equal(URI.from({ scheme: 'http', authority: '', path: 'my/path' }).toString(), 'http:my/path');
62+
assert.equal(URI.from({ scheme: 'http', authority: '', path: 'my/path' }).toString(), 'http:/my/path');
6363
assert.equal(URI.from({ scheme: 'http', authority: '', path: '/my/path' }).toString(), 'http:/my/path');
6464
assert.equal(URI.from({ scheme: '', authority: '', path: 'my/path' }).toString(), 'my/path');
6565
assert.equal(URI.from({ scheme: '', authority: '', path: '/my/path' }).toString(), '/my/path');
@@ -213,7 +213,7 @@ suite('URI', () => {
213213
value = URI.parse('file:?q');
214214
assert.equal(value.scheme, 'file');
215215
assert.equal(value.authority, '');
216-
assert.equal(value.path, '');
216+
assert.equal(value.path, '/');
217217
assert.equal(value.query, 'q');
218218
assert.equal(value.fragment, '');
219219

@@ -227,7 +227,7 @@ suite('URI', () => {
227227
value = URI.parse('file:#d');
228228
assert.equal(value.scheme, 'file');
229229
assert.equal(value.authority, '');
230-
assert.equal(value.path, '');
230+
assert.equal(value.path, '/');
231231
assert.equal(value.query, '');
232232
assert.equal(value.fragment, 'd');
233233

0 commit comments

Comments
 (0)