From: Christopher Faulet Date: Wed, 22 Mar 2023 08:30:40 +0000 (+0100) Subject: BUG/MEDIUM: stats: Consume the request except when parsing the POST payload X-Git-Tag: v2.8-dev6~7 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c2c043ed4;p=thirdparty%2Fhaproxy.git BUG/MEDIUM: stats: Consume the request except when parsing the POST payload The stats applet is designed to consume the request at the end, when it finishes to send the response. And during the response forwarding, because the request is not consumed, the applet states it will not consume data. This avoid to wake the applet up in loop. When it finishes to send the response, the request is consumed. For POST requests, there is no issue because the response is small enough. It is sent in one time and must be processed by HTTP analyzers. Thus the forwarding is not performed by the applet itself. The applet is always able to consume the request, regardless the payload length. But for other requests, it may be an issue. If the response is too big to be sent in one time and if the requests is not fully received when the response headers are sent, the applet may be blocked infinitely, not consuming the request. Indeed, in the case the applet will be switched in infinite forward mode, the request will not be consumed immediately. At the end, the request buffer is flushed. But if some data must still be received, the applet is not woken up because it is still in a "not-consuming" mode. So, to fix the issue, we must take care to re-enable data consuming when the end of the response is reached. This patch must be backported as far as 2.6. --- diff --git a/src/stats.c b/src/stats.c index d9bb367f7d..edee3aaf5e 100644 --- a/src/stats.c +++ b/src/stats.c @@ -4506,15 +4506,8 @@ static void http_stats_io_handler(struct appctx *appctx) } if (appctx->st0 == STAT_HTTP_END) { - if (!(res->flags & CF_SHUTR)) - sc_shutr(sc); - - /* eat the whole request */ - if (co_data(req)) { - req_htx = htx_from_buf(&req->buf); - co_htx_skip(req, req_htx, co_data(req)); - htx_to_buf(req_htx, &req->buf); - } + se_fl_set(appctx->sedesc, SE_FL_EOS); + applet_will_consume(appctx); } out: @@ -4526,7 +4519,15 @@ static void http_stats_io_handler(struct appctx *appctx) * emitting large blocks into small TCP windows. */ htx_to_buf(res_htx, &res->buf); - if (!channel_is_empty(res)) + if (appctx->st0 == STAT_HTTP_END) { + /* eat the whole request */ + if (co_data(req)) { + req_htx = htx_from_buf(&req->buf); + co_htx_skip(req, req_htx, co_data(req)); + htx_to_buf(req_htx, &req->buf); + } + } + else if (!channel_is_empty(res)) applet_wont_consume(appctx); }