Soft bans are like normal bans, but they are subject to grace per
usual rules.
---
 bin/varnishd/cache/cache.h       |    1 +
 bin/varnishd/cache/cache_ban.c   |   58 +++++++++++++++++++++++++++++++++----
 bin/varnishd/cache/cache_vrt.c   |    6 ++--
 bin/varnishtest/tests/s00004.vtc |   47 ++++++++++++++++++++++++++++++
 bin/varnishtest/tests/s00005.vtc |   59 ++++++++++++++++++++++++++++++++++++++
 include/vcli.h                   |    7 +++++
 include/vrt.h                    |    4 +--
 lib/libvcl/vcc_action.c          |   25 ++++++++++++++--
 8 files changed, 195 insertions(+), 12 deletions(-)
 create mode 100644 bin/varnishtest/tests/s00004.vtc
 create mode 100644 bin/varnishtest/tests/s00005.vtc

diff --git a/bin/varnishd/cache/cache.h b/bin/varnishd/cache/cache.h
index 6d4fe86..66ee459 100644
--- a/bin/varnishd/cache/cache.h
+++ b/bin/varnishd/cache/cache.h
@@ -757,6 +757,7 @@ void BAN_Compile(void);
 struct ban *BAN_RefBan(struct objcore *oc, double t0, const struct ban *tail);
 void BAN_TailDeref(struct ban **ban);
 double BAN_Time(const struct ban *ban);
+void BAN_Set_Soft(struct ban *b, int soft);
 
 /* cache_busyobj.c */
 void VBO_Init(void);
diff --git a/bin/varnishd/cache/cache_ban.c b/bin/varnishd/cache/cache_ban.c
index aa8bca9..6270a4a 100644
--- a/bin/varnishd/cache/cache_ban.c
+++ b/bin/varnishd/cache/cache_ban.c
@@ -42,6 +42,7 @@
  *     8 bytes - double: timestamp             XXX: Byteorder ?
  *     4 bytes - be32: length
  *     1 byte - flags: 0x01: BAN_F_REQ
+ *                     0x02: BAN_F_SOFT
  *     N tests
  * A test have this form:
  *     1 byte - arg (see ban_vars.h col 3 "BAN_ARG_XXX")
@@ -82,6 +83,7 @@ struct ban {
        unsigned                flags;
 #define BAN_F_GONE             (1 << 0)
 #define BAN_F_REQ              (1 << 2)
+#define BAN_F_SOFT             (1 << 3)        /* soft ban, aka grace */
 #define BAN_F_LURK             (3 << 6)        /* ban-lurker-color */
        VTAILQ_HEAD(,objcore)   objcore;
        struct vsb              *vsb;
@@ -392,7 +394,11 @@ BAN_Insert(struct ban *b)
 
        t0 = VTIM_real();
        memcpy(b->spec, &t0, sizeof t0);
-       b->spec[12] = (b->flags & BAN_F_REQ) ? 1 : 0;
+       b->spec[12] = 0;
+       if (b->flags & BAN_F_REQ)
+               b->spec[12] |= 0x1;
+       if (b->flags & BAN_F_SOFT)
+               b->spec[12] |= 0x2;
        memcpy(b->spec + 13, VSB_data(b->vsb), ln);
        ln += 13;
        vbe32enc(b->spec + 8, ln);
@@ -551,8 +557,10 @@ BAN_Reload(const uint8_t *ban, unsigned len)
        AN(b2->spec);
        memcpy(b2->spec, ban, len);
        b2->flags |= gone;
-       if (ban[12])
+       if (ban[12] & 0x01)
                b2->flags |= BAN_F_REQ;
+       if (ban[12] & 0x02)
+               b2->flags |= BAN_F_SOFT;
        if (b == NULL)
                VTAILQ_INSERT_TAIL(&ban_head, b2, list);
        else
@@ -587,6 +595,21 @@ BAN_Time(const struct ban *b)
 }
 
 /*--------------------------------------------------------------------
+ * Set/unset the soft flag on a ban
+ */
+
+void
+BAN_Set_Soft(struct ban *b, int soft)
+{
+
+       CHECK_OBJ_NOTNULL(b, BAN_MAGIC);
+       if (soft)
+               b->flags |= BAN_F_SOFT;
+       else
+               b->flags &= ~BAN_F_SOFT;
+}
+
+/*--------------------------------------------------------------------
  * All silos have read their bans, ready for action
  */
 
@@ -687,7 +710,8 @@ ban_check_object(struct object *o, struct vsl_log *vsl,
        struct ban *b;
        struct objcore *oc;
        struct ban * volatile b0;
-       unsigned tests, skipped;
+       unsigned tests, skipped, soft;
+       double now;
 
        CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
        CHECK_OBJ_ORNULL(req_http, HTTP_MAGIC);
@@ -708,6 +732,7 @@ ban_check_object(struct object *o, struct vsl_log *vsl,
         */
        tests = 0;
        skipped = 0;
+       soft = 0;
        for (b = b0; b != oc->ban; b = VTAILQ_NEXT(b, list)) {
                CHECK_OBJ_NOTNULL(b, BAN_MAGIC);
                if (b->flags & BAN_F_GONE)
@@ -724,15 +749,21 @@ ban_check_object(struct object *o, struct vsl_log *vsl,
                         * be other bans that match, so we soldier on
                         */
                        skipped++;
-               } else if (ban_evaluate(b->spec, o->http, req_http, &tests))
+               } else if (ban_evaluate(b->spec, o->http, req_http, &tests)) {
+                       if (b->flags & BAN_F_SOFT) {
+                               soft = 1;
+                               continue;
+                       }
+                       soft = 0; /* Found hard ban */
                        break;
+               }
        }
 
        Lck_Lock(&ban_mtx);
        VSC_C_main->bans_tested++;
        VSC_C_main->bans_tests_tested += tests;
 
-       if (b == oc->ban && skipped > 0) {
+       if (b == oc->ban && skipped > 0 && soft == 0) {
                AZ(req_http);
                Lck_Unlock(&ban_mtx);
                /*
@@ -751,10 +782,21 @@ ban_check_object(struct object *o, struct vsl_log *vsl,
        }
        Lck_Unlock(&ban_mtx);
 
-       if (b == oc->ban) {     /* not banned */
+       if (soft == 0 && b == oc->ban) {        /* not banned */
                oc->ban = b0;
                oc_updatemeta(oc);
                return (0);
+       } else if (soft) {
+               now =  VTIM_real();
+               /* Softban, set ttl to now */
+               if (o->exp.entered + o->exp.ttl > now)
+                       o->exp.ttl = now - o->exp.entered;
+               oc->ban = b0;
+               oc_updatemeta(oc);
+               /* XXX: no req in lurker */
+               VSLb(vsl, SLT_ExpBan, "%u was softbanned", o->vxid);
+               EXP_Rearm(o);
+               return (2);
        } else {
                EXP_Clr(&o->exp);
                oc->ban = NULL;
@@ -1026,6 +1068,9 @@ ccf_ban(struct cli *cli, const char * const *av, void 
*priv)
                VCLI_SetResult(cli, CLIS_CANT);
                return;
        }
+       if (strcmp(av[1], "softban") == 0) {
+               b->flags |= BAN_F_SOFT;
+       }
        for (i = 0; i < narg; i += 4)
                if (BAN_AddTest(cli, b, av[i + 2], av[i + 3], av[i + 4])) {
                        BAN_Free(b);
@@ -1125,6 +1170,7 @@ ccf_ban_list(struct cli *cli, const char * const *av, 
void *priv)
 static struct cli_proto ban_cmds[] = {
        { CLI_BAN_URL,                          "", ccf_ban_url },
        { CLI_BAN,                              "", ccf_ban },
+       { CLI_SOFTBAN,                          "", ccf_ban },
        { CLI_BAN_LIST,                         "", ccf_ban_list },
        { NULL }
 };
diff --git a/bin/varnishd/cache/cache_vrt.c b/bin/varnishd/cache/cache_vrt.c
index ed7ae59..70537fc 100644
--- a/bin/varnishd/cache/cache_vrt.c
+++ b/bin/varnishd/cache/cache_vrt.c
@@ -433,7 +433,7 @@ VRT_synth_page(const struct req *req, unsigned flags, const 
char *str, ...)
 /*--------------------------------------------------------------------*/
 
 void
-VRT_ban(const struct req *req, char *cmds, ...)
+VRT_ban(const struct req *req, int soft, char *cmds, ...)
 {
        char *a1, *a2, *a3;
        va_list ap;
@@ -442,6 +442,7 @@ VRT_ban(const struct req *req, char *cmds, ...)
 
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
        b = BAN_New();
+       BAN_Set_Soft(b, soft);
        va_start(ap, cmds);
        a1 = cmds;
        good = 0;
@@ -468,7 +469,7 @@ VRT_ban(const struct req *req, char *cmds, ...)
 /*--------------------------------------------------------------------*/
 
 void
-VRT_ban_string(const struct req *req, const char *str)
+VRT_ban_string(const struct req *req, int soft, const char *str)
 {
        char *a1, *a2, *a3;
        char **av;
@@ -484,6 +485,7 @@ VRT_ban_string(const struct req *req, const char *str)
                return;
        }
        b = BAN_New();
+       BAN_Set_Soft(b, soft);
        good = 0;
        for (i = 1; ;) {
                a1 = av[i++];
diff --git a/bin/varnishtest/tests/s00004.vtc b/bin/varnishtest/tests/s00004.vtc
new file mode 100644
index 0000000..781d1dc
--- /dev/null
+++ b/bin/varnishtest/tests/s00004.vtc
@@ -0,0 +1,47 @@
+varnishtest "Softbans from CLI"
+
+server s1 {
+       rxreq
+       txresp
+
+       sema r1 sync 3
+
+       rxreq
+       txresp
+} -start
+
+varnish v1 -vcl+backend {
+       sub vcl_hit {
+           if (obj.ttl <= 0s) {
+                   set req.http.grace = "t";
+           }
+       }
+       sub vcl_fetch { 
+               set beresp.ttl = 1m;
+               set beresp.grace = 1m; 
+       }
+       sub vcl_deliver {
+           set resp.http.grace = req.http.grace;
+       }
+} -start
+
+client c1 {
+       txreq
+       rxresp
+       expect resp.status == 200
+       delay 1
+       txreq
+       sema r1 sync 3
+       rxresp
+} -start
+
+varnish v1 -cliok "softban req.url ~ ^"
+delay 1;
+
+client c2 {
+       sema r1 sync 3
+       txreq
+       rxresp
+       expect resp.http.grace == "t"
+       expect resp.status == 200
+} -run
diff --git a/bin/varnishtest/tests/s00005.vtc b/bin/varnishtest/tests/s00005.vtc
new file mode 100644
index 0000000..35d1a8a
--- /dev/null
+++ b/bin/varnishtest/tests/s00005.vtc
@@ -0,0 +1,59 @@
+varnishtest "Softbans from VCL"
+
+server s1 {
+       rxreq
+       txresp
+
+       sema r1 sync 3
+
+       rxreq
+       txresp
+} -start
+
+varnish v1 -vcl+backend {
+       sub vcl_recv {
+           if (req.request == "SOFTBAN") {
+              softban("req.url ~ " + req.url);
+              error 410;
+           }
+       }
+
+       sub vcl_hit {
+           if (obj.ttl <= 0s) {
+                   set req.http.grace = "t";
+           }
+       }
+       sub vcl_fetch { 
+               set beresp.ttl = 1m;
+               set beresp.grace = 1m; 
+       }
+       sub vcl_deliver {
+           set resp.http.grace = req.http.grace;
+       }
+} -start
+
+client c1 {
+       txreq
+       rxresp
+       expect resp.status == 200
+       delay 1
+       txreq
+       sema r1 sync 3
+       rxresp
+} -start
+
+delay 1
+client c2 {
+       txreq -req SOFTBAN -url /
+       rxresp
+       expect resp.status == 410
+} -run
+
+
+client c3 {
+       sema r1 sync 3
+       txreq
+       rxresp
+       expect resp.http.grace == "t"
+       expect resp.status == 200
+} -run
diff --git a/include/vcli.h b/include/vcli.h
index 04ac11c..3d79e7b 100644
--- a/include/vcli.h
+++ b/include/vcli.h
@@ -78,6 +78,13 @@
        "\tList the active bans.",                                      \
        0, 0
 
+#define CLI_SOFTBAN                                                    \
+       "softban",                                                      \
+       "softban <field> <operator> <arg> [&& <field> <oper> <arg>]...",        
\
+       "\tAll objects where the all the conditions match will be "     \
+           "marked obsolete, but still eligible for grace.",           \
+       3, UINT_MAX
+
 #define CLI_VCL_LOAD                                                   \
        "vcl.load",                                                     \
        "vcl.load <configname> <filename>",                             \
diff --git a/include/vrt.h b/include/vrt.h
index c98e085..bb21f93 100644
--- a/include/vrt.h
+++ b/include/vrt.h
@@ -177,8 +177,8 @@ int VRT_re_match(struct req *, const char *, void *re);
 const char *VRT_regsub(struct req *, int all, const char *,
     void *, const char *);
 
-void VRT_ban(const struct req *, char *, ...);
-void VRT_ban_string(const struct req *, const char *);
+void VRT_ban(const struct req *, int, char *, ...);
+void VRT_ban_string(const struct req *, int, const char *);
 void VRT_purge(struct req *, double ttl, double grace);
 
 void VRT_count(struct req *, unsigned);
diff --git a/lib/libvcl/vcc_action.c b/lib/libvcl/vcc_action.c
index eae6231..3662a39 100644
--- a/lib/libvcl/vcc_action.c
+++ b/lib/libvcl/vcc_action.c
@@ -183,7 +183,7 @@ parse_ban(struct vcc *tl)
        ExpectErr(tl, '(');
        vcc_NextToken(tl);
 
-       Fb(tl, 1, "VRT_ban_string(req, ");
+       Fb(tl, 1, "VRT_ban_string(req, 0, ");
        vcc_Expr(tl, STRING);
        ERRCHK(tl);
        Fb(tl, 0, ");\n");
@@ -202,7 +202,7 @@ parse_ban_url(struct vcc *tl)
        ExpectErr(tl, '(');
        vcc_NextToken(tl);
 
-       Fb(tl, 1, "VRT_ban(req, \"req.url\", \"~\", ");
+       Fb(tl, 1, "VRT_ban(req, 0, \"req.url\", \"~\", ");
        vcc_Expr(tl, STRING);
        ERRCHK(tl);
        ExpectErr(tl, ')');
@@ -213,6 +213,26 @@ parse_ban_url(struct vcc *tl)
 /*--------------------------------------------------------------------*/
 
 static void
+parse_softban(struct vcc *tl)
+{
+
+       vcc_NextToken(tl);
+
+       ExpectErr(tl, '(');
+       vcc_NextToken(tl);
+
+       Fb(tl, 1, "VRT_ban_string(req, 1, ");
+       vcc_Expr(tl, STRING);
+       ERRCHK(tl);
+       Fb(tl, 0, ");\n");
+
+       ExpectErr(tl, ')');
+       vcc_NextToken(tl);
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
 parse_new_syntax(struct vcc *tl)
 {
 
@@ -325,6 +345,7 @@ static struct action_table {
        { "hash_data",          parse_hash_data, VCL_MET_HASH },
        { "ban",                parse_ban },
        { "ban_url",            parse_ban_url },
+       { "softban",            parse_softban },
        { "remove",             parse_unset }, /* backward compatibility */
        { "return",             parse_return },
        { "rollback",           parse_rollback },
-- 
1.7.10.4


_______________________________________________
varnish-dev mailing list
varnish-dev@varnish-cache.org
https://www.varnish-cache.org/lists/mailman/listinfo/varnish-dev

Reply via email to