]> err.no Git - varnish/commitdiff
Change the way bans/purges are stored, so that each ban has a list of
authorphk <phk@d4fa192b-c00b-0410-8231-f00ffab90ce4>
Tue, 13 Jan 2009 12:30:14 +0000 (12:30 +0000)
committerphk <phk@d4fa192b-c00b-0410-8231-f00ffab90ce4>
Tue, 13 Jan 2009 12:30:14 +0000 (12:30 +0000)
conditions to test.

This paves the way for a much more expressive ban/purge syntax where
things like:

purge req.http.host ~ "web1.com" && req.url ~ "\.png"
purge obj.age > 1w && obj.size > 1MB
purge obj.http.set-cookie ~ "USER=838339" && req.url ~ "\.html"

become possible.

Not quite there yet though.

git-svn-id: svn+ssh://projects.linpro.no/svn/varnish/trunk@3508 d4fa192b-c00b-0410-8231-f00ffab90ce4

varnish-cache/bin/varnishd/cache.h
varnish-cache/bin/varnishd/cache_ban.c
varnish-cache/bin/varnishd/cache_hash.c

index f4d68cd4a806a91f0c421a5f8bff11f9d90492c9..d0df6f9415961c25b8d7e0345c5714162f015724 100644 (file)
@@ -422,7 +422,7 @@ int BAN_Add(struct cli *cli, const char *regexp, int hash);
 void BAN_Init(void);
 void BAN_NewObj(struct object *o);
 void BAN_DestroyObj(struct object *o);
-int BAN_CheckObject(struct object *o, const char *url, const char *hash);
+int BAN_CheckObject(struct object *o, const struct sess *sp);
 
 /* cache_center.c [CNT] */
 void CNT_Session(struct sess *sp);
index f8663f9df8728a204954e1848b9f7ed78d5a9e1d..ebdbd3afbb521df4147bf02c4a65f87341894fe2 100644 (file)
  * $Id$
  *
  * Ban ("purge") processing
+ *
+ * A ban consists of a number of conditions (or tests), all of which must be
+ * satisfied.  Here are some potential bans we could support:
+ *
+ *     req.url == "/foo"
+ *     req.url ~ ".iso" && obj.size > 10MB
+ *     req.http.host ~ "web1.com" && obj.set-cookie ~ "USER=29293"
+ *
+ * We make the "&&" mandatory from the start, leaving the syntax space 
+ * for latter handling of "||" as well.
+ *
  */
 
 #include "config.h"
 #include "cli.h"
 #include "cli_priv.h"
 #include "cache.h"
+#include "hash_slinger.h"
+
+struct ban_test;
+
+/* A ban-testing function */
+typedef int ban_cond_f(const struct ban_test *bt, const struct object *o, const struct sess *sp);
+
+/* Each individual test to be performed on a ban */
+struct ban_test {
+       unsigned                magic;
+#define BAN_TEST_MAGIC         0x54feec67
+       VTAILQ_ENTRY(ban_test)  list;
+       int                     cost;
+       ban_cond_f              *func;
+       regex_t                 re;
+};
 
 struct ban {
        unsigned                magic;
@@ -51,14 +78,104 @@ struct ban {
        unsigned                refcount;
        int                     flags;
 #define BAN_F_GONE             (1 << 0)
-       regex_t                 regexp;
        char                    *ban;
        int                     hash;
+       VTAILQ_HEAD(,ban_test)  tests;
 };
 
 static VTAILQ_HEAD(banhead,ban) ban_head = VTAILQ_HEAD_INITIALIZER(ban_head);
 static struct lock ban_mtx;
 
+/*--------------------------------------------------------------------
+ * Manipulation of bans
+ */
+
+static struct ban *
+ban_new_ban(void)
+{
+       struct ban *b;
+       ALLOC_OBJ(b, BAN_MAGIC);
+       if (b == NULL)
+               return (b);
+       VTAILQ_INIT(&b->tests);
+       return (b);
+}
+
+static struct ban_test *
+ban_add_test(struct ban *b)
+{
+       struct ban_test *bt;
+
+       CHECK_OBJ_NOTNULL(b, BAN_MAGIC);
+       ALLOC_OBJ(bt, BAN_TEST_MAGIC);
+       if (bt == NULL)
+               return (bt);
+       VTAILQ_INSERT_TAIL(&b->tests, bt, list);
+       return (bt);
+}
+
+static void
+ban_sort_by_cost(struct ban *b)
+{
+       struct ban_test *bt, *btn;
+       int i;
+
+       CHECK_OBJ_NOTNULL(b, BAN_MAGIC);
+
+       do {
+               i = 0;
+               VTAILQ_FOREACH(bt, &b->tests, list) {
+                       btn = VTAILQ_NEXT(bt, list);
+                       if (btn != NULL && btn->cost < bt->cost) {
+                               VTAILQ_REMOVE(&b->tests, bt, list);
+                               VTAILQ_INSERT_AFTER(&b->tests, btn, bt, list);
+                               i++;
+                       }
+               }
+       } while (i);
+}
+
+static void
+ban_free_ban(struct ban *b)
+{
+       struct ban_test *bt;
+
+       CHECK_OBJ_NOTNULL(b, BAN_MAGIC);
+       while (!VTAILQ_EMPTY(&b->tests)) {
+               bt = VTAILQ_FIRST(&b->tests);
+               VTAILQ_REMOVE(&b->tests, bt, list);
+               FREE_OBJ(bt);
+       }
+       FREE_OBJ(b);
+}
+
+/*--------------------------------------------------------------------
+ * Test functions -- return 0 if the test does not match
+ */
+
+static int
+ban_cond_url_regexp(const struct ban_test *bt, const struct object *o,
+   const struct sess *sp)
+{
+       (void)o;
+       return (!regexec(&bt->re, sp->http->hd[HTTP_HDR_URL].b, 0, NULL, 0));
+}
+
+static int
+ban_cond_hash_regexp(const struct ban_test *bt, const struct object *o,
+   const struct sess *sp)
+{
+       (void)sp;
+       CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
+       CHECK_OBJ_NOTNULL(o->objhead, OBJHEAD_MAGIC);
+       AN(o->objhead->hash);
+       return (!regexec(&bt->re, o->objhead->hash, 0, NULL, 0));
+}
+
+/*--------------------------------------------------------------------
+ */
+
+
 /*
  * We maintain ban_start as a pointer to the first element of the list
  * as a separate variable from the VTAILQ, to avoid depending on the
@@ -71,25 +188,41 @@ int
 BAN_Add(struct cli *cli, const char *regexp, int hash)
 {
        struct ban *b, *bi, *be;
+       struct ban_test *bt;
        char buf[512];
        unsigned pcount;
        int i;
 
-       ALLOC_OBJ(b, BAN_MAGIC);
+       b = ban_new_ban();
        if (b == NULL) {
                cli_out(cli, "Out of Memory");
                cli_result(cli, CLIS_CANT);
                return (-1);
        }
 
-       i = regcomp(&b->regexp, regexp, REG_EXTENDED | REG_ICASE | REG_NOSUB);
+       bt = ban_add_test(b);
+       if (bt == NULL) {
+               cli_out(cli, "Out of Memory");
+               cli_result(cli, CLIS_CANT);
+               ban_free_ban(b);
+               return (-1);
+       }
+
+       ban_sort_by_cost(b);
+
+       if (hash)
+               bt->func = ban_cond_hash_regexp;
+       else
+               bt->func = ban_cond_url_regexp;
+               
+       i = regcomp(&bt->re, regexp, REG_EXTENDED | REG_ICASE | REG_NOSUB);
        if (i) {
-               (void)regerror(i, &b->regexp, buf, sizeof buf);
-               regfree(&b->regexp);
+               (void)regerror(i, &bt->re, buf, sizeof buf);
+               regfree(&bt->re);
                VSL(SLT_Debug, 0, "REGEX: <%s>", buf);
                cli_out(cli, "%s", buf);
                cli_result(cli, CLIS_PARAM);
-               FREE_OBJ(b);
+               ban_free_ban(b);
                return (-1);
        }
        b->hash = hash;
@@ -169,21 +302,20 @@ BAN_DestroyObj(struct object *o)
                b = NULL;
        }
        Lck_Unlock(&ban_mtx);
-       if (b != NULL) {
-               free(b->ban);
-               regfree(&b->regexp);
-               FREE_OBJ(b);
-       }
+       if (b != NULL)
+               ban_free_ban(b);
 
 }
 
 int
-BAN_CheckObject(struct object *o, const char *url, const char *hash)
+BAN_CheckObject(struct object *o, const struct sess *sp)
 {
        struct ban *b;
+       struct ban_test *bt;
        struct ban * volatile b0;
        unsigned tests;
 
+       CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
        CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
        CHECK_OBJ_NOTNULL(o->ban, BAN_MAGIC);
 
@@ -199,9 +331,14 @@ BAN_CheckObject(struct object *o, const char *url, const char *hash)
         */
        tests = 0;
        for (b = b0; b != o->ban; b = VTAILQ_NEXT(b, list)) {
-               tests++;
-               if (!(b->flags & BAN_F_GONE) &&
-                   !regexec(&b->regexp, b->hash ? hash : url, 0, NULL, 0))
+               if (b->flags & BAN_F_GONE)
+                       continue;
+               VTAILQ_FOREACH(bt, &b->tests, list) {
+                       tests++;
+                       if (bt->func(bt, o, sp))
+                               break;
+               }
+               if (bt != NULL)
                        break;
        }
 
@@ -226,6 +363,17 @@ BAN_CheckObject(struct object *o, const char *url, const char *hash)
  * CLI functions to add bans
  */
 
+#if 0
+static void
+ccf_purge(struct cli *cli, const char * const *av, void *priv)
+{
+
+       (void)priv;
+       (void)av;
+       (void)cli;
+}
+#endif
+
 static void
 ccf_purge_url(struct cli *cli, const char * const *av, void *priv)
 {
@@ -277,6 +425,9 @@ static struct cli_proto ban_cmds[] = {
 
        { CLI_PURGE_URL,                        ccf_purge_url },
        { CLI_PURGE_HASH,                       ccf_purge_hash },
+#if 0
+       { CLI_PURGE,                            ccf_purge },
+#endif
        { CLI_PURGE_LIST,                       ccf_purge_list },
        { NULL }
 };
index f95cd3f3cd1b00d2dac7e7c4c3ce5ed5eb80ab76..112b41f2d66b785172b90b8b91a691fbd167bf6f 100644 (file)
@@ -255,7 +255,7 @@ HSH_Lookup(struct sess *sp)
                        continue;
                if (o->ttl == 0)
                        continue;
-               if (BAN_CheckObject(o, h->hd[HTTP_HDR_URL].b, oh->hash)) {
+               if (BAN_CheckObject(o, sp)) {
                        o->ttl = 0;
                        WSP(sp, SLT_ExpBan, "%u was banned", o->xid);
                        EXP_Rearm(o);