xref: /unit/src/nxt_conf.c (revision 1049:961567625038)
1 
2 /*
3  * Copyright (C) Igor Sysoev
4  * Copyright (C) Valentin V. Bartenev
5  * Copyright (C) NGINX, Inc.
6  */
7 
8 #include <nxt_main.h>
9 #include <nxt_conf.h>
10 #if 0
11 #include <math.h>
12 #include <float.h>
13 #endif
14 
15 
16 #define NXT_CONF_MAX_SHORT_STRING  14
17 #define NXT_CONF_MAX_STRING        NXT_INT32_T_MAX
18 
19 
20 typedef enum {
21     NXT_CONF_VALUE_NULL = 0,
22     NXT_CONF_VALUE_BOOLEAN,
23     NXT_CONF_VALUE_INTEGER,
24     NXT_CONF_VALUE_NUMBER,
25     NXT_CONF_VALUE_SHORT_STRING,
26     NXT_CONF_VALUE_STRING,
27     NXT_CONF_VALUE_ARRAY,
28     NXT_CONF_VALUE_OBJECT,
29 } nxt_conf_value_type_t;
30 
31 
32 typedef enum {
33     NXT_CONF_OP_PASS = 0,
34     NXT_CONF_OP_CREATE,
35     NXT_CONF_OP_REPLACE,
36     NXT_CONF_OP_DELETE,
37 } nxt_conf_op_action_t;
38 
39 
40 typedef struct nxt_conf_array_s   nxt_conf_array_t;
41 typedef struct nxt_conf_object_s  nxt_conf_object_t;
42 
43 
44 struct nxt_conf_value_s {
45     union {
46         uint8_t               boolean;  /* 1 bit. */
47         int64_t               integer;
48         double                number;
49 
50         struct {
51             u_char            start[NXT_CONF_MAX_SHORT_STRING];
52             uint8_t           length;
53         } str;
54 
55         struct {
56             u_char            *start;
57             uint32_t          length;
58         } nxt_packed string;
59 
60         nxt_conf_array_t      *array;
61         nxt_conf_object_t     *object;
62     } nxt_packed u;
63 
64     uint8_t                   type;  /* 3 bits. */
65 } nxt_aligned(8);
66 
67 
68 struct nxt_conf_array_s {
69     nxt_uint_t                count;
70     nxt_conf_value_t          elements[];
71 };
72 
73 
74 typedef struct {
75     nxt_conf_value_t          name;
76     nxt_conf_value_t          value;
77 } nxt_conf_object_member_t;
78 
79 
80 struct nxt_conf_object_s {
81     nxt_uint_t                count;
82     nxt_conf_object_member_t  members[];
83 };
84 
85 
86 struct nxt_conf_op_s {
87     uint32_t                  index;
88     uint32_t                  action;  /* nxt_conf_op_action_t */
89     void                      *ctx;
90 };
91 
92 
93 static u_char *nxt_conf_json_skip_space(u_char *start, u_char *end);
94 static u_char *nxt_conf_json_parse_value(nxt_mp_t *mp, nxt_conf_value_t *value,
95     u_char *start, u_char *end, nxt_conf_json_error_t *error);
96 static u_char *nxt_conf_json_parse_object(nxt_mp_t *mp, nxt_conf_value_t *value,
97     u_char *start, u_char *end, nxt_conf_json_error_t *error);
98 static nxt_int_t nxt_conf_object_hash_add(nxt_mp_t *mp,
99     nxt_lvlhsh_t *lvlhsh, nxt_conf_object_member_t *member);
100 static nxt_int_t nxt_conf_object_hash_test(nxt_lvlhsh_query_t *lhq,
101     void *data);
102 static void *nxt_conf_object_hash_alloc(void *data, size_t size);
103 static void nxt_conf_object_hash_free(void *data, void *p);
104 static u_char *nxt_conf_json_parse_array(nxt_mp_t *mp, nxt_conf_value_t *value,
105     u_char *start, u_char *end, nxt_conf_json_error_t *error);
106 static u_char *nxt_conf_json_parse_string(nxt_mp_t *mp, nxt_conf_value_t *value,
107     u_char *start, u_char *end, nxt_conf_json_error_t *error);
108 static u_char *nxt_conf_json_parse_number(nxt_mp_t *mp, nxt_conf_value_t *value,
109     u_char *start, u_char *end, nxt_conf_json_error_t *error);
110 static void nxt_conf_json_parse_error(nxt_conf_json_error_t *error, u_char *pos,
111     const char *detail);
112 
113 static nxt_int_t nxt_conf_copy_value(nxt_mp_t *mp, nxt_conf_op_t *op,
114     nxt_conf_value_t *dst, nxt_conf_value_t *src);
115 static nxt_int_t nxt_conf_copy_array(nxt_mp_t *mp, nxt_conf_op_t *op,
116     nxt_conf_value_t *dst, nxt_conf_value_t *src);
117 static nxt_int_t nxt_conf_copy_object(nxt_mp_t *mp, nxt_conf_op_t *op,
118     nxt_conf_value_t *dst, nxt_conf_value_t *src);
119 
120 static size_t nxt_conf_json_integer_length(nxt_conf_value_t *value);
121 static u_char *nxt_conf_json_print_integer(u_char *p, nxt_conf_value_t *value);
122 static size_t nxt_conf_json_string_length(nxt_conf_value_t *value);
123 static u_char *nxt_conf_json_print_string(u_char *p, nxt_conf_value_t *value);
124 static size_t nxt_conf_json_array_length(nxt_conf_value_t *value,
125     nxt_conf_json_pretty_t *pretty);
126 static u_char *nxt_conf_json_print_array(u_char *p, nxt_conf_value_t *value,
127     nxt_conf_json_pretty_t *pretty);
128 static size_t nxt_conf_json_object_length(nxt_conf_value_t *value,
129     nxt_conf_json_pretty_t *pretty);
130 static u_char *nxt_conf_json_print_object(u_char *p, nxt_conf_value_t *value,
131     nxt_conf_json_pretty_t *pretty);
132 
133 static size_t nxt_conf_json_escape_length(u_char *p, size_t size);
134 static u_char *nxt_conf_json_escape(u_char *dst, u_char *src, size_t size);
135 
136 
137 #define nxt_conf_json_newline(p)                                              \
138     ((p)[0] = '\r', (p)[1] = '\n', (p) + 2)
139 
140 
141 nxt_inline u_char *
142 nxt_conf_json_indentation(u_char *p, uint32_t level)
143 {
144     while (level) {
145         *p++ = '\t';
146         level--;
147     }
148 
149     return p;
150 }
151 
152 
153 void
154 nxt_conf_get_string(nxt_conf_value_t *value, nxt_str_t *str)
155 {
156     if (value->type == NXT_CONF_VALUE_SHORT_STRING) {
157         str->length = value->u.str.length;
158         str->start = value->u.str.start;
159 
160     } else {
161         str->length = value->u.string.length;
162         str->start = value->u.string.start;
163     }
164 }
165 
166 
167 void
168 nxt_conf_set_string(nxt_conf_value_t *value, nxt_str_t *str)
169 {
170     if (str->length > NXT_CONF_MAX_SHORT_STRING) {
171         value->type = NXT_CONF_VALUE_STRING;
172         value->u.string.length = str->length;
173         value->u.string.start = str->start;
174 
175     } else {
176         value->type = NXT_CONF_VALUE_SHORT_STRING;
177         value->u.str.length = str->length;
178 
179         nxt_memcpy(value->u.str.start, str->start, str->length);
180     }
181 }
182 
183 
184 nxt_int_t
185 nxt_conf_set_string_dup(nxt_conf_value_t *value, nxt_mp_t *mp, nxt_str_t *str)
186 {
187     nxt_str_t  tmp, *ptr;
188 
189     if (str->length > NXT_CONF_MAX_SHORT_STRING) {
190         value->type = NXT_CONF_VALUE_STRING;
191 
192         ptr = nxt_str_dup(mp, &tmp, str);
193         if (nxt_slow_path(ptr == NULL)) {
194             return NXT_ERROR;
195         }
196 
197         value->u.string.length = tmp.length;
198         value->u.string.start = tmp.start;
199 
200     } else {
201         value->type = NXT_CONF_VALUE_SHORT_STRING;
202         value->u.str.length = str->length;
203 
204         nxt_memcpy(value->u.str.start, str->start, str->length);
205     }
206 
207     return NXT_OK;
208 }
209 
210 
211 int64_t
212 nxt_conf_get_integer(nxt_conf_value_t *value)
213 {
214     return value->u.integer;
215 }
216 
217 
218 nxt_uint_t
219 nxt_conf_object_members_count(nxt_conf_value_t *value)
220 {
221     return value->u.object->count;
222 }
223 
224 
225 nxt_conf_value_t *
226 nxt_conf_create_object(nxt_mp_t *mp, nxt_uint_t count)
227 {
228     size_t            size;
229     nxt_conf_value_t  *value;
230 
231     size = sizeof(nxt_conf_value_t)
232            + sizeof(nxt_conf_object_t)
233            + count * sizeof(nxt_conf_object_member_t);
234 
235     value = nxt_mp_get(mp, size);
236     if (nxt_slow_path(value == NULL)) {
237         return NULL;
238     }
239 
240     value->u.object = nxt_pointer_to(value, sizeof(nxt_conf_value_t));
241     value->u.object->count = count;
242 
243     value->type = NXT_CONF_VALUE_OBJECT;
244 
245     return value;
246 }
247 
248 
249 void
250 nxt_conf_set_member(nxt_conf_value_t *object, nxt_str_t *name,
251     nxt_conf_value_t *value, uint32_t index)
252 {
253     nxt_conf_object_member_t  *member;
254 
255     member = &object->u.object->members[index];
256 
257     nxt_conf_set_string(&member->name, name);
258 
259     member->value = *value;
260 }
261 
262 
263 void
264 nxt_conf_set_member_string(nxt_conf_value_t *object, nxt_str_t *name,
265     nxt_str_t *value, uint32_t index)
266 {
267     nxt_conf_object_member_t  *member;
268 
269     member = &object->u.object->members[index];
270 
271     nxt_conf_set_string(&member->name, name);
272 
273     nxt_conf_set_string(&member->value, value);
274 }
275 
276 
277 nxt_int_t
278 nxt_conf_set_member_string_dup(nxt_conf_value_t *object, nxt_mp_t *mp,
279     nxt_str_t *name, nxt_str_t *value, uint32_t index)
280 {
281     nxt_conf_object_member_t  *member;
282 
283     member = &object->u.object->members[index];
284 
285     nxt_conf_set_string(&member->name, name);
286 
287     return nxt_conf_set_string_dup(&member->value, mp, value);
288 }
289 
290 
291 void
292 nxt_conf_set_member_integer(nxt_conf_value_t *object, nxt_str_t *name,
293     int64_t value, uint32_t index)
294 {
295     nxt_conf_object_member_t  *member;
296 
297     member = &object->u.object->members[index];
298 
299     nxt_conf_set_string(&member->name, name);
300 
301     member->value.u.integer = value;
302     member->value.type = NXT_CONF_VALUE_INTEGER;
303 }
304 
305 
306 void
307 nxt_conf_set_member_null(nxt_conf_value_t *object, nxt_str_t *name,
308     uint32_t index)
309 {
310     nxt_conf_object_member_t  *member;
311 
312     member = &object->u.object->members[index];
313 
314     nxt_conf_set_string(&member->name, name);
315 
316     member->value.type = NXT_CONF_VALUE_NULL;
317 }
318 
319 
320 nxt_conf_value_t *
321 nxt_conf_create_array(nxt_mp_t *mp, nxt_uint_t count)
322 {
323     size_t            size;
324     nxt_conf_value_t  *value;
325 
326     size = sizeof(nxt_conf_value_t)
327            + sizeof(nxt_conf_array_t)
328            + count * sizeof(nxt_conf_value_t);
329 
330     value = nxt_mp_get(mp, size);
331     if (nxt_slow_path(value == NULL)) {
332         return NULL;
333     }
334 
335     value->u.array = nxt_pointer_to(value, sizeof(nxt_conf_value_t));
336     value->u.array->count = count;
337 
338     value->type = NXT_CONF_VALUE_ARRAY;
339 
340     return value;
341 }
342 
343 
344 void
345 nxt_conf_set_element(nxt_conf_value_t *array, nxt_uint_t index,
346     nxt_conf_value_t *value)
347 {
348     array->u.array->elements[index] = *value;
349 }
350 
351 
352 nxt_int_t
353 nxt_conf_set_element_string_dup(nxt_conf_value_t *array, nxt_mp_t *mp,
354     nxt_uint_t index, nxt_str_t *value)
355 {
356     nxt_conf_value_t  *element;
357 
358     element = &array->u.array->elements[index];
359 
360     return nxt_conf_set_string_dup(element, mp, value);
361 }
362 
363 
364 nxt_uint_t
365 nxt_conf_array_elements_count(nxt_conf_value_t *value)
366 {
367     return value->u.array->count;
368 }
369 
370 
371 nxt_uint_t
372 nxt_conf_type(nxt_conf_value_t *value)
373 {
374     switch (value->type) {
375 
376     case NXT_CONF_VALUE_NULL:
377         return NXT_CONF_NULL;
378 
379     case NXT_CONF_VALUE_BOOLEAN:
380         return NXT_CONF_BOOLEAN;
381 
382     case NXT_CONF_VALUE_INTEGER:
383         return NXT_CONF_INTEGER;
384 
385     case NXT_CONF_VALUE_NUMBER:
386         return NXT_CONF_NUMBER;
387 
388     case NXT_CONF_VALUE_SHORT_STRING:
389     case NXT_CONF_VALUE_STRING:
390         return NXT_CONF_STRING;
391 
392     case NXT_CONF_VALUE_ARRAY:
393         return NXT_CONF_ARRAY;
394 
395     case NXT_CONF_VALUE_OBJECT:
396         return NXT_CONF_OBJECT;
397     }
398 
399     nxt_unreachable();
400 
401     return 0;
402 }
403 
404 
405 typedef struct {
406     u_char      *start;
407     u_char      *end;
408     nxt_bool_t  last;
409 } nxt_conf_path_parse_t;
410 
411 
412 static void nxt_conf_path_next_token(nxt_conf_path_parse_t *parse,
413     nxt_str_t *token);
414 
415 
416 nxt_conf_value_t *
417 nxt_conf_get_path(nxt_conf_value_t *value, nxt_str_t *path)
418 {
419     nxt_str_t              token;
420     nxt_int_t              index;
421     nxt_conf_path_parse_t  parse;
422 
423     parse.start = path->start;
424     parse.end = path->start + path->length;
425     parse.last = 0;
426 
427     do {
428         nxt_conf_path_next_token(&parse, &token);
429 
430         if (token.length == 0) {
431 
432             if (parse.last) {
433                 break;
434             }
435 
436             return NULL;
437         }
438 
439         switch (value->type) {
440 
441         case NXT_CONF_VALUE_OBJECT:
442             value = nxt_conf_get_object_member(value, &token, NULL);
443             break;
444 
445         case NXT_CONF_VALUE_ARRAY:
446             index = nxt_int_parse(token.start, token.length);
447 
448             if (index < 0 || index > NXT_INT32_T_MAX) {
449                 return NULL;
450             }
451 
452             value = nxt_conf_get_array_element(value, index);
453             break;
454 
455         default:
456             return NULL;
457         }
458 
459         if (value == NULL) {
460             return NULL;
461         }
462 
463     } while (parse.last == 0);
464 
465     return value;
466 }
467 
468 
469 static void
470 nxt_conf_path_next_token(nxt_conf_path_parse_t *parse, nxt_str_t *token)
471 {
472     u_char  *p, *end;
473 
474     end = parse->end;
475     p = parse->start + 1;
476 
477     token->start = p;
478 
479     while (p < end && *p != '/') {
480         p++;
481     }
482 
483     parse->start = p;
484     parse->last = (p >= end);
485 
486     token->length = p - token->start;
487 }
488 
489 
490 nxt_conf_value_t *
491 nxt_conf_get_object_member(nxt_conf_value_t *value, nxt_str_t *name,
492     uint32_t *index)
493 {
494     nxt_str_t                 str;
495     nxt_uint_t                n;
496     nxt_conf_object_t         *object;
497     nxt_conf_object_member_t  *member;
498 
499     if (value->type != NXT_CONF_VALUE_OBJECT) {
500         return NULL;
501     }
502 
503     object = value->u.object;
504 
505     for (n = 0; n < object->count; n++) {
506         member = &object->members[n];
507 
508         nxt_conf_get_string(&member->name, &str);
509 
510         if (nxt_strstr_eq(&str, name)) {
511 
512             if (index != NULL) {
513                 *index = n;
514             }
515 
516             return &member->value;
517         }
518     }
519 
520     return NULL;
521 }
522 
523 
524 nxt_int_t
525 nxt_conf_map_object(nxt_mp_t *mp, nxt_conf_value_t *value, nxt_conf_map_t *map,
526     nxt_uint_t n, void *data)
527 {
528     nxt_str_t         str, *s;
529     nxt_uint_t        i;
530     nxt_conf_value_t  *v;
531 
532     union {
533         uint8_t     ui8;
534         int32_t     i32;
535         int64_t     i64;
536         int         i;
537         ssize_t     size;
538         off_t       off;
539         nxt_msec_t  msec;
540         double      dbl;
541         nxt_str_t   str;
542         char        *cstrz;
543         void        *v;
544     } *ptr;
545 
546     for (i = 0; i < n; i++) {
547 
548         v = nxt_conf_get_object_member(value, &map[i].name, NULL);
549 
550         if (v == NULL || v->type == NXT_CONF_VALUE_NULL) {
551             continue;
552         }
553 
554         ptr = nxt_pointer_to(data, map[i].offset);
555 
556         switch (map[i].type) {
557 
558         case NXT_CONF_MAP_INT8:
559 
560             if (v->type == NXT_CONF_VALUE_BOOLEAN) {
561                 ptr->ui8 = v->u.boolean;
562             }
563 
564             break;
565 
566         case NXT_CONF_MAP_INT32:
567         case NXT_CONF_MAP_INT64:
568         case NXT_CONF_MAP_INT:
569         case NXT_CONF_MAP_SIZE:
570         case NXT_CONF_MAP_OFF:
571         case NXT_CONF_MAP_MSEC:
572 
573             if (v->type != NXT_CONF_VALUE_INTEGER) {
574                 break;
575             }
576 
577             switch (map[i].type) {
578 
579             case NXT_CONF_MAP_INT32:
580                 ptr->i32 = v->u.integer;
581                 break;
582 
583             case NXT_CONF_MAP_INT64:
584                 ptr->i64 = v->u.integer;
585                 break;
586 
587             case NXT_CONF_MAP_INT:
588                 ptr->i = v->u.integer;
589                 break;
590 
591             case NXT_CONF_MAP_SIZE:
592                 ptr->size = v->u.integer;
593                 break;
594 
595             case NXT_CONF_MAP_OFF:
596                 ptr->off = v->u.integer;
597                 break;
598 
599             case NXT_CONF_MAP_MSEC:
600                 ptr->msec = v->u.integer * 1000;
601                 break;
602 
603             default:
604                 nxt_unreachable();
605             }
606 
607             break;
608 
609         case NXT_CONF_MAP_DOUBLE:
610 
611             if (v->type == NXT_CONF_VALUE_NUMBER) {
612                 ptr->dbl = v->u.number;
613 
614             } else if (v->type == NXT_CONF_VALUE_INTEGER) {
615                 ptr->dbl = v->u.integer;
616 
617             }
618 
619             break;
620 
621         case NXT_CONF_MAP_STR:
622         case NXT_CONF_MAP_STR_COPY:
623         case NXT_CONF_MAP_CSTRZ:
624 
625             if (v->type != NXT_CONF_VALUE_SHORT_STRING
626                 && v->type != NXT_CONF_VALUE_STRING)
627             {
628                 break;
629             }
630 
631             nxt_conf_get_string(v, &str);
632 
633             switch (map[i].type) {
634 
635             case NXT_CONF_MAP_STR:
636                 ptr->str = str;
637                 break;
638 
639             case NXT_CONF_MAP_STR_COPY:
640 
641                 s = nxt_str_dup(mp, &ptr->str, &str);
642 
643                 if (nxt_slow_path(s == NULL)) {
644                     return NXT_ERROR;
645                 }
646 
647                 break;
648 
649             case NXT_CONF_MAP_CSTRZ:
650 
651                 ptr->cstrz = nxt_str_cstrz(mp, &str);
652 
653                 if (nxt_slow_path(ptr->cstrz == NULL)) {
654                     return NXT_ERROR;
655                 }
656 
657                 break;
658 
659             default:
660                 nxt_unreachable();
661             }
662 
663             break;
664 
665         case NXT_CONF_MAP_PTR:
666 
667             ptr->v = v;
668 
669             break;
670         }
671     }
672 
673     return NXT_OK;
674 }
675 
676 
677 nxt_conf_value_t *
678 nxt_conf_next_object_member(nxt_conf_value_t *value, nxt_str_t *name,
679     uint32_t *next)
680 {
681     uint32_t                  n;
682     nxt_conf_object_t         *object;
683     nxt_conf_object_member_t  *member;
684 
685     if (value->type != NXT_CONF_VALUE_OBJECT) {
686         return NULL;
687     }
688 
689     n = *next;
690     object = value->u.object;
691 
692     if (n >= object->count) {
693         return NULL;
694     }
695 
696     member = &object->members[n];
697     *next = n + 1;
698 
699     nxt_conf_get_string(&member->name, name);
700 
701     return &member->value;
702 }
703 
704 
705 nxt_conf_value_t *
706 nxt_conf_get_array_element(nxt_conf_value_t *value, uint32_t index)
707 {
708     nxt_conf_array_t  *array;
709 
710     if (value->type != NXT_CONF_VALUE_ARRAY) {
711         return NULL;
712     }
713 
714     array = value->u.array;
715 
716     if (index >= array->count) {
717         return NULL;
718     }
719 
720     return &array->elements[index];
721 }
722 
723 
724 void
725 nxt_conf_array_qsort(nxt_conf_value_t *value,
726     int (*compare)(const void *, const void *))
727 {
728     nxt_conf_array_t  *array;
729 
730     if (value->type != NXT_CONF_VALUE_ARRAY) {
731         return;
732     }
733 
734     array = value->u.array;
735 
736     nxt_qsort(array->elements, array->count, sizeof(nxt_conf_value_t), compare);
737 }
738 
739 
740 nxt_conf_op_ret_t
741 nxt_conf_op_compile(nxt_mp_t *mp, nxt_conf_op_t **ops, nxt_conf_value_t *root,
742     nxt_str_t *path, nxt_conf_value_t *value, nxt_bool_t add)
743 {
744     nxt_str_t                 token;
745     nxt_int_t                 index;
746     nxt_conf_op_t             *op, **parent;
747     nxt_conf_value_t          *node;
748     nxt_conf_path_parse_t     parse;
749     nxt_conf_object_member_t  *member;
750 
751     parse.start = path->start;
752     parse.end = path->start + path->length;
753     parse.last = 0;
754 
755     parent = ops;
756 
757     for ( ;; ) {
758         op = nxt_mp_zget(mp, sizeof(nxt_conf_op_t));
759         if (nxt_slow_path(op == NULL)) {
760             return NXT_CONF_OP_ERROR;
761         }
762 
763         *parent = op;
764         parent = (nxt_conf_op_t **) &op->ctx;
765 
766         nxt_conf_path_next_token(&parse, &token);
767 
768         switch (root->type) {
769 
770         case NXT_CONF_VALUE_OBJECT:
771             node = nxt_conf_get_object_member(root, &token, &op->index);
772             break;
773 
774         case NXT_CONF_VALUE_ARRAY:
775             index = nxt_int_parse(token.start, token.length);
776 
777             if (index < 0 || index > NXT_INT32_T_MAX) {
778                 return NXT_CONF_OP_NOT_FOUND;
779             }
780 
781             op->index = index;
782 
783             node = nxt_conf_get_array_element(root, index);
784             break;
785 
786         default:
787             node = NULL;
788         }
789 
790         if (parse.last) {
791             break;
792         }
793 
794         if (node == NULL) {
795             return NXT_CONF_OP_NOT_FOUND;
796         }
797 
798         op->action = NXT_CONF_OP_PASS;
799         root = node;
800     }
801 
802     if (value == NULL) {
803 
804         if (node == NULL) {
805             return NXT_CONF_OP_NOT_FOUND;
806         }
807 
808         op->action = NXT_CONF_OP_DELETE;
809 
810         return NXT_CONF_OP_OK;
811     }
812 
813     if (add) {
814         if (node == NULL) {
815             return NXT_CONF_OP_NOT_FOUND;
816         }
817 
818         if (node->type != NXT_CONF_VALUE_ARRAY) {
819             return NXT_CONF_OP_NOT_ALLOWED;
820         }
821 
822         op->action = NXT_CONF_OP_PASS;
823 
824         op = nxt_mp_zget(mp, sizeof(nxt_conf_op_t));
825         if (nxt_slow_path(op == NULL)) {
826             return NXT_CONF_OP_ERROR;
827         }
828 
829         *parent = op;
830 
831         op->index = node->u.array->count;
832         op->action = NXT_CONF_OP_CREATE;
833         op->ctx = value;
834 
835         return NXT_CONF_OP_OK;
836     }
837 
838     if (node != NULL) {
839         op->action = NXT_CONF_OP_REPLACE;
840         op->ctx = value;
841 
842         return NXT_CONF_OP_OK;
843     }
844 
845     op->action = NXT_CONF_OP_CREATE;
846 
847     if (root->type == NXT_CONF_VALUE_ARRAY) {
848         if (op->index > root->u.array->count) {
849             return NXT_CONF_OP_NOT_FOUND;
850         }
851 
852         op->ctx = value;
853 
854     } else {
855         member = nxt_mp_zget(mp, sizeof(nxt_conf_object_member_t));
856         if (nxt_slow_path(member == NULL)) {
857             return NXT_CONF_OP_ERROR;
858         }
859 
860         nxt_conf_set_string(&member->name, &token);
861 
862         member->value = *value;
863 
864         op->index = root->u.object->count;
865         op->ctx = member;
866     }
867 
868     return NXT_CONF_OP_OK;
869 }
870 
871 
872 nxt_conf_value_t *
873 nxt_conf_clone(nxt_mp_t *mp, nxt_conf_op_t *op, nxt_conf_value_t *value)
874 {
875     nxt_int_t         rc;
876     nxt_conf_value_t  *copy;
877 
878     copy = nxt_mp_get(mp, sizeof(nxt_conf_value_t));
879     if (nxt_slow_path(copy == NULL)) {
880         return NULL;
881     }
882 
883     rc = nxt_conf_copy_value(mp, op, copy, value);
884 
885     if (nxt_slow_path(rc != NXT_OK)) {
886         return NULL;
887     }
888 
889     return copy;
890 }
891 
892 
893 static nxt_int_t
894 nxt_conf_copy_value(nxt_mp_t *mp, nxt_conf_op_t *op, nxt_conf_value_t *dst,
895     nxt_conf_value_t *src)
896 {
897     if (op != NULL
898         && src->type != NXT_CONF_VALUE_ARRAY
899         && src->type != NXT_CONF_VALUE_OBJECT)
900     {
901         return NXT_ERROR;
902     }
903 
904     switch (src->type) {
905 
906     case NXT_CONF_VALUE_STRING:
907 
908         dst->u.string.start = nxt_mp_nget(mp, src->u.string.length);
909         if (nxt_slow_path(dst->u.string.start == NULL)) {
910             return NXT_ERROR;
911         }
912 
913         nxt_memcpy(dst->u.string.start, src->u.string.start,
914                    src->u.string.length);
915 
916         dst->u.string.length = src->u.string.length;
917 
918         break;
919 
920     case NXT_CONF_VALUE_ARRAY:
921         return nxt_conf_copy_array(mp, op, dst, src);
922 
923     case NXT_CONF_VALUE_OBJECT:
924         return nxt_conf_copy_object(mp, op, dst, src);
925 
926     default:
927         dst->u = src->u;
928     }
929 
930     dst->type = src->type;
931 
932     return NXT_OK;
933 }
934 
935 
936 static nxt_int_t
937 nxt_conf_copy_array(nxt_mp_t *mp, nxt_conf_op_t *op, nxt_conf_value_t *dst,
938     nxt_conf_value_t *src)
939 {
940     size_t            size;
941     nxt_int_t         rc;
942     nxt_uint_t        s, d, count, index;
943     nxt_conf_op_t     *pass_op;
944     nxt_conf_value_t  *value;
945 
946     count = src->u.array->count;
947 
948     if (op != NULL) {
949         if (op->action == NXT_CONF_OP_CREATE) {
950             count++;
951 
952         } else if (op->action == NXT_CONF_OP_DELETE) {
953             count--;
954         }
955     }
956 
957     size = sizeof(nxt_conf_array_t) + count * sizeof(nxt_conf_value_t);
958 
959     dst->u.array = nxt_mp_get(mp, size);
960     if (nxt_slow_path(dst->u.array == NULL)) {
961         return NXT_ERROR;
962     }
963 
964     dst->u.array->count = count;
965 
966     s = 0;
967     d = 0;
968 
969     pass_op = NULL;
970 
971     /*
972      * This initialization is needed only to
973      * suppress a warning on GCC 4.8 and older.
974      */
975     index = 0;
976 
977     do {
978         if (pass_op == NULL) {
979             index = (op == NULL) ? src->u.array->count : op->index;
980         }
981 
982         while (s != index) {
983             rc = nxt_conf_copy_value(mp, pass_op, &dst->u.array->elements[d],
984                                                   &src->u.array->elements[s]);
985             if (nxt_slow_path(rc != NXT_OK)) {
986                 return NXT_ERROR;
987             }
988 
989             s++;
990             d++;
991         }
992 
993         if (pass_op != NULL) {
994             pass_op = NULL;
995             continue;
996         }
997 
998         if (op != NULL) {
999             switch (op->action) {
1000             case NXT_CONF_OP_PASS:
1001                 pass_op = op->ctx;
1002                 index++;
1003                 break;
1004 
1005             case NXT_CONF_OP_CREATE:
1006                 value = op->ctx;
1007                 dst->u.array->elements[d] = *value;
1008 
1009                 d++;
1010                 break;
1011 
1012             case NXT_CONF_OP_REPLACE:
1013                 value = op->ctx;
1014                 dst->u.array->elements[d] = *value;
1015 
1016                 s++;
1017                 d++;
1018                 break;
1019 
1020             case NXT_CONF_OP_DELETE:
1021                 s++;
1022                 break;
1023             }
1024 
1025             op = NULL;
1026         }
1027 
1028     } while (d != count);
1029 
1030     dst->type = src->type;
1031 
1032     return NXT_OK;
1033 }
1034 
1035 
1036 static nxt_int_t
1037 nxt_conf_copy_object(nxt_mp_t *mp, nxt_conf_op_t *op, nxt_conf_value_t *dst,
1038     nxt_conf_value_t *src)
1039 {
1040     size_t                    size;
1041     nxt_int_t                 rc;
1042     nxt_uint_t                s, d, count, index;
1043     nxt_conf_op_t             *pass_op;
1044     nxt_conf_value_t          *value;
1045     nxt_conf_object_member_t  *member;
1046 
1047     count = src->u.object->count;
1048 
1049     if (op != NULL) {
1050         if (op->action == NXT_CONF_OP_CREATE) {
1051             count++;
1052 
1053         } else if (op->action == NXT_CONF_OP_DELETE) {
1054             count--;
1055         }
1056     }
1057 
1058     size = sizeof(nxt_conf_object_t)
1059            + count * sizeof(nxt_conf_object_member_t);
1060 
1061     dst->u.object = nxt_mp_get(mp, size);
1062     if (nxt_slow_path(dst->u.object == NULL)) {
1063         return NXT_ERROR;
1064     }
1065 
1066     dst->u.object->count = count;
1067 
1068     s = 0;
1069     d = 0;
1070 
1071     pass_op = NULL;
1072 
1073     /*
1074      * This initialization is needed only to
1075      * suppress a warning on GCC 4.8 and older.
1076      */
1077     index = 0;
1078 
1079     do {
1080         if (pass_op == NULL) {
1081             index = (op == NULL) ? src->u.object->count : op->index;
1082         }
1083 
1084         while (s != index) {
1085             rc = nxt_conf_copy_value(mp, NULL,
1086                                      &dst->u.object->members[d].name,
1087                                      &src->u.object->members[s].name);
1088 
1089             if (nxt_slow_path(rc != NXT_OK)) {
1090                 return NXT_ERROR;
1091             }
1092 
1093             rc = nxt_conf_copy_value(mp, pass_op,
1094                                      &dst->u.object->members[d].value,
1095                                      &src->u.object->members[s].value);
1096 
1097             if (nxt_slow_path(rc != NXT_OK)) {
1098                 return NXT_ERROR;
1099             }
1100 
1101             s++;
1102             d++;
1103         }
1104 
1105         if (pass_op != NULL) {
1106             pass_op = NULL;
1107             continue;
1108         }
1109 
1110         if (op != NULL) {
1111             switch (op->action) {
1112             case NXT_CONF_OP_PASS:
1113                 pass_op = op->ctx;
1114                 index++;
1115                 break;
1116 
1117             case NXT_CONF_OP_CREATE:
1118                 member = op->ctx;
1119 
1120                 rc = nxt_conf_copy_value(mp, NULL,
1121                                          &dst->u.object->members[d].name,
1122                                          &member->name);
1123 
1124                 if (nxt_slow_path(rc != NXT_OK)) {
1125                     return NXT_ERROR;
1126                 }
1127 
1128                 dst->u.object->members[d].value = member->value;
1129 
1130                 d++;
1131                 break;
1132 
1133             case NXT_CONF_OP_REPLACE:
1134                 rc = nxt_conf_copy_value(mp, NULL,
1135                                          &dst->u.object->members[d].name,
1136                                          &src->u.object->members[s].name);
1137 
1138                 if (nxt_slow_path(rc != NXT_OK)) {
1139                     return NXT_ERROR;
1140                 }
1141 
1142                 value = op->ctx;
1143 
1144                 dst->u.object->members[d].value = *value;
1145 
1146                 s++;
1147                 d++;
1148                 break;
1149 
1150             case NXT_CONF_OP_DELETE:
1151                 s++;
1152                 break;
1153             }
1154 
1155             op = NULL;
1156         }
1157 
1158     } while (d != count);
1159 
1160     dst->type = src->type;
1161 
1162     return NXT_OK;
1163 }
1164 
1165 
1166 nxt_conf_value_t *
1167 nxt_conf_json_parse(nxt_mp_t *mp, u_char *start, u_char *end,
1168     nxt_conf_json_error_t *error)
1169 {
1170     u_char            *p;
1171     nxt_conf_value_t  *value;
1172 
1173     value = nxt_mp_get(mp, sizeof(nxt_conf_value_t));
1174     if (nxt_slow_path(value == NULL)) {
1175         return NULL;
1176     }
1177 
1178     p = nxt_conf_json_skip_space(start, end);
1179 
1180     if (nxt_slow_path(p == end)) {
1181 
1182         nxt_conf_json_parse_error(error, start,
1183             "An empty JSON payload isn't allowed.  It must be either a literal "
1184             "(null, true, or false), a number, a string (in double quotes "
1185             "\"\"), an array (with brackets []), or an object (with braces {})."
1186         );
1187 
1188         return NULL;
1189     }
1190 
1191     p = nxt_conf_json_parse_value(mp, value, p, end, error);
1192 
1193     if (nxt_slow_path(p == NULL)) {
1194         return NULL;
1195     }
1196 
1197     p = nxt_conf_json_skip_space(p, end);
1198 
1199     if (nxt_slow_path(p != end)) {
1200 
1201         nxt_conf_json_parse_error(error, p,
1202             "Unexpected character after the end of a valid JSON value."
1203         );
1204 
1205         return NULL;
1206     }
1207 
1208     return value;
1209 }
1210 
1211 
1212 static u_char *
1213 nxt_conf_json_skip_space(u_char *start, u_char *end)
1214 {
1215     u_char  *p;
1216 
1217     for (p = start; nxt_fast_path(p != end); p++) {
1218 
1219         switch (*p) {
1220         case ' ':
1221         case '\t':
1222         case '\r':
1223         case '\n':
1224             continue;
1225         }
1226 
1227         break;
1228     }
1229 
1230     return p;
1231 }
1232 
1233 
1234 static u_char *
1235 nxt_conf_json_parse_value(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
1236     u_char *end, nxt_conf_json_error_t *error)
1237 {
1238     u_char  ch, *p;
1239 
1240     ch = *start;
1241 
1242     switch (ch) {
1243     case '{':
1244         return nxt_conf_json_parse_object(mp, value, start, end, error);
1245 
1246     case '[':
1247         return nxt_conf_json_parse_array(mp, value, start, end, error);
1248 
1249     case '"':
1250         return nxt_conf_json_parse_string(mp, value, start, end, error);
1251 
1252     case 't':
1253         if (nxt_fast_path(end - start >= 4
1254                           && nxt_memcmp(start, "true", 4) == 0))
1255         {
1256             value->u.boolean = 1;
1257             value->type = NXT_CONF_VALUE_BOOLEAN;
1258 
1259             return start + 4;
1260         }
1261 
1262         goto error;
1263 
1264     case 'f':
1265         if (nxt_fast_path(end - start >= 5
1266                           && nxt_memcmp(start, "false", 5) == 0))
1267         {
1268             value->u.boolean = 0;
1269             value->type = NXT_CONF_VALUE_BOOLEAN;
1270 
1271             return start + 5;
1272         }
1273 
1274         goto error;
1275 
1276     case 'n':
1277         if (nxt_fast_path(end - start >= 4
1278                           && nxt_memcmp(start, "null", 4) == 0))
1279         {
1280             value->type = NXT_CONF_VALUE_NULL;
1281             return start + 4;
1282         }
1283 
1284         goto error;
1285 
1286     case '-':
1287         if (nxt_fast_path(end - start > 1)) {
1288             ch = start[1];
1289             break;
1290         }
1291 
1292         goto error;
1293     }
1294 
1295     if (nxt_fast_path((ch - '0') <= 9)) {
1296         p = nxt_conf_json_parse_number(mp, value, start, end, error);
1297 
1298         if (nxt_slow_path(p == NULL)) {
1299             return NULL;
1300         }
1301 
1302         if (p == end) {
1303             return end;
1304         }
1305 
1306         switch (*p) {
1307         case ' ':
1308         case '\t':
1309         case '\r':
1310         case '\n':
1311         case ',':
1312         case '}':
1313         case ']':
1314         case '{':
1315         case '[':
1316         case '"':
1317             return p;
1318         }
1319     }
1320 
1321 error:
1322 
1323     nxt_conf_json_parse_error(error, start,
1324         "A valid JSON value is expected here.  It must be either a literal "
1325         "(null, true, or false), a number, a string (in double quotes \"\"), "
1326         "an array (with brackets []), or an object (with braces {})."
1327     );
1328 
1329     return NULL;
1330 }
1331 
1332 
1333 static const nxt_lvlhsh_proto_t  nxt_conf_object_hash_proto
1334     nxt_aligned(64) =
1335 {
1336     NXT_LVLHSH_DEFAULT,
1337     nxt_conf_object_hash_test,
1338     nxt_conf_object_hash_alloc,
1339     nxt_conf_object_hash_free,
1340 };
1341 
1342 
1343 static u_char *
1344 nxt_conf_json_parse_object(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
1345     u_char *end, nxt_conf_json_error_t *error)
1346 {
1347     u_char                    *p, *name;
1348     nxt_mp_t                  *mp_temp;
1349     nxt_int_t                 rc;
1350     nxt_uint_t                count;
1351     nxt_lvlhsh_t              hash;
1352     nxt_lvlhsh_each_t         lhe;
1353     nxt_conf_object_t         *object;
1354     nxt_conf_object_member_t  *member, *element;
1355 
1356     mp_temp = nxt_mp_create(1024, 128, 256, 32);
1357     if (nxt_slow_path(mp_temp == NULL)) {
1358         return NULL;
1359     }
1360 
1361     nxt_lvlhsh_init(&hash);
1362 
1363     count = 0;
1364     p = start;
1365 
1366     for ( ;; ) {
1367         p = nxt_conf_json_skip_space(p + 1, end);
1368 
1369         if (nxt_slow_path(p == end)) {
1370 
1371             nxt_conf_json_parse_error(error, p,
1372                 "Unexpected end of JSON payload.  There's an object without "
1373                 "a closing brace (})."
1374             );
1375 
1376             goto error;
1377         }
1378 
1379         if (*p != '"') {
1380             if (nxt_fast_path(*p == '}')) {
1381                 break;
1382             }
1383 
1384             nxt_conf_json_parse_error(error, p,
1385                 "A double quote (\") is expected here.  There must be a valid "
1386                 "JSON object member starts with a name, which is a string "
1387                 "enclosed in double quotes."
1388             );
1389 
1390             goto error;
1391         }
1392 
1393         name = p;
1394 
1395         count++;
1396 
1397         member = nxt_mp_get(mp_temp, sizeof(nxt_conf_object_member_t));
1398         if (nxt_slow_path(member == NULL)) {
1399             goto error;
1400         }
1401 
1402         p = nxt_conf_json_parse_string(mp, &member->name, p, end, error);
1403 
1404         if (nxt_slow_path(p == NULL)) {
1405             goto error;
1406         }
1407 
1408         rc = nxt_conf_object_hash_add(mp_temp, &hash, member);
1409 
1410         if (nxt_slow_path(rc != NXT_OK)) {
1411 
1412             if (rc == NXT_DECLINED) {
1413                 nxt_conf_json_parse_error(error, name,
1414                     "Duplicate object member.  All JSON object members must "
1415                     "have unique names."
1416                 );
1417             }
1418 
1419             goto error;
1420         }
1421 
1422         p = nxt_conf_json_skip_space(p, end);
1423 
1424         if (nxt_slow_path(p == end)) {
1425 
1426             nxt_conf_json_parse_error(error, p,
1427                 "Unexpected end of JSON payload.  There's an object member "
1428                 "without a value."
1429             );
1430 
1431             goto error;
1432         }
1433 
1434         if (nxt_slow_path(*p != ':')) {
1435 
1436             nxt_conf_json_parse_error(error, p,
1437                 "A colon (:) is expected here.  There must be a colon after "
1438                 "a JSON member name."
1439             );
1440 
1441             goto error;
1442         }
1443 
1444         p = nxt_conf_json_skip_space(p + 1, end);
1445 
1446         if (nxt_slow_path(p == end)) {
1447 
1448             nxt_conf_json_parse_error(error, p,
1449                 "Unexpected end of JSON payload.  There's an object member "
1450                 "without a value."
1451             );
1452 
1453             goto error;
1454         }
1455 
1456         p = nxt_conf_json_parse_value(mp, &member->value, p, end, error);
1457 
1458         if (nxt_slow_path(p == NULL)) {
1459             goto error;
1460         }
1461 
1462         p = nxt_conf_json_skip_space(p, end);
1463 
1464         if (nxt_slow_path(p == end)) {
1465 
1466             nxt_conf_json_parse_error(error, p,
1467                 "Unexpected end of JSON payload.  There's an object without "
1468                 "a closing brace (})."
1469             );
1470 
1471             goto error;
1472         }
1473 
1474         if (*p != ',') {
1475             if (nxt_fast_path(*p == '}')) {
1476                 break;
1477             }
1478 
1479             nxt_conf_json_parse_error(error, p,
1480                 "Either a closing brace (}) or a comma (,) is expected here.  "
1481                 "Each JSON object must be enclosed in braces and its members "
1482                 "must be separated by commas."
1483             );
1484 
1485             goto error;
1486         }
1487     }
1488 
1489     object = nxt_mp_get(mp, sizeof(nxt_conf_object_t)
1490                             + count * sizeof(nxt_conf_object_member_t));
1491     if (nxt_slow_path(object == NULL)) {
1492         goto error;
1493     }
1494 
1495     value->u.object = object;
1496     value->type = NXT_CONF_VALUE_OBJECT;
1497 
1498     object->count = count;
1499     member = object->members;
1500 
1501     nxt_lvlhsh_each_init(&lhe, &nxt_conf_object_hash_proto);
1502 
1503     for ( ;; ) {
1504         element = nxt_lvlhsh_each(&hash, &lhe);
1505 
1506         if (element == NULL) {
1507             break;
1508         }
1509 
1510         *member++ = *element;
1511     }
1512 
1513     nxt_mp_destroy(mp_temp);
1514 
1515     return p + 1;
1516 
1517 error:
1518 
1519     nxt_mp_destroy(mp_temp);
1520     return NULL;
1521 }
1522 
1523 
1524 static nxt_int_t
1525 nxt_conf_object_hash_add(nxt_mp_t *mp, nxt_lvlhsh_t *lvlhsh,
1526     nxt_conf_object_member_t *member)
1527 {
1528     nxt_lvlhsh_query_t  lhq;
1529 
1530     nxt_conf_get_string(&member->name, &lhq.key);
1531 
1532     lhq.key_hash = nxt_djb_hash(lhq.key.start, lhq.key.length);
1533     lhq.replace = 0;
1534     lhq.value = member;
1535     lhq.proto = &nxt_conf_object_hash_proto;
1536     lhq.pool = mp;
1537 
1538     return nxt_lvlhsh_insert(lvlhsh, &lhq);
1539 }
1540 
1541 
1542 static nxt_int_t
1543 nxt_conf_object_hash_test(nxt_lvlhsh_query_t *lhq, void *data)
1544 {
1545     nxt_str_t                 str;
1546     nxt_conf_object_member_t  *member;
1547 
1548     member = data;
1549 
1550     nxt_conf_get_string(&member->name, &str);
1551 
1552     return nxt_strstr_eq(&lhq->key, &str) ? NXT_OK : NXT_DECLINED;
1553 }
1554 
1555 
1556 static void *
1557 nxt_conf_object_hash_alloc(void *data, size_t size)
1558 {
1559     return nxt_mp_align(data, size, size);
1560 }
1561 
1562 
1563 static void
1564 nxt_conf_object_hash_free(void *data, void *p)
1565 {
1566     nxt_mp_free(data, p);
1567 }
1568 
1569 
1570 static u_char *
1571 nxt_conf_json_parse_array(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
1572     u_char *end, nxt_conf_json_error_t *error)
1573 {
1574     u_char            *p;
1575     nxt_mp_t          *mp_temp;
1576     nxt_uint_t        count;
1577     nxt_list_t        *list;
1578     nxt_conf_array_t  *array;
1579     nxt_conf_value_t  *element;
1580 
1581     mp_temp = nxt_mp_create(1024, 128, 256, 32);
1582     if (nxt_slow_path(mp_temp == NULL)) {
1583         return NULL;
1584     }
1585 
1586     list = nxt_list_create(mp_temp, 8, sizeof(nxt_conf_value_t));
1587     if (nxt_slow_path(list == NULL)) {
1588         goto error;
1589     }
1590 
1591     count = 0;
1592     p = start;
1593 
1594     for ( ;; ) {
1595         p = nxt_conf_json_skip_space(p + 1, end);
1596 
1597         if (nxt_slow_path(p == end)) {
1598 
1599             nxt_conf_json_parse_error(error, p,
1600                 "Unexpected end of JSON payload.  There's an array without "
1601                 "a closing bracket (])."
1602             );
1603 
1604             goto error;
1605         }
1606 
1607         if (*p == ']') {
1608             break;
1609         }
1610 
1611         count++;
1612 
1613         element = nxt_list_add(list);
1614         if (nxt_slow_path(element == NULL)) {
1615             goto error;
1616         }
1617 
1618         p = nxt_conf_json_parse_value(mp, element, p, end, error);
1619 
1620         if (nxt_slow_path(p == NULL)) {
1621             goto error;
1622         }
1623 
1624         p = nxt_conf_json_skip_space(p, end);
1625 
1626         if (nxt_slow_path(p == end)) {
1627 
1628             nxt_conf_json_parse_error(error, p,
1629                 "Unexpected end of JSON payload.  There's an array without "
1630                 "a closing bracket (])."
1631             );
1632 
1633             goto error;
1634         }
1635 
1636         if (*p != ',') {
1637             if (nxt_fast_path(*p == ']')) {
1638                 break;
1639             }
1640 
1641             nxt_conf_json_parse_error(error, p,
1642                 "Either a closing bracket (]) or a comma (,) is expected "
1643                 "here.  Each array must be enclosed in brackets and its "
1644                 "members must be separated by commas."
1645             );
1646 
1647             goto error;
1648         }
1649     }
1650 
1651     array = nxt_mp_get(mp, sizeof(nxt_conf_array_t)
1652                            + count * sizeof(nxt_conf_value_t));
1653     if (nxt_slow_path(array == NULL)) {
1654         goto error;
1655     }
1656 
1657     value->u.array = array;
1658     value->type = NXT_CONF_VALUE_ARRAY;
1659 
1660     array->count = count;
1661     element = array->elements;
1662 
1663     nxt_list_each(value, list) {
1664         *element++ = *value;
1665     } nxt_list_loop;
1666 
1667     nxt_mp_destroy(mp_temp);
1668 
1669     return p + 1;
1670 
1671 error:
1672 
1673     nxt_mp_destroy(mp_temp);
1674     return NULL;
1675 }
1676 
1677 
1678 static u_char *
1679 nxt_conf_json_parse_string(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
1680     u_char *end, nxt_conf_json_error_t *error)
1681 {
1682     u_char      *p, ch, *last, *s;
1683     size_t      size, surplus;
1684     uint32_t    utf, utf_high;
1685     nxt_uint_t  i;
1686     enum {
1687         sw_usual = 0,
1688         sw_escape,
1689         sw_encoded1,
1690         sw_encoded2,
1691         sw_encoded3,
1692         sw_encoded4,
1693     } state;
1694 
1695     start++;
1696 
1697     state = 0;
1698     surplus = 0;
1699 
1700     for (p = start; nxt_fast_path(p != end); p++) {
1701         ch = *p;
1702 
1703         switch (state) {
1704 
1705         case sw_usual:
1706 
1707             if (ch == '"') {
1708                 break;
1709             }
1710 
1711             if (ch == '\\') {
1712                 state = sw_escape;
1713                 continue;
1714             }
1715 
1716             if (nxt_fast_path(ch >= ' ')) {
1717                 continue;
1718             }
1719 
1720             nxt_conf_json_parse_error(error, p,
1721                 "Unexpected character.  All control characters in a JSON "
1722                 "string must be escaped."
1723             );
1724 
1725             return NULL;
1726 
1727         case sw_escape:
1728 
1729             switch (ch) {
1730             case '"':
1731             case '\\':
1732             case '/':
1733             case 'n':
1734             case 'r':
1735             case 't':
1736             case 'b':
1737             case 'f':
1738                 surplus++;
1739                 state = sw_usual;
1740                 continue;
1741 
1742             case 'u':
1743                 /*
1744                  * Basic unicode 6 bytes "\uXXXX" in JSON
1745                  * and up to 3 bytes in UTF-8.
1746                  *
1747                  * Surrogate pair: 12 bytes "\uXXXX\uXXXX" in JSON
1748                  * and 3 or 4 bytes in UTF-8.
1749                  */
1750                 surplus += 3;
1751                 state = sw_encoded1;
1752                 continue;
1753             }
1754 
1755             nxt_conf_json_parse_error(error, p - 1,
1756                 "Unexpected backslash.  A literal backslash in a JSON string "
1757                 "must be escaped with a second backslash (\\\\)."
1758             );
1759 
1760             return NULL;
1761 
1762         case sw_encoded1:
1763         case sw_encoded2:
1764         case sw_encoded3:
1765         case sw_encoded4:
1766 
1767             if (nxt_fast_path((ch >= '0' && ch <= '9')
1768                               || (ch >= 'A' && ch <= 'F')
1769                               || (ch >= 'a' && ch <= 'f')))
1770             {
1771                 state = (state == sw_encoded4) ? sw_usual : state + 1;
1772                 continue;
1773             }
1774 
1775             nxt_conf_json_parse_error(error, p,
1776                 "Invalid escape sequence.  An escape sequence in a JSON "
1777                 "string must start with a backslash, followed by the lowercase "
1778                 "letter u, followed by four hexadecimal digits (\\uXXXX)."
1779             );
1780 
1781             return NULL;
1782         }
1783 
1784         break;
1785     }
1786 
1787     if (nxt_slow_path(p == end)) {
1788 
1789         nxt_conf_json_parse_error(error, p,
1790             "Unexpected end of JSON payload.  There's a string without "
1791             "a final double quote (\")."
1792         );
1793 
1794         return NULL;
1795     }
1796 
1797     /* Points to the ending quote mark. */
1798     last = p;
1799 
1800     size = last - start - surplus;
1801 
1802     if (size > NXT_CONF_MAX_SHORT_STRING) {
1803 
1804         if (nxt_slow_path(size > NXT_CONF_MAX_STRING)) {
1805 
1806             nxt_conf_json_parse_error(error, start,
1807                 "The string is too long.  Such a long JSON string value "
1808                 "is not supported."
1809             );
1810 
1811             return NULL;
1812         }
1813 
1814         value->type = NXT_CONF_VALUE_STRING;
1815 
1816         value->u.string.start = nxt_mp_nget(mp, size);
1817         if (nxt_slow_path(value->u.string.start == NULL)) {
1818             return NULL;
1819         }
1820 
1821         value->u.string.length = size;
1822 
1823         s = value->u.string.start;
1824 
1825     } else {
1826         value->type = NXT_CONF_VALUE_SHORT_STRING;
1827         value->u.str.length = size;
1828 
1829         s = value->u.str.start;
1830     }
1831 
1832     if (surplus == 0) {
1833         nxt_memcpy(s, start, size);
1834         return last + 1;
1835     }
1836 
1837     p = start;
1838 
1839     do {
1840         ch = *p++;
1841 
1842         if (ch != '\\') {
1843             *s++ = ch;
1844             continue;
1845         }
1846 
1847         ch = *p++;
1848 
1849         switch (ch) {
1850         case '"':
1851         case '\\':
1852         case '/':
1853             *s++ = ch;
1854             continue;
1855 
1856         case 'n':
1857             *s++ = '\n';
1858             continue;
1859 
1860         case 'r':
1861             *s++ = '\r';
1862             continue;
1863 
1864         case 't':
1865             *s++ = '\t';
1866             continue;
1867 
1868         case 'b':
1869             *s++ = '\b';
1870             continue;
1871 
1872         case 'f':
1873             *s++ = '\f';
1874             continue;
1875         }
1876 
1877         utf = 0;
1878         utf_high = 0;
1879 
1880         for ( ;; ) {
1881             for (i = 0; i < 4; i++) {
1882                 utf = (utf << 4) | (p[i] >= 'A' ? 10 + ((p[i] & ~0x20) - 'A')
1883                                                 : p[i] - '0');
1884             }
1885 
1886             p += 4;
1887 
1888             if (utf_high != 0) {
1889                 if (nxt_slow_path(utf < 0xDC00 || utf > 0xDFFF)) {
1890 
1891                     nxt_conf_json_parse_error(error, p - 12,
1892                         "Invalid JSON encoding sequence.  This 12-byte "
1893                         "sequence composes an illegal UTF-16 surrogate pair."
1894                     );
1895 
1896                     return NULL;
1897                 }
1898 
1899                 utf = ((utf_high - 0xD800) << 10) + (utf - 0xDC00) + 0x10000;
1900 
1901                 break;
1902             }
1903 
1904             if (utf < 0xD800 || utf > 0xDFFF) {
1905                 break;
1906             }
1907 
1908             if (utf > 0xDBFF || p[0] != '\\' || p[1] != 'u') {
1909 
1910                 nxt_conf_json_parse_error(error, p - 6,
1911                     "Invalid JSON encoding sequence.  This 6-byte sequence "
1912                     "does not represent a valid UTF character."
1913                 );
1914 
1915                 return NULL;
1916             }
1917 
1918             p += 2;
1919 
1920             utf_high = utf;
1921             utf = 0;
1922         }
1923 
1924         s = nxt_utf8_encode(s, utf);
1925 
1926     } while (p != last);
1927 
1928     if (size > NXT_CONF_MAX_SHORT_STRING) {
1929         value->u.string.length = s - value->u.string.start;
1930 
1931     } else {
1932         value->u.str.length = s - value->u.str.start;
1933     }
1934 
1935     return last + 1;
1936 }
1937 
1938 
1939 static u_char *
1940 nxt_conf_json_parse_number(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
1941     u_char *end, nxt_conf_json_error_t *error)
1942 {
1943     u_char     *p, ch;
1944     uint64_t   integer;
1945     nxt_int_t  sign;
1946 #if 0
1947     uint64_t   frac, power
1948     nxt_int_t  e, negative;
1949 #endif
1950 
1951     static const uint64_t cutoff = NXT_INT64_T_MAX / 10;
1952     static const uint64_t cutlim = NXT_INT64_T_MAX % 10;
1953 
1954     ch = *start;
1955 
1956     if (ch == '-') {
1957         sign = -1;
1958         start++;
1959 
1960     } else {
1961         sign = 1;
1962     }
1963 
1964     integer = 0;
1965 
1966     for (p = start; nxt_fast_path(p != end); p++) {
1967         ch = *p;
1968 
1969         /* Values below '0' become >= 208. */
1970         ch = ch - '0';
1971 
1972         if (ch > 9) {
1973             break;
1974         }
1975 
1976         if (nxt_slow_path(integer >= cutoff
1977                           && (integer > cutoff || ch > cutlim)))
1978         {
1979             nxt_conf_json_parse_error(error, start,
1980                 "The integer is too large.  Such a large JSON integer value "
1981                 "is not supported."
1982             );
1983 
1984             return NULL;
1985         }
1986 
1987         integer = integer * 10 + ch;
1988     }
1989 
1990     if (nxt_slow_path(p - start > 1 && *start == '0')) {
1991 
1992         nxt_conf_json_parse_error(error, start,
1993             "The number is invalid.  Leading zeros are not allowed in JSON "
1994             "numbers."
1995         );
1996 
1997         return NULL;
1998     }
1999 
2000     if (ch != '.') {
2001         value->type = NXT_CONF_VALUE_INTEGER;
2002         value->u.integer = sign * integer;
2003         return p;
2004     }
2005 
2006 #if 0
2007     start = p + 1;
2008 
2009     frac = 0;
2010     power = 1;
2011 
2012     for (p = start; nxt_fast_path(p != end); p++) {
2013         ch = *p;
2014 
2015         /* Values below '0' become >= 208. */
2016         ch = ch - '0';
2017 
2018         if (ch > 9) {
2019             break;
2020         }
2021 
2022         if (nxt_slow_path((frac >= cutoff && (frac > cutoff || ch > cutlim))
2023                           || power > cutoff))
2024         {
2025             return NULL;
2026         }
2027 
2028         frac = frac * 10 + ch;
2029         power *= 10;
2030     }
2031 
2032     if (nxt_slow_path(p == start)) {
2033         return NULL;
2034     }
2035 
2036     value->type = NXT_CONF_VALUE_NUMBER;
2037     value->u.number = integer + (double) frac / power;
2038 
2039     value->u.number = copysign(value->u.number, sign);
2040 
2041     if (ch == 'e' || ch == 'E') {
2042         start = p + 1;
2043 
2044         ch = *start;
2045 
2046         if (ch == '-' || ch == '+') {
2047             start++;
2048         }
2049 
2050         negative = (ch == '-') ? 1 : 0;
2051         e = 0;
2052 
2053         for (p = start; nxt_fast_path(p != end); p++) {
2054             ch = *p;
2055 
2056             /* Values below '0' become >= 208. */
2057             ch = ch - '0';
2058 
2059             if (ch > 9) {
2060                 break;
2061             }
2062 
2063             e = e * 10 + ch;
2064 
2065             if (nxt_slow_path(e > DBL_MAX_10_EXP)) {
2066                 return NULL;
2067             }
2068         }
2069 
2070         if (nxt_slow_path(p == start)) {
2071             return NULL;
2072         }
2073 
2074         if (negative) {
2075             value->u.number /= exp10(e);
2076 
2077         } else {
2078             value->u.number *= exp10(e);
2079         }
2080     }
2081 
2082     if (nxt_fast_path(isfinite(value->u.number))) {
2083         return p;
2084     }
2085 #else
2086 
2087     nxt_conf_json_parse_error(error, start,
2088         "The number is not an integer.  JSON numbers with decimals and "
2089         "exponents are not supported."
2090     );
2091 
2092 #endif
2093 
2094     return NULL;
2095 }
2096 
2097 
2098 static void
2099 nxt_conf_json_parse_error(nxt_conf_json_error_t *error, u_char *pos,
2100     const char *detail)
2101 {
2102     if (error == NULL) {
2103         return;
2104     }
2105 
2106     error->pos = pos;
2107     error->detail = (u_char *) detail;
2108 }
2109 
2110 
2111 size_t
2112 nxt_conf_json_length(nxt_conf_value_t *value, nxt_conf_json_pretty_t *pretty)
2113 {
2114     switch (value->type) {
2115 
2116     case NXT_CONF_VALUE_NULL:
2117         return nxt_length("null");
2118 
2119     case NXT_CONF_VALUE_BOOLEAN:
2120         return value->u.boolean ? nxt_length("true") : nxt_length("false");
2121 
2122     case NXT_CONF_VALUE_INTEGER:
2123         return nxt_conf_json_integer_length(value);
2124 
2125     case NXT_CONF_VALUE_NUMBER:
2126         /* TODO */
2127         return 0;
2128 
2129     case NXT_CONF_VALUE_SHORT_STRING:
2130     case NXT_CONF_VALUE_STRING:
2131         return nxt_conf_json_string_length(value);
2132 
2133     case NXT_CONF_VALUE_ARRAY:
2134         return nxt_conf_json_array_length(value, pretty);
2135 
2136     case NXT_CONF_VALUE_OBJECT:
2137         return nxt_conf_json_object_length(value, pretty);
2138     }
2139 
2140     nxt_unreachable();
2141 
2142     return 0;
2143 }
2144 
2145 
2146 u_char *
2147 nxt_conf_json_print(u_char *p, nxt_conf_value_t *value,
2148     nxt_conf_json_pretty_t *pretty)
2149 {
2150     switch (value->type) {
2151 
2152     case NXT_CONF_VALUE_NULL:
2153         return nxt_cpymem(p, "null", 4);
2154 
2155     case NXT_CONF_VALUE_BOOLEAN:
2156         return value->u.boolean ? nxt_cpymem(p, "true", 4)
2157                                 : nxt_cpymem(p, "false", 5);
2158 
2159     case NXT_CONF_VALUE_INTEGER:
2160         return nxt_conf_json_print_integer(p, value);
2161 
2162     case NXT_CONF_VALUE_NUMBER:
2163         /* TODO */
2164         return p;
2165 
2166     case NXT_CONF_VALUE_SHORT_STRING:
2167     case NXT_CONF_VALUE_STRING:
2168         return nxt_conf_json_print_string(p, value);
2169 
2170     case NXT_CONF_VALUE_ARRAY:
2171         return nxt_conf_json_print_array(p, value, pretty);
2172 
2173     case NXT_CONF_VALUE_OBJECT:
2174         return nxt_conf_json_print_object(p, value, pretty);
2175     }
2176 
2177     nxt_unreachable();
2178 
2179     return p;
2180 }
2181 
2182 
2183 static size_t
2184 nxt_conf_json_integer_length(nxt_conf_value_t *value)
2185 {
2186     int64_t  num;
2187 
2188     num = llabs(value->u.integer);
2189 
2190     if (num <= 9999) {
2191         return nxt_length("-9999");
2192     }
2193 
2194     if (num <= 99999999999LL) {
2195         return nxt_length("-99999999999");
2196     }
2197 
2198     return NXT_INT64_T_LEN;
2199 }
2200 
2201 
2202 static u_char *
2203 nxt_conf_json_print_integer(u_char *p, nxt_conf_value_t *value)
2204 {
2205     return nxt_sprintf(p, p + NXT_INT64_T_LEN, "%L", value->u.integer);
2206 }
2207 
2208 
2209 static size_t
2210 nxt_conf_json_string_length(nxt_conf_value_t *value)
2211 {
2212     nxt_str_t  str;
2213 
2214     nxt_conf_get_string(value, &str);
2215 
2216     return 2 + nxt_conf_json_escape_length(str.start, str.length);
2217 }
2218 
2219 
2220 static u_char *
2221 nxt_conf_json_print_string(u_char *p, nxt_conf_value_t *value)
2222 {
2223     nxt_str_t  str;
2224 
2225     nxt_conf_get_string(value, &str);
2226 
2227     *p++ = '"';
2228 
2229     p = nxt_conf_json_escape(p, str.start, str.length);
2230 
2231     *p++ = '"';
2232 
2233     return p;
2234 }
2235 
2236 
2237 static size_t
2238 nxt_conf_json_array_length(nxt_conf_value_t *value,
2239     nxt_conf_json_pretty_t *pretty)
2240 {
2241     size_t            len;
2242     nxt_uint_t        n;
2243     nxt_conf_array_t  *array;
2244 
2245     array = value->u.array;
2246 
2247     /* [] */
2248     len = 2;
2249 
2250     if (pretty != NULL) {
2251         pretty->level++;
2252     }
2253 
2254     value = array->elements;
2255 
2256     for (n = 0; n < array->count; n++) {
2257         len += nxt_conf_json_length(&value[n], pretty);
2258 
2259         if (pretty != NULL) {
2260             /* Indentation and new line. */
2261             len += pretty->level + 2;
2262         }
2263     }
2264 
2265     if (pretty != NULL) {
2266         pretty->level--;
2267 
2268         if (n != 0) {
2269             /* Indentation and new line. */
2270             len += pretty->level + 2;
2271         }
2272     }
2273 
2274     /* Reserve space for "n" commas. */
2275     return len + n;
2276 }
2277 
2278 
2279 static u_char *
2280 nxt_conf_json_print_array(u_char *p, nxt_conf_value_t *value,
2281     nxt_conf_json_pretty_t *pretty)
2282 {
2283     nxt_uint_t        n;
2284     nxt_conf_array_t  *array;
2285 
2286     array = value->u.array;
2287 
2288     *p++ = '[';
2289 
2290     if (array->count != 0) {
2291         value = array->elements;
2292 
2293         if (pretty != NULL) {
2294             p = nxt_conf_json_newline(p);
2295 
2296             pretty->level++;
2297             p = nxt_conf_json_indentation(p, pretty->level);
2298         }
2299 
2300         p = nxt_conf_json_print(p, &value[0], pretty);
2301 
2302         for (n = 1; n < array->count; n++) {
2303             *p++ = ',';
2304 
2305             if (pretty != NULL) {
2306                 p = nxt_conf_json_newline(p);
2307                 p = nxt_conf_json_indentation(p, pretty->level);
2308 
2309                 pretty->more_space = 0;
2310             }
2311 
2312             p = nxt_conf_json_print(p, &value[n], pretty);
2313         }
2314 
2315         if (pretty != NULL) {
2316             p = nxt_conf_json_newline(p);
2317 
2318             pretty->level--;
2319             p = nxt_conf_json_indentation(p, pretty->level);
2320 
2321             pretty->more_space = 1;
2322         }
2323     }
2324 
2325     *p++ = ']';
2326 
2327     return p;
2328 }
2329 
2330 
2331 static size_t
2332 nxt_conf_json_object_length(nxt_conf_value_t *value,
2333     nxt_conf_json_pretty_t *pretty)
2334 {
2335     size_t                    len;
2336     nxt_uint_t                n;
2337     nxt_conf_object_t         *object;
2338     nxt_conf_object_member_t  *member;
2339 
2340     object = value->u.object;
2341 
2342     /* {} */
2343     len = 2;
2344 
2345     if (pretty != NULL) {
2346         pretty->level++;
2347     }
2348 
2349     member = object->members;
2350 
2351     for (n = 0; n < object->count; n++) {
2352         len += nxt_conf_json_string_length(&member[n].name) + 1
2353                + nxt_conf_json_length(&member[n].value, pretty) + 1;
2354 
2355         if (pretty != NULL) {
2356             /*
2357              * Indentation, space after ":", new line, and possible
2358              * additional empty line between non-empty objects.
2359              */
2360             len += pretty->level + 1 + 2 + 2;
2361         }
2362     }
2363 
2364     if (pretty != NULL) {
2365         pretty->level--;
2366 
2367         /* Indentation and new line. */
2368         len += pretty->level + 2;
2369     }
2370 
2371     return len;
2372 }
2373 
2374 
2375 static u_char *
2376 nxt_conf_json_print_object(u_char *p, nxt_conf_value_t *value,
2377     nxt_conf_json_pretty_t *pretty)
2378 {
2379     nxt_uint_t                n;
2380     nxt_conf_object_t         *object;
2381     nxt_conf_object_member_t  *member;
2382 
2383     object = value->u.object;
2384 
2385     *p++ = '{';
2386 
2387     if (object->count != 0) {
2388 
2389         if (pretty != NULL) {
2390             p = nxt_conf_json_newline(p);
2391             pretty->level++;
2392         }
2393 
2394         member = object->members;
2395 
2396         n = 0;
2397 
2398         for ( ;; ) {
2399             if (pretty != NULL) {
2400                 p = nxt_conf_json_indentation(p, pretty->level);
2401             }
2402 
2403             p = nxt_conf_json_print_string(p, &member[n].name);
2404 
2405             *p++ = ':';
2406 
2407             if (pretty != NULL) {
2408                 *p++ = ' ';
2409             }
2410 
2411             p = nxt_conf_json_print(p, &member[n].value, pretty);
2412 
2413             n++;
2414 
2415             if (n == object->count) {
2416                 break;
2417             }
2418 
2419             *p++ = ',';
2420 
2421             if (pretty != NULL) {
2422                 p = nxt_conf_json_newline(p);
2423 
2424                 if (pretty->more_space) {
2425                     pretty->more_space = 0;
2426                     p = nxt_conf_json_newline(p);
2427                 }
2428             }
2429         }
2430 
2431         if (pretty != NULL) {
2432             p = nxt_conf_json_newline(p);
2433 
2434             pretty->level--;
2435             p = nxt_conf_json_indentation(p, pretty->level);
2436 
2437             pretty->more_space = 1;
2438         }
2439     }
2440 
2441     *p++ = '}';
2442 
2443     return p;
2444 }
2445 
2446 
2447 static size_t
2448 nxt_conf_json_escape_length(u_char *p, size_t size)
2449 {
2450     u_char  ch;
2451     size_t  len;
2452 
2453     len = size;
2454 
2455     while (size) {
2456         ch = *p++;
2457 
2458         if (ch == '\\' || ch == '"') {
2459             len++;
2460 
2461         } else if (ch <= 0x1F) {
2462 
2463             switch (ch) {
2464             case '\n':
2465             case '\r':
2466             case '\t':
2467             case '\b':
2468             case '\f':
2469                 len++;
2470                 break;
2471 
2472             default:
2473                 len += sizeof("\\u001F") - 2;
2474             }
2475         }
2476 
2477         size--;
2478     }
2479 
2480     return len;
2481 }
2482 
2483 
2484 static u_char *
2485 nxt_conf_json_escape(u_char *dst, u_char *src, size_t size)
2486 {
2487     u_char  ch;
2488 
2489     while (size) {
2490         ch = *src++;
2491 
2492         if (ch > 0x1F) {
2493 
2494             if (ch == '\\' || ch == '"') {
2495                 *dst++ = '\\';
2496             }
2497 
2498             *dst++ = ch;
2499 
2500         } else {
2501             *dst++ = '\\';
2502 
2503             switch (ch) {
2504             case '\n':
2505                 *dst++ = 'n';
2506                 break;
2507 
2508             case '\r':
2509                 *dst++ = 'r';
2510                 break;
2511 
2512             case '\t':
2513                 *dst++ = 't';
2514                 break;
2515 
2516             case '\b':
2517                 *dst++ = 'b';
2518                 break;
2519 
2520             case '\f':
2521                 *dst++ = 'f';
2522                 break;
2523 
2524             default:
2525                 *dst++ = 'u'; *dst++ = '0'; *dst++ = '0';
2526                 *dst++ = '0' + (ch >> 4);
2527 
2528                 ch &= 0xF;
2529 
2530                 *dst++ = (ch < 10) ? ('0' + ch) : ('A' + ch - 10);
2531             }
2532         }
2533 
2534         size--;
2535     }
2536 
2537     return dst;
2538 }
2539 
2540 
2541 void
2542 nxt_conf_json_position(u_char *start, u_char *pos, nxt_uint_t *line,
2543     nxt_uint_t *column)
2544 {
2545     u_char      *p;
2546     ssize_t     symbols;
2547     nxt_uint_t  lines;
2548 
2549     lines = 1;
2550 
2551     for (p = start; p != pos; p++) {
2552 
2553         if (*p != '\n') {
2554             continue;
2555         }
2556 
2557         lines++;
2558         start = p + 1;
2559     }
2560 
2561     symbols = nxt_utf8_length(start, p - start);
2562 
2563     if (symbols != -1) {
2564         *line = lines;
2565         *column = 1 + symbols;
2566     }
2567 }
2568