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