Commit 8bdce4b5 authored by Geoff Simmons's avatar Geoff Simmons

Add the .namedref() method; currently a lot of duplication with .backref().

parent ccff2eb0
......@@ -72,6 +72,15 @@ regex.backref
STRING regex.backref(INT ref, STRING fallback="**BACKREF METHOD FAILED**")
.. _func_regex.namedref:
regex.namedref
--------------
::
STRING regex.namedref(STRING name, STRING fallback="**NAMEDREF METHOD FAILED**")
.. _func_config_bool:
config_bool
......
# looks like -*- vcl -*-
varnishtest "namedref()"
varnish v1 -vcl {
import pcre2 from "${vmod_topbuild}/src/.libs/libvmod_pcre2.so";
backend b { .host = "${bad_ip}"; }
sub vcl_init {
new barbaz = pcre2.regex("(?<bar>bar)(?<baz>baz)");
new bazplus = pcre2.regex("(?<baz>baz)(?<dots>.+)");
}
sub vcl_recv {
return(synth(200));
}
sub vcl_synth {
# Tests task scopes for two different objects.
# Numbered backrefs also work with named groups.
if (barbaz.match("barbaz") && bazplus.match("bazquux")) {
set resp.http.bar-bar
= barbaz.namedref("bar", "err_bar");
set resp.http.bar-baz
= barbaz.namedref("baz", "err_baz");
set resp.http.baz-baz
= bazplus.namedref("baz", "err_baz");
set resp.http.baz-dots
= bazplus.namedref("dots", "err_dots");
set resp.http.bar0 = barbaz.backref(0, "error0");
set resp.http.bar1 = barbaz.backref(1, "error1");
set resp.http.bar2 = barbaz.backref(2, "error2");
set resp.http.baz0 = bazplus.backref(0, "error0");
set resp.http.baz1 = bazplus.backref(1, "error1");
set resp.http.baz2 = bazplus.backref(2, "error2");
}
else {
set resp.status = 999;
}
}
} -start
client c1 -repeat 2 {
txreq
rxresp
expect resp.status == "200"
expect resp.http.bar-bar == "bar"
expect resp.http.bar-baz == "baz"
expect resp.http.baz-baz == "baz"
expect resp.http.baz-dots == "quux"
expect resp.http.bar0 == "barbaz"
expect resp.http.bar1 == "bar"
expect resp.http.bar2 == "baz"
expect resp.http.baz0 == "bazquux"
expect resp.http.baz1 == "baz"
expect resp.http.baz2 == "quux"
} -run
# failure
varnish v1 -vcl {
import pcre2 from "${vmod_topbuild}/src/.libs/libvmod_pcre2.so";
backend b { .host = "${bad_ip}"; }
sub vcl_init {
new frobnitz = pcre2.regex("(?<frob>frob)(?<nitz>nitz)");
new barbaz = pcre2.regex("(?<bar>bar)(?<baz>baz)");
new azbc = pcre2.regex("(?<a>a|(?<z>z))(?<bc>bc)");
new foo = pcre2.regex("(?<f>f)(?<o>o)(o)",
no_auto_capture=true);
}
sub vcl_recv {
return(synth(200));
}
sub vcl_synth {
# Call to namedref() before match()
# Also tests the default fallback.
set resp.http.nomatch = barbaz.namedref("bar");
# match() and namedref() now re-use the object's task scope
if (barbaz.match("barbaz")) {
set resp.http.bar-bar
= barbaz.namedref("bar", "err_bar");
# no such name
set resp.http.bar-quux
= barbaz.namedref("quux", "err_quux");
# fallback is NULL
set resp.http.fallback
= barbaz.namedref("bar", req.http.undef);
}
# match fails
set resp.http.frob1 = frobnitz.match("barbaz");
# ... so all namedrefs fail
set resp.http.frob1-frob
= frobnitz.namedref("frob", "err_frob");
set resp.http.frob1-nitz
= frobnitz.namedref("nitz", "err_nitz");
# match succeeds, then fails again
set resp.http.frob-yes = frobnitz.match("frobnitz");
set resp.http.frob-no = frobnitz.match("barbaz");
# ... so all namedrefs fail, despite previous match
set resp.http.frob2-frob
= frobnitz.namedref("frob", "err_frob");
set resp.http.frob2-nitz
= frobnitz.namedref("nitz", "err_nitz");
# namedref "z" is unset
set resp.http.azbc = azbc.match("abc");
set resp.http.azbc-a = azbc.namedref("a", "err_a");
set resp.http.azbc-z = azbc.namedref("z", "err_z");
set resp.http.azbc-bc = azbc.namedref("bc", "err_bc");
# namedrefs succeed with no_auto_capture, as well as
# numbered backrefs that correspond to the named
# groups, and backref 0, but not the other numbered backrefs.
set resp.http.foo = foo.match("foo");
set resp.http.foo-f = foo.namedref("f", "err_f");
set resp.http.foo-o = foo.namedref("o", "err_o");
set resp.http.foo-0 = foo.backref(0, "error0");
set resp.http.foo-1 = foo.backref(1, "error1");
set resp.http.foo-2 = foo.backref(2, "error2");
set resp.http.foo-3 = foo.backref(3, "error3");
}
}
client c1 -repeat 2 {
txreq
rxresp
expect resp.status == "200"
expect resp.http.nomatch == "**NAMEDREF METHOD FAILED**"
expect resp.http.bar-bar == "bar"
expect resp.http.bar-quux == "err_quux"
expect resp.http.fallback == "**NAMEDREF METHOD FAILED**"
expect resp.http.frob1 == "false"
expect resp.http.frob1-frob == "err_frob"
expect resp.http.frob1-nitz == "err_nitz"
expect resp.http.frob-yes == "true"
expect resp.http.frob-no == "false"
expect resp.http.frob2-frob == "err_frob"
expect resp.http.frob2-nitz == "err_nitz"
expect resp.http.azbc == "true"
expect resp.http.azbc-a == "a"
expect resp.http.azbc-z == "err_z"
expect resp.http.azbc-bc == "bc"
expect resp.http.foo == "true"
expect resp.http.foo-f == "f"
expect resp.http.foo-o == "o"
expect resp.http.foo-0 == "foo"
expect resp.http.foo-1 == "f"
expect resp.http.foo-2 == "o"
expect resp.http.foo-3 == "error3"
} -run
logexpect l1 -v v1 -d 1 -g vxid -q "VCL_Error" {
expect 0 * Begin req
expect * = VCL_Error "^vmod pcre2 error: barbaz.namedref.bar. called without prior match$"
expect * = VCL_Error "^vmod pcre2 error: in barbaz.namedref.quux.: unknown substring$"
expect * = VCL_Error "^vmod pcre2 error: in barbaz.namedref..: fallback is undefined$"
expect * = VCL_Error "^vmod pcre2 error: in frobnitz.namedref.frob.: no match$"
expect * = VCL_Error "^vmod pcre2 error: in frobnitz.namedref.nitz.: no match$"
expect * = VCL_Error "^vmod pcre2 error: in frobnitz.namedref.frob.: no match$"
expect * = VCL_Error "^vmod pcre2 error: in frobnitz.namedref.nitz.: no match$"
expect * = VCL_Error "^vmod pcre2 error: in azbc.namedref.z.: requested value is not set$"
expect * = VCL_Error "^vmod pcre2 error: in foo.backref.3.: unknown substring$"
expect * = End
} -run
......@@ -572,6 +572,63 @@ vmod_regex_backref(VRT_CTX, struct vmod_pcre2_regex *regex, VCL_INT ref,
return fallback;
}
VCL_STRING
vmod_regex_namedref(VRT_CTX, struct vmod_pcre2_regex *regex, VCL_STRING name,
VCL_STRING fallback)
{
struct vmod_priv *match_task;
pcre2_match_data *mdata;
PCRE2_UCHAR *buf;
PCRE2_SIZE len;
int ret;
char *msg;
uintptr_t snap;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(regex, VMOD_PCRE2_REGEX_MAGIC);
if (fallback == NULL) {
VERR(ctx, "in %s.namedref(): fallback is undefined",
regex->vcl_name);
return "**NAMEDREF METHOD FAILED**";
}
if (name == NULL) {
VERR(ctx, "in %s.namedref(<undefined>): name is undefined",
regex->vcl_name);
return fallback;
}
match_task = VRT_priv_task(ctx, regex);
AN(match_task);
if (match_task->priv == NULL) {
VERR(ctx, "%s.namedref(%s) called without prior match",
regex->vcl_name, name);
return fallback;
}
WS_Assert_Allocated(ctx->ws, match_task->priv, 0);
mdata = match_task->priv;
if ((ret = pcre2_substring_get_byname(mdata, (PCRE2_SPTR)name, &buf,
&len)) == 0) {
WS_Assert_Allocated(ctx->ws, buf, len + 1);
return (VCL_STRING)buf;
}
/*
* This error is returned when the ovector was too small, cannot
* happen after using pcre2_match_data_create_from_pattern() to
* get the match data block.
*/
assert(ret != PCRE2_ERROR_UNAVAILABLE);
snap = WS_Snapshot(ctx->ws);
if ((msg = WS_Printf(ctx->ws, "in %s.namedref(%s)", regex->vcl_name,
name)) == NULL)
msg = "";
report_pcre2_err(ctx, ret, msg, "");
WS_Reset(ctx->ws, snap);
return fallback;
}
/* Functions */
VCL_BOOL
......
......@@ -41,6 +41,9 @@ $Method BOOL .match(PRIV_CALL, PRIV_TASK, STRING subject, INT len=0,
$Method STRING .backref(INT ref, STRING fallback = "**BACKREF METHOD FAILED**")
$Method STRING .namedref(STRING name,
STRING fallback = "**NAMEDREF METHOD FAILED**")
$Function BOOL config_bool(ENUM {JIT, STACKRECURSE, UNICODE})
$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