mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2024-12-27 07:02:11 +00:00
BUG/MEDIUM: httpclient: Rework CLI I/O handler to handle full buffer cases
'httpclient' command does not properly handle full buffer cases. When the response buffer is full, we exit to retry later. However, the context flags are updated. It means when this happens, we may loose a part of the response. So now, flags are preserved when we fail to push data into the response buffer. In addition, instead of dumping one part per call, we now try to dump as much data as possible. Finally, when there is no more data, because everything was dumped or because we are waiting for more data from the HTTP client, the applet is updated accordingly by calling applet_have_no_more_data(). Otherwise, when some data are blocked, applet_putchk() already takes care to update the SE flags. So, it is useless to call sc_need_room(). This patch should fix the issue #1723. It must be backported as far as 2.5. But a massive refactoring was performed in 2.6. So, for the 2.5 and below, the patch will have to be adapted.
This commit is contained in:
parent
18de6f2880
commit
0158bb23d7
@ -196,32 +196,29 @@ static int hc_cli_io_handler(struct appctx *appctx)
|
||||
{
|
||||
struct hcli_svc_ctx *ctx = appctx->svcctx;
|
||||
struct stconn *sc = appctx_sc(appctx);
|
||||
struct buffer *trash = alloc_trash_chunk();
|
||||
struct httpclient *hc = ctx->hc;
|
||||
struct http_hdr *hdrs, *hdr;
|
||||
|
||||
if (!trash)
|
||||
goto out;
|
||||
|
||||
if (ctx->flags & HC_CLI_F_RES_STLINE) {
|
||||
chunk_appendf(trash, "%.*s %d %.*s\n", (unsigned int)istlen(hc->res.vsn), istptr(hc->res.vsn),
|
||||
hc->res.status, (unsigned int)istlen(hc->res.reason), istptr(hc->res.reason));
|
||||
applet_putchk(appctx, trash);
|
||||
chunk_printf(&trash, "%.*s %d %.*s\n", (unsigned int)istlen(hc->res.vsn), istptr(hc->res.vsn),
|
||||
hc->res.status, (unsigned int)istlen(hc->res.reason), istptr(hc->res.reason));
|
||||
if (applet_putchk(appctx, &trash) == -1)
|
||||
goto more;
|
||||
ctx->flags &= ~HC_CLI_F_RES_STLINE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ctx->flags & HC_CLI_F_RES_HDR) {
|
||||
chunk_reset(&trash);
|
||||
hdrs = hc->res.hdrs;
|
||||
for (hdr = hdrs; isttest(hdr->v); hdr++) {
|
||||
if (!h1_format_htx_hdr(hdr->n, hdr->v, trash))
|
||||
goto out;
|
||||
if (!h1_format_htx_hdr(hdr->n, hdr->v, &trash))
|
||||
goto too_many_hdrs;
|
||||
}
|
||||
if (!chunk_memcat(trash, "\r\n", 2))
|
||||
goto out;
|
||||
applet_putchk(appctx, trash);
|
||||
if (!chunk_memcat(&trash, "\r\n", 2))
|
||||
goto too_many_hdrs;
|
||||
if (applet_putchk(appctx, &trash) == -1)
|
||||
goto more;
|
||||
ctx->flags &= ~HC_CLI_F_RES_HDR;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ctx->flags & HC_CLI_F_RES_BODY) {
|
||||
@ -230,10 +227,10 @@ static int hc_cli_io_handler(struct appctx *appctx)
|
||||
ret = httpclient_res_xfer(hc, sc_ib(sc));
|
||||
channel_add_input(sc_ic(sc), ret); /* forward what we put in the buffer channel */
|
||||
|
||||
if (!httpclient_data(hc)) {/* remove the flag if the buffer was emptied */
|
||||
ctx->flags &= ~HC_CLI_F_RES_BODY;
|
||||
}
|
||||
goto out;
|
||||
/* remove the flag if the buffer was emptied */
|
||||
if (httpclient_data(hc))
|
||||
goto more;
|
||||
ctx->flags &= ~HC_CLI_F_RES_BODY;
|
||||
}
|
||||
|
||||
/* we must close only if F_END is the last flag */
|
||||
@ -241,16 +238,15 @@ static int hc_cli_io_handler(struct appctx *appctx)
|
||||
sc_shutw(sc);
|
||||
sc_shutr(sc);
|
||||
ctx->flags &= ~HC_CLI_F_RES_END;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
/* we didn't clear every flags, we should come back to finish things */
|
||||
if (ctx->flags)
|
||||
sc_need_room(sc);
|
||||
|
||||
free_trash_chunk(trash);
|
||||
more:
|
||||
if (!ctx->flags)
|
||||
applet_have_no_more_data(appctx);
|
||||
return 0;
|
||||
|
||||
too_many_hdrs:
|
||||
return cli_err(appctx, "Too many headers.\n");
|
||||
}
|
||||
|
||||
static void hc_cli_release(struct appctx *appctx)
|
||||
|
Loading…
Reference in New Issue
Block a user