Commit 1ccec57c authored by Geoff Simmons's avatar Geoff Simmons

Add the .subroutine() method.

parent ce05494e
...@@ -879,7 +879,7 @@ Example: ...@@ -879,7 +879,7 @@ Example:
perl_classes=true); perl_classes=true);
} }
#### VOID xset.add(STRING, \[STRING string\], \[BACKEND backend\], \[BOOL save\], \[BOOL never\_capture\], \[INT integer\]) #### VOID xset.add(STRING, \[STRING string\], \[BACKEND backend\], \[BOOL save\], \[BOOL never\_capture\], \[INT integer\], \[SUB sub\])
VOID xset.add( VOID xset.add(
STRING, STRING,
...@@ -887,7 +887,8 @@ Example: ...@@ -887,7 +887,8 @@ Example:
[BACKEND backend], [BACKEND backend],
[BOOL save], [BOOL save],
[BOOL never_capture], [BOOL never_capture],
[INT integer] [INT integer],
[SUB sub]
) )
Add the given pattern to the set. If the pattern is invalid, `.add()` Add the given pattern to the set. If the pattern is invalid, `.add()`
...@@ -1523,10 +1524,19 @@ Example: ...@@ -1523,10 +1524,19 @@ Example:
} }
} }
#### SUB xset.subroutine(INT n, ENUM select)
SUB xset.subroutine(
INT n=0,
ENUM {FIRST, LAST, UNIQUE} select=UNIQUE
)
XXX ...
#### BOOL xset.saved(ENUM which, INT n, ENUM select) #### BOOL xset.saved(ENUM which, INT n, ENUM select)
BOOL xset.saved( BOOL xset.saved(
ENUM {REGEX, STR, BE, INT} which=REGEX, ENUM {REGEX, STR, BE, INT, SUB} which=REGEX,
INT n=0, INT n=0,
ENUM {FIRST, LAST, UNIQUE} select=UNIQUE ENUM {FIRST, LAST, UNIQUE} select=UNIQUE
) )
......
...@@ -40,6 +40,7 @@ enum bitmap_e { ...@@ -40,6 +40,7 @@ enum bitmap_e {
BACKEND, BACKEND,
REGEX, REGEX,
INTEGER, INTEGER,
SUBROUTINE,
__MAX_BITMAP, __MAX_BITMAP,
}; };
...@@ -69,6 +70,7 @@ struct vmod_re2_set { ...@@ -69,6 +70,7 @@ struct vmod_re2_set {
VCL_BACKEND *backend; VCL_BACKEND *backend;
struct vmod_re2_regex **regex; struct vmod_re2_regex **regex;
VCL_INT *integer; VCL_INT *integer;
VCL_SUB *sub;
struct set_options opts; struct set_options opts;
unsigned compiled; unsigned compiled;
int npatterns; int npatterns;
...@@ -386,6 +388,17 @@ vmod_set_add(VRT_CTX, struct vmod_re2_set *set, struct VARGS(set_add) *args) ...@@ -386,6 +388,17 @@ vmod_set_add(VRT_CTX, struct vmod_re2_set *set, struct VARGS(set_add) *args)
set->regex[n] = re; set->regex[n] = re;
vbit_set(set->added[REGEX], n); vbit_set(set->added[REGEX], n);
} }
if (args->valid_sub) {
if ((set->sub = realloc(set->sub,
(n + 1) * (sizeof(VCL_SUB))))
== NULL) {
VERRNOMEM(ctx, ERR_PREFIX "adding subroutine",
set->vcl_name, pattern);
return;
}
set->sub[n] = args->sub;
vbit_set(set->added[SUBROUTINE], n);
}
set->npatterns++; set->npatterns++;
} }
...@@ -741,6 +754,34 @@ vmod_set_integer(VRT_CTX, struct vmod_re2_set *set, VCL_INT n, VCL_ENUM selects) ...@@ -741,6 +754,34 @@ vmod_set_integer(VRT_CTX, struct vmod_re2_set *set, VCL_INT n, VCL_ENUM selects)
return set->integer[idx]; return set->integer[idx];
} }
VCL_SUB
vmod_set_subroutine(VRT_CTX, struct VPFX(re2_set) *set, VCL_INT n,
VCL_ENUM selects)
{
int idx;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(set, VMOD_RE2_SET_MAGIC);
if (set->sub == NULL) {
VRT_fail(ctx,
"%s.subroutine(%jd): No subroutines were set for %s",
set->vcl_name, (intmax_t)n, set->vcl_name);
return (NULL);
}
idx = get_match_idx(ctx, set, n, selects, "subroutine");
if (idx < 0)
return (0);
if (!vbit_test(set->added[SUBROUTINE], idx)) {
AN(selects);
VRT_fail(ctx,
"%s.subroutine(%jd, %s): subroutine %d was not added",
set->vcl_name, n, selects, idx + 1);
return (NULL);
}
return set->sub[idx];
}
VCL_BOOL VCL_BOOL
vmod_set_saved(VRT_CTX, struct vmod_re2_set *set, VCL_ENUM whichs, VCL_INT n, vmod_set_saved(VRT_CTX, struct vmod_re2_set *set, VCL_ENUM whichs, VCL_INT n,
VCL_ENUM selects) VCL_ENUM selects)
...@@ -761,6 +802,8 @@ vmod_set_saved(VRT_CTX, struct vmod_re2_set *set, VCL_ENUM whichs, VCL_INT n, ...@@ -761,6 +802,8 @@ vmod_set_saved(VRT_CTX, struct vmod_re2_set *set, VCL_ENUM whichs, VCL_INT n,
return vbit_test(set->added[STRING], idx); return vbit_test(set->added[STRING], idx);
if (whichs == VENUM(INT)) if (whichs == VENUM(INT))
return vbit_test(set->added[INTEGER], idx); return vbit_test(set->added[INTEGER], idx);
if (whichs == VENUM(SUB))
return vbit_test(set->added[SUBROUTINE], idx);
WRONG("illegal which ENUM"); WRONG("illegal which ENUM");
return 0; return 0;
} }
......
# looks like -*- vcl -*-
varnishtest "set .subroutine() and .check_call() methods"
server s1 {
rxreq
txresp
} -start
varnish v1 -vcl+backend {
import ${vmod_re2};
sub foo {
if (!resp.http.Foo) {
set resp.http.Foo = resp.http.X;
}
else {
set resp.http.Foo = resp.http.Foo + resp.http.X;
}
}
sub bar {
if (!resp.http.Bar) {
set resp.http.Bar = resp.http.X;
}
else {
set resp.http.Bar = resp.http.Bar + resp.http.X;
}
}
sub vcl_init {
new s = re2.set();
s.add("foo", sub=foo);
s.add("bar", sub=bar);
}
sub vcl_deliver {
set resp.http.X = "N";
call s.subroutine(1);
call s.subroutine(2);
set resp.http.s-saved-1 = s.saved(SUB, 1);
set resp.http.s-saved-2 = s.saved(SUB, 2);
if (req.http.Test == "b4match") {
if (req.http.Call == "subroutine") {
call s.subroutine();
}
if (req.http.Call == "saved") {
set resp.http.s-saved-before-match =
s.saved(SUB);
}
}
set resp.http.s-foo-match = s.match("foo");
set resp.http.s-foo-n = s.nmatches();
set resp.http.X = "F";
call s.subroutine();
set resp.http.s-foo-saved = s.saved(SUB);
set resp.http.s-bar-match = s.match("bar");
set resp.http.s-bar-n = s.nmatches();
set resp.http.X = "B";
call s.subroutine();
set resp.http.s-bar-saved = s.saved(SUB);
call s.subroutine(0);
call s.subroutine(-1);
set resp.http.s-bar-saved-0 = s.saved(SUB, 0);
set resp.http.s-bar-saved-1 = s.saved(SUB, -1);
set resp.http.s-fail-match = s.match("fail");
set resp.http.s-fail-n = s.nmatches();
if (req.http.Test == "failmatch") {
set resp.http.X = "X";
if (req.http.Call == "subroutine") {
call s.subroutine();
}
if (req.http.Call == "saved") {
set resp.http.s-fail-saved = s.saved(SUB);
}
}
set resp.http.s-many-match = s.match("foobar");
set resp.http.s-many-n = s.nmatches();
set resp.http.X = "2";
call s.subroutine(select=FIRST);
call s.subroutine(select=LAST);
set resp.http.s-many-saved-first = s.saved(SUB, select=FIRST);
set resp.http.s-many-saved-last = s.saved(SUB, select=FIRST);
if (req.http.Test == "manymatch") {
set resp.http.X = "!";
if (req.http.Call == "subroutine") {
call s.subroutine();
}
if (req.http.Call == "saved") {
set resp.http.s-many-saved = s.saved(SUB);
}
}
if (req.http.Test == "range") {
set resp.http.X = "3";
call s.subroutine(3);
}
}
} -start
client c1 {
txreq
rxresp
expect resp.status == 200
expect resp.http.Foo == "NF2"
expect resp.http.Bar == "NBBB2"
expect resp.http.s-saved-1 == "true"
expect resp.http.s-saved-2 == "true"
expect resp.http.s-foo-match == "true"
expect resp.http.s-foo-n == 1
expect resp.http.s-foo-saved == "true"
expect resp.http.s-bar-match == "true"
expect resp.http.s-bar-n == 1
expect resp.http.s-bar-saved == "true"
expect resp.http.s-bar-saved-0 == "true"
expect resp.http.s-bar-saved-1 == "true"
expect resp.http.s-fail-match == "false"
expect resp.http.s-fail-n == 0
expect resp.http.s-many-match == "true"
expect resp.http.s-many-n == 2
expect resp.http.s-many-saved-first == "true"
expect resp.http.s-many-saved-last == "true"
} -run
client c1 {
txreq -hdr "Test: b4match" -hdr "Call: subroutine"
rxresp
expect resp.status == 503
expect resp.reason == "VCL failed"
expect resp.http.Foo == <undef>
expect resp.http.Bar == <undef>
expect_close
} -run
client c1 {
txreq -hdr "Test: b4match" -hdr "Call: saved"
rxresp
expect resp.status == 503
expect resp.reason == "VCL failed"
expect resp.http.s-saved-before-match == <undef>
expect_close
} -run
client c1 {
txreq -hdr "Test: failmatch" -hdr "Call: subroutine"
rxresp
expect resp.status == 503
expect resp.reason == "VCL failed"
expect resp.http.Foo == <undef>
expect resp.http.Bar == <undef>
expect_close
} -run
client c1 {
txreq -hdr "Test: failmatch" -hdr "Call: saved"
rxresp
expect resp.status == 503
expect resp.reason == "VCL failed"
expect resp.http.s-fail-saved == <undef>
expect_close
} -run
client c1 {
txreq -hdr "Test: manymatch" -hdr "Call: subroutine"
rxresp
expect resp.status == 503
expect resp.reason == "VCL failed"
expect resp.http.Foo == <undef>
expect resp.http.Bar == <undef>
expect_close
} -run
client c1 {
txreq -hdr "Test: manymatch" -hdr "Call: saved"
rxresp
expect resp.status == 503
expect resp.reason == "VCL failed"
expect resp.http.s-many-saved == <undef>
expect_close
} -run
client c1 {
txreq -hdr "Test: range"
rxresp
expect resp.status == 503
expect resp.reason == "VCL failed"
expect resp.http.Foo == <undef>
expect resp.http.Bar == <undef>
expect_close
} -run
logexpect l1 -v v1 -d 1 -g vxid -q "VCL_Error" {
expect 0 * Begin req
expect * = ReqHeader {^Test: b4match$}
expect * = ReqHeader {^Call: subroutine$}
expect * = VCL_Error {^vmod re2 failure: s\.subroutine\(\) called without prior match$}
expect 0 = VCL_return fail
expect * = End
expect 0 * Begin req
expect * = ReqHeader {^Test: b4match$}
expect * = ReqHeader {^Call: saved$}
expect * = VCL_Error {^vmod re2 failure: s\.saved\(\) called without prior match$}
expect 0 = RespHeader {^s-saved-before-match: false$}
expect 0 = VCL_return fail
expect * = End
expect 0 * Begin req
expect * = ReqHeader {^Test: failmatch$}
expect * = ReqHeader {^Call: subroutine$}
expect * = VCL_Error {^vmod re2 failure: s\.subroutine\(0\): previous match was unsuccessful$}
expect 0 = VCL_return fail
expect * = End
expect 0 * Begin req
expect * = ReqHeader {^Test: failmatch$}
expect * = ReqHeader {^Call: saved$}
expect * = VCL_Error {^vmod re2 failure: s\.saved\(0\): previous match was unsuccessful$}
expect 0 = RespHeader {^s-fail-saved: false$}
expect 0 = VCL_return fail
expect * = End
expect 0 * Begin req
expect * = ReqHeader {^Test: manymatch$}
expect * = ReqHeader {^Call: subroutine$}
expect * = VCL_Error {^vmod re2 failure: s\.subroutine\(0\): 2 successful matches$}
expect 0 = VCL_return fail
expect * = End
expect 0 * Begin req
expect * = ReqHeader {^Test: manymatch$}
expect * = ReqHeader {^Call: saved$}
expect * = VCL_Error {^vmod re2 failure: s\.saved\(0\): 2 successful matches$}
expect 0 = RespHeader {^s-many-saved: false$}
expect 0 = VCL_return fail
expect * = End
expect 0 * Begin req
expect * = ReqHeader {^Test: range$}
expect * = VCL_Error {^vmod re2 failure: s\.subroutine\(3\): set has 2 patterns$}
expect 0 = VCL_return fail
expect * = End
} -run
...@@ -770,7 +770,7 @@ Example:: ...@@ -770,7 +770,7 @@ Example::
} }
$Method VOID .add(STRING, [STRING string], [BACKEND backend], [BOOL save], $Method VOID .add(STRING, [STRING string], [BACKEND backend], [BOOL save],
[BOOL never_capture], [INT integer]) [BOOL never_capture], [INT integer], [SUB sub])
Add the given pattern to the set. If the pattern is invalid, Add the given pattern to the set. If the pattern is invalid,
``.add()`` fails, and the VCL will fail to load, with an error message ``.add()`` fails, and the VCL will fail to load, with an error message
...@@ -1397,7 +1397,11 @@ Example:: ...@@ -1397,7 +1397,11 @@ Example::
} }
} }
$Method BOOL .saved(ENUM {REGEX, STR, BE, INT} which=REGEX, INT n=0, $Method SUB .subroutine(INT n=0, ENUM {FIRST, LAST, UNIQUE} select=UNIQUE)
XXX ...
$Method BOOL .saved(ENUM {REGEX, STR, BE, INT, SUB} which=REGEX, INT n=0,
ENUM {FIRST, LAST, UNIQUE} select=UNIQUE) ENUM {FIRST, LAST, UNIQUE} select=UNIQUE)
Returns true if and only if an object of the type indicated by Returns true if and only if an object of the type indicated by
......
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