Commit 44a8dbe9 authored by Geoff Simmons's avatar Geoff Simmons

Add the set.suball() method.

parent 0f7a1789
......@@ -59,7 +59,10 @@ SYNOPSIS
INT <obj>.which([ENUM select])
STRING <obj>.string([INT n,] [ENUM select])
BACKEND <obj>.backend([INT n,] [ENUM select])
STRING <obj>.sub(STRING text, STRING rewrite [, INT n] [, ENUM select])
STRING <obj>.sub(STRING text, STRING rewrite [, INT n]
[, ENUM select])
STRING <obj>.suball(STRING text, STRING rewrite [, INT n]
[, ENUM select])
# VMOD version
STRING re2.version()
......@@ -1450,6 +1453,63 @@ Examples::
}
.. _func_set.suball:
set.suball(...)
---------------
::
STRING xset.suball(
STRING text,
STRING rewrite,
STRING fallback="**SUBALL METHOD FAILED**",
INT n=0,
ENUM {FIRST, LAST, UNIQUE} select=UNIQUE
)
Like the ``.sub()`` method, this returns the result of calling
``.suball(text, rewrite, fallback)`` from the regex interface for
`nth` pattern added to the set, or the pattern that most recently
matched in a ``.match()`` call.
``.suball()`` is subject to the same conditions as the ``.sub()`` method:
* The pattern to which it is applied is identified by ``n`` and
``select`` according to the rules given above.
* It fails if:
* The pattern that it identifies was not saved with ``.add(save=true)``.
* The values of ``n`` or ``select`` are invalid.
* The ``.suball()`` method invoked on the saved ``regex`` object
fails.
Example::
# In any URL that matches one of the words given below, replace all
# occurrences of the matching word with "quux" (for example to
# rewrite path components or elements of query strings).
sub vcl_init {
new matcher = re2.set();
matcher.add("\bfoo\b", save=true);
matcher.add("\bbar\b", save=true);
matcher.add("\bbaz\b", save=true);
matcher.compile();
}
sub vcl_recv {
if (matcher.match(req.url)) {
if (matcher.nmatches() != 1) {
return(fail);
}
set req.url = matcher.suball(req.url, "quux");
}
}
......
......@@ -76,6 +76,16 @@ struct task_set_match {
size_t nmatches;
};
typedef
VCL_STRING regex_rewrite_f(const struct vrt_ctx *ctx, struct vmod_re2_regex *re,
VCL_STRING text, VCL_STRING rewrite,
VCL_STRING fallback);
static regex_rewrite_f * const regex_rewrite[] = {
[SUB] = vmod_regex_sub,
[SUBALL] = vmod_regex_suball,
};
static inline int
decimal_digits(int n)
{
......@@ -491,31 +501,50 @@ vmod_set_which(VRT_CTX, struct vmod_re2_set *set, VCL_ENUM selects)
return get_match_idx(ctx, set, 0, selects, "which") + 1;
}
VCL_STRING
vmod_set_sub(VRT_CTX, struct vmod_re2_set *set, VCL_STRING text,
VCL_STRING rewrite, VCL_STRING fallback, VCL_INT n,
VCL_ENUM selects)
static VCL_STRING
rewritef(VRT_CTX, struct vmod_re2_set * const restrict set,
VCL_STRING const restrict text, VCL_STRING const restrict rewrite,
VCL_STRING const restrict fallback, VCL_INT n,
VCL_ENUM const restrict selects, rewrite_e type)
{
int idx;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(set, VMOD_RE2_SET_MAGIC);
if (set->regex == NULL) {
VERR(ctx, "%s.sub(%lld): No regexen were saved for %s",
set->vcl_name, n, set->vcl_name);
VERR(ctx, "%s.%s(%lld): No regexen were saved for %s",
set->vcl_name, rewrite_name[type], n, set->vcl_name);
return NULL;
}
idx = get_match_idx(ctx, set, n, selects, "sub");
idx = get_match_idx(ctx, set, n, selects, rewrite_name[type]);
if (idx < 0)
return NULL;
if (!vbit_test(set->added[RE_ADDED], idx)) {
AN(selects);
VERR(ctx, "%s.sub(%s, %s, %lld, %s): Pattern %d was not saved",
set->vcl_name, text, rewrite, n, selects, idx + 1);
VERR(ctx, "%s.%s(%s, %s, %lld, %s): Pattern %d was not saved",
set->vcl_name, rewrite_name[type], text, rewrite, n,
selects, idx + 1);
return NULL;
}
return vmod_regex_sub(ctx, set->regex[idx], text, rewrite, fallback);
return (regex_rewrite[type])(ctx, set->regex[idx], text, rewrite,
fallback);
}
VCL_STRING
vmod_set_sub(VRT_CTX, struct vmod_re2_set *set, VCL_STRING text,
VCL_STRING rewrite, VCL_STRING fallback, VCL_INT n,
VCL_ENUM selects)
{
return rewritef(ctx, set, text, rewrite, fallback, n, selects, SUB);
}
VCL_STRING
vmod_set_suball(VRT_CTX, struct vmod_re2_set *set, VCL_STRING text,
VCL_STRING rewrite, VCL_STRING fallback, VCL_INT n,
VCL_ENUM selects)
{
return rewritef(ctx, set, text, rewrite, fallback, n, selects, SUBALL);
}
VCL_STRING
......
# looks like -*- vcl -*-
varnishtest "set.suball() method"
varnish v1 -vcl {
import ${vmod_re2};
backend be { .host = "${bad_ip}"; }
sub vcl_init {
new s = re2.set();
s.add("(qu|[b-df-hj-np-tv-z]*)([a-z]+)", save=true);
s.add("\w+", save=true);
s.add("^", save=true);
s.add("$", save=true);
s.add("b", save=true);
s.add("b+", save=true);
s.add("b*", save=true);
s.compile();
new n = re2.set();
n.add("b");
n.add("b+", save=true);
n.compile();
}
sub vcl_recv {
return(synth(200));
}
sub vcl_synth {
set resp.http.s-suball-1
= s.suball("the quick brown fox jumps over the lazy dogs.",
"\2\1ay", n=1);
set resp.http.s-suball-2 = s.suball("abcd.efghi@google.com",
"\0-NOSPAM", n=2);
set resp.http.s-suball-3 = s.suball("foo", "(START)", n=3);
set resp.http.s-suball-3-1 = s.suball("", "(START)", n=3);
set resp.http.s-suball-4 = s.suball("", "(END)", n=4);
set resp.http.s-suball-5-1 = s.suball("ababababab", "bb", n=5);
set resp.http.s-suball-5-2 = s.suball("bbbbbb", "bb", n=5);
set resp.http.s-suball-6 = s.suball("bbbbbb", "bb", n=6);
set resp.http.s-suball-7-1 = s.suball("bbbbbb", "bb", n=7);
set resp.http.s-suball-7-2 = s.suball("aaaaa", "bb", n=7);
set resp.http.s-match
= s.match("the quick brown fox jumps over the lazy dogs.");
set resp.http.s-n = s.nmatches();
set resp.http.s-pangram
= s.suball("the quick brown fox jumps over the lazy dogs.",
"\2\1ay", select=FIRST);
set resp.http.s-ab = s.suball("ababababab", "bb", select=LAST);
set resp.http.n-suball-1 = n.suball("bbbbbb", "bb", n=1);
set resp.http.n-suball-2 = n.suball("bbbbbb", "bb", n=2);
set resp.http.n-match = n.match("bbbbbb");
set resp.http.n-n = n.nmatches();
set resp.http.n-first = n.suball("bbbbbb", "bb", select=FIRST);
set resp.http.n-last = n.suball("bbbbbb", "bb", select=LAST);
}
} -start
client c1 {
txreq
rxresp
expect resp.status == 200
expect resp.http.s-suball-1 == "ethay ickquay ownbray oxfay umpsjay overay ethay azylay ogsday."
expect resp.http.s-suball-2 == "abcd-NOSPAM.efghi-NOSPAM@google-NOSPAM.com-NOSPAM"
expect resp.http.s-suball-3 == "(START)foo"
expect resp.http.s-suball-3-1 == "(START)"
expect resp.http.s-suball-4 == "(END)"
expect resp.http.s-suball-5-1 == "abbabbabbabbabb"
expect resp.http.s-suball-5-2 == "bbbbbbbbbbbb"
expect resp.http.s-suball-6 == "bb"
expect resp.http.s-suball-7-1 == "bb"
expect resp.http.s-suball-7-2 == "bbabbabbabbabbabb"
expect resp.http.s-match == "true"
expect resp.http.s-n == "7"
expect resp.http.s-pangram == resp.http.s-suball-1
expect resp.http.s-ab == resp.http.s-suball-7-2
expect resp.http.n-suball-1 == ""
expect resp.http.n-suball-2 == "bb"
expect resp.http.n-match == "true"
expect resp.http.n-n == "2"
expect resp.http.n-first == resp.http.n-suball-1
expect resp.http.n-last == resp.http.n-suball-2
} -run
logexpect l1 -v v1 -d 1 -g vxid -q "VCL_Error" {
expect 0 * Begin req
expect * = VCL_Error "^vmod re2 error: n.suball.bbbbbb, bb, 1, UNIQUE.: Pattern 1 was not saved$"
expect * = VCL_Error "^vmod re2 error: n.suball.bbbbbb, bb, 0, FIRST.: Pattern 1 was not saved$"
expect * = End
} -run
......@@ -51,7 +51,7 @@ static const void *match_failed = (void *) &c;
static size_t match_sz;
static const char * const rewrite_name[] = {
const char * const rewrite_name[] = {
[SUB] = "sub",
[SUBALL] = "suball",
[EXTRACT] = "extract",
......
......@@ -60,3 +60,6 @@ struct vmod_re2_regex {
};
void errmsg(VRT_CTX, const char *fmt, ...);
/* Defined in vmod_re2.c */
extern const char * const rewrite_name[];
......@@ -48,7 +48,10 @@ SYNOPSIS
INT <obj>.which([ENUM select])
STRING <obj>.string([INT n,] [ENUM select])
BACKEND <obj>.backend([INT n,] [ENUM select])
STRING <obj>.sub(STRING text, STRING rewrite [, INT n] [, ENUM select])
STRING <obj>.sub(STRING text, STRING rewrite [, INT n]
[, ENUM select])
STRING <obj>.suball(STRING text, STRING rewrite [, INT n]
[, ENUM select])
# VMOD version
STRING re2.version()
......@@ -1181,6 +1184,51 @@ Examples::
}
}
$Method STRING .suball(STRING text, STRING rewrite,
STRING fallback="**SUBALL METHOD FAILED**",
INT n=0, ENUM {FIRST, LAST, UNIQUE} select=UNIQUE)
Like the ``.sub()`` method, this returns the result of calling
``.suball(text, rewrite, fallback)`` from the regex interface for
`nth` pattern added to the set, or the pattern that most recently
matched in a ``.match()`` call.
``.suball()`` is subject to the same conditions as the ``.sub()`` method:
* The pattern to which it is applied is identified by ``n`` and
``select`` according to the rules given above.
* It fails if:
* The pattern that it identifies was not saved with ``.add(save=true)``.
* The values of ``n`` or ``select`` are invalid.
* The ``.suball()`` method invoked on the saved ``regex`` object
fails.
Example::
# In any URL that matches one of the words given below, replace all
# occurrences of the matching word with "quux" (for example to
# rewrite path components or elements of query strings).
sub vcl_init {
new matcher = re2.set();
matcher.add("\bfoo\b", save=true);
matcher.add("\bbar\b", save=true);
matcher.add("\bbaz\b", save=true);
matcher.compile();
}
sub vcl_recv {
if (matcher.match(req.url)) {
if (matcher.nmatches() != 1) {
return(fail);
}
set req.url = matcher.suball(req.url, "quux");
}
}
$Function STRING version()
Return the version string for this VMOD.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment