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