Commit f1bb0147 authored by Geoff Simmons's avatar Geoff Simmons

Add the backref() function.

There's still a bit of code repetition to be factored out.
parent 4b9b68b0
Pipeline #244 skipped
...@@ -39,6 +39,7 @@ CONTENTS ...@@ -39,6 +39,7 @@ CONTENTS
* regex(STRING, BOOL, BOOL, ENUM {ANYCRLF,UNICODE}, BOOL, BOOL, BOOL, BOOL, BOOL, BOOL, BOOL, BOOL, BOOL, STRING, BOOL, INT, BOOL, BOOL, BOOL, BOOL, ENUM {CR,LF,CRLF,ANYCRLF,ANY}, BOOL, BOOL, BOOL, BOOL, BOOL, INT, BOOL, BOOL, BOOL, BOOL) * regex(STRING, BOOL, BOOL, ENUM {ANYCRLF,UNICODE}, BOOL, BOOL, BOOL, BOOL, BOOL, BOOL, BOOL, BOOL, BOOL, STRING, BOOL, INT, BOOL, BOOL, BOOL, BOOL, ENUM {CR,LF,CRLF,ANYCRLF,ANY}, BOOL, BOOL, BOOL, BOOL, BOOL, INT, BOOL, BOOL, BOOL, BOOL)
* BOOL match(PRIV_CALL, PRIV_TASK, STRING, STRING, BOOL, BOOL, ENUM {ANYCRLF,UNICODE}, BOOL, BOOL, BOOL, BOOL, BOOL, BOOL, BOOL, BOOL, BOOL, STRING, BOOL, INT, BOOL, BOOL, BOOL, BOOL, ENUM {CR,LF,CRLF,ANYCRLF,ANY}, BOOL, BOOL, BOOL, BOOL, BOOL, INT, BOOL, BOOL, BOOL, BOOL, INT, INT, INT, BOOL, BOOL, BOOL, BOOL, BOOL, ENUM {HARD,SOFT}, INT) * BOOL match(PRIV_CALL, PRIV_TASK, STRING, STRING, BOOL, BOOL, ENUM {ANYCRLF,UNICODE}, BOOL, BOOL, BOOL, BOOL, BOOL, BOOL, BOOL, BOOL, BOOL, STRING, BOOL, INT, BOOL, BOOL, BOOL, BOOL, ENUM {CR,LF,CRLF,ANYCRLF,ANY}, BOOL, BOOL, BOOL, BOOL, BOOL, INT, BOOL, BOOL, BOOL, BOOL, INT, INT, INT, BOOL, BOOL, BOOL, BOOL, BOOL, ENUM {HARD,SOFT}, INT)
* STRING backref(PRIV_TASK, INT, STRING)
* BOOL config_bool(ENUM {JIT,STACKRECURSE,UNICODE}) * BOOL config_bool(ENUM {JIT,STACKRECURSE,UNICODE})
* STRING config_str(ENUM {BSR,JITTARGET,NEWLINE,UNICODE_VERSION,VERSION}) * STRING config_str(ENUM {BSR,JITTARGET,NEWLINE,UNICODE_VERSION,VERSION})
* INT config_int(ENUM {LINKSIZE,MATCHLIMIT,PARENSLIMIT,RECURSIONLIMIT}) * INT config_int(ENUM {LINKSIZE,MATCHLIMIT,PARENSLIMIT,RECURSIONLIMIT})
...@@ -91,6 +92,15 @@ match ...@@ -91,6 +92,15 @@ match
BOOL match(PRIV_CALL, PRIV_TASK, STRING pattern, STRING subject, BOOL allow_empty_class=0, BOOL anchored=0, ENUM {ANYCRLF,UNICODE} bsr=0, BOOL alt_bsux=0, BOOL alt_circumflex=0, BOOL alt_verbnames=0, BOOL caseless=0, BOOL dollar_endonly=0, BOOL dotall=0, BOOL dupnames=0, BOOL extended=0, BOOL firstline=0, STRING locale=0, BOOL match_unset_backref=0, INT max_pattern_len=0, BOOL multiline=0, BOOL never_backslash_c=0, BOOL never_ucp=0, BOOL never_utf=0, ENUM {CR,LF,CRLF,ANYCRLF,ANY} newline=0, BOOL no_auto_capture=0, BOOL no_auto_possess=0, BOOL no_dotstar_anchor=0, BOOL no_start_optimize=0, BOOL no_utf_check=0, INT parens_nest_limit=0, BOOL ucp=0, BOOL ungreedy=0, BOOL use_offset_limit=0, BOOL utf=0, INT len=0, INT match_limit=0, INT offset_limit=0, BOOL notbol=0, BOOL noteol=0, BOOL notempty=0, BOOL notempty_atstart=0, BOOL no_jit=0, ENUM {HARD,SOFT} partial=0, INT recursion_limit=0) BOOL match(PRIV_CALL, PRIV_TASK, STRING pattern, STRING subject, BOOL allow_empty_class=0, BOOL anchored=0, ENUM {ANYCRLF,UNICODE} bsr=0, BOOL alt_bsux=0, BOOL alt_circumflex=0, BOOL alt_verbnames=0, BOOL caseless=0, BOOL dollar_endonly=0, BOOL dotall=0, BOOL dupnames=0, BOOL extended=0, BOOL firstline=0, STRING locale=0, BOOL match_unset_backref=0, INT max_pattern_len=0, BOOL multiline=0, BOOL never_backslash_c=0, BOOL never_ucp=0, BOOL never_utf=0, ENUM {CR,LF,CRLF,ANYCRLF,ANY} newline=0, BOOL no_auto_capture=0, BOOL no_auto_possess=0, BOOL no_dotstar_anchor=0, BOOL no_start_optimize=0, BOOL no_utf_check=0, INT parens_nest_limit=0, BOOL ucp=0, BOOL ungreedy=0, BOOL use_offset_limit=0, BOOL utf=0, INT len=0, INT match_limit=0, INT offset_limit=0, BOOL notbol=0, BOOL noteol=0, BOOL notempty=0, BOOL notempty_atstart=0, BOOL no_jit=0, ENUM {HARD,SOFT} partial=0, INT recursion_limit=0)
.. _func_backref:
backref
-------
::
STRING backref(PRIV_TASK, INT ref, STRING fallback="**BACKREF FUNCTION FAILED**")
.. _func_config_bool: .. _func_config_bool:
config_bool config_bool
......
...@@ -17,6 +17,7 @@ varnish v1 -vcl { ...@@ -17,6 +17,7 @@ varnish v1 -vcl {
} }
sub vcl_synth { sub vcl_synth {
# .backref() method
# Tests task scopes for two different objects # Tests task scopes for two different objects
if (barbaz.match("barbaz") && bazplus.match("bazquux")) { if (barbaz.match("barbaz") && bazplus.match("bazquux")) {
set resp.http.bar0 = barbaz.backref(0, "error0"); set resp.http.bar0 = barbaz.backref(0, "error0");
...@@ -39,6 +40,34 @@ varnish v1 -vcl { ...@@ -39,6 +40,34 @@ varnish v1 -vcl {
else { else {
set resp.status = 999; set resp.status = 999;
} }
# backref() function
if (pcre2.match("(bar)(baz)", "barbaz")) {
set resp.http.bar0-f = pcre2.backref(0, "error0");
set resp.http.bar1-f = pcre2.backref(1, "error1");
set resp.http.bar2-f = pcre2.backref(2, "error2");
}
else {
set resp.status = 999;
}
if (pcre2.match("(baz)(.+)", "bazquux")) {
set resp.http.baz0-f = pcre2.backref(0, "error0");
set resp.http.baz1-f = pcre2.backref(1, "error1");
set resp.http.baz2-f = pcre2.backref(2, "error2");
}
else {
set resp.status = 999;
}
if (pcre2.match("(.)(.)(.)(.)", "barf")) {
set resp.http.frap-f
= "_" + pcre2.backref(0, "error0") + "_"
+ pcre2.backref(4, "error4")
+ pcre2.backref(3, "error3")
+ pcre2.backref(2, "error2") + "p_";
}
else {
set resp.status = 999;
}
} }
} -start } -start
...@@ -53,6 +82,13 @@ client c1 -repeat 2 { ...@@ -53,6 +82,13 @@ client c1 -repeat 2 {
expect resp.http.baz1 == "baz" expect resp.http.baz1 == "baz"
expect resp.http.baz2 == "quux" expect resp.http.baz2 == "quux"
expect resp.http.frap == "_barf_frap_" expect resp.http.frap == "_barf_frap_"
expect resp.http.bar0-f == "barbaz"
expect resp.http.bar1-f == "bar"
expect resp.http.bar2-f == "baz"
expect resp.http.baz0-f == "bazquux"
expect resp.http.baz1-f == "baz"
expect resp.http.baz2-f == "quux"
expect resp.http.frap-f == "_barf_frap_"
} -run } -run
# backref failure # backref failure
...@@ -170,3 +206,106 @@ logexpect l1 -v v1 -d 1 -g vxid -q "VCL_Error" { ...@@ -170,3 +206,106 @@ logexpect l1 -v v1 -d 1 -g vxid -q "VCL_Error" {
expect * = VCL_Error "^vmod pcre2 error: in foo.backref..: unknown substring$" expect * = VCL_Error "^vmod pcre2 error: in foo.backref..: unknown substring$"
expect * = End expect * = End
} -run } -run
# The same tests with the backref function.
varnish v1 -vcl {
import pcre2 from "${vmod_topbuild}/src/.libs/libvmod_pcre2.so";
backend b { .host = "${bad_ip}"; }
sub vcl_recv {
return(synth(200));
}
sub vcl_synth {
set resp.http.nomatch = pcre2.backref(0);
if (pcre2.match("(bar)(baz)", "barbaz")) {
set resp.http.bar0 = pcre2.backref(0, "error0");
set resp.http.bar3 = pcre2.backref(3, "error3");
set resp.http.bar-1 = pcre2.backref(-1, "error-1");
set resp.http.barinf
= pcre2.backref(4294967296, "errorinf");
set resp.http.fallback
= pcre2.backref(0, req.http.undef);
}
set resp.http.frob1 = pcre2.match("(frob)(nitz)", "barbaz");
set resp.http.frob1-0 = pcre2.backref(0, "error0");
set resp.http.frob1-1 = pcre2.backref(1, "error1");
set resp.http.frob1-2 = pcre2.backref(2, "error2");
set resp.http.frob-yes
= pcre2.match("(frob)(nitz)", "frobnitz");
set resp.http.frob-no = pcre2.match("(frob)(nitz)", "barbaz");
set resp.http.frob2-0 = pcre2.backref(0, "error0");
set resp.http.frob2-1 = pcre2.backref(1, "error1");
set resp.http.frob2-2 = pcre2.backref(2, "error2");
set resp.http.azbc = pcre2.match("(a|(z))(bc)", "abc");
set resp.http.azbc-0 = pcre2.backref(0, "error0");
set resp.http.azbc-1 = pcre2.backref(1, "error1");
set resp.http.azbc-2 = pcre2.backref(2, "error2");
set resp.http.azbc-3 = pcre2.backref(3, "error3");
set resp.http.foo
= pcre2.match("(f)(o)(o)", "foo", no_auto_capture=true);
set resp.http.foo-0 = pcre2.backref(0, "error0");
set resp.http.foo-1 = pcre2.backref(1, "error1");
set resp.http.foo-2 = pcre2.backref(2, "error2");
set resp.http.foo-3 = pcre2.backref(3, "error3");
}
}
logexpect l1 -v v1 -d 0 -g vxid -q "VCL_Error" {
expect 0 * Begin req
expect * = VCL_Error "^vmod pcre2 error: pcre2.backref.. called without prior match$"
expect * = VCL_Error "^vmod pcre2 error: in pcre2.backref..: unknown substring$"
expect * = VCL_Error "^vmod pcre2 error: ref .-1. out of range in pcre2.backref.. .must be >= 0 and <= 4294967295.$"
expect * = VCL_Error "^vmod pcre2 error: ref .4294967296. out of range in pcre2.backref.. .must be >= 0 and <= 4294967295.$"
expect * = VCL_Error "^vmod pcre2 error: in pcre2.backref..: fallback is undefined$"
expect * = VCL_Error "^vmod pcre2 error: in pcre2.backref..: no match$"
expect * = VCL_Error "^vmod pcre2 error: in pcre2.backref..: no match$"
expect * = VCL_Error "^vmod pcre2 error: in pcre2.backref..: no match$"
expect * = VCL_Error "^vmod pcre2 error: in pcre2.backref..: no match$"
expect * = VCL_Error "^vmod pcre2 error: in pcre2.backref..: no match$"
expect * = VCL_Error "^vmod pcre2 error: in pcre2.backref..: no match$"
expect * = VCL_Error "^vmod pcre2 error: in pcre2.backref..: requested value is not set$"
expect * = VCL_Error "^vmod pcre2 error: in pcre2.backref..: unknown substring$"
expect * = VCL_Error "^vmod pcre2 error: in pcre2.backref..: unknown substring$"
expect * = VCL_Error "^vmod pcre2 error: in pcre2.backref..: unknown substring$"
expect * = End
} -start
client c1 -repeat 2 {
txreq
rxresp
expect resp.status == "200"
expect resp.http.nomatch == "**BACKREF FUNCTION FAILED**"
expect resp.http.bar0 == "barbaz"
expect resp.http.bar3 == "error3"
expect resp.http.barinf == "errorinf"
expect resp.http.fallback == "**BACKREF FUNCTION FAILED**"
expect resp.http.frob1 == "false"
expect resp.http.frob1-0 == "error0"
expect resp.http.frob1-1 == "error1"
expect resp.http.frob1-2 == "error2"
expect resp.http.frob-yes == "true"
expect resp.http.frob-no == "false"
expect resp.http.frob2-0 == "error0"
expect resp.http.frob2-1 == "error1"
expect resp.http.frob2-2 == "error2"
expect resp.http.azbc == "true"
expect resp.http.azbc-0 == "abc"
expect resp.http.azbc-1 == "a"
expect resp.http.azbc-2 == "error2"
expect resp.http.azbc-3 == "bc"
expect resp.http.foo == "true"
expect resp.http.foo-0 == "foo"
expect resp.http.foo-1 == "error1"
expect resp.http.foo-2 == "error2"
expect resp.http.foo-3 == "error3"
} -run
logexpect l1 -wait
This diff is collapsed.
...@@ -1446,24 +1446,24 @@ varnish v1 -vcl { ...@@ -1446,24 +1446,24 @@ varnish v1 -vcl {
set resp.http.r7b = r7.backref(0); set resp.http.r7b = r7.backref(0);
set resp.http.f1m = pcre2.match("<.*>", "abc<def>ghi<klm>nop"); set resp.http.f1m = pcre2.match("<.*>", "abc<def>ghi<klm>nop");
# set resp.http.f1b = pcre2.backref(0); set resp.http.f1b = pcre2.backref(0);
set resp.http.f2m = pcre2.match("<.*?>", "abc<def>ghi<klm>nop"); set resp.http.f2m = pcre2.match("<.*?>", "abc<def>ghi<klm>nop");
# set resp.http.f2b = pcre2.backref(0); set resp.http.f2b = pcre2.backref(0);
set resp.http.f3m set resp.http.f3m
= pcre2.match("<.*>", "abc<def>ghi<klm>nop", ungreedy=true); = pcre2.match("<.*>", "abc<def>ghi<klm>nop", ungreedy=true);
# set resp.http.f3b = pcre2.backref(0); set resp.http.f3b = pcre2.backref(0);
set resp.http.f4m set resp.http.f4m
= pcre2.match("(?U)<.*>", "abc<def>ghi<klm>nop"); = pcre2.match("(?U)<.*>", "abc<def>ghi<klm>nop");
# set resp.http.f4b = pcre2.backref(0); set resp.http.f4b = pcre2.backref(0);
set resp.http.f5m set resp.http.f5m
= pcre2.match("<.*?>", "abc<def>ghi<klm>nop", = pcre2.match("<.*?>", "abc<def>ghi<klm>nop",
ungreedy=true); ungreedy=true);
# set resp.http.f5b = pcre2.backref(0); set resp.http.f5b = pcre2.backref(0);
set resp.http.f6m set resp.http.f6m
= pcre2.match("={3,}", "abc========def", ungreedy=true); = pcre2.match("={3,}", "abc========def", ungreedy=true);
# set resp.http.f6b = pcre2.backref(0); set resp.http.f6b = pcre2.backref(0);
set resp.http.f7m = pcre2.match("(?U)={3,}?", "abc========def"); set resp.http.f7m = pcre2.match("(?U)={3,}?", "abc========def");
# set resp.http.f7b = pcre2.backref(0); set resp.http.f7b = pcre2.backref(0);
} }
} }
...@@ -1486,19 +1486,19 @@ client c1 { ...@@ -1486,19 +1486,19 @@ client c1 {
expect resp.http.r7m == "true" expect resp.http.r7m == "true"
expect resp.http.r7b == "========" expect resp.http.r7b == "========"
expect resp.http.f1m == "true" expect resp.http.f1m == "true"
expect resp.http.f1b == "<def>ghi<klm>"
expect resp.http.f2m == "true" expect resp.http.f2m == "true"
expect resp.http.f2b == "<def>"
expect resp.http.f3m == "true" expect resp.http.f3m == "true"
expect resp.http.f3b == "<def>"
expect resp.http.f4m == "true" expect resp.http.f4m == "true"
expect resp.http.f4b == "<def>"
expect resp.http.f5m == "true" expect resp.http.f5m == "true"
expect resp.http.f5b == "<def>ghi<klm>"
expect resp.http.f6m == "true" expect resp.http.f6m == "true"
expect resp.http.f6b == "==="
expect resp.http.f7m == "true" expect resp.http.f7m == "true"
expect resp.http.f7b == "========"
} -run } -run
# use_offset_limit # use_offset_limit
......
...@@ -865,6 +865,29 @@ vmod_match(VRT_CTX, struct vmod_priv *call, struct vmod_priv *task, ...@@ -865,6 +865,29 @@ vmod_match(VRT_CTX, struct vmod_priv *call, struct vmod_priv *task,
return ret; return ret;
} }
VCL_STRING
vmod_backref(VRT_CTX, struct vmod_priv *task, VCL_INT ref, VCL_STRING fallback)
{
struct task *match_task;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
AN(task);
if (fallback == NULL) {
ERR(ctx, "in pcre2.backref(): fallback is undefined");
return "**BACKREF FUNCTION FAILED**";
}
if (task->priv == NULL) {
ERR(ctx, "pcre2.backref() called without prior match");
return fallback;
}
WS_Assert_Allocated(ctx->ws, task->priv, sizeof(*match_task));
CAST_OBJ(match_task, task->priv, VMOD_PCRE2_TASK_MAGIC);
return refer(ctx, ref, NULL, fallback, NUMBERED, match_task->mdata,
"pcre2", "backref", "**BACKREF FUNCTION FAILED**");
}
/* Functions */ /* Functions */
VCL_BOOL VCL_BOOL
......
...@@ -64,6 +64,9 @@ $Function BOOL match(PRIV_CALL, PRIV_TASK, STRING pattern, STRING subject, ...@@ -64,6 +64,9 @@ $Function BOOL match(PRIV_CALL, PRIV_TASK, STRING pattern, STRING subject,
BOOL notempty_atstart=0, BOOL no_jit=0, BOOL notempty_atstart=0, BOOL no_jit=0,
ENUM {HARD, SOFT} partial=0, INT recursion_limit=0) ENUM {HARD, SOFT} partial=0, INT recursion_limit=0)
$Function STRING backref(PRIV_TASK, INT ref,
STRING fallback = "**BACKREF FUNCTION FAILED**")
$Function BOOL config_bool(ENUM {JIT, STACKRECURSE, UNICODE}) $Function BOOL config_bool(ENUM {JIT, STACKRECURSE, UNICODE})
$Function STRING config_str(ENUM {BSR, JITTARGET, NEWLINE, UNICODE_VERSION, $Function STRING config_str(ENUM {BSR, JITTARGET, NEWLINE, UNICODE_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