From f03b53c81d52344c29d7a5434ac32f3127cebf75 Mon Sep 17 00:00:00 2001 From: William Lallemand Date: Wed, 24 Nov 2021 15:38:17 +0100 Subject: [PATCH] BUG/MINOR: httpclient: allow to replace the host header This patch allows to replace the host header generated by the httpclient instead of adding a new one, resulting in the server replying an error 400. The host header is now generated from the uri only if it wasn't found in the list of headers. Also add a new request in the VTC file to test this. This patch must be backported in 2.5. --- reg-tests/lua/lua_httpclient.lua | 6 ++++++ reg-tests/lua/lua_httpclient.vtc | 11 ++++++++++- src/http_client.c | 32 +++++++++++++++++++++----------- 3 files changed, 37 insertions(+), 12 deletions(-) diff --git a/reg-tests/lua/lua_httpclient.lua b/reg-tests/lua/lua_httpclient.lua index a79dfb2d1..e9ec0f02c 100644 --- a/reg-tests/lua/lua_httpclient.lua +++ b/reg-tests/lua/lua_httpclient.lua @@ -1,10 +1,12 @@ local vtc_port = 0 local vtc_port2 = 0 +local vtc_port3 = 0 core.register_service("fakeserv", "http", function(applet) vtc_port = applet.headers["vtcport"][0] vtc_port2 = applet.headers["vtcport2"][0] + vtc_port3 = applet.headers["vtcport3"][0] core.Info("APPLET START") local response = "OK" applet:add_header("Server", "haproxy/webstats") @@ -38,6 +40,10 @@ local function cron() local httpclient2 = core.httpclient() local response2 = httpclient2:post{url="http://127.0.0.1:" .. vtc_port2, body=body} + core.Info("Third httpclient request") + local httpclient3 = core.httpclient() + local response3 = httpclient3:get{url="http://127.0.0.1:" .. vtc_port3, headers={ [ "Host" ] = { "foobar.haproxy.local" } }} + end core.register_task(cron) diff --git a/reg-tests/lua/lua_httpclient.vtc b/reg-tests/lua/lua_httpclient.vtc index 9d53cfe23..7c55d54bf 100644 --- a/reg-tests/lua/lua_httpclient.vtc +++ b/reg-tests/lua/lua_httpclient.vtc @@ -28,6 +28,14 @@ server s2 { expect req.bodylen == 54000 } -start +server s3 { + rxreq + txresp -bodylen 54000 + expect req.method == "GET" + expect req.http.host == "foobar.haproxy.local" +} -start + + haproxy h1 -conf { global lua-load ${testdir}/lua_httpclient.lua @@ -44,7 +52,7 @@ haproxy h1 -conf { } -start client c0 -connect ${h1_fe1_sock} { - txreq -url "/" -hdr "vtcport: ${s1_port}" -hdr "vtcport2: ${s2_port}" + txreq -url "/" -hdr "vtcport: ${s1_port}" -hdr "vtcport2: ${s2_port}" -hdr "vtcport3: ${s3_port}" rxresp expect resp.status == 200 } -run @@ -52,3 +60,4 @@ client c0 -connect ${h1_fe1_sock} { server s1 -wait server s2 -wait +server s3 -wait diff --git a/src/http_client.c b/src/http_client.c index 4e5ef7c1c..34e27c661 100644 --- a/src/http_client.c +++ b/src/http_client.c @@ -265,6 +265,8 @@ int httpclient_req_gen(struct httpclient *hc, const struct ist url, enum http_me int err_code = 0; struct ist meth_ist, vsn; unsigned int flags = HTX_SL_F_VER_11 | HTX_SL_F_NORMALIZED_URI | HTX_SL_F_HAS_SCHM; + int i; + int foundhost = 0; if (meth >= HTTP_METH_OTHER) goto error; @@ -282,21 +284,29 @@ int httpclient_req_gen(struct httpclient *hc, const struct ist url, enum http_me } sl->info.req.meth = meth; - /* Add Host Header from URL */ - if (!htx_add_header(htx, ist("Host"), ist("h"))) - goto error; - if (!http_update_host(htx, sl, url)) - goto error; + for (i = 0; hdrs && hdrs[i].n.len; i++) { + /* Don't check the value length because a header value may be empty */ + if (isttest(hdrs[i].v) == 0) + continue; - /* add the headers and EOH */ - if (hdrs) { - if (!htx_add_all_headers(htx, hdrs)) - goto error; - } else { - if (!htx_add_endof(htx, HTX_BLK_EOH)) + if (isteqi(hdrs[i].n, ist("host"))) + foundhost = 1; + + if (!htx_add_header(htx, hdrs[i].n, hdrs[i].v)) goto error; } + if (!foundhost) { + /* Add Host Header from URL */ + if (!htx_add_header(htx, ist("Host"), ist("h"))) + goto error; + if (!http_update_host(htx, sl, url)) + goto error; + } + + if (!htx_add_endof(htx, HTX_BLK_EOH)) + 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 */