190 { nxt_string("websocket"), 191 NXT_CONF_VLDT_OBJECT, 192 &nxt_conf_vldt_object, 193 (void *) &nxt_conf_vldt_websocket_members }, 194 195 { nxt_string("static"), 196 NXT_CONF_VLDT_OBJECT, 197 &nxt_conf_vldt_object, 198 (void *) &nxt_conf_vldt_static_members }, 199 200 NXT_CONF_VLDT_END 201}; 202 203 204static nxt_conf_vldt_object_t nxt_conf_vldt_setting_members[] = { 205 { nxt_string("http"), 206 NXT_CONF_VLDT_OBJECT, 207 &nxt_conf_vldt_object, 208 (void *) &nxt_conf_vldt_http_members }, 209 210 NXT_CONF_VLDT_END 211}; 212 213 214static nxt_conf_vldt_object_t nxt_conf_vldt_root_members[] = { 215 { nxt_string("settings"), 216 NXT_CONF_VLDT_OBJECT, 217 &nxt_conf_vldt_object, 218 (void *) &nxt_conf_vldt_setting_members }, 219 220 { nxt_string("listeners"), 221 NXT_CONF_VLDT_OBJECT, 222 &nxt_conf_vldt_object_iterator, 223 (void *) &nxt_conf_vldt_listener }, 224 225 { nxt_string("routes"), 226 NXT_CONF_VLDT_ARRAY | NXT_CONF_VLDT_OBJECT, 227 &nxt_conf_vldt_routes, 228 NULL }, 229 230 { nxt_string("applications"), 231 NXT_CONF_VLDT_OBJECT, 232 &nxt_conf_vldt_object_iterator, 233 (void *) &nxt_conf_vldt_app }, 234 235 { nxt_string("upstreams"), 236 NXT_CONF_VLDT_OBJECT, 237 &nxt_conf_vldt_object_iterator, 238 (void *) &nxt_conf_vldt_upstream }, 239 240 { nxt_string("access_log"), 241 NXT_CONF_VLDT_STRING, 242 NULL, 243 NULL }, 244 245 NXT_CONF_VLDT_END 246}; 247 248 249#if (NXT_TLS) 250 251static nxt_conf_vldt_object_t nxt_conf_vldt_tls_members[] = { 252 { nxt_string("certificate"), 253 NXT_CONF_VLDT_STRING, 254 &nxt_conf_vldt_certificate, 255 NULL }, 256 257 NXT_CONF_VLDT_END 258}; 259 260#endif 261 262 263static nxt_conf_vldt_object_t nxt_conf_vldt_listener_members[] = { 264 { nxt_string("pass"), 265 NXT_CONF_VLDT_STRING, 266 &nxt_conf_vldt_pass, 267 NULL }, 268 269 { nxt_string("application"), 270 NXT_CONF_VLDT_STRING, 271 &nxt_conf_vldt_app_name, 272 NULL }, 273 274#if (NXT_TLS) 275 276 { nxt_string("tls"), 277 NXT_CONF_VLDT_OBJECT, 278 &nxt_conf_vldt_object, 279 (void *) &nxt_conf_vldt_tls_members }, 280 281#endif 282 283 NXT_CONF_VLDT_END 284}; 285 286 287static nxt_conf_vldt_object_t nxt_conf_vldt_match_members[] = { 288 { nxt_string("method"), 289 NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY, 290 &nxt_conf_vldt_match_patterns, 291 NULL }, 292 293 { nxt_string("scheme"), 294 NXT_CONF_VLDT_STRING, 295 &nxt_conf_vldt_match_scheme_pattern, 296 NULL }, 297 298 { nxt_string("host"), 299 NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY, 300 &nxt_conf_vldt_match_patterns, 301 NULL }, 302 303 { nxt_string("source"), 304 NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY, 305 &nxt_conf_vldt_match_addrs, 306 NULL }, 307 308 { nxt_string("destination"), 309 NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY, 310 &nxt_conf_vldt_match_addrs, 311 NULL }, 312 313 { nxt_string("uri"), 314 NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY, 315 &nxt_conf_vldt_match_patterns, 316 NULL }, 317 318 { nxt_string("arguments"), 319 NXT_CONF_VLDT_OBJECT | NXT_CONF_VLDT_ARRAY, 320 &nxt_conf_vldt_match_patterns_sets, 321 NULL }, 322 323 { nxt_string("headers"), 324 NXT_CONF_VLDT_OBJECT | NXT_CONF_VLDT_ARRAY, 325 &nxt_conf_vldt_match_patterns_sets, 326 NULL }, 327 328 { nxt_string("cookies"), 329 NXT_CONF_VLDT_OBJECT | NXT_CONF_VLDT_ARRAY, 330 &nxt_conf_vldt_match_patterns_sets, 331 NULL }, 332 333 NXT_CONF_VLDT_END 334}; 335 336 337static nxt_conf_vldt_object_t nxt_conf_vldt_pass_action_members[] = { 338 { nxt_string("pass"), 339 NXT_CONF_VLDT_STRING, 340 &nxt_conf_vldt_pass, 341 NULL }, 342 343 NXT_CONF_VLDT_END 344}; 345 346 347static nxt_conf_vldt_object_t nxt_conf_vldt_share_action_members[] = { 348 { nxt_string("share"), 349 NXT_CONF_VLDT_STRING, 350 NULL, 351 NULL }, 352 353 { nxt_string("fallback"), 354 NXT_CONF_VLDT_OBJECT, 355 &nxt_conf_vldt_action, 356 NULL }, 357 358 NXT_CONF_VLDT_END 359}; 360 361 362static nxt_conf_vldt_object_t nxt_conf_vldt_proxy_action_members[] = { 363 { nxt_string("proxy"), 364 NXT_CONF_VLDT_STRING, 365 &nxt_conf_vldt_proxy, 366 NULL }, 367 368 NXT_CONF_VLDT_END 369}; 370 371 372static nxt_conf_vldt_object_t nxt_conf_vldt_route_members[] = { 373 { nxt_string("match"), 374 NXT_CONF_VLDT_OBJECT, 375 &nxt_conf_vldt_object, 376 (void *) &nxt_conf_vldt_match_members }, 377 378 { nxt_string("action"), 379 NXT_CONF_VLDT_OBJECT, 380 &nxt_conf_vldt_action, 381 NULL }, 382 383 NXT_CONF_VLDT_END 384}; 385 386 387static nxt_conf_vldt_object_t nxt_conf_vldt_app_limits_members[] = { 388 { nxt_string("timeout"), 389 NXT_CONF_VLDT_INTEGER, 390 NULL, 391 NULL }, 392 393 { nxt_string("reschedule_timeout"), 394 NXT_CONF_VLDT_INTEGER, 395 NULL, 396 NULL }, 397 398 { nxt_string("requests"), 399 NXT_CONF_VLDT_INTEGER, 400 NULL, 401 NULL }, 402 403 { nxt_string("shm"), 404 NXT_CONF_VLDT_INTEGER, 405 NULL, 406 NULL }, 407 408 NXT_CONF_VLDT_END 409}; 410 411 412static nxt_conf_vldt_object_t nxt_conf_vldt_app_processes_members[] = { 413 { nxt_string("spare"), 414 NXT_CONF_VLDT_INTEGER, 415 NULL, 416 NULL }, 417 418 { nxt_string("max"), 419 NXT_CONF_VLDT_INTEGER, 420 NULL, 421 NULL }, 422 423 { nxt_string("idle_timeout"), 424 NXT_CONF_VLDT_INTEGER, 425 NULL, 426 NULL }, 427 428 NXT_CONF_VLDT_END 429}; 430 431 432static nxt_conf_vldt_object_t nxt_conf_vldt_app_namespaces_members[] = { 433 434#if (NXT_HAVE_CLONE_NEWUSER) 435 { nxt_string("credential"), 436 NXT_CONF_VLDT_BOOLEAN, 437 NULL, 438 NULL }, 439#endif 440 441#if (NXT_HAVE_CLONE_NEWPID) 442 { nxt_string("pid"), 443 NXT_CONF_VLDT_BOOLEAN, 444 NULL, 445 NULL }, 446#endif 447 448#if (NXT_HAVE_CLONE_NEWNET) 449 { nxt_string("network"), 450 NXT_CONF_VLDT_BOOLEAN, 451 NULL, 452 NULL }, 453#endif 454 455#if (NXT_HAVE_CLONE_NEWNS) 456 { nxt_string("mount"), 457 NXT_CONF_VLDT_BOOLEAN, 458 NULL, 459 NULL }, 460#endif 461 462#if (NXT_HAVE_CLONE_NEWUTS) 463 { nxt_string("uname"), 464 NXT_CONF_VLDT_BOOLEAN, 465 NULL, 466 NULL }, 467#endif 468 469#if (NXT_HAVE_CLONE_NEWCGROUP) 470 { nxt_string("cgroup"), 471 NXT_CONF_VLDT_BOOLEAN, 472 NULL, 473 NULL }, 474#endif 475 476 NXT_CONF_VLDT_END 477}; 478 479 480#if (NXT_HAVE_CLONE_NEWUSER) 481 482static nxt_conf_vldt_object_t nxt_conf_vldt_app_procmap_members[] = { 483 { nxt_string("container"), 484 NXT_CONF_VLDT_INTEGER, 485 NULL, 486 NULL }, 487 488 { nxt_string("host"), 489 NXT_CONF_VLDT_INTEGER, 490 NULL, 491 NULL }, 492 493 { nxt_string("size"), 494 NXT_CONF_VLDT_INTEGER, 495 NULL, 496 NULL }, 497}; 498 499#endif 500 501 502static nxt_conf_vldt_object_t nxt_conf_vldt_app_isolation_members[] = { 503 { nxt_string("namespaces"), 504 NXT_CONF_VLDT_OBJECT, 505 &nxt_conf_vldt_clone_namespaces, 506 (void *) &nxt_conf_vldt_app_namespaces_members }, 507 508#if (NXT_HAVE_CLONE_NEWUSER) 509 510 { nxt_string("uidmap"), 511 NXT_CONF_VLDT_ARRAY, 512 &nxt_conf_vldt_array_iterator, 513 (void *) &nxt_conf_vldt_clone_uidmap }, 514 515 { nxt_string("gidmap"), 516 NXT_CONF_VLDT_ARRAY, 517 &nxt_conf_vldt_array_iterator, 518 (void *) &nxt_conf_vldt_clone_gidmap }, 519 520#endif 521 522 NXT_CONF_VLDT_END 523}; 524 525 526static nxt_conf_vldt_object_t nxt_conf_vldt_common_members[] = { 527 { nxt_string("type"), 528 NXT_CONF_VLDT_STRING, 529 NULL, 530 NULL }, 531 532 { nxt_string("limits"), 533 NXT_CONF_VLDT_OBJECT, 534 &nxt_conf_vldt_object, 535 (void *) &nxt_conf_vldt_app_limits_members }, 536 537 { nxt_string("processes"), 538 NXT_CONF_VLDT_INTEGER | NXT_CONF_VLDT_OBJECT, 539 &nxt_conf_vldt_processes, 540 (void *) &nxt_conf_vldt_app_processes_members }, 541 542 { nxt_string("user"), 543 NXT_CONF_VLDT_STRING, 544 NULL, 545 NULL }, 546 547 { nxt_string("group"), 548 NXT_CONF_VLDT_STRING, 549 NULL, 550 NULL }, 551 552 { nxt_string("working_directory"), 553 NXT_CONF_VLDT_STRING, 554 NULL, 555 NULL }, 556 557 { nxt_string("environment"), 558 NXT_CONF_VLDT_OBJECT, 559 &nxt_conf_vldt_object_iterator, 560 (void *) &nxt_conf_vldt_environment }, 561 562 { nxt_string("isolation"), 563 NXT_CONF_VLDT_OBJECT, 564 &nxt_conf_vldt_isolation, 565 (void *) &nxt_conf_vldt_app_isolation_members }, 566 567 NXT_CONF_VLDT_END 568}; 569 570 571static nxt_conf_vldt_object_t nxt_conf_vldt_external_members[] = { 572 { nxt_string("executable"), 573 NXT_CONF_VLDT_STRING, 574 NULL, 575 NULL }, 576 577 { nxt_string("arguments"), 578 NXT_CONF_VLDT_ARRAY, 579 &nxt_conf_vldt_array_iterator, 580 (void *) &nxt_conf_vldt_argument }, 581 582 NXT_CONF_VLDT_NEXT(&nxt_conf_vldt_common_members) 583}; 584 585 586static nxt_conf_vldt_object_t nxt_conf_vldt_python_members[] = { 587 { nxt_string("home"), 588 NXT_CONF_VLDT_STRING, 589 NULL, 590 NULL }, 591 592 { nxt_string("path"), 593 NXT_CONF_VLDT_STRING, 594 NULL, 595 NULL }, 596 597 { nxt_string("module"), 598 NXT_CONF_VLDT_STRING, 599 NULL, 600 NULL }, 601 602 NXT_CONF_VLDT_NEXT(&nxt_conf_vldt_common_members) 603}; 604 605 606static nxt_conf_vldt_object_t nxt_conf_vldt_php_options_members[] = { 607 { nxt_string("file"), 608 NXT_CONF_VLDT_STRING, 609 NULL, 610 NULL }, 611 612 { nxt_string("admin"), 613 NXT_CONF_VLDT_OBJECT, 614 &nxt_conf_vldt_object_iterator, 615 (void *) &nxt_conf_vldt_php_option }, 616 617 { nxt_string("user"), 618 NXT_CONF_VLDT_OBJECT, 619 &nxt_conf_vldt_object_iterator, 620 (void *) &nxt_conf_vldt_php_option }, 621 622 NXT_CONF_VLDT_END 623}; 624 625 626static nxt_conf_vldt_object_t nxt_conf_vldt_php_members[] = { 627 { nxt_string("root"), 628 NXT_CONF_VLDT_STRING, 629 NULL, 630 NULL }, 631 632 { nxt_string("script"), 633 NXT_CONF_VLDT_STRING, 634 NULL, 635 NULL }, 636 637 { nxt_string("index"), 638 NXT_CONF_VLDT_STRING, 639 NULL, 640 NULL }, 641 642 { nxt_string("options"), 643 NXT_CONF_VLDT_OBJECT, 644 &nxt_conf_vldt_object, 645 (void *) &nxt_conf_vldt_php_options_members }, 646 647 NXT_CONF_VLDT_NEXT(&nxt_conf_vldt_common_members) 648}; 649 650 651static nxt_conf_vldt_object_t nxt_conf_vldt_perl_members[] = { 652 { nxt_string("script"), 653 NXT_CONF_VLDT_STRING, 654 NULL, 655 NULL }, 656 657 NXT_CONF_VLDT_NEXT(&nxt_conf_vldt_common_members) 658}; 659 660 661static nxt_conf_vldt_object_t nxt_conf_vldt_ruby_members[] = { 662 { nxt_string("script"), 663 NXT_CONF_VLDT_STRING, 664 NULL, 665 NULL }, 666 667 NXT_CONF_VLDT_NEXT(&nxt_conf_vldt_common_members) 668}; 669 670 671static nxt_conf_vldt_object_t nxt_conf_vldt_java_members[] = { 672 { nxt_string("classpath"), 673 NXT_CONF_VLDT_ARRAY, 674 &nxt_conf_vldt_array_iterator, 675 (void *) &nxt_conf_vldt_java_classpath }, 676 677 { nxt_string("webapp"), 678 NXT_CONF_VLDT_STRING, 679 NULL, 680 NULL }, 681 682 { nxt_string("options"), 683 NXT_CONF_VLDT_ARRAY, 684 &nxt_conf_vldt_array_iterator, 685 (void *) &nxt_conf_vldt_java_option }, 686 687 { nxt_string("unit_jars"), 688 NXT_CONF_VLDT_STRING, 689 NULL, 690 NULL }, 691 692 NXT_CONF_VLDT_NEXT(&nxt_conf_vldt_common_members) 693}; 694 695 696static nxt_conf_vldt_object_t nxt_conf_vldt_upstream_members[] = { 697 { nxt_string("servers"), 698 NXT_CONF_VLDT_OBJECT, 699 &nxt_conf_vldt_object_iterator, 700 (void *) &nxt_conf_vldt_server }, 701 702 NXT_CONF_VLDT_END 703}; 704 705 706static nxt_conf_vldt_object_t nxt_conf_vldt_upstream_server_members[] = { 707 { nxt_string("weight"), 708 NXT_CONF_VLDT_INTEGER, 709 &nxt_conf_vldt_server_weight, 710 NULL }, 711 712 NXT_CONF_VLDT_END 713}; 714 715 716nxt_int_t 717nxt_conf_validate(nxt_conf_validation_t *vldt) 718{ 719 nxt_int_t ret; 720 721 ret = nxt_conf_vldt_type(vldt, NULL, vldt->conf, NXT_CONF_VLDT_OBJECT); 722 723 if (ret != NXT_OK) { 724 return ret; 725 } 726 727 return nxt_conf_vldt_object(vldt, vldt->conf, nxt_conf_vldt_root_members); 728} 729 730 731#define NXT_CONF_VLDT_ANY_TYPE \ 732 "either a null, a boolean, an integer, " \ 733 "a number, a string, an array, or an object" 734 735 736static nxt_int_t 737nxt_conf_vldt_type(nxt_conf_validation_t *vldt, nxt_str_t *name, 738 nxt_conf_value_t *value, nxt_conf_vldt_type_t type) 739{ 740 u_char *p; 741 nxt_str_t expected; 742 nxt_bool_t serial; 743 nxt_uint_t value_type, n, t; 744 u_char buf[nxt_length(NXT_CONF_VLDT_ANY_TYPE)]; 745 746 static nxt_str_t type_name[] = { 747 nxt_string("a null"), 748 nxt_string("a boolean"), 749 nxt_string("an integer"), 750 nxt_string("a number"), 751 nxt_string("a string"), 752 nxt_string("an array"), 753 nxt_string("an object"), 754 }; 755 756 value_type = nxt_conf_type(value); 757 758 if ((1 << value_type) & type) { 759 return NXT_OK; 760 } 761 762 p = buf; 763 764 n = nxt_popcount(type); 765 766 if (n > 1) { 767 p = nxt_cpymem(p, "either ", 7); 768 } 769 770 serial = (n > 2); 771 772 for ( ;; ) { 773 t = __builtin_ffs(type) - 1; 774 775 p = nxt_cpymem(p, type_name[t].start, type_name[t].length); 776 777 n--; 778 779 if (n == 0) { 780 break; 781 } 782 783 if (n > 1 || serial) { 784 *p++ = ','; 785 } 786 787 if (n == 1) { 788 p = nxt_cpymem(p, " or", 3); 789 } 790 791 *p++ = ' '; 792 793 type = type & ~(1 << t); 794 } 795 796 expected.length = p - buf; 797 expected.start = buf; 798 799 if (name == NULL) { 800 return nxt_conf_vldt_error(vldt, 801 "The configuration must be %V, but not %V.", 802 &expected, &type_name[value_type]); 803 } 804 805 return nxt_conf_vldt_error(vldt, 806 "The \"%V\" value must be %V, but not %V.", 807 name, &expected, &type_name[value_type]); 808} 809 810 811static nxt_int_t 812nxt_conf_vldt_error(nxt_conf_validation_t *vldt, const char *fmt, ...) 813{ 814 u_char *p, *end; 815 size_t size; 816 va_list args; 817 u_char error[NXT_MAX_ERROR_STR]; 818 819 va_start(args, fmt); 820 end = nxt_vsprintf(error, error + NXT_MAX_ERROR_STR, fmt, args); 821 va_end(args); 822 823 size = end - error; 824 825 p = nxt_mp_nget(vldt->pool, size); 826 if (p == NULL) { 827 return NXT_ERROR; 828 } 829 830 nxt_memcpy(p, error, size); 831 832 vldt->error.length = size; 833 vldt->error.start = p; 834 835 return NXT_DECLINED; 836} 837 838 839typedef struct { 840 nxt_mp_t *pool; 841 nxt_str_t *type; 842 nxt_lvlhsh_t hash; 843} nxt_conf_vldt_mtypes_ctx_t; 844 845 846static nxt_int_t 847nxt_conf_vldt_mtypes(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, 848 void *data) 849{ 850 nxt_int_t ret; 851 nxt_conf_vldt_mtypes_ctx_t ctx; 852 853 ctx.pool = nxt_mp_create(1024, 128, 256, 32); 854 if (nxt_slow_path(ctx.pool == NULL)) { 855 return NXT_ERROR; 856 } 857 858 nxt_lvlhsh_init(&ctx.hash); 859 860 vldt->ctx = &ctx; 861 862 ret = nxt_conf_vldt_object_iterator(vldt, value, 863 &nxt_conf_vldt_mtypes_type); 864 865 vldt->ctx = NULL; 866 867 nxt_mp_destroy(ctx.pool); 868 869 return ret; 870} 871 872 873static nxt_int_t 874nxt_conf_vldt_mtypes_type(nxt_conf_validation_t *vldt, nxt_str_t *name, 875 nxt_conf_value_t *value) 876{ 877 nxt_int_t ret; 878 nxt_conf_vldt_mtypes_ctx_t *ctx; 879 880 ret = nxt_conf_vldt_type(vldt, name, value, 881 NXT_CONF_VLDT_STRING|NXT_CONF_VLDT_ARRAY); 882 if (ret != NXT_OK) { 883 return ret; 884 } 885 886 ctx = vldt->ctx; 887 888 ctx->type = nxt_mp_get(ctx->pool, sizeof(nxt_str_t)); 889 if (nxt_slow_path(ctx->type == NULL)) { 890 return NXT_ERROR; 891 } 892 893 *ctx->type = *name; 894 895 if (nxt_conf_type(value) == NXT_CONF_ARRAY) { 896 return nxt_conf_vldt_array_iterator(vldt, value, 897 &nxt_conf_vldt_mtypes_extension); 898 } 899 900 /* NXT_CONF_STRING */ 901 902 return nxt_conf_vldt_mtypes_extension(vldt, value); 903} 904 905 906static nxt_int_t 907nxt_conf_vldt_mtypes_extension(nxt_conf_validation_t *vldt, 908 nxt_conf_value_t *value) 909{ 910 nxt_str_t ext, *dup_type; 911 nxt_conf_vldt_mtypes_ctx_t *ctx; 912 913 ctx = vldt->ctx; 914 915 if (nxt_conf_type(value) != NXT_CONF_STRING) { 916 return nxt_conf_vldt_error(vldt, "The \"%V\" MIME type array must " 917 "contain only strings.", ctx->type); 918 } 919 920 nxt_conf_get_string(value, &ext); 921 922 if (ext.length == 0) { 923 return nxt_conf_vldt_error(vldt, "An empty file extension for " 924 "the \"%V\" MIME type.", ctx->type); 925 } 926 927 dup_type = nxt_http_static_mtypes_hash_find(&ctx->hash, &ext); 928 929 if (dup_type != NULL) { 930 return nxt_conf_vldt_error(vldt, "The \"%V\" file extension has been " 931 "declared for \"%V\" and \"%V\" " 932 "MIME types at the same time.", 933 &ext, dup_type, ctx->type); 934 } 935 936 return nxt_http_static_mtypes_hash_add(ctx->pool, &ctx->hash, 937 &ext, ctx->type); 938} 939 940 941static nxt_int_t 942nxt_conf_vldt_listener(nxt_conf_validation_t *vldt, nxt_str_t *name, 943 nxt_conf_value_t *value) 944{ 945 nxt_int_t ret; 946 947 ret = nxt_conf_vldt_type(vldt, name, value, NXT_CONF_VLDT_OBJECT); 948 949 if (ret != NXT_OK) { 950 return ret; 951 } 952 953 return nxt_conf_vldt_object(vldt, value, nxt_conf_vldt_listener_members); 954} 955 956 957static nxt_int_t 958nxt_conf_vldt_action(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, 959 void *data) 960{ 961 nxt_uint_t i; 962 nxt_conf_value_t *action; 963 nxt_conf_vldt_object_t *members; 964 965 static struct { 966 nxt_str_t name; 967 nxt_conf_vldt_object_t *members; 968 969 } actions[] = { 970 { nxt_string("pass"), nxt_conf_vldt_pass_action_members }, 971 { nxt_string("share"), nxt_conf_vldt_share_action_members }, 972 { nxt_string("proxy"), nxt_conf_vldt_proxy_action_members }, 973 }; 974 975 members = NULL; 976 977 for (i = 0; i < nxt_nitems(actions); i++) { 978 action = nxt_conf_get_object_member(value, &actions[i].name, NULL); 979 980 if (action == NULL) { 981 continue; 982 } 983 984 if (members != NULL) { 985 return nxt_conf_vldt_error(vldt, "The \"action\" object must have " 986 "just one of \"pass\", \"share\" or " 987 "\"proxy\" options set."); 988 } 989 990 members = actions[i].members; 991 } 992 993 if (members == NULL) { 994 return nxt_conf_vldt_error(vldt, "The \"action\" object must have " 995 "either \"pass\", \"share\", or " 996 "\"proxy\" option set."); 997 } 998 999 return nxt_conf_vldt_object(vldt, value, members); 1000} 1001 1002 1003static nxt_int_t 1004nxt_conf_vldt_pass(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, 1005 void *data) 1006{ 1007 u_char *p; 1008 nxt_str_t pass, first, second; 1009 1010 nxt_conf_get_string(value, &pass); 1011 1012 p = nxt_memchr(pass.start, '/', pass.length); 1013 1014 if (p != NULL) { 1015 first.length = p - pass.start; 1016 first.start = pass.start; 1017 1018 if (pass.length - first.length == 1) { 1019 goto error; 1020 } 1021 1022 second.length = pass.length - first.length - 1; 1023 second.start = p + 1; 1024 1025 } else { 1026 first = pass; 1027 second.length = 0; 1028 } 1029 1030 if (nxt_str_eq(&first, "applications", 12)) { 1031 1032 if (second.length == 0) { 1033 goto error; 1034 } 1035 1036 value = nxt_conf_get_object_member(vldt->conf, &first, NULL); 1037 1038 if (nxt_slow_path(value == NULL)) { 1039 goto error; 1040 } 1041 1042 value = nxt_conf_get_object_member(value, &second, NULL); 1043 1044 if (nxt_slow_path(value == NULL)) { 1045 goto error; 1046 } 1047 1048 return NXT_OK; 1049 } 1050 1051 if (nxt_str_eq(&first, "upstreams", 9)) { 1052 1053 if (second.length == 0) { 1054 goto error; 1055 } 1056 1057 value = nxt_conf_get_object_member(vldt->conf, &first, NULL); 1058 1059 if (nxt_slow_path(value == NULL)) { 1060 goto error; 1061 } 1062 1063 value = nxt_conf_get_object_member(value, &second, NULL); 1064 1065 if (nxt_slow_path(value == NULL)) { 1066 goto error; 1067 } 1068 1069 return NXT_OK; 1070 } 1071 1072 if (nxt_str_eq(&first, "routes", 6)) { 1073 value = nxt_conf_get_object_member(vldt->conf, &first, NULL); 1074 1075 if (nxt_slow_path(value == NULL)) { 1076 goto error; 1077 } 1078 1079 if (second.length == 0) { 1080 if (nxt_conf_type(value) != NXT_CONF_ARRAY) { 1081 goto error; 1082 } 1083 1084 return NXT_OK; 1085 } 1086 1087 if (nxt_conf_type(value) != NXT_CONF_OBJECT) { 1088 goto error; 1089 } 1090 1091 value = nxt_conf_get_object_member(value, &second, NULL); 1092 1093 if (nxt_slow_path(value == NULL)) { 1094 goto error; 1095 } 1096 1097 return NXT_OK; 1098 } 1099 1100error: 1101 1102 return nxt_conf_vldt_error(vldt, "Request \"pass\" points to invalid " 1103 "location \"%V\".", &pass); 1104} 1105 1106 1107static nxt_int_t 1108nxt_conf_vldt_proxy(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, 1109 void *data) 1110{ 1111 nxt_str_t name; 1112 nxt_sockaddr_t *sa; 1113 1114 nxt_conf_get_string(value, &name); 1115 1116 if (nxt_str_start(&name, "http://", 7)) { 1117 name.length -= 7; 1118 name.start += 7; 1119 1120 sa = nxt_sockaddr_parse(vldt->pool, &name); 1121 if (sa != NULL) { 1122 return NXT_OK; 1123 } 1124 } 1125 1126 return nxt_conf_vldt_error(vldt, "The \"proxy\" address is invalid \"%V\"", 1127 &name); 1128} 1129 1130 1131static nxt_int_t 1132nxt_conf_vldt_routes(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, 1133 void *data) 1134{ 1135 if (nxt_conf_type(value) == NXT_CONF_ARRAY) { 1136 return nxt_conf_vldt_array_iterator(vldt, value, 1137 &nxt_conf_vldt_route); 1138 } 1139 1140 /* NXT_CONF_OBJECT */ 1141 1142 return nxt_conf_vldt_object_iterator(vldt, value, 1143 &nxt_conf_vldt_routes_member); 1144} 1145 1146 1147static nxt_int_t 1148nxt_conf_vldt_routes_member(nxt_conf_validation_t *vldt, nxt_str_t *name, 1149 nxt_conf_value_t *value) 1150{ 1151 nxt_int_t ret; 1152 1153 ret = nxt_conf_vldt_type(vldt, name, value, NXT_CONF_VLDT_ARRAY); 1154 1155 if (ret != NXT_OK) { 1156 return ret; 1157 } 1158 1159 return nxt_conf_vldt_array_iterator(vldt, value, &nxt_conf_vldt_route); 1160} 1161 1162 1163static nxt_int_t 1164nxt_conf_vldt_route(nxt_conf_validation_t *vldt, nxt_conf_value_t *value) 1165{ 1166 if (nxt_conf_type(value) != NXT_CONF_OBJECT) { 1167 return nxt_conf_vldt_error(vldt, "The \"routes\" array must contain " 1168 "only object values."); 1169 } 1170 1171 return nxt_conf_vldt_object(vldt, value, nxt_conf_vldt_route_members); 1172} 1173 1174 1175static nxt_int_t 1176nxt_conf_vldt_match_patterns(nxt_conf_validation_t *vldt, 1177 nxt_conf_value_t *value, void *data) 1178{ 1179 if (nxt_conf_type(value) == NXT_CONF_ARRAY) { 1180 return nxt_conf_vldt_array_iterator(vldt, value, 1181 &nxt_conf_vldt_match_pattern); 1182 } 1183 1184 /* NXT_CONF_STRING */ 1185 1186 return nxt_conf_vldt_match_pattern(vldt, value); 1187} 1188 1189 1190static nxt_int_t 1191nxt_conf_vldt_match_pattern(nxt_conf_validation_t *vldt, 1192 nxt_conf_value_t *value) 1193{ 1194 u_char ch; 1195 nxt_str_t pattern; 1196 nxt_uint_t i, first, last; 1197 1198 enum { 1199 sw_none, 1200 sw_side, 1201 sw_middle 1202 } state; 1203 1204 if (nxt_conf_type(value) != NXT_CONF_STRING) { 1205 return nxt_conf_vldt_error(vldt, "The \"match\" patterns for \"host\", " 1206 "\"uri\", and \"method\" must be strings."); 1207 } 1208 1209 nxt_conf_get_string(value, &pattern); 1210 1211 if (pattern.length == 0) { 1212 return NXT_OK; 1213 } 1214 1215 first = (pattern.start[0] == '!'); 1216 last = pattern.length - 1; 1217 state = sw_none; 1218 1219 for (i = first; i != pattern.length; i++) { 1220 1221 ch = pattern.start[i]; 1222 1223 if (ch != '*') { 1224 continue; 1225 } 1226 1227 switch (state) { 1228 case sw_none: 1229 state = (i == first) ? sw_side : sw_middle; 1230 break; 1231 1232 case sw_side: 1233 if (i == last) { 1234 if (last - first != 1) { 1235 break; 1236 } 1237 1238 return nxt_conf_vldt_error(vldt, "The \"match\" pattern must " 1239 "not contain double \"*\" markers."); 1240 } 1241 1242 /* Fall through. */ 1243 1244 case sw_middle: 1245 return nxt_conf_vldt_error(vldt, "The \"match\" patterns can " 1246 "either contain \"*\" markers at " 1247 "the sides or only one in the middle."); 1248 } 1249 } 1250 1251 return NXT_OK; 1252} 1253 1254 1255static nxt_int_t 1256nxt_conf_vldt_match_addrs(nxt_conf_validation_t *vldt, 1257 nxt_conf_value_t *value, void *data) 1258{ 1259 if (nxt_conf_type(value) == NXT_CONF_ARRAY) { 1260 return nxt_conf_vldt_array_iterator(vldt, value, 1261 &nxt_conf_vldt_match_addr); 1262 } 1263 1264 return nxt_conf_vldt_match_addr(vldt, value); 1265} 1266 1267 1268static nxt_int_t 1269nxt_conf_vldt_match_addr(nxt_conf_validation_t *vldt, 1270 nxt_conf_value_t *value) 1271{ 1272 nxt_http_route_addr_pattern_t pattern; 1273 1274 switch (nxt_http_route_addr_pattern_parse(vldt->pool, &pattern, value)) { 1275 1276 case NXT_OK: 1277 return NXT_OK; 1278 1279 case NXT_ADDR_PATTERN_PORT_ERROR: 1280 return nxt_conf_vldt_error(vldt, "The \"address\" port an invalid " 1281 "port."); 1282 1283 case NXT_ADDR_PATTERN_CV_TYPE_ERROR: 1284 return nxt_conf_vldt_error(vldt, "The \"match\" pattern for " 1285 "\"address\" must be a string."); 1286 1287 case NXT_ADDR_PATTERN_LENGTH_ERROR: 1288 return nxt_conf_vldt_error(vldt, "The \"address\" is too short."); 1289 1290 case NXT_ADDR_PATTERN_FORMAT_ERROR: 1291 return nxt_conf_vldt_error(vldt, "The \"address\" format is invalid."); 1292 1293 case NXT_ADDR_PATTERN_RANGE_OVERLAP_ERROR: 1294 return nxt_conf_vldt_error(vldt, "The \"address\" range is " 1295 "overlapping."); 1296 1297 case NXT_ADDR_PATTERN_CIDR_ERROR: 1298 return nxt_conf_vldt_error(vldt, "The \"address\" has an invalid CIDR " 1299 "prefix."); 1300 1301 case NXT_ADDR_PATTERN_NO_IPv6_ERROR: 1302 return nxt_conf_vldt_error(vldt, "The \"address\" does not support " 1303 "IPv6 with your configuration."); 1304 1305 default: 1306 return nxt_conf_vldt_error(vldt, "The \"address\" has an unknown " 1307 "format."); 1308 } 1309} 1310 1311 1312static nxt_int_t 1313nxt_conf_vldt_match_scheme_pattern(nxt_conf_validation_t *vldt, 1314 nxt_conf_value_t *value, void *data) 1315{ 1316 nxt_str_t scheme; 1317 1318 static const nxt_str_t http = nxt_string("http"); 1319 static const nxt_str_t https = nxt_string("https"); 1320 1321 nxt_conf_get_string(value, &scheme); 1322 1323 if (nxt_strcasestr_eq(&scheme, &http) 1324 || nxt_strcasestr_eq(&scheme, &https)) 1325 { 1326 return NXT_OK; 1327 } 1328 1329 return nxt_conf_vldt_error(vldt, "The \"scheme\" can either be " 1330 "\"http\" or \"https\"."); 1331} 1332 1333 1334static nxt_int_t 1335nxt_conf_vldt_match_patterns_sets(nxt_conf_validation_t *vldt, 1336 nxt_conf_value_t *value, void *data) 1337{ 1338 if (nxt_conf_type(value) == NXT_CONF_ARRAY) { 1339 return nxt_conf_vldt_array_iterator(vldt, value, 1340 &nxt_conf_vldt_match_patterns_set); 1341 } 1342 1343 /* NXT_CONF_OBJECT */ 1344 1345 return nxt_conf_vldt_match_patterns_set(vldt, value); 1346} 1347 1348 1349static nxt_int_t 1350nxt_conf_vldt_match_patterns_set(nxt_conf_validation_t *vldt, 1351 nxt_conf_value_t *value) 1352{ 1353 if (nxt_conf_type(value) != NXT_CONF_OBJECT) { 1354 return nxt_conf_vldt_error(vldt, "The \"match\" patterns for " 1355 "\"arguments\", \"cookies\", and " 1356 "\"headers\" must be objects."); 1357 } 1358 1359 return nxt_conf_vldt_object_iterator(vldt, value, 1360 &nxt_conf_vldt_match_patterns_set_member); 1361} 1362 1363 1364static nxt_int_t 1365nxt_conf_vldt_match_patterns_set_member(nxt_conf_validation_t *vldt, 1366 nxt_str_t *name, nxt_conf_value_t *value) 1367{ 1368 if (name->length == 0) { 1369 return nxt_conf_vldt_error(vldt, "The \"match\" pattern objects must " 1370 "not contain empty member names."); 1371 } 1372 1373 return nxt_conf_vldt_match_patterns(vldt, value, NULL); 1374} 1375 1376 1377#if (NXT_TLS) 1378 1379static nxt_int_t 1380nxt_conf_vldt_certificate(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, 1381 void *data) 1382{ 1383 nxt_str_t name; 1384 nxt_conf_value_t *cert; 1385 1386 nxt_conf_get_string(value, &name); 1387 1388 cert = nxt_cert_info_get(&name); 1389 1390 if (cert == NULL) { 1391 return nxt_conf_vldt_error(vldt, "Certificate \"%V\" is not found.", 1392 &name); 1393 } 1394 1395 return NXT_OK; 1396} 1397 1398#endif 1399 1400 1401static nxt_int_t 1402nxt_conf_vldt_app_name(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, 1403 void *data) 1404{ 1405 nxt_str_t name; 1406 nxt_conf_value_t *apps, *app; 1407 1408 static nxt_str_t apps_str = nxt_string("applications"); 1409 1410 nxt_conf_get_string(value, &name); 1411 1412 apps = nxt_conf_get_object_member(vldt->conf, &apps_str, NULL); 1413 1414 if (nxt_slow_path(apps == NULL)) { 1415 goto error; 1416 } 1417 1418 app = nxt_conf_get_object_member(apps, &name, NULL); 1419 1420 if (nxt_slow_path(app == NULL)) { 1421 goto error; 1422 } 1423 1424 return NXT_OK; 1425 1426error: 1427 1428 return nxt_conf_vldt_error(vldt, "Listening socket is assigned for " 1429 "a non existing application \"%V\".", 1430 &name); 1431} 1432 1433 1434static nxt_int_t 1435nxt_conf_vldt_app(nxt_conf_validation_t *vldt, nxt_str_t *name, 1436 nxt_conf_value_t *value) 1437{ 1438 nxt_int_t ret; 1439 nxt_str_t type; 1440 nxt_thread_t *thread; 1441 nxt_conf_value_t *type_value; 1442 nxt_app_lang_module_t *lang; 1443 1444 static nxt_str_t type_str = nxt_string("type"); 1445 1446 static void *members[] = { 1447 nxt_conf_vldt_external_members, 1448 nxt_conf_vldt_python_members, 1449 nxt_conf_vldt_php_members, 1450 nxt_conf_vldt_perl_members, 1451 nxt_conf_vldt_ruby_members, 1452 nxt_conf_vldt_java_members, 1453 }; 1454 1455 ret = nxt_conf_vldt_type(vldt, name, value, NXT_CONF_VLDT_OBJECT); 1456 1457 if (ret != NXT_OK) { 1458 return ret; 1459 } 1460 1461 type_value = nxt_conf_get_object_member(value, &type_str, NULL); 1462 1463 if (type_value == NULL) { 1464 return nxt_conf_vldt_error(vldt, 1465 "Application must have the \"type\" property set."); 1466 } 1467 1468 ret = nxt_conf_vldt_type(vldt, &type_str, type_value, NXT_CONF_VLDT_STRING); 1469 1470 if (ret != NXT_OK) { 1471 return ret; 1472 } 1473 1474 nxt_conf_get_string(type_value, &type); 1475 1476 thread = nxt_thread(); 1477 1478 lang = nxt_app_lang_module(thread->runtime, &type); 1479 if (lang == NULL) { 1480 return nxt_conf_vldt_error(vldt, 1481 "The module to run \"%V\" is not found " 1482 "among the available application modules.", 1483 &type); 1484 } 1485 1486 return nxt_conf_vldt_object(vldt, value, members[lang->type]); 1487} 1488 1489 1490static nxt_int_t 1491nxt_conf_vldt_object(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, 1492 void *data) 1493{ 1494 uint32_t index; 1495 nxt_int_t ret; 1496 nxt_str_t name; 1497 nxt_conf_value_t *member; 1498 nxt_conf_vldt_object_t *vals; 1499 1500 index = 0; 1501 1502 for ( ;; ) { 1503 member = nxt_conf_next_object_member(value, &name, &index); 1504 1505 if (member == NULL) { 1506 return NXT_OK; 1507 } 1508 1509 vals = data; 1510 1511 for ( ;; ) { 1512 if (vals->name.length == 0) { 1513 1514 if (vals->data != NULL) { 1515 vals = vals->data; 1516 continue; 1517 } 1518 1519 return nxt_conf_vldt_error(vldt, "Unknown parameter \"%V\".", 1520 &name); 1521 } 1522 1523 if (!nxt_strstr_eq(&vals->name, &name)) { 1524 vals++; 1525 continue; 1526 } 1527 1528 ret = nxt_conf_vldt_type(vldt, &name, member, vals->type); 1529 1530 if (ret != NXT_OK) { 1531 return ret; 1532 } 1533 1534 if (vals->validator != NULL) { 1535 ret = vals->validator(vldt, member, vals->data); 1536 1537 if (ret != NXT_OK) { 1538 return ret; 1539 } 1540 } 1541 1542 break; 1543 } 1544 } 1545} 1546 1547 1548typedef struct { 1549 int64_t spare; 1550 int64_t max; 1551 int64_t idle_timeout; 1552} nxt_conf_vldt_processes_conf_t; 1553 1554 1555static nxt_conf_map_t nxt_conf_vldt_processes_conf_map[] = { 1556 { 1557 nxt_string("spare"), 1558 NXT_CONF_MAP_INT64, 1559 offsetof(nxt_conf_vldt_processes_conf_t, spare), 1560 }, 1561 1562 { 1563 nxt_string("max"), 1564 NXT_CONF_MAP_INT64, 1565 offsetof(nxt_conf_vldt_processes_conf_t, max), 1566 }, 1567 1568 { 1569 nxt_string("idle_timeout"), 1570 NXT_CONF_MAP_INT64, 1571 offsetof(nxt_conf_vldt_processes_conf_t, idle_timeout), 1572 }, 1573}; 1574 1575 1576static nxt_int_t 1577nxt_conf_vldt_processes(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, 1578 void *data) 1579{ 1580 int64_t int_value; 1581 nxt_int_t ret; 1582 nxt_conf_vldt_processes_conf_t proc; 1583 1584 if (nxt_conf_type(value) == NXT_CONF_INTEGER) { 1585 int_value = nxt_conf_get_integer(value); 1586 1587 if (int_value < 1) { 1588 return nxt_conf_vldt_error(vldt, "The \"processes\" number must be " 1589 "equal to or greater than 1."); 1590 } 1591 1592 if (int_value > NXT_INT32_T_MAX) { 1593 return nxt_conf_vldt_error(vldt, "The \"processes\" number must " 1594 "not exceed %d.", NXT_INT32_T_MAX); 1595 } 1596 1597 return NXT_OK; 1598 } 1599 1600 ret = nxt_conf_vldt_object(vldt, value, data); 1601 if (ret != NXT_OK) { 1602 return ret; 1603 } 1604 1605 proc.spare = 0; 1606 proc.max = 1; 1607 proc.idle_timeout = 15; 1608 1609 ret = nxt_conf_map_object(vldt->pool, value, 1610 nxt_conf_vldt_processes_conf_map, 1611 nxt_nitems(nxt_conf_vldt_processes_conf_map), 1612 &proc); 1613 if (ret != NXT_OK) { 1614 return ret; 1615 } 1616 1617 if (proc.spare < 0) { 1618 return nxt_conf_vldt_error(vldt, "The \"spare\" number must not be " 1619 "negative."); 1620 } 1621 1622 if (proc.spare > NXT_INT32_T_MAX) { 1623 return nxt_conf_vldt_error(vldt, "The \"spare\" number must not " 1624 "exceed %d.", NXT_INT32_T_MAX); 1625 } 1626 1627 if (proc.max < 1) { 1628 return nxt_conf_vldt_error(vldt, "The \"max\" number must be equal " 1629 "to or greater than 1."); 1630 } 1631 1632 if (proc.max > NXT_INT32_T_MAX) { 1633 return nxt_conf_vldt_error(vldt, "The \"max\" number must not " 1634 "exceed %d.", NXT_INT32_T_MAX); 1635 } 1636 1637 if (proc.max < proc.spare) { 1638 return nxt_conf_vldt_error(vldt, "The \"spare\" number must be " 1639 "less than or equal to \"max\"."); 1640 } 1641 1642 if (proc.idle_timeout < 0) { 1643 return nxt_conf_vldt_error(vldt, "The \"idle_timeout\" number must not " 1644 "be negative."); 1645 } 1646 1647 if (proc.idle_timeout > NXT_INT32_T_MAX / 1000) { 1648 return nxt_conf_vldt_error(vldt, "The \"idle_timeout\" number must not " 1649 "exceed %d.", NXT_INT32_T_MAX / 1000); 1650 } 1651 1652 return NXT_OK; 1653} 1654 1655 1656static nxt_int_t 1657nxt_conf_vldt_object_iterator(nxt_conf_validation_t *vldt, 1658 nxt_conf_value_t *value, void *data) 1659{ 1660 uint32_t index; 1661 nxt_int_t ret; 1662 nxt_str_t name; 1663 nxt_conf_value_t *member; 1664 nxt_conf_vldt_member_t validator; 1665 1666 validator = (nxt_conf_vldt_member_t) data; 1667 index = 0; 1668 1669 for ( ;; ) { 1670 member = nxt_conf_next_object_member(value, &name, &index); 1671 1672 if (member == NULL) { 1673 return NXT_OK; 1674 } 1675 1676 ret = validator(vldt, &name, member); 1677 1678 if (ret != NXT_OK) { 1679 return ret; 1680 } 1681 } 1682} 1683 1684 1685static nxt_int_t 1686nxt_conf_vldt_array_iterator(nxt_conf_validation_t *vldt, 1687 nxt_conf_value_t *value, void *data) 1688{ 1689 uint32_t index; 1690 nxt_int_t ret; 1691 nxt_conf_value_t *element; 1692 nxt_conf_vldt_element_t validator; 1693 1694 validator = (nxt_conf_vldt_element_t) data; 1695 1696 for (index = 0; /* void */ ; index++) { 1697 element = nxt_conf_get_array_element(value, index); 1698 1699 if (element == NULL) { 1700 return NXT_OK; 1701 } 1702 1703 ret = validator(vldt, element); 1704 1705 if (ret != NXT_OK) { 1706 return ret; 1707 } 1708 } 1709} 1710 1711 1712static nxt_int_t 1713nxt_conf_vldt_environment(nxt_conf_validation_t *vldt, nxt_str_t *name, 1714 nxt_conf_value_t *value) 1715{ 1716 nxt_str_t str; 1717 1718 if (name->length == 0) { 1719 return nxt_conf_vldt_error(vldt, 1720 "The environment name must not be empty."); 1721 } 1722 1723 if (nxt_memchr(name->start, '\0', name->length) != NULL) { 1724 return nxt_conf_vldt_error(vldt, "The environment name must not " 1725 "contain null character."); 1726 } 1727 1728 if (nxt_memchr(name->start, '=', name->length) != NULL) { 1729 return nxt_conf_vldt_error(vldt, "The environment name must not " 1730 "contain '=' character."); 1731 } 1732 1733 if (nxt_conf_type(value) != NXT_CONF_STRING) { 1734 return nxt_conf_vldt_error(vldt, "The \"%V\" environment value must be " 1735 "a string.", name); 1736 } 1737 1738 nxt_conf_get_string(value, &str); 1739 1740 if (nxt_memchr(str.start, '\0', str.length) != NULL) { 1741 return nxt_conf_vldt_error(vldt, "The \"%V\" environment value must " 1742 "not contain null character.", name); 1743 } 1744 1745 return NXT_OK; 1746} 1747 1748 1749static nxt_int_t 1750nxt_conf_vldt_clone_namespaces(nxt_conf_validation_t *vldt, 1751 nxt_conf_value_t *value, void *data) 1752{ 1753 return nxt_conf_vldt_object(vldt, value, data); 1754} 1755 1756 1757static nxt_int_t 1758nxt_conf_vldt_isolation(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, 1759 void *data) 1760{ 1761 return nxt_conf_vldt_object(vldt, value, data); 1762} 1763 1764 1765#if (NXT_HAVE_CLONE_NEWUSER) 1766 1767typedef struct { 1768 nxt_int_t container; 1769 nxt_int_t host; 1770 nxt_int_t size; 1771} nxt_conf_vldt_clone_procmap_conf_t; 1772 1773 1774static nxt_conf_map_t nxt_conf_vldt_clone_procmap_conf_map[] = { 1775 { 1776 nxt_string("container"), 1777 NXT_CONF_MAP_INT32, 1778 offsetof(nxt_conf_vldt_clone_procmap_conf_t, container), 1779 }, 1780 1781 { 1782 nxt_string("host"), 1783 NXT_CONF_MAP_INT32, 1784 offsetof(nxt_conf_vldt_clone_procmap_conf_t, host), 1785 }, 1786 1787 { 1788 nxt_string("size"), 1789 NXT_CONF_MAP_INT32, 1790 offsetof(nxt_conf_vldt_clone_procmap_conf_t, size), 1791 }, 1792 1793}; 1794 1795 1796static nxt_int_t 1797nxt_conf_vldt_clone_procmap(nxt_conf_validation_t *vldt, const char *mapfile, 1798 nxt_conf_value_t *value) 1799{ 1800 nxt_int_t ret; 1801 nxt_conf_vldt_clone_procmap_conf_t procmap; 1802 1803 procmap.container = -1; 1804 procmap.host = -1; 1805 procmap.size = -1; 1806 1807 ret = nxt_conf_map_object(vldt->pool, value, 1808 nxt_conf_vldt_clone_procmap_conf_map, 1809 nxt_nitems(nxt_conf_vldt_clone_procmap_conf_map), 1810 &procmap); 1811 if (ret != NXT_OK) { 1812 return ret; 1813 } 1814 1815 if (procmap.container == -1) { 1816 return nxt_conf_vldt_error(vldt, "The %s requires the " 1817 "\"container\" field set.", mapfile); 1818 } 1819 1820 if (procmap.host == -1) { 1821 return nxt_conf_vldt_error(vldt, "The %s requires the " 1822 "\"host\" field set.", mapfile); 1823 } 1824 1825 if (procmap.size == -1) { 1826 return nxt_conf_vldt_error(vldt, "The %s requires the " 1827 "\"size\" field set.", mapfile); 1828 } 1829 1830 return NXT_OK; 1831} 1832 1833 1834static nxt_int_t 1835nxt_conf_vldt_clone_uidmap(nxt_conf_validation_t *vldt, nxt_conf_value_t *value) 1836{ 1837 nxt_int_t ret; 1838 1839 if (nxt_conf_type(value) != NXT_CONF_OBJECT) { 1840 return nxt_conf_vldt_error(vldt, "The \"uidmap\" array " 1841 "must contain only object values."); 1842 } 1843 1844 ret = nxt_conf_vldt_object(vldt, value, 1845 (void *) nxt_conf_vldt_app_procmap_members); 1846 if (nxt_slow_path(ret != NXT_OK)) { 1847 return ret; 1848 } 1849 1850 return nxt_conf_vldt_clone_procmap(vldt, "uid_map", value); 1851} 1852 1853 1854static nxt_int_t 1855nxt_conf_vldt_clone_gidmap(nxt_conf_validation_t *vldt, nxt_conf_value_t *value) 1856{ 1857 nxt_int_t ret; 1858 1859 if (nxt_conf_type(value) != NXT_CONF_OBJECT) { 1860 return nxt_conf_vldt_error(vldt, "The \"gidmap\" array " 1861 "must contain only object values."); 1862 } 1863 1864 ret = nxt_conf_vldt_object(vldt, value, 1865 (void *) nxt_conf_vldt_app_procmap_members); 1866 if (nxt_slow_path(ret != NXT_OK)) { 1867 return ret; 1868 } 1869 1870 return nxt_conf_vldt_clone_procmap(vldt, "gid_map", value); 1871} 1872 1873#endif 1874 1875 1876static nxt_int_t 1877nxt_conf_vldt_argument(nxt_conf_validation_t *vldt, nxt_conf_value_t *value) 1878{ 1879 nxt_str_t str; 1880 1881 if (nxt_conf_type(value) != NXT_CONF_STRING) { 1882 return nxt_conf_vldt_error(vldt, "The \"arguments\" array " 1883 "must contain only string values."); 1884 } 1885 1886 nxt_conf_get_string(value, &str); 1887 1888 if (nxt_memchr(str.start, '\0', str.length) != NULL) { 1889 return nxt_conf_vldt_error(vldt, "The \"arguments\" array must not " 1890 "contain strings with null character."); 1891 } 1892 1893 return NXT_OK; 1894} 1895 1896 1897static nxt_int_t 1898nxt_conf_vldt_php_option(nxt_conf_validation_t *vldt, nxt_str_t *name, 1899 nxt_conf_value_t *value) 1900{ 1901 if (name->length == 0) { 1902 return nxt_conf_vldt_error(vldt, 1903 "The PHP option name must not be empty."); 1904 } 1905 1906 if (nxt_conf_type(value) != NXT_CONF_STRING) { 1907 return nxt_conf_vldt_error(vldt, "The \"%V\" PHP option must be " 1908 "a string.", name); 1909 } 1910 1911 return NXT_OK; 1912} 1913 1914 1915static nxt_int_t 1916nxt_conf_vldt_java_classpath(nxt_conf_validation_t *vldt, 1917 nxt_conf_value_t *value) 1918{ 1919 nxt_str_t str; 1920 1921 if (nxt_conf_type(value) != NXT_CONF_STRING) { 1922 return nxt_conf_vldt_error(vldt, "The \"classpath\" array " 1923 "must contain only string values."); 1924 } 1925 1926 nxt_conf_get_string(value, &str); 1927 1928 if (nxt_memchr(str.start, '\0', str.length) != NULL) { 1929 return nxt_conf_vldt_error(vldt, "The \"classpath\" array must not " 1930 "contain strings with null character."); 1931 } 1932 1933 return NXT_OK; 1934} 1935 1936 1937static nxt_int_t 1938nxt_conf_vldt_java_option(nxt_conf_validation_t *vldt, nxt_conf_value_t *value) 1939{ 1940 nxt_str_t str; 1941 1942 if (nxt_conf_type(value) != NXT_CONF_STRING) { 1943 return nxt_conf_vldt_error(vldt, "The \"options\" array " 1944 "must contain only string values."); 1945 } 1946 1947 nxt_conf_get_string(value, &str); 1948 1949 if (nxt_memchr(str.start, '\0', str.length) != NULL) { 1950 return nxt_conf_vldt_error(vldt, "The \"options\" array must not " 1951 "contain strings with null character."); 1952 } 1953 1954 return NXT_OK; 1955} 1956 1957 1958static nxt_int_t 1959nxt_conf_vldt_upstream(nxt_conf_validation_t *vldt, nxt_str_t *name, 1960 nxt_conf_value_t *value) 1961{ 1962 nxt_int_t ret; 1963 nxt_conf_value_t *conf; 1964 1965 static nxt_str_t servers = nxt_string("servers"); 1966 1967 ret = nxt_conf_vldt_type(vldt, name, value, NXT_CONF_VLDT_OBJECT); 1968 1969 if (ret != NXT_OK) { 1970 return ret; 1971 } 1972 1973 ret = nxt_conf_vldt_object(vldt, value, nxt_conf_vldt_upstream_members); 1974 1975 if (ret != NXT_OK) { 1976 return ret; 1977 } 1978 1979 conf = nxt_conf_get_object_member(value, &servers, NULL); 1980 if (conf == NULL) { 1981 return nxt_conf_vldt_error(vldt, "The \"%V\" upstream must contain " 1982 "\"servers\" object value.", name); 1983 } 1984 1985 return NXT_OK; 1986} 1987 1988 1989static nxt_int_t 1990nxt_conf_vldt_server(nxt_conf_validation_t *vldt, nxt_str_t *name, 1991 nxt_conf_value_t *value) 1992{ 1993 nxt_int_t ret; 1994 nxt_sockaddr_t *sa; 1995 1996 ret = nxt_conf_vldt_type(vldt, name, value, NXT_CONF_VLDT_OBJECT); 1997 1998 if (ret != NXT_OK) { 1999 return ret; 2000 } 2001 2002 sa = nxt_sockaddr_parse(vldt->pool, name); 2003 2004 if (sa == NULL) { 2005 return nxt_conf_vldt_error(vldt, "The \"%V\" is not valid " 2006 "server address.", name); 2007 } 2008 2009 return nxt_conf_vldt_object(vldt, value, 2010 nxt_conf_vldt_upstream_server_members); 2011} 2012 2013 2014static nxt_int_t 2015nxt_conf_vldt_server_weight(nxt_conf_validation_t *vldt, 2016 nxt_conf_value_t *value, void *data) 2017{ 2018 int64_t int_value; 2019 2020 int_value = nxt_conf_get_integer(value); 2021 2022 if (int_value <= 0) { 2023 return nxt_conf_vldt_error(vldt, "The \"weight\" number must be " 2024 "greater than 0."); 2025 } 2026 2027 if (int_value > NXT_INT32_T_MAX) { 2028 return nxt_conf_vldt_error(vldt, "The \"weight\" number must " 2029 "not exceed %d.", NXT_INT32_T_MAX); 2030 } 2031 2032 return NXT_OK; 2033}
| 200 { nxt_string("websocket"), 201 NXT_CONF_VLDT_OBJECT, 202 &nxt_conf_vldt_object, 203 (void *) &nxt_conf_vldt_websocket_members }, 204 205 { nxt_string("static"), 206 NXT_CONF_VLDT_OBJECT, 207 &nxt_conf_vldt_object, 208 (void *) &nxt_conf_vldt_static_members }, 209 210 NXT_CONF_VLDT_END 211}; 212 213 214static nxt_conf_vldt_object_t nxt_conf_vldt_setting_members[] = { 215 { nxt_string("http"), 216 NXT_CONF_VLDT_OBJECT, 217 &nxt_conf_vldt_object, 218 (void *) &nxt_conf_vldt_http_members }, 219 220 NXT_CONF_VLDT_END 221}; 222 223 224static nxt_conf_vldt_object_t nxt_conf_vldt_root_members[] = { 225 { nxt_string("settings"), 226 NXT_CONF_VLDT_OBJECT, 227 &nxt_conf_vldt_object, 228 (void *) &nxt_conf_vldt_setting_members }, 229 230 { nxt_string("listeners"), 231 NXT_CONF_VLDT_OBJECT, 232 &nxt_conf_vldt_object_iterator, 233 (void *) &nxt_conf_vldt_listener }, 234 235 { nxt_string("routes"), 236 NXT_CONF_VLDT_ARRAY | NXT_CONF_VLDT_OBJECT, 237 &nxt_conf_vldt_routes, 238 NULL }, 239 240 { nxt_string("applications"), 241 NXT_CONF_VLDT_OBJECT, 242 &nxt_conf_vldt_object_iterator, 243 (void *) &nxt_conf_vldt_app }, 244 245 { nxt_string("upstreams"), 246 NXT_CONF_VLDT_OBJECT, 247 &nxt_conf_vldt_object_iterator, 248 (void *) &nxt_conf_vldt_upstream }, 249 250 { nxt_string("access_log"), 251 NXT_CONF_VLDT_STRING, 252 NULL, 253 NULL }, 254 255 NXT_CONF_VLDT_END 256}; 257 258 259#if (NXT_TLS) 260 261static nxt_conf_vldt_object_t nxt_conf_vldt_tls_members[] = { 262 { nxt_string("certificate"), 263 NXT_CONF_VLDT_STRING, 264 &nxt_conf_vldt_certificate, 265 NULL }, 266 267 NXT_CONF_VLDT_END 268}; 269 270#endif 271 272 273static nxt_conf_vldt_object_t nxt_conf_vldt_listener_members[] = { 274 { nxt_string("pass"), 275 NXT_CONF_VLDT_STRING, 276 &nxt_conf_vldt_pass, 277 NULL }, 278 279 { nxt_string("application"), 280 NXT_CONF_VLDT_STRING, 281 &nxt_conf_vldt_app_name, 282 NULL }, 283 284#if (NXT_TLS) 285 286 { nxt_string("tls"), 287 NXT_CONF_VLDT_OBJECT, 288 &nxt_conf_vldt_object, 289 (void *) &nxt_conf_vldt_tls_members }, 290 291#endif 292 293 NXT_CONF_VLDT_END 294}; 295 296 297static nxt_conf_vldt_object_t nxt_conf_vldt_match_members[] = { 298 { nxt_string("method"), 299 NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY, 300 &nxt_conf_vldt_match_patterns, 301 NULL }, 302 303 { nxt_string("scheme"), 304 NXT_CONF_VLDT_STRING, 305 &nxt_conf_vldt_match_scheme_pattern, 306 NULL }, 307 308 { nxt_string("host"), 309 NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY, 310 &nxt_conf_vldt_match_patterns, 311 NULL }, 312 313 { nxt_string("source"), 314 NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY, 315 &nxt_conf_vldt_match_addrs, 316 NULL }, 317 318 { nxt_string("destination"), 319 NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY, 320 &nxt_conf_vldt_match_addrs, 321 NULL }, 322 323 { nxt_string("uri"), 324 NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY, 325 &nxt_conf_vldt_match_patterns, 326 NULL }, 327 328 { nxt_string("arguments"), 329 NXT_CONF_VLDT_OBJECT | NXT_CONF_VLDT_ARRAY, 330 &nxt_conf_vldt_match_patterns_sets, 331 NULL }, 332 333 { nxt_string("headers"), 334 NXT_CONF_VLDT_OBJECT | NXT_CONF_VLDT_ARRAY, 335 &nxt_conf_vldt_match_patterns_sets, 336 NULL }, 337 338 { nxt_string("cookies"), 339 NXT_CONF_VLDT_OBJECT | NXT_CONF_VLDT_ARRAY, 340 &nxt_conf_vldt_match_patterns_sets, 341 NULL }, 342 343 NXT_CONF_VLDT_END 344}; 345 346 347static nxt_conf_vldt_object_t nxt_conf_vldt_pass_action_members[] = { 348 { nxt_string("pass"), 349 NXT_CONF_VLDT_STRING, 350 &nxt_conf_vldt_pass, 351 NULL }, 352 353 NXT_CONF_VLDT_END 354}; 355 356 357static nxt_conf_vldt_object_t nxt_conf_vldt_share_action_members[] = { 358 { nxt_string("share"), 359 NXT_CONF_VLDT_STRING, 360 NULL, 361 NULL }, 362 363 { nxt_string("fallback"), 364 NXT_CONF_VLDT_OBJECT, 365 &nxt_conf_vldt_action, 366 NULL }, 367 368 NXT_CONF_VLDT_END 369}; 370 371 372static nxt_conf_vldt_object_t nxt_conf_vldt_proxy_action_members[] = { 373 { nxt_string("proxy"), 374 NXT_CONF_VLDT_STRING, 375 &nxt_conf_vldt_proxy, 376 NULL }, 377 378 NXT_CONF_VLDT_END 379}; 380 381 382static nxt_conf_vldt_object_t nxt_conf_vldt_route_members[] = { 383 { nxt_string("match"), 384 NXT_CONF_VLDT_OBJECT, 385 &nxt_conf_vldt_object, 386 (void *) &nxt_conf_vldt_match_members }, 387 388 { nxt_string("action"), 389 NXT_CONF_VLDT_OBJECT, 390 &nxt_conf_vldt_action, 391 NULL }, 392 393 NXT_CONF_VLDT_END 394}; 395 396 397static nxt_conf_vldt_object_t nxt_conf_vldt_app_limits_members[] = { 398 { nxt_string("timeout"), 399 NXT_CONF_VLDT_INTEGER, 400 NULL, 401 NULL }, 402 403 { nxt_string("reschedule_timeout"), 404 NXT_CONF_VLDT_INTEGER, 405 NULL, 406 NULL }, 407 408 { nxt_string("requests"), 409 NXT_CONF_VLDT_INTEGER, 410 NULL, 411 NULL }, 412 413 { nxt_string("shm"), 414 NXT_CONF_VLDT_INTEGER, 415 NULL, 416 NULL }, 417 418 NXT_CONF_VLDT_END 419}; 420 421 422static nxt_conf_vldt_object_t nxt_conf_vldt_app_processes_members[] = { 423 { nxt_string("spare"), 424 NXT_CONF_VLDT_INTEGER, 425 NULL, 426 NULL }, 427 428 { nxt_string("max"), 429 NXT_CONF_VLDT_INTEGER, 430 NULL, 431 NULL }, 432 433 { nxt_string("idle_timeout"), 434 NXT_CONF_VLDT_INTEGER, 435 NULL, 436 NULL }, 437 438 NXT_CONF_VLDT_END 439}; 440 441 442static nxt_conf_vldt_object_t nxt_conf_vldt_app_namespaces_members[] = { 443 444#if (NXT_HAVE_CLONE_NEWUSER) 445 { nxt_string("credential"), 446 NXT_CONF_VLDT_BOOLEAN, 447 NULL, 448 NULL }, 449#endif 450 451#if (NXT_HAVE_CLONE_NEWPID) 452 { nxt_string("pid"), 453 NXT_CONF_VLDT_BOOLEAN, 454 NULL, 455 NULL }, 456#endif 457 458#if (NXT_HAVE_CLONE_NEWNET) 459 { nxt_string("network"), 460 NXT_CONF_VLDT_BOOLEAN, 461 NULL, 462 NULL }, 463#endif 464 465#if (NXT_HAVE_CLONE_NEWNS) 466 { nxt_string("mount"), 467 NXT_CONF_VLDT_BOOLEAN, 468 NULL, 469 NULL }, 470#endif 471 472#if (NXT_HAVE_CLONE_NEWUTS) 473 { nxt_string("uname"), 474 NXT_CONF_VLDT_BOOLEAN, 475 NULL, 476 NULL }, 477#endif 478 479#if (NXT_HAVE_CLONE_NEWCGROUP) 480 { nxt_string("cgroup"), 481 NXT_CONF_VLDT_BOOLEAN, 482 NULL, 483 NULL }, 484#endif 485 486 NXT_CONF_VLDT_END 487}; 488 489 490#if (NXT_HAVE_CLONE_NEWUSER) 491 492static nxt_conf_vldt_object_t nxt_conf_vldt_app_procmap_members[] = { 493 { nxt_string("container"), 494 NXT_CONF_VLDT_INTEGER, 495 NULL, 496 NULL }, 497 498 { nxt_string("host"), 499 NXT_CONF_VLDT_INTEGER, 500 NULL, 501 NULL }, 502 503 { nxt_string("size"), 504 NXT_CONF_VLDT_INTEGER, 505 NULL, 506 NULL }, 507}; 508 509#endif 510 511 512static nxt_conf_vldt_object_t nxt_conf_vldt_app_isolation_members[] = { 513 { nxt_string("namespaces"), 514 NXT_CONF_VLDT_OBJECT, 515 &nxt_conf_vldt_clone_namespaces, 516 (void *) &nxt_conf_vldt_app_namespaces_members }, 517 518#if (NXT_HAVE_CLONE_NEWUSER) 519 520 { nxt_string("uidmap"), 521 NXT_CONF_VLDT_ARRAY, 522 &nxt_conf_vldt_array_iterator, 523 (void *) &nxt_conf_vldt_clone_uidmap }, 524 525 { nxt_string("gidmap"), 526 NXT_CONF_VLDT_ARRAY, 527 &nxt_conf_vldt_array_iterator, 528 (void *) &nxt_conf_vldt_clone_gidmap }, 529 530#endif 531 532 NXT_CONF_VLDT_END 533}; 534 535 536static nxt_conf_vldt_object_t nxt_conf_vldt_common_members[] = { 537 { nxt_string("type"), 538 NXT_CONF_VLDT_STRING, 539 NULL, 540 NULL }, 541 542 { nxt_string("limits"), 543 NXT_CONF_VLDT_OBJECT, 544 &nxt_conf_vldt_object, 545 (void *) &nxt_conf_vldt_app_limits_members }, 546 547 { nxt_string("processes"), 548 NXT_CONF_VLDT_INTEGER | NXT_CONF_VLDT_OBJECT, 549 &nxt_conf_vldt_processes, 550 (void *) &nxt_conf_vldt_app_processes_members }, 551 552 { nxt_string("user"), 553 NXT_CONF_VLDT_STRING, 554 NULL, 555 NULL }, 556 557 { nxt_string("group"), 558 NXT_CONF_VLDT_STRING, 559 NULL, 560 NULL }, 561 562 { nxt_string("working_directory"), 563 NXT_CONF_VLDT_STRING, 564 NULL, 565 NULL }, 566 567 { nxt_string("environment"), 568 NXT_CONF_VLDT_OBJECT, 569 &nxt_conf_vldt_object_iterator, 570 (void *) &nxt_conf_vldt_environment }, 571 572 { nxt_string("isolation"), 573 NXT_CONF_VLDT_OBJECT, 574 &nxt_conf_vldt_isolation, 575 (void *) &nxt_conf_vldt_app_isolation_members }, 576 577 NXT_CONF_VLDT_END 578}; 579 580 581static nxt_conf_vldt_object_t nxt_conf_vldt_external_members[] = { 582 { nxt_string("executable"), 583 NXT_CONF_VLDT_STRING, 584 NULL, 585 NULL }, 586 587 { nxt_string("arguments"), 588 NXT_CONF_VLDT_ARRAY, 589 &nxt_conf_vldt_array_iterator, 590 (void *) &nxt_conf_vldt_argument }, 591 592 NXT_CONF_VLDT_NEXT(&nxt_conf_vldt_common_members) 593}; 594 595 596static nxt_conf_vldt_object_t nxt_conf_vldt_python_members[] = { 597 { nxt_string("home"), 598 NXT_CONF_VLDT_STRING, 599 NULL, 600 NULL }, 601 602 { nxt_string("path"), 603 NXT_CONF_VLDT_STRING, 604 NULL, 605 NULL }, 606 607 { nxt_string("module"), 608 NXT_CONF_VLDT_STRING, 609 NULL, 610 NULL }, 611 612 NXT_CONF_VLDT_NEXT(&nxt_conf_vldt_common_members) 613}; 614 615 616static nxt_conf_vldt_object_t nxt_conf_vldt_php_options_members[] = { 617 { nxt_string("file"), 618 NXT_CONF_VLDT_STRING, 619 NULL, 620 NULL }, 621 622 { nxt_string("admin"), 623 NXT_CONF_VLDT_OBJECT, 624 &nxt_conf_vldt_object_iterator, 625 (void *) &nxt_conf_vldt_php_option }, 626 627 { nxt_string("user"), 628 NXT_CONF_VLDT_OBJECT, 629 &nxt_conf_vldt_object_iterator, 630 (void *) &nxt_conf_vldt_php_option }, 631 632 NXT_CONF_VLDT_END 633}; 634 635 636static nxt_conf_vldt_object_t nxt_conf_vldt_php_members[] = { 637 { nxt_string("root"), 638 NXT_CONF_VLDT_STRING, 639 NULL, 640 NULL }, 641 642 { nxt_string("script"), 643 NXT_CONF_VLDT_STRING, 644 NULL, 645 NULL }, 646 647 { nxt_string("index"), 648 NXT_CONF_VLDT_STRING, 649 NULL, 650 NULL }, 651 652 { nxt_string("options"), 653 NXT_CONF_VLDT_OBJECT, 654 &nxt_conf_vldt_object, 655 (void *) &nxt_conf_vldt_php_options_members }, 656 657 NXT_CONF_VLDT_NEXT(&nxt_conf_vldt_common_members) 658}; 659 660 661static nxt_conf_vldt_object_t nxt_conf_vldt_perl_members[] = { 662 { nxt_string("script"), 663 NXT_CONF_VLDT_STRING, 664 NULL, 665 NULL }, 666 667 NXT_CONF_VLDT_NEXT(&nxt_conf_vldt_common_members) 668}; 669 670 671static nxt_conf_vldt_object_t nxt_conf_vldt_ruby_members[] = { 672 { nxt_string("script"), 673 NXT_CONF_VLDT_STRING, 674 NULL, 675 NULL }, 676 677 NXT_CONF_VLDT_NEXT(&nxt_conf_vldt_common_members) 678}; 679 680 681static nxt_conf_vldt_object_t nxt_conf_vldt_java_members[] = { 682 { nxt_string("classpath"), 683 NXT_CONF_VLDT_ARRAY, 684 &nxt_conf_vldt_array_iterator, 685 (void *) &nxt_conf_vldt_java_classpath }, 686 687 { nxt_string("webapp"), 688 NXT_CONF_VLDT_STRING, 689 NULL, 690 NULL }, 691 692 { nxt_string("options"), 693 NXT_CONF_VLDT_ARRAY, 694 &nxt_conf_vldt_array_iterator, 695 (void *) &nxt_conf_vldt_java_option }, 696 697 { nxt_string("unit_jars"), 698 NXT_CONF_VLDT_STRING, 699 NULL, 700 NULL }, 701 702 NXT_CONF_VLDT_NEXT(&nxt_conf_vldt_common_members) 703}; 704 705 706static nxt_conf_vldt_object_t nxt_conf_vldt_upstream_members[] = { 707 { nxt_string("servers"), 708 NXT_CONF_VLDT_OBJECT, 709 &nxt_conf_vldt_object_iterator, 710 (void *) &nxt_conf_vldt_server }, 711 712 NXT_CONF_VLDT_END 713}; 714 715 716static nxt_conf_vldt_object_t nxt_conf_vldt_upstream_server_members[] = { 717 { nxt_string("weight"), 718 NXT_CONF_VLDT_INTEGER, 719 &nxt_conf_vldt_server_weight, 720 NULL }, 721 722 NXT_CONF_VLDT_END 723}; 724 725 726nxt_int_t 727nxt_conf_validate(nxt_conf_validation_t *vldt) 728{ 729 nxt_int_t ret; 730 731 ret = nxt_conf_vldt_type(vldt, NULL, vldt->conf, NXT_CONF_VLDT_OBJECT); 732 733 if (ret != NXT_OK) { 734 return ret; 735 } 736 737 return nxt_conf_vldt_object(vldt, vldt->conf, nxt_conf_vldt_root_members); 738} 739 740 741#define NXT_CONF_VLDT_ANY_TYPE \ 742 "either a null, a boolean, an integer, " \ 743 "a number, a string, an array, or an object" 744 745 746static nxt_int_t 747nxt_conf_vldt_type(nxt_conf_validation_t *vldt, nxt_str_t *name, 748 nxt_conf_value_t *value, nxt_conf_vldt_type_t type) 749{ 750 u_char *p; 751 nxt_str_t expected; 752 nxt_bool_t serial; 753 nxt_uint_t value_type, n, t; 754 u_char buf[nxt_length(NXT_CONF_VLDT_ANY_TYPE)]; 755 756 static nxt_str_t type_name[] = { 757 nxt_string("a null"), 758 nxt_string("a boolean"), 759 nxt_string("an integer"), 760 nxt_string("a number"), 761 nxt_string("a string"), 762 nxt_string("an array"), 763 nxt_string("an object"), 764 }; 765 766 value_type = nxt_conf_type(value); 767 768 if ((1 << value_type) & type) { 769 return NXT_OK; 770 } 771 772 p = buf; 773 774 n = nxt_popcount(type); 775 776 if (n > 1) { 777 p = nxt_cpymem(p, "either ", 7); 778 } 779 780 serial = (n > 2); 781 782 for ( ;; ) { 783 t = __builtin_ffs(type) - 1; 784 785 p = nxt_cpymem(p, type_name[t].start, type_name[t].length); 786 787 n--; 788 789 if (n == 0) { 790 break; 791 } 792 793 if (n > 1 || serial) { 794 *p++ = ','; 795 } 796 797 if (n == 1) { 798 p = nxt_cpymem(p, " or", 3); 799 } 800 801 *p++ = ' '; 802 803 type = type & ~(1 << t); 804 } 805 806 expected.length = p - buf; 807 expected.start = buf; 808 809 if (name == NULL) { 810 return nxt_conf_vldt_error(vldt, 811 "The configuration must be %V, but not %V.", 812 &expected, &type_name[value_type]); 813 } 814 815 return nxt_conf_vldt_error(vldt, 816 "The \"%V\" value must be %V, but not %V.", 817 name, &expected, &type_name[value_type]); 818} 819 820 821static nxt_int_t 822nxt_conf_vldt_error(nxt_conf_validation_t *vldt, const char *fmt, ...) 823{ 824 u_char *p, *end; 825 size_t size; 826 va_list args; 827 u_char error[NXT_MAX_ERROR_STR]; 828 829 va_start(args, fmt); 830 end = nxt_vsprintf(error, error + NXT_MAX_ERROR_STR, fmt, args); 831 va_end(args); 832 833 size = end - error; 834 835 p = nxt_mp_nget(vldt->pool, size); 836 if (p == NULL) { 837 return NXT_ERROR; 838 } 839 840 nxt_memcpy(p, error, size); 841 842 vldt->error.length = size; 843 vldt->error.start = p; 844 845 return NXT_DECLINED; 846} 847 848 849typedef struct { 850 nxt_mp_t *pool; 851 nxt_str_t *type; 852 nxt_lvlhsh_t hash; 853} nxt_conf_vldt_mtypes_ctx_t; 854 855 856static nxt_int_t 857nxt_conf_vldt_mtypes(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, 858 void *data) 859{ 860 nxt_int_t ret; 861 nxt_conf_vldt_mtypes_ctx_t ctx; 862 863 ctx.pool = nxt_mp_create(1024, 128, 256, 32); 864 if (nxt_slow_path(ctx.pool == NULL)) { 865 return NXT_ERROR; 866 } 867 868 nxt_lvlhsh_init(&ctx.hash); 869 870 vldt->ctx = &ctx; 871 872 ret = nxt_conf_vldt_object_iterator(vldt, value, 873 &nxt_conf_vldt_mtypes_type); 874 875 vldt->ctx = NULL; 876 877 nxt_mp_destroy(ctx.pool); 878 879 return ret; 880} 881 882 883static nxt_int_t 884nxt_conf_vldt_mtypes_type(nxt_conf_validation_t *vldt, nxt_str_t *name, 885 nxt_conf_value_t *value) 886{ 887 nxt_int_t ret; 888 nxt_conf_vldt_mtypes_ctx_t *ctx; 889 890 ret = nxt_conf_vldt_type(vldt, name, value, 891 NXT_CONF_VLDT_STRING|NXT_CONF_VLDT_ARRAY); 892 if (ret != NXT_OK) { 893 return ret; 894 } 895 896 ctx = vldt->ctx; 897 898 ctx->type = nxt_mp_get(ctx->pool, sizeof(nxt_str_t)); 899 if (nxt_slow_path(ctx->type == NULL)) { 900 return NXT_ERROR; 901 } 902 903 *ctx->type = *name; 904 905 if (nxt_conf_type(value) == NXT_CONF_ARRAY) { 906 return nxt_conf_vldt_array_iterator(vldt, value, 907 &nxt_conf_vldt_mtypes_extension); 908 } 909 910 /* NXT_CONF_STRING */ 911 912 return nxt_conf_vldt_mtypes_extension(vldt, value); 913} 914 915 916static nxt_int_t 917nxt_conf_vldt_mtypes_extension(nxt_conf_validation_t *vldt, 918 nxt_conf_value_t *value) 919{ 920 nxt_str_t ext, *dup_type; 921 nxt_conf_vldt_mtypes_ctx_t *ctx; 922 923 ctx = vldt->ctx; 924 925 if (nxt_conf_type(value) != NXT_CONF_STRING) { 926 return nxt_conf_vldt_error(vldt, "The \"%V\" MIME type array must " 927 "contain only strings.", ctx->type); 928 } 929 930 nxt_conf_get_string(value, &ext); 931 932 if (ext.length == 0) { 933 return nxt_conf_vldt_error(vldt, "An empty file extension for " 934 "the \"%V\" MIME type.", ctx->type); 935 } 936 937 dup_type = nxt_http_static_mtypes_hash_find(&ctx->hash, &ext); 938 939 if (dup_type != NULL) { 940 return nxt_conf_vldt_error(vldt, "The \"%V\" file extension has been " 941 "declared for \"%V\" and \"%V\" " 942 "MIME types at the same time.", 943 &ext, dup_type, ctx->type); 944 } 945 946 return nxt_http_static_mtypes_hash_add(ctx->pool, &ctx->hash, 947 &ext, ctx->type); 948} 949 950 951static nxt_int_t 952nxt_conf_vldt_listener(nxt_conf_validation_t *vldt, nxt_str_t *name, 953 nxt_conf_value_t *value) 954{ 955 nxt_int_t ret; 956 957 ret = nxt_conf_vldt_type(vldt, name, value, NXT_CONF_VLDT_OBJECT); 958 959 if (ret != NXT_OK) { 960 return ret; 961 } 962 963 return nxt_conf_vldt_object(vldt, value, nxt_conf_vldt_listener_members); 964} 965 966 967static nxt_int_t 968nxt_conf_vldt_action(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, 969 void *data) 970{ 971 nxt_uint_t i; 972 nxt_conf_value_t *action; 973 nxt_conf_vldt_object_t *members; 974 975 static struct { 976 nxt_str_t name; 977 nxt_conf_vldt_object_t *members; 978 979 } actions[] = { 980 { nxt_string("pass"), nxt_conf_vldt_pass_action_members }, 981 { nxt_string("share"), nxt_conf_vldt_share_action_members }, 982 { nxt_string("proxy"), nxt_conf_vldt_proxy_action_members }, 983 }; 984 985 members = NULL; 986 987 for (i = 0; i < nxt_nitems(actions); i++) { 988 action = nxt_conf_get_object_member(value, &actions[i].name, NULL); 989 990 if (action == NULL) { 991 continue; 992 } 993 994 if (members != NULL) { 995 return nxt_conf_vldt_error(vldt, "The \"action\" object must have " 996 "just one of \"pass\", \"share\" or " 997 "\"proxy\" options set."); 998 } 999 1000 members = actions[i].members; 1001 } 1002 1003 if (members == NULL) { 1004 return nxt_conf_vldt_error(vldt, "The \"action\" object must have " 1005 "either \"pass\", \"share\", or " 1006 "\"proxy\" option set."); 1007 } 1008 1009 return nxt_conf_vldt_object(vldt, value, members); 1010} 1011 1012 1013static nxt_int_t 1014nxt_conf_vldt_pass(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, 1015 void *data) 1016{ 1017 u_char *p; 1018 nxt_str_t pass, first, second; 1019 1020 nxt_conf_get_string(value, &pass); 1021 1022 p = nxt_memchr(pass.start, '/', pass.length); 1023 1024 if (p != NULL) { 1025 first.length = p - pass.start; 1026 first.start = pass.start; 1027 1028 if (pass.length - first.length == 1) { 1029 goto error; 1030 } 1031 1032 second.length = pass.length - first.length - 1; 1033 second.start = p + 1; 1034 1035 } else { 1036 first = pass; 1037 second.length = 0; 1038 } 1039 1040 if (nxt_str_eq(&first, "applications", 12)) { 1041 1042 if (second.length == 0) { 1043 goto error; 1044 } 1045 1046 value = nxt_conf_get_object_member(vldt->conf, &first, NULL); 1047 1048 if (nxt_slow_path(value == NULL)) { 1049 goto error; 1050 } 1051 1052 value = nxt_conf_get_object_member(value, &second, NULL); 1053 1054 if (nxt_slow_path(value == NULL)) { 1055 goto error; 1056 } 1057 1058 return NXT_OK; 1059 } 1060 1061 if (nxt_str_eq(&first, "upstreams", 9)) { 1062 1063 if (second.length == 0) { 1064 goto error; 1065 } 1066 1067 value = nxt_conf_get_object_member(vldt->conf, &first, NULL); 1068 1069 if (nxt_slow_path(value == NULL)) { 1070 goto error; 1071 } 1072 1073 value = nxt_conf_get_object_member(value, &second, NULL); 1074 1075 if (nxt_slow_path(value == NULL)) { 1076 goto error; 1077 } 1078 1079 return NXT_OK; 1080 } 1081 1082 if (nxt_str_eq(&first, "routes", 6)) { 1083 value = nxt_conf_get_object_member(vldt->conf, &first, NULL); 1084 1085 if (nxt_slow_path(value == NULL)) { 1086 goto error; 1087 } 1088 1089 if (second.length == 0) { 1090 if (nxt_conf_type(value) != NXT_CONF_ARRAY) { 1091 goto error; 1092 } 1093 1094 return NXT_OK; 1095 } 1096 1097 if (nxt_conf_type(value) != NXT_CONF_OBJECT) { 1098 goto error; 1099 } 1100 1101 value = nxt_conf_get_object_member(value, &second, NULL); 1102 1103 if (nxt_slow_path(value == NULL)) { 1104 goto error; 1105 } 1106 1107 return NXT_OK; 1108 } 1109 1110error: 1111 1112 return nxt_conf_vldt_error(vldt, "Request \"pass\" points to invalid " 1113 "location \"%V\".", &pass); 1114} 1115 1116 1117static nxt_int_t 1118nxt_conf_vldt_proxy(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, 1119 void *data) 1120{ 1121 nxt_str_t name; 1122 nxt_sockaddr_t *sa; 1123 1124 nxt_conf_get_string(value, &name); 1125 1126 if (nxt_str_start(&name, "http://", 7)) { 1127 name.length -= 7; 1128 name.start += 7; 1129 1130 sa = nxt_sockaddr_parse(vldt->pool, &name); 1131 if (sa != NULL) { 1132 return NXT_OK; 1133 } 1134 } 1135 1136 return nxt_conf_vldt_error(vldt, "The \"proxy\" address is invalid \"%V\"", 1137 &name); 1138} 1139 1140 1141static nxt_int_t 1142nxt_conf_vldt_routes(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, 1143 void *data) 1144{ 1145 if (nxt_conf_type(value) == NXT_CONF_ARRAY) { 1146 return nxt_conf_vldt_array_iterator(vldt, value, 1147 &nxt_conf_vldt_route); 1148 } 1149 1150 /* NXT_CONF_OBJECT */ 1151 1152 return nxt_conf_vldt_object_iterator(vldt, value, 1153 &nxt_conf_vldt_routes_member); 1154} 1155 1156 1157static nxt_int_t 1158nxt_conf_vldt_routes_member(nxt_conf_validation_t *vldt, nxt_str_t *name, 1159 nxt_conf_value_t *value) 1160{ 1161 nxt_int_t ret; 1162 1163 ret = nxt_conf_vldt_type(vldt, name, value, NXT_CONF_VLDT_ARRAY); 1164 1165 if (ret != NXT_OK) { 1166 return ret; 1167 } 1168 1169 return nxt_conf_vldt_array_iterator(vldt, value, &nxt_conf_vldt_route); 1170} 1171 1172 1173static nxt_int_t 1174nxt_conf_vldt_route(nxt_conf_validation_t *vldt, nxt_conf_value_t *value) 1175{ 1176 if (nxt_conf_type(value) != NXT_CONF_OBJECT) { 1177 return nxt_conf_vldt_error(vldt, "The \"routes\" array must contain " 1178 "only object values."); 1179 } 1180 1181 return nxt_conf_vldt_object(vldt, value, nxt_conf_vldt_route_members); 1182} 1183 1184 1185static nxt_int_t 1186nxt_conf_vldt_match_patterns(nxt_conf_validation_t *vldt, 1187 nxt_conf_value_t *value, void *data) 1188{ 1189 if (nxt_conf_type(value) == NXT_CONF_ARRAY) { 1190 return nxt_conf_vldt_array_iterator(vldt, value, 1191 &nxt_conf_vldt_match_pattern); 1192 } 1193 1194 /* NXT_CONF_STRING */ 1195 1196 return nxt_conf_vldt_match_pattern(vldt, value); 1197} 1198 1199 1200static nxt_int_t 1201nxt_conf_vldt_match_pattern(nxt_conf_validation_t *vldt, 1202 nxt_conf_value_t *value) 1203{ 1204 u_char ch; 1205 nxt_str_t pattern; 1206 nxt_uint_t i, first, last; 1207 1208 enum { 1209 sw_none, 1210 sw_side, 1211 sw_middle 1212 } state; 1213 1214 if (nxt_conf_type(value) != NXT_CONF_STRING) { 1215 return nxt_conf_vldt_error(vldt, "The \"match\" patterns for \"host\", " 1216 "\"uri\", and \"method\" must be strings."); 1217 } 1218 1219 nxt_conf_get_string(value, &pattern); 1220 1221 if (pattern.length == 0) { 1222 return NXT_OK; 1223 } 1224 1225 first = (pattern.start[0] == '!'); 1226 last = pattern.length - 1; 1227 state = sw_none; 1228 1229 for (i = first; i != pattern.length; i++) { 1230 1231 ch = pattern.start[i]; 1232 1233 if (ch != '*') { 1234 continue; 1235 } 1236 1237 switch (state) { 1238 case sw_none: 1239 state = (i == first) ? sw_side : sw_middle; 1240 break; 1241 1242 case sw_side: 1243 if (i == last) { 1244 if (last - first != 1) { 1245 break; 1246 } 1247 1248 return nxt_conf_vldt_error(vldt, "The \"match\" pattern must " 1249 "not contain double \"*\" markers."); 1250 } 1251 1252 /* Fall through. */ 1253 1254 case sw_middle: 1255 return nxt_conf_vldt_error(vldt, "The \"match\" patterns can " 1256 "either contain \"*\" markers at " 1257 "the sides or only one in the middle."); 1258 } 1259 } 1260 1261 return NXT_OK; 1262} 1263 1264 1265static nxt_int_t 1266nxt_conf_vldt_match_addrs(nxt_conf_validation_t *vldt, 1267 nxt_conf_value_t *value, void *data) 1268{ 1269 if (nxt_conf_type(value) == NXT_CONF_ARRAY) { 1270 return nxt_conf_vldt_array_iterator(vldt, value, 1271 &nxt_conf_vldt_match_addr); 1272 } 1273 1274 return nxt_conf_vldt_match_addr(vldt, value); 1275} 1276 1277 1278static nxt_int_t 1279nxt_conf_vldt_match_addr(nxt_conf_validation_t *vldt, 1280 nxt_conf_value_t *value) 1281{ 1282 nxt_http_route_addr_pattern_t pattern; 1283 1284 switch (nxt_http_route_addr_pattern_parse(vldt->pool, &pattern, value)) { 1285 1286 case NXT_OK: 1287 return NXT_OK; 1288 1289 case NXT_ADDR_PATTERN_PORT_ERROR: 1290 return nxt_conf_vldt_error(vldt, "The \"address\" port an invalid " 1291 "port."); 1292 1293 case NXT_ADDR_PATTERN_CV_TYPE_ERROR: 1294 return nxt_conf_vldt_error(vldt, "The \"match\" pattern for " 1295 "\"address\" must be a string."); 1296 1297 case NXT_ADDR_PATTERN_LENGTH_ERROR: 1298 return nxt_conf_vldt_error(vldt, "The \"address\" is too short."); 1299 1300 case NXT_ADDR_PATTERN_FORMAT_ERROR: 1301 return nxt_conf_vldt_error(vldt, "The \"address\" format is invalid."); 1302 1303 case NXT_ADDR_PATTERN_RANGE_OVERLAP_ERROR: 1304 return nxt_conf_vldt_error(vldt, "The \"address\" range is " 1305 "overlapping."); 1306 1307 case NXT_ADDR_PATTERN_CIDR_ERROR: 1308 return nxt_conf_vldt_error(vldt, "The \"address\" has an invalid CIDR " 1309 "prefix."); 1310 1311 case NXT_ADDR_PATTERN_NO_IPv6_ERROR: 1312 return nxt_conf_vldt_error(vldt, "The \"address\" does not support " 1313 "IPv6 with your configuration."); 1314 1315 default: 1316 return nxt_conf_vldt_error(vldt, "The \"address\" has an unknown " 1317 "format."); 1318 } 1319} 1320 1321 1322static nxt_int_t 1323nxt_conf_vldt_match_scheme_pattern(nxt_conf_validation_t *vldt, 1324 nxt_conf_value_t *value, void *data) 1325{ 1326 nxt_str_t scheme; 1327 1328 static const nxt_str_t http = nxt_string("http"); 1329 static const nxt_str_t https = nxt_string("https"); 1330 1331 nxt_conf_get_string(value, &scheme); 1332 1333 if (nxt_strcasestr_eq(&scheme, &http) 1334 || nxt_strcasestr_eq(&scheme, &https)) 1335 { 1336 return NXT_OK; 1337 } 1338 1339 return nxt_conf_vldt_error(vldt, "The \"scheme\" can either be " 1340 "\"http\" or \"https\"."); 1341} 1342 1343 1344static nxt_int_t 1345nxt_conf_vldt_match_patterns_sets(nxt_conf_validation_t *vldt, 1346 nxt_conf_value_t *value, void *data) 1347{ 1348 if (nxt_conf_type(value) == NXT_CONF_ARRAY) { 1349 return nxt_conf_vldt_array_iterator(vldt, value, 1350 &nxt_conf_vldt_match_patterns_set); 1351 } 1352 1353 /* NXT_CONF_OBJECT */ 1354 1355 return nxt_conf_vldt_match_patterns_set(vldt, value); 1356} 1357 1358 1359static nxt_int_t 1360nxt_conf_vldt_match_patterns_set(nxt_conf_validation_t *vldt, 1361 nxt_conf_value_t *value) 1362{ 1363 if (nxt_conf_type(value) != NXT_CONF_OBJECT) { 1364 return nxt_conf_vldt_error(vldt, "The \"match\" patterns for " 1365 "\"arguments\", \"cookies\", and " 1366 "\"headers\" must be objects."); 1367 } 1368 1369 return nxt_conf_vldt_object_iterator(vldt, value, 1370 &nxt_conf_vldt_match_patterns_set_member); 1371} 1372 1373 1374static nxt_int_t 1375nxt_conf_vldt_match_patterns_set_member(nxt_conf_validation_t *vldt, 1376 nxt_str_t *name, nxt_conf_value_t *value) 1377{ 1378 if (name->length == 0) { 1379 return nxt_conf_vldt_error(vldt, "The \"match\" pattern objects must " 1380 "not contain empty member names."); 1381 } 1382 1383 return nxt_conf_vldt_match_patterns(vldt, value, NULL); 1384} 1385 1386 1387#if (NXT_TLS) 1388 1389static nxt_int_t 1390nxt_conf_vldt_certificate(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, 1391 void *data) 1392{ 1393 nxt_str_t name; 1394 nxt_conf_value_t *cert; 1395 1396 nxt_conf_get_string(value, &name); 1397 1398 cert = nxt_cert_info_get(&name); 1399 1400 if (cert == NULL) { 1401 return nxt_conf_vldt_error(vldt, "Certificate \"%V\" is not found.", 1402 &name); 1403 } 1404 1405 return NXT_OK; 1406} 1407 1408#endif 1409 1410 1411static nxt_int_t 1412nxt_conf_vldt_app_name(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, 1413 void *data) 1414{ 1415 nxt_str_t name; 1416 nxt_conf_value_t *apps, *app; 1417 1418 static nxt_str_t apps_str = nxt_string("applications"); 1419 1420 nxt_conf_get_string(value, &name); 1421 1422 apps = nxt_conf_get_object_member(vldt->conf, &apps_str, NULL); 1423 1424 if (nxt_slow_path(apps == NULL)) { 1425 goto error; 1426 } 1427 1428 app = nxt_conf_get_object_member(apps, &name, NULL); 1429 1430 if (nxt_slow_path(app == NULL)) { 1431 goto error; 1432 } 1433 1434 return NXT_OK; 1435 1436error: 1437 1438 return nxt_conf_vldt_error(vldt, "Listening socket is assigned for " 1439 "a non existing application \"%V\".", 1440 &name); 1441} 1442 1443 1444static nxt_int_t 1445nxt_conf_vldt_app(nxt_conf_validation_t *vldt, nxt_str_t *name, 1446 nxt_conf_value_t *value) 1447{ 1448 nxt_int_t ret; 1449 nxt_str_t type; 1450 nxt_thread_t *thread; 1451 nxt_conf_value_t *type_value; 1452 nxt_app_lang_module_t *lang; 1453 1454 static nxt_str_t type_str = nxt_string("type"); 1455 1456 static void *members[] = { 1457 nxt_conf_vldt_external_members, 1458 nxt_conf_vldt_python_members, 1459 nxt_conf_vldt_php_members, 1460 nxt_conf_vldt_perl_members, 1461 nxt_conf_vldt_ruby_members, 1462 nxt_conf_vldt_java_members, 1463 }; 1464 1465 ret = nxt_conf_vldt_type(vldt, name, value, NXT_CONF_VLDT_OBJECT); 1466 1467 if (ret != NXT_OK) { 1468 return ret; 1469 } 1470 1471 type_value = nxt_conf_get_object_member(value, &type_str, NULL); 1472 1473 if (type_value == NULL) { 1474 return nxt_conf_vldt_error(vldt, 1475 "Application must have the \"type\" property set."); 1476 } 1477 1478 ret = nxt_conf_vldt_type(vldt, &type_str, type_value, NXT_CONF_VLDT_STRING); 1479 1480 if (ret != NXT_OK) { 1481 return ret; 1482 } 1483 1484 nxt_conf_get_string(type_value, &type); 1485 1486 thread = nxt_thread(); 1487 1488 lang = nxt_app_lang_module(thread->runtime, &type); 1489 if (lang == NULL) { 1490 return nxt_conf_vldt_error(vldt, 1491 "The module to run \"%V\" is not found " 1492 "among the available application modules.", 1493 &type); 1494 } 1495 1496 return nxt_conf_vldt_object(vldt, value, members[lang->type]); 1497} 1498 1499 1500static nxt_int_t 1501nxt_conf_vldt_object(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, 1502 void *data) 1503{ 1504 uint32_t index; 1505 nxt_int_t ret; 1506 nxt_str_t name; 1507 nxt_conf_value_t *member; 1508 nxt_conf_vldt_object_t *vals; 1509 1510 index = 0; 1511 1512 for ( ;; ) { 1513 member = nxt_conf_next_object_member(value, &name, &index); 1514 1515 if (member == NULL) { 1516 return NXT_OK; 1517 } 1518 1519 vals = data; 1520 1521 for ( ;; ) { 1522 if (vals->name.length == 0) { 1523 1524 if (vals->data != NULL) { 1525 vals = vals->data; 1526 continue; 1527 } 1528 1529 return nxt_conf_vldt_error(vldt, "Unknown parameter \"%V\".", 1530 &name); 1531 } 1532 1533 if (!nxt_strstr_eq(&vals->name, &name)) { 1534 vals++; 1535 continue; 1536 } 1537 1538 ret = nxt_conf_vldt_type(vldt, &name, member, vals->type); 1539 1540 if (ret != NXT_OK) { 1541 return ret; 1542 } 1543 1544 if (vals->validator != NULL) { 1545 ret = vals->validator(vldt, member, vals->data); 1546 1547 if (ret != NXT_OK) { 1548 return ret; 1549 } 1550 } 1551 1552 break; 1553 } 1554 } 1555} 1556 1557 1558typedef struct { 1559 int64_t spare; 1560 int64_t max; 1561 int64_t idle_timeout; 1562} nxt_conf_vldt_processes_conf_t; 1563 1564 1565static nxt_conf_map_t nxt_conf_vldt_processes_conf_map[] = { 1566 { 1567 nxt_string("spare"), 1568 NXT_CONF_MAP_INT64, 1569 offsetof(nxt_conf_vldt_processes_conf_t, spare), 1570 }, 1571 1572 { 1573 nxt_string("max"), 1574 NXT_CONF_MAP_INT64, 1575 offsetof(nxt_conf_vldt_processes_conf_t, max), 1576 }, 1577 1578 { 1579 nxt_string("idle_timeout"), 1580 NXT_CONF_MAP_INT64, 1581 offsetof(nxt_conf_vldt_processes_conf_t, idle_timeout), 1582 }, 1583}; 1584 1585 1586static nxt_int_t 1587nxt_conf_vldt_processes(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, 1588 void *data) 1589{ 1590 int64_t int_value; 1591 nxt_int_t ret; 1592 nxt_conf_vldt_processes_conf_t proc; 1593 1594 if (nxt_conf_type(value) == NXT_CONF_INTEGER) { 1595 int_value = nxt_conf_get_integer(value); 1596 1597 if (int_value < 1) { 1598 return nxt_conf_vldt_error(vldt, "The \"processes\" number must be " 1599 "equal to or greater than 1."); 1600 } 1601 1602 if (int_value > NXT_INT32_T_MAX) { 1603 return nxt_conf_vldt_error(vldt, "The \"processes\" number must " 1604 "not exceed %d.", NXT_INT32_T_MAX); 1605 } 1606 1607 return NXT_OK; 1608 } 1609 1610 ret = nxt_conf_vldt_object(vldt, value, data); 1611 if (ret != NXT_OK) { 1612 return ret; 1613 } 1614 1615 proc.spare = 0; 1616 proc.max = 1; 1617 proc.idle_timeout = 15; 1618 1619 ret = nxt_conf_map_object(vldt->pool, value, 1620 nxt_conf_vldt_processes_conf_map, 1621 nxt_nitems(nxt_conf_vldt_processes_conf_map), 1622 &proc); 1623 if (ret != NXT_OK) { 1624 return ret; 1625 } 1626 1627 if (proc.spare < 0) { 1628 return nxt_conf_vldt_error(vldt, "The \"spare\" number must not be " 1629 "negative."); 1630 } 1631 1632 if (proc.spare > NXT_INT32_T_MAX) { 1633 return nxt_conf_vldt_error(vldt, "The \"spare\" number must not " 1634 "exceed %d.", NXT_INT32_T_MAX); 1635 } 1636 1637 if (proc.max < 1) { 1638 return nxt_conf_vldt_error(vldt, "The \"max\" number must be equal " 1639 "to or greater than 1."); 1640 } 1641 1642 if (proc.max > NXT_INT32_T_MAX) { 1643 return nxt_conf_vldt_error(vldt, "The \"max\" number must not " 1644 "exceed %d.", NXT_INT32_T_MAX); 1645 } 1646 1647 if (proc.max < proc.spare) { 1648 return nxt_conf_vldt_error(vldt, "The \"spare\" number must be " 1649 "less than or equal to \"max\"."); 1650 } 1651 1652 if (proc.idle_timeout < 0) { 1653 return nxt_conf_vldt_error(vldt, "The \"idle_timeout\" number must not " 1654 "be negative."); 1655 } 1656 1657 if (proc.idle_timeout > NXT_INT32_T_MAX / 1000) { 1658 return nxt_conf_vldt_error(vldt, "The \"idle_timeout\" number must not " 1659 "exceed %d.", NXT_INT32_T_MAX / 1000); 1660 } 1661 1662 return NXT_OK; 1663} 1664 1665 1666static nxt_int_t 1667nxt_conf_vldt_object_iterator(nxt_conf_validation_t *vldt, 1668 nxt_conf_value_t *value, void *data) 1669{ 1670 uint32_t index; 1671 nxt_int_t ret; 1672 nxt_str_t name; 1673 nxt_conf_value_t *member; 1674 nxt_conf_vldt_member_t validator; 1675 1676 validator = (nxt_conf_vldt_member_t) data; 1677 index = 0; 1678 1679 for ( ;; ) { 1680 member = nxt_conf_next_object_member(value, &name, &index); 1681 1682 if (member == NULL) { 1683 return NXT_OK; 1684 } 1685 1686 ret = validator(vldt, &name, member); 1687 1688 if (ret != NXT_OK) { 1689 return ret; 1690 } 1691 } 1692} 1693 1694 1695static nxt_int_t 1696nxt_conf_vldt_array_iterator(nxt_conf_validation_t *vldt, 1697 nxt_conf_value_t *value, void *data) 1698{ 1699 uint32_t index; 1700 nxt_int_t ret; 1701 nxt_conf_value_t *element; 1702 nxt_conf_vldt_element_t validator; 1703 1704 validator = (nxt_conf_vldt_element_t) data; 1705 1706 for (index = 0; /* void */ ; index++) { 1707 element = nxt_conf_get_array_element(value, index); 1708 1709 if (element == NULL) { 1710 return NXT_OK; 1711 } 1712 1713 ret = validator(vldt, element); 1714 1715 if (ret != NXT_OK) { 1716 return ret; 1717 } 1718 } 1719} 1720 1721 1722static nxt_int_t 1723nxt_conf_vldt_environment(nxt_conf_validation_t *vldt, nxt_str_t *name, 1724 nxt_conf_value_t *value) 1725{ 1726 nxt_str_t str; 1727 1728 if (name->length == 0) { 1729 return nxt_conf_vldt_error(vldt, 1730 "The environment name must not be empty."); 1731 } 1732 1733 if (nxt_memchr(name->start, '\0', name->length) != NULL) { 1734 return nxt_conf_vldt_error(vldt, "The environment name must not " 1735 "contain null character."); 1736 } 1737 1738 if (nxt_memchr(name->start, '=', name->length) != NULL) { 1739 return nxt_conf_vldt_error(vldt, "The environment name must not " 1740 "contain '=' character."); 1741 } 1742 1743 if (nxt_conf_type(value) != NXT_CONF_STRING) { 1744 return nxt_conf_vldt_error(vldt, "The \"%V\" environment value must be " 1745 "a string.", name); 1746 } 1747 1748 nxt_conf_get_string(value, &str); 1749 1750 if (nxt_memchr(str.start, '\0', str.length) != NULL) { 1751 return nxt_conf_vldt_error(vldt, "The \"%V\" environment value must " 1752 "not contain null character.", name); 1753 } 1754 1755 return NXT_OK; 1756} 1757 1758 1759static nxt_int_t 1760nxt_conf_vldt_clone_namespaces(nxt_conf_validation_t *vldt, 1761 nxt_conf_value_t *value, void *data) 1762{ 1763 return nxt_conf_vldt_object(vldt, value, data); 1764} 1765 1766 1767static nxt_int_t 1768nxt_conf_vldt_isolation(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, 1769 void *data) 1770{ 1771 return nxt_conf_vldt_object(vldt, value, data); 1772} 1773 1774 1775#if (NXT_HAVE_CLONE_NEWUSER) 1776 1777typedef struct { 1778 nxt_int_t container; 1779 nxt_int_t host; 1780 nxt_int_t size; 1781} nxt_conf_vldt_clone_procmap_conf_t; 1782 1783 1784static nxt_conf_map_t nxt_conf_vldt_clone_procmap_conf_map[] = { 1785 { 1786 nxt_string("container"), 1787 NXT_CONF_MAP_INT32, 1788 offsetof(nxt_conf_vldt_clone_procmap_conf_t, container), 1789 }, 1790 1791 { 1792 nxt_string("host"), 1793 NXT_CONF_MAP_INT32, 1794 offsetof(nxt_conf_vldt_clone_procmap_conf_t, host), 1795 }, 1796 1797 { 1798 nxt_string("size"), 1799 NXT_CONF_MAP_INT32, 1800 offsetof(nxt_conf_vldt_clone_procmap_conf_t, size), 1801 }, 1802 1803}; 1804 1805 1806static nxt_int_t 1807nxt_conf_vldt_clone_procmap(nxt_conf_validation_t *vldt, const char *mapfile, 1808 nxt_conf_value_t *value) 1809{ 1810 nxt_int_t ret; 1811 nxt_conf_vldt_clone_procmap_conf_t procmap; 1812 1813 procmap.container = -1; 1814 procmap.host = -1; 1815 procmap.size = -1; 1816 1817 ret = nxt_conf_map_object(vldt->pool, value, 1818 nxt_conf_vldt_clone_procmap_conf_map, 1819 nxt_nitems(nxt_conf_vldt_clone_procmap_conf_map), 1820 &procmap); 1821 if (ret != NXT_OK) { 1822 return ret; 1823 } 1824 1825 if (procmap.container == -1) { 1826 return nxt_conf_vldt_error(vldt, "The %s requires the " 1827 "\"container\" field set.", mapfile); 1828 } 1829 1830 if (procmap.host == -1) { 1831 return nxt_conf_vldt_error(vldt, "The %s requires the " 1832 "\"host\" field set.", mapfile); 1833 } 1834 1835 if (procmap.size == -1) { 1836 return nxt_conf_vldt_error(vldt, "The %s requires the " 1837 "\"size\" field set.", mapfile); 1838 } 1839 1840 return NXT_OK; 1841} 1842 1843 1844static nxt_int_t 1845nxt_conf_vldt_clone_uidmap(nxt_conf_validation_t *vldt, nxt_conf_value_t *value) 1846{ 1847 nxt_int_t ret; 1848 1849 if (nxt_conf_type(value) != NXT_CONF_OBJECT) { 1850 return nxt_conf_vldt_error(vldt, "The \"uidmap\" array " 1851 "must contain only object values."); 1852 } 1853 1854 ret = nxt_conf_vldt_object(vldt, value, 1855 (void *) nxt_conf_vldt_app_procmap_members); 1856 if (nxt_slow_path(ret != NXT_OK)) { 1857 return ret; 1858 } 1859 1860 return nxt_conf_vldt_clone_procmap(vldt, "uid_map", value); 1861} 1862 1863 1864static nxt_int_t 1865nxt_conf_vldt_clone_gidmap(nxt_conf_validation_t *vldt, nxt_conf_value_t *value) 1866{ 1867 nxt_int_t ret; 1868 1869 if (nxt_conf_type(value) != NXT_CONF_OBJECT) { 1870 return nxt_conf_vldt_error(vldt, "The \"gidmap\" array " 1871 "must contain only object values."); 1872 } 1873 1874 ret = nxt_conf_vldt_object(vldt, value, 1875 (void *) nxt_conf_vldt_app_procmap_members); 1876 if (nxt_slow_path(ret != NXT_OK)) { 1877 return ret; 1878 } 1879 1880 return nxt_conf_vldt_clone_procmap(vldt, "gid_map", value); 1881} 1882 1883#endif 1884 1885 1886static nxt_int_t 1887nxt_conf_vldt_argument(nxt_conf_validation_t *vldt, nxt_conf_value_t *value) 1888{ 1889 nxt_str_t str; 1890 1891 if (nxt_conf_type(value) != NXT_CONF_STRING) { 1892 return nxt_conf_vldt_error(vldt, "The \"arguments\" array " 1893 "must contain only string values."); 1894 } 1895 1896 nxt_conf_get_string(value, &str); 1897 1898 if (nxt_memchr(str.start, '\0', str.length) != NULL) { 1899 return nxt_conf_vldt_error(vldt, "The \"arguments\" array must not " 1900 "contain strings with null character."); 1901 } 1902 1903 return NXT_OK; 1904} 1905 1906 1907static nxt_int_t 1908nxt_conf_vldt_php_option(nxt_conf_validation_t *vldt, nxt_str_t *name, 1909 nxt_conf_value_t *value) 1910{ 1911 if (name->length == 0) { 1912 return nxt_conf_vldt_error(vldt, 1913 "The PHP option name must not be empty."); 1914 } 1915 1916 if (nxt_conf_type(value) != NXT_CONF_STRING) { 1917 return nxt_conf_vldt_error(vldt, "The \"%V\" PHP option must be " 1918 "a string.", name); 1919 } 1920 1921 return NXT_OK; 1922} 1923 1924 1925static nxt_int_t 1926nxt_conf_vldt_java_classpath(nxt_conf_validation_t *vldt, 1927 nxt_conf_value_t *value) 1928{ 1929 nxt_str_t str; 1930 1931 if (nxt_conf_type(value) != NXT_CONF_STRING) { 1932 return nxt_conf_vldt_error(vldt, "The \"classpath\" array " 1933 "must contain only string values."); 1934 } 1935 1936 nxt_conf_get_string(value, &str); 1937 1938 if (nxt_memchr(str.start, '\0', str.length) != NULL) { 1939 return nxt_conf_vldt_error(vldt, "The \"classpath\" array must not " 1940 "contain strings with null character."); 1941 } 1942 1943 return NXT_OK; 1944} 1945 1946 1947static nxt_int_t 1948nxt_conf_vldt_java_option(nxt_conf_validation_t *vldt, nxt_conf_value_t *value) 1949{ 1950 nxt_str_t str; 1951 1952 if (nxt_conf_type(value) != NXT_CONF_STRING) { 1953 return nxt_conf_vldt_error(vldt, "The \"options\" array " 1954 "must contain only string values."); 1955 } 1956 1957 nxt_conf_get_string(value, &str); 1958 1959 if (nxt_memchr(str.start, '\0', str.length) != NULL) { 1960 return nxt_conf_vldt_error(vldt, "The \"options\" array must not " 1961 "contain strings with null character."); 1962 } 1963 1964 return NXT_OK; 1965} 1966 1967 1968static nxt_int_t 1969nxt_conf_vldt_upstream(nxt_conf_validation_t *vldt, nxt_str_t *name, 1970 nxt_conf_value_t *value) 1971{ 1972 nxt_int_t ret; 1973 nxt_conf_value_t *conf; 1974 1975 static nxt_str_t servers = nxt_string("servers"); 1976 1977 ret = nxt_conf_vldt_type(vldt, name, value, NXT_CONF_VLDT_OBJECT); 1978 1979 if (ret != NXT_OK) { 1980 return ret; 1981 } 1982 1983 ret = nxt_conf_vldt_object(vldt, value, nxt_conf_vldt_upstream_members); 1984 1985 if (ret != NXT_OK) { 1986 return ret; 1987 } 1988 1989 conf = nxt_conf_get_object_member(value, &servers, NULL); 1990 if (conf == NULL) { 1991 return nxt_conf_vldt_error(vldt, "The \"%V\" upstream must contain " 1992 "\"servers\" object value.", name); 1993 } 1994 1995 return NXT_OK; 1996} 1997 1998 1999static nxt_int_t 2000nxt_conf_vldt_server(nxt_conf_validation_t *vldt, nxt_str_t *name, 2001 nxt_conf_value_t *value) 2002{ 2003 nxt_int_t ret; 2004 nxt_sockaddr_t *sa; 2005 2006 ret = nxt_conf_vldt_type(vldt, name, value, NXT_CONF_VLDT_OBJECT); 2007 2008 if (ret != NXT_OK) { 2009 return ret; 2010 } 2011 2012 sa = nxt_sockaddr_parse(vldt->pool, name); 2013 2014 if (sa == NULL) { 2015 return nxt_conf_vldt_error(vldt, "The \"%V\" is not valid " 2016 "server address.", name); 2017 } 2018 2019 return nxt_conf_vldt_object(vldt, value, 2020 nxt_conf_vldt_upstream_server_members); 2021} 2022 2023 2024static nxt_int_t 2025nxt_conf_vldt_server_weight(nxt_conf_validation_t *vldt, 2026 nxt_conf_value_t *value, void *data) 2027{ 2028 int64_t int_value; 2029 2030 int_value = nxt_conf_get_integer(value); 2031 2032 if (int_value <= 0) { 2033 return nxt_conf_vldt_error(vldt, "The \"weight\" number must be " 2034 "greater than 0."); 2035 } 2036 2037 if (int_value > NXT_INT32_T_MAX) { 2038 return nxt_conf_vldt_error(vldt, "The \"weight\" number must " 2039 "not exceed %d.", NXT_INT32_T_MAX); 2040 } 2041 2042 return NXT_OK; 2043}
|