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