xref: /unit/src/nxt_conf_validation.c (revision 1942:296628096d6c)
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;
1737 
1738     size = nxt_conf_get_number(value);
1739 
1740     if (size < NXT_THREAD_STACK_MIN) {
1741         return nxt_conf_vldt_error(vldt, "The \"thread_stack_size\" number "
1742                                    "must be equal to or greater than %d.",
1743                                    NXT_THREAD_STACK_MIN);
1744     }
1745 
1746     if ((size % nxt_pagesize) != 0) {
1747         return nxt_conf_vldt_error(vldt, "The \"thread_stack_size\" number "
1748                              "must be a multiple of the system page size (%d).",
1749                              nxt_pagesize);
1750     }
1751 
1752     return NXT_OK;
1753 }
1754 
1755 
1756 static nxt_int_t
1757 nxt_conf_vldt_routes(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
1758     void *data)
1759 {
1760     if (nxt_conf_type(value) == NXT_CONF_ARRAY) {
1761         return nxt_conf_vldt_array_iterator(vldt, value,
1762                                             &nxt_conf_vldt_route);
1763     }
1764 
1765     /* NXT_CONF_OBJECT */
1766 
1767     return nxt_conf_vldt_object_iterator(vldt, value,
1768                                          &nxt_conf_vldt_routes_member);
1769 }
1770 
1771 
1772 static nxt_int_t
1773 nxt_conf_vldt_routes_member(nxt_conf_validation_t *vldt, nxt_str_t *name,
1774     nxt_conf_value_t *value)
1775 {
1776     nxt_int_t  ret;
1777 
1778     ret = nxt_conf_vldt_type(vldt, name, value, NXT_CONF_VLDT_ARRAY);
1779 
1780     if (ret != NXT_OK) {
1781         return ret;
1782     }
1783 
1784     return nxt_conf_vldt_array_iterator(vldt, value, &nxt_conf_vldt_route);
1785 }
1786 
1787 
1788 static nxt_int_t
1789 nxt_conf_vldt_route(nxt_conf_validation_t *vldt, nxt_conf_value_t *value)
1790 {
1791     if (nxt_conf_type(value) != NXT_CONF_OBJECT) {
1792         return nxt_conf_vldt_error(vldt, "The \"routes\" array must contain "
1793                                    "only object values.");
1794     }
1795 
1796     return nxt_conf_vldt_object(vldt, value, nxt_conf_vldt_route_members);
1797 }
1798 
1799 
1800 static nxt_int_t
1801 nxt_conf_vldt_match_patterns(nxt_conf_validation_t *vldt,
1802     nxt_conf_value_t *value, void *data)
1803 {
1804     if (nxt_conf_type(value) == NXT_CONF_ARRAY) {
1805         return nxt_conf_vldt_array_iterator(vldt, value,
1806                                             &nxt_conf_vldt_match_pattern);
1807     }
1808 
1809     /* NXT_CONF_STRING */
1810 
1811     return nxt_conf_vldt_match_pattern(vldt, value);
1812 }
1813 
1814 
1815 static nxt_int_t
1816 nxt_conf_vldt_match_pattern(nxt_conf_validation_t *vldt,
1817     nxt_conf_value_t *value)
1818 {
1819     nxt_str_t        pattern;
1820     nxt_uint_t       i, first, last;
1821 #if (NXT_HAVE_REGEX)
1822     nxt_regex_t      *re;
1823     nxt_regex_err_t  err;
1824 #endif
1825 
1826     if (nxt_conf_type(value) != NXT_CONF_STRING) {
1827         return nxt_conf_vldt_error(vldt, "The \"match\" patterns for \"host\", "
1828                                    "\"uri\", and \"method\" must be strings.");
1829     }
1830 
1831     nxt_conf_get_string(value, &pattern);
1832 
1833     if (pattern.length == 0) {
1834         return NXT_OK;
1835     }
1836 
1837     first = (pattern.start[0] == '!');
1838 
1839     if (first < pattern.length && pattern.start[first] == '~') {
1840 #if (NXT_HAVE_REGEX)
1841         pattern.start += first + 1;
1842         pattern.length -= first + 1;
1843 
1844         re = nxt_regex_compile(vldt->pool, &pattern, &err);
1845         if (nxt_slow_path(re == NULL)) {
1846             if (err.offset < pattern.length) {
1847                 return nxt_conf_vldt_error(vldt, "Invalid regular expression: "
1848                                            "%s at offset %d",
1849                                            err.msg, err.offset);
1850             }
1851 
1852             return nxt_conf_vldt_error(vldt, "Invalid regular expression: %s",
1853                                        err.msg);
1854         }
1855 
1856         return NXT_OK;
1857 #else
1858         return nxt_conf_vldt_error(vldt, "Unit is built without support of "
1859                                    "regular expressions: \"--no-regex\" "
1860                                    "./configure option was set.");
1861 #endif
1862     }
1863 
1864     last = pattern.length - 1;
1865 
1866     for (i = first; i < last; i++) {
1867         if (pattern.start[i] == '*' && pattern.start[i + 1] == '*') {
1868             return nxt_conf_vldt_error(vldt, "The \"match\" pattern must "
1869                                        "not contain double \"*\" markers.");
1870         }
1871     }
1872 
1873     return NXT_OK;
1874 }
1875 
1876 
1877 static nxt_int_t nxt_conf_vldt_match_encoded_patterns_sets(
1878     nxt_conf_validation_t *vldt, nxt_conf_value_t *value, void *data)
1879 {
1880     if (nxt_conf_type(value) == NXT_CONF_ARRAY) {
1881         return nxt_conf_vldt_array_iterator(vldt, value,
1882                                      &nxt_conf_vldt_match_encoded_patterns_set);
1883     }
1884 
1885     /* NXT_CONF_STRING */
1886 
1887     return nxt_conf_vldt_match_encoded_patterns_set(vldt, value);
1888 }
1889 
1890 
1891 static nxt_int_t nxt_conf_vldt_match_encoded_patterns_set(
1892     nxt_conf_validation_t *vldt, nxt_conf_value_t *value)
1893 {
1894     if (nxt_conf_type(value) != NXT_CONF_OBJECT) {
1895         return nxt_conf_vldt_error(vldt, "The \"match\" pattern for "
1896                                    "\"arguments\" must be an object.");
1897     }
1898 
1899     return nxt_conf_vldt_object_iterator(vldt, value,
1900                               &nxt_conf_vldt_match_encoded_patterns_set_member);
1901 }
1902 
1903 
1904 static nxt_int_t
1905 nxt_conf_vldt_match_encoded_patterns_set_member(nxt_conf_validation_t *vldt,
1906     nxt_str_t *name, nxt_conf_value_t *value)
1907 {
1908     u_char  *p, *end;
1909 
1910     if (nxt_slow_path(name->length == 0)) {
1911         return nxt_conf_vldt_error(vldt, "The \"match\" pattern objects must "
1912                                    "not contain empty member names.");
1913     }
1914 
1915     p = nxt_mp_nget(vldt->pool, name->length);
1916     if (nxt_slow_path(p == NULL)) {
1917         return NXT_ERROR;
1918     }
1919 
1920     end = nxt_decode_uri(p, name->start, name->length);
1921     if (nxt_slow_path(end == NULL)) {
1922         return nxt_conf_vldt_error(vldt, "The \"match\" pattern for "
1923                                    "\"arguments\" is encoded but is invalid.");
1924     }
1925 
1926     return nxt_conf_vldt_match_encoded_patterns(vldt, value, NULL);
1927 }
1928 
1929 
1930 static nxt_int_t
1931 nxt_conf_vldt_match_encoded_patterns(nxt_conf_validation_t *vldt,
1932     nxt_conf_value_t *value, void *data)
1933 {
1934     if (nxt_conf_type(value) == NXT_CONF_ARRAY) {
1935         return nxt_conf_vldt_array_iterator(vldt, value,
1936                                           &nxt_conf_vldt_match_encoded_pattern);
1937     }
1938 
1939     /* NXT_CONF_STRING */
1940 
1941     return nxt_conf_vldt_match_encoded_pattern(vldt, value);
1942 }
1943 
1944 
1945 static nxt_int_t
1946 nxt_conf_vldt_match_encoded_pattern(nxt_conf_validation_t *vldt,
1947     nxt_conf_value_t *value)
1948 {
1949     u_char     *p, *end;
1950     nxt_int_t  ret;
1951     nxt_str_t  pattern;
1952 
1953     if (nxt_conf_type(value) != NXT_CONF_STRING) {
1954         return nxt_conf_vldt_error(vldt, "The \"match\" pattern for \"uri\" "
1955                                    "must be a string.");
1956     }
1957 
1958     ret = nxt_conf_vldt_match_pattern(vldt, value);
1959     if (nxt_slow_path(ret != NXT_OK)) {
1960         return ret;
1961     }
1962 
1963     nxt_conf_get_string(value, &pattern);
1964 
1965     p = nxt_mp_nget(vldt->pool, pattern.length);
1966     if (nxt_slow_path(p == NULL)) {
1967         return NXT_ERROR;
1968     }
1969 
1970     end = nxt_decode_uri(p, pattern.start, pattern.length);
1971     if (nxt_slow_path(end == NULL)) {
1972         return nxt_conf_vldt_error(vldt, "The \"match\" pattern for \"uri\" "
1973                                    "is encoded but is invalid.");
1974     }
1975 
1976     return NXT_OK;
1977 }
1978 
1979 
1980 static nxt_int_t
1981 nxt_conf_vldt_match_addrs(nxt_conf_validation_t *vldt,
1982     nxt_conf_value_t *value, void *data)
1983 {
1984     if (nxt_conf_type(value) == NXT_CONF_ARRAY) {
1985         return nxt_conf_vldt_array_iterator(vldt, value,
1986                                             &nxt_conf_vldt_match_addr);
1987     }
1988 
1989     return nxt_conf_vldt_match_addr(vldt, value);
1990 }
1991 
1992 
1993 static nxt_int_t
1994 nxt_conf_vldt_match_addr(nxt_conf_validation_t *vldt,
1995     nxt_conf_value_t *value)
1996 {
1997     nxt_http_route_addr_pattern_t  pattern;
1998 
1999     switch (nxt_http_route_addr_pattern_parse(vldt->pool, &pattern, value)) {
2000 
2001     case NXT_OK:
2002         return NXT_OK;
2003 
2004     case NXT_ADDR_PATTERN_PORT_ERROR:
2005         return nxt_conf_vldt_error(vldt, "The \"address\" port an invalid "
2006                                          "port.");
2007 
2008     case NXT_ADDR_PATTERN_CV_TYPE_ERROR:
2009         return nxt_conf_vldt_error(vldt, "The \"match\" pattern for "
2010                                          "\"address\" must be a string.");
2011 
2012     case NXT_ADDR_PATTERN_LENGTH_ERROR:
2013         return nxt_conf_vldt_error(vldt, "The \"address\" is too short.");
2014 
2015     case NXT_ADDR_PATTERN_FORMAT_ERROR:
2016         return nxt_conf_vldt_error(vldt, "The \"address\" format is invalid.");
2017 
2018     case NXT_ADDR_PATTERN_RANGE_OVERLAP_ERROR:
2019         return nxt_conf_vldt_error(vldt, "The \"address\" range is "
2020                                          "overlapping.");
2021 
2022     case NXT_ADDR_PATTERN_CIDR_ERROR:
2023         return nxt_conf_vldt_error(vldt, "The \"address\" has an invalid CIDR "
2024                                          "prefix.");
2025 
2026     case NXT_ADDR_PATTERN_NO_IPv6_ERROR:
2027         return nxt_conf_vldt_error(vldt, "The \"address\" does not support "
2028                                          "IPv6 with your configuration.");
2029 
2030     default:
2031         return nxt_conf_vldt_error(vldt, "The \"address\" has an unknown "
2032                                          "format.");
2033     }
2034 }
2035 
2036 
2037 static nxt_int_t
2038 nxt_conf_vldt_match_scheme_pattern(nxt_conf_validation_t *vldt,
2039     nxt_conf_value_t *value, void *data)
2040 {
2041     nxt_str_t  scheme;
2042 
2043     static const nxt_str_t  http = nxt_string("http");
2044     static const nxt_str_t  https = nxt_string("https");
2045 
2046     nxt_conf_get_string(value, &scheme);
2047 
2048     if (nxt_strcasestr_eq(&scheme, &http)
2049         || nxt_strcasestr_eq(&scheme, &https))
2050     {
2051         return NXT_OK;
2052     }
2053 
2054     return nxt_conf_vldt_error(vldt, "The \"scheme\" can either be "
2055                                      "\"http\" or \"https\".");
2056 }
2057 
2058 
2059 static nxt_int_t
2060 nxt_conf_vldt_match_patterns_sets(nxt_conf_validation_t *vldt,
2061     nxt_conf_value_t *value, void *data)
2062 {
2063     if (nxt_conf_type(value) == NXT_CONF_ARRAY) {
2064         return nxt_conf_vldt_array_iterator(vldt, value,
2065                                             &nxt_conf_vldt_match_patterns_set);
2066     }
2067 
2068     /* NXT_CONF_OBJECT */
2069 
2070     return nxt_conf_vldt_match_patterns_set(vldt, value);
2071 }
2072 
2073 
2074 static nxt_int_t
2075 nxt_conf_vldt_match_patterns_set(nxt_conf_validation_t *vldt,
2076     nxt_conf_value_t *value)
2077 {
2078     if (nxt_conf_type(value) != NXT_CONF_OBJECT) {
2079         return nxt_conf_vldt_error(vldt, "The \"match\" patterns for "
2080                                    "\"arguments\", \"cookies\", and "
2081                                    "\"headers\" must be objects.");
2082     }
2083 
2084     return nxt_conf_vldt_object_iterator(vldt, value,
2085                                      &nxt_conf_vldt_match_patterns_set_member);
2086 }
2087 
2088 
2089 static nxt_int_t
2090 nxt_conf_vldt_match_patterns_set_member(nxt_conf_validation_t *vldt,
2091     nxt_str_t *name, nxt_conf_value_t *value)
2092 {
2093     if (name->length == 0) {
2094         return nxt_conf_vldt_error(vldt, "The \"match\" pattern objects must "
2095                                    "not contain empty member names.");
2096     }
2097 
2098     return nxt_conf_vldt_match_patterns(vldt, value, NULL);
2099 }
2100 
2101 
2102 #if (NXT_TLS)
2103 
2104 static nxt_int_t
2105 nxt_conf_vldt_certificate(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
2106     void *data)
2107 {
2108     if (nxt_conf_type(value) == NXT_CONF_ARRAY) {
2109         if (nxt_conf_array_elements_count(value) == 0) {
2110             return nxt_conf_vldt_error(vldt, "The \"certificate\" array "
2111                                        "must contain at least one element.");
2112         }
2113 
2114         return nxt_conf_vldt_array_iterator(vldt, value,
2115                                             &nxt_conf_vldt_certificate_element);
2116     }
2117 
2118     /* NXT_CONF_STRING */
2119 
2120     return nxt_conf_vldt_certificate_element(vldt, value);
2121 }
2122 
2123 
2124 static nxt_int_t
2125 nxt_conf_vldt_certificate_element(nxt_conf_validation_t *vldt,
2126     nxt_conf_value_t *value)
2127 {
2128     nxt_str_t         name;
2129     nxt_conf_value_t  *cert;
2130 
2131     if (nxt_conf_type(value) != NXT_CONF_STRING) {
2132         return nxt_conf_vldt_error(vldt, "The \"certificate\" array must "
2133                                    "contain only string values.");
2134     }
2135 
2136     nxt_conf_get_string(value, &name);
2137 
2138     cert = nxt_cert_info_get(&name);
2139 
2140     if (cert == NULL) {
2141         return nxt_conf_vldt_error(vldt, "Certificate \"%V\" is not found.",
2142                                    &name);
2143     }
2144 
2145     return NXT_OK;
2146 }
2147 
2148 
2149 #if (NXT_HAVE_OPENSSL_CONF_CMD)
2150 
2151 static nxt_int_t
2152 nxt_conf_vldt_object_conf_commands(nxt_conf_validation_t *vldt,
2153     nxt_conf_value_t *value, void *data)
2154 {
2155     uint32_t          index;
2156     nxt_int_t         ret;
2157     nxt_str_t         name;
2158     nxt_conf_value_t  *member;
2159 
2160     index = 0;
2161 
2162     for ( ;; ) {
2163         member = nxt_conf_next_object_member(value, &name, &index);
2164 
2165         if (member == NULL) {
2166             break;
2167         }
2168 
2169         ret = nxt_conf_vldt_type(vldt, &name, member, NXT_CONF_VLDT_STRING);
2170         if (ret != NXT_OK) {
2171             return ret;
2172         }
2173     }
2174 
2175     return NXT_OK;
2176 }
2177 
2178 #endif
2179 
2180 #endif
2181 
2182 
2183 static nxt_int_t
2184 nxt_conf_vldt_app_name(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
2185     void *data)
2186 {
2187     nxt_str_t         name;
2188     nxt_conf_value_t  *apps, *app;
2189 
2190     static nxt_str_t  apps_str = nxt_string("applications");
2191 
2192     nxt_conf_get_string(value, &name);
2193 
2194     apps = nxt_conf_get_object_member(vldt->conf, &apps_str, NULL);
2195 
2196     if (nxt_slow_path(apps == NULL)) {
2197         goto error;
2198     }
2199 
2200     app = nxt_conf_get_object_member(apps, &name, NULL);
2201 
2202     if (nxt_slow_path(app == NULL)) {
2203         goto error;
2204     }
2205 
2206     return NXT_OK;
2207 
2208 error:
2209 
2210     return nxt_conf_vldt_error(vldt, "Listening socket is assigned for "
2211                                      "a non existing application \"%V\".",
2212                                      &name);
2213 }
2214 
2215 
2216 static nxt_int_t
2217 nxt_conf_vldt_app(nxt_conf_validation_t *vldt, nxt_str_t *name,
2218     nxt_conf_value_t *value)
2219 {
2220     nxt_int_t              ret;
2221     nxt_str_t              type;
2222     nxt_thread_t           *thread;
2223     nxt_conf_value_t       *type_value;
2224     nxt_app_lang_module_t  *lang;
2225 
2226     static nxt_str_t  type_str = nxt_string("type");
2227 
2228     static struct {
2229         nxt_conf_vldt_handler_t  validator;
2230         nxt_conf_vldt_object_t   *members;
2231 
2232     } types[] = {
2233         { nxt_conf_vldt_object, nxt_conf_vldt_external_members },
2234         { nxt_conf_vldt_python, NULL },
2235         { nxt_conf_vldt_php,    NULL },
2236         { nxt_conf_vldt_object, nxt_conf_vldt_perl_members },
2237         { nxt_conf_vldt_object, nxt_conf_vldt_ruby_members },
2238         { nxt_conf_vldt_object, nxt_conf_vldt_java_members },
2239     };
2240 
2241     ret = nxt_conf_vldt_type(vldt, name, value, NXT_CONF_VLDT_OBJECT);
2242 
2243     if (ret != NXT_OK) {
2244         return ret;
2245     }
2246 
2247     type_value = nxt_conf_get_object_member(value, &type_str, NULL);
2248 
2249     if (type_value == NULL) {
2250         return nxt_conf_vldt_error(vldt,
2251                            "Application must have the \"type\" property set.");
2252     }
2253 
2254     ret = nxt_conf_vldt_type(vldt, &type_str, type_value, NXT_CONF_VLDT_STRING);
2255 
2256     if (ret != NXT_OK) {
2257         return ret;
2258     }
2259 
2260     nxt_conf_get_string(type_value, &type);
2261 
2262     thread = nxt_thread();
2263 
2264     lang = nxt_app_lang_module(thread->runtime, &type);
2265     if (lang == NULL) {
2266         return nxt_conf_vldt_error(vldt,
2267                                    "The module to run \"%V\" is not found "
2268                                    "among the available application modules.",
2269                                    &type);
2270     }
2271 
2272     return types[lang->type].validator(vldt, value, types[lang->type].members);
2273 }
2274 
2275 
2276 static nxt_int_t
2277 nxt_conf_vldt_object(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
2278     void *data)
2279 {
2280     uint32_t                index;
2281     nxt_int_t               ret;
2282     nxt_str_t               name;
2283     nxt_conf_value_t        *member;
2284     nxt_conf_vldt_object_t  *vals;
2285 
2286     vals = data;
2287 
2288     for ( ;; ) {
2289         if (vals->name.length == 0) {
2290 
2291             if (vals->u.members != NULL) {
2292                 vals = vals->u.members;
2293                 continue;
2294             }
2295 
2296             break;
2297         }
2298 
2299         if (vals->flags & NXT_CONF_VLDT_REQUIRED) {
2300             member = nxt_conf_get_object_member(value, &vals->name, NULL);
2301 
2302             if (member == NULL) {
2303                 return nxt_conf_vldt_error(vldt, "Required parameter \"%V\" "
2304                                            "is missing.", &vals->name);
2305             }
2306         }
2307 
2308         vals++;
2309     }
2310 
2311     index = 0;
2312 
2313     for ( ;; ) {
2314         member = nxt_conf_next_object_member(value, &name, &index);
2315 
2316         if (member == NULL) {
2317             return NXT_OK;
2318         }
2319 
2320         vals = data;
2321 
2322         for ( ;; ) {
2323             if (vals->name.length == 0) {
2324 
2325                 if (vals->u.members != NULL) {
2326                     vals = vals->u.members;
2327                     continue;
2328                 }
2329 
2330                 return nxt_conf_vldt_error(vldt, "Unknown parameter \"%V\".",
2331                                            &name);
2332             }
2333 
2334             if (!nxt_strstr_eq(&vals->name, &name)) {
2335                 vals++;
2336                 continue;
2337             }
2338 
2339             ret = nxt_conf_vldt_type(vldt, &name, member, vals->type);
2340 
2341             if (ret != NXT_OK) {
2342                 return ret;
2343             }
2344 
2345             if (vals->validator != NULL) {
2346                 ret = vals->validator(vldt, member, vals->u.members);
2347 
2348                 if (ret != NXT_OK) {
2349                     return ret;
2350                 }
2351             }
2352 
2353             break;
2354         }
2355     }
2356 }
2357 
2358 
2359 typedef struct {
2360     int64_t  spare;
2361     int64_t  max;
2362     int64_t  idle_timeout;
2363 } nxt_conf_vldt_processes_conf_t;
2364 
2365 
2366 static nxt_conf_map_t  nxt_conf_vldt_processes_conf_map[] = {
2367     {
2368         nxt_string("spare"),
2369         NXT_CONF_MAP_INT64,
2370         offsetof(nxt_conf_vldt_processes_conf_t, spare),
2371     },
2372 
2373     {
2374         nxt_string("max"),
2375         NXT_CONF_MAP_INT64,
2376         offsetof(nxt_conf_vldt_processes_conf_t, max),
2377     },
2378 
2379     {
2380         nxt_string("idle_timeout"),
2381         NXT_CONF_MAP_INT64,
2382         offsetof(nxt_conf_vldt_processes_conf_t, idle_timeout),
2383     },
2384 };
2385 
2386 
2387 static nxt_int_t
2388 nxt_conf_vldt_processes(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
2389     void *data)
2390 {
2391     int64_t                         int_value;
2392     nxt_int_t                       ret;
2393     nxt_conf_vldt_processes_conf_t  proc;
2394 
2395     if (nxt_conf_type(value) == NXT_CONF_NUMBER) {
2396         int_value = nxt_conf_get_number(value);
2397 
2398         if (int_value < 1) {
2399             return nxt_conf_vldt_error(vldt, "The \"processes\" number must be "
2400                                        "equal to or greater than 1.");
2401         }
2402 
2403         if (int_value > NXT_INT32_T_MAX) {
2404             return nxt_conf_vldt_error(vldt, "The \"processes\" number must "
2405                                        "not exceed %d.", NXT_INT32_T_MAX);
2406         }
2407 
2408         return NXT_OK;
2409     }
2410 
2411     ret = nxt_conf_vldt_object(vldt, value, data);
2412     if (ret != NXT_OK) {
2413         return ret;
2414     }
2415 
2416     proc.spare = 0;
2417     proc.max = 1;
2418     proc.idle_timeout = 15;
2419 
2420     ret = nxt_conf_map_object(vldt->pool, value,
2421                               nxt_conf_vldt_processes_conf_map,
2422                               nxt_nitems(nxt_conf_vldt_processes_conf_map),
2423                               &proc);
2424     if (ret != NXT_OK) {
2425         return ret;
2426     }
2427 
2428     if (proc.spare < 0) {
2429         return nxt_conf_vldt_error(vldt, "The \"spare\" number must not be "
2430                                    "negative.");
2431     }
2432 
2433     if (proc.spare > NXT_INT32_T_MAX) {
2434         return nxt_conf_vldt_error(vldt, "The \"spare\" number must not "
2435                                    "exceed %d.", NXT_INT32_T_MAX);
2436     }
2437 
2438     if (proc.max < 1) {
2439         return nxt_conf_vldt_error(vldt, "The \"max\" number must be equal "
2440                                    "to or greater than 1.");
2441     }
2442 
2443     if (proc.max > NXT_INT32_T_MAX) {
2444         return nxt_conf_vldt_error(vldt, "The \"max\" number must not "
2445                                    "exceed %d.", NXT_INT32_T_MAX);
2446     }
2447 
2448     if (proc.max < proc.spare) {
2449         return nxt_conf_vldt_error(vldt, "The \"spare\" number must be "
2450                                    "less than or equal to \"max\".");
2451     }
2452 
2453     if (proc.idle_timeout < 0) {
2454         return nxt_conf_vldt_error(vldt, "The \"idle_timeout\" number must not "
2455                                    "be negative.");
2456     }
2457 
2458     if (proc.idle_timeout > NXT_INT32_T_MAX / 1000) {
2459         return nxt_conf_vldt_error(vldt, "The \"idle_timeout\" number must not "
2460                                    "exceed %d.", NXT_INT32_T_MAX / 1000);
2461     }
2462 
2463     return NXT_OK;
2464 }
2465 
2466 
2467 static nxt_int_t
2468 nxt_conf_vldt_object_iterator(nxt_conf_validation_t *vldt,
2469     nxt_conf_value_t *value, void *data)
2470 {
2471     uint32_t                index;
2472     nxt_int_t               ret;
2473     nxt_str_t               name;
2474     nxt_conf_value_t        *member;
2475     nxt_conf_vldt_member_t  validator;
2476 
2477     validator = (nxt_conf_vldt_member_t) data;
2478     index = 0;
2479 
2480     for ( ;; ) {
2481         member = nxt_conf_next_object_member(value, &name, &index);
2482 
2483         if (member == NULL) {
2484             return NXT_OK;
2485         }
2486 
2487         ret = validator(vldt, &name, member);
2488 
2489         if (ret != NXT_OK) {
2490             return ret;
2491         }
2492     }
2493 }
2494 
2495 
2496 static nxt_int_t
2497 nxt_conf_vldt_array_iterator(nxt_conf_validation_t *vldt,
2498     nxt_conf_value_t *value, void *data)
2499 {
2500     uint32_t                 index;
2501     nxt_int_t                ret;
2502     nxt_conf_value_t         *element;
2503     nxt_conf_vldt_element_t  validator;
2504 
2505     validator = (nxt_conf_vldt_element_t) data;
2506 
2507     for (index = 0; /* void */ ; index++) {
2508         element = nxt_conf_get_array_element(value, index);
2509 
2510         if (element == NULL) {
2511             return NXT_OK;
2512         }
2513 
2514         ret = validator(vldt, element);
2515 
2516         if (ret != NXT_OK) {
2517             return ret;
2518         }
2519     }
2520 }
2521 
2522 
2523 static nxt_int_t
2524 nxt_conf_vldt_environment(nxt_conf_validation_t *vldt, nxt_str_t *name,
2525     nxt_conf_value_t *value)
2526 {
2527     nxt_str_t  str;
2528 
2529     if (name->length == 0) {
2530         return nxt_conf_vldt_error(vldt,
2531                                    "The environment name must not be empty.");
2532     }
2533 
2534     if (nxt_memchr(name->start, '\0', name->length) != NULL) {
2535         return nxt_conf_vldt_error(vldt, "The environment name must not "
2536                                    "contain null character.");
2537     }
2538 
2539     if (nxt_memchr(name->start, '=', name->length) != NULL) {
2540         return nxt_conf_vldt_error(vldt, "The environment name must not "
2541                                    "contain '=' character.");
2542     }
2543 
2544     if (nxt_conf_type(value) != NXT_CONF_STRING) {
2545         return nxt_conf_vldt_error(vldt, "The \"%V\" environment value must be "
2546                                    "a string.", name);
2547     }
2548 
2549     nxt_conf_get_string(value, &str);
2550 
2551     if (nxt_memchr(str.start, '\0', str.length) != NULL) {
2552         return nxt_conf_vldt_error(vldt, "The \"%V\" environment value must "
2553                                    "not contain null character.", name);
2554     }
2555 
2556     return NXT_OK;
2557 }
2558 
2559 
2560 static nxt_int_t
2561 nxt_conf_vldt_targets_exclusive(nxt_conf_validation_t *vldt,
2562     nxt_conf_value_t *value, void *data)
2563 {
2564     return nxt_conf_vldt_error(vldt, "The \"%s\" option is mutually exclusive "
2565                                "with the \"targets\" object.", data);
2566 }
2567 
2568 
2569 static nxt_int_t
2570 nxt_conf_vldt_targets(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
2571     void *data)
2572 {
2573     nxt_int_t   ret;
2574     nxt_uint_t  n;
2575 
2576     n = nxt_conf_object_members_count(value);
2577 
2578     if (n > 254) {
2579         return nxt_conf_vldt_error(vldt, "The \"targets\" object must not "
2580                                    "contain more than 254 members.");
2581     }
2582 
2583     vldt->ctx = data;
2584 
2585     ret = nxt_conf_vldt_object_iterator(vldt, value, &nxt_conf_vldt_target);
2586 
2587     vldt->ctx = NULL;
2588 
2589     return ret;
2590 }
2591 
2592 
2593 static nxt_int_t
2594 nxt_conf_vldt_target(nxt_conf_validation_t *vldt, nxt_str_t *name,
2595     nxt_conf_value_t *value)
2596 {
2597     if (name->length == 0) {
2598         return nxt_conf_vldt_error(vldt,
2599                                    "The target name must not be empty.");
2600     }
2601 
2602     if (nxt_conf_type(value) != NXT_CONF_OBJECT) {
2603         return nxt_conf_vldt_error(vldt, "The \"%V\" target must be "
2604                                    "an object.", name);
2605     }
2606 
2607     return nxt_conf_vldt_object(vldt, value, vldt->ctx);
2608 }
2609 
2610 
2611 static nxt_int_t
2612 nxt_conf_vldt_clone_namespaces(nxt_conf_validation_t *vldt,
2613     nxt_conf_value_t *value, void *data)
2614 {
2615     return nxt_conf_vldt_object(vldt, value, data);
2616 }
2617 
2618 
2619 static nxt_int_t
2620 nxt_conf_vldt_isolation(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
2621     void *data)
2622 {
2623     return nxt_conf_vldt_object(vldt, value, data);
2624 }
2625 
2626 
2627 #if (NXT_HAVE_CLONE_NEWUSER)
2628 
2629 typedef struct {
2630     nxt_int_t container;
2631     nxt_int_t host;
2632     nxt_int_t size;
2633 } nxt_conf_vldt_clone_procmap_conf_t;
2634 
2635 
2636 static nxt_conf_map_t nxt_conf_vldt_clone_procmap_conf_map[] = {
2637     {
2638         nxt_string("container"),
2639         NXT_CONF_MAP_INT32,
2640         offsetof(nxt_conf_vldt_clone_procmap_conf_t, container),
2641     },
2642 
2643     {
2644         nxt_string("host"),
2645         NXT_CONF_MAP_INT32,
2646         offsetof(nxt_conf_vldt_clone_procmap_conf_t, host),
2647     },
2648 
2649     {
2650         nxt_string("size"),
2651         NXT_CONF_MAP_INT32,
2652         offsetof(nxt_conf_vldt_clone_procmap_conf_t, size),
2653     },
2654 
2655 };
2656 
2657 
2658 static nxt_int_t
2659 nxt_conf_vldt_clone_procmap(nxt_conf_validation_t *vldt, const char *mapfile,
2660         nxt_conf_value_t *value)
2661 {
2662     nxt_int_t                           ret;
2663     nxt_conf_vldt_clone_procmap_conf_t  procmap;
2664 
2665     procmap.container = -1;
2666     procmap.host = -1;
2667     procmap.size = -1;
2668 
2669     ret = nxt_conf_map_object(vldt->pool, value,
2670                               nxt_conf_vldt_clone_procmap_conf_map,
2671                               nxt_nitems(nxt_conf_vldt_clone_procmap_conf_map),
2672                               &procmap);
2673     if (ret != NXT_OK) {
2674         return ret;
2675     }
2676 
2677     if (procmap.container == -1) {
2678         return nxt_conf_vldt_error(vldt, "The %s requires the "
2679                 "\"container\" field set.", mapfile);
2680     }
2681 
2682     if (procmap.host == -1) {
2683         return nxt_conf_vldt_error(vldt, "The %s requires the "
2684                 "\"host\" field set.", mapfile);
2685     }
2686 
2687     if (procmap.size == -1) {
2688         return nxt_conf_vldt_error(vldt, "The %s requires the "
2689                 "\"size\" field set.", mapfile);
2690     }
2691 
2692     return NXT_OK;
2693 }
2694 
2695 
2696 static nxt_int_t
2697 nxt_conf_vldt_clone_uidmap(nxt_conf_validation_t *vldt, nxt_conf_value_t *value)
2698 {
2699     nxt_int_t  ret;
2700 
2701     if (nxt_conf_type(value) != NXT_CONF_OBJECT) {
2702         return nxt_conf_vldt_error(vldt, "The \"uidmap\" array "
2703                                    "must contain only object values.");
2704     }
2705 
2706     ret = nxt_conf_vldt_object(vldt, value,
2707                                (void *) nxt_conf_vldt_app_procmap_members);
2708     if (nxt_slow_path(ret != NXT_OK)) {
2709         return ret;
2710     }
2711 
2712     return nxt_conf_vldt_clone_procmap(vldt, "uid_map", value);
2713 }
2714 
2715 
2716 static nxt_int_t
2717 nxt_conf_vldt_clone_gidmap(nxt_conf_validation_t *vldt, nxt_conf_value_t *value)
2718 {
2719     nxt_int_t ret;
2720 
2721     if (nxt_conf_type(value) != NXT_CONF_OBJECT) {
2722         return nxt_conf_vldt_error(vldt, "The \"gidmap\" array "
2723                                    "must contain only object values.");
2724     }
2725 
2726     ret = nxt_conf_vldt_object(vldt, value,
2727                                (void *) nxt_conf_vldt_app_procmap_members);
2728     if (nxt_slow_path(ret != NXT_OK)) {
2729         return ret;
2730     }
2731 
2732     return nxt_conf_vldt_clone_procmap(vldt, "gid_map", value);
2733 }
2734 
2735 #endif
2736 
2737 
2738 static nxt_int_t
2739 nxt_conf_vldt_argument(nxt_conf_validation_t *vldt, nxt_conf_value_t *value)
2740 {
2741     nxt_str_t  str;
2742 
2743     if (nxt_conf_type(value) != NXT_CONF_STRING) {
2744         return nxt_conf_vldt_error(vldt, "The \"arguments\" array "
2745                                    "must contain only string values.");
2746     }
2747 
2748     nxt_conf_get_string(value, &str);
2749 
2750     if (nxt_memchr(str.start, '\0', str.length) != NULL) {
2751         return nxt_conf_vldt_error(vldt, "The \"arguments\" array must not "
2752                                    "contain strings with null character.");
2753     }
2754 
2755     return NXT_OK;
2756 }
2757 
2758 
2759 static nxt_int_t
2760 nxt_conf_vldt_php(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
2761     void *data)
2762 {
2763     nxt_conf_value_t  *targets;
2764 
2765     static nxt_str_t  targets_str = nxt_string("targets");
2766 
2767     targets = nxt_conf_get_object_member(value, &targets_str, NULL);
2768 
2769     if (targets != NULL) {
2770         return nxt_conf_vldt_object(vldt, value, nxt_conf_vldt_php_members);
2771     }
2772 
2773     return nxt_conf_vldt_object(vldt, value,
2774                                 nxt_conf_vldt_php_notargets_members);
2775 }
2776 
2777 
2778 static nxt_int_t
2779 nxt_conf_vldt_php_option(nxt_conf_validation_t *vldt, nxt_str_t *name,
2780     nxt_conf_value_t *value)
2781 {
2782     if (name->length == 0) {
2783         return nxt_conf_vldt_error(vldt,
2784                                    "The PHP option name must not be empty.");
2785     }
2786 
2787     if (nxt_conf_type(value) != NXT_CONF_STRING) {
2788         return nxt_conf_vldt_error(vldt, "The \"%V\" PHP option must be "
2789                                    "a string.", name);
2790     }
2791 
2792     return NXT_OK;
2793 }
2794 
2795 
2796 static nxt_int_t
2797 nxt_conf_vldt_java_classpath(nxt_conf_validation_t *vldt,
2798     nxt_conf_value_t *value)
2799 {
2800     nxt_str_t  str;
2801 
2802     if (nxt_conf_type(value) != NXT_CONF_STRING) {
2803         return nxt_conf_vldt_error(vldt, "The \"classpath\" array "
2804                                    "must contain only string values.");
2805     }
2806 
2807     nxt_conf_get_string(value, &str);
2808 
2809     if (nxt_memchr(str.start, '\0', str.length) != NULL) {
2810         return nxt_conf_vldt_error(vldt, "The \"classpath\" array must not "
2811                                    "contain strings with null character.");
2812     }
2813 
2814     return NXT_OK;
2815 }
2816 
2817 
2818 static nxt_int_t
2819 nxt_conf_vldt_java_option(nxt_conf_validation_t *vldt, nxt_conf_value_t *value)
2820 {
2821     nxt_str_t  str;
2822 
2823     if (nxt_conf_type(value) != NXT_CONF_STRING) {
2824         return nxt_conf_vldt_error(vldt, "The \"options\" array "
2825                                    "must contain only string values.");
2826     }
2827 
2828     nxt_conf_get_string(value, &str);
2829 
2830     if (nxt_memchr(str.start, '\0', str.length) != NULL) {
2831         return nxt_conf_vldt_error(vldt, "The \"options\" array must not "
2832                                    "contain strings with null character.");
2833     }
2834 
2835     return NXT_OK;
2836 }
2837 
2838 
2839 static nxt_int_t
2840 nxt_conf_vldt_upstream(nxt_conf_validation_t *vldt, nxt_str_t *name,
2841     nxt_conf_value_t *value)
2842 {
2843     nxt_int_t         ret;
2844     nxt_conf_value_t  *conf;
2845 
2846     static nxt_str_t  servers = nxt_string("servers");
2847 
2848     ret = nxt_conf_vldt_type(vldt, name, value, NXT_CONF_VLDT_OBJECT);
2849 
2850     if (ret != NXT_OK) {
2851         return ret;
2852     }
2853 
2854     ret = nxt_conf_vldt_object(vldt, value, nxt_conf_vldt_upstream_members);
2855 
2856     if (ret != NXT_OK) {
2857         return ret;
2858     }
2859 
2860     conf = nxt_conf_get_object_member(value, &servers, NULL);
2861     if (conf == NULL) {
2862         return nxt_conf_vldt_error(vldt, "The \"%V\" upstream must contain "
2863                                    "\"servers\" object value.", name);
2864     }
2865 
2866     return NXT_OK;
2867 }
2868 
2869 
2870 static nxt_int_t
2871 nxt_conf_vldt_server(nxt_conf_validation_t *vldt, nxt_str_t *name,
2872     nxt_conf_value_t *value)
2873 {
2874     nxt_int_t       ret;
2875     nxt_sockaddr_t  *sa;
2876 
2877     ret = nxt_conf_vldt_type(vldt, name, value, NXT_CONF_VLDT_OBJECT);
2878 
2879     if (ret != NXT_OK) {
2880         return ret;
2881     }
2882 
2883     sa = nxt_sockaddr_parse(vldt->pool, name);
2884 
2885     if (sa == NULL) {
2886         return nxt_conf_vldt_error(vldt, "The \"%V\" is not valid "
2887                                    "server address.", name);
2888     }
2889 
2890     return nxt_conf_vldt_object(vldt, value,
2891                                 nxt_conf_vldt_upstream_server_members);
2892 }
2893 
2894 
2895 static nxt_int_t
2896 nxt_conf_vldt_server_weight(nxt_conf_validation_t *vldt,
2897     nxt_conf_value_t *value, void *data)
2898 {
2899     double  num_value;
2900 
2901     num_value = nxt_conf_get_number(value);
2902 
2903     if (num_value < 0) {
2904         return nxt_conf_vldt_error(vldt, "The \"weight\" number must be "
2905                                    "positive.");
2906     }
2907 
2908     if (num_value > 1000000) {
2909         return nxt_conf_vldt_error(vldt, "The \"weight\" number must "
2910                                    "not exceed 1,000,000");
2911     }
2912 
2913     return NXT_OK;
2914 }
2915