Skip to content

Commit 24df9e7

Browse files
Improve based on testing
1 parent f88050c commit 24df9e7

2 files changed

Lines changed: 26 additions & 3 deletions

File tree

packages/web-api/src/instrument.test.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,15 +60,24 @@ describe('instrument', () => {
6060
assert.ok(isLatin1Safe(ua));
6161
});
6262

63-
it('should return a Latin-1 safe user agent when process.title contains non-ASCII characters', () => {
64-
const notLatin1SafeTitle = '管理者'
63+
it('should return a Latin-1 safe user agent when process.title contains non-Latin-1 characters', () => {
64+
const notLatin1SafeTitle = '管理者: Windows PowerShell'
6565
assert.strictEqual(isLatin1Safe(notLatin1SafeTitle), false);
6666

6767
mockProcessTitle(notLatin1SafeTitle);
6868
const { getUserAgent } = freshImport();
6969
const ua = getUserAgent();
7070
assert.ok(isLatin1Safe(ua), `User-Agent contains non-Latin-1 characters: ${ua}`);
7171
assert.ok(!ua.includes(notLatin1SafeTitle), 'User-Agent should not contain raw non-ASCII characters');
72+
assert.ok(ua.includes('%E7%AE%A1%E7%90%86%E8%80%85: Windows PowerShell'), 'User-Agent should percent-encode only non-Latin-1 characters');
73+
});
74+
75+
it('should preserve Latin-1 characters in process.title', () => {
76+
mockProcessTitle('café');
77+
const { getUserAgent } = freshImport();
78+
const ua = getUserAgent();
79+
assert.ok(ua.includes('café/'), `User-Agent should preserve Latin-1 characters: ${ua}`);
80+
assert.ok(isLatin1Safe(ua));
7281
});
7382
});
7483
});

packages/web-api/src/instrument.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,20 @@ function replaceSlashes(s: string): string {
1010
return s.replace('/', ':');
1111
}
1212

13+
const MAX_LATIN1_CODE = 0xFF;
14+
15+
/**
16+
* Ensures a string is safe for use in HTTP headers by URI-encoding characters outside the Latin-1 (ISO-8859-1) range.
17+
* Latin-1 characters (code points 0x00–0xFF) are preserved as-is; all others are percent-encoded via encodeURIComponent.
18+
*/
19+
function toLatin1Safe(s: string): string {
20+
let result = '';
21+
for (const char of s) {
22+
result += char.charCodeAt(0) <= MAX_LATIN1_CODE ? char : encodeURIComponent(char);
23+
}
24+
return result;
25+
}
26+
1327
// TODO: for the deno build (see the `npm run build:deno` npm run script), we could replace the `os-browserify` npm
1428
// module shim with our own shim leveraging the deno beta compatibility layer for node's `os` module (for more info
1529
// see https://deno.land/std@0.116.0/node/os.ts). At the time of writing this TODO (2021/11/25), this required deno
@@ -18,7 +32,7 @@ function replaceSlashes(s: string): string {
1832
// based code will report "browser/undefined" from a deno runtime.
1933
const baseUserAgent =
2034
`${replaceSlashes(packageJson.name)}/${packageJson.version} ` +
21-
`${encodeURI(basename(process.title))}/${process.version.replace('v', '')} ` +
35+
`${toLatin1Safe(basename(process.title))}/${process.version.replace('v', '')} ` +
2236
`${os.platform()}/${os.release()}`;
2337

2438
const appMetadata: { [key: string]: string } = {};

0 commit comments

Comments
 (0)