-
Notifications
You must be signed in to change notification settings - Fork 39
Expand file tree
/
Copy pathsafeDecodeURIComponent.ts
More file actions
121 lines (108 loc) · 3.81 KB
/
safeDecodeURIComponent.ts
File metadata and controls
121 lines (108 loc) · 3.81 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
// Based on https://github.com/delvedor/fast-decode-uri-component
// Licensed under the MIT License
// Copyright (c) 2018 Tomas Della Vedova
// Copyright (c) 2017 Justin Ridgewell
// Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
const UTF8_ACCEPT = 12;
const UTF8_REJECT = 0;
const UTF8_DATA = [
// The first part of the table maps bytes to character to a transition.
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 8, 7, 7, 10, 9, 9, 9, 11, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
// The second part of the table maps a state to a new state when adding a
// transition.
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 24, 36, 48, 60, 72, 84,
96, 0, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0,
0, 0, 24, 24, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 24, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 48, 48, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 48, 0, 0, 0, 0, 0, 0, 0,
0, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// The third part maps the current transition to a mask that needs to apply
// to the byte.
0x7f, 0x3f, 0x3f, 0x3f, 0x00, 0x1f, 0x0f, 0x0f, 0x0f, 0x07, 0x07, 0x07,
];
const HEX = {
"0": 0,
"1": 1,
"2": 2,
"3": 3,
"4": 4,
"5": 5,
"6": 6,
"7": 7,
"8": 8,
"9": 9,
a: 10,
A: 10,
b: 11,
B: 11,
c: 12,
C: 12,
d: 13,
D: 13,
e: 14,
E: 14,
f: 15,
F: 15,
};
/**
* Decodes a URI component, returning undefined if the URI is invalid.
* This function is a safe alternative to `decodeURIComponent`, which throws
* an error if the URI is malformed.
*
* We use this for performance reasons (throwing errors is very slow).
*/
export function safeDecodeURIComponent(uri: string): string | undefined {
let percentPosition = uri.indexOf("%");
if (percentPosition === -1) {
// Uri does not contain any percent signs, so it is already decoded.
return uri;
}
const length = uri.length;
let decoded = "";
let last = 0;
let codepoint = 0;
let startOfOctets = percentPosition;
let state = UTF8_ACCEPT;
while (percentPosition > -1 && percentPosition < length) {
const high = hexCodeToInt(uri[percentPosition + 1], 4);
const low = hexCodeToInt(uri[percentPosition + 2], 0);
const byte = high | low;
const type = UTF8_DATA[byte];
state = UTF8_DATA[256 + state + type];
codepoint = (codepoint << 6) | (byte & UTF8_DATA[364 + type]);
if (state === UTF8_ACCEPT) {
decoded += uri.slice(last, startOfOctets);
decoded +=
codepoint <= 0xffff
? String.fromCharCode(codepoint)
: String.fromCharCode(
0xd7c0 + (codepoint >> 10),
0xdc00 + (codepoint & 0x3ff)
);
codepoint = 0;
last = percentPosition + 3;
percentPosition = startOfOctets = uri.indexOf("%", last);
} else if (state === UTF8_REJECT) {
return undefined;
} else {
percentPosition += 3;
if (percentPosition < length && uri.charCodeAt(percentPosition) === 37) {
continue;
}
return undefined;
}
}
return decoded + uri.slice(last);
}
function hexCodeToInt(c: string, shift: number): number {
const i = HEX[c as keyof typeof HEX];
return i === undefined ? 255 : i << shift;
}