From: phk Date: Sun, 10 Jun 2007 08:49:43 +0000 (+0000) Subject: Take a shot at light-weight "Vary:" processing. X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=dbd77a25ddd47681d725503a53b711b178e89b87;p=varnish Take a shot at light-weight "Vary:" processing. 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 --- diff --git a/varnish-cache/bin/varnishd/Makefile.am b/varnish-cache/bin/varnishd/Makefile.am index 3f4d6d0f..4a3773e0 100644 --- a/varnish-cache/bin/varnishd/Makefile.am +++ b/varnish-cache/bin/varnishd/Makefile.am @@ -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 \ diff --git a/varnish-cache/bin/varnishd/cache.h b/varnish-cache/bin/varnishd/cache.h index dbb11a02..40422308 100644 --- a/varnish-cache/bin/varnishd/cache.h +++ b/varnish-cache/bin/varnishd/cache.h @@ -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); diff --git a/varnish-cache/bin/varnishd/cache_center.c b/varnish-cache/bin/varnishd/cache_center.c index 8e0700b3..58d60320 100644 --- a/varnish-cache/bin/varnishd/cache_center.c +++ b/varnish-cache/bin/varnishd/cache_center.c @@ -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); } diff --git a/varnish-cache/bin/varnishd/cache_hash.c b/varnish-cache/bin/varnishd/cache_hash.c index f011a56f..d6498406 100644 --- a/varnish-cache/bin/varnishd/cache_hash.c +++ b/varnish-cache/bin/varnishd/cache_hash.c @@ -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 index 00000000..0753b82d --- /dev/null +++ b/varnish-cache/bin/varnishd/cache_vary.c @@ -0,0 +1,176 @@ +/*- + * Copyright (c) 2006-2007 Linpro AS + * All rights reserved. + * + * Author: Poul-Henning Kamp + * + * 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: { + * \ + *
\ Same format as argument to http_GetHdr() + * ':' / + * '\0' / + * \ Length of header contents. + * / + *
Only present if length != 0xffff + * } + * '\0' + */ + +#include +#include +#include + +#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); +}