From: Christopher Faulet Date: Wed, 6 Sep 2023 06:59:33 +0000 (+0200) Subject: BUG/MEDIUM: stconn/stream: Forward shutdown on write timeout X-Git-Tag: v2.9-dev5~41 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b9c87f8082;p=thirdparty%2Fhaproxy.git BUG/MEDIUM: stconn/stream: Forward shutdown on write timeout The commit 7f59d68fe2 ("BUG/MEDIIM: stconn: Flush output data before forwarding close to write side") introduced a regression. When a write timeout is detected, the shutdown is no longer forwarded. Dependig on the channels state, it may block the processing, waiting the client or the server leaves. The commit above tries to avoid to truncate messages on shutdown but on write timeout, if the channel is not empty, there is nothing more we can do to send these data. It means the endpoint is unable to send data. In this case, we must forward the shutdown. This patch should be backported as far as 2.2. --- diff --git a/src/stconn.c b/src/stconn.c index 27544645c4..273a1d894e 100644 --- a/src/stconn.c +++ b/src/stconn.c @@ -512,6 +512,10 @@ struct appctx *sc_applet_create(struct stconn *sc, struct applet *app) */ static inline int sc_cond_forward_shut(struct stconn *sc) { + /* Foward the shutdown if an write error occurred on the input channel */ + if (sc_ic(sc)->flags & CF_WRITE_TIMEOUT) + return 1; + /* The close must not be forwarded */ if (!(sc->flags & (SC_FL_EOS|SC_FL_ABRT_DONE)) || !(sc->flags & SC_FL_NOHALF)) return 0; diff --git a/src/stream.c b/src/stream.c index 00a6c07b78..45b0c56d98 100644 --- a/src/stream.c +++ b/src/stream.c @@ -2378,7 +2378,7 @@ struct task *process_stream(struct task *t, void *context, unsigned int state) /* shutdown(write) pending */ if (unlikely((scb->flags & (SC_FL_SHUT_DONE|SC_FL_SHUT_WANTED)) == SC_FL_SHUT_WANTED && - channel_is_empty(req))) { + (channel_is_empty(req) || (req->flags & CF_WRITE_TIMEOUT)))) { if (scf->flags & SC_FL_ERROR) scb->flags |= SC_FL_NOLINGER; sc_shutdown(scb); @@ -2502,7 +2502,7 @@ struct task *process_stream(struct task *t, void *context, unsigned int state) /* shutdown(write) pending */ if (unlikely((scf->flags & (SC_FL_SHUT_DONE|SC_FL_SHUT_WANTED)) == SC_FL_SHUT_WANTED && - channel_is_empty(res))) { + (channel_is_empty(res) || (res->flags & CF_WRITE_TIMEOUT)))) { sc_shutdown(scf); }