This patch provides some statistics about the conditions used in the
configuration. The main goal is to have a debugging tool to track
misconfigurations or to understand how the rules are applied.

The statistics are available on the UNIX socket with the below command :

  show conds

Counters can be reset without the need to restart HAProxy, allowing the
statistics to be periodically monitored.
---
 include/common/mini-clist.h |   13 ++
 include/proto/dumpstats.h   |    3 +
 include/types/acl.h         |   10 ++
 include/types/proto_http.h  |    1 +
 include/types/proxy.h       |    2 +
 include/types/session.h     |   28 ++++-
 src/acl.c                   |   29 ++++-
 src/cfgparse.c              |    5 +
 src/dumpstats.c             |  317 ++++++++++++++++++++++++++++++++++++++++---
 9 files changed, 382 insertions(+), 26 deletions(-)

diff --git a/include/common/mini-clist.h b/include/common/mini-clist.h
index e89ffe0..0e10b47 100644
--- a/include/common/mini-clist.h
+++ b/include/common/mini-clist.h
@@ -185,6 +185,19 @@ struct cond_wordlist {
             item = LIST_ELEM(item->member.n, typeof(item), member))
 
 /*
+ * Iterates <item> through a list of items of type "typeof(*item)" which are
+ * linked via a "struct list" member named <member>, starting from a given item
+ * in the list. A pointer to the head of the list is passed in <list_head>,
+ * another pointer to the starting item is passed in <from>.
+ * No temporary variable is needed. Note that <item> must not be modified 
during
+ * the loop.
+ */
+#define list_for_each_entry_from(item, list_head, from, member) \
+       for (item = LIST_ELEM((from)->n, typeof(item), member); \
+            &item->member != (list_head);                      \
+            item = LIST_ELEM(item->member.n, typeof(item), member))
+
+/*
  * Simpler FOREACH_ITEM_SAFE macro inspired from Linux sources.
  * Iterates <item> through a list of items of type "typeof(*item)" which are
  * linked via a "struct list" member named <member>. A pointer to the head of
diff --git a/include/proto/dumpstats.h b/include/proto/dumpstats.h
index 9cf5eec..9019255 100644
--- a/include/proto/dumpstats.h
+++ b/include/proto/dumpstats.h
@@ -53,6 +53,7 @@
 #define STAT_CLI_O_SESS 6   /* dump sessions */
 #define STAT_CLI_O_ERR  7   /* dump errors */
 #define STAT_CLI_O_TAB  8   /* dump tables */
+#define STAT_CLI_O_COND 9   /* dump conditions */
 
 /* status codes (strictly 4 chars) used in the URL to display a message */
 #define STAT_STATUS_UNKN "UNKN"        /* an unknown error occured, shouldn't 
happen */
@@ -71,6 +72,8 @@ int stats_dump_proxy(struct session *s, struct proxy *px, 
struct uri_auth *uri);
 int stats_dump_sess_to_buffer(struct session *s, struct buffer *rep);
 int stats_dump_table_to_buffer(struct session *s, struct buffer *rep);
 int stats_dump_errors_to_buffer(struct session *s, struct buffer *rep);
+int stats_dump_conds_to_buffer(struct session *s, struct buffer *rep);
+int stats_dump_conds_proxy(struct session *s, struct proxy *px);
 void http_stats_io_handler(struct stream_interface *si);
 
 
diff --git a/include/types/acl.h b/include/types/acl.h
index 58ea7cc..bf8eb21 100644
--- a/include/types/acl.h
+++ b/include/types/acl.h
@@ -325,11 +325,14 @@ struct acl_term {
        struct list list;           /* chaining */
        struct acl *acl;            /* acl pointed to by this term */
        int neg;                    /* 1 if the ACL result must be negated */
+       int uid;
+       long long tot_pass, tot_fail;
 };
 
 struct acl_term_suite {
        struct list list;           /* chaining of term suites */
        struct list terms;          /* list of acl_terms */
+       int uid;
 };
 
 struct acl_cond {
@@ -339,6 +342,13 @@ struct acl_cond {
        unsigned int requires;      /* or'ed bit mask of all acl's ACL_USE_* */
        const char *file;           /* config file where the condition is 
declared */
        int line;                   /* line in the config file where the 
condition is declared */
+       int uid;
+       long long tot_pass, tot_fail;
+};
+
+struct acl_conds {
+       struct list list;           /* chaining of acl_conds */
+       struct acl_cond *cond;
 };
 
 
diff --git a/include/types/proto_http.h b/include/types/proto_http.h
index 2222304..192b5ff 100644
--- a/include/types/proto_http.h
+++ b/include/types/proto_http.h
@@ -208,6 +208,7 @@ enum {
        DATA_ST_PX_LI,
        DATA_ST_PX_SV,
        DATA_ST_PX_BE,
+       DATA_ST_PX_AC,
        DATA_ST_PX_END,
        DATA_ST_PX_FIN,
 };
diff --git a/include/types/proxy.h b/include/types/proxy.h
index 7a3276e..9671046 100644
--- a/include/types/proxy.h
+++ b/include/types/proxy.h
@@ -311,6 +311,8 @@ struct proxy {
        unsigned int bind_proc;                 /* bitmask of processes using 
this proxy. 0 = all. */
        struct error_snapshot invalid_req, invalid_rep; /* captures of last 
errors */
 
+       struct list acl_conds;                  /* the full list of acl_conds 
used by this proxy */
+
        /* used only during configuration parsing */
        int no_options;                         /* PR_O_REDISP, PR_O_TRANSP, 
... */
        int no_options2;                        /* PR_O2_* */
diff --git a/include/types/session.h b/include/types/session.h
index 0bbb9bf..5dcdad0 100644
--- a/include/types/session.h
+++ b/include/types/session.h
@@ -212,11 +212,31 @@ struct session {
        union {
                struct {
                        struct proxy *px;
-                       struct server *sv;
-                       struct listener *l;
-                       short px_st, sv_st;     /* DATA_ST_INIT or DATA_ST_DATA 
*/
+                       short px_st;            /* DATA_ST_INIT or DATA_ST_DATA 
*/
                        unsigned int flags;     /* STAT_* */
-                       int iid, type, sid;     /* proxy id, type and service 
id if bounding of stats is enabled */
+                       int iid;                /* proxy id if bounding of 
stats is enabled */
+                       union {
+                               /* used by "show conds" */
+                               struct {
+                                       int cuid, suid; /* current cond and 
suite uids being dumped */
+                                       struct list *cl;/* current cond list 
item */
+                                       struct list *sl;/* current suite list 
item  */
+                                       struct list *tl;/* current term list 
item  */
+                                       /* if bounding of stats is enabled */
+                                       int bcid;       /* acl_cond id */
+                                       int bsid;       /* acl_term_suite id */
+                                       int btid;       /* acl_term id */
+                               } conds;
+                               /* default structure for other commands */
+                               struct {
+                                       struct listener *l;
+                                       struct server *sv;
+                                       short sv_st;    /* DATA_ST_INIT or 
DATA_ST_DATA */
+                                       /* if bounding of stats is enabled */
+                                       int type;       /* type of dumpable 
objects */
+                                       int sid;        /* service id  */
+                               } def;
+                       } cmd;
                        const char *st_code;    /* pointer to the status code 
returned by an action */
                } stats;
                struct {
diff --git a/src/acl.c b/src/acl.c
index c8a5a88..aa546ed 100644
--- a/src/acl.c
+++ b/src/acl.c
@@ -29,6 +29,8 @@
 
 #include <ebsttree.h>
 
+int next_cond_uid = 1;
+
 /* The capabilities of filtering hooks describe the type of information
  * available to each of them.
  */
@@ -1406,6 +1408,7 @@ struct acl_cond *parse_acl_cond(const char **args, struct 
list *known_acl, int p
 {
        __label__ out_return, out_free_suite, out_free_term;
        int arg, neg;
+       int next_suite_uid, next_term_uid;
        const char *word;
        struct acl *cur_acl;
        struct acl_term *cur_term;
@@ -1422,6 +1425,7 @@ struct acl_cond *parse_acl_cond(const char **args, struct 
list *known_acl, int p
 
        cur_suite = NULL;
        neg = 0;
+       next_suite_uid = next_term_uid = 1;
        for (arg = 0; *args[arg]; arg++) {
                word = args[arg];
 
@@ -1477,6 +1481,8 @@ struct acl_cond *parse_acl_cond(const char **args, struct 
list *known_acl, int p
                         * it to the list of ACLs of this proxy. This makes it 
possible
                         * to override them.
                         */
+                       if (invalid_char(word))
+                               goto out_free_suite;
                        cur_acl = find_acl_by_name(word, known_acl);
                        if (cur_acl == NULL) {
                                cur_acl = find_acl_default(word, known_acl);
@@ -1494,12 +1500,15 @@ struct acl_cond *parse_acl_cond(const char **args, 
struct list *known_acl, int p
                cond->requires |= cur_acl->requires;
 
                if (!cur_suite) {
+                       next_term_uid = 1;
                        cur_suite = (struct acl_term_suite *)calloc(1, 
sizeof(*cur_suite));
-                       if (cur_term == NULL)
+                       if (cur_suite == NULL)
                                goto out_free_term;
+                       cur_suite->uid = next_suite_uid++;
                        LIST_INIT(&cur_suite->terms);
                        LIST_ADDQ(&cond->suites, &cur_suite->list);
                }
+               cur_term->uid = next_term_uid++;
                LIST_ADDQ(&cur_suite->terms, &cur_term->list);
                neg = 0;
        }
@@ -1543,6 +1552,13 @@ struct acl_cond *build_acl_cond(const char *file, int 
line, struct proxy *px, co
 
        cond->file = file;
        cond->line = line;
+       cond->uid = next_cond_uid++;
+
+       struct acl_conds *conds;
+       conds = (struct acl_conds *)calloc(1, sizeof(*conds));
+       conds->cond = cond;
+       LIST_ADDQ(&px->acl_conds, &conds->list);
+
        px->acl_requires |= cond->requires;
 
        return cond;
@@ -1674,6 +1690,11 @@ int acl_exec_cond(struct acl_cond *cond, struct proxy 
*px, struct session *l4, v
                        if (term->neg)
                                acl_res = acl_neg(acl_res);
 
+                       if (acl_res & ACL_PAT_PASS)
+                               term->tot_pass++;
+                       else
+                               term->tot_fail++;
+
                        suite_res &= acl_res;
 
                        /* we're ANDing these terms, so a single FAIL is enough 
*/
@@ -1686,6 +1707,12 @@ int acl_exec_cond(struct acl_cond *cond, struct proxy 
*px, struct session *l4, v
                if (cond_res == ACL_PAT_PASS)
                        break;
        }
+
+       if (cond_res & ACL_PAT_PASS)
+               cond->tot_pass++;
+       else
+               cond->tot_fail++;
+
        return cond_res;
 }
 
diff --git a/src/cfgparse.c b/src/cfgparse.c
index dd266af..a9e5393 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -64,6 +64,8 @@
 #include <proto/stick_table.h>
 
 
+extern int next_cond_uid;
+
 /* This is the SSLv3 CLIENT HELLO packet used in conjunction with the
  * ssl-hello-chk option to ensure that the remote server speaks SSL.
  *
@@ -1071,10 +1073,13 @@ static void init_new_proxy(struct proxy *p)
        LIST_INIT(&p->tcp_req.l4_rules);
        LIST_INIT(&p->req_add);
        LIST_INIT(&p->rsp_add);
+       LIST_INIT(&p->acl_conds);
 
        /* Timeouts are defined as -1 */
        proxy_reset_timeouts(p);
        p->tcp_rep.inspect_delay = TICK_ETERNITY;
+
+       next_cond_uid = 1;
 }
 
 void init_default_instance()
diff --git a/src/dumpstats.c b/src/dumpstats.c
index a45d40a..a254ce6 100644
--- a/src/dumpstats.c
+++ b/src/dumpstats.c
@@ -64,6 +64,7 @@ const char stats_sock_usage_msg[] =
        "  show info      : report information about the running process\n"
        "  show stat      : report counters for each proxy and server\n"
        "  show errors    : report last request and response errors for each 
proxy\n"
+       "  show conds     : report statistics about the conditions\n"
        "  show sess [id] : report the list of current sessions or dump this 
session\n"
        "  show table [id]: report table usage stats or dump this table's 
contents\n"
        "  get weight     : report a server's current weight\n"
@@ -349,12 +350,48 @@ int stats_sock_parse_request(struct stream_interface *si, 
char *line)
 
        s->data_ctx.stats.flags = 0;
        if (strcmp(args[0], "show") == 0) {
-               if (strcmp(args[1], "stat") == 0) {
+               if (strcmp(args[1], "conds") == 0) {
+                       int n = 2;
+
+                       s->data_state = DATA_ST_INIT;
+                       si->st0 = STAT_CLI_O_COND; // stats_dump_conds_to_buffer
+                       
+                       if (strcmp(args[n], "clear") == 0) {
+                               s->data_ctx.stats.flags |= STAT_ADMIN;
+                               n++;
+                       }
+                       if (*args[n]) {
+                               s->data_ctx.stats.flags |= STAT_BOUND;
+                               s->data_ctx.stats.iid = atoi(args[n]);
+                       }
+                       /* bounding cond */
+                       if (*args[n + 1]) {
+                               s->data_ctx.stats.cmd.conds.bcid = atoi(args[n 
+ 1]);
+                       }
+                       else {
+                               s->data_ctx.stats.cmd.conds.bcid = -1;
+                       }
+                       /* bounding suite */
+                       if (*args[n + 2]) {
+                               s->data_ctx.stats.cmd.conds.bsid = atoi(args[n 
+ 2]);
+                       }
+                       else {
+                               s->data_ctx.stats.cmd.conds.bsid = -1;
+                       }
+                       /* bounding term  */
+                       if (*args[n + 3]) {
+                               s->data_ctx.stats.cmd.conds.btid = atoi(args[n 
+ 3]);
+                       }
+                       else {
+                               s->data_ctx.stats.cmd.conds.btid = -1;
+                       }
+               }
+               else if (strcmp(args[1], "stat") == 0) {
                        if (*args[2] && *args[3] && *args[4]) {
                                s->data_ctx.stats.flags |= STAT_BOUND;
-                               s->data_ctx.stats.iid   = atoi(args[2]);
-                               s->data_ctx.stats.type  = atoi(args[3]);
-                               s->data_ctx.stats.sid   = atoi(args[4]);
+                               s->data_ctx.stats.iid = atoi(args[2]);
+                               s->data_ctx.stats.cmd.def.type = atoi(args[3]);
+                               s->data_ctx.stats.cmd.def.sid  = atoi(args[4]);
                        }
 
                        s->data_ctx.stats.flags |= STAT_SHOW_STAT;
@@ -930,6 +967,10 @@ void stats_io_handler(struct stream_interface *si)
                        }
 
                        switch (si->st0) {
+                       case STAT_CLI_O_COND:
+                               if (stats_dump_conds_to_buffer(s, res))
+                                       si->st0 = STAT_CLI_PROMPT;
+                               break;
                        case STAT_CLI_PRINT:
                                if (buffer_feed(si->ib, s->data_ctx.cli.msg) < 
0)
                                        si->st0 = STAT_CLI_PROMPT;
@@ -1021,6 +1062,71 @@ void stats_io_handler(struct stream_interface *si)
 }
 
 /* This function is called to send output to the response buffer.
+ * It dumps conditions statistics onto the output buffer <rep>
+ * owned by session <s>.
+ * s->data_ctx must have been zeroed first, and the flags properly set.
+ * It returns 0 as long as it does not complete, non-zero upon completion.
+ */
+int stats_dump_conds_to_buffer(struct session *s, struct buffer *rep)
+{
+       struct proxy *px;
+       struct chunk msg;
+
+       chunk_init(&msg, trash, sizeof(trash));
+
+       switch (s->data_state) {
+       case DATA_ST_INIT:
+               /* the function had not been called yet */
+               s->data_state = DATA_ST_HEAD;
+               /* fall through */
+
+       case DATA_ST_HEAD:
+               chunk_printf(&msg, "pct,pass,fail,path,detail\n");
+               if (buffer_feed_chunk(rep, &msg) >= 0)
+                       return 0;
+               s->data_state = DATA_ST_INFO;
+               /* fall through */
+
+       case DATA_ST_INFO:
+               s->data_ctx.stats.px = proxy;
+               s->data_ctx.stats.px_st = DATA_ST_PX_INIT;
+
+               s->data_state = DATA_ST_LIST;
+               /* fall through */
+
+       case DATA_ST_LIST:
+               /* dump proxies */
+               while (s->data_ctx.stats.px) {
+                       px = s->data_ctx.stats.px;
+                       /* skip the disabled proxies and non-networked ones */
+                       if (px->state != PR_STSTOPPED &&
+                               (px->cap & (PR_CAP_FE | PR_CAP_BE))) {
+                               if (stats_dump_conds_proxy(s, px) == 0)
+                                       return 0;
+                       }
+
+                       s->data_ctx.stats.px = px->next;
+                       s->data_ctx.stats.px_st = DATA_ST_PX_INIT;
+               }
+
+               s->data_state = DATA_ST_END;
+               /* fall through */
+
+       case DATA_ST_END:
+               s->data_state = DATA_ST_FIN;
+               /* fall through */
+
+       case DATA_ST_FIN:
+               return 1;
+
+       default:
+               /* unknown state ! */
+               s->data_state = DATA_ST_FIN;
+               return 1;
+       }
+}
+
+/* This function is called to send output to the response buffer.
  * It dumps statistics onto the output buffer <rep> owned by session <s>.
  * s->data_ctx must have been zeroed first, and the flags properly set.
  * It returns 0 as long as it does not complete, non-zero upon completion.
@@ -1095,8 +1201,8 @@ int stats_dump_raw_to_buffer(struct session *s, struct 
buffer *rep)
                s->data_ctx.stats.px = proxy;
                s->data_ctx.stats.px_st = DATA_ST_PX_INIT;
 
-               s->data_ctx.stats.sv = NULL;
-               s->data_ctx.stats.sv_st = 0;
+               s->data_ctx.stats.cmd.def.sv = NULL;
+               s->data_ctx.stats.cmd.def.sv_st = 0;
 
                s->data_state = DATA_ST_LIST;
                /* fall through */
@@ -1231,6 +1337,175 @@ void http_stats_io_handler(struct stream_interface *si)
 
 
 /*
+ * Dumps conditions statistics for a proxy.
+ * Returns 0 if it had to stop dumping data because of lack of buffer space,
+ * ot non-zero if everything completed.
+ */
+int stats_dump_conds_proxy(struct session *s, struct proxy *px)
+{
+       struct buffer *rep = s->rep;
+       struct acl_conds *conds;
+       struct chunk msg;
+
+       chunk_init(&msg, trash, sizeof(trash));
+
+       switch (s->data_ctx.stats.px_st) {
+       case DATA_ST_PX_INIT:
+               /* we are on a new proxy */
+               if ((s->data_ctx.stats.flags & STAT_BOUND) &&
+                   (s->data_ctx.stats.iid != -1) &&
+                   (px->uuid != s->data_ctx.stats.iid))
+                       return 1;
+
+               s->data_ctx.stats.cmd.conds.cl = &px->acl_conds;
+               s->data_ctx.stats.cmd.conds.cuid = 0;
+               if (!(s->data_ctx.stats.flags & STAT_BOUND) ||
+                    (s->data_ctx.stats.cmd.conds.bcid <= 0)) {
+                       chunk_printf(&msg, ",,,%d-0-0-0,[PROXY %s (#%d) %s]\n",
+                                    px->uuid, px->id, px->uuid, px->conf.file);
+                       if (buffer_feed_chunk(rep, &msg) >= 0)
+                               return 0;
+               }
+
+               s->data_ctx.stats.px_st = DATA_ST_PX_AC;
+               /* fall through */
+
+       case DATA_ST_PX_AC:
+               list_for_each_entry_from(conds, &px->acl_conds, 
s->data_ctx.stats.cmd.conds.cl, list) {
+                       struct acl_cond *cond;
+                       struct acl_term_suite *suite;
+
+                       cond = conds->cond;
+
+                       /* filter conds not matching the bound one */
+                       if ((s->data_ctx.stats.flags & STAT_BOUND) &&
+                           (s->data_ctx.stats.cmd.conds.bcid != -1)) {
+                               if (cond->uid < 
s->data_ctx.stats.cmd.conds.bcid) {
+                                       continue;
+                               }
+                               else if (cond->uid > 
s->data_ctx.stats.cmd.conds.bcid) {
+                                       return 1;
+                               }
+                       }
+
+                       if (cond->uid > s->data_ctx.stats.cmd.conds.cuid) {
+                               if (!(s->data_ctx.stats.flags & STAT_BOUND) ||
+                                    (s->data_ctx.stats.cmd.conds.bsid <= 0)) {
+                                       chunk_printf(&msg, 
"%.2f,%lld,%lld,%d-%d-0-0,[%s line %d]\n",
+                                               (cond->tot_pass + 
cond->tot_fail) ? 100LL * cond->tot_pass / (double) (cond->tot_pass + 
cond->tot_fail) : 0LL,
+                                               cond->tot_pass, cond->tot_fail,
+                                               px->uuid, cond->uid,
+                                               (cond->pol == ACL_COND_IF) ? 
"IF" : "UNLESS", cond->line);
+                                       if (buffer_feed_chunk(rep, &msg) >= 0)
+                                               return 0;
+                               }
+
+                               s->data_ctx.stats.cmd.conds.cuid = cond->uid;
+                               s->data_ctx.stats.cmd.conds.suid = 0;
+                               s->data_ctx.stats.cmd.conds.sl = &cond->suites;
+                       }
+
+                       list_for_each_entry_from(suite, &cond->suites, 
s->data_ctx.stats.cmd.conds.sl, list) {
+                               struct acl_term *term;
+
+                               /* filter suites not matching the bound one */
+                               if ((s->data_ctx.stats.flags & STAT_BOUND) &&
+                                   (s->data_ctx.stats.cmd.conds.bsid != -1)) {
+                                       if (suite->uid < 
s->data_ctx.stats.cmd.conds.bsid) {
+                                               continue;
+                                       }
+                                       else if (suite->uid > 
s->data_ctx.stats.cmd.conds.bsid) {
+                                               return 1;
+                                       }
+                               }
+
+                               if (suite->uid > 
s->data_ctx.stats.cmd.conds.suid) {
+                                       if ((suite->uid > 1) &&
+                                           (!(s->data_ctx.stats.flags & 
STAT_BOUND) ||
+                                             (s->data_ctx.stats.cmd.conds.bsid 
== -1))) {
+                                               chunk_printf(&msg, 
",,,%d-%d-%d-0,[OR]\n",
+                                                       px->uuid, cond->uid, 
suite->uid);
+                                               if (buffer_feed_chunk(rep, 
&msg) >= 0)
+                                                       return 0;
+                                       }
+
+                                       s->data_ctx.stats.cmd.conds.suid = 
suite->uid;
+                                       s->data_ctx.stats.cmd.conds.tl = 
&suite->terms;
+                               }
+                               list_for_each_entry_from(term, &suite->terms, 
s->data_ctx.stats.cmd.conds.tl, list) {
+                                       struct acl_expr *expr;
+                                       struct acl_keyword * keyword;
+
+                                       /* filter terms not matching the bound 
one */
+                                       if ((s->data_ctx.stats.flags & 
STAT_BOUND) &&
+                                           (s->data_ctx.stats.cmd.conds.btid 
!= -1)) {
+                                               if (term->uid < 
s->data_ctx.stats.cmd.conds.btid) {
+                                                       continue;
+                                               }
+                                               else if (term->uid > 
s->data_ctx.stats.cmd.conds.btid) {
+                                                       return 1;
+                                               }
+                                       }
+
+                                       if (!(s->data_ctx.stats.flags & 
STAT_BOUND) ||
+                                            (s->data_ctx.stats.cmd.conds.btid 
== -1) ||
+                                            (s->data_ctx.stats.cmd.conds.btid 
== term->uid)) {
+                                               /* anonymous acl, we'll display 
the first keyword */
+                                               expr = NULL;
+                                               keyword = NULL;
+                                               if (! *term->acl->name) {
+                                                       expr = 
LIST_NEXT(&term->acl->expr, struct acl_expr *, list);
+                                                       if (expr) {
+                                                               keyword = 
expr->kw;
+                                                       }
+                                               }
+
+                                               chunk_printf(&msg, 
"%.2f,%lld,%lld,%d-%d-%d-%d,%s%s%s%s%s%s%s\n",
+                                                       (term->tot_pass + 
term->tot_fail) ? 100LL * term->tot_pass / (double) (term->tot_pass + 
term->tot_fail) : 0LL,
+                                                       term->tot_pass, 
term->tot_fail,
+                                                       px->uuid, cond->uid, 
suite->uid, term->uid,
+                                                       term->neg ? "!" : "",
+                                                       keyword ?  "{ " : 
term->acl->name,
+                                                       keyword ?  keyword->kw 
: "",
+                                                       expr && expr->arg_len ? 
"(" : "",
+                                                       expr && expr->arg_len ? 
expr->arg.str : "",
+                                                       expr && expr->arg_len ? 
")" : "",
+                                                       keyword ?  " }" : "");
+                                               if (buffer_feed_chunk(rep, 
&msg) >= 0)
+                                                       return 0;
+                                       }
+
+                                       s->data_ctx.stats.cmd.conds.tl = 
&term->list;
+
+                                       if (s->data_ctx.stats.flags & 
STAT_ADMIN) {
+                                               term->tot_pass = 0;
+                                               term->tot_fail = 0;
+                                       }
+                               }
+                               s->data_ctx.stats.cmd.conds.sl = &suite->list;
+                       }
+                       
+                       s->data_ctx.stats.cmd.conds.cl = &conds->list;
+                       if (s->data_ctx.stats.flags & STAT_ADMIN) {
+                               cond->tot_pass = 0;
+                               cond->tot_fail = 0;
+                       }
+               }
+
+               s->data_ctx.stats.px_st = DATA_ST_PX_FIN;
+               /* fall through */
+
+       case DATA_ST_PX_FIN:
+               return 1;
+
+       default:
+               /* unknown state, we should put an abort() here ! */
+               return 1;
+       }
+}
+
+
+/*
  * Produces statistics data for the session <s>. Expects to be called with
  * client socket shut down on input. It stops by itself by unsetting the
  * BF_HIJACK flag from the buffer, which it uses to keep on being called
@@ -1702,7 +1977,7 @@ int stats_dump_proxy(struct session *s, struct proxy *px, 
struct uri_auth *uri)
        case DATA_ST_PX_FE:
                /* print the frontend */
                if ((px->cap & PR_CAP_FE) &&
-                   (!(s->data_ctx.stats.flags & STAT_BOUND) || 
(s->data_ctx.stats.type & (1 << STATS_TYPE_FE)))) {
+                   (!(s->data_ctx.stats.flags & STAT_BOUND) || 
(s->data_ctx.stats.cmd.def.type & (1 << STATS_TYPE_FE)))) {
                        if (!(s->data_ctx.stats.flags & STAT_FMT_CSV)) {
                                chunk_printf(&msg,
                                     /* name, queue */
@@ -1852,25 +2127,25 @@ int stats_dump_proxy(struct session *s, struct proxy 
*px, struct uri_auth *uri)
                                return 0;
                }
 
-               s->data_ctx.stats.l = px->listen; /* may be NULL */
+               s->data_ctx.stats.cmd.def.l = px->listen; /* may be NULL */
                s->data_ctx.stats.px_st = DATA_ST_PX_LI;
                /* fall through */
 
        case DATA_ST_PX_LI:
-               /* stats.l has been initialized above */
-               for (; s->data_ctx.stats.l != NULL; s->data_ctx.stats.l = 
l->next) {
+               /* stats.cmd.def.l has been initialized above */
+               for (; s->data_ctx.stats.cmd.def.l != NULL; 
s->data_ctx.stats.cmd.def.l = l->next) {
                        if (buffer_almost_full(rep))
                                return 0;
 
-                       l = s->data_ctx.stats.l;
+                       l = s->data_ctx.stats.cmd.def.l;
                        if (!l->counters)
                                continue;
 
                        if (s->data_ctx.stats.flags & STAT_BOUND) {
-                               if (!(s->data_ctx.stats.type & (1 << 
STATS_TYPE_SO)))
+                               if (!(s->data_ctx.stats.cmd.def.type & (1 << 
STATS_TYPE_SO)))
                                        break;
 
-                               if (s->data_ctx.stats.sid != -1 && l->luid != 
s->data_ctx.stats.sid)
+                               if (s->data_ctx.stats.cmd.def.sid != -1 && 
l->luid != s->data_ctx.stats.cmd.def.sid)
                                        continue;
                        }
 
@@ -1995,25 +2270,25 @@ int stats_dump_proxy(struct session *s, struct proxy 
*px, struct uri_auth *uri)
                                return 0;
                }
 
-               s->data_ctx.stats.sv = px->srv; /* may be NULL */
+               s->data_ctx.stats.cmd.def.sv = px->srv; /* may be NULL */
                s->data_ctx.stats.px_st = DATA_ST_PX_SV;
                /* fall through */
 
        case DATA_ST_PX_SV:
-               /* stats.sv has been initialized above */
-               for (; s->data_ctx.stats.sv != NULL; s->data_ctx.stats.sv = 
sv->next) {
+               /* stats.cmd.def.sv has been initialized above */
+               for (; s->data_ctx.stats.cmd.def.sv != NULL; 
s->data_ctx.stats.cmd.def.sv = sv->next) {
                        int sv_state; /* 0=DOWN, 1=going up, 2=going down, 
3=UP, 4,5=NOLB, 6=unchecked */
 
                        if (buffer_almost_full(rep))
                                return 0;
 
-                       sv = s->data_ctx.stats.sv;
+                       sv = s->data_ctx.stats.cmd.def.sv;
 
                        if (s->data_ctx.stats.flags & STAT_BOUND) {
-                               if (!(s->data_ctx.stats.type & (1 << 
STATS_TYPE_SV)))
+                               if (!(s->data_ctx.stats.cmd.def.type & (1 << 
STATS_TYPE_SV)))
                                        break;
 
-                               if (s->data_ctx.stats.sid != -1 && sv->puid != 
s->data_ctx.stats.sid)
+                               if (s->data_ctx.stats.cmd.def.sid != -1 && 
sv->puid != s->data_ctx.stats.cmd.def.sid)
                                        continue;
                        }
 
@@ -2042,7 +2317,7 @@ int stats_dump_proxy(struct session *s, struct proxy *px, 
struct uri_auth *uri)
 
                        if (((sv_state == 0) || (sv->state & SRV_MAINTAIN)) && 
(s->data_ctx.stats.flags & STAT_HIDE_DOWN)) {
                                /* do not report servers which are DOWN */
-                               s->data_ctx.stats.sv = sv->next;
+                               s->data_ctx.stats.cmd.def.sv = sv->next;
                                continue;
                        }
 
@@ -2400,7 +2675,7 @@ int stats_dump_proxy(struct session *s, struct proxy *px, 
struct uri_auth *uri)
        case DATA_ST_PX_BE:
                /* print the backend */
                if ((px->cap & PR_CAP_BE) &&
-                   (!(s->data_ctx.stats.flags & STAT_BOUND) || 
(s->data_ctx.stats.type & (1 << STATS_TYPE_BE)))) {
+                   (!(s->data_ctx.stats.flags & STAT_BOUND) || 
(s->data_ctx.stats.cmd.def.type & (1 << STATS_TYPE_BE)))) {
                        if (!(s->data_ctx.stats.flags & STAT_FMT_CSV)) {
                                chunk_printf(&msg, "<tr class=\"backend\">");
                                if (px->cap & PR_CAP_BE && px->srv && 
(s->data_ctx.stats.flags & STAT_ADMIN)) {
-- 
1.7.1


Reply via email to