ngx_string.c

来源:互联网 发布:淘宝客链接转换api 编辑:程序博客网 时间:2024/06/07 09:20
/* * Copyright (C) Igor Sysoev * Copyright (C) Nginx, Inc. */#include <ngx_config.h>#include <ngx_core.h>static u_char *ngx_sprintf_num(u_char *buf, u_char *last, uint64_t ui64,    u_char zero, ngx_uint_t hexadecimal, ngx_uint_t width);static ngx_int_t ngx_decode_base64_internal(ngx_str_t *dst, ngx_str_t *src,    const u_char *basis);voidngx_strlow(u_char *dst, u_char *src, size_t n){    while (n) {        *dst = ngx_tolower(*src);        dst++;        src++;        n--;    }}u_char *ngx_cpystrn(u_char *dst, u_char *src, size_t n){    if (n == 0) {        return dst;    }    while (--n) {        *dst = *src;        if (*dst == '\0') {            return dst;        }        dst++;        src++;    }    *dst = '\0';    return dst;}u_char *ngx_pstrdup(ngx_pool_t *pool, ngx_str_t *src){    u_char  *dst;    dst = ngx_pnalloc(pool, src->len);    if (dst == NULL) {        return NULL;    }    ngx_memcpy(dst, src->data, src->len);    return dst;}/* * supported formats: *    %[0][width][x][X]O        off_t *    %[0][width]T              time_t *    %[0][width][u][x|X]z      ssize_t/size_t *    %[0][width][u][x|X]d      int/u_int *    %[0][width][u][x|X]l      long *    %[0][width|m][u][x|X]i    ngx_int_t/ngx_uint_t *    %[0][width][u][x|X]D      int32_t/uint32_t *    %[0][width][u][x|X]L      int64_t/uint64_t *    %[0][width|m][u][x|X]A    ngx_atomic_int_t/ngx_atomic_uint_t *    %[0][width][.width]f      double, max valid number fits to %18.15f *    %P                        ngx_pid_t *    %M                        ngx_msec_t *    %r                        rlim_t *    %p                        void * *    %V                        ngx_str_t * *    %v                        ngx_variable_value_t * *    %s                        null-terminated string *    %*s                       length and string *    %Z                        '\0' *    %N                        '\n' *    %c                        char *    %%                        % * *  reserved: *    %t                        ptrdiff_t *    %S                        null-terminated wchar string *    %C                        wchar */u_char * ngx_cdeclngx_sprintf(u_char *buf, const char *fmt, ...){    u_char   *p;    va_list   args;    va_start(args, fmt);    p = ngx_vslprintf(buf, (void *) -1, fmt, args);    va_end(args);    return p;}u_char * ngx_cdeclngx_snprintf(u_char *buf, size_t max, const char *fmt, ...){    u_char   *p;    va_list   args;    va_start(args, fmt);    p = ngx_vslprintf(buf, buf + max, fmt, args);    va_end(args);    return p;}u_char * ngx_cdeclngx_slprintf(u_char *buf, u_char *last, const char *fmt, ...){    u_char   *p;    va_list   args;    va_start(args, fmt);    p = ngx_vslprintf(buf, last, fmt, args);    va_end(args);    return p;}u_char *ngx_vslprintf(u_char *buf, u_char *last, const char *fmt, va_list args){    u_char                *p, zero;    int                    d;    double                 f;    size_t                 len, slen;    int64_t                i64;    uint64_t               ui64, frac;    ngx_msec_t             ms;    ngx_uint_t             width, sign, hex, max_width, frac_width, scale, n;    ngx_str_t             *v;    ngx_variable_value_t  *vv;    while (*fmt && buf < last) {        /*         * "buf < last" means that we could copy at least one character:         * the plain character, "%%", "%c", and minus without the checking         */        if (*fmt == '%') {            i64 = 0;            ui64 = 0;            zero = (u_char) ((*++fmt == '0') ? '0' : ' ');            width = 0;            sign = 1;            hex = 0;            max_width = 0;            frac_width = 0;            slen = (size_t) -1;            while (*fmt >= '0' && *fmt <= '9') {                width = width * 10 + *fmt++ - '0';            }            for ( ;; ) {                switch (*fmt) {                case 'u':                    sign = 0;                    fmt++;                    continue;                case 'm':                    max_width = 1;                    fmt++;                    continue;                case 'X':                    hex = 2;                    sign = 0;                    fmt++;                    continue;                case 'x':                    hex = 1;                    sign = 0;                    fmt++;                    continue;                case '.':                    fmt++;                    while (*fmt >= '0' && *fmt <= '9') {                        frac_width = frac_width * 10 + *fmt++ - '0';                    }                    break;                case '*':                    slen = va_arg(args, size_t);                    fmt++;                    continue;                default:                    break;                }                break;            }            switch (*fmt) {            case 'V':                v = va_arg(args, ngx_str_t *);                len = ngx_min(((size_t) (last - buf)), v->len);                buf = ngx_cpymem(buf, v->data, len);                fmt++;                continue;            case 'v':                vv = va_arg(args, ngx_variable_value_t *);                len = ngx_min(((size_t) (last - buf)), vv->len);                buf = ngx_cpymem(buf, vv->data, len);                fmt++;                continue;            case 's':                p = va_arg(args, u_char *);                if (slen == (size_t) -1) {                    while (*p && buf < last) {                        *buf++ = *p++;                    }                } else {                    len = ngx_min(((size_t) (last - buf)), slen);                    buf = ngx_cpymem(buf, p, len);                }                fmt++;                continue;            case 'O':                i64 = (int64_t) va_arg(args, off_t);                sign = 1;                break;            case 'P':                i64 = (int64_t) va_arg(args, ngx_pid_t);                sign = 1;                break;            case 'T':                i64 = (int64_t) va_arg(args, time_t);                sign = 1;                break;            case 'M':                ms = (ngx_msec_t) va_arg(args, ngx_msec_t);                if ((ngx_msec_int_t) ms == -1) {                    sign = 1;                    i64 = -1;                } else {                    sign = 0;                    ui64 = (uint64_t) ms;                }                break;            case 'z':                if (sign) {                    i64 = (int64_t) va_arg(args, ssize_t);                } else {                    ui64 = (uint64_t) va_arg(args, size_t);                }                break;            case 'i':                if (sign) {                    i64 = (int64_t) va_arg(args, ngx_int_t);                } else {                    ui64 = (uint64_t) va_arg(args, ngx_uint_t);                }                if (max_width) {                    width = NGX_INT_T_LEN;                }                break;            case 'd':                if (sign) {                    i64 = (int64_t) va_arg(args, int);                } else {                    ui64 = (uint64_t) va_arg(args, u_int);                }                break;            case 'l':                if (sign) {                    i64 = (int64_t) va_arg(args, long);                } else {                    ui64 = (uint64_t) va_arg(args, u_long);                }                break;            case 'D':                if (sign) {                    i64 = (int64_t) va_arg(args, int32_t);                } else {                    ui64 = (uint64_t) va_arg(args, uint32_t);                }                break;            case 'L':                if (sign) {                    i64 = va_arg(args, int64_t);                } else {                    ui64 = va_arg(args, uint64_t);                }                break;            case 'A':                if (sign) {                    i64 = (int64_t) va_arg(args, ngx_atomic_int_t);                } else {                    ui64 = (uint64_t) va_arg(args, ngx_atomic_uint_t);                }                if (max_width) {                    width = NGX_ATOMIC_T_LEN;                }                break;            case 'f':                f = va_arg(args, double);                if (f < 0) {                    *buf++ = '-';                    f = -f;                }                ui64 = (int64_t) f;                frac = 0;                if (frac_width) {                    scale = 1;                    for (n = frac_width; n; n--) {                        scale *= 10;                    }                    frac = (uint64_t) ((f - (double) ui64) * scale + 0.5);                    if (frac == scale) {                        ui64++;                        frac = 0;                    }                }                buf = ngx_sprintf_num(buf, last, ui64, zero, 0, width);                if (frac_width) {                    if (buf < last) {                        *buf++ = '.';                    }                    buf = ngx_sprintf_num(buf, last, frac, '0', 0, frac_width);                }                fmt++;                continue;#if !(NGX_WIN32)            case 'r':                i64 = (int64_t) va_arg(args, rlim_t);                sign = 1;                break;#endif            case 'p':                ui64 = (uintptr_t) va_arg(args, void *);                hex = 2;                sign = 0;                zero = '0';                width = NGX_PTR_SIZE * 2;                break;            case 'c':                d = va_arg(args, int);                *buf++ = (u_char) (d & 0xff);                fmt++;                continue;            case 'Z':                *buf++ = '\0';                fmt++;                continue;            case 'N':#if (NGX_WIN32)                *buf++ = CR;#endif                *buf++ = LF;                fmt++;                continue;            case '%':                *buf++ = '%';                fmt++;                continue;            default:                *buf++ = *fmt++;                continue;            }            if (sign) {                if (i64 < 0) {                    *buf++ = '-';                    ui64 = (uint64_t) -i64;                } else {                    ui64 = (uint64_t) i64;                }            }            buf = ngx_sprintf_num(buf, last, ui64, zero, hex, width);            fmt++;        } else {            *buf++ = *fmt++;        }    }    return buf;}static u_char *ngx_sprintf_num(u_char *buf, u_char *last, uint64_t ui64, u_char zero,    ngx_uint_t hexadecimal, ngx_uint_t width){    u_char         *p, temp[NGX_INT64_LEN + 1];                       /*                        * we need temp[NGX_INT64_LEN] only,                        * but icc issues the warning                        */    size_t          len;    uint32_t        ui32;    static u_char   hex[] = "0123456789abcdef";    static u_char   HEX[] = "0123456789ABCDEF";    p = temp + NGX_INT64_LEN;    if (hexadecimal == 0) {        if (ui64 <= NGX_MAX_UINT32_VALUE) {            /*             * To divide 64-bit numbers and to find remainders             * on the x86 platform gcc and icc call the libc functions             * [u]divdi3() and [u]moddi3(), they call another function             * in its turn.  On FreeBSD it is the qdivrem() function,             * its source code is about 170 lines of the code.             * The glibc counterpart is about 150 lines of the code.             *             * For 32-bit numbers and some divisors gcc and icc use             * a inlined multiplication and shifts.  For example,             * unsigned "i32 / 10" is compiled to             *             *     (i32 * 0xCCCCCCCD) >> 35             */            ui32 = (uint32_t) ui64;            do {                *--p = (u_char) (ui32 % 10 + '0');            } while (ui32 /= 10);        } else {            do {                *--p = (u_char) (ui64 % 10 + '0');            } while (ui64 /= 10);        }    } else if (hexadecimal == 1) {        do {            /* the "(uint32_t)" cast disables the BCC's warning */            *--p = hex[(uint32_t) (ui64 & 0xf)];        } while (ui64 >>= 4);    } else { /* hexadecimal == 2 */        do {            /* the "(uint32_t)" cast disables the BCC's warning */            *--p = HEX[(uint32_t) (ui64 & 0xf)];        } while (ui64 >>= 4);    }    /* zero or space padding */    len = (temp + NGX_INT64_LEN) - p;    while (len++ < width && buf < last) {        *buf++ = zero;    }    /* number safe copy */    len = (temp + NGX_INT64_LEN) - p;    if (buf + len > last) {        len = last - buf;    }    return ngx_cpymem(buf, p, len);}/* * We use ngx_strcasecmp()/ngx_strncasecmp() for 7-bit ASCII strings only, * and implement our own ngx_strcasecmp()/ngx_strncasecmp() * to avoid libc locale overhead.  Besides, we use the ngx_uint_t's * instead of the u_char's, because they are slightly faster. */ngx_int_tngx_strcasecmp(u_char *s1, u_char *s2){    ngx_uint_t  c1, c2;    for ( ;; ) {        c1 = (ngx_uint_t) *s1++;        c2 = (ngx_uint_t) *s2++;        c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;        c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;        if (c1 == c2) {            if (c1) {                continue;            }            return 0;        }        return c1 - c2;    }}ngx_int_tngx_strncasecmp(u_char *s1, u_char *s2, size_t n){    ngx_uint_t  c1, c2;    while (n) {        c1 = (ngx_uint_t) *s1++;        c2 = (ngx_uint_t) *s2++;        c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;        c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;        if (c1 == c2) {            if (c1) {                n--;                continue;            }            return 0;        }        return c1 - c2;    }    return 0;}u_char *ngx_strnstr(u_char *s1, char *s2, size_t len){    u_char  c1, c2;    size_t  n;    c2 = *(u_char *) s2++;    n = ngx_strlen(s2);    do {        do {            if (len-- == 0) {                return NULL;            }            c1 = *s1++;            if (c1 == 0) {                return NULL;            }        } while (c1 != c2);        if (n > len) {            return NULL;        }    } while (ngx_strncmp(s1, (u_char *) s2, n) != 0);    return --s1;}/* * ngx_strstrn() and ngx_strcasestrn() are intended to search for static * substring with known length in null-terminated string. The argument n * must be length of the second substring - 1. */u_char *ngx_strstrn(u_char *s1, char *s2, size_t n){    u_char  c1, c2;    c2 = *(u_char *) s2++;    do {        do {            c1 = *s1++;            if (c1 == 0) {                return NULL;            }        } while (c1 != c2);    } while (ngx_strncmp(s1, (u_char *) s2, n) != 0);    return --s1;}u_char *ngx_strcasestrn(u_char *s1, char *s2, size_t n){    ngx_uint_t  c1, c2;    c2 = (ngx_uint_t) *s2++;    c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;    do {        do {            c1 = (ngx_uint_t) *s1++;            if (c1 == 0) {                return NULL;            }            c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;        } while (c1 != c2);    } while (ngx_strncasecmp(s1, (u_char *) s2, n) != 0);    return --s1;}/* * ngx_strlcasestrn() is intended to search for static substring * with known length in string until the argument last. The argument n * must be length of the second substring - 1. */u_char *ngx_strlcasestrn(u_char *s1, u_char *last, u_char *s2, size_t n){    ngx_uint_t  c1, c2;    c2 = (ngx_uint_t) *s2++;    c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;    last -= n;    do {        do {            if (s1 >= last) {                return NULL;            }            c1 = (ngx_uint_t) *s1++;            c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;        } while (c1 != c2);    } while (ngx_strncasecmp(s1, s2, n) != 0);    return --s1;}ngx_int_tngx_rstrncmp(u_char *s1, u_char *s2, size_t n){    if (n == 0) {        return 0;    }    n--;    for ( ;; ) {        if (s1[n] != s2[n]) {            return s1[n] - s2[n];        }        if (n == 0) {            return 0;        }        n--;    }}ngx_int_tngx_rstrncasecmp(u_char *s1, u_char *s2, size_t n){    u_char  c1, c2;    if (n == 0) {        return 0;    }    n--;    for ( ;; ) {        c1 = s1[n];        if (c1 >= 'a' && c1 <= 'z') {            c1 -= 'a' - 'A';        }        c2 = s2[n];        if (c2 >= 'a' && c2 <= 'z') {            c2 -= 'a' - 'A';        }        if (c1 != c2) {            return c1 - c2;        }        if (n == 0) {            return 0;        }        n--;    }}ngx_int_tngx_memn2cmp(u_char *s1, u_char *s2, size_t n1, size_t n2){    size_t     n;    ngx_int_t  m, z;    if (n1 <= n2) {        n = n1;        z = -1;    } else {        n = n2;        z = 1;    }    m = ngx_memcmp(s1, s2, n);    if (m || n1 == n2) {        return m;    }    return z;}ngx_int_tngx_dns_strcmp(u_char *s1, u_char *s2){    ngx_uint_t  c1, c2;    for ( ;; ) {        c1 = (ngx_uint_t) *s1++;        c2 = (ngx_uint_t) *s2++;        c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;        c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;        if (c1 == c2) {            if (c1) {                continue;            }            return 0;        }        /* in ASCII '.' > '-', but we need '.' to be the lowest character */        c1 = (c1 == '.') ? ' ' : c1;        c2 = (c2 == '.') ? ' ' : c2;        return c1 - c2;    }}ngx_int_tngx_atoi(u_char *line, size_t n){    ngx_int_t  value;    if (n == 0) {        return NGX_ERROR;    }    for (value = 0; n--; line++) {        if (*line < '0' || *line > '9') {            return NGX_ERROR;        }        value = value * 10 + (*line - '0');    }    if (value < 0) {        return NGX_ERROR;    } else {        return value;    }}/* parse a fixed point number, e.g., ngx_atofp("10.5", 4, 2) returns 1050 */ngx_int_tngx_atofp(u_char *line, size_t n, size_t point){    ngx_int_t   value;    ngx_uint_t  dot;    if (n == 0) {        return NGX_ERROR;    }    dot = 0;    for (value = 0; n--; line++) {        if (point == 0) {            return NGX_ERROR;        }        if (*line == '.') {            if (dot) {                return NGX_ERROR;            }            dot = 1;            continue;        }        if (*line < '0' || *line > '9') {            return NGX_ERROR;        }        value = value * 10 + (*line - '0');        point -= dot;    }    while (point--) {        value = value * 10;    }    if (value < 0) {        return NGX_ERROR;    } else {        return value;    }}ssize_tngx_atosz(u_char *line, size_t n){    ssize_t  value;    if (n == 0) {        return NGX_ERROR;    }    for (value = 0; n--; line++) {        if (*line < '0' || *line > '9') {            return NGX_ERROR;        }        value = value * 10 + (*line - '0');    }    if (value < 0) {        return NGX_ERROR;    } else {        return value;    }}off_tngx_atoof(u_char *line, size_t n){    off_t  value;    if (n == 0) {        return NGX_ERROR;    }    for (value = 0; n--; line++) {        if (*line < '0' || *line > '9') {            return NGX_ERROR;        }        value = value * 10 + (*line - '0');    }    if (value < 0) {        return NGX_ERROR;    } else {        return value;    }}time_tngx_atotm(u_char *line, size_t n){    time_t  value;    if (n == 0) {        return NGX_ERROR;    }    for (value = 0; n--; line++) {        if (*line < '0' || *line > '9') {            return NGX_ERROR;        }        value = value * 10 + (*line - '0');    }    if (value < 0) {        return NGX_ERROR;    } else {        return value;    }}ngx_int_tngx_hextoi(u_char *line, size_t n){    u_char     c, ch;    ngx_int_t  value;    if (n == 0) {        return NGX_ERROR;    }    for (value = 0; n--; line++) {        ch = *line;        if (ch >= '0' && ch <= '9') {            value = value * 16 + (ch - '0');            continue;        }        c = (u_char) (ch | 0x20);        if (c >= 'a' && c <= 'f') {            value = value * 16 + (c - 'a' + 10);            continue;        }        return NGX_ERROR;    }    if (value < 0) {        return NGX_ERROR;    } else {        return value;    }}u_char *ngx_hex_dump(u_char *dst, u_char *src, size_t len){    static u_char  hex[] = "0123456789abcdef";    while (len--) {        *dst++ = hex[*src >> 4];        *dst++ = hex[*src++ & 0xf];    }    return dst;}voidngx_encode_base64(ngx_str_t *dst, ngx_str_t *src){    u_char         *d, *s;    size_t          len;    static u_char   basis64[] =            "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";    len = src->len;    s = src->data;    d = dst->data;    while (len > 2) {        *d++ = basis64[(s[0] >> 2) & 0x3f];        *d++ = basis64[((s[0] & 3) << 4) | (s[1] >> 4)];        *d++ = basis64[((s[1] & 0x0f) << 2) | (s[2] >> 6)];        *d++ = basis64[s[2] & 0x3f];        s += 3;        len -= 3;    }    if (len) {        *d++ = basis64[(s[0] >> 2) & 0x3f];        if (len == 1) {            *d++ = basis64[(s[0] & 3) << 4];            *d++ = '=';        } else {            *d++ = basis64[((s[0] & 3) << 4) | (s[1] >> 4)];            *d++ = basis64[(s[1] & 0x0f) << 2];        }        *d++ = '=';    }    dst->len = d - dst->data;}ngx_int_tngx_decode_base64(ngx_str_t *dst, ngx_str_t *src){    static u_char   basis64[] = {        77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,        77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,        77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 62, 77, 77, 77, 63,        52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 77, 77, 77, 77, 77, 77,        77,  0,  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, 77, 77, 77, 77, 77,        77, 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, 77, 77, 77, 77, 77,        77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,        77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,        77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,        77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,        77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,        77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,        77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,        77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77    };    return ngx_decode_base64_internal(dst, src, basis64);}ngx_int_tngx_decode_base64url(ngx_str_t *dst, ngx_str_t *src){    static u_char   basis64[] = {        77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,        77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,        77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 62, 77, 77,        52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 77, 77, 77, 77, 77, 77,        77,  0,  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, 77, 77, 77, 77, 63,        77, 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, 77, 77, 77, 77, 77,        77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,        77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,        77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,        77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,        77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,        77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,        77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,        77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77    };    return ngx_decode_base64_internal(dst, src, basis64);}static ngx_int_tngx_decode_base64_internal(ngx_str_t *dst, ngx_str_t *src, const u_char *basis){    size_t          len;    u_char         *d, *s;    for (len = 0; len < src->len; len++) {        if (src->data[len] == '=') {            break;        }        if (basis[src->data[len]] == 77) {            return NGX_ERROR;        }    }    if (len % 4 == 1) {        return NGX_ERROR;    }    s = src->data;    d = dst->data;    while (len > 3) {        *d++ = (u_char) (basis[s[0]] << 2 | basis[s[1]] >> 4);        *d++ = (u_char) (basis[s[1]] << 4 | basis[s[2]] >> 2);        *d++ = (u_char) (basis[s[2]] << 6 | basis[s[3]]);        s += 4;        len -= 4;    }    if (len > 1) {        *d++ = (u_char) (basis[s[0]] << 2 | basis[s[1]] >> 4);    }    if (len > 2) {        *d++ = (u_char) (basis[s[1]] << 4 | basis[s[2]] >> 2);    }    dst->len = d - dst->data;    return NGX_OK;}/* * ngx_utf8_decode() decodes two and more bytes UTF sequences only * the return values: *    0x80 - 0x10ffff         valid character *    0x110000 - 0xfffffffd   invalid sequence *    0xfffffffe              incomplete sequence *    0xffffffff              error */uint32_tngx_utf8_decode(u_char **p, size_t n){    size_t    len;    uint32_t  u, i, valid;    u = **p;    if (u >= 0xf0) {        u &= 0x07;        valid = 0xffff;        len = 3;    } else if (u >= 0xe0) {        u &= 0x0f;        valid = 0x7ff;        len = 2;    } else if (u >= 0xc2) {        u &= 0x1f;        valid = 0x7f;        len = 1;    } else {        (*p)++;        return 0xffffffff;    }    if (n - 1 < len) {        return 0xfffffffe;    }    (*p)++;    while (len) {        i = *(*p)++;        if (i < 0x80) {            return 0xffffffff;        }        u = (u << 6) | (i & 0x3f);        len--;    }    if (u > valid) {        return u;    }    return 0xffffffff;}size_tngx_utf8_length(u_char *p, size_t n){    u_char  c, *last;    size_t  len;    last = p + n;    for (len = 0; p < last; len++) {        c = *p;        if (c < 0x80) {            p++;            continue;        }        if (ngx_utf8_decode(&p, n) > 0x10ffff) {            /* invalid UTF-8 */            return n;        }    }    return len;}u_char *ngx_utf8_cpystrn(u_char *dst, u_char *src, size_t n, size_t len){    u_char  c, *next;    if (n == 0) {        return dst;    }    while (--n) {        c = *src;        *dst = c;        if (c < 0x80) {            if (c != '\0') {                dst++;                src++;                len--;                continue;            }            return dst;        }        next = src;        if (ngx_utf8_decode(&next, len) > 0x10ffff) {            /* invalid UTF-8 */            break;        }        while (src < next) {            *dst++ = *src++;            len--;        }    }    *dst = '\0';    return dst;}uintptr_tngx_escape_uri(u_char *dst, u_char *src, size_t size, ngx_uint_t type){    ngx_uint_t      n;    uint32_t       *escape;    static u_char   hex[] = "0123456789abcdef";                    /* " ", "#", "%", "?", %00-%1F, %7F-%FF */    static uint32_t   uri[] = {        0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */                    /* ?>=< ;:98 7654 3210  /.-, +*)( '&%$ #"!  */        0x80000029, /* 1000 0000 0000 0000  0000 0000 0010 1001 */                    /* _^]\ [ZYX WVUT SRQP  ONML KJIH GFED CBA@ */        0x00000000, /* 0000 0000 0000 0000  0000 0000 0000 0000 */                    /*  ~}| {zyx wvut srqp  onml kjih gfed cba` */        0x80000000, /* 1000 0000 0000 0000  0000 0000 0000 0000 */        0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */        0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */        0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */        0xffffffff  /* 1111 1111 1111 1111  1111 1111 1111 1111 */    };                    /* " ", "#", "%", "&", "+", "?", %00-%1F, %7F-%FF */    static uint32_t   args[] = {        0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */                    /* ?>=< ;:98 7654 3210  /.-, +*)( '&%$ #"!  */        0x88000869, /* 1000 1000 0000 0000  0000 1000 0110 1001 */                    /* _^]\ [ZYX WVUT SRQP  ONML KJIH GFED CBA@ */        0x00000000, /* 0000 0000 0000 0000  0000 0000 0000 0000 */                    /*  ~}| {zyx wvut srqp  onml kjih gfed cba` */        0x80000000, /* 1000 0000 0000 0000  0000 0000 0000 0000 */        0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */        0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */        0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */        0xffffffff  /* 1111 1111 1111 1111  1111 1111 1111 1111 */    };                    /* not ALPHA, DIGIT, "-", ".", "_", "~" */    static uint32_t   uri_component[] = {        0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */                    /* ?>=< ;:98 7654 3210  /.-, +*)( '&%$ #"!  */        0xfc009fff, /* 1111 1100 0000 0000  1001 1111 1111 1111 */                    /* _^]\ [ZYX WVUT SRQP  ONML KJIH GFED CBA@ */        0x78000001, /* 0111 1000 0000 0000  0000 0000 0000 0001 */                    /*  ~}| {zyx wvut srqp  onml kjih gfed cba` */        0xb8000001, /* 1011 1000 0000 0000  0000 0000 0000 0001 */        0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */        0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */        0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */        0xffffffff  /* 1111 1111 1111 1111  1111 1111 1111 1111 */    };                    /* " ", "#", """, "%", "'", %00-%1F, %7F-%FF */    static uint32_t   html[] = {        0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */                    /* ?>=< ;:98 7654 3210  /.-, +*)( '&%$ #"!  */        0x000000ad, /* 0000 0000 0000 0000  0000 0000 1010 1101 */                    /* _^]\ [ZYX WVUT SRQP  ONML KJIH GFED CBA@ */        0x00000000, /* 0000 0000 0000 0000  0000 0000 0000 0000 */                    /*  ~}| {zyx wvut srqp  onml kjih gfed cba` */        0x80000000, /* 1000 0000 0000 0000  0000 0000 0000 0000 */        0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */        0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */        0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */        0xffffffff  /* 1111 1111 1111 1111  1111 1111 1111 1111 */    };                    /* " ", """, "%", "'", %00-%1F, %7F-%FF */    static uint32_t   refresh[] = {        0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */                    /* ?>=< ;:98 7654 3210  /.-, +*)( '&%$ #"!  */        0x00000085, /* 0000 0000 0000 0000  0000 0000 1000 0101 */                    /* _^]\ [ZYX WVUT SRQP  ONML KJIH GFED CBA@ */        0x00000000, /* 0000 0000 0000 0000  0000 0000 0000 0000 */                    /*  ~}| {zyx wvut srqp  onml kjih gfed cba` */        0x80000000, /* 1000 0000 0000 0000  0000 0000 0000 0000 */        0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */        0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */        0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */        0xffffffff  /* 1111 1111 1111 1111  1111 1111 1111 1111 */    };                    /* " ", "%", %00-%1F */    static uint32_t   memcached[] = {        0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */                    /* ?>=< ;:98 7654 3210  /.-, +*)( '&%$ #"!  */        0x00000021, /* 0000 0000 0000 0000  0000 0000 0010 0001 */                    /* _^]\ [ZYX WVUT SRQP  ONML KJIH GFED CBA@ */        0x00000000, /* 0000 0000 0000 0000  0000 0000 0000 0000 */                    /*  ~}| {zyx wvut srqp  onml kjih gfed cba` */        0x00000000, /* 0000 0000 0000 0000  0000 0000 0000 0000 */        0x00000000, /* 0000 0000 0000 0000  0000 0000 0000 0000 */        0x00000000, /* 0000 0000 0000 0000  0000 0000 0000 0000 */        0x00000000, /* 0000 0000 0000 0000  0000 0000 0000 0000 */        0x00000000, /* 0000 0000 0000 0000  0000 0000 0000 0000 */    };                    /* mail_auth is the same as memcached */    static uint32_t  *map[] =        { uri, args, uri_component, html, refresh, memcached, memcached };    escape = map[type];    if (dst == NULL) {        /* find the number of the characters to be escaped */        n = 0;        while (size) {            if (escape[*src >> 5] & (1 << (*src & 0x1f))) {                n++;            }            src++;            size--;        }        return (uintptr_t) n;    }    while (size) {        if (escape[*src >> 5] & (1 << (*src & 0x1f))) {            *dst++ = '%';            *dst++ = hex[*src >> 4];            *dst++ = hex[*src & 0xf];            src++;        } else {            *dst++ = *src++;        }        size--;    }    return (uintptr_t) dst;}voidngx_unescape_uri(u_char **dst, u_char **src, size_t size, ngx_uint_t type){    u_char  *d, *s, ch, c, decoded;    enum {        sw_usual = 0,        sw_quoted,        sw_quoted_second    } state;    d = *dst;    s = *src;    state = 0;    decoded = 0;    while (size--) {        ch = *s++;        switch (state) {        case sw_usual:            if (ch == '?'                && (type & (NGX_UNESCAPE_URI|NGX_UNESCAPE_REDIRECT)))            {                *d++ = ch;                goto done;            }            if (ch == '%') {                state = sw_quoted;                break;            }            *d++ = ch;            break;        case sw_quoted:            if (ch >= '0' && ch <= '9') {                decoded = (u_char) (ch - '0');                state = sw_quoted_second;                break;            }            c = (u_char) (ch | 0x20);            if (c >= 'a' && c <= 'f') {                decoded = (u_char) (c - 'a' + 10);                state = sw_quoted_second;                break;            }            /* the invalid quoted character */            state = sw_usual;            *d++ = ch;            break;        case sw_quoted_second:            state = sw_usual;            if (ch >= '0' && ch <= '9') {                ch = (u_char) ((decoded << 4) + ch - '0');                if (type & NGX_UNESCAPE_REDIRECT) {                    if (ch > '%' && ch < 0x7f) {                        *d++ = ch;                        break;                    }                    *d++ = '%'; *d++ = *(s - 2); *d++ = *(s - 1);                    break;                }                *d++ = ch;                break;            }            c = (u_char) (ch | 0x20);            if (c >= 'a' && c <= 'f') {                ch = (u_char) ((decoded << 4) + c - 'a' + 10);                if (type & NGX_UNESCAPE_URI) {                    if (ch == '?') {                        *d++ = ch;                        goto done;                    }                    *d++ = ch;                    break;                }                if (type & NGX_UNESCAPE_REDIRECT) {                    if (ch == '?') {                        *d++ = ch;                        goto done;                    }                    if (ch > '%' && ch < 0x7f) {                        *d++ = ch;                        break;                    }                    *d++ = '%'; *d++ = *(s - 2); *d++ = *(s - 1);                    break;                }                *d++ = ch;                break;            }            /* the invalid quoted character */            break;        }    }done:    *dst = d;    *src = s;}uintptr_tngx_escape_html(u_char *dst, u_char *src, size_t size){    u_char      ch;    ngx_uint_t  len;    if (dst == NULL) {        len = 0;        while (size) {            switch (*src++) {            case '<':                len += sizeof("<") - 2;                break;            case '>':                len += sizeof(">") - 2;                break;            case '&':                len += sizeof("&") - 2;                break;            case '"':                len += sizeof(""") - 2;                break;            default:                break;            }            size--;        }        return (uintptr_t) len;    }    while (size) {        ch = *src++;        switch (ch) {        case '<':            *dst++ = '&'; *dst++ = 'l'; *dst++ = 't'; *dst++ = ';';            break;        case '>':            *dst++ = '&'; *dst++ = 'g'; *dst++ = 't'; *dst++ = ';';            break;        case '&':            *dst++ = '&'; *dst++ = 'a'; *dst++ = 'm'; *dst++ = 'p';            *dst++ = ';';            break;        case '"':            *dst++ = '&'; *dst++ = 'q'; *dst++ = 'u'; *dst++ = 'o';            *dst++ = 't'; *dst++ = ';';            break;        default:            *dst++ = ch;            break;        }        size--;    }    return (uintptr_t) dst;}voidngx_str_rbtree_insert_value(ngx_rbtree_node_t *temp,    ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel){    ngx_str_node_t      *n, *t;    ngx_rbtree_node_t  **p;    for ( ;; ) {        n = (ngx_str_node_t *) node;        t = (ngx_str_node_t *) temp;        if (node->key != temp->key) {            p = (node->key < temp->key) ? &temp->left : &temp->right;        } else if (n->str.len != t->str.len) {            p = (n->str.len < t->str.len) ? &temp->left : &temp->right;        } else {            p = (ngx_memcmp(n->str.data, t->str.data, n->str.len) < 0)                 ? &temp->left : &temp->right;        }        if (*p == sentinel) {            break;        }        temp = *p;    }    *p = node;    node->parent = temp;    node->left = sentinel;    node->right = sentinel;    ngx_rbt_red(node);}ngx_str_node_t *ngx_str_rbtree_lookup(ngx_rbtree_t *rbtree, ngx_str_t *val, uint32_t hash){    ngx_int_t           rc;    ngx_str_node_t     *n;    ngx_rbtree_node_t  *node, *sentinel;    node = rbtree->root;    sentinel = rbtree->sentinel;    while (node != sentinel) {        n = (ngx_str_node_t *) node;        if (hash != node->key) {            node = (hash < node->key) ? node->left : node->right;            continue;        }        if (val->len != n->str.len) {            node = (val->len < n->str.len) ? node->left : node->right;            continue;        }        rc = ngx_memcmp(val->data, n->str.data, val->len);        if (rc < 0) {            node = node->left;            continue;        }        if (rc > 0) {            node = node->right;            continue;        }        return n;    }    return NULL;}/* ngx_sort() is implemented as insertion sort because we need stable sort */voidngx_sort(void *base, size_t n, size_t size,    ngx_int_t (*cmp)(const void *, const void *)){    u_char  *p1, *p2, *p;    p = ngx_alloc(size, ngx_cycle->log);    if (p == NULL) {        return;    }    for (p1 = (u_char *) base + size;         p1 < (u_char *) base + n * size;         p1 += size)    {        ngx_memcpy(p, p1, size);        for (p2 = p1;             p2 > (u_char *) base && cmp(p2 - size, p) > 0;             p2 -= size)        {            ngx_memcpy(p2, p2 - size, size);        }        ngx_memcpy(p2, p, size);    }    ngx_free(p);}#if (NGX_MEMCPY_LIMIT)void *ngx_memcpy(void *dst, const void *src, size_t n){    if (n > NGX_MEMCPY_LIMIT) {        ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "memcpy %uz bytes", n);        ngx_debug_point();    }    return memcpy(dst, src, n);}#endif

原创粉丝点击