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