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