]> git.kaiwu.me - haproxy.git/commitdiff
BUG/MINOR: hlua/filters: Track the payload phase per channel
authorChristopher Faulet <cfaulet@haproxy.com>
Thu, 22 Oct 2026 13:32:03 +0000 (15:32 +0200)
committerChristopher Faulet <cfaulet@haproxy.com>
Fri, 23 Oct 2026 17:36:57 +0000 (19:36 +0200)
HLUA_FLT_CTX_FL_PAYLOAD is used to know if a filter is in its payload
forwarding stage, when its http_payload or tcp_payload callback is
called, because the data of a channel may only be manipulated in this
context. But this was a per-context flag, shared by both channels,
while the payload phase is specific to a channel. Thus, when a filter
processed the request payload, a forbidden operation could be performed
on the response data while it was analyzed, and reciprocally.

Now the payload phase is tracked per channel, with a dedicated flag for
the request and the response. All the data manipulation functions now
check the flag of the channel on which they operate. The flags are set
or cleared by the payload and analysis callbacks of the corresponding
channel. In particular, start_analyze only clears the flag of the
channel being analyzed, so starting the analysis of a channel no longer
resets the payload phase of the other one.

src/hlua.c

index c62b952b4bf2679a9aa4e12e8cef4ac3f0f176dc..f2f12b23cf774a3935629bd6e589a59ae29b32b4 100644 (file)
@@ -414,7 +414,9 @@ static lua_State *hlua_states[MAX_THREADS + 1];
 #define HLUA_FLT_CB_ARG_CHN       0x00000004
 #define HLUA_FLT_CB_ARG_HTTP_MSG  0x00000008
 
-#define HLUA_FLT_CTX_FL_PAYLOAD  0x00000001
+#define HLUA_FLT_CTX_FL_REQ_PAYLOAD   0x00000001
+#define HLUA_FLT_CTX_FL_RES_PAYLOAD   0x00000002
+#define HLUA_FLT_CTX_FL_PAYLOAD_BIT(idx) ((idx) ? HLUA_FLT_CTX_FL_RES_PAYLOAD : HLUA_FLT_CTX_FL_REQ_PAYLOAD)
 
 const char *hlua_filter_cls_name = "lua";
 
@@ -478,7 +480,7 @@ struct hlua_cli_ctx {
 
 DECLARE_STATIC_TYPED_POOL(pool_head_hlua_flt_ctx, "hlua_flt_ctx", struct hlua_flt_ctx);
 
-static int hlua_filter_from_payload(struct filter *filter);
+static int hlua_filter_from_payload(struct filter *filter, struct channel *chn);
 
 /* This is the chained list of struct hlua_flt referenced
  * for haproxy filters. It is used for a post-initialisation control.
@@ -3856,7 +3858,7 @@ static struct filter *hlua_channel_filter(lua_State *L, int ud, struct channel *
 
                filter  = lua_touserdata (L, -1);
                flt_ctx = filter->ctx;
-               if (hlua_filter_from_payload(filter)) {
+               if (hlua_filter_from_payload(filter, chn)) {
                        *offset  = flt_ctx->cur_off[CHN_IDX(chn)];
                        *len     = flt_ctx->cur_len[CHN_IDX(chn)];
                }
@@ -3945,7 +3947,7 @@ __LJMP static int hlua_channel_get_data_yield(lua_State *L, int status, lua_KCon
        input = ci_data(chn);
 
        filter = hlua_channel_filter(L, 1, chn, &output, &input);
-       if (filter && !hlua_filter_from_payload(filter))
+       if (filter && !hlua_filter_from_payload(filter, chn))
                WILL_LJMP(lua_error(L));
 
        offset = output;
@@ -4028,7 +4030,7 @@ __LJMP static int hlua_channel_get_line_yield(lua_State *L, int status, lua_KCon
        input = ci_data(chn);
 
        filter = hlua_channel_filter(L, 1, chn, &output, &input);
-       if (filter && !hlua_filter_from_payload(filter))
+       if (filter && !hlua_filter_from_payload(filter, chn))
                WILL_LJMP(lua_error(L));
 
        offset = output;
@@ -4122,7 +4124,7 @@ __LJMP static int hlua_channel_dup(lua_State *L)
        len = ci_data(chn);
 
        filter = hlua_channel_filter(L, 1, chn, &offset, &len);
-       if (filter && !hlua_filter_from_payload(filter))
+       if (filter && !hlua_filter_from_payload(filter, chn))
                WILL_LJMP(lua_error(L));
 
        if (!ci_data(chn) && channel_input_closed(chn)) {
@@ -4161,7 +4163,7 @@ __LJMP static int hlua_channel_get(lua_State *L)
        len = ci_data(chn);
 
        filter = hlua_channel_filter(L, 1, chn, &offset, &len);
-       if (filter && !hlua_filter_from_payload(filter))
+       if (filter && !hlua_filter_from_payload(filter, chn))
                WILL_LJMP(lua_error(L));
 
        if (!ci_data(chn) && channel_input_closed(chn)) {
@@ -4195,7 +4197,7 @@ __LJMP static int hlua_channel_getline_yield(lua_State *L, int status, lua_KCont
        len = ci_data(chn);
 
        filter = hlua_channel_filter(L, 1, chn, &offset, &len);
-       if (filter && !hlua_filter_from_payload(filter))
+       if (filter && !hlua_filter_from_payload(filter, chn))
                WILL_LJMP(lua_error(L));
 
        if (!ci_data(chn) && channel_input_closed(chn)) {
@@ -4303,7 +4305,7 @@ __LJMP static int hlua_channel_append(lua_State *L)
        len = ci_data(chn);
 
        filter = hlua_channel_filter(L, 1, chn, &offset, &len);
-       if (filter && !hlua_filter_from_payload(filter))
+       if (filter && !hlua_filter_from_payload(filter, chn))
                WILL_LJMP(lua_error(L));
 
        ret = _hlua_channel_insert(chn, L, ist2(str, sz), offset);
@@ -4344,7 +4346,7 @@ __LJMP static int hlua_channel_prepend(lua_State *L)
        len = ci_data(chn);
 
        filter = hlua_channel_filter(L, 1, chn, &offset, &len);
-       if (filter && !hlua_filter_from_payload(filter))
+       if (filter && !hlua_filter_from_payload(filter, chn))
                WILL_LJMP(lua_error(L));
 
        ret = _hlua_channel_insert(chn, L, ist2(str, sz), offset);
@@ -4383,7 +4385,7 @@ __LJMP static int hlua_channel_insert_data(lua_State *L)
        input = ci_data(chn);
 
        filter = hlua_channel_filter(L, 1, chn, &output, &input);
-       if (filter && !hlua_filter_from_payload(filter))
+       if (filter && !hlua_filter_from_payload(filter, chn))
                WILL_LJMP(lua_error(L));
 
        offset = output;
@@ -4442,7 +4444,7 @@ __LJMP static int hlua_channel_set_data(lua_State *L)
        input = ci_data(chn);
 
        filter = hlua_channel_filter(L, 1, chn, &output, &input);
-       if (filter && !hlua_filter_from_payload(filter))
+       if (filter && !hlua_filter_from_payload(filter, chn))
                WILL_LJMP(lua_error(L));
 
        offset = output;
@@ -4516,7 +4518,7 @@ __LJMP static int hlua_channel_del_data(lua_State *L)
        input = ci_data(chn);
 
        filter = hlua_channel_filter(L, 1, chn, &output, &input);
-       if (filter && !hlua_filter_from_payload(filter))
+       if (filter && !hlua_filter_from_payload(filter, chn))
                WILL_LJMP(lua_error(L));
 
        offset = output;
@@ -4586,7 +4588,7 @@ __LJMP static int hlua_channel_send_yield(lua_State *L, int status, lua_KContext
        len = ci_data(chn);
 
        filter = hlua_channel_filter(L, 1, chn, &offset, &len);
-       if (filter && !hlua_filter_from_payload(filter))
+       if (filter && !hlua_filter_from_payload(filter, chn))
                WILL_LJMP(lua_error(L));
 
 
@@ -4698,7 +4700,7 @@ __LJMP static int hlua_channel_forward_yield(lua_State *L, int status, lua_KCont
        len = ci_data(chn);
 
        filter = hlua_channel_filter(L, 1, chn, &offset, &len);
-       if (filter && !hlua_filter_from_payload(filter))
+       if (filter && !hlua_filter_from_payload(filter, chn))
                WILL_LJMP(lua_error(L));
 
        max = fwd - l;
@@ -7533,7 +7535,7 @@ __LJMP static int hlua_http_msg_get_body(lua_State *L)
                WILL_LJMP(lua_error(L));
 
        filter = hlua_http_msg_filter(L, 1, msg, &output, &input);
-       if (!filter || !hlua_filter_from_payload(filter))
+       if (!filter || !hlua_filter_from_payload(filter, msg->chn))
                WILL_LJMP(lua_error(L));
 
        if (!ci_data(msg->chn) && channel_input_closed(msg->chn)) {
@@ -7592,7 +7594,7 @@ __LJMP static int hlua_http_msg_append(lua_State *L)
 
        str = MAY_LJMP(luaL_checklstring(L, 2, &sz));
        filter = hlua_http_msg_filter(L, 1, msg, &offset, &len);
-       if (!filter || !hlua_filter_from_payload(filter))
+       if (!filter || !hlua_filter_from_payload(filter, msg->chn))
                WILL_LJMP(lua_error(L));
 
        ret = _hlua_http_msg_insert(msg, filter, ist2(str, sz), offset+len);
@@ -7622,7 +7624,7 @@ __LJMP static int hlua_http_msg_prepend(lua_State *L)
 
        str = MAY_LJMP(luaL_checklstring(L, 2, &sz));
        filter = hlua_http_msg_filter(L, 1, msg, &offset, &len);
-       if (!filter || !hlua_filter_from_payload(filter))
+       if (!filter || !hlua_filter_from_payload(filter, msg->chn))
                WILL_LJMP(lua_error(L));
 
        ret = _hlua_http_msg_insert(msg, filter, ist2(str, sz), offset);
@@ -7655,7 +7657,7 @@ __LJMP static int hlua_http_msg_insert_data(lua_State *L)
 
        str = MAY_LJMP(luaL_checklstring(L, 2, &sz));
        filter = hlua_http_msg_filter(L, 1, msg, &output, &input);
-       if (!filter || !hlua_filter_from_payload(filter))
+       if (!filter || !hlua_filter_from_payload(filter, msg->chn))
                WILL_LJMP(lua_error(L));
 
        offset = output;
@@ -7696,7 +7698,7 @@ __LJMP static int hlua_http_msg_del_data(lua_State *L)
                WILL_LJMP(lua_error(L));
 
        filter = hlua_http_msg_filter(L, 1, msg, &output, &input);
-       if (!filter || !hlua_filter_from_payload(filter))
+       if (!filter || !hlua_filter_from_payload(filter, msg->chn))
                WILL_LJMP(lua_error(L));
 
        offset = output;
@@ -7757,7 +7759,7 @@ __LJMP static int hlua_http_msg_set_data(lua_State *L)
 
        str = MAY_LJMP(luaL_checklstring(L, 2, &sz));
        filter = hlua_http_msg_filter(L, 1, msg, &output, &input);
-       if (!filter || !hlua_filter_from_payload(filter))
+       if (!filter || !hlua_filter_from_payload(filter, msg->chn))
                WILL_LJMP(lua_error(L));
 
        offset = output;
@@ -7821,7 +7823,7 @@ __LJMP static int hlua_http_msg_send(lua_State *L)
 
        str = MAY_LJMP(luaL_checklstring(L, 2, &sz));
        filter = hlua_http_msg_filter(L, 1, msg, &offset, &len);
-       if (!filter || !hlua_filter_from_payload(filter))
+       if (!filter || !hlua_filter_from_payload(filter, msg->chn))
                WILL_LJMP(lua_error(L));
 
        /* Return an error if the channel's output is closed */
@@ -7871,7 +7873,7 @@ __LJMP static int hlua_http_msg_forward(lua_State *L)
 
        fwd = MAY_LJMP(luaL_checkinteger(L, 2));
        filter = hlua_http_msg_filter(L, 1, msg, &offset, &len);
-       if (!filter || !hlua_filter_from_payload(filter))
+       if (!filter || !hlua_filter_from_payload(filter, msg->chn))
                WILL_LJMP(lua_error(L));
 
        /* Nothing to do, just return */
@@ -12267,11 +12269,18 @@ static void hlua_filter_delete(struct stream *s, struct filter *filter)
        filter->ctx = NULL;
 }
 
-static int hlua_filter_from_payload(struct filter *filter)
+/* Returns true if the filter is currently processing the payload of the
+ * channel <chn>, from its http_payload or tcp_payload callback. This is the
+ * only context where the data of a channel may be manipulated from lua. The
+ * payload-processing phase is tracked per channel: when a filter processes
+ * the payload of the request, it must not be allowed to manipulate the data
+ * of the response while it is analyzed, and reciprocally.
+ */
+static int hlua_filter_from_payload(struct filter *filter, struct channel *chn)
 {
        struct hlua_flt_ctx *flt_ctx = filter->ctx;
 
-       return (flt_ctx && !!(flt_ctx->flags & HLUA_FLT_CTX_FL_PAYLOAD));
+       return (flt_ctx && !!(flt_ctx->flags & HLUA_FLT_CTX_FL_PAYLOAD_BIT(CHN_IDX(chn))));
 }
 
 static int hlua_filter_callback(struct stream *s, struct filter *filter, const char *fun,
@@ -12443,7 +12452,7 @@ static int  hlua_filter_start_analyze(struct stream *s, struct filter *filter, s
 {
        struct hlua_flt_ctx *flt_ctx = filter->ctx;
 
-       flt_ctx->flags = 0;
+       flt_ctx->flags &= ~HLUA_FLT_CTX_FL_PAYLOAD_BIT(CHN_IDX(chn));
        return hlua_filter_callback(s, filter, "start_analyze",
                                    (!(chn->flags & CF_ISRESP) ? SMP_OPT_DIR_REQ : SMP_OPT_DIR_RES),
                                    (HLUA_FLT_CB_FINAL | HLUA_FLT_CB_RETVAL | HLUA_FLT_CB_ARG_CHN));
@@ -12453,7 +12462,7 @@ static int  hlua_filter_end_analyze(struct stream *s, struct filter *filter, str
 {
        struct hlua_flt_ctx *flt_ctx = filter->ctx;
 
-       flt_ctx->flags &= ~HLUA_FLT_CTX_FL_PAYLOAD;
+       flt_ctx->flags &= ~HLUA_FLT_CTX_FL_PAYLOAD_BIT(CHN_IDX(chn));
        return hlua_filter_callback(s, filter, "end_analyze",
                                    (!(chn->flags & CF_ISRESP) ? SMP_OPT_DIR_REQ : SMP_OPT_DIR_RES),
                                    (HLUA_FLT_CB_FINAL | HLUA_FLT_CB_RETVAL | HLUA_FLT_CB_ARG_CHN));
@@ -12463,7 +12472,7 @@ static int  hlua_filter_http_headers(struct stream *s, struct filter *filter, st
 {
        struct hlua_flt_ctx *flt_ctx = filter->ctx;
 
-       flt_ctx->flags &= ~HLUA_FLT_CTX_FL_PAYLOAD;
+       flt_ctx->flags &= ~HLUA_FLT_CTX_FL_PAYLOAD_BIT(CHN_IDX(msg->chn));
        return hlua_filter_callback(s, filter, "http_headers",
                                    (!(msg->chn->flags & CF_ISRESP) ? SMP_OPT_DIR_REQ : SMP_OPT_DIR_RES),
                                    (HLUA_FLT_CB_FINAL | HLUA_FLT_CB_RETVAL | HLUA_FLT_CB_ARG_HTTP_MSG));
@@ -12481,7 +12490,7 @@ static int  hlua_filter_http_payload(struct stream *s, struct filter *filter, st
        flt_hlua = flt_ctx->hlua[idx];
        flt_ctx->cur_off[idx] = offset;
        flt_ctx->cur_len[idx] = len;
-       flt_ctx->flags |= HLUA_FLT_CTX_FL_PAYLOAD;
+       flt_ctx->flags |= HLUA_FLT_CTX_FL_PAYLOAD_BIT(idx);
        ret = hlua_filter_callback(s, filter, "http_payload", dir, (HLUA_FLT_CB_FINAL | HLUA_FLT_CB_ARG_HTTP_MSG));
        if (ret != -1) {
                ret = flt_ctx->cur_len[idx];
@@ -12499,7 +12508,7 @@ static int  hlua_filter_http_end(struct stream *s, struct filter *filter, struct
 {
        struct hlua_flt_ctx *flt_ctx = filter->ctx;
 
-       flt_ctx->flags &= ~HLUA_FLT_CTX_FL_PAYLOAD;
+       flt_ctx->flags &= ~HLUA_FLT_CTX_FL_PAYLOAD_BIT(CHN_IDX(msg->chn));
        return hlua_filter_callback(s, filter, "http_end",
                                    (!(msg->chn->flags & CF_ISRESP) ? SMP_OPT_DIR_REQ : SMP_OPT_DIR_RES),
                                    (HLUA_FLT_CB_FINAL | HLUA_FLT_CB_RETVAL | HLUA_FLT_CB_ARG_HTTP_MSG));
@@ -12517,7 +12526,7 @@ static int  hlua_filter_tcp_payload(struct stream *s, struct filter *filter, str
        flt_hlua = flt_ctx->hlua[idx];
        flt_ctx->cur_off[idx] = offset;
        flt_ctx->cur_len[idx] = len;
-       flt_ctx->flags |= HLUA_FLT_CTX_FL_PAYLOAD;
+       flt_ctx->flags |= HLUA_FLT_CTX_FL_PAYLOAD_BIT(idx);
        ret = hlua_filter_callback(s, filter, "tcp_payload", dir, (HLUA_FLT_CB_FINAL | HLUA_FLT_CB_ARG_CHN));
        if (ret != -1) {
                ret = flt_ctx->cur_len[idx];