From: Christopher Faulet Date: Wed, 16 Sep 2026 07:19:46 +0000 (+0200) Subject: MINOR: http-client: Add a function to notify some data were consumed X-Git-Tag: v3.5-dev8~183 X-Git-Url: https://git.kaiwu.me/?a=commitdiff_plain;h=0d727e82c4805fcb3d43742a48901cd500c05aa1;p=haproxy.git MINOR: http-client: Add a function to notify some data were consumed Since commit b24260ec9 ("BUG/MEDIUM: http-client: Only consume input buffer when hc one is empty"), the http-client applet stops to consume data as soon as its response buffer is not empty. Only httpclient_res_xfer() is able to unblock it. However, some callers are directly accessing the httpclient response buffer. These ones have no way to notify the applet it can fill the response buffer again. httpclient_res_consumed() is added to do so and is now called from httpclient_res_xfer(). In addition, the applet is no longer only woken up when the response buffer is emptied, but as soon as some room was released. Because the response buffer is no longer necessarily released when data are consumed, the I/O handler must now rely on b_data() instead of b_is_null() to decide to stop the reception. Otherwise, an emptied but still allocated buffer would block the applet for good. This patch is required to fix a bug and must be backported as far as 3.3 with the next commit. --- diff --git a/include/haproxy/http_client.h b/include/haproxy/http_client.h index 41ea4bb80..2eee0496c 100644 --- a/include/haproxy/http_client.h +++ b/include/haproxy/http_client.h @@ -16,6 +16,7 @@ struct appctx *httpclient_start(struct httpclient *hc); int httpclient_set_dst(struct httpclient *hc, const char *dst); void httpclient_set_timeout(struct httpclient *hc, int timeout); int httpclient_res_xfer(struct httpclient *hc, struct buffer *dst); +void httpclient_res_consumed(struct httpclient *hc); int httpclient_req_gen(struct httpclient *hc, const struct ist url, enum http_meth_t meth, const struct http_hdr *hdrs, const struct ist payload); int httpclient_req_xfer(struct httpclient *hc, struct ist src, int end); diff --git a/src/http_client.c b/src/http_client.c index d97ec0e30..b4a945e1f 100644 --- a/src/http_client.c +++ b/src/http_client.c @@ -178,6 +178,20 @@ error: return err_code; } +/* + * Must be called by the caller when it has consumed data from the httpclient + * response buffer, to let the applet fill it again. It is automatically called + * by httpclient_res_xfer(). Callers accessing res.buf> by hand must call it + * by themselves. + */ +void httpclient_res_consumed(struct httpclient *hc) +{ + if (hc->appctx) { + applet_will_consume(hc->appctx); + appctx_wakeup(hc->appctx); + } +} + /* * transfer the response to the destination buffer and wakeup the HTTP client * applet so it could fill again its buffer. @@ -191,14 +205,15 @@ int httpclient_res_xfer(struct httpclient *hc, struct buffer *dst) ret = b_force_xfer(dst, &hc->res.buf, MIN(room, b_data(&hc->res.buf))); - /* call the client once we consumed all data */ - if (!b_data(&hc->res.buf)) { + if (!b_data(&hc->res.buf)) b_free(&hc->res.buf); - if (ret && hc->appctx) { - applet_will_consume(hc->appctx); - appctx_wakeup(hc->appctx); - } - } + + /* Some room was released in the response buffer. Notify the applet it + * can fill it again. + */ + if (ret) + httpclient_res_consumed(hc); + return ret; } @@ -880,7 +895,7 @@ void httpclient_applet_io_handler(struct appctx *appctx) out: if (hc && appctx->st0 != HTTPCLIENT_S_RES_END && - !(hc->options & HTTPCLIENT_O_RES_ACCUM) && !b_is_null(&hc->res.buf)) { + !(hc->options & HTTPCLIENT_O_RES_ACCUM) && b_data(&hc->res.buf)) { /* Don't accept more data while the httpclient response buffer is * not empty. It will be re-enabled by the caller, when it will * consume these data.