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