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