From: Rafael Sadowski Subject: Re: httpd: do NOT send location fcgiparams twice To: Fabien Romano Cc: tech@openbsd.org Date: Mon, 13 Jul 2026 21:44:51 +0200 On Mon Jul 13, 2026 at 06:29:09PM +0100, Fabien Romano wrote: > > > On 7/13/26 12:55, Rafael Sadowski wrote: > > While working on the custom headers, I'm noticing more and more issues > > in fcgiparams (since I used that as a template). > > > > server "fcgi-test" { > > listen on 127.0.0.1 port 8089 > > root "/htdocs" > > > > location "*.cgi" { > > fastcgi { > > socket "/run/slowcgi.sock" > > param FCGI_TEST_A "A" > > param FCGI_TEST_B "B" > > param FCGI_TEST_C "C" > > param FCGI_TEST_D "D" > > param FCGI_TEST_E "E" > > } > > } > > } > > > > curl -s http://127.0.0.1:8089/env.cgi > > FCGI_TEST_E=E > > FCGI_TEST_D=D > > FCGI_TEST_C=C > > FCGI_TEST_B=B > > FCGI_TEST_A=A > > FCGI_TEST_E=E > > FCGI_TEST_D=D > > FCGI_TEST_C=C > > FCGI_TEST_B=B > > FCGI_TEST_A=A > > > > Yes, the order is reversed. we can fix it in a different commit. > > > > OK? > > config_setserver_fcgiparams() always sends imsg to PROC_SERVER: > if (proc_composev(ps, PROC_SERVER, IMSG_CFG_FCGI, iov, c) != 0) > > But is called inside proc loop: > for (id = 0; id < PROC_MAX; id++) { > ... > if (id == PROC_SERVER && > (srv->srv_conf.flags & SRVFLAG_LOCATION) == 0) { > ... > /* Configure TLS if necessary. */ > config_setserver_tls(env, srv); > } else { > ... > /* Configure FCGI parameters if necessary. */ > config_setserver_fcgiparams(env, srv); > } > } > > The same applies to config_setserver_tls() > config_settls(): > if (proc_composev(ps, PROC_SERVER, IMSG_CFG_TLS, iov, c) != 0) > > Thus, I think the correct fix is to move those two outside the loop. > And while there, check the return value. > > > commit 603108536a8ef506d76179d9d4007d1038b50eee > > Author: Rafael Sadowski > > Date: Mon Jul 13 13:33:34 2026 +0200 > > > > httpd: do NOT send location fcgiparams twice > > > > Only emit the params when the current receiver is the server child. > > > > When sending a location-config from the parent, the FCGI params IMSG > > was emitted once per receiver iteration and always targeted the server > > child. With both the server and the logger process needing the server > > config, the server child received IMSG_CFG_FCGI twice per location and > > appended the same params on top of the existing list. The FastCGI backends > > then saw every param duplicated. > > > > diff --git a/config.c b/config.c > > index 146ed2c..6522a4b 100644 > > --- a/config.c > > +++ b/config.c > > @@ -281,7 +281,8 @@ config_setserver(struct httpd *env, struct server *srv) > > } > > > > /* Configure FCGI parameters if necessary. */ > > - config_setserver_fcgiparams(env, srv); > > + if (id == PROC_SERVER) > > + config_setserver_fcgiparams(env, srv); > > } > > } > > > > > > Index: config.c > =================================================================== > RCS file: /mnt/ext/cvs/src/usr.sbin/httpd/config.c,v > diff -u -p -r1.72 config.c > --- config.c 17 May 2026 10:56:41 -0000 1.72 > +++ config.c 13 Jul 2026 17:23:18 -0000 > @@ -268,9 +268,6 @@ config_setserver(struct httpd *env, stru > return (-1); > } > } > - > - /* Configure TLS if necessary. */ > - config_setserver_tls(env, srv); > } else { > if (proc_composev(ps, id, IMSG_CFG_SERVER, > iov, c) != 0) { > @@ -279,10 +276,17 @@ config_setserver(struct httpd *env, stru > __func__, srv->srv_conf.name); > return (-1); > } > - > - /* Configure FCGI parameters if necessary. */ > - config_setserver_fcgiparams(env, srv); > } > + } > + > + if ((srv->srv_conf.flags & SRVFLAG_LOCATION) == 0) { > + /* Configure TLS if necessary. */ > + if (config_setserver_tls(env, srv) != 0) > + return (-1); > + } else { > + /* Configure FCGI parameters if necessary. */ > + if (config_setserver_fcgiparams(env, srv) != 0) > + return (-1); > } > > /* Close server socket early to prevent fd exhaustion in the parent. */ > Thanks Fabien I like it, Yes these are per-server messages, so they belong outside the receiver loop. One change to your diff: fcgiparams runs unconditionally, not as the else of the LOCATION check. "fastcgi ... param" is also valid at server scope and would otherwise be dropped. You can verify it with: server "fcgi-test" { listen on 127.0.0.1 port 8089 root "/htdocs" fastcgi { socket "/run/slowcgi.sock" param FCGI_TEST_A "A" } } OK? commit 87c270a68ae2c43d388a2c65f08c83e73a0d905d Author: Rafael Sadowski Date: Mon Jul 13 13:33:34 2026 +0200 httpd: send TLS and fcgiparams config once per server Both calls target the server child but were made inside the loop over all config receivers, so the server child received the FCGI params twice per location and the backends saw every param duplicated. Move them after the loop and check the return values. idea suggested by Fabien Romano diff --git a/config.c b/config.c index 146ed2c..c2062a3 100644 --- a/config.c +++ b/config.c @@ -268,9 +268,6 @@ config_setserver(struct httpd *env, struct server *srv) return (-1); } } - - /* Configure TLS if necessary. */ - config_setserver_tls(env, srv); } else { if (proc_composev(ps, id, IMSG_CFG_SERVER, iov, c) != 0) { @@ -279,12 +276,19 @@ config_setserver(struct httpd *env, struct server *srv) __func__, srv->srv_conf.name); return (-1); } - - /* Configure FCGI parameters if necessary. */ - config_setserver_fcgiparams(env, srv); } } + if ((srv->srv_conf.flags & SRVFLAG_LOCATION) == 0) { + /* Configure TLS if necessary. */ + if (config_setserver_tls(env, srv) != 0) + return (-1); + } + + /* Configure FCGI parameters if necessary. */ + if (config_setserver_fcgiparams(env, srv) != 0) + return (-1); + /* Close server socket early to prevent fd exhaustion in the parent. */ if (srv->srv_s != -1) { close(srv->srv_s);