Commit 26f3394e authored by Geoff Simmons's avatar Geoff Simmons

Use PRIV_TASK instead of pthread keys; THIS CHANGES THE INTERFACE.

The .match_dyn method has been removed, in its place we have the
functions match_dyn and backref_dyn.

Closes #1
parent b01518a1
Pipeline #200 skipped
......@@ -59,7 +59,7 @@ The equivalent solution with the VMOD looks like this::
sub vcl_recv {
if (myregex.match(req.http.Foo)) {
set req.http.Baz = myregex.backref(1, "");
set req.http.Baz = myregex.backref(1);
}
}
......@@ -68,29 +68,34 @@ the capture expression, only describing the substring to be
matched. When a match with the ``match`` method succeeds, then a
captured string can be obtained from the ``backref`` method.
Calls to the ``backref`` method refer back to the most recent
successful call to ``match`` for the same object in the same task
scope; that is, in the same client or backend context. For example if
``match`` is called for an object in one of the ``vcl_backend_*``
subroutines and returns ``true``, then subsequent calls to ``backref``
in the same backend scope extract substrings from the matched
substring.
The VMOD also supports dynamic regex matching with the ``match_dyn``
method::
and ``backref_dyn`` functions::
import re;
sub vcl_init {
new myregex = re.regex("");
}
sub vcl_backend_response {
if (myregex.match_dyn(beresp.http.Bar + "(\d+)",
if (re.match_dyn(beresp.http.Bar + "(\d+)",
req.http.Foo)) {
set beresp.http.Baz = myregex.backref(1, "");
set beresp.http.Baz = re.backref_dyn(1);
}
}
In ``match_dyn``, the regex in the first argument is compiled when it
is called, and matched against the string in the second argument; the
regex provided in ``vcl_init`` is ignored. Subsequent calls to
``backref`` extract substrings from the matched string.
is called, and matched against the string in the second
argument. Subsequent calls to ``backref_dyn`` extract substrings from
the matched string for the most recent successful call to
``match_dyn`` in the same task scope.
As with the constructor, the regex argument to ``match_dyn`` should
contain any capturing expressions needed for calls to ``backref``.
contain any capturing expressions needed for calls to ``backref_dyn``.
``match_dyn`` makes it possible to construct regexen whose contents
are not fully known until runtime, but ``match`` is more efficient,
......@@ -102,6 +107,8 @@ CONTENTS
========
* regex(STRING)
* BOOL match_dyn(PRIV_TASK, STRING, STRING)
* STRING backref_dyn(PRIV_TASK, INT, STRING)
* STRING version()
.. _obj_regex:
......@@ -113,9 +120,6 @@ regex
new OBJ = regex(STRING)
Prototype
new OBJ = re.regex(STRING)
Description
Create a regex object with the given regular expression. The
expression is compiled when the constructor is called. It
......@@ -177,24 +181,6 @@ Description
Example
``if (myregex.match(beresp.http.Surrogate-Control)) { # ...``
.. _func_regex.match_dyn:
regex.match_dyn
---------------
::
BOOL regex.match_dyn(STRING, STRING)
Description
Compiles the regular expression given in the first argument,
and determines whether it matches the string in the second
argument. The regex supplied in the constructor is ignored.
Example
``if (myregex.match_dyn(req.http.Foo + "(\d+)",``
``beresp.http.Bar)) { # ...``
.. _func_regex.backref:
regex.backref
......@@ -202,31 +188,72 @@ regex.backref
::
STRING regex.backref(INT, STRING)
STRING regex.backref(INT, STRING fallback="**BACKREF METHOD FAILED**")
Description
Extracts the `nth` subexpression of the most recent successful
call of the ``match`` or ``match_dyn`` method for this object
in the same VCL subroutine call, or a fallback string in case
the extraction fails. Backref 0 indicates the entire matched
string. Thus this function behaves like the ``\n`` symbols in
``regsub`` and ``regsuball``, and the ``$1``, ``$2`` ...
variables in Perl.
call of the ``match`` method for this object in the same task
scope (client or backend context), or a fallback string in
case the extraction fails. Backref 0 indicates the entire
matched string. Thus this function behaves like the ``\n``
symbols in ``regsub`` and ``regsuball``, and the ``$1``,
``$2`` ... variables in Perl.
After unsuccessful matches, the ``fallback`` string is returned
for any call to ``backref``.
for any call to ``backref``. The default value of ``fallback``
is ``"**BACKREF METHOD FAILED**"``.
The VCL infix operators ``~`` and ``!~`` do not affect this
method, nor do the functions ``regsub`` or ``regsuball``.
If ``backref`` is called without any prior call to ``match``
or ``match_dyn`` for this object in the same VCL context, then
an error message is emitted to the Varnish log using the
``VCL_Error`` tag, and the fallback string is returned.
for this object in the same task scope, then an error message
is emitted to the Varnish log using the ``VCL_Error`` tag, and
the fallback string is returned.
Example
``set beresp.ttl = std.duration(myregex.backref(1, "120"), 120s);``
.. _func_match_dyn:
match_dyn
---------
::
BOOL match_dyn(PRIV_TASK, STRING, STRING)
Description
Compiles the regular expression given in the first argument,
and determines whether it matches the string in the second
argument.
Example
``if (re.match_dyn(req.http.Foo + "(\d+)", beresp.http.Bar)) { # ...``
.. _func_backref_dyn:
backref_dyn
-----------
::
STRING backref_dyn(PRIV_TASK, INT, STRING fallback="**BACKREF FUNCTION FAILED**")
Description
Similar to the ``backref`` method, this function extracts the
`nth` subexpression of the most recent successful call of the
``match_dyn`` function in the same task scope, or a fallback
string in case the extraction fails.
After unsuccessful matches, the ``fallback`` string is returned
for any call to ``backref_dyn``. The default value of ``fallback``
is ``"**BACKREF FUNCTION FAILED**"``.
If ``backref_dyn`` is called without any prior call to ``match_dyn``
in the same task scope, then a ``VCL_Error`` message is logged, and
the fallback string is returned.
.. _func_version:
version
......
......@@ -29,7 +29,7 @@ varnish v1 -vcl+backend {
set beresp.http.static = "nomatch";
}
if (baz.match_dyn(beresp.http.foo, beresp.http.bar)) {
if (re.match_dyn(beresp.http.foo, beresp.http.bar)) {
set beresp.http.dynamic = "match";
}
else {
......
......@@ -25,7 +25,7 @@ varnish v1 -vcl+backend {
set beresp.status = 999;
}
if (barbaz.match_dyn("(bar)(baz)", beresp.http.foo)) {
if (re.match_dyn("(bar)(baz)", beresp.http.foo)) {
set beresp.http.foo0d = barbaz.backref(0, "error0");
set beresp.http.foo1d = barbaz.backref(1, "error1");
set beresp.http.foo2d = barbaz.backref(2, "error2");
......@@ -43,7 +43,7 @@ varnish v1 -vcl+backend {
set beresp.status = 999;
}
if (bazplus.match_dyn("(baz)(.+)", beresp.http.bar)) {
if (re.match_dyn("(baz)(.+)", beresp.http.bar)) {
set beresp.http.bar0d = bazplus.backref(0, "error0");
set beresp.http.bar1d = bazplus.backref(1, "error1");
set beresp.http.bar2d = bazplus.backref(2, "error2");
......@@ -66,8 +66,8 @@ varnish v1 -vcl+backend {
set beresp.status = 999;
}
if (barbaz.match_dyn("(bar)(baz)", beresp.http.foo)
&& bazplus.match_dyn("(baz)(.+)", beresp.http.bar)) {
if (re.match_dyn("(bar)(baz)", beresp.http.foo)
&& re.match_dyn("(baz)(.+)", beresp.http.bar)) {
set beresp.http.foo20d = barbaz.backref(0, "error0");
set beresp.http.foo21d = barbaz.backref(1, "error1");
set beresp.http.foo22d = barbaz.backref(2, "error2");
......@@ -91,7 +91,7 @@ varnish v1 -vcl+backend {
set beresp.status = 999;
}
if (fourdots.match_dyn("(.)(.)(.)(.)", beresp.http.barf)) {
if (re.match_dyn("(.)(.)(.)(.)", beresp.http.barf)) {
set beresp.http.frapd
= "_" + fourdots.backref(0, "error0") + "_"
+ fourdots.backref(5, "")
......
......@@ -11,49 +11,44 @@ server s1 {
varnish v1 -vcl+backend {
import re from "${vmod_topbuild}/src/.libs/libvmod_re.so";
sub vcl_init {
new frobnitz = re.regex("");
new barbaz = re.regex("");
}
sub vcl_deliver {
set resp.http.nomatch = barbaz.backref(0, "fallback");
set resp.http.nomatch = re.backref_dyn(0, "fallback");
if (frobnitz.match_dyn("(frob)(nitz)", resp.http.foo)) {
if (re.match_dyn("(frob)(nitz)", resp.http.foo)) {
set resp.http.frob = "nitz";
}
set resp.http.frob0 = frobnitz.backref(0, "fallback0");
set resp.http.frob1 = frobnitz.backref(1, "fallback1");
set resp.http.frob2 = frobnitz.backref(2, "fallback2");
set resp.http.frob3 = frobnitz.backref(3, "fallback3");
set resp.http.frob4 = frobnitz.backref(4, "fallback4");
set resp.http.frob5 = frobnitz.backref(5, "fallback5");
set resp.http.frob6 = frobnitz.backref(6, "fallback6");
set resp.http.frob7 = frobnitz.backref(7, "fallback7");
set resp.http.frob8 = frobnitz.backref(8, "fallback8");
set resp.http.frob9 = frobnitz.backref(9, "fallback9");
set resp.http.frob10 = frobnitz.backref(10, "fallback10");
set resp.http.frob0 = re.backref_dyn(0, "fallback0");
set resp.http.frob1 = re.backref_dyn(1, "fallback1");
set resp.http.frob2 = re.backref_dyn(2, "fallback2");
set resp.http.frob3 = re.backref_dyn(3, "fallback3");
set resp.http.frob4 = re.backref_dyn(4, "fallback4");
set resp.http.frob5 = re.backref_dyn(5, "fallback5");
set resp.http.frob6 = re.backref_dyn(6, "fallback6");
set resp.http.frob7 = re.backref_dyn(7, "fallback7");
set resp.http.frob8 = re.backref_dyn(8, "fallback8");
set resp.http.frob9 = re.backref_dyn(9, "fallback9");
set resp.http.frob10 = re.backref_dyn(10, "fallback10");
if (barbaz.match_dyn("(bar)(baz)", resp.http.foo)) {
set resp.http.foo0 = barbaz.backref(0, "error0");
set resp.http.foo1 = barbaz.backref(1, "error1");
set resp.http.foo2 = barbaz.backref(2, "error2");
set resp.http.foo3 = barbaz.backref(3, "foofallback");
if (re.match_dyn("(bar)(baz)", resp.http.foo)) {
set resp.http.foo0 = re.backref_dyn(0, "error0");
set resp.http.foo1 = re.backref_dyn(1, "error1");
set resp.http.foo2 = re.backref_dyn(2, "error2");
set resp.http.foo3 = re.backref_dyn(3, "foofallback");
}
if (barbaz.match_dyn("(bar)(baz)", resp.http.barf)) {
if (re.match_dyn("(bar)(baz)", resp.http.barf)) {
set resp.http.puke = "match";
}
set resp.http.barf0 = barbaz.backref(0, "fallback0");
set resp.http.barf1 = barbaz.backref(1, "fallback1");
set resp.http.barf2 = barbaz.backref(2, "fallback2");
set resp.http.barf3 = barbaz.backref(3, "fallback3");
set resp.http.barf4 = barbaz.backref(4, "fallback4");
set resp.http.barf5 = barbaz.backref(5, "fallback5");
set resp.http.barf6 = barbaz.backref(6, "fallback6");
set resp.http.barf7 = barbaz.backref(7, "fallback7");
set resp.http.barf8 = barbaz.backref(8, "fallback8");
set resp.http.barf9 = barbaz.backref(9, "fallback9");
set resp.http.barf10 = barbaz.backref(10, "fallback10");
set resp.http.barf0 = re.backref_dyn(0, "fallback0");
set resp.http.barf1 = re.backref_dyn(1, "fallback1");
set resp.http.barf2 = re.backref_dyn(2, "fallback2");
set resp.http.barf3 = re.backref_dyn(3, "fallback3");
set resp.http.barf4 = re.backref_dyn(4, "fallback4");
set resp.http.barf5 = re.backref_dyn(5, "fallback5");
set resp.http.barf6 = re.backref_dyn(6, "fallback6");
set resp.http.barf7 = re.backref_dyn(7, "fallback7");
set resp.http.barf8 = re.backref_dyn(8, "fallback8");
set resp.http.barf9 = re.backref_dyn(9, "fallback9");
set resp.http.barf10 = re.backref_dyn(10, "fallback10");
}
} -start
......
......@@ -21,10 +21,10 @@ varnish v1 -vcl+backend {
set beresp.status = 999;
}
if (barbaz.match_dyn("(?:bar)(baz)", beresp.http.foo)) {
set beresp.http.foo0d = barbaz.backref(0, "error0");
set beresp.http.foo1d = barbaz.backref(1, "error1");
set beresp.http.foo2d = barbaz.backref(2, "fallback");
if (re.match_dyn("(?:bar)(baz)", beresp.http.foo)) {
set beresp.http.foo0d = re.backref_dyn(0, "error0");
set beresp.http.foo1d = re.backref_dyn(1, "error1");
set beresp.http.foo2d = re.backref_dyn(2, "fallback");
} else {
set beresp.status = 999;
}
......
......@@ -10,43 +10,38 @@ server s1 {
varnish v1 -vcl+backend {
import re from "${vmod_topbuild}/src/.libs/libvmod_re.so";
sub vcl_init {
new tendots = re.regex("");
new moredots = re.regex("");
}
sub vcl_backend_response {
if (tendots.match_dyn("(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)",
if (re.match_dyn("(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)",
beresp.http.foo)) {
set beresp.http.foo0 = tendots.backref(0, "error0");
set beresp.http.foo1 = tendots.backref(1, "error1");
set beresp.http.foo2 = tendots.backref(2, "error2");
set beresp.http.foo3 = tendots.backref(3, "error3");
set beresp.http.foo4 = tendots.backref(4, "error4");
set beresp.http.foo5 = tendots.backref(5, "error5");
set beresp.http.foo6 = tendots.backref(6, "error6");
set beresp.http.foo7 = tendots.backref(7, "error7");
set beresp.http.foo8 = tendots.backref(8, "error8");
set beresp.http.foo9 = tendots.backref(9, "error9");
set beresp.http.foo10 = tendots.backref(10, "error10");
set beresp.http.foo11 = tendots.backref(11, "fallback");
set beresp.http.foo0 = re.backref_dyn(0, "error0");
set beresp.http.foo1 = re.backref_dyn(1, "error1");
set beresp.http.foo2 = re.backref_dyn(2, "error2");
set beresp.http.foo3 = re.backref_dyn(3, "error3");
set beresp.http.foo4 = re.backref_dyn(4, "error4");
set beresp.http.foo5 = re.backref_dyn(5, "error5");
set beresp.http.foo6 = re.backref_dyn(6, "error6");
set beresp.http.foo7 = re.backref_dyn(7, "error7");
set beresp.http.foo8 = re.backref_dyn(8, "error8");
set beresp.http.foo9 = re.backref_dyn(9, "error9");
set beresp.http.foo10 = re.backref_dyn(10, "error10");
set beresp.http.foo11 = re.backref_dyn(11, "fallback");
} else {
set beresp.status = 999;
}
if (moredots.match_dyn("(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)",
if (re.match_dyn("(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)",
beresp.http.bar)) {
set beresp.http.bar0 = moredots.backref(0, "error0");
set beresp.http.bar1 = moredots.backref(1, "error1");
set beresp.http.bar2 = moredots.backref(2, "error2");
set beresp.http.bar3 = moredots.backref(3, "error3");
set beresp.http.bar4 = moredots.backref(4, "error4");
set beresp.http.bar5 = moredots.backref(5, "error5");
set beresp.http.bar6 = moredots.backref(6, "error6");
set beresp.http.bar7 = moredots.backref(7, "error7");
set beresp.http.bar8 = moredots.backref(8, "error8");
set beresp.http.bar9 = moredots.backref(9, "error9");
set beresp.http.bar10 = moredots.backref(10, "error10");
set beresp.http.bar11 = moredots.backref(11, "fallback");
set beresp.http.bar0 = re.backref_dyn(0, "error0");
set beresp.http.bar1 = re.backref_dyn(1, "error1");
set beresp.http.bar2 = re.backref_dyn(2, "error2");
set beresp.http.bar3 = re.backref_dyn(3, "error3");
set beresp.http.bar4 = re.backref_dyn(4, "error4");
set beresp.http.bar5 = re.backref_dyn(5, "error5");
set beresp.http.bar6 = re.backref_dyn(6, "error6");
set beresp.http.bar7 = re.backref_dyn(7, "error7");
set beresp.http.bar8 = re.backref_dyn(8, "error8");
set beresp.http.bar9 = re.backref_dyn(9, "error9");
set beresp.http.bar10 = re.backref_dyn(10, "error10");
set beresp.http.bar11 = re.backref_dyn(11, "fallback");
} else {
set beresp.status = 999;
}
......
......@@ -41,33 +41,33 @@ varnish v1 -vcl+backend {
set beresp.http.regsuball0 = barbaz.backref(0, "regsuball0");
set beresp.http.regsuball1 = barbaz.backref(1, "regsuball1");
if (!barbaz.match_dyn("(bar)baz", beresp.http.foo)) {
if (!re.match_dyn("(bar)baz", beresp.http.foo)) {
set beresp.status = 999;
}
if (beresp.http.foo ~ "bar(baz)") {
set beresp.http.tilde0d = barbaz.backref(0, "tilde0d");
set beresp.http.tilde1d = barbaz.backref(1, "tilde1d");
set beresp.http.tilde0d = re.backref_dyn(0, "tilde0d");
set beresp.http.tilde1d = re.backref_dyn(1, "tilde1d");
} else {
set beresp.status = 999;
}
if (beresp.http.foo !~ "bar(quux)") {
set beresp.http.neg0d = barbaz.backref(0, "neg0d");
set beresp.http.neg1d = barbaz.backref(1, "neg1d");
set beresp.http.neg0d = re.backref_dyn(0, "neg0d");
set beresp.http.neg1d = re.backref_dyn(1, "neg1d");
} else {
set beresp.status = 999;
}
set beresp.http.regsubd
= regsub(beresp.http.foo, "bar(baz)", "\1");
set beresp.http.regsub0d = barbaz.backref(0, "regsub0d");
set beresp.http.regsub1d = barbaz.backref(1, "regsub1d");
set beresp.http.regsub0d = re.backref_dyn(0, "regsub0d");
set beresp.http.regsub1d = re.backref_dyn(1, "regsub1d");
set beresp.http.regsuballd
= regsuball(beresp.http.foo, "(.)", "x");
set beresp.http.regsuball0d = barbaz.backref(0, "regsuball0d");
set beresp.http.regsuball1d = barbaz.backref(1, "regsuball1d");
set beresp.http.regsuball0d = re.backref_dyn(0, "regsuball0d");
set beresp.http.regsuball1d = re.backref_dyn(1, "regsuball1d");
}
} -start
......
......@@ -34,28 +34,27 @@ varnish v1 -vcl+backend {
set resp.http.paren9 = paren.backref(9, "fallback9");
set resp.http.paren10 = paren.backref(10, "fallback10");
if (paren.match_dyn("(bar)", resp.http.foo)) {
# dynamic matches do not affect failed() or error()
set resp.http.parend = paren.failed();
set resp.http.errord = paren.error();
if (!re.match_dyn("(bar)", resp.http.foo)) {
set resp.status = 999;
return(deliver);
}
/* compilation fails */
if (parend.match_dyn(")", resp.http.foo)) {
if (re.match_dyn(")", resp.http.foo)) {
set resp.http.matchd = "success";
}
/* ... so all backrefs fail */
set resp.http.paren0d = parend.backref(0, "fallback0");
set resp.http.paren1d = parend.backref(1, "fallback1");
set resp.http.paren2d = parend.backref(2, "fallback2");
set resp.http.paren3d = parend.backref(3, "fallback3");
set resp.http.paren4d = parend.backref(4, "fallback4");
set resp.http.paren5d = parend.backref(5, "fallback5");
set resp.http.paren6d = parend.backref(6, "fallback6");
set resp.http.paren7d = parend.backref(7, "fallback7");
set resp.http.paren8d = parend.backref(8, "fallback8");
set resp.http.paren9d = parend.backref(9, "fallback9");
set resp.http.paren10d = parend.backref(10, "fallback10");
set resp.http.paren0d = re.backref_dyn(0, "fallback0");
set resp.http.paren1d = re.backref_dyn(1, "fallback1");
set resp.http.paren2d = re.backref_dyn(2, "fallback2");
set resp.http.paren3d = re.backref_dyn(3, "fallback3");
set resp.http.paren4d = re.backref_dyn(4, "fallback4");
set resp.http.paren5d = re.backref_dyn(5, "fallback5");
set resp.http.paren6d = re.backref_dyn(6, "fallback6");
set resp.http.paren7d = re.backref_dyn(7, "fallback7");
set resp.http.paren8d = re.backref_dyn(8, "fallback8");
set resp.http.paren9d = re.backref_dyn(9, "fallback9");
set resp.http.paren10d = re.backref_dyn(10, "fallback10");
}
} -start
......@@ -80,10 +79,7 @@ client c1 {
expect resp.http.paren9 == "fallback9"
expect resp.http.paren10 == "fallback10"
expect resp.http.parend == "true"
expect resp.http.matchd == <undef>
expect resp.http.errord != <undef>
expect resp.http.errord != ""
expect resp.http.paren0d == "fallback0"
expect resp.http.paren1d == "fallback1"
expect resp.http.paren2d == "fallback2"
......@@ -106,18 +102,5 @@ logexpect l1 -v v1 -d 1 -g vxid -q "VCL_Error" {
# from match_dyn()
expect * = VCL_Error "^vmod re: error compiling regex"
# from the backref() calls after match_dyn()
expect * = VCL_Error "^vmod re: backref called without prior match$"
expect * = VCL_Error "^vmod re: backref called without prior match$"
expect * = VCL_Error "^vmod re: backref called without prior match$"
expect * = VCL_Error "^vmod re: backref called without prior match$"
expect * = VCL_Error "^vmod re: backref called without prior match$"
expect * = VCL_Error "^vmod re: backref called without prior match$"
expect * = VCL_Error "^vmod re: backref called without prior match$"
expect * = VCL_Error "^vmod re: backref called without prior match$"
expect * = VCL_Error "^vmod re: backref called without prior match$"
expect * = VCL_Error "^vmod re: backref called without prior match$"
expect * = VCL_Error "^vmod re: backref called without prior match$"
expect * = End
} -run
......@@ -30,7 +30,6 @@
#include "config.h"
#include <stdlib.h>
#include <pthread.h>
#include "vre.h"
#include "cache/cache.h"
......@@ -60,7 +59,6 @@ struct vmod_re_regex {
unsigned magic;
#define VMOD_RE_REGEX_MAGIC 0x955706ee
vre_t *vre;
pthread_key_t ovk;
int erroffset;
const char *error;
};
......@@ -76,8 +74,8 @@ static char c;
static const void *match_failed = (void *) &c;
VCL_VOID
vmod_regex__init(const struct vrt_ctx *ctx, struct vmod_re_regex **rep,
const char *vcl_name, VCL_STRING pattern)
vmod_regex__init(VRT_CTX, struct vmod_re_regex **rep, const char *vcl_name,
VCL_STRING pattern)
{
struct vmod_re_regex *re;
......@@ -93,7 +91,6 @@ vmod_regex__init(const struct vrt_ctx *ctx, struct vmod_re_regex **rep,
AN(re);
*rep = re;
AZ(pthread_key_create(&re->ovk, NULL));
re->erroffset = 0;
re->error = NULL;
......@@ -107,7 +104,7 @@ vmod_regex__init(const struct vrt_ctx *ctx, struct vmod_re_regex **rep,
}
VCL_BOOL
vmod_regex_failed(const struct vrt_ctx *ctx, struct vmod_re_regex *re)
vmod_regex_failed(VRT_CTX, struct vmod_re_regex *re)
{
(void) ctx;
CHECK_OBJ_NOTNULL(re, VMOD_RE_REGEX_MAGIC);
......@@ -115,7 +112,7 @@ vmod_regex_failed(const struct vrt_ctx *ctx, struct vmod_re_regex *re)
}
VCL_STRING
vmod_regex_error(const struct vrt_ctx *ctx, struct vmod_re_regex *re)
vmod_regex_error(VRT_CTX, struct vmod_re_regex *re)
{
VCL_STRING error;
......@@ -142,7 +139,6 @@ vmod_regex__fini(struct vmod_re_regex **rep)
return;
re = *rep;
*rep = NULL;
AZ(pthread_key_delete(re->ovk));
CHECK_OBJ_NOTNULL(re, VMOD_RE_REGEX_MAGIC);
if (re->vre != NULL)
VRE_free(&re->vre);
......@@ -150,33 +146,30 @@ vmod_regex__fini(struct vmod_re_regex **rep)
}
static VCL_BOOL
match(const struct vrt_ctx *ctx, struct vmod_re_regex *re, vre_t *vre,
VCL_STRING subject)
match(VRT_CTX, vre_t *vre, VCL_STRING subject, struct vmod_priv *task)
{
ov_t *ov;
int s, nov[MAX_OV];
uintptr_t snap;
size_t cp;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(re, VMOD_RE_REGEX_MAGIC);
if (vre == NULL)
vre = re->vre;
AZ(pthread_setspecific(re->ovk, match_failed));
AN(vre);
if (subject == NULL)
subject = "";
/* compilation error at init time */
if (vre == NULL) {
AN(re->error);
VSLb(ctx->vsl, SLT_VCL_Error,
"vmod re: error compiling regex: %s (position %d)",
re->error, re->erroffset);
if (task->priv == NULL) {
if ((task->priv = WS_Alloc(ctx->ws, sizeof(*ov))) == NULL) {
VSLb(ctx->vsl, SLT_VCL_Error, "vmod re error: "
"insufficient workspace for backref data");
return 0;
}
if (subject == NULL)
subject = "";
task->len = -1;
task->free = NULL;
ov = (ov_t *) task->priv;
ov->magic = OV_MAGIC;
}
else
CAST_OBJ(ov, task->priv, OV_MAGIC);
/* XXX: cache_param->vre_limits incorrect?! */
s = VRE_exec(vre, subject, strlen(subject), 0, 0, nov, MAX_OV,
......@@ -197,13 +190,8 @@ match(const struct vrt_ctx *ctx, struct vmod_re_regex *re, vre_t *vre,
s = MAX_MATCHES;
}
task->len = sizeof(*ov);
snap = WS_Snapshot(ctx->ws);
ov = (ov_t *) WS_Alloc(ctx->ws, sizeof(ov_t));
if (ov == NULL) {
VSLb(ctx->vsl, SLT_VCL_Error,
"vmod re: insufficient workspace");
return 0;
}
ov->subject = WS_Copy(ctx->ws, (const void *) subject, -1);
if (ov->subject == NULL) {
WS_Reset(ctx->ws, snap);
......@@ -211,71 +199,39 @@ match(const struct vrt_ctx *ctx, struct vmod_re_regex *re, vre_t *vre,
"vmod re: insufficient workspace");
return 0;
}
ov->magic = OV_MAGIC;
memset(ov->ovector, -1, sizeof(ov->ovector));
cp = s * 2 * sizeof(*nov);
assert(cp <= sizeof(nov));
memcpy(ov->ovector, nov, cp);
AZ(pthread_setspecific(re->ovk, (const void *) ov));
return 1;
}
VCL_BOOL
vmod_regex_match(const struct vrt_ctx *ctx, struct vmod_re_regex *re,
VCL_STRING subject)
{
return match(ctx, re, NULL, subject);
}
VCL_BOOL
vmod_regex_match_dyn(const struct vrt_ctx *ctx, struct vmod_re_regex *re,
VCL_STRING pattern, VCL_STRING subject)
static VCL_STRING
backref(VRT_CTX, VCL_INT refnum, VCL_STRING fallback, struct vmod_priv *task)
{
vre_t *vre;
int erroffset;
const char *error;
AN(pattern);
vre = VRE_compile(pattern, 0, &error, &erroffset);
if (vre == NULL) {
VSLb(ctx->vsl, SLT_VCL_Error,
"vmod re: error compiling regex \"%s\": %s (position %d)",
pattern, error, erroffset);
return 0;
}
return match(ctx, re, vre, subject);
}
VCL_STRING
vmod_regex_backref(const struct vrt_ctx *ctx, struct vmod_re_regex *re,
VCL_INT refnum, VCL_STRING fallback)
{
void *p;
ov_t *ov;
char *substr;
int len;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(re, VMOD_RE_REGEX_MAGIC);
AN(fallback);
assert(refnum >= 0);
AN(task);
if (refnum >= MAX_MATCHES) {
if (refnum < 0 || refnum >= MAX_MATCHES) {
VSLb(ctx->vsl, SLT_VCL_Error,
"vmod re: backref %ld out of range", refnum);
return fallback;
}
p = pthread_getspecific(re->ovk);
if (p == NULL) {
if (task->priv == NULL) {
VSLb(ctx->vsl, SLT_VCL_Error,
"vmod re: backref called without prior match");
return fallback;
}
if (p == match_failed)
if (task->len <= 0)
return fallback;
CAST_OBJ(ov, p, OV_MAGIC);
CAST_OBJ(ov, task->priv, OV_MAGIC);
assert((char *)ov >= ctx->ws->s && (char *)ov < ctx->ws->e);
assert(ov->subject >= ctx->ws->s && ov->subject < ctx->ws->e);
......@@ -296,8 +252,72 @@ vmod_regex_backref(const struct vrt_ctx *ctx, struct vmod_re_regex *re,
return substr;
}
VCL_BOOL
vmod_regex_match(VRT_CTX, struct vmod_re_regex *re, VCL_STRING subject)
{
struct vmod_priv *task;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(re, VMOD_RE_REGEX_MAGIC);
/* compilation error at init time */
if (re->vre == NULL) {
AN(re->error);
VSLb(ctx->vsl, SLT_VCL_Error,
"vmod re: error compiling regex: %s (position %d)",
re->error, re->erroffset);
return 0;
}
task = VRT_priv_task(ctx, re);
AN(task);
task->len = 0;
return match(ctx, re->vre, subject, task);
}
VCL_STRING
vmod_regex_backref(VRT_CTX, struct vmod_re_regex *re, VCL_INT refnum,
VCL_STRING fallback)
{
struct vmod_priv *task;
CHECK_OBJ_NOTNULL(re, VMOD_RE_REGEX_MAGIC);
task = VRT_priv_task(ctx, re);
return backref(ctx, refnum, fallback, task);
}
VCL_BOOL
vmod_match_dyn(VRT_CTX, struct vmod_priv *task, VCL_STRING pattern,
VCL_STRING subject)
{
vre_t *vre;
int erroffset;
const char *error;
AN(pattern);
AN(task);
task->len = 0;
vre = VRE_compile(pattern, 0, &error, &erroffset);
if (vre == NULL) {
VSLb(ctx->vsl, SLT_VCL_Error,
"vmod re: error compiling regex \"%s\": %s (position %d)",
pattern, error, erroffset);
return 0;
}
return match(ctx, vre, subject, task);
}
VCL_STRING
vmod_backref_dyn(VRT_CTX, struct vmod_priv *task, VCL_INT refnum,
VCL_STRING fallback)
{
return backref(ctx, refnum, fallback, task);
}
VCL_STRING
vmod_version(const struct vrt_ctx *ctx __attribute__((unused)))
vmod_version(VRT_CTX __attribute__((unused)))
{
return VERSION;
}
......@@ -44,7 +44,7 @@ The equivalent solution with the VMOD looks like this::
sub vcl_recv {
if (myregex.match(req.http.Foo)) {
set req.http.Baz = myregex.backref(1, "");
set req.http.Baz = myregex.backref(1);
}
}
......@@ -53,29 +53,34 @@ the capture expression, only describing the substring to be
matched. When a match with the ``match`` method succeeds, then a
captured string can be obtained from the ``backref`` method.
Calls to the ``backref`` method refer back to the most recent
successful call to ``match`` for the same object in the same task
scope; that is, in the same client or backend context. For example if
``match`` is called for an object in one of the ``vcl_backend_*``
subroutines and returns ``true``, then subsequent calls to ``backref``
in the same backend scope extract substrings from the matched
substring.
The VMOD also supports dynamic regex matching with the ``match_dyn``
method::
and ``backref_dyn`` functions::
import re;
sub vcl_init {
new myregex = re.regex("");
}
sub vcl_backend_response {
if (myregex.match_dyn(beresp.http.Bar + "(\d+)",
if (re.match_dyn(beresp.http.Bar + "(\d+)",
req.http.Foo)) {
set beresp.http.Baz = myregex.backref(1, "");
set beresp.http.Baz = re.backref_dyn(1);
}
}
In ``match_dyn``, the regex in the first argument is compiled when it
is called, and matched against the string in the second argument; the
regex provided in ``vcl_init`` is ignored. Subsequent calls to
``backref`` extract substrings from the matched string.
is called, and matched against the string in the second
argument. Subsequent calls to ``backref_dyn`` extract substrings from
the matched string for the most recent successful call to
``match_dyn`` in the same task scope.
As with the constructor, the regex argument to ``match_dyn`` should
contain any capturing expressions needed for calls to ``backref``.
contain any capturing expressions needed for calls to ``backref_dyn``.
``match_dyn`` makes it possible to construct regexen whose contents
are not fully known until runtime, but ``match`` is more efficient,
......@@ -85,9 +90,6 @@ never changes during the lifetime of VCL, use ``match``.
$Object regex(STRING)
Prototype
new OBJ = re.regex(STRING)
Description
Create a regex object with the given regular expression. The
expression is compiled when the constructor is called. It
......@@ -128,42 +130,59 @@ Description
Example
``if (myregex.match(beresp.http.Surrogate-Control)) { # ...``
$Method BOOL .match_dyn(STRING, STRING)
Description
Compiles the regular expression given in the first argument,
and determines whether it matches the string in the second
argument. The regex supplied in the constructor is ignored.
Example
``if (myregex.match_dyn(req.http.Foo + "(\d+)",``
``beresp.http.Bar)) { # ...``
$Method STRING .backref(INT, STRING)
$Method STRING .backref(INT, STRING fallback="**BACKREF METHOD FAILED**")
Description
Extracts the `nth` subexpression of the most recent successful
call of the ``match`` or ``match_dyn`` method for this object
in the same VCL subroutine call, or a fallback string in case
the extraction fails. Backref 0 indicates the entire matched
string. Thus this function behaves like the ``\n`` symbols in
``regsub`` and ``regsuball``, and the ``$1``, ``$2`` ...
variables in Perl.
call of the ``match`` method for this object in the same task
scope (client or backend context), or a fallback string in
case the extraction fails. Backref 0 indicates the entire
matched string. Thus this function behaves like the ``\n``
symbols in ``regsub`` and ``regsuball``, and the ``$1``,
``$2`` ... variables in Perl.
After unsuccessful matches, the ``fallback`` string is returned
for any call to ``backref``.
for any call to ``backref``. The default value of ``fallback``
is ``"**BACKREF METHOD FAILED**"``.
The VCL infix operators ``~`` and ``!~`` do not affect this
method, nor do the functions ``regsub`` or ``regsuball``.
If ``backref`` is called without any prior call to ``match``
or ``match_dyn`` for this object in the same VCL context, then
an error message is emitted to the Varnish log using the
``VCL_Error`` tag, and the fallback string is returned.
for this object in the same task scope, then an error message
is emitted to the Varnish log using the ``VCL_Error`` tag, and
the fallback string is returned.
Example
``set beresp.ttl = std.duration(myregex.backref(1, "120"), 120s);``
$Function BOOL match_dyn(PRIV_TASK, STRING, STRING)
Description
Compiles the regular expression given in the first argument,
and determines whether it matches the string in the second
argument.
Example
``if (re.match_dyn(req.http.Foo + "(\d+)", beresp.http.Bar)) { # ...``
$Function STRING backref_dyn(PRIV_TASK, INT,
STRING fallback="**BACKREF FUNCTION FAILED**")
Description
Similar to the ``backref`` method, this function extracts the
`nth` subexpression of the most recent successful call of the
``match_dyn`` function in the same task scope, or a fallback
string in case the extraction fails.
After unsuccessful matches, the ``fallback`` string is returned
for any call to ``backref_dyn``. The default value of ``fallback``
is ``"**BACKREF FUNCTION FAILED**"``.
If ``backref_dyn`` is called without any prior call to ``match_dyn``
in the same task scope, then a ``VCL_Error`` message is logged, and
the fallback string is returned.
$Function STRING version()
Description
......
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