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