xref: /unit/src/nxt_conf_validation.c (revision 1489:4a3ec07f4b19)
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 
15 
16 typedef enum {
17     NXT_CONF_VLDT_NULL    = 1 << NXT_CONF_NULL,
18     NXT_CONF_VLDT_BOOLEAN = 1 << NXT_CONF_BOOLEAN,
19     NXT_CONF_VLDT_INTEGER = 1 << NXT_CONF_INTEGER,
20     NXT_CONF_VLDT_NUMBER  = (1 << NXT_CONF_NUMBER) | NXT_CONF_VLDT_INTEGER,
21     NXT_CONF_VLDT_STRING  = 1 << NXT_CONF_STRING,
22     NXT_CONF_VLDT_ARRAY   = 1 << NXT_CONF_ARRAY,
23     NXT_CONF_VLDT_OBJECT  = 1 << NXT_CONF_OBJECT,
24 } nxt_conf_vldt_type_t;
25 
26 #define NXT_CONF_VLDT_ANY_TYPE  (NXT_CONF_VLDT_NULL                           \
27                                  |NXT_CONF_VLDT_BOOLEAN                       \
28                                  |NXT_CONF_VLDT_NUMBER                        \
29                                  |NXT_CONF_VLDT_STRING                        \
30                                  |NXT_CONF_VLDT_ARRAY                         \
31                                  |NXT_CONF_VLDT_OBJECT)
32 
33 
34 typedef nxt_int_t (*nxt_conf_vldt_handler_t)(nxt_conf_validation_t *vldt,
35                                              nxt_conf_value_t *value,
36                                              void *data);
37 
38 
39 typedef struct {
40     nxt_str_t                name;
41     nxt_conf_vldt_type_t     type;
42     nxt_conf_vldt_handler_t  validator;
43     void                     *data;
44 } nxt_conf_vldt_object_t;
45 
46 
47 #define NXT_CONF_VLDT_NEXT(f)  { nxt_null_string, 0, NULL, (f) }
48 #define NXT_CONF_VLDT_END      { nxt_null_string, 0, NULL, NULL }
49 
50 
51 typedef nxt_int_t (*nxt_conf_vldt_member_t)(nxt_conf_validation_t *vldt,
52                                             nxt_str_t *name,
53                                             nxt_conf_value_t *value);
54 typedef nxt_int_t (*nxt_conf_vldt_element_t)(nxt_conf_validation_t *vldt,
55                                              nxt_conf_value_t *value);
56 
57 static nxt_int_t nxt_conf_vldt_type(nxt_conf_validation_t *vldt,
58     nxt_str_t *name, nxt_conf_value_t *value, nxt_conf_vldt_type_t type);
59 static nxt_int_t nxt_conf_vldt_error(nxt_conf_validation_t *vldt,
60     const char *fmt, ...);
61 
62 static nxt_int_t nxt_conf_vldt_mtypes(nxt_conf_validation_t *vldt,
63     nxt_conf_value_t *value, void *data);
64 static nxt_int_t nxt_conf_vldt_mtypes_type(nxt_conf_validation_t *vldt,
65     nxt_str_t *name, nxt_conf_value_t *value);
66 static nxt_int_t nxt_conf_vldt_mtypes_extension(nxt_conf_validation_t *vldt,
67     nxt_conf_value_t *value);
68 static nxt_int_t nxt_conf_vldt_listener(nxt_conf_validation_t *vldt,
69     nxt_str_t *name, nxt_conf_value_t *value);
70 #if (NXT_TLS)
71 static nxt_int_t nxt_conf_vldt_certificate(nxt_conf_validation_t *vldt,
72     nxt_conf_value_t *value, void *data);
73 #endif
74 static nxt_int_t nxt_conf_vldt_action(nxt_conf_validation_t *vldt,
75     nxt_conf_value_t *value, void *data);
76 static nxt_int_t nxt_conf_vldt_pass(nxt_conf_validation_t *vldt,
77     nxt_conf_value_t *value, void *data);
78 static nxt_int_t nxt_conf_vldt_return(nxt_conf_validation_t *vldt,
79     nxt_conf_value_t *value, void *data);
80 static nxt_int_t nxt_conf_vldt_proxy(nxt_conf_validation_t *vldt,
81     nxt_conf_value_t *value, void *data);
82 static nxt_int_t nxt_conf_vldt_routes(nxt_conf_validation_t *vldt,
83     nxt_conf_value_t *value, void *data);
84 static nxt_int_t nxt_conf_vldt_routes_member(nxt_conf_validation_t *vldt,
85     nxt_str_t *name, nxt_conf_value_t *value);
86 static nxt_int_t nxt_conf_vldt_route(nxt_conf_validation_t *vldt,
87     nxt_conf_value_t *value);
88 static nxt_int_t nxt_conf_vldt_match_encoded_patterns_sets(
89     nxt_conf_validation_t *vldt, nxt_conf_value_t *value, void *data);
90 static nxt_int_t nxt_conf_vldt_match_encoded_patterns_set(
91     nxt_conf_validation_t *vldt, nxt_conf_value_t *value);
92 static nxt_int_t nxt_conf_vldt_match_encoded_patterns_set_member(
93     nxt_conf_validation_t *vldt, nxt_str_t *name, nxt_conf_value_t *value);
94 static nxt_int_t nxt_conf_vldt_match_encoded_patterns(
95     nxt_conf_validation_t *vldt, nxt_conf_value_t *value, void *data);
96 static nxt_int_t nxt_conf_vldt_match_encoded_pattern(
97     nxt_conf_validation_t *vldt, nxt_conf_value_t *value);
98 static nxt_int_t nxt_conf_vldt_match_patterns(nxt_conf_validation_t *vldt,
99     nxt_conf_value_t *value, void *data);
100 static nxt_int_t nxt_conf_vldt_match_pattern(nxt_conf_validation_t *vldt,
101     nxt_conf_value_t *value);
102 static nxt_int_t nxt_conf_vldt_match_patterns_sets(nxt_conf_validation_t *vldt,
103     nxt_conf_value_t *value, void *data);
104 static nxt_int_t nxt_conf_vldt_match_patterns_set(nxt_conf_validation_t *vldt,
105     nxt_conf_value_t *value);
106 static nxt_int_t nxt_conf_vldt_match_patterns_set_member(
107     nxt_conf_validation_t *vldt, nxt_str_t *name, nxt_conf_value_t *value);
108 static nxt_int_t nxt_conf_vldt_match_scheme_pattern(nxt_conf_validation_t *vldt,
109     nxt_conf_value_t *value, void *data);
110 static nxt_int_t nxt_conf_vldt_match_addrs(nxt_conf_validation_t *vldt,
111     nxt_conf_value_t *value, void *data);
112 static nxt_int_t nxt_conf_vldt_match_addr(nxt_conf_validation_t *vldt,
113     nxt_conf_value_t *value);
114 static nxt_int_t nxt_conf_vldt_app_name(nxt_conf_validation_t *vldt,
115     nxt_conf_value_t *value, void *data);
116 static nxt_int_t nxt_conf_vldt_app(nxt_conf_validation_t *vldt,
117     nxt_str_t *name, nxt_conf_value_t *value);
118 static nxt_int_t nxt_conf_vldt_object(nxt_conf_validation_t *vldt,
119     nxt_conf_value_t *value, void *data);
120 static nxt_int_t nxt_conf_vldt_processes(nxt_conf_validation_t *vldt,
121     nxt_conf_value_t *value, void *data);
122 static nxt_int_t nxt_conf_vldt_object_iterator(nxt_conf_validation_t *vldt,
123     nxt_conf_value_t *value, void *data);
124 static nxt_int_t nxt_conf_vldt_array_iterator(nxt_conf_validation_t *vldt,
125     nxt_conf_value_t *value, void *data);
126 static nxt_int_t nxt_conf_vldt_environment(nxt_conf_validation_t *vldt,
127     nxt_str_t *name, nxt_conf_value_t *value);
128 static nxt_int_t nxt_conf_vldt_argument(nxt_conf_validation_t *vldt,
129     nxt_conf_value_t *value);
130 static nxt_int_t nxt_conf_vldt_php(nxt_conf_validation_t *vldt,
131     nxt_conf_value_t *value, void *data);
132 static nxt_int_t nxt_conf_vldt_php_targets_exclusive(
133     nxt_conf_validation_t *vldt, nxt_conf_value_t *value, void *data);
134 static nxt_int_t nxt_conf_vldt_php_targets(nxt_conf_validation_t *vldt,
135     nxt_conf_value_t *value, void *data);
136 static nxt_int_t nxt_conf_vldt_php_target(nxt_conf_validation_t *vldt,
137     nxt_str_t *name, nxt_conf_value_t *value);
138 static nxt_int_t nxt_conf_vldt_php_option(nxt_conf_validation_t *vldt,
139     nxt_str_t *name, nxt_conf_value_t *value);
140 static nxt_int_t nxt_conf_vldt_java_classpath(nxt_conf_validation_t *vldt,
141     nxt_conf_value_t *value);
142 static nxt_int_t nxt_conf_vldt_java_option(nxt_conf_validation_t *vldt,
143     nxt_conf_value_t *value);
144 static nxt_int_t nxt_conf_vldt_upstream(nxt_conf_validation_t *vldt,
145      nxt_str_t *name, nxt_conf_value_t *value);
146 static nxt_int_t nxt_conf_vldt_server(nxt_conf_validation_t *vldt,
147     nxt_str_t *name, nxt_conf_value_t *value);
148 static nxt_int_t nxt_conf_vldt_server_weight(nxt_conf_validation_t *vldt,
149     nxt_conf_value_t *value, void *data);
150 
151 static nxt_int_t nxt_conf_vldt_isolation(nxt_conf_validation_t *vldt,
152     nxt_conf_value_t *value, void *data);
153 static nxt_int_t nxt_conf_vldt_clone_namespaces(nxt_conf_validation_t *vldt,
154     nxt_conf_value_t *value, void *data);
155 
156 #if (NXT_HAVE_CLONE_NEWUSER)
157 static nxt_int_t nxt_conf_vldt_clone_procmap(nxt_conf_validation_t *vldt,
158     const char* mapfile, nxt_conf_value_t *value);
159 static nxt_int_t nxt_conf_vldt_clone_uidmap(nxt_conf_validation_t *vldt,
160     nxt_conf_value_t *value);
161 static nxt_int_t nxt_conf_vldt_clone_gidmap(nxt_conf_validation_t *vldt,
162     nxt_conf_value_t *value);
163 #endif
164 
165 static nxt_conf_vldt_object_t  nxt_conf_vldt_websocket_members[] = {
166     { nxt_string("read_timeout"),
167       NXT_CONF_VLDT_INTEGER,
168       NULL,
169       NULL },
170 
171     { nxt_string("keepalive_interval"),
172       NXT_CONF_VLDT_INTEGER,
173       NULL,
174       NULL },
175 
176     { nxt_string("max_frame_size"),
177       NXT_CONF_VLDT_INTEGER,
178       NULL,
179       NULL },
180 
181     NXT_CONF_VLDT_END
182 };
183 
184 
185 static nxt_conf_vldt_object_t  nxt_conf_vldt_static_members[] = {
186     { nxt_string("mime_types"),
187       NXT_CONF_VLDT_OBJECT,
188       &nxt_conf_vldt_mtypes,
189       NULL },
190 
191     NXT_CONF_VLDT_END
192 };
193 
194 
195 static nxt_conf_vldt_object_t  nxt_conf_vldt_http_members[] = {
196     { nxt_string("header_read_timeout"),
197       NXT_CONF_VLDT_INTEGER,
198       NULL,
199       NULL },
200 
201     { nxt_string("body_read_timeout"),
202       NXT_CONF_VLDT_INTEGER,
203       NULL,
204       NULL },
205 
206     { nxt_string("send_timeout"),
207       NXT_CONF_VLDT_INTEGER,
208       NULL,
209       NULL },
210 
211     { nxt_string("idle_timeout"),
212       NXT_CONF_VLDT_INTEGER,
213       NULL,
214       NULL },
215 
216     { nxt_string("body_buffer_size"),
217       NXT_CONF_VLDT_INTEGER,
218       NULL,
219       NULL },
220 
221     { nxt_string("max_body_size"),
222       NXT_CONF_VLDT_INTEGER,
223       NULL,
224       NULL },
225 
226     { nxt_string("body_temp_path"),
227       NXT_CONF_VLDT_STRING,
228       NULL,
229       NULL },
230 
231     { nxt_string("websocket"),
232       NXT_CONF_VLDT_OBJECT,
233       &nxt_conf_vldt_object,
234       (void *) &nxt_conf_vldt_websocket_members },
235 
236     { nxt_string("static"),
237       NXT_CONF_VLDT_OBJECT,
238       &nxt_conf_vldt_object,
239       (void *) &nxt_conf_vldt_static_members },
240 
241     NXT_CONF_VLDT_END
242 };
243 
244 
245 static nxt_conf_vldt_object_t  nxt_conf_vldt_setting_members[] = {
246     { nxt_string("http"),
247       NXT_CONF_VLDT_OBJECT,
248       &nxt_conf_vldt_object,
249       (void *) &nxt_conf_vldt_http_members },
250 
251     NXT_CONF_VLDT_END
252 };
253 
254 
255 static nxt_conf_vldt_object_t  nxt_conf_vldt_root_members[] = {
256     { nxt_string("settings"),
257       NXT_CONF_VLDT_OBJECT,
258       &nxt_conf_vldt_object,
259       (void *) &nxt_conf_vldt_setting_members },
260 
261     { nxt_string("listeners"),
262       NXT_CONF_VLDT_OBJECT,
263       &nxt_conf_vldt_object_iterator,
264       (void *) &nxt_conf_vldt_listener },
265 
266     { nxt_string("routes"),
267       NXT_CONF_VLDT_ARRAY | NXT_CONF_VLDT_OBJECT,
268       &nxt_conf_vldt_routes,
269       NULL },
270 
271     { nxt_string("applications"),
272       NXT_CONF_VLDT_OBJECT,
273       &nxt_conf_vldt_object_iterator,
274       (void *) &nxt_conf_vldt_app },
275 
276     { nxt_string("upstreams"),
277       NXT_CONF_VLDT_OBJECT,
278       &nxt_conf_vldt_object_iterator,
279       (void *) &nxt_conf_vldt_upstream },
280 
281     { nxt_string("access_log"),
282       NXT_CONF_VLDT_STRING,
283       NULL,
284       NULL },
285 
286     NXT_CONF_VLDT_END
287 };
288 
289 
290 #if (NXT_TLS)
291 
292 static nxt_conf_vldt_object_t  nxt_conf_vldt_tls_members[] = {
293     { nxt_string("certificate"),
294       NXT_CONF_VLDT_STRING,
295       &nxt_conf_vldt_certificate,
296       NULL },
297 
298     NXT_CONF_VLDT_END
299 };
300 
301 #endif
302 
303 
304 static nxt_conf_vldt_object_t  nxt_conf_vldt_listener_members[] = {
305     { nxt_string("pass"),
306       NXT_CONF_VLDT_STRING,
307       &nxt_conf_vldt_pass,
308       NULL },
309 
310     { nxt_string("application"),
311       NXT_CONF_VLDT_STRING,
312       &nxt_conf_vldt_app_name,
313       NULL },
314 
315 #if (NXT_TLS)
316 
317     { nxt_string("tls"),
318       NXT_CONF_VLDT_OBJECT,
319       &nxt_conf_vldt_object,
320       (void *) &nxt_conf_vldt_tls_members },
321 
322 #endif
323 
324     NXT_CONF_VLDT_END
325 };
326 
327 
328 static nxt_conf_vldt_object_t  nxt_conf_vldt_match_members[] = {
329     { nxt_string("method"),
330       NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY,
331       &nxt_conf_vldt_match_patterns,
332       NULL },
333 
334     { nxt_string("scheme"),
335       NXT_CONF_VLDT_STRING,
336       &nxt_conf_vldt_match_scheme_pattern,
337       NULL },
338 
339     { nxt_string("host"),
340       NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY,
341       &nxt_conf_vldt_match_patterns,
342       NULL },
343 
344     { nxt_string("source"),
345       NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY,
346       &nxt_conf_vldt_match_addrs,
347       NULL },
348 
349     { nxt_string("destination"),
350       NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY,
351       &nxt_conf_vldt_match_addrs,
352       NULL },
353 
354     { nxt_string("uri"),
355       NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY,
356       &nxt_conf_vldt_match_encoded_patterns,
357       NULL },
358 
359     { nxt_string("arguments"),
360       NXT_CONF_VLDT_OBJECT | NXT_CONF_VLDT_ARRAY,
361       &nxt_conf_vldt_match_encoded_patterns_sets,
362       NULL },
363 
364     { nxt_string("headers"),
365       NXT_CONF_VLDT_OBJECT | NXT_CONF_VLDT_ARRAY,
366       &nxt_conf_vldt_match_patterns_sets,
367       NULL },
368 
369     { nxt_string("cookies"),
370       NXT_CONF_VLDT_OBJECT | NXT_CONF_VLDT_ARRAY,
371       &nxt_conf_vldt_match_patterns_sets,
372       NULL },
373 
374     NXT_CONF_VLDT_END
375 };
376 
377 
378 static nxt_conf_vldt_object_t  nxt_conf_vldt_pass_action_members[] = {
379     { nxt_string("pass"),
380       NXT_CONF_VLDT_STRING,
381       &nxt_conf_vldt_pass,
382       NULL },
383 
384     NXT_CONF_VLDT_END
385 };
386 
387 
388 static nxt_conf_vldt_object_t  nxt_conf_vldt_return_action_members[] = {
389     { nxt_string("return"),
390       NXT_CONF_VLDT_INTEGER,
391       &nxt_conf_vldt_return,
392       NULL },
393 
394     { nxt_string("location"),
395       NXT_CONF_VLDT_STRING,
396       NULL,
397       NULL },
398 
399     NXT_CONF_VLDT_END
400 };
401 
402 
403 static nxt_conf_vldt_object_t  nxt_conf_vldt_share_action_members[] = {
404     { nxt_string("share"),
405       NXT_CONF_VLDT_STRING,
406       NULL,
407       NULL },
408 
409     { nxt_string("fallback"),
410       NXT_CONF_VLDT_OBJECT,
411       &nxt_conf_vldt_action,
412       NULL },
413 
414     NXT_CONF_VLDT_END
415 };
416 
417 
418 static nxt_conf_vldt_object_t  nxt_conf_vldt_proxy_action_members[] = {
419     { nxt_string("proxy"),
420       NXT_CONF_VLDT_STRING,
421       &nxt_conf_vldt_proxy,
422       NULL },
423 
424     NXT_CONF_VLDT_END
425 };
426 
427 
428 static nxt_conf_vldt_object_t  nxt_conf_vldt_route_members[] = {
429     { nxt_string("match"),
430       NXT_CONF_VLDT_OBJECT,
431       &nxt_conf_vldt_object,
432       (void *) &nxt_conf_vldt_match_members },
433 
434     { nxt_string("action"),
435       NXT_CONF_VLDT_OBJECT,
436       &nxt_conf_vldt_action,
437       NULL },
438 
439     NXT_CONF_VLDT_END
440 };
441 
442 
443 static nxt_conf_vldt_object_t  nxt_conf_vldt_app_limits_members[] = {
444     { nxt_string("timeout"),
445       NXT_CONF_VLDT_INTEGER,
446       NULL,
447       NULL },
448 
449     { nxt_string("reschedule_timeout"),
450       NXT_CONF_VLDT_INTEGER,
451       NULL,
452       NULL },
453 
454     { nxt_string("requests"),
455       NXT_CONF_VLDT_INTEGER,
456       NULL,
457       NULL },
458 
459     { nxt_string("shm"),
460       NXT_CONF_VLDT_INTEGER,
461       NULL,
462       NULL },
463 
464     NXT_CONF_VLDT_END
465 };
466 
467 
468 static nxt_conf_vldt_object_t  nxt_conf_vldt_app_processes_members[] = {
469     { nxt_string("spare"),
470       NXT_CONF_VLDT_INTEGER,
471       NULL,
472       NULL },
473 
474     { nxt_string("max"),
475       NXT_CONF_VLDT_INTEGER,
476       NULL,
477       NULL },
478 
479     { nxt_string("idle_timeout"),
480       NXT_CONF_VLDT_INTEGER,
481       NULL,
482       NULL },
483 
484     NXT_CONF_VLDT_END
485 };
486 
487 
488 static nxt_conf_vldt_object_t  nxt_conf_vldt_app_namespaces_members[] = {
489 
490 #if (NXT_HAVE_CLONE_NEWUSER)
491     { nxt_string("credential"),
492       NXT_CONF_VLDT_BOOLEAN,
493       NULL,
494       NULL },
495 #endif
496 
497 #if (NXT_HAVE_CLONE_NEWPID)
498     { nxt_string("pid"),
499       NXT_CONF_VLDT_BOOLEAN,
500       NULL,
501       NULL },
502 #endif
503 
504 #if (NXT_HAVE_CLONE_NEWNET)
505     { nxt_string("network"),
506       NXT_CONF_VLDT_BOOLEAN,
507       NULL,
508       NULL },
509 #endif
510 
511 #if (NXT_HAVE_CLONE_NEWNS)
512     { nxt_string("mount"),
513       NXT_CONF_VLDT_BOOLEAN,
514       NULL,
515       NULL },
516 #endif
517 
518 #if (NXT_HAVE_CLONE_NEWUTS)
519     { nxt_string("uname"),
520       NXT_CONF_VLDT_BOOLEAN,
521       NULL,
522       NULL },
523 #endif
524 
525 #if (NXT_HAVE_CLONE_NEWCGROUP)
526     { nxt_string("cgroup"),
527       NXT_CONF_VLDT_BOOLEAN,
528       NULL,
529       NULL },
530 #endif
531 
532     NXT_CONF_VLDT_END
533 };
534 
535 
536 #if (NXT_HAVE_CLONE_NEWUSER)
537 
538 static nxt_conf_vldt_object_t nxt_conf_vldt_app_procmap_members[] = {
539     { nxt_string("container"),
540       NXT_CONF_VLDT_INTEGER,
541       NULL,
542       NULL },
543 
544     { nxt_string("host"),
545       NXT_CONF_VLDT_INTEGER,
546       NULL,
547       NULL },
548 
549     { nxt_string("size"),
550       NXT_CONF_VLDT_INTEGER,
551       NULL,
552       NULL },
553 };
554 
555 #endif
556 
557 
558 static nxt_conf_vldt_object_t  nxt_conf_vldt_app_isolation_members[] = {
559     { nxt_string("namespaces"),
560       NXT_CONF_VLDT_OBJECT,
561       &nxt_conf_vldt_clone_namespaces,
562       (void *) &nxt_conf_vldt_app_namespaces_members },
563 
564 #if (NXT_HAVE_CLONE_NEWUSER)
565 
566     { nxt_string("uidmap"),
567       NXT_CONF_VLDT_ARRAY,
568       &nxt_conf_vldt_array_iterator,
569       (void *) &nxt_conf_vldt_clone_uidmap },
570 
571     { nxt_string("gidmap"),
572       NXT_CONF_VLDT_ARRAY,
573       &nxt_conf_vldt_array_iterator,
574       (void *) &nxt_conf_vldt_clone_gidmap },
575 
576 #endif
577 
578 #if (NXT_HAVE_ISOLATION_ROOTFS)
579 
580     { nxt_string("rootfs"),
581       NXT_CONF_VLDT_STRING,
582       NULL,
583       NULL },
584 
585 #endif
586 
587 #if (NXT_HAVE_PR_SET_NO_NEW_PRIVS)
588 
589     { nxt_string("new_privs"),
590       NXT_CONF_VLDT_BOOLEAN,
591       NULL,
592       NULL },
593 
594 #endif
595 
596     NXT_CONF_VLDT_END
597 };
598 
599 
600 static nxt_conf_vldt_object_t  nxt_conf_vldt_common_members[] = {
601     { nxt_string("type"),
602       NXT_CONF_VLDT_STRING,
603       NULL,
604       NULL },
605 
606     { nxt_string("limits"),
607       NXT_CONF_VLDT_OBJECT,
608       &nxt_conf_vldt_object,
609       (void *) &nxt_conf_vldt_app_limits_members },
610 
611     { nxt_string("processes"),
612       NXT_CONF_VLDT_INTEGER | NXT_CONF_VLDT_OBJECT,
613       &nxt_conf_vldt_processes,
614       (void *) &nxt_conf_vldt_app_processes_members },
615 
616     { nxt_string("user"),
617       NXT_CONF_VLDT_STRING,
618       NULL,
619       NULL },
620 
621     { nxt_string("group"),
622       NXT_CONF_VLDT_STRING,
623       NULL,
624       NULL },
625 
626     { nxt_string("working_directory"),
627       NXT_CONF_VLDT_STRING,
628       NULL,
629       NULL },
630 
631     { nxt_string("environment"),
632       NXT_CONF_VLDT_OBJECT,
633       &nxt_conf_vldt_object_iterator,
634       (void *) &nxt_conf_vldt_environment },
635 
636     { nxt_string("isolation"),
637       NXT_CONF_VLDT_OBJECT,
638       &nxt_conf_vldt_isolation,
639       (void *) &nxt_conf_vldt_app_isolation_members },
640 
641     NXT_CONF_VLDT_END
642 };
643 
644 
645 static nxt_conf_vldt_object_t  nxt_conf_vldt_external_members[] = {
646     { nxt_string("executable"),
647       NXT_CONF_VLDT_STRING,
648       NULL,
649       NULL },
650 
651     { nxt_string("arguments"),
652       NXT_CONF_VLDT_ARRAY,
653       &nxt_conf_vldt_array_iterator,
654       (void *) &nxt_conf_vldt_argument },
655 
656     NXT_CONF_VLDT_NEXT(&nxt_conf_vldt_common_members)
657 };
658 
659 
660 static nxt_conf_vldt_object_t  nxt_conf_vldt_python_members[] = {
661     { nxt_string("home"),
662       NXT_CONF_VLDT_STRING,
663       NULL,
664       NULL },
665 
666     { nxt_string("path"),
667       NXT_CONF_VLDT_STRING,
668       NULL,
669       NULL },
670 
671     { nxt_string("module"),
672       NXT_CONF_VLDT_STRING,
673       NULL,
674       NULL },
675 
676     NXT_CONF_VLDT_NEXT(&nxt_conf_vldt_common_members)
677 };
678 
679 
680 static nxt_conf_vldt_object_t  nxt_conf_vldt_php_target_members[] = {
681     { nxt_string("root"),
682       NXT_CONF_VLDT_STRING,
683       NULL,
684       NULL },
685 
686     { nxt_string("script"),
687       NXT_CONF_VLDT_STRING,
688       NULL,
689       NULL },
690 
691     { nxt_string("index"),
692       NXT_CONF_VLDT_STRING,
693       NULL,
694       NULL }
695 };
696 
697 
698 static nxt_conf_vldt_object_t  nxt_conf_vldt_php_options_members[] = {
699     { nxt_string("file"),
700       NXT_CONF_VLDT_STRING,
701       NULL,
702       NULL },
703 
704     { nxt_string("admin"),
705       NXT_CONF_VLDT_OBJECT,
706       &nxt_conf_vldt_object_iterator,
707       (void *) &nxt_conf_vldt_php_option },
708 
709     { nxt_string("user"),
710       NXT_CONF_VLDT_OBJECT,
711       &nxt_conf_vldt_object_iterator,
712       (void *) &nxt_conf_vldt_php_option },
713 
714     NXT_CONF_VLDT_END
715 };
716 
717 
718 static nxt_conf_vldt_object_t  nxt_conf_vldt_php_common_members[] = {
719     { nxt_string("options"),
720       NXT_CONF_VLDT_OBJECT,
721       &nxt_conf_vldt_object,
722       (void *) &nxt_conf_vldt_php_options_members },
723 
724     NXT_CONF_VLDT_NEXT(&nxt_conf_vldt_common_members)
725 };
726 
727 
728 static nxt_conf_vldt_object_t  nxt_conf_vldt_php_notargets_members[] = {
729     { nxt_string("root"),
730       NXT_CONF_VLDT_STRING,
731       NULL,
732       NULL },
733 
734     { nxt_string("script"),
735       NXT_CONF_VLDT_STRING,
736       NULL,
737       NULL },
738 
739     { nxt_string("index"),
740       NXT_CONF_VLDT_STRING,
741       NULL,
742       NULL },
743 
744     NXT_CONF_VLDT_NEXT(&nxt_conf_vldt_php_common_members)
745 };
746 
747 
748 static nxt_conf_vldt_object_t  nxt_conf_vldt_php_members[] = {
749     { nxt_string("root"),
750       NXT_CONF_VLDT_ANY_TYPE,
751       &nxt_conf_vldt_php_targets_exclusive,
752       (void *) "root" },
753 
754     { nxt_string("script"),
755       NXT_CONF_VLDT_ANY_TYPE,
756       &nxt_conf_vldt_php_targets_exclusive,
757       (void *) "script" },
758 
759     { nxt_string("index"),
760       NXT_CONF_VLDT_ANY_TYPE,
761       &nxt_conf_vldt_php_targets_exclusive,
762       (void *) "index" },
763 
764     { nxt_string("targets"),
765       NXT_CONF_VLDT_OBJECT,
766       &nxt_conf_vldt_php_targets,
767       NULL },
768 
769     NXT_CONF_VLDT_NEXT(&nxt_conf_vldt_php_common_members)
770 };
771 
772 
773 static nxt_conf_vldt_object_t  nxt_conf_vldt_perl_members[] = {
774     { nxt_string("script"),
775       NXT_CONF_VLDT_STRING,
776       NULL,
777       NULL },
778 
779     NXT_CONF_VLDT_NEXT(&nxt_conf_vldt_common_members)
780 };
781 
782 
783 static nxt_conf_vldt_object_t  nxt_conf_vldt_ruby_members[] = {
784     { nxt_string("script"),
785       NXT_CONF_VLDT_STRING,
786       NULL,
787       NULL },
788 
789     NXT_CONF_VLDT_NEXT(&nxt_conf_vldt_common_members)
790 };
791 
792 
793 static nxt_conf_vldt_object_t  nxt_conf_vldt_java_members[] = {
794     { nxt_string("classpath"),
795       NXT_CONF_VLDT_ARRAY,
796       &nxt_conf_vldt_array_iterator,
797       (void *) &nxt_conf_vldt_java_classpath },
798 
799     { nxt_string("webapp"),
800       NXT_CONF_VLDT_STRING,
801       NULL,
802       NULL },
803 
804     { nxt_string("options"),
805       NXT_CONF_VLDT_ARRAY,
806       &nxt_conf_vldt_array_iterator,
807       (void *) &nxt_conf_vldt_java_option },
808 
809     { nxt_string("unit_jars"),
810       NXT_CONF_VLDT_STRING,
811       NULL,
812       NULL },
813 
814     NXT_CONF_VLDT_NEXT(&nxt_conf_vldt_common_members)
815 };
816 
817 
818 static nxt_conf_vldt_object_t  nxt_conf_vldt_upstream_members[] = {
819     { nxt_string("servers"),
820       NXT_CONF_VLDT_OBJECT,
821       &nxt_conf_vldt_object_iterator,
822       (void *) &nxt_conf_vldt_server },
823 
824     NXT_CONF_VLDT_END
825 };
826 
827 
828 static nxt_conf_vldt_object_t  nxt_conf_vldt_upstream_server_members[] = {
829     { nxt_string("weight"),
830       NXT_CONF_VLDT_NUMBER,
831       &nxt_conf_vldt_server_weight,
832       NULL },
833 
834     NXT_CONF_VLDT_END
835 };
836 
837 
838 nxt_int_t
839 nxt_conf_validate(nxt_conf_validation_t *vldt)
840 {
841     nxt_int_t  ret;
842 
843     ret = nxt_conf_vldt_type(vldt, NULL, vldt->conf, NXT_CONF_VLDT_OBJECT);
844 
845     if (ret != NXT_OK) {
846         return ret;
847     }
848 
849     return nxt_conf_vldt_object(vldt, vldt->conf, nxt_conf_vldt_root_members);
850 }
851 
852 
853 #define NXT_CONF_VLDT_ANY_TYPE_STR                                            \
854     "either a null, a boolean, an integer, "                                  \
855     "a number, a string, an array, or an object"
856 
857 
858 static nxt_int_t
859 nxt_conf_vldt_type(nxt_conf_validation_t *vldt, nxt_str_t *name,
860     nxt_conf_value_t *value, nxt_conf_vldt_type_t type)
861 {
862     u_char      *p;
863     nxt_str_t   expected;
864     nxt_bool_t  serial;
865     nxt_uint_t  value_type, n, t;
866     u_char      buf[nxt_length(NXT_CONF_VLDT_ANY_TYPE_STR)];
867 
868     static nxt_str_t  type_name[] = {
869         nxt_string("a null"),
870         nxt_string("a boolean"),
871         nxt_string("an integer number"),
872         nxt_string("a fractional number"),
873         nxt_string("a string"),
874         nxt_string("an array"),
875         nxt_string("an object"),
876     };
877 
878     value_type = nxt_conf_type(value);
879 
880     if ((1 << value_type) & type) {
881         return NXT_OK;
882     }
883 
884     p = buf;
885 
886     n = nxt_popcount(type);
887 
888     if (n > 1) {
889         p = nxt_cpymem(p, "either ", 7);
890     }
891 
892     serial = (n > 2);
893 
894     for ( ;; ) {
895         t = __builtin_ffs(type) - 1;
896 
897         p = nxt_cpymem(p, type_name[t].start, type_name[t].length);
898 
899         n--;
900 
901         if (n == 0) {
902             break;
903         }
904 
905         if (n > 1 || serial) {
906             *p++ = ',';
907         }
908 
909         if (n == 1) {
910             p = nxt_cpymem(p, " or", 3);
911         }
912 
913         *p++ = ' ';
914 
915         type = type & ~(1 << t);
916     }
917 
918     expected.length = p - buf;
919     expected.start = buf;
920 
921     if (name == NULL) {
922         return nxt_conf_vldt_error(vldt,
923                                    "The configuration must be %V, but not %V.",
924                                    &expected, &type_name[value_type]);
925     }
926 
927     return nxt_conf_vldt_error(vldt,
928                                "The \"%V\" value must be %V, but not %V.",
929                                name, &expected, &type_name[value_type]);
930 }
931 
932 
933 static nxt_int_t
934 nxt_conf_vldt_error(nxt_conf_validation_t *vldt, const char *fmt, ...)
935 {
936     u_char   *p, *end;
937     size_t   size;
938     va_list  args;
939     u_char   error[NXT_MAX_ERROR_STR];
940 
941     va_start(args, fmt);
942     end = nxt_vsprintf(error, error + NXT_MAX_ERROR_STR, fmt, args);
943     va_end(args);
944 
945     size = end - error;
946 
947     p = nxt_mp_nget(vldt->pool, size);
948     if (p == NULL) {
949         return NXT_ERROR;
950     }
951 
952     nxt_memcpy(p, error, size);
953 
954     vldt->error.length = size;
955     vldt->error.start = p;
956 
957     return NXT_DECLINED;
958 }
959 
960 
961 typedef struct {
962     nxt_mp_t      *pool;
963     nxt_str_t     *type;
964     nxt_lvlhsh_t  hash;
965 } nxt_conf_vldt_mtypes_ctx_t;
966 
967 
968 static nxt_int_t
969 nxt_conf_vldt_mtypes(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
970     void *data)
971 {
972     nxt_int_t                   ret;
973     nxt_conf_vldt_mtypes_ctx_t  ctx;
974 
975     ctx.pool = nxt_mp_create(1024, 128, 256, 32);
976     if (nxt_slow_path(ctx.pool == NULL)) {
977         return NXT_ERROR;
978     }
979 
980     nxt_lvlhsh_init(&ctx.hash);
981 
982     vldt->ctx = &ctx;
983 
984     ret = nxt_conf_vldt_object_iterator(vldt, value,
985                                         &nxt_conf_vldt_mtypes_type);
986 
987     vldt->ctx = NULL;
988 
989     nxt_mp_destroy(ctx.pool);
990 
991     return ret;
992 }
993 
994 
995 static nxt_int_t
996 nxt_conf_vldt_mtypes_type(nxt_conf_validation_t *vldt, nxt_str_t *name,
997     nxt_conf_value_t *value)
998 {
999     nxt_int_t                   ret;
1000     nxt_conf_vldt_mtypes_ctx_t  *ctx;
1001 
1002     ret = nxt_conf_vldt_type(vldt, name, value,
1003                              NXT_CONF_VLDT_STRING|NXT_CONF_VLDT_ARRAY);
1004     if (ret != NXT_OK) {
1005         return ret;
1006     }
1007 
1008     ctx = vldt->ctx;
1009 
1010     ctx->type = nxt_mp_get(ctx->pool, sizeof(nxt_str_t));
1011     if (nxt_slow_path(ctx->type == NULL)) {
1012         return NXT_ERROR;
1013     }
1014 
1015     *ctx->type = *name;
1016 
1017     if (nxt_conf_type(value) == NXT_CONF_ARRAY) {
1018         return nxt_conf_vldt_array_iterator(vldt, value,
1019                                             &nxt_conf_vldt_mtypes_extension);
1020     }
1021 
1022     /* NXT_CONF_STRING */
1023 
1024     return nxt_conf_vldt_mtypes_extension(vldt, value);
1025 }
1026 
1027 
1028 static nxt_int_t
1029 nxt_conf_vldt_mtypes_extension(nxt_conf_validation_t *vldt,
1030     nxt_conf_value_t *value)
1031 {
1032     nxt_str_t                   ext, *dup_type;
1033     nxt_conf_vldt_mtypes_ctx_t  *ctx;
1034 
1035     ctx = vldt->ctx;
1036 
1037     if (nxt_conf_type(value) != NXT_CONF_STRING) {
1038         return nxt_conf_vldt_error(vldt, "The \"%V\" MIME type array must "
1039                                    "contain only strings.", ctx->type);
1040     }
1041 
1042     nxt_conf_get_string(value, &ext);
1043 
1044     if (ext.length == 0) {
1045         return nxt_conf_vldt_error(vldt, "An empty file extension for "
1046                                          "the \"%V\" MIME type.", ctx->type);
1047     }
1048 
1049     dup_type = nxt_http_static_mtypes_hash_find(&ctx->hash, &ext);
1050 
1051     if (dup_type != NULL) {
1052         return nxt_conf_vldt_error(vldt, "The \"%V\" file extension has been "
1053                                          "declared for \"%V\" and \"%V\" "
1054                                          "MIME types at the same time.",
1055                                          &ext, dup_type, ctx->type);
1056     }
1057 
1058     return nxt_http_static_mtypes_hash_add(ctx->pool, &ctx->hash,
1059                                            &ext, ctx->type);
1060 }
1061 
1062 
1063 static nxt_int_t
1064 nxt_conf_vldt_listener(nxt_conf_validation_t *vldt, nxt_str_t *name,
1065     nxt_conf_value_t *value)
1066 {
1067     nxt_int_t  ret;
1068 
1069     ret = nxt_conf_vldt_type(vldt, name, value, NXT_CONF_VLDT_OBJECT);
1070 
1071     if (ret != NXT_OK) {
1072         return ret;
1073     }
1074 
1075     return nxt_conf_vldt_object(vldt, value, nxt_conf_vldt_listener_members);
1076 }
1077 
1078 
1079 static nxt_int_t
1080 nxt_conf_vldt_action(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
1081     void *data)
1082 {
1083     nxt_uint_t              i;
1084     nxt_conf_value_t        *action;
1085     nxt_conf_vldt_object_t  *members;
1086 
1087     static struct {
1088         nxt_str_t               name;
1089         nxt_conf_vldt_object_t  *members;
1090 
1091     } actions[] = {
1092         { nxt_string("pass"), nxt_conf_vldt_pass_action_members },
1093         { nxt_string("return"), nxt_conf_vldt_return_action_members },
1094         { nxt_string("share"), nxt_conf_vldt_share_action_members },
1095         { nxt_string("proxy"), nxt_conf_vldt_proxy_action_members },
1096     };
1097 
1098     members = NULL;
1099 
1100     for (i = 0; i < nxt_nitems(actions); i++) {
1101         action = nxt_conf_get_object_member(value, &actions[i].name, NULL);
1102 
1103         if (action == NULL) {
1104             continue;
1105         }
1106 
1107         if (members != NULL) {
1108             return nxt_conf_vldt_error(vldt, "The \"action\" object must have "
1109                                        "just one of \"pass\", \"return\", "
1110                                        "\"share\", or \"proxy\" options set.");
1111         }
1112 
1113         members = actions[i].members;
1114     }
1115 
1116     if (members == NULL) {
1117         return nxt_conf_vldt_error(vldt, "The \"action\" object must have "
1118                                    "either \"pass\", \"return\", \"share\", "
1119                                    "or \"proxy\" option set.");
1120     }
1121 
1122     return nxt_conf_vldt_object(vldt, value, members);
1123 }
1124 
1125 
1126 static nxt_int_t
1127 nxt_conf_vldt_pass(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
1128     void *data)
1129 {
1130     nxt_str_t  pass;
1131     nxt_int_t  ret;
1132     nxt_str_t  segments[3];
1133 
1134     static nxt_str_t  targets_str = nxt_string("targets");
1135 
1136     nxt_conf_get_string(value, &pass);
1137 
1138     ret = nxt_http_pass_segments(vldt->pool, &pass, segments, 3);
1139 
1140     if (ret != NXT_OK) {
1141         if (ret == NXT_DECLINED) {
1142             return nxt_conf_vldt_error(vldt, "Request \"pass\" value \"%V\" "
1143                                        "is invalid.", &pass);
1144         }
1145 
1146         return NXT_ERROR;
1147     }
1148 
1149     if (nxt_str_eq(&segments[0], "applications", 12)) {
1150 
1151         if (segments[1].length == 0) {
1152             goto error;
1153         }
1154 
1155         value = nxt_conf_get_object_member(vldt->conf, &segments[0], NULL);
1156 
1157         if (value == NULL) {
1158             goto error;
1159         }
1160 
1161         value = nxt_conf_get_object_member(value, &segments[1], NULL);
1162 
1163         if (value == NULL) {
1164             goto error;
1165         }
1166 
1167         if (segments[2].length > 0) {
1168             value = nxt_conf_get_object_member(value, &targets_str, NULL);
1169 
1170             if (value == NULL) {
1171                 goto error;
1172             }
1173 
1174             value = nxt_conf_get_object_member(value, &segments[2], NULL);
1175 
1176             if (value == NULL) {
1177                 goto error;
1178             }
1179         }
1180 
1181         return NXT_OK;
1182     }
1183 
1184     if (nxt_str_eq(&segments[0], "upstreams", 9)) {
1185 
1186         if (segments[1].length == 0 || segments[2].length != 0) {
1187             goto error;
1188         }
1189 
1190         value = nxt_conf_get_object_member(vldt->conf, &segments[0], NULL);
1191 
1192         if (value == NULL) {
1193             goto error;
1194         }
1195 
1196         value = nxt_conf_get_object_member(value, &segments[1], NULL);
1197 
1198         if (value == NULL) {
1199             goto error;
1200         }
1201 
1202         return NXT_OK;
1203     }
1204 
1205     if (nxt_str_eq(&segments[0], "routes", 6)) {
1206 
1207         if (segments[2].length != 0) {
1208             goto error;
1209         }
1210 
1211         value = nxt_conf_get_object_member(vldt->conf, &segments[0], NULL);
1212 
1213         if (value == NULL) {
1214             goto error;
1215         }
1216 
1217         if (segments[1].length == 0) {
1218             if (nxt_conf_type(value) != NXT_CONF_ARRAY) {
1219                 goto error;
1220             }
1221 
1222             return NXT_OK;
1223         }
1224 
1225         if (nxt_conf_type(value) != NXT_CONF_OBJECT) {
1226             goto error;
1227         }
1228 
1229         value = nxt_conf_get_object_member(value, &segments[1], NULL);
1230 
1231         if (value == NULL) {
1232             goto error;
1233         }
1234 
1235         return NXT_OK;
1236     }
1237 
1238 error:
1239 
1240     return nxt_conf_vldt_error(vldt, "Request \"pass\" points to invalid "
1241                                "location \"%V\".", &pass);
1242 }
1243 
1244 
1245 static nxt_int_t
1246 nxt_conf_vldt_return(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
1247     void *data)
1248 {
1249     int64_t  status;
1250 
1251     status = nxt_conf_get_number(value);
1252 
1253     if (status < NXT_HTTP_INVALID || status > NXT_HTTP_STATUS_MAX) {
1254         return nxt_conf_vldt_error(vldt, "The \"return\" value is out of "
1255                                    "allowed HTTP status code range 0-999.");
1256     }
1257 
1258     return NXT_OK;
1259 }
1260 
1261 
1262 static nxt_int_t
1263 nxt_conf_vldt_proxy(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
1264     void *data)
1265 {
1266     nxt_str_t       name;
1267     nxt_sockaddr_t  *sa;
1268 
1269     nxt_conf_get_string(value, &name);
1270 
1271     if (nxt_str_start(&name, "http://", 7)) {
1272         name.length -= 7;
1273         name.start += 7;
1274 
1275         sa = nxt_sockaddr_parse(vldt->pool, &name);
1276         if (sa != NULL) {
1277             return NXT_OK;
1278         }
1279     }
1280 
1281     return nxt_conf_vldt_error(vldt, "The \"proxy\" address is invalid \"%V\"",
1282                                &name);
1283 }
1284 
1285 
1286 static nxt_int_t
1287 nxt_conf_vldt_routes(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
1288     void *data)
1289 {
1290     if (nxt_conf_type(value) == NXT_CONF_ARRAY) {
1291         return nxt_conf_vldt_array_iterator(vldt, value,
1292                                             &nxt_conf_vldt_route);
1293     }
1294 
1295     /* NXT_CONF_OBJECT */
1296 
1297     return nxt_conf_vldt_object_iterator(vldt, value,
1298                                          &nxt_conf_vldt_routes_member);
1299 }
1300 
1301 
1302 static nxt_int_t
1303 nxt_conf_vldt_routes_member(nxt_conf_validation_t *vldt, nxt_str_t *name,
1304     nxt_conf_value_t *value)
1305 {
1306     nxt_int_t  ret;
1307 
1308     ret = nxt_conf_vldt_type(vldt, name, value, NXT_CONF_VLDT_ARRAY);
1309 
1310     if (ret != NXT_OK) {
1311         return ret;
1312     }
1313 
1314     return nxt_conf_vldt_array_iterator(vldt, value, &nxt_conf_vldt_route);
1315 }
1316 
1317 
1318 static nxt_int_t
1319 nxt_conf_vldt_route(nxt_conf_validation_t *vldt, nxt_conf_value_t *value)
1320 {
1321     if (nxt_conf_type(value) != NXT_CONF_OBJECT) {
1322         return nxt_conf_vldt_error(vldt, "The \"routes\" array must contain "
1323                                    "only object values.");
1324     }
1325 
1326     return nxt_conf_vldt_object(vldt, value, nxt_conf_vldt_route_members);
1327 }
1328 
1329 
1330 static nxt_int_t
1331 nxt_conf_vldt_match_patterns(nxt_conf_validation_t *vldt,
1332     nxt_conf_value_t *value, void *data)
1333 {
1334     if (nxt_conf_type(value) == NXT_CONF_ARRAY) {
1335         return nxt_conf_vldt_array_iterator(vldt, value,
1336                                             &nxt_conf_vldt_match_pattern);
1337     }
1338 
1339     /* NXT_CONF_STRING */
1340 
1341     return nxt_conf_vldt_match_pattern(vldt, value);
1342 }
1343 
1344 
1345 static nxt_int_t
1346 nxt_conf_vldt_match_pattern(nxt_conf_validation_t *vldt,
1347     nxt_conf_value_t *value)
1348 {
1349     u_char      ch;
1350     nxt_str_t   pattern;
1351     nxt_uint_t  i, first, last;
1352 
1353     enum {
1354         sw_none,
1355         sw_side,
1356         sw_middle
1357     } state;
1358 
1359     if (nxt_conf_type(value) != NXT_CONF_STRING) {
1360         return nxt_conf_vldt_error(vldt, "The \"match\" patterns for \"host\", "
1361                                    "\"uri\", and \"method\" must be strings.");
1362     }
1363 
1364     nxt_conf_get_string(value, &pattern);
1365 
1366     if (pattern.length == 0) {
1367         return NXT_OK;
1368     }
1369 
1370     first = (pattern.start[0] == '!');
1371     last = pattern.length - 1;
1372     state = sw_none;
1373 
1374     for (i = first; i != pattern.length; i++) {
1375 
1376         ch = pattern.start[i];
1377 
1378         if (ch != '*') {
1379             continue;
1380         }
1381 
1382         switch (state) {
1383         case sw_none:
1384             state = (i == first) ? sw_side : sw_middle;
1385             break;
1386 
1387         case sw_side:
1388             if (i == last) {
1389                 if (last - first != 1) {
1390                     break;
1391                 }
1392 
1393                 return nxt_conf_vldt_error(vldt, "The \"match\" pattern must "
1394                                            "not contain double \"*\" markers.");
1395             }
1396 
1397             /* Fall through. */
1398 
1399         case sw_middle:
1400             return nxt_conf_vldt_error(vldt, "The \"match\" patterns can "
1401                                        "either contain \"*\" markers at "
1402                                        "the sides or only one in the middle.");
1403         }
1404     }
1405 
1406     return NXT_OK;
1407 }
1408 
1409 
1410 static nxt_int_t nxt_conf_vldt_match_encoded_patterns_sets(
1411     nxt_conf_validation_t *vldt, nxt_conf_value_t *value, void *data)
1412 {
1413     if (nxt_conf_type(value) == NXT_CONF_ARRAY) {
1414         return nxt_conf_vldt_array_iterator(vldt, value,
1415                                      &nxt_conf_vldt_match_encoded_patterns_set);
1416     }
1417 
1418     /* NXT_CONF_STRING */
1419 
1420     return nxt_conf_vldt_match_encoded_patterns_set(vldt, value);
1421 }
1422 
1423 
1424 static nxt_int_t nxt_conf_vldt_match_encoded_patterns_set(
1425     nxt_conf_validation_t *vldt, nxt_conf_value_t *value)
1426 {
1427     if (nxt_conf_type(value) != NXT_CONF_OBJECT) {
1428         return nxt_conf_vldt_error(vldt, "The \"match\" pattern for "
1429                                    "\"arguments\" must be an object.");
1430     }
1431 
1432     return nxt_conf_vldt_object_iterator(vldt, value,
1433                               &nxt_conf_vldt_match_encoded_patterns_set_member);
1434 }
1435 
1436 
1437 static nxt_int_t
1438 nxt_conf_vldt_match_encoded_patterns_set_member(nxt_conf_validation_t *vldt,
1439     nxt_str_t *name, nxt_conf_value_t *value)
1440 {
1441     u_char  *p, *end;
1442 
1443     if (nxt_slow_path(name->length == 0)) {
1444         return nxt_conf_vldt_error(vldt, "The \"match\" pattern objects must "
1445                                    "not contain empty member names.");
1446     }
1447 
1448     p = nxt_mp_nget(vldt->pool, name->length);
1449     if (nxt_slow_path(p == NULL)) {
1450         return NXT_ERROR;
1451     }
1452 
1453     end = nxt_decode_uri(p, name->start, name->length);
1454     if (nxt_slow_path(end == NULL)) {
1455         return nxt_conf_vldt_error(vldt, "The \"match\" pattern for "
1456                                    "\"arguments\" is encoded but is invalid.");
1457     }
1458 
1459     return nxt_conf_vldt_match_encoded_patterns(vldt, value, NULL);
1460 }
1461 
1462 
1463 static nxt_int_t
1464 nxt_conf_vldt_match_encoded_patterns(nxt_conf_validation_t *vldt,
1465     nxt_conf_value_t *value, void *data)
1466 {
1467     if (nxt_conf_type(value) == NXT_CONF_ARRAY) {
1468         return nxt_conf_vldt_array_iterator(vldt, value,
1469                                           &nxt_conf_vldt_match_encoded_pattern);
1470     }
1471 
1472     /* NXT_CONF_STRING */
1473 
1474     return nxt_conf_vldt_match_encoded_pattern(vldt, value);
1475 }
1476 
1477 
1478 static nxt_int_t
1479 nxt_conf_vldt_match_encoded_pattern(nxt_conf_validation_t *vldt,
1480     nxt_conf_value_t *value)
1481 {
1482     u_char     *p, *end;
1483     nxt_int_t  ret;
1484     nxt_str_t  pattern;
1485 
1486     if (nxt_conf_type(value) != NXT_CONF_STRING) {
1487         return nxt_conf_vldt_error(vldt, "The \"match\" pattern for \"uri\" "
1488                                    "must be a string.");
1489     }
1490 
1491     ret = nxt_conf_vldt_match_pattern(vldt, value);
1492     if (nxt_slow_path(ret != NXT_OK)) {
1493         return ret;
1494     }
1495 
1496     nxt_conf_get_string(value, &pattern);
1497 
1498     p = nxt_mp_nget(vldt->pool, pattern.length);
1499     if (nxt_slow_path(p == NULL)) {
1500         return NXT_ERROR;
1501     }
1502 
1503     end = nxt_decode_uri(p, pattern.start, pattern.length);
1504     if (nxt_slow_path(end == NULL)) {
1505         return nxt_conf_vldt_error(vldt, "The \"match\" pattern for \"uri\" "
1506                                    "is encoded but is invalid.");
1507     }
1508 
1509     return NXT_OK;
1510 }
1511 
1512 
1513 static nxt_int_t
1514 nxt_conf_vldt_match_addrs(nxt_conf_validation_t *vldt,
1515     nxt_conf_value_t *value, void *data)
1516 {
1517     if (nxt_conf_type(value) == NXT_CONF_ARRAY) {
1518         return nxt_conf_vldt_array_iterator(vldt, value,
1519                                             &nxt_conf_vldt_match_addr);
1520     }
1521 
1522     return nxt_conf_vldt_match_addr(vldt, value);
1523 }
1524 
1525 
1526 static nxt_int_t
1527 nxt_conf_vldt_match_addr(nxt_conf_validation_t *vldt,
1528     nxt_conf_value_t *value)
1529 {
1530     nxt_http_route_addr_pattern_t  pattern;
1531 
1532     switch (nxt_http_route_addr_pattern_parse(vldt->pool, &pattern, value)) {
1533 
1534     case NXT_OK:
1535         return NXT_OK;
1536 
1537     case NXT_ADDR_PATTERN_PORT_ERROR:
1538         return nxt_conf_vldt_error(vldt, "The \"address\" port an invalid "
1539                                          "port.");
1540 
1541     case NXT_ADDR_PATTERN_CV_TYPE_ERROR:
1542         return nxt_conf_vldt_error(vldt, "The \"match\" pattern for "
1543                                          "\"address\" must be a string.");
1544 
1545     case NXT_ADDR_PATTERN_LENGTH_ERROR:
1546         return nxt_conf_vldt_error(vldt, "The \"address\" is too short.");
1547 
1548     case NXT_ADDR_PATTERN_FORMAT_ERROR:
1549         return nxt_conf_vldt_error(vldt, "The \"address\" format is invalid.");
1550 
1551     case NXT_ADDR_PATTERN_RANGE_OVERLAP_ERROR:
1552         return nxt_conf_vldt_error(vldt, "The \"address\" range is "
1553                                          "overlapping.");
1554 
1555     case NXT_ADDR_PATTERN_CIDR_ERROR:
1556         return nxt_conf_vldt_error(vldt, "The \"address\" has an invalid CIDR "
1557                                          "prefix.");
1558 
1559     case NXT_ADDR_PATTERN_NO_IPv6_ERROR:
1560         return nxt_conf_vldt_error(vldt, "The \"address\" does not support "
1561                                          "IPv6 with your configuration.");
1562 
1563     default:
1564         return nxt_conf_vldt_error(vldt, "The \"address\" has an unknown "
1565                                          "format.");
1566     }
1567 }
1568 
1569 
1570 static nxt_int_t
1571 nxt_conf_vldt_match_scheme_pattern(nxt_conf_validation_t *vldt,
1572     nxt_conf_value_t *value, void *data)
1573 {
1574     nxt_str_t  scheme;
1575 
1576     static const nxt_str_t  http = nxt_string("http");
1577     static const nxt_str_t  https = nxt_string("https");
1578 
1579     nxt_conf_get_string(value, &scheme);
1580 
1581     if (nxt_strcasestr_eq(&scheme, &http)
1582         || nxt_strcasestr_eq(&scheme, &https))
1583     {
1584         return NXT_OK;
1585     }
1586 
1587     return nxt_conf_vldt_error(vldt, "The \"scheme\" can either be "
1588                                      "\"http\" or \"https\".");
1589 }
1590 
1591 
1592 static nxt_int_t
1593 nxt_conf_vldt_match_patterns_sets(nxt_conf_validation_t *vldt,
1594     nxt_conf_value_t *value, void *data)
1595 {
1596     if (nxt_conf_type(value) == NXT_CONF_ARRAY) {
1597         return nxt_conf_vldt_array_iterator(vldt, value,
1598                                             &nxt_conf_vldt_match_patterns_set);
1599     }
1600 
1601     /* NXT_CONF_OBJECT */
1602 
1603     return nxt_conf_vldt_match_patterns_set(vldt, value);
1604 }
1605 
1606 
1607 static nxt_int_t
1608 nxt_conf_vldt_match_patterns_set(nxt_conf_validation_t *vldt,
1609     nxt_conf_value_t *value)
1610 {
1611     if (nxt_conf_type(value) != NXT_CONF_OBJECT) {
1612         return nxt_conf_vldt_error(vldt, "The \"match\" patterns for "
1613                                    "\"arguments\", \"cookies\", and "
1614                                    "\"headers\" must be objects.");
1615     }
1616 
1617     return nxt_conf_vldt_object_iterator(vldt, value,
1618                                      &nxt_conf_vldt_match_patterns_set_member);
1619 }
1620 
1621 
1622 static nxt_int_t
1623 nxt_conf_vldt_match_patterns_set_member(nxt_conf_validation_t *vldt,
1624     nxt_str_t *name, nxt_conf_value_t *value)
1625 {
1626     if (name->length == 0) {
1627         return nxt_conf_vldt_error(vldt, "The \"match\" pattern objects must "
1628                                    "not contain empty member names.");
1629     }
1630 
1631     return nxt_conf_vldt_match_patterns(vldt, value, NULL);
1632 }
1633 
1634 
1635 #if (NXT_TLS)
1636 
1637 static nxt_int_t
1638 nxt_conf_vldt_certificate(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
1639     void *data)
1640 {
1641     nxt_str_t         name;
1642     nxt_conf_value_t  *cert;
1643 
1644     nxt_conf_get_string(value, &name);
1645 
1646     cert = nxt_cert_info_get(&name);
1647 
1648     if (cert == NULL) {
1649         return nxt_conf_vldt_error(vldt, "Certificate \"%V\" is not found.",
1650                                    &name);
1651     }
1652 
1653     return NXT_OK;
1654 }
1655 
1656 #endif
1657 
1658 
1659 static nxt_int_t
1660 nxt_conf_vldt_app_name(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
1661     void *data)
1662 {
1663     nxt_str_t         name;
1664     nxt_conf_value_t  *apps, *app;
1665 
1666     static nxt_str_t  apps_str = nxt_string("applications");
1667 
1668     nxt_conf_get_string(value, &name);
1669 
1670     apps = nxt_conf_get_object_member(vldt->conf, &apps_str, NULL);
1671 
1672     if (nxt_slow_path(apps == NULL)) {
1673         goto error;
1674     }
1675 
1676     app = nxt_conf_get_object_member(apps, &name, NULL);
1677 
1678     if (nxt_slow_path(app == NULL)) {
1679         goto error;
1680     }
1681 
1682     return NXT_OK;
1683 
1684 error:
1685 
1686     return nxt_conf_vldt_error(vldt, "Listening socket is assigned for "
1687                                      "a non existing application \"%V\".",
1688                                      &name);
1689 }
1690 
1691 
1692 static nxt_int_t
1693 nxt_conf_vldt_app(nxt_conf_validation_t *vldt, nxt_str_t *name,
1694     nxt_conf_value_t *value)
1695 {
1696     nxt_int_t              ret;
1697     nxt_str_t              type;
1698     nxt_thread_t           *thread;
1699     nxt_conf_value_t       *type_value;
1700     nxt_app_lang_module_t  *lang;
1701 
1702     static nxt_str_t  type_str = nxt_string("type");
1703 
1704     static struct {
1705         nxt_conf_vldt_handler_t  validator;
1706         nxt_conf_vldt_object_t   *members;
1707 
1708     } types[] = {
1709         { nxt_conf_vldt_object, nxt_conf_vldt_external_members },
1710         { nxt_conf_vldt_object, nxt_conf_vldt_python_members },
1711         { nxt_conf_vldt_php,    NULL },
1712         { nxt_conf_vldt_object, nxt_conf_vldt_perl_members },
1713         { nxt_conf_vldt_object, nxt_conf_vldt_ruby_members },
1714         { nxt_conf_vldt_object, nxt_conf_vldt_java_members },
1715     };
1716 
1717     ret = nxt_conf_vldt_type(vldt, name, value, NXT_CONF_VLDT_OBJECT);
1718 
1719     if (ret != NXT_OK) {
1720         return ret;
1721     }
1722 
1723     type_value = nxt_conf_get_object_member(value, &type_str, NULL);
1724 
1725     if (type_value == NULL) {
1726         return nxt_conf_vldt_error(vldt,
1727                            "Application must have the \"type\" property set.");
1728     }
1729 
1730     ret = nxt_conf_vldt_type(vldt, &type_str, type_value, NXT_CONF_VLDT_STRING);
1731 
1732     if (ret != NXT_OK) {
1733         return ret;
1734     }
1735 
1736     nxt_conf_get_string(type_value, &type);
1737 
1738     thread = nxt_thread();
1739 
1740     lang = nxt_app_lang_module(thread->runtime, &type);
1741     if (lang == NULL) {
1742         return nxt_conf_vldt_error(vldt,
1743                                    "The module to run \"%V\" is not found "
1744                                    "among the available application modules.",
1745                                    &type);
1746     }
1747 
1748     return types[lang->type].validator(vldt, value, types[lang->type].members);
1749 }
1750 
1751 
1752 static nxt_int_t
1753 nxt_conf_vldt_object(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
1754     void *data)
1755 {
1756     uint32_t                index;
1757     nxt_int_t               ret;
1758     nxt_str_t               name;
1759     nxt_conf_value_t        *member;
1760     nxt_conf_vldt_object_t  *vals;
1761 
1762     index = 0;
1763 
1764     for ( ;; ) {
1765         member = nxt_conf_next_object_member(value, &name, &index);
1766 
1767         if (member == NULL) {
1768             return NXT_OK;
1769         }
1770 
1771         vals = data;
1772 
1773         for ( ;; ) {
1774             if (vals->name.length == 0) {
1775 
1776                 if (vals->data != NULL) {
1777                     vals = vals->data;
1778                     continue;
1779                 }
1780 
1781                 return nxt_conf_vldt_error(vldt, "Unknown parameter \"%V\".",
1782                                            &name);
1783             }
1784 
1785             if (!nxt_strstr_eq(&vals->name, &name)) {
1786                 vals++;
1787                 continue;
1788             }
1789 
1790             ret = nxt_conf_vldt_type(vldt, &name, member, vals->type);
1791 
1792             if (ret != NXT_OK) {
1793                 return ret;
1794             }
1795 
1796             if (vals->validator != NULL) {
1797                 ret = vals->validator(vldt, member, vals->data);
1798 
1799                 if (ret != NXT_OK) {
1800                     return ret;
1801                 }
1802             }
1803 
1804             break;
1805         }
1806     }
1807 }
1808 
1809 
1810 typedef struct {
1811     int64_t  spare;
1812     int64_t  max;
1813     int64_t  idle_timeout;
1814 } nxt_conf_vldt_processes_conf_t;
1815 
1816 
1817 static nxt_conf_map_t  nxt_conf_vldt_processes_conf_map[] = {
1818     {
1819         nxt_string("spare"),
1820         NXT_CONF_MAP_INT64,
1821         offsetof(nxt_conf_vldt_processes_conf_t, spare),
1822     },
1823 
1824     {
1825         nxt_string("max"),
1826         NXT_CONF_MAP_INT64,
1827         offsetof(nxt_conf_vldt_processes_conf_t, max),
1828     },
1829 
1830     {
1831         nxt_string("idle_timeout"),
1832         NXT_CONF_MAP_INT64,
1833         offsetof(nxt_conf_vldt_processes_conf_t, idle_timeout),
1834     },
1835 };
1836 
1837 
1838 static nxt_int_t
1839 nxt_conf_vldt_processes(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
1840     void *data)
1841 {
1842     int64_t                         int_value;
1843     nxt_int_t                       ret;
1844     nxt_conf_vldt_processes_conf_t  proc;
1845 
1846     if (nxt_conf_type(value) == NXT_CONF_NUMBER) {
1847         int_value = nxt_conf_get_number(value);
1848 
1849         if (int_value < 1) {
1850             return nxt_conf_vldt_error(vldt, "The \"processes\" number must be "
1851                                        "equal to or greater than 1.");
1852         }
1853 
1854         if (int_value > NXT_INT32_T_MAX) {
1855             return nxt_conf_vldt_error(vldt, "The \"processes\" number must "
1856                                        "not exceed %d.", NXT_INT32_T_MAX);
1857         }
1858 
1859         return NXT_OK;
1860     }
1861 
1862     ret = nxt_conf_vldt_object(vldt, value, data);
1863     if (ret != NXT_OK) {
1864         return ret;
1865     }
1866 
1867     proc.spare = 0;
1868     proc.max = 1;
1869     proc.idle_timeout = 15;
1870 
1871     ret = nxt_conf_map_object(vldt->pool, value,
1872                               nxt_conf_vldt_processes_conf_map,
1873                               nxt_nitems(nxt_conf_vldt_processes_conf_map),
1874                               &proc);
1875     if (ret != NXT_OK) {
1876         return ret;
1877     }
1878 
1879     if (proc.spare < 0) {
1880         return nxt_conf_vldt_error(vldt, "The \"spare\" number must not be "
1881                                    "negative.");
1882     }
1883 
1884     if (proc.spare > NXT_INT32_T_MAX) {
1885         return nxt_conf_vldt_error(vldt, "The \"spare\" number must not "
1886                                    "exceed %d.", NXT_INT32_T_MAX);
1887     }
1888 
1889     if (proc.max < 1) {
1890         return nxt_conf_vldt_error(vldt, "The \"max\" number must be equal "
1891                                    "to or greater than 1.");
1892     }
1893 
1894     if (proc.max > NXT_INT32_T_MAX) {
1895         return nxt_conf_vldt_error(vldt, "The \"max\" number must not "
1896                                    "exceed %d.", NXT_INT32_T_MAX);
1897     }
1898 
1899     if (proc.max < proc.spare) {
1900         return nxt_conf_vldt_error(vldt, "The \"spare\" number must be "
1901                                    "less than or equal to \"max\".");
1902     }
1903 
1904     if (proc.idle_timeout < 0) {
1905         return nxt_conf_vldt_error(vldt, "The \"idle_timeout\" number must not "
1906                                    "be negative.");
1907     }
1908 
1909     if (proc.idle_timeout > NXT_INT32_T_MAX / 1000) {
1910         return nxt_conf_vldt_error(vldt, "The \"idle_timeout\" number must not "
1911                                    "exceed %d.", NXT_INT32_T_MAX / 1000);
1912     }
1913 
1914     return NXT_OK;
1915 }
1916 
1917 
1918 static nxt_int_t
1919 nxt_conf_vldt_object_iterator(nxt_conf_validation_t *vldt,
1920     nxt_conf_value_t *value, void *data)
1921 {
1922     uint32_t                index;
1923     nxt_int_t               ret;
1924     nxt_str_t               name;
1925     nxt_conf_value_t        *member;
1926     nxt_conf_vldt_member_t  validator;
1927 
1928     validator = (nxt_conf_vldt_member_t) data;
1929     index = 0;
1930 
1931     for ( ;; ) {
1932         member = nxt_conf_next_object_member(value, &name, &index);
1933 
1934         if (member == NULL) {
1935             return NXT_OK;
1936         }
1937 
1938         ret = validator(vldt, &name, member);
1939 
1940         if (ret != NXT_OK) {
1941             return ret;
1942         }
1943     }
1944 }
1945 
1946 
1947 static nxt_int_t
1948 nxt_conf_vldt_array_iterator(nxt_conf_validation_t *vldt,
1949     nxt_conf_value_t *value, void *data)
1950 {
1951     uint32_t                 index;
1952     nxt_int_t                ret;
1953     nxt_conf_value_t         *element;
1954     nxt_conf_vldt_element_t  validator;
1955 
1956     validator = (nxt_conf_vldt_element_t) data;
1957 
1958     for (index = 0; /* void */ ; index++) {
1959         element = nxt_conf_get_array_element(value, index);
1960 
1961         if (element == NULL) {
1962             return NXT_OK;
1963         }
1964 
1965         ret = validator(vldt, element);
1966 
1967         if (ret != NXT_OK) {
1968             return ret;
1969         }
1970     }
1971 }
1972 
1973 
1974 static nxt_int_t
1975 nxt_conf_vldt_environment(nxt_conf_validation_t *vldt, nxt_str_t *name,
1976     nxt_conf_value_t *value)
1977 {
1978     nxt_str_t  str;
1979 
1980     if (name->length == 0) {
1981         return nxt_conf_vldt_error(vldt,
1982                                    "The environment name must not be empty.");
1983     }
1984 
1985     if (nxt_memchr(name->start, '\0', name->length) != NULL) {
1986         return nxt_conf_vldt_error(vldt, "The environment name must not "
1987                                    "contain null character.");
1988     }
1989 
1990     if (nxt_memchr(name->start, '=', name->length) != NULL) {
1991         return nxt_conf_vldt_error(vldt, "The environment name must not "
1992                                    "contain '=' character.");
1993     }
1994 
1995     if (nxt_conf_type(value) != NXT_CONF_STRING) {
1996         return nxt_conf_vldt_error(vldt, "The \"%V\" environment value must be "
1997                                    "a string.", name);
1998     }
1999 
2000     nxt_conf_get_string(value, &str);
2001 
2002     if (nxt_memchr(str.start, '\0', str.length) != NULL) {
2003         return nxt_conf_vldt_error(vldt, "The \"%V\" environment value must "
2004                                    "not contain null character.", name);
2005     }
2006 
2007     return NXT_OK;
2008 }
2009 
2010 
2011 static nxt_int_t
2012 nxt_conf_vldt_clone_namespaces(nxt_conf_validation_t *vldt,
2013     nxt_conf_value_t *value, void *data)
2014 {
2015     return nxt_conf_vldt_object(vldt, value, data);
2016 }
2017 
2018 
2019 static nxt_int_t
2020 nxt_conf_vldt_isolation(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
2021     void *data)
2022 {
2023     return nxt_conf_vldt_object(vldt, value, data);
2024 }
2025 
2026 
2027 #if (NXT_HAVE_CLONE_NEWUSER)
2028 
2029 typedef struct {
2030     nxt_int_t container;
2031     nxt_int_t host;
2032     nxt_int_t size;
2033 } nxt_conf_vldt_clone_procmap_conf_t;
2034 
2035 
2036 static nxt_conf_map_t nxt_conf_vldt_clone_procmap_conf_map[] = {
2037     {
2038         nxt_string("container"),
2039         NXT_CONF_MAP_INT32,
2040         offsetof(nxt_conf_vldt_clone_procmap_conf_t, container),
2041     },
2042 
2043     {
2044         nxt_string("host"),
2045         NXT_CONF_MAP_INT32,
2046         offsetof(nxt_conf_vldt_clone_procmap_conf_t, host),
2047     },
2048 
2049     {
2050         nxt_string("size"),
2051         NXT_CONF_MAP_INT32,
2052         offsetof(nxt_conf_vldt_clone_procmap_conf_t, size),
2053     },
2054 
2055 };
2056 
2057 
2058 static nxt_int_t
2059 nxt_conf_vldt_clone_procmap(nxt_conf_validation_t *vldt, const char *mapfile,
2060         nxt_conf_value_t *value)
2061 {
2062     nxt_int_t                           ret;
2063     nxt_conf_vldt_clone_procmap_conf_t  procmap;
2064 
2065     procmap.container = -1;
2066     procmap.host = -1;
2067     procmap.size = -1;
2068 
2069     ret = nxt_conf_map_object(vldt->pool, value,
2070                               nxt_conf_vldt_clone_procmap_conf_map,
2071                               nxt_nitems(nxt_conf_vldt_clone_procmap_conf_map),
2072                               &procmap);
2073     if (ret != NXT_OK) {
2074         return ret;
2075     }
2076 
2077     if (procmap.container == -1) {
2078         return nxt_conf_vldt_error(vldt, "The %s requires the "
2079                 "\"container\" field set.", mapfile);
2080     }
2081 
2082     if (procmap.host == -1) {
2083         return nxt_conf_vldt_error(vldt, "The %s requires the "
2084                 "\"host\" field set.", mapfile);
2085     }
2086 
2087     if (procmap.size == -1) {
2088         return nxt_conf_vldt_error(vldt, "The %s requires the "
2089                 "\"size\" field set.", mapfile);
2090     }
2091 
2092     return NXT_OK;
2093 }
2094 
2095 
2096 static nxt_int_t
2097 nxt_conf_vldt_clone_uidmap(nxt_conf_validation_t *vldt, nxt_conf_value_t *value)
2098 {
2099     nxt_int_t  ret;
2100 
2101     if (nxt_conf_type(value) != NXT_CONF_OBJECT) {
2102         return nxt_conf_vldt_error(vldt, "The \"uidmap\" array "
2103                                    "must contain only object values.");
2104     }
2105 
2106     ret = nxt_conf_vldt_object(vldt, value,
2107                                (void *) nxt_conf_vldt_app_procmap_members);
2108     if (nxt_slow_path(ret != NXT_OK)) {
2109         return ret;
2110     }
2111 
2112     return nxt_conf_vldt_clone_procmap(vldt, "uid_map", value);
2113 }
2114 
2115 
2116 static nxt_int_t
2117 nxt_conf_vldt_clone_gidmap(nxt_conf_validation_t *vldt, nxt_conf_value_t *value)
2118 {
2119     nxt_int_t ret;
2120 
2121     if (nxt_conf_type(value) != NXT_CONF_OBJECT) {
2122         return nxt_conf_vldt_error(vldt, "The \"gidmap\" array "
2123                                    "must contain only object values.");
2124     }
2125 
2126     ret = nxt_conf_vldt_object(vldt, value,
2127                                (void *) nxt_conf_vldt_app_procmap_members);
2128     if (nxt_slow_path(ret != NXT_OK)) {
2129         return ret;
2130     }
2131 
2132     return nxt_conf_vldt_clone_procmap(vldt, "gid_map", value);
2133 }
2134 
2135 #endif
2136 
2137 
2138 static nxt_int_t
2139 nxt_conf_vldt_argument(nxt_conf_validation_t *vldt, nxt_conf_value_t *value)
2140 {
2141     nxt_str_t  str;
2142 
2143     if (nxt_conf_type(value) != NXT_CONF_STRING) {
2144         return nxt_conf_vldt_error(vldt, "The \"arguments\" array "
2145                                    "must contain only string values.");
2146     }
2147 
2148     nxt_conf_get_string(value, &str);
2149 
2150     if (nxt_memchr(str.start, '\0', str.length) != NULL) {
2151         return nxt_conf_vldt_error(vldt, "The \"arguments\" array must not "
2152                                    "contain strings with null character.");
2153     }
2154 
2155     return NXT_OK;
2156 }
2157 
2158 
2159 static nxt_int_t
2160 nxt_conf_vldt_php(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
2161     void *data)
2162 {
2163     nxt_conf_value_t  *targets;
2164 
2165     static nxt_str_t  targets_str = nxt_string("targets");
2166 
2167     targets = nxt_conf_get_object_member(value, &targets_str, NULL);
2168 
2169     if (targets != NULL) {
2170         return nxt_conf_vldt_object(vldt, value, nxt_conf_vldt_php_members);
2171     }
2172 
2173     return nxt_conf_vldt_object(vldt, value,
2174                                 nxt_conf_vldt_php_notargets_members);
2175 }
2176 
2177 
2178 static nxt_int_t
2179 nxt_conf_vldt_php_targets_exclusive(nxt_conf_validation_t *vldt,
2180     nxt_conf_value_t *value, void *data)
2181 {
2182     return nxt_conf_vldt_error(vldt, "The \"%s\" option is mutually exclusive "
2183                                "with the \"targets\" object.", data);
2184 }
2185 
2186 
2187 static nxt_int_t
2188 nxt_conf_vldt_php_targets(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
2189     void *data)
2190 {
2191     nxt_uint_t  n;
2192 
2193     n = nxt_conf_object_members_count(value);
2194 
2195     if (n > 254) {
2196         return nxt_conf_vldt_error(vldt, "The \"targets\" object must not "
2197                                    "contain more than 254 members.");
2198     }
2199 
2200     return nxt_conf_vldt_object_iterator(vldt, value,
2201                                          &nxt_conf_vldt_php_target);
2202 }
2203 
2204 
2205 static nxt_int_t
2206 nxt_conf_vldt_php_target(nxt_conf_validation_t *vldt, nxt_str_t *name,
2207     nxt_conf_value_t *value)
2208 {
2209     if (name->length == 0) {
2210         return nxt_conf_vldt_error(vldt,
2211                                    "The PHP target name must not be empty.");
2212     }
2213 
2214     if (nxt_conf_type(value) != NXT_CONF_OBJECT) {
2215         return nxt_conf_vldt_error(vldt, "The \"%V\" PHP target must be "
2216                                    "an object.", name);
2217     }
2218 
2219     return nxt_conf_vldt_object(vldt, value, &nxt_conf_vldt_php_target_members);
2220 }
2221 
2222 
2223 static nxt_int_t
2224 nxt_conf_vldt_php_option(nxt_conf_validation_t *vldt, nxt_str_t *name,
2225     nxt_conf_value_t *value)
2226 {
2227     if (name->length == 0) {
2228         return nxt_conf_vldt_error(vldt,
2229                                    "The PHP option name must not be empty.");
2230     }
2231 
2232     if (nxt_conf_type(value) != NXT_CONF_STRING) {
2233         return nxt_conf_vldt_error(vldt, "The \"%V\" PHP option must be "
2234                                    "a string.", name);
2235     }
2236 
2237     return NXT_OK;
2238 }
2239 
2240 
2241 static nxt_int_t
2242 nxt_conf_vldt_java_classpath(nxt_conf_validation_t *vldt,
2243     nxt_conf_value_t *value)
2244 {
2245     nxt_str_t  str;
2246 
2247     if (nxt_conf_type(value) != NXT_CONF_STRING) {
2248         return nxt_conf_vldt_error(vldt, "The \"classpath\" array "
2249                                    "must contain only string values.");
2250     }
2251 
2252     nxt_conf_get_string(value, &str);
2253 
2254     if (nxt_memchr(str.start, '\0', str.length) != NULL) {
2255         return nxt_conf_vldt_error(vldt, "The \"classpath\" array must not "
2256                                    "contain strings with null character.");
2257     }
2258 
2259     return NXT_OK;
2260 }
2261 
2262 
2263 static nxt_int_t
2264 nxt_conf_vldt_java_option(nxt_conf_validation_t *vldt, nxt_conf_value_t *value)
2265 {
2266     nxt_str_t  str;
2267 
2268     if (nxt_conf_type(value) != NXT_CONF_STRING) {
2269         return nxt_conf_vldt_error(vldt, "The \"options\" array "
2270                                    "must contain only string values.");
2271     }
2272 
2273     nxt_conf_get_string(value, &str);
2274 
2275     if (nxt_memchr(str.start, '\0', str.length) != NULL) {
2276         return nxt_conf_vldt_error(vldt, "The \"options\" array must not "
2277                                    "contain strings with null character.");
2278     }
2279 
2280     return NXT_OK;
2281 }
2282 
2283 
2284 static nxt_int_t
2285 nxt_conf_vldt_upstream(nxt_conf_validation_t *vldt, nxt_str_t *name,
2286     nxt_conf_value_t *value)
2287 {
2288     nxt_int_t         ret;
2289     nxt_conf_value_t  *conf;
2290 
2291     static nxt_str_t  servers = nxt_string("servers");
2292 
2293     ret = nxt_conf_vldt_type(vldt, name, value, NXT_CONF_VLDT_OBJECT);
2294 
2295     if (ret != NXT_OK) {
2296         return ret;
2297     }
2298 
2299     ret = nxt_conf_vldt_object(vldt, value, nxt_conf_vldt_upstream_members);
2300 
2301     if (ret != NXT_OK) {
2302         return ret;
2303     }
2304 
2305     conf = nxt_conf_get_object_member(value, &servers, NULL);
2306     if (conf == NULL) {
2307         return nxt_conf_vldt_error(vldt, "The \"%V\" upstream must contain "
2308                                    "\"servers\" object value.", name);
2309     }
2310 
2311     return NXT_OK;
2312 }
2313 
2314 
2315 static nxt_int_t
2316 nxt_conf_vldt_server(nxt_conf_validation_t *vldt, nxt_str_t *name,
2317     nxt_conf_value_t *value)
2318 {
2319     nxt_int_t       ret;
2320     nxt_sockaddr_t  *sa;
2321 
2322     ret = nxt_conf_vldt_type(vldt, name, value, NXT_CONF_VLDT_OBJECT);
2323 
2324     if (ret != NXT_OK) {
2325         return ret;
2326     }
2327 
2328     sa = nxt_sockaddr_parse(vldt->pool, name);
2329 
2330     if (sa == NULL) {
2331         return nxt_conf_vldt_error(vldt, "The \"%V\" is not valid "
2332                                    "server address.", name);
2333     }
2334 
2335     return nxt_conf_vldt_object(vldt, value,
2336                                 nxt_conf_vldt_upstream_server_members);
2337 }
2338 
2339 
2340 static nxt_int_t
2341 nxt_conf_vldt_server_weight(nxt_conf_validation_t *vldt,
2342     nxt_conf_value_t *value, void *data)
2343 {
2344     double  num_value;
2345 
2346     num_value = nxt_conf_get_number(value);
2347 
2348     if (num_value < 0) {
2349         return nxt_conf_vldt_error(vldt, "The \"weight\" number must be "
2350                                    "positive.");
2351     }
2352 
2353     if (num_value > 1000000) {
2354         return nxt_conf_vldt_error(vldt, "The \"weight\" number must "
2355                                    "not exceed 1,000,000");
2356     }
2357 
2358     return NXT_OK;
2359 }
2360