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