xref: /unit/src/nxt_conf_validation.c (revision 2247:baa6b9879267)
1 
2 /*
3  * Copyright (C) Valentin V. Bartenev
4  * Copyright (C) NGINX, Inc.
5  */
6 
7 #include <nxt_main.h>
8 #include <nxt_conf.h>
9 #include <nxt_cert.h>
10 #include <nxt_router.h>
11 #include <nxt_http.h>
12 #include <nxt_sockaddr.h>
13 #include <nxt_http_route_addr.h>
14 #include <nxt_regex.h>
15 
16 
17 typedef enum {
18     NXT_CONF_VLDT_NULL    = 1 << NXT_CONF_NULL,
19     NXT_CONF_VLDT_BOOLEAN = 1 << NXT_CONF_BOOLEAN,
20     NXT_CONF_VLDT_INTEGER = 1 << NXT_CONF_INTEGER,
21     NXT_CONF_VLDT_NUMBER  = (1 << NXT_CONF_NUMBER) | NXT_CONF_VLDT_INTEGER,
22     NXT_CONF_VLDT_STRING  = 1 << NXT_CONF_STRING,
23     NXT_CONF_VLDT_ARRAY   = 1 << NXT_CONF_ARRAY,
24     NXT_CONF_VLDT_OBJECT  = 1 << NXT_CONF_OBJECT,
25 } nxt_conf_vldt_type_t;
26 
27 #define NXT_CONF_VLDT_ANY_TYPE  (NXT_CONF_VLDT_NULL                           \
28                                  |NXT_CONF_VLDT_BOOLEAN                       \
29                                  |NXT_CONF_VLDT_NUMBER                        \
30                                  |NXT_CONF_VLDT_STRING                        \
31                                  |NXT_CONF_VLDT_ARRAY                         \
32                                  |NXT_CONF_VLDT_OBJECT)
33 
34 
35 typedef enum {
36     NXT_CONF_VLDT_REQUIRED  = 1 << 0,
37     NXT_CONF_VLDT_TSTR      = 1 << 1,
38 } nxt_conf_vldt_flags_t;
39 
40 
41 typedef nxt_int_t (*nxt_conf_vldt_handler_t)(nxt_conf_validation_t *vldt,
42                                              nxt_conf_value_t *value,
43                                              void *data);
44 typedef nxt_int_t (*nxt_conf_vldt_member_t)(nxt_conf_validation_t *vldt,
45                                             nxt_str_t *name,
46                                             nxt_conf_value_t *value);
47 typedef nxt_int_t (*nxt_conf_vldt_element_t)(nxt_conf_validation_t *vldt,
48                                              nxt_conf_value_t *value);
49 
50 
51 typedef struct nxt_conf_vldt_object_s  nxt_conf_vldt_object_t;
52 
53 struct nxt_conf_vldt_object_s {
54     nxt_str_t                     name;
55     nxt_conf_vldt_type_t          type:32;
56     nxt_conf_vldt_flags_t         flags:32;
57     nxt_conf_vldt_handler_t       validator;
58 
59     union {
60         nxt_conf_vldt_object_t    *members;
61         nxt_conf_vldt_object_t    *next;
62         nxt_conf_vldt_member_t    object;
63         nxt_conf_vldt_element_t   array;
64         const char                *string;
65     } u;
66 };
67 
68 
69 #define NXT_CONF_VLDT_NEXT(next)  { .u.members = next }
70 #define NXT_CONF_VLDT_END         { .name = nxt_null_string }
71 
72 
73 static nxt_int_t nxt_conf_vldt_type(nxt_conf_validation_t *vldt,
74     nxt_str_t *name, nxt_conf_value_t *value, nxt_conf_vldt_type_t type);
75 static nxt_int_t nxt_conf_vldt_error(nxt_conf_validation_t *vldt,
76     const char *fmt, ...);
77 static nxt_int_t nxt_conf_vldt_var(nxt_conf_validation_t *vldt, nxt_str_t *name,
78     nxt_str_t *value);
79 nxt_inline nxt_int_t nxt_conf_vldt_unsupported(nxt_conf_validation_t *vldt,
80     nxt_conf_value_t *value, void *data)
81     NXT_MAYBE_UNUSED;
82 
83 static nxt_int_t nxt_conf_vldt_mtypes(nxt_conf_validation_t *vldt,
84     nxt_conf_value_t *value, void *data);
85 static nxt_int_t nxt_conf_vldt_mtypes_type(nxt_conf_validation_t *vldt,
86     nxt_str_t *name, nxt_conf_value_t *value);
87 static nxt_int_t nxt_conf_vldt_mtypes_extension(nxt_conf_validation_t *vldt,
88     nxt_conf_value_t *value);
89 static nxt_int_t nxt_conf_vldt_listener(nxt_conf_validation_t *vldt,
90     nxt_str_t *name, nxt_conf_value_t *value);
91 #if (NXT_TLS)
92 static nxt_int_t nxt_conf_vldt_certificate(nxt_conf_validation_t *vldt,
93     nxt_conf_value_t *value, void *data);
94 #if (NXT_HAVE_OPENSSL_CONF_CMD)
95 static nxt_int_t nxt_conf_vldt_object_conf_commands(nxt_conf_validation_t *vldt,
96     nxt_conf_value_t *value, void *data);
97 #endif
98 static nxt_int_t nxt_conf_vldt_certificate_element(nxt_conf_validation_t *vldt,
99     nxt_conf_value_t *value);
100 static nxt_int_t nxt_conf_vldt_tls_cache_size(nxt_conf_validation_t *vldt,
101     nxt_conf_value_t *value, void *data);
102 static nxt_int_t nxt_conf_vldt_tls_timeout(nxt_conf_validation_t *vldt,
103     nxt_conf_value_t *value, void *data);
104 #if (NXT_HAVE_OPENSSL_TLSEXT)
105 static nxt_int_t nxt_conf_vldt_ticket_key(nxt_conf_validation_t *vldt,
106     nxt_conf_value_t *value, void *data);
107 static nxt_int_t nxt_conf_vldt_ticket_key_element(nxt_conf_validation_t *vldt,
108     nxt_conf_value_t *value);
109 #endif
110 #endif
111 static nxt_int_t nxt_conf_vldt_action(nxt_conf_validation_t *vldt,
112     nxt_conf_value_t *value, void *data);
113 static nxt_int_t nxt_conf_vldt_pass(nxt_conf_validation_t *vldt,
114     nxt_conf_value_t *value, void *data);
115 static nxt_int_t nxt_conf_vldt_return(nxt_conf_validation_t *vldt,
116     nxt_conf_value_t *value, void *data);
117 static nxt_int_t nxt_conf_vldt_share(nxt_conf_validation_t *vldt,
118     nxt_conf_value_t *value, void *data);
119 static nxt_int_t nxt_conf_vldt_share_element(nxt_conf_validation_t *vldt,
120     nxt_conf_value_t *value);
121 static nxt_int_t nxt_conf_vldt_proxy(nxt_conf_validation_t *vldt,
122     nxt_conf_value_t *value, void *data);
123 static nxt_int_t nxt_conf_vldt_python(nxt_conf_validation_t *vldt,
124     nxt_conf_value_t *value, void *data);
125 static nxt_int_t nxt_conf_vldt_python_path(nxt_conf_validation_t *vldt,
126     nxt_conf_value_t *value, void *data);
127 static nxt_int_t nxt_conf_vldt_python_path_element(nxt_conf_validation_t *vldt,
128     nxt_conf_value_t *value);
129 static nxt_int_t nxt_conf_vldt_python_protocol(nxt_conf_validation_t *vldt,
130     nxt_conf_value_t *value, void *data);
131 static nxt_int_t nxt_conf_vldt_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_TSTR,
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_TSTR,
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_TSTR,
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_TSTR,
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     u_char     error[NXT_MAX_ERROR_STR];
1230 
1231     vldt->tstr_state = nxt_tstr_state_new(vldt->pool, 1);
1232     if (nxt_slow_path(vldt->tstr_state == NULL)) {
1233         return NXT_ERROR;
1234     }
1235 
1236     ret = nxt_conf_vldt_type(vldt, NULL, vldt->conf, NXT_CONF_VLDT_OBJECT);
1237     if (ret != NXT_OK) {
1238         return ret;
1239     }
1240 
1241     ret = nxt_conf_vldt_object(vldt, vldt->conf, nxt_conf_vldt_root_members);
1242     if (ret != NXT_OK) {
1243         return ret;
1244     }
1245 
1246     ret = nxt_tstr_state_done(vldt->tstr_state, error);
1247     if (ret != NXT_OK) {
1248         return nxt_conf_vldt_error(vldt, "%s", error);
1249     }
1250 
1251     return NXT_OK;
1252 }
1253 
1254 
1255 #define NXT_CONF_VLDT_ANY_TYPE_STR                                            \
1256     "either a null, a boolean, an integer, "                                  \
1257     "a number, a string, an array, or an object"
1258 
1259 
1260 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)1261 nxt_conf_vldt_type(nxt_conf_validation_t *vldt, nxt_str_t *name,
1262     nxt_conf_value_t *value, nxt_conf_vldt_type_t type)
1263 {
1264     u_char      *p;
1265     nxt_str_t   expected;
1266     nxt_bool_t  comma;
1267     nxt_uint_t  value_type, n, t;
1268     u_char      buf[nxt_length(NXT_CONF_VLDT_ANY_TYPE_STR)];
1269 
1270     static nxt_str_t  type_name[] = {
1271         nxt_string("a null"),
1272         nxt_string("a boolean"),
1273         nxt_string("an integer number"),
1274         nxt_string("a fractional number"),
1275         nxt_string("a string"),
1276         nxt_string("an array"),
1277         nxt_string("an object"),
1278     };
1279 
1280     value_type = nxt_conf_type(value);
1281 
1282     if ((1 << value_type) & type) {
1283         return NXT_OK;
1284     }
1285 
1286     p = buf;
1287 
1288     n = nxt_popcount(type);
1289 
1290     if (n > 1) {
1291         p = nxt_cpymem(p, "either ", 7);
1292     }
1293 
1294     comma = (n > 2);
1295 
1296     for ( ;; ) {
1297         t = __builtin_ffs(type) - 1;
1298 
1299         p = nxt_cpymem(p, type_name[t].start, type_name[t].length);
1300 
1301         n--;
1302 
1303         if (n == 0) {
1304             break;
1305         }
1306 
1307         if (comma) {
1308             *p++ = ',';
1309         }
1310 
1311         if (n == 1) {
1312             p = nxt_cpymem(p, " or", 3);
1313         }
1314 
1315         *p++ = ' ';
1316 
1317         type = type & ~(1 << t);
1318     }
1319 
1320     expected.length = p - buf;
1321     expected.start = buf;
1322 
1323     if (name == NULL) {
1324         return nxt_conf_vldt_error(vldt,
1325                                    "The configuration must be %V, but not %V.",
1326                                    &expected, &type_name[value_type]);
1327     }
1328 
1329     return nxt_conf_vldt_error(vldt,
1330                                "The \"%V\" value must be %V, but not %V.",
1331                                name, &expected, &type_name[value_type]);
1332 }
1333 
1334 
1335 static nxt_int_t
nxt_conf_vldt_error(nxt_conf_validation_t * vldt,const char * fmt,...)1336 nxt_conf_vldt_error(nxt_conf_validation_t *vldt, const char *fmt, ...)
1337 {
1338     u_char   *p, *end;
1339     size_t   size;
1340     va_list  args;
1341     u_char   error[NXT_MAX_ERROR_STR];
1342 
1343     va_start(args, fmt);
1344     end = nxt_vsprintf(error, error + NXT_MAX_ERROR_STR, fmt, args);
1345     va_end(args);
1346 
1347     size = end - error;
1348 
1349     p = nxt_mp_nget(vldt->pool, size);
1350     if (p == NULL) {
1351         return NXT_ERROR;
1352     }
1353 
1354     nxt_memcpy(p, error, size);
1355 
1356     vldt->error.length = size;
1357     vldt->error.start = p;
1358 
1359     return NXT_DECLINED;
1360 }
1361 
1362 
1363 nxt_inline nxt_int_t
nxt_conf_vldt_unsupported(nxt_conf_validation_t * vldt,nxt_conf_value_t * value,void * data)1364 nxt_conf_vldt_unsupported(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
1365     void *data)
1366 {
1367     return nxt_conf_vldt_error(vldt, "Unit is built without the \"%s\" "
1368                                      "option support.", data);
1369 }
1370 
1371 
1372 static nxt_int_t
nxt_conf_vldt_var(nxt_conf_validation_t * vldt,nxt_str_t * name,nxt_str_t * value)1373 nxt_conf_vldt_var(nxt_conf_validation_t *vldt, nxt_str_t *name,
1374     nxt_str_t *value)
1375 {
1376     u_char  error[NXT_MAX_ERROR_STR];
1377 
1378     if (nxt_tstr_test(vldt->tstr_state, value, error) != NXT_OK) {
1379         return nxt_conf_vldt_error(vldt, "%s in the \"%V\" value.",
1380                                    error, name);
1381     }
1382 
1383     return NXT_OK;
1384 }
1385 
1386 
1387 typedef struct {
1388     nxt_mp_t      *pool;
1389     nxt_str_t     *type;
1390     nxt_lvlhsh_t  hash;
1391 } nxt_conf_vldt_mtypes_ctx_t;
1392 
1393 
1394 static nxt_int_t
nxt_conf_vldt_mtypes(nxt_conf_validation_t * vldt,nxt_conf_value_t * value,void * data)1395 nxt_conf_vldt_mtypes(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
1396     void *data)
1397 {
1398     nxt_int_t                   ret;
1399     nxt_conf_vldt_mtypes_ctx_t  ctx;
1400 
1401     ctx.pool = nxt_mp_create(1024, 128, 256, 32);
1402     if (nxt_slow_path(ctx.pool == NULL)) {
1403         return NXT_ERROR;
1404     }
1405 
1406     nxt_lvlhsh_init(&ctx.hash);
1407 
1408     vldt->ctx = &ctx;
1409 
1410     ret = nxt_conf_vldt_object_iterator(vldt, value,
1411                                         &nxt_conf_vldt_mtypes_type);
1412 
1413     vldt->ctx = NULL;
1414 
1415     nxt_mp_destroy(ctx.pool);
1416 
1417     return ret;
1418 }
1419 
1420 
1421 static nxt_int_t
nxt_conf_vldt_mtypes_type(nxt_conf_validation_t * vldt,nxt_str_t * name,nxt_conf_value_t * value)1422 nxt_conf_vldt_mtypes_type(nxt_conf_validation_t *vldt, nxt_str_t *name,
1423     nxt_conf_value_t *value)
1424 {
1425     nxt_int_t                   ret;
1426     nxt_conf_vldt_mtypes_ctx_t  *ctx;
1427 
1428     ret = nxt_conf_vldt_type(vldt, name, value,
1429                              NXT_CONF_VLDT_STRING|NXT_CONF_VLDT_ARRAY);
1430     if (ret != NXT_OK) {
1431         return ret;
1432     }
1433 
1434     ctx = vldt->ctx;
1435 
1436     ctx->type = nxt_mp_get(ctx->pool, sizeof(nxt_str_t));
1437     if (nxt_slow_path(ctx->type == NULL)) {
1438         return NXT_ERROR;
1439     }
1440 
1441     *ctx->type = *name;
1442 
1443     if (nxt_conf_type(value) == NXT_CONF_ARRAY) {
1444         return nxt_conf_vldt_array_iterator(vldt, value,
1445                                             &nxt_conf_vldt_mtypes_extension);
1446     }
1447 
1448     /* NXT_CONF_STRING */
1449 
1450     return nxt_conf_vldt_mtypes_extension(vldt, value);
1451 }
1452 
1453 
1454 static nxt_int_t
nxt_conf_vldt_mtypes_extension(nxt_conf_validation_t * vldt,nxt_conf_value_t * value)1455 nxt_conf_vldt_mtypes_extension(nxt_conf_validation_t *vldt,
1456     nxt_conf_value_t *value)
1457 {
1458     nxt_str_t                   exten, *dup_type;
1459     nxt_conf_vldt_mtypes_ctx_t  *ctx;
1460 
1461     ctx = vldt->ctx;
1462 
1463     if (nxt_conf_type(value) != NXT_CONF_STRING) {
1464         return nxt_conf_vldt_error(vldt, "The \"%V\" MIME type array must "
1465                                    "contain only strings.", ctx->type);
1466     }
1467 
1468     nxt_conf_get_string(value, &exten);
1469 
1470     if (exten.length == 0) {
1471         return nxt_conf_vldt_error(vldt, "An empty file extension for "
1472                                          "the \"%V\" MIME type.", ctx->type);
1473     }
1474 
1475     dup_type = nxt_http_static_mtype_get(&ctx->hash, &exten);
1476 
1477     if (dup_type->length != 0) {
1478         return nxt_conf_vldt_error(vldt, "The \"%V\" file extension has been "
1479                                          "declared for \"%V\" and \"%V\" "
1480                                          "MIME types at the same time.",
1481                                          &exten, dup_type, ctx->type);
1482     }
1483 
1484     return nxt_http_static_mtypes_hash_add(ctx->pool, &ctx->hash, &exten,
1485                                            ctx->type);
1486 }
1487 
1488 
1489 static nxt_int_t
nxt_conf_vldt_listener(nxt_conf_validation_t * vldt,nxt_str_t * name,nxt_conf_value_t * value)1490 nxt_conf_vldt_listener(nxt_conf_validation_t *vldt, nxt_str_t *name,
1491     nxt_conf_value_t *value)
1492 {
1493     nxt_int_t       ret;
1494     nxt_str_t       str;
1495     nxt_sockaddr_t  *sa;
1496 
1497     if (nxt_slow_path(nxt_str_dup(vldt->pool, &str, name) == NULL)) {
1498         return NXT_ERROR;
1499     }
1500 
1501     sa = nxt_sockaddr_parse(vldt->pool, &str);
1502     if (nxt_slow_path(sa == NULL)) {
1503         return nxt_conf_vldt_error(vldt,
1504                                    "The listener address \"%V\" is invalid.",
1505                                    name);
1506     }
1507 
1508     ret = nxt_conf_vldt_type(vldt, name, value, NXT_CONF_VLDT_OBJECT);
1509     if (ret != NXT_OK) {
1510         return ret;
1511     }
1512 
1513     return nxt_conf_vldt_object(vldt, value, nxt_conf_vldt_listener_members);
1514 }
1515 
1516 
1517 static nxt_int_t
nxt_conf_vldt_action(nxt_conf_validation_t * vldt,nxt_conf_value_t * value,void * data)1518 nxt_conf_vldt_action(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
1519     void *data)
1520 {
1521     nxt_uint_t              i;
1522     nxt_conf_value_t        *action;
1523     nxt_conf_vldt_object_t  *members;
1524 
1525     static struct {
1526         nxt_str_t               name;
1527         nxt_conf_vldt_object_t  *members;
1528 
1529     } actions[] = {
1530         { nxt_string("pass"), nxt_conf_vldt_pass_action_members },
1531         { nxt_string("return"), nxt_conf_vldt_return_action_members },
1532         { nxt_string("share"), nxt_conf_vldt_share_action_members },
1533         { nxt_string("proxy"), nxt_conf_vldt_proxy_action_members },
1534     };
1535 
1536     members = NULL;
1537 
1538     for (i = 0; i < nxt_nitems(actions); i++) {
1539         action = nxt_conf_get_object_member(value, &actions[i].name, NULL);
1540 
1541         if (action == NULL) {
1542             continue;
1543         }
1544 
1545         if (members != NULL) {
1546             return nxt_conf_vldt_error(vldt, "The \"action\" object must have "
1547                                        "just one of \"pass\", \"return\", "
1548                                        "\"share\", or \"proxy\" options set.");
1549         }
1550 
1551         members = actions[i].members;
1552     }
1553 
1554     if (members == NULL) {
1555         return nxt_conf_vldt_error(vldt, "The \"action\" object must have "
1556                                    "either \"pass\", \"return\", \"share\", "
1557                                    "or \"proxy\" option set.");
1558     }
1559 
1560     return nxt_conf_vldt_object(vldt, value, members);
1561 }
1562 
1563 
1564 static nxt_int_t
nxt_conf_vldt_pass(nxt_conf_validation_t * vldt,nxt_conf_value_t * value,void * data)1565 nxt_conf_vldt_pass(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
1566     void *data)
1567 {
1568     nxt_str_t  pass;
1569     nxt_int_t  ret;
1570     nxt_str_t  segments[3];
1571 
1572     static nxt_str_t  targets_str = nxt_string("targets");
1573 
1574     nxt_conf_get_string(value, &pass);
1575 
1576     ret = nxt_http_pass_segments(vldt->pool, &pass, segments, 3);
1577 
1578     if (ret != NXT_OK) {
1579         if (ret == NXT_DECLINED) {
1580             return nxt_conf_vldt_error(vldt, "Request \"pass\" value \"%V\" "
1581                                        "is invalid.", &pass);
1582         }
1583 
1584         return NXT_ERROR;
1585     }
1586 
1587     if (nxt_str_eq(&segments[0], "applications", 12)) {
1588 
1589         if (segments[1].length == 0) {
1590             goto error;
1591         }
1592 
1593         value = nxt_conf_get_object_member(vldt->conf, &segments[0], NULL);
1594 
1595         if (value == NULL) {
1596             goto error;
1597         }
1598 
1599         value = nxt_conf_get_object_member(value, &segments[1], NULL);
1600 
1601         if (value == NULL) {
1602             goto error;
1603         }
1604 
1605         if (segments[2].length > 0) {
1606             value = nxt_conf_get_object_member(value, &targets_str, NULL);
1607 
1608             if (value == NULL) {
1609                 goto error;
1610             }
1611 
1612             value = nxt_conf_get_object_member(value, &segments[2], NULL);
1613 
1614             if (value == NULL) {
1615                 goto error;
1616             }
1617         }
1618 
1619         return NXT_OK;
1620     }
1621 
1622     if (nxt_str_eq(&segments[0], "upstreams", 9)) {
1623 
1624         if (segments[1].length == 0 || segments[2].length != 0) {
1625             goto error;
1626         }
1627 
1628         value = nxt_conf_get_object_member(vldt->conf, &segments[0], NULL);
1629 
1630         if (value == NULL) {
1631             goto error;
1632         }
1633 
1634         value = nxt_conf_get_object_member(value, &segments[1], NULL);
1635 
1636         if (value == NULL) {
1637             goto error;
1638         }
1639 
1640         return NXT_OK;
1641     }
1642 
1643     if (nxt_str_eq(&segments[0], "routes", 6)) {
1644 
1645         if (segments[2].length != 0) {
1646             goto error;
1647         }
1648 
1649         value = nxt_conf_get_object_member(vldt->conf, &segments[0], NULL);
1650 
1651         if (value == NULL) {
1652             goto error;
1653         }
1654 
1655         if (segments[1].length == 0) {
1656             if (nxt_conf_type(value) != NXT_CONF_ARRAY) {
1657                 goto error;
1658             }
1659 
1660             return NXT_OK;
1661         }
1662 
1663         if (nxt_conf_type(value) != NXT_CONF_OBJECT) {
1664             goto error;
1665         }
1666 
1667         value = nxt_conf_get_object_member(value, &segments[1], NULL);
1668 
1669         if (value == NULL) {
1670             goto error;
1671         }
1672 
1673         return NXT_OK;
1674     }
1675 
1676 error:
1677 
1678     return nxt_conf_vldt_error(vldt, "Request \"pass\" points to invalid "
1679                                "location \"%V\".", &pass);
1680 }
1681 
1682 
1683 static nxt_int_t
nxt_conf_vldt_return(nxt_conf_validation_t * vldt,nxt_conf_value_t * value,void * data)1684 nxt_conf_vldt_return(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
1685     void *data)
1686 {
1687     int64_t  status;
1688 
1689     status = nxt_conf_get_number(value);
1690 
1691     if (status < NXT_HTTP_INVALID || status > NXT_HTTP_STATUS_MAX) {
1692         return nxt_conf_vldt_error(vldt, "The \"return\" value is out of "
1693                                    "allowed HTTP status code range 0-999.");
1694     }
1695 
1696     return NXT_OK;
1697 }
1698 
1699 
1700 static nxt_int_t
nxt_conf_vldt_share(nxt_conf_validation_t * vldt,nxt_conf_value_t * value,void * data)1701 nxt_conf_vldt_share(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
1702     void *data)
1703 {
1704     if (nxt_conf_type(value) == NXT_CONF_ARRAY) {
1705         if (nxt_conf_array_elements_count(value) == 0) {
1706             return nxt_conf_vldt_error(vldt, "The \"share\" array "
1707                                        "must contain at least one element.");
1708         }
1709 
1710         return nxt_conf_vldt_array_iterator(vldt, value,
1711                                             &nxt_conf_vldt_share_element);
1712     }
1713 
1714     /* NXT_CONF_STRING */
1715 
1716     return nxt_conf_vldt_share_element(vldt, value);
1717 }
1718 
1719 
1720 static nxt_int_t
nxt_conf_vldt_share_element(nxt_conf_validation_t * vldt,nxt_conf_value_t * value)1721 nxt_conf_vldt_share_element(nxt_conf_validation_t *vldt,
1722     nxt_conf_value_t *value)
1723 {
1724     nxt_str_t  str;
1725 
1726     static nxt_str_t  share = nxt_string("share");
1727 
1728     if (nxt_conf_type(value) != NXT_CONF_STRING) {
1729         return nxt_conf_vldt_error(vldt, "The \"share\" array must "
1730                                    "contain only string values.");
1731     }
1732 
1733     nxt_conf_get_string(value, &str);
1734 
1735     if (nxt_is_tstr(&str)) {
1736         return nxt_conf_vldt_var(vldt, &share, &str);
1737     }
1738 
1739     return NXT_OK;
1740 }
1741 
1742 
1743 static nxt_int_t
nxt_conf_vldt_proxy(nxt_conf_validation_t * vldt,nxt_conf_value_t * value,void * data)1744 nxt_conf_vldt_proxy(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
1745     void *data)
1746 {
1747     nxt_str_t       name;
1748     nxt_sockaddr_t  *sa;
1749 
1750     nxt_conf_get_string(value, &name);
1751 
1752     if (nxt_str_start(&name, "http://", 7)) {
1753         name.length -= 7;
1754         name.start += 7;
1755 
1756         sa = nxt_sockaddr_parse(vldt->pool, &name);
1757         if (sa != NULL) {
1758             return NXT_OK;
1759         }
1760     }
1761 
1762     return nxt_conf_vldt_error(vldt, "The \"proxy\" address is invalid \"%V\"",
1763                                &name);
1764 }
1765 
1766 
1767 static nxt_int_t
nxt_conf_vldt_python(nxt_conf_validation_t * vldt,nxt_conf_value_t * value,void * data)1768 nxt_conf_vldt_python(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
1769     void *data)
1770 {
1771     nxt_conf_value_t  *targets;
1772 
1773     static nxt_str_t  targets_str = nxt_string("targets");
1774 
1775     targets = nxt_conf_get_object_member(value, &targets_str, NULL);
1776 
1777     if (targets != NULL) {
1778         return nxt_conf_vldt_object(vldt, value, nxt_conf_vldt_python_members);
1779     }
1780 
1781     return nxt_conf_vldt_object(vldt, value,
1782                                 nxt_conf_vldt_python_notargets_members);
1783 }
1784 
1785 
1786 static nxt_int_t
nxt_conf_vldt_python_path(nxt_conf_validation_t * vldt,nxt_conf_value_t * value,void * data)1787 nxt_conf_vldt_python_path(nxt_conf_validation_t *vldt,
1788     nxt_conf_value_t *value, void *data)
1789 {
1790     if (nxt_conf_type(value) == NXT_CONF_ARRAY) {
1791         return nxt_conf_vldt_array_iterator(vldt, value,
1792                                             &nxt_conf_vldt_python_path_element);
1793     }
1794 
1795     /* NXT_CONF_STRING */
1796 
1797     return NXT_OK;
1798 }
1799 
1800 
1801 static nxt_int_t
nxt_conf_vldt_python_path_element(nxt_conf_validation_t * vldt,nxt_conf_value_t * value)1802 nxt_conf_vldt_python_path_element(nxt_conf_validation_t *vldt,
1803     nxt_conf_value_t *value)
1804 {
1805     if (nxt_conf_type(value) != NXT_CONF_STRING) {
1806         return nxt_conf_vldt_error(vldt, "The \"path\" array must contain "
1807                                    "only string values.");
1808     }
1809 
1810     return NXT_OK;
1811 }
1812 
1813 
1814 static nxt_int_t
nxt_conf_vldt_python_protocol(nxt_conf_validation_t * vldt,nxt_conf_value_t * value,void * data)1815 nxt_conf_vldt_python_protocol(nxt_conf_validation_t *vldt,
1816     nxt_conf_value_t *value, void *data)
1817 {
1818     nxt_str_t  proto;
1819 
1820     static const nxt_str_t  wsgi = nxt_string("wsgi");
1821     static const nxt_str_t  asgi = nxt_string("asgi");
1822 
1823     nxt_conf_get_string(value, &proto);
1824 
1825     if (nxt_strstr_eq(&proto, &wsgi) || nxt_strstr_eq(&proto, &asgi)) {
1826         return NXT_OK;
1827     }
1828 
1829     return nxt_conf_vldt_error(vldt, "The \"protocol\" can either be "
1830                                      "\"wsgi\" or \"asgi\".");
1831 }
1832 
1833 
1834 static nxt_int_t
nxt_conf_vldt_threads(nxt_conf_validation_t * vldt,nxt_conf_value_t * value,void * data)1835 nxt_conf_vldt_threads(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
1836     void *data)
1837 {
1838     int64_t  threads;
1839 
1840     threads = nxt_conf_get_number(value);
1841 
1842     if (threads < 1) {
1843         return nxt_conf_vldt_error(vldt, "The \"threads\" number must be "
1844                                    "equal to or greater than 1.");
1845     }
1846 
1847     if (threads > NXT_INT32_T_MAX) {
1848         return nxt_conf_vldt_error(vldt, "The \"threads\" number must "
1849                                    "not exceed %d.", NXT_INT32_T_MAX);
1850     }
1851 
1852     return NXT_OK;
1853 }
1854 
1855 
1856 static nxt_int_t
nxt_conf_vldt_thread_stack_size(nxt_conf_validation_t * vldt,nxt_conf_value_t * value,void * data)1857 nxt_conf_vldt_thread_stack_size(nxt_conf_validation_t *vldt,
1858     nxt_conf_value_t *value, void *data)
1859 {
1860     int64_t  size, min_size;
1861 
1862     size = nxt_conf_get_number(value);
1863     min_size = sysconf(_SC_THREAD_STACK_MIN);
1864 
1865     if (size < min_size) {
1866         return nxt_conf_vldt_error(vldt, "The \"thread_stack_size\" number "
1867                                    "must be equal to or greater than %d.",
1868                                    min_size);
1869     }
1870 
1871     if ((size % nxt_pagesize) != 0) {
1872         return nxt_conf_vldt_error(vldt, "The \"thread_stack_size\" number "
1873                              "must be a multiple of the system page size (%d).",
1874                              nxt_pagesize);
1875     }
1876 
1877     return NXT_OK;
1878 }
1879 
1880 
1881 static nxt_int_t
nxt_conf_vldt_routes(nxt_conf_validation_t * vldt,nxt_conf_value_t * value,void * data)1882 nxt_conf_vldt_routes(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
1883     void *data)
1884 {
1885     if (nxt_conf_type(value) == NXT_CONF_ARRAY) {
1886         return nxt_conf_vldt_array_iterator(vldt, value,
1887                                             &nxt_conf_vldt_route);
1888     }
1889 
1890     /* NXT_CONF_OBJECT */
1891 
1892     return nxt_conf_vldt_object_iterator(vldt, value,
1893                                          &nxt_conf_vldt_routes_member);
1894 }
1895 
1896 
1897 static nxt_int_t
nxt_conf_vldt_routes_member(nxt_conf_validation_t * vldt,nxt_str_t * name,nxt_conf_value_t * value)1898 nxt_conf_vldt_routes_member(nxt_conf_validation_t *vldt, nxt_str_t *name,
1899     nxt_conf_value_t *value)
1900 {
1901     nxt_int_t  ret;
1902 
1903     ret = nxt_conf_vldt_type(vldt, name, value, NXT_CONF_VLDT_ARRAY);
1904 
1905     if (ret != NXT_OK) {
1906         return ret;
1907     }
1908 
1909     return nxt_conf_vldt_array_iterator(vldt, value, &nxt_conf_vldt_route);
1910 }
1911 
1912 
1913 static nxt_int_t
nxt_conf_vldt_route(nxt_conf_validation_t * vldt,nxt_conf_value_t * value)1914 nxt_conf_vldt_route(nxt_conf_validation_t *vldt, nxt_conf_value_t *value)
1915 {
1916     if (nxt_conf_type(value) != NXT_CONF_OBJECT) {
1917         return nxt_conf_vldt_error(vldt, "The \"routes\" array must contain "
1918                                    "only object values.");
1919     }
1920 
1921     return nxt_conf_vldt_object(vldt, value, nxt_conf_vldt_route_members);
1922 }
1923 
1924 
1925 static nxt_int_t
nxt_conf_vldt_match_patterns(nxt_conf_validation_t * vldt,nxt_conf_value_t * value,void * data)1926 nxt_conf_vldt_match_patterns(nxt_conf_validation_t *vldt,
1927     nxt_conf_value_t *value, void *data)
1928 {
1929     nxt_int_t  ret;
1930 
1931     vldt->ctx = data;
1932 
1933     if (nxt_conf_type(value) == NXT_CONF_ARRAY) {
1934         ret = nxt_conf_vldt_array_iterator(vldt, value,
1935                                            &nxt_conf_vldt_match_pattern);
1936 
1937     } else {
1938         /* NXT_CONF_STRING */
1939         ret = nxt_conf_vldt_match_pattern(vldt, value);
1940     }
1941 
1942     vldt->ctx = NULL;
1943 
1944     return ret;
1945 }
1946 
1947 
1948 static nxt_int_t
nxt_conf_vldt_match_pattern(nxt_conf_validation_t * vldt,nxt_conf_value_t * value)1949 nxt_conf_vldt_match_pattern(nxt_conf_validation_t *vldt,
1950     nxt_conf_value_t *value)
1951 {
1952     nxt_str_t        pattern;
1953     nxt_uint_t       i, first, last;
1954 #if (NXT_HAVE_REGEX)
1955     nxt_regex_t      *re;
1956     nxt_regex_err_t  err;
1957 #endif
1958 
1959     if (nxt_conf_type(value) != NXT_CONF_STRING) {
1960         return nxt_conf_vldt_error(vldt, "The \"match\" pattern for \"%s\" "
1961                                    "must be strings.", vldt->ctx);
1962     }
1963 
1964     nxt_conf_get_string(value, &pattern);
1965 
1966     if (pattern.length == 0) {
1967         return NXT_OK;
1968     }
1969 
1970     first = (pattern.start[0] == '!');
1971 
1972     if (first < pattern.length && pattern.start[first] == '~') {
1973 #if (NXT_HAVE_REGEX)
1974         pattern.start += first + 1;
1975         pattern.length -= first + 1;
1976 
1977         re = nxt_regex_compile(vldt->pool, &pattern, &err);
1978         if (nxt_slow_path(re == NULL)) {
1979             if (err.offset < pattern.length) {
1980                 return nxt_conf_vldt_error(vldt, "Invalid regular expression: "
1981                                            "%s at offset %d",
1982                                            err.msg, err.offset);
1983             }
1984 
1985             return nxt_conf_vldt_error(vldt, "Invalid regular expression: %s",
1986                                        err.msg);
1987         }
1988 
1989         return NXT_OK;
1990 #else
1991         return nxt_conf_vldt_error(vldt, "Unit is built without support of "
1992                                    "regular expressions: \"--no-regex\" "
1993                                    "./configure option was set.");
1994 #endif
1995     }
1996 
1997     last = pattern.length - 1;
1998 
1999     for (i = first; i < last; i++) {
2000         if (pattern.start[i] == '*' && pattern.start[i + 1] == '*') {
2001             return nxt_conf_vldt_error(vldt, "The \"match\" pattern must "
2002                                        "not contain double \"*\" markers.");
2003         }
2004     }
2005 
2006     return NXT_OK;
2007 }
2008 
2009 
nxt_conf_vldt_match_encoded_patterns_sets(nxt_conf_validation_t * vldt,nxt_conf_value_t * value,void * data)2010 static nxt_int_t nxt_conf_vldt_match_encoded_patterns_sets(
2011     nxt_conf_validation_t *vldt, nxt_conf_value_t *value, void *data)
2012 {
2013     if (nxt_conf_type(value) == NXT_CONF_ARRAY) {
2014         return nxt_conf_vldt_array_iterator(vldt, value,
2015                                      &nxt_conf_vldt_match_encoded_patterns_set);
2016     }
2017 
2018     /* NXT_CONF_OBJECT */
2019 
2020     return nxt_conf_vldt_match_encoded_patterns_set(vldt, value);
2021 }
2022 
2023 
nxt_conf_vldt_match_encoded_patterns_set(nxt_conf_validation_t * vldt,nxt_conf_value_t * value)2024 static nxt_int_t nxt_conf_vldt_match_encoded_patterns_set(
2025     nxt_conf_validation_t *vldt, nxt_conf_value_t *value)
2026 {
2027     if (nxt_conf_type(value) != NXT_CONF_OBJECT) {
2028         return nxt_conf_vldt_error(vldt, "The \"match\" pattern for "
2029                                    "\"arguments\" must be an object.");
2030     }
2031 
2032     return nxt_conf_vldt_object_iterator(vldt, value,
2033                               &nxt_conf_vldt_match_encoded_patterns_set_member);
2034 }
2035 
2036 
2037 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)2038 nxt_conf_vldt_match_encoded_patterns_set_member(nxt_conf_validation_t *vldt,
2039     nxt_str_t *name, nxt_conf_value_t *value)
2040 {
2041     u_char  *p, *end;
2042 
2043     if (nxt_slow_path(name->length == 0)) {
2044         return nxt_conf_vldt_error(vldt, "The \"match\" pattern objects must "
2045                                    "not contain empty member names.");
2046     }
2047 
2048     p = nxt_mp_nget(vldt->pool, name->length);
2049     if (nxt_slow_path(p == NULL)) {
2050         return NXT_ERROR;
2051     }
2052 
2053     end = nxt_decode_uri(p, name->start, name->length);
2054     if (nxt_slow_path(end == NULL)) {
2055         return nxt_conf_vldt_error(vldt, "The \"match\" pattern for "
2056                                    "\"arguments\" is encoded but is invalid.");
2057     }
2058 
2059     return nxt_conf_vldt_match_encoded_patterns(vldt, value,
2060                                                 (void *) "arguments");
2061 }
2062 
2063 
2064 static nxt_int_t
nxt_conf_vldt_match_encoded_patterns(nxt_conf_validation_t * vldt,nxt_conf_value_t * value,void * data)2065 nxt_conf_vldt_match_encoded_patterns(nxt_conf_validation_t *vldt,
2066     nxt_conf_value_t *value, void *data)
2067 {
2068     nxt_int_t  ret;
2069 
2070     vldt->ctx = data;
2071 
2072     if (nxt_conf_type(value) == NXT_CONF_ARRAY) {
2073         ret = nxt_conf_vldt_array_iterator(vldt, value,
2074                                           &nxt_conf_vldt_match_encoded_pattern);
2075 
2076     } else {
2077         /* NXT_CONF_STRING */
2078         ret = nxt_conf_vldt_match_encoded_pattern(vldt, value);
2079     }
2080 
2081     vldt->ctx = NULL;
2082 
2083     return ret;
2084 }
2085 
2086 
2087 static nxt_int_t
nxt_conf_vldt_match_encoded_pattern(nxt_conf_validation_t * vldt,nxt_conf_value_t * value)2088 nxt_conf_vldt_match_encoded_pattern(nxt_conf_validation_t *vldt,
2089     nxt_conf_value_t *value)
2090 {
2091     u_char     *p, *end;
2092     nxt_int_t  ret;
2093     nxt_str_t  pattern;
2094 
2095     if (nxt_conf_type(value) != NXT_CONF_STRING) {
2096         return nxt_conf_vldt_error(vldt, "The \"match\" pattern for \"%s\" "
2097                                    "must be a string.", vldt->ctx);
2098     }
2099 
2100     ret = nxt_conf_vldt_match_pattern(vldt, value);
2101     if (nxt_slow_path(ret != NXT_OK)) {
2102         return ret;
2103     }
2104 
2105     nxt_conf_get_string(value, &pattern);
2106 
2107     p = nxt_mp_nget(vldt->pool, pattern.length);
2108     if (nxt_slow_path(p == NULL)) {
2109         return NXT_ERROR;
2110     }
2111 
2112     end = nxt_decode_uri(p, pattern.start, pattern.length);
2113     if (nxt_slow_path(end == NULL)) {
2114         return nxt_conf_vldt_error(vldt, "The \"match\" pattern for \"%s\" "
2115                                    "is encoded but is invalid.", vldt->ctx);
2116     }
2117 
2118     return NXT_OK;
2119 }
2120 
2121 
2122 static nxt_int_t
nxt_conf_vldt_match_addrs(nxt_conf_validation_t * vldt,nxt_conf_value_t * value,void * data)2123 nxt_conf_vldt_match_addrs(nxt_conf_validation_t *vldt,
2124     nxt_conf_value_t *value, void *data)
2125 {
2126     if (nxt_conf_type(value) == NXT_CONF_ARRAY) {
2127         return nxt_conf_vldt_array_iterator(vldt, value,
2128                                             &nxt_conf_vldt_match_addr);
2129     }
2130 
2131     return nxt_conf_vldt_match_addr(vldt, value);
2132 }
2133 
2134 
2135 static nxt_int_t
nxt_conf_vldt_match_addr(nxt_conf_validation_t * vldt,nxt_conf_value_t * value)2136 nxt_conf_vldt_match_addr(nxt_conf_validation_t *vldt,
2137     nxt_conf_value_t *value)
2138 {
2139     nxt_http_route_addr_pattern_t  pattern;
2140 
2141     switch (nxt_http_route_addr_pattern_parse(vldt->pool, &pattern, value)) {
2142 
2143     case NXT_OK:
2144         return NXT_OK;
2145 
2146     case NXT_ADDR_PATTERN_PORT_ERROR:
2147         return nxt_conf_vldt_error(vldt, "The \"address\" port an invalid "
2148                                          "port.");
2149 
2150     case NXT_ADDR_PATTERN_CV_TYPE_ERROR:
2151         return nxt_conf_vldt_error(vldt, "The \"match\" pattern for "
2152                                          "\"address\" must be a string.");
2153 
2154     case NXT_ADDR_PATTERN_LENGTH_ERROR:
2155         return nxt_conf_vldt_error(vldt, "The \"address\" is too short.");
2156 
2157     case NXT_ADDR_PATTERN_FORMAT_ERROR:
2158         return nxt_conf_vldt_error(vldt, "The \"address\" format is invalid.");
2159 
2160     case NXT_ADDR_PATTERN_RANGE_OVERLAP_ERROR:
2161         return nxt_conf_vldt_error(vldt, "The \"address\" range is "
2162                                          "overlapping.");
2163 
2164     case NXT_ADDR_PATTERN_CIDR_ERROR:
2165         return nxt_conf_vldt_error(vldt, "The \"address\" has an invalid CIDR "
2166                                          "prefix.");
2167 
2168     case NXT_ADDR_PATTERN_NO_IPv6_ERROR:
2169         return nxt_conf_vldt_error(vldt, "The \"address\" does not support "
2170                                          "IPv6 with your configuration.");
2171 
2172     case NXT_ADDR_PATTERN_NO_UNIX_ERROR:
2173         return nxt_conf_vldt_error(vldt, "The \"address\" does not support "
2174                                          "UNIX domain sockets with your "
2175                                          "configuration.");
2176 
2177     default:
2178         return nxt_conf_vldt_error(vldt, "The \"address\" has an unknown "
2179                                          "format.");
2180     }
2181 }
2182 
2183 
2184 static nxt_int_t
nxt_conf_vldt_match_scheme_pattern(nxt_conf_validation_t * vldt,nxt_conf_value_t * value,void * data)2185 nxt_conf_vldt_match_scheme_pattern(nxt_conf_validation_t *vldt,
2186     nxt_conf_value_t *value, void *data)
2187 {
2188     nxt_str_t  scheme;
2189 
2190     static const nxt_str_t  http = nxt_string("http");
2191     static const nxt_str_t  https = nxt_string("https");
2192 
2193     nxt_conf_get_string(value, &scheme);
2194 
2195     if (nxt_strcasestr_eq(&scheme, &http)
2196         || nxt_strcasestr_eq(&scheme, &https))
2197     {
2198         return NXT_OK;
2199     }
2200 
2201     return nxt_conf_vldt_error(vldt, "The \"scheme\" can either be "
2202                                      "\"http\" or \"https\".");
2203 }
2204 
2205 
2206 static nxt_int_t
nxt_conf_vldt_match_patterns_sets(nxt_conf_validation_t * vldt,nxt_conf_value_t * value,void * data)2207 nxt_conf_vldt_match_patterns_sets(nxt_conf_validation_t *vldt,
2208     nxt_conf_value_t *value, void *data)
2209 {
2210     nxt_int_t  ret;
2211 
2212     vldt->ctx = data;
2213 
2214     if (nxt_conf_type(value) == NXT_CONF_ARRAY) {
2215         ret = nxt_conf_vldt_array_iterator(vldt, value,
2216                                            &nxt_conf_vldt_match_patterns_set);
2217 
2218     } else {
2219         /* NXT_CONF_OBJECT */
2220         ret = nxt_conf_vldt_match_patterns_set(vldt, value);
2221     }
2222 
2223     vldt->ctx = NULL;
2224 
2225     return ret;
2226 }
2227 
2228 
2229 static nxt_int_t
nxt_conf_vldt_match_patterns_set(nxt_conf_validation_t * vldt,nxt_conf_value_t * value)2230 nxt_conf_vldt_match_patterns_set(nxt_conf_validation_t *vldt,
2231     nxt_conf_value_t *value)
2232 {
2233     if (nxt_conf_type(value) != NXT_CONF_OBJECT) {
2234         return nxt_conf_vldt_error(vldt, "The \"match\" patterns for "
2235                                    "\"%s\" must be objects.", vldt->ctx);
2236     }
2237 
2238     return nxt_conf_vldt_object_iterator(vldt, value,
2239                                      &nxt_conf_vldt_match_patterns_set_member);
2240 }
2241 
2242 
2243 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)2244 nxt_conf_vldt_match_patterns_set_member(nxt_conf_validation_t *vldt,
2245     nxt_str_t *name, nxt_conf_value_t *value)
2246 {
2247     if (name->length == 0) {
2248         return nxt_conf_vldt_error(vldt, "The \"match\" pattern objects must "
2249                                    "not contain empty member names.");
2250     }
2251 
2252     return nxt_conf_vldt_match_patterns(vldt, value, vldt->ctx);
2253 }
2254 
2255 
2256 #if (NXT_TLS)
2257 
2258 static nxt_int_t
nxt_conf_vldt_certificate(nxt_conf_validation_t * vldt,nxt_conf_value_t * value,void * data)2259 nxt_conf_vldt_certificate(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
2260     void *data)
2261 {
2262     if (nxt_conf_type(value) == NXT_CONF_ARRAY) {
2263         if (nxt_conf_array_elements_count(value) == 0) {
2264             return nxt_conf_vldt_error(vldt, "The \"certificate\" array "
2265                                        "must contain at least one element.");
2266         }
2267 
2268         return nxt_conf_vldt_array_iterator(vldt, value,
2269                                             &nxt_conf_vldt_certificate_element);
2270     }
2271 
2272     /* NXT_CONF_STRING */
2273 
2274     return nxt_conf_vldt_certificate_element(vldt, value);
2275 }
2276 
2277 
2278 static nxt_int_t
nxt_conf_vldt_certificate_element(nxt_conf_validation_t * vldt,nxt_conf_value_t * value)2279 nxt_conf_vldt_certificate_element(nxt_conf_validation_t *vldt,
2280     nxt_conf_value_t *value)
2281 {
2282     nxt_str_t         name;
2283     nxt_conf_value_t  *cert;
2284 
2285     if (nxt_conf_type(value) != NXT_CONF_STRING) {
2286         return nxt_conf_vldt_error(vldt, "The \"certificate\" array must "
2287                                    "contain only string values.");
2288     }
2289 
2290     nxt_conf_get_string(value, &name);
2291 
2292     cert = nxt_cert_info_get(&name);
2293 
2294     if (cert == NULL) {
2295         return nxt_conf_vldt_error(vldt, "Certificate \"%V\" is not found.",
2296                                    &name);
2297     }
2298 
2299     return NXT_OK;
2300 }
2301 
2302 
2303 #if (NXT_HAVE_OPENSSL_CONF_CMD)
2304 
2305 static nxt_int_t
nxt_conf_vldt_object_conf_commands(nxt_conf_validation_t * vldt,nxt_conf_value_t * value,void * data)2306 nxt_conf_vldt_object_conf_commands(nxt_conf_validation_t *vldt,
2307     nxt_conf_value_t *value, void *data)
2308 {
2309     uint32_t          index;
2310     nxt_int_t         ret;
2311     nxt_str_t         name;
2312     nxt_conf_value_t  *member;
2313 
2314     index = 0;
2315 
2316     for ( ;; ) {
2317         member = nxt_conf_next_object_member(value, &name, &index);
2318 
2319         if (member == NULL) {
2320             break;
2321         }
2322 
2323         ret = nxt_conf_vldt_type(vldt, &name, member, NXT_CONF_VLDT_STRING);
2324         if (ret != NXT_OK) {
2325             return ret;
2326         }
2327     }
2328 
2329     return NXT_OK;
2330 }
2331 
2332 #endif
2333 
2334 #endif
2335 
2336 
2337 static nxt_int_t
nxt_conf_vldt_app_name(nxt_conf_validation_t * vldt,nxt_conf_value_t * value,void * data)2338 nxt_conf_vldt_app_name(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
2339     void *data)
2340 {
2341     nxt_str_t         name;
2342     nxt_conf_value_t  *apps, *app;
2343 
2344     static nxt_str_t  apps_str = nxt_string("applications");
2345 
2346     nxt_conf_get_string(value, &name);
2347 
2348     apps = nxt_conf_get_object_member(vldt->conf, &apps_str, NULL);
2349 
2350     if (nxt_slow_path(apps == NULL)) {
2351         goto error;
2352     }
2353 
2354     app = nxt_conf_get_object_member(apps, &name, NULL);
2355 
2356     if (nxt_slow_path(app == NULL)) {
2357         goto error;
2358     }
2359 
2360     return NXT_OK;
2361 
2362 error:
2363 
2364     return nxt_conf_vldt_error(vldt, "Listening socket is assigned for "
2365                                      "a non existing application \"%V\".",
2366                                      &name);
2367 }
2368 
2369 
2370 static nxt_int_t
nxt_conf_vldt_forwarded(nxt_conf_validation_t * vldt,nxt_conf_value_t * value,void * data)2371 nxt_conf_vldt_forwarded(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
2372     void *data)
2373 {
2374     nxt_conf_value_t  *client_ip, *protocol;
2375 
2376     static nxt_str_t  client_ip_str = nxt_string("client_ip");
2377     static nxt_str_t  protocol_str = nxt_string("protocol");
2378 
2379     client_ip = nxt_conf_get_object_member(value, &client_ip_str, NULL);
2380     protocol = nxt_conf_get_object_member(value, &protocol_str, NULL);
2381 
2382     if (client_ip == NULL && protocol == NULL) {
2383         return nxt_conf_vldt_error(vldt, "The \"forwarded\" object must have "
2384                                    "either \"client_ip\" or \"protocol\" "
2385                                    "option set.");
2386     }
2387 
2388     return nxt_conf_vldt_object(vldt, value, nxt_conf_vldt_forwarded_members);
2389 }
2390 
2391 
2392 static nxt_int_t
nxt_conf_vldt_app(nxt_conf_validation_t * vldt,nxt_str_t * name,nxt_conf_value_t * value)2393 nxt_conf_vldt_app(nxt_conf_validation_t *vldt, nxt_str_t *name,
2394     nxt_conf_value_t *value)
2395 {
2396     nxt_int_t              ret;
2397     nxt_str_t              type;
2398     nxt_thread_t           *thread;
2399     nxt_conf_value_t       *type_value;
2400     nxt_app_lang_module_t  *lang;
2401 
2402     static nxt_str_t  type_str = nxt_string("type");
2403 
2404     static struct {
2405         nxt_conf_vldt_handler_t  validator;
2406         nxt_conf_vldt_object_t   *members;
2407 
2408     } types[] = {
2409         { nxt_conf_vldt_object, nxt_conf_vldt_external_members },
2410         { nxt_conf_vldt_python, NULL },
2411         { nxt_conf_vldt_php,    NULL },
2412         { nxt_conf_vldt_object, nxt_conf_vldt_perl_members },
2413         { nxt_conf_vldt_object, nxt_conf_vldt_ruby_members },
2414         { nxt_conf_vldt_object, nxt_conf_vldt_java_members },
2415     };
2416 
2417     ret = nxt_conf_vldt_type(vldt, name, value, NXT_CONF_VLDT_OBJECT);
2418 
2419     if (ret != NXT_OK) {
2420         return ret;
2421     }
2422 
2423     type_value = nxt_conf_get_object_member(value, &type_str, NULL);
2424 
2425     if (type_value == NULL) {
2426         return nxt_conf_vldt_error(vldt,
2427                            "Application must have the \"type\" property set.");
2428     }
2429 
2430     ret = nxt_conf_vldt_type(vldt, &type_str, type_value, NXT_CONF_VLDT_STRING);
2431 
2432     if (ret != NXT_OK) {
2433         return ret;
2434     }
2435 
2436     nxt_conf_get_string(type_value, &type);
2437 
2438     thread = nxt_thread();
2439 
2440     lang = nxt_app_lang_module(thread->runtime, &type);
2441     if (lang == NULL) {
2442         return nxt_conf_vldt_error(vldt,
2443                                    "The module to run \"%V\" is not found "
2444                                    "among the available application modules.",
2445                                    &type);
2446     }
2447 
2448     return types[lang->type].validator(vldt, value, types[lang->type].members);
2449 }
2450 
2451 
2452 static nxt_int_t
nxt_conf_vldt_object(nxt_conf_validation_t * vldt,nxt_conf_value_t * value,void * data)2453 nxt_conf_vldt_object(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
2454     void *data)
2455 {
2456     uint32_t                index;
2457     nxt_int_t               ret;
2458     nxt_str_t               name, var;
2459     nxt_conf_value_t        *member;
2460     nxt_conf_vldt_object_t  *vals;
2461 
2462     vals = data;
2463 
2464     for ( ;; ) {
2465         if (vals->name.length == 0) {
2466 
2467             if (vals->u.members != NULL) {
2468                 vals = vals->u.members;
2469                 continue;
2470             }
2471 
2472             break;
2473         }
2474 
2475         if (vals->flags & NXT_CONF_VLDT_REQUIRED) {
2476             member = nxt_conf_get_object_member(value, &vals->name, NULL);
2477 
2478             if (member == NULL) {
2479                 return nxt_conf_vldt_error(vldt, "Required parameter \"%V\" "
2480                                            "is missing.", &vals->name);
2481             }
2482         }
2483 
2484         vals++;
2485     }
2486 
2487     index = 0;
2488 
2489     for ( ;; ) {
2490         member = nxt_conf_next_object_member(value, &name, &index);
2491 
2492         if (member == NULL) {
2493             return NXT_OK;
2494         }
2495 
2496         vals = data;
2497 
2498         for ( ;; ) {
2499             if (vals->name.length == 0) {
2500 
2501                 if (vals->u.members != NULL) {
2502                     vals = vals->u.members;
2503                     continue;
2504                 }
2505 
2506                 return nxt_conf_vldt_error(vldt, "Unknown parameter \"%V\".",
2507                                            &name);
2508             }
2509 
2510             if (!nxt_strstr_eq(&vals->name, &name)) {
2511                 vals++;
2512                 continue;
2513             }
2514 
2515             if (vals->flags & NXT_CONF_VLDT_TSTR
2516                 && nxt_conf_type(member) == NXT_CONF_STRING)
2517             {
2518                 nxt_conf_get_string(member, &var);
2519 
2520                 if (nxt_is_tstr(&var)) {
2521                     ret = nxt_conf_vldt_var(vldt, &name, &var);
2522                     if (ret != NXT_OK) {
2523                         return ret;
2524                     }
2525 
2526                     break;
2527                 }
2528             }
2529 
2530             ret = nxt_conf_vldt_type(vldt, &name, member, vals->type);
2531             if (ret != NXT_OK) {
2532                 return ret;
2533             }
2534 
2535             if (vals->validator != NULL) {
2536                 ret = vals->validator(vldt, member, vals->u.members);
2537 
2538                 if (ret != NXT_OK) {
2539                     return ret;
2540                 }
2541             }
2542 
2543             break;
2544         }
2545     }
2546 }
2547 
2548 
2549 typedef struct {
2550     int64_t  spare;
2551     int64_t  max;
2552     int64_t  idle_timeout;
2553 } nxt_conf_vldt_processes_conf_t;
2554 
2555 
2556 static nxt_conf_map_t  nxt_conf_vldt_processes_conf_map[] = {
2557     {
2558         nxt_string("spare"),
2559         NXT_CONF_MAP_INT64,
2560         offsetof(nxt_conf_vldt_processes_conf_t, spare),
2561     },
2562 
2563     {
2564         nxt_string("max"),
2565         NXT_CONF_MAP_INT64,
2566         offsetof(nxt_conf_vldt_processes_conf_t, max),
2567     },
2568 
2569     {
2570         nxt_string("idle_timeout"),
2571         NXT_CONF_MAP_INT64,
2572         offsetof(nxt_conf_vldt_processes_conf_t, idle_timeout),
2573     },
2574 };
2575 
2576 
2577 static nxt_int_t
nxt_conf_vldt_processes(nxt_conf_validation_t * vldt,nxt_conf_value_t * value,void * data)2578 nxt_conf_vldt_processes(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
2579     void *data)
2580 {
2581     int64_t                         int_value;
2582     nxt_int_t                       ret;
2583     nxt_conf_vldt_processes_conf_t  proc;
2584 
2585     if (nxt_conf_type(value) == NXT_CONF_NUMBER) {
2586         int_value = nxt_conf_get_number(value);
2587 
2588         if (int_value < 1) {
2589             return nxt_conf_vldt_error(vldt, "The \"processes\" number must be "
2590                                        "equal to or greater than 1.");
2591         }
2592 
2593         if (int_value > NXT_INT32_T_MAX) {
2594             return nxt_conf_vldt_error(vldt, "The \"processes\" number must "
2595                                        "not exceed %d.", NXT_INT32_T_MAX);
2596         }
2597 
2598         return NXT_OK;
2599     }
2600 
2601     ret = nxt_conf_vldt_object(vldt, value, data);
2602     if (ret != NXT_OK) {
2603         return ret;
2604     }
2605 
2606     proc.spare = 0;
2607     proc.max = 1;
2608     proc.idle_timeout = 15;
2609 
2610     ret = nxt_conf_map_object(vldt->pool, value,
2611                               nxt_conf_vldt_processes_conf_map,
2612                               nxt_nitems(nxt_conf_vldt_processes_conf_map),
2613                               &proc);
2614     if (ret != NXT_OK) {
2615         return ret;
2616     }
2617 
2618     if (proc.spare < 0) {
2619         return nxt_conf_vldt_error(vldt, "The \"spare\" number must not be "
2620                                    "negative.");
2621     }
2622 
2623     if (proc.spare > NXT_INT32_T_MAX) {
2624         return nxt_conf_vldt_error(vldt, "The \"spare\" number must not "
2625                                    "exceed %d.", NXT_INT32_T_MAX);
2626     }
2627 
2628     if (proc.max < 1) {
2629         return nxt_conf_vldt_error(vldt, "The \"max\" number must be equal "
2630                                    "to or greater than 1.");
2631     }
2632 
2633     if (proc.max > NXT_INT32_T_MAX) {
2634         return nxt_conf_vldt_error(vldt, "The \"max\" number must not "
2635                                    "exceed %d.", NXT_INT32_T_MAX);
2636     }
2637 
2638     if (proc.max < proc.spare) {
2639         return nxt_conf_vldt_error(vldt, "The \"spare\" number must be "
2640                                    "less than or equal to \"max\".");
2641     }
2642 
2643     if (proc.idle_timeout < 0) {
2644         return nxt_conf_vldt_error(vldt, "The \"idle_timeout\" number must not "
2645                                    "be negative.");
2646     }
2647 
2648     if (proc.idle_timeout > NXT_INT32_T_MAX / 1000) {
2649         return nxt_conf_vldt_error(vldt, "The \"idle_timeout\" number must not "
2650                                    "exceed %d.", NXT_INT32_T_MAX / 1000);
2651     }
2652 
2653     return NXT_OK;
2654 }
2655 
2656 
2657 static nxt_int_t
nxt_conf_vldt_object_iterator(nxt_conf_validation_t * vldt,nxt_conf_value_t * value,void * data)2658 nxt_conf_vldt_object_iterator(nxt_conf_validation_t *vldt,
2659     nxt_conf_value_t *value, void *data)
2660 {
2661     uint32_t                index;
2662     nxt_int_t               ret;
2663     nxt_str_t               name;
2664     nxt_conf_value_t        *member;
2665     nxt_conf_vldt_member_t  validator;
2666 
2667     validator = (nxt_conf_vldt_member_t) data;
2668     index = 0;
2669 
2670     for ( ;; ) {
2671         member = nxt_conf_next_object_member(value, &name, &index);
2672 
2673         if (member == NULL) {
2674             return NXT_OK;
2675         }
2676 
2677         ret = validator(vldt, &name, member);
2678 
2679         if (ret != NXT_OK) {
2680             return ret;
2681         }
2682     }
2683 }
2684 
2685 
2686 static nxt_int_t
nxt_conf_vldt_array_iterator(nxt_conf_validation_t * vldt,nxt_conf_value_t * value,void * data)2687 nxt_conf_vldt_array_iterator(nxt_conf_validation_t *vldt,
2688     nxt_conf_value_t *value, void *data)
2689 {
2690     uint32_t                 index;
2691     nxt_int_t                ret;
2692     nxt_conf_value_t         *element;
2693     nxt_conf_vldt_element_t  validator;
2694 
2695     validator = (nxt_conf_vldt_element_t) data;
2696 
2697     for (index = 0; /* void */ ; index++) {
2698         element = nxt_conf_get_array_element(value, index);
2699 
2700         if (element == NULL) {
2701             return NXT_OK;
2702         }
2703 
2704         ret = validator(vldt, element);
2705 
2706         if (ret != NXT_OK) {
2707             return ret;
2708         }
2709     }
2710 }
2711 
2712 
2713 static nxt_int_t
nxt_conf_vldt_environment(nxt_conf_validation_t * vldt,nxt_str_t * name,nxt_conf_value_t * value)2714 nxt_conf_vldt_environment(nxt_conf_validation_t *vldt, nxt_str_t *name,
2715     nxt_conf_value_t *value)
2716 {
2717     nxt_str_t  str;
2718 
2719     if (name->length == 0) {
2720         return nxt_conf_vldt_error(vldt,
2721                                    "The environment name must not be empty.");
2722     }
2723 
2724     if (memchr(name->start, '\0', name->length) != NULL) {
2725         return nxt_conf_vldt_error(vldt, "The environment name must not "
2726                                    "contain null character.");
2727     }
2728 
2729     if (memchr(name->start, '=', name->length) != NULL) {
2730         return nxt_conf_vldt_error(vldt, "The environment name must not "
2731                                    "contain '=' character.");
2732     }
2733 
2734     if (nxt_conf_type(value) != NXT_CONF_STRING) {
2735         return nxt_conf_vldt_error(vldt, "The \"%V\" environment value must be "
2736                                    "a string.", name);
2737     }
2738 
2739     nxt_conf_get_string(value, &str);
2740 
2741     if (memchr(str.start, '\0', str.length) != NULL) {
2742         return nxt_conf_vldt_error(vldt, "The \"%V\" environment value must "
2743                                    "not contain null character.", name);
2744     }
2745 
2746     return NXT_OK;
2747 }
2748 
2749 
2750 static nxt_int_t
nxt_conf_vldt_targets_exclusive(nxt_conf_validation_t * vldt,nxt_conf_value_t * value,void * data)2751 nxt_conf_vldt_targets_exclusive(nxt_conf_validation_t *vldt,
2752     nxt_conf_value_t *value, void *data)
2753 {
2754     return nxt_conf_vldt_error(vldt, "The \"%s\" option is mutually exclusive "
2755                                "with the \"targets\" object.", data);
2756 }
2757 
2758 
2759 static nxt_int_t
nxt_conf_vldt_targets(nxt_conf_validation_t * vldt,nxt_conf_value_t * value,void * data)2760 nxt_conf_vldt_targets(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
2761     void *data)
2762 {
2763     nxt_int_t   ret;
2764     nxt_uint_t  n;
2765 
2766     n = nxt_conf_object_members_count(value);
2767 
2768     if (n > 254) {
2769         return nxt_conf_vldt_error(vldt, "The \"targets\" object must not "
2770                                    "contain more than 254 members.");
2771     }
2772 
2773     vldt->ctx = data;
2774 
2775     ret = nxt_conf_vldt_object_iterator(vldt, value, &nxt_conf_vldt_target);
2776 
2777     vldt->ctx = NULL;
2778 
2779     return ret;
2780 }
2781 
2782 
2783 static nxt_int_t
nxt_conf_vldt_target(nxt_conf_validation_t * vldt,nxt_str_t * name,nxt_conf_value_t * value)2784 nxt_conf_vldt_target(nxt_conf_validation_t *vldt, nxt_str_t *name,
2785     nxt_conf_value_t *value)
2786 {
2787     if (name->length == 0) {
2788         return nxt_conf_vldt_error(vldt,
2789                                    "The target name must not be empty.");
2790     }
2791 
2792     if (nxt_conf_type(value) != NXT_CONF_OBJECT) {
2793         return nxt_conf_vldt_error(vldt, "The \"%V\" target must be "
2794                                    "an object.", name);
2795     }
2796 
2797     return nxt_conf_vldt_object(vldt, value, vldt->ctx);
2798 }
2799 
2800 
2801 static nxt_int_t
nxt_conf_vldt_clone_namespaces(nxt_conf_validation_t * vldt,nxt_conf_value_t * value,void * data)2802 nxt_conf_vldt_clone_namespaces(nxt_conf_validation_t *vldt,
2803     nxt_conf_value_t *value, void *data)
2804 {
2805     return nxt_conf_vldt_object(vldt, value, data);
2806 }
2807 
2808 
2809 static nxt_int_t
nxt_conf_vldt_isolation(nxt_conf_validation_t * vldt,nxt_conf_value_t * value,void * data)2810 nxt_conf_vldt_isolation(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
2811     void *data)
2812 {
2813     return nxt_conf_vldt_object(vldt, value, data);
2814 }
2815 
2816 
2817 #if (NXT_HAVE_CLONE_NEWUSER)
2818 
2819 typedef struct {
2820     nxt_int_t container;
2821     nxt_int_t host;
2822     nxt_int_t size;
2823 } nxt_conf_vldt_clone_procmap_conf_t;
2824 
2825 
2826 static nxt_conf_map_t nxt_conf_vldt_clone_procmap_conf_map[] = {
2827     {
2828         nxt_string("container"),
2829         NXT_CONF_MAP_INT32,
2830         offsetof(nxt_conf_vldt_clone_procmap_conf_t, container),
2831     },
2832 
2833     {
2834         nxt_string("host"),
2835         NXT_CONF_MAP_INT32,
2836         offsetof(nxt_conf_vldt_clone_procmap_conf_t, host),
2837     },
2838 
2839     {
2840         nxt_string("size"),
2841         NXT_CONF_MAP_INT32,
2842         offsetof(nxt_conf_vldt_clone_procmap_conf_t, size),
2843     },
2844 
2845 };
2846 
2847 
2848 static nxt_int_t
nxt_conf_vldt_clone_procmap(nxt_conf_validation_t * vldt,const char * mapfile,nxt_conf_value_t * value)2849 nxt_conf_vldt_clone_procmap(nxt_conf_validation_t *vldt, const char *mapfile,
2850         nxt_conf_value_t *value)
2851 {
2852     nxt_int_t                           ret;
2853     nxt_conf_vldt_clone_procmap_conf_t  procmap;
2854 
2855     procmap.container = -1;
2856     procmap.host = -1;
2857     procmap.size = -1;
2858 
2859     ret = nxt_conf_map_object(vldt->pool, value,
2860                               nxt_conf_vldt_clone_procmap_conf_map,
2861                               nxt_nitems(nxt_conf_vldt_clone_procmap_conf_map),
2862                               &procmap);
2863     if (ret != NXT_OK) {
2864         return ret;
2865     }
2866 
2867     if (procmap.container == -1) {
2868         return nxt_conf_vldt_error(vldt, "The %s requires the "
2869                 "\"container\" field set.", mapfile);
2870     }
2871 
2872     if (procmap.host == -1) {
2873         return nxt_conf_vldt_error(vldt, "The %s requires the "
2874                 "\"host\" field set.", mapfile);
2875     }
2876 
2877     if (procmap.size == -1) {
2878         return nxt_conf_vldt_error(vldt, "The %s requires the "
2879                 "\"size\" field set.", mapfile);
2880     }
2881 
2882     return NXT_OK;
2883 }
2884 
2885 
2886 static nxt_int_t
nxt_conf_vldt_clone_uidmap(nxt_conf_validation_t * vldt,nxt_conf_value_t * value)2887 nxt_conf_vldt_clone_uidmap(nxt_conf_validation_t *vldt, nxt_conf_value_t *value)
2888 {
2889     nxt_int_t  ret;
2890 
2891     if (nxt_conf_type(value) != NXT_CONF_OBJECT) {
2892         return nxt_conf_vldt_error(vldt, "The \"uidmap\" array "
2893                                    "must contain only object values.");
2894     }
2895 
2896     ret = nxt_conf_vldt_object(vldt, value,
2897                                (void *) nxt_conf_vldt_app_procmap_members);
2898     if (nxt_slow_path(ret != NXT_OK)) {
2899         return ret;
2900     }
2901 
2902     return nxt_conf_vldt_clone_procmap(vldt, "uid_map", value);
2903 }
2904 
2905 
2906 static nxt_int_t
nxt_conf_vldt_clone_gidmap(nxt_conf_validation_t * vldt,nxt_conf_value_t * value)2907 nxt_conf_vldt_clone_gidmap(nxt_conf_validation_t *vldt, nxt_conf_value_t *value)
2908 {
2909     nxt_int_t ret;
2910 
2911     if (nxt_conf_type(value) != NXT_CONF_OBJECT) {
2912         return nxt_conf_vldt_error(vldt, "The \"gidmap\" array "
2913                                    "must contain only object values.");
2914     }
2915 
2916     ret = nxt_conf_vldt_object(vldt, value,
2917                                (void *) nxt_conf_vldt_app_procmap_members);
2918     if (nxt_slow_path(ret != NXT_OK)) {
2919         return ret;
2920     }
2921 
2922     return nxt_conf_vldt_clone_procmap(vldt, "gid_map", value);
2923 }
2924 
2925 #endif
2926 
2927 
2928 static nxt_int_t
nxt_conf_vldt_argument(nxt_conf_validation_t * vldt,nxt_conf_value_t * value)2929 nxt_conf_vldt_argument(nxt_conf_validation_t *vldt, nxt_conf_value_t *value)
2930 {
2931     nxt_str_t  str;
2932 
2933     if (nxt_conf_type(value) != NXT_CONF_STRING) {
2934         return nxt_conf_vldt_error(vldt, "The \"arguments\" array "
2935                                    "must contain only string values.");
2936     }
2937 
2938     nxt_conf_get_string(value, &str);
2939 
2940     if (memchr(str.start, '\0', str.length) != NULL) {
2941         return nxt_conf_vldt_error(vldt, "The \"arguments\" array must not "
2942                                    "contain strings with null character.");
2943     }
2944 
2945     return NXT_OK;
2946 }
2947 
2948 
2949 static nxt_int_t
nxt_conf_vldt_php(nxt_conf_validation_t * vldt,nxt_conf_value_t * value,void * data)2950 nxt_conf_vldt_php(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
2951     void *data)
2952 {
2953     nxt_conf_value_t  *targets;
2954 
2955     static nxt_str_t  targets_str = nxt_string("targets");
2956 
2957     targets = nxt_conf_get_object_member(value, &targets_str, NULL);
2958 
2959     if (targets != NULL) {
2960         return nxt_conf_vldt_object(vldt, value, nxt_conf_vldt_php_members);
2961     }
2962 
2963     return nxt_conf_vldt_object(vldt, value,
2964                                 nxt_conf_vldt_php_notargets_members);
2965 }
2966 
2967 
2968 static nxt_int_t
nxt_conf_vldt_php_option(nxt_conf_validation_t * vldt,nxt_str_t * name,nxt_conf_value_t * value)2969 nxt_conf_vldt_php_option(nxt_conf_validation_t *vldt, nxt_str_t *name,
2970     nxt_conf_value_t *value)
2971 {
2972     if (name->length == 0) {
2973         return nxt_conf_vldt_error(vldt,
2974                                    "The PHP option name must not be empty.");
2975     }
2976 
2977     if (nxt_conf_type(value) != NXT_CONF_STRING) {
2978         return nxt_conf_vldt_error(vldt, "The \"%V\" PHP option must be "
2979                                    "a string.", name);
2980     }
2981 
2982     return NXT_OK;
2983 }
2984 
2985 
2986 static nxt_int_t
nxt_conf_vldt_java_classpath(nxt_conf_validation_t * vldt,nxt_conf_value_t * value)2987 nxt_conf_vldt_java_classpath(nxt_conf_validation_t *vldt,
2988     nxt_conf_value_t *value)
2989 {
2990     nxt_str_t  str;
2991 
2992     if (nxt_conf_type(value) != NXT_CONF_STRING) {
2993         return nxt_conf_vldt_error(vldt, "The \"classpath\" array "
2994                                    "must contain only string values.");
2995     }
2996 
2997     nxt_conf_get_string(value, &str);
2998 
2999     if (memchr(str.start, '\0', str.length) != NULL) {
3000         return nxt_conf_vldt_error(vldt, "The \"classpath\" array must not "
3001                                    "contain strings with null character.");
3002     }
3003 
3004     return NXT_OK;
3005 }
3006 
3007 
3008 static nxt_int_t
nxt_conf_vldt_java_option(nxt_conf_validation_t * vldt,nxt_conf_value_t * value)3009 nxt_conf_vldt_java_option(nxt_conf_validation_t *vldt, nxt_conf_value_t *value)
3010 {
3011     nxt_str_t  str;
3012 
3013     if (nxt_conf_type(value) != NXT_CONF_STRING) {
3014         return nxt_conf_vldt_error(vldt, "The \"options\" array "
3015                                    "must contain only string values.");
3016     }
3017 
3018     nxt_conf_get_string(value, &str);
3019 
3020     if (memchr(str.start, '\0', str.length) != NULL) {
3021         return nxt_conf_vldt_error(vldt, "The \"options\" array must not "
3022                                    "contain strings with null character.");
3023     }
3024 
3025     return NXT_OK;
3026 }
3027 
3028 
3029 static nxt_int_t
nxt_conf_vldt_upstream(nxt_conf_validation_t * vldt,nxt_str_t * name,nxt_conf_value_t * value)3030 nxt_conf_vldt_upstream(nxt_conf_validation_t *vldt, nxt_str_t *name,
3031     nxt_conf_value_t *value)
3032 {
3033     nxt_int_t         ret;
3034     nxt_conf_value_t  *conf;
3035 
3036     static nxt_str_t  servers = nxt_string("servers");
3037 
3038     ret = nxt_conf_vldt_type(vldt, name, value, NXT_CONF_VLDT_OBJECT);
3039 
3040     if (ret != NXT_OK) {
3041         return ret;
3042     }
3043 
3044     ret = nxt_conf_vldt_object(vldt, value, nxt_conf_vldt_upstream_members);
3045 
3046     if (ret != NXT_OK) {
3047         return ret;
3048     }
3049 
3050     conf = nxt_conf_get_object_member(value, &servers, NULL);
3051     if (conf == NULL) {
3052         return nxt_conf_vldt_error(vldt, "The \"%V\" upstream must contain "
3053                                    "\"servers\" object value.", name);
3054     }
3055 
3056     return NXT_OK;
3057 }
3058 
3059 
3060 static nxt_int_t
nxt_conf_vldt_server(nxt_conf_validation_t * vldt,nxt_str_t * name,nxt_conf_value_t * value)3061 nxt_conf_vldt_server(nxt_conf_validation_t *vldt, nxt_str_t *name,
3062     nxt_conf_value_t *value)
3063 {
3064     nxt_int_t       ret;
3065     nxt_sockaddr_t  *sa;
3066 
3067     ret = nxt_conf_vldt_type(vldt, name, value, NXT_CONF_VLDT_OBJECT);
3068 
3069     if (ret != NXT_OK) {
3070         return ret;
3071     }
3072 
3073     sa = nxt_sockaddr_parse(vldt->pool, name);
3074 
3075     if (sa == NULL) {
3076         return nxt_conf_vldt_error(vldt, "The \"%V\" is not valid "
3077                                    "server address.", name);
3078     }
3079 
3080     return nxt_conf_vldt_object(vldt, value,
3081                                 nxt_conf_vldt_upstream_server_members);
3082 }
3083 
3084 
3085 static nxt_int_t
nxt_conf_vldt_server_weight(nxt_conf_validation_t * vldt,nxt_conf_value_t * value,void * data)3086 nxt_conf_vldt_server_weight(nxt_conf_validation_t *vldt,
3087     nxt_conf_value_t *value, void *data)
3088 {
3089     double  num_value;
3090 
3091     num_value = nxt_conf_get_number(value);
3092 
3093     if (num_value < 0) {
3094         return nxt_conf_vldt_error(vldt, "The \"weight\" number must be "
3095                                    "positive.");
3096     }
3097 
3098     if (num_value > 1000000) {
3099         return nxt_conf_vldt_error(vldt, "The \"weight\" number must "
3100                                    "not exceed 1,000,000");
3101     }
3102 
3103     return NXT_OK;
3104 }
3105 
3106 
3107 typedef struct {
3108     nxt_str_t  path;
3109     nxt_str_t  format;
3110 } nxt_conf_vldt_access_log_conf_t;
3111 
3112 
3113 static nxt_conf_map_t  nxt_conf_vldt_access_log_map[] = {
3114     {
3115         nxt_string("path"),
3116         NXT_CONF_MAP_STR,
3117         offsetof(nxt_conf_vldt_access_log_conf_t, path),
3118     },
3119 
3120     {
3121         nxt_string("format"),
3122         NXT_CONF_MAP_STR,
3123         offsetof(nxt_conf_vldt_access_log_conf_t, format),
3124     },
3125 };
3126 
3127 
3128 static nxt_int_t
nxt_conf_vldt_access_log(nxt_conf_validation_t * vldt,nxt_conf_value_t * value,void * data)3129 nxt_conf_vldt_access_log(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
3130     void *data)
3131 {
3132     nxt_int_t                        ret;
3133     nxt_conf_vldt_access_log_conf_t  conf;
3134 
3135     static nxt_str_t  format_str = nxt_string("format");
3136 
3137     if (nxt_conf_type(value) == NXT_CONF_STRING) {
3138         return NXT_OK;
3139     }
3140 
3141     ret = nxt_conf_vldt_object(vldt, value, nxt_conf_vldt_access_log_members);
3142     if (ret != NXT_OK) {
3143         return ret;
3144     }
3145 
3146     nxt_memzero(&conf, sizeof(nxt_conf_vldt_access_log_conf_t));
3147 
3148     ret = nxt_conf_map_object(vldt->pool, value,
3149                               nxt_conf_vldt_access_log_map,
3150                               nxt_nitems(nxt_conf_vldt_access_log_map),
3151                               &conf);
3152     if (ret != NXT_OK) {
3153         return ret;
3154     }
3155 
3156     if (conf.path.length == 0) {
3157         return nxt_conf_vldt_error(vldt,
3158                                    "The \"path\" string must not be empty.");
3159     }
3160 
3161     if (nxt_is_tstr(&conf.format)) {
3162         return nxt_conf_vldt_var(vldt, &format_str, &conf.format);
3163     }
3164 
3165     return NXT_OK;
3166 }
3167