Commit 3290b19c authored by Poul-Henning Kamp's avatar Poul-Henning Kamp

Make ESI processing actually work.

So far we support only the <esi:remove> element.

All other <esi:...> elements are ignored.



git-svn-id: http://www.varnish-cache.org/svn/trunk/varnish-cache@2121 d4fa192b-c00b-0410-8231-f00ffab90ce4
parent c7b72ec7
...@@ -68,6 +68,7 @@ struct object; ...@@ -68,6 +68,7 @@ struct object;
struct objhead; struct objhead;
struct workreq; struct workreq;
struct addrinfo; struct addrinfo;
struct esi_bit;
/*--------------------------------------------------------------------*/ /*--------------------------------------------------------------------*/
...@@ -252,6 +253,8 @@ struct object { ...@@ -252,6 +253,8 @@ struct object {
VTAILQ_HEAD(, sess) waitinglist; VTAILQ_HEAD(, sess) waitinglist;
VTAILQ_HEAD(, esi_bit) esibits;
double lru_stamp; double lru_stamp;
}; };
...@@ -567,6 +570,11 @@ cli_func_t cli_func_config_use; ...@@ -567,6 +570,11 @@ cli_func_t cli_func_config_use;
cli_func_t cli_func_dump_pool; cli_func_t cli_func_dump_pool;
#endif #endif
/* cache_vrt_esi.c */
void ESI_Deliver(struct sess *);
void ESI_Destroy(struct object *);
/* cache_ws.c */ /* cache_ws.c */
void WS_Init(struct ws *ws, void *space, unsigned len); void WS_Init(struct ws *ws, void *space, unsigned len);
......
...@@ -97,6 +97,7 @@ HSH_Prealloc(struct sess *sp) ...@@ -97,6 +97,7 @@ HSH_Prealloc(struct sess *sp)
w->nobj->refcnt = 1; w->nobj->refcnt = 1;
VTAILQ_INIT(&w->nobj->store); VTAILQ_INIT(&w->nobj->store);
VTAILQ_INIT(&w->nobj->waitinglist); VTAILQ_INIT(&w->nobj->waitinglist);
VTAILQ_INIT(&w->nobj->esibits);
VSL_stats->n_object++; VSL_stats->n_object++;
} else } else
CHECK_OBJ_NOTNULL(w->nobj, OBJECT_MAGIC); CHECK_OBJ_NOTNULL(w->nobj, OBJECT_MAGIC);
...@@ -312,6 +313,7 @@ HSH_Deref(struct object *o) ...@@ -312,6 +313,7 @@ HSH_Deref(struct object *o)
if (o->vary != NULL) if (o->vary != NULL)
free(o->vary); free(o->vary);
ESI_Destroy(o);
HSH_Freestore(o); HSH_Freestore(o);
STV_free(o->objstore); STV_free(o->objstore);
VSL_stats->n_object--; VSL_stats->n_object--;
......
...@@ -157,7 +157,10 @@ RES_WriteObj(struct sess *sp) ...@@ -157,7 +157,10 @@ RES_WriteObj(struct sess *sp)
sp->wrk->acct.hdrbytes += http_Write(sp->wrk, sp->http, 1); sp->wrk->acct.hdrbytes += http_Write(sp->wrk, sp->http, 1);
CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); 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) { VTAILQ_FOREACH(st, &sp->obj->store, list) {
CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
CHECK_OBJ_NOTNULL(st, STORAGE_MAGIC); CHECK_OBJ_NOTNULL(st, STORAGE_MAGIC);
......
...@@ -50,32 +50,104 @@ ...@@ -50,32 +50,104 @@
#include "vcl.h" #include "vcl.h"
#include "cache.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 * Add one piece to the output, either verbatim or include
*/ */
static void 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 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; int ellipsis = 0;
char buf[256], *q; char buf[256], *q;
txt t;
if (i == 0) { if (i == 0)
i = t.e - p; i = p - ((char *)ew->st->ptr + ew->st->len);
}
if (i > 20) { if (i > 20) {
i = 20; i = 20;
ellipsis = 1; ellipsis = 1;
} }
q = buf; 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) { while (i > 0) {
if (*p >= ' ' && *p <= '~') { if (*p >= ' ' && *p <= '~') {
*q++ = *p; *q++ = *p;
...@@ -106,7 +178,7 @@ vxml_error(struct sess *sp, const char *p, txt t, size_t off, int i, const char ...@@ -106,7 +178,7 @@ vxml_error(struct sess *sp, const char *p, txt t, size_t off, int i, const char
*q++ = '\0'; *q++ = '\0';
t.b = buf; t.b = buf;
t.e = q; 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 ...@@ -117,18 +189,22 @@ vxml_error(struct sess *sp, const char *p, txt t, size_t off, int i, const char
*/ */
static int static int
vxml(struct sess *sp, txt t, size_t off) esi_parse(struct esi_work *ew)
{ {
char *p, *q, *r; char *p, *q, *r;
txt o; txt t, o;
int celem; /* closing element */ int celem; /* closing element */
int remflg; /* inside <esi:remove> </esi:remove> */ int remflg; /* inside <esi:remove> </esi:remove> */
int incmt; /* inside <!--esi ... --> comment */ int incmt; /* inside <!--esi ... --> comment */
int i; 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; remflg = 0;
incmt = 0; incmt = 0;
o.b = t.b;
for (p = t.b; p < t.e; ) { for (p = t.b; p < t.e; ) {
if (incmt && *p == '-') { if (incmt && *p == '-') {
/* /*
...@@ -142,7 +218,7 @@ vxml(struct sess *sp, txt t, size_t off) ...@@ -142,7 +218,7 @@ vxml(struct sess *sp, txt t, size_t off)
if (!memcmp(p, "-->", 3)) { if (!memcmp(p, "-->", 3)) {
incmt = 0; incmt = 0;
o.e = p; o.e = p;
add_piece(o, 0); esi_addverbatim(ew, o);
p += 3; p += 3;
o.b = p; o.b = p;
} else } else
...@@ -172,7 +248,7 @@ vxml(struct sess *sp, txt t, size_t off) ...@@ -172,7 +248,7 @@ vxml(struct sess *sp, txt t, size_t off)
return (p - t.b); return (p - t.b);
o.e = p; o.e = p;
add_piece(o, 0); esi_addverbatim(ew, o);
p += 7; p += 7;
o.b = p; o.b = p;
...@@ -216,7 +292,7 @@ vxml(struct sess *sp, txt t, size_t off) ...@@ -216,7 +292,7 @@ vxml(struct sess *sp, txt t, size_t off)
/* /*
* Unrecognized <! sequence, ignore * Unrecognized <! sequence, ignore
*/ */
vxml_error(sp, p, t, off, i, esi_error(ew, p, i,
"XML 1.0 Unknown <! sequence"); "XML 1.0 Unknown <! sequence");
p += 2; p += 2;
continue; continue;
...@@ -233,7 +309,7 @@ vxml(struct sess *sp, txt t, size_t off) ...@@ -233,7 +309,7 @@ vxml(struct sess *sp, txt t, size_t off)
celem = 1; celem = 1;
r = p + 2; r = p + 2;
if (q[-1] == '/') { if (q[-1] == '/') {
vxml_error(sp, p, t, off, 1 + q - p, esi_error(ew, p, 1 + q - p,
"XML 1.0 empty and closing element"); "XML 1.0 empty and closing element");
} }
} else { } else {
...@@ -247,22 +323,22 @@ vxml(struct sess *sp, txt t, size_t off) ...@@ -247,22 +323,22 @@ vxml(struct sess *sp, txt t, size_t off)
/* /*
* ESI 1.0 violation, ignore element * ESI 1.0 violation, ignore element
*/ */
vxml_error(sp, p, t, off, 1 + q - p, esi_error(ew, p, 1 + q - p,
remflg ? "ESI 1.0 forbids nested esi:remove" remflg ? "ESI 1.0 forbids nested esi:remove"
: "ESI 1.0 esi:remove not opened"); : "ESI 1.0 esi:remove not opened");
if (!remflg) { if (!remflg) {
o.e = p; o.e = p;
add_piece(o, 0); esi_addverbatim(ew, o);
} }
} else if (!celem && q[-1] == '/') { } else if (!celem && q[-1] == '/') {
/* empty element */ /* empty element */
o.e = p; o.e = p;
add_piece(o, 0); esi_addverbatim(ew, o);
} else if (!celem) { } else if (!celem) {
/* open element */ /* open element */
o.e = p; o.e = p;
add_piece(o, 0); esi_addverbatim(ew, o);
remflg = !celem; remflg = !celem;
} else { } else {
/* close element */ /* close element */
...@@ -277,7 +353,7 @@ vxml(struct sess *sp, txt t, size_t off) ...@@ -277,7 +353,7 @@ vxml(struct sess *sp, txt t, size_t off)
/* /*
* ESI 1.0 violation, no esi: elements in esi:remove * ESI 1.0 violation, no esi: elements in esi:remove
*/ */
vxml_error(sp, p, t, off, 1 + q - p, esi_error(ew, p, 1 + q - p,
"ESI 1.0 forbids esi: elements inside esi:remove"); "ESI 1.0 forbids esi: elements inside esi:remove");
p = q + 1; p = q + 1;
continue; continue;
...@@ -286,18 +362,20 @@ vxml(struct sess *sp, txt t, size_t off) ...@@ -286,18 +362,20 @@ vxml(struct sess *sp, txt t, size_t off)
if (r + 10 < q && !memcmp(r, "esi:include", 11)) { if (r + 10 < q && !memcmp(r, "esi:include", 11)) {
o.e = p; o.e = p;
add_piece(o, 0); esi_addverbatim(ew, o);
if (celem == 0) { if (celem == 0) {
o.b = r + 11; o.b = r + 11;
o.e = q; o.e = q;
add_piece(o, 1); esi_addinclude(ew, o);
if (q[-1] != '/') { if (q[-1] != '/') {
vxml_error(sp, p, t, off, 1 + q - p, esi_error(ew, p, 1 + q - p,
"ESI 1.0 wants emtpy esi:include"); "ESI 1.0 wants emtpy esi:include");
} }
ew->dst.b = q + 1;
ew->dst.e = q + 1;
} else { } else {
vxml_error(sp, p, t, off, 1 + q - p, esi_error(ew, p, 1 + q - p,
"ESI 1.0 closing esi:include illegal"); "ESI 1.0 closing esi:include illegal");
} }
p = q + 1; p = q + 1;
...@@ -309,10 +387,10 @@ vxml(struct sess *sp, txt t, size_t off) ...@@ -309,10 +387,10 @@ vxml(struct sess *sp, txt t, size_t off)
/* /*
* Unimplemented ESI element, ignore * 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"); "ESI 1.0 unimplemented element");
o.e = p; o.e = p;
add_piece(o, 0); esi_addverbatim(ew, o);
p = q + 1; p = q + 1;
o.b = p; o.b = p;
continue; continue;
...@@ -322,7 +400,7 @@ vxml(struct sess *sp, txt t, size_t off) ...@@ -322,7 +400,7 @@ vxml(struct sess *sp, txt t, size_t off)
p = q + 1; p = q + 1;
} }
o.e = p; o.e = p;
add_piece(o, 0); esi_addverbatim(ew, o);
return (p - t.b); return (p - t.b);
} }
...@@ -332,23 +410,76 @@ void ...@@ -332,23 +410,76 @@ void
VRT_ESI(struct sess *sp) VRT_ESI(struct sess *sp)
{ {
struct storage *st; struct storage *st;
txt t; struct esi_work *ew, eww[1];
int i; int i;
size_t o;
CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
CHECK_OBJ_NOTNULL(sp->obj, OBJECT_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) { VTAILQ_FOREACH(st, &sp->obj->store, list) {
t.b = (void*)st->ptr; ew->st = st;
t.e = t.b + st->len; i = esi_parse(ew);
i = vxml(sp, t, o); ew->off += st->len;
o += st->len;
printf("VXML(%p+%d) = %d", st->ptr, st->len, i); 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); printf(" \"%.*s\"", st->len - i, st->ptr + i);
if (VTAILQ_NEXT(st, list))
INCOMPL();
}
printf("\n"); 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);
}
}
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