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