/src/unit/src/nxt_string.c
Line | Count | Source (jump to first uncovered line) |
1 | | |
2 | | /* |
3 | | * Copyright (C) Igor Sysoev |
4 | | * Copyright (C) NGINX, Inc. |
5 | | */ |
6 | | |
7 | | #include <nxt_main.h> |
8 | | |
9 | | |
10 | | nxt_str_t * |
11 | | nxt_str_alloc(nxt_mp_t *mp, size_t length) |
12 | 0 | { |
13 | 0 | nxt_str_t *s; |
14 | | |
15 | | /* The string start is allocated aligned to be close to nxt_str_t. */ |
16 | 0 | s = nxt_mp_get(mp, sizeof(nxt_str_t) + length); |
17 | |
|
18 | 0 | if (nxt_fast_path(s != NULL)) { |
19 | 0 | s->length = length; |
20 | 0 | s->start = nxt_pointer_to(s, sizeof(nxt_str_t)); |
21 | 0 | } |
22 | |
|
23 | 0 | return s; |
24 | 0 | } |
25 | | |
26 | | |
27 | | /* |
28 | | * nxt_str_dup() creates a new string with a copy of a source string. |
29 | | * If length of the source string is zero, then the new string anyway |
30 | | * gets a pointer somewhere in mem_pool. |
31 | | */ |
32 | | |
33 | | nxt_str_t * |
34 | | nxt_str_dup(nxt_mp_t *mp, nxt_str_t *dst, const nxt_str_t *src) |
35 | 0 | { |
36 | 0 | u_char *p; |
37 | |
|
38 | 0 | if (dst == NULL) { |
39 | | /* The string start is allocated aligned to be close to nxt_str_t. */ |
40 | 0 | dst = nxt_mp_get(mp, sizeof(nxt_str_t) + src->length); |
41 | 0 | if (nxt_slow_path(dst == NULL)) { |
42 | 0 | return NULL; |
43 | 0 | } |
44 | | |
45 | 0 | p = (u_char *) dst; |
46 | 0 | p += sizeof(nxt_str_t); |
47 | 0 | dst->start = p; |
48 | |
|
49 | 0 | } else { |
50 | 0 | dst->start = nxt_mp_nget(mp, src->length); |
51 | 0 | if (nxt_slow_path(dst->start == NULL)) { |
52 | 0 | return NULL; |
53 | 0 | } |
54 | 0 | } |
55 | | |
56 | 0 | nxt_memcpy(dst->start, src->start, src->length); |
57 | 0 | dst->length = src->length; |
58 | |
|
59 | 0 | return dst; |
60 | 0 | } |
61 | | |
62 | | |
63 | | /* |
64 | | * nxt_str_cstrz() creates a C style zero-terminated copy of a source |
65 | | * nxt_str_t. The function is intended to create strings suitable |
66 | | * for libc and kernel interfaces so result is pointer to char instead |
67 | | * of u_char to minimize casts. |
68 | | */ |
69 | | |
70 | | char * |
71 | | nxt_str_cstrz(nxt_mp_t *mp, const nxt_str_t *src) |
72 | 0 | { |
73 | 0 | char *p, *dst; |
74 | |
|
75 | 0 | dst = nxt_mp_alloc(mp, src->length + 1); |
76 | |
|
77 | 0 | if (nxt_fast_path(dst != NULL)) { |
78 | 0 | p = nxt_cpymem(dst, src->start, src->length); |
79 | 0 | *p = '\0'; |
80 | 0 | } |
81 | |
|
82 | 0 | return dst; |
83 | 0 | } |
84 | | |
85 | | |
86 | | void |
87 | | nxt_memcpy_lowcase(u_char *dst, const u_char *src, size_t length) |
88 | 151 | { |
89 | 151 | u_char c; |
90 | | |
91 | 9.39k | while (length != 0) { |
92 | 9.24k | c = *src++; |
93 | 9.24k | *dst++ = nxt_lowcase(c); |
94 | 9.24k | length--; |
95 | 9.24k | } |
96 | 151 | } |
97 | | |
98 | | |
99 | | void |
100 | | nxt_memcpy_upcase(u_char *dst, const u_char *src, size_t length) |
101 | 0 | { |
102 | 0 | u_char c; |
103 | |
|
104 | 0 | while (length != 0) { |
105 | 0 | c = *src++; |
106 | 0 | *dst++ = nxt_upcase(c); |
107 | 0 | length--; |
108 | 0 | } |
109 | 0 | } |
110 | | |
111 | | |
112 | | u_char * |
113 | | nxt_cpystr(u_char *dst, const u_char *src) |
114 | 0 | { |
115 | 0 | for ( ;; ) { |
116 | 0 | *dst = *src; |
117 | |
|
118 | 0 | if (*dst == '\0') { |
119 | 0 | break; |
120 | 0 | } |
121 | | |
122 | 0 | dst++; |
123 | 0 | src++; |
124 | 0 | } |
125 | |
|
126 | 0 | return dst; |
127 | 0 | } |
128 | | |
129 | | |
130 | | u_char * |
131 | | nxt_cpystrn(u_char *dst, const u_char *src, size_t length) |
132 | 0 | { |
133 | 0 | if (length == 0) { |
134 | 0 | return dst; |
135 | 0 | } |
136 | | |
137 | 0 | while (--length != 0) { |
138 | 0 | *dst = *src; |
139 | |
|
140 | 0 | if (*dst == '\0') { |
141 | 0 | return dst; |
142 | 0 | } |
143 | | |
144 | 0 | dst++; |
145 | 0 | src++; |
146 | 0 | } |
147 | | |
148 | 0 | *dst = '\0'; |
149 | |
|
150 | 0 | return dst; |
151 | 0 | } |
152 | | |
153 | | |
154 | | nxt_int_t |
155 | | nxt_strcasecmp(const u_char *s1, const u_char *s2) |
156 | 0 | { |
157 | 0 | u_char c1, c2; |
158 | 0 | nxt_int_t n; |
159 | |
|
160 | 0 | for ( ;; ) { |
161 | 0 | c1 = *s1++; |
162 | 0 | c2 = *s2++; |
163 | |
|
164 | 0 | c1 = nxt_lowcase(c1); |
165 | 0 | c2 = nxt_lowcase(c2); |
166 | |
|
167 | 0 | n = c1 - c2; |
168 | |
|
169 | 0 | if (n != 0) { |
170 | 0 | return n; |
171 | 0 | } |
172 | | |
173 | 0 | if (c1 == 0) { |
174 | 0 | return 0; |
175 | 0 | } |
176 | 0 | } |
177 | 0 | } |
178 | | |
179 | | |
180 | | nxt_int_t |
181 | | nxt_strncasecmp(const u_char *s1, const u_char *s2, size_t length) |
182 | 0 | { |
183 | 0 | u_char c1, c2; |
184 | 0 | nxt_int_t n; |
185 | |
|
186 | 0 | while (length-- != 0) { |
187 | 0 | c1 = *s1++; |
188 | 0 | c2 = *s2++; |
189 | |
|
190 | 0 | c1 = nxt_lowcase(c1); |
191 | 0 | c2 = nxt_lowcase(c2); |
192 | |
|
193 | 0 | n = c1 - c2; |
194 | |
|
195 | 0 | if (n != 0) { |
196 | 0 | return n; |
197 | 0 | } |
198 | | |
199 | 0 | if (c1 == 0) { |
200 | 0 | return 0; |
201 | 0 | } |
202 | 0 | } |
203 | | |
204 | 0 | return 0; |
205 | 0 | } |
206 | | |
207 | | |
208 | | nxt_int_t |
209 | | nxt_memcasecmp(const void *p1, const void *p2, size_t length) |
210 | 3.74k | { |
211 | 3.74k | u_char c1, c2; |
212 | 3.74k | nxt_int_t n; |
213 | 3.74k | const u_char *s1, *s2; |
214 | | |
215 | 3.74k | s1 = p1; |
216 | 3.74k | s2 = p2; |
217 | | |
218 | 33.0k | while (length-- != 0) { |
219 | 30.6k | c1 = *s1++; |
220 | 30.6k | c2 = *s2++; |
221 | | |
222 | 30.6k | c1 = nxt_lowcase(c1); |
223 | 30.6k | c2 = nxt_lowcase(c2); |
224 | | |
225 | 30.6k | n = c1 - c2; |
226 | | |
227 | 30.6k | if (n != 0) { |
228 | 1.30k | return n; |
229 | 1.30k | } |
230 | 30.6k | } |
231 | | |
232 | 2.43k | return 0; |
233 | 3.74k | } |
234 | | |
235 | | |
236 | | /* |
237 | | * nxt_memstrn() is intended for search of static substring "ss" |
238 | | * with known length "length" in string "s" limited by parameter "end". |
239 | | * Zeros are ignored in both strings. |
240 | | */ |
241 | | |
242 | | u_char * |
243 | | nxt_memstrn(const u_char *s, const u_char *end, const char *ss, size_t length) |
244 | 0 | { |
245 | 0 | u_char c1, c2, *s2; |
246 | |
|
247 | 0 | s2 = (u_char *) ss; |
248 | 0 | c2 = *s2++; |
249 | 0 | length--; |
250 | |
|
251 | 0 | while (s < end) { |
252 | 0 | c1 = *s++; |
253 | |
|
254 | 0 | if (c1 == c2) { |
255 | |
|
256 | 0 | if (s + length > end) { |
257 | 0 | return NULL; |
258 | 0 | } |
259 | | |
260 | 0 | if (memcmp(s, s2, length) == 0) { |
261 | 0 | return (u_char *) s - 1; |
262 | 0 | } |
263 | 0 | } |
264 | 0 | } |
265 | | |
266 | 0 | return NULL; |
267 | 0 | } |
268 | | |
269 | | |
270 | | /* |
271 | | * nxt_strcasestrn() is intended for caseless search of static substring |
272 | | * "ss" with known length "length" in string "s" limited by parameter "end". |
273 | | * Zeros are ignored in both strings. |
274 | | */ |
275 | | |
276 | | u_char * |
277 | | nxt_memcasestrn(const u_char *s, const u_char *end, const char *ss, |
278 | | size_t length) |
279 | 1.80k | { |
280 | 1.80k | u_char c1, c2, *s2; |
281 | | |
282 | 1.80k | s2 = (u_char *) ss; |
283 | 1.80k | c2 = *s2++; |
284 | 1.80k | c2 = nxt_lowcase(c2); |
285 | 1.80k | length--; |
286 | | |
287 | 13.1k | while (s < end) { |
288 | 11.8k | c1 = *s++; |
289 | 11.8k | c1 = nxt_lowcase(c1); |
290 | | |
291 | 11.8k | if (c1 == c2) { |
292 | | |
293 | 1.34k | if (s + length > end) { |
294 | 237 | return NULL; |
295 | 237 | } |
296 | | |
297 | 1.10k | if (nxt_memcasecmp(s, s2, length) == 0) { |
298 | 271 | return (u_char *) s - 1; |
299 | 271 | } |
300 | 1.10k | } |
301 | 11.8k | } |
302 | | |
303 | 1.29k | return NULL; |
304 | 1.80k | } |
305 | | |
306 | | |
307 | | /* |
308 | | * nxt_rstrstrn() is intended to search for static substring "ss" |
309 | | * with known length "length" in string "s" limited by parameter "end" |
310 | | * in reverse order. Zeros are ignored in both strings. |
311 | | */ |
312 | | |
313 | | u_char * |
314 | | nxt_rmemstrn(const u_char *s, const u_char *end, const char *ss, size_t length) |
315 | 0 | { |
316 | 0 | u_char c1, c2; |
317 | 0 | const u_char *s1, *s2; |
318 | |
|
319 | 0 | s1 = end - length; |
320 | 0 | s2 = (u_char *) ss; |
321 | 0 | c2 = *s2++; |
322 | 0 | length--; |
323 | |
|
324 | 0 | while (s < s1) { |
325 | 0 | c1 = *s1; |
326 | |
|
327 | 0 | if (c1 == c2) { |
328 | 0 | if (memcmp(s1 + 1, s2, length) == 0) { |
329 | 0 | return (u_char *) s1; |
330 | 0 | } |
331 | 0 | } |
332 | | |
333 | 0 | s1--; |
334 | 0 | } |
335 | | |
336 | 0 | return NULL; |
337 | 0 | } |
338 | | |
339 | | |
340 | | size_t |
341 | | nxt_str_strip(const u_char *start, u_char *end) |
342 | 0 | { |
343 | 0 | u_char *p; |
344 | |
|
345 | 0 | for (p = end - 1; p >= start; p--) { |
346 | 0 | if (*p != '\r' && *p != '\n') { |
347 | 0 | break; |
348 | 0 | } |
349 | 0 | } |
350 | |
|
351 | 0 | return (p + 1) - start; |
352 | 0 | } |
353 | | |
354 | | |
355 | | nxt_int_t |
356 | | nxt_strverscmp(const u_char *s1, const u_char *s2) |
357 | 0 | { |
358 | 0 | u_char c1, c2; |
359 | 0 | nxt_int_t diff; |
360 | |
|
361 | 0 | enum { |
362 | 0 | st_str = 0, |
363 | 0 | st_num, |
364 | 0 | st_zero, |
365 | 0 | st_frac, |
366 | 0 | } state; |
367 | |
|
368 | 0 | state = st_str; |
369 | |
|
370 | 0 | for ( ;; ) { |
371 | 0 | c1 = *s1++; |
372 | 0 | c2 = *s2++; |
373 | |
|
374 | 0 | diff = c1 - c2; |
375 | |
|
376 | 0 | if (diff != 0) { |
377 | 0 | break; |
378 | 0 | } |
379 | | |
380 | 0 | if (c1 == '\0') { |
381 | 0 | return 0; |
382 | 0 | } |
383 | | |
384 | 0 | if (!nxt_isdigit(c1)) { |
385 | 0 | state = st_str; |
386 | 0 | continue; |
387 | 0 | } |
388 | | |
389 | 0 | if (state == st_str) { |
390 | 0 | state = (c1 != '0') ? st_num : st_zero; |
391 | 0 | continue; |
392 | 0 | } |
393 | | |
394 | 0 | if (state == st_zero && c1 != '0') { |
395 | 0 | state = st_frac; |
396 | 0 | continue; |
397 | 0 | } |
398 | 0 | } |
399 | | |
400 | 0 | switch (state) { |
401 | | |
402 | 0 | case st_str: |
403 | |
|
404 | 0 | if ((u_char) (c1 - '1') > 8 || (u_char) (c2 - '1') > 8) { |
405 | 0 | return diff; |
406 | 0 | } |
407 | | |
408 | 0 | c1 = *s1++; |
409 | 0 | c2 = *s2++; |
410 | | |
411 | | /* Fall through. */ |
412 | |
|
413 | 0 | case st_num: |
414 | |
|
415 | 0 | while (nxt_isdigit(c1) && nxt_isdigit(c2)) { |
416 | 0 | c1 = *s1++; |
417 | 0 | c2 = *s2++; |
418 | 0 | } |
419 | |
|
420 | 0 | if (nxt_isdigit(c1)) { |
421 | 0 | return 1; |
422 | 0 | } |
423 | | |
424 | 0 | if (nxt_isdigit(c2)) { |
425 | 0 | return -1; |
426 | 0 | } |
427 | | |
428 | 0 | return diff; |
429 | | |
430 | 0 | case st_zero: |
431 | |
|
432 | 0 | if (c1 == '0' || c2 == '\0') { |
433 | 0 | return -1; |
434 | 0 | } |
435 | | |
436 | 0 | if (c2 == '0' || c1 == '\0') { |
437 | 0 | return 1; |
438 | 0 | } |
439 | | |
440 | | /* Fall through. */ |
441 | | |
442 | 0 | case st_frac: |
443 | 0 | default: |
444 | 0 | return diff; |
445 | 0 | } |
446 | 0 | } |
447 | | |
448 | | |
449 | | nxt_bool_t |
450 | | nxt_strvers_match(u_char *version, u_char *prefix, size_t length) |
451 | 0 | { |
452 | 0 | u_char next, last; |
453 | |
|
454 | 0 | if (length == 0) { |
455 | 0 | return 1; |
456 | 0 | } |
457 | | |
458 | 0 | if (nxt_strncmp(version, prefix, length) == 0) { |
459 | |
|
460 | 0 | next = version[length]; |
461 | |
|
462 | 0 | if (next == '\0') { |
463 | 0 | return 1; |
464 | 0 | } |
465 | | |
466 | 0 | last = version[length - 1]; |
467 | |
|
468 | 0 | if (nxt_isdigit(last) != nxt_isdigit(next)) { |
469 | | /* This is a version part boundary. */ |
470 | 0 | return 1; |
471 | 0 | } |
472 | 0 | } |
473 | | |
474 | 0 | return 0; |
475 | 0 | } |
476 | | |
477 | | |
478 | | const uint8_t nxt_hex2int[256] |
479 | | nxt_aligned(32) = |
480 | | { |
481 | | 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, |
482 | | 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, |
483 | | 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, |
484 | | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 16, 16, 16, 16, 16, 16, |
485 | | 16, 10, 11, 12, 13, 14, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, |
486 | | 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, |
487 | | 16, 10, 11, 12, 13, 14, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, |
488 | | 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, |
489 | | 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, |
490 | | 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, |
491 | | 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, |
492 | | 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, |
493 | | 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, |
494 | | 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, |
495 | | 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, |
496 | | 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, |
497 | | }; |
498 | | |
499 | | |
500 | | static const uint32_t nxt_uri_escape[] = { |
501 | | 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ |
502 | | |
503 | | /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */ |
504 | | 0xd000002d, /* 1101 0000 0000 0000 0000 0000 0010 1101 */ |
505 | | |
506 | | /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */ |
507 | | 0x50000000, /* 0101 0000 0000 0000 0000 0000 0000 0000 */ |
508 | | |
509 | | /* ~}| {zyx wvut srqp onml kjih gfed cba` */ |
510 | | 0xb8000001, /* 1011 1000 0000 0000 0000 0000 0000 0001 */ |
511 | | |
512 | | 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ |
513 | | 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ |
514 | | 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ |
515 | | 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */ |
516 | | }; |
517 | | |
518 | | |
519 | | u_char * |
520 | | nxt_decode_uri(u_char *dst, u_char *src, size_t length) |
521 | 0 | { |
522 | 0 | u_char *end, ch; |
523 | 0 | uint8_t d0, d1; |
524 | |
|
525 | 0 | nxt_prefetch(&nxt_hex2int['0']); |
526 | |
|
527 | 0 | end = src + length; |
528 | |
|
529 | 0 | while (src < end) { |
530 | 0 | ch = *src++; |
531 | |
|
532 | 0 | if (ch == '%') { |
533 | 0 | if (nxt_slow_path(end - src < 2)) { |
534 | 0 | return NULL; |
535 | 0 | } |
536 | | |
537 | 0 | d0 = nxt_hex2int[*src++]; |
538 | 0 | d1 = nxt_hex2int[*src++]; |
539 | |
|
540 | 0 | if (nxt_slow_path((d0 | d1) >= 16)) { |
541 | 0 | return NULL; |
542 | 0 | } |
543 | | |
544 | 0 | ch = (d0 << 4) + d1; |
545 | 0 | } |
546 | | |
547 | 0 | *dst++ = ch; |
548 | 0 | } |
549 | | |
550 | 0 | return dst; |
551 | 0 | } |
552 | | |
553 | | |
554 | | u_char * |
555 | | nxt_decode_uri_plus(u_char *dst, u_char *src, size_t length) |
556 | 0 | { |
557 | 0 | u_char *end, ch; |
558 | 0 | uint8_t d0, d1; |
559 | |
|
560 | 0 | nxt_prefetch(&nxt_hex2int['0']); |
561 | |
|
562 | 0 | end = src + length; |
563 | |
|
564 | 0 | while (src < end) { |
565 | 0 | ch = *src++; |
566 | |
|
567 | 0 | switch (ch) { |
568 | 0 | case '%': |
569 | 0 | if (nxt_slow_path(end - src < 2)) { |
570 | 0 | return NULL; |
571 | 0 | } |
572 | | |
573 | 0 | d0 = nxt_hex2int[*src++]; |
574 | 0 | d1 = nxt_hex2int[*src++]; |
575 | |
|
576 | 0 | if (nxt_slow_path((d0 | d1) >= 16)) { |
577 | 0 | return NULL; |
578 | 0 | } |
579 | | |
580 | 0 | ch = (d0 << 4) + d1; |
581 | 0 | break; |
582 | | |
583 | 0 | case '+': |
584 | 0 | ch = ' '; |
585 | 0 | break; |
586 | 0 | } |
587 | | |
588 | 0 | *dst++ = ch; |
589 | 0 | } |
590 | | |
591 | 0 | return dst; |
592 | 0 | } |
593 | | |
594 | | |
595 | | uintptr_t |
596 | | nxt_encode_uri(u_char *dst, u_char *src, size_t length) |
597 | 0 | { |
598 | 0 | u_char *end; |
599 | 0 | nxt_uint_t n; |
600 | |
|
601 | 0 | static const u_char hex[16] NXT_NONSTRING = "0123456789ABCDEF"; |
602 | |
|
603 | 0 | end = src + length; |
604 | |
|
605 | 0 | if (dst == NULL) { |
606 | | |
607 | | /* Find the number of the characters to be escaped. */ |
608 | |
|
609 | 0 | n = 0; |
610 | |
|
611 | 0 | while (src < end) { |
612 | |
|
613 | 0 | if (nxt_uri_escape[*src >> 5] & (1U << (*src & 0x1f))) { |
614 | 0 | n++; |
615 | 0 | } |
616 | |
|
617 | 0 | src++; |
618 | 0 | } |
619 | |
|
620 | 0 | return (uintptr_t) n; |
621 | 0 | } |
622 | | |
623 | 0 | while (src < end) { |
624 | |
|
625 | 0 | if (nxt_uri_escape[*src >> 5] & (1U << (*src & 0x1f))) { |
626 | 0 | *dst++ = '%'; |
627 | 0 | *dst++ = hex[*src >> 4]; |
628 | 0 | *dst++ = hex[*src & 0xf]; |
629 | |
|
630 | 0 | } else { |
631 | 0 | *dst++ = *src; |
632 | 0 | } |
633 | |
|
634 | 0 | src++; |
635 | 0 | } |
636 | |
|
637 | 0 | return (uintptr_t) dst; |
638 | 0 | } |
639 | | |
640 | | |
641 | | uintptr_t |
642 | | nxt_encode_complex_uri(u_char *dst, u_char *src, size_t length) |
643 | 0 | { |
644 | 0 | u_char *reserved, *end, ch; |
645 | 0 | nxt_uint_t n; |
646 | |
|
647 | 0 | static const u_char hex[16] NXT_NONSTRING = "0123456789ABCDEF"; |
648 | |
|
649 | 0 | reserved = (u_char *) "?#\0"; |
650 | |
|
651 | 0 | end = src + length; |
652 | |
|
653 | 0 | if (dst == NULL) { |
654 | | |
655 | | /* Find the number of the characters to be escaped. */ |
656 | |
|
657 | 0 | n = 0; |
658 | |
|
659 | 0 | while (src < end) { |
660 | 0 | ch = *src++; |
661 | |
|
662 | 0 | if (nxt_uri_escape[ch >> 5] & (1U << (ch & 0x1f))) { |
663 | 0 | if (ch == reserved[0]) { |
664 | 0 | reserved++; |
665 | 0 | continue; |
666 | 0 | } |
667 | | |
668 | 0 | if (ch == reserved[1]) { |
669 | 0 | reserved += 2; |
670 | 0 | continue; |
671 | 0 | } |
672 | | |
673 | 0 | n++; |
674 | 0 | } |
675 | 0 | } |
676 | |
|
677 | 0 | return (uintptr_t) n; |
678 | 0 | } |
679 | | |
680 | 0 | while (src < end) { |
681 | 0 | ch = *src++; |
682 | |
|
683 | 0 | if (nxt_uri_escape[ch >> 5] & (1U << (ch & 0x1f))) { |
684 | 0 | if (ch == reserved[0]) { |
685 | 0 | reserved++; |
686 | |
|
687 | 0 | } else if (ch == reserved[1]) { |
688 | 0 | reserved += 2; |
689 | |
|
690 | 0 | } else { |
691 | 0 | *dst++ = '%'; |
692 | 0 | *dst++ = hex[ch >> 4]; |
693 | 0 | *dst++ = hex[ch & 0xf]; |
694 | 0 | continue; |
695 | 0 | } |
696 | 0 | } |
697 | | |
698 | 0 | *dst++ = ch; |
699 | 0 | } |
700 | |
|
701 | 0 | return (uintptr_t) dst; |
702 | 0 | } |
703 | | |
704 | | |
705 | | nxt_bool_t |
706 | | nxt_is_complex_uri_encoded(u_char *src, size_t length) |
707 | 0 | { |
708 | 0 | u_char *reserved, *end, ch; |
709 | 0 | uint8_t d0, d1; |
710 | |
|
711 | 0 | reserved = (u_char *) "?#\0"; |
712 | |
|
713 | 0 | for (end = src + length; src < end; src++) { |
714 | 0 | ch = *src; |
715 | |
|
716 | 0 | if (nxt_uri_escape[ch >> 5] & (1U << (ch & 0x1f))) { |
717 | 0 | if (ch == '%') { |
718 | 0 | if (end - src < 2) { |
719 | 0 | return 0; |
720 | 0 | } |
721 | | |
722 | 0 | d0 = nxt_hex2int[*++src]; |
723 | 0 | d1 = nxt_hex2int[*++src]; |
724 | |
|
725 | 0 | if ((d0 | d1) >= 16) { |
726 | 0 | return 0; |
727 | 0 | } |
728 | | |
729 | 0 | continue; |
730 | 0 | } |
731 | | |
732 | 0 | if (ch == reserved[0]) { |
733 | 0 | reserved++; |
734 | 0 | continue; |
735 | 0 | } |
736 | | |
737 | 0 | if (ch == reserved[1]) { |
738 | 0 | reserved += 2; |
739 | 0 | continue; |
740 | 0 | } |
741 | | |
742 | 0 | return 0; |
743 | 0 | } |
744 | 0 | } |
745 | | |
746 | 0 | return 1; |
747 | 0 | } |
748 | | |
749 | | |
750 | | ssize_t |
751 | | nxt_base64_decode(u_char *dst, u_char *src, size_t length) |
752 | 0 | { |
753 | 0 | u_char *end, *p; |
754 | 0 | size_t pad; |
755 | 0 | uint8_t v1, v2, v3, v4; |
756 | |
|
757 | 0 | static const uint8_t decode[] = { |
758 | 0 | 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, |
759 | 0 | 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, |
760 | 0 | 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 62, 77, 77, 77, 63, |
761 | 0 | 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 77, 77, 77, 77, 77, 77, |
762 | 0 | 77, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, |
763 | 0 | 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 77, 77, 77, 77, 77, |
764 | 0 | 77, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, |
765 | 0 | 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 77, 77, 77, 77, 77, |
766 | |
|
767 | 0 | 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, |
768 | 0 | 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, |
769 | 0 | 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, |
770 | 0 | 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, |
771 | 0 | 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, |
772 | 0 | 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, |
773 | 0 | 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, |
774 | 0 | 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77 |
775 | 0 | }; |
776 | |
|
777 | 0 | end = src + length; |
778 | 0 | pad = (4 - (length % 4)) % 4; |
779 | |
|
780 | 0 | if (dst == NULL) { |
781 | 0 | if (pad > 2) { |
782 | 0 | return NXT_ERROR; |
783 | 0 | } |
784 | | |
785 | 0 | while (src < end) { |
786 | 0 | if (decode[*src] != 77) { |
787 | 0 | src++; |
788 | 0 | continue; |
789 | 0 | } |
790 | | |
791 | 0 | if (pad == 0) { |
792 | 0 | pad = end - src; |
793 | |
|
794 | 0 | if ((pad == 1 || (pad == 2 && src[1] == '=')) && src[0] == '=') |
795 | 0 | { |
796 | 0 | break; |
797 | 0 | } |
798 | 0 | } |
799 | | |
800 | 0 | return NXT_ERROR; |
801 | 0 | } |
802 | | |
803 | 0 | return (length + 3) / 4 * 3 - pad; |
804 | 0 | } |
805 | | |
806 | 0 | nxt_assert(length != 0); |
807 | |
|
808 | 0 | if (pad == 0) { |
809 | 0 | pad = (end[-1] == '=') + (end[-2] == '='); |
810 | 0 | end -= (pad + 3) & 4; |
811 | |
|
812 | 0 | } else { |
813 | 0 | end -= 4 - pad; |
814 | 0 | } |
815 | |
|
816 | 0 | p = dst; |
817 | |
|
818 | 0 | while (src < end) { |
819 | 0 | v1 = decode[src[0]]; |
820 | 0 | v2 = decode[src[1]]; |
821 | 0 | v3 = decode[src[2]]; |
822 | 0 | v4 = decode[src[3]]; |
823 | |
|
824 | 0 | *p++ = (v1 << 2 | v2 >> 4); |
825 | 0 | *p++ = (v2 << 4 | v3 >> 2); |
826 | 0 | *p++ = (v3 << 6 | v4); |
827 | |
|
828 | 0 | src += 4; |
829 | 0 | } |
830 | |
|
831 | 0 | if (pad > 0) { |
832 | 0 | v1 = decode[src[0]]; |
833 | 0 | v2 = decode[src[1]]; |
834 | |
|
835 | 0 | *p++ = (v1 << 2 | v2 >> 4); |
836 | |
|
837 | 0 | if (pad == 1) { |
838 | 0 | v3 = decode[src[2]]; |
839 | 0 | *p++ = (v2 << 4 | v3 >> 2); |
840 | 0 | } |
841 | 0 | } |
842 | |
|
843 | 0 | return (p - dst); |
844 | 0 | } |