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