Annotation of embedaddon/nginx/src/core/ngx_string.c, revision 1.1
1.1 ! misho 1:
! 2: /*
! 3: * Copyright (C) Igor Sysoev
! 4: * Copyright (C) Nginx, Inc.
! 5: */
! 6:
! 7:
! 8: #include <ngx_config.h>
! 9: #include <ngx_core.h>
! 10:
! 11:
! 12: static u_char *ngx_sprintf_num(u_char *buf, u_char *last, uint64_t ui64,
! 13: u_char zero, ngx_uint_t hexadecimal, ngx_uint_t width);
! 14: static ngx_int_t ngx_decode_base64_internal(ngx_str_t *dst, ngx_str_t *src,
! 15: const u_char *basis);
! 16:
! 17:
! 18: void
! 19: ngx_strlow(u_char *dst, u_char *src, size_t n)
! 20: {
! 21: while (n) {
! 22: *dst = ngx_tolower(*src);
! 23: dst++;
! 24: src++;
! 25: n--;
! 26: }
! 27: }
! 28:
! 29:
! 30: u_char *
! 31: ngx_cpystrn(u_char *dst, u_char *src, size_t n)
! 32: {
! 33: if (n == 0) {
! 34: return dst;
! 35: }
! 36:
! 37: while (--n) {
! 38: *dst = *src;
! 39:
! 40: if (*dst == '\0') {
! 41: return dst;
! 42: }
! 43:
! 44: dst++;
! 45: src++;
! 46: }
! 47:
! 48: *dst = '\0';
! 49:
! 50: return dst;
! 51: }
! 52:
! 53:
! 54: u_char *
! 55: ngx_pstrdup(ngx_pool_t *pool, ngx_str_t *src)
! 56: {
! 57: u_char *dst;
! 58:
! 59: dst = ngx_pnalloc(pool, src->len);
! 60: if (dst == NULL) {
! 61: return NULL;
! 62: }
! 63:
! 64: ngx_memcpy(dst, src->data, src->len);
! 65:
! 66: return dst;
! 67: }
! 68:
! 69:
! 70: /*
! 71: * supported formats:
! 72: * %[0][width][x][X]O off_t
! 73: * %[0][width]T time_t
! 74: * %[0][width][u][x|X]z ssize_t/size_t
! 75: * %[0][width][u][x|X]d int/u_int
! 76: * %[0][width][u][x|X]l long
! 77: * %[0][width|m][u][x|X]i ngx_int_t/ngx_uint_t
! 78: * %[0][width][u][x|X]D int32_t/uint32_t
! 79: * %[0][width][u][x|X]L int64_t/uint64_t
! 80: * %[0][width|m][u][x|X]A ngx_atomic_int_t/ngx_atomic_uint_t
! 81: * %[0][width][.width]f double, max valid number fits to %18.15f
! 82: * %P ngx_pid_t
! 83: * %M ngx_msec_t
! 84: * %r rlim_t
! 85: * %p void *
! 86: * %V ngx_str_t *
! 87: * %v ngx_variable_value_t *
! 88: * %s null-terminated string
! 89: * %*s length and string
! 90: * %Z '\0'
! 91: * %N '\n'
! 92: * %c char
! 93: * %% %
! 94: *
! 95: * reserved:
! 96: * %t ptrdiff_t
! 97: * %S null-terminated wchar string
! 98: * %C wchar
! 99: */
! 100:
! 101:
! 102: u_char * ngx_cdecl
! 103: ngx_sprintf(u_char *buf, const char *fmt, ...)
! 104: {
! 105: u_char *p;
! 106: va_list args;
! 107:
! 108: va_start(args, fmt);
! 109: p = ngx_vslprintf(buf, (void *) -1, fmt, args);
! 110: va_end(args);
! 111:
! 112: return p;
! 113: }
! 114:
! 115:
! 116: u_char * ngx_cdecl
! 117: ngx_snprintf(u_char *buf, size_t max, const char *fmt, ...)
! 118: {
! 119: u_char *p;
! 120: va_list args;
! 121:
! 122: va_start(args, fmt);
! 123: p = ngx_vslprintf(buf, buf + max, fmt, args);
! 124: va_end(args);
! 125:
! 126: return p;
! 127: }
! 128:
! 129:
! 130: u_char * ngx_cdecl
! 131: ngx_slprintf(u_char *buf, u_char *last, const char *fmt, ...)
! 132: {
! 133: u_char *p;
! 134: va_list args;
! 135:
! 136: va_start(args, fmt);
! 137: p = ngx_vslprintf(buf, last, fmt, args);
! 138: va_end(args);
! 139:
! 140: return p;
! 141: }
! 142:
! 143:
! 144: u_char *
! 145: ngx_vslprintf(u_char *buf, u_char *last, const char *fmt, va_list args)
! 146: {
! 147: u_char *p, zero;
! 148: int d;
! 149: double f;
! 150: size_t len, slen;
! 151: int64_t i64;
! 152: uint64_t ui64, frac;
! 153: ngx_msec_t ms;
! 154: ngx_uint_t width, sign, hex, max_width, frac_width, scale, n;
! 155: ngx_str_t *v;
! 156: ngx_variable_value_t *vv;
! 157:
! 158: while (*fmt && buf < last) {
! 159:
! 160: /*
! 161: * "buf < last" means that we could copy at least one character:
! 162: * the plain character, "%%", "%c", and minus without the checking
! 163: */
! 164:
! 165: if (*fmt == '%') {
! 166:
! 167: i64 = 0;
! 168: ui64 = 0;
! 169:
! 170: zero = (u_char) ((*++fmt == '0') ? '0' : ' ');
! 171: width = 0;
! 172: sign = 1;
! 173: hex = 0;
! 174: max_width = 0;
! 175: frac_width = 0;
! 176: slen = (size_t) -1;
! 177:
! 178: while (*fmt >= '0' && *fmt <= '9') {
! 179: width = width * 10 + *fmt++ - '0';
! 180: }
! 181:
! 182:
! 183: for ( ;; ) {
! 184: switch (*fmt) {
! 185:
! 186: case 'u':
! 187: sign = 0;
! 188: fmt++;
! 189: continue;
! 190:
! 191: case 'm':
! 192: max_width = 1;
! 193: fmt++;
! 194: continue;
! 195:
! 196: case 'X':
! 197: hex = 2;
! 198: sign = 0;
! 199: fmt++;
! 200: continue;
! 201:
! 202: case 'x':
! 203: hex = 1;
! 204: sign = 0;
! 205: fmt++;
! 206: continue;
! 207:
! 208: case '.':
! 209: fmt++;
! 210:
! 211: while (*fmt >= '0' && *fmt <= '9') {
! 212: frac_width = frac_width * 10 + *fmt++ - '0';
! 213: }
! 214:
! 215: break;
! 216:
! 217: case '*':
! 218: slen = va_arg(args, size_t);
! 219: fmt++;
! 220: continue;
! 221:
! 222: default:
! 223: break;
! 224: }
! 225:
! 226: break;
! 227: }
! 228:
! 229:
! 230: switch (*fmt) {
! 231:
! 232: case 'V':
! 233: v = va_arg(args, ngx_str_t *);
! 234:
! 235: len = ngx_min(((size_t) (last - buf)), v->len);
! 236: buf = ngx_cpymem(buf, v->data, len);
! 237: fmt++;
! 238:
! 239: continue;
! 240:
! 241: case 'v':
! 242: vv = va_arg(args, ngx_variable_value_t *);
! 243:
! 244: len = ngx_min(((size_t) (last - buf)), vv->len);
! 245: buf = ngx_cpymem(buf, vv->data, len);
! 246: fmt++;
! 247:
! 248: continue;
! 249:
! 250: case 's':
! 251: p = va_arg(args, u_char *);
! 252:
! 253: if (slen == (size_t) -1) {
! 254: while (*p && buf < last) {
! 255: *buf++ = *p++;
! 256: }
! 257:
! 258: } else {
! 259: len = ngx_min(((size_t) (last - buf)), slen);
! 260: buf = ngx_cpymem(buf, p, len);
! 261: }
! 262:
! 263: fmt++;
! 264:
! 265: continue;
! 266:
! 267: case 'O':
! 268: i64 = (int64_t) va_arg(args, off_t);
! 269: sign = 1;
! 270: break;
! 271:
! 272: case 'P':
! 273: i64 = (int64_t) va_arg(args, ngx_pid_t);
! 274: sign = 1;
! 275: break;
! 276:
! 277: case 'T':
! 278: i64 = (int64_t) va_arg(args, time_t);
! 279: sign = 1;
! 280: break;
! 281:
! 282: case 'M':
! 283: ms = (ngx_msec_t) va_arg(args, ngx_msec_t);
! 284: if ((ngx_msec_int_t) ms == -1) {
! 285: sign = 1;
! 286: i64 = -1;
! 287: } else {
! 288: sign = 0;
! 289: ui64 = (uint64_t) ms;
! 290: }
! 291: break;
! 292:
! 293: case 'z':
! 294: if (sign) {
! 295: i64 = (int64_t) va_arg(args, ssize_t);
! 296: } else {
! 297: ui64 = (uint64_t) va_arg(args, size_t);
! 298: }
! 299: break;
! 300:
! 301: case 'i':
! 302: if (sign) {
! 303: i64 = (int64_t) va_arg(args, ngx_int_t);
! 304: } else {
! 305: ui64 = (uint64_t) va_arg(args, ngx_uint_t);
! 306: }
! 307:
! 308: if (max_width) {
! 309: width = NGX_INT_T_LEN;
! 310: }
! 311:
! 312: break;
! 313:
! 314: case 'd':
! 315: if (sign) {
! 316: i64 = (int64_t) va_arg(args, int);
! 317: } else {
! 318: ui64 = (uint64_t) va_arg(args, u_int);
! 319: }
! 320: break;
! 321:
! 322: case 'l':
! 323: if (sign) {
! 324: i64 = (int64_t) va_arg(args, long);
! 325: } else {
! 326: ui64 = (uint64_t) va_arg(args, u_long);
! 327: }
! 328: break;
! 329:
! 330: case 'D':
! 331: if (sign) {
! 332: i64 = (int64_t) va_arg(args, int32_t);
! 333: } else {
! 334: ui64 = (uint64_t) va_arg(args, uint32_t);
! 335: }
! 336: break;
! 337:
! 338: case 'L':
! 339: if (sign) {
! 340: i64 = va_arg(args, int64_t);
! 341: } else {
! 342: ui64 = va_arg(args, uint64_t);
! 343: }
! 344: break;
! 345:
! 346: case 'A':
! 347: if (sign) {
! 348: i64 = (int64_t) va_arg(args, ngx_atomic_int_t);
! 349: } else {
! 350: ui64 = (uint64_t) va_arg(args, ngx_atomic_uint_t);
! 351: }
! 352:
! 353: if (max_width) {
! 354: width = NGX_ATOMIC_T_LEN;
! 355: }
! 356:
! 357: break;
! 358:
! 359: case 'f':
! 360: f = va_arg(args, double);
! 361:
! 362: if (f < 0) {
! 363: *buf++ = '-';
! 364: f = -f;
! 365: }
! 366:
! 367: ui64 = (int64_t) f;
! 368: frac = 0;
! 369:
! 370: if (frac_width) {
! 371:
! 372: scale = 1;
! 373: for (n = frac_width; n; n--) {
! 374: scale *= 10;
! 375: }
! 376:
! 377: frac = (uint64_t) ((f - (double) ui64) * scale + 0.5);
! 378:
! 379: if (frac == scale) {
! 380: ui64++;
! 381: frac = 0;
! 382: }
! 383: }
! 384:
! 385: buf = ngx_sprintf_num(buf, last, ui64, zero, 0, width);
! 386:
! 387: if (frac_width) {
! 388: if (buf < last) {
! 389: *buf++ = '.';
! 390: }
! 391:
! 392: buf = ngx_sprintf_num(buf, last, frac, '0', 0, frac_width);
! 393: }
! 394:
! 395: fmt++;
! 396:
! 397: continue;
! 398:
! 399: #if !(NGX_WIN32)
! 400: case 'r':
! 401: i64 = (int64_t) va_arg(args, rlim_t);
! 402: sign = 1;
! 403: break;
! 404: #endif
! 405:
! 406: case 'p':
! 407: ui64 = (uintptr_t) va_arg(args, void *);
! 408: hex = 2;
! 409: sign = 0;
! 410: zero = '0';
! 411: width = NGX_PTR_SIZE * 2;
! 412: break;
! 413:
! 414: case 'c':
! 415: d = va_arg(args, int);
! 416: *buf++ = (u_char) (d & 0xff);
! 417: fmt++;
! 418:
! 419: continue;
! 420:
! 421: case 'Z':
! 422: *buf++ = '\0';
! 423: fmt++;
! 424:
! 425: continue;
! 426:
! 427: case 'N':
! 428: #if (NGX_WIN32)
! 429: *buf++ = CR;
! 430: #endif
! 431: *buf++ = LF;
! 432: fmt++;
! 433:
! 434: continue;
! 435:
! 436: case '%':
! 437: *buf++ = '%';
! 438: fmt++;
! 439:
! 440: continue;
! 441:
! 442: default:
! 443: *buf++ = *fmt++;
! 444:
! 445: continue;
! 446: }
! 447:
! 448: if (sign) {
! 449: if (i64 < 0) {
! 450: *buf++ = '-';
! 451: ui64 = (uint64_t) -i64;
! 452:
! 453: } else {
! 454: ui64 = (uint64_t) i64;
! 455: }
! 456: }
! 457:
! 458: buf = ngx_sprintf_num(buf, last, ui64, zero, hex, width);
! 459:
! 460: fmt++;
! 461:
! 462: } else {
! 463: *buf++ = *fmt++;
! 464: }
! 465: }
! 466:
! 467: return buf;
! 468: }
! 469:
! 470:
! 471: static u_char *
! 472: ngx_sprintf_num(u_char *buf, u_char *last, uint64_t ui64, u_char zero,
! 473: ngx_uint_t hexadecimal, ngx_uint_t width)
! 474: {
! 475: u_char *p, temp[NGX_INT64_LEN + 1];
! 476: /*
! 477: * we need temp[NGX_INT64_LEN] only,
! 478: * but icc issues the warning
! 479: */
! 480: size_t len;
! 481: uint32_t ui32;
! 482: static u_char hex[] = "0123456789abcdef";
! 483: static u_char HEX[] = "0123456789ABCDEF";
! 484:
! 485: p = temp + NGX_INT64_LEN;
! 486:
! 487: if (hexadecimal == 0) {
! 488:
! 489: if (ui64 <= NGX_MAX_UINT32_VALUE) {
! 490:
! 491: /*
! 492: * To divide 64-bit numbers and to find remainders
! 493: * on the x86 platform gcc and icc call the libc functions
! 494: * [u]divdi3() and [u]moddi3(), they call another function
! 495: * in its turn. On FreeBSD it is the qdivrem() function,
! 496: * its source code is about 170 lines of the code.
! 497: * The glibc counterpart is about 150 lines of the code.
! 498: *
! 499: * For 32-bit numbers and some divisors gcc and icc use
! 500: * a inlined multiplication and shifts. For example,
! 501: * unsigned "i32 / 10" is compiled to
! 502: *
! 503: * (i32 * 0xCCCCCCCD) >> 35
! 504: */
! 505:
! 506: ui32 = (uint32_t) ui64;
! 507:
! 508: do {
! 509: *--p = (u_char) (ui32 % 10 + '0');
! 510: } while (ui32 /= 10);
! 511:
! 512: } else {
! 513: do {
! 514: *--p = (u_char) (ui64 % 10 + '0');
! 515: } while (ui64 /= 10);
! 516: }
! 517:
! 518: } else if (hexadecimal == 1) {
! 519:
! 520: do {
! 521:
! 522: /* the "(uint32_t)" cast disables the BCC's warning */
! 523: *--p = hex[(uint32_t) (ui64 & 0xf)];
! 524:
! 525: } while (ui64 >>= 4);
! 526:
! 527: } else { /* hexadecimal == 2 */
! 528:
! 529: do {
! 530:
! 531: /* the "(uint32_t)" cast disables the BCC's warning */
! 532: *--p = HEX[(uint32_t) (ui64 & 0xf)];
! 533:
! 534: } while (ui64 >>= 4);
! 535: }
! 536:
! 537: /* zero or space padding */
! 538:
! 539: len = (temp + NGX_INT64_LEN) - p;
! 540:
! 541: while (len++ < width && buf < last) {
! 542: *buf++ = zero;
! 543: }
! 544:
! 545: /* number safe copy */
! 546:
! 547: len = (temp + NGX_INT64_LEN) - p;
! 548:
! 549: if (buf + len > last) {
! 550: len = last - buf;
! 551: }
! 552:
! 553: return ngx_cpymem(buf, p, len);
! 554: }
! 555:
! 556:
! 557: /*
! 558: * We use ngx_strcasecmp()/ngx_strncasecmp() for 7-bit ASCII strings only,
! 559: * and implement our own ngx_strcasecmp()/ngx_strncasecmp()
! 560: * to avoid libc locale overhead. Besides, we use the ngx_uint_t's
! 561: * instead of the u_char's, because they are slightly faster.
! 562: */
! 563:
! 564: ngx_int_t
! 565: ngx_strcasecmp(u_char *s1, u_char *s2)
! 566: {
! 567: ngx_uint_t c1, c2;
! 568:
! 569: for ( ;; ) {
! 570: c1 = (ngx_uint_t) *s1++;
! 571: c2 = (ngx_uint_t) *s2++;
! 572:
! 573: c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;
! 574: c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;
! 575:
! 576: if (c1 == c2) {
! 577:
! 578: if (c1) {
! 579: continue;
! 580: }
! 581:
! 582: return 0;
! 583: }
! 584:
! 585: return c1 - c2;
! 586: }
! 587: }
! 588:
! 589:
! 590: ngx_int_t
! 591: ngx_strncasecmp(u_char *s1, u_char *s2, size_t n)
! 592: {
! 593: ngx_uint_t c1, c2;
! 594:
! 595: while (n) {
! 596: c1 = (ngx_uint_t) *s1++;
! 597: c2 = (ngx_uint_t) *s2++;
! 598:
! 599: c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;
! 600: c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;
! 601:
! 602: if (c1 == c2) {
! 603:
! 604: if (c1) {
! 605: n--;
! 606: continue;
! 607: }
! 608:
! 609: return 0;
! 610: }
! 611:
! 612: return c1 - c2;
! 613: }
! 614:
! 615: return 0;
! 616: }
! 617:
! 618:
! 619: u_char *
! 620: ngx_strnstr(u_char *s1, char *s2, size_t len)
! 621: {
! 622: u_char c1, c2;
! 623: size_t n;
! 624:
! 625: c2 = *(u_char *) s2++;
! 626:
! 627: n = ngx_strlen(s2);
! 628:
! 629: do {
! 630: do {
! 631: if (len-- == 0) {
! 632: return NULL;
! 633: }
! 634:
! 635: c1 = *s1++;
! 636:
! 637: if (c1 == 0) {
! 638: return NULL;
! 639: }
! 640:
! 641: } while (c1 != c2);
! 642:
! 643: if (n > len) {
! 644: return NULL;
! 645: }
! 646:
! 647: } while (ngx_strncmp(s1, (u_char *) s2, n) != 0);
! 648:
! 649: return --s1;
! 650: }
! 651:
! 652:
! 653: /*
! 654: * ngx_strstrn() and ngx_strcasestrn() are intended to search for static
! 655: * substring with known length in null-terminated string. The argument n
! 656: * must be length of the second substring - 1.
! 657: */
! 658:
! 659: u_char *
! 660: ngx_strstrn(u_char *s1, char *s2, size_t n)
! 661: {
! 662: u_char c1, c2;
! 663:
! 664: c2 = *(u_char *) s2++;
! 665:
! 666: do {
! 667: do {
! 668: c1 = *s1++;
! 669:
! 670: if (c1 == 0) {
! 671: return NULL;
! 672: }
! 673:
! 674: } while (c1 != c2);
! 675:
! 676: } while (ngx_strncmp(s1, (u_char *) s2, n) != 0);
! 677:
! 678: return --s1;
! 679: }
! 680:
! 681:
! 682: u_char *
! 683: ngx_strcasestrn(u_char *s1, char *s2, size_t n)
! 684: {
! 685: ngx_uint_t c1, c2;
! 686:
! 687: c2 = (ngx_uint_t) *s2++;
! 688: c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;
! 689:
! 690: do {
! 691: do {
! 692: c1 = (ngx_uint_t) *s1++;
! 693:
! 694: if (c1 == 0) {
! 695: return NULL;
! 696: }
! 697:
! 698: c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;
! 699:
! 700: } while (c1 != c2);
! 701:
! 702: } while (ngx_strncasecmp(s1, (u_char *) s2, n) != 0);
! 703:
! 704: return --s1;
! 705: }
! 706:
! 707:
! 708: /*
! 709: * ngx_strlcasestrn() is intended to search for static substring
! 710: * with known length in string until the argument last. The argument n
! 711: * must be length of the second substring - 1.
! 712: */
! 713:
! 714: u_char *
! 715: ngx_strlcasestrn(u_char *s1, u_char *last, u_char *s2, size_t n)
! 716: {
! 717: ngx_uint_t c1, c2;
! 718:
! 719: c2 = (ngx_uint_t) *s2++;
! 720: c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;
! 721: last -= n;
! 722:
! 723: do {
! 724: do {
! 725: if (s1 >= last) {
! 726: return NULL;
! 727: }
! 728:
! 729: c1 = (ngx_uint_t) *s1++;
! 730:
! 731: c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;
! 732:
! 733: } while (c1 != c2);
! 734:
! 735: } while (ngx_strncasecmp(s1, s2, n) != 0);
! 736:
! 737: return --s1;
! 738: }
! 739:
! 740:
! 741: ngx_int_t
! 742: ngx_rstrncmp(u_char *s1, u_char *s2, size_t n)
! 743: {
! 744: if (n == 0) {
! 745: return 0;
! 746: }
! 747:
! 748: n--;
! 749:
! 750: for ( ;; ) {
! 751: if (s1[n] != s2[n]) {
! 752: return s1[n] - s2[n];
! 753: }
! 754:
! 755: if (n == 0) {
! 756: return 0;
! 757: }
! 758:
! 759: n--;
! 760: }
! 761: }
! 762:
! 763:
! 764: ngx_int_t
! 765: ngx_rstrncasecmp(u_char *s1, u_char *s2, size_t n)
! 766: {
! 767: u_char c1, c2;
! 768:
! 769: if (n == 0) {
! 770: return 0;
! 771: }
! 772:
! 773: n--;
! 774:
! 775: for ( ;; ) {
! 776: c1 = s1[n];
! 777: if (c1 >= 'a' && c1 <= 'z') {
! 778: c1 -= 'a' - 'A';
! 779: }
! 780:
! 781: c2 = s2[n];
! 782: if (c2 >= 'a' && c2 <= 'z') {
! 783: c2 -= 'a' - 'A';
! 784: }
! 785:
! 786: if (c1 != c2) {
! 787: return c1 - c2;
! 788: }
! 789:
! 790: if (n == 0) {
! 791: return 0;
! 792: }
! 793:
! 794: n--;
! 795: }
! 796: }
! 797:
! 798:
! 799: ngx_int_t
! 800: ngx_memn2cmp(u_char *s1, u_char *s2, size_t n1, size_t n2)
! 801: {
! 802: size_t n;
! 803: ngx_int_t m, z;
! 804:
! 805: if (n1 <= n2) {
! 806: n = n1;
! 807: z = -1;
! 808:
! 809: } else {
! 810: n = n2;
! 811: z = 1;
! 812: }
! 813:
! 814: m = ngx_memcmp(s1, s2, n);
! 815:
! 816: if (m || n1 == n2) {
! 817: return m;
! 818: }
! 819:
! 820: return z;
! 821: }
! 822:
! 823:
! 824: ngx_int_t
! 825: ngx_dns_strcmp(u_char *s1, u_char *s2)
! 826: {
! 827: ngx_uint_t c1, c2;
! 828:
! 829: for ( ;; ) {
! 830: c1 = (ngx_uint_t) *s1++;
! 831: c2 = (ngx_uint_t) *s2++;
! 832:
! 833: c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;
! 834: c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;
! 835:
! 836: if (c1 == c2) {
! 837:
! 838: if (c1) {
! 839: continue;
! 840: }
! 841:
! 842: return 0;
! 843: }
! 844:
! 845: /* in ASCII '.' > '-', but we need '.' to be the lowest character */
! 846:
! 847: c1 = (c1 == '.') ? ' ' : c1;
! 848: c2 = (c2 == '.') ? ' ' : c2;
! 849:
! 850: return c1 - c2;
! 851: }
! 852: }
! 853:
! 854:
! 855: ngx_int_t
! 856: ngx_atoi(u_char *line, size_t n)
! 857: {
! 858: ngx_int_t value;
! 859:
! 860: if (n == 0) {
! 861: return NGX_ERROR;
! 862: }
! 863:
! 864: for (value = 0; n--; line++) {
! 865: if (*line < '0' || *line > '9') {
! 866: return NGX_ERROR;
! 867: }
! 868:
! 869: value = value * 10 + (*line - '0');
! 870: }
! 871:
! 872: if (value < 0) {
! 873: return NGX_ERROR;
! 874:
! 875: } else {
! 876: return value;
! 877: }
! 878: }
! 879:
! 880:
! 881: /* parse a fixed point number, e.g., ngx_atofp("10.5", 4, 2) returns 1050 */
! 882:
! 883: ngx_int_t
! 884: ngx_atofp(u_char *line, size_t n, size_t point)
! 885: {
! 886: ngx_int_t value;
! 887: ngx_uint_t dot;
! 888:
! 889: if (n == 0) {
! 890: return NGX_ERROR;
! 891: }
! 892:
! 893: dot = 0;
! 894:
! 895: for (value = 0; n--; line++) {
! 896:
! 897: if (point == 0) {
! 898: return NGX_ERROR;
! 899: }
! 900:
! 901: if (*line == '.') {
! 902: if (dot) {
! 903: return NGX_ERROR;
! 904: }
! 905:
! 906: dot = 1;
! 907: continue;
! 908: }
! 909:
! 910: if (*line < '0' || *line > '9') {
! 911: return NGX_ERROR;
! 912: }
! 913:
! 914: value = value * 10 + (*line - '0');
! 915: point -= dot;
! 916: }
! 917:
! 918: while (point--) {
! 919: value = value * 10;
! 920: }
! 921:
! 922: if (value < 0) {
! 923: return NGX_ERROR;
! 924:
! 925: } else {
! 926: return value;
! 927: }
! 928: }
! 929:
! 930:
! 931: ssize_t
! 932: ngx_atosz(u_char *line, size_t n)
! 933: {
! 934: ssize_t value;
! 935:
! 936: if (n == 0) {
! 937: return NGX_ERROR;
! 938: }
! 939:
! 940: for (value = 0; n--; line++) {
! 941: if (*line < '0' || *line > '9') {
! 942: return NGX_ERROR;
! 943: }
! 944:
! 945: value = value * 10 + (*line - '0');
! 946: }
! 947:
! 948: if (value < 0) {
! 949: return NGX_ERROR;
! 950:
! 951: } else {
! 952: return value;
! 953: }
! 954: }
! 955:
! 956:
! 957: off_t
! 958: ngx_atoof(u_char *line, size_t n)
! 959: {
! 960: off_t value;
! 961:
! 962: if (n == 0) {
! 963: return NGX_ERROR;
! 964: }
! 965:
! 966: for (value = 0; n--; line++) {
! 967: if (*line < '0' || *line > '9') {
! 968: return NGX_ERROR;
! 969: }
! 970:
! 971: value = value * 10 + (*line - '0');
! 972: }
! 973:
! 974: if (value < 0) {
! 975: return NGX_ERROR;
! 976:
! 977: } else {
! 978: return value;
! 979: }
! 980: }
! 981:
! 982:
! 983: time_t
! 984: ngx_atotm(u_char *line, size_t n)
! 985: {
! 986: time_t value;
! 987:
! 988: if (n == 0) {
! 989: return NGX_ERROR;
! 990: }
! 991:
! 992: for (value = 0; n--; line++) {
! 993: if (*line < '0' || *line > '9') {
! 994: return NGX_ERROR;
! 995: }
! 996:
! 997: value = value * 10 + (*line - '0');
! 998: }
! 999:
! 1000: if (value < 0) {
! 1001: return NGX_ERROR;
! 1002:
! 1003: } else {
! 1004: return value;
! 1005: }
! 1006: }
! 1007:
! 1008:
! 1009: ngx_int_t
! 1010: ngx_hextoi(u_char *line, size_t n)
! 1011: {
! 1012: u_char c, ch;
! 1013: ngx_int_t value;
! 1014:
! 1015: if (n == 0) {
! 1016: return NGX_ERROR;
! 1017: }
! 1018:
! 1019: for (value = 0; n--; line++) {
! 1020: ch = *line;
! 1021:
! 1022: if (ch >= '0' && ch <= '9') {
! 1023: value = value * 16 + (ch - '0');
! 1024: continue;
! 1025: }
! 1026:
! 1027: c = (u_char) (ch | 0x20);
! 1028:
! 1029: if (c >= 'a' && c <= 'f') {
! 1030: value = value * 16 + (c - 'a' + 10);
! 1031: continue;
! 1032: }
! 1033:
! 1034: return NGX_ERROR;
! 1035: }
! 1036:
! 1037: if (value < 0) {
! 1038: return NGX_ERROR;
! 1039:
! 1040: } else {
! 1041: return value;
! 1042: }
! 1043: }
! 1044:
! 1045:
! 1046: u_char *
! 1047: ngx_hex_dump(u_char *dst, u_char *src, size_t len)
! 1048: {
! 1049: static u_char hex[] = "0123456789abcdef";
! 1050:
! 1051: while (len--) {
! 1052: *dst++ = hex[*src >> 4];
! 1053: *dst++ = hex[*src++ & 0xf];
! 1054: }
! 1055:
! 1056: return dst;
! 1057: }
! 1058:
! 1059:
! 1060: void
! 1061: ngx_encode_base64(ngx_str_t *dst, ngx_str_t *src)
! 1062: {
! 1063: u_char *d, *s;
! 1064: size_t len;
! 1065: static u_char basis64[] =
! 1066: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
! 1067:
! 1068: len = src->len;
! 1069: s = src->data;
! 1070: d = dst->data;
! 1071:
! 1072: while (len > 2) {
! 1073: *d++ = basis64[(s[0] >> 2) & 0x3f];
! 1074: *d++ = basis64[((s[0] & 3) << 4) | (s[1] >> 4)];
! 1075: *d++ = basis64[((s[1] & 0x0f) << 2) | (s[2] >> 6)];
! 1076: *d++ = basis64[s[2] & 0x3f];
! 1077:
! 1078: s += 3;
! 1079: len -= 3;
! 1080: }
! 1081:
! 1082: if (len) {
! 1083: *d++ = basis64[(s[0] >> 2) & 0x3f];
! 1084:
! 1085: if (len == 1) {
! 1086: *d++ = basis64[(s[0] & 3) << 4];
! 1087: *d++ = '=';
! 1088:
! 1089: } else {
! 1090: *d++ = basis64[((s[0] & 3) << 4) | (s[1] >> 4)];
! 1091: *d++ = basis64[(s[1] & 0x0f) << 2];
! 1092: }
! 1093:
! 1094: *d++ = '=';
! 1095: }
! 1096:
! 1097: dst->len = d - dst->data;
! 1098: }
! 1099:
! 1100:
! 1101: ngx_int_t
! 1102: ngx_decode_base64(ngx_str_t *dst, ngx_str_t *src)
! 1103: {
! 1104: static u_char basis64[] = {
! 1105: 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
! 1106: 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
! 1107: 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 62, 77, 77, 77, 63,
! 1108: 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 77, 77, 77, 77, 77, 77,
! 1109: 77, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
! 1110: 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 77, 77, 77, 77, 77,
! 1111: 77, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
! 1112: 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 77, 77, 77, 77, 77,
! 1113:
! 1114: 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
! 1115: 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
! 1116: 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
! 1117: 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
! 1118: 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
! 1119: 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
! 1120: 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
! 1121: 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77
! 1122: };
! 1123:
! 1124: return ngx_decode_base64_internal(dst, src, basis64);
! 1125: }
! 1126:
! 1127:
! 1128: ngx_int_t
! 1129: ngx_decode_base64url(ngx_str_t *dst, ngx_str_t *src)
! 1130: {
! 1131: static u_char basis64[] = {
! 1132: 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
! 1133: 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
! 1134: 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 62, 77, 77,
! 1135: 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 77, 77, 77, 77, 77, 77,
! 1136: 77, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
! 1137: 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 77, 77, 77, 77, 63,
! 1138: 77, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
! 1139: 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 77, 77, 77, 77, 77,
! 1140:
! 1141: 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
! 1142: 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
! 1143: 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
! 1144: 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
! 1145: 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
! 1146: 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
! 1147: 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
! 1148: 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77
! 1149: };
! 1150:
! 1151: return ngx_decode_base64_internal(dst, src, basis64);
! 1152: }
! 1153:
! 1154:
! 1155: static ngx_int_t
! 1156: ngx_decode_base64_internal(ngx_str_t *dst, ngx_str_t *src, const u_char *basis)
! 1157: {
! 1158: size_t len;
! 1159: u_char *d, *s;
! 1160:
! 1161: for (len = 0; len < src->len; len++) {
! 1162: if (src->data[len] == '=') {
! 1163: break;
! 1164: }
! 1165:
! 1166: if (basis[src->data[len]] == 77) {
! 1167: return NGX_ERROR;
! 1168: }
! 1169: }
! 1170:
! 1171: if (len % 4 == 1) {
! 1172: return NGX_ERROR;
! 1173: }
! 1174:
! 1175: s = src->data;
! 1176: d = dst->data;
! 1177:
! 1178: while (len > 3) {
! 1179: *d++ = (u_char) (basis[s[0]] << 2 | basis[s[1]] >> 4);
! 1180: *d++ = (u_char) (basis[s[1]] << 4 | basis[s[2]] >> 2);
! 1181: *d++ = (u_char) (basis[s[2]] << 6 | basis[s[3]]);
! 1182:
! 1183: s += 4;
! 1184: len -= 4;
! 1185: }
! 1186:
! 1187: if (len > 1) {
! 1188: *d++ = (u_char) (basis[s[0]] << 2 | basis[s[1]] >> 4);
! 1189: }
! 1190:
! 1191: if (len > 2) {
! 1192: *d++ = (u_char) (basis[s[1]] << 4 | basis[s[2]] >> 2);
! 1193: }
! 1194:
! 1195: dst->len = d - dst->data;
! 1196:
! 1197: return NGX_OK;
! 1198: }
! 1199:
! 1200:
! 1201: /*
! 1202: * ngx_utf8_decode() decodes two and more bytes UTF sequences only
! 1203: * the return values:
! 1204: * 0x80 - 0x10ffff valid character
! 1205: * 0x110000 - 0xfffffffd invalid sequence
! 1206: * 0xfffffffe incomplete sequence
! 1207: * 0xffffffff error
! 1208: */
! 1209:
! 1210: uint32_t
! 1211: ngx_utf8_decode(u_char **p, size_t n)
! 1212: {
! 1213: size_t len;
! 1214: uint32_t u, i, valid;
! 1215:
! 1216: u = **p;
! 1217:
! 1218: if (u >= 0xf0) {
! 1219:
! 1220: u &= 0x07;
! 1221: valid = 0xffff;
! 1222: len = 3;
! 1223:
! 1224: } else if (u >= 0xe0) {
! 1225:
! 1226: u &= 0x0f;
! 1227: valid = 0x7ff;
! 1228: len = 2;
! 1229:
! 1230: } else if (u >= 0xc2) {
! 1231:
! 1232: u &= 0x1f;
! 1233: valid = 0x7f;
! 1234: len = 1;
! 1235:
! 1236: } else {
! 1237: (*p)++;
! 1238: return 0xffffffff;
! 1239: }
! 1240:
! 1241: if (n - 1 < len) {
! 1242: return 0xfffffffe;
! 1243: }
! 1244:
! 1245: (*p)++;
! 1246:
! 1247: while (len) {
! 1248: i = *(*p)++;
! 1249:
! 1250: if (i < 0x80) {
! 1251: return 0xffffffff;
! 1252: }
! 1253:
! 1254: u = (u << 6) | (i & 0x3f);
! 1255:
! 1256: len--;
! 1257: }
! 1258:
! 1259: if (u > valid) {
! 1260: return u;
! 1261: }
! 1262:
! 1263: return 0xffffffff;
! 1264: }
! 1265:
! 1266:
! 1267: size_t
! 1268: ngx_utf8_length(u_char *p, size_t n)
! 1269: {
! 1270: u_char c, *last;
! 1271: size_t len;
! 1272:
! 1273: last = p + n;
! 1274:
! 1275: for (len = 0; p < last; len++) {
! 1276:
! 1277: c = *p;
! 1278:
! 1279: if (c < 0x80) {
! 1280: p++;
! 1281: continue;
! 1282: }
! 1283:
! 1284: if (ngx_utf8_decode(&p, n) > 0x10ffff) {
! 1285: /* invalid UTF-8 */
! 1286: return n;
! 1287: }
! 1288: }
! 1289:
! 1290: return len;
! 1291: }
! 1292:
! 1293:
! 1294: u_char *
! 1295: ngx_utf8_cpystrn(u_char *dst, u_char *src, size_t n, size_t len)
! 1296: {
! 1297: u_char c, *next;
! 1298:
! 1299: if (n == 0) {
! 1300: return dst;
! 1301: }
! 1302:
! 1303: while (--n) {
! 1304:
! 1305: c = *src;
! 1306: *dst = c;
! 1307:
! 1308: if (c < 0x80) {
! 1309:
! 1310: if (c != '\0') {
! 1311: dst++;
! 1312: src++;
! 1313: len--;
! 1314:
! 1315: continue;
! 1316: }
! 1317:
! 1318: return dst;
! 1319: }
! 1320:
! 1321: next = src;
! 1322:
! 1323: if (ngx_utf8_decode(&next, len) > 0x10ffff) {
! 1324: /* invalid UTF-8 */
! 1325: break;
! 1326: }
! 1327:
! 1328: while (src < next) {
! 1329: *dst++ = *src++;
! 1330: len--;
! 1331: }
! 1332: }
! 1333:
! 1334: *dst = '\0';
! 1335:
! 1336: return dst;
! 1337: }
! 1338:
! 1339:
! 1340: uintptr_t
! 1341: ngx_escape_uri(u_char *dst, u_char *src, size_t size, ngx_uint_t type)
! 1342: {
! 1343: ngx_uint_t n;
! 1344: uint32_t *escape;
! 1345: static u_char hex[] = "0123456789abcdef";
! 1346:
! 1347: /* " ", "#", "%", "?", %00-%1F, %7F-%FF */
! 1348:
! 1349: static uint32_t uri[] = {
! 1350: 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
! 1351:
! 1352: /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
! 1353: 0x80000029, /* 1000 0000 0000 0000 0000 0000 0010 1001 */
! 1354:
! 1355: /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
! 1356: 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
! 1357:
! 1358: /* ~}| {zyx wvut srqp onml kjih gfed cba` */
! 1359: 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */
! 1360:
! 1361: 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
! 1362: 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
! 1363: 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
! 1364: 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */
! 1365: };
! 1366:
! 1367: /* " ", "#", "%", "&", "+", "?", %00-%1F, %7F-%FF */
! 1368:
! 1369: static uint32_t args[] = {
! 1370: 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
! 1371:
! 1372: /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
! 1373: 0x88000869, /* 1000 1000 0000 0000 0000 1000 0110 1001 */
! 1374:
! 1375: /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
! 1376: 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
! 1377:
! 1378: /* ~}| {zyx wvut srqp onml kjih gfed cba` */
! 1379: 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */
! 1380:
! 1381: 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
! 1382: 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
! 1383: 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
! 1384: 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */
! 1385: };
! 1386:
! 1387: /* not ALPHA, DIGIT, "-", ".", "_", "~" */
! 1388:
! 1389: static uint32_t uri_component[] = {
! 1390: 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
! 1391:
! 1392: /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
! 1393: 0xfc009fff, /* 1111 1100 0000 0000 1001 1111 1111 1111 */
! 1394:
! 1395: /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
! 1396: 0x78000001, /* 0111 1000 0000 0000 0000 0000 0000 0001 */
! 1397:
! 1398: /* ~}| {zyx wvut srqp onml kjih gfed cba` */
! 1399: 0xb8000001, /* 1011 1000 0000 0000 0000 0000 0000 0001 */
! 1400:
! 1401: 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
! 1402: 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
! 1403: 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
! 1404: 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */
! 1405: };
! 1406:
! 1407: /* " ", "#", """, "%", "'", %00-%1F, %7F-%FF */
! 1408:
! 1409: static uint32_t html[] = {
! 1410: 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
! 1411:
! 1412: /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
! 1413: 0x000000ad, /* 0000 0000 0000 0000 0000 0000 1010 1101 */
! 1414:
! 1415: /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
! 1416: 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
! 1417:
! 1418: /* ~}| {zyx wvut srqp onml kjih gfed cba` */
! 1419: 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */
! 1420:
! 1421: 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
! 1422: 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
! 1423: 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
! 1424: 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */
! 1425: };
! 1426:
! 1427: /* " ", """, "%", "'", %00-%1F, %7F-%FF */
! 1428:
! 1429: static uint32_t refresh[] = {
! 1430: 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
! 1431:
! 1432: /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
! 1433: 0x00000085, /* 0000 0000 0000 0000 0000 0000 1000 0101 */
! 1434:
! 1435: /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
! 1436: 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
! 1437:
! 1438: /* ~}| {zyx wvut srqp onml kjih gfed cba` */
! 1439: 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */
! 1440:
! 1441: 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
! 1442: 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
! 1443: 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
! 1444: 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */
! 1445: };
! 1446:
! 1447: /* " ", "%", %00-%1F */
! 1448:
! 1449: static uint32_t memcached[] = {
! 1450: 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
! 1451:
! 1452: /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
! 1453: 0x00000021, /* 0000 0000 0000 0000 0000 0000 0010 0001 */
! 1454:
! 1455: /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
! 1456: 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
! 1457:
! 1458: /* ~}| {zyx wvut srqp onml kjih gfed cba` */
! 1459: 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
! 1460:
! 1461: 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
! 1462: 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
! 1463: 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
! 1464: 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
! 1465: };
! 1466:
! 1467: /* mail_auth is the same as memcached */
! 1468:
! 1469: static uint32_t *map[] =
! 1470: { uri, args, uri_component, html, refresh, memcached, memcached };
! 1471:
! 1472:
! 1473: escape = map[type];
! 1474:
! 1475: if (dst == NULL) {
! 1476:
! 1477: /* find the number of the characters to be escaped */
! 1478:
! 1479: n = 0;
! 1480:
! 1481: while (size) {
! 1482: if (escape[*src >> 5] & (1 << (*src & 0x1f))) {
! 1483: n++;
! 1484: }
! 1485: src++;
! 1486: size--;
! 1487: }
! 1488:
! 1489: return (uintptr_t) n;
! 1490: }
! 1491:
! 1492: while (size) {
! 1493: if (escape[*src >> 5] & (1 << (*src & 0x1f))) {
! 1494: *dst++ = '%';
! 1495: *dst++ = hex[*src >> 4];
! 1496: *dst++ = hex[*src & 0xf];
! 1497: src++;
! 1498:
! 1499: } else {
! 1500: *dst++ = *src++;
! 1501: }
! 1502: size--;
! 1503: }
! 1504:
! 1505: return (uintptr_t) dst;
! 1506: }
! 1507:
! 1508:
! 1509: void
! 1510: ngx_unescape_uri(u_char **dst, u_char **src, size_t size, ngx_uint_t type)
! 1511: {
! 1512: u_char *d, *s, ch, c, decoded;
! 1513: enum {
! 1514: sw_usual = 0,
! 1515: sw_quoted,
! 1516: sw_quoted_second
! 1517: } state;
! 1518:
! 1519: d = *dst;
! 1520: s = *src;
! 1521:
! 1522: state = 0;
! 1523: decoded = 0;
! 1524:
! 1525: while (size--) {
! 1526:
! 1527: ch = *s++;
! 1528:
! 1529: switch (state) {
! 1530: case sw_usual:
! 1531: if (ch == '?'
! 1532: && (type & (NGX_UNESCAPE_URI|NGX_UNESCAPE_REDIRECT)))
! 1533: {
! 1534: *d++ = ch;
! 1535: goto done;
! 1536: }
! 1537:
! 1538: if (ch == '%') {
! 1539: state = sw_quoted;
! 1540: break;
! 1541: }
! 1542:
! 1543: *d++ = ch;
! 1544: break;
! 1545:
! 1546: case sw_quoted:
! 1547:
! 1548: if (ch >= '0' && ch <= '9') {
! 1549: decoded = (u_char) (ch - '0');
! 1550: state = sw_quoted_second;
! 1551: break;
! 1552: }
! 1553:
! 1554: c = (u_char) (ch | 0x20);
! 1555: if (c >= 'a' && c <= 'f') {
! 1556: decoded = (u_char) (c - 'a' + 10);
! 1557: state = sw_quoted_second;
! 1558: break;
! 1559: }
! 1560:
! 1561: /* the invalid quoted character */
! 1562:
! 1563: state = sw_usual;
! 1564:
! 1565: *d++ = ch;
! 1566:
! 1567: break;
! 1568:
! 1569: case sw_quoted_second:
! 1570:
! 1571: state = sw_usual;
! 1572:
! 1573: if (ch >= '0' && ch <= '9') {
! 1574: ch = (u_char) ((decoded << 4) + ch - '0');
! 1575:
! 1576: if (type & NGX_UNESCAPE_REDIRECT) {
! 1577: if (ch > '%' && ch < 0x7f) {
! 1578: *d++ = ch;
! 1579: break;
! 1580: }
! 1581:
! 1582: *d++ = '%'; *d++ = *(s - 2); *d++ = *(s - 1);
! 1583:
! 1584: break;
! 1585: }
! 1586:
! 1587: *d++ = ch;
! 1588:
! 1589: break;
! 1590: }
! 1591:
! 1592: c = (u_char) (ch | 0x20);
! 1593: if (c >= 'a' && c <= 'f') {
! 1594: ch = (u_char) ((decoded << 4) + c - 'a' + 10);
! 1595:
! 1596: if (type & NGX_UNESCAPE_URI) {
! 1597: if (ch == '?') {
! 1598: *d++ = ch;
! 1599: goto done;
! 1600: }
! 1601:
! 1602: *d++ = ch;
! 1603: break;
! 1604: }
! 1605:
! 1606: if (type & NGX_UNESCAPE_REDIRECT) {
! 1607: if (ch == '?') {
! 1608: *d++ = ch;
! 1609: goto done;
! 1610: }
! 1611:
! 1612: if (ch > '%' && ch < 0x7f) {
! 1613: *d++ = ch;
! 1614: break;
! 1615: }
! 1616:
! 1617: *d++ = '%'; *d++ = *(s - 2); *d++ = *(s - 1);
! 1618: break;
! 1619: }
! 1620:
! 1621: *d++ = ch;
! 1622:
! 1623: break;
! 1624: }
! 1625:
! 1626: /* the invalid quoted character */
! 1627:
! 1628: break;
! 1629: }
! 1630: }
! 1631:
! 1632: done:
! 1633:
! 1634: *dst = d;
! 1635: *src = s;
! 1636: }
! 1637:
! 1638:
! 1639: uintptr_t
! 1640: ngx_escape_html(u_char *dst, u_char *src, size_t size)
! 1641: {
! 1642: u_char ch;
! 1643: ngx_uint_t len;
! 1644:
! 1645: if (dst == NULL) {
! 1646:
! 1647: len = 0;
! 1648:
! 1649: while (size) {
! 1650: switch (*src++) {
! 1651:
! 1652: case '<':
! 1653: len += sizeof("<") - 2;
! 1654: break;
! 1655:
! 1656: case '>':
! 1657: len += sizeof(">") - 2;
! 1658: break;
! 1659:
! 1660: case '&':
! 1661: len += sizeof("&") - 2;
! 1662: break;
! 1663:
! 1664: case '"':
! 1665: len += sizeof(""") - 2;
! 1666: break;
! 1667:
! 1668: default:
! 1669: break;
! 1670: }
! 1671: size--;
! 1672: }
! 1673:
! 1674: return (uintptr_t) len;
! 1675: }
! 1676:
! 1677: while (size) {
! 1678: ch = *src++;
! 1679:
! 1680: switch (ch) {
! 1681:
! 1682: case '<':
! 1683: *dst++ = '&'; *dst++ = 'l'; *dst++ = 't'; *dst++ = ';';
! 1684: break;
! 1685:
! 1686: case '>':
! 1687: *dst++ = '&'; *dst++ = 'g'; *dst++ = 't'; *dst++ = ';';
! 1688: break;
! 1689:
! 1690: case '&':
! 1691: *dst++ = '&'; *dst++ = 'a'; *dst++ = 'm'; *dst++ = 'p';
! 1692: *dst++ = ';';
! 1693: break;
! 1694:
! 1695: case '"':
! 1696: *dst++ = '&'; *dst++ = 'q'; *dst++ = 'u'; *dst++ = 'o';
! 1697: *dst++ = 't'; *dst++ = ';';
! 1698: break;
! 1699:
! 1700: default:
! 1701: *dst++ = ch;
! 1702: break;
! 1703: }
! 1704: size--;
! 1705: }
! 1706:
! 1707: return (uintptr_t) dst;
! 1708: }
! 1709:
! 1710:
! 1711: void
! 1712: ngx_str_rbtree_insert_value(ngx_rbtree_node_t *temp,
! 1713: ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
! 1714: {
! 1715: ngx_str_node_t *n, *t;
! 1716: ngx_rbtree_node_t **p;
! 1717:
! 1718: for ( ;; ) {
! 1719:
! 1720: n = (ngx_str_node_t *) node;
! 1721: t = (ngx_str_node_t *) temp;
! 1722:
! 1723: if (node->key != temp->key) {
! 1724:
! 1725: p = (node->key < temp->key) ? &temp->left : &temp->right;
! 1726:
! 1727: } else if (n->str.len != t->str.len) {
! 1728:
! 1729: p = (n->str.len < t->str.len) ? &temp->left : &temp->right;
! 1730:
! 1731: } else {
! 1732: p = (ngx_memcmp(n->str.data, t->str.data, n->str.len) < 0)
! 1733: ? &temp->left : &temp->right;
! 1734: }
! 1735:
! 1736: if (*p == sentinel) {
! 1737: break;
! 1738: }
! 1739:
! 1740: temp = *p;
! 1741: }
! 1742:
! 1743: *p = node;
! 1744: node->parent = temp;
! 1745: node->left = sentinel;
! 1746: node->right = sentinel;
! 1747: ngx_rbt_red(node);
! 1748: }
! 1749:
! 1750:
! 1751: ngx_str_node_t *
! 1752: ngx_str_rbtree_lookup(ngx_rbtree_t *rbtree, ngx_str_t *val, uint32_t hash)
! 1753: {
! 1754: ngx_int_t rc;
! 1755: ngx_str_node_t *n;
! 1756: ngx_rbtree_node_t *node, *sentinel;
! 1757:
! 1758: node = rbtree->root;
! 1759: sentinel = rbtree->sentinel;
! 1760:
! 1761: while (node != sentinel) {
! 1762:
! 1763: n = (ngx_str_node_t *) node;
! 1764:
! 1765: if (hash != node->key) {
! 1766: node = (hash < node->key) ? node->left : node->right;
! 1767: continue;
! 1768: }
! 1769:
! 1770: if (val->len != n->str.len) {
! 1771: node = (val->len < n->str.len) ? node->left : node->right;
! 1772: continue;
! 1773: }
! 1774:
! 1775: rc = ngx_memcmp(val->data, n->str.data, val->len);
! 1776:
! 1777: if (rc < 0) {
! 1778: node = node->left;
! 1779: continue;
! 1780: }
! 1781:
! 1782: if (rc > 0) {
! 1783: node = node->right;
! 1784: continue;
! 1785: }
! 1786:
! 1787: return n;
! 1788: }
! 1789:
! 1790: return NULL;
! 1791: }
! 1792:
! 1793:
! 1794: /* ngx_sort() is implemented as insertion sort because we need stable sort */
! 1795:
! 1796: void
! 1797: ngx_sort(void *base, size_t n, size_t size,
! 1798: ngx_int_t (*cmp)(const void *, const void *))
! 1799: {
! 1800: u_char *p1, *p2, *p;
! 1801:
! 1802: p = ngx_alloc(size, ngx_cycle->log);
! 1803: if (p == NULL) {
! 1804: return;
! 1805: }
! 1806:
! 1807: for (p1 = (u_char *) base + size;
! 1808: p1 < (u_char *) base + n * size;
! 1809: p1 += size)
! 1810: {
! 1811: ngx_memcpy(p, p1, size);
! 1812:
! 1813: for (p2 = p1;
! 1814: p2 > (u_char *) base && cmp(p2 - size, p) > 0;
! 1815: p2 -= size)
! 1816: {
! 1817: ngx_memcpy(p2, p2 - size, size);
! 1818: }
! 1819:
! 1820: ngx_memcpy(p2, p, size);
! 1821: }
! 1822:
! 1823: ngx_free(p);
! 1824: }
! 1825:
! 1826:
! 1827: #if (NGX_MEMCPY_LIMIT)
! 1828:
! 1829: void *
! 1830: ngx_memcpy(void *dst, const void *src, size_t n)
! 1831: {
! 1832: if (n > NGX_MEMCPY_LIMIT) {
! 1833: ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "memcpy %uz bytes", n);
! 1834: ngx_debug_point();
! 1835: }
! 1836:
! 1837: return memcpy(dst, src, n);
! 1838: }
! 1839:
! 1840: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>