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