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