diff --git a/src/vs/base/common/uri.ts b/src/vs/base/common/uri.ts index f6a8959a04c..19f89eec626 100644 --- a/src/vs/base/common/uri.ts +++ b/src/vs/base/common/uri.ts @@ -267,10 +267,10 @@ export class URI implements UriComponents { } return new _URI( match[2] || _empty, - decodeURIComponent(match[4] || _empty), - decodeURIComponent(match[5] || _empty), - decodeURIComponent(match[7] || _empty), - decodeURIComponent(match[9] || _empty), + percentDecode(match[4] || _empty), + percentDecode(match[5] || _empty), + percentDecode(match[7] || _empty), + percentDecode(match[9] || _empty), _strict ); } @@ -648,3 +648,26 @@ function _asFormatted(uri: URI, skipEncoding: boolean): string { } return res; } + +// --- decode + +function decodeURIComponentGraceful(str: string): string { + try { + return decodeURIComponent(str); + } catch { + if (str.length > 3) { + return str.substr(0, 3) + decodeURIComponentGraceful(str.substr(3)); + } else { + return str; + } + } +} + +const _rEncodedAsHex = /(%[0-9A-Za-z][0-9A-Za-z])+/g; + +function percentDecode(str: string): string { + if (!str.match(_rEncodedAsHex)) { + return str; + } + return str.replace(_rEncodedAsHex, (match) => decodeURIComponentGraceful(match)); +} diff --git a/src/vs/base/test/common/uri.test.ts b/src/vs/base/test/common/uri.test.ts index 3255575ae57..6b35d6afc9c 100644 --- a/src/vs/base/test/common/uri.test.ts +++ b/src/vs/base/test/common/uri.test.ts @@ -439,6 +439,10 @@ suite('URI', () => { assert.equal(uri.path, uri2.path); }); + test('Unable to open \'%A0.txt\': URI malformed #76506', function () { + assert.equal(URI.parse('file://some/%.txt'), 'file://some/%25.txt'); + assert.equal(URI.parse('file://some/%A0.txt'), 'file://some/%25A0.txt'); + }); test('Links in markdown are broken if url contains encoded parameters #79474', function () { this.skip();