Index: doc/sphinx/reference/vcl.rst
===================================================================
--- doc/sphinx/reference/vcl.rst	(revision 5064)
+++ doc/sphinx/reference/vcl.rst	(revision 5066)
@@ -310,6 +310,11 @@
   pipe    
     Switch to pipe mode.  Control will eventually pass to vcl_pipe.
 
+  refresh
+    Go through normal caching channels, but guarantee a cache miss even if
+    there is valid content in the cache, thereby performing a controlled
+    refresh of the content.
+
   lookup  
     Look up the requested object in the cache.  Control will
     eventually pass to vcl_hit or vcl_miss, depending on whether the
Index: lib/libvcl/generate.py
===================================================================
--- lib/libvcl/generate.py	(revision 5064)
+++ lib/libvcl/generate.py	(revision 5066)
@@ -84,7 +84,7 @@
 # Our methods and actions
 
 returns =(
-	('recv',	('error', 'pass', 'pipe', 'lookup',)),
+	('recv',	('error', 'pass', 'pipe', 'refresh','lookup',)),
 	('pipe',	('error', 'pipe',)),
 	('pass',	('error', 'restart', 'pass',)),
 	('hash',	('hash',)),
Index: bin/varnishtest/tests/c00035.vtc
===================================================================
--- bin/varnishtest/tests/c00035.vtc	(revision 0)
+++ bin/varnishtest/tests/c00035.vtc	(revision 5066)
@@ -0,0 +1,38 @@
+# $Id: c00024.vtc 4651 2010-04-08 16:21:16Z phk $
+
+test "Test return(refresh) in vcl_recv"
+
+server s1 {
+        rxreq 
+        txresp -hdr "Inc: 1"
+        rxreq 
+        txresp -hdr "Inc: 2"
+} -start
+
+varnish v1 -vcl+backend { 
+	sub vcl_recv {
+		if (req.http.x-refresh == "1") {
+			return(refresh);
+		}
+	}
+ } -start 
+
+client c1 {
+        txreq -url "/"
+        rxresp
+        expect resp.status == 200
+	expect resp.http.Inc == "1"
+        txreq -url "/"
+        rxresp
+        expect resp.status == 200
+	expect resp.http.Inc == "1"
+        txreq -url "/" -hdr "x-refresh: 1"
+        rxresp
+        expect resp.status == 200
+	expect resp.http.Inc == "2"
+        txreq -url "/"
+        rxresp
+        expect resp.status == 200
+	expect resp.http.Inc == "2"
+} -run
+
Index: bin/varnishd/steps.h
===================================================================
--- bin/varnishd/steps.h	(revision 5064)
+++ bin/varnishd/steps.h	(revision 5066)
@@ -36,6 +36,7 @@
 STEP(pipe,	PIPE)
 STEP(pass,	PASS)
 STEP(lookup,	LOOKUP)
+STEP(refresh,	REFRESH)
 STEP(miss,	MISS)
 STEP(hit,	HIT)
 STEP(fetch,	FETCH)
Index: bin/varnishd/cache_center.c
===================================================================
--- bin/varnishd/cache_center.c	(revision 5064)
+++ bin/varnishd/cache_center.c	(revision 5066)
@@ -830,6 +830,11 @@
 	return (0);
 }
 
+static int
+cnt_refresh(struct sess *sp)
+{
+	return cnt_lookup(sp);
+}
 /*--------------------------------------------------------------------
  * We had a miss, ask VCL, proceed as instructed
  *
@@ -1063,6 +1068,9 @@
 		/* XXX: discard req body, if any */
 		sp->step = STP_LOOKUP;
 		return (0);
+	case VCL_RET_REFRESH:
+		sp->step = STP_REFRESH;
+		return (0);
 	case VCL_RET_PIPE:
 		if (sp->esis > 0) {
 			/* XXX: VSL something */
@@ -1207,6 +1215,7 @@
 	    sp->step == STP_FIRST ||
 	    sp->step == STP_START ||
 	    sp->step == STP_LOOKUP ||
+	    sp->step == STP_REFRESH ||
 	    sp->step == STP_RECV);
 
 	/*
Index: bin/varnishd/cache_hash.c
===================================================================
--- bin/varnishd/cache_hash.c	(revision 5064)
+++ bin/varnishd/cache_hash.c	(revision 5066)
@@ -402,7 +402,8 @@
 	if (oc == NULL			/* We found no live object */
 	    && grace_oc != NULL		/* There is a grace candidate */
 	    && (busy_oc != NULL		/* Somebody else is already busy */
-	    || !VBE_Healthy(sp->t_req, sp->director, (uintptr_t)oh))) {
+	    || !VBE_Healthy(sp->t_req, sp->director, (uintptr_t)oh))
+	    && sp->step != STP_REFRESH) {
 					 /* Or it is impossible to fetch: */
 		o = grace_oc->obj;
 		CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
@@ -414,16 +415,24 @@
 		o = oc->obj;
 		CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
 		assert(oc->objhead == oh);
-
-		/* We found an object we like */
-		oc->refcnt++;
-		if (o->hits < INT_MAX)
-			o->hits++;
-		assert(oh->refcnt > 1);
-		Lck_Unlock(&oh->mtx);
-		assert(hash->deref(oh));
-		*poh = oh;
-		return (oc);
+		if (sp->step == STP_REFRESH) {
+			if (o->ttl >= sp->t_req) {
+				o->ttl = sp->t_req - 1;
+				o->grace = HSH_Grace(sp->grace);
+				EXP_Rearm(o);
+			}
+			o = NULL;
+		} else {
+			/* We found an object we like */
+			oc->refcnt++;
+			if (o->hits < INT_MAX)
+				o->hits++;
+			assert(oh->refcnt > 1);
+			Lck_Unlock(&oh->mtx);
+			assert(hash->deref(oh));
+			*poh = oh;
+			return (oc);
+		}
 	}
 
 	if (busy_oc != NULL) {