MEDIUM: tcp-rules: Use a dedicated expiration date for tcp ruleset

A dedicated expiration date is now used to apply the inspect-delay of the
tcp-request or tcp-response rulesets. Before, the analyse expiratation date was
used but it may also be updated by the lua (at least). So a lua script may
extend or reduce the inspect-delay by side effect. This is not expected. If it
becomes necessary, a specific function will be added to do this. Because, for
now, it is a bit confusing.
diff --git a/include/haproxy/stream-t.h b/include/haproxy/stream-t.h
index 9640111..b2c8378 100644
--- a/include/haproxy/stream-t.h
+++ b/include/haproxy/stream-t.h
@@ -180,6 +180,7 @@
 	/* These two pointers are used to resume the execution of the rule lists. */
 	struct list *current_rule_list;         /* this is used to store the current executed rule list. */
 	void *current_rule;                     /* this is used to store the current rule to be resumed. */
+	int rules_exp;                          /* expiration date for current rules execution */
 	struct hlua *hlua;                      /* lua runtime context */
 
 	/* Context */
diff --git a/src/stream.c b/src/stream.c
index c8078f5..f282665 100644
--- a/src/stream.c
+++ b/src/stream.c
@@ -371,6 +371,7 @@
 	 */
 	s->current_rule_list = NULL;
 	s->current_rule = NULL;
+	s->rules_exp = TICK_ETERNITY;
 
 	/* Copy SC counters for the stream. We don't touch refcounts because
 	 * any reference we have is inherited from the session. Since the stream
diff --git a/src/tcp_rules.c b/src/tcp_rules.c
index d80c27c..6a31a32 100644
--- a/src/tcp_rules.c
+++ b/src/tcp_rules.c
@@ -113,7 +113,7 @@
 	 */
 
 	if ((req->flags & CF_SHUTR) || channel_full(req, global.tune.maxrewrite) ||
-	    !s->be->tcp_req.inspect_delay || tick_is_expired(req->analyse_exp, now_ms))
+	    !s->be->tcp_req.inspect_delay || tick_is_expired(s->rules_exp, now_ms))
 		partial = SMP_OPT_FINAL;
 	else
 		partial = 0;
@@ -195,15 +195,16 @@
 	 * we have an explicit accept, so we apply the default accept.
 	 */
 	req->analysers &= ~an_bit;
-	req->analyse_exp = TICK_ETERNITY;
+	req->analyse_exp = s->rules_exp = TICK_ETERNITY;
 	DBG_TRACE_LEAVE(STRM_EV_STRM_ANA|STRM_EV_TCP_ANA, s);
 	return 1;
 
  missing_data:
 	channel_dont_connect(req);
 	/* just set the request timeout once at the beginning of the request */
-	if (!tick_isset(req->analyse_exp) && s->be->tcp_req.inspect_delay)
-		req->analyse_exp = tick_add(now_ms, s->be->tcp_req.inspect_delay);
+	if (!tick_isset(s->rules_exp) && s->be->tcp_req.inspect_delay)
+		s->rules_exp = tick_add(now_ms, s->be->tcp_req.inspect_delay);
+	req->analyse_exp = tick_first((tick_is_expired(req->analyse_exp, now_ms) ? 0 : req->analyse_exp), s->rules_exp);
 	DBG_TRACE_DEVEL("waiting for more data", STRM_EV_STRM_ANA|STRM_EV_TCP_ANA, s);
 	return 0;
 
@@ -267,7 +268,7 @@
 	 * - if one rule returns KO, then return KO
 	 */
 	if ((rep->flags & CF_SHUTR) || channel_full(rep, global.tune.maxrewrite) ||
-	    !s->be->tcp_rep.inspect_delay || tick_is_expired(rep->analyse_exp, now_ms))
+	    !s->be->tcp_rep.inspect_delay || tick_is_expired(s->rules_exp, now_ms))
 		partial = SMP_OPT_FINAL;
 	else
 		partial = 0;
@@ -284,19 +285,15 @@
 			goto resume_execution;
 	}
 	s->current_rule_list = &s->be->tcp_rep.inspect_rules;
+	s->rules_exp = TICK_ETERNITY;
 
 	list_for_each_entry(rule, &s->be->tcp_rep.inspect_rules, list) {
 		enum acl_test_res ret = ACL_TEST_PASS;
 
 		if (rule->cond) {
 			ret = acl_exec_cond(rule->cond, s->be, sess, s, SMP_OPT_DIR_RES | partial);
-			if (ret == ACL_TEST_MISS) {
-				/* just set the analyser timeout once at the beginning of the response */
-				if (!tick_isset(rep->analyse_exp) && s->be->tcp_rep.inspect_delay)
-					rep->analyse_exp = tick_add(now_ms, s->be->tcp_rep.inspect_delay);
-				DBG_TRACE_DEVEL("waiting for more data", STRM_EV_STRM_ANA|STRM_EV_TCP_ANA, s);
-				return 0;
-			}
+			if (ret == ACL_TEST_MISS)
+				goto missing_data;
 
 			ret = acl_pass(ret);
 			if (rule->cond->pol == ACL_COND_UNLESS)
@@ -325,6 +322,7 @@
 								 "for the tcp-response content actions.");
 							goto internal;
 						}
+						channel_dont_close(rep);
 						goto missing_data;
 					case ACT_RET_DENY:
 						goto deny;
@@ -360,15 +358,15 @@
 	 * we have an explicit accept, so we apply the default accept.
 	 */
 	rep->analysers &= ~an_bit;
-	rep->analyse_exp = TICK_ETERNITY;
+	rep->analyse_exp = s->rules_exp = TICK_ETERNITY;
 	DBG_TRACE_LEAVE(STRM_EV_STRM_ANA|STRM_EV_TCP_ANA, s);
 	return 1;
 
  missing_data:
-	channel_dont_close(rep);
 	/* just set the analyser timeout once at the beginning of the response */
-	if (!tick_isset(rep->analyse_exp) && s->be->tcp_rep.inspect_delay)
-		rep->analyse_exp = tick_add(now_ms, s->be->tcp_rep.inspect_delay);
+	if (!tick_isset(s->rules_exp) && s->be->tcp_rep.inspect_delay)
+		s->rules_exp = tick_add(now_ms, s->be->tcp_rep.inspect_delay);
+	rep->analyse_exp = tick_first((tick_is_expired(rep->analyse_exp, now_ms) ? 0 : rep->analyse_exp), s->rules_exp);
 	DBG_TRACE_DEVEL("waiting for more data", STRM_EV_STRM_ANA|STRM_EV_TCP_ANA, s);
 	return 0;