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