From c8f1eb99b4004444c7674d48d967ea3040a62d6e Mon Sep 17 00:00:00 2001 From: William Lallemand Date: Wed, 9 Mar 2022 11:58:51 +0100 Subject: [PATCH] BUG/MINOR: httpclient: consume partly the blocks when necessary Consume partly the blocks in the httpclient I/O handler when there is not enough room in the destination buffer for the whole block or when the block is not contained entirely in the channel's output. It prevents the I/O handler to be stuck in cases when we need to modify the buffer with a filter for exemple. Must be backported in 2.5. --- src/http_client.c | 42 ++++++++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/src/http_client.c b/src/http_client.c index ad3c40c3c..f17e805e6 100644 --- a/src/http_client.c +++ b/src/http_client.c @@ -849,40 +849,54 @@ static void httpclient_applet_io_handler(struct appctx *appctx) /* decapsule the htx data to raw data */ for (pos = htx_get_first(htx); pos != -1; pos = htx_get_next(htx, pos)) { - enum htx_blk_type type; - uint32_t sz; + struct htx_blk *blk = htx_get_blk(htx, pos); + enum htx_blk_type type = htx_get_blk_type(blk); + size_t count = co_data(res); + uint32_t blksz = htx_get_blksz(blk); + uint32_t room = b_room(&hc->res.buf); + uint32_t vlen; - blk = htx_get_blk(htx, pos); - type = htx_get_blk_type(blk); - sz = htx_get_blksz(blk); + /* we should try to copy the maximum output data in a block, which fit + * the destination buffer */ + vlen = MIN(count, blksz); + vlen = MIN(vlen, room); - /* we need to check if the data are part of the ouput */ - if (co_data(res) < sz) + if (vlen == 0) goto process_data; if (type == HTX_BLK_DATA) { struct ist v = htx_get_blk_value(htx, blk); - if ((b_room(&hc->res.buf) < v.len)) - goto process_data; + __b_putblk(&hc->res.buf, v.ptr, vlen); + c_rew(res, vlen); - __b_putblk(&hc->res.buf, v.ptr, v.len); - co_set_data(res, co_data(res) - sz); - htx_remove_blk(htx, blk); + if (vlen == blksz) + htx_remove_blk(htx, blk); + else + htx_cut_data_blk(htx, blk, vlen); /* the data must be processed by the caller in the receive phase */ if (hc->ops.res_payload) hc->ops.res_payload(hc); + + /* cannot copy everything, need to processs */ + if (vlen != blksz) + goto process_data; } else { + if (vlen != blksz) + goto process_data; + /* remove any block which is not a data block */ - co_set_data(res, co_data(res) - sz); + c_rew(res, blksz); htx_remove_blk(htx, blk); } } + /* if not finished, should be called again */ - if (!(htx->flags & HTX_FL_EOM)) + if (!(htx_is_empty(htx) && (htx->flags & HTX_FL_EOM))) goto more; + /* end of message, we should quit */ appctx->st0 = HTTPCLIENT_S_RES_END; break;