]> err.no Git - varnish/commitdiff
Take a shot at light-weight "Vary:" processing.
authorphk <phk@d4fa192b-c00b-0410-8231-f00ffab90ce4>
Sun, 10 Jun 2007 08:49:43 +0000 (08:49 +0000)
committerphk <phk@d4fa192b-c00b-0410-8231-f00ffab90ce4>
Sun, 10 Jun 2007 08:49:43 +0000 (08:49 +0000)
When we cache an object with a "Vary:" header, we generate
a "vary matching string" which can be used to efficiently
check for compliance when doing a cache lookup.

Only very lightly tested (ie: cnn.com).

For a full description of the reasoning, please see
http://varnish.projects.linpro.no/wiki/ArchitectureVary

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

varnish-cache/bin/varnishd/Makefile.am
varnish-cache/bin/varnishd/cache.h
varnish-cache/bin/varnishd/cache_center.c
varnish-cache/bin/varnishd/cache_hash.c
varnish-cache/bin/varnishd/cache_vary.c [new file with mode: 0644]

index 3f4d6d0f252abbcd7030e84bad66140253bda63f..4a3773e0d0d1ee4d150f8f04463e99f37b9d550e 100644 (file)
@@ -25,6 +25,7 @@ varnishd_SOURCES = \
        cache_response.c \
        cache_session.c \
        cache_synthetic.c \
+       cache_vary.c \
        cache_vcl.c \
        cache_vrt.c \
        cache_vrt_acl.c \
index dbb11a02c65fe4f4bfe46915f149e97644357561..40422308ae503443146f8eebb1dbe81a4884446f 100644 (file)
@@ -225,6 +225,8 @@ struct object {
        unsigned                xid;
        struct objhead          *objhead;
 
+       unsigned char           *vary;
+
        unsigned                heap_idx;
        unsigned                ban_seq;
 
@@ -463,6 +465,10 @@ void RES_WriteObj(struct sess *sp);
 /* cache_synthetic.c */
 void SYN_ErrorPage(struct sess *sp, int status, const char *reason, int ttl);
 
+/* cache_vary.c */
+void VRY_Create(struct sess *sp);
+int VRY_Match(struct sess *sp, unsigned char *vary);
+
 /* cache_vcl.c */
 void VCL_Init(void);
 void VCL_Refresh(struct VCL_conf **vcc);
index 8e0700b300e6fec7637b19fdfd4f93eb22fe9434..58d60320b7313dc6127692fa8f668c96eefcaf8d 100644 (file)
@@ -298,6 +298,7 @@ cnt_fetch(struct sess *sp)
 
        sp->obj->cacheable = 1;
        if (sp->obj->objhead != NULL) {
+               VRY_Create(sp);
                HSH_Ref(sp->obj); /* get another, STP_DELIVER will deref */
                HSH_Unbusy(sp->obj);
        }
index f011a56fc96a131353ea6391d0c738b1c3043402..d6498406e4146fa09f1e1d606021099a1883af7a 100644 (file)
@@ -148,7 +148,6 @@ VSLR(SLT_Debug, sp->fd, sp->hash_b, sp->hash_e);
                        return (NULL);
                }
        were_back:
-               /* XXX: check Vary: */
                if (!o->cacheable) {
                        /* ignore */
                } else if (o->ttl == 0) {
@@ -159,7 +158,7 @@ VSLR(SLT_Debug, sp->fd, sp->hash_b, sp->hash_e);
                        o->ttl = 0;
                        VSL(SLT_ExpBan, 0, "%u was banned", o->xid);
                        EXP_TTLchange(o);
-               } else
+               } else if (VRY_Match(sp, o->vary))
                        break;
                o->refcnt--;
        }
@@ -254,6 +253,9 @@ HSH_Deref(struct object *o)
        if (o->http.ws->s != NULL)
                free(o->http.ws->s);
 
+       if (o->vary != NULL)
+               free(o->vary);
+
        HSH_Freestore(o);
        free(o);
        VSL_stats->n_object--;
diff --git a/varnish-cache/bin/varnishd/cache_vary.c b/varnish-cache/bin/varnishd/cache_vary.c
new file mode 100644 (file)
index 0000000..0753b82
--- /dev/null
@@ -0,0 +1,176 @@
+/*-
+ * Copyright (c) 2006-2007 Linpro AS
+ * All rights reserved.
+ *
+ * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ *
+ * Do Vary processing.
+ *
+ * When we insert an object into the cache which has a Vary: header,
+ * we encode a vary matching string containing the headers mentioned
+ * and their value.
+ *
+ * When we match an object in the cache, we check the present request
+ * against the vary matching string.
+ *
+ * The only kind of header-munging we do is leading & trailing space
+ * removal.  All the potential "q=foo" gymnastics is not worth the
+ * effort.
+ *
+ * The vary matching string has the following format:
+ *
+ * Sequence of: {
+ *     <length of header + 1>  \
+ *     <header>                 \  Same format as argument to http_GetHdr()
+ *     ':'                      /
+ *     '\0'                    /
+ *     <msb>                   \   Length of header contents.
+ *     <lsb>                   /
+ *      <header>                   Only present if length != 0xffff
+ * }
+ *      '\0'
+ */
+
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "cache.h"
+
+void
+VRY_Create(struct sess *sp)
+{
+       char *v, *p, *q, *h, *e;
+       struct vsb *sb, *sbh;
+       unsigned l;
+
+       /* For vary matching string */
+       sb = vsb_new(NULL, NULL, 0, VSB_AUTOEXTEND);
+       AN(sb);
+
+       /* For header matching strings */
+       sbh = vsb_new(NULL, NULL, 0, VSB_AUTOEXTEND);
+       AN(sbh);
+
+       /* No Vary: header, no worries */
+       if (!http_GetHdr(&sp->obj->http, H_Vary, &v))
+               return;
+
+       for (p = v; *p; p++) {
+
+               /* Find next header-name */
+               if (isspace(*p))
+                       continue;
+               for (q = p; *q && !isspace(*q) && *q != ','; q++)
+                       continue;
+
+               /* Build a header-matching string out of it */
+               vsb_clear(sbh);
+               vsb_printf(sbh, "%c%.*s:%c", 1 + (q - p), q - p, p, 0);
+               vsb_finish(sbh);
+
+               /* Append to vary matching string */
+               vsb_bcat(sb, vsb_data(sbh), vsb_len(sbh));
+
+               if (http_GetHdr(sp->http, vsb_data(sbh), &h)) {
+                       /* Trim leading and trailing space */
+                       while (isspace(*h))
+                               h++;
+                       e = strchr(h, '\0');
+                       while (e > h && isspace(e[-1]))
+                               e--;
+                       /* Encode two byte length and contents */
+                       l = e - h;
+                       vsb_printf(sb, "%c%c", l >> 8, l & 0xff);
+                       vsb_bcat(sb, h, e - h);
+               } else {
+                       /* Mark as "not present" */
+                       vsb_printf(sb, "%c%c", 0xff, 0xff);
+               }
+               
+               while (isspace(*q)) 
+                       q++;
+               if (*q == '\0')
+                       break;
+               xxxassert(*q == ',');
+               p = q;
+       }
+       /* Terminate vary matching string */
+       vsb_printf(sb, "%c", 0);
+
+       vsb_finish(sb);
+       l = vsb_len(sb);
+       sp->obj->vary = malloc(l);
+       AN(sp->obj->vary);
+       memcpy(sp->obj->vary, vsb_data(sb), l);
+}
+
+int
+VRY_Match(struct sess *sp, unsigned char *vary)
+{
+       char *h, *e;
+       int i, l, lh;
+
+       while (*vary) {
+
+               /* Look for header */
+               i = http_GetHdr(sp->http, (char*)vary, &h);
+               vary += *vary + 2;
+
+               /* Expected length of header (or 0xffff) */
+               l = vary[0] * 256 + vary[1];
+               vary += 2;
+
+               /* Fail if we have the header, but shouldn't */
+               if (i && l == 0xffff)
+                       return (0);
+               /* or if we don't when we should */
+               if (l != 0xffff && !i)
+                       return (0);
+
+               /* Nothing to match */
+               if (!i)
+                       continue;
+
+               /* Trim leading & trailing space */
+               while (isspace(*h))
+                       h++;
+               e = strchr(h, '\0');
+               while (e > h && isspace(e[-1]))
+                       e--;
+
+               /* Fail if wrong length */
+               lh = e - h;
+               if (lh != l)
+                       return (0);
+
+               /* or if wrong contents */
+               if (memcmp(h, vary, l))
+                       return (0);
+               vary += l;
+       }
+       return (1);
+}