]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
REORG: http: move HTTP rules parsing to http_rules.c
authorWilly Tarreau <w@1wt.eu>
Tue, 2 Oct 2018 14:43:32 +0000 (16:43 +0200)
committerWilly Tarreau <w@1wt.eu>
Tue, 2 Oct 2018 16:28:05 +0000 (18:28 +0200)
These ones are mostly called from cfgparse.c for the parsing and do
not depend on the HTTP representation. The functions's prototypes
were moved to proto/http_rules.h, making this file work exactly like
tcp_rules. Ideally we should stop calling these functions directly
from cfgparse and register keywords, but there are a few cases where
that wouldn't work (stats http-request) so it's probably not worth
trying to go this far.

19 files changed:
Makefile
include/proto/http_rules.h [new file with mode: 0644]
include/proto/proto_http.h
include/proto/stream.h
include/types/proto_http.h
src/cache.c
src/cfgparse.c
src/flt_spoe.c
src/haproxy.c
src/hlua.c
src/http_act.c
src/http_rules.c [new file with mode: 0644]
src/proto_http.c
src/proto_tcp.c
src/queue.c
src/ssl_sock.c
src/stick_table.c
src/stream.c
src/vars.c

index 3140a4ac33c917c89f162e04da8c3b6458f0eca3..5cf4ce0b66aa0d0749483049b6254c6443662c82 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -895,7 +895,7 @@ OBJS = src/proto_http.o src/cfgparse.o src/server.o src/stream.o        \
        src/protocol.o src/lru.o src/hdr_idx.o src/hpack-huff.o          \
        src/mailers.o src/h2.o src/base64.o src/hash.o src/http.o       \
        src/http_acl.o src/http_fetch.o src/http_conv.o src/http_act.o   \
-       src/proto_sockpair.o
+       src/http_rules.o src/proto_sockpair.o
 
 EBTREE_OBJS = $(EBTREE_DIR)/ebtree.o $(EBTREE_DIR)/eb32sctree.o \
               $(EBTREE_DIR)/eb32tree.o $(EBTREE_DIR)/eb64tree.o \
diff --git a/include/proto/http_rules.h b/include/proto/http_rules.h
new file mode 100644 (file)
index 0000000..5e03dd8
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * include/proto/http_rules.h
+ * This file contains "http" rules definitions
+ *
+ * Copyright (C) 2000-2018 Willy Tarreau - w@1wt.eu
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, version 2.1
+ * exclusively.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef _PROTO_HTTP_RULES_H
+#define _PROTO_HTTP_RULES_H
+
+#include <common/config.h>
+#include <common/mini-clist.h>
+#include <types/action.h>
+#include <types/proxy.h>
+
+extern struct action_kw_list http_req_keywords;
+extern struct action_kw_list http_res_keywords;
+
+struct act_rule *parse_http_req_cond(const char **args, const char *file, int linenum, struct proxy *proxy);
+struct act_rule *parse_http_res_cond(const char **args, const char *file, int linenum, struct proxy *proxy);
+void free_http_req_rules(struct list *r);
+void free_http_res_rules(struct list *r);
+struct redirect_rule *http_parse_redirect_rule(const char *file, int linenum, struct proxy *curproxy,
+                                               const char **args, char **errmsg, int use_fmt, int dir);
+
+static inline void http_req_keywords_register(struct action_kw_list *kw_list)
+{
+       LIST_ADDQ(&http_req_keywords.list, &kw_list->list);
+}
+
+static inline void http_res_keywords_register(struct action_kw_list *kw_list)
+{
+       LIST_ADDQ(&http_res_keywords.list, &kw_list->list);
+}
+
+#endif /* _PROTO_HTTP_RULES_H */
+
+/*
+ * Local variables:
+ *  c-indent-level: 8
+ *  c-basic-offset: 8
+ * End:
+ */
index da6d0c74a56cc7d87b30af66181d43f2d320c00b..daa72bb6370042c390b4c226f4491da19368b8f1 100644 (file)
@@ -23,7 +23,6 @@
 #define _PROTO_PROTO_HTTP_H
 
 #include <common/config.h>
-#include <types/action.h>
 #include <types/proto_http.h>
 #include <types/stream.h>
 #include <types/task.h>
@@ -115,28 +114,8 @@ void http_reset_txn(struct stream *s);
 void http_end_txn_clean_session(struct stream *s);
 void http_adjust_conn_mode(struct stream *s, struct http_txn *txn, struct http_msg *msg);
 
-struct act_rule *parse_http_req_cond(const char **args, const char *file, int linenum, struct proxy *proxy);
-struct act_rule *parse_http_res_cond(const char **args, const char *file, int linenum, struct proxy *proxy);
-void free_http_req_rules(struct list *r);
-void free_http_res_rules(struct list *r);
 void http_reply_and_close(struct stream *s, short status, struct buffer *msg);
 struct buffer *http_error_message(struct stream *s);
-struct redirect_rule *http_parse_redirect_rule(const char *file, int linenum, struct proxy *curproxy,
-                                               const char **args, char **errmsg, int use_fmt, int dir);
-
-struct action_kw *action_http_req_custom(const char *kw);
-struct action_kw *action_http_res_custom(const char *kw);
-
-static inline void http_req_keywords_register(struct action_kw_list *kw_list)
-{
-       LIST_ADDQ(&http_req_keywords.list, &kw_list->list);
-}
-
-static inline void http_res_keywords_register(struct action_kw_list *kw_list)
-{
-       LIST_ADDQ(&http_res_keywords.list, &kw_list->list);
-}
-
 
 /* to be used when contents change in an HTTP message */
 #define http_msg_move_end(msg, bytes) do { \
index 5e7c4ccde11fed39bfd11c5acec81b8d0d3ffd7d..0e1cf66e0bbee0cc6bf8dfda10519b7af3069dbb 100644 (file)
@@ -24,6 +24,7 @@
 
 #include <common/config.h>
 #include <common/memory.h>
+#include <types/action.h>
 #include <types/stream.h>
 #include <proto/fd.h>
 #include <proto/freq_ctr.h>
index 5cb05894477e7302bca51beb82315b74c9bc60b2..1b10c0790d10567ad95c1ecce12c2f7cf7ca1359 100644 (file)
@@ -317,9 +317,6 @@ struct hdr_ctx {
        int  prev; /* index of previous header */
 };
 
-extern struct action_kw_list http_req_keywords;
-extern struct action_kw_list http_res_keywords;
-
 extern struct pool_head *pool_head_http_txn;
 
 #endif /* _TYPES_PROTO_HTTP_H */
index 3abb46cea98f42642f50239dddb99a76c71d8dfd..2024642f9f61ba80b63d3e2eba21754edb8bdd3d 100644 (file)
@@ -24,6 +24,7 @@
 #include <proto/proxy.h>
 #include <proto/hdr_idx.h>
 #include <proto/filters.h>
+#include <proto/http_rules.h>
 #include <proto/proto_http.h>
 #include <proto/log.h>
 #include <proto/stream.h>
index e20ab72daa4d4f036d22951690e6916359ff0bae..e5d6082f9f37e1649c17375643f62d471148f13f 100644 (file)
@@ -66,6 +66,7 @@
 #include <proto/filters.h>
 #include <proto/frontend.h>
 #include <proto/hdr_idx.h>
+#include <proto/http_rules.h>
 #include <proto/lb_chash.h>
 #include <proto/lb_fas.h>
 #include <proto/lb_fwlc.h>
index 73e8f623a382db7e4c6b3797aef99a3fd08682fe..81af855fdf57b6e0784b15f96c56fc1946f6be32 100644 (file)
@@ -31,6 +31,7 @@
 #include <proto/filters.h>
 #include <proto/freq_ctr.h>
 #include <proto/frontend.h>
+#include <proto/http_rules.h>
 #include <proto/log.h>
 #include <proto/proto_http.h>
 #include <proto/proxy.h>
index 3bf1f3bcd8b564ed5b4a22176c6de9ec25871b06..728e71d9affdc0de17fafc766712b3e265f617ec 100644 (file)
@@ -99,6 +99,7 @@
 #include <proto/filters.h>
 #include <proto/hdr_idx.h>
 #include <proto/hlua.h>
+#include <proto/http_rules.h>
 #include <proto/listener.h>
 #include <proto/log.h>
 #include <proto/pattern.h>
index c2be5f9f80690f87b86b2c418055141422663bec..aaa884073df8678ec1c2a8ef22a52c3af17b57c2 100644 (file)
@@ -43,6 +43,7 @@
 #include <proto/hlua.h>
 #include <proto/hlua_fcn.h>
 #include <proto/http_fetch.h>
+#include <proto/http_rules.h>
 #include <proto/map.h>
 #include <proto/obj_type.h>
 #include <proto/queue.h>
index 6ed4852f181a430ed072133d4f5d70f3ce59741a..8ca6ba482767f8addf3bf61baeb428ee66420804 100644 (file)
@@ -30,6 +30,7 @@
 
 #include <proto/acl.h>
 #include <proto/arg.h>
+#include <proto/http_rules.h>
 #include <proto/log.h>
 #include <proto/proto_http.h>
 
diff --git a/src/http_rules.c b/src/http_rules.c
new file mode 100644 (file)
index 0000000..ce67240
--- /dev/null
@@ -0,0 +1,1212 @@
+/*
+ * HTTP rules parsing and registration
+ *
+ * Copyright 2000-2018 Willy Tarreau <w@1wt.eu>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <sys/types.h>
+
+#include <ctype.h>
+#include <string.h>
+#include <time.h>
+
+#include <common/cfgparse.h>
+#include <common/chunk.h>
+#include <common/compat.h>
+#include <common/config.h>
+#include <common/debug.h>
+#include <common/http.h>
+#include <common/memory.h>
+#include <common/standard.h>
+#include <common/version.h>
+
+#include <types/capture.h>
+#include <types/global.h>
+
+#include <proto/acl.h>
+#include <proto/action.h>
+#include <proto/arg.h>
+#include <proto/http_rules.h>
+#include <proto/proto_http.h>
+#include <proto/sample.h>
+
+
+/* List head of all known action keywords for "http-request" */
+struct action_kw_list http_req_keywords = {
+       .list = LIST_HEAD_INIT(http_req_keywords.list)
+};
+
+/* List head of all known action keywords for "http-response" */
+struct action_kw_list http_res_keywords = {
+       .list = LIST_HEAD_INIT(http_res_keywords.list)
+};
+
+/*
+ * Return the struct http_req_action_kw associated to a keyword.
+ */
+static struct action_kw *action_http_req_custom(const char *kw)
+{
+       return action_lookup(&http_req_keywords.list, kw);
+}
+
+/*
+ * Return the struct http_res_action_kw associated to a keyword.
+ */
+static struct action_kw *action_http_res_custom(const char *kw)
+{
+       return action_lookup(&http_res_keywords.list, kw);
+}
+
+/* parse an "http-request" rule */
+struct act_rule *parse_http_req_cond(const char **args, const char *file, int linenum, struct proxy *proxy)
+{
+       struct act_rule *rule;
+       struct action_kw *custom = NULL;
+       int cur_arg;
+       char *error;
+
+       rule = calloc(1, sizeof(*rule));
+       if (!rule) {
+               ha_alert("parsing [%s:%d]: out of memory.\n", file, linenum);
+               goto out_err;
+       }
+
+       if (!strcmp(args[0], "allow")) {
+               rule->action = ACT_ACTION_ALLOW;
+               cur_arg = 1;
+       } else if (!strcmp(args[0], "deny") || !strcmp(args[0], "block") || !strcmp(args[0], "tarpit")) {
+               int code;
+               int hc;
+
+               if (!strcmp(args[0], "tarpit")) {
+                   rule->action = ACT_HTTP_REQ_TARPIT;
+                   rule->deny_status = HTTP_ERR_500;
+               }
+               else {
+                       rule->action = ACT_ACTION_DENY;
+                       rule->deny_status = HTTP_ERR_403;
+               }
+               cur_arg = 1;
+                if (strcmp(args[cur_arg], "deny_status") == 0) {
+                        cur_arg++;
+                        if (!args[cur_arg]) {
+                                ha_alert("parsing [%s:%d] : error detected in %s '%s' while parsing 'http-request %s' rule : missing status code.\n",
+                                        file, linenum, proxy_type_str(proxy), proxy->id, args[0]);
+                                goto out_err;
+                        }
+
+                        code = atol(args[cur_arg]);
+                        cur_arg++;
+                        for (hc = 0; hc < HTTP_ERR_SIZE; hc++) {
+                                if (http_err_codes[hc] == code) {
+                                        rule->deny_status = hc;
+                                        break;
+                                }
+                        }
+
+                        if (hc >= HTTP_ERR_SIZE) {
+                                ha_warning("parsing [%s:%d] : status code %d not handled, using default code %d.\n",
+                                          file, linenum, code, http_err_codes[rule->deny_status]);
+                        }
+                }
+       } else if (!strcmp(args[0], "auth")) {
+               rule->action = ACT_HTTP_REQ_AUTH;
+               cur_arg = 1;
+
+               while(*args[cur_arg]) {
+                       if (!strcmp(args[cur_arg], "realm")) {
+                               rule->arg.auth.realm = strdup(args[cur_arg + 1]);
+                               cur_arg+=2;
+                               continue;
+                       } else
+                               break;
+               }
+       } else if (!strcmp(args[0], "set-nice")) {
+               rule->action = ACT_HTTP_SET_NICE;
+               cur_arg = 1;
+
+               if (!*args[cur_arg] ||
+                   (*args[cur_arg + 1] && strcmp(args[cur_arg + 1], "if") != 0 && strcmp(args[cur_arg + 1], "unless") != 0)) {
+                       ha_alert("parsing [%s:%d]: 'http-request %s' expects exactly 1 argument (integer value).\n",
+                                file, linenum, args[0]);
+                       goto out_err;
+               }
+               rule->arg.nice = atoi(args[cur_arg]);
+               if (rule->arg.nice < -1024)
+                       rule->arg.nice = -1024;
+               else if (rule->arg.nice > 1024)
+                       rule->arg.nice = 1024;
+               cur_arg++;
+       } else if (!strcmp(args[0], "set-tos")) {
+#ifdef IP_TOS
+               char *err;
+               rule->action = ACT_HTTP_SET_TOS;
+               cur_arg = 1;
+
+               if (!*args[cur_arg] ||
+                   (*args[cur_arg + 1] && strcmp(args[cur_arg + 1], "if") != 0 && strcmp(args[cur_arg + 1], "unless") != 0)) {
+                       ha_alert("parsing [%s:%d]: 'http-request %s' expects exactly 1 argument (integer/hex value).\n",
+                                file, linenum, args[0]);
+                       goto out_err;
+               }
+
+               rule->arg.tos = strtol(args[cur_arg], &err, 0);
+               if (err && *err != '\0') {
+                       ha_alert("parsing [%s:%d]: invalid character starting at '%s' in 'http-request %s' (integer/hex value expected).\n",
+                                file, linenum, err, args[0]);
+                       goto out_err;
+               }
+               cur_arg++;
+#else
+               ha_alert("parsing [%s:%d]: 'http-request %s' is not supported on this platform (IP_TOS undefined).\n", file, linenum, args[0]);
+               goto out_err;
+#endif
+       } else if (!strcmp(args[0], "set-mark")) {
+#ifdef SO_MARK
+               char *err;
+               rule->action = ACT_HTTP_SET_MARK;
+               cur_arg = 1;
+
+               if (!*args[cur_arg] ||
+                   (*args[cur_arg + 1] && strcmp(args[cur_arg + 1], "if") != 0 && strcmp(args[cur_arg + 1], "unless") != 0)) {
+                       ha_alert("parsing [%s:%d]: 'http-request %s' expects exactly 1 argument (integer/hex value).\n",
+                                file, linenum, args[0]);
+                       goto out_err;
+               }
+
+               rule->arg.mark = strtoul(args[cur_arg], &err, 0);
+               if (err && *err != '\0') {
+                       ha_alert("parsing [%s:%d]: invalid character starting at '%s' in 'http-request %s' (integer/hex value expected).\n",
+                                file, linenum, err, args[0]);
+                       goto out_err;
+               }
+               cur_arg++;
+               global.last_checks |= LSTCHK_NETADM;
+#else
+               ha_alert("parsing [%s:%d]: 'http-request %s' is not supported on this platform (SO_MARK undefined).\n", file, linenum, args[0]);
+               goto out_err;
+#endif
+       } else if (!strcmp(args[0], "set-log-level")) {
+               rule->action = ACT_HTTP_SET_LOGL;
+               cur_arg = 1;
+
+               if (!*args[cur_arg] ||
+                   (*args[cur_arg + 1] && strcmp(args[cur_arg + 1], "if") != 0 && strcmp(args[cur_arg + 1], "unless") != 0)) {
+               bad_log_level:
+                       ha_alert("parsing [%s:%d]: 'http-request %s' expects exactly 1 argument (log level name or 'silent').\n",
+                                file, linenum, args[0]);
+                       goto out_err;
+               }
+               if (strcmp(args[cur_arg], "silent") == 0)
+                       rule->arg.loglevel = -1;
+               else if ((rule->arg.loglevel = get_log_level(args[cur_arg]) + 1) == 0)
+                       goto bad_log_level;
+               cur_arg++;
+       } else if (strcmp(args[0], "add-header") == 0 || strcmp(args[0], "set-header") == 0) {
+               rule->action = *args[0] == 'a' ? ACT_HTTP_ADD_HDR : ACT_HTTP_SET_HDR;
+               cur_arg = 1;
+
+               if (!*args[cur_arg] || !*args[cur_arg+1] ||
+                   (*args[cur_arg+2] && strcmp(args[cur_arg+2], "if") != 0 && strcmp(args[cur_arg+2], "unless") != 0)) {
+                       ha_alert("parsing [%s:%d]: 'http-request %s' expects exactly 2 arguments.\n",
+                                file, linenum, args[0]);
+                       goto out_err;
+               }
+
+               rule->arg.hdr_add.name = strdup(args[cur_arg]);
+               rule->arg.hdr_add.name_len = strlen(rule->arg.hdr_add.name);
+               LIST_INIT(&rule->arg.hdr_add.fmt);
+
+               proxy->conf.args.ctx = ARGC_HRQ;
+               error = NULL;
+               if (!parse_logformat_string(args[cur_arg + 1], proxy, &rule->arg.hdr_add.fmt, LOG_OPT_HTTP,
+                                           (proxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR, &error)) {
+                       ha_alert("parsing [%s:%d]: 'http-request %s': %s.\n",
+                                file, linenum, args[0], error);
+                       free(error);
+                       goto out_err;
+               }
+               free(proxy->conf.lfs_file);
+               proxy->conf.lfs_file = strdup(proxy->conf.args.file);
+               proxy->conf.lfs_line = proxy->conf.args.line;
+               cur_arg += 2;
+       } else if (strcmp(args[0], "replace-header") == 0 || strcmp(args[0], "replace-value") == 0) {
+               rule->action = args[0][8] == 'h' ? ACT_HTTP_REPLACE_HDR : ACT_HTTP_REPLACE_VAL;
+               cur_arg = 1;
+
+               if (!*args[cur_arg] || !*args[cur_arg+1] || !*args[cur_arg+2] ||
+                   (*args[cur_arg+3] && strcmp(args[cur_arg+3], "if") != 0 && strcmp(args[cur_arg+3], "unless") != 0)) {
+                       ha_alert("parsing [%s:%d]: 'http-request %s' expects exactly 3 arguments.\n",
+                                file, linenum, args[0]);
+                       goto out_err;
+               }
+
+               rule->arg.hdr_add.name = strdup(args[cur_arg]);
+               rule->arg.hdr_add.name_len = strlen(rule->arg.hdr_add.name);
+               LIST_INIT(&rule->arg.hdr_add.fmt);
+
+               error = NULL;
+               if (!regex_comp(args[cur_arg + 1], &rule->arg.hdr_add.re, 1, 1, &error)) {
+                       ha_alert("parsing [%s:%d] : '%s' : %s.\n", file, linenum,
+                                args[cur_arg + 1], error);
+                       free(error);
+                       goto out_err;
+               }
+
+               proxy->conf.args.ctx = ARGC_HRQ;
+               error = NULL;
+               if (!parse_logformat_string(args[cur_arg + 2], proxy, &rule->arg.hdr_add.fmt, LOG_OPT_HTTP,
+                                           (proxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR, &error)) {
+                       ha_alert("parsing [%s:%d]: 'http-request %s': %s.\n",
+                                file, linenum, args[0], error);
+                       free(error);
+                       goto out_err;
+               }
+
+               free(proxy->conf.lfs_file);
+               proxy->conf.lfs_file = strdup(proxy->conf.args.file);
+               proxy->conf.lfs_line = proxy->conf.args.line;
+               cur_arg += 3;
+       } else if (strcmp(args[0], "del-header") == 0) {
+               rule->action = ACT_HTTP_DEL_HDR;
+               cur_arg = 1;
+
+               if (!*args[cur_arg] ||
+                   (*args[cur_arg+1] && strcmp(args[cur_arg+1], "if") != 0 && strcmp(args[cur_arg+1], "unless") != 0)) {
+                       ha_alert("parsing [%s:%d]: 'http-request %s' expects exactly 1 argument.\n",
+                                file, linenum, args[0]);
+                       goto out_err;
+               }
+
+               rule->arg.hdr_add.name = strdup(args[cur_arg]);
+               rule->arg.hdr_add.name_len = strlen(rule->arg.hdr_add.name);
+
+               proxy->conf.args.ctx = ARGC_HRQ;
+               free(proxy->conf.lfs_file);
+               proxy->conf.lfs_file = strdup(proxy->conf.args.file);
+               proxy->conf.lfs_line = proxy->conf.args.line;
+               cur_arg += 1;
+       } else if (strncmp(args[0], "track-sc", 8) == 0) {
+               struct sample_expr *expr;
+               unsigned int where;
+               char *err = NULL;
+               unsigned int tsc_num;
+               const char *tsc_num_str;
+
+               cur_arg = 1;
+               proxy->conf.args.ctx = ARGC_TRK;
+
+               tsc_num_str = &args[0][8];
+               if (cfg_parse_track_sc_num(&tsc_num, tsc_num_str, tsc_num_str + strlen(tsc_num_str), &err) == -1) {
+                       ha_alert("parsing [%s:%d] : error detected in %s '%s' while parsing 'http-request %s' rule : %s.\n",
+                                file, linenum, proxy_type_str(proxy), proxy->id, args[0], err);
+                       free(err);
+                       goto out_err;
+               }
+
+               expr = sample_parse_expr((char **)args, &cur_arg, file, linenum, &err, &proxy->conf.args);
+               if (!expr) {
+                       ha_alert("parsing [%s:%d] : error detected in %s '%s' while parsing 'http-request %s' rule : %s.\n",
+                                file, linenum, proxy_type_str(proxy), proxy->id, args[0], err);
+                       free(err);
+                       goto out_err;
+               }
+
+               where = 0;
+               if (proxy->cap & PR_CAP_FE)
+                       where |= SMP_VAL_FE_HRQ_HDR;
+               if (proxy->cap & PR_CAP_BE)
+                       where |= SMP_VAL_BE_HRQ_HDR;
+
+               if (!(expr->fetch->val & where)) {
+                       ha_alert("parsing [%s:%d] : error detected in %s '%s' while parsing 'http-request %s' rule :"
+                                " fetch method '%s' extracts information from '%s', none of which is available here.\n",
+                                file, linenum, proxy_type_str(proxy), proxy->id, args[0],
+                                args[cur_arg-1], sample_src_names(expr->fetch->use));
+                       free(expr);
+                       goto out_err;
+               }
+
+               if (strcmp(args[cur_arg], "table") == 0) {
+                       cur_arg++;
+                       if (!args[cur_arg]) {
+                               ha_alert("parsing [%s:%d] : error detected in %s '%s' while parsing 'http-request %s' rule : missing table name.\n",
+                                        file, linenum, proxy_type_str(proxy), proxy->id, args[0]);
+                               free(expr);
+                               goto out_err;
+                       }
+                       /* we copy the table name for now, it will be resolved later */
+                       rule->arg.trk_ctr.table.n = strdup(args[cur_arg]);
+                       cur_arg++;
+               }
+               rule->arg.trk_ctr.expr = expr;
+               rule->action = ACT_ACTION_TRK_SC0 + tsc_num;
+               rule->check_ptr = check_trk_action;
+       } else if (strcmp(args[0], "redirect") == 0) {
+               struct redirect_rule *redir;
+               char *errmsg = NULL;
+
+               if ((redir = http_parse_redirect_rule(file, linenum, proxy, (const char **)args + 1, &errmsg, 1, 0)) == NULL) {
+                       ha_alert("parsing [%s:%d] : error detected in %s '%s' while parsing 'http-request %s' rule : %s.\n",
+                                file, linenum, proxy_type_str(proxy), proxy->id, args[0], errmsg);
+                       goto out_err;
+               }
+
+               /* this redirect rule might already contain a parsed condition which
+                * we'll pass to the http-request rule.
+                */
+               rule->action = ACT_HTTP_REDIR;
+               rule->arg.redir = redir;
+               rule->cond = redir->cond;
+               redir->cond = NULL;
+               cur_arg = 2;
+               return rule;
+       } else if (strncmp(args[0], "add-acl", 7) == 0) {
+               /* http-request add-acl(<reference (acl name)>) <key pattern> */
+               rule->action = ACT_HTTP_ADD_ACL;
+               /*
+                * '+ 8' for 'add-acl('
+                * '- 9' for 'add-acl(' + trailing ')'
+                */
+               rule->arg.map.ref = my_strndup(args[0] + 8, strlen(args[0]) - 9);
+
+               cur_arg = 1;
+
+               if (!*args[cur_arg] ||
+                   (*args[cur_arg+1] && strcmp(args[cur_arg+1], "if") != 0 && strcmp(args[cur_arg+1], "unless") != 0)) {
+                       ha_alert("parsing [%s:%d]: 'http-request %s' expects exactly 1 argument.\n",
+                                file, linenum, args[0]);
+                       goto out_err;
+               }
+
+               LIST_INIT(&rule->arg.map.key);
+               proxy->conf.args.ctx = ARGC_HRQ;
+               error = NULL;
+               if (!parse_logformat_string(args[cur_arg], proxy, &rule->arg.map.key, LOG_OPT_HTTP,
+                                           (proxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR, &error)) {
+                       ha_alert("parsing [%s:%d]: 'http-request %s': %s.\n",
+                                file, linenum, args[0], error);
+                       free(error);
+                       goto out_err;
+               }
+               free(proxy->conf.lfs_file);
+               proxy->conf.lfs_file = strdup(proxy->conf.args.file);
+               proxy->conf.lfs_line = proxy->conf.args.line;
+               cur_arg += 1;
+       } else if (strncmp(args[0], "del-acl", 7) == 0) {
+               /* http-request del-acl(<reference (acl name)>) <key pattern> */
+               rule->action = ACT_HTTP_DEL_ACL;
+               /*
+                * '+ 8' for 'del-acl('
+                * '- 9' for 'del-acl(' + trailing ')'
+                */
+               rule->arg.map.ref = my_strndup(args[0] + 8, strlen(args[0]) - 9);
+
+               cur_arg = 1;
+
+               if (!*args[cur_arg] ||
+                   (*args[cur_arg+1] && strcmp(args[cur_arg+1], "if") != 0 && strcmp(args[cur_arg+1], "unless") != 0)) {
+                       ha_alert("parsing [%s:%d]: 'http-request %s' expects exactly 1 argument.\n",
+                                file, linenum, args[0]);
+                       goto out_err;
+               }
+
+               LIST_INIT(&rule->arg.map.key);
+               proxy->conf.args.ctx = ARGC_HRQ;
+               error = NULL;
+               if (!parse_logformat_string(args[cur_arg], proxy, &rule->arg.map.key, LOG_OPT_HTTP,
+                                           (proxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR, &error)) {
+                       ha_alert("parsing [%s:%d]: 'http-request %s': %s.\n",
+                                file, linenum, args[0], error);
+                       free(error);
+                       goto out_err;
+               }
+               free(proxy->conf.lfs_file);
+               proxy->conf.lfs_file = strdup(proxy->conf.args.file);
+               proxy->conf.lfs_line = proxy->conf.args.line;
+               cur_arg += 1;
+       } else if (strncmp(args[0], "del-map", 7) == 0) {
+               /* http-request del-map(<reference (map name)>) <key pattern> */
+               rule->action = ACT_HTTP_DEL_MAP;
+               /*
+                * '+ 8' for 'del-map('
+                * '- 9' for 'del-map(' + trailing ')'
+                */
+               rule->arg.map.ref = my_strndup(args[0] + 8, strlen(args[0]) - 9);
+
+               cur_arg = 1;
+
+               if (!*args[cur_arg] ||
+                   (*args[cur_arg+1] && strcmp(args[cur_arg+1], "if") != 0 && strcmp(args[cur_arg+1], "unless") != 0)) {
+                       ha_alert("parsing [%s:%d]: 'http-request %s' expects exactly 1 argument.\n",
+                                file, linenum, args[0]);
+                       goto out_err;
+               }
+
+               LIST_INIT(&rule->arg.map.key);
+               proxy->conf.args.ctx = ARGC_HRQ;
+               error = NULL;
+               if (!parse_logformat_string(args[cur_arg], proxy, &rule->arg.map.key, LOG_OPT_HTTP,
+                                           (proxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR, &error)) {
+                       ha_alert("parsing [%s:%d]: 'http-request %s': %s.\n",
+                                file, linenum, args[0], error);
+                       free(error);
+                       goto out_err;
+               }
+               free(proxy->conf.lfs_file);
+               proxy->conf.lfs_file = strdup(proxy->conf.args.file);
+               proxy->conf.lfs_line = proxy->conf.args.line;
+               cur_arg += 1;
+       } else if (strncmp(args[0], "set-map", 7) == 0) {
+               /* http-request set-map(<reference (map name)>) <key pattern> <value pattern> */
+               rule->action = ACT_HTTP_SET_MAP;
+               /*
+                * '+ 8' for 'set-map('
+                * '- 9' for 'set-map(' + trailing ')'
+                */
+               rule->arg.map.ref = my_strndup(args[0] + 8, strlen(args[0]) - 9);
+
+               cur_arg = 1;
+
+               if (!*args[cur_arg] || !*args[cur_arg+1] ||
+                   (*args[cur_arg+2] && strcmp(args[cur_arg+2], "if") != 0 && strcmp(args[cur_arg+2], "unless") != 0)) {
+                       ha_alert("parsing [%s:%d]: 'http-request %s' expects exactly 2 arguments.\n",
+                                file, linenum, args[0]);
+                       goto out_err;
+               }
+
+               LIST_INIT(&rule->arg.map.key);
+               LIST_INIT(&rule->arg.map.value);
+               proxy->conf.args.ctx = ARGC_HRQ;
+
+               /* key pattern */
+               error = NULL;
+               if (!parse_logformat_string(args[cur_arg], proxy, &rule->arg.map.key, LOG_OPT_HTTP,
+                                           (proxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR, &error)) {
+                       ha_alert("parsing [%s:%d]: 'http-request %s' key: %s.\n",
+                                file, linenum, args[0], error);
+                       free(error);
+                       goto out_err;
+               }
+
+               /* value pattern */
+               error = NULL;
+               if (!parse_logformat_string(args[cur_arg + 1], proxy, &rule->arg.map.value, LOG_OPT_HTTP,
+                                           (proxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR, &error)) {
+                       ha_alert("parsing [%s:%d]: 'http-request %s' pattern: %s.\n",
+                                file, linenum, args[0], error);
+                       free(error);
+                       goto out_err;
+               }
+               free(proxy->conf.lfs_file);
+               proxy->conf.lfs_file = strdup(proxy->conf.args.file);
+               proxy->conf.lfs_line = proxy->conf.args.line;
+
+               cur_arg += 2;
+       } else if (((custom = action_http_req_custom(args[0])) != NULL)) {
+               char *errmsg = NULL;
+               cur_arg = 1;
+               /* try in the module list */
+               rule->from = ACT_F_HTTP_REQ;
+               rule->kw = custom;
+               if (custom->parse(args, &cur_arg, proxy, rule, &errmsg) == ACT_RET_PRS_ERR) {
+                       ha_alert("parsing [%s:%d] : error detected in %s '%s' while parsing 'http-request %s' rule : %s.\n",
+                                file, linenum, proxy_type_str(proxy), proxy->id, args[0], errmsg);
+                       free(errmsg);
+                       goto out_err;
+               }
+       } else {
+               action_build_list(&http_req_keywords.list, &trash);
+               ha_alert("parsing [%s:%d]: 'http-request' expects 'allow', 'deny', 'auth', 'redirect', "
+                        "'tarpit', 'add-header', 'set-header', 'replace-header', 'replace-value', 'set-nice', "
+                        "'set-tos', 'set-mark', 'set-log-level', 'add-acl', 'del-acl', 'del-map', 'set-map', 'track-sc*'"
+                        "%s%s, but got '%s'%s.\n",
+                        file, linenum, *trash.area ? ", " : "", trash.area,
+                        args[0], *args[0] ? "" : " (missing argument)");
+               goto out_err;
+       }
+
+       if (strcmp(args[cur_arg], "if") == 0 || strcmp(args[cur_arg], "unless") == 0) {
+               struct acl_cond *cond;
+               char *errmsg = NULL;
+
+               if ((cond = build_acl_cond(file, linenum, &proxy->acl, proxy, args+cur_arg, &errmsg)) == NULL) {
+                       ha_alert("parsing [%s:%d] : error detected while parsing an 'http-request %s' condition : %s.\n",
+                                file, linenum, args[0], errmsg);
+                       free(errmsg);
+                       goto out_err;
+               }
+               rule->cond = cond;
+       }
+       else if (*args[cur_arg]) {
+               ha_alert("parsing [%s:%d]: 'http-request %s' expects 'realm' for 'auth' or"
+                        " either 'if' or 'unless' followed by a condition but found '%s'.\n",
+                        file, linenum, args[0], args[cur_arg]);
+               goto out_err;
+       }
+
+       return rule;
+ out_err:
+       free(rule);
+       return NULL;
+}
+
+/* parse an "http-respose" rule */
+struct act_rule *parse_http_res_cond(const char **args, const char *file, int linenum, struct proxy *proxy)
+{
+       struct act_rule *rule;
+       struct action_kw *custom = NULL;
+       int cur_arg;
+       char *error;
+
+       rule = calloc(1, sizeof(*rule));
+       if (!rule) {
+               ha_alert("parsing [%s:%d]: out of memory.\n", file, linenum);
+               goto out_err;
+       }
+
+       if (!strcmp(args[0], "allow")) {
+               rule->action = ACT_ACTION_ALLOW;
+               cur_arg = 1;
+       } else if (!strcmp(args[0], "deny")) {
+               rule->action = ACT_ACTION_DENY;
+               cur_arg = 1;
+       } else if (!strcmp(args[0], "set-nice")) {
+               rule->action = ACT_HTTP_SET_NICE;
+               cur_arg = 1;
+
+               if (!*args[cur_arg] ||
+                   (*args[cur_arg + 1] && strcmp(args[cur_arg + 1], "if") != 0 && strcmp(args[cur_arg + 1], "unless") != 0)) {
+                       ha_alert("parsing [%s:%d]: 'http-response %s' expects exactly 1 argument (integer value).\n",
+                                file, linenum, args[0]);
+                       goto out_err;
+               }
+               rule->arg.nice = atoi(args[cur_arg]);
+               if (rule->arg.nice < -1024)
+                       rule->arg.nice = -1024;
+               else if (rule->arg.nice > 1024)
+                       rule->arg.nice = 1024;
+               cur_arg++;
+       } else if (!strcmp(args[0], "set-tos")) {
+#ifdef IP_TOS
+               char *err;
+               rule->action = ACT_HTTP_SET_TOS;
+               cur_arg = 1;
+
+               if (!*args[cur_arg] ||
+                   (*args[cur_arg + 1] && strcmp(args[cur_arg + 1], "if") != 0 && strcmp(args[cur_arg + 1], "unless") != 0)) {
+                       ha_alert("parsing [%s:%d]: 'http-response %s' expects exactly 1 argument (integer/hex value).\n",
+                                file, linenum, args[0]);
+                       goto out_err;
+               }
+
+               rule->arg.tos = strtol(args[cur_arg], &err, 0);
+               if (err && *err != '\0') {
+                       ha_alert("parsing [%s:%d]: invalid character starting at '%s' in 'http-response %s' (integer/hex value expected).\n",
+                                file, linenum, err, args[0]);
+                       goto out_err;
+               }
+               cur_arg++;
+#else
+               ha_alert("parsing [%s:%d]: 'http-response %s' is not supported on this platform (IP_TOS undefined).\n", file, linenum, args[0]);
+               goto out_err;
+#endif
+       } else if (!strcmp(args[0], "set-mark")) {
+#ifdef SO_MARK
+               char *err;
+               rule->action = ACT_HTTP_SET_MARK;
+               cur_arg = 1;
+
+               if (!*args[cur_arg] ||
+                   (*args[cur_arg + 1] && strcmp(args[cur_arg + 1], "if") != 0 && strcmp(args[cur_arg + 1], "unless") != 0)) {
+                       ha_alert("parsing [%s:%d]: 'http-response %s' expects exactly 1 argument (integer/hex value).\n",
+                                file, linenum, args[0]);
+                       goto out_err;
+               }
+
+               rule->arg.mark = strtoul(args[cur_arg], &err, 0);
+               if (err && *err != '\0') {
+                       ha_alert("parsing [%s:%d]: invalid character starting at '%s' in 'http-response %s' (integer/hex value expected).\n",
+                                file, linenum, err, args[0]);
+                       goto out_err;
+               }
+               cur_arg++;
+               global.last_checks |= LSTCHK_NETADM;
+#else
+               ha_alert("parsing [%s:%d]: 'http-response %s' is not supported on this platform (SO_MARK undefined).\n", file, linenum, args[0]);
+               goto out_err;
+#endif
+       } else if (!strcmp(args[0], "set-log-level")) {
+               rule->action = ACT_HTTP_SET_LOGL;
+               cur_arg = 1;
+
+               if (!*args[cur_arg] ||
+                   (*args[cur_arg + 1] && strcmp(args[cur_arg + 1], "if") != 0 && strcmp(args[cur_arg + 1], "unless") != 0)) {
+               bad_log_level:
+                       ha_alert("parsing [%s:%d]: 'http-response %s' expects exactly 1 argument (log level name or 'silent').\n",
+                                file, linenum, args[0]);
+                       goto out_err;
+               }
+               if (strcmp(args[cur_arg], "silent") == 0)
+                       rule->arg.loglevel = -1;
+               else if ((rule->arg.loglevel = get_log_level(args[cur_arg]) + 1) == 0)
+                       goto bad_log_level;
+               cur_arg++;
+       } else if (strcmp(args[0], "add-header") == 0 || strcmp(args[0], "set-header") == 0) {
+               rule->action = *args[0] == 'a' ? ACT_HTTP_ADD_HDR : ACT_HTTP_SET_HDR;
+               cur_arg = 1;
+
+               if (!*args[cur_arg] || !*args[cur_arg+1] ||
+                   (*args[cur_arg+2] && strcmp(args[cur_arg+2], "if") != 0 && strcmp(args[cur_arg+2], "unless") != 0)) {
+                       ha_alert("parsing [%s:%d]: 'http-response %s' expects exactly 2 arguments.\n",
+                                file, linenum, args[0]);
+                       goto out_err;
+               }
+
+               rule->arg.hdr_add.name = strdup(args[cur_arg]);
+               rule->arg.hdr_add.name_len = strlen(rule->arg.hdr_add.name);
+               LIST_INIT(&rule->arg.hdr_add.fmt);
+
+               proxy->conf.args.ctx = ARGC_HRS;
+               error = NULL;
+               if (!parse_logformat_string(args[cur_arg + 1], proxy, &rule->arg.hdr_add.fmt, LOG_OPT_HTTP,
+                                           (proxy->cap & PR_CAP_BE) ? SMP_VAL_BE_HRS_HDR : SMP_VAL_FE_HRS_HDR, &error)) {
+                       ha_alert("parsing [%s:%d]: 'http-response %s': %s.\n",
+                                file, linenum, args[0], error);
+                       free(error);
+                       goto out_err;
+               }
+               free(proxy->conf.lfs_file);
+               proxy->conf.lfs_file = strdup(proxy->conf.args.file);
+               proxy->conf.lfs_line = proxy->conf.args.line;
+               cur_arg += 2;
+       } else if (strcmp(args[0], "replace-header") == 0 || strcmp(args[0], "replace-value") == 0) {
+               rule->action = args[0][8] == 'h' ? ACT_HTTP_REPLACE_HDR : ACT_HTTP_REPLACE_VAL;
+               cur_arg = 1;
+
+               if (!*args[cur_arg] || !*args[cur_arg+1] || !*args[cur_arg+2] ||
+                   (*args[cur_arg+3] && strcmp(args[cur_arg+3], "if") != 0 && strcmp(args[cur_arg+3], "unless") != 0)) {
+                       ha_alert("parsing [%s:%d]: 'http-response %s' expects exactly 3 arguments.\n",
+                                file, linenum, args[0]);
+                       goto out_err;
+               }
+
+               rule->arg.hdr_add.name = strdup(args[cur_arg]);
+               rule->arg.hdr_add.name_len = strlen(rule->arg.hdr_add.name);
+               LIST_INIT(&rule->arg.hdr_add.fmt);
+
+               error = NULL;
+               if (!regex_comp(args[cur_arg + 1], &rule->arg.hdr_add.re, 1, 1, &error)) {
+                       ha_alert("parsing [%s:%d] : '%s' : %s.\n", file, linenum,
+                                args[cur_arg + 1], error);
+                       free(error);
+                       goto out_err;
+               }
+
+               proxy->conf.args.ctx = ARGC_HRQ;
+               error = NULL;
+               if (!parse_logformat_string(args[cur_arg + 2], proxy, &rule->arg.hdr_add.fmt, LOG_OPT_HTTP,
+                                           (proxy->cap & PR_CAP_BE) ? SMP_VAL_BE_HRS_HDR : SMP_VAL_FE_HRS_HDR, &error)) {
+                       ha_alert("parsing [%s:%d]: 'http-response %s': %s.\n",
+                                file, linenum, args[0], error);
+                       free(error);
+                       goto out_err;
+               }
+
+               free(proxy->conf.lfs_file);
+               proxy->conf.lfs_file = strdup(proxy->conf.args.file);
+               proxy->conf.lfs_line = proxy->conf.args.line;
+               cur_arg += 3;
+       } else if (strcmp(args[0], "del-header") == 0) {
+               rule->action = ACT_HTTP_DEL_HDR;
+               cur_arg = 1;
+
+               if (!*args[cur_arg] ||
+                   (*args[cur_arg+1] && strcmp(args[cur_arg+1], "if") != 0 && strcmp(args[cur_arg+1], "unless") != 0)) {
+                       ha_alert("parsing [%s:%d]: 'http-response %s' expects exactly 1 argument.\n",
+                                file, linenum, args[0]);
+                       goto out_err;
+               }
+
+               rule->arg.hdr_add.name = strdup(args[cur_arg]);
+               rule->arg.hdr_add.name_len = strlen(rule->arg.hdr_add.name);
+
+               proxy->conf.args.ctx = ARGC_HRS;
+               free(proxy->conf.lfs_file);
+               proxy->conf.lfs_file = strdup(proxy->conf.args.file);
+               proxy->conf.lfs_line = proxy->conf.args.line;
+               cur_arg += 1;
+       } else if (strncmp(args[0], "add-acl", 7) == 0) {
+               /* http-request add-acl(<reference (acl name)>) <key pattern> */
+               rule->action = ACT_HTTP_ADD_ACL;
+               /*
+                * '+ 8' for 'add-acl('
+                * '- 9' for 'add-acl(' + trailing ')'
+                */
+               rule->arg.map.ref = my_strndup(args[0] + 8, strlen(args[0]) - 9);
+
+               cur_arg = 1;
+
+               if (!*args[cur_arg] ||
+                   (*args[cur_arg+1] && strcmp(args[cur_arg+1], "if") != 0 && strcmp(args[cur_arg+1], "unless") != 0)) {
+                       ha_alert("parsing [%s:%d]: 'http-response %s' expects exactly 1 argument.\n",
+                                file, linenum, args[0]);
+                       goto out_err;
+               }
+
+               LIST_INIT(&rule->arg.map.key);
+               proxy->conf.args.ctx = ARGC_HRS;
+               error = NULL;
+               if (!parse_logformat_string(args[cur_arg], proxy, &rule->arg.map.key, LOG_OPT_HTTP,
+                                           (proxy->cap & PR_CAP_BE) ? SMP_VAL_BE_HRS_HDR : SMP_VAL_FE_HRS_HDR, &error)) {
+                       ha_alert("parsing [%s:%d]: 'http-response %s': %s.\n",
+                                file, linenum, args[0], error);
+                       free(error);
+                       goto out_err;
+               }
+               free(proxy->conf.lfs_file);
+               proxy->conf.lfs_file = strdup(proxy->conf.args.file);
+               proxy->conf.lfs_line = proxy->conf.args.line;
+
+               cur_arg += 1;
+       } else if (strncmp(args[0], "del-acl", 7) == 0) {
+               /* http-response del-acl(<reference (acl name)>) <key pattern> */
+               rule->action = ACT_HTTP_DEL_ACL;
+               /*
+                * '+ 8' for 'del-acl('
+                * '- 9' for 'del-acl(' + trailing ')'
+                */
+               rule->arg.map.ref = my_strndup(args[0] + 8, strlen(args[0]) - 9);
+
+               cur_arg = 1;
+
+               if (!*args[cur_arg] ||
+                   (*args[cur_arg+1] && strcmp(args[cur_arg+1], "if") != 0 && strcmp(args[cur_arg+1], "unless") != 0)) {
+                       ha_alert("parsing [%s:%d]: 'http-response %s' expects exactly 1 argument.\n",
+                                file, linenum, args[0]);
+                       goto out_err;
+               }
+
+               LIST_INIT(&rule->arg.map.key);
+               proxy->conf.args.ctx = ARGC_HRS;
+               error = NULL;
+               if (!parse_logformat_string(args[cur_arg], proxy, &rule->arg.map.key, LOG_OPT_HTTP,
+                                           (proxy->cap & PR_CAP_BE) ? SMP_VAL_BE_HRS_HDR : SMP_VAL_FE_HRS_HDR, &error)) {
+                       ha_alert("parsing [%s:%d]: 'http-response %s': %s.\n",
+                                file, linenum, args[0], error);
+                       free(error);
+                       goto out_err;
+               }
+               free(proxy->conf.lfs_file);
+               proxy->conf.lfs_file = strdup(proxy->conf.args.file);
+               proxy->conf.lfs_line = proxy->conf.args.line;
+               cur_arg += 1;
+       } else if (strncmp(args[0], "del-map", 7) == 0) {
+               /* http-response del-map(<reference (map name)>) <key pattern> */
+               rule->action = ACT_HTTP_DEL_MAP;
+               /*
+                * '+ 8' for 'del-map('
+                * '- 9' for 'del-map(' + trailing ')'
+                */
+               rule->arg.map.ref = my_strndup(args[0] + 8, strlen(args[0]) - 9);
+
+               cur_arg = 1;
+
+               if (!*args[cur_arg] ||
+                   (*args[cur_arg+1] && strcmp(args[cur_arg+1], "if") != 0 && strcmp(args[cur_arg+1], "unless") != 0)) {
+                       ha_alert("parsing [%s:%d]: 'http-response %s' expects exactly 1 argument.\n",
+                                file, linenum, args[0]);
+                       goto out_err;
+               }
+
+               LIST_INIT(&rule->arg.map.key);
+               proxy->conf.args.ctx = ARGC_HRS;
+               error = NULL;
+               if (!parse_logformat_string(args[cur_arg], proxy, &rule->arg.map.key, LOG_OPT_HTTP,
+                                           (proxy->cap & PR_CAP_BE) ? SMP_VAL_BE_HRS_HDR : SMP_VAL_FE_HRS_HDR, &error)) {
+                       ha_alert("parsing [%s:%d]: 'http-response %s' %s.\n",
+                                file, linenum, args[0], error);
+                       free(error);
+                       goto out_err;
+               }
+               free(proxy->conf.lfs_file);
+               proxy->conf.lfs_file = strdup(proxy->conf.args.file);
+               proxy->conf.lfs_line = proxy->conf.args.line;
+               cur_arg += 1;
+       } else if (strncmp(args[0], "set-map", 7) == 0) {
+               /* http-response set-map(<reference (map name)>) <key pattern> <value pattern> */
+               rule->action = ACT_HTTP_SET_MAP;
+               /*
+                * '+ 8' for 'set-map('
+                * '- 9' for 'set-map(' + trailing ')'
+                */
+               rule->arg.map.ref = my_strndup(args[0] + 8, strlen(args[0]) - 9);
+
+               cur_arg = 1;
+
+               if (!*args[cur_arg] || !*args[cur_arg+1] ||
+                   (*args[cur_arg+2] && strcmp(args[cur_arg+2], "if") != 0 && strcmp(args[cur_arg+2], "unless") != 0)) {
+                       ha_alert("parsing [%s:%d]: 'http-response %s' expects exactly 2 arguments.\n",
+                                file, linenum, args[0]);
+                       goto out_err;
+               }
+
+               LIST_INIT(&rule->arg.map.key);
+               LIST_INIT(&rule->arg.map.value);
+
+               proxy->conf.args.ctx = ARGC_HRS;
+
+               /* key pattern */
+               error = NULL;
+               if (!parse_logformat_string(args[cur_arg], proxy, &rule->arg.map.key, LOG_OPT_HTTP,
+                                           (proxy->cap & PR_CAP_BE) ? SMP_VAL_BE_HRS_HDR : SMP_VAL_FE_HRS_HDR, &error)) {
+                       ha_alert("parsing [%s:%d]: 'http-response %s' name: %s.\n",
+                                file, linenum, args[0], error);
+                       free(error);
+                       goto out_err;
+               }
+
+               /* value pattern */
+               error = NULL;
+               if (!parse_logformat_string(args[cur_arg + 1], proxy, &rule->arg.map.value, LOG_OPT_HTTP,
+                                           (proxy->cap & PR_CAP_BE) ? SMP_VAL_BE_HRS_HDR : SMP_VAL_FE_HRS_HDR, &error)) {
+                       ha_alert("parsing [%s:%d]: 'http-response %s' value: %s.\n",
+                                file, linenum, args[0], error);
+                       free(error);
+                       goto out_err;
+               }
+
+               free(proxy->conf.lfs_file);
+               proxy->conf.lfs_file = strdup(proxy->conf.args.file);
+               proxy->conf.lfs_line = proxy->conf.args.line;
+
+               cur_arg += 2;
+       } else if (strcmp(args[0], "redirect") == 0) {
+               struct redirect_rule *redir;
+               char *errmsg = NULL;
+
+               if ((redir = http_parse_redirect_rule(file, linenum, proxy, (const char **)args + 1, &errmsg, 1, 1)) == NULL) {
+                       ha_alert("parsing [%s:%d] : error detected in %s '%s' while parsing 'http-response %s' rule : %s.\n",
+                                file, linenum, proxy_type_str(proxy), proxy->id, args[0], errmsg);
+                       goto out_err;
+               }
+
+               /* this redirect rule might already contain a parsed condition which
+                * we'll pass to the http-request rule.
+                */
+               rule->action = ACT_HTTP_REDIR;
+               rule->arg.redir = redir;
+               rule->cond = redir->cond;
+               redir->cond = NULL;
+               cur_arg = 2;
+               return rule;
+       } else if (strncmp(args[0], "track-sc", 8) == 0) {
+               struct sample_expr *expr;
+               unsigned int where;
+               char *err = NULL;
+               unsigned int tsc_num;
+               const char *tsc_num_str;
+
+               cur_arg = 1;
+               proxy->conf.args.ctx = ARGC_TRK;
+
+               tsc_num_str = &args[0][8];
+               if (cfg_parse_track_sc_num(&tsc_num, tsc_num_str, tsc_num_str + strlen(tsc_num_str), &err) == -1) {
+                       ha_alert("parsing [%s:%d] : error detected in %s '%s' while parsing 'http-response %s' rule : %s.\n",
+                                file, linenum, proxy_type_str(proxy), proxy->id, args[0], err);
+                       free(err);
+                       goto out_err;
+               }
+
+               expr = sample_parse_expr((char **)args, &cur_arg, file, linenum, &err, &proxy->conf.args);
+               if (!expr) {
+                       ha_alert("parsing [%s:%d] : error detected in %s '%s' while parsing 'http-response %s' rule : %s.\n",
+                                file, linenum, proxy_type_str(proxy), proxy->id, args[0], err);
+                       free(err);
+                       goto out_err;
+               }
+
+               where = 0;
+               if (proxy->cap & PR_CAP_FE)
+                       where |= SMP_VAL_FE_HRS_HDR;
+               if (proxy->cap & PR_CAP_BE)
+                       where |= SMP_VAL_BE_HRS_HDR;
+
+               if (!(expr->fetch->val & where)) {
+                       ha_alert("parsing [%s:%d] : error detected in %s '%s' while parsing 'http-response %s' rule :"
+                                " fetch method '%s' extracts information from '%s', none of which is available here.\n",
+                                file, linenum, proxy_type_str(proxy), proxy->id, args[0],
+                                args[cur_arg-1], sample_src_names(expr->fetch->use));
+                       free(expr);
+                       goto out_err;
+               }
+
+               if (strcmp(args[cur_arg], "table") == 0) {
+                       cur_arg++;
+                       if (!args[cur_arg]) {
+                               ha_alert("parsing [%s:%d] : error detected in %s '%s' while parsing 'http-response %s' rule : missing table name.\n",
+                                        file, linenum, proxy_type_str(proxy), proxy->id, args[0]);
+                               free(expr);
+                               goto out_err;
+                       }
+                       /* we copy the table name for now, it will be resolved later */
+                       rule->arg.trk_ctr.table.n = strdup(args[cur_arg]);
+                       cur_arg++;
+               }
+               rule->arg.trk_ctr.expr = expr;
+               rule->action = ACT_ACTION_TRK_SC0 + tsc_num;
+               rule->check_ptr = check_trk_action;
+       } else if (((custom = action_http_res_custom(args[0])) != NULL)) {
+               char *errmsg = NULL;
+               cur_arg = 1;
+               /* try in the module list */
+               rule->from = ACT_F_HTTP_RES;
+               rule->kw = custom;
+               if (custom->parse(args, &cur_arg, proxy, rule, &errmsg) == ACT_RET_PRS_ERR) {
+                       ha_alert("parsing [%s:%d] : error detected in %s '%s' while parsing 'http-response %s' rule : %s.\n",
+                                file, linenum, proxy_type_str(proxy), proxy->id, args[0], errmsg);
+                       free(errmsg);
+                       goto out_err;
+               }
+       } else {
+               action_build_list(&http_res_keywords.list, &trash);
+               ha_alert("parsing [%s:%d]: 'http-response' expects 'allow', 'deny', 'redirect', "
+                        "'add-header', 'del-header', 'set-header', 'replace-header', 'replace-value', 'set-nice', "
+                        "'set-tos', 'set-mark', 'set-log-level', 'add-acl', 'del-acl', 'del-map', 'set-map', 'track-sc*'"
+                        "%s%s, but got '%s'%s.\n",
+                        file, linenum, *trash.area ? ", " : "", trash.area,
+                        args[0], *args[0] ? "" : " (missing argument)");
+               goto out_err;
+       }
+
+       if (strcmp(args[cur_arg], "if") == 0 || strcmp(args[cur_arg], "unless") == 0) {
+               struct acl_cond *cond;
+               char *errmsg = NULL;
+
+               if ((cond = build_acl_cond(file, linenum, &proxy->acl, proxy, args+cur_arg, &errmsg)) == NULL) {
+                       ha_alert("parsing [%s:%d] : error detected while parsing an 'http-response %s' condition : %s.\n",
+                                file, linenum, args[0], errmsg);
+                       free(errmsg);
+                       goto out_err;
+               }
+               rule->cond = cond;
+       }
+       else if (*args[cur_arg]) {
+               ha_alert("parsing [%s:%d]: 'http-response %s' expects"
+                        " either 'if' or 'unless' followed by a condition but found '%s'.\n",
+                        file, linenum, args[0], args[cur_arg]);
+               goto out_err;
+       }
+
+       return rule;
+ out_err:
+       free(rule);
+       return NULL;
+}
+
+/* Parses a redirect rule. Returns the redirect rule on success or NULL on error,
+ * with <err> filled with the error message. If <use_fmt> is not null, builds a
+ * dynamic log-format rule instead of a static string. Parameter <dir> indicates
+ * the direction of the rule, and equals 0 for request, non-zero for responses.
+ */
+struct redirect_rule *http_parse_redirect_rule(const char *file, int linenum, struct proxy *curproxy,
+                                               const char **args, char **errmsg, int use_fmt, int dir)
+{
+       struct redirect_rule *rule;
+       int cur_arg;
+       int type = REDIRECT_TYPE_NONE;
+       int code = 302;
+       const char *destination = NULL;
+       const char *cookie = NULL;
+       int cookie_set = 0;
+       unsigned int flags = REDIRECT_FLAG_NONE;
+       struct acl_cond *cond = NULL;
+
+       cur_arg = 0;
+       while (*(args[cur_arg])) {
+               if (strcmp(args[cur_arg], "location") == 0) {
+                       if (!*args[cur_arg + 1])
+                               goto missing_arg;
+
+                       type = REDIRECT_TYPE_LOCATION;
+                       cur_arg++;
+                       destination = args[cur_arg];
+               }
+               else if (strcmp(args[cur_arg], "prefix") == 0) {
+                       if (!*args[cur_arg + 1])
+                               goto missing_arg;
+                       type = REDIRECT_TYPE_PREFIX;
+                       cur_arg++;
+                       destination = args[cur_arg];
+               }
+               else if (strcmp(args[cur_arg], "scheme") == 0) {
+                       if (!*args[cur_arg + 1])
+                               goto missing_arg;
+
+                       type = REDIRECT_TYPE_SCHEME;
+                       cur_arg++;
+                       destination = args[cur_arg];
+               }
+               else if (strcmp(args[cur_arg], "set-cookie") == 0) {
+                       if (!*args[cur_arg + 1])
+                               goto missing_arg;
+
+                       cur_arg++;
+                       cookie = args[cur_arg];
+                       cookie_set = 1;
+               }
+               else if (strcmp(args[cur_arg], "clear-cookie") == 0) {
+                       if (!*args[cur_arg + 1])
+                               goto missing_arg;
+
+                       cur_arg++;
+                       cookie = args[cur_arg];
+                       cookie_set = 0;
+               }
+               else if (strcmp(args[cur_arg], "code") == 0) {
+                       if (!*args[cur_arg + 1])
+                               goto missing_arg;
+
+                       cur_arg++;
+                       code = atol(args[cur_arg]);
+                       if (code < 301 || code > 308 || (code > 303 && code < 307)) {
+                               memprintf(errmsg,
+                                         "'%s': unsupported HTTP code '%s' (must be one of 301, 302, 303, 307 or 308)",
+                                         args[cur_arg - 1], args[cur_arg]);
+                               return NULL;
+                       }
+               }
+               else if (!strcmp(args[cur_arg],"drop-query")) {
+                       flags |= REDIRECT_FLAG_DROP_QS;
+               }
+               else if (!strcmp(args[cur_arg],"append-slash")) {
+                       flags |= REDIRECT_FLAG_APPEND_SLASH;
+               }
+               else if (strcmp(args[cur_arg], "if") == 0 ||
+                        strcmp(args[cur_arg], "unless") == 0) {
+                       cond = build_acl_cond(file, linenum, &curproxy->acl, curproxy, (const char **)args + cur_arg, errmsg);
+                       if (!cond) {
+                               memprintf(errmsg, "error in condition: %s", *errmsg);
+                               return NULL;
+                       }
+                       break;
+               }
+               else {
+                       memprintf(errmsg,
+                                 "expects 'code', 'prefix', 'location', 'scheme', 'set-cookie', 'clear-cookie', 'drop-query' or 'append-slash' (was '%s')",
+                                 args[cur_arg]);
+                       return NULL;
+               }
+               cur_arg++;
+       }
+
+       if (type == REDIRECT_TYPE_NONE) {
+               memprintf(errmsg, "redirection type expected ('prefix', 'location', or 'scheme')");
+               return NULL;
+       }
+
+       if (dir && type != REDIRECT_TYPE_LOCATION) {
+               memprintf(errmsg, "response only supports redirect type 'location'");
+               return NULL;
+       }
+
+       rule = calloc(1, sizeof(*rule));
+       rule->cond = cond;
+       LIST_INIT(&rule->rdr_fmt);
+
+       if (!use_fmt) {
+               /* old-style static redirect rule */
+               rule->rdr_str = strdup(destination);
+               rule->rdr_len = strlen(destination);
+       }
+       else {
+               /* log-format based redirect rule */
+
+               /* Parse destination. Note that in the REDIRECT_TYPE_PREFIX case,
+                * if prefix == "/", we don't want to add anything, otherwise it
+                * makes it hard for the user to configure a self-redirection.
+                */
+               curproxy->conf.args.ctx = ARGC_RDR;
+               if (!(type == REDIRECT_TYPE_PREFIX && destination[0] == '/' && destination[1] == '\0')) {
+                       if (!parse_logformat_string(destination, curproxy, &rule->rdr_fmt, LOG_OPT_HTTP,
+                                                   dir ? (curproxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRS_HDR : SMP_VAL_BE_HRS_HDR
+                                                       : (curproxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR,
+                                                   errmsg)) {
+                               return  NULL;
+                       }
+                       free(curproxy->conf.lfs_file);
+                       curproxy->conf.lfs_file = strdup(curproxy->conf.args.file);
+                       curproxy->conf.lfs_line = curproxy->conf.args.line;
+               }
+       }
+
+       if (cookie) {
+               /* depending on cookie_set, either we want to set the cookie, or to clear it.
+                * a clear consists in appending "; path=/; Max-Age=0;" at the end.
+                */
+               rule->cookie_len = strlen(cookie);
+               if (cookie_set) {
+                       rule->cookie_str = malloc(rule->cookie_len + 10);
+                       memcpy(rule->cookie_str, cookie, rule->cookie_len);
+                       memcpy(rule->cookie_str + rule->cookie_len, "; path=/;", 10);
+                       rule->cookie_len += 9;
+               } else {
+                       rule->cookie_str = malloc(rule->cookie_len + 21);
+                       memcpy(rule->cookie_str, cookie, rule->cookie_len);
+                       memcpy(rule->cookie_str + rule->cookie_len, "; path=/; Max-Age=0;", 21);
+                       rule->cookie_len += 20;
+               }
+       }
+       rule->type = type;
+       rule->code = code;
+       rule->flags = flags;
+       LIST_INIT(&rule->list);
+       return rule;
+
+ missing_arg:
+       memprintf(errmsg, "missing argument for '%s'", args[cur_arg]);
+       return NULL;
+}
+
+void free_http_res_rules(struct list *r)
+{
+       struct act_rule *tr, *pr;
+
+       list_for_each_entry_safe(pr, tr, r, list) {
+               LIST_DEL(&pr->list);
+               regex_free(&pr->arg.hdr_add.re);
+               free(pr);
+       }
+}
+
+void free_http_req_rules(struct list *r)
+{
+       struct act_rule *tr, *pr;
+
+       list_for_each_entry_safe(pr, tr, r, list) {
+               LIST_DEL(&pr->list);
+               if (pr->action == ACT_HTTP_REQ_AUTH)
+                       free(pr->arg.auth.realm);
+
+               regex_free(&pr->arg.hdr_add.re);
+               free(pr);
+       }
+}
+
+__attribute__((constructor))
+static void __http_rules_init(void)
+{
+}
+
+/*
+ * Local variables:
+ *  c-indent-level: 8
+ *  c-basic-offset: 8
+ * End:
+ */
index 94e672d11dba93ed644135875217049f0b951666..ec5140981e80421cfa8a4ff73b0917c981ce3022 100644 (file)
@@ -88,16 +88,6 @@ const char *stat_status_codes[STAT_STATUS_SIZE] = {
 };
 
 
-/* List head of all known action keywords for "http-request" */
-struct action_kw_list http_req_keywords = {
-       .list = LIST_HEAD_INIT(http_req_keywords.list)
-};
-
-/* List head of all known action keywords for "http-response" */
-struct action_kw_list http_res_keywords = {
-       .list = LIST_HEAD_INIT(http_res_keywords.list)
-};
-
 static int http_apply_redirect_rule(struct redirect_rule *rule, struct stream *s, struct http_txn *txn);
 
 static inline int http_msg_forward_body(struct stream *s, struct http_msg *msg);
@@ -7666,1142 +7656,6 @@ void http_reset_txn(struct stream *s)
        s->si[1].hcto = TICK_ETERNITY;
 }
 
-void free_http_res_rules(struct list *r)
-{
-       struct act_rule *tr, *pr;
-
-       list_for_each_entry_safe(pr, tr, r, list) {
-               LIST_DEL(&pr->list);
-               regex_free(&pr->arg.hdr_add.re);
-               free(pr);
-       }
-}
-
-void free_http_req_rules(struct list *r)
-{
-       struct act_rule *tr, *pr;
-
-       list_for_each_entry_safe(pr, tr, r, list) {
-               LIST_DEL(&pr->list);
-               if (pr->action == ACT_HTTP_REQ_AUTH)
-                       free(pr->arg.auth.realm);
-
-               regex_free(&pr->arg.hdr_add.re);
-               free(pr);
-       }
-}
-
-/* parse an "http-request" rule */
-struct act_rule *parse_http_req_cond(const char **args, const char *file, int linenum, struct proxy *proxy)
-{
-       struct act_rule *rule;
-       struct action_kw *custom = NULL;
-       int cur_arg;
-       char *error;
-
-       rule = calloc(1, sizeof(*rule));
-       if (!rule) {
-               ha_alert("parsing [%s:%d]: out of memory.\n", file, linenum);
-               goto out_err;
-       }
-
-       if (!strcmp(args[0], "allow")) {
-               rule->action = ACT_ACTION_ALLOW;
-               cur_arg = 1;
-       } else if (!strcmp(args[0], "deny") || !strcmp(args[0], "block") || !strcmp(args[0], "tarpit")) {
-               int code;
-               int hc;
-
-               if (!strcmp(args[0], "tarpit")) {
-                   rule->action = ACT_HTTP_REQ_TARPIT;
-                   rule->deny_status = HTTP_ERR_500;
-               }
-               else {
-                       rule->action = ACT_ACTION_DENY;
-                       rule->deny_status = HTTP_ERR_403;
-               }
-               cur_arg = 1;
-                if (strcmp(args[cur_arg], "deny_status") == 0) {
-                        cur_arg++;
-                        if (!args[cur_arg]) {
-                                ha_alert("parsing [%s:%d] : error detected in %s '%s' while parsing 'http-request %s' rule : missing status code.\n",
-                                        file, linenum, proxy_type_str(proxy), proxy->id, args[0]);
-                                goto out_err;
-                        }
-
-                        code = atol(args[cur_arg]);
-                        cur_arg++;
-                        for (hc = 0; hc < HTTP_ERR_SIZE; hc++) {
-                                if (http_err_codes[hc] == code) {
-                                        rule->deny_status = hc;
-                                        break;
-                                }
-                        }
-
-                        if (hc >= HTTP_ERR_SIZE) {
-                                ha_warning("parsing [%s:%d] : status code %d not handled, using default code %d.\n",
-                                          file, linenum, code, http_err_codes[rule->deny_status]);
-                        }
-                }
-       } else if (!strcmp(args[0], "auth")) {
-               rule->action = ACT_HTTP_REQ_AUTH;
-               cur_arg = 1;
-
-               while(*args[cur_arg]) {
-                       if (!strcmp(args[cur_arg], "realm")) {
-                               rule->arg.auth.realm = strdup(args[cur_arg + 1]);
-                               cur_arg+=2;
-                               continue;
-                       } else
-                               break;
-               }
-       } else if (!strcmp(args[0], "set-nice")) {
-               rule->action = ACT_HTTP_SET_NICE;
-               cur_arg = 1;
-
-               if (!*args[cur_arg] ||
-                   (*args[cur_arg + 1] && strcmp(args[cur_arg + 1], "if") != 0 && strcmp(args[cur_arg + 1], "unless") != 0)) {
-                       ha_alert("parsing [%s:%d]: 'http-request %s' expects exactly 1 argument (integer value).\n",
-                                file, linenum, args[0]);
-                       goto out_err;
-               }
-               rule->arg.nice = atoi(args[cur_arg]);
-               if (rule->arg.nice < -1024)
-                       rule->arg.nice = -1024;
-               else if (rule->arg.nice > 1024)
-                       rule->arg.nice = 1024;
-               cur_arg++;
-       } else if (!strcmp(args[0], "set-tos")) {
-#ifdef IP_TOS
-               char *err;
-               rule->action = ACT_HTTP_SET_TOS;
-               cur_arg = 1;
-
-               if (!*args[cur_arg] ||
-                   (*args[cur_arg + 1] && strcmp(args[cur_arg + 1], "if") != 0 && strcmp(args[cur_arg + 1], "unless") != 0)) {
-                       ha_alert("parsing [%s:%d]: 'http-request %s' expects exactly 1 argument (integer/hex value).\n",
-                                file, linenum, args[0]);
-                       goto out_err;
-               }
-
-               rule->arg.tos = strtol(args[cur_arg], &err, 0);
-               if (err && *err != '\0') {
-                       ha_alert("parsing [%s:%d]: invalid character starting at '%s' in 'http-request %s' (integer/hex value expected).\n",
-                                file, linenum, err, args[0]);
-                       goto out_err;
-               }
-               cur_arg++;
-#else
-               ha_alert("parsing [%s:%d]: 'http-request %s' is not supported on this platform (IP_TOS undefined).\n", file, linenum, args[0]);
-               goto out_err;
-#endif
-       } else if (!strcmp(args[0], "set-mark")) {
-#ifdef SO_MARK
-               char *err;
-               rule->action = ACT_HTTP_SET_MARK;
-               cur_arg = 1;
-
-               if (!*args[cur_arg] ||
-                   (*args[cur_arg + 1] && strcmp(args[cur_arg + 1], "if") != 0 && strcmp(args[cur_arg + 1], "unless") != 0)) {
-                       ha_alert("parsing [%s:%d]: 'http-request %s' expects exactly 1 argument (integer/hex value).\n",
-                                file, linenum, args[0]);
-                       goto out_err;
-               }
-
-               rule->arg.mark = strtoul(args[cur_arg], &err, 0);
-               if (err && *err != '\0') {
-                       ha_alert("parsing [%s:%d]: invalid character starting at '%s' in 'http-request %s' (integer/hex value expected).\n",
-                                file, linenum, err, args[0]);
-                       goto out_err;
-               }
-               cur_arg++;
-               global.last_checks |= LSTCHK_NETADM;
-#else
-               ha_alert("parsing [%s:%d]: 'http-request %s' is not supported on this platform (SO_MARK undefined).\n", file, linenum, args[0]);
-               goto out_err;
-#endif
-       } else if (!strcmp(args[0], "set-log-level")) {
-               rule->action = ACT_HTTP_SET_LOGL;
-               cur_arg = 1;
-
-               if (!*args[cur_arg] ||
-                   (*args[cur_arg + 1] && strcmp(args[cur_arg + 1], "if") != 0 && strcmp(args[cur_arg + 1], "unless") != 0)) {
-               bad_log_level:
-                       ha_alert("parsing [%s:%d]: 'http-request %s' expects exactly 1 argument (log level name or 'silent').\n",
-                                file, linenum, args[0]);
-                       goto out_err;
-               }
-               if (strcmp(args[cur_arg], "silent") == 0)
-                       rule->arg.loglevel = -1;
-               else if ((rule->arg.loglevel = get_log_level(args[cur_arg]) + 1) == 0)
-                       goto bad_log_level;
-               cur_arg++;
-       } else if (strcmp(args[0], "add-header") == 0 || strcmp(args[0], "set-header") == 0) {
-               rule->action = *args[0] == 'a' ? ACT_HTTP_ADD_HDR : ACT_HTTP_SET_HDR;
-               cur_arg = 1;
-
-               if (!*args[cur_arg] || !*args[cur_arg+1] ||
-                   (*args[cur_arg+2] && strcmp(args[cur_arg+2], "if") != 0 && strcmp(args[cur_arg+2], "unless") != 0)) {
-                       ha_alert("parsing [%s:%d]: 'http-request %s' expects exactly 2 arguments.\n",
-                                file, linenum, args[0]);
-                       goto out_err;
-               }
-
-               rule->arg.hdr_add.name = strdup(args[cur_arg]);
-               rule->arg.hdr_add.name_len = strlen(rule->arg.hdr_add.name);
-               LIST_INIT(&rule->arg.hdr_add.fmt);
-
-               proxy->conf.args.ctx = ARGC_HRQ;
-               error = NULL;
-               if (!parse_logformat_string(args[cur_arg + 1], proxy, &rule->arg.hdr_add.fmt, LOG_OPT_HTTP,
-                                           (proxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR, &error)) {
-                       ha_alert("parsing [%s:%d]: 'http-request %s': %s.\n",
-                                file, linenum, args[0], error);
-                       free(error);
-                       goto out_err;
-               }
-               free(proxy->conf.lfs_file);
-               proxy->conf.lfs_file = strdup(proxy->conf.args.file);
-               proxy->conf.lfs_line = proxy->conf.args.line;
-               cur_arg += 2;
-       } else if (strcmp(args[0], "replace-header") == 0 || strcmp(args[0], "replace-value") == 0) {
-               rule->action = args[0][8] == 'h' ? ACT_HTTP_REPLACE_HDR : ACT_HTTP_REPLACE_VAL;
-               cur_arg = 1;
-
-               if (!*args[cur_arg] || !*args[cur_arg+1] || !*args[cur_arg+2] ||
-                   (*args[cur_arg+3] && strcmp(args[cur_arg+3], "if") != 0 && strcmp(args[cur_arg+3], "unless") != 0)) {
-                       ha_alert("parsing [%s:%d]: 'http-request %s' expects exactly 3 arguments.\n",
-                                file, linenum, args[0]);
-                       goto out_err;
-               }
-
-               rule->arg.hdr_add.name = strdup(args[cur_arg]);
-               rule->arg.hdr_add.name_len = strlen(rule->arg.hdr_add.name);
-               LIST_INIT(&rule->arg.hdr_add.fmt);
-
-               error = NULL;
-               if (!regex_comp(args[cur_arg + 1], &rule->arg.hdr_add.re, 1, 1, &error)) {
-                       ha_alert("parsing [%s:%d] : '%s' : %s.\n", file, linenum,
-                                args[cur_arg + 1], error);
-                       free(error);
-                       goto out_err;
-               }
-
-               proxy->conf.args.ctx = ARGC_HRQ;
-               error = NULL;
-               if (!parse_logformat_string(args[cur_arg + 2], proxy, &rule->arg.hdr_add.fmt, LOG_OPT_HTTP,
-                                           (proxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR, &error)) {
-                       ha_alert("parsing [%s:%d]: 'http-request %s': %s.\n",
-                                file, linenum, args[0], error);
-                       free(error);
-                       goto out_err;
-               }
-
-               free(proxy->conf.lfs_file);
-               proxy->conf.lfs_file = strdup(proxy->conf.args.file);
-               proxy->conf.lfs_line = proxy->conf.args.line;
-               cur_arg += 3;
-       } else if (strcmp(args[0], "del-header") == 0) {
-               rule->action = ACT_HTTP_DEL_HDR;
-               cur_arg = 1;
-
-               if (!*args[cur_arg] ||
-                   (*args[cur_arg+1] && strcmp(args[cur_arg+1], "if") != 0 && strcmp(args[cur_arg+1], "unless") != 0)) {
-                       ha_alert("parsing [%s:%d]: 'http-request %s' expects exactly 1 argument.\n",
-                                file, linenum, args[0]);
-                       goto out_err;
-               }
-
-               rule->arg.hdr_add.name = strdup(args[cur_arg]);
-               rule->arg.hdr_add.name_len = strlen(rule->arg.hdr_add.name);
-
-               proxy->conf.args.ctx = ARGC_HRQ;
-               free(proxy->conf.lfs_file);
-               proxy->conf.lfs_file = strdup(proxy->conf.args.file);
-               proxy->conf.lfs_line = proxy->conf.args.line;
-               cur_arg += 1;
-       } else if (strncmp(args[0], "track-sc", 8) == 0) {
-               struct sample_expr *expr;
-               unsigned int where;
-               char *err = NULL;
-               unsigned int tsc_num;
-               const char *tsc_num_str;
-
-               cur_arg = 1;
-               proxy->conf.args.ctx = ARGC_TRK;
-
-               tsc_num_str = &args[0][8];
-               if (cfg_parse_track_sc_num(&tsc_num, tsc_num_str, tsc_num_str + strlen(tsc_num_str), &err) == -1) {
-                       ha_alert("parsing [%s:%d] : error detected in %s '%s' while parsing 'http-request %s' rule : %s.\n",
-                                file, linenum, proxy_type_str(proxy), proxy->id, args[0], err);
-                       free(err);
-                       goto out_err;
-               }
-
-               expr = sample_parse_expr((char **)args, &cur_arg, file, linenum, &err, &proxy->conf.args);
-               if (!expr) {
-                       ha_alert("parsing [%s:%d] : error detected in %s '%s' while parsing 'http-request %s' rule : %s.\n",
-                                file, linenum, proxy_type_str(proxy), proxy->id, args[0], err);
-                       free(err);
-                       goto out_err;
-               }
-
-               where = 0;
-               if (proxy->cap & PR_CAP_FE)
-                       where |= SMP_VAL_FE_HRQ_HDR;
-               if (proxy->cap & PR_CAP_BE)
-                       where |= SMP_VAL_BE_HRQ_HDR;
-
-               if (!(expr->fetch->val & where)) {
-                       ha_alert("parsing [%s:%d] : error detected in %s '%s' while parsing 'http-request %s' rule :"
-                                " fetch method '%s' extracts information from '%s', none of which is available here.\n",
-                                file, linenum, proxy_type_str(proxy), proxy->id, args[0],
-                                args[cur_arg-1], sample_src_names(expr->fetch->use));
-                       free(expr);
-                       goto out_err;
-               }
-
-               if (strcmp(args[cur_arg], "table") == 0) {
-                       cur_arg++;
-                       if (!args[cur_arg]) {
-                               ha_alert("parsing [%s:%d] : error detected in %s '%s' while parsing 'http-request %s' rule : missing table name.\n",
-                                        file, linenum, proxy_type_str(proxy), proxy->id, args[0]);
-                               free(expr);
-                               goto out_err;
-                       }
-                       /* we copy the table name for now, it will be resolved later */
-                       rule->arg.trk_ctr.table.n = strdup(args[cur_arg]);
-                       cur_arg++;
-               }
-               rule->arg.trk_ctr.expr = expr;
-               rule->action = ACT_ACTION_TRK_SC0 + tsc_num;
-               rule->check_ptr = check_trk_action;
-       } else if (strcmp(args[0], "redirect") == 0) {
-               struct redirect_rule *redir;
-               char *errmsg = NULL;
-
-               if ((redir = http_parse_redirect_rule(file, linenum, proxy, (const char **)args + 1, &errmsg, 1, 0)) == NULL) {
-                       ha_alert("parsing [%s:%d] : error detected in %s '%s' while parsing 'http-request %s' rule : %s.\n",
-                                file, linenum, proxy_type_str(proxy), proxy->id, args[0], errmsg);
-                       goto out_err;
-               }
-
-               /* this redirect rule might already contain a parsed condition which
-                * we'll pass to the http-request rule.
-                */
-               rule->action = ACT_HTTP_REDIR;
-               rule->arg.redir = redir;
-               rule->cond = redir->cond;
-               redir->cond = NULL;
-               cur_arg = 2;
-               return rule;
-       } else if (strncmp(args[0], "add-acl", 7) == 0) {
-               /* http-request add-acl(<reference (acl name)>) <key pattern> */
-               rule->action = ACT_HTTP_ADD_ACL;
-               /*
-                * '+ 8' for 'add-acl('
-                * '- 9' for 'add-acl(' + trailing ')'
-                */
-               rule->arg.map.ref = my_strndup(args[0] + 8, strlen(args[0]) - 9);
-
-               cur_arg = 1;
-
-               if (!*args[cur_arg] ||
-                   (*args[cur_arg+1] && strcmp(args[cur_arg+1], "if") != 0 && strcmp(args[cur_arg+1], "unless") != 0)) {
-                       ha_alert("parsing [%s:%d]: 'http-request %s' expects exactly 1 argument.\n",
-                                file, linenum, args[0]);
-                       goto out_err;
-               }
-
-               LIST_INIT(&rule->arg.map.key);
-               proxy->conf.args.ctx = ARGC_HRQ;
-               error = NULL;
-               if (!parse_logformat_string(args[cur_arg], proxy, &rule->arg.map.key, LOG_OPT_HTTP,
-                                           (proxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR, &error)) {
-                       ha_alert("parsing [%s:%d]: 'http-request %s': %s.\n",
-                                file, linenum, args[0], error);
-                       free(error);
-                       goto out_err;
-               }
-               free(proxy->conf.lfs_file);
-               proxy->conf.lfs_file = strdup(proxy->conf.args.file);
-               proxy->conf.lfs_line = proxy->conf.args.line;
-               cur_arg += 1;
-       } else if (strncmp(args[0], "del-acl", 7) == 0) {
-               /* http-request del-acl(<reference (acl name)>) <key pattern> */
-               rule->action = ACT_HTTP_DEL_ACL;
-               /*
-                * '+ 8' for 'del-acl('
-                * '- 9' for 'del-acl(' + trailing ')'
-                */
-               rule->arg.map.ref = my_strndup(args[0] + 8, strlen(args[0]) - 9);
-
-               cur_arg = 1;
-
-               if (!*args[cur_arg] ||
-                   (*args[cur_arg+1] && strcmp(args[cur_arg+1], "if") != 0 && strcmp(args[cur_arg+1], "unless") != 0)) {
-                       ha_alert("parsing [%s:%d]: 'http-request %s' expects exactly 1 argument.\n",
-                                file, linenum, args[0]);
-                       goto out_err;
-               }
-
-               LIST_INIT(&rule->arg.map.key);
-               proxy->conf.args.ctx = ARGC_HRQ;
-               error = NULL;
-               if (!parse_logformat_string(args[cur_arg], proxy, &rule->arg.map.key, LOG_OPT_HTTP,
-                                           (proxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR, &error)) {
-                       ha_alert("parsing [%s:%d]: 'http-request %s': %s.\n",
-                                file, linenum, args[0], error);
-                       free(error);
-                       goto out_err;
-               }
-               free(proxy->conf.lfs_file);
-               proxy->conf.lfs_file = strdup(proxy->conf.args.file);
-               proxy->conf.lfs_line = proxy->conf.args.line;
-               cur_arg += 1;
-       } else if (strncmp(args[0], "del-map", 7) == 0) {
-               /* http-request del-map(<reference (map name)>) <key pattern> */
-               rule->action = ACT_HTTP_DEL_MAP;
-               /*
-                * '+ 8' for 'del-map('
-                * '- 9' for 'del-map(' + trailing ')'
-                */
-               rule->arg.map.ref = my_strndup(args[0] + 8, strlen(args[0]) - 9);
-
-               cur_arg = 1;
-
-               if (!*args[cur_arg] ||
-                   (*args[cur_arg+1] && strcmp(args[cur_arg+1], "if") != 0 && strcmp(args[cur_arg+1], "unless") != 0)) {
-                       ha_alert("parsing [%s:%d]: 'http-request %s' expects exactly 1 argument.\n",
-                                file, linenum, args[0]);
-                       goto out_err;
-               }
-
-               LIST_INIT(&rule->arg.map.key);
-               proxy->conf.args.ctx = ARGC_HRQ;
-               error = NULL;
-               if (!parse_logformat_string(args[cur_arg], proxy, &rule->arg.map.key, LOG_OPT_HTTP,
-                                           (proxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR, &error)) {
-                       ha_alert("parsing [%s:%d]: 'http-request %s': %s.\n",
-                                file, linenum, args[0], error);
-                       free(error);
-                       goto out_err;
-               }
-               free(proxy->conf.lfs_file);
-               proxy->conf.lfs_file = strdup(proxy->conf.args.file);
-               proxy->conf.lfs_line = proxy->conf.args.line;
-               cur_arg += 1;
-       } else if (strncmp(args[0], "set-map", 7) == 0) {
-               /* http-request set-map(<reference (map name)>) <key pattern> <value pattern> */
-               rule->action = ACT_HTTP_SET_MAP;
-               /*
-                * '+ 8' for 'set-map('
-                * '- 9' for 'set-map(' + trailing ')'
-                */
-               rule->arg.map.ref = my_strndup(args[0] + 8, strlen(args[0]) - 9);
-
-               cur_arg = 1;
-
-               if (!*args[cur_arg] || !*args[cur_arg+1] ||
-                   (*args[cur_arg+2] && strcmp(args[cur_arg+2], "if") != 0 && strcmp(args[cur_arg+2], "unless") != 0)) {
-                       ha_alert("parsing [%s:%d]: 'http-request %s' expects exactly 2 arguments.\n",
-                                file, linenum, args[0]);
-                       goto out_err;
-               }
-
-               LIST_INIT(&rule->arg.map.key);
-               LIST_INIT(&rule->arg.map.value);
-               proxy->conf.args.ctx = ARGC_HRQ;
-
-               /* key pattern */
-               error = NULL;
-               if (!parse_logformat_string(args[cur_arg], proxy, &rule->arg.map.key, LOG_OPT_HTTP,
-                                           (proxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR, &error)) {
-                       ha_alert("parsing [%s:%d]: 'http-request %s' key: %s.\n",
-                                file, linenum, args[0], error);
-                       free(error);
-                       goto out_err;
-               }
-
-               /* value pattern */
-               error = NULL;
-               if (!parse_logformat_string(args[cur_arg + 1], proxy, &rule->arg.map.value, LOG_OPT_HTTP,
-                                           (proxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR, &error)) {
-                       ha_alert("parsing [%s:%d]: 'http-request %s' pattern: %s.\n",
-                                file, linenum, args[0], error);
-                       free(error);
-                       goto out_err;
-               }
-               free(proxy->conf.lfs_file);
-               proxy->conf.lfs_file = strdup(proxy->conf.args.file);
-               proxy->conf.lfs_line = proxy->conf.args.line;
-
-               cur_arg += 2;
-       } else if (((custom = action_http_req_custom(args[0])) != NULL)) {
-               char *errmsg = NULL;
-               cur_arg = 1;
-               /* try in the module list */
-               rule->from = ACT_F_HTTP_REQ;
-               rule->kw = custom;
-               if (custom->parse(args, &cur_arg, proxy, rule, &errmsg) == ACT_RET_PRS_ERR) {
-                       ha_alert("parsing [%s:%d] : error detected in %s '%s' while parsing 'http-request %s' rule : %s.\n",
-                                file, linenum, proxy_type_str(proxy), proxy->id, args[0], errmsg);
-                       free(errmsg);
-                       goto out_err;
-               }
-       } else {
-               action_build_list(&http_req_keywords.list, &trash);
-               ha_alert("parsing [%s:%d]: 'http-request' expects 'allow', 'deny', 'auth', 'redirect', "
-                        "'tarpit', 'add-header', 'set-header', 'replace-header', 'replace-value', 'set-nice', "
-                        "'set-tos', 'set-mark', 'set-log-level', 'add-acl', 'del-acl', 'del-map', 'set-map', 'track-sc*'"
-                        "%s%s, but got '%s'%s.\n",
-                        file, linenum, *trash.area ? ", " : "", trash.area,
-                        args[0], *args[0] ? "" : " (missing argument)");
-               goto out_err;
-       }
-
-       if (strcmp(args[cur_arg], "if") == 0 || strcmp(args[cur_arg], "unless") == 0) {
-               struct acl_cond *cond;
-               char *errmsg = NULL;
-
-               if ((cond = build_acl_cond(file, linenum, &proxy->acl, proxy, args+cur_arg, &errmsg)) == NULL) {
-                       ha_alert("parsing [%s:%d] : error detected while parsing an 'http-request %s' condition : %s.\n",
-                                file, linenum, args[0], errmsg);
-                       free(errmsg);
-                       goto out_err;
-               }
-               rule->cond = cond;
-       }
-       else if (*args[cur_arg]) {
-               ha_alert("parsing [%s:%d]: 'http-request %s' expects 'realm' for 'auth' or"
-                        " either 'if' or 'unless' followed by a condition but found '%s'.\n",
-                        file, linenum, args[0], args[cur_arg]);
-               goto out_err;
-       }
-
-       return rule;
- out_err:
-       free(rule);
-       return NULL;
-}
-
-/* parse an "http-respose" rule */
-struct act_rule *parse_http_res_cond(const char **args, const char *file, int linenum, struct proxy *proxy)
-{
-       struct act_rule *rule;
-       struct action_kw *custom = NULL;
-       int cur_arg;
-       char *error;
-
-       rule = calloc(1, sizeof(*rule));
-       if (!rule) {
-               ha_alert("parsing [%s:%d]: out of memory.\n", file, linenum);
-               goto out_err;
-       }
-
-       if (!strcmp(args[0], "allow")) {
-               rule->action = ACT_ACTION_ALLOW;
-               cur_arg = 1;
-       } else if (!strcmp(args[0], "deny")) {
-               rule->action = ACT_ACTION_DENY;
-               cur_arg = 1;
-       } else if (!strcmp(args[0], "set-nice")) {
-               rule->action = ACT_HTTP_SET_NICE;
-               cur_arg = 1;
-
-               if (!*args[cur_arg] ||
-                   (*args[cur_arg + 1] && strcmp(args[cur_arg + 1], "if") != 0 && strcmp(args[cur_arg + 1], "unless") != 0)) {
-                       ha_alert("parsing [%s:%d]: 'http-response %s' expects exactly 1 argument (integer value).\n",
-                                file, linenum, args[0]);
-                       goto out_err;
-               }
-               rule->arg.nice = atoi(args[cur_arg]);
-               if (rule->arg.nice < -1024)
-                       rule->arg.nice = -1024;
-               else if (rule->arg.nice > 1024)
-                       rule->arg.nice = 1024;
-               cur_arg++;
-       } else if (!strcmp(args[0], "set-tos")) {
-#ifdef IP_TOS
-               char *err;
-               rule->action = ACT_HTTP_SET_TOS;
-               cur_arg = 1;
-
-               if (!*args[cur_arg] ||
-                   (*args[cur_arg + 1] && strcmp(args[cur_arg + 1], "if") != 0 && strcmp(args[cur_arg + 1], "unless") != 0)) {
-                       ha_alert("parsing [%s:%d]: 'http-response %s' expects exactly 1 argument (integer/hex value).\n",
-                                file, linenum, args[0]);
-                       goto out_err;
-               }
-
-               rule->arg.tos = strtol(args[cur_arg], &err, 0);
-               if (err && *err != '\0') {
-                       ha_alert("parsing [%s:%d]: invalid character starting at '%s' in 'http-response %s' (integer/hex value expected).\n",
-                                file, linenum, err, args[0]);
-                       goto out_err;
-               }
-               cur_arg++;
-#else
-               ha_alert("parsing [%s:%d]: 'http-response %s' is not supported on this platform (IP_TOS undefined).\n", file, linenum, args[0]);
-               goto out_err;
-#endif
-       } else if (!strcmp(args[0], "set-mark")) {
-#ifdef SO_MARK
-               char *err;
-               rule->action = ACT_HTTP_SET_MARK;
-               cur_arg = 1;
-
-               if (!*args[cur_arg] ||
-                   (*args[cur_arg + 1] && strcmp(args[cur_arg + 1], "if") != 0 && strcmp(args[cur_arg + 1], "unless") != 0)) {
-                       ha_alert("parsing [%s:%d]: 'http-response %s' expects exactly 1 argument (integer/hex value).\n",
-                                file, linenum, args[0]);
-                       goto out_err;
-               }
-
-               rule->arg.mark = strtoul(args[cur_arg], &err, 0);
-               if (err && *err != '\0') {
-                       ha_alert("parsing [%s:%d]: invalid character starting at '%s' in 'http-response %s' (integer/hex value expected).\n",
-                                file, linenum, err, args[0]);
-                       goto out_err;
-               }
-               cur_arg++;
-               global.last_checks |= LSTCHK_NETADM;
-#else
-               ha_alert("parsing [%s:%d]: 'http-response %s' is not supported on this platform (SO_MARK undefined).\n", file, linenum, args[0]);
-               goto out_err;
-#endif
-       } else if (!strcmp(args[0], "set-log-level")) {
-               rule->action = ACT_HTTP_SET_LOGL;
-               cur_arg = 1;
-
-               if (!*args[cur_arg] ||
-                   (*args[cur_arg + 1] && strcmp(args[cur_arg + 1], "if") != 0 && strcmp(args[cur_arg + 1], "unless") != 0)) {
-               bad_log_level:
-                       ha_alert("parsing [%s:%d]: 'http-response %s' expects exactly 1 argument (log level name or 'silent').\n",
-                                file, linenum, args[0]);
-                       goto out_err;
-               }
-               if (strcmp(args[cur_arg], "silent") == 0)
-                       rule->arg.loglevel = -1;
-               else if ((rule->arg.loglevel = get_log_level(args[cur_arg]) + 1) == 0)
-                       goto bad_log_level;
-               cur_arg++;
-       } else if (strcmp(args[0], "add-header") == 0 || strcmp(args[0], "set-header") == 0) {
-               rule->action = *args[0] == 'a' ? ACT_HTTP_ADD_HDR : ACT_HTTP_SET_HDR;
-               cur_arg = 1;
-
-               if (!*args[cur_arg] || !*args[cur_arg+1] ||
-                   (*args[cur_arg+2] && strcmp(args[cur_arg+2], "if") != 0 && strcmp(args[cur_arg+2], "unless") != 0)) {
-                       ha_alert("parsing [%s:%d]: 'http-response %s' expects exactly 2 arguments.\n",
-                                file, linenum, args[0]);
-                       goto out_err;
-               }
-
-               rule->arg.hdr_add.name = strdup(args[cur_arg]);
-               rule->arg.hdr_add.name_len = strlen(rule->arg.hdr_add.name);
-               LIST_INIT(&rule->arg.hdr_add.fmt);
-
-               proxy->conf.args.ctx = ARGC_HRS;
-               error = NULL;
-               if (!parse_logformat_string(args[cur_arg + 1], proxy, &rule->arg.hdr_add.fmt, LOG_OPT_HTTP,
-                                           (proxy->cap & PR_CAP_BE) ? SMP_VAL_BE_HRS_HDR : SMP_VAL_FE_HRS_HDR, &error)) {
-                       ha_alert("parsing [%s:%d]: 'http-response %s': %s.\n",
-                                file, linenum, args[0], error);
-                       free(error);
-                       goto out_err;
-               }
-               free(proxy->conf.lfs_file);
-               proxy->conf.lfs_file = strdup(proxy->conf.args.file);
-               proxy->conf.lfs_line = proxy->conf.args.line;
-               cur_arg += 2;
-       } else if (strcmp(args[0], "replace-header") == 0 || strcmp(args[0], "replace-value") == 0) {
-               rule->action = args[0][8] == 'h' ? ACT_HTTP_REPLACE_HDR : ACT_HTTP_REPLACE_VAL;
-               cur_arg = 1;
-
-               if (!*args[cur_arg] || !*args[cur_arg+1] || !*args[cur_arg+2] ||
-                   (*args[cur_arg+3] && strcmp(args[cur_arg+3], "if") != 0 && strcmp(args[cur_arg+3], "unless") != 0)) {
-                       ha_alert("parsing [%s:%d]: 'http-response %s' expects exactly 3 arguments.\n",
-                                file, linenum, args[0]);
-                       goto out_err;
-               }
-
-               rule->arg.hdr_add.name = strdup(args[cur_arg]);
-               rule->arg.hdr_add.name_len = strlen(rule->arg.hdr_add.name);
-               LIST_INIT(&rule->arg.hdr_add.fmt);
-
-               error = NULL;
-               if (!regex_comp(args[cur_arg + 1], &rule->arg.hdr_add.re, 1, 1, &error)) {
-                       ha_alert("parsing [%s:%d] : '%s' : %s.\n", file, linenum,
-                                args[cur_arg + 1], error);
-                       free(error);
-                       goto out_err;
-               }
-
-               proxy->conf.args.ctx = ARGC_HRQ;
-               error = NULL;
-               if (!parse_logformat_string(args[cur_arg + 2], proxy, &rule->arg.hdr_add.fmt, LOG_OPT_HTTP,
-                                           (proxy->cap & PR_CAP_BE) ? SMP_VAL_BE_HRS_HDR : SMP_VAL_FE_HRS_HDR, &error)) {
-                       ha_alert("parsing [%s:%d]: 'http-response %s': %s.\n",
-                                file, linenum, args[0], error);
-                       free(error);
-                       goto out_err;
-               }
-
-               free(proxy->conf.lfs_file);
-               proxy->conf.lfs_file = strdup(proxy->conf.args.file);
-               proxy->conf.lfs_line = proxy->conf.args.line;
-               cur_arg += 3;
-       } else if (strcmp(args[0], "del-header") == 0) {
-               rule->action = ACT_HTTP_DEL_HDR;
-               cur_arg = 1;
-
-               if (!*args[cur_arg] ||
-                   (*args[cur_arg+1] && strcmp(args[cur_arg+1], "if") != 0 && strcmp(args[cur_arg+1], "unless") != 0)) {
-                       ha_alert("parsing [%s:%d]: 'http-response %s' expects exactly 1 argument.\n",
-                                file, linenum, args[0]);
-                       goto out_err;
-               }
-
-               rule->arg.hdr_add.name = strdup(args[cur_arg]);
-               rule->arg.hdr_add.name_len = strlen(rule->arg.hdr_add.name);
-
-               proxy->conf.args.ctx = ARGC_HRS;
-               free(proxy->conf.lfs_file);
-               proxy->conf.lfs_file = strdup(proxy->conf.args.file);
-               proxy->conf.lfs_line = proxy->conf.args.line;
-               cur_arg += 1;
-       } else if (strncmp(args[0], "add-acl", 7) == 0) {
-               /* http-request add-acl(<reference (acl name)>) <key pattern> */
-               rule->action = ACT_HTTP_ADD_ACL;
-               /*
-                * '+ 8' for 'add-acl('
-                * '- 9' for 'add-acl(' + trailing ')'
-                */
-               rule->arg.map.ref = my_strndup(args[0] + 8, strlen(args[0]) - 9);
-
-               cur_arg = 1;
-
-               if (!*args[cur_arg] ||
-                   (*args[cur_arg+1] && strcmp(args[cur_arg+1], "if") != 0 && strcmp(args[cur_arg+1], "unless") != 0)) {
-                       ha_alert("parsing [%s:%d]: 'http-response %s' expects exactly 1 argument.\n",
-                                file, linenum, args[0]);
-                       goto out_err;
-               }
-
-               LIST_INIT(&rule->arg.map.key);
-               proxy->conf.args.ctx = ARGC_HRS;
-               error = NULL;
-               if (!parse_logformat_string(args[cur_arg], proxy, &rule->arg.map.key, LOG_OPT_HTTP,
-                                           (proxy->cap & PR_CAP_BE) ? SMP_VAL_BE_HRS_HDR : SMP_VAL_FE_HRS_HDR, &error)) {
-                       ha_alert("parsing [%s:%d]: 'http-response %s': %s.\n",
-                                file, linenum, args[0], error);
-                       free(error);
-                       goto out_err;
-               }
-               free(proxy->conf.lfs_file);
-               proxy->conf.lfs_file = strdup(proxy->conf.args.file);
-               proxy->conf.lfs_line = proxy->conf.args.line;
-
-               cur_arg += 1;
-       } else if (strncmp(args[0], "del-acl", 7) == 0) {
-               /* http-response del-acl(<reference (acl name)>) <key pattern> */
-               rule->action = ACT_HTTP_DEL_ACL;
-               /*
-                * '+ 8' for 'del-acl('
-                * '- 9' for 'del-acl(' + trailing ')'
-                */
-               rule->arg.map.ref = my_strndup(args[0] + 8, strlen(args[0]) - 9);
-
-               cur_arg = 1;
-
-               if (!*args[cur_arg] ||
-                   (*args[cur_arg+1] && strcmp(args[cur_arg+1], "if") != 0 && strcmp(args[cur_arg+1], "unless") != 0)) {
-                       ha_alert("parsing [%s:%d]: 'http-response %s' expects exactly 1 argument.\n",
-                                file, linenum, args[0]);
-                       goto out_err;
-               }
-
-               LIST_INIT(&rule->arg.map.key);
-               proxy->conf.args.ctx = ARGC_HRS;
-               error = NULL;
-               if (!parse_logformat_string(args[cur_arg], proxy, &rule->arg.map.key, LOG_OPT_HTTP,
-                                           (proxy->cap & PR_CAP_BE) ? SMP_VAL_BE_HRS_HDR : SMP_VAL_FE_HRS_HDR, &error)) {
-                       ha_alert("parsing [%s:%d]: 'http-response %s': %s.\n",
-                                file, linenum, args[0], error);
-                       free(error);
-                       goto out_err;
-               }
-               free(proxy->conf.lfs_file);
-               proxy->conf.lfs_file = strdup(proxy->conf.args.file);
-               proxy->conf.lfs_line = proxy->conf.args.line;
-               cur_arg += 1;
-       } else if (strncmp(args[0], "del-map", 7) == 0) {
-               /* http-response del-map(<reference (map name)>) <key pattern> */
-               rule->action = ACT_HTTP_DEL_MAP;
-               /*
-                * '+ 8' for 'del-map('
-                * '- 9' for 'del-map(' + trailing ')'
-                */
-               rule->arg.map.ref = my_strndup(args[0] + 8, strlen(args[0]) - 9);
-
-               cur_arg = 1;
-
-               if (!*args[cur_arg] ||
-                   (*args[cur_arg+1] && strcmp(args[cur_arg+1], "if") != 0 && strcmp(args[cur_arg+1], "unless") != 0)) {
-                       ha_alert("parsing [%s:%d]: 'http-response %s' expects exactly 1 argument.\n",
-                                file, linenum, args[0]);
-                       goto out_err;
-               }
-
-               LIST_INIT(&rule->arg.map.key);
-               proxy->conf.args.ctx = ARGC_HRS;
-               error = NULL;
-               if (!parse_logformat_string(args[cur_arg], proxy, &rule->arg.map.key, LOG_OPT_HTTP,
-                                           (proxy->cap & PR_CAP_BE) ? SMP_VAL_BE_HRS_HDR : SMP_VAL_FE_HRS_HDR, &error)) {
-                       ha_alert("parsing [%s:%d]: 'http-response %s' %s.\n",
-                                file, linenum, args[0], error);
-                       free(error);
-                       goto out_err;
-               }
-               free(proxy->conf.lfs_file);
-               proxy->conf.lfs_file = strdup(proxy->conf.args.file);
-               proxy->conf.lfs_line = proxy->conf.args.line;
-               cur_arg += 1;
-       } else if (strncmp(args[0], "set-map", 7) == 0) {
-               /* http-response set-map(<reference (map name)>) <key pattern> <value pattern> */
-               rule->action = ACT_HTTP_SET_MAP;
-               /*
-                * '+ 8' for 'set-map('
-                * '- 9' for 'set-map(' + trailing ')'
-                */
-               rule->arg.map.ref = my_strndup(args[0] + 8, strlen(args[0]) - 9);
-
-               cur_arg = 1;
-
-               if (!*args[cur_arg] || !*args[cur_arg+1] ||
-                   (*args[cur_arg+2] && strcmp(args[cur_arg+2], "if") != 0 && strcmp(args[cur_arg+2], "unless") != 0)) {
-                       ha_alert("parsing [%s:%d]: 'http-response %s' expects exactly 2 arguments.\n",
-                                file, linenum, args[0]);
-                       goto out_err;
-               }
-
-               LIST_INIT(&rule->arg.map.key);
-               LIST_INIT(&rule->arg.map.value);
-
-               proxy->conf.args.ctx = ARGC_HRS;
-
-               /* key pattern */
-               error = NULL;
-               if (!parse_logformat_string(args[cur_arg], proxy, &rule->arg.map.key, LOG_OPT_HTTP,
-                                           (proxy->cap & PR_CAP_BE) ? SMP_VAL_BE_HRS_HDR : SMP_VAL_FE_HRS_HDR, &error)) {
-                       ha_alert("parsing [%s:%d]: 'http-response %s' name: %s.\n",
-                                file, linenum, args[0], error);
-                       free(error);
-                       goto out_err;
-               }
-
-               /* value pattern */
-               error = NULL;
-               if (!parse_logformat_string(args[cur_arg + 1], proxy, &rule->arg.map.value, LOG_OPT_HTTP,
-                                           (proxy->cap & PR_CAP_BE) ? SMP_VAL_BE_HRS_HDR : SMP_VAL_FE_HRS_HDR, &error)) {
-                       ha_alert("parsing [%s:%d]: 'http-response %s' value: %s.\n",
-                                file, linenum, args[0], error);
-                       free(error);
-                       goto out_err;
-               }
-
-               free(proxy->conf.lfs_file);
-               proxy->conf.lfs_file = strdup(proxy->conf.args.file);
-               proxy->conf.lfs_line = proxy->conf.args.line;
-
-               cur_arg += 2;
-       } else if (strcmp(args[0], "redirect") == 0) {
-               struct redirect_rule *redir;
-               char *errmsg = NULL;
-
-               if ((redir = http_parse_redirect_rule(file, linenum, proxy, (const char **)args + 1, &errmsg, 1, 1)) == NULL) {
-                       ha_alert("parsing [%s:%d] : error detected in %s '%s' while parsing 'http-response %s' rule : %s.\n",
-                                file, linenum, proxy_type_str(proxy), proxy->id, args[0], errmsg);
-                       goto out_err;
-               }
-
-               /* this redirect rule might already contain a parsed condition which
-                * we'll pass to the http-request rule.
-                */
-               rule->action = ACT_HTTP_REDIR;
-               rule->arg.redir = redir;
-               rule->cond = redir->cond;
-               redir->cond = NULL;
-               cur_arg = 2;
-               return rule;
-       } else if (strncmp(args[0], "track-sc", 8) == 0) {
-               struct sample_expr *expr;
-               unsigned int where;
-               char *err = NULL;
-               unsigned int tsc_num;
-               const char *tsc_num_str;
-
-               cur_arg = 1;
-               proxy->conf.args.ctx = ARGC_TRK;
-
-               tsc_num_str = &args[0][8];
-               if (cfg_parse_track_sc_num(&tsc_num, tsc_num_str, tsc_num_str + strlen(tsc_num_str), &err) == -1) {
-                       ha_alert("parsing [%s:%d] : error detected in %s '%s' while parsing 'http-response %s' rule : %s.\n",
-                                file, linenum, proxy_type_str(proxy), proxy->id, args[0], err);
-                       free(err);
-                       goto out_err;
-               }
-
-               expr = sample_parse_expr((char **)args, &cur_arg, file, linenum, &err, &proxy->conf.args);
-               if (!expr) {
-                       ha_alert("parsing [%s:%d] : error detected in %s '%s' while parsing 'http-response %s' rule : %s.\n",
-                                file, linenum, proxy_type_str(proxy), proxy->id, args[0], err);
-                       free(err);
-                       goto out_err;
-               }
-
-               where = 0;
-               if (proxy->cap & PR_CAP_FE)
-                       where |= SMP_VAL_FE_HRS_HDR;
-               if (proxy->cap & PR_CAP_BE)
-                       where |= SMP_VAL_BE_HRS_HDR;
-
-               if (!(expr->fetch->val & where)) {
-                       ha_alert("parsing [%s:%d] : error detected in %s '%s' while parsing 'http-response %s' rule :"
-                                " fetch method '%s' extracts information from '%s', none of which is available here.\n",
-                                file, linenum, proxy_type_str(proxy), proxy->id, args[0],
-                                args[cur_arg-1], sample_src_names(expr->fetch->use));
-                       free(expr);
-                       goto out_err;
-               }
-
-               if (strcmp(args[cur_arg], "table") == 0) {
-                       cur_arg++;
-                       if (!args[cur_arg]) {
-                               ha_alert("parsing [%s:%d] : error detected in %s '%s' while parsing 'http-response %s' rule : missing table name.\n",
-                                        file, linenum, proxy_type_str(proxy), proxy->id, args[0]);
-                               free(expr);
-                               goto out_err;
-                       }
-                       /* we copy the table name for now, it will be resolved later */
-                       rule->arg.trk_ctr.table.n = strdup(args[cur_arg]);
-                       cur_arg++;
-               }
-               rule->arg.trk_ctr.expr = expr;
-               rule->action = ACT_ACTION_TRK_SC0 + tsc_num;
-               rule->check_ptr = check_trk_action;
-       } else if (((custom = action_http_res_custom(args[0])) != NULL)) {
-               char *errmsg = NULL;
-               cur_arg = 1;
-               /* try in the module list */
-               rule->from = ACT_F_HTTP_RES;
-               rule->kw = custom;
-               if (custom->parse(args, &cur_arg, proxy, rule, &errmsg) == ACT_RET_PRS_ERR) {
-                       ha_alert("parsing [%s:%d] : error detected in %s '%s' while parsing 'http-response %s' rule : %s.\n",
-                                file, linenum, proxy_type_str(proxy), proxy->id, args[0], errmsg);
-                       free(errmsg);
-                       goto out_err;
-               }
-       } else {
-               action_build_list(&http_res_keywords.list, &trash);
-               ha_alert("parsing [%s:%d]: 'http-response' expects 'allow', 'deny', 'redirect', "
-                        "'add-header', 'del-header', 'set-header', 'replace-header', 'replace-value', 'set-nice', "
-                        "'set-tos', 'set-mark', 'set-log-level', 'add-acl', 'del-acl', 'del-map', 'set-map', 'track-sc*'"
-                        "%s%s, but got '%s'%s.\n",
-                        file, linenum, *trash.area ? ", " : "", trash.area,
-                        args[0], *args[0] ? "" : " (missing argument)");
-               goto out_err;
-       }
-
-       if (strcmp(args[cur_arg], "if") == 0 || strcmp(args[cur_arg], "unless") == 0) {
-               struct acl_cond *cond;
-               char *errmsg = NULL;
-
-               if ((cond = build_acl_cond(file, linenum, &proxy->acl, proxy, args+cur_arg, &errmsg)) == NULL) {
-                       ha_alert("parsing [%s:%d] : error detected while parsing an 'http-response %s' condition : %s.\n",
-                                file, linenum, args[0], errmsg);
-                       free(errmsg);
-                       goto out_err;
-               }
-               rule->cond = cond;
-       }
-       else if (*args[cur_arg]) {
-               ha_alert("parsing [%s:%d]: 'http-response %s' expects"
-                        " either 'if' or 'unless' followed by a condition but found '%s'.\n",
-                        file, linenum, args[0], args[cur_arg]);
-               goto out_err;
-       }
-
-       return rule;
- out_err:
-       free(rule);
-       return NULL;
-}
-
-/* Parses a redirect rule. Returns the redirect rule on success or NULL on error,
- * with <err> filled with the error message. If <use_fmt> is not null, builds a
- * dynamic log-format rule instead of a static string. Parameter <dir> indicates
- * the direction of the rule, and equals 0 for request, non-zero for responses.
- */
-struct redirect_rule *http_parse_redirect_rule(const char *file, int linenum, struct proxy *curproxy,
-                                               const char **args, char **errmsg, int use_fmt, int dir)
-{
-       struct redirect_rule *rule;
-       int cur_arg;
-       int type = REDIRECT_TYPE_NONE;
-       int code = 302;
-       const char *destination = NULL;
-       const char *cookie = NULL;
-       int cookie_set = 0;
-       unsigned int flags = REDIRECT_FLAG_NONE;
-       struct acl_cond *cond = NULL;
-
-       cur_arg = 0;
-       while (*(args[cur_arg])) {
-               if (strcmp(args[cur_arg], "location") == 0) {
-                       if (!*args[cur_arg + 1])
-                               goto missing_arg;
-
-                       type = REDIRECT_TYPE_LOCATION;
-                       cur_arg++;
-                       destination = args[cur_arg];
-               }
-               else if (strcmp(args[cur_arg], "prefix") == 0) {
-                       if (!*args[cur_arg + 1])
-                               goto missing_arg;
-                       type = REDIRECT_TYPE_PREFIX;
-                       cur_arg++;
-                       destination = args[cur_arg];
-               }
-               else if (strcmp(args[cur_arg], "scheme") == 0) {
-                       if (!*args[cur_arg + 1])
-                               goto missing_arg;
-
-                       type = REDIRECT_TYPE_SCHEME;
-                       cur_arg++;
-                       destination = args[cur_arg];
-               }
-               else if (strcmp(args[cur_arg], "set-cookie") == 0) {
-                       if (!*args[cur_arg + 1])
-                               goto missing_arg;
-
-                       cur_arg++;
-                       cookie = args[cur_arg];
-                       cookie_set = 1;
-               }
-               else if (strcmp(args[cur_arg], "clear-cookie") == 0) {
-                       if (!*args[cur_arg + 1])
-                               goto missing_arg;
-
-                       cur_arg++;
-                       cookie = args[cur_arg];
-                       cookie_set = 0;
-               }
-               else if (strcmp(args[cur_arg], "code") == 0) {
-                       if (!*args[cur_arg + 1])
-                               goto missing_arg;
-
-                       cur_arg++;
-                       code = atol(args[cur_arg]);
-                       if (code < 301 || code > 308 || (code > 303 && code < 307)) {
-                               memprintf(errmsg,
-                                         "'%s': unsupported HTTP code '%s' (must be one of 301, 302, 303, 307 or 308)",
-                                         args[cur_arg - 1], args[cur_arg]);
-                               return NULL;
-                       }
-               }
-               else if (!strcmp(args[cur_arg],"drop-query")) {
-                       flags |= REDIRECT_FLAG_DROP_QS;
-               }
-               else if (!strcmp(args[cur_arg],"append-slash")) {
-                       flags |= REDIRECT_FLAG_APPEND_SLASH;
-               }
-               else if (strcmp(args[cur_arg], "if") == 0 ||
-                        strcmp(args[cur_arg], "unless") == 0) {
-                       cond = build_acl_cond(file, linenum, &curproxy->acl, curproxy, (const char **)args + cur_arg, errmsg);
-                       if (!cond) {
-                               memprintf(errmsg, "error in condition: %s", *errmsg);
-                               return NULL;
-                       }
-                       break;
-               }
-               else {
-                       memprintf(errmsg,
-                                 "expects 'code', 'prefix', 'location', 'scheme', 'set-cookie', 'clear-cookie', 'drop-query' or 'append-slash' (was '%s')",
-                                 args[cur_arg]);
-                       return NULL;
-               }
-               cur_arg++;
-       }
-
-       if (type == REDIRECT_TYPE_NONE) {
-               memprintf(errmsg, "redirection type expected ('prefix', 'location', or 'scheme')");
-               return NULL;
-       }
-
-       if (dir && type != REDIRECT_TYPE_LOCATION) {
-               memprintf(errmsg, "response only supports redirect type 'location'");
-               return NULL;
-       }
-
-       rule = calloc(1, sizeof(*rule));
-       rule->cond = cond;
-       LIST_INIT(&rule->rdr_fmt);
-
-       if (!use_fmt) {
-               /* old-style static redirect rule */
-               rule->rdr_str = strdup(destination);
-               rule->rdr_len = strlen(destination);
-       }
-       else {
-               /* log-format based redirect rule */
-
-               /* Parse destination. Note that in the REDIRECT_TYPE_PREFIX case,
-                * if prefix == "/", we don't want to add anything, otherwise it
-                * makes it hard for the user to configure a self-redirection.
-                */
-               curproxy->conf.args.ctx = ARGC_RDR;
-               if (!(type == REDIRECT_TYPE_PREFIX && destination[0] == '/' && destination[1] == '\0')) {
-                       if (!parse_logformat_string(destination, curproxy, &rule->rdr_fmt, LOG_OPT_HTTP,
-                                                   dir ? (curproxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRS_HDR : SMP_VAL_BE_HRS_HDR
-                                                       : (curproxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR,
-                                                   errmsg)) {
-                               return  NULL;
-                       }
-                       free(curproxy->conf.lfs_file);
-                       curproxy->conf.lfs_file = strdup(curproxy->conf.args.file);
-                       curproxy->conf.lfs_line = curproxy->conf.args.line;
-               }
-       }
-
-       if (cookie) {
-               /* depending on cookie_set, either we want to set the cookie, or to clear it.
-                * a clear consists in appending "; path=/; Max-Age=0;" at the end.
-                */
-               rule->cookie_len = strlen(cookie);
-               if (cookie_set) {
-                       rule->cookie_str = malloc(rule->cookie_len + 10);
-                       memcpy(rule->cookie_str, cookie, rule->cookie_len);
-                       memcpy(rule->cookie_str + rule->cookie_len, "; path=/;", 10);
-                       rule->cookie_len += 9;
-               } else {
-                       rule->cookie_str = malloc(rule->cookie_len + 21);
-                       memcpy(rule->cookie_str, cookie, rule->cookie_len);
-                       memcpy(rule->cookie_str + rule->cookie_len, "; path=/; Max-Age=0;", 21);
-                       rule->cookie_len += 20;
-               }
-       }
-       rule->type = type;
-       rule->code = code;
-       rule->flags = flags;
-       LIST_INIT(&rule->list);
-       return rule;
-
- missing_arg:
-       memprintf(errmsg, "missing argument for '%s'", args[cur_arg]);
-       return NULL;
-}
-
 /* This function executes one of the set-{method,path,query,uri} actions. It
  * takes the string from the variable 'replace' with length 'len', then modifies
  * the relevant part of the request line accordingly. Then it updates various
@@ -8940,23 +7794,6 @@ void http_set_status(unsigned int status, const char *reason, struct stream *s)
        http_msg_move_end(&txn->rsp, delta);
 }
 
-/*
- * Return the struct http_req_action_kw associated to a keyword.
- */
-struct action_kw *action_http_req_custom(const char *kw)
-{
-       return action_lookup(&http_req_keywords.list, kw);
-}
-
-/*
- * Return the struct http_res_action_kw associated to a keyword.
- */
-struct action_kw *action_http_res_custom(const char *kw)
-{
-       return action_lookup(&http_res_keywords.list, kw);
-}
-
-
 __attribute__((constructor))
 static void __http_protocol_init(void)
 {
index c000602b64f624a73f421b39e9c52f0c4061c04d..3cc622a6d453b2bda12dcaf55e4566aa998ab36c 100644 (file)
@@ -49,6 +49,7 @@
 #include <proto/channel.h>
 #include <proto/connection.h>
 #include <proto/fd.h>
+#include <proto/http_rules.h>
 #include <proto/listener.h>
 #include <proto/log.h>
 #include <proto/port_range.h>
index 245fb7dad5adcedfd130645ca1c52a5e7275689b..a5f129d50367659872dd8d464df7bb4cba610f9d 100644 (file)
@@ -75,6 +75,7 @@
 #include <common/hathreads.h>
 #include <eb32tree.h>
 
+#include <proto/http_rules.h>
 #include <proto/proto_http.h>
 #include <proto/queue.h>
 #include <proto/sample.h>
index 0899418f4092aa47519e725e97d9d424c3951c14..5bd0abf9a21434c7ca80abace95f6090ad452f4f 100644 (file)
@@ -91,6 +91,7 @@
 #include <proto/fd.h>
 #include <proto/freq_ctr.h>
 #include <proto/frontend.h>
+#include <proto/http_rules.h>
 #include <proto/listener.h>
 #include <proto/openssl-compat.h>
 #include <proto/pattern.h>
index e8d4f3a6038b4a21cda2b7c8d27ae3e5f0ad44e3..d2aea6d9755b9caafa7bb650396c64f7f54f9b57 100644 (file)
@@ -29,6 +29,7 @@
 
 #include <proto/arg.h>
 #include <proto/cli.h>
+#include <proto/http_rules.h>
 #include <proto/log.h>
 #include <proto/proto_http.h>
 #include <proto/proto_tcp.h>
index 266f3b1636b9bc3c057aaba8fca03d5edd50ba13..b616346741951df4a6c2882fb81b9dc703499982 100644 (file)
@@ -43,6 +43,7 @@
 #include <proto/frontend.h>
 #include <proto/hdr_idx.h>
 #include <proto/hlua.h>
+#include <proto/http_rules.h>
 #include <proto/listener.h>
 #include <proto/log.h>
 #include <proto/raw_sock.h>
index 905e20c4f2eeb6efd85db2f909aec491b2a5d31a..7cc06d6dc93420c9521ffe4c5d20cbf06a340b89 100644 (file)
@@ -7,6 +7,7 @@
 #include <types/vars.h>
 
 #include <proto/arg.h>
+#include <proto/http_rules.h>
 #include <proto/proto_http.h>
 #include <proto/sample.h>
 #include <proto/stream.h>