xref: /unit/src/nxt_string.c (revision 1431)
10Sigor@sysoev.ru 
20Sigor@sysoev.ru /*
30Sigor@sysoev.ru  * Copyright (C) Igor Sysoev
40Sigor@sysoev.ru  * Copyright (C) NGINX, Inc.
50Sigor@sysoev.ru  */
60Sigor@sysoev.ru 
70Sigor@sysoev.ru #include <nxt_main.h>
80Sigor@sysoev.ru 
90Sigor@sysoev.ru 
100Sigor@sysoev.ru nxt_str_t *
1165Sigor@sysoev.ru nxt_str_alloc(nxt_mp_t *mp, size_t length)
120Sigor@sysoev.ru {
130Sigor@sysoev.ru     nxt_str_t  *s;
140Sigor@sysoev.ru 
1510Sigor@sysoev.ru     /* The string start is allocated aligned to be close to nxt_str_t. */
1665Sigor@sysoev.ru     s = nxt_mp_get(mp, sizeof(nxt_str_t) + length);
170Sigor@sysoev.ru 
180Sigor@sysoev.ru     if (nxt_fast_path(s != NULL)) {
1910Sigor@sysoev.ru         s->length = length;
2098Svbart@nginx.com         s->start = nxt_pointer_to(s, sizeof(nxt_str_t));
210Sigor@sysoev.ru     }
220Sigor@sysoev.ru 
230Sigor@sysoev.ru     return s;
240Sigor@sysoev.ru }
250Sigor@sysoev.ru 
260Sigor@sysoev.ru 
270Sigor@sysoev.ru /*
280Sigor@sysoev.ru  * nxt_str_dup() creates a new string with a copy of a source string.
290Sigor@sysoev.ru  * If length of the source string is zero, then the new string anyway
300Sigor@sysoev.ru  * gets a pointer somewhere in mem_pool.
310Sigor@sysoev.ru  */
320Sigor@sysoev.ru 
330Sigor@sysoev.ru nxt_str_t *
3465Sigor@sysoev.ru nxt_str_dup(nxt_mp_t *mp, nxt_str_t *dst, const nxt_str_t *src)
350Sigor@sysoev.ru {
360Sigor@sysoev.ru     u_char  *p;
370Sigor@sysoev.ru 
380Sigor@sysoev.ru     if (dst == NULL) {
3910Sigor@sysoev.ru         /* The string start is allocated aligned to be close to nxt_str_t. */
4065Sigor@sysoev.ru         dst = nxt_mp_get(mp, sizeof(nxt_str_t) + src->length);
410Sigor@sysoev.ru         if (nxt_slow_path(dst == NULL)) {
420Sigor@sysoev.ru             return NULL;
430Sigor@sysoev.ru         }
440Sigor@sysoev.ru 
450Sigor@sysoev.ru         p = (u_char *) dst;
460Sigor@sysoev.ru         p += sizeof(nxt_str_t);
4710Sigor@sysoev.ru         dst->start = p;
480Sigor@sysoev.ru 
490Sigor@sysoev.ru     } else {
5065Sigor@sysoev.ru         dst->start = nxt_mp_nget(mp, src->length);
5110Sigor@sysoev.ru         if (nxt_slow_path(dst->start == NULL)) {
520Sigor@sysoev.ru             return NULL;
530Sigor@sysoev.ru         }
540Sigor@sysoev.ru     }
550Sigor@sysoev.ru 
5610Sigor@sysoev.ru     nxt_memcpy(dst->start, src->start, src->length);
5710Sigor@sysoev.ru     dst->length = src->length;
580Sigor@sysoev.ru 
590Sigor@sysoev.ru     return dst;
600Sigor@sysoev.ru }
610Sigor@sysoev.ru 
620Sigor@sysoev.ru 
630Sigor@sysoev.ru /*
64212Svbart@nginx.com  * nxt_str_cstrz() creates a C style zero-terminated copy of a source
650Sigor@sysoev.ru  * nxt_str_t.  The function is intended to create strings suitable
660Sigor@sysoev.ru  * for libc and kernel interfaces so result is pointer to char instead
67216Sigor@sysoev.ru  * of u_char to minimize casts.
680Sigor@sysoev.ru  */
690Sigor@sysoev.ru 
700Sigor@sysoev.ru char *
71212Svbart@nginx.com nxt_str_cstrz(nxt_mp_t *mp, const nxt_str_t *src)
720Sigor@sysoev.ru {
730Sigor@sysoev.ru     char  *p, *dst;
740Sigor@sysoev.ru 
75216Sigor@sysoev.ru     dst = nxt_mp_alloc(mp, src->length + 1);
760Sigor@sysoev.ru 
770Sigor@sysoev.ru     if (nxt_fast_path(dst != NULL)) {
7810Sigor@sysoev.ru         p = nxt_cpymem(dst, src->start, src->length);
790Sigor@sysoev.ru         *p = '\0';
800Sigor@sysoev.ru     }
810Sigor@sysoev.ru 
820Sigor@sysoev.ru     return dst;
830Sigor@sysoev.ru }
840Sigor@sysoev.ru 
850Sigor@sysoev.ru 
860Sigor@sysoev.ru void
8710Sigor@sysoev.ru nxt_memcpy_lowcase(u_char *dst, const u_char *src, size_t length)
880Sigor@sysoev.ru {
890Sigor@sysoev.ru     u_char  c;
900Sigor@sysoev.ru 
9110Sigor@sysoev.ru     while (length != 0) {
920Sigor@sysoev.ru         c = *src++;
930Sigor@sysoev.ru         *dst++ = nxt_lowcase(c);
9410Sigor@sysoev.ru         length--;
950Sigor@sysoev.ru     }
960Sigor@sysoev.ru }
970Sigor@sysoev.ru 
980Sigor@sysoev.ru 
99963Sigor@sysoev.ru void
100963Sigor@sysoev.ru nxt_memcpy_upcase(u_char *dst, const u_char *src, size_t length)
101963Sigor@sysoev.ru {
102963Sigor@sysoev.ru     u_char  c;
103963Sigor@sysoev.ru 
104963Sigor@sysoev.ru     while (length != 0) {
105963Sigor@sysoev.ru         c = *src++;
106963Sigor@sysoev.ru         *dst++ = nxt_upcase(c);
107963Sigor@sysoev.ru         length--;
108963Sigor@sysoev.ru     }
109963Sigor@sysoev.ru }
110963Sigor@sysoev.ru 
111963Sigor@sysoev.ru 
1120Sigor@sysoev.ru u_char *
11310Sigor@sysoev.ru nxt_cpystrn(u_char *dst, const u_char *src, size_t length)
1140Sigor@sysoev.ru {
11510Sigor@sysoev.ru     if (length == 0) {
1160Sigor@sysoev.ru         return dst;
1170Sigor@sysoev.ru     }
1180Sigor@sysoev.ru 
11910Sigor@sysoev.ru     while (--length != 0) {
1200Sigor@sysoev.ru         *dst = *src;
1210Sigor@sysoev.ru 
1220Sigor@sysoev.ru         if (*dst == '\0') {
1230Sigor@sysoev.ru             return dst;
1240Sigor@sysoev.ru         }
1250Sigor@sysoev.ru 
1260Sigor@sysoev.ru         dst++;
1270Sigor@sysoev.ru         src++;
1280Sigor@sysoev.ru     }
1290Sigor@sysoev.ru 
1300Sigor@sysoev.ru     *dst = '\0';
1310Sigor@sysoev.ru 
1320Sigor@sysoev.ru     return dst;
1330Sigor@sysoev.ru }
1340Sigor@sysoev.ru 
1350Sigor@sysoev.ru 
1360Sigor@sysoev.ru nxt_int_t
1370Sigor@sysoev.ru nxt_strcasecmp(const u_char *s1, const u_char *s2)
1380Sigor@sysoev.ru {
1390Sigor@sysoev.ru     u_char     c1, c2;
1400Sigor@sysoev.ru     nxt_int_t  n;
1410Sigor@sysoev.ru 
1420Sigor@sysoev.ru     for ( ;; ) {
1430Sigor@sysoev.ru         c1 = *s1++;
1440Sigor@sysoev.ru         c2 = *s2++;
1450Sigor@sysoev.ru 
1460Sigor@sysoev.ru         c1 = nxt_lowcase(c1);
1470Sigor@sysoev.ru         c2 = nxt_lowcase(c2);
1480Sigor@sysoev.ru 
1490Sigor@sysoev.ru         n = c1 - c2;
1500Sigor@sysoev.ru 
1510Sigor@sysoev.ru         if (n != 0) {
1520Sigor@sysoev.ru             return n;
1530Sigor@sysoev.ru         }
1540Sigor@sysoev.ru 
1550Sigor@sysoev.ru         if (c1 == 0) {
1560Sigor@sysoev.ru             return 0;
1570Sigor@sysoev.ru         }
1580Sigor@sysoev.ru     }
1590Sigor@sysoev.ru }
1600Sigor@sysoev.ru 
1610Sigor@sysoev.ru 
1620Sigor@sysoev.ru nxt_int_t
16310Sigor@sysoev.ru nxt_strncasecmp(const u_char *s1, const u_char *s2, size_t length)
1640Sigor@sysoev.ru {
1650Sigor@sysoev.ru     u_char     c1, c2;
1660Sigor@sysoev.ru     nxt_int_t  n;
1670Sigor@sysoev.ru 
16810Sigor@sysoev.ru     while (length-- != 0) {
1690Sigor@sysoev.ru         c1 = *s1++;
1700Sigor@sysoev.ru         c2 = *s2++;
1710Sigor@sysoev.ru 
1720Sigor@sysoev.ru         c1 = nxt_lowcase(c1);
1730Sigor@sysoev.ru         c2 = nxt_lowcase(c2);
1740Sigor@sysoev.ru 
1750Sigor@sysoev.ru         n = c1 - c2;
1760Sigor@sysoev.ru 
1770Sigor@sysoev.ru         if (n != 0) {
1780Sigor@sysoev.ru             return n;
1790Sigor@sysoev.ru         }
1800Sigor@sysoev.ru 
1810Sigor@sysoev.ru         if (c1 == 0) {
1820Sigor@sysoev.ru             return 0;
1830Sigor@sysoev.ru         }
1840Sigor@sysoev.ru     }
1850Sigor@sysoev.ru 
1860Sigor@sysoev.ru     return 0;
1870Sigor@sysoev.ru }
1880Sigor@sysoev.ru 
1890Sigor@sysoev.ru 
1900Sigor@sysoev.ru nxt_int_t
1911234Sigor@sysoev.ru nxt_memcasecmp(const void *p1, const void *p2, size_t length)
1920Sigor@sysoev.ru {
1931234Sigor@sysoev.ru     u_char        c1, c2;
1941234Sigor@sysoev.ru     nxt_int_t     n;
1951234Sigor@sysoev.ru     const u_char  *s1, *s2;
1961234Sigor@sysoev.ru 
1971234Sigor@sysoev.ru     s1 = p1;
1981234Sigor@sysoev.ru     s2 = p2;
1990Sigor@sysoev.ru 
20010Sigor@sysoev.ru     while (length-- != 0) {
2010Sigor@sysoev.ru         c1 = *s1++;
2020Sigor@sysoev.ru         c2 = *s2++;
2030Sigor@sysoev.ru 
2040Sigor@sysoev.ru         c1 = nxt_lowcase(c1);
2050Sigor@sysoev.ru         c2 = nxt_lowcase(c2);
2060Sigor@sysoev.ru 
2070Sigor@sysoev.ru         n = c1 - c2;
2080Sigor@sysoev.ru 
2090Sigor@sysoev.ru         if (n != 0) {
2100Sigor@sysoev.ru             return n;
2110Sigor@sysoev.ru         }
2120Sigor@sysoev.ru     }
2130Sigor@sysoev.ru 
2140Sigor@sysoev.ru     return 0;
2150Sigor@sysoev.ru }
2160Sigor@sysoev.ru 
2170Sigor@sysoev.ru 
2180Sigor@sysoev.ru /*
2190Sigor@sysoev.ru  * nxt_memstrn() is intended for search of static substring "ss"
22010Sigor@sysoev.ru  * with known length "length" in string "s" limited by parameter "end".
2210Sigor@sysoev.ru  * Zeros are ignored in both strings.
2220Sigor@sysoev.ru  */
2230Sigor@sysoev.ru 
2240Sigor@sysoev.ru u_char *
22510Sigor@sysoev.ru nxt_memstrn(const u_char *s, const u_char *end, const char *ss, size_t length)
2260Sigor@sysoev.ru {
2270Sigor@sysoev.ru     u_char  c1, c2, *s2;
2280Sigor@sysoev.ru 
2290Sigor@sysoev.ru     s2 = (u_char *) ss;
2300Sigor@sysoev.ru     c2 = *s2++;
23110Sigor@sysoev.ru     length--;
2320Sigor@sysoev.ru 
2330Sigor@sysoev.ru     while (s < end) {
2340Sigor@sysoev.ru         c1 = *s++;
2350Sigor@sysoev.ru 
2360Sigor@sysoev.ru         if (c1 == c2) {
2370Sigor@sysoev.ru 
23810Sigor@sysoev.ru             if (s + length > end) {
2390Sigor@sysoev.ru                 return NULL;
2400Sigor@sysoev.ru             }
2410Sigor@sysoev.ru 
24210Sigor@sysoev.ru             if (nxt_memcmp(s, s2, length) == 0) {
2430Sigor@sysoev.ru                 return (u_char *) s - 1;
2440Sigor@sysoev.ru             }
2450Sigor@sysoev.ru         }
2460Sigor@sysoev.ru     }
2470Sigor@sysoev.ru 
2480Sigor@sysoev.ru     return NULL;
2490Sigor@sysoev.ru }
2500Sigor@sysoev.ru 
2510Sigor@sysoev.ru 
2520Sigor@sysoev.ru /*
2530Sigor@sysoev.ru  * nxt_strcasestrn() is intended for caseless search of static substring
25410Sigor@sysoev.ru  * "ss" with known length "length" in string "s" limited by parameter "end".
2550Sigor@sysoev.ru  * Zeros are ignored in both strings.
2560Sigor@sysoev.ru  */
2570Sigor@sysoev.ru 
2580Sigor@sysoev.ru u_char *
25910Sigor@sysoev.ru nxt_memcasestrn(const u_char *s, const u_char *end, const char *ss,
26010Sigor@sysoev.ru     size_t length)
2610Sigor@sysoev.ru {
2620Sigor@sysoev.ru     u_char  c1, c2, *s2;
2630Sigor@sysoev.ru 
2640Sigor@sysoev.ru     s2 = (u_char *) ss;
2650Sigor@sysoev.ru     c2 = *s2++;
2660Sigor@sysoev.ru     c2 = nxt_lowcase(c2);
26710Sigor@sysoev.ru     length--;
2680Sigor@sysoev.ru 
2690Sigor@sysoev.ru     while (s < end) {
2700Sigor@sysoev.ru         c1 = *s++;
2710Sigor@sysoev.ru         c1 = nxt_lowcase(c1);
2720Sigor@sysoev.ru 
2730Sigor@sysoev.ru         if (c1 == c2) {
2740Sigor@sysoev.ru 
27510Sigor@sysoev.ru             if (s + length > end) {
2760Sigor@sysoev.ru                 return NULL;
2770Sigor@sysoev.ru             }
2780Sigor@sysoev.ru 
27910Sigor@sysoev.ru             if (nxt_memcasecmp(s, s2, length) == 0) {
2800Sigor@sysoev.ru                 return (u_char *) s - 1;
2810Sigor@sysoev.ru             }
2820Sigor@sysoev.ru         }
2830Sigor@sysoev.ru     }
2840Sigor@sysoev.ru 
2850Sigor@sysoev.ru     return NULL;
2860Sigor@sysoev.ru }
2870Sigor@sysoev.ru 
2880Sigor@sysoev.ru 
2890Sigor@sysoev.ru /*
2900Sigor@sysoev.ru  * nxt_rstrstrn() is intended to search for static substring "ss"
29110Sigor@sysoev.ru  * with known length "length" in string "s" limited by parameter "end"
2920Sigor@sysoev.ru  * in reverse order.  Zeros are ignored in both strings.
2930Sigor@sysoev.ru  */
2940Sigor@sysoev.ru 
2950Sigor@sysoev.ru u_char *
29610Sigor@sysoev.ru nxt_rmemstrn(const u_char *s, const u_char *end, const char *ss, size_t length)
2970Sigor@sysoev.ru {
2980Sigor@sysoev.ru     u_char        c1, c2;
2990Sigor@sysoev.ru     const u_char  *s1, *s2;
3000Sigor@sysoev.ru 
30110Sigor@sysoev.ru     s1 = end - length;
3020Sigor@sysoev.ru     s2 = (u_char *) ss;
3030Sigor@sysoev.ru     c2 = *s2++;
30410Sigor@sysoev.ru     length--;
3050Sigor@sysoev.ru 
3060Sigor@sysoev.ru     while (s < s1) {
3070Sigor@sysoev.ru         c1 = *s1;
3080Sigor@sysoev.ru 
3090Sigor@sysoev.ru         if (c1 == c2) {
31010Sigor@sysoev.ru             if (nxt_memcmp(s1 + 1, s2, length) == 0) {
3110Sigor@sysoev.ru                 return (u_char *) s1;
3120Sigor@sysoev.ru             }
3130Sigor@sysoev.ru         }
3140Sigor@sysoev.ru 
3150Sigor@sysoev.ru         s1--;
3160Sigor@sysoev.ru     }
3170Sigor@sysoev.ru 
3180Sigor@sysoev.ru     return NULL;
3190Sigor@sysoev.ru }
3200Sigor@sysoev.ru 
3210Sigor@sysoev.ru 
3220Sigor@sysoev.ru size_t
3230Sigor@sysoev.ru nxt_str_strip(u_char *start, u_char *end)
3240Sigor@sysoev.ru {
3250Sigor@sysoev.ru     u_char  *p;
3260Sigor@sysoev.ru 
3270Sigor@sysoev.ru     for (p = end - 1; p >= start; p--) {
328704Sigor@sysoev.ru         if (*p != '\r' && *p != '\n') {
3290Sigor@sysoev.ru             break;
3300Sigor@sysoev.ru         }
3310Sigor@sysoev.ru     }
3320Sigor@sysoev.ru 
3330Sigor@sysoev.ru     return (p + 1) - start;
3340Sigor@sysoev.ru }
335354Svbart@nginx.com 
336354Svbart@nginx.com 
337354Svbart@nginx.com nxt_int_t
338354Svbart@nginx.com nxt_strverscmp(const u_char *s1, const u_char *s2)
339354Svbart@nginx.com {
340354Svbart@nginx.com     u_char     c1, c2;
341354Svbart@nginx.com     nxt_int_t  diff;
342354Svbart@nginx.com 
343354Svbart@nginx.com     enum {
344354Svbart@nginx.com         st_str = 0,
345354Svbart@nginx.com         st_num,
346354Svbart@nginx.com         st_zero,
347354Svbart@nginx.com         st_frac,
348354Svbart@nginx.com     } state;
349354Svbart@nginx.com 
350354Svbart@nginx.com     state = st_str;
351354Svbart@nginx.com 
352354Svbart@nginx.com     for ( ;; ) {
353354Svbart@nginx.com         c1 = *s1++;
354354Svbart@nginx.com         c2 = *s2++;
355354Svbart@nginx.com 
356354Svbart@nginx.com         diff = c1 - c2;
357354Svbart@nginx.com 
358354Svbart@nginx.com         if (diff != 0) {
359354Svbart@nginx.com             break;
360354Svbart@nginx.com         }
361354Svbart@nginx.com 
362354Svbart@nginx.com         if (c1 == '\0') {
363354Svbart@nginx.com             return 0;
364354Svbart@nginx.com         }
365354Svbart@nginx.com 
366354Svbart@nginx.com         if (!nxt_isdigit(c1)) {
367354Svbart@nginx.com             state = st_str;
368354Svbart@nginx.com             continue;
369354Svbart@nginx.com         }
370354Svbart@nginx.com 
371354Svbart@nginx.com         if (state == st_str) {
372354Svbart@nginx.com             state = (c1 != '0') ? st_num : st_zero;
373354Svbart@nginx.com             continue;
374354Svbart@nginx.com         }
375354Svbart@nginx.com 
376354Svbart@nginx.com         if (state == st_zero && c1 != '0') {
377354Svbart@nginx.com             state = st_frac;
378354Svbart@nginx.com             continue;
379354Svbart@nginx.com         }
380354Svbart@nginx.com     }
381354Svbart@nginx.com 
382354Svbart@nginx.com     switch (state) {
383354Svbart@nginx.com 
384354Svbart@nginx.com     case st_str:
385354Svbart@nginx.com 
386354Svbart@nginx.com         if ((u_char) (c1 - '1') > 8 || (u_char) (c2 - '1') > 8) {
387354Svbart@nginx.com             return diff;
388354Svbart@nginx.com         }
389354Svbart@nginx.com 
390354Svbart@nginx.com         c1 = *s1++;
391354Svbart@nginx.com         c2 = *s2++;
392354Svbart@nginx.com 
393354Svbart@nginx.com         /* Fall through. */
394354Svbart@nginx.com 
395354Svbart@nginx.com     case st_num:
396354Svbart@nginx.com 
397354Svbart@nginx.com         while (nxt_isdigit(c1) && nxt_isdigit(c2)) {
398354Svbart@nginx.com             c1 = *s1++;
399354Svbart@nginx.com             c2 = *s2++;
400354Svbart@nginx.com         }
401354Svbart@nginx.com 
402354Svbart@nginx.com         if (nxt_isdigit(c1)) {
403354Svbart@nginx.com             return 1;
404354Svbart@nginx.com         }
405354Svbart@nginx.com 
406354Svbart@nginx.com         if (nxt_isdigit(c2)) {
407354Svbart@nginx.com             return -1;
408354Svbart@nginx.com         }
409354Svbart@nginx.com 
410354Svbart@nginx.com         return diff;
411354Svbart@nginx.com 
412354Svbart@nginx.com     case st_zero:
413354Svbart@nginx.com 
414354Svbart@nginx.com         if (c1 == '0' || c2 == '\0') {
415354Svbart@nginx.com             return -1;
416354Svbart@nginx.com         }
417354Svbart@nginx.com 
418354Svbart@nginx.com         if (c2 == '0' || c1 == '\0') {
419354Svbart@nginx.com             return 1;
420354Svbart@nginx.com         }
421354Svbart@nginx.com 
422354Svbart@nginx.com         /* Fall through. */
423354Svbart@nginx.com 
424354Svbart@nginx.com     case st_frac:
425355Svbart@nginx.com     default:
426354Svbart@nginx.com         return diff;
427354Svbart@nginx.com     }
428354Svbart@nginx.com }
429354Svbart@nginx.com 
430354Svbart@nginx.com 
431354Svbart@nginx.com nxt_bool_t
432354Svbart@nginx.com nxt_strvers_match(u_char *version, u_char *prefix, size_t length)
433354Svbart@nginx.com {
434354Svbart@nginx.com     u_char  next, last;
435354Svbart@nginx.com 
436362Svbart@nginx.com     if (length == 0) {
437362Svbart@nginx.com         return 1;
438362Svbart@nginx.com     }
439362Svbart@nginx.com 
440354Svbart@nginx.com     if (nxt_strncmp(version, prefix, length) == 0) {
441354Svbart@nginx.com 
442354Svbart@nginx.com         next = version[length];
443354Svbart@nginx.com 
444354Svbart@nginx.com         if (next == '\0') {
445354Svbart@nginx.com             return 1;
446354Svbart@nginx.com         }
447354Svbart@nginx.com 
448354Svbart@nginx.com         last = version[length - 1];
449354Svbart@nginx.com 
450354Svbart@nginx.com         if (nxt_isdigit(last) != nxt_isdigit(next)) {
451354Svbart@nginx.com             /* This is a version part boundary. */
452354Svbart@nginx.com             return 1;
453354Svbart@nginx.com         }
454354Svbart@nginx.com     }
455354Svbart@nginx.com 
456354Svbart@nginx.com     return 0;
457354Svbart@nginx.com }
4581167Svbart@nginx.com 
4591167Svbart@nginx.com 
460*1431Svbart@nginx.com static const uint8_t  nxt_hex2int[256]
461*1431Svbart@nginx.com     nxt_aligned(32) =
462*1431Svbart@nginx.com {
463*1431Svbart@nginx.com     16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
464*1431Svbart@nginx.com     16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
465*1431Svbart@nginx.com     16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
466*1431Svbart@nginx.com      0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 16, 16, 16, 16, 16, 16,
467*1431Svbart@nginx.com     16, 10, 11, 12, 13, 14, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16,
468*1431Svbart@nginx.com     16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
469*1431Svbart@nginx.com     16, 10, 11, 12, 13, 14, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16,
470*1431Svbart@nginx.com     16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
471*1431Svbart@nginx.com     16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
472*1431Svbart@nginx.com     16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
473*1431Svbart@nginx.com     16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
474*1431Svbart@nginx.com     16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
475*1431Svbart@nginx.com     16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
476*1431Svbart@nginx.com     16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
477*1431Svbart@nginx.com     16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
478*1431Svbart@nginx.com     16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
479*1431Svbart@nginx.com };
480*1431Svbart@nginx.com 
481*1431Svbart@nginx.com 
482*1431Svbart@nginx.com static const uint32_t  nxt_uri_escape[] = {
483*1431Svbart@nginx.com     0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
484*1431Svbart@nginx.com 
485*1431Svbart@nginx.com                 /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
486*1431Svbart@nginx.com     0xd000002d, /* 1101 0000 0000 0000 0000 0000 0010 1101 */
487*1431Svbart@nginx.com 
488*1431Svbart@nginx.com                 /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
489*1431Svbart@nginx.com     0x50000000, /* 0101 0000 0000 0000 0000 0000 0000 0000 */
490*1431Svbart@nginx.com 
491*1431Svbart@nginx.com                 /*  ~}| {zyx wvut srqp onml kjih gfed cba` */
492*1431Svbart@nginx.com     0xb8000001, /* 1011 1000 0000 0000 0000 0000 0000 0001 */
493*1431Svbart@nginx.com 
494*1431Svbart@nginx.com     0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
495*1431Svbart@nginx.com     0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
496*1431Svbart@nginx.com     0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
497*1431Svbart@nginx.com     0xffffffff  /* 1111 1111 1111 1111 1111 1111 1111 1111 */
498*1431Svbart@nginx.com };
499*1431Svbart@nginx.com 
500*1431Svbart@nginx.com 
5011167Svbart@nginx.com u_char *
5021167Svbart@nginx.com nxt_decode_uri(u_char *dst, u_char *src, size_t length)
5031167Svbart@nginx.com {
5041167Svbart@nginx.com     u_char   *end, ch;
5051167Svbart@nginx.com     uint8_t  d0, d1;
5061167Svbart@nginx.com 
507*1431Svbart@nginx.com     nxt_prefetch(&nxt_hex2int['0']);
5081167Svbart@nginx.com 
5091167Svbart@nginx.com     end = src + length;
5101167Svbart@nginx.com 
5111167Svbart@nginx.com     while (src < end) {
5121167Svbart@nginx.com         ch = *src++;
5131167Svbart@nginx.com 
5141167Svbart@nginx.com         if (ch == '%') {
5151167Svbart@nginx.com             if (nxt_slow_path(end - src < 2)) {
5161167Svbart@nginx.com                 return NULL;
5171167Svbart@nginx.com             }
5181167Svbart@nginx.com 
519*1431Svbart@nginx.com             d0 = nxt_hex2int[*src++];
520*1431Svbart@nginx.com             d1 = nxt_hex2int[*src++];
5211167Svbart@nginx.com 
5221167Svbart@nginx.com             if (nxt_slow_path((d0 | d1) >= 16)) {
5231167Svbart@nginx.com                 return NULL;
5241167Svbart@nginx.com             }
5251167Svbart@nginx.com 
5261167Svbart@nginx.com             ch = (d0 << 4) + d1;
5271167Svbart@nginx.com         }
5281167Svbart@nginx.com 
5291167Svbart@nginx.com         *dst++ = ch;
5301167Svbart@nginx.com     }
5311167Svbart@nginx.com 
5321167Svbart@nginx.com     return dst;
5331167Svbart@nginx.com }
5341183Svbart@nginx.com 
5351183Svbart@nginx.com 
5361183Svbart@nginx.com uintptr_t
5371183Svbart@nginx.com nxt_encode_uri(u_char *dst, u_char *src, size_t length)
5381183Svbart@nginx.com {
5391183Svbart@nginx.com     u_char      *end;
5401183Svbart@nginx.com     nxt_uint_t  n;
5411183Svbart@nginx.com 
5421183Svbart@nginx.com     static const u_char  hex[16] = "0123456789ABCDEF";
5431183Svbart@nginx.com 
5441183Svbart@nginx.com     end = src + length;
5451183Svbart@nginx.com 
5461183Svbart@nginx.com     if (dst == NULL) {
5471183Svbart@nginx.com 
5481183Svbart@nginx.com         /* Find the number of the characters to be escaped. */
5491183Svbart@nginx.com 
5501183Svbart@nginx.com         n = 0;
5511183Svbart@nginx.com 
5521183Svbart@nginx.com         while (src < end) {
5531183Svbart@nginx.com 
554*1431Svbart@nginx.com             if (nxt_uri_escape[*src >> 5] & (1U << (*src & 0x1f))) {
5551183Svbart@nginx.com                 n++;
5561183Svbart@nginx.com             }
5571183Svbart@nginx.com 
5581183Svbart@nginx.com             src++;
5591183Svbart@nginx.com         }
5601183Svbart@nginx.com 
5611183Svbart@nginx.com         return (uintptr_t) n;
5621183Svbart@nginx.com     }
5631183Svbart@nginx.com 
5641183Svbart@nginx.com     while (src < end) {
5651183Svbart@nginx.com 
566*1431Svbart@nginx.com         if (nxt_uri_escape[*src >> 5] & (1U << (*src & 0x1f))) {
5671183Svbart@nginx.com             *dst++ = '%';
5681183Svbart@nginx.com             *dst++ = hex[*src >> 4];
5691183Svbart@nginx.com             *dst++ = hex[*src & 0xf];
5701183Svbart@nginx.com 
5711183Svbart@nginx.com         } else {
5721183Svbart@nginx.com             *dst++ = *src;
5731183Svbart@nginx.com         }
5741183Svbart@nginx.com 
5751183Svbart@nginx.com         src++;
5761183Svbart@nginx.com     }
5771183Svbart@nginx.com 
5781183Svbart@nginx.com     return (uintptr_t) dst;
5791183Svbart@nginx.com }
580*1431Svbart@nginx.com 
581*1431Svbart@nginx.com 
582*1431Svbart@nginx.com uintptr_t
583*1431Svbart@nginx.com nxt_encode_complex_uri(u_char *dst, u_char *src, size_t length)
584*1431Svbart@nginx.com {
585*1431Svbart@nginx.com     u_char      *reserved, *end, ch;
586*1431Svbart@nginx.com     nxt_uint_t  n;
587*1431Svbart@nginx.com 
588*1431Svbart@nginx.com     static const u_char  hex[16] = "0123456789ABCDEF";
589*1431Svbart@nginx.com 
590*1431Svbart@nginx.com     reserved = (u_char *) "?#\0";
591*1431Svbart@nginx.com 
592*1431Svbart@nginx.com     end = src + length;
593*1431Svbart@nginx.com 
594*1431Svbart@nginx.com     if (dst == NULL) {
595*1431Svbart@nginx.com 
596*1431Svbart@nginx.com         /* Find the number of the characters to be escaped. */
597*1431Svbart@nginx.com 
598*1431Svbart@nginx.com         n = 0;
599*1431Svbart@nginx.com 
600*1431Svbart@nginx.com         while (src < end) {
601*1431Svbart@nginx.com             ch = *src++;
602*1431Svbart@nginx.com 
603*1431Svbart@nginx.com             if (nxt_uri_escape[ch >> 5] & (1U << (ch & 0x1f))) {
604*1431Svbart@nginx.com                 if (ch == reserved[0]) {
605*1431Svbart@nginx.com                     reserved++;
606*1431Svbart@nginx.com                     continue;
607*1431Svbart@nginx.com                 }
608*1431Svbart@nginx.com 
609*1431Svbart@nginx.com                 if (ch == reserved[1]) {
610*1431Svbart@nginx.com                     reserved += 2;
611*1431Svbart@nginx.com                     continue;
612*1431Svbart@nginx.com                 }
613*1431Svbart@nginx.com 
614*1431Svbart@nginx.com                 n++;
615*1431Svbart@nginx.com             }
616*1431Svbart@nginx.com         }
617*1431Svbart@nginx.com 
618*1431Svbart@nginx.com         return (uintptr_t) n;
619*1431Svbart@nginx.com     }
620*1431Svbart@nginx.com 
621*1431Svbart@nginx.com     while (src < end) {
622*1431Svbart@nginx.com         ch = *src++;
623*1431Svbart@nginx.com 
624*1431Svbart@nginx.com         if (nxt_uri_escape[ch >> 5] & (1U << (ch & 0x1f))) {
625*1431Svbart@nginx.com             if (ch == reserved[0]) {
626*1431Svbart@nginx.com                 reserved++;
627*1431Svbart@nginx.com 
628*1431Svbart@nginx.com             } else if (ch == reserved[1]) {
629*1431Svbart@nginx.com                 reserved += 2;
630*1431Svbart@nginx.com 
631*1431Svbart@nginx.com             } else {
632*1431Svbart@nginx.com                 *dst++ = '%';
633*1431Svbart@nginx.com                 *dst++ = hex[ch >> 4];
634*1431Svbart@nginx.com                 *dst++ = hex[ch & 0xf];
635*1431Svbart@nginx.com                 continue;
636*1431Svbart@nginx.com             }
637*1431Svbart@nginx.com         }
638*1431Svbart@nginx.com 
639*1431Svbart@nginx.com         *dst++ = ch;
640*1431Svbart@nginx.com     }
641*1431Svbart@nginx.com 
642*1431Svbart@nginx.com     return (uintptr_t) dst;
643*1431Svbart@nginx.com }
644*1431Svbart@nginx.com 
645*1431Svbart@nginx.com 
646*1431Svbart@nginx.com nxt_bool_t
647*1431Svbart@nginx.com nxt_is_complex_uri_encoded(u_char *src, size_t length)
648*1431Svbart@nginx.com {
649*1431Svbart@nginx.com     u_char   *reserved, *end, ch;
650*1431Svbart@nginx.com     uint8_t  d0, d1;
651*1431Svbart@nginx.com 
652*1431Svbart@nginx.com     reserved = (u_char *) "?#\0";
653*1431Svbart@nginx.com 
654*1431Svbart@nginx.com     for (end = src + length; src < end; src++) {
655*1431Svbart@nginx.com         ch = *src;
656*1431Svbart@nginx.com 
657*1431Svbart@nginx.com         if (nxt_uri_escape[ch >> 5] & (1U << (ch & 0x1f))) {
658*1431Svbart@nginx.com             if (ch == '%') {
659*1431Svbart@nginx.com                 if (end - src < 2) {
660*1431Svbart@nginx.com                     return 0;
661*1431Svbart@nginx.com                 }
662*1431Svbart@nginx.com 
663*1431Svbart@nginx.com                 d0 = nxt_hex2int[*++src];
664*1431Svbart@nginx.com                 d1 = nxt_hex2int[*++src];
665*1431Svbart@nginx.com 
666*1431Svbart@nginx.com                 if ((d0 | d1) >= 16) {
667*1431Svbart@nginx.com                     return 0;
668*1431Svbart@nginx.com                 }
669*1431Svbart@nginx.com 
670*1431Svbart@nginx.com                 continue;
671*1431Svbart@nginx.com             }
672*1431Svbart@nginx.com 
673*1431Svbart@nginx.com             if (ch == reserved[0]) {
674*1431Svbart@nginx.com                 reserved++;
675*1431Svbart@nginx.com                 continue;
676*1431Svbart@nginx.com             }
677*1431Svbart@nginx.com 
678*1431Svbart@nginx.com             if (ch == reserved[1]) {
679*1431Svbart@nginx.com                 reserved += 2;
680*1431Svbart@nginx.com                 continue;
681*1431Svbart@nginx.com             }
682*1431Svbart@nginx.com 
683*1431Svbart@nginx.com             return 0;
684*1431Svbart@nginx.com         }
685*1431Svbart@nginx.com     }
686*1431Svbart@nginx.com 
687*1431Svbart@nginx.com     return 1;
688*1431Svbart@nginx.com }
689