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