]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MINOR: tcp-rules: Make action call final on read error and delay expiration
authorChristopher Faulet <cfaulet@haproxy.com>
Fri, 10 Jun 2022 14:48:47 +0000 (16:48 +0200)
committerChristopher Faulet <cfaulet@haproxy.com>
Mon, 13 Jun 2022 06:04:10 +0000 (08:04 +0200)
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

index 131895340eabbd7dfd6c463a3112a5278745cac6..e649794951f2304ec164b65b867af3e2710f8c2b 100644 (file)
@@ -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.");