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