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