--- 2.0.3/varnish-cache/autogen.des	2008-10-16 07:43:08.000000000 +0200
+++ trunk/varnish-cache/autogen.des	2008-11-06 12:22:01.000000000 +0100
@@ -1,6 +1,6 @@
 #!/bin/sh
 #
-# $Id: autogen.des 2458 2008-02-13 17:12:59Z des $
+# $Id: autogen.des 3341 2008-10-20 20:09:51Z des $
 #
 
 set -ex
@@ -11,7 +11,6 @@
 export CONFIG_SHELL=/bin/sh
 
 ./configure \
-    --config-cache \
     --enable-developer-warnings \
     --enable-debugging-symbols \
     --enable-dependency-tracking \
diff -Nru 2.0.3/varnish-cache/bin/varnishadm/varnishadm.c trunk/varnish-cache/bin/varnishadm/varnishadm.c
--- 2.0.3/varnish-cache/bin/varnishadm/varnishadm.c	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/bin/varnishadm/varnishadm.c	2008-11-06 12:22:00.000000000 +0100
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: varnishadm.c 3072 2008-08-11 07:47:24Z phk $
+ * $Id: varnishadm.c 3336 2008-10-20 18:47:24Z des $
  */
 
 #include "config.h"
@@ -36,7 +36,6 @@
 #include <unistd.h>
 #include <string.h>
 
-#include "config.h"
 #include "libvarnish.h"
 #include "vss.h"
 
@@ -90,14 +89,16 @@
 		exit(1);
 	}
 	if (!(p = strchr(buf, ' '))) {
-		fprintf(stderr, "An error occured in parsing of status code.\n");
+		fprintf(stderr,
+		    "An error occured in parsing of status code.\n");
 		exit(1);
 	}
 	*p = '\0';
 	status = strtol(buf, &p, 10);
 	pp = p+1;
 	if (!(p = strchr(pp, '\n'))) {
-		fprintf(stderr, "An error occured in parsing of number of bytes returned.\n");
+		fprintf(stderr, "An error occured "
+		    "in parsing of number of bytes returned.\n");
 		exit(1);
 	}
 	*p = '\0';
diff -Nru 2.0.3/varnish-cache/bin/varnishd/cache_acceptor.c trunk/varnish-cache/bin/varnishd/cache_acceptor.c
--- 2.0.3/varnish-cache/bin/varnishd/cache_acceptor.c	2008-10-16 07:43:08.000000000 +0200
+++ trunk/varnish-cache/bin/varnishd/cache_acceptor.c	2008-11-10 09:23:00.000000000 +0100
@@ -26,11 +26,8 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: cache_acceptor.c 3261 2008-10-07 09:46:24Z tfheen $
+ * $Id: cache_acceptor.c 3363 2008-11-09 13:46:57Z phk $
  *
- * XXX: We need to pass sessions back into the event engine when they are
- * reused.  Not sure what the most efficient way is for that.  For now
- * write the session pointer to a pipe which the event engine monitors.
  */
 
 #include "config.h"
@@ -52,7 +49,7 @@
 #include "cache.h"
 #include "cache_acceptor.h"
 
-static struct acceptor *vca_acceptors[] = {
+static struct acceptor * const vca_acceptors[] = {
 #if defined(HAVE_KQUEUE)
 	&acceptor_kqueue,
 #endif
@@ -66,9 +63,9 @@
 	NULL,
 };
 
-static struct acceptor *vca_act;
+static struct acceptor const *vca_act;
 
-static pthread_t 	vca_thread_acct;
+static pthread_t	vca_thread_acct;
 static struct timeval	tv_sndtimeo;
 static struct timeval	tv_rcvtimeo;
 static struct linger	linger;
@@ -227,12 +224,15 @@
 					break;
 				case EMFILE:
 					VSL(SLT_Debug, ls->sock,
-					    "Too many open files when accept(2)ing. Sleeping.");
-					TIM_sleep(params->accept_fd_holdoff * 1000.0);
+					    "Too many open files "
+					    "when accept(2)ing. Sleeping.");
+					TIM_sleep(
+					    params->accept_fd_holdoff * 1000.0);
 					break;
 				default:
 					VSL(SLT_Debug, ls->sock,
-					    "Accept failed: %s", strerror(errno));
+					    "Accept failed: %s",
+					    strerror(errno));
 					/* XXX: stats ? */
 					break;
 				}
@@ -320,7 +320,7 @@
 	(void)cli;
 	(void)av;
 	(void)priv;
-	
+
 	if (vca_act == NULL)
 		vca_act = vca_acceptors[0];
 
@@ -356,7 +356,7 @@
 			cli_out(cli, "default");
 		else
 			cli_out(cli, "%s", vca_act->name);
-		
+
 		cli_out(cli, " (");
 		for (i = 0; vca_acceptors[i] != NULL; i++)
 			cli_out(cli, "%s%s", i == 0 ? "" : ", ",
diff -Nru 2.0.3/varnish-cache/bin/varnishd/cache_acceptor.h trunk/varnish-cache/bin/varnishd/cache_acceptor.h
--- 2.0.3/varnish-cache/bin/varnishd/cache_acceptor.h	2008-10-16 07:43:08.000000000 +0200
+++ trunk/varnish-cache/bin/varnishd/cache_acceptor.h	2008-10-20 10:58:16.000000000 +0200
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: cache_acceptor.h 3113 2008-08-19 21:34:16Z phk $
+ * $Id: cache_acceptor.h 3324 2008-10-18 20:50:10Z phk $
  */
 
 struct sess;
@@ -35,7 +35,7 @@
 typedef void acceptor_pass_f(struct sess *);
 
 struct acceptor {
-	const char 		*name;
+	const char		*name;
 	acceptor_init_f		*init;
 	acceptor_pass_f		*pass;
 };
diff -Nru 2.0.3/varnish-cache/bin/varnishd/cache_acceptor_kqueue.c trunk/varnish-cache/bin/varnishd/cache_acceptor_kqueue.c
--- 2.0.3/varnish-cache/bin/varnishd/cache_acceptor_kqueue.c	2009-01-09 15:40:15.000000000 +0100
+++ trunk/varnish-cache/bin/varnishd/cache_acceptor_kqueue.c	2009-01-05 14:45:27.000000000 +0100
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: cache_acceptor_kqueue.c 2976 2008-07-20 11:28:40Z phk $
+ * $Id: cache_acceptor_kqueue.c 3488 2008-12-21 18:33:30Z phk $
  *
  * XXX: We need to pass sessions back into the event engine when they are
  * reused.  Not sure what the most efficient way is for that.  For now
@@ -85,7 +85,7 @@
 	assert(sp->fd >= 0);
 	DSL(0x04, SLT_Debug, sp->fd, "KQ: EV_SET sp %p arm %x", sp, arm);
 	EV_SET(&ki[nki], sp->fd, EVFILT_READ, arm, 0, 0, sp);
-	if (++nki == NKEV) 
+	if (++nki == NKEV)
 		vca_kq_flush();
 }
 
diff -Nru 2.0.3/varnish-cache/bin/varnishd/cache_acceptor_poll.c trunk/varnish-cache/bin/varnishd/cache_acceptor_poll.c
--- 2.0.3/varnish-cache/bin/varnishd/cache_acceptor_poll.c	2008-10-16 07:43:08.000000000 +0200
+++ trunk/varnish-cache/bin/varnishd/cache_acceptor_poll.c	2008-11-10 09:23:00.000000000 +0100
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: cache_acceptor_poll.c 3113 2008-08-19 21:34:16Z phk $
+ * $Id: cache_acceptor_poll.c 3365 2008-11-09 14:26:24Z phk $
  *
  */
 
@@ -55,7 +55,7 @@
 vca_pollspace(unsigned fd)
 {
 	struct pollfd *newpollfd = pollfd;
-	unsigned newnpoll = npoll;
+	unsigned newnpoll;
 
 	if (fd < npoll)
 		return;
diff -Nru 2.0.3/varnish-cache/bin/varnishd/cache_acceptor_ports.c trunk/varnish-cache/bin/varnishd/cache_acceptor_ports.c
--- 2.0.3/varnish-cache/bin/varnishd/cache_acceptor_ports.c	2008-10-16 07:43:08.000000000 +0200
+++ trunk/varnish-cache/bin/varnishd/cache_acceptor_ports.c	2008-10-20 10:58:16.000000000 +0200
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: cache_acceptor_ports.c 3300 2008-10-15 09:52:15Z tfheen $
+ * $Id: cache_acceptor_ports.c 3324 2008-10-18 20:50:10Z phk $
  *
  * XXX: We need to pass sessions back into the event engine when they are
  * reused.  Not sure what the most efficient way is for that.  For now
@@ -61,7 +61,8 @@
 static void
 vca_add(int fd, void *data)
 {
-	AZ(port_associate(solaris_dport, PORT_SOURCE_FD, fd, POLLIN | POLLERR | POLLPRI, data));
+	AZ(port_associate(solaris_dport, PORT_SOURCE_FD, fd,
+	    POLLIN | POLLERR | POLLPRI, data));
 }
 
 static void
@@ -120,7 +121,8 @@
 		ts.tv_sec = 0L;
 		ts.tv_nsec = 50L /*ms*/  * 1000L /*us*/  * 1000L /*ns*/;
 		nevents = 1;
-		if (port_getn(solaris_dport, ev, MAX_EVENTS, &nevents, &ts) == 0) {
+		if (port_getn(solaris_dport, ev, MAX_EVENTS, &nevents, &ts)
+		     == 0) {
 			for (ei=0; ei<nevents; ei++) {
 				vca_port_ev(ev + ei);
 			}
diff -Nru 2.0.3/varnish-cache/bin/varnishd/cache_backend.c trunk/varnish-cache/bin/varnishd/cache_backend.c
--- 2.0.3/varnish-cache/bin/varnishd/cache_backend.c	2008-10-16 07:43:08.000000000 +0200
+++ trunk/varnish-cache/bin/varnishd/cache_backend.c	2009-01-05 14:45:27.000000000 +0100
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: cache_backend.c 3212 2008-09-22 09:35:03Z phk $
+ * $Id: cache_backend.c 3464 2008-12-18 10:04:15Z phk $
  *
  * Handle backend connections and backend request structures.
  *
@@ -82,7 +82,8 @@
  */
 
 static int
-VBE_TryConnect(const struct sess *sp, int pf, const struct sockaddr *sa, socklen_t salen, const struct backend *bp)
+VBE_TryConnect(const struct sess *sp, int pf, const struct sockaddr *sa,
+    socklen_t salen, const struct backend *bp)
 {
 	int s, i, tmo;
 	char abuf1[TCP_ADDRBUFSIZE], abuf2[TCP_ADDRBUFSIZE];
@@ -91,10 +92,10 @@
 	CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
 
 	s = socket(pf, SOCK_STREAM, 0);
-	if (s < 0) 
+	if (s < 0)
 		return (s);
 
-	tmo = params->connect_timeout;
+	tmo = (int)(sp->connect_timeout * 1000);
 	if (bp->connect_timeout > 10e-3)
 		tmo = (int)(bp->connect_timeout * 1000);
 
@@ -146,11 +147,11 @@
 	struct bereq *bereq;
 	volatile unsigned len;
 
-	LOCK(&VBE_mtx);
+	Lck_Lock(&VBE_mtx);
 	bereq = VTAILQ_FIRST(&bereq_head);
 	if (bereq != NULL)
 		VTAILQ_REMOVE(&bereq_head, bereq, list);
-	UNLOCK(&VBE_mtx);
+	Lck_Unlock(&VBE_mtx);
 	if (bereq != NULL) {
 		CHECK_OBJ(bereq, BEREQ_MAGIC);
 	} else {
@@ -171,14 +172,19 @@
  */
 
 void
-VBE_free_bereq(struct bereq *bereq)
+VBE_free_bereq(struct bereq **bereqp)
 {
+	struct bereq *bereq;
+
+	AN(bereqp);
+	bereq = *bereqp;
+	*bereqp = NULL;
 
 	CHECK_OBJ_NOTNULL(bereq, BEREQ_MAGIC);
 	WS_Reset(bereq->ws, NULL);
-	LOCK(&VBE_mtx);
+	Lck_Lock(&VBE_mtx);
 	VTAILQ_INSERT_HEAD(&bereq_head, bereq, list);
-	UNLOCK(&VBE_mtx);
+	Lck_Unlock(&VBE_mtx);
 }
 
 /*--------------------------------------------------------------------
@@ -194,13 +200,13 @@
 
 	vc = VTAILQ_FIRST(&vbe_conns);
 	if (vc != NULL) {
-		LOCK(&VBE_mtx);
+		Lck_Lock(&VBE_mtx);
 		vc = VTAILQ_FIRST(&vbe_conns);
 		if (vc != NULL) {
 			VSL_stats->backend_unused--;
 			VTAILQ_REMOVE(&vbe_conns, vc, list);
 		}
-		UNLOCK(&VBE_mtx);
+		Lck_Unlock(&VBE_mtx);
 	}
 	if (vc != NULL)
 		return (vc);
@@ -221,10 +227,10 @@
 	assert(vc->fd < 0);
 
 	if (params->cache_vbe_conns) {
-		LOCK(&VBE_mtx);
+		Lck_Lock(&VBE_mtx);
 		VTAILQ_INSERT_HEAD(&vbe_conns, vc, list);
 		VSL_stats->backend_unused++;
-		UNLOCK(&VBE_mtx);
+		Lck_Unlock(&VBE_mtx);
 	} else {
 		VSL_stats->n_vbe_conn--;
 		free(vc);
@@ -238,10 +244,10 @@
 {
 	int s;
 
-	LOCK(&bp->mtx);
+	Lck_Lock(&bp->mtx);
 	bp->refcount++;
 	bp->n_conn++;		/* It mostly works */
-	UNLOCK(&bp->mtx);
+	Lck_Unlock(&bp->mtx);
 
 	s = -1;
 	assert(bp->ipv6 != NULL || bp->ipv4 != NULL);
@@ -256,10 +262,10 @@
 		s = VBE_TryConnect(sp, PF_INET6, bp->ipv6, bp->ipv6len, bp);
 
 	if (s < 0) {
-		LOCK(&bp->mtx);
-		bp->n_conn--;		
+		Lck_Lock(&bp->mtx);
+		bp->n_conn--;
 		bp->refcount--;		/* Only keep ref on success */
-		UNLOCK(&bp->mtx);
+		Lck_Unlock(&bp->mtx);
 	}
 	return (s);
 }
@@ -294,7 +300,7 @@
 
 	/* first look for vbe_conn's we can recycle */
 	while (1) {
-		LOCK(&bp->mtx);
+		Lck_Lock(&bp->mtx);
 		vc = VTAILQ_FIRST(&bp->connlist);
 		if (vc != NULL) {
 			bp->refcount++;
@@ -302,7 +308,7 @@
 			assert(vc->fd >= 0);
 			VTAILQ_REMOVE(&bp->connlist, vc, list);
 		}
-		UNLOCK(&bp->mtx);
+		Lck_Unlock(&bp->mtx);
 		if (vc == NULL)
 			break;
 		if (VBE_CheckFd(vc->fd)) {
@@ -378,7 +384,7 @@
 	bp = sp->vbe->backend;
 
 	WSL(sp->wrk, SLT_BackendReuse, sp->vbe->fd, "%s", bp->vcl_name);
-	LOCK(&bp->mtx);
+	Lck_Lock(&bp->mtx);
 	VSL_stats->backend_recycle++;
 	VTAILQ_INSERT_HEAD(&bp->connlist, sp->vbe, list);
 	sp->vbe = NULL;
diff -Nru 2.0.3/varnish-cache/bin/varnishd/cache_backend_cfg.c trunk/varnish-cache/bin/varnishd/cache_backend_cfg.c
--- 2.0.3/varnish-cache/bin/varnishd/cache_backend_cfg.c	2008-10-16 07:43:08.000000000 +0200
+++ trunk/varnish-cache/bin/varnishd/cache_backend_cfg.c	2009-01-05 14:45:27.000000000 +0100
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: cache_backend_cfg.c 3135 2008-08-26 19:59:23Z phk $
+ * $Id: cache_backend_cfg.c 3406 2008-11-19 14:13:57Z petter $
  *
  * Handle configuration of backends from VCL programs.
  *
@@ -48,7 +48,7 @@
 #include "cache_backend.h"
 #include "cli_priv.h"
 
-MTX VBE_mtx;
+struct lock VBE_mtx;
 
 /*
  * The list of backends is not locked, it is only ever accessed from
@@ -105,7 +105,7 @@
 	assert(b->refcount > 0);
 
 	i = --b->refcount;
-	UNLOCK(&b->mtx);
+	Lck_Unlock(&b->mtx);
 	if (i > 0)
 		return;
 
@@ -128,7 +128,7 @@
 
 	CHECK_OBJ_NOTNULL(b, BACKEND_MAGIC);
 
-	LOCK(&b->mtx);
+	Lck_Lock(&b->mtx);
 	VBE_DropRefLocked(b);
 }
 
@@ -138,7 +138,7 @@
 
 	CHECK_OBJ_NOTNULL(b, BACKEND_MAGIC);
 
-	LOCK(&b->mtx);
+	Lck_Lock(&b->mtx);
 	assert(b->n_conn > 0);
 	b->n_conn--;
 	VBE_DropRefLocked(b);
@@ -207,7 +207,7 @@
 	/* Create new backend */
 	ALLOC_OBJ(b, BACKEND_MAGIC);
 	XXXAN(b);
-	MTX_INIT(&b->mtx);
+	Lck_New(&b->mtx);
 	b->refcount = 1;
 
 	VTAILQ_INIT(&b->connlist);
@@ -222,14 +222,16 @@
 	REPLACE(b->hosthdr, vb->hosthdr);
 
 	b->connect_timeout = vb->connect_timeout;
+	b->first_byte_timeout = vb->first_byte_timeout;
+	b->between_bytes_timeout = vb->between_bytes_timeout;
 	b->max_conn = vb->max_connections;
 
 	/*
 	 * Copy over the sockaddrs
 	 */
-	if (vb->ipv4_sockaddr != NULL) 
+	if (vb->ipv4_sockaddr != NULL)
 		copy_sockaddr(&b->ipv4, &b->ipv4len, vb->ipv4_sockaddr);
-	if (vb->ipv6_sockaddr != NULL) 
+	if (vb->ipv6_sockaddr != NULL)
 		copy_sockaddr(&b->ipv6, &b->ipv6len, vb->ipv6_sockaddr);
 
 	assert(b->ipv4 != NULL || b->ipv6 != NULL);
@@ -283,6 +285,6 @@
 VBE_Init(void)
 {
 
-	MTX_INIT(&VBE_mtx);
+	Lck_New(&VBE_mtx);
 	CLI_AddFuncs(DEBUG_CLI, debug_cmds);
 }
diff -Nru 2.0.3/varnish-cache/bin/varnishd/cache_backend.h trunk/varnish-cache/bin/varnishd/cache_backend.h
--- 2.0.3/varnish-cache/bin/varnishd/cache_backend.h	2008-10-16 07:43:08.000000000 +0200
+++ trunk/varnish-cache/bin/varnishd/cache_backend.h	2009-01-05 14:45:27.000000000 +0100
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: cache_backend.h 3197 2008-09-17 10:04:47Z tfheen $
+ * $Id: cache_backend.h 3406 2008-11-19 14:13:57Z petter $
  *
  * This is the central switch-board for backend connections and it is
  * slightly complicated by a number of optimizations.
@@ -104,12 +104,14 @@
 	char			*ident;
 	char			*vcl_name;
 	double			connect_timeout;
+	double			first_byte_timeout;
+	double			between_bytes_timeout;
 
 	uint32_t		hash;
 
 	VTAILQ_ENTRY(backend)	list;
 	int			refcount;
-	pthread_mutex_t		mtx;
+	struct lock		mtx;
 
 	struct sockaddr		*ipv4;
 	socklen_t		ipv4len;
@@ -129,7 +131,7 @@
 struct vbe_conn *VBE_GetVbe(struct sess *sp, struct backend *bp);
 
 /* cache_backend_cfg.c */
-extern MTX VBE_mtx;
+extern struct lock VBE_mtx;
 void VBE_DropRefConn(struct backend *);
 void VBE_DropRef(struct backend *);
 void VBE_DropRefLocked(struct backend *b);
diff -Nru 2.0.3/varnish-cache/bin/varnishd/cache_backend_poll.c trunk/varnish-cache/bin/varnishd/cache_backend_poll.c
--- 2.0.3/varnish-cache/bin/varnishd/cache_backend_poll.c	2009-01-09 15:46:11.000000000 +0100
+++ trunk/varnish-cache/bin/varnishd/cache_backend_poll.c	2009-01-05 14:45:27.000000000 +0100
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: cache_backend_poll.c 3300 2008-10-15 09:52:15Z tfheen $
+ * $Id: cache_backend_poll.c 3492 2008-12-21 18:35:24Z phk $
  *
  * Poll backends for collection of health statistics
  *
@@ -62,14 +62,14 @@
 #define VBP_TARGET_MAGIC		0x6b7cb656
 
 	struct backend			*backend;
-	struct vrt_backend_probe 	probe;
+	struct vrt_backend_probe	probe;
 	int				stop;
 	char				*req;
 	int				req_len;
 
 	char				resp_buf[128];
 	unsigned			good;
-	
+
 	/* Collected statistics */
 #define BITMAP(n, c, t, b)	uint64_t	n;
 #include "cache_backend_poll.h"
@@ -86,7 +86,7 @@
 static VTAILQ_HEAD(, vbp_target)	vbp_list =
     VTAILQ_HEAD_INITIALIZER(vbp_list);
 
-static char default_request[] = 
+static const char default_request[] =
     "GET / HTTP/1.1\r\n"
     "Connection: close\r\n"
     "\r\n";
@@ -324,7 +324,7 @@
 		    vt->backend->vcl_name, logmsg, bits,
 		    vt->good, vt->probe.threshold, vt->probe.window,
 		    vt->last, vt->avg, vt->resp_buf);
-			
+
 		if (!vt->stop)
 			TIM_sleep(vt->probe.interval);
 	}
@@ -363,15 +363,15 @@
 	cli_out(cli, "Current states  good: %2u threshold: %2u window: %2u\n",
 	    vt->good, vt->probe.threshold, vt->probe.window);
 	cli_out(cli, "Average responsetime of good probes: %.6f\n", vt->avg);
-	cli_out(cli, 
+	cli_out(cli,
 	    "Oldest                       "
 	    "                             Newest\n");
-	cli_out(cli, 
+	cli_out(cli,
 	    "============================="
 	    "===================================\n");
 
 #define BITMAP(n, c, t, b)					\
-		if ((vt->n != 0) || (b)) 				\
+		if ((vt->n != 0) || (b))			\
 			vbp_bitmap(cli, (c), vt->n, (t));
 #include "cache_backend_poll.h"
 #undef BITMAP
@@ -391,10 +391,10 @@
 }
 
 static struct cli_proto debug_cmds[] = {
-        { "debug.health", "debug.health",
-                "\tDump backend health stuff\n",
-                0, 0, vbp_health },
-        { NULL }
+	{ "debug.health", "debug.health",
+		"\tDump backend health stuff\n",
+		0, 0, vbp_health },
+	{ NULL }
 };
 
 /*--------------------------------------------------------------------
diff -Nru 2.0.3/varnish-cache/bin/varnishd/cache_backend_poll.h trunk/varnish-cache/bin/varnishd/cache_backend_poll.h
--- 2.0.3/varnish-cache/bin/varnishd/cache_backend_poll.h	2008-10-16 07:43:08.000000000 +0200
+++ trunk/varnish-cache/bin/varnishd/cache_backend_poll.h	2009-01-05 14:45:27.000000000 +0100
@@ -25,12 +25,12 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: cache_backend_poll.h 3300 2008-10-15 09:52:15Z tfheen $
+ * $Id: cache_backend_poll.h 3418 2008-11-22 01:35:16Z tfheen $
  *
  */
 
 BITMAP(good_ipv4, '4', "Good IPv4", 0)
-BITMAP(good_ipv6, '6', "Good IPv4", 0)
+BITMAP(good_ipv6, '6', "Good IPv6", 0)
 BITMAP( err_xmit, 'x', "Error Xmit", 0)
 BITMAP(good_xmit, 'X', "Good Xmit", 0)
 BITMAP( err_shut, 's', "Error Shut", 0)
diff -Nru 2.0.3/varnish-cache/bin/varnishd/cache_ban.c trunk/varnish-cache/bin/varnishd/cache_ban.c
--- 2.0.3/varnish-cache/bin/varnishd/cache_ban.c	2008-11-10 11:09:32.000000000 +0100
+++ trunk/varnish-cache/bin/varnishd/cache_ban.c	2008-11-11 14:27:27.000000000 +0100
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: cache_ban.c 3370 2008-11-10 10:09:31Z tfheen $
+ * $Id: cache_ban.c 3381 2008-11-10 19:46:25Z phk $
  *
  * Ban ("purge") processing
  */
@@ -57,7 +57,7 @@
 };
 
 static VTAILQ_HEAD(banhead,ban) ban_head = VTAILQ_HEAD_INITIALIZER(ban_head);
-static MTX ban_mtx;
+static struct lock ban_mtx;
 
 /*
  * We maintain ban_start as a pointer to the first element of the list
@@ -95,7 +95,7 @@
 	b->hash = hash;
 	b->ban = strdup(regexp);
 	AN(b->ban);
-	LOCK(&ban_mtx);
+	Lck_Lock(&ban_mtx);
 	VTAILQ_INSERT_HEAD(&ban_head, b, list);
 	ban_start = b;
 	VSL_stats->n_purge++;
@@ -106,7 +106,7 @@
 		be->refcount++;
 	} else
 		be = NULL;
-	UNLOCK(&ban_mtx);
+	Lck_Unlock(&ban_mtx);
 
 	if (be == NULL)
 		return (0);
@@ -125,11 +125,11 @@
 		bi->flags |= BAN_F_GONE;
 		pcount++;
 	}
-	LOCK(&ban_mtx);
+	Lck_Lock(&ban_mtx);
 	be->refcount--;
 	/* XXX: We should check if the tail can be removed */
 	VSL_stats->n_purge_dups += pcount;
-	UNLOCK(&ban_mtx);
+	Lck_Unlock(&ban_mtx);
 
 	return (0);
 }
@@ -140,10 +140,10 @@
 
 	CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
 	AZ(o->ban);
-	LOCK(&ban_mtx);
+	Lck_Lock(&ban_mtx);
 	o->ban = ban_start;
 	ban_start->refcount++;
-	UNLOCK(&ban_mtx);
+	Lck_Unlock(&ban_mtx);
 }
 
 void
@@ -155,7 +155,7 @@
 	if (o->ban == NULL)
 		return;
 	CHECK_OBJ_NOTNULL(o->ban, BAN_MAGIC);
-	LOCK(&ban_mtx);
+	Lck_Lock(&ban_mtx);
 	o->ban->refcount--;
 	o->ban = NULL;
 
@@ -168,7 +168,7 @@
 	} else {
 		b = NULL;
 	}
-	UNLOCK(&ban_mtx);
+	Lck_Unlock(&ban_mtx);
 	if (b != NULL) {
 		free(b->ban);
 		regfree(&b->regexp);
@@ -205,13 +205,13 @@
 			break;
 	}
 
-	LOCK(&ban_mtx);
+	Lck_Lock(&ban_mtx);
 	o->ban->refcount--;
 	if (b == o->ban)	/* not banned */
 		b0->refcount++;
 	VSL_stats->n_purge_obj_test++;
 	VSL_stats->n_purge_re_test += tests;
-	UNLOCK(&ban_mtx);
+	Lck_Unlock(&ban_mtx);
 
 	if (b == o->ban) {	/* not banned */
 		o->ban = b0;
@@ -250,10 +250,10 @@
 	(void)av;
 	(void)priv;
 	/*
- 	 * XXX: Strictly speaking, this loop traversal is not lock-safe
+	 * XXX: Strictly speaking, this loop traversal is not lock-safe
 	 * XXX: because we might inspect the last ban while it gets
 	 * XXX: destroyed.  To properly fix this, we would need to either
- 	 * XXX: hold the lock over the entire loop, or grab refcounts
+	 * XXX: hold the lock over the entire loop, or grab refcounts
 	 * XXX: under lock for each element of the list.
 	 * XXX: We do neither, and hope for the best.
 	 */
@@ -285,7 +285,7 @@
 BAN_Init(void)
 {
 
-	MTX_INIT(&ban_mtx);
+	Lck_New(&ban_mtx);
 	CLI_AddFuncs(PUBLIC_CLI, ban_cmds);
 	/* Add an initial ban, since the list can never be empty */
 	(void)BAN_Add(NULL, ".", 0);
diff -Nru 2.0.3/varnish-cache/bin/varnishd/cache_center.c trunk/varnish-cache/bin/varnishd/cache_center.c
--- 2.0.3/varnish-cache/bin/varnishd/cache_center.c	2009-01-09 15:36:53.000000000 +0100
+++ trunk/varnish-cache/bin/varnishd/cache_center.c	2009-01-05 14:45:27.000000000 +0100
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: cache_center.c 3316 2008-10-17 11:04:12Z tfheen $
+ * $Id: cache_center.c 3497 2008-12-21 18:42:48Z phk $
  *
  * This file contains the central state machine for pushing requests.
  *
@@ -67,7 +67,6 @@
 #include <string.h>
 #include <unistd.h>
 
-#include "config.h"
 #ifndef HAVE_SRANDOMDEV
 #include "compat/srandomdev.h"
 #endif
@@ -76,6 +75,7 @@
 #include "vcl.h"
 #include "cli_priv.h"
 #include "cache.h"
+#include "hash_slinger.h"
 
 static unsigned xids;
 
@@ -109,7 +109,6 @@
 	return (0);
 }
 
-
 /*--------------------------------------------------------------------
  * We have a refcounted object on the session, now deliver it.
  *
@@ -175,15 +174,14 @@
 
 	sp->director = NULL;
 	sp->restarts = 0;
-					
+
 	RES_WriteObj(sp);
-	HSH_Deref(sp->obj);
-	sp->obj = NULL;
+	AZ(sp->wrk->wfd);
+	HSH_Deref(&sp->obj);
 	sp->step = STP_DONE;
 	return (0);
 }
 
-
 /*--------------------------------------------------------------------
  * This is the final state, figure out if we should close or recycle
  * the client connection
@@ -209,7 +207,7 @@
 	AZ(sp->bereq);
 	sp->director = NULL;
 	sp->restarts = 0;
-					
+
 	if (sp->vcl != NULL && sp->esis == 0) {
 		if (sp->wrk->vcl != NULL)
 			VCL_Rel(&sp->wrk->vcl);
@@ -282,7 +280,6 @@
 	return (1);
 }
 
-
 /*--------------------------------------------------------------------
  * Emit an error
  *
@@ -301,7 +298,6 @@
 {
 	struct worker *w;
 	struct http *h;
-	time_t now;
 	char date[40];
 
 	CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
@@ -325,11 +321,10 @@
 
 	http_PutProtocol(w, sp->fd, h, "HTTP/1.1");
 	http_PutStatus(w, sp->fd, h, sp->err_code);
-	now = TIM_real();
-	TIM_format(now, date);
-        http_PrintfHeader(w, sp->fd, h, "Date: %s", date);
-        http_PrintfHeader(w, sp->fd, h, "Server: Varnish");
-        http_PrintfHeader(w, sp->fd, h, "Retry-After: %d", params->err_ttl);
+	TIM_format(TIM_real(), date);
+	http_PrintfHeader(w, sp->fd, h, "Date: %s", date);
+	http_PrintfHeader(w, sp->fd, h, "Server: Varnish");
+	http_PrintfHeader(w, sp->fd, h, "Retry-After: %d", params->err_ttl);
 
 	if (sp->err_reason != NULL)
 		http_PutResponse(w, sp->fd, h, sp->err_reason);
@@ -344,7 +339,6 @@
 	return (0);
 }
 
-
 /*--------------------------------------------------------------------
  * We have fetched the headers from the backend, ask the VCL code what
  * to do next, then head off in that direction.
@@ -370,7 +364,7 @@
 DOT vcl_fetch -> recv [label="restart"]
 DOT vcl_fetch -> rstfetch [label="restart",color=purple]
 DOT rstfetch [label="RESTART",shape=plaintext]
-DOT fetch -> errfetch 
+DOT fetch -> errfetch
 DOT vcl_fetch -> errfetch [label="error"]
 DOT errfetch [label="ERROR",shape=plaintext]
  */
@@ -387,19 +381,16 @@
 	AN(sp->director);
 	AZ(sp->vbe);
 	i = Fetch(sp);
+	AZ(sp->wrk->wfd);
 	AZ(sp->vbe);
 	AN(sp->director);
 
 	if (i) {
 		sp->err_code = 503;
 		sp->step = STP_ERROR;
-		VBE_free_bereq(sp->bereq);
-		sp->bereq = NULL;
-		sp->obj->ttl = 0;
-		sp->obj->cacheable = 0;
-		HSH_Unbusy(sp);
-		HSH_Deref(sp->obj);
-		sp->obj = NULL;
+		VBE_free_bereq(&sp->bereq);
+		HSH_Drop(sp);
+		AZ(sp->obj);
 		return (0);
 	}
 
@@ -408,16 +399,11 @@
 	sp->err_code = http_GetStatus(sp->obj->http);
 	VCL_fetch_method(sp);
 
-	VBE_free_bereq(sp->bereq);
-	sp->bereq = NULL;
+	VBE_free_bereq(&sp->bereq);
 
 	switch (sp->handling) {
 	case VCL_RET_RESTART:
-		sp->obj->ttl = 0;
-		sp->obj->cacheable = 0;
-		HSH_Unbusy(sp);
-		HSH_Deref(sp->obj);
-		sp->obj = NULL;
+		HSH_Drop(sp);
 		sp->director = NULL;
 		sp->restarts++;
 		sp->step = STP_RECV;
@@ -429,11 +415,7 @@
 		break;
 	case VCL_RET_ERROR:
 		sp->step = STP_ERROR;
-		sp->obj->ttl = 0;
-		sp->obj->cacheable = 0;
-		HSH_Unbusy(sp);
-		HSH_Deref(sp->obj);
-		sp->obj = NULL;
+		HSH_Drop(sp);
 		return (0);
 	default:
 		WRONG("Illegal action in vcl_fetch{}");
@@ -537,8 +519,7 @@
 	}
 
 	/* Drop our object, we won't need it */
-	HSH_Deref(sp->obj);
-	sp->obj = NULL;
+	HSH_Deref(&sp->obj);
 
 	switch(sp->handling) {
 	case VCL_RET_PASS:
@@ -554,11 +535,9 @@
 		return (0);
 	default:
 		WRONG("Illegal action in vcl_hit{}");
-		return (0);
 	}
 }
 
-
 /*--------------------------------------------------------------------
  * LOOKUP
  * Hash things together and look object up in hash-table.
@@ -591,28 +570,12 @@
 cnt_lookup(struct sess *sp)
 {
 	struct object *o;
-	char *p;
-	uintptr_t u;
 
 	CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
 	CHECK_OBJ_NOTNULL(sp->vcl, VCL_CONF_MAGIC);
 
 	if (sp->obj == NULL) {
-
-		/* Allocate the pointers we need, align properly. */
-		sp->lhashptr = 1;	/* space for NUL */
-		sp->ihashptr = 0;
-		sp->nhashptr = sp->vcl->nhashcount * 2;
-		p = WS_Alloc(sp->http->ws,
-		    sizeof(const char *) * (sp->nhashptr + 1));
-		XXXAN(p);
-		/* Align pointer properly (?) */
-		u = (uintptr_t)p;
-		u &= sizeof(const char *) - 1;
-		if (u)
-			p += sizeof(const char *) - u;
-		sp->hashptr = (void*)p;
-
+		HSH_Prepare(sp, sp->vcl->nhashcount);
 		VCL_hash_method(sp);
 		assert(sp->handling == VCL_RET_HASH);
 	}
@@ -644,8 +607,7 @@
 	if (sp->obj->pass) {
 		VSL_stats->cache_hitpass++;
 		WSP(sp, SLT_HitPass, "%u", sp->obj->xid);
-		HSH_Deref(sp->obj);
-		sp->obj = NULL;
+		HSH_Deref(&sp->obj);
 		sp->step = STP_PASS;
 		return (0);
 	}
@@ -656,7 +618,6 @@
 	return (0);
 }
 
-
 /*--------------------------------------------------------------------
  * We had a miss, ask VCL, proceed as instructed
  *
@@ -690,38 +651,28 @@
 
 	http_FilterHeader(sp, HTTPH_R_FETCH);
 	VCL_miss_method(sp);
+	AZ(sp->obj->cacheable);
 	switch(sp->handling) {
 	case VCL_RET_ERROR:
-		sp->obj->cacheable = 0;
-		HSH_Unbusy(sp);
-		HSH_Deref(sp->obj);
-		sp->obj = NULL;
-		VBE_free_bereq(sp->bereq);
-		sp->bereq = NULL;
+		HSH_Drop(sp);
+		VBE_free_bereq(&sp->bereq);
 		sp->step = STP_ERROR;
 		return (0);
 	case VCL_RET_PASS:
-		sp->obj->cacheable = 0;
-		HSH_Unbusy(sp);
-		HSH_Deref(sp->obj);
-		sp->obj = NULL;
+		HSH_Drop(sp);
+		VBE_free_bereq(&sp->bereq);
 		sp->step = STP_PASS;
-		VBE_free_bereq(sp->bereq);
-		sp->bereq = NULL;
 		return (0);
 	case VCL_RET_FETCH:
 		sp->step = STP_FETCH;
 		return (0);
 	case VCL_RET_RESTART:
 		INCOMPL();
-		return (0);
 	default:
 		WRONG("Illegal action in vcl_miss{}");
-		return (0);
 	}
 }
 
-
 /*--------------------------------------------------------------------
  * Start pass processing by getting headers from backend, then
  * continue in passbody.
@@ -822,11 +773,11 @@
 	assert(sp->handling == VCL_RET_PIPE);
 
 	PipeSession(sp);
+	AZ(sp->wrk->wfd);
 	sp->step = STP_DONE;
 	return (0);
 }
 
-
 /*--------------------------------------------------------------------
  * RECV
  * We have a complete request, set everything up and start it.
@@ -853,6 +804,8 @@
 	CHECK_OBJ_NOTNULL(sp->vcl, VCL_CONF_MAGIC);
 	AZ(sp->obj);
 
+	SES_ResetBackendTimeouts(sp);
+
 	/* By default we use the first backend */
 	AZ(sp->director);
 	sp->director = sp->vcl->director[0];
@@ -891,7 +844,6 @@
 		return (0);
 	default:
 		WRONG("Illegal action in vcl_recv{}");
-		return (0);
 	}
 }
 
@@ -1008,14 +960,14 @@
 	    sp->step == STP_START ||
 	    sp->step == STP_LOOKUP ||
 	    sp->step == STP_RECV);
-	  
+
 	/*
 	 * Whenever we come in from the acceptor we need to set blocking
 	 * mode, but there is no point in setting it when we come from
 	 * ESI or when a parked sessions returns.
 	 * It would be simpler to do this in the acceptor, but we'd rather
 	 * do the syscall in the worker thread.
- 	 */
+	 */
 	if (sp->step == STP_FIRST || sp->step == STP_START)
 		TCP_blocking(sp->fd);
 
@@ -1047,6 +999,7 @@
 		CHECK_OBJ_ORNULL(w->nobjhead, OBJHEAD_MAGIC);
 	}
 	WSL_Flush(w, 0);
+	AZ(w->wfd);
 }
 
 /*
@@ -1060,17 +1013,21 @@
 static void
 cli_debug_xid(struct cli *cli, const char * const *av, void *priv)
 {
-        (void)priv;
-	if (av[2] != NULL) 
+	(void)priv;
+	if (av[2] != NULL)
 		xids = strtoul(av[2], NULL, 0);
 	cli_out(cli, "XID is %u", xids);
 }
 
+/*
+ * Default to seed=1, this is the only seed value POSIXl guarantees will
+ * result in a reproducible random number sequence.
+ */
 static void
 cli_debug_srandom(struct cli *cli, const char * const *av, void *priv)
 {
 	(void)priv;
-	unsigned long seed;
+	unsigned seed = 1;
 
 	if (av[2] != NULL)
 		seed = strtoul(av[2], NULL, 0);
diff -Nru 2.0.3/varnish-cache/bin/varnishd/cache_cli.c trunk/varnish-cache/bin/varnishd/cache_cli.c
--- 2.0.3/varnish-cache/bin/varnishd/cache_cli.c	2008-10-16 07:43:08.000000000 +0200
+++ trunk/varnish-cache/bin/varnishd/cache_cli.c	2009-01-05 14:45:27.000000000 +0100
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: cache_cli.c 3155 2008-09-02 17:54:33Z sky $
+ * $Id: cache_cli.c 3405 2008-11-19 11:58:48Z phk $
  *
  * Caching process CLI handling.
  *
@@ -52,9 +52,10 @@
 #include "cache.h"
 #include "vlu.h"
 #include "vsb.h"
+#include "hash_slinger.h"
 
-pthread_t	cli_thread;
-static MTX	cli_mtx;
+pthread_t		cli_thread;
+static struct lock	cli_mtx;
 
 /*
  * The CLI commandlist is split in three:
@@ -81,16 +82,16 @@
 	case DEBUG_CLI:	 cp = &ccf_debug_cli;  break;
 	default: INCOMPL();
 	}
-	LOCK(&cli_mtx);
+	Lck_Lock(&cli_mtx);
 	c = cli_concat(*cp, p);
 	AN(c);
 	free(*cp);
 	*cp = c;
-	UNLOCK(&cli_mtx);
+	Lck_Unlock(&cli_mtx);
 }
 
 /*--------------------------------------------------------------------
- * Called when we have a full line, look through all three command 
+ * Called when we have a full line, look through all three command
  * lists to find it.
  */
 
@@ -105,7 +106,7 @@
 	VCL_Poll();
 	VBE_Poll();
 	vsb_clear(cli->sb);
-	LOCK(&cli_mtx);
+	Lck_Lock(&cli_mtx);
 	cli_dispatch(cli, ccf_master_cli, p);
 	if (cli->result == CLIS_UNKNOWN) {
 		vsb_clear(cli->sb);
@@ -117,7 +118,7 @@
 		cli->result = CLIS_OK;
 		cli_dispatch(cli, ccf_debug_cli, p);
 	}
-	UNLOCK(&cli_mtx);
+	Lck_Unlock(&cli_mtx);
 	vsb_finish(cli->sb);
 	AZ(vsb_overflowed(cli->sb));
 	i = cli_writeres(heritage.cli_out, cli);
@@ -182,19 +183,19 @@
 
 #define SZOF(foo)       cli_out(cli, \
     "sizeof(%s) = %zd = 0x%zx\n", #foo, sizeof(foo), sizeof(foo));
-        SZOF(struct ws);
-        SZOF(struct http);
-        SZOF(struct http_conn);
-        SZOF(struct acct);
-        SZOF(struct worker);
-        SZOF(struct workreq);
-        SZOF(struct bereq);
-        SZOF(struct storage);
-        SZOF(struct object);
-        SZOF(struct objhead);
-        SZOF(struct sess);
-        SZOF(struct vbe_conn);
-        SZOF(struct varnish_stats);
+	SZOF(struct ws);
+	SZOF(struct http);
+	SZOF(struct http_conn);
+	SZOF(struct acct);
+	SZOF(struct worker);
+	SZOF(struct workreq);
+	SZOF(struct bereq);
+	SZOF(struct storage);
+	SZOF(struct object);
+	SZOF(struct objhead);
+	SZOF(struct sess);
+	SZOF(struct vbe_conn);
+	SZOF(struct varnish_stats);
 }
 
 /*--------------------------------------------------------------------*/
@@ -242,7 +243,7 @@
 CLI_Init(void)
 {
 
-	MTX_INIT(&cli_mtx);
+	Lck_New(&cli_mtx);
 	cli_thread = pthread_self();
 
 	CLI_AddFuncs(MASTER_CLI, master_cmds);
diff -Nru 2.0.3/varnish-cache/bin/varnishd/cache_dir_random.c trunk/varnish-cache/bin/varnishd/cache_dir_random.c
--- 2.0.3/varnish-cache/bin/varnishd/cache_dir_random.c	2008-11-10 11:07:30.000000000 +0100
+++ trunk/varnish-cache/bin/varnishd/cache_dir_random.c	2009-01-05 14:45:27.000000000 +0100
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: cache_dir_random.c 3369 2008-11-10 10:07:29Z tfheen $
+ * $Id: cache_dir_random.c 3489 2008-12-21 18:33:44Z phk $
  *
  */
 
@@ -75,7 +75,6 @@
 	CHECK_OBJ_NOTNULL(sp->director, DIRECTOR_MAGIC);
 	CAST_OBJ_NOTNULL(vs, sp->director->priv, VDI_RANDOM_MAGIC);
 
-	k = 0;
 	for (k = 0; k < vs->retries; ) {
 
 		/* Sum up the weights of healty backends */
@@ -136,7 +135,7 @@
 
 	CHECK_OBJ_NOTNULL(d, DIRECTOR_MAGIC);
 	CAST_OBJ_NOTNULL(vs, d->priv, VDI_RANDOM_MAGIC);
-	
+
 	vh = vs->hosts;
 	for (i = 0; i < vs->nhosts; i++, vh++)
 		VBE_DropRef(vh->backend);
@@ -147,13 +146,14 @@
 }
 
 void
-VRT_init_dir_random(struct cli *cli, struct director **bp, const struct vrt_dir_random *t)
+VRT_init_dir_random(struct cli *cli, struct director **bp,
+    const struct vrt_dir_random *t)
 {
 	struct vdi_random *vs;
 	const struct vrt_dir_random_entry *te;
 	struct vdi_random_host *vh;
 	int i;
-	
+
 	(void)cli;
 
 	ALLOC_OBJ(vs, VDI_RANDOM_MAGIC);
diff -Nru 2.0.3/varnish-cache/bin/varnishd/cache_dir_round_robin.c trunk/varnish-cache/bin/varnishd/cache_dir_round_robin.c
--- 2.0.3/varnish-cache/bin/varnishd/cache_dir_round_robin.c	2008-10-16 07:43:08.000000000 +0200
+++ trunk/varnish-cache/bin/varnishd/cache_dir_round_robin.c	2008-10-20 10:58:16.000000000 +0200
@@ -25,7 +25,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: cache_dir_round_robin.c 3197 2008-09-17 10:04:47Z tfheen $
+ * $Id: cache_dir_round_robin.c 3324 2008-10-18 20:50:10Z phk $
  *
  */
 
@@ -111,7 +111,7 @@
 
 	CHECK_OBJ_NOTNULL(d, DIRECTOR_MAGIC);
 	CAST_OBJ_NOTNULL(vs, d->priv, VDI_ROUND_ROBIN_MAGIC);
-	
+
 	vh = vs->hosts;
 	for (i = 0; i < vs->nhosts; i++, vh++)
 		VBE_DropRef(vh->backend);
@@ -123,13 +123,14 @@
 }
 
 void
-VRT_init_dir_round_robin(struct cli *cli, struct director **bp, const struct vrt_dir_round_robin *t)
+VRT_init_dir_round_robin(struct cli *cli, struct director **bp,
+    const struct vrt_dir_round_robin *t)
 {
 	struct vdi_round_robin *vs;
 	const struct vrt_dir_round_robin_entry *te;
 	struct vdi_round_robin_host *vh;
 	int i;
-	
+
 	(void)cli;
 
 	ALLOC_OBJ(vs, VDI_ROUND_ROBIN_MAGIC);
diff -Nru 2.0.3/varnish-cache/bin/varnishd/cache_dir_simple.c trunk/varnish-cache/bin/varnishd/cache_dir_simple.c
--- 2.0.3/varnish-cache/bin/varnishd/cache_dir_simple.c	2008-10-16 07:43:08.000000000 +0200
+++ trunk/varnish-cache/bin/varnishd/cache_dir_simple.c	2008-10-20 10:58:16.000000000 +0200
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: cache_dir_simple.c 3197 2008-09-17 10:04:47Z tfheen $
+ * $Id: cache_dir_simple.c 3324 2008-10-18 20:50:10Z phk $
  *
  */
 
@@ -85,7 +85,7 @@
 
 	CHECK_OBJ_NOTNULL(d, DIRECTOR_MAGIC);
 	CAST_OBJ_NOTNULL(vs, d->priv, VDI_SIMPLE_MAGIC);
-	
+
 	VBE_DropRef(vs->backend);
 	free(vs->dir.vcl_name);
 	vs->dir.magic = 0;
@@ -93,10 +93,11 @@
 }
 
 void
-VRT_init_dir_simple(struct cli *cli, struct director **bp, const struct vrt_dir_simple *t)
+VRT_init_dir_simple(struct cli *cli, struct director **bp,
+    const struct vrt_dir_simple *t)
 {
 	struct vdi_simple *vs;
-	
+
 	(void)cli;
 
 	ALLOC_OBJ(vs, VDI_SIMPLE_MAGIC);
diff -Nru 2.0.3/varnish-cache/bin/varnishd/cache_expire.c trunk/varnish-cache/bin/varnishd/cache_expire.c
--- 2.0.3/varnish-cache/bin/varnishd/cache_expire.c	2008-10-16 07:43:08.000000000 +0200
+++ trunk/varnish-cache/bin/varnishd/cache_expire.c	2009-01-05 14:45:27.000000000 +0100
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: cache_expire.c 3179 2008-09-12 07:25:51Z phk $
+ * $Id: cache_expire.c 3483 2008-12-21 16:19:14Z phk $
  *
  * LRU and object timer handling.
  *
@@ -60,17 +60,19 @@
 #include "shmlog.h"
 #include "binary_heap.h"
 #include "cache.h"
+#include "vcl.h"
+#include "hash_slinger.h"
 
 /*
  * Objects have sideways references in the binary heap and the LRU list
  * and we want to avoid paging in a lot of objects just to move them up
  * or down the binheap or to move a unrelated object on the LRU list.
- * To avoid this we use a proxy object, objexp, to hold the relevant 
+ * To avoid this we use a proxy object, objexp, to hold the relevant
  * housekeeping fields parts of an object.
  */
 
-static const char *tmr_prefetch	= "prefetch";
-static const char *tmr_ttl	= "ttl";
+static const char * const tmr_prefetch	= "prefetch";
+static const char * const tmr_ttl	= "ttl";
 
 struct objexp {
 	unsigned		magic;
@@ -86,7 +88,7 @@
 
 static pthread_t exp_thread;
 static struct binheap *exp_heap;
-static MTX exp_mtx;
+static struct lock exp_mtx;
 static VTAILQ_HEAD(,objexp) lru = VTAILQ_HEAD_INITIALIZER(lru);
 
 /*
@@ -176,12 +178,12 @@
 	assert(o->entered != 0 && !isnan(o->entered));
 	oe->lru_stamp = o->entered;
 	update_object_when(o);
-	LOCK(&exp_mtx);
+	Lck_Lock(&exp_mtx);
 	binheap_insert(exp_heap, oe);
 	assert(oe->timer_idx != BINHEAP_NOIDX);
 	VTAILQ_INSERT_TAIL(&lru, oe, list);
 	oe->on_lru = 1;
-	UNLOCK(&exp_mtx);
+	Lck_Unlock(&exp_mtx);
 }
 
 /*--------------------------------------------------------------------
@@ -196,7 +198,6 @@
 void
 EXP_Touch(const struct object *o, double now)
 {
-	int i;
 	struct objexp *oe;
 
 	CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
@@ -206,8 +207,7 @@
 	CHECK_OBJ_NOTNULL(oe, OBJEXP_MAGIC);
 	if (oe->lru_stamp + params->lru_timeout > now)
 		return;
-	TRYLOCK(&exp_mtx, i);
-	if (i)
+	if (Lck_Trylock(&exp_mtx))
 		return;
 	if (oe->on_lru) {
 		VTAILQ_REMOVE(&lru, oe, list);
@@ -215,11 +215,11 @@
 		oe->lru_stamp = now;
 		VSL_stats->n_lru_moved++;
 	}
-	UNLOCK(&exp_mtx);
+	Lck_Unlock(&exp_mtx);
 }
 
 /*--------------------------------------------------------------------
- * We have changed one or more of the object timers, shuffle it 
+ * We have changed one or more of the object timers, shuffle it
  * accordingly in the binheap
  *
  * The VCL code can send us here on a non-cached object, just return.
@@ -238,13 +238,13 @@
 		return;
 	CHECK_OBJ_NOTNULL(oe, OBJEXP_MAGIC);
 	update_object_when(o);
-	LOCK(&exp_mtx);
+	Lck_Lock(&exp_mtx);
 	assert(oe->timer_idx != BINHEAP_NOIDX);
 	binheap_delete(exp_heap, oe->timer_idx); /* XXX: binheap_shuffle() ? */
 	assert(oe->timer_idx == BINHEAP_NOIDX);
 	binheap_insert(exp_heap, oe);
 	assert(oe->timer_idx != BINHEAP_NOIDX);
-	UNLOCK(&exp_mtx);
+	Lck_Unlock(&exp_mtx);
 }
 
 
@@ -278,18 +278,18 @@
 	VCL_Get(&sp->vcl);
 	t = TIM_real();
 	while (1) {
-		LOCK(&exp_mtx);
+		Lck_Lock(&exp_mtx);
 		oe = binheap_root(exp_heap);
 		CHECK_OBJ_ORNULL(oe, OBJEXP_MAGIC);
 		if (oe == NULL || oe->timer_when > t) { /* XXX: > or >= ? */
-			UNLOCK(&exp_mtx);
+			Lck_Unlock(&exp_mtx);
 			WSL_Flush(&ww, 0);
 			AZ(sleep(1));
 			VCL_Refresh(&sp->vcl);
 			t = TIM_real();
 			continue;
 		}
-	
+
 		o = oe->obj;
 		CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
 		assert(oe->timer_idx != BINHEAP_NOIDX);
@@ -305,7 +305,7 @@
 		}
 
 		assert(oe->on_lru);
-		UNLOCK(&exp_mtx);
+		Lck_Unlock(&exp_mtx);
 
 		WSL(&ww, SLT_ExpPick, 0, "%u %s", o->xid, oe->timer_what);
 
@@ -319,10 +319,10 @@
 				    o->xid);
 			}
 			update_object_when(o);
-			LOCK(&exp_mtx);
+			Lck_Lock(&exp_mtx);
 			binheap_insert(exp_heap, oe);
 			assert(oe->timer_idx != BINHEAP_NOIDX);
-			UNLOCK(&exp_mtx);
+			Lck_Unlock(&exp_mtx);
 		} else {
 			assert(oe->timer_what == tmr_ttl);
 			sp->obj = o;
@@ -332,13 +332,13 @@
 			assert(sp->handling == VCL_RET_DISCARD);
 			WSL(&ww, SLT_ExpKill, 0,
 			    "%u %d", o->xid, (int)(o->ttl - t));
-			LOCK(&exp_mtx);
+			Lck_Lock(&exp_mtx);
 			VTAILQ_REMOVE(&lru, o->objexp, list);
 			oe->on_lru = 0;
 			VSL_stats->n_expired++;
-			UNLOCK(&exp_mtx);
+			Lck_Unlock(&exp_mtx);
 			del_objexp(o);
-			HSH_Deref(o);
+			HSH_Deref(&o);
 		}
 	}
 }
@@ -364,10 +364,10 @@
 	 * with active references, likely means that it is already in core. An
 	 * object with no active references will be prodded further anyway.
 	 *
-	 * NB: Checking refcount here is no guarantee that it does not gain 
+	 * NB: Checking refcount here is no guarantee that it does not gain
 	 * another ref while we ponder its destiny without the lock held.
 	 */
-	LOCK(&exp_mtx);
+	Lck_Lock(&exp_mtx);
 	VTAILQ_FOREACH(oe, &lru, list) {
 		CHECK_OBJ_NOTNULL(oe, OBJEXP_MAGIC);
 		if (oe->timer_idx == BINHEAP_NOIDX)	/* exp_timer has it */
@@ -388,7 +388,7 @@
 		assert(oe->timer_idx == BINHEAP_NOIDX);
 		VSL_stats->n_lru_nuked++;
 	}
-	UNLOCK(&exp_mtx);
+	Lck_Unlock(&exp_mtx);
 
 	if (oe == NULL)
 		return (-1);
@@ -407,21 +407,21 @@
 	if (sp->handling == VCL_RET_DISCARD) {
 		WSL(sp->wrk, SLT_ExpKill, 0, "%u LRU", o->xid);
 		del_objexp(o);
-		HSH_Deref(o);
+		HSH_Deref(&o);
 		return (1);
 	}
 
 	assert(sp->handling == VCL_RET_KEEP);
 
 	/* Insert in binheap and lru again */
-	LOCK(&exp_mtx);
-	VSL_stats->n_lru_nuked--; 		/* It was premature */
+	Lck_Lock(&exp_mtx);
+	VSL_stats->n_lru_nuked--;		/* It was premature */
 	VSL_stats->n_lru_saved++;
 	binheap_insert(exp_heap, oe);
 	assert(oe->timer_idx != BINHEAP_NOIDX);
 	VTAILQ_INSERT_TAIL(&lru, oe, list);
 	oe->on_lru = 1;
-	UNLOCK(&exp_mtx);
+	Lck_Unlock(&exp_mtx);
 	return (0);
 }
 
@@ -456,7 +456,7 @@
 EXP_Init(void)
 {
 
-	MTX_INIT(&exp_mtx);
+	Lck_New(&exp_mtx);
 	exp_heap = binheap_new(NULL, object_cmp, object_update);
 	XXXAN(exp_heap);
 	AZ(pthread_create(&exp_thread, NULL, exp_timer, NULL));
diff -Nru 2.0.3/varnish-cache/bin/varnishd/cache_fetch.c trunk/varnish-cache/bin/varnishd/cache_fetch.c
--- 2.0.3/varnish-cache/bin/varnishd/cache_fetch.c	2008-10-16 07:43:08.000000000 +0200
+++ trunk/varnish-cache/bin/varnishd/cache_fetch.c	2009-01-05 14:45:27.000000000 +0100
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: cache_fetch.c 3296 2008-10-14 20:28:26Z phk $
+ * $Id: cache_fetch.c 3470 2008-12-18 11:30:02Z phk $
  */
 
 #include "config.h"
@@ -288,8 +288,8 @@
 			content_length -= rdcnt;
 			if (!sp->sendbody)
 				continue;
-			WRK_Write(sp->wrk, buf, rdcnt);	/* XXX: stats ? */
-			if (WRK_Flush(sp->wrk))
+			(void)WRW_Write(sp->wrk, buf, rdcnt); /* XXX: stats ? */
+			if (WRW_Flush(sp->wrk))
 				return (2);
 		}
 	}
@@ -322,7 +322,7 @@
 	CHECK_OBJ_NOTNULL(sp->obj, OBJECT_MAGIC);
 	CHECK_OBJ_NOTNULL(sp->bereq, BEREQ_MAGIC);
 	AN(sp->director);
-	assert(sp->obj->busy != 0);
+	AN(sp->obj->busy);
 	w = sp->wrk;
 	bereq = sp->bereq;
 	hp = bereq->http;
@@ -336,27 +336,24 @@
 	if (sp->vbe == NULL)
 		return (__LINE__);
 	vc = sp->vbe;
+	/* Inherit the backend timeouts from the selected backend */
+	SES_InheritBackendTimeouts(sp);
 
 	/*
 	 * Now that we know our backend, we can set a default Host:
 	 * header if one is necessary.
 	 * XXX: This possibly ought to go into the default VCL
 	 */
-	if (!http_GetHdr(hp, H_Host, &b)) 
+	if (!http_GetHdr(hp, H_Host, &b))
 		VBE_AddHostHeader(sp);
 
 	TCP_blocking(vc->fd);	/* XXX: we should timeout instead */
-	WRK_Reset(w, &vc->fd);
+	WRW_Reserve(w, &vc->fd);
 	http_Write(w, hp, 0);	/* XXX: stats ? */
 
 	/* Deal with any message-body the request might have */
 	i = FetchReqBody(sp);
-	if (i > 0) {
-		VBE_ClosedFd(sp);
-		return (__LINE__);
-	}
-
-	if (WRK_Flush(w)) {
+	if (WRW_FlushRelease(w) || i > 0) {
 		VBE_ClosedFd(sp);
 		/* XXX: other cleanup ? */
 		return (__LINE__);
@@ -369,8 +366,11 @@
 	VSL_stats->backend_req++;
 
 	HTC_Init(htc, bereq->ws, vc->fd);
-	do
+	TCP_set_read_timeout(vc->fd, sp->first_byte_timeout);
+	do {
 		i = HTC_Rx(htc);
+		TCP_set_read_timeout(vc->fd, sp->between_bytes_timeout);
+	}
 	while (i == 0);
 
 	if (i < 0) {
@@ -414,15 +414,31 @@
 		WSL(sp->wrk, SLT_Debug, vc->fd, "Invalid Transfer-Encoding");
 		VBE_ClosedFd(sp);
 		return (__LINE__);
+	} else if (http_HdrIs(hp, H_Connection, "keep-alive")) {
+		/*
+		 * If we have Connection: keep-alive, it cannot possibly be
+		 * EOF encoded, and since it is neither length nor chunked
+		 * it must be zero length.
+		 */
+		mklen = 1;
+	} else if (http_HdrIs(hp, H_Connection, "close")) {
+		/*
+		 * If we have connection closed, it is safe to read what
+		 * comes in any case.
+		 */
+		cls = fetch_eof(sp, htc);
+		mklen = 1;
+	} else if (hp->protover < 1.1) {
+		/*
+		 * With no Connection header, assume EOF
+		 */
+		cls = fetch_eof(sp, htc);
+		mklen = 1;
 	} else {
-		switch (http_GetStatus(hp)) {
-			case 200:
-				cls = fetch_eof(sp, htc);
-				mklen = 1;
-				break;
-			default:
-				break;
-		}
+		/*
+		 * Assume zero length
+		 */
+		mklen = 1;
 	}
 
 	if (cls < 0) {
@@ -451,7 +467,7 @@
 		http_PrintfHeader(sp->wrk, sp->fd, hp2,
 		    "Content-Length: %u", sp->obj->len);
 
-	if (http_GetHdr(hp, H_Connection, &b) && !strcasecmp(b, "close"))
+	if (http_HdrIs(hp, H_Connection, "close")) 
 		cls = 1;
 
 	if (cls)
@@ -469,8 +485,8 @@
 static void
 debug_fragfetch(struct cli *cli, const char * const *av, void *priv)
 {
-        (void)priv;
-        (void)cli;
+	(void)priv;
+	(void)cli;
 	fetchfrag = strtoul(av[2], NULL, 0);
 }
 
diff -Nru 2.0.3/varnish-cache/bin/varnishd/cache.h trunk/varnish-cache/bin/varnishd/cache.h
--- 2.0.3/varnish-cache/bin/varnishd/cache.h	2008-10-16 07:43:08.000000000 +0200
+++ trunk/varnish-cache/bin/varnishd/cache.h	2009-01-05 14:45:27.000000000 +0100
@@ -26,9 +26,15 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: cache.h 3290 2008-10-11 10:42:05Z phk $
+ * $Id: cache.h 3485 2008-12-21 17:03:37Z phk $
  */
 
+/*
+ * This macro can be used in .h files to isolate bits that the manager
+ * should not (need to) see, such as pthread mutexes etc.
+ */
+#define VARNISH_CACHE_CHILD	1
+
 #include <sys/time.h>
 #include <sys/uio.h>
 #include <sys/socket.h>
@@ -48,7 +54,6 @@
 
 #include "libvarnish.h"
 
-#include "vcl_returns.h"
 #include "common.h"
 #include "heritage.h"
 #include "miniobj.h"
@@ -87,6 +92,9 @@
 struct vrt_backend;
 struct cli_proto;
 struct ban;
+struct SHA256Context;
+
+struct lock { void *priv; };		// Opaque
 
 /*--------------------------------------------------------------------*/
 
@@ -135,11 +143,11 @@
 	struct ws		*ws;
 
 	unsigned char		conds;		/* If-* headers present */
-	enum httpwhence 	logtag;
+	enum httpwhence		logtag;
 	int			status;
 	double			protover;
 
-	txt 			hd[HTTP_HDR_MAX];
+	txt			hd[HTTP_HDR_MAX];
 	unsigned char		hdf[HTTP_HDR_MAX];
 #define HDF_FILTER		(1 << 0)	/* Filtered by Connection */
 	unsigned		nhd;
@@ -195,6 +203,8 @@
 
 	unsigned char		*wlb, *wlp, *wle;
 	unsigned		wlr;
+
+	struct SHA256Context	*sha256ctx;
 };
 
 /* Work Request for worker thread ------------------------------------*/
@@ -212,8 +222,6 @@
 	void			*priv;
 };
 
-#include "hash_slinger.h"
-
 /* Backend Request ---------------------------------------------------*/
 
 struct bereq {
@@ -246,7 +254,7 @@
 struct object {
 	unsigned		magic;
 #define OBJECT_MAGIC		0x32851d42
-	unsigned 		refcnt;
+	unsigned		refcnt;
 	unsigned		xid;
 	struct objhead		*objhead;
 	struct storage		*objstore;
@@ -290,18 +298,6 @@
 	int			hits;
 };
 
-struct objhead {
-	unsigned		magic;
-#define OBJHEAD_MAGIC		0x1b96615d
-	void			*hashpriv;
-
-	pthread_mutex_t		mtx;
-	VTAILQ_HEAD(,object)	objects;
-	char			*hash;
-	unsigned		hashlen;
-	VTAILQ_HEAD(, sess)	waitinglist;
-};
-
 /* -------------------------------------------------------------------*/
 
 struct sess {
@@ -344,12 +340,17 @@
 	double			t_resp;
 	double			t_end;
 
+	/* Timeouts */
+	double connect_timeout;
+	double first_byte_timeout;
+	double between_bytes_timeout;
+
 	/* Acceptable grace period */
 	double			grace;
 
 	enum step		step;
 	unsigned		cur_method;
-	unsigned 		handling;
+	unsigned		handling;
 	unsigned char		sendbody;
 	unsigned char		wantbody;
 	int			err_code;
@@ -405,7 +406,7 @@
 void VBE_ClosedFd(struct sess *sp);
 void VBE_RecycleFd(struct sess *sp);
 struct bereq * VBE_new_bereq(void);
-void VBE_free_bereq(struct bereq *bereq);
+void VBE_free_bereq(struct bereq **bereq);
 void VBE_AddHostHeader(const struct sess *sp);
 void VBE_Poll(void);
 
@@ -447,43 +448,37 @@
 int FetchReqBody(struct sess *sp);
 void Fetch_Init(void);
 
-/* cache_hash.c */
-void HSH_Prealloc(struct sess *sp);
-void HSH_Freestore(struct object *o);
-int HSH_Compare(const struct sess *sp, const struct objhead *o);
-void HSH_Copy(const struct sess *sp, const struct objhead *o);
-struct object *HSH_Lookup(struct sess *sp);
-void HSH_Unbusy(const struct sess *sp);
-void HSH_Ref(struct object *o);
-void HSH_Deref(struct object *o);
-double HSH_Grace(double g);
-void HSH_Init(void);
-
 /* cache_http.c */
 const char *http_StatusMessage(unsigned);
 void HTTP_Init(void);
 void http_ClrHeader(struct http *to);
 unsigned http_Write(struct worker *w, const struct http *hp, int resp);
 void http_CopyResp(struct http *to, const struct http *fm);
-void http_SetResp(struct http *to, const char *proto, const char *status, const char *response);
-void http_FilterFields(struct worker *w, int fd, struct http *to, const struct http *fm, unsigned how);
+void http_SetResp(struct http *to, const char *proto, const char *status,
+    const char *response);
+void http_FilterFields(struct worker *w, int fd, struct http *to,
+    const struct http *fm, unsigned how);
 void http_FilterHeader(struct sess *sp, unsigned how);
-void http_PutProtocol(struct worker *w, int fd, struct http *to, const char *protocol);
+void http_PutProtocol(struct worker *w, int fd, struct http *to,
+    const char *protocol);
 void http_PutStatus(struct worker *w, int fd, struct http *to, int status);
-void http_PutResponse(struct worker *w, int fd, struct http *to, const char *response);
-void http_PrintfHeader(struct worker *w, int fd, struct http *to, const char *fmt, ...);
+void http_PutResponse(struct worker *w, int fd, struct http *to,
+    const char *response);
+void http_PrintfHeader(struct worker *w, int fd, struct http *to,
+    const char *fmt, ...);
 void http_SetHeader(struct worker *w, int fd, struct http *to, const char *hdr);
 void http_SetH(struct http *to, unsigned n, const char *fm);
 void http_ForceGet(struct http *to);
 void http_Setup(struct http *ht, struct ws *ws);
 int http_GetHdr(const struct http *hp, const char *hdr, char **ptr);
-int http_GetHdrField(const struct http *hp, const char *hdr, const char *field, char **ptr);
+int http_GetHdrField(const struct http *hp, const char *hdr,
+    const char *field, char **ptr);
 int http_GetStatus(const struct http *hp);
 const char *http_GetReq(const struct http *hp);
-const char *http_GetProto(const struct http *hp);
 int http_HdrIs(const struct http *hp, const char *hdr, const char *val);
 int http_DissectRequest(struct sess *sp);
-int http_DissectResponse(struct worker *w, const struct http_conn *htc, struct http *sp);
+int http_DissectResponse(struct worker *w, const struct http_conn *htc,
+    struct http *sp);
 const char *http_DoConnection(struct http *hp);
 void http_CopyHome(struct worker *w, int fd, struct http *hp);
 void http_Unset(struct http *hp, const char *hdr);
@@ -505,6 +500,27 @@
 void THR_SetSession(const struct sess *sp);
 const struct sess * THR_GetSession(void);
 
+/* cache_lck.c */
+
+/* Internal functions, call only through macros below */
+void Lck__Lock(struct lock *lck, const char *p, const char *f, int l);
+void Lck__Unlock(struct lock *lck, const char *p, const char *f, int l);
+int Lck__Trylock(struct lock *lck, const char *p, const char *f, int l);
+void Lck__New(struct lock *lck, const char *w);
+void Lck__Assert(const struct lock *lck, int held);
+
+/* public interface: */
+void LCK_Init(void);
+void Lck_Delete(struct lock *lck);
+void Lck_CondWait(pthread_cond_t *cond, struct lock *lck);
+
+#define Lck_New(a) Lck__New(a, #a);
+#define Lck_Lock(a) Lck__Lock(a, __func__, __FILE__, __LINE__)
+#define Lck_Unlock(a) Lck__Unlock(a, __func__, __FILE__, __LINE__)
+#define Lck_Trylock(a) Lck__Trylock(a, __func__, __FILE__, __LINE__)
+#define Lck_AssertHeld(a) Lck__Assert(a, 1)
+#define Lck_AssertNotHeld(a) Lck__Assert(a, 0)
+
 /* cache_panic.c */
 void PAN_Init(void);
 
@@ -515,12 +531,15 @@
 void WRK_Init(void);
 int WRK_Queue(struct workreq *wrq);
 void WRK_QueueSession(struct sess *sp);
-void WRK_Reset(struct worker *w, int *fd);
-unsigned WRK_Flush(struct worker *w);
-unsigned WRK_Write(struct worker *w, const void *ptr, int len);
-unsigned WRK_WriteH(struct worker *w, const txt *hh, const char *suf);
+
+void WRW_Reserve(struct worker *w, int *fd);
+void WRW_Release(struct worker *w);
+unsigned WRW_Flush(struct worker *w);
+unsigned WRW_FlushRelease(struct worker *w);
+unsigned WRW_Write(struct worker *w, const void *ptr, int len);
+unsigned WRW_WriteH(struct worker *w, const txt *hh, const char *suf);
 #ifdef SENDFILE_WORKS
-void WRK_Sendfile(struct worker *w, int fd, off_t off, unsigned len);
+void WRW_Sendfile(struct worker *w, int fd, off_t off, unsigned len);
 #endif  /* SENDFILE_WORKS */
 
 /* cache_session.c [SES] */
@@ -529,6 +548,8 @@
 void SES_Delete(struct sess *sp);
 void SES_RefSrcAddr(struct sess *sp);
 void SES_Charge(struct sess *sp);
+void SES_ResetBackendTimeouts(struct sess *sp);
+void SES_InheritBackendTimeouts(struct sess *sp);
 
 /* cache_shmlog.c */
 void VSL_Init(void);
@@ -538,21 +559,23 @@
 void WSL(struct worker *w, enum shmlogtag tag, int id, const char *fmt, ...);
 void WSL_Flush(struct worker *w, int overflow);
 
-#define DSL(flag, tag, id, ...) 				\
+#define DSL(flag, tag, id, ...)					\
 	do {							\
 		if (params->diag_bitmap & (flag))		\
 			VSL((tag), (id), __VA_ARGS__);		\
 	} while (0)
 
-#define WSP(sess, tag, ...) 					\
+#define WSP(sess, tag, ...)					\
 	WSL((sess)->wrk, tag, (sess)->fd, __VA_ARGS__)
 
-#define WSPR(sess, tag, txt) 					\
+#define WSPR(sess, tag, txt)					\
 	WSLR((sess)->wrk, tag, (sess)->fd, txt)
 
 #define INCOMPL() do {							\
 	VSL(SLT_Debug, 0, "INCOMPLETE AT: %s(%d)", __func__, __LINE__); \
-	fprintf(stderr,"INCOMPLETE AT: %s(%d)\n", (const char *)__func__, __LINE__);	\
+	fprintf(stderr,							\
+	    "INCOMPLETE AT: %s(%d)\n",					\
+	    (const char *)__func__, __LINE__);				\
 	abort();							\
 	} while (0)
 #endif
@@ -572,11 +595,9 @@
 void VCL_Get(struct VCL_conf **vcc);
 void VCL_Poll(void);
 
-#define VCL_RET_MAC(l,u,b,n)
 #define VCL_MET_MAC(l,u,b) void VCL_##l##_method(struct sess *);
 #include "vcl_returns.h"
 #undef VCL_MET_MAC
-#undef VCL_RET_MAC
 
 /* cache_vrt_esi.c */
 
@@ -603,55 +624,6 @@
 struct vsb *SMS_Makesynth(struct object *obj);
 void SMS_Finish(struct object *obj);
 
-#define MTX			pthread_mutex_t
-#define MTX_INIT(foo)		AZ(pthread_mutex_init(foo, NULL))
-#define MTX_DESTROY(foo)	AZ(pthread_mutex_destroy(foo))
-#define TRYLOCK(foo, r)						\
-do {								\
-	(r) = pthread_mutex_trylock(foo);			\
-	assert(r == 0 || r == EBUSY);				\
-	if (params->diag_bitmap & 0x8) {			\
-		VSL(SLT_Debug, 0,				\
-		    "MTX_TRYLOCK(%s,%s,%d," #foo ") = %d",	\
-		    __func__, __FILE__, __LINE__, (r));		\
-	}							\
-} while (0)
-#define LOCK(foo) 						\
-do { 								\
-	if (!(params->diag_bitmap & 0x18)) {			\
-		AZ(pthread_mutex_lock(foo)); 			\
-	} else {						\
-		int ixjd = pthread_mutex_trylock(foo);		\
-		assert(ixjd == 0 || ixjd == EBUSY);		\
-		if (ixjd) {					\
-			VSL(SLT_Debug, 0,			\
-			    "MTX_CONTEST(%s,%s,%d," #foo ")",	\
-			    __func__, __FILE__, __LINE__);	\
-			AZ(pthread_mutex_lock(foo)); 		\
-		} else if (params->diag_bitmap & 0x8) {		\
-			VSL(SLT_Debug, 0,			\
-			    "MTX_LOCK(%s,%s,%d," #foo ")",	\
-			    __func__, __FILE__, __LINE__); 	\
-		}						\
-	}							\
-} while (0)
-#define UNLOCK(foo)						\
-do {								\
-	AZ(pthread_mutex_unlock(foo));				\
-	if (params->diag_bitmap & 0x8)				\
-		VSL(SLT_Debug, 0,				\
-		    "MTX_UNLOCK(%s,%s,%d," #foo ")",		\
-		    __func__, __FILE__, __LINE__);		\
-} while (0)
-
-#if defined(HAVE_PTHREAD_MUTEX_ISOWNED_NP)
-#define ALOCKED(mutex)		AN(pthread_mutex_isowned_np((mutex)))
-#elif defined(DIAGNOSTICS)
-#define ALOCKED(mutex)		AN(pthread_mutex_trylock((mutex)))
-#else
-#define ALOCKED(mutex)		(void)(mutex)
-#endif
-
 /*
  * A normal pointer difference is signed, but we never want a negative value
  * so this little tool will make sure we don't get that.
@@ -684,8 +656,7 @@
 {
 
 	Tcheck(t);
-	return
-	    ((unsigned)(t.e - t.b));
+	return ((unsigned)(t.e - t.b));
 }
 
 static inline void
diff -Nru 2.0.3/varnish-cache/bin/varnishd/cache_hash.c trunk/varnish-cache/bin/varnishd/cache_hash.c
--- 2.0.3/varnish-cache/bin/varnishd/cache_hash.c	2008-10-20 10:55:25.000000000 +0200
+++ trunk/varnish-cache/bin/varnishd/cache_hash.c	2009-01-05 14:45:27.000000000 +0100
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: cache_hash.c 3325 2008-10-20 08:55:24Z tfheen $
+ * $Id: cache_hash.c 3464 2008-12-18 10:04:15Z phk $
  *
  * This is the central hash-table code, it relies on a chosen hash
  * implementation only for the actual hashing, all the housekeeping
@@ -65,8 +65,10 @@
 #include "shmlog.h"
 #include "cache.h"
 #include "stevedore.h"
+#include "hash_slinger.h"
+#include "vsha256.h"
 
-static struct hash_slinger      *hash;
+static const struct hash_slinger *hash;
 
 double
 HSH_Grace(double g)
@@ -81,6 +83,8 @@
 HSH_Prealloc(struct sess *sp)
 {
 	struct worker *w;
+	struct objhead *oh;
+	struct object *o;
 	struct storage *st;
 
 	CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
@@ -88,38 +92,41 @@
 	w = sp->wrk;
 
 	if (w->nobjhead == NULL) {
-		w->nobjhead = calloc(sizeof *w->nobjhead, 1);
-		XXXAN(w->nobjhead);
-		w->nobjhead->magic = OBJHEAD_MAGIC;
-		VTAILQ_INIT(&w->nobjhead->objects);
-		VTAILQ_INIT(&w->nobjhead->waitinglist);
-		MTX_INIT(&w->nobjhead->mtx);
+		ALLOC_OBJ(oh, OBJHEAD_MAGIC);
+		XXXAN(oh);
+		oh->refcnt = 1;
+		VTAILQ_INIT(&oh->objects);
+		VTAILQ_INIT(&oh->waitinglist);
+		Lck_New(&oh->mtx);
+		w->nobjhead = oh;
 		VSL_stats->n_objecthead++;
 	} else
 		CHECK_OBJ_NOTNULL(w->nobjhead, OBJHEAD_MAGIC);
+
 	if (w->nobj == NULL) {
 		st = STV_alloc(sp, params->obj_workspace);
 		XXXAN(st);
 		assert(st->space > sizeof *w->nobj);
-		w->nobj = (void *)st->ptr; /* XXX: align ? */
-		st->len = sizeof *w->nobj;
-		memset(w->nobj, 0, sizeof *w->nobj);
-		w->nobj->objstore = st;
-		WS_Init(w->nobj->ws_o, "obj",
+		o = (void *)st->ptr; /* XXX: align ? */
+		st->len = sizeof *o;
+		memset(o, 0, sizeof *o);
+		o->objstore = st;
+		WS_Init(o->ws_o, "obj",
 		    st->ptr + st->len, st->space - st->len);
 		st->len = st->space;
-		WS_Assert(w->nobj->ws_o);
-		http_Setup(w->nobj->http, w->nobj->ws_o);
-		w->nobj->magic = OBJECT_MAGIC;
-		w->nobj->http->magic = HTTP_MAGIC;
-		w->nobj->busy = 1;
-		w->nobj->refcnt = 1;
-		w->nobj->grace = NAN;
-		w->nobj->entered = NAN;
-		VTAILQ_INIT(&w->nobj->store);
-		VTAILQ_INIT(&w->nobj->esibits);
+		WS_Assert(o->ws_o);
+		http_Setup(o->http, o->ws_o);
+		o->magic = OBJECT_MAGIC;
+		o->http->magic = HTTP_MAGIC;
+		o->busy = 1;
+		o->refcnt = 1;
+		o->grace = NAN;
+		o->entered = NAN;
+		VTAILQ_INIT(&o->store);
+		VTAILQ_INIT(&o->esibits);
+		w->nobj = o;
 		VSL_stats->n_object++;
-		
+
 	} else
 		CHECK_OBJ_NOTNULL(w->nobj, OBJECT_MAGIC);
 }
@@ -137,7 +144,7 @@
 }
 
 int
-HSH_Compare(const struct sess *sp, const struct objhead *obj)
+HSH_Compare(const struct sess *sp, const struct objhead *oh)
 {
 	int i;
 	unsigned u, v;
@@ -145,11 +152,11 @@
 
 	CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
 	CHECK_OBJ_NOTNULL(sp->wrk, WORKER_MAGIC);
-	CHECK_OBJ_NOTNULL(obj, OBJHEAD_MAGIC);
-	i = sp->lhashptr - obj->hashlen;
+	CHECK_OBJ_NOTNULL(oh, OBJHEAD_MAGIC);
+	i = sp->lhashptr - oh->hashlen;
 	if (i)
 		return (i);
-	b = obj->hash;
+	b = oh->hash;
 	for (u = 0; u < sp->ihashptr; u += 2) {
 		v = pdiff(sp->hashptr[u], sp->hashptr[u + 1]);
 		i = memcmp(sp->hashptr[u], b, v);
@@ -162,18 +169,23 @@
 	}
 	assert(*b == '\0');
 	b++;
-	assert(b == obj->hash + obj->hashlen);
+	assert(b == oh->hash + oh->hashlen);
 	return (0);
 }
 
 void
-HSH_Copy(const struct sess *sp, const struct objhead *obj)
+HSH_Copy(const struct sess *sp, struct objhead *oh)
 {
 	unsigned u, v;
 	char *b;
 
-	assert(obj->hashlen >= sp->lhashptr);
-	b = obj->hash;
+	CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
+	CHECK_OBJ_NOTNULL(oh, OBJHEAD_MAGIC);
+
+	oh->hash = malloc(sp->lhashptr);
+	XXXAN(oh->hash);
+	oh->hashlen = sp->lhashptr;
+	b = oh->hash;
 	for (u = 0; u < sp->ihashptr; u += 2) {
 		v = pdiff(sp->hashptr[u], sp->hashptr[u + 1]);
 		memcpy(b, sp->hashptr[u], v);
@@ -181,7 +193,55 @@
 		*b++ = '#';
 	}
 	*b++ = '\0';
-	assert(b <= obj->hash + obj->hashlen);
+	assert(b <= oh->hash + oh->hashlen);
+}
+
+void
+HSH_Prepare(struct sess *sp, unsigned nhashcount)
+{
+	char *p;
+	unsigned u;
+
+	/* Allocate the pointers we need, align properly. */
+	sp->lhashptr = 1;       /* space for NUL */
+	sp->ihashptr = 0;
+	sp->nhashptr = nhashcount * 2;
+	p = WS_Alloc(sp->http->ws, sizeof(const char *) * (sp->nhashptr + 1));
+	XXXAN(p);
+	/* Align pointer properly (?) */
+	u = (uintptr_t)p;
+	u &= sizeof(const char *) - 1;
+	if (u)
+		p += sizeof(const char *) - u;
+	sp->hashptr = (void*)p;
+	if (params->hash_sha256)
+		SHA256_Init(sp->wrk->sha256ctx);
+}
+
+void
+HSH_AddString(struct sess *sp, const char *str)
+{
+	int l;
+
+	if (str == NULL)
+		str = "";
+	l = strlen(str);
+
+	/*
+	* XXX: handle this by bouncing sp->vcl->nhashcount when it fails
+	* XXX: and dispose of this request either by reallocating the
+	* XXX: hashptr (if possible) or restarting/error the request
+	*/
+	xxxassert(sp->ihashptr < sp->nhashptr);
+
+	sp->hashptr[sp->ihashptr] = str;
+	sp->hashptr[sp->ihashptr + 1] = str + l;
+	sp->ihashptr += 2;
+	sp->lhashptr += l + 1;
+	if (params->hash_sha256) {
+		SHA256_Update(sp->wrk->sha256ctx, str, l);
+		SHA256_Update(sp->wrk->sha256ctx, "#", 1);
+	}
 }
 
 struct object *
@@ -200,18 +260,24 @@
 	h = sp->http;
 
 	HSH_Prealloc(sp);
+	if (params->hash_sha256) {
+		SHA256_Final(sp->wrk->nobjhead->digest, sp->wrk->sha256ctx);
+		/* WSP(sp, SLT_Debug, "SHA256: <%.32s>", sha256); */
+	}
+	
 	if (sp->objhead != NULL) {
 		CHECK_OBJ_NOTNULL(sp->objhead, OBJHEAD_MAGIC);
 		oh = sp->objhead;
 		sp->objhead = NULL;
 		CHECK_OBJ_NOTNULL(oh, OBJHEAD_MAGIC);
-		LOCK(&oh->mtx);
+		Lck_Lock(&oh->mtx);
 	} else {
+		AN(w->nobjhead);
 		oh = hash->lookup(sp, w->nobjhead);
 		CHECK_OBJ_NOTNULL(oh, OBJHEAD_MAGIC);
 		if (oh == w->nobjhead)
 			w->nobjhead = NULL;
-		LOCK(&oh->mtx);
+		Lck_Lock(&oh->mtx);
 	}
 
 	busy_o = NULL;
@@ -223,7 +289,7 @@
 		}
 		if (!o->cacheable)
 			continue;
-		if (o->ttl == 0) 
+		if (o->ttl == 0)
 			continue;
 		if (BAN_CheckObject(o, h->hd[HTTP_HDR_URL].b, oh->hash)) {
 			o->ttl = 0;
@@ -257,7 +323,7 @@
 		o->refcnt++;
 		if (o->hits < INT_MAX)
 			o->hits++;
-		UNLOCK(&oh->mtx);
+		Lck_Unlock(&oh->mtx);
 		if (params->log_hash)
 			WSP(sp, SLT_Hash, "%s", oh->hash);
 		(void)hash->deref(oh);
@@ -269,7 +335,7 @@
 		if (sp->esis == 0)
 			VTAILQ_INSERT_TAIL(&oh->waitinglist, sp, list);
 		sp->objhead = oh;
-		UNLOCK(&oh->mtx);
+		Lck_Unlock(&oh->mtx);
 		return (NULL);
 	}
 
@@ -285,7 +351,7 @@
 		o->parent = grace_o;
 		grace_o->refcnt++;
 	}
-	UNLOCK(&oh->mtx);
+	Lck_Unlock(&oh->mtx);
 	if (params->log_hash)
 		WSP(sp, SLT_Hash, "%s", oh->hash);
 	/*
@@ -313,6 +379,22 @@
 }
 
 void
+HSH_Drop(struct sess *sp)
+{
+	struct object *o;
+
+	CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
+	o = sp->obj;
+	CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
+	assert(o->busy);
+	assert(o->refcnt > 0);
+	o->ttl = 0;
+	o->cacheable = 0;
+	HSH_Unbusy(sp);
+	HSH_Deref(&sp->obj);
+}
+
+void
 HSH_Unbusy(const struct sess *sp)
 {
 	struct object *o;
@@ -327,13 +409,13 @@
 	if (o->ws_o->overflow)
 		VSL_stats->n_objoverflow++;
 	if (params->diag_bitmap & 0x40)
-		WSP(sp, SLT_Debug, 
+		WSP(sp, SLT_Debug,
 		    "Object %u workspace free %u", o->xid, WS_Free(o->ws_o));
-	
+
 	oh = o->objhead;
 	if (oh != NULL) {
 		CHECK_OBJ(oh, OBJHEAD_MAGIC);
-		LOCK(&oh->mtx);
+		Lck_Lock(&oh->mtx);
 	}
 	o->busy = 0;
 	if (oh != NULL)
@@ -343,9 +425,9 @@
 	if (parent != NULL)
 		parent->child = NULL;
 	if (oh != NULL)
-		UNLOCK(&oh->mtx);
+		Lck_Unlock(&oh->mtx);
 	if (parent != NULL)
-		HSH_Deref(parent);
+		HSH_Deref(&parent);
 }
 
 void
@@ -355,29 +437,30 @@
 
 	CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
 	oh = o->objhead;
-	if (oh != NULL) {
-		CHECK_OBJ(oh, OBJHEAD_MAGIC);
-		LOCK(&oh->mtx);
-	}
+	CHECK_OBJ_NOTNULL(oh, OBJHEAD_MAGIC);
+	Lck_Lock(&oh->mtx);
 	assert(o->refcnt > 0);
 	o->refcnt++;
-	if (oh != NULL)
-		UNLOCK(&oh->mtx);
+	Lck_Unlock(&oh->mtx);
 }
 
 void
-HSH_Deref(struct object *o)
+HSH_Deref(struct object **oo)
 {
+	struct object *o;
 	struct objhead *oh;
 	unsigned r;
 
+	AN(oo);
+	o = *oo;
+	*oo = NULL;
 	CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
 	oh = o->objhead;
 	if (oh != NULL) {
 		CHECK_OBJ(oh, OBJHEAD_MAGIC);
 
 		/* drop ref on object */
-		LOCK(&oh->mtx);
+		Lck_Lock(&oh->mtx);
 	}
 	assert(o->refcnt > 0);
 	r = --o->refcnt;
@@ -386,7 +469,7 @@
 	if (oh != NULL) {
 		if (!r)
 			VTAILQ_REMOVE(&oh->objects, o, list);
-		UNLOCK(&oh->mtx);
+		Lck_Unlock(&oh->mtx);
 	}
 
 	/* If still referenced, done */
@@ -411,7 +494,7 @@
 	if (hash->deref(oh))
 		return;
 	assert(VTAILQ_EMPTY(&oh->objects));
-	MTX_DESTROY(&oh->mtx);
+	Lck_Delete(&oh->mtx);
 	VSL_stats->n_objecthead--;
 	free(oh->hash);
 	FREE_OBJ(oh);
diff -Nru 2.0.3/varnish-cache/bin/varnishd/cache_http.c trunk/varnish-cache/bin/varnishd/cache_http.c
--- 2.0.3/varnish-cache/bin/varnishd/cache_http.c	2008-10-17 13:04:12.000000000 +0200
+++ trunk/varnish-cache/bin/varnishd/cache_http.c	2009-01-05 14:45:27.000000000 +0100
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: cache_http.c 3316 2008-10-17 11:04:12Z tfheen $
+ * $Id: cache_http.c 3475 2008-12-20 23:27:00Z phk $
  *
  * HTTP request storage and manipulation
  */
@@ -41,7 +41,6 @@
 #include <string.h>
 #include <strings.h>
 
-#include "config.h"
 #include "shmlog.h"
 #include "vct.h"
 #include "cache.h"
@@ -55,9 +54,9 @@
 #undef HTTPH
 
 /*lint -save -e773 not () */
-#define LOGMTX2(ax, bx, cx) 	[bx] = SLT_##ax##cx
+#define LOGMTX2(ax, bx, cx)	[bx] = SLT_##ax##cx
 
-#define LOGMTX1(ax) { 		\
+#define LOGMTX1(ax) {					\
 	LOGMTX2(ax, HTTP_HDR_REQ,	Request),	\
 	LOGMTX2(ax, HTTP_HDR_RESPONSE,	Response),	\
 	LOGMTX2(ax, HTTP_HDR_STATUS,	Status),	\
@@ -66,7 +65,7 @@
 	LOGMTX2(ax, HTTP_HDR_FIRST,	Header),	\
 	}
 
-static enum shmlogtag logmtx[][HTTP_HDR_FIRST + 1] = {
+static const enum shmlogtag logmtx[][HTTP_HDR_FIRST + 1] = {
 	[HTTP_Rx] = LOGMTX1(Rx),
 	[HTTP_Tx] = LOGMTX1(Tx),
 	[HTTP_Obj] = LOGMTX1(Obj)
@@ -99,46 +98,8 @@
 	unsigned	nbr;
 	const char	*txt;
 } http_msg[] = {
-	{ 101, "Switching Protocols" },
-	{ 200, "OK" },
-	{ 201, "Created" },
-	{ 202, "Accepted" },
-	{ 203, "Non-Authoritative Information" },
-	{ 204, "No Content" },
-	{ 205, "Reset Content" },
-	{ 206, "Partial Content" },
-	{ 300, "Multiple Choices" },
-	{ 301, "Moved Permanently" },
-	{ 302, "Found" },
-	{ 303, "See Other" },
-	{ 304, "Not Modified" },
-	{ 305, "Use Proxy" },
-	{ 306, "(Unused)" },
-	{ 307, "Temporary Redirect" },
-	{ 400, "Bad Request" },
-	{ 401, "Unauthorized" },
-	{ 402, "Payment Required" },
-	{ 403, "Forbidden" },
-	{ 404, "Not Found" },
-	{ 405, "Method Not Allowed" },
-	{ 406, "Not Acceptable" },
-	{ 407, "Proxy Authentication Required" },
-	{ 408, "Request Timeout" },
-	{ 409, "Conflict" },
-	{ 410, "Gone" },
-	{ 411, "Length Required" },
-	{ 412, "Precondition Failed" },
-	{ 413, "Request Entity Too Large" },
-	{ 414, "Request-URI Too Long" },
-	{ 415, "Unsupported Media Type" },
-	{ 416, "Requested Range Not Satisfiable" },
-	{ 417, "Expectation Failed" },
-	{ 500, "Internal Server Error" },
-	{ 501, "Not Implemented" },
-	{ 502, "Bad Gateway" },
-	{ 503, "Service Unavailable" },
-	{ 504, "Gateway Timeout" },
-	{ 505, "HTTP Version Not Supported" },
+#define HTTP_RESP(n, t)	{ n, t},
+#include "http_response.h"
 	{ 0, NULL }
 };
 
@@ -229,12 +190,13 @@
 }
 
 /*--------------------------------------------------------------------
- * Find a given headerfield, and if present and wanted, the beginning 
+ * Find a given headerfield, and if present and wanted, the beginning
  * of its value.
  */
 
 int
-http_GetHdrField(const struct http *hp, const char *hdr, const char *field, char **ptr)
+http_GetHdrField(const struct http *hp, const char *hdr,
+    const char *field, char **ptr)
 {
 	char *h, *e;
 	unsigned fl;
@@ -271,7 +233,7 @@
 			return (1);
 		}
 		/* Skip token */
-		while (*h && !vct_issepctl(*h)) 
+		while (*h && !vct_issepctl(*h))
 			h++;
 	}
 	return (0);
@@ -289,7 +251,7 @@
 	unsigned u;
 
 	if (!http_GetHdr(hp, H_Connection, &p)) {
-		if (strcmp(hp->hd[HTTP_HDR_PROTO].b, "HTTP/1.1"))
+		if (hp->protover < 1.1)
 			return ("not HTTP/1.1");
 		return (NULL);
 	}
@@ -341,14 +303,6 @@
 }
 
 const char *
-http_GetProto(const struct http *hp)
-{
-
-	Tcheck(hp->hd[HTTP_HDR_PROTO]);
-	return (hp->hd[HTTP_HDR_PROTO].b);
-}
-
-const char *
 http_GetReq(const struct http *hp)
 {
 
@@ -410,7 +364,8 @@
  */
 
 static int
-http_splitline(struct worker *w, int fd, struct http *hp, const struct http_conn *htc, int h1, int h2, int h3)
+http_splitline(struct worker *w, int fd, struct http *hp,
+    const struct http_conn *htc, int h1, int h2, int h3)
 {
 	char *p;
 
@@ -479,6 +434,21 @@
 
 /*--------------------------------------------------------------------*/
 
+static void
+http_ProtoVer(struct http *hp)
+{
+
+	if (!strcmp(hp->hd[HTTP_HDR_PROTO].b, "HTTP/1.0"))
+		hp->protover = 1.0;
+	else if (!strcmp(hp->hd[HTTP_HDR_PROTO].b, "HTTP/1.1"))
+		hp->protover = 1.1;
+	else
+		hp->protover = 0.9;
+}
+
+
+/*--------------------------------------------------------------------*/
+
 int
 http_DissectRequest(struct sess *sp)
 {
@@ -500,20 +470,15 @@
 		WSPR(sp, SLT_HttpGarbage, htc->rxbuf);
 		return (i);
 	}
-
-	if (!strcmp(hp->hd[HTTP_HDR_PROTO].b, "HTTP/1.0"))
-		hp->protover = 1.0;
-	else if (!strcmp(hp->hd[HTTP_HDR_PROTO].b, "HTTP/1.1"))
-		hp->protover = 1.1;
-	else
-		hp->protover = 0.9;
+	http_ProtoVer(hp);
 	return (i);
 }
 
 /*--------------------------------------------------------------------*/
 
 int
-http_DissectResponse(struct worker *w, const struct http_conn *htc, struct http *hp)
+http_DissectResponse(struct worker *w, const struct http_conn *htc,
+    struct http *hp)
 {
 	int i;
 
@@ -530,13 +495,14 @@
 		if (hp->status == 0)
 			hp->status = i;
 	} else {
-		hp->status = 
+		hp->status =
 		    strtoul(hp->hd[HTTP_HDR_STATUS].b, NULL /* XXX */, 10);
 	}
+	http_ProtoVer(hp);
 	if (hp->hd[HTTP_HDR_RESPONSE].b == NULL ||
 	    !Tlen(hp->hd[HTTP_HDR_RESPONSE])) {
 		/* Backend didn't send a response string, use the standard */
-		hp->hd[HTTP_HDR_RESPONSE].b = 
+		hp->hd[HTTP_HDR_RESPONSE].b =
 		    TRUST_ME(http_StatusMessage(hp->status));
 		hp->hd[HTTP_HDR_RESPONSE].e =
 		    strchr(hp->hd[HTTP_HDR_RESPONSE].b, '\0');
@@ -606,7 +572,8 @@
 }
 
 void
-http_SetResp(struct http *to, const char *proto, const char *status, const char *response)
+http_SetResp(struct http *to, const char *proto, const char *status,
+    const char *response)
 {
 
 	CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
@@ -616,7 +583,8 @@
 }
 
 static void
-http_copyheader(struct worker *w, int fd, struct http *to, const struct http *fm, unsigned n)
+http_copyheader(struct worker *w, int fd, struct http *to,
+    const struct http *fm, unsigned n)
 {
 
 	CHECK_OBJ_NOTNULL(fm, HTTP_MAGIC);
@@ -636,7 +604,8 @@
 /*--------------------------------------------------------------------*/
 
 void
-http_FilterFields(struct worker *w, int fd, struct http *to, const struct http *fm, unsigned how)
+http_FilterFields(struct worker *w, int fd, struct http *to,
+    const struct http *fm, unsigned how)
 {
 	unsigned u;
 
@@ -664,10 +633,10 @@
 	struct bereq *bereq;
 	struct http *hp;
 
-        bereq = VBE_new_bereq();
-        AN(bereq);
-        hp = bereq->http;
-        hp->logtag = HTTP_Tx;
+	bereq = VBE_new_bereq();
+	AN(bereq);
+	hp = bereq->http;
+	hp->logtag = HTTP_Tx;
 
 	http_copyreq(hp, sp->http, how);
 	http_FilterFields(sp->wrk, sp->fd, hp, sp->http, how);
@@ -741,7 +710,8 @@
 /*--------------------------------------------------------------------*/
 
 static void
-http_PutField(struct worker *w, int fd, struct http *to, int field, const char *string)
+http_PutField(struct worker *w, int fd, struct http *to, int field,
+    const char *string)
 {
 	char *p;
 	unsigned l;
@@ -763,7 +733,8 @@
 }
 
 void
-http_PutProtocol(struct worker *w, int fd, struct http *to, const char *protocol)
+http_PutProtocol(struct worker *w, int fd, struct http *to,
+    const char *protocol)
 {
 
 	http_PutField(w, fd, to, HTTP_HDR_PROTO, protocol);
@@ -781,14 +752,16 @@
 }
 
 void
-http_PutResponse(struct worker *w, int fd, struct http *to, const char *response)
+http_PutResponse(struct worker *w, int fd, struct http *to,
+    const char *response)
 {
 
 	http_PutField(w, fd, to, HTTP_HDR_RESPONSE, response);
 }
 
 void
-http_PrintfHeader(struct worker *w, int fd, struct http *to, const char *fmt, ...)
+http_PrintfHeader(struct worker *w, int fd, struct http *to,
+    const char *fmt, ...)
 {
 	va_list ap;
 	unsigned l, n;
@@ -818,7 +791,7 @@
 	unsigned u, v;
 
 	for (v = u = HTTP_HDR_FIRST; u < hp->nhd; u++) {
-		if (http_IsHdr(&hp->hd[u], hdr)) 
+		if (http_IsHdr(&hp->hd[u], hdr))
 			continue;
 		if (v != u) {
 			memcpy(&hp->hd[v], &hp->hd[u], sizeof hp->hd[v]);
@@ -838,28 +811,28 @@
 
 	if (resp) {
 		AN(hp->hd[HTTP_HDR_STATUS].b);
-		l = WRK_WriteH(w, &hp->hd[HTTP_HDR_PROTO], " ");
+		l = WRW_WriteH(w, &hp->hd[HTTP_HDR_PROTO], " ");
 		WSLH(w, *w->wfd, hp, HTTP_HDR_PROTO);
-		l += WRK_WriteH(w, &hp->hd[HTTP_HDR_STATUS], " ");
+		l += WRW_WriteH(w, &hp->hd[HTTP_HDR_STATUS], " ");
 		WSLH(w, *w->wfd, hp, HTTP_HDR_STATUS);
-		l += WRK_WriteH(w, &hp->hd[HTTP_HDR_RESPONSE], "\r\n");
+		l += WRW_WriteH(w, &hp->hd[HTTP_HDR_RESPONSE], "\r\n");
 		WSLH(w, *w->wfd, hp, HTTP_HDR_RESPONSE);
 	} else {
 		AN(hp->hd[HTTP_HDR_URL].b);
-		l = WRK_WriteH(w, &hp->hd[HTTP_HDR_REQ], " ");
+		l = WRW_WriteH(w, &hp->hd[HTTP_HDR_REQ], " ");
 		WSLH(w, *w->wfd, hp, HTTP_HDR_REQ);
-		l += WRK_WriteH(w, &hp->hd[HTTP_HDR_URL], " ");
+		l += WRW_WriteH(w, &hp->hd[HTTP_HDR_URL], " ");
 		WSLH(w, *w->wfd, hp, HTTP_HDR_URL);
-		l += WRK_WriteH(w, &hp->hd[HTTP_HDR_PROTO], "\r\n");
+		l += WRW_WriteH(w, &hp->hd[HTTP_HDR_PROTO], "\r\n");
 		WSLH(w, *w->wfd, hp, HTTP_HDR_PROTO);
 	}
 	for (u = HTTP_HDR_FIRST; u < hp->nhd; u++) {
 		AN(hp->hd[u].b);
 		AN(hp->hd[u].e);
-		l += WRK_WriteH(w, &hp->hd[u], "\r\n");
+		l += WRW_WriteH(w, &hp->hd[u], "\r\n");
 		WSLH(w, *w->wfd, hp, u);
 	}
-	l += WRK_Write(w, "\r\n", -1);
+	l += WRW_Write(w, "\r\n", -1);
 	return (l);
 }
 
diff -Nru 2.0.3/varnish-cache/bin/varnishd/cache_httpconn.c trunk/varnish-cache/bin/varnishd/cache_httpconn.c
--- 2.0.3/varnish-cache/bin/varnishd/cache_httpconn.c	2008-10-16 07:43:08.000000000 +0200
+++ trunk/varnish-cache/bin/varnishd/cache_httpconn.c	2008-10-20 10:58:16.000000000 +0200
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: cache_httpconn.c 2906 2008-07-08 10:29:07Z phk $
+ * $Id: cache_httpconn.c 3324 2008-10-18 20:50:10Z phk $
  *
  * HTTP protocol requests
  */
@@ -133,7 +133,7 @@
 
 	CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC);
 	i = htc_header_complete(&htc->rxbuf);
-	if (i < 0) 
+	if (i < 0)
 		htc->rxbuf.e = htc->rxbuf.b;
 	if (i <= 0)
 		return (0);
@@ -195,7 +195,7 @@
 		p += l;
 		len -= l;
 		htc->pipeline.b += l;
-		if (htc->pipeline.b == htc->pipeline.e) 
+		if (htc->pipeline.b == htc->pipeline.e)
 			htc->pipeline.b = htc->pipeline.e = NULL;
 	}
 	if (len == 0)
diff -Nru 2.0.3/varnish-cache/bin/varnishd/cache_lck.c trunk/varnish-cache/bin/varnishd/cache_lck.c
--- 2.0.3/varnish-cache/bin/varnishd/cache_lck.c	1970-01-01 01:00:00.000000000 +0100
+++ trunk/varnish-cache/bin/varnishd/cache_lck.c	2009-01-05 14:45:27.000000000 +0100
@@ -0,0 +1,192 @@
+/*-
+ * Copyright (c) 2008 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$
+ *
+ * The geniuses who came up with pthreads did not think operations like
+ * pthread_assert_mutex_held() were important enough to include them in
+ * the API.
+ *
+ * Build our own locks on top of pthread mutexes and hope that the next
+ * civilization is better at such crucial details than this one.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+
+#include <pthread.h>
+#ifdef HAVE_PTHREAD_NP_H
+#include <pthread_np.h>
+#endif
+#include <stdlib.h>
+
+#include "shmlog.h"
+#include "cache.h"
+
+struct ilck {
+	unsigned		magic;
+#define ILCK_MAGIC		0x7b86c8a5
+	pthread_mutex_t		mtx;
+	int			held;
+	pthread_t		owner;
+	VTAILQ_ENTRY(ilck)	list;
+	const char		*w;
+};
+
+static VTAILQ_HEAD(, ilck)	ilck_head =
+    VTAILQ_HEAD_INITIALIZER(ilck_head);
+
+static pthread_mutex_t		lck_mtx;
+
+void
+Lck__Lock(struct lock *lck, const char *p, const char *f, int l)
+{
+	struct ilck *ilck;
+	int r;
+
+	CAST_OBJ_NOTNULL(ilck, lck->priv, ILCK_MAGIC);
+	if (!(params->diag_bitmap & 0x18)) {
+		AZ(pthread_mutex_lock(&ilck->mtx));
+		AZ(ilck->held);
+		ilck->owner = pthread_self();
+		ilck->held = 1;
+		return;
+	}
+	r = pthread_mutex_trylock(&ilck->mtx);
+	assert(r == 0 || errno == EBUSY);
+	if (r) {
+		VSL(SLT_Debug, 0, "MTX_CONTEST(%s,%s,%d,%s)", p, f, l, ilck->w);
+		AZ(pthread_mutex_lock(&ilck->mtx));
+	} else if (params->diag_bitmap & 0x8) {
+		VSL(SLT_Debug, 0, "MTX_LOCK(%s,%s,%d,%s)", p, f, l, ilck->w);
+	}
+	AZ(ilck->held);
+	ilck->owner = pthread_self();
+	ilck->held = 1;
+}
+
+void
+Lck__Unlock(struct lock *lck, const char *p, const char *f, int l)
+{
+	struct ilck *ilck;
+
+	CAST_OBJ_NOTNULL(ilck, lck->priv, ILCK_MAGIC);
+	assert(pthread_equal(ilck->owner, pthread_self()));
+	AN(ilck->held);
+	ilck->held = 0;
+	AZ(pthread_mutex_unlock(&ilck->mtx));
+	if (params->diag_bitmap & 0x8)
+		VSL(SLT_Debug, 0, "MTX_UNLOCK(%s,%s,%d,%s)", p, f, l, ilck->w);
+}
+
+int
+Lck__Trylock(struct lock *lck, const char *p, const char *f, int l)
+{
+	struct ilck *ilck;
+	int r;
+
+	CAST_OBJ_NOTNULL(ilck, lck->priv, ILCK_MAGIC);
+	r = pthread_mutex_lock(&ilck->mtx);
+	assert(r == 0 || errno == EBUSY);
+	if (params->diag_bitmap & 0x8)
+		VSL(SLT_Debug, 0,
+		    "MTX_TRYLOCK(%s,%s,%d,%s) = %d", p, f, l, ilck->w);
+	if (r == 0) {
+		AZ(ilck->held);
+		ilck->held = 1;
+		ilck->owner = pthread_self();
+	}
+	return (r);
+}
+
+void
+Lck__Assert(const struct lock *lck, int held)
+{
+	struct ilck *ilck;
+
+	CAST_OBJ_NOTNULL(ilck, lck->priv, ILCK_MAGIC);
+	if (held)
+		assert(ilck->held &&
+		    pthread_equal(ilck->owner, pthread_self()));
+	else
+		assert(!ilck->held ||
+		    !pthread_equal(ilck->owner, pthread_self()));
+}
+
+void
+Lck_CondWait(pthread_cond_t *cond, struct lock *lck)
+{
+	struct ilck *ilck;
+
+	CAST_OBJ_NOTNULL(ilck, lck->priv, ILCK_MAGIC);
+	AN(ilck->held);
+	assert(pthread_equal(ilck->owner, pthread_self()));
+	ilck->held = 0;
+	AZ(pthread_cond_wait(cond, &ilck->mtx));
+	AZ(ilck->held);
+	ilck->held = 1;
+	ilck->owner = pthread_self();
+}
+
+void
+Lck__New(struct lock *lck, const char *w)
+{
+	struct ilck *ilck;
+
+	AZ(lck->priv);
+	ALLOC_OBJ(ilck, ILCK_MAGIC);
+	AN(ilck);
+	ilck->w = w;
+	AZ(pthread_mutex_init(&ilck->mtx, NULL));
+	AZ(pthread_mutex_lock(&lck_mtx));
+	VTAILQ_INSERT_TAIL(&ilck_head, ilck, list);
+	AZ(pthread_mutex_unlock(&lck_mtx));
+	lck->priv = ilck;
+}
+
+void
+Lck_Delete(struct lock *lck)
+{
+	struct ilck *ilck;
+
+	CAST_OBJ_NOTNULL(ilck, lck->priv, ILCK_MAGIC);
+	lck->priv = NULL;
+	AZ(pthread_mutex_lock(&lck_mtx));
+	VTAILQ_REMOVE(&ilck_head, ilck, list);
+	AZ(pthread_mutex_unlock(&lck_mtx));
+	AZ(pthread_mutex_destroy(&ilck->mtx));
+	FREE_OBJ(ilck);
+}
+
+
+void
+LCK_Init(void)
+{
+
+	AZ(pthread_mutex_init(&lck_mtx, NULL));
+}
diff -Nru 2.0.3/varnish-cache/bin/varnishd/cache_main.c trunk/varnish-cache/bin/varnishd/cache_main.c
--- 2.0.3/varnish-cache/bin/varnishd/cache_main.c	2008-10-16 07:43:08.000000000 +0200
+++ trunk/varnish-cache/bin/varnishd/cache_main.c	2009-01-05 14:45:27.000000000 +0100
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: cache_main.c 3084 2008-08-12 12:57:00Z phk $
+ * $Id: cache_main.c 3405 2008-11-19 11:58:48Z phk $
  */
 
 #include "config.h"
@@ -39,6 +39,7 @@
 #include "shmlog.h"
 #include "cache.h"
 #include "stevedore.h"
+#include "hash_slinger.h"
 
 /*--------------------------------------------------------------------
  * Per thread storage for the session currently being processed by
@@ -101,6 +102,10 @@
 
 	THR_SetName("cache-main");
 
+	VSL_Init();	/* First, LCK needs it. */
+
+	LCK_Init();	/* Locking, must be first */
+
 	PAN_Init();
 	CLI_Init();
 	Fetch_Init();
@@ -113,7 +118,6 @@
 
 	VBE_Init();
 	VBP_Init();
-	VSL_Init();
 	WRK_Init();
 
 	EXP_Init();
diff -Nru 2.0.3/varnish-cache/bin/varnishd/cache_panic.c trunk/varnish-cache/bin/varnishd/cache_panic.c
--- 2.0.3/varnish-cache/bin/varnishd/cache_panic.c	2008-10-16 07:43:08.000000000 +0200
+++ trunk/varnish-cache/bin/varnishd/cache_panic.c	2009-01-05 14:45:27.000000000 +0100
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: cache_panic.c 3230 2008-09-26 13:20:18Z phk $
+ * $Id: cache_panic.c 3479 2008-12-21 10:47:09Z phk $
  */
 
 #include "config.h"
@@ -37,10 +37,10 @@
 #include <stdlib.h>
 #include <unistd.h>
 
-#include "config.h"
 #include "cache.h"
 #include "cache_backend.h"
 #include "vcl.h"
+#include "libvcl.h"
 
 /*
  * The panic string is constructed in memory, then copied to the
@@ -64,15 +64,15 @@
 	    ws, ws->overflow ? "overflow" : "");
 	vsb_printf(vsp, "%*sid = \"%s\",\n", indent + 2, "", ws->id);
 	vsb_printf(vsp, "%*s{s,f,r,e} = {%p,", indent + 2, "", ws->s);
-	if (ws->f > ws->s) 
+	if (ws->f > ws->s)
 		vsb_printf(vsp, ",+%d", ws->f - ws->s);
 	else
 		vsb_printf(vsp, ",%p", ws->f);
-	if (ws->r > ws->s) 
+	if (ws->r > ws->s)
 		vsb_printf(vsp, ",+%d", ws->r - ws->s);
 	else
 		vsb_printf(vsp, ",%p", ws->r);
-	if (ws->e > ws->s) 
+	if (ws->e > ws->s)
 		vsb_printf(vsp, ",+%d", ws->e - ws->s);
 	else
 		vsb_printf(vsp, ",%p", ws->e);
@@ -215,16 +215,7 @@
 /*lint -restore */
 		default: stp = NULL;
 	}
-	switch (sp->handling) {
-/*lint -save -e525 */
-#define VCL_RET_MAC(l, u, b, v) case VCL_RET_##u: hand = #u; break;
-#define VCL_RET_MAC_E(l, u, b, v) case VCL_RET_##u: hand = #u; break;
-#include "vcl_returns.h"
-#undef VCL_RET_MAC
-#undef VCL_RET_MAC_E
-/*lint -restore */
-		default: hand = NULL;
-	}
+	hand = VCC_Return_Name(sp->handling);
 	if (stp != NULL)
 		vsb_printf(vsp, "  step = %s,\n", stp);
 	else
@@ -258,7 +249,8 @@
 /*--------------------------------------------------------------------*/
 
 static void
-pan_ic(const char *func, const char *file, int line, const char *cond, int err, int xxx)
+pan_ic(const char *func, const char *file, int line, const char *cond,
+    int err, int xxx)
 {
 	int l;
 	char *p;
@@ -296,7 +288,7 @@
 		vsb_printf(vsp, "  thread = (%s)", q);
 	if (!(params->diag_bitmap & 0x2000)) {
 		sp = THR_GetSession();
-		if (sp != NULL) 
+		if (sp != NULL)
 			pan_sess(sp);
 	}
 	vsb_printf(vsp, "\n");
@@ -307,7 +299,7 @@
 	memcpy(p, panicstr, l);
 	if (params->diag_bitmap & 0x4000)
 		(void)fputs(panicstr, stderr);
-		
+
 #ifdef HAVE_ABORT2
 	if (params->diag_bitmap & 0x8000) {
 		void *arg[1];
diff -Nru 2.0.3/varnish-cache/bin/varnishd/cache_pipe.c trunk/varnish-cache/bin/varnishd/cache_pipe.c
--- 2.0.3/varnish-cache/bin/varnishd/cache_pipe.c	2008-10-16 07:43:08.000000000 +0200
+++ trunk/varnish-cache/bin/varnishd/cache_pipe.c	2009-01-05 14:45:27.000000000 +0100
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: cache_pipe.c 3129 2008-08-26 09:17:32Z phk $
+ * $Id: cache_pipe.c 3464 2008-12-18 10:04:15Z phk $
  *
  * XXX: charge bytes to srcaddr
  */
@@ -83,21 +83,20 @@
 	vc = sp->vbe;
 	TCP_blocking(vc->fd);
 
-	WRK_Reset(w, &vc->fd);
+	WRW_Reserve(w, &vc->fd);
 	w->acct.hdrbytes += http_Write(w, bereq->http, 0);
 
 	if (sp->htc->pipeline.b != NULL)
 		w->acct.bodybytes +=
-		    WRK_Write(w, sp->htc->pipeline.b, Tlen(sp->htc->pipeline));
+		    WRW_Write(w, sp->htc->pipeline.b, Tlen(sp->htc->pipeline));
 
-	if (WRK_Flush(w)) {
+	if (WRW_FlushRelease(w)) {
 		vca_close_session(sp, "pipe");
 		VBE_ClosedFd(sp);
 		return;
 	}
 
-	VBE_free_bereq(bereq);
-	bereq = NULL;
+	VBE_free_bereq(&bereq);
 
 	sp->t_resp = TIM_real();
 
@@ -111,7 +110,7 @@
 		fds[0].revents = 0;
 		fds[1].revents = 0;
 		i = poll(fds, 2, params->pipe_timeout * 1000);
-		if (i < 1) 
+		if (i < 1)
 			break;
 		if (fds[0].revents && rdf(vc->fd, sp->fd)) {
 			(void)shutdown(vc->fd, SHUT_RD);
diff -Nru 2.0.3/varnish-cache/bin/varnishd/cache_pool.c trunk/varnish-cache/bin/varnishd/cache_pool.c
--- 2.0.3/varnish-cache/bin/varnishd/cache_pool.c	2008-10-16 07:43:08.000000000 +0200
+++ trunk/varnish-cache/bin/varnishd/cache_pool.c	2009-01-05 14:45:27.000000000 +0100
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: cache_pool.c 3213 2008-09-22 13:36:34Z phk $
+ * $Id: cache_pool.c 3445 2008-11-26 12:05:44Z phk $
  *
  * We maintain a number of worker thread pools, to spread lock contention.
  *
@@ -71,6 +71,8 @@
 #include "cli_priv.h"
 #include "cache.h"
 #include "stevedore.h"
+#include "hash_slinger.h"
+#include "vsha256.h"
 
 VTAILQ_HEAD(workerhead, worker);
 
@@ -79,7 +81,7 @@
 struct wq {
 	unsigned		magic;
 #define WQ_MAGIC		0x606658fa
-	MTX 			mtx;
+	struct lock		mtx;
 	struct workerhead	idle;
 	VTAILQ_HEAD(, workreq)	overflow;
 	unsigned		nthr;
@@ -95,7 +97,7 @@
 static unsigned			nthr_max;
 
 static pthread_cond_t		herder_cond;
-static MTX			herder_mtx;
+static struct lock		herder_mtx;
 
 /*--------------------------------------------------------------------
  * Write data to fd
@@ -105,26 +107,43 @@
  */
 
 void
-WRK_Reset(struct worker *w, int *fd)
+WRW_Reserve(struct worker *w, int *fd)
 {
 
 	CHECK_OBJ_NOTNULL(w, WORKER_MAGIC);
+	AZ(w->wfd);
 	w->werr = 0;
 	w->liov = 0;
 	w->niov = 0;
 	w->wfd = fd;
 }
 
+void
+WRW_Release(struct worker *w)
+{
+
+	CHECK_OBJ_NOTNULL(w, WORKER_MAGIC);
+	w->werr = 0;
+	w->liov = 0;
+	w->niov = 0;
+	w->wfd = NULL;
+}
+
 unsigned
-WRK_Flush(struct worker *w)
+WRW_Flush(struct worker *w)
 {
 	ssize_t i;
 
 	CHECK_OBJ_NOTNULL(w, WORKER_MAGIC);
+	AN(w->wfd);
 	if (*w->wfd >= 0 && w->niov > 0 && w->werr == 0) {
 		i = writev(*w->wfd, w->iov, w->niov);
-		if (i != w->liov)
+		if (i != w->liov) {
 			w->werr++;
+			WSL(w, SLT_Debug, *w->wfd,
+			    "Write error, len = %d/%d, errno = %s",
+			    i, w->liov, strerror(errno));
+		}
 	}
 	w->liov = 0;
 	w->niov = 0;
@@ -132,32 +151,46 @@
 }
 
 unsigned
-WRK_WriteH(struct worker *w, const txt *hh, const char *suf)
+WRW_FlushRelease(struct worker *w)
+{
+	unsigned u;
+
+	CHECK_OBJ_NOTNULL(w, WORKER_MAGIC);
+	AN(w->wfd);
+	u = WRW_Flush(w);
+	WRW_Release(w);
+	return (u);
+}
+
+unsigned
+WRW_WriteH(struct worker *w, const txt *hh, const char *suf)
 {
 	unsigned u;
 
 	CHECK_OBJ_NOTNULL(w, WORKER_MAGIC);
+	AN(w->wfd);
 	AN(w);
 	AN(hh);
 	AN(hh->b);
 	AN(hh->e);
-	u = WRK_Write(w, hh->b, hh->e - hh->b);
+	u = WRW_Write(w, hh->b, hh->e - hh->b);
 	if (suf != NULL)
-		u += WRK_Write(w, suf, -1);
+		u += WRW_Write(w, suf, -1);
 	return (u);
 }
 
 unsigned
-WRK_Write(struct worker *w, const void *ptr, int len)
+WRW_Write(struct worker *w, const void *ptr, int len)
 {
 
 	CHECK_OBJ_NOTNULL(w, WORKER_MAGIC);
+	AN(w->wfd);
 	if (len == 0 || *w->wfd < 0)
 		return (0);
 	if (len == -1)
 		len = strlen(ptr);
 	if (w->niov == MAX_IOVS)
-		(void)WRK_Flush(w);
+		(void)WRW_Flush(w);
 	w->iov[w->niov].iov_base = TRUST_ME(ptr);
 	w->iov[w->niov].iov_len = len;
 	w->liov += len;
@@ -167,10 +200,11 @@
 
 #ifdef SENDFILE_WORKS
 void
-WRK_Sendfile(struct worker *w, int fd, off_t off, unsigned len)
+WRW_Sendfile(struct worker *w, int fd, off_t off, unsigned len)
 {
 
 	CHECK_OBJ_NOTNULL(w, WORKER_MAGIC);
+	AN(w->wfd);
 	assert(fd >= 0);
 	assert(len > 0);
 
@@ -193,8 +227,7 @@
 		    sendfile(*w->wfd, fd, &off, len) != len)
 			w->werr++;
 	} while (0);
-#elif defined(__sun)
-#ifdef HAVE_SENDFILEV
+#elif defined(__sun) && defined(HAVE_SENDFILEV)
 	do {
 		sendfilevec_t svvec[HTTP_HDR_MAX * 2 + 1];
 		size_t xferred = 0, expected = 0;
@@ -217,13 +250,12 @@
 		w->liov = 0;
 		w->niov = 0;
 	} while (0);
-#else
+#elif defined(__sun) && defined(HAVE_SENDFILE)
 	do {
 		if (WRK_Flush(w) == 0 &&
 		    sendfile(*w->wfd, fd, &off, len) != len)
 			w->werr++;
 	} while (0);
-#endif
 #else
 #error Unknown sendfile() implementation
 #endif
@@ -238,6 +270,7 @@
 	struct worker *w, ww;
 	struct wq *qp;
 	unsigned char wlog[params->shm_workspace];
+	struct SHA256Context sha256;
 
 	THR_SetName("cache-worker");
 	w = &ww;
@@ -247,11 +280,12 @@
 	w->lastused = NAN;
 	w->wlb = w->wlp = wlog;
 	w->wle = wlog + sizeof wlog;
+	w->sha256ctx = &sha256;
 	AZ(pthread_cond_init(&w->cond, NULL));
 
 	VSL(SLT_WorkThread, 0, "%p start", w);
 
-	LOCK(&qp->mtx);
+	Lck_Lock(&qp->mtx);
 	qp->nthr++;
 	while (1) {
 		CHECK_OBJ_NOTNULL(w, WORKER_MAGIC);
@@ -265,20 +299,22 @@
 			if (isnan(w->lastused))
 				w->lastused = TIM_real();
 			VTAILQ_INSERT_HEAD(&qp->idle, w, list);
-			AZ(pthread_cond_wait(&w->cond, &qp->mtx));
+			Lck_CondWait(&w->cond, &qp->mtx);
 		}
 		if (w->wrq == NULL)
 			break;
-		UNLOCK(&qp->mtx);
+		Lck_Unlock(&qp->mtx);
 		AN(w->wrq);
 		AN(w->wrq->func);
 		w->lastused = NAN;
 		w->wrq->func(w, w->wrq->priv);
+		AZ(w->wfd);
+		assert(w->wlp == w->wlb);
 		w->wrq = NULL;
-		LOCK(&qp->mtx);
+		Lck_Lock(&qp->mtx);
 	}
 	qp->nthr--;
-	UNLOCK(&qp->mtx);
+	Lck_Unlock(&qp->mtx);
 
 	VSL(SLT_WorkThread, 0, "%p end", w);
 	if (w->vcl != NULL)
@@ -287,7 +323,7 @@
 	if (w->srcaddr != NULL)
 		free(w->srcaddr);
 	if (w->nobjhead != NULL) {
-		MTX_DESTROY(&w->nobjhead->mtx);
+		Lck_Delete(&w->nobjhead->mtx);
 		FREE_OBJ(w->nobjhead);
 	}
 	if (w->nobj!= NULL)
@@ -320,13 +356,13 @@
 	qp = wq[onq];
 	nq = onq;
 
-	LOCK(&qp->mtx);
+	Lck_Lock(&qp->mtx);
 
 	/* If there are idle threads, we tickle the first one into action */
 	w = VTAILQ_FIRST(&qp->idle);
 	if (w != NULL) {
 		VTAILQ_REMOVE(&qp->idle, w, list);
-		UNLOCK(&qp->mtx);
+		Lck_Unlock(&qp->mtx);
 		w->wrq = wrq;
 		AZ(pthread_cond_signal(&w->cond));
 		return (0);
@@ -335,14 +371,14 @@
 	/* If we have too much in the overflow already, refuse. */
 	if (qp->nqueue > ovfl_max) {
 		qp->ndrop++;
-		UNLOCK(&qp->mtx);
+		Lck_Unlock(&qp->mtx);
 		return (-1);
 	}
 
 	VTAILQ_INSERT_TAIL(&qp->overflow, wrq, list);
 	qp->noverflow++;
 	qp->nqueue++;
-	UNLOCK(&qp->mtx);
+	Lck_Unlock(&qp->mtx);
 	AZ(pthread_cond_signal(&herder_cond));
 	return (0);
 }
@@ -414,7 +450,7 @@
 		wq[u] = calloc(sizeof *wq[u], 1);
 		XXXAN(wq[u]);
 		wq[u]->magic = WQ_MAGIC;
-		MTX_INIT(&wq[u]->mtx);
+		Lck_New(&wq[u]->mtx);
 		VTAILQ_INIT(&wq[u]->overflow);
 		VTAILQ_INIT(&wq[u]->idle);
 	}
@@ -431,7 +467,7 @@
 {
 	struct worker *w = NULL;
 
-	LOCK(&qp->mtx);
+	Lck_Lock(&qp->mtx);
 	vs->n_wrk += qp->nthr;
 	vs->n_wrk_queue += qp->nqueue;
 	vs->n_wrk_drop += qp->ndrop;
@@ -444,7 +480,7 @@
 		else
 			w = NULL;
 	}
-	UNLOCK(&qp->mtx);
+	Lck_Unlock(&qp->mtx);
 
 	/* And give it a kiss on the cheek... */
 	if (w != NULL) {
@@ -456,7 +492,7 @@
 
 /*--------------------------------------------------------------------
  * Periodic pool herding thread
- * 
+ *
  * Do things which we can do at our leisure:
  *  Add pools
  *  Scale constants
@@ -574,9 +610,9 @@
 			 * We cannot avoid getting a mutex, so we have a
 			 * bogo mutex just for POSIX_STUPIDITY
 			 */
-			AZ(pthread_mutex_lock(&herder_mtx));
-			AZ(pthread_cond_wait(&herder_cond, &herder_mtx));
-			AZ(pthread_mutex_unlock(&herder_mtx));
+			Lck_Lock(&herder_mtx);
+			Lck_CondWait(&herder_cond, &herder_mtx);
+			Lck_Unlock(&herder_mtx);
 			wrk_breed_flock(wq[u]);
 		}
 	}
@@ -590,7 +626,7 @@
 	pthread_t tp;
 
 	AZ(pthread_cond_init(&herder_cond, NULL));
-	AZ(pthread_mutex_init(&herder_mtx, NULL));
+	Lck_New(&herder_mtx);
 
 	wrk_addpools(params->wthread_pools);
 	AZ(pthread_create(&tp, NULL, wrk_herdtimer_thread, NULL));
@@ -598,3 +634,5 @@
 	AZ(pthread_create(&tp, NULL, wrk_herder_thread, NULL));
 	AZ(pthread_detach(tp));
 }
+
+/*--------------------------------------------------------------------*/
diff -Nru 2.0.3/varnish-cache/bin/varnishd/cache_response.c trunk/varnish-cache/bin/varnishd/cache_response.c
--- 2.0.3/varnish-cache/bin/varnishd/cache_response.c	2008-10-16 07:43:08.000000000 +0200
+++ trunk/varnish-cache/bin/varnishd/cache_response.c	2009-01-05 14:45:27.000000000 +0100
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: cache_response.c 3292 2008-10-11 11:28:52Z phk $
+ * $Id: cache_response.c 3429 2008-11-24 17:47:21Z phk $
  */
 
 #include "config.h"
@@ -137,17 +137,24 @@
 	CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
 	CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
 
-	WRK_Reset(sp->wrk, &sp->fd);
+	WRW_Reserve(sp->wrk, &sp->fd);
+
 	if (sp->esis == 0)
 		sp->wrk->acct.hdrbytes += http_Write(sp->wrk, sp->http, 1);
 
 	if (sp->wantbody && !VTAILQ_EMPTY(&sp->obj->esibits)) {
+		if (WRW_FlushRelease(sp->wrk)) {
+			vca_close_session(sp, "remote closed");
+			return;
+		}
 		ESI_Deliver(sp);
-	} else if (sp->wantbody) {
+		return;
+	}
+
+	if (sp->wantbody) {
 		if (sp->esis > 0 && sp->http->protover >= 1.1) {
 			sprintf(lenbuf, "%x\r\n", sp->obj->len);
-			sp->wrk->acct.hdrbytes +=
-			    WRK_Write(sp->wrk, lenbuf, -1);
+			(void)WRW_Write(sp->wrk, lenbuf, -1);
 		}
 
 		VTAILQ_FOREACH(st, &sp->obj->store, list) {
@@ -165,18 +172,18 @@
 			if (st->fd >= 0 &&
 			    st->len >= params->sendfile_threshold) {
 				VSL_stats->n_objsendfile++;
-				WRK_Sendfile(sp->wrk, st->fd,
+				WRW_Sendfile(sp->wrk, st->fd,
 				    st->where, st->len);
 				continue;
 			}
 #endif /* SENDFILE_WORKS */
 			VSL_stats->n_objwrite++;
-			WRK_Write(sp->wrk, st->ptr, st->len);
+			(void)WRW_Write(sp->wrk, st->ptr, st->len);
 		}
 		assert(u == sp->obj->len);
 		if (sp->esis > 0 && sp->http->protover >= 1.1)
-			WRK_Write(sp->wrk, "\r\n", -1);
+			(void)WRW_Write(sp->wrk, "\r\n", -1);
 	}
-	if (WRK_Flush(sp->wrk))
+	if (WRW_FlushRelease(sp->wrk))
 		vca_close_session(sp, "remote closed");
 }
diff -Nru 2.0.3/varnish-cache/bin/varnishd/cache_session.c trunk/varnish-cache/bin/varnishd/cache_session.c
--- 2.0.3/varnish-cache/bin/varnishd/cache_session.c	2008-10-16 07:43:08.000000000 +0200
+++ trunk/varnish-cache/bin/varnishd/cache_session.c	2009-01-05 14:45:27.000000000 +0100
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: cache_session.c 2976 2008-07-20 11:28:40Z phk $
+ * $Id: cache_session.c 3493 2008-12-21 18:35:47Z phk $
  *
  * Session and Client management.
  *
@@ -58,6 +58,7 @@
 
 #include "shmlog.h"
 #include "cache.h"
+#include "cache_backend.h"
 
 /*--------------------------------------------------------------------*/
 
@@ -78,7 +79,7 @@
 };
 
 static unsigned ses_qp;
-static MTX			ses_mem_mtx;
+static struct lock		ses_mem_mtx;
 
 /*--------------------------------------------------------------------*/
 
@@ -103,11 +104,11 @@
 	unsigned		magic;
 #define SRCADDRHEAD_MAGIC	0x38231a8b
 	VTAILQ_HEAD(,srcaddr)	head;
-	MTX			mtx;
+	struct lock		mtx;
 } *srchash;
 
 static unsigned			nsrchash;
-static MTX			stat_mtx;
+static struct lock 		stat_mtx;
 
 /*--------------------------------------------------------------------
  * Assign a srcaddr to this session.
@@ -140,7 +141,7 @@
 		XXXAN(sp->wrk->srcaddr);
 	}
 
-	LOCK(&ch->mtx);
+	Lck_Lock(&ch->mtx);
 	c3 = NULL;
 	VTAILQ_FOREACH_SAFE(c, &ch->head, list, c2) {
 		if (c->hash == u && !strcmp(c->addr, sp->addr)) {
@@ -155,7 +156,7 @@
 				VTAILQ_REMOVE(&ch->head, c3, list);
 				VSL_stats->n_srcaddr--;
 			}
-			UNLOCK(&ch->mtx);
+			Lck_Unlock(&ch->mtx);
 			if (c3 != NULL)
 				free(c3);
 			return;
@@ -183,7 +184,7 @@
 	VSL_stats->n_srcaddr_act++;
 	VTAILQ_INSERT_TAIL(&ch->head, c3, list);
 	sp->srcaddr = c3;
-	UNLOCK(&ch->mtx);
+	Lck_Unlock(&ch->mtx);
 }
 
 /*--------------------------------------------------------------------*/
@@ -198,13 +199,13 @@
 	CHECK_OBJ(sp->srcaddr, SRCADDR_MAGIC);
 	ch = sp->srcaddr->sah;
 	CHECK_OBJ(ch, SRCADDRHEAD_MAGIC);
-	LOCK(&ch->mtx);
+	Lck_Lock(&ch->mtx);
 	assert(sp->srcaddr->nref > 0);
 	sp->srcaddr->nref--;
 	if (sp->srcaddr->nref == 0)
 		VSL_stats->n_srcaddr_act--;
 	sp->srcaddr = NULL;
-	UNLOCK(&ch->mtx);
+	Lck_Unlock(&ch->mtx);
 }
 
 /*--------------------------------------------------------------------*/
@@ -228,21 +229,21 @@
 	if (sp->srcaddr != NULL) {
 		/* XXX: only report once per second ? */
 		CHECK_OBJ(sp->srcaddr, SRCADDR_MAGIC);
-		LOCK(&sp->srcaddr->sah->mtx);
+		Lck_Lock(&sp->srcaddr->sah->mtx);
 		ses_sum_acct(&sp->srcaddr->acct, a);
 		b = sp->srcaddr->acct;
-		UNLOCK(&sp->srcaddr->sah->mtx);
+		Lck_Unlock(&sp->srcaddr->sah->mtx);
 		WSL(sp->wrk, SLT_StatAddr, 0,
 		    "%s 0 %.0f %ju %ju %ju %ju %ju %ju %ju",
 		    sp->srcaddr->addr, sp->t_end - b.first,
 		    b.sess, b.req, b.pipe, b.pass,
 		    b.fetch, b.hdrbytes, b.bodybytes);
 	}
-	LOCK(&stat_mtx);
+	Lck_Lock(&stat_mtx);
 #define ACCT(foo)	VSL_stats->s_##foo += a->foo;
 #include "acct_fields.h"
 #undef ACCT
-	UNLOCK(&stat_mtx);
+	Lck_Unlock(&stat_mtx);
 	memset(a, 0, sizeof *a);
 }
 
@@ -266,9 +267,9 @@
 		 * If that queue is empty, flip queues holding the lock
 		 * and try the new unlocked queue.
 		 */
-		LOCK(&ses_mem_mtx);
+		Lck_Lock(&ses_mem_mtx);
 		ses_qp = 1 - ses_qp;
-		UNLOCK(&ses_mem_mtx);
+		Lck_Unlock(&ses_mem_mtx);
 		sm = VTAILQ_FIRST(&ses_free_mem[ses_qp]);
 	}
 	if (sm != NULL) {
@@ -316,6 +317,8 @@
 	sp->http = &sm->http[0];
 	sp->http0 = &sm->http[1];
 
+	SES_ResetBackendTimeouts(sp);
+
 	return (sp);
 }
 
@@ -343,9 +346,9 @@
 		VSL_stats->n_sess_mem--;
 		free(sm);
 	} else {
-		LOCK(&ses_mem_mtx);
+		Lck_Lock(&ses_mem_mtx);
 		VTAILQ_INSERT_HEAD(&ses_free_mem[1 - ses_qp], sm, list);
-		UNLOCK(&ses_mem_mtx);
+		Lck_Unlock(&ses_mem_mtx);
 	}
 }
 
@@ -362,8 +365,42 @@
 	for (i = 0; i < nsrchash; i++) {
 		srchash[i].magic = SRCADDRHEAD_MAGIC;
 		VTAILQ_INIT(&srchash[i].head);
-		MTX_INIT(&srchash[i].mtx);
+		Lck_New(&srchash[i].mtx);
 	}
-	MTX_INIT(&stat_mtx);
-	MTX_INIT(&ses_mem_mtx);
+	Lck_New(&stat_mtx);
+	Lck_New(&ses_mem_mtx);
+}
+
+void
+SES_ResetBackendTimeouts(struct sess *sp)
+{
+	sp->connect_timeout = params->connect_timeout;
+	sp->first_byte_timeout = params->first_byte_timeout;
+	sp->between_bytes_timeout = params->between_bytes_timeout;
+}
+
+void
+SES_InheritBackendTimeouts(struct sess *sp)
+{
+	struct backend *be;
+
+	AN(sp);
+	AN(sp->vbe);
+	AN(sp->vbe->backend);
+
+	be = sp->vbe->backend;
+	/* 
+	 * We only inherit the backend's timeout if the session timeout
+	 * has not already been set in the VCL, as the order of precedence
+	 * is parameter < backend definition < VCL.
+	 */
+	if (be->connect_timeout > 1e-3 && 
+	    sp->connect_timeout == params->connect_timeout)
+		sp->connect_timeout = be->connect_timeout;
+	if (be->first_byte_timeout > 1e-3 && 
+	    sp->first_byte_timeout == params->first_byte_timeout)
+		sp->first_byte_timeout = be->first_byte_timeout;
+	if (be->between_bytes_timeout > 1e-3 &&
+	    sp->between_bytes_timeout == params->between_bytes_timeout)
+		sp->between_bytes_timeout = be->between_bytes_timeout;
 }
diff -Nru 2.0.3/varnish-cache/bin/varnishd/cache_vcl.c trunk/varnish-cache/bin/varnishd/cache_vcl.c
--- 2.0.3/varnish-cache/bin/varnishd/cache_vcl.c	2008-10-16 07:43:08.000000000 +0200
+++ trunk/varnish-cache/bin/varnishd/cache_vcl.c	2009-01-05 14:45:27.000000000 +0100
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: cache_vcl.c 3295 2008-10-14 09:16:33Z phk $
+ * $Id: cache_vcl.c 3485 2008-12-21 17:03:37Z phk $
  *
  * Interface *to* compiled VCL code:  Loading, unloading, calling into etc.
  *
@@ -46,6 +46,7 @@
 #include "shmlog.h"
 #include "vcl.h"
 #include "cache.h"
+#include "libvcl.h"
 
 struct vcls {
 	unsigned		magic;
@@ -64,7 +65,7 @@
     VTAILQ_HEAD_INITIALIZER(vcl_head);
 
 
-static MTX			vcl_mtx;
+static struct lock		vcl_mtx;
 static struct vcls		*vcl_active; /* protected by vcl_mtx */
 
 /*--------------------------------------------------------------------*/
@@ -83,13 +84,13 @@
 VCL_Get(struct VCL_conf **vcc)
 {
 
-	LOCK(&vcl_mtx);
+	Lck_Lock(&vcl_mtx);
 	AN(vcl_active);
 	*vcc = vcl_active->conf;
 	AN(*vcc);
 	AZ((*vcc)->discard);
 	(*vcc)->busy++;
-	UNLOCK(&vcl_mtx);
+	Lck_Unlock(&vcl_mtx);
 }
 
 void
@@ -100,14 +101,14 @@
 	vc = *vcc;
 	*vcc = NULL;
 
-	LOCK(&vcl_mtx);
+	Lck_Lock(&vcl_mtx);
 	assert(vc->busy > 0);
 	vc->busy--;
 	/*
 	 * We do not garbage collect discarded VCL's here, that happens
 	 * in VCL_Poll() which is called from the CLI thread.
 	 */
-	UNLOCK(&vcl_mtx);
+	Lck_Unlock(&vcl_mtx);
 }
 
 /*--------------------------------------------------------------------*/
@@ -167,10 +168,10 @@
 	}
 	REPLACE(vcl->name, name);
 	VTAILQ_INSERT_TAIL(&vcl_head, vcl, list);
-	LOCK(&vcl_mtx);
+	Lck_Lock(&vcl_mtx);
 	if (vcl_active == NULL)
 		vcl_active = vcl;
-	UNLOCK(&vcl_mtx);
+	Lck_Unlock(&vcl_mtx);
 	cli_out(cli, "Loaded \"%s\" as \"%s\"", fn , name);
 	vcl->conf->init_func(cli);
 	VSL_stats->n_vcl++;
@@ -208,8 +209,8 @@
 	struct vcls *vcl, *vcl2;
 
 	ASSERT_CLI();
-	VTAILQ_FOREACH_SAFE(vcl, &vcl_head, list, vcl2) 
-		if (vcl->conf->discard && vcl->conf->busy == 0) 
+	VTAILQ_FOREACH_SAFE(vcl, &vcl_head, list, vcl2)
+		if (vcl->conf->discard && vcl->conf->busy == 0)
 			VCL_Nuke(vcl);
 }
 
@@ -264,9 +265,9 @@
 		cli_out(cli, "VCL '%s' unknown", av[2]);
 		return;
 	}
-	LOCK(&vcl_mtx);
+	Lck_Lock(&vcl_mtx);
 	if (vcl == vcl_active) {
-		UNLOCK(&vcl_mtx);
+		Lck_Unlock(&vcl_mtx);
 		cli_result(cli, CLIS_PARAM);
 		cli_out(cli, "VCL %s is the active VCL", av[2]);
 		return;
@@ -274,7 +275,7 @@
 	VSL_stats->n_vcl_discard++;
 	VSL_stats->n_vcl_avail--;
 	vcl->conf->discard = 1;
-	UNLOCK(&vcl_mtx);
+	Lck_Unlock(&vcl_mtx);
 	if (vcl->conf->busy == 0)
 		VCL_Nuke(vcl);
 }
@@ -292,30 +293,13 @@
 		cli_result(cli, CLIS_PARAM);
 		return;
 	}
-	LOCK(&vcl_mtx);
+	Lck_Lock(&vcl_mtx);
 	vcl_active = vcl;
-	UNLOCK(&vcl_mtx);
+	Lck_Unlock(&vcl_mtx);
 }
 
 /*--------------------------------------------------------------------*/
 
-static const char *
-vcl_handlingname(unsigned u)
-{
-
-	switch (u) {
-#define VCL_RET_MAC(a, b, c,d)	case VCL_RET_##b: return(#a);
-#define VCL_RET_MAC_E(a, b, c,d)	case VCL_RET_##b: return(#a);
-#include "vcl_returns.h"
-#undef VCL_RET_MAC
-#undef VCL_RET_MAC_E
-	default:
-		return (NULL);
-	}
-}
-
-#define VCL_RET_MAC(l,u,b,n)
-
 #define VCL_MET_MAC(func, upper, bitmap)				\
 void									\
 VCL_##func##_method(struct sess *sp)					\
@@ -323,17 +307,16 @@
 									\
 	sp->handling = 0;						\
 	sp->cur_method = VCL_MET_ ## upper;				\
-	WSP(sp, SLT_VCL_call, "%s", #func); 				\
+	WSP(sp, SLT_VCL_call, "%s", #func);				\
 	sp->vcl->func##_func(sp);					\
-	WSP(sp, SLT_VCL_return, "%s", vcl_handlingname(sp->handling));	\
+	WSP(sp, SLT_VCL_return, "%s", VCC_Return_Name(sp->handling));	\
 	sp->cur_method = 0;						\
-	assert(sp->handling & bitmap);					\
-	assert(!(sp->handling & ~bitmap));				\
+	assert((1 << sp->handling) & bitmap);				\
+	assert(!((1 << sp->handling) & ~bitmap));			\
 }
 
 #include "vcl_returns.h"
 #undef VCL_MET_MAC
-#undef VCL_RET_MAC
 
 /*--------------------------------------------------------------------*/
 
@@ -342,7 +325,7 @@
 	{ CLI_VCL_LIST,         ccf_config_list },
 	{ CLI_VCL_DISCARD,      ccf_config_discard },
 	{ CLI_VCL_USE,          ccf_config_use },
-	{ NULL }        
+	{ NULL }
 };
 
 void
@@ -350,5 +333,5 @@
 {
 
 	CLI_AddFuncs(MASTER_CLI, vcl_cmds);
-	MTX_INIT(&vcl_mtx);
+	Lck_New(&vcl_mtx);
 }
diff -Nru 2.0.3/varnish-cache/bin/varnishd/cache_vrt_acl.c trunk/varnish-cache/bin/varnishd/cache_vrt_acl.c
--- 2.0.3/varnish-cache/bin/varnishd/cache_vrt_acl.c	2008-10-16 07:43:08.000000000 +0200
+++ trunk/varnish-cache/bin/varnishd/cache_vrt_acl.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,45 +0,0 @@
-/*-
- * Copyright (c) 2006 Verdens Gang AS
- * Copyright (c) 2006-2008 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: cache_vrt_acl.c 2995 2008-07-23 15:01:54Z phk $
- *
- * Runtime support for compiled VCL programs, ACLs
- *
- */
-
-#include "config.h"
-
-#include "shmlog.h"
-#include "vrt.h"
-#include "cache.h"
-
-void
-VRT_acl_log(const struct sess *sp, const char *msg)
-{
-	WSL(sp->wrk, SLT_VCL_acl, sp->fd, msg);
-}
diff -Nru 2.0.3/varnish-cache/bin/varnishd/cache_vrt.c trunk/varnish-cache/bin/varnishd/cache_vrt.c
--- 2.0.3/varnish-cache/bin/varnishd/cache_vrt.c	2009-01-09 15:37:04.000000000 +0100
+++ trunk/varnish-cache/bin/varnishd/cache_vrt.c	2009-01-05 14:45:27.000000000 +0100
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: cache_vrt.c 3373 2008-11-10 10:12:00Z tfheen $
+ * $Id: cache_vrt.c 3485 2008-12-21 17:03:37Z phk $
  *
  * Runtime support for compiled VCL programs
  */
@@ -50,6 +50,7 @@
 #include "vrt_obj.h"
 #include "vcl.h"
 #include "cache.h"
+#include "hash_slinger.h"
 #include "cache_backend.h"
 
 void *vrt_magic_string_end = &vrt_magic_string_end;
@@ -80,6 +81,14 @@
 
 /*--------------------------------------------------------------------*/
 
+void
+VRT_acl_log(const struct sess *sp, const char *msg)
+{
+	WSL(sp->wrk, SLT_VCL_acl, sp->fd, msg);
+}
+
+/*--------------------------------------------------------------------*/
+
 static struct http *
 vrt_selecthttp(const struct sess *sp, enum gethdr_e where)
 {
@@ -136,7 +145,7 @@
 		if (b + x < e)
 			memcpy(b, h, x);
 		b += x;
-		if (b + 1 < e) 
+		if (b + 1 < e)
 			*b++ = ' ';
 	}
 	while (p != vrt_magic_string_end) {
@@ -148,7 +157,7 @@
 		b += x;
 		p = va_arg(ap, const char *);
 	}
-	if (b + 1 < e) 
+	if (b + 1 < e)
 		*b++ = '\0';
 	if (b > e) {
 		WS_Release(hp->ws, 0);
@@ -164,7 +173,8 @@
 /*--------------------------------------------------------------------*/
 
 void
-VRT_SetHdr(const struct sess *sp , enum gethdr_e where, const char *hdr, const char *p, ...)
+VRT_SetHdr(const struct sess *sp , enum gethdr_e where, const char *hdr,
+    const char *p, ...)
 {
 	struct http *hp;
 	va_list ap;
@@ -190,7 +200,8 @@
 /*--------------------------------------------------------------------*/
 
 static void
-vrt_do_string(struct worker *w, int fd, struct http *hp, int fld, const char *err, const char *p, va_list ap)
+vrt_do_string(struct worker *w, int fd, struct http *hp, int fld,
+    const char *err, const char *p, va_list ap)
 {
 	char *b;
 
@@ -288,6 +299,48 @@
 	return (atoi(sp->http->hd[HTTP_HDR_STATUS].b));
 }
 
+void
+VRT_l_bereq_connect_timeout(struct sess *sp, double num)
+{
+	CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
+	sp->connect_timeout = (num > 0 ? num : 0);
+}
+
+double
+VRT_r_bereq_connect_timeout(struct sess *sp)
+{
+	CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
+	return sp->connect_timeout;
+}
+
+void
+VRT_l_bereq_first_byte_timeout(struct sess *sp, double num)
+{
+	CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
+	sp->first_byte_timeout = (num > 0 ? num : 0);
+}
+
+double
+VRT_r_bereq_first_byte_timeout(struct sess *sp)
+{
+	CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
+	return sp->first_byte_timeout;
+}
+
+void
+VRT_l_bereq_between_bytes_timeout(struct sess *sp, double num)
+{
+	CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
+	sp->between_bytes_timeout = (num > 0 ? num : 0);
+}
+
+double
+VRT_r_bereq_between_bytes_timeout(struct sess *sp)
+{
+	CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
+	return sp->between_bytes_timeout;
+}
+
 /*--------------------------------------------------------------------*/
 
 void
@@ -295,7 +348,7 @@
 {
 
 	CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
-	assert(!(hand & (hand -1)));	/* must be power of two */
+	assert(hand < VCL_RET_MAX);
 	sp->handling = hand;
 }
 
@@ -519,7 +572,8 @@
 
 	if (sp->mysockaddr->sa_family == AF_UNSPEC)
 		AZ(getsockname(sp->fd, sp->mysockaddr, &sp->mysockaddrlen));
-	TCP_name(sp->mysockaddr, sp->mysockaddrlen, abuf, sizeof abuf, pbuf, sizeof pbuf);
+	TCP_name(sp->mysockaddr, sp->mysockaddrlen,
+	    abuf, sizeof abuf, pbuf, sizeof pbuf);
 
 	return (atoi(pbuf));
 }
@@ -531,23 +585,8 @@
 void
 VRT_l_req_hash(struct sess *sp, const char *str)
 {
-	int l;
-
-	if (str == NULL)
-		str = "";
-	l = strlen(str);
 
-	/*
-	 * XXX: handle this by bouncing sp->vcl->nhashcount when it fails
-	 * XXX: and dispose of this request either by reallocating the
-	 * XXX: hashptr (if possible) or restarting/error the request
-	 */
-	xxxassert(sp->ihashptr < sp->nhashptr);
-
-	sp->hashptr[sp->ihashptr] = str;
-	sp->hashptr[sp->ihashptr + 1] = str + l;
-	sp->ihashptr += 2;
-	sp->lhashptr += l + 1;
+	HSH_AddString(sp, str);
 }
 
 /*--------------------------------------------------------------------*/
@@ -672,7 +711,7 @@
 	*sp->http = *sp->http0;
 	WS_Reset(sp->ws, sp->ws_req);
 }
-	
+
 /*--------------------------------------------------------------------*/
 
 /*lint -e{818} sp could be const */
@@ -725,7 +764,7 @@
 void
 VRT_purge(const char *regexp, int hash)
 {
-	
+
 	if (regexp != NULL)
 		(void)BAN_Add(NULL, regexp, hash);
 }
diff -Nru 2.0.3/varnish-cache/bin/varnishd/cache_vrt_esi.c trunk/varnish-cache/bin/varnishd/cache_vrt_esi.c
--- 2.0.3/varnish-cache/bin/varnishd/cache_vrt_esi.c	2009-01-09 15:35:03.000000000 +0100
+++ trunk/varnish-cache/bin/varnishd/cache_vrt_esi.c	2009-01-05 14:45:27.000000000 +0100
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: cache_vrt_esi.c 3325 2008-10-20 08:55:24Z tfheen $
+ * $Id: cache_vrt_esi.c 3433 2008-11-25 08:37:34Z phk $
  *
  * Runtime support for compiled VCL programs ESI processing.
  *
@@ -95,7 +95,7 @@
 	char buf[256], *q;
 	txt t;
 
-	if (i == 0) 
+	if (i == 0)
 		i = p - ew->t.b;
 	if (i > 20) {
 		i = 20;
@@ -158,8 +158,9 @@
 	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: %d <%.*s>",
-	    Tlen(ew->dst), Tlen(ew->dst), ew->dst.b);
+	if (params->esi_syntax & 0x4)
+		VSL(SLT_Debug, ew->sp->fd, "AddBit: %d <%.*s>",
+		    Tlen(ew->dst), Tlen(ew->dst), ew->dst.b);
 	return(ew->eb);
 }
 
@@ -172,8 +173,9 @@
 esi_addverbatim(struct esi_work *ew)
 {
 
-	VSL(SLT_Debug, ew->sp->fd, "AddVer: %d <%.*s>",
-	    Tlen(ew->o), Tlen(ew->o), ew->o.b);
+	if (params->esi_syntax & 0x4)
+		VSL(SLT_Debug, ew->sp->fd, "AddVer: %d <%.*s>",
+		    Tlen(ew->o), Tlen(ew->o), ew->o.b);
 	if (ew->o.b != ew->dst.e)
 		memmove(ew->dst.e, ew->o.b, Tlen(ew->o));
 	ew->dst.e += Tlen(ew->o);
@@ -234,7 +236,7 @@
 
 	/* Value, if any ? */
 	*val = *in;
-	if (in->b >= in->e) 
+	if (in->b >= in->e)
 		return (1);
 
 	if (*in->b == '"') {
@@ -280,14 +282,14 @@
 	unsigned u, v;
 	struct ws *ws;
 
-	VSL(SLT_Debug, 0, "Incl \"%.*s\"", t.e - t.b, t.b);
+	VSL(SLT_Debug, ew->sp->fd, "Incl \"%.*s\"", t.e - t.b, t.b);
 	eb = esi_addbit(ew);
 	while (esi_attrib(ew, &t, &tag, &val) == 1) {
-		VSL(SLT_Debug, 0, "<%.*s> -> <%.*s>",
-		    tag.e - tag.b, tag.b,
-		    val.e - val.b, val.b);
+		if (params->esi_syntax & 0x4)
+			VSL(SLT_Debug, ew->sp->fd, "<%.*s> -> <%.*s>",
+			    tag.e - tag.b, tag.b, val.e - val.b, val.b);
 		if (Tlen(tag) != 3 || memcmp(tag.b, "src", 3))
-			continue; 
+			continue;
 		if (Tlen(val) == 0) {
 			esi_error(ew, tag.b, Tlen(tag),
 			    "ESI esi:include src attribute withou value");
@@ -351,7 +353,7 @@
 
 /*--------------------------------------------------------------------
  * Zoom over a piece of object and dike out all releveant esi: pieces.
- * The entire txt may not be processed because an interesting part 
+ * The entire txt may not be processed because an interesting part
  * could possibly span into the next chunk of storage.
  * Return value: number of bytes processed.
  */
@@ -385,7 +387,7 @@
 				if (!memcmp(p, "]]>", 3)) {
 					ew->incdata = 0;
 					p += 3;
-				} else 
+				} else
 					p++;
 			}
 			continue;
@@ -464,7 +466,7 @@
 			ew->incdata = 1;
 			p += 9;
 			continue;
-		} 
+		}
 
 		/* Ignore non esi elements, if so instructed */
 		if ((params->esi_syntax & 0x02)) {
@@ -496,8 +498,9 @@
 			r = p + 1;
 		}
 
-		VSL(SLT_Debug, ew->sp->fd, "Element: clos=%d [%.*s]",
-		    celem, q - r, r);
+		if (params->esi_syntax & 0x4)
+			VSL(SLT_Debug, ew->sp->fd, "Element: clos=%d [%.*s]",
+			    celem, q - r, r);
 
 		if (r + 9 < q && !memcmp(r, "esi:remove", 10)) {
 
@@ -510,7 +513,7 @@
 				esi_error(ew, p, 1 + q - p, ew->remflg ?
 				    "ESI 1.0 forbids nested esi:remove"
 				    : "ESI 1.0 esi:remove not opened");
-					
+
 				if (!ew->remflg) {
 					ew->o.e = p;
 					esi_addverbatim(ew);
@@ -561,7 +564,7 @@
 			continue;
 		}
 		if (r + 10 < q && !memcmp(r, "esi:include", 11)) {
-			
+
 			ew->o.e = p;
 			esi_addverbatim(ew);
 
@@ -612,8 +615,9 @@
 {
 	char *p;
 
-	VSL(SLT_Debug, ew->sp->fd, "Parse: %d <%.*s>",
-	    Tlen(ew->t), Tlen(ew->t), ew->t.b);
+	if (params->esi_syntax & 0x4)
+		VSL(SLT_Debug, ew->sp->fd, "Parse: %d <%.*s>",
+		    Tlen(ew->t), Tlen(ew->t), ew->t.b);
 	p = esi_parse2(ew);
 	assert(ew->o.b >= ew->t.b);
 	assert(ew->o.e <= ew->t.e);
@@ -723,7 +727,7 @@
 			p = NULL;
 			continue;
 		}
-		assert(t.e > t.b + u); 	/* XXX incredibly long element ? */
+		assert(t.e > t.b + u);	/* XXX incredibly long element ? */
 		memcpy(t.b, p, u);
 
 		/* Peel start off next chunk, until and including '<' */
@@ -755,7 +759,7 @@
 		ew->t = t;
 		q = esi_parse(ew);
 		assert(q == ew->t.e);	/* XXX */
-	
+
 		/* 'p' is cached starting point for next storage part */
 	}
 
@@ -799,24 +803,24 @@
 	struct esi_bit *eb;
 	struct object *obj;
 
+	WRW_Reserve(sp->wrk, &sp->fd);
 	VTAILQ_FOREACH(eb, &sp->obj->esibits, list) {
 		if (Tlen(eb->verbatim)) {
 			if (sp->http->protover >= 1.1)
-				WRK_Write(sp->wrk, eb->chunk_length, -1);
-			WRK_Write(sp->wrk, eb->verbatim.b, Tlen(eb->verbatim));
+				(void)WRW_Write(sp->wrk, eb->chunk_length, -1);
+			sp->wrk->acct.bodybytes += WRW_Write(sp->wrk,
+			    eb->verbatim.b, Tlen(eb->verbatim));
 			if (sp->http->protover >= 1.1)
-				WRK_Write(sp->wrk, "\r\n", -1);
+				(void)WRW_Write(sp->wrk, "\r\n", -1);
 		}
 		if (eb->include.b == NULL ||
 		    sp->esis >= params->max_esi_includes)
 			continue;
 
-		/*
-		 * We flush here, because the next transaction is
-		 * quite likely to take some time, so we should get
-		 * as many bits to the client as we can already
-		 */
-		WRK_Flush(sp->wrk);
+		if (WRW_FlushRelease(sp->wrk)) {
+			vca_close_session(sp, "remote closed");
+			return;
+		}
 
 		sp->esis++;
 		obj = sp->obj;
@@ -857,10 +861,12 @@
 		assert(sp->step == STP_DONE);
 		sp->esis--;
 		sp->obj = obj;
-
+		WRW_Reserve(sp->wrk, &sp->fd);
 	}
 	if (sp->esis == 0 && sp->http->protover >= 1.1)
-		WRK_Write(sp->wrk, "0\r\n\r\n", -1);
+		(void)WRW_Write(sp->wrk, "0\r\n\r\n", -1);
+	if (WRW_FlushRelease(sp->wrk))
+		vca_close_session(sp, "remote closed");
 }
 
 /*--------------------------------------------------------------------*/
diff -Nru 2.0.3/varnish-cache/bin/varnishd/cache_vrt_re.c trunk/varnish-cache/bin/varnishd/cache_vrt_re.c
--- 2.0.3/varnish-cache/bin/varnishd/cache_vrt_re.c	2008-10-16 07:43:08.000000000 +0200
+++ trunk/varnish-cache/bin/varnishd/cache_vrt_re.c	2009-01-05 14:45:27.000000000 +0100
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: cache_vrt_re.c 2792 2008-06-24 18:12:02Z phk $
+ * $Id: cache_vrt_re.c 3450 2008-12-01 21:46:20Z phk $
  *
  * Runtime support for compiled VCL programs, regexps
  */
@@ -43,7 +43,6 @@
 
 #include "shmlog.h"
 #include "vrt.h"
-#include "vsb.h"
 #include "vcl.h"
 #include "cache.h"
 
@@ -84,27 +83,9 @@
 	return (0);
 }
 
-int
-VRT_re_test(struct vsb *sb, const char *re, int sub)
-{
-	int i;
-	regex_t	t;
-	char buf[BUFSIZ];
-
-	memset(&t, 0, sizeof t);
-	i = regcomp(&t, re, REG_EXTENDED | (sub ? 0 : REG_NOSUB));
-	if (i == 0) {
-		regfree(&t);
-		return (0);
-	}
-	(void)regerror(i, &t, buf, sizeof buf);
-	vsb_printf(sb, "Regexp compilation error:\n\n%s\n\n", buf);
-	regfree(&t);
-	return (1);
-}
-
 const char *
-VRT_regsub(const struct sess *sp, int all, const char *str, void *re, const char *sub)
+VRT_regsub(const struct sess *sp, int all, const char *str, void *re,
+    const char *sub)
 {
 	regmatch_t pm[10];
 	regex_t *t;
@@ -161,7 +142,7 @@
 	if (res.b >= res.e) {
 		WS_Release(sp->http->ws, 0);
 		return (str);
-	} 
+	}
 	Tcheck(res);
 	WS_ReleaseP(sp->http->ws, res.b);
 	return (b0);
diff -Nru 2.0.3/varnish-cache/bin/varnishd/default.vcl trunk/varnish-cache/bin/varnishd/default.vcl
--- 2.0.3/varnish-cache/bin/varnishd/default.vcl	2008-10-16 07:43:08.000000000 +0200
+++ trunk/varnish-cache/bin/varnishd/default.vcl	2009-01-05 14:45:27.000000000 +0100
@@ -16,23 +16,24 @@
  *
  * 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.
+ * 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: default.vcl 3206 2008-09-19 20:49:30Z phk $
+ * $Id: default.vcl 3460 2008-12-09 13:54:09Z phk $
  *
  * The default VCL code.
  *
- * NB! You do NOT need to copy & paste all of this into your won vcl code,
- * if you do not handle one of the functions, the compiler will automaticall
- * fall back to the default code.
+ * NB! You do NOT need to copy & paste all of these functions into your
+ * own vcl code, if you do not provide a definition of one of these
+ * functions, the compiler will automatically fall back to the default
+ * code from this file.
  *
  * This code will be prefixed with a backend declaration built from the
  * -b argument.
@@ -47,25 +48,25 @@
       req.request != "OPTIONS" &&
       req.request != "DELETE") {
         /* Non-RFC2616 or CONNECT which is weird. */
-        pipe;
+        return (pipe);
     }
     if (req.request != "GET" && req.request != "HEAD") {
         /* We only deal with GET and HEAD by default */
-        pass;
+        return (pass);
     }
     if (req.http.Authorization || req.http.Cookie) {
         /* Not cacheable by default */
-        pass;
+        return (pass);
     }
-    lookup;
+    return (lookup);
 }
 
 sub vcl_pipe {
-    pipe;
+    return (pipe);
 }
 
 sub vcl_pass {
-    pass;
+    return (pass);
 }
 
 sub vcl_hash {
@@ -75,48 +76,48 @@
     } else {
         set req.hash += server.ip;
     }
-    hash;
+    return (hash);
 }
 
 sub vcl_hit {
     if (!obj.cacheable) {
-        pass;
+        return (pass);
     }
-    deliver;
+    return (deliver);
 }
 
 sub vcl_miss {
-    fetch;
+    return (fetch);
 }
 
 sub vcl_fetch {
     if (!obj.cacheable) {
-        pass;
+        return (pass);
     }
     if (obj.http.Set-Cookie) {
-        pass;
+        return (pass);
     }
     set obj.prefetch =  -30s;
-    deliver;
+    return (deliver);
 }
 
 sub vcl_deliver {
-    deliver;
+    return (deliver);
 }
 
 sub vcl_discard {
     /* XXX: Do not redefine vcl_discard{}, it is not yet supported */
-    discard;
+    return (discard);
 }
 
 sub vcl_prefetch {
     /* XXX: Do not redefine vcl_prefetch{}, it is not yet supported */
-    fetch;
+    return (fetch);
 }
 
 sub vcl_timeout {
     /* XXX: Do not redefine vcl_timeout{}, it is not yet supported */
-    discard;
+    return (discard);
 }
 
 sub vcl_error {
@@ -134,9 +135,11 @@
     <p>"} obj.response {"</p>
     <h3>Guru Meditation:</h3>
     <p>XID: "} req.xid {"</p>
-    <address><a href="http://www.varnish-cache.org/">Varnish</a></address>
+    <address>
+       <a href="http://www.varnish-cache.org/">Varnish</a>
+    </address>
   </body>
 </html>
 "};
-    deliver;
+    return (deliver);
 }
diff -Nru 2.0.3/varnish-cache/bin/varnishd/flint.lnt trunk/varnish-cache/bin/varnishd/flint.lnt
--- 2.0.3/varnish-cache/bin/varnishd/flint.lnt	2008-10-16 07:43:08.000000000 +0200
+++ trunk/varnish-cache/bin/varnishd/flint.lnt	2009-01-05 14:45:27.000000000 +0100
@@ -1,3 +1,45 @@
+
+-d__flexelint_v9__=1
+
+//-sem (pthread_mutex_lock, thread_lock)
+-sem (pthread_mutex_trylock, thread_lock)
+-sem (VBE_DropRefLocked, thread_unlock)
+-e459	// unlocked access from func-ptr
+-e454	// mutex not released (...ReleaseLocked)
+-e457	// unprotected access
+
+-esym(458, lbv_assert)	// unlocked access
+-esym(458, params)	// unlocked access
+
+-emacro(835, HTTPH)	// Info 835: A zero has been given as left argument to operator '&'
+-emacro(845, HTTPH)	// Info 845: The left argument to operator '&&' is certain to be 0
+//////////////
+-efunc(1791, pdiff)	// return last on line
+//////////////
+-efile(451, "sys/*.h")	// No include guard
+-efile(451, "machine/*.h")	// No include guard
+-efile(451, "vcl_returns.h")	// No include guard
+-efile(451, "cache_backend_poll.h")	// No include guard
+-efile(451, "steps.h")	// No include guard
+-efile(451, "http_headers.h")	// No include guard
+-efile(451, "stat_field.h")	// No include guard
+-efile(451, "acct_fields.h")	// No include guard
+-efile(451, "config.h")	// No include guard
+//////////////
+// -e458			// unprotected access
+// -e456			// merged locking paths
+-sem(vca_thread_acct, thread_mono)
+-sem(vca_epoll_thread, thread_mono)
+-sem(vca_kqueue_thread, thread_mono)
+-sem(vca_poll_thread, thread_mono)
+-sem(vca_ports_thread, thread_mono)
+-sem(exp_timer, thread_mono)
+-sem(wrk_herdtimer_thread, thread_mono)
+-sem(wrk_herder_thread, thread_mono)
+-esym(458, VSL_stats)
+-esym(458, heritage)
+-esym(458, name_key)
+//////////////
 -passes=3
 
 +libh mgt_event.h
@@ -9,16 +51,17 @@
 -emacro(736, isnan)  // isnanf
 -efile(766, ../../config.h)
 -emacro(413, offsetof)	// likely null pointer
+-emacro(527, WRONG)	// unreachable code
 
 -emacro(702, WEXITSTATUS)	// signed shift right 
-
+-efunc(525, VCC_Return_Name)	// Negative indent
 
 // -header(../../config.h)
 
 // Fix strchr() semtics, it can only return NULL if arg2 != 0
 -sem(strchr, 1p, type(1), 2n == 0 ? (@p < 1p) : (@p < 1p || @p == 0 ))
 
--sem(vsb_new, @p == malloc(1))
+-sem(vsb_new, @p == (1p ? 1p : malloc(1)))
 -sem(vsb_delete, custodial(1))
 -sem(lbv_assert, r_no)
 -sem(lbv_xxxassert, r_no)
@@ -27,6 +70,8 @@
 
 -ffc	// No automatic custody
 
+-e455	// thread lock
+-e458	// unprotected read
 -e763	// Redundant declaration for symbol '...' previously declared
 -e726	// Extraneous comma ignored
 -e728	// Symbol ... not explicitly initialized
diff -Nru 2.0.3/varnish-cache/bin/varnishd/flint.sh trunk/varnish-cache/bin/varnishd/flint.sh
--- 2.0.3/varnish-cache/bin/varnishd/flint.sh	2008-10-16 07:43:08.000000000 +0200
+++ trunk/varnish-cache/bin/varnishd/flint.sh	2009-01-05 14:45:27.000000000 +0100
@@ -10,25 +10,4 @@
 	flint.lnt \
 	*.c \
 	../../lib/libvarnish/*.c \
-	../../lib/libvcl/*.c \
-	> $T 2>&1
-
-for t in Error Warning Info Note
-do
-	sed -n "/$t [0-9][0-9][0-9]:/s/.*\($t [0-9][0-9][0-9]\).*/\1/p" $T
-done | awk '
-$2 == 830	{ next }
-$2 == 831	{ next }
-	{
-	i=$2"_"$1
-	h[i]++
-	n++
-	}
-END	{
-	printf "%5d %s\n", n, "Total"
-	for (i in h)
-		printf "%5d %s\n", h[i], i
-	}
-' | sort -rn
-
-cat $T
+	../../lib/libvcl/*.c 
diff -Nru 2.0.3/varnish-cache/bin/varnishd/hash_classic.c trunk/varnish-cache/bin/varnishd/hash_classic.c
--- 2.0.3/varnish-cache/bin/varnishd/hash_classic.c	2008-10-16 07:43:08.000000000 +0200
+++ trunk/varnish-cache/bin/varnishd/hash_classic.c	2009-01-05 14:45:27.000000000 +0100
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: hash_classic.c 2955 2008-07-19 09:24:07Z phk $
+ * $Id: hash_classic.c 3450 2008-12-01 21:46:20Z phk $
  *
  * A classic bucketed hash
  */
@@ -40,25 +40,15 @@
 
 #include "shmlog.h"
 #include "cache.h"
+#include "hash_slinger.h"
 
 /*--------------------------------------------------------------------*/
 
-struct hcl_entry {
-	unsigned		magic;
-#define HCL_ENTRY_MAGIC		0x0ba707bf
-	VTAILQ_ENTRY(hcl_entry)	list;
-	struct hcl_hd		*head;
-	struct objhead		*oh;
-	unsigned		refcnt;
-	unsigned		digest;
-	unsigned		hash;
-};
-
 struct hcl_hd {
 	unsigned		magic;
 #define HCL_HEAD_MAGIC		0x0f327016
-	VTAILQ_HEAD(, hcl_entry)	head;
-	MTX			mtx;
+	VTAILQ_HEAD(, objhead)	head;
+	struct lock		mtx;
 };
 
 static unsigned			hcl_nhash = 16383;
@@ -110,7 +100,7 @@
 
 	for (u = 0; u < hcl_nhash; u++) {
 		VTAILQ_INIT(&hcl_head[u].head);
-		MTX_INIT(&hcl_head[u].mtx);
+		Lck_New(&hcl_head[u].mtx);
 		hcl_head[u].magic = HCL_HEAD_MAGIC;
 	}
 }
@@ -127,17 +117,14 @@
 static struct objhead *
 hcl_lookup(const struct sess *sp, struct objhead *noh)
 {
-	struct objhead *roh;
-	struct hcl_entry *he, *he2;
+	struct objhead *oh;
 	struct hcl_hd *hp;
-	unsigned u1, digest, r;
+	unsigned u1, digest;
 	unsigned u, v;
 	int i;
 
 	CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
-	CHECK_OBJ_NOTNULL(sp->wrk, WORKER_MAGIC);
-	CHECK_OBJ_NOTNULL(sp->http, HTTP_MAGIC);
-	CHECK_OBJ_ORNULL(noh, OBJHEAD_MAGIC);
+	CHECK_OBJ_NOTNULL(noh, OBJHEAD_MAGIC);
 
 	digest = ~0U;
 	for (u = 0; u < sp->ihashptr; u += 2) {
@@ -148,73 +135,39 @@
 
 	u1 = digest % hcl_nhash;
 	hp = &hcl_head[u1];
-	he2 = NULL;
 
-	for (r = 0; r < 2; r++ ) {
-		LOCK(&hp->mtx);
-		VTAILQ_FOREACH(he, &hp->head, list) {
-			CHECK_OBJ_NOTNULL(he, HCL_ENTRY_MAGIC);
-			if (sp->lhashptr < he->oh->hashlen)
-				continue;
-			if (sp->lhashptr > he->oh->hashlen)
-				break;
-			if (he->digest < digest)
-				continue;
-			if (he->digest > digest)
-				break;
-			i = HSH_Compare(sp, he->oh);
-			if (i < 0)
-				continue;
-			if (i > 0)
-				break;
-			he->refcnt++;
-			roh = he->oh;
-			UNLOCK(&hp->mtx);
-			/*
-			 * If we loose the race, we need to clean up
-			 * the work we did for our second attempt.
-			 */
-			if (he2 != NULL)
-				free(he2);
-			if (noh != NULL && noh->hash != NULL) {
-				free(noh->hash);
-				noh->hash = NULL;
-			}
-			return (roh);
-		}
-		if (noh == NULL) {
-			UNLOCK(&hp->mtx);
-			return (NULL);
-		}
-		if (he2 != NULL) {
-			if (he != NULL)
-				VTAILQ_INSERT_BEFORE(he, he2, list);
-			else
-				VTAILQ_INSERT_TAIL(&hp->head, he2, list);
-			he2->refcnt++;
-			noh = he2->oh;
-			UNLOCK(&hp->mtx);
-			return (noh);
-		}
-		UNLOCK(&hp->mtx);
-
-		he2 = calloc(sizeof *he2, 1);
-		XXXAN(he2);
-		he2->magic = HCL_ENTRY_MAGIC;
-		he2->oh = noh;
-		he2->digest = digest;
-		he2->hash = u1;
-		he2->head = hp;
-
-		noh->hashpriv = he2;
-		AZ(noh->hash);
-		noh->hash = malloc(sp->lhashptr);
-		XXXAN(noh->hash);
-		noh->hashlen = sp->lhashptr;
-		HSH_Copy(sp, noh);
+	Lck_Lock(&hp->mtx);
+	VTAILQ_FOREACH(oh, &hp->head, hoh_list) {
+		if (sp->lhashptr < oh->hashlen)
+			continue;
+		if (sp->lhashptr > oh->hashlen)
+			break;
+		if (oh->hoh_digest < digest)
+			continue;
+		if (oh->hoh_digest > digest)
+			break;
+		i = HSH_Compare(sp, oh);
+		if (i < 0)
+			continue;
+		if (i > 0)
+			break;
+		oh->refcnt++;
+		Lck_Unlock(&hp->mtx);
+		return (oh);
 	}
-	assert(he2 == NULL);		/* FlexeLint */
-	INCOMPL();
+
+	if (oh != NULL)
+		VTAILQ_INSERT_BEFORE(oh, noh, hoh_list);
+	else
+		VTAILQ_INSERT_TAIL(&hp->head, noh, hoh_list);
+
+	noh->hoh_digest = digest;
+	noh->hoh_head = hp;
+
+	HSH_Copy(sp, noh);
+
+	Lck_Unlock(&hp->mtx);
+	return (noh);
 }
 
 /*--------------------------------------------------------------------
@@ -222,34 +175,28 @@
  */
 
 static int
-hcl_deref(const struct objhead *oh)
+hcl_deref(struct objhead *oh)
 {
-	struct hcl_entry *he;
 	struct hcl_hd *hp;
+	int ret;
 
 	CHECK_OBJ_NOTNULL(oh, OBJHEAD_MAGIC);
-	CAST_OBJ_NOTNULL(he, oh->hashpriv, HCL_ENTRY_MAGIC);
-	hp = he->head;
-	CHECK_OBJ_NOTNULL(hp, HCL_HEAD_MAGIC);
-	assert(he->refcnt > 0);
-	assert(he->hash < hcl_nhash);
-	assert(hp == &hcl_head[he->hash]);
-	LOCK(&hp->mtx);
-	if (--he->refcnt == 0)
-		VTAILQ_REMOVE(&hp->head, he, list);
-	else
-		he = NULL;
-	UNLOCK(&hp->mtx);
-	if (he == NULL)
-		return (1);
-	free(he);
-	return (0);
+	CAST_OBJ_NOTNULL(hp, oh->hoh_head, HCL_HEAD_MAGIC);
+	assert(oh->refcnt > 0);
+	Lck_Lock(&hp->mtx);
+	if (--oh->refcnt == 0) {
+		VTAILQ_REMOVE(&hp->head, oh, hoh_list);
+		ret = 0;
+	} else 
+		ret = 1;
+	Lck_Unlock(&hp->mtx);
+	return (ret);
 }
 
 /*--------------------------------------------------------------------*/
 
 struct hash_slinger hcl_slinger = {
-	.magic	= 	SLINGER_MAGIC,
+	.magic	=	SLINGER_MAGIC,
 	.name	=	"classic",
 	.init	=	hcl_init,
 	.start	=	hcl_start,
diff -Nru 2.0.3/varnish-cache/bin/varnishd/hash_critbit.c trunk/varnish-cache/bin/varnishd/hash_critbit.c
--- 2.0.3/varnish-cache/bin/varnishd/hash_critbit.c	1970-01-01 01:00:00.000000000 +0100
+++ trunk/varnish-cache/bin/varnishd/hash_critbit.c	2009-01-05 14:45:27.000000000 +0100
@@ -0,0 +1,455 @@
+/*-
+ * Copyright (c) 2008 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$
+ *
+ * A Crit Bit tree based hash
+ */
+
+#undef PHK
+
+#include "config.h"
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "shmlog.h"
+#include "cache.h"
+#include "hash_slinger.h"
+
+static struct lock hcb_mtx;
+
+static VTAILQ_HEAD(,objhead)	laylow = VTAILQ_HEAD_INITIALIZER(laylow);
+
+/**********************************************************************
+ * Table for finding out how many bits two bytes have in common,
+ * counting from the MSB towards the LSB.
+ * ie: 
+ *	hcb_bittbl[0x01 ^ 0x22] == 2
+ *	hcb_bittbl[0x10 ^ 0x0b] == 3
+ * 
+ */
+
+static unsigned char hcb_bittbl[256];
+
+static unsigned char
+hcb_bits(unsigned char x, unsigned char y)
+{
+	return hcb_bittbl[x ^ y];
+}
+
+static void
+hcb_build_bittbl(void)
+{
+	unsigned char x;
+	unsigned y;
+
+	y = 0;
+	for (x = 0; x < 8; x++)
+		for (; y < (1U << x); y++)
+			hcb_bittbl[y] = 8 - x;
+
+	/* Quick asserts for sanity check */
+	assert(hcb_bits(0x34, 0x34) == 8);
+	assert(hcb_bits(0xaa, 0x55) == 0);
+	assert(hcb_bits(0x01, 0x22) == 2);
+	assert(hcb_bits(0x10, 0x0b) == 3);
+}
+
+/**********************************************************************
+ * For space reasons we overload the two pointers with two different
+ * kinds of of pointers.  We cast them to uintptr_t's and abuse the
+ * low two bits to tell them apart, assuming that Varnish will never
+ * run on machines with less than 32bit alignment.
+ *
+ * Asserts will explode if these assumptions are not met.
+ */
+
+struct hcb_y {
+	unsigned short	critbit;
+	unsigned char	ptr;
+	unsigned char	bitmask;
+	uintptr_t	leaf[2];
+};
+
+#define HCB_BIT_NODE		(1<<0)
+#define HCB_BIT_Y		(1<<1)
+
+struct hcb_root {
+	uintptr_t	origo;
+	unsigned	cmps;
+};
+
+static struct hcb_root	hcb_root;
+
+/**********************************************************************
+ * Pointer accessor functions
+ */
+static int
+hcb_is_node(uintptr_t u)
+{
+
+	return (u & HCB_BIT_NODE);
+}
+
+static int
+hcb_is_y(uintptr_t u)
+{
+
+	return (u & HCB_BIT_Y);
+}
+
+static uintptr_t
+hcb_r_node(struct objhead *n)
+{
+
+	assert(!((uintptr_t)n & (HCB_BIT_NODE|HCB_BIT_Y)));
+	return (HCB_BIT_NODE | (uintptr_t)n);
+}
+
+static struct objhead *
+hcb_l_node(uintptr_t u)
+{
+
+	assert(u & HCB_BIT_NODE);
+	assert(!(u & HCB_BIT_Y));
+	return ((struct objhead *)(u & ~HCB_BIT_NODE));
+}
+
+static uintptr_t
+hcb_r_y(struct hcb_y *y)
+{
+
+	assert(!((uintptr_t)y & (HCB_BIT_NODE|HCB_BIT_Y)));
+	return (HCB_BIT_Y | (uintptr_t)y);
+}
+
+static struct hcb_y *
+hcb_l_y(uintptr_t u)
+{
+
+	assert(!(u & HCB_BIT_NODE));
+	assert(u & HCB_BIT_Y);
+	return ((struct hcb_y *)(u & ~HCB_BIT_Y));
+}
+
+/**********************************************************************/
+
+static unsigned
+hcb_crit_bit(const struct objhead *oh1, const struct objhead *oh2, struct hcb_y *y)
+{
+	unsigned char u, r;
+
+	for (u = 0; u < DIGEST_LEN && oh1->digest[u] == oh2->digest[u]; u++)
+		;
+	assert(u < DIGEST_LEN);
+	r = hcb_bits(oh1->digest[u], oh2->digest[u]);
+	y->ptr = u;
+	y->bitmask = 0x80 >> r;
+	y->critbit = u * 8 + r;
+	return (y->critbit);
+}
+
+/**********************************************************************/
+
+static struct objhead *
+hcb_insert(struct hcb_root *root, struct objhead *oh, int has_lock)
+{
+	uintptr_t *p;
+	struct hcb_y *y, *y2;
+	struct objhead *oh2;
+	unsigned s, s2;
+
+
+	p = &root->origo;
+	if (*p == 0) {
+		if (!has_lock)
+			return (NULL);
+		*p = hcb_r_node(oh);
+		return (oh);
+	}
+
+	while(hcb_is_y(*p)) {
+		y = hcb_l_y(*p);
+		if (y->ptr > DIGEST_LEN)
+			s = 0;
+		else
+			s = (oh->digest[y->ptr] & y->bitmask) != 0;
+		assert(s < 2);
+		root->cmps++;
+		p = &y->leaf[s];
+	}
+
+	assert(hcb_is_node(*p));
+
+	/* We found a node, does it match ? */
+	oh2 = hcb_l_node(*p);
+	if (!memcmp(oh2->digest, oh->digest, DIGEST_LEN))
+		return (oh2);
+
+	if (!has_lock)
+		return (NULL);
+
+	/* Insert */
+
+	y2 = (void*)&oh->u;
+	memset(y2, 0, sizeof *y2);
+	(void)hcb_crit_bit(oh, hcb_l_node(*p), y2);
+	s2 = (oh->digest[y2->ptr] & y2->bitmask) != 0;
+	assert(s2 < 2);
+	y2->leaf[s2] = hcb_r_node(oh);
+	s2 = 1-s2;
+
+	p = &root->origo;
+	assert(*p != 0);
+
+	while(hcb_is_y(*p)) {
+		y = hcb_l_y(*p);
+		if (y->critbit > y2->critbit)
+			break;
+		if (y->ptr > DIGEST_LEN)
+			s = 0;
+		else
+			s = (oh->digest[y->ptr] & y->bitmask) != 0;
+		assert(s < 2);
+		root->cmps++;
+		p = &y->leaf[s];
+	}
+	y2->leaf[s2] = *p;
+	*p = hcb_r_y(y2);
+	return(oh);
+}
+
+/**********************************************************************/
+
+static void
+hcb_delete(struct hcb_root *r, struct objhead *oh)
+{
+	struct hcb_y *y;
+	uintptr_t *p;
+	unsigned s;
+
+	if (r->origo == hcb_r_node(oh)) {
+		r->origo = 0;
+		return;
+	}
+	p = &r->origo;
+	assert(hcb_is_y(*p));
+	
+	y = NULL;
+	while(1) {
+		assert(hcb_is_y(*p));
+		y = hcb_l_y(*p);
+		if (y->ptr > DIGEST_LEN)
+			s = 0;
+		else
+			s = (oh->digest[y->ptr] & y->bitmask) != 0;
+		assert(s < 2);
+		if (y->leaf[s] == hcb_r_node(oh)) {
+			*p = y->leaf[1 - s];
+			y->leaf[0] = 0;
+			y->leaf[1] = 0;
+			return;
+		}
+		r->cmps++;
+		p = &y->leaf[s];
+	}
+}
+
+/**********************************************************************/
+#ifdef PHK
+static void
+dumptree(uintptr_t p, int indent, FILE *fd)
+{
+	int i;
+	const struct objhead *oh;
+	const struct hcb_y *y;
+
+	if (p == 0)
+		return;
+	if (hcb_is_node(p)) {
+		oh = hcb_l_node(p);
+		fprintf(fd, "%*.*sN %d r%u <%02x%02x%02x...> <%s>\n",
+		    indent, indent, "", indent / 2, oh->refcnt,
+		    oh->digest[0], oh->digest[1], oh->digest[2],
+		    oh->hash);
+		return;
+	}
+	assert(hcb_is_y(p));
+	y = hcb_l_y(p);
+	fprintf(fd, "%*.*sY c %u p %u b %02x i %d\n",
+	    indent, indent, "",
+	    y->critbit, y->ptr, y->bitmask, indent / 2);
+	indent += 2;
+	for (i = 0; i < 2; i++)
+		dumptree(y->leaf[i], indent, fd);
+}
+
+static void
+dump(const struct hcb_root *root, FILE *fd)
+{
+	fprintf(fd, "-------------\n");
+	dumptree(root->origo, 0, fd);
+	fprintf(fd, "-------------\n");
+	(void)fflush(fd);
+}
+#endif
+
+
+/**********************************************************************/
+
+#define COOL_DURATION	15		/* seconds */
+
+static void *
+hcb_cleaner(void *priv)
+{
+	struct objhead *oh, *oh2;
+	struct hcb_y *y;
+
+	THR_SetName("hcb_cleaner");
+	(void)priv;
+	while (1) {
+		(void)sleep(1);
+		Lck_Lock(&hcb_mtx);
+		VTAILQ_FOREACH_SAFE(oh, &laylow, coollist, oh2) {
+			if (oh->hash != NULL) {
+				free(oh->hash);
+				oh->hash = NULL;
+			}
+			y = (void *)&oh->u;
+			if (y->leaf[0] || y->leaf[1])
+				continue;
+			if (++oh->refcnt > COOL_DURATION) {
+				VTAILQ_REMOVE(&laylow, oh, coollist);
+#ifdef PHK
+				fprintf(stderr, "OH %p is cold enough\n", oh);
+#endif
+				free(oh);
+				VSL_stats->n_objecthead--;
+			}
+		}
+		Lck_Unlock(&hcb_mtx);
+	}
+}
+
+/**********************************************************************/
+
+static void
+hcb_start(void)
+{
+	struct objhead *oh = NULL;
+	pthread_t tp;
+
+	(void)oh;
+	AZ(pthread_create(&tp, NULL, hcb_cleaner, NULL));
+	assert(params->hash_sha256);
+	assert(sizeof(struct hcb_y) <= sizeof(oh->u));
+	memset(&hcb_root, 0, sizeof hcb_root);
+	hcb_build_bittbl();
+	Lck_New(&hcb_mtx);
+}
+
+static int
+hcb_deref(struct objhead *oh)
+{
+	int r;
+
+	r = 1;
+	CHECK_OBJ_NOTNULL(oh, OBJHEAD_MAGIC);
+	Lck_Lock(&oh->mtx);
+	if (--oh->refcnt == 0) {
+		Lck_Lock(&hcb_mtx);
+		hcb_delete(&hcb_root, oh);
+		VTAILQ_INSERT_TAIL(&laylow, oh, coollist);
+		Lck_Unlock(&hcb_mtx);
+	}
+	Lck_Unlock(&oh->mtx);
+#ifdef PHK
+	fprintf(stderr, "hcb_defef %d %d <%s>\n", __LINE__, r, oh->hash);
+	dump(&hcb_root, stderr);
+#endif
+	return (r);
+}
+
+static struct objhead *
+hcb_lookup(const struct sess *sp, struct objhead *noh)
+{
+	struct objhead *oh;
+	unsigned u;
+	
+	assert(params->hash_sha256);
+	oh =  hcb_insert(&hcb_root, noh, 0);
+	if (oh != NULL) {
+		/* Assert that we didn't muck with the tree without lock */
+		assert(oh != noh);
+		Lck_Lock(&oh->mtx);
+		u = oh->refcnt;
+		if (u)
+			oh->refcnt++;
+		Lck_Unlock(&oh->mtx);
+		if (u) {
+			VSL_stats->hcb_nolock++;
+			return (oh);
+		}
+	}
+
+	/*
+	 * Try again, holding lock and fully ready objhead, so that if
+	 * somebody else beats us back, they do not get surprised.
+	 */
+	HSH_Copy(sp, noh);
+	Lck_Lock(&hcb_mtx);
+	oh =  hcb_insert(&hcb_root, noh, 1);
+	if (oh == noh) {
+		VSL_stats->hcb_insert++;
+#ifdef PHK
+		fprintf(stderr, "hcb_lookup %d\n", __LINE__);
+		dump(&hcb_root, stderr);
+#endif
+	} else {
+		free(noh->hash);
+		noh->hash = NULL;
+		noh->hashlen = 0;
+		VSL_stats->hcb_lock++;
+#ifdef PHK
+		fprintf(stderr, "hcb_lookup %d\n", __LINE__);
+		dump(&hcb_root, stderr);
+#endif
+	}
+	Lck_Unlock(&hcb_mtx);
+	return (oh);
+}
+
+
+struct hash_slinger hcb_slinger = {
+	.magic  =       SLINGER_MAGIC,
+	.name   =       "critbit",
+	.start  =       hcb_start,
+	.lookup =       hcb_lookup,
+	.deref  =       hcb_deref,
+};
diff -Nru 2.0.3/varnish-cache/bin/varnishd/hash_simple_list.c trunk/varnish-cache/bin/varnishd/hash_simple_list.c
--- 2.0.3/varnish-cache/bin/varnishd/hash_simple_list.c	2008-10-16 07:43:08.000000000 +0200
+++ trunk/varnish-cache/bin/varnishd/hash_simple_list.c	2009-01-05 14:45:27.000000000 +0100
@@ -26,32 +26,25 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: hash_simple_list.c 2955 2008-07-19 09:24:07Z phk $
+ * $Id: hash_simple_list.c 3450 2008-12-01 21:46:20Z phk $
  *
  * This is the reference hash(/lookup) implementation
  */
 
 #include "config.h"
 
-#include <sys/types.h>
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
 #include "shmlog.h"
 #include "cache.h"
+#include "hash_slinger.h"
 
 /*--------------------------------------------------------------------*/
 
-struct hsl_entry {
-	VTAILQ_ENTRY(hsl_entry)	list;
-	struct objhead		*obj;
-	unsigned		refcnt;
-};
-
-static VTAILQ_HEAD(, hsl_entry)	hsl_head = VTAILQ_HEAD_INITIALIZER(hsl_head);
-static MTX hsl_mutex;
+static VTAILQ_HEAD(, objhead)	hsl_head = VTAILQ_HEAD_INITIALIZER(hsl_head);
+static struct lock hsl_mtx;
 
 /*--------------------------------------------------------------------
  * The ->init method is called during process start and allows
@@ -62,7 +55,7 @@
 hsl_start(void)
 {
 
-	MTX_INIT(&hsl_mutex);
+	Lck_New(&hsl_mtx);
 }
 
 /*--------------------------------------------------------------------
@@ -73,44 +66,34 @@
  */
 
 static struct objhead *
-hsl_lookup(const struct sess *sp, struct objhead *nobj)
+hsl_lookup(const struct sess *sp, struct objhead *noh)
 {
-	struct hsl_entry *he, *he2;
+	struct objhead *oh;
 	int i;
 
-	LOCK(&hsl_mutex);
-	VTAILQ_FOREACH(he, &hsl_head, list) {
-		i = HSH_Compare(sp, he->obj);
+	CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
+	CHECK_OBJ_NOTNULL(noh, OBJHEAD_MAGIC);
+	Lck_Lock(&hsl_mtx);
+	VTAILQ_FOREACH(oh, &hsl_head, hoh_list) {
+		i = HSH_Compare(sp, oh);
 		if (i < 0)
 			continue;
 		if (i > 0)
 			break;
-		he->refcnt++;
-		nobj = he->obj;
-		UNLOCK(&hsl_mutex);
-		return (nobj);
+		oh->refcnt++;
+		Lck_Unlock(&hsl_mtx);
+		return (oh);
 	}
-	if (nobj == NULL) {
-		UNLOCK(&hsl_mutex);
-		return (NULL);
-	}
-	he2 = calloc(sizeof *he2, 1);
-	XXXAN(he2);
-	he2->obj = nobj;
-	he2->refcnt = 1;
-
-	nobj->hashpriv = he2;
-	nobj->hash = malloc(sp->lhashptr);
-	XXXAN(nobj->hash);
-	nobj->hashlen = sp->lhashptr;
-	HSH_Copy(sp, nobj);
 
-	if (he != NULL)
-		VTAILQ_INSERT_BEFORE(he, he2, list);
+	if (oh != NULL)
+		VTAILQ_INSERT_BEFORE(oh, noh, hoh_list);
 	else
-		VTAILQ_INSERT_TAIL(&hsl_head, he2, list);
-	UNLOCK(&hsl_mutex);
-	return (nobj);
+		VTAILQ_INSERT_TAIL(&hsl_head, noh, hoh_list);
+
+	HSH_Copy(sp, noh);
+
+	Lck_Unlock(&hsl_mtx);
+	return (noh);
 }
 
 /*--------------------------------------------------------------------
@@ -118,21 +101,17 @@
  */
 
 static int
-hsl_deref(const struct objhead *obj)
+hsl_deref(struct objhead *oh)
 {
-	struct hsl_entry *he;
 	int ret;
 
-	AN(obj->hashpriv);
-	he = obj->hashpriv;
-	LOCK(&hsl_mutex);
-	if (--he->refcnt == 0) {
-		VTAILQ_REMOVE(&hsl_head, he, list);
-		free(he);
+	Lck_Lock(&hsl_mtx);
+	if (--oh->refcnt == 0) {
+		VTAILQ_REMOVE(&hsl_head, oh, hoh_list);
 		ret = 0;
 	} else
 		ret = 1;
-	UNLOCK(&hsl_mutex);
+	Lck_Unlock(&hsl_mtx);
 	return (ret);
 }
 
@@ -143,5 +122,5 @@
 	.name	=	"simple",
 	.start	=	hsl_start,
 	.lookup =	hsl_lookup,
-	.deref 	=	hsl_deref,
+	.deref	=	hsl_deref,
 };
diff -Nru 2.0.3/varnish-cache/bin/varnishd/hash_slinger.h trunk/varnish-cache/bin/varnishd/hash_slinger.h
--- 2.0.3/varnish-cache/bin/varnishd/hash_slinger.h	2008-10-16 07:43:08.000000000 +0200
+++ trunk/varnish-cache/bin/varnishd/hash_slinger.h	2009-01-05 14:45:27.000000000 +0100
@@ -26,15 +26,17 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: hash_slinger.h 2955 2008-07-19 09:24:07Z phk $
+ * $Id: hash_slinger.h 3464 2008-12-18 10:04:15Z phk $
  */
 
 struct sess;
+struct object;
 
 typedef void hash_init_f(int ac, char * const *av);
 typedef void hash_start_f(void);
-typedef struct objhead *hash_lookup_f(const struct sess *sp, struct objhead *nobj);
-typedef int hash_deref_f(const struct objhead *obj);
+typedef struct objhead *
+    hash_lookup_f(const struct sess *sp, struct objhead *nobj);
+typedef int hash_deref_f(struct objhead *obj);
 
 struct hash_slinger {
 	unsigned		magic;
@@ -45,3 +47,58 @@
 	hash_lookup_f		*lookup;
 	hash_deref_f		*deref;
 };
+
+/* cache_hash.c */
+void HSH_Prealloc(struct sess *sp);
+void HSH_Freestore(struct object *o);
+int HSH_Compare(const struct sess *sp, const struct objhead *o);
+void HSH_Copy(const struct sess *sp, struct objhead *o);
+struct object *HSH_Lookup(struct sess *sp);
+void HSH_Unbusy(const struct sess *sp);
+void HSH_Ref(struct object *o);
+void HSH_Deref(struct object **o);
+void HSH_Drop(struct sess *sp);
+double HSH_Grace(double g);
+void HSH_Init(void);
+void HSH_AddString(struct sess *sp, const char *str);
+void HSH_Prepare(struct sess *sp, unsigned hashcount);
+
+
+#ifdef VARNISH_CACHE_CHILD
+
+#define DIGEST_LEN		32
+
+struct objhead {
+	unsigned		magic;
+#define OBJHEAD_MAGIC		0x1b96615d
+
+	struct lock		mtx;
+	unsigned		refcnt;
+	VTAILQ_HEAD(,object)	objects;
+	char			*hash;
+	unsigned		hashlen;
+	unsigned char		digest[DIGEST_LEN];
+	union {
+		VTAILQ_HEAD(, sess)	__u_waitinglist;
+		VTAILQ_ENTRY(objhead)	__u_coollist;
+	} __u;
+#define waitinglist __u.__u_waitinglist
+#define coollist __u.__u_coollist
+
+	/*----------------------------------------------------
+	 * The fields below are for the sole private use of
+	 * the hash implementation(s).
+	 */
+	union {
+		void		*filler[3];
+		struct {
+			VTAILQ_ENTRY(objhead)	u_n_hoh_list;
+			void			*u_n_hoh_head;
+			unsigned		u_n_hoh_digest;
+		} n;
+	} u;
+#define hoh_list u.n.u_n_hoh_list
+#define hoh_head u.n.u_n_hoh_head
+#define hoh_digest u.n.u_n_hoh_digest
+};
+#endif /* VARNISH_CACHE_CHILD */
diff -Nru 2.0.3/varnish-cache/bin/varnishd/heritage.h trunk/varnish-cache/bin/varnishd/heritage.h
--- 2.0.3/varnish-cache/bin/varnishd/heritage.h	2008-11-10 11:09:32.000000000 +0100
+++ trunk/varnish-cache/bin/varnishd/heritage.h	2009-01-05 14:45:27.000000000 +0100
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: heritage.h 3370 2008-11-10 10:09:31Z tfheen $
+ * $Id: heritage.h 3437 2008-11-25 11:09:38Z phk $
  *
  * This file contains the heritage passed when mgt forks cache
  */
@@ -77,7 +77,7 @@
 
 	/* TTL used for lack of anything better */
 	unsigned		default_ttl;
-	
+
 	/* TTL used for synthesized error pages */
 	unsigned		err_ttl;
 
@@ -98,6 +98,8 @@
 	unsigned		obj_workspace;
 	unsigned		shm_workspace;
 
+	unsigned		shm_reclen;
+
 	/* Acceptor hints */
 	unsigned		sess_timeout;
 	unsigned		pipe_timeout;
@@ -154,7 +156,11 @@
 	unsigned		cache_vbe_conns;
 
 	/* Default connection_timeout */
-	unsigned		connect_timeout;
+	double			connect_timeout;
+
+	/* Read timeouts for backend */
+	double			first_byte_timeout;
+	double	 		between_bytes_timeout;
 
 	/* How long to linger on sessions */
 	unsigned		session_linger;
@@ -168,6 +174,9 @@
 	/* Default grace period */
 	unsigned		default_grace;
 
+	/* Use sha256 hasing */
+	unsigned		hash_sha256;
+
 	/* Log hash string to shm */
 	unsigned		log_hash;
 
@@ -193,4 +202,5 @@
 
 void child_main(void);
 
-int varnish_instance(const char *n_arg, char *name, size_t namelen, char *dir, size_t dirlen);
+int varnish_instance(const char *n_arg, char *name, size_t namelen,
+    char *dir, size_t dirlen);
diff -Nru 2.0.3/varnish-cache/bin/varnishd/instance.c trunk/varnish-cache/bin/varnishd/instance.c
--- 2.0.3/varnish-cache/bin/varnishd/instance.c	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/bin/varnishd/instance.c	2008-11-06 12:22:01.000000000 +0100
@@ -25,7 +25,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: instance.c 3072 2008-08-11 07:47:24Z phk $
+ * $Id: instance.c 3336 2008-10-20 18:47:24Z des $
  */
 
 #include "config.h"
@@ -34,13 +34,11 @@
 #include <stdio.h>
 #include <unistd.h>
 
-#include "config.h"
 #include "varnishapi.h"
 
 int
 varnish_instance(const char *n_arg,
-    char *name, size_t namelen,
-    char *dir, size_t dirlen)
+    char *name, size_t namelen, char *dir, size_t dirlen)
 {
 	size_t len;
 
diff -Nru 2.0.3/varnish-cache/bin/varnishd/Makefile.am trunk/varnish-cache/bin/varnishd/Makefile.am
--- 2.0.3/varnish-cache/bin/varnishd/Makefile.am	2008-10-16 07:43:08.000000000 +0200
+++ trunk/varnish-cache/bin/varnishd/Makefile.am	2009-01-05 14:45:27.000000000 +0100
@@ -1,4 +1,4 @@
-# $Id: Makefile.am 3216 2008-09-24 12:41:29Z tfheen $
+# $Id: Makefile.am 3454 2008-12-03 10:49:34Z phk $
 
 INCLUDES = -I$(top_srcdir)/include
 
@@ -27,6 +27,7 @@
 	cache_http.c \
 	cache_httpconn.c \
 	cache_main.c \
+	cache_lck.c \
 	cache_panic.c \
 	cache_pipe.c \
 	cache_pool.c \
@@ -35,16 +36,17 @@
 	cache_vary.c \
 	cache_vcl.c \
 	cache_vrt.c \
-	cache_vrt_acl.c \
 	cache_vrt_esi.c \
 	cache_vrt_re.c \
 	cache_ws.c \
 	hash_classic.c \
+	hash_critbit.c \
 	hash_simple_list.c \
 	instance.c \
 	mgt_child.c \
 	mgt_cli.c \
 	mgt_param.c \
+	mgt_pool.c \
 	mgt_vcc.c \
 	rfc2616.c \
 	shmlog.c \
@@ -80,7 +82,7 @@
 	$(top_builddir)/lib/libvarnishcompat/libvarnishcompat.la \
 	$(top_builddir)/lib/libvcl/libvcl.la \
 	@JEMALLOC_LDADD@ \
-	${DL_LIBS} ${PTHREAD_LIBS} ${NET_LIBS} ${LIBM}
+	${DL_LIBS} ${PTHREAD_LIBS} ${NET_LIBS} ${LIBM} ${LIBUMEM}
 
 EXTRA_DIST = default.vcl
 DISTCLEANFILES = default_vcl.h
@@ -89,8 +91,7 @@
 # Turn the default.vcl file into a C-string we can include in the program.
 #
 default_vcl.h:	default.vcl Makefile
-	sed -e 's/"/\\"/g' -e 's/$$/\\n"/' -e 's/^/	"/' $(srcdir)/default.vcl > $@
+	sed -e 's/"/\\"/g' -e 's/$$/\\n"/' -e 's/^/ "/' $(srcdir)/default.vcl > $@
 
 # Explicitly record dependency
 mgt_vcc.c:	default_vcl.h
-
diff -Nru 2.0.3/varnish-cache/bin/varnishd/mgt_child.c trunk/varnish-cache/bin/varnishd/mgt_child.c
--- 2.0.3/varnish-cache/bin/varnishd/mgt_child.c	2008-10-16 07:43:08.000000000 +0200
+++ trunk/varnish-cache/bin/varnishd/mgt_child.c	2008-11-10 09:23:00.000000000 +0100
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: mgt_child.c 3145 2008-08-29 12:35:00Z tfheen $
+ * $Id: mgt_child.c 3364 2008-11-09 14:25:22Z phk $
  *
  * The mechanics of handling the child process
  */
@@ -45,7 +45,6 @@
 #include <sys/types.h>
 #include <sys/wait.h>
 
-#include "config.h"
 #ifndef HAVE_SETPROCTITLE
 #include "compat/setproctitle.h"
 #endif
@@ -82,7 +81,7 @@
 	CH_DIED = 4
 }			child_state = CH_STOPPED;
 
-static const char *ch_state[] = {
+static const char * const ch_state[] = {
 	[CH_STOPPED] =	"stopped",
 	[CH_STARTING] =	"starting",
 	[CH_RUNNING] =	"running",
@@ -194,7 +193,7 @@
 			continue;
 		}
 		ls->sock = VSS_bind(ls->addr);
-		if (ls->sock < 0) 
+		if (ls->sock < 0)
 			continue;
 
 		mgt_child_inherit(ls->sock, "sock");
@@ -269,7 +268,7 @@
 	child_cli_in = cp[0];
 
 	/*
-	 * Open pipe for child stdout/err 
+	 * Open pipe for child stdout/err
 	 * NB: not inherited, because we dup2() it to stdout/stderr in child
 	 */
 	AZ(pipe(cp));
@@ -548,7 +547,7 @@
 	AZ(sigaction(SIGPIPE, &sac, NULL));
 	AZ(sigaction(SIGHUP, &sac, NULL));
 
-	if (!dflag && !mgt_has_vcl()) 
+	if (!dflag && !mgt_has_vcl())
 		REPORT0(LOG_ERR, "No VCL loaded yet");
 	else if (!dflag) {
 		start_child(NULL);
diff -Nru 2.0.3/varnish-cache/bin/varnishd/mgt_cli.c trunk/varnish-cache/bin/varnishd/mgt_cli.c
--- 2.0.3/varnish-cache/bin/varnishd/mgt_cli.c	2008-10-16 07:43:08.000000000 +0200
+++ trunk/varnish-cache/bin/varnishd/mgt_cli.c	2009-01-05 14:45:27.000000000 +0100
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: mgt_cli.c 3072 2008-08-11 07:47:24Z phk $
+ * $Id: mgt_cli.c 3495 2008-12-21 18:40:35Z phk $
  *
  * The management process' CLI handling
  */
@@ -45,7 +45,6 @@
 #include <unistd.h>
 #include <sys/socket.h>
 
-#include "config.h"
 #ifndef HAVE_VASPRINTF
 #include "compat/vasprintf.h"
 #endif
@@ -66,8 +65,8 @@
 static int		cli_i = -1, cli_o = -1;
 
 struct telnet {
-	int 			fd;
-	struct vev 		*ev;
+	int			fd;
+	struct vev		*ev;
 	VTAILQ_ENTRY(telnet)	list;
 };
 
@@ -108,7 +107,7 @@
 		    "help %s\n", av[2] != NULL ? av[2] : "")) {
 			cli_out(cli, "%s", p);
 			cli_result(cli, u);
-		} 
+		}
 		free(p);
 	}
 }
@@ -144,7 +143,7 @@
 	{ CLI_PARAM_SHOW,	mcf_param_show, NULL },
 	{ CLI_PARAM_SET,	mcf_param_set, NULL },
 
-	{ CLI_QUIT, 		mcf_close, NULL},
+	{ CLI_QUIT,		mcf_close, NULL},
 #if 0
 	{ CLI_SERVER_RESTART },
 	{ CLI_ZERO },
@@ -190,7 +189,7 @@
 		return (CLIS_COMMS);
 	}
 
-	i = cli_readres(cli_i, &u, resp, params->cli_timeout);
+	(void)cli_readres(cli_i, &u, resp, params->cli_timeout);
 	if (status != NULL)
 		*status = u;
 	return (u == CLIS_OK ? 0 : u);
@@ -271,7 +270,7 @@
 			xxxassert(i == strlen(p));
 			i = write(cli_o, "\n", 1);
 			xxxassert(i == 1);
-			i = cli_readres(cli_i, &u, &q, params->cli_timeout);
+			(void)cli_readres(cli_i, &u, &q, params->cli_timeout);
 			cli_result(cp->cli, u);
 			cli_out(cp->cli, "%s", q);
 			free(q);
@@ -460,22 +459,23 @@
 {
 	struct vss_addr **ta;
 	char *addr, *port;
-	int i, n, sock;
+	int i, n, sock, good;
 	struct telnet *tn;
 
 	dflag_copy = dflag;
 
 	XXXAZ(VSS_parse(T_arg, &addr, &port));
 	n = VSS_resolve(addr, port, &ta);
-	free(addr);
-	free(port);
 	if (n == 0) {
 		fprintf(stderr, "Could not open management port\n");
 		exit(2);
 	}
+	good = 0;
 	for (i = 0; i < n; ++i) {
 		sock = VSS_listen(ta[i], 10);
-		assert(sock >= 0);
+		if (sock < 0)
+			continue;
+		good++;
 		tn = telnet_new(sock);
 		tn->ev = vev_new();
 		XXXAN(tn->ev);
@@ -487,5 +487,12 @@
 		ta[i] = NULL;
 	}
 	free(ta);
+	if (good == 0) {
+		REPORT(LOG_ERR, "-T %s:%s could not be listened on.",
+		    addr, port);
+		exit(2);
+	}
+	free(addr);
+	free(port);
 	return (0);
 }
diff -Nru 2.0.3/varnish-cache/bin/varnishd/mgt.h trunk/varnish-cache/bin/varnishd/mgt.h
--- 2.0.3/varnish-cache/bin/varnishd/mgt.h	2008-10-16 07:43:08.000000000 +0200
+++ trunk/varnish-cache/bin/varnishd/mgt.h	2009-01-05 14:45:27.000000000 +0100
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: mgt.h 2955 2008-07-19 09:24:07Z phk $
+ * $Id: mgt.h 3415 2008-11-21 12:09:46Z phk $
  */
 
 #include "common.h"
@@ -58,7 +58,7 @@
 
 /* mgt_vcc.c */
 void mgt_vcc_init(void);
-int mgt_vcc_default(const char *bflag, const char *fflag, int f_fd, int Cflag);
+int mgt_vcc_default(const char *bflag, char *vcl, int Cflag);
 int mgt_push_vcls_and_start(unsigned *status, char **p);
 int mgt_has_vcl(void);
 extern char *mgt_cc_cmd;
diff -Nru 2.0.3/varnish-cache/bin/varnishd/mgt_param.c trunk/varnish-cache/bin/varnishd/mgt_param.c
--- 2.0.3/varnish-cache/bin/varnishd/mgt_param.c	2009-01-09 15:45:56.000000000 +0100
+++ trunk/varnish-cache/bin/varnishd/mgt_param.c	2009-01-05 14:45:27.000000000 +0100
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: mgt_param.c 3370 2008-11-10 10:09:31Z tfheen $
+ * $Id: mgt_param.c 3490 2008-12-21 18:34:02Z phk $
  */
 
 #include "config.h"
@@ -43,7 +43,6 @@
 #include <string.h>
 #include <unistd.h>
 
-#include "config.h"
 #include "cli.h"
 #include "cli_priv.h"
 #include "cli_common.h"
@@ -51,33 +50,28 @@
 #include "mgt_cli.h"
 
 #include "heritage.h"
+#include "vparam.h"
 
 #include "vss.h"
 
 #define MAGIC_INIT_STRING	"\001"
-
-struct parspec;
+struct params master;
+static int nparspec;
+static struct parspec const ** parspec;
 static int margin;
 
-typedef void tweak_t(struct cli *, const struct parspec *, const char *arg);
+/*--------------------------------------------------------------------*/
 
-struct parspec {
-	const char	*name;
-	tweak_t		*func;
-	volatile void	*priv;
-	unsigned	umin;
-	unsigned	umax;
-	const char	*descr;
-	int		 flags;
-#define DELAYED_EFFECT 1
-#define EXPERIMENTAL   2
-#define MUST_RESTART   4
-#define MUST_RELOAD    8
-	const char	*def;
-	const char	*units;
-};
+static const struct parspec *
+mcf_findpar(const char *name)
+{
+	int i;
 
-static struct params master;
+	for (i = 0; i < nparspec; i++)
+		if (!strcmp(parspec[i]->name, name)) 
+			return (parspec[i]);
+	return (NULL);
+}
 
 /*--------------------------------------------------------------------*/
 
@@ -98,9 +92,27 @@
 		cli_out(cli, "%u", *dst);
 }
 
+static void
+tweak_generic_timeout_double(struct cli *cli, volatile double *dst, const char *arg)
+{
+	double u;
+
+	if (arg != NULL) {
+		u = strtod(arg, NULL);
+		if (u < 0) {
+			cli_out(cli, "Timeout must be greater or equal to zero\n");
+			cli_result(cli, CLIS_PARAM);
+			return;
+		}
+		*dst = u;
+	} else
+		cli_out(cli, "%f", *dst);
+}
+
+
 /*--------------------------------------------------------------------*/
 
-static void
+void
 tweak_timeout(struct cli *cli, const struct parspec *par, const char *arg)
 {
 	volatile unsigned *dest;
@@ -109,7 +121,14 @@
 	tweak_generic_timeout(cli, dest, arg);
 }
 
+static void
+tweak_timeout_double(struct cli *cli, const struct parspec *par, const char *arg)
+{
+	volatile double *dest;
 
+	dest = par->priv;
+	tweak_generic_timeout_double(cli, dest, arg);
+}
 /*--------------------------------------------------------------------*/
 
 static void
@@ -122,12 +141,16 @@
 			*dest = 0;
 		else if (!strcasecmp(arg, "no"))
 			*dest = 0;
+		else if (!strcasecmp(arg, "false"))
+			*dest = 0;
 		else if (!strcasecmp(arg, "on"))
 			*dest = 1;
 		else if (!strcasecmp(arg, "enable"))
 			*dest = 1;
 		else if (!strcasecmp(arg, "yes"))
 			*dest = 1;
+		else if (!strcasecmp(arg, "true"))
+			*dest = 1;
 		else {
 			cli_out(cli, "use \"on\" or \"off\"\n");
 			cli_result(cli, CLIS_PARAM);
@@ -150,8 +173,9 @@
 
 /*--------------------------------------------------------------------*/
 
-static void
-tweak_generic_uint(struct cli *cli, volatile unsigned *dest, const char *arg, unsigned min, unsigned max)
+void
+tweak_generic_uint(struct cli *cli, volatile unsigned *dest, const char *arg,
+    unsigned min, unsigned max)
 {
 	unsigned u;
 
@@ -180,7 +204,7 @@
 
 /*--------------------------------------------------------------------*/
 
-static void
+void
 tweak_uint(struct cli *cli, const struct parspec *par, const char *arg)
 {
 	volatile unsigned *dest;
@@ -211,7 +235,7 @@
 				master.uid = getuid();
 				return;
 			}
-		} else 
+		} else
 			pw = getpwnam(arg);
 		if (pw == NULL) {
 			cli_out(cli, "Unknown user");
@@ -225,7 +249,7 @@
 		/* set group to user's primary group */
 		if ((gr = getgrgid(pw->pw_gid)) != NULL &&
 		    (gr = getgrnam(gr->gr_name)) != NULL &&
-		    gr->gr_gid == pw->pw_gid) 
+		    gr->gr_gid == pw->pw_gid)
 			REPLACE(master.group, gr->gr_name);
 	} else if (master.user) {
 		cli_out(cli, "%s (%d)", master.user, (int)master.uid);
@@ -272,27 +296,6 @@
 /*--------------------------------------------------------------------*/
 
 static void
-tweak_thread_pool_min(struct cli *cli, const struct parspec *par, const char *arg)
-{
-
-	tweak_generic_uint(cli, &master.wthread_min, arg,
-	    par->umin, master.wthread_max);
-}
-
-/*--------------------------------------------------------------------*/
-
-static void
-tweak_thread_pool_max(struct cli *cli, const struct parspec *par, const char *arg)
-{
-
-	(void)par;
-	tweak_generic_uint(cli, &master.wthread_max, arg,
-	    master.wthread_min, UINT_MAX);
-}
-
-/*--------------------------------------------------------------------*/
-
-static void
 clean_listen_sock_head(struct listen_sock_head *lsh)
 {
 	struct listen_sock *ls, *ls2;
@@ -306,7 +309,8 @@
 }
 
 static void
-tweak_listen_address(struct cli *cli, const struct parspec *par, const char *arg)
+tweak_listen_address(struct cli *cli, const struct parspec *par,
+    const char *arg)
 {
 	char **av;
 	int i;
@@ -370,7 +374,7 @@
 		free(ta);
 	}
 	FreeArgv(av);
-	if (cli->result != CLIS_OK) {
+	if (cli != NULL && cli->result != CLIS_OK) {
 		clean_listen_sock_head(&lsh);
 		return;
 	}
@@ -460,7 +464,7 @@
  * change its default value.
  * XXX: we should generate the relevant section of varnishd.1 from here.
  */
-static const struct parspec parspec[] = {
+static const struct parspec input_parspec[] = {
 	{ "user", tweak_user, NULL, 0, 0,
 		"The unprivileged user to run as.  Setting this will "
 		"also set \"group\" to the specified user's primary group.",
@@ -479,114 +483,13 @@
 		"flush of the cache use \"url.purge .\"",
 		0,
 		"120", "seconds" },
-	{ "thread_pools", tweak_uint, &master.wthread_pools, 1, UINT_MAX,
-		"Number of worker thread pools.\n"
-		"\n"
-		"Increasing number of worker pools decreases lock "
-		"contention.\n"
-		"\n"
-		"Too many pools waste CPU and RAM resources, and more than "
-		"one pool for each CPU is probably detrimal to performance.\n"
-		"\n"
-		"Can be increased on the fly, but decreases require a "
-		"restart to take effect.",
-		EXPERIMENTAL | DELAYED_EFFECT,
-		"2", "pools" },
-	{ "thread_pool_max", tweak_thread_pool_max, NULL, 1, 0,
-		"The maximum number of worker threads in all pools combined.\n"
-		"\n"
-		"Do not set this higher than you have to, since excess "
-		"worker threads soak up RAM and CPU and generally just get "
-		"in the way of getting work done.\n",
-		EXPERIMENTAL | DELAYED_EFFECT,
-		"500", "threads" },
-	{ "thread_pool_min", tweak_thread_pool_min, NULL, 2, 0,
-		"The minimum number of threads in each worker pool.\n"
-		"\n"
-		"Increasing this may help ramp up faster from low load "
-		"situations where threads have expired.\n"
-		"\n"
-		"Minimum is 2 threads.",
-		EXPERIMENTAL | DELAYED_EFFECT,
-		"5", "threads" },
-	{ "thread_pool_timeout", tweak_timeout, &master.wthread_timeout, 1, 0,
-		"Thread idle threshold.\n"
-		"\n"
-		"Threads in excess of thread_pool_min, which have been idle "
-		"for at least this long are candidates for purging.\n"
-		"\n"
-		"Minimum is 1 second.",
-		EXPERIMENTAL | DELAYED_EFFECT,
-		"300", "seconds" },
-	{ "thread_pool_purge_delay",
-		tweak_timeout, &master.wthread_purge_delay, 100, 0,
-		"Wait this long between purging threads.\n"
-		"\n"
-		"This controls the decay of thread pools when idle(-ish).\n"
-		"\n"
-		"Minimum is 100 milliseconds.",
-		EXPERIMENTAL | DELAYED_EFFECT,
-		"1000", "milliseconds" },
-	{ "thread_pool_add_threshold",
-		tweak_uint, &master.wthread_add_threshold, 0, UINT_MAX,
-		"Overflow threshold for worker thread creation.\n"
-		"\n"
-		"Setting this too low, will result in excess worker threads, "
-		"which is generally a bad idea.\n"
-		"\n"
-		"Setting it too high results in insuffient worker threads.\n",
-		EXPERIMENTAL,
-		"2", "requests" },
-	{ "thread_pool_add_delay",
-		tweak_timeout, &master.wthread_add_delay, 0, UINT_MAX,
-		"Wait at least this long between creating threads.\n"
-		"\n"
-		"Setting this too long results in insuffient worker threads.\n"
-		"\n"
-		"Setting this too short increases the risk of worker "
-		"thread pile-up.\n",
-		EXPERIMENTAL,
-		"20", "milliseconds" },
-	{ "thread_pool_fail_delay",
-		tweak_timeout, &master.wthread_fail_delay, 100, UINT_MAX,
-		"Wait at least this long after a failed thread creation "
-		"before trying to create another thread.\n"
-		"\n"
-		"Failure to create a worker thread is often a sign that "
-		" the end is near, because the process is running out of "
-		"RAM resources for thread stacks.\n"
-		"This delay tries to not rush it on needlessly.\n"
-		"\n"
-		"If thread creation failures are a problem, check that "
-		"thread_pool_max is not too high.\n"
-		"\n"
-		"It may also help to increase thread_pool_timeout and "
-		"thread_pool_min, to reduce the rate at which treads are "
-		"destroyed and later recreated.\n",
-		EXPERIMENTAL,
-		"200", "milliseconds" },
-	{ "overflow_max", tweak_uint, &master.overflow_max, 0, UINT_MAX,
-		"Percentage permitted overflow queue length.\n"
-		"\n"
-		"This sets the ratio of queued requests to worker threads, "
-		"above which sessions will be dropped instead of queued.\n",
-		EXPERIMENTAL,
-		"100", "%" },
-	{ "rush_exponent", tweak_uint, &master.rush_exponent, 2, UINT_MAX,
-		"How many parked request we start for each completed "
-		"request on the object.\n"
-		"NB: Even with the implict delay of delivery, "
-		"this parameter controls an exponential increase in "
-		"number of worker threads.  ",
-		EXPERIMENTAL,
-		"3", "requests per request" },
 	{ "sess_workspace", tweak_uint, &master.sess_workspace, 1024, UINT_MAX,
 		"Bytes of HTTP protocol workspace allocated for sessions. "
 		"This space must be big enough for the entire HTTP protocol "
 		"header and any edits done to it in the VCL code.\n"
 		"Minimum is 1024 bytes.",
 		DELAYED_EFFECT,
-		"8192", "bytes" },
+		"16384", "bytes" },
 	{ "obj_workspace", tweak_uint, &master.obj_workspace, 1024, UINT_MAX,
 		"Bytes of HTTP protocol workspace allocated for objects. "
 		"This space must be big enough for the entire HTTP protocol "
@@ -604,6 +507,11 @@
 		"Minimum is 4096 bytes.",
 		DELAYED_EFFECT,
 		"8192", "bytes" },
+	{ "shm_reclen", tweak_uint, &master.shm_reclen, 16, 65535,
+		"Maximum number of bytes in SHM log record.\n"
+		"Maximum is 65535 bytes.",
+		0,
+		"255", "bytes" },
 	{ "default_grace", tweak_uint, &master.default_grace, 0, UINT_MAX,
 		"Default grace period.  We will deliver an object "
 		"this long after it has expired, provided another thread "
@@ -682,7 +590,7 @@
 		"By default we copy the protocol version from the "
 		"incoming client request.",
 		EXPERIMENTAL,
-		"off", "bool" },
+		"on", "bool" },
 	{ "client_http11", tweak_bool, &master.client_http11, 0, 0,
 		"Force all client responses to be HTTP/1.1.\n"
 		"By default we copy the protocol version from the "
@@ -727,6 +635,7 @@
 		"Bitmap controlling ESI parsing code:\n"
 		"  0x00000001 - Don't check if it looks like XML\n"
 		"  0x00000002 - Ignore non-esi elements\n"
+		"  0x00000004 - Emit parsing debug records\n"
 		"Use 0x notation and do the bitor in your head :-)\n",
 		0,
 		"0", "bitmap" },
@@ -739,14 +648,33 @@
 		"Cache vbe_conn's or rely on malloc, that's the question.",
 		EXPERIMENTAL,
 		"off", "bool" },
-	{ "connect_timeout", tweak_uint,
+	{ "connect_timeout", tweak_timeout_double,
 		&master.connect_timeout,0, UINT_MAX,
-		"Default connection timeout for backend connections.  "
+		"Default connection timeout for backend connections. "
 		"We only try to connect to the backend for this many "
-		"milliseconds before giving up.  "
-		"VCL can override this default value for each backend.",
+		"seconds before giving up. "
+		"VCL can override this default value for each backend and "
+		"backend request.",
+		0,
+		"0.4", "s" },
+	{ "first_byte_timeout", tweak_timeout_double,
+		&master.first_byte_timeout,0, UINT_MAX,
+		"Default timeout for receiving first byte from backend. "
+		"We only wait for this many seconds for the first "
+		"byte before giving up. A value of 0 means it will never time out. "
+		"VCL can override this default value for each backend and "
+		"backend request. This parameter does not apply to pipe.",
+		0,
+		"60", "s" },
+	{ "between_bytes_timeout", tweak_timeout_double,
+		&master.between_bytes_timeout,0, UINT_MAX,
+		"Default timeout between bytes when receiving data from backend. "
+		"We only wait for this many seconds between bytes "
+		"before giving up. A value of 0 means it will never time out. "
+		"VCL can override this default value for each backend request and "
+		"backend request. This parameter does not apply to pipe.",
 		0,
-		"400", "ms" },
+		"60", "s" },
 	{ "accept_fd_holdoff", tweak_timeout,
 		&master.accept_fd_holdoff, 0,  3600*1000,
 		"If we run out of file descriptors, the accept thread will "
@@ -782,6 +710,10 @@
 		"NB: Must be specified with -p to have effect.\n",
 		0,
 		"8192", "bytes" },
+	{ "hash_sha256", tweak_bool, &master.hash_sha256, 0, 0,
+		"Use SHA256 compression of hash-strings",
+		0,
+		"on", "bool" },
 	{ "log_hashstring", tweak_bool, &master.log_hash, 0, 0,
 		"Log the hash string to shared memory log.\n",
 		0,
@@ -854,6 +786,7 @@
 void
 mcf_param_show(struct cli *cli, const char * const *av, void *priv)
 {
+	int i;
 	const struct parspec *pp;
 	int lfmt;
 
@@ -862,7 +795,8 @@
 		lfmt = 0;
 	else
 		lfmt = 1;
-	for (pp = parspec; pp->name != NULL; pp++) {
+	for (i = 0; i < nparspec; i++) {
+		pp = parspec[i];
 		if (av[2] != NULL && !lfmt && strcmp(pp->name, av[2]))
 			continue;
 		cli_out(cli, "%-*s ", margin, pp->name);
@@ -918,20 +852,19 @@
 {
 	const struct parspec *pp;
 
-	for (pp = parspec; pp->name != NULL; pp++) {
-		if (!strcmp(pp->name, param)) {
-			pp->func(cli, pp, val);
-			if (cli->result != CLIS_OK) {
-			} else if (child_pid >= 0 && pp->flags & MUST_RESTART) {
-				cli_out(cli, "Change will take effect"
-				    " when child is restarted");
-			} else if (pp->flags & MUST_RELOAD) {
-				cli_out(cli, "Change will take effect"
-				    " when VCL script is reloaded");
-			}
-			MCF_ParamSync();
-			return;
+	pp = mcf_findpar(param);
+	if (pp != NULL) {
+		pp->func(cli, pp, val);
+		if (cli->result != CLIS_OK) {
+		} else if (child_pid >= 0 && pp->flags & MUST_RESTART) {
+			cli_out(cli, "Change will take effect"
+			    " when child is restarted");
+		} else if (pp->flags & MUST_RELOAD) {
+			cli_out(cli, "Change will take effect"
+			    " when VCL script is reloaded");
 		}
+		MCF_ParamSync();
+		return;
 	}
 	cli_result(cli, CLIS_PARAM);
 	cli_out(cli, "Unknown parameter \"%s\".", param);
@@ -948,20 +881,73 @@
 	MCF_ParamSet(cli, av[2], av[3]);
 }
 
-/*--------------------------------------------------------------------*/
+/*--------------------------------------------------------------------
+ * Add a group of parameters to the global set and sort by name.
+ */
 
-void
-MCF_ParamInit(struct cli *cli)
+static int
+parspec_cmp(const void *a, const void *b)
+{
+	struct parspec * const * pa = a;
+	struct parspec * const * pb = b;
+	return (strcmp((*pa)->name, (*pb)->name));
+}
+
+static void
+MCF_AddParams(const struct parspec *ps)
 {
 	const struct parspec *pp;
+	int n;
 
-	for (pp = parspec; pp->name != NULL; pp++) {
-		cli_out(cli, "Set Default for %s = %s\n", pp->name, pp->def);
+	n = 0;
+	for (pp = ps; pp->name != NULL; pp++) {
+		if (mcf_findpar(pp->name) != NULL)
+			fprintf(stderr, "Duplicate param: %s\n", pp->name);
 		if (strlen(pp->name) + 1 > margin)
 			margin = strlen(pp->name) + 1;
+		n++;
+	}
+	parspec = realloc(parspec, (nparspec + n + 1) * sizeof *parspec);
+	XXXAN(parspec);
+	for (pp = ps; pp->name != NULL; pp++)
+		parspec[nparspec++] = pp;
+	parspec[nparspec] = NULL;
+	qsort (parspec, nparspec, sizeof parspec[0], parspec_cmp);
+}
+
+/*--------------------------------------------------------------------
+ * Set defaults for all parameters
+ */
+
+static void
+MCF_SetDefaults(struct cli *cli)
+{
+	const struct parspec *pp;
+	int i;
+
+	for (i = 0; i < nparspec; i++) {
+		pp = parspec[i];
+		if (cli != NULL)
+			cli_out(cli,
+			    "Set Default for %s = %s\n", pp->name, pp->def);
 		pp->func(cli, pp, pp->def);
-		if (cli->result != CLIS_OK)
+		if (cli != NULL && cli->result != CLIS_OK)
 			return;
 	}
+}
+
+/*--------------------------------------------------------------------*/
+
+void
+MCF_ParamInit(struct cli *cli)
+{
+
+	MCF_AddParams(input_parspec);
+	MCF_AddParams(WRK_parspec);
+
+	/* XXX: We do this twice, to get past any interdependencies */
+	MCF_SetDefaults(NULL);
+	MCF_SetDefaults(cli);
+
 	params = &master;
 }
diff -Nru 2.0.3/varnish-cache/bin/varnishd/mgt_pool.c trunk/varnish-cache/bin/varnishd/mgt_pool.c
--- 2.0.3/varnish-cache/bin/varnishd/mgt_pool.c	1970-01-01 01:00:00.000000000 +0100
+++ trunk/varnish-cache/bin/varnishd/mgt_pool.c	2009-01-05 14:45:27.000000000 +0100
@@ -0,0 +1,184 @@
+/*-
+ * Copyright (c) 2006 Verdens Gang AS
+ * Copyright (c) 2006-2008 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: cache_pool.c 3429 2008-11-24 17:47:21Z phk $
+ *
+ * We maintain a number of worker thread pools, to spread lock contention.
+ *
+ * Pools can be added on the fly, as a means to mitigate lock contention,
+ * but can only be removed again by a restart. (XXX: we could fix that)
+ *
+ * Two threads herd the pools, one eliminates idle threads and aggregates
+ * statistics for all the pools, the other thread creates new threads
+ * on demand, subject to various numerical constraints.
+ *
+ * The algorithm for when to create threads needs to be reactive enough
+ * to handle startup spikes, but sufficiently attenuated to not cause
+ * thread pileups.  This remains subject for improvement.
+ */
+
+#include "config.h"
+#include <limits.h>
+#include <sys/types.h>
+
+#include "cli_priv.h"
+#include "mgt.h"
+
+#include "vparam.h"
+#include "heritage.h"
+
+/*--------------------------------------------------------------------*/
+
+static void
+tweak_thread_pool_min(struct cli *cli, const struct parspec *par,
+    const char *arg)
+{
+
+	tweak_generic_uint(cli, &master.wthread_min, arg,
+	    par->umin, master.wthread_max);
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+tweak_thread_pool_max(struct cli *cli, const struct parspec *par,
+    const char *arg)
+{
+
+	(void)par;
+	tweak_generic_uint(cli, &master.wthread_max, arg,
+	    master.wthread_min, UINT_MAX);
+}
+
+/*--------------------------------------------------------------------*/
+
+const struct parspec WRK_parspec[] = {
+	{ "thread_pools", tweak_uint, &master.wthread_pools, 1, UINT_MAX,
+		"Number of worker thread pools.\n"
+		"\n"
+		"Increasing number of worker pools decreases lock "
+		"contention.\n"
+		"\n"
+		"Too many pools waste CPU and RAM resources, and more than "
+		"one pool for each CPU is probably detrimal to performance.\n"
+		"\n"
+		"Can be increased on the fly, but decreases require a "
+		"restart to take effect.",
+		EXPERIMENTAL | DELAYED_EFFECT,
+		"2", "pools" },
+	{ "thread_pool_max", tweak_thread_pool_max, NULL, 1, 0,
+		"The maximum number of worker threads in all pools combined.\n"
+		"\n"
+		"Do not set this higher than you have to, since excess "
+		"worker threads soak up RAM and CPU and generally just get "
+		"in the way of getting work done.\n",
+		EXPERIMENTAL | DELAYED_EFFECT,
+		"500", "threads" },
+	{ "thread_pool_min", tweak_thread_pool_min, NULL, 2, 0,
+		"The minimum number of threads in each worker pool.\n"
+		"\n"
+		"Increasing this may help ramp up faster from low load "
+		"situations where threads have expired.\n"
+		"\n"
+		"Minimum is 2 threads.",
+		EXPERIMENTAL | DELAYED_EFFECT,
+		"5", "threads" },
+	{ "thread_pool_timeout", tweak_timeout, &master.wthread_timeout, 1, 0,
+		"Thread idle threshold.\n"
+		"\n"
+		"Threads in excess of thread_pool_min, which have been idle "
+		"for at least this long are candidates for purging.\n"
+		"\n"
+		"Minimum is 1 second.",
+		EXPERIMENTAL | DELAYED_EFFECT,
+		"300", "seconds" },
+	{ "thread_pool_purge_delay",
+		tweak_timeout, &master.wthread_purge_delay, 100, 0,
+		"Wait this long between purging threads.\n"
+		"\n"
+		"This controls the decay of thread pools when idle(-ish).\n"
+		"\n"
+		"Minimum is 100 milliseconds.",
+		EXPERIMENTAL | DELAYED_EFFECT,
+		"1000", "milliseconds" },
+	{ "thread_pool_add_threshold",
+		tweak_uint, &master.wthread_add_threshold, 0, UINT_MAX,
+		"Overflow threshold for worker thread creation.\n"
+		"\n"
+		"Setting this too low, will result in excess worker threads, "
+		"which is generally a bad idea.\n"
+		"\n"
+		"Setting it too high results in insuffient worker threads.\n",
+		EXPERIMENTAL,
+		"2", "requests" },
+	{ "thread_pool_add_delay",
+		tweak_timeout, &master.wthread_add_delay, 0, UINT_MAX,
+		"Wait at least this long between creating threads.\n"
+		"\n"
+		"Setting this too long results in insuffient worker threads.\n"
+		"\n"
+		"Setting this too short increases the risk of worker "
+		"thread pile-up.\n",
+		EXPERIMENTAL,
+		"20", "milliseconds" },
+	{ "thread_pool_fail_delay",
+		tweak_timeout, &master.wthread_fail_delay, 100, UINT_MAX,
+		"Wait at least this long after a failed thread creation "
+		"before trying to create another thread.\n"
+		"\n"
+		"Failure to create a worker thread is often a sign that "
+		" the end is near, because the process is running out of "
+		"RAM resources for thread stacks.\n"
+		"This delay tries to not rush it on needlessly.\n"
+		"\n"
+		"If thread creation failures are a problem, check that "
+		"thread_pool_max is not too high.\n"
+		"\n"
+		"It may also help to increase thread_pool_timeout and "
+		"thread_pool_min, to reduce the rate at which treads are "
+		"destroyed and later recreated.\n",
+		EXPERIMENTAL,
+		"200", "milliseconds" },
+	{ "overflow_max", tweak_uint, &master.overflow_max, 0, UINT_MAX,
+		"Percentage permitted overflow queue length.\n"
+		"\n"
+		"This sets the ratio of queued requests to worker threads, "
+		"above which sessions will be dropped instead of queued.\n",
+		EXPERIMENTAL,
+		"100", "%" },
+	{ "rush_exponent", tweak_uint, &master.rush_exponent, 2, UINT_MAX,
+		"How many parked request we start for each completed "
+		"request on the object.\n"
+		"NB: Even with the implict delay of delivery, "
+		"this parameter controls an exponential increase in "
+		"number of worker threads.  ",
+		EXPERIMENTAL,
+		"3", "requests per request" },
+	{ NULL, NULL, NULL }
+};
+
diff -Nru 2.0.3/varnish-cache/bin/varnishd/mgt_vcc.c trunk/varnish-cache/bin/varnishd/mgt_vcc.c
--- 2.0.3/varnish-cache/bin/varnishd/mgt_vcc.c	2008-10-16 07:43:08.000000000 +0200
+++ trunk/varnish-cache/bin/varnishd/mgt_vcc.c	2009-01-05 14:45:27.000000000 +0100
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: mgt_vcc.c 3095 2008-08-15 08:30:49Z phk $
+ * $Id: mgt_vcc.c 3491 2008-12-21 18:34:39Z phk $
  *
  * VCL compiler stuff
  */
@@ -43,12 +43,10 @@
 #include <string.h>
 #include <unistd.h>
 
-#include "config.h"
 #ifndef HAVE_ASPRINTF
 #include "compat/asprintf.h"
 #endif
 #include "vsb.h"
-#include "vlu.h"
 
 #include "vqueue.h"
 
@@ -65,7 +63,7 @@
 
 struct vclprog {
 	VTAILQ_ENTRY(vclprog)	list;
-	char 			*name;
+	char			*name;
 	char			*fname;
 	int			active;
 };
@@ -79,19 +77,22 @@
 /*
  * Keep this in synch with man/vcl.7 and etc/default.vcl!
  */
-static const char *default_vcl =
+static const char * const default_vcl =
 #include "default_vcl.h"
     ""	;
 
 /*
  * Prepare the compiler command line
  */
-static void
-mgt_make_cc_cmd(struct vsb *sb, const char *sf, const char *of)
+static struct vsb *
+mgt_make_cc_cmd(const char *sf, const char *of)
 {
+	struct vsb *sb;
 	int pct;
 	char *p;
 
+	sb = vsb_newauto();
+	XXXAN(sb);
 	for (p = mgt_cc_cmd, pct = 0; *p; ++p) {
 		if (pct) {
 			switch (*p) {
@@ -118,127 +119,130 @@
 	}
 	if (pct)
 		vsb_putc(sb, '%');
+	vsb_finish(sb);
+	AZ(vsb_overflowed(sb));
+	return (sb);
 }
 
 /*--------------------------------------------------------------------
- * Invoke system C compiler on source and return resulting dlfile.
- * Errors goes in sb;
+ * Invoke system C compiler in a sub-process
  */
 
-static int
-mgt_cc_vlu(void *priv, const char *str)
+static void
+run_cc(void *priv)
 {
-	struct vsb *vsb;
+	(void)execl("/bin/sh", "/bin/sh", "-c", priv, NULL);
+}
 
-	vsb = priv;
-	vsb_printf(vsb, "C-compiler said: %s\n", str);
-	return (0);
+/*--------------------------------------------------------------------
+ * Invoke system VCC compiler in a sub-process
+ */
+
+struct vcc_priv {
+	char		*sf;
+	const char	*vcl;
+};
+
+static void
+run_vcc(void *priv)
+{
+	char *csrc;
+	struct vsb *sb;
+	struct vcc_priv *vp;
+	int fd, i, l;
+
+	vp = priv;
+	sb = vsb_newauto();
+	XXXAN(sb);
+	csrc = VCC_Compile(sb, vp->vcl, NULL);
+	vsb_finish(sb);
+	AZ(vsb_overflowed(sb));
+	if (vsb_len(sb))
+		printf("%s", vsb_data(sb));
+	vsb_delete(sb);
+	if (csrc == NULL)
+		exit (1);
+
+	fd = open(vp->sf, O_WRONLY);
+	if (fd < 0) {
+		fprintf(stderr, "Cannot open %s", vp->sf);
+		exit (1);
+	}
+	l = strlen(csrc);
+	i = write(fd, csrc, l);
+	if (i != l) {
+		fprintf(stderr, "Cannot write %s", vp->sf);
+		exit (1);
+	}
+	AZ(close(fd));
+	free(csrc);
+	exit (0);
 }
 
+/*--------------------------------------------------------------------
+ * Compile a VCL program, return shared object, errors in sb.
+ */
+
 static char *
-mgt_run_cc(const char *source, struct vsb *sb)
+mgt_run_cc(const char *vcl, struct vsb *sb, int C_flag)
 {
-	char cmdline[1024];
-	struct vsb cmdsb;
+	char *csrc;
+	struct vsb *cmdsb;
 	char sf[] = "./vcl.########.c";
 	char of[sizeof sf + 1];
 	char *retval;
-	int rv, p[2], sfd, srclen, status;
-	pid_t pid;
+	int sfd, i;
 	void *dlh;
-	struct vlu *vlu;
+	struct vcc_priv vp;
 
 	/* Create temporary C source file */
 	sfd = vtmpfile(sf);
 	if (sfd < 0) {
-		vsb_printf(sb,
-		    "%s(): failed to create %s: %s",
-		    __func__, sf, strerror(errno));
+		vsb_printf(sb, "Failed to create %s: %s", sf, strerror(errno));
 		return (NULL);
 	}
-	srclen = strlen(source);
-	if (write(sfd, source, srclen) != srclen) {
-		vsb_printf(sb,
-		    "Failed to write C source to file: %s",
-		    strerror(errno));
-		AZ(unlink(sf));
-		AZ(close(sfd));
+	AZ(close(sfd));
+
+	/* Run the VCC compiler in a sub-process */
+	vp.sf = sf;
+	vp.vcl = vcl;
+	if (SUB_run(sb, run_vcc, &vp, "VCC-compiler", -1)) {
+		(void)unlink(sf);
 		return (NULL);
 	}
-	AZ(close(sfd));
 
-	/* Name the output shared library by overwriting the final 'c' */
+	if (C_flag) {
+		csrc = vreadfile(sf);
+		XXXAN(csrc);
+		(void)fputs(csrc, stdout);
+		free(csrc);
+	}
+
+	/* Name the output shared library by "s/[.]c$/[.]so/" */
 	memcpy(of, sf, sizeof sf);
 	assert(sf[sizeof sf - 2] == 'c');
 	of[sizeof sf - 2] = 's';
 	of[sizeof sf - 1] = 'o';
 	of[sizeof sf] = '\0';
-	AN(vsb_new(&cmdsb, cmdline, sizeof cmdline, 0));
-	mgt_make_cc_cmd(&cmdsb, sf, of);
-	vsb_finish(&cmdsb);
-	AZ(vsb_overflowed(&cmdsb));
-	/* XXX check vsb state */
-
-	if (pipe(p) < 0) {
-		vsb_printf(sb, "%s(): pipe() failed: %s",
-		    __func__, strerror(errno));
-		(void)unlink(sf);
-		return (NULL);
-	}
-	assert(p[0] > STDERR_FILENO);
-	assert(p[1] > STDERR_FILENO);
-	if ((pid = fork()) < 0) {
-		vsb_printf(sb, "%s(): fork() failed: %s",
-		    __func__, strerror(errno));
-		AZ(close(p[0]));
-		AZ(close(p[1]));
-		(void)unlink(sf);
-		return (NULL);
-	}
-	if (pid == 0) {
-		AZ(close(STDIN_FILENO));
-		assert(open("/dev/null", O_RDONLY) == STDIN_FILENO);
-		assert(dup2(p[1], STDOUT_FILENO) == STDOUT_FILENO);
-		assert(dup2(p[1], STDERR_FILENO) == STDERR_FILENO);
-		/* Close all other fds */
-		for (sfd = STDERR_FILENO + 1; sfd < 100; sfd++)
-			(void)close(sfd);
-		(void)execl("/bin/sh", "/bin/sh", "-c", cmdline, NULL);
-		_exit(1);
-	}
-	AZ(close(p[1]));
-	vlu = VLU_New(sb, mgt_cc_vlu, 0);
-	while (!VLU_Fd(p[0], vlu))
-		continue;
-	AZ(close(p[0]));
-	VLU_Destroy(vlu);
+
+	/* Build the C-compiler command line */
+	cmdsb = mgt_make_cc_cmd(sf, of);
+
+	/* Run the C-compiler in a sub-shell */
+	i = SUB_run(sb, run_cc, vsb_data(cmdsb), "C-compiler", 10);
+
 	(void)unlink(sf);
-	do {
-		rv = waitpid(pid, &status, 0);
-		if (rv < 0 && errno != EINTR) {
-			vsb_printf(sb, "%s(): waitpid() failed: %s",
-			    __func__, strerror(errno));
-			(void)unlink(of);
-			return (NULL);
-		}
-	} while (rv < 0);
-	if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
-		vsb_printf(sb, "%s(): Compiler failed", __func__);
-		if (WIFEXITED(status))
-			vsb_printf(sb, ", exit %d", WEXITSTATUS(status));
-		if (WIFSIGNALED(status))
-			vsb_printf(sb, ", signal %d", WTERMSIG(status));
-		if (WCOREDUMP(status))
-			vsb_printf(sb, ", core dumped");
+	vsb_delete(cmdsb);
+
+	if (i) {
 		(void)unlink(of);
 		return (NULL);
 	}
 
-	/* Next, try to load the object into the management process */
+	/* Try to load the object into the management process */
 	if ((dlh = dlopen(of, RTLD_NOW | RTLD_LOCAL)) == NULL) {
 		vsb_printf(sb,
-		    "%s(): failed to load compiled VCL program:\n  %s",
-		    __func__, dlerror());
+		    "Compiled VCL program failed to load:\n  %s", dlerror());
 		(void)unlink(of);
 		return (NULL);
 	}
@@ -257,40 +261,18 @@
 /*--------------------------------------------------------------------*/
 
 static char *
-mgt_VccCompile(struct vsb *sb, const char *b, const char *e, int C_flag)
-{
-	char *csrc, *vf = NULL;
-
-	csrc = VCC_Compile(sb, b, e);
-	if (csrc != NULL) {
-		if (C_flag)
-			(void)fputs(csrc, stdout);
-		vf = mgt_run_cc(csrc, sb);
-		if (C_flag && vf != NULL)
-			AZ(unlink(vf));
-		free(csrc);
-	}
-	return (vf);
-}
-
-static char *
-mgt_VccCompileFile(struct vsb *sb, const char *fn, int C_flag, int fd)
+mgt_VccCompile(struct vsb **sb, const char *b, int C_flag)
 {
-	char *csrc, *vf = NULL;
+	char *vf = NULL;
 
-	csrc = VCC_CompileFile(sb, fn, fd);
-	if (csrc != NULL) {
-		if (C_flag)
-			(void)fputs(csrc, stdout);
-		vf = mgt_run_cc(csrc, sb);
-		if (C_flag && vf != NULL)
-			AZ(unlink(vf));
-		free(csrc);
-	}
+	*sb = vsb_newauto();
+	XXXAN(*sb);
+	vf = mgt_run_cc(b, *sb, C_flag);
+	vsb_finish(*sb);
+	AZ(vsb_overflowed(*sb));
 	return (vf);
 }
 
-
 /*--------------------------------------------------------------------*/
 
 static struct vclprog *
@@ -346,16 +328,15 @@
 /*--------------------------------------------------------------------*/
 
 int
-mgt_vcc_default(const char *b_arg, const char *f_arg, int f_fd, int C_flag)
+mgt_vcc_default(const char *b_arg, char *vcl, int C_flag)
 {
 	char *addr, *port;
-	char *buf, *vf;
+	char *vf;
 	struct vsb *sb;
 	struct vclprog *vp;
 
-	sb = vsb_newauto();
-	XXXAN(sb);
 	if (b_arg != NULL) {
+		AZ(vcl);
 		/*
 		 * XXX: should do a "HEAD /" on the -b argument to see that
 		 * XXX: it even works.  On the other hand, we should do that
@@ -374,31 +355,29 @@
 			 */
 			free(port);
 			fprintf(stderr, "invalid backend address\n");
-			vsb_delete(sb);
 			return (1);
 		}
 
-		buf = NULL;
-		asprintf(&buf,
+		asprintf(&vcl,
 		    "backend default {\n"
 		    "    .host = \"%s\";\n"
 		    "    .port = \"%s\";\n"
 		    "}\n", addr, port ? port : "http");
 		free(addr);
 		free(port);
-		AN(buf);
-		vf = mgt_VccCompile(sb, buf, NULL, C_flag);
-		free(buf);
-	} else {
-		vf = mgt_VccCompileFile(sb, f_arg, C_flag, f_fd);
+		AN(vcl);
 	}
-	vsb_finish(sb);
-	AZ(vsb_overflowed(sb));
+
+	vf = mgt_VccCompile(&sb, vcl, C_flag);
+	free(vcl);
 	if (vsb_len(sb) > 0)
 		fprintf(stderr, "%s", vsb_data(sb));
 	vsb_delete(sb);
-	if (C_flag)
+	if (C_flag) {
+		if (vf != NULL) 
+			AZ(unlink(vf));
 		return (0);
+	}
 	if (vf == NULL) {
 		fprintf(stderr, "\nVCL compilation failed\n");
 		return (1);
@@ -487,14 +466,10 @@
 		cli_result(cli, CLIS_PARAM);
 		return;
 	}
-	
-	sb = vsb_newauto();
-	XXXAN(sb);
-	vf = mgt_VccCompile(sb, av[3], NULL, 0);
-	vsb_finish(sb);
-	AZ(vsb_overflowed(sb));
+
+	vf = mgt_VccCompile(&sb, av[3], 0);
 	if (vsb_len(sb) > 0)
-		cli_out(cli, "%s", vsb_data(sb));
+		cli_out(cli, "%s\n", vsb_data(sb));
 	vsb_delete(sb);
 	if (vf == NULL) {
 		cli_out(cli, "VCL compilation failed");
@@ -515,7 +490,7 @@
 void
 mcf_config_load(struct cli *cli, const char * const *av, void *priv)
 {
-	char *vf;
+	char *vf, *vcl;
 	struct vsb *sb;
 	unsigned status;
 	char *p = NULL;
@@ -529,11 +504,16 @@
 		return;
 	}
 
-	sb = vsb_newauto();
-	XXXAN(sb);
-	vf = mgt_VccCompileFile(sb, av[3], 0, -1);
-	vsb_finish(sb);
-	AZ(vsb_overflowed(sb));
+	vcl = vreadfile(av[3]);
+	if (vcl == NULL) {
+		cli_out(cli, "Cannot open '%s'", av[3]);
+		cli_result(cli, CLIS_PARAM);
+		return;
+	}
+
+	vf = mgt_VccCompile(&sb, vcl, 0);
+	free(vcl);
+
 	if (vsb_len(sb) > 0)
 		cli_out(cli, "%s", vsb_data(sb));
 	vsb_delete(sb);
@@ -577,7 +557,7 @@
 	vp = mcf_find_vcl(cli, av[2]);
 	if (vp == NULL)
 		return;
-	if (vp->active != 0) 
+	if (vp->active != 0)
 		return;
 	if (child_pid >= 0 &&
 	    mgt_cli_askchild(&status, &p, "vcl.use %s\n", av[2])) {
diff -Nru 2.0.3/varnish-cache/bin/varnishd/shmlog.c trunk/varnish-cache/bin/varnishd/shmlog.c
--- 2.0.3/varnish-cache/bin/varnishd/shmlog.c	2008-10-16 07:43:08.000000000 +0200
+++ trunk/varnish-cache/bin/varnishd/shmlog.c	2009-01-05 14:45:27.000000000 +0100
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: shmlog.c 2993 2008-07-22 14:40:33Z phk $
+ * $Id: shmlog.c 3428 2008-11-24 15:53:26Z phk $
  */
 
 #include "config.h"
@@ -64,7 +64,7 @@
 struct varnish_stats *VSL_stats;
 static struct shmloghead *loghead;
 static unsigned char *logstart;
-static MTX vsl_mtx;
+static pthread_mutex_t vsl_mtx;
 
 
 static void
@@ -81,12 +81,14 @@
 vsl_hdr(enum shmlogtag tag, unsigned char *p, unsigned len, unsigned id)
 {
 
+	assert(len < 0x10000);
+	assert(id < 0x10000);
 	p[__SHMLOG_LEN_HIGH] = (len >> 8) & 0xff;
 	p[__SHMLOG_LEN_LOW] = len & 0xff;
 	p[__SHMLOG_ID_HIGH] = (id >> 8) & 0xff;
 	p[__SHMLOG_ID_LOW] = id & 0xff;
 	p[SHMLOG_DATA + len] = '\0';
-	p[SHMLOG_NEXTTAG + len] = SLT_ENDMARKER;	
+	p[SHMLOG_NEXTTAG + len] = SLT_ENDMARKER;
 	/* XXX: Write barrier here */
 	p[SHMLOG_TAG] = tag;
 }
@@ -100,14 +102,15 @@
 VSLR(enum shmlogtag tag, int id, txt t)
 {
 	unsigned char *p;
-	unsigned l;
+	unsigned l, mlen;
 
 	Tcheck(t);
+	mlen = params->shm_reclen;
 
 	/* Truncate */
 	l = Tlen(t);
-	if (l > 255) {
-		l = 255;
+	if (l > mlen) {
+		l = mlen;
 		t.e = t.b + l;
 	}
 
@@ -136,11 +139,12 @@
 {
 	va_list ap;
 	unsigned char *p;
-	unsigned n;
+	unsigned n, mlen;
 	txt t;
 
 	AN(fmt);
 	va_start(ap, fmt);
+	mlen = params->shm_reclen;
 
 	if (strchr(fmt, '%') == NULL) {
 		t.b = TRUST_ME(fmt);
@@ -153,13 +157,14 @@
 		assert(loghead->ptr < loghead->size);
 
 		/* Wrap if we cannot fit a full size record */
-		if (loghead->ptr + SHMLOG_NEXTTAG + 255 + 1 >= loghead->size)
+		if (loghead->ptr + SHMLOG_NEXTTAG + mlen + 1 >= loghead->size)
 			vsl_wrap();
 
 		p = logstart + loghead->ptr;
-		n = vsnprintf((char *)(p + SHMLOG_DATA), 256, fmt, ap);
-		if (n > 255)
-			n = 255; 	/* we truncate long fields */
+		/* +1 for the NUL */
+		n = vsnprintf((char *)(p + SHMLOG_DATA), mlen + 1, fmt, ap);
+		if (n > mlen)
+			n = mlen;		/* we truncate long fields */
 		vsl_hdr(tag, p, n, id);
 		loghead->ptr += SHMLOG_NEXTTAG + n;
 		assert(loghead->ptr < loghead->size);
@@ -203,14 +208,15 @@
 WSLR(struct worker *w, enum shmlogtag tag, int id, txt t)
 {
 	unsigned char *p;
-	unsigned l;
+	unsigned l, mlen;
 
 	Tcheck(t);
+	mlen = params->shm_reclen;
 
 	/* Truncate */
 	l = Tlen(t);
-	if (l > 255) {
-		l = 255;
+	if (l > mlen) {
+		l = mlen;
 		t.e = t.b + l;
 	}
 
@@ -234,11 +240,12 @@
 {
 	va_list ap;
 	unsigned char *p;
-	unsigned n;
+	unsigned n, mlen;
 	txt t;
 
 	AN(fmt);
 	va_start(ap, fmt);
+	mlen = params->shm_reclen;
 
 	if (strchr(fmt, '%') == NULL) {
 		t.b = TRUST_ME(fmt);
@@ -248,13 +255,14 @@
 		assert(w->wlp < w->wle);
 
 		/* Wrap if we cannot fit a full size record */
-		if (w->wlp + SHMLOG_NEXTTAG + 255 + 1 >= w->wle)
+		if (w->wlp + SHMLOG_NEXTTAG + mlen + 1 >= w->wle)
 			WSL_Flush(w, 1);
 
 		p = w->wlp;
-		n = vsnprintf((char *)(p + SHMLOG_DATA), 256, fmt, ap);
-		if (n > 255)
-			n = 255; 	/* we truncate long fields */
+		/* +1 for the NUL */
+		n = vsnprintf((char *)(p + SHMLOG_DATA), mlen + 1, fmt, ap);
+		if (n > mlen)
+			n = mlen;	/* we truncate long fields */
 		vsl_hdr(tag, p, n, id);
 		w->wlp += SHMLOG_NEXTTAG + n;
 		assert(w->wlp < w->wle);
@@ -287,7 +295,7 @@
 	assert(loghead->hdrsize == sizeof *loghead);
 	/* XXX more check sanity of loghead  ? */
 	logstart = (unsigned char *)loghead + loghead->start;
-	MTX_INIT(&vsl_mtx);
+	AZ(pthread_mutex_init(&vsl_mtx, NULL));
 	loghead->starttime = TIM_real();
 	loghead->panicstr[0] = '\0';
 	memset(VSL_stats, 0, sizeof *VSL_stats);
diff -Nru 2.0.3/varnish-cache/bin/varnishd/stevedore.c trunk/varnish-cache/bin/varnishd/stevedore.c
--- 2.0.3/varnish-cache/bin/varnishd/stevedore.c	2008-10-16 07:43:08.000000000 +0200
+++ trunk/varnish-cache/bin/varnishd/stevedore.c	2008-11-10 09:23:00.000000000 +0100
@@ -25,7 +25,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: stevedore.c 3025 2008-07-25 15:27:04Z phk $
+ * $Id: stevedore.c 3363 2008-11-09 13:46:57Z phk $
  */
 
 #include "config.h"
@@ -40,7 +40,7 @@
 static VTAILQ_HEAD(, stevedore)	stevedores =
     VTAILQ_HEAD_INITIALIZER(stevedores);
 
-static struct stevedore * volatile stv_next;
+static const struct stevedore * volatile stv_next;
 
 struct storage *
 STV_alloc(struct sess *sp, size_t size)
@@ -105,7 +105,7 @@
 
 	if (stv->init != NULL)
 		stv->init(stv, ac, av);
-	else if (ac != 0) 
+	else if (ac != 0)
 		ARGV_ERR("(-s%s) too many arguments\n", stv->name);
 
 	VTAILQ_INSERT_TAIL(&stevedores, stv, list);
diff -Nru 2.0.3/varnish-cache/bin/varnishd/storage_file.c trunk/varnish-cache/bin/varnishd/storage_file.c
--- 2.0.3/varnish-cache/bin/varnishd/storage_file.c	2008-10-16 07:43:08.000000000 +0200
+++ trunk/varnish-cache/bin/varnishd/storage_file.c	2009-01-05 14:45:27.000000000 +0100
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: storage_file.c 3072 2008-08-11 07:47:24Z phk $
+ * $Id: storage_file.c 3474 2008-12-18 12:16:45Z phk $
  *
  * Storage method based on mmap'ed file
  */
@@ -38,7 +38,6 @@
 #include <sys/socket.h>
 #include <sys/stat.h>
 
-#include "config.h"
 #ifdef HAVE_SYS_MOUNT_H
 #include <sys/mount.h>
 #endif
@@ -116,7 +115,7 @@
 	struct smfhead		order;
 	struct smfhead		free[NBUCKET];
 	struct smfhead		used;
-	MTX			mtx;
+	struct lock		mtx;
 };
 
 /*--------------------------------------------------------------------*/
@@ -185,7 +184,7 @@
 	i = 0;
 	while(1) {
 		o = l;
-		if (o == l && o > 0) 
+		if (o == l && o > 0)
 			break;
 		l >>= 1;
 		i++;
@@ -234,8 +233,8 @@
 	/* XXX: force block allocation here or in open ? */
 }
 
-static char default_size[] = "50%";
-static char default_filename[] = ".";
+static const char default_size[] = "50%";
+static const char default_filename[] = ".";
 
 static void
 smf_init(struct stevedore *parent, int ac, char * const *av)
@@ -303,7 +302,7 @@
 
 	if (S_ISREG(st.st_mode)) {
 		sc->fd = open(fn, O_RDWR);
-		if (sc->fd < 0) 
+		if (sc->fd < 0)
 			ARGV_ERR("(-sfile) \"%s\" could not open (%s)\n",
 			    fn, strerror(errno));
 		AZ(fstat(sc->fd, &st));
@@ -344,6 +343,7 @@
 
 	assert(sp->alloc == 0);
 	assert(sp->flist == NULL);
+	Lck_AssertHeld(&sc->mtx);
 	b = sp->size / sc->pagesize;
 	if (b >= NBUCKET) {
 		b = NBUCKET - 1;
@@ -373,6 +373,7 @@
 
 	assert(sp->alloc == 0);
 	assert(sp->flist != NULL);
+	Lck_AssertHeld(&sc->mtx);
 	b = sp->size / sc->pagesize;
 	if (b >= NBUCKET) {
 		b = NBUCKET - 1;
@@ -603,14 +604,16 @@
 
 	sc = st->priv;
 
+	Lck_New(&sc->mtx);
+	Lck_Lock(&sc->mtx);
 	smf_open_chunk(sc, sc->filesize, 0, &fail, &sum);
+	Lck_Unlock(&sc->mtx);
 	printf("managed to mmap %ju bytes of %ju\n",
 	    (uintmax_t)sum, sc->filesize);
 
 	/* XXX */
 	if (sum < MINPAGES * (off_t)getpagesize())
 		exit (2);
-	MTX_INIT(&sc->mtx);
 
 	VSL_stats->sm_bfree += sc->filesize;
 }
@@ -626,18 +629,18 @@
 	assert(size > 0);
 	size += (sc->pagesize - 1);
 	size &= ~(sc->pagesize - 1);
-	LOCK(&sc->mtx);
+	Lck_Lock(&sc->mtx);
 	VSL_stats->sm_nreq++;
 	smf = alloc_smf(sc, size);
 	if (smf == NULL) {
-		UNLOCK(&sc->mtx);
+		Lck_Unlock(&sc->mtx);
 		return (NULL);
 	}
 	CHECK_OBJ_NOTNULL(smf, SMF_MAGIC);
 	VSL_stats->sm_nobj++;
 	VSL_stats->sm_balloc += smf->size;
 	VSL_stats->sm_bfree -= smf->size;
-	UNLOCK(&sc->mtx);
+	Lck_Unlock(&sc->mtx);
 	CHECK_OBJ_NOTNULL(&smf->s, STORAGE_MAGIC);	/*lint !e774 */
 	XXXAN(smf);
 	assert(smf->size == size);
@@ -669,12 +672,12 @@
 	size += (sc->pagesize - 1);
 	size &= ~(sc->pagesize - 1);
 	if (smf->size > size) {
-		LOCK(&sc->mtx);
+		Lck_Lock(&sc->mtx);
 		VSL_stats->sm_balloc -= (smf->size - size);
 		VSL_stats->sm_bfree += (smf->size - size);
 		trim_smf(smf, size);
 		assert(smf->size == size);
-		UNLOCK(&sc->mtx);
+		Lck_Unlock(&sc->mtx);
 		smf->s.space = size;
 	}
 }
@@ -691,12 +694,12 @@
 	CHECK_OBJ_NOTNULL(s, STORAGE_MAGIC);
 	CAST_OBJ_NOTNULL(smf, s->priv, SMF_MAGIC);
 	sc = smf->sc;
-	LOCK(&sc->mtx);
+	Lck_Lock(&sc->mtx);
 	VSL_stats->sm_nobj--;
 	VSL_stats->sm_balloc -= smf->size;
 	VSL_stats->sm_bfree += smf->size;
 	free_smf(smf);
-	UNLOCK(&sc->mtx);
+	Lck_Unlock(&sc->mtx);
 }
 
 /*--------------------------------------------------------------------*/
diff -Nru 2.0.3/varnish-cache/bin/varnishd/storage_malloc.c trunk/varnish-cache/bin/varnishd/storage_malloc.c
--- 2.0.3/varnish-cache/bin/varnishd/storage_malloc.c	2009-01-09 15:38:46.000000000 +0100
+++ trunk/varnish-cache/bin/varnishd/storage_malloc.c	2009-01-05 14:45:27.000000000 +0100
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: storage_malloc.c 3036 2008-07-31 09:24:25Z phk $
+ * $Id: storage_malloc.c 3401 2008-11-18 13:29:34Z tfheen $
  *
  * Storage method based on malloc(3)
  */
@@ -44,7 +44,7 @@
 #include "stevedore.h"
 
 static size_t			sma_max = SIZE_MAX;
-static MTX			sma_mtx;
+static struct lock		sma_mtx;
 
 struct sma {
 	struct storage		s;
@@ -56,7 +56,7 @@
 {
 	struct sma *sma;
 
-	LOCK(&sma_mtx);
+	Lck_Lock(&sma_mtx);
 	VSL_stats->sma_nreq++;
 	if (VSL_stats->sma_nbytes + size > sma_max)
 		size = 0;
@@ -65,7 +65,7 @@
 		VSL_stats->sma_nbytes += size;
 		VSL_stats->sma_balloc += size;
 	}
-	UNLOCK(&sma_mtx);
+	Lck_Unlock(&sma_mtx);
 
 	if (size == 0)
 		return (NULL);
@@ -94,11 +94,11 @@
 	CHECK_OBJ_NOTNULL(s, STORAGE_MAGIC);
 	sma = s->priv;
 	assert(sma->sz == sma->s.space);
-	LOCK(&sma_mtx);
+	Lck_Lock(&sma_mtx);
 	VSL_stats->sma_nobj--;
 	VSL_stats->sma_nbytes -= sma->sz;
 	VSL_stats->sma_bfree += sma->sz;
-	UNLOCK(&sma_mtx);
+	Lck_Unlock(&sma_mtx);
 	free(sma->s.ptr);
 	free(sma);
 }
@@ -113,11 +113,11 @@
 	sma = s->priv;
 	assert(sma->sz == sma->s.space);
 	if ((p = realloc(sma->s.ptr, size)) != NULL) {
-		LOCK(&sma_mtx);
+		Lck_Lock(&sma_mtx);
 		VSL_stats->sma_nbytes -= (sma->sz - size);
 		VSL_stats->sma_bfree += sma->sz - size;
 		sma->sz = size;
-		UNLOCK(&sma_mtx);
+		Lck_Unlock(&sma_mtx);
 		sma->s.ptr = p;
 		sma->s.space = size;
 	}
@@ -132,7 +132,7 @@
 	(void)parent;
 
 	AZ(av[ac]);
-	if (ac > 1) 
+	if (ac > 1)
 		ARGV_ERR("(-smalloc) too many arguments\n");
 
 	if (ac == 0 || *av[0] == '\0')
@@ -141,7 +141,7 @@
 	e = str2bytes(av[0], &u, 0);
 	if (e != NULL)
 		ARGV_ERR("(-smalloc) size \"%s\": %s\n", av[0], e);
-	if ((u != (uintmax_t)(size_t)u)) 
+	if ((u != (uintmax_t)(size_t)u))
 		ARGV_ERR("(-smalloc) size \"%s\": too big\n", av[0]);
 
 	printf("storage_malloc: max size %ju MB.\n",
@@ -153,7 +153,7 @@
 sma_open(const struct stevedore *st)
 {
 	(void)st;
-	AZ(pthread_mutex_init(&sma_mtx, NULL));
+	Lck_New(&sma_mtx);
 }
 
 struct stevedore sma_stevedore = {
diff -Nru 2.0.3/varnish-cache/bin/varnishd/storage_synth.c trunk/varnish-cache/bin/varnishd/storage_synth.c
--- 2.0.3/varnish-cache/bin/varnishd/storage_synth.c	2008-10-16 07:43:08.000000000 +0200
+++ trunk/varnish-cache/bin/varnishd/storage_synth.c	2009-01-05 14:45:27.000000000 +0100
@@ -25,7 +25,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: storage_synth.c 3300 2008-10-15 09:52:15Z tfheen $
+ * $Id: storage_synth.c 3405 2008-11-19 11:58:48Z phk $
  *
  * Storage method for synthetic content, based on vsb.
  */
@@ -42,19 +42,20 @@
 #include "cache.h"
 #include "vsb.h"
 #include "stevedore.h"
+#include "hash_slinger.h"
 
-static MTX			sms_mtx;
+static struct lock		sms_mtx;
 
 static void
 sms_free(struct storage *sto)
 {
 
 	CHECK_OBJ_NOTNULL(sto, STORAGE_MAGIC);
-	LOCK(&sms_mtx);
+	Lck_Lock(&sms_mtx);
 	VSL_stats->sms_nobj--;
 	VSL_stats->sms_nbytes -= sto->len;
 	VSL_stats->sms_bfree += sto->len;
-	UNLOCK(&sms_mtx);
+	Lck_Unlock(&sms_mtx);
 	vsb_delete(sto->priv);
 	free(sto);
 }
@@ -63,7 +64,7 @@
 SMS_Init(void)
 {
 
-	AZ(pthread_mutex_init(&sms_mtx, NULL));
+	Lck_New(&sms_mtx);
 }
 
 static struct stevedore sms_stevedore = {
@@ -82,10 +83,10 @@
 	HSH_Freestore(obj);
 	obj->len = 0;
 
-	LOCK(&sms_mtx);
+	Lck_Lock(&sms_mtx);
 	VSL_stats->sms_nreq++;
 	VSL_stats->sms_nobj++;
-	UNLOCK(&sms_mtx);
+	Lck_Unlock(&sms_mtx);
 
 	sto = calloc(sizeof *sto, 1);
 	XXXAN(sto);
diff -Nru 2.0.3/varnish-cache/bin/varnishd/storage_umem.c trunk/varnish-cache/bin/varnishd/storage_umem.c
--- 2.0.3/varnish-cache/bin/varnishd/storage_umem.c	2008-10-16 07:43:08.000000000 +0200
+++ trunk/varnish-cache/bin/varnishd/storage_umem.c	2008-11-11 14:27:27.000000000 +0100
@@ -26,14 +26,14 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: storage_umem.c 3300 2008-10-15 09:52:15Z tfheen $
+ * $Id: storage_umem.c 3381 2008-11-10 19:46:25Z phk $
  *
  * Storage method based on umem_alloc(3MALLOC)
  */
 
 #include "config.h"
 
-#ifdef HAVE_UMEM_H
+#ifdef HAVE_LIBUMEM
 
 #include <sys/types.h>
 
@@ -61,7 +61,7 @@
 {
 	struct smu *smu;
 
-	LOCK(&smu_mtx);
+	Lck_Lock(&smu_mtx);
 	VSL_stats->sma_nreq++;
 	if (VSL_stats->sma_nbytes + size > smu_max)
 		size = 0;
@@ -70,7 +70,7 @@
 		VSL_stats->sma_nbytes += size;
 		VSL_stats->sma_balloc += size;
 	}
-	UNLOCK(&smu_mtx);
+	Lck_Unlock(&smu_mtx);
 
 	if (size == 0)
 		return (NULL);
@@ -99,11 +99,11 @@
 	CHECK_OBJ_NOTNULL(s, STORAGE_MAGIC);
 	smu = s->priv;
 	assert(smu->sz == smu->s.space);
-	LOCK(&smu_mtx);
+	Lck_Lock(&smu_mtx);
 	VSL_stats->sma_nobj--;
 	VSL_stats->sma_nbytes -= smu->sz;
 	VSL_stats->sma_bfree += smu->sz;
-	UNLOCK(&smu_mtx);
+	Lck_Unlock(&smu_mtx);
 	umem_free(smu->s.ptr, smu->s.space);
 	umem_free(smu, sizeof *smu);
 }
@@ -120,11 +120,11 @@
 	if ((p = umem_alloc(size, UMEM_DEFAULT)) != NULL) {
 		memcpy(p, smu->s.ptr, size);
 		umem_free(smu->s.ptr, smu->s.space);
-		LOCK(&smu_mtx);
+		Lck_Lock(&smu_mtx);
 		VSL_stats->sma_nbytes -= (smu->sz - size);
 		VSL_stats->sma_bfree += smu->sz - size;
 		smu->sz = size;
-		UNLOCK(&smu_mtx);
+		Lck_Unlock(&smu_mtx);
 		smu->s.ptr = p;
 		smu->s.space = size;
 	}
@@ -139,7 +139,7 @@
 	(void)parent;
 
 	AZ(av[ac]);
-	if (ac > 1) 
+	if (ac > 1)
 		ARGV_ERR("(-sumem) too many arguments\n");
 
 	if (ac == 0 || *av[0] == '\0')
@@ -148,7 +148,7 @@
 	e = str2bytes(av[0], &u, 0);
 	if (e != NULL)
 		ARGV_ERR("(-sumem) size \"%s\": %s\n", av[0], e);
-	if ((u != (uintmax_t)(size_t)u)) 
+	if ((u != (uintmax_t)(size_t)u))
 		ARGV_ERR("(-sumem) size \"%s\": too big\n", av[0]);
 	smu_max = u;
 }
--- 2.0.3/varnish-cache/bin/varnishd/varnishd.1	2009-01-09 15:39:00.000000000 +0100
+++ trunk/varnish-cache/bin/varnishd/varnishd.1	2009-01-05 14:45:27.000000000 +0100
@@ -26,7 +26,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\" $Id: varnishd.1 3240 2008-09-29 12:10:12Z tfheen $
+.\" $Id: varnishd.1 3411 2008-11-20 11:01:26Z petter $
 .\"
 .Dd March 8, 2008
 .Dt VARNISHD 1
@@ -405,6 +405,15 @@
 .Pp
 The default is
 .Dv off .
+.It Va between_bytes_timeout
+Default timeout between bytes when receiving data from backend.
+We only wait for this many seconds between bytes before giving up.
+A value of 0 means it will never time out.
+VCL can override this default value for each backend and backend request.
+This parameter does not apply to pipe.
+.Pp
+The default is
+.Dv 60 seconds
 .It Va client_http11
 Whether to force the use of HTTP/1.1 when responding to client
 requests, or just use the same protocol version as that used by the
@@ -412,6 +421,13 @@
 .Pp
 The default is
 .Dv off .
+.It Va connect_timeout
+Default connection timeout for backend connections.
+We only try to connect to the backend for this many seconds before giving up.
+VCL can override this default value for each backend and backend request.
+.Pp
+The default is
+.Dv 0.4 seconds
 .It Va default_ttl
 The default time-to-live assigned to objects if neither the backend
 nor the configuration assign one.
@@ -427,6 +443,15 @@
 backend server does not specify a content length.
 .Pp
 The default is 128 kilobytes.
+.It Va first_byte_timeout
+Default timeout for receiving first byte from backend.
+We only wait for this many seconds for the first byte before giving up.
+A value of 0 means it will never time out.
+VCL can override this default value for each backend and backend request.
+This parameter does not apply to pipe.
+.Pp
+The default is
+.Dv 60 seconds
 .It Va group
 The name of an unprivileged group to which the child process should
 switch before it starts accepting connections.
diff -Nru 2.0.3/varnish-cache/bin/varnishd/varnishd.c trunk/varnish-cache/bin/varnishd/varnishd.c
--- 2.0.3/varnish-cache/bin/varnishd/varnishd.c	2008-10-16 07:43:08.000000000 +0200
+++ trunk/varnish-cache/bin/varnishd/varnishd.c	2009-01-05 14:45:27.000000000 +0100
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: varnishd.c 3137 2008-08-27 14:22:03Z phk $
+ * $Id: varnishd.c 3497 2008-12-21 18:42:48Z phk $
  *
  * The management process and CLI handling
  */
@@ -59,6 +59,7 @@
 
 #include "vsb.h"
 #include "vpf.h"
+#include "vsha256.h"
 
 #include "cli.h"
 #include "cli_priv.h"
@@ -117,7 +118,7 @@
 extern struct stevedore smu_stevedore;
 #endif
 
-static struct choice stv_choice[] = {
+static const struct choice stv_choice[] = {
 	{ "file",	&smf_stevedore },
 	{ "malloc",	&sma_stevedore },
 #ifdef HAVE_LIBUMEM
@@ -136,7 +137,7 @@
 	av = ParseArgv(spec, ARGV_COMMA);
 	AN(av);
 
-	if (av[0] != NULL) 
+	if (av[0] != NULL)
 		ARGV_ERR("%s\n", av[0]);
 
 	if (av[1] == NULL)
@@ -157,11 +158,13 @@
 
 extern struct hash_slinger hsl_slinger;
 extern struct hash_slinger hcl_slinger;
+extern struct hash_slinger hcb_slinger;
 
-static struct choice hsh_choice[] = {
+static const struct choice hsh_choice[] = {
 	{ "classic",		&hcl_slinger },
 	{ "simple",		&hsl_slinger },
 	{ "simple_list",	&hsl_slinger },	/* backwards compat */
+	{ "critbit",		&hcb_slinger },
 	{ NULL,			NULL }
 };
 
@@ -175,7 +178,7 @@
 	av = ParseArgv(h_arg, ARGV_COMMA);
 	AN(av);
 
-	if (av[0] != NULL) 
+	if (av[0] != NULL)
 		ARGV_ERR("%s\n", av[0]);
 
 	if (av[1] == NULL)
@@ -226,7 +229,8 @@
 	fprintf(stderr, FMT, "", "  -s file  [default: use /tmp]");
 	fprintf(stderr, FMT, "", "  -s file,<dir_or_file>");
 	fprintf(stderr, FMT, "", "  -s file,<dir_or_file>,<size>");
-	fprintf(stderr, FMT, "", "  -s file,<dir_or_file>,<size>,<granularity>");
+	fprintf(stderr, FMT, "",
+	    "  -s file,<dir_or_file>,<size>,<granularity>");
 	fprintf(stderr, FMT, "-t", "Default TTL");
 	fprintf(stderr, FMT, "-T address:port",
 	    "Telnet listen address and port");
@@ -252,10 +256,10 @@
 	av = ParseArgv(argv, ARGV_COMMA);
 	AN(av);
 
-	if (av[0] != NULL) 
+	if (av[0] != NULL)
 		ARGV_ERR("%s\n", av[0]);
 
-	if (av[1] == NULL) 
+	if (av[1] == NULL)
 		usage();
 
 	u = arg_ul(av[1]);
@@ -423,14 +427,13 @@
 	const char *l_arg = "80m";
 	uintmax_t l_size;
 	const char *q;
-	int f_fd = -1;
 	const char *h_arg = "classic";
 	const char *n_arg = NULL;
 	const char *P_arg = NULL;
 	const char *s_arg = "file";
 	int s_arg_given = 0;
 	const char *T_arg = NULL;
-	char *p;
+	char *p, *vcl = NULL;
 	struct cli cli[1];
 	struct pidfh *pfh = NULL;
 	char dirname[1024];
@@ -450,6 +453,11 @@
 	assert(TIM_parse("Sunday, 06-Nov-94 08:49:37 GMT") == 784111777);
 	assert(TIM_parse("Sun Nov  6 08:49:37 1994") == 784111777);
 
+	/*
+	 * Check that our SHA256 works
+	 */
+	SHA256_Test();
+
 	memset(cli, 0, sizeof cli);
 	cli[0].sb = vsb_newauto();
 	XXXAN(cli[0].sb);
@@ -462,7 +470,8 @@
 	MCF_ParamInit(cli);
 	cli_check(cli);
 
-	while ((o = getopt(argc, argv, "a:b:Cdf:Fg:h:l:n:P:p:s:T:t:u:Vw:")) != -1)
+	while ((o = getopt(argc, argv,
+	    "a:b:Cdf:Fg:h:l:n:P:p:s:T:t:u:Vw:")) != -1)
 		switch (o) {
 		case 'a':
 			MCF_ParamSet(cli, "listen_address", optarg);
@@ -534,7 +543,7 @@
 	argv += optind;
 
 	if (argc != 0) {
-		fprintf(stderr, "Too many arguments\n");
+		fprintf(stderr, "Too many arguments (%s...)\n", argv[0]);
 		usage();
 	}
 
@@ -565,9 +574,9 @@
 	}
 
 	if (f_arg != NULL) {
-		f_fd = open(f_arg, O_RDONLY);
-		if (f_fd < 0) {
-			fprintf(stderr, "Cannot open '%s': %s\n",
+		vcl = vreadfile(f_arg);
+		if (vcl == NULL) {
+			fprintf(stderr, "Cannot read '%s': %s\n",
 			    f_arg, strerror(errno));
 			exit(1);
 		}
@@ -580,7 +589,7 @@
 		exit(1);
 	}
 
-	if (n_arg != NULL) 
+	if (n_arg != NULL)
 		openlog(n_arg, LOG_PID, LOG_LOCAL0);
 	else
 		openlog("varnishd", LOG_PID, LOG_LOCAL0);
@@ -604,7 +613,7 @@
 	}
 
 	if (b_arg != NULL || f_arg != NULL)
-		if (mgt_vcc_default(b_arg, f_arg, f_fd, C_flag))
+		if (mgt_vcc_default(b_arg, vcl, C_flag))
 			exit (2);
 
 	if (C_flag)
@@ -624,7 +633,7 @@
 	if (d_flag == 1)
 		printf("%d\n", getpid());
 
-	if (pfh != NULL && vpf_write(pfh)) 
+	if (pfh != NULL && vpf_write(pfh))
 		fprintf(stderr, "NOTE: Could not write PID file\n");
 
 	mgt_run(d_flag, T_arg);
Binary files 2.0.3/varnish-cache/bin/varnishd/varnishtest and trunk/varnish-cache/bin/varnishd/varnishtest differ
diff -Nru 2.0.3/varnish-cache/bin/varnishd/vparam.h trunk/varnish-cache/bin/varnishd/vparam.h
--- 2.0.3/varnish-cache/bin/varnishd/vparam.h	1970-01-01 01:00:00.000000000 +0100
+++ trunk/varnish-cache/bin/varnishd/vparam.h	2009-01-05 14:45:27.000000000 +0100
@@ -0,0 +1,61 @@
+/*-
+ * Copyright (c) 2006 Verdens Gang AS
+ * Copyright (c) 2006-2008 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: mgt_param.c 3440 2008-11-25 13:39:15Z phk $
+ */
+
+struct parspec;
+
+typedef void tweak_t(struct cli *, const struct parspec *, const char *arg);
+
+struct parspec {
+	const char	*name;
+	tweak_t		*func;
+	volatile void	*priv;
+	unsigned	umin;
+	unsigned	umax;
+	const char	*descr;
+	int		 flags;
+#define DELAYED_EFFECT 1
+#define EXPERIMENTAL   2
+#define MUST_RESTART   4
+#define MUST_RELOAD    8
+	const char	*def;
+	const char	*units;
+};
+
+void tweak_generic_uint(struct cli *cli,
+    volatile unsigned *dest, const char *arg, unsigned min, unsigned max);
+void tweak_uint(struct cli *cli, const struct parspec *par, const char *arg);
+void tweak_timeout(struct cli *cli,
+    const struct parspec *par, const char *arg);
+
+extern struct params master;
+
+/* mgt_pool.c */
+extern const struct parspec WRK_parspec[];
diff -Nru 2.0.3/varnish-cache/bin/varnishhist/Makefile.in trunk/varnish-cache/bin/varnishhist/Makefile.in
diff -Nru 2.0.3/varnish-cache/bin/varnishhist/.svn/entries trunk/varnish-cache/bin/varnishhist/.svn/entries
diff -Nru 2.0.3/varnish-cache/bin/varnishhist/.svn/text-base/varnishhist.c.svn-base trunk/varnish-cache/bin/varnishhist/.svn/text-base/varnishhist.c.svn-base
diff -Nru 2.0.3/varnish-cache/bin/varnishhist/varnishhist.c trunk/varnish-cache/bin/varnishhist/varnishhist.c
--- 2.0.3/varnish-cache/bin/varnishhist/varnishhist.c	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/bin/varnishhist/varnishhist.c	2008-11-06 12:22:00.000000000 +0100
@@ -27,7 +27,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: varnishhist.c 3072 2008-08-11 07:47:24Z phk $
+ * $Id: varnishhist.c 3336 2008-10-20 18:47:24Z des $
  *
  * Log tailer for Varnish
  */
@@ -46,7 +46,6 @@
 #include <string.h>
 #include <unistd.h>
 
-#include "config.h"
 #include "libvarnish.h"
 #include "shmlog.h"
 #include "varnishapi.h"
@@ -147,7 +146,8 @@
 }
 
 static int
-h_hist(void *priv, enum shmlogtag tag, unsigned fd, unsigned len, unsigned spec, const char *ptr)
+h_hist(void *priv, enum shmlogtag tag, unsigned fd, unsigned len,
+    unsigned spec, const char *ptr)
 {
 	double b;
 	int i, j;
@@ -308,8 +308,8 @@
 static void
 usage(void)
 {
-	fprintf(stderr,
-	    "usage: varnishhist %s [-n varnish_name] [-V] [-w delay]\n", VSL_USAGE);
+	fprintf(stderr, "usage: varnishhist "
+	    "%s [-n varnish_name] [-V] [-w delay]\n", VSL_USAGE);
 	exit(1);
 }
 
diff -Nru 2.0.3/varnish-cache/bin/varnishlog/Makefile.in trunk/varnish-cache/bin/varnishlog/Makefile.in
diff -Nru 2.0.3/varnish-cache/bin/varnishlog/.svn/entries trunk/varnish-cache/bin/varnishlog/.svn/entries
diff -Nru 2.0.3/varnish-cache/bin/varnishlog/.svn/text-base/varnishlog.c.svn-base trunk/varnish-cache/bin/varnishlog/.svn/text-base/varnishlog.c.svn-base
diff -Nru 2.0.3/varnish-cache/bin/varnishlog/varnishlog.c trunk/varnish-cache/bin/varnishlog/varnishlog.c
--- 2.0.3/varnish-cache/bin/varnishlog/varnishlog.c	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/bin/varnishlog/varnishlog.c	2009-01-05 14:45:27.000000000 +0100
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: varnishlog.c 3104 2008-08-19 07:50:50Z phk $
+ * $Id: varnishlog.c 3421 2008-11-24 10:17:24Z phk $
  *
  * Log tailer for Varnish
  */
@@ -43,17 +43,10 @@
 #include <unistd.h>
 #include <limits.h>
 
-#include "config.h"
 #ifndef HAVE_DAEMON
 #include "compat/daemon.h"
 #endif
 
-#ifdef HAVE_VIS_H
-#include <vis.h>
-#else
-#include "compat/vis.h"
-#endif
-
 #include "vsb.h"
 #include "vpf.h"
 
@@ -120,7 +113,8 @@
 }
 
 static int
-h_order(void *priv, enum shmlogtag tag, unsigned fd, unsigned len, unsigned spec, const char *ptr)
+h_order(void *priv, enum shmlogtag tag, unsigned fd, unsigned len,
+    unsigned spec, const char *ptr)
 {
 	char type;
 
@@ -261,7 +255,7 @@
 
 	flags = (a_flag ? O_APPEND : O_TRUNC) | O_WRONLY | O_CREAT;
 #ifdef O_LARGEFILE
-        flags |= O_LARGEFILE;
+	flags |= O_LARGEFILE;
 #endif
 	if (!strcmp(w_arg, "-"))
 		fd = STDOUT_FILENO;
@@ -308,8 +302,8 @@
 static void
 usage(void)
 {
-	fprintf(stderr,
-	    "usage: varnishlog %s [-aDoV] [-n varnish_name] [-P file] [-w file]\n", VSL_USAGE);
+	fprintf(stderr, "usage: varnishlog "
+	    "%s [-aDoV] [-n varnish_name] [-P file] [-w file]\n", VSL_USAGE);
 	exit(1);
 }
 
diff -Nru 2.0.3/varnish-cache/bin/varnishncsa/Makefile.in trunk/varnish-cache/bin/varnishncsa/Makefile.in
diff -Nru 2.0.3/varnish-cache/bin/varnishncsa/.svn/entries trunk/varnish-cache/bin/varnishncsa/.svn/entries
diff -Nru 2.0.3/varnish-cache/bin/varnishncsa/.svn/text-base/varnishncsa.c.svn-base trunk/varnish-cache/bin/varnishncsa/.svn/text-base/varnishncsa.c.svn-base
diff -Nru 2.0.3/varnish-cache/bin/varnishncsa/.svn/tmp/tempfile.2.tmp trunk/varnish-cache/bin/varnishncsa/.svn/tmp/tempfile.2.tmp
diff -Nru 2.0.3/varnish-cache/bin/varnishncsa/.svn/tmp/tempfile.3.tmp trunk/varnish-cache/bin/varnishncsa/.svn/tmp/tempfile.3.tmp
diff -Nru 2.0.3/varnish-cache/bin/varnishncsa/varnishncsa.c trunk/varnish-cache/bin/varnishncsa/varnishncsa.c
--- 2.0.3/varnish-cache/bin/varnishncsa/varnishncsa.c	2008-11-10 11:10:09.000000000 +0100
+++ trunk/varnish-cache/bin/varnishncsa/varnishncsa.c	2008-11-06 12:22:00.000000000 +0100
@@ -27,7 +27,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: varnishncsa.c 3371 2008-11-10 10:10:09Z tfheen $
+ * $Id: varnishncsa.c 3344 2008-10-20 20:19:12Z des $
  *
  * Obtain log data from the shared memory log, order it by session ID, and
  * display it in Apache / NCSA combined log format:
@@ -71,7 +71,6 @@
 #include <unistd.h>
 #include <limits.h>
 
-#include "config.h"
 #ifndef HAVE_DAEMON
 #include "compat/daemon.h"
 #endif
@@ -105,7 +104,8 @@
 static int prefer_x_forwarded_for = 0;
 
 static int
-isprefix(const char *str, const char *prefix, const char *end, const char **next)
+isprefix(const char *str, const char *prefix, const char *end,
+    const char **next)
 {
 
 	while (str < end && *str && *prefix &&
@@ -511,7 +511,9 @@
 usage(void)
 {
 
-	fprintf(stderr, "usage: varnishncsa %s [-aDV] [-n varnish_name] [-P file] [-w file]\n", VSL_USAGE);
+	fprintf(stderr,
+	    "usage: varnishncsa %s [-aDV] [-n varnish_name] "
+	    "[-P file] [-w file]\n", VSL_USAGE);
 	exit(1);
 }
 
--- 2.0.3/varnish-cache/bin/varnishreplay/varnishreplay.c	2008-10-20 10:58:06.000000000 +0200
+++ trunk/varnish-cache/bin/varnishreplay/varnishreplay.c	2008-11-06 12:22:00.000000000 +0100
@@ -25,7 +25,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: varnishreplay.c 3326 2008-10-20 08:58:05Z tfheen $
+ * $Id: varnishreplay.c 3336 2008-10-20 18:47:24Z des $
  */
 
 #include "config.h"
@@ -43,7 +43,6 @@
 #include <string.h>
 #include <unistd.h>
 
-#include "config.h"
 #include "vqueue.h"
 
 #include "libvarnish.h"
@@ -251,7 +250,8 @@
 
 		while (fd >= newnthreads)
 			newnthreads += newnthreads + 1;
-		newthreads = realloc(newthreads, newnthreads * sizeof *newthreads);
+		newthreads = realloc(newthreads,
+		    newnthreads * sizeof *newthreads);
 		XXXAN(newthreads != NULL);
 		memset(newthreads + nthreads, 0,
 		    (newnthreads - nthreads) * sizeof *newthreads);
@@ -557,12 +557,15 @@
 
 		if (!thr->method || !thr->url || !thr->proto) {
 			thr->bogus = 1;
-		} else if (strcmp(thr->method, "GET") != 0 && strcmp(thr->method, "HEAD") != 0) {
+		} else if (strcmp(thr->method, "GET") != 0 &&
+		    strcmp(thr->method, "HEAD") != 0) {
 			thr->bogus = 1;
 		} else if (strcmp(thr->proto, "HTTP/1.0") == 0) {
-			reopen = !(thr->conn && strcasecmp(thr->conn, "keep-alive") == 0);
+			reopen = !(thr->conn &&
+			    strcasecmp(thr->conn, "keep-alive") == 0);
 		} else if (strcmp(thr->proto, "HTTP/1.1") == 0) {
-			reopen = (thr->conn && strcasecmp(thr->conn, "close") == 0);
+			reopen = (thr->conn &&
+			    strcasecmp(thr->conn, "close") == 0);
 		} else {
 			thr->bogus = 1;
 		}
@@ -701,7 +704,8 @@
 usage(void)
 {
 
-	fprintf(stderr, "usage: varnishreplay [-D] -a address:port -r logfile\n");
+	fprintf(stderr,
+	    "usage: varnishreplay [-D] -a address:port -r logfile\n");
 	exit(1);
 }
 
@@ -743,7 +747,11 @@
 	signal(SIGPIPE, SIG_IGN);
 
 	pthread_attr_init(&thread_attr);
-	/* XXX: seting the stack size manually reduces the memory usasage and increases speed */
+
+	/*
+	 * XXX: seting the stack size manually reduces the memory usage
+	 * XXX: (allowing more threads) and increases speed (?)
+	 */
 	pthread_attr_setstacksize(&thread_attr, 32768);
 
 	while (VSL_Dispatch(vd, gen_traffic, NULL) == 0)
--- 2.0.3/varnish-cache/bin/varnishstat/varnishstat.c	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/bin/varnishstat/varnishstat.c	2009-01-05 14:45:26.000000000 +0100
@@ -27,7 +27,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: varnishstat.c 3072 2008-08-11 07:47:24Z phk $
+ * $Id: varnishstat.c 3447 2008-12-01 14:13:49Z phk $
  *
  * Log tailer for Varnish
  */
@@ -46,13 +46,13 @@
 #include <time.h>
 #include <unistd.h>
 
-#include "config.h"
 #include "libvarnish.h"
 #include "shmlog.h"
 #include "varnishapi.h"
 
 #define FIELD_EXCLUSION_CHARACTER '^'
 
+
 static void
 myexp(double *acc, double val, unsigned *n, unsigned nmax)
 {
@@ -81,9 +81,10 @@
 
 		while (field_start != NULL) {
 			field_end = field_start + field_length;
-			if ((field_start == fields || *(field_start - 1) == ',') &&
-				(*field_end == ',' || *field_end == '\0'))
-					return (match_value);
+			if ((field_start == fields ||
+			    *(field_start - 1) == ',') &&
+			    (*field_end == ',' || *field_end == '\0'))
+				return (match_value);
 			field_start = strstr( field_end, field );
 		}
 	}
@@ -95,6 +96,7 @@
 do_curses(struct varnish_stats *VSL_stats, int delay, const char *fields)
 {
 	struct varnish_stats copy;
+	struct varnish_stats seen;
 	intmax_t ju;
 	struct timeval tv;
 	double tt, lt, hit, miss, ratio, up;
@@ -104,6 +106,7 @@
 	int ch, line;
 
 	memset(&copy, 0, sizeof copy);
+	memset(&seen, 0, sizeof seen);
 
 	a1 = a2 = a3 = 0.0;
 	n1 = n2 = n3 = 0;
@@ -144,13 +147,18 @@
 
 		line = 3;
 #define MAC_STAT(n, t, f, d) \
-	if ((fields == NULL || show_field( #n, fields )) && ++line < LINES) { \
+	if ((fields == NULL || show_field( #n, fields )) && line < LINES) { \
 		ju = VSL_stats->n; \
-		if (f == 'a') { \
+		if (ju == 0 && !seen.n) { \
+		} else if (f == 'a') { \
+			seen.n = 1; \
+			line++; \
 			mvprintw(line, 0, "%12ju %12.2f %12.2f %s\n", \
 			    ju, (ju - (intmax_t)copy.n)/lt, ju / up, d); \
 			copy.n = ju; \
 		} else { \
+			seen.n = 1; \
+			line++; \
 			mvprintw(line, 0, "%12ju %12s %12s %s\n", \
 			    ju, ".  ", ".  ", d); \
 		} \
@@ -237,14 +245,20 @@
 usage(void)
 {
 #define FMT "    %-28s # %s\n"
-	fprintf(stderr, "usage: varnishstat [-1lV] [-f field_list] [-n varnish_name] [-w delay]\n");
+	fprintf(stderr, "usage: varnishstat "
+	    "[-1lV] [-f field_list] [-n varnish_name] [-w delay]\n");
 	fprintf(stderr, FMT, "-1", "Print the statistics once and exit");
-	fprintf(stderr, FMT, "-f field_list", "Comma separated list of fields to display. ");
-	fprintf(stderr, FMT, "", "If it starts with '^' it is used as an exclusion list");
-	fprintf(stderr, FMT, "-l", "Lists the available fields to use with the -f option");
-	fprintf(stderr, FMT, "-n varnish_name", "The varnishd instance to get logs from");
+	fprintf(stderr, FMT, "-f field_list",
+	    "Comma separated list of fields to display. ");
+	fprintf(stderr, FMT, "",
+	    "If it starts with '^' it is used as an exclusion list");
+	fprintf(stderr, FMT, "-l",
+	    "Lists the available fields to use with the -f option");
+	fprintf(stderr, FMT, "-n varnish_name",
+	    "The varnishd instance to get logs from");
 	fprintf(stderr, FMT, "-V", "Display the version number and exit");
-	fprintf(stderr, FMT, "-w delay", "Wait delay seconds between updates.  The default is 1.");
+	fprintf(stderr, FMT, "-w delay",
+	    "Wait delay seconds between updates.  The default is 1.");
 #undef FMT
 	exit(1);
 }
@@ -252,7 +266,7 @@
 static void
 list_fields(void)
 {
-	fprintf(stderr, "Available fields to use with the varnishstat -f option:\n");
+	fprintf(stderr, "Varnishstat -f option fields:\n");
 	fprintf(stderr, "Field name           Description\n");
 	fprintf(stderr, "----------           -----------\n");
 	fprintf(stderr, "uptime               Child uptime\n");
@@ -290,7 +304,8 @@
 
 		valid_field = 0;
 		for (i = 0; all_fields[i] != NULL; i++) {
-			if (strncmp(field_start, all_fields[i], field_length) == 0 && field_length == strlen( all_fields[i] )) {
+			if (strncmp(field_start, all_fields[i], field_length)
+			     == 0 && field_length == strlen( all_fields[i])) {
 				valid_field = 1;
 				break;
 			}
@@ -346,7 +361,7 @@
 
 	if ((VSL_stats = VSL_OpenStats(n_arg)) == NULL)
 		exit(1);
-	
+
 	if (fields != NULL && !valid_fields(fields)) {
 		usage();
 		exit(1);
--- 2.0.3/varnish-cache/bin/varnishtest/c00019.vtc	2008-11-10 11:08:35.000000000 +0100
+++ trunk/varnish-cache/bin/varnishtest/c00019.vtc	1970-01-01 01:00:00.000000000 +0100
@@ -1,83 +0,0 @@
-# $Id$
-
-test "Check purge counters and duplicate purge elimination"
-
-server s1 {
-	rxreq
-	txresp -hdr "foo: 1" -body "foo1"
-	rxreq
-	txresp -hdr "foo: 2" -body "foo2"
-	rxreq
-	txresp -hdr "foo: 3" -body "foo3"
-} -start
-
-varnish v1 -vcl+backend {} -start
-
-varnish v1 -cliok "purge.url FOO"
-
-# There is one "magic" purge from boot
-varnish v1 -expect n_purge_add == 2
-varnish v1 -cliok "purge.list"
-
-# Our fetch is not affected by the purge
-# as the FOO-purge was preexisting
-client c1 {
-	txreq -url /FOO
-	rxresp
-	expect resp.http.foo == 1
-} -run
-
-varnish v1 -cliok "purge.list"
-varnish v1 -expect n_purge_obj_test == 0
-varnish v1 -expect n_purge_re_test == 0
-
-# Add another purge
-varnish v1 -cliok "purge.url FOO"
-varnish v1 -expect n_purge_add == 3
-varnish v1 -cliok "purge.list"
-
-# The cached object will be purged, and a new
-# fetched from the backend
-client c1 {
-	txreq -url /FOO
-	rxresp
-	expect resp.http.foo == 2
-} -run
-
-varnish v1 -expect n_purge_obj_test == 1
-varnish v1 -expect n_purge_re_test == 1
-varnish v1 -cliok "purge.list"
-
-# Fetch the cached copy, just for grins
-client c1 {
-	txreq -url /FOO
-	rxresp
-	expect resp.http.foo == 2
-} -run
-
-
-# Now add another purge
-varnish v1 -cliok "purge.url FOO"
-varnish v1 -expect n_purge_add == 4
-
-# Enable dup removal of purges
-varnish v1 -cliok "param.set purge_dups on"
-
-# This should incapacitate the to previous FOO purges.
-varnish v1 -cliok "purge.url FOO"
-varnish v1 -expect n_purge_add == 5
-varnish v1 -expect n_purge_dups == 3
-varnish v1 -cliok "purge.list"
-
-# And we should get a fresh object from backend
-client c1 {
-	txreq -url /FOO
-	rxresp
-	expect resp.http.foo == 3
-} -run
-
-# With only two objects having ever been compared
-varnish v1 -expect n_purge_obj_test == 2
-varnish v1 -expect n_purge_re_test == 2
-varnish v1 -cliok "purge.list"
-
--- 2.0.3/varnish-cache/bin/varnishtest/Makefile.am	2008-11-10 11:12:28.000000000 +0100
+++ trunk/varnish-cache/bin/varnishtest/Makefile.am	2008-11-06 12:22:00.000000000 +0100
@@ -1,4 +1,4 @@
-# $Id: Makefile.am 3374 2008-11-10 10:12:28Z tfheen $
+# $Id: Makefile.am 3356 2008-10-29 06:55:40Z ssm $
 
 TESTS_ENVIRONMENT = ./varnishtest
 TESTS = $(srcdir)/tests/*.vtc
--- 2.0.3/varnish-cache/bin/varnishtest/tests/b00001.vtc	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/bin/varnishtest/tests/b00001.vtc	2008-10-20 11:04:55.000000000 +0200
@@ -1,4 +1,4 @@
-# $Id: b00001.vtc 3052 2008-08-01 08:24:23Z phk $
+# $Id: b00001.vtc 3328 2008-10-20 09:04:54Z tfheen $
 
 test "Check that a pipe transaction works"
 
@@ -19,9 +19,6 @@
 	expect resp.status == 200
 } -run
 
-# Give varnish a chance to update stats
-delay .1
-
 varnish v1 -expect n_object == 0
 varnish v1 -expect client_conn == 1
 varnish v1 -expect client_req == 1
--- 2.0.3/varnish-cache/bin/varnishtest/tests/b00020.vtc	1970-01-01 01:00:00.000000000 +0100
+++ trunk/varnish-cache/bin/varnishtest/tests/b00020.vtc	2009-01-05 14:45:27.000000000 +0100
@@ -0,0 +1,34 @@
+# $Id: b00019.vtc 3300 2008-10-15 09:52:15Z tfheen $
+
+test "Check the between_bytes_timeout behaves from parameters"
+
+server s1 {
+	rxreq
+	send "HTTP/1.1 200 Ok\r\nConnection: close\r\n\r\n"
+	delay 1.5
+	send "Baba\n"
+} -start
+
+varnish v1 -vcl+backend {} -start
+varnish v1 -cliok "param.set between_bytes_timeout 1"
+
+client c1 {
+	txreq
+	rxresp
+	expect resp.status == 503
+} -run
+
+server s1 {
+	rxreq
+	send "HTTP/1.1 200 Ok\r\nConnection: close\r\n\r\n"
+	delay 0.5
+	send "Baba\n"
+	delay 0.5
+	send "Baba\n"
+} -start
+
+client c1 {
+	txreq
+	rxresp
+	expect resp.status == 200
+} -run
--- 2.0.3/varnish-cache/bin/varnishtest/tests/b00021.vtc	1970-01-01 01:00:00.000000000 +0100
+++ trunk/varnish-cache/bin/varnishtest/tests/b00021.vtc	2009-01-05 14:45:27.000000000 +0100
@@ -0,0 +1,37 @@
+# $Id: b00019.vtc 3300 2008-10-15 09:52:15Z tfheen $
+
+test "Check the between_bytes_timeout behaves from vcl"
+
+server s1 {
+	rxreq
+	send "HTTP/1.1 200 Ok\r\nConnection: close\r\n\r\n"
+	delay 1.5
+	send "Baba\n"
+} -start
+
+varnish v1 -vcl+backend {
+	sub vcl_miss {
+		set bereq.between_bytes_timeout = 1s;
+	}
+} -start
+
+client c1 {
+	txreq
+	rxresp
+	expect resp.status == 503
+} -run
+
+server s1 {
+	rxreq
+	send "HTTP/1.1 200 Ok\r\nConnection: close\r\n\r\n"
+	delay 0.5
+	send "Baba\n"
+	delay 0.5
+	send "Baba\n"
+} -start
+
+client c1 {
+	txreq
+	rxresp
+	expect resp.status == 200
+} -run
--- 2.0.3/varnish-cache/bin/varnishtest/tests/b00022.vtc	1970-01-01 01:00:00.000000000 +0100
+++ trunk/varnish-cache/bin/varnishtest/tests/b00022.vtc	2009-01-05 14:45:27.000000000 +0100
@@ -0,0 +1,39 @@
+# $Id: b00019.vtc 3300 2008-10-15 09:52:15Z tfheen $
+
+test "Check the between_bytes_timeout behaves from backend definition"
+
+server s1 {
+	rxreq
+	send "HTTP/1.1 200 Ok\r\nConnection: close\r\n\r\n"
+	delay 1.5
+	send "Baba\n"
+} -start
+
+varnish v1 -vcl {
+	backend b1 {
+		.host = "127.0.0.1";
+		.port = "9080";
+		.between_bytes_timeout = 1s;
+	}
+} -start
+
+client c1 {
+	txreq
+	rxresp
+	expect resp.status == 503
+} -run
+
+server s1 {
+	rxreq
+	send "HTTP/1.1 200 Ok\r\nConnection: close\r\n\r\n"
+	delay 0.5
+	send "Baba\n"
+	delay 0.5
+	send "Baba\n"
+} -start
+
+client c1 {
+	txreq
+	rxresp
+	expect resp.status == 200
+} -run
--- 2.0.3/varnish-cache/bin/varnishtest/tests/b00023.vtc	1970-01-01 01:00:00.000000000 +0100
+++ trunk/varnish-cache/bin/varnishtest/tests/b00023.vtc	2009-01-05 14:45:27.000000000 +0100
@@ -0,0 +1,31 @@
+# $Id: b00019.vtc 3300 2008-10-15 09:52:15Z tfheen $
+
+test "Check that the first_byte_timeout works from parameters"
+
+server s1 {
+	rxreq
+	delay 1.5
+	txresp -body "foo"
+} -start
+
+varnish v1 -vcl+backend {} -start
+varnish v1 -cliok "param.set first_byte_timeout 1"
+
+client c1 {
+	txreq
+	rxresp
+	expect resp.status == 503
+} -run
+
+
+server s1 {
+	rxreq
+	delay 0.5
+	txresp -body "foo"
+} -start
+
+client c1 {
+	txreq
+	rxresp
+	expect resp.status == 200
+} -run
--- 2.0.3/varnish-cache/bin/varnishtest/tests/b00024.vtc	1970-01-01 01:00:00.000000000 +0100
+++ trunk/varnish-cache/bin/varnishtest/tests/b00024.vtc	2009-01-05 14:45:27.000000000 +0100
@@ -0,0 +1,34 @@
+# $Id: b00019.vtc 3300 2008-10-15 09:52:15Z tfheen $
+
+test "Check that the first_byte_timeout works from vcl"
+
+server s1 {
+	rxreq
+	delay 1.5
+	txresp
+} -start
+
+varnish v1 -vcl+backend {
+	sub vcl_miss {
+		set bereq.first_byte_timeout = 1s;	
+	}
+} -start
+
+client c1 {
+	txreq
+	rxresp
+	expect resp.status == 503
+} -run
+
+
+server s1 {
+	rxreq
+	delay 0.5
+	txresp
+} -start
+
+client c1 {
+	txreq
+	rxresp
+	expect resp.status == 200
+} -run
--- 2.0.3/varnish-cache/bin/varnishtest/tests/b00025.vtc	1970-01-01 01:00:00.000000000 +0100
+++ trunk/varnish-cache/bin/varnishtest/tests/b00025.vtc	2009-01-05 14:45:27.000000000 +0100
@@ -0,0 +1,36 @@
+# $Id: b00019.vtc 3300 2008-10-15 09:52:15Z tfheen $
+
+test "Check that the first_byte_timeout works from backend definition"
+
+server s1 {
+	rxreq
+	delay 1.5
+	txresp
+} -start
+
+varnish v1 -vcl {
+	backend b1 {
+		.host = "127.0.0.1";
+		.port = "9080";
+		.first_byte_timeout = 1s;
+	}
+} -start
+
+client c1 {
+	txreq
+	rxresp
+	expect resp.status == 503
+} -run
+
+
+server s1 {
+	rxreq
+	delay 0.5
+	txresp
+} -start
+
+client c1 {
+	txreq
+	rxresp
+	expect resp.status == 200
+} -run
--- 2.0.3/varnish-cache/bin/varnishtest/tests/b00026.vtc	1970-01-01 01:00:00.000000000 +0100
+++ trunk/varnish-cache/bin/varnishtest/tests/b00026.vtc	2009-01-05 14:45:27.000000000 +0100
@@ -0,0 +1,50 @@
+# $Id: b00019.vtc 3300 2008-10-15 09:52:15Z tfheen $
+
+test "Check the precedence for timeouts"
+
+server s1 -listen 127.0.0.1:9080 {
+	rxreq
+	expect req.url == "from_backend"
+	delay 1; 
+	txresp
+} -start
+server s2 -listen 127.0.0.1:9180 {
+	rxreq
+	expect req.url == "from_vcl"
+	delay 1.5;
+	txresp
+} -start
+
+varnish v1 -vcl {
+	backend b1 {
+		.host = "127.0.0.1";
+		.port = "9080";
+		.first_byte_timeout = 2s;
+	}
+	backend b2 {
+		.host = "127.0.0.1";
+		.port = "9180";
+		.first_byte_timeout = 1s;
+	}
+
+	sub vcl_recv {
+		if (req.url  == "from_backend") {
+			set req.backend = b1;
+			pass;
+		}
+		set req.backend = b2;
+	}
+	sub vcl_miss {
+		set bereq.first_byte_timeout = 2s;
+	}
+} -start
+varnish v1 -cliok "param.set first_byte_timeout 0.5"
+
+client c1 {
+	txreq -url "from_backend"
+	rxresp
+	expect resp.status == 200
+	txreq -url "from_vcl"
+	rxresp
+	expect resp.status == 200
+} -run
--- 2.0.3/varnish-cache/bin/varnishtest/tests/b00027.vtc	1970-01-01 01:00:00.000000000 +0100
+++ trunk/varnish-cache/bin/varnishtest/tests/b00027.vtc	2009-01-05 14:45:27.000000000 +0100
@@ -0,0 +1,28 @@
+# $Id$
+
+test "test backend transmission corner cases"
+
+server s1 {
+	rxreq
+	txresp
+	rxreq
+	txresp -proto HTTP/1.0 -hdr "Connection: keep-alive"
+	rxreq
+	txresp -hdr "Transfer-encoding: foobar"
+} -start
+
+varnish v1 -vcl+backend {} -start
+
+client c1 {
+	txreq -url /foo
+	rxresp
+	expect resp.status == 200
+	expect resp.bodylen == 0
+	txreq -url /bar
+	rxresp
+	expect resp.status == 200
+	expect resp.bodylen == 0
+	txreq -url /barf
+	rxresp
+	expect resp.status == 503
+} -run
--- 2.0.3/varnish-cache/bin/varnishtest/tests/c00008.vtc	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/bin/varnishtest/tests/c00008.vtc	2009-01-05 14:45:27.000000000 +0100
@@ -1,11 +1,12 @@
-# $Id: c00008.vtc 2906 2008-07-08 10:29:07Z phk $
+# $Id: c00008.vtc 3453 2008-12-03 10:39:15Z phk $
 
 test "Test If-Modified-Since"
 
 server s1 {
 	rxreq
 	expect req.url == "/foo"
-	txresp -hdr "Last-Modified: Thu, 26 Jun 2008 12:00:01 GMT" -body "11111\n"
+	txresp -hdr "Last-Modified: Thu, 26 Jun 2008 12:00:01 GMT" \
+	    -body "11111\n"
 } -start
 
 varnish v1 -vcl+backend { } -start
@@ -16,15 +17,18 @@
 	expect resp.status == 200
 	expect resp.http.content-length == 6
 
-	txreq -url "/foo" -hdr "If-Modified-Since: Thu, 26 Jun 2008 12:00:00 GMT"
+	txreq -url "/foo" \
+	    -hdr "If-Modified-Since: Thu, 26 Jun 2008 12:00:00 GMT"
 	rxresp
 	expect resp.status == 200
 
-	txreq -url "/foo" -hdr "If-Modified-Since: Thu, 26 Jun 2008 12:00:01 GMT"
+	txreq -url "/foo" \
+	    -hdr "If-Modified-Since: Thu, 26 Jun 2008 12:00:01 GMT"
 	rxresp
 	expect resp.status == 304
 
-	txreq -url "/foo" -hdr "If-Modified-Since: Thu, 26 Jun 2008 12:00:02 GMT"
+	txreq -url "/foo" \
+	    -hdr "If-Modified-Since: Thu, 26 Jun 2008 12:00:02 GMT"
 	rxresp
 	expect resp.status == 304
 } 
--- 2.0.3/varnish-cache/bin/varnishtest/tests/c00019.vtc	1970-01-01 01:00:00.000000000 +0100
+++ trunk/varnish-cache/bin/varnishtest/tests/c00019.vtc	2008-11-06 12:22:00.000000000 +0100
@@ -0,0 +1,87 @@
+# $Id$
+
+test "Check purge counters and duplicate purge elimination"
+
+server s1 {
+	rxreq
+	txresp -hdr "foo: 1" -body "foo1"
+	rxreq
+	txresp -hdr "foo: 2" -body "foo2"
+	rxreq
+	txresp -hdr "foo: 3" -body "foo3"
+} -start
+
+varnish v1 -vcl+backend {} -start
+
+varnish v1 -cliok "purge.url FOO"
+
+# There is one "magic" purge from boot
+varnish v1 -expect n_purge_add == 2
+varnish v1 -cliok "purge.list"
+
+# Our fetch is not affected by the purge
+# as the FOO-purge was preexisting
+client c1 {
+	txreq -url /FOO
+	rxresp
+	expect resp.http.foo == 1
+} -run
+
+varnish v1 -cliok "purge.list"
+varnish v1 -expect n_purge_obj_test == 0
+varnish v1 -expect n_purge_re_test == 0
+
+# Add another purge
+varnish v1 -cliok "purge.url FOO"
+varnish v1 -expect n_purge_add == 3
+varnish v1 -cliok "purge.list"
+
+# The cached object will be purged, and a new
+# fetched from the backend
+client c1 {
+	txreq -url /FOO
+	rxresp
+	expect resp.http.foo == 2
+} -run
+
+varnish v1 -expect n_purge_obj_test == 1
+varnish v1 -expect n_purge_re_test == 1
+varnish v1 -cliok "purge.list"
+
+# Fetch the cached copy, just for grins
+client c1 {
+	txreq -url /FOO
+	rxresp
+	expect resp.http.foo == 2
+} -run
+
+
+# Now add another two purge, the hash should not be hit.
+varnish v1 -cliok "purge.hash FOO"
+varnish v1 -cliok "purge.url FOO"
+varnish v1 -expect n_purge_add == 5
+
+# Enable dup removal of purges
+varnish v1 -cliok "param.set purge_dups on"
+
+# This should incapacitate the to previous FOO purges.
+varnish v1 -cliok "purge.url FOO"
+varnish v1 -expect n_purge_add == 6
+varnish v1 -expect n_purge_dups == 3
+varnish v1 -cliok "purge.list"
+
+# And we should get a fresh object from backend
+client c1 {
+	txreq -url /FOO
+	rxresp
+	expect resp.http.foo == 3
+} -run
+
+# With only two objects having ever been compared
+varnish v1 -expect n_purge_obj_test == 2
+varnish v1 -expect n_purge_re_test == 2
+varnish v1 -cliok "purge.list"
+
+# Test a bogus regexp
+
+varnish v1 -clierr 106 "purge.url [[["
--- 2.0.3/varnish-cache/bin/varnishtest/tests/r00400.vtc	1970-01-01 01:00:00.000000000 +0100
+++ trunk/varnish-cache/bin/varnishtest/tests/r00400.vtc	2009-01-05 14:45:27.000000000 +0100
@@ -0,0 +1,21 @@
+# $Id$
+
+test "Regression test for ticket 409"
+
+server s1 {
+	rxreq
+	expect req.url == "/"
+	send "HTTP/1.0 400 Not funny\r\n"
+	send "\r\n"
+	send "12345\r\n"
+} -start
+
+varnish v1 -vcl+backend {
+} -start
+
+client c1 {
+	txreq
+	rxresp
+	expect resp.status == 400
+	expect resp.bodylen == 7
+} -run
diff -Nru 2.0.3/varnish-cache/bin/varnishtest/tests/r00409.vtc trunk/varnish-cache/bin/varnishtest/tests/r00409.vtc
--- 2.0.3/varnish-cache/bin/varnishtest/tests/r00409.vtc	1970-01-01 01:00:00.000000000 +0100
+++ trunk/varnish-cache/bin/varnishtest/tests/r00409.vtc	2009-01-05 14:45:27.000000000 +0100
@@ -0,0 +1,11 @@
+# $Id$
+
+test "Regression test for ticket 409"
+
+varnish v1  -badvcl {
+	sub vcl_recv {
+		if ( req.url ~ ! "\.(png|jpg|gif|js|css)$" ) {
+			return (pass);
+		}
+	}
+}
diff -Nru 2.0.3/varnish-cache/bin/varnishtest/tests/r00412.vtc trunk/varnish-cache/bin/varnishtest/tests/r00412.vtc
--- 2.0.3/varnish-cache/bin/varnishtest/tests/r00412.vtc	1970-01-01 01:00:00.000000000 +0100
+++ trunk/varnish-cache/bin/varnishtest/tests/r00412.vtc	2009-01-05 14:45:27.000000000 +0100
@@ -0,0 +1,36 @@
+# $Id$
+
+test "Regression test for ticket 412"
+
+server s1 {
+	rxreq
+	expect req.url == "/"
+	txresp -status 303 -hdr "Location: /foo" 
+	rxreq
+	expect req.url == "/foo"
+	txresp -body "12345"
+} -start
+
+varnish v1 -vcl+backend {
+	sub vcl_fetch {
+		if (obj.status == 303) {
+			set obj.cacheable = true;
+			set obj.ttl = 60 s;
+			set obj.http.X-Magic-Redirect = "1";
+			set req.url = obj.http.Location;
+			restart;
+		}
+	}
+	sub vcl_hit {
+		if (obj.http.X-Magic-Redirect == "1") {
+			set req.url = obj.http.Location;
+			restart;
+		}
+	}
+} -start
+
+client c1 {
+	txreq
+	rxresp
+	expect resp.status == 200
+} -run
--- 2.0.3/varnish-cache/bin/varnishtest/tests/v00016.vtc	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/bin/varnishtest/tests/v00016.vtc	2009-01-05 14:45:27.000000000 +0100
@@ -1,17 +1,21 @@
-# $Id: v00016.vtc 3300 2008-10-15 09:52:15Z tfheen $
+# $Id: v00016.vtc 3389 2008-11-11 20:40:37Z phk $
 
 test "Various VCL compiler coverage tests"
 
+shell "true > /tmp/_varnishtest_empty_file"
+
 varnish v1 -vcl {
 	backend b { .host = "127.0.0.1"; }
-	include "/dev/null" ;
+	include "/tmp/_varnishtest_empty_file" ;
 }
 
 varnish v1 -badvcl {
 	backend b { .host = "127.0.0.1"; }
-	include "/dev/null" |
+	include "/tmp/_varnishtest_empty_file" |
 }
 
+shell "rm -f /tmp/_varnishtest_empty_file"
+
 varnish v1 -badvcl {
 	backend b { .host = "127.0.0.1"; }
 	include <<
diff -Nru 2.0.3/varnish-cache/bin/varnishtest/tests/v00017.vtc trunk/varnish-cache/bin/varnishtest/tests/v00017.vtc
--- 2.0.3/varnish-cache/bin/varnishtest/tests/v00017.vtc	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/bin/varnishtest/tests/v00017.vtc	2008-11-06 12:22:00.000000000 +0100
@@ -1,4 +1,4 @@
-# $Id: v00017.vtc 3300 2008-10-15 09:52:15Z tfheen $
+# $Id: v00017.vtc 3352 2008-10-27 00:36:04Z sky $
 
 test "VCL compiler coverage test: vcc_acl.c"
 
@@ -34,7 +34,7 @@
 
 varnish v1 -badvcl {
 	backend b { .host = "127.0.0.1"; }
-	acl a { "en.lille.nisse.rejste"; }
+	acl a { "en.lille.nisse.rejste."; }
 	sub vcl_recv { if (client.ip ~ a) { pass; } }
 }
 
@@ -60,8 +60,8 @@
 	backend b { .host = "127.0.0.1"; }
 	acl a {
 		! "10.1.3"; 
-		("en.lille.nisse.rejste" / 22); 
-		(!"en.lille.nisse.rejste"); 
+		("en.lille.nisse.rejste." / 22); 
+		(!"en.lille.nisse.rejste."); 
 	}
 	sub vcl_recv { if (client.ip ~ a) { pass; } }
 }
diff -Nru 2.0.3/varnish-cache/bin/varnishtest/vtc.c trunk/varnish-cache/bin/varnishtest/vtc.c
--- 2.0.3/varnish-cache/bin/varnishtest/vtc.c	2009-01-09 15:36:38.000000000 +0100
+++ trunk/varnish-cache/bin/varnishtest/vtc.c	2008-11-10 12:11:47.000000000 +0100
@@ -1,7 +1,7 @@
 /*
  * Copyright (c) 2006-2008 Linpro AS
  * All rights reserved.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -10,7 +10,7 @@
  * 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
@@ -23,9 +23,11 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: vtc.c 3277 2008-10-10 11:00:02Z tfheen $
+ * $Id: vtc.c 3367 2008-11-10 09:37:21Z phk $
  */
 
+#include "config.h"
+
 #include <stdio.h>
 #include <string.h>
 #include <ctype.h>
@@ -140,7 +142,8 @@
 						p++;
 					} else {
 						if (*p == '\n')
-							fprintf(stderr, "Unterminated quoted string in line:\n%s", p);
+							fprintf(stderr,
+				"Unterminated quoted string in line:\n%s", p);
 						assert(*p != '\n');
 						*q++ = *p;
 					}
@@ -184,7 +187,7 @@
 			fprintf(stderr, "Unknown command: \"%s\"", token_s[0]);
 			exit (1);
 		}
-	
+
 		assert(cp->cmd != NULL);
 		cp->cmd(token_s, priv, cmd, vl);
 		if (stop)
@@ -336,15 +339,15 @@
  */
 
 static struct cmds cmds[] = {
-	{ "server", 	cmd_server },
-	{ "client", 	cmd_client },
-	{ "varnish", 	cmd_varnish },
-	{ "delay", 	cmd_delay },
-	{ "test", 	cmd_test },
-	{ "shell", 	cmd_shell },
-	{ "sema", 	cmd_sema },
+	{ "server",	cmd_server },
+	{ "client",	cmd_client },
+	{ "varnish",	cmd_varnish },
+	{ "delay",	cmd_delay },
+	{ "test",	cmd_test },
+	{ "shell",	cmd_shell },
+	{ "sema",	cmd_sema },
 	{ "random",	cmd_random },
-	{ NULL, 	NULL }
+	{ NULL,		NULL }
 };
 
 static void
@@ -377,7 +380,7 @@
 }
 
 /**********************************************************************
- * Main 
+ * Main
  */
 
 int
diff -Nru 2.0.3/varnish-cache/bin/varnishtest/vtc_client.c trunk/varnish-cache/bin/varnishtest/vtc_client.c
--- 2.0.3/varnish-cache/bin/varnishtest/vtc_client.c	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/bin/varnishtest/vtc_client.c	2008-11-06 12:22:00.000000000 +0100
@@ -1,7 +1,7 @@
 /*
  * Copyright (c) 2006-2008 Linpro AS
  * All rights reserved.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -10,7 +10,7 @@
  * 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
@@ -23,9 +23,11 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: vtc_client.c 3272 2008-10-09 11:39:24Z phk $
+ * $Id: vtc_client.c 3336 2008-10-20 18:47:24Z des $
  */
 
+#include "config.h"
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
@@ -50,7 +52,7 @@
 	VTAILQ_ENTRY(client)	list;
 
 	char			*spec;
-	
+
 	char			*connect;
 
 	pthread_t		tp;
@@ -208,7 +210,7 @@
 	VTAILQ_FOREACH(c, &clients, list)
 		if (!strcmp(c->name, av[0]))
 			break;
-	if (c == NULL) 
+	if (c == NULL)
 		c = client_new(av[0]);
 	av++;
 
diff -Nru 2.0.3/varnish-cache/bin/varnishtest/vtc.h trunk/varnish-cache/bin/varnishtest/vtc.h
--- 2.0.3/varnish-cache/bin/varnishtest/vtc.h	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/bin/varnishtest/vtc.h	2008-10-20 10:58:16.000000000 +0200
@@ -1,7 +1,7 @@
 /*
  * Copyright (c) 2006-2008 Linpro AS
  * All rights reserved.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -10,7 +10,7 @@
  * 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
@@ -22,15 +22,17 @@
  * 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: vtc.h 3272 2008-10-09 11:39:24Z phk $
+ *
+ * $Id: vtc.h 3324 2008-10-18 20:50:10Z phk $
  */
 
 struct vsb;
 struct vtclog;
 struct cmds;
 
-#define CMD_ARGS char * const *av, void *priv, const struct cmds *cmd, struct vtclog *vl
+#define CMD_ARGS \
+    char * const *av, void *priv, const struct cmds *cmd, struct vtclog *vl
+
 typedef void cmd_f(CMD_ARGS);
 
 struct cmds {
@@ -38,7 +40,8 @@
 	cmd_f		*cmd;
 };
 
-void parse_string(char *buf, const struct cmds *cmd, void *priv, struct vtclog *vl);
+void parse_string(char *buf, const struct cmds *cmd, void *priv,
+    struct vtclog *vl);
 
 cmd_f cmd_dump;
 cmd_f cmd_delay;
@@ -60,4 +63,5 @@
 struct vtclog *vtc_logopen(const char *id);
 void vtc_logclose(struct vtclog *vl);
 void vtc_log(struct vtclog *vl, unsigned lvl, const char *fmt, ...);
-void vtc_dump(struct vtclog *vl, unsigned lvl, const char *pfx, const char *str);
+void vtc_dump(struct vtclog *vl, unsigned lvl, const char *pfx,
+    const char *str);
diff -Nru 2.0.3/varnish-cache/bin/varnishtest/vtc_http.c trunk/varnish-cache/bin/varnishtest/vtc_http.c
--- 2.0.3/varnish-cache/bin/varnishtest/vtc_http.c	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/bin/varnishtest/vtc_http.c	2008-11-06 12:22:00.000000000 +0100
@@ -1,7 +1,7 @@
 /*
  * Copyright (c) 2006-2008 Linpro AS
  * All rights reserved.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -10,7 +10,7 @@
  * 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
@@ -23,12 +23,15 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: vtc_http.c 3291 2008-10-11 11:27:56Z phk $
+ * $Id: vtc_http.c 3336 2008-10-20 18:47:24Z des $
  */
 
+#include "config.h"
 
 #include <poll.h>
 #include <stdio.h>
+#include <poll.h>
+#include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
 #include <unistd.h>
@@ -75,8 +78,8 @@
 {
 	int i, j, k, l;
 	char *b;
-	
-	
+
+
 	AN(len);
 	i = strtoul(len, NULL, 0);
 	assert(i > 0);
@@ -347,7 +350,7 @@
 {
 	char *p, *q;
 	int i, l, ll;
-	
+
 
 	ll = 0;
 	p = http_find_header(hh, "content-length");
@@ -397,7 +400,7 @@
 			ll += i;
 		} while (i > 0);
 		vtc_dump(hp->vl, 4, "rxeof", hp->body);
-	} 
+	}
 	sprintf(hp->bodylen, "%d", ll);
 }
 
@@ -419,7 +422,7 @@
 		p = hp->rxbuf + hp->prxbuf - 1;
 		i = 0;
 		for (i = 0; p > hp->rxbuf; p--) {
-			if (*p != '\n') 
+			if (*p != '\n')
 				break;
 			if (p - 1 > hp->rxbuf && p[-1] == '\r')
 				p--;
@@ -456,7 +459,7 @@
 	vtc_log(hp->vl, 3, "rxresp");
 	http_rxhdr(hp);
 	http_splitheader(hp, 0);
-	if (!strcmp(hp->resp[1], "200")) 
+	if (!strcmp(hp->resp[1], "200"))
 		http_swallow_body(hp, hp->resp, 1);
 	else
 		http_swallow_body(hp, hp->resp, 0);
@@ -506,7 +509,7 @@
 		if (!strcmp(*av, "-hdr")) {
 			vsb_printf(hp->vsb, "%s%s", av[1], nl);
 			av++;
-		} else 
+		} else
 			break;
 	}
 	for(; *av != NULL; av++) {
@@ -525,7 +528,7 @@
 		fprintf(stderr, "Unknown http txresp spec: %s\n", *av);
 		exit (1);
 	}
-	if (body != NULL) 
+	if (body != NULL)
 		vsb_printf(hp->vsb, "Content-Length: %d%s", strlen(body), nl);
 	vsb_cat(hp->vsb, nl);
 	if (body != NULL) {
@@ -621,7 +624,7 @@
 		fprintf(stderr, "Unknown http txreq spec: %s\n", *av);
 		exit (1);
 	}
-	if (body != NULL) 
+	if (body != NULL)
 		vsb_printf(hp->vsb, "Content-Length: %d%s", strlen(body), nl);
 	vsb_cat(hp->vsb, nl);
 	if (body != NULL) {
diff -Nru 2.0.3/varnish-cache/bin/varnishtest/vtc_log.c trunk/varnish-cache/bin/varnishtest/vtc_log.c
--- 2.0.3/varnish-cache/bin/varnishtest/vtc_log.c	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/bin/varnishtest/vtc_log.c	2008-11-06 12:22:00.000000000 +0100
@@ -1,7 +1,7 @@
 /*
  * Copyright (c) 2006-2008 Linpro AS
  * All rights reserved.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -10,7 +10,7 @@
  * 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
@@ -23,9 +23,11 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: vtc_log.c 3272 2008-10-09 11:39:24Z phk $
+ * $Id: vtc_log.c 3336 2008-10-20 18:47:24Z des $
  */
 
+#include "config.h"
+
 #include <stdio.h>
 #include <string.h>
 #include <ctype.h>
@@ -56,7 +58,7 @@
 	struct vtclog *vl;
 
 	ALLOC_OBJ(vl, VTCLOG_MAGIC);
-	AN(vl);	
+	AN(vl);
 	vl->id = id;
 	vl->vsb = vsb_newauto();
 	return (vl);
@@ -125,7 +127,7 @@
 	vsb_clear(vl->vsb);
 	if (pfx == NULL)
 		pfx = "";
-	if (str == NULL) 
+	if (str == NULL)
 		vsb_printf(vl->vsb, "%s %-4s %s(null)\n",
 		    lead[lvl], vl->id, pfx);
 	else
diff -Nru 2.0.3/varnish-cache/bin/varnishtest/vtc_sema.c trunk/varnish-cache/bin/varnishtest/vtc_sema.c
--- 2.0.3/varnish-cache/bin/varnishtest/vtc_sema.c	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/bin/varnishtest/vtc_sema.c	2008-11-06 12:22:00.000000000 +0100
@@ -1,7 +1,7 @@
 /*
  * Copyright (c) 2006-2008 Linpro AS
  * All rights reserved.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -10,7 +10,7 @@
  * 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
@@ -23,9 +23,11 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: vtc_sema.c 3272 2008-10-09 11:39:24Z phk $
+ * $Id: vtc_sema.c 3336 2008-10-20 18:47:24Z des $
  */
 
+#include "config.h"
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
@@ -141,7 +143,7 @@
 	VTAILQ_FOREACH(r, &semas, list)
 		if (!strcmp(r->name, av[0]))
 			break;
-	if (r == NULL) 
+	if (r == NULL)
 		r = sema_new(av[0], vl);
 	AZ(pthread_mutex_unlock(&sema_mtx));
 	av++;
diff -Nru 2.0.3/varnish-cache/bin/varnishtest/vtc_server.c trunk/varnish-cache/bin/varnishtest/vtc_server.c
--- 2.0.3/varnish-cache/bin/varnishtest/vtc_server.c	2009-01-09 15:39:07.000000000 +0100
+++ trunk/varnish-cache/bin/varnishtest/vtc_server.c	2009-01-05 14:45:27.000000000 +0100
@@ -1,7 +1,7 @@
 /*
  * Copyright (c) 2006-2008 Linpro AS
  * All rights reserved.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -10,7 +10,7 @@
  * 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
@@ -23,9 +23,10 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: vtc_server.c 3272 2008-10-09 11:39:24Z phk $
+ * $Id: vtc_server.c 3408 2008-11-20 08:50:56Z phk $
  */
 
+#include "config.h"
 
 #include <stdio.h>
 #include <errno.h>
@@ -54,7 +55,7 @@
 
 	unsigned		repeat;
 	char			*spec;
-	
+
 	int			depth;
 	int			sock;
 	char			*listen;
@@ -234,7 +235,7 @@
 		/* Reset and free */
 		VTAILQ_FOREACH_SAFE(s, &servers, list, s2) {
 			VTAILQ_REMOVE(&servers, s, list);
-			if (s->sock >= 0) 
+			if (s->sock >= 0)
 				server_wait(s);
 			server_delete(s);
 		}
@@ -247,7 +248,7 @@
 	VTAILQ_FOREACH(s, &servers, list)
 		if (!strcmp(s->name, av[0]))
 			break;
-	if (s == NULL) 
+	if (s == NULL)
 		s = server_new(av[0]);
 	av++;
 
diff -Nru 2.0.3/varnish-cache/bin/varnishtest/vtc_varnish.c trunk/varnish-cache/bin/varnishtest/vtc_varnish.c
--- 2.0.3/varnish-cache/bin/varnishtest/vtc_varnish.c	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/bin/varnishtest/vtc_varnish.c	2008-11-06 12:22:00.000000000 +0100
@@ -1,7 +1,7 @@
 /*
  * Copyright (c) 2006-2008 Linpro AS
  * All rights reserved.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -10,7 +10,7 @@
  * 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
@@ -23,9 +23,10 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: vtc_varnish.c 3283 2008-10-10 20:44:14Z phk $
+ * $Id: vtc_varnish.c 3336 2008-10-20 18:47:24Z des $
  */
 
+#include "config.h"
 
 #include <stdio.h>
 
@@ -446,7 +447,7 @@
 	for (i = 0; i < 10; i++, usleep(100000)) {
 
 
-#define MAC_STAT(n, t, f, d) 					\
+#define MAC_STAT(n, t, f, d)					\
 		if (!strcmp(av[0], #n)) {			\
 			val = v->stats->n;			\
 		} else
@@ -510,7 +511,7 @@
 	VTAILQ_FOREACH(v, &varnishes, list)
 		if (!strcmp(v->name, av[0]))
 			break;
-	if (v == NULL) 
+	if (v == NULL)
 		v = varnish_new(av[0]);
 	av++;
 
diff -Nru 2.0.3/varnish-cache/bin/varnishtop/Makefile.in trunk/varnish-cache/bin/varnishtop/Makefile.in
diff -Nru 2.0.3/varnish-cache/bin/varnishtop/.svn/entries trunk/varnish-cache/bin/varnishtop/.svn/entries
diff -Nru 2.0.3/varnish-cache/bin/varnishtop/.svn/text-base/varnishtop.c.svn-base trunk/varnish-cache/bin/varnishtop/.svn/text-base/varnishtop.c.svn-base
diff -Nru 2.0.3/varnish-cache/bin/varnishtop/varnishtop.c trunk/varnish-cache/bin/varnishtop/varnishtop.c
--- 2.0.3/varnish-cache/bin/varnishtop/varnishtop.c	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/bin/varnishtop/varnishtop.c	2008-11-06 12:22:00.000000000 +0100
@@ -27,7 +27,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: varnishtop.c 3187 2008-09-16 07:30:30Z tfheen $
+ * $Id: varnishtop.c 3336 2008-10-20 18:47:24Z des $
  *
  * Log tailer for Varnish
  */
@@ -45,7 +45,6 @@
 #include <unistd.h>
 #include <limits.h>
 
-#include "config.h"
 #include "vqueue.h"
 
 #include "vsb.h"
@@ -286,7 +285,8 @@
 static void
 usage(void)
 {
-	fprintf(stderr, "usage: varnishtop %s [-1fV] [-n varnish_name]\n", VSL_USAGE);
+	fprintf(stderr,
+	    "usage: varnishtop %s [-1fV] [-n varnish_name]\n", VSL_USAGE);
 	exit(1);
 }
 
diff -Nru 2.0.3/varnish-cache/configure.ac trunk/varnish-cache/configure.ac
--- 2.0.3/varnish-cache/configure.ac	2008-11-14 13:59:03.000000000 +0100
+++ trunk/varnish-cache/configure.ac	2009-01-05 14:45:28.000000000 +0100
@@ -1,9 +1,9 @@
-# $Id: configure.ac 3397 2008-11-14 12:59:02Z tfheen $
+# $Id: configure.ac 3439 2008-11-25 12:02:10Z phk $
 
 AC_PREREQ(2.59)
 AC_COPYRIGHT([Copyright (c) 2006-2008 Linpro AS / Verdens Gang AS])
-AC_REVISION([$Id: configure.ac 3397 2008-11-14 12:59:02Z tfheen $])
-AC_INIT([Varnish], [2.0.2], [varnish-dev@projects.linpro.no])
+AC_REVISION([$Id: configure.ac 3439 2008-11-25 12:02:10Z phk $])
+AC_INIT([Varnish], [trunk], [varnish-dev@projects.linpro.no])
 AC_CONFIG_SRCDIR(include/varnishapi.h)
 AM_CONFIG_HEADER(config.h)
 
@@ -70,16 +70,18 @@
 AC_HEADER_STDC
 AC_HEADER_SYS_WAIT
 AC_HEADER_TIME
-AC_CHECK_HEADERS([sys/socket.h])
+AC_CHECK_HEADERS([sys/endian.h])
+AC_CHECK_HEADERS([sys/filio.h])
 AC_CHECK_HEADERS([sys/mount.h])
+AC_CHECK_HEADERS([sys/socket.h])
 AC_CHECK_HEADERS([sys/statvfs.h])
 AC_CHECK_HEADERS([sys/vfs.h])
+AC_CHECK_HEADERS([endian.h])
 AC_CHECK_HEADERS([netinet/in.h])
 AC_CHECK_HEADERS([pthread_np.h])
 AC_CHECK_HEADERS([stddef.h])
 AC_CHECK_HEADERS([stdlib.h])
 AC_CHECK_HEADERS([unistd.h])
-AC_CHECK_HEADERS([vis.h])
 
 # Checks for typedefs, structures, and compiler characteristics.
 AC_C_CONST
@@ -109,8 +111,9 @@
 AC_CHECK_FUNCS([pthread_mutex_isowned_np])
 LIBS="${save_LIBS}"
 
-## This one is tricky, there are multiple versions
-case $host in
+# sendfile is tricky: there are multiple versions, and most of them
+# don't work.
+case $target in
 *-*-freebsd*)
 	AC_CACHE_CHECK([whether sendfile works],
 	  [ac_cv_so_sendfile_works],
@@ -125,28 +128,37 @@
 	    [ac_cv_so_sendfile_works=yes],
 	    [ac_cv_so_sendfile_works=no])
 	  ])
-	if test "$ac_cv_so_sendfile_works" = yes; then
-	   AC_DEFINE([SENDFILE_WORKS], [1], [Define if SENDFILE works])
-	fi
- 	;;
+	;;
+#*-*-solaris*)
+#	save_LIBS="${LIBS}"
+#	LIBS="${NET_LIBS}"
+#	AC_CHECK_LIB(sendfile, sendfile)
+#	AC_CHECK_FUNCS([sendfile])
+#	AC_CHECK_FUNCS([sendfilev])
+#	NET_LIBS="${LIBS}"
+#	LIBS="${save_LIBS}"
+*)
+	AC_MSG_WARN([won't look for sendfile() on $target])
+	;;
+esac
+if test "$ac_cv_so_sendfile_works" = yes; then
+	AC_DEFINE([SENDFILE_WORKS], [1], [Define if SENDFILE works])
+fi
+
+# Userland slab allocator, available only on Solaris
+case $target in
 *-*-solaris*)
-	AC_CHECK_HEADERS([sys/filio.h])
-	AC_CHECK_LIB(sendfile, sendfile)
-	AC_CHECK_LIB(umem, malloc)
 	AC_CHECK_HEADERS([umem.h])
-
-	if test "$ac_cv_lib_sendfile_sendfile" = yes; then
+	if test "$ac_cv_have_umem_h" = yes; then
 		save_LIBS="${LIBS}"
-		LIBS="${NET_LIBS}"
-		AC_CHECK_FUNCS([sendfile])
-		AC_CHECK_FUNCS([sendfilev])
+		LIBS=""
+		AC_CHECK_LIB(umem, umem_alloc)
+		LIBUMEM="${LIBS}"
 		LIBS="${save_LIBS}"
 	fi
 	;;
-*)
-	AC_MSG_WARN([won't look for sendfile() on $host])
-	;;
 esac
+AC_SUBST(LIBUMEM)
 
 # These functions are provided by libcompat on platforms where they
 # are not available
@@ -155,7 +167,6 @@
 AC_CHECK_FUNCS([srandomdev])
 AC_CHECK_FUNCS([strlcat strlcpy])
 AC_CHECK_FUNCS([strndup])
-AC_CHECK_FUNCS([vis strvis strvisx])
 AC_CHECK_FUNCS([daemon])
 AC_SYS_LARGEFILE
 
@@ -178,13 +189,13 @@
     [enable_kqueue=yes])
 
 if test "$enable_kqueue" = yes; then
-	case $host in
+	case $target in
 	*-*-freebsd* | *-*-darwin9* )
 		AC_CHECK_FUNCS([kqueue])
 		;;
 	*-*-bsd*)
 		# No other BSD has a sufficiently recent implementation
-		AC_MSG_WARN([won't look for kqueue() on $host])
+		AC_MSG_WARN([won't look for kqueue() on $target])
 		ac_cv_func_kqueue=no
 		;;
 	esac
@@ -221,7 +232,7 @@
 AM_MISSING_HAS_RUN
 AC_CHECK_PROGS(TCLSH, [tclsh tclsh8.4 tclsh8.5], :)
 if test "$TCLSH" = :; then
-  TCLSH="${am_missing_run}tclsh || true"
+  TCLSH="${am_missing_run}tclsh"
 fi
 
 # Solaris defines SO_{RCV,SND}TIMEO, but does not implement them.
@@ -330,7 +341,7 @@
 if test "$ac_cv_env_VCC_CC_set" = "set"; then
 	VCC_CC="$ac_cv_env_VCC_CC_value"
 else
-	case $host in
+	case $target in
 	*-*-solaris*)
 		VCC_CC="cc -Kpic -G -o %o %s"
 		;;
@@ -353,7 +364,7 @@
 	JEMALLOC_SUBDIR=libjemalloc
 	JEMALLOC_LDADD='$(top_builddir)/lib/libjemalloc/libjemalloc_mt.la'
 fi],
-[case $host in #(
+[case $target in #(
 *-*-linux*)
 	JEMALLOC_SUBDIR=libjemalloc
 	JEMALLOC_LDADD='$(top_builddir)/lib/libjemalloc/libjemalloc_mt.la'
diff -Nru 2.0.3/varnish-cache/debian/.svn/entries trunk/varnish-cache/debian/.svn/entries
diff -Nru 2.0.3/varnish-cache/doc/changes-2.0.1-2.0.2~ trunk/varnish-cache/doc/changes-2.0.1-2.0.2~
diff -Nru 2.0.3/varnish-cache/doc/changes-2.0.1-2.0.2.xml trunk/varnish-cache/doc/changes-2.0.1-2.0.2.xml
--- 2.0.3/varnish-cache/doc/changes-2.0.1-2.0.2.xml	2008-10-20 10:53:55.000000000 +0200
+++ trunk/varnish-cache/doc/changes-2.0.1-2.0.2.xml	1970-01-01 01:00:00.000000000 +0100
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!DOCTYPE group [
-<!ENTITY mdash "&#8212;">
-]>
-<!-- $Id$ -->
-<group from="2.0.1" to="2.0.2">
-  <subsystem>
-    <name>varnishd</name>
-
-    <change type="bug" ref="345">
-      <para>In high-load situations, when using
-      ESI, <code>varnishd</code> would sometimes mishandle objects and
-      crash.  This has been worked around. </para>
-    </change>
-  </subsystem>
-
-  <subsystem>
-    <name>varnishreplay</name>
-
-    <change type="bug">
-      <para><code>varnishreplay</code> did not work correctly on
-      Linux, due to a too small stack.  This has now been fixed.</para>
-    </change>
-  </subsystem>
-</group>
diff -Nru 2.0.3/varnish-cache/doc/changes-2.0.2.xml trunk/varnish-cache/doc/changes-2.0.2.xml
--- 2.0.3/varnish-cache/doc/changes-2.0.2.xml	2008-10-20 10:46:53.000000000 +0200
+++ trunk/varnish-cache/doc/changes-2.0.2.xml	1970-01-01 01:00:00.000000000 +0100
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<?xml-stylesheet type="text/xml" href="changes-html.xsl"?>
-<!DOCTYPE changelog [
- <!ENTITY mdash "&#8212;">
-]>
-<!-- $Id$ -->
-<changelog xmlns:xi="http://www.w3.org/2001/XInclude">
-  <package>Varnish</package>
-  <version>2.0.2</version>
-
-  <xi:include href="changes-2.0.1-2.0.2.xml"/>
-</changelog>
diff -Nru 2.0.3/varnish-cache/doc/Makefile.am trunk/varnish-cache/doc/Makefile.am
--- 2.0.3/varnish-cache/doc/Makefile.am	2008-10-17 17:53:35.000000000 +0200
+++ trunk/varnish-cache/doc/Makefile.am	2008-10-20 11:03:54.000000000 +0200
@@ -1,4 +1,4 @@
-# $Id: Makefile.am 3317 2008-10-17 15:53:34Z tfheen $
+# $Id: Makefile.am 3327 2008-10-20 09:03:53Z tfheen $
 
 CHANGELOGS = \
 	changes-2.0.1.html \
--- 2.0.3/varnish-cache/include/cli.h	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/include/cli.h	2008-10-20 10:58:16.000000000 +0200
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: cli.h 2645 2008-05-31 21:26:20Z phk $
+ * $Id: cli.h 3324 2008-10-18 20:50:10Z phk $
  *
  * Public definition of the CLI protocol, part of the published Varnish-API.
  *
@@ -57,7 +57,7 @@
 	"url.query",							\
 	"url.query <url>",						\
 	"\tQuery the cache status of a specific URL.\n"			\
-	    "\tReturns the TTL, size and checksum of the object.", 	\
+	    "\tReturns the TTL, size and checksum of the object.",	\
 	1, 1
 
 #define CLI_PURGE_URL							\
--- 2.0.3/varnish-cache/include/compat/vis.h	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/include/compat/vis.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,87 +0,0 @@
-/*-
- * Copyright (c) 1990, 1993
- *	The Regents of the University of California.  All rights reserved.
- *
- * 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.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 THE REGENTS 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.
- *
- *	@(#)vis.h	8.1 (Berkeley) 6/2/93
- * $FreeBSD: src/include/vis.h,v 1.11 2003/10/30 10:40:49 phk Exp $
- * $Id: vis.h 1783 2007-07-30 08:03:42Z des $
- */
-
-#ifndef _VIS_H_
-#define	_VIS_H_
-
-/*
- * to select alternate encoding format
- */
-#define	VIS_OCTAL	0x01	/* use octal \ddd format */
-#define	VIS_CSTYLE	0x02	/* use \[nrft0..] where appropriate */
-
-/*
- * to alter set of characters encoded (default is to encode all
- * non-graphic except space, tab, and newline).
- */
-#define	VIS_SP		0x04	/* also encode space */
-#define	VIS_TAB		0x08	/* also encode tab */
-#define	VIS_NL		0x10	/* also encode newline */
-#define	VIS_WHITE	(VIS_SP | VIS_TAB | VIS_NL)
-#define	VIS_SAFE	0x20	/* only encode "unsafe" characters */
-
-/*
- * other
- */
-#define	VIS_NOSLASH	0x40	/* inhibit printing '\' */
-#define	VIS_HTTPSTYLE	0x80	/* http-style escape % HEX HEX */
-#define	VIS_GLOB	0x100	/* encode glob(3) magics */
-
-/*
- * unvis return codes
- */
-#define	UNVIS_VALID	 1	/* character valid */
-#define	UNVIS_VALIDPUSH	 2	/* character valid, push back passed char */
-#define	UNVIS_NOCHAR	 3	/* valid sequence, no character produced */
-#define	UNVIS_SYNBAD	-1	/* unrecognized escape sequence */
-#define	UNVIS_ERROR	-2	/* decoder in unknown state (unrecoverable) */
-
-/*
- * unvis flags
- */
-#define	UNVIS_END	1	/* no more characters */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-char	*vis(char *, int, int, int);
-int	strvis(char *, const char *, int);
-int	strvisx(char *, const char *, size_t, int);
-int	strunvis(char *, const char *);
-int	strunvisx(char *, const char *, int);
-int	unvis(char *, int, int *, int);
-#ifdef __cplusplus
-};
-#endif
-
-#endif /* !_VIS_H_ */
diff -Nru 2.0.3/varnish-cache/include/http_headers.h trunk/varnish-cache/include/http_headers.h
--- 2.0.3/varnish-cache/include/http_headers.h	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/include/http_headers.h	2008-10-20 10:58:16.000000000 +0200
@@ -26,8 +26,10 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: http_headers.h 2415 2008-01-31 11:57:51Z des $
+ * $Id: http_headers.h 3324 2008-10-18 20:50:10Z phk $
  *
+ * Argument list:
+ * ---------------------------------------
  * a	Http header name
  * b	session field name
  * c	Request(1)/Response(2) bitfield
@@ -38,8 +40,6 @@
  *
  * see [RFC2616 13.5.1 End-to-end and Hop-by-hop Headers]
  *
- *    a                         b                       c  d  e  f  g
- *--------------------------------------------------------------------
  */
 
 #ifndef HTTPH_R_PASS
@@ -51,52 +51,51 @@
 #define HTTPH_A_DELIVER	(1 << 5)	/* Response (o->c) for deliver */
 #endif
 
-HTTPH("Keep-Alive",		H_Keep_Alive,		3, 3, HTTPH_R_PASS|HTTPH_A_PASS|HTTPH_R_FETCH, 0, 0)	/* RFC2068 */
-
-HTTPH("Accept",			H_Accept,		1, 0, 0, 0, 0)	/* RFC2616 14.1 */
-HTTPH("Accept-Charset",		H_Accept_Charset,	1, 0, 0, 0, 0)	/* RFC2616 14.2 */
-HTTPH("Accept-Encoding",	H_Accept_Encoding,	1, 0, 0, 0, 0)	/* RFC2616 14.3 */
-HTTPH("Accept-Language",	H_Accept_Language,	1, 0, 0, 0, 0)	/* RFC2616 14.4 */
-HTTPH("Accept-Ranges",		H_Accept_Ranges,	2, 3, HTTPH_R_PASS|HTTPH_A_PASS|HTTPH_R_FETCH|HTTPH_A_INS, 0, 0)	/* RFC2616 14.5 */
-HTTPH("Age",			H_Age,			2, 0, HTTPH_A_INS, 0, 0)	/* RFC2616 14.6 */
-HTTPH("Allow",			H_Allow,		2, 0, 0, 0, 0)	/* RFC2616 14.7 */
-HTTPH("Authorization",		H_Authorization,	1, 0, 0, 0, 0)	/* RFC2616 14.8 */
-HTTPH("Cache-Control",		H_Cache_Control,	3, 3, HTTPH_R_PASS|HTTPH_R_FETCH, 0, 0)	/* RFC2616 14.9 */
-HTTPH("Connection",		H_Connection,		3, 3, HTTPH_R_PASS|HTTPH_A_PASS|HTTPH_R_FETCH|HTTPH_A_INS, 0, 0)	/* RFC2616 14.10 */
-HTTPH("Content-Encoding",	H_Content_Encoding,	2, 0, 0, 0, 0)	/* RFC2616 14.11 */
-HTTPH("Content-Langugae",	H_Content_Language,	2, 0, 0, 0, 0)	/* RFC2616 14.12 */
-HTTPH("Content-Length",		H_Content_Length,	2, 2, HTTPH_R_FETCH|HTTPH_A_INS, 0, 0)	/* RFC2616 14.13 */
-HTTPH("Content-Location",	H_Content_Location,	2, 0, 0, 0, 0)  /* RFC2616 14.14 */
-HTTPH("Content-MD5",		H_Content_MD5,		2, 0, 0, 0, 0)  /* RFC2616 14.15 */
-HTTPH("Content-Range",		H_Content_Range,	2, 3, HTTPH_R_PASS|HTTPH_A_PASS|HTTPH_R_FETCH|HTTPH_A_INS, 0, 0)  /* RFC2616 14.16 */
-HTTPH("Content-Type",		H_Content_Type,		2, 0, 0, 0, 0)  /* RFC2616 14.17 */
-HTTPH("Date",			H_Date,			2, 0, HTTPH_A_DELIVER, 0, 0)  /* RFC2616 14.18 */
-HTTPH("ETag", 			H_ETag,			2, 0, 0, 0, 0)	/* RFC2616 14.19 */
-HTTPH("Expect",			H_Expect,		1, 0, 0, 0, 0)	/* RFC2616 14.20 */
-HTTPH("Expires",		H_Expires,		2, 0, 0, 0, 0)	/* RFC2616 14.21 */
-HTTPH("From",			H_From,			1, 0, 0, 0, 0)	/* RFC2616 14.22 */
-HTTPH("Host",			H_Host,			1, 0, 0, 0, 0)	/* RFC2616 14.23 */
-HTTPH("If-Match",		H_If_Match,		1, 1, HTTPH_R_FETCH, 0, 0)	/* RFC2616 14.24 */
-HTTPH("If-Modified-Since",	H_If_Modified_Since,	1, 1, HTTPH_R_FETCH, 0, 0)	/* RFC2616 14.25 */
-HTTPH("If-None-Match",		H_If_None_Match,	1, 1, HTTPH_R_FETCH, 0, 0)	/* RFC2616 14.26 */
-HTTPH("If-Range",		H_If_Range,		1, 1, HTTPH_R_FETCH, 0, 0)	/* RFC2616 14.27 */
-HTTPH("If-Unmodified-Since",	H_If_Unmodifed_Since,	1, 1, HTTPH_R_FETCH, 0, 0)	/* RFC2616 14.28 */
-HTTPH("Last-Modified",		H_Last_Modified,	2, 0, 0, 0, 0)	/* RFC2616 14.29 */
-HTTPH("Location",		H_Location,		2, 0, 0, 0, 0)	/* RFC2616 14.30 */
-HTTPH("Max-Forwards",		H_Max_Forwards,		1, 0, 0, 0, 0)	/* RFC2616 14.31 */
-HTTPH("Pragma",			H_Pragma,		1, 0, 0, 0, 0)  /* RFC2616 14.32 */
-HTTPH("Proxy-Authenticate",	H_Proxy_Authenticate,	2, 3, HTTPH_R_FETCH|HTTPH_A_INS, 0, 0)	/* RFC2616 14.33 */
-HTTPH("Proxy-Authorization",	H_Proxy_Authorization,	1, 3, HTTPH_R_FETCH|HTTPH_A_INS, 0, 0)	/* RFC2616 14.34 */
-HTTPH("Range",			H_Range,		1, 0, 0, 0, 0)	/* RFC2616 14.35 */
-HTTPH("Referer",		H_Referer,		1, 0, 0, 0, 0)	/* RFC2616 14.36 */
-HTTPH("Retry-After",		H_Retry_After,		2, 0, 0, 0, 0)	/* RFC2616 14.37 */
-HTTPH("Server",			H_Server,		2, 0, 0, 0, 0)	/* RFC2616 14.38 */
-HTTPH("TE",			H_TE,			1, 3, HTTPH_R_PASS|HTTPH_A_PASS|HTTPH_R_FETCH|HTTPH_A_INS, 0, 0)	/* RFC2616 14.39 */
-HTTPH("Trailer",		H_Trailer,		1, 3, HTTPH_R_PASS|HTTPH_A_PASS|HTTPH_R_FETCH|HTTPH_A_INS, 0, 0)	/* RFC2616 14.40 */
-HTTPH("Transfer-Encoding", 	H_Transfer_Encoding,	2, 3, HTTPH_R_PASS|HTTPH_A_PASS|HTTPH_R_FETCH|HTTPH_A_INS, 0, 0)	/* RFC2616 14.41 */
-HTTPH("Upgrade", 		H_Upgrade,		2, 3, HTTPH_R_PASS|HTTPH_A_PASS|HTTPH_R_FETCH|HTTPH_A_INS, 0, 0)	/* RFC2616 14.42 */
-HTTPH("User-Agent",		H_User_Agent,		1, 0, 0, 0, 0)	/* RFC2616 14.43 */
-HTTPH("Vary",			H_Vary,			2, 0, 0, 0, 0)	/* RFC2616 14.44 */
-HTTPH("Via",			H_Via,			2, 0, 0, 0, 0)	/* RFC2616 14.45 */
-HTTPH("Warning",		H_Warning,		2, 0, 0, 0, 0)	/* RFC2616 14.46 */
-HTTPH("WWW-Authenticate",	H_WWW_Authenticate,	2, 0, 0, 0, 0)	/* RFC2616 14.47 */
+HTTPH("Keep-Alive",		H_Keep_Alive,		3, 3, HTTPH_R_PASS | HTTPH_A_PASS | HTTPH_R_FETCH,					0, 0)	/* RFC2068 */
+HTTPH("Accept",			H_Accept,		1, 0, 0,										0, 0)	/* RFC2616 14.1 */
+HTTPH("Accept-Charset",		H_Accept_Charset,	1, 0, 0,										0, 0)	/* RFC2616 14.2 */
+HTTPH("Accept-Encoding",	H_Accept_Encoding,	1, 0, 0,										0, 0)	/* RFC2616 14.3 */
+HTTPH("Accept-Language",	H_Accept_Language,	1, 0, 0,										0, 0)	/* RFC2616 14.4 */
+HTTPH("Accept-Ranges",		H_Accept_Ranges,	2, 3, HTTPH_R_PASS | HTTPH_A_PASS | HTTPH_R_FETCH | HTTPH_A_INS,			0, 0)	/* RFC2616 14.5 */
+HTTPH("Age",			H_Age,			2, 0, 						    HTTPH_A_INS,			0, 0)	/* RFC2616 14.6 */
+HTTPH("Allow",			H_Allow,		2, 0, 0,										0, 0)	/* RFC2616 14.7 */
+HTTPH("Authorization",		H_Authorization,	1, 0, 0,										0, 0)	/* RFC2616 14.8 */
+HTTPH("Cache-Control",		H_Cache_Control,	3, 3, HTTPH_R_PASS | 		    HTTPH_R_FETCH,					0, 0)	/* RFC2616 14.9 */
+HTTPH("Connection",		H_Connection,		3, 3, HTTPH_R_PASS | HTTPH_A_PASS | HTTPH_R_FETCH | HTTPH_A_INS,			0, 0)	/* RFC2616 14.10 */
+HTTPH("Content-Encoding",	H_Content_Encoding,	2, 0, 0,										0, 0)	/* RFC2616 14.11 */
+HTTPH("Content-Langugae",	H_Content_Language,	2, 0, 0,										0, 0)	/* RFC2616 14.12 */
+HTTPH("Content-Length",		H_Content_Length,	2, 2, 				    HTTPH_R_FETCH | HTTPH_A_INS,			0, 0)	/* RFC2616 14.13 */
+HTTPH("Content-Location",	H_Content_Location,	2, 0, 0,										0, 0)	/* RFC2616 14.14 */
+HTTPH("Content-MD5",		H_Content_MD5,		2, 0, 0,										0, 0)	/* RFC2616 14.15 */
+HTTPH("Content-Range",		H_Content_Range,	2, 3, HTTPH_R_PASS | HTTPH_A_PASS | HTTPH_R_FETCH | HTTPH_A_INS,			0, 0)	/* RFC2616 14.16 */
+HTTPH("Content-Type",		H_Content_Type,		2, 0, 0,										0, 0)	/* RFC2616 14.17 */
+HTTPH("Date",			H_Date,			2, 0, 								HTTPH_A_DELIVER,	0, 0)	/* RFC2616 14.18 */
+HTTPH("ETag",			H_ETag,			2, 0, 0,										0, 0)	/* RFC2616 14.19 */
+HTTPH("Expect",			H_Expect,		1, 0, 0,										0, 0)	/* RFC2616 14.20 */
+HTTPH("Expires",		H_Expires,		2, 0, 0,										0, 0)	/* RFC2616 14.21 */
+HTTPH("From",			H_From,			1, 0, 0,										0, 0)	/* RFC2616 14.22 */
+HTTPH("Host",			H_Host,			1, 0, 0,										0, 0)	/* RFC2616 14.23 */
+HTTPH("If-Match",		H_If_Match,		1, 1, 				    HTTPH_R_FETCH,					0, 0)	/* RFC2616 14.24 */
+HTTPH("If-Modified-Since",	H_If_Modified_Since,	1, 1, 				    HTTPH_R_FETCH,					0, 0)	/* RFC2616 14.25 */
+HTTPH("If-None-Match",		H_If_None_Match,	1, 1, 				    HTTPH_R_FETCH,					0, 0)	/* RFC2616 14.26 */
+HTTPH("If-Range",		H_If_Range,		1, 1, 				    HTTPH_R_FETCH,					0, 0)	/* RFC2616 14.27 */
+HTTPH("If-Unmodified-Since",	H_If_Unmodifed_Since,	1, 1, 				    HTTPH_R_FETCH,					0, 0)	/* RFC2616 14.28 */
+HTTPH("Last-Modified",		H_Last_Modified,	2, 0, 0,										0, 0)	/* RFC2616 14.29 */
+HTTPH("Location",		H_Location,		2, 0, 0,										0, 0)	/* RFC2616 14.30 */
+HTTPH("Max-Forwards",		H_Max_Forwards,		1, 0, 0,										0, 0)	/* RFC2616 14.31 */
+HTTPH("Pragma",			H_Pragma,		1, 0, 0,										0, 0)	/* RFC2616 14.32 */
+HTTPH("Proxy-Authenticate",	H_Proxy_Authenticate,	2, 3, 				    HTTPH_R_FETCH | HTTPH_A_INS,			0, 0)	/* RFC2616 14.33 */
+HTTPH("Proxy-Authorization",	H_Proxy_Authorization,	1, 3, 				    HTTPH_R_FETCH | HTTPH_A_INS,			0, 0)	/* RFC2616 14.34 */
+HTTPH("Range",			H_Range,		1, 0, 0,										0, 0)	/* RFC2616 14.35 */
+HTTPH("Referer",		H_Referer,		1, 0, 0,										0, 0)	/* RFC2616 14.36 */
+HTTPH("Retry-After",		H_Retry_After,		2, 0, 0,										0, 0)	/* RFC2616 14.37 */
+HTTPH("Server",			H_Server,		2, 0, 0,										0, 0)	/* RFC2616 14.38 */
+HTTPH("TE",			H_TE,			1, 3, HTTPH_R_PASS | HTTPH_A_PASS | HTTPH_R_FETCH | HTTPH_A_INS,			0, 0)	/* RFC2616 14.39 */
+HTTPH("Trailer",		H_Trailer,		1, 3, HTTPH_R_PASS | HTTPH_A_PASS | HTTPH_R_FETCH | HTTPH_A_INS,			0, 0)	/* RFC2616 14.40 */
+HTTPH("Transfer-Encoding",	H_Transfer_Encoding,	2, 3, HTTPH_R_PASS | HTTPH_A_PASS | HTTPH_R_FETCH | HTTPH_A_INS,			0, 0)	/* RFC2616 14.41 */
+HTTPH("Upgrade",		H_Upgrade,		2, 3, HTTPH_R_PASS | HTTPH_A_PASS | HTTPH_R_FETCH | HTTPH_A_INS,			0, 0)	/* RFC2616 14.42 */
+HTTPH("User-Agent",		H_User_Agent,		1, 0, 0,										0, 0)	/* RFC2616 14.43 */
+HTTPH("Vary",			H_Vary,			2, 0, 0,										0, 0)	/* RFC2616 14.44 */
+HTTPH("Via",			H_Via,			2, 0, 0,										0, 0)	/* RFC2616 14.45 */
+HTTPH("Warning",		H_Warning,		2, 0, 0,										0, 0)	/* RFC2616 14.46 */
+HTTPH("WWW-Authenticate",	H_WWW_Authenticate,	2, 0, 0,										0, 0)	/* RFC2616 14.47 */
diff -Nru 2.0.3/varnish-cache/include/http_response.h trunk/varnish-cache/include/http_response.h
--- 2.0.3/varnish-cache/include/http_response.h	1970-01-01 01:00:00.000000000 +0100
+++ trunk/varnish-cache/include/http_response.h	2008-11-06 12:22:00.000000000 +0100
@@ -0,0 +1,71 @@
+/*-
+ * Copyright (c) 2006 Verdens Gang AS
+ * Copyright (c) 2006-2008 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$
+ */
+
+HTTP_RESP(101, "Switching Protocols")
+HTTP_RESP(200, "OK")
+HTTP_RESP(201, "Created")
+HTTP_RESP(202, "Accepted")
+HTTP_RESP(203, "Non-Authoritative Information")
+HTTP_RESP(204, "No Content")
+HTTP_RESP(205, "Reset Content")
+HTTP_RESP(206, "Partial Content")
+HTTP_RESP(300, "Multiple Choices")
+HTTP_RESP(301, "Moved Permanently")
+HTTP_RESP(302, "Found")
+HTTP_RESP(303, "See Other")
+HTTP_RESP(304, "Not Modified")
+HTTP_RESP(305, "Use Proxy")
+HTTP_RESP(306, "(Unused)")
+HTTP_RESP(307, "Temporary Redirect")
+HTTP_RESP(400, "Bad Request")
+HTTP_RESP(401, "Unauthorized")
+HTTP_RESP(402, "Payment Required")
+HTTP_RESP(403, "Forbidden")
+HTTP_RESP(404, "Not Found")
+HTTP_RESP(405, "Method Not Allowed")
+HTTP_RESP(406, "Not Acceptable")
+HTTP_RESP(407, "Proxy Authentication Required")
+HTTP_RESP(408, "Request Timeout")
+HTTP_RESP(409, "Conflict")
+HTTP_RESP(410, "Gone")
+HTTP_RESP(411, "Length Required")
+HTTP_RESP(412, "Precondition Failed")
+HTTP_RESP(413, "Request Entity Too Large")
+HTTP_RESP(414, "Request-URI Too Long")
+HTTP_RESP(415, "Unsupported Media Type")
+HTTP_RESP(416, "Requested Range Not Satisfiable")
+HTTP_RESP(417, "Expectation Failed")
+HTTP_RESP(500, "Internal Server Error")
+HTTP_RESP(501, "Not Implemented")
+HTTP_RESP(502, "Bad Gateway")
+HTTP_RESP(503, "Service Unavailable")
+HTTP_RESP(504, "Gateway Timeout")
+HTTP_RESP(505, "HTTP Version Not Supported")
diff -Nru 2.0.3/varnish-cache/include/libvarnish.h trunk/varnish-cache/include/libvarnish.h
--- 2.0.3/varnish-cache/include/libvarnish.h	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/include/libvarnish.h	2009-01-05 14:45:26.000000000 +0100
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: libvarnish.h 3260 2008-10-07 09:46:21Z tfheen $
+ * $Id: libvarnish.h 3477 2008-12-21 10:45:33Z phk $
  */
 
 #include <errno.h>
@@ -37,6 +37,8 @@
 #define NULL ((void*)0)
 #endif
 
+struct vsb;
+
 /* from libvarnish/argv.c */
 void FreeArgv(char **argv);
 char **ParseArgv(const char *s, int flag);
@@ -50,6 +52,10 @@
 /* from libvarnish/num.c */
 const char *str2bytes(const char *p, uintmax_t *r, uintmax_t rel);
 
+/* from libvarnish/subproc.c */
+typedef void sub_func_f(void*);
+int SUB_run(struct vsb *sb, sub_func_f *func, void *priv, const char *name, int maxlines);
+
 /* from libvarnish/tcp.c */
 /* NI_MAXHOST and NI_MAXSERV are ridiculously long for numeric format */
 #define TCP_ADDRBUFSIZE		64
@@ -60,9 +66,12 @@
 void TCP_blocking(int sock);
 void TCP_nonblocking(int sock);
 #ifdef SOL_SOCKET
-void TCP_name(const struct sockaddr *addr, unsigned l, char *abuf, unsigned alen, char *pbuf, unsigned plen);
-int TCP_connect(int s, const struct sockaddr *name, socklen_t namelen, int msec);
+void TCP_name(const struct sockaddr *addr, unsigned l, char *abuf,
+    unsigned alen, char *pbuf, unsigned plen);
+int TCP_connect(int s, const struct sockaddr *name, socklen_t namelen,
+    int msec);
 void TCP_close(int *s);
+void TCP_set_read_timeout(int socket, double seconds);
 #endif
 
 /* from libvarnish/time.c */
@@ -77,6 +86,7 @@
 
 /* from libvarnish/vtmpfile.c */
 int vtmpfile(char *);
+char *vreadfile(const char *fn);
 
 /*
  * assert(), AN() and AZ() are static checks that should not happen.
@@ -88,7 +98,8 @@
  *	handle gracefully, such as malloc failure.
  */
 
-typedef void lbv_assert_f(const char *, const char *, int, const char *, int, int);
+typedef void lbv_assert_f(const char *, const char *, int, const char *,
+    int, int);
 
 extern lbv_assert_f *lbv_assert;
 
@@ -96,14 +107,14 @@
 #define assert(e)	((void)(e))
 #else /* WITH_ASSERTS */
 #define assert(e)							\
-do { 									\
+do {									\
 	if (!(e))							\
 		lbv_assert(__func__, __FILE__, __LINE__, #e, errno, 0);	\
 } while (0)
 #endif
 
 #define xxxassert(e)							\
-do { 									\
+do {									\
 	if (!(e))							\
 		lbv_assert(__func__, __FILE__, __LINE__, #e, errno, 1); \
 } while (0)
@@ -114,7 +125,8 @@
 #define XXXAZ(foo)	do { xxxassert((foo) == 0); } while (0)
 #define XXXAN(foo)	do { xxxassert((foo) != 0); } while (0)
 #define diagnostic(foo)	assert(foo)
-#define WRONG(expl) 							\
+#define WRONG(expl)							\
 do {									\
 	lbv_assert(__func__, __FILE__, __LINE__, expl, errno, 3);	\
+	abort();							\
 } while (0)
diff -Nru 2.0.3/varnish-cache/include/libvcl.h trunk/varnish-cache/include/libvcl.h
--- 2.0.3/varnish-cache/include/libvcl.h	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/include/libvcl.h	2009-01-05 14:45:26.000000000 +0100
@@ -26,11 +26,10 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: libvcl.h 2415 2008-01-31 11:57:51Z des $
+ * $Id: libvcl.h 3478 2008-12-21 10:46:34Z phk $
  */
 
 char *VCC_Compile(struct vsb *sb, const char *b, const char *e);
-char *VCC_CompileFile(struct vsb *sb, const char *fn, int fd);
 void VCC_InitCompile(const char *default_vcl);
-
+const char *VCC_Return_Name(unsigned action);
 
diff -Nru 2.0.3/varnish-cache/include/Makefile.am trunk/varnish-cache/include/Makefile.am
--- 2.0.3/varnish-cache/include/Makefile.am	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/include/Makefile.am	2009-01-05 14:45:26.000000000 +0100
@@ -1,4 +1,4 @@
-# $Id: Makefile.am 2939 2008-07-11 21:33:26Z phk $
+# $Id: Makefile.am 3421 2008-11-24 10:17:24Z phk $
 
 pkginclude_HEADERS = \
 	shmlog.h \
@@ -20,7 +20,6 @@
 	compat/strlcpy.h \
 	compat/strndup.h \
 	compat/vasprintf.h \
-	compat/vis.h \
 	flopen.h \
 	http_headers.h \
 	libvarnish.h \
diff -Nru 2.0.3/varnish-cache/include/Makefile.in trunk/varnish-cache/include/Makefile.in
diff -Nru 2.0.3/varnish-cache/include/stat_field.h trunk/varnish-cache/include/stat_field.h
--- 2.0.3/varnish-cache/include/stat_field.h	2008-11-10 11:09:32.000000000 +0100
+++ trunk/varnish-cache/include/stat_field.h	2009-01-05 14:45:26.000000000 +0100
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: stat_field.h 3370 2008-11-10 10:09:31Z tfheen $
+ * $Id: stat_field.h 3454 2008-12-03 10:49:34Z phk $
  */
 
 MAC_STAT(client_conn,		uint64_t, 'a', "Client connections accepted")
@@ -37,7 +37,8 @@
 MAC_STAT(cache_miss,		uint64_t, 'a', "Cache misses")
 
 MAC_STAT(backend_conn,		uint64_t, 'a', "Backend connections success")
-MAC_STAT(backend_unhealthy,	uint64_t, 'a', "Backend connections not attempted")
+MAC_STAT(backend_unhealthy,	uint64_t, 'a',
+    "Backend connections not attempted")
 MAC_STAT(backend_busy,		uint64_t, 'a', "Backend connections too many")
 MAC_STAT(backend_fail,		uint64_t, 'a', "Backend connections failures")
 MAC_STAT(backend_reuse,		uint64_t, 'a', "Backend connections reuses")
@@ -125,3 +126,7 @@
 MAC_STAT(n_purge_obj_test,	uint64_t, 'a', "N objects tested")
 MAC_STAT(n_purge_re_test,	uint64_t, 'a', "N regexps tested against")
 MAC_STAT(n_purge_dups,		uint64_t, 'a', "N duplicate purges removed")
+
+MAC_STAT(hcb_nolock,		uint64_t, 'a', "HCB Lookups without lock")
+MAC_STAT(hcb_lock,		uint64_t, 'a', "HCB Lookups with lock")
+MAC_STAT(hcb_insert,		uint64_t, 'a', "HCB Inserts")
--- 2.0.3/varnish-cache/include/varnishapi.h	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/include/varnishapi.h	2008-10-20 10:58:16.000000000 +0200
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: varnishapi.h 2575 2008-03-09 15:14:04Z des $
+ * $Id: varnishapi.h 3324 2008-10-18 20:50:10Z phk $
  */
 
 #ifndef VARNISHAPI_H_INCLUDED
@@ -41,11 +41,13 @@
 int base64_decode(char *d, unsigned dlen, const char *s);
 
 /* shmlog.c */
-typedef int vsl_handler(void *priv, enum shmlogtag tag, unsigned fd, unsigned len, unsigned spec, const char *ptr);
+typedef int vsl_handler(void *priv, enum shmlogtag tag, unsigned fd,
+    unsigned len, unsigned spec, const char *ptr);
 #define VSL_S_CLIENT	(1 << 0)
 #define VSL_S_BACKEND	(1 << 1)
 #define VSL_ARGS	"bCcdI:i:k:r:s:X:x:"
-#define VSL_USAGE	"[-bCcd] [-i tag] [-I regexp] [-k keep] [-r file] [-s skip] [-X regexp] [-x tag]"
+#define VSL_USAGE	"[-bCcd] [-i tag] [-I regexp] [-k keep]" \
+			" [-r file] [-s skip] [-X regexp] [-x tag]"
 vsl_handler VSL_H_Print;
 struct VSL_data;
 struct VSL_data *VSL_New(void);
@@ -60,6 +62,6 @@
 extern const char *VSL_tags[256];
 
 /* instance.c */
-int		 varnish_instance(const char *n_arg, char *name, size_t namelen, char *dir, size_t dirlen);
-
+int varnish_instance(const char *n_arg, char *name, size_t namelen, char *dir,
+    size_t dirlen);
 #endif
diff -Nru 2.0.3/varnish-cache/include/vcl.h trunk/varnish-cache/include/vcl.h
--- 2.0.3/varnish-cache/include/vcl.h	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/include/vcl.h	2009-01-05 14:45:26.000000000 +0100
@@ -1,9 +1,9 @@
 /*
- * $Id: vcl.h 3039 2008-07-31 10:01:36Z phk $
+ * $Id: vcl.h 3485 2008-12-21 17:03:37Z phk $
  *
  * NB:  This file is machine generated, DO NOT EDIT!
  *
- * Edit vcc_gen_fixed_token.tcl instead
+ * Edit and run vcc_gen_fixed_token.tcl instead
  */
 
 struct sess;
@@ -13,25 +13,55 @@
 typedef void vcl_fini_f(struct cli *);
 typedef int vcl_func_f(struct sess *sp);
 
+/* VCL Methods */
+#define VCL_MET_RECV		(1 << 0)
+#define VCL_MET_PIPE		(1 << 1)
+#define VCL_MET_PASS		(1 << 2)
+#define VCL_MET_HASH		(1 << 3)
+#define VCL_MET_MISS		(1 << 4)
+#define VCL_MET_HIT		(1 << 5)
+#define VCL_MET_FETCH		(1 << 6)
+#define VCL_MET_DELIVER		(1 << 7)
+#define VCL_MET_PREFETCH	(1 << 8)
+#define VCL_MET_TIMEOUT		(1 << 9)
+#define VCL_MET_DISCARD		(1 << 10)
+#define VCL_MET_ERROR		(1 << 11)
+
+#define VCL_MET_MAX		12
+
+/* VCL Returns */
+#define VCL_RET_ERROR		0
+#define VCL_RET_LOOKUP		1
+#define VCL_RET_HASH		2
+#define VCL_RET_PIPE		3
+#define VCL_RET_PASS		4
+#define VCL_RET_FETCH		5
+#define VCL_RET_DELIVER		6
+#define VCL_RET_DISCARD		7
+#define VCL_RET_KEEP		8
+#define VCL_RET_RESTART		9
+
+#define VCL_RET_MAX		10
+
 struct VCL_conf {
-	unsigned        magic;
-#define VCL_CONF_MAGIC  0x7406c509      /* from /dev/random */
+	unsigned	magic;
+#define VCL_CONF_MAGIC	0x7406c509	/* from /dev/random */
+
+	struct director	**director;
+	unsigned	ndirector;
+	struct vrt_ref	*ref;
+	unsigned	nref;
+	unsigned	busy;
+	unsigned	discard;
 
-        struct director  **director;
-        unsigned        ndirector;
-        struct vrt_ref  *ref;
-        unsigned        nref;
-        unsigned        busy;
-        unsigned        discard;
-        
 	unsigned	nsrc;
 	const char	**srcname;
 	const char	**srcbody;
 
 	unsigned	nhashcount;
 
-        vcl_init_f      *init_func;
-        vcl_fini_f      *fini_func;
+	vcl_init_f	*init_func;
+	vcl_fini_f	*fini_func;
 
 	vcl_func_f	*recv_func;
 	vcl_func_f	*pipe_func;
diff -Nru 2.0.3/varnish-cache/include/vcl_returns.h trunk/varnish-cache/include/vcl_returns.h
--- 2.0.3/varnish-cache/include/vcl_returns.h	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/include/vcl_returns.h	2009-01-05 14:45:26.000000000 +0100
@@ -1,63 +1,78 @@
 /*
- * $Id: vcl_returns.h 3048 2008-07-31 22:38:01Z phk $
+ * $Id: vcl_returns.h 3485 2008-12-21 17:03:37Z phk $
  *
  * NB:  This file is machine generated, DO NOT EDIT!
  *
- * Edit vcc_gen_fixed_token.tcl instead
+ * Edit and run vcc_gen_fixed_token.tcl instead
  */
 
 #ifdef VCL_RET_MAC
-#ifdef VCL_RET_MAC_E
-VCL_RET_MAC_E(error, ERROR, (1 << 0), 0)
-#endif
-VCL_RET_MAC(lookup, LOOKUP, (1 << 1), 1)
-VCL_RET_MAC(hash, HASH, (1 << 2), 2)
-VCL_RET_MAC(pipe, PIPE, (1 << 3), 3)
-VCL_RET_MAC(pass, PASS, (1 << 4), 4)
-VCL_RET_MAC(fetch, FETCH, (1 << 5), 5)
-VCL_RET_MAC(deliver, DELIVER, (1 << 6), 6)
-VCL_RET_MAC(discard, DISCARD, (1 << 7), 7)
-VCL_RET_MAC(keep, KEEP, (1 << 8), 8)
-VCL_RET_MAC(restart, RESTART, (1 << 9), 9)
-#else
-#define VCL_RET_ERROR  (1 << 0)
-#define VCL_RET_LOOKUP  (1 << 1)
-#define VCL_RET_HASH  (1 << 2)
-#define VCL_RET_PIPE  (1 << 3)
-#define VCL_RET_PASS  (1 << 4)
-#define VCL_RET_FETCH  (1 << 5)
-#define VCL_RET_DELIVER  (1 << 6)
-#define VCL_RET_DISCARD  (1 << 7)
-#define VCL_RET_KEEP  (1 << 8)
-#define VCL_RET_RESTART  (1 << 9)
-#define VCL_RET_MAX 10
+VCL_RET_MAC(error, ERROR)
+VCL_RET_MAC(lookup, LOOKUP)
+VCL_RET_MAC(hash, HASH)
+VCL_RET_MAC(pipe, PIPE)
+VCL_RET_MAC(pass, PASS)
+VCL_RET_MAC(fetch, FETCH)
+VCL_RET_MAC(deliver, DELIVER)
+VCL_RET_MAC(discard, DISCARD)
+VCL_RET_MAC(keep, KEEP)
+VCL_RET_MAC(restart, RESTART)
 #endif
 
 #ifdef VCL_MET_MAC
-VCL_MET_MAC(recv,RECV,(VCL_RET_ERROR|VCL_RET_PASS|VCL_RET_PIPE|VCL_RET_LOOKUP))
-VCL_MET_MAC(pipe,PIPE,(VCL_RET_ERROR|VCL_RET_PIPE))
-VCL_MET_MAC(pass,PASS,(VCL_RET_ERROR|VCL_RET_RESTART|VCL_RET_PASS))
-VCL_MET_MAC(hash,HASH,(VCL_RET_HASH))
-VCL_MET_MAC(miss,MISS,(VCL_RET_ERROR|VCL_RET_RESTART|VCL_RET_PASS|VCL_RET_FETCH))
-VCL_MET_MAC(hit,HIT,(VCL_RET_ERROR|VCL_RET_RESTART|VCL_RET_PASS|VCL_RET_DELIVER))
-VCL_MET_MAC(fetch,FETCH,(VCL_RET_ERROR|VCL_RET_RESTART|VCL_RET_PASS|VCL_RET_DELIVER))
-VCL_MET_MAC(deliver,DELIVER,(VCL_RET_RESTART|VCL_RET_DELIVER))
-VCL_MET_MAC(prefetch,PREFETCH,(VCL_RET_FETCH|VCL_RET_PASS))
-VCL_MET_MAC(timeout,TIMEOUT,(VCL_RET_FETCH|VCL_RET_DISCARD))
-VCL_MET_MAC(discard,DISCARD,(VCL_RET_DISCARD|VCL_RET_KEEP))
-VCL_MET_MAC(error,ERROR,(VCL_RET_DELIVER))
-#else
-#define VCL_MET_RECV	(1 << 0)
-#define VCL_MET_PIPE	(1 << 1)
-#define VCL_MET_PASS	(1 << 2)
-#define VCL_MET_HASH	(1 << 3)
-#define VCL_MET_MISS	(1 << 4)
-#define VCL_MET_HIT	(1 << 5)
-#define VCL_MET_FETCH	(1 << 6)
-#define VCL_MET_DELIVER	(1 << 7)
-#define VCL_MET_PREFETCH	(1 << 8)
-#define VCL_MET_TIMEOUT	(1 << 9)
-#define VCL_MET_DISCARD	(1 << 10)
-#define VCL_MET_ERROR	(1 << 11)
+VCL_MET_MAC(recv,RECV,
+     ((1 << VCL_RET_ERROR)
+    | (1 << VCL_RET_PASS)
+    | (1 << VCL_RET_PIPE)
+    | (1 << VCL_RET_LOOKUP)
+))
+VCL_MET_MAC(pipe,PIPE,
+     ((1 << VCL_RET_ERROR)
+    | (1 << VCL_RET_PIPE)
+))
+VCL_MET_MAC(pass,PASS,
+     ((1 << VCL_RET_ERROR)
+    | (1 << VCL_RET_RESTART)
+    | (1 << VCL_RET_PASS)
+))
+VCL_MET_MAC(hash,HASH,
+     ((1 << VCL_RET_HASH)
+))
+VCL_MET_MAC(miss,MISS,
+     ((1 << VCL_RET_ERROR)
+    | (1 << VCL_RET_RESTART)
+    | (1 << VCL_RET_PASS)
+    | (1 << VCL_RET_FETCH)
+))
+VCL_MET_MAC(hit,HIT,
+     ((1 << VCL_RET_ERROR)
+    | (1 << VCL_RET_RESTART)
+    | (1 << VCL_RET_PASS)
+    | (1 << VCL_RET_DELIVER)
+))
+VCL_MET_MAC(fetch,FETCH,
+     ((1 << VCL_RET_ERROR)
+    | (1 << VCL_RET_RESTART)
+    | (1 << VCL_RET_PASS)
+    | (1 << VCL_RET_DELIVER)
+))
+VCL_MET_MAC(deliver,DELIVER,
+     ((1 << VCL_RET_RESTART)
+    | (1 << VCL_RET_DELIVER)
+))
+VCL_MET_MAC(prefetch,PREFETCH,
+     ((1 << VCL_RET_FETCH)
+    | (1 << VCL_RET_PASS)
+))
+VCL_MET_MAC(timeout,TIMEOUT,
+     ((1 << VCL_RET_FETCH)
+    | (1 << VCL_RET_DISCARD)
+))
+VCL_MET_MAC(discard,DISCARD,
+     ((1 << VCL_RET_DISCARD)
+    | (1 << VCL_RET_KEEP)
+))
+VCL_MET_MAC(error,ERROR,
+     ((1 << VCL_RET_DELIVER)
+))
 #endif
-#define N_METHODS 12
diff -Nru 2.0.3/varnish-cache/include/vct.h trunk/varnish-cache/include/vct.h
--- 2.0.3/varnish-cache/include/vct.h	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/include/vct.h	2008-10-20 10:58:16.000000000 +0200
@@ -26,15 +26,15 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: vct.h 2757 2008-06-21 18:51:29Z phk $
+ * $Id: vct.h 3324 2008-10-18 20:50:10Z phk $
  */
 
 /* from libvarnish/vct.c */
 
-#define VCT_SP    	(1<<0)
-#define VCT_CRLF  	(1<<1)
-#define VCT_LWS   	(VCT_CRLF | VCT_SP)
-#define VCT_CTL   	(1<<2)
+#define VCT_SP		(1<<0)
+#define VCT_CRLF	(1<<1)
+#define VCT_LWS		(VCT_CRLF | VCT_SP)
+#define VCT_CTL		(1<<2)
 #define VCT_ALPHA	(1<<3)
 #define VCT_SEPARATOR	(1<<4)
 #define VCT_DIGIT	(1<<5)
@@ -45,8 +45,8 @@
 static inline int
 vct_is(unsigned char x, unsigned char y)
 {
- 
-        return (vct_typtab[x] & (y));
+
+	return (vct_typtab[x] & (y));
 }
 
 #define vct_issp(x) vct_is(x, VCT_SP)
diff -Nru 2.0.3/varnish-cache/include/vev.h trunk/varnish-cache/include/vev.h
--- 2.0.3/varnish-cache/include/vev.h	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/include/vev.h	2008-10-20 10:58:16.000000000 +0200
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: vev.h 2939 2008-07-11 21:33:26Z phk $
+ * $Id: vev.h 3324 2008-10-18 20:50:10Z phk $
  */
 
 #include <poll.h>
@@ -40,7 +40,7 @@
 
 struct vev {
 	unsigned		magic;
-#define VEV_MAGIC		0x46bbd419 
+#define VEV_MAGIC		0x46bbd419
 
 	/* pub */
 	const char		*name;
diff -Nru 2.0.3/varnish-cache/include/vqueue.h trunk/varnish-cache/include/vqueue.h
--- 2.0.3/varnish-cache/include/vqueue.h	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/include/vqueue.h	2008-10-20 10:58:16.000000000 +0200
@@ -28,7 +28,7 @@
  *
  *	@(#)queue.h	8.5 (Berkeley) 8/20/94
  * $FreeBSD: src/sys/sys/queue.h,v 1.68 2006/10/24 11:20:29 ru Exp $
- * $Id: vqueue.h 2033 2007-09-25 08:48:14Z des $
+ * $Id: vqueue.h 3324 2008-10-18 20:50:10Z phk $
  */
 
 #ifndef VARNISH_QUEUE_H
@@ -220,7 +220,8 @@
 } while (0)
 
 #define	VSTAILQ_INSERT_AFTER(head, tqelm, elm, field) do {		\
-	if ((VSTAILQ_NEXT((elm), field) = VSTAILQ_NEXT((tqelm), field)) == NULL)\
+	if ((VSTAILQ_NEXT((elm), field) =				\
+	    VSTAILQ_NEXT((tqelm), field)) == NULL)			\
 		(head)->vstqh_last = &VSTAILQ_NEXT((elm), field);	\
 	VSTAILQ_NEXT((tqelm), field) = (elm);				\
 } while (0)
@@ -241,7 +242,8 @@
 	(VSTAILQ_EMPTY((head)) ?					\
 		NULL :							\
 	        ((struct type *)(void *)				\
-		((char *)((head)->vstqh_last) - __offsetof(struct type, field))))
+		((char *)((head)->vstqh_last) - 			\
+		     __offsetof(struct type, field))))
 
 #define	VSTAILQ_NEXT(elm, field)	((elm)->field.vstqe_next)
 
@@ -320,7 +322,8 @@
 
 #define	VLIST_INSERT_HEAD(head, elm, field) do {			\
 	if ((VLIST_NEXT((elm), field) = VLIST_FIRST((head))) != NULL)	\
-		VLIST_FIRST((head))->field.vle_prev = &VLIST_NEXT((elm), field);\
+		VLIST_FIRST((head))->field.vle_prev =			\
+		    &VLIST_NEXT((elm), field);				\
 	VLIST_FIRST((head)) = (elm);					\
 	(elm)->field.vle_prev = &VLIST_FIRST((head));			\
 } while (0)
@@ -329,7 +332,7 @@
 
 #define	VLIST_REMOVE(elm, field) do {					\
 	if (VLIST_NEXT((elm), field) != NULL)				\
-		VLIST_NEXT((elm), field)->field.vle_prev = 		\
+		VLIST_NEXT((elm), field)->field.vle_prev =		\
 		    (elm)->field.vle_prev;				\
 	*(elm)->field.vle_prev = VLIST_NEXT((elm), field);		\
 } while (0)
@@ -394,8 +397,9 @@
 } while (0)
 
 #define	VTAILQ_INSERT_AFTER(head, listelm, elm, field) do {		\
-	if ((VTAILQ_NEXT((elm), field) = VTAILQ_NEXT((listelm), field)) != NULL)\
-		VTAILQ_NEXT((elm), field)->field.vtqe_prev = 		\
+	if ((VTAILQ_NEXT((elm), field) =				\
+	    VTAILQ_NEXT((listelm), field)) != NULL)			\
+		VTAILQ_NEXT((elm), field)->field.vtqe_prev =		\
 		    &VTAILQ_NEXT((elm), field);				\
 	else {								\
 		(head)->vtqh_last = &VTAILQ_NEXT((elm), field);		\
@@ -438,7 +442,7 @@
 
 #define	VTAILQ_REMOVE(head, elm, field) do {				\
 	if ((VTAILQ_NEXT((elm), field)) != NULL)			\
-		VTAILQ_NEXT((elm), field)->field.vtqe_prev = 		\
+		VTAILQ_NEXT((elm), field)->field.vtqe_prev =		\
 		    (elm)->field.vtqe_prev;				\
 	else {								\
 		(head)->vtqh_last = (elm)->field.vtqe_prev;		\
diff -Nru 2.0.3/varnish-cache/include/vrt.h trunk/varnish-cache/include/vrt.h
--- 2.0.3/varnish-cache/include/vrt.h	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/include/vrt.h	2009-01-05 14:45:26.000000000 +0100
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: vrt.h 3234 2008-09-29 07:32:26Z phk $
+ * $Id: vrt.h 3406 2008-11-19 14:13:57Z petter $
  *
  * Runtime support for compiled VCL programs.
  *
@@ -69,8 +69,10 @@
 	const unsigned char		*ipv6_sockaddr;
 
 	double				connect_timeout;
+	double				first_byte_timeout;
+	double				between_bytes_timeout;
 	unsigned			max_connections;
-	struct vrt_backend_probe 	probe;
+	struct vrt_backend_probe	probe;
 };
 
 /*
@@ -92,9 +94,9 @@
 };
 
 struct vrt_dir_random {
-	const char 				*name;
+	const char				*name;
 	unsigned				retries;
-	unsigned 				nmember;
+	unsigned				nmember;
 	const struct vrt_dir_random_entry	*members;
 };
 
@@ -108,7 +110,7 @@
 
 struct vrt_dir_round_robin {
 	const char				*name;
-	unsigned 				nmember;
+	unsigned				nmember;
 	const struct vrt_dir_round_robin_entry	*members;
 };
 
@@ -136,8 +138,8 @@
 void VRT_re_init(void **, const char *, int sub);
 void VRT_re_fini(void *);
 int VRT_re_match(const char *, void *re);
-int VRT_re_test(struct vsb *, const char *, int sub);
-const char *VRT_regsub(const struct sess *sp, int all, const char *, void *, const char *);
+const char *VRT_regsub(const struct sess *sp, int all, const char *,
+    void *, const char *);
 
 void VRT_panic(struct sess *sp,  const char *, ...);
 void VRT_purge(const char *, int hash);
@@ -149,7 +151,8 @@
 
 enum gethdr_e { HDR_REQ, HDR_RESP, HDR_OBJ, HDR_BEREQ };
 char *VRT_GetHdr(const struct sess *, enum gethdr_e where, const char *);
-void VRT_SetHdr(const struct sess *, enum gethdr_e where, const char *, const char *, ...);
+void VRT_SetHdr(const struct sess *, enum gethdr_e where, const char *,
+    const char *, ...);
 void VRT_handling(struct sess *sp, unsigned hand);
 
 /* Simple stuff */
@@ -163,9 +166,12 @@
 void VRT_synth_page(struct sess *sp, unsigned flags, const char *, ...);
 
 /* Backend related */
-void VRT_init_dir_simple(struct cli *, struct director **, const struct vrt_dir_simple *);
-void VRT_init_dir_random(struct cli *, struct director **, const struct vrt_dir_random *);
-void VRT_init_dir_round_robin(struct cli *, struct director **, const struct vrt_dir_round_robin *);
+void VRT_init_dir_simple(struct cli *, struct director **,
+    const struct vrt_dir_simple *);
+void VRT_init_dir_random(struct cli *, struct director **,
+    const struct vrt_dir_random *);
+void VRT_init_dir_round_robin(struct cli *, struct director **,
+    const struct vrt_dir_round_robin *);
 void VRT_fini_dir(struct cli *, struct director *);
 
 char *VRT_IP_string(const struct sess *sp, const struct sockaddr *sa);
diff -Nru 2.0.3/varnish-cache/include/vrt_obj.h trunk/varnish-cache/include/vrt_obj.h
--- 2.0.3/varnish-cache/include/vrt_obj.h	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/include/vrt_obj.h	2009-01-05 14:45:26.000000000 +0100
@@ -1,5 +1,5 @@
 /*
- * $Id: vrt_obj.h 3169 2008-09-08 09:49:01Z tfheen $
+ * $Id: vrt_obj.h 3406 2008-11-19 14:13:57Z petter $
  *
  * NB:  This file is machine generated, DO NOT EDIT!
  *
@@ -28,6 +28,12 @@
 void VRT_l_bereq_url(const struct sess *, const char *, ...);
 const char * VRT_r_bereq_proto(const struct sess *);
 void VRT_l_bereq_proto(const struct sess *, const char *, ...);
+double VRT_r_bereq_connect_timeout(struct sess *);
+void VRT_l_bereq_connect_timeout(struct sess *, double);
+double VRT_r_bereq_first_byte_timeout(struct sess *);
+void VRT_l_bereq_first_byte_timeout(struct sess *, double);
+double VRT_r_bereq_between_bytes_timeout(struct sess *);
+void VRT_l_bereq_between_bytes_timeout(struct sess *, double);
 const char * VRT_r_obj_proto(const struct sess *);
 void VRT_l_obj_proto(const struct sess *, const char *, ...);
 int VRT_r_obj_status(const struct sess *);
diff -Nru 2.0.3/varnish-cache/include/vsb.h trunk/varnish-cache/include/vsb.h
--- 2.0.3/varnish-cache/include/vsb.h	2009-01-09 15:39:13.000000000 +0100
+++ trunk/varnish-cache/include/vsb.h	2009-01-05 14:45:26.000000000 +0100
@@ -23,7 +23,7 @@
  * (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: vsb.h 3024 2008-07-25 14:53:08Z phk $
+ * $Id: vsb.h 3420 2008-11-24 10:05:55Z phk $
  * $FreeBSD: src/sys/sys/vsb.h,v 1.14 2004/07/09 11:35:30 des Exp $
  */
 
@@ -63,9 +63,11 @@
 int		 vsb_bcpy(struct vsb *, const void *, size_t);
 int		 vsb_cat(struct vsb *, const char *);
 int		 vsb_cpy(struct vsb *, const char *);
-int		 vsb_printf(struct vsb *, const char *, ...) /* __printflike(2, 3) */;
+int		 vsb_printf(struct vsb *, const char *, ...)
+    /* __printflike(2, 3) */;
 #ifdef va_start
-int		 vsb_vprintf(struct vsb *, const char *, va_list) /* __printflike(2, 0) */;
+int		 vsb_vprintf(struct vsb *, const char *, va_list)
+    /* __printflike(2, 0) */;
 #endif
 int		 vsb_putc(struct vsb *, int);
 int		 vsb_trim(struct vsb *);
diff -Nru 2.0.3/varnish-cache/include/vsha256.h trunk/varnish-cache/include/vsha256.h
--- 2.0.3/varnish-cache/include/vsha256.h	1970-01-01 01:00:00.000000000 +0100
+++ trunk/varnish-cache/include/vsha256.h	2009-01-05 14:45:26.000000000 +0100
@@ -0,0 +1,47 @@
+/*-
+ * Copyright 2005 Colin Percival
+ * All rights reserved.
+ *
+ * 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 THE 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.
+ *
+ * $FreeBSD: head/lib/libmd/sha256.h 154479 2006-01-17 15:35:57Z phk $
+ */
+
+#ifndef _SHA256_H_
+#define _SHA256_H_
+
+#include <stdint.h>
+
+typedef struct SHA256Context {
+	uint32_t state[8];
+	uint64_t count;
+	unsigned char buf[64];
+} SHA256_CTX;
+
+__BEGIN_DECLS
+void	SHA256_Init(SHA256_CTX *);
+void	SHA256_Update(SHA256_CTX *, const void *, size_t);
+void	SHA256_Final(unsigned char [32], SHA256_CTX *);
+void	SHA256_Test(void);
+__END_DECLS
+
+#endif /* !_SHA256_H_ */
diff -Nru 2.0.3/varnish-cache/lib/libjemalloc/jemalloc_linux.c trunk/varnish-cache/lib/libjemalloc/jemalloc_linux.c
--- 2.0.3/varnish-cache/lib/libjemalloc/jemalloc_linux.c	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/lib/libjemalloc/jemalloc_linux.c	2009-01-05 14:45:26.000000000 +0100
@@ -200,6 +200,17 @@
 
 #include "rb.h"
 
+/* Prevent -Werror to complain about unused parameters when compiling
+   with non-ancient GCC.  Added directly here instead of grabbed from
+   ansidecl.h to save a build dependency on binutils-dev */
+#if __GNUC__ >= 3
+#ifndef ATTRIBUTE_UNUSED
+#define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
+#endif /* ATTRIBUTE_UNUSED */
+#else
+#define ATTRIBUTE_UNUSED
+#endif
+
 #ifdef MALLOC_DEBUG
    /* Disable inlining to make debugging easier. */
 #  define inline
@@ -1113,7 +1124,6 @@
 static bool	base_pages_alloc_mmap(size_t minsize);
 static bool	base_pages_alloc(size_t minsize);
 static void	*base_alloc(size_t size);
-static void	*base_calloc(size_t number, size_t size);
 static extent_node_t *base_node_alloc(void);
 static void	base_node_dealloc(extent_node_t *node);
 #ifdef MALLOC_STATS
@@ -1200,6 +1210,14 @@
  */
 /******************************************************************************/
 
+/*
+ * Functions missing prototypes which caused -Werror to fail. 
+ * Not sure if it has any side effects.
+ * */
+size_t malloc_usable_size(const void *ptr);
+void _malloc_thread_cleanup(void);
+
+
 static void
 wrtmessage(const char *p1, const char *p2, const char *p3, const char *p4)
 {
@@ -1625,17 +1643,6 @@
 	return (ret);
 }
 
-static void *
-base_calloc(size_t number, size_t size)
-{
-	void *ret;
-
-	ret = base_alloc(number * size);
-	memset(ret, 0, number * size);
-
-	return (ret);
-}
-
 static extent_node_t *
 base_node_alloc(void)
 {
@@ -1779,7 +1786,7 @@
 }
 
 /* Wrap red-black tree macros in functions. */
-rb_wrap(static, extent_tree_szad_, extent_tree_t, extent_node_t,
+rb_wrap(static ATTRIBUTE_UNUSED, extent_tree_szad_, extent_tree_t, extent_node_t,
     link_szad, extent_szad_comp)
 #endif
 
@@ -1793,7 +1800,7 @@
 }
 
 /* Wrap red-black tree macros in functions. */
-rb_wrap(static, extent_tree_ad_, extent_tree_t, extent_node_t, link_ad,
+rb_wrap(static ATTRIBUTE_UNUSED, extent_tree_ad_, extent_tree_t, extent_node_t, link_ad,
     extent_ad_comp)
 
 /*
@@ -2029,6 +2036,7 @@
 {
 	void *ret;
 
+	(void)zero; /* XXX */
 	assert(size != 0);
 	assert((size & chunksize_mask) == 0);
 
@@ -2346,7 +2354,7 @@
 }
 
 /* Wrap red-black tree macros in functions. */
-rb_wrap(static, arena_chunk_tree_dirty_, arena_chunk_tree_t,
+rb_wrap(static ATTRIBUTE_UNUSED, arena_chunk_tree_dirty_, arena_chunk_tree_t,
     arena_chunk_t, link_dirty, arena_chunk_comp)
 
 static inline int
@@ -2362,7 +2370,7 @@
 }
 
 /* Wrap red-black tree macros in functions. */
-rb_wrap(static, arena_run_tree_, arena_run_tree_t, arena_chunk_map_t,
+rb_wrap(static ATTRIBUTE_UNUSED, arena_run_tree_, arena_run_tree_t, arena_chunk_map_t,
     link, arena_run_comp)
 
 static inline int
@@ -2394,7 +2402,7 @@
 }
 
 /* Wrap red-black tree macros in functions. */
-rb_wrap(static, arena_avail_tree_, arena_avail_tree_t,
+rb_wrap(static ATTRIBUTE_UNUSED, arena_avail_tree_, arena_avail_tree_t,
     arena_chunk_map_t, link, arena_avail_comp)
 
 static inline void *
@@ -3045,6 +3053,7 @@
 {
 	void *ret;
 
+	(void)arena; /* XXX */
 	assert(run->magic == ARENA_RUN_MAGIC);
 	assert(run->nfree > 0);
 
diff -Nru 2.0.3/varnish-cache/lib/libjemalloc/Makefile.in trunk/varnish-cache/lib/libjemalloc/Makefile.in
diff -Nru 2.0.3/varnish-cache/lib/libjemalloc/.svn/dir-prop-base trunk/varnish-cache/lib/libjemalloc/.svn/dir-prop-base
diff -Nru 2.0.3/varnish-cache/lib/libjemalloc/.svn/entries trunk/varnish-cache/lib/libjemalloc/.svn/entries
diff -Nru 2.0.3/varnish-cache/lib/libjemalloc/.svn/text-base/jemalloc_linux.c.svn-base trunk/varnish-cache/lib/libjemalloc/.svn/text-base/jemalloc_linux.c.svn-base
diff -Nru 2.0.3/varnish-cache/lib/libvarnish/argv.c trunk/varnish-cache/lib/libvarnish/argv.c
--- 2.0.3/varnish-cache/lib/libvarnish/argv.c	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/lib/libvarnish/argv.c	2008-11-06 12:22:01.000000000 +0100
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: argv.c 3072 2008-08-11 07:47:24Z phk $
+ * $Id: argv.c 3336 2008-10-20 18:47:24Z des $
  *
  * const char **ParseArgv(const char *s, int comment)
  *	Parse a command like line into an argv[]
@@ -45,7 +45,6 @@
 #include <stdio.h>
 #include <stdint.h>
 
-#include "config.h"
 #include "libvarnish.h"
 
 static int
diff -Nru 2.0.3/varnish-cache/lib/libvarnish/assert.c trunk/varnish-cache/lib/libvarnish/assert.c
--- 2.0.3/varnish-cache/lib/libvarnish/assert.c	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/lib/libvarnish/assert.c	2008-11-06 12:22:01.000000000 +0100
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: assert.c 3072 2008-08-11 07:47:24Z phk $
+ * $Id: assert.c 3336 2008-10-20 18:47:24Z des $
  *
  * This is the default backend function for libvarnish' assert facilities.
  */
@@ -37,11 +37,11 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include "config.h"
 #include "libvarnish.h"
 
 static void
-lbv_assert_default(const char *func, const char *file, int line, const char *cond, int err, int xxx)
+lbv_assert_default(const char *func, const char *file, int line,
+    const char *cond, int err, int xxx)
 {
 
 	if (xxx) {
diff -Nru 2.0.3/varnish-cache/lib/libvarnish/binary_heap.c trunk/varnish-cache/lib/libvarnish/binary_heap.c
--- 2.0.3/varnish-cache/lib/libvarnish/binary_heap.c	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/lib/libvarnish/binary_heap.c	2009-01-05 14:45:26.000000000 +0100
@@ -26,14 +26,12 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: binary_heap.c 3079 2008-08-11 09:49:41Z tfheen $
+ * $Id: binary_heap.c 3390 2008-11-14 00:19:33Z phk $
  *
  * Implementation of a binary heap API
  *
  * We use a malloc(3)/realloc(3) array to store the pointers using the
  * classical FORTRAN strategy.
- *
- * XXX: the array is not scaled back when items are deleted.
  */
 
 #include "config.h"
@@ -41,42 +39,74 @@
 #include <unistd.h>
 #include <stdlib.h>
 
-#include "config.h"
 #include "binary_heap.h"
 #include "libvarnish.h"
 
-/* Private definitions -----------------------------------------------*/
+/* Paramters ---------------------------------------------------------*/
 
-#define MIN_LENGTH		16
+/*
+ * The number of elements in a row has to be a compromise between
+ * wasted space and number of memory allocations.
+ * With 64k objects per row, there will be at least 5...10 seconds
+ * between row additions on a very busy server.
+ * At the same time, the worst case amount of wasted memory is kept
+ * at a reasonable 1 MB -- two rows on 64bit system.
+ * Finally, but without practical significance: 16 bits should be
+ * easier for the compiler to optimize.
+ */
+#define ROW_SHIFT		16
+
+/* Private definitions -----------------------------------------------*/
 
 #define ROOT_IDX		1
 
+#define ROW_WIDTH		(1 << ROW_SHIFT)
+
+/*lint -emacro(572, ROW) shift 0 >> by 16 */
+/*lint -emacro(835, ROW) 0 left of >> */
+/*lint -emacro(778, ROW) const >> evaluates to zero */
+#define ROW(b, n)		((b)->array[(n) >> ROW_SHIFT])
+
+/*lint -emacro(835, A) 0 left of & */
+#define A(b, n)			ROW(b, n)[(n) & (ROW_WIDTH - 1)]
+
 struct binheap {
 	unsigned		magic;
 #define BINHEAP_MAGIC		0xf581581aU	/* from /dev/random */
 	void			*priv;
 	binheap_cmp_t		*cmp;
 	binheap_update_t	*update;
-	void			**array;
+	void			***array;
+	unsigned		rows;
 	unsigned		length;
 	unsigned		next;
-	unsigned		granularity;
 };
 
 #define PARENT(u)	((u) / 2)
+/*lint -emacro(835, CHILD) 0 right of + */
 #define CHILD(u,n)	((u) * 2 + (n))
 
 /* Implementation ----------------------------------------------------*/
 
 static void
-binheap_update(const struct binheap *bh, unsigned u)
+binheap_addrow(struct binheap *bh)
 {
-	assert(bh->magic == BINHEAP_MAGIC);
-	assert(u < bh->next);
-	assert(bh->array[u] != NULL);
-	if (bh->update == NULL)
-		return;
-	bh->update(bh->priv, bh->array[u], u);
+	unsigned u;
+
+	/* First make sure we have space for another row */
+	if (&ROW(bh, bh->length) >= bh->array + bh->rows) {
+		u = bh->rows * 2;
+		bh->array = realloc(bh->array, sizeof(*bh->array) * u);
+		assert(bh->array != NULL);
+
+		/* NULL out new pointers */
+		while (bh->rows < u)
+			bh->array[bh->rows++] = NULL;
+	}
+	assert(ROW(bh, bh->length) == NULL);
+	ROW(bh, bh->length) = malloc(sizeof(**bh->array) * ROW_WIDTH);
+	assert(ROW(bh, bh->length));
+	bh->length += ROW_WIDTH;
 }
 
 struct binheap *
@@ -91,15 +121,27 @@
 	bh->cmp = cmp_f;
 	bh->update = update_f;
 	bh->next = ROOT_IDX;
-	bh->length = MIN_LENGTH;
-	bh->array = calloc(sizeof *bh->array, bh->length);
+	bh->rows = 16;		/* A tiny-ish number */
+	bh->array = calloc(sizeof *bh->array, bh->rows);
 	assert(bh->array != NULL);
-	bh->granularity = getpagesize() / sizeof *bh->array;
+	binheap_addrow(bh);
+	A(bh, ROOT_IDX) = NULL;
 	bh->magic = BINHEAP_MAGIC;
 	return (bh);
 }
 
 static void
+binheap_update(const struct binheap *bh, unsigned u)
+{
+	assert(bh->magic == BINHEAP_MAGIC);
+	assert(u < bh->next);
+	assert(A(bh, u) != NULL);
+	if (bh->update == NULL)
+		return;
+	bh->update(bh->priv, A(bh, u), u);
+}
+
+static void
 binhead_swap(const struct binheap *bh, unsigned u, unsigned v)
 {
 	void *p;
@@ -107,9 +149,9 @@
 	assert(bh->magic == BINHEAP_MAGIC);
 	assert(u < bh->next);
 	assert(v < bh->next);
-	p = bh->array[u];
-	bh->array[u] = bh->array[v];
-	bh->array[v] = p;
+	p = A(bh, u);
+	A(bh, u) = A(bh, v);
+	A(bh, v) = p;
 	binheap_update(bh, u);
 	binheap_update(bh, v);
 }
@@ -122,11 +164,10 @@
 	assert(bh->magic == BINHEAP_MAGIC);
 	while (u > ROOT_IDX) {
 		v = PARENT(u);
-		if (bh->cmp(bh->priv, bh->array[u], bh->array[v])) {
-			binhead_swap(bh, u, v);
-			u = v;
-		} else
+		if (!bh->cmp(bh->priv, A(bh, u), A(bh, v)))
 			break;
+		binhead_swap(bh, u, v);
+		u = v;
 	}
 	return (u);
 }
@@ -139,28 +180,15 @@
 	assert(bh->magic == BINHEAP_MAGIC);
 	while (1) {
 		v1 = CHILD(u, 0);
-		v2 = CHILD(u, 1);
 		if (v1 >= bh->next)
 			return;
-		if (v2 >= bh->next) {
-			if (!bh->cmp(bh->priv, bh->array[u], bh->array[v1]))
-				binhead_swap(bh, u, v1);
+		v2 = CHILD(u, 1);
+		if (v2 < bh->next && bh->cmp(bh->priv, A(bh, v2), A(bh, v1)))
+			v1 = v2;
+		if (bh->cmp(bh->priv, A(bh, u), A(bh, v1))) 
 			return;
-		}
-		if (bh->cmp(bh->priv, bh->array[v1], bh->array[v2])) {
-			if (!bh->cmp(bh->priv, bh->array[u], bh->array[v1])) {
-				binhead_swap(bh, u, v1);
-				u = v1;
-				continue;
-			}
-		} else {
-			if (!bh->cmp(bh->priv, bh->array[u], bh->array[v2])) {
-				binhead_swap(bh, u, v2);
-				u = v2;
-				continue;
-			}
-		}
-		return;
+		binhead_swap(bh, u, v1);
+		u = v1;
 	}
 }
 
@@ -172,18 +200,10 @@
 	assert(bh != NULL);
 	assert(bh->magic == BINHEAP_MAGIC);
 	assert(bh->length >= bh->next);
-	if (bh->length == bh->next) {
-		if (bh->length >= bh->granularity * 32)
-			bh->length += bh->granularity * 32;
-		else if (bh->length > bh->granularity)
-			bh->length += bh->granularity;
-		else
-			bh->length += bh->length;
-		bh->array = realloc(bh->array, bh->length * sizeof *bh->array);
-		assert(bh->array != NULL);
-	}
+	if (bh->length == bh->next)
+		binheap_addrow(bh);
 	u = bh->next++;
-	bh->array[u] = p;
+	A(bh, u) = p;
 	binheap_update(bh, u);
 	(void)binheap_trickleup(bh, u);
 }
@@ -194,11 +214,33 @@
 
 	assert(bh != NULL);
 	assert(bh->magic == BINHEAP_MAGIC);
-	if (bh->next == ROOT_IDX)
-		return (NULL);
-	return (bh->array[ROOT_IDX]);
+	return (A(bh, ROOT_IDX));
 }
 
+/*
+ * It may seem counter-intuitive that we delete by replacement with
+ * the tail object. "That's almost certain to not belong there, in
+ * particular when we delete the root ?" is the typical reaction.
+ *
+ * If we tried to trickle up into the empty position, we would,
+ * eventually, end up with a hole in the bottom row, at which point
+ * we would move the tail object there.
+ * But there is no guarantee that the tail object would not need to
+ * trickle up from that position, in fact, it might be the new root
+ * of this half of the subtree.
+ * The total number of operations is guaranteed to be at least
+ * N{height} downward selections, because we have to get the hole
+ * all the way down, but in addition to that, we may get up to
+ * N{height}-1 upward trickles.
+ *
+ * When we fill the hole with the tail object, the worst case is
+ * that it trickles all the way down to become the tail object
+ * again.
+ * In other words worst case is N{height} downward trickles.
+ * But there is a pretty decent chance that it does not make
+ * it all the way down.
+ */
+
 void
 binheap_delete(struct binheap *bh, unsigned idx)
 {
@@ -208,27 +250,38 @@
 	assert(bh->next > ROOT_IDX);
 	assert(idx < bh->next);
 	assert(idx > 0);
-	assert(bh->array[idx] != NULL);
-	bh->update(bh->priv, bh->array[idx], 0);
+	assert(A(bh, idx) != NULL);
+	bh->update(bh->priv, A(bh, idx), 0);
 	if (idx == --bh->next) {
-		bh->array[bh->next] = NULL;
+		A(bh, bh->next) = NULL;
 		return;
 	}
-	bh->array[idx] = bh->array[bh->next];
-	bh->array[bh->next] = NULL;
+	A(bh, idx) = A(bh, bh->next);
+	A(bh, bh->next) = NULL;
 	binheap_update(bh, idx);
 	idx = binheap_trickleup(bh, idx);
 	binheap_trickledown(bh, idx);
-	/* XXX: free part of array ? */
+
+	/*
+	 * We keep a hysteresis of one full row before we start to
+	 * return space to the OS to avoid silly behaviour around
+	 * row boundaries.
+	 */
+	if (bh->next + 2 * ROW_WIDTH <= bh->length) {
+		free(ROW(bh, bh->length - 1));
+		ROW(bh, bh->length - 1) = NULL;
+		bh->length -= ROW_WIDTH;
+	}
 }
 
 
 #ifdef TEST_DRIVER
 /* Test driver -------------------------------------------------------*/
-
 #include <stdio.h>
 
-#if 0
+#if 1
+
+#define N 23
 
 static int
 cmp(void *priv, void *a, void *b)
@@ -250,14 +303,14 @@
 	unsigned u, *up;
 
 	printf("dump\n");
-	f = popen("dot -Tps >> /tmp/_.ps", "w");
+	f = popen("dot -Tps >> /tmp/_.ps 2>/dev/null", "w");
 	assert(f != NULL);
 	fprintf(f, "digraph binheap {\n");
 	fprintf(f, "size=\"7,10\"\n");
 	fprintf(f, "ptr [label=\"%s\"]\n", what);
 	fprintf(f, "ptr -> node_%u\n", ptr);
 	for (u = 1; u < bh->next; u++) {
-		up = bh->array[u];
+		up = A(bh, u);
 		fprintf(f, "node_%u [label=\"%u\"];\n", u, *up);
 		if (u > 0)
 			fprintf(f, "node_%u -> node_%u\n", PARENT(u), u);
@@ -266,7 +319,6 @@
 	pclose(f);
 }
 
-#define N 31
 int
 main(int argc, char **argv)
 {
@@ -289,28 +341,25 @@
 			break;
 		assert(*up >= lu);
 		lu = *up;
-		u = random() % bh->next;
+		u = (random() % (bh->next - 1)) + 1;
 		binheap_delete(bh, u);
 		if (1)
 			dump(bh, "Delete", u);
 	}
 	printf("Deletes done\n");
-
 	return (0);
 }
 #else
-
 struct foo {
 	unsigned	idx;
 	unsigned	key;
 };
 
 #define M 1311191
-#define N 131
+#define N 1311
 
 struct foo ff[N];
 
-
 static int
 cmp(void *priv, void *a, void *b)
 {
@@ -338,8 +387,8 @@
 
 	for (u = 2; u < bh->next; u++) {
 		v = PARENT(u);
-		fa = bh->array[u];
-		fb = bh->array[v];
+		fa = A(bh, u);
+		fb = A(bh, v);
 		assert(fa->key > fb->key);
 		continue;
 		printf("[%2u/%2u] %10u > [%2u/%2u] %10u %s\n",
@@ -359,21 +408,27 @@
 	struct binheap *bh;
 	unsigned u, v;
 
-#if 0
-	srandomdev();
-	u = random();
-	printf("Seed %u\n", u);
-	srandom(u);
-#endif
+	if (0) {
+		srandomdev();
+		u = random();
+		printf("Seed %u\n", u);
+		srandom(u);
+	}
 	bh = binheap_new(NULL, cmp, update);
 	for (u = 0; u < M; u++) {
 		v = random() % N;
 		if (ff[v].idx > 0) {
-			printf("Delete [%u] %'u\n", v, ff[v].key);
+			if (0)
+				printf("Delete [%u] %'u\n", v, ff[v].key);
+			else
+				printf("-%u", v);
 			binheap_delete(bh, ff[v].idx);
 		} else {
 			ff[v].key = random();
-			printf("Insert [%u] %'u\n", v, ff[v].key);
+			if (0) 
+				printf("Insert [%u] %'u\n", v, ff[v].key);
+			else
+				printf("+%u", v);
 			binheap_insert(bh, &ff[v]);
 		}
 		chk(bh);
diff -Nru 2.0.3/varnish-cache/lib/libvarnish/cli_common.c trunk/varnish-cache/lib/libvarnish/cli_common.c
--- 2.0.3/varnish-cache/lib/libvarnish/cli_common.c	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/lib/libvarnish/cli_common.c	2009-01-05 14:45:26.000000000 +0100
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: cli_common.c 3072 2008-08-11 07:47:24Z phk $
+ * $Id: cli_common.c 3494 2008-12-21 18:40:10Z phk $
  */
 
 #include "config.h"
@@ -46,7 +46,6 @@
 #include <time.h>
 #include <unistd.h>
 
-#include "config.h"
 #include "vsb.h"
 
 #include "libvarnish.h"
@@ -124,7 +123,7 @@
 	if (cli != NULL)
 		cli->result = res;	/*lint !e64 type mismatch */
 	else
-		printf("CLI result = %d\n", res);
+		printf("CLI result = %u\n", res);
 }
 
 void
@@ -132,7 +131,8 @@
 {
 
 	cli_result(cli, CLIS_PARAM);
-	cli_out(cli, "Parameter error, use \"help [command]\" for more info.\n");
+	cli_out(cli,
+	    "Parameter error, use \"help [command]\" for more info.\n");
 }
 
 int
@@ -192,15 +192,16 @@
 {
 	char res[CLI_LINE0_LEN];	/* For NUL */
 	int i, j;
-	unsigned u, v;
+	unsigned u, v, s;
 	char *p;
 
+	if (status == NULL)
+		status = &s;
 	if (ptr != NULL)
 		*ptr = NULL;
 	i = read_tmo(fd, res, CLI_LINE0_LEN, tmo);
 	if (i != CLI_LINE0_LEN) {
-		if (status != NULL)
-			*status = CLIS_COMMS;
+		*status = CLIS_COMMS;
 		if (ptr != NULL)
 			*ptr = strdup("CLI communication error");
 		return (1);
@@ -211,12 +212,12 @@
 	res[CLI_LINE0_LEN - 1] = '\0';
 	j = sscanf(res, "%u %u\n", &u, &v);
 	assert(j == 2);
-	if (status != NULL)
-		*status = u;
+	*status = u;
 	p = malloc(v + 1);
 	assert(p != NULL);
 	i = read_tmo(fd, p, v + 1, tmo);
 	if (i < 0) {
+		*status = CLIS_COMMS;
 		free(p);
 		return (i);
 	}
diff -Nru 2.0.3/varnish-cache/lib/libvarnish/crc32.c trunk/varnish-cache/lib/libvarnish/crc32.c
--- 2.0.3/varnish-cache/lib/libvarnish/crc32.c	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/lib/libvarnish/crc32.c	2008-11-10 09:23:00.000000000 +0100
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: crc32.c 2455 2008-02-13 13:55:39Z des $
+ * $Id: crc32.c 3364 2008-11-09 14:25:22Z phk $
  *
  * This CRC32 implementation is in the public domain.
  */
@@ -37,7 +37,7 @@
 
 /*--------------------------------------------------------------------*/
 
-static uint32_t crc32bits[] = {
+static const uint32_t crc32bits[] = {
     0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
     0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
     0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
diff -Nru 2.0.3/varnish-cache/lib/libvarnish/flint.lnt trunk/varnish-cache/lib/libvarnish/flint.lnt
--- 2.0.3/varnish-cache/lib/libvarnish/flint.lnt	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/lib/libvarnish/flint.lnt	2009-01-05 14:45:26.000000000 +0100
@@ -11,6 +11,8 @@
 
 -header(../../config.h)
 
+-efile(451, "../../config.h")
+
 // Fix strchr() semtics, it can only return NULL if arg2 != 0
 -sem(strchr, 1p, type(1), 2n == 0 ? (@p < 1p) : (@p < 1p || @p == 0 ))
 
diff -Nru 2.0.3/varnish-cache/lib/libvarnish/flopen.c trunk/varnish-cache/lib/libvarnish/flopen.c
--- 2.0.3/varnish-cache/lib/libvarnish/flopen.c	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/lib/libvarnish/flopen.c	2008-11-06 12:22:01.000000000 +0100
@@ -24,30 +24,29 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: flopen.c 3072 2008-08-11 07:47:24Z phk $
+ * $Id: flopen.c 3336 2008-10-20 18:47:24Z des $
  * Derived from:
- * $FreeBSD: src/lib/libutil/flopen.c,v 1.7 2007/05/23 12:09:33 des Exp $
+ * $FreeBSD: head/lib/libutil/flopen.c 184094 2008-10-20 18:11:30Z des $
  */
 
 #include "config.h"
 
-#include <sys/file.h>
 #include <sys/stat.h>
 
 #include <errno.h>
 #include <fcntl.h>
 #include <stdarg.h>
+#include <string.h>
 #include <unistd.h>
 
-#include "config.h"
 #include "flopen.h"
 
 int
 flopen(const char *path, int flags, ...)
 {
 	int fd, operation, serrno, trunc;
-	struct stat sb, fsb;
 	struct flock lock;
+	struct stat sb, fsb;
 	mode_t mode;
 
 #ifdef O_EXLOCK
@@ -63,10 +62,9 @@
 		va_end(ap);
 	}
 
+	memset(&lock, 0, sizeof lock);
 	lock.l_type = ((flags & O_ACCMODE) == O_RDONLY) ? F_RDLCK : F_WRLCK;
-	lock.l_start = 0;
 	lock.l_whence = SEEK_SET;
-	lock.l_len = 0;
 	operation = (flags & O_NONBLOCK) ? F_SETLK : F_SETLKW;
 
 	trunc = (flags & O_TRUNC);
diff -Nru 2.0.3/varnish-cache/lib/libvarnish/Makefile.am trunk/varnish-cache/lib/libvarnish/Makefile.am
--- 2.0.3/varnish-cache/lib/libvarnish/Makefile.am	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/lib/libvarnish/Makefile.am	2009-01-05 14:45:26.000000000 +0100
@@ -1,4 +1,4 @@
-# $Id: Makefile.am 3140 2008-08-29 09:37:19Z tfheen $
+# $Id: Makefile.am 3436 2008-11-25 11:07:39Z phk $
 
 INCLUDES = -I$(top_srcdir)/include
 
@@ -10,6 +10,7 @@
 	argv.c \
 	assert.c \
 	binary_heap.c \
+	subproc.c \
 	cli.c \
 	cli_common.c \
 	crc32.c \
@@ -23,6 +24,7 @@
 	vlu.c \
 	vpf.c \
 	vsb.c \
+	vsha256.c \
 	vss.c \
 	vtmpfile.c
 
diff -Nru 2.0.3/varnish-cache/lib/libvarnish/Makefile.in trunk/varnish-cache/lib/libvarnish/Makefile.in
diff -Nru 2.0.3/varnish-cache/lib/libvarnish/num.c trunk/varnish-cache/lib/libvarnish/num.c
--- 2.0.3/varnish-cache/lib/libvarnish/num.c	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/lib/libvarnish/num.c	2008-10-20 10:58:16.000000000 +0200
@@ -25,7 +25,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: num.c 3107 2008-08-19 09:35:28Z phk $
+ * $Id: num.c 3324 2008-10-18 20:50:10Z phk $
  *
  * Deal with numbers with data storage suffix scaling
  */
@@ -125,45 +125,45 @@
 	uintmax_t val;
 	const char *err;
 } test_cases[] = {
-	{ "1",			(uintmax_t)0,		(uintmax_t)1 },
-	{ "1B",			(uintmax_t)0,		(uintmax_t)1<<0 },
-	{ "1 B",		(uintmax_t)0,		(uintmax_t)1<<0 },
-	{ "1.3B",		(uintmax_t)0,		(uintmax_t)1 },
-	{ "1.7B",		(uintmax_t)0,		(uintmax_t)2 },
-
-	{ "1024",		(uintmax_t)0,		(uintmax_t)1024 },
-	{ "1k",			(uintmax_t)0,		(uintmax_t)1<<10 },
-	{ "1kB",		(uintmax_t)0,		(uintmax_t)1<<10 },
-	{ "1.3kB",		(uintmax_t)0,		(uintmax_t)1331 },
-	{ "1.7kB",		(uintmax_t)0,		(uintmax_t)1741 },
-
-	{ "1048576",		(uintmax_t)0,		(uintmax_t)1048576 },
-	{ "1M",			(uintmax_t)0,		(uintmax_t)1<<20 },
-	{ "1MB",		(uintmax_t)0,		(uintmax_t)1<<20 },
-	{ "1.3MB",		(uintmax_t)0,		(uintmax_t)1363149 },
-	{ "1.7MB",		(uintmax_t)0,		(uintmax_t)1782579 },
-
-	{ "1073741824",		(uintmax_t)0,		(uintmax_t)1073741824 },
-	{ "1G",			(uintmax_t)0,		(uintmax_t)1<<30 },
-	{ "1GB",		(uintmax_t)0,		(uintmax_t)1<<30 },
-	{ "1.3GB",		(uintmax_t)0,		(uintmax_t)1395864371 },
-	{ "1.7GB",		(uintmax_t)0,		(uintmax_t)1825361101 },
-
-	{ "1099511627776",	(uintmax_t)0,		(uintmax_t)1099511627776ULL },
-	{ "1T",			(uintmax_t)0,		(uintmax_t)1<<40 },
-	{ "1TB",		(uintmax_t)0,		(uintmax_t)1<<40 },
-	{ "1.3TB",		(uintmax_t)0,		(uintmax_t)1429365116109ULL },
-	{ "1.7TB",		(uintmax_t)0,		(uintmax_t)1869169767219ULL },
+	{ "1",			(uintmax_t)0,	(uintmax_t)1 },
+	{ "1B",			(uintmax_t)0,	(uintmax_t)1<<0 },
+	{ "1 B",		(uintmax_t)0,	(uintmax_t)1<<0 },
+	{ "1.3B",		(uintmax_t)0,	(uintmax_t)1 },
+	{ "1.7B",		(uintmax_t)0,	(uintmax_t)2 },
+
+	{ "1024",		(uintmax_t)0,	(uintmax_t)1024 },
+	{ "1k",			(uintmax_t)0,	(uintmax_t)1<<10 },
+	{ "1kB",		(uintmax_t)0,	(uintmax_t)1<<10 },
+	{ "1.3kB",		(uintmax_t)0,	(uintmax_t)1331 },
+	{ "1.7kB",		(uintmax_t)0,	(uintmax_t)1741 },
+
+	{ "1048576",		(uintmax_t)0,	(uintmax_t)1048576 },
+	{ "1M",			(uintmax_t)0,	(uintmax_t)1<<20 },
+	{ "1MB",		(uintmax_t)0,	(uintmax_t)1<<20 },
+	{ "1.3MB",		(uintmax_t)0,	(uintmax_t)1363149 },
+	{ "1.7MB",		(uintmax_t)0,	(uintmax_t)1782579 },
+
+	{ "1073741824",		(uintmax_t)0,	(uintmax_t)1073741824 },
+	{ "1G",			(uintmax_t)0,	(uintmax_t)1<<30 },
+	{ "1GB",		(uintmax_t)0,	(uintmax_t)1<<30 },
+	{ "1.3GB",		(uintmax_t)0,	(uintmax_t)1395864371 },
+	{ "1.7GB",		(uintmax_t)0,	(uintmax_t)1825361101 },
+
+	{ "1099511627776",	(uintmax_t)0,	(uintmax_t)1099511627776ULL },
+	{ "1T",			(uintmax_t)0,	(uintmax_t)1<<40 },
+	{ "1TB",		(uintmax_t)0,	(uintmax_t)1<<40 },
+	{ "1.3TB",		(uintmax_t)0,	(uintmax_t)1429365116109ULL },
+	{ "1.7TB",		(uintmax_t)0,	(uintmax_t)1869169767219ULL },
 
 	{ "1%",			(uintmax_t)1024,	(uintmax_t)10 },
 	{ "2%",			(uintmax_t)1024,	(uintmax_t)20 },
 	{ "3%",			(uintmax_t)1024,	(uintmax_t)31 },
 
 	/* Check the error checks */
-	{ "",			0,			0,				err_miss_num },
-	{ "m",			0,			0,				err_invalid_num },
-	{ "4%",			0,			0,				err_abs_req },
-	{ "3*",			0,			0,				err_invalid_suff },
+	{ "",			0,	0,	err_miss_num },
+	{ "m",			0,	0,	err_invalid_num },
+	{ "4%",			0,	0,	err_abs_req },
+	{ "3*",			0,	0,	err_invalid_suff },
 
 	/* TODO: add more */
 
diff -Nru 2.0.3/varnish-cache/lib/libvarnish/subproc.c trunk/varnish-cache/lib/libvarnish/subproc.c
--- 2.0.3/varnish-cache/lib/libvarnish/subproc.c	1970-01-01 01:00:00.000000000 +0100
+++ trunk/varnish-cache/lib/libvarnish/subproc.c	2009-01-05 14:45:26.000000000 +0100
@@ -0,0 +1,133 @@
+/*-
+ * Copyright (c) 2006 Verdens Gang AS
+ * Copyright (c) 2006-2008 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$
+ *
+ * Run stuff in a child process
+ */
+
+#include "config.h"
+
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+
+#include <sys/wait.h>
+
+#include "vsb.h"
+#include "vlu.h"
+#include "libvarnish.h"
+
+struct sub_priv {
+	const char	*name;
+	struct vsb	*sb;
+	int		lines;
+	int		maxlines;
+};
+
+static int
+sub_vlu(void *priv, const char *str)
+{
+	struct sub_priv *sp;
+
+	sp = priv;
+	if (!sp->lines++)
+		vsb_printf(sp->sb, "Message from %s:\n", sp->name);
+	if (sp->maxlines < 0 || sp->lines <= sp->maxlines)
+		vsb_printf(sp->sb, "%s\n", str);
+	return (0);
+}
+
+int
+SUB_run(struct vsb *sb, sub_func_f *func, void *priv, const char *name, int maxlines)
+{
+	int rv, p[2], sfd, status;
+	pid_t pid;
+	struct vlu *vlu;
+	struct sub_priv sp;
+
+	sp.sb = sb;
+	sp.name = name;
+	sp.lines = 0;
+	sp.maxlines = maxlines;
+
+	if (pipe(p) < 0) {
+		vsb_printf(sb, "Starting %s: pipe() failed: %s",
+		    name, strerror(errno));
+		return (-1);
+	}
+	assert(p[0] > STDERR_FILENO);
+	assert(p[1] > STDERR_FILENO);
+	if ((pid = fork()) < 0) {
+		vsb_printf(sb, "Starting %s: fork() failed: %s",
+		    name, strerror(errno));
+		AZ(close(p[0]));
+		AZ(close(p[1]));
+		return (-1);
+	}
+	if (pid == 0) {
+		AZ(close(STDIN_FILENO));
+		assert(open("/dev/null", O_RDONLY) == STDIN_FILENO);
+		assert(dup2(p[1], STDOUT_FILENO) == STDOUT_FILENO);
+		assert(dup2(p[1], STDERR_FILENO) == STDERR_FILENO);
+		/* Close all other fds */
+		for (sfd = STDERR_FILENO + 1; sfd < 100; sfd++)
+			(void)close(sfd);
+		func(priv);
+		_exit(1);
+	}
+	AZ(close(p[1]));
+	vlu = VLU_New(&sp, sub_vlu, 0);
+	while (!VLU_Fd(p[0], vlu))
+		continue;
+	AZ(close(p[0]));
+	VLU_Destroy(vlu);
+	if (sp.maxlines >= 0 && sp.lines > sp.maxlines)
+		vsb_printf(sb, "[%d lines truncated]\n",
+		    sp.lines - sp.maxlines);
+	do {
+		rv = waitpid(pid, &status, 0);
+		if (rv < 0 && errno != EINTR) {
+			vsb_printf(sb, "Running %s: waitpid() failed: %s",
+			    name, strerror(errno));
+			return (-1);
+		}
+	} while (rv < 0);
+	if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
+		vsb_printf(sb, "Running %s failed", name);
+		if (WIFEXITED(status))
+			vsb_printf(sb, ", exit %d", WEXITSTATUS(status));
+		if (WIFSIGNALED(status))
+			vsb_printf(sb, ", signal %d", WTERMSIG(status));
+		if (WCOREDUMP(status))
+			vsb_printf(sb, ", core dumped");
+		return (-1);
+	}
+	return (0);
+}
diff -Nru 2.0.3/varnish-cache/lib/libvarnish/.svn/dir-prop-base trunk/varnish-cache/lib/libvarnish/.svn/dir-prop-base
diff -Nru 2.0.3/varnish-cache/lib/libvarnish/.svn/entries trunk/varnish-cache/lib/libvarnish/.svn/entries
diff -Nru 2.0.3/varnish-cache/lib/libvarnish/.svn/text-base/argv.c.svn-base trunk/varnish-cache/lib/libvarnish/.svn/text-base/argv.c.svn-base
diff -Nru 2.0.3/varnish-cache/lib/libvarnish/.svn/text-base/assert.c.svn-base trunk/varnish-cache/lib/libvarnish/.svn/text-base/assert.c.svn-base
diff -Nru 2.0.3/varnish-cache/lib/libvarnish/.svn/text-base/binary_heap.c.svn-base trunk/varnish-cache/lib/libvarnish/.svn/text-base/binary_heap.c.svn-base
diff -Nru 2.0.3/varnish-cache/lib/libvarnish/.svn/text-base/cli_common.c.svn-base trunk/varnish-cache/lib/libvarnish/.svn/text-base/cli_common.c.svn-base
diff -Nru 2.0.3/varnish-cache/lib/libvarnish/.svn/text-base/crc32.c.svn-base trunk/varnish-cache/lib/libvarnish/.svn/text-base/crc32.c.svn-base
diff -Nru 2.0.3/varnish-cache/lib/libvarnish/.svn/text-base/flint.lnt.svn-base trunk/varnish-cache/lib/libvarnish/.svn/text-base/flint.lnt.svn-base
diff -Nru 2.0.3/varnish-cache/lib/libvarnish/.svn/text-base/flopen.c.svn-base trunk/varnish-cache/lib/libvarnish/.svn/text-base/flopen.c.svn-base
diff -Nru 2.0.3/varnish-cache/lib/libvarnish/.svn/text-base/Makefile.am.svn-base trunk/varnish-cache/lib/libvarnish/.svn/text-base/Makefile.am.svn-base
diff -Nru 2.0.3/varnish-cache/lib/libvarnish/.svn/text-base/num.c.svn-base trunk/varnish-cache/lib/libvarnish/.svn/text-base/num.c.svn-base
diff -Nru 2.0.3/varnish-cache/lib/libvarnish/.svn/text-base/subproc.c.svn-base trunk/varnish-cache/lib/libvarnish/.svn/text-base/subproc.c.svn-base
diff -Nru 2.0.3/varnish-cache/lib/libvarnish/.svn/text-base/tcp.c.svn-base trunk/varnish-cache/lib/libvarnish/.svn/text-base/tcp.c.svn-base
diff -Nru 2.0.3/varnish-cache/lib/libvarnish/.svn/text-base/time.c.svn-base trunk/varnish-cache/lib/libvarnish/.svn/text-base/time.c.svn-base
diff -Nru 2.0.3/varnish-cache/lib/libvarnish/.svn/text-base/vct.c.svn-base trunk/varnish-cache/lib/libvarnish/.svn/text-base/vct.c.svn-base
diff -Nru 2.0.3/varnish-cache/lib/libvarnish/.svn/text-base/version.c.svn-base trunk/varnish-cache/lib/libvarnish/.svn/text-base/version.c.svn-base
diff -Nru 2.0.3/varnish-cache/lib/libvarnish/.svn/text-base/vlu.c.svn-base trunk/varnish-cache/lib/libvarnish/.svn/text-base/vlu.c.svn-base
diff -Nru 2.0.3/varnish-cache/lib/libvarnish/.svn/text-base/vpf.c.svn-base trunk/varnish-cache/lib/libvarnish/.svn/text-base/vpf.c.svn-base
diff -Nru 2.0.3/varnish-cache/lib/libvarnish/.svn/text-base/vsb.c.svn-base trunk/varnish-cache/lib/libvarnish/.svn/text-base/vsb.c.svn-base
diff -Nru 2.0.3/varnish-cache/lib/libvarnish/.svn/text-base/vsha256.c.svn-base trunk/varnish-cache/lib/libvarnish/.svn/text-base/vsha256.c.svn-base
diff -Nru 2.0.3/varnish-cache/lib/libvarnish/.svn/text-base/vss.c.svn-base trunk/varnish-cache/lib/libvarnish/.svn/text-base/vss.c.svn-base
diff -Nru 2.0.3/varnish-cache/lib/libvarnish/.svn/text-base/vtmpfile.c.svn-base trunk/varnish-cache/lib/libvarnish/.svn/text-base/vtmpfile.c.svn-base
diff -Nru 2.0.3/varnish-cache/lib/libvarnish/.svn/tmp/tempfile.2.tmp trunk/varnish-cache/lib/libvarnish/.svn/tmp/tempfile.2.tmp
diff -Nru 2.0.3/varnish-cache/lib/libvarnish/.svn/tmp/tempfile.3.tmp trunk/varnish-cache/lib/libvarnish/.svn/tmp/tempfile.3.tmp
diff -Nru 2.0.3/varnish-cache/lib/libvarnish/tcp.c trunk/varnish-cache/lib/libvarnish/tcp.c
--- 2.0.3/varnish-cache/lib/libvarnish/tcp.c	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/lib/libvarnish/tcp.c	2009-01-05 14:45:26.000000000 +0100
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: tcp.c 3126 2008-08-26 07:47:23Z phk $
+ * $Id: tcp.c 3406 2008-11-19 14:13:57Z petter $
  */
 
 #include "config.h"
@@ -47,6 +47,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <math.h>
 
 #include "config.h"
 #ifndef HAVE_STRLCPY
@@ -58,7 +59,8 @@
 /*--------------------------------------------------------------------*/
 
 void
-TCP_name(const struct sockaddr *addr, unsigned l, char *abuf, unsigned alen, char *pbuf, unsigned plen)
+TCP_name(const struct sockaddr *addr, unsigned l, char *abuf, unsigned alen,
+    char *pbuf, unsigned plen)
 {
 	int i;
 
@@ -101,7 +103,7 @@
 	struct accept_filter_arg afa;
 	int i;
 
-	bzero(&afa, sizeof(afa));
+	memset(&afa, 0, sizeof(afa));
 	strcpy(afa.af_name, "httpready");
 	errno = 0;
 	i = setsockopt(sock, SOL_SOCKET, SO_ACCEPTFILTER,
@@ -119,7 +121,7 @@
 
 /*--------------------------------------------------------------------
  * Functions for controlling NONBLOCK mode.
- * 
+ *
  * We use FIONBIO because it is cheaper than fcntl(2), which requires
  * us to do two syscalls, one to get and one to set, the latter of
  * which mucks about a bit before it ends up calling ioctl(FIONBIO),
@@ -209,3 +211,14 @@
 	    errno == ENOTCONN);
 	*s = -1;
 }
+
+void
+TCP_set_read_timeout(int s, double seconds)
+{
+	struct timeval timeout;
+	timeout.tv_sec = floor(seconds);
+	timeout.tv_usec = 1e6 * (seconds - timeout.tv_sec);
+#ifdef SO_RCVTIMEO_WORKS
+	AZ(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof timeout));
+#endif
+}
diff -Nru 2.0.3/varnish-cache/lib/libvarnish/time.c trunk/varnish-cache/lib/libvarnish/time.c
--- 2.0.3/varnish-cache/lib/libvarnish/time.c	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/lib/libvarnish/time.c	2008-11-06 12:22:01.000000000 +0100
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: time.c 3260 2008-10-07 09:46:21Z tfheen $
+ * $Id: time.c 3336 2008-10-20 18:47:24Z des $
  *
  * Semi-trivial functions to handle HTTP header timestamps according to
  * RFC 2616 section 3.3.
@@ -56,7 +56,6 @@
 #include <unistd.h>
 #include <math.h>
 
-#include "config.h"
 #include "libvarnish.h"
 
 double
diff -Nru 2.0.3/varnish-cache/lib/libvarnish/vct.c trunk/varnish-cache/lib/libvarnish/vct.c
--- 2.0.3/varnish-cache/lib/libvarnish/vct.c	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/lib/libvarnish/vct.c	2008-11-06 12:22:01.000000000 +0100
@@ -25,11 +25,13 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: vct.c 2906 2008-07-08 10:29:07Z phk $
+ * $Id: vct.c 3336 2008-10-20 18:47:24Z des $
  *
  * ctype(3) like functions, according to RFC2616
  */
 
+#include "config.h"
+
 #include <vct.h>
 
 /* NB: VCT always operate in ASCII, don't replace 0x0d with \r etc. */
@@ -70,12 +72,12 @@
 	[0x1d]	=	VCT_CTL,
 	[0x1e]	=	VCT_CTL,
 	[0x1f]	=	VCT_CTL,
-        [0x20]  =	VCT_SP | VCT_SEPARATOR,
-        [0x22]  =	VCT_SEPARATOR,
-        [0x28]  =	VCT_SEPARATOR,
-        [0x29]  =	VCT_SEPARATOR,
-        [0x2c]  =	VCT_SEPARATOR,
-        [0x2f]  =	VCT_SEPARATOR,
+	[0x20]  =	VCT_SP | VCT_SEPARATOR,
+	[0x22]  =	VCT_SEPARATOR,
+	[0x28]  =	VCT_SEPARATOR,
+	[0x29]  =	VCT_SEPARATOR,
+	[0x2c]  =	VCT_SEPARATOR,
+	[0x2f]  =	VCT_SEPARATOR,
 	[0x30]	=	VCT_DIGIT | VCT_HEX,
 	[0x31]	=	VCT_DIGIT | VCT_HEX,
 	[0x32]	=	VCT_DIGIT | VCT_HEX,
@@ -86,13 +88,13 @@
 	[0x37]	=	VCT_DIGIT | VCT_HEX,
 	[0x38]	=	VCT_DIGIT | VCT_HEX,
 	[0x39]	=	VCT_DIGIT | VCT_HEX,
-        [0x3a]  =	VCT_SEPARATOR,
-        [0x3b]  =	VCT_SEPARATOR,
-        [0x3c]  =	VCT_SEPARATOR,
-        [0x3d]  =	VCT_SEPARATOR,
-        [0x3e]  =	VCT_SEPARATOR,
-        [0x3f]  =	VCT_SEPARATOR,
-        [0x40]  =	VCT_SEPARATOR,
+	[0x3a]  =	VCT_SEPARATOR,
+	[0x3b]  =	VCT_SEPARATOR,
+	[0x3c]  =	VCT_SEPARATOR,
+	[0x3d]  =	VCT_SEPARATOR,
+	[0x3e]  =	VCT_SEPARATOR,
+	[0x3f]  =	VCT_SEPARATOR,
+	[0x40]  =	VCT_SEPARATOR,
 	[0x41]	=	VCT_UPALPHA | VCT_HEX,
 	[0x42]	=	VCT_UPALPHA | VCT_HEX,
 	[0x43]	=	VCT_UPALPHA | VCT_HEX,
@@ -119,9 +121,9 @@
 	[0x58]	=	VCT_UPALPHA,
 	[0x59]	=	VCT_UPALPHA,
 	[0x5a]	=	VCT_UPALPHA,
-        [0x5b]  =	VCT_SEPARATOR,
-        [0x5c]  =	VCT_SEPARATOR,
-        [0x5d]  =	VCT_SEPARATOR,
+	[0x5b]  =	VCT_SEPARATOR,
+	[0x5c]  =	VCT_SEPARATOR,
+	[0x5d]  =	VCT_SEPARATOR,
 	[0x61]	=	VCT_LOALPHA | VCT_HEX,
 	[0x62]	=	VCT_LOALPHA | VCT_HEX,
 	[0x63]	=	VCT_LOALPHA | VCT_HEX,
@@ -148,7 +150,7 @@
 	[0x78]	=	VCT_LOALPHA,
 	[0x79]	=	VCT_LOALPHA,
 	[0x7a]	=	VCT_LOALPHA,
-        [0x7b]  =	VCT_SEPARATOR,
-        [0x7d]  =	VCT_SEPARATOR,
+	[0x7b]  =	VCT_SEPARATOR,
+	[0x7d]  =	VCT_SEPARATOR,
 	[0x7f]	=	VCT_CTL,
 };
diff -Nru 2.0.3/varnish-cache/lib/libvarnish/version.c trunk/varnish-cache/lib/libvarnish/version.c
--- 2.0.3/varnish-cache/lib/libvarnish/version.c	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/lib/libvarnish/version.c	2008-11-06 12:22:01.000000000 +0100
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: version.c 3072 2008-08-11 07:47:24Z phk $
+ * $Id: version.c 3336 2008-10-20 18:47:24Z des $
  *
  * Display a standardized version message.
  */
@@ -35,7 +35,6 @@
 
 #include <stdio.h>
 
-#include "config.h"
 #include "libvarnish.h"
 
 void
@@ -43,5 +42,6 @@
 {
 	fprintf(stderr, "%s (%s-%s)\n", progname,
 	    PACKAGE_TARNAME, PACKAGE_VERSION);
-	fprintf(stderr, "Copyright (c) 2006-2008 Linpro AS / Verdens Gang AS\n");
+	fprintf(stderr,
+	    "Copyright (c) 2006-2008 Linpro AS / Verdens Gang AS\n");
 }
diff -Nru 2.0.3/varnish-cache/lib/libvarnish/vlu.c trunk/varnish-cache/lib/libvarnish/vlu.c
--- 2.0.3/varnish-cache/lib/libvarnish/vlu.c	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/lib/libvarnish/vlu.c	2008-11-11 14:27:26.000000000 +0100
@@ -23,12 +23,14 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: vlu.c 2906 2008-07-08 10:29:07Z phk $
+ * $Id: vlu.c 3383 2008-11-11 13:15:01Z phk $
  *
  * Functions for assembling a bytestream into text-lines and calling
  * a function on each.
  */
 
+#include "config.h"
+
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
@@ -63,7 +65,7 @@
 		if (l->buf == NULL) {
 			FREE_OBJ(l);
 			l = NULL;
-		} 
+		}
 	}
 	return (l);
 }
@@ -85,8 +87,11 @@
 
 	l->buf[l->bufp] = '\0';
 	for (p = l->buf; *p != '\0'; p = q) {
-		q = strchr(p, '\n');
-		if (q == NULL)
+		/* Find first CR or NL */
+		for (q = p; *q != '\0'; q++)
+			if (*q == '\n' || *q == '\r')
+				break;
+		if (*q == '\0')
 			break;
 		*q++ = '\0';
 		i = l->func(l->priv, p);
diff -Nru 2.0.3/varnish-cache/lib/libvarnish/vpf.c trunk/varnish-cache/lib/libvarnish/vpf.c
--- 2.0.3/varnish-cache/lib/libvarnish/vpf.c	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/lib/libvarnish/vpf.c	2008-11-06 12:22:01.000000000 +0100
@@ -23,9 +23,9 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: vpf.c 3072 2008-08-11 07:47:24Z phk $
+ * $Id: vpf.c 3336 2008-10-20 18:47:24Z des $
  * Derived from:
- * $FreeBSD: src/lib/libutil/pidfile.c,v 1.5 2007/05/11 11:10:05 des Exp $
+ * $FreeBSD: head/lib/libutil/pidfile.c 184091 2008-10-20 17:41:08Z des $
  */
 
 #include "config.h"
@@ -41,7 +41,6 @@
 #include <string.h>
 #include <unistd.h>
 
-#include "config.h"
 #ifndef HAVE_STRLCPY
 #include "compat/strlcpy.h"
 #endif
@@ -230,14 +229,8 @@
 static int
 _vpf_remove(struct pidfh *pfh, int freeit)
 {
-	struct flock lock;
 	int error;
 
-	lock.l_type = F_UNLCK;
-	lock.l_start = 0;
-	lock.l_whence = SEEK_SET;
-	lock.l_len = 0;
-
 	error = vpf_verify(pfh);
 	if (error != 0) {
 		errno = error;
@@ -246,10 +239,6 @@
 
 	if (unlink(pfh->pf_path) == -1)
 		error = errno;
-	if (fcntl(pfh->pf_fd, F_SETLK, &lock) == -1) {
-		if (error == 0)
-			error = errno;
-	}
 	if (close(pfh->pf_fd) == -1) {
 		if (error == 0)
 			error = errno;
diff -Nru 2.0.3/varnish-cache/lib/libvarnish/vsb.c trunk/varnish-cache/lib/libvarnish/vsb.c
--- 2.0.3/varnish-cache/lib/libvarnish/vsb.c	2009-01-09 15:39:13.000000000 +0100
+++ trunk/varnish-cache/lib/libvarnish/vsb.c	2009-01-05 14:45:26.000000000 +0100
@@ -23,7 +23,7 @@
  * (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: vsb.c 3034 2008-07-31 09:22:46Z phk $
+ * $Id: vsb.c 3496 2008-12-21 18:41:43Z phk $
  * $FreeBSD: src/sys/kern/subr_sbuf.c,v 1.30 2005/12/23 11:49:53 phk Exp $
  */
 
@@ -34,7 +34,6 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <strings.h>
 
 #include "libvarnish.h"
 #include "vsb.h"
@@ -135,7 +134,7 @@
 	newbuf = (char *)SBMALLOC(newsize);
 	if (newbuf == NULL)
 		return (-1);
-	bcopy(s->s_buf, newbuf, s->s_size);
+	memcpy(newbuf, s->s_buf, s->s_size);
 	if (VSB_ISDYNAMIC(s))
 		SBFREE(s->s_buf);
 	else
@@ -163,15 +162,17 @@
 		s = (struct vsb *)SBMALLOC(sizeof *s);
 		if (s == NULL)
 			return (NULL);
-		bzero(s, sizeof *s);
-		s->s_flags = flags;
-		s->s_magic = VSB_MAGIC;
+		if (vsb_new(s, buf, length, flags) == NULL) {
+			free(s);
+			return (NULL);
+		}
 		VSB_SETFLAG(s, VSB_DYNSTRUCT);
-	} else {
-		bzero(s, sizeof *s);
-		s->s_flags = flags;
-		s->s_magic = VSB_MAGIC;
+		return (s);
 	}
+
+	memset(s, 0, sizeof *s);
+	s->s_flags = flags;
+	s->s_magic = VSB_MAGIC;
 	s->s_size = length;
 	if (buf) {
 		s->s_buf = buf;
@@ -180,11 +181,8 @@
 	if (flags & VSB_AUTOEXTEND)
 		s->s_size = vsb_extendsize(s->s_size);
 	s->s_buf = (char *)SBMALLOC(s->s_size);
-	if (s->s_buf == NULL) {
-		if (VSB_ISDYNSTRUCT(s))
-			SBFREE(s);
+	if (s->s_buf == NULL)
 		return (NULL);
-	}
 	VSB_SETFLAG(s, VSB_DYNAMIC);
 	return (s);
 }
@@ -464,7 +462,7 @@
 	if (VSB_ISDYNAMIC(s))
 		SBFREE(s->s_buf);
 	isdyn = VSB_ISDYNSTRUCT(s);
-	bzero(s, sizeof *s);
+	memset(s, 0, sizeof *s);
 	if (isdyn)
 		SBFREE(s);
 }
diff -Nru 2.0.3/varnish-cache/lib/libvarnish/vsha256.c trunk/varnish-cache/lib/libvarnish/vsha256.c
--- 2.0.3/varnish-cache/lib/libvarnish/vsha256.c	1970-01-01 01:00:00.000000000 +0100
+++ trunk/varnish-cache/lib/libvarnish/vsha256.c	2009-01-05 14:45:26.000000000 +0100
@@ -0,0 +1,360 @@
+/*-
+ * Copyright 2005 Colin Percival
+ * All rights reserved.
+ *
+ * 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 THE 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.
+ *
+ * From: $FreeBSD: head/lib/libmd/sha256c.c 154479 2006-01-17 15:35:57Z phk $
+ */
+
+#include "config.h"
+
+#include <stdint.h>
+#include <string.h>
+
+#ifdef HAVE_ENDIAN_H
+#include <endian.h>
+#define VBYTE_ORDER	__BYTE_ORDER
+#define VBIG_ENDIAN	__BIG_ENDIAN
+#endif
+#ifdef HAVE_SYS_ENDIAN_H
+#include <sys/endian.h>
+#define VBYTE_ORDER	_BYTE_ORDER
+#define VBIG_ENDIAN	_BIG_ENDIAN
+#endif
+
+#include "libvarnish.h"
+#include "vsha256.h"
+
+#if defined(VBYTE_ORDER) && VBYTE_ORDER == VBIG_ENDIAN
+
+/* Copy a vector of big-endian uint32_t into a vector of bytes */
+#define be32enc_vect(dst, src, len)	\
+	memcpy((void *)dst, (const void *)src, (size_t)len)
+
+/* Copy a vector of bytes into a vector of big-endian uint32_t */
+#define be32dec_vect(dst, src, len)	\
+	memcpy((void *)dst, (const void *)src, (size_t)len)
+
+#else /* BYTE_ORDER != BIG_ENDIAN or in doubt... */
+
+static __inline uint32_t
+mybe32dec(const void *pp)
+{
+        unsigned char const *p = (unsigned char const *)pp;
+
+        return (((unsigned)p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
+}
+
+static __inline void
+mybe32enc(void *pp, uint32_t u)
+{
+        unsigned char *p = (unsigned char *)pp;
+
+        p[0] = (u >> 24) & 0xff;
+        p[1] = (u >> 16) & 0xff;
+        p[2] = (u >> 8) & 0xff;
+        p[3] = u & 0xff;
+}
+
+static __inline void
+mybe64enc(void *pp, uint64_t u)
+{
+	unsigned char *p = (unsigned char *)pp;
+
+	mybe32enc(p, u >> 32);
+	mybe32enc(p + 4, u & 0xffffffff);
+}
+
+/*
+ * Encode a length len/4 vector of (uint32_t) into a length len vector of
+ * (unsigned char) in big-endian form.  Assumes len is a multiple of 4.
+ */
+static void
+be32enc_vect(unsigned char *dst, const uint32_t *src, size_t len)
+{
+	size_t i;
+
+	for (i = 0; i < len / 4; i++)
+		mybe32enc(dst + i * 4, src[i]);
+}
+
+/*
+ * Decode a big-endian length len vector of (unsigned char) into a length
+ * len/4 vector of (uint32_t).  Assumes len is a multiple of 4.
+ */
+static void
+be32dec_vect(uint32_t *dst, const unsigned char *src, size_t len)
+{
+	size_t i;
+
+	for (i = 0; i < len / 4; i++)
+		dst[i] = mybe32dec(src + i * 4);
+}
+
+#endif 
+
+/* Elementary functions used by SHA256 */
+#define Ch(x, y, z)	((x & (y ^ z)) ^ z)
+#define Maj(x, y, z)	((x & (y | z)) | (y & z))
+#define SHR(x, n)	(x >> n)
+#define ROTR(x, n)	((x >> n) | (x << (32 - n)))
+#define S0(x)		(ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22))
+#define S1(x)		(ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25))
+#define s0(x)		(ROTR(x, 7) ^ ROTR(x, 18) ^ SHR(x, 3))
+#define s1(x)		(ROTR(x, 17) ^ ROTR(x, 19) ^ SHR(x, 10))
+
+/* SHA256 round function */
+#define RND(a, b, c, d, e, f, g, h, k)			\
+	t0 = h + S1(e) + Ch(e, f, g) + k;		\
+	t1 = S0(a) + Maj(a, b, c);			\
+	d += t0;					\
+	h  = t0 + t1;
+
+/* Adjusted round function for rotating state */
+#define RNDr(S, W, i, k)			\
+	RND(S[(64 - i) % 8], S[(65 - i) % 8],	\
+	    S[(66 - i) % 8], S[(67 - i) % 8],	\
+	    S[(68 - i) % 8], S[(69 - i) % 8],	\
+	    S[(70 - i) % 8], S[(71 - i) % 8],	\
+	    (W[i] + k))
+
+/*
+ * SHA256 block compression function.  The 256-bit state is transformed via
+ * the 512-bit input block to produce a new state.
+ */
+static void
+SHA256_Transform(uint32_t * state, const unsigned char block[64])
+{
+	uint32_t W[64];
+	uint32_t S[8];
+	uint32_t t0, t1;
+	int i;
+
+	/* 1. Prepare message schedule W. */
+	be32dec_vect(W, block, 64);
+	for (i = 16; i < 64; i++)
+		W[i] = s1(W[i - 2]) + W[i - 7] + s0(W[i - 15]) + W[i - 16];
+
+	/* 2. Initialize working variables. */
+	memcpy(S, state, 32);
+
+	/* 3. Mix. */
+	RNDr(S, W, 0, 0x428a2f98);
+	RNDr(S, W, 1, 0x71374491);
+	RNDr(S, W, 2, 0xb5c0fbcf);
+	RNDr(S, W, 3, 0xe9b5dba5);
+	RNDr(S, W, 4, 0x3956c25b);
+	RNDr(S, W, 5, 0x59f111f1);
+	RNDr(S, W, 6, 0x923f82a4);
+	RNDr(S, W, 7, 0xab1c5ed5);
+	RNDr(S, W, 8, 0xd807aa98);
+	RNDr(S, W, 9, 0x12835b01);
+	RNDr(S, W, 10, 0x243185be);
+	RNDr(S, W, 11, 0x550c7dc3);
+	RNDr(S, W, 12, 0x72be5d74);
+	RNDr(S, W, 13, 0x80deb1fe);
+	RNDr(S, W, 14, 0x9bdc06a7);
+	RNDr(S, W, 15, 0xc19bf174);
+	RNDr(S, W, 16, 0xe49b69c1);
+	RNDr(S, W, 17, 0xefbe4786);
+	RNDr(S, W, 18, 0x0fc19dc6);
+	RNDr(S, W, 19, 0x240ca1cc);
+	RNDr(S, W, 20, 0x2de92c6f);
+	RNDr(S, W, 21, 0x4a7484aa);
+	RNDr(S, W, 22, 0x5cb0a9dc);
+	RNDr(S, W, 23, 0x76f988da);
+	RNDr(S, W, 24, 0x983e5152);
+	RNDr(S, W, 25, 0xa831c66d);
+	RNDr(S, W, 26, 0xb00327c8);
+	RNDr(S, W, 27, 0xbf597fc7);
+	RNDr(S, W, 28, 0xc6e00bf3);
+	RNDr(S, W, 29, 0xd5a79147);
+	RNDr(S, W, 30, 0x06ca6351);
+	RNDr(S, W, 31, 0x14292967);
+	RNDr(S, W, 32, 0x27b70a85);
+	RNDr(S, W, 33, 0x2e1b2138);
+	RNDr(S, W, 34, 0x4d2c6dfc);
+	RNDr(S, W, 35, 0x53380d13);
+	RNDr(S, W, 36, 0x650a7354);
+	RNDr(S, W, 37, 0x766a0abb);
+	RNDr(S, W, 38, 0x81c2c92e);
+	RNDr(S, W, 39, 0x92722c85);
+	RNDr(S, W, 40, 0xa2bfe8a1);
+	RNDr(S, W, 41, 0xa81a664b);
+	RNDr(S, W, 42, 0xc24b8b70);
+	RNDr(S, W, 43, 0xc76c51a3);
+	RNDr(S, W, 44, 0xd192e819);
+	RNDr(S, W, 45, 0xd6990624);
+	RNDr(S, W, 46, 0xf40e3585);
+	RNDr(S, W, 47, 0x106aa070);
+	RNDr(S, W, 48, 0x19a4c116);
+	RNDr(S, W, 49, 0x1e376c08);
+	RNDr(S, W, 50, 0x2748774c);
+	RNDr(S, W, 51, 0x34b0bcb5);
+	RNDr(S, W, 52, 0x391c0cb3);
+	RNDr(S, W, 53, 0x4ed8aa4a);
+	RNDr(S, W, 54, 0x5b9cca4f);
+	RNDr(S, W, 55, 0x682e6ff3);
+	RNDr(S, W, 56, 0x748f82ee);
+	RNDr(S, W, 57, 0x78a5636f);
+	RNDr(S, W, 58, 0x84c87814);
+	RNDr(S, W, 59, 0x8cc70208);
+	RNDr(S, W, 60, 0x90befffa);
+	RNDr(S, W, 61, 0xa4506ceb);
+	RNDr(S, W, 62, 0xbef9a3f7);
+	RNDr(S, W, 63, 0xc67178f2);
+
+	/* 4. Mix local working variables into global state */
+	for (i = 0; i < 8; i++)
+		state[i] += S[i];
+}
+
+static const unsigned char PAD[64] = {
+	0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* Add padding and terminating bit-count. */
+static void
+SHA256_Pad(SHA256_CTX * ctx)
+{
+	unsigned char len[8];
+	uint32_t r, plen;
+
+	/*
+	 * Convert length to bits and encode as a vector of bytes
+	 * -- we do this now rather than later because the length
+	 * will change after we pad.
+	 */
+	mybe64enc(len, ctx->count << 3);
+
+	/* Add 1--64 bytes so that the resulting length is 56 mod 64 */
+	r = ctx->count & 0x3f;
+	plen = (r < 56) ? (56 - r) : (120 - r);
+	SHA256_Update(ctx, PAD, (size_t)plen);
+
+	/* Add the terminating bit-count */
+	SHA256_Update(ctx, len, 8);
+}
+
+/* SHA-256 initialization.  Begins a SHA-256 operation. */
+void
+SHA256_Init(SHA256_CTX * ctx)
+{
+
+	/* Zero bits processed so far */
+	ctx->count = 0;
+
+	/* Magic initialization constants */
+	ctx->state[0] = 0x6A09E667;
+	ctx->state[1] = 0xBB67AE85;
+	ctx->state[2] = 0x3C6EF372;
+	ctx->state[3] = 0xA54FF53A;
+	ctx->state[4] = 0x510E527F;
+	ctx->state[5] = 0x9B05688C;
+	ctx->state[6] = 0x1F83D9AB;
+	ctx->state[7] = 0x5BE0CD19;
+}
+
+/* Add bytes into the hash */
+void
+SHA256_Update(SHA256_CTX * ctx, const void *in, size_t len)
+{
+	uint32_t r, l;
+	const unsigned char *src = in;
+
+	/* Number of bytes left in the buffer from previous updates */
+	r = ctx->count & 0x3f;
+	while (len > 0) {
+		l = 64 - r;
+		if (l > len)
+			l = len;
+		memcpy(&ctx->buf[r], src, l);
+		len -= l;
+		src += l;
+		ctx->count += l;
+		r = ctx->count & 0x3f;
+		if (r == 0)
+			SHA256_Transform(ctx->state, ctx->buf);
+	}
+}
+
+/*
+ * SHA-256 finalization.  Pads the input data, exports the hash value,
+ * and clears the context state.
+ */
+void
+SHA256_Final(unsigned char digest[32], SHA256_CTX * ctx)
+{
+
+	/* Add padding */
+	SHA256_Pad(ctx);
+
+	/* Write the hash */
+	be32enc_vect(digest, ctx->state, 32);
+
+	/* Clear the context state */
+	memset((void *)ctx, 0, sizeof(*ctx));
+}
+
+/*
+ * A few test-vectors, just in case
+ */
+
+static const struct sha256test {
+	const char              *input;
+	const unsigned char     output[32];
+} sha256test[] = {
+    { "",
+	{0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4,
+	 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b,
+	 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55} },
+    { "message digest",
+	{0xf7, 0x84, 0x6f, 0x55, 0xcf, 0x23, 0xe1, 0x4e, 0xeb, 0xea, 0xb5,
+	 0xb4, 0xe1, 0x55, 0x0c, 0xad, 0x5b, 0x50, 0x9e, 0x33, 0x48, 0xfb,
+	 0xc4, 0xef, 0xa3, 0xa1, 0x41, 0x3d, 0x39, 0x3c, 0xb6, 0x50} },
+    { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+	{0xdb, 0x4b, 0xfc, 0xbd, 0x4d, 0xa0, 0xcd, 0x85, 0xa6, 0x0c, 0x3c,
+	 0x37, 0xd3, 0xfb, 0xd8, 0x80, 0x5c, 0x77, 0xf1, 0x5f, 0xc6, 0xb1,
+	 0xfd, 0xfe, 0x61, 0x4e, 0xe0, 0xa7, 0xc8, 0xfd, 0xb4, 0xc0} },
+    { NULL }
+};
+
+
+void
+SHA256_Test(void)
+{
+	struct SHA256Context c;
+	const struct sha256test *p;
+	unsigned char o[32];
+
+	for (p = sha256test; p->input != NULL; p++) {
+		SHA256_Init(&c);
+		SHA256_Update(&c, p->input, strlen(p->input));
+		SHA256_Final(o, &c);
+		assert(!memcmp(o, p->output, 32));
+	}
+}
+
diff -Nru 2.0.3/varnish-cache/lib/libvarnish/vss.c trunk/varnish-cache/lib/libvarnish/vss.c
--- 2.0.3/varnish-cache/lib/libvarnish/vss.c	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/lib/libvarnish/vss.c	2009-01-05 14:45:26.000000000 +0100
@@ -27,7 +27,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: vss.c 3072 2008-08-11 07:47:24Z phk $
+ * $Id: vss.c 3410 2008-11-20 10:19:56Z phk $
  */
 
 #include "config.h"
@@ -44,7 +44,6 @@
 #include <string.h>
 #include <unistd.h>
 
-#include "config.h"
 #ifndef HAVE_STRLCPY
 #include "compat/strlcpy.h"
 #endif
@@ -156,7 +155,7 @@
 	XXXAN(va);
 	*vap = va;
 	for (res = res0, i = 0; res != NULL; res = res->ai_next, ++i) {
-		va[i] = calloc(1, sizeof *va[i]);
+		va[i] = calloc(1, sizeof(*va[i]));
 		XXXAN(va[i]);
 		va[i]->va_family = res->ai_family;
 		va[i]->va_socktype = res->ai_socktype;
@@ -283,7 +282,7 @@
 		if (retval >= 0)
 			break;
 	}
-	for (n = 0; n < nvaddr; n++) 
+	for (n = 0; n < nvaddr; n++)
 		free(vaddr[n]);
 	free(vaddr);
 	free(addr);
diff -Nru 2.0.3/varnish-cache/lib/libvarnish/vtmpfile.c trunk/varnish-cache/lib/libvarnish/vtmpfile.c
--- 2.0.3/varnish-cache/lib/libvarnish/vtmpfile.c	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/lib/libvarnish/vtmpfile.c	2009-01-05 14:45:26.000000000 +0100
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: vtmpfile.c 3072 2008-08-11 07:47:24Z phk $
+ * $Id: vtmpfile.c 3415 2008-11-21 12:09:46Z phk $
  */
 
 #include "config.h"
@@ -35,8 +35,10 @@
 #include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <unistd.h>
+
+#include <sys/stat.h>
 
-#include "config.h"
 #include "libvarnish.h"
 
 int
@@ -75,3 +77,37 @@
 	}
 	/* not reached */
 }
+
+static char *
+vreadfd(int fd)
+{
+	struct stat st;
+	char *f;
+	int i;
+
+	assert(0 == fstat(fd, &st));
+	if (!S_ISREG(st.st_mode))
+		return (NULL);
+	f = malloc(st.st_size + 1);
+	assert(f != NULL);
+	i = read(fd, f, st.st_size);
+	assert(i == st.st_size);
+	f[i] = '\0';
+	return (f);
+}
+
+char *
+vreadfile(const char *fn)
+{
+	int fd, err;
+	char *r;
+
+	fd = open(fn, O_RDONLY);
+	if (fd < 0)
+		return (NULL);
+	r = vreadfd(fd);
+	err = errno;
+	AZ(close(fd));
+	errno = err;
+	return (r);
+}
diff -Nru 2.0.3/varnish-cache/lib/libvarnishapi/base64.c trunk/varnish-cache/lib/libvarnishapi/base64.c
--- 2.0.3/varnish-cache/lib/libvarnishapi/base64.c	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/lib/libvarnishapi/base64.c	2008-11-06 12:22:01.000000000 +0100
@@ -3,14 +3,13 @@
  *
  * This file is in the public domain.
  *
- * $Id: base64.c 3072 2008-08-11 07:47:24Z phk $
+ * $Id: base64.c 3336 2008-10-20 18:47:24Z des $
  */
 
 #include "config.h"
 
 #include <sys/types.h>
 #include <stdint.h>
-#include "config.h"
 #include "varnishapi.h"
 
 static const char *b64 =
diff -Nru 2.0.3/varnish-cache/lib/libvarnishapi/instance.c trunk/varnish-cache/lib/libvarnishapi/instance.c
--- 2.0.3/varnish-cache/lib/libvarnishapi/instance.c	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/lib/libvarnishapi/instance.c	2008-11-06 12:22:01.000000000 +0100
@@ -25,7 +25,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: instance.c 3072 2008-08-11 07:47:24Z phk $
+ * $Id: instance.c 3336 2008-10-20 18:47:24Z des $
  */
 
 #include "config.h"
@@ -34,13 +34,11 @@
 #include <stdio.h>
 #include <unistd.h>
 
-#include "config.h"
 #include "varnishapi.h"
 
 int
 varnish_instance(const char *n_arg,
-    char *name, size_t namelen,
-    char *dir, size_t dirlen)
+    char *name, size_t namelen, char *dir, size_t dirlen)
 {
 	size_t len;
 
diff -Nru 2.0.3/varnish-cache/lib/libvarnishapi/Makefile.in trunk/varnish-cache/lib/libvarnishapi/Makefile.in
diff -Nru 2.0.3/varnish-cache/lib/libvarnishapi/shmlog.c trunk/varnish-cache/lib/libvarnishapi/shmlog.c
--- 2.0.3/varnish-cache/lib/libvarnishapi/shmlog.c	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/lib/libvarnishapi/shmlog.c	2008-11-06 12:22:01.000000000 +0100
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: shmlog.c 3072 2008-08-11 07:47:24Z phk $
+ * $Id: shmlog.c 3336 2008-10-20 18:47:24Z des $
  */
 
 #include "config.h"
@@ -45,7 +45,6 @@
 #include <string.h>
 #include <unistd.h>
 
-#include "config.h"
 #include "shmlog.h"
 #include "miniobj.h"
 #include "varnishapi.h"
@@ -362,7 +361,8 @@
 /*--------------------------------------------------------------------*/
 
 int
-VSL_H_Print(void *priv, enum shmlogtag tag, unsigned fd, unsigned len, unsigned spec, const char *ptr)
+VSL_H_Print(void *priv, enum shmlogtag tag, unsigned fd, unsigned len,
+    unsigned spec, const char *ptr)
 {
 	FILE *fo = priv;
 	int type;
diff -Nru 2.0.3/varnish-cache/lib/libvarnishapi/.svn/entries trunk/varnish-cache/lib/libvarnishapi/.svn/entries
diff -Nru 2.0.3/varnish-cache/lib/libvarnishapi/.svn/text-base/base64.c.svn-base trunk/varnish-cache/lib/libvarnishapi/.svn/text-base/base64.c.svn-base
diff -Nru 2.0.3/varnish-cache/lib/libvarnishapi/.svn/text-base/instance.c.svn-base trunk/varnish-cache/lib/libvarnishapi/.svn/text-base/instance.c.svn-base
diff -Nru 2.0.3/varnish-cache/lib/libvarnishapi/.svn/text-base/shmlog.c.svn-base trunk/varnish-cache/lib/libvarnishapi/.svn/text-base/shmlog.c.svn-base
diff -Nru 2.0.3/varnish-cache/lib/libvarnishcompat/Makefile.am trunk/varnish-cache/lib/libvarnishcompat/Makefile.am
--- 2.0.3/varnish-cache/lib/libvarnishcompat/Makefile.am	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/lib/libvarnishcompat/Makefile.am	2009-01-05 14:45:26.000000000 +0100
@@ -1,4 +1,4 @@
-# $Id: Makefile.am 3140 2008-08-29 09:37:19Z tfheen $
+# $Id: Makefile.am 3421 2008-11-24 10:17:24Z phk $
 
 INCLUDES = -I$(top_srcdir)/include
 
@@ -14,5 +14,4 @@
 	srandomdev.c \
 	strlcat.c \
 	strlcpy.c \
-	strndup.c \
-	vis.c
+	strndup.c
diff -Nru 2.0.3/varnish-cache/lib/libvarnishcompat/Makefile.in trunk/varnish-cache/lib/libvarnishcompat/Makefile.in
diff -Nru 2.0.3/varnish-cache/lib/libvarnishcompat/strndup.c trunk/varnish-cache/lib/libvarnishcompat/strndup.c
--- 2.0.3/varnish-cache/lib/libvarnishcompat/strndup.c	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/lib/libvarnishcompat/strndup.c	2008-11-06 12:22:01.000000000 +0100
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: strndup.c 2861 2008-06-30 01:40:12Z des $
+ * $Id: strndup.c 3345 2008-10-22 11:33:58Z des $
  *
  */
 
@@ -36,7 +36,6 @@
 
 #include <stdlib.h>
 #include <string.h>
-#include <strings.h>
 
 #ifndef HAVE_STRLCPY
 #include "compat/strlcpy.h"
diff -Nru 2.0.3/varnish-cache/lib/libvarnishcompat/.svn/entries trunk/varnish-cache/lib/libvarnishcompat/.svn/entries
diff -Nru 2.0.3/varnish-cache/lib/libvarnishcompat/.svn/prop-base/vis.c.svn-base trunk/varnish-cache/lib/libvarnishcompat/.svn/prop-base/vis.c.svn-base
diff -Nru 2.0.3/varnish-cache/lib/libvarnishcompat/.svn/text-base/Makefile.am.svn-base trunk/varnish-cache/lib/libvarnishcompat/.svn/text-base/Makefile.am.svn-base
diff -Nru 2.0.3/varnish-cache/lib/libvarnishcompat/.svn/text-base/strndup.c.svn-base trunk/varnish-cache/lib/libvarnishcompat/.svn/text-base/strndup.c.svn-base
diff -Nru 2.0.3/varnish-cache/lib/libvarnishcompat/.svn/text-base/vis.c.svn-base trunk/varnish-cache/lib/libvarnishcompat/.svn/text-base/vis.c.svn-base
diff -Nru 2.0.3/varnish-cache/lib/libvarnishcompat/vis.c trunk/varnish-cache/lib/libvarnishcompat/vis.c
--- 2.0.3/varnish-cache/lib/libvarnishcompat/vis.c	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/lib/libvarnishcompat/vis.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,212 +0,0 @@
-/*-
- * Copyright (c) 1989, 1993
- *	The Regents of the University of California.  All rights reserved.
- *
- * 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.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 THE REGENTS 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.
- *
- * @(#)vis.c	8.1 (Berkeley) 7/19/93
- * $FreeBSD: src/lib/libc/gen/vis.c,v 1.13 2003/10/30 12:41:50 phk Exp $
- * $Id: vis.c 2455 2008-02-13 13:55:39Z des $
- */
-
-#include "config.h"
-
-#if !defined(HAVE_VIS) || !defined(HAVE_STRVIS) || !defined(HAVE_STRVISX)
-
-#include <sys/types.h>
-#include <limits.h>
-#include <ctype.h>
-#include <stdio.h>
-
-#include "compat/vis.h"
-
-#define	isoctal(c)	(((u_char)(c)) >= '0' && ((u_char)(c)) <= '7')
-
-/*
- * vis - visually encode characters
- */
-#ifndef HAVE_VIS
-char *
-vis(dst, c, flag, nextc)
-	char *dst;
-	int c, nextc;
-	int flag;
-{
-	c = (unsigned char)c;
-
-	if (flag & VIS_HTTPSTYLE) {
-		/* Described in RFC 1808 */
-		if (!(isalnum(c) /* alpha-numeric */
-		    /* safe */
-		    || c == '$' || c == '-' || c == '_' || c == '.' || c == '+'
-		    /* extra */
-		    || c == '!' || c == '*' || c == '\'' || c == '('
-		    || c == ')' || c == ',')) {
-			*dst++ = '%';
-			snprintf(dst, 4, (c < 16 ? "0%X" : "%X"), c);
-			dst += 2;
-			goto done;
-		}
-	}
-
-	if ((flag & VIS_GLOB) &&
-	    (c == '*' || c == '?' || c == '[' || c == '#'))
-		;
-	else if (isgraph(c) ||
-	   ((flag & VIS_SP) == 0 && c == ' ') ||
-	   ((flag & VIS_TAB) == 0 && c == '\t') ||
-	   ((flag & VIS_NL) == 0 && c == '\n') ||
-	   ((flag & VIS_SAFE) && (c == '\b' || c == '\007' || c == '\r'))) {
-		*dst++ = c;
-		if (c == '\\' && (flag & VIS_NOSLASH) == 0)
-			*dst++ = '\\';
-		*dst = '\0';
-		return (dst);
-	}
-
-	if (flag & VIS_CSTYLE) {
-		switch(c) {
-		case '\n':
-			*dst++ = '\\';
-			*dst++ = 'n';
-			goto done;
-		case '\r':
-			*dst++ = '\\';
-			*dst++ = 'r';
-			goto done;
-		case '\b':
-			*dst++ = '\\';
-			*dst++ = 'b';
-			goto done;
-		case '\a':
-			*dst++ = '\\';
-			*dst++ = 'a';
-			goto done;
-		case '\v':
-			*dst++ = '\\';
-			*dst++ = 'v';
-			goto done;
-		case '\t':
-			*dst++ = '\\';
-			*dst++ = 't';
-			goto done;
-		case '\f':
-			*dst++ = '\\';
-			*dst++ = 'f';
-			goto done;
-		case ' ':
-			*dst++ = '\\';
-			*dst++ = 's';
-			goto done;
-		case '\0':
-			*dst++ = '\\';
-			*dst++ = '0';
-			if (isoctal(nextc)) {
-				*dst++ = '0';
-				*dst++ = '0';
-			}
-			goto done;
-		}
-	}
-	if (((c & 0177) == ' ') || isgraph(c) || (flag & VIS_OCTAL)) {
-		*dst++ = '\\';
-		*dst++ = ((u_char)c >> 6 & 07) + '0';
-		*dst++ = ((u_char)c >> 3 & 07) + '0';
-		*dst++ = ((u_char)c & 07) + '0';
-		goto done;
-	}
-	if ((flag & VIS_NOSLASH) == 0)
-		*dst++ = '\\';
-	if (c & 0200) {
-		c &= 0177;
-		*dst++ = 'M';
-	}
-	if (iscntrl(c)) {
-		*dst++ = '^';
-		if (c == 0177)
-			*dst++ = '?';
-		else
-			*dst++ = c + '@';
-	} else {
-		*dst++ = '-';
-		*dst++ = c;
-	}
-done:
-	*dst = '\0';
-	return (dst);
-}
-#endif
-
-/*
- * strvis, strvisx - visually encode characters from src into dst
- *
- *	Dst must be 4 times the size of src to account for possible
- *	expansion.  The length of dst, not including the trailing NUL,
- *	is returned.
- *
- *	Strvisx encodes exactly len bytes from src into dst.
- *	This is useful for encoding a block of data.
- */
-#ifndef HAVE_STRVIS
-int
-strvis(dst, src, flag)
-	char *dst;
-	const char *src;
-	int flag;
-{
-	char c;
-	char *start;
-
-	for (start = dst; (c = *src); )
-		dst = vis(dst, c, flag, *++src);
-	*dst = '\0';
-	return (dst - start);
-}
-#endif
-
-#ifndef HAVE_STRVISX
-int
-strvisx(dst, src, len, flag)
-	char *dst;
-	const char *src;
-	size_t len;
-	int flag;
-{
-	int c;
-	char *start;
-
-	for (start = dst; len > 1; len--) {
-		c = *src;
-		dst = vis(dst, c, flag, *++src);
-	}
-	if (len)
-		dst = vis(dst, *src, flag, '\0');
-	*dst = '\0';
-
-	return (dst - start);
-}
-#endif
-
-#endif
diff -Nru 2.0.3/varnish-cache/lib/libvcl/Makefile.am trunk/varnish-cache/lib/libvcl/Makefile.am
--- 2.0.3/varnish-cache/lib/libvcl/Makefile.am	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/lib/libvcl/Makefile.am	2008-11-10 09:23:00.000000000 +0100
@@ -1,4 +1,4 @@
-# $Id: Makefile.am 3202 2008-09-19 12:17:28Z tfheen $
+# $Id: Makefile.am 3360 2008-11-06 11:45:45Z tfheen $
 
 INCLUDES = -I$(top_srcdir)/include
 
@@ -29,10 +29,10 @@
 	vcc_gen_fixed_token.tcl
 
 $(srcdir)/vcc_obj.c: $(srcdir)/vcc_gen_obj.tcl
-	cd $(srcdir) && @TCLSH@ vcc_gen_obj.tcl
+	cd $(srcdir) && @TCLSH@ vcc_gen_obj.tcl || true
 
 $(srcdir)/vcc_fixed_token.c: $(srcdir)/vcc_gen_fixed_token.tcl $(top_srcdir)/include/vcl.h $(top_srcdir)/include/vrt.h $(top_srcdir)/include/vrt_obj.h
-	cd $(srcdir) && @TCLSH@ vcc_gen_fixed_token.tcl
+	cd $(srcdir) && @TCLSH@ vcc_gen_fixed_token.tcl || true
 
 $(srcdir)/vcc_token_defs.h: $(srcdir)/vcc_gen_fixed_token.tcl $(top_srcdir)/include/vcl.h $(top_srcdir)/include/vrt.h $(top_srcdir)/include/vrt_obj.h
-	cd $(srcdir) && @TCLSH@ vcc_gen_fixed_token.tcl
+	cd $(srcdir) && @TCLSH@ vcc_gen_fixed_token.tcl || true
diff -Nru 2.0.3/varnish-cache/lib/libvcl/Makefile.in trunk/varnish-cache/lib/libvcl/Makefile.in
diff -Nru 2.0.3/varnish-cache/lib/libvcl/.svn/entries trunk/varnish-cache/lib/libvcl/.svn/entries
diff -Nru 2.0.3/varnish-cache/lib/libvcl/.svn/text-base/Makefile.am.svn-base trunk/varnish-cache/lib/libvcl/.svn/text-base/Makefile.am.svn-base
diff -Nru 2.0.3/varnish-cache/lib/libvcl/.svn/text-base/vcc_acl.c.svn-base trunk/varnish-cache/lib/libvcl/.svn/text-base/vcc_acl.c.svn-base
diff -Nru 2.0.3/varnish-cache/lib/libvcl/.svn/text-base/vcc_action.c.svn-base trunk/varnish-cache/lib/libvcl/.svn/text-base/vcc_action.c.svn-base
diff -Nru 2.0.3/varnish-cache/lib/libvcl/.svn/text-base/vcc_backend.c.svn-base trunk/varnish-cache/lib/libvcl/.svn/text-base/vcc_backend.c.svn-base
diff -Nru 2.0.3/varnish-cache/lib/libvcl/.svn/text-base/vcc_compile.c.svn-base trunk/varnish-cache/lib/libvcl/.svn/text-base/vcc_compile.c.svn-base
diff -Nru 2.0.3/varnish-cache/lib/libvcl/.svn/text-base/vcc_compile.h.svn-base trunk/varnish-cache/lib/libvcl/.svn/text-base/vcc_compile.h.svn-base
diff -Nru 2.0.3/varnish-cache/lib/libvcl/.svn/text-base/vcc_dir_random.c.svn-base trunk/varnish-cache/lib/libvcl/.svn/text-base/vcc_dir_random.c.svn-base
diff -Nru 2.0.3/varnish-cache/lib/libvcl/.svn/text-base/vcc_dir_round_robin.c.svn-base trunk/varnish-cache/lib/libvcl/.svn/text-base/vcc_dir_round_robin.c.svn-base
diff -Nru 2.0.3/varnish-cache/lib/libvcl/.svn/text-base/vcc_fixed_token.c.svn-base trunk/varnish-cache/lib/libvcl/.svn/text-base/vcc_fixed_token.c.svn-base
diff -Nru 2.0.3/varnish-cache/lib/libvcl/.svn/text-base/vcc_gen_fixed_token.tcl.svn-base trunk/varnish-cache/lib/libvcl/.svn/text-base/vcc_gen_fixed_token.tcl.svn-base
diff -Nru 2.0.3/varnish-cache/lib/libvcl/.svn/text-base/vcc_gen_obj.tcl.svn-base trunk/varnish-cache/lib/libvcl/.svn/text-base/vcc_gen_obj.tcl.svn-base
diff -Nru 2.0.3/varnish-cache/lib/libvcl/.svn/text-base/vcc_obj.c.svn-base trunk/varnish-cache/lib/libvcl/.svn/text-base/vcc_obj.c.svn-base
diff -Nru 2.0.3/varnish-cache/lib/libvcl/.svn/text-base/vcc_parse.c.svn-base trunk/varnish-cache/lib/libvcl/.svn/text-base/vcc_parse.c.svn-base
diff -Nru 2.0.3/varnish-cache/lib/libvcl/.svn/text-base/vcc_priv.h.svn-base trunk/varnish-cache/lib/libvcl/.svn/text-base/vcc_priv.h.svn-base
diff -Nru 2.0.3/varnish-cache/lib/libvcl/.svn/text-base/vcc_string.c.svn-base trunk/varnish-cache/lib/libvcl/.svn/text-base/vcc_string.c.svn-base
diff -Nru 2.0.3/varnish-cache/lib/libvcl/.svn/text-base/vcc_token.c.svn-base trunk/varnish-cache/lib/libvcl/.svn/text-base/vcc_token.c.svn-base
diff -Nru 2.0.3/varnish-cache/lib/libvcl/.svn/text-base/vcc_token_defs.h.svn-base trunk/varnish-cache/lib/libvcl/.svn/text-base/vcc_token_defs.h.svn-base
diff -Nru 2.0.3/varnish-cache/lib/libvcl/.svn/text-base/vcc_var.c.svn-base trunk/varnish-cache/lib/libvcl/.svn/text-base/vcc_var.c.svn-base
diff -Nru 2.0.3/varnish-cache/lib/libvcl/.svn/text-base/vcc_xref.c.svn-base trunk/varnish-cache/lib/libvcl/.svn/text-base/vcc_xref.c.svn-base
diff -Nru 2.0.3/varnish-cache/lib/libvcl/.svn/tmp/tempfile.2.tmp trunk/varnish-cache/lib/libvcl/.svn/tmp/tempfile.2.tmp
diff -Nru 2.0.3/varnish-cache/lib/libvcl/.svn/tmp/tempfile.3.tmp trunk/varnish-cache/lib/libvcl/.svn/tmp/tempfile.3.tmp
diff -Nru 2.0.3/varnish-cache/lib/libvcl/.svn/tmp/tempfile.4.tmp trunk/varnish-cache/lib/libvcl/.svn/tmp/tempfile.4.tmp
diff -Nru 2.0.3/varnish-cache/lib/libvcl/.svn/tmp/tempfile.5.tmp trunk/varnish-cache/lib/libvcl/.svn/tmp/tempfile.5.tmp
diff -Nru 2.0.3/varnish-cache/lib/libvcl/.svn/tmp/tempfile.6.tmp trunk/varnish-cache/lib/libvcl/.svn/tmp/tempfile.6.tmp
diff -Nru 2.0.3/varnish-cache/lib/libvcl/.svn/tmp/tempfile.7.tmp trunk/varnish-cache/lib/libvcl/.svn/tmp/tempfile.7.tmp
diff -Nru 2.0.3/varnish-cache/lib/libvcl/.svn/tmp/tempfile.tmp trunk/varnish-cache/lib/libvcl/.svn/tmp/tempfile.tmp
diff -Nru 2.0.3/varnish-cache/lib/libvcl/vcc_acl.c trunk/varnish-cache/lib/libvcl/vcc_acl.c
--- 2.0.3/varnish-cache/lib/libvcl/vcc_acl.c	2008-10-16 11:09:01.000000000 +0200
+++ trunk/varnish-cache/lib/libvcl/vcc_acl.c	2009-01-05 14:45:26.000000000 +0100
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: vcc_acl.c 3310 2008-10-16 09:08:57Z tfheen $
+ * $Id: vcc_acl.c 3409 2008-11-20 10:03:53Z phk $
  */
 
 #include "config.h"
@@ -41,7 +41,6 @@
 #include <netinet/in.h>
 #include <arpa/inet.h>
 
-#include "config.h"
 #include "vsb.h"
 #include "vrt.h"
 
@@ -52,7 +51,7 @@
 struct acl_e {
 	VTAILQ_ENTRY(acl_e)	list;
 	unsigned char		data[VRT_ACL_MAXADDR + 1];
-	unsigned 		mask;
+	unsigned		mask;
 	unsigned		not;
 	unsigned		para;
 	struct token		*t_addr;
@@ -61,59 +60,87 @@
 
 /* Compare two acl rules for ordering */
 
+#define CMP(a, b)							\
+	do {								\
+		if ((a) < (b))						\
+			return (-1);					\
+		else if ((b) < (a))					\
+			return (1);					\
+	} while (0)
+		
 static int
-vcl_acl_cmp(struct tokenlist *tl, struct acl_e *ae1, struct acl_e *ae2)
+vcl_acl_cmp(struct acl_e *ae1, struct acl_e *ae2)
 {
 	unsigned char *p1, *p2;
 	unsigned m;
 
-	(void)tl;
 	p1 = ae1->data;
 	p2 = ae2->data;
 	m = ae1->mask;
 	if (ae2->mask < m)
 		m = ae2->mask;
 	for (; m >= 8; m -= 8) {
-		if (*p1 < *p2)	
-			return (-1);
-		if (*p1 > *p2)	
-			return (1);
+		CMP(*p1, *p2);
 		p1++;
 		p2++;
 	}
 	if (m) {
 		m = 0xff00 >> m;
 		m &= 0xff;
-		if ((*p1 & m) < (*p2 & m))
-			return (-1);
-		if ((*p1 & m) > (*p2 & m))
-			return (1);
-	}
-	if (ae1->mask > ae2->mask)
-		return (-1);
-	if (ae1->mask < ae2->mask)
-		return (1);
+		CMP(*p1 & m, *p2 & m);
+	}
+	/* Long mask is less than short mask */
+	CMP(ae2->mask, ae1->mask);
 
 	return (0);
 }
 
 
 static void
-vcl_acl_add_entry(struct tokenlist *tl, struct acl_e *ae)
+vcc_acl_add_entry(struct tokenlist *tl, const struct acl_e *ae, int l,
+    const unsigned char *u, int fam)
 {
-	struct acl_e *ae2;
+	struct acl_e *ae2, *aen;
 	int i;
 
+	if (fam == PF_INET && ae->mask > 32) {
+		vsb_printf(tl->sb,
+		    "Too wide mask (%u) for IPv4 address", ae->mask);
+		vcc_ErrWhere(tl, ae->t_mask);
+		return;
+	}
+	if (fam == PF_INET6 && ae->mask > 128) {
+		vsb_printf(tl->sb,
+		    "Too wide mask (%u) for IPv6 address", ae->mask);
+		vcc_ErrWhere(tl, ae->t_mask);
+		return;
+	}
+
+	/* Make a copy from the template */
+	aen = TlAlloc(tl, sizeof *ae2);
+	AN(aen);
+	*aen = *ae;
+
+	/* We treat family as part of address, it saves code */
+	assert(fam <= 0xff);
+	aen->data[0] = fam & 0xff;
+	aen->mask += 8;
+
+	memcpy(aen->data + 1, u, l);
+
 	VTAILQ_FOREACH(ae2, &tl->acl, list) {
-		i = vcl_acl_cmp(tl, ae, ae2);
+		i = vcl_acl_cmp(aen, ae2);
 		if (i == 0) {
-			/* If the two rules agree, silently ignore it */
-			if (ae->not == ae2->not)
+			/*
+			 * If the two rules agree, silently ignore it
+			 * XXX: is that counter intuitive ?
+			 */
+			if (aen->not == ae2->not)
 				return;
 			vsb_printf(tl->sb, "Conflicting ACL entries:\n");
 			vcc_ErrWhere(tl, ae2->t_addr);
 			vsb_printf(tl->sb, "vs:\n");
-			vcc_ErrWhere(tl, ae->t_addr);
+			vcc_ErrWhere(tl, aen->t_addr);
 			return;
 		}
 		/*
@@ -127,42 +154,11 @@
 		 * be used to gather statistics.
 		 */
 		if (i < 0) {
-			VTAILQ_INSERT_BEFORE(ae2, ae, list);
+			VTAILQ_INSERT_BEFORE(ae2, aen, list);
 			return;
 		}
 	}
-	VTAILQ_INSERT_TAIL(&tl->acl, ae, list);
-}
-
-static void
-vcc_acl_emit_entry(struct tokenlist *tl, const struct acl_e *ae, int l, const unsigned char *u, int fam)
-{
-	struct acl_e *ae2;
-
-	if (fam == PF_INET && ae->mask > 32) {
-		vsb_printf(tl->sb,
-		    "Too wide mask (%u) for IPv4 address", ae->mask);
-		vcc_ErrWhere(tl, ae->t_mask);
-		return;
-	}
-	if (fam == PF_INET6 && ae->mask > 128) {
-		vsb_printf(tl->sb,
-		    "Too wide mask (%u) for IPv6 address", ae->mask);
-		vcc_ErrWhere(tl, ae->t_mask);
-		return;
-	}
-
-	ae2 = TlAlloc(tl, sizeof *ae2);
-	AN(ae2);
-	*ae2 = *ae;
-
-	ae2->data[0] = fam & 0xff;
-	ae2->mask += 8;	/* family matching */
-
-	memcpy(ae2->data + 1, u, l);
-
-	vcl_acl_add_entry(tl, ae2);
-
+	VTAILQ_INSERT_TAIL(&tl->acl, aen, list);
 }
 
 static void
@@ -186,7 +182,7 @@
 			Fh(tl, 1, "/* Ignored ACL entry: %s%s",
 			    ae->para ? "\"(\" " : "", ae->not ? "\"!\" " : "");
 			EncToken(tl->fh, ae->t_addr);
-			if (ae->t_mask) 
+			if (ae->t_mask)
 				Fh(tl, 0, "/%u", ae->mask);
 			Fh(tl, 0, "%s\n", ae->para ? " \")\"" : "");
 			Fh(tl, 1, " * getaddrinfo:  %s */\n",
@@ -211,7 +207,7 @@
 			if (ae->t_mask == NULL)
 				ae->mask = 32;
 			i4++;
-			vcc_acl_emit_entry(tl, ae, 4, u, res->ai_family);
+			vcc_acl_add_entry(tl, ae, 4, u, res->ai_family);
 			break;
 		case PF_INET6:
 			assert(PF_INET6 < 256);
@@ -221,7 +217,7 @@
 			if (ae->t_mask == NULL)
 				ae->mask = 128;
 			i6++;
-			vcc_acl_emit_entry(tl, ae, 16, u, res->ai_family);
+			vcc_acl_add_entry(tl, ae, 16, u, res->ai_family);
 			break;
 		default:
 			vsb_printf(tl->sb,
@@ -270,7 +266,7 @@
 	}
 	if (ae->t_mask == NULL)
 		ae->mask = 8 + 8 * i;
-	vcc_acl_emit_entry(tl, ae, 4, b, AF_INET);
+	vcc_acl_add_entry(tl, ae, 4, b, AF_INET);
 	return (1);
 }
 
@@ -321,8 +317,12 @@
 	ERRCHK(tl);
 }
 
+/*********************************************************************
+ * Emit a function to match the ACL we have collected
+ */
+
 static void
-vcc_acl_bot(const struct tokenlist *tl, const char *acln, int silent, const char *pfx)
+vcc_acl_emit(const struct tokenlist *tl, const char *acln, int anon)
 {
 	struct acl_e *ae;
 	int depth, l, m, i;
@@ -332,7 +332,7 @@
 
 	Fh(tl, 0, "\nstatic int\n");
 	Fh(tl, 0, "match_acl_%s_%s(const struct sess *sp, const void *p)\n",
-	    pfx, acln);
+	    anon ? "anon" : "named", acln);
 	Fh(tl, 0, "{\n");
 	Fh(tl, 0, "\tconst unsigned char *a;\n");
 	assert(sizeof (unsigned char) == 1);
@@ -346,7 +346,7 @@
 		Fh(tl, 0, "\tunsigned int fam;\n");
 	else
 		assert(0 == __LINE__);
-		
+
 	Fh(tl, 0, "\n");
 	Fh(tl, 0, "\ta = p;\n");
 	Fh(tl, 0, "\tVRT_memmove(&fam, a + %d, sizeof fam);\n",
@@ -374,30 +374,31 @@
 		/* Back down, if necessary */
 		oc = "";
 		while (l <= depth) {
-			Fh(tl, 0, "\t%*s}\n",
-			    -depth, "");
+			Fh(tl, 0, "\t%*s}\n", -depth, "");
 			depth--;
 			oc = "else ";
 		}
+
 		m = ae->mask;
 		m -= l * 8;
+
+		/* Do whole byte compares */
 		for (i = l; m >= 8; m -= 8, i++) {
-			if (i == 0) {
+			if (i == 0)
 				Fh(tl, 0, "\t%*s%sif (fam == %d) {\n",
 				    -i, "", oc, ae->data[i]);
-			} else {
+			else
 				Fh(tl, 0, "\t%*s%sif (a[%d] == %d) {\n",
 				    -i, "", oc, i - 1, ae->data[i]);
-			}
 			at[i] = ae->data[i];
 			depth = i;
 			oc = "";
 		}
+
 		if (m > 0) {
+			/* Do fractional byte compares */
 			Fh(tl, 0, "\t%*s%sif ((a[%d] & 0x%x) == %d) {\n",
-			    -i, "",
-			    oc,
-			    i - 1, (0xff00 >> m) & 0xff,
+			    -i, "", oc, i - 1, (0xff00 >> m) & 0xff,
 			    ae->data[i] & ((0xff00 >> m) & 0xff));
 			at[i] = 256;
 			depth = i;
@@ -406,11 +407,9 @@
 
 		i = (ae->mask + 7) / 8;
 
-		if (!silent) {
+		if (!anon) {
 			Fh(tl, 0, "\t%*sVRT_acl_log(sp, \"%sMATCH %s \" ",
-			    -i, "",
-			    ae->not ? "NEG_" : "",
-			    acln,
+			    -i, "", ae->not ? "NEG_" : "", acln,
 			    PF(ae->t_addr));
 			EncToken(tl->fh, ae->t_addr);
 			if (ae->t_mask != NULL)
@@ -421,9 +420,12 @@
 		Fh(tl, 0, "\t%*sreturn (%d);\n", -i, "", ae->not ? 0 : 1);
 	}
 
-	for (; 0 <= depth; depth--) 
+	/* Unwind */
+	for (; 0 <= depth; depth--)
 		Fh(tl, 0, "\t%*.*s}\n", depth, depth, "");
-	if (!silent)
+
+	/* Deny by default */
+	if (!anon)
 		Fh(tl, 0, "\tVRT_acl_log(sp, \"NO_MATCH %s\");\n", acln);
 	Fh(tl, 0, "\treturn (0);\n}\n");
 }
@@ -439,7 +441,8 @@
 		vcc_NextToken(tl);
 		ExpectErr(tl, ID);
 		vcc_AddRef(tl, tl->t, R_ACL);
-		Fb(tl, 1, "match_acl_named_%.*s(sp, %s)\n", PF(tl->t), vp->rname);
+		Fb(tl, 1, "match_acl_named_%.*s(sp, %s)\n",
+		    PF(tl->t), vp->rname);
 		vcc_NextToken(tl);
 		break;
 	case T_EQ:
@@ -451,7 +454,7 @@
 		asprintf(&acln, "%u", tl->cnt);
 		assert(acln != NULL);
 		vcc_acl_entry(tl);
-		vcc_acl_bot(tl, acln, 1, "anon");
+		vcc_acl_emit(tl, acln, 1);
 		Fb(tl, 1, "%smatch_acl_anon_%s(sp, %s)\n",
 		    (tcond == T_NEQ ? "!" : ""), acln, vp->rname);
 		free(acln);
@@ -495,7 +498,7 @@
 	ExpectErr(tl, '}');
 	vcc_NextToken(tl);
 
-	vcc_acl_bot(tl, acln, 0, "named");
+	vcc_acl_emit(tl, acln, 0);
 
 	free(acln);
 }
diff -Nru 2.0.3/varnish-cache/lib/libvcl/vcc_action.c trunk/varnish-cache/lib/libvcl/vcc_action.c
--- 2.0.3/varnish-cache/lib/libvcl/vcc_action.c	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/lib/libvcl/vcc_action.c	2009-01-05 14:45:26.000000000 +0100
@@ -26,14 +26,13 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: vcc_action.c 3167 2008-09-08 07:42:25Z tfheen $
+ * $Id: vcc_action.c 3485 2008-12-21 17:03:37Z phk $
  */
 
 #include "config.h"
 
 #include <stdio.h>
 
-#include "config.h"
 #include "vsb.h"
 
 #include "vcc_priv.h"
@@ -42,26 +41,38 @@
 
 /*--------------------------------------------------------------------*/
 
-#define VCL_RET_MAC(l,u,b,i) 				\
-static void						\
-parse_##l(struct tokenlist *tl)				\
-{							\
-							\
-	Fb(tl, 1, "VRT_done(sp, VCL_RET_%s);\n", #u); 	\
-	vcc_ProcAction(tl->curproc, i, tl->t); 		\
-	vcc_NextToken(tl);				\
-}
+static void
+parse_action(struct tokenlist *tl)
+{
+	int retval = 0;
+
+	Expect(tl, ID);
 
+#define VCL_RET_MAC(l, U)						\
+	do {								\
+		if (vcc_IdIs(tl->t, #l)) {				\
+			Fb(tl, 1, "VRT_done(sp, VCL_RET_" #U ");\n");	\
+			vcc_ProcAction(tl->curproc, VCL_RET_##U, tl->t);\
+			retval = 1;					\
+		}							\
+	} while (0);
 #include "vcl_returns.h"
 #undef VCL_RET_MAC
+	if (!retval) {
+		vsb_printf(tl->sb, "Expected action name.\n");
+		vcc_ErrWhere(tl, tl->t);
+		ERRCHK(tl);
+	}
+	vcc_NextToken(tl);
+}
 
 /*--------------------------------------------------------------------*/
 
 static void
-parse_restart_real(struct tokenlist *tl)
+parse_restart(struct tokenlist *tl)
 {
 	struct token *t1;
-	
+
 	t1 = VTAILQ_NEXT(tl->t, list);
 	if (t1->tok == ID && vcc_IdIs(t1, "rollback")) {
 		Fb(tl, 1, "VRT_Rollback(sp);\n");
@@ -71,7 +82,9 @@
 		vcc_ErrWhere(tl, t1);
 		ERRCHK(tl);
 	}
-	parse_restart(tl);
+	Fb(tl, 1, "VRT_done(sp, VCL_RET_RESTART);\n");
+	vcc_ProcAction(tl->curproc, VCL_RET_RESTART, tl->t);
+	vcc_NextToken(tl);
 }
 
 /*--------------------------------------------------------------------*/
@@ -201,7 +214,8 @@
 				Fb(tl, 0, "%u", vcc_UintVal(tl));
 				vcc_NextToken(tl);
 			} else {
-				vsb_printf(tl->sb, "Cannot assign this variable type.\n");
+				vsb_printf(tl->sb,
+				    "Cannot assign this variable type.\n");
 				vcc_ErrWhere(tl, vt);
 				return;
 			}
@@ -269,7 +283,7 @@
 			vcc_ExpectedStringval(tl);
 			return;
 		}
-		do 
+		do
 			Fb(tl, 0, ", ");
 		while (vcc_StringVal(tl));
 		if (tl->t->tok != ';') {
@@ -338,17 +352,17 @@
 {
 
 	vcc_NextToken(tl);
-	
+
 	Fb(tl, 1, "VRT_purge(");
-	
+
 	Expect(tl, '(');
 	vcc_NextToken(tl);
-	
+
 	if (!vcc_StringVal(tl)) {
 		vcc_ExpectedStringval(tl);
 		return;
 	}
-	
+
 	Expect(tl, ')');
 	vcc_NextToken(tl);
 	Fb(tl, 0, ", 0);\n");
@@ -362,17 +376,17 @@
 {
 
 	vcc_NextToken(tl);
-	
+
 	Fb(tl, 1, "VRT_purge(");
-	
+
 	Expect(tl, '(');
 	vcc_NextToken(tl);
-	
+
 	if (!vcc_StringVal(tl)) {
 		vcc_ExpectedStringval(tl);
 		return;
 	}
-	
+
 	Expect(tl, ')');
 	vcc_NextToken(tl);
 	Fb(tl, 0, ", 1);\n");
@@ -392,13 +406,13 @@
 parse_panic(struct tokenlist *tl)
 {
 	vcc_NextToken(tl);
-	
+
 	Fb(tl, 1, "VRT_panic(sp, ");
 	if (!vcc_StringVal(tl)) {
 		vcc_ExpectedStringval(tl);
 		return;
 	}
-	do 
+	do
 		Fb(tl, 0, ", ");
 	while (vcc_StringVal(tl));
 	Fb(tl, 0, " vrt_magic_string_end);\n");
@@ -407,16 +421,32 @@
 /*--------------------------------------------------------------------*/
 
 static void
+parse_return(struct tokenlist *tl)
+{
+	vcc_NextToken(tl);
+	Expect(tl, '(');
+	vcc_NextToken(tl);
+	Expect(tl, ID);
+
+	parse_action(tl);
+	ERRCHK(tl);
+	Expect(tl, ')');
+	vcc_NextToken(tl);
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
 parse_synthetic(struct tokenlist *tl)
 {
 	vcc_NextToken(tl);
-	
+
 	Fb(tl, 1, "VRT_synth_page(sp, 0, ");
 	if (!vcc_StringVal(tl)) {
 		vcc_ExpectedStringval(tl);
 		return;
 	}
-	do 
+	do
 		Fb(tl, 0, ", ");
 	while (vcc_StringVal(tl));
 	Fb(tl, 0, " vrt_magic_string_end);\n");
@@ -430,23 +460,23 @@
 	const char		*name;
 	action_f		*func;
 } action_table[] = {
-	{ "restart",	parse_restart_real },
-#define VCL_RET_MAC(l, u, b, i) { #l, parse_##l },
-#define VCL_RET_MAC_E(l, u, b, i) VCL_RET_MAC(l, u, b, i) 
+	{ "restart",		parse_restart },
+	{ "error",		parse_error },
+#define VCL_RET_MAC(l, U) { #l, parse_action },
 #include "vcl_returns.h"
 #undef VCL_RET_MAC
-#undef VCL_RET_MAC_E
 
 	/* Keep list sorted from here */
-	{ "call", 		parse_call },
+	{ "call",		parse_call },
 	{ "esi",		parse_esi },
 	{ "panic",		parse_panic },
 	{ "purge_hash",		parse_purge_hash },
 	{ "purge_url",		parse_purge_url },
-	{ "remove", 		parse_unset }, /* backward compatibility */
-	{ "set", 		parse_set },
-	{ "synthetic", 		parse_synthetic },
-	{ "unset", 		parse_unset },
+	{ "remove",		parse_unset }, /* backward compatibility */
+	{ "set",		parse_set },
+	{ "synthetic",		parse_synthetic },
+	{ "unset",		parse_unset },
+	{ "return",		parse_return },
 	{ NULL,			NULL }
 };
 
diff -Nru 2.0.3/varnish-cache/lib/libvcl/vcc_backend.c trunk/varnish-cache/lib/libvcl/vcc_backend.c
--- 2.0.3/varnish-cache/lib/libvcl/vcc_backend.c	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/lib/libvcl/vcc_backend.c	2009-01-05 14:45:26.000000000 +0100
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: vcc_backend.c 3284 2008-10-10 20:56:06Z phk $
+ * $Id: vcc_backend.c 3406 2008-11-19 14:13:57Z petter $
  *
  * A necessary explanation of a convoluted policy:
  *
@@ -37,7 +37,7 @@
  * A VCL backend therefore has an implicit director of type "simple" created
  * by the compiler, but not visible in VCL.
  *
- * A VCL backend is a "named host", these can be referenced by name form
+ * A VCL backend is a "named host", these can be referenced by name from
  * VCL directors, but not from VCL backends.
  *
  * The reason for this quasimadness is that we want to collect statistics
@@ -60,7 +60,6 @@
 #include <stdarg.h>
 #include <string.h>
 
-#include "config.h"
 #include "vsb.h"
 
 #include "vcc_priv.h"
@@ -90,13 +89,14 @@
 }
 
 /*--------------------------------------------------------------------
- * Struct sockaddr is not really designed to be a compile time 
+ * Struct sockaddr is not really designed to be a compile time
  * initialized data structure, so we encode it as a byte-string
  * and put it in an official sockaddr when we load the VCL.
  */
 
 static void
-Emit_Sockaddr(struct tokenlist *tl, const struct token *t_host, const char *port)
+Emit_Sockaddr(struct tokenlist *tl, const struct token *t_host,
+    const char *port)
 {
 	struct addrinfo *res, *res0, hint;
 	int n4, n6, len, error, retval;
@@ -118,7 +118,7 @@
 		if (res->ai_family == PF_INET) {
 			if (n4++ == 0)
 				emit = "ipv4_sockaddr";
-			else 
+			else
 				multiple = "IPv4";
 		} else if (res->ai_family == PF_INET6) {
 			if (n6++ == 0)
@@ -155,12 +155,12 @@
 		Fh(tl, 0, "    %3u, /* Length */\n",  res->ai_addrlen);
 		u = (void*)res->ai_addr;
 		for (len = 0; len < res->ai_addrlen; len++) {
-			if ((len % 8) == 0) 
+			if ((len % 8) == 0)
 				Fh(tl, 0, "   ");
 			Fh(tl, 0, " %3u", u[len]);
 			if (len + 1 < res->ai_addrlen)
 				Fh(tl, 0, ",");
-			if ((len % 8) == 7) 
+			if ((len % 8) == 7)
 				Fh(tl, 0, "\n");
 		}
 		Fh(tl, 0, "\n};\n");
@@ -188,7 +188,9 @@
  */
 
 static void
-vcc_EmitBeIdent(struct vsb *v, const struct token *name, const struct token *qual, int serial, const struct token *first, const struct token *last)
+vcc_EmitBeIdent(struct vsb *v, const struct token *name,
+    const struct token *qual, int serial, const struct token *first,
+    const struct token *last)
 {
 
 	AN(name);
@@ -276,7 +278,7 @@
 	vcc_NextToken(tl);
 
 	for (; fs->name != NULL; fs++) {
-		if (!vcc_IdIs(t_field, fs->name + 1)) 
+		if (!vcc_IdIs(t_field, fs->name + 1))
 			continue;
 		if (fs->found == NULL) {
 			fs->found = t_field;
@@ -315,7 +317,8 @@
  */
 
 static void
-vcc_ProbeRedef(struct tokenlist *tl, struct token **t_did, struct token *t_field)
+vcc_ProbeRedef(struct tokenlist *tl, struct token **t_did,
+    struct token *t_field)
 {
 	/* .url and .request are mutually exclusive */
 
@@ -446,25 +449,14 @@
 }
 
 /*--------------------------------------------------------------------
- * Parse and emit a backend host definition 
- *
- * The syntax is the following:
- *
- * backend_host_def:
- *	'{' be_elements '}'
- *
- * be_elements:
- *	be_element
- *	be_element be_elements
- *
- * be_element:
- *	'.' name '=' value ';'
+ * Parse and emit a backend host definition
  *
  * The struct vrt_backend is emitted to Fh().
  */
 
 static void
-vcc_ParseHostDef(struct tokenlist *tl, int *nbh, const struct token *name, const struct token *qual, int serial)
+vcc_ParseHostDef(struct tokenlist *tl, int *nbh, const struct token *name,
+    const struct token *qual, int serial)
 {
 	struct token *t_field;
 	struct token *t_first;
@@ -481,6 +473,8 @@
 	    "?port",
 	    "?host_header",
 	    "?connect_timeout",
+	    "?first_byte_timeout",
+	    "?between_bytes_timeout",
 	    "?probe",
 	    "?max_connections",
 	    NULL);
@@ -545,6 +539,20 @@
 			Fb(tl, 0, ",\n");
 			ExpectErr(tl, ';');
 			vcc_NextToken(tl);
+		} else if (vcc_IdIs(t_field, "first_byte_timeout")) {
+			Fb(tl, 0, "\t.first_byte_timeout = ");
+			vcc_TimeVal(tl);
+			ERRCHK(tl);
+			Fb(tl, 0, ",\n");
+			ExpectErr(tl, ';');
+			vcc_NextToken(tl);
+		} else if (vcc_IdIs(t_field, "between_bytes_timeout")) {
+			Fb(tl, 0, "\t.between_bytes_timeout = ");
+			vcc_TimeVal(tl);
+			ERRCHK(tl);
+			Fb(tl, 0, ",\n");
+			ExpectErr(tl, ';');
+			vcc_NextToken(tl);
 		} else if (vcc_IdIs(t_field, "max_connections")) {
 			u = vcc_UintVal(tl);
 			vcc_NextToken(tl);
@@ -627,7 +635,8 @@
  */
 
 void
-vcc_ParseBackendHost(struct tokenlist *tl, int *nbh, const struct token *name, const struct token *qual, int serial)
+vcc_ParseBackendHost(struct tokenlist *tl, int *nbh, const struct token *name,
+    const struct token *qual, int serial)
 {
 	struct host *h;
 	struct token *t;
@@ -674,7 +683,8 @@
  */
 
 static void
-vcc_ParseSimpleDirector(struct tokenlist *tl, const struct token *t_first, struct token *t_dir)
+vcc_ParseSimpleDirector(struct tokenlist *tl, const struct token *t_first,
+    struct token *t_dir)
 {
 	struct host *h;
 
@@ -707,8 +717,8 @@
 	const char	*name;
 	parsedirector_f	*func;
 } dirlist[] = {
-	{ "random", 		vcc_ParseRandomDirector },
-	{ "round-robin", 	vcc_ParseRoundRobinDirector },
+	{ "random",		vcc_ParseRandomDirector },
+	{ "round-robin",	vcc_ParseRoundRobinDirector },
 	{ NULL,		NULL }
 };
 
@@ -738,7 +748,7 @@
 		t_policy = tl->t;
 		vcc_NextToken(tl);
 
-		for (dl = dirlist; dl->name != NULL; dl++) 
+		for (dl = dirlist; dl->name != NULL; dl++)
 			if (vcc_IdIs(t_policy, dl->name))
 				break;
 		if (dl->name == NULL) {
diff -Nru 2.0.3/varnish-cache/lib/libvcl/vcc_compile.c trunk/varnish-cache/lib/libvcl/vcc_compile.c
--- 2.0.3/varnish-cache/lib/libvcl/vcc_compile.c	2008-11-10 11:10:50.000000000 +0100
+++ trunk/varnish-cache/lib/libvcl/vcc_compile.c	2009-01-05 14:45:26.000000000 +0100
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: vcc_compile.c 3372 2008-11-10 10:10:49Z tfheen $
+ * $Id: vcc_compile.c 3487 2008-12-21 17:46:51Z phk $
  */
 
 /*
@@ -73,7 +73,6 @@
 #include <string.h>
 #include <unistd.h>
 
-#include "config.h"
 #include "vqueue.h"
 
 #include "vsb.h"
@@ -85,11 +84,9 @@
 #include "libvarnish.h"
 
 struct method method_tab[] = {
-#define VCL_RET_MAC(l,U,b,n)
 #define VCL_MET_MAC(l,U,m)	{ "vcl_"#l, m, VCL_MET_##U },
 #include "vcl_returns.h"
 #undef VCL_MET_MAC
-#undef VCL_RET_MAC
 	{ NULL, 0U, 0}
 };
 
@@ -361,12 +358,10 @@
 	Fc(tl, 0, "\t.srcname = srcname,\n");
 	Fc(tl, 0, "\t.srcbody = srcbody,\n");
 	Fc(tl, 0, "\t.nhashcount = %u,\n", tl->nhashcount);
-#define VCL_RET_MAC(l,u,b,n)
 #define VCL_MET_MAC(l,u,b) \
 	Fc(tl, 0, "\t." #l "_func = VGC_function_vcl_" #l ",\n");
 #include "vcl_returns.h"
 #undef VCL_MET_MAC
-#undef VCL_RET_MAC
 	Fc(tl, 0, "};\n");
 }
 
@@ -400,29 +395,18 @@
 /*--------------------------------------------------------------------*/
 
 static struct source *
-vcc_file_source(struct vsb *sb, const char *fn, int fd)
+vcc_file_source(struct vsb *sb, const char *fn)
 {
 	char *f;
-	int i;
-	struct stat st;
 	struct source *sp;
 
-	if (fd < 0) {
-		fd = open(fn, O_RDONLY);
-		if (fd < 0) {
-			vsb_printf(sb, "Cannot open file '%s': %s\n",
-			    fn, strerror(errno));
-			return (NULL);
-		}
+	f = vreadfile(fn);
+	if (f == NULL) {
+		vsb_printf(sb, "Cannot read file '%s': %s\n",
+		    fn, strerror(errno));
+		return (NULL);
 	}
-	assert(0 == fstat(fd, &st));
-	f = malloc(st.st_size + 1);
-	assert(f != NULL);
-	i = read(fd, f, st.st_size);
-	assert(i == st.st_size);
-	AZ(close(fd));
-	f[i] = '\0';
-	sp = vcc_new_source(f, f + i, fn);
+	sp = vcc_new_source(f, NULL, fn);
 	sp->freeit = f;
 	return (sp);
 }
@@ -457,7 +441,7 @@
 		}
 		assert(t2 != NULL);
 
-		sp = vcc_file_source(tl->sb, t1->dec, -1);
+		sp = vcc_file_source(tl->sb, t1->dec);
 		if (sp == NULL) {
 			vcc_ErrWhere(tl, t1);
 			return;
@@ -512,7 +496,7 @@
 	assert(tl->ff != NULL);
 
 	/* body code of methods */
-	for (i = 0; i < N_METHODS; i++) {
+	for (i = 0; i < VCL_MET_MAX; i++) {
 		tl->fm[i] = vsb_newauto();
 		assert(tl->fm[i] != NULL);
 	}
@@ -544,7 +528,7 @@
 	vsb_delete(tl->fc);
 	vsb_delete(tl->fi);
 	vsb_delete(tl->ff);
-	for (i = 0; i < N_METHODS; i++)
+	for (i = 0; i < VCL_MET_MAX; i++)
 		vsb_delete(tl->fm[i]);
 
 	free(tl);
@@ -623,7 +607,7 @@
 		return (vcc_DestroyTokenList(tl, NULL));
 
 	/* Emit method functions */
-	for (i = 0; i < N_METHODS; i++) {
+	for (i = 0; i < VCL_MET_MAX; i++) {
 		Fc(tl, 1, "\nstatic int\n");
 		Fc(tl, 1, "VGC_function_%s (struct sess *sp)\n",
 		    method_tab[i].name);
@@ -674,22 +658,19 @@
 	return (r);
 }
 
-/*--------------------------------------------------------------------
- * Compile the VCL code from the file named.  Error messages, if any
- * are formatted into the vsb.
- */
+/*--------------------------------------------------------------------*/
 
-char *
-VCC_CompileFile(struct vsb *sb, const char *fn, int fd)
+const char *
+VCC_Return_Name(unsigned method)
 {
-	struct source *sp;
-	char *r;
 
-	sp = vcc_file_source(sb, fn, fd);
-	if (sp == NULL)
+	switch (method) {
+#define VCL_RET_MAC(l, U) case VCL_RET_##U: return(#l);
+#include "vcl_returns.h"
+#undef VCL_RET_MAC
+	default:
 		return (NULL);
-	r = vcc_CompileSource(sb, sp);
-	return (r);
+	}
 }
 
 /*--------------------------------------------------------------------
@@ -704,6 +685,4 @@
 	vcc_default_vcl_b = default_vcl;
 	vcc_default_vcl_e = strchr(default_vcl, '\0');
 	assert(vcc_default_vcl_e != NULL);
-
-	vcl_init_tnames();
 }
diff -Nru 2.0.3/varnish-cache/lib/libvcl/vcc_compile.h trunk/varnish-cache/lib/libvcl/vcc_compile.h
--- 2.0.3/varnish-cache/lib/libvcl/vcc_compile.h	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/lib/libvcl/vcc_compile.h	2009-01-05 14:45:26.000000000 +0100
@@ -26,12 +26,12 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: vcc_compile.h 3235 2008-09-29 08:11:06Z phk $
+ * $Id: vcc_compile.h 3485 2008-12-21 17:03:37Z phk $
  */
 
 #include "vqueue.h"
 
-#include "vcl_returns.h"
+#include "vcl.h"
 
 #define INDENT		2
 
@@ -77,7 +77,7 @@
 	int			findent;
 	unsigned		cnt;
 	struct vsb		*fc, *fh, *fi, *ff, *fb;
-	struct vsb		*fm[N_METHODS];
+	struct vsb		*fm[VCL_MET_MAX];
 	VTAILQ_HEAD(, ref)	refs;
 	struct vsb		*sb;
 	int			err;
@@ -85,7 +85,7 @@
 	int			ndirector;
 	VTAILQ_HEAD(, proc)	procs;
 	struct proc		*curproc;
-	struct proc		*mprocs[N_METHODS];
+	struct proc		*mprocs[VCL_MET_MAX];
 
 	VTAILQ_HEAD(, acl_e)	acl;
 
@@ -142,7 +142,7 @@
 
 struct method {
 	const char		*name;
-	unsigned		returns;
+	unsigned		ret_bitmap;
 	unsigned		bitval;
 };
 
@@ -158,10 +158,12 @@
 
 /* vcc_backend.c */
 struct fld_spec;
-typedef void parsedirector_f(struct tokenlist *tl, const struct token *t_policy, const struct token *t_dir);
+typedef void parsedirector_f(struct tokenlist *tl,
+    const struct token *t_policy, const struct token *t_dir);
 
 void vcc_ParseDirector(struct tokenlist *tl);
-void vcc_ParseBackendHost(struct tokenlist *tl, int *nbr, const struct token *name, const struct token *qual, int serial);
+void vcc_ParseBackendHost(struct tokenlist *tl, int *nbr,
+    const struct token *name, const struct token *qual, int serial);
 struct fld_spec * vcc_FldSpec(struct tokenlist *tl, const char *first, ...);
 void vcc_ResetFldSpec(struct fld_spec *f);
 void vcc_IsField(struct tokenlist *tl, struct token **t, struct fld_spec *fs);
@@ -203,7 +205,8 @@
 void vcc_ExpectedStringval(struct tokenlist *tl);
 
 /* vcc_token.c */
-void vcc_Coord(const struct tokenlist *tl, struct vsb *vsb, const struct token *t);
+void vcc_Coord(const struct tokenlist *tl, struct vsb *vsb,
+    const struct token *t);
 void vcc_ErrToken(const struct tokenlist *tl, const struct token *t);
 void vcc_ErrWhere(struct tokenlist *tl, const struct token *t);
 void vcc__Expect(struct tokenlist *tl, unsigned tok, int line);
@@ -212,11 +215,14 @@
 void vcc_ExpectCid(struct tokenlist *tl);
 void vcc_Lexer(struct tokenlist *tl, struct source *sp);
 void vcc_NextToken(struct tokenlist *tl);
-void vcc__ErrInternal(struct tokenlist *tl, const char *func, unsigned line);
-void vcc_AddToken(struct tokenlist *tl, unsigned tok, const char *b, const char *e);
+void vcc__ErrInternal(struct tokenlist *tl, const char *func,
+    unsigned line);
+void vcc_AddToken(struct tokenlist *tl, unsigned tok, const char *b,
+    const char *e);
 
 /* vcc_var.c */
-struct var *vcc_FindVar(struct tokenlist *tl, const struct token *t, struct var *vl);
+struct var *vcc_FindVar(struct tokenlist *tl, const struct token *t,
+    struct var *vl);
 
 /* vcc_xref.c */
 void vcc_AddDef(struct tokenlist *tl, struct token *t, enum ref_type type);
diff -Nru 2.0.3/varnish-cache/lib/libvcl/vcc_dir_random.c trunk/varnish-cache/lib/libvcl/vcc_dir_random.c
--- 2.0.3/varnish-cache/lib/libvcl/vcc_dir_random.c	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/lib/libvcl/vcc_dir_random.c	2008-10-20 10:58:16.000000000 +0200
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: vcc_dir_random.c 3199 2008-09-18 13:16:09Z tfheen $
+ * $Id: vcc_dir_random.c 3324 2008-10-18 20:50:10Z phk $
  */
 
 #include "config.h"
@@ -50,7 +50,8 @@
  */
 
 void
-vcc_ParseRandomDirector(struct tokenlist *tl, const struct token *t_policy, const struct token *t_dir)
+vcc_ParseRandomDirector(struct tokenlist *tl, const struct token *t_policy,
+    const struct token *t_dir)
 {
 	struct token *t_field, *t_be;
 	int nbh, nelem;
@@ -91,7 +92,7 @@
 		ExpectErr(tl, '{');
 		vcc_NextToken(tl);
 		Fc(tl, 0, "\t{");
-	
+
 		while (tl->t->tok != '}') {	/* Member fields */
 			vcc_IsField(tl, &t_field, mfs);
 			ERRCHK(tl);
diff -Nru 2.0.3/varnish-cache/lib/libvcl/vcc_dir_round_robin.c trunk/varnish-cache/lib/libvcl/vcc_dir_round_robin.c
--- 2.0.3/varnish-cache/lib/libvcl/vcc_dir_round_robin.c	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/lib/libvcl/vcc_dir_round_robin.c	2008-10-20 10:58:16.000000000 +0200
@@ -25,7 +25,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: vcc_dir_round_robin.c 3199 2008-09-18 13:16:09Z tfheen $
+ * $Id: vcc_dir_round_robin.c 3324 2008-10-18 20:50:10Z phk $
  */
 
 #include "config.h"
@@ -49,7 +49,8 @@
  */
 
 void
-vcc_ParseRoundRobinDirector(struct tokenlist *tl, const struct token *t_policy, const struct token *t_dir)
+vcc_ParseRoundRobinDirector(struct tokenlist *tl, const struct token *t_policy,
+    const struct token *t_dir)
 {
 	struct token *t_field, *t_be;
 	int nbh, nelem;
@@ -58,9 +59,8 @@
 
 	fs = vcc_FldSpec(tl, "!backend", NULL);
 
-	Fc(tl, 0,
-	    "\nstatic const struct vrt_dir_round_robin_entry vdrre_%.*s[] = {\n",
-	    PF(t_dir));
+	Fc(tl, 0, "\nstatic const struct vrt_dir_round_robin_entry "
+	    "vdrre_%.*s[] = {\n", PF(t_dir));
 
 	for (nelem = 0; tl->t->tok != '}'; nelem++) {	/* List of members */
 		first = "";
@@ -71,7 +71,7 @@
 		ExpectErr(tl, '{');
 		vcc_NextToken(tl);
 		Fc(tl, 0, "\t{");
-	
+
 		while (tl->t->tok != '}') {	/* Member fields */
 			vcc_IsField(tl, &t_field, fs);
 			ERRCHK(tl);
@@ -103,8 +103,7 @@
 	Fc(tl, 0, "\t.nmember = %d,\n", nelem);
 	Fc(tl, 0, "\t.members = vdrre_%.*s,\n", PF(t_dir));
 	Fc(tl, 0, "};\n");
-	Fi(tl, 0,
-	    "\tVRT_init_dir_round_robin(cli, &VGC_backend_%.*s , &vdrr_%.*s);\n",
-	    PF(t_dir), PF(t_dir));
+	Fi(tl, 0, "\tVRT_init_dir_round_robin("
+	    "cli, &VGC_backend_%.*s , &vdrr_%.*s);\n", PF(t_dir), PF(t_dir));
 	Ff(tl, 0, "\tVRT_fini_dir(cli, VGC_backend_%.*s);\n", PF(t_dir));
 }
diff -Nru 2.0.3/varnish-cache/lib/libvcl/vcc_fixed_token.c trunk/varnish-cache/lib/libvcl/vcc_fixed_token.c
--- 2.0.3/varnish-cache/lib/libvcl/vcc_fixed_token.c	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/lib/libvcl/vcc_fixed_token.c	2009-01-05 14:45:26.000000000 +0100
@@ -1,9 +1,9 @@
 /*
- * $Id: vcc_fixed_token.c 3234 2008-09-29 07:32:26Z phk $
+ * $Id: vcc_fixed_token.c 3485 2008-12-21 17:03:37Z phk $
  *
  * NB:  This file is machine generated, DO NOT EDIT!
  *
- * Edit vcc_gen_fixed_token.tcl instead
+ * Edit and run vcc_gen_fixed_token.tcl instead
  */
 
 #include "config.h"
@@ -13,491 +13,357 @@
 #include "vcc_priv.h"
 #include "vsb.h"
 
+#define M1()     do {*q = p + 1; return (p[0]); } while (0)
+#define M2(c, t) do {if (p[1] == (c)) { *q = p + 2; return (t); }} while (0)
+
 unsigned
 vcl_fixed_token(const char *p, const char **q)
 {
 
 	switch (p[0]) {
 	case '!':
-		if (p[1] == '=') {
-			*q = p + 2;
-			return (T_NEQ);
-		}
-		*q = p + 1;
-		return (p[0]);
+		M2('=', T_NEQ);
+		M1();
 	case '%':
-		*q = p + 1;
-		return (p[0]);
+		M1();
 	case '&':
-		if (p[1] == '&') {
-			*q = p + 2;
-			return (T_CAND);
-		}
-		*q = p + 1;
-		return (p[0]);
+		M2('&', T_CAND);
+		M1();
 	case '(':
-		*q = p + 1;
-		return (p[0]);
+		M1();
 	case ')':
-		*q = p + 1;
-		return (p[0]);
+		M1();
 	case '*':
-		if (p[1] == '=') {
-			*q = p + 2;
-			return (T_MUL);
-		}
-		*q = p + 1;
-		return (p[0]);
+		M2('=', T_MUL);
+		M1();
 	case '+':
-		if (p[1] == '=') {
-			*q = p + 2;
-			return (T_INCR);
-		}
-		if (p[1] == '+') {
-			*q = p + 2;
-			return (T_INC);
-		}
-		*q = p + 1;
-		return (p[0]);
+		M2('=', T_INCR);
+		M2('+', T_INC);
+		M1();
 	case ',':
-		*q = p + 1;
-		return (p[0]);
+		M1();
 	case '-':
-		if (p[1] == '=') {
-			*q = p + 2;
-			return (T_DECR);
-		}
-		if (p[1] == '-') {
-			*q = p + 2;
-			return (T_DEC);
-		}
-		*q = p + 1;
-		return (p[0]);
+		M2('=', T_DECR);
+		M2('-', T_DEC);
+		M1();
 	case '.':
-		*q = p + 1;
-		return (p[0]);
+		M1();
 	case '/':
-		if (p[1] == '=') {
-			*q = p + 2;
-			return (T_DIV);
-		}
-		*q = p + 1;
-		return (p[0]);
+		M2('=', T_DIV);
+		M1();
 	case ';':
-		*q = p + 1;
-		return (p[0]);
+		M1();
 	case '<':
-		if (p[1] == '=') {
-			*q = p + 2;
-			return (T_LEQ);
-		}
-		if (p[1] == '<') {
-			*q = p + 2;
-			return (T_SHL);
-		}
-		*q = p + 1;
-		return (p[0]);
+		M2('=', T_LEQ);
+		M2('<', T_SHL);
+		M1();
 	case '=':
-		if (p[1] == '=') {
-			*q = p + 2;
-			return (T_EQ);
-		}
-		*q = p + 1;
-		return (p[0]);
+		M2('=', T_EQ);
+		M1();
 	case '>':
-		if (p[1] == '>') {
-			*q = p + 2;
-			return (T_SHR);
-		}
-		if (p[1] == '=') {
-			*q = p + 2;
-			return (T_GEQ);
-		}
-		*q = p + 1;
-		return (p[0]);
+		M2('>', T_SHR);
+		M2('=', T_GEQ);
+		M1();
 	case 'e':
-		if (p[1] == 'l' && p[2] == 's' && 
-		    p[3] == 'i' && p[4] == 'f' && !isvar(p[5])) {
+		if (p[1] == 'l' && p[2] == 's' && p[3] == 'i' &&
+		    p[4] == 'f' && !isvar(p[5])) {
 			*q = p + 5;
 			return (T_ELSIF);
 		}
-		if (p[1] == 'l' && p[2] == 's' && 
-		    p[3] == 'e' && p[4] == 'i' && p[5] == 'f'
-		     && !isvar(p[6])) {
+		if (p[1] == 'l' && p[2] == 's' && p[3] == 'e' &&
+		    p[4] == 'i' && p[5] == 'f' && !isvar(p[6])) {
 			*q = p + 6;
 			return (T_ELSEIF);
 		}
-		if (p[1] == 'l' && p[2] == 's' && 
-		    p[3] == 'e' && !isvar(p[4])) {
+		if (p[1] == 'l' && p[2] == 's' && p[3] == 'e'
+		     && !isvar(p[4])) {
 			*q = p + 4;
 			return (T_ELSE);
 		}
 		return (0);
 	case 'i':
-		if (p[1] == 'n' && p[2] == 'c' && 
-		    p[3] == 'l' && p[4] == 'u' && p[5] == 'd' && 
-		    p[6] == 'e' && !isvar(p[7])) {
+		if (p[1] == 'n' && p[2] == 'c' && p[3] == 'l' &&
+		    p[4] == 'u' && p[5] == 'd' && p[6] == 'e'
+		     && !isvar(p[7])) {
 			*q = p + 7;
 			return (T_INCLUDE);
 		}
-		if (p[1] == 'f' && !isvar(p[2])) {
-			*q = p + 2;
-			return (T_IF);
-		}
+		M2('f', T_IF);
 		return (0);
 	case '{':
-		*q = p + 1;
-		return (p[0]);
+		M1();
 	case '|':
-		if (p[1] == '|') {
-			*q = p + 2;
-			return (T_COR);
-		}
-		*q = p + 1;
-		return (p[0]);
+		M2('|', T_COR);
+		M1();
 	case '}':
-		*q = p + 1;
-		return (p[0]);
+		M1();
 	case '~':
-		*q = p + 1;
-		return (p[0]);
+		M1();
 	default:
 		return (0);
 	}
 }
 
-const char *vcl_tnames[256];
-
-void
-vcl_init_tnames(void)
-{
-	vcl_tnames['!'] = "'!'";
-	vcl_tnames['%'] = "'%'";
-	vcl_tnames['&'] = "'&'";
-	vcl_tnames['('] = "'('";
-	vcl_tnames[')'] = "')'";
-	vcl_tnames['*'] = "'*'";
-	vcl_tnames['+'] = "'+'";
-	vcl_tnames[','] = "','";
-	vcl_tnames['-'] = "'-'";
-	vcl_tnames['.'] = "'.'";
-	vcl_tnames['/'] = "'/'";
-	vcl_tnames['<'] = "'<'";
-	vcl_tnames['='] = "'='";
-	vcl_tnames['>'] = "'>'";
-	vcl_tnames['{'] = "'{'";
-	vcl_tnames['}'] = "'}'";
-	vcl_tnames['|'] = "'|'";
-	vcl_tnames['~'] = "'~'";
-	vcl_tnames[';'] = "';'";
-	vcl_tnames[CNUM] = "CNUM";
-	vcl_tnames[CSRC] = "CSRC";
-	vcl_tnames[CSTR] = "CSTR";
-	vcl_tnames[EOI] = "EOI";
-	vcl_tnames[ID] = "ID";
-	vcl_tnames[T_CAND] = "&&";
-	vcl_tnames[T_COR] = "||";
-	vcl_tnames[T_DEC] = "--";
-	vcl_tnames[T_DECR] = "-=";
-	vcl_tnames[T_DIV] = "/=";
-	vcl_tnames[T_ELSE] = "else";
-	vcl_tnames[T_ELSEIF] = "elseif";
-	vcl_tnames[T_ELSIF] = "elsif";
-	vcl_tnames[T_EQ] = "==";
-	vcl_tnames[T_GEQ] = ">=";
-	vcl_tnames[T_IF] = "if";
-	vcl_tnames[T_INC] = "++";
-	vcl_tnames[T_INCLUDE] = "include";
-	vcl_tnames[T_INCR] = "+=";
-	vcl_tnames[T_LEQ] = "<=";
-	vcl_tnames[T_MUL] = "*=";
-	vcl_tnames[T_NEQ] = "!=";
-	vcl_tnames[T_SHL] = "<<";
-	vcl_tnames[T_SHR] = ">>";
-	vcl_tnames[VAR] = "VAR";
-}
+const char * const vcl_tnames[256] = {
+	['!'] = "'!'",
+	['%'] = "'%'",
+	['&'] = "'&'",
+	['('] = "'('",
+	[')'] = "')'",
+	['*'] = "'*'",
+	['+'] = "'+'",
+	[','] = "','",
+	['-'] = "'-'",
+	['.'] = "'.'",
+	['/'] = "'/'",
+	['<'] = "'<'",
+	['='] = "'='",
+	['>'] = "'>'",
+	['{'] = "'{'",
+	['}'] = "'}'",
+	['|'] = "'|'",
+	['~'] = "'~'",
+	[';'] = "';'",
+	[CNUM] = "CNUM",
+	[CSRC] = "CSRC",
+	[CSTR] = "CSTR",
+	[EOI] = "EOI",
+	[ID] = "ID",
+	[T_CAND] = "&&",
+	[T_COR] = "||",
+	[T_DEC] = "--",
+	[T_DECR] = "-=",
+	[T_DIV] = "/=",
+	[T_ELSE] = "else",
+	[T_ELSEIF] = "elseif",
+	[T_ELSIF] = "elsif",
+	[T_EQ] = "==",
+	[T_GEQ] = ">=",
+	[T_IF] = "if",
+	[T_INC] = "++",
+	[T_INCLUDE] = "include",
+	[T_INCR] = "+=",
+	[T_LEQ] = "<=",
+	[T_MUL] = "*=",
+	[T_NEQ] = "!=",
+	[T_SHL] = "<<",
+	[T_SHR] = ">>",
+	[VAR] = "VAR",
+};
 
 void
 vcl_output_lang_h(struct vsb *sb)
 {
-	vsb_cat(sb, "#define VCL_RET_ERROR  (1 << 0)\n");
-	vsb_cat(sb, "#define VCL_RET_LOOKUP  (1 << 1)\n");
-	vsb_cat(sb, "#define VCL_RET_HASH  (1 << 2)\n");
-	vsb_cat(sb, "#define VCL_RET_PIPE  (1 << 3)\n");
-	vsb_cat(sb, "#define VCL_RET_PASS  (1 << 4)\n");
-	vsb_cat(sb, "#define VCL_RET_FETCH  (1 << 5)\n");
-	vsb_cat(sb, "#define VCL_RET_DELIVER  (1 << 6)\n");
-	vsb_cat(sb, "#define VCL_RET_DISCARD  (1 << 7)\n");
-	vsb_cat(sb, "#define VCL_RET_KEEP  (1 << 8)\n");
-	vsb_cat(sb, "#define VCL_RET_RESTART  (1 << 9)\n");
-	vsb_cat(sb, "/*\n");
-	vsb_cat(sb, " * $Id: vcc_fixed_token.c 3234 2008-09-29 07:32:26Z phk $\n");
-	vsb_cat(sb, " *\n");
-	vsb_cat(sb, " * NB:  This file is machine generated, DO NOT EDIT!\n");
-	vsb_cat(sb, " *\n");
-	vsb_cat(sb, " * Edit vcc_gen_fixed_token.tcl instead\n");
-	vsb_cat(sb, " */\n");
-	vsb_cat(sb, "\n");
-	vsb_cat(sb, "struct sess;\n");
-	vsb_cat(sb, "struct cli;\n");
-	vsb_cat(sb, "\n");
-	vsb_cat(sb, "typedef void vcl_init_f(struct cli *);\n");
+
+	/* ../../include/vcl.h */
+
+	vsb_cat(sb, "/*\n * $Id: vcc_gen_fixed_token.tcl 3484 2008-12-21 17");
+	vsb_cat(sb, ":01:58Z phk $\n *\n * NB:  This file is machine genera");
+	vsb_cat(sb, "ted, DO NOT EDIT!\n *\n * Edit and run vcc_gen_fixed_t");
+	vsb_cat(sb, "oken.tcl instead\n */\n\nstruct sess;\n");
+	vsb_cat(sb, "struct cli;\n\ntypedef void vcl_init_f(struct cli *);\n");
 	vsb_cat(sb, "typedef void vcl_fini_f(struct cli *);\n");
 	vsb_cat(sb, "typedef int vcl_func_f(struct sess *sp);\n");
-	vsb_cat(sb, "\n");
-	vsb_cat(sb, "struct VCL_conf {\n");
-	vsb_cat(sb, "	unsigned        magic;\n");
-	vsb_cat(sb, "#define VCL_CONF_MAGIC  0x7406c509      /* from /dev/random */\n");
-	vsb_cat(sb, "\n");
-	vsb_cat(sb, "        struct director  **director;\n");
-	vsb_cat(sb, "        unsigned        ndirector;\n");
-	vsb_cat(sb, "        struct vrt_ref  *ref;\n");
-	vsb_cat(sb, "        unsigned        nref;\n");
-	vsb_cat(sb, "        unsigned        busy;\n");
-	vsb_cat(sb, "        unsigned        discard;\n");
-	vsb_cat(sb, "        \n");
-	vsb_cat(sb, "	unsigned	nsrc;\n");
-	vsb_cat(sb, "	const char	**srcname;\n");
-	vsb_cat(sb, "	const char	**srcbody;\n");
-	vsb_cat(sb, "\n");
-	vsb_cat(sb, "	unsigned	nhashcount;\n");
-	vsb_cat(sb, "\n");
-	vsb_cat(sb, "        vcl_init_f      *init_func;\n");
-	vsb_cat(sb, "        vcl_fini_f      *fini_func;\n");
-	vsb_cat(sb, "\n");
-	vsb_cat(sb, "	vcl_func_f	*recv_func;\n");
-	vsb_cat(sb, "	vcl_func_f	*pipe_func;\n");
-	vsb_cat(sb, "	vcl_func_f	*pass_func;\n");
-	vsb_cat(sb, "	vcl_func_f	*hash_func;\n");
-	vsb_cat(sb, "	vcl_func_f	*miss_func;\n");
-	vsb_cat(sb, "	vcl_func_f	*hit_func;\n");
-	vsb_cat(sb, "	vcl_func_f	*fetch_func;\n");
-	vsb_cat(sb, "	vcl_func_f	*deliver_func;\n");
-	vsb_cat(sb, "	vcl_func_f	*prefetch_func;\n");
-	vsb_cat(sb, "	vcl_func_f	*timeout_func;\n");
-	vsb_cat(sb, "	vcl_func_f	*discard_func;\n");
-	vsb_cat(sb, "	vcl_func_f	*error_func;\n");
+	vsb_cat(sb, "\n/* VCL Methods */\n#define VCL_MET_RECV\t\t(1 << 0)\n");
+	vsb_cat(sb, "#define VCL_MET_PIPE\t\t(1 << 1)\n");
+	vsb_cat(sb, "#define VCL_MET_PASS\t\t(1 << 2)\n");
+	vsb_cat(sb, "#define VCL_MET_HASH\t\t(1 << 3)\n");
+	vsb_cat(sb, "#define VCL_MET_MISS\t\t(1 << 4)\n");
+	vsb_cat(sb, "#define VCL_MET_HIT\t\t(1 << 5)\n");
+	vsb_cat(sb, "#define VCL_MET_FETCH\t\t(1 << 6)\n");
+	vsb_cat(sb, "#define VCL_MET_DELIVER\t\t(1 << 7)\n");
+	vsb_cat(sb, "#define VCL_MET_PREFETCH\t(1 << 8)\n");
+	vsb_cat(sb, "#define VCL_MET_TIMEOUT\t\t(1 << 9)\n");
+	vsb_cat(sb, "#define VCL_MET_DISCARD\t\t(1 << 10)\n");
+	vsb_cat(sb, "#define VCL_MET_ERROR\t\t(1 << 11)\n");
+	vsb_cat(sb, "\n#define VCL_MET_MAX\t\t12\n\n");
+	vsb_cat(sb, "/* VCL Returns */\n#define VCL_RET_ERROR\t\t0\n");
+	vsb_cat(sb, "#define VCL_RET_LOOKUP\t\t1\n#define VCL_RET_HASH\t\t2");
+	vsb_cat(sb, "\n#define VCL_RET_PIPE\t\t3\n#define VCL_RET_PASS\t\t4");
+	vsb_cat(sb, "\n#define VCL_RET_FETCH\t\t5\n#define VCL_RET_DELIVER\t");
+	vsb_cat(sb, "\t6\n#define VCL_RET_DISCARD\t\t7\n");
+	vsb_cat(sb, "#define VCL_RET_KEEP\t\t8\n#define VCL_RET_RESTART\t\t");
+	vsb_cat(sb, "9\n\n#define VCL_RET_MAX\t\t10\n");
+	vsb_cat(sb, "\nstruct VCL_conf {\n\tunsigned\tmagic;\n");
+	vsb_cat(sb, "#define VCL_CONF_MAGIC\t0x7406c509\t/* from /dev/rando");
+	vsb_cat(sb, "m */\n\n\tstruct director\t**director;\n");
+	vsb_cat(sb, "\tunsigned\tndirector;\n\tstruct vrt_ref\t*ref;\n");
+	vsb_cat(sb, "\tunsigned\tnref;\n\tunsigned\tbusy;\n");
+	vsb_cat(sb, "\tunsigned\tdiscard;\n\n\tunsigned\tnsrc;\n");
+	vsb_cat(sb, "\tconst char\t**srcname;\n\tconst char\t**srcbody;\n");
+	vsb_cat(sb, "\n\tunsigned\tnhashcount;\n\n\tvcl_init_f\t*init_func;");
+	vsb_cat(sb, "\n\tvcl_fini_f\t*fini_func;\n\n");
+	vsb_cat(sb, "\tvcl_func_f\t*recv_func;\n\tvcl_func_f\t*pipe_func;\n");
+	vsb_cat(sb, "\tvcl_func_f\t*pass_func;\n\tvcl_func_f\t*hash_func;\n");
+	vsb_cat(sb, "\tvcl_func_f\t*miss_func;\n\tvcl_func_f\t*hit_func;\n");
+	vsb_cat(sb, "\tvcl_func_f\t*fetch_func;\n\tvcl_func_f\t*deliver_fun");
+	vsb_cat(sb, "c;\n\tvcl_func_f\t*prefetch_func;\n");
+	vsb_cat(sb, "\tvcl_func_f\t*timeout_func;\n\tvcl_func_f\t*discard_f");
+	vsb_cat(sb, "unc;\n\tvcl_func_f\t*error_func;\n");
 	vsb_cat(sb, "};\n");
-	vsb_cat(sb, "/*-\n");
-	vsb_cat(sb, " * Copyright (c) 2006 Verdens Gang AS\n");
+
+	/* ../../include/vrt.h */
+
+	vsb_cat(sb, "/*-\n * Copyright (c) 2006 Verdens Gang AS\n");
 	vsb_cat(sb, " * Copyright (c) 2006-2008 Linpro AS\n");
-	vsb_cat(sb, " * All rights reserved.\n");
-	vsb_cat(sb, " *\n");
-	vsb_cat(sb, " * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>\n");
-	vsb_cat(sb, " *\n");
-	vsb_cat(sb, " * Redistribution and use in source and binary forms, with or without\n");
-	vsb_cat(sb, " * modification, are permitted provided that the following conditions\n");
-	vsb_cat(sb, " * are met:\n");
-	vsb_cat(sb, " * 1. Redistributions of source code must retain the above copyright\n");
-	vsb_cat(sb, " *    notice, this list of conditions and the following disclaimer.\n");
-	vsb_cat(sb, " * 2. Redistributions in binary form must reproduce the above copyright\n");
-	vsb_cat(sb, " *    notice, this list of conditions and the following disclaimer in the\n");
-	vsb_cat(sb, " *    documentation and/or other materials provided with the distribution.\n");
-	vsb_cat(sb, " *\n");
-	vsb_cat(sb, " * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n");
-	vsb_cat(sb, " * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n");
-	vsb_cat(sb, " * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n");
-	vsb_cat(sb, " * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE\n");
-	vsb_cat(sb, " * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n");
-	vsb_cat(sb, " * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n");
-	vsb_cat(sb, " * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n");
-	vsb_cat(sb, " * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n");
-	vsb_cat(sb, " * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n");
-	vsb_cat(sb, " * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n");
-	vsb_cat(sb, " * SUCH DAMAGE.\n");
-	vsb_cat(sb, " *\n");
-	vsb_cat(sb, " * $Id: vcc_fixed_token.c 3234 2008-09-29 07:32:26Z phk $\n");
-	vsb_cat(sb, " *\n");
-	vsb_cat(sb, " * Runtime support for compiled VCL programs.\n");
-	vsb_cat(sb, " *\n");
-	vsb_cat(sb, " * XXX: When this file is changed, lib/libvcl/vcc_gen_fixed_token.tcl\n");
-	vsb_cat(sb, " * XXX: *MUST* be rerun.\n");
-	vsb_cat(sb, " */\n");
-	vsb_cat(sb, "\n");
-	vsb_cat(sb, "struct sess;\n");
-	vsb_cat(sb, "struct vsb;\n");
-	vsb_cat(sb, "struct cli;\n");
-	vsb_cat(sb, "struct director;\n");
-	vsb_cat(sb, "struct VCL_conf;\n");
-	vsb_cat(sb, "struct sockaddr;\n");
-	vsb_cat(sb, "\n");
-	vsb_cat(sb, "/*\n");
-	vsb_cat(sb, " * A backend probe specification\n");
-	vsb_cat(sb, " */\n");
-	vsb_cat(sb, "\n");
-	vsb_cat(sb, "extern void *vrt_magic_string_end;\n");
-	vsb_cat(sb, "\n");
-	vsb_cat(sb, "struct vrt_backend_probe {\n");
-	vsb_cat(sb, "	const char	*url;\n");
-	vsb_cat(sb, "	const char	*request;\n");
-	vsb_cat(sb, "	double		timeout;\n");
-	vsb_cat(sb, "	double		interval;\n");
-	vsb_cat(sb, "	unsigned	window;\n");
-	vsb_cat(sb, "	unsigned	threshold;\n");
-	vsb_cat(sb, "};\n");
-	vsb_cat(sb, "\n");
-	vsb_cat(sb, "/*\n");
+	vsb_cat(sb, " * All rights reserved.\n *\n * Author: Poul-Henning K");
+	vsb_cat(sb, "amp <phk@phk.freebsd.dk>\n *\n * Redistribution and us");
+	vsb_cat(sb, "e in source and binary forms, with or without\n");
+	vsb_cat(sb, " * modification, are permitted provided that the follo");
+	vsb_cat(sb, "wing conditions\n * are met:\n * 1. Redistributions of");
+	vsb_cat(sb, " source code must retain the above copyright\n");
+	vsb_cat(sb, " *    notice, this list of conditions and the followin");
+	vsb_cat(sb, "g disclaimer.\n * 2. Redistributions in binary form mu");
+	vsb_cat(sb, "st reproduce the above copyright\n");
+	vsb_cat(sb, " *    notice, this list of conditions and the followin");
+	vsb_cat(sb, "g disclaimer in the\n *    documentation and/or other ");
+	vsb_cat(sb, "materials provided with the distribution.\n");
+	vsb_cat(sb, " *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CON");
+	vsb_cat(sb, "TRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WAR");
+	vsb_cat(sb, "RANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n");
+	vsb_cat(sb, " * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS F");
+	vsb_cat(sb, "OR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVE");
+	vsb_cat(sb, "NT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE\n");
+	vsb_cat(sb, " * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEM");
+	vsb_cat(sb, "PLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NO");
+	vsb_cat(sb, "T LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n");
+	vsb_cat(sb, " * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSI");
+	vsb_cat(sb, "NESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEOR");
+	vsb_cat(sb, "Y OF LIABILITY, WHETHER IN CONTRACT, STRICT\n");
+	vsb_cat(sb, " * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWI");
+	vsb_cat(sb, "SE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFT");
+	vsb_cat(sb, "WARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n");
+	vsb_cat(sb, " * SUCH DAMAGE.\n *\n * $Id: vrt.h 3406 2008-11-19 14:");
+	vsb_cat(sb, "13:57Z petter $\n *\n * Runtime support for compiled V");
+	vsb_cat(sb, "CL programs.\n *\n * XXX: When this file is changed, l");
+	vsb_cat(sb, "ib/libvcl/vcc_gen_fixed_token.tcl\n");
+	vsb_cat(sb, " * XXX: *MUST* be rerun.\n */\n");
+	vsb_cat(sb, "\nstruct sess;\nstruct vsb;\nstruct cli;\n");
+	vsb_cat(sb, "struct director;\nstruct VCL_conf;\n");
+	vsb_cat(sb, "struct sockaddr;\n\n/*\n * A backend probe specificati");
+	vsb_cat(sb, "on\n */\n\nextern void *vrt_magic_string_end;\n");
+	vsb_cat(sb, "\nstruct vrt_backend_probe {\n\tconst char\t*url;\n");
+	vsb_cat(sb, "\tconst char\t*request;\n\tdouble\t\ttimeout;\n");
+	vsb_cat(sb, "\tdouble\t\tinterval;\n\tunsigned\twindow;\n");
+	vsb_cat(sb, "\tunsigned\tthreshold;\n};\n\n/*\n");
 	vsb_cat(sb, " * A backend is a host+port somewhere on the network\n");
-	vsb_cat(sb, " */\n");
-	vsb_cat(sb, "struct vrt_backend {\n");
-	vsb_cat(sb, "	const char			*vcl_name;\n");
-	vsb_cat(sb, "	const char			*ident;\n");
-	vsb_cat(sb, "\n");
-	vsb_cat(sb, "	const char			*hosthdr;\n");
-	vsb_cat(sb, "\n");
-	vsb_cat(sb, "	const unsigned char		*ipv4_sockaddr;\n");
-	vsb_cat(sb, "	const unsigned char		*ipv6_sockaddr;\n");
-	vsb_cat(sb, "\n");
-	vsb_cat(sb, "	double				connect_timeout;\n");
-	vsb_cat(sb, "	unsigned			max_connections;\n");
-	vsb_cat(sb, "	struct vrt_backend_probe 	probe;\n");
-	vsb_cat(sb, "};\n");
-	vsb_cat(sb, "\n");
-	vsb_cat(sb, "/*\n");
-	vsb_cat(sb, " * A director with a predictable reply\n");
-	vsb_cat(sb, " */\n");
-	vsb_cat(sb, "\n");
-	vsb_cat(sb, "struct vrt_dir_simple {\n");
-	vsb_cat(sb, "	const char				*name;\n");
-	vsb_cat(sb, "	const struct vrt_backend		*host;\n");
-	vsb_cat(sb, "};\n");
-	vsb_cat(sb, "\n");
-	vsb_cat(sb, "/*\n");
-	vsb_cat(sb, " * A director with an unpredictable reply\n");
-	vsb_cat(sb, " */\n");
-	vsb_cat(sb, "\n");
-	vsb_cat(sb, "struct vrt_dir_random_entry {\n");
-	vsb_cat(sb, "	const struct vrt_backend		*host;\n");
-	vsb_cat(sb, "	double					weight;\n");
-	vsb_cat(sb, "};\n");
-	vsb_cat(sb, "\n");
-	vsb_cat(sb, "struct vrt_dir_random {\n");
-	vsb_cat(sb, "	const char 				*name;\n");
-	vsb_cat(sb, "	unsigned				retries;\n");
-	vsb_cat(sb, "	unsigned 				nmember;\n");
-	vsb_cat(sb, "	const struct vrt_dir_random_entry	*members;\n");
-	vsb_cat(sb, "};\n");
-	vsb_cat(sb, "\n");
-	vsb_cat(sb, "/*\n");
-	vsb_cat(sb, " * A director with round robin selection\n");
-	vsb_cat(sb, " */\n");
-	vsb_cat(sb, "\n");
-	vsb_cat(sb, "struct vrt_dir_round_robin_entry {\n");
-	vsb_cat(sb, "	const struct vrt_backend		*host;\n");
-	vsb_cat(sb, "};\n");
-	vsb_cat(sb, "\n");
-	vsb_cat(sb, "struct vrt_dir_round_robin {\n");
-	vsb_cat(sb, "	const char				*name;\n");
-	vsb_cat(sb, "	unsigned 				nmember;\n");
-	vsb_cat(sb, "	const struct vrt_dir_round_robin_entry	*members;\n");
-	vsb_cat(sb, "};\n");
-	vsb_cat(sb, "\n");
-	vsb_cat(sb, "\n");
-	vsb_cat(sb, "/*\n");
-	vsb_cat(sb, " * other stuff.\n");
-	vsb_cat(sb, " * XXX: document when bored\n");
-	vsb_cat(sb, " */\n");
-	vsb_cat(sb, "\n");
-	vsb_cat(sb, "struct vrt_ref {\n");
-	vsb_cat(sb, "	unsigned	source;\n");
-	vsb_cat(sb, "	unsigned	offset;\n");
-	vsb_cat(sb, "	unsigned	line;\n");
-	vsb_cat(sb, "	unsigned	pos;\n");
-	vsb_cat(sb, "	unsigned	count;\n");
-	vsb_cat(sb, "	const char	*token;\n");
-	vsb_cat(sb, "};\n");
-	vsb_cat(sb, "\n");
-	vsb_cat(sb, "/* ACL related */\n");
-	vsb_cat(sb, "#define VRT_ACL_MAXADDR		16	/* max(IPv4, IPv6) */\n");
-	vsb_cat(sb, "\n");
-	vsb_cat(sb, "void VRT_acl_log(const struct sess *, const char *msg);\n");
-	vsb_cat(sb, "\n");
-	vsb_cat(sb, "/* Regexp related */\n");
-	vsb_cat(sb, "void VRT_re_init(void **, const char *, int sub);\n");
-	vsb_cat(sb, "void VRT_re_fini(void *);\n");
+	vsb_cat(sb, " */\nstruct vrt_backend {\n\tconst char\t\t\t*vcl_name");
+	vsb_cat(sb, ";\n\tconst char\t\t\t*ident;\n\n");
+	vsb_cat(sb, "\tconst char\t\t\t*hosthdr;\n\n");
+	vsb_cat(sb, "\tconst unsigned char\t\t*ipv4_sockaddr;\n");
+	vsb_cat(sb, "\tconst unsigned char\t\t*ipv6_sockaddr;\n");
+	vsb_cat(sb, "\n\tdouble\t\t\t\tconnect_timeout;\n");
+	vsb_cat(sb, "\tdouble\t\t\t\tfirst_byte_timeout;\n");
+	vsb_cat(sb, "\tdouble\t\t\t\tbetween_bytes_timeout;\n");
+	vsb_cat(sb, "\tunsigned\t\t\tmax_connections;\n");
+	vsb_cat(sb, "\tstruct vrt_backend_probe\tprobe;\n");
+	vsb_cat(sb, "};\n\n/*\n * A director with a predictable reply\n");
+	vsb_cat(sb, " */\n\nstruct vrt_dir_simple {\n");
+	vsb_cat(sb, "\tconst char\t\t\t\t*name;\n\tconst struct vrt_backend");
+	vsb_cat(sb, "\t\t*host;\n};\n\n/*\n * A director with an unpredicta");
+	vsb_cat(sb, "ble reply\n */\n\nstruct vrt_dir_random_entry {\n");
+	vsb_cat(sb, "\tconst struct vrt_backend\t\t*host;\n");
+	vsb_cat(sb, "\tdouble\t\t\t\t\tweight;\n};\n");
+	vsb_cat(sb, "\nstruct vrt_dir_random {\n\tconst char\t\t\t\t*name;\n");
+	vsb_cat(sb, "\tunsigned\t\t\t\tretries;\n\tunsigned\t\t\t\tnmember;");
+	vsb_cat(sb, "\n\tconst struct vrt_dir_random_entry\t*members;\n");
+	vsb_cat(sb, "};\n\n/*\n * A director with round robin selection\n");
+	vsb_cat(sb, " */\n\nstruct vrt_dir_round_robin_entry {\n");
+	vsb_cat(sb, "\tconst struct vrt_backend\t\t*host;\n");
+	vsb_cat(sb, "};\n\nstruct vrt_dir_round_robin {\n");
+	vsb_cat(sb, "\tconst char\t\t\t\t*name;\n\tunsigned\t\t\t\tnmember;");
+	vsb_cat(sb, "\n\tconst struct vrt_dir_round_robin_entry\t*members;\n");
+	vsb_cat(sb, "};\n\n\n/*\n * other stuff.\n * XXX: document when bor");
+	vsb_cat(sb, "ed\n */\n\nstruct vrt_ref {\n\tunsigned\tsource;\n");
+	vsb_cat(sb, "\tunsigned\toffset;\n\tunsigned\tline;\n");
+	vsb_cat(sb, "\tunsigned\tpos;\n\tunsigned\tcount;\n");
+	vsb_cat(sb, "\tconst char\t*token;\n};\n\n/* ACL related */\n");
+	vsb_cat(sb, "#define VRT_ACL_MAXADDR\t\t16\t/* max(IPv4, IPv6) */\n");
+	vsb_cat(sb, "\nvoid VRT_acl_log(const struct sess *, const char *ms");
+	vsb_cat(sb, "g);\n\n/* Regexp related */\nvoid VRT_re_init(void **,");
+	vsb_cat(sb, " const char *, int sub);\nvoid VRT_re_fini(void *);\n");
 	vsb_cat(sb, "int VRT_re_match(const char *, void *re);\n");
-	vsb_cat(sb, "int VRT_re_test(struct vsb *, const char *, int sub);\n");
-	vsb_cat(sb, "const char *VRT_regsub(const struct sess *sp, int all, const char *, void *, const char *);\n");
-	vsb_cat(sb, "\n");
-	vsb_cat(sb, "void VRT_panic(struct sess *sp,  const char *, ...);\n");
-	vsb_cat(sb, "void VRT_purge(const char *, int hash);\n");
-	vsb_cat(sb, "\n");
-	vsb_cat(sb, "void VRT_count(const struct sess *, unsigned);\n");
+	vsb_cat(sb, "const char *VRT_regsub(const struct sess *sp, int all,");
+	vsb_cat(sb, " const char *,\n    void *, const char *);\n");
+	vsb_cat(sb, "\nvoid VRT_panic(struct sess *sp,  const char *, ...);");
+	vsb_cat(sb, "\nvoid VRT_purge(const char *, int hash);\n");
+	vsb_cat(sb, "\nvoid VRT_count(const struct sess *, unsigned);\n");
 	vsb_cat(sb, "int VRT_rewrite(const char *, const char *);\n");
-	vsb_cat(sb, "void VRT_error(struct sess *, unsigned, const char *);\n");
-	vsb_cat(sb, "int VRT_switch_config(const char *);\n");
-	vsb_cat(sb, "\n");
-	vsb_cat(sb, "enum gethdr_e { HDR_REQ, HDR_RESP, HDR_OBJ, HDR_BEREQ };\n");
-	vsb_cat(sb, "char *VRT_GetHdr(const struct sess *, enum gethdr_e where, const char *);\n");
-	vsb_cat(sb, "void VRT_SetHdr(const struct sess *, enum gethdr_e where, const char *, const char *, ...);\n");
-	vsb_cat(sb, "void VRT_handling(struct sess *sp, unsigned hand);\n");
-	vsb_cat(sb, "\n");
-	vsb_cat(sb, "/* Simple stuff */\n");
+	vsb_cat(sb, "void VRT_error(struct sess *, unsigned, const char *);");
+	vsb_cat(sb, "\nint VRT_switch_config(const char *);\n");
+	vsb_cat(sb, "\nenum gethdr_e { HDR_REQ, HDR_RESP, HDR_OBJ, HDR_BERE");
+	vsb_cat(sb, "Q };\nchar *VRT_GetHdr(const struct sess *, enum gethd");
+	vsb_cat(sb, "r_e where, const char *);\nvoid VRT_SetHdr(const struc");
+	vsb_cat(sb, "t sess *, enum gethdr_e where, const char *,\n");
+	vsb_cat(sb, "    const char *, ...);\nvoid VRT_handling(struct sess");
+	vsb_cat(sb, " *sp, unsigned hand);\n\n/* Simple stuff */\n");
 	vsb_cat(sb, "int VRT_strcmp(const char *s1, const char *s2);\n");
-	vsb_cat(sb, "void VRT_memmove(void *dst, const void *src, unsigned len);\n");
-	vsb_cat(sb, "\n");
-	vsb_cat(sb, "void VRT_ESI(struct sess *sp);\n");
+	vsb_cat(sb, "void VRT_memmove(void *dst, const void *src, unsigned ");
+	vsb_cat(sb, "len);\n\nvoid VRT_ESI(struct sess *sp);\n");
 	vsb_cat(sb, "void VRT_Rollback(struct sess *sp);\n");
-	vsb_cat(sb, "\n");
-	vsb_cat(sb, "/* Synthetic pages */\n");
-	vsb_cat(sb, "void VRT_synth_page(struct sess *sp, unsigned flags, const char *, ...);\n");
-	vsb_cat(sb, "\n");
-	vsb_cat(sb, "/* Backend related */\n");
-	vsb_cat(sb, "void VRT_init_dir_simple(struct cli *, struct director **, const struct vrt_dir_simple *);\n");
-	vsb_cat(sb, "void VRT_init_dir_random(struct cli *, struct director **, const struct vrt_dir_random *);\n");
-	vsb_cat(sb, "void VRT_init_dir_round_robin(struct cli *, struct director **, const struct vrt_dir_round_robin *);\n");
+	vsb_cat(sb, "\n/* Synthetic pages */\nvoid VRT_synth_page(struct se");
+	vsb_cat(sb, "ss *sp, unsigned flags, const char *, ...);\n");
+	vsb_cat(sb, "\n/* Backend related */\nvoid VRT_init_dir_simple(stru");
+	vsb_cat(sb, "ct cli *, struct director **,\n");
+	vsb_cat(sb, "    const struct vrt_dir_simple *);\n");
+	vsb_cat(sb, "void VRT_init_dir_random(struct cli *, struct director");
+	vsb_cat(sb, " **,\n    const struct vrt_dir_random *);\n");
+	vsb_cat(sb, "void VRT_init_dir_round_robin(struct cli *, struct dir");
+	vsb_cat(sb, "ector **,\n    const struct vrt_dir_round_robin *);\n");
 	vsb_cat(sb, "void VRT_fini_dir(struct cli *, struct director *);\n");
-	vsb_cat(sb, "\n");
-	vsb_cat(sb, "char *VRT_IP_string(const struct sess *sp, const struct sockaddr *sa);\n");
-	vsb_cat(sb, "char *VRT_int_string(const struct sess *sp, int);\n");
-	vsb_cat(sb, "char *VRT_double_string(const struct sess *sp, double);\n");
-	vsb_cat(sb, "const char *VRT_backend_string(struct sess *sp);\n");
-	vsb_cat(sb, "\n");
-	vsb_cat(sb, "#define VRT_done(sp, hand)			\\\n");
-	vsb_cat(sb, "	do {					\\\n");
-	vsb_cat(sb, "		VRT_handling(sp, hand);		\\\n");
-	vsb_cat(sb, "		return (1);			\\\n");
-	vsb_cat(sb, "	} while (0)\n");
-	vsb_cat(sb, "/*\n");
-	vsb_cat(sb, " * $Id: vcc_fixed_token.c 3234 2008-09-29 07:32:26Z phk $\n");
-	vsb_cat(sb, " *\n");
-	vsb_cat(sb, " * NB:  This file is machine generated, DO NOT EDIT!\n");
-	vsb_cat(sb, " *\n");
-	vsb_cat(sb, " * Edit vcc_gen_obj.tcl instead\n");
-	vsb_cat(sb, " */\n");
-	vsb_cat(sb, "\n");
-	vsb_cat(sb, "struct sockaddr * VRT_r_client_ip(const struct sess *);\n");
-	vsb_cat(sb, "struct sockaddr * VRT_r_server_ip(struct sess *);\n");
-	vsb_cat(sb, "int VRT_r_server_port(struct sess *);\n");
+	vsb_cat(sb, "\nchar *VRT_IP_string(const struct sess *sp, const str");
+	vsb_cat(sb, "uct sockaddr *sa);\nchar *VRT_int_string(const struct ");
+	vsb_cat(sb, "sess *sp, int);\nchar *VRT_double_string(const struct ");
+	vsb_cat(sb, "sess *sp, double);\nconst char *VRT_backend_string(str");
+	vsb_cat(sb, "uct sess *sp);\n\n#define VRT_done(sp, hand)\t\t\t\\\n");
+	vsb_cat(sb, "\tdo {\t\t\t\t\t\\\n\t\tVRT_handling(sp, hand);\t\t\\\n");
+	vsb_cat(sb, "\t\treturn (1);\t\t\t\\\n\t} while (0)\n");
+
+	/* ../../include/vrt_obj.h */
+
+	vsb_cat(sb, "/*\n * $Id: vrt_obj.h 3406 2008-11-19 14:13:57Z petter");
+	vsb_cat(sb, " $\n *\n * NB:  This file is machine generated, DO NOT");
+	vsb_cat(sb, " EDIT!\n *\n * Edit vcc_gen_obj.tcl instead\n");
+	vsb_cat(sb, " */\n\nstruct sockaddr * VRT_r_client_ip(const struct ");
+	vsb_cat(sb, "sess *);\nstruct sockaddr * VRT_r_server_ip(struct ses");
+	vsb_cat(sb, "s *);\nint VRT_r_server_port(struct sess *);\n");
 	vsb_cat(sb, "const char * VRT_r_req_request(const struct sess *);\n");
-	vsb_cat(sb, "void VRT_l_req_request(const struct sess *, const char *, ...);\n");
-	vsb_cat(sb, "const char * VRT_r_req_url(const struct sess *);\n");
-	vsb_cat(sb, "void VRT_l_req_url(const struct sess *, const char *, ...);\n");
-	vsb_cat(sb, "const char * VRT_r_req_proto(const struct sess *);\n");
-	vsb_cat(sb, "void VRT_l_req_proto(const struct sess *, const char *, ...);\n");
-	vsb_cat(sb, "void VRT_l_req_hash(struct sess *, const char *);\n");
-	vsb_cat(sb, "struct director * VRT_r_req_backend(struct sess *);\n");
-	vsb_cat(sb, "void VRT_l_req_backend(struct sess *, struct director *);\n");
-	vsb_cat(sb, "int VRT_r_req_restarts(const struct sess *);\n");
-	vsb_cat(sb, "double VRT_r_req_grace(struct sess *);\n");
+	vsb_cat(sb, "void VRT_l_req_request(const struct sess *, const char");
+	vsb_cat(sb, " *, ...);\nconst char * VRT_r_req_url(const struct ses");
+	vsb_cat(sb, "s *);\nvoid VRT_l_req_url(const struct sess *, const c");
+	vsb_cat(sb, "har *, ...);\nconst char * VRT_r_req_proto(const struc");
+	vsb_cat(sb, "t sess *);\nvoid VRT_l_req_proto(const struct sess *, ");
+	vsb_cat(sb, "const char *, ...);\nvoid VRT_l_req_hash(struct sess *");
+	vsb_cat(sb, ", const char *);\nstruct director * VRT_r_req_backend(");
+	vsb_cat(sb, "struct sess *);\nvoid VRT_l_req_backend(struct sess *,");
+	vsb_cat(sb, " struct director *);\nint VRT_r_req_restarts(const str");
+	vsb_cat(sb, "uct sess *);\ndouble VRT_r_req_grace(struct sess *);\n");
 	vsb_cat(sb, "void VRT_l_req_grace(struct sess *, double);\n");
 	vsb_cat(sb, "const char * VRT_r_req_xid(struct sess *);\n");
-	vsb_cat(sb, "const char * VRT_r_bereq_request(const struct sess *);\n");
-	vsb_cat(sb, "void VRT_l_bereq_request(const struct sess *, const char *, ...);\n");
-	vsb_cat(sb, "const char * VRT_r_bereq_url(const struct sess *);\n");
-	vsb_cat(sb, "void VRT_l_bereq_url(const struct sess *, const char *, ...);\n");
-	vsb_cat(sb, "const char * VRT_r_bereq_proto(const struct sess *);\n");
-	vsb_cat(sb, "void VRT_l_bereq_proto(const struct sess *, const char *, ...);\n");
-	vsb_cat(sb, "const char * VRT_r_obj_proto(const struct sess *);\n");
-	vsb_cat(sb, "void VRT_l_obj_proto(const struct sess *, const char *, ...);\n");
+	vsb_cat(sb, "const char * VRT_r_bereq_request(const struct sess *);");
+	vsb_cat(sb, "\nvoid VRT_l_bereq_request(const struct sess *, const ");
+	vsb_cat(sb, "char *, ...);\nconst char * VRT_r_bereq_url(const stru");
+	vsb_cat(sb, "ct sess *);\nvoid VRT_l_bereq_url(const struct sess *,");
+	vsb_cat(sb, " const char *, ...);\nconst char * VRT_r_bereq_proto(c");
+	vsb_cat(sb, "onst struct sess *);\nvoid VRT_l_bereq_proto(const str");
+	vsb_cat(sb, "uct sess *, const char *, ...);\n");
+	vsb_cat(sb, "double VRT_r_bereq_connect_timeout(struct sess *);\n");
+	vsb_cat(sb, "void VRT_l_bereq_connect_timeout(struct sess *, double");
+	vsb_cat(sb, ");\ndouble VRT_r_bereq_first_byte_timeout(struct sess ");
+	vsb_cat(sb, "*);\nvoid VRT_l_bereq_first_byte_timeout(struct sess *");
+	vsb_cat(sb, ", double);\ndouble VRT_r_bereq_between_bytes_timeout(s");
+	vsb_cat(sb, "truct sess *);\nvoid VRT_l_bereq_between_bytes_timeout");
+	vsb_cat(sb, "(struct sess *, double);\nconst char * VRT_r_obj_proto");
+	vsb_cat(sb, "(const struct sess *);\nvoid VRT_l_obj_proto(const str");
+	vsb_cat(sb, "uct sess *, const char *, ...);\n");
 	vsb_cat(sb, "int VRT_r_obj_status(const struct sess *);\n");
 	vsb_cat(sb, "void VRT_l_obj_status(const struct sess *, int);\n");
 	vsb_cat(sb, "const char * VRT_r_obj_response(const struct sess *);\n");
-	vsb_cat(sb, "void VRT_l_obj_response(const struct sess *, const char *, ...);\n");
-	vsb_cat(sb, "int VRT_r_obj_hits(const struct sess *);\n");
+	vsb_cat(sb, "void VRT_l_obj_response(const struct sess *, const cha");
+	vsb_cat(sb, "r *, ...);\nint VRT_r_obj_hits(const struct sess *);\n");
 	vsb_cat(sb, "unsigned VRT_r_obj_cacheable(const struct sess *);\n");
-	vsb_cat(sb, "void VRT_l_obj_cacheable(const struct sess *, unsigned);\n");
-	vsb_cat(sb, "double VRT_r_obj_ttl(const struct sess *);\n");
+	vsb_cat(sb, "void VRT_l_obj_cacheable(const struct sess *, unsigned");
+	vsb_cat(sb, ");\ndouble VRT_r_obj_ttl(const struct sess *);\n");
 	vsb_cat(sb, "void VRT_l_obj_ttl(const struct sess *, double);\n");
 	vsb_cat(sb, "double VRT_r_obj_grace(const struct sess *);\n");
 	vsb_cat(sb, "void VRT_l_obj_grace(const struct sess *, double);\n");
@@ -506,11 +372,12 @@
 	vsb_cat(sb, "double VRT_r_obj_lastuse(const struct sess *);\n");
 	vsb_cat(sb, "const char * VRT_r_obj_hash(const struct sess *);\n");
 	vsb_cat(sb, "const char * VRT_r_resp_proto(const struct sess *);\n");
-	vsb_cat(sb, "void VRT_l_resp_proto(const struct sess *, const char *, ...);\n");
-	vsb_cat(sb, "int VRT_r_resp_status(const struct sess *);\n");
+	vsb_cat(sb, "void VRT_l_resp_proto(const struct sess *, const char ");
+	vsb_cat(sb, "*, ...);\nint VRT_r_resp_status(const struct sess *);\n");
 	vsb_cat(sb, "void VRT_l_resp_status(const struct sess *, int);\n");
-	vsb_cat(sb, "const char * VRT_r_resp_response(const struct sess *);\n");
-	vsb_cat(sb, "void VRT_l_resp_response(const struct sess *, const char *, ...);\n");
-	vsb_cat(sb, "double VRT_r_now(const struct sess *);\n");
-	vsb_cat(sb, "unsigned VRT_r_req_backend_healthy(const struct sess *);\n");
+	vsb_cat(sb, "const char * VRT_r_resp_response(const struct sess *);");
+	vsb_cat(sb, "\nvoid VRT_l_resp_response(const struct sess *, const ");
+	vsb_cat(sb, "char *, ...);\ndouble VRT_r_now(const struct sess *);\n");
+	vsb_cat(sb, "unsigned VRT_r_req_backend_healthy(const struct sess *");
+	vsb_cat(sb, ");\n");
 }
diff -Nru 2.0.3/varnish-cache/lib/libvcl/vcc_gen_fixed_token.tcl trunk/varnish-cache/lib/libvcl/vcc_gen_fixed_token.tcl
--- 2.0.3/varnish-cache/lib/libvcl/vcc_gen_fixed_token.tcl	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/lib/libvcl/vcc_gen_fixed_token.tcl	2009-01-05 14:45:26.000000000 +0100
@@ -30,7 +30,7 @@
 # Generate various .c and .h files for the VCL compiler and the interfaces
 # for it.
 
-# These are the metods which can be called in the VCL program. 
+# These are the metods which can be called in the VCL program.
 # Second element is list of valid return actions.
 #
 set methods {
@@ -66,7 +66,7 @@
 # Language keywords
 #
 set keywords {
-	include 
+	include
 
 	if else elseif elsif
 }
@@ -104,11 +104,12 @@
 proc warns {fd} {
 
 	puts $fd "/*"
-	puts $fd { * $Id: vcc_gen_fixed_token.tcl 3098 2008-08-18 08:18:43Z phk $}
+	puts $fd \
+	    { * $Id: vcc_gen_fixed_token.tcl 3484 2008-12-21 17:01:58Z phk $}
 	puts $fd " *"
 	puts $fd " * NB:  This file is machine generated, DO NOT EDIT!"
 	puts $fd " *"
-	puts $fd " * Edit vcc_gen_fixed_token.tcl instead"
+	puts $fd " * Edit and run vcc_gen_fixed_token.tcl instead"
 	puts $fd " */"
 	puts $fd ""
 }
@@ -125,25 +126,48 @@
 typedef void vcl_fini_f(struct cli *);
 typedef int vcl_func_f(struct sess *sp);
 }
+
+puts $fo "/* VCL Methods */"
+set u 0
+foreach m $methods {
+	if {[string length [lindex $m 0]] < 8} {
+		set sp "\t"
+	} else {
+		set sp ""
+	}
+	puts $fo "#define VCL_MET_[string toupper [lindex $m 0]]\t${sp}(1 << $u)"
+	incr u
+}
+
+puts $fo "\n#define VCL_MET_MAX\t\t$u\n"
+
+puts $fo "/* VCL Returns */"
+set i 0
+foreach k $returns {
+	puts $fo "#define VCL_RET_[string toupper $k]\t\t$i"
+	incr i
+}
+puts $fo "\n#define VCL_RET_MAX\t\t$i\n"
+
 puts $fo "struct VCL_conf {"
-puts $fo {	unsigned        magic;
-#define VCL_CONF_MAGIC  0x7406c509      /* from /dev/random */
+puts $fo {	unsigned	magic;
+#define VCL_CONF_MAGIC	0x7406c509	/* from /dev/random */
+
+	struct director	**director;
+	unsigned	ndirector;
+	struct vrt_ref	*ref;
+	unsigned	nref;
+	unsigned	busy;
+	unsigned	discard;
 
-        struct director  **director;
-        unsigned        ndirector;
-        struct vrt_ref  *ref;
-        unsigned        nref;
-        unsigned        busy;
-        unsigned        discard;
-        
 	unsigned	nsrc;
 	const char	**srcname;
 	const char	**srcbody;
 
 	unsigned	nhashcount;
 
-        vcl_init_f      *init_func;
-        vcl_fini_f      *fini_func;
+	vcl_init_f	*init_func;
+	vcl_fini_f	*fini_func;
 }
 foreach m $methods {
 	puts $fo "\tvcl_func_f\t*[lindex $m 0]_func;"
@@ -160,22 +184,14 @@
 puts $for "#ifdef VCL_RET_MAC"
 set i 0
 foreach k $returns {
+	set u [string toupper $k]
 	if {$k == "error"} {
-		puts $for "#ifdef VCL_RET_MAC_E"
-		puts $for "VCL_RET_MAC_E($k, [string toupper $k], (1 << $i), $i)"
-		puts $for "#endif"
+		puts $for "VCL_RET_MAC($k, $u)"
 	} else {
-		puts $for "VCL_RET_MAC($k, [string toupper $k], (1 << $i), $i)"
+		puts $for "VCL_RET_MAC($k, $u)"
 	}
 	incr i
 }
-puts $for "#else"
-set i 0
-foreach k $returns {
-	puts $for "#define VCL_RET_[string toupper $k]  (1 << $i)"
-	incr i
-}
-puts $for "#define VCL_RET_MAX $i"
 puts $for "#endif"
 puts $for ""
 puts $for "#ifdef VCL_MET_MAC"
@@ -184,22 +200,15 @@
 	puts -nonewline $for "VCL_MET_MAC([lindex $m 0]"
 	puts -nonewline $for ",[string toupper [lindex $m 0]]"
 	set l [lindex $m 1]
-	puts -nonewline $for ",(VCL_RET_[string toupper [lindex $l 0]]"
+	puts $for ","
+	puts $for "     ((1 << VCL_RET_[string toupper [lindex $l 0]])"
 	foreach r [lrange $l 1 end] {
-		puts -nonewline $for "|VCL_RET_[string toupper $r]"
+		puts $for "    | (1 << VCL_RET_[string toupper $r])"
 	}
-	puts -nonewline $for ")"
-	puts $for ")"
-	incr u
-}
-puts $for "#else"
-set u 0
-foreach m $methods {
-	puts $for "#define VCL_MET_[string toupper [lindex $m 0]]\t(1 << $u)"
+	puts $for "))"
 	incr u
 }
 puts $for "#endif"
-puts $for "#define N_METHODS $u"
 close $for
 
 #----------------------------------------------------------------------
@@ -260,6 +269,9 @@
 set seq [lsort [array names xx]]
 
 puts $fo {
+#define M1()     do {*q = p + 1; return (p[0]); } while (0)
+#define M2(c, t) do {if (p[1] == (c)) { *q = p + 2; return (t); }} while (0)
+
 unsigned
 vcl_fixed_token(const char *p, const char **q)}
 puts $fo "{"
@@ -279,25 +291,33 @@
 	scan "$ch" "%c" cx
 	puts $fo "	case '$ch':"
 	set retval "0"
+	set m1 0
 	foreach tt $l {
 		set k [lindex $tt 0]
 		if {[string length $k] == 1} {
-			puts $fo "\t\t*q = p + 1;"
-			set retval {p[0]}
+			puts $fo "\t\tM1();"
+			set m1 1
 			continue;
 		}
+		if {[string length $k] == 2} {
+			puts -nonewline $fo "		M2("
+			puts -nonewline $fo "'[string index $k 1]'"
+			puts            $fo ", [lindex $tt 1]);"
+			continue;
+		} 
 		puts -nonewline $fo "		if ("
 		for {set i 1} {$i < [string length $k]} {incr i} {
 			if {$i > 1} {
-				puts -nonewline $fo " && "
-				if {![expr $i % 3]} {
-					puts -nonewline $fo "\n\t\t    "
+				puts -nonewline $fo " &&"
+				if {[expr $i % 3] == 1} {
+					puts -nonewline $fo "\n\t\t   "
 				}
+				puts -nonewline $fo " "
 			}
 			puts -nonewline $fo "p\[$i\] == '[string index $k $i]'"
 		}
 		if {[lindex $tt 2]} {
-			if {![expr $i % 3]} {
+			if {[expr $i % 3] == 1} {
 				puts -nonewline $fo "\n\t\t    "
 			}
 			puts -nonewline $fo " && !isvar(p\[$i\])"
@@ -307,8 +327,10 @@
 		puts $fo "\t\t\treturn ([lindex $tt 1]);"
 		puts $fo "\t\t}"
 	}
-	puts $fo "\t\treturn ($retval);"
-} 
+	if {$m1 == 0} {
+		puts $fo "\t\treturn ($retval);"
+	}
+}
 
 puts $fo "	default:"
 puts $fo "		return (0);"
@@ -316,17 +338,14 @@
 puts $fo "}"
 
 puts $fo ""
-puts $fo "const char *vcl_tnames\[256\];\n"
-puts $fo "void"
-puts $fo "vcl_init_tnames(void)"
-puts $fo "{"
+puts $fo "const char * const vcl_tnames\[256\] = {"
 foreach i $token2 {
-	puts $fo "\tvcl_tnames\[[lindex $i 0]\] = \"[lindex $i 0]\";"
+	puts $fo "\t\[[lindex $i 0]\] = \"[lindex $i 0]\","
 }
 foreach i $tokens {
-	puts $fo "\tvcl_tnames\[[lindex $i 0]\] = \"[lindex $i 1]\";"
+	puts $fo "\t\[[lindex $i 0]\] = \"[lindex $i 1]\","
 }
-puts $fo "}"
+puts $fo "};"
 
 #----------------------------------------------------------------------
 # Create the C-code which emits the boilerplate definitions for the
@@ -335,10 +354,42 @@
 proc copy_include {n} {
 	global fo
 
+	puts $fo "\n\t/* $n */\n"
 	set fi [open $n]
+	set n 0
 	while {[gets $fi a] >= 0} {
-		regsub -all {\\} $a {\\\\} a
-		puts $fo "\tvsb_cat(sb, \"$a\\n\");"
+		for {set b 0} {$b < [string length $a]} {incr b} {
+			if {$n == 0} {
+				puts -nonewline $fo "\tvsb_cat(sb, \""
+			}
+			set c [string index $a $b]
+			if {"$c" == "\\"} {
+				puts -nonewline $fo "\\\\"
+				incr n
+			} elseif {"$c" == "\t"} {
+				puts -nonewline $fo "\\t"
+				incr n
+			} else {
+				puts -nonewline $fo "$c"
+			}
+			incr n
+			if {$n > 53} {
+				puts $fo "\");"
+				set n 0
+			}
+		}
+		if {$n == 0} {
+			puts -nonewline $fo "\tvsb_cat(sb, \""
+		}
+		puts -nonewline $fo "\\n"
+		incr n 2
+		if {$n > 30} {
+			puts $fo "\");"
+			set n 0
+		}
+	}
+	if {$n > 0} {
+		puts $fo "\");"
 	}
 	close $fi
 }
@@ -347,11 +398,6 @@
 puts $fo "void"
 puts $fo "vcl_output_lang_h(struct vsb *sb)"
 puts $fo "{"
-set i 0
-foreach k $returns {
-	puts $fo "\tvsb_cat(sb, \"#define VCL_RET_[string toupper $k]  (1 << $i)\\n\");"
-	incr i
-}
 
 copy_include ../../include/vcl.h
 copy_include ../../include/vrt.h
diff -Nru 2.0.3/varnish-cache/lib/libvcl/vcc_gen_obj.tcl trunk/varnish-cache/lib/libvcl/vcc_gen_obj.tcl
--- 2.0.3/varnish-cache/lib/libvcl/vcc_gen_obj.tcl	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/lib/libvcl/vcc_gen_obj.tcl	2009-01-05 14:45:26.000000000 +0100
@@ -127,6 +127,21 @@
 	{     pipe pass      miss     fetch                        }
 	"const struct sess *"
     }
+    { bereq.connect_timeout
+	RW TIME
+	{     pass      miss     }
+	"struct sess *"
+    }
+    { bereq.first_byte_timeout
+	RW TIME
+	{     pass      miss     }
+	"struct sess *"
+    }
+    { bereq.between_bytes_timeout
+	RW TIME
+	{     pass      miss     }
+	"struct sess *"
+    }
 
     # The (possibly) cached object
     { obj.proto
@@ -245,7 +260,7 @@
 proc warns {fd} {
 
 	puts $fd "/*"
-	puts $fd { * $Id: vcc_gen_obj.tcl 3169 2008-09-08 09:49:01Z tfheen $}
+	puts $fd { * $Id: vcc_gen_obj.tcl 3406 2008-11-19 14:13:57Z petter $}
 	puts $fd " *"
 	puts $fd " * NB:  This file is machine generated, DO NOT EDIT!"
 	puts $fd " *"
@@ -261,15 +276,31 @@
 
 proc method_map {m} {
 
-	set l ""
+	set l1 ""
+	set l2 ""
 	foreach i $m {
-		append l " | "
-		append l VCL_MET_[string toupper $i]
+		if {[string length $l2] > 55} {
+			if {$l1 != ""} {
+				append l1 "\n\t    "
+			}
+			append l1 "$l2"
+			set l2 ""
+		}
+		if {$l2 != "" || $l1 != ""} {
+			append l2 " | "
+		}
+		append l2 VCL_MET_[string toupper $i]
 	}
-	if {$l == ""} {
+	if {$l2 != ""} {
+		if {$l1 != ""} {
+			append l1 "\n\t    "
+		}
+		append l1 "$l2"
+	}
+	if {$l1 == ""} {
 		return "0"
 	}
-	return [string range $l 3 end]
+	return $l1
 }
 
 proc vars {v pa} {
@@ -289,12 +320,12 @@
 			puts $fo  "\t\{ \"$n\", $t, [string length $n],"
 		}
 		if {$a == "RO" || $a == "RW"} {
-			puts $fo  "\t    \"VRT_r_${m}($pa)\","
+			puts -nonewline $fo  "\t    \"VRT_r_${m}($pa)\","
 			if {![regexp HDR_ $t]} {
 				puts $fp  "$tt($t) VRT_r_${m}($ty);"
 			}
 		} else {
-			puts $fo  "\t    NULL,"
+			puts -nonewline $fo  "\t    NULL,"
 		}
 		if {$a == "WO" || $a == "RW"} {
 			puts $fo  "\t    \"VRT_l_${m}($pa, \","
@@ -307,7 +338,7 @@
 		} else {
 			puts $fo  "\t    NULL,"
 		}
-		puts $fo  "\t    V_$a,"
+		puts -nonewline $fo  "\t    V_$a,"
 		if {![regexp HDR_ $t]} {
 			puts $fo  "\t    0,"
 		} else {
diff -Nru 2.0.3/varnish-cache/lib/libvcl/vcc_obj.c trunk/varnish-cache/lib/libvcl/vcc_obj.c
--- 2.0.3/varnish-cache/lib/libvcl/vcc_obj.c	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/lib/libvcl/vcc_obj.c	2009-01-05 14:45:26.000000000 +0100
@@ -1,5 +1,5 @@
 /*
- * $Id: vcc_obj.c 3169 2008-09-08 09:49:01Z tfheen $
+ * $Id: vcc_obj.c 3406 2008-11-19 14:13:57Z petter $
  *
  * NB:  This file is machine generated, DO NOT EDIT!
  *
@@ -12,235 +12,210 @@
 
 struct var vcc_vars[] = {
 	{ "client.ip", IP, 9,
-	    "VRT_r_client_ip(sp)",
-	    NULL,
-	    V_RO,
-	    0,
-	    VCL_MET_RECV | VCL_MET_PIPE | VCL_MET_PASS | VCL_MET_HASH | VCL_MET_MISS | VCL_MET_HIT | VCL_MET_FETCH | VCL_MET_DELIVER | VCL_MET_ERROR
+	    "VRT_r_client_ip(sp)",	    NULL,
+	    V_RO,	    0,
+	    VCL_MET_RECV | VCL_MET_PIPE | VCL_MET_PASS | VCL_MET_HASH
+	     | VCL_MET_MISS | VCL_MET_HIT | VCL_MET_FETCH | VCL_MET_DELIVER
+	     | VCL_MET_ERROR
 	},
 	{ "server.ip", IP, 9,
-	    "VRT_r_server_ip(sp)",
-	    NULL,
-	    V_RO,
-	    0,
-	    VCL_MET_RECV | VCL_MET_PIPE | VCL_MET_PASS | VCL_MET_HASH | VCL_MET_MISS | VCL_MET_HIT | VCL_MET_FETCH | VCL_MET_DELIVER | VCL_MET_ERROR
+	    "VRT_r_server_ip(sp)",	    NULL,
+	    V_RO,	    0,
+	    VCL_MET_RECV | VCL_MET_PIPE | VCL_MET_PASS | VCL_MET_HASH
+	     | VCL_MET_MISS | VCL_MET_HIT | VCL_MET_FETCH | VCL_MET_DELIVER
+	     | VCL_MET_ERROR
 	},
 	{ "server.port", INT, 11,
-	    "VRT_r_server_port(sp)",
-	    NULL,
-	    V_RO,
-	    0,
-	    VCL_MET_RECV | VCL_MET_PIPE | VCL_MET_PASS | VCL_MET_HASH | VCL_MET_MISS | VCL_MET_HIT | VCL_MET_FETCH | VCL_MET_DELIVER | VCL_MET_ERROR
+	    "VRT_r_server_port(sp)",	    NULL,
+	    V_RO,	    0,
+	    VCL_MET_RECV | VCL_MET_PIPE | VCL_MET_PASS | VCL_MET_HASH
+	     | VCL_MET_MISS | VCL_MET_HIT | VCL_MET_FETCH | VCL_MET_DELIVER
+	     | VCL_MET_ERROR
 	},
 	{ "req.request", STRING, 11,
-	    "VRT_r_req_request(sp)",
-	    "VRT_l_req_request(sp, ",
-	    V_RW,
-	    0,
-	    VCL_MET_RECV | VCL_MET_PIPE | VCL_MET_PASS | VCL_MET_HASH | VCL_MET_MISS | VCL_MET_HIT | VCL_MET_FETCH | VCL_MET_ERROR
+	    "VRT_r_req_request(sp)",	    "VRT_l_req_request(sp, ",
+	    V_RW,	    0,
+	    VCL_MET_RECV | VCL_MET_PIPE | VCL_MET_PASS | VCL_MET_HASH
+	     | VCL_MET_MISS | VCL_MET_HIT | VCL_MET_FETCH | VCL_MET_ERROR
 	},
 	{ "req.url", STRING, 7,
-	    "VRT_r_req_url(sp)",
-	    "VRT_l_req_url(sp, ",
-	    V_RW,
-	    0,
-	    VCL_MET_RECV | VCL_MET_PIPE | VCL_MET_PASS | VCL_MET_HASH | VCL_MET_MISS | VCL_MET_HIT | VCL_MET_FETCH | VCL_MET_ERROR
+	    "VRT_r_req_url(sp)",	    "VRT_l_req_url(sp, ",
+	    V_RW,	    0,
+	    VCL_MET_RECV | VCL_MET_PIPE | VCL_MET_PASS | VCL_MET_HASH
+	     | VCL_MET_MISS | VCL_MET_HIT | VCL_MET_FETCH | VCL_MET_ERROR
 	},
 	{ "req.proto", STRING, 9,
-	    "VRT_r_req_proto(sp)",
-	    "VRT_l_req_proto(sp, ",
-	    V_RW,
-	    0,
-	    VCL_MET_RECV | VCL_MET_PIPE | VCL_MET_PASS | VCL_MET_HASH | VCL_MET_MISS | VCL_MET_HIT | VCL_MET_FETCH | VCL_MET_ERROR
+	    "VRT_r_req_proto(sp)",	    "VRT_l_req_proto(sp, ",
+	    V_RW,	    0,
+	    VCL_MET_RECV | VCL_MET_PIPE | VCL_MET_PASS | VCL_MET_HASH
+	     | VCL_MET_MISS | VCL_MET_HIT | VCL_MET_FETCH | VCL_MET_ERROR
 	},
 	{ "req.http.", HEADER, 9,
-	    "VRT_r_req_http_(sp)",
-	    "VRT_l_req_http_(sp, ",
-	    V_RW,
-	    "HDR_REQ",
-	    VCL_MET_RECV | VCL_MET_PIPE | VCL_MET_PASS | VCL_MET_HASH | VCL_MET_MISS | VCL_MET_HIT | VCL_MET_FETCH | VCL_MET_ERROR
+	    "VRT_r_req_http_(sp)",	    "VRT_l_req_http_(sp, ",
+	    V_RW,	    "HDR_REQ",
+	    VCL_MET_RECV | VCL_MET_PIPE | VCL_MET_PASS | VCL_MET_HASH
+	     | VCL_MET_MISS | VCL_MET_HIT | VCL_MET_FETCH | VCL_MET_ERROR
 	},
 	{ "req.hash", HASH, 8,
-	    NULL,
-	    "VRT_l_req_hash(sp, ",
-	    V_WO,
-	    0,
+	    NULL,	    "VRT_l_req_hash(sp, ",
+	    V_WO,	    0,
 	    VCL_MET_HASH | VCL_MET_ERROR
 	},
 	{ "req.backend", BACKEND, 11,
-	    "VRT_r_req_backend(sp)",
-	    "VRT_l_req_backend(sp, ",
-	    V_RW,
-	    0,
-	    VCL_MET_RECV | VCL_MET_PIPE | VCL_MET_PASS | VCL_MET_HASH | VCL_MET_MISS | VCL_MET_HIT | VCL_MET_FETCH | VCL_MET_ERROR
+	    "VRT_r_req_backend(sp)",	    "VRT_l_req_backend(sp, ",
+	    V_RW,	    0,
+	    VCL_MET_RECV | VCL_MET_PIPE | VCL_MET_PASS | VCL_MET_HASH
+	     | VCL_MET_MISS | VCL_MET_HIT | VCL_MET_FETCH | VCL_MET_ERROR
 	},
 	{ "req.restarts", INT, 12,
-	    "VRT_r_req_restarts(sp)",
-	    NULL,
-	    V_RO,
-	    0,
-	    VCL_MET_RECV | VCL_MET_PIPE | VCL_MET_PASS | VCL_MET_HASH | VCL_MET_MISS | VCL_MET_HIT | VCL_MET_FETCH | VCL_MET_DELIVER | VCL_MET_ERROR
+	    "VRT_r_req_restarts(sp)",	    NULL,
+	    V_RO,	    0,
+	    VCL_MET_RECV | VCL_MET_PIPE | VCL_MET_PASS | VCL_MET_HASH
+	     | VCL_MET_MISS | VCL_MET_HIT | VCL_MET_FETCH | VCL_MET_DELIVER
+	     | VCL_MET_ERROR
 	},
 	{ "req.grace", TIME, 9,
-	    "VRT_r_req_grace(sp)",
-	    "VRT_l_req_grace(sp, ",
-	    V_RW,
-	    0,
-	    VCL_MET_RECV | VCL_MET_PIPE | VCL_MET_PASS | VCL_MET_HASH | VCL_MET_MISS | VCL_MET_HIT | VCL_MET_FETCH | VCL_MET_DELIVER | VCL_MET_ERROR
+	    "VRT_r_req_grace(sp)",	    "VRT_l_req_grace(sp, ",
+	    V_RW,	    0,
+	    VCL_MET_RECV | VCL_MET_PIPE | VCL_MET_PASS | VCL_MET_HASH
+	     | VCL_MET_MISS | VCL_MET_HIT | VCL_MET_FETCH | VCL_MET_DELIVER
+	     | VCL_MET_ERROR
 	},
 	{ "req.xid", STRING, 7,
-	    "VRT_r_req_xid(sp)",
-	    NULL,
-	    V_RO,
-	    0,
-	    VCL_MET_RECV | VCL_MET_PIPE | VCL_MET_PASS | VCL_MET_HASH | VCL_MET_MISS | VCL_MET_HIT | VCL_MET_FETCH | VCL_MET_DELIVER | VCL_MET_ERROR
+	    "VRT_r_req_xid(sp)",	    NULL,
+	    V_RO,	    0,
+	    VCL_MET_RECV | VCL_MET_PIPE | VCL_MET_PASS | VCL_MET_HASH
+	     | VCL_MET_MISS | VCL_MET_HIT | VCL_MET_FETCH | VCL_MET_DELIVER
+	     | VCL_MET_ERROR
 	},
 	{ "bereq.request", STRING, 13,
-	    "VRT_r_bereq_request(sp)",
-	    "VRT_l_bereq_request(sp, ",
-	    V_RW,
-	    0,
+	    "VRT_r_bereq_request(sp)",	    "VRT_l_bereq_request(sp, ",
+	    V_RW,	    0,
 	    VCL_MET_PIPE | VCL_MET_PASS | VCL_MET_MISS | VCL_MET_FETCH
 	},
 	{ "bereq.url", STRING, 9,
-	    "VRT_r_bereq_url(sp)",
-	    "VRT_l_bereq_url(sp, ",
-	    V_RW,
-	    0,
+	    "VRT_r_bereq_url(sp)",	    "VRT_l_bereq_url(sp, ",
+	    V_RW,	    0,
 	    VCL_MET_PIPE | VCL_MET_PASS | VCL_MET_MISS | VCL_MET_FETCH
 	},
 	{ "bereq.proto", STRING, 11,
-	    "VRT_r_bereq_proto(sp)",
-	    "VRT_l_bereq_proto(sp, ",
-	    V_RW,
-	    0,
+	    "VRT_r_bereq_proto(sp)",	    "VRT_l_bereq_proto(sp, ",
+	    V_RW,	    0,
 	    VCL_MET_PIPE | VCL_MET_PASS | VCL_MET_MISS | VCL_MET_FETCH
 	},
 	{ "bereq.http.", HEADER, 11,
-	    "VRT_r_bereq_http_(sp)",
-	    "VRT_l_bereq_http_(sp, ",
-	    V_RW,
-	    "HDR_BEREQ",
+	    "VRT_r_bereq_http_(sp)",	    "VRT_l_bereq_http_(sp, ",
+	    V_RW,	    "HDR_BEREQ",
 	    VCL_MET_PIPE | VCL_MET_PASS | VCL_MET_MISS | VCL_MET_FETCH
 	},
+	{ "bereq.connect_timeout", TIME, 21,
+	    "VRT_r_bereq_connect_timeout(sp)",	    "VRT_l_bereq_connect_timeout(sp, ",
+	    V_RW,	    0,
+	    VCL_MET_PASS | VCL_MET_MISS
+	},
+	{ "bereq.first_byte_timeout", TIME, 24,
+	    "VRT_r_bereq_first_byte_timeout(sp)",	    "VRT_l_bereq_first_byte_timeout(sp, ",
+	    V_RW,	    0,
+	    VCL_MET_PASS | VCL_MET_MISS
+	},
+	{ "bereq.between_bytes_timeout", TIME, 27,
+	    "VRT_r_bereq_between_bytes_timeout(sp)",	    "VRT_l_bereq_between_bytes_timeout(sp, ",
+	    V_RW,	    0,
+	    VCL_MET_PASS | VCL_MET_MISS
+	},
 	{ "obj.proto", STRING, 9,
-	    "VRT_r_obj_proto(sp)",
-	    "VRT_l_obj_proto(sp, ",
-	    V_RW,
-	    0,
+	    "VRT_r_obj_proto(sp)",	    "VRT_l_obj_proto(sp, ",
+	    V_RW,	    0,
 	    VCL_MET_HIT | VCL_MET_FETCH | VCL_MET_ERROR
 	},
 	{ "obj.status", INT, 10,
-	    "VRT_r_obj_status(sp)",
-	    "VRT_l_obj_status(sp, ",
-	    V_RW,
-	    0,
+	    "VRT_r_obj_status(sp)",	    "VRT_l_obj_status(sp, ",
+	    V_RW,	    0,
 	    VCL_MET_FETCH | VCL_MET_ERROR
 	},
 	{ "obj.response", STRING, 12,
-	    "VRT_r_obj_response(sp)",
-	    "VRT_l_obj_response(sp, ",
-	    V_RW,
-	    0,
+	    "VRT_r_obj_response(sp)",	    "VRT_l_obj_response(sp, ",
+	    V_RW,	    0,
 	    VCL_MET_FETCH | VCL_MET_ERROR
 	},
 	{ "obj.hits", INT, 8,
-	    "VRT_r_obj_hits(sp)",
-	    NULL,
-	    V_RO,
-	    0,
+	    "VRT_r_obj_hits(sp)",	    NULL,
+	    V_RO,	    0,
 	    VCL_MET_HIT | VCL_MET_FETCH | VCL_MET_DELIVER
 	},
 	{ "obj.http.", HEADER, 9,
-	    "VRT_r_obj_http_(sp)",
-	    "VRT_l_obj_http_(sp, ",
-	    V_RW,
-	    "HDR_OBJ",
+	    "VRT_r_obj_http_(sp)",	    "VRT_l_obj_http_(sp, ",
+	    V_RW,	    "HDR_OBJ",
 	    VCL_MET_HIT | VCL_MET_FETCH | VCL_MET_ERROR
 	},
 	{ "obj.cacheable", BOOL, 13,
-	    "VRT_r_obj_cacheable(sp)",
-	    "VRT_l_obj_cacheable(sp, ",
-	    V_RW,
-	    0,
-	    VCL_MET_HIT | VCL_MET_FETCH | VCL_MET_DISCARD | VCL_MET_TIMEOUT | VCL_MET_ERROR
+	    "VRT_r_obj_cacheable(sp)",	    "VRT_l_obj_cacheable(sp, ",
+	    V_RW,	    0,
+	    VCL_MET_HIT | VCL_MET_FETCH | VCL_MET_DISCARD | VCL_MET_TIMEOUT
+	     | VCL_MET_ERROR
 	},
 	{ "obj.ttl", TIME, 7,
-	    "VRT_r_obj_ttl(sp)",
-	    "VRT_l_obj_ttl(sp, ",
-	    V_RW,
-	    0,
-	    VCL_MET_HIT | VCL_MET_FETCH | VCL_MET_DISCARD | VCL_MET_TIMEOUT | VCL_MET_ERROR
+	    "VRT_r_obj_ttl(sp)",	    "VRT_l_obj_ttl(sp, ",
+	    V_RW,	    0,
+	    VCL_MET_HIT | VCL_MET_FETCH | VCL_MET_DISCARD | VCL_MET_TIMEOUT
+	     | VCL_MET_ERROR
 	},
 	{ "obj.grace", TIME, 9,
-	    "VRT_r_obj_grace(sp)",
-	    "VRT_l_obj_grace(sp, ",
-	    V_RW,
-	    0,
-	    VCL_MET_HIT | VCL_MET_FETCH | VCL_MET_DISCARD | VCL_MET_TIMEOUT | VCL_MET_ERROR
+	    "VRT_r_obj_grace(sp)",	    "VRT_l_obj_grace(sp, ",
+	    V_RW,	    0,
+	    VCL_MET_HIT | VCL_MET_FETCH | VCL_MET_DISCARD | VCL_MET_TIMEOUT
+	     | VCL_MET_ERROR
 	},
 	{ "obj.prefetch", RTIME, 12,
-	    "VRT_r_obj_prefetch(sp)",
-	    "VRT_l_obj_prefetch(sp, ",
-	    V_RW,
-	    0,
+	    "VRT_r_obj_prefetch(sp)",	    "VRT_l_obj_prefetch(sp, ",
+	    V_RW,	    0,
 	    VCL_MET_FETCH | VCL_MET_PREFETCH
 	},
 	{ "obj.lastuse", TIME, 11,
-	    "VRT_r_obj_lastuse(sp)",
-	    NULL,
-	    V_RO,
-	    0,
-	    VCL_MET_HIT | VCL_MET_FETCH | VCL_MET_DELIVER | VCL_MET_DISCARD | VCL_MET_TIMEOUT | VCL_MET_ERROR
+	    "VRT_r_obj_lastuse(sp)",	    NULL,
+	    V_RO,	    0,
+	    VCL_MET_HIT | VCL_MET_FETCH | VCL_MET_DELIVER | VCL_MET_DISCARD
+	     | VCL_MET_TIMEOUT | VCL_MET_ERROR
 	},
 	{ "obj.hash", STRING, 8,
-	    "VRT_r_obj_hash(sp)",
-	    NULL,
-	    V_RO,
-	    0,
-	    VCL_MET_MISS | VCL_MET_HIT | VCL_MET_FETCH | VCL_MET_DELIVER | VCL_MET_ERROR
+	    "VRT_r_obj_hash(sp)",	    NULL,
+	    V_RO,	    0,
+	    VCL_MET_MISS | VCL_MET_HIT | VCL_MET_FETCH | VCL_MET_DELIVER
+	     | VCL_MET_ERROR
 	},
 	{ "resp.proto", STRING, 10,
-	    "VRT_r_resp_proto(sp)",
-	    "VRT_l_resp_proto(sp, ",
-	    V_RW,
-	    0,
+	    "VRT_r_resp_proto(sp)",	    "VRT_l_resp_proto(sp, ",
+	    V_RW,	    0,
 	    VCL_MET_DELIVER
 	},
 	{ "resp.status", INT, 11,
-	    "VRT_r_resp_status(sp)",
-	    "VRT_l_resp_status(sp, ",
-	    V_RW,
-	    0,
+	    "VRT_r_resp_status(sp)",	    "VRT_l_resp_status(sp, ",
+	    V_RW,	    0,
 	    VCL_MET_DELIVER
 	},
 	{ "resp.response", STRING, 13,
-	    "VRT_r_resp_response(sp)",
-	    "VRT_l_resp_response(sp, ",
-	    V_RW,
-	    0,
+	    "VRT_r_resp_response(sp)",	    "VRT_l_resp_response(sp, ",
+	    V_RW,	    0,
 	    VCL_MET_DELIVER
 	},
 	{ "resp.http.", HEADER, 10,
-	    "VRT_r_resp_http_(sp)",
-	    "VRT_l_resp_http_(sp, ",
-	    V_RW,
-	    "HDR_RESP",
+	    "VRT_r_resp_http_(sp)",	    "VRT_l_resp_http_(sp, ",
+	    V_RW,	    "HDR_RESP",
 	    VCL_MET_DELIVER
 	},
 	{ "now", TIME, 3,
-	    "VRT_r_now(sp)",
-	    NULL,
-	    V_RO,
-	    0,
-	    VCL_MET_RECV | VCL_MET_PIPE | VCL_MET_PASS | VCL_MET_HASH | VCL_MET_MISS | VCL_MET_HIT | VCL_MET_FETCH | VCL_MET_DELIVER | VCL_MET_DISCARD | VCL_MET_TIMEOUT
+	    "VRT_r_now(sp)",	    NULL,
+	    V_RO,	    0,
+	    VCL_MET_RECV | VCL_MET_PIPE | VCL_MET_PASS | VCL_MET_HASH
+	     | VCL_MET_MISS | VCL_MET_HIT | VCL_MET_FETCH | VCL_MET_DELIVER
+	     | VCL_MET_DISCARD | VCL_MET_TIMEOUT
 	},
 	{ "req.backend.healthy", BOOL, 19,
-	    "VRT_r_req_backend_healthy(sp)",
-	    NULL,
-	    V_RO,
-	    0,
-	    VCL_MET_RECV | VCL_MET_PIPE | VCL_MET_PASS | VCL_MET_HASH | VCL_MET_MISS | VCL_MET_HIT | VCL_MET_FETCH | VCL_MET_DELIVER | VCL_MET_DISCARD | VCL_MET_TIMEOUT
+	    "VRT_r_req_backend_healthy(sp)",	    NULL,
+	    V_RO,	    0,
+	    VCL_MET_RECV | VCL_MET_PIPE | VCL_MET_PASS | VCL_MET_HASH
+	     | VCL_MET_MISS | VCL_MET_HIT | VCL_MET_FETCH | VCL_MET_DELIVER
+	     | VCL_MET_DISCARD | VCL_MET_TIMEOUT
 	},
 	{ NULL }
 };
diff -Nru 2.0.3/varnish-cache/lib/libvcl/vcc_parse.c trunk/varnish-cache/lib/libvcl/vcc_parse.c
--- 2.0.3/varnish-cache/lib/libvcl/vcc_parse.c	2009-01-09 15:40:07.000000000 +0100
+++ trunk/varnish-cache/lib/libvcl/vcc_parse.c	2009-01-05 14:45:26.000000000 +0100
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: vcc_parse.c 3275 2008-10-10 08:32:24Z phk $
+ * $Id: vcc_parse.c 3483 2008-12-21 16:19:14Z phk $
  */
 
 #include "config.h"
@@ -34,7 +34,6 @@
 #include <stdio.h>
 #include <string.h>
 
-#include "config.h"
 #include "vsb.h"
 
 #include "vcc_priv.h"
@@ -56,7 +55,7 @@
 
 #define C(tl, sep)	do {					\
 	Fb(tl, 1, "VRT_count(sp, %u)%s\n", ++tl->cnt, sep);	\
-	tl->t->cnt = tl->cnt; 					\
+	tl->t->cnt = tl->cnt;					\
 } while (0)
 
 /*--------------------------------------------------------------------
@@ -128,7 +127,7 @@
 static double
 RateUnit(struct tokenlist *tl)
 {
-	double sc = 1.0;
+	double sc;
 
 	assert(tl->t->tok == ID);
 	sc = SizeUnit(tl);
@@ -250,6 +249,7 @@
 	switch (tl->t->tok) {
 	case '~':
 		vcc_NextToken(tl);
+		ExpectErr(tl, CSTR);
 		p = vcc_regexp(tl, 0);
 		ERRCHK(tl);
 		vcc_NextToken(tl);
@@ -540,7 +540,7 @@
 
 	m = IsMethod(tl->t);
 	if (m != -1) {
-		assert(m < N_METHODS);
+		assert(m < VCL_MET_MAX);
 		tl->fb = tl->fm[m];
 		if (tl->mprocs[m] == NULL) {
 			tl->mprocs[m] = vcc_AddProc(tl, tl->t);
@@ -614,7 +614,7 @@
 			break;
 		case ID:
 			for (tp = toplev; tp->name != NULL; tp++) {
-				if (!vcc_IdIs(tl->t, tp->name)) 
+				if (!vcc_IdIs(tl->t, tp->name))
 					continue;
 				tp->func(tl);
 				break;
diff -Nru 2.0.3/varnish-cache/lib/libvcl/vcc_priv.h trunk/varnish-cache/lib/libvcl/vcc_priv.h
--- 2.0.3/varnish-cache/lib/libvcl/vcc_priv.h	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/lib/libvcl/vcc_priv.h	2008-11-10 09:23:00.000000000 +0100
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: vcc_priv.h 2888 2008-07-07 20:26:58Z phk $
+ * $Id: vcc_priv.h 3364 2008-11-09 14:25:22Z phk $
  *
  * Stuff shared between main.c and fixed_token.c
  */
@@ -39,8 +39,7 @@
 #define isident(c) (isalpha(c) || isdigit(c) || (c) == '_' || (c) == '-')
 #define isvar(c) (isident(c) || (c) == '.')
 unsigned vcl_fixed_token(const char *p, const char **q);
-extern const char *vcl_tnames[256];
-void vcl_init_tnames(void);
+extern const char * const vcl_tnames[256];
 void vcl_output_lang_h(struct vsb *sb);
 
 #define PF(t)	(int)((t)->e - (t)->b), (t)->b
diff -Nru 2.0.3/varnish-cache/lib/libvcl/vcc_string.c trunk/varnish-cache/lib/libvcl/vcc_string.c
--- 2.0.3/varnish-cache/lib/libvcl/vcc_string.c	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/lib/libvcl/vcc_string.c	2009-01-05 14:45:26.000000000 +0100
@@ -26,15 +26,15 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: vcc_string.c 3197 2008-09-17 10:04:47Z tfheen $
+ * $Id: vcc_string.c 3392 2008-11-14 09:48:57Z phk $
  */
 
 #include "config.h"
 
 #include <stdio.h>
 #include <string.h>
+#include <regex.h>
 
-#include "config.h"
 #include "vsb.h"
 
 #include "vcc_priv.h"
@@ -48,13 +48,22 @@
 char *
 vcc_regexp(struct tokenlist *tl, int sub)
 {
-	char buf[32], *p;
+	char buf[BUFSIZ], *p;
+	regex_t	t;
+	int i;
 
 	Expect(tl, CSTR);
-	if (VRT_re_test(tl->sb, tl->t->dec, sub)) {
+	memset(&t, 0, sizeof t);
+	i = regcomp(&t, tl->t->dec, REG_EXTENDED | (sub ? 0 : REG_NOSUB));
+	if (i != 0) {
+		(void)regerror(i, &t, buf, sizeof buf);
+		vsb_printf(tl->sb,
+		    "Regexp compilation error:\n\n%s\n\n", buf);
 		vcc_ErrWhere(tl, tl->t);
+		regfree(&t);
 		return (NULL);
 	}
+	regfree(&t);
 	sprintf(buf, "VGC_re_%u", tl->recnt++);
 	p = TlAlloc(tl, strlen(buf) + 1);
 	strcpy(p, buf);
@@ -88,7 +97,7 @@
 
 	Expect(tl, ',');
 	vcc_NextToken(tl);
-	
+
 	Expect(tl, CSTR);
 	p = vcc_regexp(tl, 1);
 	vcc_NextToken(tl);
@@ -96,7 +105,7 @@
 
 	Expect(tl, ',');
 	vcc_NextToken(tl);
-	
+
 	if (!vcc_StringVal(tl)) {
 		vcc_ExpectedStringval(tl);
 		return (0);
@@ -119,7 +128,7 @@
  */
 
 int
-vcc_StringVal(struct tokenlist *tl) 
+vcc_StringVal(struct tokenlist *tl)
 {
 	struct var *vp;
 
@@ -154,9 +163,8 @@
 			Fb(tl, 0, "VRT_backend_string(sp)");
 			break;
 		default:
-			vsb_printf(tl->sb,
-			    "String representation of '%s' not implemented yet.\n",
-				vp->name);
+			vsb_printf(tl->sb, "String representation of '%s'"
+			    " not implemented yet.\n", vp->name);
 			vcc_ErrWhere(tl, tl->t);
 			return (0);
 		}
diff -Nru 2.0.3/varnish-cache/lib/libvcl/vcc_token.c trunk/varnish-cache/lib/libvcl/vcc_token.c
--- 2.0.3/varnish-cache/lib/libvcl/vcc_token.c	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/lib/libvcl/vcc_token.c	2008-11-10 09:23:00.000000000 +0100
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: vcc_token.c 3258 2008-10-05 22:40:16Z phk $
+ * $Id: vcc_token.c 3363 2008-11-09 13:46:57Z phk $
  */
 
 #include "config.h"
@@ -36,7 +36,6 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include "config.h"
 #include "vqueue.h"
 
 #include "vsb.h"
@@ -113,7 +112,7 @@
 
 	vcc_icoord(tl->sb, t, &l);
 	vsb_printf(tl->sb, "\n");
-	
+
 	x = y = 0;
 	e = t->src->e;
 	for (p = l; p < e && *p != '\n'; p++) {
@@ -221,7 +220,7 @@
 
 	assert(t->tok == ID);
 	for (q = t->b; q < t->e; q++) {
-		if (!isalnum(*q) && *q != '_') 
+		if (!isalnum(*q) && *q != '_')
 			return (0);
 	}
 	return (1);
@@ -249,7 +248,7 @@
 static int8_t
 vcc_xdig(const char c)
 {
-	static const char *xdigit =
+	static const char * const xdigit =
 	    "0123456789abcdef"
 	    "0123456789ABCDEF";
 	const char *p;
@@ -394,7 +393,7 @@
 			vcc_ErrWhere(tl, tl->t);
 			return;
 		}
-	
+
 		/* Recognize long-strings */
 		if (*p == '{' && p[1] == '"') {
 			for (q = p + 2; q < sp->e; q++) {
@@ -406,7 +405,7 @@
 			if (q < sp->e) {
 				p = q + 2;
 				u = tl->t->e - tl->t->b;
-				u -= 4; 	/* {" ... "} */
+				u -= 4;		/* {" ... "} */
 				tl->t->dec = TlAlloc(tl, u + 1 );
 				AN(tl->t->dec);
 				memcpy(tl->t->dec, tl->t->b + 2, u);
diff -Nru 2.0.3/varnish-cache/lib/libvcl/vcc_token_defs.h trunk/varnish-cache/lib/libvcl/vcc_token_defs.h
--- 2.0.3/varnish-cache/lib/libvcl/vcc_token_defs.h	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/lib/libvcl/vcc_token_defs.h	2009-01-05 14:45:26.000000000 +0100
@@ -1,9 +1,9 @@
 /*
- * $Id: vcc_token_defs.h 2886 2008-07-07 18:21:06Z phk $
+ * $Id: vcc_token_defs.h 3483 2008-12-21 16:19:14Z phk $
  *
  * NB:  This file is machine generated, DO NOT EDIT!
  *
- * Edit vcc_gen_fixed_token.tcl instead
+ * Edit and run vcc_gen_fixed_token.tcl instead
  */
 
 #define LOW_TOKEN 128
diff -Nru 2.0.3/varnish-cache/lib/libvcl/vcc_var.c trunk/varnish-cache/lib/libvcl/vcc_var.c
--- 2.0.3/varnish-cache/lib/libvcl/vcc_var.c	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/lib/libvcl/vcc_var.c	2008-11-06 12:22:01.000000000 +0100
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: vcc_var.c 3072 2008-08-11 07:47:24Z phk $
+ * $Id: vcc_var.c 3336 2008-10-20 18:47:24Z des $
  */
 
 #include "config.h"
@@ -34,7 +34,6 @@
 #include <stdio.h>
 #include <string.h>
 
-#include "config.h"
 #include "vsb.h"
 
 #include "vcc_priv.h"
diff -Nru 2.0.3/varnish-cache/lib/libvcl/vcc_xref.c trunk/varnish-cache/lib/libvcl/vcc_xref.c
--- 2.0.3/varnish-cache/lib/libvcl/vcc_xref.c	2008-10-16 07:43:07.000000000 +0200
+++ trunk/varnish-cache/lib/libvcl/vcc_xref.c	2009-01-05 14:45:26.000000000 +0100
@@ -26,9 +26,9 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: vcc_xref.c 3072 2008-08-11 07:47:24Z phk $
+ * $Id: vcc_xref.c 3485 2008-12-21 17:03:37Z phk $
  *
- * This fine contains code for two cross-reference or consistency checks.
+ * This file contains code for two cross-reference or consistency checks.
  *
  * The first check is simply that all functions, acls and backends are
  * both defined and referenced.  Complaints about referenced but undefined
@@ -43,7 +43,6 @@
 
 #include <stdio.h>
 
-#include "config.h"
 #include "vsb.h"
 
 #include "libvarnish.h"
@@ -69,7 +68,7 @@
 	VTAILQ_HEAD(,proccall)	calls;
 	VTAILQ_HEAD(,procuse)	uses;
 	struct token		*name;
-	unsigned		returns;
+	unsigned		ret_bitmap;
 	unsigned		exists;
 	unsigned		called;
 	unsigned		active;
@@ -91,7 +90,7 @@
 		vcc_ErrToken(tl, r->name);
 		vsb_printf(tl->sb, " has unknown type %d\n",
 		    r->type);
-		return "???";
+		return "?";
 	}
 }
 
@@ -243,14 +242,15 @@
 vcc_ProcAction(struct proc *p, unsigned returns, struct token *t)
 {
 
-	p->returns |= (1U << returns);
+	assert(returns < VCL_RET_MAX);
+	p->ret_bitmap |= (1U << returns);
 	/* Record the first instance of this return */
 	if (p->return_tok[returns] == NULL)
 		p->return_tok[returns] = t;
 }
 
 static int
-vcc_CheckActionRecurse(struct tokenlist *tl, struct proc *p, unsigned returns)
+vcc_CheckActionRecurse(struct tokenlist *tl, struct proc *p, unsigned bitmap)
 {
 	unsigned u;
 	struct proccall *pc;
@@ -265,13 +265,13 @@
 		vcc_ErrWhere(tl, p->name);
 		return (1);
 	}
-	u = p->returns & ~returns;
+	u = p->ret_bitmap & ~bitmap;
 	if (u) {
 /*lint -save -e525 -e539 */
-#define VCL_RET_MAC(a, b, c, d) \
-		if (u & VCL_RET_##b) { \
-			vsb_printf(tl->sb, "Invalid return \"%s\"\n", #a); \
-			vcc_ErrWhere(tl, p->return_tok[d]); \
+#define VCL_RET_MAC(l, U) 						\
+		if (u & (1 << (VCL_RET_##U))) {				\
+			vsb_printf(tl->sb, "Invalid return \"" #l "\"\n");\
+			vcc_ErrWhere(tl, p->return_tok[VCL_RET_##U]);	\
 		}
 #include "vcl_returns.h"
 #undef VCL_RET_MAC
@@ -282,7 +282,7 @@
 	}
 	p->active = 1;
 	VTAILQ_FOREACH(pc, &p->calls, list) {
-		if (vcc_CheckActionRecurse(tl, pc->p, returns)) {
+		if (vcc_CheckActionRecurse(tl, pc->p, bitmap)) {
 			vsb_printf(tl->sb, "\n...called from \"%.*s\"\n",
 			    PF(p->name));
 			vcc_ErrWhere(tl, pc->t);
@@ -306,19 +306,17 @@
 		if (i < 0)
 			continue;
 		m = method_tab + i;
-		if (vcc_CheckActionRecurse(tl, p, m->returns)) {
+		if (vcc_CheckActionRecurse(tl, p, m->ret_bitmap)) {
 			vsb_printf(tl->sb,
 			    "\n...which is the \"%s\" method\n", m->name);
 			vsb_printf(tl->sb, "Legal returns are:");
-#define VCL_RET_MAC(a, b, c, d) \
-			if (m->returns & c) \
-				vsb_printf(tl->sb, " \"%s\"", #a);
-#define VCL_RET_MAC_E(a, b, c, d) VCL_RET_MAC(a, b, c, d)
+#define VCL_RET_MAC(l, U)						\
+			if (m->ret_bitmap & ((1 << VCL_RET_##U)))	\
+				vsb_printf(tl->sb, " \"%s\"", #l);
 /*lint -save -e525 -e539 */
 #include "vcl_returns.h"
 /*lint +e525 */
 #undef VCL_RET_MAC
-#undef VCL_RET_MAC_E
 /*lint -restore */
 			vsb_printf(tl->sb, "\n");
 			return (1);
@@ -340,13 +338,14 @@
 	struct procuse *pu;
 
 	VTAILQ_FOREACH(pu, &p->uses, list)
-		if (!(pu->v->methods & m->bitval)) 
+		if (!(pu->v->methods & m->bitval))
 			return (pu);
 	return (NULL);
 }
 
 static int
-vcc_CheckUseRecurse(struct tokenlist *tl, const struct proc *p, struct method *m)
+vcc_CheckUseRecurse(struct tokenlist *tl, const struct proc *p,
+    struct method *m)
 {
 	struct proccall *pc;
 	struct procuse *pu;
@@ -356,7 +355,7 @@
 		vsb_printf(tl->sb,
 		    "Variable \"%.*s\" is not available in %s\n",
 		    PF(pu->t), m->name);
-		vcc_ErrWhere(tl, pu->t); 
+		vcc_ErrWhere(tl, pu->t);
 		vsb_printf(tl->sb, "\n...in function \"%.*s\"\n",
 		    PF(p->name));
 		vcc_ErrWhere(tl, p->name);
diff -Nru 2.0.3/varnish-cache/lib/Makefile.in trunk/varnish-cache/lib/Makefile.in
diff -Nru 2.0.3/varnish-cache/lib/.svn/entries trunk/varnish-cache/lib/.svn/entries
diff -Nru 2.0.3/varnish-cache/Makefile.in trunk/varnish-cache/Makefile.in
diff -Nru 2.0.3/varnish-cache/man/Makefile.in trunk/varnish-cache/man/Makefile.in
diff -Nru 2.0.3/varnish-cache/man/.svn/dir-prop-base trunk/varnish-cache/man/.svn/dir-prop-base
diff -Nru 2.0.3/varnish-cache/man/.svn/entries trunk/varnish-cache/man/.svn/entries
diff -Nru 2.0.3/varnish-cache/man/.svn/text-base/vcl.7so.svn-base trunk/varnish-cache/man/.svn/text-base/vcl.7so.svn-base
diff -Nru 2.0.3/varnish-cache/man/.svn/tmp/tempfile.2.tmp trunk/varnish-cache/man/.svn/tmp/tempfile.2.tmp
diff -Nru 2.0.3/varnish-cache/man/.svn/tmp/tempfile.3.tmp trunk/varnish-cache/man/.svn/tmp/tempfile.3.tmp
diff -Nru 2.0.3/varnish-cache/man/.svn/tmp/tempfile.4.tmp trunk/varnish-cache/man/.svn/tmp/tempfile.4.tmp
diff -Nru 2.0.3/varnish-cache/man/.svn/tmp/tempfile.5.tmp trunk/varnish-cache/man/.svn/tmp/tempfile.5.tmp
diff -Nru 2.0.3/varnish-cache/man/vcl.7so trunk/varnish-cache/man/vcl.7so
--- 2.0.3/varnish-cache/man/vcl.7so	2009-01-09 15:38:51.000000000 +0100
+++ trunk/varnish-cache/man/vcl.7so	2009-01-05 14:45:28.000000000 +0100
@@ -26,7 +26,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\" $Id: vcl.7so 3271 2008-10-09 09:05:20Z ssm $
+.\" $Id: vcl.7so 3411 2008-11-20 11:01:26Z petter $
 .\"
 .Dd August 10, 2007
 .Dt VCL 7
@@ -92,6 +92,26 @@
     set req.backend = www;
 }
 .Ed
+.Pp
+The timeout parameters can be overridden in the backend declaration.
+The timeout parameters are
+.Fa .connect_timeout
+for the time to wait for a backend connection,
+.Fa .first_byte_timeout
+for the time to wait for the first byte from the backend and
+.Fa .between_bytes_timeout
+for time to wait between each received byte.
+.Pp
+These can be set in the declaration like this:
+.Bd -literal -offset 4n
+backend www {
+    .host = "www.example.com";
+    .port = "http";
+    .connect_timeout = 1s;
+    .first_byte_timeout = 5s;
+    .between_bytes_timeout = 2s;
+}
+.Ed
 .Ss Directors
 Directors choose from different backends based on health status and a
 per-director algorithm.
@@ -516,6 +536,14 @@
 .It Va bereq.http. Ns Ar header
 The corresponding HTTP
 .Ar header .
+.It Va bereq.connect_timeout
+The time in seconds to wait for a backend connection.
+.It Va bereq.first_byte_timeout
+The time in seconds to wait for the first byte from the backend.
+Not available in pipe mode.
+.It Va bereq.between_bytes_timeout
+The time in seconds to wait between each received byte from the backend.
+Not available in pipe mode.
 .El
 .Pp
 The following variables are available after the requested object has
diff -Nru 2.0.3/varnish-cache/redhat/Makefile.in trunk/varnish-cache/redhat/Makefile.in
diff -Nru 2.0.3/varnish-cache/redhat/.svn/entries trunk/varnish-cache/redhat/.svn/entries
diff -Nru 2.0.3/varnish-cache/redhat/.svn/text-base/varnish.spec.svn-base trunk/varnish-cache/redhat/.svn/text-base/varnish.spec.svn-base
diff -Nru 2.0.3/varnish-cache/redhat/.svn/tmp/tempfile.10.tmp trunk/varnish-cache/redhat/.svn/tmp/tempfile.10.tmp
diff -Nru 2.0.3/varnish-cache/redhat/.svn/tmp/tempfile.11.tmp trunk/varnish-cache/redhat/.svn/tmp/tempfile.11.tmp
diff -Nru 2.0.3/varnish-cache/redhat/.svn/tmp/tempfile.12.tmp trunk/varnish-cache/redhat/.svn/tmp/tempfile.12.tmp
diff -Nru 2.0.3/varnish-cache/redhat/.svn/tmp/tempfile.13.tmp trunk/varnish-cache/redhat/.svn/tmp/tempfile.13.tmp
diff -Nru 2.0.3/varnish-cache/redhat/.svn/tmp/tempfile.14.tmp trunk/varnish-cache/redhat/.svn/tmp/tempfile.14.tmp
diff -Nru 2.0.3/varnish-cache/redhat/.svn/tmp/tempfile.15.tmp trunk/varnish-cache/redhat/.svn/tmp/tempfile.15.tmp
diff -Nru 2.0.3/varnish-cache/redhat/.svn/tmp/tempfile.2.tmp trunk/varnish-cache/redhat/.svn/tmp/tempfile.2.tmp
diff -Nru 2.0.3/varnish-cache/redhat/.svn/tmp/tempfile.3.tmp trunk/varnish-cache/redhat/.svn/tmp/tempfile.3.tmp
diff -Nru 2.0.3/varnish-cache/redhat/.svn/tmp/tempfile.4.tmp trunk/varnish-cache/redhat/.svn/tmp/tempfile.4.tmp
diff -Nru 2.0.3/varnish-cache/redhat/.svn/tmp/tempfile.5.tmp trunk/varnish-cache/redhat/.svn/tmp/tempfile.5.tmp
diff -Nru 2.0.3/varnish-cache/redhat/.svn/tmp/tempfile.6.tmp trunk/varnish-cache/redhat/.svn/tmp/tempfile.6.tmp
diff -Nru 2.0.3/varnish-cache/redhat/.svn/tmp/tempfile.7.tmp trunk/varnish-cache/redhat/.svn/tmp/tempfile.7.tmp
diff -Nru 2.0.3/varnish-cache/redhat/.svn/tmp/tempfile.8.tmp trunk/varnish-cache/redhat/.svn/tmp/tempfile.8.tmp
diff -Nru 2.0.3/varnish-cache/redhat/.svn/tmp/tempfile.9.tmp trunk/varnish-cache/redhat/.svn/tmp/tempfile.9.tmp
diff -Nru 2.0.3/varnish-cache/redhat/varnish.spec trunk/varnish-cache/redhat/varnish.spec
--- 2.0.3/varnish-cache/redhat/varnish.spec	2009-01-09 15:40:01.000000000 +0100
+++ trunk/varnish-cache/redhat/varnish.spec	2009-01-05 14:45:26.000000000 +0100
@@ -6,6 +6,7 @@
 Group: System Environment/Daemons
 URL: http://www.varnish-cache.org/
 Source0: http://downloads.sourceforge.net/varnish/varnish-%{version}.tar.gz
+Patch0: varnish.varnishtest_debugflag.patch
 BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
 # The svn sources needs autoconf, automake and libtool to generate a suitable
 # configure script. Release tarballs would not need this
@@ -63,6 +64,8 @@
 %setup -q
 #%setup -q -n varnish-cache
 
+%patch0 -p0
+
 # The svn sources needs to generate a suitable configure script
 # Release tarballs would not need this
 #./autogen.sh
@@ -122,6 +125,13 @@
 %endif
 
 %check
+# rhel5 on ppc64 is just too strange
+%ifarch ppc64
+	%if 0%{?rhel} > 4
+		cp bin/varnishd/.libs/varnishd bin/varnishd/lt-varnishd
+	%endif
+%endif
+
 LD_LIBRARY_PATH="lib/libvarnish/.libs:lib/libvarnishcompat/.libs:lib/libvarnishapi/.libs:lib/libvcl/.libs" bin/varnishd/varnishd -b 127.0.0.1:80 -C -n /tmp/foo
 %{__make} check LD_LIBRARY_PATH="../../lib/libvarnish/.libs:../../lib/libvarnishcompat/.libs:../../lib/libvarnishapi/.libs:../../lib/libvcl/.libs"
 
@@ -237,14 +247,14 @@
 
 * Wed Oct 15 2008 Ingvar Hagelund <ingvar@linpro.no> - 2.0-1
 - 2.0 released. New upstream sources
-- Disabled jemalloc on ppc and ppc64. Added a note in README.redhat.
-- Synced to upstream again. No more patches needed.
+- Disabled jemalloc on ppc and ppc64. Added a note in README.redhat
+- Synced to upstream again. No more patches needed
 
 * Wed Oct 08 2008 Ingvar Hagelund <ingvar@linpro.no> - 2.0-0.11.rc1
 - 2.0-rc1 released. New upstream sources
 - Added a patch for pagesize to match redhat's rhel5 ppc64 koji build boxes
 - Added a patch for test a00008, from r3269
-- Removed condrestart in postscript at upgrade. We don't want that.
+- Removed condrestart in postscript at upgrade. We don't want that
 
 * Fri Sep 26 2008 Ingvar Hagelund <ingvar@linpro.no> - 2.0-0.10.beta2
 - 2.0-beta2 released. New upstream sources
diff -Nru 2.0.3/varnish-cache/.svn/entries trunk/varnish-cache/.svn/entries
diff -Nru 2.0.3/varnish-cache/.svn/text-base/autogen.des.svn-base trunk/varnish-cache/.svn/text-base/autogen.des.svn-base
diff -Nru 2.0.3/varnish-cache/.svn/text-base/configure.ac.svn-base trunk/varnish-cache/.svn/text-base/configure.ac.svn-base
diff -Nru 2.0.3/varnish-cache/.svn/tmp/tempfile.2.tmp trunk/varnish-cache/.svn/tmp/tempfile.2.tmp
diff -Nru 2.0.3/varnish-cache/.svn/tmp/tempfile.tmp trunk/varnish-cache/.svn/tmp/tempfile.tmp
diff -Nru 2.0.3/varnish-doc/en/handout/.svn/entries trunk/varnish-doc/en/handout/.svn/entries
diff -Nru 2.0.3/varnish-doc/en/inside-varnish/.svn/entries trunk/varnish-doc/en/inside-varnish/.svn/entries
diff -Nru 2.0.3/varnish-doc/en/sheets/request-processing/.svn/entries trunk/varnish-doc/en/sheets/request-processing/.svn/entries
diff -Nru 2.0.3/varnish-doc/en/sheets/.svn/entries trunk/varnish-doc/en/sheets/.svn/entries
diff -Nru 2.0.3/varnish-doc/en/.svn/entries trunk/varnish-doc/en/.svn/entries
diff -Nru 2.0.3/varnish-doc/en/varnish-architecture/.svn/entries trunk/varnish-doc/en/varnish-architecture/.svn/entries
diff -Nru 2.0.3/varnish-doc/en/varnish-getting-started/.svn/entries trunk/varnish-doc/en/varnish-getting-started/.svn/entries
diff -Nru 2.0.3/varnish-doc/en/varnish-specification/.svn/entries trunk/varnish-doc/en/varnish-specification/.svn/entries
diff -Nru 2.0.3/varnish-doc/images/.svn/entries trunk/varnish-doc/images/.svn/entries
diff -Nru 2.0.3/varnish-doc/share/.svn/entries trunk/varnish-doc/share/.svn/entries
diff -Nru 2.0.3/varnish-doc/.svn/entries trunk/varnish-doc/.svn/entries
diff -Nru 2.0.3/varnish-logo/icon/.svn/entries trunk/varnish-logo/icon/.svn/entries
diff -Nru 2.0.3/varnish-logo/logo/.svn/entries trunk/varnish-logo/logo/.svn/entries
diff -Nru 2.0.3/varnish-logo/.svn/entries trunk/varnish-logo/.svn/entries
diff -Nru 2.0.3/varnish-tools/autobuild/.svn/entries trunk/varnish-tools/autobuild/.svn/entries
diff -Nru 2.0.3/varnish-tools/emacs/.svn/entries trunk/varnish-tools/emacs/.svn/entries
diff -Nru 2.0.3/varnish-tools/fetcher/.svn/entries trunk/varnish-tools/fetcher/.svn/entries
diff -Nru 2.0.3/varnish-tools/firefox/chrome/content/.svn/entries trunk/varnish-tools/firefox/chrome/content/.svn/entries
diff -Nru 2.0.3/varnish-tools/firefox/chrome/icons/default/.svn/entries trunk/varnish-tools/firefox/chrome/icons/default/.svn/entries
diff -Nru 2.0.3/varnish-tools/firefox/chrome/icons/.svn/entries trunk/varnish-tools/firefox/chrome/icons/.svn/entries
diff -Nru 2.0.3/varnish-tools/firefox/chrome/.svn/entries trunk/varnish-tools/firefox/chrome/.svn/entries
diff -Nru 2.0.3/varnish-tools/firefox/components/.svn/entries trunk/varnish-tools/firefox/components/.svn/entries
diff -Nru 2.0.3/varnish-tools/firefox/defaults/preferences/.svn/entries trunk/varnish-tools/firefox/defaults/preferences/.svn/entries
diff -Nru 2.0.3/varnish-tools/firefox/defaults/.svn/entries trunk/varnish-tools/firefox/defaults/.svn/entries
diff -Nru 2.0.3/varnish-tools/firefox/plugins/.svn/entries trunk/varnish-tools/firefox/plugins/.svn/entries
diff -Nru 2.0.3/varnish-tools/firefox/.svn/entries trunk/varnish-tools/firefox/.svn/entries
diff -Nru 2.0.3/varnish-tools/munin/.svn/entries trunk/varnish-tools/munin/.svn/entries
diff -Nru 2.0.3/varnish-tools/nagios/.svn/entries trunk/varnish-tools/nagios/.svn/entries
diff -Nru 2.0.3/varnish-tools/regress/bin/.svn/entries trunk/varnish-tools/regress/bin/.svn/entries
diff -Nru 2.0.3/varnish-tools/regress/doc/.svn/entries trunk/varnish-tools/regress/doc/.svn/entries
diff -Nru 2.0.3/varnish-tools/regress/lib/.svn/entries trunk/varnish-tools/regress/lib/.svn/entries
diff -Nru 2.0.3/varnish-tools/regress/lib/Varnish/.svn/entries trunk/varnish-tools/regress/lib/Varnish/.svn/entries
diff -Nru 2.0.3/varnish-tools/regress/lib/Varnish/Test/Case/.svn/entries trunk/varnish-tools/regress/lib/Varnish/Test/Case/.svn/entries
diff -Nru 2.0.3/varnish-tools/regress/lib/Varnish/Test/Report/.svn/entries trunk/varnish-tools/regress/lib/Varnish/Test/Report/.svn/entries
diff -Nru 2.0.3/varnish-tools/regress/lib/Varnish/Test/Server/.svn/entries trunk/varnish-tools/regress/lib/Varnish/Test/Server/.svn/entries
diff -Nru 2.0.3/varnish-tools/regress/lib/Varnish/Test/.svn/entries trunk/varnish-tools/regress/lib/Varnish/Test/.svn/entries
diff -Nru 2.0.3/varnish-tools/regress/.svn/entries trunk/varnish-tools/regress/.svn/entries
diff -Nru 2.0.3/varnish-tools/.svn/entries trunk/varnish-tools/.svn/entries
diff -Nru 2.0.3/varnish-tools/webgui/css/.svn/entries trunk/varnish-tools/webgui/css/.svn/entries
diff -Nru 2.0.3/varnish-tools/webgui/css/.svn/format trunk/varnish-tools/webgui/css/.svn/format
diff -Nru 2.0.3/varnish-tools/webgui/css/.svn/text-base/web.css.svn-base trunk/varnish-tools/webgui/css/.svn/text-base/web.css.svn-base
diff -Nru 2.0.3/varnish-tools/webgui/css/web.css trunk/varnish-tools/webgui/css/web.css
--- 2.0.3/varnish-tools/webgui/css/web.css	1970-01-01 01:00:00.000000000 +0100
+++ trunk/varnish-tools/webgui/css/web.css	2009-01-05 14:45:25.000000000 +0100
@@ -0,0 +1,189 @@
+* {
+	padding: 0px;
+	margin: 0px;
+}
+
+a {
+	color: black;
+}
+
+body {
+	background-color: #d7d7d7;
+	padding: 10px;
+}
+
+#header {
+	background-color: #990200;
+	border-style: solid;
+	padding-bottom: 3px;
+	border-width: 0px 0px 2px 0px;
+}
+
+img#headerLogo {
+	background-color: #d7d7d7;
+}
+
+#menu {
+	padding: 5px 3px 5px 3px;
+	text-align: center;
+}
+
+a.menu {
+	color: #fff;
+	padding-right: 20px;
+}
+
+#error {
+	font-size: 1.1em;
+	padding: 5px;
+	border-width: 3px;
+	border-style: solid;
+	border-color: #6c0000;
+	background-color: #a21616;
+	margin-bottom: 10px;
+}
+
+#content {
+	background-color: #f2f2f2;	
+	padding: 10px;
+}
+
+td.header {
+	font-weight: bold;
+	border-style: solid;
+	border-width: 0px 0px 1px 0px;
+}
+
+td.footer {
+	font-size: 0.7em;
+	padding-top: 10px;
+	border-style: solid;
+	border-width: 1px 0px 0px 0px;
+}
+
+
+table#parameters {
+	padding: 2px;
+}
+
+td.parameterLabel {
+	padding: 0px 5px 0px 5px;
+}
+
+td.parameterValue {
+	padding: 0px 5px 0px 5px;
+	text-align: right;
+}
+
+td.parameterUnit {
+	font-style: italic;
+	padding: 0px 5px 0px 5px;
+}
+
+td.parameterDescription {
+	padding: 0px 5px 0px 5px;
+}
+
+td.parameterEdit {
+	padding: 0px 5px 0px 5px;
+	text-align: center;
+}
+
+tr.evenRow {
+	background-color:#fff;
+	vertical-align: top;
+}
+
+tr.oddRow {
+	background-color:#eee;
+	vertical-align: top;
+}
+
+textarea#vclEditor {
+	margin: 5px 0px 10px 0px;
+}
+
+span.tab {
+	padding: 0px 10px 0px 10px;
+	width: 10em;
+	background-color: #ddd;
+	border-style: solid;
+	border-width: 1px 1px 1px 1px;
+}	
+
+span.selectedTab {
+	padding: 1px 10px 1px 10px;
+	border-style: solid;
+	background-color: #fff;
+	border-width: 1px 1px 0px 1px;
+}	
+
+span.space {
+	border-style: solid;
+	border-width: 0 0 1px 0;
+}
+
+div.tabArea {
+	background-color: #fff;
+	padding: 5px;
+	border-style: solid;
+	border-width: 0px 1px 1px 1px;
+}
+
+table#statsTable {
+	background-color: #fff;
+	border-style: solid;
+	border-width: 1px;
+}
+
+option {
+	padding-right: 10px;
+}
+
+#groupControls {
+	padding-top: 30px;
+}
+
+td {
+	padding: 1px 2px 1px 2px;
+}
+
+textarea#vclConfig {
+	font-size: 1.1em;
+	border-style: solid;
+	border-width: 2px;
+	border-color: #990200;
+	padding: 2px 0 0 5px;
+}
+
+#themeSelection {
+	padding: 3px;
+}
+
+li.consoleSetting {
+	margin-left: 30px;
+	margin-top: 10px;
+}
+
+input.removeNode {
+	margin-left: 50px;
+}
+
+#status {
+	border-color: #2e6c00;
+	border-style: solid;
+	border-width: 3px;
+	background-color: #419a00;
+	padding: 5px;
+	margin-bottom: 10px;
+}
+
+#vclError {
+	font-family: monospace;
+	font-size: 1.1em;
+	border-color: black;
+	border-style: solid;
+	border-width: 3px;
+	background-color: red;
+	padding: 5px;
+}
Binary files 2.0.3/varnish-tools/webgui/images/favicon.png and trunk/varnish-tools/webgui/images/favicon.png differ
Binary files 2.0.3/varnish-tools/webgui/images/nograph.png and trunk/varnish-tools/webgui/images/nograph.png differ
Binary files 2.0.3/varnish-tools/webgui/images/running_nok.png and trunk/varnish-tools/webgui/images/running_nok.png differ
Binary files 2.0.3/varnish-tools/webgui/images/running.png and trunk/varnish-tools/webgui/images/running.png differ
Binary files 2.0.3/varnish-tools/webgui/images/stopped.png and trunk/varnish-tools/webgui/images/stopped.png differ
diff -Nru 2.0.3/varnish-tools/webgui/images/.svn/entries trunk/varnish-tools/webgui/images/.svn/entries
diff -Nru 2.0.3/varnish-tools/webgui/images/.svn/format trunk/varnish-tools/webgui/images/.svn/format
diff -Nru 2.0.3/varnish-tools/webgui/images/.svn/prop-base/favicon.png.svn-base trunk/varnish-tools/webgui/images/.svn/prop-base/favicon.png.svn-base
diff -Nru 2.0.3/varnish-tools/webgui/images/.svn/prop-base/nograph.png.svn-base trunk/varnish-tools/webgui/images/.svn/prop-base/nograph.png.svn-base
diff -Nru 2.0.3/varnish-tools/webgui/images/.svn/prop-base/running_nok.png.svn-base trunk/varnish-tools/webgui/images/.svn/prop-base/running_nok.png.svn-base
diff -Nru 2.0.3/varnish-tools/webgui/images/.svn/prop-base/running.png.svn-base trunk/varnish-tools/webgui/images/.svn/prop-base/running.png.svn-base
diff -Nru 2.0.3/varnish-tools/webgui/images/.svn/prop-base/stopped.png.svn-base trunk/varnish-tools/webgui/images/.svn/prop-base/stopped.png.svn-base
diff -Nru 2.0.3/varnish-tools/webgui/images/.svn/prop-base/varnish-logo-christmas.png.svn-base trunk/varnish-tools/webgui/images/.svn/prop-base/varnish-logo-christmas.png.svn-base
diff -Nru 2.0.3/varnish-tools/webgui/images/.svn/prop-base/varnish-logo.png.svn-base trunk/varnish-tools/webgui/images/.svn/prop-base/varnish-logo.png.svn-base
Binary files 2.0.3/varnish-tools/webgui/images/.svn/text-base/favicon.png.svn-base and trunk/varnish-tools/webgui/images/.svn/text-base/favicon.png.svn-base differ
Binary files 2.0.3/varnish-tools/webgui/images/.svn/text-base/nograph.png.svn-base and trunk/varnish-tools/webgui/images/.svn/text-base/nograph.png.svn-base differ
Binary files 2.0.3/varnish-tools/webgui/images/.svn/text-base/running_nok.png.svn-base and trunk/varnish-tools/webgui/images/.svn/text-base/running_nok.png.svn-base differ
Binary files 2.0.3/varnish-tools/webgui/images/.svn/text-base/running.png.svn-base and trunk/varnish-tools/webgui/images/.svn/text-base/running.png.svn-base differ
Binary files 2.0.3/varnish-tools/webgui/images/.svn/text-base/stopped.png.svn-base and trunk/varnish-tools/webgui/images/.svn/text-base/stopped.png.svn-base differ
Binary files 2.0.3/varnish-tools/webgui/images/.svn/text-base/varnish-logo-christmas.png.svn-base and trunk/varnish-tools/webgui/images/.svn/text-base/varnish-logo-christmas.png.svn-base differ
Binary files 2.0.3/varnish-tools/webgui/images/.svn/text-base/varnish-logo.png.svn-base and trunk/varnish-tools/webgui/images/.svn/text-base/varnish-logo.png.svn-base differ
Binary files 2.0.3/varnish-tools/webgui/images/varnish-logo-christmas.png and trunk/varnish-tools/webgui/images/varnish-logo-christmas.png differ
Binary files 2.0.3/varnish-tools/webgui/images/varnish-logo.png and trunk/varnish-tools/webgui/images/varnish-logo.png differ
diff -Nru 2.0.3/varnish-tools/webgui/README trunk/varnish-tools/webgui/README
--- 2.0.3/varnish-tools/webgui/README	1970-01-01 01:00:00.000000000 +0100
+++ trunk/varnish-tools/webgui/README	2009-01-05 14:45:25.000000000 +0100
@@ -0,0 +1,107 @@
+Web GUI for Varnish, very limited christmas edition
+===================================================
+
+This is a preview of the upcoming web GUI for Varnish, which will be released with version 2.1 It has most of the features intended for the final version, but a number of things are still missing, so it is just inteded to get feedback. The following known things are _not_ implemented
+ - saving of state: if the web server goes down, the information is lost.
+ - smart data collection: it stores ALL the polled data with the given poll intervlal. It does not truncate data used for the hour, day, week and month graph. So eventually you will go out of memory. 
+ - simple configuration: currently, you must edit the start.pl script by hand to set the configuration, and edit Varnish/RequestHandler.pl to add graphs and summary statistics. 
+ - security: there is no form for access control or security implemented.
+
+So I wouldn't use it for anything with 'prod' in its name, but as a preview of what is to come. It should be noted that when adding nodes to an existing group, all the parameters and VCL of that node are replaced with the default parameters and VCL of the group. So if you add more nodes to a group, be aware of this.
+
+Any feedback is most welcome, so just post it to varnish-misc@projects.linpro.no.
+
+So what can you actually do with this thing?
+
+
+Overview
+--------
+
+The web GUI is written in Perl and runs in its own server container, so a web server is not required, only the necessary Perl modules. The GUI consists of five sections: 'View stats', 'Configure parameters', 'Edit VCL', 'Node management' and 'Management console'. As the names might suggest, the GUI let you
+
+- view statistics from the Varnish nodes
+- configure the parameters of the Varnish nodes and clusters
+- edit the VCL for each cluster, which will be shared between all the nodes
+- perform node management, like adding clusters and nodes, get the state of the nodes and backend healths
+- get access to the management console of each node
+
+Requirements
+------------
+
+The web GUI is written in Perl, and uses some modules that might not be installed by default:
+
+- HTTP::Daemon (libwww-perl)
+- HTML::Template (libhtml-template-perl)
+- GD::Graph (libgd-graph-perl) 
+- LWP::UserAgent (libwww-perl)
+
+The name in the paranthesis are the package name on a standard Ubuntu system. The rest of the modules should be pretty standard.
+
+As the management port of the Varnish instances are used for collecting data, this must be enaled when starting varnish. This is done with the -T option to varnish, e.g. like this
+
+$ /opt/varnish/sbin/varnishd -a :80 -b :8080 -T :9003
+
+Configuration
+-------------
+
+The configuration is done directly in the Perl code for this very limited christmas edition, but will be more userfriendly in the final version. As this version doesn't save your state, e.g. the nodes and clusters added, I would recommend adding this in the start.pl. The files needing customisation are
+
+- start.pl: early in the file you'll see '# Configuration starts here', and this is where to set the config. It is all commented, so should be fairly straight forward.
+- Varnish/RequestHandler.pl: this is the main enging of the whole web GUI, including the parts creating the summary stats and graphs. This is well documented in the code, so look at line 380 for adding values to the summary statistics and 826 for adding custom graphs (and removing the dummy 'Missing graph').
+
+That is configuration for this version. Remember that when creating and editing VCLs, the information is stored on the node, so if the web server is restarted, the nodes will still have the VCLs (unless they are restarted too, of course).
+
+Starting it
+-----------
+
+'perl start.pl' shoud do it, after reading the Configuration section and setting the values to something reasonable for your setup. If the shebang matches your perl, and the script is executable, './start.pl' should also do it.
+
+The GUI
+======
+
+View stats
+----------
+
+In 'View stats' you will see statistics gathered from the nodes. The 'Summary statistics' is/will be customisable (see Configuration) and shows the most important statistics. If you want to see all the statistics from the Varnish nodes you turn 'Raw statistics' on. If you want the page to be refreshed automatically in order to follow the graph 'live', you can turn 'Auto refresh' on. The refresh rate is the same as the rate the statistics are collected from the nodes.
+
+Configure parameters
+--------------------
+
+'Configure' parameters let you configure the parameters for a group (cluster) or a single node. For this version, the parameters for the groups are a copy of the parameters of the first node added to the group, so if a group has not been populated, it will not contain any values. Changing a value in a group will change the same value of all the nodes in that group. Changing a value for node only changes that node, naturally. 
+
+Edit VCL
+--------
+
+'Edit VCL' lets you edit the VCL of the group, and any changes made here will be reflected on all the nodes of the group. You can add, edit, save and discard VCLs as well as making a VCL active. It discards without warning (isn't baby safe yet), so be carefull.
+
+A note about the editor: it is a simple text are, with <tab> giving you an indent as expected. If you save a VCL with error, the errors are listed and you can click on the 'Line X Pos Y' information in the error list to jump to that position in the editor.
+
+
+Node management
+---------------
+
+From 'Node management' you can manage groups and nodes. It will let you add, remove, stop and start the nodes and groups. It also displays information about the state of the node:
+ - the V column is the state of Varnish. Green means it responds with a 200 message to a probe (it probes http://varnish-host/), a yellow light means it anwers with a non-200 status code and a red light means it does not respond at all.
+ - the M columns is the state of the management port, with green meaning OK and red meaning it is not reachable. As almost all functionality is dependent on the management port, it should never have a red light.
+
+ If a health probe is defined in the VCL, a list of backend healths for the running VCL is shown as well.
+
+ Since this version does not let you save the configuration, it is recommended that you add groups and nodes in the stat.pl file as explained in Configuration.
+
+ WARNING: as noted earlier, adding nodes to a group will replace that nodes parameter and VCL.
+
+Management console
+------------------
+
+'Management console' gives you access to the management console of each node. The input field has magical tab completion for the CLI commands and a command history accessable by arrow up/down. In addition to the standard CLI commands, 'cls' can be issued to clear the console.
+
+The color and size of the console can be changed, but this information is unfortunately not stored when switching nodes.
+
+
+Road ahead
+==========
+
+This is a sneak preview of the web GUI for 2.1, and as such is not complete. It is mostly feature complete (minus things mentioned in the start of this file), so any comments on what is working, what is lacking etc. is most appreciated. Please use the varnish-misc@projects.linpro.no mailing list for discussion.
+
+
+Merry christmas!
diff -Nru 2.0.3/varnish-tools/webgui/start.pl trunk/varnish-tools/webgui/start.pl
--- 2.0.3/varnish-tools/webgui/start.pl	1970-01-01 01:00:00.000000000 +0100
+++ trunk/varnish-tools/webgui/start.pl	2009-01-05 14:45:25.000000000 +0100
@@ -0,0 +1,138 @@
+#!/usr/bin/perl
+use threads;
+use strict;
+use warnings;
+use HTTP::Daemon;
+use HTTP::Status;
+use HTTP::Request;
+use LWP::UserAgent;
+use Varnish::Util;
+use Varnish::RequestHandler;
+use Varnish::NodeManager;
+use Varnish::Node;
+use Varnish::Statistics;
+
+
+# Configuration starts here
+my %config = (
+# 'address' is the IP to bind to. If not set, it listens on all.
+#	address				=> localhost,
+
+# 'port' is the port of the web server
+	port				=> 8000,
+
+# 'poll_intervall' is the polling interval for the statistics
+	poll_interval		=> 5,
+);
+
+# create some default groups 
+my @groups = qw(default images);
+
+# create some default nodes 
+my @node_params = (
+	{
+		name 			=> 'varnish-1',
+		address			=> 'localhost',
+		port			=> '80',
+		group			=> 'default',
+		management_port	=> 9001,
+	},
+	{
+		name 			=> 'varnish-2',
+		address			=> 'localhost',
+		port			=> '8181',
+		group			=> 'default',
+		management_port	=> 9002,
+	},
+	{
+		name 			=> 'varnish-1',
+		address			=> 'localhost',
+		port			=> '8888',
+		group			=> 'images',
+		management_port	=> 9003,
+	},
+);
+
+# End of configuration
+
+set_config(\%config);
+
+for my $group (@groups) {
+	Varnish::NodeManager->add_group($group);
+}
+
+for my $node_param_ref (@node_params) {
+	my $group_exists =	grep {
+							$_ eq $node_param_ref->{'group'}
+						} @groups;
+	if ($group_exists) {
+		my $node = Varnish::Node->new($node_param_ref);
+		Varnish::NodeManager->add_node($node);
+	}
+	else {
+		print "Node " . $node_param_ref->{'name'} . " has an invalid group "
+				. $node_param_ref->{'group'} . ". Skipping.";
+	}
+}
+
+# catch interupt to stop the daemon
+$SIG{'INT'} = sub {
+	print "Interrupt detected.\n";
+};
+
+# ignore the occational sigpipe
+$SIG{'PIPE'} = sub { 
+#	print "Pipe ignored\n";
+};
+
+my $daemon = HTTP::Daemon->new(	LocalPort => $config{'port'}, 
+								LocalAddr => $config{'address'},
+								ReuseAddr => 1 ) || die "Could not start web server";
+print "Web server started with URL: " . $daemon->url, "\n";
+my $data_collector_handle = threads->create('data_collector_thread');
+while (my $connection = $daemon->accept) {
+	REQUEST:
+	while (my $request = $connection->get_request) {
+		$connection->force_last_request;
+		if ($request->uri =~ m{/(.*?\.png)} ||
+			$request->uri =~ m{/(.*?\.css)} ||
+			$request->uri =~ m{/(.*?\.ico)}) {
+			my $filename = $1;
+			
+			$connection->send_file($filename);
+			next REQUEST;
+		}
+		
+		my $request_handler = Varnish::RequestHandler->new(\$request, $connection);
+		$request_handler->process();
+
+		my $response = HTTP::Response->new(200);
+		$response->header( $request_handler->get_response_header() );
+		$response->content( $request_handler->get_response_content() );
+		$connection->send_response($response);
+	}
+	$connection->close();
+	undef($connection);
+}
+print "Shutting down!\n";
+$daemon->close();
+Varnish::NodeManager->quit();
+print "Stopping data collector thread\n";
+$data_collector_handle->join();
+
+sub data_collector_thread {
+	my $url = $daemon->url . "collect_data";
+	my $interval = $config{'poll_interval'};
+	print "Data collector thread started. Polling URL $url at $interval seconds interval\n";
+
+	sleep 1; # wait for the server to come up
+	while (1) {
+		my $user_agent = LWP::UserAgent->new;
+		$user_agent->timeout(6);
+		my $response = $user_agent->get($url);
+			
+		last if ($response->code eq "500");
+		sleep $interval;
+	}
+	print "Data collector thread stopped.\n";
+}
diff -Nru 2.0.3/varnish-tools/webgui/.svn/entries trunk/varnish-tools/webgui/.svn/entries
diff -Nru 2.0.3/varnish-tools/webgui/.svn/format trunk/varnish-tools/webgui/.svn/format
diff -Nru 2.0.3/varnish-tools/webgui/.svn/prop-base/start.pl.svn-base trunk/varnish-tools/webgui/.svn/prop-base/start.pl.svn-base
diff -Nru 2.0.3/varnish-tools/webgui/.svn/text-base/README.svn-base trunk/varnish-tools/webgui/.svn/text-base/README.svn-base
diff -Nru 2.0.3/varnish-tools/webgui/.svn/text-base/start.pl.svn-base trunk/varnish-tools/webgui/.svn/text-base/start.pl.svn-base
diff -Nru 2.0.3/varnish-tools/webgui/templates/configure_parameters.tmpl trunk/varnish-tools/webgui/templates/configure_parameters.tmpl
--- 2.0.3/varnish-tools/webgui/templates/configure_parameters.tmpl	1970-01-01 01:00:00.000000000 +0100
+++ trunk/varnish-tools/webgui/templates/configure_parameters.tmpl	2009-01-05 14:45:25.000000000 +0100
@@ -0,0 +1,89 @@
+<script type="text/javascript">
+function toggleHelp(sectionId) {
+
+	var sectionStyle = document.getElementById(sectionId).style;
+	if (sectionStyle.display == "none") {
+		sectionStyle.display = "block";
+	}
+	else {
+		sectionStyle.display = "none";
+	}
+}
+</script>
+
+<TMPL_IF NAME=UNIT_INFOS>
+<form action="configure_parameters" method="POST">
+<div class="tabHeader">
+<TMPL_LOOP NAME=UNIT_INFOS>
+<TMPL_IF NAME=SELECTED>
+<span class="selectedTab">
+<TMPL_IF NAME=IS_NODE>
+<input type="hidden" name="node_id" value="<TMPL_VAR NAME=ID>"/>
+<TMPL_ELSE>
+<input type="hidden" name="group" value="<TMPL_VAR NAME=ID>"/>
+</TMPL_IF>
+<TMPL_ELSE>
+<span class="tab">
+</TMPL_IF>
+<TMPL_IF NAME=IS_NODE>
+<a href="configure_parameters?node_id=<TMPL_VAR NAME=ID>"><TMPL_VAR NAME=NAME> (node)</a>
+<TMPL_ELSE>
+<a href="configure_parameters?group=<TMPL_VAR NAME=ID>"><TMPL_VAR NAME=NAME> (group)</a>
+</TMPL_IF>
+</span>
+</TMPL_LOOP>
+</div>
+<div class="tabArea">
+<table id="parameters">
+<tr><td class="header">Name</td><td class="header">Value</td><td class="header">Unit</td><td class="header"></td></tr>
+<TMPL_LOOP NAME=PARAMETER_INFOS>
+<TMPL_IF NAME=ODD_ROW>
+<tr class="oddRow">
+<TMPL_ELSE>
+<tr class="evenRow">
+</TMPL_IF>
+<td class="parameterLabel"><TMPL_VAR NAME=NAME></td>
+<td class="parameterValue">
+<TMPL_IF NAME=IS_BOOLEAN>
+<select name="new_<TMPL_VAR NAME=NAME>">
+<TMPL_IF NAME=VALUE>
+<option value="on" selected>on</option>
+<option value="off">off</option>
+<TMPL_ELSE>
+<option value="on">on</option>
+<option value="off" selected>off</option>
+</TMPL_IF>
+</select>
+<TMPL_ELSE>
+<input type="text" name="new_<TMPL_VAR NAME=NAME>" value="<TMPL_VAR NAME=VALUE>"/>
+</TMPL_IF>
+
+<TMPL_IF NAME=IS_BOOLEAN>
+<TMPL_IF NAME=VALUE>
+<input type="hidden" name="old_<TMPL_VAR NAME=NAME>" value="on"/>
+<TMPL_ELSE>
+<input type="hidden" name="old_<TMPL_VAR NAME=NAME>" value="off"/>
+</TMPL_IF>
+<TMPL_ELSE>
+<input type="hidden" name="old_<TMPL_VAR NAME=NAME>" value="<TMPL_VAR NAME=VALUE>"/>
+</TMPL_IF>
+
+</td>
+<td class="parameterUnit"><TMPL_VAR NAME=UNIT></td>
+<td class="parameterDescription">
+<a href="javascript:toggleHelp('<TMPL_VAR NAME=NAME>');">?</a>
+<div id="<TMPL_VAR NAME=NAME>" style="display: none">
+<TMPL_VAR NAME=DESCRIPTION>
+</div>
+</td>
+</tr>
+</TMPL_LOOP>
+<tr><td class="footer" colspan="4">
+<input type="submit" value="Update"/>
+</td></tr>
+</form>
+</table>
+</div>
+<TMPL_ELSE>
+No nodes available
+</TMPL_IF>
diff -Nru 2.0.3/varnish-tools/webgui/templates/edit_vcl.tmpl trunk/varnish-tools/webgui/templates/edit_vcl.tmpl
--- 2.0.3/varnish-tools/webgui/templates/edit_vcl.tmpl	1970-01-01 01:00:00.000000000 +0100
+++ trunk/varnish-tools/webgui/templates/edit_vcl.tmpl	2009-01-05 14:45:25.000000000 +0100
@@ -0,0 +1,182 @@
+<script type="text/javascript">
+
+// The following is lended from http://www.webdeveloper.com/forum/archive/index.php/t-74982.html in a post by m2c
+/*
+** Returns the caret (cursor) position of the specified text field.
+** Return value range is 0-oField.length.
+*/
+function getCaretPosition (oField) {
+	// Initialize
+	var iCaretPos = 0;
+	// IE Support
+	if (document.selection) {
+		// Set focus on the element
+		oField.focus ();
+		// To get cursor position, get empty selection range
+		var oSel = document.selection.createRange ();
+		// Move selection start to 0 position
+		oSel.moveStart ('character', -oField.value.length);
+		// The caret position is selection length
+		iCaretPos = oSel.text.length;
+	}
+	// Firefox support
+	else if (oField.selectionStart || oField.selectionStart == '0')
+		iCaretPos = oField.selectionStart;
+	// Return results
+	return (iCaretPos);
+}
+
+/*
+ ** Sets the caret (cursor) position of the specified text field.
+ ** Valid positions are 0-oField.length.
+ */
+function setCaretPosition (oField, iCaretPos) {
+	// IE Support
+	if (document.selection) {
+		// Set focus on the element
+		oField.focus ();
+		// Create empty selection range
+		var oSel = document.selection.createRange ();
+		// Move selection start and end to 0 position
+		oSel.moveStart ('character', -oField.value.length);
+		// Move selection start and end to desired position
+		oSel.moveStart ('character', iCaretPos);
+		oSel.moveEnd ('character', 0);
+		oSel.select ();
+	}
+	// Firefox support
+	else if (oField.selectionStart || oField.selectionStart == '0') {
+		oField.selectionStart = iCaretPos;
+		oField.selectionEnd = iCaretPos;
+		oField.focus ();
+	}
+}
+// End of code lending
+
+
+var indentString = "    ";
+
+function onEditorKeyDown(e) {
+	var keyCode = (window.Event) ? e.which : e.keyCode;
+	var charCode = e.charCode;
+	var editor = document.getElementById('editor');
+	var currentPosition = getCaretPosition(editor);
+
+// trap the tab
+	if (keyCode == 9) {
+		var indent = indentString;
+		var newValue = editor.value.substring(0, currentPosition) + indent
+						+ editor.value.substring(currentPosition);
+		editor.value = newValue;
+		setCaretPosition(editor, currentPosition + indent.length);
+		return false;
+	}
+	
+	return true;
+}
+
+function showNewEntry() {
+	document.getElementById('newVclCell').style['display'] = 'block';
+	document.getElementById('newVclEntry').focus();
+}
+
+function onNewVclEntryDown(e, form) {
+	var keyCode = (window.Event) ? e.which : e.keyCode;
+
+	if (keyCode == 13) {
+		form.operation.value = 'new';
+		form.submit();
+	}
+}
+
+function goToPosition(row, column) {
+	var editor = document.getElementById('editor');
+	var text = editor.value;
+	var pos = 0;
+	
+	while (row > 1) {
+		if (text.charAt(pos) == '\n')
+			row--;
+		pos++;
+	}
+
+	pos += column -1;
+	setCaretPosition(editor, pos);
+}
+
+</script>
+<TMPL_IF NAME=GROUP_INFOS>
+<div class="tabArea">
+<div class="tabHeader">
+<TMPL_LOOP NAME=GROUP_INFOS>
+<TMPL_IF NAME=SELECTED>
+<span class="selectedTab">
+<TMPL_ELSE>
+<span class="tab">
+</TMPL_IF>
+<a href="edit_vcl?group_name=<TMPL_VAR NAME=NAME>"><TMPL_VAR NAME=NAME></a>
+</span>
+</TMPL_LOOP>
+</div>
+<form action="edit_vcl" method="POST">
+<textarea cols=80 rows=30 onkeydown="return onEditorKeyDown(event);" id="editor" name="vcl"><TMPL_VAR NAME=VCL></textarea>
+<br/>
+<table>
+<tr>
+<td>
+<input type="button" onclick="showNewEntry();" value="New"/>
+</td>
+<td id="newVclCell" style="display: none;">
+<input type="text" name="new_vcl_name" id="newVclEntry" onkeydown="onNewVclEntryDown(event, this.form)"> 
+<input type="button" onclick="this.form.operation.value='new'; this.form.submit();" value="OK">
+</td>
+<td>
+|
+<select name="vcl_name">
+<TMPL_LOOP NAME=VCL_INFOS>
+<option 
+<TMPL_IF NAME=SELECTED>
+selected 
+</TMPL_IF>
+value="<TMPL_VAR NAME=NAME>"><TMPL_VAR NAME=NAME> 
+<TMPL_IF NAME=ACTIVE>
+(active)
+</TMPL_IF>
+</option>
+</TMPL_LOOP>
+</select>
+</td>
+<td>
+<input type="hidden" value="load" name="operation"/>
+<input type="submit" value="Load"/>
+<TMPL_IF NAME=EDITING_NEW_VCL>
+<input type="button" disabled value="Make active"/>
+<TMPL_ELSE>
+<input type="button" onclick="this.form.operation.value='make_active'; this.form.submit();" value="Make active"/>
+</TMPL_IF>
+<TMPL_LOOP NAME=GROUP_INFOS>
+<TMPL_IF NAME=SELECTED>
+<input type="hidden" name="group_name" value="<TMPL_VAR NAME=NAME>"/>
+</TMPL_IF>
+</TMPL_LOOP>
+<input type="button" onclick="this.form.operation.value='save'; this.form.submit();" value="Save"/>
+| <input type="button" onclick="this.form.operation.value='discard'; this.form.submit();" value="Discard"/>
+</td>
+</tr>
+</table>
+</form>
+<TMPL_IF NAME=EDITING_NEW_VCL>
+<script type="text/javascript">
+document.getElementById('editor').focus();
+</script>
+</TMPL_IF>
+<TMPL_IF NAME=VCL_ERROR>
+<b>Errors found in the VCL:</b>
+<div id="vclError">
+<TMPL_VAR NAME=VCL_ERROR>
+</div>
+</TMPL_IF>
+</div>
+<TMPL_ELSE>
+No groups available
+</TMPL_IF>
diff -Nru 2.0.3/varnish-tools/webgui/templates/management_console.tmpl trunk/varnish-tools/webgui/templates/management_console.tmpl
--- 2.0.3/varnish-tools/webgui/templates/management_console.tmpl	1970-01-01 01:00:00.000000000 +0100
+++ trunk/varnish-tools/webgui/templates/management_console.tmpl	2009-01-05 14:45:25.000000000 +0100
@@ -0,0 +1,248 @@
+<script type="text/javascript">
+<TMPL_LOOP NAME=NODE_INFOS>
+<TMPL_IF NAME=SELECTED>
+var currentNodeId = <TMPL_VAR NAME=ID>;
+</TMPL_IF>
+</TMPL_LOOP>
+
+var commandHistoryMaxSize = 10;
+var commandHistoryIndex = 0;
+var commandHistorySize = 1;
+var commandHistory = new Array(10);
+
+var lastMatchIndex = -1;
+var lastPartialCommand;
+var managementCommands = [
+	"help",
+	"param.set",
+	"param.show", 
+	"ping",
+	"purge.hash",
+	"purge.list",
+	"purge.url",
+	"quit",
+	"start",
+	"stats",
+	"status",
+	"stop",
+	"vcl.discard",
+	"vcl.inline",
+	"vcl.list",
+	"vcl.load",
+	"vcl.show",
+	"vcl.use"
+	];
+
+function consolePrint(text) {
+	var console = document.getElementById('console');
+	console.value += text + "\n";
+	console.scrollTop = console.scrollHeight;
+}
+
+// taken from http://www.jibbering.com/2002/4/httprequest.html
+function doHttpRequest(url) {
+	var xmlhttp=false;
+	/*@cc_on @*/
+	/*@if (@_jscript_version >= 5)
+	// JScript gives us Conditional compilation, we can cope with old IE versions.
+	// and security blocked creation of the objects.
+	try {
+	xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
+	} catch (e) {
+	try {
+	xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
+	} catch (E) {
+	xmlhttp = false;
+	}
+	}
+	@end @*/
+	if (!xmlhttp && typeof XMLHttpRequest!='undefined') {
+		try {
+			xmlhttp = new XMLHttpRequest();
+		} catch (e) {
+			xmlhttp=false;
+		}
+	}
+	if (!xmlhttp && window.createRequest) {
+		try {
+			xmlhttp = window.createRequest();
+		} catch (e) {
+			xmlhttp=false;
+		}
+	}
+	xmlhttp.open("GET", url, true);
+	xmlhttp.onreadystatechange=function() {
+		if (xmlhttp.readyState == 4)
+			consolePrint(xmlhttp.responseText);
+	}
+	xmlhttp.send(null)
+}
+
+function runCommand(command) {
+	if (command == "cls")
+		document.getElementById('console').value = "";
+	else {
+		consolePrint(command);
+		var url = "http://<TMPL_VAR NAME=SERVER_HOST>:<TMPL_VAR NAME=SERVER_PORT>/send_management_command?node_id=" + escape(currentNodeId) + "&command=" + escape(command);
+		doHttpRequest(url);
+	}
+}
+
+function onInputKeyDown(e) {
+	var keyCode = (window.Event) ? e.which : e.keyCode;
+
+	if (keyCode == 13) {
+		var input = document.getElementById('input');
+		runCommand(input.value);
+		commandHistory[0] = input.value;
+
+		if (commandHistorySize < commandHistoryMaxSize)
+			commandHistorySize++;
+		for (var i = commandHistorySize - 1; i > 0; i--)
+			commandHistory[i] = commandHistory[i-1];
+		commandHistory[0] = input.value = "";
+		commandHistoryIndex = 0;
+	}
+	else if (keyCode == 9) {
+		var firstMatchIndex = -1;
+		var matchIndex = -1;
+		var partialCommandPattern = new RegExp("^" + lastPartialCommand);
+		for (var i = 0; i < managementCommands.length; i++) {
+			if (managementCommands[i].match(partialCommandPattern)) {
+				if (i > lastMatchIndex) {
+					matchIndex = i;
+					break;
+				}
+				
+				if (firstMatchIndex == -1)
+					firstMatchIndex = i;
+			}
+		}
+		
+		if (firstMatchIndex != -1 && matchIndex == -1 )
+			matchIndex = firstMatchIndex;
+
+		if (matchIndex != -1) {
+			lastMatchIndex = matchIndex;
+			document.getElementById('input').value = managementCommands[matchIndex];
+		}
+
+		// trap tab from escaping the input field
+		return false;
+	}
+	else if (keyCode == 38) {
+		
+		if (commandHistoryIndex + 1 < commandHistorySize) {
+			commandHistoryIndex++;
+			document.getElementById('input').value = commandHistory[commandHistoryIndex];
+		}
+
+		return false;
+	}
+	else if (keyCode == 40) {
+
+		if (commandHistoryIndex > 0 ) {
+			commandHistoryIndex--;
+			document.getElementById('input').value = commandHistory[commandHistoryIndex];
+		}
+
+		return false;
+	}
+
+}
+
+function onInputKeyUp(e) {
+	var keyCode = (window.Event) ? e.which : e.keyCode;
+	var inputValue = document.getElementById('input').value;
+
+	if (keyCode != 10 && keyCode != 9)
+		lastPartialCommand = inputValue;
+	if (keyCode != 38 && keyCode != 40)
+		commandHistory[0] = inputValue; 
+}
+
+function setConsoleColors(foreground, background) {
+	var console = document.getElementById('console');
+	var input = document.getElementById('input');
+	console.style['color'] = foreground;
+	console.style['backgroundColor'] = background;
+	input.style['color'] = foreground;
+	input.style['backgroundColor'] = background;
+
+	document.getElementById('input').focus();
+}
+
+function adjustConsoleSettings() {
+	var console = document.getElementById('console');
+	console.rows = document.getElementById('consoleRows').value;
+	console.cols = document.getElementById('consoleCols').value;
+}
+</script>
+
+<TMPL_IF NAME=NODE_INFOS>
+<div class="tabHeader">
+<TMPL_LOOP NAME=NODE_INFOS>
+<TMPL_IF NAME=SELECTED>
+<span class="selectedTab">
+<TMPL_ELSE>
+<span class="tab">
+</TMPL_IF>
+<a href="management_console?node_id=<TMPL_VAR NAME=ID>"><TMPL_VAR NAME=NAME></a>
+</span>
+</TMPL_LOOP>
+</div>
+<div class="tabArea">
+<textarea id="console" cols="<TMPL_VAR NAME=DEFAULT_CONSOLE_COLS>" rows="<TMPL_VAR NAME=DEFAULT_CONSOLE_ROWS>" style="font-size: <TMPL_VAR NAME=DEFAULT_CONSOLE_FONT_SIZE>;" readonly>
+ 
+                           oooo$$$$$$$$$$$$oooo
+                       oo$$$$$$$$$$$$$$$$$$$$$$$$o
+                    oo$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$o         o$   $$ o$
+    o $ oo        o$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$o       $$ $$ $$o$
+ oo $ $ "$      o$$$$$$$$$    $$$$$$$$$$$$$    $$$$$$$$$o       $$$o$$o$
+ "$$$$$$o$     o$$$$$$$$$      $$$$$$$$$$$      $$$$$$$$$$o    $$$$$$$$
+   $$$$$$$    $$$$$$$$$$$      $$$$$$$$$$$      $$$$$$$$$$$$$$$$$$$$$$$
+   $$$$$$$$$$$$$$$$$$$$$$$    $$$$$$$$$$$$$    $$$$$$$$$$$$$$  """$$$
+    "$$$""""$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$     "$$$
+     $$$   o$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$     "$$$o
+    o$$"   $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$       $$$o
+    $$$    $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$" "$$$$$$ooooo$$$$o
+   o$$$oooo$$$$$  $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$   o$$$$$$$$$$$$$$$$$
+   $$$$$$$$"$$$$   $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$     $$$$""""""""
+  """"       $$$$    "$$$$$$$$$$$$$$$$$$$$$$$$$$$$"      o$$$
+             "$$$o     """$$$$$$$$$$$$$$$$$$"$$"         $$$
+               $$$o          "$$""$$$$$$""""           o$$$    Welcome to the
+                $$$$o                                o$$$"
+                 "$$$$o      o$$$$$$o"$$$$o        o$$$$          Varnish
+                   "$$$$$oo     ""$$$$o$$$$$o   o$$$$""
+                      ""$$$$$oooo  "$$$o$$$$$$$$$"""         management console
+                         ""$$$$$$$oo $$$$$$$$$$
+                                 """"$$$$$$$$$$$                    for
+                                     $$$$$$$$$$$$
+                                      $$$$$$$$$$"             <TMPL_VAR NAME=CURRENT_NODE_NAME>
+                                       "$$$""""
+</textarea><br/>
+&gt;<input size="60" type="text" id="input" onkeydown="return onInputKeyDown(event);" onkeyup="onInputKeyUp(event);"/>
+<br/>
+Console settings:
+<ul>
+<li class="consoleSetting">
+Color theme: 
+<TMPL_LOOP NAME=CONSOLE_THEMES>
+<a style="font-size: <TMPL_VAR NAME=DEFAULT_CONSOLE_FONT_SIZE>; margin-left: 3px; padding: 5px; background-color: <TMPL_VAR NAME=BACKGROUND>; color: <TMPL_VAR NAME=FOREGROUND>;"
+	href="javascript:setConsoleColors('<TMPL_VAR NAME=FOREGROUND>', '<TMPL_VAR NAME=BACKGROUND>')">
+<TMPL_VAR NAME=NAME>
+</a>
+</TMPL_LOOP>
+</li>
+<li class="consoleSetting">Size: 
+<input type="text" id="consoleCols" value="<TMPL_VAR NAME=DEFAULT_CONSOLE_COLS>" onchange="adjustConsoleSettings();"> x 
+ <input type="text" id="consoleRows" value="<TMPL_VAR NAME=DEFAULT_CONSOLE_ROWS>" onchange="adjustConsoleSettings();">
+ </li>
+</div>
+<script type="text/javascript">
+document.getElementById('input').focus();
+setConsoleColors('<TMPL_VAR NAME=DEFAULT_CONSOLE_FOREGROUND>', '<TMPL_VAR NAME=DEFAULT_CONSOLE_BACKGROUND>');
+</script>
+<TMPL_ELSE>
+No nodes to manage.
+</TMPL_IF>
diff -Nru 2.0.3/varnish-tools/webgui/templates/master.tmpl trunk/varnish-tools/webgui/templates/master.tmpl
--- 2.0.3/varnish-tools/webgui/templates/master.tmpl	1970-01-01 01:00:00.000000000 +0100
+++ trunk/varnish-tools/webgui/templates/master.tmpl	2009-01-05 14:45:25.000000000 +0100
@@ -0,0 +1,43 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<link rel="stylesheet" type="text/css" href="css/web.css" />
+<link rel="icon" type="image/png" href="/images/favicon.png">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+<TMPL_IF NAME=AUTO_REFRESH_INTERVAL>
+<meta http-equiv="refresh" content="<TMPL_VAR NAME=AUTO_REFRESH_INTERVAL>">
+</TMPL_IF>
+<title>Varnish - Lust controller christmas edition</title>
+</head>
+<body>
+<div id="canvas">
+<div id="header">
+<img id="headerLogo" src="images/varnish-logo-christmas.png" id="logo"/>
+<span id="menu">
+<a href="/view_stats" class="menu">View stats</a>
+<a href="/configure_parameters" class="menu">Configure parameters</a>
+<a href="/edit_vcl" class="menu">Edit VCL</a>
+<a href="/node_management" class="menu">Node management</a>
+<a href="/management_console" class="menu">Management console</a>
+</span>
+</div>
+<div id="content">
+<TMPL_IF NAME=ERROR>
+<div id="error">
+An error occured:<br/>
+<pre>
+<TMPL_VAR NAME=ERROR>
+</pre>
+</div>
+</TMPL_IF>
+<TMPL_IF NAME=STATUS>
+<div id="status">
+<TMPL_VAR NAME=STATUS>
+</div>
+</TMPL_IF>
+<TMPL_INCLUDE NAME=templates/CONTENT_TEMPLATE>
+</div>
+</div>
+</body>
+</html>
Binary files 2.0.3/varnish-tools/webgui/templates/.master.tmpl.swp and trunk/varnish-tools/webgui/templates/.master.tmpl.swp differ
diff -Nru 2.0.3/varnish-tools/webgui/templates/node_management.tmpl trunk/varnish-tools/webgui/templates/node_management.tmpl
--- 2.0.3/varnish-tools/webgui/templates/node_management.tmpl	1970-01-01 01:00:00.000000000 +0100
+++ trunk/varnish-tools/webgui/templates/node_management.tmpl	2009-01-05 14:45:25.000000000 +0100
@@ -0,0 +1,138 @@
+<div class="tabHeader">
+<TMPL_LOOP NAME=GROUP_INFOS>
+<TMPL_IF NAME=SELECTED>
+<span class="selectedTab">
+<TMPL_ELSE>
+<span class="tab">
+</TMPL_IF>
+<a href="node_management?group=<TMPL_VAR NAME=NAME>"><TMPL_VAR NAME=NAME></a>
+</span>
+</TMPL_LOOP>
+<TMPL_IF NAME=ADD_GROUP>
+<span class="selectedTab">
+<TMPL_ELSE>
+<span class="tab">
+</TMPL_IF>
+<a href="node_management?operation=add_group">Add..</a>
+</span>
+</div>
+<div class="tabArea">
+<TMPL_IF NAME=ADD_GROUP>
+<form action="node_management" method="post">
+<input type="hidden" name="operation" value="add_group"/>
+<table>
+<tr><td>Name:</td><td><input name="group"/></td></tr>
+<tr><td><input type="submit" value="Add"/></td></tr>
+</table>
+<TMPL_ELSE>
+<table>
+<tr>
+<td class="header">V</td>
+<td class="header">M</td>
+<td class="header">Name</td>
+<td class="header">Address</td>
+<td class="header">Port</td>
+<td class="header">Management port</td>
+<td></td></tr>
+<TMPL_LOOP NAME=NODE_INFOS>
+<tr>
+<td>
+<TMPL_IF NAME=IS_RUNNING_OK>
+<img src="images/running.png"/>
+<TMPL_ELSE>
+<TMPL_IF NAME=IS_RUNNING>
+<img src="images/running_nok.png"/>
+<TMPL_ELSE>
+<img src="images/stopped.png"/>
+</TMPL_IF>
+</TMPL_IF>
+</td>
+<td>
+<TMPL_IF NAME=IS_MANAGEMENT_RUNNING>
+<img src="images/running.png"/>
+<TMPL_ELSE>
+<img src="images/stopped.png"/>
+</TMPL_IF>
+</td>
+<td><TMPL_VAR NAME=NAME></td>
+<td><TMPL_VAR NAME=ADDRESS></td>
+<td><TMPL_VAR NAME=PORT></td>
+<td><TMPL_VAR NAME=MANAGEMENT_PORT></td>
+<td>
+<form action="node_management" method="POST">
+<input type="hidden" name="node_id" value="<TMPL_VAR NAME=ID>">
+<input type="hidden" name="operation" value="start_node">
+<input type="submit" value="Start">
+</form>
+</td>
+<td>
+<form action="node_management" method="POST">
+<input type="hidden" name="node_id" value="<TMPL_VAR NAME=ID>">
+<input type="hidden" name="operation" value="stop_node">
+<input type="submit" value="Stop">
+</form>
+</td>
+<td>
+<form action="node_management" method="POST">
+<input type="hidden" name="node_id" value="<TMPL_VAR NAME=ID>">
+<input type="hidden" name="operation" value="remove_node">
+<input type="submit" value="Remove" class="removeNode">
+</form>
+</td>
+</tr>
+</TMPL_LOOP>
+</td>
+<tr>
+<form action="node_management" method="post">
+<input type="hidden" name="operation" value="add_node"/>
+<td></td>
+<td></td>
+<td><input type="text" name="name"/></td>
+<td><input type="text" name="address"/></td>
+<td><input type="text" name="port"/></td>
+<td><input type="text" name="management_port" value="<TMPL_VAR NAME=DEFAULT_MANAGEMENT_PORT>"/></td>
+<td>
+<input type="hidden" name="group" value="<TMPL_VAR NAME=GROUP>"/>
+<input type="submit" value="Add"/></td>
+</tr>
+</form>
+</table>
+<TMPL_IF NAME=BACKEND_HEALTH_INFOS>
+<table>
+<tr><td class="header">Backend</td><td class="header">Health</td></tr>
+<TMPL_LOOP NAME=BACKEND_HEALTH_INFOS>
+<tr><td><TMPL_VAR NAME=NAME></td><td><TMPL_VAR NAME=HEALTH></td></tr>
+</TMPL_LOOP>
+</table>
+<TMPL_ELSE>
+<i>No backend health information available</i>
+</TMPL_IF>
+<div id="groupControls">
+<table>
+<tr>
+<td>
+<form action="node_management" method="POST">
+<input type="hidden" name="group" value="<TMPL_VAR NAME=GROUP>">
+<input type="hidden" name="operation" value="start_group">
+<input type="submit" value="Start group">
+</form>
+</td>
+<td>
+<form action="node_management" method="POST">
+<input type="hidden" name="group" value="<TMPL_VAR NAME=GROUP>">
+<input type="hidden" name="operation" value="stop_group">
+<input type="submit" value="Stop group">
+</form>
+</td>
+<td>
+<form action="node_management" method="POST">
+<input type="hidden" name="group" value="<TMPL_VAR NAME=GROUP>">
+<input type="hidden" name="operation" value="remove_group">
+<input type="submit" value="Remove group" class="removeNode">
+</form>
+</td>
+</tr>
+</table>
+</div>
+</TMPL_IF>
+</div>
diff -Nru 2.0.3/varnish-tools/webgui/templates/.svn/entries trunk/varnish-tools/webgui/templates/.svn/entries
diff -Nru 2.0.3/varnish-tools/webgui/templates/.svn/format trunk/varnish-tools/webgui/templates/.svn/format
diff -Nru 2.0.3/varnish-tools/webgui/templates/.svn/prop-base/.master.tmpl.swp.svn-base trunk/varnish-tools/webgui/templates/.svn/prop-base/.master.tmpl.swp.svn-base
diff -Nru 2.0.3/varnish-tools/webgui/templates/.svn/text-base/configure_parameters.tmpl.svn-base trunk/varnish-tools/webgui/templates/.svn/text-base/configure_parameters.tmpl.svn-base
diff -Nru 2.0.3/varnish-tools/webgui/templates/.svn/text-base/edit_vcl.tmpl.svn-base trunk/varnish-tools/webgui/templates/.svn/text-base/edit_vcl.tmpl.svn-base
diff -Nru 2.0.3/varnish-tools/webgui/templates/.svn/text-base/management_console.tmpl.svn-base trunk/varnish-tools/webgui/templates/.svn/text-base/management_console.tmpl.svn-base
diff -Nru 2.0.3/varnish-tools/webgui/templates/.svn/text-base/master.tmpl.svn-base trunk/varnish-tools/webgui/templates/.svn/text-base/master.tmpl.svn-base
Binary files 2.0.3/varnish-tools/webgui/templates/.svn/text-base/.master.tmpl.swp.svn-base and trunk/varnish-tools/webgui/templates/.svn/text-base/.master.tmpl.swp.svn-base differ
diff -Nru 2.0.3/varnish-tools/webgui/templates/.svn/text-base/node_management.tmpl.svn-base trunk/varnish-tools/webgui/templates/.svn/text-base/node_management.tmpl.svn-base
diff -Nru 2.0.3/varnish-tools/webgui/templates/.svn/text-base/view_stats.tmpl.svn-base trunk/varnish-tools/webgui/templates/.svn/text-base/view_stats.tmpl.svn-base
diff -Nru 2.0.3/varnish-tools/webgui/templates/view_stats.tmpl trunk/varnish-tools/webgui/templates/view_stats.tmpl
--- 2.0.3/varnish-tools/webgui/templates/view_stats.tmpl	1970-01-01 01:00:00.000000000 +0100
+++ trunk/varnish-tools/webgui/templates/view_stats.tmpl	2009-01-05 14:45:25.000000000 +0100
@@ -0,0 +1,99 @@
+<script type="text/javascript">
+
+function loadGraph(nodeId, graphId, timeSpan) {
+	var id= "img_" + nodeId + "_" + graphId;
+	var graphUrl = "/generate_graph?time_span=" + timeSpan + "&node_id=" + nodeId + "&type=" + graphId;
+
+	var graphImage = document.getElementById(id);
+	if (graphImage) 
+		graphImage.src = graphUrl;
+}
+
+</script>
+
+<TMPL_IF NAME=NODE_INFOS>
+<h2> 
+<TMPL_IF NAME=STAT_TIME>
+Statistics collected at <TMPL_VAR NAME=STAT_TIME>
+<TMPL_IF NAME=AUTO_REFRESH>
+<span style="font-size:0.5em">(auto-refreshing)</span>
+</TMPL_IF>
+<TMPL_ELSE>
+No statistics yet collected
+</TMPL_IF>
+</h2>
+<table id="statsTable">
+<tr>
+<td> 
+<h2>Summary</h2>
+</td>
+</tr>
+<tr class="header">
+<td></td>
+<TMPL_LOOP NAME=NODE_INFOS>
+<td><TMPL_VAR NAME=NAME></td>
+</TMPL_LOOP>
+</tr>
+<tr>
+<td>
+<TMPL_LOOP NAME=SUMMARY_STATS>
+<TMPL_IF NAME=ODD_ROW>
+<tr class="oddRow">
+<TMPL_ELSE>
+<tr class="evenRow">
+</TMPL_IF>
+<td><TMPL_VAR NAME=NAME></td>
+<TMPL_LOOP NAME=VALUES>
+<td>
+<TMPL_IF NAME=IS_GRAPH>
+<div class="graph">
+<img id="img_<TMPL_VAR NAME=NODE_ID>_<TMPL_VAR NAME=GRAPH_ID>" src=""/><br/>
+Last: 
+<a class="timeSpan" id="link_<TMPL_VAR NAME=NODE_ID>_<TMPL_VAR NAME=GRAPH_ID>" href="javascript:loadGraph('<TMPL_VAR NAME=NODE_ID>', '<TMPL_VAR NAME=GRAPH_ID>', 'minute')">Mi</a>
+<a class="timeSpan" id="link_<TMPL_VAR NAME=NODE_ID>_<TMPL_VAR NAME=GRAPH_ID>_hour" href="javascript:loadGraph('<TMPL_VAR NAME=NODE_ID>', '<TMPL_VAR NAME=GRAPH_ID>', 'hour')">H</a>
+<a class="timeSpan" id="link_<TMPL_VAR NAME=NODE_ID>_<TMPL_VAR NAME=GRAPH_ID>_hour" href="javascript:loadGraph('<TMPL_VAR NAME=NODE_ID>', '<TMPL_VAR NAME=GRAPH_ID>', 'day')">D</a>
+<a class="timeSpan" id="link_<TMPL_VAR NAME=NODE_ID>_<TMPL_VAR NAME=GRAPH_ID>_hour" href="javascript:loadGraph('<TMPL_VAR NAME=NODE_ID>', '<TMPL_VAR NAME=GRAPH_ID>', 'week')">W</a>
+<a class="timeSpan" id="link_<TMPL_VAR NAME=NODE_ID>_<TMPL_VAR NAME=GRAPH_ID>_hour" href="javascript:loadGraph('<TMPL_VAR NAME=NODE_ID>', '<TMPL_VAR NAME=GRAPH_ID>', 'month')">Mo</a>
+</div>
+<script type="text/javascript">
+loadGraph('<TMPL_VAR NAME=NODE_ID>', '<TMPL_VAR NAME=GRAPH_ID>', 'minute');
+</script>
+<TMPL_ELSE>
+<TMPL_VAR NAME=VALUE>
+</TMPL_IF>
+</td>
+</TMPL_LOOP>
+<tr>
+</TMPL_LOOP>
+<TMPL_IF NAME=VIEW_RAW_STATS>
+<tr><td><h2>Raw statistics</h2>
+</td></tr>
+<tr>
+<td>
+<TMPL_LOOP NAME=RAW_STATS>
+<TMPL_IF NAME=ODD_ROW>
+<tr class="oddRow">
+<TMPL_ELSE>
+<tr class="evenRow">
+</TMPL_IF>
+<td><TMPL_VAR NAME=NAME></td>
+<TMPL_LOOP NAME=VALUES>
+<td><TMPL_VAR NAME=VALUE></td>
+</TMPL_LOOP>
+</tr>
+</TMPL_LOOP>
+</table>
+Raw statistics: On <a href="/view_stats?view_raw_stats=0&auto_refresh=<TMPL_VAR NAME=AUTO_REFRESH>">Off</a>
+<TMPL_ELSE>
+</table>
+Raw statistics: <a href="/view_stats?view_raw_stats=1&auto_refresh=<TMPL_VAR NAME=AUTO_REFRESH>">On</a> Off
+</TMPL_IF>
+| Auto refresh: 
+<TMPL_IF NAME=AUTO_REFRESH>
+On <a href="/view_stats?view_raw_stats=<TMPL_VAR NAME=VIEW_RAW_STATS>&auto_refresh=0">Off</a>
+<TMPL_ELSE>
+<a href="/view_stats?view_raw_stats=<TMPL_VAR NAME=VIEW_RAW_STATS>&auto_refresh=1">On</a> Off
+</TMPL_IF>
+<TMPL_ELSE>
+No nodes available
+</TMPL_IF>
diff -Nru 2.0.3/varnish-tools/webgui/test/.svn/entries trunk/varnish-tools/webgui/test/.svn/entries
diff -Nru 2.0.3/varnish-tools/webgui/test/.svn/format trunk/varnish-tools/webgui/test/.svn/format
diff -Nru 2.0.3/varnish-tools/webgui/test/.svn/text-base/test_management.pl.svn-base trunk/varnish-tools/webgui/test/.svn/text-base/test_management.pl.svn-base
diff -Nru 2.0.3/varnish-tools/webgui/test/test_management.pl trunk/varnish-tools/webgui/test/test_management.pl
--- 2.0.3/varnish-tools/webgui/test/test_management.pl	1970-01-01 01:00:00.000000000 +0100
+++ trunk/varnish-tools/webgui/test/test_management.pl	2009-01-05 14:45:25.000000000 +0100
@@ -0,0 +1,41 @@
+use strict;
+use warnings;
+use Varnish::Management;
+
+my $console = Varnish::Management->new("localhost", "9001");
+
+my $status = $console->set_config("testing", "backend b0 { .host = \"localhost\"; .port = \"8080\"; }");
+
+if ($status ne "") {
+	print "Error:\n$status\n";
+}
+
+for my $config ($console->get_config_names()) {
+	print "Config: $config\n";
+	print "-" x 80 . "\n";
+	print $console->get_config($config) . "\n";
+}
+
+
+my %stats_counter = $console->get_stats();
+while (my ($stat, $value) = each %stats_counter) {
+	print "$stat = $value\n";
+}
+
+if ($console->ping()) {
+	print "I am alive!\n";
+}
+else {
+	print "I am dead: " . $console->get_error() . "\n";
+}
+
+my $console2 = Varnish::Management->new("localhost", "9002");
+
+
+if ($console2->ping()) {
+	print "I am alive!\n";
+}
+else {
+	print "I am dead: " . $console2->get_error() . "\n";
+}
+
diff -Nru 2.0.3/varnish-tools/webgui/Varnish/Management.pm trunk/varnish-tools/webgui/Varnish/Management.pm
--- 2.0.3/varnish-tools/webgui/Varnish/Management.pm	1970-01-01 01:00:00.000000000 +0100
+++ trunk/varnish-tools/webgui/Varnish/Management.pm	2009-01-05 14:45:25.000000000 +0100
@@ -0,0 +1,286 @@
+package Varnish::Management;
+
+use strict;
+use IO::Socket::INET;
+use Exporter;
+use List::Util qw(first);
+
+{
+	my %hostname_of;
+	my %port_of;
+	my %error_of;
+	my %socket_of;
+
+	sub new {
+		my ($class, $hostname, $port) = @_;
+
+		my $new_object = bless \do{ my $anon_scalar; }, $class;
+
+		$hostname_of{$new_object} = $hostname;
+		$port_of{$new_object} = $port;
+		$error_of{$new_object} = "";
+
+		return $new_object;
+	}
+
+	sub _send_command {
+		my ($self, $command) = @_;
+
+		if (!$socket_of{$self} || !$socket_of{$self}->connected ) {
+			my $socket = new IO::Socket::INET->new(
+					PeerPort => $port_of{$self},
+					Proto	 => 'tcp',
+					PeerAddr => $hostname_of{$self}
+					);
+			return ("666", "Could not connect to node") if (!$socket);
+			$socket_of{$self} = $socket;
+		}
+		my $socket = $socket_of{$self};
+		
+		print $socket "$command\n";
+		my ($status_code, $response_size) = <$socket> =~ m/^(\d+) (\d+)/;
+		my $response;
+		my $remaining_bytes = $response_size;
+		while ($remaining_bytes > 0 ) {
+			my $data;
+			my $read = read $socket, $data, $remaining_bytes;
+			$response .= $data;
+			$remaining_bytes -= $read;
+		}
+		my $eat_newline = <$socket>;
+		return ($status_code, $response);
+	}
+
+	sub send_command {
+		my ($self, $command) = @_;
+	
+		my ($status_code, $response) = _send_command($self, $command);
+
+		return no_error($self, $response) if $status_code eq "200";
+		return set_error($self, $response);
+	}
+
+	sub get_parameters {
+		my ($self) = @_;
+
+		my %param;
+		my $current_param;
+
+		my ($status_code, $response) = _send_command($self, "param.show -l");
+		return set_error($self, $response) if ($status_code ne "200");
+		for my $line (split( '\n', $response)) {
+
+			if ($line =~ /^(\w+)\s+(\w+) (.*)$/) {
+				my %param_info = (
+						value 	=> $2,
+						unit	=> $3
+						);
+
+				$current_param = $1;
+				$param{$1} = \%param_info;
+			}
+			elsif ($line =~ /^\s+(.+)$/) {
+# The first comment line contains no . and describes the default value.
+				if (!$param{$current_param}->{'description'}) {
+					$param{$current_param}->{'description'} = "$1. ";
+				}
+				else  {
+					$param{$current_param}->{'description'} .= "$1 ";
+				}
+			}
+		}
+
+		return \%param;
+	}
+
+	sub get_parameter($) {
+		my ($self, $parameter) = @_;
+
+		my ($status_code, $response) = _send_command($self, "param.show $parameter");
+
+		return no_error($self, $1) if ($response =~ /^(?:\w+)\s+(\w+)/);
+		return set_error($self, $response);
+	}
+
+	sub set_parameter {
+		my ($self, $parameter, $value) = @_;
+
+		my ($status_code, $response) = _send_command($self, "param.set $parameter $value");
+
+		return no_error($self) if ($status_code eq "200");
+		return set_error($self, $response);
+	}
+
+	sub get_vcl_names {
+		my ($self) = @_;
+
+		my ($status_code, $response) = _send_command($self, "vcl.list");
+		return set_error($self, $response) if ($status_code ne "200");
+
+		my @vcl_infos = ($response =~ /^(\w+)\s+\d+\s+(\w+)$/gm);
+		my $vcl_names_ref = [];
+		my $active_vcl_name = "";
+		while (my ($status, $name) = splice @vcl_infos, 0, 2) {
+			next if ($status eq "discarded");
+
+			if ($status eq "active") {
+				$active_vcl_name = $name;
+			}
+			push @$vcl_names_ref, $name;
+		}
+
+		unshift @$vcl_names_ref, $active_vcl_name;
+		return no_error($self, $vcl_names_ref) if ($status_code eq "200");
+	}
+	
+	sub get_vcl {
+		my ($self, $vcl_name) = @_;
+
+		my ($status_code, $response) = _send_command($self, "vcl.show $vcl_name");
+
+		return no_error($self, $response) if ($status_code eq "200");
+		return set_error($self, $response);
+	}
+
+	sub set_vcl {
+		my ($self, $vcl_name, $vcl) = @_;
+		$vcl =~ s/"/\\"/g;
+		$vcl =~ s/\r//g;
+		$vcl =~ s/\n/\\n/g;
+
+		my $need_restart = 0;
+		my ($active_vcl_name, @vcl_names) = @{get_vcl_names($self)};
+		my $editing_active_vcl = $vcl_name eq $active_vcl_name;
+
+		# try to compile the new vcl
+		my ($status_code, $response) = _send_command($self, "vcl.inline _new_vcl \"$vcl\"");
+		if ($status_code ne "200") {
+			_send_command($self, "vcl.discard _new_vcl");
+			return set_error($self, $response);
+		}
+
+		if ($editing_active_vcl) {
+			($status_code, $response) = _send_command($self, "vcl.use _new_vcl");
+		}
+
+		if (grep { $_ eq $vcl_name } @vcl_names) {
+			($status_code, $response) = _send_command($self, "vcl.discard $vcl_name");
+			if ($status_code ne "200") {
+				_send_command($self, "vcl.use $vcl_name");
+				_send_command($self, "vcl.discard _new_vcl");
+				return set_error($self, $response);
+			}
+		}
+		($status_code, $response) = _send_command($self, "vcl.inline $vcl_name \"$vcl\"");
+
+		if ($editing_active_vcl) {
+			($status_code, $response) = _send_command($self, "vcl.use $vcl_name");
+		}
+		_send_command($self, "vcl.discard _new_vcl");
+
+		return no_error($self) if ($status_code eq "200");
+		return set_error($self, $response);
+	}
+
+	sub discard_vcl {
+		my ($self, $vcl_name) = @_;
+
+		my ($status_code, $response) = _send_command($self, "vcl.discard $vcl_name");
+
+		return no_error($self) if ($status_code eq "200");
+		return set_error($self, $response);
+	}
+
+	sub make_vcl_active {
+		my ($self, $vcl_name) = @_;
+
+		my ($status_code, $response) = _send_command($self, "vcl.use $vcl_name");
+
+		return no_error($self) if ($status_code eq "200");
+		return set_error($self, $response);
+	}
+
+	sub get_stats {
+		my ($self) = @_;
+
+		my ($status_code, $response) = _send_command($self, "stats");
+
+		my %stat_counter = map {
+								/^\s*(\d+)\s+(.*?)$/;
+								$2 => $1
+							} split /\n/, $response;
+
+		return no_error($self, \%stat_counter) if ($status_code eq "200");
+		return set_error($self, $response);
+	}
+
+	sub ping {
+		my ($self) = @_;
+
+		my ($status_code, $response) = _send_command($self, "stats");
+
+		return no_error($self) if ($status_code eq "200");
+		return set_error($self, $response);
+	}
+
+	sub start {
+		my ($self) = @_;
+
+		my ($status_code, $response) = _send_command($self, "start");
+
+		return no_error($self) if ($status_code eq "200");
+		return set_error($self, $response);
+	}
+
+	sub stop {
+		my ($self) = @_;
+
+		my ($status_code, $response) = _send_command($self, "stop");
+
+		return no_error($self) if ($status_code eq "200");
+		return set_error($self, $response);
+	}
+
+	sub set_error {
+		my ($self, $error) = @_;
+
+		$error_of{$self} = $error;
+
+		return;
+	}
+
+	sub get_error {
+		my ($self) = @_;
+
+		return $error_of{$self};
+	}
+
+	sub no_error {
+		my ($self, $return_value) = @_;
+
+		$error_of{$self} = "";
+
+		return defined($return_value) ? $return_value : 1;
+	}
+
+	sub close {
+		my ($self) = @_;
+
+		if ($socket_of{$self} && $socket_of{$self}->connected) {
+			$socket_of{$self}->close();
+		}
+	}
+
+	sub get_backend_health {
+		my ($self) = @_;
+
+		my ($status_code, $response) = _send_command($self, "debug.health");
+		return set_error($self, $response) if ($status_code ne "200");
+		
+		my %backend_health = ($response =~ /^Backend (\w+) is (\w+)$/gm);
+
+		return no_error($self, \%backend_health);
+	}
+}
+
+1;
diff -Nru 2.0.3/varnish-tools/webgui/Varnish/NodeManager.pm trunk/varnish-tools/webgui/Varnish/NodeManager.pm
--- 2.0.3/varnish-tools/webgui/Varnish/NodeManager.pm	1970-01-01 01:00:00.000000000 +0100
+++ trunk/varnish-tools/webgui/Varnish/NodeManager.pm	2009-01-05 14:45:25.000000000 +0100
@@ -0,0 +1,221 @@
+package Varnish::NodeManager;
+use strict;
+use warnings;
+use Varnish::Node;
+use List::Util qw(first);
+
+{
+	my @groups = ();
+	my @nodes = ();
+	my %group_parameters = ();
+
+	my $error = "";
+
+	sub add_node {
+		my ($self, $node) = @_;
+
+		my $group = $node->get_group();
+		if (! grep { $_->get_group eq $group } @nodes ) {
+			$node->set_master(1);
+			my %node_parameters = %{$node->get_management()->get_parameters()};
+			while (my ($parameter, $value) = each %node_parameters) {
+				$group_parameters{$group}->{$parameter} = $value;
+			}
+		}
+		else {
+# inherit the VCL and the parameters of the group
+			my %group_parameters = %{$group_parameters{$group}};
+			my $management = $node->get_management();
+			while (my ($parameter, $value) = each %group_parameters) {
+				$management->set_parameter($parameter, $value->{'value'});
+			}
+
+			my $vcl_names_ref = $management->get_vcl_names();
+			my $active_vcl_name;
+			my @vcl_names;
+			if ($vcl_names_ref) {
+				@vcl_names = @{$vcl_names_ref};
+				$active_vcl_name = shift @vcl_names;
+			}
+
+			for my $vcl_name (@vcl_names) {
+				if ($vcl_name ne $active_vcl_name) {
+					$management->discard_vcl($vcl_name);
+				}
+			}
+		
+			my $discard_active_vcl = 1;
+			my $group_master = first {
+									$_->get_group() eq $group
+									&& $_->is_master()
+								} @nodes;
+			my $master_management = $group_master->get_management();
+			my $master_active_vcl_name;
+			my @master_vcl_names;
+			my $master_vcl_names_ref = $group_master->get_management()->get_vcl_names();
+			if ($master_vcl_names_ref) {
+				@master_vcl_names = @{$master_vcl_names_ref};
+				$master_active_vcl_name = shift @master_vcl_names;
+			}
+
+			for my $vcl_name (@master_vcl_names) {
+				my $vcl = $master_management->get_vcl($vcl_name); 
+				$management->set_vcl($vcl_name, $vcl);
+
+				if ($vcl_name eq $master_active_vcl_name) {
+					$management->make_vcl_active($vcl_name);
+				}
+				if ($vcl_name eq $active_vcl_name) {
+					$discard_active_vcl = 0;
+				}
+			}
+
+			if ($discard_active_vcl) {
+				$management->discard_vcl($active_vcl_name);
+			}
+		}
+
+		push @nodes, $node;
+	}
+
+	sub remove_node {
+		my ($self, $node) = @_;
+
+		if ($node) {
+			@nodes = grep { $_ != $node } @nodes;
+
+			if ($node->is_master()) {
+				my $new_master = first {
+									$_->is_master
+									&& $_->get_group() eq $node->get_group()
+								 } @nodes;
+				if ($new_master) {
+					$new_master->set_master(1);
+				}
+			}
+		}
+	}
+
+	sub get_node {
+		my ($self, $node_id) = @_;
+		
+		my $node = first {
+						$_->get_id() == $node_id
+					} @nodes;
+
+		return $node;
+	}
+
+	sub add_group {
+		my ($self, $name) = @_;
+
+		push @groups, $name;
+	}
+
+	sub remove_group {
+		my ($self, $name) = @_;
+
+		@groups = grep { $_ ne $name } @groups;
+		my @nodes_to_remove = grep { $_->get_group() eq $name } @nodes;
+		for my $node (@nodes_to_remove) {
+			remove_node($self, $node);
+		}
+	}
+
+	sub get_groups {
+
+		return @groups;
+	}
+
+	sub get_nodes {
+
+		return @nodes;
+	}
+
+	sub get_nodes_for_group {
+		my ($self, $group) = @_;
+
+		return grep { $_->get_group() eq $group } @nodes;
+	}
+
+	sub get_group_masters {
+		my ($self) = @_;
+
+		return grep { $_->is_master() } @nodes;
+	}
+
+	sub load {
+
+
+	}
+
+	sub save {
+		my ($self) = @_;
+
+	}
+
+	sub quit {
+		my ($self) = @_;
+
+		for my $node (@nodes) {
+			my $management = $node->get_management();
+			if ($management) {
+				$management->close();
+			}
+		}
+		
+		save($self);
+	}
+
+	sub set_error {
+		my ($self, $new_error) = @_;
+
+		$error = $new_error;
+
+		return;
+	}
+
+	sub get_error {
+		my ($self) = @_;
+
+		return $error;
+	}
+
+	sub no_error {
+		my ($self, $return_value) = @_;
+
+		$error = "";
+
+		return defined($return_value) ? $return_value : 1;
+	}
+
+	sub set_group_parameter {
+		my ($self, $group, $parameter, $value) = @_;
+
+		my $error;
+
+		$group_parameters{$group}->{$parameter}->{'value'} = $value;
+		my @nodes_in_group = grep { $_->get_group() eq $group } @nodes;
+		for my $node (@nodes_in_group) {
+			my $management = $node->get_management();
+			if (!$management->set_parameter($parameter, $value)) {
+				$error .= $management->get_error() . "\n";
+			}
+		}
+
+		if ($error) {
+			return set_error($self, $error);
+		}
+		else {
+			return no_error();
+		}
+	}
+
+	sub get_group_parameters {
+		my ($self, $group) = @_;
+
+		return $group_parameters{$group};
+	}
+}
+
+1;
diff -Nru 2.0.3/varnish-tools/webgui/Varnish/Node.pm trunk/varnish-tools/webgui/Varnish/Node.pm
--- 2.0.3/varnish-tools/webgui/Varnish/Node.pm	1970-01-01 01:00:00.000000000 +0100
+++ trunk/varnish-tools/webgui/Varnish/Node.pm	2009-01-05 14:45:25.000000000 +0100
@@ -0,0 +1,128 @@
+package Varnish::Node;
+
+use strict;
+use LWP::UserAgent;
+use Varnish::Management;
+
+{
+	my %name_of;
+	my %address_of;
+	my %port_of;
+	my %group_of;
+	my %management_of;
+	my %management_port_of;
+	my %is_master_of;
+	my %node_id_of;
+
+	my $next_node_id = 1;
+
+	sub new {
+		my ($class, $arg_ref) = @_;
+
+		my $new_object = bless \do{ my $anon_scalar; }, $class;
+
+		$name_of{$new_object} = $arg_ref->{'name'};
+		$address_of{$new_object} = $arg_ref->{'address'};
+		$port_of{$new_object} = $arg_ref->{'port'};
+		$group_of{$new_object} = $arg_ref->{'group'};
+		$management_port_of{$new_object} = $arg_ref->{'management_port'};
+		$management_of{$new_object} = Varnish::Management->new($arg_ref->{'address'}, 
+															   $arg_ref->{'management_port'});
+		$is_master_of{$new_object} = 0;
+		$node_id_of{$new_object} = $next_node_id++;
+
+		return $new_object;
+	}
+
+	sub get_id {
+		my ($self) = @_;
+
+		return $node_id_of{$self};
+	}
+
+	sub get_name {
+		my ($self) = @_;
+
+		return $name_of{$self};
+	}
+
+	sub get_address {
+		my ($self) = @_;
+
+		return $address_of{$self};
+	}
+
+	sub get_port {
+		my ($self) = @_;
+
+		return $port_of{$self};
+	}
+
+	sub get_group {
+		my ($self) = @_;
+
+		return $group_of{$self};
+	}
+
+	sub get_management {
+		my ($self) = @_;
+
+		return $management_of{$self};
+	}
+
+	sub get_management_port {
+		my ($self) = @_;
+
+		return $management_port_of{$self};
+	}
+
+	sub is_master {
+		my ($self) = @_;
+
+		return $is_master_of{$self};
+	}
+
+	sub set_master {
+		my ($self, $master) = @_;
+
+		$is_master_of{$self} = $master;
+	}
+
+	sub is_running_ok {
+		my ($self) = @_;
+
+		my $user_agent = LWP::UserAgent->new;
+		$user_agent->timeout(1);
+
+		my $url = 'http://' . get_address($self) . ':' . get_port($self);
+		my $response = $user_agent->head($url);
+		return $response->is_success;
+	}
+
+	sub is_running {
+		my ($self) = @_;
+
+		my $user_agent = LWP::UserAgent->new;
+		$user_agent->timeout(1);
+
+		my $url = 'http://' . get_address($self) . ':' . get_port($self);
+		my $response = $user_agent->head($url);
+		return $response->code != 500;
+	}
+
+
+	sub is_management_running {
+		my ($self) = @_;
+
+		my $management = get_management($self);
+		if ($management) {
+			my $ping = $management->ping();
+			return defined($ping) && $ping;
+		}
+		else {
+			return 0;
+		}
+	}
+}
+
+1;
diff -Nru 2.0.3/varnish-tools/webgui/Varnish/RequestHandler.pm trunk/varnish-tools/webgui/Varnish/RequestHandler.pm
--- 2.0.3/varnish-tools/webgui/Varnish/RequestHandler.pm	1970-01-01 01:00:00.000000000 +0100
+++ trunk/varnish-tools/webgui/Varnish/RequestHandler.pm	2009-01-05 14:45:25.000000000 +0100
@@ -0,0 +1,1008 @@
+package Varnish::RequestHandler;
+
+use strict;
+use warnings;
+use HTML::Template;
+use HTTP::Request;
+use Varnish::Util;
+use Varnish::Management;
+use Varnish::NodeManager;
+use Varnish::Node;
+use Varnish::Statistics;
+use URI::Escape;
+use GD::Graph::lines;
+use POSIX qw(strftime);
+use List::Util qw(first);
+use Socket;
+
+{
+	my %request_ref_of;
+	my %response_content_ref_of;
+	my %response_header_ref_of;
+	my %master_tmpl_var_of;
+
+	sub new {
+		my ($class, $request_ref, $connection) = @_;
+
+		my $new_object = bless \do{ my $anon_scalar; }, $class;
+
+		$request_ref_of{$new_object} = $request_ref;
+		$response_content_ref_of{$new_object} = \"";
+		$response_header_ref_of{$new_object} = {};
+
+		my $server_ip = $connection->sockhost();
+		my $server_hostname = gethostbyaddr(inet_aton($server_ip), AF_INET);
+		$master_tmpl_var_of{$new_object}->{'server_host'} = $server_hostname;
+		$master_tmpl_var_of{$new_object}->{'server_port'} = $connection->sockport();
+
+		return $new_object;
+	}
+
+	sub DESTROY {
+		my ($self) = @_;
+
+		delete $request_ref_of{$self};
+
+		return;
+	}
+
+	sub get_response_header {
+		my ($self) = @_;
+
+		return $response_header_ref_of{$self};
+	}
+	sub get_response_content {
+		my ($self) = @_;
+
+		return ${$response_content_ref_of{$self}};
+	}
+
+	sub _parse_request_parameters {
+		my ($content_ref) = @_;
+		
+		my %parameter = ();
+		for my $pair (split /&/,$$content_ref) {
+			my ($key,$value) = split /=/,$pair;	
+			$value = uri_unescape($value);
+			$value =~ s/\+/ /g;
+			$parameter{$key} = $value;
+		}
+
+		return %parameter;
+	}
+
+	sub process {
+		my ($self) = @_;
+
+		my $request = ${$request_ref_of{$self}};
+		my $operation = $request->uri();
+		my $content = $request->content();
+
+		$operation =~ s:^/::;
+		if ($operation =~ /^(.*?)\?(.*)/) {
+			$operation = $1;
+			$content = $2;
+		}
+
+		my $content_template;
+		my $response_content;
+		my %request_parameter = _parse_request_parameters(\$content);
+
+#		while (my ($k, $v) = each %request_parameter) {
+#			print "$k => $v\n";
+#		}
+		
+		my $param;
+		if ($operation eq 'view_stats' || $operation eq '') {
+			($content_template, $param) = view_stats(\%request_parameter);
+		}
+		elsif ($operation eq 'configure_parameters') {
+			($content_template, $param) = configure_parameters(\%request_parameter);
+		}
+		elsif ($operation eq 'edit_vcl') {
+			($content_template, $param) = edit_vcl(\%request_parameter);
+		}
+		elsif ($operation eq 'node_management') {
+			($content_template, $param) = node_management(\%request_parameter);
+		}
+		elsif ($operation eq 'management_console') {
+			($content_template, $param) = management_console(\%request_parameter);
+		}
+		elsif ($operation eq 'send_management_command') {
+			$response_content = send_management_command(\%request_parameter);
+		}
+		elsif ($operation eq 'generate_graph') {
+			$response_header_ref_of{$self}->{'Content-Type'} = "image/png";
+			$response_content = generate_graph(\%request_parameter);
+			if (!$response_content) {
+				$response_content = read_file('images/nograph.png');
+			}
+		}
+		elsif ($operation eq 'collect_data') {
+			Varnish::Statistics->collect_data();
+			$response_content = "Ok";
+		}
+		else {
+			return;
+		}
+		
+		if ($content_template) {
+			my $template_text = read_file("templates/master.tmpl");
+			$template_text =~ s/CONTENT_TEMPLATE/$content_template/;
+
+			my $template = HTML::Template->new_scalar_ref(	\$template_text,
+					die_on_bad_params => 0);
+
+			my $tmpl_var = $master_tmpl_var_of{$self};
+			if ($param) {
+				while (my ($parameter, $value) = each %{$param}) {
+					$tmpl_var->{$parameter} = $value;
+				}
+			}
+			$template->param($tmpl_var);
+			$response_content = $template->output;
+		}
+		$response_content_ref_of{$self} = \$response_content;
+	}
+
+	sub edit_vcl {
+		my ($parameter_ref) = @_;
+
+		my %param = %{$parameter_ref};
+		$param{'vcl'} ||= "";
+		$param{'operation'} ||= "load";
+		$param{'group_name'} ||= "";
+		$param{'vcl_name'} ||= "";
+		$param{'new_vcl_name'} ||= "";
+
+
+		my $template = "edit_vcl.tmpl";
+		my %tmpl_var;
+		$tmpl_var{'error'} = "";
+		$tmpl_var{'vcl_name'} = $param{'vcl_name'};
+		$tmpl_var{'status'} = "";
+		$tmpl_var{'vcl_infos'} = [];
+		$tmpl_var{'group_infos'} = [];
+		$tmpl_var{'vcl_error'} = "";
+		$tmpl_var{'vcl'} = "";
+		
+		my $successfull_save = 0;
+		my $editing_new_vcl = 0;
+
+		my @group_masters = Varnish::NodeManager->get_group_masters();
+		if ($param{'operation'} eq "make_active") {
+			my $group_master = first { 
+				$_->get_group() eq $param{'group_name'};
+			} @group_masters;
+
+			if ($group_master) {
+				my $management = $group_master->get_management();
+				if ($management->make_vcl_active($param{'vcl_name'})) {
+					my @nodes = Varnish::NodeManager->get_nodes();
+					for my $node (@nodes) {
+						if ($node != $group_master && $node->get_group() eq $param{'group_name'}) {
+							$node->get_management()->make_vcl_active($param{'vcl_name'});
+						}
+					}
+					$tmpl_var{'status'} = "VCL activated successfully";
+				}
+				else {
+					$tmpl_var{'error'} .= "Error activating configuration:\n" . $management->get_error() . "\n";
+				}
+			}
+		}
+		elsif ($param{'operation'} eq 'new') {
+			if ($param{'new_vcl_name'}) {
+				$tmpl_var{'vcl_name'} = $param{'new_vcl_name'};					
+				$tmpl_var{'vcl'} = "";
+				push @{$tmpl_var{'vcl_infos'}}, {
+					name		=> $param{'new_vcl_name'},
+					selected	=> 1,
+					active		=> 0
+				};
+				$editing_new_vcl = 1;
+			}
+		}
+		elsif ($param{'operation'} eq 'save') {
+			my $group_master = first { 
+				$_->get_group() eq $param{'group_name'}
+			} @group_masters;
+
+			if ($group_master && $param{'vcl'} ne "" && $param{'vcl_name'} ne "") {
+				my $master_management = $group_master->get_management();
+				if ($master_management->set_vcl($param{'vcl_name'}, $param{'vcl'})) {
+					my @nodes = Varnish::NodeManager->get_nodes();
+					for my $node (@nodes) {
+						if ($node != $group_master && $node->get_group() eq $param{'group_name'}) {
+							my $management = $node->get_management();
+							if (!$management->set_vcl($param{'vcl_name'}, $param{'vcl'})) {
+								$tmpl_var{'error'} .= "Error saving configuration for " . $node->get_name()
+													. ":\n" . $management->get_error() . "\n";
+							}
+						}
+					}
+					$successfull_save = 1;
+					$tmpl_var{'status'} = "VCL saved successfully";
+				}
+				else {
+					push @{$tmpl_var{'vcl_infos'}}, {
+						name		=> $param{'vcl_name'},
+						selected	=> 1,
+						active		=> 0
+					};
+					$editing_new_vcl = 1;
+					$tmpl_var{'vcl'} = $param{'vcl'};
+					my $vcl_error = $master_management->get_error();
+					# it is bad bad bad mixing presentation and code, I know, but sometimes you have to
+					$vcl_error =~ s/Line (\d+) Pos (\d+)/<a href="javascript:goToPosition($1,$2)">$&<\/a>/g;
+					$vcl_error =~ s/\n/<br\/>/g;
+					$tmpl_var{'vcl_error'} = $vcl_error;
+				}
+			}
+		}
+		elsif ($param{'operation'} eq "discard") {
+			my ($group_master) = grep { 
+				$_->get_group() eq $param{'group_name'}
+			} @group_masters;
+			if ($group_master && $param{'vcl_name'} ne "") {
+				my $management = $group_master->get_management();
+				if ($management->discard_vcl($param{'vcl_name'})) {
+					my @nodes = Varnish::NodeManager->get_nodes();
+					for my $node (@nodes) {
+						if ($node != $group_master && $node->get_group() eq $param{'group_name'}) {
+							$node->get_management()->discard_vcl($param{'vcl_name'});
+						}
+					}
+
+					$tmpl_var{'vcl_name'} = "";
+					$tmpl_var{'status'} = "VCL discarded successfully";
+				}
+				else {
+					$tmpl_var{'error'} .= "Error discarding configuration:\n" . $management->get_error() . "\n";
+				}
+			}
+		}
+	
+		my $selected_group_master;
+		for my $group_master (@group_masters) {
+			my %group_info = (
+					name 		=>	$group_master->get_group(),
+					selected	=>	0,
+					);
+			if ($param{'group_name'} eq $group_master->get_group()) {
+				$group_info{'selected'} = '1';
+				$selected_group_master = $group_master;
+			}
+			push @{$tmpl_var{'group_infos'}}, \%group_info;
+		}
+		if (!$selected_group_master && @group_masters > 0) {
+			$selected_group_master = $group_masters[0];
+			$tmpl_var{'group_infos'}->[0]->{'selected'} = 1;
+		}
+
+		if ($selected_group_master) {
+			my $active_vcl_name;
+			my @vcl_names;
+			my $vcl_names_ref = $selected_group_master->get_management()->get_vcl_names();
+			if ($vcl_names_ref) {
+				@vcl_names = @{$vcl_names_ref};
+				$active_vcl_name = shift @vcl_names;
+				
+				for my $vcl_name (@vcl_names) {
+					my %vcl_info = (
+							name 		=>	$vcl_name,
+							selected	=>	0,
+							active		=>	0,	
+							);
+					if ($vcl_name eq $tmpl_var{'vcl_name'}) {
+						$vcl_info{'selected'} = 1;
+						$tmpl_var{'vcl_name'} = $vcl_name;
+					}
+					if ($vcl_name eq $active_vcl_name) {
+						$vcl_info{'active'} = 1;
+					}
+					push @{$tmpl_var{'vcl_infos'}}, \%vcl_info;
+				}
+				if ($tmpl_var{'vcl_name'} eq "") {
+					FIND_ACTIVE_VCL:
+					for my $vcl_info (@{$tmpl_var{'vcl_infos'}}) {
+						if ($vcl_info->{'active'}) {
+							$tmpl_var{'vcl_name'} = $vcl_info->{'name'};
+							$vcl_info->{'selected'} = 1;
+							last FIND_ACTIVE_VCL;
+						}
+					}
+					if ($tmpl_var{'vcl_name'} eq "") {
+						$tmpl_var{'vcl_name'} = $tmpl_var{'vcl_infos'}->[0]->{'name'};
+						$tmpl_var{'vcl_infos'}->[0]->{'selected'} = 1;
+					}
+				}
+
+				if (!(($param{'operation'} eq 'save' && !$successfull_save
+						|| $param{'operation'} eq 'new'))) {
+					my $vcl = $selected_group_master->get_management()->get_vcl($tmpl_var{'vcl_name'});
+					if ($vcl) {
+						$tmpl_var{'vcl'} = $vcl;
+					}
+					else {
+						$tmpl_var{'error'} .= "Error retrieving VCL: " . $selected_group_master->get_management()->get_error() . "\n";
+					}
+				}
+			}
+			else {
+				$tmpl_var{'error'} .= "Error retrieving the VCLs: " . $selected_group_master->get_management()->get_error();
+			}
+		}
+
+		$tmpl_var{'editing_new_vcl'} = $editing_new_vcl;
+		$tmpl_var{'successfull_save'} = $successfull_save;
+
+		return ($template, \%tmpl_var);
+	}
+
+
+	sub view_stats {
+		my ($parameter_ref) = @_;
+
+		my $template = "view_stats.tmpl";
+
+		my %param = %{$parameter_ref};
+		$param{'view_raw_stats'} ||= 0;
+		$param{'auto_refresh'} ||= 0;
+
+		my %tmpl_var;
+		$tmpl_var{'error'} = "";
+		$tmpl_var{'stat_time'} = 0;
+		$tmpl_var{'node_infos'} = [];
+		$tmpl_var{'summary_stats'} = [];
+		$tmpl_var{'raw_stats'} = [];
+		$tmpl_var{'auto_refresh'} = $param{'toggle_auto_refresh'} ? 1 - $param{'auto_refresh'} : $param{'auto_refresh'};
+		$tmpl_var{'auto_refresh_interval'} = $tmpl_var{'auto_refresh'} ? get_config_value('poll_interval') : 0;
+		$tmpl_var{'view_raw_stats'} = $param{'view_raw_stats'};
+
+		my $error = "";
+	
+		my ($stat_time, $stat_ref) = Varnish::Statistics->get_last_measure();
+		my @nodes = Varnish::NodeManager->get_nodes();
+
+		if ($stat_time) {
+			$stat_time = strftime("%a %b %e %H:%M:%S %Y", localtime($stat_time));
+		}
+
+		my %summary_stat_list;
+		my %raw_stat_list;
+		for my $node (@nodes) {
+			push @{$tmpl_var{'node_infos'}}, {
+				name	=> $node->get_name(),
+			};
+
+			my $node_stat_ref = $stat_ref->{$node};
+			my $node_id = $node->get_id();
+			my $time_span = 'minute';
+			
+			# example of adding graph the graph ID must match that of a predefind graph
+			# which is created in generate_graph found around line 826
+			push @{$summary_stat_list{'Hit ratio'}}, {
+				is_graph 	=> 1,
+				node_id 	=> $node_id,
+				graph_id 	=> 'cache_hit_ratio',
+			};
+			push @{$summary_stat_list{'Connect requests'}}, {
+				is_graph 	=> 1,
+				node_id 	=> $node_id,
+				graph_id 	=> 'connect_rate',
+			};
+
+			# example of missing graph_id
+			push @{$summary_stat_list{'Missing graph'}}, {
+				is_graph 	=> 1,
+				node_id 	=> $node_id,
+				graph_id 	=> 'missing_graph',
+			};
+
+			# to add custom values, just add values by adding it to the list. The 
+			# get_formatted_bytes() function is usefull for displaying byte values
+			# as it will convert to MB, GB etc as needed.
+			push @{$summary_stat_list{'% of requests served from cache'}}, {
+				value	=> get_formatted_percentage($$node_stat_ref{'Cache hits'} 
+													, $$node_stat_ref{'Client requests received'})
+			};
+
+			# these are examples of adding plain values from the raw stats
+			push @{$summary_stat_list{'Client connections accepted'}}, {
+				value	=> $$node_stat_ref{'Client connections accepted'}
+			};
+			push @{$summary_stat_list{'Client requests received'}}, {
+				value	=> $$node_stat_ref{'Client requests received'}
+			};
+
+			my $total_bytes_served;
+			if ($$node_stat_ref{'Total header bytes'} 
+				&& $$node_stat_ref{'Total body bytes'}) {
+				$total_bytes_served = $$node_stat_ref{'Total header bytes'} + $$node_stat_ref{'Total header bytes'};
+			}
+			push @{$summary_stat_list{'Total bytes served'}}, {
+				'value'	
+					=> get_formatted_bytes($total_bytes_served)
+			};
+
+			if ($param{'view_raw_stats'}) {
+				while (my ($stat_name, $value) = each %{$node_stat_ref}) {
+					push @{$raw_stat_list{$stat_name}}, {
+						value	=> $value,
+					};
+				}
+			}
+		}
+
+		my $row = 1;
+		while (my ($stat_name, $values_ref) = each %raw_stat_list) {
+			push @{$tmpl_var{'raw_stats'}}, {
+				name	=> $stat_name,
+				values	=> $values_ref,
+				odd_row	=> $row++ % 2,
+			}
+		}
+
+		$row = 1;
+		my $graph_row = 0;
+		while (my ($stat_name, $values_ref) = each %summary_stat_list) {
+			if ($values_ref->[0]->{'is_graph'}) {
+				unshift @{$tmpl_var{'summary_stats'}}, {
+					name	=> $stat_name,
+					values	=> $values_ref,
+					odd_row	=> $graph_row++ % 2,
+				}
+			}
+			else {
+				push @{$tmpl_var{'summary_stats'}}, {
+					name	=> $stat_name,
+					values	=> $values_ref,
+					odd_row	=> $row++ % 2,
+				}
+			}
+		}
+
+		$tmpl_var{'error'} = $error;
+		$tmpl_var{'stat_time'} = $stat_time;
+
+		return ($template, \%tmpl_var);
+	}
+
+	sub configure_parameters {
+		my ($parameter_ref) = @_;
+
+		my %param = %{$parameter_ref};
+		$param{'node_id'} = $$parameter_ref{'node_id'} || "";
+		$param{'group'} = $$parameter_ref{'group'} || "";
+
+		my $template = "configure_parameters.tmpl";
+		my %tmpl_var;
+		$tmpl_var{'error'} = "";
+		$tmpl_var{'status'} = "";
+		$tmpl_var{'unit_infos'} = [];
+		$tmpl_var{'parameter_infos'} = [];
+
+		my $unit_parameter_ref = {};
+		my $error = "";
+
+		my %changed_parameters;
+		while (my ($parameter, $value) = each %$parameter_ref) {
+			if ($parameter =~ /^new_(.*?)$/ &&
+					$$parameter_ref{"old_$1"} ne $value) {
+				$changed_parameters{$1} = $value;
+			}
+		}
+
+		my @nodes = Varnish::NodeManager->get_nodes();
+		my @groups = Varnish::NodeManager->get_groups();
+		if (%changed_parameters) {
+			my $node = first { $_->get_id() eq $param{'node_id'} } @nodes;
+			if ($node) {
+				my $management = $node->get_management();
+				while (my ($parameter, $value) = each %changed_parameters) {
+					if (!$management->set_parameter($parameter, $value)) {
+						$error .= "Could not set parameter $parameter: ". $node->get_management()->get_error() . "\n";
+					}
+				}
+			}
+			else {
+				my $group = first { $_ eq $param{'group'} } @groups;
+				if ($group ne "") {
+					while (my ($parameter, $value) = each %changed_parameters) {
+						if (!Varnish::NodeManager->set_group_parameter($group, $parameter, $value)) {
+							$error .= "Could not set parameter $parameter for group $group: "
+									. Varnish::NodeManager->get_error()  . "\n";
+						}
+					}
+				}
+			}
+			if ($error eq "") {
+				my @changed_parameters = keys %changed_parameters;
+				my $status = "Parameter" . (@changed_parameters > 1 ? "s " : " ");
+
+				$status .= shift @changed_parameters;
+				for my $parameter (@changed_parameters) {
+					$status .= ", $parameter";
+				}
+				$status .= " configured successfully";
+				$tmpl_var{'status'} = $status;
+			}
+		}
+
+		for my $group (@groups) {
+			my %unit_info = (
+					name		=>	$group,
+					id			=>	$group,
+					is_node		=>	0,
+					selected	=>	0, 
+			);
+			if ($group eq $param{'group'}) {
+				$unit_info{'selected'} = 1;
+				$unit_parameter_ref = Varnish::NodeManager->get_group_parameters($group);
+				if (!$unit_parameter_ref) {
+					$error .= "Could not get parameters for group $group. You need to have added a node to set these.\n";
+				}
+			}
+			push @{$tmpl_var{'unit_infos'}}, \%unit_info;
+		}
+
+		for my $node (@nodes) {
+			my %unit_info = (
+				name		=>	$node->get_name(),
+				id			=>	$node->get_id(),
+				is_node		=>	1,
+				selected	=>	0, 
+			);
+			if ($node->get_id() eq $param{'node_id'}) {
+				$unit_info{'selected'} = 1;
+				$unit_parameter_ref = $node->get_management()->get_parameters();
+				if (!$unit_parameter_ref) {
+					$error .= "Could not get parameters for node " . $node->get_name() . "\n";
+				}
+			}
+			push @{$tmpl_var{'unit_infos'}}, \%unit_info;
+		}
+
+		if ($param{'group'} eq "" && $param{'node_id'} eq ""
+			&& @{$tmpl_var{'unit_infos'}} > 0) {
+			$tmpl_var{'unit_infos'}->[0]->{'selected'} = 1;
+			my $group = $tmpl_var{'unit_infos'}->[0]->{'name'};
+			$unit_parameter_ref = Varnish::NodeManager->get_group_parameters($group);
+			if (!$unit_parameter_ref) {
+				$error .= "Could not get parameters for group $group\n";
+			}
+		}
+
+		my $row = 0;
+		while (my ($parameter, $info) = each %{$unit_parameter_ref} ) {
+			my $value = $info->{'value'};
+			my $unit = $info->{'unit'};
+			my $is_boolean = $unit eq "[bool]";
+			if ($is_boolean) {
+				$value = $value eq "on";
+				$unit = '';
+			}
+			
+			push @{$tmpl_var{'parameter_infos'}}, {
+				name 		=> $parameter,
+				value 		=> $value,
+				unit 		=> $unit,
+				description	=> $info->{'description'},
+				is_boolean 	=> $is_boolean,
+				odd_row 	=> $row++ % 2,
+			};
+		}
+
+		$tmpl_var{'error'} = $error;
+		
+		return ($template, \%tmpl_var);
+	}
+
+
+	sub node_management {
+		my ($parameter_ref) = @_;
+
+		my %param = %{$parameter_ref};
+		$param{'node_id'} ||= "";
+		$param{'group'} ||= "";
+		$param{'operation'} ||= "";
+		$param{'name'} ||= "";
+		$param{'address'} = $$parameter_ref{'address'} || "";
+		$param{'port'} ||= "";
+		$param{'management_port'} ||= "";
+	
+		my $template = "node_management.tmpl";
+		my %tmpl_var = ();
+		$tmpl_var{'error'} = "";
+		$tmpl_var{'status'} = "";
+		$tmpl_var{'add_group'} = 0;
+		$tmpl_var{'group_infos'} = [];
+		$tmpl_var{'group'} = $param{'group'} || "";
+		$tmpl_var{'node_infos'} = [];
+		$tmpl_var{'default_managment_port'} = 9001;
+		$tmpl_var{'backend_health_infos'} = [];
+
+		my $error = "";
+		my $status = "";
+
+		if ($param{'operation'} eq "add_group") {
+			if ($param{'group'}) {
+				Varnish::NodeManager->add_group($param{'group'});
+				 $status .= "Group " . $param{'group'} . " added successfully.";
+			}
+			else {
+				$tmpl_var{'add_group'} = 1;
+			}
+		}
+		elsif ($param{'operation'} eq "remove_group") {
+			if ($param{'group'}) {
+				Varnish::NodeManager->remove_group($param{'group'});
+				$status = "Group " . $param{'group'} . " removed successfully";
+				$tmpl_var{'group'} = "";
+			}
+		}
+		elsif ($param{'operation'} eq "start_group") {
+			my $node_errors = "";
+			for my $node (Varnish::NodeManager->get_nodes()) {
+				if ($node->get_group() eq $param{'group'}
+						&& !$node->is_running()) {
+					my $management = $node->get_management();
+					if (!$management->start()) {
+						$node_errors .= "Could not start " . $node->get_name() . ": " 
+										. $management->get_error() . ". ";
+					}
+				}
+			}
+
+			if ($node_errors eq "") {
+				$status .= "Group " . $param{'group'} . " started successfully.";
+			}
+			else {
+				$status .= "Group " . $param{'group'} . " started with errors: $node_errors.";
+			}
+		}
+		elsif ($param{'operation'} eq "stop_group") {
+			my $node_errors = "";
+			for my $node (Varnish::NodeManager->get_nodes()) {
+				if ($node->get_group() eq $param{'group'} 
+						&& $node->is_running()) {
+					my $management = $node->get_management();
+					if (!$management->stop()) {
+						$node_errors .= "Could not stop " . $node->get_name() . ": " 
+										. $management->get_error() . ". ";
+					}
+				}
+			}
+			if ($node_errors eq "") {
+				$status .= "Group " . $param{'group'} . " stopped successfully.";
+			}
+			else {
+				$status .= "Group " . $param{'group'} . " stopped with errors: $node_errors.";
+			}
+		}
+		elsif ($param{'operation'} eq 'add_node') {
+			if ($param{'name'} && $param{'address'} && $param{'port'} 
+				&& $param{'group'} && $param{'management_port'}) {
+				my $node = Varnish::Node->new({
+					name 			=> $param{'name'}, 
+					address			=> $param{'address'},
+					port			=> $param{'port'}, 
+					group			=> $param{'group'}, 
+					management_port	=> $param{'management_port'}
+				});
+				Varnish::NodeManager->add_node($node);
+				$status .= "Node " . $node->get_name() . " added successfully.";
+			}
+			else {
+				$error .= "Not enough information to add node:\n"; 
+				$error .= "Name: " . $param{'name'} . ":\n"; 
+				$error .= "Address: " . $param{'address'} . ":\n"; 
+				$error .= "Port: " . $param{'port'} . ":\n"; 
+				$error .= "Group: " . $param{'group'} . ":\n"; 
+				$error .= "Management port: " . $param{'management_port'} . ":\n"; 
+			}
+		}
+		elsif ($param{'operation'} eq "remove_node") {
+			if ($param{'node_id'}) {
+				my $node = Varnish::NodeManager->get_node($param{'node_id'});
+				if ($node) {
+					$tmpl_var{'group'} = $node->get_group();
+					Varnish::NodeManager->remove_node($node);
+					$status .= "Node " . $node->get_name() . " removed successfully.";
+				}
+			}
+			else {
+				$error .= "Could not remove node: Missing node ID\n";
+			}
+		}
+		elsif ($param{'operation'} eq "start_node") {
+			if ($param{'node_id'}) {
+				my $node = Varnish::NodeManager->get_node($param{'node_id'});
+				if ($node) {
+					my $management = $node->get_management();
+					if ($node->is_running()) {
+						$status .= "Node " . $node->get_name() . " already running.";
+					}
+					elsif ($management->start() ) {
+						$status .= "Node " . $node->get_name() . " started successfully.";
+					}
+					else {
+						$error .= "Could not start " . $node->get_name() 
+								. ": " . $management->get_error() . "\n"; 
+					}
+					$tmpl_var{'group'} = $node->get_group();
+				}
+			}
+			else {
+				$error .= "Could not start node: Missing node ID\n";
+			}
+		}
+		elsif ($param{'operation'} eq "stop_node") {
+			if ($param{'node_id'}) {
+				my $node = Varnish::NodeManager->get_node($param{'node_id'});
+				if ($node) {
+					my $management = $node->get_management();
+					if (!$node->is_running()) {
+						$status .= "Node " . $node->get_name() . " already stopped.";
+					}
+					elsif ($management->stop()) {
+						$status .= "Node " . $node->get_name() . " stopped successfully.";
+					}
+					else {
+						$error .= "Could not stop " . $node->get_name() 
+								. ": " . $management->get_error() . "\n"; 
+					}
+				}
+				$tmpl_var{'group'} = $node->get_group();
+			}
+			else {
+				$error .= "Could not stop node: Missing node ID\n";
+			}
+		}
+
+		# Populate the node table
+		my @groups = Varnish::NodeManager->get_groups();
+		if (@groups) {
+			if (!$tmpl_var{'group'} && !$tmpl_var{'add_group'}) {
+				$tmpl_var{'group'} = $groups[0];
+			}
+			my @group_infos = map {
+				{
+					name		=> $_,
+					selected	=> $_ eq $tmpl_var{'group'},
+				}
+			} @groups;
+			$tmpl_var{'group_infos'} = \@group_infos;
+			
+			my @nodes = Varnish::NodeManager->get_nodes();
+			for my $node (@nodes) {
+				next if ($node->get_group() ne $tmpl_var{'group'});
+
+				push @{$tmpl_var{'node_infos'}}, {
+					id						=> $node->get_id(),	
+					is_running_ok			=> $node->is_running_ok(),	
+					is_running				=> $node->is_running(),	
+					is_management_running	=> $node->is_management_running(),	
+					name					=> $node->get_name(),	
+					address					=> $node->get_address(),	
+					port					=> $node->get_port(),	
+					management_port			=> $node->get_management_port(),
+					group					=> $node->get_group(),	
+				};
+
+				if (@{$tmpl_var{'backend_health_infos'}} == 0) {
+					my $backend_health = $node->get_management()->get_backend_health();
+					if ($backend_health) {
+						while (my ($backend, $health) = each %{$backend_health}) {
+							push @{$tmpl_var{'backend_health_infos'}}, {
+								name	=> $backend,
+								health	=> $health,
+							};
+						}
+					}
+				}
+			}
+		}
+		else {
+			$tmpl_var{'add_group'} = 1;
+		}
+
+		$tmpl_var{'error'} = $error;
+		$tmpl_var{'status'} = $status;
+		
+		return ($template, \%tmpl_var);
+	}
+
+sub generate_graph {
+	my ($parameter_ref) = @_;
+
+	my %param = %{$parameter_ref};
+	$param{'width'} ||= 250;
+	$param{'height'} ||= 150;
+	$param{'time_span'} ||= "minute";
+	$param{'type'} ||= "";
+	$param{'node_id'} ||= 0;
+
+	my $interval = get_config_value('poll_interval');
+
+	# this hash holds available graphs which can be added to the summary stats in the view_stats
+	# function.
+	my %graph_info = (
+		# the name of the graph
+		cache_hit_ratio	=> {
+			# the parameters to GD::Graph. y_number_format should be noted, as it let you format
+			# the presentation, like multiplying with 100 to get the percentage as shown here
+			graph_parameter	=> {
+				y_label			=> '%',
+				title			=> "Cache hit ratio last " . $param{'time_span'},
+				y_max_value		=> 1,
+				y_min_value		=> 0,
+				y_number_format	=> sub { return $_[0] * 100 }
+			},
+			# the divisors and dividends are lists of names of the statistics to
+			# use when calculating the values in the graph. The names can be obtained
+			# by turning 'Raw statistics' on in the GUI. The value in the graph is calculated
+			# by taking the sum of divisors and divide witht the sum of the dividends, i.e.
+			# value = (divisor1 + divisor2 + divisor3 ...) / (dividend1 + dividend 2 +..)
+			# if divisor or dividend is emitted, the value of 1 is used instead
+			divisors			=> [ 'Cache hits' ],
+			dividends			=> [ 'Cache hits', 'Cache misses' ],
+		},
+		connect_rate	=> {
+			graph_parameter	=> {
+				y_label			=> 'Reqs',
+				title			=> "Reqs / $interval s  last " . $param{'time_span'},
+				y_min_value		=> 0,
+			},
+			# here we have no dividends as we only want to plot 'Client requests received'
+			divisors			=> [ 'Client requests received' ],
+			# if use_delta is set to 1, the derived value is used, i.e. the difference
+			# in value between two measurements. This is usefull for graphs showing rates
+			# like this connect rate
+			use_delta			=> 1,
+		},
+	);
+	my %time_span_graph_parameters  = (
+			minute	=> {
+				x_label		=> 'Time',
+				x_tick_number	=> 6, # need to be set to make x_number_format work
+				x_number_format	=> sub { return strftime(":%S", localtime($_[0])); },
+				x_max_value		=> time
+			},
+			hour	=> {
+				x_label			=> 'Time',
+				x_tick_number	=> 6, # need to be set to make x_number_format work
+				x_number_format	=> sub { return strftime("%H:%M", localtime($_[0])); },
+			},
+			day	=> {
+				x_label			=> 'Time',
+				x_tick_number	=> 4, # need to be set to make x_number_format work
+				x_number_format	=> sub { return strftime("%H", localtime($_[0])); },
+			},
+			week	=> {
+				x_label			=> 'Time',
+				x_tick_number	=> 7, # need to be set to make x_number_format work
+				x_number_format	=> sub { return strftime("%d", localtime($_[0])); },
+			},
+			month	=> {
+				x_label			=> 'Time',
+				x_tick_number	=> 4, # need to be set to make x_number_format work
+				x_number_format	=> sub { return strftime("%d.%m", localtime($_[0])); },
+			},
+			);
+
+
+	if ( !$graph_info{$param{'type'}} 
+		 || !$time_span_graph_parameters{$param{'time_span'}}) {
+		#print "Error: Missing data";
+		return;
+	}
+	my $data_ref = Varnish::Statistics->generate_graph_data(
+			$param{'node_id'}, 
+			$param{'time_span'}, 
+			$graph_info{$param{'type'}}->{'divisors'},
+			$graph_info{$param{'type'}}->{'dividends'},
+			$graph_info{$param{'type'}}->{'use_delta'}
+			);
+	if (!$data_ref) {
+		#print "Error generating graph data\n";
+		return;
+	}
+	my $graph = GD::Graph::lines->new($param{'width'}, $param{'height'});
+	$graph->set((%{$graph_info{$param{'type'}}->{'graph_parameter'}}, 
+				%{$time_span_graph_parameters{$param{'time_span'}}}),
+				dclrs => ["#990200"]);
+
+		my $graph_image = $graph->plot($data_ref);
+
+		if (!$graph_image) {
+			return;
+		}
+
+		return $graph_image->png;
+	}
+
+	sub management_console {
+		my ($parameter_ref) = @_;
+
+		my %param = %{$parameter_ref};
+		$param{'node_id'} = $$parameter_ref{'node_id'} || 0;
+
+		my $template = "management_console.tmpl";
+		my %tmpl_var;
+		$tmpl_var{'error'} = "";
+		$tmpl_var{'unit_infos'} = [];
+		$tmpl_var{'parameter_infos'} = [];
+		$tmpl_var{'default_console_font_size'} = '1.1em',
+		$tmpl_var{'default_console_cols'} = 80,
+		$tmpl_var{'default_console_rows'} = 30,
+
+		my @nodes = Varnish::NodeManager->get_nodes();
+		if (@nodes) {
+			my $node_id = $param{'node_id'} ? $param{'node_id'} : $nodes[0]->get_id();
+			for my $node (@nodes) {
+				my $selected = $node->get_id() == $node_id;
+				push @{$tmpl_var{'node_infos'}}, {
+					id			=> $node->get_id(),
+					name		=> $node->get_name(),
+					selected	=> $selected,
+				};
+
+				if ($selected) {
+					$tmpl_var{'current_node_name'} = $node->get_name();
+				}
+			}
+		}
+		
+		$tmpl_var{'console_themes'} = [
+			{
+				name		=> 'Grey on black',
+				foreground	=> '#bbb',
+				background	=> 'black',
+			},
+			{
+				name		=> 'Black on white',
+				foreground	=> 'black',
+				background	=> 'white',
+			},
+			{
+				name		=> 'Retro',
+				foreground	=> 'green',
+				background	=> 'black',
+			}
+		];
+		$tmpl_var{'default_console_foreground'}	= $tmpl_var{'console_themes'}->[0]->{'foreground'},
+		$tmpl_var{'default_console_background'} = $tmpl_var{'console_themes'}->[0]->{'background'},
+
+		return ($template, \%tmpl_var);
+	}
+
+	sub send_management_command {
+		my ($parameter_ref) = @_;
+		
+		my $node_id = $$parameter_ref{'node_id'};
+		my $command = $$parameter_ref{'command'};
+
+		if ($node_id && $command) {
+			my $node = Varnish::NodeManager->get_node($node_id);
+			return "Error: Node not found." if (!$node);
+		
+			my $management = $node->get_management();
+			my $response = $management->send_command($command);
+			if ($response) {
+				return $response;
+			}
+			else {
+				return "Error: " . $management->get_error();
+			}
+		}
+		else {
+			return "Error: Not valid input";
+		}
+	}
+
+}
+
+
+1;
diff -Nru 2.0.3/varnish-tools/webgui/Varnish/Statistics.pm trunk/varnish-tools/webgui/Varnish/Statistics.pm
--- 2.0.3/varnish-tools/webgui/Varnish/Statistics.pm	1970-01-01 01:00:00.000000000 +0100
+++ trunk/varnish-tools/webgui/Varnish/Statistics.pm	2009-01-05 14:45:25.000000000 +0100
@@ -0,0 +1,132 @@
+package Varnish::Statistics;
+
+use strict;
+use POSIX qw(strftime);
+use List::Util qw(first);
+
+use Varnish::Util;
+use Varnish::NodeManager;
+
+{
+	my %data;
+	my $last_measure_ref;
+	my $last_measure_time;
+
+	sub collect_data {
+		my $time_stamp = time();
+		my %measure;
+		my $good_stat_ref;
+		my @nodes = Varnish::NodeManager->get_nodes();
+
+		my @bad_nodes;
+		for my $node (@nodes) {
+			my $management = $node->get_management();
+			my $stat_ref;
+			if ($management) {
+			 	$stat_ref = $management->get_stats();
+			}
+			if ($stat_ref) {
+				$measure{$node} = $stat_ref;
+				if (!$good_stat_ref) {
+					$good_stat_ref = $stat_ref;
+				}
+			}
+			else {
+				push @bad_nodes, $node;
+			}
+		}
+
+		if (@bad_nodes && $good_stat_ref) {
+			for my $bad_node (@bad_nodes) {
+				$measure{$bad_node}->{'missing data'} = 1;
+				for my $key (keys %$good_stat_ref) {
+					$measure{$bad_node}->{$key} = -1;
+				}
+			}
+		}
+
+		$data{$time_stamp} = \%measure;
+		$last_measure_ref = \%measure;
+		$last_measure_time = $time_stamp;
+	}
+
+
+	sub get_last_measure {
+	
+		return ($last_measure_time, $last_measure_ref);
+	}
+	
+	sub generate_graph_data {
+		my ($self, $node_id, $time_span, $divisors_ref, $dividends_ref, $use_delta) = @_;
+		
+		my %seconds_for = (
+			minute	=> 60,
+			hour	=> 3600,
+			day		=> 86400,
+			week	=> 604800,	
+			month	=> 18144000, # 30 days
+		);
+		my $start_time = time() - $seconds_for{$time_span};
+		if ($use_delta) {
+			$start_time -= get_config_value('poll_interval');
+		}
+		my $node = first { 
+						$_->get_id() == $node_id
+					} Varnish::NodeManager->get_nodes();
+
+		my @measures = grep { 
+							$_ > $start_time 
+						} (sort keys %data);
+		my @values;
+		my $last_value;
+		GENERATE_DATA:
+		for my $measure (@measures) {
+			my $value;
+			if (!$data{$measure}->{$node}->{'missing data'}) {
+				my $divisor_value = 0;
+				my $dividend_value = 0;
+
+				if ($divisors_ref && @$divisors_ref) {
+					for my $divisor (@$divisors_ref) {
+						$divisor_value += $data{$measure}->{$node}->{$divisor};
+					}
+				}
+				else {
+					$divisor_value = 1;
+				}
+				if ($dividends_ref && @$dividends_ref) {
+					for my $dividend (@$dividends_ref) {
+						$dividend_value += $data{$measure}->{$node}->{$dividend};
+					}
+				}
+				else {
+					$dividend_value = 1;
+				}
+				if ($dividend_value) {
+					$value = $divisor_value / $dividend_value;
+				}
+
+				if ($use_delta) {
+					if (!$last_value) {
+						$last_value = $value;
+						next GENERATE_DATA;
+					}
+					my $delta_value = $value - $last_value;
+					$last_value = $value;
+					# if the value is negative, then we have had restart and don't plot it.
+					if ($delta_value < 0) {
+						$value = undef;
+					}
+					else {
+						$value = $delta_value;
+					}
+				}
+			}
+			push @values, $value;
+		}
+
+		return [ \@measures, \@values ];
+	}
+}
+
+1;
diff -Nru 2.0.3/varnish-tools/webgui/Varnish/.svn/entries trunk/varnish-tools/webgui/Varnish/.svn/entries
diff -Nru 2.0.3/varnish-tools/webgui/Varnish/.svn/format trunk/varnish-tools/webgui/Varnish/.svn/format
diff -Nru 2.0.3/varnish-tools/webgui/Varnish/.svn/text-base/Management.pm.svn-base trunk/varnish-tools/webgui/Varnish/.svn/text-base/Management.pm.svn-base
diff -Nru 2.0.3/varnish-tools/webgui/Varnish/.svn/text-base/NodeManager.pm.svn-base trunk/varnish-tools/webgui/Varnish/.svn/text-base/NodeManager.pm.svn-base
diff -Nru 2.0.3/varnish-tools/webgui/Varnish/.svn/text-base/Node.pm.svn-base trunk/varnish-tools/webgui/Varnish/.svn/text-base/Node.pm.svn-base
diff -Nru 2.0.3/varnish-tools/webgui/Varnish/.svn/text-base/RequestHandler.pm.svn-base trunk/varnish-tools/webgui/Varnish/.svn/text-base/RequestHandler.pm.svn-base
diff -Nru 2.0.3/varnish-tools/webgui/Varnish/.svn/text-base/Statistics.pm.svn-base trunk/varnish-tools/webgui/Varnish/.svn/text-base/Statistics.pm.svn-base
diff -Nru 2.0.3/varnish-tools/webgui/Varnish/.svn/text-base/Util.pm.svn-base trunk/varnish-tools/webgui/Varnish/.svn/text-base/Util.pm.svn-base
diff -Nru 2.0.3/varnish-tools/webgui/Varnish/Util.pm trunk/varnish-tools/webgui/Varnish/Util.pm
--- 2.0.3/varnish-tools/webgui/Varnish/Util.pm	1970-01-01 01:00:00.000000000 +0100
+++ trunk/varnish-tools/webgui/Varnish/Util.pm	2009-01-05 14:45:25.000000000 +0100
@@ -0,0 +1,68 @@
+package Varnish::Util;
+
+use strict;
+use Exporter;
+use base qw(Exporter);
+
+our @EXPORT = qw(
+				set_config
+				get_config_value
+				read_file
+				get_formatted_percentage
+				get_formatted_bytes
+				);
+
+{
+	my %config;
+
+	sub set_config {
+		my ($config_ref) = @_;
+
+		%config = %{$config_ref};
+	}
+
+	sub get_config_value {
+		my ($key) = @_;
+
+		return $config{$key};
+	}
+
+	sub read_file($) {
+		my ($filename) = @_;	
+
+		open(my $fh, "<$filename" );
+		my $content = do { local($/); <$fh> };
+		close($fh);
+
+		return $content;
+	}
+
+	sub get_formatted_percentage {
+		my ($divisor, $dividend) = @_;
+		
+		return $dividend > 0 ? sprintf( "%.2f", 100 * ($divisor / $dividend)) : "inf";
+	}
+
+	# thanks to foxdie at #varnish for php snippet
+	sub get_formatted_bytes {
+		my ($bytes) = @_;
+        
+		if ($bytes > 1099511627776) {
+			return sprintf( "%.3f TB", $bytes / 1099511627776);
+        }
+        elsif ($bytes > 1073741824) {
+			return sprintf( "%.3f GB", $bytes / 1073741824);
+        }
+        elsif ($bytes > 1048576) {
+			return sprintf( "%.3f MB", $bytes / 1048576);
+        }
+        elsif ($bytes > 1024) {
+			return sprintf( "%.3f KB", $bytes / 1024);
+        }
+        else {
+			return $bytes . " B";
+        }
+	}
+}
+
+1;
diff -Nru 2.0.3/varnish-tools/webmin/images/.svn/entries trunk/varnish-tools/webmin/images/.svn/entries
diff -Nru 2.0.3/varnish-tools/webmin/.svn/entries trunk/varnish-tools/webmin/.svn/entries
diff -Nru 2.0.3/varnish-tools/webmin/Varnish/.svn/entries trunk/varnish-tools/webmin/Varnish/.svn/entries
