From: Willy Tarreau Date: Fri, 12 Jan 2018 09:42:12 +0000 (+0100) Subject: BUG/MEDIUM: stream: properly handle client aborts during redispatch X-Git-Tag: v1.9-dev1~519 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d651ba14d44a7350b4506e9de7c7b44cc18a6bff;p=thirdparty%2Fhaproxy.git BUG/MEDIUM: stream: properly handle client aborts during redispatch James Mc Bride reported an interesting case affecting all versions since at least 1.5 : if a client aborts a connection on an empty buffer at the exact moment a server redispatch happens, the CF_SHUTW_NOW flag on the channel is immediately turned into CF_SHUTW, which is not caught by check_req_may_abort(), leading the redispatch to be performed anyway with the channel marked as shut in both directions while the stream interface correctly establishes. This situation makes no sense. Ultimately the transfer times out and the server-side stream interface remains in EST state while the client is in CLO state, and this case doesn't correspond to anything we can handle in process_stream, leading to poll() being woken up all the time without any progress being made. And the session cannot even be killed from the CLI. So we must ensure that check_req_may_abort() also considers the case where the channel is already closed, which is what this patch does. Thanks to James for providing detailed captures allowing to diagnose the problem. This fix must be backported to all maintained versions. --- diff --git a/src/stream.c b/src/stream.c index 39ee9ba558..60d3eff44c 100644 --- a/src/stream.c +++ b/src/stream.c @@ -833,7 +833,7 @@ static void sess_establish(struct stream *s) static int check_req_may_abort(struct channel *req, struct stream *s) { return ((req->flags & (CF_READ_ERROR)) || - ((req->flags & CF_SHUTW_NOW) && /* empty and client aborted */ + ((req->flags & (CF_SHUTW_NOW|CF_SHUTW)) && /* empty and client aborted */ (channel_is_empty(req) || ((s->be->options & PR_O_ABRT_CLOSE) && !(s->si[0].flags & SI_FL_CLEAN_ABRT))))); }