diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2013-07-22 23:02:59 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2013-07-22 23:05:28 +0300 |
commit | 7cc646c790465f6975aafa52626b99d04ac2f62d (patch) | |
tree | 3ed4ed45093ce78750f228c737064f8327ac09c0 | |
parent | 88126134cd43e8da9ade49d18c757c6a41b777bc (diff) | |
download | vmod-tbf-7cc646c790465f6975aafa52626b99d04ac2f62d.tar.gz vmod-tbf-7cc646c790465f6975aafa52626b99d04ac2f62d.tar.bz2 |
New function "check"
* src/vmod_tbf.c (vmod_rate): Use %lu instead of %z
(vmod_check): New function.
* src/vmod_tbf.vcc (check): New function.
* tests/Makefile.am: Add new files.
* tests/test02.vtc: New file.
* tests/test03.vtc: New file.
* tests/time01.vtc: New file.
-rw-r--r-- | src/vmod_tbf.c | 71 | ||||
-rw-r--r-- | src/vmod_tbf.vcc | 1 | ||||
-rw-r--r-- | tests/Makefile.am | 2 | ||||
-rw-r--r-- | tests/test02.vtc | 47 | ||||
-rw-r--r-- | tests/test03.vtc | 71 | ||||
-rw-r--r-- | tests/time01.vtc | 23 |
6 files changed, 213 insertions, 2 deletions
diff --git a/src/vmod_tbf.c b/src/vmod_tbf.c index dab0987..02c26ec 100644 --- a/src/vmod_tbf.c +++ b/src/vmod_tbf.c @@ -337,8 +337,8 @@ vmod_rate(struct sess *sp, const char *key, int cost, double t, int burst_size) if (cost <= bkt->tokens) { res = 1; bkt->tokens -= cost; - debug(2, ("tbf_rate matched %s, tokens left %z", key, - bkt->tokens)); + debug(2, ("tbf_rate matched %s, tokens left %lu", key, + (unsigned long)bkt->tokens)); } else { res = 0; debug(1, ("tbf_rate overlimit on %s", key)); @@ -365,3 +365,70 @@ vmod_rate(struct sess *sp, const char *key, int cost, double t, int burst_size) return res; } + +#define ISWS(c) ((c)==' '||(c)=='\t') + +unsigned +vmod_check(struct sess *sp, const char *key, const char *spec) +{ + double t, v, n; + char *p; +#define SKIPWS(init) for (init; *spec && ISWS(*spec); spec++) + int burst; + + errno = 0; + v = strtod(spec, &p); + if (errno || v < 0) { + syslog(LOG_DAEMON|LOG_ERR, "bad rate: %s", spec); + return false; + } + SKIPWS(spec = p); + if (strncmp(spec, "req", 3)) { + syslog(LOG_DAEMON|LOG_ERR, + "bad rate: expected \"req\", but found \"%s\"", spec); + return false; + } + SKIPWS(spec += 3); + if (*spec != '/') { + syslog(LOG_DAEMON|LOG_ERR, + "bad rate: expected \"/\", but found \"%c\"", *spec); + return false; + } + SKIPWS(++spec); + if (*spec >= '0' && *spec <= '9') { + errno = 0; + n = strtod(spec, &p); + if (errno || n < 0) { + syslog(LOG_DAEMON|LOG_ERR, "bad interval: %s", spec); + return false; + } + spec = p; + } else + n = 1; + SKIPWS(); + + switch (*spec) { + case 0: + case 's': + break; + case 'd': + n *= 24; + case 'h': + n *= 60; + case 'm': + n *= 60; + break; + default: + syslog(LOG_DAEMON|LOG_ERR, "invalid interval specifier: %s", + spec); + return false; + } + + SKIPWS(++spec); + + if (*spec) + syslog(LOG_DAEMON|LOG_WARNING, "garbage after rate spec: %s", + spec); + + return vmod_rate(sp, key, 1, n/v, v/n+1); +} diff --git a/src/vmod_tbf.vcc b/src/vmod_tbf.vcc index babca68..637c4f8 100644 --- a/src/vmod_tbf.vcc +++ b/src/vmod_tbf.vcc @@ -4,6 +4,7 @@ Function VOID open(STRING, STRING) Function VOID close() Function VOID sync() Function BOOL rate(STRING, INT, DURATION, INT) +Function BOOL check(STRING, STRING) Function REAL getla(INT) Function INT systime() Function STRING strftime(STRING, INT) diff --git a/tests/Makefile.am b/tests/Makefile.am index 5826201..383f18a 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,6 +1,8 @@ VMOD_TESTS = \ test00.vtc\ test01.vtc\ + test02.vtc\ + test03.vtc\ time00.vtc EXTRA_DIST=$(VMOD_TESTS) diff --git a/tests/test02.vtc b/tests/test02.vtc new file mode 100644 index 0000000..b957181 --- /dev/null +++ b/tests/test02.vtc @@ -0,0 +1,47 @@ +varnishtest "Test tbf overlimit" + +server s1 { + rxreq + txresp +} -start + +varnish v1 -vcl+backend { + import tbf from "${vmod_topbuild}/src/.libs/libvmod_tbf.so"; + sub vcl_init { + tbf.open("${vmod_topbuild}/tests/tbf.db", "truncate"); + } + sub vcl_fini { + tbf.close(); + } + sub vcl_recv { + if (!tbf.check("url:"+req.url, "4 req/s")) { + error 420 "Overlimit"; + } + return (lookup); + } +} -start + +client c1 { + txreq -url "/" + rxresp + expect resp.status == 200 + txreq -url "/" + rxresp + expect resp.status == 200 + txreq -url "/" + rxresp + expect resp.status == 200 + txreq -url "/" + rxresp + expect resp.status == 200 + txreq -url "/" + rxresp + expect resp.status == 200 + txreq -url "/" + rxresp + expect resp.status == 420 +} + +client c1 -run + + diff --git a/tests/test03.vtc b/tests/test03.vtc new file mode 100644 index 0000000..5ffba9a --- /dev/null +++ b/tests/test03.vtc @@ -0,0 +1,71 @@ +varnishtest "Test tbf flow" + +server s1 { + rxreq + txresp +} -start + +varnish v1 -vcl+backend { + import tbf from "${vmod_topbuild}/src/.libs/libvmod_tbf.so"; + sub vcl_init { + tbf.open("${vmod_topbuild}/tests/tbf.db", "trunc"); + } + sub vcl_fini { + tbf.close(); + } + sub vcl_deliver { + set resp.http.result = tbf.check("url:"+req.url, "4req/s"); + } +} -start + +client c1 { + txreq -url "/" + rxresp + expect resp.http.result == true + + txreq -url "/" + rxresp + expect resp.http.result == true + + txreq -url "/" + rxresp + expect resp.http.result == true + + txreq -url "/" + rxresp + expect resp.http.result == true + + txreq -url "/" + rxresp + expect resp.http.result == true + + txreq -url "/" + rxresp + expect resp.http.result == false + + delay 1.0 + + txreq -url "/" + rxresp + expect resp.http.result == true + + txreq -url "/" + rxresp + expect resp.http.result == true + + txreq -url "/" + rxresp + expect resp.http.result == true + + txreq -url "/" + rxresp + expect resp.http.result == true + + txreq -url "/" + rxresp + expect resp.http.result == false +} + +client c1 -run + + diff --git a/tests/time01.vtc b/tests/time01.vtc new file mode 100644 index 0000000..2325f4c --- /dev/null +++ b/tests/time01.vtc @@ -0,0 +1,23 @@ +varnishtest "Test strftime" + +server s1 { + rxreq + txresp +} -start + +varnish v1 -vcl+backend { + import tbf from "${vmod_topbuild}/src/.libs/libvmod_tbf.so"; + sub vcl_deliver { + set resp.http.result = tbf.strftime("%Y-%m-%d", tbf.systime()); + } +} -start + +client c1 { + txreq + rxresp + expect resp.http.result == 2013 +} + +client c1 -run + + |