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