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