From 20ba3c49c5b0e32cdedc948e60533063de0f05b2 Mon Sep 17 00:00:00 2001 From: phk Date: Thu, 18 Oct 2007 19:09:33 +0000 Subject: [PATCH] Make ESI processing actually work. So far we support only the element. All other elements are ignored. git-svn-id: svn+ssh://projects.linpro.no/svn/varnish/trunk@2121 d4fa192b-c00b-0410-8231-f00ffab90ce4 --- varnish-cache/bin/varnishd/cache.h | 8 + varnish-cache/bin/varnishd/cache_hash.c | 2 + varnish-cache/bin/varnishd/cache_response.c | 5 +- varnish-cache/bin/varnishd/cache_vrt_esi.c | 201 ++++++++++++++++---- 4 files changed, 180 insertions(+), 36 deletions(-) diff --git a/varnish-cache/bin/varnishd/cache.h b/varnish-cache/bin/varnishd/cache.h index 94afb0a9..8d6d177c 100644 --- a/varnish-cache/bin/varnishd/cache.h +++ b/varnish-cache/bin/varnishd/cache.h @@ -68,6 +68,7 @@ struct object; struct objhead; struct workreq; struct addrinfo; +struct esi_bit; /*--------------------------------------------------------------------*/ @@ -252,6 +253,8 @@ struct object { VTAILQ_HEAD(, sess) waitinglist; + VTAILQ_HEAD(, esi_bit) esibits; + double lru_stamp; }; @@ -567,6 +570,11 @@ cli_func_t cli_func_config_use; cli_func_t cli_func_dump_pool; #endif +/* cache_vrt_esi.c */ + +void ESI_Deliver(struct sess *); +void ESI_Destroy(struct object *); + /* cache_ws.c */ void WS_Init(struct ws *ws, void *space, unsigned len); diff --git a/varnish-cache/bin/varnishd/cache_hash.c b/varnish-cache/bin/varnishd/cache_hash.c index a26f1788..869b4bf6 100644 --- a/varnish-cache/bin/varnishd/cache_hash.c +++ b/varnish-cache/bin/varnishd/cache_hash.c @@ -97,6 +97,7 @@ HSH_Prealloc(struct sess *sp) w->nobj->refcnt = 1; VTAILQ_INIT(&w->nobj->store); VTAILQ_INIT(&w->nobj->waitinglist); + VTAILQ_INIT(&w->nobj->esibits); VSL_stats->n_object++; } else CHECK_OBJ_NOTNULL(w->nobj, OBJECT_MAGIC); @@ -312,6 +313,7 @@ HSH_Deref(struct object *o) if (o->vary != NULL) free(o->vary); + ESI_Destroy(o); HSH_Freestore(o); STV_free(o->objstore); VSL_stats->n_object--; diff --git a/varnish-cache/bin/varnishd/cache_response.c b/varnish-cache/bin/varnishd/cache_response.c index f40710e9..cfe84a1d 100644 --- a/varnish-cache/bin/varnishd/cache_response.c +++ b/varnish-cache/bin/varnishd/cache_response.c @@ -157,7 +157,10 @@ RES_WriteObj(struct sess *sp) sp->wrk->acct.hdrbytes += http_Write(sp->wrk, sp->http, 1); CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); - if (sp->wantbody) { + if (sp->wantbody && !VTAILQ_EMPTY(&sp->obj->esibits)) { + ESI_Deliver(sp); + } else if (sp->wantbody) { + VTAILQ_FOREACH(st, &sp->obj->store, list) { CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); CHECK_OBJ_NOTNULL(st, STORAGE_MAGIC); diff --git a/varnish-cache/bin/varnishd/cache_vrt_esi.c b/varnish-cache/bin/varnishd/cache_vrt_esi.c index a5ae57db..93f953b3 100644 --- a/varnish-cache/bin/varnishd/cache_vrt_esi.c +++ b/varnish-cache/bin/varnishd/cache_vrt_esi.c @@ -50,32 +50,104 @@ #include "vcl.h" #include "cache.h" +#define NDEFELEM 10 + +/*--------------------------------------------------------------------*/ + +struct esi_bit { + VTAILQ_ENTRY(esi_bit) list; + char chunk_length[20]; + txt verbatim; + txt include; + int free_this; +}; + +VTAILQ_HEAD(esibithead, esi_bit); + +struct esi_work { + struct sess *sp; + size_t off; + struct storage *st; + txt dst; + struct esi_bit *eb; + struct esi_bit *ebl; /* list of */ + int neb; +}; + +/*-------------------------------------------------------------------- + * Add ESI bit to object + */ + +static void +esi_addbit(struct esi_work *ew) +{ + + if (ew->neb == 0) { + ew->ebl = calloc(NDEFELEM, sizeof(struct esi_bit)); + XXXAN(ew->ebl); + ew->neb = NDEFELEM; + ew->ebl->free_this = 1; + } + ew->eb = ew->ebl; + ew->ebl++; + ew->neb--; + +printf("FIRST: %p\n", VTAILQ_FIRST(&ew->sp->obj->esibits)); +printf("ADD %p->%p\n", ew->sp->obj, ew->eb); + + VTAILQ_INSERT_TAIL(&ew->sp->obj->esibits, ew->eb, list); + ew->eb->verbatim = ew->dst; + sprintf(ew->eb->chunk_length, "%x\r\n", Tlen(ew->dst)); + VSL(SLT_Debug, ew->sp->fd, "AddBit: %.*s", Tlen(ew->dst), ew->dst.b); +} + + +/*-------------------------------------------------------------------- + * Add verbatim piece to output + */ + +static void +esi_addverbatim(struct esi_work *ew, txt t) +{ + + if (t.b != ew->dst.e) + memmove(ew->dst.e, t.b, Tlen(t)); + ew->dst.e += Tlen(t); +} + /*-------------------------------------------------------------------- * Add one piece to the output, either verbatim or include */ static void -add_piece(txt t, int kind) +esi_addinclude(struct esi_work *ew, txt t) { - printf("K%d \"%.*s\"\n", kind, (int)(t.e - t.b), t.b); + VSL(SLT_Debug, 0, "Incl \"%.*s\"", t.e - t.b, t.b); + esi_addbit(ew); + ew->eb->include = t; } +/*-------------------------------------------------------------------- + * Report a parsing error + */ + static void -vxml_error(struct sess *sp, const char *p, txt t, size_t off, int i, const char *err) +esi_error(const struct esi_work *ew, const char *p, int i, const char *err) { int ellipsis = 0; char buf[256], *q; + txt t; - if (i == 0) { - i = t.e - p; - } + if (i == 0) + i = p - ((char *)ew->st->ptr + ew->st->len); if (i > 20) { i = 20; ellipsis = 1; } q = buf; - q += sprintf(buf, "at %d: %s \"", (int)(off + (p - t.b)), err); + q += sprintf(buf, "at %zd: %s \"", + ew->off + (p - (char*)ew->st->ptr), err); while (i > 0) { if (*p >= ' ' && *p <= '~') { *q++ = *p; @@ -106,7 +178,7 @@ vxml_error(struct sess *sp, const char *p, txt t, size_t off, int i, const char *q++ = '\0'; t.b = buf; t.e = q; - WSPR(sp, SLT_ESI_xmlerror, t); + WSPR(ew->sp, SLT_ESI_xmlerror, t); } /*-------------------------------------------------------------------- @@ -117,18 +189,22 @@ vxml_error(struct sess *sp, const char *p, txt t, size_t off, int i, const char */ static int -vxml(struct sess *sp, txt t, size_t off) +esi_parse(struct esi_work *ew) { char *p, *q, *r; - txt o; + txt t, o; int celem; /* closing element */ int remflg; /* inside */ int incmt; /* inside comment */ int i; - o.b = t.b; + t.b = (char *)ew->st->ptr; + t.e = t.b + ew->st->len; + ew->dst.b = t.b; + ew->dst.e = t.b; remflg = 0; incmt = 0; + o.b = t.b; for (p = t.b; p < t.e; ) { if (incmt && *p == '-') { /* @@ -142,7 +218,7 @@ vxml(struct sess *sp, txt t, size_t off) if (!memcmp(p, "-->", 3)) { incmt = 0; o.e = p; - add_piece(o, 0); + esi_addverbatim(ew, o); p += 3; o.b = p; } else @@ -172,7 +248,7 @@ vxml(struct sess *sp, txt t, size_t off) return (p - t.b); o.e = p; - add_piece(o, 0); + esi_addverbatim(ew, o); p += 7; o.b = p; @@ -216,7 +292,7 @@ vxml(struct sess *sp, txt t, size_t off) /* * Unrecognized dst.b = q + 1; + ew->dst.e = q + 1; } else { - vxml_error(sp, p, t, off, 1 + q - p, + esi_error(ew, p, 1 + q - p, "ESI 1.0 closing esi:include illegal"); } p = q + 1; @@ -309,10 +387,10 @@ vxml(struct sess *sp, txt t, size_t off) /* * Unimplemented ESI element, ignore */ - vxml_error(sp, p, t, off, 1 + q - p, + esi_error(ew, p, 1 + q - p, "ESI 1.0 unimplemented element"); o.e = p; - add_piece(o, 0); + esi_addverbatim(ew, o); p = q + 1; o.b = p; continue; @@ -322,7 +400,7 @@ vxml(struct sess *sp, txt t, size_t off) p = q + 1; } o.e = p; - add_piece(o, 0); + esi_addverbatim(ew, o); return (p - t.b); } @@ -332,23 +410,76 @@ void VRT_ESI(struct sess *sp) { struct storage *st; - txt t; + struct esi_work *ew, eww[1]; int i; - size_t o; CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); CHECK_OBJ_NOTNULL(sp->obj, OBJECT_MAGIC); - o = 1; + ew = eww; + memset(eww, 0, sizeof eww); + ew->sp = sp; + ew->off = 1; + VTAILQ_FOREACH(st, &sp->obj->store, list) { - t.b = (void*)st->ptr; - t.e = t.b + st->len; - i = vxml(sp, t, o); - o += st->len; + ew->st = st; + i = esi_parse(ew); + ew->off += st->len; printf("VXML(%p+%d) = %d", st->ptr, st->len, i); - if (i < st->len) + if (i < st->len) { + /* XXX: Handle complications */ printf(" \"%.*s\"", st->len - i, st->ptr + i); + if (VTAILQ_NEXT(st, list)) + INCOMPL(); + } printf("\n"); + i = Tlen(ew->dst); + } + if (Tlen(ew->dst)) + esi_addbit(ew); + + /* + * Our ESI implementation needs chunked encoding + * XXX: We should only do this if we find any ESI directives + */ + http_Unset(sp->obj->http, H_Content_Length); + http_PrintfHeader(sp->wrk, sp->fd, sp->obj->http, + "Transfer-Encoding: chunked"); + +} + +/*--------------------------------------------------------------------*/ + +void +ESI_Deliver(struct sess *sp) +{ + + struct esi_bit *eb; + + VTAILQ_FOREACH(eb, &sp->obj->esibits, list) { + WRK_Write(sp->wrk, eb->chunk_length, -1); + WRK_Write(sp->wrk, eb->verbatim.b, Tlen(eb->verbatim)); + if (VTAILQ_NEXT(eb, list)) + WRK_Write(sp->wrk, "\r\n", -1); + else + WRK_Write(sp->wrk, "\r\n0\r\n", -1); } } /*--------------------------------------------------------------------*/ + +void +ESI_Destroy(struct object *o) +{ + struct esi_bit *eb; + + /* + * Delete esi_bits from behind and free(3) the ones that want to be. + */ + while (!VTAILQ_EMPTY(&o->esibits)) { + eb = VTAILQ_LAST(&o->esibits, esibithead); + VTAILQ_REMOVE(&o->esibits, eb, list); + if (eb->free_this) + free(eb); + } +} + -- 2.39.5