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