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