xref: /unit/src/nxt_conf_validation.c (revision 1969:be6409cdb028)
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     u_char     *p;
1628     nxt_str_t  name, temp;
1629 
1630     static nxt_str_t  uri = nxt_string("$uri");
1631 
1632     if (nxt_conf_type(value) == NXT_CONF_ARRAY) {
1633         if (nxt_conf_array_elements_count(value) == 0) {
1634             return nxt_conf_vldt_error(vldt, "The \"share\" array "
1635                                        "must contain at least one element.");
1636         }
1637 
1638         return nxt_conf_vldt_array_iterator(vldt, value,
1639                                             &nxt_conf_vldt_share_element);
1640     }
1641 
1642     /* NXT_CONF_STRING */
1643 
1644     if (vldt->ver < 12600) {
1645         nxt_conf_get_string(value, &name);
1646 
1647         temp.length = name.length + uri.length;
1648 
1649         temp.start = nxt_mp_get(vldt->conf_pool, temp.length);
1650         if (nxt_slow_path(temp.start == NULL)) {
1651             return NXT_ERROR;
1652         }
1653 
1654         p = nxt_cpymem(temp.start, name.start, name.length);
1655         nxt_memcpy(p, uri.start, uri.length);
1656 
1657         nxt_conf_set_string(value, &temp);
1658     }
1659 
1660     return nxt_conf_vldt_share_element(vldt, value);
1661 }
1662 
1663 
1664 static nxt_int_t
1665 nxt_conf_vldt_share_element(nxt_conf_validation_t *vldt,
1666     nxt_conf_value_t *value)
1667 {
1668     nxt_str_t  str;
1669 
1670     static nxt_str_t  share = nxt_string("share");
1671 
1672     if (nxt_conf_type(value) != NXT_CONF_STRING) {
1673         return nxt_conf_vldt_error(vldt, "The \"share\" array must "
1674                                    "contain only string values.");
1675     }
1676 
1677     nxt_conf_get_string(value, &str);
1678 
1679     if (nxt_is_var(&str)) {
1680         return nxt_conf_vldt_var(vldt, &share, &str);
1681     }
1682 
1683     return NXT_OK;
1684 }
1685 
1686 
1687 static nxt_int_t
1688 nxt_conf_vldt_proxy(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
1689     void *data)
1690 {
1691     nxt_str_t       name;
1692     nxt_sockaddr_t  *sa;
1693 
1694     nxt_conf_get_string(value, &name);
1695 
1696     if (nxt_str_start(&name, "http://", 7)) {
1697         name.length -= 7;
1698         name.start += 7;
1699 
1700         sa = nxt_sockaddr_parse(vldt->pool, &name);
1701         if (sa != NULL) {
1702             return NXT_OK;
1703         }
1704     }
1705 
1706     return nxt_conf_vldt_error(vldt, "The \"proxy\" address is invalid \"%V\"",
1707                                &name);
1708 }
1709 
1710 
1711 static nxt_int_t
1712 nxt_conf_vldt_python(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
1713     void *data)
1714 {
1715     nxt_conf_value_t  *targets;
1716 
1717     static nxt_str_t  targets_str = nxt_string("targets");
1718 
1719     targets = nxt_conf_get_object_member(value, &targets_str, NULL);
1720 
1721     if (targets != NULL) {
1722         return nxt_conf_vldt_object(vldt, value, nxt_conf_vldt_python_members);
1723     }
1724 
1725     return nxt_conf_vldt_object(vldt, value,
1726                                 nxt_conf_vldt_python_notargets_members);
1727 }
1728 
1729 
1730 static nxt_int_t
1731 nxt_conf_vldt_python_path(nxt_conf_validation_t *vldt,
1732     nxt_conf_value_t *value, void *data)
1733 {
1734     if (nxt_conf_type(value) == NXT_CONF_ARRAY) {
1735         return nxt_conf_vldt_array_iterator(vldt, value,
1736                                             &nxt_conf_vldt_python_path_element);
1737     }
1738 
1739     /* NXT_CONF_STRING */
1740 
1741     return NXT_OK;
1742 }
1743 
1744 
1745 static nxt_int_t
1746 nxt_conf_vldt_python_path_element(nxt_conf_validation_t *vldt,
1747     nxt_conf_value_t *value)
1748 {
1749     if (nxt_conf_type(value) != NXT_CONF_STRING) {
1750         return nxt_conf_vldt_error(vldt, "The \"path\" array must contain "
1751                                    "only string values.");
1752     }
1753 
1754     return NXT_OK;
1755 }
1756 
1757 
1758 static nxt_int_t
1759 nxt_conf_vldt_python_protocol(nxt_conf_validation_t *vldt,
1760     nxt_conf_value_t *value, void *data)
1761 {
1762     nxt_str_t  proto;
1763 
1764     static const nxt_str_t  wsgi = nxt_string("wsgi");
1765     static const nxt_str_t  asgi = nxt_string("asgi");
1766 
1767     nxt_conf_get_string(value, &proto);
1768 
1769     if (nxt_strstr_eq(&proto, &wsgi) || nxt_strstr_eq(&proto, &asgi)) {
1770         return NXT_OK;
1771     }
1772 
1773     return nxt_conf_vldt_error(vldt, "The \"protocol\" can either be "
1774                                      "\"wsgi\" or \"asgi\".");
1775 }
1776 
1777 
1778 static nxt_int_t
1779 nxt_conf_vldt_threads(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
1780     void *data)
1781 {
1782     int64_t  threads;
1783 
1784     threads = nxt_conf_get_number(value);
1785 
1786     if (threads < 1) {
1787         return nxt_conf_vldt_error(vldt, "The \"threads\" number must be "
1788                                    "equal to or greater than 1.");
1789     }
1790 
1791     if (threads > NXT_INT32_T_MAX) {
1792         return nxt_conf_vldt_error(vldt, "The \"threads\" number must "
1793                                    "not exceed %d.", NXT_INT32_T_MAX);
1794     }
1795 
1796     return NXT_OK;
1797 }
1798 
1799 
1800 static nxt_int_t
1801 nxt_conf_vldt_thread_stack_size(nxt_conf_validation_t *vldt,
1802     nxt_conf_value_t *value, void *data)
1803 {
1804     int64_t  size, min_size;
1805 
1806     size = nxt_conf_get_number(value);
1807     min_size = sysconf(_SC_THREAD_STACK_MIN);
1808 
1809     if (size < min_size) {
1810         return nxt_conf_vldt_error(vldt, "The \"thread_stack_size\" number "
1811                                    "must be equal to or greater than %d.",
1812                                    min_size);
1813     }
1814 
1815     if ((size % nxt_pagesize) != 0) {
1816         return nxt_conf_vldt_error(vldt, "The \"thread_stack_size\" number "
1817                              "must be a multiple of the system page size (%d).",
1818                              nxt_pagesize);
1819     }
1820 
1821     return NXT_OK;
1822 }
1823 
1824 
1825 static nxt_int_t
1826 nxt_conf_vldt_routes(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
1827     void *data)
1828 {
1829     if (nxt_conf_type(value) == NXT_CONF_ARRAY) {
1830         return nxt_conf_vldt_array_iterator(vldt, value,
1831                                             &nxt_conf_vldt_route);
1832     }
1833 
1834     /* NXT_CONF_OBJECT */
1835 
1836     return nxt_conf_vldt_object_iterator(vldt, value,
1837                                          &nxt_conf_vldt_routes_member);
1838 }
1839 
1840 
1841 static nxt_int_t
1842 nxt_conf_vldt_routes_member(nxt_conf_validation_t *vldt, nxt_str_t *name,
1843     nxt_conf_value_t *value)
1844 {
1845     nxt_int_t  ret;
1846 
1847     ret = nxt_conf_vldt_type(vldt, name, value, NXT_CONF_VLDT_ARRAY);
1848 
1849     if (ret != NXT_OK) {
1850         return ret;
1851     }
1852 
1853     return nxt_conf_vldt_array_iterator(vldt, value, &nxt_conf_vldt_route);
1854 }
1855 
1856 
1857 static nxt_int_t
1858 nxt_conf_vldt_route(nxt_conf_validation_t *vldt, nxt_conf_value_t *value)
1859 {
1860     if (nxt_conf_type(value) != NXT_CONF_OBJECT) {
1861         return nxt_conf_vldt_error(vldt, "The \"routes\" array must contain "
1862                                    "only object values.");
1863     }
1864 
1865     return nxt_conf_vldt_object(vldt, value, nxt_conf_vldt_route_members);
1866 }
1867 
1868 
1869 static nxt_int_t
1870 nxt_conf_vldt_match_patterns(nxt_conf_validation_t *vldt,
1871     nxt_conf_value_t *value, void *data)
1872 {
1873     if (nxt_conf_type(value) == NXT_CONF_ARRAY) {
1874         return nxt_conf_vldt_array_iterator(vldt, value,
1875                                             &nxt_conf_vldt_match_pattern);
1876     }
1877 
1878     /* NXT_CONF_STRING */
1879 
1880     return nxt_conf_vldt_match_pattern(vldt, value);
1881 }
1882 
1883 
1884 static nxt_int_t
1885 nxt_conf_vldt_match_pattern(nxt_conf_validation_t *vldt,
1886     nxt_conf_value_t *value)
1887 {
1888     nxt_str_t        pattern;
1889     nxt_uint_t       i, first, last;
1890 #if (NXT_HAVE_REGEX)
1891     nxt_regex_t      *re;
1892     nxt_regex_err_t  err;
1893 #endif
1894 
1895     if (nxt_conf_type(value) != NXT_CONF_STRING) {
1896         return nxt_conf_vldt_error(vldt, "The \"match\" patterns for \"host\", "
1897                                    "\"uri\", and \"method\" must be strings.");
1898     }
1899 
1900     nxt_conf_get_string(value, &pattern);
1901 
1902     if (pattern.length == 0) {
1903         return NXT_OK;
1904     }
1905 
1906     first = (pattern.start[0] == '!');
1907 
1908     if (first < pattern.length && pattern.start[first] == '~') {
1909 #if (NXT_HAVE_REGEX)
1910         pattern.start += first + 1;
1911         pattern.length -= first + 1;
1912 
1913         re = nxt_regex_compile(vldt->pool, &pattern, &err);
1914         if (nxt_slow_path(re == NULL)) {
1915             if (err.offset < pattern.length) {
1916                 return nxt_conf_vldt_error(vldt, "Invalid regular expression: "
1917                                            "%s at offset %d",
1918                                            err.msg, err.offset);
1919             }
1920 
1921             return nxt_conf_vldt_error(vldt, "Invalid regular expression: %s",
1922                                        err.msg);
1923         }
1924 
1925         return NXT_OK;
1926 #else
1927         return nxt_conf_vldt_error(vldt, "Unit is built without support of "
1928                                    "regular expressions: \"--no-regex\" "
1929                                    "./configure option was set.");
1930 #endif
1931     }
1932 
1933     last = pattern.length - 1;
1934 
1935     for (i = first; i < last; i++) {
1936         if (pattern.start[i] == '*' && pattern.start[i + 1] == '*') {
1937             return nxt_conf_vldt_error(vldt, "The \"match\" pattern must "
1938                                        "not contain double \"*\" markers.");
1939         }
1940     }
1941 
1942     return NXT_OK;
1943 }
1944 
1945 
1946 static nxt_int_t nxt_conf_vldt_match_encoded_patterns_sets(
1947     nxt_conf_validation_t *vldt, nxt_conf_value_t *value, void *data)
1948 {
1949     if (nxt_conf_type(value) == NXT_CONF_ARRAY) {
1950         return nxt_conf_vldt_array_iterator(vldt, value,
1951                                      &nxt_conf_vldt_match_encoded_patterns_set);
1952     }
1953 
1954     /* NXT_CONF_STRING */
1955 
1956     return nxt_conf_vldt_match_encoded_patterns_set(vldt, value);
1957 }
1958 
1959 
1960 static nxt_int_t nxt_conf_vldt_match_encoded_patterns_set(
1961     nxt_conf_validation_t *vldt, nxt_conf_value_t *value)
1962 {
1963     if (nxt_conf_type(value) != NXT_CONF_OBJECT) {
1964         return nxt_conf_vldt_error(vldt, "The \"match\" pattern for "
1965                                    "\"arguments\" must be an object.");
1966     }
1967 
1968     return nxt_conf_vldt_object_iterator(vldt, value,
1969                               &nxt_conf_vldt_match_encoded_patterns_set_member);
1970 }
1971 
1972 
1973 static nxt_int_t
1974 nxt_conf_vldt_match_encoded_patterns_set_member(nxt_conf_validation_t *vldt,
1975     nxt_str_t *name, nxt_conf_value_t *value)
1976 {
1977     u_char  *p, *end;
1978 
1979     if (nxt_slow_path(name->length == 0)) {
1980         return nxt_conf_vldt_error(vldt, "The \"match\" pattern objects must "
1981                                    "not contain empty member names.");
1982     }
1983 
1984     p = nxt_mp_nget(vldt->pool, name->length);
1985     if (nxt_slow_path(p == NULL)) {
1986         return NXT_ERROR;
1987     }
1988 
1989     end = nxt_decode_uri(p, name->start, name->length);
1990     if (nxt_slow_path(end == NULL)) {
1991         return nxt_conf_vldt_error(vldt, "The \"match\" pattern for "
1992                                    "\"arguments\" is encoded but is invalid.");
1993     }
1994 
1995     return nxt_conf_vldt_match_encoded_patterns(vldt, value, NULL);
1996 }
1997 
1998 
1999 static nxt_int_t
2000 nxt_conf_vldt_match_encoded_patterns(nxt_conf_validation_t *vldt,
2001     nxt_conf_value_t *value, void *data)
2002 {
2003     if (nxt_conf_type(value) == NXT_CONF_ARRAY) {
2004         return nxt_conf_vldt_array_iterator(vldt, value,
2005                                           &nxt_conf_vldt_match_encoded_pattern);
2006     }
2007 
2008     /* NXT_CONF_STRING */
2009 
2010     return nxt_conf_vldt_match_encoded_pattern(vldt, value);
2011 }
2012 
2013 
2014 static nxt_int_t
2015 nxt_conf_vldt_match_encoded_pattern(nxt_conf_validation_t *vldt,
2016     nxt_conf_value_t *value)
2017 {
2018     u_char     *p, *end;
2019     nxt_int_t  ret;
2020     nxt_str_t  pattern;
2021 
2022     if (nxt_conf_type(value) != NXT_CONF_STRING) {
2023         return nxt_conf_vldt_error(vldt, "The \"match\" pattern for \"uri\" "
2024                                    "must be a string.");
2025     }
2026 
2027     ret = nxt_conf_vldt_match_pattern(vldt, value);
2028     if (nxt_slow_path(ret != NXT_OK)) {
2029         return ret;
2030     }
2031 
2032     nxt_conf_get_string(value, &pattern);
2033 
2034     p = nxt_mp_nget(vldt->pool, pattern.length);
2035     if (nxt_slow_path(p == NULL)) {
2036         return NXT_ERROR;
2037     }
2038 
2039     end = nxt_decode_uri(p, pattern.start, pattern.length);
2040     if (nxt_slow_path(end == NULL)) {
2041         return nxt_conf_vldt_error(vldt, "The \"match\" pattern for \"uri\" "
2042                                    "is encoded but is invalid.");
2043     }
2044 
2045     return NXT_OK;
2046 }
2047 
2048 
2049 static nxt_int_t
2050 nxt_conf_vldt_match_addrs(nxt_conf_validation_t *vldt,
2051     nxt_conf_value_t *value, void *data)
2052 {
2053     if (nxt_conf_type(value) == NXT_CONF_ARRAY) {
2054         return nxt_conf_vldt_array_iterator(vldt, value,
2055                                             &nxt_conf_vldt_match_addr);
2056     }
2057 
2058     return nxt_conf_vldt_match_addr(vldt, value);
2059 }
2060 
2061 
2062 static nxt_int_t
2063 nxt_conf_vldt_match_addr(nxt_conf_validation_t *vldt,
2064     nxt_conf_value_t *value)
2065 {
2066     nxt_http_route_addr_pattern_t  pattern;
2067 
2068     switch (nxt_http_route_addr_pattern_parse(vldt->pool, &pattern, value)) {
2069 
2070     case NXT_OK:
2071         return NXT_OK;
2072 
2073     case NXT_ADDR_PATTERN_PORT_ERROR:
2074         return nxt_conf_vldt_error(vldt, "The \"address\" port an invalid "
2075                                          "port.");
2076 
2077     case NXT_ADDR_PATTERN_CV_TYPE_ERROR:
2078         return nxt_conf_vldt_error(vldt, "The \"match\" pattern for "
2079                                          "\"address\" must be a string.");
2080 
2081     case NXT_ADDR_PATTERN_LENGTH_ERROR:
2082         return nxt_conf_vldt_error(vldt, "The \"address\" is too short.");
2083 
2084     case NXT_ADDR_PATTERN_FORMAT_ERROR:
2085         return nxt_conf_vldt_error(vldt, "The \"address\" format is invalid.");
2086 
2087     case NXT_ADDR_PATTERN_RANGE_OVERLAP_ERROR:
2088         return nxt_conf_vldt_error(vldt, "The \"address\" range is "
2089                                          "overlapping.");
2090 
2091     case NXT_ADDR_PATTERN_CIDR_ERROR:
2092         return nxt_conf_vldt_error(vldt, "The \"address\" has an invalid CIDR "
2093                                          "prefix.");
2094 
2095     case NXT_ADDR_PATTERN_NO_IPv6_ERROR:
2096         return nxt_conf_vldt_error(vldt, "The \"address\" does not support "
2097                                          "IPv6 with your configuration.");
2098 
2099     default:
2100         return nxt_conf_vldt_error(vldt, "The \"address\" has an unknown "
2101                                          "format.");
2102     }
2103 }
2104 
2105 
2106 static nxt_int_t
2107 nxt_conf_vldt_match_scheme_pattern(nxt_conf_validation_t *vldt,
2108     nxt_conf_value_t *value, void *data)
2109 {
2110     nxt_str_t  scheme;
2111 
2112     static const nxt_str_t  http = nxt_string("http");
2113     static const nxt_str_t  https = nxt_string("https");
2114 
2115     nxt_conf_get_string(value, &scheme);
2116 
2117     if (nxt_strcasestr_eq(&scheme, &http)
2118         || nxt_strcasestr_eq(&scheme, &https))
2119     {
2120         return NXT_OK;
2121     }
2122 
2123     return nxt_conf_vldt_error(vldt, "The \"scheme\" can either be "
2124                                      "\"http\" or \"https\".");
2125 }
2126 
2127 
2128 static nxt_int_t
2129 nxt_conf_vldt_match_patterns_sets(nxt_conf_validation_t *vldt,
2130     nxt_conf_value_t *value, void *data)
2131 {
2132     if (nxt_conf_type(value) == NXT_CONF_ARRAY) {
2133         return nxt_conf_vldt_array_iterator(vldt, value,
2134                                             &nxt_conf_vldt_match_patterns_set);
2135     }
2136 
2137     /* NXT_CONF_OBJECT */
2138 
2139     return nxt_conf_vldt_match_patterns_set(vldt, value);
2140 }
2141 
2142 
2143 static nxt_int_t
2144 nxt_conf_vldt_match_patterns_set(nxt_conf_validation_t *vldt,
2145     nxt_conf_value_t *value)
2146 {
2147     if (nxt_conf_type(value) != NXT_CONF_OBJECT) {
2148         return nxt_conf_vldt_error(vldt, "The \"match\" patterns for "
2149                                    "\"arguments\", \"cookies\", and "
2150                                    "\"headers\" must be objects.");
2151     }
2152 
2153     return nxt_conf_vldt_object_iterator(vldt, value,
2154                                      &nxt_conf_vldt_match_patterns_set_member);
2155 }
2156 
2157 
2158 static nxt_int_t
2159 nxt_conf_vldt_match_patterns_set_member(nxt_conf_validation_t *vldt,
2160     nxt_str_t *name, nxt_conf_value_t *value)
2161 {
2162     if (name->length == 0) {
2163         return nxt_conf_vldt_error(vldt, "The \"match\" pattern objects must "
2164                                    "not contain empty member names.");
2165     }
2166 
2167     return nxt_conf_vldt_match_patterns(vldt, value, NULL);
2168 }
2169 
2170 
2171 #if (NXT_TLS)
2172 
2173 static nxt_int_t
2174 nxt_conf_vldt_certificate(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
2175     void *data)
2176 {
2177     if (nxt_conf_type(value) == NXT_CONF_ARRAY) {
2178         if (nxt_conf_array_elements_count(value) == 0) {
2179             return nxt_conf_vldt_error(vldt, "The \"certificate\" array "
2180                                        "must contain at least one element.");
2181         }
2182 
2183         return nxt_conf_vldt_array_iterator(vldt, value,
2184                                             &nxt_conf_vldt_certificate_element);
2185     }
2186 
2187     /* NXT_CONF_STRING */
2188 
2189     return nxt_conf_vldt_certificate_element(vldt, value);
2190 }
2191 
2192 
2193 static nxt_int_t
2194 nxt_conf_vldt_certificate_element(nxt_conf_validation_t *vldt,
2195     nxt_conf_value_t *value)
2196 {
2197     nxt_str_t         name;
2198     nxt_conf_value_t  *cert;
2199 
2200     if (nxt_conf_type(value) != NXT_CONF_STRING) {
2201         return nxt_conf_vldt_error(vldt, "The \"certificate\" array must "
2202                                    "contain only string values.");
2203     }
2204 
2205     nxt_conf_get_string(value, &name);
2206 
2207     cert = nxt_cert_info_get(&name);
2208 
2209     if (cert == NULL) {
2210         return nxt_conf_vldt_error(vldt, "Certificate \"%V\" is not found.",
2211                                    &name);
2212     }
2213 
2214     return NXT_OK;
2215 }
2216 
2217 
2218 #if (NXT_HAVE_OPENSSL_CONF_CMD)
2219 
2220 static nxt_int_t
2221 nxt_conf_vldt_object_conf_commands(nxt_conf_validation_t *vldt,
2222     nxt_conf_value_t *value, void *data)
2223 {
2224     uint32_t          index;
2225     nxt_int_t         ret;
2226     nxt_str_t         name;
2227     nxt_conf_value_t  *member;
2228 
2229     index = 0;
2230 
2231     for ( ;; ) {
2232         member = nxt_conf_next_object_member(value, &name, &index);
2233 
2234         if (member == NULL) {
2235             break;
2236         }
2237 
2238         ret = nxt_conf_vldt_type(vldt, &name, member, NXT_CONF_VLDT_STRING);
2239         if (ret != NXT_OK) {
2240             return ret;
2241         }
2242     }
2243 
2244     return NXT_OK;
2245 }
2246 
2247 #endif
2248 
2249 #endif
2250 
2251 
2252 static nxt_int_t
2253 nxt_conf_vldt_app_name(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
2254     void *data)
2255 {
2256     nxt_str_t         name;
2257     nxt_conf_value_t  *apps, *app;
2258 
2259     static nxt_str_t  apps_str = nxt_string("applications");
2260 
2261     nxt_conf_get_string(value, &name);
2262 
2263     apps = nxt_conf_get_object_member(vldt->conf, &apps_str, NULL);
2264 
2265     if (nxt_slow_path(apps == NULL)) {
2266         goto error;
2267     }
2268 
2269     app = nxt_conf_get_object_member(apps, &name, NULL);
2270 
2271     if (nxt_slow_path(app == NULL)) {
2272         goto error;
2273     }
2274 
2275     return NXT_OK;
2276 
2277 error:
2278 
2279     return nxt_conf_vldt_error(vldt, "Listening socket is assigned for "
2280                                      "a non existing application \"%V\".",
2281                                      &name);
2282 }
2283 
2284 
2285 static nxt_int_t
2286 nxt_conf_vldt_app(nxt_conf_validation_t *vldt, nxt_str_t *name,
2287     nxt_conf_value_t *value)
2288 {
2289     nxt_int_t              ret;
2290     nxt_str_t              type;
2291     nxt_thread_t           *thread;
2292     nxt_conf_value_t       *type_value;
2293     nxt_app_lang_module_t  *lang;
2294 
2295     static nxt_str_t  type_str = nxt_string("type");
2296 
2297     static struct {
2298         nxt_conf_vldt_handler_t  validator;
2299         nxt_conf_vldt_object_t   *members;
2300 
2301     } types[] = {
2302         { nxt_conf_vldt_object, nxt_conf_vldt_external_members },
2303         { nxt_conf_vldt_python, NULL },
2304         { nxt_conf_vldt_php,    NULL },
2305         { nxt_conf_vldt_object, nxt_conf_vldt_perl_members },
2306         { nxt_conf_vldt_object, nxt_conf_vldt_ruby_members },
2307         { nxt_conf_vldt_object, nxt_conf_vldt_java_members },
2308     };
2309 
2310     ret = nxt_conf_vldt_type(vldt, name, value, NXT_CONF_VLDT_OBJECT);
2311 
2312     if (ret != NXT_OK) {
2313         return ret;
2314     }
2315 
2316     type_value = nxt_conf_get_object_member(value, &type_str, NULL);
2317 
2318     if (type_value == NULL) {
2319         return nxt_conf_vldt_error(vldt,
2320                            "Application must have the \"type\" property set.");
2321     }
2322 
2323     ret = nxt_conf_vldt_type(vldt, &type_str, type_value, NXT_CONF_VLDT_STRING);
2324 
2325     if (ret != NXT_OK) {
2326         return ret;
2327     }
2328 
2329     nxt_conf_get_string(type_value, &type);
2330 
2331     thread = nxt_thread();
2332 
2333     lang = nxt_app_lang_module(thread->runtime, &type);
2334     if (lang == NULL) {
2335         return nxt_conf_vldt_error(vldt,
2336                                    "The module to run \"%V\" is not found "
2337                                    "among the available application modules.",
2338                                    &type);
2339     }
2340 
2341     return types[lang->type].validator(vldt, value, types[lang->type].members);
2342 }
2343 
2344 
2345 static nxt_int_t
2346 nxt_conf_vldt_object(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
2347     void *data)
2348 {
2349     uint32_t                index;
2350     nxt_int_t               ret;
2351     nxt_str_t               name, var;
2352     nxt_conf_value_t        *member;
2353     nxt_conf_vldt_object_t  *vals;
2354 
2355     vals = data;
2356 
2357     for ( ;; ) {
2358         if (vals->name.length == 0) {
2359 
2360             if (vals->u.members != NULL) {
2361                 vals = vals->u.members;
2362                 continue;
2363             }
2364 
2365             break;
2366         }
2367 
2368         if (vals->flags & NXT_CONF_VLDT_REQUIRED) {
2369             member = nxt_conf_get_object_member(value, &vals->name, NULL);
2370 
2371             if (member == NULL) {
2372                 return nxt_conf_vldt_error(vldt, "Required parameter \"%V\" "
2373                                            "is missing.", &vals->name);
2374             }
2375         }
2376 
2377         vals++;
2378     }
2379 
2380     index = 0;
2381 
2382     for ( ;; ) {
2383         member = nxt_conf_next_object_member(value, &name, &index);
2384 
2385         if (member == NULL) {
2386             return NXT_OK;
2387         }
2388 
2389         vals = data;
2390 
2391         for ( ;; ) {
2392             if (vals->name.length == 0) {
2393 
2394                 if (vals->u.members != NULL) {
2395                     vals = vals->u.members;
2396                     continue;
2397                 }
2398 
2399                 return nxt_conf_vldt_error(vldt, "Unknown parameter \"%V\".",
2400                                            &name);
2401             }
2402 
2403             if (!nxt_strstr_eq(&vals->name, &name)) {
2404                 vals++;
2405                 continue;
2406             }
2407 
2408             if (vals->flags & NXT_CONF_VLDT_VAR
2409                 && nxt_conf_type(member) == NXT_CONF_STRING)
2410             {
2411                 nxt_conf_get_string(member, &var);
2412 
2413                 if (nxt_is_var(&var)) {
2414                     ret = nxt_conf_vldt_var(vldt, &name, &var);
2415                     if (ret != NXT_OK) {
2416                         return ret;
2417                     }
2418 
2419                     break;
2420                 }
2421            }
2422 
2423             ret = nxt_conf_vldt_type(vldt, &name, member, vals->type);
2424             if (ret != NXT_OK) {
2425                 return ret;
2426             }
2427 
2428             if (vals->validator != NULL) {
2429                 ret = vals->validator(vldt, member, vals->u.members);
2430 
2431                 if (ret != NXT_OK) {
2432                     return ret;
2433                 }
2434             }
2435 
2436             break;
2437         }
2438     }
2439 }
2440 
2441 
2442 typedef struct {
2443     int64_t  spare;
2444     int64_t  max;
2445     int64_t  idle_timeout;
2446 } nxt_conf_vldt_processes_conf_t;
2447 
2448 
2449 static nxt_conf_map_t  nxt_conf_vldt_processes_conf_map[] = {
2450     {
2451         nxt_string("spare"),
2452         NXT_CONF_MAP_INT64,
2453         offsetof(nxt_conf_vldt_processes_conf_t, spare),
2454     },
2455 
2456     {
2457         nxt_string("max"),
2458         NXT_CONF_MAP_INT64,
2459         offsetof(nxt_conf_vldt_processes_conf_t, max),
2460     },
2461 
2462     {
2463         nxt_string("idle_timeout"),
2464         NXT_CONF_MAP_INT64,
2465         offsetof(nxt_conf_vldt_processes_conf_t, idle_timeout),
2466     },
2467 };
2468 
2469 
2470 static nxt_int_t
2471 nxt_conf_vldt_processes(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
2472     void *data)
2473 {
2474     int64_t                         int_value;
2475     nxt_int_t                       ret;
2476     nxt_conf_vldt_processes_conf_t  proc;
2477 
2478     if (nxt_conf_type(value) == NXT_CONF_NUMBER) {
2479         int_value = nxt_conf_get_number(value);
2480 
2481         if (int_value < 1) {
2482             return nxt_conf_vldt_error(vldt, "The \"processes\" number must be "
2483                                        "equal to or greater than 1.");
2484         }
2485 
2486         if (int_value > NXT_INT32_T_MAX) {
2487             return nxt_conf_vldt_error(vldt, "The \"processes\" number must "
2488                                        "not exceed %d.", NXT_INT32_T_MAX);
2489         }
2490 
2491         return NXT_OK;
2492     }
2493 
2494     ret = nxt_conf_vldt_object(vldt, value, data);
2495     if (ret != NXT_OK) {
2496         return ret;
2497     }
2498 
2499     proc.spare = 0;
2500     proc.max = 1;
2501     proc.idle_timeout = 15;
2502 
2503     ret = nxt_conf_map_object(vldt->pool, value,
2504                               nxt_conf_vldt_processes_conf_map,
2505                               nxt_nitems(nxt_conf_vldt_processes_conf_map),
2506                               &proc);
2507     if (ret != NXT_OK) {
2508         return ret;
2509     }
2510 
2511     if (proc.spare < 0) {
2512         return nxt_conf_vldt_error(vldt, "The \"spare\" number must not be "
2513                                    "negative.");
2514     }
2515 
2516     if (proc.spare > NXT_INT32_T_MAX) {
2517         return nxt_conf_vldt_error(vldt, "The \"spare\" number must not "
2518                                    "exceed %d.", NXT_INT32_T_MAX);
2519     }
2520 
2521     if (proc.max < 1) {
2522         return nxt_conf_vldt_error(vldt, "The \"max\" number must be equal "
2523                                    "to or greater than 1.");
2524     }
2525 
2526     if (proc.max > NXT_INT32_T_MAX) {
2527         return nxt_conf_vldt_error(vldt, "The \"max\" number must not "
2528                                    "exceed %d.", NXT_INT32_T_MAX);
2529     }
2530 
2531     if (proc.max < proc.spare) {
2532         return nxt_conf_vldt_error(vldt, "The \"spare\" number must be "
2533                                    "less than or equal to \"max\".");
2534     }
2535 
2536     if (proc.idle_timeout < 0) {
2537         return nxt_conf_vldt_error(vldt, "The \"idle_timeout\" number must not "
2538                                    "be negative.");
2539     }
2540 
2541     if (proc.idle_timeout > NXT_INT32_T_MAX / 1000) {
2542         return nxt_conf_vldt_error(vldt, "The \"idle_timeout\" number must not "
2543                                    "exceed %d.", NXT_INT32_T_MAX / 1000);
2544     }
2545 
2546     return NXT_OK;
2547 }
2548 
2549 
2550 static nxt_int_t
2551 nxt_conf_vldt_object_iterator(nxt_conf_validation_t *vldt,
2552     nxt_conf_value_t *value, void *data)
2553 {
2554     uint32_t                index;
2555     nxt_int_t               ret;
2556     nxt_str_t               name;
2557     nxt_conf_value_t        *member;
2558     nxt_conf_vldt_member_t  validator;
2559 
2560     validator = (nxt_conf_vldt_member_t) data;
2561     index = 0;
2562 
2563     for ( ;; ) {
2564         member = nxt_conf_next_object_member(value, &name, &index);
2565 
2566         if (member == NULL) {
2567             return NXT_OK;
2568         }
2569 
2570         ret = validator(vldt, &name, member);
2571 
2572         if (ret != NXT_OK) {
2573             return ret;
2574         }
2575     }
2576 }
2577 
2578 
2579 static nxt_int_t
2580 nxt_conf_vldt_array_iterator(nxt_conf_validation_t *vldt,
2581     nxt_conf_value_t *value, void *data)
2582 {
2583     uint32_t                 index;
2584     nxt_int_t                ret;
2585     nxt_conf_value_t         *element;
2586     nxt_conf_vldt_element_t  validator;
2587 
2588     validator = (nxt_conf_vldt_element_t) data;
2589 
2590     for (index = 0; /* void */ ; index++) {
2591         element = nxt_conf_get_array_element(value, index);
2592 
2593         if (element == NULL) {
2594             return NXT_OK;
2595         }
2596 
2597         ret = validator(vldt, element);
2598 
2599         if (ret != NXT_OK) {
2600             return ret;
2601         }
2602     }
2603 }
2604 
2605 
2606 static nxt_int_t
2607 nxt_conf_vldt_environment(nxt_conf_validation_t *vldt, nxt_str_t *name,
2608     nxt_conf_value_t *value)
2609 {
2610     nxt_str_t  str;
2611 
2612     if (name->length == 0) {
2613         return nxt_conf_vldt_error(vldt,
2614                                    "The environment name must not be empty.");
2615     }
2616 
2617     if (nxt_memchr(name->start, '\0', name->length) != NULL) {
2618         return nxt_conf_vldt_error(vldt, "The environment name must not "
2619                                    "contain null character.");
2620     }
2621 
2622     if (nxt_memchr(name->start, '=', name->length) != NULL) {
2623         return nxt_conf_vldt_error(vldt, "The environment name must not "
2624                                    "contain '=' character.");
2625     }
2626 
2627     if (nxt_conf_type(value) != NXT_CONF_STRING) {
2628         return nxt_conf_vldt_error(vldt, "The \"%V\" environment value must be "
2629                                    "a string.", name);
2630     }
2631 
2632     nxt_conf_get_string(value, &str);
2633 
2634     if (nxt_memchr(str.start, '\0', str.length) != NULL) {
2635         return nxt_conf_vldt_error(vldt, "The \"%V\" environment value must "
2636                                    "not contain null character.", name);
2637     }
2638 
2639     return NXT_OK;
2640 }
2641 
2642 
2643 static nxt_int_t
2644 nxt_conf_vldt_targets_exclusive(nxt_conf_validation_t *vldt,
2645     nxt_conf_value_t *value, void *data)
2646 {
2647     return nxt_conf_vldt_error(vldt, "The \"%s\" option is mutually exclusive "
2648                                "with the \"targets\" object.", data);
2649 }
2650 
2651 
2652 static nxt_int_t
2653 nxt_conf_vldt_targets(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
2654     void *data)
2655 {
2656     nxt_int_t   ret;
2657     nxt_uint_t  n;
2658 
2659     n = nxt_conf_object_members_count(value);
2660 
2661     if (n > 254) {
2662         return nxt_conf_vldt_error(vldt, "The \"targets\" object must not "
2663                                    "contain more than 254 members.");
2664     }
2665 
2666     vldt->ctx = data;
2667 
2668     ret = nxt_conf_vldt_object_iterator(vldt, value, &nxt_conf_vldt_target);
2669 
2670     vldt->ctx = NULL;
2671 
2672     return ret;
2673 }
2674 
2675 
2676 static nxt_int_t
2677 nxt_conf_vldt_target(nxt_conf_validation_t *vldt, nxt_str_t *name,
2678     nxt_conf_value_t *value)
2679 {
2680     if (name->length == 0) {
2681         return nxt_conf_vldt_error(vldt,
2682                                    "The target name must not be empty.");
2683     }
2684 
2685     if (nxt_conf_type(value) != NXT_CONF_OBJECT) {
2686         return nxt_conf_vldt_error(vldt, "The \"%V\" target must be "
2687                                    "an object.", name);
2688     }
2689 
2690     return nxt_conf_vldt_object(vldt, value, vldt->ctx);
2691 }
2692 
2693 
2694 static nxt_int_t
2695 nxt_conf_vldt_clone_namespaces(nxt_conf_validation_t *vldt,
2696     nxt_conf_value_t *value, void *data)
2697 {
2698     return nxt_conf_vldt_object(vldt, value, data);
2699 }
2700 
2701 
2702 static nxt_int_t
2703 nxt_conf_vldt_isolation(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
2704     void *data)
2705 {
2706     return nxt_conf_vldt_object(vldt, value, data);
2707 }
2708 
2709 
2710 #if (NXT_HAVE_CLONE_NEWUSER)
2711 
2712 typedef struct {
2713     nxt_int_t container;
2714     nxt_int_t host;
2715     nxt_int_t size;
2716 } nxt_conf_vldt_clone_procmap_conf_t;
2717 
2718 
2719 static nxt_conf_map_t nxt_conf_vldt_clone_procmap_conf_map[] = {
2720     {
2721         nxt_string("container"),
2722         NXT_CONF_MAP_INT32,
2723         offsetof(nxt_conf_vldt_clone_procmap_conf_t, container),
2724     },
2725 
2726     {
2727         nxt_string("host"),
2728         NXT_CONF_MAP_INT32,
2729         offsetof(nxt_conf_vldt_clone_procmap_conf_t, host),
2730     },
2731 
2732     {
2733         nxt_string("size"),
2734         NXT_CONF_MAP_INT32,
2735         offsetof(nxt_conf_vldt_clone_procmap_conf_t, size),
2736     },
2737 
2738 };
2739 
2740 
2741 static nxt_int_t
2742 nxt_conf_vldt_clone_procmap(nxt_conf_validation_t *vldt, const char *mapfile,
2743         nxt_conf_value_t *value)
2744 {
2745     nxt_int_t                           ret;
2746     nxt_conf_vldt_clone_procmap_conf_t  procmap;
2747 
2748     procmap.container = -1;
2749     procmap.host = -1;
2750     procmap.size = -1;
2751 
2752     ret = nxt_conf_map_object(vldt->pool, value,
2753                               nxt_conf_vldt_clone_procmap_conf_map,
2754                               nxt_nitems(nxt_conf_vldt_clone_procmap_conf_map),
2755                               &procmap);
2756     if (ret != NXT_OK) {
2757         return ret;
2758     }
2759 
2760     if (procmap.container == -1) {
2761         return nxt_conf_vldt_error(vldt, "The %s requires the "
2762                 "\"container\" field set.", mapfile);
2763     }
2764 
2765     if (procmap.host == -1) {
2766         return nxt_conf_vldt_error(vldt, "The %s requires the "
2767                 "\"host\" field set.", mapfile);
2768     }
2769 
2770     if (procmap.size == -1) {
2771         return nxt_conf_vldt_error(vldt, "The %s requires the "
2772                 "\"size\" field set.", mapfile);
2773     }
2774 
2775     return NXT_OK;
2776 }
2777 
2778 
2779 static nxt_int_t
2780 nxt_conf_vldt_clone_uidmap(nxt_conf_validation_t *vldt, nxt_conf_value_t *value)
2781 {
2782     nxt_int_t  ret;
2783 
2784     if (nxt_conf_type(value) != NXT_CONF_OBJECT) {
2785         return nxt_conf_vldt_error(vldt, "The \"uidmap\" array "
2786                                    "must contain only object values.");
2787     }
2788 
2789     ret = nxt_conf_vldt_object(vldt, value,
2790                                (void *) nxt_conf_vldt_app_procmap_members);
2791     if (nxt_slow_path(ret != NXT_OK)) {
2792         return ret;
2793     }
2794 
2795     return nxt_conf_vldt_clone_procmap(vldt, "uid_map", value);
2796 }
2797 
2798 
2799 static nxt_int_t
2800 nxt_conf_vldt_clone_gidmap(nxt_conf_validation_t *vldt, nxt_conf_value_t *value)
2801 {
2802     nxt_int_t ret;
2803 
2804     if (nxt_conf_type(value) != NXT_CONF_OBJECT) {
2805         return nxt_conf_vldt_error(vldt, "The \"gidmap\" array "
2806                                    "must contain only object values.");
2807     }
2808 
2809     ret = nxt_conf_vldt_object(vldt, value,
2810                                (void *) nxt_conf_vldt_app_procmap_members);
2811     if (nxt_slow_path(ret != NXT_OK)) {
2812         return ret;
2813     }
2814 
2815     return nxt_conf_vldt_clone_procmap(vldt, "gid_map", value);
2816 }
2817 
2818 #endif
2819 
2820 
2821 static nxt_int_t
2822 nxt_conf_vldt_argument(nxt_conf_validation_t *vldt, nxt_conf_value_t *value)
2823 {
2824     nxt_str_t  str;
2825 
2826     if (nxt_conf_type(value) != NXT_CONF_STRING) {
2827         return nxt_conf_vldt_error(vldt, "The \"arguments\" array "
2828                                    "must contain only string values.");
2829     }
2830 
2831     nxt_conf_get_string(value, &str);
2832 
2833     if (nxt_memchr(str.start, '\0', str.length) != NULL) {
2834         return nxt_conf_vldt_error(vldt, "The \"arguments\" array must not "
2835                                    "contain strings with null character.");
2836     }
2837 
2838     return NXT_OK;
2839 }
2840 
2841 
2842 static nxt_int_t
2843 nxt_conf_vldt_php(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
2844     void *data)
2845 {
2846     nxt_conf_value_t  *targets;
2847 
2848     static nxt_str_t  targets_str = nxt_string("targets");
2849 
2850     targets = nxt_conf_get_object_member(value, &targets_str, NULL);
2851 
2852     if (targets != NULL) {
2853         return nxt_conf_vldt_object(vldt, value, nxt_conf_vldt_php_members);
2854     }
2855 
2856     return nxt_conf_vldt_object(vldt, value,
2857                                 nxt_conf_vldt_php_notargets_members);
2858 }
2859 
2860 
2861 static nxt_int_t
2862 nxt_conf_vldt_php_option(nxt_conf_validation_t *vldt, nxt_str_t *name,
2863     nxt_conf_value_t *value)
2864 {
2865     if (name->length == 0) {
2866         return nxt_conf_vldt_error(vldt,
2867                                    "The PHP option name must not be empty.");
2868     }
2869 
2870     if (nxt_conf_type(value) != NXT_CONF_STRING) {
2871         return nxt_conf_vldt_error(vldt, "The \"%V\" PHP option must be "
2872                                    "a string.", name);
2873     }
2874 
2875     return NXT_OK;
2876 }
2877 
2878 
2879 static nxt_int_t
2880 nxt_conf_vldt_java_classpath(nxt_conf_validation_t *vldt,
2881     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 \"classpath\" 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 \"classpath\" 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_java_option(nxt_conf_validation_t *vldt, nxt_conf_value_t *value)
2903 {
2904     nxt_str_t  str;
2905 
2906     if (nxt_conf_type(value) != NXT_CONF_STRING) {
2907         return nxt_conf_vldt_error(vldt, "The \"options\" array "
2908                                    "must contain only string values.");
2909     }
2910 
2911     nxt_conf_get_string(value, &str);
2912 
2913     if (nxt_memchr(str.start, '\0', str.length) != NULL) {
2914         return nxt_conf_vldt_error(vldt, "The \"options\" array must not "
2915                                    "contain strings with null character.");
2916     }
2917 
2918     return NXT_OK;
2919 }
2920 
2921 
2922 static nxt_int_t
2923 nxt_conf_vldt_upstream(nxt_conf_validation_t *vldt, nxt_str_t *name,
2924     nxt_conf_value_t *value)
2925 {
2926     nxt_int_t         ret;
2927     nxt_conf_value_t  *conf;
2928 
2929     static nxt_str_t  servers = nxt_string("servers");
2930 
2931     ret = nxt_conf_vldt_type(vldt, name, value, NXT_CONF_VLDT_OBJECT);
2932 
2933     if (ret != NXT_OK) {
2934         return ret;
2935     }
2936 
2937     ret = nxt_conf_vldt_object(vldt, value, nxt_conf_vldt_upstream_members);
2938 
2939     if (ret != NXT_OK) {
2940         return ret;
2941     }
2942 
2943     conf = nxt_conf_get_object_member(value, &servers, NULL);
2944     if (conf == NULL) {
2945         return nxt_conf_vldt_error(vldt, "The \"%V\" upstream must contain "
2946                                    "\"servers\" object value.", name);
2947     }
2948 
2949     return NXT_OK;
2950 }
2951 
2952 
2953 static nxt_int_t
2954 nxt_conf_vldt_server(nxt_conf_validation_t *vldt, nxt_str_t *name,
2955     nxt_conf_value_t *value)
2956 {
2957     nxt_int_t       ret;
2958     nxt_sockaddr_t  *sa;
2959 
2960     ret = nxt_conf_vldt_type(vldt, name, value, NXT_CONF_VLDT_OBJECT);
2961 
2962     if (ret != NXT_OK) {
2963         return ret;
2964     }
2965 
2966     sa = nxt_sockaddr_parse(vldt->pool, name);
2967 
2968     if (sa == NULL) {
2969         return nxt_conf_vldt_error(vldt, "The \"%V\" is not valid "
2970                                    "server address.", name);
2971     }
2972 
2973     return nxt_conf_vldt_object(vldt, value,
2974                                 nxt_conf_vldt_upstream_server_members);
2975 }
2976 
2977 
2978 static nxt_int_t
2979 nxt_conf_vldt_server_weight(nxt_conf_validation_t *vldt,
2980     nxt_conf_value_t *value, void *data)
2981 {
2982     double  num_value;
2983 
2984     num_value = nxt_conf_get_number(value);
2985 
2986     if (num_value < 0) {
2987         return nxt_conf_vldt_error(vldt, "The \"weight\" number must be "
2988                                    "positive.");
2989     }
2990 
2991     if (num_value > 1000000) {
2992         return nxt_conf_vldt_error(vldt, "The \"weight\" number must "
2993                                    "not exceed 1,000,000");
2994     }
2995 
2996     return NXT_OK;
2997 }
2998