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