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