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