xref: /unit/src/nxt_string.c (revision 1474)
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 *
1131439Svbart@nginx.com nxt_cpystr(u_char *dst, const u_char *src)
1141439Svbart@nginx.com {
1151439Svbart@nginx.com     for ( ;; ) {
1161439Svbart@nginx.com         *dst = *src;
1171439Svbart@nginx.com 
1181439Svbart@nginx.com         if (*dst == '\0') {
1191439Svbart@nginx.com             break;
1201439Svbart@nginx.com         }
1211439Svbart@nginx.com 
1221439Svbart@nginx.com         dst++;
1231439Svbart@nginx.com         src++;
1241439Svbart@nginx.com     }
1251439Svbart@nginx.com 
1261439Svbart@nginx.com     return dst;
1271439Svbart@nginx.com }
1281439Svbart@nginx.com 
1291439Svbart@nginx.com 
1301439Svbart@nginx.com u_char *
13110Sigor@sysoev.ru nxt_cpystrn(u_char *dst, const u_char *src, size_t length)
1320Sigor@sysoev.ru {
13310Sigor@sysoev.ru     if (length == 0) {
1340Sigor@sysoev.ru         return dst;
1350Sigor@sysoev.ru     }
1360Sigor@sysoev.ru 
13710Sigor@sysoev.ru     while (--length != 0) {
1380Sigor@sysoev.ru         *dst = *src;
1390Sigor@sysoev.ru 
1400Sigor@sysoev.ru         if (*dst == '\0') {
1410Sigor@sysoev.ru             return dst;
1420Sigor@sysoev.ru         }
1430Sigor@sysoev.ru 
1440Sigor@sysoev.ru         dst++;
1450Sigor@sysoev.ru         src++;
1460Sigor@sysoev.ru     }
1470Sigor@sysoev.ru 
1480Sigor@sysoev.ru     *dst = '\0';
1490Sigor@sysoev.ru 
1500Sigor@sysoev.ru     return dst;
1510Sigor@sysoev.ru }
1520Sigor@sysoev.ru 
1530Sigor@sysoev.ru 
1540Sigor@sysoev.ru nxt_int_t
1550Sigor@sysoev.ru nxt_strcasecmp(const u_char *s1, const u_char *s2)
1560Sigor@sysoev.ru {
1570Sigor@sysoev.ru     u_char     c1, c2;
1580Sigor@sysoev.ru     nxt_int_t  n;
1590Sigor@sysoev.ru 
1600Sigor@sysoev.ru     for ( ;; ) {
1610Sigor@sysoev.ru         c1 = *s1++;
1620Sigor@sysoev.ru         c2 = *s2++;
1630Sigor@sysoev.ru 
1640Sigor@sysoev.ru         c1 = nxt_lowcase(c1);
1650Sigor@sysoev.ru         c2 = nxt_lowcase(c2);
1660Sigor@sysoev.ru 
1670Sigor@sysoev.ru         n = c1 - c2;
1680Sigor@sysoev.ru 
1690Sigor@sysoev.ru         if (n != 0) {
1700Sigor@sysoev.ru             return n;
1710Sigor@sysoev.ru         }
1720Sigor@sysoev.ru 
1730Sigor@sysoev.ru         if (c1 == 0) {
1740Sigor@sysoev.ru             return 0;
1750Sigor@sysoev.ru         }
1760Sigor@sysoev.ru     }
1770Sigor@sysoev.ru }
1780Sigor@sysoev.ru 
1790Sigor@sysoev.ru 
1800Sigor@sysoev.ru nxt_int_t
18110Sigor@sysoev.ru nxt_strncasecmp(const u_char *s1, const u_char *s2, size_t length)
1820Sigor@sysoev.ru {
1830Sigor@sysoev.ru     u_char     c1, c2;
1840Sigor@sysoev.ru     nxt_int_t  n;
1850Sigor@sysoev.ru 
18610Sigor@sysoev.ru     while (length-- != 0) {
1870Sigor@sysoev.ru         c1 = *s1++;
1880Sigor@sysoev.ru         c2 = *s2++;
1890Sigor@sysoev.ru 
1900Sigor@sysoev.ru         c1 = nxt_lowcase(c1);
1910Sigor@sysoev.ru         c2 = nxt_lowcase(c2);
1920Sigor@sysoev.ru 
1930Sigor@sysoev.ru         n = c1 - c2;
1940Sigor@sysoev.ru 
1950Sigor@sysoev.ru         if (n != 0) {
1960Sigor@sysoev.ru             return n;
1970Sigor@sysoev.ru         }
1980Sigor@sysoev.ru 
1990Sigor@sysoev.ru         if (c1 == 0) {
2000Sigor@sysoev.ru             return 0;
2010Sigor@sysoev.ru         }
2020Sigor@sysoev.ru     }
2030Sigor@sysoev.ru 
2040Sigor@sysoev.ru     return 0;
2050Sigor@sysoev.ru }
2060Sigor@sysoev.ru 
2070Sigor@sysoev.ru 
2080Sigor@sysoev.ru nxt_int_t
2091234Sigor@sysoev.ru nxt_memcasecmp(const void *p1, const void *p2, size_t length)
2100Sigor@sysoev.ru {
2111234Sigor@sysoev.ru     u_char        c1, c2;
2121234Sigor@sysoev.ru     nxt_int_t     n;
2131234Sigor@sysoev.ru     const u_char  *s1, *s2;
2141234Sigor@sysoev.ru 
2151234Sigor@sysoev.ru     s1 = p1;
2161234Sigor@sysoev.ru     s2 = p2;
2170Sigor@sysoev.ru 
21810Sigor@sysoev.ru     while (length-- != 0) {
2190Sigor@sysoev.ru         c1 = *s1++;
2200Sigor@sysoev.ru         c2 = *s2++;
2210Sigor@sysoev.ru 
2220Sigor@sysoev.ru         c1 = nxt_lowcase(c1);
2230Sigor@sysoev.ru         c2 = nxt_lowcase(c2);
2240Sigor@sysoev.ru 
2250Sigor@sysoev.ru         n = c1 - c2;
2260Sigor@sysoev.ru 
2270Sigor@sysoev.ru         if (n != 0) {
2280Sigor@sysoev.ru             return n;
2290Sigor@sysoev.ru         }
2300Sigor@sysoev.ru     }
2310Sigor@sysoev.ru 
2320Sigor@sysoev.ru     return 0;
2330Sigor@sysoev.ru }
2340Sigor@sysoev.ru 
2350Sigor@sysoev.ru 
2360Sigor@sysoev.ru /*
2370Sigor@sysoev.ru  * nxt_memstrn() is intended for search of static substring "ss"
23810Sigor@sysoev.ru  * with known length "length" in string "s" limited by parameter "end".
2390Sigor@sysoev.ru  * Zeros are ignored in both strings.
2400Sigor@sysoev.ru  */
2410Sigor@sysoev.ru 
2420Sigor@sysoev.ru u_char *
24310Sigor@sysoev.ru nxt_memstrn(const u_char *s, const u_char *end, const char *ss, size_t length)
2440Sigor@sysoev.ru {
2450Sigor@sysoev.ru     u_char  c1, c2, *s2;
2460Sigor@sysoev.ru 
2470Sigor@sysoev.ru     s2 = (u_char *) ss;
2480Sigor@sysoev.ru     c2 = *s2++;
24910Sigor@sysoev.ru     length--;
2500Sigor@sysoev.ru 
2510Sigor@sysoev.ru     while (s < end) {
2520Sigor@sysoev.ru         c1 = *s++;
2530Sigor@sysoev.ru 
2540Sigor@sysoev.ru         if (c1 == c2) {
2550Sigor@sysoev.ru 
25610Sigor@sysoev.ru             if (s + length > end) {
2570Sigor@sysoev.ru                 return NULL;
2580Sigor@sysoev.ru             }
2590Sigor@sysoev.ru 
26010Sigor@sysoev.ru             if (nxt_memcmp(s, s2, length) == 0) {
2610Sigor@sysoev.ru                 return (u_char *) s - 1;
2620Sigor@sysoev.ru             }
2630Sigor@sysoev.ru         }
2640Sigor@sysoev.ru     }
2650Sigor@sysoev.ru 
2660Sigor@sysoev.ru     return NULL;
2670Sigor@sysoev.ru }
2680Sigor@sysoev.ru 
2690Sigor@sysoev.ru 
2700Sigor@sysoev.ru /*
2710Sigor@sysoev.ru  * nxt_strcasestrn() is intended for caseless search of static substring
27210Sigor@sysoev.ru  * "ss" with known length "length" in string "s" limited by parameter "end".
2730Sigor@sysoev.ru  * Zeros are ignored in both strings.
2740Sigor@sysoev.ru  */
2750Sigor@sysoev.ru 
2760Sigor@sysoev.ru u_char *
27710Sigor@sysoev.ru nxt_memcasestrn(const u_char *s, const u_char *end, const char *ss,
27810Sigor@sysoev.ru     size_t length)
2790Sigor@sysoev.ru {
2800Sigor@sysoev.ru     u_char  c1, c2, *s2;
2810Sigor@sysoev.ru 
2820Sigor@sysoev.ru     s2 = (u_char *) ss;
2830Sigor@sysoev.ru     c2 = *s2++;
2840Sigor@sysoev.ru     c2 = nxt_lowcase(c2);
28510Sigor@sysoev.ru     length--;
2860Sigor@sysoev.ru 
2870Sigor@sysoev.ru     while (s < end) {
2880Sigor@sysoev.ru         c1 = *s++;
2890Sigor@sysoev.ru         c1 = nxt_lowcase(c1);
2900Sigor@sysoev.ru 
2910Sigor@sysoev.ru         if (c1 == c2) {
2920Sigor@sysoev.ru 
29310Sigor@sysoev.ru             if (s + length > end) {
2940Sigor@sysoev.ru                 return NULL;
2950Sigor@sysoev.ru             }
2960Sigor@sysoev.ru 
29710Sigor@sysoev.ru             if (nxt_memcasecmp(s, s2, length) == 0) {
2980Sigor@sysoev.ru                 return (u_char *) s - 1;
2990Sigor@sysoev.ru             }
3000Sigor@sysoev.ru         }
3010Sigor@sysoev.ru     }
3020Sigor@sysoev.ru 
3030Sigor@sysoev.ru     return NULL;
3040Sigor@sysoev.ru }
3050Sigor@sysoev.ru 
3060Sigor@sysoev.ru 
3070Sigor@sysoev.ru /*
3080Sigor@sysoev.ru  * nxt_rstrstrn() is intended to search for static substring "ss"
30910Sigor@sysoev.ru  * with known length "length" in string "s" limited by parameter "end"
3100Sigor@sysoev.ru  * in reverse order.  Zeros are ignored in both strings.
3110Sigor@sysoev.ru  */
3120Sigor@sysoev.ru 
3130Sigor@sysoev.ru u_char *
31410Sigor@sysoev.ru nxt_rmemstrn(const u_char *s, const u_char *end, const char *ss, size_t length)
3150Sigor@sysoev.ru {
3160Sigor@sysoev.ru     u_char        c1, c2;
3170Sigor@sysoev.ru     const u_char  *s1, *s2;
3180Sigor@sysoev.ru 
31910Sigor@sysoev.ru     s1 = end - length;
3200Sigor@sysoev.ru     s2 = (u_char *) ss;
3210Sigor@sysoev.ru     c2 = *s2++;
32210Sigor@sysoev.ru     length--;
3230Sigor@sysoev.ru 
3240Sigor@sysoev.ru     while (s < s1) {
3250Sigor@sysoev.ru         c1 = *s1;
3260Sigor@sysoev.ru 
3270Sigor@sysoev.ru         if (c1 == c2) {
32810Sigor@sysoev.ru             if (nxt_memcmp(s1 + 1, s2, length) == 0) {
3290Sigor@sysoev.ru                 return (u_char *) s1;
3300Sigor@sysoev.ru             }
3310Sigor@sysoev.ru         }
3320Sigor@sysoev.ru 
3330Sigor@sysoev.ru         s1--;
3340Sigor@sysoev.ru     }
3350Sigor@sysoev.ru 
3360Sigor@sysoev.ru     return NULL;
3370Sigor@sysoev.ru }
3380Sigor@sysoev.ru 
3390Sigor@sysoev.ru 
3400Sigor@sysoev.ru size_t
3410Sigor@sysoev.ru nxt_str_strip(u_char *start, u_char *end)
3420Sigor@sysoev.ru {
3430Sigor@sysoev.ru     u_char  *p;
3440Sigor@sysoev.ru 
3450Sigor@sysoev.ru     for (p = end - 1; p >= start; p--) {
346704Sigor@sysoev.ru         if (*p != '\r' && *p != '\n') {
3470Sigor@sysoev.ru             break;
3480Sigor@sysoev.ru         }
3490Sigor@sysoev.ru     }
3500Sigor@sysoev.ru 
3510Sigor@sysoev.ru     return (p + 1) - start;
3520Sigor@sysoev.ru }
353354Svbart@nginx.com 
354354Svbart@nginx.com 
355354Svbart@nginx.com nxt_int_t
356354Svbart@nginx.com nxt_strverscmp(const u_char *s1, const u_char *s2)
357354Svbart@nginx.com {
358354Svbart@nginx.com     u_char     c1, c2;
359354Svbart@nginx.com     nxt_int_t  diff;
360354Svbart@nginx.com 
361354Svbart@nginx.com     enum {
362354Svbart@nginx.com         st_str = 0,
363354Svbart@nginx.com         st_num,
364354Svbart@nginx.com         st_zero,
365354Svbart@nginx.com         st_frac,
366354Svbart@nginx.com     } state;
367354Svbart@nginx.com 
368354Svbart@nginx.com     state = st_str;
369354Svbart@nginx.com 
370354Svbart@nginx.com     for ( ;; ) {
371354Svbart@nginx.com         c1 = *s1++;
372354Svbart@nginx.com         c2 = *s2++;
373354Svbart@nginx.com 
374354Svbart@nginx.com         diff = c1 - c2;
375354Svbart@nginx.com 
376354Svbart@nginx.com         if (diff != 0) {
377354Svbart@nginx.com             break;
378354Svbart@nginx.com         }
379354Svbart@nginx.com 
380354Svbart@nginx.com         if (c1 == '\0') {
381354Svbart@nginx.com             return 0;
382354Svbart@nginx.com         }
383354Svbart@nginx.com 
384354Svbart@nginx.com         if (!nxt_isdigit(c1)) {
385354Svbart@nginx.com             state = st_str;
386354Svbart@nginx.com             continue;
387354Svbart@nginx.com         }
388354Svbart@nginx.com 
389354Svbart@nginx.com         if (state == st_str) {
390354Svbart@nginx.com             state = (c1 != '0') ? st_num : st_zero;
391354Svbart@nginx.com             continue;
392354Svbart@nginx.com         }
393354Svbart@nginx.com 
394354Svbart@nginx.com         if (state == st_zero && c1 != '0') {
395354Svbart@nginx.com             state = st_frac;
396354Svbart@nginx.com             continue;
397354Svbart@nginx.com         }
398354Svbart@nginx.com     }
399354Svbart@nginx.com 
400354Svbart@nginx.com     switch (state) {
401354Svbart@nginx.com 
402354Svbart@nginx.com     case st_str:
403354Svbart@nginx.com 
404354Svbart@nginx.com         if ((u_char) (c1 - '1') > 8 || (u_char) (c2 - '1') > 8) {
405354Svbart@nginx.com             return diff;
406354Svbart@nginx.com         }
407354Svbart@nginx.com 
408354Svbart@nginx.com         c1 = *s1++;
409354Svbart@nginx.com         c2 = *s2++;
410354Svbart@nginx.com 
411354Svbart@nginx.com         /* Fall through. */
412354Svbart@nginx.com 
413354Svbart@nginx.com     case st_num:
414354Svbart@nginx.com 
415354Svbart@nginx.com         while (nxt_isdigit(c1) && nxt_isdigit(c2)) {
416354Svbart@nginx.com             c1 = *s1++;
417354Svbart@nginx.com             c2 = *s2++;
418354Svbart@nginx.com         }
419354Svbart@nginx.com 
420354Svbart@nginx.com         if (nxt_isdigit(c1)) {
421354Svbart@nginx.com             return 1;
422354Svbart@nginx.com         }
423354Svbart@nginx.com 
424354Svbart@nginx.com         if (nxt_isdigit(c2)) {
425354Svbart@nginx.com             return -1;
426354Svbart@nginx.com         }
427354Svbart@nginx.com 
428354Svbart@nginx.com         return diff;
429354Svbart@nginx.com 
430354Svbart@nginx.com     case st_zero:
431354Svbart@nginx.com 
432354Svbart@nginx.com         if (c1 == '0' || c2 == '\0') {
433354Svbart@nginx.com             return -1;
434354Svbart@nginx.com         }
435354Svbart@nginx.com 
436354Svbart@nginx.com         if (c2 == '0' || c1 == '\0') {
437354Svbart@nginx.com             return 1;
438354Svbart@nginx.com         }
439354Svbart@nginx.com 
440354Svbart@nginx.com         /* Fall through. */
441354Svbart@nginx.com 
442354Svbart@nginx.com     case st_frac:
443355Svbart@nginx.com     default:
444354Svbart@nginx.com         return diff;
445354Svbart@nginx.com     }
446354Svbart@nginx.com }
447354Svbart@nginx.com 
448354Svbart@nginx.com 
449354Svbart@nginx.com nxt_bool_t
450354Svbart@nginx.com nxt_strvers_match(u_char *version, u_char *prefix, size_t length)
451354Svbart@nginx.com {
452354Svbart@nginx.com     u_char  next, last;
453354Svbart@nginx.com 
454362Svbart@nginx.com     if (length == 0) {
455362Svbart@nginx.com         return 1;
456362Svbart@nginx.com     }
457362Svbart@nginx.com 
458354Svbart@nginx.com     if (nxt_strncmp(version, prefix, length) == 0) {
459354Svbart@nginx.com 
460354Svbart@nginx.com         next = version[length];
461354Svbart@nginx.com 
462354Svbart@nginx.com         if (next == '\0') {
463354Svbart@nginx.com             return 1;
464354Svbart@nginx.com         }
465354Svbart@nginx.com 
466354Svbart@nginx.com         last = version[length - 1];
467354Svbart@nginx.com 
468354Svbart@nginx.com         if (nxt_isdigit(last) != nxt_isdigit(next)) {
469354Svbart@nginx.com             /* This is a version part boundary. */
470354Svbart@nginx.com             return 1;
471354Svbart@nginx.com         }
472354Svbart@nginx.com     }
473354Svbart@nginx.com 
474354Svbart@nginx.com     return 0;
475354Svbart@nginx.com }
4761167Svbart@nginx.com 
4771167Svbart@nginx.com 
478*1474Saxel.duch@nginx.com const uint8_t  nxt_hex2int[256]
4791431Svbart@nginx.com     nxt_aligned(32) =
4801431Svbart@nginx.com {
4811431Svbart@nginx.com     16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
4821431Svbart@nginx.com     16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
4831431Svbart@nginx.com     16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
4841431Svbart@nginx.com      0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 16, 16, 16, 16, 16, 16,
4851431Svbart@nginx.com     16, 10, 11, 12, 13, 14, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16,
4861431Svbart@nginx.com     16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
4871431Svbart@nginx.com     16, 10, 11, 12, 13, 14, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16,
4881431Svbart@nginx.com     16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
4891431Svbart@nginx.com     16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
4901431Svbart@nginx.com     16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
4911431Svbart@nginx.com     16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
4921431Svbart@nginx.com     16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
4931431Svbart@nginx.com     16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
4941431Svbart@nginx.com     16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
4951431Svbart@nginx.com     16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
4961431Svbart@nginx.com     16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
4971431Svbart@nginx.com };
4981431Svbart@nginx.com 
4991431Svbart@nginx.com 
5001431Svbart@nginx.com static const uint32_t  nxt_uri_escape[] = {
5011431Svbart@nginx.com     0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
5021431Svbart@nginx.com 
5031431Svbart@nginx.com                 /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
5041431Svbart@nginx.com     0xd000002d, /* 1101 0000 0000 0000 0000 0000 0010 1101 */
5051431Svbart@nginx.com 
5061431Svbart@nginx.com                 /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
5071431Svbart@nginx.com     0x50000000, /* 0101 0000 0000 0000 0000 0000 0000 0000 */
5081431Svbart@nginx.com 
5091431Svbart@nginx.com                 /*  ~}| {zyx wvut srqp onml kjih gfed cba` */
5101431Svbart@nginx.com     0xb8000001, /* 1011 1000 0000 0000 0000 0000 0000 0001 */
5111431Svbart@nginx.com 
5121431Svbart@nginx.com     0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
5131431Svbart@nginx.com     0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
5141431Svbart@nginx.com     0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
5151431Svbart@nginx.com     0xffffffff  /* 1111 1111 1111 1111 1111 1111 1111 1111 */
5161431Svbart@nginx.com };
5171431Svbart@nginx.com 
5181431Svbart@nginx.com 
5191167Svbart@nginx.com u_char *
5201167Svbart@nginx.com nxt_decode_uri(u_char *dst, u_char *src, size_t length)
5211167Svbart@nginx.com {
5221167Svbart@nginx.com     u_char   *end, ch;
5231167Svbart@nginx.com     uint8_t  d0, d1;
5241167Svbart@nginx.com 
5251431Svbart@nginx.com     nxt_prefetch(&nxt_hex2int['0']);
5261167Svbart@nginx.com 
5271167Svbart@nginx.com     end = src + length;
5281167Svbart@nginx.com 
5291167Svbart@nginx.com     while (src < end) {
5301167Svbart@nginx.com         ch = *src++;
5311167Svbart@nginx.com 
5321167Svbart@nginx.com         if (ch == '%') {
5331167Svbart@nginx.com             if (nxt_slow_path(end - src < 2)) {
5341167Svbart@nginx.com                 return NULL;
5351167Svbart@nginx.com             }
5361167Svbart@nginx.com 
5371431Svbart@nginx.com             d0 = nxt_hex2int[*src++];
5381431Svbart@nginx.com             d1 = nxt_hex2int[*src++];
5391167Svbart@nginx.com 
5401167Svbart@nginx.com             if (nxt_slow_path((d0 | d1) >= 16)) {
5411167Svbart@nginx.com                 return NULL;
5421167Svbart@nginx.com             }
5431167Svbart@nginx.com 
5441167Svbart@nginx.com             ch = (d0 << 4) + d1;
5451167Svbart@nginx.com         }
5461167Svbart@nginx.com 
5471167Svbart@nginx.com         *dst++ = ch;
5481167Svbart@nginx.com     }
5491167Svbart@nginx.com 
5501167Svbart@nginx.com     return dst;
5511167Svbart@nginx.com }
5521183Svbart@nginx.com 
5531183Svbart@nginx.com 
554*1474Saxel.duch@nginx.com u_char *
555*1474Saxel.duch@nginx.com nxt_decode_uri_plus(u_char *dst, u_char *src, size_t length)
556*1474Saxel.duch@nginx.com {
557*1474Saxel.duch@nginx.com     u_char   *end, ch;
558*1474Saxel.duch@nginx.com     uint8_t  d0, d1;
559*1474Saxel.duch@nginx.com 
560*1474Saxel.duch@nginx.com     nxt_prefetch(&nxt_hex2int['0']);
561*1474Saxel.duch@nginx.com 
562*1474Saxel.duch@nginx.com     end = src + length;
563*1474Saxel.duch@nginx.com 
564*1474Saxel.duch@nginx.com     while (src < end) {
565*1474Saxel.duch@nginx.com         ch = *src++;
566*1474Saxel.duch@nginx.com 
567*1474Saxel.duch@nginx.com         switch (ch) {
568*1474Saxel.duch@nginx.com         case '%':
569*1474Saxel.duch@nginx.com             if (nxt_slow_path(end - src < 2)) {
570*1474Saxel.duch@nginx.com                 return NULL;
571*1474Saxel.duch@nginx.com             }
572*1474Saxel.duch@nginx.com 
573*1474Saxel.duch@nginx.com             d0 = nxt_hex2int[*src++];
574*1474Saxel.duch@nginx.com             d1 = nxt_hex2int[*src++];
575*1474Saxel.duch@nginx.com 
576*1474Saxel.duch@nginx.com             if (nxt_slow_path((d0 | d1) >= 16)) {
577*1474Saxel.duch@nginx.com                 return NULL;
578*1474Saxel.duch@nginx.com             }
579*1474Saxel.duch@nginx.com 
580*1474Saxel.duch@nginx.com             ch = (d0 << 4) + d1;
581*1474Saxel.duch@nginx.com             break;
582*1474Saxel.duch@nginx.com 
583*1474Saxel.duch@nginx.com         case '+':
584*1474Saxel.duch@nginx.com             ch = ' ';
585*1474Saxel.duch@nginx.com             break;
586*1474Saxel.duch@nginx.com         }
587*1474Saxel.duch@nginx.com 
588*1474Saxel.duch@nginx.com         *dst++ = ch;
589*1474Saxel.duch@nginx.com     }
590*1474Saxel.duch@nginx.com 
591*1474Saxel.duch@nginx.com     return dst;
592*1474Saxel.duch@nginx.com }
593*1474Saxel.duch@nginx.com 
594*1474Saxel.duch@nginx.com 
5951183Svbart@nginx.com uintptr_t
5961183Svbart@nginx.com nxt_encode_uri(u_char *dst, u_char *src, size_t length)
5971183Svbart@nginx.com {
5981183Svbart@nginx.com     u_char      *end;
5991183Svbart@nginx.com     nxt_uint_t  n;
6001183Svbart@nginx.com 
6011183Svbart@nginx.com     static const u_char  hex[16] = "0123456789ABCDEF";
6021183Svbart@nginx.com 
6031183Svbart@nginx.com     end = src + length;
6041183Svbart@nginx.com 
6051183Svbart@nginx.com     if (dst == NULL) {
6061183Svbart@nginx.com 
6071183Svbart@nginx.com         /* Find the number of the characters to be escaped. */
6081183Svbart@nginx.com 
6091183Svbart@nginx.com         n = 0;
6101183Svbart@nginx.com 
6111183Svbart@nginx.com         while (src < end) {
6121183Svbart@nginx.com 
6131431Svbart@nginx.com             if (nxt_uri_escape[*src >> 5] & (1U << (*src & 0x1f))) {
6141183Svbart@nginx.com                 n++;
6151183Svbart@nginx.com             }
6161183Svbart@nginx.com 
6171183Svbart@nginx.com             src++;
6181183Svbart@nginx.com         }
6191183Svbart@nginx.com 
6201183Svbart@nginx.com         return (uintptr_t) n;
6211183Svbart@nginx.com     }
6221183Svbart@nginx.com 
6231183Svbart@nginx.com     while (src < end) {
6241183Svbart@nginx.com 
6251431Svbart@nginx.com         if (nxt_uri_escape[*src >> 5] & (1U << (*src & 0x1f))) {
6261183Svbart@nginx.com             *dst++ = '%';
6271183Svbart@nginx.com             *dst++ = hex[*src >> 4];
6281183Svbart@nginx.com             *dst++ = hex[*src & 0xf];
6291183Svbart@nginx.com 
6301183Svbart@nginx.com         } else {
6311183Svbart@nginx.com             *dst++ = *src;
6321183Svbart@nginx.com         }
6331183Svbart@nginx.com 
6341183Svbart@nginx.com         src++;
6351183Svbart@nginx.com     }
6361183Svbart@nginx.com 
6371183Svbart@nginx.com     return (uintptr_t) dst;
6381183Svbart@nginx.com }
6391431Svbart@nginx.com 
6401431Svbart@nginx.com 
6411431Svbart@nginx.com uintptr_t
6421431Svbart@nginx.com nxt_encode_complex_uri(u_char *dst, u_char *src, size_t length)
6431431Svbart@nginx.com {
6441431Svbart@nginx.com     u_char      *reserved, *end, ch;
6451431Svbart@nginx.com     nxt_uint_t  n;
6461431Svbart@nginx.com 
6471431Svbart@nginx.com     static const u_char  hex[16] = "0123456789ABCDEF";
6481431Svbart@nginx.com 
6491431Svbart@nginx.com     reserved = (u_char *) "?#\0";
6501431Svbart@nginx.com 
6511431Svbart@nginx.com     end = src + length;
6521431Svbart@nginx.com 
6531431Svbart@nginx.com     if (dst == NULL) {
6541431Svbart@nginx.com 
6551431Svbart@nginx.com         /* Find the number of the characters to be escaped. */
6561431Svbart@nginx.com 
6571431Svbart@nginx.com         n = 0;
6581431Svbart@nginx.com 
6591431Svbart@nginx.com         while (src < end) {
6601431Svbart@nginx.com             ch = *src++;
6611431Svbart@nginx.com 
6621431Svbart@nginx.com             if (nxt_uri_escape[ch >> 5] & (1U << (ch & 0x1f))) {
6631431Svbart@nginx.com                 if (ch == reserved[0]) {
6641431Svbart@nginx.com                     reserved++;
6651431Svbart@nginx.com                     continue;
6661431Svbart@nginx.com                 }
6671431Svbart@nginx.com 
6681431Svbart@nginx.com                 if (ch == reserved[1]) {
6691431Svbart@nginx.com                     reserved += 2;
6701431Svbart@nginx.com                     continue;
6711431Svbart@nginx.com                 }
6721431Svbart@nginx.com 
6731431Svbart@nginx.com                 n++;
6741431Svbart@nginx.com             }
6751431Svbart@nginx.com         }
6761431Svbart@nginx.com 
6771431Svbart@nginx.com         return (uintptr_t) n;
6781431Svbart@nginx.com     }
6791431Svbart@nginx.com 
6801431Svbart@nginx.com     while (src < end) {
6811431Svbart@nginx.com         ch = *src++;
6821431Svbart@nginx.com 
6831431Svbart@nginx.com         if (nxt_uri_escape[ch >> 5] & (1U << (ch & 0x1f))) {
6841431Svbart@nginx.com             if (ch == reserved[0]) {
6851431Svbart@nginx.com                 reserved++;
6861431Svbart@nginx.com 
6871431Svbart@nginx.com             } else if (ch == reserved[1]) {
6881431Svbart@nginx.com                 reserved += 2;
6891431Svbart@nginx.com 
6901431Svbart@nginx.com             } else {
6911431Svbart@nginx.com                 *dst++ = '%';
6921431Svbart@nginx.com                 *dst++ = hex[ch >> 4];
6931431Svbart@nginx.com                 *dst++ = hex[ch & 0xf];
6941431Svbart@nginx.com                 continue;
6951431Svbart@nginx.com             }
6961431Svbart@nginx.com         }
6971431Svbart@nginx.com 
6981431Svbart@nginx.com         *dst++ = ch;
6991431Svbart@nginx.com     }
7001431Svbart@nginx.com 
7011431Svbart@nginx.com     return (uintptr_t) dst;
7021431Svbart@nginx.com }
7031431Svbart@nginx.com 
7041431Svbart@nginx.com 
7051431Svbart@nginx.com nxt_bool_t
7061431Svbart@nginx.com nxt_is_complex_uri_encoded(u_char *src, size_t length)
7071431Svbart@nginx.com {
7081431Svbart@nginx.com     u_char   *reserved, *end, ch;
7091431Svbart@nginx.com     uint8_t  d0, d1;
7101431Svbart@nginx.com 
7111431Svbart@nginx.com     reserved = (u_char *) "?#\0";
7121431Svbart@nginx.com 
7131431Svbart@nginx.com     for (end = src + length; src < end; src++) {
7141431Svbart@nginx.com         ch = *src;
7151431Svbart@nginx.com 
7161431Svbart@nginx.com         if (nxt_uri_escape[ch >> 5] & (1U << (ch & 0x1f))) {
7171431Svbart@nginx.com             if (ch == '%') {
7181431Svbart@nginx.com                 if (end - src < 2) {
7191431Svbart@nginx.com                     return 0;
7201431Svbart@nginx.com                 }
7211431Svbart@nginx.com 
7221431Svbart@nginx.com                 d0 = nxt_hex2int[*++src];
7231431Svbart@nginx.com                 d1 = nxt_hex2int[*++src];
7241431Svbart@nginx.com 
7251431Svbart@nginx.com                 if ((d0 | d1) >= 16) {
7261431Svbart@nginx.com                     return 0;
7271431Svbart@nginx.com                 }
7281431Svbart@nginx.com 
7291431Svbart@nginx.com                 continue;
7301431Svbart@nginx.com             }
7311431Svbart@nginx.com 
7321431Svbart@nginx.com             if (ch == reserved[0]) {
7331431Svbart@nginx.com                 reserved++;
7341431Svbart@nginx.com                 continue;
7351431Svbart@nginx.com             }
7361431Svbart@nginx.com 
7371431Svbart@nginx.com             if (ch == reserved[1]) {
7381431Svbart@nginx.com                 reserved += 2;
7391431Svbart@nginx.com                 continue;
7401431Svbart@nginx.com             }
7411431Svbart@nginx.com 
7421431Svbart@nginx.com             return 0;
7431431Svbart@nginx.com         }
7441431Svbart@nginx.com     }
7451431Svbart@nginx.com 
7461431Svbart@nginx.com     return 1;
7471431Svbart@nginx.com }
748