mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2024-12-23 13:17:16 +00:00
MINOR: http_act: Add -m flag for del-header name matching method
This patch adds -m flag which allows to specify header name matching method when deleting headers from http request/response. Currently beg, end, sub, str and reg are supported. This is related to GitHub issue #909
This commit is contained in:
parent
302b9f8d7a
commit
ebdd4c55da
@ -4687,9 +4687,13 @@ http-after-response allow [ { if | unless } <condition> ]
|
||||
This stops the evaluation of the rules and lets the response pass the check.
|
||||
No further "http-after-response" rules are evaluated.
|
||||
|
||||
http-after-response del-header <name> [ { if | unless } <condition> ]
|
||||
http-after-response del-header <name> [ -m <meth> ] [ { if | unless } <condition> ]
|
||||
|
||||
This removes all HTTP header fields whose name is specified in <name>.
|
||||
This removes all HTTP header fields whose name is specified in <name>. <meth>
|
||||
is the matching method, applied on the header name. Supported matching methods
|
||||
are "str" (exact match), "beg" (prefix match), "end" (suffix match), "sub"
|
||||
(substring match) and "reg" (regex match). If not specified, exact matching
|
||||
method is used.
|
||||
|
||||
http-after-response replace-header <name> <regex-match> <replace-fmt>
|
||||
[ { if | unless } <condition> ]
|
||||
@ -5461,9 +5465,13 @@ http-request del-acl(<file-name>) <key fmt> [ { if | unless } <condition> ]
|
||||
It is the equivalent of the "del acl" command from the stats socket, but can
|
||||
be triggered by an HTTP request.
|
||||
|
||||
http-request del-header <name> [ { if | unless } <condition> ]
|
||||
http-request del-header <name> [ -m <meth> ] [ { if | unless } <condition> ]
|
||||
|
||||
This removes all HTTP header fields whose name is specified in <name>.
|
||||
This removes all HTTP header fields whose name is specified in <name>. <meth>
|
||||
is the matching method, applied on the header name. Supported matching methods
|
||||
are "str" (exact match), "beg" (prefix match), "end" (suffix match), "sub"
|
||||
(substring match) and "reg" (regex match). If not specified, exact matching
|
||||
method is used.
|
||||
|
||||
http-request del-map(<file-name>) <key fmt> [ { if | unless } <condition> ]
|
||||
|
||||
@ -6274,9 +6282,13 @@ http-response del-acl(<file-name>) <key fmt> [ { if | unless } <condition> ]
|
||||
It is the equivalent of the "del acl" command from the stats socket, but can
|
||||
be triggered by an HTTP response.
|
||||
|
||||
http-response del-header <name> [ { if | unless } <condition> ]
|
||||
http-response del-header <name> [ -m <meth> ] [ { if | unless } <condition> ]
|
||||
|
||||
This removes all HTTP header fields whose name is specified in <name>.
|
||||
This removes all HTTP header fields whose name is specified in <name>. <meth>
|
||||
is the matching method, applied on the header name. Supported matching methods
|
||||
are "str" (exact match), "beg" (prefix match), "end" (suffix match), "sub"
|
||||
(substring match) and "reg" (regex match). If not specified, exact matching
|
||||
method is used.
|
||||
|
||||
http-response del-map(<file-name>) <key fmt> [ { if | unless } <condition> ]
|
||||
|
||||
|
@ -78,7 +78,6 @@ enum act_name {
|
||||
ACT_ACTION_DENY,
|
||||
|
||||
/* common http actions .*/
|
||||
ACT_HTTP_DEL_HDR,
|
||||
ACT_HTTP_REDIR,
|
||||
ACT_HTTP_SET_NICE,
|
||||
ACT_HTTP_SET_LOGL,
|
||||
|
93
reg-tests/http-rules/del_header.vtc
Normal file
93
reg-tests/http-rules/del_header.vtc
Normal file
@ -0,0 +1,93 @@
|
||||
varnishtest "del-header tests"
|
||||
|
||||
# This config tests various http-request/response del-header operations
|
||||
# with or without specified header name matching method.
|
||||
|
||||
feature ignore_unknown_macro
|
||||
|
||||
server s1 {
|
||||
rxreq
|
||||
expect req.url == /
|
||||
expect req.http.x-always == always
|
||||
expect req.http.x-str1 == <undef>
|
||||
expect req.http.x-str2 == <undef>
|
||||
expect req.http.x-beg1 == <undef>
|
||||
expect req.http.x-beg2 == <undef>
|
||||
expect req.http.x-end1 == <undef>
|
||||
expect req.http.x-end2 == end2
|
||||
expect req.http.x-sub1 == <undef>
|
||||
expect req.http.x-sub2 == <undef>
|
||||
expect req.http.x-reg1 == <undef>
|
||||
expect req.http.x-reg2 == <undef>
|
||||
txresp -hdr "x-always: always" \
|
||||
-hdr "x-str1: str1" \
|
||||
-hdr "x-str2: str2" \
|
||||
-hdr "x-beg1: beg1" \
|
||||
-hdr "x-beg2: beg2" \
|
||||
-hdr "x-end1: end1" \
|
||||
-hdr "x-end2: end2" \
|
||||
-hdr "x-sub1: sub1" \
|
||||
-hdr "x-sub2: sub2" \
|
||||
-hdr "x-reg1: reg1" \
|
||||
-hdr "x-reg2: reg2"
|
||||
|
||||
} -start
|
||||
|
||||
haproxy h1 -conf {
|
||||
defaults
|
||||
mode http
|
||||
timeout connect 1s
|
||||
timeout client 1s
|
||||
timeout server 1s
|
||||
|
||||
frontend fe
|
||||
bind "fd@${fe}"
|
||||
|
||||
http-request del-header x-str1
|
||||
http-request del-header x-str2 -m str
|
||||
http-request del-header x-beg -m beg
|
||||
http-request del-header end1 -m end
|
||||
http-request del-header sub -m sub
|
||||
http-request del-header ^x.reg.$ -m reg
|
||||
|
||||
http-response del-header x-str1
|
||||
http-response del-header x-str2 -m str
|
||||
http-response del-header x-beg -m beg
|
||||
http-response del-header end1 -m end
|
||||
http-response del-header sub -m sub
|
||||
http-response del-header ^x.reg.$ -m reg
|
||||
|
||||
default_backend be
|
||||
|
||||
backend be
|
||||
server s1 ${s1_addr}:${s1_port}
|
||||
|
||||
} -start
|
||||
|
||||
client c1 -connect ${h1_fe_sock} {
|
||||
txreq -req GET -url / \
|
||||
-hdr "x-always: always" \
|
||||
-hdr "x-str1: str1" \
|
||||
-hdr "x-str2: str2" \
|
||||
-hdr "x-beg1: beg1" \
|
||||
-hdr "x-beg2: beg2" \
|
||||
-hdr "x-end1: end1" \
|
||||
-hdr "x-end2: end2" \
|
||||
-hdr "x-sub1: sub1" \
|
||||
-hdr "x-sub2: sub2" \
|
||||
-hdr "x-reg1: reg1" \
|
||||
-hdr "x-reg2: reg2"
|
||||
rxresp
|
||||
expect resp.status == 200
|
||||
expect resp.http.x-always == always
|
||||
expect resp.http.x-str1 == <undef>
|
||||
expect resp.http.x-str2 == <undef>
|
||||
expect resp.http.x-beg1 == <undef>
|
||||
expect resp.http.x-beg2 == <undef>
|
||||
expect resp.http.x-end1 == <undef>
|
||||
expect resp.http.x-end2 == end2
|
||||
expect resp.http.x-sub1 == <undef>
|
||||
expect resp.http.x-sub2 == <undef>
|
||||
expect resp.http.x-reg1 == <undef>
|
||||
expect resp.http.x-reg2 == <undef>
|
||||
} -run
|
@ -1438,20 +1438,67 @@ static enum act_parse_ret parse_http_replace_header(const char **args, int *orig
|
||||
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.
|
||||
/* This function executes a del-header action with selected matching mode for
|
||||
* header name. It finds the matching method to be performed in <.action>, previously
|
||||
* filled by function parse_http_del_header(). On success, it returns ACT_RET_CONT.
|
||||
* Otherwise ACT_RET_ERR is returned.
|
||||
*/
|
||||
static enum act_return http_action_del_header(struct act_rule *rule, struct proxy *px,
|
||||
struct session *sess, struct stream *s, int flags)
|
||||
{
|
||||
struct http_hdr_ctx ctx;
|
||||
struct http_msg *msg = ((rule->from == ACT_F_HTTP_REQ) ? &s->txn->req : &s->txn->rsp);
|
||||
struct htx *htx = htxbuf(&msg->chn->buf);
|
||||
enum act_return ret = ACT_RET_CONT;
|
||||
|
||||
/* remove all occurrences of the header */
|
||||
ctx.blk = NULL;
|
||||
switch (rule->action) {
|
||||
case PAT_MATCH_STR:
|
||||
while (http_find_header(htx, rule->arg.http.str, &ctx, 1))
|
||||
http_remove_header(htx, &ctx);
|
||||
break;
|
||||
case PAT_MATCH_BEG:
|
||||
while (http_find_pfx_header(htx, rule->arg.http.str, &ctx, 1))
|
||||
http_remove_header(htx, &ctx);
|
||||
break;
|
||||
case PAT_MATCH_END:
|
||||
while (http_find_sfx_header(htx, rule->arg.http.str, &ctx, 1))
|
||||
http_remove_header(htx, &ctx);
|
||||
break;
|
||||
case PAT_MATCH_SUB:
|
||||
while (http_find_sub_header(htx, rule->arg.http.str, &ctx, 1))
|
||||
http_remove_header(htx, &ctx);
|
||||
break;
|
||||
case PAT_MATCH_REG:
|
||||
while (http_match_header(htx, rule->arg.http.re, &ctx, 1))
|
||||
http_remove_header(htx, &ctx);
|
||||
break;
|
||||
default:
|
||||
return ACT_RET_ERR;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Parse a "del-header" action. It takes string as a required argument,
|
||||
* optional flag (currently only -m) and optional matching method of input string
|
||||
* with header name to be deleted. Default matching method is exact match (-m str).
|
||||
* 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;
|
||||
int pat_idx;
|
||||
|
||||
rule->action = ACT_HTTP_DEL_HDR;
|
||||
/* set exact matching (-m str) as default */
|
||||
rule->action = PAT_MATCH_STR;
|
||||
rule->action_ptr = http_action_del_header;
|
||||
rule->release_ptr = release_http_action;
|
||||
|
||||
cur_arg = *orig_arg;
|
||||
if (!*args[cur_arg]) {
|
||||
memprintf(err, "expects exactly 1 arguments");
|
||||
memprintf(err, "expects at least 1 argument");
|
||||
return ACT_RET_PRS_ERR;
|
||||
}
|
||||
|
||||
@ -1459,7 +1506,32 @@ static enum act_parse_ret parse_http_del_header(const char **args, int *orig_arg
|
||||
rule->arg.http.str.len = strlen(rule->arg.http.str.ptr);
|
||||
px->conf.args.ctx = (rule->from == ACT_F_HTTP_REQ ? ARGC_HRQ : ARGC_HRS);
|
||||
|
||||
LIST_INIT(&rule->arg.http.fmt);
|
||||
if (strcmp(args[cur_arg+1], "-m") == 0) {
|
||||
cur_arg++;
|
||||
if (!*args[cur_arg+1]) {
|
||||
memprintf(err, "-m flag expects exactly 1 argument");
|
||||
return ACT_RET_PRS_ERR;
|
||||
}
|
||||
|
||||
cur_arg++;
|
||||
pat_idx = pat_find_match_name(args[cur_arg]);
|
||||
switch (pat_idx) {
|
||||
case PAT_MATCH_REG:
|
||||
if (!(rule->arg.http.re = regex_comp(rule->arg.http.str.ptr, 1, 1, err)))
|
||||
return ACT_RET_PRS_ERR;
|
||||
/* fall through */
|
||||
case PAT_MATCH_STR:
|
||||
case PAT_MATCH_BEG:
|
||||
case PAT_MATCH_END:
|
||||
case PAT_MATCH_SUB:
|
||||
rule->action = pat_idx;
|
||||
break;
|
||||
default:
|
||||
memprintf(err, "-m with unsupported matching method '%s'", args[cur_arg]);
|
||||
return ACT_RET_PRS_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
*orig_arg = cur_arg + 1;
|
||||
return ACT_RET_PRS_OK;
|
||||
}
|
||||
|
@ -2838,14 +2838,10 @@ static enum rule_result http_req_get_intercept_rule(struct proxy *px, struct lis
|
||||
{
|
||||
struct session *sess = strm_sess(s);
|
||||
struct http_txn *txn = s->txn;
|
||||
struct htx *htx;
|
||||
struct act_rule *rule;
|
||||
struct http_hdr_ctx ctx;
|
||||
enum rule_result rule_ret = HTTP_RULE_RES_CONT;
|
||||
int act_opts = 0;
|
||||
|
||||
htx = htxbuf(&s->req.buf);
|
||||
|
||||
/* If "the current_rule_list" match the executed rule list, we are in
|
||||
* resume condition. If a resume is needed it is always in the action
|
||||
* and never in the ACL or converters. In this case, we initialise the
|
||||
@ -2958,13 +2954,6 @@ static enum rule_result http_req_get_intercept_rule(struct proxy *px, struct lis
|
||||
s->logs.level = rule->arg.http.i;
|
||||
break;
|
||||
|
||||
case ACT_HTTP_DEL_HDR:
|
||||
/* remove all occurrences of the header */
|
||||
ctx.blk = NULL;
|
||||
while (http_find_header(htx, rule->arg.http.str, &ctx, 1))
|
||||
http_remove_header(htx, &ctx);
|
||||
break;
|
||||
|
||||
/* other flags exists, but normally, they never be matched. */
|
||||
default:
|
||||
break;
|
||||
@ -2994,14 +2983,10 @@ static enum rule_result http_res_get_intercept_rule(struct proxy *px, struct lis
|
||||
{
|
||||
struct session *sess = strm_sess(s);
|
||||
struct http_txn *txn = s->txn;
|
||||
struct htx *htx;
|
||||
struct act_rule *rule;
|
||||
struct http_hdr_ctx ctx;
|
||||
enum rule_result rule_ret = HTTP_RULE_RES_CONT;
|
||||
int act_opts = 0;
|
||||
|
||||
htx = htxbuf(&s->res.buf);
|
||||
|
||||
/* If "the current_rule_list" match the executed rule list, we are in
|
||||
* resume condition. If a resume is needed it is always in the action
|
||||
* and never in the ACL or converters. In this case, we initialise the
|
||||
@ -3102,13 +3087,6 @@ resume_execution:
|
||||
s->logs.level = rule->arg.http.i;
|
||||
break;
|
||||
|
||||
case ACT_HTTP_DEL_HDR:
|
||||
/* remove all occurrences of the header */
|
||||
ctx.blk = NULL;
|
||||
while (http_find_header(htx, rule->arg.http.str, &ctx, 1))
|
||||
http_remove_header(htx, &ctx);
|
||||
break;
|
||||
|
||||
case ACT_HTTP_REDIR:
|
||||
rule_ret = HTTP_RULE_RES_ABRT;
|
||||
if (!http_apply_redirect_rule(rule->arg.redir, s, txn))
|
||||
|
Loading…
Reference in New Issue
Block a user