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