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