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