# outputs:
User-Agent: foo
+http-request replace-path <match-regex> <replace-fmt>
+ [ { if | unless } <condition> ]
+
+ This works like "replace-header" except that it works on the request's path
+ component instead of a header. The path component starts at the first '/'
+ after an optional scheme+authority. It does contain the query string if any
+ is present. The replacement does not modify the scheme nor authority.
+
+ 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-path (.*) /foo\1
+
+ # suffix /foo : turn /bar?q=1 into /bar/foo?q=1 :
+ http-request replace-path ([^?]*)(\?(.*))? \1/foo\2
+
+ # strip /foo : turn /foo/bar?q=1 into /bar?q=1
+ http-request replace-path /foo/(.*) /\1
+ # or more efficient if only some requests match :
+ http-request replace-path /foo/(.*) /\1 if { url_beg /foo/ }
+
http-request replace-uri <match-regex> <replace-fmt>
[ { if | unless } <condition> ]
with HTTP/2, clients are encouraged to send absolute URIs only, which look
like the ones HTTP/1 clients use to talk to proxies. Such partial replace-uri
rules may then fail in HTTP/2 when they work in HTTP/1. Either the rules need
- to be adapted to optionally match a scheme and authority.
+ to be adapted to optionally match a scheme and authority, or replace-path
+ should be used.
Example:
# rewrite all "http" absolute requests to "https":
* <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].
+ * The component to act on (path/uri) is taken from act.p[0] which contains 1
+ * for the path or 3 for the URI (values used by http_req_replace_stline()).
* It always returns ACT_RET_CONT. If an error occurs, the action is canceled,
* but the rule processing continues.
*/
if (!replace || !output)
goto leave;
uri = htx_sl_req_uri(http_get_stline(htxbuf(&s->req.buf)));
+
+ if (rule->arg.act.p[0] == (void *)1)
+ uri = http_get_path(uri); // replace path
+
if (!regex_exec_match2(rule->arg.act.p[1], uri.ptr, uri.len, MAX_MATCH, pmatch, 0))
goto leave;
if (len == -1)
goto leave;
- /* 3 is the set-uri action */
- http_req_replace_stline(3, output->area, len, px, s);
+ http_req_replace_stline((long)rule->arg.act.p[0], output->area, len, px, s);
ret = ACT_RET_CONT;
return ret;
}
-/* parse a "replace-uri" http-request action.
+/* parse a "replace-uri" or "replace-path" 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),
+ * The resulting rule makes use of arg->act.p[0] to store the action (1/3 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.
*/
char *error = NULL;
rule->action = ACT_CUSTOM;
- rule->arg.act.p[0] = (void *)0; // replace-uri
+ if (strcmp(args[cur_arg-1], "replace-path") == 0)
+ rule->arg.act.p[0] = (void *)1; // replace-path
+ else
+ rule->arg.act.p[0] = (void *)3; // replace-uri
+
rule->action_ptr = http_action_replace_uri;
if (!*args[cur_arg] || !*args[cur_arg+1] ||
{ "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 },