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