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