/*
* Copyright (C) Valentin V. Bartenev
* Copyright (C) NGINX, Inc.
* Copyright 2024, Alejandro Colomar <alx@kernel.org>
*/
#include <nxt_main.h>
#include <nxt_conf.h>
#include <nxt_cert.h>
#include <nxt_script.h>
#include <nxt_router.h>
#include <nxt_http.h>
#include <nxt_sockaddr.h>
#include <nxt_http_route_addr.h>
#include <nxt_regex.h>
typedef enum {
NXT_CONF_VLDT_NULL = 1 << NXT_CONF_NULL,
NXT_CONF_VLDT_BOOLEAN = 1 << NXT_CONF_BOOLEAN,
NXT_CONF_VLDT_INTEGER = 1 << NXT_CONF_INTEGER,
NXT_CONF_VLDT_NUMBER = (1 << NXT_CONF_NUMBER) | NXT_CONF_VLDT_INTEGER,
NXT_CONF_VLDT_STRING = 1 << NXT_CONF_STRING,
NXT_CONF_VLDT_ARRAY = 1 << NXT_CONF_ARRAY,
NXT_CONF_VLDT_OBJECT = 1 << NXT_CONF_OBJECT,
} nxt_conf_vldt_type_t;
#define NXT_CONF_VLDT_ANY_TYPE (NXT_CONF_VLDT_NULL \
|NXT_CONF_VLDT_BOOLEAN \
|NXT_CONF_VLDT_NUMBER \
|NXT_CONF_VLDT_STRING \
|NXT_CONF_VLDT_ARRAY \
|NXT_CONF_VLDT_OBJECT)
typedef enum {
NXT_CONF_VLDT_REQUIRED = 1 << 0,
NXT_CONF_VLDT_TSTR = 1 << 1,
} nxt_conf_vldt_flags_t;
typedef nxt_int_t (*nxt_conf_vldt_handler_t)(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value,
void *data);
typedef nxt_int_t (*nxt_conf_vldt_member_t)(nxt_conf_validation_t *vldt,
nxt_str_t *name,
nxt_conf_value_t *value);
typedef nxt_int_t (*nxt_conf_vldt_element_t)(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value);
typedef struct nxt_conf_vldt_object_s nxt_conf_vldt_object_t;
struct nxt_conf_vldt_object_s {
nxt_str_t name;
nxt_conf_vldt_type_t type:32;
nxt_conf_vldt_flags_t flags:32;
nxt_conf_vldt_handler_t validator;
union {
nxt_conf_vldt_object_t *members;
nxt_conf_vldt_object_t *next;
nxt_conf_vldt_member_t object;
nxt_conf_vldt_element_t array;
const char *string;
} u;
};
#define NXT_CONF_VLDT_NEXT(next) { .u.members = next }
#define NXT_CONF_VLDT_END { .name = nxt_null_string }
static nxt_int_t nxt_conf_vldt_type(nxt_conf_validation_t *vldt,
const nxt_str_t *name, nxt_conf_value_t *value, nxt_conf_vldt_type_t type);
static nxt_int_t nxt_conf_vldt_error(nxt_conf_validation_t *vldt,
const char *fmt, ...);
static nxt_int_t nxt_conf_vldt_var(nxt_conf_validation_t *vldt,
const nxt_str_t *name, nxt_str_t *value);
static nxt_int_t nxt_conf_vldt_if(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data);
nxt_inline nxt_int_t nxt_conf_vldt_unsupported(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data)
NXT_MAYBE_UNUSED;
static nxt_int_t nxt_conf_vldt_mtypes(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data);
static nxt_int_t nxt_conf_vldt_mtypes_type(nxt_conf_validation_t *vldt,
nxt_str_t *name, nxt_conf_value_t *value);
static nxt_int_t nxt_conf_vldt_mtypes_extension(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value);
static nxt_int_t nxt_conf_vldt_listener(nxt_conf_validation_t *vldt,
nxt_str_t *name, nxt_conf_value_t *value);
#if (NXT_TLS)
static nxt_int_t nxt_conf_vldt_certificate(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data);
#if (NXT_HAVE_OPENSSL_CONF_CMD)
static nxt_int_t nxt_conf_vldt_object_conf_commands(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data);
#endif
static nxt_int_t nxt_conf_vldt_certificate_element(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value);
static nxt_int_t nxt_conf_vldt_tls_cache_size(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data);
static nxt_int_t nxt_conf_vldt_tls_timeout(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data);
#if (NXT_HAVE_OPENSSL_TLSEXT)
static nxt_int_t nxt_conf_vldt_ticket_key(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data);
static nxt_int_t nxt_conf_vldt_ticket_key_element(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value);
#endif
#endif
static nxt_int_t nxt_conf_vldt_action(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data);
static nxt_int_t nxt_conf_vldt_pass(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data);
static nxt_int_t nxt_conf_vldt_return(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data);
static nxt_int_t nxt_conf_vldt_share(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data);
static nxt_int_t nxt_conf_vldt_share_element(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value);
static nxt_int_t nxt_conf_vldt_proxy(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data);
static nxt_int_t nxt_conf_vldt_python(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data);
static nxt_int_t nxt_conf_vldt_python_path(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data);
static nxt_int_t nxt_conf_vldt_python_path_element(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value);
static nxt_int_t nxt_conf_vldt_python_protocol(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data);
static nxt_int_t nxt_conf_vldt_python_prefix(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data);
static nxt_int_t nxt_conf_vldt_listen_threads(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data);
static nxt_int_t nxt_conf_vldt_threads(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data);
static nxt_int_t nxt_conf_vldt_thread_stack_size(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data);
static nxt_int_t nxt_conf_vldt_routes(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data);
static nxt_int_t nxt_conf_vldt_routes_member(nxt_conf_validation_t *vldt,
nxt_str_t *name, nxt_conf_value_t *value);
static nxt_int_t nxt_conf_vldt_route(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value);
static nxt_int_t nxt_conf_vldt_match_encoded_patterns_sets(
nxt_conf_validation_t *vldt, nxt_conf_value_t *value, void *data);
static nxt_int_t nxt_conf_vldt_match_encoded_patterns_set(
nxt_conf_validation_t *vldt, nxt_conf_value_t *value);
static nxt_int_t nxt_conf_vldt_match_encoded_patterns_set_member(
nxt_conf_validation_t *vldt, nxt_str_t *name, nxt_conf_value_t *value);
static nxt_int_t nxt_conf_vldt_match_encoded_patterns(
nxt_conf_validation_t *vldt, nxt_conf_value_t *value, void *data);
static nxt_int_t nxt_conf_vldt_match_encoded_pattern(
nxt_conf_validation_t *vldt, nxt_conf_value_t *value);
static nxt_int_t nxt_conf_vldt_match_patterns(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data);
static nxt_int_t nxt_conf_vldt_match_pattern(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value);
static nxt_int_t nxt_conf_vldt_match_patterns_sets(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data);
static nxt_int_t nxt_conf_vldt_match_patterns_set(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value);
static nxt_int_t nxt_conf_vldt_match_patterns_set_member(
nxt_conf_validation_t *vldt, nxt_str_t *name, nxt_conf_value_t *value);
static nxt_int_t nxt_conf_vldt_match_scheme_pattern(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data);
static nxt_int_t nxt_conf_vldt_match_addrs(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data);
static nxt_int_t nxt_conf_vldt_match_addr(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value);
static nxt_int_t nxt_conf_vldt_response_header(nxt_conf_validation_t *vldt,
nxt_str_t *name, nxt_conf_value_t *value);
static nxt_int_t nxt_conf_vldt_app_name(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data);
static nxt_int_t nxt_conf_vldt_forwarded(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data);
static nxt_int_t nxt_conf_vldt_listen_backlog(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data);
static nxt_int_t nxt_conf_vldt_app(nxt_conf_validation_t *vldt,
nxt_str_t *name, nxt_conf_value_t *value);
static nxt_int_t nxt_conf_vldt_object(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data);
static nxt_int_t nxt_conf_vldt_processes(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data);
static nxt_int_t nxt_conf_vldt_object_iterator(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data);
static nxt_int_t nxt_conf_vldt_array_iterator(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data);
static nxt_int_t nxt_conf_vldt_environment(nxt_conf_validation_t *vldt,
nxt_str_t *name, nxt_conf_value_t *value);
static nxt_int_t nxt_conf_vldt_targets_exclusive(
nxt_conf_validation_t *vldt, nxt_conf_value_t *value, void *data);
static nxt_int_t nxt_conf_vldt_targets(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data);
static nxt_int_t nxt_conf_vldt_target(nxt_conf_validation_t *vldt,
nxt_str_t *name, nxt_conf_value_t *value);
static nxt_int_t nxt_conf_vldt_argument(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value);
static nxt_int_t nxt_conf_vldt_php(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data);
static nxt_int_t nxt_conf_vldt_php_option(nxt_conf_validation_t *vldt,
nxt_str_t *name, nxt_conf_value_t *value);
static nxt_int_t nxt_conf_vldt_java_classpath(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value);
static nxt_int_t nxt_conf_vldt_java_option(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value);
static nxt_int_t nxt_conf_vldt_upstream(nxt_conf_validation_t *vldt,
nxt_str_t *name, nxt_conf_value_t *value);
static nxt_int_t nxt_conf_vldt_server(nxt_conf_validation_t *vldt,
nxt_str_t *name, nxt_conf_value_t *value);
static nxt_int_t nxt_conf_vldt_server_weight(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data);
static nxt_int_t nxt_conf_vldt_access_log(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data);
static nxt_int_t nxt_conf_vldt_access_log_format(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data);
static nxt_int_t nxt_conf_vldt_access_log_format_field(
nxt_conf_validation_t *vldt, const nxt_str_t *name,
nxt_conf_value_t *value);
static nxt_int_t nxt_conf_vldt_isolation(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data);
static nxt_int_t nxt_conf_vldt_clone_namespaces(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data);
#if (NXT_HAVE_CLONE_NEWUSER)
static nxt_int_t nxt_conf_vldt_clone_uidmap(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value);
static nxt_int_t nxt_conf_vldt_clone_gidmap(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value);
#endif
#if (NXT_HAVE_CGROUP)
static nxt_int_t nxt_conf_vldt_cgroup_path(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data);
#endif
#if (NXT_HAVE_NJS)
static nxt_int_t nxt_conf_vldt_js_module(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data);
static nxt_int_t nxt_conf_vldt_js_module_element(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value);
#endif
#if (NXT_HAVE_OTEL)
static nxt_int_t nxt_otel_validate_batch_size(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data);
static nxt_int_t nxt_otel_validate_sample_ratio(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data);
static nxt_int_t nxt_otel_validate_protocol(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data);
#endif
static nxt_conf_vldt_object_t nxt_conf_vldt_setting_members[];
static nxt_conf_vldt_object_t nxt_conf_vldt_http_members[];
#if (NXT_HAVE_OTEL)
static nxt_conf_vldt_object_t nxt_conf_vldt_otel_members[];
#endif
static nxt_conf_vldt_object_t nxt_conf_vldt_websocket_members[];
static nxt_conf_vldt_object_t nxt_conf_vldt_static_members[];
static nxt_conf_vldt_object_t nxt_conf_vldt_forwarded_members[];
static nxt_conf_vldt_object_t nxt_conf_vldt_client_ip_members[];
#if (NXT_TLS)
static nxt_conf_vldt_object_t nxt_conf_vldt_tls_members[];
static nxt_conf_vldt_object_t nxt_conf_vldt_session_members[];
#endif
static nxt_conf_vldt_object_t nxt_conf_vldt_match_members[];
static nxt_conf_vldt_object_t nxt_conf_vldt_python_target_members[];
static nxt_conf_vldt_object_t nxt_conf_vldt_php_common_members[];
static nxt_conf_vldt_object_t nxt_conf_vldt_php_options_members[];
static nxt_conf_vldt_object_t nxt_conf_vldt_php_target_members[];
static nxt_conf_vldt_object_t nxt_conf_vldt_wasm_access_members[];
static nxt_conf_vldt_object_t nxt_conf_vldt_common_members[];
static nxt_conf_vldt_object_t nxt_conf_vldt_app_limits_members[];
static nxt_conf_vldt_object_t nxt_conf_vldt_app_processes_members[];
static nxt_conf_vldt_object_t nxt_conf_vldt_app_isolation_members[];
static nxt_conf_vldt_object_t nxt_conf_vldt_app_namespaces_members[];
#if (NXT_HAVE_CGROUP)
static nxt_conf_vldt_object_t nxt_conf_vldt_app_cgroup_members[];
#endif
#if (NXT_HAVE_ISOLATION_ROOTFS)
static nxt_conf_vldt_object_t nxt_conf_vldt_app_automount_members[];
#endif
static nxt_conf_vldt_object_t nxt_conf_vldt_access_log_members[];
static nxt_conf_vldt_object_t nxt_conf_vldt_root_members[] = {
{
.name = nxt_string("settings"),
.type = NXT_CONF_VLDT_OBJECT,
.validator = nxt_conf_vldt_object,
.u.members = nxt_conf_vldt_setting_members,
}, {
.name = nxt_string("listeners"),
.type = NXT_CONF_VLDT_OBJECT,
.validator = nxt_conf_vldt_object_iterator,
.u.object = nxt_conf_vldt_listener,
}, {
.name = nxt_string("routes"),
.type = NXT_CONF_VLDT_ARRAY | NXT_CONF_VLDT_OBJECT,
.validator = nxt_conf_vldt_routes,
}, {
.name = nxt_string("applications"),
.type = NXT_CONF_VLDT_OBJECT,
.validator = nxt_conf_vldt_object_iterator,
.u.object = nxt_conf_vldt_app,
}, {
.name = nxt_string("upstreams"),
.type = NXT_CONF_VLDT_OBJECT,
.validator = nxt_conf_vldt_object_iterator,
.u.object = nxt_conf_vldt_upstream,
}, {
.name = nxt_string("access_log"),
.type = NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_OBJECT,
.validator = nxt_conf_vldt_access_log,
},
NXT_CONF_VLDT_END
};
static nxt_conf_vldt_object_t nxt_conf_vldt_setting_members[] = {
{
.name = nxt_string("listen_threads"),
.type = NXT_CONF_VLDT_INTEGER,
.validator = nxt_conf_vldt_listen_threads,
}, {
.name = nxt_string("http"),
.type = NXT_CONF_VLDT_OBJECT,
.validator = nxt_conf_vldt_object,
.u.members = nxt_conf_vldt_http_members,
#if (NXT_HAVE_OTEL)
}, {
.name = nxt_string("telemetry"),
.type = NXT_CONF_VLDT_OBJECT,
.validator = nxt_conf_vldt_object,
.u.members = nxt_conf_vldt_otel_members,
#endif
#if (NXT_HAVE_NJS)
}, {
.name = nxt_string("js_module"),
.type = NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY,
.validator = nxt_conf_vldt_js_module,
#endif
},
NXT_CONF_VLDT_END
};
static nxt_conf_vldt_object_t nxt_conf_vldt_http_members[] = {
{
.name = nxt_string("header_read_timeout"),
.type = NXT_CONF_VLDT_INTEGER,
}, {
.name = nxt_string("body_read_timeout"),
.type = NXT_CONF_VLDT_INTEGER,
}, {
.name = nxt_string("send_timeout"),
.type = NXT_CONF_VLDT_INTEGER,
}, {
.name = nxt_string("idle_timeout"),
.type = NXT_CONF_VLDT_INTEGER,
}, {
.name = nxt_string("large_header_buffer_size"),
.type = NXT_CONF_VLDT_INTEGER,
}, {
.name = nxt_string("large_header_buffers"),
.type = NXT_CONF_VLDT_INTEGER,
}, {
.name = nxt_string("body_buffer_size"),
.type = NXT_CONF_VLDT_INTEGER,
}, {
.name = nxt_string("max_body_size"),
.type = NXT_CONF_VLDT_INTEGER,
}, {
.name = nxt_string("body_temp_path"),
.type = NXT_CONF_VLDT_STRING,
}, {
.name = nxt_string("discard_unsafe_fields"),
.type = NXT_CONF_VLDT_BOOLEAN,
}, {
.name = nxt_string("websocket"),
.type = NXT_CONF_VLDT_OBJECT,
.validator = nxt_conf_vldt_object,
.u.members = nxt_conf_vldt_websocket_members,
}, {
.name = nxt_string("static"),
.type = NXT_CONF_VLDT_OBJECT,
.validator = nxt_conf_vldt_object,
.u.members = nxt_conf_vldt_static_members,
}, {
.name = nxt_string("log_route"),
.type = NXT_CONF_VLDT_BOOLEAN,
}, {
.name = nxt_string("server_version"),
.type = NXT_CONF_VLDT_BOOLEAN,
}, {
.name = nxt_string("chunked_transform"),
.type = NXT_CONF_VLDT_BOOLEAN,
},
NXT_CONF_VLDT_END
};
#if (NXT_HAVE_OTEL)
static nxt_conf_vldt_object_t nxt_conf_vldt_otel_members[] = {
{
.name = nxt_string("endpoint"),
.type = NXT_CONF_VLDT_STRING,
.flags = NXT_CONF_VLDT_REQUIRED
}, {
.name = nxt_string("batch_size"),
.type = NXT_CONF_VLDT_INTEGER,
.validator = nxt_otel_validate_batch_size,
}, {
.name = nxt_string("protocol"),
.type = NXT_CONF_VLDT_STRING,
.validator = nxt_otel_validate_protocol,
.flags = NXT_CONF_VLDT_REQUIRED
}, {
.name = nxt_string("sampling_ratio"),
.type = NXT_CONF_VLDT_NUMBER,
.validator = nxt_otel_validate_sample_ratio,
},
NXT_CONF_VLDT_END
};
#endif
static nxt_conf_vldt_object_t nxt_conf_vldt_websocket_members[] = {
{
.name = nxt_string("read_timeout"),
.type = NXT_CONF_VLDT_INTEGER,
}, {
.name = nxt_string("keepalive_interval"),
.type = NXT_CONF_VLDT_INTEGER,
}, {
.name = nxt_string("max_frame_size"),
.type = NXT_CONF_VLDT_INTEGER,
},
NXT_CONF_VLDT_END
};
static nxt_conf_vldt_object_t nxt_conf_vldt_static_members[] = {
{
.name = nxt_string("mime_types"),
.type = NXT_CONF_VLDT_OBJECT,
.validator = nxt_conf_vldt_mtypes,
},
NXT_CONF_VLDT_END
};
static nxt_conf_vldt_object_t nxt_conf_vldt_listener_members[] = {
{
.name = nxt_string("pass"),
.type = NXT_CONF_VLDT_STRING,
.validator = nxt_conf_vldt_pass,
.flags = NXT_CONF_VLDT_TSTR,
}, {
.name = nxt_string("application"),
.type = NXT_CONF_VLDT_STRING,
.validator = nxt_conf_vldt_app_name,
}, {
.name = nxt_string("forwarded"),
.type = NXT_CONF_VLDT_OBJECT,
.validator = nxt_conf_vldt_forwarded,
}, {
.name = nxt_string("client_ip"),
.type = NXT_CONF_VLDT_OBJECT,
.validator = nxt_conf_vldt_object,
.u.members = nxt_conf_vldt_client_ip_members
}, {
.name = nxt_string("backlog"),
.type = NXT_CONF_VLDT_NUMBER,
.validator = nxt_conf_vldt_listen_backlog,
},
#if (NXT_TLS)
{
.name = nxt_string("tls"),
.type = NXT_CONF_VLDT_OBJECT,
.validator = nxt_conf_vldt_object,
.u.members = nxt_conf_vldt_tls_members,
},
#endif
NXT_CONF_VLDT_END
};
static nxt_conf_vldt_object_t nxt_conf_vldt_forwarded_members[] = {
{
.name = nxt_string("client_ip"),
.type = NXT_CONF_VLDT_STRING,
}, {
.name = nxt_string("protocol"),
.type = NXT_CONF_VLDT_STRING,
}, {
.name = nxt_string("source"),
.type = NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY,
.validator = nxt_conf_vldt_match_addrs,
.flags = NXT_CONF_VLDT_REQUIRED
}, {
.name = nxt_string("recursive"),
.type = NXT_CONF_VLDT_BOOLEAN,
},
NXT_CONF_VLDT_END
};
static nxt_conf_vldt_object_t nxt_conf_vldt_client_ip_members[] = {
{
.name = nxt_string("source"),
.type = NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY,
.validator = nxt_conf_vldt_match_addrs,
.flags = NXT_CONF_VLDT_REQUIRED
}, {
.name = nxt_string("header"),
.type = NXT_CONF_VLDT_STRING,
.flags = NXT_CONF_VLDT_REQUIRED
}, {
.name = nxt_string("recursive"),
.type = NXT_CONF_VLDT_BOOLEAN,
},
NXT_CONF_VLDT_END
};
#if (NXT_TLS)
static nxt_conf_vldt_object_t nxt_conf_vldt_tls_members[] = {
{
.name = nxt_string("certificate"),
.type = NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY,
.flags = NXT_CONF_VLDT_REQUIRED,
.validator = nxt_conf_vldt_certificate,
}, {
.name = nxt_string("conf_commands"),
.type = NXT_CONF_VLDT_OBJECT,
#if (NXT_HAVE_OPENSSL_CONF_CMD)
.validator = nxt_conf_vldt_object_conf_commands,
#else
.validator = nxt_conf_vldt_unsupported,
.u.string = "conf_commands",
#endif
}, {
.name = nxt_string("session"),
.type = NXT_CONF_VLDT_OBJECT,
.validator = nxt_conf_vldt_object,
.u.members = nxt_conf_vldt_session_members,
},
NXT_CONF_VLDT_END
};
static nxt_conf_vldt_object_t nxt_conf_vldt_session_members[] = {
{
.name = nxt_string("cache_size"),
.type = NXT_CONF_VLDT_INTEGER,
.validator = nxt_conf_vldt_tls_cache_size,
}, {
.name = nxt_string("timeout"),
.type = NXT_CONF_VLDT_INTEGER,
.validator = nxt_conf_vldt_tls_timeout,
}, {
.name = nxt_string("tickets"),
.type = NXT_CONF_VLDT_STRING
| NXT_CONF_VLDT_ARRAY
| NXT_CONF_VLDT_BOOLEAN,
#if (NXT_HAVE_OPENSSL_TLSEXT)
.validator = nxt_conf_vldt_ticket_key,
#else
.validator = nxt_conf_vldt_unsupported,
.u.string = "tickets",
#endif
},
NXT_CONF_VLDT_END
};
static nxt_int_t
nxt_conf_vldt_tls_cache_size(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data)
{
int64_t cache_size;
cache_size = nxt_conf_get_number(value);
if (cache_size < 0) {
return nxt_conf_vldt_error(vldt, "The \"cache_size\" number must not "
"be negative.");
}
return NXT_OK;
}
static nxt_int_t
nxt_conf_vldt_tls_timeout(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
void *data)
{
int64_t timeout;
timeout = nxt_conf_get_number(value);
if (timeout <= 0) {
return nxt_conf_vldt_error(vldt, "The \"timeout\" number must be "
"greater than zero.");
}
return NXT_OK;
}
#endif
#if (NXT_HAVE_OPENSSL_TLSEXT)
static nxt_int_t
nxt_conf_vldt_ticket_key(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
void *data)
{
if (nxt_conf_type(value) == NXT_CONF_BOOLEAN) {
return NXT_OK;
}
if (nxt_conf_type(value) == NXT_CONF_ARRAY) {
return nxt_conf_vldt_array_iterator(vldt, value,
&nxt_conf_vldt_ticket_key_element);
}
/* NXT_CONF_STRING */
return nxt_conf_vldt_ticket_key_element(vldt, value);
}
static nxt_int_t
nxt_conf_vldt_ticket_key_element(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value)
{
ssize_t ret;
nxt_str_t key;
if (nxt_conf_type(value) != NXT_CONF_STRING) {
return nxt_conf_vldt_error(vldt, "The \"key\" array must "
"contain only string values.");
}
nxt_conf_get_string(value, &key);
ret = nxt_base64_decode(NULL, key.start, key.length);
if (ret == NXT_ERROR) {
return nxt_conf_vldt_error(vldt, "Invalid Base64 format for the ticket "
"key \"%V\".", &key);
}
if (ret != 48 && ret != 80) {
return nxt_conf_vldt_error(vldt, "Invalid length %d of the ticket "
"key \"%V\". Must be 48 or 80 bytes.",
ret, &key);
}
return NXT_OK;
}
#endif
static nxt_conf_vldt_object_t nxt_conf_vldt_route_members[] = {
{
.name = nxt_string("match"),
.type = NXT_CONF_VLDT_OBJECT,
.validator = nxt_conf_vldt_object,
.u.members = nxt_conf_vldt_match_members,
}, {
.name = nxt_string("action"),
.type = NXT_CONF_VLDT_OBJECT,
.validator = nxt_conf_vldt_action,
},
NXT_CONF_VLDT_END
};
static nxt_conf_vldt_object_t nxt_conf_vldt_match_members[] = {
{
.name = nxt_string("method"),
.type = NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY,
.validator = nxt_conf_vldt_match_patterns,
.u.string = "method",
}, {
.name = nxt_string("scheme"),
.type = NXT_CONF_VLDT_STRING,
.validator = nxt_conf_vldt_match_scheme_pattern,
}, {
.name = nxt_string("host"),
.type = NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY,
.validator = nxt_conf_vldt_match_patterns,
.u.string = "host",
}, {
.name = nxt_string("source"),
.type = NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY,
.validator = nxt_conf_vldt_match_addrs,
}, {
.name = nxt_string("destination"),
.type = NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY,
.validator = nxt_conf_vldt_match_addrs,
}, {
.name = nxt_string("uri"),
.type = NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY,
.validator = nxt_conf_vldt_match_encoded_patterns,
.u.string = "uri"
}, {
.name = nxt_string("query"),
.type = NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY,
.validator = nxt_conf_vldt_match_encoded_patterns,
.u.string = "query"
}, {
.name = nxt_string("arguments"),
.type = NXT_CONF_VLDT_OBJECT | NXT_CONF_VLDT_ARRAY,
.validator = nxt_conf_vldt_match_encoded_patterns_sets,
}, {
.name = nxt_string("headers"),
.type = NXT_CONF_VLDT_OBJECT | NXT_CONF_VLDT_ARRAY,
.validator = nxt_conf_vldt_match_patterns_sets,
.u.string = "headers"
}, {
.name = nxt_string("cookies"),
.type = NXT_CONF_VLDT_OBJECT | NXT_CONF_VLDT_ARRAY,
.validator = nxt_conf_vldt_match_patterns_sets,
.u.string = "cookies"
}, {
.name = nxt_string("if"),
.type = NXT_CONF_VLDT_STRING,
.validator = nxt_conf_vldt_if,
},
NXT_CONF_VLDT_END
};
static nxt_conf_vldt_object_t nxt_conf_vldt_action_common_members[] = {
{
.name = nxt_string("rewrite"),
.type = NXT_CONF_VLDT_STRING,
.flags = NXT_CONF_VLDT_TSTR,
},
{
.name = nxt_string("response_headers"),
.type = NXT_CONF_VLDT_OBJECT,
.validator = nxt_conf_vldt_object_iterator,
.u.object = nxt_conf_vldt_response_header,
},
NXT_CONF_VLDT_END
};
static nxt_conf_vldt_object_t nxt_conf_vldt_pass_action_members[] = {
{
.name = nxt_string("pass"),
.type = NXT_CONF_VLDT_STRING,
.validator = nxt_conf_vldt_pass,
.flags = NXT_CONF_VLDT_TSTR,
},
NXT_CONF_VLDT_NEXT(nxt_conf_vldt_action_common_members)
};
static nxt_conf_vldt_object_t nxt_conf_vldt_return_action_members[] = {
{
.name = nxt_string("return"),
.type = NXT_CONF_VLDT_INTEGER,
.validator = nxt_conf_vldt_return,
}, {
.name = nxt_string("location"),
.type = NXT_CONF_VLDT_STRING,
.flags = NXT_CONF_VLDT_TSTR,
},
NXT_CONF_VLDT_NEXT(nxt_conf_vldt_action_common_members)
};
static nxt_conf_vldt_object_t nxt_conf_vldt_share_action_members[] = {
{
.name = nxt_string("share"),
.type = NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY,
.validator = nxt_conf_vldt_share,
}, {
.name = nxt_string("index"),
.type = NXT_CONF_VLDT_STRING,
}, {
.name = nxt_string("types"),
.type = NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY,
.validator = nxt_conf_vldt_match_patterns,
}, {
.name = nxt_string("fallback"),
.type = NXT_CONF_VLDT_OBJECT,
.validator = nxt_conf_vldt_action,
}, {
.name = nxt_string("chroot"),
.type = NXT_CONF_VLDT_STRING,
#if !(NXT_HAVE_OPENAT2)
.validator = nxt_conf_vldt_unsupported,
.u.string = "chroot",
#endif
.flags = NXT_CONF_VLDT_TSTR,
}, {
.name = nxt_string("follow_symlinks"),
.type = NXT_CONF_VLDT_BOOLEAN,
#if !(NXT_HAVE_OPENAT2)
.validator = nxt_conf_vldt_unsupported,
.u.string = "follow_symlinks",
#endif
}, {
.name = nxt_string("traverse_mounts"),
.type = NXT_CONF_VLDT_BOOLEAN,
#if !(NXT_HAVE_OPENAT2)
.validator = nxt_conf_vldt_unsupported,
.u.string = "traverse_mounts",
#endif
},
NXT_CONF_VLDT_NEXT(nxt_conf_vldt_action_common_members)
};
static nxt_conf_vldt_object_t nxt_conf_vldt_proxy_action_members[] = {
{
.name = nxt_string("proxy"),
.type = NXT_CONF_VLDT_STRING,
.validator = nxt_conf_vldt_proxy,
},
NXT_CONF_VLDT_NEXT(nxt_conf_vldt_action_common_members)
};
static nxt_conf_vldt_object_t nxt_conf_vldt_external_members[] = {
{
.name = nxt_string("executable"),
.type = NXT_CONF_VLDT_STRING,
.flags = NXT_CONF_VLDT_REQUIRED,
}, {
.name = nxt_string("arguments"),
.type = NXT_CONF_VLDT_ARRAY,
.validator = nxt_conf_vldt_array_iterator,
.u.array = nxt_conf_vldt_argument,
},
NXT_CONF_VLDT_NEXT(nxt_conf_vldt_common_members)
};
static nxt_conf_vldt_object_t nxt_conf_vldt_python_common_members[] = {
{
.name = nxt_string("home"),
.type = NXT_CONF_VLDT_STRING,
}, {
.name = nxt_string("path"),
.type = NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY,
.validator = nxt_conf_vldt_python_path,
}, {
.name = nxt_string("protocol"),
.type = NXT_CONF_VLDT_STRING,
.validator = nxt_conf_vldt_python_protocol,
}, {
.name = nxt_string("threads"),
.type = NXT_CONF_VLDT_INTEGER,
.validator = nxt_conf_vldt_threads,
}, {
.name = nxt_string("thread_stack_size"),
.type = NXT_CONF_VLDT_INTEGER,
.validator = nxt_conf_vldt_thread_stack_size,
},
NXT_CONF_VLDT_NEXT(nxt_conf_vldt_common_members)
};
static nxt_conf_vldt_object_t nxt_conf_vldt_python_members[] = {
{
.name = nxt_string("module"),
.type = NXT_CONF_VLDT_STRING,
.validator = nxt_conf_vldt_targets_exclusive,
.u.string = "module",
}, {
.name = nxt_string("callable"),
.type = NXT_CONF_VLDT_STRING,
.validator = nxt_conf_vldt_targets_exclusive,
.u.string = "callable",
}, {
.name = nxt_string("factory"),
.type = NXT_CONF_VLDT_BOOLEAN,
.validator = nxt_conf_vldt_targets_exclusive,
.u.string = "factory",
}, {
.name = nxt_string("prefix"),
.type = NXT_CONF_VLDT_STRING,
.validator = nxt_conf_vldt_targets_exclusive,
.u.string = "prefix",
}, {
.name = nxt_string("targets"),
.type = NXT_CONF_VLDT_OBJECT,
.validator = nxt_conf_vldt_targets,
.u.members = nxt_conf_vldt_python_target_members
},
NXT_CONF_VLDT_NEXT(nxt_conf_vldt_python_common_members)
};
static nxt_conf_vldt_object_t nxt_conf_vldt_python_target_members[] = {
{
.name = nxt_string("module"),
.type = NXT_CONF_VLDT_STRING,
.flags = NXT_CONF_VLDT_REQUIRED,
}, {
.name = nxt_string("callable"),
.type = NXT_CONF_VLDT_STRING,
}, {
.name = nxt_string("factory"),
.type = NXT_CONF_VLDT_BOOLEAN,
}, {
.name = nxt_string("prefix"),
.type = NXT_CONF_VLDT_STRING,
.validator = nxt_conf_vldt_python_prefix,
},
NXT_CONF_VLDT_END
};
static nxt_conf_vldt_object_t nxt_conf_vldt_python_notargets_members[] = {
{
.name = nxt_string("module"),
.type = NXT_CONF_VLDT_STRING,
.flags = NXT_CONF_VLDT_REQUIRED,
}, {
.name = nxt_string("callable"),
.type = NXT_CONF_VLDT_STRING,
}, {
.name = nxt_string("factory"),
.type = NXT_CONF_VLDT_BOOLEAN,
}, {
.name = nxt_string("prefix"),
.type = NXT_CONF_VLDT_STRING,
.validator = nxt_conf_vldt_python_prefix,
},
NXT_CONF_VLDT_NEXT(nxt_conf_vldt_python_common_members)
};
static nxt_conf_vldt_object_t nxt_conf_vldt_php_members[] = {
{
.name = nxt_string("root"),
.type = NXT_CONF_VLDT_ANY_TYPE,
.validator = nxt_conf_vldt_targets_exclusive,
.u.string = "root",
}, {
.name = nxt_string("script"),
.type = NXT_CONF_VLDT_ANY_TYPE,
.validator = nxt_conf_vldt_targets_exclusive,
.u.string = "script",
}, {
.name = nxt_string("index"),
.type = NXT_CONF_VLDT_ANY_TYPE,
.validator = nxt_conf_vldt_targets_exclusive,
.u.string = "index",
}, {
.name = nxt_string("targets"),
.type = NXT_CONF_VLDT_OBJECT,
.validator = nxt_conf_vldt_targets,
.u.members = nxt_conf_vldt_php_target_members
},
NXT_CONF_VLDT_NEXT(nxt_conf_vldt_php_common_members)
};
static nxt_conf_vldt_object_t nxt_conf_vldt_php_common_members[] = {
{
.name = nxt_string("options"),
.type = NXT_CONF_VLDT_OBJECT,
.validator = nxt_conf_vldt_object,
.u.members = nxt_conf_vldt_php_options_members,
},
NXT_CONF_VLDT_NEXT(nxt_conf_vldt_common_members)
};
static nxt_conf_vldt_object_t nxt_conf_vldt_php_options_members[] = {
{
.name = nxt_string("file"),
.type = NXT_CONF_VLDT_STRING,
}, {
.name = nxt_string("admin"),
.type = NXT_CONF_VLDT_OBJECT,
.validator = nxt_conf_vldt_object_iterator,
.u.object = nxt_conf_vldt_php_option,
}, {
.name = nxt_string("user"),
.type = NXT_CONF_VLDT_OBJECT,
.validator = nxt_conf_vldt_object_iterator,
.u.object = nxt_conf_vldt_php_option,
},
NXT_CONF_VLDT_END
};
static nxt_conf_vldt_object_t nxt_conf_vldt_php_target_members[] = {
{
.name = nxt_string("root"),
.type = NXT_CONF_VLDT_STRING,
.flags = NXT_CONF_VLDT_REQUIRED,
}, {
.name = nxt_string("script"),
.type = NXT_CONF_VLDT_STRING,
}, {
.name = nxt_string("index"),
.type = NXT_CONF_VLDT_STRING,
},
NXT_CONF_VLDT_END
};
static nxt_conf_vldt_object_t nxt_conf_vldt_php_notargets_members[] = {
{
.name = nxt_string("root"),
.type = NXT_CONF_VLDT_STRING,
.flags = NXT_CONF_VLDT_REQUIRED,
}, {
.name = nxt_string("script"),
.type = NXT_CONF_VLDT_STRING,
}, {
.name = nxt_string("index"),
.type = NXT_CONF_VLDT_STRING,
},
NXT_CONF_VLDT_NEXT(nxt_conf_vldt_php_common_members)
};
static nxt_conf_vldt_object_t nxt_conf_vldt_perl_members[] = {
{
.name = nxt_string("script"),
.type = NXT_CONF_VLDT_STRING,
.flags = NXT_CONF_VLDT_REQUIRED,
}, {
.name = nxt_string("threads"),
.type = NXT_CONF_VLDT_INTEGER,
.validator = nxt_conf_vldt_threads,
}, {
.name = nxt_string("thread_stack_size"),
.type = NXT_CONF_VLDT_INTEGER,
.validator = nxt_conf_vldt_thread_stack_size,
},
NXT_CONF_VLDT_NEXT(nxt_conf_vldt_common_members)
};
static nxt_conf_vldt_object_t nxt_conf_vldt_ruby_members[] = {
{
.name = nxt_string("script"),
.type = NXT_CONF_VLDT_STRING,
.flags = NXT_CONF_VLDT_REQUIRED,
}, {
.name = nxt_string("threads"),
.type = NXT_CONF_VLDT_INTEGER,
.validator = nxt_conf_vldt_threads,
}, {
.name = nxt_string("hooks"),
.type = NXT_CONF_VLDT_STRING
},
NXT_CONF_VLDT_NEXT(nxt_conf_vldt_common_members)
};
static nxt_conf_vldt_object_t nxt_conf_vldt_java_members[] = {
{
.name = nxt_string("classpath"),
.type = NXT_CONF_VLDT_ARRAY,
.validator = nxt_conf_vldt_array_iterator,
.u.array = nxt_conf_vldt_java_classpath,
}, {
.name = nxt_string("webapp"),
.type = NXT_CONF_VLDT_STRING,
.flags = NXT_CONF_VLDT_REQUIRED,
}, {
.name = nxt_string("options"),
.type = NXT_CONF_VLDT_ARRAY,
.validator = nxt_conf_vldt_array_iterator,
.u.array = nxt_conf_vldt_java_option,
}, {
.name = nxt_string("unit_jars"),
.type = NXT_CONF_VLDT_STRING,
}, {
.name = nxt_string("threads"),
.type = NXT_CONF_VLDT_INTEGER,
.validator = nxt_conf_vldt_threads,
}, {
.name = nxt_string("thread_stack_size"),
.type = NXT_CONF_VLDT_INTEGER,
.validator = nxt_conf_vldt_thread_stack_size,
},
NXT_CONF_VLDT_NEXT(nxt_conf_vldt_common_members)
};
static nxt_conf_vldt_object_t nxt_conf_vldt_wasm_members[] = {
{
.name = nxt_string("module"),
.type = NXT_CONF_VLDT_STRING,
.flags = NXT_CONF_VLDT_REQUIRED,
}, {
.name = nxt_string("request_handler"),
.type = NXT_CONF_VLDT_STRING,
.flags = NXT_CONF_VLDT_REQUIRED,
},{
.name = nxt_string("malloc_handler"),
.type = NXT_CONF_VLDT_STRING,
.flags = NXT_CONF_VLDT_REQUIRED,
}, {
.name = nxt_string("free_handler"),
.type = NXT_CONF_VLDT_STRING,
.flags = NXT_CONF_VLDT_REQUIRED,
}, {
.name = nxt_string("module_init_handler"),
.type = NXT_CONF_VLDT_STRING,
}, {
.name = nxt_string("module_end_handler"),
.type = NXT_CONF_VLDT_STRING,
}, {
.name = nxt_string("request_init_handler"),
.type = NXT_CONF_VLDT_STRING,
}, {
.name = nxt_string("request_end_handler"),
.type = NXT_CONF_VLDT_STRING,
}, {
.name = nxt_string("response_end_handler"),
.type = NXT_CONF_VLDT_STRING,
}, {
.name = nxt_string("access"),
.type = NXT_CONF_VLDT_OBJECT,
.validator = nxt_conf_vldt_object,
.u.members = nxt_conf_vldt_wasm_access_members,
},
NXT_CONF_VLDT_NEXT(nxt_conf_vldt_common_members)
};
static nxt_conf_vldt_object_t nxt_conf_vldt_wasm_wc_members[] = {
{
.name = nxt_string("component"),
.type = NXT_CONF_VLDT_STRING,
.flags = NXT_CONF_VLDT_REQUIRED,
}, {
.name = nxt_string("access"),
.type = NXT_CONF_VLDT_OBJECT,
.validator = nxt_conf_vldt_object,
.u.members = nxt_conf_vldt_wasm_access_members,
},
NXT_CONF_VLDT_NEXT(nxt_conf_vldt_common_members)
};
static nxt_conf_vldt_object_t nxt_conf_vldt_wasm_access_members[] = {
{
.name = nxt_string("filesystem"),
.type = NXT_CONF_VLDT_ARRAY,
},
NXT_CONF_VLDT_END
};
static nxt_conf_vldt_object_t nxt_conf_vldt_skel_members[] = {
{
.name = nxt_string("module"),
.type = NXT_CONF_VLDT_STRING,
.flags = NXT_CONF_VLDT_REQUIRED,
},
NXT_CONF_VLDT_NEXT(nxt_conf_vldt_common_members)
};
static nxt_conf_vldt_object_t nxt_conf_vldt_common_members[] = {
{
.name = nxt_string("type"),
.type = NXT_CONF_VLDT_STRING,
}, {
.name = nxt_string("limits"),
.type = NXT_CONF_VLDT_OBJECT,
.validator = nxt_conf_vldt_object,
.u.members = nxt_conf_vldt_app_limits_members,
}, {
.name = nxt_string("processes"),
.type = NXT_CONF_VLDT_INTEGER | NXT_CONF_VLDT_OBJECT,
.validator = nxt_conf_vldt_processes,
.u.members = nxt_conf_vldt_app_processes_members,
}, {
.name = nxt_string("user"),
.type = NXT_CONF_VLDT_STRING,
}, {
.name = nxt_string("group"),
.type = NXT_CONF_VLDT_STRING,
}, {
.name = nxt_string("working_directory"),
.type = NXT_CONF_VLDT_STRING,
}, {
.name = nxt_string("environment"),
.type = NXT_CONF_VLDT_OBJECT,
.validator = nxt_conf_vldt_object_iterator,
.u.object = nxt_conf_vldt_environment,
}, {
.name = nxt_string("isolation"),
.type = NXT_CONF_VLDT_OBJECT,
.validator = nxt_conf_vldt_isolation,
.u.members = nxt_conf_vldt_app_isolation_members,
}, {
.name = nxt_string("stdout"),
.type = NXT_CONF_VLDT_STRING,
}, {
.name = nxt_string("stderr"),
.type = NXT_CONF_VLDT_STRING,
},
NXT_CONF_VLDT_END
};
static nxt_conf_vldt_object_t nxt_conf_vldt_app_limits_members[] = {
{
.name = nxt_string("timeout"),
.type = NXT_CONF_VLDT_INTEGER,
}, {
.name = nxt_string("requests"),
.type = NXT_CONF_VLDT_INTEGER,
}, {
.name = nxt_string("shm"),
.type = NXT_CONF_VLDT_INTEGER,
},
NXT_CONF_VLDT_END
};
static nxt_conf_vldt_object_t nxt_conf_vldt_app_processes_members[] = {
{
.name = nxt_string("spare"),
.type = NXT_CONF_VLDT_INTEGER,
}, {
.name = nxt_string("max"),
.type = NXT_CONF_VLDT_INTEGER,
}, {
.name = nxt_string("idle_timeout"),
.type = NXT_CONF_VLDT_INTEGER,
},
NXT_CONF_VLDT_END
};
static nxt_conf_vldt_object_t nxt_conf_vldt_app_isolation_members[] = {
{
.name = nxt_string("namespaces"),
.type = NXT_CONF_VLDT_OBJECT,
.validator = nxt_conf_vldt_clone_namespaces,
.u.members = nxt_conf_vldt_app_namespaces_members,
},
#if (NXT_HAVE_CLONE_NEWUSER)
{
.name = nxt_string("uidmap"),
.type = NXT_CONF_VLDT_ARRAY,
.validator = nxt_conf_vldt_array_iterator,
.u.array = nxt_conf_vldt_clone_uidmap,
}, {
.name = nxt_string("gidmap"),
.type = NXT_CONF_VLDT_ARRAY,
.validator = nxt_conf_vldt_array_iterator,
.u.array = nxt_conf_vldt_clone_gidmap,
},
#endif
#if (NXT_HAVE_ISOLATION_ROOTFS)
{
.name = nxt_string("rootfs"),
.type = NXT_CONF_VLDT_STRING,
}, {
.name = nxt_string("automount"),
.type = NXT_CONF_VLDT_OBJECT,
.validator = nxt_conf_vldt_object,
.u.members = nxt_conf_vldt_app_automount_members,
},
#endif
#if (NXT_HAVE_PR_SET_NO_NEW_PRIVS)
{
.name = nxt_string("new_privs"),
.type = NXT_CONF_VLDT_BOOLEAN,
},
#endif
#if (NXT_HAVE_CGROUP)
{
.name = nxt_string("cgroup"),
.type = NXT_CONF_VLDT_OBJECT,
.validator = nxt_conf_vldt_object,
.u.members = nxt_conf_vldt_app_cgroup_members,
},
#endif
NXT_CONF_VLDT_END
};
static nxt_conf_vldt_object_t nxt_conf_vldt_app_namespaces_members[] = {
#if (NXT_HAVE_CLONE_NEWUSER)
{
.name = nxt_string("credential"),
.type = NXT_CONF_VLDT_BOOLEAN,
},
#endif
#if (NXT_HAVE_CLONE_NEWPID)
{
.name = nxt_string("pid"),
.type = NXT_CONF_VLDT_BOOLEAN,
},
#endif
#if (NXT_HAVE_CLONE_NEWNET)
{
.name = nxt_string("network"),
.type = NXT_CONF_VLDT_BOOLEAN,
},
#endif
#if (NXT_HAVE_CLONE_NEWNS)
{
.name = nxt_string("mount"),
.type = NXT_CONF_VLDT_BOOLEAN,
},
#endif
#if (NXT_HAVE_CLONE_NEWUTS)
{
.name = nxt_string("uname"),
.type = NXT_CONF_VLDT_BOOLEAN,
},
#endif
#if (NXT_HAVE_CLONE_NEWCGROUP)
{
.name = nxt_string("cgroup"),
.type = NXT_CONF_VLDT_BOOLEAN,
},
#endif
NXT_CONF_VLDT_END
};
#if (NXT_HAVE_ISOLATION_ROOTFS)
static nxt_conf_vldt_object_t nxt_conf_vldt_app_automount_members[] = {
{
.name = nxt_string("language_deps"),
.type = NXT_CONF_VLDT_BOOLEAN,
}, {
.name = nxt_string("tmpfs"),
.type = NXT_CONF_VLDT_BOOLEAN,
}, {
.name = nxt_string("procfs"),
.type = NXT_CONF_VLDT_BOOLEAN,
},
NXT_CONF_VLDT_END
};
#endif
#if (NXT_HAVE_CGROUP)
static nxt_conf_vldt_object_t nxt_conf_vldt_app_cgroup_members[] = {
{
.name = nxt_string("path"),
.type = NXT_CONF_VLDT_STRING,
.flags = NXT_CONF_VLDT_REQUIRED,
.validator = nxt_conf_vldt_cgroup_path,
},
NXT_CONF_VLDT_END
};
#endif
#if (NXT_HAVE_CLONE_NEWUSER)
static nxt_conf_vldt_object_t nxt_conf_vldt_app_procmap_members[] = {
{
.name = nxt_string("container"),
.type = NXT_CONF_VLDT_INTEGER,
.flags = NXT_CONF_VLDT_REQUIRED,
}, {
.name = nxt_string("host"),
.type = NXT_CONF_VLDT_INTEGER,
.flags = NXT_CONF_VLDT_REQUIRED,
}, {
.name = nxt_string("size"),
.type = NXT_CONF_VLDT_INTEGER,
.flags = NXT_CONF_VLDT_REQUIRED,
},
NXT_CONF_VLDT_END
};
#endif
static nxt_conf_vldt_object_t nxt_conf_vldt_upstream_members[] = {
{
.name = nxt_string("servers"),
.type = NXT_CONF_VLDT_OBJECT,
.validator = nxt_conf_vldt_object_iterator,
.u.object = nxt_conf_vldt_server,
},
NXT_CONF_VLDT_END
};
static nxt_conf_vldt_object_t nxt_conf_vldt_upstream_server_members[] = {
{
.name = nxt_string("weight"),
.type = NXT_CONF_VLDT_NUMBER,
.validator = nxt_conf_vldt_server_weight,
},
NXT_CONF_VLDT_END
};
static nxt_conf_vldt_object_t nxt_conf_vldt_access_log_members[] = {
{
.name = nxt_string("path"),
.type = NXT_CONF_VLDT_STRING,
}, {
.name = nxt_string("format"),
.type = NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_OBJECT,
.validator = nxt_conf_vldt_access_log_format,
}, {
.name = nxt_string("if"),
.type = NXT_CONF_VLDT_STRING,
.validator = nxt_conf_vldt_if,
},
NXT_CONF_VLDT_END
};
nxt_int_t
nxt_conf_validate(nxt_conf_validation_t *vldt)
{
nxt_int_t ret;
u_char error[NXT_MAX_ERROR_STR];
vldt->tstr_state = nxt_tstr_state_new(vldt->pool, 1);
if (nxt_slow_path(vldt->tstr_state == NULL)) {
return NXT_ERROR;
}
ret = nxt_conf_vldt_type(vldt, NULL, vldt->conf, NXT_CONF_VLDT_OBJECT);
if (ret != NXT_OK) {
return ret;
}
ret = nxt_conf_vldt_object(vldt, vldt->conf, nxt_conf_vldt_root_members);
if (ret != NXT_OK) {
return ret;
}
ret = nxt_tstr_state_done(vldt->tstr_state, error);
if (ret != NXT_OK) {
ret = nxt_conf_vldt_error(vldt, "%s", error);
return ret;
}
return NXT_OK;
}
#define NXT_CONF_VLDT_ANY_TYPE_STR \
"either a null, a boolean, an integer, " \
"a number, a string, an array, or an object"
#if (NXT_HAVE_OTEL)
nxt_int_t
nxt_otel_validate_batch_size(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data)
{
double batch_size;
batch_size = nxt_conf_get_number(value);
if (batch_size <= 0) {
return NXT_ERROR;
}
return NXT_OK;
}
nxt_int_t
nxt_otel_validate_sample_ratio(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data)
{
double sample_ratio;
sample_ratio = nxt_conf_get_number(value);
if (sample_ratio < 0 || sample_ratio > 1) {
return NXT_ERROR;
}
return NXT_OK;
}
nxt_int_t
nxt_otel_validate_protocol(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data)
{
nxt_str_t proto;
nxt_conf_get_string(value, &proto);
if (nxt_str_eq(&proto, "HTTP", 4) || nxt_str_eq(&proto, "http", 4)) {
return NXT_OK;
}
if (nxt_str_eq(&proto, "GRPC", 4) || nxt_str_eq(&proto, "grpc", 4)) {
return NXT_OK;
}
return NXT_ERROR;
}
#endif
static nxt_int_t
nxt_conf_vldt_type(nxt_conf_validation_t *vldt, const nxt_str_t *name,
nxt_conf_value_t *value, nxt_conf_vldt_type_t type)
{
u_char *p;
nxt_str_t expected;
nxt_bool_t comma;
nxt_uint_t value_type, n, t;
u_char buf[nxt_length(NXT_CONF_VLDT_ANY_TYPE_STR)];
static const nxt_str_t type_name[] = {
nxt_string("a null"),
nxt_string("a boolean"),
nxt_string("an integer number"),
nxt_string("a fractional number"),
nxt_string("a string"),
nxt_string("an array"),
nxt_string("an object"),
};
value_type = nxt_conf_type(value);
if ((1 << value_type) & type) {
return NXT_OK;
}
p = buf;
n = nxt_popcount(type);
if (n > 1) {
p = nxt_cpymem(p, "either ", 7);
}
comma = (n > 2);
for ( ;; ) {
t = __builtin_ffs(type) - 1;
p = nxt_cpymem(p, type_name[t].start, type_name[t].length);
n--;
if (n == 0) {
break;
}
if (comma) {
*p++ = ',';
}
if (n == 1) {
p = nxt_cpymem(p, " or", 3);
}
*p++ = ' ';
type = type & ~(1 << t);
}
expected.length = p - buf;
expected.start = buf;
if (name == NULL) {
return nxt_conf_vldt_error(vldt,
"The configuration must be %V, but not %V.",
&expected, &type_name[value_type]);
}
return nxt_conf_vldt_error(vldt,
"The \"%V\" value must be %V, but not %V.",
name, &expected, &type_name[value_type]);
}
static nxt_int_t
nxt_conf_vldt_error(nxt_conf_validation_t *vldt, const char *fmt, ...)
{
u_char *p, *end;
size_t size;
va_list args;
u_char error[NXT_MAX_ERROR_STR];
va_start(args, fmt);
end = nxt_vsprintf(error, error + NXT_MAX_ERROR_STR, fmt, args);
va_end(args);
size = end - error;
p = nxt_mp_nget(vldt->pool, size);
if (p == NULL) {
return NXT_ERROR;
}
nxt_memcpy(p, error, size);
vldt->error.length = size;
vldt->error.start = p;
return NXT_DECLINED;
}
nxt_inline nxt_int_t
nxt_conf_vldt_unsupported(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
void *data)
{
return nxt_conf_vldt_error(vldt, "Unit is built without the \"%s\" "
"option support.", data);
}
static nxt_int_t
nxt_conf_vldt_var(nxt_conf_validation_t *vldt, const nxt_str_t *name,
nxt_str_t *value)
{
u_char error[NXT_MAX_ERROR_STR];
if (nxt_tstr_test(vldt->tstr_state, value, error) != NXT_OK) {
return nxt_conf_vldt_error(vldt, "%s in the \"%V\" value.",
error, name);
}
return NXT_OK;
}
static nxt_int_t
nxt_conf_vldt_if(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
void *data)
{
nxt_str_t str;
static const nxt_str_t if_str = nxt_string("if");
if (nxt_conf_type(value) != NXT_CONF_STRING) {
return nxt_conf_vldt_error(vldt, "The \"if\" must be a string");
}
nxt_conf_get_string(value, &str);
if (str.length == 0) {
return NXT_OK;
}
if (str.start[0] == '!') {
str.start++;
str.length--;
}
if (nxt_is_tstr(&str)) {
return nxt_conf_vldt_var(vldt, &if_str, &str);
}
return NXT_OK;
}
typedef struct {
nxt_mp_t *pool;
nxt_str_t *type;
nxt_lvlhsh_t hash;
} nxt_conf_vldt_mtypes_ctx_t;
static nxt_int_t
nxt_conf_vldt_mtypes(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
void *data)
{
nxt_int_t ret;
nxt_conf_vldt_mtypes_ctx_t ctx;
ctx.pool = nxt_mp_create(1024, 128, 256, 32);
if (nxt_slow_path(ctx.pool == NULL)) {
return NXT_ERROR;
}
nxt_lvlhsh_init(&ctx.hash);
vldt->ctx = &ctx;
ret = nxt_conf_vldt_object_iterator(vldt, value,
&nxt_conf_vldt_mtypes_type);
vldt->ctx = NULL;
nxt_mp_destroy(ctx.pool);
return ret;
}
static nxt_int_t
nxt_conf_vldt_mtypes_type(nxt_conf_validation_t *vldt, nxt_str_t *name,
nxt_conf_value_t *value)
{
nxt_int_t ret;
nxt_conf_vldt_mtypes_ctx_t *ctx;
ret = nxt_conf_vldt_type(vldt, name, value,
NXT_CONF_VLDT_STRING|NXT_CONF_VLDT_ARRAY);
if (ret != NXT_OK) {
return ret;
}
ctx = vldt->ctx;
ctx->type = nxt_mp_get(ctx->pool, sizeof(nxt_str_t));
if (nxt_slow_path(ctx->type == NULL)) {
return NXT_ERROR;
}
*ctx->type = *name;
if (nxt_conf_type(value) == NXT_CONF_ARRAY) {
return nxt_conf_vldt_array_iterator(vldt, value,
&nxt_conf_vldt_mtypes_extension);
}
/* NXT_CONF_STRING */
return nxt_conf_vldt_mtypes_extension(vldt, value);
}
static nxt_int_t
nxt_conf_vldt_mtypes_extension(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value)
{
nxt_str_t exten, *dup_type;
nxt_conf_vldt_mtypes_ctx_t *ctx;
ctx = vldt->ctx;
if (nxt_conf_type(value) != NXT_CONF_STRING) {
return nxt_conf_vldt_error(vldt, "The \"%V\" MIME type array must "
"contain only strings.", ctx->type);
}
nxt_conf_get_string(value, &exten);
if (exten.length == 0) {
return nxt_conf_vldt_error(vldt, "An empty file extension for "
"the \"%V\" MIME type.", ctx->type);
}
dup_type = nxt_http_static_mtype_get(&ctx->hash, &exten);
if (dup_type->length != 0) {
return nxt_conf_vldt_error(vldt, "The \"%V\" file extension has been "
"declared for \"%V\" and \"%V\" "
"MIME types at the same time.",
&exten, dup_type, ctx->type);
}
return nxt_http_static_mtypes_hash_add(ctx->pool, &ctx->hash, &exten,
ctx->type);
}
static nxt_int_t
nxt_conf_vldt_listener(nxt_conf_validation_t *vldt, nxt_str_t *name,
nxt_conf_value_t *value)
{
nxt_int_t ret;
nxt_str_t str;
nxt_sockaddr_t *sa;
if (nxt_slow_path(nxt_str_dup(vldt->pool, &str, name) == NULL)) {
return NXT_ERROR;
}
sa = nxt_sockaddr_parse(vldt->pool, &str);
if (nxt_slow_path(sa == NULL)) {
return nxt_conf_vldt_error(vldt,
"The listener address \"%V\" is invalid.",
name);
}
ret = nxt_conf_vldt_type(vldt, name, value, NXT_CONF_VLDT_OBJECT);
if (ret != NXT_OK) {
return ret;
}
return nxt_conf_vldt_object(vldt, value, nxt_conf_vldt_listener_members);
}
static nxt_int_t
nxt_conf_vldt_action(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
void *data)
{
nxt_uint_t i;
nxt_conf_value_t *action;
nxt_conf_vldt_object_t *members;
static const struct {
nxt_str_t name;
nxt_conf_vldt_object_t *members;
} actions[] = {
{ nxt_string("pass"), nxt_conf_vldt_pass_action_members },
{ nxt_string("return"), nxt_conf_vldt_return_action_members },
{ nxt_string("share"), nxt_conf_vldt_share_action_members },
{ nxt_string("proxy"), nxt_conf_vldt_proxy_action_members },
};
members = NULL;
for (i = 0; i < nxt_nitems(actions); i++) {
action = nxt_conf_get_object_member(value, &actions[i].name, NULL);
if (action == NULL) {
continue;
}
if (members != NULL) {
return nxt_conf_vldt_error(vldt, "The \"action\" object must have "
"just one of \"pass\", \"return\", "
"\"share\", or \"proxy\" options set.");
}
members = actions[i].members;
}
if (members == NULL) {
return nxt_conf_vldt_error(vldt, "The \"action\" object must have "
"either \"pass\", \"return\", \"share\", "
"or \"proxy\" option set.");
}
return nxt_conf_vldt_object(vldt, value, members);
}
static nxt_int_t
nxt_conf_vldt_pass(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
void *data)
{
nxt_str_t pass;
nxt_int_t ret;
nxt_str_t segments[3];
static const nxt_str_t targets_str = nxt_string("targets");
nxt_conf_get_string(value, &pass);
ret = nxt_http_pass_segments(vldt->pool, &pass, segments, 3);
if (ret != NXT_OK) {
if (ret == NXT_DECLINED) {
return nxt_conf_vldt_error(vldt, "Request \"pass\" value \"%V\" "
"is invalid.", &pass);
}
return NXT_ERROR;
}
if (nxt_str_eq(&segments[0], "applications", 12)) {
if (segments[1].length == 0) {
goto error;
}
value = nxt_conf_get_object_member(vldt->conf, &segments[0], NULL);
if (value == NULL) {
goto error;
}
value = nxt_conf_get_object_member(value, &segments[1], NULL);
if (value == NULL) {
goto error;
}
if (segments[2].length > 0) {
value = nxt_conf_get_object_member(value, &targets_str, NULL);
if (value == NULL) {
goto error;
}
value = nxt_conf_get_object_member(value, &segments[2], NULL);
if (value == NULL) {
goto error;
}
}
return NXT_OK;
}
if (nxt_str_eq(&segments[0], "upstreams", 9)) {
if (segments[1].length == 0 || segments[2].length != 0) {
goto error;
}
value = nxt_conf_get_object_member(vldt->conf, &segments[0], NULL);
if (value == NULL) {
goto error;
}
value = nxt_conf_get_object_member(value, &segments[1], NULL);
if (value == NULL) {
goto error;
}
return NXT_OK;
}
if (nxt_str_eq(&segments[0], "routes", 6)) {
if (segments[2].length != 0) {
goto error;
}
value = nxt_conf_get_object_member(vldt->conf, &segments[0], NULL);
if (value == NULL) {
goto error;
}
if (segments[1].length == 0) {
if (nxt_conf_type(value) != NXT_CONF_ARRAY) {
goto error;
}
return NXT_OK;
}
if (nxt_conf_type(value) != NXT_CONF_OBJECT) {
goto error;
}
value = nxt_conf_get_object_member(value, &segments[1], NULL);
if (value == NULL) {
goto error;
}
return NXT_OK;
}
error:
return nxt_conf_vldt_error(vldt, "Request \"pass\" points to invalid "
"location \"%V\".", &pass);
}
static nxt_int_t
nxt_conf_vldt_return(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
void *data)
{
int64_t status;
status = nxt_conf_get_number(value);
if (status < NXT_HTTP_INVALID || status > NXT_HTTP_STATUS_MAX) {
return nxt_conf_vldt_error(vldt, "The \"return\" value is out of "
"allowed HTTP status code range 0-999.");
}
return NXT_OK;
}
static nxt_int_t
nxt_conf_vldt_share(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
void *data)
{
if (nxt_conf_type(value) == NXT_CONF_ARRAY) {
if (nxt_conf_array_elements_count(value) == 0) {
return nxt_conf_vldt_error(vldt, "The \"share\" array "
"must contain at least one element.");
}
return nxt_conf_vldt_array_iterator(vldt, value,
&nxt_conf_vldt_share_element);
}
/* NXT_CONF_STRING */
return nxt_conf_vldt_share_element(vldt, value);
}
static nxt_int_t
nxt_conf_vldt_share_element(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value)
{
nxt_str_t str;
static const nxt_str_t share = nxt_string("share");
if (nxt_conf_type(value) != NXT_CONF_STRING) {
return nxt_conf_vldt_error(vldt, "The \"share\" array must "
"contain only string values.");
}
nxt_conf_get_string(value, &str);
if (nxt_is_tstr(&str)) {
return nxt_conf_vldt_var(vldt, &share, &str);
}
return NXT_OK;
}
static nxt_int_t
nxt_conf_vldt_proxy(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
void *data)
{
nxt_str_t name, *ret;
nxt_sockaddr_t *sa;
ret = nxt_conf_get_string_dup(value, vldt->pool, &name);
if (nxt_slow_path(ret == NULL)) {
return NXT_ERROR;
}
if (nxt_str_start(&name, "http://", 7)) {
name.length -= 7;
name.start += 7;
sa = nxt_sockaddr_parse(vldt->pool, &name);
if (sa != NULL) {
return NXT_OK;
}
}
return nxt_conf_vldt_error(vldt, "The \"proxy\" address is invalid \"%V\"",
&name);
}
static nxt_int_t
nxt_conf_vldt_python(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
void *data)
{
nxt_conf_value_t *targets;
static const nxt_str_t targets_str = nxt_string("targets");
targets = nxt_conf_get_object_member(value, &targets_str, NULL);
if (targets != NULL) {
return nxt_conf_vldt_object(vldt, value, nxt_conf_vldt_python_members);
}
return nxt_conf_vldt_object(vldt, value,
nxt_conf_vldt_python_notargets_members);
}
static nxt_int_t
nxt_conf_vldt_python_path(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data)
{
if (nxt_conf_type(value) == NXT_CONF_ARRAY) {
return nxt_conf_vldt_array_iterator(vldt, value,
&nxt_conf_vldt_python_path_element);
}
/* NXT_CONF_STRING */
return NXT_OK;
}
static nxt_int_t
nxt_conf_vldt_python_path_element(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value)
{
if (nxt_conf_type(value) != NXT_CONF_STRING) {
return nxt_conf_vldt_error(vldt, "The \"path\" array must contain "
"only string values.");
}
return NXT_OK;
}
static nxt_int_t
nxt_conf_vldt_python_protocol(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data)
{
nxt_str_t proto;
static const nxt_str_t wsgi = nxt_string("wsgi");
static const nxt_str_t asgi = nxt_string("asgi");
nxt_conf_get_string(value, &proto);
if (nxt_strstr_eq(&proto, &wsgi) || nxt_strstr_eq(&proto, &asgi)) {
return NXT_OK;
}
return nxt_conf_vldt_error(vldt, "The \"protocol\" can either be "
"\"wsgi\" or \"asgi\".");
}
static nxt_int_t
nxt_conf_vldt_python_prefix(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data)
{
nxt_str_t prefix;
if (nxt_conf_type(value) != NXT_CONF_STRING) {
return nxt_conf_vldt_error(vldt, "The \"prefix\" must be a string "
"beginning with \"/\".");
}
nxt_conf_get_string(value, &prefix);
if (!nxt_strchr_start(&prefix, '/')) {
return nxt_conf_vldt_error(vldt, "The \"prefix\" must be a string "
"beginning with \"/\".");
}
return NXT_OK;
}
static nxt_int_t
nxt_conf_vldt_listen_threads(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data)
{
int64_t threads;
threads = nxt_conf_get_number(value);
if (threads < 1) {
return nxt_conf_vldt_error(vldt, "The \"listen_threads\" number must "
"be equal to or greater than 1.");
}
if (threads > NXT_INT32_T_MAX) {
return nxt_conf_vldt_error(vldt, "The \"listen_threads\" number must "
"not exceed %d.", NXT_INT32_T_MAX);
}
return NXT_OK;
}
static nxt_int_t
nxt_conf_vldt_threads(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
void *data)
{
int64_t threads;
threads = nxt_conf_get_number(value);
if (threads < 1) {
return nxt_conf_vldt_error(vldt, "The \"threads\" number must be "
"equal to or greater than 1.");
}
if (threads > NXT_INT32_T_MAX) {
return nxt_conf_vldt_error(vldt, "The \"threads\" number must "
"not exceed %d.", NXT_INT32_T_MAX);
}
return NXT_OK;
}
static nxt_int_t
nxt_conf_vldt_thread_stack_size(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data)
{
int64_t size, min_size;
size = nxt_conf_get_number(value);
min_size = sysconf(_SC_THREAD_STACK_MIN);
if (size < min_size) {
return nxt_conf_vldt_error(vldt, "The \"thread_stack_size\" number "
"must be equal to or greater than %d.",
min_size);
}
if ((size % nxt_pagesize) != 0) {
return nxt_conf_vldt_error(vldt, "The \"thread_stack_size\" number "
"must be a multiple of the system page size (%d).",
nxt_pagesize);
}
return NXT_OK;
}
static nxt_int_t
nxt_conf_vldt_routes(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
void *data)
{
if (nxt_conf_type(value) == NXT_CONF_ARRAY) {
return nxt_conf_vldt_array_iterator(vldt, value,
&nxt_conf_vldt_route);
}
/* NXT_CONF_OBJECT */
return nxt_conf_vldt_object_iterator(vldt, value,
&nxt_conf_vldt_routes_member);
}
static nxt_int_t
nxt_conf_vldt_routes_member(nxt_conf_validation_t *vldt, nxt_str_t *name,
nxt_conf_value_t *value)
{
nxt_int_t ret;
ret = nxt_conf_vldt_type(vldt, name, value, NXT_CONF_VLDT_ARRAY);
if (ret != NXT_OK) {
return ret;
}
return nxt_conf_vldt_array_iterator(vldt, value, &nxt_conf_vldt_route);
}
static nxt_int_t
nxt_conf_vldt_route(nxt_conf_validation_t *vldt, nxt_conf_value_t *value)
{
if (nxt_conf_type(value) != NXT_CONF_OBJECT) {
return nxt_conf_vldt_error(vldt, "The \"routes\" array must contain "
"only object values.");
}
return nxt_conf_vldt_object(vldt, value, nxt_conf_vldt_route_members);
}
static nxt_int_t
nxt_conf_vldt_match_patterns(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data)
{
nxt_int_t ret;
vldt->ctx = data;
if (nxt_conf_type(value) == NXT_CONF_ARRAY) {
ret = nxt_conf_vldt_array_iterator(vldt, value,
&nxt_conf_vldt_match_pattern);
} else {
/* NXT_CONF_STRING */
ret = nxt_conf_vldt_match_pattern(vldt, value);
}
vldt->ctx = NULL;
return ret;
}
static nxt_int_t
nxt_conf_vldt_match_pattern(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value)
{
nxt_str_t pattern;
nxt_uint_t i, first, last;
#if (NXT_HAVE_REGEX)
nxt_regex_t *re;
nxt_regex_err_t err;
#endif
if (nxt_conf_type(value) != NXT_CONF_STRING) {
return nxt_conf_vldt_error(vldt, "The \"match\" pattern for \"%s\" "
"must be strings.", vldt->ctx);
}
nxt_conf_get_string(value, &pattern);
if (pattern.length == 0) {
return NXT_OK;
}
first = (pattern.start[0] == '!');
if (first < pattern.length && pattern.start[first] == '~') {
#if (NXT_HAVE_REGEX)
pattern.start += first + 1;
pattern.length -= first + 1;
re = nxt_regex_compile(vldt->pool, &pattern, &err);
if (nxt_slow_path(re == NULL)) {
if (err.offset < pattern.length) {
return nxt_conf_vldt_error(vldt, "Invalid regular expression: "
"%s at offset %d",
err.msg, err.offset);
}
return nxt_conf_vldt_error(vldt, "Invalid regular expression: %s",
err.msg);
}
return NXT_OK;
#else
return nxt_conf_vldt_error(vldt, "Unit is built without support of "
"regular expressions: \"--no-regex\" "
"./configure option was set.");
#endif
}
last = pattern.length - 1;
for (i = first; i < last; i++) {
if (pattern.start[i] == '*' && pattern.start[i + 1] == '*') {
return nxt_conf_vldt_error(vldt, "The \"match\" pattern must "
"not contain double \"*\" markers.");
}
}
return NXT_OK;
}
static nxt_int_t nxt_conf_vldt_match_encoded_patterns_sets(
nxt_conf_validation_t *vldt, nxt_conf_value_t *value, void *data)
{
if (nxt_conf_type(value) == NXT_CONF_ARRAY) {
return nxt_conf_vldt_array_iterator(vldt, value,
&nxt_conf_vldt_match_encoded_patterns_set);
}
/* NXT_CONF_OBJECT */
return nxt_conf_vldt_match_encoded_patterns_set(vldt, value);
}
static nxt_int_t nxt_conf_vldt_match_encoded_patterns_set(
nxt_conf_validation_t *vldt, nxt_conf_value_t *value)
{
if (nxt_conf_type(value) != NXT_CONF_OBJECT) {
return nxt_conf_vldt_error(vldt, "The \"match\" pattern for "
"\"arguments\" must be an object.");
}
return nxt_conf_vldt_object_iterator(vldt, value,
&nxt_conf_vldt_match_encoded_patterns_set_member);
}
static nxt_int_t
nxt_conf_vldt_match_encoded_patterns_set_member(nxt_conf_validation_t *vldt,
nxt_str_t *name, nxt_conf_value_t *value)
{
u_char *p, *end;
if (nxt_slow_path(name->length == 0)) {
return nxt_conf_vldt_error(vldt, "The \"match\" pattern objects must "
"not contain empty member names.");
}
p = nxt_mp_nget(vldt->pool, name->length);
if (nxt_slow_path(p == NULL)) {
return NXT_ERROR;
}
end = nxt_decode_uri(p, name->start, name->length);
if (nxt_slow_path(end == NULL)) {
return nxt_conf_vldt_error(vldt, "The \"match\" pattern for "
"\"arguments\" is encoded but is invalid.");
}
return nxt_conf_vldt_match_encoded_patterns(vldt, value,
(void *) "arguments");
}
static nxt_int_t
nxt_conf_vldt_match_encoded_patterns(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data)
{
nxt_int_t ret;
vldt->ctx = data;
if (nxt_conf_type(value) == NXT_CONF_ARRAY) {
ret = nxt_conf_vldt_array_iterator(vldt, value,
&nxt_conf_vldt_match_encoded_pattern);
} else {
/* NXT_CONF_STRING */
ret = nxt_conf_vldt_match_encoded_pattern(vldt, value);
}
vldt->ctx = NULL;
return ret;
}
static nxt_int_t
nxt_conf_vldt_match_encoded_pattern(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value)
{
u_char *p, *end;
nxt_int_t ret;
nxt_str_t pattern;
if (nxt_conf_type(value) != NXT_CONF_STRING) {
return nxt_conf_vldt_error(vldt, "The \"match\" pattern for \"%s\" "
"must be a string.", vldt->ctx);
}
ret = nxt_conf_vldt_match_pattern(vldt, value);
if (nxt_slow_path(ret != NXT_OK)) {
return ret;
}
nxt_conf_get_string(value, &pattern);
p = nxt_mp_nget(vldt->pool, pattern.length);
if (nxt_slow_path(p == NULL)) {
return NXT_ERROR;
}
end = nxt_decode_uri(p, pattern.start, pattern.length);
if (nxt_slow_path(end == NULL)) {
return nxt_conf_vldt_error(vldt, "The \"match\" pattern for \"%s\" "
"is encoded but is invalid.", vldt->ctx);
}
return NXT_OK;
}
static nxt_int_t
nxt_conf_vldt_match_addrs(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data)
{
if (nxt_conf_type(value) == NXT_CONF_ARRAY) {
return nxt_conf_vldt_array_iterator(vldt, value,
&nxt_conf_vldt_match_addr);
}
return nxt_conf_vldt_match_addr(vldt, value);
}
static nxt_int_t
nxt_conf_vldt_match_addr(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value)
{
nxt_http_route_addr_pattern_t pattern;
switch (nxt_http_route_addr_pattern_parse(vldt->pool, &pattern, value)) {
case NXT_OK:
return NXT_OK;
case NXT_ADDR_PATTERN_PORT_ERROR:
return nxt_conf_vldt_error(vldt, "The \"address\" port an invalid "
"port.");
case NXT_ADDR_PATTERN_CV_TYPE_ERROR:
return nxt_conf_vldt_error(vldt, "The \"match\" pattern for "
"\"address\" must be a string.");
case NXT_ADDR_PATTERN_LENGTH_ERROR:
return nxt_conf_vldt_error(vldt, "The \"address\" is too short.");
case NXT_ADDR_PATTERN_FORMAT_ERROR:
return nxt_conf_vldt_error(vldt, "The \"address\" format is invalid.");
case NXT_ADDR_PATTERN_RANGE_OVERLAP_ERROR:
return nxt_conf_vldt_error(vldt, "The \"address\" range is "
"overlapping.");
case NXT_ADDR_PATTERN_CIDR_ERROR:
return nxt_conf_vldt_error(vldt, "The \"address\" has an invalid CIDR "
"prefix.");
case NXT_ADDR_PATTERN_NO_IPv6_ERROR:
return nxt_conf_vldt_error(vldt, "The \"address\" does not support "
"IPv6 with your configuration.");
case NXT_ADDR_PATTERN_NO_UNIX_ERROR:
return nxt_conf_vldt_error(vldt, "The \"address\" does not support "
"UNIX domain sockets with your "
"configuration.");
default:
return nxt_conf_vldt_error(vldt, "The \"address\" has an unknown "
"format.");
}
}
static nxt_int_t
nxt_conf_vldt_match_scheme_pattern(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data)
{
nxt_str_t scheme;
static const nxt_str_t http = nxt_string("http");
static const nxt_str_t https = nxt_string("https");
nxt_conf_get_string(value, &scheme);
if (nxt_strcasestr_eq(&scheme, &http)
|| nxt_strcasestr_eq(&scheme, &https))
{
return NXT_OK;
}
return nxt_conf_vldt_error(vldt, "The \"scheme\" can either be "
"\"http\" or \"https\".");
}
static nxt_int_t
nxt_conf_vldt_match_patterns_sets(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data)
{
nxt_int_t ret;
vldt->ctx = data;
if (nxt_conf_type(value) == NXT_CONF_ARRAY) {
ret = nxt_conf_vldt_array_iterator(vldt, value,
&nxt_conf_vldt_match_patterns_set);
} else {
/* NXT_CONF_OBJECT */
ret = nxt_conf_vldt_match_patterns_set(vldt, value);
}
vldt->ctx = NULL;
return ret;
}
static nxt_int_t
nxt_conf_vldt_match_patterns_set(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value)
{
if (nxt_conf_type(value) != NXT_CONF_OBJECT) {
return nxt_conf_vldt_error(vldt, "The \"match\" patterns for "
"\"%s\" must be objects.", vldt->ctx);
}
return nxt_conf_vldt_object_iterator(vldt, value,
&nxt_conf_vldt_match_patterns_set_member);
}
static nxt_int_t
nxt_conf_vldt_match_patterns_set_member(nxt_conf_validation_t *vldt,
nxt_str_t *name, nxt_conf_value_t *value)
{
if (name->length == 0) {
return nxt_conf_vldt_error(vldt, "The \"match\" pattern objects must "
"not contain empty member names.");
}
return nxt_conf_vldt_match_patterns(vldt, value, vldt->ctx);
}
#if (NXT_TLS)
static nxt_int_t
nxt_conf_vldt_certificate(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
void *data)
{
if (nxt_conf_type(value) == NXT_CONF_ARRAY) {
if (nxt_conf_array_elements_count(value) == 0) {
return nxt_conf_vldt_error(vldt, "The \"certificate\" array "
"must contain at least one element.");
}
return nxt_conf_vldt_array_iterator(vldt, value,
&nxt_conf_vldt_certificate_element);
}
/* NXT_CONF_STRING */
return nxt_conf_vldt_certificate_element(vldt, value);
}
static nxt_int_t
nxt_conf_vldt_certificate_element(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value)
{
nxt_str_t name;
nxt_conf_value_t *cert;
if (nxt_conf_type(value) != NXT_CONF_STRING) {
return nxt_conf_vldt_error(vldt, "The \"certificate\" array must "
"contain only string values.");
}
nxt_conf_get_string(value, &name);
cert = nxt_cert_info_get(&name);
if (cert == NULL) {
return nxt_conf_vldt_error(vldt, "Certificate \"%V\" is not found.",
&name);
}
return NXT_OK;
}
#if (NXT_HAVE_OPENSSL_CONF_CMD)
static nxt_int_t
nxt_conf_vldt_object_conf_commands(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data)
{
uint32_t index;
nxt_int_t ret;
nxt_str_t name;
nxt_conf_value_t *member;
index = 0;
for ( ;; ) {
member = nxt_conf_next_object_member(value, &name, &index);
if (member == NULL) {
break;
}
ret = nxt_conf_vldt_type(vldt, &name, member, NXT_CONF_VLDT_STRING);
if (ret != NXT_OK) {
return ret;
}
}
return NXT_OK;
}
#endif
#endif
static nxt_int_t
nxt_conf_vldt_response_header(nxt_conf_validation_t *vldt, nxt_str_t *name,
nxt_conf_value_t *value)
{
nxt_str_t str;
nxt_uint_t type;
static const nxt_str_t content_length = nxt_string("Content-Length");
if (name->length == 0) {
return nxt_conf_vldt_error(vldt, "The response header name "
"must not be empty.");
}
if (nxt_strstr_eq(name, &content_length)) {
return nxt_conf_vldt_error(vldt, "The \"Content-Length\" response "
"header value is not supported");
}
type = nxt_conf_type(value);
if (type == NXT_CONF_NULL) {
return NXT_OK;
}
if (type == NXT_CONF_STRING) {
nxt_conf_get_string(value, &str);
if (nxt_is_tstr(&str)) {
return nxt_conf_vldt_var(vldt, name, &str);
}
return NXT_OK;
}
return nxt_conf_vldt_error(vldt, "The \"%V\" response header value "
"must either be a string or a null", name);
}
static nxt_int_t
nxt_conf_vldt_app_name(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
void *data)
{
nxt_str_t name;
nxt_conf_value_t *apps, *app;
static const nxt_str_t apps_str = nxt_string("applications");
nxt_conf_get_string(value, &name);
apps = nxt_conf_get_object_member(vldt->conf, &apps_str, NULL);
if (nxt_slow_path(apps == NULL)) {
goto error;
}
app = nxt_conf_get_object_member(apps, &name, NULL);
if (nxt_slow_path(app == NULL)) {
goto error;
}
return NXT_OK;
error:
return nxt_conf_vldt_error(vldt, "Listening socket is assigned for "
"a non existing application \"%V\".",
&name);
}
static nxt_int_t
nxt_conf_vldt_forwarded(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
void *data)
{
nxt_conf_value_t *client_ip, *protocol;
static const nxt_str_t client_ip_str = nxt_string("client_ip");
static const nxt_str_t protocol_str = nxt_string("protocol");
client_ip = nxt_conf_get_object_member(value, &client_ip_str, NULL);
protocol = nxt_conf_get_object_member(value, &protocol_str, NULL);
if (client_ip == NULL && protocol == NULL) {
return nxt_conf_vldt_error(vldt, "The \"forwarded\" object must have "
"either \"client_ip\" or \"protocol\" "
"option set.");
}
return nxt_conf_vldt_object(vldt, value, nxt_conf_vldt_forwarded_members);
}
static nxt_int_t
nxt_conf_vldt_listen_backlog(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data)
{
int64_t backlog;
backlog = nxt_conf_get_number(value);
/*
* POSIX allows this to be 0 and some systems use -1 to
* indicate to use the OS's default value.
*/
if (backlog < -1) {
return nxt_conf_vldt_error(vldt, "The \"backlog\" number must be "
"equal to or greater than -1.");
}
if (backlog > NXT_INT32_T_MAX) {
return nxt_conf_vldt_error(vldt, "The \"backlog\" number must "
"not exceed %d.", NXT_INT32_T_MAX);
}
return NXT_OK;
}
static nxt_int_t
nxt_conf_vldt_app(nxt_conf_validation_t *vldt, nxt_str_t *name,
nxt_conf_value_t *value)
{
nxt_int_t ret;
nxt_str_t type;
nxt_thread_t *thread;
nxt_conf_value_t *type_value;
nxt_app_lang_module_t *lang;
static const nxt_str_t type_str = nxt_string("type");
static const struct {
nxt_conf_vldt_handler_t validator;
nxt_conf_vldt_object_t *members;
} types[] = {
{ nxt_conf_vldt_object, nxt_conf_vldt_external_members },
{ nxt_conf_vldt_python, NULL },
{ nxt_conf_vldt_php, NULL },
{ nxt_conf_vldt_object, nxt_conf_vldt_perl_members },
{ nxt_conf_vldt_object, nxt_conf_vldt_ruby_members },
{ nxt_conf_vldt_object, nxt_conf_vldt_java_members },
{ nxt_conf_vldt_object, nxt_conf_vldt_wasm_members },
{ nxt_conf_vldt_object, nxt_conf_vldt_wasm_wc_members },
{ nxt_conf_vldt_object, nxt_conf_vldt_skel_members },
};
ret = nxt_conf_vldt_type(vldt, name, value, NXT_CONF_VLDT_OBJECT);
if (ret != NXT_OK) {
return ret;
}
type_value = nxt_conf_get_object_member(value, &type_str, NULL);
if (type_value == NULL) {
return nxt_conf_vldt_error(vldt,
"Application must have the \"type\" property set.");
}
ret = nxt_conf_vldt_type(vldt, &type_str, type_value, NXT_CONF_VLDT_STRING);
if (ret != NXT_OK) {
return ret;
}
nxt_conf_get_string(type_value, &type);
thread = nxt_thread();
lang = nxt_app_lang_module(thread->runtime, &type);
if (lang == NULL) {
return nxt_conf_vldt_error(vldt,
"The module to run \"%V\" is not found "
"among the available application modules.",
&type);
}
return types[lang->type].validator(vldt, value, types[lang->type].members);
}
static nxt_int_t
nxt_conf_vldt_object(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
void *data)
{
uint32_t index;
nxt_int_t ret;
nxt_str_t name, var;
nxt_conf_value_t *member;
nxt_conf_vldt_object_t *vals;
vals = data;
for ( ;; ) {
if (vals->name.length == 0) {
if (vals->u.members != NULL) {
vals = vals->u.members;
continue;
}
break;
}
if (vals->flags & NXT_CONF_VLDT_REQUIRED) {
member = nxt_conf_get_object_member(value, &vals->name, NULL);
if (member == NULL) {
return nxt_conf_vldt_error(vldt, "Required parameter \"%V\" "
"is missing.", &vals->name);
}
}
vals++;
}
index = 0;
for ( ;; ) {
member = nxt_conf_next_object_member(value, &name, &index);
if (member == NULL) {
return NXT_OK;
}
vals = data;
for ( ;; ) {
if (vals->name.length == 0) {
if (vals->u.members != NULL) {
vals = vals->u.members;
continue;
}
return nxt_conf_vldt_error(vldt, "Unknown parameter \"%V\".",
&name);
}
if (!nxt_strstr_eq(&vals->name, &name)) {
vals++;
continue;
}
if (vals->flags & NXT_CONF_VLDT_TSTR
&& nxt_conf_type(member) == NXT_CONF_STRING)
{
nxt_conf_get_string(member, &var);
if (nxt_is_tstr(&var)) {
ret = nxt_conf_vldt_var(vldt, &name, &var);
if (ret != NXT_OK) {
return ret;
}
break;
}
}
ret = nxt_conf_vldt_type(vldt, &name, member, vals->type);
if (ret != NXT_OK) {
return ret;
}
if (vals->validator != NULL) {
ret = vals->validator(vldt, member, vals->u.members);
if (ret != NXT_OK) {
return ret;
}
}
break;
}
}
}
typedef struct {
int64_t spare;
int64_t max;
int64_t idle_timeout;
} nxt_conf_vldt_processes_conf_t;
static nxt_conf_map_t nxt_conf_vldt_processes_conf_map[] = {
{
nxt_string("spare"),
NXT_CONF_MAP_INT64,
offsetof(nxt_conf_vldt_processes_conf_t, spare),
},
{
nxt_string("max"),
NXT_CONF_MAP_INT64,
offsetof(nxt_conf_vldt_processes_conf_t, max),
},
{
nxt_string("idle_timeout"),
NXT_CONF_MAP_INT64,
offsetof(nxt_conf_vldt_processes_conf_t, idle_timeout),
},
};
static nxt_int_t
nxt_conf_vldt_processes(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
void *data)
{
int64_t int_value;
nxt_int_t ret;
nxt_conf_vldt_processes_conf_t proc;
if (nxt_conf_type(value) == NXT_CONF_INTEGER) {
int_value = nxt_conf_get_number(value);
if (int_value < 1) {
return nxt_conf_vldt_error(vldt, "The \"processes\" number must be "
"equal to or greater than 1.");
}
if (int_value > NXT_INT32_T_MAX) {
return nxt_conf_vldt_error(vldt, "The \"processes\" number must "
"not exceed %d.", NXT_INT32_T_MAX);
}
return NXT_OK;
}
ret = nxt_conf_vldt_object(vldt, value, data);
if (ret != NXT_OK) {
return ret;
}
proc.spare = 0;
proc.max = 1;
proc.idle_timeout = 15;
ret = nxt_conf_map_object(vldt->pool, value,
nxt_conf_vldt_processes_conf_map,
nxt_nitems(nxt_conf_vldt_processes_conf_map),
&proc);
if (ret != NXT_OK) {
return ret;
}
if (proc.spare < 0) {
return nxt_conf_vldt_error(vldt, "The \"spare\" number must not be "
"negative.");
}
if (proc.spare > NXT_INT32_T_MAX) {
return nxt_conf_vldt_error(vldt, "The \"spare\" number must not "
"exceed %d.", NXT_INT32_T_MAX);
}
if (proc.max < 1) {
return nxt_conf_vldt_error(vldt, "The \"max\" number must be equal "
"to or greater than 1.");
}
if (proc.max > NXT_INT32_T_MAX) {
return nxt_conf_vldt_error(vldt, "The \"max\" number must not "
"exceed %d.", NXT_INT32_T_MAX);
}
if (proc.max < proc.spare) {
return nxt_conf_vldt_error(vldt, "The \"spare\" number must be "
"less than or equal to \"max\".");
}
if (proc.idle_timeout < 0) {
return nxt_conf_vldt_error(vldt, "The \"idle_timeout\" number must not "
"be negative.");
}
if (proc.idle_timeout > NXT_INT32_T_MAX / 1000) {
return nxt_conf_vldt_error(vldt, "The \"idle_timeout\" number must not "
"exceed %d.", NXT_INT32_T_MAX / 1000);
}
return NXT_OK;
}
static nxt_int_t
nxt_conf_vldt_object_iterator(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data)
{
uint32_t index;
nxt_int_t ret;
nxt_str_t name;
nxt_conf_value_t *member;
nxt_conf_vldt_member_t validator;
validator = (nxt_conf_vldt_member_t) data;
index = 0;
for ( ;; ) {
member = nxt_conf_next_object_member(value, &name, &index);
if (member == NULL) {
return NXT_OK;
}
ret = validator(vldt, &name, member);
if (ret != NXT_OK) {
return ret;
}
}
}
static nxt_int_t
nxt_conf_vldt_array_iterator(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data)
{
uint32_t index;
nxt_int_t ret;
nxt_conf_value_t *element;
nxt_conf_vldt_element_t validator;
validator = (nxt_conf_vldt_element_t) data;
for (index = 0; /* void */ ; index++) {
element = nxt_conf_get_array_element(value, index);
if (element == NULL) {
return NXT_OK;
}
ret = validator(vldt, element);
if (ret != NXT_OK) {
return ret;
}
}
}
static nxt_int_t
nxt_conf_vldt_environment(nxt_conf_validation_t *vldt, nxt_str_t *name,
nxt_conf_value_t *value)
{
nxt_str_t str;
if (name->length == 0) {
return nxt_conf_vldt_error(vldt,
"The environment name must not be empty.");
}
if (memchr(name->start, '\0', name->length) != NULL) {
return nxt_conf_vldt_error(vldt, "The environment name must not "
"contain null character.");
}
if (memchr(name->start, '=', name->length) != NULL) {
return nxt_conf_vldt_error(vldt, "The environment name must not "
"contain '=' character.");
}
if (nxt_conf_type(value) != NXT_CONF_STRING) {
return nxt_conf_vldt_error(vldt, "The \"%V\" environment value must be "
"a string.", name);
}
nxt_conf_get_string(value, &str);
if (memchr(str.start, '\0', str.length) != NULL) {
return nxt_conf_vldt_error(vldt, "The \"%V\" environment value must "
"not contain null character.", name);
}
return NXT_OK;
}
static nxt_int_t
nxt_conf_vldt_targets_exclusive(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data)
{
return nxt_conf_vldt_error(vldt, "The \"%s\" option is mutually exclusive "
"with the \"targets\" object.", data);
}
static nxt_int_t
nxt_conf_vldt_targets(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
void *data)
{
nxt_int_t ret;
nxt_uint_t n;
n = nxt_conf_object_members_count(value);
if (n > 254) {
return nxt_conf_vldt_error(vldt, "The \"targets\" object must not "
"contain more than 254 members.");
}
vldt->ctx = data;
ret = nxt_conf_vldt_object_iterator(vldt, value, &nxt_conf_vldt_target);
vldt->ctx = NULL;
return ret;
}
static nxt_int_t
nxt_conf_vldt_target(nxt_conf_validation_t *vldt, nxt_str_t *name,
nxt_conf_value_t *value)
{
if (name->length == 0) {
return nxt_conf_vldt_error(vldt,
"The target name must not be empty.");
}
if (nxt_conf_type(value) != NXT_CONF_OBJECT) {
return nxt_conf_vldt_error(vldt, "The \"%V\" target must be "
"an object.", name);
}
return nxt_conf_vldt_object(vldt, value, vldt->ctx);
}
#if (NXT_HAVE_CGROUP)
static nxt_int_t
nxt_conf_vldt_cgroup_path(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
void *data)
{
char path[NXT_MAX_PATH_LEN];
nxt_str_t cgpath;
nxt_conf_get_string(value, &cgpath);
if (cgpath.length >= NXT_MAX_PATH_LEN - strlen(NXT_CGROUP_ROOT) - 1) {
return nxt_conf_vldt_error(vldt, "The cgroup path \"%V\" is too long.",
&cgpath);
}
sprintf(path, "/%*s/", (int) cgpath.length, cgpath.start);
if (cgpath.length == 0 || strstr(path, "/../") != NULL) {
return nxt_conf_vldt_error(vldt,
"The cgroup path \"%V\" is invalid.",
&cgpath);
}
return NXT_OK;
}
#endif
static nxt_int_t
nxt_conf_vldt_clone_namespaces(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data)
{
return nxt_conf_vldt_object(vldt, value, data);
}
static nxt_int_t
nxt_conf_vldt_isolation(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
void *data)
{
return nxt_conf_vldt_object(vldt, value, data);
}
#if (NXT_HAVE_CLONE_NEWUSER)
static nxt_int_t
nxt_conf_vldt_clone_uidmap(nxt_conf_validation_t *vldt, nxt_conf_value_t *value)
{
nxt_int_t ret;
if (nxt_conf_type(value) != NXT_CONF_OBJECT) {
return nxt_conf_vldt_error(vldt, "The \"uidmap\" array "
"must contain only object values.");
}
ret = nxt_conf_vldt_object(vldt, value,
(void *) nxt_conf_vldt_app_procmap_members);
if (nxt_slow_path(ret != NXT_OK)) {
return ret;
}
return NXT_OK;
}
static nxt_int_t
nxt_conf_vldt_clone_gidmap(nxt_conf_validation_t *vldt, nxt_conf_value_t *value)
{
nxt_int_t ret;
if (nxt_conf_type(value) != NXT_CONF_OBJECT) {
return nxt_conf_vldt_error(vldt, "The \"gidmap\" array "
"must contain only object values.");
}
ret = nxt_conf_vldt_object(vldt, value,
(void *) nxt_conf_vldt_app_procmap_members);
if (nxt_slow_path(ret != NXT_OK)) {
return ret;
}
return NXT_OK;
}
#endif
static nxt_int_t
nxt_conf_vldt_argument(nxt_conf_validation_t *vldt, nxt_conf_value_t *value)
{
nxt_str_t str;
if (nxt_conf_type(value) != NXT_CONF_STRING) {
return nxt_conf_vldt_error(vldt, "The \"arguments\" array "
"must contain only string values.");
}
nxt_conf_get_string(value, &str);
if (memchr(str.start, '\0', str.length) != NULL) {
return nxt_conf_vldt_error(vldt, "The \"arguments\" array must not "
"contain strings with null character.");
}
return NXT_OK;
}
static nxt_int_t
nxt_conf_vldt_php(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
void *data)
{
nxt_conf_value_t *targets;
static const nxt_str_t targets_str = nxt_string("targets");
targets = nxt_conf_get_object_member(value, &targets_str, NULL);
if (targets != NULL) {
return nxt_conf_vldt_object(vldt, value, nxt_conf_vldt_php_members);
}
return nxt_conf_vldt_object(vldt, value,
nxt_conf_vldt_php_notargets_members);
}
static nxt_int_t
nxt_conf_vldt_php_option(nxt_conf_validation_t *vldt, nxt_str_t *name,
nxt_conf_value_t *value)
{
if (name->length == 0) {
return nxt_conf_vldt_error(vldt,
"The PHP option name must not be empty.");
}
if (nxt_conf_type(value) != NXT_CONF_STRING) {
return nxt_conf_vldt_error(vldt, "The \"%V\" PHP option must be "
"a string.", name);
}
return NXT_OK;
}
static nxt_int_t
nxt_conf_vldt_java_classpath(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value)
{
nxt_str_t str;
if (nxt_conf_type(value) != NXT_CONF_STRING) {
return nxt_conf_vldt_error(vldt, "The \"classpath\" array "
"must contain only string values.");
}
nxt_conf_get_string(value, &str);
if (memchr(str.start, '\0', str.length) != NULL) {
return nxt_conf_vldt_error(vldt, "The \"classpath\" array must not "
"contain strings with null character.");
}
return NXT_OK;
}
static nxt_int_t
nxt_conf_vldt_java_option(nxt_conf_validation_t *vldt, nxt_conf_value_t *value)
{
nxt_str_t str;
if (nxt_conf_type(value) != NXT_CONF_STRING) {
return nxt_conf_vldt_error(vldt, "The \"options\" array "
"must contain only string values.");
}
nxt_conf_get_string(value, &str);
if (memchr(str.start, '\0', str.length) != NULL) {
return nxt_conf_vldt_error(vldt, "The \"options\" array must not "
"contain strings with null character.");
}
return NXT_OK;
}
static nxt_int_t
nxt_conf_vldt_upstream(nxt_conf_validation_t *vldt, nxt_str_t *name,
nxt_conf_value_t *value)
{
nxt_int_t ret;
nxt_conf_value_t *conf;
static const nxt_str_t servers = nxt_string("servers");
ret = nxt_conf_vldt_type(vldt, name, value, NXT_CONF_VLDT_OBJECT);
if (ret != NXT_OK) {
return ret;
}
ret = nxt_conf_vldt_object(vldt, value, nxt_conf_vldt_upstream_members);
if (ret != NXT_OK) {
return ret;
}
conf = nxt_conf_get_object_member(value, &servers, NULL);
if (conf == NULL) {
return nxt_conf_vldt_error(vldt, "The \"%V\" upstream must contain "
"\"servers\" object value.", name);
}
return NXT_OK;
}
static nxt_int_t
nxt_conf_vldt_server(nxt_conf_validation_t *vldt, nxt_str_t *name,
nxt_conf_value_t *value)
{
nxt_int_t ret;
nxt_str_t str;
nxt_sockaddr_t *sa;
ret = nxt_conf_vldt_type(vldt, name, value, NXT_CONF_VLDT_OBJECT);
if (ret != NXT_OK) {
return ret;
}
if (nxt_slow_path(nxt_str_dup(vldt->pool, &str, name) == NULL)) {
return NXT_ERROR;
}
sa = nxt_sockaddr_parse(vldt->pool, &str);
if (sa == NULL) {
return nxt_conf_vldt_error(vldt, "The \"%V\" is not valid "
"server address.", name);
}
return nxt_conf_vldt_object(vldt, value,
nxt_conf_vldt_upstream_server_members);
}
static nxt_int_t
nxt_conf_vldt_server_weight(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data)
{
double num_value;
num_value = nxt_conf_get_number(value);
if (num_value < 0) {
return nxt_conf_vldt_error(vldt, "The \"weight\" number must be "
"positive.");
}
if (num_value > 1000000) {
return nxt_conf_vldt_error(vldt, "The \"weight\" number must "
"not exceed 1,000,000");
}
return NXT_OK;
}
#if (NXT_HAVE_NJS)
static nxt_int_t
nxt_conf_vldt_js_module(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
void *data)
{
if (nxt_conf_type(value) == NXT_CONF_ARRAY) {
return nxt_conf_vldt_array_iterator(vldt, value,
&nxt_conf_vldt_js_module_element);
}
/* NXT_CONF_STRING */
return nxt_conf_vldt_js_module_element(vldt, value);
}
static nxt_int_t
nxt_conf_vldt_js_module_element(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value)
{
nxt_str_t name;
nxt_conf_value_t *module;
if (nxt_conf_type(value) != NXT_CONF_STRING) {
return nxt_conf_vldt_error(vldt, "The \"js_module\" array must "
"contain only string values.");
}
nxt_conf_get_string(value, &name);
module = nxt_script_info_get(&name);
if (module == NULL) {
return nxt_conf_vldt_error(vldt, "JS module \"%V\" is not found.",
&name);
}
return NXT_OK;
}
#endif
typedef struct {
nxt_str_t path;
nxt_str_t format;
} nxt_conf_vldt_access_log_conf_t;
static nxt_conf_map_t nxt_conf_vldt_access_log_map[] = {
{
nxt_string("path"),
NXT_CONF_MAP_STR,
offsetof(nxt_conf_vldt_access_log_conf_t, path),
},
{
nxt_string("format"),
NXT_CONF_MAP_STR,
offsetof(nxt_conf_vldt_access_log_conf_t, format),
},
};
static nxt_int_t
nxt_conf_vldt_access_log(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
void *data)
{
nxt_int_t ret;
nxt_conf_vldt_access_log_conf_t conf;
static const nxt_str_t format_str = nxt_string("format");
if (nxt_conf_type(value) == NXT_CONF_STRING) {
return NXT_OK;
}
ret = nxt_conf_vldt_object(vldt, value, nxt_conf_vldt_access_log_members);
if (ret != NXT_OK) {
return ret;
}
nxt_memzero(&conf, sizeof(nxt_conf_vldt_access_log_conf_t));
ret = nxt_conf_map_object(vldt->pool, value,
nxt_conf_vldt_access_log_map,
nxt_nitems(nxt_conf_vldt_access_log_map),
&conf);
if (ret != NXT_OK) {
return ret;
}
if (conf.path.length == 0) {
return nxt_conf_vldt_error(vldt,
"The \"path\" string must not be empty.");
}
if (nxt_is_tstr(&conf.format)) {
return nxt_conf_vldt_var(vldt, &format_str, &conf.format);
}
return NXT_OK;
}
static nxt_int_t
nxt_conf_vldt_access_log_format(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data)
{
static const nxt_str_t format = nxt_string("format");
if (nxt_conf_type(value) == NXT_CONF_OBJECT) {
return nxt_conf_vldt_object_iterator(vldt, value,
nxt_conf_vldt_access_log_format_field);
}
/* NXT_CONF_STRING */
return nxt_conf_vldt_access_log_format_field(vldt, &format, value);
}
static nxt_int_t
nxt_conf_vldt_access_log_format_field(nxt_conf_validation_t *vldt,
const nxt_str_t *name, nxt_conf_value_t *value)
{
nxt_str_t str;
if (name->length == 0) {
return nxt_conf_vldt_error(vldt, "In the access log format, the name "
"must not be empty.");
}
if (nxt_conf_type(value) != NXT_CONF_STRING) {
return nxt_conf_vldt_error(vldt, "In the access log format, the value "
"must be a string.");
}
nxt_conf_get_string(value, &str);
if (nxt_is_tstr(&str)) {
return nxt_conf_vldt_var(vldt, name, &str);
}
return NXT_OK;
}