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