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