xref: /unit/src/nxt_conf_validation.c (revision 977:4f9268f27b57)
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 
12 
13 typedef enum {
14     NXT_CONF_VLDT_NULL    = 1 << NXT_CONF_NULL,
15     NXT_CONF_VLDT_BOOLEAN = 1 << NXT_CONF_BOOLEAN,
16     NXT_CONF_VLDT_INTEGER = 1 << NXT_CONF_INTEGER,
17     NXT_CONF_VLDT_NUMBER  = 1 << NXT_CONF_NUMBER,
18     NXT_CONF_VLDT_STRING  = 1 << NXT_CONF_STRING,
19     NXT_CONF_VLDT_ARRAY   = 1 << NXT_CONF_ARRAY,
20     NXT_CONF_VLDT_OBJECT  = 1 << NXT_CONF_OBJECT,
21 } nxt_conf_vldt_type_t;
22 
23 
24 typedef struct {
25     nxt_str_t             name;
26     nxt_conf_vldt_type_t  type;
27     nxt_int_t             (*validator)(nxt_conf_validation_t *vldt,
28                                        nxt_conf_value_t *value, void *data);
29     void                  *data;
30 } nxt_conf_vldt_object_t;
31 
32 
33 #define NXT_CONF_VLDT_NEXT(f)  { nxt_null_string, 0, NULL, (f) }
34 #define NXT_CONF_VLDT_END      { nxt_null_string, 0, NULL, NULL }
35 
36 
37 typedef nxt_int_t (*nxt_conf_vldt_member_t)(nxt_conf_validation_t *vldt,
38                                             nxt_str_t *name,
39                                             nxt_conf_value_t *value);
40 typedef nxt_int_t (*nxt_conf_vldt_element_t)(nxt_conf_validation_t *vldt,
41                                              nxt_conf_value_t *value);
42 typedef nxt_int_t (*nxt_conf_vldt_system_t)(nxt_conf_validation_t *vldt,
43                                             char *name);
44 
45 
46 static nxt_int_t nxt_conf_vldt_type(nxt_conf_validation_t *vldt,
47     nxt_str_t *name, nxt_conf_value_t *value, nxt_conf_vldt_type_t type);
48 static nxt_int_t nxt_conf_vldt_error(nxt_conf_validation_t *vldt,
49     const char *fmt, ...);
50 
51 static nxt_int_t nxt_conf_vldt_listener(nxt_conf_validation_t *vldt,
52     nxt_str_t *name, nxt_conf_value_t *value);
53 #if (NXT_TLS)
54 static nxt_int_t nxt_conf_vldt_certificate(nxt_conf_validation_t *vldt,
55     nxt_conf_value_t *value, void *data);
56 #endif
57 static nxt_int_t nxt_conf_vldt_pass(nxt_conf_validation_t *vldt,
58     nxt_conf_value_t *value, void *data);
59 static nxt_int_t nxt_conf_vldt_routes(nxt_conf_validation_t *vldt,
60     nxt_conf_value_t *value, void *data);
61 static nxt_int_t nxt_conf_vldt_routes_member(nxt_conf_validation_t *vldt,
62     nxt_str_t *name, nxt_conf_value_t *value);
63 static nxt_int_t nxt_conf_vldt_route(nxt_conf_validation_t *vldt,
64     nxt_conf_value_t *value);
65 static nxt_int_t nxt_conf_vldt_match_patterns(nxt_conf_validation_t *vldt,
66     nxt_conf_value_t *value, void *data);
67 static nxt_int_t nxt_conf_vldt_match_pattern(nxt_conf_validation_t *vldt,
68     nxt_conf_value_t *value);
69 static nxt_int_t nxt_conf_vldt_app_name(nxt_conf_validation_t *vldt,
70     nxt_conf_value_t *value, void *data);
71 static nxt_int_t nxt_conf_vldt_app(nxt_conf_validation_t *vldt,
72     nxt_str_t *name, nxt_conf_value_t *value);
73 static nxt_int_t nxt_conf_vldt_object(nxt_conf_validation_t *vldt,
74     nxt_conf_value_t *value, void *data);
75 static nxt_int_t nxt_conf_vldt_processes(nxt_conf_validation_t *vldt,
76     nxt_conf_value_t *value, void *data);
77 static nxt_int_t nxt_conf_vldt_object_iterator(nxt_conf_validation_t *vldt,
78     nxt_conf_value_t *value, void *data);
79 static nxt_int_t nxt_conf_vldt_array_iterator(nxt_conf_validation_t *vldt,
80     nxt_conf_value_t *value, void *data);
81 static nxt_int_t nxt_conf_vldt_system(nxt_conf_validation_t *vldt,
82     nxt_conf_value_t *value, void *data);
83 static nxt_int_t nxt_conf_vldt_user(nxt_conf_validation_t *vldt, char *name);
84 static nxt_int_t nxt_conf_vldt_group(nxt_conf_validation_t *vldt, char *name);
85 static nxt_int_t nxt_conf_vldt_environment(nxt_conf_validation_t *vldt,
86     nxt_str_t *name, nxt_conf_value_t *value);
87 static nxt_int_t nxt_conf_vldt_argument(nxt_conf_validation_t *vldt,
88     nxt_conf_value_t *value);
89 static nxt_int_t nxt_conf_vldt_php_option(nxt_conf_validation_t *vldt,
90     nxt_str_t *name, nxt_conf_value_t *value);
91 static nxt_int_t nxt_conf_vldt_java_classpath(nxt_conf_validation_t *vldt,
92     nxt_conf_value_t *value);
93 static nxt_int_t nxt_conf_vldt_java_option(nxt_conf_validation_t *vldt,
94     nxt_conf_value_t *value);
95 
96 
97 static nxt_conf_vldt_object_t  nxt_conf_vldt_http_members[] = {
98     { nxt_string("header_read_timeout"),
99       NXT_CONF_VLDT_INTEGER,
100       NULL,
101       NULL },
102 
103     { nxt_string("body_read_timeout"),
104       NXT_CONF_VLDT_INTEGER,
105       NULL,
106       NULL },
107 
108     { nxt_string("send_timeout"),
109       NXT_CONF_VLDT_INTEGER,
110       NULL,
111       NULL },
112 
113     { nxt_string("idle_timeout"),
114       NXT_CONF_VLDT_INTEGER,
115       NULL,
116       NULL },
117 
118     { nxt_string("max_body_size"),
119       NXT_CONF_VLDT_INTEGER,
120       NULL,
121       NULL },
122 
123     NXT_CONF_VLDT_END
124 };
125 
126 
127 static nxt_conf_vldt_object_t  nxt_conf_vldt_setting_members[] = {
128     { nxt_string("http"),
129       NXT_CONF_VLDT_OBJECT,
130       &nxt_conf_vldt_object,
131       (void *) &nxt_conf_vldt_http_members },
132 
133     NXT_CONF_VLDT_END
134 };
135 
136 
137 static nxt_conf_vldt_object_t  nxt_conf_vldt_root_members[] = {
138     { nxt_string("settings"),
139       NXT_CONF_VLDT_OBJECT,
140       &nxt_conf_vldt_object,
141       (void *) &nxt_conf_vldt_setting_members },
142 
143     { nxt_string("listeners"),
144       NXT_CONF_VLDT_OBJECT,
145       &nxt_conf_vldt_object_iterator,
146       (void *) &nxt_conf_vldt_listener },
147 
148     { nxt_string("routes"),
149       NXT_CONF_VLDT_ARRAY | NXT_CONF_VLDT_OBJECT,
150       &nxt_conf_vldt_routes,
151       NULL },
152 
153     { nxt_string("applications"),
154       NXT_CONF_VLDT_OBJECT,
155       &nxt_conf_vldt_object_iterator,
156       (void *) &nxt_conf_vldt_app },
157 
158     { nxt_string("access_log"),
159       NXT_CONF_VLDT_STRING,
160       NULL,
161       NULL },
162 
163     NXT_CONF_VLDT_END
164 };
165 
166 
167 #if (NXT_TLS)
168 
169 static nxt_conf_vldt_object_t  nxt_conf_vldt_tls_members[] = {
170     { nxt_string("certificate"),
171       NXT_CONF_VLDT_STRING,
172       &nxt_conf_vldt_certificate,
173       NULL },
174 
175     NXT_CONF_VLDT_END
176 };
177 
178 #endif
179 
180 
181 static nxt_conf_vldt_object_t  nxt_conf_vldt_listener_members[] = {
182     { nxt_string("pass"),
183       NXT_CONF_VLDT_STRING,
184       &nxt_conf_vldt_pass,
185       NULL },
186 
187     { nxt_string("application"),
188       NXT_CONF_VLDT_STRING,
189       &nxt_conf_vldt_app_name,
190       NULL },
191 
192 #if (NXT_TLS)
193 
194     { nxt_string("tls"),
195       NXT_CONF_VLDT_OBJECT,
196       &nxt_conf_vldt_object,
197       (void *) &nxt_conf_vldt_tls_members },
198 
199 #endif
200 
201     NXT_CONF_VLDT_END
202 };
203 
204 
205 static nxt_conf_vldt_object_t  nxt_conf_vldt_match_members[] = {
206     { nxt_string("method"),
207       NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY,
208       &nxt_conf_vldt_match_patterns,
209       NULL },
210 
211     { nxt_string("host"),
212       NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY,
213       &nxt_conf_vldt_match_patterns,
214       NULL },
215 
216     { nxt_string("uri"),
217       NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY,
218       &nxt_conf_vldt_match_patterns,
219       NULL },
220 
221     NXT_CONF_VLDT_END
222 };
223 
224 
225 static nxt_conf_vldt_object_t  nxt_conf_vldt_action_members[] = {
226     { nxt_string("pass"),
227       NXT_CONF_VLDT_STRING,
228       &nxt_conf_vldt_pass,
229       NULL },
230 
231     NXT_CONF_VLDT_END
232 };
233 
234 
235 static nxt_conf_vldt_object_t  nxt_conf_vldt_route_members[] = {
236     { nxt_string("match"),
237       NXT_CONF_VLDT_OBJECT,
238       &nxt_conf_vldt_object,
239       (void *) &nxt_conf_vldt_match_members },
240 
241     { nxt_string("action"),
242       NXT_CONF_VLDT_OBJECT,
243       &nxt_conf_vldt_object,
244       (void *) &nxt_conf_vldt_action_members },
245 
246     NXT_CONF_VLDT_END
247 };
248 
249 
250 static nxt_conf_vldt_object_t  nxt_conf_vldt_app_limits_members[] = {
251     { nxt_string("timeout"),
252       NXT_CONF_VLDT_INTEGER,
253       NULL,
254       NULL },
255 
256     { nxt_string("reschedule_timeout"),
257       NXT_CONF_VLDT_INTEGER,
258       NULL,
259       NULL },
260 
261     { nxt_string("requests"),
262       NXT_CONF_VLDT_INTEGER,
263       NULL,
264       NULL },
265 
266     NXT_CONF_VLDT_END
267 };
268 
269 
270 static nxt_conf_vldt_object_t  nxt_conf_vldt_app_processes_members[] = {
271     { nxt_string("spare"),
272       NXT_CONF_VLDT_INTEGER,
273       NULL,
274       NULL },
275 
276     { nxt_string("max"),
277       NXT_CONF_VLDT_INTEGER,
278       NULL,
279       NULL },
280 
281     { nxt_string("idle_timeout"),
282       NXT_CONF_VLDT_INTEGER,
283       NULL,
284       NULL },
285 
286     NXT_CONF_VLDT_END
287 };
288 
289 
290 static nxt_conf_vldt_object_t  nxt_conf_vldt_common_members[] = {
291     { nxt_string("type"),
292       NXT_CONF_VLDT_STRING,
293       NULL,
294       NULL },
295 
296     { nxt_string("limits"),
297       NXT_CONF_VLDT_OBJECT,
298       &nxt_conf_vldt_object,
299       (void *) &nxt_conf_vldt_app_limits_members },
300 
301     { nxt_string("processes"),
302       NXT_CONF_VLDT_INTEGER | NXT_CONF_VLDT_OBJECT,
303       &nxt_conf_vldt_processes,
304       (void *) &nxt_conf_vldt_app_processes_members },
305 
306     { nxt_string("user"),
307       NXT_CONF_VLDT_STRING,
308       nxt_conf_vldt_system,
309       (void *) &nxt_conf_vldt_user },
310 
311     { nxt_string("group"),
312       NXT_CONF_VLDT_STRING,
313       nxt_conf_vldt_system,
314       (void *) &nxt_conf_vldt_group },
315 
316     { nxt_string("working_directory"),
317       NXT_CONF_VLDT_STRING,
318       NULL,
319       NULL },
320 
321     { nxt_string("environment"),
322       NXT_CONF_VLDT_OBJECT,
323       &nxt_conf_vldt_object_iterator,
324       (void *) &nxt_conf_vldt_environment },
325 
326     NXT_CONF_VLDT_END
327 };
328 
329 
330 static nxt_conf_vldt_object_t  nxt_conf_vldt_external_members[] = {
331     { nxt_string("executable"),
332       NXT_CONF_VLDT_STRING,
333       NULL,
334       NULL },
335 
336     { nxt_string("arguments"),
337       NXT_CONF_VLDT_ARRAY,
338       &nxt_conf_vldt_array_iterator,
339       (void *) &nxt_conf_vldt_argument },
340 
341     NXT_CONF_VLDT_NEXT(&nxt_conf_vldt_common_members)
342 };
343 
344 
345 static nxt_conf_vldt_object_t  nxt_conf_vldt_python_members[] = {
346     { nxt_string("home"),
347       NXT_CONF_VLDT_STRING,
348       NULL,
349       NULL },
350 
351     { nxt_string("path"),
352       NXT_CONF_VLDT_STRING,
353       NULL,
354       NULL },
355 
356     { nxt_string("module"),
357       NXT_CONF_VLDT_STRING,
358       NULL,
359       NULL },
360 
361     NXT_CONF_VLDT_NEXT(&nxt_conf_vldt_common_members)
362 };
363 
364 
365 static nxt_conf_vldt_object_t  nxt_conf_vldt_php_options_members[] = {
366     { nxt_string("file"),
367       NXT_CONF_VLDT_STRING,
368       NULL,
369       NULL },
370 
371     { nxt_string("admin"),
372       NXT_CONF_VLDT_OBJECT,
373       &nxt_conf_vldt_object_iterator,
374       (void *) &nxt_conf_vldt_php_option },
375 
376     { nxt_string("user"),
377       NXT_CONF_VLDT_OBJECT,
378       &nxt_conf_vldt_object_iterator,
379       (void *) &nxt_conf_vldt_php_option },
380 
381     NXT_CONF_VLDT_END
382 };
383 
384 
385 static nxt_conf_vldt_object_t  nxt_conf_vldt_php_members[] = {
386     { nxt_string("root"),
387       NXT_CONF_VLDT_STRING,
388       NULL,
389       NULL },
390 
391     { nxt_string("script"),
392       NXT_CONF_VLDT_STRING,
393       NULL,
394       NULL },
395 
396     { nxt_string("index"),
397       NXT_CONF_VLDT_STRING,
398       NULL,
399       NULL },
400 
401     { nxt_string("options"),
402       NXT_CONF_VLDT_OBJECT,
403       &nxt_conf_vldt_object,
404       (void *) &nxt_conf_vldt_php_options_members },
405 
406     NXT_CONF_VLDT_NEXT(&nxt_conf_vldt_common_members)
407 };
408 
409 
410 static nxt_conf_vldt_object_t  nxt_conf_vldt_perl_members[] = {
411     { nxt_string("script"),
412       NXT_CONF_VLDT_STRING,
413       NULL,
414       NULL },
415 
416     NXT_CONF_VLDT_NEXT(&nxt_conf_vldt_common_members)
417 };
418 
419 
420 static nxt_conf_vldt_object_t  nxt_conf_vldt_ruby_members[] = {
421     { nxt_string("script"),
422       NXT_CONF_VLDT_STRING,
423       NULL,
424       NULL },
425 
426     NXT_CONF_VLDT_NEXT(&nxt_conf_vldt_common_members)
427 };
428 
429 
430 static nxt_conf_vldt_object_t  nxt_conf_vldt_java_members[] = {
431     { nxt_string("classpath"),
432       NXT_CONF_VLDT_ARRAY,
433       &nxt_conf_vldt_array_iterator,
434       (void *) &nxt_conf_vldt_java_classpath},
435 
436     { nxt_string("webapp"),
437       NXT_CONF_VLDT_STRING,
438       NULL,
439       NULL },
440 
441     { nxt_string("options"),
442       NXT_CONF_VLDT_ARRAY,
443       &nxt_conf_vldt_array_iterator,
444       (void *) &nxt_conf_vldt_java_option},
445 
446     { nxt_string("unit_jars"),
447       NXT_CONF_VLDT_STRING,
448       NULL,
449       NULL },
450 
451     NXT_CONF_VLDT_NEXT(&nxt_conf_vldt_common_members)
452 };
453 
454 
455 nxt_int_t
456 nxt_conf_validate(nxt_conf_validation_t *vldt)
457 {
458     nxt_int_t  ret;
459 
460     ret = nxt_conf_vldt_type(vldt, NULL, vldt->conf, NXT_CONF_VLDT_OBJECT);
461 
462     if (ret != NXT_OK) {
463         return ret;
464     }
465 
466     return nxt_conf_vldt_object(vldt, vldt->conf, nxt_conf_vldt_root_members);
467 }
468 
469 
470 #define NXT_CONF_VLDT_ANY_TYPE                                                \
471     "either a null, a boolean, an integer, "                                  \
472     "a number, a string, an array, or an object"
473 
474 
475 static nxt_int_t
476 nxt_conf_vldt_type(nxt_conf_validation_t *vldt, nxt_str_t *name,
477     nxt_conf_value_t *value, nxt_conf_vldt_type_t type)
478 {
479     u_char      *p;
480     nxt_str_t   expected;
481     nxt_bool_t  serial;
482     nxt_uint_t  value_type, n, t;
483     u_char      buf[nxt_length(NXT_CONF_VLDT_ANY_TYPE)];
484 
485     static nxt_str_t  type_name[] = {
486         nxt_string("a null"),
487         nxt_string("a boolean"),
488         nxt_string("an integer"),
489         nxt_string("a number"),
490         nxt_string("a string"),
491         nxt_string("an array"),
492         nxt_string("an object"),
493     };
494 
495     value_type = nxt_conf_type(value);
496 
497     if ((1 << value_type) & type) {
498         return NXT_OK;
499     }
500 
501     p = buf;
502 
503     n = nxt_popcount(type);
504 
505     if (n > 1) {
506         p = nxt_cpymem(p, "either ", 7);
507     }
508 
509     serial = (n > 2);
510 
511     for ( ;; ) {
512         t = __builtin_ffs(type) - 1;
513 
514         p = nxt_cpymem(p, type_name[t].start, type_name[t].length);
515 
516         n--;
517 
518         if (n == 0) {
519             break;
520         }
521 
522         if (n > 1 || serial) {
523             *p++ = ',';
524         }
525 
526         if (n == 1) {
527             p = nxt_cpymem(p, " or", 3);
528         }
529 
530         *p++ = ' ';
531 
532         type = type & ~(1 << t);
533     }
534 
535     expected.length = p - buf;
536     expected.start = buf;
537 
538     if (name == NULL) {
539         return nxt_conf_vldt_error(vldt,
540                                    "The configuration must be %V, but not %V.",
541                                    &expected, &type_name[value_type]);
542     }
543 
544     return nxt_conf_vldt_error(vldt,
545                                "The \"%V\" value must be %V, but not %V.",
546                                name, &expected, &type_name[value_type]);
547 }
548 
549 
550 static nxt_int_t
551 nxt_conf_vldt_error(nxt_conf_validation_t *vldt, const char *fmt, ...)
552 {
553     u_char   *p, *end;
554     size_t   size;
555     va_list  args;
556     u_char   error[NXT_MAX_ERROR_STR];
557 
558     va_start(args, fmt);
559     end = nxt_vsprintf(error, error + NXT_MAX_ERROR_STR, fmt, args);
560     va_end(args);
561 
562     size = end - error;
563 
564     p = nxt_mp_nget(vldt->pool, size);
565     if (p == NULL) {
566         return NXT_ERROR;
567     }
568 
569     nxt_memcpy(p, error, size);
570 
571     vldt->error.length = size;
572     vldt->error.start = p;
573 
574     return NXT_DECLINED;
575 }
576 
577 
578 static nxt_int_t
579 nxt_conf_vldt_listener(nxt_conf_validation_t *vldt, nxt_str_t *name,
580     nxt_conf_value_t *value)
581 {
582     nxt_int_t  ret;
583 
584     ret = nxt_conf_vldt_type(vldt, name, value, NXT_CONF_VLDT_OBJECT);
585 
586     if (ret != NXT_OK) {
587         return ret;
588     }
589 
590     return nxt_conf_vldt_object(vldt, value, nxt_conf_vldt_listener_members);
591 }
592 
593 
594 static nxt_int_t
595 nxt_conf_vldt_pass(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
596     void *data)
597 {
598     u_char     *p;
599     nxt_str_t  pass, first, second;
600 
601     nxt_conf_get_string(value, &pass);
602 
603     p = nxt_memchr(pass.start, '/', pass.length);
604 
605     if (p != NULL) {
606         first.length = p - pass.start;
607         first.start = pass.start;
608 
609         if (pass.length - first.length == 1) {
610             goto error;
611         }
612 
613         second.length = pass.length - first.length - 1;
614         second.start = p + 1;
615 
616     } else {
617         first = pass;
618         second.length = 0;
619     }
620 
621     if (nxt_str_eq(&first, "applications", 12)) {
622 
623         if (second.length == 0) {
624             goto error;
625         }
626 
627         value = nxt_conf_get_object_member(vldt->conf, &first, NULL);
628 
629         if (nxt_slow_path(value == NULL)) {
630             goto error;
631         }
632 
633         value = nxt_conf_get_object_member(value, &second, NULL);
634 
635         if (nxt_slow_path(value == NULL)) {
636             goto error;
637         }
638 
639         return NXT_OK;
640     }
641 
642     if (nxt_str_eq(&first, "routes", 6)) {
643         value = nxt_conf_get_object_member(vldt->conf, &first, NULL);
644 
645         if (nxt_slow_path(value == NULL)) {
646             goto error;
647         }
648 
649         if (second.length == 0) {
650             if (nxt_conf_type(value) != NXT_CONF_ARRAY) {
651                 goto error;
652             }
653 
654             return NXT_OK;
655         }
656 
657         if (nxt_conf_type(value) != NXT_CONF_OBJECT) {
658             goto error;
659         }
660 
661         value = nxt_conf_get_object_member(value, &second, NULL);
662 
663         if (nxt_slow_path(value == NULL)) {
664             goto error;
665         }
666 
667         return NXT_OK;
668     }
669 
670 error:
671 
672     return nxt_conf_vldt_error(vldt, "Request \"pass\" points to invalid "
673                                "location \"%V\".", &pass);
674 }
675 
676 
677 static nxt_int_t
678 nxt_conf_vldt_routes(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
679     void *data)
680 {
681     if (nxt_conf_type(value) == NXT_CONF_ARRAY) {
682         return nxt_conf_vldt_array_iterator(vldt, value,
683                                             &nxt_conf_vldt_route);
684     }
685 
686     /* NXT_CONF_OBJECT */
687 
688     return nxt_conf_vldt_object_iterator(vldt, value,
689                                          &nxt_conf_vldt_routes_member);
690 }
691 
692 
693 static nxt_int_t
694 nxt_conf_vldt_routes_member(nxt_conf_validation_t *vldt, nxt_str_t *name,
695     nxt_conf_value_t *value)
696 {
697     nxt_int_t  ret;
698 
699     ret = nxt_conf_vldt_type(vldt, name, value, NXT_CONF_VLDT_ARRAY);
700 
701     if (ret != NXT_OK) {
702         return ret;
703     }
704 
705     return nxt_conf_vldt_array_iterator(vldt, value, &nxt_conf_vldt_route);
706 }
707 
708 
709 static nxt_int_t
710 nxt_conf_vldt_route(nxt_conf_validation_t *vldt, nxt_conf_value_t *value)
711 {
712     if (nxt_conf_type(value) != NXT_CONF_OBJECT) {
713         return nxt_conf_vldt_error(vldt, "The \"routes\" array must contain "
714                                    "only object values.");
715     }
716 
717     return nxt_conf_vldt_object(vldt, value, nxt_conf_vldt_route_members);
718 }
719 
720 
721 static nxt_int_t
722 nxt_conf_vldt_match_patterns(nxt_conf_validation_t *vldt,
723     nxt_conf_value_t *value, void *data)
724 {
725     if (nxt_conf_type(value) == NXT_CONF_ARRAY) {
726         return nxt_conf_vldt_array_iterator(vldt, value,
727                                             &nxt_conf_vldt_match_pattern);
728     }
729 
730     /* NXT_CONF_STRING */
731 
732     return nxt_conf_vldt_match_pattern(vldt, value);
733 }
734 
735 
736 static nxt_int_t
737 nxt_conf_vldt_match_pattern(nxt_conf_validation_t *vldt,
738     nxt_conf_value_t *value)
739 {
740     u_char      ch;
741     nxt_str_t   pattern;
742     nxt_uint_t  i, first, last;
743 
744     if (nxt_conf_type(value) != NXT_CONF_STRING) {
745         return nxt_conf_vldt_error(vldt,
746                                    "The \"match\" patterns must be strings.");
747     }
748 
749     nxt_conf_get_string(value, &pattern);
750 
751     if (pattern.length == 0) {
752         return NXT_OK;
753     }
754 
755     first = (pattern.start[0] == '!');
756     last = pattern.length - 1;
757 
758     for (i = first; i != pattern.length; i++) {
759         ch = pattern.start[i];
760 
761         if (ch != '*') {
762             continue;
763         }
764 
765         if (i != first && i != last) {
766             return nxt_conf_vldt_error(vldt, "The \"match\" patterns can only "
767                                        "contain \"*\" markers at the sides.");
768         }
769     }
770 
771     return NXT_OK;
772 }
773 
774 
775 #if (NXT_TLS)
776 
777 static nxt_int_t
778 nxt_conf_vldt_certificate(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
779     void *data)
780 {
781     nxt_str_t         name;
782     nxt_conf_value_t  *cert;
783 
784     nxt_conf_get_string(value, &name);
785 
786     cert = nxt_cert_info_get(&name);
787 
788     if (cert == NULL) {
789         return nxt_conf_vldt_error(vldt, "Certificate \"%V\" is not found.",
790                                    &name);
791     }
792 
793     return NXT_OK;
794 }
795 
796 #endif
797 
798 
799 static nxt_int_t
800 nxt_conf_vldt_app_name(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
801     void *data)
802 {
803     nxt_str_t         name;
804     nxt_conf_value_t  *apps, *app;
805 
806     static nxt_str_t  apps_str = nxt_string("applications");
807 
808     nxt_conf_get_string(value, &name);
809 
810     apps = nxt_conf_get_object_member(vldt->conf, &apps_str, NULL);
811 
812     if (nxt_slow_path(apps == NULL)) {
813         goto error;
814     }
815 
816     app = nxt_conf_get_object_member(apps, &name, NULL);
817 
818     if (nxt_slow_path(app == NULL)) {
819         goto error;
820     }
821 
822     return NXT_OK;
823 
824 error:
825 
826     return nxt_conf_vldt_error(vldt, "Listening socket is assigned for "
827                                      "a non existing application \"%V\".",
828                                      &name);
829 }
830 
831 
832 static nxt_int_t
833 nxt_conf_vldt_app(nxt_conf_validation_t *vldt, nxt_str_t *name,
834     nxt_conf_value_t *value)
835 {
836     nxt_int_t              ret;
837     nxt_str_t              type;
838     nxt_thread_t           *thread;
839     nxt_conf_value_t       *type_value;
840     nxt_app_lang_module_t  *lang;
841 
842     static nxt_str_t  type_str = nxt_string("type");
843 
844     static void  *members[] = {
845         nxt_conf_vldt_external_members,
846         nxt_conf_vldt_python_members,
847         nxt_conf_vldt_php_members,
848         nxt_conf_vldt_perl_members,
849         nxt_conf_vldt_ruby_members,
850         nxt_conf_vldt_java_members,
851     };
852 
853     ret = nxt_conf_vldt_type(vldt, name, value, NXT_CONF_VLDT_OBJECT);
854 
855     if (ret != NXT_OK) {
856         return ret;
857     }
858 
859     type_value = nxt_conf_get_object_member(value, &type_str, NULL);
860 
861     if (type_value == NULL) {
862         return nxt_conf_vldt_error(vldt,
863                            "Application must have the \"type\" property set.");
864     }
865 
866     ret = nxt_conf_vldt_type(vldt, &type_str, type_value, NXT_CONF_VLDT_STRING);
867 
868     if (ret != NXT_OK) {
869         return ret;
870     }
871 
872     nxt_conf_get_string(type_value, &type);
873 
874     thread = nxt_thread();
875 
876     lang = nxt_app_lang_module(thread->runtime, &type);
877     if (lang == NULL) {
878         return nxt_conf_vldt_error(vldt,
879                                    "The module to run \"%V\" is not found "
880                                    "among the available application modules.",
881                                    &type);
882     }
883 
884     return nxt_conf_vldt_object(vldt, value, members[lang->type]);
885 }
886 
887 
888 static nxt_int_t
889 nxt_conf_vldt_object(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
890     void *data)
891 {
892     uint32_t                index;
893     nxt_int_t               ret;
894     nxt_str_t               name;
895     nxt_conf_value_t        *member;
896     nxt_conf_vldt_object_t  *vals;
897 
898     index = 0;
899 
900     for ( ;; ) {
901         member = nxt_conf_next_object_member(value, &name, &index);
902 
903         if (member == NULL) {
904             return NXT_OK;
905         }
906 
907         vals = data;
908 
909         for ( ;; ) {
910             if (vals->name.length == 0) {
911 
912                 if (vals->data != NULL) {
913                     vals = vals->data;
914                     continue;
915                 }
916 
917                 return nxt_conf_vldt_error(vldt, "Unknown parameter \"%V\".",
918                                            &name);
919             }
920 
921             if (!nxt_strstr_eq(&vals->name, &name)) {
922                 vals++;
923                 continue;
924             }
925 
926             ret = nxt_conf_vldt_type(vldt, &name, member, vals->type);
927 
928             if (ret != NXT_OK) {
929                 return ret;
930             }
931 
932             if (vals->validator != NULL) {
933                 ret = vals->validator(vldt, member, vals->data);
934 
935                 if (ret != NXT_OK) {
936                     return ret;
937                 }
938             }
939 
940             break;
941         }
942     }
943 }
944 
945 
946 typedef struct {
947     int64_t  spare;
948     int64_t  max;
949     int64_t  idle_timeout;
950 } nxt_conf_vldt_processes_conf_t;
951 
952 
953 static nxt_conf_map_t  nxt_conf_vldt_processes_conf_map[] = {
954     {
955         nxt_string("spare"),
956         NXT_CONF_MAP_INT64,
957         offsetof(nxt_conf_vldt_processes_conf_t, spare),
958     },
959 
960     {
961         nxt_string("max"),
962         NXT_CONF_MAP_INT64,
963         offsetof(nxt_conf_vldt_processes_conf_t, max),
964     },
965 
966     {
967         nxt_string("idle_timeout"),
968         NXT_CONF_MAP_INT64,
969         offsetof(nxt_conf_vldt_processes_conf_t, idle_timeout),
970     },
971 };
972 
973 
974 static nxt_int_t
975 nxt_conf_vldt_processes(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
976     void *data)
977 {
978     int64_t                         int_value;
979     nxt_int_t                       ret;
980     nxt_conf_vldt_processes_conf_t  proc;
981 
982     if (nxt_conf_type(value) == NXT_CONF_INTEGER) {
983         int_value = nxt_conf_get_integer(value);
984 
985         if (int_value < 1) {
986             return nxt_conf_vldt_error(vldt, "The \"processes\" number must be "
987                                        "equal to or greater than 1.");
988         }
989 
990         if (int_value > NXT_INT32_T_MAX) {
991             return nxt_conf_vldt_error(vldt, "The \"processes\" number must "
992                                        "not exceed %d.", NXT_INT32_T_MAX);
993         }
994 
995         return NXT_OK;
996     }
997 
998     ret = nxt_conf_vldt_object(vldt, value, data);
999     if (ret != NXT_OK) {
1000         return ret;
1001     }
1002 
1003     proc.spare = 0;
1004     proc.max = 1;
1005     proc.idle_timeout = 15;
1006 
1007     ret = nxt_conf_map_object(vldt->pool, value,
1008                               nxt_conf_vldt_processes_conf_map,
1009                               nxt_nitems(nxt_conf_vldt_processes_conf_map),
1010                               &proc);
1011     if (ret != NXT_OK) {
1012         return ret;
1013     }
1014 
1015     if (proc.spare < 0) {
1016         return nxt_conf_vldt_error(vldt, "The \"spare\" number must not be "
1017                                    "negative.");
1018     }
1019 
1020     if (proc.spare > NXT_INT32_T_MAX) {
1021         return nxt_conf_vldt_error(vldt, "The \"spare\" number must not "
1022                                    "exceed %d.", NXT_INT32_T_MAX);
1023     }
1024 
1025     if (proc.max < 1) {
1026         return nxt_conf_vldt_error(vldt, "The \"max\" number must be equal "
1027                                    "to or greater than 1.");
1028     }
1029 
1030     if (proc.max > NXT_INT32_T_MAX) {
1031         return nxt_conf_vldt_error(vldt, "The \"max\" number must not "
1032                                    "exceed %d.", NXT_INT32_T_MAX);
1033     }
1034 
1035     if (proc.max < proc.spare) {
1036         return nxt_conf_vldt_error(vldt, "The \"spare\" number must be "
1037                                    "less than or equal to \"max\".");
1038     }
1039 
1040     if (proc.idle_timeout < 0) {
1041         return nxt_conf_vldt_error(vldt, "The \"idle_timeout\" number must not "
1042                                    "be negative.");
1043     }
1044 
1045     if (proc.idle_timeout > NXT_INT32_T_MAX / 1000) {
1046         return nxt_conf_vldt_error(vldt, "The \"idle_timeout\" number must not "
1047                                    "exceed %d.", NXT_INT32_T_MAX / 1000);
1048     }
1049 
1050     return NXT_OK;
1051 }
1052 
1053 
1054 static nxt_int_t
1055 nxt_conf_vldt_object_iterator(nxt_conf_validation_t *vldt,
1056     nxt_conf_value_t *value, void *data)
1057 {
1058     uint32_t                index;
1059     nxt_int_t               ret;
1060     nxt_str_t               name;
1061     nxt_conf_value_t        *member;
1062     nxt_conf_vldt_member_t  validator;
1063 
1064     validator = (nxt_conf_vldt_member_t) data;
1065     index = 0;
1066 
1067     for ( ;; ) {
1068         member = nxt_conf_next_object_member(value, &name, &index);
1069 
1070         if (member == NULL) {
1071             return NXT_OK;
1072         }
1073 
1074         ret = validator(vldt, &name, member);
1075 
1076         if (ret != NXT_OK) {
1077             return ret;
1078         }
1079     }
1080 }
1081 
1082 
1083 static nxt_int_t
1084 nxt_conf_vldt_array_iterator(nxt_conf_validation_t *vldt,
1085     nxt_conf_value_t *value, void *data)
1086 {
1087     uint32_t                 index;
1088     nxt_int_t                ret;
1089     nxt_conf_value_t         *element;
1090     nxt_conf_vldt_element_t  validator;
1091 
1092     validator = (nxt_conf_vldt_element_t) data;
1093 
1094     for (index = 0; /* void */ ; index++) {
1095         element = nxt_conf_get_array_element(value, index);
1096 
1097         if (element == NULL) {
1098             return NXT_OK;
1099         }
1100 
1101         ret = validator(vldt, element);
1102 
1103         if (ret != NXT_OK) {
1104             return ret;
1105         }
1106     }
1107 }
1108 
1109 
1110 static nxt_int_t
1111 nxt_conf_vldt_system(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
1112     void *data)
1113 {
1114     size_t                  length;
1115     nxt_str_t               name;
1116     nxt_conf_vldt_system_t  validator;
1117     char                    string[32];
1118 
1119     /* The cast is required by Sun C. */
1120     validator = (nxt_conf_vldt_system_t) data;
1121 
1122     nxt_conf_get_string(value, &name);
1123 
1124     length = name.length + 1;
1125     length = nxt_min(length, sizeof(string));
1126 
1127     nxt_cpystrn((u_char *) string, name.start, length);
1128 
1129     return validator(vldt, string);
1130 }
1131 
1132 
1133 static nxt_int_t
1134 nxt_conf_vldt_user(nxt_conf_validation_t *vldt, char *user)
1135 {
1136     struct passwd  *pwd;
1137 
1138     nxt_errno = 0;
1139 
1140     pwd = getpwnam(user);
1141 
1142     if (pwd != NULL) {
1143         return NXT_OK;
1144     }
1145 
1146     if (nxt_errno == 0) {
1147         return nxt_conf_vldt_error(vldt, "User \"%s\" is not found.", user);
1148     }
1149 
1150     return NXT_ERROR;
1151 }
1152 
1153 
1154 static nxt_int_t
1155 nxt_conf_vldt_group(nxt_conf_validation_t *vldt, char *group)
1156 {
1157     struct group  *grp;
1158 
1159     nxt_errno = 0;
1160 
1161     grp = getgrnam(group);
1162 
1163     if (grp != NULL) {
1164         return NXT_OK;
1165     }
1166 
1167     if (nxt_errno == 0) {
1168         return nxt_conf_vldt_error(vldt, "Group \"%s\" is not found.", group);
1169     }
1170 
1171     return NXT_ERROR;
1172 }
1173 
1174 
1175 static nxt_int_t
1176 nxt_conf_vldt_environment(nxt_conf_validation_t *vldt, nxt_str_t *name,
1177     nxt_conf_value_t *value)
1178 {
1179     nxt_str_t  str;
1180 
1181     if (name->length == 0) {
1182         return nxt_conf_vldt_error(vldt,
1183                                    "The environment name must not be empty.");
1184     }
1185 
1186     if (nxt_memchr(name->start, '\0', name->length) != NULL) {
1187         return nxt_conf_vldt_error(vldt, "The environment name must not "
1188                                    "contain null character.");
1189     }
1190 
1191     if (nxt_memchr(name->start, '=', name->length) != NULL) {
1192         return nxt_conf_vldt_error(vldt, "The environment name must not "
1193                                    "contain '=' character.");
1194     }
1195 
1196     if (nxt_conf_type(value) != NXT_CONF_STRING) {
1197         return nxt_conf_vldt_error(vldt, "The \"%V\" environment value must be "
1198                                    "a string.", name);
1199     }
1200 
1201     nxt_conf_get_string(value, &str);
1202 
1203     if (nxt_memchr(str.start, '\0', str.length) != NULL) {
1204         return nxt_conf_vldt_error(vldt, "The \"%V\" environment value must "
1205                                    "not contain null character.", name);
1206     }
1207 
1208     return NXT_OK;
1209 }
1210 
1211 
1212 static nxt_int_t
1213 nxt_conf_vldt_argument(nxt_conf_validation_t *vldt, nxt_conf_value_t *value)
1214 {
1215     nxt_str_t  str;
1216 
1217     if (nxt_conf_type(value) != NXT_CONF_STRING) {
1218         return nxt_conf_vldt_error(vldt, "The \"arguments\" array "
1219                                    "must contain only string values.");
1220     }
1221 
1222     nxt_conf_get_string(value, &str);
1223 
1224     if (nxt_memchr(str.start, '\0', str.length) != NULL) {
1225         return nxt_conf_vldt_error(vldt, "The \"arguments\" array must not "
1226                                    "contain strings with null character.");
1227     }
1228 
1229     return NXT_OK;
1230 }
1231 
1232 
1233 static nxt_int_t
1234 nxt_conf_vldt_php_option(nxt_conf_validation_t *vldt, nxt_str_t *name,
1235     nxt_conf_value_t *value)
1236 {
1237     if (name->length == 0) {
1238         return nxt_conf_vldt_error(vldt,
1239                                    "The PHP option name must not be empty.");
1240     }
1241 
1242     if (nxt_conf_type(value) != NXT_CONF_STRING) {
1243         return nxt_conf_vldt_error(vldt, "The \"%V\" PHP option must be "
1244                                    "a string.", name);
1245     }
1246 
1247     return NXT_OK;
1248 }
1249 
1250 
1251 static nxt_int_t
1252 nxt_conf_vldt_java_classpath(nxt_conf_validation_t *vldt, nxt_conf_value_t *value)
1253 {
1254     nxt_str_t  str;
1255 
1256     if (nxt_conf_type(value) != NXT_CONF_STRING) {
1257         return nxt_conf_vldt_error(vldt, "The \"classpath\" array "
1258                                    "must contain only string values.");
1259     }
1260 
1261     nxt_conf_get_string(value, &str);
1262 
1263     if (nxt_memchr(str.start, '\0', str.length) != NULL) {
1264         return nxt_conf_vldt_error(vldt, "The \"classpath\" array must not "
1265                                    "contain strings with null character.");
1266     }
1267 
1268     return NXT_OK;
1269 }
1270 
1271 static nxt_int_t
1272 nxt_conf_vldt_java_option(nxt_conf_validation_t *vldt, nxt_conf_value_t *value)
1273 {
1274     nxt_str_t  str;
1275 
1276     if (nxt_conf_type(value) != NXT_CONF_STRING) {
1277         return nxt_conf_vldt_error(vldt, "The \"options\" array "
1278                                    "must contain only string values.");
1279     }
1280 
1281     nxt_conf_get_string(value, &str);
1282 
1283     if (nxt_memchr(str.start, '\0', str.length) != NULL) {
1284         return nxt_conf_vldt_error(vldt, "The \"options\" array must not "
1285                                    "contain strings with null character.");
1286     }
1287 
1288     return NXT_OK;
1289 }
1290