Commit d32524c5 authored by Poul-Henning Kamp's avatar Poul-Henning Kamp

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: http://www.varnish-cache.org/svn/trunk/varnish-cache@1506 d4fa192b-c00b-0410-8231-f00ffab90ce4
parent a5489b1a
......@@ -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 \
......
......@@ -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);
......
......@@ -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);
}
......
......@@ -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--;
......
/*-
* 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);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment