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