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