diff --git a/src/vs/base/common/uriTemplate.ts b/src/vs/base/common/uriTemplate.ts index 4734dc0d9f1..f425f810a28 100644 --- a/src/vs/base/common/uriTemplate.ts +++ b/src/vs/base/common/uriTemplate.ts @@ -298,7 +298,7 @@ function pctEncode(str: string): string { ) { out += str[i]; } else { - out += '%' + chr.toString(16).toUpperCase(); + out += '%' + chr.toString(16).toUpperCase().padStart(2, '0'); } } return out; diff --git a/src/vs/base/test/common/uriTemplate.test.ts b/src/vs/base/test/common/uriTemplate.test.ts index 0165f0aa4a4..fbe0ad8d1d7 100644 --- a/src/vs/base/test/common/uriTemplate.test.ts +++ b/src/vs/base/test/common/uriTemplate.test.ts @@ -103,6 +103,14 @@ suite('UriTemplate', () => { testResolution('{hello}', variables, 'Hello%20World%21'); }); + test('control characters are percent-encoded with two hex digits', () => { + // Code points below 0x10 must be zero-padded (e.g. %09, not %9) so the + // output is a valid percent-encoding that decodeURIComponent accepts. + testResolution('{x}', { x: 'a\tb' }, 'a%09b'); + testResolution('{x}', { x: '\n' }, '%0A'); + testResolution('{x}', { x: '\r' }, '%0D'); + }); + test('Level 2 - Reserved expansion', () => { // Test cases from RFC 6570 Section 1.2 const variables = {