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