3 * Copyright (C) Igor Sysoev
4 * Copyright (C) Nginx, Inc.
8 #include <ngx_config.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
,
19 ngx_strlow(u_char
*dst
, u_char
*src
, size_t n
)
22 *dst
= ngx_tolower(*src
);
31 ngx_cpystrn(u_char
*dst
, u_char
*src
, size_t n
)
55 ngx_pstrdup(ngx_pool_t
*pool
, ngx_str_t
*src
)
59 dst
= ngx_pnalloc(pool
, src
->len
);
64 ngx_memcpy(dst
, src
->data
, src
->len
);
72 * %[0][width][x][X]O off_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
87 * %v ngx_variable_value_t *
88 * %s null-terminated string
89 * %*s length and string
97 * %S null-terminated wchar string
103 ngx_sprintf(u_char
*buf
, const char *fmt
, ...)
109 p
= ngx_vslprintf(buf
, (void *) -1, fmt
, args
);
117 ngx_snprintf(u_char
*buf
, size_t max
, const char *fmt
, ...)
123 p
= ngx_vslprintf(buf
, buf
+ max
, fmt
, args
);
131 ngx_slprintf(u_char
*buf
, u_char
*last
, const char *fmt
, ...)
137 p
= ngx_vslprintf(buf
, last
, fmt
, args
);
145 ngx_vslprintf(u_char
*buf
, u_char
*last
, const char *fmt
, va_list args
)
154 ngx_uint_t width
, sign
, hex
, max_width
, frac_width
, scale
, n
;
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
170 zero
= (u_char
) ((*++fmt
== '0') ? '0' : ' ');
178 while (*fmt
>= '0' && *fmt
<= '9') {
179 width
= width
* 10 + *fmt
++ - '0';
211 while (*fmt
>= '0' && *fmt
<= '9') {
212 frac_width
= frac_width
* 10 + *fmt
++ - '0';
218 slen
= va_arg(args
, size_t);
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
);
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
);
251 p
= va_arg(args
, u_char
*);
253 if (slen
== (size_t) -1) {
254 while (*p
&& buf
< last
) {
259 len
= ngx_min(((size_t) (last
- buf
)), slen
);
260 buf
= ngx_cpymem(buf
, p
, len
);
268 i64
= (int64_t) va_arg(args
, off_t
);
273 i64
= (int64_t) va_arg(args
, ngx_pid_t
);
278 i64
= (int64_t) va_arg(args
, time_t);
283 ms
= (ngx_msec_t
) va_arg(args
, ngx_msec_t
);
284 if ((ngx_msec_int_t
) ms
== -1) {
289 ui64
= (uint64_t) ms
;
295 i64
= (int64_t) va_arg(args
, ssize_t
);
297 ui64
= (uint64_t) va_arg(args
, size_t);
303 i64
= (int64_t) va_arg(args
, ngx_int_t
);
305 ui64
= (uint64_t) va_arg(args
, ngx_uint_t
);
309 width
= NGX_INT_T_LEN
;
316 i64
= (int64_t) va_arg(args
, int);
318 ui64
= (uint64_t) va_arg(args
, u_int
);
324 i64
= (int64_t) va_arg(args
, long);
326 ui64
= (uint64_t) va_arg(args
, u_long
);
332 i64
= (int64_t) va_arg(args
, int32_t);
334 ui64
= (uint64_t) va_arg(args
, uint32_t);
340 i64
= va_arg(args
, int64_t);
342 ui64
= va_arg(args
, uint64_t);
348 i64
= (int64_t) va_arg(args
, ngx_atomic_int_t
);
350 ui64
= (uint64_t) va_arg(args
, ngx_atomic_uint_t
);
354 width
= NGX_ATOMIC_T_LEN
;
360 f
= va_arg(args
, double);
373 for (n
= frac_width
; n
; n
--) {
377 frac
= (uint64_t) ((f
- (double) ui64
) * scale
+ 0.5);
385 buf
= ngx_sprintf_num(buf
, last
, ui64
, zero
, 0, width
);
392 buf
= ngx_sprintf_num(buf
, last
, frac
, '0', 0, frac_width
);
401 i64
= (int64_t) va_arg(args
, rlim_t
);
407 ui64
= (uintptr_t) va_arg(args
, void *);
411 width
= NGX_PTR_SIZE
* 2;
415 d
= va_arg(args
, int);
416 *buf
++ = (u_char
) (d
& 0xff);
451 ui64
= (uint64_t) -i64
;
454 ui64
= (uint64_t) i64
;
458 buf
= ngx_sprintf_num(buf
, last
, ui64
, zero
, hex
, width
);
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
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
;
509 *--p
= (u_char
) (ui32
% 10 + '0');
510 } while (ui32
/= 10);
514 *--p
= (u_char
) (ui64
% 10 + '0');
515 } while (ui64
/= 10);
518 } else if (hexadecimal
== 1) {
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 */
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
) {
545 /* number safe copy */
547 len
= (temp
+ NGX_INT64_LEN
) - p
;
549 if (buf
+ len
> last
) {
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.
565 ngx_strcasecmp(u_char
*s1
, u_char
*s2
)
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
;
591 ngx_strncasecmp(u_char
*s1
, u_char
*s2
, size_t 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
;
620 ngx_strnstr(u_char
*s1
, char *s2
, size_t len
)
625 c2
= *(u_char
*) s2
++;
647 } while (ngx_strncmp(s1
, (u_char
*) s2
, n
) != 0);
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.
660 ngx_strstrn(u_char
*s1
, char *s2
, size_t n
)
664 c2
= *(u_char
*) s2
++;
676 } while (ngx_strncmp(s1
, (u_char
*) s2
, n
) != 0);
683 ngx_strcasestrn(u_char
*s1
, char *s2
, size_t n
)
687 c2
= (ngx_uint_t
) *s2
++;
688 c2
= (c2
>= 'A' && c2
<= 'Z') ? (c2
| 0x20) : c2
;
692 c1
= (ngx_uint_t
) *s1
++;
698 c1
= (c1
>= 'A' && c1
<= 'Z') ? (c1
| 0x20) : c1
;
702 } while (ngx_strncasecmp(s1
, (u_char
*) s2
, n
) != 0);
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.
715 ngx_strlcasestrn(u_char
*s1
, u_char
*last
, u_char
*s2
, size_t n
)
719 c2
= (ngx_uint_t
) *s2
++;
720 c2
= (c2
>= 'A' && c2
<= 'Z') ? (c2
| 0x20) : c2
;
729 c1
= (ngx_uint_t
) *s1
++;
731 c1
= (c1
>= 'A' && c1
<= 'Z') ? (c1
| 0x20) : c1
;
735 } while (ngx_strncasecmp(s1
, s2
, n
) != 0);
742 ngx_rstrncmp(u_char
*s1
, u_char
*s2
, size_t n
)
751 if (s1
[n
] != s2
[n
]) {
752 return s1
[n
] - s2
[n
];
765 ngx_rstrncasecmp(u_char
*s1
, u_char
*s2
, size_t n
)
777 if (c1
>= 'a' && c1
<= 'z') {
782 if (c2
>= 'a' && c2
<= 'z') {
800 ngx_memn2cmp(u_char
*s1
, u_char
*s2
, size_t n1
, size_t n2
)
814 m
= ngx_memcmp(s1
, s2
, n
);
825 ngx_dns_strcmp(u_char
*s1
, u_char
*s2
)
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
;
845 /* in ASCII '.' > '-', but we need '.' to be the lowest character */
847 c1
= (c1
== '.') ? ' ' : c1
;
848 c2
= (c2
== '.') ? ' ' : c2
;
856 ngx_atoi(u_char
*line
, size_t n
)
864 for (value
= 0; n
--; line
++) {
865 if (*line
< '0' || *line
> '9') {
869 value
= value
* 10 + (*line
- '0');
881 /* parse a fixed point number, e.g., ngx_atofp("10.5", 4, 2) returns 1050 */
884 ngx_atofp(u_char
*line
, size_t n
, size_t point
)
895 for (value
= 0; n
--; line
++) {
910 if (*line
< '0' || *line
> '9') {
914 value
= value
* 10 + (*line
- '0');
932 ngx_atosz(u_char
*line
, size_t n
)
940 for (value
= 0; n
--; line
++) {
941 if (*line
< '0' || *line
> '9') {
945 value
= value
* 10 + (*line
- '0');
958 ngx_atoof(u_char
*line
, size_t n
)
966 for (value
= 0; n
--; line
++) {
967 if (*line
< '0' || *line
> '9') {
971 value
= value
* 10 + (*line
- '0');
984 ngx_atotm(u_char
*line
, size_t n
)
992 for (value
= 0; n
--; line
++) {
993 if (*line
< '0' || *line
> '9') {
997 value
= value
* 10 + (*line
- '0');
1010 ngx_hextoi(u_char
*line
, size_t n
)
1019 for (value
= 0; n
--; line
++) {
1022 if (ch
>= '0' && ch
<= '9') {
1023 value
= value
* 16 + (ch
- '0');
1027 c
= (u_char
) (ch
| 0x20);
1029 if (c
>= 'a' && c
<= 'f') {
1030 value
= value
* 16 + (c
- 'a' + 10);
1047 ngx_hex_dump(u_char
*dst
, u_char
*src
, size_t len
)
1049 static u_char hex
[] = "0123456789abcdef";
1052 *dst
++ = hex
[*src
>> 4];
1053 *dst
++ = hex
[*src
++ & 0xf];
1061 ngx_encode_base64(ngx_str_t
*dst
, ngx_str_t
*src
)
1065 static u_char basis64
[] =
1066 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
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];
1083 *d
++ = basis64
[(s
[0] >> 2) & 0x3f];
1086 *d
++ = basis64
[(s
[0] & 3) << 4];
1090 *d
++ = basis64
[((s
[0] & 3) << 4) | (s
[1] >> 4)];
1091 *d
++ = basis64
[(s
[1] & 0x0f) << 2];
1097 dst
->len
= d
- dst
->data
;
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
);
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
);
1156 ngx_decode_base64_internal(ngx_str_t
*dst
, ngx_str_t
*src
, const u_char
*basis
)
1161 for (len
= 0; len
< src
->len
; len
++) {
1162 if (src
->data
[len
] == '=') {
1166 if (basis
[src
->data
[len
]] == 77) {
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]]);
1188 *d
++ = (u_char
) (basis
[s
[0]] << 2 | basis
[s
[1]] >> 4);
1192 *d
++ = (u_char
) (basis
[s
[1]] << 4 | basis
[s
[2]] >> 2);
1195 dst
->len
= d
- dst
->data
;
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
1211 ngx_utf8_decode(u_char
**p
, size_t n
)
1214 uint32_t u
, i
, valid
;
1224 } else if (u
>= 0xe0) {
1230 } else if (u
>= 0xc2) {
1254 u
= (u
<< 6) | (i
& 0x3f);
1268 ngx_utf8_length(u_char
*p
, size_t n
)
1275 for (len
= 0; p
< last
; len
++) {
1284 if (ngx_utf8_decode(&p
, n
) > 0x10ffff) {
1295 ngx_utf8_cpystrn(u_char
*dst
, u_char
*src
, size_t n
, size_t len
)
1323 if (ngx_utf8_decode(&next
, len
) > 0x10ffff) {
1328 while (src
< next
) {
1341 ngx_escape_uri(u_char
*dst
, u_char
*src
, size_t size
, ngx_uint_t type
)
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
};
1477 /* find the number of the characters to be escaped */
1482 if (escape
[*src
>> 5] & (1 << (*src
& 0x1f))) {
1489 return (uintptr_t) n
;
1493 if (escape
[*src
>> 5] & (1 << (*src
& 0x1f))) {
1495 *dst
++ = hex
[*src
>> 4];
1496 *dst
++ = hex
[*src
& 0xf];
1505 return (uintptr_t) dst
;
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
;
1532 && (type
& (NGX_UNESCAPE_URI
|NGX_UNESCAPE_REDIRECT
)))
1548 if (ch
>= '0' && ch
<= '9') {
1549 decoded
= (u_char
) (ch
- '0');
1550 state
= sw_quoted_second
;
1554 c
= (u_char
) (ch
| 0x20);
1555 if (c
>= 'a' && c
<= 'f') {
1556 decoded
= (u_char
) (c
- 'a' + 10);
1557 state
= sw_quoted_second
;
1561 /* the invalid quoted character */
1569 case sw_quoted_second
:
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) {
1582 *d
++ = '%'; *d
++ = *(s
- 2); *d
++ = *(s
- 1);
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
) {
1606 if (type
& NGX_UNESCAPE_REDIRECT
) {
1612 if (ch
> '%' && ch
< 0x7f) {
1617 *d
++ = '%'; *d
++ = *(s
- 2); *d
++ = *(s
- 1);
1626 /* the invalid quoted character */
1640 ngx_escape_html(u_char
*dst
, u_char
*src
, size_t size
)
1653 len
+= sizeof("<") - 2;
1657 len
+= sizeof(">") - 2;
1661 len
+= sizeof("&") - 2;
1665 len
+= sizeof(""") - 2;
1674 return (uintptr_t) len
;
1683 *dst
++ = '&'; *dst
++ = 'l'; *dst
++ = 't'; *dst
++ = ';';
1687 *dst
++ = '&'; *dst
++ = 'g'; *dst
++ = 't'; *dst
++ = ';';
1691 *dst
++ = '&'; *dst
++ = 'a'; *dst
++ = 'm'; *dst
++ = 'p';
1696 *dst
++ = '&'; *dst
++ = 'q'; *dst
++ = 'u'; *dst
++ = 'o';
1697 *dst
++ = 't'; *dst
++ = ';';
1707 return (uintptr_t) dst
;
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
;
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
;
1732 p
= (ngx_memcmp(n
->str
.data
, t
->str
.data
, n
->str
.len
) < 0)
1733 ? &temp
->left
: &temp
->right
;
1736 if (*p
== sentinel
) {
1744 node
->parent
= temp
;
1745 node
->left
= sentinel
;
1746 node
->right
= sentinel
;
1752 ngx_str_rbtree_lookup(ngx_rbtree_t
*rbtree
, ngx_str_t
*val
, uint32_t hash
)
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
;
1770 if (val
->len
!= n
->str
.len
) {
1771 node
= (val
->len
< n
->str
.len
) ? node
->left
: node
->right
;
1775 rc
= ngx_memcmp(val
->data
, n
->str
.data
, val
->len
);
1794 /* ngx_sort() is implemented as insertion sort because we need stable sort */
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
);
1807 for (p1
= (u_char
*) base
+ size
;
1808 p1
< (u_char
*) base
+ n
* size
;
1811 ngx_memcpy(p
, p1
, size
);
1814 p2
> (u_char
*) base
&& cmp(p2
- size
, p
) > 0;
1817 ngx_memcpy(p2
, p2
- size
, size
);
1820 ngx_memcpy(p2
, p
, size
);
1827 #if (NGX_MEMCPY_LIMIT)
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
);
1837 return memcpy(dst
, src
, n
);