xref: /f-stack/app/nginx-1.16.1/src/core/ngx_string.c (revision 3da8d17d)
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("&lt;") - 2;
1754                 break;
1755 
1756             case '>':
1757                 len += sizeof("&gt;") - 2;
1758                 break;
1759 
1760             case '&':
1761                 len += sizeof("&amp;") - 2;
1762                 break;
1763 
1764             case '"':
1765                 len += sizeof("&quot;") - 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