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