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