---------------------
PatchSet 10170 
Date: 2007/11/27 08:12:17
Author: adri
Branch: store_copy
Tag: (none) 
Log:
Merge changes from Squid-2.HEAD.

Members: 
	ChangeLog:1.93->1.93.2.1 
	configure.in:1.184->1.184.2.1 
	doc/release-notes/release-2.6.html:1.47->1.47.2.1 
	doc/release-notes/release-2.6.sgml:1.59->1.59.2.1 
	helpers/basic_auth/DB/.cvsignore:1.2->1.2.2.1 
	helpers/basic_auth/DB/squid_db_auth.in:1.2->1.2.4.1 
	helpers/basic_auth/squid_radius_auth/ChangeLog:1.1->1.1.4.1(DEAD) 
	helpers/basic_auth/squid_radius_auth/Makefile.am:1.1->1.1.4.1 
	helpers/basic_auth/squid_radius_auth/md5.c:1.1->1.1.4.1(DEAD) 
	helpers/basic_auth/squid_radius_auth/md5.h:1.1->1.1.4.1(DEAD) 
	helpers/basic_auth/squid_radius_auth/squid_rad_auth.c:1.1->1.1.4.1 
	helpers/basic_auth/squid_radius_auth/util.c:1.1->1.1.4.1 
	helpers/basic_auth/squid_radius_auth/util.h:1.1->1.1.4.1 
	include/Array.h:1.7->1.7.52.1 
	include/md5.h:1.12->1.12.34.1 
	lib/Array.c:1.6->1.6.52.1 
	lib/Makefile.am:1.10->1.10.18.1 
	lib/md5.c:1.12->1.12.30.1 
	src/HttpHeader.c:1.28->1.28.6.1 
	src/HttpReply.c:1.23->1.23.6.1 
	src/HttpRequest.c:1.17->1.17.10.1 
	src/Makefile.am:1.54->1.54.2.1 
	src/access_log.c:1.43->1.43.2.1 
	src/cache_cf.c:1.102->1.102.2.1 
	src/cf.data.depend:1.1->1.1.4.1 
	src/cf.data.pre:1.209->1.209.2.1 
	src/client_side.c:1.202.2.6->1.202.2.7 
	src/client_side_rewrite.c:1.2.4.1->1.2.4.2 
	src/client_side_storeurl_rewrite.c:1.3.2.1->1.3.2.2 
	src/enums.h:1.62->1.62.2.1 
	src/errorpage.c:1.37->1.37.6.1 
	src/fqdncache.c:1.22->1.22.2.1 
	src/helper.c:1.43->1.43.6.1 
	src/http.c:1.63->1.63.2.1 
	src/ipcache.c:1.25->1.25.2.1 
	src/main.c:1.80->1.80.2.1 
	src/mib.txt:1.9->1.9.4.1 
	src/protos.h:1.146.2.3->1.146.2.4 
	src/redirect.c:1.16->1.16.10.1 
	src/refresh.c:1.15->1.15.6.1 
	src/refresh_check.c:1.2.4.1->1.2.4.2 
	src/stat.c:1.42.2.2->1.42.2.3 
	src/store.c:1.49->1.49.4.1 
	src/store_client.c:1.25.10.4->1.25.10.5 
	src/store_key_md5.c:1.10->1.10.10.1 
	src/store_rewrite.c:1.1.4.1->1.1.4.2 
	src/store_swapmeta.c:1.12->1.12.22.1 
	src/store_update.c:1.2.4.1->1.2.4.2 
	src/structs.h:1.158.2.4->1.158.2.5 
	src/typedefs.h:1.43.2.2->1.43.2.3 
	src/fs/aufs/aiops.c:1.28->1.28.18.1 
	src/fs/aufs/aiops_win32.c:1.4->1.4.28.1 
	src/fs/aufs/store_dir_aufs.c:1.50->1.50.6.1 

Index: squid/ChangeLog
===================================================================
RCS file: /cvsroot/squid-sf//squid/ChangeLog,v
retrieving revision 1.93
retrieving revision 1.93.2.1
diff -u -r1.93 -r1.93.2.1
--- squid/ChangeLog	23 Sep 2007 16:52:56 -0000	1.93
+++ squid/ChangeLog	27 Nov 2007 08:12:17 -0000	1.93.2.1
@@ -39,6 +39,45 @@
 	- Implementation of an external logfile daemon (ie, logging to
 	  a pipe); UDP logging (based in part on work done by Tim Starling)
 
+Changes to squid-2.6.STABLE17 (26 Nov 2007)
+
+	- Fix compile error with old GCC 2.x or other ANSI-C compilers before
+	  C99
+	- Mention the login= cache_peer option in release notes
+	- Fix bad cache_peer example in squid.conf
+	- Bug #2086: Fix a compile-time memory corruption error causing cf_gen
+	  to fail
+	- Bug #2048: Clarify high_memory_warning usage
+	- Reject DNS responses which result in no data
+	- Fix version number in configuration manual
+	- Move cache and request/reply_header_max_size to their proper
+	  sections
+	- Bug #2088: sbrk statistics broken when process size >2GB
+	- Move logopen() much earlier to have fatal startup errors sent to the
+	  proper syslog facility
+	- Fix HTTP/0.9 responses
+	- Correct bad example config for tos_outgoing_tos
+	- Fix grammar in description of mail_program squid.conf option
+	- Ignore Content-Length in chunked responses instead of rejecting the
+	  response as invalid
+	- Documented that http_port no longer have a default
+	- Cleanup of cache digest documentation
+	- Make aufs store rebuilding back off a little if I/O load too high
+	- Bug #2100: Respect DNS ttl=0
+	- Update udp_(incoming|outgoing)_address documentation to reflect
+	  current bahaviour.
+	- Update HTCP documentation
+	- Document the overlapping helper request format
+	- Change priority of proxy auth and extacl provided username in
+	  login=*:pass
+	- pack header entries on cache updates
+	- Make squid_db_auth reopen the database connection on each query by
+	  default
+	- Improve helper debug ouput, including the channel number
+	- Update cachePeerEntry MIB description to mention what is used as
+	  index key
+	- Import squid_radius_auth for authenticating to RADIUS
+
 Changes to squid-2.6.STABLE16 (5 Sep 2007)
 
 	- Test for sys/capability.h linux include file to avoid failing on
Index: squid/configure.in
===================================================================
RCS file: /cvsroot/squid-sf//squid/configure.in,v
retrieving revision 1.184
retrieving revision 1.184.2.1
diff -u -r1.184 -r1.184.2.1
--- squid/configure.in	5 Sep 2007 22:52:14 -0000	1.184
+++ squid/configure.in	27 Nov 2007 08:12:17 -0000	1.184.2.1
@@ -1,7 +1,7 @@
 dnl
 dnl  Configuration input file for Squid
 dnl
-dnl  $Id: configure.in,v 1.184 2007/09/05 22:52:14 squidadm Exp $
+dnl  $Id: configure.in,v 1.184.2.1 2007/11/27 08:12:17 adri Exp $
 dnl
 dnl
 dnl
@@ -10,7 +10,7 @@
 AM_CONFIG_HEADER(include/autoconf.h)
 AC_CONFIG_AUX_DIR(cfgaux)
 AM_INIT_AUTOMAKE
-AC_REVISION($Revision: 1.184 $)dnl
+AC_REVISION($Revision: 1.184.2.1 $)dnl
 AC_PREFIX_DEFAULT(/usr/local/squid)
 AM_MAINTAINER_MODE
 
@@ -686,11 +686,13 @@
   fi
 ])
 
+dnl SSL is not enabled by default.
 AM_CONDITIONAL(ENABLE_SSL, false)
 
 SSLLIB=''
 SSLFLAGS=''
 
+dnl Default is to use OpenSSL when available
 AC_ARG_ENABLE(ssl,
 [  --enable-ssl            Enable ssl gatewaying support using OpenSSL],
 [ if test "$enableval" != "no"; then
@@ -709,8 +711,7 @@
   fi
 ])
 
-AM_CONDITIONAL(NEED_OWN_MD5, true)
-
+dnl User may specify OpenSSL is needed from a non-standard location
 AC_ARG_WITH(openssl,
 [  --with-openssl[=prefix]
 			  Compile with the OpenSSL libraries. The path to
@@ -739,7 +740,6 @@
   AC_DEFINE(USE_OPENSSL, 1, [Define this to make use of the OpenSSL libraries for
 	MD5 calculation rather than Squid's own MD5 implementation
 	or if building with SSL encryption (USE_SSL)])
-  AM_CONDITIONAL(NEED_OWN_MD5, false)
   if test -z "$SSLLIB"; then
     SSLLIB="-lcrypto" # for MD5 routines
   fi
@@ -751,6 +751,7 @@
 fi
 AC_SUBST(SSLLIB)
 
+
 AC_ARG_ENABLE(forw-via-db,
 [  --enable-forw-via-db    Enable Forw/Via database],
 [ if test "$enableval" = "yes" ; then
@@ -1635,6 +1636,7 @@
 	sys/file.h \
 	sys/ioctl.h \
 	sys/mount.h \
+	sys/md5.h \
 	sys/msg.h \
 	sys/prctl.h \
 	sys/resource.h \
@@ -2103,7 +2105,11 @@
 dnl Check for libcrypt
 dnl Some of our helpers use crypt(3) which may be in libc, or in
 dnl libcrypt (eg FreeBSD)
-AC_CHECK_LIB(crypt, crypt, [CRYPTLIB="-lcrypt"])
+AC_CHECK_LIB(crypt, crypt, [CRYPTLIB=" -lcrypt "])
+
+dnl Solaris10 provides MD5 natively through libmd5
+AC_CHECK_LIB(md5, MD5Init, [CRYPTLIB+=" -lmd5 "])
+
 AC_SUBST(CRYPTLIB)
 
 dnl Check for libdl, used by auth_modules/PAM
Index: squid/doc/release-notes/release-2.6.html
===================================================================
RCS file: /cvsroot/squid-sf//squid/doc/release-notes/release-2.6.html,v
retrieving revision 1.47
retrieving revision 1.47.2.1
diff -u -r1.47 -r1.47.2.1
--- squid/doc/release-notes/release-2.6.html	5 Sep 2007 22:52:15 -0000	1.47
+++ squid/doc/release-notes/release-2.6.html	27 Nov 2007 08:12:19 -0000	1.47.2.1
@@ -2,12 +2,12 @@
 <HTML>
 <HEAD>
  <META NAME="GENERATOR" CONTENT="LinuxDoc-Tools 0.9.21">
- <TITLE>Squid 2.6.STABLE16 release notes</TITLE>
+ <TITLE>Squid 2.6.STABLE17 release notes</TITLE>
 </HEAD>
 <BODY>
-<H1>Squid 2.6.STABLE16 release notes</H1>
+<H1>Squid 2.6.STABLE17 release notes</H1>
 
-<H2>Squid Developers</H2>$Id: release-2.6.html,v 1.47 2007/09/05 22:52:15 squidadm Exp $
+<H2>Squid Developers</H2>$Id: release-2.6.html,v 1.47.2.1 2007/11/27 08:12:19 adri Exp $
 <HR>
 <EM>This document contains the release notes for version 2.6 of Squid.
 Squid is a WWW Cache application developed by the Web Caching community.</EM>
@@ -75,6 +75,9 @@
 <P>
 <H2><A NAME="toc21">21.</A> <A HREF="#s21">Key changes squid-2.6.STABLE15 to 2.6.STABLE16</A></H2>
 
+<P>
+<H2><A NAME="toc22">22.</A> <A HREF="#s22">Key changes squid-2.6.STABLE16 to 2.6.STABLE17</A></H2>
+
 
 <HR>
 <H2><A NAME="s1">1.</A> <A HREF="#toc1">Key changes from squid 2.5</A></H2>
@@ -153,7 +156,7 @@
 
 <P>
 <DL>
-<DT><B>http_port</B><DD><P>Now takes a list of options in addition to the port address, specifying the purpose of this http_port. Default is plain Internet proxy as usual.</P>
+<DT><B>http_port</B><DD><P>Now takes a list of options in addition to the port address, specifying the purpose of this http_port. Default is plain Internet proxy as usual. Also there is no longer a default port and you must include a http_port directive in your squid.conf if you want Squid to listen for http requests.</P>
 <DT><B>httpd_accel_* for transparent proxy</B><DD><P>Now implemented by the "transparent" http_port option</P>
 <DT><B>httpd_accel_* for accelerator mode</B><DD><P>Now implemented by other options and the http_port accel option. See individual directives below.</P>
 <DT><B>httpd_accel_host</B><DD><P>Replaced by defaultsite http_port option and cache_peer originserver option.</P>
@@ -207,6 +210,7 @@
 <DT><B>check_hostnames</B><DD><P>Control if Squid should check the sanity of host names before trying to look them up in DNS</P>
 <DT><B>allow_underscores</B><DD><P>Control if _ is to be considered a valid character in hostnames or not</P>
 <DT><B>cache_peer carp-load-factor</B><DD><P>Option removed. CARP now uses the weight parameter instead.</P>
+<DT><B>cache_peer login=</B><DD><P>Controls how Squid forwards login information to peer caches and servers.</P>
 </DL>
 </P>
 
@@ -743,5 +747,20 @@
 </UL>
 </P>
 
+<H2><A NAME="s22">22.</A> <A HREF="#toc22">Key changes squid-2.6.STABLE16 to 2.6.STABLE17</A></H2>
+
+<P>
+<UL>
+<LI>A temporary memory leak fixed on cache updates</LI>
+<LI>New squid_radius_auth RADIUS authentication helper</LI>
+<LI>Documentation cleanups</LI>
+<LI>Code cleanups and portability fixes</LI>
+<LI>Several minor bugfixes</LI>
+<LI>See also the list of 
+<A HREF="http://www.squid-cache.org/Versions/v2/2.6/changesets/SQUID_2_6_STABLE16.html">squid-2.6.STABLE16 changes</A> and the 
+<A HREF="ChangeLog">ChangeLog</A> file for details.</LI>
+</UL>
+</P>
+
 </BODY>
 </HTML>
Index: squid/doc/release-notes/release-2.6.sgml
===================================================================
RCS file: /cvsroot/squid-sf//squid/doc/release-notes/release-2.6.sgml,v
retrieving revision 1.59
retrieving revision 1.59.2.1
diff -u -r1.59 -r1.59.2.1
--- squid/doc/release-notes/release-2.6.sgml	9 Sep 2007 09:53:06 -0000	1.59
+++ squid/doc/release-notes/release-2.6.sgml	27 Nov 2007 08:12:19 -0000	1.59.2.1
@@ -1,8 +1,8 @@
 <!doctype linuxdoc system>
 <article>
-<title>Squid 2.6.STABLE16 release notes</title>
+<title>Squid 2.6.STABLE17 release notes</title>
 <author>Squid Developers</author>
-<date>$Id: release-2.6.sgml,v 1.59 2007/09/09 09:53:06 squidadm Exp $</date>
+<date>$Id: release-2.6.sgml,v 1.59.2.1 2007/11/27 08:12:19 adri Exp $</date>
 
 <abstract>
 This document contains the release notes for version 2.6 of Squid.
@@ -82,7 +82,7 @@
 
 <sect>Changes to squid.conf
 <p><descrip>
-<tag>http_port</tag>Now takes a list of options in addition to the port address, specifying the purpose of this http_port. Default is plain Internet proxy as usual.
+<tag>http_port</tag>Now takes a list of options in addition to the port address, specifying the purpose of this http_port. Default is plain Internet proxy as usual. Also there is no longer a default port and you must include a http_port directive in your squid.conf if you want Squid to listen for http requests.
 <tag>httpd_accel_* for transparent proxy</tag>Now implemented by the "transparent" http_port option
 <tag>httpd_accel_* for accelerator mode</tag>Now implemented by other options and the http_port accel option. See individual directives below.
 <tag>httpd_accel_host</tag>Replaced by defaultsite http_port option and cache_peer originserver option.
@@ -638,5 +638,20 @@
 				name="ChangeLog"> file for details.
 </itemize>
 
+<sect>Key changes squid-2.6.STABLE16 to 2.6.STABLE17
+
+<p>
+<itemize>
+	<item>A temporary memory leak fixed on cache updates
+	<item>New squid_radius_auth RADIUS authentication helper
+	<item>Documentation cleanups
+	<item>Code cleanups and portability fixes
+	<item>Several minor bugfixes
+	<item>See also the list of <url
+		url="http://www.squid-cache.org/Versions/v2/2.6/changesets/SQUID_2_6_STABLE16.html"
+			name="squid-2.6.STABLE16 changes"> and the <url url="ChangeLog"
+				name="ChangeLog"> file for details.
+</itemize>
+
 </article>
 
Index: squid/helpers/basic_auth/DB/.cvsignore
===================================================================
RCS file: /cvsroot/squid-sf//squid/helpers/basic_auth/DB/.cvsignore,v
retrieving revision 1.2
retrieving revision 1.2.2.1
diff -u -r1.2 -r1.2.2.1
--- squid/helpers/basic_auth/DB/.cvsignore	3 Sep 2007 04:51:58 -0000	1.2
+++ squid/helpers/basic_auth/DB/.cvsignore	27 Nov 2007 08:12:20 -0000	1.2.2.1
@@ -2,4 +2,4 @@
 Makefile
 Makefile.in
 squid_db_auth
-squid_db_auth.8Makefile.in
+squid_db_auth.8
Index: squid/helpers/basic_auth/DB/squid_db_auth.in
===================================================================
RCS file: /cvsroot/squid-sf//squid/helpers/basic_auth/DB/squid_db_auth.in,v
retrieving revision 1.2
retrieving revision 1.2.4.1
diff -u -r1.2 -r1.2.4.1
--- squid/helpers/basic_auth/DB/squid_db_auth.in	22 Aug 2007 06:52:10 -0000	1.2
+++ squid/helpers/basic_auth/DB/squid_db_auth.in	27 Nov 2007 08:12:20 -0000	1.2.4.1
@@ -21,6 +21,7 @@
 my $db_passwdcol = "password";
 my $db_cond = "enabled = 1";
 my $plaintext = 0;
+my $persist = 0;
 
 =pod
 
@@ -66,6 +67,10 @@
 
 Database contains plain-text passwords
 
+=item	B<--persist>
+
+Keep a persistent database connection open between queries. 
+
 =back
 
 =cut
@@ -79,13 +84,30 @@
 	'passwdcol=s' => \$db_passwdcol,
 	'cond=s' => \$db_cond,
 	'plaintext' => \$plaintext,
+	'persist' => \$persist,
 	);
 
-my $dbh = DBI->connect($dsn, $db_user, $db_passwd) || die ("Could not connect to $dsn\n");
+my ($_dbh, $_sth);
 
-my ($sth) = $dbh->prepare("SELECT $db_passwdcol FROM $db_table WHERE $db_usercol = ?" . ($db_cond ne "" ? " AND $db_cond" : "")) || die;
+sub close_db()
+{
+    return if !defined($_dbh);
+    $_dbh->disconnect();
+    undef $_dbh;
+    undef $_sth;
+}
 
-my $status;
+sub open_db()
+{
+    return $_sth if defined $_sth;
+    $_dbh = DBI->connect($dsn, $db_user, $db_passwd);
+    if (!defined $_dbh) {
+    	warn ("Could not connect to $dsn\n");
+	return undef;
+    }
+    $_sth = $_dbh->prepare("SELECT $db_passwdcol FROM $db_table WHERE $db_usercol = ?" . ($db_cond ne "" ? " AND $db_cond" : "")) || die;
+    return $_sth;
+}
 
 sub check_password($$)
 {
@@ -97,20 +119,34 @@
 
     return 0;
 }
+
+sub query_db($) {
+    my ($user) = @_;
+    my ($sth) = open_db() || return undef;
+    if (!$sth->execute($user)) {
+	close_db();
+	open_db() || return undef;
+	$sth->execute($user) || return undef;;
+    }
+    return $sth;
+}
+my $status;
+
 while (<>) {
     my ($user, $password) = split;
     $status = "ERR";
     $user =~ s/%(..)/pack("H*", $1)/ge;
     $password =~ s/%(..)/pack("H*", $1)/ge;
 
-    $status = "ERR internal error";
-    $sth->execute($user) || next;
+    $status = "ERR database error";
+    my $sth = query_db($user) || next;
     $status = "ERR unknown login";
-    my ($row) = $sth->fetchrow_arrayref() || next;
+    my $row = $sth->fetchrow_arrayref() || next;
     $status = "ERR login failure";
     next if (!check_password($password, @$row[0]));
     $status = "OK";
 } continue {
+    close_db() if (!$persist);
     print $status . "\n";
 }
 
--- squid/helpers/basic_auth/squid_radius_auth/ChangeLog	Wed Nov 28 01:20:24 2007
+++ /dev/null	Wed Nov 28 01:20:24 2007
@@ -1,47 +0,0 @@
-2007-08-27 02:10  hno
-
-	* Makefile.in: Bootstrapped
-
-2007-08-24 14:31  hno
-
-	* Makefile.in: Bootstrapped
-
-2007-08-24 04:36  amosjeffries
-
-	* Makefile.in: Bootstrapped.
-
-2007-08-18 02:11  hno
-
-	* Makefile.in: Bootstrapped
-
-2007-08-17 20:58  serassio
-
-	* Makefile.in: Bootstrapped
-
-2007-08-15 02:11  hno
-
-	* Makefile.in: Bootstrapped
-
-2007-08-14 19:07  serassio
-
-	* Makefile.in: Bootstrapped
-
-2007-08-13 10:28  serassio
-
-	* .cvsignore: Added/updated .cvsignore files
-
-2007-06-25 15:57  hno
-
-	* Makefile.in: Bootstrapped
-
-2007-06-25 13:02  hno
-
-	* COPYRIGHT, Changelog, Make.inc, Makefile.am, Makefile.default,
-	  Makefile.in, Makefile.solaris, README, md5.c, md5.h, radius.h,
-	  squid_rad_auth.c, squid_radius_auth.8, util.c, util.h: Import
-	  squid_radius_auth helper for basic authentication to RADIUS
-
-2004-08-07 20:09  hno
-
-	* etc/squid_radius_auth.conf: Import of version 1.07
-
Index: squid/helpers/basic_auth/squid_radius_auth/Makefile.am
===================================================================
RCS file: /cvsroot/squid-sf//squid/helpers/basic_auth/squid_radius_auth/Makefile.am,v
retrieving revision 1.1
retrieving revision 1.1.4.1
diff -u -r1.1 -r1.1.4.1
--- squid/helpers/basic_auth/squid_radius_auth/Makefile.am	5 Sep 2007 22:52:16 -0000	1.1
+++ squid/helpers/basic_auth/squid_radius_auth/Makefile.am	27 Nov 2007 08:12:20 -0000	1.1.4.1
@@ -1,7 +1,7 @@
 #
 #  Makefile for the Squid LDAP authentication helper
 #
-#  $Id: Makefile.am,v 1.1 2007/09/05 22:52:16 squidadm Exp $
+#  $Id: Makefile.am,v 1.1.4.1 2007/11/27 08:12:20 adri Exp $
 #
 #  Uncomment and customize the following to suit your needs:
 #
@@ -11,8 +11,8 @@
 EXTRA_DIST		= squid_radius_auth.8
 squid_radius_auth_SOURCES = \
 			squid_rad_auth.c \
-			md5.c md5.h \
 			radius.h \
 			util.c util.h
 
-LDADD = $(XTRA_LIBS)
+LDADD			= -L$(top_builddir)/lib -lmiscutil $(SSLLIB) $(XTRA_LIBS)
+INCLUDES		= -I$(top_srcdir)/include
--- squid/helpers/basic_auth/squid_radius_auth/md5.c	Wed Nov 28 01:20:24 2007
+++ /dev/null	Wed Nov 28 01:20:24 2007
@@ -1,333 +0,0 @@
-/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
- */
-
-/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
-rights reserved.
-
-License to copy and use this software is granted provided that it
-is identified as the "RSA Data Security, Inc. MD5 Message-Digest
-Algorithm" in all material mentioning or referencing this software
-or this function.
-
-License is also granted to make and use derivative works provided
-that such works are identified as "derived from the RSA Data
-Security, Inc. MD5 Message-Digest Algorithm" in all material
-mentioning or referencing the derived work.
-
-RSA Data Security, Inc. makes no representations concerning either
-the merchantability of this software or the suitability of this
-software for any particular purpose. It is provided "as is"
-without express or implied warranty of any kind.
-
-These notices must be retained in any copies of any part of this
-documentation and/or software.
- */
-
-#include "md5.h"
-
-/* Constants for MD5Transform routine.
- */
-#define S11 7
-#define S12 12
-#define S13 17
-#define S14 22
-#define S21 5
-#define S22 9
-#define S23 14
-#define S24 20
-#define S31 4
-#define S32 11
-#define S33 16
-#define S34 23
-#define S41 6
-#define S42 10
-#define S43 15
-#define S44 21
-
-static void MD5Transform PROTO_LIST ((UINT4 [4], unsigned char [64]));
-static void Encode PROTO_LIST
-  ((unsigned char *, UINT4 *, unsigned int));
-static void Decode PROTO_LIST
-  ((UINT4 *, unsigned char *, unsigned int));
-static void MD5_memcpy PROTO_LIST ((POINTER, POINTER, unsigned int));
-static void MD5_memset PROTO_LIST ((POINTER, int, unsigned int));
-
-static unsigned char PADDING[64] = {
-  0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
-};
-
-/* F, G, H and I are basic MD5 functions.
- */
-#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
-#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
-#define H(x, y, z) ((x) ^ (y) ^ (z))
-#define I(x, y, z) ((y) ^ ((x) | (~z)))
-
-/* ROTATE_LEFT rotates x left n bits.
- */
-#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
-
-/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
-Rotation is separate from addition to prevent recomputation.
- */
-#define FF(a, b, c, d, x, s, ac) { \
- (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
- (a) = ROTATE_LEFT ((a), (s)); \
- (a) += (b); \
-  }
-#define GG(a, b, c, d, x, s, ac) { \
- (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
- (a) = ROTATE_LEFT ((a), (s)); \
- (a) += (b); \
-  }
-#define HH(a, b, c, d, x, s, ac) { \
- (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
- (a) = ROTATE_LEFT ((a), (s)); \
- (a) += (b); \
-  }
-#define II(a, b, c, d, x, s, ac) { \
- (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
- (a) = ROTATE_LEFT ((a), (s)); \
- (a) += (b); \
-  }
-
-/* MD5 initialization. Begins an MD5 operation, writing a new context.
- */
-void MD5Init (context)
-MD5_CTX *context;                                        /* context */
-{
-  context->count[0] = context->count[1] = 0;
-  /* Load magic initialization constants.
-*/
-  context->state[0] = 0x67452301;
-  context->state[1] = 0xefcdab89;
-  context->state[2] = 0x98badcfe;
-  context->state[3] = 0x10325476;
-}
-
-/* MD5 block update operation. Continues an MD5 message-digest
-  operation, processing another message block, and updating the
-  context.
- */
-void MD5Update (context, input, inputLen)
-MD5_CTX *context;                                        /* context */
-unsigned char *input;                                /* input block */
-unsigned int inputLen;                     /* length of input block */
-{
-  unsigned int i, index, partLen;
-
-  /* Compute number of bytes mod 64 */
-  index = (unsigned int)((context->count[0] >> 3) & 0x3F);
-
-  /* Update number of bits */
-  if ((context->count[0] += ((UINT4)inputLen << 3))
-   < ((UINT4)inputLen << 3))
- context->count[1]++;
-  context->count[1] += ((UINT4)inputLen >> 29);
-
-  partLen = 64 - index;
-
-  /* Transform as many times as possible.
-*/
-  if (inputLen >= partLen) {
- MD5_memcpy
-   ((POINTER)&context->buffer[index], (POINTER)input, partLen);
- MD5Transform (context->state, context->buffer);
-
- for (i = partLen; i + 63 < inputLen; i += 64)
-   MD5Transform (context->state, &input[i]);
-
- index = 0;
-  }
-  else
- i = 0;
-
-  /* Buffer remaining input */
-  MD5_memcpy
- ((POINTER)&context->buffer[index], (POINTER)&input[i],
-  inputLen-i);
-}
-
-/* MD5 finalization. Ends an MD5 message-digest operation, writing the
-  the message digest and zeroizing the context.
- */
-void MD5Final (digest, context)
-unsigned char digest[16];                         /* message digest */
-MD5_CTX *context;                                       /* context */
-{
-  unsigned char bits[8];
-  unsigned int index, padLen;
-
-  /* Save number of bits */
-  Encode (bits, context->count, 8);
-
-  /* Pad out to 56 mod 64.
-*/
-  index = (unsigned int)((context->count[0] >> 3) & 0x3f);
-  padLen = (index < 56) ? (56 - index) : (120 - index);
-  MD5Update (context, PADDING, padLen);
-
-  /* Append length (before padding) */
-  MD5Update (context, bits, 8);
-
-  /* Store state in digest */
-  Encode (digest, context->state, 16);
-
-  /* Zeroize sensitive information.
-*/
-  MD5_memset ((POINTER)context, 0, sizeof (*context));
-}
-
-/* MD5 basic transformation. Transforms state based on block.
- */
-static void MD5Transform (state, block)
-UINT4 state[4];
-unsigned char block[64];
-{
-  UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
-
-  Decode (x, block, 64);
-
-  /* Round 1 */
-  FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
-  FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
-  FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
-  FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
-  FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
-  FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
-  FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
-  FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
-  FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
-  FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
-  FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
-  FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
-  FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
-  FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
-  FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
-  FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
-
- /* Round 2 */
-  GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
-  GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
-  GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
-  GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
-  GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
-  GG (d, a, b, c, x[10], S22,  0x2441453); /* 22 */
-  GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
-  GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
-  GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
-  GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
-  GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
-  GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
-  GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
-  GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
-  GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
-  GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
-
-  /* Round 3 */
-  HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
-  HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
-  HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
-  HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
-  HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
-  HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
-  HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
-  HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
-  HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
-  HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
-  HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
-  HH (b, c, d, a, x[ 6], S34,  0x4881d05); /* 44 */
-  HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
-  HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
-  HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
-  HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
-
-  /* Round 4 */
-  II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
-  II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
-  II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
-  II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
-  II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
-  II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
-  II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
-  II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
-  II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
-  II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
-  II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
-  II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
-  II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
-  II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
-  II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
-  II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
-
-  state[0] += a;
-  state[1] += b;
-  state[2] += c;
-  state[3] += d;
-
-  /* Zeroize sensitive information.
-*/
-  MD5_memset ((POINTER)x, 0, sizeof (x));
-}
-
-/* Encodes input (UINT4) into output (unsigned char). Assumes len is
-  a multiple of 4.
- */
-static void Encode (output, input, len)
-unsigned char *output;
-UINT4 *input;
-unsigned int len;
-{
-  unsigned int i, j;
-
-  for (i = 0, j = 0; j < len; i++, j += 4) {
- output[j] = (unsigned char)(input[i] & 0xff);
- output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
- output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
- output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
-  }
-}
-
-/* Decodes input (unsigned char) into output (UINT4). Assumes len is
-  a multiple of 4.
- */
-static void Decode (output, input, len)
-UINT4 *output;
-unsigned char *input;
-unsigned int len;
-{
-  unsigned int i, j;
-
-  for (i = 0, j = 0; j < len; i++, j += 4)
- output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
-   (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
-}
-
-/* Note: Replace "for loop" with standard memcpy if possible.
- */
-
-static void MD5_memcpy (output, input, len)
-POINTER output;
-POINTER input;
-unsigned int len;
-{
-  unsigned int i;
-
-  for (i = 0; i < len; i++)
- output[i] = input[i];
-}
-
-/* Note: Replace "for loop" with standard memset if possible.
- */
-static void MD5_memset (output, value, len)
-POINTER output;
-int value;
-unsigned int len;
-{
-  unsigned int i;
-
-  for (i = 0; i < len; i++)
- ((char *)output)[i] = (char)value;
-}
--- squid/helpers/basic_auth/squid_radius_auth/md5.h	Wed Nov 28 01:20:24 2007
+++ /dev/null	Wed Nov 28 01:20:24 2007
@@ -1,77 +0,0 @@
-/* GLOBAL.H - RSAREF types and constants
- */
-
-/* PROTOTYPES should be set to one if and only if the compiler supports
-  function argument prototyping.
-  The following makes PROTOTYPES default to 0 if it has not already
-  been defined with C compiler flags.
- */
-#ifndef PROTOTYPES
-#  if __STDC__
-#    define PROTOTYPES 1
-#  else
-#    define PROTOTYPES 0
-#  endif
-#endif
-
-/* POINTER defines a generic pointer type */
-typedef unsigned char *POINTER;
-
-/* UINT2 defines a two byte word */
-typedef unsigned short int UINT2;
-
-/* UINT4 defines a four byte word */
-#if defined(__alpha) && (defined(__osf__) || defined(__linux__))
-typedef unsigned int UINT4;
-#else
-typedef unsigned long int UINT4;
-#endif
-
-/* PROTO_LIST is defined depending on how PROTOTYPES is defined above.
-   If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it
-  returns an empty list.
- */
-#if PROTOTYPES
-#define PROTO_LIST(list) list
-#else
-#define PROTO_LIST(list) ()
-#endif
-
-/* MD5.H - header file for MD5C.C
- */
-
-/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
-rights reserved.
-
-License to copy and use this software is granted provided that it
-is identified as the "RSA Data Security, Inc. MD5 Message-Digest
-Algorithm" in all material mentioning or referencing this software
-or this function.
-
-License is also granted to make and use derivative works provided
-that such works are identified as "derived from the RSA Data
-Security, Inc. MD5 Message-Digest Algorithm" in all material
-mentioning or referencing the derived work.
-
-RSA Data Security, Inc. makes no representations concerning either
-the merchantability of this software or the suitability of this
-software for any particular purpose. It is provided "as is"
-without express or implied warranty of any kind.
-
-These notices must be retained in any copies of any part of this
-documentation and/or software.
- */
-
-/* MD5 context. */
-typedef struct {
-  UINT4 state[4];                                   /* state (ABCD) */
-  UINT4 count[2];        /* number of bits, modulo 2^64 (lsb first) */
-  unsigned char buffer[64];                         /* input buffer */
-} MD5_CTX;
-
-void MD5Init PROTO_LIST ((MD5_CTX *));
-void MD5Update PROTO_LIST
-  ((MD5_CTX *, unsigned char *, unsigned int));
-void MD5Final PROTO_LIST ((unsigned char [16], MD5_CTX *));
-void md5_calc PROTO_LIST ((unsigned char *output, unsigned char *input, unsigned int inlen));
-
Index: squid/helpers/basic_auth/squid_radius_auth/squid_rad_auth.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/helpers/basic_auth/squid_radius_auth/squid_rad_auth.c,v
retrieving revision 1.1
retrieving revision 1.1.4.1
diff -u -r1.1 -r1.1.4.1
--- squid/helpers/basic_auth/squid_radius_auth/squid_rad_auth.c	5 Sep 2007 22:52:16 -0000	1.1
+++ squid/helpers/basic_auth/squid_radius_auth/squid_rad_auth.c	27 Nov 2007 08:12:20 -0000	1.1.4.1
@@ -45,21 +45,51 @@
  * and many others
  */
 
+#include	"config.h"
+
+#if HAVE_SYS_TYPES_H
 #include	<sys/types.h>
+#endif
+#if HAVE_SYS_SOCKET_H
 #include	<sys/socket.h>
+#endif
+#if HAVE_NETINET_IN_H
 #include	<netinet/in.h>
+#endif
+#if HAVE_SYS_TIME_H
 #include	<sys/time.h>
+#endif
+#if HAVE_UNISTD_H
 #include	<unistd.h>
+#endif
+#if HAVE_FCNTL_H
 #include	<fcntl.h>
+#endif
 
+#if HAVE_CTYPE_H
 #include	<ctype.h>
+#endif
+#if HAVE_STDIO_H
 #include	<stdio.h>
+#endif
+#if HAVE_UNISTD_H
 #include	<unistd.h>
+#endif
+#if HAVE_NETDB_H
 #include	<netdb.h>
+#endif
+#if HAVE_PWD_H
 #include	<pwd.h>
+#endif
+#if HAVE_STDLIB_H
 #include	<stdlib.h>
+#endif
+#if HAVE_TIME_H
 #include	<time.h>
+#endif
+#if HAVE_STRING_H
 #include	<string.h>
+#endif
 
 #include	"md5.h"
 #include	"radius.h"
@@ -83,8 +113,8 @@
 static char svc_name[MAXLINE] = "radius";
 static int nasport = 111;
 static int nasporttype = 0;
-static UINT4 nas_ipaddr;
-static UINT4 auth_ipaddr;
+static u_int32_t nas_ipaddr;
+static u_int32_t auth_ipaddr;
 static int retries = 30;
 
 char *progname = "squid_rad_auth";
@@ -111,10 +141,22 @@
 }
 
 /*
+ *     MD5 digest
+ */
+static void
+md5_calc(uint8_t out[16], void *in, size_t len)
+{
+    MD5_CTX ctx;
+    MD5Init(&ctx);
+    MD5Update(&ctx, in, len);
+    MD5Final(out, &ctx);
+}
+
+/*
  *    Receive and verify the result.
  */
 static int
-result_recv(UINT4 host, u_short udp_port, char *buffer, int length)
+result_recv(u_int32_t host, u_short udp_port, char *buffer, int length)
 {
     AUTH_HDR *auth;
     int totallen;
@@ -241,7 +283,7 @@
     int secretlen;
     u_char cbc[AUTH_VECTOR_LEN];
     int i, j;
-    UINT4 ui;
+    u_int32_t ui;
     struct sockaddr_in saremote;
     fd_set readfds;
     socklen_t salen;
Index: squid/helpers/basic_auth/squid_radius_auth/util.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/helpers/basic_auth/squid_radius_auth/util.c,v
retrieving revision 1.1
retrieving revision 1.1.4.1
diff -u -r1.1 -r1.1.4.1
--- squid/helpers/basic_auth/squid_radius_auth/util.c	5 Sep 2007 22:52:16 -0000	1.1
+++ squid/helpers/basic_auth/squid_radius_auth/util.c	27 Nov 2007 08:12:20 -0000	1.1.4.1
@@ -35,18 +35,42 @@
 "@(#)util.c	1.5 Copyright 1992 Livingston Enterprises Inc\n"
 "		2.1 Copyright 1997 Cistron Internet Services B.V.";
 
+#include	"config.h"
+
+#if HAVE_SYS_TYES_H
 #include	<sys/types.h>
+#endif
+#if HAVE_SYS_SOCKET_H
 #include	<sys/socket.h>
+#endif
+#if HAVE_SYS_TIME_H
 #include	<sys/time.h>
+#endif
+#if HAVE_NETINET_IN_H
 #include	<netinet/in.h>
+#endif
 
+#if HAVE_STDIO_H
 #include	<stdio.h>
+#endif
+#if HAVE_STDLIB_H
 #include	<stdlib.h>
+#endif
+#if HAVE_NETDB_H
 #include	<netdb.h>
+#endif
+#if HAVE_PWD_H
 #include	<pwd.h>
+#endif
+#if HAVE_TIME_H
 #include	<time.h>
+#endif
+#if HAVE_CTYPE_H
 #include	<ctype.h>
+#endif
+#if HAVE_SIGNAL_H
 #include	<signal.h>
+#endif
 
 #include	"md5.h"
 #include	"util.h"
@@ -89,37 +113,37 @@
  *	Return an IP address in host long notation from
  *	one supplied in standard dot notation.
  */
-static UINT4 ipstr2long(char *ip_str)
+static u_int32_t ipstr2long(char *ip_str)
 {
 	char	buf[6];
 	char	*ptr;
 	int	i;
 	int	count;
-	UINT4	ipaddr;
+	u_int32_t	ipaddr;
 	int	cur_byte;
 
-	ipaddr = (UINT4)0;
+	ipaddr = (u_int32_t)0;
 	for(i = 0;i < 4;i++) {
 		ptr = buf;
 		count = 0;
 		*ptr = '\0';
 		while(*ip_str != '.' && *ip_str != '\0' && count < 4) {
 			if(!isdigit(*ip_str)) {
-				return((UINT4)0);
+				return((u_int32_t)0);
 			}
 			*ptr++ = *ip_str++;
 			count++;
 		}
 		if(count >= 4 || count == 0) {
-			return((UINT4)0);
+			return((u_int32_t)0);
 		}
 		*ptr = '\0';
 		cur_byte = atoi(buf);
 		if(cur_byte < 0 || cur_byte > 255) {
-			return((UINT4)0);
+			return((u_int32_t)0);
 		}
 		ip_str++;
-		ipaddr = ipaddr << 8 | (UINT4)cur_byte;
+		ipaddr = ipaddr << 8 | (u_int32_t)cur_byte;
 	}
 	return(ipaddr);
 }
@@ -128,7 +152,7 @@
  *	Return an IP address in host long notation from a host
  *	name or address in dot notation.
  */
-UINT4 get_ipaddr(char *host)
+u_int32_t get_ipaddr(char *host)
 {
 	struct hostent	*hp;
 
@@ -136,9 +160,9 @@
 		return(ipstr2long(host));
 	}
 	else if((hp = gethostbyname(host)) == (struct hostent *)NULL) {
-		return((UINT4)0);
+		return((u_int32_t)0);
 	}
-	return(ntohl(*(UINT4 *)hp->h_addr));
+	return(ntohl(*(u_int32_t *)hp->h_addr));
 }
 
 
Index: squid/helpers/basic_auth/squid_radius_auth/util.h
===================================================================
RCS file: /cvsroot/squid-sf//squid/helpers/basic_auth/squid_radius_auth/util.h,v
retrieving revision 1.1
retrieving revision 1.1.4.1
diff -u -r1.1 -r1.1.4.1
--- squid/helpers/basic_auth/squid_radius_auth/util.h	5 Sep 2007 22:52:16 -0000	1.1
+++ squid/helpers/basic_auth/squid_radius_auth/util.h	27 Nov 2007 08:12:20 -0000	1.1.4.1
@@ -1,2 +1,2 @@
 /* util.c */
-UINT4		get_ipaddr (char *);
+u_int32_t		get_ipaddr (char *);
Index: squid/include/Array.h
===================================================================
RCS file: /cvsroot/squid-sf//squid/include/Array.h,v
retrieving revision 1.7
retrieving revision 1.7.52.1
diff -u -r1.7 -r1.7.52.1
--- squid/include/Array.h	28 Apr 2006 11:10:49 -0000	1.7
+++ squid/include/Array.h	27 Nov 2007 08:12:20 -0000	1.7.52.1
@@ -1,5 +1,5 @@
 /*
- * $Id: Array.h,v 1.7 2006/04/28 11:10:49 squidadm Exp $
+ * $Id: Array.h,v 1.7.52.1 2007/11/27 08:12:20 adri Exp $
  *
  * AUTHOR: Alex Rousskov
  *
@@ -50,6 +50,8 @@
 extern void arrayAppend(Array * s, void *obj);
 extern void arrayInsert(Array * s, void *obj, int position);
 extern void arrayPreAppend(Array * s, int app_count);
+extern void arrayShrink(Array *a, int new_count);
+
 
 
 #endif /* SQUID_ARRAY_H */
Index: squid/include/md5.h
===================================================================
RCS file: /cvsroot/squid-sf//squid/include/md5.h,v
retrieving revision 1.12
retrieving revision 1.12.34.1
diff -u -r1.12 -r1.12.34.1
--- squid/include/md5.h	29 May 2006 00:14:40 -0000	1.12
+++ squid/include/md5.h	27 Nov 2007 08:12:20 -0000	1.12.34.1
@@ -1,18 +1,18 @@
 #ifndef SQUID_MD5_H
 #define SQUID_MD5_H
 
-#if USE_OPENSSL
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
 
 /*
  * If Squid is compiled with OpenSSL then we use the MD5 routines
  * from there via some wrapper macros, and the rest of this file is ignored..
  */
+#define USE_SQUID_MD5 0
 
-#if HAVE_OPENSSL_MD5_H
+#if USE_OPENSSL && HAVE_OPENSSL_MD5_H
 #include <openssl/md5.h>
-#else
-#error Cannot find OpenSSL headers
-#endif
 
 /* Hack to adopt Squid to the OpenSSL syntax */
 #define MD5_DIGEST_CHARS MD5_DIGEST_LENGTH
@@ -21,7 +21,28 @@
 #define MD5Update MD5_Update
 #define MD5Final MD5_Final
 
-#else /* USE_OPENSSL */
+#elif USE_OPENSSL && !HAVE_OPENSSL_MD5_H
+#error Cannot find OpenSSL MD5 headers
+
+#elif HAVE_SYS_MD5_H
+/*
+ * Solaris 10 provides MD5 as part of the system.
+ */
+#include <sys/md5.h>
+
+/*
+ * They also define MD5_CTX with different field names
+ * fortunately we do not access it directly in the squid code.
+ */
+
+/* Hack to adopt Squid to the OpenSSL syntax */
+#define MD5_DIGEST_CHARS MD5_DIGEST_LENGTH
+
+#else /* NEED_OWN_MD5 */
+
+ /* Turn on internal MD5 code */
+#undef  USE_SQUID_MD5
+#define USE_SQUID_MD5 1
 
 /*
  * This is the header file for the MD5 message-digest algorithm.
Index: squid/lib/Array.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/lib/Array.c,v
retrieving revision 1.6
retrieving revision 1.6.52.1
diff -u -r1.6 -r1.6.52.1
--- squid/lib/Array.c	28 Apr 2006 11:10:49 -0000	1.6
+++ squid/lib/Array.c	27 Nov 2007 08:12:20 -0000	1.6.52.1
@@ -1,5 +1,5 @@
 /*
- * $Id: Array.c,v 1.6 2006/04/28 11:10:49 squidadm Exp $
+ * $Id: Array.c,v 1.6.52.1 2007/11/27 08:12:20 adri Exp $
  *
  * AUTHOR: Alex Rousskov
  *
@@ -138,3 +138,11 @@
     /* reset, just in case */
     memset(a->items + a->count, 0, (a->capacity - a->count) * sizeof(void *));
 }
+
+void
+arrayShrink(Array *a, int new_count)
+{
+	assert(new_count < a->capacity);
+	assert(new_count >= 0);
+	a->count = new_count;
+}
Index: squid/lib/Makefile.am
===================================================================
RCS file: /cvsroot/squid-sf//squid/lib/Makefile.am,v
retrieving revision 1.10
retrieving revision 1.10.18.1
diff -u -r1.10 -r1.10.18.1
--- squid/lib/Makefile.am	8 Sep 2006 19:50:55 -0000	1.10
+++ squid/lib/Makefile.am	27 Nov 2007 08:12:20 -0000	1.10.18.1
@@ -13,11 +13,6 @@
 else
 STRSEPSOURCE=
 endif
-if NEED_OWN_MD5
-MD5SOURCE=md5.c
-else
-MD5SOURCE=
-endif
 if ENABLE_WIN32SPECIFIC
 LIBSSPWIN32=libsspwin32.a
 else
@@ -41,7 +36,6 @@
 	@LIBREGEX@ \
 	$(LIBSSPWIN32)
 EXTRA_libmiscutil_a_SOURCES = \
-	md5.c \
 	snprintf.c \
 	strsep.c \
 	win32lib.c
@@ -53,7 +47,7 @@
 	heap.c \
 	html_quote.c \
 	iso3307.c \
-	$(MD5SOURCE) \
+	md5.c \
 	radix.c \
 	rfc1035.c \
 	rfc1123.c \
Index: squid/lib/md5.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/lib/md5.c,v
retrieving revision 1.12
retrieving revision 1.12.30.1
diff -u -r1.12 -r1.12.30.1
--- squid/lib/md5.c	31 May 2006 11:51:11 -0000	1.12
+++ squid/lib/md5.c	27 Nov 2007 08:12:21 -0000	1.12.30.1
@@ -26,11 +26,16 @@
  */
 #include "config.h"
 
-/* MS VisualStudio Projects are monolithic, so we need the following
- * #if to exclude the MD5 code from compile process when we are
- * building the SSL support.
+#include "md5.h"
+
+/*
+ * Now that we have several alternatives the MD5 files are
+ * passed in by default. But a header-selection decides whether
+ * this provided version is to be built.
+ * TODO: may obsolete the MSV #if below.
  */
-#if !USE_SSL
+#if USE_SQUID_MD5
+
 #if HAVE_STRING_H
 #include <string.h>		/* for memcpy() */
 #endif
@@ -41,8 +46,6 @@
 #include <netinet/in.h>		/* for ntohl() */
 #endif
 
-#include "md5.h"
-
 #ifdef WORDS_BIGENDIAN
 void
 byteSwap(uint32_t * buf, unsigned words)
@@ -255,5 +258,5 @@
     buf[3] += d;
 }
 
-#endif
-#endif
+#endif /* !ASM_MD5 */
+#endif /* !USE_SQUID_MD5 */
Index: squid/src/HttpHeader.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/HttpHeader.c,v
retrieving revision 1.28
retrieving revision 1.28.6.1
diff -u -r1.28 -r1.28.6.1
--- squid/src/HttpHeader.c	11 Apr 2007 22:52:54 -0000	1.28
+++ squid/src/HttpHeader.c	27 Nov 2007 08:12:23 -0000	1.28.6.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: HttpHeader.c,v 1.28 2007/04/11 22:52:54 squidadm Exp $
+ * $Id: HttpHeader.c,v 1.28.6.1 2007/11/27 08:12:23 adri Exp $
  *
  * DEBUG: section 55    HTTP Header
  * AUTHOR: Alex Rousskov
@@ -381,12 +381,34 @@
     }
 }
 
+static void
+httpHeaderRepack(HttpHeader * hdr)
+{
+    HttpHeaderPos dp = HttpHeaderInitPos;
+    HttpHeaderPos pos = HttpHeaderInitPos;
+
+    /* XXX breaks layering for now! ie, getting grubby fingers in without httpHeaderEntryGet() */
+    dp = 0;
+    pos = 0;
+    while (dp < hdr->entries.count) {
+	for (; dp < hdr->entries.count && hdr->entries.items[dp] == NULL; dp++);
+	assert(dp < hdr->entries.count);
+	hdr->entries.items[pos] = hdr->entries.items[dp];
+	if (dp != pos)
+	    hdr->entries.items[dp] = NULL;
+	pos++;
+	dp++;
+    }
+    arrayShrink(&hdr->entries, pos);
+}
+
 /* use fresh entries to replace old ones */
 void
 httpHeaderUpdate(HttpHeader * old, const HttpHeader * fresh, const HttpHeaderMask * denied_mask)
 {
     const HttpHeaderEntry *e;
     HttpHeaderPos pos = HttpHeaderInitPos;
+
     assert(old && fresh);
     assert(old != fresh);
     debug(55, 7) ("updating hdr: %p <- %p\n", old, fresh);
@@ -399,8 +421,17 @@
 	    httpHeaderDelById(old, e->id);
 	else
 	    httpHeaderDelByName(old, strBuf(e->name));
+    }
+    pos = HttpHeaderInitPos;
+    while ((e = httpHeaderGetEntry(fresh, &pos))) {
+	/* deny bad guys (ok to check for HDR_OTHER) here */
+	if (denied_mask && CBIT_TEST(*denied_mask, e->id))
+	    continue;
 	httpHeaderAddClone(old, e);
     }
+
+    /* And now, repack the array to "fill in the holes" */
+    httpHeaderRepack(old);
 }
 
 /* just handy in parsing: resets and returns false */
Index: squid/src/HttpReply.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/HttpReply.c,v
retrieving revision 1.23
retrieving revision 1.23.6.1
diff -u -r1.23 -r1.23.6.1
--- squid/src/HttpReply.c	2 Jun 2007 19:52:18 -0000	1.23
+++ squid/src/HttpReply.c	27 Nov 2007 08:12:23 -0000	1.23.6.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: HttpReply.c,v 1.23 2007/06/02 19:52:18 squidadm Exp $
+ * $Id: HttpReply.c,v 1.23.6.1 2007/11/27 08:12:23 adri Exp $
  *
  * DEBUG: section 58    HTTP Reply (Response)
  * AUTHOR: Alex Rousskov
@@ -42,9 +42,8 @@
 static HttpHeaderMask Denied304HeadersMask;
 static http_hdr_type Denied304HeadersArr[] =
 {
-    HDR_ALLOW, HDR_CONTENT_ENCODING, HDR_CONTENT_LANGUAGE, HDR_CONTENT_LENGTH,
-    HDR_CONTENT_LOCATION, HDR_CONTENT_RANGE, HDR_LAST_MODIFIED, HDR_LINK,
-    HDR_OTHER
+    HDR_CONTENT_ENCODING, HDR_CONTENT_LANGUAGE, HDR_CONTENT_LENGTH,
+    HDR_CONTENT_LOCATION, HDR_CONTENT_RANGE
 };
 
 /* local routines */
@@ -274,6 +273,7 @@
     /* clean cache */
     httpReplyHdrCacheClean(rep);
     /* update raw headers */
+    httpHeaderDelById(&rep->header, HDR_AGE);
     httpHeaderUpdate(&rep->header, &freshRep->header,
 	(const HttpHeaderMask *) &Denied304HeadersMask);
     /* init cache */
Index: squid/src/HttpRequest.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/HttpRequest.c,v
retrieving revision 1.17
retrieving revision 1.17.10.1
diff -u -r1.17 -r1.17.10.1
--- squid/src/HttpRequest.c	21 Jan 2007 14:03:34 -0000	1.17
+++ squid/src/HttpRequest.c	27 Nov 2007 08:12:24 -0000	1.17.10.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: HttpRequest.c,v 1.17 2007/01/21 14:03:34 squidadm Exp $
+ * $Id: HttpRequest.c,v 1.17.10.1 2007/11/27 08:12:24 adri Exp $
  *
  * DEBUG: section 73    HTTP Request
  * AUTHOR: Duane Wessels
@@ -59,6 +59,7 @@
 	requestAbortBody(req);
     if (req->auth_user_request)
 	authenticateAuthUserRequestUnlock(req->auth_user_request);
+    safe_free(req->store_url);
     safe_free(req->canonical);
     safe_free(req->vary_hdr);
     safe_free(req->vary_headers);
Index: squid/src/Makefile.am
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/Makefile.am,v
retrieving revision 1.54
retrieving revision 1.54.2.1
diff -u -r1.54 -r1.54.2.1
--- squid/src/Makefile.am	23 Sep 2007 14:51:42 -0000	1.54
+++ squid/src/Makefile.am	27 Nov 2007 08:12:24 -0000	1.54.2.1
@@ -156,6 +156,8 @@
 	cbdata.c \
 	client_db.c \
 	client_side.c \
+	client_side_rewrite.c \
+	client_side_storeurl_rewrite.c \
 	comm.c \
 	$(COMMLOOP_SOURCE) \
 	debug.c \
@@ -223,8 +225,10 @@
 	peer_userhash.c \
 	protos.h \
 	redirect.c \
+	store_rewrite.c \
 	referer.c \
 	refresh.c \
+	refresh_check.c \
 	send-announce.c \
 	$(SNMPSOURCE) \
 	squid.h \
@@ -245,6 +249,7 @@
 	store_swapin.c \
 	store_swapmeta.c \
 	store_swapout.c \
+	store_update.c \
 	structs.h \
 	tools.c \
 	typedefs.h \
Index: squid/src/access_log.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/access_log.c,v
retrieving revision 1.43
retrieving revision 1.43.2.1
diff -u -r1.43 -r1.43.2.1
--- squid/src/access_log.c	23 Sep 2007 14:51:42 -0000	1.43
+++ squid/src/access_log.c	27 Nov 2007 08:12:24 -0000	1.43.2.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: access_log.c,v 1.43 2007/09/23 14:51:42 squidadm Exp $
+ * $Id: access_log.c,v 1.43.2.1 2007/11/27 08:12:24 adri Exp $
  *
  * DEBUG: section 46    Access Log
  * AUTHOR: Duane Wessels
@@ -320,6 +320,8 @@
 
     LFT_SEQUENCE_NUMBER,
 
+    LFT_EXT_FRESHNESS,
+
     LFT_PERCENT			/* special string cases for escaped chars */
 } logformat_bcode_t;
 
@@ -428,6 +430,8 @@
 
     {"ea", LFT_EXT_LOG},
 
+    {"ef", LFT_EXT_FRESHNESS},
+
     {"%", LFT_PERCENT},
 
     {NULL, LFT_NONE}		/* this must be last */
@@ -691,6 +695,12 @@
 	    doint = 1;
 	    break;
 
+	case LFT_EXT_FRESHNESS:
+	    out = al->ext_refresh;
+
+	    quote = 1;
+	    break;
+
 	case LFT_PERCENT:
 	    out = "%";
 	    break;
Index: squid/src/cache_cf.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/cache_cf.c,v
retrieving revision 1.102
retrieving revision 1.102.2.1
diff -u -r1.102 -r1.102.2.1
--- squid/src/cache_cf.c	23 Sep 2007 14:51:42 -0000	1.102
+++ squid/src/cache_cf.c	27 Nov 2007 08:12:24 -0000	1.102.2.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: cache_cf.c,v 1.102 2007/09/23 14:51:42 squidadm Exp $
+ * $Id: cache_cf.c,v 1.102.2.1 2007/11/27 08:12:24 adri Exp $
  *
  * DEBUG: section 3     Configuration File Parsing
  * AUTHOR: Harvest Derived
@@ -479,6 +479,7 @@
     requirePathnameExists("Error Directory", Config.errorDirectory);
     authenticateConfigure(&Config.authConfig);
     externalAclConfigure();
+    refreshCheckConfigure();
 #if HTTP_VIOLATIONS
     {
 	const refresh_t *R;
@@ -494,6 +495,12 @@
 	    debug(22, 1) ("WARNING: use of 'override-lastmod' in 'refresh_pattern' violates HTTP\n");
 	    break;
 	}
+	for (R = Config.Refresh; R; R = R->next) {
+	    if (R->stale_while_revalidate <= 0)
+		continue;
+	    debug(22, 1) ("WARNING: use of 'stale-while-revalidate' in 'refresh_pattern' violates HTTP\n");
+	    break;
+	}
     }
 #endif
 #if !HTTP_VIOLATIONS
@@ -1610,6 +1617,34 @@
     }
 }
 
+static u_short
+GetService(const char *proto)
+{
+    struct servent *port = NULL;
+    char *token = strtok(NULL, w_space);
+    if (token == NULL) {
+	self_destruct();
+	return -1;		/* NEVER REACHED */
+    }
+    port = getservbyname(token, proto);
+    if (port != NULL) {
+	return ntohs((u_short) port->s_port);
+    }
+    return xatos(token);
+}
+
+static u_short
+GetTcpService(void)
+{
+    return GetService("tcp");
+}
+
+static u_short
+GetUdpService(void)
+{
+    return GetService("udp");
+}
+
 static void
 parse_peer(peer ** head)
 {
@@ -1634,10 +1669,10 @@
 	p->options.no_digest = 1;
 	p->options.no_netdb_exchange = 1;
     }
-    p->http_port = GetShort();
+    p->http_port = GetTcpService();
     if (!p->http_port)
 	self_destruct();
-    p->icp.port = GetShort();
+    p->icp.port = GetUdpService();
     p->connection_auth = -1;	/* auto */
     while ((token = strtok(NULL, w_space))) {
 	if (!strcasecmp(token, "proxy-only")) {
@@ -2146,7 +2181,13 @@
 	    storeAppendPrintf(entry, " ignore-private");
 	if (head->flags.ignore_auth)
 	    storeAppendPrintf(entry, " ignore-auth");
+	if (head->stale_while_revalidate > 0)
+	    storeAppendPrintf(entry, " stale-while-revalidate=%d", head->stale_while_revalidate);
 #endif
+	if (head->max_stale >= 0)
+	    storeAppendPrintf(entry, " max-stale=%d", head->max_stale);
+	if (head->negative_ttl >= 0)
+	    storeAppendPrintf(entry, " negative-ttl=%d", head->negative_ttl);
 	storeAppendPrintf(entry, "\n");
 	head = head->next;
     }
@@ -2169,6 +2210,9 @@
     int ignore_private = 0;
     int ignore_auth = 0;
 #endif
+    int stale_while_revalidate = -1;
+    int max_stale = -1;
+    int negative_ttl = -1;
     int i;
     refresh_t *t;
     regex_t comp;
@@ -2213,10 +2257,18 @@
 	    ignore_reload = 1;
 	    refresh_nocache_hack = 1;
 	    /* tell client_side.c that this is used */
+	} else if (!strncmp(token, "stale-while-revalidate=", 23)) {
+	    stale_while_revalidate = atoi(token + 23);
 	} else
 #endif
+	if (!strncmp(token, "max-stale=", 10)) {
+	    max_stale = atoi(token + 10);
+	} else if (!strncmp(token, "negative-ttl=", 13)) {
+	    negative_ttl = atoi(token + 13);
+	} else {
 	    debug(22, 0) ("redreshAddToList: Unknown option '%s': %s\n",
 		pattern, token);
+	}
     }
     if ((errcode = regcomp(&comp, pattern, flags)) != 0) {
 	char errbuf[256];
@@ -2253,6 +2305,9 @@
     if (ignore_auth)
 	t->flags.ignore_auth = 1;
 #endif
+    t->stale_while_revalidate = stale_while_revalidate;
+    t->max_stale = max_stale;
+    t->negative_ttl = negative_ttl;
     t->next = NULL;
     while (*head)
 	head = &(*head)->next;
Index: squid/src/cf.data.depend
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/cf.data.depend,v
retrieving revision 1.1
retrieving revision 1.1.4.1
diff -u -r1.1 -r1.1.4.1
--- squid/src/cf.data.depend	5 Sep 2007 21:51:54 -0000	1.1
+++ squid/src/cf.data.depend	27 Nov 2007 08:12:24 -0000	1.1.4.1
@@ -52,3 +52,4 @@
 programline
 extension_method
 errormap
+refreshCheckHelper
Index: squid/src/cf.data.pre
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/cf.data.pre,v
retrieving revision 1.209
retrieving revision 1.209.2.1
diff -u -r1.209 -r1.209.2.1
--- squid/src/cf.data.pre	23 Sep 2007 14:51:43 -0000	1.209
+++ squid/src/cf.data.pre	27 Nov 2007 08:12:24 -0000	1.209.2.1
@@ -1,6 +1,6 @@
 
 #
-# $Id: cf.data.pre,v 1.209 2007/09/23 14:51:43 squidadm Exp $
+# $Id: cf.data.pre,v 1.209.2.1 2007/11/27 08:12:24 adri Exp $
 #
 # SQUID Web Proxy Cache          http://www.squid-cache.org/
 # ----------------------------------------------------------
@@ -626,10 +626,18 @@
 
 NOCOMMENT_START
 #Recommended minimum configuration:
-acl all src 0.0.0.0/0.0.0.0
+acl all src all
 acl manager proto cache_object
-acl localhost src 127.0.0.1/255.255.255.255
+acl localhost src 127.0.0.1/32
 acl to_localhost dst 127.0.0.0/8
+#
+# Example rule allowing access from your local networks.
+# Adapt to list your (internal) IP networks from where browsing
+# should be allowed
+acl localnet src 10.0.0.0/8	# RFC1918 possible internal network
+acl localnet src 172.16.0.0/12	# RFC1918 possible internal network
+acl localnet src 192.168.0.0/16	# RFC1918 possible internal network
+#
 acl SSL_ports port 443
 acl Safe_ports port 80		# http
 acl Safe_ports port 21		# ftp
@@ -686,11 +694,10 @@
 #
 # INSERT YOUR OWN RULE(S) HERE TO ALLOW ACCESS FROM YOUR CLIENTS
 
-# Example rule allowing access from your local networks. Adapt
-# to list your (internal) IP networks from where browsing should
-# be allowed
-#acl our_networks src 192.168.1.0/24 192.168.2.0/24
-#http_access allow our_networks
+# Example rule allowing access from your local networks.
+# Adapt localnet in the ACL section to list your (internal) IP networks
+# from where browsing should be allowed
+http_access allow localnet
 
 # And finally deny all other access to this proxy
 http_access deny all
@@ -740,8 +747,9 @@
 	See http_access for details
 
 NOCOMMENT_START
-#Allow ICP queries from everyone
-icp_access allow all
+#Allow ICP queries from local networks only
+icp_access allow localnet
+icp_access deny all
 NOCOMMENT_END
 DOC_END
 
@@ -759,8 +767,15 @@
 
 	See http_access for details
 
-#Allow HTCP queries from everyone
-htcp_access allow all
+	NOTE: The default if no htcp_access lines are present is to
+	deny all traffic. This default may cause problems with peers
+	using the htcp or htcp-oldsquid options.
+
+NOCOMMENT_START
+#Allow HTCP queries from local networks only
+htcp_access allow localnet
+htcp_access deny all
+NOCOMMENT_END
 DOC_END
 
 NAME: htcp_clr_access
@@ -1161,7 +1176,7 @@
 
 	acl normal_service_net src 10.0.0.0/255.255.255.0
 	acl good_service_net src 10.0.1.0/255.255.255.0
-	tcp_outgoing_tos 0x00 normal_service_net 0x00
+	tcp_outgoing_tos 0x00 normal_service_net
 	tcp_outgoing_tos 0x20 good_service_net
 
 	TOS/DSCP values really only have local significance - so you should
@@ -1515,8 +1530,12 @@
 		     use 'htcp' to send HTCP, instead of ICP, queries
 		     to the neighbor.  You probably also want to
 		     set the "icp port" to 4827 instead of 3130.
+		     You must also allow this Squid htcp_access and
+		     http_access in the peer Squid configuration.
 
 		     use 'htcp-oldsquid' to send HTCP to old Squid versions
+		     You must also allow this Squid htcp_access and
+		     http_access in the peer Squid configuration.
 
 		     'originserver' causes this parent peer to be contacted as
 		     a origin server. Meant to be used in accelerator setups.
@@ -2064,6 +2083,20 @@
 	numbers closer together.
 DOC_END
 
+NAME: update_headers
+IFDEF: HTTP_VIOLATIONS
+COMMENT: on|off
+TYPE: onoff
+DEFAULT: on
+LOC: Config.onoff.update_headers
+DOC_START
+	By default Squid updates stored HTTP headers when receiving
+	a 304 response. Set this to off if you want to disable this
+	for disk I/O performance reasons. Disabling this VIOLATES the
+	HTTP standard, and could make you liable for problems which it
+	causes.
+DOC_END
+
 COMMENT_START
  LOGFILE OPTIONS
  -----------------------------------------------------------------------------
@@ -2529,6 +2562,30 @@
  -----------------------------------------------------------------------------
 COMMENT_END
 
+NAME: storeurl_rewrite_program
+TYPE: programline
+LOC: Config.Program.store_rewrite.command
+DEFAULT: none
+DOC_START
+
+DOC_END
+
+NAME: storeurl_rewrite_children
+TYPE: int
+DEFAULT: 5
+LOC: Config.Program.store_rewrite.children
+DOC_START
+
+DOC_END
+
+NAME: storeurl_rewrite_concurrency
+TYPE: int
+DEFAULT: 0
+LOC: Config.Program.store_rewrite.concurrency
+DOC_START
+
+DOC_END
+
 NAME: url_rewrite_program redirect_program
 TYPE: programline
 LOC: Config.Program.url_rewrite.command
@@ -2539,7 +2596,13 @@
 
 	For each requested URL rewriter will receive on line with the format
 
-	URL <SP> client_ip "/" fqdn <SP> user <SP> method <SP> urlgroup <NL>
+	URL <SP> client_ip "/" fqdn <SP> user <SP> method <SP> urlgroup
+	 [<SP> kvpairs] <NL>
+
+	In the future, the rewriter interface will be extended with
+	key=value pairs ("kvpairs" shown above).  Rewriter programs
+	should be prepared to receive and possibly ignore additional
+	whitespace-separated tokens on each input line.
 
 	And the rewriter may return a rewritten URL. The other components of
 	the request line does not need to be returned (ignored if they are).
@@ -2550,7 +2613,7 @@
 
 	It can also return a "urlgroup" that can subsequently be matched
 	in cache_peer_access and similar ACL driven rules. An urlgroup is
-	returned by prefixing the returned url with "!urlgroup!"
+	returned by prefixing the returned URL with "!urlgroup!".
 
 	By default, a URL rewriter is not used.
 DOC_END
@@ -2574,6 +2637,12 @@
 	The number of requests each redirector helper can handle in
 	parallel. Defaults to 0 which indicates the redirector
 	is a old-style single threaded redirector.
+
+	When this directive is set to a value >= 1 then the protocol
+	used to communicate with the helper is modified to include
+	a request ID in front of the request/response. The request
+	ID from the request must be echoed back with the response
+	to that request.
 DOC_END
 
 NAME: url_rewrite_host_header redirect_rewrites_host_header
@@ -2599,6 +2668,14 @@
 	are sent.
 DOC_END
 
+NAME: storeurl_access
+TYPE: acl_access
+DEFAULT: none
+LOC: Config.accessList.storeurl_rewrite
+DOC_START
+
+DOC_END
+
 NAME: redirector_bypass
 TYPE: onoff
 LOC: Config.onoff.redirector_bypass
@@ -2692,6 +2769,16 @@
 NOCOMMENT_END
 DOC_END
 
+NAME: max_stale
+COMMENT: time-units
+TYPE: time_t
+LOC: Config.maxStale
+DEFAULT: 1 week
+DOC_START
+	This option puts an upper limit on how stale content Squid
+	will serve from the cache if cache validation fails.
+DOC_END
+
 NAME: refresh_pattern
 TYPE: refreshpattern
 LOC: Config.Refresh
@@ -2722,6 +2809,9 @@
 		 ignore-no-cache
 		 ignore-private
 		 ignore-auth
+		 stale-while-revalidate=NN
+		 max-stale=NN
+		 negative-ttl=NN
 
 		override-expire enforces min age even if the server
 		sent a Expires: header. Doing this VIOLATES the HTTP
@@ -2758,6 +2848,19 @@
 		Enabling this feature could make you liable for problems which
 		it causes.
 
+		stale-while-revalidate=NN makes Squid perform an asyncronous
+		cache validation if the object isn't more stale than NN.
+		Doing this VIOLATES the HTTP standard. Enabling this
+		feature could make you liable for problems which it
+		causes.
+
+		max-stale=NN provided a maximum staleness factor. Squid won't
+		serve objects more stale than this even if it failed to
+		validate the object.
+
+		negative-ttl=NN overrides the global negative_ttl parameter
+		selectively for URLs matching this pattern (in seconds).
+
 	Basically a cached object is:
 
 		FRESH if expires < now, else STALE
@@ -3232,6 +3335,69 @@
 	or response to be rejected.
 DOC_END
 
+NAME: external_refresh_check
+TYPE: refreshCheckHelper
+DEFAULT: none
+LOC: Config.Program.refresh_check
+DOC_START
+	This option defines an external helper for determining whether to
+	refresh a stale response. It will be called when Squid receives a
+	request for a cached response that is stale; the helper can either
+	confirm that the response is stale with a STALE response, or
+	extend the freshness of the response (thereby avoiding a refresh
+	check) with a FRESH response, along with a freshness=nnn keyword.
+
+	  external_refresh_check [options] FORMAT.. /path/to/helper [helper_args]
+
+	If present, helper_args will be passed to the helper on the command
+	line verbatim.
+
+	Options:
+
+	  children=n	Number of processes to spawn to service external
+			refresh checks (default 5).
+	  concurrency=n	Concurrency level per process. Only used with
+			helpers capable of processing more than one query
+			at a time.
+
+	When using the concurrency option, the protocol is changed by introducing
+	a query channel tag infront of the request/response. The query channel
+	tag is a number between 0 and concurrency−1.
+
+	FORMAT specifications:
+
+	  %CACHE_URI	The URI of the cached response
+	  %RES{Header}	HTTP response header value
+	  %AGE		The age of the cached response
+
+	The request sent to the helper consists of the data in the format
+	specification in the order specified.
+
+	The helper receives lines per the above format specification, and
+	returns lines starting with OK or ERR indicating the validity of
+	the request and optionally followed by additional keywords with
+	more details.  URL escaping is used to protect each value in both
+	requests and responses.
+
+	General result syntax:
+
+	  FRESH / STALE keyword=value ...
+
+	Defined keywords:
+
+	  freshness=nnn	The number of seconds to extend the freshness of
+			the response by.
+	  log=string	String to be logged in access.log. Available as
+			%ef in logformat specifications.
+	  res{Header}=value
+			Value to update response headers with. If already
+			present, the supplied value completely replaces
+			the cached value.
+
+	In the event of a helper−related error (e.g., overload), Squid
+	will always default to STALE.
+DOC_END
+
 COMMENT_START
  TIMEOUTS
  -----------------------------------------------------------------------------
@@ -3404,9 +3570,10 @@
 LOC: Config.EmailProgram
 DOC_START
 	Email program used to send mail if the cache dies.
-	The default is "mail". The specified program must complain
+	The default is "mail". The specified program must comply
 	with the standard Unix mail syntax:
-	mail_program recipient < mailfile
+	  mail-program recipient < mailfile
+
 	Optional command line options can be specified.
 DOC_END
 
@@ -3989,8 +4156,7 @@
 DEFAULT: on
 DOC_START
 	This controls whether the server will generate a Cache Digest
-	of its contents.  By default, Cache Digest generation is
-	enabled if Squid is compiled with USE_CACHE_DIGESTS defined.
+	of its contents.
 DOC_END
 
 NAME: digest_bits_per_entry
@@ -4011,7 +4177,7 @@
 LOC: Config.digest.rebuild_period
 DEFAULT: 1 hour
 DOC_START
-	This is the number of seconds between Cache Digest rebuilds.
+	This is the wait time between Cache Digest rebuilds.
 DOC_END
 
 NAME: digest_rewrite_period
@@ -4021,8 +4187,7 @@
 LOC: Config.digest.rewrite_period
 DEFAULT: 1 hour
 DOC_START
-	This is the number of seconds between Cache Digest writes to
-	disk.
+	This is the wait time between Cache Digest writes to disk.
 DOC_END
 
 NAME: digest_swapout_chunk_size
@@ -4155,31 +4320,46 @@
 TYPE: address
 LOC:Config.Addrs.udp_incoming
 DEFAULT: 0.0.0.0
-DOC_NONE
+DOC_START
+	udp_incoming_address	is used for UDP packets received from other
+				caches.
+
+	The default behavior is to not bind to any specific address.
+
+	Only change this if you want to have all UDP queries received on
+	a specific interface/address.
+
+	NOTE: udp_incoming_address is used by the ICP, HTCP, and DNS
+	modules. Altering it will affect all of them in the same manner.
+
+	see also; udp_outgoing_address
+
+	NOTE, udp_incoming_address and udp_outgoing_address can not
+	have the same value since they both use the same port.
+DOC_END
 
 NAME: udp_outgoing_address
 TYPE: address
 LOC: Config.Addrs.udp_outgoing
 DEFAULT: 255.255.255.255
 DOC_START
-	udp_incoming_address	is used for the ICP socket receiving packets
-				from other caches.
-	udp_outgoing_address	is used for ICP packets sent out to other
+	udp_outgoing_address	is used for UDP packets sent out to other
 				caches.
 
 	The default behavior is to not bind to any specific address.
 
-	A udp_incoming_address value of 0.0.0.0 indicates Squid
-	should listen for UDP messages on all available interfaces.
-
-	If udp_outgoing_address is set to 255.255.255.255 (the default)
-	it will use the same socket as udp_incoming_address. Only
-	change this if you want to have ICP queries sent using another
-	address than where this Squid listens for ICP queries from other
+	Instead it will use the same socket as udp_incoming_address.
+	Only change this if you want to have UDP queries sent using another
+	address than where this Squid listens for UDP queries from other
 	caches.
 
+	NOTE: udp_outgoing_address is used by the ICP, HTCP, and DNS
+	modules. Altering it will affect all of them in the same manner.
+
+	see also; udp_incoming_address
+
 	NOTE, udp_incoming_address and udp_outgoing_address can not
-	have the same value since they both use port 3130.
+	have the same value since they both use the same port.
 DOC_END
 
 NAME: icp_hit_stale
@@ -4580,6 +4760,18 @@
 	acts on cacheable requests.
 DOC_END
 
+NAME: ignore_ims_on_miss
+IFDEF: HTTP_VIOLATIONS
+COMMENT: on|off
+TYPE: onoff
+DEFAULT: off
+LOC: Config.onoff.ignore_ims_on_miss
+DOC_START
+	This options makes Squid ignore If-Modified-Since on
+	cache misses. This is useful while the cache is
+	mostly empty to more quickly have the cache populated.
+DOC_END
+
 NAME: always_direct
 TYPE: acl_access
 LOC: Config.accessList.AlwaysDirect
Index: squid/src/client_side.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/client_side.c,v
retrieving revision 1.202.2.6
retrieving revision 1.202.2.7
diff -u -r1.202.2.6 -r1.202.2.7
--- squid/src/client_side.c	29 Sep 2007 10:38:27 -0000	1.202.2.6
+++ squid/src/client_side.c	27 Nov 2007 08:12:25 -0000	1.202.2.7
@@ -1,6 +1,6 @@
 
 /*
- * $Id: client_side.c,v 1.202.2.6 2007/09/29 10:38:27 adri Exp $
+ * $Id: client_side.c,v 1.202.2.7 2007/11/27 08:12:25 adri Exp $
  *
  * DEBUG: section 33    Client-side Routines
  * AUTHOR: Duane Wessels
@@ -116,14 +116,14 @@
 static int clientGotNotEnough(clientHttpRequest *);
 static void checkFailureRatio(err_type, hier_code);
 static void clientProcessMiss(clientHttpRequest *);
+static void clientProcessHit(clientHttpRequest * http);
 static void clientBuildReplyHeader(clientHttpRequest * http, HttpReply * rep);
 static clientHttpRequest *parseHttpRequestAbort(ConnStateData * conn, const char *uri);
 static clientHttpRequest *parseHttpRequest(ConnStateData *, HttpMsgBuf *, method_t *, int *);
-static void clientRedirectStart(clientHttpRequest * http);
-static RH clientRedirectDone;
+
 static void clientCheckNoCache(clientHttpRequest *);
 static void clientCheckNoCacheDone(int answer, void *data);
-static STNCB clientHandleIMSReply;
+static STHCB clientHandleIMSReply;
 static int clientGetsOldEntry(StoreEntry * new, StoreEntry * old, request_t * request);
 #if USE_IDENT
 static IDCB clientIdentDone;
@@ -135,14 +135,15 @@
 #endif /* FOLLOW_X_FORWARDED_FOR */
 static int clientOnlyIfCached(clientHttpRequest * http);
 static STNCB clientSendMoreData;
-static STNCB clientSendMoreHeaderData;
-static STNCB clientCacheHit;
+static STHCB clientSendHeaders;
+static STHCB clientCacheHit;
 static void clientSetKeepaliveFlag(clientHttpRequest *);
 static void clientPackRangeHdr(const HttpReply * rep, const HttpHdrRangeSpec * spec, String boundary, MemBuf * mb);
 static void clientPackTermBound(String boundary, MemBuf * mb);
-static void clientInterpretRequestHeaders(clientHttpRequest *);
 static void clientProcessRequest(clientHttpRequest *);
-static void clientProcessExpired(void *data);
+static void clientProcessExpired(clientHttpRequest *);
+static void clientRefreshCheck(clientHttpRequest *);
+static REFRESHCHECK clientRefreshCheckDone;
 static void clientProcessOnlyIfCachedMiss(clientHttpRequest * http);
 static int clientCachable(clientHttpRequest * http);
 static int clientHierarchical(clientHttpRequest * http);
@@ -155,7 +156,6 @@
 static void clientEatRequestBody(clientHttpRequest *);
 static void clientAccessCheck(void *data);
 static void clientAccessCheckDone(int answer, void *data);
-static void clientAccessCheck2(void *data);
 static void clientAccessCheckDone2(int answer, void *data);
 static BODY_HANDLER clientReadBody;
 static void clientAbortBody(request_t * req);
@@ -167,6 +167,31 @@
 static StoreEntry *clientCreateStoreEntry(clientHttpRequest *, method_t, request_flags);
 static inline int clientNatLookup(ConnStateData * conn);
 
+/* Temporary here while restructuring stuff */
+static void
+storeClientCopyHeadersCB(void *data, char *buf, ssize_t size)
+{
+    clientHttpRequest *http = data;
+    assert(http->header_callback);
+    assert(http->header_entry);
+    memFree(buf, MEM_STORE_CLIENT_BUF);
+    if (!http->header_entry)
+	return;
+    if (size < 0 || !memHaveHeaders(http->header_entry->mem_obj)) {
+	http->header_callback(data, NULL);
+	return;
+    }
+    http->header_callback(data, http->header_entry->mem_obj->reply);
+}
+void
+storeClientCopyHeaders(store_client * sc, StoreEntry * e, STHCB * callback, void *callback_data)
+{
+    clientHttpRequest *http = callback_data;
+    http->header_callback = callback;
+    http->header_entry = e;
+    storeClientCopy(http->sc, e, 0, 0, STORE_CLIENT_BUF_SZ, memAllocate(MEM_STORE_CLIENT_BUF), storeClientCopyHeadersCB, http);
+}
+
 #if USE_IDENT
 static void
 clientIdentDone(const char *ident, void *data)
@@ -177,7 +202,7 @@
 
 #endif
 
-static aclCheck_t *
+aclCheck_t *
 clientAclChecklistCreate(const acl_access * acl, const clientHttpRequest * http)
 {
     aclCheck_t *ch;
@@ -358,7 +383,7 @@
     aclNBCheck(http->acl_checklist, clientAccessCheckDone, http);
 }
 
-static void
+void
 clientAccessCheck2(void *data)
 {
     clientHttpRequest *http = data;
@@ -394,12 +419,14 @@
     if (h->request == NULL)
 	h->request = requestLink(requestCreate(m, PROTO_NONE, null_string));
     e = storeCreateEntry(h->uri, flags, m);
+    if (h->request->store_url)
+	storeEntrySetStoreUrl(e, h->request->store_url);
     h->sc = storeClientRegister(e, h);
 #if DELAY_POOLS
     if (h->log_type != LOG_TCP_DENIED)
 	delaySetStoreClient(h->sc, delayClient(h));
 #endif
-    storeClientRef(h->sc, e, 0, 0, SM_PAGE_SIZE, clientSendMoreHeaderData, h);
+    storeClientCopyHeaders(h->sc, e, clientSendHeaders, h);
     return e;
 }
 
@@ -531,123 +558,6 @@
 }
 
 static void
-clientRedirectAccessCheckDone(int answer, void *data)
-{
-    clientHttpRequest *http = data;
-    http->acl_checklist = NULL;
-    if (answer == ACCESS_ALLOWED)
-	redirectStart(http, clientRedirectDone, http);
-    else
-	clientRedirectDone(http, NULL);
-}
-
-static void
-clientRedirectStart(clientHttpRequest * http)
-{
-    debug(33, 5) ("clientRedirectStart: '%s'\n", http->uri);
-    if (Config.Program.url_rewrite.command == NULL) {
-	clientRedirectDone(http, NULL);
-	return;
-    }
-    if (Config.accessList.url_rewrite) {
-	http->acl_checklist = clientAclChecklistCreate(Config.accessList.url_rewrite, http);
-	aclNBCheck(http->acl_checklist, clientRedirectAccessCheckDone, http);
-    } else {
-	redirectStart(http, clientRedirectDone, http);
-    }
-}
-
-static void
-clientRedirectDone(void *data, char *result)
-{
-    clientHttpRequest *http = data;
-    request_t *new_request = NULL;
-    request_t *old_request = http->request;
-    const char *urlgroup = http->conn->port->urlgroup;
-    debug(33, 5) ("clientRedirectDone: '%s' result=%s\n", http->uri,
-	result ? result : "NULL");
-    assert(http->redirect_state == REDIRECT_PENDING);
-    http->redirect_state = REDIRECT_DONE;
-    if (result) {
-	http_status status;
-	if (*result == '!') {
-	    char *t;
-	    if ((t = strchr(result + 1, '!')) != NULL) {
-		urlgroup = result + 1;
-		*t++ = '\0';
-		result = t;
-	    } else {
-		debug(33, 1) ("clientRedirectDone: bad input: %s\n", result);
-	    }
-	}
-	status = (http_status) atoi(result);
-	if (status == HTTP_MOVED_PERMANENTLY
-	    || status == HTTP_MOVED_TEMPORARILY
-	    || status == HTTP_SEE_OTHER
-	    || status == HTTP_TEMPORARY_REDIRECT) {
-	    char *t = result;
-	    if ((t = strchr(result, ':')) != NULL) {
-		http->redirect.status = status;
-		http->redirect.location = xstrdup(t + 1);
-		goto redirect_parsed;
-	    } else {
-		debug(33, 1) ("clientRedirectDone: bad input: %s\n", result);
-	    }
-	} else if (strcmp(result, http->uri))
-	    new_request = urlParse(old_request->method, result);
-    }
-  redirect_parsed:
-    if (new_request) {
-	safe_free(http->uri);
-	http->uri = xstrdup(urlCanonical(new_request));
-	new_request->http_ver = old_request->http_ver;
-	httpHeaderAppend(&new_request->header, &old_request->header);
-	new_request->client_addr = old_request->client_addr;
-	new_request->client_port = old_request->client_port;
-#if FOLLOW_X_FORWARDED_FOR
-	new_request->indirect_client_addr = old_request->indirect_client_addr;
-#endif /* FOLLOW_X_FORWARDED_FOR */
-	new_request->my_addr = old_request->my_addr;
-	new_request->my_port = old_request->my_port;
-	new_request->flags = old_request->flags;
-	new_request->flags.redirected = 1;
-	if (old_request->auth_user_request) {
-	    new_request->auth_user_request = old_request->auth_user_request;
-	    authenticateAuthUserRequestLock(new_request->auth_user_request);
-	}
-	if (old_request->body_reader) {
-	    new_request->body_reader = old_request->body_reader;
-	    new_request->body_reader_data = old_request->body_reader_data;
-	    old_request->body_reader = NULL;
-	    old_request->body_reader_data = NULL;
-	}
-	new_request->content_length = old_request->content_length;
-	if (strBuf(old_request->extacl_log))
-	    new_request->extacl_log = stringDup(&old_request->extacl_log);
-	if (old_request->extacl_user)
-	    new_request->extacl_user = xstrdup(old_request->extacl_user);
-	if (old_request->extacl_passwd)
-	    new_request->extacl_passwd = xstrdup(old_request->extacl_passwd);
-	requestUnlink(old_request);
-	http->request = requestLink(new_request);
-    } else {
-	/* Don't mess with urlgroup on internal request */
-	if (old_request->flags.internal)
-	    urlgroup = NULL;
-    }
-    safe_free(http->request->urlgroup);		/* only paranoia. should not happen */
-    if (urlgroup && *urlgroup)
-	http->request->urlgroup = xstrdup(urlgroup);
-    clientInterpretRequestHeaders(http);
-#if HEADERS_LOG
-    headersLog(0, 1, request->method, request);
-#endif
-    /* XXX This really should become a ref-counted string type pointer, not a copy! */
-    fd_note(http->conn->fd, http->uri);
-    clientAccessCheck2(http);
-}
-
-static void
 clientCheckNoCache(clientHttpRequest * http)
 {
     if (Config.accessList.noCache && http->request->flags.cachable) {
@@ -689,74 +599,49 @@
 }
 
 static void
-clientHandleETagReply(void *data, mem_node_ref ref, ssize_t size)
+clientHandleETagReply(void *data, HttpReply * rep)
 {
     //const char *buf = ref.node->data + ref.offset;
     clientHttpRequest *http = data;
     StoreEntry *entry = http->entry;
-    MemObject *mem;
-    const char *url = storeUrl(entry);
-    http_status status;
-    debug(33, 3) ("clientHandleETagReply: %s, %d bytes\n", url, (int) size);
+    const char *url = storeLookupUrl(entry);
     if (entry == NULL) {
 	/* client aborted */
-        stmemNodeUnref(&ref);
 	return;
     }
-    if (size < 0 && !EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
-        stmemNodeUnref(&ref);
+    if (!rep) {
+	debug(33, 3) ("clientHandleETagReply: FAILED '%s'\n", url);
 	clientHandleETagMiss(http);
 	return;
     }
-    mem = entry->mem_obj;
-    status = mem->reply->sline.status;
     if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
 	debug(33, 3) ("clientHandleETagReply: ABORTED '%s'\n", url);
-        stmemNodeUnref(&ref);
 	clientHandleETagMiss(http);
 	return;
     }
-    if (STORE_PENDING == entry->store_status && 0 == status) {
-	debug(33, 3) ("clientHandleETagReply: Incomplete headers for '%s'\n", url);
-	if (size >= SM_PAGE_SIZE) {
-	    /* will not get any bigger than that */
-	    debug(33, 3) ("clientHandleETagReply: Reply is too large '%s'\n", url);
-            stmemNodeUnref(&ref);
-	    clientHandleETagMiss(http);
-	} else {
-            stmemNodeUnref(&ref);
-	    storeClientRef(http->sc, entry,
-		http->out.offset + size,
-		http->out.offset,
-		SM_PAGE_SIZE,
-		clientHandleETagReply,
-		http);
-	}
-	return;
-    }
-    if (HTTP_NOT_MODIFIED == mem->reply->sline.status) {
+    debug(33, 3) ("clientHandleETagReply: %s = %d\n", url, (int) rep->sline.status);
+    if (HTTP_NOT_MODIFIED == rep->sline.status) {
 	/* Remember the ETag and restart */
-        stmemNodeUnref(&ref);
-	if (mem->reply) {
+	if (rep) {
 	    request_t *request = http->request;
-	    const char *etag = httpHeaderGetStr(&mem->reply->header, HDR_ETAG);
+	    const char *etag = httpHeaderGetStr(&rep->header, HDR_ETAG);
 	    const char *vary = request->vary_headers;
-	    int has_vary = httpHeaderHas(&entry->mem_obj->reply->header, HDR_VARY);
+	    int has_vary = httpHeaderHas(&rep->header, HDR_VARY);
 #if X_ACCELERATOR_VARY
-	    has_vary |= httpHeaderHas(&entry->mem_obj->reply->header, HDR_X_ACCELERATOR_VARY);
+	    has_vary |= httpHeaderHas(&rep->header, HDR_X_ACCELERATOR_VARY);
 #endif
 	    if (has_vary)
-		vary = httpMakeVaryMark(request, mem->reply);
+		vary = httpMakeVaryMark(request, rep);
 
 	    if (etag && vary) {
-		storeAddVary(mem->url, mem->method, NULL, httpHeaderGetStr(&mem->reply->header, HDR_ETAG), request->vary_hdr, request->vary_headers, strBuf(request->vary_encoding));
+		storeAddVary(url, entry->mem_obj->method, NULL, httpHeaderGetStr(&rep->header, HDR_ETAG), request->vary_hdr, request->vary_headers, strBuf(request->vary_encoding));
 	    }
 	}
 	clientHandleETagMiss(http);
 	return;
     }
     /* Send the new object to the client */
-    clientSendMoreHeaderData(data, ref, size);
+    clientSendHeaders(data, rep);
     return;
 }
 
@@ -767,6 +652,8 @@
     StoreEntry *entry = NULL;
     debug(33, 3) ("clientProcessETag: '%s'\n", http->uri);
     entry = storeCreateEntry(url, http->request->flags, http->request->method);
+    if (http->request->store_url)
+	storeEntrySetStoreUrl(entry, http->request->store_url);
     http->sc = storeClientRegister(entry, http);
 #if DELAY_POOLS
     /* delay_id is already set on original store client */
@@ -778,18 +665,34 @@
     /* Register with storage manager to receive updates when data comes in. */
     if (EBIT_TEST(entry->flags, ENTRY_ABORTED))
 	debug(33, 0) ("clientProcessETag: found ENTRY_ABORTED object\n");
-    storeClientRef(http->sc, entry,
-	http->out.offset,
-	http->out.offset,
-	SM_PAGE_SIZE,
+    storeClientCopyHeaders(http->sc, entry,
 	clientHandleETagReply,
 	http);
 }
 
 static void
-clientProcessExpired(void *data)
+clientRefreshCheck(clientHttpRequest * http)
+{
+    refreshCheckSubmit(http->entry, clientRefreshCheckDone, http);
+}
+
+static void
+clientRefreshCheckDone(void *data, int fresh, const char *log)
 {
     clientHttpRequest *http = data;
+    if (log) {
+	safe_free(http->al.ext_refresh);
+	http->al.ext_refresh = xstrdup(log);
+    }
+    if (fresh)
+	clientProcessHit(http);
+    else
+	clientProcessExpired(http);
+}
+
+static void
+clientProcessExpired(clientHttpRequest * http)
+{
     char *url = http->uri;
     StoreEntry *entry = NULL;
     int hit = 0;
@@ -828,6 +731,8 @@
     }
     if (!entry) {
 	entry = storeCreateEntry(url, http->request->flags, http->request->method);
+	if (http->request->store_url)
+	    storeEntrySetStoreUrl(entry, http->request->store_url);
 	if (http->entry->mem_obj) {
 	    http->entry->mem_obj->refresh_timestamp = squid_curtime;
 	    if (Config.onoff.collapsed_forwarding) {
@@ -836,7 +741,12 @@
 	    }
 	}
     }
-    /* NOTE, don't call storeLockObject(), storeCreateEntry() does it */
+    if (entry->mem_obj->old_entry) {
+	storeUnlockObject(entry->mem_obj->old_entry);
+	entry->mem_obj->old_entry = NULL;
+    }
+    entry->mem_obj->old_entry = http->old_entry;
+    storeLockObject(entry->mem_obj->old_entry);
     http->sc = storeClientRegister(entry, http);
 #if DELAY_POOLS
     /* delay_id is already set on original store client */
@@ -848,6 +758,7 @@
     } else
 	http->request->lastmod = -1;
     debug(33, 5) ("clientProcessExpired: lastmod %ld\n", (long int) entry->lastmod);
+    /* NOTE, don't call storeLockObject(), storeCreateEntry() does it */
     http->entry = entry;
     http->out.offset = 0;
     if (can_revalidate) {
@@ -862,10 +773,7 @@
     /* Register with storage manager to receive updates when data comes in. */
     if (EBIT_TEST(entry->flags, ENTRY_ABORTED))
 	debug(33, 0) ("clientProcessExpired: found ENTRY_ABORTED object\n");
-    storeClientRef(http->sc, entry,
-	http->out.offset,
-	http->out.offset,
-	SM_PAGE_SIZE,
+    storeClientCopyHeaders(http->sc, entry,
 	clientHandleIMSReply,
 	http);
 }
@@ -881,8 +789,16 @@
     /* If the reply is a failure then send the old object as a last
      * resort */
     if (status >= 500 && status < 600) {
-	debug(33, 3) ("clientGetsOldEntry: YES, failure reply=%d\n", status);
-	return 1;
+	if (EBIT_TEST(new_entry->flags, ENTRY_NEGCACHED)) {
+	    debug(33, 3) ("clientGetsOldEntry: NO, negatively cached failure reply=%d\n", status);
+	    return 0;
+	}
+	if (refreshCheckStaleOK(old_entry, request)) {
+	    debug(33, 3) ("clientGetsOldEntry: YES, failure reply=%d and old acceptable to send\n", status);
+	    return 1;
+	}
+	debug(33, 3) ("clientGetsOldEntry: NO, failure reply=%d and old NOT acceptable to send\n", status);
+	return 0;
     }
     /* If the reply is not to a cache validation conditional then
      * we should forward it to the client */
@@ -929,7 +845,7 @@
 
 
 static void
-clientHandleIMSReply(void *data, mem_node_ref ref, ssize_t size)
+clientHandleIMSReply(void *data, HttpReply * rep)
 {
     clientHttpRequest *http = data;
     StoreEntry *entry = http->entry;
@@ -938,23 +854,20 @@
     int unlink_request = 0;
     StoreEntry *oldentry;
     int recopy = 1;
-    http_status status;
-    debug(33, 3) ("clientHandleIMSReply: %s, %ld bytes\n", url, (long int) size);
+    debug(33, 3) ("clientHandleIMSReply: %s\n", url);
     if (http->old_entry && http->old_entry->mem_obj && http->old_entry->mem_obj->ims_entry) {
 	storeUnlockObject(http->old_entry->mem_obj->ims_entry);
 	http->old_entry->mem_obj->ims_entry = NULL;
     }
     if (entry == NULL) {
-        stmemNodeUnref(&ref);
 	return;
     }
-    if (size < 0 && !EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
-        stmemNodeUnref(&ref);
-	return;
+    if (entry->mem_obj->old_entry) {
+	storeUnlockObject(entry->mem_obj->old_entry);
+	entry->mem_obj->old_entry = NULL;
     }
     mem = entry->mem_obj;
-    status = mem->reply->sline.status;
-    if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
+    if (!rep) {
 	debug(33, 3) ("clientHandleIMSReply: ABORTED '%s'\n", url);
 	/* We have an existing entry, but failed to validate it */
 	/* Its okay to send the old one anyway */
@@ -963,45 +876,26 @@
 	storeUnlockObject(entry);
 	entry = http->entry = http->old_entry;
 	http->sc = http->old_sc;
-    } else if (STORE_PENDING == entry->store_status && 0 == status) {
-	debug(33, 3) ("clientHandleIMSReply: Incomplete headers for '%s'\n", url);
-	if (size >= SM_PAGE_SIZE) {
-	    /* will not get any bigger than that */
-	    debug(33, 3) ("clientHandleIMSReply: Reply is too large '%s', using old entry\n", url);
-	    /* use old entry, this repeats the code abovez */
-	    http->log_type = LOG_TCP_REFRESH_FAIL_HIT;
-	    storeClientUnregister(http->sc, entry, http);
-	    storeUnlockObject(entry);
-	    entry = http->entry = http->old_entry;
-	    http->sc = http->old_sc;
-	    /* continue */
-	} else {
-            stmemNodeUnref(&ref);
-	    storeClientRef(http->sc, entry,
-		http->out.offset + size,
-		http->out.offset,
-		SM_PAGE_SIZE,
-		clientHandleIMSReply,
-		http);
-	    return;
-	}
     } else if (clientGetsOldEntry(entry, http->old_entry, http->request)) {
 	/* We initiated the IMS request, the client is not expecting
 	 * 304, so put the good one back.  First, make sure the old entry
 	 * headers have been loaded from disk. */
 	oldentry = http->old_entry;
-	http->log_type = LOG_TCP_REFRESH_HIT;
 	if (oldentry->mem_obj->request == NULL) {
 	    oldentry->mem_obj->request = requestLink(mem->request);
 	    unlink_request = 1;
 	}
-	if (mem->reply->sline.status == HTTP_NOT_MODIFIED) {
+	if (rep->sline.status == HTTP_NOT_MODIFIED) {
 	    /* Don't memcpy() the whole reply structure here.  For example,
 	     * www.thegist.com (Netscape/1.13) returns a content-length for
 	     * 304's which seems to be the length of the 304 HEADERS!!! and
 	     * not the body they refer to.  */
-	    httpReplyUpdateOnNotModified(oldentry->mem_obj->reply, mem->reply);
+	    httpReplyUpdateOnNotModified(oldentry->mem_obj->reply, rep);
 	    storeTimestampsSet(oldentry);
+	    storeUpdate(oldentry, http->request);
+	    http->log_type = LOG_TCP_REFRESH_HIT;
+	} else {
+	    http->log_type = LOG_TCP_REFRESH_FAIL_HIT;
 	}
 	storeClientUnregister(http->sc, entry, http);
 	http->sc = http->old_sc;
@@ -1015,11 +909,14 @@
 	/* the client can handle this reply, whatever it is */
 	http->flags.hit = 0;
 	http->log_type = LOG_TCP_REFRESH_MISS;
-	if (HTTP_NOT_MODIFIED == mem->reply->sline.status) {
+	if (HTTP_NOT_MODIFIED == rep->sline.status) {
 	    httpReplyUpdateOnNotModified(http->old_entry->mem_obj->reply,
-		mem->reply);
+		rep);
 	    storeTimestampsSet(http->old_entry);
-	    http->log_type = LOG_TCP_REFRESH_HIT;
+	    if (!EBIT_TEST(http->old_entry->flags, REFRESH_FAILURE))
+		http->log_type = LOG_TCP_REFRESH_HIT;
+	    else
+		http->log_type = LOG_TCP_REFRESH_FAIL_HIT;
 	}
 	/* Get rid of the old entry if not a cache validation */
 	if (!http->request->flags.cache_validation)
@@ -1032,16 +929,11 @@
     http->old_sc = NULL;
     assert(!EBIT_TEST(entry->flags, ENTRY_ABORTED));
     if (recopy) {
-        stmemNodeUnref(&ref);
-	storeClientRef(http->sc, entry,
-	    http->out.offset,
-	    http->out.offset,
-	    SM_PAGE_SIZE,
-	    clientSendMoreHeaderData,
+	storeClientCopyHeaders(http->sc, entry,
+	    clientSendHeaders,
 	    http);
     } else {
-	clientSendMoreHeaderData(data, stmemNodeRef(&ref), size);
-        stmemNodeUnref(&ref);
+	clientSendHeaders(data, rep);
     }
 }
 
@@ -1051,7 +943,7 @@
     squid_off_t object_length;
     MemObject *mem = entry->mem_obj;
     time_t mod_time = entry->lastmod;
-    debug(33, 3) ("modifiedSince: '%s'\n", storeUrl(entry));
+    debug(33, 3) ("modifiedSince: '%s'\n", storeLookupUrl(entry));
     debug(33, 3) ("modifiedSince: mod_time = %ld\n", (long int) mod_time);
     if (mod_time < 0)
 	return 1;
@@ -1116,10 +1008,7 @@
 	    http->entry->mem_obj->method = http->request->method;
 	    http->sc = storeClientRegister(http->entry, http);
 	    http->log_type = LOG_TCP_HIT;
-	    storeClientRef(http->sc, http->entry,
-		http->out.offset,
-		http->out.offset,
-		SM_PAGE_SIZE,
+	    storeClientCopyHeaders(http->sc, http->entry,
 		clientCacheHit,
 		http);
 	    return;
@@ -1407,7 +1296,7 @@
 #endif
 }
 
-static void
+void
 clientInterpretRequestHeaders(clientHttpRequest * http)
 {
     request_t *request = http->request;
@@ -1680,6 +1569,8 @@
 	return 1;
     if (code == LOG_TCP_STALE_HIT)
 	return 1;
+    if (code == LOG_TCP_ASYNC_HIT)
+	return 1;
     if (code == LOG_TCP_IMS_HIT)
 	return 1;
     if (code == LOG_TCP_REFRESH_FAIL_HIT)
@@ -2032,7 +1923,7 @@
     httpHdrMangleList(hdr, request);
 }
 
-/* Used exclusively by clientBuildReply() during failure cases only */
+/* Used exclusively by clientCloneReply() during failure cases only */
 static void
 clientUnwindReply(clientHttpRequest * http, HttpReply * rep)
 {
@@ -2054,7 +1945,7 @@
  * be.
  */
 static HttpReply *
-clientBuildReply(clientHttpRequest * http)
+clientCloneReply(clientHttpRequest * http, HttpReply * orig_rep)
 {
     HttpReply *rep = NULL;
     /* If we don't have a memobj / reply by now then we're stuffed */
@@ -2063,7 +1954,7 @@
 	return NULL;
     }
     /* try to grab the already-parsed header */
-    rep = httpReplyClone(http->sc->entry->mem_obj->reply);
+    rep = httpReplyClone(orig_rep);
     if (rep->pstate == psParsed) {
 	/* enforce 1.0 reply version */
 	httpBuildVersion(&rep->sline.version, 1, 0);
@@ -2108,6 +1999,163 @@
 }
 
 /*
+ * Perform an async refresh of an object
+ */
+typedef struct _clientAsyncRefreshRequest {
+    request_t *request;
+    StoreEntry *entry;
+    StoreEntry *old_entry;
+    store_client *sc;
+    squid_off_t offset;
+    size_t buf_in_use;
+    char readbuf[STORE_CLIENT_BUF_SZ];
+    struct timeval start;
+} clientAsyncRefreshRequest;
+
+CBDATA_TYPE(clientAsyncRefreshRequest);
+
+static void
+clientAsyncDone(clientAsyncRefreshRequest * async)
+{
+    AccessLogEntry al;
+    static aclCheck_t *ch;
+    MemObject *mem = async->entry->mem_obj;
+    request_t *request = async->request;
+    memset(&al, 0, sizeof(al));
+    al.icp.opcode = ICP_INVALID;
+    al.url = mem->url;
+    debug(33, 9) ("clientAsyncDone: url='%s'\n", al.url);
+    al.http.code = mem->reply->sline.status;
+    al.http.content_type = strBuf(mem->reply->content_type);
+    al.cache.size = async->offset;
+    if (async->old_entry->mem_obj)
+	async->old_entry->mem_obj->refresh_timestamp = 0;
+    if (mem->reply->sline.status == 304) {
+	/* Don't memcpy() the whole reply structure here.  For example,
+	 * www.thegist.com (Netscape/1.13) returns a content-length for
+	 * 304's which seems to be the length of the 304 HEADERS!!! and
+	 * not the body they refer to.  */
+	httpReplyUpdateOnNotModified(async->old_entry->mem_obj->reply, async->entry->mem_obj->reply);
+	storeTimestampsSet(async->old_entry);
+	storeUpdate(async->old_entry, async->request);
+	al.cache.code = LOG_TCP_ASYNC_HIT;
+    } else
+	al.cache.code = LOG_TCP_ASYNC_MISS;
+    al.cache.msec = tvSubMsec(async->start, current_time);
+    if (Config.onoff.log_mime_hdrs) {
+	Packer p;
+	MemBuf mb;
+	memBufDefInit(&mb);
+	packerToMemInit(&p, &mb);
+	httpHeaderPackInto(&request->header, &p);
+	al.headers.request = xstrdup(mb.buf);
+	packerClean(&p);
+	memBufClean(&mb);
+    }
+    al.http.method = request->method;
+    al.http.version = request->http_ver;
+    al.hier = request->hier;
+    if (request->auth_user_request) {
+	if (authenticateUserRequestUsername(request->auth_user_request))
+	    al.cache.authuser = xstrdup(authenticateUserRequestUsername(request->auth_user_request));
+	authenticateAuthUserRequestUnlock(request->auth_user_request);
+	request->auth_user_request = NULL;
+    } else if (request->extacl_user) {
+	al.cache.authuser = xstrdup(request->extacl_user);
+    }
+    al.request = request;
+    al.reply = mem->reply;
+    ch = aclChecklistCreate(Config.accessList.http, request, NULL);
+    ch->reply = mem->reply;
+    if (!Config.accessList.log || aclCheckFast(Config.accessList.log, ch))
+	accessLogLog(&al, ch);
+    aclChecklistFree(ch);
+    storeClientUnregister(async->sc, async->entry, async);
+    storeUnlockObject(async->entry);
+    storeUnlockObject(async->old_entry);
+    requestUnlink(async->request);
+    safe_free(al.headers.request);
+    safe_free(al.headers.reply);
+    safe_free(al.cache.authuser);
+    cbdataFree(async);
+}
+
+static void
+clientHandleAsyncReply(void *data, char *buf, ssize_t size)
+{
+    clientAsyncRefreshRequest *async = data;
+    StoreEntry *e = async->entry;
+    if (EBIT_TEST(e->flags, ENTRY_ABORTED)) {
+	clientAsyncDone(async);
+	return;
+    }
+    if (size <= 0) {
+	clientAsyncDone(async);
+	return;
+    }
+    async->offset += size;
+    if (e->mem_obj->reply->sline.status == 304) {
+	clientAsyncDone(async);
+	return;
+    }
+    storeClientCopy(async->sc, async->entry,
+	async->offset,
+	async->offset,
+	STORE_CLIENT_BUF_SZ, async->readbuf,
+	clientHandleAsyncReply,
+	async);
+}
+
+static void
+clientAsyncRefresh(clientHttpRequest * http)
+{
+    char *url = http->uri;
+    clientAsyncRefreshRequest *async;
+    request_t *request = http->request;
+    debug(33, 3) ("clientAsyncRefresh: '%s'\n", http->uri);
+    CBDATA_INIT_TYPE(clientAsyncRefreshRequest);
+    http->entry->mem_obj->refresh_timestamp = squid_curtime;
+    async = cbdataAlloc(clientAsyncRefreshRequest);
+    async->start = current_time;
+    async->request = requestLink(request);
+    async->old_entry = http->entry;
+    storeLockObject(async->old_entry);
+    async->entry = storeCreateEntry(url,
+	request->flags,
+	request->method);
+    async->entry->mem_obj->old_entry = async->old_entry;
+    storeLockObject(async->entry->mem_obj->old_entry);
+    async->sc = storeClientRegister(async->entry, async);
+    request->etags = NULL;	/* Should always be null as this was a cache hit, but just in case.. */
+    httpHeaderDelById(&request->header, HDR_RANGE);
+    httpHeaderDelById(&request->header, HDR_IF_RANGE);
+    httpHeaderDelById(&request->header, HDR_IF_NONE_MATCH);
+    httpHeaderDelById(&request->header, HDR_IF_MATCH);
+    if (async->old_entry->lastmod > 0)
+	request->lastmod = async->old_entry->lastmod;
+    else if (async->old_entry->mem_obj && async->old_entry->mem_obj->reply)
+	request->lastmod = async->old_entry->mem_obj->reply->date;
+    else
+	request->lastmod = -1;
+    if (!request->etag) {
+	const char *etag = httpHeaderGetStr(&async->old_entry->mem_obj->reply->header, HDR_ETAG);
+	if (etag)
+	    async->request->etag = xstrdup(etag);
+    }
+#if DELAY_POOLS
+    /* delay_id is already set on original store client */
+    delaySetStoreClient(async->sc, delayClient(http));
+#endif
+    fwdStart(-1, async->entry, async->request);
+    storeClientCopy(async->sc, async->entry,
+	async->offset,
+	async->offset,
+	STORE_CLIENT_BUF_SZ, async->readbuf,
+	clientHandleAsyncReply,
+	async);
+}
+
+/*
  * clientCacheHit should only be called until the HTTP reply headers
  * have been parsed.  Normally this should be a single call, but
  * it might take more than one.  As soon as we have the headers,
@@ -2115,7 +2163,7 @@
  * clientProcessMiss.
  */
 static void
-clientCacheHit(void *data, mem_node_ref ref, ssize_t size)
+clientCacheHit(void *data, HttpReply * rep)
 {
     clientHttpRequest *http = data;
     StoreEntry *e = http->entry;
@@ -2123,32 +2171,31 @@
     request_t *r = http->request;
     int is_modified = -1;
     int stale;
-    debug(33, 3) ("clientCacheHit: %s, %d bytes\n", http->uri, (int) size);
     http->flags.hit = 0;
     if (http->entry == NULL) {
-        stmemNodeUnref(&ref);
 	debug(33, 3) ("clientCacheHit: request aborted\n");
 	return;
-    } else if (size <= 0) {
+    } else if (!rep) {
 	/* swap in failure */
-        stmemNodeUnref(&ref);
 	debug(33, 3) ("clientCacheHit: swapin failure for %s\n", http->uri);
 	http->log_type = LOG_TCP_SWAPFAIL_MISS;
 	clientProcessMiss(http);
 	return;
     }
-    assert(size > 0);
     mem = e->mem_obj;
+    debug(33, 3) ("clientCacheHit: %s = %d\n", http->uri, rep->sline.status);
     assert(!EBIT_TEST(e->flags, ENTRY_ABORTED));
-    if (!memHaveHeaders(mem)) {
-	debug(33, 1) ("clientCacheHit: No reply headers in '%s'?\n", e->mem_obj->url);
-        stmemNodeUnref(&ref);
+
+    if (r->store_url && mem->store_url == NULL && strcmp(r->store_url, mem->url) != 0) {
+	debug(33, 1) ("clientCacheHit: request has store_url '%s'; mem object in hit doesn't and doesn't match the url '%s'!\n", r->store_url, mem->url);
 	clientProcessMiss(http);
 	return;
-    }
-    if (strcmp(mem->url, urlCanonical(r)) != 0) {
-	debug(33, 1) ("clientCacheHit: URL mismatch '%s' != '%s'?\n", e->mem_obj->url, urlCanonical(r));
-        stmemNodeUnref(&ref);
+    } else if (r->store_url && strcmp(mem->store_url, r->store_url) != 0) {
+	debug(33, 1) ("clientCacheHit: store URL mismatch '%s' != '%s'?\n", mem->store_url, r->store_url);
+	clientProcessMiss(http);
+	return;
+    } else if ((!r->store_url) && (!mem->store_url) && strcmp(mem->url, urlCanonical(r)) != 0) {
+	debug(33, 1) ("clientCacheHit: (store url '%s'); URL mismatch '%s' != '%s'?\n", r->store_url, e->mem_obj->url, urlCanonical(r));
 	clientProcessMiss(http);
 	return;
     }
@@ -2184,7 +2231,6 @@
 	     * so we only get here once. (it also takes care of cancelling loops)
 	     */
 	    debug(33, 2) ("clientProcessHit: Vary detected!\n");
-            stmemNodeUnref(&ref);
 	    return;
 	}
     case VARY_RESTART:
@@ -2194,13 +2240,11 @@
 	safe_free(r->vary_hdr);
 	safe_free(r->vary_headers);
 	clientProcessRequest(http);
-        stmemNodeUnref(&ref);
 	return;
     case VARY_CANCEL:
 	/* varyEvaluateMatch found a object loop. Process as miss */
 	debug(33, 1) ("clientProcessHit: Vary object loop!\n");
 	clientProcessMiss(http);
-        stmemNodeUnref(&ref);
 	return;
     }
     if (r->method == METHOD_PURGE) {
@@ -2209,7 +2253,6 @@
 	http->sc = NULL;
 	storeUnlockObject(e);
 	clientPurgeRequest(http);
-        stmemNodeUnref(&ref);
 	return;
     }
     http->flags.hit = 1;
@@ -2220,11 +2263,9 @@
 #endif
 	    ) {
 	    http->log_type = LOG_TCP_NEGATIVE_HIT;
-	    clientSendMoreHeaderData(data, stmemNodeRef(&ref), size);
-            stmemNodeUnref(&ref);
+	    clientSendHeaders(data, rep);
 	} else {
 	    http->log_type = LOG_TCP_MISS;
-            stmemNodeUnref(&ref);
 	    clientProcessMiss(http);
 	}
 	return;
@@ -2242,7 +2283,6 @@
 	     * Query the origin to see what should be done.
 	     */
 	    http->log_type = LOG_TCP_MISS;
-            stmemNodeUnref(&ref);
 	    clientProcessMiss(http);
 	    return;
 	}
@@ -2255,7 +2295,6 @@
 	    debug(33, 4) ("clientCacheHit: Reply code %d != 200\n",
 		mem->reply->sline.status);
 	    http->log_type = LOG_TCP_MISS;
-            stmemNodeUnref(&ref);
 	    clientProcessMiss(http);
 	    return;
 	}
@@ -2290,6 +2329,10 @@
 	debug(33, 2) ("clientProcessHit: refresh_stale HIT\n");
 	http->log_type = LOG_TCP_STALE_HIT;
 	stale = 0;
+    } else if (stale == -2 && e->mem_obj->refresh_timestamp + e->mem_obj->stale_while_revalidate >= squid_curtime) {
+	debug(33, 2) ("clientProcessHit: stale-while-revalidate HIT\n");
+	http->log_type = LOG_TCP_STALE_HIT;
+	stale = 0;
     } else if (stale && http->flags.internal) {
 	debug(33, 2) ("clientProcessHit: internal HIT\n");
 	stale = 0;
@@ -2297,7 +2340,13 @@
 	debug(33, 2) ("clientProcessHit: offline HIT\n");
 	http->log_type = LOG_TCP_OFFLINE_HIT;
 	stale = 0;
+    } else if (stale == -2) {
+	debug(33, 2) ("clientProcessHit: stale-while-revalidate needs revalidation\n");
+	clientAsyncRefresh(http);
+	http->log_type = LOG_TCP_STALE_HIT;
+	stale = 0;
     }
+    http->is_modified = is_modified;
     if (stale) {
 	debug(33, 5) ("clientCacheHit: in refreshCheck() block\n");
 	/*
@@ -2318,12 +2367,20 @@
 	     */
 	    http->log_type = LOG_TCP_CLIENT_REFRESH_MISS;
 	    clientProcessMiss(http);
-	} else {
-	    clientProcessExpired(http);
+	    return;
 	}
-        stmemNodeUnref(&ref);
+	clientRefreshCheck(http);
 	return;
     }
+    clientProcessHit(http);
+}
+
+static void
+clientProcessHit(clientHttpRequest * http)
+{
+    int is_modified = http->is_modified;
+    StoreEntry *e = http->entry;
+
     if (is_modified == 0) {
 	time_t timestamp = e->timestamp;
 	MemBuf mb = httpPacked304Reply(e->mem_obj->reply);
@@ -2343,18 +2400,18 @@
 	storeAppend(e, mb.buf, mb.size);
 	memBufClean(&mb);
 	storeComplete(e);
-        stmemNodeUnref(&ref);
 	return;
     }
     /*
      * plain ol' cache hit
      */
+    if (EBIT_TEST(e->flags, REFRESH_FAILURE))
+	http->log_type = LOG_TCP_NEGATIVE_HIT;
     if (e->store_status != STORE_OK)
 	http->log_type = LOG_TCP_MISS;
     else if (http->log_type == LOG_TCP_HIT && e->mem_status == IN_MEMORY)
 	http->log_type = LOG_TCP_MEM_HIT;
-    clientSendMoreHeaderData(data, stmemNodeRef(&ref), size);
-    stmemNodeUnref(&ref);
+    clientSendHeaders(http, e->mem_obj->reply);
 }
 
 /* put terminating boundary for multiparts */
@@ -2612,49 +2669,32 @@
  * such, writes processed message to the client's socket
  */
 static void
-clientSendMoreHeaderData(void *data, mem_node_ref ref, ssize_t size)
+clientSendHeaders(void *data, HttpReply * rep)
 {
     //const char *buf = ref.node->data + ref.offset;
     clientHttpRequest *http = data;
     StoreEntry *entry = http->entry;
     ConnStateData *conn = http->conn;
     int fd = conn->fd;
-    HttpReply *rep = NULL;
-    debug(33, 5) ("clientSendMoreHeaderData: %s, %d bytes\n", http->uri, (int) size);
-    assert(size <= SM_PAGE_SIZE);
     assert(http->request != NULL);
     dlinkDelete(&http->active, &ClientActiveRequests);
     dlinkAdd(http, &http->active, &ClientActiveRequests);
-    debug(33, 5) ("clientSendMoreHeaderData: FD %d '%s', out.offset=%ld \n",
-	fd, storeUrl(entry), (long int) http->out.offset);
+    debug(33, 5) ("clientSendMoreHeaderData: FD %d '%s'\n", fd, storeUrl(entry));
     assert(conn->reqs.head != NULL);
     if (DLINK_HEAD(conn->reqs) != http) {
 	/* there is another object in progress, defer this one */
 	debug(33, 2) ("clientSendMoreHeaderData: Deferring %s\n", storeUrl(entry));
-        stmemNodeUnref(&ref);
 	return;
     } else if (http->request->flags.reset_tcp) {
 	comm_reset_close(fd);
-        stmemNodeUnref(&ref);
-	return;
-    } else if (entry && EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
-	/* call clientWriteComplete so the client socket gets closed */
-        stmemNodeUnref(&ref);
-	clientWriteComplete(fd, NULL, 0, COMM_OK, http);
-	return;
-    } else if (size < 0) {
-	/* call clientWriteComplete so the client socket gets closed */
-	clientWriteComplete(fd, NULL, 0, COMM_OK, http);
-        stmemNodeUnref(&ref);
 	return;
-    } else if (size == 0) {
+    } else if (!rep) {
 	/* call clientWriteComplete so the client socket gets closed */
 	clientWriteComplete(fd, NULL, 0, COMM_OK, http);
-        stmemNodeUnref(&ref);
 	return;
     }
     assert(http->out.offset == 0);
-    rep = http->reply = clientBuildReply(http);
+    rep = http->reply = clientCloneReply(http, rep);
     if (!rep) {
 	ErrorState *err = errorCon(ERR_INVALID_RESP, HTTP_BAD_GATEWAY, http->orig_request);
 	storeClientUnregister(http->sc, http->entry, http);
@@ -2663,7 +2703,6 @@
 	http->entry = clientCreateStoreEntry(http, http->request->method,
 	    null_request_flags);
 	errorAppendEntry(http->entry, err);
-        stmemNodeUnref(&ref);
 	return;
     }
     clientMaxBodySize(http->request, http, rep);
@@ -2676,7 +2715,6 @@
 	http->entry = clientCreateStoreEntry(http, http->request->method,
 	    null_request_flags);
 	errorAppendEntry(http->entry, err);
-        stmemNodeUnref(&ref);
 	return;
     }
     /* 
@@ -2691,7 +2729,6 @@
      */
     http->range_iter.prefix_size = rep->hdr_sz;
     debug(33, 3) ("clientSendMoreHeaderData: %d bytes of headers\n", rep->hdr_sz);
-    stmemNodeUnref(&ref);
     clientHttpLocationRewriteCheck(http);
 }
 
@@ -2956,7 +2993,7 @@
 	 * If we are here, then store_status == STORE_OK and it
 	 * seems we have a HEAD repsponse which is missing the
 	 * empty end-of-headers line (home.mira.net, phttpd/0.99.72
-	 * does this).  Because clientBuildReply() fails we just
+	 * does this).  Because clientCloneReply() fails we just
 	 * call this reply a body, set the done_copying flag and
 	 * continue...
 	 */
@@ -3047,11 +3084,8 @@
 	if (0 == storeClientCopyPending(http->sc, entry, http)) {
 	    if (EBIT_TEST(entry->flags, ENTRY_ABORTED))
 		debug(33, 0) ("clientKeepaliveNextRequest: ENTRY_ABORTED\n");
-	    storeClientRef(http->sc, entry,
-		http->out.offset,
-		http->out.offset,
-		SM_PAGE_SIZE,
-		clientSendMoreHeaderData,
+	    storeClientCopyHeaders(http->sc, entry,
+		clientSendHeaders,
 		http);
 	}
     }
@@ -3357,10 +3391,7 @@
 #if DELAY_POOLS
 	delaySetStoreClient(http->sc, delayClient(http));
 #endif
-	storeClientRef(http->sc, http->entry,
-	    http->out.offset,
-	    http->out.offset,
-	    SM_PAGE_SIZE,
+	storeClientCopyHeaders(http->sc, http->entry,
 	    clientCacheHit,
 	    http);
     } else {
--- /dev/null	Wed Nov 28 01:20:24 2007
+++ squid/src/client_side_rewrite.c	Wed Nov 28 01:20:25 2007
@@ -0,0 +1,154 @@
+
+/*
+ * $Id: client_side_rewrite.c,v 1.2.4.2 2007/11/27 08:12:27 adri Exp $
+ *
+ * DEBUG: section 33    Client-side Routines - URL Rewriter
+ * AUTHOR: Duane Wessels; Adrian Chadd
+ *
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from
+ *  the Internet community; see the CONTRIBUTORS file for full
+ *  details.   Many organizations have provided support for Squid's
+ *  development; see the SPONSORS file for full details.  Squid is
+ *  Copyrighted (C) 2001 by the Regents of the University of
+ *  California; see the COPYRIGHT file for full details.  Squid
+ *  incorporates software developed and/or copyrighted by other
+ *  sources; see the CREDITS file for full details.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+#include "squid.h"
+
+
+/* Local functions */
+
+void
+clientRedirectAccessCheckDone(int answer, void *data)
+{
+    clientHttpRequest *http = data;
+    http->acl_checklist = NULL;
+    if (answer == ACCESS_ALLOWED)
+	redirectStart(http, clientRedirectDone, http);
+    else
+	clientRedirectDone(http, NULL);
+}
+
+void
+clientRedirectStart(clientHttpRequest * http)
+{
+    debug(33, 5) ("clientRedirectStart: '%s'\n", http->uri);
+    if (Config.Program.url_rewrite.command == NULL) {
+	clientRedirectDone(http, NULL);
+	return;
+    }
+    if (Config.accessList.url_rewrite) {
+	http->acl_checklist = clientAclChecklistCreate(Config.accessList.url_rewrite, http);
+	aclNBCheck(http->acl_checklist, clientRedirectAccessCheckDone, http);
+    } else {
+	redirectStart(http, clientRedirectDone, http);
+    }
+}
+
+void
+clientRedirectDone(void *data, char *result)
+{
+    clientHttpRequest *http = data;
+    request_t *new_request = NULL;
+    request_t *old_request = http->request;
+    const char *urlgroup = http->conn->port->urlgroup;
+    debug(33, 5) ("clientRedirectDone: '%s' result=%s\n", http->uri,
+	result ? result : "NULL");
+    assert(http->redirect_state == REDIRECT_PENDING);
+    http->redirect_state = REDIRECT_DONE;
+    if (result) {
+	http_status status;
+	if (*result == '!') {
+	    char *t;
+	    if ((t = strchr(result + 1, '!')) != NULL) {
+		urlgroup = result + 1;
+		*t++ = '\0';
+		result = t;
+	    } else {
+		debug(33, 1) ("clientRedirectDone: bad input: %s\n", result);
+	    }
+	}
+	status = (http_status) atoi(result);
+	if (status == HTTP_MOVED_PERMANENTLY
+	    || status == HTTP_MOVED_TEMPORARILY
+	    || status == HTTP_SEE_OTHER
+	    || status == HTTP_TEMPORARY_REDIRECT) {
+	    char *t = result;
+	    if ((t = strchr(result, ':')) != NULL) {
+		http->redirect.status = status;
+		http->redirect.location = xstrdup(t + 1);
+		goto redirect_parsed;
+	    } else {
+		debug(33, 1) ("clientRedirectDone: bad input: %s\n", result);
+	    }
+	} else if (strcmp(result, http->uri))
+	    new_request = urlParse(old_request->method, result);
+    }
+  redirect_parsed:
+    if (new_request) {
+	safe_free(http->uri);
+	http->uri = xstrdup(urlCanonical(new_request));
+	new_request->http_ver = old_request->http_ver;
+	httpHeaderAppend(&new_request->header, &old_request->header);
+	new_request->client_addr = old_request->client_addr;
+	new_request->client_port = old_request->client_port;
+#if FOLLOW_X_FORWARDED_FOR
+	new_request->indirect_client_addr = old_request->indirect_client_addr;
+#endif /* FOLLOW_X_FORWARDED_FOR */
+	new_request->my_addr = old_request->my_addr;
+	new_request->my_port = old_request->my_port;
+	new_request->flags = old_request->flags;
+	new_request->flags.redirected = 1;
+	if (old_request->auth_user_request) {
+	    new_request->auth_user_request = old_request->auth_user_request;
+	    authenticateAuthUserRequestLock(new_request->auth_user_request);
+	}
+	if (old_request->body_reader) {
+	    new_request->body_reader = old_request->body_reader;
+	    new_request->body_reader_data = old_request->body_reader_data;
+	    old_request->body_reader = NULL;
+	    old_request->body_reader_data = NULL;
+	}
+	new_request->content_length = old_request->content_length;
+	if (strBuf(old_request->extacl_log))
+	    new_request->extacl_log = stringDup(&old_request->extacl_log);
+	if (old_request->extacl_user)
+	    new_request->extacl_user = xstrdup(old_request->extacl_user);
+	if (old_request->extacl_passwd)
+	    new_request->extacl_passwd = xstrdup(old_request->extacl_passwd);
+	requestUnlink(old_request);
+	http->request = requestLink(new_request);
+    } else {
+	/* Don't mess with urlgroup on internal request */
+	if (old_request->flags.internal)
+	    urlgroup = NULL;
+    }
+    safe_free(http->request->urlgroup);		/* only paranoia. should not happen */
+    if (urlgroup && *urlgroup)
+	http->request->urlgroup = xstrdup(urlgroup);
+    clientInterpretRequestHeaders(http);
+    /* XXX This really should become a ref-counted string type pointer, not a copy! */
+    fd_note(http->conn->fd, http->uri);
+
+    clientStoreURLRewriteStart(http);
+}
--- /dev/null	Wed Nov 28 01:20:24 2007
+++ squid/src/client_side_storeurl_rewrite.c	Wed Nov 28 01:20:25 2007
@@ -0,0 +1,92 @@
+
+/*
+ * $Id: client_side_storeurl_rewrite.c,v 1.3.2.2 2007/11/27 08:12:27 adri Exp $
+ *
+ * DEBUG: section 85    Client-side Routines - Store URL Rewriter
+ * AUTHOR: Duane Wessels; Adrian Chadd
+ *
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from
+ *  the Internet community; see the CONTRIBUTORS file for full
+ *  details.   Many organizations have provided support for Squid's
+ *  development; see the SPONSORS file for full details.  Squid is
+ *  Copyrighted (C) 2001 by the Regents of the University of
+ *  California; see the COPYRIGHT file for full details.  Squid
+ *  incorporates software developed and/or copyrighted by other
+ *  sources; see the CREDITS file for full details.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+#include "squid.h"
+
+
+/* Local functions */
+
+void
+clientStoreURLRewriteAccessCheckDone(int answer, void *data)
+{
+    clientHttpRequest *http = data;
+    http->acl_checklist = NULL;
+    if (answer == ACCESS_ALLOWED)
+	storeurlStart(http, clientStoreURLRewriteDone, http);
+    else
+	clientStoreURLRewriteDone(http, NULL);
+}
+
+void
+clientStoreURLRewriteStart(clientHttpRequest * http)
+{
+    debug(85, 5) ("clientStoreURLRewriteStart: '%s'\n", http->uri);
+    if (Config.Program.store_rewrite.command == NULL) {
+	clientStoreURLRewriteDone(http, NULL);
+	return;
+    }
+    if (Config.accessList.storeurl_rewrite) {
+	http->acl_checklist = clientAclChecklistCreate(Config.accessList.storeurl_rewrite, http);
+	aclNBCheck(http->acl_checklist, clientStoreURLRewriteAccessCheckDone, http);
+    } else {
+	storeurlStart(http, clientStoreURLRewriteDone, http);
+    }
+}
+
+void
+clientStoreURLRewriteDone(void *data, char *result)
+{
+    clientHttpRequest *http = data;
+
+    debug(85, 3) ("clientStoreURLRewriteDone: '%s' result=%s\n", http->uri,
+	result ? result : "NULL");
+#if 0
+    assert(http->redirect_state == REDIRECT_PENDING);
+    http->redirect_state = REDIRECT_DONE;
+#endif
+
+    if (result) {
+	http->request->store_url = xstrdup(result);
+	debug(85, 3) ("Rewrote to %s\n", http->request->store_url);
+	/* XXX is this actually the right spot to do this? How about revalidation? */
+	//storeEntrySetStoreUrl(http->entry, result);
+    }
+    /* This is the final part of the rewrite chain - this should be broken out! */
+    clientInterpretRequestHeaders(http);
+#if HEADERS_LOG
+    headersLog(0, 1, request->method, request);
+#endif
+    clientAccessCheck2(http);
+}
Index: squid/src/enums.h
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/enums.h,v
retrieving revision 1.62
retrieving revision 1.62.2.1
diff -u -r1.62 -r1.62.2.1
--- squid/src/enums.h	24 Sep 2007 13:52:08 -0000	1.62
+++ squid/src/enums.h	27 Nov 2007 08:12:27 -0000	1.62.2.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: enums.h,v 1.62 2007/09/24 13:52:08 squidadm Exp $
+ * $Id: enums.h,v 1.62.2.1 2007/11/27 08:12:27 adri Exp $
  *
  *
  * SQUID Web Proxy Cache          http://www.squid-cache.org/
@@ -52,6 +52,8 @@
     LOG_TCP_REDIRECT,
 #endif
     LOG_TCP_STALE_HIT,
+    LOG_TCP_ASYNC_HIT,
+    LOG_TCP_ASYNC_MISS,
     LOG_UDP_HIT,
     LOG_UDP_MISS,
     LOG_UDP_DENIED,
@@ -525,7 +527,7 @@
     ENTRY_REVALIDATE,
     DELAY_SENDING,
     RELEASE_REQUEST,
-    REFRESH_REQUEST,
+    REFRESH_FAILURE,
     ENTRY_CACHABLE,
     ENTRY_DISPATCHED,
     KEY_PRIVATE,
@@ -654,6 +656,7 @@
     STORE_META_VARY_HEADERS,	/* Stores Vary request headers */
     STORE_META_STD_LFS,		/* standard metadata in lfs format */
     STORE_META_OBJSIZE,		/* object size, if its known */
+    STORE_META_STOREURL,	/* the store url, if different to the normal URL */
     STORE_META_END
 };
 
Index: squid/src/errorpage.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/errorpage.c,v
retrieving revision 1.37
retrieving revision 1.37.6.1
diff -u -r1.37 -r1.37.6.1
--- squid/src/errorpage.c	26 Feb 2007 09:51:31 -0000	1.37
+++ squid/src/errorpage.c	27 Nov 2007 08:12:27 -0000	1.37.6.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: errorpage.c,v 1.37 2007/02/26 09:51:31 squidadm Exp $
+ * $Id: errorpage.c,v 1.37.6.1 2007/11/27 08:12:27 adri Exp $
  *
  * DEBUG: section 4     Error Generation
  * AUTHOR: Duane Wessels
@@ -324,7 +324,7 @@
     authenticateFixHeader(rep, err->auth_user_request, err->request, 0, 1);
     httpReplySwapOut(rep, entry);
     EBIT_CLR(entry->flags, ENTRY_FWD_HDR_WAIT);
-    storeNegativeCache(entry);
+    storeExpireNow(entry);
     storeReleaseRequest(entry);
     storeBufferFlush(entry);
     storeComplete(entry);
Index: squid/src/fqdncache.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/fqdncache.c,v
retrieving revision 1.22
retrieving revision 1.22.2.1
diff -u -r1.22 -r1.22.2.1
--- squid/src/fqdncache.c	17 Sep 2007 09:51:44 -0000	1.22
+++ squid/src/fqdncache.c	27 Nov 2007 08:12:27 -0000	1.22.2.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: fqdncache.c,v 1.22 2007/09/17 09:51:44 squidadm Exp $
+ * $Id: fqdncache.c,v 1.22.2.1 2007/11/27 08:12:27 adri Exp $
  *
  * DEBUG: section 35    FQDN Cache
  * AUTHOR: Harvest Derived
@@ -316,7 +316,7 @@
 	f->error_message = xstrdup("No PTR record");
 	return f;
     }
-    if (ttl == 0 || ttl > Config.positiveDnsTtl)
+    if (ttl > Config.positiveDnsTtl)
 	ttl = Config.positiveDnsTtl;
     if (ttl < Config.negativeDnsTtl)
 	ttl = Config.negativeDnsTtl;
Index: squid/src/helper.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/helper.c,v
retrieving revision 1.43
retrieving revision 1.43.6.1
diff -u -r1.43 -r1.43.6.1
--- squid/src/helper.c	1 Apr 2007 15:08:17 -0000	1.43
+++ squid/src/helper.c	27 Nov 2007 08:12:27 -0000	1.43.6.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: helper.c,v 1.43 2007/04/01 15:08:17 squidadm Exp $
+ * $Id: helper.c,v 1.43.6.1 2007/11/27 08:12:27 adri Exp $
  *
  * DEBUG: section 84    Helper process maintenance
  * AUTHOR: Harvest Derived?
@@ -1026,7 +1026,7 @@
 {
     helper *hlp = srv->parent;
     helper_request **ptr = NULL;
-    int slot;
+    int slot = -1;
     if (!cbdataValid(r->data)) {
 	debug(84, 1) ("helperDispatch: invalid callback data\n");
 	helperRequestFree(r);
@@ -1057,8 +1057,8 @@
 	    helperDispatch_done,	/* Handler */
 	    srv);
     }
-    debug(84, 5) ("helperDispatch: Request sent to %s #%d, %d bytes\n",
-	hlp->id_name, srv->index + 1, (int) strlen(r->buf));
+    debug(84, 5) ("helperDispatch: Request sent to %s #%d[%d], %d bytes\n",
+	hlp->id_name, srv->index + 1, slot, (int) strlen(r->buf));
     srv->stats.uses++;
     hlp->stats.requests++;
 }
Index: squid/src/http.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/http.c,v
retrieving revision 1.63
retrieving revision 1.63.2.1
diff -u -r1.63 -r1.63.2.1
--- squid/src/http.c	3 Sep 2007 04:49:47 -0000	1.63
+++ squid/src/http.c	27 Nov 2007 08:12:28 -0000	1.63.2.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: http.c,v 1.63 2007/09/03 04:49:47 squidadm Exp $
+ * $Id: http.c,v 1.63.2.1 2007/11/27 08:12:28 adri Exp $
  *
  * DEBUG: section 11    Hypertext Transfer Protocol (HTTP)
  * AUTHOR: Harvest Derived
@@ -131,6 +131,8 @@
     storeNegativeCache(entry);
     if (EBIT_TEST(entry->flags, ENTRY_CACHABLE))
 	storeSetPublicKey(entry);
+    if (entry->expires <= squid_curtime)
+	storeRelease(entry);
 }
 
 static void
@@ -432,7 +434,7 @@
 	debug(11, 3) ("httpProcessReplyHeader: Non-HTTP-compliant header: '%s'\n", httpState->reply_hdr.buf);
 	httpState->reply_hdr_state += 2;
 	httpState->chunk_size = -1;	/* Terminated by EOF */
-	memBufClean(&httpState->reply_hdr);
+	httpState->reply_hdr.size = old_size;
 	httpBuildVersion(&reply->sline.version, 0, 9);
 	reply->sline.status = HTTP_INVALID_HEADER;
 	ctx_exit(ctx);
@@ -506,8 +508,8 @@
 	stringClean(&tr);
 	if (httpState->flags.chunked && reply->content_length >= 0) {
 	    /* Can't have a content-length in chunked encoding */
-	    reply->sline.status = HTTP_INVALID_HEADER;
-	    return done;
+	    reply->content_length = -1;
+	    httpHeaderDelById(&reply->header, HDR_CONTENT_LENGTH);
 	}
     }
     if (!httpState->flags.chunked) {
@@ -530,6 +532,8 @@
 	if (strBuf(httpState->orig_request->vary_encoding))
 	    entry->mem_obj->vary_encoding = xstrdup(strBuf(httpState->orig_request->vary_encoding));
     }
+    if (entry->mem_obj->old_entry)
+	EBIT_CLR(entry->mem_obj->old_entry->flags, REFRESH_FAILURE);
     switch (httpCachableReply(httpState)) {
     case 1:
 	httpMakePublic(entry);
@@ -538,10 +542,7 @@
 	httpMakePrivate(entry);
 	break;
     case -1:
-	if (Config.negativeTtl > 0)
-	    httpCacheNegatively(entry);
-	else
-	    httpMakePrivate(entry);
+	httpCacheNegatively(entry);
 	break;
     default:
 	assert(0);
@@ -955,6 +956,8 @@
 		    httpHeaderPutTime(&reply->header, HDR_DATE, squid_curtime);
 		    mb = httpReplyPack(reply);
 		    storeAppend(entry, mb.buf, mb.size);
+		    storeAppend(entry, httpState->reply_hdr.buf, httpState->reply_hdr.size);
+		    memBufClean(&httpState->reply_hdr);
 		    httpReplyReset(reply);
 		    httpReplyParse(reply, mb.buf, mb.size);
 		    memBufClean(&mb);
@@ -1145,13 +1148,14 @@
 	    /* append unless we added our own;
 	     * note: at most one client's ims header can pass through */
 	    if (!httpHeaderHas(hdr_out, HDR_IF_MODIFIED_SINCE))
-		httpHeaderAddClone(hdr_out, e);
+		if (!Config.onoff.ignore_ims_on_miss || !orig_request->flags.cachable || orig_request->flags.auth)
+		    httpHeaderAddClone(hdr_out, e);
 	    break;
 	case HDR_IF_NONE_MATCH:
-	    /* append unless we added our own;
-	     * note: at most one client's ims header can pass through */
+	    /* append unless ignore_ims_on_miss is in effect */
 	    if (!httpHeaderHas(hdr_out, HDR_IF_NONE_MATCH))
-		httpHeaderAddClone(hdr_out, e);
+		if (!Config.onoff.ignore_ims_on_miss || !orig_request->flags.cachable || orig_request->flags.auth)
+		    httpHeaderAddClone(hdr_out, e);
 	    break;
 	case HDR_MAX_FORWARDS:
 	    if (orig_request->method == METHOD_TRACE) {
@@ -1253,10 +1257,10 @@
 	    /* Special mode, to pass the username to the upstream cache */
 	    char loginbuf[256];
 	    const char *username = "-";
-	    if (orig_request->auth_user_request)
-		username = authenticateUserRequestUsername(orig_request->auth_user_request);
-	    else if (orig_request->extacl_user)
+	    if (orig_request->extacl_user)
 		username = orig_request->extacl_user;
+	    else if (orig_request->auth_user_request)
+		username = authenticateUserRequestUsername(orig_request->auth_user_request);
 	    snprintf(loginbuf, sizeof(loginbuf), "%s%s", username, orig_request->peer_login + 1);
 	    httpHeaderPutStrf(hdr_out, HDR_PROXY_AUTHORIZATION, "Basic %s",
 		base64_encode(loginbuf));
Index: squid/src/ipcache.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/ipcache.c,v
retrieving revision 1.25
retrieving revision 1.25.2.1
diff -u -r1.25 -r1.25.2.1
--- squid/src/ipcache.c	17 Sep 2007 09:51:44 -0000	1.25
+++ squid/src/ipcache.c	27 Nov 2007 08:12:28 -0000	1.25.2.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: ipcache.c,v 1.25 2007/09/17 09:51:44 squidadm Exp $
+ * $Id: ipcache.c,v 1.25.2.1 2007/11/27 08:12:28 adri Exp $
  *
  * DEBUG: section 14    IP Cache
  * AUTHOR: Harvest Derived
@@ -369,7 +369,7 @@
 	i->addrs.count = (unsigned char) na;
     else
 	i->addrs.count = 255;
-    if (ttl == 0 || ttl > Config.positiveDnsTtl)
+    if (ttl > Config.positiveDnsTtl)
 	ttl = Config.positiveDnsTtl;
     if (ttl < Config.negativeDnsTtl)
 	ttl = Config.negativeDnsTtl;
Index: squid/src/main.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/main.c,v
retrieving revision 1.80
retrieving revision 1.80.2.1
diff -u -r1.80 -r1.80.2.1
--- squid/src/main.c	24 Sep 2007 13:52:09 -0000	1.80
+++ squid/src/main.c	27 Nov 2007 08:12:28 -0000	1.80.2.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: main.c,v 1.80 2007/09/24 13:52:09 squidadm Exp $
+ * $Id: main.c,v 1.80.2.1 2007/11/27 08:12:28 adri Exp $
  *
  * DEBUG: section 1     Startup and Main Loop
  * AUTHOR: Harvest Derived
@@ -396,9 +396,11 @@
     idnsShutdown();
 #endif
     redirectShutdown();
+    storeurlShutdown();
     locationRewriteShutdown();
     authenticateShutdown();
     externalAclShutdown();
+    refreshCheckShutdown();
     storeDirCloseSwapLogs();
     storeLogClose();
     accessLogClose();
@@ -425,9 +427,11 @@
     idnsInit();
 #endif
     redirectInit();
+    storeurlInit();
     locationRewriteInit();
     authenticateInit(&Config.authConfig);
     externalAclInit();
+    refreshCheckInit();
 #if USE_WCCP
     wccpInit();
 #endif
@@ -463,6 +467,7 @@
     locationRewriteShutdown();
     authenticateShutdown();
     externalAclShutdown();
+    refreshCheckShutdown();
     _db_rotate_log();		/* cache.log */
     storeDirWriteCleanLogs(1);
     storeDirSync();		/* Flush pending I/O ops */
@@ -478,9 +483,11 @@
     dnsInit();
 #endif
     redirectInit();
+    storeurlInit();
     locationRewriteInit();
     authenticateInit(&Config.authConfig);
     externalAclInit();
+    refreshCheckInit();
 }
 
 static void
@@ -576,10 +583,12 @@
     idnsInit();
 #endif
     redirectInit();
+    storeurlInit();
     locationRewriteInit();
     errorMapInit();
     authenticateInit(&Config.authConfig);
     externalAclInit();
+    refreshCheckInit();
     useragentOpenLog();
     refererOpenLog();
     httpHeaderInitModule();	/* must go before any header processing (e.g. the one in errorInitialize) */
@@ -715,7 +724,9 @@
 #endif
     mainParseOptions(argc, argv);
 
+#if HAVE_SYSLOG && defined(LOG_LOCAL4)
     openlog(appname, LOG_PID | LOG_NDELAY | LOG_CONS, syslog_facility);
+#endif
 
 #if defined(USE_WIN32_SERVICE) && defined(_SQUID_WIN32_)
     if (opt_install_service) {
@@ -1087,6 +1098,7 @@
 #endif
     redirectShutdown();
     externalAclShutdown();
+    refreshCheckShutdown();
     locationRewriteShutdown();
     icpConnectionClose();
 #if USE_HTCP
Index: squid/src/mib.txt
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/mib.txt,v
retrieving revision 1.9
retrieving revision 1.9.4.1
diff -u -r1.9 -r1.9.4.1
--- squid/src/mib.txt	27 Aug 2007 13:53:41 -0000	1.9
+++ squid/src/mib.txt	27 Nov 2007 08:12:28 -0000	1.9.4.1
@@ -2,7 +2,7 @@
 
 SQUID-MIB DEFINITIONS ::= BEGIN
 --
--- $Id: mib.txt,v 1.9 2007/08/27 13:53:41 squidadm Exp $
+-- $Id: mib.txt,v 1.9.4.1 2007/11/27 08:12:28 adri Exp $
 --
 
 IMPORTS
@@ -715,7 +715,7 @@
 		MAX-ACCESS not-accessible
 		STATUS current
 		DESCRIPTION
-			" An entry in cachePeerTable "
+			" cache_peer indexed by IP address "
 		INDEX 	{ cachePeerAddr }
 	::= { cachePeerTable 1 }
 
@@ -724,7 +724,7 @@
 		MAX-ACCESS not-accessible
 		STATUS current
 		DESCRIPTION
-			" An entry in cachePeerTable "
+			" cache_peer indexed by position in squid.conf "
 		INDEX 	{ cachePeerIndex }
 	::= { cachePeerTable 2 }
 
Index: squid/src/protos.h
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/protos.h,v
retrieving revision 1.146.2.3
retrieving revision 1.146.2.4
diff -u -r1.146.2.3 -r1.146.2.4
--- squid/src/protos.h	27 Sep 2007 15:09:17 -0000	1.146.2.3
+++ squid/src/protos.h	27 Nov 2007 08:12:28 -0000	1.146.2.4
@@ -1,6 +1,6 @@
 
 /*
- * $Id: protos.h,v 1.146.2.3 2007/09/27 15:09:17 adri Exp $
+ * $Id: protos.h,v 1.146.2.4 2007/11/27 08:12:28 adri Exp $
  *
  *
  * SQUID Web Proxy Cache          http://www.squid-cache.org/
@@ -747,6 +747,10 @@
 extern void redirectInit(void);
 extern void redirectShutdown(void);
 
+extern void storeurlStart(clientHttpRequest *, RH *, void *);
+extern void storeurlInit(void);
+extern void storeurlShutdown(void);
+
 extern void locationRewriteStart(HttpReply *, clientHttpRequest *, RH *, void *);
 extern void locationRewriteInit(void);
 extern void locationRewriteShutdown(void);
@@ -796,9 +800,11 @@
 extern int refreshIsCachable(const StoreEntry *);
 extern int refreshCheckHTTP(const StoreEntry *, request_t *);
 extern int refreshCheckHTTPStale(const StoreEntry *, request_t *);
+extern int refreshCheckStaleOK(const StoreEntry *, request_t *);
 extern int refreshCheckICP(const StoreEntry *, request_t *);
 extern int refreshCheckHTCP(const StoreEntry *, request_t *);
 extern int refreshCheckDigest(const StoreEntry *, time_t delta);
+extern refresh_cc refreshCC(const StoreEntry *, request_t *);
 extern time_t getMaxAge(const char *url);
 extern void refreshInit(void);
 extern const refresh_t *refreshLimits(const char *url);
@@ -911,6 +917,7 @@
  * store.c
  */
 extern StoreEntry *new_StoreEntry(int, const char *);
+extern void storeEntrySetStoreUrl(StoreEntry * e, const char *store_url);
 extern StoreEntry *storeGet(const cache_key *);
 extern StoreEntry *storeGetPublic(const char *uri, const method_t method);
 extern StoreEntry *storeGetPublicByRequest(request_t * request);
@@ -924,6 +931,7 @@
 extern void storeLockObjectDebug(StoreEntry *, const char *file, const int line);
 extern void storeRelease(StoreEntry *);
 extern int storeUnlockObjectDebug(StoreEntry *, const char *file, const int line);
+extern const char *storeLookupUrl(const StoreEntry * e);
 #define	storeLockObject(a) storeLockObjectDebug(a, __FILE__, __LINE__);
 #define	storeUnlockObject(a) storeUnlockObjectDebug(a, __FILE__, __LINE__);
 extern EVH storeMaintainSwapSpace;
@@ -970,6 +978,7 @@
 void storeResumeRead(StoreEntry *);
 void storeResetDefer(StoreEntry *);
 extern int memHaveHeaders(const MemObject * mem);
+extern void storeUpdate(StoreEntry * e, request_t *);
 
 
 /* store_modules.c */
@@ -1091,6 +1100,7 @@
 extern store_client *storeClientRegister(StoreEntry * e, void *data);
 extern void storeClientCopy(store_client *, StoreEntry *, squid_off_t, squid_off_t, size_t, char *, STCB *, void *);
 extern void storeClientRef(store_client *, StoreEntry *, squid_off_t, squid_off_t, size_t, STNCB *, void *);
+extern void storeClientCopyHeaders(store_client *, StoreEntry *, STHCB *, void *);
 extern int storeClientCopyPending(store_client *, StoreEntry * e, void *data);
 extern int storeClientUnregister(store_client * sc, StoreEntry * e, void *data);
 extern squid_off_t storeLowestMemReaderOffset(const StoreEntry * entry);
@@ -1415,6 +1425,15 @@
 const char *externalAclMessage(external_acl_entry * entry);
 
 
+/* refresh_check.c */
+extern void parse_refreshCheckHelper(refresh_check_helper **);
+extern void dump_refreshCheckHelper(StoreEntry * sentry, const char *name, const refresh_check_helper *);
+extern void free_refreshCheckHelper(refresh_check_helper **);
+extern void refreshCheckSubmit(StoreEntry * entry, REFRESHCHECK * callback, void *data);
+extern void refreshCheckInit(void);
+extern void refreshCheckConfigure(void);
+extern void refreshCheckShutdown(void);
+
 #if USE_WCCPv2
 extern void parse_wccp2_service(void *v);
 extern void free_wccp2_service(void *v);
@@ -1448,5 +1467,20 @@
 
 extern const char *xinet_ntoa(const struct in_addr addr);
 
+/* client_side.c */
+extern aclCheck_t *clientAclChecklistCreate(const acl_access * acl, const clientHttpRequest * http);
+extern void clientInterpretRequestHeaders(clientHttpRequest * http);
+extern void clientAccessCheck2(void *data);
+
+/* client_side_redirect.c */
+extern void clientRedirectAccessCheckDone(int answer, void *data);
+extern void clientRedirectStart(clientHttpRequest * http);
+extern void clientRedirectDone(void *data, char *result);
+
+/* client_side_storeurl_rewrite.c */
+extern void clientStoreURLRewriteAccessCheckDone(int answer, void *data);
+extern void clientStoreURLRewriteStart(clientHttpRequest * http);
+extern void clientStoreURLRewriteDone(void *data, char *result);
+
 
 #endif /* SQUID_PROTOS_H */
Index: squid/src/redirect.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/redirect.c,v
retrieving revision 1.16
retrieving revision 1.16.10.1
diff -u -r1.16 -r1.16.10.1
--- squid/src/redirect.c	1 Feb 2007 09:51:50 -0000	1.16
+++ squid/src/redirect.c	27 Nov 2007 08:12:28 -0000	1.16.10.1
@@ -1,9 +1,9 @@
 
 /*
- * $Id: redirect.c,v 1.16 2007/02/01 09:51:50 squidadm Exp $
+ * $Id: redirect.c,v 1.16.10.1 2007/11/27 08:12:28 adri Exp $
  *
- * DEBUG: section 61    Redirector
- * AUTHOR: Duane Wessels
+ * DEBUG: section 85   Store URL Redirector
+ * AUTHOR: Adrian Chadd; based on redirect.c by Duane Wessels
  *
  * SQUID Web Proxy Cache          http://www.squid-cache.org/
  * ----------------------------------------------------------
@@ -98,6 +98,8 @@
     const char *fqdn;
     char *urlgroup = conn->port->urlgroup;
     char buf[8192];
+    char claddr[20];
+    char myaddr[20];
     assert(http);
     assert(handler);
     debug(61, 5) ("redirectStart: '%s'\n", http->uri);
@@ -130,13 +132,17 @@
     cbdataLock(r->data);
     if ((fqdn = fqdncache_gethostbyaddr(r->client_addr, 0)) == NULL)
 	fqdn = dash_str;
-    snprintf(buf, 8191, "%s %s/%s %s %s %s",
+    xstrncpy(claddr, inet_ntoa(r->client_addr), 20);
+    xstrncpy(myaddr, inet_ntoa(http->request->my_addr), 20);
+    snprintf(buf, 8191, "%s %s/%s %s %s %s myip=%s myport=%d",
 	r->orig_url,
-	inet_ntoa(r->client_addr),
+	claddr,
 	fqdn,
 	r->client_ident[0] ? rfc1738_escape(r->client_ident) : dash_str,
 	r->method_s,
-	urlgroup ? urlgroup : "-");
+	urlgroup ? urlgroup : "-",
+	myaddr,
+	http->request->my_port);
     debug(61, 6) ("redirectStart: sending '%s' to the helper\n", buf);
     strcat(buf, "\n");
     helperSubmit(redirectors, buf, redirectHandleReply, r);
Index: squid/src/refresh.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/refresh.c,v
retrieving revision 1.15
retrieving revision 1.15.6.1
diff -u -r1.15 -r1.15.6.1
--- squid/src/refresh.c	24 May 2007 01:51:31 -0000	1.15
+++ squid/src/refresh.c	27 Nov 2007 08:12:28 -0000	1.15.6.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: refresh.c,v 1.15 2007/05/24 01:51:31 squidadm Exp $
+ * $Id: refresh.c,v 1.15.6.1 2007/11/27 08:12:28 adri Exp $
  *
  * DEBUG: section 22    Refresh Calculation
  * AUTHOR: Harvest Derived
@@ -81,6 +81,8 @@
     STALE_MAX_RULE,
     STALE_LMFACTOR_RULE,
     STALE_WITHIN_DELTA,
+    STALE_ASYNC_REFRESH,
+    STALE_MAX_STALE,
     STALE_DEFAULT = 299
 };
 
@@ -128,6 +130,30 @@
     return NULL;
 }
 
+refresh_cc
+refreshCC(const StoreEntry * entry, request_t * request)
+{
+    const refresh_t *R;
+    const char *uri = NULL;
+    refresh_cc cc;
+    cc.negative_ttl = Config.negativeTtl;
+    cc.max_stale = Config.maxStale;
+    if (entry->mem_obj)
+	uri = entry->mem_obj->url;
+    else if (request)
+	uri = urlCanonical(request);
+
+    R = uri ? refreshLimits(uri) : refreshUncompiledPattern(".");
+
+    if (R && R->negative_ttl >= 0)
+	cc.negative_ttl = R->negative_ttl;
+
+    if (R && R->max_stale >= 0)
+	cc.max_stale = R->max_stale;
+
+    return cc;
+}
+
 /*
  * Calculate how stale the response is (or will be at the check_time).
  * Staleness calculation is based on the following: (1) response
@@ -308,6 +334,20 @@
      * At this point the response is stale, unless one of
      * the override options kicks in.
      */
+    if (entry->mem_obj) {
+	int stale_while_revalidate = R->stale_while_revalidate;
+	if (staleness < stale_while_revalidate) {
+	    debug(22, 3) ("stale-while-revalidate: age=%d, staleness=%d, stale_while_revalidate=%d\n", (int) age, staleness, stale_while_revalidate);
+	    entry->mem_obj->stale_while_revalidate = stale_while_revalidate;
+	    return STALE_ASYNC_REFRESH;
+	}
+    } {
+	int max_stale = Config.maxStale;
+	if (R->max_stale >= 0)
+	    max_stale = R->max_stale;
+	if (max_stale >= 0 && staleness >= max_stale)
+	    return STALE_MAX_STALE;
+    }
     if (delta < 0 && staleness + delta < 0) {
 	return STALE_WITHIN_DELTA;
     }
@@ -382,10 +422,25 @@
     int reason = refreshCheck(entry, request, -Config.refresh_stale_window);
     if (reason == STALE_WITHIN_DELTA)
 	return -1;
+    if (reason == STALE_ASYNC_REFRESH)
+	return -2;
+    if (reason == STALE_MAX_STALE)
+	return 3;
     return (reason < 200) ? 0 : 1;
 }
 
 int
+refreshCheckStaleOK(const StoreEntry * entry, request_t * request)
+{
+    int reason = refreshCheck(entry, request, 0);
+    if (reason == STALE_MUST_REVALIDATE)
+	return 0;
+    if (reason == STALE_MAX_STALE)
+	return 0;
+    return 1;
+}
+
+int
 refreshCheckICP(const StoreEntry * entry, request_t * request)
 {
     int reason = refreshCheck(entry, request, 30);
@@ -472,6 +527,12 @@
 	"Stale: refresh_pattern max age rule");
     refreshCountsStatsEntry(STALE_LMFACTOR_RULE,
 	"Stale: refresh_pattern last-mod factor percentage");
+    refreshCountsStatsEntry(STALE_WITHIN_DELTA,
+	"Staĺe: but within a certain delta");
+    refreshCountsStatsEntry(STALE_ASYNC_REFRESH,
+	"Stale: suitable for an async refresh");
+    refreshCountsStatsEntry(STALE_MAX_STALE,
+	"Stale: max-stale");
     refreshCountsStatsEntry(STALE_DEFAULT,
 	"Stale: by default");
 
--- /dev/null	Wed Nov 28 01:20:24 2007
+++ squid/src/refresh_check.c	Wed Nov 28 01:20:25 2007
@@ -0,0 +1,550 @@
+
+/*
+ * $Id: refresh_check.c,v 1.2.4.2 2007/11/27 08:12:28 adri Exp $
+ *
+ * DEBUG: section 84    Refresh Check Helper
+ * AUTHOR: Henrik Nordstrom
+ *
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ *  The contents of this file is Copyright (C) 2007 by Henrik Nordstrom,
+ *  Sweden, unless otherwise is indicated in the specific function. The
+ *  author gives his full permission to include this file into the Squid
+ *  software product under the terms of the GNU General Public License as
+ *  published by the Free Software Foundation; either version 2 of the
+ *  License, or (at your option) any later version.
+ *
+ *  Squid is the result of efforts by numerous individuals from
+ *  the Internet community; see the CONTRIBUTORS file for full
+ *  details.   Many organizations have provided support for Squid's
+ *  development; see the SPONSORS file for full details.  Squid is
+ *  Copyrighted (C) 2001 by the Regents of the University of
+ *  California; see the COPYRIGHT file for full details.  Squid
+ *  incorporates software developed and/or copyrighted by other
+ *  sources; see the CREDITS file for full details.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ * Partially based on the External ACL implementation.
+ */
+
+#include "squid.h"
+
+#ifndef DEFAULT_REFRESH_CHECK_CHILDREN
+#define DEFAULT_REFRESH_CHECK_CHILDREN 5
+#endif
+
+/******************************************************************
+ * external_refresh_check parser
+ */
+typedef struct _refresh_check_format refresh_check_format;
+
+struct _refresh_check_helper {
+    refresh_check_format *format;
+    wordlist *cmdline;
+    int children;
+    int concurrency;
+    helper *helper;
+    dlink_list queue;
+};
+
+struct _refresh_check_format {
+    enum {
+	REFRESH_CHECK_UNKNOWN,
+	REFRESH_CHECK_URI,
+	REFRESH_CHECK_RESP_HEADER,
+	REFRESH_CHECK_RESP_HEADER_MEMBER,
+	REFRESH_CHECK_RESP_HEADER_ID,
+	REFRESH_CHECK_RESP_HEADER_ID_MEMBER,
+	REFRESH_CHECK_AGE,
+	REFRESH_CHECK_END
+    } type;
+    refresh_check_format *next;
+    char *header;
+    char *member;
+    char separator;
+    http_hdr_type header_id;
+};
+
+/* FIXME: These are not really cbdata, but it is an easy way
+ * to get them pooled, refcounted, accounted and freed properly...
+ */
+CBDATA_TYPE(refresh_check_helper);
+CBDATA_TYPE(refresh_check_format);
+
+static void
+free_refresh_check_format(void *data)
+{
+    refresh_check_format *p = data;
+    safe_free(p->header);
+}
+
+static void
+free_refresh_check_helper(void *data)
+{
+    refresh_check_helper *p = data;
+    while (p->format) {
+	refresh_check_format *f = p->format;
+	p->format = f->next;
+	cbdataFree(f);
+    }
+    wordlistDestroy(&p->cmdline);
+    if (p->helper) {
+	helperShutdown(p->helper);
+	helperFree(p->helper);
+	p->helper = NULL;
+    }
+}
+
+void
+parse_refreshCheckHelper(refresh_check_helper ** ptr)
+{
+    refresh_check_helper *a;
+    char *token;
+    refresh_check_format **p;
+
+    if (*ptr)
+	self_destruct();
+
+    CBDATA_INIT_TYPE_FREECB(refresh_check_helper, free_refresh_check_helper);
+    CBDATA_INIT_TYPE_FREECB(refresh_check_format, free_refresh_check_format);
+
+    a = cbdataAlloc(refresh_check_helper);
+
+    a->children = DEFAULT_REFRESH_CHECK_CHILDREN;
+
+    /* Parse options */
+    while ((token = strtok(NULL, w_space)) != NULL) {
+	if (strncmp(token, "children=", 9) == 0) {
+	    a->children = atoi(token + 9);
+	} else if (strncmp(token, "concurrency=", 12) == 0) {
+	    a->concurrency = atoi(token + 12);
+	} else {
+	    break;
+	}
+    }
+
+    /* Parse format */
+    p = &a->format;
+    while (token) {
+	refresh_check_format *format;
+
+	/* stop on first non-format token found */
+	if (*token != '%')
+	    break;
+
+	format = cbdataAlloc(refresh_check_format);
+
+	if (strncmp(token, "%RES{", 5) == 0) {
+	    /* header format */
+	    char *header, *member, *end;
+	    header = token + 5;
+	    end = strchr(header, '}');
+	    /* cut away the terminating } */
+	    if (end && strlen(end) == 1)
+		*end = '\0';
+	    else
+		self_destruct();
+
+	    member = strchr(header, ':');
+	    if (member) {
+		/* Split in header and member */
+		*member++ = '\0';
+		if (!xisalnum(*member))
+		    format->separator = *member++;
+		else
+		    format->separator = ',';
+		format->member = xstrdup(member);
+		format->type = REFRESH_CHECK_RESP_HEADER_MEMBER;
+	    } else {
+		format->type = REFRESH_CHECK_RESP_HEADER;
+	    }
+	    format->header = xstrdup(header);
+	    format->header_id = httpHeaderIdByNameDef(header, strlen(header));
+	    if (format->header_id != -1) {
+		if (member)
+		    format->type = REFRESH_CHECK_RESP_HEADER_ID_MEMBER;
+		else
+		    format->type = REFRESH_CHECK_RESP_HEADER_ID;
+	    }
+	} else if (strcmp(token, "%URI") == 0)
+	    format->type = REFRESH_CHECK_URI;
+	else if (strcmp(token, "%URL") == 0)
+	    format->type = REFRESH_CHECK_URI;
+	else if (strcmp(token, "%CACHE_URI") == 0)
+	    format->type = REFRESH_CHECK_URI;
+	else if (strcmp(token, "%AGE") == 0)
+	    format->type = REFRESH_CHECK_AGE;
+	else {
+	    self_destruct();
+	}
+	*p = format;
+	p = &format->next;
+	token = strtok(NULL, w_space);
+    }
+    /* There must be at least one format token */
+    if (!a->format)
+	self_destruct();
+
+    /* helper */
+    if (!token)
+	self_destruct();
+    wordlistAdd(&a->cmdline, token);
+
+    /* arguments */
+    parse_wordlist(&a->cmdline);
+
+    *ptr = a;
+}
+
+void
+dump_refreshCheckHelper(StoreEntry * sentry, const char *name, const refresh_check_helper * list)
+{
+    const refresh_check_helper *node = list;
+    const refresh_check_format *format;
+    const wordlist *word;
+    if (node) {
+	storeAppendPrintf(sentry, "%s", name);
+	if (node->children != DEFAULT_REFRESH_CHECK_CHILDREN)
+	    storeAppendPrintf(sentry, " children=%d", node->children);
+	if (node->concurrency)
+	    storeAppendPrintf(sentry, " concurrency=%d", node->concurrency);
+	for (format = node->format; format; format = format->next) {
+	    switch (format->type) {
+	    case REFRESH_CHECK_RESP_HEADER:
+	    case REFRESH_CHECK_RESP_HEADER_ID:
+		storeAppendPrintf(sentry, " %%{%s}", format->header);
+		break;
+	    case REFRESH_CHECK_RESP_HEADER_MEMBER:
+	    case REFRESH_CHECK_RESP_HEADER_ID_MEMBER:
+		storeAppendPrintf(sentry, " %%{%s:%s}", format->header, format->member);
+		break;
+#define DUMP_REFRESH_CHECK_TYPE(a) \
+	    case REFRESH_CHECK_##a: \
+		storeAppendPrintf(sentry, " %%%s", #a); \
+		break
+		DUMP_REFRESH_CHECK_TYPE(URI);
+		DUMP_REFRESH_CHECK_TYPE(AGE);
+	    case REFRESH_CHECK_UNKNOWN:
+	    case REFRESH_CHECK_END:
+		fatal("unknown refresh_check format error");
+		break;
+	    }
+	}
+	for (word = node->cmdline; word; word = word->next)
+	    storeAppendPrintf(sentry, " %s", word->key);
+	storeAppendPrintf(sentry, "\n");
+    }
+}
+
+void
+free_refreshCheckHelper(refresh_check_helper ** list)
+{
+    while (*list) {
+	refresh_check_helper *node = *list;
+	*list = NULL;
+	cbdataFree(node);
+    }
+}
+
+/******************************************************************
+ * refresh_check runtime
+ */
+
+static inline int
+refreshCheckOverload(refresh_check_helper * def)
+{
+    return def->helper->stats.queue_size > def->helper->n_running;
+}
+
+static char *
+makeRefreshCheckRequest(StoreEntry * entry, refresh_check_format * format)
+{
+    static MemBuf mb = MemBufNULL;
+    int first = 1;
+    HttpReply *reply;
+    String sb = StringNull;
+
+    if (!entry->mem_obj)
+	return NULL;
+
+    reply = entry->mem_obj->reply;
+    memBufReset(&mb);
+    for (; format; format = format->next) {
+	char buf[256];
+	const char *str = NULL;
+	const char *quoted;
+	switch (format->type) {
+	case REFRESH_CHECK_URI:
+	    str = entry->mem_obj->url;
+	    break;
+	case REFRESH_CHECK_AGE:
+	    snprintf(buf, sizeof(buf), "%ld", (long int) (squid_curtime - entry->timestamp));
+	    str = buf;
+	    break;
+	case REFRESH_CHECK_RESP_HEADER:
+	    sb = httpHeaderGetByName(&reply->header, format->header);
+	    str = strBuf(sb);
+	    break;
+	case REFRESH_CHECK_RESP_HEADER_ID:
+	    sb = httpHeaderGetStrOrList(&reply->header, format->header_id);
+	    str = strBuf(sb);
+	    break;
+	case REFRESH_CHECK_RESP_HEADER_MEMBER:
+	    sb = httpHeaderGetByNameListMember(&reply->header, format->header, format->member, format->separator);
+	    str = strBuf(sb);
+	    break;
+	case REFRESH_CHECK_RESP_HEADER_ID_MEMBER:
+	    sb = httpHeaderGetListMember(&reply->header, format->header_id, format->member, format->separator);
+	    str = strBuf(sb);
+	    break;
+
+	case REFRESH_CHECK_UNKNOWN:
+	case REFRESH_CHECK_END:
+	    fatal("unknown refresh_check_program format error");
+	    break;
+	}
+	if (!str || !*str)
+	    str = "-";
+	if (!first)
+	    memBufAppend(&mb, " ", 1);
+	quoted = rfc1738_escape(str);
+	memBufAppend(&mb, quoted, strlen(quoted));
+	stringClean(&sb);
+	first = 0;
+    }
+    return mb.buf;
+}
+
+/******************************************************************
+ * refresh_check requests
+ */
+
+typedef struct _refreshCheckState refreshCheckState;
+struct _refreshCheckState {
+    REFRESHCHECK *callback;
+    void *callback_data;
+    StoreEntry *entry;
+    refresh_check_helper *def;
+    dlink_node list;
+    refreshCheckState *queue;
+};
+
+CBDATA_TYPE(refreshCheckState);
+static void
+free_refreshCheckState(void *data)
+{
+    refreshCheckState *state = data;
+    storeUnlockObject(state->entry);
+    cbdataUnlock(state->callback_data);
+    cbdataUnlock(state->def);
+}
+
+/*
+ * The helper program receives queries on stdin, one
+ * per line, and must return the result on on stdout
+ */
+static void
+refreshCheckHandleReply(void *data, char *reply)
+{
+    refreshCheckState *state = data;
+    refreshCheckState *next;
+    int freshness = -1;
+    char *log = NULL;
+    MemBuf hdrs = MemBufNULL;
+
+
+    debug(84, 2) ("refreshCheckHandleReply: reply=\"%s\"\n", reply);
+
+    if (reply) {
+	char *t = NULL;
+	char *token = strwordtok(reply, &t);
+	if (token && strcmp(token, "FRESH") == 0)
+	    freshness = 0;
+	else if (token && strcmp(token, "OK") == 0)
+	    freshness = 0;
+
+	while ((token = strwordtok(NULL, &t))) {
+	    char *value = strchr(token, '=');
+	    if (value) {
+		*value++ = '\0';	/* terminate the token, and move up to the value */
+		rfc1738_unescape(value);
+		if (strcmp(token, "freshness") == 0)
+		    freshness = atoi(value);
+		else if (strcmp(token, "log") == 0)
+		    log = value;
+		else if (strncmp(token, "res{", 4) == 0) {
+		    char *header, *t;
+		    header = token + 4;
+		    t = strrchr(header, '}');
+		    if (!t)
+			continue;
+		    *t = '\0';
+		    if (!hdrs.buf)
+			memBufDefInit(&hdrs);
+		    memBufPrintf(&hdrs, "%s: %s\r\n", header, value);
+		}
+	    }
+	}
+    }
+    if (freshness >= 0) {
+	if (hdrs.size) {
+	    HttpReply *rep = httpReplyCreate();
+	    httpHeaderParse(&rep->header, hdrs.buf, hdrs.buf + hdrs.size);
+	    httpReplyUpdateOnNotModified(state->entry->mem_obj->reply, rep);
+	    storeTimestampsSet(state->entry);
+	    if (!httpHeaderHas(&rep->header, HDR_DATE)) {
+		state->entry->timestamp = squid_curtime;
+		state->entry->expires = squid_curtime + freshness;
+	    } else if (freshness) {
+		state->entry->expires = squid_curtime + freshness;
+	    }
+	    httpReplyDestroy(rep);
+	    storeUpdate(state->entry, NULL);
+	} else {
+	    state->entry->timestamp = squid_curtime;
+	    state->entry->expires = squid_curtime + freshness;
+	}
+    }
+    if (hdrs.buf)
+	memBufClean(&hdrs);
+    dlinkDelete(&state->list, &state->def->queue);
+    do {
+	cbdataUnlock(state->def);
+	state->def = NULL;
+
+	if (state->callback && cbdataValid(state->callback_data))
+	    state->callback(state->callback_data, freshness >= 0, log);
+	cbdataUnlock(state->callback_data);
+	state->callback_data = NULL;
+
+	next = state->queue;
+	cbdataFree(state);
+	state = next;
+    } while (state);
+}
+
+void
+refreshCheckSubmit(StoreEntry * entry, REFRESHCHECK * callback, void *callback_data)
+{
+    MemBuf buf;
+    const char *key;
+    refresh_check_helper *def = Config.Program.refresh_check;
+    refreshCheckState *state;
+    dlink_node *node;
+    refreshCheckState *oldstate = NULL;
+
+    if (!def) {
+	callback(callback_data, 0, NULL);
+	return;
+    }
+    key = makeRefreshCheckRequest(entry, def->format);
+    if (!key) {
+	callback(callback_data, 0, NULL);
+	return;
+    }
+    debug(84, 2) ("refreshCheckLookup: for '%s'\n", key);
+
+    /* Check for a pending lookup to hook into */
+    for (node = def->queue.head; node; node = node->next) {
+	refreshCheckState *oldstatetmp = node->data;
+	if (entry == oldstatetmp->entry) {
+	    oldstate = oldstatetmp;
+	    break;
+	}
+    }
+
+    state = cbdataAlloc(refreshCheckState);
+    state->def = def;
+    cbdataLock(state->def);
+    state->entry = entry;
+    storeLockObject(entry);
+    state->callback = callback;
+    state->callback_data = callback_data;
+    cbdataLock(state->callback_data);
+    if (oldstate) {
+	/* Hook into pending lookup */
+	state->queue = oldstate->queue;
+	oldstate->queue = state;
+    } else {
+	/* No pending lookup found. Sumbit to helper */
+	/* Check for queue overload */
+	if (refreshCheckOverload(def)) {
+	    debug(84, 1) ("refreshCheckLookup: queue overload\n");
+	    cbdataFree(state);
+	    callback(callback_data, 0, "Overload");
+	    return;
+	}
+	/* Send it off to the helper */
+	memBufDefInit(&buf);
+	memBufPrintf(&buf, "%s\n", key);
+	helperSubmit(def->helper, buf.buf, refreshCheckHandleReply, state);
+	dlinkAdd(state, &state->list, &def->queue);
+	memBufClean(&buf);
+    }
+}
+
+static void
+refreshCheckStats(StoreEntry * sentry)
+{
+    refresh_check_helper *p = Config.Program.refresh_check;
+
+    if (p) {
+	storeAppendPrintf(sentry, "Refresh Check helper statistics:\n");
+	helperStats(sentry, p->helper);
+	storeAppendPrintf(sentry, "\n");
+    }
+}
+void
+refreshCheckConfigure(void)
+{
+    refresh_check_helper *p = Config.Program.refresh_check;
+    if (p) {
+	requirePathnameExists("external_refresh_check", p->cmdline->key);
+    }
+}
+void
+refreshCheckInit(void)
+{
+    static int firstTimeInit = 1;
+    refresh_check_helper *p = Config.Program.refresh_check;
+
+    if (p) {
+	if (!p->helper)
+	    p->helper = helperCreate("external_refresh_check");
+	p->helper->cmdline = p->cmdline;
+	p->helper->n_to_start = p->children;
+	p->helper->concurrency = p->concurrency;
+	p->helper->ipc_type = IPC_STREAM;
+	helperOpenServers(p->helper);
+	if (firstTimeInit) {
+	    firstTimeInit = 0;
+	    cachemgrRegister("refresh_check",
+		"External ACL stats",
+		refreshCheckStats, 0, 1);
+	}
+	CBDATA_INIT_TYPE_FREECB(refreshCheckState, free_refreshCheckState);
+    }
+}
+
+void
+refreshCheckShutdown(void)
+{
+    refresh_check_helper *p = Config.Program.refresh_check;
+    if (p) {
+	helperShutdown(p->helper);
+    }
+}
Index: squid/src/stat.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/stat.c,v
retrieving revision 1.42.2.2
retrieving revision 1.42.2.3
diff -u -r1.42.2.2 -r1.42.2.3
--- squid/src/stat.c	26 Sep 2007 07:33:50 -0000	1.42.2.2
+++ squid/src/stat.c	27 Nov 2007 08:12:28 -0000	1.42.2.3
@@ -1,6 +1,6 @@
 
 /*
- * $Id: stat.c,v 1.42.2.2 2007/09/26 07:33:50 adri Exp $
+ * $Id: stat.c,v 1.42.2.3 2007/11/27 08:12:28 adri Exp $
  *
  * DEBUG: section 18    Cache Manager Statistics
  * AUTHOR: Harvest Derived
@@ -204,8 +204,8 @@
 	strcat(buf, "DELAY_SENDING,");
     if (EBIT_TEST(flags, RELEASE_REQUEST))
 	strcat(buf, "RELEASE_REQUEST,");
-    if (EBIT_TEST(flags, REFRESH_REQUEST))
-	strcat(buf, "REFRESH_REQUEST,");
+    if (EBIT_TEST(flags, REFRESH_FAILURE))
+	strcat(buf, "REFRESH_FAILURE,");
     if (EBIT_TEST(flags, ENTRY_CACHABLE))
 	strcat(buf, "CACHABLE,");
     if (EBIT_TEST(flags, ENTRY_DISPATCHED))
@@ -251,6 +251,8 @@
     if (mem)
 	memBufPrintf(mb, "\t%s %s\n",
 	    RequestMethods[mem->method].str, mem->url);
+    if (mem && mem->store_url)
+	memBufPrintf(mb, "\tStore lookup URL: %s\n", mem->store_url);
     memBufPrintf(mb, "\t%s\n", describeStatuses(e));
     memBufPrintf(mb, "\t%s\n", storeEntryFlags(e));
     memBufPrintf(mb, "\t%s\n", describeTimestamps(e));
@@ -421,7 +423,15 @@
     LOCAL_ARRAY(char, buf, 32);
     if (f->type != FD_SOCKET)
 	return null_string;
-    snprintf(buf, 32, "%s.%d", f->ipaddr, (int) f->remote_port);
+    if (*f->ipaddr)
+	snprintf(buf, 32, "%s.%d", f->ipaddr, (int) f->remote_port);
+    else {
+	if (f->local_addr.s_addr != any_addr.s_addr) {
+	    snprintf(buf, 32, "%s.%d", inet_ntoa(f->local_addr), (int) f->local_port);
+	} else {
+	    snprintf(buf, 32, "*.%d", (int) f->local_port);
+	}
+    }
     return buf;
 }
 
Index: squid/src/store.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/store.c,v
retrieving revision 1.49
retrieving revision 1.49.4.1
diff -u -r1.49 -r1.49.4.1
--- squid/src/store.c	29 Aug 2007 21:52:57 -0000	1.49
+++ squid/src/store.c	27 Nov 2007 08:12:29 -0000	1.49.4.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: store.c,v 1.49 2007/08/29 21:52:57 squidadm Exp $
+ * $Id: store.c,v 1.49.4.1 2007/11/27 08:12:29 adri Exp $
  *
  * DEBUG: section 20    Storage Manager
  * AUTHOR: Harvest Derived
@@ -128,7 +128,9 @@
 int
 memHaveHeaders(const MemObject * mem)
 {
-    if (mem->reply == NULL)
+    if (!mem)
+	return 0;
+    if (!mem->reply)
 	return 0;
     if (mem->reply->pstate != psParsed)
 	return 0;
@@ -150,6 +152,16 @@
     return e;
 }
 
+void
+storeEntrySetStoreUrl(StoreEntry * e, const char *store_url)
+{
+    /* XXX eww, another strdup! */
+    if (!e->mem_obj)
+	return;
+    safe_free(e->mem_obj->store_url);
+    e->mem_obj->store_url = xstrdup(store_url);
+}
+
 static void
 destroy_MemObject(StoreEntry * e)
 {
@@ -175,6 +187,10 @@
 	storeUnlockObject(mem->ims_entry);
 	mem->ims_entry = NULL;
     }
+    if (mem->old_entry) {
+	storeUnlockObject(mem->old_entry);
+	mem->old_entry = NULL;
+    }
     httpReplyDestroy(mem->reply);
     requestUnlink(mem->request);
     mem->request = NULL;
@@ -1010,7 +1026,7 @@
 		 * to record the new variance key
 		 */
 		safe_free(request->vary_headers);	/* free old "bad" variance key */
-		pe = storeGetPublic(mem->url, mem->method);
+		pe = storeGetPublic(storeLookupUrl(e), mem->method);
 		if (pe)
 		    storeRelease(pe);
 	    }
@@ -1042,7 +1058,7 @@
 	    stringClean(&vary);
 	}
     } else {
-	newkey = storeKeyPublic(mem->url, mem->method);
+	newkey = storeKeyPublic(storeLookupUrl(e), mem->method);
     }
     if ((e2 = (StoreEntry *) hash_lookup(store_table, newkey))) {
 	debug(20, 3) ("storeSetPublicKey: Making old '%s' private.\n", mem->url);
@@ -1051,7 +1067,7 @@
 	if (mem->request)
 	    newkey = storeKeyPublicByRequest(mem->request);
 	else
-	    newkey = storeKeyPublic(mem->url, mem->method);
+	    newkey = storeKeyPublic(storeLookupUrl(e), mem->method);
     }
     if (e->hash.key)
 	storeHashDelete(e);
@@ -1314,7 +1330,11 @@
     if (e->mem_obj->request)
 	e->mem_obj->request->hier.store_complete_stop = current_time;
 #endif
-    e->mem_obj->refresh_timestamp = e->timestamp;
+    e->mem_obj->refresh_timestamp = 0;
+    if (e->mem_obj->old_entry) {
+	if (e->mem_obj->old_entry->mem_obj)
+	    e->mem_obj->old_entry->mem_obj->refresh_timestamp = 0;
+    }
     /*
      * We used to call InvokeHandlers, then storeSwapOut.  However,
      * Madhukar Reddy <myreddy@persistence.com> reported that
@@ -1338,7 +1358,7 @@
     assert(mem != NULL);
     debug(20, 6) ("storeAbort: %s\n", storeKeyText(e->hash.key));
     storeLockObject(e);		/* lock while aborting */
-    storeNegativeCache(e);
+    storeExpireNow(e);
     storeReleaseRequest(e);
     EBIT_SET(e->flags, ENTRY_ABORTED);
     storeSetMemStatus(e, NOT_IN_MEMORY);
@@ -1627,7 +1647,34 @@
 void
 storeNegativeCache(StoreEntry * e)
 {
-    e->expires = squid_curtime + Config.negativeTtl;
+    StoreEntry *oe = e->mem_obj->old_entry;
+    time_t expires = e->expires;
+    refresh_cc cc = refreshCC(e, e->mem_obj->request);
+    if (expires == -1)
+	expires = squid_curtime + cc.negative_ttl;
+    if (oe && !EBIT_TEST(oe->flags, KEY_PRIVATE) && !EBIT_TEST(oe->flags, ENTRY_REVALIDATE)) {
+	if (cc.max_stale >= 0) {
+	    time_t max_expires;
+	    storeTimestampsSet(oe);
+	    max_expires = oe->expires + cc.max_stale;
+	    /* Bail out if beyond the stale-if-error staleness limit */
+	    if (max_expires <= squid_curtime)
+		goto cache_error_response;
+	    /* Limit expiry time to stale-if-error/max_stale */
+	    if (expires > max_expires)
+		expires = max_expires;
+	}
+	/* Block the new error from getting cached */
+	EBIT_CLR(e->flags, ENTRY_CACHABLE);
+	/* And negatively cache the old one */
+	if (oe->expires < expires)
+	    oe->expires = expires;
+	EBIT_SET(oe->flags, REFRESH_FAILURE);
+	return;
+    }
+  cache_error_response:
+    if (e->expires < expires)
+	e->expires = expires;
     EBIT_SET(e->flags, ENTRY_NEGCACHED);
 }
 
@@ -1819,6 +1866,19 @@
 	return e->mem_obj->url;
 }
 
+const char *
+storeLookupUrl(const StoreEntry * e)
+{
+    if (e == NULL)
+	return "[null_entry]";
+    else if (e->mem_obj == NULL)
+	return "[null_mem_obj]";
+    else if (e->mem_obj->store_url)
+	return e->mem_obj->store_url;
+    else
+	return e->mem_obj->url;
+}
+
 void
 storeCreateMemObject(StoreEntry * e, const char *url)
 {
Index: squid/src/store_client.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/store_client.c,v
retrieving revision 1.25.10.4
retrieving revision 1.25.10.5
diff -u -r1.25.10.4 -r1.25.10.5
--- squid/src/store_client.c	27 Sep 2007 15:09:17 -0000	1.25.10.4
+++ squid/src/store_client.c	27 Nov 2007 08:12:29 -0000	1.25.10.5
@@ -1,6 +1,6 @@
 
 /*
- * $Id: store_client.c,v 1.25.10.4 2007/09/27 15:09:17 adri Exp $
+ * $Id: store_client.c,v 1.25.10.5 2007/11/27 08:12:29 adri Exp $
  *
  * DEBUG: section 20    Storage Manager Client-Side Interface
  * AUTHOR: Duane Wessels
@@ -533,6 +533,18 @@
 		break;
 	    }
 	    break;
+	case STORE_META_STOREURL:
+	    if (NULL == mem->store_url)
+		mem->store_url = xstrdup(t->value);
+	    else if (0 == strcasecmp(mem->store_url, t->value))
+		(void) 0;	/* a match! */
+	    else {
+		debug(20, 1) ("storeClientReadHeader: store URL mismatch\n");
+		debug(20, 1) ("\t{%s} != {%s}\n", (char *) t->value, mem->store_url);
+		swap_object_ok = 0;
+		break;
+	    }
+	    break;
 	case STORE_META_OBJSIZE:
 	    break;
 	case STORE_META_STD:
Index: squid/src/store_key_md5.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/store_key_md5.c,v
retrieving revision 1.10
retrieving revision 1.10.10.1
diff -u -r1.10 -r1.10.10.1
--- squid/src/store_key_md5.c	21 Jan 2007 14:04:07 -0000	1.10
+++ squid/src/store_key_md5.c	27 Nov 2007 08:12:29 -0000	1.10.10.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: store_key_md5.c,v 1.10 2007/01/21 14:04:07 squidadm Exp $
+ * $Id: store_key_md5.c,v 1.10.10.1 2007/11/27 08:12:29 adri Exp $
  *
  * DEBUG: section 20    Storage Manager MD5 Cache Keys
  * AUTHOR: Duane Wessels
@@ -131,7 +131,14 @@
 {
     static cache_key digest[MD5_DIGEST_CHARS];
     unsigned char m = (unsigned char) method;
-    const char *url = urlCanonical(request);
+    const char *url;
+
+    if (request->store_url) {
+	url = request->store_url;
+    } else {
+	url = urlCanonical(request);
+    }
+
     MD5_CTX M;
     MD5Init(&M);
     MD5Update(&M, &m, sizeof(m));
--- /dev/null	Wed Nov 28 01:20:24 2007
+++ squid/src/store_rewrite.c	Wed Nov 28 01:20:25 2007
@@ -0,0 +1,183 @@
+
+/*
+ * $Id: store_rewrite.c,v 1.1.4.2 2007/11/27 08:12:29 adri Exp $
+ *
+ * DEBUG: section 61    Redirector
+ * AUTHOR: Duane Wessels
+ *
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from
+ *  the Internet community; see the CONTRIBUTORS file for full
+ *  details.   Many organizations have provided support for Squid's
+ *  development; see the SPONSORS file for full details.  Squid is
+ *  Copyrighted (C) 2001 by the Regents of the University of
+ *  California; see the COPYRIGHT file for full details.  Squid
+ *  incorporates software developed and/or copyrighted by other
+ *  sources; see the CREDITS file for full details.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+#include "squid.h"
+
+typedef struct {
+    void *data;
+    char *orig_url;
+    struct in_addr client_addr;
+    const char *client_ident;
+    const char *method_s;
+    RH *handler;
+} storeurlStateData;
+
+static HLPCB storeurlHandleReply;
+static void storeurlStateFree(storeurlStateData * r);
+static helper *storeurlors = NULL;
+static OBJH storeurlStats;
+static int n_bypassed = 0;
+CBDATA_TYPE(storeurlStateData);
+
+static void
+storeurlHandleReply(void *data, char *reply)
+{
+    storeurlStateData *r = data;
+    int valid;
+    char *t;
+    debug(61, 5) ("storeurlHandleRead: {%s}\n", reply ? reply : "<NULL>");
+    if (reply) {
+	if ((t = strchr(reply, ' ')))
+	    *t = '\0';
+	if (*reply == '\0')
+	    reply = NULL;
+    }
+    valid = cbdataValid(r->data);
+    cbdataUnlock(r->data);
+    if (valid)
+	r->handler(r->data, reply);
+    storeurlStateFree(r);
+}
+
+static void
+storeurlStateFree(storeurlStateData * r)
+{
+    safe_free(r->orig_url);
+    cbdataFree(r);
+}
+
+static void
+storeurlStats(StoreEntry * sentry)
+{
+    storeAppendPrintf(sentry, "Redirector Statistics:\n");
+    helperStats(sentry, storeurlors);
+    if (Config.onoff.storeurl_bypass)
+	storeAppendPrintf(sentry, "\nNumber of requests bypassed "
+	    "because all store url bypassers were busy: %d\n", n_bypassed);
+}
+
+/**** PUBLIC FUNCTIONS ****/
+
+void
+storeurlStart(clientHttpRequest * http, RH * handler, void *data)
+{
+    ConnStateData *conn = http->conn;
+    storeurlStateData *r = NULL;
+    const char *fqdn;
+    char *urlgroup = conn->port->urlgroup;
+    char buf[8192];
+    char claddr[20];
+    char myaddr[20];
+    assert(http);
+    assert(handler);
+    debug(61, 5) ("storeurlStart: '%s'\n", http->uri);
+    if (Config.onoff.storeurl_bypass && storeurlors->stats.queue_size) {
+	/* Skip storeurlor if there is one request queued */
+	n_bypassed++;
+	handler(data, NULL);
+	return;
+    }
+    r = cbdataAlloc(storeurlStateData);
+    r->orig_url = xstrdup(http->uri);
+    r->client_addr = conn->log_addr;
+    r->client_ident = NULL;
+    if (http->request->auth_user_request)
+	r->client_ident = authenticateUserRequestUsername(http->request->auth_user_request);
+    else if (http->request->extacl_user) {
+	r->client_ident = http->request->extacl_user;
+    }
+    if (!r->client_ident && conn->rfc931[0])
+	r->client_ident = conn->rfc931;
+#if USE_SSL
+    if (!r->client_ident)
+	r->client_ident = sslGetUserEmail(fd_table[conn->fd].ssl);
+#endif
+    if (!r->client_ident)
+	r->client_ident = dash_str;
+    r->method_s = RequestMethods[http->request->method].str;
+    r->handler = handler;
+    r->data = data;
+    cbdataLock(r->data);
+    if ((fqdn = fqdncache_gethostbyaddr(r->client_addr, 0)) == NULL)
+	fqdn = dash_str;
+    xstrncpy(claddr, inet_ntoa(r->client_addr), 20);
+    xstrncpy(myaddr, inet_ntoa(http->request->my_addr), 20);
+    snprintf(buf, 8191, "%s %s/%s %s %s %s myip=%s myport=%d",
+	r->orig_url,
+	claddr,
+	fqdn,
+	r->client_ident[0] ? rfc1738_escape(r->client_ident) : dash_str,
+	r->method_s,
+	urlgroup ? urlgroup : "-",
+	myaddr,
+	http->request->my_port);
+    debug(61, 6) ("storeurlStart: sending '%s' to the helper\n", buf);
+    strcat(buf, "\n");
+    helperSubmit(storeurlors, buf, storeurlHandleReply, r);
+}
+
+void
+storeurlInit(void)
+{
+    static int init = 0;
+    if (!Config.Program.store_rewrite.command)
+	return;
+    if (storeurlors == NULL)
+	storeurlors = helperCreate("store_rewriter");
+    storeurlors->cmdline = Config.Program.store_rewrite.command;
+    storeurlors->n_to_start = Config.Program.store_rewrite.children;
+    storeurlors->concurrency = Config.Program.store_rewrite.concurrency;
+    storeurlors->ipc_type = IPC_STREAM;
+    helperOpenServers(storeurlors);
+    if (!init) {
+	cachemgrRegister("store_rewriter",
+	    "URL Rewriter Stats",
+	    storeurlStats, 0, 1);
+	init = 1;
+	CBDATA_INIT_TYPE(storeurlStateData);
+    }
+}
+
+void
+storeurlShutdown(void)
+{
+    if (!storeurlors)
+	return;
+    helperShutdown(storeurlors);
+    if (!shutting_down)
+	return;
+    helperFree(storeurlors);
+    storeurlors = NULL;
+}
Index: squid/src/store_swapmeta.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/store_swapmeta.c,v
retrieving revision 1.12
retrieving revision 1.12.22.1
diff -u -r1.12 -r1.12.22.1
--- squid/src/store_swapmeta.c	29 Jul 2006 14:53:20 -0000	1.12
+++ squid/src/store_swapmeta.c	27 Nov 2007 08:12:29 -0000	1.12.22.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: store_swapmeta.c,v 1.12 2006/07/29 14:53:20 squidadm Exp $
+ * $Id: store_swapmeta.c,v 1.12.22.1 2007/11/27 08:12:29 adri Exp $
  *
  * DEBUG: section 20    Storage Manager Swapfile Metadata
  * AUTHOR: Kostas Anagnostakis
@@ -86,6 +86,8 @@
     vary = e->mem_obj->vary_headers;
     if (vary)
 	T = storeSwapTLVAdd(STORE_META_VARY_HEADERS, vary, strlen(vary) + 1, T);
+    if (e->mem_obj->store_url)
+	T = storeSwapTLVAdd(STORE_META_STOREURL, e->mem_obj->store_url, strlen(e->mem_obj->store_url) + 1, T);
     return TLV;
 }
 
--- /dev/null	Wed Nov 28 01:20:24 2007
+++ squid/src/store_update.c	Wed Nov 28 01:20:25 2007
@@ -0,0 +1,187 @@
+
+/*
+ * $Id: store_update.c,v 1.2.4.2 2007/11/27 08:12:29 adri Exp $
+ *
+ * DEBUG: section 20    Storage Manager
+ * AUTHOR: Henrik Nordstrom <henrik@henriknordstrom.net>
+ *
+ * Copyright (C) 2007 Henrik Nordstrom <henrik@henriknordstrom.net>
+ *
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from
+ *  the Internet community; see the CONTRIBUTORS file for full
+ *  details.   Many organizations have provided support for Squid's
+ *  development; see the SPONSORS file for full details.  Squid is
+ *  Copyrighted (C) 2001 by the Regents of the University of
+ *  California; see the COPYRIGHT file for full details.  Squid
+ *  incorporates software developed and/or copyrighted by other
+ *  sources; see the CREDITS file for full details.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+#include "squid.h"
+
+/* Update the on-disk representation of the object to match
+ * current in-memory representation. This requires rewriting
+ * the object headers (bot meta and http) which isn't supported
+ * by the store layer today, so we rewrite the full object.
+ */
+
+/* Local state */
+typedef struct {
+    StoreEntry *oldentry;
+    StoreEntry *newentry;
+    store_client *sc;
+    squid_off_t offset;
+    char buf[4096];
+} StoreUpdateState;
+
+CBDATA_TYPE(StoreUpdateState);
+
+static void
+free_StoreUpdateState(void *data)
+{
+    StoreUpdateState *state = data;
+    if (state->sc)
+	storeClientUnregister(state->sc, state->oldentry, state);
+    if (state->oldentry)
+	storeUnlockObject(state->oldentry);
+    if (state->newentry) {
+	/* Set to NULL on completion, so we only get here in abnormal situations */
+	storeRelease(state->newentry);
+	storeUnlockObject(state->newentry);
+    }
+}
+
+static void
+storeUpdateDone(StoreUpdateState * state)
+{
+    if (state->sc) {
+	store_client *sc = state->sc;
+	state->sc = NULL;
+	storeClientUnregister(sc, state->oldentry, state);
+    }
+    cbdataFree(state);
+}
+static void
+storeUpdateAbort(void *data)
+{
+    StoreUpdateState *state = data;
+    storeUpdateDone(state);
+}
+
+static void
+storeUpdateCopy(void *data, char *buf, ssize_t size)
+{
+    StoreUpdateState *state = data;
+
+    if (EBIT_TEST(state->newentry->flags, ENTRY_ABORTED)) {
+	debug(20, 1) ("storeUpdateCopy: Aborted at %d (%d)\n", (int) state->offset, (int) size);
+	/* the abort callback deals with the needed cleanup */
+	return;
+    }
+    if (EBIT_TEST(state->newentry->flags, KEY_PRIVATE) && state->newentry->mem_obj->nclients == 0) {
+	debug(20, 2) ("storeUpdateCopy: Gone stale with no clients, skip copying of the rest\n");
+	storeUpdateDone(state);
+	return;
+    }
+    if (size < 0) {
+	debug(20, 1) ("storeUpdateCopy: Error at %d (%d)\n", (int) state->offset, (int) size);
+	storeUpdateDone(state);
+	return;
+    }
+    if (size > 0) {
+	storeAppend(state->newentry, buf, size);
+	if (EBIT_TEST(state->newentry->flags, ENTRY_ABORTED)) {
+	    debug(20, 1) ("storeUpdateCopy: Aborted on write at %d (%d)\n", (int) state->offset, (int) size);
+	    return;
+	}
+	state->offset += size;
+	storeClientCopy(state->sc, state->oldentry, state->offset, state->offset, sizeof(state->buf), state->buf, storeUpdateCopy, state);
+	return;
+    } else {
+	storeComplete(state->newentry);
+	storeUnlockObject(state->newentry);
+	state->newentry = NULL;
+	storeUpdateDone(state);
+    }
+}
+
+void
+storeUpdate(StoreEntry * entry, request_t * request)
+{
+    StoreUpdateState *state;
+    request_flags flags = null_request_flags;
+    const char *vary;
+
+    if (!request)
+	request = entry->mem_obj->request;
+
+    if (EBIT_TEST(entry->flags, KEY_PRIVATE))
+	return;			/* Nothing to do here... */
+
+    if (!Config.onoff.update_headers)
+	return;			/* Disabled */
+
+    CBDATA_INIT_TYPE_FREECB(StoreUpdateState, free_StoreUpdateState);
+
+    if (entry->mem_obj)
+	entry->mem_obj->refresh_timestamp = 0;
+    state = cbdataAlloc(StoreUpdateState);
+    state->oldentry = entry;
+    storeLockObject(state->oldentry);
+    flags.cachable = 1;
+    state->newentry = storeCreateEntry(storeUrl(entry), flags, entry->mem_obj->method);
+    storeRegisterAbort(state->newentry, storeUpdateAbort, state);
+    state->sc = storeClientRegister(state->oldentry, state);
+    state->offset = entry->mem_obj->reply->hdr_sz;
+    storeBuffer(state->newentry);
+    httpReplySwapOut(httpReplyClone(entry->mem_obj->reply), state->newentry);
+    state->newentry->timestamp = entry->timestamp;
+    state->newentry->lastref = entry->lastref;
+    state->newentry->expires = entry->expires;
+    state->newentry->lastmod = entry->lastmod;
+    state->newentry->refcount = entry->refcount;
+    if (request) {
+	state->newentry->mem_obj->request = requestLink(request);
+	vary = httpMakeVaryMark(request, state->newentry->mem_obj->reply);
+	if (vary) {
+	    state->newentry->mem_obj->vary_headers = xstrdup(vary);
+	    if (strBuf(request->vary_encoding))
+		entry->mem_obj->vary_encoding = xstrdup(strBuf(request->vary_encoding));
+	}
+    } else {
+	if (entry->mem_obj->vary_headers)
+	    state->newentry->mem_obj->vary_headers = xstrdup(entry->mem_obj->vary_headers);
+	if (entry->mem_obj->vary_encoding)
+	    state->newentry->mem_obj->vary_encoding = xstrdup(entry->mem_obj->vary_encoding);
+    }
+    storeSetPublicKey(state->newentry);
+    storeBufferFlush(state->newentry);
+    if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
+	/*
+	 * the above storeBufferFlush() call could ABORT this entry,
+	 * in that case, there's nothing for us to do.
+	 */
+	debug(20, 1) ("storeUpdate: Aborted on write\n");
+	return;
+    }
+    storeClientCopy(state->sc, state->oldentry, state->offset, state->offset, sizeof(state->buf), state->buf, storeUpdateCopy, state);
+    return;
+}
Index: squid/src/structs.h
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/structs.h,v
retrieving revision 1.158.2.4
retrieving revision 1.158.2.5
diff -u -r1.158.2.4 -r1.158.2.5
--- squid/src/structs.h	26 Sep 2007 07:33:50 -0000	1.158.2.4
+++ squid/src/structs.h	27 Nov 2007 08:12:29 -0000	1.158.2.5
@@ -1,6 +1,6 @@
 
 /*
- * $Id: structs.h,v 1.158.2.4 2007/09/26 07:33:50 adri Exp $
+ * $Id: structs.h,v 1.158.2.5 2007/11/27 08:12:29 adri Exp $
  *
  *
  * SQUID Web Proxy Cache          http://www.squid-cache.org/
@@ -443,6 +443,7 @@
     RemovalPolicySettings *replPolicy;
     RemovalPolicySettings *memPolicy;
     time_t negativeTtl;
+    time_t maxStale;
     time_t negativeDnsTtl;
     time_t positiveDnsTtl;
     time_t shutdownLifetime;
@@ -549,7 +550,13 @@
 	    wordlist *command;
 	    int children;
 	    int concurrency;
+	} store_rewrite;
+	struct {
+	    wordlist *command;
+	    int children;
+	    int concurrency;
 	} location_rewrite;
+	refresh_check_helper *refresh_check;
 #if USE_ICMP
 	char *pinger;
 #endif
@@ -652,6 +659,7 @@
 	int nonhierarchical_direct;
 	int strip_query_terms;
 	int redirector_bypass;
+	int storeurl_bypass;
 	int ignore_unknown_nameservers;
 	int client_pconns;
 	int server_pconns;
@@ -672,6 +680,7 @@
 	int global_internal_static;
 	int httpd_suppress_version_string;
 	int via;
+	int ignore_ims_on_miss;
 	int check_hostnames;
 	int allow_underscore;
 	int cache_vary;
@@ -680,6 +689,7 @@
 	int delay_pool_uses_indirect_client;
 	int log_uses_indirect_client;
 #endif
+	int update_headers;
     } onoff;
     acl *aclList;
     struct {
@@ -700,6 +710,7 @@
 	acl_access *identLookup;
 #endif
 	acl_access *url_rewrite;
+	acl_access *storeurl_rewrite;
 	acl_access *location_rewrite;
 	acl_access *reply;
 	acl_address *outgoing_address;
@@ -1190,6 +1201,7 @@
     HierarchyLogEntry hier;
     HttpReply *reply;
     request_t *request;
+    char *ext_refresh;
 };
 
 struct _clientHttpRequest {
@@ -1238,6 +1250,9 @@
     dlink_node active;
     squid_off_t maxBodySize;
     mem_node_ref nr;
+    STHCB *header_callback;	/* Temporarily here for storeClientCopyHeaders */
+    StoreEntry *header_entry;	/* Temporarily here for storeClientCopyHeaders */
+    int is_modified;
 };
 
 struct _ConnStateData {
@@ -1698,6 +1713,7 @@
 struct _MemObject {
     method_t method;
     char *url;
+    const char *store_url;
     mem_hdr data_hdr;
     squid_off_t inmem_hi;
     squid_off_t inmem_lo;
@@ -1730,7 +1746,9 @@
     const char *vary_headers;
     const char *vary_encoding;
     StoreEntry *ims_entry;
+    StoreEntry *old_entry;
     time_t refresh_timestamp;
+    time_t stale_while_revalidate;
 };
 
 struct _StoreEntry {
@@ -1885,6 +1903,7 @@
     u_short port;
     String urlpath;
     char *canonical;
+    char *store_url;		/* rewritten URL for store lookup/storage; if NULL use canonical */
     int link_count;		/* free when zero */
     request_flags flags;
     HttpHdrCc *cache_control;
@@ -1936,6 +1955,11 @@
     cachemgr_passwd *next;
 };
 
+struct _refresh_cc {
+    int max_stale;
+    int negative_ttl;
+};
+
 struct _refresh_t {
     const char *pattern;
     regex_t compiled_pattern;
@@ -1955,6 +1979,9 @@
 	unsigned int ignore_auth:1;
 #endif
     } flags;
+    int max_stale;
+    int stale_while_revalidate;
+    int negative_ttl;
 };
 
 struct _ErrorState {
Index: squid/src/typedefs.h
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/typedefs.h,v
retrieving revision 1.43.2.2
retrieving revision 1.43.2.3
diff -u -r1.43.2.2 -r1.43.2.3
--- squid/src/typedefs.h	25 Sep 2007 00:29:28 -0000	1.43.2.2
+++ squid/src/typedefs.h	27 Nov 2007 08:12:29 -0000	1.43.2.3
@@ -1,6 +1,6 @@
 
 /*
- * $Id: typedefs.h,v 1.43.2.2 2007/09/25 00:29:28 adri Exp $
+ * $Id: typedefs.h,v 1.43.2.3 2007/11/27 08:12:29 adri Exp $
  *
  *
  * SQUID Web Proxy Cache          http://www.squid-cache.org/
@@ -188,6 +188,7 @@
 typedef struct _AccessLogEntry AccessLogEntry;
 typedef struct _cachemgr_passwd cachemgr_passwd;
 typedef struct _refresh_t refresh_t;
+typedef struct _refresh_cc refresh_cc;
 typedef struct _CommWriteStateData CommWriteStateData;
 typedef struct _ErrorState ErrorState;
 typedef struct _dlink_node dlink_node;
@@ -289,6 +290,7 @@
 typedef int QS(const void *, const void *);	/* qsort */
 typedef void STCB(void *, char *, ssize_t);	/* store callback */
 typedef void STNCB(void *, struct _mem_node_ref r, ssize_t);	/* new store callback */
+typedef void STHCB(void *, HttpReply *);	/* store callback */
 typedef void STABH(void *);
 typedef void ERCB(int fd, void *, size_t);
 typedef void OBJH(StoreEntry *);
@@ -429,4 +431,6 @@
 typedef void LOGROTATE(Logfile *);
 typedef void LOGCLOSE(Logfile *);
 
+typedef void REFRESHCHECK(void *data, int fresh, const char *log);
+typedef struct _refresh_check_helper refresh_check_helper;
 #endif /* SQUID_TYPEDEFS_H */
Index: squid/src/fs/aufs/aiops.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/fs/aufs/aiops.c,v
retrieving revision 1.28
retrieving revision 1.28.18.1
diff -u -r1.28 -r1.28.18.1
--- squid/src/fs/aufs/aiops.c	23 Sep 2006 10:51:41 -0000	1.28
+++ squid/src/fs/aufs/aiops.c	27 Nov 2007 08:12:30 -0000	1.28.18.1
@@ -322,7 +322,7 @@
     /* Create threads and get them to sit in their wait loop */
     squidaio_thread_pool = memPoolCreate("aio_thread", sizeof(squidaio_thread_t));
     if (squidaio_nthreads == 0) {
-	int j = 16;
+	int j = THREAD_FACTOR;
 	for (i = 0; i < n_asyncufs_dirs; i++) {
 	    squidaio_nthreads += j;
 	    j = j * 2 / 3;
@@ -338,7 +338,7 @@
 #endif
     }
     if (squidaio_nthreads == 0)
-	squidaio_nthreads = 16;
+	squidaio_nthreads = THREAD_FACTOR;
     squidaio_magic1 = squidaio_nthreads * MAGIC1_FACTOR;
     squidaio_magic2 = squidaio_nthreads * MAGIC2_FACTOR;
     for (i = 0; i < squidaio_nthreads; i++) {
Index: squid/src/fs/aufs/aiops_win32.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/fs/aufs/aiops_win32.c,v
retrieving revision 1.4
retrieving revision 1.4.28.1
diff -u -r1.4 -r1.4.28.1
--- squid/src/fs/aufs/aiops_win32.c	23 Sep 2006 10:51:41 -0000	1.4
+++ squid/src/fs/aufs/aiops_win32.c	27 Nov 2007 08:12:30 -0000	1.4.28.1
@@ -1,5 +1,5 @@
 /*
- * $Id: aiops_win32.c,v 1.4 2006/09/23 10:51:41 squidadm Exp $
+ * $Id: aiops_win32.c,v 1.4.28.1 2007/11/27 08:12:30 adri Exp $
  *
  * DEBUG: section 43    Windows AIOPS
  * AUTHOR: Stewart Forster <slf@connect.com.au>
@@ -322,7 +322,7 @@
     /* Create threads and get them to sit in their wait loop */
     squidaio_thread_pool = memPoolCreate("aio_thread", sizeof(squidaio_thread_t));
     if (squidaio_nthreads == 0) {
-	int j = 16;
+	int j = THREAD_FACTOR;
 	for (i = 0; i < n_asyncufs_dirs; i++) {
 	    squidaio_nthreads += j;
 	    j = j * 2 / 3;
@@ -338,7 +338,7 @@
 #endif
     }
     if (squidaio_nthreads == 0)
-	squidaio_nthreads = 16;
+	squidaio_nthreads = THREAD_FACTOR;
     squidaio_magic1 = squidaio_nthreads * MAGIC1_FACTOR;
     squidaio_magic2 = squidaio_nthreads * MAGIC2_FACTOR;
     for (i = 0; i < squidaio_nthreads; i++) {
Index: squid/src/fs/aufs/store_dir_aufs.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/fs/aufs/store_dir_aufs.c,v
retrieving revision 1.50
retrieving revision 1.50.6.1
diff -u -r1.50 -r1.50.6.1
--- squid/src/fs/aufs/store_dir_aufs.c	1 Mar 2007 07:53:23 -0000	1.50
+++ squid/src/fs/aufs/store_dir_aufs.c	27 Nov 2007 08:12:30 -0000	1.50.6.1
@@ -1551,6 +1551,8 @@
 	    break;		/* no more objects */
 	removed++;
 	storeRelease(e);
+	if (aioQueueSize() > MAGIC2)
+	    break;
     }
     walker->Done(walker);
     debug(47, (removed ? 2 : 3)) ("storeAufsDirMaintain: %s removed %d/%d f=%.03f max_scan=%d\n",
