blob: 0ad594f82a427ce29e432943c2bafd06b85418e3 [file] [log] [blame]
Igor Sysoev6de5c2c2002-08-06 16:39:45 +00001
Igor Sysoevd90282d2004-09-28 08:34:51 +00002/*
Igor Sysoevff8da912004-09-29 16:00:49 +00003 * Copyright (C) Igor Sysoev
Igor Sysoevd90282d2004-09-28 08:34:51 +00004 */
5
6
Igor Sysoev6de5c2c2002-08-06 16:39:45 +00007#include <ngx_config.h>
Igor Sysoevdc479b42003-03-20 16:09:44 +00008#include <ngx_core.h>
Igor Sysoev6de5c2c2002-08-06 16:39:45 +00009
10
Igor Sysoev74b7e5f2008-11-10 15:20:59 +000011static u_char *ngx_sprintf_num(u_char *buf, u_char *last, uint64_t ui64,
12 u_char zero, ngx_uint_t hexadecimal, ngx_uint_t width);
13
14
Igor Sysoev777b0192008-08-04 10:07:00 +000015void
16ngx_strlow(u_char *dst, u_char *src, size_t n)
17{
18 while (n--) {
19 *dst = ngx_tolower(*src);
20 dst++;
21 src++;
22 }
23}
24
25
Igor Sysoevd039a2e2005-02-22 14:40:13 +000026u_char *
27ngx_cpystrn(u_char *dst, u_char *src, size_t n)
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000028{
Igor Sysoev3d09c8d2003-05-06 17:03:16 +000029 if (n == 0) {
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000030 return dst;
Igor Sysoev3d09c8d2003-05-06 17:03:16 +000031 }
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000032
Igor Sysoev4959ec42005-05-23 12:07:45 +000033 for ( /* void */ ; --n; dst++, src++) {
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000034 *dst = *src;
35
Igor Sysoev3d09c8d2003-05-06 17:03:16 +000036 if (*dst == '\0') {
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000037 return dst;
Igor Sysoev3d09c8d2003-05-06 17:03:16 +000038 }
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000039 }
40
41 *dst = '\0';
42
43 return dst;
44}
Igor Sysoevdc479b42003-03-20 16:09:44 +000045
46
Igor Sysoevd039a2e2005-02-22 14:40:13 +000047u_char *
48ngx_pstrdup(ngx_pool_t *pool, ngx_str_t *src)
Igor Sysoev805d9db2005-02-03 19:33:37 +000049{
50 u_char *dst;
51
Igor Sysoev7f6b2ff2008-06-17 15:00:30 +000052 dst = ngx_pnalloc(pool, src->len);
Igor Sysoevc1571722005-03-19 12:38:37 +000053 if (dst == NULL) {
Igor Sysoev805d9db2005-02-03 19:33:37 +000054 return NULL;
55 }
56
57 ngx_memcpy(dst, src->data, src->len);
58
59 return dst;
60}
61
62
Igor Sysoevc0edbcc2004-10-21 15:34:38 +000063/*
64 * supported formats:
Igor Sysoev42b12b32004-12-02 18:40:46 +000065 * %[0][width][x][X]O off_t
Igor Sysoev1b735832004-11-11 14:07:14 +000066 * %[0][width]T time_t
67 * %[0][width][u][x|X]z ssize_t/size_t
68 * %[0][width][u][x|X]d int/u_int
69 * %[0][width][u][x|X]l long
70 * %[0][width|m][u][x|X]i ngx_int_t/ngx_uint_t
71 * %[0][width][u][x|X]D int32_t/uint32_t
72 * %[0][width][u][x|X]L int64_t/uint64_t
Igor Sysoev4a715592005-02-24 12:29:09 +000073 * %[0][width|m][u][x|X]A ngx_atomic_int_t/ngx_atomic_uint_t
Igor Sysoev74b7e5f2008-11-10 15:20:59 +000074 * %[0][width][.width]f float
Igor Sysoev1b735832004-11-11 14:07:14 +000075 * %P ngx_pid_t
Igor Sysoev208eed22005-10-07 13:30:52 +000076 * %M ngx_msec_t
Igor Sysoev1b735832004-11-11 14:07:14 +000077 * %r rlim_t
Igor Sysoev0d4b3722007-08-20 09:57:19 +000078 * %p void *
79 * %V ngx_str_t *
80 * %v ngx_variable_value_t *
Igor Sysoev1b735832004-11-11 14:07:14 +000081 * %s null-terminated string
Igor Sysoev79d9a042007-12-24 17:05:16 +000082 * %*s length and string
Igor Sysoev1b735832004-11-11 14:07:14 +000083 * %Z '\0'
Igor Sysoev85ef94b2005-06-23 13:41:06 +000084 * %N '\n'
Igor Sysoev1b735832004-11-11 14:07:14 +000085 * %c char
86 * %% %
Igor Sysoevc0edbcc2004-10-21 15:34:38 +000087 *
Igor Sysoev1b735832004-11-11 14:07:14 +000088 * reserved:
89 * %t ptrdiff_t
90 * %S null-teminated wchar string
91 * %C wchar
Igor Sysoevc0edbcc2004-10-21 15:34:38 +000092 */
93
Igor Sysoev1b735832004-11-11 14:07:14 +000094
Igor Sysoev4d656dc2005-03-22 16:02:46 +000095u_char * ngx_cdecl
Igor Sysoevd039a2e2005-02-22 14:40:13 +000096ngx_sprintf(u_char *buf, const char *fmt, ...)
Igor Sysoevc0edbcc2004-10-21 15:34:38 +000097{
Igor Sysoev1b735832004-11-11 14:07:14 +000098 u_char *p;
99 va_list args;
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000100
Igor Sysoev1b735832004-11-11 14:07:14 +0000101 va_start(args, fmt);
102 p = ngx_vsnprintf(buf, /* STUB */ 65536, fmt, args);
103 va_end(args);
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000104
Igor Sysoev1b735832004-11-11 14:07:14 +0000105 return p;
106}
107
108
Igor Sysoev4d656dc2005-03-22 16:02:46 +0000109u_char * ngx_cdecl
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000110ngx_snprintf(u_char *buf, size_t max, const char *fmt, ...)
Igor Sysoev1b735832004-11-11 14:07:14 +0000111{
112 u_char *p;
113 va_list args;
114
115 va_start(args, fmt);
116 p = ngx_vsnprintf(buf, max, fmt, args);
117 va_end(args);
118
119 return p;
120}
121
122
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000123u_char *
124ngx_vsnprintf(u_char *buf, size_t max, const char *fmt, va_list args)
Igor Sysoev1b735832004-11-11 14:07:14 +0000125{
Igor Sysoev74b7e5f2008-11-10 15:20:59 +0000126 u_char *p, zero, *last;
Igor Sysoevf42ed052007-07-17 09:23:23 +0000127 int d;
Igor Sysoev74b7e5f2008-11-10 15:20:59 +0000128 float f, scale;
Igor Sysoev79d9a042007-12-24 17:05:16 +0000129 size_t len, slen;
Igor Sysoevf42ed052007-07-17 09:23:23 +0000130 int64_t i64;
131 uint64_t ui64;
132 ngx_msec_t ms;
Igor Sysoev74b7e5f2008-11-10 15:20:59 +0000133 ngx_uint_t width, sign, hex, max_width, frac_width, i;
Igor Sysoev0d4b3722007-08-20 09:57:19 +0000134 ngx_str_t *v;
135 ngx_variable_value_t *vv;
Igor Sysoev1b735832004-11-11 14:07:14 +0000136
137 if (max == 0) {
138 return buf;
139 }
140
141 last = buf + max;
142
143 while (*fmt && buf < last) {
144
145 /*
146 * "buf < last" means that we could copy at least one character:
147 * the plain character, "%%", "%c", and minus without the checking
148 */
149
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000150 if (*fmt == '%') {
151
Igor Sysoev1b735832004-11-11 14:07:14 +0000152 i64 = 0;
153 ui64 = 0;
154
155 zero = (u_char) ((*++fmt == '0') ? '0' : ' ');
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000156 width = 0;
157 sign = 1;
Igor Sysoev74b7e5f2008-11-10 15:20:59 +0000158 hex = 0;
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000159 max_width = 0;
Igor Sysoev74b7e5f2008-11-10 15:20:59 +0000160 frac_width = 0;
Igor Sysoev0bd32b72008-01-22 15:13:01 +0000161 slen = (size_t) -1;
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000162
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000163 while (*fmt >= '0' && *fmt <= '9') {
164 width = width * 10 + *fmt++ - '0';
165 }
166
167
168 for ( ;; ) {
169 switch (*fmt) {
170
171 case 'u':
172 sign = 0;
173 fmt++;
174 continue;
175
Igor Sysoevd43bee82004-11-20 19:52:20 +0000176 case 'm':
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000177 max_width = 1;
Igor Sysoevd43bee82004-11-20 19:52:20 +0000178 fmt++;
179 continue;
180
Igor Sysoev1b735832004-11-11 14:07:14 +0000181 case 'X':
Igor Sysoev74b7e5f2008-11-10 15:20:59 +0000182 hex = 2;
Igor Sysoev1b735832004-11-11 14:07:14 +0000183 sign = 0;
184 fmt++;
185 continue;
186
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000187 case 'x':
Igor Sysoev74b7e5f2008-11-10 15:20:59 +0000188 hex = 1;
Igor Sysoev1b735832004-11-11 14:07:14 +0000189 sign = 0;
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000190 fmt++;
191 continue;
192
Igor Sysoev74b7e5f2008-11-10 15:20:59 +0000193 case '.':
194 fmt++;
195
196 while (*fmt >= '0' && *fmt <= '9') {
197 frac_width = frac_width * 10 + *fmt++ - '0';
198 }
199
200 break;
201
Igor Sysoev79d9a042007-12-24 17:05:16 +0000202 case '*':
Igor Sysoevfb424652008-01-24 15:18:17 +0000203 slen = va_arg(args, size_t);
Igor Sysoev79d9a042007-12-24 17:05:16 +0000204 fmt++;
205 continue;
206
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000207 default:
208 break;
209 }
210
211 break;
212 }
213
214
215 switch (*fmt) {
216
Igor Sysoev1b735832004-11-11 14:07:14 +0000217 case 'V':
Igor Sysoev0d4b3722007-08-20 09:57:19 +0000218 v = va_arg(args, ngx_str_t *);
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000219
Igor Sysoevf42ed052007-07-17 09:23:23 +0000220 len = v->len;
Igor Sysoev09c684b2005-11-09 17:25:55 +0000221 len = (buf + len < last) ? len : (size_t) (last - buf);
222
Igor Sysoevf42ed052007-07-17 09:23:23 +0000223 buf = ngx_cpymem(buf, v->data, len);
Igor Sysoev1b735832004-11-11 14:07:14 +0000224 fmt++;
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000225
Igor Sysoev1b735832004-11-11 14:07:14 +0000226 continue;
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000227
Igor Sysoev0d4b3722007-08-20 09:57:19 +0000228 case 'v':
229 vv = va_arg(args, ngx_variable_value_t *);
230
231 len = vv->len;
232 len = (buf + len < last) ? len : (size_t) (last - buf);
233
234 buf = ngx_cpymem(buf, vv->data, len);
235 fmt++;
236
237 continue;
238
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000239 case 's':
Igor Sysoev1b735832004-11-11 14:07:14 +0000240 p = va_arg(args, u_char *);
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000241
Igor Sysoev0bd32b72008-01-22 15:13:01 +0000242 if (slen == (size_t) -1) {
Igor Sysoev79d9a042007-12-24 17:05:16 +0000243 while (*p && buf < last) {
244 *buf++ = *p++;
245 }
246
247 } else {
Igor Sysoev16315762008-01-24 15:18:58 +0000248 len = (buf + slen < last) ? slen : (size_t) (last - buf);
249
250 buf = ngx_cpymem(buf, p, len);
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000251 }
Igor Sysoev79d9a042007-12-24 17:05:16 +0000252
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000253 fmt++;
254
255 continue;
256
Igor Sysoev1b735832004-11-11 14:07:14 +0000257 case 'O':
258 i64 = (int64_t) va_arg(args, off_t);
259 sign = 1;
260 break;
261
262 case 'P':
263 i64 = (int64_t) va_arg(args, ngx_pid_t);
264 sign = 1;
265 break;
266
267 case 'T':
268 i64 = (int64_t) va_arg(args, time_t);
269 sign = 1;
270 break;
271
Igor Sysoev208eed22005-10-07 13:30:52 +0000272 case 'M':
Igor Sysoev78452232005-10-12 13:50:36 +0000273 ms = (ngx_msec_t) va_arg(args, ngx_msec_t);
274 if ((ngx_msec_int_t) ms == -1) {
275 sign = 1;
276 i64 = -1;
277 } else {
278 sign = 0;
279 ui64 = (uint64_t) ms;
280 }
Igor Sysoev208eed22005-10-07 13:30:52 +0000281 break;
282
Igor Sysoev1b735832004-11-11 14:07:14 +0000283 case 'z':
284 if (sign) {
285 i64 = (int64_t) va_arg(args, ssize_t);
286 } else {
287 ui64 = (uint64_t) va_arg(args, size_t);
288 }
289 break;
290
291 case 'i':
292 if (sign) {
293 i64 = (int64_t) va_arg(args, ngx_int_t);
294 } else {
295 ui64 = (uint64_t) va_arg(args, ngx_uint_t);
296 }
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000297
298 if (max_width) {
299 width = NGX_INT_T_LEN;
300 }
301
Igor Sysoev1b735832004-11-11 14:07:14 +0000302 break;
303
304 case 'd':
305 if (sign) {
306 i64 = (int64_t) va_arg(args, int);
307 } else {
308 ui64 = (uint64_t) va_arg(args, u_int);
309 }
310 break;
311
312 case 'l':
313 if (sign) {
314 i64 = (int64_t) va_arg(args, long);
315 } else {
316 ui64 = (uint64_t) va_arg(args, u_long);
317 }
318 break;
319
320 case 'D':
321 if (sign) {
322 i64 = (int64_t) va_arg(args, int32_t);
323 } else {
324 ui64 = (uint64_t) va_arg(args, uint32_t);
325 }
326 break;
327
328 case 'L':
329 if (sign) {
330 i64 = va_arg(args, int64_t);
331 } else {
332 ui64 = va_arg(args, uint64_t);
333 }
334 break;
335
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000336 case 'A':
337 if (sign) {
338 i64 = (int64_t) va_arg(args, ngx_atomic_int_t);
339 } else {
Igor Sysoev4a715592005-02-24 12:29:09 +0000340 ui64 = (uint64_t) va_arg(args, ngx_atomic_uint_t);
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000341 }
342
343 if (max_width) {
344 width = NGX_ATOMIC_T_LEN;
345 }
346
347 break;
348
Igor Sysoev74b7e5f2008-11-10 15:20:59 +0000349 case 'f':
350 f = (float) va_arg(args, double);
351
352 if (f < 0) {
353 *buf++ = '-';
354 f = -f;
355 }
356
357 ui64 = (int64_t) f;
358
359 buf = ngx_sprintf_num(buf, last, ui64, zero, 0, width);
360
361 if (frac_width) {
362
363 if (buf < last) {
364 *buf++ = '.';
365 }
366
367 scale = 1.0;
368
369 for (i = 0; i < frac_width; i++) {
370 scale *= 10.0;
371 }
372
373 /*
374 * (int64_t) cast is required for msvc6:
375 * it can not convert uint64_t to double
376 */
377 ui64 = (uint64_t) ((f - (int64_t) ui64) * scale);
378
379 buf = ngx_sprintf_num(buf, last, ui64, '0', 0, frac_width);
380 }
381
382 fmt++;
383
384 continue;
385
Igor Sysoev1b735832004-11-11 14:07:14 +0000386#if !(NGX_WIN32)
387 case 'r':
388 i64 = (int64_t) va_arg(args, rlim_t);
389 sign = 1;
390 break;
391#endif
392
393 case 'p':
394 ui64 = (uintptr_t) va_arg(args, void *);
Igor Sysoev74b7e5f2008-11-10 15:20:59 +0000395 hex = 2;
Igor Sysoev1b735832004-11-11 14:07:14 +0000396 sign = 0;
397 zero = '0';
Igor Sysoevc2807ec2006-02-16 15:26:46 +0000398 width = NGX_PTR_SIZE * 2;
Igor Sysoev1b735832004-11-11 14:07:14 +0000399 break;
400
Igor Sysoev723e6cc2004-10-25 15:29:23 +0000401 case 'c':
Igor Sysoev1b735832004-11-11 14:07:14 +0000402 d = va_arg(args, int);
Igor Sysoev723e6cc2004-10-25 15:29:23 +0000403 *buf++ = (u_char) (d & 0xff);
404 fmt++;
405
406 continue;
407
Igor Sysoev1b735832004-11-11 14:07:14 +0000408 case 'Z':
409 *buf++ = '\0';
410 fmt++;
411
412 continue;
413
Igor Sysoev85ef94b2005-06-23 13:41:06 +0000414 case 'N':
415#if (NGX_WIN32)
416 *buf++ = CR;
417#endif
418 *buf++ = LF;
419 fmt++;
420
421 continue;
422
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000423 case '%':
424 *buf++ = '%';
425 fmt++;
426
427 continue;
428
429 default:
430 *buf++ = *fmt++;
431
432 continue;
433 }
434
Igor Sysoev1b735832004-11-11 14:07:14 +0000435 if (sign) {
436 if (i64 < 0) {
437 *buf++ = '-';
438 ui64 = (uint64_t) -i64;
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000439
Igor Sysoev1b735832004-11-11 14:07:14 +0000440 } else {
441 ui64 = (uint64_t) i64;
442 }
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000443 }
444
Igor Sysoev74b7e5f2008-11-10 15:20:59 +0000445 buf = ngx_sprintf_num(buf, last, ui64, zero, hex, width);
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000446
447 fmt++;
448
449 } else {
450 *buf++ = *fmt++;
451 }
452 }
453
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000454 return buf;
455}
456
457
Igor Sysoev74b7e5f2008-11-10 15:20:59 +0000458static u_char *
459ngx_sprintf_num(u_char *buf, u_char *last, uint64_t ui64, u_char zero,
460 ngx_uint_t hexadecimal, ngx_uint_t width)
461{
462 u_char *p, temp[NGX_INT64_LEN + 1];
463 /*
464 * we need temp[NGX_INT64_LEN] only,
465 * but icc issues the warning
466 */
467 size_t len;
468 uint32_t ui32;
469 static u_char hex[] = "0123456789abcdef";
470 static u_char HEX[] = "0123456789ABCDEF";
471
472 p = temp + NGX_INT64_LEN;
473
474 if (hexadecimal == 0) {
475
476 if (ui64 <= NGX_MAX_UINT32_VALUE) {
477
478 /*
479 * To divide 64-bit numbers and to find remainders
480 * on the x86 platform gcc and icc call the libc functions
481 * [u]divdi3() and [u]moddi3(), they call another function
482 * in its turn. On FreeBSD it is the qdivrem() function,
483 * its source code is about 170 lines of the code.
484 * The glibc counterpart is about 150 lines of the code.
485 *
486 * For 32-bit numbers and some divisors gcc and icc use
487 * a inlined multiplication and shifts. For example,
488 * unsigned "i32 / 10" is compiled to
489 *
490 * (i32 * 0xCCCCCCCD) >> 35
491 */
492
493 ui32 = (uint32_t) ui64;
494
495 do {
496 *--p = (u_char) (ui32 % 10 + '0');
497 } while (ui32 /= 10);
498
499 } else {
500 do {
501 *--p = (u_char) (ui64 % 10 + '0');
502 } while (ui64 /= 10);
503 }
504
505 } else if (hexadecimal == 1) {
506
507 do {
508
509 /* the "(uint32_t)" cast disables the BCC's warning */
510 *--p = hex[(uint32_t) (ui64 & 0xf)];
511
512 } while (ui64 >>= 4);
513
514 } else { /* hexadecimal == 2 */
515
516 do {
517
518 /* the "(uint32_t)" cast disables the BCC's warning */
519 *--p = HEX[(uint32_t) (ui64 & 0xf)];
520
521 } while (ui64 >>= 4);
522 }
523
524 /* zero or space padding */
525
526 len = (temp + NGX_INT64_LEN) - p;
527
528 while (len++ < width && buf < last) {
529 *buf++ = zero;
530 }
531
532 /* number safe copy */
533
534 len = (temp + NGX_INT64_LEN) - p;
535
536 if (buf + len > last) {
537 len = last - buf;
538 }
539
540 return ngx_cpymem(buf, p, len);
541}
542
543
Igor Sysoev722231f2007-02-14 18:51:19 +0000544/*
Igor Sysoev066e6322007-09-26 12:23:34 +0000545 * We use ngx_strcasecmp()/ngx_strncasecmp() for 7-bit ASCII strings only,
Igor Sysoev722231f2007-02-14 18:51:19 +0000546 * and implement our own ngx_strcasecmp()/ngx_strncasecmp()
547 * to avoid libc locale overhead. Besides, we use the ngx_uint_t's
548 * instead of the u_char's, because they are slightly faster.
549 */
550
551ngx_int_t
552ngx_strcasecmp(u_char *s1, u_char *s2)
553{
554 ngx_uint_t c1, c2;
555
556 for ( ;; ) {
557 c1 = (ngx_uint_t) *s1++;
558 c2 = (ngx_uint_t) *s2++;
559
560 c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;
561 c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;
562
563 if (c1 == c2) {
564
565 if (c1) {
566 continue;
567 }
568
569 return 0;
570 }
571
572 return c1 - c2;
573 }
574}
575
576
577ngx_int_t
578ngx_strncasecmp(u_char *s1, u_char *s2, size_t n)
579{
580 ngx_uint_t c1, c2;
581
582 while (n) {
583 c1 = (ngx_uint_t) *s1++;
584 c2 = (ngx_uint_t) *s2++;
585
586 c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;
587 c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;
588
589 if (c1 == c2) {
590
591 if (c1) {
592 n--;
593 continue;
594 }
595
596 return 0;
597 }
598
599 return c1 - c2;
600 }
601
602 return 0;
603}
604
605
Igor Sysoev35fe5fd2007-10-01 14:48:33 +0000606u_char *
607ngx_strnstr(u_char *s1, char *s2, size_t len)
608{
609 u_char c1, c2;
610 size_t n;
611
612 c2 = *(u_char *) s2++;
613
614 n = ngx_strlen(s2);
615
616 do {
617 do {
618 if (len-- == 0) {
619 return NULL;
620 }
621
622 c1 = *s1++;
623
624 if (c1 == 0) {
625 return NULL;
626 }
627
628 } while (c1 != c2);
629
630 if (n > len) {
631 return NULL;
632 }
633
634 } while (ngx_strncmp(s1, (u_char *) s2, n) != 0);
635
636 return --s1;
637}
638
639
Igor Sysoev66697022007-10-01 13:00:30 +0000640/*
641 * ngx_strstrn() and ngx_strcasestrn() are intended to search for static
642 * substring with known length in null-terminated string. The argument n
643 * must be length of the second substring - 1.
644 */
645
Igor Sysoev1bd98702007-09-26 19:25:52 +0000646u_char *
647ngx_strstrn(u_char *s1, char *s2, size_t n)
648{
649 u_char c1, c2;
650
651 c2 = *(u_char *) s2++;
652
653 do {
654 do {
655 c1 = *s1++;
656
657 if (c1 == 0) {
658 return NULL;
659 }
660
661 } while (c1 != c2);
662
663 } while (ngx_strncmp(s1, (u_char *) s2, n) != 0);
664
665 return --s1;
666}
667
668
669u_char *
670ngx_strcasestrn(u_char *s1, char *s2, size_t n)
671{
672 ngx_uint_t c1, c2;
673
674 c2 = (ngx_uint_t) *s2++;
675 c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;
676
677 do {
678 do {
679 c1 = (ngx_uint_t) *s1++;
680
681 if (c1 == 0) {
682 return NULL;
683 }
684
685 c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;
686
687 } while (c1 != c2);
688
689 } while (ngx_strncasecmp(s1, (u_char *) s2, n) != 0);
690
691 return --s1;
692}
693
694
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000695ngx_int_t
696ngx_rstrncmp(u_char *s1, u_char *s2, size_t n)
Igor Sysoev3d09c8d2003-05-06 17:03:16 +0000697{
698 if (n == 0) {
699 return 0;
700 }
701
702 n--;
703
704 for ( ;; ) {
705 if (s1[n] != s2[n]) {
Igor Sysoev10a543a2004-03-16 07:10:12 +0000706 return s1[n] - s2[n];
Igor Sysoev3d09c8d2003-05-06 17:03:16 +0000707 }
708
709 if (n == 0) {
710 return 0;
711 }
712
713 n--;
714 }
715}
716
717
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000718ngx_int_t
719ngx_rstrncasecmp(u_char *s1, u_char *s2, size_t n)
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000720{
721 u_char c1, c2;
722
723 if (n == 0) {
724 return 0;
725 }
726
727 n--;
728
729 for ( ;; ) {
730 c1 = s1[n];
731 if (c1 >= 'a' && c1 <= 'z') {
732 c1 -= 'a' - 'A';
733 }
734
735 c2 = s2[n];
736 if (c2 >= 'a' && c2 <= 'z') {
737 c2 -= 'a' - 'A';
738 }
739
740 if (c1 != c2) {
741 return c1 - c2;
742 }
743
744 if (n == 0) {
745 return 0;
746 }
747
748 n--;
749 }
750}
751
752
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000753ngx_int_t
Igor Sysoevec3cabd2007-01-12 21:58:02 +0000754ngx_memn2cmp(u_char *s1, u_char *s2, size_t n1, size_t n2)
Igor Sysoev37cc1652007-01-12 20:15:59 +0000755{
756 size_t n;
757 ngx_int_t m, z;
758
759 if (n1 <= n2) {
760 n = n1;
761 z = -1;
762
763 } else {
764 n = n2;
765 z = 1;
766 }
767
Igor Sysoevec3cabd2007-01-12 21:58:02 +0000768 m = ngx_memcmp(s1, s2, n);
Igor Sysoev37cc1652007-01-12 20:15:59 +0000769
770 if (m || n1 == n2) {
771 return m;
772 }
773
774 return z;
775}
776
777
778ngx_int_t
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000779ngx_atoi(u_char *line, size_t n)
Igor Sysoevdc479b42003-03-20 16:09:44 +0000780{
Igor Sysoev10a543a2004-03-16 07:10:12 +0000781 ngx_int_t value;
Igor Sysoevdc479b42003-03-20 16:09:44 +0000782
Igor Sysoev3d09c8d2003-05-06 17:03:16 +0000783 if (n == 0) {
784 return NGX_ERROR;
785 }
786
Igor Sysoevdc479b42003-03-20 16:09:44 +0000787 for (value = 0; n--; line++) {
Igor Sysoev1d8d9ee2003-04-28 15:06:39 +0000788 if (*line < '0' || *line > '9') {
789 return NGX_ERROR;
790 }
Igor Sysoevdc479b42003-03-20 16:09:44 +0000791
Igor Sysoev1d8d9ee2003-04-28 15:06:39 +0000792 value = value * 10 + (*line - '0');
Igor Sysoevdc479b42003-03-20 16:09:44 +0000793 }
794
Igor Sysoev1d8d9ee2003-04-28 15:06:39 +0000795 if (value < 0) {
796 return NGX_ERROR;
Igor Sysoev18684bd2004-05-20 17:33:52 +0000797
798 } else {
799 return value;
800 }
801}
802
803
Igor Sysoevc1571722005-03-19 12:38:37 +0000804ssize_t
805ngx_atosz(u_char *line, size_t n)
806{
807 ssize_t value;
808
809 if (n == 0) {
810 return NGX_ERROR;
811 }
812
813 for (value = 0; n--; line++) {
814 if (*line < '0' || *line > '9') {
815 return NGX_ERROR;
816 }
817
818 value = value * 10 + (*line - '0');
819 }
820
821 if (value < 0) {
822 return NGX_ERROR;
823
824 } else {
825 return value;
826 }
827}
828
829
830off_t
831ngx_atoof(u_char *line, size_t n)
832{
833 off_t value;
834
835 if (n == 0) {
836 return NGX_ERROR;
837 }
838
839 for (value = 0; n--; line++) {
840 if (*line < '0' || *line > '9') {
841 return NGX_ERROR;
842 }
843
844 value = value * 10 + (*line - '0');
845 }
846
847 if (value < 0) {
848 return NGX_ERROR;
849
850 } else {
851 return value;
852 }
853}
854
855
856time_t
857ngx_atotm(u_char *line, size_t n)
858{
859 time_t value;
860
861 if (n == 0) {
862 return NGX_ERROR;
863 }
864
865 for (value = 0; n--; line++) {
866 if (*line < '0' || *line > '9') {
867 return NGX_ERROR;
868 }
869
870 value = value * 10 + (*line - '0');
871 }
872
873 if (value < 0) {
874 return NGX_ERROR;
875
876 } else {
877 return value;
878 }
879}
880
881
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000882ngx_int_t
883ngx_hextoi(u_char *line, size_t n)
Igor Sysoev18684bd2004-05-20 17:33:52 +0000884{
Igor Sysoev066496a2006-10-16 12:21:17 +0000885 u_char c, ch;
Igor Sysoev18684bd2004-05-20 17:33:52 +0000886 ngx_int_t value;
887
888 if (n == 0) {
889 return NGX_ERROR;
890 }
891
892 for (value = 0; n--; line++) {
893 ch = *line;
894
895 if (ch >= '0' && ch <= '9') {
896 value = value * 16 + (ch - '0');
897 continue;
898 }
899
Igor Sysoev066496a2006-10-16 12:21:17 +0000900 c = (u_char) (ch | 0x20);
Igor Sysoev18684bd2004-05-20 17:33:52 +0000901
Igor Sysoev066496a2006-10-16 12:21:17 +0000902 if (c >= 'a' && c <= 'f') {
903 value = value * 16 + (c - 'a' + 10);
Igor Sysoev18684bd2004-05-20 17:33:52 +0000904 continue;
905 }
906
907 return NGX_ERROR;
908 }
909
910 if (value < 0) {
911 return NGX_ERROR;
912
Igor Sysoev1d8d9ee2003-04-28 15:06:39 +0000913 } else {
914 return value;
915 }
Igor Sysoevdc479b42003-03-20 16:09:44 +0000916}
917
918
Igor Sysoeva03fa362007-12-17 21:06:17 +0000919u_char *
920ngx_hex_dump(u_char *dst, u_char *src, size_t len)
Igor Sysoev9cc1ace2003-11-04 22:12:39 +0000921{
Igor Sysoev10a543a2004-03-16 07:10:12 +0000922 static u_char hex[] = "0123456789abcdef";
Igor Sysoeve8732b02003-11-05 17:03:41 +0000923
Igor Sysoeva03fa362007-12-17 21:06:17 +0000924 while (len--) {
925 *dst++ = hex[*src >> 4];
926 *dst++ = hex[*src++ & 0xf];
Igor Sysoev74e95c22003-11-09 20:03:38 +0000927 }
928
Igor Sysoeva03fa362007-12-17 21:06:17 +0000929 return dst;
Igor Sysoev9cc1ace2003-11-04 22:12:39 +0000930}
931
932
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000933void
934ngx_encode_base64(ngx_str_t *dst, ngx_str_t *src)
Igor Sysoev6deb0412004-07-30 17:05:14 +0000935{
936 u_char *d, *s;
Igor Sysoev967fd632004-08-27 15:40:59 +0000937 size_t len;
Igor Sysoev6deb0412004-07-30 17:05:14 +0000938 static u_char basis64[] =
939 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
940
Igor Sysoev967fd632004-08-27 15:40:59 +0000941 len = src->len;
Igor Sysoeva7c4a2a2004-08-29 03:55:41 +0000942 s = src->data;
943 d = dst->data;
Igor Sysoev6deb0412004-07-30 17:05:14 +0000944
Igor Sysoev967fd632004-08-27 15:40:59 +0000945 while (len > 2) {
946 *d++ = basis64[(s[0] >> 2) & 0x3f];
947 *d++ = basis64[((s[0] & 3) << 4) | (s[1] >> 4)];
948 *d++ = basis64[((s[1] & 0x0f) << 2) | (s[2] >> 6)];
949 *d++ = basis64[s[2] & 0x3f];
950
951 s += 3;
952 len -= 3;
Igor Sysoev6deb0412004-07-30 17:05:14 +0000953 }
954
Igor Sysoev967fd632004-08-27 15:40:59 +0000955 if (len) {
956 *d++ = basis64[(s[0] >> 2) & 0x3f];
Igor Sysoev6deb0412004-07-30 17:05:14 +0000957
Igor Sysoev967fd632004-08-27 15:40:59 +0000958 if (len == 1) {
959 *d++ = basis64[(s[0] & 3) << 4];
Igor Sysoev6deb0412004-07-30 17:05:14 +0000960 *d++ = '=';
961
962 } else {
Igor Sysoev967fd632004-08-27 15:40:59 +0000963 *d++ = basis64[((s[0] & 3) << 4) | (s[1] >> 4)];
964 *d++ = basis64[(s[1] & 0x0f) << 2];
Igor Sysoev6deb0412004-07-30 17:05:14 +0000965 }
966
967 *d++ = '=';
968 }
969
970 dst->len = d - dst->data;
Igor Sysoev6deb0412004-07-30 17:05:14 +0000971}
972
973
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000974ngx_int_t
975ngx_decode_base64(ngx_str_t *dst, ngx_str_t *src)
Igor Sysoev6deb0412004-07-30 17:05:14 +0000976{
Igor Sysoev967fd632004-08-27 15:40:59 +0000977 size_t len;
978 u_char *d, *s;
Igor Sysoevb5c75dc2006-10-28 14:36:44 +0000979 static u_char basis64[] = {
980 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
981 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
982 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 62, 77, 77, 77, 63,
983 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 77, 77, 77, 77, 77, 77,
984 77, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
985 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 77, 77, 77, 77, 77,
986 77, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
987 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 77, 77, 77, 77, 77,
Igor Sysoev6deb0412004-07-30 17:05:14 +0000988
Igor Sysoevb5c75dc2006-10-28 14:36:44 +0000989 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
990 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
991 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
992 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
993 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
994 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
995 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
996 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77
997 };
Igor Sysoev967fd632004-08-27 15:40:59 +0000998
999 for (len = 0; len < src->len; len++) {
1000 if (src->data[len] == '=') {
1001 break;
1002 }
1003
1004 if (basis64[src->data[len]] == 77) {
1005 return NGX_ERROR;
1006 }
1007 }
1008
1009 if (len % 4 == 1) {
1010 return NGX_ERROR;
1011 }
1012
Igor Sysoev6deb0412004-07-30 17:05:14 +00001013 s = src->data;
Igor Sysoeva7c4a2a2004-08-29 03:55:41 +00001014 d = dst->data;
Igor Sysoev6deb0412004-07-30 17:05:14 +00001015
Igor Sysoev967fd632004-08-27 15:40:59 +00001016 while (len > 3) {
Igor Sysoeva7c4a2a2004-08-29 03:55:41 +00001017 *d++ = (u_char) (basis64[s[0]] << 2 | basis64[s[1]] >> 4);
1018 *d++ = (u_char) (basis64[s[1]] << 4 | basis64[s[2]] >> 2);
1019 *d++ = (u_char) (basis64[s[2]] << 6 | basis64[s[3]]);
Igor Sysoev6deb0412004-07-30 17:05:14 +00001020
Igor Sysoev967fd632004-08-27 15:40:59 +00001021 s += 4;
1022 len -= 4;
Igor Sysoev6deb0412004-07-30 17:05:14 +00001023 }
1024
Igor Sysoev967fd632004-08-27 15:40:59 +00001025 if (len > 1) {
Igor Sysoeva7c4a2a2004-08-29 03:55:41 +00001026 *d++ = (u_char) (basis64[s[0]] << 2 | basis64[s[1]] >> 4);
Igor Sysoev967fd632004-08-27 15:40:59 +00001027 }
1028
1029 if (len > 2) {
Igor Sysoeva7c4a2a2004-08-29 03:55:41 +00001030 *d++ = (u_char) (basis64[s[1]] << 4 | basis64[s[2]] >> 2);
Igor Sysoev967fd632004-08-27 15:40:59 +00001031 }
1032
1033 dst->len = d - dst->data;
Igor Sysoev967fd632004-08-27 15:40:59 +00001034
Igor Sysoev6deb0412004-07-30 17:05:14 +00001035 return NGX_OK;
1036}
1037
1038
Igor Sysoevef809b82006-06-28 16:00:26 +00001039/*
Igor Sysoeva0898572008-07-29 14:41:34 +00001040 * ngx_utf8_decode() decodes two and more bytes UTF sequences only
Igor Sysoevef809b82006-06-28 16:00:26 +00001041 * the return values:
1042 * 0x80 - 0x10ffff valid character
Igor Sysoev96eaa052008-07-25 14:29:05 +00001043 * 0x110000 - 0xfffffffd invalid sequence
Igor Sysoevef809b82006-06-28 16:00:26 +00001044 * 0xfffffffe incomplete sequence
1045 * 0xffffffff error
1046 */
1047
1048uint32_t
Igor Sysoeva0898572008-07-29 14:41:34 +00001049ngx_utf8_decode(u_char **p, size_t n)
Igor Sysoevef809b82006-06-28 16:00:26 +00001050{
1051 size_t len;
1052 uint32_t u, i, valid;
1053
1054 u = **p;
1055
1056 if (u > 0xf0) {
1057
1058 u &= 0x07;
1059 valid = 0xffff;
1060 len = 3;
1061
1062 } else if (u > 0xe0) {
1063
1064 u &= 0x0f;
1065 valid = 0x7ff;
1066 len = 2;
1067
1068 } else if (u > 0xc0) {
1069
1070 u &= 0x1f;
1071 valid = 0x7f;
1072 len = 1;
1073
1074 } else {
1075 (*p)++;
1076 return 0xffffffff;
1077 }
1078
1079 if (n - 1 < len) {
1080 return 0xfffffffe;
1081 }
1082
1083 (*p)++;
1084
1085 while (len) {
1086 i = *(*p)++;
1087
1088 if (i < 0x80) {
1089 return 0xffffffff;
1090 }
1091
1092 u = (u << 6) | (i & 0x3f);
1093
1094 len--;
1095 }
1096
1097 if (u > valid) {
1098 return u;
1099 }
1100
1101 return 0xffffffff;
1102}
1103
1104
Igor Sysoevb145b062005-06-15 18:33:41 +00001105size_t
Igor Sysoeva0898572008-07-29 14:41:34 +00001106ngx_utf8_length(u_char *p, size_t n)
Igor Sysoevb145b062005-06-15 18:33:41 +00001107{
Igor Sysoev96eaa052008-07-25 14:29:05 +00001108 u_char c, *last;
1109 size_t len;
Igor Sysoevb145b062005-06-15 18:33:41 +00001110
Igor Sysoev96eaa052008-07-25 14:29:05 +00001111 last = p + n;
Igor Sysoevb145b062005-06-15 18:33:41 +00001112
Igor Sysoev96eaa052008-07-25 14:29:05 +00001113 for (len = 0; p < last; len++) {
1114
1115 c = *p;
Igor Sysoevb145b062005-06-15 18:33:41 +00001116
1117 if (c < 0x80) {
Igor Sysoev96eaa052008-07-25 14:29:05 +00001118 p++;
Igor Sysoevb145b062005-06-15 18:33:41 +00001119 continue;
1120 }
1121
Igor Sysoeva0898572008-07-29 14:41:34 +00001122 if (ngx_utf8_decode(&p, n) > 0x10ffff) {
1123 /* invalid UTF-8 */
Igor Sysoev96eaa052008-07-25 14:29:05 +00001124 return n;
Igor Sysoevb145b062005-06-15 18:33:41 +00001125 }
Igor Sysoevb145b062005-06-15 18:33:41 +00001126 }
1127
1128 return len;
1129}
1130
1131
Igor Sysoev5192b362005-07-08 14:34:20 +00001132u_char *
Igor Sysoeva0898572008-07-29 14:41:34 +00001133ngx_utf8_cpystrn(u_char *dst, u_char *src, size_t n, size_t len)
Igor Sysoev5192b362005-07-08 14:34:20 +00001134{
Igor Sysoev96eaa052008-07-25 14:29:05 +00001135 u_char c, *next;
Igor Sysoev5192b362005-07-08 14:34:20 +00001136
1137 if (n == 0) {
1138 return dst;
1139 }
1140
Igor Sysoev96eaa052008-07-25 14:29:05 +00001141 while (--n) {
Igor Sysoev5192b362005-07-08 14:34:20 +00001142
1143 c = *src;
1144 *dst = c;
1145
1146 if (c < 0x80) {
Igor Sysoev96eaa052008-07-25 14:29:05 +00001147
1148 if (c != '\0') {
1149 dst++;
1150 src++;
1151 len--;
1152
Igor Sysoev5192b362005-07-08 14:34:20 +00001153 continue;
1154 }
1155
1156 return dst;
1157 }
1158
Igor Sysoev96eaa052008-07-25 14:29:05 +00001159 next = src;
Igor Sysoev5192b362005-07-08 14:34:20 +00001160
Igor Sysoeva0898572008-07-29 14:41:34 +00001161 if (ngx_utf8_decode(&next, len) > 0x10ffff) {
1162 /* invalid UTF-8 */
Igor Sysoev96eaa052008-07-25 14:29:05 +00001163 break;
Igor Sysoev5192b362005-07-08 14:34:20 +00001164 }
1165
Igor Sysoev96eaa052008-07-25 14:29:05 +00001166 len--;
1167
1168 while (src < next) {
1169 *++dst = *++src;
1170 len--;
1171 }
Igor Sysoev5192b362005-07-08 14:34:20 +00001172 }
1173
1174 *dst = '\0';
1175
1176 return dst;
1177}
1178
1179
Igor Sysoevd039a2e2005-02-22 14:40:13 +00001180uintptr_t
1181ngx_escape_uri(u_char *dst, u_char *src, size_t size, ngx_uint_t type)
Igor Sysoevdc479b42003-03-20 16:09:44 +00001182{
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001183 ngx_uint_t i, n;
1184 uint32_t *escape;
1185 static u_char hex[] = "0123456789abcdef";
Igor Sysoev1b735832004-11-11 14:07:14 +00001186
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001187 /* " ", "#", "%", "?", %00-%1F, %7F-%FF */
Igor Sysoev805d9db2005-02-03 19:33:37 +00001188
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001189 static uint32_t uri[] = {
1190 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
Igor Sysoevdc479b42003-03-20 16:09:44 +00001191
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001192 /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
1193 0x80000029, /* 1000 0000 0000 0000 0000 0000 0010 1001 */
Igor Sysoevdc479b42003-03-20 16:09:44 +00001194
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001195 /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
1196 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
Igor Sysoevdc479b42003-03-20 16:09:44 +00001197
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001198 /* ~}| {zyx wvut srqp onml kjih gfed cba` */
1199 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */
Igor Sysoev924bd792004-10-11 15:07:03 +00001200
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001201 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1202 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1203 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1204 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1205 };
Igor Sysoev924bd792004-10-11 15:07:03 +00001206
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001207 /* " ", "#", "%", "+", "?", %00-%1F, %7F-%FF */
Igor Sysoev805d9db2005-02-03 19:33:37 +00001208
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001209 static uint32_t args[] = {
1210 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
Igor Sysoev805d9db2005-02-03 19:33:37 +00001211
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001212 /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
1213 0x80000829, /* 1000 0000 0000 0000 0000 1000 0010 1001 */
Igor Sysoev805d9db2005-02-03 19:33:37 +00001214
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001215 /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
1216 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
Igor Sysoev805d9db2005-02-03 19:33:37 +00001217
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001218 /* ~}| {zyx wvut srqp onml kjih gfed cba` */
1219 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */
Igor Sysoev805d9db2005-02-03 19:33:37 +00001220
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001221 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1222 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1223 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1224 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1225 };
Igor Sysoev805d9db2005-02-03 19:33:37 +00001226
Igor Sysoevd4ff5612007-08-20 09:50:53 +00001227 /* " ", "#", """, "%", "'", %00-%1F, %7F-%FF */
Igor Sysoev805d9db2005-02-03 19:33:37 +00001228
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001229 static uint32_t html[] = {
1230 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
Igor Sysoev1b735832004-11-11 14:07:14 +00001231
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001232 /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
Igor Sysoev049ae002007-07-13 09:35:51 +00001233 0x000000ad, /* 0000 0000 0000 0000 0000 0000 1010 1101 */
Igor Sysoev1b735832004-11-11 14:07:14 +00001234
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001235 /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
1236 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
Igor Sysoev1b735832004-11-11 14:07:14 +00001237
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001238 /* ~}| {zyx wvut srqp onml kjih gfed cba` */
1239 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */
Igor Sysoev1b735832004-11-11 14:07:14 +00001240
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001241 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1242 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1243 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1244 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1245 };
Igor Sysoev1b735832004-11-11 14:07:14 +00001246
Igor Sysoevd4ff5612007-08-20 09:50:53 +00001247 /* " ", """, "%", "'", %00-%1F, %7F-%FF */
Igor Sysoev1b735832004-11-11 14:07:14 +00001248
Igor Sysoev8662b6b2007-07-13 09:37:01 +00001249 static uint32_t refresh[] = {
1250 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1251
1252 /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
Igor Sysoevcc5484f2007-11-09 13:17:58 +00001253 0x00000085, /* 0000 0000 0000 0000 0000 0000 1000 0101 */
Igor Sysoev8662b6b2007-07-13 09:37:01 +00001254
1255 /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
1256 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1257
1258 /* ~}| {zyx wvut srqp onml kjih gfed cba` */
1259 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */
1260
1261 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1262 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1263 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1264 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1265 };
1266
Igor Sysoevd4ff5612007-08-20 09:50:53 +00001267 /* " ", "%", %00-%1F */
Igor Sysoev3f707822007-07-22 19:18:59 +00001268
1269 static uint32_t memcached[] = {
1270 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1271
1272 /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
Igor Sysoevd4ff5612007-08-20 09:50:53 +00001273 0x00000021, /* 0000 0000 0000 0000 0000 0000 0010 0001 */
Igor Sysoev3f707822007-07-22 19:18:59 +00001274
1275 /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
1276 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1277
1278 /* ~}| {zyx wvut srqp onml kjih gfed cba` */
1279 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1280
1281 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1282 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1283 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1284 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1285 };
1286
Igor Sysoevd4ff5612007-08-20 09:50:53 +00001287 /* mail_auth is the same as memcached */
1288
1289 static uint32_t *map[] =
1290 { uri, args, html, refresh, memcached, memcached };
Igor Sysoev8662b6b2007-07-13 09:37:01 +00001291
1292
1293 escape = map[type];
Igor Sysoev1b735832004-11-11 14:07:14 +00001294
Igor Sysoev924bd792004-10-11 15:07:03 +00001295 if (dst == NULL) {
1296
1297 /* find the number of the characters to be escaped */
1298
1299 n = 0;
1300
1301 for (i = 0; i < size; i++) {
1302 if (escape[*src >> 5] & (1 << (*src & 0x1f))) {
1303 n++;
1304 }
1305 src++;
1306 }
1307
Igor Sysoev805d9db2005-02-03 19:33:37 +00001308 return (uintptr_t) n;
Igor Sysoevdc479b42003-03-20 16:09:44 +00001309 }
1310
Igor Sysoev924bd792004-10-11 15:07:03 +00001311 for (i = 0; i < size; i++) {
1312 if (escape[*src >> 5] & (1 << (*src & 0x1f))) {
1313 *dst++ = '%';
1314 *dst++ = hex[*src >> 4];
1315 *dst++ = hex[*src & 0xf];
1316 src++;
Igor Sysoevdc479b42003-03-20 16:09:44 +00001317
Igor Sysoev924bd792004-10-11 15:07:03 +00001318 } else {
1319 *dst++ = *src++;
1320 }
Igor Sysoevdc479b42003-03-20 16:09:44 +00001321 }
1322
Igor Sysoev805d9db2005-02-03 19:33:37 +00001323 return (uintptr_t) dst;
Igor Sysoevdc479b42003-03-20 16:09:44 +00001324}
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +00001325
1326
1327void
Igor Sysoevae33d012006-01-17 20:04:32 +00001328ngx_unescape_uri(u_char **dst, u_char **src, size_t size, ngx_uint_t type)
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +00001329{
1330 u_char *d, *s, ch, c, decoded;
1331 enum {
1332 sw_usual = 0,
1333 sw_quoted,
1334 sw_quoted_second
1335 } state;
1336
1337 d = *dst;
1338 s = *src;
1339
1340 state = 0;
1341 decoded = 0;
1342
1343 while (size--) {
1344
1345 ch = *s++;
1346
1347 switch (state) {
1348 case sw_usual:
Igor Sysoevf0a51cf2007-10-22 10:19:17 +00001349 if (ch == '?'
1350 && (type & (NGX_UNESCAPE_URI|NGX_UNESCAPE_REDIRECT)))
1351 {
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +00001352 *d++ = ch;
1353 goto done;
1354 }
1355
1356 if (ch == '%') {
1357 state = sw_quoted;
1358 break;
1359 }
1360
1361 *d++ = ch;
1362 break;
1363
1364 case sw_quoted:
1365
1366 if (ch >= '0' && ch <= '9') {
1367 decoded = (u_char) (ch - '0');
1368 state = sw_quoted_second;
1369 break;
1370 }
1371
1372 c = (u_char) (ch | 0x20);
1373 if (c >= 'a' && c <= 'f') {
1374 decoded = (u_char) (c - 'a' + 10);
1375 state = sw_quoted_second;
1376 break;
1377 }
1378
Igor Sysoev24025022005-12-16 15:07:08 +00001379 /* the invalid quoted character */
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +00001380
Igor Sysoev24025022005-12-16 15:07:08 +00001381 state = sw_usual;
1382
1383 *d++ = ch;
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +00001384
1385 break;
1386
1387 case sw_quoted_second:
1388
Igor Sysoev24025022005-12-16 15:07:08 +00001389 state = sw_usual;
1390
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +00001391 if (ch >= '0' && ch <= '9') {
1392 ch = (u_char) ((decoded << 4) + ch - '0');
1393
Igor Sysoevf0a51cf2007-10-22 10:19:17 +00001394 if (type & NGX_UNESCAPE_REDIRECT) {
Igor Sysoevae33d012006-01-17 20:04:32 +00001395 if (ch > '%' && ch < 0x7f) {
1396 *d++ = ch;
1397 break;
1398 }
1399
1400 *d++ = '%'; *d++ = *(s - 2); *d++ = *(s - 1);
1401
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +00001402 break;
1403 }
1404
Igor Sysoevae33d012006-01-17 20:04:32 +00001405 *d++ = ch;
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +00001406
1407 break;
1408 }
1409
1410 c = (u_char) (ch | 0x20);
1411 if (c >= 'a' && c <= 'f') {
1412 ch = (u_char) ((decoded << 4) + c - 'a' + 10);
1413
Igor Sysoevf0a51cf2007-10-22 10:19:17 +00001414 if (type & NGX_UNESCAPE_URI) {
1415 if (ch == '?') {
1416 *d++ = ch;
1417 goto done;
1418 }
1419
1420 *d++ = ch;
1421 break;
1422 }
1423
1424 if (type & NGX_UNESCAPE_REDIRECT) {
Igor Sysoevae33d012006-01-17 20:04:32 +00001425 if (ch == '?') {
1426 *d++ = ch;
1427 goto done;
1428 }
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +00001429
Igor Sysoevae33d012006-01-17 20:04:32 +00001430 if (ch > '%' && ch < 0x7f) {
1431 *d++ = ch;
1432 break;
1433 }
1434
1435 *d++ = '%'; *d++ = *(s - 2); *d++ = *(s - 1);
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +00001436 break;
1437 }
1438
Igor Sysoevae33d012006-01-17 20:04:32 +00001439 *d++ = ch;
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +00001440
1441 break;
1442 }
1443
Igor Sysoev24025022005-12-16 15:07:08 +00001444 /* the invalid quoted character */
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +00001445
1446 break;
1447 }
1448 }
1449
1450done:
1451
1452 *dst = d;
1453 *src = s;
1454}
Igor Sysoevd3283ff2005-12-05 13:18:09 +00001455
1456
Igor Sysoev1730c752007-09-27 09:36:50 +00001457uintptr_t
1458ngx_escape_html(u_char *dst, u_char *src, size_t size)
1459{
1460 u_char ch;
1461 ngx_uint_t i, len;
1462
1463 if (dst == NULL) {
1464
1465 len = 0;
1466
1467 for (i = 0; i < size; i++) {
1468 switch (*src++) {
1469
1470 case '<':
1471 len += sizeof("&lt;") - 2;
Igor Sysoevd3db9ea2007-10-09 18:42:00 +00001472 break;
Igor Sysoev1730c752007-09-27 09:36:50 +00001473
1474 case '>':
1475 len += sizeof("&gt;") - 2;
Igor Sysoevd3db9ea2007-10-09 18:42:00 +00001476 break;
Igor Sysoev1730c752007-09-27 09:36:50 +00001477
1478 case '&':
1479 len += sizeof("&amp;") - 2;
Igor Sysoevd3db9ea2007-10-09 18:42:00 +00001480 break;
Igor Sysoev1730c752007-09-27 09:36:50 +00001481
1482 default:
1483 break;
1484 }
1485 }
1486
1487 return (uintptr_t) len;
1488 }
1489
1490 for (i = 0; i < size; i++) {
1491 ch = *src++;
1492
1493 switch (ch) {
1494
1495 case '<':
1496 *dst++ = '&'; *dst++ = 'l'; *dst++ = 't'; *dst++ = ';';
1497 break;
1498
1499 case '>':
1500 *dst++ = '&'; *dst++ = 'g'; *dst++ = 't'; *dst++ = ';';
1501 break;
1502
1503 case '&':
1504 *dst++ = '&'; *dst++ = 'a'; *dst++ = 'm'; *dst++ = 'p';
1505 *dst++ = ';';
1506 break;
1507
1508 default:
1509 *dst++ = ch;
1510 break;
1511 }
1512 }
1513
1514 return (uintptr_t) dst;
1515}
1516
1517
Igor Sysoev35921282007-05-21 14:05:23 +00001518/* ngx_sort() is implemented as insertion sort because we need stable sort */
1519
1520void
1521ngx_sort(void *base, size_t n, size_t size,
Igor Sysoevde8ec1e2008-03-24 13:04:02 +00001522 ngx_int_t (*cmp)(const void *, const void *))
Igor Sysoev35921282007-05-21 14:05:23 +00001523{
Igor Sysoev86341182008-03-23 19:58:54 +00001524 u_char *p1, *p2, *p;
1525
1526 p = ngx_alloc(size, ngx_cycle->log);
1527 if (p == NULL) {
1528 return;
1529 }
Igor Sysoev35921282007-05-21 14:05:23 +00001530
1531 for (p1 = (u_char *) base + size;
1532 p1 < (u_char *) base + n * size;
1533 p1 += size)
1534 {
Igor Sysoev86341182008-03-23 19:58:54 +00001535 ngx_memcpy(p, p1, size);
Igor Sysoev35921282007-05-21 14:05:23 +00001536
1537 for (p2 = p1;
Igor Sysoev86341182008-03-23 19:58:54 +00001538 p2 > (u_char *) base && cmp(p2 - size, p) > 0;
Igor Sysoev35921282007-05-21 14:05:23 +00001539 p2 -= size)
1540 {
1541 ngx_memcpy(p2, p2 - size, size);
1542 }
1543
Igor Sysoev86341182008-03-23 19:58:54 +00001544 ngx_memcpy(p2, p, size);
Igor Sysoev35921282007-05-21 14:05:23 +00001545 }
Igor Sysoev86341182008-03-23 19:58:54 +00001546
1547 ngx_free(p);
Igor Sysoev35921282007-05-21 14:05:23 +00001548}
1549
1550
Igor Sysoevd3283ff2005-12-05 13:18:09 +00001551#if (NGX_MEMCPY_LIMIT)
1552
1553void *
1554ngx_memcpy(void *dst, void *src, size_t n)
1555{
1556 if (n > NGX_MEMCPY_LIMIT) {
1557 ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "memcpy %uz bytes", n);
1558 ngx_debug_point();
1559 }
1560
1561 return memcpy(dst, src, n);
1562}
1563
1564#endif