]> err.no Git - varnish/commitdiff
Commit the old urge facilities to the new world order.
authorphk <phk@d4fa192b-c00b-0410-8231-f00ffab90ce4>
Tue, 13 Jan 2009 14:05:54 +0000 (14:05 +0000)
committerphk <phk@d4fa192b-c00b-0410-8231-f00ffab90ce4>
Tue, 13 Jan 2009 14:05:54 +0000 (14:05 +0000)
git-svn-id: svn+ssh://projects.linpro.no/svn/varnish/trunk@3509 d4fa192b-c00b-0410-8231-f00ffab90ce4

varnish-cache/bin/varnishd/cache_ban.c

index ebdbd3afbb521df4147bf02c4a65f87341894fe2..2db21feafc4e853f8131388e32d2d1f441a15265 100644 (file)
@@ -46,6 +46,7 @@
 
 #include <sys/types.h>
 
+#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <regex.h>
@@ -67,6 +68,7 @@ struct ban_test {
 #define BAN_TEST_MAGIC         0x54feec67
        VTAILQ_ENTRY(ban_test)  list;
        int                     cost;
+       char                    *test;
        ban_cond_f              *func;
        regex_t                 re;
 };
@@ -78,8 +80,6 @@ struct ban {
        unsigned                refcount;
        int                     flags;
 #define BAN_F_GONE             (1 << 0)
-       char                    *ban;
-       int                     hash;
        VTAILQ_HEAD(,ban_test)  tests;
 };
 
@@ -144,11 +144,45 @@ ban_free_ban(struct ban *b)
        while (!VTAILQ_EMPTY(&b->tests)) {
                bt = VTAILQ_FIRST(&b->tests);
                VTAILQ_REMOVE(&b->tests, bt, list);
+               free(bt->test);
+               regfree(&bt->re);
                FREE_OBJ(bt);
        }
        FREE_OBJ(b);
 }
 
+/*
+ * Return zero of the two bans have the same components
+ *
+ * XXX: Looks too expensive for my taste.
+ */
+
+static int
+ban_compare(const struct ban *b1, const struct ban *b2)
+{
+       struct ban_test *bt1, *bt2;
+       int n, m;
+
+       CHECK_OBJ_NOTNULL(b1, BAN_MAGIC);
+       CHECK_OBJ_NOTNULL(b2, BAN_MAGIC);
+
+       n = 0;
+       VTAILQ_FOREACH(bt1, &b1->tests, list) {
+               n++;
+               VTAILQ_FOREACH(bt2, &b2->tests, list)
+                       if (!strcmp(bt1->test, bt2->test))
+                               break;
+               if (bt2 == NULL)
+                       return (1);
+       }
+       m = 0;
+       VTAILQ_FOREACH(bt2, &b2->tests, list)
+               m++;
+       if (m != n)
+               return (1);
+       return (0);
+}
+
 /*--------------------------------------------------------------------
  * Test functions -- return 0 if the test does not match
  */
@@ -173,61 +207,78 @@ ban_cond_hash_regexp(const struct ban_test *bt, const struct object *o,
 }
 
 /*--------------------------------------------------------------------
+ * Parse and add a ban test specification
  */
 
-
-/*
- * 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
- * internals of the VTAILQ macros.  We tacitly assume that a pointer
- * write is always atomic in doing so.
- */
-static struct ban * volatile ban_start;
-
-int
-BAN_Add(struct cli *cli, const char *regexp, int hash)
+static int
+ban_parse_test(struct cli *cli, struct ban *b, const char *a1, const char *a2, const char *a3)
 {
-       struct ban *b, *bi, *be;
        struct ban_test *bt;
        char buf[512];
-       unsigned pcount;
        int i;
 
-       b = ban_new_ban();
-       if (b == NULL) {
-               cli_out(cli, "Out of Memory");
-               cli_result(cli, CLIS_CANT);
-               return (-1);
-       }
-
+       CHECK_OBJ_NOTNULL(b, BAN_MAGIC);
        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 (strcmp(a2, "~")) {
+               /* XXX: Add more conditionals */
+               cli_out(cli, "expected \"~\" got \"%s\"", a2);
+               cli_result(cli, CLIS_PARAM);
+               return (-1);
+       }
 
-       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);
+       i = regcomp(&bt->re, a3, REG_EXTENDED | REG_ICASE | REG_NOSUB);
        if (i) {
                (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);
-               ban_free_ban(b);
                return (-1);
        }
-       b->hash = hash;
-       b->ban = strdup(regexp);
-       AN(b->ban);
+
+       if (!strcmp(a1, "req.url"))
+               bt->func = ban_cond_url_regexp;
+       else if (!strcmp(a1, "obj.hash"))
+               bt->func = ban_cond_hash_regexp;
+       else {
+               cli_out(cli, "unknown or unsupported field \"%s\"", a1);
+               cli_result(cli, CLIS_PARAM);
+               return (-1);
+       }
+
+        /* XXX: proper quoting */
+       asprintf(&bt->test, "%s %s \"%s\"", a1, a2, a3);
+
+       return (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
+ * internals of the VTAILQ macros.  We tacitly assume that a pointer
+ * write is always atomic in doing so.
+ */
+static struct ban * volatile ban_start;
+
+static void
+BAN_Insert(struct ban *b)
+{
+       struct ban  *bi, *be;
+       unsigned pcount;
+
+       CHECK_OBJ_NOTNULL(b, BAN_MAGIC);
+       ban_sort_by_cost(b);
+
        Lck_Lock(&ban_mtx);
        VTAILQ_INSERT_HEAD(&ban_head, b, list);
        ban_start = b;
@@ -242,7 +293,7 @@ BAN_Add(struct cli *cli, const char *regexp, int hash)
        Lck_Unlock(&ban_mtx);
 
        if (be == NULL)
-               return (0);
+               return;
 
        /* Hunt down duplicates, and mark them as gone */
        bi = b;
@@ -251,9 +302,7 @@ BAN_Add(struct cli *cli, const char *regexp, int hash)
                bi = VTAILQ_NEXT(bi, list);
                if (bi->flags & BAN_F_GONE)
                        continue;
-               if (b->hash != bi->hash)
-                       continue;
-               if (strcmp(b->ban, bi->ban))
+               if (ban_compare(b, bi))
                        continue;
                bi->flags |= BAN_F_GONE;
                pcount++;
@@ -263,8 +312,6 @@ BAN_Add(struct cli *cli, const char *regexp, int hash)
        /* XXX: We should check if the tail can be removed */
        VSL_stats->n_purge_dups += pcount;
        Lck_Unlock(&ban_mtx);
-
-       return (0);
 }
 
 void
@@ -363,37 +410,97 @@ BAN_CheckObject(struct object *o, const struct sess *sp)
  * CLI functions to add bans
  */
 
-#if 0
 static void
 ccf_purge(struct cli *cli, const char * const *av, void *priv)
 {
+       int narg, i;
+       struct ban *b;
 
        (void)priv;
-       (void)av;
-       (void)cli;
+
+       /* First do some cheap checks on the arguments */
+       for (narg = 0; av[narg + 2] != NULL; narg++)
+               continue;
+       if ((narg % 4) != 3) {
+               cli_out(cli, "Wrong number of arguments");
+               cli_result(cli, CLIS_PARAM);
+               return;
+       }
+       for (i = 3; i < narg; i += 4) {
+               if (strcmp(av[i + 2], "&&")) {
+                       cli_out(cli, "Found \"%s\" expected &&", av[i + 2]);
+                       cli_result(cli, CLIS_PARAM);
+                       return;
+               }
+       }
+
+       b = ban_new_ban();
+       if (b == NULL) {
+               cli_out(cli, "Out of Memory");
+               cli_result(cli, CLIS_CANT);
+               return;
+       }
+       for (i = 0; i < narg; i += 4)
+               if (ban_parse_test(cli, b, av[i + 2], av[i + 3], av[i + 4])) {
+                       ban_free_ban(b);
+                       return;
+               }
+       BAN_Insert(b);
+}
+
+int
+BAN_Add(struct cli *cli, const char *regexp, int hash)
+{
+       const char *aav[6];
+
+       aav[0] = NULL;
+       aav[1] = "purge";
+       if (hash)
+               aav[2] = "obj.hash";
+       else
+               aav[2] = "req.url";
+       aav[3] = "~";
+       aav[4] = regexp;
+       aav[5] = NULL;
+       ccf_purge(cli, aav, NULL);
+       return (0);
 }
-#endif
 
 static void
 ccf_purge_url(struct cli *cli, const char * const *av, void *priv)
 {
+       const char *aav[6];
 
        (void)priv;
-       (void)BAN_Add(cli, av[2], 0);
+       aav[0] = NULL;
+       aav[1] = "purge";
+       aav[2] = "req.url";
+       aav[3] = "~";
+       aav[4] = av[2];
+       aav[5] = NULL;
+       ccf_purge(cli, aav, priv);
 }
 
 static void
 ccf_purge_hash(struct cli *cli, const char * const *av, void *priv)
 {
+       const char *aav[6];
 
        (void)priv;
-       (void)BAN_Add(cli, av[2], 1);
+       aav[0] = NULL;
+       aav[1] = "purge";
+       aav[2] = "obj.hash";
+       aav[3] = "~";
+       aav[4] = av[2];
+       aav[5] = NULL;
+       ccf_purge(cli, aav, priv);
 }
 
 static void
 ccf_purge_list(struct cli *cli, const char * const *av, void *priv)
 {
        struct ban *b0;
+       struct ban_test *bt;
 
        (void)av;
        (void)priv;
@@ -408,10 +515,10 @@ ccf_purge_list(struct cli *cli, const char * const *av, void *priv)
        for (b0 = ban_start; b0 != NULL; b0 = VTAILQ_NEXT(b0, list)) {
                if (b0->refcount == 0 && VTAILQ_NEXT(b0, list) == NULL)
                        break;
-               cli_out(cli, "%5u %d %s \"%s\"\n",
-                   b0->refcount, b0->flags,
-                   b0->hash ? "hash" : "url ",
-                   b0->ban);
+               VTAILQ_FOREACH(bt, &b0->tests, list)
+                       cli_out(cli, "%5u %d \"%s\"\n",
+                           b0->refcount, b0->flags,
+                           bt->test);
        }
 }
 
@@ -425,9 +532,7 @@ 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 }
 };