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