]> git.pld-linux.org Git - packages/varnish.git/commitdiff
- apply branch.diff
authorElan Ruusamäe <glen@pld-linux.org>
Fri, 16 Oct 2009 12:59:53 +0000 (12:59 +0000)
committercvs2git <feedback@pld-linux.org>
Sun, 24 Jun 2012 12:13:13 +0000 (12:13 +0000)
Changed files:
    branch.diff -> 1.1
    branch.sh -> 1.1
    varnish.spec -> 1.40

branch.diff [new file with mode: 0644]
branch.sh [new file with mode: 0644]
varnish.spec

diff --git a/branch.diff b/branch.diff
new file mode 100644 (file)
index 0000000..434f4a3
--- /dev/null
@@ -0,0 +1,4712 @@
+Index: include/vsb.h
+===================================================================
+--- include/vsb.h      (.../tags/varnish-2.0.4/varnish-cache)
++++ include/vsb.h      (.../branches/2.0/varnish-cache)
+@@ -77,7 +77,8 @@
+ int            vsb_len(struct vsb *);
+ int            vsb_done(const struct vsb *);
+ void           vsb_delete(struct vsb *);
+-void           vsb_quote(struct vsb *s, const char *p, int how);
++void           vsb_quote(struct vsb *s, const char *p, int len, int how);
++const char    *vsb_unquote(struct vsb *s, const char *p, int len, int how);
+ #ifdef __cplusplus
+ };
+ #endif
+Index: include/compat/execinfo.h
+===================================================================
+--- include/compat/execinfo.h  (.../tags/varnish-2.0.4/varnish-cache)
++++ include/compat/execinfo.h  (.../branches/2.0/varnish-cache)
+@@ -0,0 +1,44 @@
++/*
++ * Copyright (c) 2003 Maxim Sobolev <sobomax@FreeBSD.org>
++ * 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.
++ *
++ * $Id$
++ */
++
++#ifndef COMPAT_EXECINFO_H_INCLUDED
++#define COMPAT_EXECINFO_H_INCLUDED
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++int     backtrace(void **, int);
++char ** backtrace_symbols(void *const *, int);
++void    backtrace_symbols_fd(void *const *, int, int);
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* COMPAT_EXECINFO_H_INCLUDED */
+Index: include/libvarnish.h
+===================================================================
+--- include/libvarnish.h       (.../tags/varnish-2.0.4/varnish-cache)
++++ include/libvarnish.h       (.../branches/2.0/varnish-cache)
+@@ -42,6 +42,8 @@
+ /* from libvarnish/argv.c */
+ void FreeArgv(char **argv);
+ char **ParseArgv(const char *s, int flag);
++char *BackSlashDecode(const char *s, const char *e);
++int BackSlash(const char *s, char *res);
+ #define ARGV_COMMENT  (1 << 0)
+ #define ARGV_COMMA    (1 << 1)
+@@ -65,6 +67,7 @@
+ int TCP_filter_http(int sock);
+ void TCP_blocking(int sock);
+ void TCP_nonblocking(int sock);
++void TCP_linger(int sock, int linger);
+ #ifdef SOL_SOCKET
+ void TCP_name(const struct sockaddr *addr, unsigned l, char *abuf,
+     unsigned alen, char *pbuf, unsigned plen);
+Index: include/vrt_obj.h
+===================================================================
+--- include/vrt_obj.h  (.../tags/varnish-2.0.4/varnish-cache)
++++ include/vrt_obj.h  (.../branches/2.0/varnish-cache)
+@@ -24,6 +24,8 @@
+ double VRT_r_req_grace(struct sess *);
+ void VRT_l_req_grace(struct sess *, double);
+ const char * VRT_r_req_xid(struct sess *);
++unsigned VRT_r_req_esi(struct sess *);
++void VRT_l_req_esi(struct sess *, unsigned);
+ const char * VRT_r_bereq_request(const struct sess *);
+ void VRT_l_bereq_request(const struct sess *, const char *, ...);
+ const char * VRT_r_bereq_url(const struct sess *);
+Index: include/shmlog_tags.h
+===================================================================
+--- include/shmlog_tags.h      (.../tags/varnish-2.0.4/varnish-cache)
++++ include/shmlog_tags.h      (.../branches/2.0/varnish-cache)
+@@ -101,3 +101,5 @@
+ SLTM(Hash)
+ SLTM(Backend_health)
++
++SLTM(FetchError)
+Index: include/vrt.h
+===================================================================
+--- include/vrt.h      (.../tags/varnish-2.0.4/varnish-cache)
++++ include/vrt.h      (.../branches/2.0/varnish-cache)
+@@ -54,6 +54,7 @@
+       double          interval;
+       unsigned        window;
+       unsigned        threshold;
++      unsigned        initial;
+ };
+ /*
+Index: include/stat_field.h
+===================================================================
+--- include/stat_field.h       (.../tags/varnish-2.0.4/varnish-cache)
++++ include/stat_field.h       (.../branches/2.0/varnish-cache)
+@@ -30,21 +30,33 @@
+  */
+ MAC_STAT(client_conn,         uint64_t, 'a', "Client connections accepted")
++MAC_STAT(client_drop,         uint64_t, 'a', "Connection dropped, no sess")
+ MAC_STAT(client_req,          uint64_t, 'a', "Client requests received")
+ MAC_STAT(cache_hit,           uint64_t, 'a', "Cache hits")
+ MAC_STAT(cache_hitpass,               uint64_t, 'a', "Cache hits for pass")
+ 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_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")
+-MAC_STAT(backend_recycle,     uint64_t, 'a', "Backend connections recycles")
+-MAC_STAT(backend_unused,      uint64_t, 'a', "Backend connections unused")
++MAC_STAT(backend_conn,                uint64_t, 'a', "Backend conn. success")
++MAC_STAT(backend_unhealthy,   uint64_t, 'a', "Backend conn. not attempted")
++MAC_STAT(backend_busy,                uint64_t, 'a', "Backend conn. too many")
++MAC_STAT(backend_fail,                uint64_t, 'a', "Backend conn. failures")
++MAC_STAT(backend_reuse,               uint64_t, 'a', "Backend conn. reuses")
++MAC_STAT(backend_toolate,     uint64_t, 'a', "Backend conn. was closed")
++MAC_STAT(backend_recycle,     uint64_t, 'a', "Backend conn. recycles")
++MAC_STAT(backend_unused,      uint64_t, 'a', "Backend conn. unused")
++
++MAC_STAT(fetch_head,          uint64_t, 'a', "Fetch head")
++MAC_STAT(fetch_length,                uint64_t, 'a', "Fetch with Length")
++MAC_STAT(fetch_chunked,               uint64_t, 'a', "Fetch chunked")
++MAC_STAT(fetch_eof,           uint64_t, 'a', "Fetch EOF")
++MAC_STAT(fetch_bad,           uint64_t, 'a', "Fetch had bad headers")
++MAC_STAT(fetch_close,         uint64_t, 'a', "Fetch wanted close")
++MAC_STAT(fetch_oldhttp,               uint64_t, 'a', "Fetch pre HTTP/1.1 closed")
++MAC_STAT(fetch_zero,          uint64_t, 'a', "Fetch zero len")
++MAC_STAT(fetch_failed,                uint64_t, 'a', "Fetch failed")
++
+ MAC_STAT(n_srcaddr,           uint64_t, 'i', "N struct srcaddr")
+ MAC_STAT(n_srcaddr_act,               uint64_t, 'i', "N active struct srcaddr")
+ MAC_STAT(n_sess_mem,          uint64_t, 'i', "N struct sess_mem")
+Index: include/Makefile.am
+===================================================================
+--- include/Makefile.am        (.../tags/varnish-2.0.4/varnish-cache)
++++ include/Makefile.am        (.../branches/2.0/varnish-cache)
+@@ -14,6 +14,7 @@
+       cli_priv.h \
+       compat/asprintf.h \
+       compat/daemon.h \
++      compat/execinfo.h \
+       compat/setproctitle.h \
+       compat/srandomdev.h \
+       compat/strlcat.h \
+Index: configure.ac
+===================================================================
+--- configure.ac       (.../tags/varnish-2.0.4/varnish-cache)
++++ configure.ac       (.../branches/2.0/varnish-cache)
+@@ -81,6 +81,7 @@
+ AC_CHECK_HEADERS([sys/statvfs.h])
+ AC_CHECK_HEADERS([sys/vfs.h])
+ AC_CHECK_HEADERS([endian.h])
++AC_CHECK_HEADERS([execinfo.h])
+ AC_CHECK_HEADERS([netinet/in.h])
+ AC_CHECK_HEADERS([pthread_np.h])
+ AC_CHECK_HEADERS([stddef.h])
+@@ -102,6 +103,7 @@
+ AC_FUNC_VPRINTF
+ AC_CHECK_FUNCS([strerror])
+ AC_FUNC_STRERROR_R
++AC_CHECK_FUNCS([dladdr])
+ AC_CHECK_FUNCS([socket])
+ AC_CHECK_FUNCS([strptime])
+ AC_CHECK_FUNCS([fmtcheck])
+@@ -360,6 +362,15 @@
+ fi
+ AC_DEFINE_UNQUOTED([VCC_CC],"$VCC_CC",[C compiler command line for VCL code])
++# Define HTTP_HDR_MAX_VAL
++AC_ARG_WITH(max-header-fields,
++            AS_HELP_STRING([--with-max-header-fields=NUM],
++                           [How many header fields to support (default=32)]),
++            [],
++            [with_max_header_fields=32])
++
++AC_DEFINE_UNQUOTED(HTTP_HDR_MAX_VAL, $with_max_header_fields, [Define maximum number of header fields supported by varnish ])
++
+ # Use jemalloc on Linux
+ JEMALLOC_SUBDIR=
+ JEMALLOC_LDADD=
+Index: lib/libvarnish/argv.c
+===================================================================
+--- lib/libvarnish/argv.c      (.../tags/varnish-2.0.4/varnish-cache)
++++ lib/libvarnish/argv.c      (.../branches/2.0/varnish-cache)
+@@ -43,11 +43,12 @@
+ #include <ctype.h>
+ #include <stdlib.h>
+ #include <stdio.h>
++#include <string.h>
+ #include <stdint.h>
+ #include "libvarnish.h"
+-static int
++int
+ BackSlash(const char *s, char *res)
+ {
+       int r;
+@@ -103,13 +104,16 @@
+       return (r);
+ }
+-static char *
++char *
+ BackSlashDecode(const char *s, const char *e)
+ {
+       const char *q;
+       char *p, *r;
+       int i;
++      if (e == NULL)
++              e = strchr(s, '\0');
++      assert(e != NULL);
+       p = calloc((e - s) + 1, 1);
+       if (p == NULL)
+               return (p);
+Index: lib/libvarnish/cli_common.c
+===================================================================
+--- lib/libvarnish/cli_common.c        (.../tags/varnish-2.0.4/varnish-cache)
++++ lib/libvarnish/cli_common.c        (.../branches/2.0/varnish-cache)
+@@ -73,7 +73,7 @@
+ cli_quote(struct cli *cli, const char *s)
+ {
+-      vsb_quote(cli->sb, s, 0);
++      vsb_quote(cli->sb, s, -1, 0);
+ }
+ void
+Index: lib/libvarnish/tcp.c
+===================================================================
+--- lib/libvarnish/tcp.c       (.../tags/varnish-2.0.4/varnish-cache)
++++ lib/libvarnish/tcp.c       (.../branches/2.0/varnish-cache)
+@@ -36,6 +36,10 @@
+ #include <netinet/in.h>
++#ifdef __linux
++#include <netinet/tcp.h>
++#endif
++
+ #include <errno.h>
+ #include <sys/ioctl.h>
+ #ifdef HAVE_SYS_FILIO_H
+@@ -113,6 +117,10 @@
+               printf("Acceptfilter(%d, httpready): %d %s\n",
+                   sock, i, strerror(errno));
+       return (i);
++#elif defined(__linux)
++      int defer = 1;
++      setsockopt(sock, SOL_TCP,TCP_DEFER_ACCEPT,(char *) &defer, sizeof(int));
++      return (0);
+ #else
+       (void)sock;
+       return (0);
+@@ -222,3 +230,17 @@
+       AZ(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof timeout));
+ #endif
+ }
++
++/*--------------------------------------------------------------------
++ * Set or reset SO_LINGER flag
++ */
++ 
++void
++TCP_linger(int sock, int linger)
++{
++      struct linger lin;
++
++      memset(&lin, 0, sizeof lin);
++      lin.l_onoff = linger;
++      AZ(setsockopt(sock, SOL_SOCKET, SO_LINGER, &lin, sizeof lin));
++}
+Index: lib/libvarnish/vsb.c
+===================================================================
+--- lib/libvarnish/vsb.c       (.../tags/varnish-2.0.4/varnish-cache)
++++ lib/libvarnish/vsb.c       (.../branches/2.0/varnish-cache)
+@@ -481,25 +481,27 @@
+  * Quote a string
+  */
+ void
+-vsb_quote(struct vsb *s, const char *p, int how)
++vsb_quote(struct vsb *s, const char *p, int len, int how)
+ {
+       const char *q;
+       int quote = 0;
+       (void)how;      /* For future enhancements */
++      if (len == -1)
++              len = strlen(p);
+-      for (q = p; *q != '\0'; q++) {
++      for (q = p; q < p + len; q++) {
+               if (!isgraph(*q) || *q == '"') {
+                       quote++;
+                       break;
+               }
+       }
+       if (!quote) {
+-              (void)vsb_cat(s, p);
++              (void)vsb_bcat(s, p, len);
+               return;
+       }
+       (void)vsb_putc(s, '"');
+-      for (q = p; *q != '\0'; q++) {
++      for (q = p; q < p + len; q++) {
+               switch (*q) {
+               case ' ':
+                       (void)vsb_putc(s, *q);
+@@ -522,9 +524,66 @@
+                       if (isgraph(*q))
+                               (void)vsb_putc(s, *q);
+                       else
+-                              (void)vsb_printf(s, "\\%o", *q);
++                              (void)vsb_printf(s, "\\%o", *q & 0xff);
+                       break;
+               }
+       }
+       (void)vsb_putc(s, '"');
+ }
++
++/*
++ * Unquote a string
++ */
++const char *
++vsb_unquote(struct vsb *s, const char *p, int len, int how)
++{
++      const char *q;
++      char *r;
++      unsigned long u;
++      char c;
++
++      (void)how;      /* For future enhancements */
++
++      if (len == -1)
++              len = strlen(p);
++
++      for (q = p; q < p + len; q++) {
++              if (*q != '\\') {
++                      (void)vsb_bcat(s, q, 1);
++                      continue;
++              }
++              if (++q >= p + len)
++                      return ("Incomplete '\\'-sequence at end of string");
++
++              switch(*q) {
++              case 'n':
++                      (void)vsb_bcat(s, "\n", 1);
++                      continue;
++              case 'r':
++                      (void)vsb_bcat(s, "\r", 1);
++                      continue;
++              case 't':
++                      (void)vsb_bcat(s, "\t", 1);
++                      continue;
++              case '0':
++              case '1':
++              case '2':
++              case '3':
++              case '4':
++              case '5':
++              case '6':
++              case '7':
++                      errno = 0;
++                      u = strtoul(q, &r, 8);
++                      if (errno != 0 || (u & ~0xff))
++                              return ("\\ooo sequence out of range");
++                      c = (char)u;
++                      (void)vsb_bcat(s, &c, 1);
++                      q = r - 1;
++                      continue;
++              default:
++                      (void)vsb_bcat(s, q, 1);
++              }
++      }
++      return (NULL);
++}
+Index: lib/libvarnishcompat/execinfo.c
+===================================================================
+--- lib/libvarnishcompat/execinfo.c    (.../tags/varnish-2.0.4/varnish-cache)
++++ lib/libvarnishcompat/execinfo.c    (.../branches/2.0/varnish-cache)
+@@ -0,0 +1,451 @@
++/*
++ * Copyright (c) 2003 Maxim Sobolev <sobomax@FreeBSD.org>
++ * 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.
++ *
++ * $Id$
++ */
++
++#include "config.h"
++
++#include <sys/types.h>
++#include <sys/uio.h>
++#include <dlfcn.h>
++#include <math.h>
++#include <stddef.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <unistd.h>
++
++#include "execinfo.h"
++
++void *getreturnaddr(int);
++void *getframeaddr(int);
++
++#define D10(x) ceil(log10(((x) == 0) ? 2 : ((x) + 1)))
++
++inline static void *
++realloc_safe(void *ptr, size_t size)
++{
++    void *nptr;
++
++    nptr = realloc(ptr, size);
++    if (nptr == NULL)
++        free(ptr);
++    return nptr;
++}
++
++int
++backtrace(void **buffer, int size)
++{
++    int i;
++
++    for (i = 1; getframeaddr(i + 1) != NULL && i != size + 1; i++) {
++        buffer[i - 1] = getreturnaddr(i);
++        if (buffer[i - 1] == NULL)
++            break;
++    }
++
++    return i - 1;
++}
++
++char **
++backtrace_symbols(void *const *buffer, int size)
++{
++    size_t clen, alen;
++    int i;
++    char **rval;
++
++    clen = size * sizeof(char *);
++    rval = malloc(clen);
++    if (rval == NULL)
++        return NULL;
++    for (i = 0; i < size; i++) {
++
++#ifdef HAVE_DLADDR
++    {
++        Dl_info info;
++      int offset;
++
++        if (dladdr(buffer[i], &info) != 0) {
++            if (info.dli_sname == NULL)
++                info.dli_sname = "???";
++            if (info.dli_saddr == NULL)
++                info.dli_saddr = buffer[i];
++            offset = (const char*)buffer[i] - (const char*)info.dli_saddr;
++            /* "0x01234567 <function+offset> at filename" */
++            alen = 2 +                      /* "0x" */
++                   (sizeof(void *) * 2) +   /* "01234567" */
++                   2 +                      /* " <" */
++                   strlen(info.dli_sname) + /* "function" */
++                   1 +                      /* "+" */
++                   10 +                     /* "offset */
++                   5 +                      /* "> at " */
++                   strlen(info.dli_fname) + /* "filename" */
++                   1;                       /* "\0" */
++            rval = realloc_safe(rval, clen + alen);
++            if (rval == NULL)
++                return NULL;
++            snprintf((char *) rval + clen, alen, "%p <%s+%d> at %s",
++              buffer[i], info.dli_sname, offset, info.dli_fname);
++            rval[i] = (char *) clen;
++            clen += alen;
++          continue;
++        } 
++    }
++#endif
++      alen = 2 +                      /* "0x" */
++             (sizeof(void *) * 2) +   /* "01234567" */
++             1;                       /* "\0" */
++      rval = realloc_safe(rval, clen + alen);
++      if (rval == NULL)
++          return NULL;
++      snprintf((char *) rval + clen, alen, "%p", buffer[i]);
++        rval[i] = (char *) clen;
++        clen += alen;
++    }
++
++    for (i = 0; i < size; i++)
++        rval[i] += (long) rval;
++
++    return rval;
++}
++
++#if 0
++void
++backtrace_symbols_fd(void *const *buffer, int size, int fd)
++{
++    int i, len, offset;
++    char *buf;
++    Dl_info info;
++
++    for (i = 0; i < size; i++) {
++        if (dladdr(buffer[i], &info) != 0) {
++            if (info.dli_sname == NULL)
++                info.dli_sname = "???";
++            if (info.dli_saddr == NULL)
++                info.dli_saddr = buffer[i];
++            offset = (const char *)buffer[i] - (const char *)info.dli_saddr;
++            /* "0x01234567 <function+offset> at filename" */
++            len = 2 +                      /* "0x" */
++                  (sizeof(void *) * 2) +   /* "01234567" */
++                  2 +                      /* " <" */
++                  strlen(info.dli_sname) + /* "function" */
++                  1 +                      /* "+" */
++                  D10(offset) +            /* "offset */
++                  5 +                      /* "> at " */
++                  strlen(info.dli_fname) + /* "filename" */
++                  2;                       /* "\n\0" */
++            buf = alloca(len);
++            if (buf == NULL)
++                return;
++            snprintf(buf, len, "%p <%s+%d> at %s\n",
++              buffer[i], info.dli_sname, offset, info.dli_fname);
++        } else {
++            len = 2 +                      /* "0x" */
++                  (sizeof(void *) * 2) +   /* "01234567" */
++                  2;                       /* "\n\0" */
++            buf = alloca(len);
++            if (buf == NULL)
++                return;
++            snprintf(buf, len, "%p\n", buffer[i]);
++        }
++        write(fd, buf, len - 1);
++    }
++}
++#endif
++
++void *
++getreturnaddr(int level)
++{
++
++    switch(level) {
++    case 0: return __builtin_return_address(1);
++    case 1: return __builtin_return_address(2);
++    case 2: return __builtin_return_address(3);
++    case 3: return __builtin_return_address(4);
++    case 4: return __builtin_return_address(5);
++    case 5: return __builtin_return_address(6);
++    case 6: return __builtin_return_address(7);
++    case 7: return __builtin_return_address(8);
++    case 8: return __builtin_return_address(9);
++    case 9: return __builtin_return_address(10);
++    case 10: return __builtin_return_address(11);
++    case 11: return __builtin_return_address(12);
++    case 12: return __builtin_return_address(13);
++    case 13: return __builtin_return_address(14);
++    case 14: return __builtin_return_address(15);
++    case 15: return __builtin_return_address(16);
++    case 16: return __builtin_return_address(17);
++    case 17: return __builtin_return_address(18);
++    case 18: return __builtin_return_address(19);
++    case 19: return __builtin_return_address(20);
++    case 20: return __builtin_return_address(21);
++    case 21: return __builtin_return_address(22);
++    case 22: return __builtin_return_address(23);
++    case 23: return __builtin_return_address(24);
++    case 24: return __builtin_return_address(25);
++    case 25: return __builtin_return_address(26);
++    case 26: return __builtin_return_address(27);
++    case 27: return __builtin_return_address(28);
++    case 28: return __builtin_return_address(29);
++    case 29: return __builtin_return_address(30);
++    case 30: return __builtin_return_address(31);
++    case 31: return __builtin_return_address(32);
++    case 32: return __builtin_return_address(33);
++    case 33: return __builtin_return_address(34);
++    case 34: return __builtin_return_address(35);
++    case 35: return __builtin_return_address(36);
++    case 36: return __builtin_return_address(37);
++    case 37: return __builtin_return_address(38);
++    case 38: return __builtin_return_address(39);
++    case 39: return __builtin_return_address(40);
++    case 40: return __builtin_return_address(41);
++    case 41: return __builtin_return_address(42);
++    case 42: return __builtin_return_address(43);
++    case 43: return __builtin_return_address(44);
++    case 44: return __builtin_return_address(45);
++    case 45: return __builtin_return_address(46);
++    case 46: return __builtin_return_address(47);
++    case 47: return __builtin_return_address(48);
++    case 48: return __builtin_return_address(49);
++    case 49: return __builtin_return_address(50);
++    case 50: return __builtin_return_address(51);
++    case 51: return __builtin_return_address(52);
++    case 52: return __builtin_return_address(53);
++    case 53: return __builtin_return_address(54);
++    case 54: return __builtin_return_address(55);
++    case 55: return __builtin_return_address(56);
++    case 56: return __builtin_return_address(57);
++    case 57: return __builtin_return_address(58);
++    case 58: return __builtin_return_address(59);
++    case 59: return __builtin_return_address(60);
++    case 60: return __builtin_return_address(61);
++    case 61: return __builtin_return_address(62);
++    case 62: return __builtin_return_address(63);
++    case 63: return __builtin_return_address(64);
++    case 64: return __builtin_return_address(65);
++    case 65: return __builtin_return_address(66);
++    case 66: return __builtin_return_address(67);
++    case 67: return __builtin_return_address(68);
++    case 68: return __builtin_return_address(69);
++    case 69: return __builtin_return_address(70);
++    case 70: return __builtin_return_address(71);
++    case 71: return __builtin_return_address(72);
++    case 72: return __builtin_return_address(73);
++    case 73: return __builtin_return_address(74);
++    case 74: return __builtin_return_address(75);
++    case 75: return __builtin_return_address(76);
++    case 76: return __builtin_return_address(77);
++    case 77: return __builtin_return_address(78);
++    case 78: return __builtin_return_address(79);
++    case 79: return __builtin_return_address(80);
++    case 80: return __builtin_return_address(81);
++    case 81: return __builtin_return_address(82);
++    case 82: return __builtin_return_address(83);
++    case 83: return __builtin_return_address(84);
++    case 84: return __builtin_return_address(85);
++    case 85: return __builtin_return_address(86);
++    case 86: return __builtin_return_address(87);
++    case 87: return __builtin_return_address(88);
++    case 88: return __builtin_return_address(89);
++    case 89: return __builtin_return_address(90);
++    case 90: return __builtin_return_address(91);
++    case 91: return __builtin_return_address(92);
++    case 92: return __builtin_return_address(93);
++    case 93: return __builtin_return_address(94);
++    case 94: return __builtin_return_address(95);
++    case 95: return __builtin_return_address(96);
++    case 96: return __builtin_return_address(97);
++    case 97: return __builtin_return_address(98);
++    case 98: return __builtin_return_address(99);
++    case 99: return __builtin_return_address(100);
++    case 100: return __builtin_return_address(101);
++    case 101: return __builtin_return_address(102);
++    case 102: return __builtin_return_address(103);
++    case 103: return __builtin_return_address(104);
++    case 104: return __builtin_return_address(105);
++    case 105: return __builtin_return_address(106);
++    case 106: return __builtin_return_address(107);
++    case 107: return __builtin_return_address(108);
++    case 108: return __builtin_return_address(109);
++    case 109: return __builtin_return_address(110);
++    case 110: return __builtin_return_address(111);
++    case 111: return __builtin_return_address(112);
++    case 112: return __builtin_return_address(113);
++    case 113: return __builtin_return_address(114);
++    case 114: return __builtin_return_address(115);
++    case 115: return __builtin_return_address(116);
++    case 116: return __builtin_return_address(117);
++    case 117: return __builtin_return_address(118);
++    case 118: return __builtin_return_address(119);
++    case 119: return __builtin_return_address(120);
++    case 120: return __builtin_return_address(121);
++    case 121: return __builtin_return_address(122);
++    case 122: return __builtin_return_address(123);
++    case 123: return __builtin_return_address(124);
++    case 124: return __builtin_return_address(125);
++    case 125: return __builtin_return_address(126);
++    case 126: return __builtin_return_address(127);
++    case 127: return __builtin_return_address(128);
++    default: return NULL;
++    }
++}
++
++void *
++getframeaddr(int level)
++{
++
++    switch(level) {
++    case 0: return __builtin_frame_address(1);
++    case 1: return __builtin_frame_address(2);
++    case 2: return __builtin_frame_address(3);
++    case 3: return __builtin_frame_address(4);
++    case 4: return __builtin_frame_address(5);
++    case 5: return __builtin_frame_address(6);
++    case 6: return __builtin_frame_address(7);
++    case 7: return __builtin_frame_address(8);
++    case 8: return __builtin_frame_address(9);
++    case 9: return __builtin_frame_address(10);
++    case 10: return __builtin_frame_address(11);
++    case 11: return __builtin_frame_address(12);
++    case 12: return __builtin_frame_address(13);
++    case 13: return __builtin_frame_address(14);
++    case 14: return __builtin_frame_address(15);
++    case 15: return __builtin_frame_address(16);
++    case 16: return __builtin_frame_address(17);
++    case 17: return __builtin_frame_address(18);
++    case 18: return __builtin_frame_address(19);
++    case 19: return __builtin_frame_address(20);
++    case 20: return __builtin_frame_address(21);
++    case 21: return __builtin_frame_address(22);
++    case 22: return __builtin_frame_address(23);
++    case 23: return __builtin_frame_address(24);
++    case 24: return __builtin_frame_address(25);
++    case 25: return __builtin_frame_address(26);
++    case 26: return __builtin_frame_address(27);
++    case 27: return __builtin_frame_address(28);
++    case 28: return __builtin_frame_address(29);
++    case 29: return __builtin_frame_address(30);
++    case 30: return __builtin_frame_address(31);
++    case 31: return __builtin_frame_address(32);
++    case 32: return __builtin_frame_address(33);
++    case 33: return __builtin_frame_address(34);
++    case 34: return __builtin_frame_address(35);
++    case 35: return __builtin_frame_address(36);
++    case 36: return __builtin_frame_address(37);
++    case 37: return __builtin_frame_address(38);
++    case 38: return __builtin_frame_address(39);
++    case 39: return __builtin_frame_address(40);
++    case 40: return __builtin_frame_address(41);
++    case 41: return __builtin_frame_address(42);
++    case 42: return __builtin_frame_address(43);
++    case 43: return __builtin_frame_address(44);
++    case 44: return __builtin_frame_address(45);
++    case 45: return __builtin_frame_address(46);
++    case 46: return __builtin_frame_address(47);
++    case 47: return __builtin_frame_address(48);
++    case 48: return __builtin_frame_address(49);
++    case 49: return __builtin_frame_address(50);
++    case 50: return __builtin_frame_address(51);
++    case 51: return __builtin_frame_address(52);
++    case 52: return __builtin_frame_address(53);
++    case 53: return __builtin_frame_address(54);
++    case 54: return __builtin_frame_address(55);
++    case 55: return __builtin_frame_address(56);
++    case 56: return __builtin_frame_address(57);
++    case 57: return __builtin_frame_address(58);
++    case 58: return __builtin_frame_address(59);
++    case 59: return __builtin_frame_address(60);
++    case 60: return __builtin_frame_address(61);
++    case 61: return __builtin_frame_address(62);
++    case 62: return __builtin_frame_address(63);
++    case 63: return __builtin_frame_address(64);
++    case 64: return __builtin_frame_address(65);
++    case 65: return __builtin_frame_address(66);
++    case 66: return __builtin_frame_address(67);
++    case 67: return __builtin_frame_address(68);
++    case 68: return __builtin_frame_address(69);
++    case 69: return __builtin_frame_address(70);
++    case 70: return __builtin_frame_address(71);
++    case 71: return __builtin_frame_address(72);
++    case 72: return __builtin_frame_address(73);
++    case 73: return __builtin_frame_address(74);
++    case 74: return __builtin_frame_address(75);
++    case 75: return __builtin_frame_address(76);
++    case 76: return __builtin_frame_address(77);
++    case 77: return __builtin_frame_address(78);
++    case 78: return __builtin_frame_address(79);
++    case 79: return __builtin_frame_address(80);
++    case 80: return __builtin_frame_address(81);
++    case 81: return __builtin_frame_address(82);
++    case 82: return __builtin_frame_address(83);
++    case 83: return __builtin_frame_address(84);
++    case 84: return __builtin_frame_address(85);
++    case 85: return __builtin_frame_address(86);
++    case 86: return __builtin_frame_address(87);
++    case 87: return __builtin_frame_address(88);
++    case 88: return __builtin_frame_address(89);
++    case 89: return __builtin_frame_address(90);
++    case 90: return __builtin_frame_address(91);
++    case 91: return __builtin_frame_address(92);
++    case 92: return __builtin_frame_address(93);
++    case 93: return __builtin_frame_address(94);
++    case 94: return __builtin_frame_address(95);
++    case 95: return __builtin_frame_address(96);
++    case 96: return __builtin_frame_address(97);
++    case 97: return __builtin_frame_address(98);
++    case 98: return __builtin_frame_address(99);
++    case 99: return __builtin_frame_address(100);
++    case 100: return __builtin_frame_address(101);
++    case 101: return __builtin_frame_address(102);
++    case 102: return __builtin_frame_address(103);
++    case 103: return __builtin_frame_address(104);
++    case 104: return __builtin_frame_address(105);
++    case 105: return __builtin_frame_address(106);
++    case 106: return __builtin_frame_address(107);
++    case 107: return __builtin_frame_address(108);
++    case 108: return __builtin_frame_address(109);
++    case 109: return __builtin_frame_address(110);
++    case 110: return __builtin_frame_address(111);
++    case 111: return __builtin_frame_address(112);
++    case 112: return __builtin_frame_address(113);
++    case 113: return __builtin_frame_address(114);
++    case 114: return __builtin_frame_address(115);
++    case 115: return __builtin_frame_address(116);
++    case 116: return __builtin_frame_address(117);
++    case 117: return __builtin_frame_address(118);
++    case 118: return __builtin_frame_address(119);
++    case 119: return __builtin_frame_address(120);
++    case 120: return __builtin_frame_address(121);
++    case 121: return __builtin_frame_address(122);
++    case 122: return __builtin_frame_address(123);
++    case 123: return __builtin_frame_address(124);
++    case 124: return __builtin_frame_address(125);
++    case 125: return __builtin_frame_address(126);
++    case 126: return __builtin_frame_address(127);
++    case 127: return __builtin_frame_address(128);
++    default: return NULL;
++    }
++}
+Index: lib/libvarnishcompat/Makefile.am
+===================================================================
+--- lib/libvarnishcompat/Makefile.am   (.../tags/varnish-2.0.4/varnish-cache)
++++ lib/libvarnishcompat/Makefile.am   (.../branches/2.0/varnish-cache)
+@@ -9,6 +9,7 @@
+ libvarnishcompat_la_SOURCES = \
+       asprintf.c \
+       daemon.c \
++      execinfo.c \
+       vasprintf.c \
+       setproctitle.c \
+       srandomdev.c \
+Index: lib/libvcl/vcc_gen_obj.tcl
+===================================================================
+--- lib/libvcl/vcc_gen_obj.tcl (.../tags/varnish-2.0.4/varnish-cache)
++++ lib/libvcl/vcc_gen_obj.tcl (.../branches/2.0/varnish-cache)
+@@ -116,6 +116,12 @@
+       "struct sess *"
+     }
++    { req.esi
++      RW BOOL
++      {recv fetch deliver                                        error}
++      "struct sess *"
++    }
++
+     # Request sent to backend
+     { bereq.request
+       RW STRING
+Index: lib/libvcl/vcc_parse.c
+===================================================================
+--- lib/libvcl/vcc_parse.c     (.../tags/varnish-2.0.4/varnish-cache)
++++ lib/libvcl/vcc_parse.c     (.../branches/2.0/varnish-cache)
+@@ -263,10 +263,11 @@
+               Fb(tl, 1, "%sVRT_strcmp(%s, ",
+                   tl->t->tok == T_EQ ? "!" : "", vp->rname);
+               vcc_NextToken(tl);
+-              ExpectErr(tl, CSTR);
+-              EncToken(tl->fb, tl->t);
++              if (!vcc_StringVal(tl)) {
++                      vcc_ExpectedStringval(tl);
++                      break;
++              }
+               Fb(tl, 0, ")\n");
+-              vcc_NextToken(tl);
+               break;
+       default:
+               Fb(tl, 1, "%s != (void*)0\n", vp->rname);
+Index: lib/libvcl/vcc_obj.c
+===================================================================
+--- lib/libvcl/vcc_obj.c       (.../tags/varnish-2.0.4/varnish-cache)
++++ lib/libvcl/vcc_obj.c       (.../branches/2.0/varnish-cache)
+@@ -102,6 +102,11 @@
+            | VCL_MET_MISS | VCL_MET_HIT | VCL_MET_FETCH | VCL_MET_DELIVER
+            | VCL_MET_ERROR
+       },
++      { "req.esi", BOOL, 7,
++          "VRT_r_req_esi(sp)",            "VRT_l_req_esi(sp, ",
++          V_RW,           0,
++          VCL_MET_RECV | 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,
+Index: lib/libvcl/vcc_backend.c
+===================================================================
+--- lib/libvcl/vcc_backend.c   (.../tags/varnish-2.0.4/varnish-cache)
++++ lib/libvcl/vcc_backend.c   (.../branches/2.0/varnish-cache)
+@@ -340,7 +340,8 @@
+       struct fld_spec *fs;
+       struct token *t_field;
+       struct token *t_did = NULL, *t_window = NULL, *t_threshold = NULL;
+-      unsigned window, threshold;
++      struct token *t_initial = NULL;
++      unsigned window, threshold, initial;
+       fs = vcc_FldSpec(tl,
+           "?url",
+@@ -349,6 +350,7 @@
+           "?interval",
+           "?window",
+           "?threshold",
++          "?initial",
+           NULL);
+       ExpectErr(tl, '{');
+@@ -356,6 +358,7 @@
+       window = 0;
+       threshold = 0;
++      initial = 0;
+       Fb(tl, 0, "\t.probe = {\n");
+       while (tl->t->tok != '}') {
+@@ -396,6 +399,11 @@
+                       window = vcc_UintVal(tl);
+                       vcc_NextToken(tl);
+                       ERRCHK(tl);
++              } else if (vcc_IdIs(t_field, "initial")) {
++                      t_initial = tl->t;
++                      initial = vcc_UintVal(tl);
++                      vcc_NextToken(tl);
++                      ERRCHK(tl);
+               } else if (vcc_IdIs(t_field, "threshold")) {
+                       t_threshold = tl->t;
+                       threshold = vcc_UintVal(tl);
+@@ -441,8 +449,12 @@
+                       vcc_ErrWhere(tl, t_window);
+               }
+               Fb(tl, 0, "\t\t.window = %u,\n", window);
+-              Fb(tl, 0, "\t\t.threshold = %u\n", threshold);
++              Fb(tl, 0, "\t\t.threshold = %u,\n", threshold);
+       }
++      if (t_initial != NULL) 
++              Fb(tl, 0, "\t\t.initial = %u,\n", initial);
++      else
++              Fb(tl, 0, "\t\t.initial = ~0U,\n", initial);
+       Fb(tl, 0, "\t},\n");
+       ExpectErr(tl, '}');
+       vcc_NextToken(tl);
+Index: lib/libvcl/vcc_fixed_token.c
+===================================================================
+--- lib/libvcl/vcc_fixed_token.c       (.../tags/varnish-2.0.4/varnish-cache)
++++ lib/libvcl/vcc_fixed_token.c       (.../branches/2.0/varnish-cache)
+@@ -235,8 +235,8 @@
+       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 3724 2009-02-10 14:");
+-      vsb_cat(sb, "58:17Z tfheen $\n *\n * Runtime support for compiled V");
++      vsb_cat(sb, " * SUCH DAMAGE.\n *\n * $Id: vrt.h 4303 2009-10-08 13:");
++      vsb_cat(sb, "58:25Z tfheen $\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");
+@@ -247,12 +247,12 @@
+       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, " */\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, "\tunsigned\tthreshold;\n\tunsigned\tinitial;\n");
++      vsb_cat(sb, "};\n\n/*\n * A backend is a host+port somewhere on the");
++      vsb_cat(sb, " network\n */\nstruct vrt_backend {\n");
++      vsb_cat(sb, "\tconst char\t\t\t*vcl_name;\n\tconst char\t\t\t*ident");
++      vsb_cat(sb, ";\n\n\tconst char\t\t\t*hosthdr;\n");
++      vsb_cat(sb, "\n\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");
+@@ -324,9 +324,9 @@
+       /* ../../include/vrt_obj.h */
+-      vsb_cat(sb, "/*\n * $Id: vrt_obj.h 3990 2009-03-23 12:37:42Z tfheen");
+-      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 * $Id: vcc_gen_obj.tcl 4082 2009-05-19 07:14:00Z ");
++      vsb_cat(sb, "sky $\n *\n * NB:  This file is machine generated, DO ");
++      vsb_cat(sb, "NOT 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 *);\nconst char * VRT_r_server_hostname(struct sess ");
+@@ -345,6 +345,8 @@
+       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, "unsigned VRT_r_req_esi(struct sess *);\n");
++      vsb_cat(sb, "void VRT_l_req_esi(struct sess *, unsigned);\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");
+Index: lib/libvcl/vcc_acl.c
+===================================================================
+--- lib/libvcl/vcc_acl.c       (.../tags/varnish-2.0.4/varnish-cache)
++++ lib/libvcl/vcc_acl.c       (.../branches/2.0/varnish-cache)
+@@ -250,14 +250,18 @@
+ {
+       unsigned char b[4];
+       int i, j, k;
++      unsigned u;
+       const char *p;
+       memset(b, 0, sizeof b);
+       p = ae->t_addr->dec;
+       for (i = 0; i < 4; i++) {
+-              j = sscanf(p, "%hhu%n", &b[i], &k);
++              j = sscanf(p, "%u%n", &u, &k);
+               if (j != 1)
+                       return (0);
++              if (u & ~0xff)
++                      return (0);
++              b[i] = (unsigned char)u;
+               if (p[k] == '\0')
+                       break;
+               if (p[k] != '.')
+Index: bin/varnishreplay/varnishreplay.c
+===================================================================
+--- bin/varnishreplay/varnishreplay.c  (.../tags/varnish-2.0.4/varnish-cache)
++++ bin/varnishreplay/varnishreplay.c  (.../branches/2.0/varnish-cache)
+@@ -190,7 +190,7 @@
+       pthread_mutex_unlock(&log_mutex);
+ }
+-struct thread {
++struct replay_thread {
+       pthread_t thread_id;
+       struct mailbox mbox;
+@@ -212,14 +212,14 @@
+       char temp[2048];
+ };
+-static struct thread **threads;
++static struct replay_thread **threads;
+ static size_t nthreads;
+ /*
+  * Clear thread state
+  */
+ static void
+-thread_clear(struct thread *thr)
++thread_clear(struct replay_thread *thr)
+ {
+       thr->method = thr->proto = thr->url = NULL;
+@@ -236,17 +236,17 @@
+       thr->sock = -1;
+ }
+-#define THREAD_FAIL ((struct thread *)-1)
++#define THREAD_FAIL ((struct replay_thread *)-1)
+ static pthread_attr_t thread_attr;
+-static struct thread *
++static struct replay_thread *
+ thread_get(int fd, void *(*thread_main)(void *))
+ {
+       assert(fd != 0);
+       if (fd >= nthreads) {
+-              struct thread **newthreads = threads;
++              struct replay_thread **newthreads = threads;
+               size_t newnthreads = nthreads;
+               while (fd >= newnthreads)
+@@ -309,7 +309,7 @@
+  * Allocate from thread arena
+  */
+ static void *
+-thread_alloc(struct thread *thr, size_t len)
++thread_alloc(struct replay_thread *thr, size_t len)
+ {
+       void *ptr;
+@@ -325,7 +325,7 @@
+  * trimmed.
+  */
+ static char *
+-trimline(struct thread *thr, const char *str)
++trimline(struct replay_thread *thr, const char *str)
+ {
+       size_t len;
+       char *p;
+@@ -355,7 +355,7 @@
+  * A line is terminated by \r\n
+  */
+ static int
+-read_line(struct thread *thr)
++read_line(struct replay_thread *thr)
+ {
+       int i, len;
+@@ -389,7 +389,7 @@
+  * the number of bytes read.
+  */
+ static int
+-read_block(struct thread *thr, int len)
++read_block(struct replay_thread *thr, int len)
+ {
+       int n, r, tot;
+@@ -412,7 +412,7 @@
+ /* Receive the response after sending a request.
+  */
+ static int
+-receive_response(struct thread *thr)
++receive_response(struct replay_thread *thr)
+ {
+       const char *next;
+       int line_len;
+@@ -496,7 +496,7 @@
+ {
+       struct iovec iov[6];
+       char space[1] = " ", crlf[2] = "\r\n";
+-      struct thread *thr = arg;
++      struct replay_thread *thr = arg;
+       struct message *msg;
+       enum shmlogtag tag;
+       size_t len;
+@@ -642,7 +642,7 @@
+ gen_traffic(void *priv, enum shmlogtag tag, unsigned fd,
+     unsigned len, unsigned spec, const char *ptr)
+ {
+-      struct thread *thr;
++      struct replay_thread *thr;
+       const char *end;
+       struct message *msg;
+Index: bin/varnishtest/tests/r00354.vtc
+===================================================================
+--- bin/varnishtest/tests/r00354.vtc   (.../tags/varnish-2.0.4/varnish-cache)
++++ bin/varnishtest/tests/r00354.vtc   (.../branches/2.0/varnish-cache)
+@@ -1,16 +0,0 @@
+-# $Id$
+-
+-test "#354 Segfault in strcmp in http_DissectRequest()"
+-
+-server s1 {
+-      rxreq
+-      txresp
+-}
+-
+-varnish v1 -vcl+backend {} -start
+-
+-client c1 {
+-      send "FOO\r\n\r\n"
+-      rxresp
+-      expect resp.status == 400
+-} -run
+Index: bin/varnishtest/tests/r00494.vtc
+===================================================================
+--- bin/varnishtest/tests/r00494.vtc   (.../tags/varnish-2.0.4/varnish-cache)
++++ bin/varnishtest/tests/r00494.vtc   (.../branches/2.0/varnish-cache)
+@@ -0,0 +1,27 @@
++# $Id$
++
++test "HTTP continuation lines"
++
++#NB: careful about spaces and tabs in this test.
++
++server s1 {
++      rxreq
++      txresp -hdr {Foo: bar,
++      barf: fail} -body "xxx"
++} -start
++
++varnish v1 -vcl+backend {
++      sub vcl_fetch {
++              set obj.http.bar = obj.http.foo;
++              remove obj.http.foo;
++      }
++} -start
++
++client c1 {
++      txreq
++      rxresp
++      expect resp.http.bar == "bar,  barf: fail"
++      expect resp.http.barf == resp.http.barf
++      expect resp.http.foo == resp.http.foo
++} -run
++
+Index: bin/varnishtest/tests/r00498.vtc
+===================================================================
+--- bin/varnishtest/tests/r00498.vtc   (.../tags/varnish-2.0.4/varnish-cache)
++++ bin/varnishtest/tests/r00498.vtc   (.../branches/2.0/varnish-cache)
+@@ -0,0 +1,18 @@
++# $Id$
++
++test "very very very long return header"
++
++server s1 {
++      rxreq
++      expect req.url == "/"
++      txresp -hdr "Location: 111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111" -body {foo}
++} -start
++
++varnish v1 -vcl+backend {
++} -start
++
++client c1 {
++      txreq 
++      rxresp
++      expect resp.bodylen == 3
++} -run
+Index: bin/varnishtest/tests/b00029.vtc
+===================================================================
+--- bin/varnishtest/tests/b00029.vtc   (.../tags/varnish-2.0.4/varnish-cache)
++++ bin/varnishtest/tests/b00029.vtc   (.../branches/2.0/varnish-cache)
+@@ -0,0 +1,18 @@
++# $Id$
++
++test "Test orderly connection closure"
++
++
++server s1 {
++      rxreq
++      txresp -bodylen 130000
++} -start
++
++varnish v1 -vcl+backend { } -start
++
++client c1 {
++      txreq -hdr "Connection: close"
++      delay 3
++      rxresp
++      expect resp.bodylen == 130000
++} -run
+Index: bin/varnishtest/tests/r00502.vtc
+===================================================================
+--- bin/varnishtest/tests/r00502.vtc   (.../tags/varnish-2.0.4/varnish-cache)
++++ bin/varnishtest/tests/r00502.vtc   (.../branches/2.0/varnish-cache)
+@@ -0,0 +1,30 @@
++# $Id$
++
++test "multi element purge"
++
++server s1 {
++      rxreq
++      txresp -hdr "foo: bar1" -body "1"
++      rxreq
++      txresp -hdr "foo: bar2" -body "22"
++} -start
++
++varnish v1 -vcl+backend {
++      sub vcl_recv {
++              purge("req.url == / && obj.http.foo ~ bar1");
++      }
++} -start
++
++client c1 {
++      txreq
++      rxresp
++      expect resp.http.foo == "bar1"
++      txreq
++      rxresp
++      expect resp.http.foo == "bar2"
++      txreq
++      rxresp
++      expect resp.http.foo == "bar2"
++} -run
++
++varnish v1 -cliok purge.list
+Index: bin/varnishtest/tests/v00024.vtc
+===================================================================
+--- bin/varnishtest/tests/v00024.vtc   (.../tags/varnish-2.0.4/varnish-cache)
++++ bin/varnishtest/tests/v00024.vtc   (.../branches/2.0/varnish-cache)
+@@ -0,0 +1,27 @@
++# $Id$
++
++test "Test that headers can be compared"
++
++server s1 {
++      rxreq
++      expect req.url == "/foo"
++      txresp -status 200 -body "1"
++} -start
++
++varnish v1 -vcl+backend { 
++      sub vcl_recv {
++              if (req.http.etag == req.http.if-none-match) {
++                      error 400 "FOO";
++              }
++      }
++} -start
++
++client c1 {
++      txreq -url "/foo"
++      rxresp
++      expect resp.status == 200
++      expect resp.bodylen == 1
++      txreq -url "/foo" -hdr "etag: foo" -hdr "if-none-match: foo"
++      rxresp
++      expect resp.status == 400
++} -run
+Index: bin/varnishtest/tests/r00506.vtc
+===================================================================
+--- bin/varnishtest/tests/r00506.vtc   (.../tags/varnish-2.0.4/varnish-cache)
++++ bin/varnishtest/tests/r00506.vtc   (.../branches/2.0/varnish-cache)
+@@ -0,0 +1,18 @@
++# $Id$
++
++test "Illegal HTTP status from backend"
++
++server s1 {
++      rxreq
++      send "HTTP/1.1 1000\n\nFoo"
++} -start
++
++varnish v1 -vcl+backend {
++      sub vcl_recv {
++      }
++} -start
++
++client c1 {
++      txreq
++      rxresp
++} -run
+Index: bin/varnishtest/tests/r00549.vtc
+===================================================================
+--- bin/varnishtest/tests/r00549.vtc   (.../tags/varnish-2.0.4/varnish-cache)
++++ bin/varnishtest/tests/r00549.vtc   (.../branches/2.0/varnish-cache)
+@@ -0,0 +1,15 @@
++# $Id$
++
++# Regression test for bad backend reply with ctrl char.
++
++server s1 {
++      rxreq
++      send "HTTP/1.1 200 OK\013\r\n\r\nTest"
++} -start
++
++varnish v1 -vcl+backend {} -start
++
++client c1 {
++      txreq
++      rxresp
++} -run
+Index: bin/varnishtest/tests/c00025.vtc
+===================================================================
+--- bin/varnishtest/tests/c00025.vtc   (.../tags/varnish-2.0.4/varnish-cache)
++++ bin/varnishtest/tests/c00025.vtc   (.../branches/2.0/varnish-cache)
+@@ -0,0 +1,33 @@
++# $Id$
++
++test "Test If-None-Match"
++
++server s1 {
++      rxreq
++      expect req.url == "/foo"
++      txresp -hdr "ETag: 123456789" \
++          -body "11111\n"
++} -start
++
++varnish v1 -vcl+backend { } -start
++
++client c1 {
++      txreq -url "/foo"
++      rxresp
++      expect resp.status == 200
++      expect resp.http.content-length == 6
++
++      txreq -url "/foo" \
++          -hdr "If-None-Match: 12345678"
++      rxresp
++      expect resp.status == 200
++
++      txreq -url "/foo" \
++          -hdr "If-None-Match: 123456789"
++      rxresp
++      expect resp.status == 304
++} 
++
++client c1 -run
++
++client c1 -run
+Index: bin/varnishtest/tests/r00558.vtc
+===================================================================
+--- bin/varnishtest/tests/r00558.vtc   (.../tags/varnish-2.0.4/varnish-cache)
++++ bin/varnishtest/tests/r00558.vtc   (.../branches/2.0/varnish-cache)
+@@ -0,0 +1,19 @@
++# $Id$
++
++test "error from vcl_recv{} has no numeric code"
++
++
++server s1 {
++}
++
++varnish v1 -vcl+backend {
++      sub vcl_recv {
++              return (error);
++      }
++} -start
++
++client c1 {
++      txreq
++      rxresp
++      expect resp.status == 501
++} -run
+Index: bin/varnishtest/tests/e00016.vtc
+===================================================================
+--- bin/varnishtest/tests/e00016.vtc   (.../tags/varnish-2.0.4/varnish-cache)
++++ bin/varnishtest/tests/e00016.vtc   (.../branches/2.0/varnish-cache)
+@@ -0,0 +1,49 @@
++# $Id$
++
++test "ESI request can't be turned off midstream"
++
++server s1 {
++      rxreq 
++      txresp -body {
++              <html>
++              Before include
++              <esi:include src="/body"/>
++              <esi:include src="/body3"/>
++              After include
++      }
++      rxreq 
++      expect req.url == "/body"
++      txresp -body {
++             <esi:include src="/body2"/>
++      }
++      rxreq
++      expect req.url == "/body2"
++      txresp -body {
++             included
++      }
++      rxreq
++      expect req.url == "/body3"
++      txresp -body {
++             included body3
++      }
++} -start
++
++varnish v1 -vcl+backend {
++      sub vcl_fetch {
++              set req.esi = true;     
++              if(req.url == "/body") {
++                 set req.esi = false;
++              } 
++              esi;
++      }
++} -start
++
++client c1 {
++        txreq
++      rxresp
++      expect resp.bodylen == 105
++      expect resp.status == 200
++}
++
++client c1 -run
++varnish v1 -expect esi_errors == 0
+Index: bin/varnishtest/tests/r00561.vtc
+===================================================================
+--- bin/varnishtest/tests/r00561.vtc   (.../tags/varnish-2.0.4/varnish-cache)
++++ bin/varnishtest/tests/r00561.vtc   (.../branches/2.0/varnish-cache)
+@@ -0,0 +1,25 @@
++# $Id$
++
++test "Junk request should not go to vcl_error"
++
++server s1 {
++      rxreq
++      txresp
++} -start
++
++varnish v1 -vcl+backend {
++      sub vcl_error {
++              return (restart);
++      }
++} -start
++
++client c1 {
++      send "sljdslf\r\n\r\n"
++      delay .1
++} -run
++
++client c1 {
++      txreq 
++      rxresp
++} -run
++
+Index: bin/varnishtest/tests/c00008.vtc
+===================================================================
+--- bin/varnishtest/tests/c00008.vtc   (.../tags/varnish-2.0.4/varnish-cache)
++++ bin/varnishtest/tests/c00008.vtc   (.../branches/2.0/varnish-cache)
+@@ -6,6 +6,7 @@
+       rxreq
+       expect req.url == "/foo"
+       txresp -hdr "Last-Modified: Thu, 26 Jun 2008 12:00:01 GMT" \
++          -hdr "ETag: foo" \
+           -body "11111\n"
+ } -start
+@@ -15,22 +16,26 @@
+       txreq -url "/foo"
+       rxresp
+       expect resp.status == 200
++      expect resp.http.etag == "foo"
+       expect resp.http.content-length == 6
+       txreq -url "/foo" \
+           -hdr "If-Modified-Since: Thu, 26 Jun 2008 12:00:00 GMT"
+       rxresp
+       expect resp.status == 200
++      expect resp.http.etag == "foo"
+       txreq -url "/foo" \
+           -hdr "If-Modified-Since: Thu, 26 Jun 2008 12:00:01 GMT"
+       rxresp
+       expect resp.status == 304
++      expect resp.http.etag == "foo"
+       txreq -url "/foo" \
+           -hdr "If-Modified-Since: Thu, 26 Jun 2008 12:00:02 GMT"
+       rxresp
+       expect resp.status == 304
++      expect resp.http.etag == "foo"
+ } 
+ client c1 -run
+Index: bin/varnishtest/tests/s00002.vtc
+===================================================================
+--- bin/varnishtest/tests/s00002.vtc   (.../tags/varnish-2.0.4/varnish-cache)
++++ bin/varnishtest/tests/s00002.vtc   (.../branches/2.0/varnish-cache)
+@@ -18,6 +18,7 @@
+                       .interval = 1s; 
+                       .window = 2; 
+                       .threshold = 1; 
++                      .initial = 0;
+                       } 
+               }
+       sub vcl_fetch { 
+Index: bin/varnishtest/tests/v00014.vtc
+===================================================================
+--- bin/varnishtest/tests/v00014.vtc   (.../tags/varnish-2.0.4/varnish-cache)
++++ bin/varnishtest/tests/v00014.vtc   (.../branches/2.0/varnish-cache)
+@@ -20,6 +20,7 @@
+                       .interval = 1s;
+                       .window = 3;
+                       .threshold = 2;
++                      .initial = 0;
+               }
+       }
+Index: bin/varnishtest/tests/r00306.vtc
+===================================================================
+--- bin/varnishtest/tests/r00306.vtc   (.../tags/varnish-2.0.4/varnish-cache)
++++ bin/varnishtest/tests/r00306.vtc   (.../branches/2.0/varnish-cache)
+@@ -27,6 +27,7 @@
+               .host = "127.0.0.1"; .port = "9180";
+               .probe = {
+                       .url = "/";
++                      .initial = 0;
+               }
+       }
+       director foo random {
+Index: bin/varnishtest/tests/c00026.vtc
+===================================================================
+--- bin/varnishtest/tests/c00026.vtc   (.../tags/varnish-2.0.4/varnish-cache)
++++ bin/varnishtest/tests/c00026.vtc   (.../branches/2.0/varnish-cache)
+@@ -0,0 +1,53 @@
++# $Id$
++
++test "Test Combination of If-None-Match and If-Modified-Since"
++
++server s1 {
++      rxreq
++      expect req.url == "/foo"
++      txresp -hdr "ETag: 123456789" \
++             -hdr "Last-Modified: Thu, 26 Jun 2008 12:00:01 GMT" \
++          -body "11111\n"
++} -start
++
++varnish v1 -vcl+backend { } -start
++
++client c1 {
++      txreq -url "/foo"
++      rxresp
++      expect resp.status == 200
++      expect resp.http.content-length == 6
++
++      txreq -url "/foo" \
++          -hdr "If-None-Match: 123456789"
++      rxresp
++      expect resp.status == 304
++
++      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:00 GMT" \
++          -hdr "If-None-Match: 123456789"
++      rxresp
++      expect resp.status == 200
++
++      txreq -url "/foo" \
++          -hdr "If-Modified-Since: Thu, 26 Jun 2008 12:00:01 GMT" \
++          -hdr "If-None-Match: 12345678"
++      rxresp
++      expect resp.status == 200
++
++      txreq -url "/foo" \
++          -hdr "If-Modified-Since: Thu, 26 Jun 2008 12:00:01 GMT" \
++          -hdr "If-None-Match: 123456789"
++      rxresp
++      expect resp.status == 304
++
++} 
++
++client c1 -run
++
++client c1 -run
+Index: bin/varnishtest/tests/c00028.vtc
+===================================================================
+--- bin/varnishtest/tests/c00028.vtc   (.../tags/varnish-2.0.4/varnish-cache)
++++ bin/varnishtest/tests/c00028.vtc   (.../branches/2.0/varnish-cache)
+@@ -0,0 +1,24 @@
++# $Id$
++
++test "Test that we can't recurse restarts forever"
++
++varnish v1 -vcl { 
++      backend bad { 
++              .host = "127.0.0.1";
++              .port = "9090";
++      }
++
++      sub vcl_recv {
++          set req.backend = bad;
++      }
++      sub vcl_error { 
++          restart; 
++      }
++ } -start 
++
++client c1 {
++        txreq -url "/"
++        rxresp
++        expect resp.status == 503
++} -run
++
+Index: bin/varnishtest/tests/e00013.vtc
+===================================================================
+--- bin/varnishtest/tests/e00013.vtc   (.../tags/varnish-2.0.4/varnish-cache)
++++ bin/varnishtest/tests/e00013.vtc   (.../branches/2.0/varnish-cache)
+@@ -6,7 +6,7 @@
+         rxreq
+         expect req.url == "/foo"
+         txresp -hdr "Connection: close"
+-        send {                                         }
++        send {<x>                                      }
+ } -start
+ varnish v1 -vcl+backend {
+Index: bin/varnishtest/tests/e00015.vtc
+===================================================================
+--- bin/varnishtest/tests/e00015.vtc   (.../tags/varnish-2.0.4/varnish-cache)
++++ bin/varnishtest/tests/e00015.vtc   (.../branches/2.0/varnish-cache)
+@@ -0,0 +1,48 @@
++# $Id$
++
++test "ESI requests turned off"
++
++server s1 {
++      rxreq 
++      txresp -body {
++              <html>
++              Before include
++              <esi:include src="/body"/>
++              After include
++      }
++      rxreq 
++      txresp -body {
++              <html>
++              Before include
++              <esi:include src="/body"/>
++              After include
++      }
++      rxreq 
++      expect req.url == "/body"
++      txresp -body {
++              Included file
++      }
++} -start
++
++varnish v1 -vcl+backend {
++      sub vcl_fetch {
++              if(req.url == "/") {
++                 set req.esi = false;
++              }
++              esi;
++      }
++} -start
++
++client c1 {
++        txreq
++      rxresp
++      expect resp.bodylen == 73
++      expect resp.status == 200
++      txreq -url "/esi"
++      rxresp
++      expect resp.bodylen == 65
++      expect resp.status == 200
++}
++
++client c1 -run
++varnish v1 -expect esi_errors == 0
+
+Property changes on: bin/varnishtest/tests/e00015.vtc
+___________________________________________________________________
+Added: svn:keywords
+   + Id
+
+Index: bin/varnishtest/tests/c00001.vtc
+===================================================================
+--- bin/varnishtest/tests/c00001.vtc   (.../tags/varnish-2.0.4/varnish-cache)
++++ bin/varnishtest/tests/c00001.vtc   (.../branches/2.0/varnish-cache)
+@@ -36,7 +36,7 @@
+       expect resp.http.snafu2 == "_frap_"
+       expect resp.http.snafu3 == "_f\\rap_"
+       expect resp.http.snafu4 == "_f&rap_"
+-      expect resp.http.snafu5 == "_barffra\p_"
+-      # NB: have to escape the \\ in the next line
++      # NB: have to escape the \\ in the next two lines
++      expect resp.http.snafu5 == "_barffra\\p_"
+       expect resp.http.snafu6 == "_f&rap\\_"
+ } -run
+Index: bin/varnishtest/vtc_varnish.c
+===================================================================
+--- bin/varnishtest/vtc_varnish.c      (.../tags/varnish-2.0.4/varnish-cache)
++++ bin/varnishtest/vtc_varnish.c      (.../branches/2.0/varnish-cache)
+@@ -326,9 +326,14 @@
+       vtc_log(v->vl, 2, "R %d Status: %04x", r, status);
+       if (WIFEXITED(status) && WEXITSTATUS(status) == 2)
+               return;
++#ifdef WCOREDUMP
+       vtc_log(v->vl, 0, "Bad exit code: %04x sig %x exit %x core %x",
+           status, WTERMSIG(status), WEXITSTATUS(status),
+           WCOREDUMP(status));
++#else
++      vtc_log(v->vl, 0, "Bad exit code: %04x sig %x exit %x",
++          status, WTERMSIG(status), WEXITSTATUS(status));
++#endif
+ }
+ /**********************************************************************
+Index: bin/varnishtest/vtc_http.c
+===================================================================
+--- bin/varnishtest/vtc_http.c (.../tags/varnish-2.0.4/varnish-cache)
++++ bin/varnishtest/vtc_http.c (.../branches/2.0/varnish-cache)
+@@ -322,11 +322,13 @@
+               pfd[0].revents = 0;
+               i = poll(pfd, 1, hp->timeout);
+               assert(i > 0);
+-              assert(hp->prxbuf < hp->nrxbuf);
++              assert(hp->prxbuf + n < hp->nrxbuf);
+               i = read(hp->fd, hp->rxbuf + hp->prxbuf, n);
+               if (i == 0)
+                       return (i);
+-              assert(i > 0);
++              if (i <= 0)
++                      vtc_log(hp->vl, 0, "HTTP rx failed (%s)",
++                          strerror(errno));
+               hp->prxbuf += i;
+               hp->rxbuf[hp->prxbuf] = '\0';
+               n -= i;
+@@ -781,7 +783,7 @@
+       hp->vl = vl;
+       hp->client = client;
+       hp->timeout = 3000;
+-      hp->nrxbuf = 8192;
++      hp->nrxbuf = 640*1024;
+       hp->vsb = vsb_newauto();
+       hp->rxbuf = malloc(hp->nrxbuf);         /* XXX */
+       AN(hp->rxbuf);
+Index: bin/varnishtest/vtc.c
+===================================================================
+--- bin/varnishtest/vtc.c      (.../tags/varnish-2.0.4/varnish-cache)
++++ bin/varnishtest/vtc.c      (.../branches/2.0/varnish-cache)
+@@ -130,19 +130,9 @@
+                               for (; *p != '\0'; p++) {
+                                       if (*p == '"')
+                                               break;
+-
+-                                      if (*p == '\\' && p[1] == 'n') {
+-                                              *q++ = '\n';
+-                                              p++;
+-                                      } else if (*p == '\\' && p[1] == 'r') {
+-                                              *q++ = '\r';
+-                                              p++;
+-                                      } else if (*p == '\\' && p[1] == '\\') {
+-                                              *q++ = '\\';
+-                                              p++;
+-                                      } else if (*p == '\\' && p[1] == '"') {
+-                                              *q++ = '"';
+-                                              p++;
++                                      if (*p == '\\') {
++                                              p += BackSlash(p, q) - 1;
++                                              q++;
+                                       } else {
+                                               if (*p == '\n')
+                                                       fprintf(stderr,
+Index: bin/varnishtop/varnishtop.c
+===================================================================
+--- bin/varnishtop/varnishtop.c        (.../tags/varnish-2.0.4/varnish-cache)
++++ bin/varnishtop/varnishtop.c        (.../branches/2.0/varnish-cache)
+@@ -54,7 +54,8 @@
+ #include "varnishapi.h"
+ struct top {
+-      unsigned char           rec[4 + 255];
++      unsigned char           rec[4];
++      unsigned char           *rec_data;
+       unsigned                clen;
+       unsigned                hash;
+       VTAILQ_ENTRY(top)       list;
+@@ -99,7 +100,7 @@
+                       continue;
+               if (tp->clen != q - p)
+                       continue;
+-              if (memcmp(p + SHMLOG_DATA, tp->rec + SHMLOG_DATA,
++              if (memcmp(p + SHMLOG_DATA, tp->rec_data,
+                   q - (p + SHMLOG_DATA)))
+                       continue;
+               tp->count += 1.0;
+@@ -109,12 +110,15 @@
+               ntop++;
+               tp = calloc(sizeof *tp, 1);
+               assert(tp != NULL);
++              tp->rec_data = calloc(l, 1);
++              assert(tp->rec_data != NULL);
+               tp->hash = u;
+               tp->count = 1.0;
+               tp->clen = q - p;
+               VTAILQ_INSERT_TAIL(&top_head, tp, list);
+       }
+-      memcpy(tp->rec, p, SHMLOG_DATA + l);
++      memcpy(tp->rec, p, SHMLOG_DATA - 1);
++      memcpy(tp->rec_data, p + SHMLOG_DATA, l);
+       while (1) {
+               tp2 = VTAILQ_PREV(tp, tophead, list);
+               if (tp2 == NULL || tp2->count >= tp->count)
+@@ -157,12 +161,13 @@
+                       mvprintw(l, 0, "%9.2f %-*.*s %*.*s\n",
+                           tp->count, maxfieldlen, maxfieldlen,
+                           VSL_tags[tp->rec[SHMLOG_TAG]],
+-                          len, len, tp->rec + SHMLOG_DATA);
++                          len, len, tp->rec_data);
+                       t = tp->count;
+               }
+               tp->count *= .999;
+               if (tp->count * 10 < t || l > LINES * 10) {
+                       VTAILQ_REMOVE(&top_head, tp, list);
++                      free(tp->rec_data);
+                       free(tp);
+                       ntop--;
+               }
+@@ -267,8 +272,8 @@
+       VTAILQ_FOREACH_SAFE(tp, &top_head, list, tp2) {
+               if (tp->count <= 1.0)
+                       break;
+-              len = tp->rec[1];
+-              printf("%9.2f %*.*s\n", tp->count, len, len, tp->rec + 4);
++              len = SHMLOG_LEN(tp->rec);
++              printf("%9.2f %s %*.*s\n", tp->count, VSL_tags[tp->rec[SHMLOG_TAG]], len, len, tp->rec + SHMLOG_DATA);
+       }
+ }
+Index: bin/varnishd/cache_acceptor_kqueue.c
+===================================================================
+--- bin/varnishd/cache_acceptor_kqueue.c       (.../tags/varnish-2.0.4/varnish-cache)
++++ bin/varnishd/cache_acceptor_kqueue.c       (.../branches/2.0/varnish-cache)
+@@ -197,6 +197,7 @@
+                       if (sp->t_open > deadline)
+                               break;
+                       VTAILQ_REMOVE(&sesshead, sp, list);
++                      TCP_linger(sp->fd, 0);
+                       vca_close_session(sp, "timeout");
+                       SES_Delete(sp);
+               }
+Index: bin/varnishd/storage_file.c
+===================================================================
+--- bin/varnishd/storage_file.c        (.../tags/varnish-2.0.4/varnish-cache)
++++ bin/varnishd/storage_file.c        (.../branches/2.0/varnish-cache)
+@@ -577,6 +577,7 @@
+               p = mmap(NULL, sz, PROT_READ|PROT_WRITE,
+                   MAP_NOCORE | MAP_NOSYNC | MAP_SHARED, sc->fd, off);
+               if (p != MAP_FAILED) {
++                      (void) madvise(p, sz, MADV_RANDOM);
+                       (*sum) += sz;
+                       new_smf(sc, p, off, sz);
+                       return;
+Index: bin/varnishd/steps.h
+===================================================================
+--- bin/varnishd/steps.h       (.../tags/varnish-2.0.4/varnish-cache)
++++ bin/varnishd/steps.h       (.../branches/2.0/varnish-cache)
+@@ -29,7 +29,7 @@
+  * $Id$
+  */
+-STEP(again,   AGAIN)
++STEP(wait,    WAIT)
+ STEP(first,   FIRST)
+ STEP(recv,    RECV)
+ STEP(start,   START)
+Index: bin/varnishd/mgt_param.c
+===================================================================
+--- bin/varnishd/mgt_param.c   (.../tags/varnish-2.0.4/varnish-cache)
++++ bin/varnishd/mgt_param.c   (.../branches/2.0/varnish-cache)
+@@ -692,6 +692,15 @@
+               "have both IPv4 and IPv6 addresses.",
+               0,
+               "off", "bool" },
++      { "session_max", tweak_uint,
++              &master.max_sess, 1000, UINT_MAX,
++              "Maximum number of sessions we will allocate "
++              "before just dropping connections.\n"
++              "This is mostly an anti-DoS measure, and setting it plenty "
++              "high should not hurt, as long as you have the memory for "
++              "it.\n",
++              0,
++              "100000", "sessions" },
+       { "session_linger", tweak_uint,
+               &master.session_linger,0, UINT_MAX,
+               "How long time the workerthread lingers on the session "
+@@ -703,7 +712,7 @@
+               "anything for their keep, setting it too low just means that "
+               "more sessions take a detour around the acceptor.",
+               EXPERIMENTAL,
+-              "0", "ms" },
++              "50", "ms" },
+       { "cli_buffer", tweak_uint, &master.cli_buffer, 4096, UINT_MAX,
+               "Size of buffer for CLI input."
+               "\nYou may need to increase this if you have big VCL files "
+@@ -756,7 +765,7 @@
+       { "purge_dups", tweak_bool, &master.purge_dups, 0, 0,
+               "Detect and eliminate duplicate purges.\n",
+               0,
+-              "off", "bool" },
++              "on", "bool" },
+       { NULL, NULL, NULL }
+ };
+Index: bin/varnishd/cache_vcl.c
+===================================================================
+--- bin/varnishd/cache_vcl.c   (.../tags/varnish-2.0.4/varnish-cache)
++++ bin/varnishd/cache_vcl.c   (.../branches/2.0/varnish-cache)
+@@ -83,7 +83,13 @@
+ void
+ VCL_Get(struct VCL_conf **vcc)
+ {
++      static int once;
++      while (!once && vcl_active == NULL) {
++              sleep(1);
++      }
++      once = 1;
++
+       Lck_Lock(&vcl_mtx);
+       AN(vcl_active);
+       *vcc = vcl_active->conf;
+Index: bin/varnishd/cache_ws.c
+===================================================================
+--- bin/varnishd/cache_ws.c    (.../tags/varnish-2.0.4/varnish-cache)
++++ bin/varnishd/cache_ws.c    (.../branches/2.0/varnish-cache)
+@@ -82,6 +82,10 @@
+       WS_Assert(ws);
+ }
++/*
++ * Reset a WS to start or a given pointer, likely from WS_Snapshot
++ */
++
+ void
+ WS_Reset(struct ws *ws, char *p)
+ {
+Index: bin/varnishd/cache_httpconn.c
+===================================================================
+--- bin/varnishd/cache_httpconn.c      (.../tags/varnish-2.0.4/varnish-cache)
++++ bin/varnishd/cache_httpconn.c      (.../branches/2.0/varnish-cache)
+@@ -92,6 +92,7 @@
+       (void)WS_Reserve(htc->ws, (htc->ws->e - htc->ws->s) / 2);
+       htc->rxbuf.b = ws->f;
+       htc->rxbuf.e = ws->f;
++      *htc->rxbuf.e = '\0';
+       htc->pipeline.b = NULL;
+       htc->pipeline.e = NULL;
+ }
+Index: bin/varnishd/cache_response.c
+===================================================================
+--- bin/varnishd/cache_response.c      (.../tags/varnish-2.0.4/varnish-cache)
++++ bin/varnishd/cache_response.c      (.../branches/2.0/varnish-cache)
+@@ -46,6 +46,7 @@
+ res_do_304(struct sess *sp)
+ {
+       char lm[64];
++      char *p;
+       WSP(sp, SLT_Length, "%u", 0);
+@@ -56,8 +57,23 @@
+       http_PrintfHeader(sp->wrk, sp->fd, sp->http, "Date: %s", lm);
+       http_SetHeader(sp->wrk, sp->fd, sp->http, "Via: 1.1 varnish");
+       http_PrintfHeader(sp->wrk, sp->fd, sp->http, "X-Varnish: %u", sp->xid);
+-      TIM_format(sp->obj->last_modified, lm);
+-      http_PrintfHeader(sp->wrk, sp->fd, sp->http, "Last-Modified: %s", lm);
++      if (sp->obj->last_modified) {
++              TIM_format(sp->obj->last_modified, lm);
++              http_PrintfHeader(sp->wrk, sp->fd, sp->http, "Last-Modified: %s", lm);
++      }
++
++      /* http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.5 */
++      if (http_GetHdr(sp->obj->http, H_Cache_Control, &p))
++              http_PrintfHeader(sp->wrk, sp->fd, sp->http, "Cache-Control: %s", p);
++      if (http_GetHdr(sp->obj->http, H_Content_Location, &p))
++              http_PrintfHeader(sp->wrk, sp->fd, sp->http, "Content-Location: %s", p);
++      if (http_GetHdr(sp->obj->http, H_ETag, &p))
++              http_PrintfHeader(sp->wrk, sp->fd, sp->http, "ETag: %s", p);
++      if (http_GetHdr(sp->obj->http, H_Expires, &p))
++              http_PrintfHeader(sp->wrk, sp->fd, sp->http, "Expires: %s", p);
++      if (http_GetHdr(sp->obj->http, H_Vary, &p))
++              http_PrintfHeader(sp->wrk, sp->fd, sp->http, "Vary: %s", p);
++
+       http_PrintfHeader(sp->wrk, sp->fd, sp->http, "Connection: %s",
+           sp->doclose ? "close" : "keep-alive");
+       sp->wantbody = 0;
+@@ -68,17 +84,33 @@
+ static int
+ res_do_conds(struct sess *sp)
+ {
+-      char *p;
++      char *p, *e;
+       double ims;
++      int do_cond = 0;
+-      if (sp->obj->last_modified > 0 &&
+-          http_GetHdr(sp->http, H_If_Modified_Since, &p)) {
++      /* RFC 2616 13.3.4 states we need to match both ETag
++         and If-Modified-Since if present*/
++
++      if (http_GetHdr(sp->http, H_If_Modified_Since, &p) ) {
++              if (!sp->obj->last_modified)
++                      return (0);
+               ims = TIM_parse(p);
+               if (ims > sp->t_req)    /* [RFC2616 14.25] */
+                       return (0);
+               if (sp->obj->last_modified > ims) {
+                       return (0);
+               }
++              do_cond = 1;
++      }
++
++      if (http_GetHdr(sp->http, H_If_None_Match, &p) &&
++          http_GetHdr(sp->obj->http, H_ETag, &e)) {
++              if (strcmp(p,e) != 0)
++                      return (0);
++              do_cond = 1;
++      }
++
++      if (do_cond == 1) { 
+               res_do_304(sp);
+               return (1);
+       }
+@@ -106,9 +138,12 @@
+           HTTPH_A_DELIVER);
+       /* Only HTTP 1.1 can do Chunked encoding */
+-      if (sp->http->protover < 1.1 && !VTAILQ_EMPTY(&sp->obj->esibits))
+-              http_Unset(sp->http, H_Transfer_Encoding);
+-
++      if (!sp->disable_esi && !VTAILQ_EMPTY(&sp->obj->esibits)) {
++              http_Unset(sp->http, H_Content_Length);
++              if(sp->http->protover >= 1.1)
++                      http_PrintfHeader(sp->wrk, sp->fd, sp->http, "Transfer-Encoding: chunked");
++      }
++ 
+       TIM_format(TIM_real(), time_str);
+       http_PrintfHeader(sp->wrk, sp->fd, sp->http, "Date: %s", time_str);
+@@ -139,10 +174,10 @@
+       WRW_Reserve(sp->wrk, &sp->fd);
+-      if (sp->esis == 0)
++      if (sp->disable_esi || sp->esis == 0)
+               sp->acct_req.hdrbytes += http_Write(sp->wrk, sp->http, 1);
+-      if (sp->wantbody && !VTAILQ_EMPTY(&sp->obj->esibits)) {
++      if (!sp->disable_esi && sp->wantbody && !VTAILQ_EMPTY(&sp->obj->esibits)) {
+               if (WRW_FlushRelease(sp->wrk)) {
+                       vca_close_session(sp, "remote closed");
+                       return;
+@@ -152,7 +187,8 @@
+       }
+       if (sp->wantbody) {
+-              if (sp->esis > 0 &&
++              if (!sp->disable_esi &&
++                  sp->esis > 0 &&
+                   sp->http->protover >= 1.1 &&
+                   sp->obj->len > 0) {
+                       sprintf(lenbuf, "%x\r\n", sp->obj->len);
+@@ -183,7 +219,8 @@
+                       (void)WRW_Write(sp->wrk, st->ptr, st->len);
+               }
+               assert(u == sp->obj->len);
+-              if (sp->esis > 0 &&
++              if (!sp->disable_esi &&
++                  sp->esis > 0 &&
+                   sp->http->protover >= 1.1 &&
+                   sp->obj->len > 0)
+                       (void)WRW_Write(sp->wrk, "\r\n", -1);
+Index: bin/varnishd/cache_cli.c
+===================================================================
+--- bin/varnishd/cache_cli.c   (.../tags/varnish-2.0.4/varnish-cache)
++++ bin/varnishd/cache_cli.c   (.../branches/2.0/varnish-cache)
+@@ -158,8 +158,7 @@
+                       continue;
+               assert(i == 1);
+               if (pfd[0].revents & POLLHUP) {
+-                      fprintf(stderr,
+-                          "EOF on CLI connection, exiting\n");
++                      VSL(SLT_CLI, 0, "EOF on CLI connection, worker stops");
+                       exit(0);
+               }
+               i = VLU_Fd(heritage.cli_in, vlu);
+Index: bin/varnishd/varnishd.1
+===================================================================
+--- bin/varnishd/varnishd.1    (.../tags/varnish-2.0.4/varnish-cache)
++++ bin/varnishd/varnishd.1    (.../branches/2.0/varnish-cache)
+@@ -326,8 +326,12 @@
+ address and port.
+ The following commands are available:
+ .Bl -tag -width 4n
+-.It Cm help
++.It Cm help Op Ar command
+ Display a list of available commands.
++.Pp
++If the
++.Ar command
++is specified, display help for this command.
+ .It Cm param.set Ar param Ar value
+ Set the parameter specified by
+ .Ar param
+@@ -336,35 +340,78 @@
+ See
+ .Sx Run-Time Parameters
+ for a list of parameters.
+-.It Cm param.show Ar param
+-Display the value of the parameter specified by
+-.Ar param .
+-See
+-.Sx Run-Time Parameters
+-for a list of parameters.
+-.It Cm param.show Op Fl l
+-Display a list of run-time parameters and their values.
++.It Xo
++.Cm param.show
++.Op Fl l
++.Op Ar param
++.Xc
++Display a list if run-time parameters and their values. 
++.Pp
+ If the
+ .Fl l
+ option is specified, the list includes a brief explanation of each
+ parameter.
++.Pp
++If a
++.Ar param
++is specified, display only the value and explanation for this
++parameter.
+ .It Cm ping Op Ns Ar timestamp
+-Ping the child process.
++Ping the Varnish cache process, keeping the connection alive.
++.It Cm purge Ar field Ar operator Ar argument Op && Ar field Ar operator Ar argument Op ...
++Immediately invalidate all documents matching the purge expression.
++See
++.Va Purge expressions
++for more documentation and examples.
++.It Cm purge.hash Ar regex
++Immediately invalidate all documents where
++.Va obj.hash
++matches the
++.Va regex .
++The default object hash contains the values from
++.Va req.url
++and either
++.Va req.http.host
++or
++.Va server.ip
++depending on the presence of a Host: header in the request sent by the
++client.
++The object hash may be modified further by
++.Va VCL.
++.It Cm purge.list
++Display the purge list.
++.Pp
++All requests for objects from the cache are matched against items on
++the purge list.
++If an object in the cache is older than a matching purge list item, it
++is considered
++.Qq purged ,
++and will be fetched from the backend instead.
++.Pp
++When a purge expression is older than all the objects in the cache, it
++is removed from the list.
++.It Cm purge.url Ar regexp
++Immediately invalidate all documents whose URL matches the specified
++regular expression.
++.It Cm quit
++Close the connection to the varnish admin port.
+ .It Cm start
+-Start the child process if it is not already running.
++Start the Varnish cache process if it is not already running.
+ .It Cm stats
+-Display server statistics.
++Show summary statistics.
++.Pp
+ All the numbers presented are totals since server startup; for a
+ better idea of the current situation, use the
+ .Xr varnishstat 1
+ utility.
+ .It Cm status
+-Check the status of the child process.
++Check the status of the Varnish cache process.
+ .It Cm stop
+-Stop the child process.
++Stop the Varnish cache process.
+ .It Cm url.purge Ar regexp
+-Immediately invalidate all documents whos URL matches the specified
+-regular expression.
++Deprecated, see
++.Cm purge.url
++instead.
+ .It Cm vcl.discard Ar configname
+ Discard the configuration specified by
+ .Ar configname .
+@@ -583,6 +630,65 @@
+ The default is
+ .Dv off .
+ .El
++.Ss Purge expressions
++A purge expression consists of one or more conditions.
++A condition consists of a field, an operator, and an argument.
++Conditions can be ANDed together with
++.Qq && .
++.Pp
++A field can be any of the variables from VCL, for instance
++.Va req.url ,
++.Va req.http.host
++or
++.Va obj.set-cookie .
++.Pp
++Operators are
++.Qq ==
++for direct comparision,
++.Qq ~
++for a regular expression match, and
++.Qq >
++or
++.Qq <
++for size comparisons.
++Prepending an operator with
++.Qq \&!
++negates the expression.
++.Pp
++The argument could be a quoted string, a regexp, or an integer.
++Integers can have 
++.Qq KB ,
++.Qq MB ,
++.Qq GB
++or
++.Qq TB
++appended for size related fields.
++.Pp
++Simple example: All requests where
++.Va req.url
++exactly matches the string
++.Va /news
++are purged from the cache.
++.Bd -literal -offset 4n
++req.url == "/news"
++.Ed
++.Pp
++Example: Purge all documents where the name does not end with
++.Qq .ogg ,
++and where the size of the object is greater than 10 megabytes.
++.Bd -literal -offset 4n
++req.url !~ "\\.ogg$" && obj.size > 10MB
++.Ed
++.Pp
++Example: Purge all documents where the serving host is
++.Qq example.com
++or
++.Qq www.example.com ,
++and where the Set-Cookie header received from the backend contains
++.Qq USERID=1663 .
++.Bd -literal -offset 4n
++req.http.host ~ "^(www\\.)example.com$" && obj.set-cookie ~ "USERID=1663"
++.Ed
+ .Sh SEE ALSO
+ .Xr varnishlog 1 ,
+ .Xr varnishhist 1 ,
+@@ -609,4 +715,6 @@
+ .An Poul-Henning Kamp Aq phk@phk.freebsd.dk
+ in cooperation with Verdens Gang AS and Linpro AS.
+ This manual page was written by
+-.An Dag-Erling Sm\(/orgrav Aq des@des.no .
++.An Dag-Erling Sm\(/orgrav Aq des@des.no
++with updates by
++.An Stig Sandbeck Mathisen Aq ssm@debian.org
+Index: bin/varnishd/cache_vrt_esi.c
+===================================================================
+--- bin/varnishd/cache_vrt_esi.c       (.../tags/varnish-2.0.4/varnish-cache)
++++ bin/varnishd/cache_vrt_esi.c       (.../branches/2.0/varnish-cache)
+@@ -304,8 +304,7 @@
+       in->b++;
+       if (isspace(*in->b)) {
+-              val->e = val->b = in->b;;
+-              *val->e = '\0';
++              val->e = val->b = in->b;
+               in->b++;
+               return (1);
+       }
+@@ -340,7 +339,6 @@
+               val->e = in->b;
+               in->b++;
+       }
+-      *val->e = '\0';
+       return (1);
+ }
+@@ -352,11 +350,11 @@
+ esi_handle_include(struct esi_work *ew)
+ {
+       struct esi_bit *eb;
+-      char *p, *q;
++      char *p, *q, *c;
+       txt t = ew->tag;
+       txt tag;
+       txt val;
+-      unsigned u, v;
++      unsigned u, v, s;
+       struct ws *ws;
+       if (ew->eb == NULL || ew->eb->include.b != NULL)
+@@ -371,10 +369,24 @@
+                       continue;
+               if (Tlen(val) == 0) {
+                       esi_error(ew, tag.b, Tlen(tag),
+-                          "ESI esi:include src attribute withou value");
++                          "ESI esi:include src attribute without value");
+                       continue;
+               }
++              /* Wee are saving the original string */
++              ws = ew->sp->obj->ws_o;
++              WS_Assert(ws);
++              s = 0;
++
++              if ( val.b != val.e ) {
++                      s = Tlen(val) + 1;
++                      c = WS_Alloc(ws, s);
++                      memcpy(c, val.b, Tlen(val));
++                      val.b = c;
++                      val.e = val.b + s;
++                      *val.e = '\0';
++              }
++
+               if (Tlen(val) > 7 && !memcmp(val.b, "http://", 7)) {
+                       /*  Rewrite to Host: header inplace */
+                       eb->host.b = val.b;
+@@ -406,8 +418,6 @@
+                       /* Use the objects WS to store the result */
+                       CHECK_OBJ_NOTNULL(ew->sp->obj, OBJECT_MAGIC);
+-                      ws = ew->sp->obj->ws_o;
+-                      WS_Assert(ws);
+                       /* Look for the last '/' before a '?' */
+                       q = NULL;
+@@ -747,13 +757,6 @@
+       if (ew->incmt)
+               esi_error(ew, ew->t.e, -1,
+                   "ESI 1.0 unterminated <!--esi comment");
+-
+-      /*
+-       * Our ESI implementation needs chunked encoding
+-       */
+-      http_Unset(sp->obj->http, H_Content_Length);
+-      http_PrintfHeader(sp->wrk, sp->fd, sp->obj->http,
+-          "Transfer-Encoding: chunked");
+ }
+ /*--------------------------------------------------------------------*/
+@@ -763,8 +766,11 @@
+ {
+       struct esi_bit *eb;
+       struct object *obj;
++      char *ws_wm;
++      struct http http_save;
+       WRW_Reserve(sp->wrk, &sp->fd);
++      http_save.magic = 0;
+       VTAILQ_FOREACH(eb, &sp->obj->esibits, list) {
+               if (Tlen(eb->verbatim)) {
+                       if (sp->http->protover >= 1.1)
+@@ -786,8 +792,17 @@
+               sp->esis++;
+               obj = sp->obj;
+               sp->obj = NULL;
++
++              /* Save the master objects HTTP state, we may need it later */
++              if (http_save.magic == 0)
++                      http_save = *sp->http;
++
++              /* Reset request to status before we started messing with it */
+               *sp->http = *sp->http0;
+-              /* XXX: reset sp->ws */
++
++              /* Take a workspace snapshot */
++              ws_wm = WS_Snapshot(sp->ws);
++
+               http_SetH(sp->http, HTTP_HDR_URL, eb->include.b);
+               if (eb->host.b != NULL)  {
+                       http_Unset(sp->http, H_Host);
+@@ -822,10 +837,17 @@
+               assert(sp->step == STP_DONE);
+               sp->esis--;
+               sp->obj = obj;
++
++              /* Reset the workspace */
++              WS_Reset(sp->ws, ws_wm);
++
+               WRW_Reserve(sp->wrk, &sp->fd);
+               if (sp->fd < 0)
+                       break;
+       }
++       /* Restore master objects HTTP state */
++       if (http_save.magic)
++             *sp->http = http_save;
+       if (sp->esis == 0 && sp->http->protover >= 1.1)
+               (void)WRW_Write(sp->wrk, "0\r\n\r\n", -1);
+       if (WRW_FlushRelease(sp->wrk))
+Index: bin/varnishd/cache_backend.c
+===================================================================
+--- bin/varnishd/cache_backend.c       (.../tags/varnish-2.0.4/varnish-cache)
++++ bin/varnishd/cache_backend.c       (.../branches/2.0/varnish-cache)
+@@ -314,11 +314,11 @@
+               if (VBE_CheckFd(vc->fd)) {
+                       /* XXX locking of stats */
+                       VSL_stats->backend_reuse += 1;
+-                      VSL_stats->backend_conn++;
+                       WSP(sp, SLT_Backend, "%d %s %s",
+                           vc->fd, sp->director->vcl_name, bp->vcl_name);
+                       return (vc);
+               }
++              VSL_stats->backend_toolate++;
+               sp->vbe = vc;
+               VBE_ClosedFd(sp);
+       }
+Index: bin/varnishd/hash_slinger.h
+===================================================================
+--- bin/varnishd/hash_slinger.h        (.../tags/varnish-2.0.4/varnish-cache)
++++ bin/varnishd/hash_slinger.h        (.../branches/2.0/varnish-cache)
+@@ -49,7 +49,7 @@
+ };
+ /* cache_hash.c */
+-void HSH_Prealloc(struct sess *sp);
++void HSH_Prealloc(struct sess *sp, int transient);
+ void HSH_Freestore(struct object *o);
+ void HSH_Copy(const struct sess *sp, struct objhead *o);
+ struct object *HSH_Lookup(struct sess *sp);
+Index: bin/varnishd/cache_fetch.c
+===================================================================
+--- bin/varnishd/cache_fetch.c (.../tags/varnish-2.0.4/varnish-cache)
++++ bin/varnishd/cache_fetch.c (.../branches/2.0/varnish-cache)
+@@ -70,8 +70,11 @@
+       while (cl > 0) {
+               i = HTC_Read(htc, p, cl);
+-              if (i <= 0)
++              if (i <= 0) {
++                      WSP(sp, SLT_FetchError,
++                          "straight read_error: %d", errno);
+                       return (-1);
++              }
+               p += i;
+               cl -= i;
+       }
+@@ -110,8 +113,11 @@
+               /* If we didn't succeed, add to buffer, try again */
+               if (q == NULL || q == buf || *q != '\n') {
+-                      if (bp >= be)
++                      if (bp >= be) {
++                              WSP(sp, SLT_FetchError,
++                                  "chunked hex-line too long");
+                               return (-1);
++                      }
+                       /*
+                        * The semantics we need here is "read until you have
+                        * received at least one character, but feel free to
+@@ -128,8 +134,11 @@
+                        * at a time.
+                        */
+                       i = HTC_Read(htc, bp, 1);
+-                      if (i <= 0)
++                      if (i <= 0) {
++                              WSP(sp, SLT_FetchError,
++                                  "chunked read_error: %d", errno);
+                               return (-1);
++                      }
+                       bp += i;
+                       continue;
+               }
+@@ -241,8 +250,11 @@
+               AN(p);
+               AN(st);
+               i = HTC_Read(htc, p, v);
+-              if (i < 0)
++              if (i < 0) {
++                      WSP(sp, SLT_FetchError,
++                          "eof read_error: %d", errno);
+                       return (-1);
++              }
+               if (i == 0)
+                       break;
+               p += i;
+@@ -338,8 +350,10 @@
+       /* Set up obj's workspace */
+       WS_Assert(sp->obj->ws_o);
+       VBE_GetFd(sp);
+-      if (sp->vbe == NULL)
++      if (sp->vbe == NULL) {
++              WSP(sp, SLT_FetchError, "no backend connection");
+               return (__LINE__);
++      }
+       vc = sp->vbe;
+       /* Inherit the backend timeouts from the selected backend */
+       SES_InheritBackendTimeouts(sp);
+@@ -359,6 +373,7 @@
+       /* Deal with any message-body the request might have */
+       i = FetchReqBody(sp);
+       if (WRW_FlushRelease(w) || i > 0) {
++              WSP(sp, SLT_FetchError, "backend write error: %d", errno);
+               VBE_ClosedFd(sp);
+               /* XXX: other cleanup ? */
+               return (__LINE__);
+@@ -374,17 +389,19 @@
+       TCP_set_read_timeout(vc->fd, sp->first_byte_timeout);
+       do {
+               i = HTC_Rx(htc);
++              if (i < 0) {
++                      WSP(sp, SLT_FetchError,
++                          "http read error: %d", errno);
++                      VBE_ClosedFd(sp);
++                      /* XXX: other cleanup ? */
++                      return (__LINE__);
++              }
+               TCP_set_read_timeout(vc->fd, sp->between_bytes_timeout);
+       }
+       while (i == 0);
+-      if (i < 0) {
+-              VBE_ClosedFd(sp);
+-              /* XXX: other cleanup ? */
+-              return (__LINE__);
+-      }
+-
+       if (http_DissectResponse(sp->wrk, htc, hp)) {
++              WSP(sp, SLT_FetchError, "http format error");
+               VBE_ClosedFd(sp);
+               /* XXX: other cleanup ? */
+               return (__LINE__);
+@@ -407,14 +424,17 @@
+       cls = 0;
+       mklen = 0;
+       if (is_head) {
+-              /* nothing */
++              VSL_stats->fetch_head++;
+       } else if (http_GetHdr(hp, H_Content_Length, &b)) {
++              VSL_stats->fetch_length++;
+               cls = fetch_straight(sp, htc, b);
+               mklen = 1;
+       } else if (http_HdrIs(hp, H_Transfer_Encoding, "chunked")) {
++              VSL_stats->fetch_chunked++;
+               cls = fetch_chunked(sp, htc);
+               mklen = 1;
+       } else if (http_GetHdr(hp, H_Transfer_Encoding, &b)) {
++              VSL_stats->fetch_bad++;
+               /* XXX: AUGH! */
+               WSL(sp->wrk, SLT_Debug, vc->fd, "Invalid Transfer-Encoding");
+               VBE_ClosedFd(sp);
+@@ -427,6 +447,7 @@
+                */
+               mklen = 1;
+       } else if (http_HdrIs(hp, H_Connection, "close")) {
++              VSL_stats->fetch_close++;
+               /*
+                * If we have connection closed, it is safe to read what
+                * comes in any case.
+@@ -434,19 +455,23 @@
+               cls = fetch_eof(sp, htc);
+               mklen = 1;
+       } else if (hp->protover < 1.1) {
++              VSL_stats->fetch_oldhttp++;
+               /*
+                * With no Connection header, assume EOF
+                */
+               cls = fetch_eof(sp, htc);
+               mklen = 1;
+       } else {
++              VSL_stats->fetch_zero++;
+               /*
+                * Assume zero length
++               * XXX:  ??? 
+                */
+               mklen = 1;
+       }
+       if (cls < 0) {
++              VSL_stats->fetch_failed++;
+               /* XXX: Wouldn't this store automatically be released ? */
+               while (!VTAILQ_EMPTY(&sp->obj->store)) {
+                       st = VTAILQ_FIRST(&sp->obj->store);
+@@ -511,5 +536,3 @@
+       CLI_AddFuncs(DEBUG_CLI, debug_cmds);
+ }
+-
+-
+Index: bin/varnishd/cache_panic.c
+===================================================================
+--- bin/varnishd/cache_panic.c (.../tags/varnish-2.0.4/varnish-cache)
++++ bin/varnishd/cache_panic.c (.../branches/2.0/varnish-cache)
+@@ -37,6 +37,11 @@
+ #include <stdlib.h>
+ #include <unistd.h>
++#ifndef HAVE_EXECINFO_H
++#include "compat/execinfo.h"
++#else
++#include <execinfo.h>
++#endif
+ #include "cache.h"
+ #include "cache_backend.h"
+ #include "vcl.h"
+@@ -63,7 +68,7 @@
+       vsb_printf(vsp, "%*sws = %p { %s\n", indent, "",
+           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);
++      vsb_printf(vsp, "%*s{s,f,r,e} = {%p", indent + 2, "", ws->s);
+       if (ws->f > ws->s)
+               vsb_printf(vsp, ",+%d", ws->f - ws->s);
+       else
+@@ -131,21 +136,21 @@
+ /*--------------------------------------------------------------------*/
+ static void
+-pan_http(const struct http *h)
++pan_http(const char *id, const struct http *h, int indent)
+ {
+       int i;
+-      vsb_printf(vsp, "    http = {\n");
+-      pan_ws(h->ws, 6);
+-      if (h->nhd > HTTP_HDR_FIRST) {
+-              vsb_printf(vsp, "      hd = {\n");
+-              for (i = HTTP_HDR_FIRST; i < h->nhd; ++i)
+-                      vsb_printf(vsp, "        \"%.*s\",\n",
+-                          (int)(h->hd[i].e - h->hd[i].b),
+-                          h->hd[i].b);
+-              vsb_printf(vsp, "      },\n");
++      vsb_printf(vsp, "%*shttp[%s] = {\n", indent, "", id);
++      vsb_printf(vsp, "%*sws = %p[%s]\n", indent + 2, "",
++          h->ws, h->ws ? h->ws->id : "");
++      for (i = 0; i < h->nhd; ++i) {
++              if (h->hd[i].b == NULL && h->hd[i].e == NULL)
++                      continue;
++              vsb_printf(vsp, "%*s\"%.*s\",\n", indent + 4, "",
++                  (int)(h->hd[i].e - h->hd[i].b),
++                  h->hd[i].b);
+       }
+-      vsb_printf(vsp, "    },\n");
++      vsb_printf(vsp, "%*s},\n", indent, "");
+ }
+@@ -159,7 +164,7 @@
+       vsb_printf(vsp, "  obj = %p {\n", o);
+       vsb_printf(vsp, "    refcnt = %u, xid = %u,\n", o->refcnt, o->xid);
+       pan_ws(o->ws_o, 4);
+-      pan_http(o->http);
++      pan_http("obj", o->http, 4);
+       vsb_printf(vsp, "    len = %u,\n", o->len);
+       vsb_printf(vsp, "    store = {\n");
+       VTAILQ_FOREACH(st, &o->store, list)
+@@ -190,8 +195,7 @@
+ pan_wrk(const struct worker *wrk)
+ {
+-      vsb_printf(vsp, "    worker = %p {\n", wrk);
+-      vsb_printf(vsp, "    },\n");
++      vsb_printf(vsp, "  worker = %p\n", wrk);
+ }
+ /*--------------------------------------------------------------------*/
+@@ -229,7 +233,11 @@
+                   "  err_code = %d, err_reason = %s,\n", sp->err_code,
+                   sp->err_reason ? sp->err_reason : "(null)");
++      vsb_printf(vsp, "  restarts = %d, esis = %d\n",
++          sp->restarts, sp->esis);
++
+       pan_ws(sp->ws, 2);
++      pan_http("req", sp->http, 2);
+       if (sp->wrk != NULL)
+               pan_wrk(sp->wrk);
+@@ -249,6 +257,28 @@
+ /*--------------------------------------------------------------------*/
+ static void
++pan_backtrace(void)
++{
++      void *array[10];
++      size_t size;
++      size_t i;
++
++      size = backtrace (array, 10);
++      vsb_printf(vsp, "Backtrace:\n");
++      for (i = 0; i < size; i++) {
++              vsb_printf (vsp, "  ");
++              if (Symbol_Lookup(vsp, array[i]) < 0) {
++                      char **strings;
++                      strings = backtrace_symbols(&array[i], 1);
++                      vsb_printf(vsp, "%p: %s", array[i], strings[0]);
++              }
++              vsb_printf (vsp, "\n");
++      }
++}
++
++/*--------------------------------------------------------------------*/
++
++static void
+ pan_ic(const char *func, const char *file, int line, const char *cond,
+     int err, int xxx)
+ {
+@@ -264,7 +294,7 @@
+               break;
+       case 2:
+               vsb_printf(vsp,
+-                  "Panic from VCL:\n%s\n", cond);
++                  "Panic from VCL:\n  %s\n", cond);
+               break;
+       case 1:
+               vsb_printf(vsp,
+@@ -276,16 +306,19 @@
+       case 0:
+               vsb_printf(vsp,
+                   "Assert error in %s(), %s line %d:\n"
+-                  "  Condition(%s) not true.",
++                  "  Condition(%s) not true.\n",
+                   func, file, line, cond);
+               break;
+       }
+       if (err)
+-              vsb_printf(vsp, "  errno = %d (%s)", err, strerror(err));
++              vsb_printf(vsp, "errno = %d (%s)\n", err, strerror(err));
+       q = THR_GetName();
+       if (q != NULL)
+-              vsb_printf(vsp, "  thread = (%s)", q);
++              vsb_printf(vsp, "thread = (%s)\n", q);
++
++      pan_backtrace();
++
+       if (!(params->diag_bitmap & 0x2000)) {
+               sp = THR_GetSession();
+               if (sp != NULL)
+Index: bin/varnishd/cache_expire.c
+===================================================================
+--- bin/varnishd/cache_expire.c        (.../tags/varnish-2.0.4/varnish-cache)
++++ bin/varnishd/cache_expire.c        (.../branches/2.0/varnish-cache)
+@@ -275,26 +275,13 @@
+  */
+ static void *
+-exp_timer(void *arg)
++exp_timer(struct sess *sp, void *priv)
+ {
+-      struct worker ww;
+       struct objexp *oe;
+       struct object *o;
+       double t;
+-      struct sess *sp;
+-      unsigned char logbuf[1024];             /* XXX size ? */
+-      THR_SetName("cache-timeout");
+-      (void)arg;
+-
+-      sp = SES_New(NULL, 0);
+-      XXXAN(sp);
+-      sp->wrk = &ww;
+-      ww.magic = WORKER_MAGIC;
+-      ww.wlp = ww.wlb = logbuf;
+-      ww.wle = logbuf + sizeof logbuf;
+-
+-      AZ(sleep(10));          /* XXX: Takes time for VCL to arrive */
++      (void)priv;
+       VCL_Get(&sp->vcl);
+       t = TIM_real();
+       while (1) {
+@@ -303,7 +290,7 @@
+               CHECK_OBJ_ORNULL(oe, OBJEXP_MAGIC);
+               if (oe == NULL || oe->timer_when > t) { /* XXX: > or >= ? */
+                       Lck_Unlock(&exp_mtx);
+-                      WSL_Flush(&ww, 0);
++                      WSL_Flush(sp->wrk, 0);
+                       AZ(sleep(1));
+                       VCL_Refresh(&sp->vcl);
+                       t = TIM_real();
+@@ -327,7 +314,7 @@
+               assert(oe->on_lru);
+               Lck_Unlock(&exp_mtx);
+-              WSL(&ww, SLT_ExpPick, 0, "%u %s", o->xid, oe->timer_what);
++              WSL(sp->wrk, SLT_ExpPick, 0, "%u %s", o->xid, oe->timer_what);
+               if (oe->timer_what == tmr_prefetch) {
+                       o->prefetch = 0.0;
+@@ -335,7 +322,7 @@
+                       VCL_prefetch_method(sp);
+                       sp->obj = NULL;
+                       if (sp->handling == VCL_RET_FETCH) {
+-                              WSL(&ww, SLT_Debug, 0, "Attempt Prefetch %u",
++                              WSL(sp->wrk, SLT_Debug, 0, "Attempt Prefetch %u",
+                                   o->xid);
+                       }
+                       Lck_Lock(&exp_mtx);
+@@ -351,7 +338,7 @@
+                       sp->obj = NULL;
+                       assert(sp->handling == VCL_RET_DISCARD);
+-                      WSL(&ww, SLT_ExpKill, 0,
++                      WSL(sp->wrk, SLT_ExpKill, 0,
+                           "%u %d", o->xid, (int)(o->ttl - t));
+                       Lck_Lock(&exp_mtx);
+                       assert(oe->timer_idx == BINHEAP_NOIDX);
+@@ -481,5 +468,5 @@
+       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));
++      WRK_BgThread(&exp_thread, "cache-timeout", exp_timer, NULL);
+ }
+Index: bin/varnishd/cache_ban.c
+===================================================================
+--- bin/varnishd/cache_ban.c   (.../tags/varnish-2.0.4/varnish-cache)
++++ bin/varnishd/cache_ban.c   (.../branches/2.0/varnish-cache)
+@@ -86,6 +86,7 @@
+       int                     flags;
+ #define BAN_F_GONE            (1 << 0)
+       VTAILQ_HEAD(,ban_test)  tests;
++      VTAILQ_HEAD(,object)    obj;
+ };
+ static VTAILQ_HEAD(banhead,ban) ban_head = VTAILQ_HEAD_INITIALIZER(ban_head);
+@@ -103,6 +104,7 @@
+       if (b == NULL)
+               return (b);
+       VTAILQ_INIT(&b->tests);
++      VTAILQ_INIT(&b->obj);
+       return (b);
+ }
+@@ -146,6 +148,9 @@
+       struct ban_test *bt;
+       CHECK_OBJ_NOTNULL(b, BAN_MAGIC);
++      AZ(b->refcount);
++      assert(VTAILQ_EMPTY(&b->obj));
++
+       while (!VTAILQ_EMPTY(&b->tests)) {
+               bt = VTAILQ_FIRST(&b->tests);
+               VTAILQ_REMOVE(&b->tests, bt, list);
+@@ -366,7 +371,7 @@
+       sb = vsb_newauto();
+       XXXAN(sb);
+       vsb_printf(sb, "%s %s ", a1, a2);
+-      vsb_quote(sb, a3, 0);
++      vsb_quote(sb, a3, -1, 0);
+       vsb_finish(sb);
+       AZ(vsb_overflowed(sb));
+       bt->test = strdup(vsb_data(sb));
+@@ -439,6 +444,7 @@
+       Lck_Lock(&ban_mtx);
+       o->ban = ban_start;
+       ban_start->refcount++;
++      VTAILQ_INSERT_TAIL(&ban_start->obj, o, ban_list);
+       Lck_Unlock(&ban_mtx);
+ }
+@@ -470,6 +476,7 @@
+       CHECK_OBJ_NOTNULL(o->ban, BAN_MAGIC);
+       Lck_Lock(&ban_mtx);
+       o->ban->refcount--;
++      VTAILQ_REMOVE(&o->ban->obj, o, ban_list);
+       o->ban = NULL;
+       /* Attempt to purge last ban entry */
+@@ -518,8 +525,11 @@
+       Lck_Lock(&ban_mtx);
+       o->ban->refcount--;
+-      if (b == o->ban)        /* not banned */
++      VTAILQ_REMOVE(&o->ban->obj, o, ban_list);
++      if (b == o->ban) {      /* not banned */
++              VTAILQ_INSERT_TAIL(&b0->obj, o, ban_list);
+               b0->refcount++;
++      }
+       VSL_stats->n_purge_obj_test++;
+       VSL_stats->n_purge_re_test += tests;
+       Lck_Unlock(&ban_mtx);
+@@ -529,6 +539,7 @@
+               return (0);
+       } else {
+               o->ttl = 0;
++              o->cacheable = 0;
+               WSP(sp, SLT_ExpBan, "%u was banned", o->xid);
+               EXP_Rearm(o);
+               o->ban = NULL;
+Index: bin/varnishd/default.vcl
+===================================================================
+--- bin/varnishd/default.vcl   (.../tags/varnish-2.0.4/varnish-cache)
++++ bin/varnishd/default.vcl   (.../branches/2.0/varnish-cache)
+@@ -141,8 +141,9 @@
+     <p>"} obj.response {"</p>
+     <h3>Guru Meditation:</h3>
+     <p>XID: "} req.xid {"</p>
++    <hr>
+     <address>
+-       <a href="http://www.varnish-cache.org/">Varnish</a>
++       <a href="http://www.varnish-cache.org/">Varnish cache server</a>
+     </address>
+   </body>
+ </html>
+Index: bin/varnishd/cache_lck.c
+===================================================================
+--- bin/varnishd/cache_lck.c   (.../tags/varnish-2.0.4/varnish-cache)
++++ bin/varnishd/cache_lck.c   (.../branches/2.0/varnish-cache)
+@@ -78,7 +78,7 @@
+               return;
+       }
+       r = pthread_mutex_trylock(&ilck->mtx);
+-      assert(r == 0 || errno == EBUSY);
++      assert(r == 0 || r == EBUSY);
+       if (r) {
+               VSL(SLT_Debug, 0, "MTX_CONTEST(%s,%s,%d,%s)", p, f, l, ilck->w);
+               AZ(pthread_mutex_lock(&ilck->mtx));
+@@ -111,8 +111,8 @@
+       int r;
+       CAST_OBJ_NOTNULL(ilck, lck->priv, ILCK_MAGIC);
+-      r = pthread_mutex_lock(&ilck->mtx);
+-      assert(r == 0 || errno == EBUSY);
++      r = pthread_mutex_trylock(&ilck->mtx);
++      assert(r == 0 || r == EBUSY);
+       if (params->diag_bitmap & 0x8)
+               VSL(SLT_Debug, 0,
+                   "MTX_TRYLOCK(%s,%s,%d,%s) = %d", p, f, l, ilck->w);
+Index: bin/varnishd/cache_vrt.c
+===================================================================
+--- bin/varnishd/cache_vrt.c   (.../tags/varnish-2.0.4/varnish-cache)
++++ bin/varnishd/cache_vrt.c   (.../branches/2.0/varnish-cache)
+@@ -130,7 +130,9 @@
+       return (p);
+ }
+-/*--------------------------------------------------------------------*/
++/*--------------------------------------------------------------------
++ * XXX: Optimize the single element case ?
++ */
+ /*lint -e{818} ap,hp could be const */
+ static char *
+@@ -496,6 +498,25 @@
+ /*--------------------------------------------------------------------*/
++void
++VRT_l_req_esi(struct sess *sp, unsigned process_esi)
++{
++      CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
++      /* only allow you to turn of esi in the main request
++         else everything gets confused */
++      if(sp->esis == 0)
++         sp->disable_esi = !process_esi;
++}
++
++unsigned
++VRT_r_req_esi(struct sess *sp)
++{
++      CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
++      return (!sp->disable_esi);
++}
++
++/*--------------------------------------------------------------------*/
++
+ int
+ VRT_r_req_restarts(const struct sess *sp)
+ {
+@@ -846,20 +867,25 @@
+       }
+       b = BAN_New();
+       good = 0;
+-      for (i = 1; ; i += 3) {
+-              a1 = av[i];
++      for (i = 1; ;) {
++              a1 = av[i++];
+               if (a1 == NULL)
+                       break;
+               good = 0;
+-              a2 = av[i + 1];
++              a2 = av[i++];
+               if (a2 == NULL)
+                       break;
+-              a3 = av[i + 2];
++              a3 = av[i++];
+               if (a3 == NULL)
+                       break;
+               if (BAN_AddTest(NULL, b, a1, a2, a3))
+                       break;
+               good = 1;
++              if (av[i] == NULL)
++                      break;
++              good = 0;
++              if (strcmp(av[i++], "&&"))
++                      break;
+       }
+       if (!good) 
+               /* XXX: report error how ? */
+Index: bin/varnishd/cache_http.c
+===================================================================
+--- bin/varnishd/cache_http.c  (.../tags/varnish-2.0.4/varnish-cache)
++++ bin/varnishd/cache_http.c  (.../branches/2.0/varnish-cache)
+@@ -152,6 +152,11 @@
+       unsigned u;
+       for (u = HTTP_HDR_FIRST; u < hp->nhd; u++) {
++              /* XXX We have to check for empty header entries
++                 because a header could have been lost in 
++                 http_copyHome */
++              if (hp->hd[u].b == NULL)
++                      continue;
+               Tcheck(hp->hd[u]);
+               if (hp->hd[u].e < hp->hd[u].b + l + 1)
+                       continue;
+@@ -327,12 +332,29 @@
+       hp->conds = 0;
+       r = NULL;               /* For FlexeLint */
+       for (; p < t.e; p = r) {
+-              /* XXX: handle continuation lines */
+-              q = strchr(p, '\n');
+-              assert(q != NULL);
+-              r = q + 1;
+-              if (q > p && q[-1] == '\r')
+-                      q--;
++
++              /* Find end of next header */
++              q = r = p;
++              while (r < t.e) {
++                      if (!vct_iscrlf(*r)) {
++                              r++;
++                              continue;
++                      }
++                      q = r;
++                      assert(r < t.e);
++                      r += vct_skipcrlf(r);
++                      if (r >= t.e)
++                              break;
++                      /* If line does not continue: got it. */
++                      if (!vct_issp(*r))
++                              break;
++
++                      /* Clear line continuation LWS to spaces */
++                      while (vct_islws(*q))
++                              *q++ = ' ';
++              }
++
++              /* Empty header = end of headers */
+               if (p == q)
+                       break;
+@@ -368,7 +390,7 @@
+ http_splitline(struct worker *w, int fd, struct http *hp,
+     const struct http_conn *htc, int h1, int h2, int h3)
+ {
+-      char *p;
++      char *p, *q;
+       CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC);
+       CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
+@@ -381,40 +403,47 @@
+               continue;
+       /* First field cannot contain SP, CRLF or CTL */
+-      hp->hd[h1].b = p;
+-      for (; !vct_issp(*p); p++)
++      q = p;
++      for (; !vct_issp(*p); p++) {
+               if (vct_isctl(*p))
+-                      return (400);
++                      return (-1);
++      }
++      hp->hd[h1].b = q;
+       hp->hd[h1].e = p;
+       /* Skip SP */
+-      for (; vct_issp(*p); p++)
+-              ;
++      for (; vct_issp(*p); p++) {
++              if (vct_isctl(*p))
++                      return (-1);
++      }
+-      /* Second field cannot contain LWS */
+-      hp->hd[h2].b = p;
+-      for (; !vct_islws(*p); p++)
+-              ;
++      /* Second field cannot contain LWS or CTL */
++      q = p;
++      for (; !vct_islws(*p); p++) {
++              if (vct_isctl(*p))
++                      return (-1);
++      }
++      hp->hd[h2].b = q;
+       hp->hd[h2].e = p;
+       if (!Tlen(hp->hd[h2]))
+               return (400);
+       /* Skip SP */
+-      for (; vct_issp(*p); p++)
+-              ;
++      for (; vct_issp(*p); p++) {
++              if (vct_isctl(*p))
++                      return (-1);
++      }
+       /* Third field is optional and cannot contain CTL */
++      q = p;
+       if (!vct_iscrlf(*p)) {
+-              hp->hd[h3].b = p;
+               for (; !vct_iscrlf(*p); p++)
+                       if (vct_isctl(*p))
+-                              return (400);
+-              hp->hd[h3].e = p;
+-      } else {
+-              hp->hd[h3].b = p;
+-              hp->hd[h3].e = p;
++                              return (-1);
+       }
++      hp->hd[h3].b = q;
++      hp->hd[h3].e = p;
+       /* Skip CRLF */
+       p += vct_skipcrlf(p);
+@@ -481,25 +510,35 @@
+ http_DissectResponse(struct worker *w, const struct http_conn *htc,
+     struct http *hp)
+ {
+-      int i;
++      int i = 0;
+       CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC);
+       CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
+       hp->logtag = HTTP_Rx;
+-      i = http_splitline(w, htc->fd, hp, htc,
+-          HTTP_HDR_PROTO, HTTP_HDR_STATUS, HTTP_HDR_RESPONSE);
++      if (http_splitline(w, htc->fd, hp, htc,
++          HTTP_HDR_PROTO, HTTP_HDR_STATUS, HTTP_HDR_RESPONSE))
++              i = 503;
+-      if (i != 0 || memcmp(hp->hd[HTTP_HDR_PROTO].b, "HTTP/1.", 7))
++      if (i == 0 && memcmp(hp->hd[HTTP_HDR_PROTO].b, "HTTP/1.", 7))
++              i = 503;
++
++      if (i == 0 && Tlen(hp->hd[HTTP_HDR_STATUS]) != 3)
++              i = 503;
++
++      if (i == 0) {
++              hp->status = strtoul(hp->hd[HTTP_HDR_STATUS].b, NULL, 10);
++              if (hp->status < 100 || hp->status > 999)
++                      i = 503;
++      }
++
++      if (i != 0) {
+               WSLR(w, SLT_HttpGarbage, htc->fd, htc->rxbuf);
+-      if (i != 0) {
+-              if (hp->status == 0)
+-                      hp->status = i;
++              hp->status = i;
+       } else {
+-              hp->status =
+-                  strtoul(hp->hd[HTTP_HDR_STATUS].b, NULL /* XXX */, 10);
++              http_ProtoVer(hp);
+       }
+-      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 */
+@@ -615,6 +654,8 @@
+       to->nhd = HTTP_HDR_FIRST;
+       to->status = fm->status;
+       for (u = HTTP_HDR_FIRST; u < fm->nhd; u++) {
++              if (fm->hd[u].b == NULL)
++                      continue;
+               if (fm->hdf[u] & HDF_FILTER)
+                       continue;
+ #define HTTPH(a, b, c, d, e, f, g) \
+@@ -675,6 +716,8 @@
+                       hp->hd[u].b = p;
+                       hp->hd[u].e = p + l;
+               } else {
++                      /* XXX This leaves a slot empty */
++                      VSL_stats->losthdr++;
+                       WSLR(w, SLT_LostHeader, fd, hp->hd[u]);
+                       hp->hd[u].b = NULL;
+                       hp->hd[u].e = NULL;
+@@ -793,6 +836,8 @@
+       unsigned u, v;
+       for (v = u = HTTP_HDR_FIRST; u < hp->nhd; u++) {
++              if (hp->hd[u].b == NULL)
++                      continue;
+               if (http_IsHdr(&hp->hd[u], hdr))
+                       continue;
+               if (v != u) {
+@@ -829,6 +874,8 @@
+               WSLH(w, *w->wfd, hp, HTTP_HDR_PROTO);
+       }
+       for (u = HTTP_HDR_FIRST; u < hp->nhd; u++) {
++              if (hp->hd[u].b == NULL)
++                      continue;
+               AN(hp->hd[u].b);
+               AN(hp->hd[u].e);
+               l += WRW_WriteH(w, &hp->hd[u], "\r\n");
+Index: bin/varnishd/cache_center.c
+===================================================================
+--- bin/varnishd/cache_center.c        (.../tags/varnish-2.0.4/varnish-cache)
++++ bin/varnishd/cache_center.c        (.../branches/2.0/varnish-cache)
+@@ -80,17 +80,15 @@
+ static unsigned xids;
+ /*--------------------------------------------------------------------
+- * AGAIN
+- * We come here when we just completed a request and already have
+- * received (part of) the next one.  Instead taking the detour
+- * around the acceptor and then back to a worker, just stay in this
+- * worker and do what it takes.
++ * WAIT
++ * Wait until we have a full request in our htc.
+  */
+ static int
+-cnt_again(struct sess *sp)
++cnt_wait(struct sess *sp)
+ {
+       int i;
++      struct pollfd pfd[1];
+       CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
+       AZ(sp->vcl);
+@@ -98,12 +96,32 @@
+       assert(sp->xid == 0);
+       i = HTC_Complete(sp->htc);
+-      while (i == 0)
++      while (i == 0) {
++              if (params->session_linger > 0) {
++                      pfd[0].fd = sp->fd;
++                      pfd[0].events = POLLIN;
++                      pfd[0].revents = 0;
++                      i = poll(pfd, 1, params->session_linger);
++                      if (i == 0) {
++                              WSL(sp->wrk, SLT_Debug, sp->fd, "herding");
++                              VSL_stats->sess_herd++;
++                              sp->wrk = NULL;
++                              vca_return_session(sp);
++                              return (1);
++                      }
++              }
+               i = HTC_Rx(sp->htc);
++      }
+       if (i == 1) {
+               sp->step = STP_START;
+       } else {
+-              vca_close_session(sp, "overflow");
++              if (i == -2)
++                      vca_close_session(sp, "overflow");
++              else if (i == -1 && Tlen(sp->htc->rxbuf) == 0 &&
++                  (errno == 0 || errno == ECONNRESET))
++                      vca_close_session(sp, "EOF");
++              else 
++                      vca_close_session(sp, "error");
+               sp->step = STP_DONE;
+       }
+       return (0);
+@@ -198,7 +216,6 @@
+ cnt_done(struct sess *sp)
+ {
+       double dh, dp, da;
+-      struct pollfd pfd[1];
+       int i;
+       CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
+@@ -240,8 +257,14 @@
+       sp->t_req = NAN;
+-      if (sp->fd >= 0 && sp->doclose != NULL)
++      if (sp->fd >= 0 && sp->doclose != NULL) {
++              /*
++               * This is an orderly close of the connection; ditch linger 
++               * before we close, to get queued data transmitted.
++               */
++              TCP_linger(sp->fd, 0);
+               vca_close_session(sp, sp->doclose);
++      }
+       if (sp->fd < 0) {
+               SES_Charge(sp);
+               VSL_stats->sess_closed++;
+@@ -261,19 +284,13 @@
+       }
+       if (Tlen(sp->htc->rxbuf)) {
+               VSL_stats->sess_readahead++;
+-              sp->step = STP_AGAIN;
++              sp->step = STP_WAIT;
+               return (0);
+       }
+       if (params->session_linger > 0) {
+-              pfd[0].fd = sp->fd;
+-              pfd[0].events = POLLIN;
+-              pfd[0].revents = 0;
+-              i = poll(pfd, 1, params->session_linger);
+-              if (i > 0) {
+-                      VSL_stats->sess_linger++;
+-                      sp->step = STP_AGAIN;
+-                      return (0);
+-              }
++              VSL_stats->sess_linger++;
++              sp->step = STP_WAIT;
++              return (0);
+       }
+       VSL_stats->sess_herd++;
+       SES_Charge(sp);
+@@ -307,7 +324,7 @@
+       w = sp->wrk;
+       if (sp->obj == NULL) {
+-              HSH_Prealloc(sp);
++              HSH_Prealloc(sp, 1);
+               sp->obj = sp->wrk->nobj;
+               sp->obj->xid = sp->xid;
+               sp->obj->entered = sp->t_req;
+@@ -318,6 +335,9 @@
+       CHECK_OBJ_NOTNULL(sp->obj, OBJECT_MAGIC);
+       h = sp->obj->http;
++      if (sp->err_code < 100 || sp->err_code > 999)
++              sp->err_code = 501;
++
+       http_PutProtocol(w, sp->fd, h, "HTTP/1.1");
+       http_PutStatus(w, sp->fd, h, sp->err_code);
+       TIM_format(TIM_real(), date);
+@@ -332,13 +352,15 @@
+                   http_StatusMessage(sp->err_code));
+       VCL_error_method(sp);
+-      if (sp->handling == VCL_RET_RESTART) {
++      if (sp->handling == VCL_RET_RESTART && sp->restarts <  params->max_restarts) {
+               HSH_Drop(sp);
+               sp->director = NULL;
+               sp->restarts++;
+               sp->step = STP_RECV;
+               return (0);
+-      }
++      } else if (sp->handling == VCL_RET_RESTART)
++              sp->handling = VCL_RET_DELIVER;
++                
+       /* We always close when we take this path */
+       sp->doclose = "error";
+@@ -439,6 +461,7 @@
+       if (sp->obj->objhead != NULL) {
+               VRY_Create(sp);
+               EXP_Insert(sp->obj);
++              AN(sp->obj->ban);
+               HSH_Unbusy(sp);
+       }
+       sp->acct_req.fetch++;
+@@ -452,7 +475,6 @@
+ static int
+ cnt_first(struct sess *sp)
+ {
+-      int i;
+       /*
+        * XXX: If we don't have acceptfilters we are somewhat subject
+@@ -473,25 +495,8 @@
+       sp->wrk->lastused = sp->t_open;
+       sp->acct_req.sess++;
+       SES_RefSrcAddr(sp);
+-      do
+-              i = HTC_Rx(sp->htc);
+-      while (i == 0);
+-      switch (i) {
+-      case 1:
+-              sp->step = STP_START;
+-              break;
+-      case -1:
+-              vca_close_session(sp, "error");
+-              sp->step = STP_DONE;
+-              break;
+-      case -2:
+-              vca_close_session(sp, "blast");
+-              sp->step = STP_DONE;
+-              break;
+-      default:
+-              WRONG("Illegal return from HTC_Rx");
+-      }
++      sp->step = STP_WAIT;
+       return (0);
+ }
+@@ -734,7 +739,7 @@
+       }
+       assert(sp->handling == VCL_RET_PASS);
+       sp->acct_req.pass++;
+-      HSH_Prealloc(sp);
++      HSH_Prealloc(sp, 0);
+       sp->obj = sp->wrk->nobj;
+       sp->wrk->nobj = NULL;
+       sp->obj->busy = 1;
+@@ -824,6 +829,8 @@
+       sp->director = sp->vcl->director[0];
+       AN(sp->director);
++              sp->disable_esi = 0;
++      
+       VCL_recv_method(sp);
+       if (sp->restarts >= params->max_restarts) {
+               if (sp->err_code == 0)
+@@ -898,6 +905,13 @@
+       http_Setup(sp->http, sp->ws);
+       done = http_DissectRequest(sp);
++      /* If we could not even parse the request, just close */
++      if (done < 0) {
++              sp->step = STP_DONE;
++              vca_close_session(sp, "junk");
++              return (0);
++      }
++
+       /* Catch request snapshot */
+       sp->ws_req = WS_Snapshot(sp->ws);
+@@ -926,6 +940,10 @@
+               /* XXX: Don't bother with write failures for now */
+               (void)write(sp->fd, r, strlen(r));
++              /* XXX: When we do ESI includes, this is not removed
++               * XXX: because we use http0 as our basis.  Believed
++               * XXX: safe, but potentially confusing.
++               */
+               http_Unset(sp->http, H_Expect);
+       }
+Index: bin/varnishd/cache_session.c
+===================================================================
+--- bin/varnishd/cache_session.c       (.../tags/varnish-2.0.4/varnish-cache)
++++ bin/varnishd/cache_session.c       (.../branches/2.0/varnish-cache)
+@@ -249,35 +249,16 @@
+ /*--------------------------------------------------------------------*/
+-struct sess *
+-SES_New(const struct sockaddr *addr, unsigned len)
++static struct sess *
++ses_setup(struct sessmem *sm, const struct sockaddr *addr, unsigned len)
+ {
+-      struct sessmem *sm;
+       struct sess *sp;
+       volatile unsigned u;
+-      /*
+-       * One of the two queues is unlocked because only one
+-       * thread ever gets here to empty it.
+-       */
+-      assert(ses_qp <= 1);
+-      sm = VTAILQ_FIRST(&ses_free_mem[ses_qp]);
+       if (sm == NULL) {
++              if (VSL_stats->n_sess_mem >= params->max_sess)
++                      return (NULL);
+               /*
+-               * If that queue is empty, flip queues holding the lock
+-               * and try the new unlocked queue.
+-               */
+-              Lck_Lock(&ses_mem_mtx);
+-              ses_qp = 1 - ses_qp;
+-              Lck_Unlock(&ses_mem_mtx);
+-              sm = VTAILQ_FIRST(&ses_free_mem[ses_qp]);
+-      }
+-      if (sm != NULL) {
+-              VTAILQ_REMOVE(&ses_free_mem[ses_qp], sm, list);
+-      } else {
+-              /*
+-               * If that fails, alloc new one.
+-               *
+                * It is not necessary to lock mem_workspace, but we
+                * need to cache it locally, to make sure we get a
+                * consistent view of it.
+@@ -286,6 +267,8 @@
+               sm = malloc(sizeof *sm + u);
+               if (sm == NULL)
+                       return (NULL);
++              /* Don't waste time zeroing the workspace */
++              memset(sm, 0, sizeof *sm);
+               sm->magic = SESSMEM_MAGIC;
+               sm->workspace = u;
+               VSL_stats->n_sess_mem++;
+@@ -293,7 +276,6 @@
+       CHECK_OBJ_NOTNULL(sm, SESSMEM_MAGIC);
+       VSL_stats->n_sess++;
+       sp = &sm->sess;
+-      memset(sp, 0, sizeof *sp);
+       sp->magic = SESS_MAGIC;
+       sp->mem = sm;
+       sp->sockaddr = (void*)(&sm->sockaddr[0]);
+@@ -306,7 +288,8 @@
+       sp->t_resp = NAN;
+       sp->t_end = NAN;
+       sp->grace = NAN;
+-
++      sp->disable_esi = 0;
++      
+       assert(len <= sp->sockaddrlen);
+       if (addr != NULL) {
+               memcpy(sp->sockaddr, addr, len);
+@@ -322,11 +305,49 @@
+       return (sp);
+ }
++/*--------------------------------------------------------------------
++ * Try to recycle an existing session.
++ */
++
++struct sess *
++SES_New(const struct sockaddr *addr, unsigned len)
++{
++      struct sessmem *sm;
++
++      assert(pthread_self() == VCA_thread);
++      assert(ses_qp <= 1);
++      sm = VTAILQ_FIRST(&ses_free_mem[ses_qp]);
++      if (sm == NULL) {
++              /*
++               * If that queue is empty, flip queues holding the lock
++               * and try the new unlocked queue.
++               */
++              Lck_Lock(&ses_mem_mtx);
++              ses_qp = 1 - ses_qp;
++              Lck_Unlock(&ses_mem_mtx);
++              sm = VTAILQ_FIRST(&ses_free_mem[ses_qp]);
++      }
++      if (sm != NULL)
++              VTAILQ_REMOVE(&ses_free_mem[ses_qp], sm, list);
++      return (ses_setup(sm, addr, len));
++}
++
++/*--------------------------------------------------------------------*/
++
++struct sess *
++SES_Alloc(const struct sockaddr *addr, unsigned len)
++{
++      return (ses_setup(NULL, addr, len));
++}
++
++/*--------------------------------------------------------------------*/
++
+ void
+ SES_Delete(struct sess *sp)
+ {
+       struct acct *b = &sp->acct;
+       struct sessmem *sm;
++      unsigned workspace;
+       CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
+       sm = sp->mem;
+@@ -346,6 +367,12 @@
+               VSL_stats->n_sess_mem--;
+               free(sm);
+       } else {
++              /* Clean and prepare for reuse */
++              workspace = sm->workspace;
++              memset(sm, 0, sizeof *sm);
++              sm->magic = SESSMEM_MAGIC;
++              sm->workspace = workspace;
++
+               Lck_Lock(&ses_mem_mtx);
+               VTAILQ_INSERT_HEAD(&ses_free_mem[1 - ses_qp], sm, list);
+               Lck_Unlock(&ses_mem_mtx);
+Index: bin/varnishd/cache_hash.c
+===================================================================
+--- bin/varnishd/cache_hash.c  (.../tags/varnish-2.0.4/varnish-cache)
++++ bin/varnishd/cache_hash.c  (.../branches/2.0/varnish-cache)
+@@ -82,13 +82,14 @@
+ /* Precreate an objhead and object for later use */
+ void
+-HSH_Prealloc(struct sess *sp)
++HSH_Prealloc(struct sess *sp, int transient)
+ {
+       struct worker *w;
+       struct objhead *oh;
+       struct object *o;
+       struct storage *st;
+-
++      void *p;
++      
+       CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
+       CHECK_OBJ_NOTNULL(sp->wrk, WORKER_MAGIC);
+       w = sp->wrk;
+@@ -106,16 +107,26 @@
+               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);
+-              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;
++              if (transient) {
++                      p = malloc(sizeof *o + params->obj_workspace);
++                      XXXAN(p);
++                      o = p;
++                      p = o + 1;
++                      memset(o, 0, sizeof *o);
++                      o->magic = OBJECT_MAGIC;
++                      WS_Init(o->ws_o, "obj", p, params->obj_workspace);
++              } else {
++                      st = STV_alloc(sp, params->obj_workspace);
++                      XXXAN(st);
++                      assert(st->space > sizeof *w->nobj);
++                      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(o->ws_o);
+               http_Setup(o->http, o->ws_o);
+               o->magic = OBJECT_MAGIC;
+@@ -239,7 +250,7 @@
+       AN(hash);
+       w = sp->wrk;
+-      HSH_Prealloc(sp);
++      HSH_Prealloc(sp, 0);
+       SHA256_Final(sp->wrk->nobjhead->digest, sp->wrk->sha256ctx);
+       
+       if (sp->objhead != NULL) {
+@@ -449,7 +460,8 @@
+       if (r != 0)
+               return;
+-      BAN_DestroyObj(o);
++      if (oh != NULL)
++              BAN_DestroyObj(o);
+       DSL(0x40, SLT_Debug, 0, "Object %u workspace min free %u",
+           o->xid, WS_Free(o->ws_o));
+@@ -458,7 +470,11 @@
+       ESI_Destroy(o);
+       HSH_Freestore(o);
+-      STV_free(o->objstore);
++      if (o->objstore != NULL)
++              STV_free(o->objstore);
++      else
++              FREE_OBJ(o);
++              
+       VSL_stats->n_object--;
+       if (oh == NULL)
+Index: bin/varnishd/cache_acceptor_poll.c
+===================================================================
+--- bin/varnishd/cache_acceptor_poll.c (.../tags/varnish-2.0.4/varnish-cache)
++++ bin/varnishd/cache_acceptor_poll.c (.../branches/2.0/varnish-cache)
+@@ -146,6 +146,7 @@
+                               continue;
+                       VTAILQ_REMOVE(&sesshead, sp, list);
+                       vca_unpoll(fd);
++                      TCP_linger(sp->fd, 0);
+                       vca_close_session(sp, "timeout");
+                       SES_Delete(sp);
+               }
+Index: bin/varnishd/cache_acceptor_ports.c
+===================================================================
+--- bin/varnishd/cache_acceptor_ports.c        (.../tags/varnish-2.0.4/varnish-cache)
++++ bin/varnishd/cache_acceptor_ports.c        (.../branches/2.0/varnish-cache)
+@@ -138,6 +138,7 @@
+                       VTAILQ_REMOVE(&sesshead, sp, list);
+                       if(sp->fd != -1)
+                               vca_del(sp->fd);
++                      TCP_linger(sp->fd, 0);
+                       vca_close_session(sp, "timeout");
+                       SES_Delete(sp);
+               }
+Index: bin/varnishd/cache_acceptor_epoll.c
+===================================================================
+--- bin/varnishd/cache_acceptor_epoll.c        (.../tags/varnish-2.0.4/varnish-cache)
++++ bin/varnishd/cache_acceptor_epoll.c        (.../branches/2.0/varnish-cache)
+@@ -1,8 +1,10 @@
+ /*-
+  * Copyright (c) 2006 Verdens Gang AS
+- * Copyright (c) 2006-2008 Linpro AS
++ * Copyright (c) 2006-2009 Linpro AS
+  * All rights reserved.
+  *
++ * Author: Rogerio Carvalho Schneider <stockrt@gmail.com>
++ *
+  * Redistribution and use in source and binary forms, with or without
+  * modification, are permitted provided that the following conditions
+  * are met:
+@@ -36,8 +38,9 @@
+ #if defined(HAVE_EPOLL_CTL)
+ #include <stdio.h>
++#include <string.h>
+ #include <errno.h>
+-#include <string.h>
++#include <fcntl.h>
+ #include <stdlib.h>
+ #include <unistd.h>
+@@ -47,77 +50,148 @@
+ #include "cache.h"
+ #include "cache_acceptor.h"
++#define NEEV  100
++
+ static pthread_t vca_epoll_thread;
++static pthread_t vca_epoll_sess_timeout_ticker_thread;
+ static int epfd = -1;
+ static VTAILQ_HEAD(,sess) sesshead = VTAILQ_HEAD_INITIALIZER(sesshead);
++int dotimer_pipe[2];
+ static void
+-vca_add(int fd, void *data)
++vca_modadd(int fd, void *data, short arm)
+ {
+-      struct epoll_event ev = { EPOLLIN | EPOLLPRI, { data } };
+-      AZ(epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev));
++
++      assert(fd >= 0);
++      if (data == vca_pipes || data == dotimer_pipe) {
++              struct epoll_event ev = { EPOLLIN | EPOLLPRI | EPOLLET, { data } };
++              AZ(epoll_ctl(epfd, arm, fd, &ev));
++      } else {
++              struct sess *sp = (struct sess *)data;
++              CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
++              sp->ev.data.ptr = data;
++#if defined(EPOLLRDHUP)
++              sp->ev.events = EPOLLIN | EPOLLPRI | EPOLLONESHOT | EPOLLRDHUP;
++#else
++              sp->ev.events = EPOLLIN | EPOLLPRI | EPOLLONESHOT;
++#endif
++              AZ(epoll_ctl(epfd, arm, fd, &sp->ev));
++      }
+ }
+ static void
+-vca_del(int fd)
++vca_cond_modadd(int fd, void *data)
+ {
+-      struct epoll_event ev = { 0, { 0 } };
+-      AZ(epoll_ctl(epfd, EPOLL_CTL_DEL, fd, &ev));
++      struct sess *sp = (struct sess *)data;
++
++      assert(fd >= 0);
++      CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
++      if (sp->ev.data.ptr)
++              AZ(epoll_ctl(epfd, EPOLL_CTL_MOD, fd, &sp->ev));
++      else {
++              sp->ev.data.ptr = data;
++#if defined(EPOLLRDHUP)
++              sp->ev.events = EPOLLIN | EPOLLPRI | EPOLLONESHOT | EPOLLRDHUP;
++#else
++              sp->ev.events = EPOLLIN | EPOLLPRI | EPOLLONESHOT;
++#endif
++              AZ(epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &sp->ev));
++      }
+ }
++static void
++vca_eev(const struct epoll_event *ep)
++{
++      struct sess *ss[NEEV], *sp;
++      int i, j;
++
++      AN(ep->data.ptr);
++      if (ep->data.ptr == vca_pipes) {
++              if (ep->events & EPOLLIN || ep->events & EPOLLPRI) {
++                      j = 0;
++                      i = read(vca_pipes[0], ss, sizeof ss);
++                      if (i == -1 && errno == EAGAIN)
++                              return;
++                      while (i >= sizeof ss[0]) {
++                              CHECK_OBJ_NOTNULL(ss[j], SESS_MAGIC);
++                              assert(ss[j]->fd >= 0);
++                              AZ(ss[j]->obj);
++                              VTAILQ_INSERT_TAIL(&sesshead, ss[j], list);
++                              vca_cond_modadd(ss[j]->fd, ss[j]);
++                              j++;
++                              i -= sizeof ss[0];
++                      }
++                      assert(i == 0);
++              }
++      } else {
++              CAST_OBJ_NOTNULL(sp, ep->data.ptr, SESS_MAGIC);
++              if (ep->events & EPOLLIN || ep->events & EPOLLPRI) {
++                      i = HTC_Rx(sp->htc);
++                      if (i == 0) {
++                              vca_modadd(sp->fd, sp, EPOLL_CTL_MOD);
++                              return; /* more needed */
++                      }
++                      VTAILQ_REMOVE(&sesshead, sp, list);
++                      vca_handover(sp, i);
++              } else if (ep->events & EPOLLERR) {
++                      VTAILQ_REMOVE(&sesshead, sp, list);
++                      vca_close_session(sp, "ERR");
++                      SES_Delete(sp);
++              } else if (ep->events & EPOLLHUP) {
++                      VTAILQ_REMOVE(&sesshead, sp, list);
++                      vca_close_session(sp, "HUP");
++                      SES_Delete(sp);
++#if defined(EPOLLRDHUP)
++              } else if (ep->events & EPOLLRDHUP) {
++                      VTAILQ_REMOVE(&sesshead, sp, list);
++                      vca_close_session(sp, "RHUP");
++                      SES_Delete(sp);
++#endif
++              }
++      }
++}
++
++/*--------------------------------------------------------------------*/
++
+ static void *
+ vca_main(void *arg)
+ {
+-      struct epoll_event ev;
++      struct epoll_event ev[NEEV], *ep;
++      struct sess *sp;
+       double deadline;
+-      int dotimer = 0;
+-      double last_timeout = 0, tmp_timeout;
+-      struct sess *sp, *sp2;
+-      int i;
++      int dotimer, i, n;
+       THR_SetName("cache-epoll");
+       (void)arg;
+-      epfd = epoll_create(16);
++      epfd = epoll_create(1);
+       assert(epfd >= 0);
+-      vca_add(vca_pipes[0], vca_pipes);
++      vca_modadd(vca_pipes[0], vca_pipes, EPOLL_CTL_ADD);
++      vca_modadd(dotimer_pipe[0], dotimer_pipe, EPOLL_CTL_ADD);
+       while (1) {
+-              if ((dotimer = epoll_wait(epfd, &ev, 1, 100)) > 0) {
+-                      if (ev.data.ptr == vca_pipes) {
+-                              i = read(vca_pipes[0], &sp, sizeof sp);
+-                              assert(i == sizeof sp);
+-                              CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
+-                              VTAILQ_INSERT_TAIL(&sesshead, sp, list);
+-                              vca_add(sp->fd, sp);
+-                      } else {
+-                              CAST_OBJ_NOTNULL(sp, ev.data.ptr, SESS_MAGIC);
+-                              i = HTC_Rx(sp->htc);
+-                              if (i != 0) {
+-                                      VTAILQ_REMOVE(&sesshead, sp, list);
+-                                      vca_del(sp->fd);
+-                                      vca_handover(sp, i);
+-                              }
+-                      }
++              dotimer = 0;
++              n = epoll_wait(epfd, ev, NEEV, -1);
++              for (ep = ev, i = 0; i < n; i++, ep++) {
++                      if (ep->data.ptr == dotimer_pipe && (ep->events == EPOLLIN || ep->events == EPOLLPRI))
++                              dotimer = 1;
++                      else
++                              vca_eev(ep);
+               }
+-              tmp_timeout = TIM_mono();
+-              if ((tmp_timeout - last_timeout) > 60) {
+-                      last_timeout = tmp_timeout;
+-              } else {
+-                      if (dotimer > 0)
+-                              continue;
+-              }
++              if (!dotimer)
++                      continue;
+               /* check for timeouts */
+               deadline = TIM_real() - params->sess_timeout;
+-              VTAILQ_FOREACH_SAFE(sp, &sesshead, list, sp2) {
+-                      CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
++              for (;;) {
++                      sp = VTAILQ_FIRST(&sesshead);
++                      if (sp == NULL)
++                              break;
+                       if (sp->t_open > deadline)
+-                              continue;
++                              break;
+                       VTAILQ_REMOVE(&sesshead, sp, list);
+-                      vca_del(sp->fd);
+                       vca_close_session(sp, "timeout");
+                       SES_Delete(sp);
+               }
+@@ -126,10 +200,44 @@
+ /*--------------------------------------------------------------------*/
++static void *
++vca_sess_timeout_ticker(void *arg)
++{
++      char ticker = 'R';
++      char junk;
++
++      THR_SetName("cache-epoll-sess_timeout_ticker");
++      (void)arg;
++
++      while (1) {
++              /* ticking */
++              assert(write(dotimer_pipe[1], &ticker, 1));
++              TIM_sleep(100 * 1e-3);
++              assert(read(dotimer_pipe[0], &junk, 1));
++      }
++}
++
++/*--------------------------------------------------------------------*/
++
+ static void
+ vca_epoll_init(void)
+ {
++      int i;
++      i = fcntl(vca_pipes[0], F_GETFL);
++      assert(i != -1);
++      i |= O_NONBLOCK;
++      i = fcntl(vca_pipes[0], F_SETFL, i);
++      assert(i != -1);
++
++      AZ(pipe(dotimer_pipe));
++      i = fcntl(dotimer_pipe[0], F_GETFL);
++      assert(i != -1);
++      i |= O_NONBLOCK;
++      i = fcntl(dotimer_pipe[0], F_SETFL, i);
++      assert(i != -1);
++
++      AZ(pthread_create(&vca_epoll_sess_timeout_ticker_thread, NULL, vca_sess_timeout_ticker, NULL));
+       AZ(pthread_create(&vca_epoll_thread, NULL, vca_main, NULL));
+ }
+Index: bin/varnishd/varnishd.c
+===================================================================
+--- bin/varnishd/varnishd.c    (.../tags/varnish-2.0.4/varnish-cache)
++++ bin/varnishd/varnishd.c    (.../branches/2.0/varnish-cache)
+@@ -339,7 +339,8 @@
+       pipes[1][1] = 1;
+       /* close the rest */
+-      for (i = 5; i < getdtablesize(); i++)
++      j = getdtablesize();
++      for (i = 5; i < j; i++)
+               (void)close(i);
+       pfd[0].fd = pipes[0][0];
+@@ -414,6 +415,92 @@
+       exit (2);
+ }
++/*--------------------------------------------------------------------
++ * All praise POSIX!  Thanks to our glorious standards there are no
++ * standard way to get a back-trace of the stack, and even if we hack
++ * that together from spit and pieces of string, there is no way no
++ * standard way to translate a pointer to a symbol, which returns anything
++ * usable.  (See for instance FreeBSD PR-134391).
++ *
++ * Attempt to run nm(1) on our binary during startup, hoping it will
++ * give us a usable list of symbols.
++ */
++
++struct symbols {
++      uintptr_t               a;
++      char                    *n;
++      VTAILQ_ENTRY(symbols)   list;
++};
++
++static VTAILQ_HEAD(,symbols) symbols = VTAILQ_HEAD_INITIALIZER(symbols);
++
++int
++Symbol_Lookup(struct vsb *vsb, void *ptr)
++{
++      struct symbols *s, *s0;
++      uintptr_t pp;
++
++      pp = (uintptr_t)ptr;
++      s0 = NULL;
++      VTAILQ_FOREACH(s, &symbols, list) {
++              if (s->a > pp)
++                      continue;
++              if (s0 == NULL || s->a > s0->a)
++                      s0 = s;
++      }
++      if (s0 == NULL)
++              return (-1);
++      vsb_printf(vsb, "%p: %s+%jx", ptr, s0->n, (uintmax_t)pp - s0->a);
++      return (0);
++}
++
++static void
++Symbol_hack(const char *a0)
++{
++      char buf[BUFSIZ], *p, *e;
++      FILE *fi;
++      uintptr_t a;
++      struct symbols *s;
++
++      p = NULL;
++      asprintf(&p, "nm -an %s", a0);
++      if (p == NULL)
++              return;
++      fi = popen(p, "r");
++      free(p);
++      if (fi == NULL) 
++              return;
++      while (fgets(buf, sizeof buf, fi)) {
++              if (buf[0] == ' ')
++                      continue;
++              p = NULL;
++              a = strtoul(buf, &p, 16);
++              if (p == NULL)
++                      continue;
++              if (a == 0)
++                      continue;
++              if (*p++ != ' ')
++                      continue;
++              p++;
++              if (*p++ != ' ')
++                      continue;
++              if (*p <= ' ')
++                      continue;
++              e = strchr(p, '\0');
++              AN(e);
++              while (e > p && isspace(e[-1]))
++                      e--;
++              *e = '\0';
++              s = malloc(sizeof *s + strlen(p) + 1);
++              AN(s);
++              s->a = a;
++              s->n = (void*)(s + 1);
++              strcpy(s->n, p);
++              VTAILQ_INSERT_TAIL(&symbols, s, list);
++      }
++      (void)pclose(fi);
++}
++
+ /*--------------------------------------------------------------------*/
+ int
+@@ -443,6 +530,11 @@
+       setbuf(stdout, NULL);
+       setbuf(stderr, NULL);
++      Symbol_hack(argv[0]);
++
++      /* for ASSERT_MGT() */
++      mgt_pid = getpid();
++
+       /*
+        * Run in UTC timezone, on the off-chance that this operating
+        * system does not have a timegm() function, and translates
+Index: bin/varnishd/cache_pool.c
+===================================================================
+--- bin/varnishd/cache_pool.c  (.../tags/varnish-2.0.4/varnish-cache)
++++ bin/varnishd/cache_pool.c  (.../branches/2.0/varnish-cache)
+@@ -618,6 +618,58 @@
+       }
+ }
++/*--------------------------------------------------------------------
++ * Create and starte a back-ground thread which as its own worker and
++ * session data structures;
++ */
++
++struct bgthread {
++      unsigned        magic;
++#define BGTHREAD_MAGIC        0x23b5152b
++      const char      *name;
++      bgthread_t      *func;
++      void            *priv;
++};
++
++static void *
++wrk_bgthread(void *arg)
++{
++      struct bgthread *bt;
++      struct worker ww;
++      struct sess *sp;
++      unsigned char logbuf[1024];     /* XXX:  size ? */
++
++      CAST_OBJ_NOTNULL(bt, arg, BGTHREAD_MAGIC);
++      THR_SetName(bt->name);
++      sp = SES_Alloc(NULL, 0);
++      XXXAN(sp);
++      memset(&ww, 0, sizeof ww);
++      sp->wrk = &ww;
++      ww.magic = WORKER_MAGIC;
++      ww.wlp = ww.wlb = logbuf;
++      ww.wle = logbuf + sizeof logbuf;
++
++      (void)bt->func(sp, bt->priv);
++
++      WRONG("BgThread terminated");
++
++      return (NULL);
++}
++
++void
++WRK_BgThread(pthread_t *thr, const char *name, bgthread_t *func, void *priv)
++{
++      struct bgthread *bt;
++
++      ALLOC_OBJ(bt, BGTHREAD_MAGIC);
++      AN(bt);
++
++      bt->name = name;
++      bt->func = func;
++      bt->priv = priv;
++      AZ(pthread_create(thr, NULL, wrk_bgthread, bt));
++}
++
+ /*--------------------------------------------------------------------*/
+ void
+Index: bin/varnishd/cache_backend_poll.c
+===================================================================
+--- bin/varnishd/cache_backend_poll.c  (.../tags/varnish-2.0.4/varnish-cache)
++++ bin/varnishd/cache_backend_poll.c  (.../branches/2.0/varnish-cache)
+@@ -241,18 +241,82 @@
+ }
+ /*--------------------------------------------------------------------
+- * One thread per backend to be poked.
++ * Record pokings...
+  */
+-static void *
+-vbp_wrk_poll_backend(void *priv)
++static void
++vbp_start_poke(struct vbp_target *vt)
+ {
+-      struct vbp_target *vt;
++      CHECK_OBJ_NOTNULL(vt, VBP_TARGET_MAGIC);
++
++#define BITMAP(n, c, t, b)    vt->n <<= 1;
++#include "cache_backend_poll.h"
++#undef BITMAP
++
++      vt->last = 0;
++      vt->resp_buf[0] = '\0';
++}
++
++static void
++vbp_has_poked(struct vbp_target *vt)
++{
+       unsigned i, j;
+       uint64_t u;
+       const char *logmsg;
+       char bits[10];
++      CHECK_OBJ_NOTNULL(vt, VBP_TARGET_MAGIC);
++
++      /* Calculate exponential average */
++      if (vt->happy & 1) {
++              if (vt->rate < AVG_RATE)
++                      vt->rate += 1.0;
++              vt->avg += (vt->last - vt->avg) / vt->rate;
++      }
++
++      i = 0;
++#define BITMAP(n, c, t, b)    bits[i++] = (vt->n & 1) ? c : '-';
++#include "cache_backend_poll.h"
++#undef BITMAP
++      bits[i] = '\0';
++
++      u = vt->happy;
++      for (i = j = 0; i < vt->probe.window; i++) {
++              if (u & 1)
++                      j++;
++              u >>= 1;
++      }
++      vt->good = j;
++
++      if (vt->good >= vt->probe.threshold) {
++              if (vt->backend->healthy)
++                      logmsg = "Still healthy";
++              else
++                      logmsg = "Back healthy";
++              vt->backend->healthy = 1;
++      } else {
++              if (vt->backend->healthy)
++                      logmsg = "Went sick";
++              else
++                      logmsg = "Still sick";
++              vt->backend->healthy = 0;
++      }
++      VSL(SLT_Backend_health, 0, "%s %s %s %u %u %u %.6f %.6f %s",
++          vt->backend->vcl_name, logmsg, bits,
++          vt->good, vt->probe.threshold, vt->probe.window,
++          vt->last, vt->avg, vt->resp_buf);
++}
++
++/*--------------------------------------------------------------------
++ * One thread per backend to be poked.
++ */
++
++static void *
++vbp_wrk_poll_backend(void *priv)
++{
++      struct vbp_target *vt;
++      unsigned u;
++
+       THR_SetName("backend poll");
+       CAST_OBJ_NOTNULL(vt, priv, VBP_TARGET_MAGIC);
+@@ -272,59 +336,25 @@
+       if (vt->probe.threshold == 0)
+               vt->probe.threshold = 3;
++      if (vt->probe.threshold == ~0U)
++              vt->probe.initial = vt->probe.threshold - 1;
++
++      if (vt->probe.initial > vt->probe.threshold)
++              vt->probe.initial = vt->probe.threshold;
++
+       printf("Probe(\"%s\", %g, %g)\n",
+-          vt->req,
+-          vt->probe.timeout,
+-          vt->probe.interval);
++          vt->req, vt->probe.timeout, vt->probe.interval);
+-      /*lint -e{525} indent */
++      for (u = 0; u < vt->probe.initial; u++) {
++              vbp_start_poke(vt);
++              vt->happy |= 1;
++              vbp_has_poked(vt);
++      }
++
+       while (!vt->stop) {
+-#define BITMAP(n, c, t, b)    vt->n <<= 1;
+-#include "cache_backend_poll.h"
+-#undef BITMAP
+-              vt->last = 0;
+-              vt->resp_buf[0] = '\0';
++              vbp_start_poke(vt);
+               vbp_poke(vt);
+-
+-              /* Calculate exponential average */
+-              if (vt->happy & 1) {
+-                      if (vt->rate < AVG_RATE)
+-                              vt->rate += 1.0;
+-                      vt->avg += (vt->last - vt->avg) / vt->rate;
+-              }
+-
+-              i = 0;
+-#define BITMAP(n, c, t, b)    bits[i++] = (vt->n & 1) ? c : '-';
+-#include "cache_backend_poll.h"
+-#undef BITMAP
+-              bits[i] = '\0';
+-
+-              u = vt->happy;
+-              for (i = j = 0; i < vt->probe.window; i++) {
+-                      if (u & 1)
+-                              j++;
+-                      u >>= 1;
+-              }
+-              vt->good = j;
+-
+-              if (vt->good >= vt->probe.threshold) {
+-                      if (vt->backend->healthy)
+-                              logmsg = "Still healthy";
+-                      else
+-                              logmsg = "Back healthy";
+-                      vt->backend->healthy = 1;
+-              } else {
+-                      if (vt->backend->healthy)
+-                              logmsg = "Went sick";
+-                      else
+-                              logmsg = "Still sick";
+-                      vt->backend->healthy = 0;
+-              }
+-              VSL(SLT_Backend_health, 0, "%s %s %s %u %u %u %.6f %.6f %s",
+-                  vt->backend->vcl_name, logmsg, bits,
+-                  vt->good, vt->probe.threshold, vt->probe.window,
+-                  vt->last, vt->avg, vt->resp_buf);
+-
++              vbp_has_poked(vt);
+               if (!vt->stop)
+                       TIM_sleep(vt->probe.interval);
+       }
+Index: bin/varnishd/cache.h
+===================================================================
+--- bin/varnishd/cache.h       (.../tags/varnish-2.0.4/varnish-cache)
++++ bin/varnishd/cache.h       (.../branches/2.0/varnish-cache)
+@@ -48,6 +48,10 @@
+ #include <limits.h>
+ #include <unistd.h>
++#if defined(HAVE_EPOLL_CTL)
++#include <sys/epoll.h>
++#endif
++
+ #include "vqueue.h"
+ #include "vsb.h"
+@@ -58,8 +62,6 @@
+ #include "heritage.h"
+ #include "miniobj.h"
+-#define HTTP_HDR_MAX_VAL 32
+-
+ enum {
+       /* Fields from the first line of HTTP proto */
+       HTTP_HDR_REQ,
+@@ -283,6 +285,7 @@
+       struct http             http[1];
+       VTAILQ_ENTRY(object)    list;
++      VTAILQ_ENTRY(object)    ban_list;
+       VTAILQ_HEAD(, storage)  store;
+@@ -308,6 +311,7 @@
+       int                     restarts;
+       int                     esis;
++      int                     disable_esi;
+       struct worker           *wrk;
+@@ -376,6 +380,10 @@
+       unsigned                ihashptr;
+       unsigned                lhashptr;
+       const char              **hashptr;
++
++#if defined(HAVE_EPOLL_CTL)
++      struct epoll_event ev;
++#endif
+ };
+@@ -398,6 +406,7 @@
+ void vca_close_session(struct sess *sp, const char *why);
+ void VCA_Prep(struct sess *sp);
+ void VCA_Init(void);
++extern pthread_t VCA_thread;
+ /* cache_backend.c */
+@@ -544,9 +553,13 @@
+ void WRW_Sendfile(struct worker *w, int fd, off_t off, unsigned len);
+ #endif  /* SENDFILE_WORKS */
++typedef void *bgthread_t(struct sess *, void *priv);
++void WRK_BgThread(pthread_t *thr, const char *name, bgthread_t *func, void *priv);
++
+ /* cache_session.c [SES] */
+ void SES_Init(void);
+ struct sess *SES_New(const struct sockaddr *addr, unsigned len);
++struct sess *SES_Alloc(const struct sockaddr *addr, unsigned len);
+ void SES_Delete(struct sess *sp);
+ void SES_RefSrcAddr(struct sess *sp);
+ void SES_Charge(struct sess *sp);
+Index: bin/varnishd/cache_pipe.c
+===================================================================
+--- bin/varnishd/cache_pipe.c  (.../tags/varnish-2.0.4/varnish-cache)
++++ bin/varnishd/cache_pipe.c  (.../branches/2.0/varnish-cache)
+@@ -102,8 +102,12 @@
+       sp->t_resp = TIM_real();
+       memset(fds, 0, sizeof fds);
++
++      TCP_linger(vc->fd, 0);
+       fds[0].fd = vc->fd;
+       fds[0].events = POLLIN | POLLERR;
++
++      TCP_linger(sp->fd, 0);
+       fds[1].fd = sp->fd;
+       fds[1].events = POLLIN | POLLERR;
+Index: bin/varnishd/cache_acceptor.c
+===================================================================
+--- bin/varnishd/cache_acceptor.c      (.../tags/varnish-2.0.4/varnish-cache)
++++ bin/varnishd/cache_acceptor.c      (.../branches/2.0/varnish-cache)
+@@ -65,11 +65,20 @@
+ static struct acceptor const *vca_act;
+-static pthread_t      vca_thread_acct;
++pthread_t             VCA_thread;
+ static struct timeval tv_sndtimeo;
+ static struct timeval tv_rcvtimeo;
+-static struct linger  linger;
++/*
++ * We want to get out of any kind of touble-hit TCP connections as fast
++ * as absolutely possible, so we set them LINGER enabled with zero timeout,
++ * so that even if there are outstanding write data on the socket, a close(2)
++ * will return immediately.
++ */
++static const struct linger linger = {
++      .l_onoff        =       1,
++};
++
+ static unsigned char  need_sndtimeo, need_rcvtimeo, need_linger, need_test;
+ int vca_pipes[2];
+@@ -106,13 +115,17 @@
+       need_test = 0;
+ }
++/*--------------------------------------------------------------------
++ * Called once the workerthread gets hold of the session, to do setup
++ * setup overhead, we don't want to bother the acceptor thread with.
++ */
++
+ void
+ VCA_Prep(struct sess *sp)
+ {
+       char addr[TCP_ADDRBUFSIZE];
+       char port[TCP_PORTBUFSIZE];
+-
+       TCP_name(sp->sockaddr, sp->sockaddrlen,
+           addr, sizeof addr, port, sizeof port);
+       sp->addr = WS_Dup(sp->ws, addr);
+@@ -239,11 +252,15 @@
+                               continue;
+                       }
+                       sp = SES_New(addr, l);
+-                      XXXAN(sp);
+-
++                      if (sp == NULL) {
++                              AZ(close(i));
++                              VSL_stats->client_drop++;
++                              continue;
++                      }
+                       sp->fd = i;
+                       sp->id = i;
+                       sp->t_open = now;
++                      sp->t_end = now;
+                       sp->mylsock = ls;
+                       sp->step = STP_FIRST;
+@@ -330,7 +347,7 @@
+       if (vca_act->pass == NULL)
+               AZ(pipe(vca_pipes));
+       vca_act->init();
+-      AZ(pthread_create(&vca_thread_acct, NULL, vca_acct, NULL));
++      AZ(pthread_create(&VCA_thread, NULL, vca_acct, NULL));
+       VSL(SLT_Debug, 0, "Acceptor is %s", vca_act->name);
+ }
+Index: bin/varnishd/shmlog.c
+===================================================================
+--- bin/varnishd/shmlog.c      (.../tags/varnish-2.0.4/varnish-cache)
++++ bin/varnishd/shmlog.c      (.../branches/2.0/varnish-cache)
+@@ -71,16 +71,19 @@
+ vsl_wrap(void)
+ {
++      assert(loghead->magic == SHMLOGHEAD_MAGIC);
+       *logstart = SLT_ENDMARKER;
+       logstart[loghead->ptr] = SLT_WRAPMARKER;
+       loghead->ptr = 0;
+       VSL_stats->shm_cycles++;
++      assert(loghead->magic == SHMLOGHEAD_MAGIC);
+ }
+ static void
+ vsl_hdr(enum shmlogtag tag, unsigned char *p, unsigned len, unsigned id)
+ {
++      assert(loghead->magic == SHMLOGHEAD_MAGIC);
+       assert(len < 0x10000);
+       assert(id < 0x10000);
+       p[__SHMLOG_LEN_HIGH] = (len >> 8) & 0xff;
+@@ -280,13 +283,18 @@
+ void
+ VSL_Panic(int *len, char **ptr)
+ {
++      static char a[1] = { '\0' }; 
+       AN(len);
+       AN(ptr);
+-      assert(loghead->magic == SHMLOGHEAD_MAGIC);
+-      assert(loghead->hdrsize == sizeof *loghead);
+-      *len = sizeof(loghead->panicstr);
+-      *ptr = loghead->panicstr;
++      if (loghead->magic == SHMLOGHEAD_MAGIC) {
++              assert(loghead->hdrsize == sizeof *loghead);
++              *len = sizeof(loghead->panicstr);
++              *ptr = loghead->panicstr;
++      } else {
++              *len = 0;
++              *ptr = a;
++      }
+ }
+ /*--------------------------------------------------------------------*/
+Index: bin/varnishd/mgt_child.c
+===================================================================
+--- bin/varnishd/mgt_child.c   (.../tags/varnish-2.0.4/varnish-cache)
++++ bin/varnishd/mgt_child.c   (.../branches/2.0/varnish-cache)
+@@ -236,7 +236,7 @@
+       unsigned u;
+       char *p;
+       struct vev *e;
+-      int i, cp[2];
++      int i, j, cp[2];
+       if (child_state != CH_STOPPED && child_state != CH_DIED)
+               return;
+@@ -304,7 +304,8 @@
+               /* Close anything we shouldn't know about */
+               closelog();
+               printf("Closed fds:");
+-              for (i = STDERR_FILENO + 1; i < getdtablesize(); i++) {
++              j = getdtablesize();
++              for (i = STDERR_FILENO + 1; i < j; i++) {
+                       if (vbit_test(fd_map, i))
+                               continue;
+                       if (close(i) == 0)
+@@ -345,7 +346,6 @@
+       e->callback = child_listener;
+       AZ(vev_add(mgt_evb, e));
+       ev_listen = e;
+-
+       AZ(ev_poker);
+       if (params->ping_interval > 0) {
+               e = vev_new();
+@@ -362,11 +362,10 @@
+       if (mgt_push_vcls_and_start(&u, &p)) {
+               REPORT(LOG_ERR, "Pushing vcls failed: %s", p);
+               free(p);
+-              /* Pick up any stuff lingering on stdout/stderr */
+-              (void)child_listener(NULL, EV_RD);
+-              exit(2);
+-      }
+-      child_state = CH_RUNNING;
++              child_state = CH_RUNNING;
++              mgt_stop_child();
++      } else
++              child_state = CH_RUNNING;
+ }
+ /*--------------------------------------------------------------------*/
+Index: bin/varnishd/heritage.h
+===================================================================
+--- bin/varnishd/heritage.h    (.../tags/varnish-2.0.4/varnish-cache)
++++ bin/varnishd/heritage.h    (.../branches/2.0/varnish-cache)
+@@ -82,6 +82,9 @@
+       /* TTL used for synthesized error pages */
+       unsigned                err_ttl;
++      /* Maximum concurrent sessions */
++      unsigned                max_sess;
++
+       /* Worker threads and pool */
+       unsigned                wthread_min;
+       unsigned                wthread_max;
+Index: bin/varnishd/common.h
+===================================================================
+--- bin/varnishd/common.h      (.../tags/varnish-2.0.4/varnish-cache)
++++ bin/varnishd/common.h      (.../branches/2.0/varnish-cache)
+@@ -42,6 +42,10 @@
+ void VSL_MgtInit(const char *fn, unsigned size);
+ extern struct varnish_stats *VSL_stats;
++/* varnishd.c */
++struct vsb;
++int Symbol_Lookup(struct vsb *vsb, void *ptr);
++
+ #define TRUST_ME(ptr) ((void*)(uintptr_t)(ptr))
+ /* Really belongs in mgt.h, but storage_file chokes on both */
+Index: man/vcl.7so
+===================================================================
+--- man/vcl.7so        (.../tags/varnish-2.0.4/varnish-cache)
++++ man/vcl.7so        (.../branches/2.0/varnish-cache)
+@@ -93,6 +93,11 @@
+ }
+ .Ed
+ .Pp
++To avoid overloading backend servers,
++.Fa .max_connections
++can be set to limit the maximum number of concurrent backend connections.
++.Ed
++.Pp
+ The timeout parameters can be overridden in the backend declaration.
+ The timeout parameters are
+ .Fa .connect_timeout
+@@ -570,6 +575,9 @@
+ .It Va obj.lastuse
+ The approximate time elapsed since the object was last requests, in
+ seconds.
++.It Va obj.hits
++The approximate number of times the object has been delivered. A value of 0
++indicates a cache miss.
+ .El
+ .Pp
+ The following variables are available while determining the hash key
diff --git a/branch.sh b/branch.sh
new file mode 100644 (file)
index 0000000..e83c0f2
--- /dev/null
+++ b/branch.sh
@@ -0,0 +1,29 @@
+#!/bin/sh
+set -e
+svn=http://varnish.projects.linpro.no/svn
+tag=varnish-2.0.4/varnish-cache
+branch=2.0/varnish-cache
+out=branch.diff
+
+d=$-
+filter() {
+       set -$d
+       # Excluding files which change version or were not in dist tarball
+       filterdiff \
+               -x 'nothing' \
+               | \
+       # remove revno's for smaller diffs
+       sed -e 's,^\([-+]\{3\} .*\)\t(revision [0-9]\+)$,\1,'
+}
+
+old=$svn/tags/$tag
+new=$svn/branches/$branch
+echo >&2 "Running diff: $old -> $new"
+LC_ALL=C svn diff --old=$old --new=$new | filter > $out.tmp
+
+if cmp -s $out{,.tmp}; then
+       echo >&2 "No new diffs..."
+       rm -f $out.tmp
+       exit 0
+fi
+mv -f $out.diff{.tmp,}
index dee634c0d94dbff2bd41984176c73617231726a3..a567e9b58541e667c58aebec04ac5902a80981be 100644 (file)
@@ -4,7 +4,7 @@ Summary:        Varnish - a high-performance HTTP accelerator
 Summary(pl.UTF-8):     Varnish - wydajny akcelerator HTTP
 Name:          varnish
 Version:       2.0.4
-Release:       2
+Release:       2.1
 License:       BSD
 Group:         Networking/Daemons/HTTP
 Source0:       http://dl.sourceforge.net/varnish/%{name}-%{version}.tar.gz
@@ -16,6 +16,7 @@ Source4:      %{name}.sysconfig
 Source5:       %{name}ncsa.sysconfig
 Source6:       %{name}.logrotate
 Source7:       %{name}.conf
+Patch100:      branch.diff
 Patch0:                %{name}-build.patch
 URL:           http://www.varnish-cache.org/
 BuildRequires: autoconf
@@ -86,6 +87,7 @@ Statyczna biblioteka varnish.
 
 %prep
 %setup -q
+%patch100 -p0
 %patch0 -p1
 
 %build
@@ -157,7 +159,7 @@ fi
 
 %files
 %defattr(644,root,root,755)
-%doc LICENSE README ChangeLog
+%doc LICENSE README ChangeLog etc/*.vcl
 %dir %{_sysconfdir}/%{name}
 %config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/%{name}/default.vcl
 %config(noreplace) %verify(not md5 mtime size) /etc/sysconfig/varnish
This page took 0.235391 seconds and 4 git commands to generate.