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