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