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_str_t str; 1484 nxt_sockaddr_t *sa; 1485 1486 if (nxt_slow_path(nxt_str_dup(vldt->pool, &str, name) == NULL)) { 1487 return NXT_ERROR; 1488 } 1489 1490 sa = nxt_sockaddr_parse(vldt->pool, &str); 1491 if (nxt_slow_path(sa == NULL)) { 1492 return nxt_conf_vldt_error(vldt, 1493 "The listener address \"%V\" is invalid.", 1494 name); 1495 } 1496 1497 ret = nxt_conf_vldt_type(vldt, name, value, NXT_CONF_VLDT_OBJECT); 1498 if (ret != NXT_OK) { 1499 return ret; 1500 } 1501 1502 return nxt_conf_vldt_object(vldt, value, nxt_conf_vldt_listener_members); 1503 } 1504 1505 1506 static nxt_int_t 1507 nxt_conf_vldt_action(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, 1508 void *data) 1509 { 1510 nxt_uint_t i; 1511 nxt_conf_value_t *action; 1512 nxt_conf_vldt_object_t *members; 1513 1514 static struct { 1515 nxt_str_t name; 1516 nxt_conf_vldt_object_t *members; 1517 1518 } actions[] = { 1519 { nxt_string("pass"), nxt_conf_vldt_pass_action_members }, 1520 { nxt_string("return"), nxt_conf_vldt_return_action_members }, 1521 { nxt_string("share"), nxt_conf_vldt_share_action_members }, 1522 { nxt_string("proxy"), nxt_conf_vldt_proxy_action_members }, 1523 }; 1524 1525 members = NULL; 1526 1527 for (i = 0; i < nxt_nitems(actions); i++) { 1528 action = nxt_conf_get_object_member(value, &actions[i].name, NULL); 1529 1530 if (action == NULL) { 1531 continue; 1532 } 1533 1534 if (members != NULL) { 1535 return nxt_conf_vldt_error(vldt, "The \"action\" object must have " 1536 "just one of \"pass\", \"return\", " 1537 "\"share\", or \"proxy\" options set."); 1538 } 1539 1540 members = actions[i].members; 1541 } 1542 1543 if (members == NULL) { 1544 return nxt_conf_vldt_error(vldt, "The \"action\" object must have " 1545 "either \"pass\", \"return\", \"share\", " 1546 "or \"proxy\" option set."); 1547 } 1548 1549 return nxt_conf_vldt_object(vldt, value, members); 1550 } 1551 1552 1553 static nxt_int_t 1554 nxt_conf_vldt_pass(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, 1555 void *data) 1556 { 1557 nxt_str_t pass; 1558 nxt_int_t ret; 1559 nxt_str_t segments[3]; 1560 1561 static nxt_str_t targets_str = nxt_string("targets"); 1562 1563 nxt_conf_get_string(value, &pass); 1564 1565 ret = nxt_http_pass_segments(vldt->pool, &pass, segments, 3); 1566 1567 if (ret != NXT_OK) { 1568 if (ret == NXT_DECLINED) { 1569 return nxt_conf_vldt_error(vldt, "Request \"pass\" value \"%V\" " 1570 "is invalid.", &pass); 1571 } 1572 1573 return NXT_ERROR; 1574 } 1575 1576 if (nxt_str_eq(&segments[0], "applications", 12)) { 1577 1578 if (segments[1].length == 0) { 1579 goto error; 1580 } 1581 1582 value = nxt_conf_get_object_member(vldt->conf, &segments[0], NULL); 1583 1584 if (value == NULL) { 1585 goto error; 1586 } 1587 1588 value = nxt_conf_get_object_member(value, &segments[1], NULL); 1589 1590 if (value == NULL) { 1591 goto error; 1592 } 1593 1594 if (segments[2].length > 0) { 1595 value = nxt_conf_get_object_member(value, &targets_str, NULL); 1596 1597 if (value == NULL) { 1598 goto error; 1599 } 1600 1601 value = nxt_conf_get_object_member(value, &segments[2], NULL); 1602 1603 if (value == NULL) { 1604 goto error; 1605 } 1606 } 1607 1608 return NXT_OK; 1609 } 1610 1611 if (nxt_str_eq(&segments[0], "upstreams", 9)) { 1612 1613 if (segments[1].length == 0 || segments[2].length != 0) { 1614 goto error; 1615 } 1616 1617 value = nxt_conf_get_object_member(vldt->conf, &segments[0], NULL); 1618 1619 if (value == NULL) { 1620 goto error; 1621 } 1622 1623 value = nxt_conf_get_object_member(value, &segments[1], NULL); 1624 1625 if (value == NULL) { 1626 goto error; 1627 } 1628 1629 return NXT_OK; 1630 } 1631 1632 if (nxt_str_eq(&segments[0], "routes", 6)) { 1633 1634 if (segments[2].length != 0) { 1635 goto error; 1636 } 1637 1638 value = nxt_conf_get_object_member(vldt->conf, &segments[0], NULL); 1639 1640 if (value == NULL) { 1641 goto error; 1642 } 1643 1644 if (segments[1].length == 0) { 1645 if (nxt_conf_type(value) != NXT_CONF_ARRAY) { 1646 goto error; 1647 } 1648 1649 return NXT_OK; 1650 } 1651 1652 if (nxt_conf_type(value) != NXT_CONF_OBJECT) { 1653 goto error; 1654 } 1655 1656 value = nxt_conf_get_object_member(value, &segments[1], NULL); 1657 1658 if (value == NULL) { 1659 goto error; 1660 } 1661 1662 return NXT_OK; 1663 } 1664 1665 error: 1666 1667 return nxt_conf_vldt_error(vldt, "Request \"pass\" points to invalid " 1668 "location \"%V\".", &pass); 1669 } 1670 1671 1672 static nxt_int_t 1673 nxt_conf_vldt_return(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, 1674 void *data) 1675 { 1676 int64_t status; 1677 1678 status = nxt_conf_get_number(value); 1679 1680 if (status < NXT_HTTP_INVALID || status > NXT_HTTP_STATUS_MAX) { 1681 return nxt_conf_vldt_error(vldt, "The \"return\" value is out of " 1682 "allowed HTTP status code range 0-999."); 1683 } 1684 1685 return NXT_OK; 1686 } 1687 1688 1689 static nxt_int_t 1690 nxt_conf_vldt_share(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, 1691 void *data) 1692 { 1693 u_char *p; 1694 nxt_str_t name, temp; 1695 1696 static nxt_str_t uri = nxt_string("$uri"); 1697 1698 if (nxt_conf_type(value) == NXT_CONF_ARRAY) { 1699 if (nxt_conf_array_elements_count(value) == 0) { 1700 return nxt_conf_vldt_error(vldt, "The \"share\" array " 1701 "must contain at least one element."); 1702 } 1703 1704 return nxt_conf_vldt_array_iterator(vldt, value, 1705 &nxt_conf_vldt_share_element); 1706 } 1707 1708 /* NXT_CONF_STRING */ 1709 1710 if (vldt->ver < 12600) { 1711 nxt_conf_get_string(value, &name); 1712 1713 temp.length = name.length + uri.length; 1714 1715 temp.start = nxt_mp_get(vldt->conf_pool, temp.length); 1716 if (nxt_slow_path(temp.start == NULL)) { 1717 return NXT_ERROR; 1718 } 1719 1720 p = nxt_cpymem(temp.start, name.start, name.length); 1721 nxt_memcpy(p, uri.start, uri.length); 1722 1723 nxt_conf_set_string(value, &temp); 1724 } 1725 1726 return nxt_conf_vldt_share_element(vldt, value); 1727 } 1728 1729 1730 static nxt_int_t 1731 nxt_conf_vldt_share_element(nxt_conf_validation_t *vldt, 1732 nxt_conf_value_t *value) 1733 { 1734 nxt_str_t str; 1735 1736 static nxt_str_t share = nxt_string("share"); 1737 1738 if (nxt_conf_type(value) != NXT_CONF_STRING) { 1739 return nxt_conf_vldt_error(vldt, "The \"share\" array must " 1740 "contain only string values."); 1741 } 1742 1743 nxt_conf_get_string(value, &str); 1744 1745 if (nxt_is_var(&str)) { 1746 return nxt_conf_vldt_var(vldt, &share, &str); 1747 } 1748 1749 return NXT_OK; 1750 } 1751 1752 1753 static nxt_int_t 1754 nxt_conf_vldt_proxy(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, 1755 void *data) 1756 { 1757 nxt_str_t name; 1758 nxt_sockaddr_t *sa; 1759 1760 nxt_conf_get_string(value, &name); 1761 1762 if (nxt_str_start(&name, "http://", 7)) { 1763 name.length -= 7; 1764 name.start += 7; 1765 1766 sa = nxt_sockaddr_parse(vldt->pool, &name); 1767 if (sa != NULL) { 1768 return NXT_OK; 1769 } 1770 } 1771 1772 return nxt_conf_vldt_error(vldt, "The \"proxy\" address is invalid \"%V\"", 1773 &name); 1774 } 1775 1776 1777 static nxt_int_t 1778 nxt_conf_vldt_python(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, 1779 void *data) 1780 { 1781 nxt_conf_value_t *targets; 1782 1783 static nxt_str_t targets_str = nxt_string("targets"); 1784 1785 targets = nxt_conf_get_object_member(value, &targets_str, NULL); 1786 1787 if (targets != NULL) { 1788 return nxt_conf_vldt_object(vldt, value, nxt_conf_vldt_python_members); 1789 } 1790 1791 return nxt_conf_vldt_object(vldt, value, 1792 nxt_conf_vldt_python_notargets_members); 1793 } 1794 1795 1796 static nxt_int_t 1797 nxt_conf_vldt_python_path(nxt_conf_validation_t *vldt, 1798 nxt_conf_value_t *value, void *data) 1799 { 1800 if (nxt_conf_type(value) == NXT_CONF_ARRAY) { 1801 return nxt_conf_vldt_array_iterator(vldt, value, 1802 &nxt_conf_vldt_python_path_element); 1803 } 1804 1805 /* NXT_CONF_STRING */ 1806 1807 return NXT_OK; 1808 } 1809 1810 1811 static nxt_int_t 1812 nxt_conf_vldt_python_path_element(nxt_conf_validation_t *vldt, 1813 nxt_conf_value_t *value) 1814 { 1815 if (nxt_conf_type(value) != NXT_CONF_STRING) { 1816 return nxt_conf_vldt_error(vldt, "The \"path\" array must contain " 1817 "only string values."); 1818 } 1819 1820 return NXT_OK; 1821 } 1822 1823 1824 static nxt_int_t 1825 nxt_conf_vldt_python_protocol(nxt_conf_validation_t *vldt, 1826 nxt_conf_value_t *value, void *data) 1827 { 1828 nxt_str_t proto; 1829 1830 static const nxt_str_t wsgi = nxt_string("wsgi"); 1831 static const nxt_str_t asgi = nxt_string("asgi"); 1832 1833 nxt_conf_get_string(value, &proto); 1834 1835 if (nxt_strstr_eq(&proto, &wsgi) || nxt_strstr_eq(&proto, &asgi)) { 1836 return NXT_OK; 1837 } 1838 1839 return nxt_conf_vldt_error(vldt, "The \"protocol\" can either be " 1840 "\"wsgi\" or \"asgi\"."); 1841 } 1842 1843 1844 static nxt_int_t 1845 nxt_conf_vldt_threads(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, 1846 void *data) 1847 { 1848 int64_t threads; 1849 1850 threads = nxt_conf_get_number(value); 1851 1852 if (threads < 1) { 1853 return nxt_conf_vldt_error(vldt, "The \"threads\" number must be " 1854 "equal to or greater than 1."); 1855 } 1856 1857 if (threads > NXT_INT32_T_MAX) { 1858 return nxt_conf_vldt_error(vldt, "The \"threads\" number must " 1859 "not exceed %d.", NXT_INT32_T_MAX); 1860 } 1861 1862 return NXT_OK; 1863 } 1864 1865 1866 static nxt_int_t 1867 nxt_conf_vldt_thread_stack_size(nxt_conf_validation_t *vldt, 1868 nxt_conf_value_t *value, void *data) 1869 { 1870 int64_t size, min_size; 1871 1872 size = nxt_conf_get_number(value); 1873 min_size = sysconf(_SC_THREAD_STACK_MIN); 1874 1875 if (size < min_size) { 1876 return nxt_conf_vldt_error(vldt, "The \"thread_stack_size\" number " 1877 "must be equal to or greater than %d.", 1878 min_size); 1879 } 1880 1881 if ((size % nxt_pagesize) != 0) { 1882 return nxt_conf_vldt_error(vldt, "The \"thread_stack_size\" number " 1883 "must be a multiple of the system page size (%d).", 1884 nxt_pagesize); 1885 } 1886 1887 return NXT_OK; 1888 } 1889 1890 1891 static nxt_int_t 1892 nxt_conf_vldt_routes(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, 1893 void *data) 1894 { 1895 if (nxt_conf_type(value) == NXT_CONF_ARRAY) { 1896 return nxt_conf_vldt_array_iterator(vldt, value, 1897 &nxt_conf_vldt_route); 1898 } 1899 1900 /* NXT_CONF_OBJECT */ 1901 1902 return nxt_conf_vldt_object_iterator(vldt, value, 1903 &nxt_conf_vldt_routes_member); 1904 } 1905 1906 1907 static nxt_int_t 1908 nxt_conf_vldt_routes_member(nxt_conf_validation_t *vldt, nxt_str_t *name, 1909 nxt_conf_value_t *value) 1910 { 1911 nxt_int_t ret; 1912 1913 ret = nxt_conf_vldt_type(vldt, name, value, NXT_CONF_VLDT_ARRAY); 1914 1915 if (ret != NXT_OK) { 1916 return ret; 1917 } 1918 1919 return nxt_conf_vldt_array_iterator(vldt, value, &nxt_conf_vldt_route); 1920 } 1921 1922 1923 static nxt_int_t 1924 nxt_conf_vldt_route(nxt_conf_validation_t *vldt, nxt_conf_value_t *value) 1925 { 1926 if (nxt_conf_type(value) != NXT_CONF_OBJECT) { 1927 return nxt_conf_vldt_error(vldt, "The \"routes\" array must contain " 1928 "only object values."); 1929 } 1930 1931 return nxt_conf_vldt_object(vldt, value, nxt_conf_vldt_route_members); 1932 } 1933 1934 1935 static nxt_int_t 1936 nxt_conf_vldt_match_patterns(nxt_conf_validation_t *vldt, 1937 nxt_conf_value_t *value, void *data) 1938 { 1939 nxt_int_t ret; 1940 1941 vldt->ctx = data; 1942 1943 if (nxt_conf_type(value) == NXT_CONF_ARRAY) { 1944 ret = nxt_conf_vldt_array_iterator(vldt, value, 1945 &nxt_conf_vldt_match_pattern); 1946 1947 } else { 1948 /* NXT_CONF_STRING */ 1949 ret = nxt_conf_vldt_match_pattern(vldt, value); 1950 } 1951 1952 vldt->ctx = NULL; 1953 1954 return ret; 1955 } 1956 1957 1958 static nxt_int_t 1959 nxt_conf_vldt_match_pattern(nxt_conf_validation_t *vldt, 1960 nxt_conf_value_t *value) 1961 { 1962 nxt_str_t pattern; 1963 nxt_uint_t i, first, last; 1964 #if (NXT_HAVE_REGEX) 1965 nxt_regex_t *re; 1966 nxt_regex_err_t err; 1967 #endif 1968 1969 if (nxt_conf_type(value) != NXT_CONF_STRING) { 1970 return nxt_conf_vldt_error(vldt, "The \"match\" pattern for \"%s\" " 1971 "must be strings.", vldt->ctx); 1972 } 1973 1974 nxt_conf_get_string(value, &pattern); 1975 1976 if (pattern.length == 0) { 1977 return NXT_OK; 1978 } 1979 1980 first = (pattern.start[0] == '!'); 1981 1982 if (first < pattern.length && pattern.start[first] == '~') { 1983 #if (NXT_HAVE_REGEX) 1984 pattern.start += first + 1; 1985 pattern.length -= first + 1; 1986 1987 re = nxt_regex_compile(vldt->pool, &pattern, &err); 1988 if (nxt_slow_path(re == NULL)) { 1989 if (err.offset < pattern.length) { 1990 return nxt_conf_vldt_error(vldt, "Invalid regular expression: " 1991 "%s at offset %d", 1992 err.msg, err.offset); 1993 } 1994 1995 return nxt_conf_vldt_error(vldt, "Invalid regular expression: %s", 1996 err.msg); 1997 } 1998 1999 return NXT_OK; 2000 #else 2001 return nxt_conf_vldt_error(vldt, "Unit is built without support of " 2002 "regular expressions: \"--no-regex\" " 2003 "./configure option was set."); 2004 #endif 2005 } 2006 2007 last = pattern.length - 1; 2008 2009 for (i = first; i < last; i++) { 2010 if (pattern.start[i] == '*' && pattern.start[i + 1] == '*') { 2011 return nxt_conf_vldt_error(vldt, "The \"match\" pattern must " 2012 "not contain double \"*\" markers."); 2013 } 2014 } 2015 2016 return NXT_OK; 2017 } 2018 2019 2020 static nxt_int_t nxt_conf_vldt_match_encoded_patterns_sets( 2021 nxt_conf_validation_t *vldt, nxt_conf_value_t *value, void *data) 2022 { 2023 if (nxt_conf_type(value) == NXT_CONF_ARRAY) { 2024 return nxt_conf_vldt_array_iterator(vldt, value, 2025 &nxt_conf_vldt_match_encoded_patterns_set); 2026 } 2027 2028 /* NXT_CONF_OBJECT */ 2029 2030 return nxt_conf_vldt_match_encoded_patterns_set(vldt, value); 2031 } 2032 2033 2034 static nxt_int_t nxt_conf_vldt_match_encoded_patterns_set( 2035 nxt_conf_validation_t *vldt, nxt_conf_value_t *value) 2036 { 2037 if (nxt_conf_type(value) != NXT_CONF_OBJECT) { 2038 return nxt_conf_vldt_error(vldt, "The \"match\" pattern for " 2039 "\"arguments\" must be an object."); 2040 } 2041 2042 return nxt_conf_vldt_object_iterator(vldt, value, 2043 &nxt_conf_vldt_match_encoded_patterns_set_member); 2044 } 2045 2046 2047 static nxt_int_t 2048 nxt_conf_vldt_match_encoded_patterns_set_member(nxt_conf_validation_t *vldt, 2049 nxt_str_t *name, nxt_conf_value_t *value) 2050 { 2051 u_char *p, *end; 2052 2053 if (nxt_slow_path(name->length == 0)) { 2054 return nxt_conf_vldt_error(vldt, "The \"match\" pattern objects must " 2055 "not contain empty member names."); 2056 } 2057 2058 p = nxt_mp_nget(vldt->pool, name->length); 2059 if (nxt_slow_path(p == NULL)) { 2060 return NXT_ERROR; 2061 } 2062 2063 end = nxt_decode_uri(p, name->start, name->length); 2064 if (nxt_slow_path(end == NULL)) { 2065 return nxt_conf_vldt_error(vldt, "The \"match\" pattern for " 2066 "\"arguments\" is encoded but is invalid."); 2067 } 2068 2069 return nxt_conf_vldt_match_encoded_patterns(vldt, value, 2070 (void *) "arguments"); 2071 } 2072 2073 2074 static nxt_int_t 2075 nxt_conf_vldt_match_encoded_patterns(nxt_conf_validation_t *vldt, 2076 nxt_conf_value_t *value, void *data) 2077 { 2078 nxt_int_t ret; 2079 2080 vldt->ctx = data; 2081 2082 if (nxt_conf_type(value) == NXT_CONF_ARRAY) { 2083 ret = nxt_conf_vldt_array_iterator(vldt, value, 2084 &nxt_conf_vldt_match_encoded_pattern); 2085 2086 } else { 2087 /* NXT_CONF_STRING */ 2088 ret = nxt_conf_vldt_match_encoded_pattern(vldt, value); 2089 } 2090 2091 vldt->ctx = NULL; 2092 2093 return ret; 2094 } 2095 2096 2097 static nxt_int_t 2098 nxt_conf_vldt_match_encoded_pattern(nxt_conf_validation_t *vldt, 2099 nxt_conf_value_t *value) 2100 { 2101 u_char *p, *end; 2102 nxt_int_t ret; 2103 nxt_str_t pattern; 2104 2105 if (nxt_conf_type(value) != NXT_CONF_STRING) { 2106 return nxt_conf_vldt_error(vldt, "The \"match\" pattern for \"%s\" " 2107 "must be a string.", vldt->ctx); 2108 } 2109 2110 ret = nxt_conf_vldt_match_pattern(vldt, value); 2111 if (nxt_slow_path(ret != NXT_OK)) { 2112 return ret; 2113 } 2114 2115 nxt_conf_get_string(value, &pattern); 2116 2117 p = nxt_mp_nget(vldt->pool, pattern.length); 2118 if (nxt_slow_path(p == NULL)) { 2119 return NXT_ERROR; 2120 } 2121 2122 end = nxt_decode_uri(p, pattern.start, pattern.length); 2123 if (nxt_slow_path(end == NULL)) { 2124 return nxt_conf_vldt_error(vldt, "The \"match\" pattern for \"%s\" " 2125 "is encoded but is invalid.", vldt->ctx); 2126 } 2127 2128 return NXT_OK; 2129 } 2130 2131 2132 static nxt_int_t 2133 nxt_conf_vldt_match_addrs(nxt_conf_validation_t *vldt, 2134 nxt_conf_value_t *value, void *data) 2135 { 2136 if (nxt_conf_type(value) == NXT_CONF_ARRAY) { 2137 return nxt_conf_vldt_array_iterator(vldt, value, 2138 &nxt_conf_vldt_match_addr); 2139 } 2140 2141 return nxt_conf_vldt_match_addr(vldt, value); 2142 } 2143 2144 2145 static nxt_int_t 2146 nxt_conf_vldt_match_addr(nxt_conf_validation_t *vldt, 2147 nxt_conf_value_t *value) 2148 { 2149 nxt_http_route_addr_pattern_t pattern; 2150 2151 switch (nxt_http_route_addr_pattern_parse(vldt->pool, &pattern, value)) { 2152 2153 case NXT_OK: 2154 return NXT_OK; 2155 2156 case NXT_ADDR_PATTERN_PORT_ERROR: 2157 return nxt_conf_vldt_error(vldt, "The \"address\" port an invalid " 2158 "port."); 2159 2160 case NXT_ADDR_PATTERN_CV_TYPE_ERROR: 2161 return nxt_conf_vldt_error(vldt, "The \"match\" pattern for " 2162 "\"address\" must be a string."); 2163 2164 case NXT_ADDR_PATTERN_LENGTH_ERROR: 2165 return nxt_conf_vldt_error(vldt, "The \"address\" is too short."); 2166 2167 case NXT_ADDR_PATTERN_FORMAT_ERROR: 2168 return nxt_conf_vldt_error(vldt, "The \"address\" format is invalid."); 2169 2170 case NXT_ADDR_PATTERN_RANGE_OVERLAP_ERROR: 2171 return nxt_conf_vldt_error(vldt, "The \"address\" range is " 2172 "overlapping."); 2173 2174 case NXT_ADDR_PATTERN_CIDR_ERROR: 2175 return nxt_conf_vldt_error(vldt, "The \"address\" has an invalid CIDR " 2176 "prefix."); 2177 2178 case NXT_ADDR_PATTERN_NO_IPv6_ERROR: 2179 return nxt_conf_vldt_error(vldt, "The \"address\" does not support " 2180 "IPv6 with your configuration."); 2181 2182 case NXT_ADDR_PATTERN_NO_UNIX_ERROR: 2183 return nxt_conf_vldt_error(vldt, "The \"address\" does not support " 2184 "UNIX domain sockets with your " 2185 "configuration."); 2186 2187 default: 2188 return nxt_conf_vldt_error(vldt, "The \"address\" has an unknown " 2189 "format."); 2190 } 2191 } 2192 2193 2194 static nxt_int_t 2195 nxt_conf_vldt_match_scheme_pattern(nxt_conf_validation_t *vldt, 2196 nxt_conf_value_t *value, void *data) 2197 { 2198 nxt_str_t scheme; 2199 2200 static const nxt_str_t http = nxt_string("http"); 2201 static const nxt_str_t https = nxt_string("https"); 2202 2203 nxt_conf_get_string(value, &scheme); 2204 2205 if (nxt_strcasestr_eq(&scheme, &http) 2206 || nxt_strcasestr_eq(&scheme, &https)) 2207 { 2208 return NXT_OK; 2209 } 2210 2211 return nxt_conf_vldt_error(vldt, "The \"scheme\" can either be " 2212 "\"http\" or \"https\"."); 2213 } 2214 2215 2216 static nxt_int_t 2217 nxt_conf_vldt_match_patterns_sets(nxt_conf_validation_t *vldt, 2218 nxt_conf_value_t *value, void *data) 2219 { 2220 nxt_int_t ret; 2221 2222 vldt->ctx = data; 2223 2224 if (nxt_conf_type(value) == NXT_CONF_ARRAY) { 2225 ret = nxt_conf_vldt_array_iterator(vldt, value, 2226 &nxt_conf_vldt_match_patterns_set); 2227 2228 } else { 2229 /* NXT_CONF_OBJECT */ 2230 ret = nxt_conf_vldt_match_patterns_set(vldt, value); 2231 } 2232 2233 vldt->ctx = NULL; 2234 2235 return ret; 2236 } 2237 2238 2239 static nxt_int_t 2240 nxt_conf_vldt_match_patterns_set(nxt_conf_validation_t *vldt, 2241 nxt_conf_value_t *value) 2242 { 2243 if (nxt_conf_type(value) != NXT_CONF_OBJECT) { 2244 return nxt_conf_vldt_error(vldt, "The \"match\" patterns for " 2245 "\"%s\" must be objects.", vldt->ctx); 2246 } 2247 2248 return nxt_conf_vldt_object_iterator(vldt, value, 2249 &nxt_conf_vldt_match_patterns_set_member); 2250 } 2251 2252 2253 static nxt_int_t 2254 nxt_conf_vldt_match_patterns_set_member(nxt_conf_validation_t *vldt, 2255 nxt_str_t *name, nxt_conf_value_t *value) 2256 { 2257 if (name->length == 0) { 2258 return nxt_conf_vldt_error(vldt, "The \"match\" pattern objects must " 2259 "not contain empty member names."); 2260 } 2261 2262 return nxt_conf_vldt_match_patterns(vldt, value, vldt->ctx); 2263 } 2264 2265 2266 #if (NXT_TLS) 2267 2268 static nxt_int_t 2269 nxt_conf_vldt_certificate(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, 2270 void *data) 2271 { 2272 if (nxt_conf_type(value) == NXT_CONF_ARRAY) { 2273 if (nxt_conf_array_elements_count(value) == 0) { 2274 return nxt_conf_vldt_error(vldt, "The \"certificate\" array " 2275 "must contain at least one element."); 2276 } 2277 2278 return nxt_conf_vldt_array_iterator(vldt, value, 2279 &nxt_conf_vldt_certificate_element); 2280 } 2281 2282 /* NXT_CONF_STRING */ 2283 2284 return nxt_conf_vldt_certificate_element(vldt, value); 2285 } 2286 2287 2288 static nxt_int_t 2289 nxt_conf_vldt_certificate_element(nxt_conf_validation_t *vldt, 2290 nxt_conf_value_t *value) 2291 { 2292 nxt_str_t name; 2293 nxt_conf_value_t *cert; 2294 2295 if (nxt_conf_type(value) != NXT_CONF_STRING) { 2296 return nxt_conf_vldt_error(vldt, "The \"certificate\" array must " 2297 "contain only string values."); 2298 } 2299 2300 nxt_conf_get_string(value, &name); 2301 2302 cert = nxt_cert_info_get(&name); 2303 2304 if (cert == NULL) { 2305 return nxt_conf_vldt_error(vldt, "Certificate \"%V\" is not found.", 2306 &name); 2307 } 2308 2309 return NXT_OK; 2310 } 2311 2312 2313 #if (NXT_HAVE_OPENSSL_CONF_CMD) 2314 2315 static nxt_int_t 2316 nxt_conf_vldt_object_conf_commands(nxt_conf_validation_t *vldt, 2317 nxt_conf_value_t *value, void *data) 2318 { 2319 uint32_t index; 2320 nxt_int_t ret; 2321 nxt_str_t name; 2322 nxt_conf_value_t *member; 2323 2324 index = 0; 2325 2326 for ( ;; ) { 2327 member = nxt_conf_next_object_member(value, &name, &index); 2328 2329 if (member == NULL) { 2330 break; 2331 } 2332 2333 ret = nxt_conf_vldt_type(vldt, &name, member, NXT_CONF_VLDT_STRING); 2334 if (ret != NXT_OK) { 2335 return ret; 2336 } 2337 } 2338 2339 return NXT_OK; 2340 } 2341 2342 #endif 2343 2344 #endif 2345 2346 2347 static nxt_int_t 2348 nxt_conf_vldt_app_name(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, 2349 void *data) 2350 { 2351 nxt_str_t name; 2352 nxt_conf_value_t *apps, *app; 2353 2354 static nxt_str_t apps_str = nxt_string("applications"); 2355 2356 nxt_conf_get_string(value, &name); 2357 2358 apps = nxt_conf_get_object_member(vldt->conf, &apps_str, NULL); 2359 2360 if (nxt_slow_path(apps == NULL)) { 2361 goto error; 2362 } 2363 2364 app = nxt_conf_get_object_member(apps, &name, NULL); 2365 2366 if (nxt_slow_path(app == NULL)) { 2367 goto error; 2368 } 2369 2370 return NXT_OK; 2371 2372 error: 2373 2374 return nxt_conf_vldt_error(vldt, "Listening socket is assigned for " 2375 "a non existing application \"%V\".", 2376 &name); 2377 } 2378 2379 2380 static nxt_int_t 2381 nxt_conf_vldt_forwarded(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, 2382 void *data) 2383 { 2384 nxt_conf_value_t *client_ip, *protocol; 2385 2386 static nxt_str_t client_ip_str = nxt_string("client_ip"); 2387 static nxt_str_t protocol_str = nxt_string("protocol"); 2388 2389 client_ip = nxt_conf_get_object_member(value, &client_ip_str, NULL); 2390 protocol = nxt_conf_get_object_member(value, &protocol_str, NULL); 2391 2392 if (client_ip == NULL && protocol == NULL) { 2393 return nxt_conf_vldt_error(vldt, "The \"forwarded\" object must have " 2394 "either \"client_ip\" or \"protocol\" " 2395 "option set."); 2396 } 2397 2398 return nxt_conf_vldt_object(vldt, value, nxt_conf_vldt_forwarded_members); 2399 } 2400 2401 2402 static nxt_int_t 2403 nxt_conf_vldt_app(nxt_conf_validation_t *vldt, nxt_str_t *name, 2404 nxt_conf_value_t *value) 2405 { 2406 nxt_int_t ret; 2407 nxt_str_t type; 2408 nxt_thread_t *thread; 2409 nxt_conf_value_t *type_value; 2410 nxt_app_lang_module_t *lang; 2411 2412 static nxt_str_t type_str = nxt_string("type"); 2413 2414 static struct { 2415 nxt_conf_vldt_handler_t validator; 2416 nxt_conf_vldt_object_t *members; 2417 2418 } types[] = { 2419 { nxt_conf_vldt_object, nxt_conf_vldt_external_members }, 2420 { nxt_conf_vldt_python, NULL }, 2421 { nxt_conf_vldt_php, NULL }, 2422 { nxt_conf_vldt_object, nxt_conf_vldt_perl_members }, 2423 { nxt_conf_vldt_object, nxt_conf_vldt_ruby_members }, 2424 { nxt_conf_vldt_object, nxt_conf_vldt_java_members }, 2425 }; 2426 2427 ret = nxt_conf_vldt_type(vldt, name, value, NXT_CONF_VLDT_OBJECT); 2428 2429 if (ret != NXT_OK) { 2430 return ret; 2431 } 2432 2433 type_value = nxt_conf_get_object_member(value, &type_str, NULL); 2434 2435 if (type_value == NULL) { 2436 return nxt_conf_vldt_error(vldt, 2437 "Application must have the \"type\" property set."); 2438 } 2439 2440 ret = nxt_conf_vldt_type(vldt, &type_str, type_value, NXT_CONF_VLDT_STRING); 2441 2442 if (ret != NXT_OK) { 2443 return ret; 2444 } 2445 2446 nxt_conf_get_string(type_value, &type); 2447 2448 thread = nxt_thread(); 2449 2450 lang = nxt_app_lang_module(thread->runtime, &type); 2451 if (lang == NULL) { 2452 return nxt_conf_vldt_error(vldt, 2453 "The module to run \"%V\" is not found " 2454 "among the available application modules.", 2455 &type); 2456 } 2457 2458 return types[lang->type].validator(vldt, value, types[lang->type].members); 2459 } 2460 2461 2462 static nxt_int_t 2463 nxt_conf_vldt_object(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, 2464 void *data) 2465 { 2466 uint32_t index; 2467 nxt_int_t ret; 2468 nxt_str_t name, var; 2469 nxt_conf_value_t *member; 2470 nxt_conf_vldt_object_t *vals; 2471 2472 vals = data; 2473 2474 for ( ;; ) { 2475 if (vals->name.length == 0) { 2476 2477 if (vals->u.members != NULL) { 2478 vals = vals->u.members; 2479 continue; 2480 } 2481 2482 break; 2483 } 2484 2485 if (vals->flags & NXT_CONF_VLDT_REQUIRED) { 2486 member = nxt_conf_get_object_member(value, &vals->name, NULL); 2487 2488 if (member == NULL) { 2489 return nxt_conf_vldt_error(vldt, "Required parameter \"%V\" " 2490 "is missing.", &vals->name); 2491 } 2492 } 2493 2494 vals++; 2495 } 2496 2497 index = 0; 2498 2499 for ( ;; ) { 2500 member = nxt_conf_next_object_member(value, &name, &index); 2501 2502 if (member == NULL) { 2503 return NXT_OK; 2504 } 2505 2506 vals = data; 2507 2508 for ( ;; ) { 2509 if (vals->name.length == 0) { 2510 2511 if (vals->u.members != NULL) { 2512 vals = vals->u.members; 2513 continue; 2514 } 2515 2516 return nxt_conf_vldt_error(vldt, "Unknown parameter \"%V\".", 2517 &name); 2518 } 2519 2520 if (!nxt_strstr_eq(&vals->name, &name)) { 2521 vals++; 2522 continue; 2523 } 2524 2525 if (vals->flags & NXT_CONF_VLDT_VAR 2526 && nxt_conf_type(member) == NXT_CONF_STRING) 2527 { 2528 nxt_conf_get_string(member, &var); 2529 2530 if (nxt_is_var(&var)) { 2531 ret = nxt_conf_vldt_var(vldt, &name, &var); 2532 if (ret != NXT_OK) { 2533 return ret; 2534 } 2535 2536 break; 2537 } 2538 } 2539 2540 ret = nxt_conf_vldt_type(vldt, &name, member, vals->type); 2541 if (ret != NXT_OK) { 2542 return ret; 2543 } 2544 2545 if (vals->validator != NULL) { 2546 ret = vals->validator(vldt, member, vals->u.members); 2547 2548 if (ret != NXT_OK) { 2549 return ret; 2550 } 2551 } 2552 2553 break; 2554 } 2555 } 2556 } 2557 2558 2559 typedef struct { 2560 int64_t spare; 2561 int64_t max; 2562 int64_t idle_timeout; 2563 } nxt_conf_vldt_processes_conf_t; 2564 2565 2566 static nxt_conf_map_t nxt_conf_vldt_processes_conf_map[] = { 2567 { 2568 nxt_string("spare"), 2569 NXT_CONF_MAP_INT64, 2570 offsetof(nxt_conf_vldt_processes_conf_t, spare), 2571 }, 2572 2573 { 2574 nxt_string("max"), 2575 NXT_CONF_MAP_INT64, 2576 offsetof(nxt_conf_vldt_processes_conf_t, max), 2577 }, 2578 2579 { 2580 nxt_string("idle_timeout"), 2581 NXT_CONF_MAP_INT64, 2582 offsetof(nxt_conf_vldt_processes_conf_t, idle_timeout), 2583 }, 2584 }; 2585 2586 2587 static nxt_int_t 2588 nxt_conf_vldt_processes(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, 2589 void *data) 2590 { 2591 int64_t int_value; 2592 nxt_int_t ret; 2593 nxt_conf_vldt_processes_conf_t proc; 2594 2595 if (nxt_conf_type(value) == NXT_CONF_NUMBER) { 2596 int_value = nxt_conf_get_number(value); 2597 2598 if (int_value < 1) { 2599 return nxt_conf_vldt_error(vldt, "The \"processes\" number must be " 2600 "equal to or greater than 1."); 2601 } 2602 2603 if (int_value > NXT_INT32_T_MAX) { 2604 return nxt_conf_vldt_error(vldt, "The \"processes\" number must " 2605 "not exceed %d.", NXT_INT32_T_MAX); 2606 } 2607 2608 return NXT_OK; 2609 } 2610 2611 ret = nxt_conf_vldt_object(vldt, value, data); 2612 if (ret != NXT_OK) { 2613 return ret; 2614 } 2615 2616 proc.spare = 0; 2617 proc.max = 1; 2618 proc.idle_timeout = 15; 2619 2620 ret = nxt_conf_map_object(vldt->pool, value, 2621 nxt_conf_vldt_processes_conf_map, 2622 nxt_nitems(nxt_conf_vldt_processes_conf_map), 2623 &proc); 2624 if (ret != NXT_OK) { 2625 return ret; 2626 } 2627 2628 if (proc.spare < 0) { 2629 return nxt_conf_vldt_error(vldt, "The \"spare\" number must not be " 2630 "negative."); 2631 } 2632 2633 if (proc.spare > NXT_INT32_T_MAX) { 2634 return nxt_conf_vldt_error(vldt, "The \"spare\" number must not " 2635 "exceed %d.", NXT_INT32_T_MAX); 2636 } 2637 2638 if (proc.max < 1) { 2639 return nxt_conf_vldt_error(vldt, "The \"max\" number must be equal " 2640 "to or greater than 1."); 2641 } 2642 2643 if (proc.max > NXT_INT32_T_MAX) { 2644 return nxt_conf_vldt_error(vldt, "The \"max\" number must not " 2645 "exceed %d.", NXT_INT32_T_MAX); 2646 } 2647 2648 if (proc.max < proc.spare) { 2649 return nxt_conf_vldt_error(vldt, "The \"spare\" number must be " 2650 "less than or equal to \"max\"."); 2651 } 2652 2653 if (proc.idle_timeout < 0) { 2654 return nxt_conf_vldt_error(vldt, "The \"idle_timeout\" number must not " 2655 "be negative."); 2656 } 2657 2658 if (proc.idle_timeout > NXT_INT32_T_MAX / 1000) { 2659 return nxt_conf_vldt_error(vldt, "The \"idle_timeout\" number must not " 2660 "exceed %d.", NXT_INT32_T_MAX / 1000); 2661 } 2662 2663 return NXT_OK; 2664 } 2665 2666 2667 static nxt_int_t 2668 nxt_conf_vldt_object_iterator(nxt_conf_validation_t *vldt, 2669 nxt_conf_value_t *value, void *data) 2670 { 2671 uint32_t index; 2672 nxt_int_t ret; 2673 nxt_str_t name; 2674 nxt_conf_value_t *member; 2675 nxt_conf_vldt_member_t validator; 2676 2677 validator = (nxt_conf_vldt_member_t) data; 2678 index = 0; 2679 2680 for ( ;; ) { 2681 member = nxt_conf_next_object_member(value, &name, &index); 2682 2683 if (member == NULL) { 2684 return NXT_OK; 2685 } 2686 2687 ret = validator(vldt, &name, member); 2688 2689 if (ret != NXT_OK) { 2690 return ret; 2691 } 2692 } 2693 } 2694 2695 2696 static nxt_int_t 2697 nxt_conf_vldt_array_iterator(nxt_conf_validation_t *vldt, 2698 nxt_conf_value_t *value, void *data) 2699 { 2700 uint32_t index; 2701 nxt_int_t ret; 2702 nxt_conf_value_t *element; 2703 nxt_conf_vldt_element_t validator; 2704 2705 validator = (nxt_conf_vldt_element_t) data; 2706 2707 for (index = 0; /* void */ ; index++) { 2708 element = nxt_conf_get_array_element(value, index); 2709 2710 if (element == NULL) { 2711 return NXT_OK; 2712 } 2713 2714 ret = validator(vldt, element); 2715 2716 if (ret != NXT_OK) { 2717 return ret; 2718 } 2719 } 2720 } 2721 2722 2723 static nxt_int_t 2724 nxt_conf_vldt_environment(nxt_conf_validation_t *vldt, nxt_str_t *name, 2725 nxt_conf_value_t *value) 2726 { 2727 nxt_str_t str; 2728 2729 if (name->length == 0) { 2730 return nxt_conf_vldt_error(vldt, 2731 "The environment name must not be empty."); 2732 } 2733 2734 if (nxt_memchr(name->start, '\0', name->length) != NULL) { 2735 return nxt_conf_vldt_error(vldt, "The environment name must not " 2736 "contain null character."); 2737 } 2738 2739 if (nxt_memchr(name->start, '=', name->length) != NULL) { 2740 return nxt_conf_vldt_error(vldt, "The environment name must not " 2741 "contain '=' character."); 2742 } 2743 2744 if (nxt_conf_type(value) != NXT_CONF_STRING) { 2745 return nxt_conf_vldt_error(vldt, "The \"%V\" environment value must be " 2746 "a string.", name); 2747 } 2748 2749 nxt_conf_get_string(value, &str); 2750 2751 if (nxt_memchr(str.start, '\0', str.length) != NULL) { 2752 return nxt_conf_vldt_error(vldt, "The \"%V\" environment value must " 2753 "not contain null character.", name); 2754 } 2755 2756 return NXT_OK; 2757 } 2758 2759 2760 static nxt_int_t 2761 nxt_conf_vldt_targets_exclusive(nxt_conf_validation_t *vldt, 2762 nxt_conf_value_t *value, void *data) 2763 { 2764 return nxt_conf_vldt_error(vldt, "The \"%s\" option is mutually exclusive " 2765 "with the \"targets\" object.", data); 2766 } 2767 2768 2769 static nxt_int_t 2770 nxt_conf_vldt_targets(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, 2771 void *data) 2772 { 2773 nxt_int_t ret; 2774 nxt_uint_t n; 2775 2776 n = nxt_conf_object_members_count(value); 2777 2778 if (n > 254) { 2779 return nxt_conf_vldt_error(vldt, "The \"targets\" object must not " 2780 "contain more than 254 members."); 2781 } 2782 2783 vldt->ctx = data; 2784 2785 ret = nxt_conf_vldt_object_iterator(vldt, value, &nxt_conf_vldt_target); 2786 2787 vldt->ctx = NULL; 2788 2789 return ret; 2790 } 2791 2792 2793 static nxt_int_t 2794 nxt_conf_vldt_target(nxt_conf_validation_t *vldt, nxt_str_t *name, 2795 nxt_conf_value_t *value) 2796 { 2797 if (name->length == 0) { 2798 return nxt_conf_vldt_error(vldt, 2799 "The target name must not be empty."); 2800 } 2801 2802 if (nxt_conf_type(value) != NXT_CONF_OBJECT) { 2803 return nxt_conf_vldt_error(vldt, "The \"%V\" target must be " 2804 "an object.", name); 2805 } 2806 2807 return nxt_conf_vldt_object(vldt, value, vldt->ctx); 2808 } 2809 2810 2811 static nxt_int_t 2812 nxt_conf_vldt_clone_namespaces(nxt_conf_validation_t *vldt, 2813 nxt_conf_value_t *value, void *data) 2814 { 2815 return nxt_conf_vldt_object(vldt, value, data); 2816 } 2817 2818 2819 static nxt_int_t 2820 nxt_conf_vldt_isolation(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, 2821 void *data) 2822 { 2823 return nxt_conf_vldt_object(vldt, value, data); 2824 } 2825 2826 2827 #if (NXT_HAVE_CLONE_NEWUSER) 2828 2829 typedef struct { 2830 nxt_int_t container; 2831 nxt_int_t host; 2832 nxt_int_t size; 2833 } nxt_conf_vldt_clone_procmap_conf_t; 2834 2835 2836 static nxt_conf_map_t nxt_conf_vldt_clone_procmap_conf_map[] = { 2837 { 2838 nxt_string("container"), 2839 NXT_CONF_MAP_INT32, 2840 offsetof(nxt_conf_vldt_clone_procmap_conf_t, container), 2841 }, 2842 2843 { 2844 nxt_string("host"), 2845 NXT_CONF_MAP_INT32, 2846 offsetof(nxt_conf_vldt_clone_procmap_conf_t, host), 2847 }, 2848 2849 { 2850 nxt_string("size"), 2851 NXT_CONF_MAP_INT32, 2852 offsetof(nxt_conf_vldt_clone_procmap_conf_t, size), 2853 }, 2854 2855 }; 2856 2857 2858 static nxt_int_t 2859 nxt_conf_vldt_clone_procmap(nxt_conf_validation_t *vldt, const char *mapfile, 2860 nxt_conf_value_t *value) 2861 { 2862 nxt_int_t ret; 2863 nxt_conf_vldt_clone_procmap_conf_t procmap; 2864 2865 procmap.container = -1; 2866 procmap.host = -1; 2867 procmap.size = -1; 2868 2869 ret = nxt_conf_map_object(vldt->pool, value, 2870 nxt_conf_vldt_clone_procmap_conf_map, 2871 nxt_nitems(nxt_conf_vldt_clone_procmap_conf_map), 2872 &procmap); 2873 if (ret != NXT_OK) { 2874 return ret; 2875 } 2876 2877 if (procmap.container == -1) { 2878 return nxt_conf_vldt_error(vldt, "The %s requires the " 2879 "\"container\" field set.", mapfile); 2880 } 2881 2882 if (procmap.host == -1) { 2883 return nxt_conf_vldt_error(vldt, "The %s requires the " 2884 "\"host\" field set.", mapfile); 2885 } 2886 2887 if (procmap.size == -1) { 2888 return nxt_conf_vldt_error(vldt, "The %s requires the " 2889 "\"size\" field set.", mapfile); 2890 } 2891 2892 return NXT_OK; 2893 } 2894 2895 2896 static nxt_int_t 2897 nxt_conf_vldt_clone_uidmap(nxt_conf_validation_t *vldt, nxt_conf_value_t *value) 2898 { 2899 nxt_int_t ret; 2900 2901 if (nxt_conf_type(value) != NXT_CONF_OBJECT) { 2902 return nxt_conf_vldt_error(vldt, "The \"uidmap\" array " 2903 "must contain only object values."); 2904 } 2905 2906 ret = nxt_conf_vldt_object(vldt, value, 2907 (void *) nxt_conf_vldt_app_procmap_members); 2908 if (nxt_slow_path(ret != NXT_OK)) { 2909 return ret; 2910 } 2911 2912 return nxt_conf_vldt_clone_procmap(vldt, "uid_map", value); 2913 } 2914 2915 2916 static nxt_int_t 2917 nxt_conf_vldt_clone_gidmap(nxt_conf_validation_t *vldt, nxt_conf_value_t *value) 2918 { 2919 nxt_int_t ret; 2920 2921 if (nxt_conf_type(value) != NXT_CONF_OBJECT) { 2922 return nxt_conf_vldt_error(vldt, "The \"gidmap\" array " 2923 "must contain only object values."); 2924 } 2925 2926 ret = nxt_conf_vldt_object(vldt, value, 2927 (void *) nxt_conf_vldt_app_procmap_members); 2928 if (nxt_slow_path(ret != NXT_OK)) { 2929 return ret; 2930 } 2931 2932 return nxt_conf_vldt_clone_procmap(vldt, "gid_map", value); 2933 } 2934 2935 #endif 2936 2937 2938 static nxt_int_t 2939 nxt_conf_vldt_argument(nxt_conf_validation_t *vldt, nxt_conf_value_t *value) 2940 { 2941 nxt_str_t str; 2942 2943 if (nxt_conf_type(value) != NXT_CONF_STRING) { 2944 return nxt_conf_vldt_error(vldt, "The \"arguments\" array " 2945 "must contain only string values."); 2946 } 2947 2948 nxt_conf_get_string(value, &str); 2949 2950 if (nxt_memchr(str.start, '\0', str.length) != NULL) { 2951 return nxt_conf_vldt_error(vldt, "The \"arguments\" array must not " 2952 "contain strings with null character."); 2953 } 2954 2955 return NXT_OK; 2956 } 2957 2958 2959 static nxt_int_t 2960 nxt_conf_vldt_php(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, 2961 void *data) 2962 { 2963 nxt_conf_value_t *targets; 2964 2965 static nxt_str_t targets_str = nxt_string("targets"); 2966 2967 targets = nxt_conf_get_object_member(value, &targets_str, NULL); 2968 2969 if (targets != NULL) { 2970 return nxt_conf_vldt_object(vldt, value, nxt_conf_vldt_php_members); 2971 } 2972 2973 return nxt_conf_vldt_object(vldt, value, 2974 nxt_conf_vldt_php_notargets_members); 2975 } 2976 2977 2978 static nxt_int_t 2979 nxt_conf_vldt_php_option(nxt_conf_validation_t *vldt, nxt_str_t *name, 2980 nxt_conf_value_t *value) 2981 { 2982 if (name->length == 0) { 2983 return nxt_conf_vldt_error(vldt, 2984 "The PHP option name must not be empty."); 2985 } 2986 2987 if (nxt_conf_type(value) != NXT_CONF_STRING) { 2988 return nxt_conf_vldt_error(vldt, "The \"%V\" PHP option must be " 2989 "a string.", name); 2990 } 2991 2992 return NXT_OK; 2993 } 2994 2995 2996 static nxt_int_t 2997 nxt_conf_vldt_java_classpath(nxt_conf_validation_t *vldt, 2998 nxt_conf_value_t *value) 2999 { 3000 nxt_str_t str; 3001 3002 if (nxt_conf_type(value) != NXT_CONF_STRING) { 3003 return nxt_conf_vldt_error(vldt, "The \"classpath\" array " 3004 "must contain only string values."); 3005 } 3006 3007 nxt_conf_get_string(value, &str); 3008 3009 if (nxt_memchr(str.start, '\0', str.length) != NULL) { 3010 return nxt_conf_vldt_error(vldt, "The \"classpath\" array must not " 3011 "contain strings with null character."); 3012 } 3013 3014 return NXT_OK; 3015 } 3016 3017 3018 static nxt_int_t 3019 nxt_conf_vldt_java_option(nxt_conf_validation_t *vldt, nxt_conf_value_t *value) 3020 { 3021 nxt_str_t str; 3022 3023 if (nxt_conf_type(value) != NXT_CONF_STRING) { 3024 return nxt_conf_vldt_error(vldt, "The \"options\" array " 3025 "must contain only string values."); 3026 } 3027 3028 nxt_conf_get_string(value, &str); 3029 3030 if (nxt_memchr(str.start, '\0', str.length) != NULL) { 3031 return nxt_conf_vldt_error(vldt, "The \"options\" array must not " 3032 "contain strings with null character."); 3033 } 3034 3035 return NXT_OK; 3036 } 3037 3038 3039 static nxt_int_t 3040 nxt_conf_vldt_upstream(nxt_conf_validation_t *vldt, nxt_str_t *name, 3041 nxt_conf_value_t *value) 3042 { 3043 nxt_int_t ret; 3044 nxt_conf_value_t *conf; 3045 3046 static nxt_str_t servers = nxt_string("servers"); 3047 3048 ret = nxt_conf_vldt_type(vldt, name, value, NXT_CONF_VLDT_OBJECT); 3049 3050 if (ret != NXT_OK) { 3051 return ret; 3052 } 3053 3054 ret = nxt_conf_vldt_object(vldt, value, nxt_conf_vldt_upstream_members); 3055 3056 if (ret != NXT_OK) { 3057 return ret; 3058 } 3059 3060 conf = nxt_conf_get_object_member(value, &servers, NULL); 3061 if (conf == NULL) { 3062 return nxt_conf_vldt_error(vldt, "The \"%V\" upstream must contain " 3063 "\"servers\" object value.", name); 3064 } 3065 3066 return NXT_OK; 3067 } 3068 3069 3070 static nxt_int_t 3071 nxt_conf_vldt_server(nxt_conf_validation_t *vldt, nxt_str_t *name, 3072 nxt_conf_value_t *value) 3073 { 3074 nxt_int_t ret; 3075 nxt_sockaddr_t *sa; 3076 3077 ret = nxt_conf_vldt_type(vldt, name, value, NXT_CONF_VLDT_OBJECT); 3078 3079 if (ret != NXT_OK) { 3080 return ret; 3081 } 3082 3083 sa = nxt_sockaddr_parse(vldt->pool, name); 3084 3085 if (sa == NULL) { 3086 return nxt_conf_vldt_error(vldt, "The \"%V\" is not valid " 3087 "server address.", name); 3088 } 3089 3090 return nxt_conf_vldt_object(vldt, value, 3091 nxt_conf_vldt_upstream_server_members); 3092 } 3093 3094 3095 static nxt_int_t 3096 nxt_conf_vldt_server_weight(nxt_conf_validation_t *vldt, 3097 nxt_conf_value_t *value, void *data) 3098 { 3099 double num_value; 3100 3101 num_value = nxt_conf_get_number(value); 3102 3103 if (num_value < 0) { 3104 return nxt_conf_vldt_error(vldt, "The \"weight\" number must be " 3105 "positive."); 3106 } 3107 3108 if (num_value > 1000000) { 3109 return nxt_conf_vldt_error(vldt, "The \"weight\" number must " 3110 "not exceed 1,000,000"); 3111 } 3112 3113 return NXT_OK; 3114 } 3115 3116 3117 typedef struct { 3118 nxt_str_t path; 3119 nxt_str_t format; 3120 } nxt_conf_vldt_access_log_conf_t; 3121 3122 3123 static nxt_conf_map_t nxt_conf_vldt_access_log_map[] = { 3124 { 3125 nxt_string("path"), 3126 NXT_CONF_MAP_STR, 3127 offsetof(nxt_conf_vldt_access_log_conf_t, path), 3128 }, 3129 3130 { 3131 nxt_string("format"), 3132 NXT_CONF_MAP_STR, 3133 offsetof(nxt_conf_vldt_access_log_conf_t, format), 3134 }, 3135 }; 3136 3137 3138 static nxt_int_t 3139 nxt_conf_vldt_access_log(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, 3140 void *data) 3141 { 3142 nxt_int_t ret; 3143 nxt_conf_vldt_access_log_conf_t conf; 3144 3145 static nxt_str_t format_str = nxt_string("format"); 3146 3147 if (nxt_conf_type(value) == NXT_CONF_STRING) { 3148 return NXT_OK; 3149 } 3150 3151 ret = nxt_conf_vldt_object(vldt, value, nxt_conf_vldt_access_log_members); 3152 if (ret != NXT_OK) { 3153 return ret; 3154 } 3155 3156 nxt_memzero(&conf, sizeof(nxt_conf_vldt_access_log_conf_t)); 3157 3158 ret = nxt_conf_map_object(vldt->pool, value, 3159 nxt_conf_vldt_access_log_map, 3160 nxt_nitems(nxt_conf_vldt_access_log_map), 3161 &conf); 3162 if (ret != NXT_OK) { 3163 return ret; 3164 } 3165 3166 if (conf.path.length == 0) { 3167 return nxt_conf_vldt_error(vldt, 3168 "The \"path\" string must not be empty."); 3169 } 3170 3171 if (nxt_is_var(&conf.format)) { 3172 return nxt_conf_vldt_var(vldt, &format_str, &conf.format); 3173 } 3174 3175 return NXT_OK; 3176 } 3177