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

Add the .subroutine() method.

parent ce05494e
......@@ -879,7 +879,7 @@ Example:
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(
STRING,
......@@ -887,7 +887,8 @@ Example:
[BACKEND backend],
[BOOL save],
[BOOL never_capture],
[INT integer]
[INT integer],
[SUB sub]
)
Add the given pattern to the set. If the pattern is invalid, `.add()`
......@@ -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 {REGEX, STR, BE, INT} which=REGEX,
ENUM {REGEX, STR, BE, INT, SUB} which=REGEX,
INT n=0,
ENUM {FIRST, LAST, UNIQUE} select=UNIQUE
)
......
......@@ -40,6 +40,7 @@ enum bitmap_e {
BACKEND,
REGEX,
INTEGER,
SUBROUTINE,
__MAX_BITMAP,
};
......@@ -69,6 +70,7 @@ struct vmod_re2_set {
VCL_BACKEND *backend;
struct vmod_re2_regex **regex;
VCL_INT *integer;
VCL_SUB *sub;
struct set_options opts;
unsigned compiled;
int npatterns;
......@@ -386,6 +388,17 @@ vmod_set_add(VRT_CTX, struct vmod_re2_set *set, struct VARGS(set_add) *args)
set->regex[n] = re;
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++;
}
......@@ -741,6 +754,34 @@ vmod_set_integer(VRT_CTX, struct vmod_re2_set *set, VCL_INT n, VCL_ENUM selects)
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
vmod_set_saved(VRT_CTX, struct vmod_re2_set *set, VCL_ENUM whichs, VCL_INT n,
VCL_ENUM selects)
......@@ -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);
if (whichs == VENUM(INT))
return vbit_test(set->added[INTEGER], idx);
if (whichs == VENUM(SUB))
return vbit_test(set->added[SUBROUTINE], idx);
WRONG("illegal which ENUM");
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::
}
$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()`` fails, and the VCL will fail to load, with an error message
......@@ -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)
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