mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2026-05-14 17:56:09 +02:00
MINOR: sample: add a generic reverse converter
Some use cases benefit from reversing a string before passing it to other converters or lookups. While reverse_dom addresses domain-specific label reversal, a generic byte-wise string reversal remains useful on its own and can also be combined with other converters such as concat(). A common lookup use case is turning a suffix match on the original string into a prefix match on the reversed string. Prefix string matches use the prefix-tree index (PAT_MATCH_BEG with pat_idx_tree_pfx), while end matches use the string-list index (PAT_MATCH_END with pat_idx_list_str), so reversing before map_beg can avoid linear suffix scans for large maps. This patch adds a new string converter named "reverse". It reverses the input string byte by byte and returns the resulting string unchanged otherwise. It does not apply any domain-specific semantics or character-encoding semantics. The documentation is updated and a reg-test is added to cover the basic conversion as well as a simple composition with concat(.).
This commit is contained in:
parent
c090e51502
commit
f3fc68e3a2
@ -21145,6 +21145,7 @@ param(name[,delim]) string string
|
||||
port_only string integer
|
||||
protobuf(field_number[,field_type]) binary binary
|
||||
regsub(regex,subst[,flags]) string string
|
||||
reverse string string
|
||||
rfc7239_field(field) string string
|
||||
rfc7239_is_valid string boolean
|
||||
rfc7239_n2nn string address / str
|
||||
@ -22642,6 +22643,26 @@ regsub(<regex>,<subst>[,<flags>])
|
||||
http-request redirect location %[url,'regsub("(foo|bar)([0-9]+)?","\2\1",i)']
|
||||
http-request redirect location %[url,regsub(\"(foo|bar)([0-9]+)?\",\"\2\1\",i)]
|
||||
|
||||
reverse
|
||||
Reverses the input string byte by byte.
|
||||
|
||||
This converter is encoding-agnostic and reverses bytes, not characters; it is
|
||||
not suitable for reversing human text encoded as UTF-8.
|
||||
|
||||
This can turn suffix lookups on the original string into prefix lookups on
|
||||
the reversed string, allowing the use of indexed prefix matchers such as
|
||||
"map_beg" on large maps.
|
||||
|
||||
Examples:
|
||||
"example.com" -> "moc.elpmaxe"
|
||||
"ab cd" -> "dc ba"
|
||||
|
||||
# Given a map file where each key contains a reversed hostname:
|
||||
# moc.elpmaxe.ppa app1
|
||||
# moc.elpmaxe.bd dbcluster
|
||||
# Pick a backend based on the domain suffix of the Host header:
|
||||
use_backend %[req.hdr(host),lower,reverse,map_beg(/etc/haproxy/hosts.map,default)]
|
||||
|
||||
rfc7239_field(<field>)
|
||||
Extracts a single field/parameter from RFC 7239 compliant header value input.
|
||||
|
||||
|
||||
41
reg-tests/converter/reverse.vtc
Normal file
41
reg-tests/converter/reverse.vtc
Normal file
@ -0,0 +1,41 @@
|
||||
varnishtest "reverse converter test"
|
||||
|
||||
feature ignore_unknown_macro
|
||||
|
||||
server s1 {
|
||||
rxreq
|
||||
txresp -hdr "Connection: close"
|
||||
} -repeat 4 -start
|
||||
|
||||
haproxy h1 -conf {
|
||||
global
|
||||
.if feature(THREAD)
|
||||
thread-groups 1
|
||||
.endif
|
||||
|
||||
defaults
|
||||
mode http
|
||||
timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
|
||||
timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
|
||||
timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
|
||||
|
||||
frontend fe
|
||||
bind "fd@${fe}"
|
||||
|
||||
http-request return status 200 hdr X-Reverse "%[str(example.com),reverse]" hdr X-Reverse2 "%[str(ab cd),reverse]" hdr X-Reverse3 "%[str(example.com),reverse,concat(.)]" hdr X-Reverse4 "%[str(),reverse]"
|
||||
|
||||
default_backend be
|
||||
|
||||
backend be
|
||||
server s1 ${s1_addr}:${s1_port}
|
||||
} -start
|
||||
|
||||
client c1 -connect ${h1_fe_sock} {
|
||||
txreq -url "/"
|
||||
rxresp
|
||||
expect resp.status == 200
|
||||
expect resp.http.x-reverse == "moc.elpmaxe"
|
||||
expect resp.http.x-reverse2 == "dc ba"
|
||||
expect resp.http.x-reverse3 == "moc.elpmaxe."
|
||||
expect resp.http.x-reverse4 == "<undef>"
|
||||
} -run
|
||||
24
src/sample.c
24
src/sample.c
@ -2311,6 +2311,29 @@ static int sample_conv_str2upper(const struct arg *arg_p, struct sample *smp, vo
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Reverses the input string byte by byte. */
|
||||
static int sample_conv_reverse(const struct arg *arg_p, struct sample *smp, void *private)
|
||||
{
|
||||
const char *input = smp->data.u.str.area;
|
||||
struct buffer *trash;
|
||||
int input_len = smp->data.u.str.data;
|
||||
int i;
|
||||
|
||||
trash = get_trash_chunk_sz(input_len + 1);
|
||||
if (!trash)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < input_len; i++)
|
||||
trash->area[i] = input[input_len - 1 - i];
|
||||
|
||||
trash->area[input_len] = 0;
|
||||
trash->data = input_len;
|
||||
smp->data.u.str = *trash;
|
||||
smp->data.type = SMP_T_STR;
|
||||
smp->flags &= ~SMP_F_CONST;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* takes the IPv4 mask in args[0] and an optional IPv6 mask in args[1] */
|
||||
static int sample_conv_ipmask(const struct arg *args, struct sample *smp, void *private)
|
||||
{
|
||||
@ -5777,6 +5800,7 @@ static struct sample_conv_kw_list sample_conv_kws = {ILH, {
|
||||
{ "strcmp", sample_conv_strcmp, ARG1(1,STR), smp_check_strcmp, SMP_T_STR, SMP_T_SINT },
|
||||
{ "host_only", sample_conv_host_only, 0, NULL, SMP_T_STR, SMP_T_STR },
|
||||
{ "port_only", sample_conv_port_only, 0, NULL, SMP_T_STR, SMP_T_SINT },
|
||||
{ "reverse", sample_conv_reverse, 0, NULL, SMP_T_STR, SMP_T_STR },
|
||||
|
||||
/* gRPC converters. */
|
||||
{ "ungrpc", sample_conv_ungrpc, ARG2(1,PBUF_FNUM,STR), sample_conv_protobuf_check, SMP_T_BIN, SMP_T_BIN },
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user