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