1 2 /* 3 * Copyright (C) Valentin V. Bartenev 4 * Copyright (C) NGINX, Inc. 5 */ 6 7 #include <nxt_main.h> 8 #include <nxt_conf.h> 9 #include <nxt_cert.h> 10 #include <nxt_router.h> 11 12 13 typedef enum { 14 NXT_CONF_VLDT_NULL = 1 << NXT_CONF_NULL, 15 NXT_CONF_VLDT_BOOLEAN = 1 << NXT_CONF_BOOLEAN, 16 NXT_CONF_VLDT_INTEGER = 1 << NXT_CONF_INTEGER, 17 NXT_CONF_VLDT_NUMBER = 1 << NXT_CONF_NUMBER, 18 NXT_CONF_VLDT_STRING = 1 << NXT_CONF_STRING, 19 NXT_CONF_VLDT_ARRAY = 1 << NXT_CONF_ARRAY, 20 NXT_CONF_VLDT_OBJECT = 1 << NXT_CONF_OBJECT, 21 } nxt_conf_vldt_type_t; 22 23 24 typedef struct { 25 nxt_str_t name; 26 nxt_conf_vldt_type_t type; 27 nxt_int_t (*validator)(nxt_conf_validation_t *vldt, 28 nxt_conf_value_t *value, void *data); 29 void *data; 30 } nxt_conf_vldt_object_t; 31 32 33 #define NXT_CONF_VLDT_NEXT(f) { nxt_null_string, 0, NULL, (f) } 34 #define NXT_CONF_VLDT_END { nxt_null_string, 0, NULL, NULL } 35 36 37 typedef nxt_int_t (*nxt_conf_vldt_member_t)(nxt_conf_validation_t *vldt, 38 nxt_str_t *name, 39 nxt_conf_value_t *value); 40 typedef nxt_int_t (*nxt_conf_vldt_element_t)(nxt_conf_validation_t *vldt, 41 nxt_conf_value_t *value); 42 typedef nxt_int_t (*nxt_conf_vldt_system_t)(nxt_conf_validation_t *vldt, 43 char *name); 44 45 46 static nxt_int_t nxt_conf_vldt_type(nxt_conf_validation_t *vldt, 47 nxt_str_t *name, nxt_conf_value_t *value, nxt_conf_vldt_type_t type); 48 static nxt_int_t nxt_conf_vldt_error(nxt_conf_validation_t *vldt, 49 const char *fmt, ...); 50 51 static nxt_int_t nxt_conf_vldt_listener(nxt_conf_validation_t *vldt, 52 nxt_str_t *name, nxt_conf_value_t *value); 53 #if (NXT_TLS) 54 static nxt_int_t nxt_conf_vldt_certificate(nxt_conf_validation_t *vldt, 55 nxt_conf_value_t *value, void *data); 56 #endif 57 static nxt_int_t nxt_conf_vldt_pass(nxt_conf_validation_t *vldt, 58 nxt_conf_value_t *value, void *data); 59 static nxt_int_t nxt_conf_vldt_routes(nxt_conf_validation_t *vldt, 60 nxt_conf_value_t *value, void *data); 61 static nxt_int_t nxt_conf_vldt_routes_member(nxt_conf_validation_t *vldt, 62 nxt_str_t *name, nxt_conf_value_t *value); 63 static nxt_int_t nxt_conf_vldt_route(nxt_conf_validation_t *vldt, 64 nxt_conf_value_t *value); 65 static nxt_int_t nxt_conf_vldt_match_patterns(nxt_conf_validation_t *vldt, 66 nxt_conf_value_t *value, void *data); 67 static nxt_int_t nxt_conf_vldt_match_pattern(nxt_conf_validation_t *vldt, 68 nxt_conf_value_t *value); 69 static nxt_int_t nxt_conf_vldt_app_name(nxt_conf_validation_t *vldt, 70 nxt_conf_value_t *value, void *data); 71 static nxt_int_t nxt_conf_vldt_app(nxt_conf_validation_t *vldt, 72 nxt_str_t *name, nxt_conf_value_t *value); 73 static nxt_int_t nxt_conf_vldt_object(nxt_conf_validation_t *vldt, 74 nxt_conf_value_t *value, void *data); 75 static nxt_int_t nxt_conf_vldt_processes(nxt_conf_validation_t *vldt, 76 nxt_conf_value_t *value, void *data); 77 static nxt_int_t nxt_conf_vldt_object_iterator(nxt_conf_validation_t *vldt, 78 nxt_conf_value_t *value, void *data); 79 static nxt_int_t nxt_conf_vldt_array_iterator(nxt_conf_validation_t *vldt, 80 nxt_conf_value_t *value, void *data); 81 static nxt_int_t nxt_conf_vldt_system(nxt_conf_validation_t *vldt, 82 nxt_conf_value_t *value, void *data); 83 static nxt_int_t nxt_conf_vldt_user(nxt_conf_validation_t *vldt, char *name); 84 static nxt_int_t nxt_conf_vldt_group(nxt_conf_validation_t *vldt, char *name); 85 static nxt_int_t nxt_conf_vldt_environment(nxt_conf_validation_t *vldt, 86 nxt_str_t *name, nxt_conf_value_t *value); 87 static nxt_int_t nxt_conf_vldt_argument(nxt_conf_validation_t *vldt, 88 nxt_conf_value_t *value); 89 static nxt_int_t nxt_conf_vldt_php_option(nxt_conf_validation_t *vldt, 90 nxt_str_t *name, nxt_conf_value_t *value); 91 static nxt_int_t nxt_conf_vldt_java_classpath(nxt_conf_validation_t *vldt, 92 nxt_conf_value_t *value); 93 static nxt_int_t nxt_conf_vldt_java_option(nxt_conf_validation_t *vldt, 94 nxt_conf_value_t *value); 95 96 97 static nxt_conf_vldt_object_t nxt_conf_vldt_http_members[] = { 98 { nxt_string("header_read_timeout"), 99 NXT_CONF_VLDT_INTEGER, 100 NULL, 101 NULL }, 102 103 { nxt_string("body_read_timeout"), 104 NXT_CONF_VLDT_INTEGER, 105 NULL, 106 NULL }, 107 108 { nxt_string("send_timeout"), 109 NXT_CONF_VLDT_INTEGER, 110 NULL, 111 NULL }, 112 113 { nxt_string("idle_timeout"), 114 NXT_CONF_VLDT_INTEGER, 115 NULL, 116 NULL }, 117 118 { nxt_string("max_body_size"), 119 NXT_CONF_VLDT_INTEGER, 120 NULL, 121 NULL }, 122 123 NXT_CONF_VLDT_END 124 }; 125 126 127 static nxt_conf_vldt_object_t nxt_conf_vldt_setting_members[] = { 128 { nxt_string("http"), 129 NXT_CONF_VLDT_OBJECT, 130 &nxt_conf_vldt_object, 131 (void *) &nxt_conf_vldt_http_members }, 132 133 NXT_CONF_VLDT_END 134 }; 135 136 137 static nxt_conf_vldt_object_t nxt_conf_vldt_root_members[] = { 138 { nxt_string("settings"), 139 NXT_CONF_VLDT_OBJECT, 140 &nxt_conf_vldt_object, 141 (void *) &nxt_conf_vldt_setting_members }, 142 143 { nxt_string("listeners"), 144 NXT_CONF_VLDT_OBJECT, 145 &nxt_conf_vldt_object_iterator, 146 (void *) &nxt_conf_vldt_listener }, 147 148 { nxt_string("routes"), 149 NXT_CONF_VLDT_ARRAY | NXT_CONF_VLDT_OBJECT, 150 &nxt_conf_vldt_routes, 151 NULL }, 152 153 { nxt_string("applications"), 154 NXT_CONF_VLDT_OBJECT, 155 &nxt_conf_vldt_object_iterator, 156 (void *) &nxt_conf_vldt_app }, 157 158 { nxt_string("access_log"), 159 NXT_CONF_VLDT_STRING, 160 NULL, 161 NULL }, 162 163 NXT_CONF_VLDT_END 164 }; 165 166 167 #if (NXT_TLS) 168 169 static nxt_conf_vldt_object_t nxt_conf_vldt_tls_members[] = { 170 { nxt_string("certificate"), 171 NXT_CONF_VLDT_STRING, 172 &nxt_conf_vldt_certificate, 173 NULL }, 174 175 NXT_CONF_VLDT_END 176 }; 177 178 #endif 179 180 181 static nxt_conf_vldt_object_t nxt_conf_vldt_listener_members[] = { 182 { nxt_string("pass"), 183 NXT_CONF_VLDT_STRING, 184 &nxt_conf_vldt_pass, 185 NULL }, 186 187 { nxt_string("application"), 188 NXT_CONF_VLDT_STRING, 189 &nxt_conf_vldt_app_name, 190 NULL }, 191 192 #if (NXT_TLS) 193 194 { nxt_string("tls"), 195 NXT_CONF_VLDT_OBJECT, 196 &nxt_conf_vldt_object, 197 (void *) &nxt_conf_vldt_tls_members }, 198 199 #endif 200 201 NXT_CONF_VLDT_END 202 }; 203 204 205 static nxt_conf_vldt_object_t nxt_conf_vldt_match_members[] = { 206 { nxt_string("method"), 207 NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY, 208 &nxt_conf_vldt_match_patterns, 209 NULL }, 210 211 { nxt_string("host"), 212 NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY, 213 &nxt_conf_vldt_match_patterns, 214 NULL }, 215 216 { nxt_string("uri"), 217 NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY, 218 &nxt_conf_vldt_match_patterns, 219 NULL }, 220 221 NXT_CONF_VLDT_END 222 }; 223 224 225 static nxt_conf_vldt_object_t nxt_conf_vldt_action_members[] = { 226 { nxt_string("pass"), 227 NXT_CONF_VLDT_STRING, 228 &nxt_conf_vldt_pass, 229 NULL }, 230 231 NXT_CONF_VLDT_END 232 }; 233 234 235 static nxt_conf_vldt_object_t nxt_conf_vldt_route_members[] = { 236 { nxt_string("match"), 237 NXT_CONF_VLDT_OBJECT, 238 &nxt_conf_vldt_object, 239 (void *) &nxt_conf_vldt_match_members }, 240 241 { nxt_string("action"), 242 NXT_CONF_VLDT_OBJECT, 243 &nxt_conf_vldt_object, 244 (void *) &nxt_conf_vldt_action_members }, 245 246 NXT_CONF_VLDT_END 247 }; 248 249 250 static nxt_conf_vldt_object_t nxt_conf_vldt_app_limits_members[] = { 251 { nxt_string("timeout"), 252 NXT_CONF_VLDT_INTEGER, 253 NULL, 254 NULL }, 255 256 { nxt_string("reschedule_timeout"), 257 NXT_CONF_VLDT_INTEGER, 258 NULL, 259 NULL }, 260 261 { nxt_string("requests"), 262 NXT_CONF_VLDT_INTEGER, 263 NULL, 264 NULL }, 265 266 NXT_CONF_VLDT_END 267 }; 268 269 270 static nxt_conf_vldt_object_t nxt_conf_vldt_app_processes_members[] = { 271 { nxt_string("spare"), 272 NXT_CONF_VLDT_INTEGER, 273 NULL, 274 NULL }, 275 276 { nxt_string("max"), 277 NXT_CONF_VLDT_INTEGER, 278 NULL, 279 NULL }, 280 281 { nxt_string("idle_timeout"), 282 NXT_CONF_VLDT_INTEGER, 283 NULL, 284 NULL }, 285 286 NXT_CONF_VLDT_END 287 }; 288 289 290 static nxt_conf_vldt_object_t nxt_conf_vldt_common_members[] = { 291 { nxt_string("type"), 292 NXT_CONF_VLDT_STRING, 293 NULL, 294 NULL }, 295 296 { nxt_string("limits"), 297 NXT_CONF_VLDT_OBJECT, 298 &nxt_conf_vldt_object, 299 (void *) &nxt_conf_vldt_app_limits_members }, 300 301 { nxt_string("processes"), 302 NXT_CONF_VLDT_INTEGER | NXT_CONF_VLDT_OBJECT, 303 &nxt_conf_vldt_processes, 304 (void *) &nxt_conf_vldt_app_processes_members }, 305 306 { nxt_string("user"), 307 NXT_CONF_VLDT_STRING, 308 nxt_conf_vldt_system, 309 (void *) &nxt_conf_vldt_user }, 310 311 { nxt_string("group"), 312 NXT_CONF_VLDT_STRING, 313 nxt_conf_vldt_system, 314 (void *) &nxt_conf_vldt_group }, 315 316 { nxt_string("working_directory"), 317 NXT_CONF_VLDT_STRING, 318 NULL, 319 NULL }, 320 321 { nxt_string("environment"), 322 NXT_CONF_VLDT_OBJECT, 323 &nxt_conf_vldt_object_iterator, 324 (void *) &nxt_conf_vldt_environment }, 325 326 NXT_CONF_VLDT_END 327 }; 328 329 330 static nxt_conf_vldt_object_t nxt_conf_vldt_external_members[] = { 331 { nxt_string("executable"), 332 NXT_CONF_VLDT_STRING, 333 NULL, 334 NULL }, 335 336 { nxt_string("arguments"), 337 NXT_CONF_VLDT_ARRAY, 338 &nxt_conf_vldt_array_iterator, 339 (void *) &nxt_conf_vldt_argument }, 340 341 NXT_CONF_VLDT_NEXT(&nxt_conf_vldt_common_members) 342 }; 343 344 345 static nxt_conf_vldt_object_t nxt_conf_vldt_python_members[] = { 346 { nxt_string("home"), 347 NXT_CONF_VLDT_STRING, 348 NULL, 349 NULL }, 350 351 { nxt_string("path"), 352 NXT_CONF_VLDT_STRING, 353 NULL, 354 NULL }, 355 356 { nxt_string("module"), 357 NXT_CONF_VLDT_STRING, 358 NULL, 359 NULL }, 360 361 NXT_CONF_VLDT_NEXT(&nxt_conf_vldt_common_members) 362 }; 363 364 365 static nxt_conf_vldt_object_t nxt_conf_vldt_php_options_members[] = { 366 { nxt_string("file"), 367 NXT_CONF_VLDT_STRING, 368 NULL, 369 NULL }, 370 371 { nxt_string("admin"), 372 NXT_CONF_VLDT_OBJECT, 373 &nxt_conf_vldt_object_iterator, 374 (void *) &nxt_conf_vldt_php_option }, 375 376 { nxt_string("user"), 377 NXT_CONF_VLDT_OBJECT, 378 &nxt_conf_vldt_object_iterator, 379 (void *) &nxt_conf_vldt_php_option }, 380 381 NXT_CONF_VLDT_END 382 }; 383 384 385 static nxt_conf_vldt_object_t nxt_conf_vldt_php_members[] = { 386 { nxt_string("root"), 387 NXT_CONF_VLDT_STRING, 388 NULL, 389 NULL }, 390 391 { nxt_string("script"), 392 NXT_CONF_VLDT_STRING, 393 NULL, 394 NULL }, 395 396 { nxt_string("index"), 397 NXT_CONF_VLDT_STRING, 398 NULL, 399 NULL }, 400 401 { nxt_string("options"), 402 NXT_CONF_VLDT_OBJECT, 403 &nxt_conf_vldt_object, 404 (void *) &nxt_conf_vldt_php_options_members }, 405 406 NXT_CONF_VLDT_NEXT(&nxt_conf_vldt_common_members) 407 }; 408 409 410 static nxt_conf_vldt_object_t nxt_conf_vldt_perl_members[] = { 411 { nxt_string("script"), 412 NXT_CONF_VLDT_STRING, 413 NULL, 414 NULL }, 415 416 NXT_CONF_VLDT_NEXT(&nxt_conf_vldt_common_members) 417 }; 418 419 420 static nxt_conf_vldt_object_t nxt_conf_vldt_ruby_members[] = { 421 { nxt_string("script"), 422 NXT_CONF_VLDT_STRING, 423 NULL, 424 NULL }, 425 426 NXT_CONF_VLDT_NEXT(&nxt_conf_vldt_common_members) 427 }; 428 429 430 static nxt_conf_vldt_object_t nxt_conf_vldt_java_members[] = { 431 { nxt_string("classpath"), 432 NXT_CONF_VLDT_ARRAY, 433 &nxt_conf_vldt_array_iterator, 434 (void *) &nxt_conf_vldt_java_classpath}, 435 436 { nxt_string("webapp"), 437 NXT_CONF_VLDT_STRING, 438 NULL, 439 NULL }, 440 441 { nxt_string("options"), 442 NXT_CONF_VLDT_ARRAY, 443 &nxt_conf_vldt_array_iterator, 444 (void *) &nxt_conf_vldt_java_option}, 445 446 { nxt_string("unit_jars"), 447 NXT_CONF_VLDT_STRING, 448 NULL, 449 NULL }, 450 451 NXT_CONF_VLDT_NEXT(&nxt_conf_vldt_common_members) 452 }; 453 454 455 nxt_int_t 456 nxt_conf_validate(nxt_conf_validation_t *vldt) 457 { 458 nxt_int_t ret; 459 460 ret = nxt_conf_vldt_type(vldt, NULL, vldt->conf, NXT_CONF_VLDT_OBJECT); 461 462 if (ret != NXT_OK) { 463 return ret; 464 } 465 466 return nxt_conf_vldt_object(vldt, vldt->conf, nxt_conf_vldt_root_members); 467 } 468 469 470 #define NXT_CONF_VLDT_ANY_TYPE \ 471 "either a null, a boolean, an integer, " \ 472 "a number, a string, an array, or an object" 473 474 475 static nxt_int_t 476 nxt_conf_vldt_type(nxt_conf_validation_t *vldt, nxt_str_t *name, 477 nxt_conf_value_t *value, nxt_conf_vldt_type_t type) 478 { 479 u_char *p; 480 nxt_str_t expected; 481 nxt_bool_t serial; 482 nxt_uint_t value_type, n, t; 483 u_char buf[nxt_length(NXT_CONF_VLDT_ANY_TYPE)]; 484 485 static nxt_str_t type_name[] = { 486 nxt_string("a null"), 487 nxt_string("a boolean"), 488 nxt_string("an integer"), 489 nxt_string("a number"), 490 nxt_string("a string"), 491 nxt_string("an array"), 492 nxt_string("an object"), 493 }; 494 495 value_type = nxt_conf_type(value); 496 497 if ((1 << value_type) & type) { 498 return NXT_OK; 499 } 500 501 p = buf; 502 503 n = nxt_popcount(type); 504 505 if (n > 1) { 506 p = nxt_cpymem(p, "either ", 7); 507 } 508 509 serial = (n > 2); 510 511 for ( ;; ) { 512 t = __builtin_ffs(type) - 1; 513 514 p = nxt_cpymem(p, type_name[t].start, type_name[t].length); 515 516 n--; 517 518 if (n == 0) { 519 break; 520 } 521 522 if (n > 1 || serial) { 523 *p++ = ','; 524 } 525 526 if (n == 1) { 527 p = nxt_cpymem(p, " or", 3); 528 } 529 530 *p++ = ' '; 531 532 type = type & ~(1 << t); 533 } 534 535 expected.length = p - buf; 536 expected.start = buf; 537 538 if (name == NULL) { 539 return nxt_conf_vldt_error(vldt, 540 "The configuration must be %V, but not %V.", 541 &expected, &type_name[value_type]); 542 } 543 544 return nxt_conf_vldt_error(vldt, 545 "The \"%V\" value must be %V, but not %V.", 546 name, &expected, &type_name[value_type]); 547 } 548 549 550 static nxt_int_t 551 nxt_conf_vldt_error(nxt_conf_validation_t *vldt, const char *fmt, ...) 552 { 553 u_char *p, *end; 554 size_t size; 555 va_list args; 556 u_char error[NXT_MAX_ERROR_STR]; 557 558 va_start(args, fmt); 559 end = nxt_vsprintf(error, error + NXT_MAX_ERROR_STR, fmt, args); 560 va_end(args); 561 562 size = end - error; 563 564 p = nxt_mp_nget(vldt->pool, size); 565 if (p == NULL) { 566 return NXT_ERROR; 567 } 568 569 nxt_memcpy(p, error, size); 570 571 vldt->error.length = size; 572 vldt->error.start = p; 573 574 return NXT_DECLINED; 575 } 576 577 578 static nxt_int_t 579 nxt_conf_vldt_listener(nxt_conf_validation_t *vldt, nxt_str_t *name, 580 nxt_conf_value_t *value) 581 { 582 nxt_int_t ret; 583 584 ret = nxt_conf_vldt_type(vldt, name, value, NXT_CONF_VLDT_OBJECT); 585 586 if (ret != NXT_OK) { 587 return ret; 588 } 589 590 return nxt_conf_vldt_object(vldt, value, nxt_conf_vldt_listener_members); 591 } 592 593 594 static nxt_int_t 595 nxt_conf_vldt_pass(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, 596 void *data) 597 { 598 u_char *p; 599 nxt_str_t pass, first, second; 600 601 nxt_conf_get_string(value, &pass); 602 603 p = nxt_memchr(pass.start, '/', pass.length); 604 605 if (p != NULL) { 606 first.length = p - pass.start; 607 first.start = pass.start; 608 609 if (pass.length - first.length == 1) { 610 goto error; 611 } 612 613 second.length = pass.length - first.length - 1; 614 second.start = p + 1; 615 616 } else { 617 first = pass; 618 second.length = 0; 619 } 620 621 if (nxt_str_eq(&first, "applications", 12)) { 622 623 if (second.length == 0) { 624 goto error; 625 } 626 627 value = nxt_conf_get_object_member(vldt->conf, &first, NULL); 628 629 if (nxt_slow_path(value == NULL)) { 630 goto error; 631 } 632 633 value = nxt_conf_get_object_member(value, &second, NULL); 634 635 if (nxt_slow_path(value == NULL)) { 636 goto error; 637 } 638 639 return NXT_OK; 640 } 641 642 if (nxt_str_eq(&first, "routes", 6)) { 643 value = nxt_conf_get_object_member(vldt->conf, &first, NULL); 644 645 if (nxt_slow_path(value == NULL)) { 646 goto error; 647 } 648 649 if (second.length == 0) { 650 if (nxt_conf_type(value) != NXT_CONF_ARRAY) { 651 goto error; 652 } 653 654 return NXT_OK; 655 } 656 657 if (nxt_conf_type(value) != NXT_CONF_OBJECT) { 658 goto error; 659 } 660 661 value = nxt_conf_get_object_member(value, &second, NULL); 662 663 if (nxt_slow_path(value == NULL)) { 664 goto error; 665 } 666 667 return NXT_OK; 668 } 669 670 error: 671 672 return nxt_conf_vldt_error(vldt, "Request \"pass\" points to invalid " 673 "location \"%V\".", &pass); 674 } 675 676 677 static nxt_int_t 678 nxt_conf_vldt_routes(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, 679 void *data) 680 { 681 if (nxt_conf_type(value) == NXT_CONF_ARRAY) { 682 return nxt_conf_vldt_array_iterator(vldt, value, 683 &nxt_conf_vldt_route); 684 } 685 686 /* NXT_CONF_OBJECT */ 687 688 return nxt_conf_vldt_object_iterator(vldt, value, 689 &nxt_conf_vldt_routes_member); 690 } 691 692 693 static nxt_int_t 694 nxt_conf_vldt_routes_member(nxt_conf_validation_t *vldt, nxt_str_t *name, 695 nxt_conf_value_t *value) 696 { 697 nxt_int_t ret; 698 699 ret = nxt_conf_vldt_type(vldt, name, value, NXT_CONF_VLDT_ARRAY); 700 701 if (ret != NXT_OK) { 702 return ret; 703 } 704 705 return nxt_conf_vldt_array_iterator(vldt, value, &nxt_conf_vldt_route); 706 } 707 708 709 static nxt_int_t 710 nxt_conf_vldt_route(nxt_conf_validation_t *vldt, nxt_conf_value_t *value) 711 { 712 if (nxt_conf_type(value) != NXT_CONF_OBJECT) { 713 return nxt_conf_vldt_error(vldt, "The \"routes\" array must contain " 714 "only object values."); 715 } 716 717 return nxt_conf_vldt_object(vldt, value, nxt_conf_vldt_route_members); 718 } 719 720 721 static nxt_int_t 722 nxt_conf_vldt_match_patterns(nxt_conf_validation_t *vldt, 723 nxt_conf_value_t *value, void *data) 724 { 725 if (nxt_conf_type(value) == NXT_CONF_ARRAY) { 726 return nxt_conf_vldt_array_iterator(vldt, value, 727 &nxt_conf_vldt_match_pattern); 728 } 729 730 /* NXT_CONF_STRING */ 731 732 return nxt_conf_vldt_match_pattern(vldt, value); 733 } 734 735 736 static nxt_int_t 737 nxt_conf_vldt_match_pattern(nxt_conf_validation_t *vldt, 738 nxt_conf_value_t *value) 739 { 740 u_char ch; 741 nxt_str_t pattern; 742 nxt_uint_t i, first, last; 743 744 if (nxt_conf_type(value) != NXT_CONF_STRING) { 745 return nxt_conf_vldt_error(vldt, 746 "The \"match\" patterns must be strings."); 747 } 748 749 nxt_conf_get_string(value, &pattern); 750 751 if (pattern.length == 0) { 752 return NXT_OK; 753 } 754 755 first = (pattern.start[0] == '!'); 756 last = pattern.length - 1; 757 758 for (i = first; i != pattern.length; i++) { 759 ch = pattern.start[i]; 760 761 if (ch != '*') { 762 continue; 763 } 764 765 if (i != first && i != last) { 766 return nxt_conf_vldt_error(vldt, "The \"match\" patterns can only " 767 "contain \"*\" markers at the sides."); 768 } 769 } 770 771 return NXT_OK; 772 } 773 774 775 #if (NXT_TLS) 776 777 static nxt_int_t 778 nxt_conf_vldt_certificate(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, 779 void *data) 780 { 781 nxt_str_t name; 782 nxt_conf_value_t *cert; 783 784 nxt_conf_get_string(value, &name); 785 786 cert = nxt_cert_info_get(&name); 787 788 if (cert == NULL) { 789 return nxt_conf_vldt_error(vldt, "Certificate \"%V\" is not found.", 790 &name); 791 } 792 793 return NXT_OK; 794 } 795 796 #endif 797 798 799 static nxt_int_t 800 nxt_conf_vldt_app_name(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, 801 void *data) 802 { 803 nxt_str_t name; 804 nxt_conf_value_t *apps, *app; 805 806 static nxt_str_t apps_str = nxt_string("applications"); 807 808 nxt_conf_get_string(value, &name); 809 810 apps = nxt_conf_get_object_member(vldt->conf, &apps_str, NULL); 811 812 if (nxt_slow_path(apps == NULL)) { 813 goto error; 814 } 815 816 app = nxt_conf_get_object_member(apps, &name, NULL); 817 818 if (nxt_slow_path(app == NULL)) { 819 goto error; 820 } 821 822 return NXT_OK; 823 824 error: 825 826 return nxt_conf_vldt_error(vldt, "Listening socket is assigned for " 827 "a non existing application \"%V\".", 828 &name); 829 } 830 831 832 static nxt_int_t 833 nxt_conf_vldt_app(nxt_conf_validation_t *vldt, nxt_str_t *name, 834 nxt_conf_value_t *value) 835 { 836 nxt_int_t ret; 837 nxt_str_t type; 838 nxt_thread_t *thread; 839 nxt_conf_value_t *type_value; 840 nxt_app_lang_module_t *lang; 841 842 static nxt_str_t type_str = nxt_string("type"); 843 844 static void *members[] = { 845 nxt_conf_vldt_external_members, 846 nxt_conf_vldt_python_members, 847 nxt_conf_vldt_php_members, 848 nxt_conf_vldt_perl_members, 849 nxt_conf_vldt_ruby_members, 850 nxt_conf_vldt_java_members, 851 }; 852 853 ret = nxt_conf_vldt_type(vldt, name, value, NXT_CONF_VLDT_OBJECT); 854 855 if (ret != NXT_OK) { 856 return ret; 857 } 858 859 type_value = nxt_conf_get_object_member(value, &type_str, NULL); 860 861 if (type_value == NULL) { 862 return nxt_conf_vldt_error(vldt, 863 "Application must have the \"type\" property set."); 864 } 865 866 ret = nxt_conf_vldt_type(vldt, &type_str, type_value, NXT_CONF_VLDT_STRING); 867 868 if (ret != NXT_OK) { 869 return ret; 870 } 871 872 nxt_conf_get_string(type_value, &type); 873 874 thread = nxt_thread(); 875 876 lang = nxt_app_lang_module(thread->runtime, &type); 877 if (lang == NULL) { 878 return nxt_conf_vldt_error(vldt, 879 "The module to run \"%V\" is not found " 880 "among the available application modules.", 881 &type); 882 } 883 884 return nxt_conf_vldt_object(vldt, value, members[lang->type]); 885 } 886 887 888 static nxt_int_t 889 nxt_conf_vldt_object(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, 890 void *data) 891 { 892 uint32_t index; 893 nxt_int_t ret; 894 nxt_str_t name; 895 nxt_conf_value_t *member; 896 nxt_conf_vldt_object_t *vals; 897 898 index = 0; 899 900 for ( ;; ) { 901 member = nxt_conf_next_object_member(value, &name, &index); 902 903 if (member == NULL) { 904 return NXT_OK; 905 } 906 907 vals = data; 908 909 for ( ;; ) { 910 if (vals->name.length == 0) { 911 912 if (vals->data != NULL) { 913 vals = vals->data; 914 continue; 915 } 916 917 return nxt_conf_vldt_error(vldt, "Unknown parameter \"%V\".", 918 &name); 919 } 920 921 if (!nxt_strstr_eq(&vals->name, &name)) { 922 vals++; 923 continue; 924 } 925 926 ret = nxt_conf_vldt_type(vldt, &name, member, vals->type); 927 928 if (ret != NXT_OK) { 929 return ret; 930 } 931 932 if (vals->validator != NULL) { 933 ret = vals->validator(vldt, member, vals->data); 934 935 if (ret != NXT_OK) { 936 return ret; 937 } 938 } 939 940 break; 941 } 942 } 943 } 944 945 946 typedef struct { 947 int64_t spare; 948 int64_t max; 949 int64_t idle_timeout; 950 } nxt_conf_vldt_processes_conf_t; 951 952 953 static nxt_conf_map_t nxt_conf_vldt_processes_conf_map[] = { 954 { 955 nxt_string("spare"), 956 NXT_CONF_MAP_INT64, 957 offsetof(nxt_conf_vldt_processes_conf_t, spare), 958 }, 959 960 { 961 nxt_string("max"), 962 NXT_CONF_MAP_INT64, 963 offsetof(nxt_conf_vldt_processes_conf_t, max), 964 }, 965 966 { 967 nxt_string("idle_timeout"), 968 NXT_CONF_MAP_INT64, 969 offsetof(nxt_conf_vldt_processes_conf_t, idle_timeout), 970 }, 971 }; 972 973 974 static nxt_int_t 975 nxt_conf_vldt_processes(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, 976 void *data) 977 { 978 int64_t int_value; 979 nxt_int_t ret; 980 nxt_conf_vldt_processes_conf_t proc; 981 982 if (nxt_conf_type(value) == NXT_CONF_INTEGER) { 983 int_value = nxt_conf_get_integer(value); 984 985 if (int_value < 1) { 986 return nxt_conf_vldt_error(vldt, "The \"processes\" number must be " 987 "equal to or greater than 1."); 988 } 989 990 if (int_value > NXT_INT32_T_MAX) { 991 return nxt_conf_vldt_error(vldt, "The \"processes\" number must " 992 "not exceed %d.", NXT_INT32_T_MAX); 993 } 994 995 return NXT_OK; 996 } 997 998 ret = nxt_conf_vldt_object(vldt, value, data); 999 if (ret != NXT_OK) { 1000 return ret; 1001 } 1002 1003 proc.spare = 0; 1004 proc.max = 1; 1005 proc.idle_timeout = 15; 1006 1007 ret = nxt_conf_map_object(vldt->pool, value, 1008 nxt_conf_vldt_processes_conf_map, 1009 nxt_nitems(nxt_conf_vldt_processes_conf_map), 1010 &proc); 1011 if (ret != NXT_OK) { 1012 return ret; 1013 } 1014 1015 if (proc.spare < 0) { 1016 return nxt_conf_vldt_error(vldt, "The \"spare\" number must not be " 1017 "negative."); 1018 } 1019 1020 if (proc.spare > NXT_INT32_T_MAX) { 1021 return nxt_conf_vldt_error(vldt, "The \"spare\" number must not " 1022 "exceed %d.", NXT_INT32_T_MAX); 1023 } 1024 1025 if (proc.max < 1) { 1026 return nxt_conf_vldt_error(vldt, "The \"max\" number must be equal " 1027 "to or greater than 1."); 1028 } 1029 1030 if (proc.max > NXT_INT32_T_MAX) { 1031 return nxt_conf_vldt_error(vldt, "The \"max\" number must not " 1032 "exceed %d.", NXT_INT32_T_MAX); 1033 } 1034 1035 if (proc.max < proc.spare) { 1036 return nxt_conf_vldt_error(vldt, "The \"spare\" number must be " 1037 "less than or equal to \"max\"."); 1038 } 1039 1040 if (proc.idle_timeout < 0) { 1041 return nxt_conf_vldt_error(vldt, "The \"idle_timeout\" number must not " 1042 "be negative."); 1043 } 1044 1045 if (proc.idle_timeout > NXT_INT32_T_MAX / 1000) { 1046 return nxt_conf_vldt_error(vldt, "The \"idle_timeout\" number must not " 1047 "exceed %d.", NXT_INT32_T_MAX / 1000); 1048 } 1049 1050 return NXT_OK; 1051 } 1052 1053 1054 static nxt_int_t 1055 nxt_conf_vldt_object_iterator(nxt_conf_validation_t *vldt, 1056 nxt_conf_value_t *value, void *data) 1057 { 1058 uint32_t index; 1059 nxt_int_t ret; 1060 nxt_str_t name; 1061 nxt_conf_value_t *member; 1062 nxt_conf_vldt_member_t validator; 1063 1064 validator = (nxt_conf_vldt_member_t) data; 1065 index = 0; 1066 1067 for ( ;; ) { 1068 member = nxt_conf_next_object_member(value, &name, &index); 1069 1070 if (member == NULL) { 1071 return NXT_OK; 1072 } 1073 1074 ret = validator(vldt, &name, member); 1075 1076 if (ret != NXT_OK) { 1077 return ret; 1078 } 1079 } 1080 } 1081 1082 1083 static nxt_int_t 1084 nxt_conf_vldt_array_iterator(nxt_conf_validation_t *vldt, 1085 nxt_conf_value_t *value, void *data) 1086 { 1087 uint32_t index; 1088 nxt_int_t ret; 1089 nxt_conf_value_t *element; 1090 nxt_conf_vldt_element_t validator; 1091 1092 validator = (nxt_conf_vldt_element_t) data; 1093 1094 for (index = 0; /* void */ ; index++) { 1095 element = nxt_conf_get_array_element(value, index); 1096 1097 if (element == NULL) { 1098 return NXT_OK; 1099 } 1100 1101 ret = validator(vldt, element); 1102 1103 if (ret != NXT_OK) { 1104 return ret; 1105 } 1106 } 1107 } 1108 1109 1110 static nxt_int_t 1111 nxt_conf_vldt_system(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, 1112 void *data) 1113 { 1114 size_t length; 1115 nxt_str_t name; 1116 nxt_conf_vldt_system_t validator; 1117 char string[32]; 1118 1119 /* The cast is required by Sun C. */ 1120 validator = (nxt_conf_vldt_system_t) data; 1121 1122 nxt_conf_get_string(value, &name); 1123 1124 length = name.length + 1; 1125 length = nxt_min(length, sizeof(string)); 1126 1127 nxt_cpystrn((u_char *) string, name.start, length); 1128 1129 return validator(vldt, string); 1130 } 1131 1132 1133 static nxt_int_t 1134 nxt_conf_vldt_user(nxt_conf_validation_t *vldt, char *user) 1135 { 1136 struct passwd *pwd; 1137 1138 nxt_errno = 0; 1139 1140 pwd = getpwnam(user); 1141 1142 if (pwd != NULL) { 1143 return NXT_OK; 1144 } 1145 1146 if (nxt_errno == 0) { 1147 return nxt_conf_vldt_error(vldt, "User \"%s\" is not found.", user); 1148 } 1149 1150 return NXT_ERROR; 1151 } 1152 1153 1154 static nxt_int_t 1155 nxt_conf_vldt_group(nxt_conf_validation_t *vldt, char *group) 1156 { 1157 struct group *grp; 1158 1159 nxt_errno = 0; 1160 1161 grp = getgrnam(group); 1162 1163 if (grp != NULL) { 1164 return NXT_OK; 1165 } 1166 1167 if (nxt_errno == 0) { 1168 return nxt_conf_vldt_error(vldt, "Group \"%s\" is not found.", group); 1169 } 1170 1171 return NXT_ERROR; 1172 } 1173 1174 1175 static nxt_int_t 1176 nxt_conf_vldt_environment(nxt_conf_validation_t *vldt, nxt_str_t *name, 1177 nxt_conf_value_t *value) 1178 { 1179 nxt_str_t str; 1180 1181 if (name->length == 0) { 1182 return nxt_conf_vldt_error(vldt, 1183 "The environment name must not be empty."); 1184 } 1185 1186 if (nxt_memchr(name->start, '\0', name->length) != NULL) { 1187 return nxt_conf_vldt_error(vldt, "The environment name must not " 1188 "contain null character."); 1189 } 1190 1191 if (nxt_memchr(name->start, '=', name->length) != NULL) { 1192 return nxt_conf_vldt_error(vldt, "The environment name must not " 1193 "contain '=' character."); 1194 } 1195 1196 if (nxt_conf_type(value) != NXT_CONF_STRING) { 1197 return nxt_conf_vldt_error(vldt, "The \"%V\" environment value must be " 1198 "a string.", name); 1199 } 1200 1201 nxt_conf_get_string(value, &str); 1202 1203 if (nxt_memchr(str.start, '\0', str.length) != NULL) { 1204 return nxt_conf_vldt_error(vldt, "The \"%V\" environment value must " 1205 "not contain null character.", name); 1206 } 1207 1208 return NXT_OK; 1209 } 1210 1211 1212 static nxt_int_t 1213 nxt_conf_vldt_argument(nxt_conf_validation_t *vldt, nxt_conf_value_t *value) 1214 { 1215 nxt_str_t str; 1216 1217 if (nxt_conf_type(value) != NXT_CONF_STRING) { 1218 return nxt_conf_vldt_error(vldt, "The \"arguments\" array " 1219 "must contain only string values."); 1220 } 1221 1222 nxt_conf_get_string(value, &str); 1223 1224 if (nxt_memchr(str.start, '\0', str.length) != NULL) { 1225 return nxt_conf_vldt_error(vldt, "The \"arguments\" array must not " 1226 "contain strings with null character."); 1227 } 1228 1229 return NXT_OK; 1230 } 1231 1232 1233 static nxt_int_t 1234 nxt_conf_vldt_php_option(nxt_conf_validation_t *vldt, nxt_str_t *name, 1235 nxt_conf_value_t *value) 1236 { 1237 if (name->length == 0) { 1238 return nxt_conf_vldt_error(vldt, 1239 "The PHP option name must not be empty."); 1240 } 1241 1242 if (nxt_conf_type(value) != NXT_CONF_STRING) { 1243 return nxt_conf_vldt_error(vldt, "The \"%V\" PHP option must be " 1244 "a string.", name); 1245 } 1246 1247 return NXT_OK; 1248 } 1249 1250 1251 static nxt_int_t 1252 nxt_conf_vldt_java_classpath(nxt_conf_validation_t *vldt, nxt_conf_value_t *value) 1253 { 1254 nxt_str_t str; 1255 1256 if (nxt_conf_type(value) != NXT_CONF_STRING) { 1257 return nxt_conf_vldt_error(vldt, "The \"classpath\" array " 1258 "must contain only string values."); 1259 } 1260 1261 nxt_conf_get_string(value, &str); 1262 1263 if (nxt_memchr(str.start, '\0', str.length) != NULL) { 1264 return nxt_conf_vldt_error(vldt, "The \"classpath\" array must not " 1265 "contain strings with null character."); 1266 } 1267 1268 return NXT_OK; 1269 } 1270 1271 static nxt_int_t 1272 nxt_conf_vldt_java_option(nxt_conf_validation_t *vldt, nxt_conf_value_t *value) 1273 { 1274 nxt_str_t str; 1275 1276 if (nxt_conf_type(value) != NXT_CONF_STRING) { 1277 return nxt_conf_vldt_error(vldt, "The \"options\" array " 1278 "must contain only string values."); 1279 } 1280 1281 nxt_conf_get_string(value, &str); 1282 1283 if (nxt_memchr(str.start, '\0', str.length) != NULL) { 1284 return nxt_conf_vldt_error(vldt, "The \"options\" array must not " 1285 "contain strings with null character."); 1286 } 1287 1288 return NXT_OK; 1289 } 1290