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