Skip to content

Commit c838e1f

Browse files
authored
Fix: Page crash on half surrogate pair (#261)
This commit fixes an issue where utf-16 encoded surrogated pair could crash the page when inserted as input. The commit adds endsWithHalfSurrogatePair to check for half pair and safeEncodeURIComponent to ignore half surrogated pair before passing it to encodeURIComponent. Fixes #260
1 parent 8b65a43 commit c838e1f

1 file changed

Lines changed: 29 additions & 3 deletions

File tree

packages/docusaurus-theme-openapi/src/theme/ApiDemoPanel/buildPostmanRequest.ts

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,30 @@ type Param = {
1717
value?: string | string[];
1818
} & ParameterObject;
1919

20+
function endsWithHalfSurrogatePair(value: string) {
21+
if (value.length === 0) {
22+
return false;
23+
}
24+
const lastIndex = value.length - 1;
25+
const charCode = value.charCodeAt(lastIndex);
26+
// https://unicodebook.readthedocs.io/unicode_encodings.html#utf-16-surrogate-pairs
27+
// If ends with high surrogates string is invalid and encodeURIComponent fails
28+
// Only end checked for cases where surrogates input is sequential
29+
// We assume the user inputs a valid string but sequential write might temporarily
30+
// result in half a pair ending string
31+
if (charCode < 0xd800 || charCode > 0xdbff) {
32+
return false; // If any character is not a high surrogate, return false
33+
}
34+
return true;
35+
}
36+
37+
function safeEncodeURIComponent(value: string | number | boolean) {
38+
if (typeof value === "string" && endsWithHalfSurrogatePair(value)) {
39+
return encodeURIComponent(value.slice(0, -1));
40+
}
41+
return encodeURIComponent(value);
42+
}
43+
2044
export function openApiQueryParams2PostmanQueryParams(
2145
queryParams: Param[]
2246
): sdk.QueryParam[] {
@@ -46,7 +70,7 @@ export function openApiQueryParams2PostmanQueryParams(
4670
if (Array.isArray(param.value)) {
4771
return new sdk.QueryParam({
4872
key: param.name,
49-
value: param.value.map(encodeURIComponent).join(delimiter),
73+
value: param.value.map(safeEncodeURIComponent).join(delimiter),
5074
});
5175
}
5276

@@ -63,7 +87,7 @@ export function openApiQueryParams2PostmanQueryParams(
6387

6488
return new sdk.QueryParam({
6589
key: param.name,
66-
value: encodeURIComponent(param.value),
90+
value: safeEncodeURIComponent(param.value),
6791
});
6892
})
6993
.filter((item): item is sdk.QueryParam => item !== undefined);
@@ -79,7 +103,9 @@ function setQueryParams(postman: sdk.Request, queryParams: Param[]) {
79103

80104
function setPathParams(postman: sdk.Request, queryParams: Param[]) {
81105
const recursiveEncodeURIComponent = (c: string | string[]) =>
82-
Array.isArray(c) ? c.map(encodeURIComponent) : encodeURIComponent(c);
106+
Array.isArray(c)
107+
? c.map(safeEncodeURIComponent)
108+
: safeEncodeURIComponent(c);
83109

84110
const source = queryParams.map((param) => {
85111
return new sdk.Variable({

0 commit comments

Comments
 (0)