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