mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-09-21 22:01:31 +02:00
MEDIUM: http: add actions "replace-header" and "replace-values" in http-req/resp
This patch adds two new actions to http-request and http-response rulesets : - replace-header : replace a whole header line, suited for headers which might contain commas - replace-value : replace a single header value, suited for headers defined as lists. The match consists in a regex, and the replacement string takes a log-format and supports back-references.
This commit is contained in:
parent
f5b1cc38b8
commit
218f064f55
@ -2878,6 +2878,8 @@ http-check send-state
|
||||
http-request { allow | deny | tarpit | auth [realm <realm>] | redirect <rule> |
|
||||
add-header <name> <fmt> | set-header <name> <fmt> |
|
||||
del-header <name> | set-nice <nice> | set-log-level <level> |
|
||||
replace-header <name> <match-regex> <replace-fmt> |
|
||||
replace-value <name> <match-regex> <replace-fmt> |
|
||||
set-tos <tos> | set-mark <mark> |
|
||||
add-acl(<file name>) <key fmt> |
|
||||
del-acl(<file name>) <key fmt> |
|
||||
@ -2945,6 +2947,47 @@ http-request { allow | deny | tarpit | auth [realm <realm>] | redirect <rule> |
|
||||
- "del-header" removes all HTTP header fields whose name is specified in
|
||||
<name>.
|
||||
|
||||
- "replace-header" matches the regular expression in all occurrences of
|
||||
header field <name> according to <match-regex>, and replaces them with
|
||||
the <replace-fmt> argument. Format characters are allowed in replace-fmt
|
||||
and work like in <fmt> arguments in "add-header". The match is only
|
||||
case-sensitive. It is important to understand that this action only
|
||||
considers whole header lines, regardless of the number of values they
|
||||
may contain. This usage is suited to headers naturally containing commas
|
||||
in their value, such as If-Modified-Since and so on.
|
||||
|
||||
Example:
|
||||
|
||||
http-request replace-header Cookie foo=([^;]*);(.*) foo=\1;ip=%bi;\2
|
||||
|
||||
applied to:
|
||||
|
||||
Cookie: foo=foobar; expires=Tue, 14-Jun-2016 01:40:45 GMT;
|
||||
|
||||
outputs:
|
||||
|
||||
Cookie: foo=foobar;ip=192.168.1.20; expires=Tue, 14-Jun-2016 01:40:45 GMT;
|
||||
|
||||
assuming the backend IP is 192.168.1.20
|
||||
|
||||
- "replace-value" works like "replace-header" except that it matches the
|
||||
regex against every comma-delimited value of the header field <name>
|
||||
instead of the entire header. This is suited for all headers which are
|
||||
allowed to carry more than one value. An example could be the Accept
|
||||
header.
|
||||
|
||||
Example:
|
||||
|
||||
http-request replace-value X-Forwarded-For ^192\.168\.(.*)$ 172.16.\1
|
||||
|
||||
applied to:
|
||||
|
||||
X-Forwarded-For: 192.168.10.1, 192.168.13.24, 10.0.0.37
|
||||
|
||||
outputs:
|
||||
|
||||
X-Forwarded-For: 172.16.10.1, 172.16.13.24, 10.0.0.37
|
||||
|
||||
- "set-nice" sets the "nice" factor of the current request being processed.
|
||||
It only has effect against the other requests being processed at the same
|
||||
time. The default value is 0, unless altered by the "nice" setting on the
|
||||
@ -3069,6 +3112,8 @@ http-request { allow | deny | tarpit | auth [realm <realm>] | redirect <rule> |
|
||||
|
||||
http-response { allow | deny | add-header <name> <fmt> | set-nice <nice> |
|
||||
set-header <name> <fmt> | del-header <name> |
|
||||
replace-header <name> <regex-match> <replace-fmt> |
|
||||
replace-value <name> <regex-match> <replace-fmt> |
|
||||
set-log-level <level> | set-mark <mark> | set-tos <tos> |
|
||||
add-acl(<file name>) <key fmt> |
|
||||
del-acl(<file name>) <key fmt> |
|
||||
@ -3113,6 +3158,47 @@ http-response { allow | deny | add-header <name> <fmt> | set-nice <nice> |
|
||||
- "del-header" removes all HTTP header fields whose name is specified in
|
||||
<name>.
|
||||
|
||||
- "replace-header" matches the regular expression in all occurrences of
|
||||
header field <name> according to <match-regex>, and replaces them with
|
||||
the <replace-fmt> argument. Format characters are allowed in replace-fmt
|
||||
and work like in <fmt> arguments in "add-header". The match is only
|
||||
case-sensitive. It is important to understand that this action only
|
||||
considers whole header lines, regardless of the number of values they
|
||||
may contain. This usage is suited to headers naturally containing commas
|
||||
in their value, such as Set-Cookie, Expires and so on.
|
||||
|
||||
Example:
|
||||
|
||||
http-response replace-header Set-Cookie (C=[^;]*);(.*) \1;ip=%bi;\2
|
||||
|
||||
applied to:
|
||||
|
||||
Set-Cookie: C=1; expires=Tue, 14-Jun-2016 01:40:45 GMT
|
||||
|
||||
outputs:
|
||||
|
||||
Set-Cookie: C=1;ip=192.168.1.20; expires=Tue, 14-Jun-2016 01:40:45 GMT
|
||||
|
||||
assuming the backend IP is 192.168.1.20.
|
||||
|
||||
- "replace-value" works like "replace-header" except that it matches the
|
||||
regex against every comma-delimited value of the header field <name>
|
||||
instead of the entire header. This is suited for all headers which are
|
||||
allowed to carry more than one value. An example could be the Accept
|
||||
header.
|
||||
|
||||
Example:
|
||||
|
||||
http-response replace-value Cache-control ^public$ private
|
||||
|
||||
applied to:
|
||||
|
||||
Cache-Control: max-age=3600, public
|
||||
|
||||
outputs:
|
||||
|
||||
Cache-Control: max-age=3600, private
|
||||
|
||||
- "set-nice" sets the "nice" factor of the current request being processed.
|
||||
It only has effect against the other requests being processed at the same
|
||||
time. The default value is 0, unless altered by the "nice" setting on the
|
||||
|
@ -116,6 +116,7 @@ void http_reset_txn(struct session *s);
|
||||
struct http_req_rule *parse_http_req_cond(const char **args, const char *file, int linenum, struct proxy *proxy);
|
||||
struct http_res_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 chunk *http_error_message(struct session *s, int msgnum);
|
||||
struct redirect_rule *http_parse_redirect_rule(const char *file, int linenum, struct proxy *curproxy,
|
||||
const char **args, char **errmsg, int use_fmt);
|
||||
|
@ -247,6 +247,8 @@ enum {
|
||||
HTTP_REQ_ACT_ADD_HDR,
|
||||
HTTP_REQ_ACT_SET_HDR,
|
||||
HTTP_REQ_ACT_DEL_HDR,
|
||||
HTTP_REQ_ACT_REPLACE_HDR,
|
||||
HTTP_REQ_ACT_REPLACE_VAL,
|
||||
HTTP_REQ_ACT_REDIR,
|
||||
HTTP_REQ_ACT_SET_NICE,
|
||||
HTTP_REQ_ACT_SET_LOGL,
|
||||
@ -267,6 +269,8 @@ enum {
|
||||
HTTP_RES_ACT_ALLOW,
|
||||
HTTP_RES_ACT_DENY,
|
||||
HTTP_RES_ACT_ADD_HDR,
|
||||
HTTP_RES_ACT_REPLACE_HDR,
|
||||
HTTP_RES_ACT_REPLACE_VAL,
|
||||
HTTP_RES_ACT_SET_HDR,
|
||||
HTTP_RES_ACT_DEL_HDR,
|
||||
HTTP_RES_ACT_SET_NICE,
|
||||
@ -415,6 +419,7 @@ struct http_req_rule {
|
||||
char *name; /* header name */
|
||||
int name_len; /* header name's length */
|
||||
struct list fmt; /* log-format compatible expression */
|
||||
regex_t* re; /* used by replace-header and replace-value */
|
||||
} hdr_add; /* args used by "add-header" and "set-header" */
|
||||
struct redirect_rule *redir; /* redirect rule or "http-request redirect" */
|
||||
int nice; /* nice value for HTTP_REQ_ACT_SET_NICE */
|
||||
@ -440,6 +445,7 @@ struct http_res_rule {
|
||||
char *name; /* header name */
|
||||
int name_len; /* header name's length */
|
||||
struct list fmt; /* log-format compatible expression */
|
||||
regex_t* re; /* used by replace-header and replace-value */
|
||||
} hdr_add; /* args used by "add-header" and "set-header" */
|
||||
int nice; /* nice value for HTTP_RES_ACT_SET_NICE */
|
||||
int loglevel; /* log-level value for HTTP_RES_ACT_SET_LOGL */
|
||||
|
@ -1203,6 +1203,7 @@ void deinit(void)
|
||||
free(p->fwdfor_hdr_name);
|
||||
|
||||
free_http_req_rules(&p->http_req_rules);
|
||||
free_http_res_rules(&p->http_res_rules);
|
||||
free(p->task);
|
||||
|
||||
pool_destroy2(p->req_cap_pool);
|
||||
|
233
src/proto_http.c
233
src/proto_http.c
@ -3176,6 +3176,126 @@ static inline void inet_set_tos(int fd, struct sockaddr_storage from, int tos)
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Returns the number of characters written to destination,
|
||||
* -1 on internal error and -2 if no replacement took place.
|
||||
*/
|
||||
static int http_replace_header(regex_t* re, char* dst, uint dst_size, char* val,
|
||||
const char* rep_str)
|
||||
{
|
||||
if (regexec(re, val, MAX_MATCH, pmatch, 0))
|
||||
return -2;
|
||||
|
||||
return exp_replace(dst, dst_size, val, rep_str, pmatch);
|
||||
}
|
||||
|
||||
/* Returns the number of characters written to destination,
|
||||
* -1 on internal error and -2 if no replacement took place.
|
||||
*/
|
||||
static int http_replace_value(regex_t* re, char* dst, uint dst_size, char* val, char delim,
|
||||
const char* rep_str)
|
||||
{
|
||||
char* p = val;
|
||||
char* dst_end = dst + dst_size;
|
||||
char* dst_p = dst;
|
||||
|
||||
for (;;) {
|
||||
char *p_delim;
|
||||
const char* tok_end;
|
||||
|
||||
if ((p_delim = (char*)strchr(p, delim))) {
|
||||
*p_delim = 0;
|
||||
tok_end = p_delim;
|
||||
} else {
|
||||
tok_end = p + strlen(p);
|
||||
}
|
||||
|
||||
if (regexec(re, p, MAX_MATCH, pmatch, 0) == 0) {
|
||||
int replace_n = exp_replace(dst_p, dst_end - dst_p, p, rep_str, pmatch);
|
||||
|
||||
if (replace_n < 0)
|
||||
return -1;
|
||||
|
||||
dst_p += replace_n;
|
||||
} else {
|
||||
uint len = tok_end - p;
|
||||
|
||||
if (dst_p + len >= dst_end)
|
||||
return -1;
|
||||
|
||||
memcpy(dst_p, p, len);
|
||||
dst_p += len;
|
||||
}
|
||||
|
||||
if (dst_p >= dst_end)
|
||||
return -1;
|
||||
|
||||
if (p_delim) {
|
||||
*p_delim = delim;
|
||||
*dst_p++ = delim;
|
||||
p = p_delim + 1;
|
||||
} else {
|
||||
*dst_p = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return dst_p - dst;
|
||||
}
|
||||
|
||||
static int http_transform_header(struct session* s, struct http_msg *msg, const char* name, uint name_len,
|
||||
char* buf, struct hdr_idx* idx, struct list *fmt, regex_t* re,
|
||||
struct hdr_ctx* ctx, int action)
|
||||
{
|
||||
ctx->idx = 0;
|
||||
|
||||
while (http_find_full_header2(name, name_len, buf, idx, ctx)) {
|
||||
struct hdr_idx_elem *hdr = idx->v + ctx->idx;
|
||||
int delta;
|
||||
char* val = (char*)ctx->line + name_len + 2;
|
||||
char* val_end = (char*)ctx->line + hdr->len;
|
||||
char save_val_end = *val_end;
|
||||
char* reg_dst_buf;
|
||||
uint reg_dst_buf_size;
|
||||
int n_replaced;
|
||||
|
||||
*val_end = 0;
|
||||
trash.len = build_logline(s, trash.str, trash.size, fmt);
|
||||
|
||||
if (trash.len >= trash.size - 1)
|
||||
return -1;
|
||||
|
||||
reg_dst_buf = trash.str + trash.len + 1;
|
||||
reg_dst_buf_size = trash.size - trash.len - 1;
|
||||
|
||||
switch (action) {
|
||||
case HTTP_REQ_ACT_REPLACE_VAL:
|
||||
case HTTP_RES_ACT_REPLACE_VAL:
|
||||
n_replaced = http_replace_value(re, reg_dst_buf, reg_dst_buf_size, val, ',', trash.str);
|
||||
break;
|
||||
case HTTP_REQ_ACT_REPLACE_HDR:
|
||||
case HTTP_RES_ACT_REPLACE_HDR:
|
||||
n_replaced = http_replace_header(re, reg_dst_buf, reg_dst_buf_size, val, trash.str);
|
||||
break;
|
||||
default: /* impossible */
|
||||
return -1;
|
||||
}
|
||||
|
||||
*val_end = save_val_end;
|
||||
|
||||
switch (n_replaced) {
|
||||
case -1: return -1;
|
||||
case -2: continue;
|
||||
}
|
||||
|
||||
delta = buffer_replace2(msg->chn->buf, val, val_end, reg_dst_buf, n_replaced);
|
||||
|
||||
hdr->len += delta;
|
||||
http_msg_move_end(msg, delta);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Executes the http-request rules <rules> for session <s>, proxy <px> and
|
||||
* transaction <txn>. Returns the verdict of the first rule that prevents
|
||||
* further processing of the request (auth, deny, ...), and defaults to
|
||||
@ -3265,6 +3385,14 @@ http_req_get_intercept_rule(struct proxy *px, struct list *rules, struct session
|
||||
s->logs.level = rule->arg.loglevel;
|
||||
break;
|
||||
|
||||
case HTTP_REQ_ACT_REPLACE_HDR:
|
||||
case HTTP_REQ_ACT_REPLACE_VAL:
|
||||
if (http_transform_header(s, &txn->req, rule->arg.hdr_add.name, rule->arg.hdr_add.name_len,
|
||||
txn->req.chn->buf->p, &txn->hdr_idx, &rule->arg.hdr_add.fmt,
|
||||
rule->arg.hdr_add.re, &ctx, rule->action))
|
||||
return HTTP_RULE_RES_BADREQ;
|
||||
break;
|
||||
|
||||
case HTTP_REQ_ACT_DEL_HDR:
|
||||
case HTTP_REQ_ACT_SET_HDR:
|
||||
ctx.idx = 0;
|
||||
@ -3446,6 +3574,14 @@ http_res_get_intercept_rule(struct proxy *px, struct list *rules, struct session
|
||||
s->logs.level = rule->arg.loglevel;
|
||||
break;
|
||||
|
||||
case HTTP_RES_ACT_REPLACE_HDR:
|
||||
case HTTP_RES_ACT_REPLACE_VAL:
|
||||
if (http_transform_header(s, &txn->rsp, rule->arg.hdr_add.name, rule->arg.hdr_add.name_len,
|
||||
txn->rsp.chn->buf->p, &txn->hdr_idx, &rule->arg.hdr_add.fmt,
|
||||
rule->arg.hdr_add.re, &ctx, rule->action))
|
||||
return NULL; /* note: we should report an error here */
|
||||
break;
|
||||
|
||||
case HTTP_RES_ACT_DEL_HDR:
|
||||
case HTTP_RES_ACT_SET_HDR:
|
||||
ctx.idx = 0;
|
||||
@ -8759,7 +8895,27 @@ void http_reset_txn(struct session *s)
|
||||
s->rep->analyse_exp = TICK_ETERNITY;
|
||||
}
|
||||
|
||||
void free_http_req_rules(struct list *r) {
|
||||
static inline void free_regex(regex_t* re)
|
||||
{
|
||||
if (re) {
|
||||
regfree(re);
|
||||
free(re);
|
||||
}
|
||||
}
|
||||
|
||||
void free_http_res_rules(struct list *r)
|
||||
{
|
||||
struct http_res_rule *tr, *pr;
|
||||
|
||||
list_for_each_entry_safe(pr, tr, r, list) {
|
||||
LIST_DEL(&pr->list);
|
||||
free_regex(pr->arg.hdr_add.re);
|
||||
free(pr);
|
||||
}
|
||||
}
|
||||
|
||||
void free_http_req_rules(struct list *r)
|
||||
{
|
||||
struct http_req_rule *tr, *pr;
|
||||
|
||||
list_for_each_entry_safe(pr, tr, r, list) {
|
||||
@ -8767,6 +8923,7 @@ void free_http_req_rules(struct list *r) {
|
||||
if (pr->action == HTTP_REQ_ACT_AUTH)
|
||||
free(pr->arg.auth.realm);
|
||||
|
||||
free_regex(pr->arg.hdr_add.re);
|
||||
free(pr);
|
||||
}
|
||||
}
|
||||
@ -8909,6 +9066,41 @@ struct http_req_rule *parse_http_req_cond(const char **args, const char *file, i
|
||||
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-val") == 0) {
|
||||
rule->action = *args[8] == 'h' ? HTTP_REQ_ACT_REPLACE_HDR : HTTP_REQ_ACT_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+2], "if") != 0 && strcmp(args[cur_arg+2], "unless") != 0)) {
|
||||
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);
|
||||
|
||||
if (!(rule->arg.hdr_add.re = calloc(1, sizeof(*rule->arg.hdr_add.re)))) {
|
||||
Alert("parsing [%s:%d]: out of memory.\n", file, linenum);
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
if (regcomp(rule->arg.hdr_add.re, args[cur_arg + 1], REG_EXTENDED)) {
|
||||
Alert("parsing [%s:%d] : '%s' : bad regular expression.\n", file, linenum,
|
||||
args[cur_arg + 1]);
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
proxy->conf.args.ctx = ARGC_HRQ;
|
||||
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,
|
||||
file, linenum);
|
||||
|
||||
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 = HTTP_REQ_ACT_DEL_HDR;
|
||||
cur_arg = 1;
|
||||
@ -9075,7 +9267,7 @@ struct http_req_rule *parse_http_req_cond(const char **args, const char *file, i
|
||||
goto out_err;
|
||||
}
|
||||
} else {
|
||||
Alert("parsing [%s:%d]: 'http-request' expects 'allow', 'deny', 'auth', 'redirect', 'tarpit', 'add-header', 'set-header', 'set-nice', 'set-tos', 'set-mark', 'set-log-level', 'add-acl', 'del-acl', 'del-map', 'set-map', but got '%s'%s.\n",
|
||||
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', but got '%s'%s.\n",
|
||||
file, linenum, args[0], *args[0] ? "" : " (missing argument)");
|
||||
goto out_err;
|
||||
}
|
||||
@ -9228,6 +9420,41 @@ struct http_res_rule *parse_http_res_cond(const char **args, const char *file, i
|
||||
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[8] == 'h' ? HTTP_RES_ACT_REPLACE_HDR : HTTP_RES_ACT_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+2], "if") != 0 && strcmp(args[cur_arg+2], "unless") != 0)) {
|
||||
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);
|
||||
|
||||
if (!(rule->arg.hdr_add.re = calloc(1, sizeof(*rule->arg.hdr_add.re)))) {
|
||||
Alert("parsing [%s:%d]: out of memory.\n", file, linenum);
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
if (regcomp(rule->arg.hdr_add.re, args[cur_arg + 1], REG_EXTENDED)) {
|
||||
Alert("parsing [%s:%d] : '%s' : bad regular expression.\n", file, linenum,
|
||||
args[cur_arg + 1]);
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
proxy->conf.args.ctx = ARGC_HRQ;
|
||||
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,
|
||||
file, linenum);
|
||||
|
||||
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 = HTTP_RES_ACT_DEL_HDR;
|
||||
cur_arg = 1;
|
||||
@ -9378,7 +9605,7 @@ struct http_res_rule *parse_http_res_cond(const char **args, const char *file, i
|
||||
goto out_err;
|
||||
}
|
||||
} else {
|
||||
Alert("parsing [%s:%d]: 'http-response' expects 'allow', 'deny', 'redirect', 'add-header', 'del-header', 'set-header', 'set-nice', 'set-tos', 'set-mark', 'set-log-level', 'del-acl', 'add-acl', 'del-map', 'set-map', but got '%s'%s.\n",
|
||||
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', 'del-acl', 'add-acl', 'del-map', 'set-map', but got '%s'%s.\n",
|
||||
file, linenum, args[0], *args[0] ? "" : " (missing argument)");
|
||||
goto out_err;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user