blob: 7a73ef527e891056968cd65b791bbbec27361fa2 [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
Maxim Konovalovf8d59e32012-01-18 15:07:43 +00004 * Copyright (C) Nginx, Inc.
Igor Sysoevd90282d2004-09-28 08:34:51 +00005 */
6
7
Igor Sysoev6de5c2c2002-08-06 16:39:45 +00008#include <ngx_config.h>
Igor Sysoevdc479b42003-03-20 16:09:44 +00009#include <ngx_core.h>
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000010
11
Igor Sysoev74b7e5f2008-11-10 15:20:59 +000012static u_char *ngx_sprintf_num(u_char *buf, u_char *last, uint64_t ui64,
13 u_char zero, ngx_uint_t hexadecimal, ngx_uint_t width);
Maxim Dounin7ac48da2014-02-04 04:59:21 +040014static void ngx_encode_base64_internal(ngx_str_t *dst, ngx_str_t *src,
15 const u_char *basis, ngx_uint_t padding);
Igor Sysoev94e9aaa2010-09-02 14:37:16 +000016static ngx_int_t ngx_decode_base64_internal(ngx_str_t *dst, ngx_str_t *src,
17 const u_char *basis);
Igor Sysoev74b7e5f2008-11-10 15:20:59 +000018
19
Igor Sysoev777b0192008-08-04 10:07:00 +000020void
21ngx_strlow(u_char *dst, u_char *src, size_t n)
22{
Igor Sysoev612ecb72009-11-02 17:12:09 +000023 while (n) {
Igor Sysoev777b0192008-08-04 10:07:00 +000024 *dst = ngx_tolower(*src);
25 dst++;
26 src++;
Igor Sysoev612ecb72009-11-02 17:12:09 +000027 n--;
Igor Sysoev777b0192008-08-04 10:07:00 +000028 }
29}
30
31
Igor Sysoevd039a2e2005-02-22 14:40:13 +000032u_char *
33ngx_cpystrn(u_char *dst, u_char *src, size_t n)
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000034{
Igor Sysoev3d09c8d2003-05-06 17:03:16 +000035 if (n == 0) {
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000036 return dst;
Igor Sysoev3d09c8d2003-05-06 17:03:16 +000037 }
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000038
Igor Sysoev8e5f0ac2009-06-05 12:33:49 +000039 while (--n) {
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000040 *dst = *src;
41
Igor Sysoev3d09c8d2003-05-06 17:03:16 +000042 if (*dst == '\0') {
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000043 return dst;
Igor Sysoev3d09c8d2003-05-06 17:03:16 +000044 }
Igor Sysoev8e5f0ac2009-06-05 12:33:49 +000045
46 dst++;
47 src++;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000048 }
49
50 *dst = '\0';
51
52 return dst;
53}
Igor Sysoevdc479b42003-03-20 16:09:44 +000054
55
Igor Sysoevd039a2e2005-02-22 14:40:13 +000056u_char *
57ngx_pstrdup(ngx_pool_t *pool, ngx_str_t *src)
Igor Sysoev805d9db2005-02-03 19:33:37 +000058{
59 u_char *dst;
60
Igor Sysoev7f6b2ff2008-06-17 15:00:30 +000061 dst = ngx_pnalloc(pool, src->len);
Igor Sysoevc1571722005-03-19 12:38:37 +000062 if (dst == NULL) {
Igor Sysoev805d9db2005-02-03 19:33:37 +000063 return NULL;
64 }
65
66 ngx_memcpy(dst, src->data, src->len);
67
68 return dst;
69}
70
71
Igor Sysoevc0edbcc2004-10-21 15:34:38 +000072/*
73 * supported formats:
Igor Sysoev42b12b32004-12-02 18:40:46 +000074 * %[0][width][x][X]O off_t
Igor Sysoev1b735832004-11-11 14:07:14 +000075 * %[0][width]T time_t
76 * %[0][width][u][x|X]z ssize_t/size_t
77 * %[0][width][u][x|X]d int/u_int
78 * %[0][width][u][x|X]l long
79 * %[0][width|m][u][x|X]i ngx_int_t/ngx_uint_t
80 * %[0][width][u][x|X]D int32_t/uint32_t
81 * %[0][width][u][x|X]L int64_t/uint64_t
Igor Sysoev4a715592005-02-24 12:29:09 +000082 * %[0][width|m][u][x|X]A ngx_atomic_int_t/ngx_atomic_uint_t
Igor Sysoev503b9712010-05-12 13:12:31 +000083 * %[0][width][.width]f double, max valid number fits to %18.15f
Igor Sysoev1b735832004-11-11 14:07:14 +000084 * %P ngx_pid_t
Igor Sysoev208eed22005-10-07 13:30:52 +000085 * %M ngx_msec_t
Igor Sysoev1b735832004-11-11 14:07:14 +000086 * %r rlim_t
Igor Sysoev0d4b3722007-08-20 09:57:19 +000087 * %p void *
88 * %V ngx_str_t *
89 * %v ngx_variable_value_t *
Igor Sysoev1b735832004-11-11 14:07:14 +000090 * %s null-terminated string
Igor Sysoev79d9a042007-12-24 17:05:16 +000091 * %*s length and string
Igor Sysoev1b735832004-11-11 14:07:14 +000092 * %Z '\0'
Igor Sysoev85ef94b2005-06-23 13:41:06 +000093 * %N '\n'
Igor Sysoev1b735832004-11-11 14:07:14 +000094 * %c char
95 * %% %
Igor Sysoevc0edbcc2004-10-21 15:34:38 +000096 *
Igor Sysoev1b735832004-11-11 14:07:14 +000097 * reserved:
98 * %t ptrdiff_t
Igor Sysoev9262c612009-08-26 15:03:53 +000099 * %S null-terminated wchar string
Igor Sysoev1b735832004-11-11 14:07:14 +0000100 * %C wchar
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000101 */
102
Igor Sysoev1b735832004-11-11 14:07:14 +0000103
Igor Sysoev4d656dc2005-03-22 16:02:46 +0000104u_char * ngx_cdecl
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000105ngx_sprintf(u_char *buf, const char *fmt, ...)
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000106{
Igor Sysoev1b735832004-11-11 14:07:14 +0000107 u_char *p;
108 va_list args;
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000109
Igor Sysoev1b735832004-11-11 14:07:14 +0000110 va_start(args, fmt);
Igor Sysoev4e1fe032009-04-27 12:51:33 +0000111 p = ngx_vslprintf(buf, (void *) -1, fmt, args);
Igor Sysoev1b735832004-11-11 14:07:14 +0000112 va_end(args);
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000113
Igor Sysoev1b735832004-11-11 14:07:14 +0000114 return p;
115}
116
117
Igor Sysoev4d656dc2005-03-22 16:02:46 +0000118u_char * ngx_cdecl
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000119ngx_snprintf(u_char *buf, size_t max, const char *fmt, ...)
Igor Sysoev1b735832004-11-11 14:07:14 +0000120{
121 u_char *p;
122 va_list args;
123
124 va_start(args, fmt);
Igor Sysoev4e1fe032009-04-27 12:51:33 +0000125 p = ngx_vslprintf(buf, buf + max, fmt, args);
126 va_end(args);
127
128 return p;
129}
130
131
132u_char * ngx_cdecl
133ngx_slprintf(u_char *buf, u_char *last, const char *fmt, ...)
134{
135 u_char *p;
136 va_list args;
137
138 va_start(args, fmt);
139 p = ngx_vslprintf(buf, last, fmt, args);
Igor Sysoev1b735832004-11-11 14:07:14 +0000140 va_end(args);
141
142 return p;
143}
144
145
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000146u_char *
Igor Sysoev4e1fe032009-04-27 12:51:33 +0000147ngx_vslprintf(u_char *buf, u_char *last, const char *fmt, va_list args)
Igor Sysoev1b735832004-11-11 14:07:14 +0000148{
Igor Sysoev4e1fe032009-04-27 12:51:33 +0000149 u_char *p, zero;
Igor Sysoevf42ed052007-07-17 09:23:23 +0000150 int d;
Igor Sysoevc7bb66a2012-04-23 11:11:32 +0000151 double f;
Igor Sysoev79d9a042007-12-24 17:05:16 +0000152 size_t len, slen;
Igor Sysoevf42ed052007-07-17 09:23:23 +0000153 int64_t i64;
Igor Sysoevc7bb66a2012-04-23 11:11:32 +0000154 uint64_t ui64, frac;
Igor Sysoevf42ed052007-07-17 09:23:23 +0000155 ngx_msec_t ms;
Igor Sysoevc7bb66a2012-04-23 11:11:32 +0000156 ngx_uint_t width, sign, hex, max_width, frac_width, scale, n;
Igor Sysoev0d4b3722007-08-20 09:57:19 +0000157 ngx_str_t *v;
158 ngx_variable_value_t *vv;
Igor Sysoev1b735832004-11-11 14:07:14 +0000159
Igor Sysoev1b735832004-11-11 14:07:14 +0000160 while (*fmt && buf < last) {
161
162 /*
163 * "buf < last" means that we could copy at least one character:
164 * the plain character, "%%", "%c", and minus without the checking
165 */
166
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000167 if (*fmt == '%') {
168
Igor Sysoev1b735832004-11-11 14:07:14 +0000169 i64 = 0;
170 ui64 = 0;
171
172 zero = (u_char) ((*++fmt == '0') ? '0' : ' ');
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000173 width = 0;
174 sign = 1;
Igor Sysoev74b7e5f2008-11-10 15:20:59 +0000175 hex = 0;
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000176 max_width = 0;
Igor Sysoev74b7e5f2008-11-10 15:20:59 +0000177 frac_width = 0;
Igor Sysoev0bd32b72008-01-22 15:13:01 +0000178 slen = (size_t) -1;
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000179
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000180 while (*fmt >= '0' && *fmt <= '9') {
181 width = width * 10 + *fmt++ - '0';
182 }
183
184
185 for ( ;; ) {
186 switch (*fmt) {
187
188 case 'u':
189 sign = 0;
190 fmt++;
191 continue;
192
Igor Sysoevd43bee82004-11-20 19:52:20 +0000193 case 'm':
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000194 max_width = 1;
Igor Sysoevd43bee82004-11-20 19:52:20 +0000195 fmt++;
196 continue;
197
Igor Sysoev1b735832004-11-11 14:07:14 +0000198 case 'X':
Igor Sysoev74b7e5f2008-11-10 15:20:59 +0000199 hex = 2;
Igor Sysoev1b735832004-11-11 14:07:14 +0000200 sign = 0;
201 fmt++;
202 continue;
203
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000204 case 'x':
Igor Sysoev74b7e5f2008-11-10 15:20:59 +0000205 hex = 1;
Igor Sysoev1b735832004-11-11 14:07:14 +0000206 sign = 0;
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000207 fmt++;
208 continue;
209
Igor Sysoev74b7e5f2008-11-10 15:20:59 +0000210 case '.':
211 fmt++;
212
213 while (*fmt >= '0' && *fmt <= '9') {
214 frac_width = frac_width * 10 + *fmt++ - '0';
215 }
216
217 break;
218
Igor Sysoev79d9a042007-12-24 17:05:16 +0000219 case '*':
Igor Sysoevfb424652008-01-24 15:18:17 +0000220 slen = va_arg(args, size_t);
Igor Sysoev79d9a042007-12-24 17:05:16 +0000221 fmt++;
222 continue;
223
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000224 default:
225 break;
226 }
227
228 break;
229 }
230
231
232 switch (*fmt) {
233
Igor Sysoev1b735832004-11-11 14:07:14 +0000234 case 'V':
Igor Sysoev0d4b3722007-08-20 09:57:19 +0000235 v = va_arg(args, ngx_str_t *);
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000236
Igor Sysoev328df7a2010-05-14 09:55:33 +0000237 len = ngx_min(((size_t) (last - buf)), v->len);
Igor Sysoevf42ed052007-07-17 09:23:23 +0000238 buf = ngx_cpymem(buf, v->data, len);
Igor Sysoev1b735832004-11-11 14:07:14 +0000239 fmt++;
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000240
Igor Sysoev1b735832004-11-11 14:07:14 +0000241 continue;
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000242
Igor Sysoev0d4b3722007-08-20 09:57:19 +0000243 case 'v':
244 vv = va_arg(args, ngx_variable_value_t *);
245
Igor Sysoev328df7a2010-05-14 09:55:33 +0000246 len = ngx_min(((size_t) (last - buf)), vv->len);
Igor Sysoev0d4b3722007-08-20 09:57:19 +0000247 buf = ngx_cpymem(buf, vv->data, len);
248 fmt++;
249
250 continue;
251
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000252 case 's':
Igor Sysoev1b735832004-11-11 14:07:14 +0000253 p = va_arg(args, u_char *);
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000254
Igor Sysoev0bd32b72008-01-22 15:13:01 +0000255 if (slen == (size_t) -1) {
Igor Sysoev79d9a042007-12-24 17:05:16 +0000256 while (*p && buf < last) {
257 *buf++ = *p++;
258 }
259
260 } else {
Igor Sysoev328df7a2010-05-14 09:55:33 +0000261 len = ngx_min(((size_t) (last - buf)), slen);
Igor Sysoev16315762008-01-24 15:18:58 +0000262 buf = ngx_cpymem(buf, p, len);
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000263 }
Igor Sysoev79d9a042007-12-24 17:05:16 +0000264
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000265 fmt++;
266
267 continue;
268
Igor Sysoev1b735832004-11-11 14:07:14 +0000269 case 'O':
270 i64 = (int64_t) va_arg(args, off_t);
271 sign = 1;
272 break;
273
274 case 'P':
275 i64 = (int64_t) va_arg(args, ngx_pid_t);
276 sign = 1;
277 break;
278
279 case 'T':
280 i64 = (int64_t) va_arg(args, time_t);
281 sign = 1;
282 break;
283
Igor Sysoev208eed22005-10-07 13:30:52 +0000284 case 'M':
Igor Sysoev78452232005-10-12 13:50:36 +0000285 ms = (ngx_msec_t) va_arg(args, ngx_msec_t);
286 if ((ngx_msec_int_t) ms == -1) {
287 sign = 1;
288 i64 = -1;
289 } else {
290 sign = 0;
291 ui64 = (uint64_t) ms;
292 }
Igor Sysoev208eed22005-10-07 13:30:52 +0000293 break;
294
Igor Sysoev1b735832004-11-11 14:07:14 +0000295 case 'z':
296 if (sign) {
297 i64 = (int64_t) va_arg(args, ssize_t);
298 } else {
299 ui64 = (uint64_t) va_arg(args, size_t);
300 }
301 break;
302
303 case 'i':
304 if (sign) {
305 i64 = (int64_t) va_arg(args, ngx_int_t);
306 } else {
307 ui64 = (uint64_t) va_arg(args, ngx_uint_t);
308 }
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000309
310 if (max_width) {
311 width = NGX_INT_T_LEN;
312 }
313
Igor Sysoev1b735832004-11-11 14:07:14 +0000314 break;
315
316 case 'd':
317 if (sign) {
318 i64 = (int64_t) va_arg(args, int);
319 } else {
320 ui64 = (uint64_t) va_arg(args, u_int);
321 }
322 break;
323
324 case 'l':
325 if (sign) {
326 i64 = (int64_t) va_arg(args, long);
327 } else {
328 ui64 = (uint64_t) va_arg(args, u_long);
329 }
330 break;
331
332 case 'D':
333 if (sign) {
334 i64 = (int64_t) va_arg(args, int32_t);
335 } else {
336 ui64 = (uint64_t) va_arg(args, uint32_t);
337 }
338 break;
339
340 case 'L':
341 if (sign) {
342 i64 = va_arg(args, int64_t);
343 } else {
344 ui64 = va_arg(args, uint64_t);
345 }
346 break;
347
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000348 case 'A':
349 if (sign) {
350 i64 = (int64_t) va_arg(args, ngx_atomic_int_t);
351 } else {
Igor Sysoev4a715592005-02-24 12:29:09 +0000352 ui64 = (uint64_t) va_arg(args, ngx_atomic_uint_t);
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000353 }
354
355 if (max_width) {
356 width = NGX_ATOMIC_T_LEN;
357 }
358
359 break;
360
Igor Sysoev74b7e5f2008-11-10 15:20:59 +0000361 case 'f':
Igor Sysoev503b9712010-05-12 13:12:31 +0000362 f = va_arg(args, double);
Igor Sysoev74b7e5f2008-11-10 15:20:59 +0000363
364 if (f < 0) {
365 *buf++ = '-';
366 f = -f;
367 }
368
369 ui64 = (int64_t) f;
Igor Sysoevc7bb66a2012-04-23 11:11:32 +0000370 frac = 0;
371
372 if (frac_width) {
373
374 scale = 1;
375 for (n = frac_width; n; n--) {
376 scale *= 10;
377 }
378
379 frac = (uint64_t) ((f - (double) ui64) * scale + 0.5);
380
381 if (frac == scale) {
382 ui64++;
383 frac = 0;
384 }
385 }
Igor Sysoev74b7e5f2008-11-10 15:20:59 +0000386
387 buf = ngx_sprintf_num(buf, last, ui64, zero, 0, width);
388
389 if (frac_width) {
Igor Sysoev74b7e5f2008-11-10 15:20:59 +0000390 if (buf < last) {
391 *buf++ = '.';
392 }
393
Igor Sysoevc7bb66a2012-04-23 11:11:32 +0000394 buf = ngx_sprintf_num(buf, last, frac, '0', 0, frac_width);
Igor Sysoev74b7e5f2008-11-10 15:20:59 +0000395 }
396
397 fmt++;
398
399 continue;
400
Igor Sysoev1b735832004-11-11 14:07:14 +0000401#if !(NGX_WIN32)
402 case 'r':
403 i64 = (int64_t) va_arg(args, rlim_t);
404 sign = 1;
405 break;
406#endif
407
408 case 'p':
409 ui64 = (uintptr_t) va_arg(args, void *);
Igor Sysoev74b7e5f2008-11-10 15:20:59 +0000410 hex = 2;
Igor Sysoev1b735832004-11-11 14:07:14 +0000411 sign = 0;
412 zero = '0';
Maxim Dounin9b2bc9c2015-12-03 20:06:45 +0300413 width = 2 * sizeof(void *);
Igor Sysoev1b735832004-11-11 14:07:14 +0000414 break;
415
Igor Sysoev723e6cc2004-10-25 15:29:23 +0000416 case 'c':
Igor Sysoev1b735832004-11-11 14:07:14 +0000417 d = va_arg(args, int);
Igor Sysoev723e6cc2004-10-25 15:29:23 +0000418 *buf++ = (u_char) (d & 0xff);
419 fmt++;
420
421 continue;
422
Igor Sysoev1b735832004-11-11 14:07:14 +0000423 case 'Z':
424 *buf++ = '\0';
425 fmt++;
426
427 continue;
428
Igor Sysoev85ef94b2005-06-23 13:41:06 +0000429 case 'N':
430#if (NGX_WIN32)
431 *buf++ = CR;
Igor Sysoevafa38fc2015-01-27 15:38:15 +0300432 if (buf < last) {
433 *buf++ = LF;
434 }
435#else
Igor Sysoev85ef94b2005-06-23 13:41:06 +0000436 *buf++ = LF;
Igor Sysoevafa38fc2015-01-27 15:38:15 +0300437#endif
Igor Sysoev85ef94b2005-06-23 13:41:06 +0000438 fmt++;
439
440 continue;
441
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000442 case '%':
443 *buf++ = '%';
444 fmt++;
445
446 continue;
447
448 default:
449 *buf++ = *fmt++;
450
451 continue;
452 }
453
Igor Sysoev1b735832004-11-11 14:07:14 +0000454 if (sign) {
455 if (i64 < 0) {
456 *buf++ = '-';
457 ui64 = (uint64_t) -i64;
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000458
Igor Sysoev1b735832004-11-11 14:07:14 +0000459 } else {
460 ui64 = (uint64_t) i64;
461 }
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000462 }
463
Igor Sysoev74b7e5f2008-11-10 15:20:59 +0000464 buf = ngx_sprintf_num(buf, last, ui64, zero, hex, width);
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000465
466 fmt++;
467
468 } else {
469 *buf++ = *fmt++;
470 }
471 }
472
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000473 return buf;
474}
475
476
Igor Sysoev74b7e5f2008-11-10 15:20:59 +0000477static u_char *
478ngx_sprintf_num(u_char *buf, u_char *last, uint64_t ui64, u_char zero,
479 ngx_uint_t hexadecimal, ngx_uint_t width)
480{
481 u_char *p, temp[NGX_INT64_LEN + 1];
482 /*
483 * we need temp[NGX_INT64_LEN] only,
484 * but icc issues the warning
485 */
486 size_t len;
487 uint32_t ui32;
488 static u_char hex[] = "0123456789abcdef";
489 static u_char HEX[] = "0123456789ABCDEF";
490
491 p = temp + NGX_INT64_LEN;
492
493 if (hexadecimal == 0) {
494
Maxim Dounin5b378522013-09-04 20:48:22 +0400495 if (ui64 <= (uint64_t) NGX_MAX_UINT32_VALUE) {
Igor Sysoev74b7e5f2008-11-10 15:20:59 +0000496
497 /*
498 * To divide 64-bit numbers and to find remainders
499 * on the x86 platform gcc and icc call the libc functions
500 * [u]divdi3() and [u]moddi3(), they call another function
501 * in its turn. On FreeBSD it is the qdivrem() function,
502 * its source code is about 170 lines of the code.
503 * The glibc counterpart is about 150 lines of the code.
504 *
505 * For 32-bit numbers and some divisors gcc and icc use
506 * a inlined multiplication and shifts. For example,
507 * unsigned "i32 / 10" is compiled to
508 *
509 * (i32 * 0xCCCCCCCD) >> 35
510 */
511
512 ui32 = (uint32_t) ui64;
513
514 do {
515 *--p = (u_char) (ui32 % 10 + '0');
516 } while (ui32 /= 10);
517
518 } else {
519 do {
520 *--p = (u_char) (ui64 % 10 + '0');
521 } while (ui64 /= 10);
522 }
523
524 } else if (hexadecimal == 1) {
525
526 do {
527
528 /* the "(uint32_t)" cast disables the BCC's warning */
529 *--p = hex[(uint32_t) (ui64 & 0xf)];
530
531 } while (ui64 >>= 4);
532
533 } else { /* hexadecimal == 2 */
534
535 do {
536
537 /* the "(uint32_t)" cast disables the BCC's warning */
538 *--p = HEX[(uint32_t) (ui64 & 0xf)];
539
540 } while (ui64 >>= 4);
541 }
542
543 /* zero or space padding */
544
545 len = (temp + NGX_INT64_LEN) - p;
546
547 while (len++ < width && buf < last) {
548 *buf++ = zero;
549 }
550
551 /* number safe copy */
552
553 len = (temp + NGX_INT64_LEN) - p;
554
555 if (buf + len > last) {
556 len = last - buf;
557 }
558
559 return ngx_cpymem(buf, p, len);
560}
561
562
Igor Sysoev722231f2007-02-14 18:51:19 +0000563/*
Igor Sysoev066e6322007-09-26 12:23:34 +0000564 * We use ngx_strcasecmp()/ngx_strncasecmp() for 7-bit ASCII strings only,
Igor Sysoev722231f2007-02-14 18:51:19 +0000565 * and implement our own ngx_strcasecmp()/ngx_strncasecmp()
566 * to avoid libc locale overhead. Besides, we use the ngx_uint_t's
567 * instead of the u_char's, because they are slightly faster.
568 */
569
570ngx_int_t
571ngx_strcasecmp(u_char *s1, u_char *s2)
572{
573 ngx_uint_t c1, c2;
574
575 for ( ;; ) {
576 c1 = (ngx_uint_t) *s1++;
577 c2 = (ngx_uint_t) *s2++;
578
Igor Sysoeve0f1d0a2009-09-11 13:57:50 +0000579 c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;
580 c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;
Igor Sysoev722231f2007-02-14 18:51:19 +0000581
582 if (c1 == c2) {
583
584 if (c1) {
585 continue;
586 }
587
588 return 0;
589 }
590
591 return c1 - c2;
592 }
593}
594
595
596ngx_int_t
597ngx_strncasecmp(u_char *s1, u_char *s2, size_t n)
598{
599 ngx_uint_t c1, c2;
600
601 while (n) {
602 c1 = (ngx_uint_t) *s1++;
603 c2 = (ngx_uint_t) *s2++;
604
Igor Sysoeve0f1d0a2009-09-11 13:57:50 +0000605 c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;
606 c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;
Igor Sysoev722231f2007-02-14 18:51:19 +0000607
608 if (c1 == c2) {
609
610 if (c1) {
611 n--;
612 continue;
613 }
614
615 return 0;
616 }
617
618 return c1 - c2;
619 }
620
621 return 0;
622}
623
624
Igor Sysoev35fe5fd2007-10-01 14:48:33 +0000625u_char *
626ngx_strnstr(u_char *s1, char *s2, size_t len)
627{
628 u_char c1, c2;
629 size_t n;
630
631 c2 = *(u_char *) s2++;
632
633 n = ngx_strlen(s2);
634
635 do {
636 do {
637 if (len-- == 0) {
638 return NULL;
639 }
640
641 c1 = *s1++;
642
643 if (c1 == 0) {
644 return NULL;
645 }
646
647 } while (c1 != c2);
648
649 if (n > len) {
650 return NULL;
651 }
652
653 } while (ngx_strncmp(s1, (u_char *) s2, n) != 0);
654
655 return --s1;
656}
657
658
Igor Sysoev66697022007-10-01 13:00:30 +0000659/*
660 * ngx_strstrn() and ngx_strcasestrn() are intended to search for static
661 * substring with known length in null-terminated string. The argument n
662 * must be length of the second substring - 1.
663 */
664
Igor Sysoev1bd98702007-09-26 19:25:52 +0000665u_char *
666ngx_strstrn(u_char *s1, char *s2, size_t n)
667{
668 u_char c1, c2;
669
670 c2 = *(u_char *) s2++;
671
672 do {
673 do {
674 c1 = *s1++;
675
676 if (c1 == 0) {
677 return NULL;
678 }
679
680 } while (c1 != c2);
681
682 } while (ngx_strncmp(s1, (u_char *) s2, n) != 0);
683
684 return --s1;
685}
686
687
688u_char *
689ngx_strcasestrn(u_char *s1, char *s2, size_t n)
690{
691 ngx_uint_t c1, c2;
692
693 c2 = (ngx_uint_t) *s2++;
Igor Sysoeve0f1d0a2009-09-11 13:57:50 +0000694 c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;
Igor Sysoev1bd98702007-09-26 19:25:52 +0000695
696 do {
697 do {
698 c1 = (ngx_uint_t) *s1++;
699
700 if (c1 == 0) {
701 return NULL;
702 }
703
Igor Sysoeve0f1d0a2009-09-11 13:57:50 +0000704 c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;
Igor Sysoev1bd98702007-09-26 19:25:52 +0000705
706 } while (c1 != c2);
707
708 } while (ngx_strncasecmp(s1, (u_char *) s2, n) != 0);
709
710 return --s1;
711}
712
713
Igor Sysoeva514d682009-04-04 17:31:54 +0000714/*
715 * ngx_strlcasestrn() is intended to search for static substring
716 * with known length in string until the argument last. The argument n
717 * must be length of the second substring - 1.
718 */
719
720u_char *
721ngx_strlcasestrn(u_char *s1, u_char *last, u_char *s2, size_t n)
722{
723 ngx_uint_t c1, c2;
724
725 c2 = (ngx_uint_t) *s2++;
Igor Sysoeve0f1d0a2009-09-11 13:57:50 +0000726 c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;
Igor Sysoeva514d682009-04-04 17:31:54 +0000727 last -= n;
728
729 do {
730 do {
Igor Sysoevd5ba36f2009-04-06 11:42:42 +0000731 if (s1 >= last) {
Igor Sysoeva514d682009-04-04 17:31:54 +0000732 return NULL;
733 }
734
735 c1 = (ngx_uint_t) *s1++;
736
Igor Sysoeve0f1d0a2009-09-11 13:57:50 +0000737 c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;
Igor Sysoeva514d682009-04-04 17:31:54 +0000738
739 } while (c1 != c2);
740
741 } while (ngx_strncasecmp(s1, s2, n) != 0);
742
743 return --s1;
744}
745
746
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000747ngx_int_t
748ngx_rstrncmp(u_char *s1, u_char *s2, size_t n)
Igor Sysoev3d09c8d2003-05-06 17:03:16 +0000749{
750 if (n == 0) {
751 return 0;
752 }
753
754 n--;
755
756 for ( ;; ) {
757 if (s1[n] != s2[n]) {
Igor Sysoev10a543a2004-03-16 07:10:12 +0000758 return s1[n] - s2[n];
Igor Sysoev3d09c8d2003-05-06 17:03:16 +0000759 }
760
761 if (n == 0) {
762 return 0;
763 }
764
765 n--;
766 }
767}
768
769
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000770ngx_int_t
771ngx_rstrncasecmp(u_char *s1, u_char *s2, size_t n)
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000772{
773 u_char c1, c2;
774
775 if (n == 0) {
776 return 0;
777 }
778
779 n--;
780
781 for ( ;; ) {
782 c1 = s1[n];
783 if (c1 >= 'a' && c1 <= 'z') {
784 c1 -= 'a' - 'A';
785 }
786
787 c2 = s2[n];
788 if (c2 >= 'a' && c2 <= 'z') {
789 c2 -= 'a' - 'A';
790 }
791
792 if (c1 != c2) {
793 return c1 - c2;
794 }
795
796 if (n == 0) {
797 return 0;
798 }
799
800 n--;
801 }
802}
803
804
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000805ngx_int_t
Igor Sysoevec3cabd2007-01-12 21:58:02 +0000806ngx_memn2cmp(u_char *s1, u_char *s2, size_t n1, size_t n2)
Igor Sysoev37cc1652007-01-12 20:15:59 +0000807{
808 size_t n;
809 ngx_int_t m, z;
810
811 if (n1 <= n2) {
812 n = n1;
813 z = -1;
814
815 } else {
816 n = n2;
817 z = 1;
818 }
819
Igor Sysoevec3cabd2007-01-12 21:58:02 +0000820 m = ngx_memcmp(s1, s2, n);
Igor Sysoev37cc1652007-01-12 20:15:59 +0000821
822 if (m || n1 == n2) {
823 return m;
824 }
825
826 return z;
827}
828
829
830ngx_int_t
Igor Sysoev96e36ef2009-09-12 09:28:37 +0000831ngx_dns_strcmp(u_char *s1, u_char *s2)
832{
833 ngx_uint_t c1, c2;
834
835 for ( ;; ) {
836 c1 = (ngx_uint_t) *s1++;
837 c2 = (ngx_uint_t) *s2++;
838
839 c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;
840 c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;
841
842 if (c1 == c2) {
843
844 if (c1) {
845 continue;
846 }
847
848 return 0;
849 }
850
851 /* in ASCII '.' > '-', but we need '.' to be the lowest character */
852
853 c1 = (c1 == '.') ? ' ' : c1;
854 c2 = (c2 == '.') ? ' ' : c2;
855
856 return c1 - c2;
857 }
858}
859
860
861ngx_int_t
Maxim Dounine1158412013-09-23 19:37:13 +0400862ngx_filename_cmp(u_char *s1, u_char *s2, size_t n)
863{
864 ngx_uint_t c1, c2;
865
866 while (n) {
867 c1 = (ngx_uint_t) *s1++;
868 c2 = (ngx_uint_t) *s2++;
869
870#if (NGX_HAVE_CASELESS_FILESYSTEM)
871 c1 = tolower(c1);
872 c2 = tolower(c2);
873#endif
874
875 if (c1 == c2) {
876
877 if (c1) {
878 n--;
879 continue;
880 }
881
882 return 0;
883 }
884
885 /* we need '/' to be the lowest character */
886
887 if (c1 == 0 || c2 == 0) {
888 return c1 - c2;
889 }
890
891 c1 = (c1 == '/') ? 0 : c1;
892 c2 = (c2 == '/') ? 0 : c2;
893
894 return c1 - c2;
895 }
896
897 return 0;
898}
899
900
901ngx_int_t
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000902ngx_atoi(u_char *line, size_t n)
Igor Sysoevdc479b42003-03-20 16:09:44 +0000903{
Ruslan Ermilov2a54e4b2015-03-17 00:26:15 +0300904 ngx_int_t value, cutoff, cutlim;
Igor Sysoevdc479b42003-03-20 16:09:44 +0000905
Igor Sysoev3d09c8d2003-05-06 17:03:16 +0000906 if (n == 0) {
907 return NGX_ERROR;
908 }
909
Ruslan Ermilov2a54e4b2015-03-17 00:26:15 +0300910 cutoff = NGX_MAX_INT_T_VALUE / 10;
911 cutlim = NGX_MAX_INT_T_VALUE % 10;
912
Igor Sysoevdc479b42003-03-20 16:09:44 +0000913 for (value = 0; n--; line++) {
Igor Sysoev1d8d9ee2003-04-28 15:06:39 +0000914 if (*line < '0' || *line > '9') {
915 return NGX_ERROR;
916 }
Igor Sysoevdc479b42003-03-20 16:09:44 +0000917
Ruslan Ermilov2a54e4b2015-03-17 00:26:15 +0300918 if (value >= cutoff && (value > cutoff || *line - '0' > cutlim)) {
919 return NGX_ERROR;
920 }
921
Igor Sysoev1d8d9ee2003-04-28 15:06:39 +0000922 value = value * 10 + (*line - '0');
Igor Sysoevdc479b42003-03-20 16:09:44 +0000923 }
924
Ruslan Ermilov2a54e4b2015-03-17 00:26:15 +0300925 return value;
Igor Sysoev18684bd2004-05-20 17:33:52 +0000926}
927
928
Igor Sysoevd2b687c2010-05-14 09:01:30 +0000929/* parse a fixed point number, e.g., ngx_atofp("10.5", 4, 2) returns 1050 */
930
931ngx_int_t
932ngx_atofp(u_char *line, size_t n, size_t point)
933{
Ruslan Ermilov2a54e4b2015-03-17 00:26:15 +0300934 ngx_int_t value, cutoff, cutlim;
Igor Sysoevd2b687c2010-05-14 09:01:30 +0000935 ngx_uint_t dot;
936
937 if (n == 0) {
938 return NGX_ERROR;
939 }
940
Ruslan Ermilov2a54e4b2015-03-17 00:26:15 +0300941 cutoff = NGX_MAX_INT_T_VALUE / 10;
942 cutlim = NGX_MAX_INT_T_VALUE % 10;
943
Igor Sysoevd2b687c2010-05-14 09:01:30 +0000944 dot = 0;
945
946 for (value = 0; n--; line++) {
947
948 if (point == 0) {
949 return NGX_ERROR;
950 }
951
952 if (*line == '.') {
953 if (dot) {
954 return NGX_ERROR;
955 }
956
957 dot = 1;
958 continue;
959 }
960
961 if (*line < '0' || *line > '9') {
962 return NGX_ERROR;
963 }
964
Ruslan Ermilov2a54e4b2015-03-17 00:26:15 +0300965 if (value >= cutoff && (value > cutoff || *line - '0' > cutlim)) {
966 return NGX_ERROR;
967 }
968
Igor Sysoevd2b687c2010-05-14 09:01:30 +0000969 value = value * 10 + (*line - '0');
970 point -= dot;
971 }
972
973 while (point--) {
Ruslan Ermilov2a54e4b2015-03-17 00:26:15 +0300974 if (value > cutoff) {
975 return NGX_ERROR;
976 }
977
Igor Sysoevd2b687c2010-05-14 09:01:30 +0000978 value = value * 10;
979 }
980
Ruslan Ermilov2a54e4b2015-03-17 00:26:15 +0300981 return value;
Igor Sysoevd2b687c2010-05-14 09:01:30 +0000982}
983
984
Igor Sysoevc1571722005-03-19 12:38:37 +0000985ssize_t
986ngx_atosz(u_char *line, size_t n)
987{
Ruslan Ermilov2a54e4b2015-03-17 00:26:15 +0300988 ssize_t value, cutoff, cutlim;
Igor Sysoevc1571722005-03-19 12:38:37 +0000989
990 if (n == 0) {
991 return NGX_ERROR;
992 }
993
Ruslan Ermilov2a54e4b2015-03-17 00:26:15 +0300994 cutoff = NGX_MAX_SIZE_T_VALUE / 10;
995 cutlim = NGX_MAX_SIZE_T_VALUE % 10;
996
Igor Sysoevc1571722005-03-19 12:38:37 +0000997 for (value = 0; n--; line++) {
998 if (*line < '0' || *line > '9') {
999 return NGX_ERROR;
1000 }
1001
Ruslan Ermilov2a54e4b2015-03-17 00:26:15 +03001002 if (value >= cutoff && (value > cutoff || *line - '0' > cutlim)) {
1003 return NGX_ERROR;
1004 }
1005
Igor Sysoevc1571722005-03-19 12:38:37 +00001006 value = value * 10 + (*line - '0');
1007 }
1008
Ruslan Ermilov2a54e4b2015-03-17 00:26:15 +03001009 return value;
Igor Sysoevc1571722005-03-19 12:38:37 +00001010}
1011
1012
1013off_t
1014ngx_atoof(u_char *line, size_t n)
1015{
Ruslan Ermilov2a54e4b2015-03-17 00:26:15 +03001016 off_t value, cutoff, cutlim;
Igor Sysoevc1571722005-03-19 12:38:37 +00001017
1018 if (n == 0) {
1019 return NGX_ERROR;
1020 }
1021
Ruslan Ermilov2a54e4b2015-03-17 00:26:15 +03001022 cutoff = NGX_MAX_OFF_T_VALUE / 10;
1023 cutlim = NGX_MAX_OFF_T_VALUE % 10;
1024
Igor Sysoevc1571722005-03-19 12:38:37 +00001025 for (value = 0; n--; line++) {
1026 if (*line < '0' || *line > '9') {
1027 return NGX_ERROR;
1028 }
1029
Ruslan Ermilov2a54e4b2015-03-17 00:26:15 +03001030 if (value >= cutoff && (value > cutoff || *line - '0' > cutlim)) {
1031 return NGX_ERROR;
1032 }
1033
Igor Sysoevc1571722005-03-19 12:38:37 +00001034 value = value * 10 + (*line - '0');
1035 }
1036
Ruslan Ermilov2a54e4b2015-03-17 00:26:15 +03001037 return value;
Igor Sysoevc1571722005-03-19 12:38:37 +00001038}
1039
1040
1041time_t
1042ngx_atotm(u_char *line, size_t n)
1043{
Ruslan Ermilov2a54e4b2015-03-17 00:26:15 +03001044 time_t value, cutoff, cutlim;
Igor Sysoevc1571722005-03-19 12:38:37 +00001045
1046 if (n == 0) {
1047 return NGX_ERROR;
1048 }
1049
Ruslan Ermilov2a54e4b2015-03-17 00:26:15 +03001050 cutoff = NGX_MAX_TIME_T_VALUE / 10;
1051 cutlim = NGX_MAX_TIME_T_VALUE % 10;
1052
Igor Sysoevc1571722005-03-19 12:38:37 +00001053 for (value = 0; n--; line++) {
1054 if (*line < '0' || *line > '9') {
1055 return NGX_ERROR;
1056 }
1057
Ruslan Ermilov2a54e4b2015-03-17 00:26:15 +03001058 if (value >= cutoff && (value > cutoff || *line - '0' > cutlim)) {
1059 return NGX_ERROR;
1060 }
1061
Igor Sysoevc1571722005-03-19 12:38:37 +00001062 value = value * 10 + (*line - '0');
1063 }
1064
Ruslan Ermilov2a54e4b2015-03-17 00:26:15 +03001065 return value;
Igor Sysoevc1571722005-03-19 12:38:37 +00001066}
1067
1068
Igor Sysoevd039a2e2005-02-22 14:40:13 +00001069ngx_int_t
1070ngx_hextoi(u_char *line, size_t n)
Igor Sysoev18684bd2004-05-20 17:33:52 +00001071{
Igor Sysoev066496a2006-10-16 12:21:17 +00001072 u_char c, ch;
Ruslan Ermilov2a54e4b2015-03-17 00:26:15 +03001073 ngx_int_t value, cutoff;
Igor Sysoev18684bd2004-05-20 17:33:52 +00001074
1075 if (n == 0) {
1076 return NGX_ERROR;
1077 }
1078
Ruslan Ermilov2a54e4b2015-03-17 00:26:15 +03001079 cutoff = NGX_MAX_INT_T_VALUE / 16;
1080
Igor Sysoev18684bd2004-05-20 17:33:52 +00001081 for (value = 0; n--; line++) {
Ruslan Ermilov2a54e4b2015-03-17 00:26:15 +03001082 if (value > cutoff) {
1083 return NGX_ERROR;
1084 }
1085
Igor Sysoev18684bd2004-05-20 17:33:52 +00001086 ch = *line;
1087
1088 if (ch >= '0' && ch <= '9') {
1089 value = value * 16 + (ch - '0');
1090 continue;
1091 }
1092
Igor Sysoev066496a2006-10-16 12:21:17 +00001093 c = (u_char) (ch | 0x20);
Igor Sysoev18684bd2004-05-20 17:33:52 +00001094
Igor Sysoev066496a2006-10-16 12:21:17 +00001095 if (c >= 'a' && c <= 'f') {
1096 value = value * 16 + (c - 'a' + 10);
Igor Sysoev18684bd2004-05-20 17:33:52 +00001097 continue;
1098 }
1099
1100 return NGX_ERROR;
1101 }
1102
Ruslan Ermilov2a54e4b2015-03-17 00:26:15 +03001103 return value;
Igor Sysoevdc479b42003-03-20 16:09:44 +00001104}
1105
1106
Igor Sysoeva03fa362007-12-17 21:06:17 +00001107u_char *
1108ngx_hex_dump(u_char *dst, u_char *src, size_t len)
Igor Sysoev9cc1ace2003-11-04 22:12:39 +00001109{
Igor Sysoev10a543a2004-03-16 07:10:12 +00001110 static u_char hex[] = "0123456789abcdef";
Igor Sysoeve8732b02003-11-05 17:03:41 +00001111
Igor Sysoeva03fa362007-12-17 21:06:17 +00001112 while (len--) {
1113 *dst++ = hex[*src >> 4];
1114 *dst++ = hex[*src++ & 0xf];
Igor Sysoev74e95c22003-11-09 20:03:38 +00001115 }
1116
Igor Sysoeva03fa362007-12-17 21:06:17 +00001117 return dst;
Igor Sysoev9cc1ace2003-11-04 22:12:39 +00001118}
1119
1120
Igor Sysoevd039a2e2005-02-22 14:40:13 +00001121void
1122ngx_encode_base64(ngx_str_t *dst, ngx_str_t *src)
Igor Sysoev6deb0412004-07-30 17:05:14 +00001123{
Igor Sysoev6deb0412004-07-30 17:05:14 +00001124 static u_char basis64[] =
1125 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1126
Maxim Dounin7ac48da2014-02-04 04:59:21 +04001127 ngx_encode_base64_internal(dst, src, basis64, 1);
1128}
1129
1130
1131void
1132ngx_encode_base64url(ngx_str_t *dst, ngx_str_t *src)
1133{
1134 static u_char basis64[] =
1135 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
1136
1137 ngx_encode_base64_internal(dst, src, basis64, 0);
1138}
1139
1140
1141static void
1142ngx_encode_base64_internal(ngx_str_t *dst, ngx_str_t *src, const u_char *basis,
1143 ngx_uint_t padding)
1144{
1145 u_char *d, *s;
1146 size_t len;
1147
Igor Sysoev967fd632004-08-27 15:40:59 +00001148 len = src->len;
Igor Sysoeva7c4a2a2004-08-29 03:55:41 +00001149 s = src->data;
1150 d = dst->data;
Igor Sysoev6deb0412004-07-30 17:05:14 +00001151
Igor Sysoev967fd632004-08-27 15:40:59 +00001152 while (len > 2) {
Maxim Dounin7ac48da2014-02-04 04:59:21 +04001153 *d++ = basis[(s[0] >> 2) & 0x3f];
1154 *d++ = basis[((s[0] & 3) << 4) | (s[1] >> 4)];
1155 *d++ = basis[((s[1] & 0x0f) << 2) | (s[2] >> 6)];
1156 *d++ = basis[s[2] & 0x3f];
Igor Sysoev967fd632004-08-27 15:40:59 +00001157
1158 s += 3;
1159 len -= 3;
Igor Sysoev6deb0412004-07-30 17:05:14 +00001160 }
1161
Igor Sysoev967fd632004-08-27 15:40:59 +00001162 if (len) {
Maxim Dounin7ac48da2014-02-04 04:59:21 +04001163 *d++ = basis[(s[0] >> 2) & 0x3f];
Igor Sysoev6deb0412004-07-30 17:05:14 +00001164
Igor Sysoev967fd632004-08-27 15:40:59 +00001165 if (len == 1) {
Maxim Dounin7ac48da2014-02-04 04:59:21 +04001166 *d++ = basis[(s[0] & 3) << 4];
1167 if (padding) {
1168 *d++ = '=';
1169 }
Igor Sysoev6deb0412004-07-30 17:05:14 +00001170
1171 } else {
Maxim Dounin7ac48da2014-02-04 04:59:21 +04001172 *d++ = basis[((s[0] & 3) << 4) | (s[1] >> 4)];
1173 *d++ = basis[(s[1] & 0x0f) << 2];
Igor Sysoev6deb0412004-07-30 17:05:14 +00001174 }
1175
Maxim Dounin7ac48da2014-02-04 04:59:21 +04001176 if (padding) {
1177 *d++ = '=';
1178 }
Igor Sysoev6deb0412004-07-30 17:05:14 +00001179 }
1180
1181 dst->len = d - dst->data;
Igor Sysoev6deb0412004-07-30 17:05:14 +00001182}
1183
1184
Igor Sysoevd039a2e2005-02-22 14:40:13 +00001185ngx_int_t
1186ngx_decode_base64(ngx_str_t *dst, ngx_str_t *src)
Igor Sysoev6deb0412004-07-30 17:05:14 +00001187{
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001188 static u_char basis64[] = {
1189 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
1190 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
1191 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 62, 77, 77, 77, 63,
1192 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 77, 77, 77, 77, 77, 77,
1193 77, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
1194 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 77, 77, 77, 77, 77,
1195 77, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
1196 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 77, 77, 77, 77, 77,
Igor Sysoev6deb0412004-07-30 17:05:14 +00001197
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001198 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
1199 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
1200 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
1201 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
1202 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
1203 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
1204 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
1205 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77
1206 };
Igor Sysoev967fd632004-08-27 15:40:59 +00001207
Igor Sysoev94e9aaa2010-09-02 14:37:16 +00001208 return ngx_decode_base64_internal(dst, src, basis64);
1209}
1210
1211
1212ngx_int_t
1213ngx_decode_base64url(ngx_str_t *dst, ngx_str_t *src)
1214{
1215 static u_char basis64[] = {
1216 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
1217 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
1218 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 62, 77, 77,
1219 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 77, 77, 77, 77, 77, 77,
1220 77, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
1221 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 77, 77, 77, 77, 63,
1222 77, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
1223 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 77, 77, 77, 77, 77,
1224
1225 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
1226 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
1227 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
1228 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
1229 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
1230 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
1231 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
1232 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77
1233 };
1234
1235 return ngx_decode_base64_internal(dst, src, basis64);
1236}
1237
1238
1239static ngx_int_t
1240ngx_decode_base64_internal(ngx_str_t *dst, ngx_str_t *src, const u_char *basis)
1241{
1242 size_t len;
1243 u_char *d, *s;
1244
Igor Sysoev967fd632004-08-27 15:40:59 +00001245 for (len = 0; len < src->len; len++) {
1246 if (src->data[len] == '=') {
1247 break;
1248 }
1249
Igor Sysoev94e9aaa2010-09-02 14:37:16 +00001250 if (basis[src->data[len]] == 77) {
Igor Sysoev967fd632004-08-27 15:40:59 +00001251 return NGX_ERROR;
1252 }
1253 }
1254
1255 if (len % 4 == 1) {
1256 return NGX_ERROR;
1257 }
1258
Igor Sysoev6deb0412004-07-30 17:05:14 +00001259 s = src->data;
Igor Sysoeva7c4a2a2004-08-29 03:55:41 +00001260 d = dst->data;
Igor Sysoev6deb0412004-07-30 17:05:14 +00001261
Igor Sysoev967fd632004-08-27 15:40:59 +00001262 while (len > 3) {
Igor Sysoev94e9aaa2010-09-02 14:37:16 +00001263 *d++ = (u_char) (basis[s[0]] << 2 | basis[s[1]] >> 4);
1264 *d++ = (u_char) (basis[s[1]] << 4 | basis[s[2]] >> 2);
1265 *d++ = (u_char) (basis[s[2]] << 6 | basis[s[3]]);
Igor Sysoev6deb0412004-07-30 17:05:14 +00001266
Igor Sysoev967fd632004-08-27 15:40:59 +00001267 s += 4;
1268 len -= 4;
Igor Sysoev6deb0412004-07-30 17:05:14 +00001269 }
1270
Igor Sysoev967fd632004-08-27 15:40:59 +00001271 if (len > 1) {
Igor Sysoev94e9aaa2010-09-02 14:37:16 +00001272 *d++ = (u_char) (basis[s[0]] << 2 | basis[s[1]] >> 4);
Igor Sysoev967fd632004-08-27 15:40:59 +00001273 }
1274
1275 if (len > 2) {
Igor Sysoev94e9aaa2010-09-02 14:37:16 +00001276 *d++ = (u_char) (basis[s[1]] << 4 | basis[s[2]] >> 2);
Igor Sysoev967fd632004-08-27 15:40:59 +00001277 }
1278
1279 dst->len = d - dst->data;
Igor Sysoev967fd632004-08-27 15:40:59 +00001280
Igor Sysoev6deb0412004-07-30 17:05:14 +00001281 return NGX_OK;
1282}
1283
1284
Igor Sysoevef809b82006-06-28 16:00:26 +00001285/*
Igor Sysoeva0898572008-07-29 14:41:34 +00001286 * ngx_utf8_decode() decodes two and more bytes UTF sequences only
Igor Sysoevef809b82006-06-28 16:00:26 +00001287 * the return values:
1288 * 0x80 - 0x10ffff valid character
Igor Sysoev96eaa052008-07-25 14:29:05 +00001289 * 0x110000 - 0xfffffffd invalid sequence
Igor Sysoevef809b82006-06-28 16:00:26 +00001290 * 0xfffffffe incomplete sequence
1291 * 0xffffffff error
1292 */
1293
1294uint32_t
Igor Sysoeva0898572008-07-29 14:41:34 +00001295ngx_utf8_decode(u_char **p, size_t n)
Igor Sysoevef809b82006-06-28 16:00:26 +00001296{
1297 size_t len;
1298 uint32_t u, i, valid;
1299
1300 u = **p;
1301
Maxim Douninba76a892011-10-13 13:56:41 +00001302 if (u >= 0xf0) {
Igor Sysoevef809b82006-06-28 16:00:26 +00001303
1304 u &= 0x07;
1305 valid = 0xffff;
1306 len = 3;
1307
Maxim Douninba76a892011-10-13 13:56:41 +00001308 } else if (u >= 0xe0) {
Igor Sysoevef809b82006-06-28 16:00:26 +00001309
1310 u &= 0x0f;
1311 valid = 0x7ff;
1312 len = 2;
1313
Maxim Douninba76a892011-10-13 13:56:41 +00001314 } else if (u >= 0xc2) {
Igor Sysoevef809b82006-06-28 16:00:26 +00001315
1316 u &= 0x1f;
1317 valid = 0x7f;
1318 len = 1;
1319
1320 } else {
1321 (*p)++;
1322 return 0xffffffff;
1323 }
1324
1325 if (n - 1 < len) {
1326 return 0xfffffffe;
1327 }
1328
1329 (*p)++;
1330
1331 while (len) {
1332 i = *(*p)++;
1333
1334 if (i < 0x80) {
1335 return 0xffffffff;
1336 }
1337
1338 u = (u << 6) | (i & 0x3f);
1339
1340 len--;
1341 }
1342
1343 if (u > valid) {
1344 return u;
1345 }
1346
1347 return 0xffffffff;
1348}
1349
1350
Igor Sysoevb145b062005-06-15 18:33:41 +00001351size_t
Igor Sysoeva0898572008-07-29 14:41:34 +00001352ngx_utf8_length(u_char *p, size_t n)
Igor Sysoevb145b062005-06-15 18:33:41 +00001353{
Igor Sysoev96eaa052008-07-25 14:29:05 +00001354 u_char c, *last;
1355 size_t len;
Igor Sysoevb145b062005-06-15 18:33:41 +00001356
Igor Sysoev96eaa052008-07-25 14:29:05 +00001357 last = p + n;
Igor Sysoevb145b062005-06-15 18:33:41 +00001358
Igor Sysoev96eaa052008-07-25 14:29:05 +00001359 for (len = 0; p < last; len++) {
1360
1361 c = *p;
Igor Sysoevb145b062005-06-15 18:33:41 +00001362
1363 if (c < 0x80) {
Igor Sysoev96eaa052008-07-25 14:29:05 +00001364 p++;
Igor Sysoevb145b062005-06-15 18:33:41 +00001365 continue;
1366 }
1367
Igor Sysoeva0898572008-07-29 14:41:34 +00001368 if (ngx_utf8_decode(&p, n) > 0x10ffff) {
1369 /* invalid UTF-8 */
Igor Sysoev96eaa052008-07-25 14:29:05 +00001370 return n;
Igor Sysoevb145b062005-06-15 18:33:41 +00001371 }
Igor Sysoevb145b062005-06-15 18:33:41 +00001372 }
1373
1374 return len;
1375}
1376
1377
Igor Sysoev5192b362005-07-08 14:34:20 +00001378u_char *
Igor Sysoeva0898572008-07-29 14:41:34 +00001379ngx_utf8_cpystrn(u_char *dst, u_char *src, size_t n, size_t len)
Igor Sysoev5192b362005-07-08 14:34:20 +00001380{
Igor Sysoev96eaa052008-07-25 14:29:05 +00001381 u_char c, *next;
Igor Sysoev5192b362005-07-08 14:34:20 +00001382
1383 if (n == 0) {
1384 return dst;
1385 }
1386
Igor Sysoev96eaa052008-07-25 14:29:05 +00001387 while (--n) {
Igor Sysoev5192b362005-07-08 14:34:20 +00001388
1389 c = *src;
1390 *dst = c;
1391
1392 if (c < 0x80) {
Igor Sysoev96eaa052008-07-25 14:29:05 +00001393
1394 if (c != '\0') {
1395 dst++;
1396 src++;
1397 len--;
1398
Igor Sysoev5192b362005-07-08 14:34:20 +00001399 continue;
1400 }
1401
1402 return dst;
1403 }
1404
Igor Sysoev96eaa052008-07-25 14:29:05 +00001405 next = src;
Igor Sysoev5192b362005-07-08 14:34:20 +00001406
Igor Sysoeva0898572008-07-29 14:41:34 +00001407 if (ngx_utf8_decode(&next, len) > 0x10ffff) {
1408 /* invalid UTF-8 */
Igor Sysoev96eaa052008-07-25 14:29:05 +00001409 break;
Igor Sysoev5192b362005-07-08 14:34:20 +00001410 }
1411
Igor Sysoev96eaa052008-07-25 14:29:05 +00001412 while (src < next) {
Igor Sysoevd8be48a2010-01-11 13:39:24 +00001413 *dst++ = *src++;
Igor Sysoev96eaa052008-07-25 14:29:05 +00001414 len--;
1415 }
Igor Sysoev5192b362005-07-08 14:34:20 +00001416 }
1417
1418 *dst = '\0';
1419
1420 return dst;
1421}
1422
1423
Igor Sysoevd039a2e2005-02-22 14:40:13 +00001424uintptr_t
1425ngx_escape_uri(u_char *dst, u_char *src, size_t size, ngx_uint_t type)
Igor Sysoevdc479b42003-03-20 16:09:44 +00001426{
Igor Sysoev612ecb72009-11-02 17:12:09 +00001427 ngx_uint_t n;
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001428 uint32_t *escape;
Piotr Sikora3ba8f2f2014-06-26 23:39:23 -07001429 static u_char hex[] = "0123456789ABCDEF";
Igor Sysoev1b735832004-11-11 14:07:14 +00001430
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001431 /* " ", "#", "%", "?", %00-%1F, %7F-%FF */
Igor Sysoev805d9db2005-02-03 19:33:37 +00001432
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001433 static uint32_t uri[] = {
1434 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
Igor Sysoevdc479b42003-03-20 16:09:44 +00001435
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001436 /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
1437 0x80000029, /* 1000 0000 0000 0000 0000 0000 0010 1001 */
Igor Sysoevdc479b42003-03-20 16:09:44 +00001438
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001439 /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
1440 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
Igor Sysoevdc479b42003-03-20 16:09:44 +00001441
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001442 /* ~}| {zyx wvut srqp onml kjih gfed cba` */
1443 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */
Igor Sysoev924bd792004-10-11 15:07:03 +00001444
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001445 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1446 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1447 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1448 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1449 };
Igor Sysoev924bd792004-10-11 15:07:03 +00001450
Igor Sysoev170a54f2010-04-01 12:45:59 +00001451 /* " ", "#", "%", "&", "+", "?", %00-%1F, %7F-%FF */
Igor Sysoev805d9db2005-02-03 19:33:37 +00001452
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001453 static uint32_t args[] = {
1454 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
Igor Sysoev805d9db2005-02-03 19:33:37 +00001455
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001456 /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
Igor Sysoev0e0e0af2010-07-30 13:25:19 +00001457 0x88000869, /* 1000 1000 0000 0000 0000 1000 0110 1001 */
Igor Sysoev805d9db2005-02-03 19:33:37 +00001458
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001459 /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
1460 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
Igor Sysoev805d9db2005-02-03 19:33:37 +00001461
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001462 /* ~}| {zyx wvut srqp onml kjih gfed cba` */
1463 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */
Igor Sysoev805d9db2005-02-03 19:33:37 +00001464
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001465 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1466 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1467 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1468 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1469 };
Igor Sysoev805d9db2005-02-03 19:33:37 +00001470
Maxim Dounin6226fe32011-10-11 17:56:51 +00001471 /* not ALPHA, DIGIT, "-", ".", "_", "~" */
1472
1473 static uint32_t uri_component[] = {
1474 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1475
1476 /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
1477 0xfc009fff, /* 1111 1100 0000 0000 1001 1111 1111 1111 */
1478
1479 /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
1480 0x78000001, /* 0111 1000 0000 0000 0000 0000 0000 0001 */
1481
1482 /* ~}| {zyx wvut srqp onml kjih gfed cba` */
1483 0xb8000001, /* 1011 1000 0000 0000 0000 0000 0000 0001 */
1484
1485 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1486 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1487 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1488 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1489 };
1490
Igor Sysoevd4ff5612007-08-20 09:50:53 +00001491 /* " ", "#", """, "%", "'", %00-%1F, %7F-%FF */
Igor Sysoev805d9db2005-02-03 19:33:37 +00001492
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001493 static uint32_t html[] = {
1494 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
Igor Sysoev1b735832004-11-11 14:07:14 +00001495
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001496 /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
Igor Sysoev049ae002007-07-13 09:35:51 +00001497 0x000000ad, /* 0000 0000 0000 0000 0000 0000 1010 1101 */
Igor Sysoev1b735832004-11-11 14:07:14 +00001498
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001499 /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
1500 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
Igor Sysoev1b735832004-11-11 14:07:14 +00001501
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001502 /* ~}| {zyx wvut srqp onml kjih gfed cba` */
1503 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */
Igor Sysoev1b735832004-11-11 14:07:14 +00001504
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001505 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1506 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1507 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1508 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1509 };
Igor Sysoev1b735832004-11-11 14:07:14 +00001510
Igor Sysoevd4ff5612007-08-20 09:50:53 +00001511 /* " ", """, "%", "'", %00-%1F, %7F-%FF */
Igor Sysoev1b735832004-11-11 14:07:14 +00001512
Igor Sysoev8662b6b2007-07-13 09:37:01 +00001513 static uint32_t refresh[] = {
1514 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1515
1516 /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
Igor Sysoevcc5484f2007-11-09 13:17:58 +00001517 0x00000085, /* 0000 0000 0000 0000 0000 0000 1000 0101 */
Igor Sysoev8662b6b2007-07-13 09:37:01 +00001518
1519 /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
1520 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1521
1522 /* ~}| {zyx wvut srqp onml kjih gfed cba` */
1523 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */
1524
1525 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1526 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1527 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1528 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1529 };
1530
Igor Sysoevd4ff5612007-08-20 09:50:53 +00001531 /* " ", "%", %00-%1F */
Igor Sysoev3f707822007-07-22 19:18:59 +00001532
1533 static uint32_t memcached[] = {
1534 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1535
1536 /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
Igor Sysoevd4ff5612007-08-20 09:50:53 +00001537 0x00000021, /* 0000 0000 0000 0000 0000 0000 0010 0001 */
Igor Sysoev3f707822007-07-22 19:18:59 +00001538
1539 /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
1540 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1541
1542 /* ~}| {zyx wvut srqp onml kjih gfed cba` */
1543 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1544
1545 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1546 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1547 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1548 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1549 };
1550
Igor Sysoevd4ff5612007-08-20 09:50:53 +00001551 /* mail_auth is the same as memcached */
1552
1553 static uint32_t *map[] =
Maxim Dounin6226fe32011-10-11 17:56:51 +00001554 { uri, args, uri_component, html, refresh, memcached, memcached };
Igor Sysoev8662b6b2007-07-13 09:37:01 +00001555
1556
1557 escape = map[type];
Igor Sysoev1b735832004-11-11 14:07:14 +00001558
Igor Sysoev924bd792004-10-11 15:07:03 +00001559 if (dst == NULL) {
1560
1561 /* find the number of the characters to be escaped */
1562
Igor Sysoeve0f1d0a2009-09-11 13:57:50 +00001563 n = 0;
Igor Sysoev924bd792004-10-11 15:07:03 +00001564
Igor Sysoev612ecb72009-11-02 17:12:09 +00001565 while (size) {
Sergey Kandaurov8540ec72016-07-07 21:02:28 +03001566 if (escape[*src >> 5] & (1U << (*src & 0x1f))) {
Igor Sysoev924bd792004-10-11 15:07:03 +00001567 n++;
1568 }
1569 src++;
Igor Sysoev612ecb72009-11-02 17:12:09 +00001570 size--;
Igor Sysoev924bd792004-10-11 15:07:03 +00001571 }
1572
Igor Sysoev805d9db2005-02-03 19:33:37 +00001573 return (uintptr_t) n;
Igor Sysoevdc479b42003-03-20 16:09:44 +00001574 }
1575
Igor Sysoev612ecb72009-11-02 17:12:09 +00001576 while (size) {
Sergey Kandaurov8540ec72016-07-07 21:02:28 +03001577 if (escape[*src >> 5] & (1U << (*src & 0x1f))) {
Igor Sysoev924bd792004-10-11 15:07:03 +00001578 *dst++ = '%';
1579 *dst++ = hex[*src >> 4];
1580 *dst++ = hex[*src & 0xf];
1581 src++;
Igor Sysoevdc479b42003-03-20 16:09:44 +00001582
Igor Sysoev924bd792004-10-11 15:07:03 +00001583 } else {
1584 *dst++ = *src++;
1585 }
Igor Sysoev612ecb72009-11-02 17:12:09 +00001586 size--;
Igor Sysoevdc479b42003-03-20 16:09:44 +00001587 }
1588
Igor Sysoev805d9db2005-02-03 19:33:37 +00001589 return (uintptr_t) dst;
Igor Sysoevdc479b42003-03-20 16:09:44 +00001590}
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +00001591
1592
1593void
Igor Sysoevae33d012006-01-17 20:04:32 +00001594ngx_unescape_uri(u_char **dst, u_char **src, size_t size, ngx_uint_t type)
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +00001595{
1596 u_char *d, *s, ch, c, decoded;
1597 enum {
1598 sw_usual = 0,
1599 sw_quoted,
1600 sw_quoted_second
1601 } state;
1602
1603 d = *dst;
1604 s = *src;
1605
1606 state = 0;
1607 decoded = 0;
1608
1609 while (size--) {
1610
1611 ch = *s++;
1612
1613 switch (state) {
1614 case sw_usual:
Igor Sysoevf0a51cf2007-10-22 10:19:17 +00001615 if (ch == '?'
1616 && (type & (NGX_UNESCAPE_URI|NGX_UNESCAPE_REDIRECT)))
1617 {
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +00001618 *d++ = ch;
1619 goto done;
1620 }
1621
1622 if (ch == '%') {
1623 state = sw_quoted;
1624 break;
1625 }
1626
1627 *d++ = ch;
1628 break;
1629
1630 case sw_quoted:
1631
1632 if (ch >= '0' && ch <= '9') {
1633 decoded = (u_char) (ch - '0');
1634 state = sw_quoted_second;
1635 break;
1636 }
1637
1638 c = (u_char) (ch | 0x20);
1639 if (c >= 'a' && c <= 'f') {
1640 decoded = (u_char) (c - 'a' + 10);
1641 state = sw_quoted_second;
1642 break;
1643 }
1644
Igor Sysoev24025022005-12-16 15:07:08 +00001645 /* the invalid quoted character */
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +00001646
Igor Sysoev24025022005-12-16 15:07:08 +00001647 state = sw_usual;
1648
1649 *d++ = ch;
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +00001650
1651 break;
1652
1653 case sw_quoted_second:
1654
Igor Sysoev24025022005-12-16 15:07:08 +00001655 state = sw_usual;
1656
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +00001657 if (ch >= '0' && ch <= '9') {
1658 ch = (u_char) ((decoded << 4) + ch - '0');
1659
Igor Sysoevf0a51cf2007-10-22 10:19:17 +00001660 if (type & NGX_UNESCAPE_REDIRECT) {
Igor Sysoevae33d012006-01-17 20:04:32 +00001661 if (ch > '%' && ch < 0x7f) {
1662 *d++ = ch;
1663 break;
1664 }
1665
1666 *d++ = '%'; *d++ = *(s - 2); *d++ = *(s - 1);
1667
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +00001668 break;
1669 }
1670
Igor Sysoevae33d012006-01-17 20:04:32 +00001671 *d++ = ch;
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +00001672
1673 break;
1674 }
1675
1676 c = (u_char) (ch | 0x20);
1677 if (c >= 'a' && c <= 'f') {
1678 ch = (u_char) ((decoded << 4) + c - 'a' + 10);
1679
Igor Sysoevf0a51cf2007-10-22 10:19:17 +00001680 if (type & NGX_UNESCAPE_URI) {
1681 if (ch == '?') {
1682 *d++ = ch;
1683 goto done;
1684 }
1685
1686 *d++ = ch;
1687 break;
1688 }
1689
1690 if (type & NGX_UNESCAPE_REDIRECT) {
Igor Sysoevae33d012006-01-17 20:04:32 +00001691 if (ch == '?') {
1692 *d++ = ch;
1693 goto done;
1694 }
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +00001695
Igor Sysoevae33d012006-01-17 20:04:32 +00001696 if (ch > '%' && ch < 0x7f) {
1697 *d++ = ch;
1698 break;
1699 }
1700
1701 *d++ = '%'; *d++ = *(s - 2); *d++ = *(s - 1);
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +00001702 break;
1703 }
1704
Igor Sysoevae33d012006-01-17 20:04:32 +00001705 *d++ = ch;
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +00001706
1707 break;
1708 }
1709
Igor Sysoev24025022005-12-16 15:07:08 +00001710 /* the invalid quoted character */
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +00001711
1712 break;
1713 }
1714 }
1715
1716done:
1717
1718 *dst = d;
1719 *src = s;
1720}
Igor Sysoevd3283ff2005-12-05 13:18:09 +00001721
1722
Igor Sysoev1730c752007-09-27 09:36:50 +00001723uintptr_t
1724ngx_escape_html(u_char *dst, u_char *src, size_t size)
1725{
1726 u_char ch;
Igor Sysoev612ecb72009-11-02 17:12:09 +00001727 ngx_uint_t len;
Igor Sysoev1730c752007-09-27 09:36:50 +00001728
1729 if (dst == NULL) {
1730
1731 len = 0;
1732
Igor Sysoev612ecb72009-11-02 17:12:09 +00001733 while (size) {
Igor Sysoev1730c752007-09-27 09:36:50 +00001734 switch (*src++) {
1735
1736 case '<':
1737 len += sizeof("&lt;") - 2;
Igor Sysoevd3db9ea2007-10-09 18:42:00 +00001738 break;
Igor Sysoev1730c752007-09-27 09:36:50 +00001739
1740 case '>':
1741 len += sizeof("&gt;") - 2;
Igor Sysoevd3db9ea2007-10-09 18:42:00 +00001742 break;
Igor Sysoev1730c752007-09-27 09:36:50 +00001743
1744 case '&':
1745 len += sizeof("&amp;") - 2;
Igor Sysoevd3db9ea2007-10-09 18:42:00 +00001746 break;
Igor Sysoev1730c752007-09-27 09:36:50 +00001747
Maxim Dounin1b9b19d2011-11-25 16:36:02 +00001748 case '"':
1749 len += sizeof("&quot;") - 2;
1750 break;
1751
Igor Sysoev1730c752007-09-27 09:36:50 +00001752 default:
1753 break;
1754 }
Igor Sysoev612ecb72009-11-02 17:12:09 +00001755 size--;
Igor Sysoev1730c752007-09-27 09:36:50 +00001756 }
1757
1758 return (uintptr_t) len;
1759 }
1760
Igor Sysoev612ecb72009-11-02 17:12:09 +00001761 while (size) {
Igor Sysoev1730c752007-09-27 09:36:50 +00001762 ch = *src++;
1763
1764 switch (ch) {
1765
1766 case '<':
1767 *dst++ = '&'; *dst++ = 'l'; *dst++ = 't'; *dst++ = ';';
1768 break;
1769
1770 case '>':
1771 *dst++ = '&'; *dst++ = 'g'; *dst++ = 't'; *dst++ = ';';
1772 break;
1773
1774 case '&':
1775 *dst++ = '&'; *dst++ = 'a'; *dst++ = 'm'; *dst++ = 'p';
1776 *dst++ = ';';
1777 break;
1778
Maxim Dounin1b9b19d2011-11-25 16:36:02 +00001779 case '"':
1780 *dst++ = '&'; *dst++ = 'q'; *dst++ = 'u'; *dst++ = 'o';
1781 *dst++ = 't'; *dst++ = ';';
1782 break;
1783
Igor Sysoev1730c752007-09-27 09:36:50 +00001784 default:
1785 *dst++ = ch;
1786 break;
1787 }
Igor Sysoev612ecb72009-11-02 17:12:09 +00001788 size--;
Igor Sysoev1730c752007-09-27 09:36:50 +00001789 }
1790
1791 return (uintptr_t) dst;
1792}
1793
1794
Valentin Bartenev08a960d2014-12-12 20:25:35 +03001795uintptr_t
1796ngx_escape_json(u_char *dst, u_char *src, size_t size)
1797{
1798 u_char ch;
1799 ngx_uint_t len;
1800
1801 if (dst == NULL) {
1802 len = 0;
1803
1804 while (size) {
1805 ch = *src++;
1806
1807 if (ch == '\\' || ch == '"') {
1808 len++;
1809
1810 } else if (ch <= 0x1f) {
1811 len += sizeof("\\u001F") - 2;
1812 }
1813
1814 size--;
1815 }
1816
1817 return (uintptr_t) len;
1818 }
1819
1820 while (size) {
1821 ch = *src++;
1822
1823 if (ch > 0x1f) {
1824
1825 if (ch == '\\' || ch == '"') {
1826 *dst++ = '\\';
1827 }
1828
1829 *dst++ = ch;
1830
1831 } else {
1832 *dst++ = '\\'; *dst++ = 'u'; *dst++ = '0'; *dst++ = '0';
1833 *dst++ = '0' + (ch >> 4);
1834
1835 ch &= 0xf;
1836
1837 *dst++ = (ch < 10) ? ('0' + ch) : ('A' + ch - 10);
1838 }
1839
1840 size--;
1841 }
1842
1843 return (uintptr_t) dst;
1844}
1845
1846
Igor Sysoev0923d082010-06-23 15:31:33 +00001847void
1848ngx_str_rbtree_insert_value(ngx_rbtree_node_t *temp,
1849 ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
1850{
1851 ngx_str_node_t *n, *t;
1852 ngx_rbtree_node_t **p;
1853
1854 for ( ;; ) {
1855
1856 n = (ngx_str_node_t *) node;
1857 t = (ngx_str_node_t *) temp;
1858
1859 if (node->key != temp->key) {
1860
1861 p = (node->key < temp->key) ? &temp->left : &temp->right;
1862
1863 } else if (n->str.len != t->str.len) {
1864
1865 p = (n->str.len < t->str.len) ? &temp->left : &temp->right;
1866
1867 } else {
1868 p = (ngx_memcmp(n->str.data, t->str.data, n->str.len) < 0)
1869 ? &temp->left : &temp->right;
1870 }
1871
1872 if (*p == sentinel) {
1873 break;
1874 }
1875
1876 temp = *p;
1877 }
1878
1879 *p = node;
1880 node->parent = temp;
1881 node->left = sentinel;
1882 node->right = sentinel;
1883 ngx_rbt_red(node);
1884}
1885
1886
1887ngx_str_node_t *
1888ngx_str_rbtree_lookup(ngx_rbtree_t *rbtree, ngx_str_t *val, uint32_t hash)
1889{
1890 ngx_int_t rc;
1891 ngx_str_node_t *n;
1892 ngx_rbtree_node_t *node, *sentinel;
1893
1894 node = rbtree->root;
1895 sentinel = rbtree->sentinel;
1896
1897 while (node != sentinel) {
1898
1899 n = (ngx_str_node_t *) node;
1900
1901 if (hash != node->key) {
1902 node = (hash < node->key) ? node->left : node->right;
1903 continue;
1904 }
1905
1906 if (val->len != n->str.len) {
1907 node = (val->len < n->str.len) ? node->left : node->right;
1908 continue;
1909 }
1910
1911 rc = ngx_memcmp(val->data, n->str.data, val->len);
1912
1913 if (rc < 0) {
1914 node = node->left;
1915 continue;
1916 }
1917
1918 if (rc > 0) {
1919 node = node->right;
1920 continue;
1921 }
1922
1923 return n;
1924 }
1925
1926 return NULL;
1927}
1928
1929
Igor Sysoev35921282007-05-21 14:05:23 +00001930/* ngx_sort() is implemented as insertion sort because we need stable sort */
1931
1932void
1933ngx_sort(void *base, size_t n, size_t size,
Igor Sysoevde8ec1e2008-03-24 13:04:02 +00001934 ngx_int_t (*cmp)(const void *, const void *))
Igor Sysoev35921282007-05-21 14:05:23 +00001935{
Igor Sysoev86341182008-03-23 19:58:54 +00001936 u_char *p1, *p2, *p;
1937
1938 p = ngx_alloc(size, ngx_cycle->log);
1939 if (p == NULL) {
1940 return;
1941 }
Igor Sysoev35921282007-05-21 14:05:23 +00001942
1943 for (p1 = (u_char *) base + size;
1944 p1 < (u_char *) base + n * size;
1945 p1 += size)
1946 {
Igor Sysoev86341182008-03-23 19:58:54 +00001947 ngx_memcpy(p, p1, size);
Igor Sysoev35921282007-05-21 14:05:23 +00001948
1949 for (p2 = p1;
Igor Sysoev86341182008-03-23 19:58:54 +00001950 p2 > (u_char *) base && cmp(p2 - size, p) > 0;
Igor Sysoev35921282007-05-21 14:05:23 +00001951 p2 -= size)
1952 {
1953 ngx_memcpy(p2, p2 - size, size);
1954 }
1955
Igor Sysoev86341182008-03-23 19:58:54 +00001956 ngx_memcpy(p2, p, size);
Igor Sysoev35921282007-05-21 14:05:23 +00001957 }
Igor Sysoev86341182008-03-23 19:58:54 +00001958
1959 ngx_free(p);
Igor Sysoev35921282007-05-21 14:05:23 +00001960}
1961
1962
Igor Sysoevd3283ff2005-12-05 13:18:09 +00001963#if (NGX_MEMCPY_LIMIT)
1964
1965void *
Maxim Dounind053bac2012-08-03 09:07:30 +00001966ngx_memcpy(void *dst, const void *src, size_t n)
Igor Sysoevd3283ff2005-12-05 13:18:09 +00001967{
1968 if (n > NGX_MEMCPY_LIMIT) {
1969 ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "memcpy %uz bytes", n);
1970 ngx_debug_point();
1971 }
1972
1973 return memcpy(dst, src, n);
1974}
1975
1976#endif