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 @@ ...@@ -46,6 +46,8 @@
#define VERR(ctx, fmt, ...) \ #define VERR(ctx, fmt, ...) \
errmsg((ctx), "vmod re2 error: " fmt, __VA_ARGS__) errmsg((ctx), "vmod re2 error: " fmt, __VA_ARGS__)
#define INIT(ctx) (((ctx)->method & VCL_MET_INIT) != 0)
struct vmod_re2_regex { struct vmod_re2_regex {
unsigned magic; unsigned magic;
#define VMOD_RE2_REGEX_MAGIC 0x5c3f6f24 #define VMOD_RE2_REGEX_MAGIC 0x5c3f6f24
...@@ -61,6 +63,7 @@ struct vmod_re2_set { ...@@ -61,6 +63,7 @@ struct vmod_re2_set {
#define VMOD_RE2_SET_MAGIC 0xf6d7b15a #define VMOD_RE2_SET_MAGIC 0xf6d7b15a
vre2set *set; vre2set *set;
char *vcl_name; char *vcl_name;
unsigned compiled;
}; };
typedef struct task_match_t { typedef struct task_match_t {
...@@ -443,8 +446,19 @@ vmod_set_add(VRT_CTX, struct vmod_re2_set *set, VCL_STRING pattern) ...@@ -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(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(set, VMOD_RE2_SET_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) { if ((err = vre2set_add(set->set, pattern)) != NULL) {
VERR(ctx, ERR_PREFIX "Cannot compile '%s': %s", set->vcl_name, VERR(ctx, ERR_PREFIX "Cannot compile '%s': %s", set->vcl_name,
pattern, pattern, err); pattern, pattern, err);
...@@ -463,12 +477,22 @@ vmod_set_compile(VRT_CTX, struct vmod_re2_set *set) ...@@ -463,12 +477,22 @@ vmod_set_compile(VRT_CTX, struct vmod_re2_set *set)
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(set, VMOD_RE2_SET_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) { if ((err = vre2set_compile(set->set)) != NULL) {
VERR(ctx, ERR_PREFIX "%s", set->vcl_name, err); VERR(ctx, ERR_PREFIX "%s", set->vcl_name, err);
return; return;
} }
set->compiled = 1;
} }
#undef ERR_PREFIX #undef ERR_PREFIX
...@@ -486,7 +510,11 @@ vmod_set_match(VRT_CTX, struct vmod_re2_set *set, VCL_STRING subject) ...@@ -486,7 +510,11 @@ vmod_set_match(VRT_CTX, struct vmod_re2_set *set, VCL_STRING subject)
if (subject == NULL) if (subject == NULL)
subject = ""; 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) { if ((err = vre2set_match(set->set, subject, &match)) != NULL) {
VERR(ctx, ERR_PREFIX "%s", set->vcl_name, subject, err); VERR(ctx, ERR_PREFIX "%s", set->vcl_name, subject, err);
return 0; 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