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