BUG/MEDIUM: mux-fcgi: arm the connection timeout only when data remains
The commit "BUG/MEDIUM: mux-fcgi: do not enforce the timeout on connections
with streams" made the connection timeout inactive while stream connectors
are attached, since the stream layer is then responsible for timeouts. It
has to become active again once the last stream detaches, which detach()
does not do in all cases: when the stream is blocked waiting for room in the
mux buffer, the function returns early without touching the timeout, and
when the connection is moved to an idle list, it returns before the refresh
at the end of the function.
In both cases the connection stays without any timeout. When a client aborts
a large POST to a FastCGI server that does not read it, the connection with
its full mux buffer is put in the server's idle list and is only closed
later by the purge of the idle connections, instead of after "timeout
server".
Arming "timeout server" on every connection without a stream is wrong
though: a connection with nothing left to send is idle and reusable, and
belongs to the idle connection pool for its lifetime. Arming the server
timeout there closes it while it sits in the idle list, defeating connection
reuse, unlike idle backend H1 and H2 connections which are left without a
mux timeout.
So the update is moved to fcgi_conn_update_timeout(), which now tells the
cases apart, and is called once right after the stream is destroyed, before
the connection may be moved to an idle list. The refresh that used to sit at
the end of the function is dropped: everything between the two points only
manipulates session and idle lists, so the second call recomputed the very
same expiration date.
- streams attached: no connection timeout, the stream layer knows
whether it waits for the server or for the client;
- nothing attached, but data pending in the mux buffer or streams still
queued in the send list (blocked on a missing mux buffer, their bytes
still in their own buffer): the regular data timeout, so that the
data gets a chance to be drained and the connection closed after it;
- nothing attached, nothing to send, connection closing: the shutdown
timeout, otherwise nothing would close it;
- nothing attached, nothing to send, connection alive: no timeout, it
is an idle connection.
tick_add_ifset() replaces tick_add() so an unset timeout cannot arm an
already expired timer.
It is related to GitHub issue #3558 and should be backported along with the
mentionned commit to all supported versions.