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