From: William Lallemand Date: Mon, 25 Oct 2021 17:48:37 +0000 (+0200) Subject: MINOR: httpclient: support payload within a buffer X-Git-Tag: v2.5-dev12~65 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=dec25c3e14754425a10ed386bd9bceab6af49573;p=thirdparty%2Fhaproxy.git MINOR: httpclient: support payload within a buffer httpclient_req_gen() takes a payload argument which can be use to put a payload in the request. This payload can only fit a request buffer. This payload can also be specified by the "body" named parameter within the lua. httpclient. It is also used within the CLI httpclient when specified as a CLI payload with "<<". --- diff --git a/include/haproxy/http_client.h b/include/haproxy/http_client.h index 097997eb53..13673e801b 100644 --- a/include/haproxy/http_client.h +++ b/include/haproxy/http_client.h @@ -9,7 +9,7 @@ struct httpclient *httpclient_new(void *caller, enum http_meth_t meth, struct is struct appctx *httpclient_start(struct httpclient *hc); int httpclient_res_xfer(struct httpclient *hc, struct buffer *dst); -int httpclient_req_gen(struct httpclient *hc, const struct ist url, enum http_meth_t meth, const struct http_hdr *hdrs); +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); /* Return the amount of data available in the httpclient response buffer */ diff --git a/reg-tests/lua/lua_httpclient.lua b/reg-tests/lua/lua_httpclient.lua index 9ea8e33483..5ded14f834 100644 --- a/reg-tests/lua/lua_httpclient.lua +++ b/reg-tests/lua/lua_httpclient.lua @@ -21,7 +21,7 @@ local function cron() core.Debug('CRON port:' .. vtc_port) local httpclient = core.httpclient() - local response = httpclient:get{url="http://127.0.0.1:" .. vtc_port} + local response = httpclient:get{url="http://127.0.0.1:" .. vtc_port, body="foobar-is-the-new-toto"} core.Info("Received: " .. response.body) end diff --git a/src/hlua.c b/src/hlua.c index ac61a3171b..a7ed1137a7 100644 --- a/src/hlua.c +++ b/src/hlua.c @@ -7164,6 +7164,7 @@ __LJMP static int hlua_httpclient_get(lua_State *L) struct http_hdr *hdrs_i = NULL; struct hlua *hlua; const char *url_str = NULL; + const char *body_str = NULL; int ret; hlua = hlua_gethlua(L); @@ -7187,6 +7188,12 @@ __LJMP static int hlua_httpclient_get(lua_State *L) } lua_pop(L, 1); + ret = lua_getfield(L, -1, "body"); + if (ret == LUA_TSTRING) { + body_str = lua_tostring(L, -1); + } + lua_pop(L, 1); + if (!url_str) { WILL_LJMP(luaL_error(L, "'get' need a 'url' argument")); return 0; @@ -7204,7 +7211,7 @@ __LJMP static int hlua_httpclient_get(lua_State *L) hlua_hc->hc->ops.res_end = hlua_httpclient_res_cb; - httpclient_req_gen(hlua_hc->hc, hlua_hc->hc->req.url, HTTP_METH_GET, hdrs); + httpclient_req_gen(hlua_hc->hc, hlua_hc->hc->req.url, HTTP_METH_GET, hdrs, ist(body_str)); httpclient_start(hlua_hc->hc); /* free the temporary headers array */ diff --git a/src/http_client.c b/src/http_client.c index f298fe1132..4d1ae05319 100644 --- a/src/http_client.c +++ b/src/http_client.c @@ -116,6 +116,7 @@ static int hc_cli_parse(char **args, char *payload, struct appctx *appctx, void enum http_meth_t meth; char *meth_str; struct ist uri; + struct ist body = IST_NULL; if (!cli_has_level(appctx, ACCESS_LVL_ADMIN)) return 1; @@ -128,6 +129,9 @@ static int hc_cli_parse(char **args, char *payload, struct appctx *appctx, void meth_str = args[1]; uri = ist(args[2]); + if (payload) + body = ist(payload); + meth = find_http_meth(meth_str, strlen(meth_str)); hc = httpclient_new(appctx, meth, uri); @@ -144,7 +148,7 @@ static int hc_cli_parse(char **args, char *payload, struct appctx *appctx, void appctx->ctx.cli.p0 = hc; /* store the httpclient ptr in the applet */ appctx->ctx.cli.i0 = 0; - if (httpclient_req_gen(hc, hc->req.url, hc->req.meth, default_httpclient_hdrs) != ERR_NONE) + if (httpclient_req_gen(hc, hc->req.url, hc->req.meth, default_httpclient_hdrs, body) != ERR_NONE) goto err; @@ -253,13 +257,13 @@ INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws); * If the buffer was filled correctly the function returns 0, if not it returns * an error_code but there is no guarantee that the buffer wasn't modified. */ -int httpclient_req_gen(struct httpclient *hc, const struct ist url, enum http_meth_t meth, const struct http_hdr *hdrs) +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) { struct htx_sl *sl; struct htx *htx; int err_code = 0; struct ist meth_ist, vsn; - unsigned int flags = HTX_SL_F_VER_11 | HTX_SL_F_BODYLESS | HTX_SL_F_XFER_LEN | HTX_SL_F_NORMALIZED_URI | HTX_SL_F_HAS_SCHM; + unsigned int flags = HTX_SL_F_VER_11 | HTX_SL_F_NORMALIZED_URI | HTX_SL_F_HAS_SCHM; if (meth >= HTTP_METH_OTHER) goto error; @@ -292,6 +296,13 @@ int httpclient_req_gen(struct httpclient *hc, const struct ist url, enum http_me goto error; } + if (isttest(payload)) { + /* add the payload if it can feat in the buffer, no need to set + * the Content-Length, the data will be sent chunked */ + if (!htx_add_data_atonce(htx, payload)) + goto error; + } + htx->flags |= HTX_FL_EOM; htx_to_buf(htx, &hc->req.buf);