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.
diff --git a/src/http_client.c b/src/http_client.c
index ad3c40c..f17e805 100644
--- a/src/http_client.c
+++ b/src/http_client.c
@@ -849,40 +849,54 @@
/* 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;