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