Commit ce15e3dd authored by Geoff Simmons's avatar Geoff Simmons

enforce usage constraints on set object methods: .add() and .compile()

must be called in vcl_init, all .add()s before .compile(), .compile()
exactly once, and .match() fails if .compile() was not called
parent afe1479b
# looks like -*- vcl -*-
varnishtest "legal usage of the set object interface"
varnish v1 -vcl { backend b { .host = "${bad_ip}"; } } -start
varnish v1 -errvcl {vmod re2 error: s.add("bar"): s has already been compiled} {
import re2 from "${vmod_topbuild}/src/.libs/libvmod_re2.so";
backend b { .host = "${bad_ip}"; }
sub vcl_init {
new s = re2.set();
s.add("foo");
s.compile();
s.add("bar");
}
}
varnish v1 -errvcl {vmod re2 error: s.compile(): s has already been compiled} {
import re2 from "${vmod_topbuild}/src/.libs/libvmod_re2.so";
backend b { .host = "${bad_ip}"; }
sub vcl_init {
new s = re2.set();
s.add("foo");
s.compile();
s.compile();
}
}
varnish v1 -vcl {
import re2 from "${vmod_topbuild}/src/.libs/libvmod_re2.so";
backend b { .host = "${bad_ip}"; }
sub vcl_init {
new s = re2.set();
s.add("foo");
}
sub vcl_recv {
return(synth(200));
}
sub vcl_synth {
if (s.match("foo")) {
set resp.http.foo = "match";
}
}
}
client c1 {
txreq
rxresp
expect resp.status == 200
expect resp.http.foo == <undef>
} -run
logexpect l1 -v v1 -d 1 -g vxid -q "VCL_Error" {
expect 0 * Begin req
expect * = VCL_Error "^vmod re2 error: s.match..foo..: s was not compiled$"
expect * = End
} -run
# Safe to call .match() in vcl_init
varnish v1 -vcl {
import re2 from "${vmod_topbuild}/src/.libs/libvmod_re2.so";
backend b { .host = "${bad_ip}"; }
sub vcl_init {
new s = re2.set();
s.add("foo");
s.compile();
if (s.match("foo")) {
new bar = re2.set();
bar.add("bar");
bar.compile();
}
}
sub vcl_recv {
return(synth(200));
}
sub vcl_synth {
if (bar.match("bar")) {
set resp.http.bar = "match";
}
}
}
client c1 {
txreq
rxresp
expect resp.status == 200
expect resp.http.bar == "match"
} -run
varnish v1 -vcl {
import re2 from "${vmod_topbuild}/src/.libs/libvmod_re2.so";
backend b { .host = "${bad_ip}"; }
sub vcl_init {
new s = re2.set();
}
sub vcl_recv {
return(synth(200));
}
sub vcl_synth {
s.add("foo");
s.compile();
if (s.match("foo")) {
set resp.http.foo = "match";
}
}
}
logexpect l2 -v v1 -d 0 -g vxid -q "VCL_Error" {
expect 0 * Begin req
expect * = VCL_Error "^vmod re2 error: s.add..foo..: .add.. may only be called in vcl_init$"
expect * = VCL_Error "^vmod re2 error: s.compile..: .compile.. may only be called in vcl_init$"
expect * = VCL_Error "^vmod re2 error: s.match..foo..: s was not compiled$"
expect * = End
} -start
client c1 {
txreq
rxresp
expect resp.status == 200
} -run
logexpect l2 -wait
......@@ -46,6 +46,8 @@
#define VERR(ctx, fmt, ...) \
errmsg((ctx), "vmod re2 error: " fmt, __VA_ARGS__)
#define INIT(ctx) (((ctx)->method & VCL_MET_INIT) != 0)
struct vmod_re2_regex {
unsigned magic;
#define VMOD_RE2_REGEX_MAGIC 0x5c3f6f24
......@@ -61,6 +63,7 @@ struct vmod_re2_set {
#define VMOD_RE2_SET_MAGIC 0xf6d7b15a
vre2set *set;
char *vcl_name;
unsigned compiled;
};
typedef struct task_match_t {
......@@ -443,8 +446,19 @@ vmod_set_add(VRT_CTX, struct vmod_re2_set *set, VCL_STRING pattern)
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(set, VMOD_RE2_SET_MAGIC);
if (pattern == NULL)
pattern = "";
if (!INIT(ctx)) {
VERR(ctx, ERR_PREFIX ".add() may only be called in vcl_init",
set->vcl_name, pattern);
return;
}
/* XXX: check if compiled */
if (set->compiled) {
VERR(ctx, ERR_PREFIX "%s has already been compiled",
set->vcl_name, pattern, set->vcl_name);
return;
}
if ((err = vre2set_add(set->set, pattern)) != NULL) {
VERR(ctx, ERR_PREFIX "Cannot compile '%s': %s", set->vcl_name,
pattern, pattern, err);
......@@ -463,12 +477,22 @@ vmod_set_compile(VRT_CTX, struct vmod_re2_set *set)
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(set, VMOD_RE2_SET_MAGIC);
if (!INIT(ctx)) {
VERR(ctx, ERR_PREFIX ".compile() may only be called in "
"vcl_init", set->vcl_name);
return;
}
/* XXX: check if compiled */
if (set->compiled) {
VERR(ctx, ERR_PREFIX "%s has already been compiled",
set->vcl_name, set->vcl_name);
return;
}
if ((err = vre2set_compile(set->set)) != NULL) {
VERR(ctx, ERR_PREFIX "%s", set->vcl_name, err);
return;
}
set->compiled = 1;
}
#undef ERR_PREFIX
......@@ -486,7 +510,11 @@ vmod_set_match(VRT_CTX, struct vmod_re2_set *set, VCL_STRING subject)
if (subject == NULL)
subject = "";
/* XXX: check if compiled */
if (!set->compiled) {
VERR(ctx, ERR_PREFIX "%s was not compiled", set->vcl_name,
subject, set->vcl_name);
return 0;
}
if ((err = vre2set_match(set->set, subject, &match)) != NULL) {
VERR(ctx, ERR_PREFIX "%s", set->vcl_name, subject, err);
return 0;
......
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