1
2 /*
3 * Copyright (C) Igor Sysoev
4 * Copyright (C) Nginx, Inc.
5 */
6
7
8 #include <ngx_config.h>
9 #include <ngx_core.h>
10
11
12 static u_char *ngx_sprintf_num(u_char *buf, u_char *last, uint64_t ui64,
13 u_char zero, ngx_uint_t hexadecimal, ngx_uint_t width);
14 static void ngx_encode_base64_internal(ngx_str_t *dst, ngx_str_t *src,
15 const u_char *basis, ngx_uint_t padding);
16 static ngx_int_t ngx_decode_base64_internal(ngx_str_t *dst, ngx_str_t *src,
17 const u_char *basis);
18
19
20 void
ngx_strlow(u_char * dst,u_char * src,size_t n)21 ngx_strlow(u_char *dst, u_char *src, size_t n)
22 {
23 while (n) {
24 *dst = ngx_tolower(*src);
25 dst++;
26 src++;
27 n--;
28 }
29 }
30
31
32 size_t
ngx_strnlen(u_char * p,size_t n)33 ngx_strnlen(u_char *p, size_t n)
34 {
35 size_t i;
36
37 for (i = 0; i < n; i++) {
38
39 if (p[i] == '\0') {
40 return i;
41 }
42 }
43
44 return n;
45 }
46
47
48 u_char *
ngx_cpystrn(u_char * dst,u_char * src,size_t n)49 ngx_cpystrn(u_char *dst, u_char *src, size_t n)
50 {
51 if (n == 0) {
52 return dst;
53 }
54
55 while (--n) {
56 *dst = *src;
57
58 if (*dst == '\0') {
59 return dst;
60 }
61
62 dst++;
63 src++;
64 }
65
66 *dst = '\0';
67
68 return dst;
69 }
70
71
72 u_char *
ngx_pstrdup(ngx_pool_t * pool,ngx_str_t * src)73 ngx_pstrdup(ngx_pool_t *pool, ngx_str_t *src)
74 {
75 u_char *dst;
76
77 dst = ngx_pnalloc(pool, src->len);
78 if (dst == NULL) {
79 return NULL;
80 }
81
82 ngx_memcpy(dst, src->data, src->len);
83
84 return dst;
85 }
86
87
88 /*
89 * supported formats:
90 * %[0][width][x][X]O off_t
91 * %[0][width]T time_t
92 * %[0][width][u][x|X]z ssize_t/size_t
93 * %[0][width][u][x|X]d int/u_int
94 * %[0][width][u][x|X]l long
95 * %[0][width|m][u][x|X]i ngx_int_t/ngx_uint_t
96 * %[0][width][u][x|X]D int32_t/uint32_t
97 * %[0][width][u][x|X]L int64_t/uint64_t
98 * %[0][width|m][u][x|X]A ngx_atomic_int_t/ngx_atomic_uint_t
99 * %[0][width][.width]f double, max valid number fits to %18.15f
100 * %P ngx_pid_t
101 * %M ngx_msec_t
102 * %r rlim_t
103 * %p void *
104 * %V ngx_str_t *
105 * %v ngx_variable_value_t *
106 * %s null-terminated string
107 * %*s length and string
108 * %Z '\0'
109 * %N '\n'
110 * %c char
111 * %% %
112 *
113 * reserved:
114 * %t ptrdiff_t
115 * %S null-terminated wchar string
116 * %C wchar
117 */
118
119
120 u_char * ngx_cdecl
ngx_sprintf(u_char * buf,const char * fmt,...)121 ngx_sprintf(u_char *buf, const char *fmt, ...)
122 {
123 u_char *p;
124 va_list args;
125
126 va_start(args, fmt);
127 p = ngx_vslprintf(buf, (void *) -1, fmt, args);
128 va_end(args);
129
130 return p;
131 }
132
133
134 u_char * ngx_cdecl
ngx_snprintf(u_char * buf,size_t max,const char * fmt,...)135 ngx_snprintf(u_char *buf, size_t max, const char *fmt, ...)
136 {
137 u_char *p;
138 va_list args;
139
140 va_start(args, fmt);
141 p = ngx_vslprintf(buf, buf + max, fmt, args);
142 va_end(args);
143
144 return p;
145 }
146
147
148 u_char * ngx_cdecl
ngx_slprintf(u_char * buf,u_char * last,const char * fmt,...)149 ngx_slprintf(u_char *buf, u_char *last, const char *fmt, ...)
150 {
151 u_char *p;
152 va_list args;
153
154 va_start(args, fmt);
155 p = ngx_vslprintf(buf, last, fmt, args);
156 va_end(args);
157
158 return p;
159 }
160
161
162 u_char *
ngx_vslprintf(u_char * buf,u_char * last,const char * fmt,va_list args)163 ngx_vslprintf(u_char *buf, u_char *last, const char *fmt, va_list args)
164 {
165 u_char *p, zero;
166 int d;
167 double f;
168 size_t len, slen;
169 int64_t i64;
170 uint64_t ui64, frac;
171 ngx_msec_t ms;
172 ngx_uint_t width, sign, hex, max_width, frac_width, scale, n;
173 ngx_str_t *v;
174 ngx_variable_value_t *vv;
175
176 while (*fmt && buf < last) {
177
178 /*
179 * "buf < last" means that we could copy at least one character:
180 * the plain character, "%%", "%c", and minus without the checking
181 */
182
183 if (*fmt == '%') {
184
185 i64 = 0;
186 ui64 = 0;
187
188 zero = (u_char) ((*++fmt == '0') ? '0' : ' ');
189 width = 0;
190 sign = 1;
191 hex = 0;
192 max_width = 0;
193 frac_width = 0;
194 slen = (size_t) -1;
195
196 while (*fmt >= '0' && *fmt <= '9') {
197 width = width * 10 + (*fmt++ - '0');
198 }
199
200
201 for ( ;; ) {
202 switch (*fmt) {
203
204 case 'u':
205 sign = 0;
206 fmt++;
207 continue;
208
209 case 'm':
210 max_width = 1;
211 fmt++;
212 continue;
213
214 case 'X':
215 hex = 2;
216 sign = 0;
217 fmt++;
218 continue;
219
220 case 'x':
221 hex = 1;
222 sign = 0;
223 fmt++;
224 continue;
225
226 case '.':
227 fmt++;
228
229 while (*fmt >= '0' && *fmt <= '9') {
230 frac_width = frac_width * 10 + (*fmt++ - '0');
231 }
232
233 break;
234
235 case '*':
236 slen = va_arg(args, size_t);
237 fmt++;
238 continue;
239
240 default:
241 break;
242 }
243
244 break;
245 }
246
247
248 switch (*fmt) {
249
250 case 'V':
251 v = va_arg(args, ngx_str_t *);
252
253 len = ngx_min(((size_t) (last - buf)), v->len);
254 buf = ngx_cpymem(buf, v->data, len);
255 fmt++;
256
257 continue;
258
259 case 'v':
260 vv = va_arg(args, ngx_variable_value_t *);
261
262 len = ngx_min(((size_t) (last - buf)), vv->len);
263 buf = ngx_cpymem(buf, vv->data, len);
264 fmt++;
265
266 continue;
267
268 case 's':
269 p = va_arg(args, u_char *);
270
271 if (slen == (size_t) -1) {
272 while (*p && buf < last) {
273 *buf++ = *p++;
274 }
275
276 } else {
277 len = ngx_min(((size_t) (last - buf)), slen);
278 buf = ngx_cpymem(buf, p, len);
279 }
280
281 fmt++;
282
283 continue;
284
285 case 'O':
286 i64 = (int64_t) va_arg(args, off_t);
287 sign = 1;
288 break;
289
290 case 'P':
291 i64 = (int64_t) va_arg(args, ngx_pid_t);
292 sign = 1;
293 break;
294
295 case 'T':
296 i64 = (int64_t) va_arg(args, time_t);
297 sign = 1;
298 break;
299
300 case 'M':
301 ms = (ngx_msec_t) va_arg(args, ngx_msec_t);
302 if ((ngx_msec_int_t) ms == -1) {
303 sign = 1;
304 i64 = -1;
305 } else {
306 sign = 0;
307 ui64 = (uint64_t) ms;
308 }
309 break;
310
311 case 'z':
312 if (sign) {
313 i64 = (int64_t) va_arg(args, ssize_t);
314 } else {
315 ui64 = (uint64_t) va_arg(args, size_t);
316 }
317 break;
318
319 case 'i':
320 if (sign) {
321 i64 = (int64_t) va_arg(args, ngx_int_t);
322 } else {
323 ui64 = (uint64_t) va_arg(args, ngx_uint_t);
324 }
325
326 if (max_width) {
327 width = NGX_INT_T_LEN;
328 }
329
330 break;
331
332 case 'd':
333 if (sign) {
334 i64 = (int64_t) va_arg(args, int);
335 } else {
336 ui64 = (uint64_t) va_arg(args, u_int);
337 }
338 break;
339
340 case 'l':
341 if (sign) {
342 i64 = (int64_t) va_arg(args, long);
343 } else {
344 ui64 = (uint64_t) va_arg(args, u_long);
345 }
346 break;
347
348 case 'D':
349 if (sign) {
350 i64 = (int64_t) va_arg(args, int32_t);
351 } else {
352 ui64 = (uint64_t) va_arg(args, uint32_t);
353 }
354 break;
355
356 case 'L':
357 if (sign) {
358 i64 = va_arg(args, int64_t);
359 } else {
360 ui64 = va_arg(args, uint64_t);
361 }
362 break;
363
364 case 'A':
365 if (sign) {
366 i64 = (int64_t) va_arg(args, ngx_atomic_int_t);
367 } else {
368 ui64 = (uint64_t) va_arg(args, ngx_atomic_uint_t);
369 }
370
371 if (max_width) {
372 width = NGX_ATOMIC_T_LEN;
373 }
374
375 break;
376
377 case 'f':
378 f = va_arg(args, double);
379
380 if (f < 0) {
381 *buf++ = '-';
382 f = -f;
383 }
384
385 ui64 = (int64_t) f;
386 frac = 0;
387
388 if (frac_width) {
389
390 scale = 1;
391 for (n = frac_width; n; n--) {
392 scale *= 10;
393 }
394
395 frac = (uint64_t) ((f - (double) ui64) * scale + 0.5);
396
397 if (frac == scale) {
398 ui64++;
399 frac = 0;
400 }
401 }
402
403 buf = ngx_sprintf_num(buf, last, ui64, zero, 0, width);
404
405 if (frac_width) {
406 if (buf < last) {
407 *buf++ = '.';
408 }
409
410 buf = ngx_sprintf_num(buf, last, frac, '0', 0, frac_width);
411 }
412
413 fmt++;
414
415 continue;
416
417 #if !(NGX_WIN32)
418 case 'r':
419 i64 = (int64_t) va_arg(args, rlim_t);
420 sign = 1;
421 break;
422 #endif
423
424 case 'p':
425 ui64 = (uintptr_t) va_arg(args, void *);
426 hex = 2;
427 sign = 0;
428 zero = '0';
429 width = 2 * sizeof(void *);
430 break;
431
432 case 'c':
433 d = va_arg(args, int);
434 *buf++ = (u_char) (d & 0xff);
435 fmt++;
436
437 continue;
438
439 case 'Z':
440 *buf++ = '\0';
441 fmt++;
442
443 continue;
444
445 case 'N':
446 #if (NGX_WIN32)
447 *buf++ = CR;
448 if (buf < last) {
449 *buf++ = LF;
450 }
451 #else
452 *buf++ = LF;
453 #endif
454 fmt++;
455
456 continue;
457
458 case '%':
459 *buf++ = '%';
460 fmt++;
461
462 continue;
463
464 default:
465 *buf++ = *fmt++;
466
467 continue;
468 }
469
470 if (sign) {
471 if (i64 < 0) {
472 *buf++ = '-';
473 ui64 = (uint64_t) -i64;
474
475 } else {
476 ui64 = (uint64_t) i64;
477 }
478 }
479
480 buf = ngx_sprintf_num(buf, last, ui64, zero, hex, width);
481
482 fmt++;
483
484 } else {
485 *buf++ = *fmt++;
486 }
487 }
488
489 return buf;
490 }
491
492
493 static u_char *
ngx_sprintf_num(u_char * buf,u_char * last,uint64_t ui64,u_char zero,ngx_uint_t hexadecimal,ngx_uint_t width)494 ngx_sprintf_num(u_char *buf, u_char *last, uint64_t ui64, u_char zero,
495 ngx_uint_t hexadecimal, ngx_uint_t width)
496 {
497 u_char *p, temp[NGX_INT64_LEN + 1];
498 /*
499 * we need temp[NGX_INT64_LEN] only,
500 * but icc issues the warning
501 */
502 size_t len;
503 uint32_t ui32;
504 static u_char hex[] = "0123456789abcdef";
505 static u_char HEX[] = "0123456789ABCDEF";
506
507 p = temp + NGX_INT64_LEN;
508
509 if (hexadecimal == 0) {
510
511 if (ui64 <= (uint64_t) NGX_MAX_UINT32_VALUE) {
512
513 /*
514 * To divide 64-bit numbers and to find remainders
515 * on the x86 platform gcc and icc call the libc functions
516 * [u]divdi3() and [u]moddi3(), they call another function
517 * in its turn. On FreeBSD it is the qdivrem() function,
518 * its source code is about 170 lines of the code.
519 * The glibc counterpart is about 150 lines of the code.
520 *
521 * For 32-bit numbers and some divisors gcc and icc use
522 * a inlined multiplication and shifts. For example,
523 * unsigned "i32 / 10" is compiled to
524 *
525 * (i32 * 0xCCCCCCCD) >> 35
526 */
527
528 ui32 = (uint32_t) ui64;
529
530 do {
531 *--p = (u_char) (ui32 % 10 + '0');
532 } while (ui32 /= 10);
533
534 } else {
535 do {
536 *--p = (u_char) (ui64 % 10 + '0');
537 } while (ui64 /= 10);
538 }
539
540 } else if (hexadecimal == 1) {
541
542 do {
543
544 /* the "(uint32_t)" cast disables the BCC's warning */
545 *--p = hex[(uint32_t) (ui64 & 0xf)];
546
547 } while (ui64 >>= 4);
548
549 } else { /* hexadecimal == 2 */
550
551 do {
552
553 /* the "(uint32_t)" cast disables the BCC's warning */
554 *--p = HEX[(uint32_t) (ui64 & 0xf)];
555
556 } while (ui64 >>= 4);
557 }
558
559 /* zero or space padding */
560
561 len = (temp + NGX_INT64_LEN) - p;
562
563 while (len++ < width && buf < last) {
564 *buf++ = zero;
565 }
566
567 /* number safe copy */
568
569 len = (temp + NGX_INT64_LEN) - p;
570
571 if (buf + len > last) {
572 len = last - buf;
573 }
574
575 return ngx_cpymem(buf, p, len);
576 }
577
578
579 /*
580 * We use ngx_strcasecmp()/ngx_strncasecmp() for 7-bit ASCII strings only,
581 * and implement our own ngx_strcasecmp()/ngx_strncasecmp()
582 * to avoid libc locale overhead. Besides, we use the ngx_uint_t's
583 * instead of the u_char's, because they are slightly faster.
584 */
585
586 ngx_int_t
ngx_strcasecmp(u_char * s1,u_char * s2)587 ngx_strcasecmp(u_char *s1, u_char *s2)
588 {
589 ngx_uint_t c1, c2;
590
591 for ( ;; ) {
592 c1 = (ngx_uint_t) *s1++;
593 c2 = (ngx_uint_t) *s2++;
594
595 c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;
596 c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;
597
598 if (c1 == c2) {
599
600 if (c1) {
601 continue;
602 }
603
604 return 0;
605 }
606
607 return c1 - c2;
608 }
609 }
610
611
612 ngx_int_t
ngx_strncasecmp(u_char * s1,u_char * s2,size_t n)613 ngx_strncasecmp(u_char *s1, u_char *s2, size_t n)
614 {
615 ngx_uint_t c1, c2;
616
617 while (n) {
618 c1 = (ngx_uint_t) *s1++;
619 c2 = (ngx_uint_t) *s2++;
620
621 c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;
622 c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;
623
624 if (c1 == c2) {
625
626 if (c1) {
627 n--;
628 continue;
629 }
630
631 return 0;
632 }
633
634 return c1 - c2;
635 }
636
637 return 0;
638 }
639
640
641 u_char *
ngx_strnstr(u_char * s1,char * s2,size_t len)642 ngx_strnstr(u_char *s1, char *s2, size_t len)
643 {
644 u_char c1, c2;
645 size_t n;
646
647 c2 = *(u_char *) s2++;
648
649 n = ngx_strlen(s2);
650
651 do {
652 do {
653 if (len-- == 0) {
654 return NULL;
655 }
656
657 c1 = *s1++;
658
659 if (c1 == 0) {
660 return NULL;
661 }
662
663 } while (c1 != c2);
664
665 if (n > len) {
666 return NULL;
667 }
668
669 } while (ngx_strncmp(s1, (u_char *) s2, n) != 0);
670
671 return --s1;
672 }
673
674
675 /*
676 * ngx_strstrn() and ngx_strcasestrn() are intended to search for static
677 * substring with known length in null-terminated string. The argument n
678 * must be length of the second substring - 1.
679 */
680
681 u_char *
ngx_strstrn(u_char * s1,char * s2,size_t n)682 ngx_strstrn(u_char *s1, char *s2, size_t n)
683 {
684 u_char c1, c2;
685
686 c2 = *(u_char *) s2++;
687
688 do {
689 do {
690 c1 = *s1++;
691
692 if (c1 == 0) {
693 return NULL;
694 }
695
696 } while (c1 != c2);
697
698 } while (ngx_strncmp(s1, (u_char *) s2, n) != 0);
699
700 return --s1;
701 }
702
703
704 u_char *
ngx_strcasestrn(u_char * s1,char * s2,size_t n)705 ngx_strcasestrn(u_char *s1, char *s2, size_t n)
706 {
707 ngx_uint_t c1, c2;
708
709 c2 = (ngx_uint_t) *s2++;
710 c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;
711
712 do {
713 do {
714 c1 = (ngx_uint_t) *s1++;
715
716 if (c1 == 0) {
717 return NULL;
718 }
719
720 c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;
721
722 } while (c1 != c2);
723
724 } while (ngx_strncasecmp(s1, (u_char *) s2, n) != 0);
725
726 return --s1;
727 }
728
729
730 /*
731 * ngx_strlcasestrn() is intended to search for static substring
732 * with known length in string until the argument last. The argument n
733 * must be length of the second substring - 1.
734 */
735
736 u_char *
ngx_strlcasestrn(u_char * s1,u_char * last,u_char * s2,size_t n)737 ngx_strlcasestrn(u_char *s1, u_char *last, u_char *s2, size_t n)
738 {
739 ngx_uint_t c1, c2;
740
741 c2 = (ngx_uint_t) *s2++;
742 c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;
743 last -= n;
744
745 do {
746 do {
747 if (s1 >= last) {
748 return NULL;
749 }
750
751 c1 = (ngx_uint_t) *s1++;
752
753 c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;
754
755 } while (c1 != c2);
756
757 } while (ngx_strncasecmp(s1, s2, n) != 0);
758
759 return --s1;
760 }
761
762
763 ngx_int_t
ngx_rstrncmp(u_char * s1,u_char * s2,size_t n)764 ngx_rstrncmp(u_char *s1, u_char *s2, size_t n)
765 {
766 if (n == 0) {
767 return 0;
768 }
769
770 n--;
771
772 for ( ;; ) {
773 if (s1[n] != s2[n]) {
774 return s1[n] - s2[n];
775 }
776
777 if (n == 0) {
778 return 0;
779 }
780
781 n--;
782 }
783 }
784
785
786 ngx_int_t
ngx_rstrncasecmp(u_char * s1,u_char * s2,size_t n)787 ngx_rstrncasecmp(u_char *s1, u_char *s2, size_t n)
788 {
789 u_char c1, c2;
790
791 if (n == 0) {
792 return 0;
793 }
794
795 n--;
796
797 for ( ;; ) {
798 c1 = s1[n];
799 if (c1 >= 'a' && c1 <= 'z') {
800 c1 -= 'a' - 'A';
801 }
802
803 c2 = s2[n];
804 if (c2 >= 'a' && c2 <= 'z') {
805 c2 -= 'a' - 'A';
806 }
807
808 if (c1 != c2) {
809 return c1 - c2;
810 }
811
812 if (n == 0) {
813 return 0;
814 }
815
816 n--;
817 }
818 }
819
820
821 ngx_int_t
ngx_memn2cmp(u_char * s1,u_char * s2,size_t n1,size_t n2)822 ngx_memn2cmp(u_char *s1, u_char *s2, size_t n1, size_t n2)
823 {
824 size_t n;
825 ngx_int_t m, z;
826
827 if (n1 <= n2) {
828 n = n1;
829 z = -1;
830
831 } else {
832 n = n2;
833 z = 1;
834 }
835
836 m = ngx_memcmp(s1, s2, n);
837
838 if (m || n1 == n2) {
839 return m;
840 }
841
842 return z;
843 }
844
845
846 ngx_int_t
ngx_dns_strcmp(u_char * s1,u_char * s2)847 ngx_dns_strcmp(u_char *s1, u_char *s2)
848 {
849 ngx_uint_t c1, c2;
850
851 for ( ;; ) {
852 c1 = (ngx_uint_t) *s1++;
853 c2 = (ngx_uint_t) *s2++;
854
855 c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;
856 c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;
857
858 if (c1 == c2) {
859
860 if (c1) {
861 continue;
862 }
863
864 return 0;
865 }
866
867 /* in ASCII '.' > '-', but we need '.' to be the lowest character */
868
869 c1 = (c1 == '.') ? ' ' : c1;
870 c2 = (c2 == '.') ? ' ' : c2;
871
872 return c1 - c2;
873 }
874 }
875
876
877 ngx_int_t
ngx_filename_cmp(u_char * s1,u_char * s2,size_t n)878 ngx_filename_cmp(u_char *s1, u_char *s2, size_t n)
879 {
880 ngx_uint_t c1, c2;
881
882 while (n) {
883 c1 = (ngx_uint_t) *s1++;
884 c2 = (ngx_uint_t) *s2++;
885
886 #if (NGX_HAVE_CASELESS_FILESYSTEM)
887 c1 = tolower(c1);
888 c2 = tolower(c2);
889 #endif
890
891 if (c1 == c2) {
892
893 if (c1) {
894 n--;
895 continue;
896 }
897
898 return 0;
899 }
900
901 /* we need '/' to be the lowest character */
902
903 if (c1 == 0 || c2 == 0) {
904 return c1 - c2;
905 }
906
907 c1 = (c1 == '/') ? 0 : c1;
908 c2 = (c2 == '/') ? 0 : c2;
909
910 return c1 - c2;
911 }
912
913 return 0;
914 }
915
916
917 ngx_int_t
ngx_atoi(u_char * line,size_t n)918 ngx_atoi(u_char *line, size_t n)
919 {
920 ngx_int_t value, cutoff, cutlim;
921
922 if (n == 0) {
923 return NGX_ERROR;
924 }
925
926 cutoff = NGX_MAX_INT_T_VALUE / 10;
927 cutlim = NGX_MAX_INT_T_VALUE % 10;
928
929 for (value = 0; n--; line++) {
930 if (*line < '0' || *line > '9') {
931 return NGX_ERROR;
932 }
933
934 if (value >= cutoff && (value > cutoff || *line - '0' > cutlim)) {
935 return NGX_ERROR;
936 }
937
938 value = value * 10 + (*line - '0');
939 }
940
941 return value;
942 }
943
944
945 /* parse a fixed point number, e.g., ngx_atofp("10.5", 4, 2) returns 1050 */
946
947 ngx_int_t
ngx_atofp(u_char * line,size_t n,size_t point)948 ngx_atofp(u_char *line, size_t n, size_t point)
949 {
950 ngx_int_t value, cutoff, cutlim;
951 ngx_uint_t dot;
952
953 if (n == 0) {
954 return NGX_ERROR;
955 }
956
957 cutoff = NGX_MAX_INT_T_VALUE / 10;
958 cutlim = NGX_MAX_INT_T_VALUE % 10;
959
960 dot = 0;
961
962 for (value = 0; n--; line++) {
963
964 if (point == 0) {
965 return NGX_ERROR;
966 }
967
968 if (*line == '.') {
969 if (dot) {
970 return NGX_ERROR;
971 }
972
973 dot = 1;
974 continue;
975 }
976
977 if (*line < '0' || *line > '9') {
978 return NGX_ERROR;
979 }
980
981 if (value >= cutoff && (value > cutoff || *line - '0' > cutlim)) {
982 return NGX_ERROR;
983 }
984
985 value = value * 10 + (*line - '0');
986 point -= dot;
987 }
988
989 while (point--) {
990 if (value > cutoff) {
991 return NGX_ERROR;
992 }
993
994 value = value * 10;
995 }
996
997 return value;
998 }
999
1000
1001 ssize_t
ngx_atosz(u_char * line,size_t n)1002 ngx_atosz(u_char *line, size_t n)
1003 {
1004 ssize_t value, cutoff, cutlim;
1005
1006 if (n == 0) {
1007 return NGX_ERROR;
1008 }
1009
1010 cutoff = NGX_MAX_SIZE_T_VALUE / 10;
1011 cutlim = NGX_MAX_SIZE_T_VALUE % 10;
1012
1013 for (value = 0; n--; line++) {
1014 if (*line < '0' || *line > '9') {
1015 return NGX_ERROR;
1016 }
1017
1018 if (value >= cutoff && (value > cutoff || *line - '0' > cutlim)) {
1019 return NGX_ERROR;
1020 }
1021
1022 value = value * 10 + (*line - '0');
1023 }
1024
1025 return value;
1026 }
1027
1028
1029 off_t
ngx_atoof(u_char * line,size_t n)1030 ngx_atoof(u_char *line, size_t n)
1031 {
1032 off_t value, cutoff, cutlim;
1033
1034 if (n == 0) {
1035 return NGX_ERROR;
1036 }
1037
1038 cutoff = NGX_MAX_OFF_T_VALUE / 10;
1039 cutlim = NGX_MAX_OFF_T_VALUE % 10;
1040
1041 for (value = 0; n--; line++) {
1042 if (*line < '0' || *line > '9') {
1043 return NGX_ERROR;
1044 }
1045
1046 if (value >= cutoff && (value > cutoff || *line - '0' > cutlim)) {
1047 return NGX_ERROR;
1048 }
1049
1050 value = value * 10 + (*line - '0');
1051 }
1052
1053 return value;
1054 }
1055
1056
1057 time_t
ngx_atotm(u_char * line,size_t n)1058 ngx_atotm(u_char *line, size_t n)
1059 {
1060 time_t value, cutoff, cutlim;
1061
1062 if (n == 0) {
1063 return NGX_ERROR;
1064 }
1065
1066 cutoff = NGX_MAX_TIME_T_VALUE / 10;
1067 cutlim = NGX_MAX_TIME_T_VALUE % 10;
1068
1069 for (value = 0; n--; line++) {
1070 if (*line < '0' || *line > '9') {
1071 return NGX_ERROR;
1072 }
1073
1074 if (value >= cutoff && (value > cutoff || *line - '0' > cutlim)) {
1075 return NGX_ERROR;
1076 }
1077
1078 value = value * 10 + (*line - '0');
1079 }
1080
1081 return value;
1082 }
1083
1084
1085 ngx_int_t
ngx_hextoi(u_char * line,size_t n)1086 ngx_hextoi(u_char *line, size_t n)
1087 {
1088 u_char c, ch;
1089 ngx_int_t value, cutoff;
1090
1091 if (n == 0) {
1092 return NGX_ERROR;
1093 }
1094
1095 cutoff = NGX_MAX_INT_T_VALUE / 16;
1096
1097 for (value = 0; n--; line++) {
1098 if (value > cutoff) {
1099 return NGX_ERROR;
1100 }
1101
1102 ch = *line;
1103
1104 if (ch >= '0' && ch <= '9') {
1105 value = value * 16 + (ch - '0');
1106 continue;
1107 }
1108
1109 c = (u_char) (ch | 0x20);
1110
1111 if (c >= 'a' && c <= 'f') {
1112 value = value * 16 + (c - 'a' + 10);
1113 continue;
1114 }
1115
1116 return NGX_ERROR;
1117 }
1118
1119 return value;
1120 }
1121
1122
1123 u_char *
ngx_hex_dump(u_char * dst,u_char * src,size_t len)1124 ngx_hex_dump(u_char *dst, u_char *src, size_t len)
1125 {
1126 static u_char hex[] = "0123456789abcdef";
1127
1128 while (len--) {
1129 *dst++ = hex[*src >> 4];
1130 *dst++ = hex[*src++ & 0xf];
1131 }
1132
1133 return dst;
1134 }
1135
1136
1137 void
ngx_encode_base64(ngx_str_t * dst,ngx_str_t * src)1138 ngx_encode_base64(ngx_str_t *dst, ngx_str_t *src)
1139 {
1140 static u_char basis64[] =
1141 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1142
1143 ngx_encode_base64_internal(dst, src, basis64, 1);
1144 }
1145
1146
1147 void
ngx_encode_base64url(ngx_str_t * dst,ngx_str_t * src)1148 ngx_encode_base64url(ngx_str_t *dst, ngx_str_t *src)
1149 {
1150 static u_char basis64[] =
1151 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
1152
1153 ngx_encode_base64_internal(dst, src, basis64, 0);
1154 }
1155
1156
1157 static void
ngx_encode_base64_internal(ngx_str_t * dst,ngx_str_t * src,const u_char * basis,ngx_uint_t padding)1158 ngx_encode_base64_internal(ngx_str_t *dst, ngx_str_t *src, const u_char *basis,
1159 ngx_uint_t padding)
1160 {
1161 u_char *d, *s;
1162 size_t len;
1163
1164 len = src->len;
1165 s = src->data;
1166 d = dst->data;
1167
1168 while (len > 2) {
1169 *d++ = basis[(s[0] >> 2) & 0x3f];
1170 *d++ = basis[((s[0] & 3) << 4) | (s[1] >> 4)];
1171 *d++ = basis[((s[1] & 0x0f) << 2) | (s[2] >> 6)];
1172 *d++ = basis[s[2] & 0x3f];
1173
1174 s += 3;
1175 len -= 3;
1176 }
1177
1178 if (len) {
1179 *d++ = basis[(s[0] >> 2) & 0x3f];
1180
1181 if (len == 1) {
1182 *d++ = basis[(s[0] & 3) << 4];
1183 if (padding) {
1184 *d++ = '=';
1185 }
1186
1187 } else {
1188 *d++ = basis[((s[0] & 3) << 4) | (s[1] >> 4)];
1189 *d++ = basis[(s[1] & 0x0f) << 2];
1190 }
1191
1192 if (padding) {
1193 *d++ = '=';
1194 }
1195 }
1196
1197 dst->len = d - dst->data;
1198 }
1199
1200
1201 ngx_int_t
ngx_decode_base64(ngx_str_t * dst,ngx_str_t * src)1202 ngx_decode_base64(ngx_str_t *dst, ngx_str_t *src)
1203 {
1204 static u_char basis64[] = {
1205 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
1206 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
1207 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 62, 77, 77, 77, 63,
1208 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 77, 77, 77, 77, 77, 77,
1209 77, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
1210 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 77, 77, 77, 77, 77,
1211 77, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
1212 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 77, 77, 77, 77, 77,
1213
1214 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
1215 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
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, 77, 77, 77,
1219 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
1220 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
1221 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77
1222 };
1223
1224 return ngx_decode_base64_internal(dst, src, basis64);
1225 }
1226
1227
1228 ngx_int_t
ngx_decode_base64url(ngx_str_t * dst,ngx_str_t * src)1229 ngx_decode_base64url(ngx_str_t *dst, ngx_str_t *src)
1230 {
1231 static u_char basis64[] = {
1232 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
1233 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
1234 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 62, 77, 77,
1235 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 77, 77, 77, 77, 77, 77,
1236 77, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
1237 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 77, 77, 77, 77, 63,
1238 77, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
1239 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 77, 77, 77, 77, 77,
1240
1241 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
1242 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
1243 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
1244 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
1245 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
1246 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
1247 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
1248 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77
1249 };
1250
1251 return ngx_decode_base64_internal(dst, src, basis64);
1252 }
1253
1254
1255 static ngx_int_t
ngx_decode_base64_internal(ngx_str_t * dst,ngx_str_t * src,const u_char * basis)1256 ngx_decode_base64_internal(ngx_str_t *dst, ngx_str_t *src, const u_char *basis)
1257 {
1258 size_t len;
1259 u_char *d, *s;
1260
1261 for (len = 0; len < src->len; len++) {
1262 if (src->data[len] == '=') {
1263 break;
1264 }
1265
1266 if (basis[src->data[len]] == 77) {
1267 return NGX_ERROR;
1268 }
1269 }
1270
1271 if (len % 4 == 1) {
1272 return NGX_ERROR;
1273 }
1274
1275 s = src->data;
1276 d = dst->data;
1277
1278 while (len > 3) {
1279 *d++ = (u_char) (basis[s[0]] << 2 | basis[s[1]] >> 4);
1280 *d++ = (u_char) (basis[s[1]] << 4 | basis[s[2]] >> 2);
1281 *d++ = (u_char) (basis[s[2]] << 6 | basis[s[3]]);
1282
1283 s += 4;
1284 len -= 4;
1285 }
1286
1287 if (len > 1) {
1288 *d++ = (u_char) (basis[s[0]] << 2 | basis[s[1]] >> 4);
1289 }
1290
1291 if (len > 2) {
1292 *d++ = (u_char) (basis[s[1]] << 4 | basis[s[2]] >> 2);
1293 }
1294
1295 dst->len = d - dst->data;
1296
1297 return NGX_OK;
1298 }
1299
1300
1301 /*
1302 * ngx_utf8_decode() decodes two and more bytes UTF sequences only
1303 * the return values:
1304 * 0x80 - 0x10ffff valid character
1305 * 0x110000 - 0xfffffffd invalid sequence
1306 * 0xfffffffe incomplete sequence
1307 * 0xffffffff error
1308 */
1309
1310 uint32_t
ngx_utf8_decode(u_char ** p,size_t n)1311 ngx_utf8_decode(u_char **p, size_t n)
1312 {
1313 size_t len;
1314 uint32_t u, i, valid;
1315
1316 u = **p;
1317
1318 if (u >= 0xf0) {
1319
1320 u &= 0x07;
1321 valid = 0xffff;
1322 len = 3;
1323
1324 } else if (u >= 0xe0) {
1325
1326 u &= 0x0f;
1327 valid = 0x7ff;
1328 len = 2;
1329
1330 } else if (u >= 0xc2) {
1331
1332 u &= 0x1f;
1333 valid = 0x7f;
1334 len = 1;
1335
1336 } else {
1337 (*p)++;
1338 return 0xffffffff;
1339 }
1340
1341 if (n - 1 < len) {
1342 return 0xfffffffe;
1343 }
1344
1345 (*p)++;
1346
1347 while (len) {
1348 i = *(*p)++;
1349
1350 if (i < 0x80) {
1351 return 0xffffffff;
1352 }
1353
1354 u = (u << 6) | (i & 0x3f);
1355
1356 len--;
1357 }
1358
1359 if (u > valid) {
1360 return u;
1361 }
1362
1363 return 0xffffffff;
1364 }
1365
1366
1367 size_t
ngx_utf8_length(u_char * p,size_t n)1368 ngx_utf8_length(u_char *p, size_t n)
1369 {
1370 u_char c, *last;
1371 size_t len;
1372
1373 last = p + n;
1374
1375 for (len = 0; p < last; len++) {
1376
1377 c = *p;
1378
1379 if (c < 0x80) {
1380 p++;
1381 continue;
1382 }
1383
1384 if (ngx_utf8_decode(&p, last - p) > 0x10ffff) {
1385 /* invalid UTF-8 */
1386 return n;
1387 }
1388 }
1389
1390 return len;
1391 }
1392
1393
1394 u_char *
ngx_utf8_cpystrn(u_char * dst,u_char * src,size_t n,size_t len)1395 ngx_utf8_cpystrn(u_char *dst, u_char *src, size_t n, size_t len)
1396 {
1397 u_char c, *next;
1398
1399 if (n == 0) {
1400 return dst;
1401 }
1402
1403 while (--n) {
1404
1405 c = *src;
1406 *dst = c;
1407
1408 if (c < 0x80) {
1409
1410 if (c != '\0') {
1411 dst++;
1412 src++;
1413 len--;
1414
1415 continue;
1416 }
1417
1418 return dst;
1419 }
1420
1421 next = src;
1422
1423 if (ngx_utf8_decode(&next, len) > 0x10ffff) {
1424 /* invalid UTF-8 */
1425 break;
1426 }
1427
1428 while (src < next) {
1429 *dst++ = *src++;
1430 len--;
1431 }
1432 }
1433
1434 *dst = '\0';
1435
1436 return dst;
1437 }
1438
1439
1440 uintptr_t
ngx_escape_uri(u_char * dst,u_char * src,size_t size,ngx_uint_t type)1441 ngx_escape_uri(u_char *dst, u_char *src, size_t size, ngx_uint_t type)
1442 {
1443 ngx_uint_t n;
1444 uint32_t *escape;
1445 static u_char hex[] = "0123456789ABCDEF";
1446
1447 /* " ", "#", "%", "?", %00-%1F, %7F-%FF */
1448
1449 static uint32_t uri[] = {
1450 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1451
1452 /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
1453 0x80000029, /* 1000 0000 0000 0000 0000 0000 0010 1001 */
1454
1455 /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
1456 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1457
1458 /* ~}| {zyx wvut srqp onml kjih gfed cba` */
1459 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */
1460
1461 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1462 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1463 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1464 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1465 };
1466
1467 /* " ", "#", "%", "&", "+", "?", %00-%1F, %7F-%FF */
1468
1469 static uint32_t args[] = {
1470 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1471
1472 /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
1473 0x88000869, /* 1000 1000 0000 0000 0000 1000 0110 1001 */
1474
1475 /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
1476 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1477
1478 /* ~}| {zyx wvut srqp onml kjih gfed cba` */
1479 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */
1480
1481 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1482 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1483 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1484 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1485 };
1486
1487 /* not ALPHA, DIGIT, "-", ".", "_", "~" */
1488
1489 static uint32_t uri_component[] = {
1490 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1491
1492 /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
1493 0xfc009fff, /* 1111 1100 0000 0000 1001 1111 1111 1111 */
1494
1495 /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
1496 0x78000001, /* 0111 1000 0000 0000 0000 0000 0000 0001 */
1497
1498 /* ~}| {zyx wvut srqp onml kjih gfed cba` */
1499 0xb8000001, /* 1011 1000 0000 0000 0000 0000 0000 0001 */
1500
1501 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1502 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1503 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1504 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1505 };
1506
1507 /* " ", "#", """, "%", "'", %00-%1F, %7F-%FF */
1508
1509 static uint32_t html[] = {
1510 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1511
1512 /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
1513 0x000000ad, /* 0000 0000 0000 0000 0000 0000 1010 1101 */
1514
1515 /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
1516 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1517
1518 /* ~}| {zyx wvut srqp onml kjih gfed cba` */
1519 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */
1520
1521 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1522 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1523 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1524 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1525 };
1526
1527 /* " ", """, "%", "'", %00-%1F, %7F-%FF */
1528
1529 static uint32_t refresh[] = {
1530 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1531
1532 /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
1533 0x00000085, /* 0000 0000 0000 0000 0000 0000 1000 0101 */
1534
1535 /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
1536 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1537
1538 /* ~}| {zyx wvut srqp onml kjih gfed cba` */
1539 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */
1540
1541 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1542 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1543 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1544 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1545 };
1546
1547 /* " ", "%", %00-%1F */
1548
1549 static uint32_t memcached[] = {
1550 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1551
1552 /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
1553 0x00000021, /* 0000 0000 0000 0000 0000 0000 0010 0001 */
1554
1555 /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
1556 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1557
1558 /* ~}| {zyx wvut srqp onml kjih gfed cba` */
1559 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1560
1561 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1562 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1563 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1564 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1565 };
1566
1567 /* mail_auth is the same as memcached */
1568
1569 static uint32_t *map[] =
1570 { uri, args, uri_component, html, refresh, memcached, memcached };
1571
1572
1573 escape = map[type];
1574
1575 if (dst == NULL) {
1576
1577 /* find the number of the characters to be escaped */
1578
1579 n = 0;
1580
1581 while (size) {
1582 if (escape[*src >> 5] & (1U << (*src & 0x1f))) {
1583 n++;
1584 }
1585 src++;
1586 size--;
1587 }
1588
1589 return (uintptr_t) n;
1590 }
1591
1592 while (size) {
1593 if (escape[*src >> 5] & (1U << (*src & 0x1f))) {
1594 *dst++ = '%';
1595 *dst++ = hex[*src >> 4];
1596 *dst++ = hex[*src & 0xf];
1597 src++;
1598
1599 } else {
1600 *dst++ = *src++;
1601 }
1602 size--;
1603 }
1604
1605 return (uintptr_t) dst;
1606 }
1607
1608
1609 void
ngx_unescape_uri(u_char ** dst,u_char ** src,size_t size,ngx_uint_t type)1610 ngx_unescape_uri(u_char **dst, u_char **src, size_t size, ngx_uint_t type)
1611 {
1612 u_char *d, *s, ch, c, decoded;
1613 enum {
1614 sw_usual = 0,
1615 sw_quoted,
1616 sw_quoted_second
1617 } state;
1618
1619 d = *dst;
1620 s = *src;
1621
1622 state = 0;
1623 decoded = 0;
1624
1625 while (size--) {
1626
1627 ch = *s++;
1628
1629 switch (state) {
1630 case sw_usual:
1631 if (ch == '?'
1632 && (type & (NGX_UNESCAPE_URI|NGX_UNESCAPE_REDIRECT)))
1633 {
1634 *d++ = ch;
1635 goto done;
1636 }
1637
1638 if (ch == '%') {
1639 state = sw_quoted;
1640 break;
1641 }
1642
1643 *d++ = ch;
1644 break;
1645
1646 case sw_quoted:
1647
1648 if (ch >= '0' && ch <= '9') {
1649 decoded = (u_char) (ch - '0');
1650 state = sw_quoted_second;
1651 break;
1652 }
1653
1654 c = (u_char) (ch | 0x20);
1655 if (c >= 'a' && c <= 'f') {
1656 decoded = (u_char) (c - 'a' + 10);
1657 state = sw_quoted_second;
1658 break;
1659 }
1660
1661 /* the invalid quoted character */
1662
1663 state = sw_usual;
1664
1665 *d++ = ch;
1666
1667 break;
1668
1669 case sw_quoted_second:
1670
1671 state = sw_usual;
1672
1673 if (ch >= '0' && ch <= '9') {
1674 ch = (u_char) ((decoded << 4) + (ch - '0'));
1675
1676 if (type & NGX_UNESCAPE_REDIRECT) {
1677 if (ch > '%' && ch < 0x7f) {
1678 *d++ = ch;
1679 break;
1680 }
1681
1682 *d++ = '%'; *d++ = *(s - 2); *d++ = *(s - 1);
1683
1684 break;
1685 }
1686
1687 *d++ = ch;
1688
1689 break;
1690 }
1691
1692 c = (u_char) (ch | 0x20);
1693 if (c >= 'a' && c <= 'f') {
1694 ch = (u_char) ((decoded << 4) + (c - 'a') + 10);
1695
1696 if (type & NGX_UNESCAPE_URI) {
1697 if (ch == '?') {
1698 *d++ = ch;
1699 goto done;
1700 }
1701
1702 *d++ = ch;
1703 break;
1704 }
1705
1706 if (type & NGX_UNESCAPE_REDIRECT) {
1707 if (ch == '?') {
1708 *d++ = ch;
1709 goto done;
1710 }
1711
1712 if (ch > '%' && ch < 0x7f) {
1713 *d++ = ch;
1714 break;
1715 }
1716
1717 *d++ = '%'; *d++ = *(s - 2); *d++ = *(s - 1);
1718 break;
1719 }
1720
1721 *d++ = ch;
1722
1723 break;
1724 }
1725
1726 /* the invalid quoted character */
1727
1728 break;
1729 }
1730 }
1731
1732 done:
1733
1734 *dst = d;
1735 *src = s;
1736 }
1737
1738
1739 uintptr_t
ngx_escape_html(u_char * dst,u_char * src,size_t size)1740 ngx_escape_html(u_char *dst, u_char *src, size_t size)
1741 {
1742 u_char ch;
1743 ngx_uint_t len;
1744
1745 if (dst == NULL) {
1746
1747 len = 0;
1748
1749 while (size) {
1750 switch (*src++) {
1751
1752 case '<':
1753 len += sizeof("<") - 2;
1754 break;
1755
1756 case '>':
1757 len += sizeof(">") - 2;
1758 break;
1759
1760 case '&':
1761 len += sizeof("&") - 2;
1762 break;
1763
1764 case '"':
1765 len += sizeof(""") - 2;
1766 break;
1767
1768 default:
1769 break;
1770 }
1771 size--;
1772 }
1773
1774 return (uintptr_t) len;
1775 }
1776
1777 while (size) {
1778 ch = *src++;
1779
1780 switch (ch) {
1781
1782 case '<':
1783 *dst++ = '&'; *dst++ = 'l'; *dst++ = 't'; *dst++ = ';';
1784 break;
1785
1786 case '>':
1787 *dst++ = '&'; *dst++ = 'g'; *dst++ = 't'; *dst++ = ';';
1788 break;
1789
1790 case '&':
1791 *dst++ = '&'; *dst++ = 'a'; *dst++ = 'm'; *dst++ = 'p';
1792 *dst++ = ';';
1793 break;
1794
1795 case '"':
1796 *dst++ = '&'; *dst++ = 'q'; *dst++ = 'u'; *dst++ = 'o';
1797 *dst++ = 't'; *dst++ = ';';
1798 break;
1799
1800 default:
1801 *dst++ = ch;
1802 break;
1803 }
1804 size--;
1805 }
1806
1807 return (uintptr_t) dst;
1808 }
1809
1810
1811 uintptr_t
ngx_escape_json(u_char * dst,u_char * src,size_t size)1812 ngx_escape_json(u_char *dst, u_char *src, size_t size)
1813 {
1814 u_char ch;
1815 ngx_uint_t len;
1816
1817 if (dst == NULL) {
1818 len = 0;
1819
1820 while (size) {
1821 ch = *src++;
1822
1823 if (ch == '\\' || ch == '"') {
1824 len++;
1825
1826 } else if (ch <= 0x1f) {
1827
1828 switch (ch) {
1829 case '\n':
1830 case '\r':
1831 case '\t':
1832 case '\b':
1833 case '\f':
1834 len++;
1835 break;
1836
1837 default:
1838 len += sizeof("\\u001F") - 2;
1839 }
1840 }
1841
1842 size--;
1843 }
1844
1845 return (uintptr_t) len;
1846 }
1847
1848 while (size) {
1849 ch = *src++;
1850
1851 if (ch > 0x1f) {
1852
1853 if (ch == '\\' || ch == '"') {
1854 *dst++ = '\\';
1855 }
1856
1857 *dst++ = ch;
1858
1859 } else {
1860 *dst++ = '\\';
1861
1862 switch (ch) {
1863 case '\n':
1864 *dst++ = 'n';
1865 break;
1866
1867 case '\r':
1868 *dst++ = 'r';
1869 break;
1870
1871 case '\t':
1872 *dst++ = 't';
1873 break;
1874
1875 case '\b':
1876 *dst++ = 'b';
1877 break;
1878
1879 case '\f':
1880 *dst++ = 'f';
1881 break;
1882
1883 default:
1884 *dst++ = 'u'; *dst++ = '0'; *dst++ = '0';
1885 *dst++ = '0' + (ch >> 4);
1886
1887 ch &= 0xf;
1888
1889 *dst++ = (ch < 10) ? ('0' + ch) : ('A' + ch - 10);
1890 }
1891 }
1892
1893 size--;
1894 }
1895
1896 return (uintptr_t) dst;
1897 }
1898
1899
1900 void
ngx_str_rbtree_insert_value(ngx_rbtree_node_t * temp,ngx_rbtree_node_t * node,ngx_rbtree_node_t * sentinel)1901 ngx_str_rbtree_insert_value(ngx_rbtree_node_t *temp,
1902 ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
1903 {
1904 ngx_str_node_t *n, *t;
1905 ngx_rbtree_node_t **p;
1906
1907 for ( ;; ) {
1908
1909 n = (ngx_str_node_t *) node;
1910 t = (ngx_str_node_t *) temp;
1911
1912 if (node->key != temp->key) {
1913
1914 p = (node->key < temp->key) ? &temp->left : &temp->right;
1915
1916 } else if (n->str.len != t->str.len) {
1917
1918 p = (n->str.len < t->str.len) ? &temp->left : &temp->right;
1919
1920 } else {
1921 p = (ngx_memcmp(n->str.data, t->str.data, n->str.len) < 0)
1922 ? &temp->left : &temp->right;
1923 }
1924
1925 if (*p == sentinel) {
1926 break;
1927 }
1928
1929 temp = *p;
1930 }
1931
1932 *p = node;
1933 node->parent = temp;
1934 node->left = sentinel;
1935 node->right = sentinel;
1936 ngx_rbt_red(node);
1937 }
1938
1939
1940 ngx_str_node_t *
ngx_str_rbtree_lookup(ngx_rbtree_t * rbtree,ngx_str_t * val,uint32_t hash)1941 ngx_str_rbtree_lookup(ngx_rbtree_t *rbtree, ngx_str_t *val, uint32_t hash)
1942 {
1943 ngx_int_t rc;
1944 ngx_str_node_t *n;
1945 ngx_rbtree_node_t *node, *sentinel;
1946
1947 node = rbtree->root;
1948 sentinel = rbtree->sentinel;
1949
1950 while (node != sentinel) {
1951
1952 n = (ngx_str_node_t *) node;
1953
1954 if (hash != node->key) {
1955 node = (hash < node->key) ? node->left : node->right;
1956 continue;
1957 }
1958
1959 if (val->len != n->str.len) {
1960 node = (val->len < n->str.len) ? node->left : node->right;
1961 continue;
1962 }
1963
1964 rc = ngx_memcmp(val->data, n->str.data, val->len);
1965
1966 if (rc < 0) {
1967 node = node->left;
1968 continue;
1969 }
1970
1971 if (rc > 0) {
1972 node = node->right;
1973 continue;
1974 }
1975
1976 return n;
1977 }
1978
1979 return NULL;
1980 }
1981
1982
1983 /* ngx_sort() is implemented as insertion sort because we need stable sort */
1984
1985 void
ngx_sort(void * base,size_t n,size_t size,ngx_int_t (* cmp)(const void *,const void *))1986 ngx_sort(void *base, size_t n, size_t size,
1987 ngx_int_t (*cmp)(const void *, const void *))
1988 {
1989 u_char *p1, *p2, *p;
1990
1991 p = ngx_alloc(size, ngx_cycle->log);
1992 if (p == NULL) {
1993 return;
1994 }
1995
1996 for (p1 = (u_char *) base + size;
1997 p1 < (u_char *) base + n * size;
1998 p1 += size)
1999 {
2000 ngx_memcpy(p, p1, size);
2001
2002 for (p2 = p1;
2003 p2 > (u_char *) base && cmp(p2 - size, p) > 0;
2004 p2 -= size)
2005 {
2006 ngx_memcpy(p2, p2 - size, size);
2007 }
2008
2009 ngx_memcpy(p2, p, size);
2010 }
2011
2012 ngx_free(p);
2013 }
2014
2015
2016 void
ngx_explicit_memzero(void * buf,size_t n)2017 ngx_explicit_memzero(void *buf, size_t n)
2018 {
2019 ngx_memzero(buf, n);
2020 ngx_memory_barrier();
2021 }
2022
2023
2024 #if (NGX_MEMCPY_LIMIT)
2025
2026 void *
ngx_memcpy(void * dst,const void * src,size_t n)2027 ngx_memcpy(void *dst, const void *src, size_t n)
2028 {
2029 if (n > NGX_MEMCPY_LIMIT) {
2030 ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "memcpy %uz bytes", n);
2031 ngx_debug_point();
2032 }
2033
2034 return memcpy(dst, src, n);
2035 }
2036
2037 #endif
2038