[master] abb29f4 This is a megacommit which introduces VFP's: Fetch-Processors.
Poul-Henning Kamp
phk at FreeBSD.org
Sat Dec 7 10:40:30 CET 2013
commit abb29f413f2e72647cf3f58e0153ed9c7e72587a
Author: Poul-Henning Kamp <phk at FreeBSD.org>
Date: Sat Dec 7 09:40:07 2013 +0000
This is a megacommit which introduces VFP's: Fetch-Processors.
diff --git a/bin/varnishd/cache/cache.h b/bin/varnishd/cache/cache.h
index 5cbc27b..08f81b2 100644
--- a/bin/varnishd/cache/cache.h
+++ b/bin/varnishd/cache/cache.h
@@ -123,7 +123,6 @@ struct req;
struct sess;
struct sesspool;
struct vbc;
-struct vef_priv;
struct vrt_backend;
struct vsb;
struct waitinglist;
@@ -265,20 +264,18 @@ struct dstat {
/* Fetch processors --------------------------------------------------*/
-typedef void vfp_begin_f(struct busyobj *bo, size_t );
-typedef int vfp_bytes_f(struct busyobj *bo, struct http_conn *, ssize_t);
-typedef int vfp_end_f(struct busyobj *bo);
-
-struct vfp {
- vfp_begin_f *begin;
- vfp_bytes_f *bytes;
- vfp_end_f *end;
+enum vfp_status {
+ VFP_ERROR = -1,
+ VFP_OK = 0,
+ VFP_END = 1,
};
+typedef enum vfp_status vfp_pull_f(struct busyobj *bo, void *p, ssize_t *len, intptr_t *priv);
-extern const struct vfp vfp_gunzip;
-extern const struct vfp vfp_gzip;
-extern const struct vfp vfp_testgzip;
-extern const struct vfp vfp_esi;
+extern vfp_pull_f vfp_gunzip_pull;
+extern vfp_pull_f vfp_gzip_pull;
+extern vfp_pull_f vfp_testgunzip_pull;
+extern vfp_pull_f vfp_esi_pull;
+extern vfp_pull_f vfp_esi_gzip_pull;
/* Deliver processors ------------------------------------------------*/
@@ -545,10 +542,12 @@ struct busyobj {
unsigned is_gzip;
unsigned is_gunzip;
- const struct vfp *vfp;
- struct vep_state *vep;
+#define N_VFPS 5
+ vfp_pull_f *vfps[N_VFPS];
+ intptr_t vfps_priv[N_VFPS];
+ int vfp_nxt;
+
enum busyobj_state_e state;
- struct vgz *vgz_rx;
struct ws ws[1];
struct vbc *vbc;
@@ -564,8 +563,6 @@ struct busyobj {
struct pool_task fetch_task;
- struct vef_priv *vef_priv;
-
unsigned should_close;
char *h_content_length;
@@ -859,7 +856,7 @@ void VBO_waitstate(struct busyobj *bo, enum busyobj_state_e want);
/* cache_http1_fetch.c [V1F] */
int V1F_fetch_hdr(struct worker *wrk, struct busyobj *bo, struct req *req);
-void V1F_fetch_body(struct busyobj *bo);
+ssize_t V1F_Setup_Fetch(struct busyobj *bo);
/* cache_http1_fsm.c [HTTP1] */
typedef int (req_body_iter_f)(struct req *, void *priv, void *ptr, size_t);
@@ -944,10 +941,14 @@ void VBF_Fetch(struct worker *wrk, struct req *req,
/* cache_fetch_proc.c */
struct storage *VFP_GetStorage(struct busyobj *, ssize_t sz);
-int VFP_Error2(struct busyobj *, const char *error, const char *more);
-int VFP_Error(struct busyobj *, const char *error);
+enum vfp_status VFP_Error(struct busyobj *, const char *fmt, ...)
+ __printflike(2, 3);
void VFP_Init(void);
-extern const struct vfp VFP_nop;
+void VFP_Fetch_Body(struct busyobj *bo, ssize_t est);
+void VFP_Push(struct busyobj *, vfp_pull_f *func, intptr_t priv);
+enum vfp_status VFP_Suck(struct busyobj *, void *p, ssize_t *lp);
+extern char vfp_init[];
+extern char vfp_fini[];
/* cache_gzip.c */
struct vgz;
@@ -966,7 +967,6 @@ void VGZ_Ibuf(struct vgz *, const void *, ssize_t len);
int VGZ_IbufEmpty(const struct vgz *vg);
void VGZ_Obuf(struct vgz *, void *, ssize_t len);
int VGZ_ObufFull(const struct vgz *vg);
-int VGZ_ObufStorage(struct busyobj *, struct vgz *vg);
enum vgzret_e VGZ_Gzip(struct vgz *, const void **, size_t *len, enum vgz_flag);
enum vgzret_e VGZ_Gunzip(struct vgz *, const void **, size_t *len);
enum vgzret_e VGZ_Destroy(struct vgz **);
@@ -1141,6 +1141,7 @@ void VSM_Free(void *ptr);
#ifdef VSL_ENDMARKER
void VSL(enum VSL_tag_e tag, uint32_t vxid, const char *fmt, ...)
__printflike(3, 4);
+void VSLbv(struct vsl_log *, enum VSL_tag_e tag, const char *fmt, va_list va);
void VSLb(struct vsl_log *, enum VSL_tag_e tag, const char *fmt, ...)
__printflike(3, 4);
void VSLbt(struct vsl_log *, enum VSL_tag_e tag, txt t);
diff --git a/bin/varnishd/cache/cache_esi.h b/bin/varnishd/cache/cache_esi.h
index 9903bd8..52c9d0b 100644
--- a/bin/varnishd/cache/cache_esi.h
+++ b/bin/varnishd/cache/cache_esi.h
@@ -39,8 +39,10 @@
#define VEC_S8 (0x60 + 8)
#define VEC_INCL 'I'
-typedef ssize_t vep_callback_t(struct busyobj *, ssize_t l, enum vgz_flag flg);
+typedef ssize_t vep_callback_t(struct busyobj *, void *priv, ssize_t l,
+ enum vgz_flag flg);
-void VEP_Init(struct busyobj *, vep_callback_t *cb);
-void VEP_Parse(const struct busyobj *, const char *p, size_t l);
-struct vsb *VEP_Finish(struct busyobj *);
+struct vep_state *VEP_Init(struct busyobj *, vep_callback_t *cb, void *cb_priv);
+void VEP_Parse(struct vep_state *, const struct busyobj *, const char *p,
+ size_t l);
+struct vsb *VEP_Finish(struct vep_state *, const struct busyobj *);
diff --git a/bin/varnishd/cache/cache_esi_fetch.c b/bin/varnishd/cache/cache_esi_fetch.c
index 6cf8dbd..3eb4c49 100644
--- a/bin/varnishd/cache/cache_esi_fetch.c
+++ b/bin/varnishd/cache/cache_esi_fetch.c
@@ -44,6 +44,8 @@ struct vef_priv {
#define VEF_MAGIC 0xf104b51f
struct vgz *vgz;
+ struct vep_state *vep;
+
ssize_t tot;
int error;
@@ -51,149 +53,19 @@ struct vef_priv {
char *ibuf_i;
char *ibuf_o;
ssize_t ibuf_sz;
-
- char *ibuf2;
- ssize_t ibuf2_sz;
};
-/*---------------------------------------------------------------------
- * Read some bytes.
- *
- * If the DBG_ESI_CHOP is set, we read only a couple of bytes at
- * a time, in order to stress the parse/pending/callback code.
- */
-
-static ssize_t
-vef_read(struct http_conn *htc, void *buf, ssize_t buflen, ssize_t bytes)
-{
- ssize_t d;
-
- if (buflen < bytes)
- bytes = buflen;
- if (DO_DEBUG(DBG_ESI_CHOP)) {
- d = (random() & 3) + 1;
- if (d < bytes)
- bytes = d;
- }
- return (htc->read(htc, buf, bytes));
-}
-
-/*---------------------------------------------------------------------
- * We receive a ungzip'ed object, and want to store it ungzip'ed.
- */
-
-static int
-vfp_esi_bytes_uu(struct busyobj *bo, const struct vef_priv *vef,
- struct http_conn *htc, ssize_t bytes)
-{
- ssize_t wl;
- struct storage *st;
-
- CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
- CHECK_OBJ_NOTNULL(vef, VEF_MAGIC);
-
- while (bytes > 0) {
- st = VFP_GetStorage(bo, 0);
- if (st == NULL)
- return (-1);
- wl = vef_read(htc,
- st->ptr + st->len, st->space - st->len, bytes);
- if (wl <= 0)
- return (wl);
- VEP_Parse(bo, (const char *)st->ptr + st->len, wl);
- VBO_extend(bo, wl);
- bytes -= wl;
- }
- return (1);
-}
-
-/*---------------------------------------------------------------------
- * We receive a gzip'ed object, and want to store it ungzip'ed.
- */
-
-static int
-vfp_esi_bytes_gu(struct busyobj *bo, const struct vef_priv *vef,
- struct http_conn *htc, ssize_t bytes)
-{
- struct vgz *vg;
- ssize_t wl;
- enum vgzret_e vr;
- size_t dl;
- const void *dp;
-
- CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
- CHECK_OBJ_NOTNULL(vef, VEF_MAGIC);
- vg = bo->vgz_rx;
-
- while (bytes > 0) {
- if (VGZ_IbufEmpty(vg) && bytes > 0) {
- wl = vef_read(htc, vef->ibuf, vef->ibuf_sz, bytes);
- if (wl <= 0)
- return (wl);
- VGZ_Ibuf(vg, vef->ibuf, wl);
- bytes -= wl;
- }
- if (VGZ_ObufStorage(bo, vg))
- return(-1);
- vr = VGZ_Gunzip(vg, &dp, &dl);
- if (vr < VGZ_OK)
- return (-1);
- if (dl > 0) {
- VEP_Parse(bo, dp, dl);
- VBO_extend(bo, dl);
- }
- }
- return (1);
-}
-
-/*---------------------------------------------------------------------
- * We receive a [un]gzip'ed object, and want to store it gzip'ed.
- *
- * This is rather complicated, because the ESI parser does not
- * spit out all bytes we feed it right away: Sometimes it needs
- * more input to make up its mind.
- *
- * The inject function feeds uncompressed bytes into the VEP, and
- * takes care to keep any bytes VEP didn't decide on intact until
- * later.
- *
- * The callback is called by VEP to dispose of bytes and report
- * where to find them again later.
- */
-
-static int
-vfp_vep_inject(const struct busyobj *bo, struct vef_priv *vef, ssize_t wl)
-{
-
- CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
- CHECK_OBJ_NOTNULL(vef, VEF_MAGIC);
-
- VEP_Parse(bo, vef->ibuf_i, wl);
- vef->ibuf_i += wl;
- assert(vef->ibuf_o >= vef->ibuf && vef->ibuf_o <= vef->ibuf_i);
- if (vef->error) {
- errno = vef->error;
- return (-1);
- }
- wl = vef->ibuf_i - vef->ibuf_o;
- if (wl > 0)
- memmove(vef->ibuf, vef->ibuf_o, wl);
- vef->ibuf_o = vef->ibuf;
- vef->ibuf_i = vef->ibuf + wl;
- return (0);
-}
-
static ssize_t
-vfp_vep_callback(struct busyobj *bo, ssize_t l, enum vgz_flag flg)
+vfp_vep_callback(struct busyobj *bo, void *priv, ssize_t l, enum vgz_flag flg)
{
struct vef_priv *vef;
size_t dl;
const void *dp;
+ struct storage *st;
int i;
CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
- vef = bo->vef_priv;
- CHECK_OBJ_NOTNULL(vef, VEF_MAGIC);
+ CAST_OBJ_NOTNULL(vef, priv, VEF_MAGIC);
assert(l >= 0);
if (vef->error) {
@@ -211,177 +83,36 @@ vfp_vep_callback(struct busyobj *bo, ssize_t l, enum vgz_flag flg)
VGZ_Ibuf(vef->vgz, vef->ibuf_o, l);
do {
- if (VGZ_ObufStorage(bo, vef->vgz)) {
+ st = VFP_GetStorage(bo, 0);
+ if (st == NULL) {
vef->error = ENOMEM;
vef->tot += l;
return (vef->tot);
}
+ VGZ_Obuf(vef->vgz, st->ptr + st->len, st->space - st->len);
i = VGZ_Gzip(vef->vgz, &dp, &dl, flg);
vef->tot += dl;
VBO_extend(bo, dl);
- } while (!VGZ_IbufEmpty(vef->vgz) ||
- (flg != VGZ_NORMAL && VGZ_ObufFull(vef->vgz)));
- assert(VGZ_IbufEmpty(vef->vgz));
+ } while (i != VGZ_ERROR &&
+ (!VGZ_IbufEmpty(vef->vgz) || VGZ_ObufFull(vef->vgz)));
+ assert(i == VGZ_ERROR || VGZ_IbufEmpty(vef->vgz));
vef->ibuf_o += l;
- if (flg == VGZ_FINISH)
- assert(i == 1); /* XXX */
- else
- assert(i == 0); /* XXX */
return (vef->tot);
}
-/*---------------------------------------------------------------------
- * We receive a gunzip'ed object, and want to store it gzip'ed.
- */
-
-static int
-vfp_esi_bytes_ug(const struct busyobj *bo, struct vef_priv *vef,
- struct http_conn *htc, ssize_t bytes)
-{
- ssize_t wl;
-
- CHECK_OBJ_NOTNULL(vef, VEF_MAGIC);
- CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
-
- while (bytes > 0) {
- wl = vef->ibuf_sz - (vef->ibuf_i - vef->ibuf);
- wl = vef_read(htc, vef->ibuf_i, wl, bytes);
- if (wl <= 0)
- return (wl);
- bytes -= wl;
- if (vfp_vep_inject(bo, vef, wl))
- return (-1);
- }
- return (1);
-}
-
-/*---------------------------------------------------------------------
- * We receive a gzip'ed object, and want to store it gzip'ed.
- */
-
-static int
-vfp_esi_bytes_gg(const struct busyobj *bo, struct vef_priv *vef,
- struct http_conn *htc, size_t bytes)
-{
- ssize_t wl;
- size_t dl;
- const void *dp;
- enum vgzret_e vr;
-
- CHECK_OBJ_NOTNULL(vef, VEF_MAGIC);
- CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
-
- while (bytes > 0) {
- wl = vef_read(htc, vef->ibuf2, vef->ibuf2_sz, bytes);
- if (wl <= 0)
- return (wl);
- bytes -= wl;
-
- VGZ_Ibuf(bo->vgz_rx, vef->ibuf2, wl);
- do {
- wl = vef->ibuf_sz - (vef->ibuf_i - vef->ibuf);
- VGZ_Obuf(bo->vgz_rx, vef->ibuf_i, wl);
- vr = VGZ_Gunzip(bo->vgz_rx, &dp, &dl);
- if (vr < VGZ_OK)
- return (-1);
- if (dl > 0 && vfp_vep_inject(bo, vef, dl))
- return (-1);
- } while (!VGZ_IbufEmpty(bo->vgz_rx));
- }
- return (1);
-}
-
-/*---------------------------------------------------------------------*/
-
-static void __match_proto__(vfp_begin_f)
-vfp_esi_begin(struct busyobj *bo, size_t estimate)
-{
- struct vef_priv *vef;
-
- CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
- (void)estimate;
-
- ALLOC_OBJ(vef, VEF_MAGIC);
- XXXAN(vef);
- AZ(bo->vef_priv);
- bo->vef_priv = vef;
-
- AZ(bo->vgz_rx);
- if (bo->is_gzip && bo->do_gunzip) {
- bo->vgz_rx = VGZ_NewUngzip(bo->vsl, "U F E");
- VEP_Init(bo, NULL);
- vef->ibuf_sz = cache_param->gzip_buffer;
- } else if (bo->is_gunzip && bo->do_gzip) {
- vef->vgz = VGZ_NewGzip(bo->vsl, "G F E");
- VEP_Init(bo, vfp_vep_callback);
- vef->ibuf_sz = cache_param->gzip_buffer;
- } else if (bo->is_gzip) {
- bo->vgz_rx = VGZ_NewUngzip(bo->vsl, "U F E");
- vef->vgz = VGZ_NewGzip(bo->vsl, "G F E");
- VEP_Init(bo, vfp_vep_callback);
- vef->ibuf_sz = cache_param->gzip_buffer;
- vef->ibuf2_sz = cache_param->gzip_buffer;
- } else {
- VEP_Init(bo, NULL);
- }
- if (vef->ibuf_sz > 0) {
- vef->ibuf = calloc(1L, vef->ibuf_sz);
- XXXAN(vef->ibuf);
- vef->ibuf_i = vef->ibuf;
- vef->ibuf_o = vef->ibuf;
- }
- if (vef->ibuf2_sz > 0) {
- vef->ibuf2 = calloc(1L, vef->ibuf2_sz);
- XXXAN(vef->ibuf2);
- }
- AN(bo->vep);
-}
-
-static int __match_proto__(vfp_bytes_f)
-vfp_esi_bytes(struct busyobj *bo, struct http_conn *htc, ssize_t bytes)
-{
- struct vef_priv *vef;
- int i;
-
- CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
- vef = bo->vef_priv;
- CHECK_OBJ_NOTNULL(vef, VEF_MAGIC);
-
- AN(bo->vep);
- assert(&bo->htc == htc);
- if (bo->is_gzip && bo->do_gunzip)
- i = vfp_esi_bytes_gu(bo, vef, htc, bytes);
- else if (bo->is_gunzip && bo->do_gzip)
- i = vfp_esi_bytes_ug(bo, vef, htc, bytes);
- else if (bo->is_gzip)
- i = vfp_esi_bytes_gg(bo, vef, htc, bytes);
- else
- i = vfp_esi_bytes_uu(bo, vef, htc, bytes);
- AN(bo->vep);
- return (i);
-}
-
-static int __match_proto__(vfp_end_f)
-vfp_esi_end(struct busyobj *bo)
+static enum vfp_status
+vfp_esi_end(struct busyobj *bo, struct vef_priv *vef, enum vfp_status retval)
{
struct vsb *vsb;
- struct vef_priv *vef;
ssize_t l;
- int retval = 0;
CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
- AN(bo->vep);
-
- if (bo->state == BOS_FAILED)
- retval = -1;
-
- if (bo->vgz_rx != NULL && VGZ_Destroy(&bo->vgz_rx) != VGZ_END)
- retval = VFP_Error(bo, "Gunzip+ESI Failed at the very end");
+ CHECK_OBJ_NOTNULL(vef, VEF_MAGIC);
- vsb = VEP_Finish(bo);
+ vsb = VEP_Finish(vef->vep, bo);
if (vsb != NULL) {
- if (!retval) {
+ if (retval == VFP_END) {
l = VSB_len(vsb);
assert(l > 0);
/* XXX: This is a huge waste of storage... */
@@ -398,9 +129,6 @@ vfp_esi_end(struct busyobj *bo)
VSB_delete(vsb);
}
- vef = bo->vef_priv;
- bo->vef_priv = NULL;
- CHECK_OBJ_NOTNULL(vef, VEF_MAGIC);
if (vef->vgz != NULL) {
VGZ_UpdateObj(vef->vgz, bo->fetch_obj);
if (VGZ_Destroy(&vef->vgz) != VGZ_END)
@@ -408,15 +136,107 @@ vfp_esi_end(struct busyobj *bo)
"ESI+Gzip Failed at the very end");
}
if (vef->ibuf != NULL)
- free(vef->ibuf);
- if (vef->ibuf2 != NULL)
- free(vef->ibuf2);
FREE_OBJ(vef);
return (retval);
}
-const struct vfp vfp_esi = {
- .begin = vfp_esi_begin,
- .bytes = vfp_esi_bytes,
- .end = vfp_esi_end,
-};
+enum vfp_status __match_proto__(vfp_pull_f)
+vfp_esi_gzip_pull(struct busyobj *bo, void *p, ssize_t *lp, intptr_t *priv)
+{
+ enum vfp_status vp;
+ ssize_t d, l;
+ struct vef_priv *vef;
+
+ CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
+ if (p == vfp_init) {
+ ALLOC_OBJ(vef, VEF_MAGIC);
+ XXXAN(vef);
+ vef->vgz = VGZ_NewGzip(bo->vsl, "G F E");
+ vef->vep = VEP_Init(bo, vfp_vep_callback, vef);
+ vef->ibuf_sz = cache_param->gzip_buffer;
+ vef->ibuf = calloc(1L, vef->ibuf_sz);
+ XXXAN(vef->ibuf);
+ vef->ibuf_i = vef->ibuf;
+ vef->ibuf_o = vef->ibuf;
+ *priv = (uintptr_t)vef;
+ return (VFP_OK);
+ }
+ if (p == vfp_fini) {
+ if (*priv)
+ (void)vfp_esi_end(bo, (void*)*priv, VFP_ERROR);
+ *priv = 0;
+ return (VFP_ERROR);
+ }
+ AN(p);
+ AN(lp);
+ *lp = 0;
+ AN(priv);
+ CAST_OBJ_NOTNULL(vef, (void*)*priv, VEF_MAGIC);
+ l = vef->ibuf_sz - (vef->ibuf_i - vef->ibuf);
+ if (DO_DEBUG(DBG_ESI_CHOP)) {
+ d = (random() & 3) + 1;
+ if (d < l)
+ l = d;
+ }
+ vp = VFP_Suck(bo, vef->ibuf_i, &l);
+
+ if (l > 0) {
+ VEP_Parse(vef->vep, bo, vef->ibuf_i, l);
+ vef->ibuf_i += l;
+ assert(vef->ibuf_o >= vef->ibuf && vef->ibuf_o <= vef->ibuf_i);
+ if (vef->error) {
+ errno = vef->error;
+ return (VFP_ERROR);
+ }
+ l = vef->ibuf_i - vef->ibuf_o;
+ if (l > 0)
+ memmove(vef->ibuf, vef->ibuf_o, l);
+ vef->ibuf_o = vef->ibuf;
+ vef->ibuf_i = vef->ibuf + l;
+ }
+ if (vp == VFP_END) {
+ vp = vfp_esi_end(bo, vef, vp);
+ *priv = 0;
+ }
+ return (vp);
+}
+
+enum vfp_status __match_proto__(vfp_pull_f)
+vfp_esi_pull(struct busyobj *bo, void *p, ssize_t *lp, intptr_t *priv)
+{
+ enum vfp_status vp;
+ ssize_t d;
+ struct vef_priv *vef;
+
+ CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
+ if (p == vfp_init) {
+ ALLOC_OBJ(vef, VEF_MAGIC);
+ XXXAN(vef);
+ vef->vep = VEP_Init(bo, NULL, NULL);
+ *priv = (uintptr_t)vef;
+ return (VFP_OK);
+ }
+ if (p == vfp_fini) {
+ if (*priv)
+ (void)vfp_esi_end(bo, (void*)*priv, VFP_ERROR);
+ *priv = 0;
+ return (VFP_ERROR);
+ }
+ AN(p);
+ AN(lp);
+ AN(priv);
+ CAST_OBJ_NOTNULL(vef, (void*)*priv, VEF_MAGIC);
+ if (DO_DEBUG(DBG_ESI_CHOP)) {
+ d = (random() & 3) + 1;
+ if (d < *lp)
+ *lp = d;
+ }
+ vp = VFP_Suck(bo, p, lp);
+ if (vp != VFP_ERROR && *lp > 0)
+ VEP_Parse(vef->vep, bo, p, *lp);
+ if (vp == VFP_END) {
+ vp = vfp_esi_end(bo, vef, vp);
+ *priv = 0;
+ }
+ return (vp);
+}
diff --git a/bin/varnishd/cache/cache_esi_parse.c b/bin/varnishd/cache/cache_esi_parse.c
index 1c900f6..66d3420 100644
--- a/bin/varnishd/cache/cache_esi_parse.c
+++ b/bin/varnishd/cache/cache_esi_parse.c
@@ -63,6 +63,7 @@ struct vep_state {
struct busyobj *bo;
int dogzip;
vep_callback_t *cb;
+ void *cb_priv;
/* Internal Counter for default call-back function */
ssize_t cb_x;
@@ -329,7 +330,7 @@ vep_mark_common(struct vep_state *vep, const char *p, enum vep_mark mark)
*/
if (vep->last_mark != mark && (vep->o_wait > 0 || vep->startup)) {
- lcb = vep->cb(vep->bo, 0,
+ lcb = vep->cb(vep->bo, vep->cb_priv, 0,
mark == VERBATIM ? VGZ_RESET : VGZ_ALIGN);
if (lcb - vep->o_last > 0)
vep_emit_common(vep, lcb - vep->o_last, vep->last_mark);
@@ -339,7 +340,8 @@ vep_mark_common(struct vep_state *vep, const char *p, enum vep_mark mark)
/* Transfer pending bytes CRC into active mode CRC */
if (vep->o_pending) {
- (void)vep->cb(vep->bo, vep->o_pending, VGZ_NORMAL);
+ (void)vep->cb(vep->bo, vep->cb_priv, vep->o_pending,
+ VGZ_NORMAL);
if (vep->o_crc == 0) {
vep->crc = vep->crcp;
vep->o_crc = vep->o_pending;
@@ -363,7 +365,7 @@ vep_mark_common(struct vep_state *vep, const char *p, enum vep_mark mark)
vep->o_wait += l;
vep->last_mark = mark;
- (void)vep->cb(vep->bo, l, VGZ_NORMAL);
+ (void)vep->cb(vep->bo, vep->cb_priv, l, VGZ_NORMAL);
}
static void
@@ -565,15 +567,14 @@ vep_do_include(struct vep_state *vep, enum dowhat what)
*/
void
-VEP_Parse(const struct busyobj *bo, const char *p, size_t l)
+VEP_Parse(struct vep_state *vep, const struct busyobj *bo, const char *p,
+ size_t l)
{
- struct vep_state *vep;
const char *e;
struct vep_match *vm;
int i;
CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
- vep = bo->vep;
CHECK_OBJ_NOTNULL(vep, VEP_MAGIC);
assert(l > 0);
@@ -1013,29 +1014,27 @@ VEP_Parse(const struct busyobj *bo, const char *p, size_t l)
*/
static ssize_t __match_proto__()
-vep_default_cb(struct busyobj *bo, ssize_t l, enum vgz_flag flg)
+vep_default_cb(struct busyobj *bo, void *priv, ssize_t l, enum vgz_flag flg)
{
- struct vep_state *vep;
+ ssize_t *s;
CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
- vep = bo->vep;
- CHECK_OBJ_NOTNULL(vep, VEP_MAGIC);
- assert(vep->bo == bo);
+ AN(priv);
+ s = priv;
+ *s += l;
(void)flg;
- vep->cb_x += l;
- return (vep->cb_x);
+ return (*s);
}
/*---------------------------------------------------------------------
*/
-void
-VEP_Init(struct busyobj *bo, vep_callback_t *cb)
+struct vep_state *
+VEP_Init(struct busyobj *bo, vep_callback_t *cb, void *cb_priv)
{
struct vep_state *vep;
CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
- AZ(bo->vep);
vep = (void*)WS_Alloc(bo->ws, sizeof *vep);
AN(vep);
@@ -1044,15 +1043,16 @@ VEP_Init(struct busyobj *bo, vep_callback_t *cb)
vep->bo = bo;
vep->vsb = VSB_new_auto();
AN(vep->vsb);
- bo->vep = vep;
if (cb != NULL) {
vep->dogzip = 1;
/* XXX */
VSB_printf(vep->vsb, "%c", VEC_GZ);
vep->cb = cb;
+ vep->cb_priv = cb_priv;
} else {
vep->cb = vep_default_cb;
+ vep->cb_priv = &vep->cb_x;
}
vep->state = VEP_START;
@@ -1069,31 +1069,29 @@ VEP_Init(struct busyobj *bo, vep_callback_t *cb)
vep->last_mark = SKIP;
vep_mark_common(vep, vep->ver_p, VERBATIM);
vep->startup = 0;
+ return (vep);
}
/*---------------------------------------------------------------------
*/
struct vsb *
-VEP_Finish(struct busyobj *bo)
+VEP_Finish(struct vep_state *vep, const struct busyobj *bo)
{
- struct vep_state *vep;
ssize_t l, lcb;
CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
- vep = bo->vep;
CHECK_OBJ_NOTNULL(vep, VEP_MAGIC);
assert(vep->bo == bo);
if (vep->o_pending)
vep_mark_common(vep, vep->ver_p, vep->last_mark);
if (vep->o_wait > 0) {
- lcb = vep->cb(vep->bo, 0, VGZ_ALIGN);
+ lcb = vep->cb(vep->bo, vep->cb_priv, 0, VGZ_ALIGN);
vep_emit_common(vep, lcb - vep->o_last, vep->last_mark);
}
- (void)vep->cb(vep->bo, 0, VGZ_FINISH);
+ (void)vep->cb(vep->bo, vep->cb_priv, 0, VGZ_FINISH);
- bo->vep = NULL;
AZ(VSB_finish(vep->vsb));
l = VSB_len(vep->vsb);
if (vep->esi_found && l > 0)
diff --git a/bin/varnishd/cache/cache_fetch.c b/bin/varnishd/cache/cache_fetch.c
index 7e1a5e2..eb066eb 100644
--- a/bin/varnishd/cache/cache_fetch.c
+++ b/bin/varnishd/cache/cache_fetch.c
@@ -259,6 +259,7 @@ vbf_stp_fetch(struct worker *wrk, struct busyobj *bo)
struct vsb *vary = NULL;
int varyl = 0;
struct object *obj;
+ ssize_t est = -1;
CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
@@ -309,24 +310,27 @@ vbf_stp_fetch(struct worker *wrk, struct busyobj *bo)
/* But we can't do both at the same time */
assert(bo->do_gzip == 0 || bo->do_gunzip == 0);
- /* ESI takes precedence and handles gzip/gunzip itself */
- if (bo->do_esi) {
- bo->vfp = &vfp_esi;
- /*
- * The one case were we do not weaken Etag is where
- * incoming obj is not gzip'ed and we don't gzip either
- * If we ESI expand it on deliver, we weaken there.
- */
- if (bo->is_gzip || bo->do_gzip | bo->do_gunzip)
- RFC2616_Weaken_Etag(bo->beresp);
- } else if (bo->do_gunzip) {
- bo->vfp = &vfp_gunzip;
+ if (bo->vbc != NULL)
+ est = V1F_Setup_Fetch(bo);
+
+ if (bo->do_gunzip || (bo->is_gzip && bo->do_esi)) {
+ RFC2616_Weaken_Etag(bo->beresp);
+ VFP_Push(bo, vfp_gunzip_pull, 0);
+ }
+
+ if (bo->do_esi && bo->do_gzip) {
+ VFP_Push(bo, vfp_esi_gzip_pull, 0);
+ RFC2616_Weaken_Etag(bo->beresp);
+ } else if (bo->do_esi && bo->is_gzip && !bo->do_gunzip) {
+ VFP_Push(bo, vfp_esi_gzip_pull, 0);
RFC2616_Weaken_Etag(bo->beresp);
+ } else if (bo->do_esi) {
+ VFP_Push(bo, vfp_esi_pull, 0);
} else if (bo->do_gzip) {
- bo->vfp = &vfp_gzip;
+ VFP_Push(bo, vfp_gzip_pull, 0);
RFC2616_Weaken_Etag(bo->beresp);
- } else if (bo->is_gzip) {
- bo->vfp = &vfp_testgzip;
+ } else if (bo->is_gzip && !bo->do_gunzip) {
+ VFP_Push(bo, vfp_testgunzip_pull, 0);
}
if (bo->fetch_objcore->flags & OC_F_PRIVATE)
@@ -437,9 +441,6 @@ vbf_stp_fetch(struct worker *wrk, struct busyobj *bo)
if (bo->do_stream)
HSH_Unbusy(&wrk->stats, obj->objcore);
- if (bo->vfp == NULL)
- bo->vfp = &VFP_nop;
-
assert(bo->state == BOS_REQ_DONE);
VBO_setstate(bo, BOS_FETCHING);
@@ -455,8 +456,7 @@ vbf_stp_fetch(struct worker *wrk, struct busyobj *bo)
if (bo->vbc == NULL)
(void)VFP_Error(bo, "Backend connection gone");
else
- V1F_fetch_body(bo);
- break;
+ VFP_Fetch_Body(bo, est);
}
bo->stats = NULL;
@@ -471,14 +471,12 @@ vbf_stp_fetch(struct worker *wrk, struct busyobj *bo)
AZ(bo->vbc);
}
- bo->vfp = NULL;
+ http_Teardown(bo->bereq);
+ http_Teardown(bo->beresp);
VSLb(bo->vsl, SLT_Fetch_Body, "%u(%s)",
bo->htc.body_status, body_status_2str(bo->htc.body_status));
- http_Teardown(bo->bereq);
- http_Teardown(bo->beresp);
-
if (bo->state == BOS_FAILED) {
wrk->stats.fetch_failed++;
} else {
diff --git a/bin/varnishd/cache/cache_fetch_proc.c b/bin/varnishd/cache/cache_fetch_proc.c
index e170d89..d7c3610 100644
--- a/bin/varnishd/cache/cache_fetch_proc.c
+++ b/bin/varnishd/cache/cache_fetch_proc.c
@@ -43,6 +43,9 @@
static unsigned fetchfrag;
+char vfp_init[] = "<init>";
+char vfp_fini[] = "<fini>";
+
/*--------------------------------------------------------------------
* We want to issue the first error we encounter on fetching and
* supress the rest. This function does that.
@@ -52,114 +55,24 @@ static unsigned fetchfrag;
* For convenience, always return -1
*/
-int
-VFP_Error2(struct busyobj *bo, const char *error, const char *more)
+enum vfp_status
+VFP_Error(struct busyobj *bo, const char *fmt, ...)
{
+ va_list ap;
CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
if (bo->state < BOS_FAILED) {
- if (more == NULL)
- VSLb(bo->vsl, SLT_FetchError, "%s", error);
- else
- VSLb(bo->vsl, SLT_FetchError, "%s: %s", error, more);
+ va_start(ap, fmt);
+ VSLbv(bo->vsl, SLT_FetchError, fmt, ap);
+ va_end(ap);
if (bo->fetch_objcore != NULL)
HSH_Fail(bo->fetch_objcore);
VBO_setstate(bo, BOS_FAILED);
}
- return (-1);
-}
-
-int
-VFP_Error(struct busyobj *bo, const char *error)
-{
- return(VFP_Error2(bo, error, NULL));
-}
-
-/*--------------------------------------------------------------------
- * VFP_NOP
- *
- * This fetch-processor does nothing but store the object.
- * It also documents the API
- */
-
-/*--------------------------------------------------------------------
- * VFP_BEGIN
- *
- * Called to set up stuff.
- *
- * 'estimate' is the estimate of the number of bytes we expect to receive,
- * as seen on the socket, or zero if unknown.
- */
-
-static void __match_proto__(vfp_begin_f)
-vfp_nop_begin(struct busyobj *bo, size_t estimate)
-{
-
- CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
-
- if (estimate > 0)
- (void)VFP_GetStorage(bo, estimate);
-}
-
-/*--------------------------------------------------------------------
- * VFP_BYTES
- *
- * Process (up to) 'bytes' from the socket.
- *
- * Return -1 on error, issue VFP_Error()
- * will not be called again, once error happens.
- * Return 0 on EOF on socket even if bytes not reached.
- * Return 1 when 'bytes' have been processed.
- */
-
-static int __match_proto__(vfp_bytes_f)
-vfp_nop_bytes(struct busyobj *bo, struct http_conn *htc, ssize_t bytes)
-{
- ssize_t l, wl;
- struct storage *st;
-
- CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
-
- while (bytes > 0) {
- st = VFP_GetStorage(bo, 0);
- if (st == NULL)
- return(-1);
- l = st->space - st->len;
- if (l > bytes)
- l = bytes;
- wl = HTTP1_Read(htc, st->ptr + st->len, l);
- if (wl <= 0)
- return (wl);
- VBO_extend(bo, wl);
- bytes -= wl;
- }
- return (1);
+ return (VFP_ERROR);
}
/*--------------------------------------------------------------------
- * VFP_END
- *
- * Finish & cleanup
- *
- * Return -1 for error
- * Return 0 for OK
- */
-
-static int __match_proto__(vfp_end_f)
-vfp_nop_end(struct busyobj *bo)
-{
-
- (void)bo;
- return (0);
-}
-
-const struct vfp VFP_nop = {
- .begin = vfp_nop_begin,
- .bytes = vfp_nop_bytes,
- .end = vfp_nop_end,
-};
-
-/*--------------------------------------------------------------------
* Fetch Storage to put object into.
*
*/
@@ -196,6 +109,160 @@ VFP_GetStorage(struct busyobj *bo, ssize_t sz)
return (st);
}
+/**********************************************************************
+ */
+
+static enum vfp_status
+vfp_call(struct busyobj *bo, int nbr, void *p, ssize_t *lp)
+{
+ AN(bo->vfps[nbr]);
+ return (bo->vfps[nbr](bo, p, lp, &bo->vfps_priv[nbr]));
+}
+
+static void
+vfp_suck_fini(struct busyobj *bo)
+{
+ int i;
+
+ for (i = 0; i < bo->vfp_nxt; i++) {
+ if(bo->vfps[i] != NULL)
+ (void)vfp_call(bo, i, vfp_fini, NULL);
+ }
+}
+
+static enum vfp_status
+vfp_suck_init(struct busyobj *bo)
+{
+ enum vfp_status retval = VFP_ERROR;
+ int i;
+
+ for (i = 0; i < bo->vfp_nxt; i++) {
+ retval = vfp_call(bo, i, vfp_init, NULL);
+ if (retval != VFP_OK) {
+ vfp_suck_fini(bo);
+ break;
+ }
+ }
+ return (retval);
+}
+
+/**********************************************************************
+ * Suck data up from lower levels.
+ * Once a layer return non VFP_OK, clean it up and produce the same
+ * return value for any subsequent calls.
+ */
+
+enum vfp_status
+VFP_Suck(struct busyobj *bo, void *p, ssize_t *lp)
+{
+ enum vfp_status vp;
+
+ CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
+ AN(p);
+ AN(lp);
+ assert(bo->vfp_nxt > 0);
+ bo->vfp_nxt--;
+ if (bo->vfps[bo->vfp_nxt] == NULL) {
+ *lp = 0;
+ vp = (enum vfp_status)bo->vfps_priv[bo->vfp_nxt];
+ } else {
+ vp = vfp_call(bo, bo->vfp_nxt, p, lp);
+ if (vp != VFP_OK) {
+ (void)vfp_call(bo, bo->vfp_nxt, vfp_fini, NULL);
+ bo->vfps[bo->vfp_nxt] = NULL;
+ bo->vfps_priv[bo->vfp_nxt] = vp;
+ }
+ }
+ bo->vfp_nxt++;
+ return (vp);
+}
+
+/*--------------------------------------------------------------------
+ */
+
+void
+VFP_Fetch_Body(struct busyobj *bo, ssize_t est)
+{
+ ssize_t l;
+ enum vfp_status vfps = VFP_ERROR;
+ struct storage *st = NULL;
+
+ CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
+
+ AN(bo->vfp_nxt);
+
+ if (est < 0)
+ est = 0;
+
+ if (vfp_suck_init(bo) != VFP_OK) {
+ (void)VFP_Error(bo, "Fetch Pipeline failed to initialize");
+ bo->should_close = 1;
+ return;
+ }
+
+ do {
+ if (st == NULL) {
+ l = fetchfrag;
+ if (l == 0) {
+ l = est;
+ est = 0;
+ }
+ if (l == 0)
+ l = cache_param->fetch_chunksize;
+ st = STV_alloc(bo, l);
+ if (st == NULL) {
+ bo->should_close = 1;
+ /* XXX Close VFP stack */
+ (void)VFP_Error(bo, "Out of storage");
+ break;
+ }
+ AZ(st->len);
+ Lck_Lock(&bo->mtx);
+ VTAILQ_INSERT_TAIL(&bo->fetch_obj->store, st, list);
+ Lck_Unlock(&bo->mtx);
+ }
+ l = st->space - st->len;
+ vfps = VFP_Suck(bo, st->ptr + st->len, &l);
+ if (l > 0)
+ VBO_extend(bo, l);
+ if (st->len == st->space)
+ st = NULL;
+ } while (vfps == VFP_OK);
+
+ if (vfps == VFP_ERROR) {
+ (void)VFP_Error(bo, "Fetch Pipeline failed to process");
+ bo->should_close = 1;
+ }
+
+ vfp_suck_fini(bo);
+
+ /*
+ * Trim or delete the last segment, if any
+ */
+
+ st = VTAILQ_LAST(&bo->fetch_obj->store, storagehead);
+ /* XXX: Temporary: Only trim if we are not streaming */
+ if (st != NULL && !bo->do_stream) {
+ /* None of this this is safe under streaming */
+ if (st->len == 0) {
+ VTAILQ_REMOVE(&bo->fetch_obj->store, st, list);
+ STV_free(st);
+ } else if (st->len < st->space) {
+ STV_trim(st, st->len, 1);
+ }
+ }
+}
+
+void
+VFP_Push(struct busyobj *bo, vfp_pull_f *func, intptr_t priv)
+{
+
+ CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
+ bo->vfps_priv[bo->vfp_nxt] = priv;
+ bo->vfps[bo->vfp_nxt] = func;
+ bo->vfp_nxt++;
+}
+
/*--------------------------------------------------------------------
* Debugging aids
*/
diff --git a/bin/varnishd/cache/cache_gzip.c b/bin/varnishd/cache/cache_gzip.c
index 09f1594..bdbf229 100644
--- a/bin/varnishd/cache/cache_gzip.c
+++ b/bin/varnishd/cache/cache_gzip.c
@@ -51,9 +51,8 @@ struct vgz {
enum {VGZ_GZ,VGZ_UN} dir;
struct vsl_log *vsl;
const char *id;
- struct ws *tmp;
- char *tmp_snapshot;
int last_i;
+ enum vgz_flag flag;
/* Wrw stuff */
char *m_buf;
@@ -117,11 +116,6 @@ VGZ_NewGzip(struct vsl_log *vsl, const char *id)
*
* windowBits [8..15] (-> 1K..128K)
* memLevel [1..9] (-> 1K->256K)
- *
- * XXX: They probably needs to be params...
- *
- * XXX: It may be more efficent to malloc them, rather than have
- * XXX: too many worker threads grow the stacks.
*/
i = deflateInit2(&vg->vz,
cache_param->gzip_level, /* Level */
@@ -195,24 +189,6 @@ VGZ_ObufFull(const struct vgz *vg)
return (vg->vz.avail_out == 0);
}
-/*--------------------------------------------------------------------
- * Keep the outbuffer supplied with storage
- */
-
-int
-VGZ_ObufStorage(struct busyobj *bo, struct vgz *vg)
-{
- struct storage *st;
-
- st = VFP_GetStorage(bo, 0);
- if (st == NULL)
- return (-1);
-
- VGZ_Obuf(vg, st->ptr + st->len, st->space - st->len);
-
- return (0);
-}
-
/*--------------------------------------------------------------------*/
enum vgzret_e
@@ -445,8 +421,6 @@ VGZ_Destroy(struct vgz **vgp)
(intmax_t)vg->vz.start_bit,
(intmax_t)vg->vz.last_bit,
(intmax_t)vg->vz.stop_bit);
- if (vg->tmp != NULL)
- WS_Reset(vg->tmp, vg->tmp_snapshot);
if (vg->dir == VGZ_GZ)
i = deflateEnd(&vg->vz);
else
@@ -462,7 +436,8 @@ VGZ_Destroy(struct vgz **vgp)
else if (i == Z_BUF_ERROR)
vr = VGZ_STUCK;
else {
- VSLb(vg->vsl, SLT_Gzip, "G(un)zip error: %d (%s)", i, vg->vz.msg);
+ VSLb(vg->vsl, SLT_Gzip, "G(un)zip error: %d (%s)",
+ i, vg->vz.msg);
vr = VGZ_ERROR;
}
FREE_OBJ(vg);
@@ -475,164 +450,139 @@ VGZ_Destroy(struct vgz **vgp)
* A VFP for gunzip'ing an object as we receive it from the backend
*/
-static void __match_proto__(vfp_begin_f)
-vfp_gunzip_begin(struct busyobj *bo, size_t estimate)
-{
-
- CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
- (void)estimate;
- AZ(bo->vgz_rx);
- bo->vgz_rx = VGZ_NewUngzip(bo->vsl, "U F -");
- XXXAZ(vgz_getmbuf(bo->vgz_rx));
-}
-
-static int __match_proto__(vfp_bytes_f)
-vfp_gunzip_bytes(struct busyobj *bo, struct http_conn *htc, ssize_t bytes)
+enum vfp_status __match_proto__(vfp_pull_f)
+vfp_gunzip_pull(struct busyobj *bo, void *p, ssize_t *lp, intptr_t *priv)
{
+ ssize_t l;
struct vgz *vg;
- ssize_t l, wl;
- int i = -100;
- size_t dl;
+ enum vgzret_e vr = VGZ_ERROR;
const void *dp;
-
- CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
- vg = bo->vgz_rx;
- CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC);
- AZ(vg->vz.avail_in);
- while (bytes > 0 || vg->vz.avail_in > 0) {
- if (vg->vz.avail_in == 0 && bytes > 0) {
- l = vg->m_sz;
- if (l > bytes)
- l = bytes;
- wl = htc->read(htc, vg->m_buf, l);
- if (wl <= 0)
- return (wl);
- VGZ_Ibuf(vg, vg->m_buf, wl);
- bytes -= wl;
- }
-
- if (VGZ_ObufStorage(bo, vg))
- return(-1);
- i = VGZ_Gunzip(vg, &dp, &dl);
- if (i != VGZ_OK && i != VGZ_END)
- return(VFP_Error(bo, "Gunzip data error"));
- if (i == VGZ_END && !VGZ_IbufEmpty(vg))
- return(VFP_Error(bo, "Junk after gzip data"));
- VBO_extend(bo, dl);
+ size_t dl;
+ enum vfp_status vp = VFP_OK;
+
+ CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
+ if (p == vfp_init) {
+ vg = VGZ_NewUngzip(bo->vsl, "U F -");
+ XXXAZ(vgz_getmbuf(vg));
+ *priv = (uintptr_t)vg;
+ VGZ_Ibuf(vg, vg->m_buf, 0);
+ AZ(vg->m_len);
+ return (VFP_OK);
}
- assert(i == Z_OK || i == Z_STREAM_END);
- return (1);
-}
-
-static int __match_proto__(vfp_end_f)
-vfp_gunzip_end(struct busyobj *bo)
-{
- struct vgz *vg;
-
- CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
- vg = bo->vgz_rx;
- bo->vgz_rx = NULL;
- CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC);
- if (bo->state == BOS_FAILED) {
- (void)VGZ_Destroy(&vg);
- return(0);
+ if (p == vfp_fini) {
+ if (*priv != 0) {
+ CAST_OBJ_NOTNULL(vg, (void*)(*priv), VGZ_MAGIC);
+ *priv = 0;
+ (void)VGZ_Destroy(&vg);
+ }
+ *priv = 0;
+ return (VFP_ERROR);
}
- if (VGZ_Destroy(&vg) != VGZ_END)
+ AN(p);
+ AN(lp);
+ AN(priv);
+ CAST_OBJ_NOTNULL(vg, (void*)(*priv), VGZ_MAGIC);
+ l = *lp;
+ *lp = 0;
+ VGZ_Obuf(vg, p, l);
+ do {
+ if (VGZ_IbufEmpty(vg)) {
+ l = vg->m_sz;
+ vp = VFP_Suck(bo, vg->m_buf, &l);
+ if (vp == VFP_ERROR)
+ return (vp);
+ VGZ_Ibuf(vg, vg->m_buf, l);
+ }
+ if (!VGZ_IbufEmpty(vg) || vp == VFP_END) {
+ vr = VGZ_Gunzip(vg, &dp, &dl);
+ if (vr == VGZ_END && !VGZ_IbufEmpty(vg))
+ return(VFP_Error(bo, "Junk after gzip data"));
+ if (vr < VGZ_OK)
+ return (VFP_Error(bo,
+ "Invalid Gzip data: %s", vg->vz.msg));
+ if (dl > 0) {
+ *lp = dl;
+ assert(dp == p);
+ return (VFP_OK);
+ }
+ }
+ AN(VGZ_IbufEmpty(vg));
+ } while (vp == VFP_OK);
+ if (vr != VGZ_END)
return(VFP_Error(bo, "Gunzip error at the very end"));
- return (0);
+ return (vp);
}
-const struct vfp vfp_gunzip = {
- .begin = vfp_gunzip_begin,
- .bytes = vfp_gunzip_bytes,
- .end = vfp_gunzip_end,
-};
-
/*--------------------------------------------------------------------
* VFP_GZIP
*
* A VFP for gzip'ing an object as we receive it from the backend
*/
-static void __match_proto__(vfp_begin_f)
-vfp_gzip_begin(struct busyobj *bo, size_t estimate)
-{
- (void)estimate;
-
- CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
- AZ(bo->vgz_rx);
- bo->vgz_rx = VGZ_NewGzip(bo->vsl, "G F -");
- XXXAZ(vgz_getmbuf(bo->vgz_rx));
-}
-
-static int __match_proto__(vfp_bytes_f)
-vfp_gzip_bytes(struct busyobj *bo, struct http_conn *htc, ssize_t bytes)
+enum vfp_status __match_proto__(vfp_pull_f)
+vfp_gzip_pull(struct busyobj *bo, void *p, ssize_t *lp, intptr_t *priv)
{
+ ssize_t l;
struct vgz *vg;
- ssize_t l, wl;
- int i = -100;
- size_t dl;
+ enum vgzret_e vr = VGZ_ERROR;
const void *dp;
-
- CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
- vg = bo->vgz_rx;
- CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC);
- AZ(vg->vz.avail_in);
- while (bytes > 0 || !VGZ_IbufEmpty(vg)) {
- if (VGZ_IbufEmpty(vg) && bytes > 0) {
- l = vg->m_sz;
- if (l > bytes)
- l = bytes;
- wl = htc->read(htc, vg->m_buf, l);
- if (wl <= 0)
- return (wl);
- VGZ_Ibuf(vg, vg->m_buf, wl);
- bytes -= wl;
- }
- if (VGZ_ObufStorage(bo, vg))
- return(-1);
- i = VGZ_Gzip(vg, &dp, &dl, VGZ_NORMAL);
- assert(i == Z_OK);
- VBO_extend(bo, dl);
- }
- return (1);
-}
-
-static int __match_proto__(vfp_end_f)
-vfp_gzip_end(struct busyobj *bo)
-{
- struct vgz *vg;
size_t dl;
- const void *dp;
- int i;
-
- CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
- vg = bo->vgz_rx;
- CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC);
- bo->vgz_rx = NULL;
- if (bo->state == BOS_FAILED) {
- (void)VGZ_Destroy(&vg);
- return(0);
+ enum vfp_status vp = VFP_ERROR;
+
+ CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
+ if (p == vfp_init) {
+ vg = VGZ_NewGzip(bo->vsl, "G F -");
+ XXXAZ(vgz_getmbuf(vg));
+ *priv = (uintptr_t)vg;
+ VGZ_Ibuf(vg, vg->m_buf, 0);
+ AZ(vg->m_len);
+ vg->flag = VGZ_NORMAL;
+ return (VFP_OK);
+ }
+ if (p == vfp_fini) {
+ if (*priv != 0) {
+ CAST_OBJ_NOTNULL(vg, (void*)(*priv), VGZ_MAGIC);
+ *priv = 0;
+ (void)VGZ_Destroy(&vg);
+ }
+ return (VFP_ERROR);
}
+ AN(p);
+ AN(lp);
+ AN(priv);
+ CAST_OBJ_NOTNULL(vg, (void*)(*priv), VGZ_MAGIC);
+ l = *lp;
+ *lp = 0;
+ VGZ_Obuf(vg, p, l);
do {
- VGZ_Ibuf(vg, "", 0);
- if (VGZ_ObufStorage(bo, vg))
- return(-1);
- i = VGZ_Gzip(vg, &dp, &dl, VGZ_FINISH);
- VBO_extend(bo, dl);
- } while (i != Z_STREAM_END);
+ if (VGZ_IbufEmpty(vg)) {
+ l = vg->m_sz;
+ vp = VFP_Suck(bo, vg->m_buf, &l);
+ if (vp == VFP_ERROR)
+ break;
+ if (vp == VFP_END)
+ vg->flag = VGZ_FINISH;
+ VGZ_Ibuf(vg, vg->m_buf, l);
+ }
+ if (!VGZ_IbufEmpty(vg) || vg->flag == VGZ_FINISH) {
+ vr = VGZ_Gzip(vg, &dp, &dl, vg->flag);
+ if (vr < VGZ_OK)
+ return (VFP_Error(bo, "Gzip failed"));
+ if (dl > 0) {
+ *lp = dl;
+ assert(dp == p);
+ return (VFP_OK);
+ }
+ }
+ AN(VGZ_IbufEmpty(vg));
+ } while (vg->flag != VGZ_FINISH);
+
+ if (vr != VGZ_END)
+ return (VFP_Error(bo, "Gzip failed"));
VGZ_UpdateObj(vg, bo->fetch_obj);
- if (VGZ_Destroy(&vg) != VGZ_END)
- return(VFP_Error(bo, "Gzip error at the very end"));
- return (0);
+ return (VFP_END);
}
-const struct vfp vfp_gzip = {
- .begin = vfp_gzip_begin,
- .bytes = vfp_gzip_bytes,
- .end = vfp_gzip_end,
-};
-
/*--------------------------------------------------------------------
* VFP_TESTGZIP
*
@@ -640,80 +590,54 @@ const struct vfp vfp_gzip = {
* collecting the magic bits while we're at it.
*/
-static void __match_proto__(vfp_begin_f)
-vfp_testgzip_begin(struct busyobj *bo, size_t estimate)
-{
-
- CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
- (void)estimate;
- bo->vgz_rx = VGZ_NewUngzip(bo->vsl, "u F -");
- CHECK_OBJ_NOTNULL(bo->vgz_rx, VGZ_MAGIC);
- XXXAZ(vgz_getmbuf(bo->vgz_rx));
-}
-
-static int __match_proto__(vfp_bytes_f)
-vfp_testgzip_bytes(struct busyobj *bo, struct http_conn *htc, ssize_t bytes)
+enum vfp_status __match_proto__(vfp_pull_f)
+vfp_testgunzip_pull(struct busyobj *bo, void *p, ssize_t *lp, intptr_t *priv)
{
struct vgz *vg;
- ssize_t l, wl;
- int i = -100;
- size_t dl;
+ enum vgzret_e vr = VGZ_ERROR;
const void *dp;
- struct storage *st;
-
- CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
- vg = bo->vgz_rx;
- CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC);
- AZ(vg->vz.avail_in);
- while (bytes > 0) {
- st = VFP_GetStorage(bo, 0);
- if (st == NULL)
- return(-1);
- l = st->space - st->len;
- if (l > bytes)
- l = bytes;
- wl = htc->read(htc, st->ptr + st->len, l);
- if (wl <= 0)
- return (wl);
- bytes -= wl;
- VGZ_Ibuf(vg, st->ptr + st->len, wl);
- VBO_extend(bo, wl);
-
- while (!VGZ_IbufEmpty(vg)) {
+ size_t dl;
+ enum vfp_status vp;
+
+ CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
+ if (p == vfp_init) {
+ vg = VGZ_NewUngzip(bo->vsl, "u F -");
+ XXXAZ(vgz_getmbuf(vg));
+ *priv = (uintptr_t)vg;
+ AZ(vg->m_len);
+ return (VFP_OK);
+ }
+ if (p == vfp_fini) {
+ if (*priv != 0) {
+ CAST_OBJ_NOTNULL(vg, (void*)(*priv), VGZ_MAGIC);
+ *priv = 0;
+ (void)VGZ_Destroy(&vg);
+ }
+ return (VFP_ERROR);
+ }
+ AN(p);
+ AN(lp);
+ AN(priv);
+ CAST_OBJ_NOTNULL(vg, (void*)(*priv), VGZ_MAGIC);
+ vp = VFP_Suck(bo, p, lp);
+ if (vp == VFP_ERROR)
+ return (vp);
+ if (*lp > 0 || vp == VFP_END) {
+ VGZ_Ibuf(vg, p, *lp);
+ do {
VGZ_Obuf(vg, vg->m_buf, vg->m_sz);
- i = VGZ_Gunzip(vg, &dp, &dl);
- if (i == VGZ_END && !VGZ_IbufEmpty(vg))
+ vr = VGZ_Gunzip(vg, &dp, &dl);
+ if (vr == VGZ_END && !VGZ_IbufEmpty(vg))
return(VFP_Error(bo, "Junk after gzip data"));
- if (i != VGZ_OK && i != VGZ_END)
- return(VFP_Error2(bo,
- "Invalid Gzip data", vg->vz.msg));
- }
+ if (vr < VGZ_OK)
+ return (VFP_Error(bo,
+ "Invalid Gzip data: %s", vg->vz.msg));
+ } while (!VGZ_IbufEmpty(vg));
}
- assert(i == VGZ_OK || i == VGZ_END);
- return (1);
-}
-
-static int __match_proto__(vfp_end_f)
-vfp_testgzip_end(struct busyobj *bo)
-{
- struct vgz *vg;
-
- CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
- vg = bo->vgz_rx;
- bo->vgz_rx = NULL;
- CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC);
- if (bo->state == BOS_FAILED) {
- (void)VGZ_Destroy(&vg);
- return(0);
+ if (vp == VFP_END) {
+ if (vr != VGZ_END)
+ return (VFP_Error(bo, "tGunzip failed"));
+ VGZ_UpdateObj(vg, bo->fetch_obj);
}
- VGZ_UpdateObj(vg, bo->fetch_obj);
- if (VGZ_Destroy(&vg) != VGZ_END)
- return(VFP_Error(bo, "TestGunzip error at the very end"));
- return (0);
+ return (vp);
}
-
-const struct vfp vfp_testgzip = {
- .begin = vfp_testgzip_begin,
- .bytes = vfp_testgzip_bytes,
- .end = vfp_testgzip_end,
-};
diff --git a/bin/varnishd/cache/cache_http1_fetch.c b/bin/varnishd/cache/cache_http1_fetch.c
index 3e16bcb..1bf8bd1 100644
--- a/bin/varnishd/cache/cache_http1_fetch.c
+++ b/bin/varnishd/cache/cache_http1_fetch.c
@@ -69,22 +69,35 @@ vbf_fetch_number(const char *nbr, int radix)
/*--------------------------------------------------------------------*/
-static int
-vbf_fetch_straight(struct busyobj *bo, struct http_conn *htc, ssize_t cl)
+static enum vfp_status __match_proto__(vfp_pull_f)
+v1f_pull_straight(struct busyobj *bo, void *p, ssize_t *lp, intptr_t *priv)
{
- int i;
-
- assert(htc->body_status == BS_LENGTH);
-
- if (cl < 0) {
- return (VFP_Error(bo, "straight length field bogus"));
- } else if (cl == 0)
- return (0);
+ ssize_t l, lr;
- i = bo->vfp->bytes(bo, htc, cl);
- if (i <= 0)
+ CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
+ if (p == vfp_init)
+ return (VFP_OK);
+ if (p == vfp_fini)
+ return (VFP_ERROR);
+ AN(p);
+ AN(lp);
+ AN(priv);
+
+ l = *lp;
+ *lp = 0;
+
+ if (!*priv) // XXX: Optimize Content-Len: 0 out earlier
+ return (VFP_END);
+ if (*priv < l)
+ l = *priv;
+ lr = HTTP1_Read(&bo->htc, p, l);
+ if (lr <= 0)
return (VFP_Error(bo, "straight insufficient bytes"));
- return (0);
+ *lp = lr;
+ *priv -= lr;
+ if (*priv == 0)
+ return (VFP_END);
+ return (VFP_OK);
}
/*--------------------------------------------------------------------
@@ -93,29 +106,38 @@ vbf_fetch_straight(struct busyobj *bo, struct http_conn *htc, ssize_t cl)
* XXX: Reading one byte at a time is pretty pessimal.
*/
-static int
-vbf_fetch_chunked(struct busyobj *bo, struct http_conn *htc)
+static enum vfp_status __match_proto__(vfp_pull_f)
+v1f_pull_chunked(struct busyobj *bo, void *p, ssize_t *lp, intptr_t *priv)
{
int i;
char buf[20]; /* XXX: 20 is arbitrary */
unsigned u;
- ssize_t cl;
+ ssize_t cl, l, lr;
- assert(htc->body_status == BS_CHUNKED);
- do {
+ CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
+ if (p == vfp_init)
+ return (VFP_OK);
+ if (p == vfp_fini)
+ return (VFP_ERROR);
+ AN(p);
+ AN(lp);
+ AN(priv);
+ l = *lp;
+ *lp = 0;
+ if (*priv == -1) {
/* Skip leading whitespace */
do {
- if (HTTP1_Read(htc, buf, 1) <= 0)
+ if (HTTP1_Read(&bo->htc, buf, 1) <= 0)
return (VFP_Error(bo, "chunked read err"));
} while (vct_islws(buf[0]));
if (!vct_ishex(buf[0]))
- return (VFP_Error(bo, "chunked header non-hex"));
+ return (VFP_Error(bo, "chunked header non-hex"));
/* Collect hex digits, skipping leading zeros */
for (u = 1; u < sizeof buf; u++) {
do {
- if (HTTP1_Read(htc, buf + u, 1) <= 0)
+ if (HTTP1_Read(&bo->htc, buf + u, 1) <= 0)
return (VFP_Error(bo,
"chunked read err"));
} while (u == 1 && buf[0] == '0' && buf[u] == '0');
@@ -128,40 +150,98 @@ vbf_fetch_chunked(struct busyobj *bo, struct http_conn *htc)
/* Skip trailing white space */
while(vct_islws(buf[u]) && buf[u] != '\n')
- if (HTTP1_Read(htc, buf + u, 1) <= 0)
+ if (HTTP1_Read(&bo->htc, buf + u, 1) <= 0)
return (VFP_Error(bo, "chunked read err"));
if (buf[u] != '\n')
return (VFP_Error(bo,"chunked header no NL"));
buf[u] = '\0';
+
cl = vbf_fetch_number(buf, 16);
if (cl < 0)
return (VFP_Error(bo,"chunked header number syntax"));
-
- if (cl > 0 && bo->vfp->bytes(bo, htc, cl) <= 0)
- return (VFP_Error(bo, "chunked read err"));
-
- i = HTTP1_Read(htc, buf, 1);
- if (i <= 0)
- return (VFP_Error(bo, "chunked read err"));
- if (buf[0] == '\r' && HTTP1_Read( htc, buf, 1) <= 0)
- return (VFP_Error(bo, "chunked read err"));
- if (buf[0] != '\n')
- return (VFP_Error(bo,"chunked tail no NL"));
- } while (cl > 0);
- return (0);
+ *priv = cl;
+ }
+ if (*priv > 0) {
+ if (*priv < l)
+ l = *priv;
+ lr = HTTP1_Read(&bo->htc, p, l);
+ if (lr <= 0)
+ return (VFP_Error(bo, "straight insufficient bytes"));
+ *lp = lr;
+ *priv -= lr;
+ if (*priv == 0)
+ *priv = -1;
+ return (VFP_OK);
+ }
+ AZ(*priv);
+ i = HTTP1_Read(&bo->htc, buf, 1);
+ if (i <= 0)
+ return (VFP_Error(bo, "chunked read err"));
+ if (buf[0] == '\r' && HTTP1_Read(&bo->htc, buf, 1) <= 0)
+ return (VFP_Error(bo, "chunked read err"));
+ if (buf[0] != '\n')
+ return (VFP_Error(bo,"chunked tail no NL"));
+ return (VFP_END);
}
/*--------------------------------------------------------------------*/
-static void
-vbf_fetch_eof(struct busyobj *bo, struct http_conn *htc)
+static enum vfp_status __match_proto__(vfp_pull_f)
+v1f_pull_eof(struct busyobj *bo, void *p, ssize_t *lp, intptr_t *priv)
{
+ ssize_t l, lr;
- assert(htc->body_status == BS_EOF);
- if (bo->vfp->bytes(bo, htc, SSIZE_MAX) < 0)
- (void)VFP_Error(bo,"eof socket fail");
+ CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
+ if (p == vfp_init)
+ return (VFP_OK);
+ if (p == vfp_fini)
+ return (VFP_ERROR);
+ AN(p);
+ AN(lp);
+ AN(priv);
+
+ l = *lp;
+ *lp = 0;
+ lr = HTTP1_Read(&bo->htc, p, l);
+ if (lr < 0)
+ return (VFP_Error(bo,"eof socket fail"));
+ if (lr == 0)
+ return (VFP_END);
+ *lp = lr;
+ return (VFP_OK);
+}
+
+/*--------------------------------------------------------------------
+ */
+
+ssize_t
+V1F_Setup_Fetch(struct busyobj *bo)
+{
+ struct http_conn *htc;
+ ssize_t cl;
+
+ CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
+ htc = &bo->htc;
+ CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC);
+ CHECK_OBJ_NOTNULL(bo->vbc, VBC_MAGIC);
+
+ switch(htc->body_status) {
+ case BS_EOF:
+ VFP_Push(bo, v1f_pull_eof, 0);
+ return(-1);
+ case BS_LENGTH:
+ cl = vbf_fetch_number(bo->h_content_length, 10);
+ VFP_Push(bo, v1f_pull_straight, cl);
+ return (cl);
+ case BS_CHUNKED:
+ VFP_Push(bo, v1f_pull_chunked, -1);
+ return (-1);
+ default:
+ break;
+ }
+ return (-1);
}
/*--------------------------------------------------------------------
@@ -267,6 +347,8 @@ V1F_fetch_hdr(struct worker *wrk, struct busyobj *bo, struct req *req)
HTTP1_Init(htc, bo->ws, vc->fd, vc->vsl,
cache_param->http_resp_size,
cache_param->http_resp_hdr_len);
+ CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC);
+ CHECK_OBJ_NOTNULL(&bo->htc, HTTP_CONN_MAGIC);
VTCP_set_read_timeout(vc->fd, vc->first_byte_timeout);
@@ -308,81 +390,3 @@ V1F_fetch_hdr(struct worker *wrk, struct busyobj *bo, struct req *req)
return (0);
}
-/*--------------------------------------------------------------------
- * This function is either called by the requesting thread OR by a
- * dedicated body-fetch work-thread.
- *
- * We get passed the busyobj in the priv arg, and we inherit a
- * refcount on it, which we must release, when done fetching.
- */
-
-void
-V1F_fetch_body(struct busyobj *bo)
-{
- struct storage *st;
- ssize_t cl;
- struct http_conn *htc;
- struct object *obj;
-
- CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
- htc = &bo->htc;
- CHECK_OBJ_ORNULL(bo->vbc, VBC_MAGIC);
- obj = bo->fetch_obj;
- CHECK_OBJ_NOTNULL(obj, OBJECT_MAGIC);
- CHECK_OBJ_NOTNULL(obj->http, HTTP_MAGIC);
- AN(bo->vbc);
-
- assert(bo->state == BOS_FETCHING);
-
- AN(bo->vfp);
- AZ(bo->vgz_rx);
- assert(VTAILQ_EMPTY(&obj->store));
-
- /* XXX: pick up estimate from objdr ? */
- cl = 0;
- switch (htc->body_status) {
- case BS_LENGTH:
- cl = vbf_fetch_number(bo->h_content_length, 10);
-
- bo->vfp->begin(bo, cl);
- if (bo->state == BOS_FETCHING && cl > 0)
- bo->should_close |= vbf_fetch_straight(bo, htc, cl);
- if (bo->vfp->end(bo))
- assert(bo->state == BOS_FAILED);
- break;
- case BS_CHUNKED:
- bo->vfp->begin(bo, cl > 0 ? cl : 0);
- if (bo->state == BOS_FETCHING)
- bo->should_close |= vbf_fetch_chunked(bo, htc);
- if (bo->vfp->end(bo))
- assert(bo->state == BOS_FAILED);
- break;
- case BS_EOF:
- bo->vfp->begin(bo, cl > 0 ? cl : 0);
- if (bo->state == BOS_FETCHING)
- vbf_fetch_eof(bo, htc);
- bo->should_close = 1;
- if (bo->vfp->end(bo))
- assert(bo->state == BOS_FAILED);
- break;
- default:
- WRONG("Wrong body_status");
- }
- AZ(bo->vgz_rx);
-
- /*
- * Trim or delete the last segment, if any
- */
-
- st = VTAILQ_LAST(&bo->fetch_obj->store, storagehead);
- /* XXX: Temporary: Only trim if we are not streaming */
- if (st != NULL && !bo->do_stream) {
- /* XXX: is any of this safe under streaming ? */
- if (st->len == 0) {
- VTAILQ_REMOVE(&bo->fetch_obj->store, st, list);
- STV_free(st);
- } else if (st->len < st->space) {
- STV_trim(st, st->len, 1);
- }
- }
-}
diff --git a/bin/varnishd/cache/cache_shmlog.c b/bin/varnishd/cache/cache_shmlog.c
index 4aa08ce..1a05479 100644
--- a/bin/varnishd/cache/cache_shmlog.c
+++ b/bin/varnishd/cache/cache_shmlog.c
@@ -296,12 +296,11 @@ VSLbt(struct vsl_log *vsl, enum VSL_tag_e tag, txt t)
*/
void
-VSLb(struct vsl_log *vsl, enum VSL_tag_e tag, const char *fmt, ...)
+VSLbv(struct vsl_log *vsl, enum VSL_tag_e tag, const char *fmt, va_list ap)
{
char *p;
const char *u, *f;
unsigned n, mlen;
- va_list ap;
txt t;
AN(fmt);
@@ -329,9 +328,7 @@ VSLb(struct vsl_log *vsl, enum VSL_tag_e tag, const char *fmt, ...)
VSL_Flush(vsl, 1);
p = VSL_DATA(vsl->wlp);
- va_start(ap, fmt);
n = vsnprintf(p, mlen, fmt, ap);
- va_end(ap);
if (n > mlen - 1)
n = mlen - 1; /* we truncate long fields */
p[n++] = '\0'; /* NUL-terminated */
@@ -343,6 +340,16 @@ VSLb(struct vsl_log *vsl, enum VSL_tag_e tag, const char *fmt, ...)
VSL_Flush(vsl, 0);
}
+void
+VSLb(struct vsl_log *vsl, enum VSL_tag_e tag, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ VSLbv(vsl, tag, fmt, ap);
+ va_end(ap);
+}
+
/*--------------------------------------------------------------------
* Setup a VSL buffer, allocate space if none provided.
*/
More information about the varnish-commit
mailing list