/src/haproxy/src/fcgi-app.c
Line | Count | Source |
1 | | /* |
2 | | * Functions about FCGI applications and filters. |
3 | | * |
4 | | * Copyright (C) 2019 HAProxy Technologies, Christopher Faulet <cfaulet@haproxy.com> |
5 | | * |
6 | | * This program is free software; you can redistribute it and/or |
7 | | * modify it under the terms of the GNU General Public License |
8 | | * as published by the Free Software Foundation; either version |
9 | | * 2 of the License, or (at your option) any later version. |
10 | | * |
11 | | */ |
12 | | |
13 | | #include <haproxy/acl.h> |
14 | | #include <haproxy/api.h> |
15 | | #include <haproxy/cfgparse.h> |
16 | | #include <haproxy/chunk.h> |
17 | | #include <haproxy/errors.h> |
18 | | #include <haproxy/fcgi-app.h> |
19 | | #include <haproxy/filters.h> |
20 | | #include <haproxy/http_fetch.h> |
21 | | #include <haproxy/http_htx.h> |
22 | | #include <haproxy/log.h> |
23 | | #include <haproxy/proxy.h> |
24 | | #include <haproxy/regex.h> |
25 | | #include <haproxy/sample.h> |
26 | | #include <haproxy/server-t.h> |
27 | | #include <haproxy/session.h> |
28 | | #include <haproxy/sink.h> |
29 | | #include <haproxy/tools.h> |
30 | | |
31 | | |
32 | | /* Global list of all FCGI applications */ |
33 | | static struct fcgi_app *fcgi_apps = NULL; |
34 | | |
35 | | struct flt_ops fcgi_flt_ops; |
36 | | const char *fcgi_flt_id = "FCGI filter"; |
37 | | |
38 | | DECLARE_STATIC_TYPED_POOL(pool_head_fcgi_flt_ctx, "fcgi_flt_ctx", struct fcgi_flt_ctx); |
39 | | DECLARE_STATIC_TYPED_POOL(pool_head_fcgi_param_rule, "fcgi_param_rule", struct fcgi_param_rule); |
40 | | DECLARE_STATIC_TYPED_POOL(pool_head_fcgi_hdr_rule, "fcgi_hdr_rule", struct fcgi_hdr_rule); |
41 | | |
42 | | /**************************************************************************/ |
43 | | /***************************** Uitls **************************************/ |
44 | | /**************************************************************************/ |
45 | | /* Makes a fcgi parameter name (prefixed by ':fcgi-') with <name> (in |
46 | | * lowercase). All non alphanumeric character are replaced by an underscore |
47 | | * ('_'). The result is copied into <dst>. the corresponding ist is returned. |
48 | | */ |
49 | | static struct ist fcgi_param_name(char *dst, const struct ist name) |
50 | 0 | { |
51 | 0 | size_t ofs1, ofs2; |
52 | |
|
53 | 0 | memcpy(dst, ":fcgi-", 6); |
54 | 0 | ofs1 = 6; |
55 | 0 | for (ofs2 = 0; ofs2 < name.len; ofs2++) { |
56 | 0 | if (isalnum((unsigned char)name.ptr[ofs2])) |
57 | 0 | dst[ofs1++] = ist_lc[(unsigned char)name.ptr[ofs2]]; |
58 | 0 | else |
59 | 0 | dst[ofs1++] = '_'; |
60 | 0 | } |
61 | 0 | return ist2(dst, ofs1); |
62 | 0 | } |
63 | | |
64 | | /* Returns a pointer to the FCGi application matching the name <name>. NULL is |
65 | | * returned if no match found. |
66 | | */ |
67 | | struct fcgi_app *fcgi_app_find_by_name(const char *name) |
68 | 0 | { |
69 | 0 | struct fcgi_app *app; |
70 | |
|
71 | 0 | for (app = fcgi_apps; app != NULL; app = app->next) { |
72 | 0 | if (strcmp(app->name, name) == 0) |
73 | 0 | return app; |
74 | 0 | } |
75 | | |
76 | 0 | return NULL; |
77 | 0 | } |
78 | | |
79 | | struct fcgi_flt_conf *find_px_fcgi_conf(struct proxy *px) |
80 | 0 | { |
81 | 0 | struct flt_conf *fconf; |
82 | |
|
83 | 0 | list_for_each_entry(fconf, &px->filter_configs, list) { |
84 | 0 | if (fconf->id == fcgi_flt_id) |
85 | 0 | return fconf->conf; |
86 | 0 | } |
87 | 0 | return NULL; |
88 | 0 | } |
89 | | |
90 | | struct fcgi_flt_ctx *find_strm_fcgi_ctx(struct stream *s) |
91 | 0 | { |
92 | 0 | struct filter *filter; |
93 | |
|
94 | 0 | if (!s) |
95 | 0 | return NULL; |
96 | | |
97 | 0 | list_for_each_entry(filter, &strm_flt(s)->filters, list) { |
98 | 0 | if (FLT_ID(filter) == fcgi_flt_id) |
99 | 0 | return FLT_CONF(filter); |
100 | 0 | } |
101 | 0 | return NULL; |
102 | 0 | } |
103 | | |
104 | | struct fcgi_app *get_px_fcgi_app(struct proxy *px) |
105 | 0 | { |
106 | 0 | struct fcgi_flt_conf *fcgi_conf = find_px_fcgi_conf(px); |
107 | |
|
108 | 0 | if (fcgi_conf) |
109 | 0 | return fcgi_conf->app; |
110 | 0 | return NULL; |
111 | 0 | } |
112 | | |
113 | | struct fcgi_app *get_strm_fcgi_app(struct stream *s) |
114 | 0 | { |
115 | 0 | struct fcgi_flt_ctx *fcgi_ctx = find_strm_fcgi_ctx(s); |
116 | |
|
117 | 0 | if (fcgi_ctx) |
118 | 0 | return fcgi_ctx->app; |
119 | 0 | return NULL; |
120 | 0 | } |
121 | | |
122 | | static void fcgi_release_rule_conf(struct fcgi_rule_conf *rule) |
123 | 0 | { |
124 | 0 | if (!rule) |
125 | 0 | return; |
126 | 0 | free(rule->name); |
127 | 0 | free(rule->value); |
128 | 0 | free_acl_cond(rule->cond); |
129 | 0 | free(rule); |
130 | 0 | } |
131 | | |
132 | | static void fcgi_release_rule(struct fcgi_rule *rule) |
133 | 0 | { |
134 | 0 | if (!rule) |
135 | 0 | return; |
136 | | |
137 | 0 | lf_expr_deinit(&rule->value); |
138 | | /* ->cond and ->name are not owned by the rule */ |
139 | 0 | free(rule); |
140 | 0 | } |
141 | | |
142 | | /**************************************************************************/ |
143 | | /*********************** FCGI Sample fetches ******************************/ |
144 | | /**************************************************************************/ |
145 | | |
146 | | static int smp_fetch_fcgi_docroot(const struct arg *args, struct sample *smp, |
147 | | const char *kw, void *private) |
148 | 0 | { |
149 | 0 | struct fcgi_app *app = get_strm_fcgi_app(smp->strm); |
150 | |
|
151 | 0 | if (!app) |
152 | 0 | return 0; |
153 | | |
154 | 0 | smp->data.type = SMP_T_STR; |
155 | 0 | smp->data.u.str.area = app->docroot.ptr; |
156 | 0 | smp->data.u.str.data = app->docroot.len; |
157 | 0 | smp->flags = SMP_F_CONST; |
158 | 0 | return 1; |
159 | 0 | } |
160 | | |
161 | | static int smp_fetch_fcgi_index(const struct arg *args, struct sample *smp, |
162 | | const char *kw, void *private) |
163 | 0 | { |
164 | 0 | struct fcgi_app *app = get_strm_fcgi_app(smp->strm); |
165 | |
|
166 | 0 | if (!app || !istlen(app->index)) |
167 | 0 | return 0; |
168 | | |
169 | 0 | smp->data.type = SMP_T_STR; |
170 | 0 | smp->data.u.str.area = app->index.ptr; |
171 | 0 | smp->data.u.str.data = app->index.len; |
172 | 0 | smp->flags = SMP_F_CONST; |
173 | 0 | return 1; |
174 | 0 | } |
175 | | |
176 | | /**************************************************************************/ |
177 | | /************************** FCGI filter ***********************************/ |
178 | | /**************************************************************************/ |
179 | | static int fcgi_flt_init(struct proxy *px, struct flt_conf *fconf) |
180 | 0 | { |
181 | 0 | fconf->flags |= FLT_CFG_FL_HTX; |
182 | 0 | return 0; |
183 | 0 | } |
184 | | |
185 | | static void fcgi_flt_deinit(struct proxy *px, struct flt_conf *fconf) |
186 | 0 | { |
187 | 0 | struct fcgi_flt_conf *fcgi_conf = fconf->conf; |
188 | 0 | struct fcgi_rule *rule, *back; |
189 | |
|
190 | 0 | if (!fcgi_conf) |
191 | 0 | return; |
192 | | |
193 | 0 | free(fcgi_conf->name); |
194 | |
|
195 | 0 | list_for_each_entry_safe(rule, back, &fcgi_conf->param_rules, list) { |
196 | 0 | LIST_DELETE(&rule->list); |
197 | 0 | fcgi_release_rule(rule); |
198 | 0 | } |
199 | |
|
200 | 0 | list_for_each_entry_safe(rule, back, &fcgi_conf->hdr_rules, list) { |
201 | 0 | LIST_DELETE(&rule->list); |
202 | 0 | fcgi_release_rule(rule); |
203 | 0 | } |
204 | |
|
205 | 0 | free(fcgi_conf); |
206 | 0 | } |
207 | | |
208 | | static int fcgi_flt_check(struct proxy *px, struct flt_conf *fconf) |
209 | 0 | { |
210 | 0 | struct fcgi_flt_conf *fcgi_conf = fconf->conf; |
211 | 0 | struct fcgi_rule_conf *crule, *back; |
212 | 0 | struct fcgi_rule *rule = NULL; |
213 | 0 | struct flt_conf *f; |
214 | 0 | char *errmsg = NULL; |
215 | |
|
216 | 0 | fcgi_conf->app = fcgi_app_find_by_name(fcgi_conf->name); |
217 | 0 | if (!fcgi_conf->app) { |
218 | 0 | ha_alert("proxy '%s' : fcgi-app '%s' not found.\n", |
219 | 0 | px->id, fcgi_conf->name); |
220 | 0 | goto err; |
221 | 0 | } |
222 | | |
223 | 0 | list_for_each_entry(f, &px->filter_configs, list) { |
224 | 0 | if (f->id == http_comp_req_flt_id || f->id == http_comp_res_flt_id || |
225 | 0 | f->id == cache_store_flt_id) |
226 | 0 | continue; |
227 | 0 | else if ((f->id == fconf->id) && f->conf != fcgi_conf) { |
228 | 0 | ha_alert("proxy '%s' : only one fcgi-app supported per backend.\n", |
229 | 0 | px->id); |
230 | 0 | goto err; |
231 | 0 | } |
232 | 0 | else if (f->id != fconf->id) { |
233 | | /* Implicit declaration is only allowed with the |
234 | | * compression and cache. For other filters, an implicit |
235 | | * declaration is required. */ |
236 | 0 | ha_alert("config: proxy '%s': require an explicit filter declaration " |
237 | 0 | "to use the fcgi-app '%s'.\n", px->id, fcgi_conf->name); |
238 | 0 | goto err; |
239 | 0 | } |
240 | 0 | } |
241 | | |
242 | 0 | list_for_each_entry_safe(crule, back, &fcgi_conf->app->conf.rules, list) { |
243 | 0 | rule = calloc(1, sizeof(*rule)); |
244 | 0 | if (!rule) { |
245 | 0 | ha_alert("proxy '%s' : out of memory.\n", px->id); |
246 | 0 | goto err; |
247 | 0 | } |
248 | 0 | rule->type = crule->type; |
249 | 0 | rule->name = ist(crule->name); |
250 | 0 | rule->cond = crule->cond; |
251 | 0 | lf_expr_init(&rule->value); |
252 | |
|
253 | 0 | if (crule->value) { |
254 | 0 | if (!parse_logformat_string(crule->value, px, &rule->value, LOG_OPT_HTTP, |
255 | 0 | SMP_VAL_BE_HRQ_HDR, &errmsg)) { |
256 | 0 | ha_alert("proxy '%s' : %s.\n", px->id, errmsg); |
257 | 0 | goto err; |
258 | 0 | } |
259 | 0 | } |
260 | | |
261 | 0 | if (rule->type == FCGI_RULE_SET_PARAM || rule->type == FCGI_RULE_UNSET_PARAM) |
262 | 0 | LIST_APPEND(&fcgi_conf->param_rules, &rule->list); |
263 | 0 | else /* FCGI_RULE_PASS_HDR/FCGI_RULE_HIDE_HDR */ |
264 | 0 | LIST_APPEND(&fcgi_conf->hdr_rules, &rule->list); |
265 | 0 | } |
266 | 0 | return 0; |
267 | | |
268 | 0 | err: |
269 | 0 | free(errmsg); |
270 | 0 | free(rule); |
271 | 0 | return 1; |
272 | 0 | } |
273 | | |
274 | | static int fcgi_flt_start(struct stream *s, struct filter *filter) |
275 | 0 | { |
276 | 0 | struct fcgi_flt_conf *fcgi_conf = FLT_CONF(filter); |
277 | 0 | struct fcgi_flt_ctx *fcgi_ctx; |
278 | |
|
279 | 0 | fcgi_ctx = pool_alloc(pool_head_fcgi_flt_ctx); |
280 | 0 | if (fcgi_ctx == NULL) { |
281 | | // FIXME: send a warning |
282 | 0 | return 0; |
283 | 0 | } |
284 | 0 | fcgi_ctx->filter = filter; |
285 | 0 | fcgi_ctx->app = fcgi_conf->app; |
286 | 0 | filter->ctx = fcgi_ctx; |
287 | |
|
288 | 0 | s->req.analysers |= AN_REQ_HTTP_BODY; |
289 | 0 | return 1; |
290 | 0 | } |
291 | | |
292 | | static void fcgi_flt_stop(struct stream *s, struct filter *filter) |
293 | 0 | { |
294 | 0 | struct fcgi_flt_ctx *fcgi_ctx = filter->ctx; |
295 | |
|
296 | 0 | if (!fcgi_ctx) |
297 | 0 | return; |
298 | 0 | pool_free(pool_head_fcgi_flt_ctx, fcgi_ctx); |
299 | 0 | filter->ctx = NULL; |
300 | 0 | } |
301 | | |
302 | | static int fcgi_flt_http_headers(struct stream *s, struct filter *filter, struct http_msg *msg) |
303 | 0 | { |
304 | 0 | struct session *sess = strm_sess(s); |
305 | 0 | struct buffer *value; |
306 | 0 | struct fcgi_flt_conf *fcgi_conf = FLT_CONF(filter); |
307 | 0 | struct fcgi_rule *rule; |
308 | 0 | struct fcgi_param_rule *param_rule; |
309 | 0 | struct fcgi_hdr_rule *hdr_rule; |
310 | 0 | struct ebpt_node *node, *next; |
311 | 0 | struct eb_root param_rules = EB_ROOT; |
312 | 0 | struct eb_root hdr_rules = EB_ROOT; |
313 | 0 | struct htx *htx; |
314 | 0 | struct http_hdr_ctx ctx; |
315 | |
|
316 | 0 | htx = htxbuf(&msg->chn->buf); |
317 | |
|
318 | 0 | if (msg->chn->flags & CF_ISRESP) { |
319 | 0 | struct htx_sl *sl; |
320 | | |
321 | | /* Remove the header "Status:" from the response */ |
322 | 0 | ctx.blk = NULL; |
323 | 0 | while (http_find_header(htx, ist("status"), &ctx, 1)) |
324 | 0 | http_remove_header(htx, &ctx); |
325 | | |
326 | | /* Add the header "Date:" if not found */ |
327 | 0 | ctx.blk = NULL; |
328 | 0 | if (!http_find_header(htx, ist("date"), &ctx, 1)) { |
329 | 0 | struct tm tm; |
330 | |
|
331 | 0 | get_gmtime(date.tv_sec, &tm); |
332 | 0 | trash.data = strftime(trash.area, trash.size, "%a, %d %b %Y %T %Z", &tm); |
333 | 0 | if (trash.data) |
334 | 0 | http_add_header(htx, ist("date"), ist2(trash.area, trash.data)); |
335 | 0 | } |
336 | | |
337 | | /* Add the header "Content-Length:" if possible */ |
338 | 0 | sl = http_get_stline(htx); |
339 | 0 | if (s->txn->meth != HTTP_METH_HEAD && sl && |
340 | 0 | (msg->flags & (HTTP_MSGF_XFER_LEN|HTTP_MSGF_CNT_LEN|HTTP_MSGF_TE_CHNK)) == HTTP_MSGF_XFER_LEN && |
341 | 0 | (htx->flags & HTX_FL_EOM)) { |
342 | 0 | struct htx_blk * blk; |
343 | 0 | char *end; |
344 | 0 | size_t len = 0; |
345 | |
|
346 | 0 | for (blk = htx_get_first_blk(htx); blk; blk = htx_get_next_blk(htx, blk)) { |
347 | 0 | enum htx_blk_type type = htx_get_blk_type(blk); |
348 | |
|
349 | 0 | if (type == HTX_BLK_TLR || type == HTX_BLK_EOT) |
350 | 0 | break; |
351 | 0 | if (type == HTX_BLK_DATA) |
352 | 0 | len += htx_get_blksz(blk); |
353 | 0 | } |
354 | 0 | end = ultoa_o(len, trash.area, trash.size); |
355 | 0 | if (http_add_header(htx, ist("content-length"), ist2(trash.area, end-trash.area))) { |
356 | 0 | sl->flags |= HTX_SL_F_CLEN; |
357 | 0 | msg->flags |= HTTP_MSGF_CNT_LEN; |
358 | 0 | } |
359 | 0 | } |
360 | |
|
361 | 0 | return 1; |
362 | 0 | } |
363 | | |
364 | | /* Analyze the request's headers */ |
365 | | |
366 | 0 | value = alloc_trash_chunk(); |
367 | 0 | if (!value) |
368 | 0 | goto end; |
369 | | |
370 | 0 | list_for_each_entry(rule, &fcgi_conf->param_rules, list) { |
371 | 0 | if (!acl_match_cond(rule->cond, s->be, sess, s, SMP_OPT_DIR_REQ|SMP_OPT_FINAL)) |
372 | 0 | continue; |
373 | | |
374 | 0 | param_rule = NULL; |
375 | 0 | node = ebis_lookup_len(¶m_rules, rule->name.ptr, rule->name.len); |
376 | 0 | if (node) { |
377 | 0 | param_rule = container_of(node, struct fcgi_param_rule, node); |
378 | 0 | ebpt_delete(node); |
379 | 0 | } |
380 | 0 | else { |
381 | 0 | param_rule = pool_alloc(pool_head_fcgi_param_rule); |
382 | 0 | if (param_rule == NULL) |
383 | 0 | goto param_rule_err; |
384 | 0 | } |
385 | | |
386 | 0 | param_rule->node.key = rule->name.ptr; |
387 | 0 | param_rule->name = rule->name; |
388 | 0 | param_rule->value = &rule->value; |
389 | 0 | ebis_insert(¶m_rules, ¶m_rule->node); |
390 | 0 | } |
391 | | |
392 | 0 | list_for_each_entry(rule, &fcgi_conf->hdr_rules, list) { |
393 | 0 | if (!acl_match_cond(rule->cond, s->be, sess, s, SMP_OPT_DIR_REQ|SMP_OPT_FINAL)) |
394 | 0 | continue; |
395 | | |
396 | 0 | hdr_rule = NULL; |
397 | 0 | node = ebis_lookup_len(&hdr_rules, rule->name.ptr, rule->name.len); |
398 | 0 | if (node) { |
399 | 0 | hdr_rule = container_of(node, struct fcgi_hdr_rule, node); |
400 | 0 | ebpt_delete(node); |
401 | 0 | } |
402 | 0 | else { |
403 | 0 | hdr_rule = pool_alloc(pool_head_fcgi_hdr_rule); |
404 | 0 | if (hdr_rule == NULL) |
405 | 0 | goto hdr_rule_err; |
406 | 0 | } |
407 | | |
408 | 0 | hdr_rule->node.key = rule->name.ptr; |
409 | 0 | hdr_rule->name = rule->name; |
410 | 0 | hdr_rule->pass = (rule->type == FCGI_RULE_PASS_HDR); |
411 | 0 | ebis_insert(&hdr_rules, &hdr_rule->node); |
412 | 0 | } |
413 | | |
414 | 0 | node = ebpt_first(¶m_rules); |
415 | 0 | while (node) { |
416 | 0 | next = ebpt_next(node); |
417 | 0 | ebpt_delete(node); |
418 | 0 | param_rule = container_of(node, struct fcgi_param_rule, node); |
419 | 0 | node = next; |
420 | |
|
421 | 0 | b_reset(value); |
422 | 0 | value->data = build_logline(s, value->area, value->size, param_rule->value); |
423 | 0 | if (!value->data) { |
424 | 0 | pool_free(pool_head_fcgi_param_rule, param_rule); |
425 | 0 | continue; |
426 | 0 | } |
427 | 0 | if (!http_add_header(htx, param_rule->name, ist2(value->area, value->data))) |
428 | 0 | goto rewrite_err; |
429 | 0 | pool_free(pool_head_fcgi_param_rule, param_rule); |
430 | 0 | } |
431 | | |
432 | 0 | node = ebpt_first(&hdr_rules); |
433 | 0 | while (node) { |
434 | 0 | next = ebpt_next(node); |
435 | 0 | ebpt_delete(node); |
436 | 0 | hdr_rule = container_of(node, struct fcgi_hdr_rule, node); |
437 | 0 | node = next; |
438 | |
|
439 | 0 | if (!hdr_rule->pass) { |
440 | 0 | ctx.blk = NULL; |
441 | 0 | while (http_find_header(htx, hdr_rule->name, &ctx, 1)) |
442 | 0 | http_remove_header(htx, &ctx); |
443 | 0 | } |
444 | 0 | pool_free(pool_head_fcgi_hdr_rule, hdr_rule); |
445 | 0 | } |
446 | |
|
447 | 0 | goto end; |
448 | | |
449 | 0 | rewrite_err: |
450 | 0 | if (sess->fe_tgcounters) |
451 | 0 | _HA_ATOMIC_INC(&sess->fe_tgcounters->failed_rewrites); |
452 | 0 | if (s->be_tgcounters) |
453 | 0 | _HA_ATOMIC_INC(&s->be_tgcounters->failed_rewrites); |
454 | 0 | if (sess->li_tgcounters) |
455 | 0 | _HA_ATOMIC_INC(&sess->li_tgcounters->failed_rewrites); |
456 | 0 | if (s->sv_tgcounters) |
457 | 0 | _HA_ATOMIC_INC(&s->sv_tgcounters->failed_rewrites); |
458 | 0 | hdr_rule_err: |
459 | 0 | node = ebpt_first(&hdr_rules); |
460 | 0 | while (node) { |
461 | 0 | next = ebpt_next(node); |
462 | 0 | ebpt_delete(node); |
463 | 0 | hdr_rule = container_of(node, struct fcgi_hdr_rule, node); |
464 | 0 | node = next; |
465 | 0 | pool_free(pool_head_fcgi_hdr_rule, hdr_rule); |
466 | 0 | } |
467 | 0 | param_rule_err: |
468 | 0 | node = ebpt_first(¶m_rules); |
469 | 0 | while (node) { |
470 | 0 | next = ebpt_next(node); |
471 | 0 | ebpt_delete(node); |
472 | 0 | param_rule = container_of(node, struct fcgi_param_rule, node); |
473 | 0 | node = next; |
474 | 0 | pool_free(pool_head_fcgi_param_rule, param_rule); |
475 | 0 | } |
476 | 0 | end: |
477 | 0 | free_trash_chunk(value); |
478 | 0 | return 1; |
479 | 0 | } |
480 | | |
481 | | struct flt_ops fcgi_flt_ops = { |
482 | | .init = fcgi_flt_init, |
483 | | .check = fcgi_flt_check, |
484 | | .deinit = fcgi_flt_deinit, |
485 | | |
486 | | .attach = fcgi_flt_start, |
487 | | .detach = fcgi_flt_stop, |
488 | | |
489 | | .http_headers = fcgi_flt_http_headers, |
490 | | }; |
491 | | |
492 | | /**************************************************************************/ |
493 | | /*********************** FCGI Config parsing ******************************/ |
494 | | /**************************************************************************/ |
495 | | static int |
496 | | parse_fcgi_flt(char **args, int *cur_arg, struct proxy *px, |
497 | | struct flt_conf *fconf, char **err, void *private) |
498 | 0 | { |
499 | 0 | struct flt_conf *f, *back; |
500 | 0 | struct fcgi_flt_conf *fcgi_conf = NULL; |
501 | 0 | char *name = NULL; |
502 | 0 | int pos = *cur_arg; |
503 | | |
504 | | /* Get the fcgi-app name*/ |
505 | 0 | if (!*args[pos + 1]) { |
506 | 0 | memprintf(err, "%s : expects a <name> argument", args[pos]); |
507 | 0 | goto err; |
508 | 0 | } |
509 | 0 | name = strdup(args[pos + 1]); |
510 | 0 | if (!name) { |
511 | 0 | memprintf(err, "%s '%s' : out of memory", args[pos], args[pos + 1]); |
512 | 0 | goto err; |
513 | 0 | } |
514 | 0 | pos += 2; |
515 | | |
516 | | /* Check if an fcgi-app filter with the same name already exists */ |
517 | 0 | list_for_each_entry_safe(f, back, &px->filter_configs, list) { |
518 | 0 | if (f->id != fcgi_flt_id) |
519 | 0 | continue; |
520 | 0 | fcgi_conf = f->conf; |
521 | 0 | if (strcmp(name, fcgi_conf->name) != 0) { |
522 | 0 | fcgi_conf = NULL; |
523 | 0 | continue; |
524 | 0 | } |
525 | | |
526 | | /* Place the filter at its right position */ |
527 | 0 | LIST_DELETE(&f->list); |
528 | 0 | free(f); |
529 | 0 | ha_free(&name); |
530 | 0 | break; |
531 | 0 | } |
532 | | |
533 | | /* No other fcgi-app filter found, create configuration for the explicit one */ |
534 | 0 | if (!fcgi_conf) { |
535 | 0 | fcgi_conf = calloc(1, sizeof(*fcgi_conf)); |
536 | 0 | if (!fcgi_conf) { |
537 | 0 | memprintf(err, "%s: out of memory", args[*cur_arg]); |
538 | 0 | goto err; |
539 | 0 | } |
540 | 0 | fcgi_conf->name = name; |
541 | 0 | LIST_INIT(&fcgi_conf->param_rules); |
542 | 0 | LIST_INIT(&fcgi_conf->hdr_rules); |
543 | 0 | } |
544 | | |
545 | 0 | fconf->id = fcgi_flt_id; |
546 | 0 | fconf->conf = fcgi_conf; |
547 | 0 | fconf->ops = &fcgi_flt_ops; |
548 | |
|
549 | 0 | *cur_arg = pos; |
550 | 0 | return 0; |
551 | 0 | err: |
552 | 0 | free(name); |
553 | 0 | return -1; |
554 | 0 | } |
555 | | |
556 | | /* Parses the "use-fcgi-app" proxy keyword */ |
557 | | static int proxy_parse_use_fcgi_app(char **args, int section, struct proxy *curpx, |
558 | | const struct proxy *defpx, const char *file, int line, |
559 | | char **err) |
560 | 0 | { |
561 | 0 | struct flt_conf *fconf = NULL; |
562 | 0 | struct fcgi_flt_conf *fcgi_conf = NULL; |
563 | 0 | int retval = 0; |
564 | |
|
565 | 0 | if ((curpx->cap & PR_CAP_DEF) || !(curpx->cap & PR_CAP_BE)) { |
566 | 0 | memprintf(err, "'%s' only available in backend or listen section", args[0]); |
567 | 0 | retval = -1; |
568 | 0 | goto end; |
569 | 0 | } |
570 | | |
571 | 0 | if (!*(args[1])) { |
572 | 0 | memprintf(err, "'%s' expects <name> as argument", args[0]); |
573 | 0 | retval = -1; |
574 | 0 | goto end; |
575 | 0 | } |
576 | | |
577 | | /* check if a fcgi filter was already registered with this name, |
578 | | * if that's the case, must use it. */ |
579 | 0 | list_for_each_entry(fconf, &curpx->filter_configs, list) { |
580 | 0 | if (fconf->id == fcgi_flt_id) { |
581 | 0 | fcgi_conf = fconf->conf; |
582 | 0 | if (fcgi_conf && strcmp((char *)fcgi_conf->name, args[1]) == 0) |
583 | 0 | goto end; |
584 | 0 | memprintf(err, "'%s' : only one fcgi-app supported per backend", args[0]); |
585 | 0 | retval = -1; |
586 | 0 | goto end; |
587 | 0 | } |
588 | 0 | } |
589 | | |
590 | | /* Create the FCGI filter config */ |
591 | 0 | fcgi_conf = calloc(1, sizeof(*fcgi_conf)); |
592 | 0 | if (!fcgi_conf) |
593 | 0 | goto err; |
594 | 0 | fcgi_conf->name = strdup(args[1]); |
595 | 0 | if (!fcgi_conf->name) |
596 | 0 | goto err; |
597 | 0 | LIST_INIT(&fcgi_conf->param_rules); |
598 | 0 | LIST_INIT(&fcgi_conf->hdr_rules); |
599 | | |
600 | | /* Register the filter */ |
601 | 0 | fconf = calloc(1, sizeof(*fconf)); |
602 | 0 | if (!fconf) |
603 | 0 | goto err; |
604 | 0 | fconf->id = fcgi_flt_id; |
605 | 0 | fconf->conf = fcgi_conf; |
606 | 0 | fconf->ops = &fcgi_flt_ops; |
607 | 0 | LIST_APPEND(&curpx->filter_configs, &fconf->list); |
608 | |
|
609 | 0 | end: |
610 | 0 | return retval; |
611 | 0 | err: |
612 | 0 | if (fcgi_conf) { |
613 | 0 | free(fcgi_conf->name); |
614 | 0 | free(fcgi_conf); |
615 | 0 | } |
616 | 0 | memprintf(err, "out of memory"); |
617 | 0 | retval = -1; |
618 | 0 | goto end; |
619 | 0 | } |
620 | | |
621 | | /* Finishes the parsing of FCGI application of proxies and servers */ |
622 | | static int cfg_fcgi_apps_postparser() |
623 | 0 | { |
624 | 0 | struct fcgi_app *curapp; |
625 | 0 | struct proxy *px; |
626 | 0 | struct server *srv; |
627 | 0 | int err_code = 0; |
628 | |
|
629 | 0 | for (px = proxies_list; px; px = px->next) { |
630 | 0 | struct fcgi_flt_conf *fcgi_conf = find_px_fcgi_conf(px); |
631 | 0 | int nb_fcgi_srv = 0; |
632 | |
|
633 | 0 | if (px->mode != PR_MODE_HTTP && fcgi_conf) { |
634 | 0 | ha_alert("proxy '%s': FCGI application cannot be used in non-HTTP mode.\n", |
635 | 0 | px->id); |
636 | 0 | err_code |= ERR_ALERT | ERR_FATAL; |
637 | 0 | goto end; |
638 | 0 | } |
639 | | |
640 | | /* By default, for FCGI-ready backend, HTTP request header names |
641 | | * are restricted and the "delete" policy is set |
642 | | */ |
643 | 0 | if (fcgi_conf && !(px->options2 & PR_O2_RSTRICT_REQ_HDR_NAMES_MASK)) |
644 | 0 | px->options2 |= PR_O2_RSTRICT_REQ_HDR_NAMES_DEL; |
645 | |
|
646 | 0 | for (srv = px->srv; srv; srv = srv->next) { |
647 | 0 | if (srv->mux_proto && isteq(srv->mux_proto->token, ist("fcgi"))) { |
648 | 0 | nb_fcgi_srv++; |
649 | 0 | if (fcgi_conf) |
650 | 0 | continue; |
651 | 0 | ha_alert("proxy '%s': FCGI server '%s' has no FCGI app configured.\n", |
652 | 0 | px->id, srv->id); |
653 | 0 | err_code |= ERR_ALERT | ERR_FATAL; |
654 | 0 | goto end; |
655 | 0 | } |
656 | 0 | } |
657 | 0 | if (fcgi_conf && !nb_fcgi_srv) { |
658 | 0 | ha_alert("proxy '%s': FCGI app configured but no FCGI server found.\n", |
659 | 0 | px->id); |
660 | 0 | err_code |= ERR_ALERT | ERR_FATAL; |
661 | 0 | goto end; |
662 | 0 | } |
663 | 0 | } |
664 | | |
665 | 0 | for (curapp = fcgi_apps; curapp != NULL; curapp = curapp->next) { |
666 | 0 | if (!istlen(curapp->docroot)) { |
667 | 0 | ha_alert("fcgi-app '%s': no docroot configured.\n", |
668 | 0 | curapp->name); |
669 | 0 | err_code |= ERR_ALERT | ERR_FATAL; |
670 | 0 | goto end; |
671 | 0 | } |
672 | 0 | if (!(curapp->flags & (FCGI_APP_FL_MPXS_CONNS|FCGI_APP_FL_GET_VALUES))) { |
673 | 0 | if (curapp->maxreqs > 1) { |
674 | 0 | ha_warning("fcgi-app '%s': multiplexing not supported, " |
675 | 0 | "ignore the option 'max-reqs'.\n", |
676 | 0 | curapp->name); |
677 | 0 | err_code |= ERR_WARN; |
678 | 0 | } |
679 | 0 | curapp->maxreqs = 1; |
680 | 0 | } |
681 | |
|
682 | 0 | err_code |= postresolve_logger_list(NULL, &curapp->loggers, "fcgi-app", curapp->name); |
683 | 0 | } |
684 | | |
685 | 0 | end: |
686 | 0 | return err_code; |
687 | 0 | } |
688 | | |
689 | | static int fcgi_app_add_rule(struct fcgi_app *curapp, enum fcgi_rule_type type, char *name, char *value, |
690 | | struct acl_cond *cond, char **err) |
691 | 0 | { |
692 | 0 | struct fcgi_rule_conf *rule; |
693 | | |
694 | | /* Param not found, add a new one */ |
695 | 0 | rule = calloc(1, sizeof(*rule)); |
696 | 0 | if (!rule) |
697 | 0 | goto err; |
698 | 0 | LIST_INIT(&rule->list); |
699 | 0 | rule->type = type; |
700 | 0 | if (type == FCGI_RULE_SET_PARAM || type == FCGI_RULE_UNSET_PARAM) { |
701 | 0 | struct ist fname = fcgi_param_name(trash.area, ist(name)); |
702 | 0 | rule->name = my_strndup(fname.ptr, fname.len); |
703 | 0 | } |
704 | 0 | else { /* FCGI_RULE_PASS_HDR/FCGI_RULE_HIDE_HDR */ |
705 | 0 | struct ist fname = ist2bin_lc(trash.area, ist(name)); |
706 | 0 | rule->name = my_strndup(fname.ptr, fname.len); |
707 | 0 | } |
708 | 0 | if (!rule->name) |
709 | 0 | goto err; |
710 | | |
711 | 0 | if (value) { |
712 | 0 | rule->value = strdup(value); |
713 | 0 | if (!rule->value) |
714 | 0 | goto err; |
715 | 0 | } |
716 | 0 | rule->cond = cond; |
717 | 0 | LIST_APPEND(&curapp->conf.rules, &rule->list); |
718 | 0 | return 1; |
719 | | |
720 | 0 | err: |
721 | 0 | if (rule) { |
722 | 0 | free(rule->name); |
723 | 0 | free(rule->value); |
724 | 0 | free(rule); |
725 | 0 | } |
726 | 0 | free_acl_cond(cond); |
727 | 0 | memprintf(err, "out of memory"); |
728 | 0 | return 0; |
729 | 0 | } |
730 | | |
731 | | /* Parses "fcgi-app" section */ |
732 | | static int cfg_parse_fcgi_app(const char *file, int linenum, char **args, int kwm) |
733 | 0 | { |
734 | 0 | static struct fcgi_app *curapp = NULL; |
735 | 0 | struct acl_cond *cond = NULL; |
736 | 0 | char *name, *value = NULL; |
737 | 0 | enum fcgi_rule_type type; |
738 | 0 | int err_code = 0; |
739 | 0 | const char *err; |
740 | 0 | char *errmsg = NULL; |
741 | |
|
742 | 0 | if (strcmp(args[0], "fcgi-app") == 0) { /* new fcgi-app */ |
743 | 0 | if (!*(args[1])) { |
744 | 0 | ha_alert("parsing [%s:%d]: '%s' expects <name> as argument.\n", |
745 | 0 | file, linenum, args[0]); |
746 | 0 | err_code |= ERR_ALERT | ERR_FATAL; |
747 | 0 | goto out; |
748 | 0 | } |
749 | 0 | if (alertif_too_many_args(1, file, linenum, args, &err_code)) |
750 | 0 | goto out; |
751 | | |
752 | 0 | err = invalid_char(args[1]); |
753 | 0 | if (err) { |
754 | 0 | ha_alert("parsing [%s:%d]: character '%c' is not permitted in '%s' name '%s'.\n", |
755 | 0 | file, linenum, *err, args[0], args[1]); |
756 | 0 | err_code |= ERR_ALERT | ERR_FATAL; |
757 | 0 | goto out; |
758 | 0 | } |
759 | | |
760 | 0 | for (curapp = fcgi_apps; curapp != NULL; curapp = curapp->next) { |
761 | 0 | if (strcmp(curapp->name, args[1]) == 0) { |
762 | 0 | ha_alert("Parsing [%s:%d]: fcgi-app section '%s' has the same name as another one declared at %s:%d.\n", |
763 | 0 | file, linenum, args[1], curapp->conf.file, curapp->conf.line); |
764 | 0 | err_code |= ERR_ALERT | ERR_FATAL; |
765 | 0 | } |
766 | 0 | } |
767 | |
|
768 | 0 | curapp = calloc(1, sizeof(*curapp)); |
769 | 0 | if (!curapp) { |
770 | 0 | ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum); |
771 | 0 | err_code |= ERR_ALERT | ERR_ABORT; |
772 | 0 | goto out; |
773 | 0 | } |
774 | | |
775 | 0 | curapp->next = fcgi_apps; |
776 | 0 | fcgi_apps = curapp; |
777 | 0 | curapp->flags = FCGI_APP_FL_KEEP_CONN; |
778 | 0 | curapp->docroot = ist(NULL); |
779 | 0 | curapp->index = ist(NULL); |
780 | 0 | curapp->pathinfo_re = NULL; |
781 | 0 | curapp->name = strdup(args[1]); |
782 | 0 | curapp->maxreqs = 1; |
783 | 0 | curapp->conf.file = strdup(file); |
784 | 0 | curapp->conf.line = linenum; |
785 | 0 | LIST_INIT(&curapp->acls); |
786 | 0 | LIST_INIT(&curapp->loggers); |
787 | 0 | LIST_INIT(&curapp->conf.args.list); |
788 | 0 | LIST_INIT(&curapp->conf.rules); |
789 | | |
790 | | /* Set info about authentication */ |
791 | 0 | if (!fcgi_app_add_rule(curapp, FCGI_RULE_SET_PARAM, "REMOTE_USER", "%[http_auth_user]", NULL, &errmsg) || |
792 | 0 | !fcgi_app_add_rule(curapp, FCGI_RULE_SET_PARAM, "AUTH_TYPE", "%[http_auth_type]", NULL, &errmsg)) { |
793 | 0 | ha_alert("parsing [%s:%d] : '%s' : %s.\n", file, linenum, |
794 | 0 | args[1], errmsg); |
795 | 0 | err_code |= ERR_ALERT | ERR_FATAL; |
796 | 0 | } |
797 | | |
798 | | /* Hide hop-by-hop headers by default */ |
799 | 0 | if (!fcgi_app_add_rule(curapp, FCGI_RULE_HIDE_HDR, "connection", NULL, NULL, &errmsg) || |
800 | 0 | !fcgi_app_add_rule(curapp, FCGI_RULE_HIDE_HDR, "keep-alive", NULL, NULL, &errmsg) || |
801 | 0 | !fcgi_app_add_rule(curapp, FCGI_RULE_HIDE_HDR, "authorization", NULL, NULL, &errmsg) || |
802 | 0 | !fcgi_app_add_rule(curapp, FCGI_RULE_HIDE_HDR, "proxy", NULL, NULL, &errmsg) || |
803 | 0 | !fcgi_app_add_rule(curapp, FCGI_RULE_HIDE_HDR, "proxy-authorization", NULL, NULL, &errmsg) || |
804 | 0 | !fcgi_app_add_rule(curapp, FCGI_RULE_HIDE_HDR, "proxy-authenticate", NULL, NULL, &errmsg) || |
805 | 0 | !fcgi_app_add_rule(curapp, FCGI_RULE_HIDE_HDR, "te", NULL, NULL, &errmsg) || |
806 | 0 | !fcgi_app_add_rule(curapp, FCGI_RULE_HIDE_HDR, "trailers", NULL, NULL, &errmsg) || |
807 | 0 | !fcgi_app_add_rule(curapp, FCGI_RULE_HIDE_HDR, "transfer-encoding", NULL, NULL, &errmsg) || |
808 | 0 | !fcgi_app_add_rule(curapp, FCGI_RULE_HIDE_HDR, "upgrade", NULL, NULL, &errmsg)) { |
809 | 0 | ha_alert("parsing [%s:%d] : '%s' : %s.\n", file, linenum, |
810 | 0 | args[1], errmsg); |
811 | 0 | err_code |= ERR_ALERT | ERR_FATAL; |
812 | 0 | } |
813 | 0 | } |
814 | 0 | else if (strcmp(args[0], "docroot") == 0) { |
815 | 0 | if (!*(args[1])) { |
816 | 0 | ha_alert("parsing [%s:%d] : '%s' expects <path> as argument.\n", |
817 | 0 | file, linenum, args[0]); |
818 | 0 | err_code |= ERR_ALERT | ERR_FATAL; |
819 | 0 | goto out; |
820 | 0 | } |
821 | 0 | if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code)) |
822 | 0 | goto out; |
823 | 0 | istfree(&curapp->docroot); |
824 | 0 | curapp->docroot = ist(strdup(args[1])); |
825 | 0 | if (!isttest(curapp->docroot)) { |
826 | 0 | ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum); |
827 | 0 | err_code |= ERR_ALERT | ERR_ABORT; |
828 | 0 | } |
829 | 0 | } |
830 | 0 | else if (strcmp(args[0], "path-info") == 0) { |
831 | 0 | if (!*(args[1])) { |
832 | 0 | ha_alert("parsing [%s:%d] : '%s' expects <regex> as argument.\n", |
833 | 0 | file, linenum, args[0]); |
834 | 0 | err_code |= ERR_ALERT | ERR_FATAL; |
835 | 0 | goto out; |
836 | 0 | } |
837 | 0 | if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code)) |
838 | 0 | goto out; |
839 | 0 | regex_free(curapp->pathinfo_re); |
840 | 0 | curapp->pathinfo_re = regex_comp(args[1], 1, 1, &errmsg); |
841 | 0 | if (!curapp->pathinfo_re) { |
842 | 0 | ha_alert("parsing [%s:%d] : '%s' : %s.\n", file, linenum, |
843 | 0 | args[1], errmsg); |
844 | 0 | err_code |= ERR_ALERT | ERR_FATAL; |
845 | 0 | } |
846 | 0 | } |
847 | 0 | else if (strcmp(args[0], "index") == 0) { |
848 | 0 | if (!*(args[1])) { |
849 | 0 | ha_alert("parsing [%s:%d] : '%s' expects <filename> as argument.\n", |
850 | 0 | file, linenum, args[0]); |
851 | 0 | err_code |= ERR_ALERT | ERR_FATAL; |
852 | 0 | goto out; |
853 | 0 | } |
854 | 0 | if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code)) |
855 | 0 | goto out; |
856 | 0 | istfree(&curapp->index); |
857 | 0 | curapp->index = ist(strdup(args[1])); |
858 | 0 | if (!isttest(curapp->index)) { |
859 | 0 | ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum); |
860 | 0 | err_code |= ERR_ALERT | ERR_ABORT; |
861 | 0 | } |
862 | 0 | } |
863 | 0 | else if (strcmp(args[0], "acl") == 0) { |
864 | 0 | const char *err; |
865 | 0 | err = invalid_char(args[1]); |
866 | 0 | if (err) { |
867 | 0 | ha_alert("parsing [%s:%d] : character '%c' is not permitted in acl name '%s'.\n", |
868 | 0 | file, linenum, *err, args[1]); |
869 | 0 | err_code |= ERR_ALERT | ERR_FATAL; |
870 | 0 | goto out; |
871 | 0 | } |
872 | 0 | if (strcasecmp(args[1], "or") == 0) { |
873 | 0 | ha_alert("parsing [%s:%d] : acl name '%s' will never match. 'or' is used to express a " |
874 | 0 | "logical disjunction within a condition.\n", |
875 | 0 | file, linenum, args[1]); |
876 | 0 | err_code |= ERR_ALERT | ERR_FATAL; |
877 | 0 | goto out; |
878 | 0 | } |
879 | 0 | if (parse_acl((const char **)args+1, &curapp->acls, &errmsg, &curapp->conf.args, file, linenum) == NULL) { |
880 | 0 | ha_alert("parsing [%s:%d] : error detected while parsing ACL '%s' : %s.\n", |
881 | 0 | file, linenum, args[1], errmsg); |
882 | 0 | err_code |= ERR_ALERT | ERR_FATAL; |
883 | 0 | goto out; |
884 | 0 | } |
885 | 0 | } |
886 | 0 | else if (strcmp(args[0], "set-param") == 0) { |
887 | 0 | if (!*(args[1]) || !*(args[2])) { |
888 | 0 | ha_alert("parsing [%s:%d] : '%s' expects <name> and <value> as arguments.\n", |
889 | 0 | file, linenum, args[0]); |
890 | 0 | err_code |= ERR_ALERT | ERR_FATAL; |
891 | 0 | goto out; |
892 | 0 | } |
893 | 0 | type = FCGI_RULE_SET_PARAM; |
894 | 0 | name = args[1]; |
895 | 0 | value = args[2]; |
896 | 0 | cond = NULL; |
897 | 0 | args += 3; |
898 | |
|
899 | 0 | parse_cond_rule: |
900 | 0 | if (!*(args[0])) /* No condition */ |
901 | 0 | goto add_rule; |
902 | | |
903 | 0 | if (strcmp(args[0], "if") == 0) |
904 | 0 | cond = parse_acl_cond((const char **)args+1, &curapp->acls, ACL_COND_IF, &errmsg, &curapp->conf.args, |
905 | 0 | file, linenum); |
906 | 0 | else if (strcmp(args[0], "unless") == 0) |
907 | 0 | cond = parse_acl_cond((const char **)args+1, &curapp->acls, ACL_COND_UNLESS, &errmsg, &curapp->conf.args, |
908 | 0 | file, linenum); |
909 | 0 | if (!cond) { |
910 | 0 | ha_alert("parsing [%s:%d] : '%s' : %s.\n", file, linenum, |
911 | 0 | name, errmsg); |
912 | 0 | err_code |= ERR_ALERT | ERR_FATAL; |
913 | 0 | } |
914 | 0 | add_rule: |
915 | 0 | if (!fcgi_app_add_rule(curapp, type, name, value, cond, &errmsg)) { |
916 | 0 | ha_alert("parsing [%s:%d] : '%s' : %s.\n", file, linenum, |
917 | 0 | name, errmsg); |
918 | 0 | err_code |= ERR_ALERT | ERR_FATAL; |
919 | 0 | } |
920 | 0 | } |
921 | | #if 0 /* Disabled for now */ |
922 | | else if (!strcmp(args[0], "unset-param")) { |
923 | | if (!*(args[1])) { |
924 | | ha_alert("parsing [%s:%d] : '%s' expects <name> as arguments.\n", |
925 | | file, linenum, args[0]); |
926 | | err_code |= ERR_ALERT | ERR_FATAL; |
927 | | goto out; |
928 | | } |
929 | | type = FCGI_RULE_UNSET_PARAM; |
930 | | name = args[1]; |
931 | | value = NULL; |
932 | | cond = NULL; |
933 | | args += 2; |
934 | | goto parse_cond_rule; |
935 | | } |
936 | | #endif |
937 | 0 | else if (strcmp(args[0], "pass-header") == 0) { |
938 | 0 | if (!*(args[1])) { |
939 | 0 | ha_alert("parsing [%s:%d] : '%s' expects <name> as arguments.\n", |
940 | 0 | file, linenum, args[0]); |
941 | 0 | err_code |= ERR_ALERT | ERR_FATAL; |
942 | 0 | goto out; |
943 | 0 | } |
944 | 0 | type = FCGI_RULE_PASS_HDR; |
945 | 0 | name = args[1]; |
946 | 0 | value = NULL; |
947 | 0 | cond = NULL; |
948 | 0 | args += 2; |
949 | 0 | goto parse_cond_rule; |
950 | 0 | } |
951 | | #if 0 /* Disabled for now */ |
952 | | else if (!strcmp(args[0], "hide-header")) { |
953 | | if (!*(args[1])) { |
954 | | ha_alert("parsing [%s:%d] : '%s' expects <name> as arguments.\n", |
955 | | file, linenum, args[0]); |
956 | | err_code |= ERR_ALERT | ERR_FATAL; |
957 | | goto out; |
958 | | } |
959 | | type = FCGI_RULE_HIDE_HDR; |
960 | | name = args[1]; |
961 | | value = NULL; |
962 | | cond = NULL; |
963 | | args += 2; |
964 | | goto parse_cond_rule; |
965 | | } |
966 | | #endif |
967 | 0 | else if (strcmp(args[0], "option") == 0) { |
968 | 0 | if (!*(args[1])) { |
969 | 0 | ha_alert("parsing [%s:%d]: '%s' expects an option name.\n", |
970 | 0 | file, linenum, args[0]); |
971 | 0 | err_code |= ERR_ALERT | ERR_FATAL; |
972 | 0 | } |
973 | 0 | else if (strcmp(args[1], "keep-conn") == 0) { |
974 | 0 | if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code)) |
975 | 0 | goto out; |
976 | 0 | if (kwm == KWM_STD) |
977 | 0 | curapp->flags |= FCGI_APP_FL_KEEP_CONN; |
978 | 0 | else if (kwm == KWM_NO) |
979 | 0 | curapp->flags &= ~FCGI_APP_FL_KEEP_CONN; |
980 | 0 | } |
981 | 0 | else if (strcmp(args[1], "get-values") == 0) { |
982 | 0 | if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code)) |
983 | 0 | goto out; |
984 | 0 | if (kwm == KWM_STD) |
985 | 0 | curapp->flags |= FCGI_APP_FL_GET_VALUES; |
986 | 0 | else if (kwm == KWM_NO) |
987 | 0 | curapp->flags &= ~FCGI_APP_FL_GET_VALUES; |
988 | 0 | } |
989 | 0 | else if (strcmp(args[1], "mpxs-conns") == 0) { |
990 | 0 | if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code)) |
991 | 0 | goto out; |
992 | 0 | if (kwm == KWM_STD) |
993 | 0 | curapp->flags |= FCGI_APP_FL_MPXS_CONNS; |
994 | 0 | else if (kwm == KWM_NO) |
995 | 0 | curapp->flags &= ~FCGI_APP_FL_MPXS_CONNS; |
996 | 0 | } |
997 | 0 | else if (strcmp(args[1], "max-reqs") == 0) { |
998 | 0 | if (kwm != KWM_STD) { |
999 | 0 | ha_alert("parsing [%s:%d]: negation/default is not supported for option '%s'.\n", |
1000 | 0 | file, linenum, args[1]); |
1001 | 0 | err_code |= ERR_ALERT | ERR_FATAL; |
1002 | 0 | goto out; |
1003 | 0 | } |
1004 | 0 | if (!*(args[2])) { |
1005 | 0 | ha_alert("parsing [%s:%d]: option '%s' expects an integer argument.\n", |
1006 | 0 | file, linenum, args[1]); |
1007 | 0 | err_code |= ERR_ALERT | ERR_FATAL; |
1008 | 0 | goto out; |
1009 | 0 | } |
1010 | 0 | if (alertif_too_many_args_idx(1, 1, file, linenum, args, &err_code)) |
1011 | 0 | goto out; |
1012 | | |
1013 | 0 | curapp->maxreqs = atol(args[2]); |
1014 | 0 | if (!curapp->maxreqs) { |
1015 | 0 | ha_alert("parsing [%s:%d]: option '%s' expects a strictly positive integer argument.\n", |
1016 | 0 | file, linenum, args[1]); |
1017 | 0 | err_code |= ERR_ALERT | ERR_FATAL; |
1018 | 0 | goto out; |
1019 | 0 | } |
1020 | 0 | } |
1021 | 0 | else { |
1022 | 0 | ha_alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]); |
1023 | 0 | err_code |= ERR_ALERT | ERR_FATAL; |
1024 | 0 | } |
1025 | 0 | } |
1026 | 0 | else if (strcmp(args[0], "log-stderr") == 0) { |
1027 | 0 | if (!parse_logger(args, &curapp->loggers, (kwm == KWM_NO), file, linenum, &errmsg)) { |
1028 | 0 | ha_alert("parsing [%s:%d] : %s : %s\n", file, linenum, args[0], errmsg); |
1029 | 0 | err_code |= ERR_ALERT | ERR_FATAL; |
1030 | 0 | } |
1031 | 0 | } |
1032 | 0 | else { |
1033 | 0 | ha_alert("parsing [%s:%d]: unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "fcgi-app"); |
1034 | 0 | err_code |= ERR_ALERT | ERR_FATAL; |
1035 | 0 | } |
1036 | | |
1037 | 0 | out: |
1038 | 0 | free(errmsg); |
1039 | 0 | return err_code; |
1040 | 0 | } |
1041 | | |
1042 | | |
1043 | | /**************************************************************************/ |
1044 | | /*********************** FCGI Deinit functions ****************************/ |
1045 | | /**************************************************************************/ |
1046 | | void fcgi_apps_deinit() |
1047 | 0 | { |
1048 | 0 | struct fcgi_app *curapp, *nextapp; |
1049 | 0 | struct logger *log, *logb; |
1050 | |
|
1051 | 0 | for (curapp = fcgi_apps; curapp != NULL; curapp = nextapp) { |
1052 | 0 | struct fcgi_rule_conf *rule, *back; |
1053 | |
|
1054 | 0 | free(curapp->name); |
1055 | 0 | istfree(&curapp->docroot); |
1056 | 0 | istfree(&curapp->index); |
1057 | 0 | regex_free(curapp->pathinfo_re); |
1058 | 0 | free(curapp->conf.file); |
1059 | |
|
1060 | 0 | list_for_each_entry_safe(log, logb, &curapp->loggers, list) { |
1061 | 0 | LIST_DELETE(&log->list); |
1062 | 0 | free(log); |
1063 | 0 | } |
1064 | |
|
1065 | 0 | list_for_each_entry_safe(rule, back, &curapp->conf.rules, list) { |
1066 | 0 | LIST_DELETE(&rule->list); |
1067 | 0 | fcgi_release_rule_conf(rule); |
1068 | 0 | } |
1069 | |
|
1070 | 0 | nextapp = curapp->next; |
1071 | 0 | free(curapp); |
1072 | 0 | } |
1073 | 0 | } |
1074 | | |
1075 | | |
1076 | | /**************************************************************************/ |
1077 | | /*************** Keywords definition and registration *********************/ |
1078 | | /**************************************************************************/ |
1079 | | static struct cfg_kw_list cfg_kws = {ILH, { |
1080 | | { CFG_LISTEN, "use-fcgi-app", proxy_parse_use_fcgi_app }, |
1081 | | { 0, NULL, NULL }, |
1082 | | }}; |
1083 | | |
1084 | | // FIXME: Add rep.fcgi smp_fetch |
1085 | | static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, { |
1086 | | { "fcgi.docroot", smp_fetch_fcgi_docroot, 0, NULL, SMP_T_STR, SMP_USE_HRQHV }, |
1087 | | { "fcgi.index", smp_fetch_fcgi_index, 0, NULL, SMP_T_STR, SMP_USE_HRQHV }, |
1088 | | { /* END */ } |
1089 | | }}; |
1090 | | |
1091 | | /* Declare the filter parser for "fcgi-app" keyword */ |
1092 | | static struct flt_kw_list filter_kws = { "FCGI", { }, { |
1093 | | { "fcgi-app", parse_fcgi_flt, NULL }, |
1094 | | { NULL, NULL, NULL }, |
1095 | | } |
1096 | | }; |
1097 | | |
1098 | | INITCALL1(STG_REGISTER, sample_register_fetches, &sample_fetch_keywords); |
1099 | | INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws); |
1100 | | INITCALL1(STG_REGISTER, flt_register_keywords, &filter_kws); |
1101 | | |
1102 | | INITCALL1(STG_REGISTER, hap_register_post_deinit, fcgi_apps_deinit); |
1103 | | |
1104 | | REGISTER_CONFIG_SECTION("fcgi-app", cfg_parse_fcgi_app, NULL); |
1105 | | REGISTER_CONFIG_POSTPARSER("fcgi-apps", cfg_fcgi_apps_postparser); |
1106 | | |
1107 | | /* |
1108 | | * Local variables: |
1109 | | * c-indent-level: 8 |
1110 | | * c-basic-offset: 8 |
1111 | | * End: |
1112 | | */ |