Add .foreach()

parent e31881e1
......@@ -19,6 +19,20 @@ vmod_re Changes
NEXT
----
* The ``xregex.foreach()`` method has been added to call a VCL
subroutine on all matches, which can then use ``xregex.backref()``
to access them. Example::
sub myregex_collect {
set resp.http.all += myregex.backref(0);
}
sub vcl_synth {
unset resp.http.all;
myregex.foreach(req.http.input, myregex_collect);
}
* With the optional ``asfilter`` argument to ``re.regex()``, a varnish
filter is created, which can be used to run regular expression
substitions on bodies, similar to a flexible mix between
......
......@@ -31,6 +31,9 @@ SYNOPSIS
BOOL <obj>.match_body(req_body | bereq_body | resp_body
[, INT limit] [, INT limit_recursion])
# Iterators
BOOL <obj>.foreach(STRING, SUB, [, INT limit] [, INT limit_recursion])
# filter interface (includes all of the above)
new <obj> = re.regex(STRING [, INT limit] [, INT limit_recursion]
, forbody=true)
......@@ -210,6 +213,48 @@ Description
Example
``if (myregex.match(beresp.http.Surrogate-Control)) { # ...``
.. _xregex.foreach():
BOOL xregex.foreach(STRING, SUB sub, INT limit, INT limit_recursion)
--------------------------------------------------------------------
::
BOOL xregex.foreach(
STRING,
SUB sub,
INT limit=0,
INT limit_recursion=0
)
Description
Calls subroutine *sub* as if `xregex.match()`_ was run for all
matches on the given string. If there are no matches, the
subroutine is not called. `xregex.backref()`_ can be used to
retrieve the match constituents.
Example::
sub vcl_init {
new myregex = re.regex("bar(\d+)");
}
sub myregex_collect {
set resp.http.all += myregex.backref(0);
}
sub vcl_synth {
unset resp.http.all;
myregex.foreach(req.http.input, myregex_collect);
}
sub vcl_recv {
return (synth(200));
}
*Note* This is a toy example, and if the purpose really is to collect
all matches, `regsuball()`_ is way more efficient.
.. _xregex.match_body():
BOOL xregex.match_body(ENUM which, INT limit, INT limit_recursion)
......
varnishtest ".foreach()"
# NOTE: This is a toy example, and using regsuball() is _way_
# more efficient to achieve the same result.
varnish v1 -vcl+backend {
import re from "${vmod_topbuild}/src/.libs/libvmod_re.so";
backend none none;
sub vcl_init {
new myregex = re.regex("bar(\d+)");
}
sub myregex_collect {
set resp.http.all += myregex.backref(0);
}
sub vcl_synth {
unset resp.http.all;
myregex.foreach(req.http.input, myregex_collect);
}
sub vcl_recv {
return (synth(200));
}
} -start
client c1 {
txreq -hdr "input: 0woesdbar42sadop93hu2edsbar7dskjfkdfbbar333"
rxresp
expect resp.http.all == "bar42bar7bar333"
} -run
......@@ -448,6 +448,42 @@ vmod_regex_match(VRT_CTX, struct vmod_re_regex *re, VCL_STRING subject,
> PCRE2_ERROR_NOMATCH);
}
VCL_BOOL
vmod_regex_foreach(VRT_CTX, struct vmod_re_regex *re, VCL_STRING subject,
VCL_SUB sub, VCL_INT limit, VCL_INT limit_recursion)
{
struct vmod_priv *task;
struct vre_limits buf;
ov_t *ov;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(re, VMOD_RE_REGEX_MAGIC);
AN(re->vre);
task = VRT_priv_task(ctx, re);
if (task == NULL) {
errmsg(ctx, "vmod re: Could not get a PRIV_TASK - out of workspace?");
return (0);
}
AN(task);
task->len = 0;
init_task(ctx, task);
if (task->priv == NULL)
return (0);
ov = (ov_t *) task->priv;
while (match(ctx, re->vre, subject, PCRE2_ZERO_TERMINATED,
ov->ovector[1], 0,
task, get_limits(re, &buf, limit, limit_recursion))
> PCRE2_ERROR_NOMATCH)
VRT_call(ctx, sub);
return (1);
}
struct re_iter_priv {
unsigned magic;
#define RE_ITER_PRIV_MAGIC 0x04383ab8
......
......@@ -27,6 +27,9 @@ SYNOPSIS
BOOL <obj>.match_body(req_body | bereq_body | resp_body
[, INT limit] [, INT limit_recursion])
# Iterators
BOOL <obj>.foreach(STRING, SUB, [, INT limit] [, INT limit_recursion])
# filter interface (includes all of the above)
new <obj> = re.regex(STRING [, INT limit] [, INT limit_recursion]
, forbody=true)
......@@ -187,6 +190,36 @@ Description
Example
``if (myregex.match(beresp.http.Surrogate-Control)) { # ...``
$Method BOOL .foreach(STRING, SUB sub, INT limit=0, INT limit_recursion=0)
Description
Calls subroutine *sub* as if `xregex.match()`_ was run for all
matches on the given string. If there are no matches, the
subroutine is not called. `xregex.backref()`_ can be used to
retrieve the match constituents.
Example::
sub vcl_init {
new myregex = re.regex("bar(\d+)");
}
sub myregex_collect {
set resp.http.all += myregex.backref(0);
}
sub vcl_synth {
unset resp.http.all;
myregex.foreach(req.http.input, myregex_collect);
}
sub vcl_recv {
return (synth(200));
}
*Note* This is a toy example, and if the purpose really is to collect
all matches, `regsuball()`_ is way more efficient.
$Method BOOL .match_body(ENUM {req_body, bereq_body, resp_body } which,
INT limit=0, INT limit_recursion=0)
......
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