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