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