Coverage Report

Created: 2023-11-07 06:43

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