Download raw body.
httpd: do NOT send location fcgiparams twice
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 <rafael@sizeofvoid.org>
> > 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 <rafael@sizeofvoid.org>
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);
httpd: do NOT send location fcgiparams twice