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