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