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