blob: 01d792f36f29f0cc567518c44080bccac0937d82 [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 Sysoevd039a2e2005-02-22 14:40:13 +000011u_char *
12ngx_cpystrn(u_char *dst, u_char *src, size_t n)
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000013{
Igor Sysoev3d09c8d2003-05-06 17:03:16 +000014 if (n == 0) {
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000015 return dst;
Igor Sysoev3d09c8d2003-05-06 17:03:16 +000016 }
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000017
Igor Sysoev4959ec42005-05-23 12:07:45 +000018 for ( /* void */ ; --n; dst++, src++) {
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000019 *dst = *src;
20
Igor Sysoev3d09c8d2003-05-06 17:03:16 +000021 if (*dst == '\0') {
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000022 return dst;
Igor Sysoev3d09c8d2003-05-06 17:03:16 +000023 }
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000024 }
25
26 *dst = '\0';
27
28 return dst;
29}
Igor Sysoevdc479b42003-03-20 16:09:44 +000030
31
Igor Sysoevd039a2e2005-02-22 14:40:13 +000032u_char *
33ngx_pstrdup(ngx_pool_t *pool, ngx_str_t *src)
Igor Sysoev805d9db2005-02-03 19:33:37 +000034{
35 u_char *dst;
36
Igor Sysoevc1571722005-03-19 12:38:37 +000037 dst = ngx_palloc(pool, src->len);
38 if (dst == NULL) {
Igor Sysoev805d9db2005-02-03 19:33:37 +000039 return NULL;
40 }
41
42 ngx_memcpy(dst, src->data, src->len);
43
44 return dst;
45}
46
47
Igor Sysoevc0edbcc2004-10-21 15:34:38 +000048/*
49 * supported formats:
Igor Sysoev42b12b32004-12-02 18:40:46 +000050 * %[0][width][x][X]O off_t
Igor Sysoev1b735832004-11-11 14:07:14 +000051 * %[0][width]T time_t
52 * %[0][width][u][x|X]z ssize_t/size_t
53 * %[0][width][u][x|X]d int/u_int
54 * %[0][width][u][x|X]l long
55 * %[0][width|m][u][x|X]i ngx_int_t/ngx_uint_t
56 * %[0][width][u][x|X]D int32_t/uint32_t
57 * %[0][width][u][x|X]L int64_t/uint64_t
Igor Sysoev4a715592005-02-24 12:29:09 +000058 * %[0][width|m][u][x|X]A ngx_atomic_int_t/ngx_atomic_uint_t
Igor Sysoev1b735832004-11-11 14:07:14 +000059 * %P ngx_pid_t
Igor Sysoev208eed22005-10-07 13:30:52 +000060 * %M ngx_msec_t
Igor Sysoev1b735832004-11-11 14:07:14 +000061 * %r rlim_t
Igor Sysoev0d4b3722007-08-20 09:57:19 +000062 * %p void *
63 * %V ngx_str_t *
64 * %v ngx_variable_value_t *
Igor Sysoev1b735832004-11-11 14:07:14 +000065 * %s null-terminated string
Igor Sysoev79d9a042007-12-24 17:05:16 +000066 * %*s length and string
Igor Sysoev1b735832004-11-11 14:07:14 +000067 * %Z '\0'
Igor Sysoev85ef94b2005-06-23 13:41:06 +000068 * %N '\n'
Igor Sysoev1b735832004-11-11 14:07:14 +000069 * %c char
70 * %% %
Igor Sysoevc0edbcc2004-10-21 15:34:38 +000071 *
Igor Sysoev1b735832004-11-11 14:07:14 +000072 * reserved:
73 * %t ptrdiff_t
74 * %S null-teminated wchar string
75 * %C wchar
Igor Sysoevc0edbcc2004-10-21 15:34:38 +000076 */
77
Igor Sysoev1b735832004-11-11 14:07:14 +000078
Igor Sysoev4d656dc2005-03-22 16:02:46 +000079u_char * ngx_cdecl
Igor Sysoevd039a2e2005-02-22 14:40:13 +000080ngx_sprintf(u_char *buf, const char *fmt, ...)
Igor Sysoevc0edbcc2004-10-21 15:34:38 +000081{
Igor Sysoev1b735832004-11-11 14:07:14 +000082 u_char *p;
83 va_list args;
Igor Sysoevc0edbcc2004-10-21 15:34:38 +000084
Igor Sysoev1b735832004-11-11 14:07:14 +000085 va_start(args, fmt);
86 p = ngx_vsnprintf(buf, /* STUB */ 65536, fmt, args);
87 va_end(args);
Igor Sysoevc0edbcc2004-10-21 15:34:38 +000088
Igor Sysoev1b735832004-11-11 14:07:14 +000089 return p;
90}
91
92
Igor Sysoev4d656dc2005-03-22 16:02:46 +000093u_char * ngx_cdecl
Igor Sysoevd039a2e2005-02-22 14:40:13 +000094ngx_snprintf(u_char *buf, size_t max, const char *fmt, ...)
Igor Sysoev1b735832004-11-11 14:07:14 +000095{
96 u_char *p;
97 va_list args;
98
99 va_start(args, fmt);
100 p = ngx_vsnprintf(buf, max, fmt, args);
101 va_end(args);
102
103 return p;
104}
105
106
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000107u_char *
108ngx_vsnprintf(u_char *buf, size_t max, const char *fmt, va_list args)
Igor Sysoev1b735832004-11-11 14:07:14 +0000109{
Igor Sysoevf42ed052007-07-17 09:23:23 +0000110 u_char *p, zero, *last, temp[NGX_INT64_LEN + 1];
Igor Sysoev02025fd2005-01-18 13:03:58 +0000111 /*
112 * really we need temp[NGX_INT64_LEN] only,
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000113 * but icc issues the warning
Igor Sysoev02025fd2005-01-18 13:03:58 +0000114 */
Igor Sysoevf42ed052007-07-17 09:23:23 +0000115 int d;
Igor Sysoev79d9a042007-12-24 17:05:16 +0000116 size_t len, slen;
Igor Sysoevf42ed052007-07-17 09:23:23 +0000117 uint32_t ui32;
118 int64_t i64;
119 uint64_t ui64;
120 ngx_msec_t ms;
121 ngx_uint_t width, sign, hexadecimal, max_width;
Igor Sysoev0d4b3722007-08-20 09:57:19 +0000122 ngx_str_t *v;
123 ngx_variable_value_t *vv;
Igor Sysoevf42ed052007-07-17 09:23:23 +0000124 static u_char hex[] = "0123456789abcdef";
125 static u_char HEX[] = "0123456789ABCDEF";
Igor Sysoev1b735832004-11-11 14:07:14 +0000126
127 if (max == 0) {
128 return buf;
129 }
130
131 last = buf + max;
132
133 while (*fmt && buf < last) {
134
135 /*
136 * "buf < last" means that we could copy at least one character:
137 * the plain character, "%%", "%c", and minus without the checking
138 */
139
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000140 if (*fmt == '%') {
141
Igor Sysoev1b735832004-11-11 14:07:14 +0000142 i64 = 0;
143 ui64 = 0;
144
145 zero = (u_char) ((*++fmt == '0') ? '0' : ' ');
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000146 width = 0;
147 sign = 1;
148 hexadecimal = 0;
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000149 max_width = 0;
Igor Sysoev0bd32b72008-01-22 15:13:01 +0000150 slen = (size_t) -1;
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000151
Igor Sysoevb1dfe472004-12-21 12:30:30 +0000152 p = temp + NGX_INT64_LEN;
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000153
154 while (*fmt >= '0' && *fmt <= '9') {
155 width = width * 10 + *fmt++ - '0';
156 }
157
158
159 for ( ;; ) {
160 switch (*fmt) {
161
162 case 'u':
163 sign = 0;
164 fmt++;
165 continue;
166
Igor Sysoevd43bee82004-11-20 19:52:20 +0000167 case 'm':
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000168 max_width = 1;
Igor Sysoevd43bee82004-11-20 19:52:20 +0000169 fmt++;
170 continue;
171
Igor Sysoev1b735832004-11-11 14:07:14 +0000172 case 'X':
173 hexadecimal = 2;
174 sign = 0;
175 fmt++;
176 continue;
177
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000178 case 'x':
179 hexadecimal = 1;
Igor Sysoev1b735832004-11-11 14:07:14 +0000180 sign = 0;
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000181 fmt++;
182 continue;
183
Igor Sysoev79d9a042007-12-24 17:05:16 +0000184 case '*':
Igor Sysoevfb424652008-01-24 15:18:17 +0000185 slen = va_arg(args, size_t);
Igor Sysoev79d9a042007-12-24 17:05:16 +0000186 fmt++;
187 continue;
188
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000189 default:
190 break;
191 }
192
193 break;
194 }
195
196
197 switch (*fmt) {
198
Igor Sysoev1b735832004-11-11 14:07:14 +0000199 case 'V':
Igor Sysoev0d4b3722007-08-20 09:57:19 +0000200 v = va_arg(args, ngx_str_t *);
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000201
Igor Sysoevf42ed052007-07-17 09:23:23 +0000202 len = v->len;
Igor Sysoev09c684b2005-11-09 17:25:55 +0000203 len = (buf + len < last) ? len : (size_t) (last - buf);
204
Igor Sysoevf42ed052007-07-17 09:23:23 +0000205 buf = ngx_cpymem(buf, v->data, len);
Igor Sysoev1b735832004-11-11 14:07:14 +0000206 fmt++;
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000207
Igor Sysoev1b735832004-11-11 14:07:14 +0000208 continue;
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000209
Igor Sysoev0d4b3722007-08-20 09:57:19 +0000210 case 'v':
211 vv = va_arg(args, ngx_variable_value_t *);
212
213 len = vv->len;
214 len = (buf + len < last) ? len : (size_t) (last - buf);
215
216 buf = ngx_cpymem(buf, vv->data, len);
217 fmt++;
218
219 continue;
220
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000221 case 's':
Igor Sysoev1b735832004-11-11 14:07:14 +0000222 p = va_arg(args, u_char *);
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000223
Igor Sysoev0bd32b72008-01-22 15:13:01 +0000224 if (slen == (size_t) -1) {
Igor Sysoev79d9a042007-12-24 17:05:16 +0000225 while (*p && buf < last) {
226 *buf++ = *p++;
227 }
228
229 } else {
Igor Sysoev16315762008-01-24 15:18:58 +0000230 len = (buf + slen < last) ? slen : (size_t) (last - buf);
231
232 buf = ngx_cpymem(buf, p, len);
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000233 }
Igor Sysoev79d9a042007-12-24 17:05:16 +0000234
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000235 fmt++;
236
237 continue;
238
Igor Sysoev1b735832004-11-11 14:07:14 +0000239 case 'O':
240 i64 = (int64_t) va_arg(args, off_t);
241 sign = 1;
242 break;
243
244 case 'P':
245 i64 = (int64_t) va_arg(args, ngx_pid_t);
246 sign = 1;
247 break;
248
249 case 'T':
250 i64 = (int64_t) va_arg(args, time_t);
251 sign = 1;
252 break;
253
Igor Sysoev208eed22005-10-07 13:30:52 +0000254 case 'M':
Igor Sysoev78452232005-10-12 13:50:36 +0000255 ms = (ngx_msec_t) va_arg(args, ngx_msec_t);
256 if ((ngx_msec_int_t) ms == -1) {
257 sign = 1;
258 i64 = -1;
259 } else {
260 sign = 0;
261 ui64 = (uint64_t) ms;
262 }
Igor Sysoev208eed22005-10-07 13:30:52 +0000263 break;
264
Igor Sysoev1b735832004-11-11 14:07:14 +0000265 case 'z':
266 if (sign) {
267 i64 = (int64_t) va_arg(args, ssize_t);
268 } else {
269 ui64 = (uint64_t) va_arg(args, size_t);
270 }
271 break;
272
273 case 'i':
274 if (sign) {
275 i64 = (int64_t) va_arg(args, ngx_int_t);
276 } else {
277 ui64 = (uint64_t) va_arg(args, ngx_uint_t);
278 }
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000279
280 if (max_width) {
281 width = NGX_INT_T_LEN;
282 }
283
Igor Sysoev1b735832004-11-11 14:07:14 +0000284 break;
285
286 case 'd':
287 if (sign) {
288 i64 = (int64_t) va_arg(args, int);
289 } else {
290 ui64 = (uint64_t) va_arg(args, u_int);
291 }
292 break;
293
294 case 'l':
295 if (sign) {
296 i64 = (int64_t) va_arg(args, long);
297 } else {
298 ui64 = (uint64_t) va_arg(args, u_long);
299 }
300 break;
301
302 case 'D':
303 if (sign) {
304 i64 = (int64_t) va_arg(args, int32_t);
305 } else {
306 ui64 = (uint64_t) va_arg(args, uint32_t);
307 }
308 break;
309
310 case 'L':
311 if (sign) {
312 i64 = va_arg(args, int64_t);
313 } else {
314 ui64 = va_arg(args, uint64_t);
315 }
316 break;
317
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000318 case 'A':
319 if (sign) {
320 i64 = (int64_t) va_arg(args, ngx_atomic_int_t);
321 } else {
Igor Sysoev4a715592005-02-24 12:29:09 +0000322 ui64 = (uint64_t) va_arg(args, ngx_atomic_uint_t);
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000323 }
324
325 if (max_width) {
326 width = NGX_ATOMIC_T_LEN;
327 }
328
329 break;
330
Igor Sysoev1b735832004-11-11 14:07:14 +0000331#if !(NGX_WIN32)
332 case 'r':
333 i64 = (int64_t) va_arg(args, rlim_t);
334 sign = 1;
335 break;
336#endif
337
338 case 'p':
339 ui64 = (uintptr_t) va_arg(args, void *);
340 hexadecimal = 2;
341 sign = 0;
342 zero = '0';
Igor Sysoevc2807ec2006-02-16 15:26:46 +0000343 width = NGX_PTR_SIZE * 2;
Igor Sysoev1b735832004-11-11 14:07:14 +0000344 break;
345
Igor Sysoev723e6cc2004-10-25 15:29:23 +0000346 case 'c':
Igor Sysoev1b735832004-11-11 14:07:14 +0000347 d = va_arg(args, int);
Igor Sysoev723e6cc2004-10-25 15:29:23 +0000348 *buf++ = (u_char) (d & 0xff);
349 fmt++;
350
351 continue;
352
Igor Sysoev1b735832004-11-11 14:07:14 +0000353 case 'Z':
354 *buf++ = '\0';
355 fmt++;
356
357 continue;
358
Igor Sysoev85ef94b2005-06-23 13:41:06 +0000359 case 'N':
360#if (NGX_WIN32)
361 *buf++ = CR;
362#endif
363 *buf++ = LF;
364 fmt++;
365
366 continue;
367
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000368 case '%':
369 *buf++ = '%';
370 fmt++;
371
372 continue;
373
374 default:
375 *buf++ = *fmt++;
376
377 continue;
378 }
379
Igor Sysoev1b735832004-11-11 14:07:14 +0000380 if (sign) {
381 if (i64 < 0) {
382 *buf++ = '-';
383 ui64 = (uint64_t) -i64;
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000384
Igor Sysoev1b735832004-11-11 14:07:14 +0000385 } else {
386 ui64 = (uint64_t) i64;
387 }
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000388 }
389
Igor Sysoev1b735832004-11-11 14:07:14 +0000390 if (hexadecimal == 1) {
391 do {
392
393 /* the "(uint32_t)" cast disables the BCC's warning */
394 *--p = hex[(uint32_t) (ui64 & 0xf)];
395
396 } while (ui64 >>= 4);
397
398 } else if (hexadecimal == 2) {
399 do {
400
401 /* the "(uint32_t)" cast disables the BCC's warning */
402 *--p = HEX[(uint32_t) (ui64 & 0xf)];
403
404 } while (ui64 >>= 4);
405
406 } else if (ui64 <= NGX_MAX_UINT32_VALUE) {
407
408 /*
409 * To divide 64-bit number and to find the remainder
410 * on the x86 platform gcc and icc call the libc functions
411 * [u]divdi3() and [u]moddi3(), they call another function
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000412 * in its turn. On FreeBSD it is the qdivrem() function,
Igor Sysoev1b735832004-11-11 14:07:14 +0000413 * its source code is about 170 lines of the code.
414 * The glibc counterpart is about 150 lines of the code.
415 *
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000416 * For 32-bit numbers and some divisors gcc and icc use
417 * the inlined multiplication and shifts. For example,
418 * unsigned "i32 / 10" is compiled to
419 *
420 * (i32 * 0xCCCCCCCD) >> 35
Igor Sysoev1b735832004-11-11 14:07:14 +0000421 */
422
423 ui32 = (uint32_t) ui64;
424
425 do {
426 *--p = (u_char) (ui32 % 10 + '0');
427 } while (ui32 /= 10);
428
429 } else {
430 do {
431 *--p = (u_char) (ui64 % 10 + '0');
432 } while (ui64 /= 10);
433 }
434
Igor Sysoevb1dfe472004-12-21 12:30:30 +0000435 len = (temp + NGX_INT64_LEN) - p;
Igor Sysoev1b735832004-11-11 14:07:14 +0000436
437 while (len++ < width && buf < last) {
438 *buf++ = zero;
439 }
440
Igor Sysoevb1dfe472004-12-21 12:30:30 +0000441 len = (temp + NGX_INT64_LEN) - p;
Igor Sysoev1b735832004-11-11 14:07:14 +0000442 if (buf + len > last) {
443 len = last - buf;
444 }
445
446 buf = ngx_cpymem(buf, p, len);
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000447
448 fmt++;
449
450 } else {
451 *buf++ = *fmt++;
452 }
453 }
454
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000455 return buf;
456}
457
458
Igor Sysoev722231f2007-02-14 18:51:19 +0000459/*
Igor Sysoev066e6322007-09-26 12:23:34 +0000460 * We use ngx_strcasecmp()/ngx_strncasecmp() for 7-bit ASCII strings only,
Igor Sysoev722231f2007-02-14 18:51:19 +0000461 * and implement our own ngx_strcasecmp()/ngx_strncasecmp()
462 * to avoid libc locale overhead. Besides, we use the ngx_uint_t's
463 * instead of the u_char's, because they are slightly faster.
464 */
465
466ngx_int_t
467ngx_strcasecmp(u_char *s1, u_char *s2)
468{
469 ngx_uint_t c1, c2;
470
471 for ( ;; ) {
472 c1 = (ngx_uint_t) *s1++;
473 c2 = (ngx_uint_t) *s2++;
474
475 c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;
476 c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;
477
478 if (c1 == c2) {
479
480 if (c1) {
481 continue;
482 }
483
484 return 0;
485 }
486
487 return c1 - c2;
488 }
489}
490
491
492ngx_int_t
493ngx_strncasecmp(u_char *s1, u_char *s2, size_t n)
494{
495 ngx_uint_t c1, c2;
496
497 while (n) {
498 c1 = (ngx_uint_t) *s1++;
499 c2 = (ngx_uint_t) *s2++;
500
501 c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;
502 c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;
503
504 if (c1 == c2) {
505
506 if (c1) {
507 n--;
508 continue;
509 }
510
511 return 0;
512 }
513
514 return c1 - c2;
515 }
516
517 return 0;
518}
519
520
Igor Sysoev35fe5fd2007-10-01 14:48:33 +0000521u_char *
522ngx_strnstr(u_char *s1, char *s2, size_t len)
523{
524 u_char c1, c2;
525 size_t n;
526
527 c2 = *(u_char *) s2++;
528
529 n = ngx_strlen(s2);
530
531 do {
532 do {
533 if (len-- == 0) {
534 return NULL;
535 }
536
537 c1 = *s1++;
538
539 if (c1 == 0) {
540 return NULL;
541 }
542
543 } while (c1 != c2);
544
545 if (n > len) {
546 return NULL;
547 }
548
549 } while (ngx_strncmp(s1, (u_char *) s2, n) != 0);
550
551 return --s1;
552}
553
554
Igor Sysoev66697022007-10-01 13:00:30 +0000555/*
556 * ngx_strstrn() and ngx_strcasestrn() are intended to search for static
557 * substring with known length in null-terminated string. The argument n
558 * must be length of the second substring - 1.
559 */
560
Igor Sysoev1bd98702007-09-26 19:25:52 +0000561u_char *
562ngx_strstrn(u_char *s1, char *s2, size_t n)
563{
564 u_char c1, c2;
565
566 c2 = *(u_char *) s2++;
567
568 do {
569 do {
570 c1 = *s1++;
571
572 if (c1 == 0) {
573 return NULL;
574 }
575
576 } while (c1 != c2);
577
578 } while (ngx_strncmp(s1, (u_char *) s2, n) != 0);
579
580 return --s1;
581}
582
583
584u_char *
585ngx_strcasestrn(u_char *s1, char *s2, size_t n)
586{
587 ngx_uint_t c1, c2;
588
589 c2 = (ngx_uint_t) *s2++;
590 c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;
591
592 do {
593 do {
594 c1 = (ngx_uint_t) *s1++;
595
596 if (c1 == 0) {
597 return NULL;
598 }
599
600 c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;
601
602 } while (c1 != c2);
603
604 } while (ngx_strncasecmp(s1, (u_char *) s2, n) != 0);
605
606 return --s1;
607}
608
609
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000610ngx_int_t
611ngx_rstrncmp(u_char *s1, u_char *s2, size_t n)
Igor Sysoev3d09c8d2003-05-06 17:03:16 +0000612{
613 if (n == 0) {
614 return 0;
615 }
616
617 n--;
618
619 for ( ;; ) {
620 if (s1[n] != s2[n]) {
Igor Sysoev10a543a2004-03-16 07:10:12 +0000621 return s1[n] - s2[n];
Igor Sysoev3d09c8d2003-05-06 17:03:16 +0000622 }
623
624 if (n == 0) {
625 return 0;
626 }
627
628 n--;
629 }
630}
631
632
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000633ngx_int_t
634ngx_rstrncasecmp(u_char *s1, u_char *s2, size_t n)
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000635{
636 u_char c1, c2;
637
638 if (n == 0) {
639 return 0;
640 }
641
642 n--;
643
644 for ( ;; ) {
645 c1 = s1[n];
646 if (c1 >= 'a' && c1 <= 'z') {
647 c1 -= 'a' - 'A';
648 }
649
650 c2 = s2[n];
651 if (c2 >= 'a' && c2 <= 'z') {
652 c2 -= 'a' - 'A';
653 }
654
655 if (c1 != c2) {
656 return c1 - c2;
657 }
658
659 if (n == 0) {
660 return 0;
661 }
662
663 n--;
664 }
665}
666
667
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000668ngx_int_t
Igor Sysoevec3cabd2007-01-12 21:58:02 +0000669ngx_memn2cmp(u_char *s1, u_char *s2, size_t n1, size_t n2)
Igor Sysoev37cc1652007-01-12 20:15:59 +0000670{
671 size_t n;
672 ngx_int_t m, z;
673
674 if (n1 <= n2) {
675 n = n1;
676 z = -1;
677
678 } else {
679 n = n2;
680 z = 1;
681 }
682
Igor Sysoevec3cabd2007-01-12 21:58:02 +0000683 m = ngx_memcmp(s1, s2, n);
Igor Sysoev37cc1652007-01-12 20:15:59 +0000684
685 if (m || n1 == n2) {
686 return m;
687 }
688
689 return z;
690}
691
692
693ngx_int_t
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000694ngx_atoi(u_char *line, size_t n)
Igor Sysoevdc479b42003-03-20 16:09:44 +0000695{
Igor Sysoev10a543a2004-03-16 07:10:12 +0000696 ngx_int_t value;
Igor Sysoevdc479b42003-03-20 16:09:44 +0000697
Igor Sysoev3d09c8d2003-05-06 17:03:16 +0000698 if (n == 0) {
699 return NGX_ERROR;
700 }
701
Igor Sysoevdc479b42003-03-20 16:09:44 +0000702 for (value = 0; n--; line++) {
Igor Sysoev1d8d9ee2003-04-28 15:06:39 +0000703 if (*line < '0' || *line > '9') {
704 return NGX_ERROR;
705 }
Igor Sysoevdc479b42003-03-20 16:09:44 +0000706
Igor Sysoev1d8d9ee2003-04-28 15:06:39 +0000707 value = value * 10 + (*line - '0');
Igor Sysoevdc479b42003-03-20 16:09:44 +0000708 }
709
Igor Sysoev1d8d9ee2003-04-28 15:06:39 +0000710 if (value < 0) {
711 return NGX_ERROR;
Igor Sysoev18684bd2004-05-20 17:33:52 +0000712
713 } else {
714 return value;
715 }
716}
717
718
Igor Sysoevc1571722005-03-19 12:38:37 +0000719ssize_t
720ngx_atosz(u_char *line, size_t n)
721{
722 ssize_t value;
723
724 if (n == 0) {
725 return NGX_ERROR;
726 }
727
728 for (value = 0; n--; line++) {
729 if (*line < '0' || *line > '9') {
730 return NGX_ERROR;
731 }
732
733 value = value * 10 + (*line - '0');
734 }
735
736 if (value < 0) {
737 return NGX_ERROR;
738
739 } else {
740 return value;
741 }
742}
743
744
745off_t
746ngx_atoof(u_char *line, size_t n)
747{
748 off_t value;
749
750 if (n == 0) {
751 return NGX_ERROR;
752 }
753
754 for (value = 0; n--; line++) {
755 if (*line < '0' || *line > '9') {
756 return NGX_ERROR;
757 }
758
759 value = value * 10 + (*line - '0');
760 }
761
762 if (value < 0) {
763 return NGX_ERROR;
764
765 } else {
766 return value;
767 }
768}
769
770
771time_t
772ngx_atotm(u_char *line, size_t n)
773{
774 time_t value;
775
776 if (n == 0) {
777 return NGX_ERROR;
778 }
779
780 for (value = 0; n--; line++) {
781 if (*line < '0' || *line > '9') {
782 return NGX_ERROR;
783 }
784
785 value = value * 10 + (*line - '0');
786 }
787
788 if (value < 0) {
789 return NGX_ERROR;
790
791 } else {
792 return value;
793 }
794}
795
796
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000797ngx_int_t
798ngx_hextoi(u_char *line, size_t n)
Igor Sysoev18684bd2004-05-20 17:33:52 +0000799{
Igor Sysoev066496a2006-10-16 12:21:17 +0000800 u_char c, ch;
Igor Sysoev18684bd2004-05-20 17:33:52 +0000801 ngx_int_t value;
802
803 if (n == 0) {
804 return NGX_ERROR;
805 }
806
807 for (value = 0; n--; line++) {
808 ch = *line;
809
810 if (ch >= '0' && ch <= '9') {
811 value = value * 16 + (ch - '0');
812 continue;
813 }
814
Igor Sysoev066496a2006-10-16 12:21:17 +0000815 c = (u_char) (ch | 0x20);
Igor Sysoev18684bd2004-05-20 17:33:52 +0000816
Igor Sysoev066496a2006-10-16 12:21:17 +0000817 if (c >= 'a' && c <= 'f') {
818 value = value * 16 + (c - 'a' + 10);
Igor Sysoev18684bd2004-05-20 17:33:52 +0000819 continue;
820 }
821
822 return NGX_ERROR;
823 }
824
825 if (value < 0) {
826 return NGX_ERROR;
827
Igor Sysoev1d8d9ee2003-04-28 15:06:39 +0000828 } else {
829 return value;
830 }
Igor Sysoevdc479b42003-03-20 16:09:44 +0000831}
832
833
Igor Sysoeva03fa362007-12-17 21:06:17 +0000834u_char *
835ngx_hex_dump(u_char *dst, u_char *src, size_t len)
Igor Sysoev9cc1ace2003-11-04 22:12:39 +0000836{
Igor Sysoev10a543a2004-03-16 07:10:12 +0000837 static u_char hex[] = "0123456789abcdef";
Igor Sysoeve8732b02003-11-05 17:03:41 +0000838
Igor Sysoeva03fa362007-12-17 21:06:17 +0000839 while (len--) {
840 *dst++ = hex[*src >> 4];
841 *dst++ = hex[*src++ & 0xf];
Igor Sysoev74e95c22003-11-09 20:03:38 +0000842 }
843
Igor Sysoeva03fa362007-12-17 21:06:17 +0000844 return dst;
Igor Sysoev9cc1ace2003-11-04 22:12:39 +0000845}
846
847
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000848void
849ngx_encode_base64(ngx_str_t *dst, ngx_str_t *src)
Igor Sysoev6deb0412004-07-30 17:05:14 +0000850{
851 u_char *d, *s;
Igor Sysoev967fd632004-08-27 15:40:59 +0000852 size_t len;
Igor Sysoev6deb0412004-07-30 17:05:14 +0000853 static u_char basis64[] =
854 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
855
Igor Sysoev967fd632004-08-27 15:40:59 +0000856 len = src->len;
Igor Sysoeva7c4a2a2004-08-29 03:55:41 +0000857 s = src->data;
858 d = dst->data;
Igor Sysoev6deb0412004-07-30 17:05:14 +0000859
Igor Sysoev967fd632004-08-27 15:40:59 +0000860 while (len > 2) {
861 *d++ = basis64[(s[0] >> 2) & 0x3f];
862 *d++ = basis64[((s[0] & 3) << 4) | (s[1] >> 4)];
863 *d++ = basis64[((s[1] & 0x0f) << 2) | (s[2] >> 6)];
864 *d++ = basis64[s[2] & 0x3f];
865
866 s += 3;
867 len -= 3;
Igor Sysoev6deb0412004-07-30 17:05:14 +0000868 }
869
Igor Sysoev967fd632004-08-27 15:40:59 +0000870 if (len) {
871 *d++ = basis64[(s[0] >> 2) & 0x3f];
Igor Sysoev6deb0412004-07-30 17:05:14 +0000872
Igor Sysoev967fd632004-08-27 15:40:59 +0000873 if (len == 1) {
874 *d++ = basis64[(s[0] & 3) << 4];
Igor Sysoev6deb0412004-07-30 17:05:14 +0000875 *d++ = '=';
876
877 } else {
Igor Sysoev967fd632004-08-27 15:40:59 +0000878 *d++ = basis64[((s[0] & 3) << 4) | (s[1] >> 4)];
879 *d++ = basis64[(s[1] & 0x0f) << 2];
Igor Sysoev6deb0412004-07-30 17:05:14 +0000880 }
881
882 *d++ = '=';
883 }
884
885 dst->len = d - dst->data;
Igor Sysoev6deb0412004-07-30 17:05:14 +0000886}
887
888
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000889ngx_int_t
890ngx_decode_base64(ngx_str_t *dst, ngx_str_t *src)
Igor Sysoev6deb0412004-07-30 17:05:14 +0000891{
Igor Sysoev967fd632004-08-27 15:40:59 +0000892 size_t len;
893 u_char *d, *s;
Igor Sysoevb5c75dc2006-10-28 14:36:44 +0000894 static u_char basis64[] = {
895 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
896 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
897 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 62, 77, 77, 77, 63,
898 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 77, 77, 77, 77, 77, 77,
899 77, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
900 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 77, 77, 77, 77, 77,
901 77, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
902 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 77, 77, 77, 77, 77,
Igor Sysoev6deb0412004-07-30 17:05:14 +0000903
Igor Sysoevb5c75dc2006-10-28 14:36:44 +0000904 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
905 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
906 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
907 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
908 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
909 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
910 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
911 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77
912 };
Igor Sysoev967fd632004-08-27 15:40:59 +0000913
914 for (len = 0; len < src->len; len++) {
915 if (src->data[len] == '=') {
916 break;
917 }
918
919 if (basis64[src->data[len]] == 77) {
920 return NGX_ERROR;
921 }
922 }
923
924 if (len % 4 == 1) {
925 return NGX_ERROR;
926 }
927
Igor Sysoev6deb0412004-07-30 17:05:14 +0000928 s = src->data;
Igor Sysoeva7c4a2a2004-08-29 03:55:41 +0000929 d = dst->data;
Igor Sysoev6deb0412004-07-30 17:05:14 +0000930
Igor Sysoev967fd632004-08-27 15:40:59 +0000931 while (len > 3) {
Igor Sysoeva7c4a2a2004-08-29 03:55:41 +0000932 *d++ = (u_char) (basis64[s[0]] << 2 | basis64[s[1]] >> 4);
933 *d++ = (u_char) (basis64[s[1]] << 4 | basis64[s[2]] >> 2);
934 *d++ = (u_char) (basis64[s[2]] << 6 | basis64[s[3]]);
Igor Sysoev6deb0412004-07-30 17:05:14 +0000935
Igor Sysoev967fd632004-08-27 15:40:59 +0000936 s += 4;
937 len -= 4;
Igor Sysoev6deb0412004-07-30 17:05:14 +0000938 }
939
Igor Sysoev967fd632004-08-27 15:40:59 +0000940 if (len > 1) {
Igor Sysoeva7c4a2a2004-08-29 03:55:41 +0000941 *d++ = (u_char) (basis64[s[0]] << 2 | basis64[s[1]] >> 4);
Igor Sysoev967fd632004-08-27 15:40:59 +0000942 }
943
944 if (len > 2) {
Igor Sysoeva7c4a2a2004-08-29 03:55:41 +0000945 *d++ = (u_char) (basis64[s[1]] << 4 | basis64[s[2]] >> 2);
Igor Sysoev967fd632004-08-27 15:40:59 +0000946 }
947
948 dst->len = d - dst->data;
Igor Sysoev967fd632004-08-27 15:40:59 +0000949
Igor Sysoev6deb0412004-07-30 17:05:14 +0000950 return NGX_OK;
951}
952
953
Igor Sysoevef809b82006-06-28 16:00:26 +0000954/*
955 * ngx_utf_decode() decodes two and more bytes UTF sequences only
956 * the return values:
957 * 0x80 - 0x10ffff valid character
958 * 0x10ffff - 0xfffffffd invalid sequence
959 * 0xfffffffe incomplete sequence
960 * 0xffffffff error
961 */
962
963uint32_t
964ngx_utf_decode(u_char **p, size_t n)
965{
966 size_t len;
967 uint32_t u, i, valid;
968
969 u = **p;
970
971 if (u > 0xf0) {
972
973 u &= 0x07;
974 valid = 0xffff;
975 len = 3;
976
977 } else if (u > 0xe0) {
978
979 u &= 0x0f;
980 valid = 0x7ff;
981 len = 2;
982
983 } else if (u > 0xc0) {
984
985 u &= 0x1f;
986 valid = 0x7f;
987 len = 1;
988
989 } else {
990 (*p)++;
991 return 0xffffffff;
992 }
993
994 if (n - 1 < len) {
995 return 0xfffffffe;
996 }
997
998 (*p)++;
999
1000 while (len) {
1001 i = *(*p)++;
1002
1003 if (i < 0x80) {
1004 return 0xffffffff;
1005 }
1006
1007 u = (u << 6) | (i & 0x3f);
1008
1009 len--;
1010 }
1011
1012 if (u > valid) {
1013 return u;
1014 }
1015
1016 return 0xffffffff;
1017}
1018
1019
Igor Sysoevb145b062005-06-15 18:33:41 +00001020size_t
Igor Sysoevef809b82006-06-28 16:00:26 +00001021ngx_utf_length(u_char *p, size_t n)
Igor Sysoevb145b062005-06-15 18:33:41 +00001022{
1023 u_char c;
1024 size_t len;
1025 ngx_uint_t i;
1026
Igor Sysoevef809b82006-06-28 16:00:26 +00001027 for (len = 0, i = 0; i < n; len++, i++) {
Igor Sysoevb145b062005-06-15 18:33:41 +00001028
Igor Sysoevef809b82006-06-28 16:00:26 +00001029 c = p[i];
Igor Sysoevb145b062005-06-15 18:33:41 +00001030
1031 if (c < 0x80) {
1032 continue;
1033 }
1034
Igor Sysoev5192b362005-07-08 14:34:20 +00001035 if (c >= 0xc0) {
1036 for (c <<= 1; c & 0x80; c <<= 1) {
1037 i++;
1038 }
1039
1040 continue;
Igor Sysoevb145b062005-06-15 18:33:41 +00001041 }
1042
Igor Sysoev5192b362005-07-08 14:34:20 +00001043 /* invalid utf */
1044
Igor Sysoevef809b82006-06-28 16:00:26 +00001045 return n;
Igor Sysoevb145b062005-06-15 18:33:41 +00001046 }
1047
1048 return len;
1049}
1050
1051
Igor Sysoev5192b362005-07-08 14:34:20 +00001052u_char *
1053ngx_utf_cpystrn(u_char *dst, u_char *src, size_t n)
1054{
1055 u_char c;
1056
1057 if (n == 0) {
1058 return dst;
1059 }
1060
1061 for ( /* void */ ; --n; dst++, src++) {
1062
1063 c = *src;
1064 *dst = c;
1065
1066 if (c < 0x80) {
1067 if (*dst != '\0') {
1068 continue;
1069 }
1070
1071 return dst;
1072 }
1073
1074 if (c >= 0xc0) {
1075 for (c <<= 1; c & 0x80; c <<= 1) {
1076 *++dst = *++src;
1077 }
1078
1079 continue;
1080 }
1081
1082 /* invalid utf */
1083 }
1084
1085 *dst = '\0';
1086
1087 return dst;
1088}
1089
1090
Igor Sysoevd039a2e2005-02-22 14:40:13 +00001091uintptr_t
1092ngx_escape_uri(u_char *dst, u_char *src, size_t size, ngx_uint_t type)
Igor Sysoevdc479b42003-03-20 16:09:44 +00001093{
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001094 ngx_uint_t i, n;
1095 uint32_t *escape;
1096 static u_char hex[] = "0123456789abcdef";
Igor Sysoev1b735832004-11-11 14:07:14 +00001097
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001098 /* " ", "#", "%", "?", %00-%1F, %7F-%FF */
Igor Sysoev805d9db2005-02-03 19:33:37 +00001099
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001100 static uint32_t uri[] = {
1101 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
Igor Sysoevdc479b42003-03-20 16:09:44 +00001102
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001103 /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
1104 0x80000029, /* 1000 0000 0000 0000 0000 0000 0010 1001 */
Igor Sysoevdc479b42003-03-20 16:09:44 +00001105
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001106 /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
1107 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
Igor Sysoevdc479b42003-03-20 16:09:44 +00001108
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001109 /* ~}| {zyx wvut srqp onml kjih gfed cba` */
1110 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */
Igor Sysoev924bd792004-10-11 15:07:03 +00001111
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001112 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1113 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1114 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1115 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1116 };
Igor Sysoev924bd792004-10-11 15:07:03 +00001117
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001118 /* " ", "#", "%", "+", "?", %00-%1F, %7F-%FF */
Igor Sysoev805d9db2005-02-03 19:33:37 +00001119
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001120 static uint32_t args[] = {
1121 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
Igor Sysoev805d9db2005-02-03 19:33:37 +00001122
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001123 /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
1124 0x80000829, /* 1000 0000 0000 0000 0000 1000 0010 1001 */
Igor Sysoev805d9db2005-02-03 19:33:37 +00001125
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001126 /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
1127 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
Igor Sysoev805d9db2005-02-03 19:33:37 +00001128
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001129 /* ~}| {zyx wvut srqp onml kjih gfed cba` */
1130 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */
Igor Sysoev805d9db2005-02-03 19:33:37 +00001131
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001132 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1133 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1134 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1135 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1136 };
Igor Sysoev805d9db2005-02-03 19:33:37 +00001137
Igor Sysoevd4ff5612007-08-20 09:50:53 +00001138 /* " ", "#", """, "%", "'", %00-%1F, %7F-%FF */
Igor Sysoev805d9db2005-02-03 19:33:37 +00001139
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001140 static uint32_t html[] = {
1141 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
Igor Sysoev1b735832004-11-11 14:07:14 +00001142
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001143 /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
Igor Sysoev049ae002007-07-13 09:35:51 +00001144 0x000000ad, /* 0000 0000 0000 0000 0000 0000 1010 1101 */
Igor Sysoev1b735832004-11-11 14:07:14 +00001145
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001146 /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
1147 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
Igor Sysoev1b735832004-11-11 14:07:14 +00001148
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001149 /* ~}| {zyx wvut srqp onml kjih gfed cba` */
1150 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */
Igor Sysoev1b735832004-11-11 14:07:14 +00001151
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001152 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1153 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1154 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1155 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1156 };
Igor Sysoev1b735832004-11-11 14:07:14 +00001157
Igor Sysoevd4ff5612007-08-20 09:50:53 +00001158 /* " ", """, "%", "'", %00-%1F, %7F-%FF */
Igor Sysoev1b735832004-11-11 14:07:14 +00001159
Igor Sysoev8662b6b2007-07-13 09:37:01 +00001160 static uint32_t refresh[] = {
1161 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1162
1163 /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
Igor Sysoevcc5484f2007-11-09 13:17:58 +00001164 0x00000085, /* 0000 0000 0000 0000 0000 0000 1000 0101 */
Igor Sysoev8662b6b2007-07-13 09:37:01 +00001165
1166 /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
1167 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1168
1169 /* ~}| {zyx wvut srqp onml kjih gfed cba` */
1170 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */
1171
1172 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1173 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1174 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1175 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1176 };
1177
Igor Sysoevd4ff5612007-08-20 09:50:53 +00001178 /* " ", "%", %00-%1F */
Igor Sysoev3f707822007-07-22 19:18:59 +00001179
1180 static uint32_t memcached[] = {
1181 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1182
1183 /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
Igor Sysoevd4ff5612007-08-20 09:50:53 +00001184 0x00000021, /* 0000 0000 0000 0000 0000 0000 0010 0001 */
Igor Sysoev3f707822007-07-22 19:18:59 +00001185
1186 /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
1187 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1188
1189 /* ~}| {zyx wvut srqp onml kjih gfed cba` */
1190 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1191
1192 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1193 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1194 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1195 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1196 };
1197
Igor Sysoevd4ff5612007-08-20 09:50:53 +00001198 /* mail_auth is the same as memcached */
1199
1200 static uint32_t *map[] =
1201 { uri, args, html, refresh, memcached, memcached };
Igor Sysoev8662b6b2007-07-13 09:37:01 +00001202
1203
1204 escape = map[type];
Igor Sysoev1b735832004-11-11 14:07:14 +00001205
Igor Sysoev924bd792004-10-11 15:07:03 +00001206 if (dst == NULL) {
1207
1208 /* find the number of the characters to be escaped */
1209
1210 n = 0;
1211
1212 for (i = 0; i < size; i++) {
1213 if (escape[*src >> 5] & (1 << (*src & 0x1f))) {
1214 n++;
1215 }
1216 src++;
1217 }
1218
Igor Sysoev805d9db2005-02-03 19:33:37 +00001219 return (uintptr_t) n;
Igor Sysoevdc479b42003-03-20 16:09:44 +00001220 }
1221
Igor Sysoev924bd792004-10-11 15:07:03 +00001222 for (i = 0; i < size; i++) {
1223 if (escape[*src >> 5] & (1 << (*src & 0x1f))) {
1224 *dst++ = '%';
1225 *dst++ = hex[*src >> 4];
1226 *dst++ = hex[*src & 0xf];
1227 src++;
Igor Sysoevdc479b42003-03-20 16:09:44 +00001228
Igor Sysoev924bd792004-10-11 15:07:03 +00001229 } else {
1230 *dst++ = *src++;
1231 }
Igor Sysoevdc479b42003-03-20 16:09:44 +00001232 }
1233
Igor Sysoev805d9db2005-02-03 19:33:37 +00001234 return (uintptr_t) dst;
Igor Sysoevdc479b42003-03-20 16:09:44 +00001235}
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +00001236
1237
1238void
Igor Sysoevae33d012006-01-17 20:04:32 +00001239ngx_unescape_uri(u_char **dst, u_char **src, size_t size, ngx_uint_t type)
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +00001240{
1241 u_char *d, *s, ch, c, decoded;
1242 enum {
1243 sw_usual = 0,
1244 sw_quoted,
1245 sw_quoted_second
1246 } state;
1247
1248 d = *dst;
1249 s = *src;
1250
1251 state = 0;
1252 decoded = 0;
1253
1254 while (size--) {
1255
1256 ch = *s++;
1257
1258 switch (state) {
1259 case sw_usual:
Igor Sysoevf0a51cf2007-10-22 10:19:17 +00001260 if (ch == '?'
1261 && (type & (NGX_UNESCAPE_URI|NGX_UNESCAPE_REDIRECT)))
1262 {
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +00001263 *d++ = ch;
1264 goto done;
1265 }
1266
1267 if (ch == '%') {
1268 state = sw_quoted;
1269 break;
1270 }
1271
1272 *d++ = ch;
1273 break;
1274
1275 case sw_quoted:
1276
1277 if (ch >= '0' && ch <= '9') {
1278 decoded = (u_char) (ch - '0');
1279 state = sw_quoted_second;
1280 break;
1281 }
1282
1283 c = (u_char) (ch | 0x20);
1284 if (c >= 'a' && c <= 'f') {
1285 decoded = (u_char) (c - 'a' + 10);
1286 state = sw_quoted_second;
1287 break;
1288 }
1289
Igor Sysoev24025022005-12-16 15:07:08 +00001290 /* the invalid quoted character */
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +00001291
Igor Sysoev24025022005-12-16 15:07:08 +00001292 state = sw_usual;
1293
1294 *d++ = ch;
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +00001295
1296 break;
1297
1298 case sw_quoted_second:
1299
Igor Sysoev24025022005-12-16 15:07:08 +00001300 state = sw_usual;
1301
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +00001302 if (ch >= '0' && ch <= '9') {
1303 ch = (u_char) ((decoded << 4) + ch - '0');
1304
Igor Sysoevf0a51cf2007-10-22 10:19:17 +00001305 if (type & NGX_UNESCAPE_REDIRECT) {
Igor Sysoevae33d012006-01-17 20:04:32 +00001306 if (ch > '%' && ch < 0x7f) {
1307 *d++ = ch;
1308 break;
1309 }
1310
1311 *d++ = '%'; *d++ = *(s - 2); *d++ = *(s - 1);
1312
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +00001313 break;
1314 }
1315
Igor Sysoevae33d012006-01-17 20:04:32 +00001316 *d++ = ch;
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +00001317
1318 break;
1319 }
1320
1321 c = (u_char) (ch | 0x20);
1322 if (c >= 'a' && c <= 'f') {
1323 ch = (u_char) ((decoded << 4) + c - 'a' + 10);
1324
Igor Sysoevf0a51cf2007-10-22 10:19:17 +00001325 if (type & NGX_UNESCAPE_URI) {
1326 if (ch == '?') {
1327 *d++ = ch;
1328 goto done;
1329 }
1330
1331 *d++ = ch;
1332 break;
1333 }
1334
1335 if (type & NGX_UNESCAPE_REDIRECT) {
Igor Sysoevae33d012006-01-17 20:04:32 +00001336 if (ch == '?') {
1337 *d++ = ch;
1338 goto done;
1339 }
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +00001340
Igor Sysoevae33d012006-01-17 20:04:32 +00001341 if (ch > '%' && ch < 0x7f) {
1342 *d++ = ch;
1343 break;
1344 }
1345
1346 *d++ = '%'; *d++ = *(s - 2); *d++ = *(s - 1);
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +00001347 break;
1348 }
1349
Igor Sysoevae33d012006-01-17 20:04:32 +00001350 *d++ = ch;
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +00001351
1352 break;
1353 }
1354
Igor Sysoev24025022005-12-16 15:07:08 +00001355 /* the invalid quoted character */
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +00001356
1357 break;
1358 }
1359 }
1360
1361done:
1362
1363 *dst = d;
1364 *src = s;
1365}
Igor Sysoevd3283ff2005-12-05 13:18:09 +00001366
1367
Igor Sysoev1730c752007-09-27 09:36:50 +00001368uintptr_t
1369ngx_escape_html(u_char *dst, u_char *src, size_t size)
1370{
1371 u_char ch;
1372 ngx_uint_t i, len;
1373
1374 if (dst == NULL) {
1375
1376 len = 0;
1377
1378 for (i = 0; i < size; i++) {
1379 switch (*src++) {
1380
1381 case '<':
1382 len += sizeof("&lt;") - 2;
Igor Sysoevd3db9ea2007-10-09 18:42:00 +00001383 break;
Igor Sysoev1730c752007-09-27 09:36:50 +00001384
1385 case '>':
1386 len += sizeof("&gt;") - 2;
Igor Sysoevd3db9ea2007-10-09 18:42:00 +00001387 break;
Igor Sysoev1730c752007-09-27 09:36:50 +00001388
1389 case '&':
1390 len += sizeof("&amp;") - 2;
Igor Sysoevd3db9ea2007-10-09 18:42:00 +00001391 break;
Igor Sysoev1730c752007-09-27 09:36:50 +00001392
1393 default:
1394 break;
1395 }
1396 }
1397
1398 return (uintptr_t) len;
1399 }
1400
1401 for (i = 0; i < size; i++) {
1402 ch = *src++;
1403
1404 switch (ch) {
1405
1406 case '<':
1407 *dst++ = '&'; *dst++ = 'l'; *dst++ = 't'; *dst++ = ';';
1408 break;
1409
1410 case '>':
1411 *dst++ = '&'; *dst++ = 'g'; *dst++ = 't'; *dst++ = ';';
1412 break;
1413
1414 case '&':
1415 *dst++ = '&'; *dst++ = 'a'; *dst++ = 'm'; *dst++ = 'p';
1416 *dst++ = ';';
1417 break;
1418
1419 default:
1420 *dst++ = ch;
1421 break;
1422 }
1423 }
1424
1425 return (uintptr_t) dst;
1426}
1427
1428
Igor Sysoev35921282007-05-21 14:05:23 +00001429/* ngx_sort() is implemented as insertion sort because we need stable sort */
1430
1431void
1432ngx_sort(void *base, size_t n, size_t size,
Igor Sysoevde8ec1e2008-03-24 13:04:02 +00001433 ngx_int_t (*cmp)(const void *, const void *))
Igor Sysoev35921282007-05-21 14:05:23 +00001434{
Igor Sysoev86341182008-03-23 19:58:54 +00001435 u_char *p1, *p2, *p;
1436
1437 p = ngx_alloc(size, ngx_cycle->log);
1438 if (p == NULL) {
1439 return;
1440 }
Igor Sysoev35921282007-05-21 14:05:23 +00001441
1442 for (p1 = (u_char *) base + size;
1443 p1 < (u_char *) base + n * size;
1444 p1 += size)
1445 {
Igor Sysoev86341182008-03-23 19:58:54 +00001446 ngx_memcpy(p, p1, size);
Igor Sysoev35921282007-05-21 14:05:23 +00001447
1448 for (p2 = p1;
Igor Sysoev86341182008-03-23 19:58:54 +00001449 p2 > (u_char *) base && cmp(p2 - size, p) > 0;
Igor Sysoev35921282007-05-21 14:05:23 +00001450 p2 -= size)
1451 {
1452 ngx_memcpy(p2, p2 - size, size);
1453 }
1454
Igor Sysoev86341182008-03-23 19:58:54 +00001455 ngx_memcpy(p2, p, size);
Igor Sysoev35921282007-05-21 14:05:23 +00001456 }
Igor Sysoev86341182008-03-23 19:58:54 +00001457
1458 ngx_free(p);
Igor Sysoev35921282007-05-21 14:05:23 +00001459}
1460
1461
Igor Sysoevd3283ff2005-12-05 13:18:09 +00001462#if (NGX_MEMCPY_LIMIT)
1463
1464void *
1465ngx_memcpy(void *dst, void *src, size_t n)
1466{
1467 if (n > NGX_MEMCPY_LIMIT) {
1468 ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "memcpy %uz bytes", n);
1469 ngx_debug_point();
1470 }
1471
1472 return memcpy(dst, src, n);
1473}
1474
1475#endif