1from typing import Union
2
3"""
4_url.py
5websocket - WebSocket client library for Python
6
7Copyright 2024 engn33r
8
9Licensed under the Apache License, Version 2.0 (the "License");
10you may not use this file except in compliance with the License.
11You may obtain a copy of the License at
12
13 http://www.apache.org/licenses/LICENSE-2.0
14
15Unless required by applicable law or agreed to in writing, software
16distributed under the License is distributed on an "AS IS" BASIS,
17WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18See the License for the specific language governing permissions and
19limitations under the License.
20"""
21__all__ = ["NoLock", "validate_utf8", "extract_err_message", "extract_error_code"]
22
23
24class NoLock:
25 def __enter__(self) -> None:
26 pass
27
28 def __exit__(self, exc_type, exc_value, traceback) -> None:
29 pass
30
31
32try:
33 # If wsaccel is available we use compiled routines to validate UTF-8
34 # strings.
35 from wsaccel.utf8validator import Utf8Validator
36
37 def _validate_utf8(utfbytes: Union[str, bytes]) -> bool:
38 result: bool = Utf8Validator().validate(utfbytes)[0]
39 return result
40
41except ImportError:
42 # UTF-8 validator
43 # python implementation of http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
44
45 _UTF8_ACCEPT = 0
46 _UTF8_REJECT = 12
47
48 _UTF8D = [
49 # The first part of the table maps bytes to character classes that
50 # to reduce the size of the transition table and create bitmasks.
51 0,
52 0,
53 0,
54 0,
55 0,
56 0,
57 0,
58 0,
59 0,
60 0,
61 0,
62 0,
63 0,
64 0,
65 0,
66 0,
67 0,
68 0,
69 0,
70 0,
71 0,
72 0,
73 0,
74 0,
75 0,
76 0,
77 0,
78 0,
79 0,
80 0,
81 0,
82 0,
83 0,
84 0,
85 0,
86 0,
87 0,
88 0,
89 0,
90 0,
91 0,
92 0,
93 0,
94 0,
95 0,
96 0,
97 0,
98 0,
99 0,
100 0,
101 0,
102 0,
103 0,
104 0,
105 0,
106 0,
107 0,
108 0,
109 0,
110 0,
111 0,
112 0,
113 0,
114 0,
115 0,
116 0,
117 0,
118 0,
119 0,
120 0,
121 0,
122 0,
123 0,
124 0,
125 0,
126 0,
127 0,
128 0,
129 0,
130 0,
131 0,
132 0,
133 0,
134 0,
135 0,
136 0,
137 0,
138 0,
139 0,
140 0,
141 0,
142 0,
143 0,
144 0,
145 0,
146 0,
147 0,
148 0,
149 0,
150 0,
151 0,
152 0,
153 0,
154 0,
155 0,
156 0,
157 0,
158 0,
159 0,
160 0,
161 0,
162 0,
163 0,
164 0,
165 0,
166 0,
167 0,
168 0,
169 0,
170 0,
171 0,
172 0,
173 0,
174 0,
175 0,
176 0,
177 0,
178 0,
179 1,
180 1,
181 1,
182 1,
183 1,
184 1,
185 1,
186 1,
187 1,
188 1,
189 1,
190 1,
191 1,
192 1,
193 1,
194 1,
195 9,
196 9,
197 9,
198 9,
199 9,
200 9,
201 9,
202 9,
203 9,
204 9,
205 9,
206 9,
207 9,
208 9,
209 9,
210 9,
211 7,
212 7,
213 7,
214 7,
215 7,
216 7,
217 7,
218 7,
219 7,
220 7,
221 7,
222 7,
223 7,
224 7,
225 7,
226 7,
227 7,
228 7,
229 7,
230 7,
231 7,
232 7,
233 7,
234 7,
235 7,
236 7,
237 7,
238 7,
239 7,
240 7,
241 7,
242 7,
243 8,
244 8,
245 2,
246 2,
247 2,
248 2,
249 2,
250 2,
251 2,
252 2,
253 2,
254 2,
255 2,
256 2,
257 2,
258 2,
259 2,
260 2,
261 2,
262 2,
263 2,
264 2,
265 2,
266 2,
267 2,
268 2,
269 2,
270 2,
271 2,
272 2,
273 2,
274 2,
275 10,
276 3,
277 3,
278 3,
279 3,
280 3,
281 3,
282 3,
283 3,
284 3,
285 3,
286 3,
287 3,
288 4,
289 3,
290 3,
291 11,
292 6,
293 6,
294 6,
295 5,
296 8,
297 8,
298 8,
299 8,
300 8,
301 8,
302 8,
303 8,
304 8,
305 8,
306 8,
307 # The second part is a transition table that maps a combination
308 # of a state of the automaton and a character class to a state.
309 0,
310 12,
311 24,
312 36,
313 60,
314 96,
315 84,
316 12,
317 12,
318 12,
319 48,
320 72,
321 12,
322 12,
323 12,
324 12,
325 12,
326 12,
327 12,
328 12,
329 12,
330 12,
331 12,
332 12,
333 12,
334 0,
335 12,
336 12,
337 12,
338 12,
339 12,
340 0,
341 12,
342 0,
343 12,
344 12,
345 12,
346 24,
347 12,
348 12,
349 12,
350 12,
351 12,
352 24,
353 12,
354 24,
355 12,
356 12,
357 12,
358 12,
359 12,
360 12,
361 12,
362 12,
363 12,
364 24,
365 12,
366 12,
367 12,
368 12,
369 12,
370 24,
371 12,
372 12,
373 12,
374 12,
375 12,
376 12,
377 12,
378 24,
379 12,
380 12,
381 12,
382 12,
383 12,
384 12,
385 12,
386 12,
387 12,
388 36,
389 12,
390 36,
391 12,
392 12,
393 12,
394 36,
395 12,
396 12,
397 12,
398 12,
399 12,
400 36,
401 12,
402 36,
403 12,
404 12,
405 12,
406 36,
407 12,
408 12,
409 12,
410 12,
411 12,
412 12,
413 12,
414 12,
415 12,
416 12,
417 ]
418
419 def _decode(state: int, codep: int, ch: int) -> tuple:
420 tp = _UTF8D[ch]
421
422 codep = (
423 (ch & 0x3F) | (codep << 6) if (state != _UTF8_ACCEPT) else (0xFF >> tp) & ch
424 )
425 state = _UTF8D[256 + state + tp]
426
427 return state, codep
428
429 def _validate_utf8(utfbytes: Union[str, bytes]) -> bool:
430 state = _UTF8_ACCEPT
431 codep = 0
432 for i in utfbytes:
433 state, codep = _decode(state, codep, int(i))
434 if state == _UTF8_REJECT:
435 return False
436
437 return True
438
439
440def validate_utf8(utfbytes: Union[str, bytes]) -> bool:
441 """
442 validate utf8 byte string.
443 utfbytes: utf byte string to check.
444 return value: if valid utf8 string, return true. Otherwise, return false.
445 """
446 return _validate_utf8(utfbytes)
447
448
449def extract_err_message(exception: Exception) -> Union[str, None]:
450 if exception.args:
451 exception_message: str = exception.args[0]
452 return exception_message
453 else:
454 return None
455
456
457def extract_error_code(exception: Exception) -> Union[int, None]:
458 if exception.args and len(exception.args) > 1:
459 return exception.args[0] if isinstance(exception.args[0], int) else None