]> git.kaiwu.me - haproxy.git/commitdiff
MINOR: http-client: Add a function to notify some data were consumed
authorChristopher Faulet <cfaulet@haproxy.com>
Wed, 16 Sep 2026 07:19:46 +0000 (09:19 +0200)
committerChristopher Faulet <cfaulet@haproxy.com>
Fri, 18 Sep 2026 14:50:30 +0000 (16:50 +0200)
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.

include/haproxy/http_client.h
src/http_client.c

index 41ea4bb807a485d2c06bd0f60336b6292d557cf4..2eee0496caac94ebba6aad2660fc74414b500105 100644 (file)
@@ -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);
 
index d97ec0e30f2bf08d62bcad25cb5e18c748a8e44d..b4a945e1f5f3ec8fd9e0238b08fa5506b85ef730 100644 (file)
@@ -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 <hc->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.