Commit 425244ba authored by Geoff Simmons's avatar Geoff Simmons

add the function interface for match(), backref() and namedref()

parent c1c5be51
......@@ -27,6 +27,9 @@ import re2 [from "path"] ;
CONTENTS
========
* STRING backref(PRIV_TASK, INT, STRING)
* BOOL match(PRIV_TASK, STRING, STRING, BOOL, BOOL, BOOL, INT, BOOL, BOOL, BOOL, BOOL, BOOL, BOOL, BOOL, BOOL)
* STRING namedref(PRIV_TASK, STRING, STRING)
* Object regex
* STRING regex.backref(INT, STRING)
* STRING regex.backref_named(STRING, STRING)
......@@ -63,6 +66,30 @@ STRING regex.backref_named(STRING, STRING)
Prototype
STRING regex.backref_named(STRING name, STRING fallback)
.. _func_match:
BOOL match(PRIV_TASK, STRING, STRING, BOOL, BOOL, BOOL, INT, BOOL, BOOL, BOOL, BOOL, BOOL, BOOL, BOOL, BOOL)
------------------------------------------------------------------------------------------------------------
Prototype
BOOL match(PRIV_TASK, STRING pattern, STRING subject, BOOL utf8, BOOL posix_syntax, BOOL longest_match, INT max_mem, BOOL literal, BOOL never_nl, BOOL dot_nl, BOOL never_capture, BOOL case_sensitive, BOOL perl_classes, BOOL word_boundary, BOOL one_line)
.. _func_backref:
STRING backref(PRIV_TASK, INT, STRING)
--------------------------------------
Prototype
STRING backref(PRIV_TASK, INT ref, STRING fallback)
.. _func_namedref:
STRING namedref(PRIV_TASK, STRING, STRING)
------------------------------------------
Prototype
STRING namedref(PRIV_TASK, STRING name, STRING fallback)
.. _func_version:
STRING version()
......
......@@ -55,6 +55,22 @@ varnish v1 -vcl+backend {
} else {
set beresp.status = 999;
}
if (re2.match("(bar)(baz)", beresp.http.foo)) {
set beresp.http.foo0f = re2.backref(0, "error0");
set beresp.http.foo1f = re2.backref(1, "error1");
set beresp.http.foo2f = re2.backref(2, "error2");
} else {
set beresp.status = 999;
}
if (re2.match("(baz)(.+)", beresp.http.bar)) {
set beresp.http.bar0f = re2.backref(0, "error0");
set beresp.http.bar1f = re2.backref(1, "error1");
set beresp.http.bar2f = re2.backref(2, "error2");
} else {
set beresp.status = 999;
}
}
} -start
......@@ -62,6 +78,7 @@ varnish v1 -vcl+backend {
client c1 {
txreq
rxresp
expect resp.status == 200
expect resp.http.foo0 == "barbaz"
expect resp.http.foo1 == "bar"
expect resp.http.foo2 == "baz"
......@@ -75,4 +92,11 @@ client c1 {
expect resp.http.bar21 == "baz"
expect resp.http.bar22 == "quux"
expect resp.http.frap == "_barf_frap_"
expect resp.http.foo0f == "barbaz"
expect resp.http.foo1f == "bar"
expect resp.http.foo2f == "baz"
expect resp.http.bar0f == "bazquux"
expect resp.http.bar1f == "baz"
expect resp.http.bar2f == "quux"
} -run
......@@ -18,9 +18,13 @@ varnish v1 -vcl+backend {
new never = re2.regex("(bar)(baz)", never_capture=true);
}
sub vcl_recv {
return(pass);
}
sub vcl_deliver {
# Call to backref() before match()
set resp.http.nomatch = barbaz.backref(0, "fallback");
set resp.http.nomatch = barbaz.backref(0, "fallback");
/* does not match */
if (frobnitz.match(resp.http.foo)) {
......@@ -32,13 +36,13 @@ varnish v1 -vcl+backend {
set resp.http.frob2 = frobnitz.backref(2, "fallback2");
set resp.http.frob3 = frobnitz.backref(3, "fallback3");
/* matches with backrefs, as above */
/* match succeeds */
if (barbaz.match(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");
}
/* does not match */
/* match fails */
if (barbaz.match(resp.http.barf)) {
set resp.http.puke = "match";
}
......@@ -68,7 +72,6 @@ varnish v1 -vcl+backend {
set resp.http.never1 = never.backref(1, "fallback1");
set resp.http.never2 = never.backref(2, "fallback2");
}
} -start
client c1 {
......@@ -80,6 +83,7 @@ client c1 {
expect resp.http.frob0 == "fallback0"
expect resp.http.frob1 == "fallback1"
expect resp.http.frob2 == "fallback2"
expect resp.http.frob3 == "fallback3"
expect resp.http.foo0 == "barbaz"
expect resp.http.foo1 == "bar"
expect resp.http.foo2 == "baz"
......@@ -101,15 +105,238 @@ logexpect l1 -v v1 -d 1 -g vxid -q "VCL_Error" {
expect 0 * Begin req
# due to calling barbaz.backref() before .match()
expect * = VCL_Error "^vmod re2 error: barbaz\.backref\(0, \"fallback\"\): backref called without prior match$"
expect * = VCL_Error "^vmod re2 error: backref 0, fallback .fallback.: backref called without prior match$"
# get the "out of range" error message even when the backref
# would have also failed due to failing prior match
expect * = VCL_Error "^vmod re2 error: frobnitz\.backref\(3, \"fallback3\"\): backref out of range \(max 3\)$"
expect * = VCL_Error "^vmod re2 error: frobnitz.backref.ref=3, fallback=.fallback3..: backref out of range .max 2.$"
expect * = VCL_Error "^vmod re2 error: never\.backref\(0, \"fallback0\"\): never_capture is true for object never$"
expect * = VCL_Error "^vmod re2 error: never\.backref\(1, \"fallback1\"\): never_capture is true for object never$"
expect * = VCL_Error "^vmod re2 error: never\.backref\(2, \"fallback2\"\): never_capture is true for object never$"
expect * = VCL_Error "^vmod re2 error: never.backref.ref=0, fallback=.fallback0..: never_capture is true for object never$"
expect * = VCL_Error "^vmod re2 error: never.backref.ref=1, fallback=.fallback1..: never_capture is true for object never$"
expect * = VCL_Error "^vmod re2 error: never.backref.ref=2, fallback=.fallback2..: never_capture is true for object never$"
expect * = End
} -run
# The same tests with named refs
server s1 -wait
server s1 -start
varnish v1 -vcl+backend {
import re2 from "${vmod_topbuild}/src/.libs/libvmod_re2.so";
sub vcl_init {
new frobnitz = re2.regex("(?P<frob>frob)(?P<nitz>nitz)");
new barbaz = re2.regex("(?P<bar>bar)(?P<baz>baz)");
new azbc = re2.regex("(?P<a>a|(?P<z>z))(?P<bc>bc)");
new never = re2.regex("(?P<bar>bar)(?P<baz>baz)",
never_capture=true);
}
sub vcl_recv {
return(pass);
}
sub vcl_deliver {
# Call to backref_named() before match()
set resp.http.nomatch = barbaz.backref_named("bar", "fallback");
if (frobnitz.match(resp.http.foo)) {
set resp.http.frob = "nitz";
}
set resp.http.frob1 = frobnitz.backref_named("frob",
"fallback1");
set resp.http.frob2 = frobnitz.backref_named("nitz",
"fallback2");
if (barbaz.match(resp.http.foo)) {
set resp.http.foo1 = barbaz.backref_named("bar",
"error1");
set resp.http.foo2 = barbaz.backref_named("baz",
"error2");
}
if (barbaz.match(resp.http.barf)) {
set resp.http.puke = "match";
}
set resp.http.barf1 = barbaz.backref_named("bar", "fallback1");
set resp.http.barf2 = barbaz.backref_named("baz", "fallback2");
if (azbc.match("abc")) {
set resp.http.abc1 = azbc.backref_named("a", "error1");
set resp.http.abc2 = azbc.backref_named("z", "none");
set resp.http.abc3 = azbc.backref_named("bc", "error3");
} else {
set resp.http.abc = "fail";
}
if (never.match(resp.http.foo)) {
set resp.http.never = "match";
}
set resp.http.never1 = never.backref_named("bar", "fallback1");
set resp.http.never2 = never.backref_named("baz", "fallback2");
}
}
logexpect l2 -v v1 -d 0 -g vxid -q "VCL_Error" {
expect 0 * Begin req
expect * = VCL_Error "^vmod re2 error: backref 1, fallback .fallback.: backref called without prior match$"
expect * = VCL_Error "^vmod re2 error: never.backref_named.name=.bar., fallback=.fallback1..: never_capture is true for object never$"
expect * = VCL_Error "^vmod re2 error: never.backref_named.name=.baz., fallback=.fallback2..: never_capture is true for object never$"
expect * = End
} -start
client c2 {
txreq
rxresp
expect resp.status == 200
expect resp.http.nomatch == "fallback"
expect resp.http.frob == <undef>
expect resp.http.frob1 == "fallback1"
expect resp.http.frob2 == "fallback2"
expect resp.http.foo1 == "bar"
expect resp.http.foo2 == "baz"
expect resp.http.puke == <undef>
expect resp.http.barf1 == "fallback1"
expect resp.http.barf2 == "fallback2"
expect resp.http.abc == <undef>
expect resp.http.abc1 == "a"
expect resp.http.abc2 == "none"
expect resp.http.abc3 == "bc"
expect resp.http.never == "match"
expect resp.http.never1 == "fallback1"
expect resp.http.never2 == "fallback2"
} -run
logexpect l2 -wait
# The same tests with the backref function
server s1 -wait
server s1 -start
varnish v1 -vcl+backend {
import re2 from "${vmod_topbuild}/src/.libs/libvmod_re2.so";
sub vcl_recv {
return(pass);
}
sub vcl_deliver {
set resp.http.nomatch = re2.backref(0, "fallback");
if (re2.match("(frob)(nitz)", resp.http.foo)) {
set resp.http.frob = "nitz";
}
set resp.http.frob0 = re2.backref(0, "fallback0");
set resp.http.frob1 = re2.backref(1, "fallback1");
set resp.http.frob2 = re2.backref(2, "fallback2");
set resp.http.frob3 = re2.backref(3, "fallback3");
if (re2.match("(bar)(baz)", resp.http.foo)) {
set resp.http.foo0 = re2.backref(0, "error0");
set resp.http.foo1 = re2.backref(1, "error1");
set resp.http.foo2 = re2.backref(2, "error2");
}
if (re2.match("(bar)(baz)", resp.http.barf)) {
set resp.http.puke = "match";
}
set resp.http.barf0 = re2.backref(0, "fallback0");
set resp.http.barf1 = re2.backref(1, "fallback1");
set resp.http.barf2 = re2.backref(2, "fallback2");
if (re2.match("(a|(z))(bc)", "abc")) {
set resp.http.abc1 = re2.backref(1, "error1");
set resp.http.abc2 = re2.backref(2, "none");
set resp.http.abc3 = re2.backref(3, "error3");
} else {
set resp.http.abc = "fail";
}
if (re2.match("(bar)(baz)", resp.http.foo,
never_capture=true)) {
set resp.http.never = "match";
}
set resp.http.never0 = re2.backref(0, "fallback0");
set resp.http.never1 = re2.backref(1, "fallback1");
set resp.http.never2 = re2.backref(2, "fallback2");
}
}
logexpect l3 -v v1 -d 0 -g vxid -q "VCL_Error" {
expect 0 * Begin req
expect * = VCL_Error "^vmod re2 error: re2.backref.ref=0, fallback=.fallback..: called without previous match$"
expect * = VCL_Error "^vmod re2 error: re2.backref.ref=3, fallback=.fallback3..: backref out of range .max 2.$"
expect * = VCL_Error "^vmod re2 error: re2.backref.ref=0, fallback=.fallback0..: never_capture was true in previous match$"
expect * = VCL_Error "^vmod re2 error: re2.backref.ref=1, fallback=.fallback1..: never_capture was true in previous match$"
expect * = VCL_Error "^vmod re2 error: re2.backref.ref=2, fallback=.fallback2..: never_capture was true in previous match$"
expect * = End
} -start
client c1 -run
logexpect l3 -wait
# The same tests with the namedref function
server s1 -wait
server s1 -start
varnish v1 -vcl+backend {
import re2 from "${vmod_topbuild}/src/.libs/libvmod_re2.so";
sub vcl_recv {
return(pass);
}
sub vcl_deliver {
set resp.http.nomatch = re2.namedref("bar", "fallback");
if (re2.match("(?P<frob>frob)(?P<nitz>nitz)", resp.http.foo)) {
set resp.http.frob = "nitz";
}
set resp.http.frob1 = re2.namedref("frob", "fallback1");
set resp.http.frob2 = re2.namedref("nitz", "fallback2");
if (re2.match("(?P<bar>bar)(?P<baz>baz)", resp.http.foo)) {
set resp.http.foo1 = re2.namedref("bar", "error1");
set resp.http.foo2 = re2.namedref("baz", "error2");
}
if (re2.match("(?P<bar>bar)(?P<baz>baz)", resp.http.barf)) {
set resp.http.puke = "match";
}
set resp.http.barf1 = re2.namedref("bar", "fallback1");
set resp.http.barf2 = re2.namedref("baz", "fallback2");
if (re2.match("(?P<a>a|(?P<z>z))(?P<bc>bc)", "abc")) {
set resp.http.abc1 = re2.namedref("a", "error1");
set resp.http.abc2 = re2.namedref("z", "none");
set resp.http.abc3 = re2.namedref("bc", "error3");
} else {
set resp.http.abc = "fail";
}
if (re2.match("(?P<bar>bar)(?P<baz>baz)", resp.http.foo,
never_capture=true)) {
set resp.http.never = "match";
}
set resp.http.never1 = re2.namedref("bar", "fallback1");
set resp.http.never2 = re2.namedref("baz", "fallback2");
}
}
logexpect l4 -v v1 -d 0 -g vxid -q "VCL_Error" {
expect 0 * Begin req
expect * = VCL_Error "^vmod re2 error: re2.namedref.name=.bar., fallback=.fallback..: called without previous match$"
expect * = VCL_Error "^vmod re2 error: re2.namedref.name=.bar., fallback=.fallback1..: never_capture was true in previous match$"
expect * = VCL_Error "^vmod re2 error: re2.namedref.name=.baz., fallback=.fallback2..: never_capture was true in previous match$"
expect * = End
} -start
client c2 -run
logexpect l4 -wait
......@@ -111,7 +111,77 @@ client c1 {
logexpect l1 -v v1 -d 1 -g vxid -q "VCL_Error" {
expect 0 * Begin req
expect * = VCL_Error "^vmod re2 error: elevendots\.backref\(12, \"fallback\"\): backref out of range \(max 11\)$"
expect * = VCL_Error "^vmod re2 error: twentydots\.backref\(21, \"error21\"\): backref out of range \(max 20\)$"
expect * = VCL_Error "^vmod re2 error: elevendots.backref.ref=12, fallback=.fallback..: backref out of range .max 11.$"
expect * = VCL_Error "^vmod re2 error: twentydots.backref.ref=21, fallback=.error21..: backref out of range .max 20.$"
expect * = End
} -run
varnish v1 -vcl {
import re2 from "${vmod_topbuild}/src/.libs/libvmod_re2.so";
backend b { .host = "${bad_ip}"; }
sub vcl_recv {
return(synth(200));
}
sub vcl_synth {
if (re2.match("(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)",
"123456789012")) {
set resp.http.foo0 = re2.backref(0, "error0");
set resp.http.foo1 = re2.backref(1, "error1");
set resp.http.foo2 = re2.backref(2, "error2");
set resp.http.foo3 = re2.backref(3, "error3");
set resp.http.foo4 = re2.backref(4, "error4");
set resp.http.foo5 = re2.backref(5, "error5");
set resp.http.foo6 = re2.backref(6, "error6");
set resp.http.foo7 = re2.backref(7, "error7");
set resp.http.foo8 = re2.backref(8, "error8");
set resp.http.foo9 = re2.backref(9, "error9");
set resp.http.foo10 = re2.backref(10, "error10");
set resp.http.foo11 = re2.backref(11, "error11");
set resp.http.foo12 = re2.backref(12, "fallback");
} else {
set resp.status = 999;
}
if (re2.match("(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)",
"123456789012345678901")) {
set resp.http.bar0 = re2.backref(0, "error0");
set resp.http.bar1 = re2.backref(1, "error1");
set resp.http.bar2 = re2.backref(2, "error2");
set resp.http.bar3 = re2.backref(3, "error3");
set resp.http.bar4 = re2.backref(4, "error4");
set resp.http.bar5 = re2.backref(5, "error5");
set resp.http.bar6 = re2.backref(6, "error6");
set resp.http.bar7 = re2.backref(7, "error7");
set resp.http.bar8 = re2.backref(8, "error8");
set resp.http.bar9 = re2.backref(9, "error9");
set resp.http.bar10 = re2.backref(10, "error10");
set resp.http.bar11 = re2.backref(11, "error11");
set resp.http.bar12 = re2.backref(12, "error12");
set resp.http.bar13 = re2.backref(13, "error13");
set resp.http.bar14 = re2.backref(14, "error14");
set resp.http.bar15 = re2.backref(15, "error15");
set resp.http.bar16 = re2.backref(16, "error16");
set resp.http.bar17 = re2.backref(17, "error17");
set resp.http.bar18 = re2.backref(18, "error18");
set resp.http.bar19 = re2.backref(19, "error19");
set resp.http.bar20 = re2.backref(20, "error20");
set resp.http.bar21 = re2.backref(21, "error21");
} else {
set resp.status = 999;
}
}
}
logexpect l2 -v v1 -d 0 -g vxid -q "VCL_Error" {
expect * * Begin req
expect * = VCL_Error "^vmod re2 error: re2.backref.ref=12, fallback=.fallback..: backref out of range .max 11.$"
expect * = VCL_Error "^vmod re2 error: re2.backref.ref=21, fallback=.error21..: backref out of range .max 20.$"
expect * = End
} -start
client c1 -run
logexpect l2 -wait
......@@ -37,7 +37,27 @@ varnish v1 -vcl {
set resp.http.neverquux
= never.backref_named("quux", "error_quux");
}
}
if (re2.match("(?P<bar>bar)(?P<baz>baz)", "barbaz")) {
set resp.http.num0f = re2.backref(0, "error0");
set resp.http.num1f = re2.backref(1, "error1");
set resp.http.num2f = re2.backref(2, "error2");
set resp.http.barf = re2.namedref("bar", "error_bar");
set resp.http.bazf = re2.namedref("baz", "error_baz");
set resp.http.quuxf
= re2.namedref("quux", "error_quux");
}
if (re2.match("(?P<bar>bar)(?P<baz>baz)", "barbaz",
never_capture=true)) {
set resp.http.neverf = "match";
set resp.http.neverbarf
= re2.namedref("bar", "error_bar");
set resp.http.neverbazf
= re2.namedref("baz", "error_baz");
set resp.http.neverquuxf
= re2.namedref("quux", "error_quux");
}
}
} -start
......@@ -54,13 +74,28 @@ client c1 {
expect resp.http.neverbar == "error_bar"
expect resp.http.neverbaz == "error_baz"
expect resp.http.neverquux == "error_quux"
expect resp.http.num0f == "barbaz"
expect resp.http.num1f == "bar"
expect resp.http.num2f == "baz"
expect resp.http.barf == "bar"
expect resp.http.bazf == "baz"
expect resp.http.quuxf == "error_quux"
expect resp.http.neverf == "match"
expect resp.http.neverbarf == "error_bar"
expect resp.http.neverbazf == "error_baz"
expect resp.http.neverquuxf == "error_quux"
} -run
logexpect l1 -v v1 -d 1 -g vxid -q "VCL_Error" {
expect 0 * Begin req
expect * = VCL_Error "^vmod re2 error: barbaz\.backref_named\(\"quux\", \"error_quux\"\): no such named group$"
expect * = VCL_Error "^vmod re2 error: never\.backref_named\(\"bar\", \"error_bar\"\): never_capture is true for object never$"
expect * = VCL_Error "^vmod re2 error: never\.backref_named\(\"baz\", \"error_baz\"\): never_capture is true for object never$"
expect * = VCL_Error "^vmod re2 error: never\.backref_named\(\"quux\", \"error_quux\"\): never_capture is true for object never$"
expect * = VCL_Error "^vmod re2 error: namedref name=.quux., fallback=.error_quux.: no such named group$"
expect * = VCL_Error "^vmod re2 error: never.backref_named.name=.bar., fallback=.error_bar..: never_capture is true for object never$"
expect * = VCL_Error "^vmod re2 error: never.backref_named.name=.baz., fallback=.error_baz..: never_capture is true for object never$"
expect * = VCL_Error "^vmod re2 error: never.backref_named.name=.quux., fallback=.error_quux..: never_capture is true for object never$"
expect * = VCL_Error "^vmod re2 error: namedref name=.quux., fallback=.error_quux.: no such named group$"
expect * = VCL_Error "^vmod re2 error: re2.namedref.name=.bar., fallback=.error_bar..: never_capture was true in previous match$"
expect * = VCL_Error "^vmod re2 error: re2.namedref.name=.baz., fallback=.error_baz..: never_capture was true in previous match$"
expect * = VCL_Error "^vmod re2 error: re2.namedref.name=.quux., fallback=.error_quux..: never_capture was true in previous match$"
expect * = End
} -run
......@@ -273,3 +273,165 @@ varnish v1 -vcl {
word_boundary=true);
}
}
# Function interface
varnish v1 -vcl {
import re2 from "${vmod_topbuild}/src/.libs/libvmod_re2.so";
backend b { .host = "${bad_ip}"; }
sub vcl_recv {
return(synth(200));
}
sub vcl_synth {
if (re2.match("(", "foo")) {
set resp.http.r1 = "match";
}
if (re2.match("a\1", "foo")) {
set resp.http.r2 = "match";
}
if (re2.match("a[x", "foo")) {
set resp.http.r3 = "match";
}
if (re2.match("a[z-a]", "foo")) {
set resp.http.r4 = "match";
}
if (re2.match("a[[:foobar:]]", "foo")) {
set resp.http.r5 = "match";
}
if (re2.match("a(b", "foo")) {
set resp.http.r6 = "match";
}
if (re2.match("a\", "foo")) { #"
set resp.http.r7 = "match";
}
if (re2.match("[a-b-c]", "a")) {
set resp.http.r8 = "match";
}
if (re2.match("[a-b-c]", "a", posix_syntax=true)) {
set resp.http.r9 = "match";
}
if (re2.match("\Qabc\E", "abc")) {
set resp.http.r10 = "match";
}
if (re2.match("\Qabc\E", "abc", posix_syntax=true)) {
set resp.http.r11 = "match";
}
if (re2.match("(?:a)", "a")) {
set resp.http.r12 = "match";
}
if (re2.match("(?:a)", "a", posix_syntax=true)) {
set resp.http.r13 = "match";
}
if (re2.match("(?P<name>a)", "a")) {
set resp.http.r14 = "match";
}
if (re2.match("(?P<name>a)", "a", posix_syntax=true)) {
set resp.http.r15 = "match";
}
if (re2.match("(a++)", "a", posix_syntax=true)) {
set resp.http.r16 = "match";
}
if (re2.match("(a++)", "a")) {
set resp.http.r17 = "match";
}
if (re2.match("(a**)", "a", posix_syntax=true)) {
set resp.http.r18 = "match";
}
if (re2.match("(a**)", "a")) {
set resp.http.r19 = "match";
}
if (re2.match("(a?*)", "a", posix_syntax=true)) {
set resp.http.r20 = "match";
}
if (re2.match("(a?*)", "a")) {
set resp.http.r21 = "match";
}
if (re2.match("(a+*)", "a", posix_syntax=true)) {
set resp.http.r22 = "match";
}
if (re2.match("(a+*)", "a")) {
set resp.http.r23 = "match";
}
if (re2.match("(a{1}*)", "a", posix_syntax=true)) {
set resp.http.r24 = "match";
}
if (re2.match("(a{1}*)", "a")) {
set resp.http.r25 = "match";
}
if (re2.match("\d \s \w \D \S \W", "0 a a a !",
posix_syntax=true)) {
set resp.http.r26 = "match";
}
if (re2.match("\d \s \w \D \S \W", "0 a a a !",
posix_syntax=true, perl_classes=true)) {
set resp.http.r27 = "match";
}
if (re2.match("\ba \B", "a ", posix_syntax=true)) {
set resp.http.r28 = "match";
}
if (re2.match("\ba \B", "a ", posix_syntax=true,
word_boundary=true)) {
set resp.http.r29 = "match";
}
}
}
client c1 {
txreq
rxresp
expect resp.status == 200
expect resp.http.r1 == <undef>
expect resp.http.r2 == <undef>
expect resp.http.r3 == <undef>
expect resp.http.r4 == <undef>
expect resp.http.r5 == <undef>
expect resp.http.r6 == <undef>
expect resp.http.r7 == <undef>
expect resp.http.r8 == "match"
expect resp.http.r9 == <undef>
expect resp.http.r10 == "match"
expect resp.http.r11 == <undef>
expect resp.http.r12 == "match"
expect resp.http.r13 == <undef>
expect resp.http.r14 == "match"
expect resp.http.r15 == <undef>
expect resp.http.r16 == "match"
expect resp.http.r17 == <undef>
expect resp.http.r18 == "match"
expect resp.http.r19 == <undef>
expect resp.http.r20 == "match"
expect resp.http.r21 == <undef>
expect resp.http.r22 == "match"
expect resp.http.r23 == <undef>
expect resp.http.r24 == "match"
expect resp.http.r25 == <undef>
expect resp.http.r26 == <undef>
expect resp.http.r27 == "match"
expect resp.http.r28 == <undef>
expect resp.http.r29 == "match"
} -run
logexpect l1 -v v1 -d 1 -g vxid -q "VCL_Error" {
expect 0 * Begin req
expect * = VCL_Error "^vmod re2 error: re2.match.pattern=..., text=.foo..: Cannot compile: missing .: .$"
expect * = VCL_Error "^vmod re2 error: re2.match.pattern=.a.1., text=.foo..: Cannot compile: invalid escape sequence: .1$"
expect * = VCL_Error "^vmod re2 error: re2.match.pattern=.a.x., text=.foo..: Cannot compile: missing .: .x$"
expect * = VCL_Error "^vmod re2 error: re2.match.pattern=.a.z-a.., text=.foo..: Cannot compile: invalid character class range: z-a$"
expect * = VCL_Error "^vmod re2 error: re2.match.pattern=.a..:foobar:..., text=.foo..: Cannot compile: invalid character class range: .:foobar:.$"
expect * = VCL_Error "^vmod re2 error: re2.match.pattern=.a.b., text=.foo..: Cannot compile: missing .: a.b$"
expect * = VCL_Error "^vmod re2 error: re2.match.pattern=.a.., text=.foo..: Cannot compile: trailing .$"
expect * = VCL_Error "^vmod re2 error: re2.match.pattern=..a-b-c.., text=.a..: Cannot compile: invalid character class range: -c$"
expect * = VCL_Error "^vmod re2 error: re2.match.pattern=..Qabc.E., text=.abc..: Cannot compile: invalid escape sequence: .Q$"
expect * = VCL_Error "^vmod re2 error: re2.match.pattern=...:a.., text=.a..: Cannot compile: no argument for repetition operator: .$"
expect * = VCL_Error "^vmod re2 error: re2.match.pattern=...P<name>a.., text=.a..: Cannot compile: no argument for repetition operator: .$"
expect * = VCL_Error "^vmod re2 error: re2.match.pattern=..a...., text=.a..: Cannot compile: bad repetition operator: ..$"
expect * = VCL_Error "^vmod re2 error: re2.match.pattern=..a...., text=.a..: Cannot compile: bad repetition operator: ..$"
expect * = VCL_Error "^vmod re2 error: re2.match.pattern=..a...., text=.a..: Cannot compile: bad repetition operator: ..$"
expect * = VCL_Error "^vmod re2 error: re2.match.pattern=..a...., text=.a..: Cannot compile: bad repetition operator: ..$"
expect * = VCL_Error "^vmod re2 error: re2.match.pattern=..a.1...., text=.a..: Cannot compile: bad repetition operator: .1..$"
expect * = VCL_Error "^vmod re2 error: re2.match.pattern=..d .s .w .D .S .W., text=.0 a a a !..: Cannot compile: invalid escape sequence: .d$"
expect * = VCL_Error "^vmod re2 error: re2.match.pattern=..ba .B., text=.a ..: Cannot compile: invalid escape sequence: .b$"
expect * = End
} -run
......@@ -51,6 +51,46 @@ varnish v1 -vcl {
if (patternchars.match({"日扼語"})) {
set resp.http.patternchars = "match";
}
# Function interface
if (re2.match("^.........$",
{"日扼語"})) {
set resp.http.ninebytesf = "match";
}
if (re2.match("^...$",
{"日扼語"},
utf8=true)) {
set resp.http.threecharsf = "match";
}
if (re2.match("(.)",{"日扼語"})) {
if (re2.backref(1) == {""}) {
set resp.http.captured_one_bytef = "true";
}
}
if (re2.match("(.)",
{"日扼語"},
utf8=true)) {
if (re2.backref(1) == {"日"}) {
set resp.http.captured_one_charf = "true";
}
}
if (re2.match({"日扼語"},
{"日扼語"})) {
set resp.http.bytesf = "match";
}
if (re2.match({"日扼語"},
{"日扼語"})) {
set resp.http.charsf = "match";
}
if (re2.match({"^.扼.$"},
{"日扼語"})) {
set resp.http.patternbytesf = "match";
}
if (re2.match({"^.扼.$"},
{"日扼語"},
utf8=true)) {
set resp.http.patterncharsf = "match";
}
}
} -start
......@@ -66,4 +106,13 @@ client c1 {
expect resp.http.chars == "match"
expect resp.http.patternbytes == <undef>
expect resp.http.patternchars == "match"
expect resp.http.ninebytesf == "match"
expect resp.http.threecharsf == "match"
expect resp.http.captured_one_bytef == "true"
expect resp.http.captured_one_charf == "true"
expect resp.http.bytesf == "match"
expect resp.http.charsf == "match"
expect resp.http.patternbytesf == <undef>
expect resp.http.patterncharsf == "match"
} -run
# looks like -*- vcl -*-
varnishtest "regexp match and no-match (cf. varnish b00028.vtc & v00016.vtc)"
varnishtest "regexp match and no-match (cf. varnish b00028.vtc)"
server s1 {
rxreq
......@@ -11,21 +11,9 @@ varnish v1 -vcl+backend {
import re2 from "${vmod_topbuild}/src/.libs/libvmod_re2.so";
sub vcl_init {
new foobar = re2.regex("foobar");
new snafu = re2.regex("snafu");
new bar = re2.regex("bar");
}
sub vcl_recv {
if (foobar.match(req.url)) {
return(pass);
} else if (snafu.match(req.url)) {
return(pipe);
} else {
return(pass);
}
}
sub vcl_backend_response {
if (bar.match(beresp.http.foo)) {
set beresp.http.foo1 = "1";
......@@ -38,6 +26,18 @@ varnish v1 -vcl+backend {
} else {
set beresp.status = 999;
}
if (re2.match("bar", beresp.http.foo)) {
set beresp.http.foo1f = "1";
} else {
set beresp.status = 999;
}
if (!re2.match("bar", beresp.http.bar)) {
set beresp.http.bar1f = "2";
} else {
set beresp.status = 999;
}
}
} -start
......@@ -48,4 +48,6 @@ client c1 {
expect resp.status == "200"
expect resp.http.foo1 == "1"
expect resp.http.bar1 == "2"
expect resp.http.foo1f == "1"
expect resp.http.bar1f == "2"
} -run
......@@ -35,4 +35,35 @@ varnish v1 -errvcl {vmod re2 error: Cannot compile '.{1000}x' in rep constructor
sub vcl_init {
new rep = re2.regex(".{1000}x", max_mem=1024);
}
}
\ No newline at end of file
}
varnish v1 -vcl {
import re2 from "${vmod_topbuild}/src/.libs/libvmod_re2.so";
backend b { .host = "${bad_ip}"; }
sub vcl_recv {
return(synth(200));
}
sub vcl_synth {
if (re2.match(".{1000}x", "ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccx")) {
set resp.http.rep = "match";
}
if (re2.match(".{1000}x", "ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccx", max_mem=1024)) {
set resp.http.repmem = "match";
}
}
}
client c1 {
txreq
rxresp
expect resp.http.rep == "match"
expect resp.http.repmem == <undef>
} -run
logexpect l1 -v v1 -d 1 -g vxid -q "VCL_Error" {
expect 0 * Begin req
expect * = VCL_Error "^vmod re2 error: re2.match.pattern=...1000.x., text=.c+"
expect * = End
} -run
......@@ -22,6 +22,13 @@ varnish v1 -vcl+backend {
} else {
set beresp.status = 999;
}
if (re2.match("(?:bar)(baz)", beresp.http.foo)) {
set beresp.http.foo0f = re2.backref(0, "error0");
set beresp.http.foo1f = re2.backref(1, "error1");
set beresp.http.foo2f = re2.backref(2, "fallback");
} else {
set beresp.status = 999;
}
}
} -start
......@@ -32,11 +39,14 @@ client c1 {
expect resp.http.foo0 == "barbaz"
expect resp.http.foo1 == "baz"
expect resp.http.foo2 == "fallback"
expect resp.http.foo0f == "barbaz"
expect resp.http.foo1f == "baz"
expect resp.http.foo2f == "fallback"
} -run
logexpect l1 -v v1 -d 1 -g vxid -q "VCL_Error" {
expect 0 * Begin req
# due to calling barbaz.backref() before .match()
expect * = VCL_Error "^vmod re2 error: barbaz\.backref\(2, \"fallback\"\): backref out of range \(max 1\)$"
expect * = VCL_Error "^vmod re2 error: barbaz.backref.ref=2, fallback=.fallback..: backref out of range .max 1.$"
expect * = VCL_Error "^vmod re2 error: re2.backref.ref=2, fallback=.fallback..: backref out of range .max 1.$"
expect * = End
} -run
......@@ -108,3 +108,80 @@ client c1 {
expect resp.http.not_one == "match"
expect resp.http.one == <undef>
} -run
# Function interface
varnish v1 -vcl {
import re2 from "${vmod_topbuild}/src/.libs/libvmod_re2.so";
backend b { .host = "${bad_ip}"; }
sub vcl_recv {
return(synth(200));
}
sub vcl_synth {
if (re2.match("(|)^$.[*+?]{5,10},\\", "(|)^$.[*+?]{5,10},\\",
literal=true)) {
set resp.http.literal = "match";
}
if (re2.match(pattern="(.*)", never_nl=true, subject={"abc
def
ghi
"} )) {
set resp.http.never1 = "match";
set resp.http.never11 = re2.backref(1);
}
if (re2.match("(?s)(abc.*def)", {"abc
def
"}, never_nl=true)) {
set resp.http.never2 = "match";
}
if (re2.match(pattern={"(abc(.|
)def)"}, never_nl=true, subject={"abc
def
"}, )) {
set resp.http.never3 = "match";
}
if (re2.match("(abc[^x]*def)", {"abc
def
"}, never_nl=true)) {
set resp.http.never4 = "match";
}
if (re2.match("(abc[^x]*def)", {"abczzzdef
def
"}, never_nl=true)) {
set resp.http.never5 = "match";
set resp.http.never51 = re2.backref(1);
}
if (re2.match(pattern=".", dot_nl=true, subject={"
"} )) {
set resp.http.dot1 = "match";
}
if (re2.match(pattern="(?-s).", dot_nl=true, subject={"
"} )) {
set resp.http.dot2 = "match";
}
if (re2.match(".", {"
"}, dot_nl=true, never_nl=true)) {
set resp.http.dot3 = "match";
}
if (re2.match("(?i)([wand]{5})", "A fish named *Wanda*",
case_sensitive=true)) {
set resp.http.case = "match";
set resp.http.case1 = re2.backref(1);
}
if (re2.match(pattern="^a$", posix_syntax=true, subject={"a
a
a"} )) {
set resp.http.not_one = "match";
}
if (re2.match(pattern="^a$", posix_syntax=true, subject={"a
a
a"}, one_line=true)) {
set resp.http.one = "match";
}
}
}
client c1 -run
......@@ -18,6 +18,10 @@ varnish v1 -vcl+backend {
if (longregex.match(req.http.host)) {
return(synth(500, "not ok"));
}
if (re2.match("^(abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij)",
req.http.host)) {
return(synth(500, "not ok"));
}
}
} -start
......
......@@ -22,6 +22,12 @@ varnish v1 -vcl+backend {
if (empty.match(beresp.http.foo)) {
set beresp.http.bar = "YYY";
}
if (re2.match("$", beresp.http.bar)) {
set beresp.http.foof = "XXX";
}
if (re2.match("", beresp.http.foo)) {
set beresp.http.barf = "YYY";
}
}
} -start
......@@ -31,4 +37,6 @@ client c1 {
expect resp.status == 200
expect resp.http.foo == "XXX"
expect resp.http.bar == "YYY"
expect resp.http.foof == "XXX"
expect resp.http.barf == "YYY"
} -run
......@@ -2,46 +2,47 @@
varnishtest "re2.backref not affected by standard VCL regex code"
server s1 {
rxreq
txresp -hdr "Foo: barbaz" -body "1111\n"
} -start
varnish v1 -vcl+backend {
import re2 from "${vmod_topbuild}/src/.libs/libvmod_re2.so";
backend b { .host = "${bad_ip}"; }
sub vcl_init {
new barbaz = re2.regex("(bar)baz");
}
sub vcl_backend_response {
if (!barbaz.match(beresp.http.foo)) {
set beresp.status = 999;
sub vcl_recv {
return(synth(200));
}
sub vcl_synth {
set resp.http.foo = "barbaz";
if (!barbaz.match(resp.http.foo)) {
set resp.status = 999;
}
if (beresp.http.foo ~ "bar(baz)") {
set beresp.http.tilde0 = barbaz.backref(0, "tilde0");
set beresp.http.tilde1 = barbaz.backref(1, "tilde1");
if (resp.http.foo ~ "bar(baz)") {
set resp.http.tilde0 = barbaz.backref(0, "tilde0");
set resp.http.tilde1 = barbaz.backref(1, "tilde1");
} else {
set beresp.status = 999;
set resp.status = 999;
}
if (beresp.http.foo !~ "bar(quux)") {
set beresp.http.neg0 = barbaz.backref(0, "neg0");
set beresp.http.neg1 = barbaz.backref(1, "neg1");
if (resp.http.foo !~ "bar(quux)") {
set resp.http.neg0 = barbaz.backref(0, "neg0");
set resp.http.neg1 = barbaz.backref(1, "neg1");
} else {
set beresp.status = 999;
set resp.status = 999;
}
set beresp.http.regsub
= regsub(beresp.http.foo, "bar(baz)", "\1");
set beresp.http.regsub0 = barbaz.backref(0, "regsub0");
set beresp.http.regsub1 = barbaz.backref(1, "regsub1");
set resp.http.regsub
= regsub(resp.http.foo, "bar(baz)", "\1");
set resp.http.regsub0 = barbaz.backref(0, "regsub0");
set resp.http.regsub1 = barbaz.backref(1, "regsub1");
set beresp.http.regsuball
= regsuball(beresp.http.foo, "(.)", "x");
set beresp.http.regsuball0 = barbaz.backref(0, "regsuball0");
set beresp.http.regsuball1 = barbaz.backref(1, "regsuball1");
set resp.http.regsuball
= regsuball(resp.http.foo, "(.)", "x");
set resp.http.regsuball0 = barbaz.backref(0, "regsuball0");
set resp.http.regsuball1 = barbaz.backref(1, "regsuball1");
}
} -start
......@@ -61,3 +62,48 @@ client c1 {
expect resp.http.regsuball0 == "barbaz"
expect resp.http.regsuball1 == "bar"
} -run
# Function interface
varnish v1 -vcl+backend {
import re2 from "${vmod_topbuild}/src/.libs/libvmod_re2.so";
backend b { .host = "${bad_ip}"; }
sub vcl_recv {
return(synth(200));
}
sub vcl_synth {
set resp.http.foo = "barbaz";
if (!re2.match("(bar)baz", resp.http.foo)) {
set resp.status = 999;
}
if (resp.http.foo ~ "bar(baz)") {
set resp.http.tilde0 = re2.backref(0, "tilde0");
set resp.http.tilde1 = re2.backref(1, "tilde1");
} else {
set resp.status = 999;
}
if (resp.http.foo !~ "bar(quux)") {
set resp.http.neg0 = re2.backref(0, "neg0");
set resp.http.neg1 = re2.backref(1, "neg1");
} else {
set resp.status = 999;
}
set resp.http.regsub
= regsub(resp.http.foo, "bar(baz)", "\1");
set resp.http.regsub0 = re2.backref(0, "regsub0");
set resp.http.regsub1 = re2.backref(1, "regsub1");
set resp.http.regsuball
= regsuball(resp.http.foo, "(.)", "x");
set resp.http.regsuball0 = re2.backref(0, "regsuball0");
set resp.http.regsuball1 = re2.backref(1, "regsuball1");
}
}
client c1 -run
......@@ -58,6 +58,15 @@ struct vmod_re2_regex {
unsigned never_capture;
};
typedef struct task_match_t {
unsigned magic;
#define TASK_MATCH_MAGIC 0xa4b93c57
vre2 *vre2;
void *groups;
int ngroups;
unsigned never_capture;
} task_match_t;
static char c;
static const void *match_failed = (void *) &c;
......@@ -89,32 +98,95 @@ init_matchsz(void)
match_sz = vre2_matchsz();
}
#define ERR_PREFIX "%s backref %ld, fallback \"%s\": "
static void
free_task_match(void *p)
{
task_match_t *task_match;
CAST_OBJ_NOTNULL(task_match, p, TASK_MATCH_MAGIC);
if (task_match->vre2 != NULL)
vre2_fini(&task_match->vre2);
FREE_OBJ(task_match);
}
#define ERR_PREFIX "match(\"%s\"): "
static VCL_BOOL
match(VRT_CTX, vre2 * restrict vre2, VCL_STRING restrict subject,
void * restrict * const groups, const unsigned never_capture,
int ngroups)
{
int match = 0, len;
const char *err;
char *text = (void *) subject;
AN(groups);
if (subject == NULL)
subject = "";
len = strlen(subject);
*groups = NULL;
if (!never_capture) {
ngroups++;
if ((text = WS_Copy(ctx->ws, subject, len + 1)) == NULL) {
VERR(ctx, ERR_PREFIX "insufficient workspace to copy "
"subject", subject);
return 0;
}
if ((*groups = WS_Alloc(ctx->ws, ngroups * match_sz))
== NULL) {
VERR(ctx, ERR_PREFIX "insufficient workspace to "
"allocate match data", subject);
WS_Reset(ctx->ws, text);
return 0;
}
}
if ((err = vre2_match(vre2, text, len, &match, ngroups, *groups))
!= NULL) {
VERR(ctx, ERR_PREFIX "%s", subject, err);
if (!never_capture)
WS_Reset(ctx->ws, text);
return 0;
}
if (!never_capture && !match)
WS_Reset(ctx->ws, text);
return match;
}
#undef ERR_PREFIX
static inline void
WS_Contains(struct ws * const restrict ws, const void * const restrict ptr,
const size_t len)
{
assert((char *)ptr >= ws->s && (char *)(ptr + len) <= ws->e);
}
#define ERR_PREFIX "backref %ld, fallback \"%s\": "
static VCL_STRING
backref(VRT_CTX, struct vmod_re2_regex *re, VCL_INT refnum, VCL_STRING fallback)
backref(VRT_CTX, VCL_INT refnum, VCL_STRING fallback, void * const groups,
const int ngroups)
{
void *group;
const char *err, *capture;
char *backref;
int len;
group = pthread_getspecific(re->matchk);
if (group == NULL) {
if (groups == NULL) {
VERR(ctx, ERR_PREFIX "backref called without prior match",
re->vcl_name, refnum, fallback);
refnum, fallback);
return fallback;
}
if (group == match_failed)
if (groups == match_failed)
return fallback;
assert((char *)group >= ctx->ws->s
&& (char *)(group + ((re->ngroups+1) * match_sz)) <= ctx->ws->e);
WS_Contains(ctx->ws, groups, (ngroups + 1) * match_sz);
if ((err = vre2_capture(group, (int) refnum, &capture, &len))
if ((err = vre2_capture(groups, (int) refnum, &capture, &len))
!= NULL) {
VERR(ctx, ERR_PREFIX "error retrieving capture: %s",
re->vcl_name, refnum, fallback, err);
VERR(ctx, ERR_PREFIX "error retrieving capture: %s", refnum,
fallback, err);
return fallback;
}
......@@ -123,9 +195,11 @@ backref(VRT_CTX, struct vmod_re2_regex *re, VCL_INT refnum, VCL_STRING fallback)
return fallback;
if (len == 0)
return "";
WS_Contains(ctx->ws, capture, len);
if ((backref = WS_Copy(ctx->ws, capture, len + 1)) == NULL) {
VERR(ctx, ERR_PREFIX "insufficient workspace for backref",
re->vcl_name, refnum, fallback);
refnum, fallback);
return fallback;
}
backref[len] = '\0';
......@@ -134,6 +208,29 @@ backref(VRT_CTX, struct vmod_re2_regex *re, VCL_INT refnum, VCL_STRING fallback)
#undef ERR_PREFIX
#define ERR_PREFIX "namedref name=\"%s\", fallback=\"%s\": "
static VCL_STRING
namedref(VRT_CTX, vre2 * restrict vre2, VCL_STRING name, VCL_STRING fallback,
void * const restrict groups, const int ngroups)
{
int refnum;
const char *err;
if ((err = vre2_get_group(vre2, name, &refnum)) != NULL) {
VERR(ctx, ERR_PREFIX "%s", name, fallback, err);
return fallback;
}
if (refnum == -1) {
VERR(ctx, ERR_PREFIX "no such named group", name, fallback);
return fallback;
}
assert(refnum > 0 && refnum <= ngroups);
return backref(ctx, refnum, fallback, groups, ngroups);
}
#undef ERR_PREFIX
VCL_VOID
vmod_regex__init(const struct vrt_ctx *ctx, struct vmod_re2_regex **rep,
const char *vcl_name, VCL_STRING pattern, VCL_BOOL utf8,
......@@ -198,60 +295,30 @@ VCL_BOOL
vmod_regex_match(const struct vrt_ctx *ctx, struct vmod_re2_regex *re,
VCL_STRING subject)
{
int match = 0, ngroups = 0, len;
const char *err;
char *text = (void *) subject;
void *group = NULL;
VCL_BOOL ret;
void *groups;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(re, VMOD_RE2_REGEX_MAGIC);
if (subject == NULL)
subject = "";
AZ(pthread_setspecific(re->matchk, match_failed));
len = strlen(subject);
if (! re->never_capture) {
ngroups = re->ngroups + 1;
if ((text = WS_Copy(ctx->ws, subject, len + 1)) == NULL) {
VERR(ctx, ERR_PREFIX "insufficient workspace to copy "
"subject", re->vcl_name, subject);
return 0;
}
if ((group = WS_Alloc(ctx->ws, ngroups * match_sz))
== NULL) {
VERR(ctx, ERR_PREFIX "insufficient workspace to "
"allocate match data", re->vcl_name, subject);
WS_Reset(ctx->ws, text);
return 0;
}
}
if ((err = vre2_match(re->vre2, text, len, &match, ngroups, group))
!= NULL) {
VERR(ctx, ERR_PREFIX "%s", re->vcl_name, subject, err);
WS_Reset(ctx->ws, text);
return 0;
}
if (! re->never_capture) {
if (match)
AZ(pthread_setspecific(re->matchk, group));
else
WS_Reset(ctx->ws, text);
}
return match;
ret = match(ctx, re->vre2, subject, &groups, re->never_capture,
re->ngroups);
if (ret && !re->never_capture)
AZ(pthread_setspecific(re->matchk, groups));
return ret;
}
#undef ERR_PREFIX
#define ERR_PREFIX "%s.backref(%ld, \"%s\"): "
#define ERR_PREFIX "%s.backref(ref=%ld, fallback=\"%s\"): "
VCL_STRING
vmod_regex_backref(VRT_CTX, struct vmod_re2_regex *re, VCL_INT refnum,
VCL_STRING fallback)
{
void *groups;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(re, VMOD_RE2_REGEX_MAGIC);
assert(refnum >= 0);
......@@ -268,43 +335,165 @@ vmod_regex_backref(VRT_CTX, struct vmod_re2_regex *re, VCL_INT refnum,
re->vcl_name, refnum, fallback, re->ngroups);
return fallback;
}
return backref(ctx, re, refnum, fallback);
groups = pthread_getspecific(re->matchk);
return backref(ctx, refnum, fallback, groups, re->ngroups);
}
#undef ERR_PREFIX
#define ERR_PREFIX "%s.backref_named(\"%s\", \"%s\"): "
#define ERR_PREFIX "%s.backref_named(name=\"%s\", fallback=\"%s\"): "
VCL_STRING
vmod_regex_backref_named(VRT_CTX, struct vmod_re2_regex *re, VCL_STRING name,
VCL_STRING fallback)
{
int refnum;
const char *err;
void *groups;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(re, VMOD_RE2_REGEX_MAGIC);
if (name == NULL)
name = "";
if (fallback == NULL)
fallback = "";
if (name == NULL || name[0] == '\0') {
VERR(ctx, ERR_PREFIX "name is empty", re->vcl_name, "",
fallback);
return fallback;
}
if (re->never_capture) {
VERR(ctx, ERR_PREFIX "never_capture is true for object %s",
re->vcl_name, name, fallback, re->vcl_name);
return fallback;
}
if ((err = vre2_get_group(re->vre2, name, &refnum)) != NULL) {
VERR(ctx, ERR_PREFIX "%s", re->vcl_name, name, fallback, err);
return fallback;
}
if (refnum == -1) {
VERR(ctx, ERR_PREFIX "no such named group", re->vcl_name, name,
groups = pthread_getspecific(re->matchk);
return namedref(ctx, re->vre2, name, fallback, groups, re->ngroups);
}
#undef ERR_PREFIX
#define ERR_PREFIX "re2.match(pattern=\"%s\", text=\"%s\"): "
VCL_BOOL
vmod_match(VRT_CTX, struct vmod_priv *priv, VCL_STRING pattern,
VCL_STRING subject, VCL_BOOL utf8, VCL_BOOL posix_syntax,
VCL_BOOL longest_match, VCL_INT max_mem, VCL_BOOL literal,
VCL_BOOL never_nl, VCL_BOOL dot_nl, VCL_BOOL never_capture,
VCL_BOOL case_sensitive, VCL_BOOL perl_classes,
VCL_BOOL word_boundary, VCL_BOOL one_line)
{
vre2 *vre2 = NULL;
task_match_t *task_match;
const char *err;
void *groups = NULL, **groupsp = &groups;
int ngroups = 0;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
if (pattern == NULL)
pattern = "";
if ((err = vre2_init(&vre2, pattern, utf8, posix_syntax, longest_match,
max_mem, literal, never_nl, dot_nl, never_capture,
case_sensitive, perl_classes, word_boundary,
one_line))
!= NULL) {
VERR(ctx, ERR_PREFIX "Cannot compile: %s", pattern, subject,
err);
vre2_fini(&vre2);
return 0;
}
if (! never_capture) {
if ((err = vre2_ngroups(vre2, &ngroups)) != NULL) {
VERR(ctx, "Cannot obtain number of capturing groups: "
"%s", pattern, subject, err);
return 0;
}
assert(ngroups >= 0);
}
if (priv->priv == NULL) {
ALLOC_OBJ(task_match, TASK_MATCH_MAGIC);
AN(task_match);
priv->priv = task_match;
priv->free = free_task_match;
}
else
CAST_OBJ(task_match, priv->priv, TASK_MATCH_MAGIC);
task_match->ngroups = ngroups;
task_match->never_capture = never_capture;
task_match->vre2 = vre2;
groupsp = &task_match->groups;
return match(ctx, vre2, subject, groupsp, never_capture, ngroups);
}
#undef ERR_PREFIX
#define ERR_PREFIX "re2.backref(ref=%ld, fallback=\"%s\"): "
VCL_STRING
vmod_backref(VRT_CTX, struct vmod_priv *priv, VCL_INT refnum,
VCL_STRING fallback)
{
task_match_t *task_match;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
AN(priv);
assert(refnum >= 0);
if (fallback == NULL)
fallback = "";
if (priv->priv == NULL) {
VERR(ctx, ERR_PREFIX "called without previous match", refnum,
fallback);
return fallback;
}
assert(refnum > 0 && refnum <= re->ngroups);
return backref(ctx, re, refnum, fallback);
return fallback;
}
CAST_OBJ(task_match, priv->priv, TASK_MATCH_MAGIC);
if (task_match->never_capture) {
VERR(ctx, ERR_PREFIX "never_capture was true in previous match",
refnum, fallback);
return fallback;
}
if (refnum > task_match->ngroups) {
VERR(ctx, ERR_PREFIX "backref out of range (max %d)", refnum,
fallback, task_match->ngroups);
return fallback;
}
return backref(ctx, refnum, fallback, task_match->groups,
task_match->ngroups);
}
#undef ERR_PREFIX
#define ERR_PREFIX "re2.namedref(name=\"%s\", fallback=\"%s\"): "
VCL_STRING
vmod_namedref(VRT_CTX, struct vmod_priv *priv, VCL_STRING name,
VCL_STRING fallback)
{
task_match_t *task_match;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
AN(priv);
if (fallback == NULL)
fallback = "";
if (name == NULL || name[0] == '\0') {
VERR(ctx, ERR_PREFIX "name is empty", "", fallback);
return fallback;
}
if (priv->priv == NULL) {
VERR(ctx, ERR_PREFIX "called without previous match", name,
fallback);
return fallback;
}
CAST_OBJ(task_match, priv->priv, TASK_MATCH_MAGIC);
if (task_match->never_capture) {
VERR(ctx, ERR_PREFIX "never_capture was true in previous match",
name, fallback);
return fallback;
}
return namedref(ctx, task_match->vre2, name, fallback,
task_match->groups, task_match->ngroups);
}
#undef ERR_PREFIX
......
......@@ -22,4 +22,17 @@ $Method STRING .backref(INT ref, STRING fallback = "**BACKREF FAILED**")
$Method STRING .backref_named(STRING name,
STRING fallback = "**BACKREF FAILED**")
$Function BOOL match(PRIV_TASK, STRING pattern, STRING subject, BOOL utf8=0,
BOOL posix_syntax=0, BOOL longest_match=0,
INT max_mem=8388608, BOOL literal=0, BOOL never_nl=0,
BOOL dot_nl=0, BOOL never_capture=0,
BOOL case_sensitive=1, BOOL perl_classes=0,
BOOL word_boundary=0, BOOL one_line=0)
$Function STRING backref(PRIV_TASK, INT ref,
STRING fallback = "**BACKREF FUNCTION FAILED**")
$Function STRING namedref(PRIV_TASK, STRING name,
STRING fallback = "**NAMEDREF FUNCTION FAILED**")
$Function STRING version()
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