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