Update and clean Tomato RAF files
[tomato.git] / release / src / router / nginx / src / core / ngx_string.c
blob3b392f7b27d1c66cd4b2ebe141112a8f5ccf55e9
2 /*
3 * Copyright (C) Igor Sysoev
4 * Copyright (C) Nginx, Inc.
5 */
8 #include <ngx_config.h>
9 #include <ngx_core.h>
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);
18 void
19 ngx_strlow(u_char *dst, u_char *src, size_t n)
21 while (n) {
22 *dst = ngx_tolower(*src);
23 dst++;
24 src++;
25 n--;
30 u_char *
31 ngx_cpystrn(u_char *dst, u_char *src, size_t n)
33 if (n == 0) {
34 return dst;
37 while (--n) {
38 *dst = *src;
40 if (*dst == '\0') {
41 return dst;
44 dst++;
45 src++;
48 *dst = '\0';
50 return dst;
54 u_char *
55 ngx_pstrdup(ngx_pool_t *pool, ngx_str_t *src)
57 u_char *dst;
59 dst = ngx_pnalloc(pool, src->len);
60 if (dst == NULL) {
61 return NULL;
64 ngx_memcpy(dst, src->data, src->len);
66 return dst;
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 * %% %
95 * reserved:
96 * %t ptrdiff_t
97 * %S null-terminated wchar string
98 * %C wchar
102 u_char * ngx_cdecl
103 ngx_sprintf(u_char *buf, const char *fmt, ...)
105 u_char *p;
106 va_list args;
108 va_start(args, fmt);
109 p = ngx_vslprintf(buf, (void *) -1, fmt, args);
110 va_end(args);
112 return p;
116 u_char * ngx_cdecl
117 ngx_snprintf(u_char *buf, size_t max, const char *fmt, ...)
119 u_char *p;
120 va_list args;
122 va_start(args, fmt);
123 p = ngx_vslprintf(buf, buf + max, fmt, args);
124 va_end(args);
126 return p;
130 u_char * ngx_cdecl
131 ngx_slprintf(u_char *buf, u_char *last, const char *fmt, ...)
133 u_char *p;
134 va_list args;
136 va_start(args, fmt);
137 p = ngx_vslprintf(buf, last, fmt, args);
138 va_end(args);
140 return p;
144 u_char *
145 ngx_vslprintf(u_char *buf, u_char *last, const char *fmt, va_list args)
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;
158 while (*fmt && buf < last) {
161 * "buf < last" means that we could copy at least one character:
162 * the plain character, "%%", "%c", and minus without the checking
165 if (*fmt == '%') {
167 i64 = 0;
168 ui64 = 0;
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;
178 while (*fmt >= '0' && *fmt <= '9') {
179 width = width * 10 + *fmt++ - '0';
183 for ( ;; ) {
184 switch (*fmt) {
186 case 'u':
187 sign = 0;
188 fmt++;
189 continue;
191 case 'm':
192 max_width = 1;
193 fmt++;
194 continue;
196 case 'X':
197 hex = 2;
198 sign = 0;
199 fmt++;
200 continue;
202 case 'x':
203 hex = 1;
204 sign = 0;
205 fmt++;
206 continue;
208 case '.':
209 fmt++;
211 while (*fmt >= '0' && *fmt <= '9') {
212 frac_width = frac_width * 10 + *fmt++ - '0';
215 break;
217 case '*':
218 slen = va_arg(args, size_t);
219 fmt++;
220 continue;
222 default:
223 break;
226 break;
230 switch (*fmt) {
232 case 'V':
233 v = va_arg(args, ngx_str_t *);
235 len = ngx_min(((size_t) (last - buf)), v->len);
236 buf = ngx_cpymem(buf, v->data, len);
237 fmt++;
239 continue;
241 case 'v':
242 vv = va_arg(args, ngx_variable_value_t *);
244 len = ngx_min(((size_t) (last - buf)), vv->len);
245 buf = ngx_cpymem(buf, vv->data, len);
246 fmt++;
248 continue;
250 case 's':
251 p = va_arg(args, u_char *);
253 if (slen == (size_t) -1) {
254 while (*p && buf < last) {
255 *buf++ = *p++;
258 } else {
259 len = ngx_min(((size_t) (last - buf)), slen);
260 buf = ngx_cpymem(buf, p, len);
263 fmt++;
265 continue;
267 case 'O':
268 i64 = (int64_t) va_arg(args, off_t);
269 sign = 1;
270 break;
272 case 'P':
273 i64 = (int64_t) va_arg(args, ngx_pid_t);
274 sign = 1;
275 break;
277 case 'T':
278 i64 = (int64_t) va_arg(args, time_t);
279 sign = 1;
280 break;
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;
291 break;
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);
299 break;
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);
308 if (max_width) {
309 width = NGX_INT_T_LEN;
312 break;
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);
320 break;
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);
328 break;
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);
336 break;
338 case 'L':
339 if (sign) {
340 i64 = va_arg(args, int64_t);
341 } else {
342 ui64 = va_arg(args, uint64_t);
344 break;
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);
353 if (max_width) {
354 width = NGX_ATOMIC_T_LEN;
357 break;
359 case 'f':
360 f = va_arg(args, double);
362 if (f < 0) {
363 *buf++ = '-';
364 f = -f;
367 ui64 = (int64_t) f;
368 frac = 0;
370 if (frac_width) {
372 scale = 1;
373 for (n = frac_width; n; n--) {
374 scale *= 10;
377 frac = (uint64_t) ((f - (double) ui64) * scale + 0.5);
379 if (frac == scale) {
380 ui64++;
381 frac = 0;
385 buf = ngx_sprintf_num(buf, last, ui64, zero, 0, width);
387 if (frac_width) {
388 if (buf < last) {
389 *buf++ = '.';
392 buf = ngx_sprintf_num(buf, last, frac, '0', 0, frac_width);
395 fmt++;
397 continue;
399 #if !(NGX_WIN32)
400 case 'r':
401 i64 = (int64_t) va_arg(args, rlim_t);
402 sign = 1;
403 break;
404 #endif
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;
414 case 'c':
415 d = va_arg(args, int);
416 *buf++ = (u_char) (d & 0xff);
417 fmt++;
419 continue;
421 case 'Z':
422 *buf++ = '\0';
423 fmt++;
425 continue;
427 case 'N':
428 #if (NGX_WIN32)
429 *buf++ = CR;
430 #endif
431 *buf++ = LF;
432 fmt++;
434 continue;
436 case '%':
437 *buf++ = '%';
438 fmt++;
440 continue;
442 default:
443 *buf++ = *fmt++;
445 continue;
448 if (sign) {
449 if (i64 < 0) {
450 *buf++ = '-';
451 ui64 = (uint64_t) -i64;
453 } else {
454 ui64 = (uint64_t) i64;
458 buf = ngx_sprintf_num(buf, last, ui64, zero, hex, width);
460 fmt++;
462 } else {
463 *buf++ = *fmt++;
467 return buf;
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)
475 u_char *p, temp[NGX_INT64_LEN + 1];
477 * we need temp[NGX_INT64_LEN] only,
478 * but icc issues the warning
480 size_t len;
481 uint32_t ui32;
482 static u_char hex[] = "0123456789abcdef";
483 static u_char HEX[] = "0123456789ABCDEF";
485 p = temp + NGX_INT64_LEN;
487 if (hexadecimal == 0) {
489 if (ui64 <= NGX_MAX_UINT32_VALUE) {
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.
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
503 * (i32 * 0xCCCCCCCD) >> 35
506 ui32 = (uint32_t) ui64;
508 do {
509 *--p = (u_char) (ui32 % 10 + '0');
510 } while (ui32 /= 10);
512 } else {
513 do {
514 *--p = (u_char) (ui64 % 10 + '0');
515 } while (ui64 /= 10);
518 } else if (hexadecimal == 1) {
520 do {
522 /* the "(uint32_t)" cast disables the BCC's warning */
523 *--p = hex[(uint32_t) (ui64 & 0xf)];
525 } while (ui64 >>= 4);
527 } else { /* hexadecimal == 2 */
529 do {
531 /* the "(uint32_t)" cast disables the BCC's warning */
532 *--p = HEX[(uint32_t) (ui64 & 0xf)];
534 } while (ui64 >>= 4);
537 /* zero or space padding */
539 len = (temp + NGX_INT64_LEN) - p;
541 while (len++ < width && buf < last) {
542 *buf++ = zero;
545 /* number safe copy */
547 len = (temp + NGX_INT64_LEN) - p;
549 if (buf + len > last) {
550 len = last - buf;
553 return ngx_cpymem(buf, p, len);
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.
564 ngx_int_t
565 ngx_strcasecmp(u_char *s1, u_char *s2)
567 ngx_uint_t c1, c2;
569 for ( ;; ) {
570 c1 = (ngx_uint_t) *s1++;
571 c2 = (ngx_uint_t) *s2++;
573 c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;
574 c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;
576 if (c1 == c2) {
578 if (c1) {
579 continue;
582 return 0;
585 return c1 - c2;
590 ngx_int_t
591 ngx_strncasecmp(u_char *s1, u_char *s2, size_t n)
593 ngx_uint_t c1, c2;
595 while (n) {
596 c1 = (ngx_uint_t) *s1++;
597 c2 = (ngx_uint_t) *s2++;
599 c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;
600 c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;
602 if (c1 == c2) {
604 if (c1) {
605 n--;
606 continue;
609 return 0;
612 return c1 - c2;
615 return 0;
619 u_char *
620 ngx_strnstr(u_char *s1, char *s2, size_t len)
622 u_char c1, c2;
623 size_t n;
625 c2 = *(u_char *) s2++;
627 n = ngx_strlen(s2);
629 do {
630 do {
631 if (len-- == 0) {
632 return NULL;
635 c1 = *s1++;
637 if (c1 == 0) {
638 return NULL;
641 } while (c1 != c2);
643 if (n > len) {
644 return NULL;
647 } while (ngx_strncmp(s1, (u_char *) s2, n) != 0);
649 return --s1;
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.
659 u_char *
660 ngx_strstrn(u_char *s1, char *s2, size_t n)
662 u_char c1, c2;
664 c2 = *(u_char *) s2++;
666 do {
667 do {
668 c1 = *s1++;
670 if (c1 == 0) {
671 return NULL;
674 } while (c1 != c2);
676 } while (ngx_strncmp(s1, (u_char *) s2, n) != 0);
678 return --s1;
682 u_char *
683 ngx_strcasestrn(u_char *s1, char *s2, size_t n)
685 ngx_uint_t c1, c2;
687 c2 = (ngx_uint_t) *s2++;
688 c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;
690 do {
691 do {
692 c1 = (ngx_uint_t) *s1++;
694 if (c1 == 0) {
695 return NULL;
698 c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;
700 } while (c1 != c2);
702 } while (ngx_strncasecmp(s1, (u_char *) s2, n) != 0);
704 return --s1;
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.
714 u_char *
715 ngx_strlcasestrn(u_char *s1, u_char *last, u_char *s2, size_t n)
717 ngx_uint_t c1, c2;
719 c2 = (ngx_uint_t) *s2++;
720 c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;
721 last -= n;
723 do {
724 do {
725 if (s1 >= last) {
726 return NULL;
729 c1 = (ngx_uint_t) *s1++;
731 c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;
733 } while (c1 != c2);
735 } while (ngx_strncasecmp(s1, s2, n) != 0);
737 return --s1;
741 ngx_int_t
742 ngx_rstrncmp(u_char *s1, u_char *s2, size_t n)
744 if (n == 0) {
745 return 0;
748 n--;
750 for ( ;; ) {
751 if (s1[n] != s2[n]) {
752 return s1[n] - s2[n];
755 if (n == 0) {
756 return 0;
759 n--;
764 ngx_int_t
765 ngx_rstrncasecmp(u_char *s1, u_char *s2, size_t n)
767 u_char c1, c2;
769 if (n == 0) {
770 return 0;
773 n--;
775 for ( ;; ) {
776 c1 = s1[n];
777 if (c1 >= 'a' && c1 <= 'z') {
778 c1 -= 'a' - 'A';
781 c2 = s2[n];
782 if (c2 >= 'a' && c2 <= 'z') {
783 c2 -= 'a' - 'A';
786 if (c1 != c2) {
787 return c1 - c2;
790 if (n == 0) {
791 return 0;
794 n--;
799 ngx_int_t
800 ngx_memn2cmp(u_char *s1, u_char *s2, size_t n1, size_t n2)
802 size_t n;
803 ngx_int_t m, z;
805 if (n1 <= n2) {
806 n = n1;
807 z = -1;
809 } else {
810 n = n2;
811 z = 1;
814 m = ngx_memcmp(s1, s2, n);
816 if (m || n1 == n2) {
817 return m;
820 return z;
824 ngx_int_t
825 ngx_dns_strcmp(u_char *s1, u_char *s2)
827 ngx_uint_t c1, c2;
829 for ( ;; ) {
830 c1 = (ngx_uint_t) *s1++;
831 c2 = (ngx_uint_t) *s2++;
833 c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;
834 c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;
836 if (c1 == c2) {
838 if (c1) {
839 continue;
842 return 0;
845 /* in ASCII '.' > '-', but we need '.' to be the lowest character */
847 c1 = (c1 == '.') ? ' ' : c1;
848 c2 = (c2 == '.') ? ' ' : c2;
850 return c1 - c2;
855 ngx_int_t
856 ngx_atoi(u_char *line, size_t n)
858 ngx_int_t value;
860 if (n == 0) {
861 return NGX_ERROR;
864 for (value = 0; n--; line++) {
865 if (*line < '0' || *line > '9') {
866 return NGX_ERROR;
869 value = value * 10 + (*line - '0');
872 if (value < 0) {
873 return NGX_ERROR;
875 } else {
876 return value;
881 /* parse a fixed point number, e.g., ngx_atofp("10.5", 4, 2) returns 1050 */
883 ngx_int_t
884 ngx_atofp(u_char *line, size_t n, size_t point)
886 ngx_int_t value;
887 ngx_uint_t dot;
889 if (n == 0) {
890 return NGX_ERROR;
893 dot = 0;
895 for (value = 0; n--; line++) {
897 if (point == 0) {
898 return NGX_ERROR;
901 if (*line == '.') {
902 if (dot) {
903 return NGX_ERROR;
906 dot = 1;
907 continue;
910 if (*line < '0' || *line > '9') {
911 return NGX_ERROR;
914 value = value * 10 + (*line - '0');
915 point -= dot;
918 while (point--) {
919 value = value * 10;
922 if (value < 0) {
923 return NGX_ERROR;
925 } else {
926 return value;
931 ssize_t
932 ngx_atosz(u_char *line, size_t n)
934 ssize_t value;
936 if (n == 0) {
937 return NGX_ERROR;
940 for (value = 0; n--; line++) {
941 if (*line < '0' || *line > '9') {
942 return NGX_ERROR;
945 value = value * 10 + (*line - '0');
948 if (value < 0) {
949 return NGX_ERROR;
951 } else {
952 return value;
957 off_t
958 ngx_atoof(u_char *line, size_t n)
960 off_t value;
962 if (n == 0) {
963 return NGX_ERROR;
966 for (value = 0; n--; line++) {
967 if (*line < '0' || *line > '9') {
968 return NGX_ERROR;
971 value = value * 10 + (*line - '0');
974 if (value < 0) {
975 return NGX_ERROR;
977 } else {
978 return value;
983 time_t
984 ngx_atotm(u_char *line, size_t n)
986 time_t value;
988 if (n == 0) {
989 return NGX_ERROR;
992 for (value = 0; n--; line++) {
993 if (*line < '0' || *line > '9') {
994 return NGX_ERROR;
997 value = value * 10 + (*line - '0');
1000 if (value < 0) {
1001 return NGX_ERROR;
1003 } else {
1004 return value;
1009 ngx_int_t
1010 ngx_hextoi(u_char *line, size_t n)
1012 u_char c, ch;
1013 ngx_int_t value;
1015 if (n == 0) {
1016 return NGX_ERROR;
1019 for (value = 0; n--; line++) {
1020 ch = *line;
1022 if (ch >= '0' && ch <= '9') {
1023 value = value * 16 + (ch - '0');
1024 continue;
1027 c = (u_char) (ch | 0x20);
1029 if (c >= 'a' && c <= 'f') {
1030 value = value * 16 + (c - 'a' + 10);
1031 continue;
1034 return NGX_ERROR;
1037 if (value < 0) {
1038 return NGX_ERROR;
1040 } else {
1041 return value;
1046 u_char *
1047 ngx_hex_dump(u_char *dst, u_char *src, size_t len)
1049 static u_char hex[] = "0123456789abcdef";
1051 while (len--) {
1052 *dst++ = hex[*src >> 4];
1053 *dst++ = hex[*src++ & 0xf];
1056 return dst;
1060 void
1061 ngx_encode_base64(ngx_str_t *dst, ngx_str_t *src)
1063 u_char *d, *s;
1064 size_t len;
1065 static u_char basis64[] =
1066 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1068 len = src->len;
1069 s = src->data;
1070 d = dst->data;
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];
1078 s += 3;
1079 len -= 3;
1082 if (len) {
1083 *d++ = basis64[(s[0] >> 2) & 0x3f];
1085 if (len == 1) {
1086 *d++ = basis64[(s[0] & 3) << 4];
1087 *d++ = '=';
1089 } else {
1090 *d++ = basis64[((s[0] & 3) << 4) | (s[1] >> 4)];
1091 *d++ = basis64[(s[1] & 0x0f) << 2];
1094 *d++ = '=';
1097 dst->len = d - dst->data;
1101 ngx_int_t
1102 ngx_decode_base64(ngx_str_t *dst, ngx_str_t *src)
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,
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
1124 return ngx_decode_base64_internal(dst, src, basis64);
1128 ngx_int_t
1129 ngx_decode_base64url(ngx_str_t *dst, ngx_str_t *src)
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,
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
1151 return ngx_decode_base64_internal(dst, src, basis64);
1155 static ngx_int_t
1156 ngx_decode_base64_internal(ngx_str_t *dst, ngx_str_t *src, const u_char *basis)
1158 size_t len;
1159 u_char *d, *s;
1161 for (len = 0; len < src->len; len++) {
1162 if (src->data[len] == '=') {
1163 break;
1166 if (basis[src->data[len]] == 77) {
1167 return NGX_ERROR;
1171 if (len % 4 == 1) {
1172 return NGX_ERROR;
1175 s = src->data;
1176 d = dst->data;
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]]);
1183 s += 4;
1184 len -= 4;
1187 if (len > 1) {
1188 *d++ = (u_char) (basis[s[0]] << 2 | basis[s[1]] >> 4);
1191 if (len > 2) {
1192 *d++ = (u_char) (basis[s[1]] << 4 | basis[s[2]] >> 2);
1195 dst->len = d - dst->data;
1197 return NGX_OK;
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
1210 uint32_t
1211 ngx_utf8_decode(u_char **p, size_t n)
1213 size_t len;
1214 uint32_t u, i, valid;
1216 u = **p;
1218 if (u >= 0xf0) {
1220 u &= 0x07;
1221 valid = 0xffff;
1222 len = 3;
1224 } else if (u >= 0xe0) {
1226 u &= 0x0f;
1227 valid = 0x7ff;
1228 len = 2;
1230 } else if (u >= 0xc2) {
1232 u &= 0x1f;
1233 valid = 0x7f;
1234 len = 1;
1236 } else {
1237 (*p)++;
1238 return 0xffffffff;
1241 if (n - 1 < len) {
1242 return 0xfffffffe;
1245 (*p)++;
1247 while (len) {
1248 i = *(*p)++;
1250 if (i < 0x80) {
1251 return 0xffffffff;
1254 u = (u << 6) | (i & 0x3f);
1256 len--;
1259 if (u > valid) {
1260 return u;
1263 return 0xffffffff;
1267 size_t
1268 ngx_utf8_length(u_char *p, size_t n)
1270 u_char c, *last;
1271 size_t len;
1273 last = p + n;
1275 for (len = 0; p < last; len++) {
1277 c = *p;
1279 if (c < 0x80) {
1280 p++;
1281 continue;
1284 if (ngx_utf8_decode(&p, n) > 0x10ffff) {
1285 /* invalid UTF-8 */
1286 return n;
1290 return len;
1294 u_char *
1295 ngx_utf8_cpystrn(u_char *dst, u_char *src, size_t n, size_t len)
1297 u_char c, *next;
1299 if (n == 0) {
1300 return dst;
1303 while (--n) {
1305 c = *src;
1306 *dst = c;
1308 if (c < 0x80) {
1310 if (c != '\0') {
1311 dst++;
1312 src++;
1313 len--;
1315 continue;
1318 return dst;
1321 next = src;
1323 if (ngx_utf8_decode(&next, len) > 0x10ffff) {
1324 /* invalid UTF-8 */
1325 break;
1328 while (src < next) {
1329 *dst++ = *src++;
1330 len--;
1334 *dst = '\0';
1336 return dst;
1340 uintptr_t
1341 ngx_escape_uri(u_char *dst, u_char *src, size_t size, ngx_uint_t type)
1343 ngx_uint_t n;
1344 uint32_t *escape;
1345 static u_char hex[] = "0123456789abcdef";
1347 /* " ", "#", "%", "?", %00-%1F, %7F-%FF */
1349 static uint32_t uri[] = {
1350 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1352 /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
1353 0x80000029, /* 1000 0000 0000 0000 0000 0000 0010 1001 */
1355 /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
1356 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1358 /* ~}| {zyx wvut srqp onml kjih gfed cba` */
1359 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */
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 */
1367 /* " ", "#", "%", "&", "+", "?", %00-%1F, %7F-%FF */
1369 static uint32_t args[] = {
1370 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1372 /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
1373 0x88000869, /* 1000 1000 0000 0000 0000 1000 0110 1001 */
1375 /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
1376 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1378 /* ~}| {zyx wvut srqp onml kjih gfed cba` */
1379 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */
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 */
1387 /* not ALPHA, DIGIT, "-", ".", "_", "~" */
1389 static uint32_t uri_component[] = {
1390 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1392 /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
1393 0xfc009fff, /* 1111 1100 0000 0000 1001 1111 1111 1111 */
1395 /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
1396 0x78000001, /* 0111 1000 0000 0000 0000 0000 0000 0001 */
1398 /* ~}| {zyx wvut srqp onml kjih gfed cba` */
1399 0xb8000001, /* 1011 1000 0000 0000 0000 0000 0000 0001 */
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 */
1407 /* " ", "#", """, "%", "'", %00-%1F, %7F-%FF */
1409 static uint32_t html[] = {
1410 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1412 /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
1413 0x000000ad, /* 0000 0000 0000 0000 0000 0000 1010 1101 */
1415 /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
1416 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1418 /* ~}| {zyx wvut srqp onml kjih gfed cba` */
1419 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */
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 */
1427 /* " ", """, "%", "'", %00-%1F, %7F-%FF */
1429 static uint32_t refresh[] = {
1430 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1432 /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
1433 0x00000085, /* 0000 0000 0000 0000 0000 0000 1000 0101 */
1435 /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
1436 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1438 /* ~}| {zyx wvut srqp onml kjih gfed cba` */
1439 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */
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 */
1447 /* " ", "%", %00-%1F */
1449 static uint32_t memcached[] = {
1450 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1452 /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
1453 0x00000021, /* 0000 0000 0000 0000 0000 0000 0010 0001 */
1455 /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
1456 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1458 /* ~}| {zyx wvut srqp onml kjih gfed cba` */
1459 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
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 */
1467 /* mail_auth is the same as memcached */
1469 static uint32_t *map[] =
1470 { uri, args, uri_component, html, refresh, memcached, memcached };
1473 escape = map[type];
1475 if (dst == NULL) {
1477 /* find the number of the characters to be escaped */
1479 n = 0;
1481 while (size) {
1482 if (escape[*src >> 5] & (1 << (*src & 0x1f))) {
1483 n++;
1485 src++;
1486 size--;
1489 return (uintptr_t) n;
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++;
1499 } else {
1500 *dst++ = *src++;
1502 size--;
1505 return (uintptr_t) dst;
1509 void
1510 ngx_unescape_uri(u_char **dst, u_char **src, size_t size, ngx_uint_t type)
1512 u_char *d, *s, ch, c, decoded;
1513 enum {
1514 sw_usual = 0,
1515 sw_quoted,
1516 sw_quoted_second
1517 } state;
1519 d = *dst;
1520 s = *src;
1522 state = 0;
1523 decoded = 0;
1525 while (size--) {
1527 ch = *s++;
1529 switch (state) {
1530 case sw_usual:
1531 if (ch == '?'
1532 && (type & (NGX_UNESCAPE_URI|NGX_UNESCAPE_REDIRECT)))
1534 *d++ = ch;
1535 goto done;
1538 if (ch == '%') {
1539 state = sw_quoted;
1540 break;
1543 *d++ = ch;
1544 break;
1546 case sw_quoted:
1548 if (ch >= '0' && ch <= '9') {
1549 decoded = (u_char) (ch - '0');
1550 state = sw_quoted_second;
1551 break;
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;
1561 /* the invalid quoted character */
1563 state = sw_usual;
1565 *d++ = ch;
1567 break;
1569 case sw_quoted_second:
1571 state = sw_usual;
1573 if (ch >= '0' && ch <= '9') {
1574 ch = (u_char) ((decoded << 4) + ch - '0');
1576 if (type & NGX_UNESCAPE_REDIRECT) {
1577 if (ch > '%' && ch < 0x7f) {
1578 *d++ = ch;
1579 break;
1582 *d++ = '%'; *d++ = *(s - 2); *d++ = *(s - 1);
1584 break;
1587 *d++ = ch;
1589 break;
1592 c = (u_char) (ch | 0x20);
1593 if (c >= 'a' && c <= 'f') {
1594 ch = (u_char) ((decoded << 4) + c - 'a' + 10);
1596 if (type & NGX_UNESCAPE_URI) {
1597 if (ch == '?') {
1598 *d++ = ch;
1599 goto done;
1602 *d++ = ch;
1603 break;
1606 if (type & NGX_UNESCAPE_REDIRECT) {
1607 if (ch == '?') {
1608 *d++ = ch;
1609 goto done;
1612 if (ch > '%' && ch < 0x7f) {
1613 *d++ = ch;
1614 break;
1617 *d++ = '%'; *d++ = *(s - 2); *d++ = *(s - 1);
1618 break;
1621 *d++ = ch;
1623 break;
1626 /* the invalid quoted character */
1628 break;
1632 done:
1634 *dst = d;
1635 *src = s;
1639 uintptr_t
1640 ngx_escape_html(u_char *dst, u_char *src, size_t size)
1642 u_char ch;
1643 ngx_uint_t len;
1645 if (dst == NULL) {
1647 len = 0;
1649 while (size) {
1650 switch (*src++) {
1652 case '<':
1653 len += sizeof("&lt;") - 2;
1654 break;
1656 case '>':
1657 len += sizeof("&gt;") - 2;
1658 break;
1660 case '&':
1661 len += sizeof("&amp;") - 2;
1662 break;
1664 case '"':
1665 len += sizeof("&quot;") - 2;
1666 break;
1668 default:
1669 break;
1671 size--;
1674 return (uintptr_t) len;
1677 while (size) {
1678 ch = *src++;
1680 switch (ch) {
1682 case '<':
1683 *dst++ = '&'; *dst++ = 'l'; *dst++ = 't'; *dst++ = ';';
1684 break;
1686 case '>':
1687 *dst++ = '&'; *dst++ = 'g'; *dst++ = 't'; *dst++ = ';';
1688 break;
1690 case '&':
1691 *dst++ = '&'; *dst++ = 'a'; *dst++ = 'm'; *dst++ = 'p';
1692 *dst++ = ';';
1693 break;
1695 case '"':
1696 *dst++ = '&'; *dst++ = 'q'; *dst++ = 'u'; *dst++ = 'o';
1697 *dst++ = 't'; *dst++ = ';';
1698 break;
1700 default:
1701 *dst++ = ch;
1702 break;
1704 size--;
1707 return (uintptr_t) dst;
1711 void
1712 ngx_str_rbtree_insert_value(ngx_rbtree_node_t *temp,
1713 ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
1715 ngx_str_node_t *n, *t;
1716 ngx_rbtree_node_t **p;
1718 for ( ;; ) {
1720 n = (ngx_str_node_t *) node;
1721 t = (ngx_str_node_t *) temp;
1723 if (node->key != temp->key) {
1725 p = (node->key < temp->key) ? &temp->left : &temp->right;
1727 } else if (n->str.len != t->str.len) {
1729 p = (n->str.len < t->str.len) ? &temp->left : &temp->right;
1731 } else {
1732 p = (ngx_memcmp(n->str.data, t->str.data, n->str.len) < 0)
1733 ? &temp->left : &temp->right;
1736 if (*p == sentinel) {
1737 break;
1740 temp = *p;
1743 *p = node;
1744 node->parent = temp;
1745 node->left = sentinel;
1746 node->right = sentinel;
1747 ngx_rbt_red(node);
1751 ngx_str_node_t *
1752 ngx_str_rbtree_lookup(ngx_rbtree_t *rbtree, ngx_str_t *val, uint32_t hash)
1754 ngx_int_t rc;
1755 ngx_str_node_t *n;
1756 ngx_rbtree_node_t *node, *sentinel;
1758 node = rbtree->root;
1759 sentinel = rbtree->sentinel;
1761 while (node != sentinel) {
1763 n = (ngx_str_node_t *) node;
1765 if (hash != node->key) {
1766 node = (hash < node->key) ? node->left : node->right;
1767 continue;
1770 if (val->len != n->str.len) {
1771 node = (val->len < n->str.len) ? node->left : node->right;
1772 continue;
1775 rc = ngx_memcmp(val->data, n->str.data, val->len);
1777 if (rc < 0) {
1778 node = node->left;
1779 continue;
1782 if (rc > 0) {
1783 node = node->right;
1784 continue;
1787 return n;
1790 return NULL;
1794 /* ngx_sort() is implemented as insertion sort because we need stable sort */
1796 void
1797 ngx_sort(void *base, size_t n, size_t size,
1798 ngx_int_t (*cmp)(const void *, const void *))
1800 u_char *p1, *p2, *p;
1802 p = ngx_alloc(size, ngx_cycle->log);
1803 if (p == NULL) {
1804 return;
1807 for (p1 = (u_char *) base + size;
1808 p1 < (u_char *) base + n * size;
1809 p1 += size)
1811 ngx_memcpy(p, p1, size);
1813 for (p2 = p1;
1814 p2 > (u_char *) base && cmp(p2 - size, p) > 0;
1815 p2 -= size)
1817 ngx_memcpy(p2, p2 - size, size);
1820 ngx_memcpy(p2, p, size);
1823 ngx_free(p);
1827 #if (NGX_MEMCPY_LIMIT)
1829 void *
1830 ngx_memcpy(void *dst, const void *src, size_t n)
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();
1837 return memcpy(dst, src, n);
1840 #endif