blob: 0e33e3804cade1ef43c57c23fd291e9cfe536be5 [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 Sysoev8e5f0ac2009-06-05 12:33:49 +000033 while (--n) {
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 Sysoev8e5f0ac2009-06-05 12:33:49 +000039
40 dst++;
41 src++;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000042 }
43
44 *dst = '\0';
45
46 return dst;
47}
Igor Sysoevdc479b42003-03-20 16:09:44 +000048
49
Igor Sysoevd039a2e2005-02-22 14:40:13 +000050u_char *
51ngx_pstrdup(ngx_pool_t *pool, ngx_str_t *src)
Igor Sysoev805d9db2005-02-03 19:33:37 +000052{
53 u_char *dst;
54
Igor Sysoev7f6b2ff2008-06-17 15:00:30 +000055 dst = ngx_pnalloc(pool, src->len);
Igor Sysoevc1571722005-03-19 12:38:37 +000056 if (dst == NULL) {
Igor Sysoev805d9db2005-02-03 19:33:37 +000057 return NULL;
58 }
59
60 ngx_memcpy(dst, src->data, src->len);
61
62 return dst;
63}
64
65
Igor Sysoevc0edbcc2004-10-21 15:34:38 +000066/*
67 * supported formats:
Igor Sysoev42b12b32004-12-02 18:40:46 +000068 * %[0][width][x][X]O off_t
Igor Sysoev1b735832004-11-11 14:07:14 +000069 * %[0][width]T time_t
70 * %[0][width][u][x|X]z ssize_t/size_t
71 * %[0][width][u][x|X]d int/u_int
72 * %[0][width][u][x|X]l long
73 * %[0][width|m][u][x|X]i ngx_int_t/ngx_uint_t
74 * %[0][width][u][x|X]D int32_t/uint32_t
75 * %[0][width][u][x|X]L int64_t/uint64_t
Igor Sysoev4a715592005-02-24 12:29:09 +000076 * %[0][width|m][u][x|X]A ngx_atomic_int_t/ngx_atomic_uint_t
Igor Sysoev74b7e5f2008-11-10 15:20:59 +000077 * %[0][width][.width]f float
Igor Sysoev1b735832004-11-11 14:07:14 +000078 * %P ngx_pid_t
Igor Sysoev208eed22005-10-07 13:30:52 +000079 * %M ngx_msec_t
Igor Sysoev1b735832004-11-11 14:07:14 +000080 * %r rlim_t
Igor Sysoev0d4b3722007-08-20 09:57:19 +000081 * %p void *
82 * %V ngx_str_t *
83 * %v ngx_variable_value_t *
Igor Sysoev1b735832004-11-11 14:07:14 +000084 * %s null-terminated string
Igor Sysoev79d9a042007-12-24 17:05:16 +000085 * %*s length and string
Igor Sysoev1b735832004-11-11 14:07:14 +000086 * %Z '\0'
Igor Sysoev85ef94b2005-06-23 13:41:06 +000087 * %N '\n'
Igor Sysoev1b735832004-11-11 14:07:14 +000088 * %c char
89 * %% %
Igor Sysoevc0edbcc2004-10-21 15:34:38 +000090 *
Igor Sysoev1b735832004-11-11 14:07:14 +000091 * reserved:
92 * %t ptrdiff_t
93 * %S null-teminated wchar string
94 * %C wchar
Igor Sysoevc0edbcc2004-10-21 15:34:38 +000095 */
96
Igor Sysoev1b735832004-11-11 14:07:14 +000097
Igor Sysoev4d656dc2005-03-22 16:02:46 +000098u_char * ngx_cdecl
Igor Sysoevd039a2e2005-02-22 14:40:13 +000099ngx_sprintf(u_char *buf, const char *fmt, ...)
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000100{
Igor Sysoev1b735832004-11-11 14:07:14 +0000101 u_char *p;
102 va_list args;
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000103
Igor Sysoev1b735832004-11-11 14:07:14 +0000104 va_start(args, fmt);
Igor Sysoev4e1fe032009-04-27 12:51:33 +0000105 p = ngx_vslprintf(buf, (void *) -1, fmt, args);
Igor Sysoev1b735832004-11-11 14:07:14 +0000106 va_end(args);
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000107
Igor Sysoev1b735832004-11-11 14:07:14 +0000108 return p;
109}
110
111
Igor Sysoev4d656dc2005-03-22 16:02:46 +0000112u_char * ngx_cdecl
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000113ngx_snprintf(u_char *buf, size_t max, const char *fmt, ...)
Igor Sysoev1b735832004-11-11 14:07:14 +0000114{
115 u_char *p;
116 va_list args;
117
118 va_start(args, fmt);
Igor Sysoev4e1fe032009-04-27 12:51:33 +0000119 p = ngx_vslprintf(buf, buf + max, fmt, args);
120 va_end(args);
121
122 return p;
123}
124
125
126u_char * ngx_cdecl
127ngx_slprintf(u_char *buf, u_char *last, const char *fmt, ...)
128{
129 u_char *p;
130 va_list args;
131
132 va_start(args, fmt);
133 p = ngx_vslprintf(buf, last, fmt, args);
Igor Sysoev1b735832004-11-11 14:07:14 +0000134 va_end(args);
135
136 return p;
137}
138
139
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000140u_char *
Igor Sysoev4e1fe032009-04-27 12:51:33 +0000141ngx_vslprintf(u_char *buf, u_char *last, const char *fmt, va_list args)
Igor Sysoev1b735832004-11-11 14:07:14 +0000142{
Igor Sysoev4e1fe032009-04-27 12:51:33 +0000143 u_char *p, zero;
Igor Sysoevf42ed052007-07-17 09:23:23 +0000144 int d;
Igor Sysoev74b7e5f2008-11-10 15:20:59 +0000145 float f, scale;
Igor Sysoev79d9a042007-12-24 17:05:16 +0000146 size_t len, slen;
Igor Sysoevf42ed052007-07-17 09:23:23 +0000147 int64_t i64;
148 uint64_t ui64;
149 ngx_msec_t ms;
Igor Sysoev74b7e5f2008-11-10 15:20:59 +0000150 ngx_uint_t width, sign, hex, max_width, frac_width, i;
Igor Sysoev0d4b3722007-08-20 09:57:19 +0000151 ngx_str_t *v;
152 ngx_variable_value_t *vv;
Igor Sysoev1b735832004-11-11 14:07:14 +0000153
Igor Sysoev1b735832004-11-11 14:07:14 +0000154 while (*fmt && buf < last) {
155
156 /*
157 * "buf < last" means that we could copy at least one character:
158 * the plain character, "%%", "%c", and minus without the checking
159 */
160
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000161 if (*fmt == '%') {
162
Igor Sysoev1b735832004-11-11 14:07:14 +0000163 i64 = 0;
164 ui64 = 0;
165
166 zero = (u_char) ((*++fmt == '0') ? '0' : ' ');
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000167 width = 0;
168 sign = 1;
Igor Sysoev74b7e5f2008-11-10 15:20:59 +0000169 hex = 0;
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000170 max_width = 0;
Igor Sysoev74b7e5f2008-11-10 15:20:59 +0000171 frac_width = 0;
Igor Sysoev0bd32b72008-01-22 15:13:01 +0000172 slen = (size_t) -1;
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000173
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000174 while (*fmt >= '0' && *fmt <= '9') {
175 width = width * 10 + *fmt++ - '0';
176 }
177
178
179 for ( ;; ) {
180 switch (*fmt) {
181
182 case 'u':
183 sign = 0;
184 fmt++;
185 continue;
186
Igor Sysoevd43bee82004-11-20 19:52:20 +0000187 case 'm':
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000188 max_width = 1;
Igor Sysoevd43bee82004-11-20 19:52:20 +0000189 fmt++;
190 continue;
191
Igor Sysoev1b735832004-11-11 14:07:14 +0000192 case 'X':
Igor Sysoev74b7e5f2008-11-10 15:20:59 +0000193 hex = 2;
Igor Sysoev1b735832004-11-11 14:07:14 +0000194 sign = 0;
195 fmt++;
196 continue;
197
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000198 case 'x':
Igor Sysoev74b7e5f2008-11-10 15:20:59 +0000199 hex = 1;
Igor Sysoev1b735832004-11-11 14:07:14 +0000200 sign = 0;
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000201 fmt++;
202 continue;
203
Igor Sysoev74b7e5f2008-11-10 15:20:59 +0000204 case '.':
205 fmt++;
206
207 while (*fmt >= '0' && *fmt <= '9') {
208 frac_width = frac_width * 10 + *fmt++ - '0';
209 }
210
211 break;
212
Igor Sysoev79d9a042007-12-24 17:05:16 +0000213 case '*':
Igor Sysoevfb424652008-01-24 15:18:17 +0000214 slen = va_arg(args, size_t);
Igor Sysoev79d9a042007-12-24 17:05:16 +0000215 fmt++;
216 continue;
217
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000218 default:
219 break;
220 }
221
222 break;
223 }
224
225
226 switch (*fmt) {
227
Igor Sysoev1b735832004-11-11 14:07:14 +0000228 case 'V':
Igor Sysoev0d4b3722007-08-20 09:57:19 +0000229 v = va_arg(args, ngx_str_t *);
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000230
Igor Sysoevf42ed052007-07-17 09:23:23 +0000231 len = v->len;
Igor Sysoev09c684b2005-11-09 17:25:55 +0000232 len = (buf + len < last) ? len : (size_t) (last - buf);
233
Igor Sysoevf42ed052007-07-17 09:23:23 +0000234 buf = ngx_cpymem(buf, v->data, len);
Igor Sysoev1b735832004-11-11 14:07:14 +0000235 fmt++;
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000236
Igor Sysoev1b735832004-11-11 14:07:14 +0000237 continue;
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000238
Igor Sysoev0d4b3722007-08-20 09:57:19 +0000239 case 'v':
240 vv = va_arg(args, ngx_variable_value_t *);
241
242 len = vv->len;
243 len = (buf + len < last) ? len : (size_t) (last - buf);
244
245 buf = ngx_cpymem(buf, vv->data, len);
246 fmt++;
247
248 continue;
249
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000250 case 's':
Igor Sysoev1b735832004-11-11 14:07:14 +0000251 p = va_arg(args, u_char *);
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000252
Igor Sysoev0bd32b72008-01-22 15:13:01 +0000253 if (slen == (size_t) -1) {
Igor Sysoev79d9a042007-12-24 17:05:16 +0000254 while (*p && buf < last) {
255 *buf++ = *p++;
256 }
257
258 } else {
Igor Sysoev16315762008-01-24 15:18:58 +0000259 len = (buf + slen < last) ? slen : (size_t) (last - buf);
260
261 buf = ngx_cpymem(buf, p, len);
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000262 }
Igor Sysoev79d9a042007-12-24 17:05:16 +0000263
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000264 fmt++;
265
266 continue;
267
Igor Sysoev1b735832004-11-11 14:07:14 +0000268 case 'O':
269 i64 = (int64_t) va_arg(args, off_t);
270 sign = 1;
271 break;
272
273 case 'P':
274 i64 = (int64_t) va_arg(args, ngx_pid_t);
275 sign = 1;
276 break;
277
278 case 'T':
279 i64 = (int64_t) va_arg(args, time_t);
280 sign = 1;
281 break;
282
Igor Sysoev208eed22005-10-07 13:30:52 +0000283 case 'M':
Igor Sysoev78452232005-10-12 13:50:36 +0000284 ms = (ngx_msec_t) va_arg(args, ngx_msec_t);
285 if ((ngx_msec_int_t) ms == -1) {
286 sign = 1;
287 i64 = -1;
288 } else {
289 sign = 0;
290 ui64 = (uint64_t) ms;
291 }
Igor Sysoev208eed22005-10-07 13:30:52 +0000292 break;
293
Igor Sysoev1b735832004-11-11 14:07:14 +0000294 case 'z':
295 if (sign) {
296 i64 = (int64_t) va_arg(args, ssize_t);
297 } else {
298 ui64 = (uint64_t) va_arg(args, size_t);
299 }
300 break;
301
302 case 'i':
303 if (sign) {
304 i64 = (int64_t) va_arg(args, ngx_int_t);
305 } else {
306 ui64 = (uint64_t) va_arg(args, ngx_uint_t);
307 }
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000308
309 if (max_width) {
310 width = NGX_INT_T_LEN;
311 }
312
Igor Sysoev1b735832004-11-11 14:07:14 +0000313 break;
314
315 case 'd':
316 if (sign) {
317 i64 = (int64_t) va_arg(args, int);
318 } else {
319 ui64 = (uint64_t) va_arg(args, u_int);
320 }
321 break;
322
323 case 'l':
324 if (sign) {
325 i64 = (int64_t) va_arg(args, long);
326 } else {
327 ui64 = (uint64_t) va_arg(args, u_long);
328 }
329 break;
330
331 case 'D':
332 if (sign) {
333 i64 = (int64_t) va_arg(args, int32_t);
334 } else {
335 ui64 = (uint64_t) va_arg(args, uint32_t);
336 }
337 break;
338
339 case 'L':
340 if (sign) {
341 i64 = va_arg(args, int64_t);
342 } else {
343 ui64 = va_arg(args, uint64_t);
344 }
345 break;
346
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000347 case 'A':
348 if (sign) {
349 i64 = (int64_t) va_arg(args, ngx_atomic_int_t);
350 } else {
Igor Sysoev4a715592005-02-24 12:29:09 +0000351 ui64 = (uint64_t) va_arg(args, ngx_atomic_uint_t);
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000352 }
353
354 if (max_width) {
355 width = NGX_ATOMIC_T_LEN;
356 }
357
358 break;
359
Igor Sysoev74b7e5f2008-11-10 15:20:59 +0000360 case 'f':
361 f = (float) va_arg(args, double);
362
363 if (f < 0) {
364 *buf++ = '-';
365 f = -f;
366 }
367
368 ui64 = (int64_t) f;
369
370 buf = ngx_sprintf_num(buf, last, ui64, zero, 0, width);
371
372 if (frac_width) {
373
374 if (buf < last) {
375 *buf++ = '.';
376 }
377
378 scale = 1.0;
379
380 for (i = 0; i < frac_width; i++) {
381 scale *= 10.0;
382 }
383
384 /*
385 * (int64_t) cast is required for msvc6:
386 * it can not convert uint64_t to double
387 */
388 ui64 = (uint64_t) ((f - (int64_t) ui64) * scale);
389
390 buf = ngx_sprintf_num(buf, last, ui64, '0', 0, frac_width);
391 }
392
393 fmt++;
394
395 continue;
396
Igor Sysoev1b735832004-11-11 14:07:14 +0000397#if !(NGX_WIN32)
398 case 'r':
399 i64 = (int64_t) va_arg(args, rlim_t);
400 sign = 1;
401 break;
402#endif
403
404 case 'p':
405 ui64 = (uintptr_t) va_arg(args, void *);
Igor Sysoev74b7e5f2008-11-10 15:20:59 +0000406 hex = 2;
Igor Sysoev1b735832004-11-11 14:07:14 +0000407 sign = 0;
408 zero = '0';
Igor Sysoevc2807ec2006-02-16 15:26:46 +0000409 width = NGX_PTR_SIZE * 2;
Igor Sysoev1b735832004-11-11 14:07:14 +0000410 break;
411
Igor Sysoev723e6cc2004-10-25 15:29:23 +0000412 case 'c':
Igor Sysoev1b735832004-11-11 14:07:14 +0000413 d = va_arg(args, int);
Igor Sysoev723e6cc2004-10-25 15:29:23 +0000414 *buf++ = (u_char) (d & 0xff);
415 fmt++;
416
417 continue;
418
Igor Sysoev1b735832004-11-11 14:07:14 +0000419 case 'Z':
420 *buf++ = '\0';
421 fmt++;
422
423 continue;
424
Igor Sysoev85ef94b2005-06-23 13:41:06 +0000425 case 'N':
426#if (NGX_WIN32)
427 *buf++ = CR;
428#endif
429 *buf++ = LF;
430 fmt++;
431
432 continue;
433
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000434 case '%':
435 *buf++ = '%';
436 fmt++;
437
438 continue;
439
440 default:
441 *buf++ = *fmt++;
442
443 continue;
444 }
445
Igor Sysoev1b735832004-11-11 14:07:14 +0000446 if (sign) {
447 if (i64 < 0) {
448 *buf++ = '-';
449 ui64 = (uint64_t) -i64;
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000450
Igor Sysoev1b735832004-11-11 14:07:14 +0000451 } else {
452 ui64 = (uint64_t) i64;
453 }
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000454 }
455
Igor Sysoev74b7e5f2008-11-10 15:20:59 +0000456 buf = ngx_sprintf_num(buf, last, ui64, zero, hex, width);
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000457
458 fmt++;
459
460 } else {
461 *buf++ = *fmt++;
462 }
463 }
464
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000465 return buf;
466}
467
468
Igor Sysoev74b7e5f2008-11-10 15:20:59 +0000469static u_char *
470ngx_sprintf_num(u_char *buf, u_char *last, uint64_t ui64, u_char zero,
471 ngx_uint_t hexadecimal, ngx_uint_t width)
472{
473 u_char *p, temp[NGX_INT64_LEN + 1];
474 /*
475 * we need temp[NGX_INT64_LEN] only,
476 * but icc issues the warning
477 */
478 size_t len;
479 uint32_t ui32;
480 static u_char hex[] = "0123456789abcdef";
481 static u_char HEX[] = "0123456789ABCDEF";
482
483 p = temp + NGX_INT64_LEN;
484
485 if (hexadecimal == 0) {
486
487 if (ui64 <= NGX_MAX_UINT32_VALUE) {
488
489 /*
490 * To divide 64-bit numbers and to find remainders
491 * on the x86 platform gcc and icc call the libc functions
492 * [u]divdi3() and [u]moddi3(), they call another function
493 * in its turn. On FreeBSD it is the qdivrem() function,
494 * its source code is about 170 lines of the code.
495 * The glibc counterpart is about 150 lines of the code.
496 *
497 * For 32-bit numbers and some divisors gcc and icc use
498 * a inlined multiplication and shifts. For example,
499 * unsigned "i32 / 10" is compiled to
500 *
501 * (i32 * 0xCCCCCCCD) >> 35
502 */
503
504 ui32 = (uint32_t) ui64;
505
506 do {
507 *--p = (u_char) (ui32 % 10 + '0');
508 } while (ui32 /= 10);
509
510 } else {
511 do {
512 *--p = (u_char) (ui64 % 10 + '0');
513 } while (ui64 /= 10);
514 }
515
516 } else if (hexadecimal == 1) {
517
518 do {
519
520 /* the "(uint32_t)" cast disables the BCC's warning */
521 *--p = hex[(uint32_t) (ui64 & 0xf)];
522
523 } while (ui64 >>= 4);
524
525 } else { /* hexadecimal == 2 */
526
527 do {
528
529 /* the "(uint32_t)" cast disables the BCC's warning */
530 *--p = HEX[(uint32_t) (ui64 & 0xf)];
531
532 } while (ui64 >>= 4);
533 }
534
535 /* zero or space padding */
536
537 len = (temp + NGX_INT64_LEN) - p;
538
539 while (len++ < width && buf < last) {
540 *buf++ = zero;
541 }
542
543 /* number safe copy */
544
545 len = (temp + NGX_INT64_LEN) - p;
546
547 if (buf + len > last) {
548 len = last - buf;
549 }
550
551 return ngx_cpymem(buf, p, len);
552}
553
554
Igor Sysoev722231f2007-02-14 18:51:19 +0000555/*
Igor Sysoev066e6322007-09-26 12:23:34 +0000556 * We use ngx_strcasecmp()/ngx_strncasecmp() for 7-bit ASCII strings only,
Igor Sysoev722231f2007-02-14 18:51:19 +0000557 * and implement our own ngx_strcasecmp()/ngx_strncasecmp()
558 * to avoid libc locale overhead. Besides, we use the ngx_uint_t's
559 * instead of the u_char's, because they are slightly faster.
560 */
561
562ngx_int_t
563ngx_strcasecmp(u_char *s1, u_char *s2)
564{
565 ngx_uint_t c1, c2;
566
567 for ( ;; ) {
568 c1 = (ngx_uint_t) *s1++;
569 c2 = (ngx_uint_t) *s2++;
570
571 c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;
572 c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;
573
574 if (c1 == c2) {
575
576 if (c1) {
577 continue;
578 }
579
580 return 0;
581 }
582
583 return c1 - c2;
584 }
585}
586
587
588ngx_int_t
589ngx_strncasecmp(u_char *s1, u_char *s2, size_t n)
590{
591 ngx_uint_t c1, c2;
592
593 while (n) {
594 c1 = (ngx_uint_t) *s1++;
595 c2 = (ngx_uint_t) *s2++;
596
597 c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;
598 c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;
599
600 if (c1 == c2) {
601
602 if (c1) {
603 n--;
604 continue;
605 }
606
607 return 0;
608 }
609
610 return c1 - c2;
611 }
612
613 return 0;
614}
615
616
Igor Sysoev35fe5fd2007-10-01 14:48:33 +0000617u_char *
618ngx_strnstr(u_char *s1, char *s2, size_t len)
619{
620 u_char c1, c2;
621 size_t n;
622
623 c2 = *(u_char *) s2++;
624
625 n = ngx_strlen(s2);
626
627 do {
628 do {
629 if (len-- == 0) {
630 return NULL;
631 }
632
633 c1 = *s1++;
634
635 if (c1 == 0) {
636 return NULL;
637 }
638
639 } while (c1 != c2);
640
641 if (n > len) {
642 return NULL;
643 }
644
645 } while (ngx_strncmp(s1, (u_char *) s2, n) != 0);
646
647 return --s1;
648}
649
650
Igor Sysoev66697022007-10-01 13:00:30 +0000651/*
652 * ngx_strstrn() and ngx_strcasestrn() are intended to search for static
653 * substring with known length in null-terminated string. The argument n
654 * must be length of the second substring - 1.
655 */
656
Igor Sysoev1bd98702007-09-26 19:25:52 +0000657u_char *
658ngx_strstrn(u_char *s1, char *s2, size_t n)
659{
660 u_char c1, c2;
661
662 c2 = *(u_char *) s2++;
663
664 do {
665 do {
666 c1 = *s1++;
667
668 if (c1 == 0) {
669 return NULL;
670 }
671
672 } while (c1 != c2);
673
674 } while (ngx_strncmp(s1, (u_char *) s2, n) != 0);
675
676 return --s1;
677}
678
679
680u_char *
681ngx_strcasestrn(u_char *s1, char *s2, size_t n)
682{
683 ngx_uint_t c1, c2;
684
685 c2 = (ngx_uint_t) *s2++;
686 c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;
687
688 do {
689 do {
690 c1 = (ngx_uint_t) *s1++;
691
692 if (c1 == 0) {
693 return NULL;
694 }
695
696 c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;
697
698 } while (c1 != c2);
699
700 } while (ngx_strncasecmp(s1, (u_char *) s2, n) != 0);
701
702 return --s1;
703}
704
705
Igor Sysoeva514d682009-04-04 17:31:54 +0000706/*
707 * ngx_strlcasestrn() is intended to search for static substring
708 * with known length in string until the argument last. The argument n
709 * must be length of the second substring - 1.
710 */
711
712u_char *
713ngx_strlcasestrn(u_char *s1, u_char *last, u_char *s2, size_t n)
714{
715 ngx_uint_t c1, c2;
716
717 c2 = (ngx_uint_t) *s2++;
718 c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;
719 last -= n;
720
721 do {
722 do {
Igor Sysoevd5ba36f2009-04-06 11:42:42 +0000723 if (s1 >= last) {
Igor Sysoeva514d682009-04-04 17:31:54 +0000724 return NULL;
725 }
726
727 c1 = (ngx_uint_t) *s1++;
728
729 c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;
730
731 } while (c1 != c2);
732
733 } while (ngx_strncasecmp(s1, s2, n) != 0);
734
735 return --s1;
736}
737
738
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000739ngx_int_t
740ngx_rstrncmp(u_char *s1, u_char *s2, size_t n)
Igor Sysoev3d09c8d2003-05-06 17:03:16 +0000741{
742 if (n == 0) {
743 return 0;
744 }
745
746 n--;
747
748 for ( ;; ) {
749 if (s1[n] != s2[n]) {
Igor Sysoev10a543a2004-03-16 07:10:12 +0000750 return s1[n] - s2[n];
Igor Sysoev3d09c8d2003-05-06 17:03:16 +0000751 }
752
753 if (n == 0) {
754 return 0;
755 }
756
757 n--;
758 }
759}
760
761
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000762ngx_int_t
763ngx_rstrncasecmp(u_char *s1, u_char *s2, size_t n)
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000764{
765 u_char c1, c2;
766
767 if (n == 0) {
768 return 0;
769 }
770
771 n--;
772
773 for ( ;; ) {
774 c1 = s1[n];
775 if (c1 >= 'a' && c1 <= 'z') {
776 c1 -= 'a' - 'A';
777 }
778
779 c2 = s2[n];
780 if (c2 >= 'a' && c2 <= 'z') {
781 c2 -= 'a' - 'A';
782 }
783
784 if (c1 != c2) {
785 return c1 - c2;
786 }
787
788 if (n == 0) {
789 return 0;
790 }
791
792 n--;
793 }
794}
795
796
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000797ngx_int_t
Igor Sysoevec3cabd2007-01-12 21:58:02 +0000798ngx_memn2cmp(u_char *s1, u_char *s2, size_t n1, size_t n2)
Igor Sysoev37cc1652007-01-12 20:15:59 +0000799{
800 size_t n;
801 ngx_int_t m, z;
802
803 if (n1 <= n2) {
804 n = n1;
805 z = -1;
806
807 } else {
808 n = n2;
809 z = 1;
810 }
811
Igor Sysoevec3cabd2007-01-12 21:58:02 +0000812 m = ngx_memcmp(s1, s2, n);
Igor Sysoev37cc1652007-01-12 20:15:59 +0000813
814 if (m || n1 == n2) {
815 return m;
816 }
817
818 return z;
819}
820
821
822ngx_int_t
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000823ngx_atoi(u_char *line, size_t n)
Igor Sysoevdc479b42003-03-20 16:09:44 +0000824{
Igor Sysoev10a543a2004-03-16 07:10:12 +0000825 ngx_int_t value;
Igor Sysoevdc479b42003-03-20 16:09:44 +0000826
Igor Sysoev3d09c8d2003-05-06 17:03:16 +0000827 if (n == 0) {
828 return NGX_ERROR;
829 }
830
Igor Sysoevdc479b42003-03-20 16:09:44 +0000831 for (value = 0; n--; line++) {
Igor Sysoev1d8d9ee2003-04-28 15:06:39 +0000832 if (*line < '0' || *line > '9') {
833 return NGX_ERROR;
834 }
Igor Sysoevdc479b42003-03-20 16:09:44 +0000835
Igor Sysoev1d8d9ee2003-04-28 15:06:39 +0000836 value = value * 10 + (*line - '0');
Igor Sysoevdc479b42003-03-20 16:09:44 +0000837 }
838
Igor Sysoev1d8d9ee2003-04-28 15:06:39 +0000839 if (value < 0) {
840 return NGX_ERROR;
Igor Sysoev18684bd2004-05-20 17:33:52 +0000841
842 } else {
843 return value;
844 }
845}
846
847
Igor Sysoevc1571722005-03-19 12:38:37 +0000848ssize_t
849ngx_atosz(u_char *line, size_t n)
850{
851 ssize_t value;
852
853 if (n == 0) {
854 return NGX_ERROR;
855 }
856
857 for (value = 0; n--; line++) {
858 if (*line < '0' || *line > '9') {
859 return NGX_ERROR;
860 }
861
862 value = value * 10 + (*line - '0');
863 }
864
865 if (value < 0) {
866 return NGX_ERROR;
867
868 } else {
869 return value;
870 }
871}
872
873
874off_t
875ngx_atoof(u_char *line, size_t n)
876{
877 off_t value;
878
879 if (n == 0) {
880 return NGX_ERROR;
881 }
882
883 for (value = 0; n--; line++) {
884 if (*line < '0' || *line > '9') {
885 return NGX_ERROR;
886 }
887
888 value = value * 10 + (*line - '0');
889 }
890
891 if (value < 0) {
892 return NGX_ERROR;
893
894 } else {
895 return value;
896 }
897}
898
899
900time_t
901ngx_atotm(u_char *line, size_t n)
902{
903 time_t value;
904
905 if (n == 0) {
906 return NGX_ERROR;
907 }
908
909 for (value = 0; n--; line++) {
910 if (*line < '0' || *line > '9') {
911 return NGX_ERROR;
912 }
913
914 value = value * 10 + (*line - '0');
915 }
916
917 if (value < 0) {
918 return NGX_ERROR;
919
920 } else {
921 return value;
922 }
923}
924
925
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000926ngx_int_t
927ngx_hextoi(u_char *line, size_t n)
Igor Sysoev18684bd2004-05-20 17:33:52 +0000928{
Igor Sysoev066496a2006-10-16 12:21:17 +0000929 u_char c, ch;
Igor Sysoev18684bd2004-05-20 17:33:52 +0000930 ngx_int_t value;
931
932 if (n == 0) {
933 return NGX_ERROR;
934 }
935
936 for (value = 0; n--; line++) {
937 ch = *line;
938
939 if (ch >= '0' && ch <= '9') {
940 value = value * 16 + (ch - '0');
941 continue;
942 }
943
Igor Sysoev066496a2006-10-16 12:21:17 +0000944 c = (u_char) (ch | 0x20);
Igor Sysoev18684bd2004-05-20 17:33:52 +0000945
Igor Sysoev066496a2006-10-16 12:21:17 +0000946 if (c >= 'a' && c <= 'f') {
947 value = value * 16 + (c - 'a' + 10);
Igor Sysoev18684bd2004-05-20 17:33:52 +0000948 continue;
949 }
950
951 return NGX_ERROR;
952 }
953
954 if (value < 0) {
955 return NGX_ERROR;
956
Igor Sysoev1d8d9ee2003-04-28 15:06:39 +0000957 } else {
958 return value;
959 }
Igor Sysoevdc479b42003-03-20 16:09:44 +0000960}
961
962
Igor Sysoeva03fa362007-12-17 21:06:17 +0000963u_char *
964ngx_hex_dump(u_char *dst, u_char *src, size_t len)
Igor Sysoev9cc1ace2003-11-04 22:12:39 +0000965{
Igor Sysoev10a543a2004-03-16 07:10:12 +0000966 static u_char hex[] = "0123456789abcdef";
Igor Sysoeve8732b02003-11-05 17:03:41 +0000967
Igor Sysoeva03fa362007-12-17 21:06:17 +0000968 while (len--) {
969 *dst++ = hex[*src >> 4];
970 *dst++ = hex[*src++ & 0xf];
Igor Sysoev74e95c22003-11-09 20:03:38 +0000971 }
972
Igor Sysoeva03fa362007-12-17 21:06:17 +0000973 return dst;
Igor Sysoev9cc1ace2003-11-04 22:12:39 +0000974}
975
976
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000977void
978ngx_encode_base64(ngx_str_t *dst, ngx_str_t *src)
Igor Sysoev6deb0412004-07-30 17:05:14 +0000979{
980 u_char *d, *s;
Igor Sysoev967fd632004-08-27 15:40:59 +0000981 size_t len;
Igor Sysoev6deb0412004-07-30 17:05:14 +0000982 static u_char basis64[] =
983 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
984
Igor Sysoev967fd632004-08-27 15:40:59 +0000985 len = src->len;
Igor Sysoeva7c4a2a2004-08-29 03:55:41 +0000986 s = src->data;
987 d = dst->data;
Igor Sysoev6deb0412004-07-30 17:05:14 +0000988
Igor Sysoev967fd632004-08-27 15:40:59 +0000989 while (len > 2) {
990 *d++ = basis64[(s[0] >> 2) & 0x3f];
991 *d++ = basis64[((s[0] & 3) << 4) | (s[1] >> 4)];
992 *d++ = basis64[((s[1] & 0x0f) << 2) | (s[2] >> 6)];
993 *d++ = basis64[s[2] & 0x3f];
994
995 s += 3;
996 len -= 3;
Igor Sysoev6deb0412004-07-30 17:05:14 +0000997 }
998
Igor Sysoev967fd632004-08-27 15:40:59 +0000999 if (len) {
1000 *d++ = basis64[(s[0] >> 2) & 0x3f];
Igor Sysoev6deb0412004-07-30 17:05:14 +00001001
Igor Sysoev967fd632004-08-27 15:40:59 +00001002 if (len == 1) {
1003 *d++ = basis64[(s[0] & 3) << 4];
Igor Sysoev6deb0412004-07-30 17:05:14 +00001004 *d++ = '=';
1005
1006 } else {
Igor Sysoev967fd632004-08-27 15:40:59 +00001007 *d++ = basis64[((s[0] & 3) << 4) | (s[1] >> 4)];
1008 *d++ = basis64[(s[1] & 0x0f) << 2];
Igor Sysoev6deb0412004-07-30 17:05:14 +00001009 }
1010
1011 *d++ = '=';
1012 }
1013
1014 dst->len = d - dst->data;
Igor Sysoev6deb0412004-07-30 17:05:14 +00001015}
1016
1017
Igor Sysoevd039a2e2005-02-22 14:40:13 +00001018ngx_int_t
1019ngx_decode_base64(ngx_str_t *dst, ngx_str_t *src)
Igor Sysoev6deb0412004-07-30 17:05:14 +00001020{
Igor Sysoev967fd632004-08-27 15:40:59 +00001021 size_t len;
1022 u_char *d, *s;
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001023 static u_char basis64[] = {
1024 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
1025 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
1026 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 62, 77, 77, 77, 63,
1027 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 77, 77, 77, 77, 77, 77,
1028 77, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
1029 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 77, 77, 77, 77, 77,
1030 77, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
1031 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 77, 77, 77, 77, 77,
Igor Sysoev6deb0412004-07-30 17:05:14 +00001032
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001033 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
1034 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
1035 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
1036 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
1037 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
1038 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
1039 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
1040 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77
1041 };
Igor Sysoev967fd632004-08-27 15:40:59 +00001042
1043 for (len = 0; len < src->len; len++) {
1044 if (src->data[len] == '=') {
1045 break;
1046 }
1047
1048 if (basis64[src->data[len]] == 77) {
1049 return NGX_ERROR;
1050 }
1051 }
1052
1053 if (len % 4 == 1) {
1054 return NGX_ERROR;
1055 }
1056
Igor Sysoev6deb0412004-07-30 17:05:14 +00001057 s = src->data;
Igor Sysoeva7c4a2a2004-08-29 03:55:41 +00001058 d = dst->data;
Igor Sysoev6deb0412004-07-30 17:05:14 +00001059
Igor Sysoev967fd632004-08-27 15:40:59 +00001060 while (len > 3) {
Igor Sysoeva7c4a2a2004-08-29 03:55:41 +00001061 *d++ = (u_char) (basis64[s[0]] << 2 | basis64[s[1]] >> 4);
1062 *d++ = (u_char) (basis64[s[1]] << 4 | basis64[s[2]] >> 2);
1063 *d++ = (u_char) (basis64[s[2]] << 6 | basis64[s[3]]);
Igor Sysoev6deb0412004-07-30 17:05:14 +00001064
Igor Sysoev967fd632004-08-27 15:40:59 +00001065 s += 4;
1066 len -= 4;
Igor Sysoev6deb0412004-07-30 17:05:14 +00001067 }
1068
Igor Sysoev967fd632004-08-27 15:40:59 +00001069 if (len > 1) {
Igor Sysoeva7c4a2a2004-08-29 03:55:41 +00001070 *d++ = (u_char) (basis64[s[0]] << 2 | basis64[s[1]] >> 4);
Igor Sysoev967fd632004-08-27 15:40:59 +00001071 }
1072
1073 if (len > 2) {
Igor Sysoeva7c4a2a2004-08-29 03:55:41 +00001074 *d++ = (u_char) (basis64[s[1]] << 4 | basis64[s[2]] >> 2);
Igor Sysoev967fd632004-08-27 15:40:59 +00001075 }
1076
1077 dst->len = d - dst->data;
Igor Sysoev967fd632004-08-27 15:40:59 +00001078
Igor Sysoev6deb0412004-07-30 17:05:14 +00001079 return NGX_OK;
1080}
1081
1082
Igor Sysoevef809b82006-06-28 16:00:26 +00001083/*
Igor Sysoeva0898572008-07-29 14:41:34 +00001084 * ngx_utf8_decode() decodes two and more bytes UTF sequences only
Igor Sysoevef809b82006-06-28 16:00:26 +00001085 * the return values:
1086 * 0x80 - 0x10ffff valid character
Igor Sysoev96eaa052008-07-25 14:29:05 +00001087 * 0x110000 - 0xfffffffd invalid sequence
Igor Sysoevef809b82006-06-28 16:00:26 +00001088 * 0xfffffffe incomplete sequence
1089 * 0xffffffff error
1090 */
1091
1092uint32_t
Igor Sysoeva0898572008-07-29 14:41:34 +00001093ngx_utf8_decode(u_char **p, size_t n)
Igor Sysoevef809b82006-06-28 16:00:26 +00001094{
1095 size_t len;
1096 uint32_t u, i, valid;
1097
1098 u = **p;
1099
1100 if (u > 0xf0) {
1101
1102 u &= 0x07;
1103 valid = 0xffff;
1104 len = 3;
1105
1106 } else if (u > 0xe0) {
1107
1108 u &= 0x0f;
1109 valid = 0x7ff;
1110 len = 2;
1111
1112 } else if (u > 0xc0) {
1113
1114 u &= 0x1f;
1115 valid = 0x7f;
1116 len = 1;
1117
1118 } else {
1119 (*p)++;
1120 return 0xffffffff;
1121 }
1122
1123 if (n - 1 < len) {
1124 return 0xfffffffe;
1125 }
1126
1127 (*p)++;
1128
1129 while (len) {
1130 i = *(*p)++;
1131
1132 if (i < 0x80) {
1133 return 0xffffffff;
1134 }
1135
1136 u = (u << 6) | (i & 0x3f);
1137
1138 len--;
1139 }
1140
1141 if (u > valid) {
1142 return u;
1143 }
1144
1145 return 0xffffffff;
1146}
1147
1148
Igor Sysoevb145b062005-06-15 18:33:41 +00001149size_t
Igor Sysoeva0898572008-07-29 14:41:34 +00001150ngx_utf8_length(u_char *p, size_t n)
Igor Sysoevb145b062005-06-15 18:33:41 +00001151{
Igor Sysoev96eaa052008-07-25 14:29:05 +00001152 u_char c, *last;
1153 size_t len;
Igor Sysoevb145b062005-06-15 18:33:41 +00001154
Igor Sysoev96eaa052008-07-25 14:29:05 +00001155 last = p + n;
Igor Sysoevb145b062005-06-15 18:33:41 +00001156
Igor Sysoev96eaa052008-07-25 14:29:05 +00001157 for (len = 0; p < last; len++) {
1158
1159 c = *p;
Igor Sysoevb145b062005-06-15 18:33:41 +00001160
1161 if (c < 0x80) {
Igor Sysoev96eaa052008-07-25 14:29:05 +00001162 p++;
Igor Sysoevb145b062005-06-15 18:33:41 +00001163 continue;
1164 }
1165
Igor Sysoeva0898572008-07-29 14:41:34 +00001166 if (ngx_utf8_decode(&p, n) > 0x10ffff) {
1167 /* invalid UTF-8 */
Igor Sysoev96eaa052008-07-25 14:29:05 +00001168 return n;
Igor Sysoevb145b062005-06-15 18:33:41 +00001169 }
Igor Sysoevb145b062005-06-15 18:33:41 +00001170 }
1171
1172 return len;
1173}
1174
1175
Igor Sysoev5192b362005-07-08 14:34:20 +00001176u_char *
Igor Sysoeva0898572008-07-29 14:41:34 +00001177ngx_utf8_cpystrn(u_char *dst, u_char *src, size_t n, size_t len)
Igor Sysoev5192b362005-07-08 14:34:20 +00001178{
Igor Sysoev96eaa052008-07-25 14:29:05 +00001179 u_char c, *next;
Igor Sysoev5192b362005-07-08 14:34:20 +00001180
1181 if (n == 0) {
1182 return dst;
1183 }
1184
Igor Sysoev96eaa052008-07-25 14:29:05 +00001185 while (--n) {
Igor Sysoev5192b362005-07-08 14:34:20 +00001186
1187 c = *src;
1188 *dst = c;
1189
1190 if (c < 0x80) {
Igor Sysoev96eaa052008-07-25 14:29:05 +00001191
1192 if (c != '\0') {
1193 dst++;
1194 src++;
1195 len--;
1196
Igor Sysoev5192b362005-07-08 14:34:20 +00001197 continue;
1198 }
1199
1200 return dst;
1201 }
1202
Igor Sysoev96eaa052008-07-25 14:29:05 +00001203 next = src;
Igor Sysoev5192b362005-07-08 14:34:20 +00001204
Igor Sysoeva0898572008-07-29 14:41:34 +00001205 if (ngx_utf8_decode(&next, len) > 0x10ffff) {
1206 /* invalid UTF-8 */
Igor Sysoev96eaa052008-07-25 14:29:05 +00001207 break;
Igor Sysoev5192b362005-07-08 14:34:20 +00001208 }
1209
Igor Sysoev96eaa052008-07-25 14:29:05 +00001210 len--;
1211
1212 while (src < next) {
1213 *++dst = *++src;
1214 len--;
1215 }
Igor Sysoev5192b362005-07-08 14:34:20 +00001216 }
1217
1218 *dst = '\0';
1219
1220 return dst;
1221}
1222
1223
Igor Sysoevd039a2e2005-02-22 14:40:13 +00001224uintptr_t
1225ngx_escape_uri(u_char *dst, u_char *src, size_t size, ngx_uint_t type)
Igor Sysoevdc479b42003-03-20 16:09:44 +00001226{
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001227 ngx_uint_t i, n;
1228 uint32_t *escape;
1229 static u_char hex[] = "0123456789abcdef";
Igor Sysoev1b735832004-11-11 14:07:14 +00001230
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001231 /* " ", "#", "%", "?", %00-%1F, %7F-%FF */
Igor Sysoev805d9db2005-02-03 19:33:37 +00001232
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001233 static uint32_t uri[] = {
1234 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
Igor Sysoevdc479b42003-03-20 16:09:44 +00001235
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001236 /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
1237 0x80000029, /* 1000 0000 0000 0000 0000 0000 0010 1001 */
Igor Sysoevdc479b42003-03-20 16:09:44 +00001238
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001239 /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
1240 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
Igor Sysoevdc479b42003-03-20 16:09:44 +00001241
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001242 /* ~}| {zyx wvut srqp onml kjih gfed cba` */
1243 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */
Igor Sysoev924bd792004-10-11 15:07:03 +00001244
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001245 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1246 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1247 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1248 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1249 };
Igor Sysoev924bd792004-10-11 15:07:03 +00001250
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001251 /* " ", "#", "%", "+", "?", %00-%1F, %7F-%FF */
Igor Sysoev805d9db2005-02-03 19:33:37 +00001252
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001253 static uint32_t args[] = {
1254 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
Igor Sysoev805d9db2005-02-03 19:33:37 +00001255
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001256 /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
1257 0x80000829, /* 1000 0000 0000 0000 0000 1000 0010 1001 */
Igor Sysoev805d9db2005-02-03 19:33:37 +00001258
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001259 /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
1260 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
Igor Sysoev805d9db2005-02-03 19:33:37 +00001261
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001262 /* ~}| {zyx wvut srqp onml kjih gfed cba` */
1263 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */
Igor Sysoev805d9db2005-02-03 19:33:37 +00001264
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001265 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1266 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1267 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1268 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1269 };
Igor Sysoev805d9db2005-02-03 19:33:37 +00001270
Igor Sysoevd4ff5612007-08-20 09:50:53 +00001271 /* " ", "#", """, "%", "'", %00-%1F, %7F-%FF */
Igor Sysoev805d9db2005-02-03 19:33:37 +00001272
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001273 static uint32_t html[] = {
1274 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
Igor Sysoev1b735832004-11-11 14:07:14 +00001275
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001276 /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
Igor Sysoev049ae002007-07-13 09:35:51 +00001277 0x000000ad, /* 0000 0000 0000 0000 0000 0000 1010 1101 */
Igor Sysoev1b735832004-11-11 14:07:14 +00001278
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001279 /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
1280 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
Igor Sysoev1b735832004-11-11 14:07:14 +00001281
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001282 /* ~}| {zyx wvut srqp onml kjih gfed cba` */
1283 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */
Igor Sysoev1b735832004-11-11 14:07:14 +00001284
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001285 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1286 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1287 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1288 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1289 };
Igor Sysoev1b735832004-11-11 14:07:14 +00001290
Igor Sysoevd4ff5612007-08-20 09:50:53 +00001291 /* " ", """, "%", "'", %00-%1F, %7F-%FF */
Igor Sysoev1b735832004-11-11 14:07:14 +00001292
Igor Sysoev8662b6b2007-07-13 09:37:01 +00001293 static uint32_t refresh[] = {
1294 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1295
1296 /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
Igor Sysoevcc5484f2007-11-09 13:17:58 +00001297 0x00000085, /* 0000 0000 0000 0000 0000 0000 1000 0101 */
Igor Sysoev8662b6b2007-07-13 09:37:01 +00001298
1299 /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
1300 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1301
1302 /* ~}| {zyx wvut srqp onml kjih gfed cba` */
1303 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */
1304
1305 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1306 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1307 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1308 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1309 };
1310
Igor Sysoevd4ff5612007-08-20 09:50:53 +00001311 /* " ", "%", %00-%1F */
Igor Sysoev3f707822007-07-22 19:18:59 +00001312
1313 static uint32_t memcached[] = {
1314 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1315
1316 /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
Igor Sysoevd4ff5612007-08-20 09:50:53 +00001317 0x00000021, /* 0000 0000 0000 0000 0000 0000 0010 0001 */
Igor Sysoev3f707822007-07-22 19:18:59 +00001318
1319 /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
1320 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1321
1322 /* ~}| {zyx wvut srqp onml kjih gfed cba` */
1323 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1324
1325 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1326 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1327 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1328 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1329 };
1330
Igor Sysoevd4ff5612007-08-20 09:50:53 +00001331 /* mail_auth is the same as memcached */
1332
1333 static uint32_t *map[] =
1334 { uri, args, html, refresh, memcached, memcached };
Igor Sysoev8662b6b2007-07-13 09:37:01 +00001335
1336
1337 escape = map[type];
Igor Sysoev1b735832004-11-11 14:07:14 +00001338
Igor Sysoev924bd792004-10-11 15:07:03 +00001339 if (dst == NULL) {
1340
1341 /* find the number of the characters to be escaped */
1342
1343 n = 0;
1344
1345 for (i = 0; i < size; i++) {
1346 if (escape[*src >> 5] & (1 << (*src & 0x1f))) {
1347 n++;
1348 }
1349 src++;
1350 }
1351
Igor Sysoev805d9db2005-02-03 19:33:37 +00001352 return (uintptr_t) n;
Igor Sysoevdc479b42003-03-20 16:09:44 +00001353 }
1354
Igor Sysoev924bd792004-10-11 15:07:03 +00001355 for (i = 0; i < size; i++) {
1356 if (escape[*src >> 5] & (1 << (*src & 0x1f))) {
1357 *dst++ = '%';
1358 *dst++ = hex[*src >> 4];
1359 *dst++ = hex[*src & 0xf];
1360 src++;
Igor Sysoevdc479b42003-03-20 16:09:44 +00001361
Igor Sysoev924bd792004-10-11 15:07:03 +00001362 } else {
1363 *dst++ = *src++;
1364 }
Igor Sysoevdc479b42003-03-20 16:09:44 +00001365 }
1366
Igor Sysoev805d9db2005-02-03 19:33:37 +00001367 return (uintptr_t) dst;
Igor Sysoevdc479b42003-03-20 16:09:44 +00001368}
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +00001369
1370
1371void
Igor Sysoevae33d012006-01-17 20:04:32 +00001372ngx_unescape_uri(u_char **dst, u_char **src, size_t size, ngx_uint_t type)
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +00001373{
1374 u_char *d, *s, ch, c, decoded;
1375 enum {
1376 sw_usual = 0,
1377 sw_quoted,
1378 sw_quoted_second
1379 } state;
1380
1381 d = *dst;
1382 s = *src;
1383
1384 state = 0;
1385 decoded = 0;
1386
1387 while (size--) {
1388
1389 ch = *s++;
1390
1391 switch (state) {
1392 case sw_usual:
Igor Sysoevf0a51cf2007-10-22 10:19:17 +00001393 if (ch == '?'
1394 && (type & (NGX_UNESCAPE_URI|NGX_UNESCAPE_REDIRECT)))
1395 {
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +00001396 *d++ = ch;
1397 goto done;
1398 }
1399
1400 if (ch == '%') {
1401 state = sw_quoted;
1402 break;
1403 }
1404
1405 *d++ = ch;
1406 break;
1407
1408 case sw_quoted:
1409
1410 if (ch >= '0' && ch <= '9') {
1411 decoded = (u_char) (ch - '0');
1412 state = sw_quoted_second;
1413 break;
1414 }
1415
1416 c = (u_char) (ch | 0x20);
1417 if (c >= 'a' && c <= 'f') {
1418 decoded = (u_char) (c - 'a' + 10);
1419 state = sw_quoted_second;
1420 break;
1421 }
1422
Igor Sysoev24025022005-12-16 15:07:08 +00001423 /* the invalid quoted character */
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +00001424
Igor Sysoev24025022005-12-16 15:07:08 +00001425 state = sw_usual;
1426
1427 *d++ = ch;
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +00001428
1429 break;
1430
1431 case sw_quoted_second:
1432
Igor Sysoev24025022005-12-16 15:07:08 +00001433 state = sw_usual;
1434
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +00001435 if (ch >= '0' && ch <= '9') {
1436 ch = (u_char) ((decoded << 4) + ch - '0');
1437
Igor Sysoevf0a51cf2007-10-22 10:19:17 +00001438 if (type & NGX_UNESCAPE_REDIRECT) {
Igor Sysoevae33d012006-01-17 20:04:32 +00001439 if (ch > '%' && ch < 0x7f) {
1440 *d++ = ch;
1441 break;
1442 }
1443
1444 *d++ = '%'; *d++ = *(s - 2); *d++ = *(s - 1);
1445
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +00001446 break;
1447 }
1448
Igor Sysoevae33d012006-01-17 20:04:32 +00001449 *d++ = ch;
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +00001450
1451 break;
1452 }
1453
1454 c = (u_char) (ch | 0x20);
1455 if (c >= 'a' && c <= 'f') {
1456 ch = (u_char) ((decoded << 4) + c - 'a' + 10);
1457
Igor Sysoevf0a51cf2007-10-22 10:19:17 +00001458 if (type & NGX_UNESCAPE_URI) {
1459 if (ch == '?') {
1460 *d++ = ch;
1461 goto done;
1462 }
1463
1464 *d++ = ch;
1465 break;
1466 }
1467
1468 if (type & NGX_UNESCAPE_REDIRECT) {
Igor Sysoevae33d012006-01-17 20:04:32 +00001469 if (ch == '?') {
1470 *d++ = ch;
1471 goto done;
1472 }
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +00001473
Igor Sysoevae33d012006-01-17 20:04:32 +00001474 if (ch > '%' && ch < 0x7f) {
1475 *d++ = ch;
1476 break;
1477 }
1478
1479 *d++ = '%'; *d++ = *(s - 2); *d++ = *(s - 1);
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +00001480 break;
1481 }
1482
Igor Sysoevae33d012006-01-17 20:04:32 +00001483 *d++ = ch;
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +00001484
1485 break;
1486 }
1487
Igor Sysoev24025022005-12-16 15:07:08 +00001488 /* the invalid quoted character */
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +00001489
1490 break;
1491 }
1492 }
1493
1494done:
1495
1496 *dst = d;
1497 *src = s;
1498}
Igor Sysoevd3283ff2005-12-05 13:18:09 +00001499
1500
Igor Sysoev1730c752007-09-27 09:36:50 +00001501uintptr_t
1502ngx_escape_html(u_char *dst, u_char *src, size_t size)
1503{
1504 u_char ch;
1505 ngx_uint_t i, len;
1506
1507 if (dst == NULL) {
1508
1509 len = 0;
1510
1511 for (i = 0; i < size; i++) {
1512 switch (*src++) {
1513
1514 case '<':
1515 len += sizeof("&lt;") - 2;
Igor Sysoevd3db9ea2007-10-09 18:42:00 +00001516 break;
Igor Sysoev1730c752007-09-27 09:36:50 +00001517
1518 case '>':
1519 len += sizeof("&gt;") - 2;
Igor Sysoevd3db9ea2007-10-09 18:42:00 +00001520 break;
Igor Sysoev1730c752007-09-27 09:36:50 +00001521
1522 case '&':
1523 len += sizeof("&amp;") - 2;
Igor Sysoevd3db9ea2007-10-09 18:42:00 +00001524 break;
Igor Sysoev1730c752007-09-27 09:36:50 +00001525
1526 default:
1527 break;
1528 }
1529 }
1530
1531 return (uintptr_t) len;
1532 }
1533
1534 for (i = 0; i < size; i++) {
1535 ch = *src++;
1536
1537 switch (ch) {
1538
1539 case '<':
1540 *dst++ = '&'; *dst++ = 'l'; *dst++ = 't'; *dst++ = ';';
1541 break;
1542
1543 case '>':
1544 *dst++ = '&'; *dst++ = 'g'; *dst++ = 't'; *dst++ = ';';
1545 break;
1546
1547 case '&':
1548 *dst++ = '&'; *dst++ = 'a'; *dst++ = 'm'; *dst++ = 'p';
1549 *dst++ = ';';
1550 break;
1551
1552 default:
1553 *dst++ = ch;
1554 break;
1555 }
1556 }
1557
1558 return (uintptr_t) dst;
1559}
1560
1561
Igor Sysoev35921282007-05-21 14:05:23 +00001562/* ngx_sort() is implemented as insertion sort because we need stable sort */
1563
1564void
1565ngx_sort(void *base, size_t n, size_t size,
Igor Sysoevde8ec1e2008-03-24 13:04:02 +00001566 ngx_int_t (*cmp)(const void *, const void *))
Igor Sysoev35921282007-05-21 14:05:23 +00001567{
Igor Sysoev86341182008-03-23 19:58:54 +00001568 u_char *p1, *p2, *p;
1569
1570 p = ngx_alloc(size, ngx_cycle->log);
1571 if (p == NULL) {
1572 return;
1573 }
Igor Sysoev35921282007-05-21 14:05:23 +00001574
1575 for (p1 = (u_char *) base + size;
1576 p1 < (u_char *) base + n * size;
1577 p1 += size)
1578 {
Igor Sysoev86341182008-03-23 19:58:54 +00001579 ngx_memcpy(p, p1, size);
Igor Sysoev35921282007-05-21 14:05:23 +00001580
1581 for (p2 = p1;
Igor Sysoev86341182008-03-23 19:58:54 +00001582 p2 > (u_char *) base && cmp(p2 - size, p) > 0;
Igor Sysoev35921282007-05-21 14:05:23 +00001583 p2 -= size)
1584 {
1585 ngx_memcpy(p2, p2 - size, size);
1586 }
1587
Igor Sysoev86341182008-03-23 19:58:54 +00001588 ngx_memcpy(p2, p, size);
Igor Sysoev35921282007-05-21 14:05:23 +00001589 }
Igor Sysoev86341182008-03-23 19:58:54 +00001590
1591 ngx_free(p);
Igor Sysoev35921282007-05-21 14:05:23 +00001592}
1593
1594
Igor Sysoevd3283ff2005-12-05 13:18:09 +00001595#if (NGX_MEMCPY_LIMIT)
1596
1597void *
1598ngx_memcpy(void *dst, void *src, size_t n)
1599{
1600 if (n > NGX_MEMCPY_LIMIT) {
1601 ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "memcpy %uz bytes", n);
1602 ngx_debug_point();
1603 }
1604
1605 return memcpy(dst, src, n);
1606}
1607
1608#endif