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 #include <nxt_http.h> 12 #include <nxt_sockaddr.h> 13 #include <nxt_http_route_addr.h> 14 #include <nxt_regex.h> 15 16 17 typedef enum { 18 NXT_CONF_VLDT_NULL = 1 << NXT_CONF_NULL, 19 NXT_CONF_VLDT_BOOLEAN = 1 << NXT_CONF_BOOLEAN, 20 NXT_CONF_VLDT_INTEGER = 1 << NXT_CONF_INTEGER, 21 NXT_CONF_VLDT_NUMBER = (1 << NXT_CONF_NUMBER) | NXT_CONF_VLDT_INTEGER, 22 NXT_CONF_VLDT_STRING = 1 << NXT_CONF_STRING, 23 NXT_CONF_VLDT_ARRAY = 1 << NXT_CONF_ARRAY, 24 NXT_CONF_VLDT_OBJECT = 1 << NXT_CONF_OBJECT, 25 } nxt_conf_vldt_type_t; 26 27 #define NXT_CONF_VLDT_ANY_TYPE (NXT_CONF_VLDT_NULL \ 28 |NXT_CONF_VLDT_BOOLEAN \ 29 |NXT_CONF_VLDT_NUMBER \ 30 |NXT_CONF_VLDT_STRING \ 31 |NXT_CONF_VLDT_ARRAY \ 32 |NXT_CONF_VLDT_OBJECT) 33 34 35 typedef enum { 36 NXT_CONF_VLDT_REQUIRED = 1, 37 } nxt_conf_vldt_flags_t; 38 39 40 typedef nxt_int_t (*nxt_conf_vldt_handler_t)(nxt_conf_validation_t *vldt, 41 nxt_conf_value_t *value, 42 void *data); 43 typedef nxt_int_t (*nxt_conf_vldt_member_t)(nxt_conf_validation_t *vldt, 44 nxt_str_t *name, 45 nxt_conf_value_t *value); 46 typedef nxt_int_t (*nxt_conf_vldt_element_t)(nxt_conf_validation_t *vldt, 47 nxt_conf_value_t *value); 48 49 50 typedef struct nxt_conf_vldt_object_s nxt_conf_vldt_object_t; 51 52 struct nxt_conf_vldt_object_s { 53 nxt_str_t name; 54 nxt_conf_vldt_type_t type:32; 55 nxt_conf_vldt_flags_t flags:32; 56 nxt_conf_vldt_handler_t validator; 57 58 union { 59 nxt_conf_vldt_object_t *members; 60 nxt_conf_vldt_object_t *next; 61 nxt_conf_vldt_member_t object; 62 nxt_conf_vldt_element_t array; 63 const char *string; 64 } u; 65 }; 66 67 68 #define NXT_CONF_VLDT_NEXT(next) { .u.members = next } 69 #define NXT_CONF_VLDT_END { .name = nxt_null_string } 70 71 72 static nxt_int_t nxt_conf_vldt_type(nxt_conf_validation_t *vldt, 73 nxt_str_t *name, nxt_conf_value_t *value, nxt_conf_vldt_type_t type); 74 static nxt_int_t nxt_conf_vldt_error(nxt_conf_validation_t *vldt, 75 const char *fmt, ...); 76 static nxt_int_t nxt_conf_vldt_var(nxt_conf_validation_t *vldt, 77 const char *option, nxt_str_t *value); 78 nxt_inline nxt_int_t nxt_conf_vldt_unsupported(nxt_conf_validation_t *vldt, 79 nxt_conf_value_t *value, void *data); 80 81 static nxt_int_t nxt_conf_vldt_mtypes(nxt_conf_validation_t *vldt, 82 nxt_conf_value_t *value, void *data); 83 static nxt_int_t nxt_conf_vldt_mtypes_type(nxt_conf_validation_t *vldt, 84 nxt_str_t *name, nxt_conf_value_t *value); 85 static nxt_int_t nxt_conf_vldt_mtypes_extension(nxt_conf_validation_t *vldt, 86 nxt_conf_value_t *value); 87 static nxt_int_t nxt_conf_vldt_listener(nxt_conf_validation_t *vldt, 88 nxt_str_t *name, nxt_conf_value_t *value); 89 #if (NXT_TLS) 90 static nxt_int_t nxt_conf_vldt_certificate(nxt_conf_validation_t *vldt, 91 nxt_conf_value_t *value, void *data); 92 static nxt_int_t nxt_conf_vldt_certificate_element(nxt_conf_validation_t *vldt, 93 nxt_conf_value_t *value); 94 #endif 95 static nxt_int_t nxt_conf_vldt_action(nxt_conf_validation_t *vldt, 96 nxt_conf_value_t *value, void *data); 97 static nxt_int_t nxt_conf_vldt_pass(nxt_conf_validation_t *vldt, 98 nxt_conf_value_t *value, void *data); 99 static nxt_int_t nxt_conf_vldt_return(nxt_conf_validation_t *vldt, 100 nxt_conf_value_t *value, void *data); 101 static nxt_int_t nxt_conf_vldt_proxy(nxt_conf_validation_t *vldt, 102 nxt_conf_value_t *value, void *data); 103 static nxt_int_t nxt_conf_vldt_python_path(nxt_conf_validation_t *vldt, 104 nxt_conf_value_t *value, void *data); 105 static nxt_int_t nxt_conf_vldt_python_path_element(nxt_conf_validation_t *vldt, 106 nxt_conf_value_t *value); 107 static nxt_int_t nxt_conf_vldt_python_protocol(nxt_conf_validation_t *vldt, 108 nxt_conf_value_t *value, void *data); 109 static nxt_int_t nxt_conf_vldt_threads(nxt_conf_validation_t *vldt, 110 nxt_conf_value_t *value, void *data); 111 static nxt_int_t nxt_conf_vldt_thread_stack_size(nxt_conf_validation_t *vldt, 112 nxt_conf_value_t *value, void *data); 113 static nxt_int_t nxt_conf_vldt_routes(nxt_conf_validation_t *vldt, 114 nxt_conf_value_t *value, void *data); 115 static nxt_int_t nxt_conf_vldt_routes_member(nxt_conf_validation_t *vldt, 116 nxt_str_t *name, nxt_conf_value_t *value); 117 static nxt_int_t nxt_conf_vldt_route(nxt_conf_validation_t *vldt, 118 nxt_conf_value_t *value); 119 static nxt_int_t nxt_conf_vldt_match_encoded_patterns_sets( 120 nxt_conf_validation_t *vldt, nxt_conf_value_t *value, void *data); 121 static nxt_int_t nxt_conf_vldt_match_encoded_patterns_set( 122 nxt_conf_validation_t *vldt, nxt_conf_value_t *value); 123 static nxt_int_t nxt_conf_vldt_match_encoded_patterns_set_member( 124 nxt_conf_validation_t *vldt, nxt_str_t *name, nxt_conf_value_t *value); 125 static nxt_int_t nxt_conf_vldt_match_encoded_patterns( 126 nxt_conf_validation_t *vldt, nxt_conf_value_t *value, void *data); 127 static nxt_int_t nxt_conf_vldt_match_encoded_pattern( 128 nxt_conf_validation_t *vldt, nxt_conf_value_t *value); 129 static nxt_int_t nxt_conf_vldt_match_patterns(nxt_conf_validation_t *vldt, 130 nxt_conf_value_t *value, void *data); 131 static nxt_int_t nxt_conf_vldt_match_pattern(nxt_conf_validation_t *vldt, 132 nxt_conf_value_t *value); 133 static nxt_int_t nxt_conf_vldt_match_patterns_sets(nxt_conf_validation_t *vldt, 134 nxt_conf_value_t *value, void *data); 135 static nxt_int_t nxt_conf_vldt_match_patterns_set(nxt_conf_validation_t *vldt, 136 nxt_conf_value_t *value); 137 static nxt_int_t nxt_conf_vldt_match_patterns_set_member( 138 nxt_conf_validation_t *vldt, nxt_str_t *name, nxt_conf_value_t *value); 139 static nxt_int_t nxt_conf_vldt_match_scheme_pattern(nxt_conf_validation_t *vldt, 140 nxt_conf_value_t *value, void *data); 141 static nxt_int_t nxt_conf_vldt_match_addrs(nxt_conf_validation_t *vldt, 142 nxt_conf_value_t *value, void *data); 143 static nxt_int_t nxt_conf_vldt_match_addr(nxt_conf_validation_t *vldt, 144 nxt_conf_value_t *value); 145 static nxt_int_t nxt_conf_vldt_app_name(nxt_conf_validation_t *vldt, 146 nxt_conf_value_t *value, void *data); 147 static nxt_int_t nxt_conf_vldt_app(nxt_conf_validation_t *vldt, 148 nxt_str_t *name, nxt_conf_value_t *value); 149 static nxt_int_t nxt_conf_vldt_object(nxt_conf_validation_t *vldt, 150 nxt_conf_value_t *value, void *data); 151 static nxt_int_t nxt_conf_vldt_processes(nxt_conf_validation_t *vldt, 152 nxt_conf_value_t *value, void *data); 153 static nxt_int_t nxt_conf_vldt_object_iterator(nxt_conf_validation_t *vldt, 154 nxt_conf_value_t *value, void *data); 155 static nxt_int_t nxt_conf_vldt_array_iterator(nxt_conf_validation_t *vldt, 156 nxt_conf_value_t *value, void *data); 157 static nxt_int_t nxt_conf_vldt_environment(nxt_conf_validation_t *vldt, 158 nxt_str_t *name, nxt_conf_value_t *value); 159 static nxt_int_t nxt_conf_vldt_argument(nxt_conf_validation_t *vldt, 160 nxt_conf_value_t *value); 161 static nxt_int_t nxt_conf_vldt_php(nxt_conf_validation_t *vldt, 162 nxt_conf_value_t *value, void *data); 163 static nxt_int_t nxt_conf_vldt_php_targets_exclusive( 164 nxt_conf_validation_t *vldt, nxt_conf_value_t *value, void *data); 165 static nxt_int_t nxt_conf_vldt_php_targets(nxt_conf_validation_t *vldt, 166 nxt_conf_value_t *value, void *data); 167 static nxt_int_t nxt_conf_vldt_php_target(nxt_conf_validation_t *vldt, 168 nxt_str_t *name, nxt_conf_value_t *value); 169 static nxt_int_t nxt_conf_vldt_php_option(nxt_conf_validation_t *vldt, 170 nxt_str_t *name, nxt_conf_value_t *value); 171 static nxt_int_t nxt_conf_vldt_java_classpath(nxt_conf_validation_t *vldt, 172 nxt_conf_value_t *value); 173 static nxt_int_t nxt_conf_vldt_java_option(nxt_conf_validation_t *vldt, 174 nxt_conf_value_t *value); 175 static nxt_int_t nxt_conf_vldt_upstream(nxt_conf_validation_t *vldt, 176 nxt_str_t *name, nxt_conf_value_t *value); 177 static nxt_int_t nxt_conf_vldt_server(nxt_conf_validation_t *vldt, 178 nxt_str_t *name, nxt_conf_value_t *value); 179 static nxt_int_t nxt_conf_vldt_server_weight(nxt_conf_validation_t *vldt, 180 nxt_conf_value_t *value, void *data); 181 182 static nxt_int_t nxt_conf_vldt_isolation(nxt_conf_validation_t *vldt, 183 nxt_conf_value_t *value, void *data); 184 static nxt_int_t nxt_conf_vldt_clone_namespaces(nxt_conf_validation_t *vldt, 185 nxt_conf_value_t *value, void *data); 186 187 #if (NXT_HAVE_CLONE_NEWUSER) 188 static nxt_int_t nxt_conf_vldt_clone_procmap(nxt_conf_validation_t *vldt, 189 const char* mapfile, nxt_conf_value_t *value); 190 static nxt_int_t nxt_conf_vldt_clone_uidmap(nxt_conf_validation_t *vldt, 191 nxt_conf_value_t *value); 192 static nxt_int_t nxt_conf_vldt_clone_gidmap(nxt_conf_validation_t *vldt, 193 nxt_conf_value_t *value); 194 #endif 195 196 197 static nxt_conf_vldt_object_t nxt_conf_vldt_setting_members[]; 198 static nxt_conf_vldt_object_t nxt_conf_vldt_http_members[]; 199 static nxt_conf_vldt_object_t nxt_conf_vldt_websocket_members[]; 200 static nxt_conf_vldt_object_t nxt_conf_vldt_static_members[]; 201 #if (NXT_TLS) 202 static nxt_conf_vldt_object_t nxt_conf_vldt_tls_members[]; 203 #endif 204 static nxt_conf_vldt_object_t nxt_conf_vldt_match_members[]; 205 static nxt_conf_vldt_object_t nxt_conf_vldt_php_common_members[]; 206 static nxt_conf_vldt_object_t nxt_conf_vldt_php_options_members[]; 207 static nxt_conf_vldt_object_t nxt_conf_vldt_common_members[]; 208 static nxt_conf_vldt_object_t nxt_conf_vldt_app_limits_members[]; 209 static nxt_conf_vldt_object_t nxt_conf_vldt_app_processes_members[]; 210 static nxt_conf_vldt_object_t nxt_conf_vldt_app_isolation_members[]; 211 static nxt_conf_vldt_object_t nxt_conf_vldt_app_namespaces_members[]; 212 #if (NXT_HAVE_ISOLATION_ROOTFS) 213 static nxt_conf_vldt_object_t nxt_conf_vldt_app_automount_members[]; 214 #endif 215 216 217 static nxt_conf_vldt_object_t nxt_conf_vldt_root_members[] = { 218 { 219 .name = nxt_string("settings"), 220 .type = NXT_CONF_VLDT_OBJECT, 221 .validator = nxt_conf_vldt_object, 222 .u.members = nxt_conf_vldt_setting_members, 223 }, { 224 .name = nxt_string("listeners"), 225 .type = NXT_CONF_VLDT_OBJECT, 226 .validator = nxt_conf_vldt_object_iterator, 227 .u.object = nxt_conf_vldt_listener, 228 }, { 229 .name = nxt_string("routes"), 230 .type = NXT_CONF_VLDT_ARRAY | NXT_CONF_VLDT_OBJECT, 231 .validator = nxt_conf_vldt_routes, 232 }, { 233 .name = nxt_string("applications"), 234 .type = NXT_CONF_VLDT_OBJECT, 235 .validator = nxt_conf_vldt_object_iterator, 236 .u.object = nxt_conf_vldt_app, 237 }, { 238 .name = nxt_string("upstreams"), 239 .type = NXT_CONF_VLDT_OBJECT, 240 .validator = nxt_conf_vldt_object_iterator, 241 .u.object = nxt_conf_vldt_upstream, 242 }, { 243 .name = nxt_string("access_log"), 244 .type = NXT_CONF_VLDT_STRING, 245 }, 246 247 NXT_CONF_VLDT_END 248 }; 249 250 251 static nxt_conf_vldt_object_t nxt_conf_vldt_setting_members[] = { 252 { 253 .name = nxt_string("http"), 254 .type = NXT_CONF_VLDT_OBJECT, 255 .validator = nxt_conf_vldt_object, 256 .u.members = nxt_conf_vldt_http_members, 257 }, 258 259 NXT_CONF_VLDT_END 260 }; 261 262 263 static nxt_conf_vldt_object_t nxt_conf_vldt_http_members[] = { 264 { 265 .name = nxt_string("header_read_timeout"), 266 .type = NXT_CONF_VLDT_INTEGER, 267 }, { 268 .name = nxt_string("body_read_timeout"), 269 .type = NXT_CONF_VLDT_INTEGER, 270 }, { 271 .name = nxt_string("send_timeout"), 272 .type = NXT_CONF_VLDT_INTEGER, 273 }, { 274 .name = nxt_string("idle_timeout"), 275 .type = NXT_CONF_VLDT_INTEGER, 276 }, { 277 .name = nxt_string("body_buffer_size"), 278 .type = NXT_CONF_VLDT_INTEGER, 279 }, { 280 .name = nxt_string("max_body_size"), 281 .type = NXT_CONF_VLDT_INTEGER, 282 }, { 283 .name = nxt_string("body_temp_path"), 284 .type = NXT_CONF_VLDT_STRING, 285 }, { 286 .name = nxt_string("discard_unsafe_fields"), 287 .type = NXT_CONF_VLDT_BOOLEAN, 288 }, { 289 .name = nxt_string("websocket"), 290 .type = NXT_CONF_VLDT_OBJECT, 291 .validator = nxt_conf_vldt_object, 292 .u.members = nxt_conf_vldt_websocket_members, 293 }, { 294 .name = nxt_string("static"), 295 .type = NXT_CONF_VLDT_OBJECT, 296 .validator = nxt_conf_vldt_object, 297 .u.members = nxt_conf_vldt_static_members, 298 }, 299 300 NXT_CONF_VLDT_END 301 }; 302 303 304 static nxt_conf_vldt_object_t nxt_conf_vldt_websocket_members[] = { 305 { 306 .name = nxt_string("read_timeout"), 307 .type = NXT_CONF_VLDT_INTEGER, 308 }, { 309 310 .name = nxt_string("keepalive_interval"), 311 .type = NXT_CONF_VLDT_INTEGER, 312 }, { 313 .name = nxt_string("max_frame_size"), 314 .type = NXT_CONF_VLDT_INTEGER, 315 }, 316 317 NXT_CONF_VLDT_END 318 }; 319 320 321 static nxt_conf_vldt_object_t nxt_conf_vldt_static_members[] = { 322 { 323 .name = nxt_string("mime_types"), 324 .type = NXT_CONF_VLDT_OBJECT, 325 .validator = nxt_conf_vldt_mtypes, 326 }, 327 328 NXT_CONF_VLDT_END 329 }; 330 331 332 static nxt_conf_vldt_object_t nxt_conf_vldt_listener_members[] = { 333 { 334 .name = nxt_string("pass"), 335 .type = NXT_CONF_VLDT_STRING, 336 .validator = nxt_conf_vldt_pass, 337 }, { 338 .name = nxt_string("application"), 339 .type = NXT_CONF_VLDT_STRING, 340 .validator = nxt_conf_vldt_app_name, 341 }, 342 343 #if (NXT_TLS) 344 { 345 .name = nxt_string("tls"), 346 .type = NXT_CONF_VLDT_OBJECT, 347 .validator = nxt_conf_vldt_object, 348 .u.members = nxt_conf_vldt_tls_members, 349 }, 350 #endif 351 352 NXT_CONF_VLDT_END 353 }; 354 355 356 #if (NXT_TLS) 357 358 static nxt_conf_vldt_object_t nxt_conf_vldt_tls_members[] = { 359 { 360 .name = nxt_string("certificate"), 361 .type = NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY, 362 .validator = nxt_conf_vldt_certificate, 363 }, 364 365 NXT_CONF_VLDT_END 366 }; 367 368 #endif 369 370 371 static nxt_conf_vldt_object_t nxt_conf_vldt_route_members[] = { 372 { 373 .name = nxt_string("match"), 374 .type = NXT_CONF_VLDT_OBJECT, 375 .validator = nxt_conf_vldt_object, 376 .u.members = nxt_conf_vldt_match_members, 377 }, { 378 .name = nxt_string("action"), 379 .type = NXT_CONF_VLDT_OBJECT, 380 .validator = nxt_conf_vldt_action, 381 }, 382 383 NXT_CONF_VLDT_END 384 }; 385 386 387 static nxt_conf_vldt_object_t nxt_conf_vldt_match_members[] = { 388 { 389 .name = nxt_string("method"), 390 .type = NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY, 391 .validator = nxt_conf_vldt_match_patterns, 392 }, { 393 .name = nxt_string("scheme"), 394 .type = NXT_CONF_VLDT_STRING, 395 .validator = nxt_conf_vldt_match_scheme_pattern, 396 }, { 397 .name = nxt_string("host"), 398 .type = NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY, 399 .validator = nxt_conf_vldt_match_patterns, 400 }, { 401 .name = nxt_string("source"), 402 .type = NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY, 403 .validator = nxt_conf_vldt_match_addrs, 404 }, { 405 .name = nxt_string("destination"), 406 .type = NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY, 407 .validator = nxt_conf_vldt_match_addrs, 408 }, { 409 .name = nxt_string("uri"), 410 .type = NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY, 411 .validator = nxt_conf_vldt_match_encoded_patterns, 412 }, { 413 .name = nxt_string("arguments"), 414 .type = NXT_CONF_VLDT_OBJECT | NXT_CONF_VLDT_ARRAY, 415 .validator = nxt_conf_vldt_match_encoded_patterns_sets, 416 }, { 417 .name = nxt_string("headers"), 418 .type = NXT_CONF_VLDT_OBJECT | NXT_CONF_VLDT_ARRAY, 419 .validator = nxt_conf_vldt_match_patterns_sets, 420 }, { 421 .name = nxt_string("cookies"), 422 .type = NXT_CONF_VLDT_OBJECT | NXT_CONF_VLDT_ARRAY, 423 .validator = nxt_conf_vldt_match_patterns_sets, 424 }, 425 426 NXT_CONF_VLDT_END 427 }; 428 429 430 static nxt_conf_vldt_object_t nxt_conf_vldt_pass_action_members[] = { 431 { 432 .name = nxt_string("pass"), 433 .type = NXT_CONF_VLDT_STRING, 434 .validator = nxt_conf_vldt_pass, 435 }, 436 437 NXT_CONF_VLDT_END 438 }; 439 440 441 static nxt_conf_vldt_object_t nxt_conf_vldt_return_action_members[] = { 442 { 443 .name = nxt_string("return"), 444 .type = NXT_CONF_VLDT_INTEGER, 445 .validator = nxt_conf_vldt_return, 446 }, { 447 .name = nxt_string("location"), 448 .type = NXT_CONF_VLDT_STRING, 449 }, 450 451 NXT_CONF_VLDT_END 452 }; 453 454 455 static nxt_conf_vldt_object_t nxt_conf_vldt_share_action_members[] = { 456 { 457 .name = nxt_string("share"), 458 .type = NXT_CONF_VLDT_STRING, 459 }, { 460 .name = nxt_string("fallback"), 461 .type = NXT_CONF_VLDT_OBJECT, 462 .validator = nxt_conf_vldt_action, 463 }, { 464 .name = nxt_string("chroot"), 465 .type = NXT_CONF_VLDT_STRING, 466 #if !(NXT_HAVE_OPENAT2) 467 .validator = nxt_conf_vldt_unsupported, 468 .u.string = "chroot", 469 #endif 470 }, { 471 .name = nxt_string("follow_symlinks"), 472 .type = NXT_CONF_VLDT_BOOLEAN, 473 #if !(NXT_HAVE_OPENAT2) 474 .validator = nxt_conf_vldt_unsupported, 475 .u.string = "follow_symlinks", 476 #endif 477 }, { 478 .name = nxt_string("traverse_mounts"), 479 .type = NXT_CONF_VLDT_BOOLEAN, 480 #if !(NXT_HAVE_OPENAT2) 481 .validator = nxt_conf_vldt_unsupported, 482 .u.string = "traverse_mounts", 483 #endif 484 }, 485 486 NXT_CONF_VLDT_END 487 }; 488 489 490 static nxt_conf_vldt_object_t nxt_conf_vldt_proxy_action_members[] = { 491 { 492 .name = nxt_string("proxy"), 493 .type = NXT_CONF_VLDT_STRING, 494 .validator = nxt_conf_vldt_proxy, 495 }, 496 497 NXT_CONF_VLDT_END 498 }; 499 500 501 static nxt_conf_vldt_object_t nxt_conf_vldt_external_members[] = { 502 { 503 .name = nxt_string("executable"), 504 .type = NXT_CONF_VLDT_STRING, 505 .flags = NXT_CONF_VLDT_REQUIRED, 506 }, { 507 .name = nxt_string("arguments"), 508 .type = NXT_CONF_VLDT_ARRAY, 509 .validator = nxt_conf_vldt_array_iterator, 510 .u.array = nxt_conf_vldt_argument, 511 }, 512 513 NXT_CONF_VLDT_NEXT(nxt_conf_vldt_common_members) 514 }; 515 516 517 static nxt_conf_vldt_object_t nxt_conf_vldt_python_members[] = { 518 { 519 .name = nxt_string("home"), 520 .type = NXT_CONF_VLDT_STRING, 521 }, { 522 .name = nxt_string("path"), 523 .type = NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY, 524 .validator = nxt_conf_vldt_python_path, 525 }, { 526 .name = nxt_string("module"), 527 .type = NXT_CONF_VLDT_STRING, 528 .flags = NXT_CONF_VLDT_REQUIRED, 529 }, { 530 .name = nxt_string("callable"), 531 .type = NXT_CONF_VLDT_STRING, 532 }, { 533 .name = nxt_string("protocol"), 534 .type = NXT_CONF_VLDT_STRING, 535 .validator = nxt_conf_vldt_python_protocol, 536 }, { 537 .name = nxt_string("threads"), 538 .type = NXT_CONF_VLDT_INTEGER, 539 .validator = nxt_conf_vldt_threads, 540 }, { 541 .name = nxt_string("thread_stack_size"), 542 .type = NXT_CONF_VLDT_INTEGER, 543 .validator = nxt_conf_vldt_thread_stack_size, 544 }, 545 546 NXT_CONF_VLDT_NEXT(nxt_conf_vldt_common_members) 547 }; 548 549 550 static nxt_conf_vldt_object_t nxt_conf_vldt_php_members[] = { 551 { 552 .name = nxt_string("root"), 553 .type = NXT_CONF_VLDT_ANY_TYPE, 554 .validator = nxt_conf_vldt_php_targets_exclusive, 555 .u.string = "root", 556 }, { 557 .name = nxt_string("script"), 558 .type = NXT_CONF_VLDT_ANY_TYPE, 559 .validator = nxt_conf_vldt_php_targets_exclusive, 560 .u.string = "script", 561 }, { 562 .name = nxt_string("index"), 563 .type = NXT_CONF_VLDT_ANY_TYPE, 564 .validator = nxt_conf_vldt_php_targets_exclusive, 565 .u.string = "index", 566 }, { 567 .name = nxt_string("targets"), 568 .type = NXT_CONF_VLDT_OBJECT, 569 .validator = nxt_conf_vldt_php_targets, 570 }, 571 572 NXT_CONF_VLDT_NEXT(nxt_conf_vldt_php_common_members) 573 }; 574 575 576 static nxt_conf_vldt_object_t nxt_conf_vldt_php_common_members[] = { 577 { 578 .name = nxt_string("options"), 579 .type = NXT_CONF_VLDT_OBJECT, 580 .validator = nxt_conf_vldt_object, 581 .u.members = nxt_conf_vldt_php_options_members, 582 }, 583 584 NXT_CONF_VLDT_NEXT(nxt_conf_vldt_common_members) 585 }; 586 587 588 static nxt_conf_vldt_object_t nxt_conf_vldt_php_options_members[] = { 589 { 590 .name = nxt_string("file"), 591 .type = NXT_CONF_VLDT_STRING, 592 }, { 593 .name = nxt_string("admin"), 594 .type = NXT_CONF_VLDT_OBJECT, 595 .validator = nxt_conf_vldt_object_iterator, 596 .u.object = nxt_conf_vldt_php_option, 597 }, { 598 .name = nxt_string("user"), 599 .type = NXT_CONF_VLDT_OBJECT, 600 .validator = nxt_conf_vldt_object_iterator, 601 .u.object = nxt_conf_vldt_php_option, 602 }, 603 604 NXT_CONF_VLDT_END 605 }; 606 607 608 static nxt_conf_vldt_object_t nxt_conf_vldt_php_target_members[] = { 609 { 610 .name = nxt_string("root"), 611 .type = NXT_CONF_VLDT_STRING, 612 .flags = NXT_CONF_VLDT_REQUIRED, 613 }, { 614 .name = nxt_string("script"), 615 .type = NXT_CONF_VLDT_STRING, 616 }, { 617 .name = nxt_string("index"), 618 .type = NXT_CONF_VLDT_STRING, 619 }, 620 621 NXT_CONF_VLDT_END 622 }; 623 624 625 static nxt_conf_vldt_object_t nxt_conf_vldt_php_notargets_members[] = { 626 { 627 .name = nxt_string("root"), 628 .type = NXT_CONF_VLDT_STRING, 629 .flags = NXT_CONF_VLDT_REQUIRED, 630 }, { 631 .name = nxt_string("script"), 632 .type = NXT_CONF_VLDT_STRING, 633 }, { 634 .name = nxt_string("index"), 635 .type = NXT_CONF_VLDT_STRING, 636 }, 637 638 NXT_CONF_VLDT_NEXT(nxt_conf_vldt_php_common_members) 639 }; 640 641 642 static nxt_conf_vldt_object_t nxt_conf_vldt_perl_members[] = { 643 { 644 .name = nxt_string("script"), 645 .type = NXT_CONF_VLDT_STRING, 646 .flags = NXT_CONF_VLDT_REQUIRED, 647 }, { 648 .name = nxt_string("threads"), 649 .type = NXT_CONF_VLDT_INTEGER, 650 .validator = nxt_conf_vldt_threads, 651 }, { 652 .name = nxt_string("thread_stack_size"), 653 .type = NXT_CONF_VLDT_INTEGER, 654 .validator = nxt_conf_vldt_thread_stack_size, 655 }, 656 657 NXT_CONF_VLDT_NEXT(nxt_conf_vldt_common_members) 658 }; 659 660 661 static nxt_conf_vldt_object_t nxt_conf_vldt_ruby_members[] = { 662 { 663 .name = nxt_string("script"), 664 .type = NXT_CONF_VLDT_STRING, 665 .flags = NXT_CONF_VLDT_REQUIRED, 666 }, { 667 .name = nxt_string("threads"), 668 .type = NXT_CONF_VLDT_INTEGER, 669 .validator = nxt_conf_vldt_threads, 670 }, 671 672 NXT_CONF_VLDT_NEXT(nxt_conf_vldt_common_members) 673 }; 674 675 676 static nxt_conf_vldt_object_t nxt_conf_vldt_java_members[] = { 677 { 678 .name = nxt_string("classpath"), 679 .type = NXT_CONF_VLDT_ARRAY, 680 .validator = nxt_conf_vldt_array_iterator, 681 .u.array = nxt_conf_vldt_java_classpath, 682 }, { 683 .name = nxt_string("webapp"), 684 .type = NXT_CONF_VLDT_STRING, 685 .flags = NXT_CONF_VLDT_REQUIRED, 686 }, { 687 .name = nxt_string("options"), 688 .type = NXT_CONF_VLDT_ARRAY, 689 .validator = nxt_conf_vldt_array_iterator, 690 .u.array = nxt_conf_vldt_java_option, 691 }, { 692 .name = nxt_string("unit_jars"), 693 .type = NXT_CONF_VLDT_STRING, 694 }, { 695 .name = nxt_string("threads"), 696 .type = NXT_CONF_VLDT_INTEGER, 697 .validator = nxt_conf_vldt_threads, 698 }, { 699 .name = nxt_string("thread_stack_size"), 700 .type = NXT_CONF_VLDT_INTEGER, 701 .validator = nxt_conf_vldt_thread_stack_size, 702 }, 703 704 NXT_CONF_VLDT_NEXT(nxt_conf_vldt_common_members) 705 }; 706 707 708 static nxt_conf_vldt_object_t nxt_conf_vldt_common_members[] = { 709 { 710 .name = nxt_string("type"), 711 .type = NXT_CONF_VLDT_STRING, 712 }, { 713 .name = nxt_string("limits"), 714 .type = NXT_CONF_VLDT_OBJECT, 715 .validator = nxt_conf_vldt_object, 716 .u.members = nxt_conf_vldt_app_limits_members, 717 }, { 718 .name = nxt_string("processes"), 719 .type = NXT_CONF_VLDT_INTEGER | NXT_CONF_VLDT_OBJECT, 720 .validator = nxt_conf_vldt_processes, 721 .u.members = nxt_conf_vldt_app_processes_members, 722 }, { 723 .name = nxt_string("user"), 724 .type = NXT_CONF_VLDT_STRING, 725 }, { 726 .name = nxt_string("group"), 727 .type = NXT_CONF_VLDT_STRING, 728 }, { 729 .name = nxt_string("working_directory"), 730 .type = NXT_CONF_VLDT_STRING, 731 }, { 732 .name = nxt_string("environment"), 733 .type = NXT_CONF_VLDT_OBJECT, 734 .validator = nxt_conf_vldt_object_iterator, 735 .u.object = nxt_conf_vldt_environment, 736 }, { 737 .name = nxt_string("isolation"), 738 .type = NXT_CONF_VLDT_OBJECT, 739 .validator = nxt_conf_vldt_isolation, 740 .u.members = nxt_conf_vldt_app_isolation_members, 741 }, 742 743 NXT_CONF_VLDT_END 744 }; 745 746 747 static nxt_conf_vldt_object_t nxt_conf_vldt_app_limits_members[] = { 748 { 749 .name = nxt_string("timeout"), 750 .type = NXT_CONF_VLDT_INTEGER, 751 }, { 752 .name = nxt_string("requests"), 753 .type = NXT_CONF_VLDT_INTEGER, 754 }, { 755 .name = nxt_string("shm"), 756 .type = NXT_CONF_VLDT_INTEGER, 757 }, 758 759 NXT_CONF_VLDT_END 760 }; 761 762 763 static nxt_conf_vldt_object_t nxt_conf_vldt_app_processes_members[] = { 764 { 765 .name = nxt_string("spare"), 766 .type = NXT_CONF_VLDT_INTEGER, 767 }, { 768 .name = nxt_string("max"), 769 .type = NXT_CONF_VLDT_INTEGER, 770 }, { 771 .name = nxt_string("idle_timeout"), 772 .type = NXT_CONF_VLDT_INTEGER, 773 }, 774 775 NXT_CONF_VLDT_END 776 }; 777 778 779 static nxt_conf_vldt_object_t nxt_conf_vldt_app_isolation_members[] = { 780 { 781 .name = nxt_string("namespaces"), 782 .type = NXT_CONF_VLDT_OBJECT, 783 .validator = nxt_conf_vldt_clone_namespaces, 784 .u.members = nxt_conf_vldt_app_namespaces_members, 785 }, 786 787 #if (NXT_HAVE_CLONE_NEWUSER) 788 { 789 .name = nxt_string("uidmap"), 790 .type = NXT_CONF_VLDT_ARRAY, 791 .validator = nxt_conf_vldt_array_iterator, 792 .u.array = nxt_conf_vldt_clone_uidmap, 793 }, { 794 .name = nxt_string("gidmap"), 795 .type = NXT_CONF_VLDT_ARRAY, 796 .validator = nxt_conf_vldt_array_iterator, 797 .u.array = nxt_conf_vldt_clone_gidmap, 798 }, 799 #endif 800 801 #if (NXT_HAVE_ISOLATION_ROOTFS) 802 { 803 .name = nxt_string("rootfs"), 804 .type = NXT_CONF_VLDT_STRING, 805 }, { 806 .name = nxt_string("automount"), 807 .type = NXT_CONF_VLDT_OBJECT, 808 .validator = nxt_conf_vldt_object, 809 .u.members = nxt_conf_vldt_app_automount_members, 810 }, 811 #endif 812 813 #if (NXT_HAVE_PR_SET_NO_NEW_PRIVS) 814 { 815 .name = nxt_string("new_privs"), 816 .type = NXT_CONF_VLDT_BOOLEAN, 817 }, 818 #endif 819 820 NXT_CONF_VLDT_END 821 }; 822 823 824 static nxt_conf_vldt_object_t nxt_conf_vldt_app_namespaces_members[] = { 825 826 #if (NXT_HAVE_CLONE_NEWUSER) 827 { 828 .name = nxt_string("credential"), 829 .type = NXT_CONF_VLDT_BOOLEAN, 830 }, 831 #endif 832 833 #if (NXT_HAVE_CLONE_NEWPID) 834 { 835 .name = nxt_string("pid"), 836 .type = NXT_CONF_VLDT_BOOLEAN, 837 }, 838 #endif 839 840 #if (NXT_HAVE_CLONE_NEWNET) 841 { 842 .name = nxt_string("network"), 843 .type = NXT_CONF_VLDT_BOOLEAN, 844 }, 845 #endif 846 847 #if (NXT_HAVE_CLONE_NEWNS) 848 { 849 .name = nxt_string("mount"), 850 .type = NXT_CONF_VLDT_BOOLEAN, 851 }, 852 #endif 853 854 #if (NXT_HAVE_CLONE_NEWUTS) 855 { 856 .name = nxt_string("uname"), 857 .type = NXT_CONF_VLDT_BOOLEAN, 858 }, 859 #endif 860 861 #if (NXT_HAVE_CLONE_NEWCGROUP) 862 { 863 .name = nxt_string("cgroup"), 864 .type = NXT_CONF_VLDT_BOOLEAN, 865 }, 866 #endif 867 868 NXT_CONF_VLDT_END 869 }; 870 871 872 #if (NXT_HAVE_ISOLATION_ROOTFS) 873 874 static nxt_conf_vldt_object_t nxt_conf_vldt_app_automount_members[] = { 875 { 876 .name = nxt_string("language_deps"), 877 .type = NXT_CONF_VLDT_BOOLEAN, 878 }, { 879 .name = nxt_string("tmpfs"), 880 .type = NXT_CONF_VLDT_BOOLEAN, 881 }, { 882 .name = nxt_string("procfs"), 883 .type = NXT_CONF_VLDT_BOOLEAN, 884 }, 885 886 NXT_CONF_VLDT_END 887 }; 888 889 #endif 890 891 892 #if (NXT_HAVE_CLONE_NEWUSER) 893 894 static nxt_conf_vldt_object_t nxt_conf_vldt_app_procmap_members[] = { 895 { 896 .name = nxt_string("container"), 897 .type = NXT_CONF_VLDT_INTEGER, 898 }, { 899 .name = nxt_string("host"), 900 .type = NXT_CONF_VLDT_INTEGER, 901 }, { 902 .name = nxt_string("size"), 903 .type = NXT_CONF_VLDT_INTEGER, 904 }, 905 906 NXT_CONF_VLDT_END 907 }; 908 909 #endif 910 911 912 static nxt_conf_vldt_object_t nxt_conf_vldt_upstream_members[] = { 913 { 914 .name = nxt_string("servers"), 915 .type = NXT_CONF_VLDT_OBJECT, 916 .validator = nxt_conf_vldt_object_iterator, 917 .u.object = nxt_conf_vldt_server, 918 }, 919 920 NXT_CONF_VLDT_END 921 }; 922 923 924 static nxt_conf_vldt_object_t nxt_conf_vldt_upstream_server_members[] = { 925 { 926 .name = nxt_string("weight"), 927 .type = NXT_CONF_VLDT_NUMBER, 928 .validator = nxt_conf_vldt_server_weight, 929 }, 930 931 NXT_CONF_VLDT_END 932 }; 933 934 935 nxt_int_t 936 nxt_conf_validate(nxt_conf_validation_t *vldt) 937 { 938 nxt_int_t ret; 939 940 ret = nxt_conf_vldt_type(vldt, NULL, vldt->conf, NXT_CONF_VLDT_OBJECT); 941 942 if (ret != NXT_OK) { 943 return ret; 944 } 945 946 return nxt_conf_vldt_object(vldt, vldt->conf, nxt_conf_vldt_root_members); 947 } 948 949 950 #define NXT_CONF_VLDT_ANY_TYPE_STR \ 951 "either a null, a boolean, an integer, " \ 952 "a number, a string, an array, or an object" 953 954 955 static nxt_int_t 956 nxt_conf_vldt_type(nxt_conf_validation_t *vldt, nxt_str_t *name, 957 nxt_conf_value_t *value, nxt_conf_vldt_type_t type) 958 { 959 u_char *p; 960 nxt_str_t expected; 961 nxt_bool_t comma; 962 nxt_uint_t value_type, n, t; 963 u_char buf[nxt_length(NXT_CONF_VLDT_ANY_TYPE_STR)]; 964 965 static nxt_str_t type_name[] = { 966 nxt_string("a null"), 967 nxt_string("a boolean"), 968 nxt_string("an integer number"), 969 nxt_string("a fractional number"), 970 nxt_string("a string"), 971 nxt_string("an array"), 972 nxt_string("an object"), 973 }; 974 975 value_type = nxt_conf_type(value); 976 977 if ((1 << value_type) & type) { 978 return NXT_OK; 979 } 980 981 p = buf; 982 983 n = nxt_popcount(type); 984 985 if (n > 1) { 986 p = nxt_cpymem(p, "either ", 7); 987 } 988 989 comma = (n > 2); 990 991 for ( ;; ) { 992 t = __builtin_ffs(type) - 1; 993 994 p = nxt_cpymem(p, type_name[t].start, type_name[t].length); 995 996 n--; 997 998 if (n == 0) { 999 break; 1000 } 1001 1002 if (comma) { 1003 *p++ = ','; 1004 } 1005 1006 if (n == 1) { 1007 p = nxt_cpymem(p, " or", 3); 1008 } 1009 1010 *p++ = ' '; 1011 1012 type = type & ~(1 << t); 1013 } 1014 1015 expected.length = p - buf; 1016 expected.start = buf; 1017 1018 if (name == NULL) { 1019 return nxt_conf_vldt_error(vldt, 1020 "The configuration must be %V, but not %V.", 1021 &expected, &type_name[value_type]); 1022 } 1023 1024 return nxt_conf_vldt_error(vldt, 1025 "The \"%V\" value must be %V, but not %V.", 1026 name, &expected, &type_name[value_type]); 1027 } 1028 1029 1030 static nxt_int_t 1031 nxt_conf_vldt_error(nxt_conf_validation_t *vldt, const char *fmt, ...) 1032 { 1033 u_char *p, *end; 1034 size_t size; 1035 va_list args; 1036 u_char error[NXT_MAX_ERROR_STR]; 1037 1038 va_start(args, fmt); 1039 end = nxt_vsprintf(error, error + NXT_MAX_ERROR_STR, fmt, args); 1040 va_end(args); 1041 1042 size = end - error; 1043 1044 p = nxt_mp_nget(vldt->pool, size); 1045 if (p == NULL) { 1046 return NXT_ERROR; 1047 } 1048 1049 nxt_memcpy(p, error, size); 1050 1051 vldt->error.length = size; 1052 vldt->error.start = p; 1053 1054 return NXT_DECLINED; 1055 } 1056 1057 1058 nxt_inline nxt_int_t 1059 nxt_conf_vldt_unsupported(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, 1060 void *data) 1061 { 1062 return nxt_conf_vldt_error(vldt, "Unit is built without the \"%s\" " 1063 "option support.", data); 1064 } 1065 1066 1067 static nxt_int_t 1068 nxt_conf_vldt_var(nxt_conf_validation_t *vldt, const char *option, 1069 nxt_str_t *value) 1070 { 1071 u_char error[NXT_MAX_ERROR_STR]; 1072 1073 if (nxt_var_test(value, error) != NXT_OK) { 1074 return nxt_conf_vldt_error(vldt, "%s in the \"%s\" value.", 1075 error, option); 1076 } 1077 1078 return NXT_OK; 1079 } 1080 1081 1082 typedef struct { 1083 nxt_mp_t *pool; 1084 nxt_str_t *type; 1085 nxt_lvlhsh_t hash; 1086 } nxt_conf_vldt_mtypes_ctx_t; 1087 1088 1089 static nxt_int_t 1090 nxt_conf_vldt_mtypes(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, 1091 void *data) 1092 { 1093 nxt_int_t ret; 1094 nxt_conf_vldt_mtypes_ctx_t ctx; 1095 1096 ctx.pool = nxt_mp_create(1024, 128, 256, 32); 1097 if (nxt_slow_path(ctx.pool == NULL)) { 1098 return NXT_ERROR; 1099 } 1100 1101 nxt_lvlhsh_init(&ctx.hash); 1102 1103 vldt->ctx = &ctx; 1104 1105 ret = nxt_conf_vldt_object_iterator(vldt, value, 1106 &nxt_conf_vldt_mtypes_type); 1107 1108 vldt->ctx = NULL; 1109 1110 nxt_mp_destroy(ctx.pool); 1111 1112 return ret; 1113 } 1114 1115 1116 static nxt_int_t 1117 nxt_conf_vldt_mtypes_type(nxt_conf_validation_t *vldt, nxt_str_t *name, 1118 nxt_conf_value_t *value) 1119 { 1120 nxt_int_t ret; 1121 nxt_conf_vldt_mtypes_ctx_t *ctx; 1122 1123 ret = nxt_conf_vldt_type(vldt, name, value, 1124 NXT_CONF_VLDT_STRING|NXT_CONF_VLDT_ARRAY); 1125 if (ret != NXT_OK) { 1126 return ret; 1127 } 1128 1129 ctx = vldt->ctx; 1130 1131 ctx->type = nxt_mp_get(ctx->pool, sizeof(nxt_str_t)); 1132 if (nxt_slow_path(ctx->type == NULL)) { 1133 return NXT_ERROR; 1134 } 1135 1136 *ctx->type = *name; 1137 1138 if (nxt_conf_type(value) == NXT_CONF_ARRAY) { 1139 return nxt_conf_vldt_array_iterator(vldt, value, 1140 &nxt_conf_vldt_mtypes_extension); 1141 } 1142 1143 /* NXT_CONF_STRING */ 1144 1145 return nxt_conf_vldt_mtypes_extension(vldt, value); 1146 } 1147 1148 1149 static nxt_int_t 1150 nxt_conf_vldt_mtypes_extension(nxt_conf_validation_t *vldt, 1151 nxt_conf_value_t *value) 1152 { 1153 nxt_str_t ext, *dup_type; 1154 nxt_conf_vldt_mtypes_ctx_t *ctx; 1155 1156 ctx = vldt->ctx; 1157 1158 if (nxt_conf_type(value) != NXT_CONF_STRING) { 1159 return nxt_conf_vldt_error(vldt, "The \"%V\" MIME type array must " 1160 "contain only strings.", ctx->type); 1161 } 1162 1163 nxt_conf_get_string(value, &ext); 1164 1165 if (ext.length == 0) { 1166 return nxt_conf_vldt_error(vldt, "An empty file extension for " 1167 "the \"%V\" MIME type.", ctx->type); 1168 } 1169 1170 dup_type = nxt_http_static_mtypes_hash_find(&ctx->hash, &ext); 1171 1172 if (dup_type != NULL) { 1173 return nxt_conf_vldt_error(vldt, "The \"%V\" file extension has been " 1174 "declared for \"%V\" and \"%V\" " 1175 "MIME types at the same time.", 1176 &ext, dup_type, ctx->type); 1177 } 1178 1179 return nxt_http_static_mtypes_hash_add(ctx->pool, &ctx->hash, 1180 &ext, ctx->type); 1181 } 1182 1183 1184 static nxt_int_t 1185 nxt_conf_vldt_listener(nxt_conf_validation_t *vldt, nxt_str_t *name, 1186 nxt_conf_value_t *value) 1187 { 1188 nxt_int_t ret; 1189 nxt_sockaddr_t *sa; 1190 1191 sa = nxt_sockaddr_parse(vldt->pool, name); 1192 if (nxt_slow_path(sa == NULL)) { 1193 return nxt_conf_vldt_error(vldt, 1194 "The listener address \"%V\" is invalid.", 1195 name); 1196 } 1197 1198 ret = nxt_conf_vldt_type(vldt, name, value, NXT_CONF_VLDT_OBJECT); 1199 if (ret != NXT_OK) { 1200 return ret; 1201 } 1202 1203 return nxt_conf_vldt_object(vldt, value, nxt_conf_vldt_listener_members); 1204 } 1205 1206 1207 static nxt_int_t 1208 nxt_conf_vldt_action(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, 1209 void *data) 1210 { 1211 nxt_uint_t i; 1212 nxt_conf_value_t *action; 1213 nxt_conf_vldt_object_t *members; 1214 1215 static struct { 1216 nxt_str_t name; 1217 nxt_conf_vldt_object_t *members; 1218 1219 } actions[] = { 1220 { nxt_string("pass"), nxt_conf_vldt_pass_action_members }, 1221 { nxt_string("return"), nxt_conf_vldt_return_action_members }, 1222 { nxt_string("share"), nxt_conf_vldt_share_action_members }, 1223 { nxt_string("proxy"), nxt_conf_vldt_proxy_action_members }, 1224 }; 1225 1226 members = NULL; 1227 1228 for (i = 0; i < nxt_nitems(actions); i++) { 1229 action = nxt_conf_get_object_member(value, &actions[i].name, NULL); 1230 1231 if (action == NULL) { 1232 continue; 1233 } 1234 1235 if (members != NULL) { 1236 return nxt_conf_vldt_error(vldt, "The \"action\" object must have " 1237 "just one of \"pass\", \"return\", " 1238 "\"share\", or \"proxy\" options set."); 1239 } 1240 1241 members = actions[i].members; 1242 } 1243 1244 if (members == NULL) { 1245 return nxt_conf_vldt_error(vldt, "The \"action\" object must have " 1246 "either \"pass\", \"return\", \"share\", " 1247 "or \"proxy\" option set."); 1248 } 1249 1250 return nxt_conf_vldt_object(vldt, value, members); 1251 } 1252 1253 1254 static nxt_int_t 1255 nxt_conf_vldt_pass(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, 1256 void *data) 1257 { 1258 nxt_str_t pass; 1259 nxt_int_t ret; 1260 nxt_str_t segments[3]; 1261 1262 static nxt_str_t targets_str = nxt_string("targets"); 1263 1264 nxt_conf_get_string(value, &pass); 1265 1266 if (nxt_is_var(&pass)) { 1267 return nxt_conf_vldt_var(vldt, "pass", &pass); 1268 } 1269 1270 ret = nxt_http_pass_segments(vldt->pool, &pass, segments, 3); 1271 1272 if (ret != NXT_OK) { 1273 if (ret == NXT_DECLINED) { 1274 return nxt_conf_vldt_error(vldt, "Request \"pass\" value \"%V\" " 1275 "is invalid.", &pass); 1276 } 1277 1278 return NXT_ERROR; 1279 } 1280 1281 if (nxt_str_eq(&segments[0], "applications", 12)) { 1282 1283 if (segments[1].length == 0) { 1284 goto error; 1285 } 1286 1287 value = nxt_conf_get_object_member(vldt->conf, &segments[0], NULL); 1288 1289 if (value == NULL) { 1290 goto error; 1291 } 1292 1293 value = nxt_conf_get_object_member(value, &segments[1], NULL); 1294 1295 if (value == NULL) { 1296 goto error; 1297 } 1298 1299 if (segments[2].length > 0) { 1300 value = nxt_conf_get_object_member(value, &targets_str, NULL); 1301 1302 if (value == NULL) { 1303 goto error; 1304 } 1305 1306 value = nxt_conf_get_object_member(value, &segments[2], NULL); 1307 1308 if (value == NULL) { 1309 goto error; 1310 } 1311 } 1312 1313 return NXT_OK; 1314 } 1315 1316 if (nxt_str_eq(&segments[0], "upstreams", 9)) { 1317 1318 if (segments[1].length == 0 || segments[2].length != 0) { 1319 goto error; 1320 } 1321 1322 value = nxt_conf_get_object_member(vldt->conf, &segments[0], NULL); 1323 1324 if (value == NULL) { 1325 goto error; 1326 } 1327 1328 value = nxt_conf_get_object_member(value, &segments[1], NULL); 1329 1330 if (value == NULL) { 1331 goto error; 1332 } 1333 1334 return NXT_OK; 1335 } 1336 1337 if (nxt_str_eq(&segments[0], "routes", 6)) { 1338 1339 if (segments[2].length != 0) { 1340 goto error; 1341 } 1342 1343 value = nxt_conf_get_object_member(vldt->conf, &segments[0], NULL); 1344 1345 if (value == NULL) { 1346 goto error; 1347 } 1348 1349 if (segments[1].length == 0) { 1350 if (nxt_conf_type(value) != NXT_CONF_ARRAY) { 1351 goto error; 1352 } 1353 1354 return NXT_OK; 1355 } 1356 1357 if (nxt_conf_type(value) != NXT_CONF_OBJECT) { 1358 goto error; 1359 } 1360 1361 value = nxt_conf_get_object_member(value, &segments[1], NULL); 1362 1363 if (value == NULL) { 1364 goto error; 1365 } 1366 1367 return NXT_OK; 1368 } 1369 1370 error: 1371 1372 return nxt_conf_vldt_error(vldt, "Request \"pass\" points to invalid " 1373 "location \"%V\".", &pass); 1374 } 1375 1376 1377 static nxt_int_t 1378 nxt_conf_vldt_return(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, 1379 void *data) 1380 { 1381 int64_t status; 1382 1383 status = nxt_conf_get_number(value); 1384 1385 if (status < NXT_HTTP_INVALID || status > NXT_HTTP_STATUS_MAX) { 1386 return nxt_conf_vldt_error(vldt, "The \"return\" value is out of " 1387 "allowed HTTP status code range 0-999."); 1388 } 1389 1390 return NXT_OK; 1391 } 1392 1393 1394 static nxt_int_t 1395 nxt_conf_vldt_proxy(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, 1396 void *data) 1397 { 1398 nxt_str_t name; 1399 nxt_sockaddr_t *sa; 1400 1401 nxt_conf_get_string(value, &name); 1402 1403 if (nxt_str_start(&name, "http://", 7)) { 1404 name.length -= 7; 1405 name.start += 7; 1406 1407 sa = nxt_sockaddr_parse(vldt->pool, &name); 1408 if (sa != NULL) { 1409 return NXT_OK; 1410 } 1411 } 1412 1413 return nxt_conf_vldt_error(vldt, "The \"proxy\" address is invalid \"%V\"", 1414 &name); 1415 } 1416 1417 1418 static nxt_int_t 1419 nxt_conf_vldt_python_path(nxt_conf_validation_t *vldt, 1420 nxt_conf_value_t *value, void *data) 1421 { 1422 if (nxt_conf_type(value) == NXT_CONF_ARRAY) { 1423 return nxt_conf_vldt_array_iterator(vldt, value, 1424 &nxt_conf_vldt_python_path_element); 1425 } 1426 1427 /* NXT_CONF_STRING */ 1428 1429 return NXT_OK; 1430 } 1431 1432 1433 static nxt_int_t 1434 nxt_conf_vldt_python_path_element(nxt_conf_validation_t *vldt, 1435 nxt_conf_value_t *value) 1436 { 1437 if (nxt_conf_type(value) != NXT_CONF_STRING) { 1438 return nxt_conf_vldt_error(vldt, "The \"path\" array must contain " 1439 "only string values."); 1440 } 1441 1442 return NXT_OK; 1443 } 1444 1445 1446 static nxt_int_t 1447 nxt_conf_vldt_python_protocol(nxt_conf_validation_t *vldt, 1448 nxt_conf_value_t *value, void *data) 1449 { 1450 nxt_str_t proto; 1451 1452 static const nxt_str_t wsgi = nxt_string("wsgi"); 1453 static const nxt_str_t asgi = nxt_string("asgi"); 1454 1455 nxt_conf_get_string(value, &proto); 1456 1457 if (nxt_strstr_eq(&proto, &wsgi) || nxt_strstr_eq(&proto, &asgi)) { 1458 return NXT_OK; 1459 } 1460 1461 return nxt_conf_vldt_error(vldt, "The \"protocol\" can either be " 1462 "\"wsgi\" or \"asgi\"."); 1463 } 1464 1465 1466 static nxt_int_t 1467 nxt_conf_vldt_threads(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, 1468 void *data) 1469 { 1470 int64_t threads; 1471 1472 threads = nxt_conf_get_number(value); 1473 1474 if (threads < 1) { 1475 return nxt_conf_vldt_error(vldt, "The \"threads\" number must be " 1476 "equal to or greater than 1."); 1477 } 1478 1479 if (threads > NXT_INT32_T_MAX) { 1480 return nxt_conf_vldt_error(vldt, "The \"threads\" number must " 1481 "not exceed %d.", NXT_INT32_T_MAX); 1482 } 1483 1484 return NXT_OK; 1485 } 1486 1487 1488 static nxt_int_t 1489 nxt_conf_vldt_thread_stack_size(nxt_conf_validation_t *vldt, 1490 nxt_conf_value_t *value, void *data) 1491 { 1492 int64_t size; 1493 1494 size = nxt_conf_get_number(value); 1495 1496 if (size < NXT_THREAD_STACK_MIN) { 1497 return nxt_conf_vldt_error(vldt, "The \"thread_stack_size\" number " 1498 "must be equal to or greater than %d.", 1499 NXT_THREAD_STACK_MIN); 1500 } 1501 1502 if ((size % nxt_pagesize) != 0) { 1503 return nxt_conf_vldt_error(vldt, "The \"thread_stack_size\" number " 1504 "must be a multiple of the system page size (%d).", 1505 nxt_pagesize); 1506 } 1507 1508 return NXT_OK; 1509 } 1510 1511 1512 static nxt_int_t 1513 nxt_conf_vldt_routes(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, 1514 void *data) 1515 { 1516 if (nxt_conf_type(value) == NXT_CONF_ARRAY) { 1517 return nxt_conf_vldt_array_iterator(vldt, value, 1518 &nxt_conf_vldt_route); 1519 } 1520 1521 /* NXT_CONF_OBJECT */ 1522 1523 return nxt_conf_vldt_object_iterator(vldt, value, 1524 &nxt_conf_vldt_routes_member); 1525 } 1526 1527 1528 static nxt_int_t 1529 nxt_conf_vldt_routes_member(nxt_conf_validation_t *vldt, nxt_str_t *name, 1530 nxt_conf_value_t *value) 1531 { 1532 nxt_int_t ret; 1533 1534 ret = nxt_conf_vldt_type(vldt, name, value, NXT_CONF_VLDT_ARRAY); 1535 1536 if (ret != NXT_OK) { 1537 return ret; 1538 } 1539 1540 return nxt_conf_vldt_array_iterator(vldt, value, &nxt_conf_vldt_route); 1541 } 1542 1543 1544 static nxt_int_t 1545 nxt_conf_vldt_route(nxt_conf_validation_t *vldt, nxt_conf_value_t *value) 1546 { 1547 if (nxt_conf_type(value) != NXT_CONF_OBJECT) { 1548 return nxt_conf_vldt_error(vldt, "The \"routes\" array must contain " 1549 "only object values."); 1550 } 1551 1552 return nxt_conf_vldt_object(vldt, value, nxt_conf_vldt_route_members); 1553 } 1554 1555 1556 static nxt_int_t 1557 nxt_conf_vldt_match_patterns(nxt_conf_validation_t *vldt, 1558 nxt_conf_value_t *value, void *data) 1559 { 1560 if (nxt_conf_type(value) == NXT_CONF_ARRAY) { 1561 return nxt_conf_vldt_array_iterator(vldt, value, 1562 &nxt_conf_vldt_match_pattern); 1563 } 1564 1565 /* NXT_CONF_STRING */ 1566 1567 return nxt_conf_vldt_match_pattern(vldt, value); 1568 } 1569 1570 1571 static nxt_int_t 1572 nxt_conf_vldt_match_pattern(nxt_conf_validation_t *vldt, 1573 nxt_conf_value_t *value) 1574 { 1575 nxt_str_t pattern; 1576 nxt_uint_t i, first, last; 1577 #if (NXT_HAVE_REGEX) 1578 nxt_regex_t *re; 1579 nxt_regex_err_t err; 1580 #endif 1581 1582 if (nxt_conf_type(value) != NXT_CONF_STRING) { 1583 return nxt_conf_vldt_error(vldt, "The \"match\" patterns for \"host\", " 1584 "\"uri\", and \"method\" must be strings."); 1585 } 1586 1587 nxt_conf_get_string(value, &pattern); 1588 1589 if (pattern.length == 0) { 1590 return NXT_OK; 1591 } 1592 1593 first = (pattern.start[0] == '!'); 1594 1595 if (first < pattern.length && pattern.start[first] == '~') { 1596 #if (NXT_HAVE_REGEX) 1597 pattern.start += first + 1; 1598 pattern.length -= first + 1; 1599 1600 re = nxt_regex_compile(vldt->pool, &pattern, &err); 1601 if (nxt_slow_path(re == NULL)) { 1602 if (err.offset < pattern.length) { 1603 return nxt_conf_vldt_error(vldt, "Invalid regular expression: " 1604 "%s at offset %d", 1605 err.msg, err.offset); 1606 } 1607 1608 return nxt_conf_vldt_error(vldt, "Invalid regular expression: %s", 1609 err.msg); 1610 } 1611 1612 return NXT_OK; 1613 #else 1614 return nxt_conf_vldt_error(vldt, "Unit is built without support of " 1615 "regular expressions: \"--no-regex\" " 1616 "./configure option was set."); 1617 #endif 1618 } 1619 1620 last = pattern.length - 1; 1621 1622 for (i = first; i < last; i++) { 1623 if (pattern.start[i] == '*' && pattern.start[i + 1] == '*') { 1624 return nxt_conf_vldt_error(vldt, "The \"match\" pattern must " 1625 "not contain double \"*\" markers."); 1626 } 1627 } 1628 1629 return NXT_OK; 1630 } 1631 1632 1633 static nxt_int_t nxt_conf_vldt_match_encoded_patterns_sets( 1634 nxt_conf_validation_t *vldt, nxt_conf_value_t *value, void *data) 1635 { 1636 if (nxt_conf_type(value) == NXT_CONF_ARRAY) { 1637 return nxt_conf_vldt_array_iterator(vldt, value, 1638 &nxt_conf_vldt_match_encoded_patterns_set); 1639 } 1640 1641 /* NXT_CONF_STRING */ 1642 1643 return nxt_conf_vldt_match_encoded_patterns_set(vldt, value); 1644 } 1645 1646 1647 static nxt_int_t nxt_conf_vldt_match_encoded_patterns_set( 1648 nxt_conf_validation_t *vldt, nxt_conf_value_t *value) 1649 { 1650 if (nxt_conf_type(value) != NXT_CONF_OBJECT) { 1651 return nxt_conf_vldt_error(vldt, "The \"match\" pattern for " 1652 "\"arguments\" must be an object."); 1653 } 1654 1655 return nxt_conf_vldt_object_iterator(vldt, value, 1656 &nxt_conf_vldt_match_encoded_patterns_set_member); 1657 } 1658 1659 1660 static nxt_int_t 1661 nxt_conf_vldt_match_encoded_patterns_set_member(nxt_conf_validation_t *vldt, 1662 nxt_str_t *name, nxt_conf_value_t *value) 1663 { 1664 u_char *p, *end; 1665 1666 if (nxt_slow_path(name->length == 0)) { 1667 return nxt_conf_vldt_error(vldt, "The \"match\" pattern objects must " 1668 "not contain empty member names."); 1669 } 1670 1671 p = nxt_mp_nget(vldt->pool, name->length); 1672 if (nxt_slow_path(p == NULL)) { 1673 return NXT_ERROR; 1674 } 1675 1676 end = nxt_decode_uri(p, name->start, name->length); 1677 if (nxt_slow_path(end == NULL)) { 1678 return nxt_conf_vldt_error(vldt, "The \"match\" pattern for " 1679 "\"arguments\" is encoded but is invalid."); 1680 } 1681 1682 return nxt_conf_vldt_match_encoded_patterns(vldt, value, NULL); 1683 } 1684 1685 1686 static nxt_int_t 1687 nxt_conf_vldt_match_encoded_patterns(nxt_conf_validation_t *vldt, 1688 nxt_conf_value_t *value, void *data) 1689 { 1690 if (nxt_conf_type(value) == NXT_CONF_ARRAY) { 1691 return nxt_conf_vldt_array_iterator(vldt, value, 1692 &nxt_conf_vldt_match_encoded_pattern); 1693 } 1694 1695 /* NXT_CONF_STRING */ 1696 1697 return nxt_conf_vldt_match_encoded_pattern(vldt, value); 1698 } 1699 1700 1701 static nxt_int_t 1702 nxt_conf_vldt_match_encoded_pattern(nxt_conf_validation_t *vldt, 1703 nxt_conf_value_t *value) 1704 { 1705 u_char *p, *end; 1706 nxt_int_t ret; 1707 nxt_str_t pattern; 1708 1709 if (nxt_conf_type(value) != NXT_CONF_STRING) { 1710 return nxt_conf_vldt_error(vldt, "The \"match\" pattern for \"uri\" " 1711 "must be a string."); 1712 } 1713 1714 ret = nxt_conf_vldt_match_pattern(vldt, value); 1715 if (nxt_slow_path(ret != NXT_OK)) { 1716 return ret; 1717 } 1718 1719 nxt_conf_get_string(value, &pattern); 1720 1721 p = nxt_mp_nget(vldt->pool, pattern.length); 1722 if (nxt_slow_path(p == NULL)) { 1723 return NXT_ERROR; 1724 } 1725 1726 end = nxt_decode_uri(p, pattern.start, pattern.length); 1727 if (nxt_slow_path(end == NULL)) { 1728 return nxt_conf_vldt_error(vldt, "The \"match\" pattern for \"uri\" " 1729 "is encoded but is invalid."); 1730 } 1731 1732 return NXT_OK; 1733 } 1734 1735 1736 static nxt_int_t 1737 nxt_conf_vldt_match_addrs(nxt_conf_validation_t *vldt, 1738 nxt_conf_value_t *value, void *data) 1739 { 1740 if (nxt_conf_type(value) == NXT_CONF_ARRAY) { 1741 return nxt_conf_vldt_array_iterator(vldt, value, 1742 &nxt_conf_vldt_match_addr); 1743 } 1744 1745 return nxt_conf_vldt_match_addr(vldt, value); 1746 } 1747 1748 1749 static nxt_int_t 1750 nxt_conf_vldt_match_addr(nxt_conf_validation_t *vldt, 1751 nxt_conf_value_t *value) 1752 { 1753 nxt_http_route_addr_pattern_t pattern; 1754 1755 switch (nxt_http_route_addr_pattern_parse(vldt->pool, &pattern, value)) { 1756 1757 case NXT_OK: 1758 return NXT_OK; 1759 1760 case NXT_ADDR_PATTERN_PORT_ERROR: 1761 return nxt_conf_vldt_error(vldt, "The \"address\" port an invalid " 1762 "port."); 1763 1764 case NXT_ADDR_PATTERN_CV_TYPE_ERROR: 1765 return nxt_conf_vldt_error(vldt, "The \"match\" pattern for " 1766 "\"address\" must be a string."); 1767 1768 case NXT_ADDR_PATTERN_LENGTH_ERROR: 1769 return nxt_conf_vldt_error(vldt, "The \"address\" is too short."); 1770 1771 case NXT_ADDR_PATTERN_FORMAT_ERROR: 1772 return nxt_conf_vldt_error(vldt, "The \"address\" format is invalid."); 1773 1774 case NXT_ADDR_PATTERN_RANGE_OVERLAP_ERROR: 1775 return nxt_conf_vldt_error(vldt, "The \"address\" range is " 1776 "overlapping."); 1777 1778 case NXT_ADDR_PATTERN_CIDR_ERROR: 1779 return nxt_conf_vldt_error(vldt, "The \"address\" has an invalid CIDR " 1780 "prefix."); 1781 1782 case NXT_ADDR_PATTERN_NO_IPv6_ERROR: 1783 return nxt_conf_vldt_error(vldt, "The \"address\" does not support " 1784 "IPv6 with your configuration."); 1785 1786 default: 1787 return nxt_conf_vldt_error(vldt, "The \"address\" has an unknown " 1788 "format."); 1789 } 1790 } 1791 1792 1793 static nxt_int_t 1794 nxt_conf_vldt_match_scheme_pattern(nxt_conf_validation_t *vldt, 1795 nxt_conf_value_t *value, void *data) 1796 { 1797 nxt_str_t scheme; 1798 1799 static const nxt_str_t http = nxt_string("http"); 1800 static const nxt_str_t https = nxt_string("https"); 1801 1802 nxt_conf_get_string(value, &scheme); 1803 1804 if (nxt_strcasestr_eq(&scheme, &http) 1805 || nxt_strcasestr_eq(&scheme, &https)) 1806 { 1807 return NXT_OK; 1808 } 1809 1810 return nxt_conf_vldt_error(vldt, "The \"scheme\" can either be " 1811 "\"http\" or \"https\"."); 1812 } 1813 1814 1815 static nxt_int_t 1816 nxt_conf_vldt_match_patterns_sets(nxt_conf_validation_t *vldt, 1817 nxt_conf_value_t *value, void *data) 1818 { 1819 if (nxt_conf_type(value) == NXT_CONF_ARRAY) { 1820 return nxt_conf_vldt_array_iterator(vldt, value, 1821 &nxt_conf_vldt_match_patterns_set); 1822 } 1823 1824 /* NXT_CONF_OBJECT */ 1825 1826 return nxt_conf_vldt_match_patterns_set(vldt, value); 1827 } 1828 1829 1830 static nxt_int_t 1831 nxt_conf_vldt_match_patterns_set(nxt_conf_validation_t *vldt, 1832 nxt_conf_value_t *value) 1833 { 1834 if (nxt_conf_type(value) != NXT_CONF_OBJECT) { 1835 return nxt_conf_vldt_error(vldt, "The \"match\" patterns for " 1836 "\"arguments\", \"cookies\", and " 1837 "\"headers\" must be objects."); 1838 } 1839 1840 return nxt_conf_vldt_object_iterator(vldt, value, 1841 &nxt_conf_vldt_match_patterns_set_member); 1842 } 1843 1844 1845 static nxt_int_t 1846 nxt_conf_vldt_match_patterns_set_member(nxt_conf_validation_t *vldt, 1847 nxt_str_t *name, nxt_conf_value_t *value) 1848 { 1849 if (name->length == 0) { 1850 return nxt_conf_vldt_error(vldt, "The \"match\" pattern objects must " 1851 "not contain empty member names."); 1852 } 1853 1854 return nxt_conf_vldt_match_patterns(vldt, value, NULL); 1855 } 1856 1857 1858 #if (NXT_TLS) 1859 1860 static nxt_int_t 1861 nxt_conf_vldt_certificate(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, 1862 void *data) 1863 { 1864 if (nxt_conf_type(value) == NXT_CONF_ARRAY) { 1865 if (nxt_conf_array_elements_count(value) == 0) { 1866 return nxt_conf_vldt_error(vldt, "The \"certificate\" array " 1867 "must contain at least one element."); 1868 } 1869 1870 return nxt_conf_vldt_array_iterator(vldt, value, 1871 &nxt_conf_vldt_certificate_element); 1872 } 1873 1874 /* NXT_CONF_STRING */ 1875 1876 return nxt_conf_vldt_certificate_element(vldt, value); 1877 } 1878 1879 1880 static nxt_int_t 1881 nxt_conf_vldt_certificate_element(nxt_conf_validation_t *vldt, 1882 nxt_conf_value_t *value) 1883 { 1884 nxt_str_t name; 1885 nxt_conf_value_t *cert; 1886 1887 if (nxt_conf_type(value) != NXT_CONF_STRING) { 1888 return nxt_conf_vldt_error(vldt, "The \"certificate\" array must " 1889 "contain only string values."); 1890 } 1891 1892 nxt_conf_get_string(value, &name); 1893 1894 cert = nxt_cert_info_get(&name); 1895 1896 if (cert == NULL) { 1897 return nxt_conf_vldt_error(vldt, "Certificate \"%V\" is not found.", 1898 &name); 1899 } 1900 1901 return NXT_OK; 1902 } 1903 1904 #endif 1905 1906 1907 static nxt_int_t 1908 nxt_conf_vldt_app_name(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, 1909 void *data) 1910 { 1911 nxt_str_t name; 1912 nxt_conf_value_t *apps, *app; 1913 1914 static nxt_str_t apps_str = nxt_string("applications"); 1915 1916 nxt_conf_get_string(value, &name); 1917 1918 apps = nxt_conf_get_object_member(vldt->conf, &apps_str, NULL); 1919 1920 if (nxt_slow_path(apps == NULL)) { 1921 goto error; 1922 } 1923 1924 app = nxt_conf_get_object_member(apps, &name, NULL); 1925 1926 if (nxt_slow_path(app == NULL)) { 1927 goto error; 1928 } 1929 1930 return NXT_OK; 1931 1932 error: 1933 1934 return nxt_conf_vldt_error(vldt, "Listening socket is assigned for " 1935 "a non existing application \"%V\".", 1936 &name); 1937 } 1938 1939 1940 static nxt_int_t 1941 nxt_conf_vldt_app(nxt_conf_validation_t *vldt, nxt_str_t *name, 1942 nxt_conf_value_t *value) 1943 { 1944 nxt_int_t ret; 1945 nxt_str_t type; 1946 nxt_thread_t *thread; 1947 nxt_conf_value_t *type_value; 1948 nxt_app_lang_module_t *lang; 1949 1950 static nxt_str_t type_str = nxt_string("type"); 1951 1952 static struct { 1953 nxt_conf_vldt_handler_t validator; 1954 nxt_conf_vldt_object_t *members; 1955 1956 } types[] = { 1957 { nxt_conf_vldt_object, nxt_conf_vldt_external_members }, 1958 { nxt_conf_vldt_object, nxt_conf_vldt_python_members }, 1959 { nxt_conf_vldt_php, NULL }, 1960 { nxt_conf_vldt_object, nxt_conf_vldt_perl_members }, 1961 { nxt_conf_vldt_object, nxt_conf_vldt_ruby_members }, 1962 { nxt_conf_vldt_object, nxt_conf_vldt_java_members }, 1963 }; 1964 1965 ret = nxt_conf_vldt_type(vldt, name, value, NXT_CONF_VLDT_OBJECT); 1966 1967 if (ret != NXT_OK) { 1968 return ret; 1969 } 1970 1971 type_value = nxt_conf_get_object_member(value, &type_str, NULL); 1972 1973 if (type_value == NULL) { 1974 return nxt_conf_vldt_error(vldt, 1975 "Application must have the \"type\" property set."); 1976 } 1977 1978 ret = nxt_conf_vldt_type(vldt, &type_str, type_value, NXT_CONF_VLDT_STRING); 1979 1980 if (ret != NXT_OK) { 1981 return ret; 1982 } 1983 1984 nxt_conf_get_string(type_value, &type); 1985 1986 thread = nxt_thread(); 1987 1988 lang = nxt_app_lang_module(thread->runtime, &type); 1989 if (lang == NULL) { 1990 return nxt_conf_vldt_error(vldt, 1991 "The module to run \"%V\" is not found " 1992 "among the available application modules.", 1993 &type); 1994 } 1995 1996 return types[lang->type].validator(vldt, value, types[lang->type].members); 1997 } 1998 1999 2000 static nxt_int_t 2001 nxt_conf_vldt_object(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, 2002 void *data) 2003 { 2004 uint32_t index; 2005 nxt_int_t ret; 2006 nxt_str_t name; 2007 nxt_conf_value_t *member; 2008 nxt_conf_vldt_object_t *vals; 2009 2010 vals = data; 2011 2012 for ( ;; ) { 2013 if (vals->name.length == 0) { 2014 2015 if (vals->u.members != NULL) { 2016 vals = vals->u.members; 2017 continue; 2018 } 2019 2020 break; 2021 } 2022 2023 if (vals->flags & NXT_CONF_VLDT_REQUIRED) { 2024 member = nxt_conf_get_object_member(value, &vals->name, NULL); 2025 2026 if (member == NULL) { 2027 return nxt_conf_vldt_error(vldt, "Required parameter \"%V\" " 2028 "is missing.", &vals->name); 2029 } 2030 } 2031 2032 vals++; 2033 } 2034 2035 index = 0; 2036 2037 for ( ;; ) { 2038 member = nxt_conf_next_object_member(value, &name, &index); 2039 2040 if (member == NULL) { 2041 return NXT_OK; 2042 } 2043 2044 vals = data; 2045 2046 for ( ;; ) { 2047 if (vals->name.length == 0) { 2048 2049 if (vals->u.members != NULL) { 2050 vals = vals->u.members; 2051 continue; 2052 } 2053 2054 return nxt_conf_vldt_error(vldt, "Unknown parameter \"%V\".", 2055 &name); 2056 } 2057 2058 if (!nxt_strstr_eq(&vals->name, &name)) { 2059 vals++; 2060 continue; 2061 } 2062 2063 ret = nxt_conf_vldt_type(vldt, &name, member, vals->type); 2064 2065 if (ret != NXT_OK) { 2066 return ret; 2067 } 2068 2069 if (vals->validator != NULL) { 2070 ret = vals->validator(vldt, member, vals->u.members); 2071 2072 if (ret != NXT_OK) { 2073 return ret; 2074 } 2075 } 2076 2077 break; 2078 } 2079 } 2080 } 2081 2082 2083 typedef struct { 2084 int64_t spare; 2085 int64_t max; 2086 int64_t idle_timeout; 2087 } nxt_conf_vldt_processes_conf_t; 2088 2089 2090 static nxt_conf_map_t nxt_conf_vldt_processes_conf_map[] = { 2091 { 2092 nxt_string("spare"), 2093 NXT_CONF_MAP_INT64, 2094 offsetof(nxt_conf_vldt_processes_conf_t, spare), 2095 }, 2096 2097 { 2098 nxt_string("max"), 2099 NXT_CONF_MAP_INT64, 2100 offsetof(nxt_conf_vldt_processes_conf_t, max), 2101 }, 2102 2103 { 2104 nxt_string("idle_timeout"), 2105 NXT_CONF_MAP_INT64, 2106 offsetof(nxt_conf_vldt_processes_conf_t, idle_timeout), 2107 }, 2108 }; 2109 2110 2111 static nxt_int_t 2112 nxt_conf_vldt_processes(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, 2113 void *data) 2114 { 2115 int64_t int_value; 2116 nxt_int_t ret; 2117 nxt_conf_vldt_processes_conf_t proc; 2118 2119 if (nxt_conf_type(value) == NXT_CONF_NUMBER) { 2120 int_value = nxt_conf_get_number(value); 2121 2122 if (int_value < 1) { 2123 return nxt_conf_vldt_error(vldt, "The \"processes\" number must be " 2124 "equal to or greater than 1."); 2125 } 2126 2127 if (int_value > NXT_INT32_T_MAX) { 2128 return nxt_conf_vldt_error(vldt, "The \"processes\" number must " 2129 "not exceed %d.", NXT_INT32_T_MAX); 2130 } 2131 2132 return NXT_OK; 2133 } 2134 2135 ret = nxt_conf_vldt_object(vldt, value, data); 2136 if (ret != NXT_OK) { 2137 return ret; 2138 } 2139 2140 proc.spare = 0; 2141 proc.max = 1; 2142 proc.idle_timeout = 15; 2143 2144 ret = nxt_conf_map_object(vldt->pool, value, 2145 nxt_conf_vldt_processes_conf_map, 2146 nxt_nitems(nxt_conf_vldt_processes_conf_map), 2147 &proc); 2148 if (ret != NXT_OK) { 2149 return ret; 2150 } 2151 2152 if (proc.spare < 0) { 2153 return nxt_conf_vldt_error(vldt, "The \"spare\" number must not be " 2154 "negative."); 2155 } 2156 2157 if (proc.spare > NXT_INT32_T_MAX) { 2158 return nxt_conf_vldt_error(vldt, "The \"spare\" number must not " 2159 "exceed %d.", NXT_INT32_T_MAX); 2160 } 2161 2162 if (proc.max < 1) { 2163 return nxt_conf_vldt_error(vldt, "The \"max\" number must be equal " 2164 "to or greater than 1."); 2165 } 2166 2167 if (proc.max > NXT_INT32_T_MAX) { 2168 return nxt_conf_vldt_error(vldt, "The \"max\" number must not " 2169 "exceed %d.", NXT_INT32_T_MAX); 2170 } 2171 2172 if (proc.max < proc.spare) { 2173 return nxt_conf_vldt_error(vldt, "The \"spare\" number must be " 2174 "less than or equal to \"max\"."); 2175 } 2176 2177 if (proc.idle_timeout < 0) { 2178 return nxt_conf_vldt_error(vldt, "The \"idle_timeout\" number must not " 2179 "be negative."); 2180 } 2181 2182 if (proc.idle_timeout > NXT_INT32_T_MAX / 1000) { 2183 return nxt_conf_vldt_error(vldt, "The \"idle_timeout\" number must not " 2184 "exceed %d.", NXT_INT32_T_MAX / 1000); 2185 } 2186 2187 return NXT_OK; 2188 } 2189 2190 2191 static nxt_int_t 2192 nxt_conf_vldt_object_iterator(nxt_conf_validation_t *vldt, 2193 nxt_conf_value_t *value, void *data) 2194 { 2195 uint32_t index; 2196 nxt_int_t ret; 2197 nxt_str_t name; 2198 nxt_conf_value_t *member; 2199 nxt_conf_vldt_member_t validator; 2200 2201 validator = (nxt_conf_vldt_member_t) data; 2202 index = 0; 2203 2204 for ( ;; ) { 2205 member = nxt_conf_next_object_member(value, &name, &index); 2206 2207 if (member == NULL) { 2208 return NXT_OK; 2209 } 2210 2211 ret = validator(vldt, &name, member); 2212 2213 if (ret != NXT_OK) { 2214 return ret; 2215 } 2216 } 2217 } 2218 2219 2220 static nxt_int_t 2221 nxt_conf_vldt_array_iterator(nxt_conf_validation_t *vldt, 2222 nxt_conf_value_t *value, void *data) 2223 { 2224 uint32_t index; 2225 nxt_int_t ret; 2226 nxt_conf_value_t *element; 2227 nxt_conf_vldt_element_t validator; 2228 2229 validator = (nxt_conf_vldt_element_t) data; 2230 2231 for (index = 0; /* void */ ; index++) { 2232 element = nxt_conf_get_array_element(value, index); 2233 2234 if (element == NULL) { 2235 return NXT_OK; 2236 } 2237 2238 ret = validator(vldt, element); 2239 2240 if (ret != NXT_OK) { 2241 return ret; 2242 } 2243 } 2244 } 2245 2246 2247 static nxt_int_t 2248 nxt_conf_vldt_environment(nxt_conf_validation_t *vldt, nxt_str_t *name, 2249 nxt_conf_value_t *value) 2250 { 2251 nxt_str_t str; 2252 2253 if (name->length == 0) { 2254 return nxt_conf_vldt_error(vldt, 2255 "The environment name must not be empty."); 2256 } 2257 2258 if (nxt_memchr(name->start, '\0', name->length) != NULL) { 2259 return nxt_conf_vldt_error(vldt, "The environment name must not " 2260 "contain null character."); 2261 } 2262 2263 if (nxt_memchr(name->start, '=', name->length) != NULL) { 2264 return nxt_conf_vldt_error(vldt, "The environment name must not " 2265 "contain '=' character."); 2266 } 2267 2268 if (nxt_conf_type(value) != NXT_CONF_STRING) { 2269 return nxt_conf_vldt_error(vldt, "The \"%V\" environment value must be " 2270 "a string.", name); 2271 } 2272 2273 nxt_conf_get_string(value, &str); 2274 2275 if (nxt_memchr(str.start, '\0', str.length) != NULL) { 2276 return nxt_conf_vldt_error(vldt, "The \"%V\" environment value must " 2277 "not contain null character.", name); 2278 } 2279 2280 return NXT_OK; 2281 } 2282 2283 2284 static nxt_int_t 2285 nxt_conf_vldt_clone_namespaces(nxt_conf_validation_t *vldt, 2286 nxt_conf_value_t *value, void *data) 2287 { 2288 return nxt_conf_vldt_object(vldt, value, data); 2289 } 2290 2291 2292 static nxt_int_t 2293 nxt_conf_vldt_isolation(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, 2294 void *data) 2295 { 2296 return nxt_conf_vldt_object(vldt, value, data); 2297 } 2298 2299 2300 #if (NXT_HAVE_CLONE_NEWUSER) 2301 2302 typedef struct { 2303 nxt_int_t container; 2304 nxt_int_t host; 2305 nxt_int_t size; 2306 } nxt_conf_vldt_clone_procmap_conf_t; 2307 2308 2309 static nxt_conf_map_t nxt_conf_vldt_clone_procmap_conf_map[] = { 2310 { 2311 nxt_string("container"), 2312 NXT_CONF_MAP_INT32, 2313 offsetof(nxt_conf_vldt_clone_procmap_conf_t, container), 2314 }, 2315 2316 { 2317 nxt_string("host"), 2318 NXT_CONF_MAP_INT32, 2319 offsetof(nxt_conf_vldt_clone_procmap_conf_t, host), 2320 }, 2321 2322 { 2323 nxt_string("size"), 2324 NXT_CONF_MAP_INT32, 2325 offsetof(nxt_conf_vldt_clone_procmap_conf_t, size), 2326 }, 2327 2328 }; 2329 2330 2331 static nxt_int_t 2332 nxt_conf_vldt_clone_procmap(nxt_conf_validation_t *vldt, const char *mapfile, 2333 nxt_conf_value_t *value) 2334 { 2335 nxt_int_t ret; 2336 nxt_conf_vldt_clone_procmap_conf_t procmap; 2337 2338 procmap.container = -1; 2339 procmap.host = -1; 2340 procmap.size = -1; 2341 2342 ret = nxt_conf_map_object(vldt->pool, value, 2343 nxt_conf_vldt_clone_procmap_conf_map, 2344 nxt_nitems(nxt_conf_vldt_clone_procmap_conf_map), 2345 &procmap); 2346 if (ret != NXT_OK) { 2347 return ret; 2348 } 2349 2350 if (procmap.container == -1) { 2351 return nxt_conf_vldt_error(vldt, "The %s requires the " 2352 "\"container\" field set.", mapfile); 2353 } 2354 2355 if (procmap.host == -1) { 2356 return nxt_conf_vldt_error(vldt, "The %s requires the " 2357 "\"host\" field set.", mapfile); 2358 } 2359 2360 if (procmap.size == -1) { 2361 return nxt_conf_vldt_error(vldt, "The %s requires the " 2362 "\"size\" field set.", mapfile); 2363 } 2364 2365 return NXT_OK; 2366 } 2367 2368 2369 static nxt_int_t 2370 nxt_conf_vldt_clone_uidmap(nxt_conf_validation_t *vldt, nxt_conf_value_t *value) 2371 { 2372 nxt_int_t ret; 2373 2374 if (nxt_conf_type(value) != NXT_CONF_OBJECT) { 2375 return nxt_conf_vldt_error(vldt, "The \"uidmap\" array " 2376 "must contain only object values."); 2377 } 2378 2379 ret = nxt_conf_vldt_object(vldt, value, 2380 (void *) nxt_conf_vldt_app_procmap_members); 2381 if (nxt_slow_path(ret != NXT_OK)) { 2382 return ret; 2383 } 2384 2385 return nxt_conf_vldt_clone_procmap(vldt, "uid_map", value); 2386 } 2387 2388 2389 static nxt_int_t 2390 nxt_conf_vldt_clone_gidmap(nxt_conf_validation_t *vldt, nxt_conf_value_t *value) 2391 { 2392 nxt_int_t ret; 2393 2394 if (nxt_conf_type(value) != NXT_CONF_OBJECT) { 2395 return nxt_conf_vldt_error(vldt, "The \"gidmap\" array " 2396 "must contain only object values."); 2397 } 2398 2399 ret = nxt_conf_vldt_object(vldt, value, 2400 (void *) nxt_conf_vldt_app_procmap_members); 2401 if (nxt_slow_path(ret != NXT_OK)) { 2402 return ret; 2403 } 2404 2405 return nxt_conf_vldt_clone_procmap(vldt, "gid_map", value); 2406 } 2407 2408 #endif 2409 2410 2411 static nxt_int_t 2412 nxt_conf_vldt_argument(nxt_conf_validation_t *vldt, nxt_conf_value_t *value) 2413 { 2414 nxt_str_t str; 2415 2416 if (nxt_conf_type(value) != NXT_CONF_STRING) { 2417 return nxt_conf_vldt_error(vldt, "The \"arguments\" array " 2418 "must contain only string values."); 2419 } 2420 2421 nxt_conf_get_string(value, &str); 2422 2423 if (nxt_memchr(str.start, '\0', str.length) != NULL) { 2424 return nxt_conf_vldt_error(vldt, "The \"arguments\" array must not " 2425 "contain strings with null character."); 2426 } 2427 2428 return NXT_OK; 2429 } 2430 2431 2432 static nxt_int_t 2433 nxt_conf_vldt_php(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, 2434 void *data) 2435 { 2436 nxt_conf_value_t *targets; 2437 2438 static nxt_str_t targets_str = nxt_string("targets"); 2439 2440 targets = nxt_conf_get_object_member(value, &targets_str, NULL); 2441 2442 if (targets != NULL) { 2443 return nxt_conf_vldt_object(vldt, value, nxt_conf_vldt_php_members); 2444 } 2445 2446 return nxt_conf_vldt_object(vldt, value, 2447 nxt_conf_vldt_php_notargets_members); 2448 } 2449 2450 2451 static nxt_int_t 2452 nxt_conf_vldt_php_targets_exclusive(nxt_conf_validation_t *vldt, 2453 nxt_conf_value_t *value, void *data) 2454 { 2455 return nxt_conf_vldt_error(vldt, "The \"%s\" option is mutually exclusive " 2456 "with the \"targets\" object.", data); 2457 } 2458 2459 2460 static nxt_int_t 2461 nxt_conf_vldt_php_targets(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, 2462 void *data) 2463 { 2464 nxt_uint_t n; 2465 2466 n = nxt_conf_object_members_count(value); 2467 2468 if (n > 254) { 2469 return nxt_conf_vldt_error(vldt, "The \"targets\" object must not " 2470 "contain more than 254 members."); 2471 } 2472 2473 return nxt_conf_vldt_object_iterator(vldt, value, 2474 &nxt_conf_vldt_php_target); 2475 } 2476 2477 2478 static nxt_int_t 2479 nxt_conf_vldt_php_target(nxt_conf_validation_t *vldt, nxt_str_t *name, 2480 nxt_conf_value_t *value) 2481 { 2482 if (name->length == 0) { 2483 return nxt_conf_vldt_error(vldt, 2484 "The PHP target name must not be empty."); 2485 } 2486 2487 if (nxt_conf_type(value) != NXT_CONF_OBJECT) { 2488 return nxt_conf_vldt_error(vldt, "The \"%V\" PHP target must be " 2489 "an object.", name); 2490 } 2491 2492 return nxt_conf_vldt_object(vldt, value, &nxt_conf_vldt_php_target_members); 2493 } 2494 2495 2496 static nxt_int_t 2497 nxt_conf_vldt_php_option(nxt_conf_validation_t *vldt, nxt_str_t *name, 2498 nxt_conf_value_t *value) 2499 { 2500 if (name->length == 0) { 2501 return nxt_conf_vldt_error(vldt, 2502 "The PHP option name must not be empty."); 2503 } 2504 2505 if (nxt_conf_type(value) != NXT_CONF_STRING) { 2506 return nxt_conf_vldt_error(vldt, "The \"%V\" PHP option must be " 2507 "a string.", name); 2508 } 2509 2510 return NXT_OK; 2511 } 2512 2513 2514 static nxt_int_t 2515 nxt_conf_vldt_java_classpath(nxt_conf_validation_t *vldt, 2516 nxt_conf_value_t *value) 2517 { 2518 nxt_str_t str; 2519 2520 if (nxt_conf_type(value) != NXT_CONF_STRING) { 2521 return nxt_conf_vldt_error(vldt, "The \"classpath\" array " 2522 "must contain only string values."); 2523 } 2524 2525 nxt_conf_get_string(value, &str); 2526 2527 if (nxt_memchr(str.start, '\0', str.length) != NULL) { 2528 return nxt_conf_vldt_error(vldt, "The \"classpath\" array must not " 2529 "contain strings with null character."); 2530 } 2531 2532 return NXT_OK; 2533 } 2534 2535 2536 static nxt_int_t 2537 nxt_conf_vldt_java_option(nxt_conf_validation_t *vldt, nxt_conf_value_t *value) 2538 { 2539 nxt_str_t str; 2540 2541 if (nxt_conf_type(value) != NXT_CONF_STRING) { 2542 return nxt_conf_vldt_error(vldt, "The \"options\" array " 2543 "must contain only string values."); 2544 } 2545 2546 nxt_conf_get_string(value, &str); 2547 2548 if (nxt_memchr(str.start, '\0', str.length) != NULL) { 2549 return nxt_conf_vldt_error(vldt, "The \"options\" array must not " 2550 "contain strings with null character."); 2551 } 2552 2553 return NXT_OK; 2554 } 2555 2556 2557 static nxt_int_t 2558 nxt_conf_vldt_upstream(nxt_conf_validation_t *vldt, nxt_str_t *name, 2559 nxt_conf_value_t *value) 2560 { 2561 nxt_int_t ret; 2562 nxt_conf_value_t *conf; 2563 2564 static nxt_str_t servers = nxt_string("servers"); 2565 2566 ret = nxt_conf_vldt_type(vldt, name, value, NXT_CONF_VLDT_OBJECT); 2567 2568 if (ret != NXT_OK) { 2569 return ret; 2570 } 2571 2572 ret = nxt_conf_vldt_object(vldt, value, nxt_conf_vldt_upstream_members); 2573 2574 if (ret != NXT_OK) { 2575 return ret; 2576 } 2577 2578 conf = nxt_conf_get_object_member(value, &servers, NULL); 2579 if (conf == NULL) { 2580 return nxt_conf_vldt_error(vldt, "The \"%V\" upstream must contain " 2581 "\"servers\" object value.", name); 2582 } 2583 2584 return NXT_OK; 2585 } 2586 2587 2588 static nxt_int_t 2589 nxt_conf_vldt_server(nxt_conf_validation_t *vldt, nxt_str_t *name, 2590 nxt_conf_value_t *value) 2591 { 2592 nxt_int_t ret; 2593 nxt_sockaddr_t *sa; 2594 2595 ret = nxt_conf_vldt_type(vldt, name, value, NXT_CONF_VLDT_OBJECT); 2596 2597 if (ret != NXT_OK) { 2598 return ret; 2599 } 2600 2601 sa = nxt_sockaddr_parse(vldt->pool, name); 2602 2603 if (sa == NULL) { 2604 return nxt_conf_vldt_error(vldt, "The \"%V\" is not valid " 2605 "server address.", name); 2606 } 2607 2608 return nxt_conf_vldt_object(vldt, value, 2609 nxt_conf_vldt_upstream_server_members); 2610 } 2611 2612 2613 static nxt_int_t 2614 nxt_conf_vldt_server_weight(nxt_conf_validation_t *vldt, 2615 nxt_conf_value_t *value, void *data) 2616 { 2617 double num_value; 2618 2619 num_value = nxt_conf_get_number(value); 2620 2621 if (num_value < 0) { 2622 return nxt_conf_vldt_error(vldt, "The \"weight\" number must be " 2623 "positive."); 2624 } 2625 2626 if (num_value > 1000000) { 2627 return nxt_conf_vldt_error(vldt, "The \"weight\" number must " 2628 "not exceed 1,000,000"); 2629 } 2630 2631 return NXT_OK; 2632 } 2633