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