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