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