[MEDIUM] add the "fail" condition to monitor requests

Under certain circumstances, it is very useful to be able to fail some
monitor requests. One specific case is when the number of servers in
the backend falls below a certain level. The new "monitor fail" construct
followed by either "if"/"unless" <condition> makes it possible to specify
ACL-based conditions which will make the monitor return 503 instead of
200. Any number of conditions can be passed. Another use may be to limit
the requests to local networks only.
diff --git a/include/types/proxy.h b/include/types/proxy.h
index fd48e70..61247e6 100644
--- a/include/types/proxy.h
+++ b/include/types/proxy.h
@@ -168,6 +168,7 @@
 	struct uri_auth *uri_auth;		/* if non-NULL, the (list of) per-URI authentications */
 	char *monitor_uri;			/* a special URI to which we respond with HTTP/200 OK */
 	int monitor_uri_len;			/* length of the string above. 0 if unused */
+	struct list mon_fail_cond;              /* list of conditions to fail monitoring requests (chained) */
 	struct timeval clitimeout;		/* client I/O timeout (in milliseconds) */
 	struct timeval srvtimeout;		/* server I/O timeout (in milliseconds) */
 	struct timeval contimeout;		/* connect timeout (in milliseconds) */
diff --git a/src/cfgparse.c b/src/cfgparse.c
index 869567f..232ae1c 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -564,6 +564,7 @@
 		LIST_INIT(&curproxy->pendconns);
 		LIST_INIT(&curproxy->acl);
 		LIST_INIT(&curproxy->block_cond);
+		LIST_INIT(&curproxy->mon_fail_cond);
 		LIST_INIT(&curproxy->switching_rules);
 
 		/* Timeouts are defined as -1, so we cannot use the zeroed area
@@ -1305,6 +1306,38 @@
 			return -1;
 		}
 	}
+	else if (!strcmp(args[0], "monitor")) {
+		if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL))
+			return 0;
+
+		if (strcmp(args[1], "fail") == 0) {
+			/* add a condition to fail monitor requests */
+			int pol = ACL_COND_NONE;
+			struct acl_cond *cond;
+
+			if (!strcmp(args[2], "if"))
+				pol = ACL_COND_IF;
+			else if (!strcmp(args[2], "unless"))
+				pol = ACL_COND_UNLESS;
+
+			if (pol == ACL_COND_NONE) {
+				Alert("parsing [%s:%d] : '%s %s' requires either 'if' or 'unless' followed by a condition.\n",
+				      file, linenum, args[0], args[1]);
+				return -1;
+			}
+
+			if ((cond = parse_acl_cond((const char **)args + 3, &curproxy->acl, pol)) == NULL) {
+				Alert("parsing [%s:%d] : error detected while parsing a '%s %s' condition.\n",
+				      file, linenum, args[0], args[1]);
+				return -1;
+			}
+			LIST_ADDQ(&curproxy->mon_fail_cond, &cond->list);
+		}
+		else {
+			Alert("parsing [%s:%d] : '%s' only supports 'fail'.\n", file, linenum, args[0]);
+			return -1;
+		}
+	}
 #ifdef TPROXY
 	else if (!strcmp(args[0], "transparent")) {
 		/* enable transparent proxy connections */
diff --git a/src/haproxy.c b/src/haproxy.c
index 5a79646..791f64b 100644
--- a/src/haproxy.c
+++ b/src/haproxy.c
@@ -658,6 +658,12 @@
 			free(cond);
 		}
 
+		list_for_each_entry_safe(cond, condb, &p->mon_fail_cond, list) {
+			LIST_DEL(&cond->list);
+			prune_acl_cond(cond);
+			free(cond);
+		}
+
 		for (exp = p->req_exp; exp != NULL; ) {
 			if (exp->preg)
 				regfree((regex_t *)exp->preg);
diff --git a/src/proto_http.c b/src/proto_http.c
index 59b9055..370fded 100644
--- a/src/proto_http.c
+++ b/src/proto_http.c
@@ -1637,7 +1637,26 @@
 			/*
 			 * We have found the monitor URI
 			 */
+			struct acl_cond *cond;
+			cur_proxy = t->fe;
+
 			t->flags |= SN_MONITOR;
+
+			/* Check if we want to fail this monitor request or not */
+			list_for_each_entry(cond, &cur_proxy->mon_fail_cond, list) {
+				int ret = acl_exec_cond(cond, cur_proxy, t, txn, ACL_DIR_REQ);
+				if (cond->pol == ACL_COND_UNLESS)
+					ret = !ret;
+
+				if (ret) {
+					/* we fail this request, let's return 503 service unavail */
+					txn->status = 503;
+					client_retnclose(t, error_message(t, HTTP_ERR_503));
+					goto return_prx_cond;
+				}
+			}
+
+			/* nothing to fail, let's reply normaly */
 			txn->status = 200;
 			client_retnclose(t, &http_200_chunk);
 			goto return_prx_cond;