summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWilliam Lallemand <wlallemand@haproxy.org>2021-11-08 16:55:14 +0100
committerWilliam Lallemand <wlallemand@haproxy.org>2021-11-08 17:36:31 +0100
commitdb8a1f391dbbf1072f76bdb01d86d4032b84e6ac (patch)
tree2f661b2c1674469ad5dbbb39972deb7e176123a0
parent933fe394bb11490d45fd231b43b7cd93a0cf21e4 (diff)
downloadhaproxy-httpclient-lua-2021-11-08.tar.gz
BUG/MEDIUM: httpclient: channel_add_input() must use htx->datahaproxy-httpclient-lua-2021-11-08
The httpclient uses channel_add_input() to notify the channel layer that it must forward some data. This function was used with b_data(&req->buf) which ask to send the size of a buffer (because of the HTX metadata which fill the buffer completely). This is wrong and will have the consequence of trying to send data that doesn't exist, letting HAProxy looping at 100% CPU. When using htx channel_add_input() must be used with the size of the htx payload, and not the size of a buffer. When sending the request payload it also need to sets the buffer size to 0, which is achieved with a htx_to_buf() when the htx payload is empty.
-rw-r--r--src/http_client.c38
1 files changed, 27 insertions, 11 deletions
diff --git a/src/http_client.c b/src/http_client.c
index a289206eb..fe85f050b 100644
--- a/src/http_client.c
+++ b/src/http_client.c
@@ -569,17 +569,19 @@ static void httpclient_applet_io_handler(struct appctx *appctx)
switch(appctx->st0) {
case HTTPCLIENT_S_REQ:
- /* copy the request from the hc->req.buf buffer */
- /* We now that it fits the content of a buffer so can
- * just push this entirely */
+ /* we know that the buffer is empty here, since
+ * it's the first call, we can freely copy the
+ * request from the httpclient buffer */
ret = b_xfer(&req->buf, &hc->req.buf, b_data(&hc->req.buf));
- if (ret)
- channel_add_input(req, b_data(&req->buf));
+ if (!ret)
+ goto more;
- htx = htxbuf(&req->buf);
+ htx = htx_from_buf(&req->buf);
if (!htx)
goto more;
+ channel_add_input(req, htx->data);
+
if (htx->flags & HTX_FL_EOM) /* check if a body need to be added */
appctx->st0 = HTTPCLIENT_S_RES_STLINE;
else
@@ -592,15 +594,29 @@ static void httpclient_applet_io_handler(struct appctx *appctx)
{
if (hc->ops.req_payload) {
- ret = b_xfer(&req->buf, &hc->req.buf, b_data(&hc->req.buf));
- if (ret)
- channel_add_input(req, b_data(&req->buf));
-
/* call the request callback */
hc->ops.req_payload(hc);
+ /* check if the request buffer is empty */
+
+ htx = htx_from_buf(&req->buf);
+ if (!htx_is_empty(htx))
+ goto more;
+ /* Here htx_to_buf() will set buffer data to 0 because
+ * the HTX is empty, and allow us to do an xfer.
+ */
+ htx_to_buf(htx, &req->buf);
+
+ ret = b_xfer(&req->buf, &hc->req.buf, b_data(&hc->req.buf));
+ if (!ret)
+ goto more;
+ htx = htx_from_buf(&req->buf);
+ if (!htx)
+ goto more;
+
+ channel_add_input(req, htx->data);
}
- htx = htxbuf(&req->buf);
+ htx = htx_from_buf(&req->buf);
if (!htx)
goto more;