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.
diff --git a/src/tcp_rules.c b/src/tcp_rules.c
index 1318953..e649794 100644
--- a/src/tcp_rules.c
+++ b/src/tcp_rules.c
@@ -118,8 +118,12 @@
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 @@
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 @@
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 @@
*/
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 @@
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 @@
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.");