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