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