[MEDIUM] config: replace 'tcp-request <action>' with "tcp-request connection"

It began to be problematic to have "tcp-request" followed by an
immediate action, as sometimes it was a keyword indicating a hook
or setting ("content" or "inspect-delay") and sometimes it was an
action.

Now the prefix for connection-level tcp-requests is "tcp-request connection"
and the ones processing contents remain "tcp-request contents".

This has allowed a nice simplification of the config parser and to
clean up the doc a bit. Also now it's a bit more clear why tcp-request
connection are not allowed in backends.
diff --git a/src/proto_tcp.c b/src/proto_tcp.c
index e87860b..66b8a13 100644
--- a/src/proto_tcp.c
+++ b/src/proto_tcp.c
@@ -799,6 +799,74 @@
 	return result;
 }
 
+/* Parse a tcp-request rule. Return a negative value in case of failure */
+static int tcp_parse_request_rule(char **args, int arg, int section_type,
+				  struct proxy *curpx, struct proxy *defpx,
+				  struct tcp_rule *rule, char *err, int errlen)
+{
+	if (curpx == defpx) {
+		snprintf(err, errlen, "%s %s is not allowed in 'defaults' sections",
+			 args[0], args[1]);
+		return -1;
+	}
+
+	if (!strcmp(args[arg], "accept")) {
+		arg++;
+		rule->action = TCP_ACT_ACCEPT;
+	}
+	else if (!strcmp(args[arg], "reject")) {
+		arg++;
+		rule->action = TCP_ACT_REJECT;
+	}
+	else if (strcmp(args[arg], "track-fe-counters") == 0) {
+		int ret;
+
+		arg++;
+		ret = parse_track_counters(args, &arg, section_type, curpx,
+					   &rule->act_prm.trk_ctr, defpx, err, errlen);
+
+		if (ret < 0) /* nb: warnings are not handled yet */
+			return -1;
+
+		rule->action = TCP_ACT_TRK_FE_CTR;
+	}
+	else if (strcmp(args[arg], "track-be-counters") == 0) {
+		int ret;
+
+		arg++;
+		ret = parse_track_counters(args, &arg, section_type, curpx,
+					   &rule->act_prm.trk_ctr, defpx, err, errlen);
+
+		if (ret < 0) /* nb: warnings are not handled yet */
+			return -1;
+
+		rule->action = TCP_ACT_TRK_BE_CTR;
+	}
+	else {
+		snprintf(err, errlen,
+			 "'%s %s' expects 'accept', 'reject', 'track-fe-counters' "
+			 "or 'track-be-counters' in %s '%s' (was '%s')",
+			 args[0], args[1], proxy_type_str(curpx), curpx->id, args[arg]);
+		return -1;
+	}
+
+	if (strcmp(args[arg], "if") == 0 || strcmp(args[arg], "unless") == 0) {
+		if ((rule->cond = build_acl_cond(NULL, 0, curpx, (const char **)args+arg)) == NULL) {
+			snprintf(err, errlen,
+				 "error detected in %s '%s' while parsing '%s' condition",
+				 proxy_type_str(curpx), curpx->id, args[arg]);
+			return -1;
+		}
+	}
+	else if (*args[arg]) {
+		snprintf(err, errlen,
+			 "'%s %s %s' only accepts 'if' or 'unless', in %s '%s' (was '%s')",
+			 args[0], args[1], args[2], proxy_type_str(curpx), curpx->id, args[arg]);
+		return -1;
+	}
+	return 0;
+}
+
 /* This function should be called to parse a line starting with the "tcp-request"
  * keyword.
  */
@@ -809,7 +877,6 @@
 	unsigned int val;
 	int retlen;
 	int warn = 0;
-	int pol = ACL_COND_NONE;
 	int arg;
 	struct tcp_rule *rule;
 
@@ -848,70 +915,10 @@
 	rule = (struct tcp_rule *)calloc(1, sizeof(*rule));
 	arg = 1;
 
-	if (!strcmp(args[1], "content")) {
+	if (strcmp(args[1], "content") == 0) {
 		arg++;
-		if (curpx == defpx) {
-			snprintf(err, errlen, "%s %s is not allowed in 'defaults' sections",
-				 args[0], args[1]);
-			goto error;
-		}
-
-		if (!strcmp(args[2], "accept")) {
-			arg++;
-			rule->action = TCP_ACT_ACCEPT;
-		}
-		else if (!strcmp(args[2], "reject")) {
-			arg++;
-			rule->action = TCP_ACT_REJECT;
-		}
-		else if (strcmp(args[2], "track-fe-counters") == 0) {
-			int ret;
-
-			arg++;
-			ret = parse_track_counters(args, &arg, section_type, curpx,
-						   &rule->act_prm.trk_ctr, defpx, err, errlen);
-
-			if (ret < 0) /* nb: warnings are not handled yet */
-				goto error;
-
-			rule->action = TCP_ACT_TRK_FE_CTR;
-		}
-		else if (strcmp(args[2], "track-be-counters") == 0) {
-			int ret;
-
-			arg++;
-			ret = parse_track_counters(args, &arg, section_type, curpx,
-						   &rule->act_prm.trk_ctr, defpx, err, errlen);
-
-			if (ret < 0) /* nb: warnings are not handled yet */
-				goto error;
-
-			rule->action = TCP_ACT_TRK_BE_CTR;
-		}
-		else {
-			retlen = snprintf(err, errlen,
-					  "'%s %s' expects 'accept', 'reject', 'track-fe-counters' or 'track-be-counters' in %s '%s' (was '%s')",
-					  args[0], args[1], proxy_type_str(curpx), curpx->id, args[2]);
-			goto error;
-		}
-
-		pol = ACL_COND_NONE;
-		rule->cond = NULL;
-
-		if (strcmp(args[arg], "if") == 0 || strcmp(args[arg], "unless") == 0) {
-			if ((rule->cond = build_acl_cond(NULL, 0, curpx, (const char **)args+arg)) == NULL) {
-				retlen = snprintf(err, errlen,
-						  "error detected in %s '%s' while parsing '%s' condition",
-						  proxy_type_str(curpx), curpx->id, args[arg]);
-				goto error;
-			}
-		}
-		else if (*args[arg]) {
-			retlen = snprintf(err, errlen,
-					  "'%s %s %s' only accepts 'if' or 'unless', in %s '%s' (was '%s')",
-					  args[0], args[1], args[2], proxy_type_str(curpx), curpx->id, args[arg]);
+		if (tcp_parse_request_rule(args, arg, section_type, curpx, defpx, rule, err, errlen) < 0)
 			goto error;
-		}
 
 		if (rule->cond && (rule->cond->requires & ACL_USE_RTR_ANY)) {
 			struct acl *acl;
@@ -925,96 +932,47 @@
 					  name);
 			warn++;
 		}
-		LIST_INIT(&rule->list);
-		LIST_ADDQ(&curpx->tcp_req.inspect_rules, &rule->list);
-		return warn;
-	}
-
-	/* OK so we're in front of plain L4 rules */
-
-	if (strcmp(args[1], "accept") == 0) {
-		arg++;
-		rule->action = TCP_ACT_ACCEPT;
 	}
-	else if (strcmp(args[1], "reject") == 0) {
+	else if (strcmp(args[1], "connection") == 0) {
 		arg++;
-		rule->action = TCP_ACT_REJECT;
-	}
-	else if (strcmp(args[1], "track-fe-counters") == 0) {
-		int ret;
 
-		arg++;
-		ret = parse_track_counters(args, &arg, section_type, curpx,
-					   &rule->act_prm.trk_ctr, defpx, err, errlen);
+		if (!(curpx->cap & PR_CAP_FE)) {
+			snprintf(err, errlen, "%s %s is not allowed because %s %s is not a frontend",
+				 args[0], args[1], proxy_type_str(curpx), curpx->id);
+			return -1;
+		}
 
-		if (ret < 0) /* nb: warnings are not handled yet */
+		if (tcp_parse_request_rule(args, arg, section_type, curpx, defpx, rule, err, errlen) < 0)
 			goto error;
 
-		rule->action = TCP_ACT_TRK_FE_CTR;
-	}
-	else if (strcmp(args[1], "track-be-counters") == 0) {
-		int ret;
-
-		arg++;
-		ret = parse_track_counters(args, &arg, section_type, curpx,
-					   &rule->act_prm.trk_ctr, defpx, err, errlen);
+		if (rule->cond && (rule->cond->requires & (ACL_USE_RTR_ANY|ACL_USE_L6_ANY|ACL_USE_L7_ANY))) {
+			struct acl *acl;
+			const char *name;
 
-		if (ret < 0) /* nb: warnings are not handled yet */
-			goto error;
+			acl = cond_find_require(rule->cond, ACL_USE_RTR_ANY|ACL_USE_L6_ANY|ACL_USE_L7_ANY);
+			name = acl ? acl->name : "(unknown)";
 
-		rule->action = TCP_ACT_TRK_BE_CTR;
+			if (acl->requires & (ACL_USE_L6_ANY|ACL_USE_L7_ANY)) {
+				retlen = snprintf(err, errlen,
+						  "'%s %s' may not reference acl '%s' which makes use of "
+						  "payload in %s '%s'. Please use '%s content' for this.",
+						  args[0], args[1], name, proxy_type_str(curpx), curpx->id, args[0]);
+				goto error;
+			}
+			if (acl->requires & ACL_USE_RTR_ANY)
+				retlen = snprintf(err, errlen,
+						  "acl '%s' involves some response-only criteria which will be ignored.",
+						  name);
+			warn++;
+		}
 	}
 	else {
 		retlen = snprintf(err, errlen,
-				  "'%s' expects 'inspect-delay', 'content', 'accept', 'reject', 'track-fe-counters' or 'track-be-counters' in %s '%s' (was '%s')",
+				  "'%s' expects 'inspect-delay', 'connection', or 'content' in %s '%s' (was '%s')",
 				  args[0], proxy_type_str(curpx), curpx->id, args[1]);
 		goto error;
 	}
 
-	if (curpx == defpx) {
-		snprintf(err, errlen, "%s %s is not allowed in 'defaults' sections",
-			 args[0], args[1]);
-		goto error;
-	}
-
-	pol = ACL_COND_NONE;
-
-	if (strcmp(args[arg], "if") == 0 || strcmp(args[arg], "unless") == 0) {
-		if ((rule->cond = build_acl_cond(NULL, 0, curpx, (const char **)args+arg)) == NULL) {
-			retlen = snprintf(err, errlen,
-					  "error detected in %s '%s' while parsing '%s' condition",
-					  proxy_type_str(curpx), curpx->id, args[arg]);
-			goto error;
-		}
-	}
-	else if (*args[arg]) {
-		retlen = snprintf(err, errlen,
-				  "'%s %s' only accepts 'if' or 'unless', in %s '%s' (was '%s')",
-				  args[0], args[1], proxy_type_str(curpx), curpx->id, args[arg]);
-		goto error;
-	}
-
-	if (rule->cond && (rule->cond->requires & (ACL_USE_RTR_ANY|ACL_USE_L6_ANY|ACL_USE_L7_ANY))) {
-		struct acl *acl;
-		const char *name;
-
-		acl = cond_find_require(rule->cond, ACL_USE_RTR_ANY|ACL_USE_L6_ANY|ACL_USE_L7_ANY);
-		name = acl ? acl->name : "(unknown)";
-
-		if (acl->requires & (ACL_USE_L6_ANY|ACL_USE_L7_ANY)) {
-			retlen = snprintf(err, errlen,
-					  "'%s %s' may not reference acl '%s' which makes use of payload in %s '%s'. Please use '%s content' for this.",
-					  args[0], args[1], name, proxy_type_str(curpx), curpx->id, args[0]);
-			goto error;
-		}
-		if (acl->requires & ACL_USE_RTR_ANY)
-			retlen = snprintf(err, errlen,
-					  "acl '%s' involves some response-only criteria which will be ignored.",
-					  name);
-
-		warn++;
-	}
-
 	LIST_INIT(&rule->list);
 	LIST_ADDQ(&curpx->tcp_req.l4_rules, &rule->list);
 	return warn;