From d1c6cfe45a267b3150af6af814bee94d30eb23c6 Mon Sep 17 00:00:00 2001 From: Christopher Faulet Date: Fri, 10 Jun 2022 16:48:47 +0200 Subject: [PATCH] BUG/MINOR: tcp-rules: Make action call final on read error and delay expiration When a TCP content ruleset is evaluated, we stop waiting for more data if the inspect-delay is reached, if there is a read error or if we know no more data will be received. This last point is only valid for ACLs. An action may decide to yield for another reason. For instance, in the SPOE, the "send-spoe-group" action yields while the agent response is not received. Thus, now, an action call is final only when the inspect-delay is reached or if there is a read error. But it is possible for an action to yield if the buffer is full or if CF_EOI flag is set. This patch could be backported to all supported versions. --- src/tcp_rules.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/tcp_rules.c b/src/tcp_rules.c index 131895340..e64979495 100644 --- a/src/tcp_rules.c +++ b/src/tcp_rules.c @@ -118,8 +118,12 @@ int tcp_inspect_request(struct stream *s, struct channel *req, int an_bit) if ((req->flags & (CF_EOI|CF_SHUTR|CF_READ_ERROR)) || channel_full(req, global.tune.maxrewrite) || sc_waiting_room(chn_prod(req)) || - !s->be->tcp_req.inspect_delay || tick_is_expired(s->rules_exp, now_ms)) + !s->be->tcp_req.inspect_delay || tick_is_expired(s->rules_exp, now_ms)) { partial = SMP_OPT_FINAL; + /* Action may yield while the inspect_delay is not expired and there is no read error */ + if ((req->flags & CF_READ_ERROR) || !s->be->tcp_req.inspect_delay || tick_is_expired(s->rules_exp, now_ms)) + act_opts |= ACT_OPT_FINAL; + } else partial = 0; @@ -153,12 +157,8 @@ int tcp_inspect_request(struct stream *s, struct channel *req, int an_bit) if (ret) { act_opts |= ACT_OPT_FIRST; resume_execution: - /* Always call the action function if defined */ if (rule->action_ptr) { - if (partial & SMP_OPT_FINAL) - act_opts |= ACT_OPT_FINAL; - switch (rule->action_ptr(rule, s->be, s->sess, s, act_opts)) { case ACT_RET_CONT: break; @@ -169,7 +169,7 @@ resume_execution: goto end; case ACT_RET_YIELD: s->current_rule = rule; - if (partial & SMP_OPT_FINAL) { + if (act_opts & ACT_OPT_FINAL) { send_log(s->be, LOG_WARNING, "Internal error: yield not allowed if the inspect-delay expired " "for the tcp-request content actions."); @@ -301,8 +301,12 @@ int tcp_inspect_response(struct stream *s, struct channel *rep, int an_bit) */ if ((rep->flags & (CF_EOI|CF_SHUTR|CF_READ_ERROR)) || channel_full(rep, global.tune.maxrewrite) || sc_waiting_room(chn_prod(rep)) || - !s->be->tcp_rep.inspect_delay || tick_is_expired(s->rules_exp, now_ms)) + !s->be->tcp_rep.inspect_delay || tick_is_expired(s->rules_exp, now_ms)) { partial = SMP_OPT_FINAL; + /* Action may yield while the inspect_delay is not expired and there is no read error */ + if ((rep->flags & CF_READ_ERROR) || !s->be->tcp_rep.inspect_delay || tick_is_expired(s->rules_exp, now_ms)) + act_opts |= ACT_OPT_FINAL; + } else partial = 0; @@ -338,9 +342,6 @@ int tcp_inspect_response(struct stream *s, struct channel *rep, int an_bit) resume_execution: /* Always call the action function if defined */ if (rule->action_ptr) { - if (partial & SMP_OPT_FINAL) - act_opts |= ACT_OPT_FINAL; - switch (rule->action_ptr(rule, s->be, s->sess, s, act_opts)) { case ACT_RET_CONT: break; @@ -351,7 +352,7 @@ resume_execution: goto end; case ACT_RET_YIELD: s->current_rule = rule; - if (partial & SMP_OPT_FINAL) { + if (act_opts & ACT_OPT_FINAL) { send_log(s->be, LOG_WARNING, "Internal error: yield not allowed if the inspect-delay expired " "for the tcp-response content actions.");