Commit 4aaec2ff authored by Geoff Simmons's avatar Geoff Simmons

Add the .check_call() method.

parent d6d30486
...@@ -1072,6 +1072,21 @@ SUB xset.subroutine(INT n, STRING element, ENUM select) ...@@ -1072,6 +1072,21 @@ SUB xset.subroutine(INT n, STRING element, ENUM select)
XXX ... XXX ...
.. _xset.check_call():
BOOL xset.check_call(INT n, STRING element, ENUM select)
--------------------------------------------------------
::
BOOL xset.check_call(
INT n=0,
STRING element=0,
ENUM {UNIQUE, EXACT, FIRST, LAST, SHORTEST, LONGEST} select=UNIQUE
)
XXX ...
.. _selector.version(): .. _selector.version():
STRING version() STRING version()
......
...@@ -31,11 +31,11 @@ ...@@ -31,11 +31,11 @@
static unsigned static unsigned
select(VRT_CTX, const struct match_data * const restrict match, select(VRT_CTX, const struct match_data * const restrict match,
const char * const restrict obj, VCL_ENUM const restrict selects, const char * const restrict obj, VCL_ENUM const restrict selects,
const char * const restrict method) const char * const restrict method, int fail)
{ {
if (selects == VENUM(EXACT)) { if (selects == VENUM(EXACT)) {
if (match->exact == UINT_MAX) if (match->exact == UINT_MAX)
VFAIL(ctx, "%s.%s(select=EXACT): " VFAIL_OR_NOTICE(ctx, fail, "%s.%s(select=EXACT): "
"no element matched exactly", obj, method); "no element matched exactly", obj, method);
return match->exact; return match->exact;
} }
...@@ -45,8 +45,9 @@ select(VRT_CTX, const struct match_data * const restrict match, ...@@ -45,8 +45,9 @@ select(VRT_CTX, const struct match_data * const restrict match,
switch (selects[0]) { switch (selects[0]) {
case 'U': case 'U':
assert(selects == VENUM(UNIQUE)); assert(selects == VENUM(UNIQUE));
VFAIL(ctx, "%s.%s(select=UNIQUE): %d elements were matched", VFAIL_OR_NOTICE(ctx, fail,
obj, method, match->n); "%s.%s(select=UNIQUE): %d elements were matched",
obj, method, match->n);
return (UINT_MAX); return (UINT_MAX);
case 'L': case 'L':
if (selects == VENUM(LAST)) if (selects == VENUM(LAST))
...@@ -81,7 +82,7 @@ vmod_set_which(VRT_CTX, struct vmod_selector_set *set, VCL_ENUM selects, ...@@ -81,7 +82,7 @@ vmod_set_which(VRT_CTX, struct vmod_selector_set *set, VCL_ENUM selects,
return (UINT_MAX); return (UINT_MAX);
} }
match = get_existing_match_data(ctx, set, "which"); match = get_existing_match_data(ctx, set, "which", 1);
if (element != NULL) { if (element != NULL) {
CHECK_OBJ_NOTNULL(match, MATCH_DATA_MAGIC); CHECK_OBJ_NOTNULL(match, MATCH_DATA_MAGIC);
assert(match->n == 1); assert(match->n == 1);
...@@ -89,35 +90,38 @@ vmod_set_which(VRT_CTX, struct vmod_selector_set *set, VCL_ENUM selects, ...@@ -89,35 +90,38 @@ vmod_set_which(VRT_CTX, struct vmod_selector_set *set, VCL_ENUM selects,
} }
if (match == NULL || match->n == 0) if (match == NULL || match->n == 0)
return (0); return (0);
return (select(ctx, match, set->vcl_name, selects, "which") + 1); return (select(ctx, match, set->vcl_name, selects, "which", 1) + 1);
} }
static unsigned static unsigned
get_idx(VRT_CTX, VCL_INT n, const struct vmod_selector_set * const restrict set, get_idx(VRT_CTX, VCL_INT n, const struct vmod_selector_set * const restrict set,
const char * const restrict method, VCL_STRING const restrict element, const char * const restrict method, VCL_STRING const restrict element,
VCL_ENUM const restrict selects) VCL_ENUM const restrict selects, int fail)
{ {
struct match_data *match; struct match_data *match;
if (n > 0) { if (n > 0) {
if (n > set->nmembers) { if (n > set->nmembers) {
VFAIL(ctx, "%s.%s(%ld): set has %d elements", VFAIL_OR_NOTICE(ctx, fail,
set->vcl_name, method, n, set->nmembers); "%s.%s(%ld): set has %d elements",
set->vcl_name, method, n,
set->nmembers);
return (UINT_MAX); return (UINT_MAX);
} }
return (n - 1); return (n - 1);
} }
if (element != NULL) if (element != NULL)
if (!vmod_set_match(ctx, TRUST_ME(set), element)) { if (!vmod_set_match(ctx, TRUST_ME(set), element)) {
VFAIL(ctx, "%s.%s(element=\"%s\"): no such element", VFAIL_OR_NOTICE(ctx, fail,
set->vcl_name, method, element); "%s.%s(element=\"%s\"): no such element",
set->vcl_name, method, element);
return (UINT_MAX); return (UINT_MAX);
} }
match = get_existing_match_data(ctx, set, method); match = get_existing_match_data(ctx, set, method, fail);
if (match == NULL || match->n == 0) if (match == NULL || match->n == 0)
return (UINT_MAX); return (UINT_MAX);
return (select(ctx, match, set->vcl_name, selects, method)); return (select(ctx, match, set->vcl_name, selects, method, fail));
} }
VCL_STRING VCL_STRING
...@@ -129,7 +133,7 @@ vmod_set_element(VRT_CTX, struct vmod_selector_set *set, VCL_INT n, ...@@ -129,7 +133,7 @@ vmod_set_element(VRT_CTX, struct vmod_selector_set *set, VCL_INT n,
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(set, VMOD_SELECTOR_SET_MAGIC); CHECK_OBJ_NOTNULL(set, VMOD_SELECTOR_SET_MAGIC);
idx = get_idx(ctx, n, set, "element", NULL, selects); idx = get_idx(ctx, n, set, "element", NULL, selects, 1);
if (idx == UINT_MAX) if (idx == UINT_MAX)
return (NULL); return (NULL);
return (set->members[idx]); return (set->members[idx]);
...@@ -139,11 +143,12 @@ static inline int ...@@ -139,11 +143,12 @@ static inline int
check_added(VRT_CTX, const struct vmod_selector_set * const restrict set, check_added(VRT_CTX, const struct vmod_selector_set * const restrict set,
unsigned idx, enum bitmap_e bitmap, unsigned idx, enum bitmap_e bitmap,
const char * const restrict method, const char * const restrict method,
const char * const restrict type) const char * const restrict type, int fail)
{ {
if (!is_added(set, idx, bitmap)) { if (!is_added(set, idx, bitmap)) {
VFAIL(ctx, "%s.%s(): %s not added for element %u", VFAIL_OR_NOTICE(ctx, fail,
set->vcl_name, method, type, idx + 1); "%s.%s(): %s not added for element %u",
set->vcl_name, method, type, idx + 1);
return (0); return (0);
} }
return (1); return (1);
...@@ -159,10 +164,10 @@ vmod_set_backend(VRT_CTX, struct vmod_selector_set *set, VCL_INT n, ...@@ -159,10 +164,10 @@ vmod_set_backend(VRT_CTX, struct vmod_selector_set *set, VCL_INT n,
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(set, VMOD_SELECTOR_SET_MAGIC); CHECK_OBJ_NOTNULL(set, VMOD_SELECTOR_SET_MAGIC);
idx = get_idx(ctx, n, set, "backend", element, selects); idx = get_idx(ctx, n, set, "backend", element, selects, 1);
if (idx == UINT_MAX) if (idx == UINT_MAX)
return (NULL); return (NULL);
if (!check_added(ctx, set, idx, BACKEND, "backend", "backend")) if (!check_added(ctx, set, idx, BACKEND, "backend", "backend", 1))
return (NULL); return (NULL);
b = set->table[idx]->backend; b = set->table[idx]->backend;
...@@ -180,10 +185,10 @@ vmod_set_string(VRT_CTX, struct vmod_selector_set * set, VCL_INT n, ...@@ -180,10 +185,10 @@ vmod_set_string(VRT_CTX, struct vmod_selector_set * set, VCL_INT n,
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(set, VMOD_SELECTOR_SET_MAGIC); CHECK_OBJ_NOTNULL(set, VMOD_SELECTOR_SET_MAGIC);
idx = get_idx(ctx, n, set, "string", element, selects); idx = get_idx(ctx, n, set, "string", element, selects, 1);
if (idx == UINT_MAX) if (idx == UINT_MAX)
return (NULL); return (NULL);
if (!check_added(ctx, set, idx, STRING, "string", "string")) if (!check_added(ctx, set, idx, STRING, "string", "string", 1))
return (NULL); return (NULL);
s = set->table[idx]->string; s = set->table[idx]->string;
...@@ -200,10 +205,10 @@ vmod_set_integer(VRT_CTX, struct vmod_selector_set * set, VCL_INT n, ...@@ -200,10 +205,10 @@ vmod_set_integer(VRT_CTX, struct vmod_selector_set * set, VCL_INT n,
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(set, VMOD_SELECTOR_SET_MAGIC); CHECK_OBJ_NOTNULL(set, VMOD_SELECTOR_SET_MAGIC);
idx = get_idx(ctx, n, set, "integer", element, selects); idx = get_idx(ctx, n, set, "integer", element, selects, 1);
if (idx == UINT_MAX) if (idx == UINT_MAX)
return (0); return (0);
if (!check_added(ctx, set, idx, INTEGER, "integer", "integer")) if (!check_added(ctx, set, idx, INTEGER, "integer", "integer", 1))
return (0); return (0);
return (set->table[idx]->integer); return (set->table[idx]->integer);
...@@ -220,10 +225,10 @@ get_re(VRT_CTX, const struct vmod_selector_set * const restrict set, ...@@ -220,10 +225,10 @@ get_re(VRT_CTX, const struct vmod_selector_set * const restrict set,
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(set, VMOD_SELECTOR_SET_MAGIC); CHECK_OBJ_NOTNULL(set, VMOD_SELECTOR_SET_MAGIC);
idx = get_idx(ctx, n, set, method, element, selects); idx = get_idx(ctx, n, set, method, element, selects, 1);
if (idx == UINT_MAX) if (idx == UINT_MAX)
return (NULL); return (NULL);
if (!check_added(ctx, set, idx, REGEX, method, "regex")) if (!check_added(ctx, set, idx, REGEX, method, "regex", 1))
return (NULL); return (NULL);
re = set->table[idx]->re; re = set->table[idx]->re;
...@@ -265,10 +270,10 @@ vmod_set_bool(VRT_CTX, struct VPFX(selector_set) *set, VCL_INT n, ...@@ -265,10 +270,10 @@ vmod_set_bool(VRT_CTX, struct VPFX(selector_set) *set, VCL_INT n,
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(set, VMOD_SELECTOR_SET_MAGIC); CHECK_OBJ_NOTNULL(set, VMOD_SELECTOR_SET_MAGIC);
idx = get_idx(ctx, n, set, "bool", element, selects); idx = get_idx(ctx, n, set, "bool", element, selects, 1);
if (idx == UINT_MAX) if (idx == UINT_MAX)
return (0); return (0);
if (!check_added(ctx, set, idx, BOOLEAN, "bool", "boolean")) if (!check_added(ctx, set, idx, BOOLEAN, "bool", "boolean", 1))
return (0); return (0);
return (set->table[idx]->bool); return (set->table[idx]->bool);
...@@ -283,11 +288,34 @@ vmod_set_subroutine(VRT_CTX, struct VPFX(selector_set) *set, VCL_INT n, ...@@ -283,11 +288,34 @@ vmod_set_subroutine(VRT_CTX, struct VPFX(selector_set) *set, VCL_INT n,
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(set, VMOD_SELECTOR_SET_MAGIC); CHECK_OBJ_NOTNULL(set, VMOD_SELECTOR_SET_MAGIC);
idx = get_idx(ctx, n, set, "subroutine", element, selects); idx = get_idx(ctx, n, set, "subroutine", element, selects, 1);
if (idx == UINT_MAX) if (idx == UINT_MAX)
return (NULL); return (NULL);
if (!check_added(ctx, set, idx, SUB, "subroutine", "subroutine")) if (!check_added(ctx, set, idx, SUB, "subroutine", "subroutine", 1))
return (NULL); return (NULL);
return (set->table[idx]->sub); return (set->table[idx]->sub);
} }
VCL_BOOL
vmod_set_check_call(VRT_CTX, struct VPFX(selector_set) *set, VCL_INT n,
VCL_STRING element, VCL_ENUM selects)
{
unsigned idx;
VCL_STRING err;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(set, VMOD_SELECTOR_SET_MAGIC);
idx = get_idx(ctx, n, set, "check_call", element, selects, 0);
if (idx == UINT_MAX)
return (0);
if (!check_added(ctx, set, idx, SUB, "check_call", "subroutine", 0))
return (0);
if ((err = VRT_check_call(ctx, set->table[idx]->sub)) != NULL) {
VNOTICE(ctx, "%s", err);
return (0);
}
return (1);
}
...@@ -183,7 +183,7 @@ vmod_set_hasprefix(VRT_CTX, struct vmod_selector_set *set, VCL_STRING subject) ...@@ -183,7 +183,7 @@ vmod_set_hasprefix(VRT_CTX, struct vmod_selector_set *set, VCL_STRING subject)
struct match_data * struct match_data *
get_existing_match_data(VRT_CTX, get_existing_match_data(VRT_CTX,
const struct vmod_selector_set * const restrict set, const struct vmod_selector_set * const restrict set,
const char * const restrict method) const char * const restrict method, int fail)
{ {
struct vmod_priv *task; struct vmod_priv *task;
struct match_data *match; struct match_data *match;
...@@ -191,8 +191,8 @@ get_existing_match_data(VRT_CTX, ...@@ -191,8 +191,8 @@ get_existing_match_data(VRT_CTX,
task = VRT_priv_task(ctx, set); task = VRT_priv_task(ctx, set);
AN(task); AN(task);
if (task->priv == NULL) { if (task->priv == NULL) {
VFAIL(ctx, "%s.%s() called without prior match", set->vcl_name, VFAIL_OR_NOTICE(ctx, fail, "%s.%s() called without prior match",
method); set->vcl_name, method);
return (NULL); return (NULL);
} }
WS_Assert_Allocated(ctx->ws, task->priv, sizeof(*match)); WS_Assert_Allocated(ctx->ws, task->priv, sizeof(*match));
...@@ -208,7 +208,7 @@ vmod_set_nmatches(VRT_CTX, struct vmod_selector_set *set) ...@@ -208,7 +208,7 @@ vmod_set_nmatches(VRT_CTX, struct vmod_selector_set *set)
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(set, VMOD_SELECTOR_SET_MAGIC); CHECK_OBJ_NOTNULL(set, VMOD_SELECTOR_SET_MAGIC);
match = get_existing_match_data(ctx, set, "nmatches"); match = get_existing_match_data(ctx, set, "nmatches", 1);
if (match == NULL) if (match == NULL)
return (0); return (0);
return (match->n); return (match->n);
...@@ -229,7 +229,7 @@ vmod_set_matched(VRT_CTX, struct VPFX(selector_set) *set, VCL_INT idx, ...@@ -229,7 +229,7 @@ vmod_set_matched(VRT_CTX, struct VPFX(selector_set) *set, VCL_INT idx,
return (0); return (0);
} }
match = get_existing_match_data(ctx, set, "matched"); match = get_existing_match_data(ctx, set, "matched", 1);
if (match == NULL || match->n == 0) if (match == NULL || match->n == 0)
return (0); return (0);
......
# looks like -*- vcl -*- # looks like -*- vcl -*-
varnishtest "call() method" varnishtest ".subroutine() and .check_call() methods"
varnish v1 -vcl { varnish v1 -vcl {
import ${vmod_selector}; import ${vmod_selector};
...@@ -65,6 +65,12 @@ varnish v1 -vcl { ...@@ -65,6 +65,12 @@ varnish v1 -vcl {
} }
sub vcl_synth { sub vcl_synth {
set resp.http.Check-1 = s.check_call(1);
set resp.http.Check-2 = s.check_call(2);
set resp.http.Check-3 = s.check_call(3);
set resp.http.Check-4 = s.check_call(4);
set resp.http.Check-5 = s.check_call(5);
set resp.http.X = "N"; set resp.http.X = "N";
call s.subroutine(1); call s.subroutine(1);
call s.subroutine(2); call s.subroutine(2);
...@@ -81,8 +87,25 @@ varnish v1 -vcl { ...@@ -81,8 +87,25 @@ varnish v1 -vcl {
call s.subroutine(select=LAST); call s.subroutine(select=LAST);
call s.subroutine(select=SHORTEST); call s.subroutine(select=SHORTEST);
call s.subroutine(select=LONGEST); call s.subroutine(select=LONGEST);
set resp.http.Check-Noarg = s.check_call();
set resp.http.Check-Unique
= s.check_call(select=UNIQUE);
set resp.http.Check-Exact = s.check_call(select=EXACT);
set resp.http.Check-First = s.check_call(select=FIRST);
set resp.http.Check-Last = s.check_call(select=LAST);
set resp.http.Check-Shortest
= s.check_call(select=SHORTEST);
set resp.http.Check-Longest
= s.check_call(select=LONGEST);
} }
set resp.http.Check-Foo = s.check_call(element="foo");
set resp.http.Check-Bar = s.check_call(element="bar");
set resp.http.Check-Baz = s.check_call(element="baz");
set resp.http.Check-Quux = s.check_call(element="quux");
set resp.http.Check-Foobar = s.check_call(element="foobar");
set resp.http.X = "E"; set resp.http.X = "E";
call s.subroutine(element="foo"); call s.subroutine(element="foo");
call s.subroutine(element="bar"); call s.subroutine(element="bar");
...@@ -90,6 +113,8 @@ varnish v1 -vcl { ...@@ -90,6 +113,8 @@ varnish v1 -vcl {
call s.subroutine(element="quux"); call s.subroutine(element="quux");
call s.subroutine(element="foobar"); call s.subroutine(element="foobar");
if (req.http.Element) { if (req.http.Element) {
set resp.http.Check-Element
= s.check_call(element=req.http.Element);
call s.subroutine(element=req.http.Element); call s.subroutine(element=req.http.Element);
} }
...@@ -101,6 +126,18 @@ client c1 { ...@@ -101,6 +126,18 @@ client c1 {
txreq txreq
rxresp rxresp
expect resp.status == 200 expect resp.status == 200
expect resp.http.Check-1 == true
expect resp.http.Check-2 == true
expect resp.http.Check-3 == true
expect resp.http.Check-4 == true
expect resp.http.Check-5 == true
expect resp.http.Check-Foo == true
expect resp.http.Check-Bar == true
expect resp.http.Check-Baz == true
expect resp.http.Check-Quux == true
expect resp.http.Check-Foobar == true
expect resp.http.Foo == "NE" expect resp.http.Foo == "NE"
expect resp.http.Bar == "NE" expect resp.http.Bar == "NE"
expect resp.http.Baz == "NE" expect resp.http.Baz == "NE"
...@@ -110,6 +147,14 @@ client c1 { ...@@ -110,6 +147,14 @@ client c1 {
txreq -hdr "Word: foo" txreq -hdr "Word: foo"
rxresp rxresp
expect resp.status == 200 expect resp.status == 200
expect resp.http.Check-Noarg == true
expect resp.http.Check-Unique == true
expect resp.http.Check-Exact == true
expect resp.http.Check-First == true
expect resp.http.Check-Last == true
expect resp.http.Check-Longest == true
expect resp.http.Check-Shortest == true
expect resp.http.Foo == "NSSSSSSSE" expect resp.http.Foo == "NSSSSSSSE"
expect resp.http.Bar == "NE" expect resp.http.Bar == "NE"
expect resp.http.Baz == "NE" expect resp.http.Baz == "NE"
...@@ -119,6 +164,14 @@ client c1 { ...@@ -119,6 +164,14 @@ client c1 {
txreq -hdr "Word: bar" txreq -hdr "Word: bar"
rxresp rxresp
expect resp.status == 200 expect resp.status == 200
expect resp.http.Check-Noarg == true
expect resp.http.Check-Unique == true
expect resp.http.Check-Exact == true
expect resp.http.Check-First == true
expect resp.http.Check-Last == true
expect resp.http.Check-Longest == true
expect resp.http.Check-Shortest == true
expect resp.http.Foo == "NE" expect resp.http.Foo == "NE"
expect resp.http.Bar == "NSSSSSSSE" expect resp.http.Bar == "NSSSSSSSE"
expect resp.http.Baz == "NE" expect resp.http.Baz == "NE"
...@@ -127,6 +180,14 @@ client c1 { ...@@ -127,6 +180,14 @@ client c1 {
txreq -hdr "Word: baz" txreq -hdr "Word: baz"
rxresp rxresp
expect resp.http.Check-Noarg == true
expect resp.http.Check-Unique == true
expect resp.http.Check-Exact == true
expect resp.http.Check-First == true
expect resp.http.Check-Last == true
expect resp.http.Check-Longest == true
expect resp.http.Check-Shortest == true
expect resp.status == 200 expect resp.status == 200
expect resp.http.Foo == "NE" expect resp.http.Foo == "NE"
expect resp.http.Bar == "NE" expect resp.http.Bar == "NE"
...@@ -136,6 +197,14 @@ client c1 { ...@@ -136,6 +197,14 @@ client c1 {
txreq -hdr "Word: quux" txreq -hdr "Word: quux"
rxresp rxresp
expect resp.http.Check-Noarg == true
expect resp.http.Check-Unique == true
expect resp.http.Check-Exact == true
expect resp.http.Check-First == true
expect resp.http.Check-Last == true
expect resp.http.Check-Longest == true
expect resp.http.Check-Shortest == true
expect resp.status == 200 expect resp.status == 200
expect resp.http.Foo == "NE" expect resp.http.Foo == "NE"
expect resp.http.Bar == "NE" expect resp.http.Bar == "NE"
...@@ -146,6 +215,14 @@ client c1 { ...@@ -146,6 +215,14 @@ client c1 {
txreq -hdr "Word: foobar" txreq -hdr "Word: foobar"
rxresp rxresp
expect resp.status == 200 expect resp.status == 200
expect resp.http.Check-Noarg == true
expect resp.http.Check-Unique == true
expect resp.http.Check-Exact == true
expect resp.http.Check-First == true
expect resp.http.Check-Last == true
expect resp.http.Check-Longest == true
expect resp.http.Check-Shortest == true
expect resp.http.Foo == "NE" expect resp.http.Foo == "NE"
expect resp.http.Bar == "NE" expect resp.http.Bar == "NE"
expect resp.http.Baz == "NE" expect resp.http.Baz == "NE"
...@@ -162,6 +239,12 @@ logexpect l1 -v v1 -d 1 -g vxid -q "Notice" { ...@@ -162,6 +239,12 @@ logexpect l1 -v v1 -d 1 -g vxid -q "Notice" {
expect 0 * Begin req expect 0 * Begin req
expect * = Notice {^vmod_selector: s\.match\(\): subject string is NULL$} expect * = Notice {^vmod_selector: s\.match\(\): subject string is NULL$}
expect * = End expect * = End
expect 0 * Begin req
expect * = Notice {^vmod_selector: s\.match\(\): subject string is NULL$}
expect * = Notice {^vmod_selector: s\.check_call\(element="oof"\): no such element$}
expect 0 = RespHeader {^Check-Element: false$}
expect * = End
} -run } -run
logexpect l1 -v v1 -d 1 -g vxid -q "VCL_Error" { logexpect l1 -v v1 -d 1 -g vxid -q "VCL_Error" {
...@@ -178,23 +261,23 @@ varnish v1 -vcl { ...@@ -178,23 +261,23 @@ varnish v1 -vcl {
backend b None; backend b None;
sub foo { sub foo {
set resp.http.Called = "foo"; set req.http.Called = "foo";
} }
sub bar { sub bar {
set resp.http.Called = "bar"; set req.http.Called = "bar";
} }
sub baz { sub baz {
set resp.http.Called = "baz"; set req.http.Called = "baz";
} }
sub quux { sub quux {
set resp.http.Called = "quux"; set req.http.Called = "quux";
} }
sub foobar { sub foobar {
set resp.http.Called = "foobar"; set req.http.Called = "foobar";
} }
sub vcl_init { sub vcl_init {
...@@ -207,9 +290,18 @@ varnish v1 -vcl { ...@@ -207,9 +290,18 @@ varnish v1 -vcl {
} }
sub vcl_recv { sub vcl_recv {
set req.http.Check-Call
= s.check_call(std.integer(req.http.Int));
call s.subroutine(std.integer(req.http.Int)); call s.subroutine(std.integer(req.http.Int));
return (synth(200)); return (synth(200));
} }
sub vcl_synth {
if (req.http.Called) {
set resp.http.Called = req.http.Called;
}
return (deliver);
}
} }
logexpect l1 -v v1 -d 0 -g vxid -q "VCL_Error" { logexpect l1 -v v1 -d 0 -g vxid -q "VCL_Error" {
...@@ -229,6 +321,23 @@ logexpect l1 -v v1 -d 0 -g vxid -q "VCL_Error" { ...@@ -229,6 +321,23 @@ logexpect l1 -v v1 -d 0 -g vxid -q "VCL_Error" {
expect * = End expect * = End
} -start } -start
logexpect l2 -v v1 -d 0 -g vxid -q "Notice" {
expect 0 * Begin req
expect * = Notice {^vmod_selector: s\.check_call\(\) called without prior match$}
expect 0 = ReqHeader {^Check-Call: false$}
expect * = End
expect 0 * Begin req
expect * = Notice {^vmod_selector: s\.check_call\(\) called without prior match$}
expect 0 = ReqHeader {^Check-Call: false$}
expect * = End
expect 0 * Begin req
expect * = Notice {^vmod_selector: s\.check_call\(6\): set has 5 elements$}
expect 0 = ReqHeader {^Check-Call: false$}
expect * = End
} -start
client c1 { client c1 {
txreq -hdr "Int: -1" txreq -hdr "Int: -1"
rxresp rxresp
...@@ -257,6 +366,7 @@ client c1 { ...@@ -257,6 +366,7 @@ client c1 {
} -run } -run
logexpect l1 -wait logexpect l1 -wait
logexpect l2 -wait
varnish v1 -vcl { varnish v1 -vcl {
import ${vmod_selector}; import ${vmod_selector};
...@@ -289,6 +399,17 @@ varnish v1 -vcl { ...@@ -289,6 +399,17 @@ varnish v1 -vcl {
sub vcl_synth { sub vcl_synth {
if (s.hasprefix(req.http.Word)) { if (s.hasprefix(req.http.Word)) {
set resp.http.Check-Noarg = s.check_call();
set resp.http.Check-Unique
= s.check_call(select=UNIQUE);
set resp.http.Check-Exact = s.check_call(select=EXACT);
set resp.http.Check-First = s.check_call(select=FIRST);
set resp.http.Check-Last = s.check_call(select=LAST);
set resp.http.Check-Shortest
= s.check_call(select=SHORTEST);
set resp.http.Check-Longest
= s.check_call(select=LONGEST);
call s.subroutine(); call s.subroutine();
call s.subroutine(select=UNIQUE); call s.subroutine(select=UNIQUE);
call s.subroutine(select=EXACT); call s.subroutine(select=EXACT);
...@@ -299,6 +420,17 @@ varnish v1 -vcl { ...@@ -299,6 +420,17 @@ varnish v1 -vcl {
} }
if (req.http.Element) { if (req.http.Element) {
call s.subroutine(element=req.http.Element); call s.subroutine(element=req.http.Element);
set resp.http.Check-Unique
= s.check_call(select=UNIQUE);
set resp.http.Check-Exact = s.check_call(select=EXACT);
set resp.http.Check-First = s.check_call(select=FIRST);
set resp.http.Check-Last = s.check_call(select=LAST);
set resp.http.Check-Shortest
= s.check_call(select=SHORTEST);
set resp.http.Check-Longest
= s.check_call(select=LONGEST);
call s.subroutine(select=UNIQUE); call s.subroutine(select=UNIQUE);
call s.subroutine(select=EXACT); call s.subroutine(select=EXACT);
call s.subroutine(select=FIRST); call s.subroutine(select=FIRST);
...@@ -315,12 +447,25 @@ client c1 { ...@@ -315,12 +447,25 @@ client c1 {
rxresp rxresp
expect resp.status == 200 expect resp.status == 200
expect resp.http.Foo == "XXXXXXX" expect resp.http.Foo == "XXXXXXX"
expect resp.http.Check-Noarg == true
expect resp.http.Check-Unique == true
expect resp.http.Check-Exact == true
expect resp.http.Check-First == true
expect resp.http.Check-Last == true
expect resp.http.Check-Longest == true
expect resp.http.Check-Shortest == true
expect resp.http.Called == <undef> expect resp.http.Called == <undef>
txreq -hdr "Element: foo" txreq -hdr "Element: foo"
rxresp rxresp
expect resp.status == 200 expect resp.status == 200
expect resp.http.Foo == "XXXXXXX" expect resp.http.Foo == "XXXXXXX"
expect resp.http.Check-Unique == true
expect resp.http.Check-Exact == true
expect resp.http.Check-First == true
expect resp.http.Check-Last == true
expect resp.http.Check-Longest == true
expect resp.http.Check-Shortest == true
expect resp.http.Called == <undef> expect resp.http.Called == <undef>
} -run } -run
...@@ -380,6 +525,17 @@ varnish v1 -vcl { ...@@ -380,6 +525,17 @@ varnish v1 -vcl {
sub vcl_synth { sub vcl_synth {
if (s.hasprefix(req.http.Word)) { if (s.hasprefix(req.http.Word)) {
set resp.http.Check-Noarg = s.check_call();
set resp.http.Check-Unique
= s.check_call(select=UNIQUE);
set resp.http.Check-Exact = s.check_call(select=EXACT);
set resp.http.Check-First = s.check_call(select=FIRST);
set resp.http.Check-Last = s.check_call(select=LAST);
set resp.http.Check-Shortest
= s.check_call(select=SHORTEST);
set resp.http.Check-Longest
= s.check_call(select=LONGEST);
set resp.http.X = "E"; set resp.http.X = "E";
call s.subroutine(select=EXACT); call s.subroutine(select=EXACT);
set resp.http.X = "F"; set resp.http.X = "F";
...@@ -395,10 +551,34 @@ varnish v1 -vcl { ...@@ -395,10 +551,34 @@ varnish v1 -vcl {
} }
} }
logexpect l1 -v v1 -d 0 -g vxid -q "Notice" {
expect 0 * Begin req
expect * = Notice {^vmod_selector: s\.check_call\(select=UNIQUE\): 2 elements were matched$}
expect * = Notice {^vmod_selector: s\.check_call\(select=UNIQUE\): 2 elements were matched$}
expect * = End
expect 0 * Begin req
expect * = Notice {^vmod_selector: s\.check_call\(select=UNIQUE\): 3 elements were matched$}
expect * = Notice {^vmod_selector: s\.check_call\(select=UNIQUE\): 3 elements were matched$}
expect * = End
expect 0 * Begin req
expect * = Notice {^vmod_selector: s\.check_call\(select=UNIQUE\): 4 elements were matched$}
expect * = Notice {^vmod_selector: s\.check_call\(select=UNIQUE\): 4 elements were matched$}
expect * = End
} -start
client c1 { client c1 {
txreq -hdr "Word: foobar" txreq -hdr "Word: foobar"
rxresp rxresp
expect resp.status == 200 expect resp.status == 200
expect resp.http.Check-Noarg == false
expect resp.http.Check-Unique == false
expect resp.http.Check-Exact == true
expect resp.http.Check-First == true
expect resp.http.Check-Last == true
expect resp.http.Check-Longest == true
expect resp.http.Check-Shortest == true
expect resp.http.Foo == "LaS" expect resp.http.Foo == "LaS"
expect resp.http.Foobar == "EFLo" expect resp.http.Foobar == "EFLo"
expect resp.http.Foobarbaz == <undef> expect resp.http.Foobarbaz == <undef>
...@@ -407,6 +587,13 @@ client c1 { ...@@ -407,6 +587,13 @@ client c1 {
txreq -hdr "Word: foobarbaz" txreq -hdr "Word: foobarbaz"
rxresp rxresp
expect resp.status == 200 expect resp.status == 200
expect resp.http.Check-Noarg == false
expect resp.http.Check-Unique == false
expect resp.http.Check-Exact == true
expect resp.http.Check-First == true
expect resp.http.Check-Last == true
expect resp.http.Check-Longest == true
expect resp.http.Check-Shortest == true
expect resp.http.Foo == "LaS" expect resp.http.Foo == "LaS"
expect resp.http.Foobar == <undef> expect resp.http.Foobar == <undef>
expect resp.http.Foobarbaz == "EFLo" expect resp.http.Foobarbaz == "EFLo"
...@@ -415,12 +602,21 @@ client c1 { ...@@ -415,12 +602,21 @@ client c1 {
txreq -hdr "Word: foobarbazquux" txreq -hdr "Word: foobarbazquux"
rxresp rxresp
expect resp.status == 200 expect resp.status == 200
expect resp.http.Check-Noarg == false
expect resp.http.Check-Unique == false
expect resp.http.Check-Exact == true
expect resp.http.Check-First == true
expect resp.http.Check-Last == true
expect resp.http.Check-Longest == true
expect resp.http.Check-Shortest == true
expect resp.http.Foo == "LaS" expect resp.http.Foo == "LaS"
expect resp.http.Foobar == <undef> expect resp.http.Foobar == <undef>
expect resp.http.Foobarbaz == <undef> expect resp.http.Foobarbaz == <undef>
expect resp.http.Foobarbazquux == "EFLo" expect resp.http.Foobarbazquux == "EFLo"
} -run } -run
logexpect l1 -wait
varnish v1 -vcl { varnish v1 -vcl {
import ${vmod_selector}; import ${vmod_selector};
backend b None; backend b None;
...@@ -451,6 +647,8 @@ varnish v1 -vcl { ...@@ -451,6 +647,8 @@ varnish v1 -vcl {
sub vcl_recv { sub vcl_recv {
if (s.hasprefix(req.http.Word)) { if (s.hasprefix(req.http.Word)) {
set req.http.Check-Unique = s.check_call(select=UNIQUE);
set req.http.Check-Exact = s.check_call(select=EXACT);
call s.subroutine(select=EXACT); call s.subroutine(select=EXACT);
call s.subroutine(select=UNIQUE); call s.subroutine(select=UNIQUE);
} }
...@@ -471,6 +669,21 @@ logexpect l1 -v v1 -d 0 -g vxid -q "VCL_Error" { ...@@ -471,6 +669,21 @@ logexpect l1 -v v1 -d 0 -g vxid -q "VCL_Error" {
expect * = End expect * = End
} -start } -start
logexpect l2 -v v1 -d 0 -g vxid -q "Notice" {
expect 0 * Begin req
expect * = Notice {^vmod_selector: s\.check_call\(select=UNIQUE\): 2 elements were matched$}
expect 0 = ReqHeader {^Check-Unique: false$}
expect 0 = ReqHeader {^Check-Exact: true$}
expect * = End
expect 0 * Begin req
expect * = Notice {^vmod_selector: s\.check_call\(select=UNIQUE\): 2 elements were matched$}
expect 0 = ReqHeader {^Check-Unique: false$}
expect 0 = Notice {^vmod_selector: s\.check_call\(select=EXACT\): no element matched exactly$}
expect 0 = ReqHeader {^Check-Exact: false$}
expect * = End
} -start
client c1 { client c1 {
txreq -hdr "Word: foobar" txreq -hdr "Word: foobar"
rxresp rxresp
...@@ -488,6 +701,7 @@ client c1 { ...@@ -488,6 +701,7 @@ client c1 {
} -run } -run
logexpect l1 -wait logexpect l1 -wait
logexpect l2 -wait
varnish v1 -vcl { varnish v1 -vcl {
import ${vmod_selector}; import ${vmod_selector};
...@@ -505,12 +719,14 @@ varnish v1 -vcl { ...@@ -505,12 +719,14 @@ varnish v1 -vcl {
sub vcl_recv { sub vcl_recv {
if (s.match(req.http.Word)) { if (s.match(req.http.Word)) {
set req.http.Check = s.check_call();
call s.subroutine(); call s.subroutine();
} }
return (synth(200)); return (synth(200));
} }
sub vcl_synth { sub vcl_synth {
set resp.http.Check = req.http.Check;
set resp.http.Foo = req.http.Foo; set resp.http.Foo = req.http.Foo;
return (deliver); return (deliver);
} }
...@@ -523,10 +739,18 @@ logexpect l1 -v v1 -d 0 -g vxid -q "VCL_Error" { ...@@ -523,10 +739,18 @@ logexpect l1 -v v1 -d 0 -g vxid -q "VCL_Error" {
expect * = End expect * = End
} -start } -start
logexpect l2 -v v1 -d 0 -g vxid -q "Notice" {
expect 0 * Begin req
expect * = Notice {^vmod_selector: s\.check_call\(\): subroutine not added for element 2$}
expect 0 = ReqHeader {^Check: false$}
expect * = End
} -start
client c1 { client c1 {
txreq -hdr "Word: foo" txreq -hdr "Word: foo"
rxresp rxresp
expect resp.status == 200 expect resp.status == 200
expect resp.http.Check == "true"
expect resp.http.Foo == "called" expect resp.http.Foo == "called"
txreq -hdr "Word: bar" txreq -hdr "Word: bar"
...@@ -537,6 +761,7 @@ client c1 { ...@@ -537,6 +761,7 @@ client c1 {
} -run } -run
logexpect l1 -wait logexpect l1 -wait
logexpect l2 -wait
varnish v1 -errvcl {Symbol not found: 'foo'} { varnish v1 -errvcl {Symbol not found: 'foo'} {
import ${vmod_selector}; import ${vmod_selector};
...@@ -562,6 +787,7 @@ varnish v1 -vcl { ...@@ -562,6 +787,7 @@ varnish v1 -vcl {
} }
sub vcl_recv { sub vcl_recv {
set req.http.Check = s.check_call(element="foo");
call s.subroutine(element="foo"); call s.subroutine(element="foo");
return (synth(200)); return (synth(200));
} }
...@@ -574,6 +800,13 @@ logexpect l1 -v v1 -d 0 -g vxid -q "VCL_Error" { ...@@ -574,6 +800,13 @@ logexpect l1 -v v1 -d 0 -g vxid -q "VCL_Error" {
expect * = End expect * = End
} -start } -start
logexpect l2 -v v1 -d 0 -g vxid -q "Notice" {
expect 0 * Begin req
expect * = Notice {^vmod_selector: Dynamic call to "sub foo\{\}" not allowed from here$}
expect 0 = ReqHeader {^Check: false$}
expect * = End
} -start
client c1 { client c1 {
txreq txreq
rxresp rxresp
...@@ -583,6 +816,7 @@ client c1 { ...@@ -583,6 +816,7 @@ client c1 {
} -run } -run
logexpect l1 -wait logexpect l1 -wait
logexpect l2 -wait
varnish v1 -vcl { varnish v1 -vcl {
import ${vmod_selector}; import ${vmod_selector};
...@@ -598,6 +832,7 @@ varnish v1 -vcl { ...@@ -598,6 +832,7 @@ varnish v1 -vcl {
} }
sub bar { sub bar {
set req.http.Check = s.check_call(element="foo");
call s.subroutine(element="foo"); call s.subroutine(element="foo");
} }
...@@ -614,6 +849,13 @@ logexpect l1 -v v1 -d 0 -g vxid -q "VCL_Error" { ...@@ -614,6 +849,13 @@ logexpect l1 -v v1 -d 0 -g vxid -q "VCL_Error" {
expect * = End expect * = End
} -start } -start
logexpect l2 -v v1 -d 0 -g vxid -q "Notice" {
expect 0 * Begin req
expect * = Notice {^vmod_selector: Recursive dynamic call to "sub foo\{\}"$}
expect 0 = ReqHeader {^Check: false$}
expect * = End
} -start
client c1 { client c1 {
txreq txreq
rxresp rxresp
...@@ -623,3 +865,4 @@ client c1 { ...@@ -623,3 +865,4 @@ client c1 {
} -run } -run
logexpect l1 -wait logexpect l1 -wait
logexpect l2 -wait
...@@ -45,6 +45,13 @@ ...@@ -45,6 +45,13 @@
#define VNOTICE(ctx, fmt, ...) \ #define VNOTICE(ctx, fmt, ...) \
VSLb((ctx)->vsl, SLT_Notice, "vmod_selector: " fmt, __VA_ARGS__) VSLb((ctx)->vsl, SLT_Notice, "vmod_selector: " fmt, __VA_ARGS__)
#define VFAIL_OR_NOTICE(ctx, fail, fmt, ...) do { \
if (fail) \
VFAIL((ctx), fmt, __VA_ARGS__); \
else \
VNOTICE((ctx), fmt, __VA_ARGS__); \
} while(0)
struct entry { struct entry {
unsigned magic; unsigned magic;
#define VMOD_SELECTOR_ENTRY_MAGIC 0x733dbe63 #define VMOD_SELECTOR_ENTRY_MAGIC 0x733dbe63
...@@ -101,4 +108,4 @@ is_added(const struct vmod_selector_set *set, unsigned idx, ...@@ -101,4 +108,4 @@ is_added(const struct vmod_selector_set *set, unsigned idx,
struct match_data * struct match_data *
get_existing_match_data(const struct vrt_ctx *ctx, get_existing_match_data(const struct vrt_ctx *ctx,
const struct vmod_selector_set * const restrict set, const struct vmod_selector_set * const restrict set,
const char * const restrict method); const char * const restrict method, int fail);
...@@ -937,6 +937,12 @@ $Method SUB .subroutine(INT n=0, STRING element=0, ...@@ -937,6 +937,12 @@ $Method SUB .subroutine(INT n=0, STRING element=0,
XXX ... XXX ...
$Method BOOL .check_call(INT n=0, STRING element=0,
ENUM {UNIQUE, EXACT, FIRST, LAST, SHORTEST, LONGEST}
select=UNIQUE)
XXX ...
$Function STRING version() $Function STRING version()
Return the version string for this VMOD. Return the version string for this VMOD.
......
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