mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-03-31 23:58:16 +00:00
MINOR: http: add a new "http-request replace-uri" action
This action is particularly convenient to replace some deprecated usees of "reqrep". It takes a match and a format string including back- references. The reqrep warning was updated to suggest it as well.
This commit is contained in:
parent
c9515529a0
commit
3381022d88
@ -4447,6 +4447,33 @@ http-request replace-header <name> <match-regex> <replace-fmt>
|
||||
|
||||
# assuming the backend IP is 192.168.1.20
|
||||
|
||||
http-request replace-uri <match-regex> <replace-fmt>
|
||||
[ { if | unless } <condition> ]
|
||||
|
||||
This matches the regular expression in the URI part of the request
|
||||
according to <match-regex>, and replaces it with the <replace-fmt>
|
||||
argument. Standard back-references using the backslash ('\') followed by a
|
||||
number are supported. The <fmt> field is interpreted as a log-format string
|
||||
so it may contain special expressions just like the <fmt> argument passed
|
||||
to "http-request set-uri". The match is exclusively case-sensitive. Any
|
||||
optional scheme, authority or query string are considered in the matching
|
||||
part of the URI. It is worth noting that regular expressions may be more
|
||||
expensive to evaluate than certain ACLs, so rare replacements may benefit
|
||||
from a condition to avoid performing the evaluation at all if it does not
|
||||
match.
|
||||
|
||||
Example:
|
||||
# prefix /foo : turn /bar?q=1 into /foo/bar?q=1 :
|
||||
http-request replace-uri (.*) /foo\1
|
||||
|
||||
# suffix /foo : turn /bar?q=1 into /bar/foo?q=1 :
|
||||
http-request replace-uri ([^?]*)(\?(.*))? \1/foo\2
|
||||
|
||||
# strip /foo : turn /foo/bar?q=1 into /bar?q=1
|
||||
http-request replace-uri /foo/(.*) /\1
|
||||
# or more efficient if only some requests match :
|
||||
http-request replace-uri /foo/(.*) /\1 if { url_beg /foo/ }
|
||||
|
||||
http-request replace-value <name> <match-regex> <replace-fmt>
|
||||
[ { if | unless } <condition> ]
|
||||
|
||||
|
@ -3866,7 +3866,7 @@ stats_error_parsing:
|
||||
}
|
||||
else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
|
||||
if (!already_warned(WARN_REQREP_DEPRECATED))
|
||||
ha_warning("parsing [%s:%d] : The '%s' directive is deprecated in favor of 'http-request replace-header' and will be removed in next version.\n", file, linenum, args[0]);
|
||||
ha_warning("parsing [%s:%d] : The '%s' directive is deprecated in favor of 'http-request replace-uri' and 'http-request replace-header' and will be removed in next version.\n", file, linenum, args[0]);
|
||||
|
||||
if (*(args[2]) == 0) {
|
||||
ha_alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include <proto/acl.h>
|
||||
#include <proto/arg.h>
|
||||
#include <proto/http_rules.h>
|
||||
#include <proto/http_htx.h>
|
||||
#include <proto/log.h>
|
||||
#include <proto/proto_http.h>
|
||||
#include <proto/stream_interface.h>
|
||||
@ -128,6 +129,93 @@ static enum act_parse_ret parse_set_req_line(const char **args, int *orig_arg, s
|
||||
return ACT_RET_PRS_OK;
|
||||
}
|
||||
|
||||
/* This function executes a replace-uri action. It finds its arguments in
|
||||
* <rule>.arg.act.p[]. It builds a string in the trash from the format string
|
||||
* previously filled by function parse_replace_uri() and will execute the regex
|
||||
* in p[1] to replace the URI. It uses the format string present in act.p[2..3].
|
||||
* It always returns ACT_RET_CONT. If an error occurs, the action is canceled,
|
||||
* but the rule processing continues.
|
||||
*/
|
||||
static enum act_return http_action_replace_uri(struct act_rule *rule, struct proxy *px,
|
||||
struct session *sess, struct stream *s, int flags)
|
||||
{
|
||||
enum act_return ret = ACT_RET_ERR;
|
||||
struct buffer *replace, *output;
|
||||
struct ist uri;
|
||||
int len;
|
||||
|
||||
replace = alloc_trash_chunk();
|
||||
output = alloc_trash_chunk();
|
||||
if (!replace || !output)
|
||||
goto leave;
|
||||
|
||||
if (IS_HTX_STRM(s))
|
||||
uri = htx_sl_req_uri(http_get_stline(htxbuf(&s->req.buf)));
|
||||
else
|
||||
uri = ist2(ci_head(&s->req) + s->txn->req.sl.rq.u, s->txn->req.sl.rq.u_l);
|
||||
|
||||
if (!regex_exec_match2(rule->arg.act.p[1], uri.ptr, uri.len, MAX_MATCH, pmatch, 0))
|
||||
goto leave;
|
||||
|
||||
replace->data = build_logline(s, replace->area, replace->size, (struct list *)&rule->arg.act.p[2]);
|
||||
|
||||
/* note: uri.ptr doesn't need to be zero-terminated because it will
|
||||
* only be used to pick pmatch references.
|
||||
*/
|
||||
len = exp_replace(output->area, output->size, uri.ptr, replace->area, pmatch);
|
||||
if (len == -1)
|
||||
goto leave;
|
||||
|
||||
/* 3 is the set-uri action */
|
||||
http_replace_req_line(3, output->area, len, px, s);
|
||||
|
||||
ret = ACT_RET_CONT;
|
||||
|
||||
leave:
|
||||
free_trash_chunk(output);
|
||||
free_trash_chunk(replace);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* parse a "replace-uri" http-request action.
|
||||
* This action takes 2 arguments (a regex and a replacement format string).
|
||||
* The resulting rule makes use of arg->act.p[0] to store the action (0 for now),
|
||||
* p[1] to store the compiled regex, and arg->act.p[2..3] to store the log-format
|
||||
* list head. It returns ACT_RET_PRS_OK on success, ACT_RET_PRS_ERR on error.
|
||||
*/
|
||||
static enum act_parse_ret parse_replace_uri(const char **args, int *orig_arg, struct proxy *px,
|
||||
struct act_rule *rule, char **err)
|
||||
{
|
||||
int cur_arg = *orig_arg;
|
||||
char *error = NULL;
|
||||
|
||||
rule->action = ACT_CUSTOM;
|
||||
rule->arg.act.p[0] = (void *)0; // replace-uri
|
||||
rule->action_ptr = http_action_replace_uri;
|
||||
|
||||
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)) {
|
||||
memprintf(err, "expects exactly 2 arguments <match-regex> and <replace-format>");
|
||||
return ACT_RET_PRS_ERR;
|
||||
}
|
||||
|
||||
if (!(rule->arg.act.p[1] = regex_comp(args[cur_arg], 1, 1, &error))) {
|
||||
memprintf(err, "failed to parse the regex : %s", error);
|
||||
free(error);
|
||||
return ACT_RET_PRS_ERR;
|
||||
}
|
||||
|
||||
LIST_INIT((struct list *)&rule->arg.act.p[2]);
|
||||
px->conf.args.ctx = ARGC_HRQ;
|
||||
if (!parse_logformat_string(args[cur_arg + 1], px, (struct list *)&rule->arg.act.p[2], LOG_OPT_HTTP,
|
||||
(px->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR, err)) {
|
||||
return ACT_RET_PRS_ERR;
|
||||
}
|
||||
|
||||
(*orig_arg) += 2;
|
||||
return ACT_RET_PRS_OK;
|
||||
}
|
||||
|
||||
/* This function is just a compliant action wrapper for "set-status". */
|
||||
static enum act_return action_http_set_status(struct act_rule *rule, struct proxy *px,
|
||||
struct session *sess, struct stream *s, int flags)
|
||||
@ -608,6 +696,7 @@ static struct action_kw_list http_req_actions = {
|
||||
{ "capture", parse_http_req_capture },
|
||||
{ "reject", parse_http_action_reject },
|
||||
{ "disable-l7-retry", parse_http_req_disable_l7_retry },
|
||||
{ "replace-uri", parse_replace_uri },
|
||||
{ "set-method", parse_set_req_line },
|
||||
{ "set-path", parse_set_req_line },
|
||||
{ "set-query", parse_set_req_line },
|
||||
|
Loading…
Reference in New Issue
Block a user