#include <string.h>
#include <time.h>
+#include <common/cfgparse.h>
#include <common/chunk.h>
#include <common/compat.h>
#include <common/config.h>
#include <proto/acl.h>
#include <proto/arg.h>
+#include <proto/action.h>
#include <proto/http_rules.h>
#include <proto/http_htx.h>
#include <proto/log.h>
return ACT_RET_PRS_OK;
}
+/* Parse a "allow" action for a request or a response rule. It takes no argument. It
+ * returns ACT_RET_PRS_OK on success, ACT_RET_PRS_ERR on error.
+ */
+static enum act_parse_ret parse_http_allow(const char **args, int *orig_arg, struct proxy *px,
+ struct act_rule *rule, char **err)
+{
+ rule->action = ACT_ACTION_ALLOW;
+ return ACT_RET_PRS_OK;
+}
+
+/* Parse "deny" or "tarpit" actions for a request rule. It may take 2 optional arguments
+ * to define the status code. It returns ACT_RET_PRS_OK on success,
+ * ACT_RET_PRS_ERR on error.
+ */
+static enum act_parse_ret parse_http_req_deny(const char **args, int *orig_arg, struct proxy *px,
+ struct act_rule *rule, char **err)
+{
+ int code, hc, cur_arg;
+
+ cur_arg = *orig_arg;
+ if (!strcmp(args[cur_arg-1], "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;
+ }
+
+ if (strcmp(args[cur_arg], "deny_status") == 0) {
+ cur_arg++;
+ if (!*args[cur_arg]) {
+ memprintf(err, "missing status code.\n");
+ return ACT_RET_PRS_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)
+ memprintf(err, "status code %d not handled, using default code %d",
+ code, http_err_codes[rule->deny_status]);
+ }
+
+ *orig_arg = cur_arg;
+ return ACT_RET_PRS_OK;
+}
+
+/* Parse a "deny" action for a response rule. It takes no argument. It returns
+ * ACT_RET_PRS_OK on success, ACT_RET_PRS_ERR on error.
+ */
+static enum act_parse_ret parse_http_res_deny(const char **args, int *orig_arg, struct proxy *px,
+ struct act_rule *rule, char **err)
+{
+ rule->action = ACT_ACTION_DENY;
+ return ACT_RET_PRS_OK;
+}
+
+/* Parse a "auth" action. It may take 2 optional arguments to define a "realm"
+ * parameter. It returns ACT_RET_PRS_OK on success, ACT_RET_PRS_ERR on error.
+ */
+static enum act_parse_ret parse_http_auth(const char **args, int *orig_arg, struct proxy *px,
+ struct act_rule *rule, char **err)
+{
+ int cur_arg;
+
+ rule->action = ACT_HTTP_REQ_AUTH;
+
+ cur_arg = *orig_arg;
+ if (!strcmp(args[cur_arg], "realm")) {
+ cur_arg++;
+ if (!*args[cur_arg]) {
+ memprintf(err, "missing realm value.\n");
+ return ACT_RET_PRS_ERR;
+ }
+ rule->arg.auth.realm = strdup(args[cur_arg]);
+ cur_arg++;
+ }
+
+ *orig_arg = cur_arg;
+ return ACT_RET_PRS_OK;
+}
+
+/* Parse a "set-nice" action. It takes the nice value as argument. It returns
+ * ACT_RET_PRS_OK on success, ACT_RET_PRS_ERR on error.
+ */
+static enum act_parse_ret parse_http_set_nice(const char **args, int *orig_arg, struct proxy *px,
+ struct act_rule *rule, char **err)
+{
+ int cur_arg;
+
+ rule->action = ACT_HTTP_SET_NICE;
+
+ cur_arg = *orig_arg;
+ if (!*args[cur_arg]) {
+ memprintf(err, "expects exactly 1 argument (integer value)");
+ return ACT_RET_PRS_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;
+
+ *orig_arg = cur_arg + 1;
+ return ACT_RET_PRS_OK;
+}
+
+/* Parse a "set-tos" action. It takes the TOS value as argument. It returns
+ * ACT_RET_PRS_OK on success, ACT_RET_PRS_ERR on error.
+ */
+static enum act_parse_ret parse_http_set_tos(const char **args, int *orig_arg, struct proxy *px,
+ struct act_rule *rule, char **err)
+{
+#ifdef IP_TOS
+ char *endp;
+ int cur_arg;
+
+ rule->action = ACT_HTTP_SET_TOS;
+
+ cur_arg = *orig_arg;
+ if (!*args[cur_arg]) {
+ memprintf(err, "expects exactly 1 argument (integer/hex value)");
+ return ACT_RET_PRS_ERR;
+ }
+ rule->arg.tos = strtol(args[cur_arg], &endp, 0);
+ if (endp && *endp != '\0') {
+ memprintf(err, "invalid character starting at '%s' (integer/hex value expected)", endp);
+ return ACT_RET_PRS_ERR;
+ }
+
+ *orig_arg = cur_arg + 1;
+ return ACT_RET_PRS_OK;
+#else
+ memprintf(err, "not supported on this platform (IP_TOS undefined)");
+ return ACT_RET_PRS_ERR;
+#endif
+}
+
+/* Parse a "set-mark" action. It takes the MARK value as argument. It returns
+ * ACT_RET_PRS_OK on success, ACT_RET_PRS_ERR on error.
+ */
+static enum act_parse_ret parse_http_set_mark(const char **args, int *orig_arg, struct proxy *px,
+ struct act_rule *rule, char **err)
+{
+#ifdef SO_MARK
+ char *endp;
+ int cur_arg;
+
+ rule->action = ACT_HTTP_SET_MARK;
+
+ cur_arg = *orig_arg;
+ if (!*args[cur_arg]) {
+ memprintf(err, "expects exactly 1 argument (integer/hex value)");
+ return ACT_RET_PRS_ERR;
+ }
+ rule->arg.mark = strtoul(args[cur_arg], &endp, 0);
+ if (endp && *endp != '\0') {
+ memprintf(err, "invalid character starting at '%s' (integer/hex value expected)", endp);
+ return ACT_RET_PRS_ERR;
+ }
+
+ *orig_arg = cur_arg + 1;
+ global.last_checks |= LSTCHK_NETADM;
+ return ACT_RET_PRS_OK;
+#else
+ memprintf(err, "not supported on this platform (SO_MARK undefined)");
+ return ACT_RET_PRS_ERR;
+#endif
+}
+
+/* Parse a "set-log-level" action. It takes the level value as argument. It
+ * returns ACT_RET_PRS_OK on success, ACT_RET_PRS_ERR on error.
+ */
+static enum act_parse_ret parse_http_set_log_level(const char **args, int *orig_arg, struct proxy *px,
+ struct act_rule *rule, char **err)
+{
+ int cur_arg;
+
+ rule->action = ACT_HTTP_SET_LOGL;
+
+ cur_arg = *orig_arg;
+ if (!*args[cur_arg]) {
+ bad_log_level:
+ memprintf(err, "expects exactly 1 argument (log level name or 'silent')");
+ return ACT_RET_PRS_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;
+
+ *orig_arg = cur_arg + 1;
+ return ACT_RET_PRS_OK;
+}
+
+/* Parse a "set-header", "add-header" or "early-hint" actions. It takes an
+ * header name and a log-format string as arguments. It returns ACT_RET_PRS_OK
+ * on success, ACT_RET_PRS_ERR on error.
+ *
+ * Note: same function is used for the request and the response. However
+ * "early-hint" rules are only supported for request rules.
+ */
+static enum act_parse_ret parse_http_set_header(const char **args, int *orig_arg, struct proxy *px,
+ struct act_rule *rule, char **err)
+{
+ char **hdr_name;
+ int *hdr_name_len;
+ struct list *fmt;
+ int cap, cur_arg;
+
+ rule->action = (*args[*orig_arg-1] == 'a' ? ACT_HTTP_ADD_HDR :
+ *args[*orig_arg-1] == 's' ? ACT_HTTP_SET_HDR : ACT_HTTP_EARLY_HINT);
+
+ cur_arg = *orig_arg;
+ if (!*args[cur_arg] || !*args[cur_arg+1]) {
+ memprintf(err, "expects exactly 2 arguments");
+ return ACT_RET_PRS_ERR;
+ }
+
+ hdr_name = (*args[cur_arg-1] == 'e' ? &rule->arg.early_hint.name : &rule->arg.hdr_add.name);
+ hdr_name_len = (*args[cur_arg-1] == 'e' ? &rule->arg.early_hint.name_len : &rule->arg.hdr_add.name_len);
+ fmt = (*args[cur_arg-1] == 'e' ? &rule->arg.early_hint.fmt : &rule->arg.hdr_add.fmt);
+
+ *hdr_name = strdup(args[cur_arg]);
+ *hdr_name_len = strlen(*hdr_name);
+ LIST_INIT(fmt);
+
+ if (rule->from == ACT_F_HTTP_REQ) {
+ px->conf.args.ctx = ARGC_HRQ;
+ cap = (px->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR;
+ }
+ else{
+ px->conf.args.ctx = ARGC_HRS;
+ cap = (px->cap & PR_CAP_BE) ? SMP_VAL_BE_HRS_HDR : SMP_VAL_FE_HRS_HDR;
+ }
+
+ cur_arg++;
+ if (!parse_logformat_string(args[cur_arg], px, fmt, LOG_OPT_HTTP, cap, err))
+ return ACT_RET_PRS_ERR;
+
+ free(px->conf.lfs_file);
+ px->conf.lfs_file = strdup(px->conf.args.file);
+ px->conf.lfs_line = px->conf.args.line;
+
+ *orig_arg = cur_arg + 1;
+ return ACT_RET_PRS_OK;
+}
+
+/* Parse a "replace-header" or "replace-value" actions. It takes an header name,
+ * a regex and replacement string as arguments. It returns ACT_RET_PRS_OK on
+ * success, ACT_RET_PRS_ERR on error.
+ */
+static enum act_parse_ret parse_http_replace_header(const char **args, int *orig_arg, struct proxy *px,
+ struct act_rule *rule, char **err)
+{
+ int cap, cur_arg;
+
+ rule->action = args[*orig_arg-1][8] == 'h' ? ACT_HTTP_REPLACE_HDR : ACT_HTTP_REPLACE_VAL;
+
+ cur_arg = *orig_arg;
+ if (!*args[cur_arg] || !*args[cur_arg+1] || !*args[cur_arg+2]) {
+ memprintf(err, "expects exactly 3 arguments");
+ return ACT_RET_PRS_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);
+
+ cur_arg++;
+ if (!(rule->arg.hdr_add.re = regex_comp(args[cur_arg], 1, 1, err)))
+ return ACT_RET_PRS_ERR;
+
+ if (rule->from == ACT_F_HTTP_REQ) {
+ px->conf.args.ctx = ARGC_HRQ;
+ cap = (px->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR;
+ }
+ else{
+ px->conf.args.ctx = ARGC_HRS;
+ cap = (px->cap & PR_CAP_BE) ? SMP_VAL_BE_HRS_HDR : SMP_VAL_FE_HRS_HDR;
+ }
+
+ cur_arg++;
+ if (!parse_logformat_string(args[cur_arg], px, &rule->arg.hdr_add.fmt, LOG_OPT_HTTP, cap, err))
+ return ACT_RET_PRS_ERR;
+
+ free(px->conf.lfs_file);
+ px->conf.lfs_file = strdup(px->conf.args.file);
+ px->conf.lfs_line = px->conf.args.line;
+
+ *orig_arg = cur_arg + 1;
+ return ACT_RET_PRS_OK;
+}
+
+/* Parse a "del-header" action. It takes an header name as argument. It returns
+ * ACT_RET_PRS_OK on success, ACT_RET_PRS_ERR on error.
+ */
+static enum act_parse_ret parse_http_del_header(const char **args, int *orig_arg, struct proxy *px,
+ struct act_rule *rule, char **err)
+{
+ int cur_arg;
+
+ rule->action = ACT_HTTP_DEL_HDR;
+
+ cur_arg = *orig_arg;
+ if (!*args[cur_arg]) {
+ memprintf(err, "expects exactly 1 arguments");
+ return ACT_RET_PRS_ERR;
+ }
+
+ rule->arg.hdr_add.name = strdup(args[cur_arg]);
+ rule->arg.hdr_add.name_len = strlen(rule->arg.hdr_add.name);
+
+ px->conf.args.ctx = (rule->from == ACT_F_HTTP_REQ ? ARGC_HRQ : ARGC_HRS);
+
+ *orig_arg = cur_arg + 1;
+ return ACT_RET_PRS_OK;
+}
+
+/* Parse a "redirect" action. It returns ACT_RET_PRS_OK on success,
+ * ACT_RET_PRS_ERR on error.
+ */
+static enum act_parse_ret parse_http_redirect(const char **args, int *orig_arg, struct proxy *px,
+ struct act_rule *rule, char **err)
+{
+ struct redirect_rule *redir;
+ int dir, cur_arg;
+
+ rule->action = ACT_HTTP_REDIR;
+
+ cur_arg = *orig_arg;
+
+ dir = (rule->from == ACT_F_HTTP_REQ ? 0 : 1);
+ if ((redir = http_parse_redirect_rule(px->conf.args.file, px->conf.args.line, px, &args[cur_arg], err, 1, dir)) == NULL)
+ return ACT_RET_PRS_ERR;
+
+ rule->arg.redir = redir;
+ rule->cond = redir->cond;
+ redir->cond = NULL;
+
+ /* skip all arguments */
+ while (*args[cur_arg])
+ cur_arg++;
+
+ *orig_arg = cur_arg;
+ return ACT_RET_PRS_OK;
+}
+
+/* Parse a "add-acl", "del-acl", "set-map" or "del-map" actions. It takes one or
+ * two log-format string as argument depending on the action. It returns
+ * ACT_RET_PRS_OK on success, ACT_RET_PRS_ERR on error.
+ */
+static enum act_parse_ret parse_http_set_map(const char **args, int *orig_arg, struct proxy *px,
+ struct act_rule *rule, char **err)
+{
+ int cap, cur_arg;
+
+ rule->action = (args[*orig_arg-1][0] == 'a' ? ACT_HTTP_ADD_ACL :
+ (args[*orig_arg-1][0] == 's' ? ACT_HTTP_SET_MAP :
+ (args[*orig_arg-1][4] == 'a' ? ACT_HTTP_DEL_ACL : ACT_HTTP_DEL_MAP)));
+
+ cur_arg = *orig_arg;
+ if (rule->action == ACT_HTTP_SET_MAP && (!*args[cur_arg] || !*args[cur_arg+1])) {
+ memprintf(err, "expects exactly 2 arguments");
+ return ACT_RET_PRS_ERR;
+ }
+ else if (!*args[cur_arg]) {
+ memprintf(err, "expects exactly 1 arguments");
+ return ACT_RET_PRS_ERR;
+ }
+
+ /*
+ * '+ 8' for 'set-map(' (same for del-map)
+ * '- 9' for 'set-map(' + trailing ')' (same for del-map)
+ */
+ rule->arg.map.ref = my_strndup(args[cur_arg-1] + 8, strlen(args[cur_arg-1]) - 9);
+
+ if (rule->from == ACT_F_HTTP_REQ) {
+ px->conf.args.ctx = ARGC_HRQ;
+ cap = (px->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR;
+ }
+ else{
+ px->conf.args.ctx = ARGC_HRS;
+ cap = (px->cap & PR_CAP_BE) ? SMP_VAL_BE_HRS_HDR : SMP_VAL_FE_HRS_HDR;
+ }
+
+ /* key pattern */
+ LIST_INIT(&rule->arg.map.key);
+ if (!parse_logformat_string(args[cur_arg], px, &rule->arg.map.key, LOG_OPT_HTTP, cap, err))
+ return ACT_RET_PRS_ERR;
+
+ if (rule->action == ACT_HTTP_SET_MAP) {
+ /* value pattern for set-map only */
+ cur_arg++;
+ LIST_INIT(&rule->arg.map.value);
+ if (!parse_logformat_string(args[cur_arg], px, &rule->arg.map.value, LOG_OPT_HTTP, cap, err))
+ return ACT_RET_PRS_ERR;
+ }
+
+ free(px->conf.lfs_file);
+ px->conf.lfs_file = strdup(px->conf.args.file);
+ px->conf.lfs_line = px->conf.args.line;
+
+ *orig_arg = cur_arg + 1;
+ return ACT_RET_PRS_OK;
+}
+
+
+/* Parse a "track-sc*" actions. It returns ACT_RET_PRS_OK on success,
+ * ACT_RET_PRS_ERR on error.
+ */
+static enum act_parse_ret parse_http_track_sc(const char **args, int *orig_arg, struct proxy *px,
+ struct act_rule *rule, char **err)
+{
+ struct sample_expr *expr;
+ unsigned int where;
+ unsigned int tsc_num;
+ const char *tsc_num_str;
+ int cur_arg;
+
+ tsc_num_str = &args[*orig_arg-1][8];
+ if (cfg_parse_track_sc_num(&tsc_num, tsc_num_str, tsc_num_str + strlen(tsc_num_str), err) == -1)
+ return ACT_RET_PRS_ERR;
+
+ cur_arg = *orig_arg;
+ expr = sample_parse_expr((char **)args, &cur_arg, px->conf.args.file, px->conf.args.line,
+ err, &px->conf.args);
+ if (!expr)
+ return ACT_RET_PRS_ERR;
+
+ where = 0;
+ if (px->cap & PR_CAP_FE)
+ where |= (rule->from == ACT_F_HTTP_REQ ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_FE_HRS_HDR);
+ if (px->cap & PR_CAP_BE)
+ where |= (rule->from == ACT_F_HTTP_REQ ? SMP_VAL_BE_HRQ_HDR : SMP_VAL_BE_HRS_HDR);
+
+ if (!(expr->fetch->val & where)) {
+ memprintf(err, "fetch method '%s' extracts information from '%s', none of which is available here",
+ args[cur_arg-1], sample_src_names(expr->fetch->use));
+ return ACT_RET_PRS_ERR;
+ }
+
+ if (strcmp(args[cur_arg], "table") == 0) {
+ cur_arg++;
+ if (!*args[cur_arg]) {
+ memprintf(err, "missing table name");
+ return ACT_RET_PRS_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;
+
+ *orig_arg = cur_arg;
+ return ACT_RET_PRS_OK;
+}
+
/************************************************************************/
/* All supported http-request action keywords must be declared here. */
/************************************************************************/
static struct action_kw_list http_req_actions = {
.kw = {
- { "capture", parse_http_req_capture },
- { "reject", parse_http_action_reject },
- { "disable-l7-retry", parse_http_req_disable_l7_retry },
- { "replace-path", parse_replace_uri },
- { "replace-uri", parse_replace_uri },
- { "set-method", parse_set_req_line },
- { "set-path", parse_set_req_line },
- { "set-query", parse_set_req_line },
- { "set-uri", parse_set_req_line },
+ { "add-acl", parse_http_set_map, 1 },
+ { "add-header", parse_http_set_header, 0 },
+ { "allow", parse_http_allow, 0 },
+ { "auth", parse_http_auth, 0 },
+ { "capture", parse_http_req_capture, 0 },
+ { "del-acl", parse_http_set_map, 1 },
+ { "del-header", parse_http_del_header, 0 },
+ { "del-map", parse_http_set_map, 1 },
+ { "deny", parse_http_req_deny, 0 },
+ { "disable-l7-retry", parse_http_req_disable_l7_retry, 0 },
+ { "early-hint", parse_http_set_header, 0 },
+ { "redirect", parse_http_redirect, 0 },
+ { "reject", parse_http_action_reject, 0 },
+ { "replace-header", parse_http_replace_header, 0 },
+ { "replace-path", parse_replace_uri, 0 },
+ { "replace-uri", parse_replace_uri, 0 },
+ { "replace-value", parse_http_replace_header, 0 },
+ { "set-header", parse_http_set_header, 0 },
+ { "set-log-level", parse_http_set_log_level, 0 },
+ { "set-map", parse_http_set_map, 1 },
+ { "set-method", parse_set_req_line, 0 },
+ { "set-mark", parse_http_set_mark, 0 },
+ { "set-nice", parse_http_set_nice, 0 },
+ { "set-path", parse_set_req_line, 0 },
+ { "set-query", parse_set_req_line, 0 },
+ { "set-tos", parse_http_set_tos, 0 },
+ { "set-uri", parse_set_req_line, 0 },
+ { "tarpit", parse_http_req_deny, 0 },
+ { "track-sc", parse_http_track_sc, 1 },
{ NULL, NULL }
}
};
static struct action_kw_list http_res_actions = {
.kw = {
- { "capture", parse_http_res_capture },
- { "set-status", parse_http_set_status },
+ { "add-acl", parse_http_set_map, 1 },
+ { "add-header", parse_http_set_header, 0 },
+ { "allow", parse_http_allow, 0 },
+ { "capture", parse_http_res_capture, 0 },
+ { "del-acl", parse_http_set_map, 1 },
+ { "del-header", parse_http_del_header, 0 },
+ { "del-map", parse_http_set_map, 1 },
+ { "deny", parse_http_res_deny, 0 },
+ { "redirect", parse_http_redirect, 0 },
+ { "replace-header", parse_http_replace_header, 0 },
+ { "replace-value", parse_http_replace_header, 0 },
+ { "set-header", parse_http_set_header, 0 },
+ { "set-log-level", parse_http_set_log_level, 0 },
+ { "set-map", parse_http_set_map, 1 },
+ { "set-mark", parse_http_set_mark, 0 },
+ { "set-nice", parse_http_set_nice, 0 },
+ { "set-status", parse_http_set_status, 0 },
+ { "set-tos", parse_http_set_tos, 0 },
+ { "track-sc", parse_http_track_sc, 1 },
{ NULL, NULL }
}
};
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;
}
+ rule->from = ACT_F_HTTP_REQ;
- 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 ||
- strcmp(args[0], "early-hint") == 0) {
- char **hdr_name;
- int *hdr_name_len;
- struct list *fmt;
-
- rule->action = *args[0] == 'a' ? ACT_HTTP_ADD_HDR :
- *args[0] == 's' ? ACT_HTTP_SET_HDR : ACT_HTTP_EARLY_HINT;
-
- hdr_name = *args[0] == 'e' ? &rule->arg.early_hint.name : &rule->arg.hdr_add.name;
- hdr_name_len = *args[0] == 'e' ? &rule->arg.early_hint.name_len : &rule->arg.hdr_add.name_len;
- fmt = *args[0] == 'e' ? &rule->arg.early_hint.fmt : &rule->arg.hdr_add.fmt;
-
- 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;
- }
-
- *hdr_name = strdup(args[cur_arg]);
- *hdr_name_len = strlen(*hdr_name);
- LIST_INIT(fmt);
-
- proxy->conf.args.ctx = ARGC_HRQ;
- error = NULL;
- if (!parse_logformat_string(args[cur_arg + 1], proxy, 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 (!(rule->arg.hdr_add.re = regex_comp(args[cur_arg + 1], 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;
+ if (((custom = action_http_req_custom(args[0])) != NULL)) {
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",
free(errmsg);
goto out_err;
}
- } else {
+ else if (errmsg) {
+ ha_warning("parsing [%s:%d] : %s.\n", file, linenum, errmsg);
+ free(errmsg);
+ }
+ }
+ 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",
+ ha_alert("parsing [%s:%d]: 'http-request' expects %s%s, but got '%s'%s.\n",
file, linenum, *trash.area ? ", " : "", trash.area,
args[0], *args[0] ? "" : " (missing argument)");
goto out_err;
rule->cond = cond;
}
else if (*args[cur_arg]) {
- ha_alert("parsing [%s:%d]: 'http-request %s' expects 'realm' for 'auth',"
- " 'deny_status' for 'deny', or"
+ ha_alert("parsing [%s:%d]: 'http-request %s' expects"
" either 'if' or 'unless' followed by a condition but found '%s'.\n",
file, linenum, args[0], args[cur_arg]);
goto out_err;
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;
}
+ rule->from = ACT_F_HTTP_RES;
- 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 (!(rule->arg.hdr_add.re = regex_comp(args[cur_arg + 1], 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;
+ if (((custom = action_http_res_custom(args[0])) != NULL)) {
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",
free(errmsg);
goto out_err;
}
- } else {
+ else if (errmsg) {
+ ha_warning("parsing [%s:%d] : %s.\n", file, linenum, errmsg);
+ free(errmsg);
+ }
+ }
+ 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",
+ ha_alert("parsing [%s:%d]: 'http-response' expects %s%s, but got '%s'%s.\n",
file, linenum, *trash.area ? ", " : "", trash.area,
args[0], *args[0] ? "" : " (missing argument)");
goto out_err;