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