From: Christopher Faulet Date: Fri, 23 Oct 2026 07:23:28 +0000 (+0200) Subject: BUG/MEDIUM: hlua/filters: Make Channel.may_recv relative to the filter's data X-Git-Tag: v3.5-dev10~59 X-Git-Url: https://git.kaiwu.me/?a=commitdiff_plain;h=67ef257e44ab01808885480671435058f163b052;p=haproxy.git BUG/MEDIUM: hlua/filters: Make Channel.may_recv relative to the filter's data Channel.may_recv() tested the whole channel to know if more data may be received, ignoring the data visible by the calling filter. But when several Lua filters are chained on a channel and an earlier one holds back some data (for instance to rewrite the body), the channel input may be closed while the current filter still waits for data held upstream. In that case, the function must return true, because the held data can still be exposed to the filter, even if nothing will be received on the connection anymore. Now, like HTTPMessage.eom(), HTTPMessage.may_recv() and HTTPMessage.closed(), the result is relative to the data visible by the current filter: the function always returns true if an earlier filter holds back data. This patch should be backported to all supported versions. --- diff --git a/doc/lua-api/index.rst b/doc/lua-api/index.rst index f7f6dd4e6..2a53814a1 100644 --- a/doc/lua-api/index.rst +++ b/doc/lua-api/index.rst @@ -2295,7 +2295,11 @@ Channel class .. js:function:: Channel.may_recv(channel) - This function returns true if the channel may still receive data. + This function returns true if the channel may still receive data. When + called by a filter, the result is relative to the data visible by this + filter: if an earlier filter holds back some data, the function always + returns true, even if the input is closed, because the held data may still + be received by the current filter. :param class_channel channel: The manipulated Channel. :returns: a boolean @@ -4737,7 +4741,11 @@ HTTPMessage class .. js:function:: HTTPMessage.set_eom(http_msg) - This function set the end of message for the HTTP message **http_msg**. + This function set the end of message for the HTTP message **http_msg**. It + can only be called when all data of the message are visible by the current + filter. Otherwise, an error is raised, because an earlier filter holding + data back may already have reached the end of the message, or may expose + data after it. :param class_httpmessage http_msg: The manipulated HTTP message. @@ -4804,6 +4812,10 @@ HTTPMessage class .. js:function:: HTTPMessage.unset_eom(http_msg) This function remove the end of message for the HTTP message **http_msg**. + It can only be called when all data of the message are visible by the + current filter. Otherwise, an error is raised, because an earlier filter + holding data back may expose data carrying the end of message, which could + not be removed. :param class_httpmessage http_msg: The manipulated HTTP message. diff --git a/src/hlua.c b/src/hlua.c index 9a51f1b27..ee38cf461 100644 --- a/src/hlua.c +++ b/src/hlua.c @@ -3868,6 +3868,19 @@ static struct filter *hlua_channel_filter(lua_State *L, int ud, struct channel * return filter; } +/* Helper function to know if all data in a channel are visible by the + * current filter. Returns 1 if no filter are attached to the channel or if + * all input data are visible by the filter. Otherwise 0 is returned. + */ +static int hlua_channel_fully_visible(lua_State *L, struct channel *chn) +{ + size_t offset = co_data(chn); + size_t len = ci_data(chn); + + hlua_channel_filter(L, 1, chn, &offset, &len); + return (offset + len == c_data(chn)); +} + /* Copies bytes of data present in the channel's buffer, starting at the * offset , and put it in a LUA string variable. It is the caller * responsibility to ensure and are valid. It always return the @@ -4807,10 +4820,14 @@ __LJMP static int hlua_channel_is_full(lua_State *L) __LJMP static int hlua_channel_may_recv(lua_State *L) { struct channel *chn; + int may_recv; MAY_LJMP(check_args(L, 1, "may_recv")); chn = MAY_LJMP(hlua_checkchannel(L, 1)); - lua_pushboolean(L, (!channel_input_closed(chn) && channel_may_recv(chn))); + may_recv = !hlua_channel_fully_visible(L, chn) || (!channel_input_closed(chn) && + channel_may_recv(chn)); + + lua_pushboolean(L, may_recv); return 1; }