[MEDIUM] acl: when possible, report the name and requirements of ACLs in warnings

When an ACL is referenced at a wrong place (eg: response during request, layer7
during layer4), try to indicate precisely the name and requirements of this ACL.

Only the first faulty ACL is returned. A small change consisting in iterating
that way may improve reports :
   cap = ACL_USE_any_unexpected
   while ((acl=cond_find_require(cond, cap))) {
     warning()
     cap &= ~acl->requires;
   }

This will report the first ACL of each unsupported type. But doing so will
mangle the error reporting a lot, so we need to rework error reports first.
diff --git a/include/proto/acl.h b/include/proto/acl.h
index ae64a50..fffce48 100644
--- a/include/proto/acl.h
+++ b/include/proto/acl.h
@@ -87,6 +87,11 @@
  */
 int acl_exec_cond(struct acl_cond *cond, struct proxy *px, struct session *l4, void *l7, int dir);
 
+/* Reports a pointer to the first ACL used in condition <cond> which requires
+ * at least one of the USE_FLAGS in <require>. Returns NULL if none matches.
+ */
+struct acl *cond_find_require(struct acl_cond *cond, unsigned int require);
+
 /* Return a pointer to the ACL <name> within the list starting at <head>, or
  * NULL if not found.
  */
diff --git a/src/acl.c b/src/acl.c
index 30c30de..ed41e91 100644
--- a/src/acl.c
+++ b/src/acl.c
@@ -1096,6 +1096,30 @@
 }
 
 
+/* Reports a pointer to the first ACL used in condition <cond> which requires
+ * at least one of the USE_FLAGS in <require>. Returns NULL if none matches.
+ * The construct is almost the same as for acl_exec_cond() since we're walking
+ * down the ACL tree as well. It is important that the tree is really walked
+ * through and never cached, because that way, this function can be used as a
+ * late check.
+ */
+struct acl *cond_find_require(struct acl_cond *cond, unsigned int require)
+{
+	struct acl_term_suite *suite;
+	struct acl_term *term;
+	struct acl *acl;
+
+	list_for_each_entry(suite, &cond->suites, list) {
+		list_for_each_entry(term, &suite->terms, list) {
+			acl = term->acl;
+			if (acl->requires & require)
+				return acl;
+		}
+	}
+	return NULL;
+}
+
+
 /************************************************************************/
 /*             All supported keywords must be declared here.            */
 /************************************************************************/
diff --git a/src/cfgparse.c b/src/cfgparse.c
index 1f1755f..09f63a4 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -1244,8 +1244,13 @@
 
 		cond->line = linenum;
 		if (cond->requires & ACL_USE_RTR_ANY) {
-			Warning("parsing [%s:%d] : switching rule involves some response-only criteria which will be ignored.\n",
-				file, linenum);
+			struct acl *acl;
+			const char *name;
+
+			acl = cond_find_require(cond, ACL_USE_RTR_ANY);
+			name = acl ? acl->name : "(unknown)";
+			Warning("parsing [%s:%d] : acl '%s' involves some response-only criteria which will be ignored.\n",
+				file, linenum, name);
 		}
 
 		rule = (struct switching_rule *)calloc(1, sizeof(*rule));
diff --git a/src/proto_tcp.c b/src/proto_tcp.c
index 3d93a34..cc96033 100644
--- a/src/proto_tcp.c
+++ b/src/proto_tcp.c
@@ -377,6 +377,7 @@
 
 	if (!strcmp(args[1], "content")) {
 		int action;
+		int warn = 0;
 		int pol = ACL_COND_NONE;
 		struct acl_cond *cond;
 		struct tcp_rule *rule;
@@ -410,17 +411,32 @@
 		if (pol != ACL_COND_NONE &&
 		    (cond = parse_acl_cond((const char **)args+4, &curpx->acl, pol)) == NULL) {
 			retlen = snprintf(err, errlen,
-					  "Error detected in %s '%s' while parsing '%s' condition",
+					  "error detected in %s '%s' while parsing '%s' condition",
 					  proxy_type_str(curpx), curpx->id, args[3]);
 			return -1;
 		}
 
+		// FIXME: how to set this ?
+		// cond->line = linenum;
+		if (cond->requires & (ACL_USE_RTR_ANY | ACL_USE_L7_ANY)) {
+			struct acl *acl;
+			const char *name;
+
+			acl = cond_find_require(cond, ACL_USE_RTR_ANY|ACL_USE_L7_ANY);
+			name = acl ? acl->name : "(unknown)";
+
+			retlen = snprintf(err, errlen,
+					  "acl '%s' involves some %s criteria which will be ignored.",
+					  name,
+					  (acl->requires & ACL_USE_RTR_ANY) ? "response-only" : "layer 7");
+			warn++;
+		}
 		rule = (struct tcp_rule *)calloc(1, sizeof(*rule));
 		rule->cond = cond;
 		rule->action = action;
 		LIST_INIT(&rule->list);
 		LIST_ADDQ(&curpx->tcp_req.inspect_rules, &rule->list);
-		return 0;
+		return warn;
 	}
 
 	snprintf(err, errlen, "unknown argument '%s' after '%s' in %s '%s'",