r1693 - in branches/1.1: . bin/varnishd doc include lib/libvarnish lib/libvcl man

des at projects.linpro.no des at projects.linpro.no
Fri Jul 13 16:54:51 CEST 2007


Author: des
Date: 2007-07-13 16:54:51 +0200 (Fri, 13 Jul 2007)
New Revision: 1693

Added:
   branches/1.1/lib/libvcl/vcc_string.c
Modified:
   branches/1.1/
   branches/1.1/bin/varnishd/Makefile.am
   branches/1.1/bin/varnishd/cache.h
   branches/1.1/bin/varnishd/cache_acceptor.c
   branches/1.1/bin/varnishd/cache_acceptor.h
   branches/1.1/bin/varnishd/cache_acceptor_epoll.c
   branches/1.1/bin/varnishd/cache_acceptor_kqueue.c
   branches/1.1/bin/varnishd/cache_acceptor_poll.c
   branches/1.1/bin/varnishd/cache_backend.c
   branches/1.1/bin/varnishd/cache_center.c
   branches/1.1/bin/varnishd/cache_expire.c
   branches/1.1/bin/varnishd/cache_fetch.c
   branches/1.1/bin/varnishd/cache_hash.c
   branches/1.1/bin/varnishd/cache_http.c
   branches/1.1/bin/varnishd/cache_lru.c
   branches/1.1/bin/varnishd/cache_main.c
   branches/1.1/bin/varnishd/cache_pipe.c
   branches/1.1/bin/varnishd/cache_pool.c
   branches/1.1/bin/varnishd/cache_response.c
   branches/1.1/bin/varnishd/cache_session.c
   branches/1.1/bin/varnishd/cache_synthetic.c
   branches/1.1/bin/varnishd/cache_vrt.c
   branches/1.1/bin/varnishd/cache_vrt_re.c
   branches/1.1/bin/varnishd/mgt_child.c
   branches/1.1/bin/varnishd/mgt_cli.c
   branches/1.1/bin/varnishd/mgt_cli.h
   branches/1.1/bin/varnishd/mgt_event.c
   branches/1.1/bin/varnishd/rfc2616.c
   branches/1.1/bin/varnishd/shmlog.c
   branches/1.1/bin/varnishd/varnishd.1
   branches/1.1/doc/changes-1.0.4-1.1.xml
   branches/1.1/include/cli.h
   branches/1.1/include/libvarnish.h
   branches/1.1/include/shmlog_tags.h
   branches/1.1/include/vrt.h
   branches/1.1/include/vrt_obj.h
   branches/1.1/lib/libvarnish/Makefile.am
   branches/1.1/lib/libvarnish/time.c
   branches/1.1/lib/libvcl/Makefile.am
   branches/1.1/lib/libvcl/syntax.txt
   branches/1.1/lib/libvcl/vcc_acl.c
   branches/1.1/lib/libvcl/vcc_action.c
   branches/1.1/lib/libvcl/vcc_compile.c
   branches/1.1/lib/libvcl/vcc_compile.h
   branches/1.1/lib/libvcl/vcc_fixed_token.c
   branches/1.1/lib/libvcl/vcc_gen_obj.tcl
   branches/1.1/lib/libvcl/vcc_obj.c
   branches/1.1/lib/libvcl/vcc_parse.c
   branches/1.1/lib/libvcl/vcc_var.c
   branches/1.1/lib/libvcl/vcc_xref.c
   branches/1.1/man/vcl.7
Log:
Merged revisions 1649-1650,1655-1692 via svnmerge from 
svn+ssh://projects.linpro.no/svn/varnish/trunk/varnish-cache

........
  r1657 | phk | 2007-07-05 23:08:15 +0200 (Thu, 05 Jul 2007) | 2 lines
  
  Clean up FlexeLint fluff.
........
  r1658 | phk | 2007-07-06 12:07:30 +0200 (Fri, 06 Jul 2007) | 3 lines
  
  Don't rewrite pipe'ed requests to "GET".
........
  r1659 | phk | 2007-07-09 22:23:41 +0200 (Mon, 09 Jul 2007) | 10 lines
  
  Make all protocol header fields writable, except obj.status and resp.status
  (which are numeric, they'll follow shortly)
  
  Unify the shmemlog tag used for failure to rewrite something, the Rx/Tx/Obj
  distinction is not helpful enough to warrant the complexity of it.
........
  r1660 | phk | 2007-07-09 22:34:59 +0200 (Mon, 09 Jul 2007) | 2 lines
  
  Allow assignment to INT type variables
........
  r1661 | phk | 2007-07-09 22:35:20 +0200 (Mon, 09 Jul 2007) | 2 lines
  
  Allow assignment to obj.status and resp.status
........
  r1662 | phk | 2007-07-10 21:46:16 +0200 (Tue, 10 Jul 2007) | 6 lines
  
  Move string stuff to vcc_string.c, there's going to be a fair bit of it.
  
  Give vcc_StringVal() a return value to say if it did anything so we can
  emit better error messages when confused.
........
  r1663 | phk | 2007-07-10 21:59:39 +0200 (Tue, 10 Jul 2007) | 5 lines
  
  Add conversion from IP to string format to allow things like:
  
  	set bereq.http.HeyYou = client.ip " asked for  " req.url;
........
  r1664 | phk | 2007-07-10 22:07:07 +0200 (Tue, 10 Jul 2007) | 3 lines
  
  Properly emit the header name in VRT_SetHdr();
........
  r1665 | phk | 2007-07-10 22:08:39 +0200 (Tue, 10 Jul 2007) | 2 lines
  
  Fix VRT_SetHdr() prototype
........
  r1666 | phk | 2007-07-10 22:43:24 +0200 (Tue, 10 Jul 2007) | 2 lines
  
  Add compiler side support for regsub() but only a dummy function in VRT.
........
  r1667 | phk | 2007-07-10 23:30:47 +0200 (Tue, 10 Jul 2007) | 60 lines
  
  Add "regsub" support for string manipulation.
  
  Notice this facility is subject to change!
  
  "regsub" is short for regular expression substitution and it is probably
  easiest to explain with some examples:
  
  	sub vcl_recv {
  		set req.url = regsub(req.url, "#.*", "");
  	}
  
  This will replace the requests URL with the output of the regsub() function
  
  regsub() takes three arguments: the string to be examined, a regular
  expression and a replacement string.
  
  In this case, everything after the first '#' is removed (replaced
  with nothing).
  
  The replacement string recognizes the following magic sequences:
  	&	- insert everything matched by the regexp
  	$0	- ditto.
  	$1	- replace with the first submatch of the regexp
  	$2	- replace with the second submatch of the regexp
  	...
  	$9	- replace with the ninth submatch of the regexp
  
  (The $0..$9 syntax was chosen over the \0...\9 syntax in order to avoid
  a nightmare of escape characters in the VCL source code.  Arguments and
  suggestions are welcome).
  
  A more advanced example:
  
  	set bereq.http.ClientIP = regsub(client.ip, "(.*):(.*)", "$2 $1");
  
  The client.ip variable expands to IP:port number, for instance
  	127.0.0.1:54662
  
  The regular expression "(.*):(.*)" results in the the following matches:
  	& + $0		"127.0.0.1:54662"
  	$1		"127.0.0.1"
  	$2		"54662"
  
  So the replacement string "$2 $1" results in "54662 127.0.0.1"
  
  And the completed header which is sent to the backend will look like:
  
  	"ClientIP: 54662 127.0.0.1"
  
  An even more advanced example would be:
  
      set bereq.http.magic = "Client IP = " regsub(client.ip, ":", " port = ");
  
  Where we also exploint the string concatenation ability of the "set" statement.
  
  The result string is built in the request workspace, so you may need
  to increase the workspace size if you do a lot of regsub()'s.
  
  Currently there is no decent error handling for running out of workspace.
........
  r1668 | phk | 2007-07-12 11:04:54 +0200 (Thu, 12 Jul 2007) | 6 lines
  
  Add TIM_mono() and TIM_real() which return double representations of
  timestamps on a monotonic and the UTC timescales respectively.
  
  Doubles are much more convenient than timespecs for comparisons etc.
........
  r1669 | phk | 2007-07-12 11:25:07 +0200 (Thu, 12 Jul 2007) | 2 lines
  
  Replace ev_now() with TIM_mono().
........
  r1670 | phk | 2007-07-12 11:25:45 +0200 (Thu, 12 Jul 2007) | 2 lines
  
  Replace Uptime() with TIM_mono()
........
  r1671 | phk | 2007-07-12 11:49:26 +0200 (Thu, 12 Jul 2007) | 6 lines
  
  Change all timekeeping to use doubles instead of time_t and struct timespec.
  
  Eliminate all direct calls to time(2) and clockgettime(2) and use TIM_real()
  and TIM_mono() exclusively.
........
  r1672 | phk | 2007-07-12 12:00:13 +0200 (Thu, 12 Jul 2007) | 2 lines
  
  Document timescale of srcaddr->ttl
........
  r1673 | phk | 2007-07-12 12:13:29 +0200 (Thu, 12 Jul 2007) | 2 lines
  
  Convert the last time(2) calls to TIM_real()
........
  r1674 | cecilihf | 2007-07-12 12:20:33 +0200 (Thu, 12 Jul 2007) | 2 lines
  
  Added a new cli option, status, for checking the status of the varnish child process. This is for use in the webmin plugin.
........
  r1675 | cecilihf | 2007-07-12 12:27:37 +0200 (Thu, 12 Jul 2007) | 2 lines
  
  Fixed typo
........
  r1676 | des | 2007-07-12 18:00:04 +0200 (Thu, 12 Jul 2007) | 2 lines
  
  RT_LIBS dependency has moved from varnishd to libvarnish.
........
  r1677 | des | 2007-07-12 18:02:47 +0200 (Thu, 12 Jul 2007) | 2 lines
  
  Add missing semicolon.
........
  r1678 | des | 2007-07-12 19:37:44 +0200 (Thu, 12 Jul 2007) | 2 lines
  
  sockaddr.sa_len is not portable.
........
  r1682 | phk | 2007-07-13 09:11:54 +0200 (Fri, 13 Jul 2007) | 2 lines
  
  Initialize all timestamps in the session to NAN
........
  r1683 | phk | 2007-07-13 09:21:46 +0200 (Fri, 13 Jul 2007) | 4 lines
  
  Unify the recycle functionality of the acceptors, all three used the same
  method.
........
  r1684 | phk | 2007-07-13 09:27:50 +0200 (Fri, 13 Jul 2007) | 2 lines
  
  Clean all but t_open timestamps to NAN at end of transaction.
........
  r1685 | phk | 2007-07-13 09:47:45 +0200 (Fri, 13 Jul 2007) | 9 lines
  
  Rename the "idle" field of struct worker to "used", which is more precise.
  
  Don't use the "used" field to signal suicide for worker threads,
  use the "wrq" field which is much more natural.
  
  Set the "used" field to NAN before doing anything and assert that
  somebody updated during the task.
........
  r1686 | phk | 2007-07-13 09:53:08 +0200 (Fri, 13 Jul 2007) | 2 lines
  
  Clarify XXX comment
........
  r1687 | phk | 2007-07-13 09:58:11 +0200 (Fri, 13 Jul 2007) | 3 lines
  
  Move setting of t_resp up to before we build the response.
........
  r1688 | phk | 2007-07-13 10:05:14 +0200 (Fri, 13 Jul 2007) | 2 lines
  
  Add an XXX comment
........
  r1690 | des | 2007-07-13 13:42:02 +0200 (Fri, 13 Jul 2007) | 2 lines
  
  Add an entry for r1531.
........
  r1691 | des | 2007-07-13 16:27:55 +0200 (Fri, 13 Jul 2007) | 2 lines
  
  Document regsub().
........
  r1692 | des | 2007-07-13 16:53:48 +0200 (Fri, 13 Jul 2007) | 2 lines
  
  Document recent changes.
........



Property changes on: branches/1.1
___________________________________________________________________
Name: svnmerge-integrated
   - /trunk/varnish-cache:1-1648,1651-1654
   + /trunk/varnish-cache:1-1692

Modified: branches/1.1/bin/varnishd/Makefile.am
===================================================================
--- branches/1.1/bin/varnishd/Makefile.am	2007-07-13 14:53:48 UTC (rev 1692)
+++ branches/1.1/bin/varnishd/Makefile.am	2007-07-13 14:54:51 UTC (rev 1693)
@@ -68,4 +68,4 @@
 	$(top_builddir)/lib/libvarnish/libvarnish.la \
 	$(top_builddir)/lib/libcompat/libcompat.a \
 	$(top_builddir)/lib/libvcl/libvcl.la \
-	${DL_LIBS} ${RT_LIBS} ${PTHREAD_LIBS}
+	${DL_LIBS} ${PTHREAD_LIBS}

Modified: branches/1.1/bin/varnishd/cache.h
===================================================================
--- branches/1.1/bin/varnishd/cache.h	2007-07-13 14:53:48 UTC (rev 1692)
+++ branches/1.1/bin/varnishd/cache.h	2007-07-13 14:54:51 UTC (rev 1693)
@@ -131,7 +131,7 @@
 /*--------------------------------------------------------------------*/
 
 struct acct {
-	time_t			first;
+	double			first;
 	uint64_t		sess;
 	uint64_t		req;
 	uint64_t		pipe;
@@ -149,7 +149,7 @@
 	struct objhead		*nobjhead;
 	struct object		*nobj;
 
-	time_t			idle;
+	double			used;
 
 	int			pipe[2];
 
@@ -247,11 +247,11 @@
 	unsigned		busy;
 	unsigned		len;
 
-	time_t			age;
-	time_t			entered;
-	time_t			ttl;
+	double			age;
+	double			entered;
+	double			ttl;
 
-	time_t			last_modified;
+	double			last_modified;
 
 	struct http		http;
 	TAILQ_ENTRY(object)	list;
@@ -262,7 +262,7 @@
 
 	TAILQ_HEAD(, sess)	waitinglist;
 
-	time_t			lru_stamp;
+	double			lru_stamp;
 	TAILQ_ENTRY(object)	lru;
 };
 
@@ -300,10 +300,11 @@
 	const char		*doclose;
 	struct http		*http;
 
-	struct timespec		t_open;
-	struct timespec		t_req;
-	struct timespec		t_resp;
-	struct timespec		t_end;
+	/* Timestamps, all on TIM_real() timescale */
+	double			t_open;
+	double			t_req;
+	double			t_resp;
+	double			t_end;
 
 	enum step		step;
 	unsigned 		handling;
@@ -359,6 +360,7 @@
 void vca_close_session(struct sess *sp, const char *why);
 void VCA_Prep(struct sess *sp);
 void VCA_Init(void);
+extern int vca_pipes[2];
 
 /* cache_backend.c */
 void VBE_Init(void);
@@ -412,6 +414,7 @@
 void http_PutResponse(struct worker *w, int fd, struct http *to, const char *response);
 void http_PrintfHeader(struct worker *w, int fd, struct http *to, const char *fmt, ...);
 void http_SetHeader(struct worker *w, int fd, struct http *to, const char *hdr);
+void http_SetH(struct http *to, unsigned n, const char *fm);
 void http_Setup(struct http *ht, void *space, unsigned len);
 int http_GetHdr(struct http *hp, const char *hdr, char **ptr);
 int http_GetHdrField(struct http *hp, const char *hdr, const char *field, char **ptr);
@@ -428,7 +431,6 @@
 void http_DoConnection(struct sess *sp);
 void http_CopyHome(struct worker *w, int fd, struct http *hp);
 void http_Unset(struct http *hp, const char *hdr);
-void http_LogLostHeader(struct worker *w, int fd, struct http *hp, const char *hdr);
 
 
 #define HTTPH(a, b, c, d, e, f, g) extern char b[];
@@ -492,11 +494,11 @@
 
 /* cache_lru.c */
 // void LRU_Init(void);
-void LRU_Enter(struct object *o, time_t stamp);
+void LRU_Enter(struct object *o, double stamp);
 void LRU_Remove(struct object *o);
 int LRU_DiscardOne(void);
 int LRU_DiscardSpace(int64_t quota);
-int LRU_DiscardTime(time_t cutoff);
+int LRU_DiscardTime(double cutoff);
 
 #define VCL_RET_MAC(l,u,b,n)
 #define VCL_MET_MAC(l,u,b) void VCL_##l##_method(struct sess *);

Modified: branches/1.1/bin/varnishd/cache_acceptor.c
===================================================================
--- branches/1.1/bin/varnishd/cache_acceptor.c	2007-07-13 14:53:48 UTC (rev 1692)
+++ branches/1.1/bin/varnishd/cache_acceptor.c	2007-07-13 14:54:51 UTC (rev 1693)
@@ -44,10 +44,6 @@
 #include <sys/types.h>
 #include <sys/socket.h>
 
-#ifndef HAVE_CLOCK_GETTIME
-#include "compat/clock_gettime.h"
-#endif
-
 #ifndef HAVE_SRANDOMDEV
 #include "compat/srandomdev.h"
 #endif
@@ -80,6 +76,8 @@
 
 static unsigned char	need_sndtimeo, need_rcvtimeo, need_linger, need_test;
 
+int vca_pipes[2];
+
 static void
 sock_test(int fd)
 {
@@ -116,7 +114,7 @@
 	TCP_name(sp->sockaddr, sp->sockaddrlen,
 	    sp->addr, sizeof sp->addr, sp->port, sizeof sp->port);
 	VSL(SLT_SessionOpen, sp->fd, "%s %s", sp->addr, sp->port);
-	sp->acct.first = sp->t_open.tv_sec;
+	sp->acct.first = sp->t_open;
 	if (need_test)
 		sock_test(sp->fd);
 	if (need_linger)
@@ -195,7 +193,7 @@
 
 			sp->fd = i;
 			sp->id = i;
-			(void)clock_gettime(CLOCK_REALTIME, &sp->t_open);
+			sp->t_open = TIM_real();
 
 			http_RecvPrep(sp->http);
 			sp->step = STP_FIRST;
@@ -259,7 +257,10 @@
 	CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
 	AZ(sp->obj);
 	AZ(sp->vcl);
-	vca_act->recycle(sp);
+	if (sp->fd < 0)
+		SES_Delete(sp);
+	else
+		 assert(sizeof sp == write(vca_pipes[1], &sp, sizeof sp));
 }
 
 
@@ -277,6 +278,7 @@
 		fprintf(stderr, "No acceptor in program\n");
 		exit (2);
 	}
+	AZ(pipe(vca_pipes));
 	vca_act->init();
 	AZ(pthread_create(&vca_thread_acct, NULL, vca_acct, NULL));
 }

Modified: branches/1.1/bin/varnishd/cache_acceptor.h
===================================================================
--- branches/1.1/bin/varnishd/cache_acceptor.h	2007-07-13 14:53:48 UTC (rev 1692)
+++ branches/1.1/bin/varnishd/cache_acceptor.h	2007-07-13 14:54:51 UTC (rev 1693)
@@ -32,12 +32,10 @@
 struct sess;
 
 typedef void acceptor_init_f(void);
-typedef void acceptor_recycle_f(struct sess *);
 
 struct acceptor {
 	const char 		*name;
 	acceptor_init_f		*init;
-	acceptor_recycle_f	*recycle;
 };
 
 #if defined(HAVE_EPOLL_CTL)

Modified: branches/1.1/bin/varnishd/cache_acceptor_epoll.c
===================================================================
--- branches/1.1/bin/varnishd/cache_acceptor_epoll.c	2007-07-13 14:53:48 UTC (rev 1692)
+++ branches/1.1/bin/varnishd/cache_acceptor_epoll.c	2007-07-13 14:54:51 UTC (rev 1693)
@@ -41,10 +41,6 @@
 
 #include <sys/epoll.h>
 
-#ifndef HAVE_CLOCK_GETTIME
-#include "compat/clock_gettime.h"
-#endif
-
 #include "heritage.h"
 #include "shmlog.h"
 #include "cache.h"
@@ -52,7 +48,6 @@
 
 static pthread_t vca_epoll_thread;
 static int epfd = -1;
-static int pipes[2];
 
 static TAILQ_HEAD(,sess) sesshead = TAILQ_HEAD_INITIALIZER(sesshead);
 
@@ -74,7 +69,7 @@
 vca_main(void *arg)
 {
 	struct epoll_event ev;
-	struct timespec ts;
+	double deadline;
 	struct sess *sp, *sp2;
 	int i;
 
@@ -83,12 +78,12 @@
 	epfd = epoll_create(16);
 	assert(epfd >= 0);
 
-	vca_add(pipes[0], pipes);
+	vca_add(vca_pipes[0], vca_pipes);
 
 	while (1) {
 		if (epoll_wait(epfd, &ev, 1, 100) > 0) {
-			if (ev.data.ptr == pipes) {
-				i = read(pipes[0], &sp, sizeof sp);
+			if (ev.data.ptr == vca_pipes) {
+				i = read(vca_pipes[0], &sp, sizeof sp);
 				assert(i == sizeof sp);
 				CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
 				TAILQ_INSERT_TAIL(&sesshead, sp, list);
@@ -108,15 +103,11 @@
 			}
 		}
 		/* check for timeouts */
-		clock_gettime(CLOCK_REALTIME, &ts);
-		ts.tv_sec -= params->sess_timeout;
+		deadline = TIM_real() - params->sess_timeout;
 		TAILQ_FOREACH_SAFE(sp, &sesshead, list, sp2) {
 			CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
-			if (sp->t_open.tv_sec > ts.tv_sec)
+			if (sp->t_open > deadline)
 				continue;
-			if (sp->t_open.tv_sec == ts.tv_sec &&
-			    sp->t_open.tv_nsec > ts.tv_nsec)
-				continue;
 			TAILQ_REMOVE(&sesshead, sp, list);
 			vca_del(sp->fd);
 			vca_close_session(sp, "timeout");
@@ -128,27 +119,15 @@
 /*--------------------------------------------------------------------*/
 
 static void
-vca_epoll_recycle(struct sess *sp)
-{
-
-	if (sp->fd < 0)
-		SES_Delete(sp);
-	else
-		assert(sizeof sp == write(pipes[1], &sp, sizeof sp));
-}
-
-static void
 vca_epoll_init(void)
 {
 
-	AZ(pipe(pipes));
 	AZ(pthread_create(&vca_epoll_thread, NULL, vca_main, NULL));
 }
 
 struct acceptor acceptor_epoll = {
 	.name =		"epoll",
 	.init =		vca_epoll_init,
-	.recycle =	vca_epoll_recycle,
 };
 
 #endif /* defined(HAVE_EPOLL_CTL) */

Modified: branches/1.1/bin/varnishd/cache_acceptor_kqueue.c
===================================================================
--- branches/1.1/bin/varnishd/cache_acceptor_kqueue.c	2007-07-13 14:53:48 UTC (rev 1692)
+++ branches/1.1/bin/varnishd/cache_acceptor_kqueue.c	2007-07-13 14:54:51 UTC (rev 1693)
@@ -43,10 +43,6 @@
 
 #include <sys/event.h>
 
-#ifndef HAVE_CLOCK_GETTIME
-#include "compat/clock_gettime.h"
-#endif
-
 #include "heritage.h"
 #include "shmlog.h"
 #include "cache.h"
@@ -56,7 +52,6 @@
 static int kq = -1;
 
 static TAILQ_HEAD(,sess) sesshead = TAILQ_HEAD_INITIALIZER(sesshead);
-static int pipes[2];
 
 #define NKEV	100
 
@@ -85,9 +80,9 @@
 	struct sess *ss[NKEV];
 
 	AN(kp->udata);
-	if (kp->udata == pipes) {
+	if (kp->udata == vca_pipes) {
 		j = 0;
-		i = read(pipes[0], ss, sizeof ss);
+		i = read(vca_pipes[0], ss, sizeof ss);
 		if (i == -1 && errno == EAGAIN)
 			return;
 		while (i >= sizeof ss[0]) {
@@ -129,7 +124,7 @@
 {
 	struct kevent ke[NKEV], *kp;
 	int j, n, dotimer;
-	struct timespec ts;
+	double deadline;
 	struct sess *sp;
 
 	(void)arg;
@@ -139,7 +134,7 @@
 
 	j = 0;
 	EV_SET(&ke[j++], 0, EVFILT_TIMER, EV_ADD, 0, 100, NULL);
-	EV_SET(&ke[j++], pipes[0], EVFILT_READ, EV_ADD, 0, 0, pipes);
+	EV_SET(&ke[j++], vca_pipes[0], EVFILT_READ, EV_ADD, 0, 0, vca_pipes);
 	AZ(kevent(kq, ke, j, NULL, 0, NULL));
 
 	nki = 0;
@@ -160,17 +155,13 @@
 		}
 		if (!dotimer)
 			continue;
-		clock_gettime(CLOCK_REALTIME, &ts);
-		ts.tv_sec -= params->sess_timeout;
+		deadline = TIM_real() - params->sess_timeout;
 		for (;;) {
 			sp = TAILQ_FIRST(&sesshead);
 			if (sp == NULL)
 				break;
-			if (sp->t_open.tv_sec > ts.tv_sec)
+			if (sp->t_open > deadline)
 				break;
-			if (sp->t_open.tv_sec == ts.tv_sec &&
-			    sp->t_open.tv_nsec > ts.tv_nsec)
-				break;
 			TAILQ_REMOVE(&sesshead, sp, list);
 			vca_close_session(sp, "timeout");
 			SES_Delete(sp);
@@ -181,24 +172,13 @@
 /*--------------------------------------------------------------------*/
 
 static void
-vca_kqueue_recycle(struct sess *sp)
-{
-
-	if (sp->fd < 0)
-		SES_Delete(sp);
-	else
-		assert(write(pipes[1], &sp, sizeof sp) == sizeof sp);
-}
-
-static void
 vca_kqueue_init(void)
 {
 	int i;
 
-	AZ(pipe(pipes));
-	i = fcntl(pipes[0], F_GETFL);
+	i = fcntl(vca_pipes[0], F_GETFL);
 	i |= O_NONBLOCK;
-	i = fcntl(pipes[0], F_SETFL, i);
+	i = fcntl(vca_pipes[0], F_SETFL, i);
 
 	AZ(pthread_create(&vca_kqueue_thread, NULL, vca_kqueue_main, NULL));
 }
@@ -206,7 +186,6 @@
 struct acceptor acceptor_kqueue = {
 	.name =		"kqueue",
 	.init =		vca_kqueue_init,
-	.recycle =	vca_kqueue_recycle,
 };
 
 #endif /* defined(HAVE_KQUEUE) */

Modified: branches/1.1/bin/varnishd/cache_acceptor_poll.c
===================================================================
--- branches/1.1/bin/varnishd/cache_acceptor_poll.c	2007-07-13 14:53:48 UTC (rev 1692)
+++ branches/1.1/bin/varnishd/cache_acceptor_poll.c	2007-07-13 14:54:51 UTC (rev 1693)
@@ -42,10 +42,6 @@
 #include <unistd.h>
 #include <poll.h>
 
-#ifndef HAVE_CLOCK_GETTIME
-#include "compat/clock_gettime.h"
-#endif
-
 #include "heritage.h"
 #include "shmlog.h"
 #include "cache.h"
@@ -55,8 +51,6 @@
 static struct pollfd *pollfd;
 static unsigned npoll;
 
-static int pipes[2];
-
 static TAILQ_HEAD(,sess) sesshead = TAILQ_HEAD_INITIALIZER(sesshead);
 
 /*--------------------------------------------------------------------*/
@@ -108,25 +102,24 @@
 {
 	unsigned v;
 	struct sess *sp, *sp2;
-	struct timespec ts;
+	double deadline;
 	int i, fd;
 
 	(void)arg;
 
-	vca_poll(pipes[0]);
+	vca_poll(vca_pipes[0]);
 
 	while (1) {
 		v = poll(pollfd, npoll, 100);
-		if (v && pollfd[pipes[0]].revents) {
+		if (v && pollfd[vca_pipes[0]].revents) {
 			v--;
-			i = read(pipes[0], &sp, sizeof sp);
+			i = read(vca_pipes[0], &sp, sizeof sp);
 			assert(i == sizeof sp);
 			CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
 			TAILQ_INSERT_TAIL(&sesshead, sp, list);
 			vca_poll(sp->fd);
 		}
-		clock_gettime(CLOCK_REALTIME, &ts);
-		ts.tv_sec -= params->sess_timeout;
+		deadline = TIM_real() - params->sess_timeout;
 		TAILQ_FOREACH_SAFE(sp, &sesshead, list, sp2) {
 			if (v == 0)
 				break;
@@ -145,11 +138,8 @@
 					SES_Delete(sp);
 				continue;
 			}
-			if (sp->t_open.tv_sec > ts.tv_sec)
+			if (sp->t_open > deadline)
 				continue;
-			if (sp->t_open.tv_sec == ts.tv_sec &&
-			    sp->t_open.tv_nsec > ts.tv_nsec)
-				continue;
 			TAILQ_REMOVE(&sesshead, sp, list);
 			vca_unpoll(fd);
 			vca_close_session(sp, "timeout");
@@ -161,26 +151,15 @@
 /*--------------------------------------------------------------------*/
 
 static void
-vca_poll_recycle(struct sess *sp)
-{
-
-	if (sp->fd < 0)
-		SES_Delete(sp);
-	else
-		assert(sizeof sp == write(pipes[1], &sp, sizeof sp));
-}
-
-static void
 vca_poll_init(void)
 {
-	AZ(pipe(pipes));
+
 	AZ(pthread_create(&vca_poll_thread, NULL, vca_main, NULL));
 }
 
 struct acceptor acceptor_poll = {
 	.name =		"poll",
 	.init =		vca_poll_init,
-	.recycle =	vca_poll_recycle,
 };
 
 #endif /* defined(HAVE_POLL) */

Modified: branches/1.1/bin/varnishd/cache_backend.c
===================================================================
--- branches/1.1/bin/varnishd/cache_backend.c	2007-07-13 14:53:48 UTC (rev 1692)
+++ branches/1.1/bin/varnishd/cache_backend.c	2007-07-13 14:54:51 UTC (rev 1693)
@@ -48,10 +48,6 @@
 #include <sys/select.h>
 #include <sys/ioctl.h>
 
-#ifndef HAVE_CLOCK_GETTIME
-#include "compat/clock_gettime.h"
-#endif
-
 #include "heritage.h"
 #include "shmlog.h"
 #include "cache.h"
@@ -64,19 +60,7 @@
 static MTX vbemtx;
 
 /*--------------------------------------------------------------------*/
-/* XXX: belongs a more general place */
 
-static double
-Uptime(void)
-{
-	struct timespec ts;
-
-	assert(clock_gettime(CLOCK_MONOTONIC, &ts) == 0);
-	return (ts.tv_sec + ts.tv_nsec * 1e-9);
-}
-
-/*--------------------------------------------------------------------*/
-
 struct bereq *
 vbe_new_bereq(void)
 {
@@ -153,7 +137,7 @@
 	error = getaddrinfo(bp->hostname,
 	    bp->portname == NULL ? "http" : bp->portname,
 	    &hint, &res);
-	bp->dnstime = Uptime();
+	bp->dnstime = TIM_mono();
 	if (error) {
 		if (res != NULL)
 			freeaddrinfo(res);
@@ -207,7 +191,7 @@
 		}
 	}
 
-	if (bp->dnstime + bp->dnsttl >= Uptime())
+	if (bp->dnstime + bp->dnsttl >= TIM_mono())
 		return (-1);
 
 	/* Then do another lookup to catch DNS changes */

Modified: branches/1.1/bin/varnishd/cache_center.c
===================================================================
--- branches/1.1/bin/varnishd/cache_center.c	2007-07-13 14:53:48 UTC (rev 1692)
+++ branches/1.1/bin/varnishd/cache_center.c	2007-07-13 14:54:51 UTC (rev 1693)
@@ -58,14 +58,11 @@
 
 #include <stdio.h>
 #include <errno.h>
+#include <math.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 
-#ifndef HAVE_CLOCK_GETTIME
-#include "compat/clock_gettime.h"
-#endif
-
 #ifndef HAVE_SRANDOMDEV
 #include "compat/srandomdev.h"
 #endif
@@ -149,6 +146,7 @@
 cnt_deliver(struct sess *sp)
 {
 
+	sp->t_resp = TIM_real();
 	RES_BuildHttp(sp);
 	VCL_deliver_method(sp);
 	if (sp->handling != VCL_RET_DELIVER) 
@@ -172,16 +170,6 @@
 DOT	]
  */
 
-static double
-cnt_dt(struct timespec *t1, struct timespec *t2)
-{
-	double dt;
-
-	dt = (t2->tv_sec - t1->tv_sec);
-	dt += (t2->tv_nsec - t1->tv_nsec) * 1e-9;
-	return (dt);
-}
-
 static int
 cnt_done(struct sess *sp)
 {
@@ -197,24 +185,24 @@
 		sp->vcl = NULL;
 	}
 
-	clock_gettime(CLOCK_REALTIME, &sp->t_end);
-	sp->wrk->idle = sp->t_end.tv_sec;
+	sp->t_end = TIM_real();
+	sp->wrk->used = sp->t_end;
 	if (sp->xid == 0) {
 		sp->t_req = sp->t_end;
 		sp->t_resp = sp->t_end;
 	}
-	dp = cnt_dt(&sp->t_req, &sp->t_resp);
-	da = cnt_dt(&sp->t_resp, &sp->t_end);
-	dh = cnt_dt(&sp->t_open, &sp->t_req);
-	WSL(sp->wrk, SLT_ReqEnd, sp->id, "%u %ld.%09ld %ld.%09ld %.9f %.9f %.9f",
-	    sp->xid,
-	    (long)sp->t_req.tv_sec, (long)sp->t_req.tv_nsec,
-	    (long)sp->t_end.tv_sec, (long)sp->t_end.tv_nsec,
-	    dh, dp, da);
+	dp = sp->t_resp - sp->t_req;
+	da = sp->t_end - sp->t_resp;
+	dh = sp->t_req - sp->t_open;
+	WSL(sp->wrk, SLT_ReqEnd, sp->id, "%u %.9f %.9f %.9f %.9f %.9f",
+	    sp->xid, sp->t_req, sp->t_end, dh, dp, da);
 
 	sp->xid = 0;
-	sp->t_open = sp->t_end;
 	SES_Charge(sp);
+	sp->t_open = sp->t_end;
+	sp->t_req = NAN;
+	sp->t_resp = NAN;
+	sp->t_end = NAN;
 	WSL_Flush(sp->wrk);
 	if (sp->fd >= 0 && sp->doclose != NULL)
 		vca_close_session(sp, sp->doclose);
@@ -345,7 +333,7 @@
 
 	assert(sp->xid == 0);
 	VCA_Prep(sp);
-	sp->wrk->idle = sp->t_open.tv_sec;
+	sp->wrk->used = sp->t_open;
 	sp->wrk->acct.sess++;
 	SES_RefSrcAddr(sp);
 	do
@@ -672,8 +660,8 @@
 
 	/* Update stats of various sorts */
 	VSL_stats->client_req++;			/* XXX not locked */
-	clock_gettime(CLOCK_REALTIME, &sp->t_req);
-	sp->wrk->idle = sp->t_req.tv_sec;
+	sp->t_req = TIM_real();
+	sp->wrk->used = sp->t_req;
 	sp->wrk->acct.req++;
 
 	/* Assign XID and log */

Modified: branches/1.1/bin/varnishd/cache_expire.c
===================================================================
--- branches/1.1/bin/varnishd/cache_expire.c	2007-07-13 14:53:48 UTC (rev 1692)
+++ branches/1.1/bin/varnishd/cache_expire.c	2007-07-13 14:54:51 UTC (rev 1693)
@@ -103,11 +103,11 @@
 exp_hangman(void *arg)
 {
 	struct object *o;
-	time_t t;
+	double t;
 
 	(void)arg;
 
-	t = time(NULL);
+	t = TIM_real();
 	while (1) {
 		LOCK(&exp_mtx);
 		TAILQ_FOREACH(o, &exp_deathrow, deathrow) {
@@ -127,7 +127,7 @@
 		if (o == NULL) {
 			UNLOCK(&exp_mtx);
 			AZ(sleep(1));
-			t = time(NULL);
+			t = TIM_real();
 			continue;
 		}
 		TAILQ_REMOVE(&exp_deathrow, o, deathrow);
@@ -153,7 +153,7 @@
 {
 	struct worker ww;
 	struct object *o;
-	time_t t;
+	double t;
 	struct sess *sp;
 	struct object *o2;
 
@@ -168,7 +168,7 @@
 
 	sleep(10);		/* Takes time for VCL to arrive */
 	VCL_Get(&sp->vcl);
-	t = time(NULL);
+	t = TIM_real();
 	while (1) {
 		LOCK(&exp_mtx);
 		o = binheap_root(exp_heap);
@@ -178,7 +178,7 @@
 			UNLOCK(&exp_mtx);
 			AZ(sleep(1));
 			VCL_Refresh(&sp->vcl);
-			t = time(NULL);
+			t = TIM_real();
 			continue;
 		}
 		binheap_delete(exp_heap, o->heap_idx);

Modified: branches/1.1/bin/varnishd/cache_fetch.c
===================================================================
--- branches/1.1/bin/varnishd/cache_fetch.c	2007-07-13 14:53:48 UTC (rev 1692)
+++ branches/1.1/bin/varnishd/cache_fetch.c	2007-07-13 14:54:51 UTC (rev 1693)
@@ -303,7 +303,7 @@
 	CHECK_OBJ_NOTNULL(sp->wrk, WORKER_MAGIC);
 	CHECK_OBJ_NOTNULL(sp->obj, OBJECT_MAGIC);
 
-	sp->obj->entered = time(NULL);
+	sp->obj->entered = TIM_real();
 
 	assert(sp->obj->busy != 0);
 

Modified: branches/1.1/bin/varnishd/cache_hash.c
===================================================================
--- branches/1.1/bin/varnishd/cache_hash.c	2007-07-13 14:53:48 UTC (rev 1692)
+++ branches/1.1/bin/varnishd/cache_hash.c	2007-07-13 14:54:51 UTC (rev 1693)
@@ -152,7 +152,7 @@
 			/* ignore */
 		} else if (o->ttl == 0) {
 			/* Object banned but not reaped yet */
-		} else if (o->ttl <= sp->t_req.tv_sec) {
+		} else if (o->ttl <= sp->t_req) {
 			/* Object expired */
 		} else if (BAN_CheckObject(o, h->hd[HTTP_HDR_URL].b)) {
 			o->ttl = 0;
@@ -166,7 +166,7 @@
 	if (o != NULL) {
 		UNLOCK(&oh->mtx);
 		(void)hash->deref(oh);
-		LRU_Enter(o, sp->t_req.tv_sec);
+		LRU_Enter(o, sp->t_req);
 		return (o);
 	}
 
@@ -178,7 +178,7 @@
 	/* NB: do not deref objhead the new object inherits our reference */
 	UNLOCK(&oh->mtx);
 	BAN_NewObj(o);
-	LRU_Enter(o, sp->t_req.tv_sec);
+	LRU_Enter(o, sp->t_req);
 	return (o);
 }
 

Modified: branches/1.1/bin/varnishd/cache_http.c
===================================================================
--- branches/1.1/bin/varnishd/cache_http.c	2007-07-13 14:53:48 UTC (rev 1692)
+++ branches/1.1/bin/varnishd/cache_http.c	2007-07-13 14:54:51 UTC (rev 1693)
@@ -58,7 +58,6 @@
 	HTTP_T_URL,
 	HTTP_T_Protocol,
 	HTTP_T_Header,
-	HTTP_T_LostHeader,
 };
 
 #define LOGMTX2(ax, bx) 	\
@@ -71,7 +70,6 @@
 	LOGMTX2(ax, URL),	\
 	LOGMTX2(ax, Protocol),	\
 	LOGMTX2(ax, Header),	\
-	LOGMTX2(ax, LostHeader)	\
 	}
 
 static enum shmlogtag logmtx[3][7] = {
@@ -86,7 +84,7 @@
 
 	CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
 	assert(/* hp->logtag >= HTTP_Rx && */hp->logtag <= HTTP_Obj);
-	assert(/* t >= HTTP_T_Request && */t <= HTTP_T_LostHeader);
+	assert(/* t >= HTTP_T_Request && */t <= HTTP_T_Header);
 	return (logmtx[hp->logtag][t]);
 }
 
@@ -97,12 +95,6 @@
 	WSLR(w, http2shmlog(hp, t), fd, hp->hd[hdr].b, hp->hd[hdr].e);
 }
 
-void
-http_LogLostHeader(struct worker *w, int fd, struct http *hp, const char *hdr)
-{
-	WSLR(w, http2shmlog(hp, HTTP_T_LostHeader), fd, hdr + 1, hdr + hdr[0]);
-}
-
 /*--------------------------------------------------------------------*/
 /* List of canonical HTTP response code names from RFC2616 */
 
@@ -430,7 +422,7 @@
 			hp->nhd++;
 		} else {
 			VSL_stats->losthdr++;
-			WSLR(w, http2shmlog(hp, HTTP_T_LostHeader), fd, p, q);
+			WSLR(w, SLT_LostHeader, fd, p, q);
 		}
 	}
 	return (0);
@@ -686,8 +678,8 @@
 
 /*--------------------------------------------------------------------*/
 
-static void
-http_seth(struct http *to, unsigned n, const char *fm)
+void
+http_SetH(struct http *to, unsigned n, const char *fm)
 {
 
 	assert(n < HTTP_HDR_MAX);
@@ -709,14 +701,17 @@
 }
 
 static void
-http_getreq(struct http *to, struct http *fm)
+http_copyreq(struct http *to, struct http *fm, int forceget)
 {
 
 	CHECK_OBJ_NOTNULL(fm, HTTP_MAGIC);
 	CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
-	http_seth(to, HTTP_HDR_REQ, "GET");
+	if (forceget)
+		http_SetH(to, HTTP_HDR_REQ, "GET");
+	else
+		http_copyh(to, fm, HTTP_HDR_REQ);
 	http_copyh(to, fm, HTTP_HDR_URL);
-	http_seth(to, HTTP_HDR_PROTO, "HTTP/1.1");
+	http_SetH(to, HTTP_HDR_PROTO, "HTTP/1.1");
 }
 
 void
@@ -726,7 +721,7 @@
 	CHECK_OBJ_NOTNULL(fm, HTTP_MAGIC);
 	CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
 	if (params->client_http11)
-		http_seth(to, HTTP_HDR_PROTO, "HTTP/1.1");
+		http_SetH(to, HTTP_HDR_PROTO, "HTTP/1.1");
 	else
 		http_copyh(to, fm, HTTP_HDR_PROTO);
 	http_copyh(to, fm, HTTP_HDR_STATUS);
@@ -738,9 +733,9 @@
 {
 
 	CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
-	http_seth(to, HTTP_HDR_PROTO, proto);
-	http_seth(to, HTTP_HDR_STATUS, status);
-	http_seth(to, HTTP_HDR_RESPONSE, response);
+	http_SetH(to, HTTP_HDR_PROTO, proto);
+	http_SetH(to, HTTP_HDR_STATUS, status);
+	http_SetH(to, HTTP_HDR_RESPONSE, response);
 }
 
 static void
@@ -757,7 +752,7 @@
 		to->nhd++;
 	} else  {
 		VSL_stats->losthdr++;
-		WSLH(w, HTTP_T_LostHeader, fd, fm, n);
+		WSLH(w, SLT_LostHeader, fd, fm, n);
 	}
 }
 
@@ -797,7 +792,7 @@
         hp = bereq->http;
         hp->logtag = HTTP_Tx;
 
-	http_getreq(hp, sp->http);
+	http_copyreq(hp, sp->http, how != HTTPH_R_PIPE);
 	http_FilterFields(sp->wrk, sp->fd, hp, sp->http, how);
 	http_PrintfHeader(sp->wrk, sp->fd, hp, "X-Varnish: %u", sp->xid);
 	http_PrintfHeader(sp->wrk, sp->fd, hp,
@@ -850,7 +845,7 @@
 			hp->hd[u].b = p;
 			hp->hd[u].e = p + l;
 		} else {
-			WSLH(w, HTTP_T_LostHeader, fd, hp, u);
+			WSLH(w, SLT_LostHeader, fd, hp, u);
 			hp->hd[u].b = NULL;
 			hp->hd[u].e = NULL;
 		}
@@ -864,7 +859,7 @@
 {
 
 	CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
-	/* XXX ??? to->f = to->v;  Not sure this is valid */
+	/* XXX: don't to->f = to->v;  it would kill pipelining */
 	to->nhd = HTTP_HDR_FIRST;
 	memset(to->hd, 0, sizeof to->hd);
 }
@@ -878,10 +873,10 @@
 	CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
 	if (to->nhd >= HTTP_HDR_MAX) {
 		VSL_stats->losthdr++;
-		WSL(w, http2shmlog(to, HTTP_T_LostHeader), fd, "%s", hdr);
+		WSL(w, SLT_LostHeader, fd, "%s", hdr);
 		return;
 	}
-	http_seth(to, to->nhd++, hdr);
+	http_SetH(to, to->nhd++, hdr);
 }
 
 /*--------------------------------------------------------------------*/
@@ -898,7 +893,7 @@
 	l = (e - string);
 	p = WS_Alloc(to->ws, l + 1);
 	if (p == NULL) {
-		WSL(w, http2shmlog(to, HTTP_T_LostHeader), fd, "%s", string);
+		WSL(w, SLT_LostHeader, fd, "%s", string);
 		to->hd[field].b = NULL;
 		to->hd[field].e = NULL;
 	} else {
@@ -945,7 +940,7 @@
 	va_end(ap);
 	if (n + 1 >= l || to->nhd >= HTTP_HDR_MAX) {
 		VSL_stats->losthdr++;
-		WSL(w, http2shmlog(to, HTTP_T_LostHeader), fd, "%s", to->ws->f);
+		WSL(w, SLT_LostHeader, fd, "%s", to->ws->f);
 		WS_Release(to->ws, 0);
 	} else {
 		to->hd[to->nhd].b = to->ws->f;

Modified: branches/1.1/bin/varnishd/cache_lru.c
===================================================================
--- branches/1.1/bin/varnishd/cache_lru.c	2007-07-13 14:53:48 UTC (rev 1692)
+++ branches/1.1/bin/varnishd/cache_lru.c	2007-07-13 14:54:51 UTC (rev 1693)
@@ -71,7 +71,7 @@
  * if it's already in it and hasn't moved in a while.
  */
 void
-LRU_Enter(struct object *o, time_t stamp)
+LRU_Enter(struct object *o, double stamp)
 {
 
 	CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
@@ -199,7 +199,7 @@
  * number of objects that were discarded.
  */
 int
-LRU_DiscardTime(time_t cutoff)
+LRU_DiscardTime(double cutoff)
 {
 	struct object *first = TAILQ_FIRST(&lru_list);
 	struct object *o;

Modified: branches/1.1/bin/varnishd/cache_main.c
===================================================================
--- branches/1.1/bin/varnishd/cache_main.c	2007-07-13 14:53:48 UTC (rev 1692)
+++ branches/1.1/bin/varnishd/cache_main.c	2007-07-13 14:54:51 UTC (rev 1693)
@@ -71,7 +71,7 @@
 		stevedore->open(stevedore);
 
 	printf("Ready\n");
-	VSL_stats->start_time = time(NULL);
+	VSL_stats->start_time = TIM_real();
 
 	CLI_Init();
 

Modified: branches/1.1/bin/varnishd/cache_pipe.c
===================================================================
--- branches/1.1/bin/varnishd/cache_pipe.c	2007-07-13 14:53:48 UTC (rev 1692)
+++ branches/1.1/bin/varnishd/cache_pipe.c	2007-07-13 14:54:51 UTC (rev 1693)
@@ -38,10 +38,6 @@
 #include <stdlib.h>
 #include <sys/socket.h>
 
-#ifndef HAVE_CLOCK_GETTIME
-#include "compat/clock_gettime.h"
-#endif
-
 #include "shmlog.h"
 #include "heritage.h"
 #include "cache.h"
@@ -106,7 +102,7 @@
 	vbe_free_bereq(bereq);
 	bereq = NULL;
 
-	clock_gettime(CLOCK_REALTIME, &sp->t_resp);
+	sp->t_resp = TIM_real();
 
 	memset(fds, 0, sizeof fds);
 	fds[0].fd = vc->fd;

Modified: branches/1.1/bin/varnishd/cache_pool.c
===================================================================
--- branches/1.1/bin/varnishd/cache_pool.c	2007-07-13 14:53:48 UTC (rev 1692)
+++ branches/1.1/bin/varnishd/cache_pool.c	2007-07-13 14:54:51 UTC (rev 1693)
@@ -46,6 +46,7 @@
 
 #include <errno.h>
 #include <stdio.h>
+#include <math.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
@@ -181,6 +182,7 @@
 	struct workreq *wrq;
 
 	AN(w->wrq);
+	w->used = NAN;
 	wrq = w->wrq;
 	CHECK_OBJ_NOTNULL(wrq->sess, SESS_MAGIC);
 	wrq->sess->wrk = w;
@@ -193,6 +195,7 @@
 		CHECK_OBJ(w->nobj, OBJECT_MAGIC);
 	if (w->nobjhead != NULL)
 		CHECK_OBJ(w->nobjhead, OBJHEAD_MAGIC);
+	assert(!isnan(w->used));
 	w->wrq = NULL;
 }
 
@@ -207,7 +210,7 @@
 	w = &ww;
 	memset(w, 0, sizeof *w);
 	w->magic = WORKER_MAGIC;
-	w->idle = time(NULL);
+	w->used = TIM_real();
 	w->wlp = w->wlog;
 	w->wle = w->wlog + sizeof w->wlog;
 	AZ(pipe(w->pipe));
@@ -236,10 +239,10 @@
 
 		LOCK(&qp->mtx);
 		TAILQ_INSERT_HEAD(&qp->idle, w, list);
-		assert(w->idle != 0);
+		assert(!isnan(w->used));
 		UNLOCK(&qp->mtx);
 		assert(1 == read(w->pipe[0], &c, 1));
-		if (w->idle == 0)
+		if (w->wrq == NULL)
 			break;
 		wrk_do_one(w);
 	}
@@ -381,7 +384,7 @@
 static void *
 wrk_reaperthread(void *priv)
 {
-	time_t	now;
+	double	now;
 	struct worker *w;
 	struct wq *qp;
 	unsigned u;
@@ -392,13 +395,13 @@
 		sleep(1);
 		if (VSL_stats->n_wrk <= params->wthread_min)
 			continue;
-		now = time(NULL);
+		now = TIM_real();
 		for (u = 0; u < nwq; u++) {
 			qp = wq[u];
 			LOCK(&qp->mtx);
 			w = TAILQ_LAST(&qp->idle, workerhead);
 			if (w != NULL &&
-			   (w->idle + params->wthread_timeout < now ||
+			   (w->used + params->wthread_timeout < now ||
 			    VSL_stats->n_wrk > params->wthread_max))
 				TAILQ_REMOVE(&qp->idle, w, list);
 			else
@@ -406,7 +409,7 @@
 			UNLOCK(&qp->mtx);
 			if (w == NULL)
 				continue;
-			w->idle = 0;
+			AZ(w->wrq);
 			assert(1 == write(w->pipe[1], w, 1));
 		}
 	}

Modified: branches/1.1/bin/varnishd/cache_response.c
===================================================================
--- branches/1.1/bin/varnishd/cache_response.c	2007-07-13 14:53:48 UTC (rev 1692)
+++ branches/1.1/bin/varnishd/cache_response.c	2007-07-13 14:54:51 UTC (rev 1693)
@@ -32,10 +32,6 @@
 #include <sys/types.h>
 #include <sys/time.h>
 
-#ifndef HAVE_CLOCK_GETTIME
-#include "compat/clock_gettime.h"
-#endif
-
 #include "shmlog.h"
 #include "heritage.h"
 #include "cache.h"
@@ -75,7 +71,7 @@
 	sp->http->logtag = HTTP_Tx;
 	http_SetResp(sp->http,
 	    "HTTP/1.1", "304", "Not Modified");
-	TIM_format(sp->t_req.tv_sec, lm);
+	TIM_format(sp->t_req, lm);
 	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);
@@ -95,12 +91,12 @@
 res_do_conds(struct sess *sp)
 {
 	char *p;
-	time_t ims;
+	double ims;
 
 	if (sp->obj->last_modified > 0 &&
 	    http_GetHdr(sp->http, H_If_Modified_Since, &p)) {
 		ims = TIM_parse(p);
-		if (ims > sp->t_req.tv_sec)	/* [RFC2616 14.25] */
+		if (ims > sp->t_req)	/* [RFC2616 14.25] */
 			return (0);
 		if (sp->obj->last_modified > ims) {
 			return (0);
@@ -134,8 +130,8 @@
 	else
 		http_PrintfHeader(sp->wrk, sp->fd, sp->http,
 		    "X-Varnish: %u", sp->xid);
-	http_PrintfHeader(sp->wrk, sp->fd, sp->http, "Age: %u",
-	    sp->obj->age + sp->t_resp.tv_sec - sp->obj->entered);
+	http_PrintfHeader(sp->wrk, sp->fd, sp->http, "Age: %.0f",
+	    sp->obj->age + sp->t_resp - sp->obj->entered);
 	http_SetHeader(sp->wrk, sp->fd, sp->http, "Via: 1.1 varnish");
 	if (sp->doclose != NULL)
 		http_SetHeader(sp->wrk, sp->fd, sp->http, "Connection: close");
@@ -151,7 +147,6 @@
 
 	CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
 
-	clock_gettime(CLOCK_REALTIME, &sp->t_resp);
 	WRK_Reset(sp->wrk, &sp->fd);
 	sp->wrk->acct.hdrbytes += http_Write(sp->wrk, sp->http, 1);
 	CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);

Modified: branches/1.1/bin/varnishd/cache_session.c
===================================================================
--- branches/1.1/bin/varnishd/cache_session.c	2007-07-13 14:53:48 UTC (rev 1692)
+++ branches/1.1/bin/varnishd/cache_session.c	2007-07-13 14:54:51 UTC (rev 1693)
@@ -50,6 +50,7 @@
 
 #include <stdlib.h>
 #include <string.h>
+#include <math.h>
 #include <sys/uio.h>
 #include <sys/socket.h>
 
@@ -91,7 +92,8 @@
 	char			addr[TCP_ADDRBUFSIZE];
 	unsigned		nref;
 
-	time_t			ttl;
+	/* How long to keep entry around.  Inherits timescale from t_open */
+	double			ttl;
 
 	struct acct		acct;
 };
@@ -120,7 +122,7 @@
 	unsigned u, v;
 	struct srcaddr *c, *c2, *c3;
 	struct srcaddrhead *ch;
-	time_t now;
+	double now;
 
 	if (params->srcaddr_ttl == 0) {
 		sp->srcaddr = NULL;
@@ -131,7 +133,7 @@
 	v = u % nsrchash;
 	ch = &srchash[v];
 	CHECK_OBJ(ch, SRCADDRHEAD_MAGIC);
-	now = sp->t_open.tv_sec;
+	now = sp->t_open;
 	if (sp->wrk->srcaddr == NULL) {
 		sp->wrk->srcaddr = calloc(sizeof *sp->wrk->srcaddr, 1);
 		XXXAN(sp->wrk->srcaddr);
@@ -227,14 +229,15 @@
 
 	ses_sum_acct(&sp->acct, a);
 	if (sp->srcaddr != NULL) {
+		/* XXX: only report once per second ? */
 		CHECK_OBJ(sp->srcaddr, SRCADDR_MAGIC);
 		LOCK(&sp->srcaddr->sah->mtx);
 		ses_sum_acct(&sp->srcaddr->acct, a);
 		b = sp->srcaddr->acct;
 		UNLOCK(&sp->srcaddr->sah->mtx);
 		WSL(sp->wrk, SLT_StatAddr, 0,
-		    "%s 0 %d %ju %ju %ju %ju %ju %ju %ju",
-		    sp->srcaddr->addr, sp->t_end.tv_sec - b.first,
+		    "%s 0 %.0f %ju %ju %ju %ju %ju %ju %ju",
+		    sp->srcaddr->addr, sp->t_end - b.first,
 		    b.sess, b.req, b.pipe, b.pass,
 		    b.fetch, b.hdrbytes, b.bodybytes);
 	}
@@ -307,6 +310,10 @@
 	sp->mysockaddr = (void*)(&sm->sockaddr[1]);
 	sp->mysockaddrlen = sizeof(sm->sockaddr[1]);
 	sp->sockaddr->sa_family = sp->mysockaddr->sa_family = PF_UNSPEC;
+	sp->t_open = NAN;
+	sp->t_req = NAN;
+	sp->t_resp = NAN;
+	sp->t_end = NAN;
 
 	assert(len <= sp->sockaddrlen);
 	if (addr != NULL) {
@@ -333,8 +340,8 @@
 	AZ(sp->vcl);
 	VSL_stats->n_sess--;
 	ses_relsrcaddr(sp);
-	VSL(SLT_StatSess, sp->id, "%s %s %d %ju %ju %ju %ju %ju %ju %ju",
-	    sp->addr, sp->port, sp->t_end.tv_sec - b->first,
+	VSL(SLT_StatSess, sp->id, "%s %s %.0f %ju %ju %ju %ju %ju %ju %ju",
+	    sp->addr, sp->port, sp->t_end - b->first,
 	    b->sess, b->req, b->pipe, b->pass,
 	    b->fetch, b->hdrbytes, b->bodybytes);
 	if (sm->workspace != params->mem_workspace) {

Modified: branches/1.1/bin/varnishd/cache_synthetic.c
===================================================================
--- branches/1.1/bin/varnishd/cache_synthetic.c	2007-07-13 14:53:48 UTC (rev 1692)
+++ branches/1.1/bin/varnishd/cache_synthetic.c	2007-07-13 14:54:51 UTC (rev 1693)
@@ -33,10 +33,6 @@
 
 #include <stdlib.h>
 
-#ifndef HAVE_CLOCK_GETTIME
-#include "compat/clock_gettime.h"
-#endif
-
 #include "shmlog.h"
 #include "heritage.h"
 #include "cache.h"
@@ -56,7 +52,7 @@
 	struct vsb vsb;
 	const char *msg;
 	char date[40];
-	time_t now;
+	double now;
 	int fd;
 
 	assert(status >= 100 && status <= 999);
@@ -71,7 +67,7 @@
 	fd = sp->fd;
 	o = sp->obj;
 	h = &o->http;
-	time(&now);
+	now = TIM_real();
 
 	/* look up HTTP response */
 	msg = http_StatusMessage(status);

Modified: branches/1.1/bin/varnishd/cache_vrt.c
===================================================================
--- branches/1.1/bin/varnishd/cache_vrt.c	2007-07-13 14:53:48 UTC (rev 1692)
+++ branches/1.1/bin/varnishd/cache_vrt.c	2007-07-13 14:54:51 UTC (rev 1693)
@@ -32,7 +32,10 @@
  */
 
 #include <sys/types.h>
+#include <sys/socket.h>
 
+#include <netinet/in.h>
+
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
@@ -112,45 +115,60 @@
 
 /*--------------------------------------------------------------------*/
 
+static char *
+vrt_assemble_string(struct http *hp, const char *h, const char *p, va_list ap)
+{
+	char *b, *e;
+	unsigned u, x;
+
+	u = WS_Reserve(hp->ws, 0);
+	e = b = hp->ws->f;
+	*e = '\0';
+	if (h != NULL) {
+		x = strlen(h);
+		if (x + 2 < u) {
+			memcpy(e, h, x);
+			e[x] = ' ';
+			e[x + 1] = '\0';
+		}
+		e += x + 1;
+	}
+	while (p != NULL) {
+		x = strlen(p);
+		if (x + 1 < u)
+			memcpy(e, p, x);
+		e += x;
+		p = va_arg(ap, const char *);
+	}
+	*e = '\0';
+	if (e > b + u) {
+		WS_Release(hp->ws, 0);
+		return (NULL);
+	} else {
+		WS_Release(hp->ws, 1 + e - b);
+		return (b);
+	}
+}
+
+/*--------------------------------------------------------------------*/
+
 void
-VRT_SetHdr(struct sess *sp , enum gethdr_e where, const char *hdr, ...)
+VRT_SetHdr(struct sess *sp , enum gethdr_e where, const char *hdr, const char *p, ...)
 {
 	struct http *hp;
 	va_list ap;
-	const char *p;
-	char *b, *e;
-	unsigned u, x;
+	char *b;
 
 	CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
 	hp = vrt_selecthttp(sp, where);
-	va_start(ap, hdr);
-	p = va_arg(ap, const char *);
+	va_start(ap, p);
 	if (p == NULL) {
 		http_Unset(hp, hdr);
 	} else {
-		u = WS_Reserve(hp->ws, 0);
-		e = b = hp->ws->f;
-		*e = '\0';
-		x = strlen(hdr + 1);
-		if (x + 1 < u)
-			memcpy(e, hdr + 1, x);
-		e += x;
-		if (1 + 1 < u)
-			*e++ = ' ';
-		while (p != NULL) {
-			x = strlen(p);
-			if (x + 1 < u)
-				memcpy(e, p, x);
-			e += x;
-			p = va_arg(ap, const char *);
-		}
-		*e = '\0';
-		if (e > b + u) {
-			http_LogLostHeader(sp->wrk, sp->fd, hp, hdr);
-			WS_Release(hp->ws, 0);
-			
+		b = vrt_assemble_string(hp, hdr + 1, p, ap);
+		if (b == NULL) {
+			VSL(SLT_LostHeader, sp->fd, hdr + 1);
 		} else {
-			WS_Release(hp->ws, 1 + e - b);
 			http_Unset(hp, hdr);
 			http_SetHeader(sp->wrk, sp->fd, hp, b);
 		}
@@ -160,7 +178,77 @@
 
 /*--------------------------------------------------------------------*/
 
+static void
+vrt_do_string(struct worker *w, int fd, struct http *hp, int fld, const char *err, const char *p, va_list ap)
+{
+	char *b;
+
+	AN(p);
+	AN(hp);
+	b = vrt_assemble_string(hp, NULL, p, ap);
+	if (b == NULL) {
+		WSL(w, SLT_LostHeader, fd, err);
+	} else {
+		http_SetH(hp, fld, b);
+	}
+	va_end(ap);
+}
+
+#define VRT_DO_HDR(obj, hdr, http, fld)				\
+void								\
+VRT_l_##obj##_##hdr(struct sess *sp, const char *p, ...)	\
+{								\
+	va_list ap;						\
+								\
+	AN(p);							\
+	va_start(ap, p);					\
+	vrt_do_string(sp->wrk, sp->fd,				\
+	    http, fld, #obj "." #hdr, p, ap);			\
+	va_end(ap);						\
+}
+
+VRT_DO_HDR(req,   request,	sp->http,		HTTP_HDR_REQ)
+VRT_DO_HDR(req,   url,		sp->http,		HTTP_HDR_URL)
+VRT_DO_HDR(req,   proto,	sp->http,		HTTP_HDR_PROTO)
+VRT_DO_HDR(bereq, request,	sp->bereq->http,	HTTP_HDR_REQ)
+VRT_DO_HDR(bereq, url,		sp->bereq->http,	HTTP_HDR_URL)
+VRT_DO_HDR(bereq, proto,	sp->bereq->http,	HTTP_HDR_PROTO)
+VRT_DO_HDR(obj,   proto,	&sp->obj->http,		HTTP_HDR_PROTO)
+VRT_DO_HDR(obj,   response,	&sp->obj->http,		HTTP_HDR_RESPONSE)
+VRT_DO_HDR(resp,  proto,	sp->http,		HTTP_HDR_PROTO)
+VRT_DO_HDR(resp,  response,	sp->http,		HTTP_HDR_RESPONSE)
+
 void
+VRT_l_obj_status(struct sess *sp, int num)
+{
+	char *p;
+
+	assert(num >= 100 && num <= 999);
+	p = WS_Alloc(sp->obj->http.ws, 4);
+	if (p == NULL)
+		WSL(sp->wrk, SLT_LostHeader, sp->fd, "obj.status");
+	else
+		sprintf(p, "%d", num);
+	http_SetH(&sp->obj->http, HTTP_HDR_STATUS, p);
+}
+
+void
+VRT_l_resp_status(struct sess *sp, int num)
+{
+	char *p;
+
+	assert(num >= 100 && num <= 999);
+	p = WS_Alloc(sp->http->ws, 4);
+	if (p == NULL)
+		WSL(sp->wrk, SLT_LostHeader, sp->fd, "resp.status");
+	else
+		sprintf(p, "%d", num);
+	http_SetH(sp->http, HTTP_HDR_STATUS, p);
+}
+
+/*--------------------------------------------------------------------*/
+
+void
 VRT_handling(struct sess *sp, unsigned hand)
 {
 
@@ -239,11 +327,11 @@
 
 	CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
 	CHECK_OBJ_NOTNULL(sp->obj, OBJECT_MAGIC);	/* XXX */
-	WSL(sp->wrk, SLT_TTL, sp->fd, "%u VCL %.0f %u",
-	    sp->obj->xid, a, sp->t_req.tv_sec);
+	WSL(sp->wrk, SLT_TTL, sp->fd, "%u VCL %.0f %.0f",
+	    sp->obj->xid, a, sp->t_req);
 	if (a < 0)
 		a = 0;
-	sp->obj->ttl = sp->t_req.tv_sec + (int)a;
+	sp->obj->ttl = sp->t_req + a;
 	if (sp->obj->heap_idx != 0)
 		EXP_TTLchange(sp->obj);
 }
@@ -253,7 +341,7 @@
 {
 	CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
 	CHECK_OBJ_NOTNULL(sp->obj, OBJECT_MAGIC);	/* XXX */
-	return (sp->obj->ttl - sp->t_req.tv_sec);
+	return (sp->obj->ttl - sp->t_req);
 }
 
 /*--------------------------------------------------------------------*/
@@ -375,22 +463,43 @@
 double
 VRT_r_now(struct sess *sp)
 {
-	struct timespec now;
 
 	(void)sp;
-	/* XXX use of clock_gettime() needs review */
-	clock_gettime(CLOCK_MONOTONIC, &now);
-	return (now.tv_sec);
+	return (TIM_mono());
 }
 
 double
 VRT_r_obj_lastuse(struct sess *sp)
 {
-	struct timespec now;
 
 	CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
 	CHECK_OBJ_NOTNULL(sp->obj, OBJECT_MAGIC);	/* XXX */
-	/* XXX use of clock_gettime() needs review */
-	clock_gettime(CLOCK_MONOTONIC, &now);
-	return (now.tv_sec - sp->obj->lru_stamp);
+	return (TIM_mono() - sp->obj->lru_stamp);
 }
+
+/*--------------------------------------------------------------------*/
+
+char *
+VRT_IP_string(struct sess *sp, struct sockaddr *sa)
+{
+	char h[64], p[8], *q;
+	socklen_t len = 0;
+
+	/* XXX can't rely on sockaddr.sa_len */
+	switch (sa->sa_family) {
+	case AF_INET:
+		len = sizeof(struct sockaddr_in);
+		break;
+	case AF_INET6:
+		len = sizeof(struct sockaddr_in6);
+		break;
+	}
+	XXXAN(len);
+	TCP_name(sa, len, h, sizeof h, p, sizeof p);
+	q = WS_Alloc(sp->http->ws, strlen(h) + strlen(p) + 2);
+	AN(q);
+	strcpy(q, h);
+	strcat(q, ":");
+	strcat(q, p);
+	return (q);
+}

Modified: branches/1.1/bin/varnishd/cache_vrt_re.c
===================================================================
--- branches/1.1/bin/varnishd/cache_vrt_re.c	2007-07-13 14:53:48 UTC (rev 1692)
+++ branches/1.1/bin/varnishd/cache_vrt_re.c	2007-07-13 14:54:51 UTC (rev 1693)
@@ -35,6 +35,7 @@
 
 #include <stdio.h>
 #include <string.h>
+#include <ctype.h>
 #include <stdlib.h>
 #include <regex.h>
 
@@ -45,14 +46,14 @@
 #include "cache.h"
 
 void
-VRT_re_init(void **rep, const char *re)
+VRT_re_init(void **rep, const char *re, int sub)
 {
 	regex_t	*t;
 
 	t = calloc(sizeof *t, 1);
 	XXXAN(t);
 	/* This was already check-compiled by the VCL compiler */
-	AZ(regcomp(t, re, REG_EXTENDED | REG_NOSUB));
+	AZ(regcomp(t, re, REG_EXTENDED | (sub ? 0 : REG_NOSUB)));
 	*rep = t;
 }
 
@@ -82,14 +83,14 @@
 }
 
 int
-VRT_re_test(struct vsb *sb, const char *re)
+VRT_re_test(struct vsb *sb, const char *re, int sub)
 {
 	int i;
 	regex_t	t;
 	char buf[BUFSIZ];
 
 	memset(&t, 0, sizeof t);
-	i = regcomp(&t, re, REG_EXTENDED | REG_NOSUB);
+	i = regcomp(&t, re, REG_EXTENDED | (sub ? 0 : REG_NOSUB));
 	if (i == 0) {
 		regfree(&t);
 		return (0);
@@ -99,3 +100,73 @@
 	regfree(&t);
 	return (1);
 }
+
+const char *
+VRT_regsub(struct sess *sp, const char *str, void *re, const char *sub)
+{
+	regmatch_t pm[10];
+	regex_t *t;
+	int i, l;
+	char *b, *p, *e;
+	unsigned u, x;
+
+	AN(re);
+	t = re;
+	i = regexec(t, str, 10, pm, 0);
+
+	/* If it didn't match, we can return the original string */
+	if (i == REG_NOMATCH)
+		return(str);
+
+	u = WS_Reserve(sp->http->ws, 0);
+	e = p = b = sp->http->ws->f;
+	e += u;
+
+	/* Copy prefix to match */
+	if (pm[0].rm_so > 0) {
+		if (p + pm[0].rm_so < e)
+			memcpy(p, str, pm[0].rm_so);
+		p += pm[0].rm_so;
+	}
+
+	for ( ; *sub != '\0'; sub++ ) {
+		if (*sub == '&') {
+			l = pm[0].rm_eo - pm[0].rm_so;
+			if (l > 0) {
+				if (p + l < e)
+					memcpy(p, str + pm[0].rm_so, l);
+				p += l;
+			}
+		} else if (*sub == '$' && isdigit(sub[1])) {
+			x = sub[1] - '0';
+			sub++;
+			l = pm[x].rm_eo - pm[x].rm_so;
+			if (l > 0) {
+				if (p + l < e)
+					memcpy(p, str + pm[x].rm_so, l);
+				p += l;
+			}
+		} else {
+			if (p + 1 < e)
+				*p = *sub;
+			p++;
+		}
+	}
+
+	/* Copy suffix to match */
+	l = strlen(str + pm[0].rm_eo);
+	if (l > 0) {
+		if (p + l < e)
+			memcpy(p, str + pm[0].rm_eo, l);
+		p += l;
+	}
+	if (p + 1 < e)
+		*p++ = '\0';
+	xxxassert(p <= e);
+	if (p > e) {
+		WS_Release(sp->http->ws, 0);
+		return (str);
+	} 
+	WS_Release(sp->http->ws, p - b);
+	return (b);
+}

Modified: branches/1.1/bin/varnishd/mgt_child.c
===================================================================
--- branches/1.1/bin/varnishd/mgt_child.c	2007-07-13 14:53:48 UTC (rev 1692)
+++ branches/1.1/bin/varnishd/mgt_child.c	2007-07-13 14:54:51 UTC (rev 1693)
@@ -445,3 +445,13 @@
 		cli_out(cli, "Child in state %s", ch_state[child_state]);
 	}
 }
+
+/*--------------------------------------------------------------------*/
+
+void
+mcf_server_status(struct cli *cli, char **av, void *priv)
+{
+	(void)av;
+	(void)priv;
+	cli_out(cli, "Child in state %s", ch_state[child_state]);
+}

Modified: branches/1.1/bin/varnishd/mgt_cli.c
===================================================================
--- branches/1.1/bin/varnishd/mgt_cli.c	2007-07-13 14:53:48 UTC (rev 1692)
+++ branches/1.1/bin/varnishd/mgt_cli.c	2007-07-13 14:54:51 UTC (rev 1693)
@@ -140,6 +140,7 @@
 /* XXX: what order should this list be in ? */
 static struct cli_proto mgt_cli_proto[] = {
 	{ CLI_PING,		cli_func_ping },
+	{ CLI_SERVER_STATUS,	mcf_server_status, NULL },
 	{ CLI_SERVER_START,	mcf_server_startstop, NULL },
 	{ CLI_SERVER_STOP,	mcf_server_startstop, &cli_proto },
 	{ CLI_STATS,		mcf_stats, NULL },

Modified: branches/1.1/bin/varnishd/mgt_cli.h
===================================================================
--- branches/1.1/bin/varnishd/mgt_cli.h	2007-07-13 14:53:48 UTC (rev 1692)
+++ branches/1.1/bin/varnishd/mgt_cli.h	2007-07-13 14:54:51 UTC (rev 1693)
@@ -31,6 +31,7 @@
 
 /* mgt_child.c */
 cli_func_t mcf_server_startstop;
+cli_func_t mcf_server_status;
 
 /* mgt_param.c */
 cli_func_t mcf_param_show;

Modified: branches/1.1/bin/varnishd/mgt_event.c
===================================================================
--- branches/1.1/bin/varnishd/mgt_event.c	2007-07-13 14:53:48 UTC (rev 1692)
+++ branches/1.1/bin/varnishd/mgt_event.c	2007-07-13 14:54:51 UTC (rev 1693)
@@ -37,10 +37,6 @@
 #include <string.h>
 #include <stdlib.h>
 
-#ifndef HAVE_CLOCK_GETTIME
-#include "compat/clock_gettime.h"
-#endif
-
 #include "mgt.h"
 #include "mgt_event.h"
 #include "miniobj.h"
@@ -76,19 +72,6 @@
 
 /*--------------------------------------------------------------------*/
 
-static double
-ev_now(void)
-{
-	double t;
-	struct timespec ts;
-
-	assert(clock_gettime(CLOCK_MONOTONIC, &ts) == 0);
-	t = ts.tv_sec + ts.tv_nsec * 1e-9;
-	return (t);
-}
-
-/*--------------------------------------------------------------------*/
-
 static void
 ev_bh_update(void *priv, void *a, unsigned u)
 {
@@ -265,7 +248,7 @@
 	e->magic = EV_MAGIC;	/* before binheap_insert() */
 
 	if (e->timeout != 0.0) {
-		e->__when += ev_now() + e->timeout;
+		e->__when += TIM_mono() + e->timeout;
 		binheap_insert(evb->binheap, e);
 		assert(e->__binheap_idx > 0);
 	} else {
@@ -430,7 +413,7 @@
 	if (e != NULL) {
 		CHECK_OBJ_NOTNULL(e, EV_MAGIC);
 		assert(e->__binheap_idx == 1);
-		t = ev_now();
+		t = TIM_mono();
 		if (e->__when <= t)
 			return (ev_sched_timeout(evb, e, t));
 		tmo = (int)((e->__when - t) * 1e3);
@@ -453,7 +436,7 @@
 		return (ev_sched_signal(evb));
 	if (i == 0) {
 		assert(e != NULL);
-		t = ev_now();
+		t = TIM_mono();
 		if (e->__when <= t)
 			return (ev_sched_timeout(evb, e, t));
 	}

Modified: branches/1.1/bin/varnishd/rfc2616.c
===================================================================
--- branches/1.1/bin/varnishd/rfc2616.c	2007-07-13 14:53:48 UTC (rev 1692)
+++ branches/1.1/bin/varnishd/rfc2616.c	2007-07-13 14:54:51 UTC (rev 1693)
@@ -98,12 +98,12 @@
 	ttd = min(ttd, our_clock + hard_upper_ttl)
 #endif
 
-static time_t
+static double
 RFC2616_Ttl(struct sess *sp, struct http *hp, struct object *obj)
 {
 	int retirement_age;
 	unsigned u1, u2;
-	time_t h_date, h_expires, ttd;
+	double h_date, h_expires, ttd;
 	char *p;
 
 	retirement_age = INT_MAX;
@@ -121,6 +121,14 @@
 			retirement_age = u1 - u2;
 	}
 
+	/*
+	 * XXX: if the backends time is too skewed relative to our own
+	 * XXX: we should blacklist the backend, to avoid getting totally
+	 * XXX: bogus results further down.  Exactly what "too skewed" means
+	 * XXX: in this context is a good question.  It could be determined
+	 * XXX: out according to the backends headers, but a simple fixed
+	 * XXX: tolerance of a minute either way would be more predictable.
+	 */
 	h_date = 0;
 	if (http_GetHdr(hp, H_Date, &p))
 		h_date = TIM_parse(p);

Modified: branches/1.1/bin/varnishd/shmlog.c
===================================================================
--- branches/1.1/bin/varnishd/shmlog.c	2007-07-13 14:53:48 UTC (rev 1692)
+++ branches/1.1/bin/varnishd/shmlog.c	2007-07-13 14:54:51 UTC (rev 1693)
@@ -289,7 +289,7 @@
 	/* XXX more check sanity of loghead  ? */
 	logstart = (unsigned char *)loghead + loghead->start;
 	MTX_INIT(&vsl_mtx);
-	loghead->starttime = time(NULL);
+	loghead->starttime = TIM_real();
 	memset(VSL_stats, 0, sizeof *VSL_stats);
 }
 

Modified: branches/1.1/bin/varnishd/varnishd.1
===================================================================
--- branches/1.1/bin/varnishd/varnishd.1	2007-07-13 14:53:48 UTC (rev 1692)
+++ branches/1.1/bin/varnishd/varnishd.1	2007-07-13 14:54:51 UTC (rev 1693)
@@ -316,6 +316,8 @@
 better idea of the current situation, use the
 .Xr varnishstat 1
 utility.
+.It Cm status
+Check the status of the child process.
 .It Cm stop
 Stop the child process.
 .It Cm url.purge Ar regexp

Modified: branches/1.1/doc/changes-1.0.4-1.1.xml
===================================================================
--- branches/1.1/doc/changes-1.0.4-1.1.xml	2007-07-13 14:53:48 UTC (rev 1692)
+++ branches/1.1/doc/changes-1.0.4-1.1.xml	2007-07-13 14:54:51 UTC (rev 1693)
@@ -155,6 +155,29 @@
       corresponding variable, and strip an HTTP header by using the
       <command>remove</command> keyword.</para>
     </change>
+
+    <change type="enh" ref="1661,1662">
+      <para>VCL scripts can now modify the HTTP status code of cached
+      objects (<varname>obj.status</varname>) and responses
+      (<varname>resp.status</varname>)</para>
+    </change>
+
+    <change type="enh" ref="1663">
+      <para>Numeric and other non-textual variables in VCL can now be
+      assigned to textual variables; they will be converted as
+      needed.</para>
+    </change>
+
+    <change type="enh" ref="1666,1667">
+      <para>VCL scripts can now apply regular expression substitutions
+      to textual variables using the <function>regsub</function>
+      function.</para>
+    </change>
+
+    <change type="enh" ref="1674,1675">
+      <para>A new management command, <command>status</command>,
+      returns the state of the child.</para>
+    </change>
   </subsystem>
 
   <subsystem>
@@ -189,6 +212,12 @@
       <command>varnishncsa</command> can now also process log data
       from backend traffic.</para>
     </change>
+
+    <change type="bug" ref="1531">
+      <para>A bug that would cause <command>varnishncsa</command> to
+      segfault when it encountered an empty HTTP header in the log
+      file has been fixed.</para>
+    </change>
   </subsystem>
 
   <subsystem>

Modified: branches/1.1/include/cli.h
===================================================================
--- branches/1.1/include/cli.h	2007-07-13 14:53:48 UTC (rev 1692)
+++ branches/1.1/include/cli.h	2007-07-13 14:54:51 UTC (rev 1693)
@@ -211,6 +211,12 @@
 	"\tClose connection",						\
 	0, 0
 
+# define CLI_SERVER_STATUS						\
+	"status",							\
+	"status",							\
+	"\tCheck status of Varnish cache process.",			\
+	0, 0
+
 /*
  * Status/return codes in the CLI protocol
  */

Modified: branches/1.1/include/libvarnish.h
===================================================================
--- branches/1.1/include/libvarnish.h	2007-07-13 14:53:48 UTC (rev 1692)
+++ branches/1.1/include/libvarnish.h	2007-07-13 14:54:51 UTC (rev 1693)
@@ -47,6 +47,8 @@
 /* from libvarnish/time.c */
 void TIM_format(time_t t, char *p);
 time_t TIM_parse(const char *p);
+double TIM_mono(void);
+double TIM_real(void);
 
 /* from libvarnish/version.c */
 void varnish_version(const char *);

Modified: branches/1.1/include/shmlog_tags.h
===================================================================
--- branches/1.1/include/shmlog_tags.h	2007-07-13 14:53:48 UTC (rev 1692)
+++ branches/1.1/include/shmlog_tags.h	2007-07-13 14:54:51 UTC (rev 1693)
@@ -62,7 +62,6 @@
 SLTM(RxURL)
 SLTM(RxProtocol)
 SLTM(RxHeader)
-SLTM(RxLostHeader)
 
 SLTM(TxRequest)
 SLTM(TxResponse)
@@ -70,7 +69,6 @@
 SLTM(TxURL)
 SLTM(TxProtocol)
 SLTM(TxHeader)
-SLTM(TxLostHeader)
 
 SLTM(ObjRequest)
 SLTM(ObjResponse)
@@ -78,8 +76,9 @@
 SLTM(ObjURL)
 SLTM(ObjProtocol)
 SLTM(ObjHeader)
-SLTM(ObjLostHeader)
 
+SLTM(LostHeader)
+
 SLTM(TTL)
 SLTM(VCL_acl)
 SLTM(VCL_call)

Modified: branches/1.1/include/vrt.h
===================================================================
--- branches/1.1/include/vrt.h	2007-07-13 14:53:48 UTC (rev 1692)
+++ branches/1.1/include/vrt.h	2007-07-13 14:54:51 UTC (rev 1693)
@@ -64,10 +64,11 @@
 void VRT_acl_fini(struct vrt_acl *);
 
 /* Regexp related */
-void VRT_re_init(void **, const char *);
+void VRT_re_init(void **, const char *, int sub);
 void VRT_re_fini(void *);
 int VRT_re_match(const char *, void *re);
-int VRT_re_test(struct vsb *, const char *);
+int VRT_re_test(struct vsb *, const char *, int sub);
+const char *VRT_regsub(struct sess *sp, const char *, void *, const char *);
 
 void VRT_count(struct sess *, unsigned);
 int VRT_rewrite(const char *, const char *);
@@ -76,7 +77,7 @@
 
 enum gethdr_e { HDR_REQ, HDR_RESP, HDR_OBJ, HDR_BEREQ };
 char *VRT_GetHdr(struct sess *, enum gethdr_e where, const char *);
-void VRT_SetHdr(struct sess *, enum gethdr_e where, const char *, ...);
+void VRT_SetHdr(struct sess *, enum gethdr_e where, const char *, const char *, ...);
 void VRT_handling(struct sess *sp, unsigned hand);
 
 /* Backend related */
@@ -85,6 +86,7 @@
 void VRT_free_backends(struct VCL_conf *cp);
 void VRT_fini_backend(struct backend *be);
 
+char *VRT_IP_string(struct sess *sp, struct sockaddr *sa);
 
 #define VRT_done(sp, hand)			\
 	do {					\

Modified: branches/1.1/include/vrt_obj.h
===================================================================
--- branches/1.1/include/vrt_obj.h	2007-07-13 14:53:48 UTC (rev 1692)
+++ branches/1.1/include/vrt_obj.h	2007-07-13 14:54:51 UTC (rev 1693)
@@ -12,23 +12,26 @@
 struct sockaddr * VRT_r_client_ip(struct sess *);
 struct sockaddr * VRT_r_server_ip(struct sess *);
 const char * VRT_r_req_request(struct sess *);
+void VRT_l_req_request(struct sess *, const char *, ...);
 const char * VRT_r_req_url(struct sess *);
+void VRT_l_req_url(struct sess *, const char *, ...);
 const char * VRT_r_req_proto(struct sess *);
+void VRT_l_req_proto(struct sess *, const char *, ...);
 void VRT_l_req_hash(struct sess *, const char *);
 struct backend * VRT_r_req_backend(struct sess *);
 void VRT_l_req_backend(struct sess *, struct backend *);
 const char * VRT_r_bereq_request(struct sess *);
-void VRT_l_bereq_request(struct sess *, const char *);
+void VRT_l_bereq_request(struct sess *, const char *, ...);
 const char * VRT_r_bereq_url(struct sess *);
-void VRT_l_bereq_url(struct sess *, const char *);
+void VRT_l_bereq_url(struct sess *, const char *, ...);
 const char * VRT_r_bereq_proto(struct sess *);
-void VRT_l_bereq_proto(struct sess *, const char *);
+void VRT_l_bereq_proto(struct sess *, const char *, ...);
 const char * VRT_r_obj_proto(struct sess *);
-void VRT_l_obj_proto(struct sess *, const char *);
+void VRT_l_obj_proto(struct sess *, const char *, ...);
 int VRT_r_obj_status(struct sess *);
 void VRT_l_obj_status(struct sess *, int);
 const char * VRT_r_obj_response(struct sess *);
-void VRT_l_obj_response(struct sess *, const char *);
+void VRT_l_obj_response(struct sess *, const char *, ...);
 unsigned VRT_r_obj_valid(struct sess *);
 void VRT_l_obj_valid(struct sess *, unsigned);
 unsigned VRT_r_obj_cacheable(struct sess *);
@@ -37,9 +40,9 @@
 void VRT_l_obj_ttl(struct sess *, double);
 double VRT_r_obj_lastuse(struct sess *);
 const char * VRT_r_resp_proto(struct sess *);
-void VRT_l_resp_proto(struct sess *, const char *);
+void VRT_l_resp_proto(struct sess *, const char *, ...);
 int VRT_r_resp_status(struct sess *);
 void VRT_l_resp_status(struct sess *, int);
 const char * VRT_r_resp_response(struct sess *);
-void VRT_l_resp_response(struct sess *, const char *);
+void VRT_l_resp_response(struct sess *, const char *, ...);
 double VRT_r_now(struct sess *);

Modified: branches/1.1/lib/libvarnish/Makefile.am
===================================================================
--- branches/1.1/lib/libvarnish/Makefile.am	2007-07-13 14:53:48 UTC (rev 1692)
+++ branches/1.1/lib/libvarnish/Makefile.am	2007-07-13 14:54:51 UTC (rev 1693)
@@ -19,3 +19,5 @@
 	vss.c
 
 libvarnish_la_CFLAGS = -include config.h
+
+libvarnish_la_LIBADD = ${RT_LIBS}

Modified: branches/1.1/lib/libvarnish/time.c
===================================================================
--- branches/1.1/lib/libvarnish/time.c	2007-07-13 14:53:48 UTC (rev 1692)
+++ branches/1.1/lib/libvarnish/time.c	2007-07-13 14:54:51 UTC (rev 1693)
@@ -50,8 +50,30 @@
 #include <string.h>
 #include <time.h>
 
+#ifndef HAVE_CLOCK_GETTIME
+#include "compat/clock_gettime.h"
+#endif
+
 #include "libvarnish.h"
 
+double
+TIM_mono(void)
+{
+	struct timespec ts;
+
+	assert(clock_gettime(CLOCK_MONOTONIC, &ts) == 0);
+	return (ts.tv_sec + 1e-9 * ts.tv_nsec);
+}
+
+double
+TIM_real(void)
+{
+	struct timespec ts;
+
+	assert(clock_gettime(CLOCK_REALTIME, &ts) == 0);
+	return (ts.tv_sec + 1e-9 * ts.tv_nsec);
+}
+
 void
 TIM_format(time_t t, char *p)
 {

Modified: branches/1.1/lib/libvcl/Makefile.am
===================================================================
--- branches/1.1/lib/libvcl/Makefile.am	2007-07-13 14:53:48 UTC (rev 1692)
+++ branches/1.1/lib/libvcl/Makefile.am	2007-07-13 14:54:51 UTC (rev 1693)
@@ -16,6 +16,7 @@
 	vcc_parse.c \
 	vcc_fixed_token.c \
 	vcc_obj.c \
+	vcc_string.c \
 	vcc_token.c \
 	vcc_var.c \
 	vcc_xref.c

Modified: branches/1.1/lib/libvcl/syntax.txt
===================================================================
--- branches/1.1/lib/libvcl/syntax.txt	2007-07-13 14:53:48 UTC (rev 1692)
+++ branches/1.1/lib/libvcl/syntax.txt	2007-07-13 14:54:51 UTC (rev 1693)
@@ -128,6 +128,7 @@
 	'call' ident ';'
 	'rewrite' cstr cstr ';'
 	'set' assignment ';'
+	'remove' variable ';'
 
 # see variable 'returns' in vcc_gen_fixed_token.tcl
 return_action:
@@ -162,6 +163,7 @@
 	'-=' cnum
 	'=' cnum
 
+
 ratio:
 	'*=' double
 	'/=' double

Modified: branches/1.1/lib/libvcl/vcc_acl.c
===================================================================
--- branches/1.1/lib/libvcl/vcc_acl.c	2007-07-13 14:53:48 UTC (rev 1692)
+++ branches/1.1/lib/libvcl/vcc_acl.c	2007-07-13 14:54:51 UTC (rev 1693)
@@ -30,13 +30,13 @@
  */
 
 #include <stdio.h>
-#include <assert.h>
 #include <stdlib.h>
 
 #include "vsb.h"
 
 #include "vcc_priv.h"
 #include "vcc_compile.h"
+#include "libvarnish.h"
 
 static void
 vcc_acl_top(struct tokenlist *tl, const char *acln)
@@ -108,7 +108,7 @@
 }
 
 void
-vcc_Cond_Ip(struct var *vp, struct tokenlist *tl)
+vcc_Cond_Ip(const struct var *vp, struct tokenlist *tl)
 {
 	unsigned tcond;
 	char *acln;

Modified: branches/1.1/lib/libvcl/vcc_action.c
===================================================================
--- branches/1.1/lib/libvcl/vcc_action.c	2007-07-13 14:53:48 UTC (rev 1692)
+++ branches/1.1/lib/libvcl/vcc_action.c	2007-07-13 14:54:51 UTC (rev 1693)
@@ -94,7 +94,7 @@
 /*--------------------------------------------------------------------*/
 
 static void
-illegal_assignment(struct tokenlist *tl, const char *type)
+illegal_assignment(const struct tokenlist *tl, const char *type)
 {
 
 	vsb_printf(tl->sb, "Invalid assignment operator ");
@@ -104,7 +104,7 @@
 }
 
 static void
-check_writebit(struct tokenlist *tl, struct var *vp)
+check_writebit(struct tokenlist *tl, const struct var *vp)
 {
 
 	if (vp->access == V_RW || vp->access == V_WO)
@@ -155,6 +155,8 @@
 				vcc_RateVal(tl);
 			else if (vp->fmt == FLOAT)
 				Fb(tl, 0, "%g", vcc_DoubleVal(tl));
+			else if (vp->fmt == INT)
+				Fb(tl, 0, "%u", vcc_UintVal(tl));
 			else {
 				vsb_printf(tl->sb, "Cannot assign this variable type.\n");
 				vcc_ErrWhere(tl, vt);
@@ -195,28 +197,38 @@
 		vcc_NextToken(tl);
 		Fb(tl, 0, ");\n");
 		break;
-		return;
 	case HASH:
 		ExpectErr(tl, T_INCR);
 		vcc_NextToken(tl);
-		vcc_StringVal(tl);
+		if (!vcc_StringVal(tl)) {
+			ERRCHK(tl);
+			vcc_ExpectedStringval(tl);
+			return;
+		}
 		Fb(tl, 0, ");\n");
-		return;
+		break;
 	case STRING:
 		if (tl->t->tok != '=') {
 			illegal_assignment(tl, "strings");
 			return;
 		}
 		vcc_NextToken(tl);
-		vcc_StringVal(tl);
-		if (vp->ishdr) {
-			while (tl->t->tok != ';') {
-				Fb(tl, 0, ", ");
-				vcc_StringVal(tl);
-			}
-			Fb(tl, 0, ", 0");
+		if (!vcc_StringVal(tl)) {
+			ERRCHK(tl);
+			vcc_ExpectedStringval(tl);
+			return;
 		}
-		Fb(tl, 0, ");\n");
+		do 
+			Fb(tl, 0, ", ");
+		while (vcc_StringVal(tl));
+		if (tl->t->tok != ';') {
+			ERRCHK(tl);
+			vsb_printf(tl->sb,
+			    "Expected variable, string or semicolon\n");
+			vcc_ErrWhere(tl, tl->t);
+			return;
+		}
+		Fb(tl, 0, "0);\n");
 		break;
 	default:
 		vsb_printf(tl->sb,
@@ -232,13 +244,13 @@
 parse_remove(struct tokenlist *tl)
 {
 	struct var *vp;
-	struct token *vt;
 
 	vcc_NextToken(tl);
 	ExpectErr(tl, VAR);
-	vt = tl->t;
 	vp = vcc_FindVar(tl, tl->t, vcc_vars);
-	if (vp->fmt != STRING || !vp->ishdr) {
+	ERRCHK(tl);
+	assert(vp != NULL);
+	if (vp->fmt != STRING || vp->hdr == NULL) {
 		vsb_printf(tl->sb, "Only http header lines can be removed.\n");
 		vcc_ErrWhere(tl, tl->t);
 		return;

Modified: branches/1.1/lib/libvcl/vcc_compile.c
===================================================================
--- branches/1.1/lib/libvcl/vcc_compile.c	2007-07-13 14:53:48 UTC (rev 1692)
+++ branches/1.1/lib/libvcl/vcc_compile.c	2007-07-13 14:54:51 UTC (rev 1693)
@@ -86,7 +86,7 @@
 #include "vcl_returns.h"
 #undef VCL_MET_MAC
 #undef VCL_RET_MAC
-	{ NULL, 0U }
+	{ NULL, 0U, 0}
 };
 
 /*--------------------------------------------------------------------*/

Modified: branches/1.1/lib/libvcl/vcc_compile.h
===================================================================
--- branches/1.1/lib/libvcl/vcc_compile.h	2007-07-13 14:53:48 UTC (rev 1692)
+++ branches/1.1/lib/libvcl/vcc_compile.h	2007-07-13 14:54:51 UTC (rev 1693)
@@ -121,7 +121,7 @@
 	const char		*rname;
 	const char		*lname;
 	enum {V_RO, V_RW, V_WO}	access;
-	char			ishdr;
+	const char		*hdr;
 	unsigned		methods;
 };
 
@@ -136,7 +136,7 @@
 /* vcc_acl.c */
 
 void vcc_Acl(struct tokenlist *tl);
-void vcc_Cond_Ip(struct var *vp, struct tokenlist *tl);
+void vcc_Cond_Ip(const struct var *vp, struct tokenlist *tl);
 
 /* vcc_action.c */
 void vcc_ParseAction(struct tokenlist *tl);
@@ -167,6 +167,11 @@
 unsigned vcc_UintVal(struct tokenlist *tl);
 double vcc_DoubleVal(struct tokenlist *tl);
 
+/* vcc_string.c */
+char *vcc_regexp(struct tokenlist *tl, int sub);
+int vcc_StringVal(struct tokenlist *tl);
+void vcc_ExpectedStringval(struct tokenlist *tl);
+
 /* vcc_token.c */
 void vcc_ErrToken(const struct tokenlist *tl, const struct token *t);
 void vcc_ErrWhere(struct tokenlist *tl, const struct token *t);
@@ -180,7 +185,6 @@
 void vcc_FreeToken(struct token *t);
 
 /* vcc_var.c */
-void vcc_StringVal(struct tokenlist *tl);
 struct var *vcc_FindVar(struct tokenlist *tl, const struct token *t, struct var *vl);
 
 /* vcc_xref.c */

Modified: branches/1.1/lib/libvcl/vcc_fixed_token.c
===================================================================
--- branches/1.1/lib/libvcl/vcc_fixed_token.c	2007-07-13 14:53:48 UTC (rev 1692)
+++ branches/1.1/lib/libvcl/vcc_fixed_token.c	2007-07-13 14:54:51 UTC (rev 1693)
@@ -420,10 +420,11 @@
 	vsb_cat(sb, "void VRT_acl_fini(struct vrt_acl *);\n");
 	vsb_cat(sb, "\n");
 	vsb_cat(sb, "/* Regexp related */\n");
-	vsb_cat(sb, "void VRT_re_init(void **, const char *);\n");
+	vsb_cat(sb, "void VRT_re_init(void **, const char *, int sub);\n");
 	vsb_cat(sb, "void VRT_re_fini(void *);\n");
 	vsb_cat(sb, "int VRT_re_match(const char *, void *re);\n");
-	vsb_cat(sb, "int VRT_re_test(struct vsb *, const char *);\n");
+	vsb_cat(sb, "int VRT_re_test(struct vsb *, const char *, int sub);\n");
+	vsb_cat(sb, "const char *VRT_regsub(struct sess *sp, const char *, void *, const char *);\n");
 	vsb_cat(sb, "\n");
 	vsb_cat(sb, "void VRT_count(struct sess *, unsigned);\n");
 	vsb_cat(sb, "int VRT_rewrite(const char *, const char *);\n");
@@ -432,7 +433,7 @@
 	vsb_cat(sb, "\n");
 	vsb_cat(sb, "enum gethdr_e { HDR_REQ, HDR_RESP, HDR_OBJ, HDR_BEREQ };\n");
 	vsb_cat(sb, "char *VRT_GetHdr(struct sess *, enum gethdr_e where, const char *);\n");
-	vsb_cat(sb, "void VRT_SetHdr(struct sess *, enum gethdr_e where, const char *, ...);\n");
+	vsb_cat(sb, "void VRT_SetHdr(struct sess *, enum gethdr_e where, const char *, const char *, ...);\n");
 	vsb_cat(sb, "void VRT_handling(struct sess *sp, unsigned hand);\n");
 	vsb_cat(sb, "\n");
 	vsb_cat(sb, "/* Backend related */\n");
@@ -441,6 +442,7 @@
 	vsb_cat(sb, "void VRT_free_backends(struct VCL_conf *cp);\n");
 	vsb_cat(sb, "void VRT_fini_backend(struct backend *be);\n");
 	vsb_cat(sb, "\n");
+	vsb_cat(sb, "char *VRT_IP_string(struct sess *sp, struct sockaddr *sa);\n");
 	vsb_cat(sb, "\n");
 	vsb_cat(sb, "#define VRT_done(sp, hand)			\\\n");
 	vsb_cat(sb, "	do {					\\\n");
@@ -461,23 +463,26 @@
 	vsb_cat(sb, "struct sockaddr * VRT_r_client_ip(struct sess *);\n");
 	vsb_cat(sb, "struct sockaddr * VRT_r_server_ip(struct sess *);\n");
 	vsb_cat(sb, "const char * VRT_r_req_request(struct sess *);\n");
+	vsb_cat(sb, "void VRT_l_req_request(struct sess *, const char *, ...);\n");
 	vsb_cat(sb, "const char * VRT_r_req_url(struct sess *);\n");
+	vsb_cat(sb, "void VRT_l_req_url(struct sess *, const char *, ...);\n");
 	vsb_cat(sb, "const char * VRT_r_req_proto(struct sess *);\n");
+	vsb_cat(sb, "void VRT_l_req_proto(struct sess *, const char *, ...);\n");
 	vsb_cat(sb, "void VRT_l_req_hash(struct sess *, const char *);\n");
 	vsb_cat(sb, "struct backend * VRT_r_req_backend(struct sess *);\n");
 	vsb_cat(sb, "void VRT_l_req_backend(struct sess *, struct backend *);\n");
 	vsb_cat(sb, "const char * VRT_r_bereq_request(struct sess *);\n");
-	vsb_cat(sb, "void VRT_l_bereq_request(struct sess *, const char *);\n");
+	vsb_cat(sb, "void VRT_l_bereq_request(struct sess *, const char *, ...);\n");
 	vsb_cat(sb, "const char * VRT_r_bereq_url(struct sess *);\n");
-	vsb_cat(sb, "void VRT_l_bereq_url(struct sess *, const char *);\n");
+	vsb_cat(sb, "void VRT_l_bereq_url(struct sess *, const char *, ...);\n");
 	vsb_cat(sb, "const char * VRT_r_bereq_proto(struct sess *);\n");
-	vsb_cat(sb, "void VRT_l_bereq_proto(struct sess *, const char *);\n");
+	vsb_cat(sb, "void VRT_l_bereq_proto(struct sess *, const char *, ...);\n");
 	vsb_cat(sb, "const char * VRT_r_obj_proto(struct sess *);\n");
-	vsb_cat(sb, "void VRT_l_obj_proto(struct sess *, const char *);\n");
+	vsb_cat(sb, "void VRT_l_obj_proto(struct sess *, const char *, ...);\n");
 	vsb_cat(sb, "int VRT_r_obj_status(struct sess *);\n");
 	vsb_cat(sb, "void VRT_l_obj_status(struct sess *, int);\n");
 	vsb_cat(sb, "const char * VRT_r_obj_response(struct sess *);\n");
-	vsb_cat(sb, "void VRT_l_obj_response(struct sess *, const char *);\n");
+	vsb_cat(sb, "void VRT_l_obj_response(struct sess *, const char *, ...);\n");
 	vsb_cat(sb, "unsigned VRT_r_obj_valid(struct sess *);\n");
 	vsb_cat(sb, "void VRT_l_obj_valid(struct sess *, unsigned);\n");
 	vsb_cat(sb, "unsigned VRT_r_obj_cacheable(struct sess *);\n");
@@ -486,10 +491,10 @@
 	vsb_cat(sb, "void VRT_l_obj_ttl(struct sess *, double);\n");
 	vsb_cat(sb, "double VRT_r_obj_lastuse(struct sess *);\n");
 	vsb_cat(sb, "const char * VRT_r_resp_proto(struct sess *);\n");
-	vsb_cat(sb, "void VRT_l_resp_proto(struct sess *, const char *);\n");
+	vsb_cat(sb, "void VRT_l_resp_proto(struct sess *, const char *, ...);\n");
 	vsb_cat(sb, "int VRT_r_resp_status(struct sess *);\n");
 	vsb_cat(sb, "void VRT_l_resp_status(struct sess *, int);\n");
 	vsb_cat(sb, "const char * VRT_r_resp_response(struct sess *);\n");
-	vsb_cat(sb, "void VRT_l_resp_response(struct sess *, const char *);\n");
+	vsb_cat(sb, "void VRT_l_resp_response(struct sess *, const char *, ...);\n");
 	vsb_cat(sb, "double VRT_r_now(struct sess *);\n");
 }

Modified: branches/1.1/lib/libvcl/vcc_gen_obj.tcl
===================================================================
--- branches/1.1/lib/libvcl/vcc_gen_obj.tcl	2007-07-13 14:53:48 UTC (rev 1692)
+++ branches/1.1/lib/libvcl/vcc_gen_obj.tcl	2007-07-13 14:54:51 UTC (rev 1693)
@@ -32,9 +32,9 @@
 
 # Objects available in backends
 set beobj {
-  { backend.host	WO HOSTNAME }
-  { backend.port	WO PORTNAME }
-  { backend.dnsttl	WO TIME	 }
+  { backend.host	WO HOSTNAME	{} }
+  { backend.port	WO PORTNAME	{} }
+  { backend.dnsttl	WO TIME		{} }
 }
 
 # Variables available in sessions
@@ -56,20 +56,21 @@
 
 	# Request paramters
 	{ req.request
-		RO STRING
+		RW STRING
 		{recv pipe pass hash miss hit fetch                        }
 	}
 	{ req.url
-		RO STRING
+		RW STRING
 		{recv pipe pass hash miss hit fetch                        }
 	}
 	{ req.proto
-		RO STRING
+		RW STRING
 		{recv pipe pass hash miss hit fetch                        }
 	}
 	{ req.http.
 		RW HEADER
 		{recv pipe pass hash miss hit fetch                        }
+		HDR_REQ
 	}
 
 	# Possibly misnamed, not really part of the request
@@ -98,6 +99,7 @@
 	{ bereq.http.
 		RW HEADER
 		{     pipe pass      miss                                  }
+		HDR_BEREQ
 	}
 
 	# The (possibly) cached object
@@ -116,6 +118,7 @@
 	{ obj.http.
 		RW HEADER
 		{                         hit fetch 			   }
+		HDR_OBJ
 	}
 
 	{ obj.valid
@@ -151,6 +154,7 @@
 	{ resp.http.
 		RW HEADER
 		{                                   deliver                }
+		HDR_RESP
 	}
 
 	# Miscellaneous
@@ -200,6 +204,9 @@
 		append l " | "
 		append l VCL_MET_[string toupper $i]
 	}
+	if {$l == ""} {
+		return "0"
+	}
 	return [string range $l 3 end]
 }
 
@@ -224,14 +231,21 @@
 		}
 		if {$a == "WO" || $a == "RW"} {
 			puts $fo  "\t    \"VRT_l_${m}($pa, \","
-			if {$t != "HEADER"} {
+			if {$t == "HEADER"} {
+			} elseif {$t == "STRING"} {
+				puts $fp  "void VRT_l_${m}($ty, $tt($t), ...);"
+			} else {
 				puts $fp  "void VRT_l_${m}($ty, $tt($t));"
 			}
 		} else {
 			puts $fo  "\t    NULL,"
 		}
 		puts $fo  "\t    V_$a,"
-		puts $fo  "\t    0,"
+		if {$t != "HEADER"} {
+			puts $fo  "\t    0,"
+		} else {
+			puts $fo  "\t    \"[lindex $v 4]\","
+		}
 		puts $fo  "\t    [method_map [lindex $v 3]]"
 		puts $fo "\t\},"
 

Modified: branches/1.1/lib/libvcl/vcc_obj.c
===================================================================
--- branches/1.1/lib/libvcl/vcc_obj.c	2007-07-13 14:53:48 UTC (rev 1692)
+++ branches/1.1/lib/libvcl/vcc_obj.c	2007-07-13 14:54:51 UTC (rev 1693)
@@ -15,21 +15,21 @@
 	    "VRT_l_backend_host(backend, ",
 	    V_WO,
 	    0,
-	    
+	    0
 	},
 	{ "backend.port", PORTNAME, 12,
 	    NULL,
 	    "VRT_l_backend_port(backend, ",
 	    V_WO,
 	    0,
-	    
+	    0
 	},
 	{ "backend.dnsttl", TIME, 14,
 	    NULL,
 	    "VRT_l_backend_dnsttl(backend, ",
 	    V_WO,
 	    0,
-	    
+	    0
 	},
 	{ NULL }
 };
@@ -51,22 +51,22 @@
 	},
 	{ "req.request", STRING, 11,
 	    "VRT_r_req_request(sp)",
-	    NULL,
-	    V_RO,
+	    "VRT_l_req_request(sp, ",
+	    V_RW,
 	    0,
 	    VCL_MET_RECV | VCL_MET_PIPE | VCL_MET_PASS | VCL_MET_HASH | VCL_MET_MISS | VCL_MET_HIT | VCL_MET_FETCH
 	},
 	{ "req.url", STRING, 7,
 	    "VRT_r_req_url(sp)",
-	    NULL,
-	    V_RO,
+	    "VRT_l_req_url(sp, ",
+	    V_RW,
 	    0,
 	    VCL_MET_RECV | VCL_MET_PIPE | VCL_MET_PASS | VCL_MET_HASH | VCL_MET_MISS | VCL_MET_HIT | VCL_MET_FETCH
 	},
 	{ "req.proto", STRING, 9,
 	    "VRT_r_req_proto(sp)",
-	    NULL,
-	    V_RO,
+	    "VRT_l_req_proto(sp, ",
+	    V_RW,
 	    0,
 	    VCL_MET_RECV | VCL_MET_PIPE | VCL_MET_PASS | VCL_MET_HASH | VCL_MET_MISS | VCL_MET_HIT | VCL_MET_FETCH
 	},
@@ -74,7 +74,7 @@
 	    "VRT_r_req_http_(sp)",
 	    "VRT_l_req_http_(sp, ",
 	    V_RW,
-	    0,
+	    "HDR_REQ",
 	    VCL_MET_RECV | VCL_MET_PIPE | VCL_MET_PASS | VCL_MET_HASH | VCL_MET_MISS | VCL_MET_HIT | VCL_MET_FETCH
 	},
 	{ "req.hash", HASH, 8,
@@ -116,7 +116,7 @@
 	    "VRT_r_bereq_http_(sp)",
 	    "VRT_l_bereq_http_(sp, ",
 	    V_RW,
-	    0,
+	    "HDR_BEREQ",
 	    VCL_MET_PIPE | VCL_MET_PASS | VCL_MET_MISS
 	},
 	{ "obj.proto", STRING, 9,
@@ -144,7 +144,7 @@
 	    "VRT_r_obj_http_(sp)",
 	    "VRT_l_obj_http_(sp, ",
 	    V_RW,
-	    0,
+	    "HDR_OBJ",
 	    VCL_MET_HIT | VCL_MET_FETCH
 	},
 	{ "obj.valid", BOOL, 9,
@@ -200,7 +200,7 @@
 	    "VRT_r_resp_http_(sp)",
 	    "VRT_l_resp_http_(sp, ",
 	    V_RW,
-	    0,
+	    "HDR_RESP",
 	    VCL_MET_DELIVER
 	},
 	{ "now", TIME, 3,

Modified: branches/1.1/lib/libvcl/vcc_parse.c
===================================================================
--- branches/1.1/lib/libvcl/vcc_parse.c	2007-07-13 14:53:48 UTC (rev 1692)
+++ branches/1.1/lib/libvcl/vcc_parse.c	2007-07-13 14:54:51 UTC (rev 1693)
@@ -221,38 +221,16 @@
 /*--------------------------------------------------------------------*/
 
 static void
-vcc_re(struct tokenlist *tl, const char *str, const struct token *re)
-{
-	char buf[32];
-
-	assert(re->tok == CSTR);
-	if (VRT_re_test(tl->sb, re->dec)) {
-		vcc_ErrWhere(tl, re);
-		return;
-	}
-	sprintf(buf, "VGC_re_%u", tl->recnt++);
-
-	Fb(tl, 1, "VRT_re_match(%s, %s)\n", str, buf);
-	Fh(tl, 0, "void *%s;\n", buf);
-	Fi(tl, 0, "\tVRT_re_init(&%s, ",buf);
-	EncToken(tl->fi, re);
-	Fi(tl, 0, ");\n");
-	Ff(tl, 0, "\tVRT_re_fini(%s);\n", buf);
-}
-
-
-/*--------------------------------------------------------------------*/
-
-static void
 Cond_String(const struct var *vp, struct tokenlist *tl)
 {
+	char *p;
 
 	switch (tl->t->tok) {
 	case '~':
 		vcc_NextToken(tl);
-		ExpectErr(tl, CSTR);
-		vcc_re(tl, vp->rname, tl->t);
+		p = vcc_regexp(tl, 0);
 		vcc_NextToken(tl);
+		Fb(tl, 1, "VRT_re_match(%s, %s)\n", vp->rname, p);
 		break;
 	case T_EQ:
 	case T_NEQ:

Copied: branches/1.1/lib/libvcl/vcc_string.c (from rev 1692, trunk/varnish-cache/lib/libvcl/vcc_string.c)
===================================================================
--- branches/1.1/lib/libvcl/vcc_string.c	                        (rev 0)
+++ branches/1.1/lib/libvcl/vcc_string.c	2007-07-13 14:54:51 UTC (rev 1693)
@@ -0,0 +1,164 @@
+/*-
+ * Copyright (c) 2006 Verdens Gang AS
+ * Copyright (c) 2006-2007 Linpro AS
+ * All rights reserved.
+ *
+ * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "vsb.h"
+
+#include "vcc_priv.h"
+#include "vcc_compile.h"
+#include "libvarnish.h"
+
+#include "vrt.h"
+
+/*--------------------------------------------------------------------*/
+
+char *
+vcc_regexp(struct tokenlist *tl, int sub)
+{
+	char buf[32], *p;
+
+	Expect(tl, CSTR);
+	if (VRT_re_test(tl->sb, tl->t->dec, sub)) {
+		vcc_ErrWhere(tl, tl->t);
+		return (NULL);
+	}
+	sprintf(buf, "VGC_re_%u", tl->recnt++);
+	p = TlAlloc(tl, strlen(buf) + 1);
+	strcpy(p, buf);
+
+	Fh(tl, 0, "void *%s;\n", buf);
+	Fi(tl, 0, "\tVRT_re_init(&%s, ",buf);
+	EncToken(tl->fi, tl->t);
+	Fi(tl, 0, ", %d);\n", sub);
+	Ff(tl, 0, "\tVRT_re_fini(%s);\n", buf);
+	return (p);
+}
+
+/*--------------------------------------------------------------------*/
+
+static int
+vcc_regsub(struct tokenlist *tl)
+{
+	char *p;
+
+	vcc_NextToken(tl);
+
+	Fb(tl, 0, "VRT_regsub(sp, ");
+
+	Expect(tl, '(');
+	vcc_NextToken(tl);
+
+	if (!vcc_StringVal(tl)) {
+		vcc_ExpectedStringval(tl);
+		return (0);
+	}
+
+	Expect(tl, ',');
+	vcc_NextToken(tl);
+	
+	Expect(tl, CSTR);
+	p = vcc_regexp(tl, 1);
+	vcc_NextToken(tl);
+	Fb(tl, 0, ", %s, ", p);
+
+	Expect(tl, ',');
+	vcc_NextToken(tl);
+	
+	Expect(tl, CSTR);
+	if (!vcc_StringVal(tl)) {
+		vcc_ExpectedStringval(tl);
+		return (0);
+	}
+
+	Expect(tl, ')');
+	vcc_NextToken(tl);
+	Fb(tl, 0, ")");
+
+	return (1);
+}
+
+/*--------------------------------------------------------------------
+ * Parse a string value and emit something that results in a usable
+ * "const char *".
+ * There are three possible outcomes:
+ *	tl->err != 0 means something bad happened and a message is emitted.
+ *	return (0) means "could not use this token"
+ *	return (1) means "done"
+ */
+
+int
+vcc_StringVal(struct tokenlist *tl) 
+{
+	struct var *vp;
+
+	if (tl->t->tok == CSTR) {
+		EncToken(tl->fb, tl->t);
+		vcc_NextToken(tl);
+		return (1);
+	}
+	if (tl->t->tok == ID && vcc_IdIs(tl->t, "regsub"))
+		return (vcc_regsub(tl));
+	if (tl->t->tok == VAR) {
+		vp = vcc_FindVar(tl, tl->t, vcc_vars);
+		if (tl->err)
+			return (0);
+		assert(vp != NULL);
+		switch (vp->fmt) {
+		case STRING:
+			Fb(tl, 0, "%s", vp->rname);
+			break;
+		case IP:
+			Fb(tl, 0, "VRT_IP_string(sp, %s)", vp->rname);
+			break;
+		default:
+			vsb_printf(tl->sb,
+			    "String representation of '%s' not implemented yet.\n",
+				vp->name);
+			vcc_ErrWhere(tl, tl->t);
+			return (0);
+		}
+		vcc_NextToken(tl);
+		return (1);
+	}
+	return (0);
+}
+
+void
+vcc_ExpectedStringval(struct tokenlist *tl)
+{
+
+	if (!tl->err) {
+		vsb_printf(tl->sb, "Expected string variable or constant\n");
+		vcc_ErrWhere(tl, tl->t);
+	}
+}

Modified: branches/1.1/lib/libvcl/vcc_var.c
===================================================================
--- branches/1.1/lib/libvcl/vcc_var.c	2007-07-13 14:53:48 UTC (rev 1692)
+++ branches/1.1/lib/libvcl/vcc_var.c	2007-07-13 14:54:51 UTC (rev 1693)
@@ -40,44 +40,10 @@
 
 /*--------------------------------------------------------------------*/
 
-void
-vcc_StringVal(struct tokenlist *tl) 
-{
-	struct var *vp;
-
-	if (tl->t->tok == CSTR) {
-		EncToken(tl->fb, tl->t);
-		vcc_NextToken(tl);
-		return;
-	} else if (tl->t->tok != VAR) {
-		vsb_printf(tl->sb, "Expected string variable or constant\n");
-		vcc_ErrWhere(tl, tl->t);
-		return;
-	}
-	ERRCHK(tl);
-	vp = vcc_FindVar(tl, tl->t, vcc_vars);
-	ERRCHK(tl);
-	switch (vp->fmt) {
-	case STRING:
-		Fb(tl, 0, "%s", vp->rname);
-		break;
-	default:
-		vsb_printf(tl->sb,
-		    "String representation of '%s' not implemented yet.\n",
-			vp->name);
-		vcc_ErrWhere(tl, tl->t);
-		return;
-	}
-	vcc_NextToken(tl);
-}
-
-/*--------------------------------------------------------------------*/
-
 static struct var *
 HeaderVar(struct tokenlist *tl, const struct token *t, const struct var *vh)
 {
 	char *p;
-	const char *wh;
 	struct var *v;
 	int i;
 
@@ -93,23 +59,13 @@
 	v->name = p;
 	v->access = V_RW;
 	v->fmt = STRING;
-	v->ishdr = 1;
+	v->hdr = vh->hdr;
 	v->methods = vh->methods;
-	if (!memcmp(vh->name, "req.", 4))
-		wh = "HDR_REQ";
-	else if (!memcmp(vh->name, "resp.", 5))
-		wh = "HDR_RESP";
-	else if (!memcmp(vh->name, "obj.", 4))
-		wh = "HDR_OBJ";
-	else if (!memcmp(vh->name, "bereq.", 6))
-		wh = "HDR_BEREQ";
-	else
-		assert(0 == 1);
-	asprintf(&p, "VRT_GetHdr(sp, %s, \"\\%03o%s:\")", wh,
+	asprintf(&p, "VRT_GetHdr(sp, %s, \"\\%03o%s:\")", v->hdr,
 	    (unsigned)(strlen(v->name + vh->len) + 1), v->name + vh->len);
 	AN(p);
 	v->rname = p;
-	asprintf(&p, "VRT_SetHdr(sp, %s, \"\\%03o%s:\", ", wh,
+	asprintf(&p, "VRT_SetHdr(sp, %s, \"\\%03o%s:\", ", v->hdr,
 	    (unsigned)(strlen(v->name + vh->len) + 1), v->name + vh->len);
 	AN(p);
 	v->lname = p;

Modified: branches/1.1/lib/libvcl/vcc_xref.c
===================================================================
--- branches/1.1/lib/libvcl/vcc_xref.c	2007-07-13 14:53:48 UTC (rev 1692)
+++ branches/1.1/lib/libvcl/vcc_xref.c	2007-07-13 14:54:51 UTC (rev 1693)
@@ -328,7 +328,7 @@
 }
 
 static struct procuse *
-vcc_FindIllegalUse(struct proc *p, struct method *m)
+vcc_FindIllegalUse(const struct proc *p, const struct method *m)
 {
 	struct procuse *pu;
 
@@ -339,7 +339,7 @@
 }
 
 static int
-vcc_CheckUseRecurse(struct tokenlist *tl, struct proc *p, struct method *m)
+vcc_CheckUseRecurse(struct tokenlist *tl, const struct proc *p, struct method *m)
 {
 	struct proccall *pc;
 	struct procuse *pu;

Modified: branches/1.1/man/vcl.7
===================================================================
--- branches/1.1/man/vcl.7	2007-07-13 14:53:48 UTC (rev 1692)
+++ branches/1.1/man/vcl.7	2007-07-13 14:54:51 UTC (rev 1693)
@@ -28,7 +28,7 @@
 .\"
 .\" $Id$
 .\"
-.Dd July 5, 2007
+.Dd July 13, 2007
 .Dt VCL 7
 .Os
 .Sh NAME
@@ -116,6 +116,27 @@
     pipe;
 }
 .Ed
+.Ss Functions
+The following built-in functions are available:
+.Bl -tag -width indent
+.It Fn regsub "str" "regex" "sub"
+Returns a copy of
+.Fa str
+with all occurrences of the regular expression
+.Fa regex
+replaced with
+.Fa sub .
+Within
+.Fa sub ,
+.Va $0
+(which can also be spelled
+.Va & )
+is replaced with the entire matched string, and
+.Va $n
+is replaced with the contents of subgroup
+.Ar n
+in the matched string.
+.El
 .Ss Subroutines
 A subroutine is used to group code for legibility or reusability:
 .Bd -literal -offset 4n
@@ -145,7 +166,7 @@
 request should be handled.
 Each subroutine terminates by calling one of a small number of
 keywords which indicates the desired outcome.
-.Bl -tag -width "vcl_timeout"
+.Bl -tag -width indent
 .\" vcl_recv
 .It Cm vcl_recv
 Called at the beginning of a request, after the complete request has
@@ -156,7 +177,7 @@
 The
 .Cm vcl_recv
 subroutine may terminate with one of the following keywords:
-.Bl -tag -width "discard"
+.Bl -tag -width indent
 .It Cm error Ar code Op Ar reason
 Return the specified error code to the client and abandon the
 request.
@@ -186,7 +207,7 @@
 The
 .Cm vcl_pipe
 subroutine may terminate with one of the following keywords:
-.Bl -tag -width "discard"
+.Bl -tag -width indent
 .It Cm error Ar code Op Ar reason
 Return the specified error code to the client and abandon the
 request.
@@ -205,7 +226,7 @@
 The
 .Cm vcl_pass
 subroutine may terminate with one of the following keywords:
-.Bl -tag -width "discard"
+.Bl -tag -width indent
 .It Cm error Ar code Op Ar reason
 Return the specified error code to the client and abandon the
 request.
@@ -218,7 +239,7 @@
 The
 .Cm vcl_hash
 subroutine may terminate with one of the following keywords:
-.Bl -tag -width "discard"
+.Bl -tag -width indent
 .It Cm hash
 Proceed.
 .El
@@ -230,7 +251,7 @@
 The
 .Cm vcl_hit
 subroutine may terminate with one of the following keywords:
-.Bl -tag -width "discard"
+.Bl -tag -width indent
 .It Cm error Ar code Op Ar reason
 Return the specified error code to the client and abandon the
 request.
@@ -253,7 +274,7 @@
 The
 .Cm vcl_miss
 subroutine may terminate with one of the following keywords:
-.Bl -tag -width "discard"
+.Bl -tag -width indent
 .It Cm error Ar code Op Ar reason
 Return the specified error code to the client and abandon the
 request.
@@ -274,7 +295,7 @@
 The
 .Cm vcl_fetch
 subroutine may terminate with one of the following keywords:
-.Bl -tag -width "discard"
+.Bl -tag -width indent
 .It Cm error Ar code Op Ar reason
 Return the specified error code to the client and abandon the
 request.
@@ -294,7 +315,7 @@
 The
 .Cm vcl_deliver
 subroutine may terminate with one of the following keywords:
-.Bl -tag -width "discard"
+.Bl -tag -width indent
 .It Cm error Ar code Op Ar reason
 Return the specified error code to the client and abandon the
 request.
@@ -309,7 +330,7 @@
 The
 .Cm vcl_timeout
 subroutine may terminate with one of the following keywords:
-.Bl -tag -width "discard"
+.Bl -tag -width indent
 .It Cm fetch
 Request a fresh copy of the object from the backend.
 .It Cm discard
@@ -324,7 +345,7 @@
 The
 .Cm vcl_discard
 subroutine may terminate with one of the following keywords:
-.Bl -tag -width "discard"
+.Bl -tag -width indent
 .It Cm discard
 Discard the object.
 .It Cm keep




More information about the varnish-commit mailing list