提交 3e0ded9c 编写于 作者: J Johannes Rieken

keep input (for toString) when using URI.parse, URI.file uses now URI.parse

Add tests that check our logic against Nodejs's pathToFileURL
上级 359c17a6
...@@ -74,8 +74,17 @@ function _referenceResolution(scheme: string, path: string): string { ...@@ -74,8 +74,17 @@ function _referenceResolution(scheme: string, path: string): string {
const _empty = ''; const _empty = '';
const _slash = '/'; const _slash = '/';
const _regexp = /^(([^:/?#]+?):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/; const _regexp = /^(([^:/?#]+?):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/;
const enum MatchIndex {
scheme = 2,
authority = 4,
path = 5,
query = 7,
fragment = 9
}
/** /**
* Uniform Resource Identifier (URI) http://tools.ietf.org/html/rfc3986. * Uniform Resource Identifier (URI) http://tools.ietf.org/html/rfc3986.
* This class is a simple parser which creates the basic component parts * This class is a simple parser which creates the basic component parts
...@@ -262,15 +271,24 @@ export class URI implements UriComponents { ...@@ -262,15 +271,24 @@ export class URI implements UriComponents {
static parse(value: string): URI { static parse(value: string): URI {
const match = _regexp.exec(value); const match = _regexp.exec(value);
if (!match) { if (!match) {
return new _URI(_empty, _empty, _empty, _empty, _empty); throw new Error(`[UriError]: Invalid input: ${value}`);
} }
return new _URI(
match[2] || _empty, const scheme = _schemeFix(match[MatchIndex.scheme]) || _empty;
percentDecode(match[4] || _empty), const authority = match[MatchIndex.authority] || _empty;
percentDecode(match[5] || _empty), const path = _referenceResolution(scheme, match[MatchIndex.path] || _empty);
percentDecode(match[7] || _empty), const query = match[MatchIndex.query] || _empty;
percentDecode(match[9] || _empty) const fragment = match[MatchIndex.fragment] || _empty;
const result = new _URI(
scheme,
percentDecode(authority),
percentDecode(path),
percentDecode(query),
percentDecode(fragment),
); );
result._formatted = _toString(false, scheme, authority, path, query, fragment);
return result;
} }
/** /**
...@@ -318,7 +336,15 @@ export class URI implements UriComponents { ...@@ -318,7 +336,15 @@ export class URI implements UriComponents {
} }
} }
return new _URI('file', authority, path, _empty, _empty); if (path.charAt(0) !== _slash) {
path = _slash + path;
}
// escape some vital characters
authority = authority.replace(/%/g, '%25');
path = path.replace(/%/g, '%25');
return URI.parse('file://' + authority + path);
} }
static from(components: { scheme: string; authority?: string; path?: string; query?: string; fragment?: string; }): URI { static from(components: { scheme: string; authority?: string; path?: string; query?: string; fragment?: string; }): URI {
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
import * as assert from 'assert'; import * as assert from 'assert';
import { URI, UriComponents } from 'vs/base/common/uri'; import { URI, UriComponents } from 'vs/base/common/uri';
import { isWindows } from 'vs/base/common/platform'; import { isWindows } from 'vs/base/common/platform';
import { pathToFileURL } from 'url';
suite('URI', () => { suite('URI', () => {
test('file#toString', () => { test('file#toString', () => {
...@@ -427,21 +427,24 @@ suite('URI', () => { ...@@ -427,21 +427,24 @@ suite('URI', () => {
}); });
test('Unable to open \'%A0.txt\': URI malformed #76506', function () { test('Unable to open \'%A0.txt\': URI malformed #76506', function () {
let uriFromPath = URI.file('/foo/%A0.txt');
let uri = URI.file('/foo/%A0.txt'); let uriFromStr = URI.parse(uriFromPath.toString());
let uri2 = URI.parse(uri.toString()); assert.equal(uriFromPath.scheme, uriFromStr.scheme);
assert.equal(uri.scheme, uri2.scheme); assert.equal(uriFromPath.path, uriFromStr.path);
assert.equal(uri.path, uri2.path); assert.equal(uriFromPath.toString(), 'file:///foo/%25A0.txt');
assert.equal(uriFromStr.toString(), 'file:///foo/%25A0.txt');
uri = URI.file('/foo/%2e.txt');
uri2 = URI.parse(uri.toString());
assert.equal(uri.scheme, uri2.scheme);
assert.equal(uri.path, uri2.path);
}); });
test('Valid percent-encoded character in filename', function () {
let uriFromPath = URI.file('/foo/%2e.txt');
let uriFromStr = URI.parse(uriFromPath.toString());
assert.equal(uriFromPath.scheme, uriFromStr.scheme);
assert.equal(uriFromPath.path, uriFromStr.path);
assert.equal(uriFromPath.toString(), 'file:///foo/%252e.txt');
assert.equal(uriFromStr.toString(), 'file:///foo/%252e.txt');
});
test('Links in markdown are broken if url contains encoded parameters #79474', function () { test('Links in markdown are broken if url contains encoded parameters #79474', function () {
this.skip();
let strIn = 'https://myhost.com/Redirect?url=http%3A%2F%2Fwww.bing.com%3Fsearch%3Dtom'; let strIn = 'https://myhost.com/Redirect?url=http%3A%2F%2Fwww.bing.com%3Fsearch%3Dtom';
let uri1 = URI.parse(strIn); let uri1 = URI.parse(strIn);
let strOut = uri1.toString(); let strOut = uri1.toString();
...@@ -456,7 +459,6 @@ suite('URI', () => { ...@@ -456,7 +459,6 @@ suite('URI', () => {
}); });
test('Uri#parse can break path-component #45515', function () { test('Uri#parse can break path-component #45515', function () {
this.skip();
let strIn = 'https://firebasestorage.googleapis.com/v0/b/brewlangerie.appspot.com/o/products%2FzVNZkudXJyq8bPGTXUxx%2FBetterave-Sesame.jpg?alt=media&token=0b2310c4-3ea6-4207-bbde-9c3710ba0437'; let strIn = 'https://firebasestorage.googleapis.com/v0/b/brewlangerie.appspot.com/o/products%2FzVNZkudXJyq8bPGTXUxx%2FBetterave-Sesame.jpg?alt=media&token=0b2310c4-3ea6-4207-bbde-9c3710ba0437';
let uri1 = URI.parse(strIn); let uri1 = URI.parse(strIn);
let strOut = uri1.toString(); let strOut = uri1.toString();
...@@ -499,4 +501,20 @@ suite('URI', () => { ...@@ -499,4 +501,20 @@ suite('URI', () => {
// } // }
// console.profileEnd(); // console.profileEnd();
}); });
function assertFileUri(path: string): void {
// check that our uri aligns with nodejs
const actual = URI.file(path).toString();
const expected = pathToFileURL(path).href;
assert.equal(actual, expected);
}
test('URI.file vs pathToFileURL', function () {
assertFileUri('/foo/bar');
assertFileUri('/foo/%2e.txt'); // %2e -> .
assertFileUri('/foo/%A0.txt'); // %A0 -> invalid
assertFileUri('/foo/ü.txt');
assertFileUri('/foo/ß.txt');
// assertFileUri('foo'); nodejs resolves the path first
});
}); });
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册