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